aboutsummaryrefslogtreecommitdiff
path: root/src/libui_sdl
diff options
context:
space:
mode:
Diffstat (limited to 'src/libui_sdl')
-rw-r--r--src/libui_sdl/CMakeLists.txt2
-rw-r--r--src/libui_sdl/DlgAudioSettings.cpp16
-rw-r--r--src/libui_sdl/DlgAudioSettings.h1
-rw-r--r--src/libui_sdl/DlgEmuSettings.cpp15
-rw-r--r--src/libui_sdl/DlgEmuSettings.h1
-rw-r--r--src/libui_sdl/DlgInputConfig.cpp45
-rw-r--r--src/libui_sdl/DlgInputConfig.h1
-rw-r--r--src/libui_sdl/DlgVideoSettings.cpp324
-rw-r--r--src/libui_sdl/DlgVideoSettings.h30
-rw-r--r--src/libui_sdl/DlgWifiSettings.cpp7
-rw-r--r--src/libui_sdl/DlgWifiSettings.h1
-rw-r--r--src/libui_sdl/OSD.cpp423
-rw-r--r--src/libui_sdl/OSD.h35
-rw-r--r--src/libui_sdl/Platform.cpp9
-rw-r--r--src/libui_sdl/PlatformConfig.cpp10
-rw-r--r--src/libui_sdl/PlatformConfig.h3
-rw-r--r--src/libui_sdl/font.h135
-rw-r--r--src/libui_sdl/libui/ui.h25
-rw-r--r--src/libui_sdl/libui/unix/CMakeLists.txt2
-rw-r--r--src/libui_sdl/libui/unix/area.c116
-rw-r--r--src/libui_sdl/libui/unix/draw.c4
-rw-r--r--src/libui_sdl/libui/unix/gl.c246
-rw-r--r--src/libui_sdl/libui/unix/main.c24
-rw-r--r--src/libui_sdl/libui/unix/uipriv_unix.h8
-rw-r--r--src/libui_sdl/libui/unix/window.c18
-rw-r--r--src/libui_sdl/libui/windows/CMakeLists.txt1
-rw-r--r--src/libui_sdl/libui/windows/area.cpp73
-rw-r--r--src/libui_sdl/libui/windows/area.hpp11
-rw-r--r--src/libui_sdl/libui/windows/areadraw.cpp27
-rw-r--r--src/libui_sdl/libui/windows/areaevents.cpp2
-rw-r--r--src/libui_sdl/libui/windows/areautil.cpp21
-rw-r--r--src/libui_sdl/libui/windows/draw.cpp5
-rw-r--r--src/libui_sdl/libui/windows/gl.cpp161
-rw-r--r--src/libui_sdl/libui/windows/window.cpp15
-rw-r--r--src/libui_sdl/main.cpp885
-rw-r--r--src/libui_sdl/main_shaders.h250
36 files changed, 2725 insertions, 227 deletions
diff --git a/src/libui_sdl/CMakeLists.txt b/src/libui_sdl/CMakeLists.txt
index 40019db..63e9f48 100644
--- a/src/libui_sdl/CMakeLists.txt
+++ b/src/libui_sdl/CMakeLists.txt
@@ -9,7 +9,9 @@ SET(SOURCES_LIBUI
DlgAudioSettings.cpp
DlgEmuSettings.cpp
DlgInputConfig.cpp
+ DlgVideoSettings.cpp
DlgWifiSettings.cpp
+ OSD.cpp
)
option(BUILD_SHARED_LIBS "Whether to build libui as a shared library or a static library" ON)
diff --git a/src/libui_sdl/DlgAudioSettings.cpp b/src/libui_sdl/DlgAudioSettings.cpp
index 66bdf61..d649321 100644
--- a/src/libui_sdl/DlgAudioSettings.cpp
+++ b/src/libui_sdl/DlgAudioSettings.cpp
@@ -44,8 +44,15 @@ uiEntry* txMicWavPath;
int oldvolume;
+void RevertSettings()
+{
+ Config::AudioVolume = oldvolume;
+}
+
+
int OnCloseWindow(uiWindow* window, void* blarg)
{
+ RevertSettings();
opened = false;
return 1;
}
@@ -69,7 +76,7 @@ void OnMicWavBrowse(uiButton* btn, void* blarg)
void OnCancel(uiButton* btn, void* blarg)
{
- Config::AudioVolume = oldvolume;
+ RevertSettings();
uiControlDestroy(uiControl(win));
opened = false;
@@ -180,4 +187,11 @@ void Open()
uiControlShow(uiControl(win));
}
+void Close()
+{
+ if (!opened) return;
+ uiControlDestroy(uiControl(win));
+ opened = false;
+}
+
}
diff --git a/src/libui_sdl/DlgAudioSettings.h b/src/libui_sdl/DlgAudioSettings.h
index 30a5d53..f058c25 100644
--- a/src/libui_sdl/DlgAudioSettings.h
+++ b/src/libui_sdl/DlgAudioSettings.h
@@ -23,6 +23,7 @@ namespace DlgAudioSettings
{
void Open();
+void Close();
}
diff --git a/src/libui_sdl/DlgEmuSettings.cpp b/src/libui_sdl/DlgEmuSettings.cpp
index 7d774a0..768560d 100644
--- a/src/libui_sdl/DlgEmuSettings.cpp
+++ b/src/libui_sdl/DlgEmuSettings.cpp
@@ -37,7 +37,6 @@ bool opened;
uiWindow* win;
uiCheckbox* cbDirectBoot;
-uiCheckbox* cbThreaded3D;
int OnCloseWindow(uiWindow* window, void* blarg)
@@ -55,14 +54,11 @@ void OnCancel(uiButton* btn, void* blarg)
void OnOk(uiButton* btn, void* blarg)
{
Config::DirectBoot = uiCheckboxChecked(cbDirectBoot);
- Config::Threaded3D = uiCheckboxChecked(cbThreaded3D);
Config::Save();
uiControlDestroy(uiControl(win));
opened = false;
-
- ApplyNewSettings(0);
}
void Open()
@@ -87,9 +83,6 @@ void Open()
cbDirectBoot = uiNewCheckbox("Boot game directly");
uiBoxAppend(in_ctrl, uiControl(cbDirectBoot), 0);
-
- cbThreaded3D = uiNewCheckbox("Threaded 3D renderer");
- uiBoxAppend(in_ctrl, uiControl(cbThreaded3D), 0);
}
{
@@ -110,9 +103,15 @@ void Open()
}
uiCheckboxSetChecked(cbDirectBoot, Config::DirectBoot);
- uiCheckboxSetChecked(cbThreaded3D, Config::Threaded3D);
uiControlShow(uiControl(win));
}
+void Close()
+{
+ if (!opened) return;
+ uiControlDestroy(uiControl(win));
+ opened = false;
+}
+
}
diff --git a/src/libui_sdl/DlgEmuSettings.h b/src/libui_sdl/DlgEmuSettings.h
index 126497a..baff7ce 100644
--- a/src/libui_sdl/DlgEmuSettings.h
+++ b/src/libui_sdl/DlgEmuSettings.h
@@ -23,6 +23,7 @@ namespace DlgEmuSettings
{
void Open();
+void Close();
}
diff --git a/src/libui_sdl/DlgInputConfig.cpp b/src/libui_sdl/DlgInputConfig.cpp
index 4f9307b..b17f049 100644
--- a/src/libui_sdl/DlgInputConfig.cpp
+++ b/src/libui_sdl/DlgInputConfig.cpp
@@ -64,6 +64,21 @@ int openedmask;
InputDlgData inputdlg[2];
+void KeyMappingName(int id, char* str)
+{
+ if (id < 0)
+ {
+ strcpy(str, "None");
+ return;
+ }
+
+ char* keyname = uiKeyName(id);
+ strncpy(str, keyname, 31);
+ uiFreeText(keyname);
+
+ str[31] = '\0';
+}
+
void JoyMappingName(int id, char* str)
{
if (id < 0)
@@ -134,7 +149,7 @@ int OnAreaKeyEvent(uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* evt)
return 1;
}
- char keyname[16];
+ char keyname[32];
JoyMappingName(dlg->joymap[id], keyname);
uiButtonSetText(dlg->pollbtn, keyname);
uiControlEnable(uiControl(dlg->pollbtn));
@@ -150,12 +165,17 @@ int OnAreaKeyEvent(uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* evt)
{
// set key.
if (evt->Scancode != 0x1) // ESC
- dlg->keymap[dlg->pollid] = evt->Scancode;
+ {
+ if (evt->Scancode == 0xE) // backspace
+ dlg->keymap[dlg->pollid] = -1;
+ else
+ dlg->keymap[dlg->pollid] = evt->Scancode;
+ }
- char* keyname = uiKeyName(dlg->keymap[dlg->pollid]);
+ char keyname[32];
+ KeyMappingName(dlg->keymap[dlg->pollid], keyname);
uiButtonSetText(dlg->pollbtn, keyname);
uiControlEnable(uiControl(dlg->pollbtn));
- uiFreeText(keyname);
dlg->pollid = -1;
@@ -170,7 +190,7 @@ void FinishJoyMapping(void* param)
InputDlgData* dlg = (InputDlgData*)param;
int id = dlg->pollid & 0xFF;
- char keyname[16];
+ char keyname[32];
JoyMappingName(dlg->joymap[id], keyname);
uiButtonSetText(dlg->pollbtn, keyname);
uiControlEnable(uiControl(dlg->pollbtn));
@@ -386,15 +406,14 @@ void Open(int type)
uiGridAppend(b_key, uiControl(label), 0, i, 1, 1, 1, uiAlignStart, 1, uiAlignCenter);
uiControlSetMinSize(uiControl(label), width, 1);
- char* keyname = uiKeyName(dlg->keymap[j]);
+ char keyname[32];
+ KeyMappingName(dlg->keymap[j], keyname);
uiButton* btn = uiNewButton(keyname);
uiControl(btn)->UserData = dlg;
uiGridAppend(b_key, uiControl(btn), 1, i, 1, 1, 1, uiAlignFill, 1, uiAlignCenter);
uiButtonOnClicked(btn, OnKeyStartConfig, (type==0) ? &dskeyorder[i] : &identity[i]);
uiControlSetMinSize(uiControl(btn), width, 1);
-
- uiFreeText(keyname);
}
uiGroup* g_joy = uiNewGroup("Joystick");
@@ -410,7 +429,7 @@ void Open(int type)
uiGridAppend(b_joy, uiControl(label), 0, i, 1, 1, 1, uiAlignStart, 1, uiAlignCenter);
uiControlSetMinSize(uiControl(label), width, 1);
- char keyname[16];
+ char keyname[32];
JoyMappingName(dlg->joymap[j], keyname);
uiButton* btn = uiNewButton(keyname);
@@ -450,5 +469,13 @@ void Open(int type)
uiControlShow(uiControl(dlg->win));
}
+void Close(int type)
+{
+ if (openedmask & (1<<type))
+ uiControlDestroy(uiControl(inputdlg[type].win));
+
+ openedmask &= ~(1<<type);
+}
+
}
diff --git a/src/libui_sdl/DlgInputConfig.h b/src/libui_sdl/DlgInputConfig.h
index 9a73f37..94c7325 100644
--- a/src/libui_sdl/DlgInputConfig.h
+++ b/src/libui_sdl/DlgInputConfig.h
@@ -23,6 +23,7 @@ namespace DlgInputConfig
{
void Open(int type);
+void Close(int type);
}
diff --git a/src/libui_sdl/DlgVideoSettings.cpp b/src/libui_sdl/DlgVideoSettings.cpp
new file mode 100644
index 0000000..7d876e2
--- /dev/null
+++ b/src/libui_sdl/DlgVideoSettings.cpp
@@ -0,0 +1,324 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ This file is part of melonDS.
+
+ melonDS 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 3 of the License, or (at your option)
+ any later version.
+
+ melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libui/ui.h"
+
+#include "../types.h"
+#include "PlatformConfig.h"
+
+#include "DlgVideoSettings.h"
+
+
+void ApplyNewSettings(int type);
+
+
+namespace DlgVideoSettings
+{
+
+bool opened;
+uiWindow* win;
+
+uiRadioButtons* rbRenderer;
+uiCheckbox* cbGLDisplay;
+uiCheckbox* cbThreaded3D;
+uiCombobox* cbResolution;
+uiCheckbox* cbAntialias;
+
+int old_renderer;
+int old_gldisplay;
+int old_threaded3D;
+int old_resolution;
+int old_antialias;
+
+
+void UpdateControls()
+{
+ int renderer = uiRadioButtonsSelected(rbRenderer);
+
+ if (renderer == 0)
+ {
+ uiControlEnable(uiControl(cbGLDisplay));
+ uiControlEnable(uiControl(cbThreaded3D));
+ uiControlDisable(uiControl(cbResolution));
+ //uiControlDisable(uiControl(cbAntialias));
+ }
+ else
+ {
+ uiControlDisable(uiControl(cbGLDisplay));
+ uiControlDisable(uiControl(cbThreaded3D));
+ uiControlEnable(uiControl(cbResolution));
+ //uiControlEnable(uiControl(cbAntialias));
+ }
+}
+
+void RevertSettings()
+{
+ bool apply0 = false;
+ bool apply2 = false;
+ bool apply3 = false;
+
+ bool old_usegl = (old_gldisplay != 0) || (old_renderer != 0);
+ bool new_usegl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
+
+ if (old_renderer != Config::_3DRenderer)
+ {
+ Config::_3DRenderer = old_renderer;
+ apply3 = true;
+ }
+
+ if (old_gldisplay != Config::ScreenUseGL)
+ {
+ Config::ScreenUseGL = old_gldisplay;
+ }
+ if (old_usegl != new_usegl)
+ {
+ apply2 = true;
+ }
+
+ if (old_threaded3D != Config::Threaded3D)
+ {
+ Config::Threaded3D = old_threaded3D;
+ apply0 = true;
+ }
+
+ if (old_resolution != Config::GL_ScaleFactor ||
+ old_antialias != Config::GL_Antialias)
+ {
+ Config::GL_ScaleFactor = old_resolution;
+ Config::GL_Antialias = old_antialias;
+ apply0 = true;
+ }
+
+ if (apply2) ApplyNewSettings(2);
+ else if (apply3) ApplyNewSettings(3);
+ if (apply0) ApplyNewSettings(0);
+}
+
+
+int OnCloseWindow(uiWindow* window, void* blarg)
+{
+ RevertSettings();
+ opened = false;
+ return 1;
+}
+
+void OnRendererChanged(uiRadioButtons* rb, void* blarg)
+{
+ int id = uiRadioButtonsSelected(rb);
+ bool old_usegl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
+
+ Config::_3DRenderer = id;
+ UpdateControls();
+
+ bool new_usegl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
+ if (new_usegl != old_usegl)
+ ApplyNewSettings(2);
+ else
+ ApplyNewSettings(3);
+
+ uiControlSetFocus(uiControl(win));
+}
+
+void OnGLDisplayChanged(uiCheckbox* cb, void* blarg)
+{
+ Config::ScreenUseGL = uiCheckboxChecked(cb);
+ ApplyNewSettings(2);
+ uiControlSetFocus(uiControl(win));
+}
+
+void OnThreaded3DChanged(uiCheckbox* cb, void* blarg)
+{
+ Config::Threaded3D = uiCheckboxChecked(cb);
+ ApplyNewSettings(0);
+}
+
+void OnResolutionChanged(uiCombobox* cb, void* blarg)
+{
+ int id = uiComboboxSelected(cb);
+
+ Config::GL_ScaleFactor = id+1;
+ ApplyNewSettings(0);
+}
+
+void OnAntialiasChanged(uiCheckbox* cb, void* blarg)
+{
+ Config::GL_Antialias = uiCheckboxChecked(cb);
+ ApplyNewSettings(0);
+}
+
+void OnCancel(uiButton* btn, void* blarg)
+{
+ RevertSettings();
+
+ uiControlDestroy(uiControl(win));
+ opened = false;
+}
+
+void OnOk(uiButton* btn, void* blarg)
+{
+ Config::Save();
+
+ uiControlDestroy(uiControl(win));
+ opened = false;
+}
+
+void Open()
+{
+ if (opened)
+ {
+ uiControlSetFocus(uiControl(win));
+ return;
+ }
+
+ opened = true;
+ win = uiNewWindow("Video settings - melonDS", 400, 100, 0, 0, 0);
+ uiWindowSetMargined(win, 1);
+ uiWindowOnClosing(win, OnCloseWindow, NULL);
+
+ uiBox* top = uiNewVerticalBox();
+ uiWindowSetChild(win, uiControl(top));
+ uiBoxSetPadded(top, 1);
+
+ uiBox* splitter = uiNewHorizontalBox();
+ uiBoxAppend(top, uiControl(splitter), 0);
+ uiBoxSetPadded(splitter, 1);
+
+ uiBox* left = uiNewVerticalBox();
+ uiBoxAppend(splitter, uiControl(left), 1);
+ uiBoxSetPadded(left, 1);
+ uiBox* right = uiNewVerticalBox();
+ uiBoxAppend(splitter, uiControl(right), 1);
+ uiBoxSetPadded(right, 1);
+
+ {
+ uiGroup* grp = uiNewGroup("Display settings");
+ uiBoxAppend(left, uiControl(grp), 0);
+ uiGroupSetMargined(grp, 1);
+
+ uiBox* in_ctrl = uiNewVerticalBox();
+ uiGroupSetChild(grp, uiControl(in_ctrl));
+
+ uiLabel* lbl = uiNewLabel("3D renderer:");
+ uiBoxAppend(in_ctrl, uiControl(lbl), 0);
+
+ rbRenderer = uiNewRadioButtons();
+ uiRadioButtonsAppend(rbRenderer, "Software");
+ uiRadioButtonsAppend(rbRenderer, "OpenGL");
+ uiRadioButtonsOnSelected(rbRenderer, OnRendererChanged, NULL);
+ uiBoxAppend(in_ctrl, uiControl(rbRenderer), 0);
+
+ lbl = uiNewLabel("");
+ uiBoxAppend(in_ctrl, uiControl(lbl), 0);
+
+ cbGLDisplay = uiNewCheckbox("OpenGL display");
+ uiCheckboxOnToggled(cbGLDisplay, OnGLDisplayChanged, NULL);
+ uiBoxAppend(in_ctrl, uiControl(cbGLDisplay), 0);
+ }
+
+ {
+ uiGroup* grp = uiNewGroup("Software renderer");
+ uiBoxAppend(right, uiControl(grp), 0);
+ uiGroupSetMargined(grp, 1);
+
+ uiBox* in_ctrl = uiNewVerticalBox();
+ uiGroupSetChild(grp, uiControl(in_ctrl));
+
+ cbThreaded3D = uiNewCheckbox("Threaded");
+ uiCheckboxOnToggled(cbThreaded3D, OnThreaded3DChanged, NULL);
+ uiBoxAppend(in_ctrl, uiControl(cbThreaded3D), 0);
+ }
+
+ {
+ uiGroup* grp = uiNewGroup("OpenGL renderer");
+ uiBoxAppend(right, uiControl(grp), 0);
+ uiGroupSetMargined(grp, 1);
+
+ uiBox* in_ctrl = uiNewVerticalBox();
+ uiGroupSetChild(grp, uiControl(in_ctrl));
+
+ uiLabel* lbl = uiNewLabel("Internal resolution:");
+ uiBoxAppend(in_ctrl, uiControl(lbl), 0);
+
+ cbResolution = uiNewCombobox();
+ uiComboboxOnSelected(cbResolution, OnResolutionChanged, NULL);
+ for (int i = 1; i <= 8; i++)
+ {
+ char txt[64];
+ sprintf(txt, "%dx native (%dx%d)", i, 256*i, 192*i);
+ uiComboboxAppend(cbResolution, txt);
+ }
+ uiBoxAppend(in_ctrl, uiControl(cbResolution), 0);
+
+ //lbl = uiNewLabel("");
+ //uiBoxAppend(in_ctrl, uiControl(lbl), 0);
+
+ //cbAntialias = uiNewCheckbox("Antialiasing");
+ //uiCheckboxOnToggled(cbAntialias, OnAntialiasChanged, NULL);
+ //uiBoxAppend(in_ctrl, uiControl(cbAntialias), 0);
+ }
+
+ {
+ uiBox* in_ctrl = uiNewHorizontalBox();
+ uiBoxSetPadded(in_ctrl, 1);
+ uiBoxAppend(top, uiControl(in_ctrl), 0);
+
+ uiLabel* dummy = uiNewLabel("");
+ uiBoxAppend(in_ctrl, uiControl(dummy), 1);
+
+ uiButton* btncancel = uiNewButton("Cancel");
+ uiButtonOnClicked(btncancel, OnCancel, NULL);
+ uiBoxAppend(in_ctrl, uiControl(btncancel), 0);
+
+ uiButton* btnok = uiNewButton("Ok");
+ uiButtonOnClicked(btnok, OnOk, NULL);
+ uiBoxAppend(in_ctrl, uiControl(btnok), 0);
+ }
+
+ Config::_3DRenderer = Config::_3DRenderer ? 1 : 0;
+
+ if (Config::GL_ScaleFactor < 1) Config::GL_ScaleFactor = 1;
+ else if (Config::GL_ScaleFactor > 8) Config::GL_ScaleFactor = 8;
+
+ old_renderer = Config::_3DRenderer;
+ old_gldisplay = Config::ScreenUseGL;
+ old_threaded3D = Config::Threaded3D;
+ old_resolution = Config::GL_ScaleFactor;
+ old_antialias = Config::GL_Antialias;
+
+ uiCheckboxSetChecked(cbGLDisplay, Config::ScreenUseGL);
+ uiCheckboxSetChecked(cbThreaded3D, Config::Threaded3D);
+ uiComboboxSetSelected(cbResolution, Config::GL_ScaleFactor-1);
+ //uiCheckboxSetChecked(cbAntialias, Config::GL_Antialias);
+ uiRadioButtonsSetSelected(rbRenderer, Config::_3DRenderer);
+ UpdateControls();
+
+ uiControlShow(uiControl(win));
+}
+
+void Close()
+{
+ if (!opened) return;
+ uiControlDestroy(uiControl(win));
+ opened = false;
+}
+
+}
diff --git a/src/libui_sdl/DlgVideoSettings.h b/src/libui_sdl/DlgVideoSettings.h
new file mode 100644
index 0000000..25a938f
--- /dev/null
+++ b/src/libui_sdl/DlgVideoSettings.h
@@ -0,0 +1,30 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ This file is part of melonDS.
+
+ melonDS 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 3 of the License, or (at your option)
+ any later version.
+
+ melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef DLGVIDEOSETTINGS_H
+#define DLGVIDEOSETTINGS_H
+
+namespace DlgVideoSettings
+{
+
+void Open();
+void Close();
+
+}
+
+#endif // DLGVIDEOSETTINGS_H
diff --git a/src/libui_sdl/DlgWifiSettings.cpp b/src/libui_sdl/DlgWifiSettings.cpp
index e16ce50..09080a0 100644
--- a/src/libui_sdl/DlgWifiSettings.cpp
+++ b/src/libui_sdl/DlgWifiSettings.cpp
@@ -261,4 +261,11 @@ void Open()
uiControlShow(uiControl(win));
}
+void Close()
+{
+ if (!opened) return;
+ uiControlDestroy(uiControl(win));
+ opened = false;
+}
+
}
diff --git a/src/libui_sdl/DlgWifiSettings.h b/src/libui_sdl/DlgWifiSettings.h
index f7b7398..466ce10 100644
--- a/src/libui_sdl/DlgWifiSettings.h
+++ b/src/libui_sdl/DlgWifiSettings.h
@@ -23,6 +23,7 @@ namespace DlgWifiSettings
{
void Open();
+void Close();
}
diff --git a/src/libui_sdl/OSD.cpp b/src/libui_sdl/OSD.cpp
new file mode 100644
index 0000000..c8d5f83
--- /dev/null
+++ b/src/libui_sdl/OSD.cpp
@@ -0,0 +1,423 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ This file is part of melonDS.
+
+ melonDS 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 3 of the License, or (at your option)
+ any later version.
+
+ melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <deque>
+#include <SDL2/SDL.h>
+#include "../types.h"
+
+#include "libui/ui.h"
+#include "../OpenGLSupport.h"
+
+#include "OSD.h"
+#include "font.h"
+
+extern int WindowWidth, WindowHeight;
+
+namespace OSD
+{
+
+const u32 kOSDMargin = 6;
+
+struct Item
+{
+ Uint32 Timestamp;
+ char Text[256];
+ u32 Color;
+
+ u32 Width, Height;
+ u32* Bitmap;
+
+ bool DrawBitmapLoaded;
+ uiDrawBitmap* DrawBitmap;
+
+ bool GLTextureLoaded;
+ GLuint GLTexture;
+
+};
+
+std::deque<Item> ItemQueue;
+
+GLint uOSDPos, uOSDSize;
+GLuint OSDVertexArray;
+GLuint OSDVertexBuffer;
+
+volatile bool Rendering;
+
+
+bool Init(bool opengl)
+{
+ if (opengl)
+ {
+ GLuint prog; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&prog);
+ uOSDPos = glGetUniformLocation(prog, "uOSDPos");
+ uOSDSize = glGetUniformLocation(prog, "uOSDSize");
+
+ float vertices[6*2] =
+ {
+ 0, 0,
+ 1, 1,
+ 1, 0,
+ 0, 0,
+ 0, 1,
+ 1, 1
+ };
+
+ glGenBuffers(1, &OSDVertexBuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, OSDVertexBuffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
+
+ glGenVertexArrays(1, &OSDVertexArray);
+ glBindVertexArray(OSDVertexArray);
+ glEnableVertexAttribArray(0); // position
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)(0));
+ }
+
+ return true;
+}
+
+void DeInit(bool opengl)
+{
+ for (auto it = ItemQueue.begin(); it != ItemQueue.end(); )
+ {
+ Item& item = *it;
+
+ if (item.DrawBitmapLoaded && item.DrawBitmap) uiDrawFreeBitmap(item.DrawBitmap);
+ if (item.GLTextureLoaded && opengl) glDeleteTextures(1, &item.GLTexture);
+ if (item.Bitmap) delete[] item.Bitmap;
+
+ it = ItemQueue.erase(it);
+ }
+}
+
+
+int FindBreakPoint(const char* text, int i)
+{
+ // i = character that went out of bounds
+
+ for (int j = i; j >= 0; j--)
+ {
+ if (text[j] == ' ')
+ return j;
+ }
+
+ return i;
+}
+
+void LayoutText(const char* text, u32* width, u32* height, int* breaks)
+{
+ u32 w = 0;
+ u32 h = 14;
+ u32 totalw = 0;
+ u32 maxw = WindowWidth - (kOSDMargin*2);
+ int lastbreak = -1;
+ int numbrk = 0;
+ u16* ptr;
+
+ memset(breaks, 0, sizeof(int)*64);
+
+ for (int i = 0; text[i] != '\0'; )
+ {
+ int glyphsize;
+ if (text[i] == ' ')
+ {
+ glyphsize = 6;
+ }
+ else
+ {
+ u32 ch = text[i];
+ if (ch < 0x10 || ch > 0x7E) ch = 0x7F;
+
+ ptr = &font[(ch-0x10) << 4];
+ glyphsize = ptr[0];
+ if (!glyphsize) glyphsize = 6;
+ else glyphsize += 2; // space around the character
+ }
+
+ w += glyphsize;
+ if (w > maxw)
+ {
+ // wrap shit as needed
+ if (text[i] == ' ')
+ {
+ if (numbrk >= 64) break;
+ breaks[numbrk++] = i;
+ i++;
+ }
+ else
+ {
+ int brk = FindBreakPoint(text, i);
+ if (brk != lastbreak) i = brk;
+
+ if (numbrk >= 64) break;
+ breaks[numbrk++] = i;
+
+ lastbreak = brk;
+ }
+
+ w = 0;
+ h += 14;
+ }
+ else
+ i++;
+
+ if (w > totalw) totalw = w;
+ }
+
+ *width = totalw;
+ *height = h;
+}
+
+u32 RainbowColor(u32 inc)
+{
+ // inspired from Acmlmboard
+
+ if (inc < 100) return 0xFFFF9B9B + (inc << 8);
+ else if (inc < 200) return 0xFFFFFF9B - ((inc-100) << 16);
+ else if (inc < 300) return 0xFF9BFF9B + (inc-200);
+ else if (inc < 400) return 0xFF9BFFFF - ((inc-300) << 8);
+ else if (inc < 500) return 0xFF9B9BFF + ((inc-400) << 16);
+ else return 0xFFFF9BFF - (inc-500);
+}
+
+void RenderText(u32 color, const char* text, Item* item)
+{
+ u32 w, h;
+ int breaks[64];
+
+ bool rainbow = (color == 0);
+ u32 rainbowinc = (text[0] * 17) % 600;
+
+ color |= 0xFF000000;
+ const u32 shadow = 0xE0000000;
+
+ LayoutText(text, &w, &h, breaks);
+
+ item->Width = w;
+ item->Height = h;
+ item->Bitmap = new u32[w*h];
+ memset(item->Bitmap, 0, w*h*sizeof(u32));
+
+ u32 x = 0, y = 1;
+ u32 maxw = WindowWidth - (kOSDMargin*2);
+ int curline = 0;
+ u16* ptr;
+
+ for (int i = 0; text[i] != '\0'; )
+ {
+ int glyphsize;
+ if (text[i] == ' ')
+ {
+ x += 6;
+ }
+ else
+ {
+ u32 ch = text[i];
+ if (ch < 0x10 || ch > 0x7E) ch = 0x7F;
+
+ ptr = &font[(ch-0x10) << 4];
+ int glyphsize = ptr[0];
+ if (!glyphsize) x += 6;
+ else
+ {
+ x++;
+
+ if (rainbow)
+ {
+ color = RainbowColor(rainbowinc);
+ rainbowinc = (rainbowinc + 30) % 600;
+ }
+
+ // draw character
+ for (int cy = 0; cy < 12; cy++)
+ {
+ u16 val = ptr[4+cy];
+
+ for (int cx = 0; cx < glyphsize; cx++)
+ {
+ if (val & (1<<cx))
+ item->Bitmap[((y+cy) * w) + x+cx] = color;
+ }
+ }
+
+ x += glyphsize;
+ x++;
+ }
+ }
+
+ i++;
+ if (breaks[curline] && i >= breaks[curline])
+ {
+ i = breaks[curline++];
+ if (text[i] == ' ') i++;
+
+ x = 0;
+ y += 14;
+ }
+ }
+
+ // shadow
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ u32 val;
+
+ val = item->Bitmap[(y * w) + x];
+ if ((val >> 24) == 0xFF) continue;
+
+ if (x > 0) val = item->Bitmap[(y * w) + x-1];
+ if (x < w-1) val |= item->Bitmap[(y * w) + x+1];
+ if (y > 0)
+ {
+ if (x > 0) val |= item->Bitmap[((y-1) * w) + x-1];
+ val |= item->Bitmap[((y-1) * w) + x];
+ if (x < w-1) val |= item->Bitmap[((y-1) * w) + x+1];
+ }
+ if (y < h-1)
+ {
+ if (x > 0) val |= item->Bitmap[((y+1) * w) + x-1];
+ val |= item->Bitmap[((y+1) * w) + x];
+ if (x < w-1) val |= item->Bitmap[((y+1) * w) + x+1];
+ }
+
+ if ((val >> 24) == 0xFF)
+ item->Bitmap[(y * w) + x] = shadow;
+ }
+ }
+}
+
+
+void AddMessage(u32 color, const char* text)
+{
+ while (Rendering);
+
+ Item item;
+
+ item.Timestamp = SDL_GetTicks();
+ strncpy(item.Text, text, 255); item.Text[255] = '\0';
+ item.Color = color;
+ item.Bitmap = NULL;
+
+ item.DrawBitmapLoaded = false;
+ item.GLTextureLoaded = false;
+
+ ItemQueue.push_back(item);
+}
+
+void WindowResized(bool opengl)
+{
+ /*for (auto it = ItemQueue.begin(); it != ItemQueue.end(); )
+ {
+ Item& item = *it;
+
+ if (item->DrawBitmapLoaded && item->DrawBitmap) uiDrawFreeBitmap(item->DrawBitmap);
+ //if (item->GLTextureLoaded && opengl) glDeleteTextures(1, &item->GLTexture);
+
+ item->DrawBitmapLoaded = false;
+ item->GLTextureLoaded = false;
+
+ if (item->Bitmap) delete[] item->Bitmap;
+
+ it++;
+ }*/
+}
+
+void Update(bool opengl, uiAreaDrawParams* params)
+{
+ Rendering = true;
+
+ Uint32 tick_now = SDL_GetTicks();
+ Uint32 tick_min = tick_now - 2500;
+ u32 y = kOSDMargin;
+
+ if (opengl)
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, OSDVertexBuffer);
+ glBindVertexArray(OSDVertexArray);
+
+ glActiveTexture(GL_TEXTURE0);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ for (auto it = ItemQueue.begin(); it != ItemQueue.end(); )
+ {
+ Item& item = *it;
+
+ if (item.Timestamp < tick_min)
+ {
+ if (item.DrawBitmapLoaded && item.DrawBitmap) uiDrawFreeBitmap(item.DrawBitmap);
+ if (item.GLTextureLoaded && opengl) glDeleteTextures(1, &item.GLTexture);
+ if (item.Bitmap) delete[] item.Bitmap;
+
+ it = ItemQueue.erase(it);
+ continue;
+ }
+
+ if (!item.Bitmap)
+ {
+ RenderText(item.Color, item.Text, &item);
+ }
+
+ if (opengl)
+ {
+ if (!item.GLTextureLoaded)
+ {
+ glGenTextures(1, &item.GLTexture);
+ glBindTexture(GL_TEXTURE_2D, item.GLTexture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, item.Width, item.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, item.Bitmap);
+
+ item.GLTextureLoaded = true;
+ }
+
+ glBindTexture(GL_TEXTURE_2D, item.GLTexture);
+ glUniform2i(uOSDPos, kOSDMargin, y);
+ glUniform2i(uOSDSize, item.Width, item.Height);
+ glDrawArrays(GL_TRIANGLES, 0, 2*3);
+ }
+ else
+ {
+ if (!item.DrawBitmapLoaded)
+ {
+ item.DrawBitmap = uiDrawNewBitmap(params->Context, item.Width, item.Height, 1);
+ uiDrawBitmapUpdate(item.DrawBitmap, item.Bitmap);
+
+ item.DrawBitmapLoaded = true;
+ }
+
+ uiRect rc_src = {0, 0, item.Width, item.Height};
+ uiRect rc_dst = {kOSDMargin, y, item.Width, item.Height};
+
+ uiDrawBitmapDraw(params->Context, item.DrawBitmap, &rc_src, &rc_dst, 0);
+ }
+
+ y += item.Height;
+ it++;
+ }
+
+ Rendering = false;
+}
+
+}
diff --git a/src/libui_sdl/OSD.h b/src/libui_sdl/OSD.h
new file mode 100644
index 0000000..afe403f
--- /dev/null
+++ b/src/libui_sdl/OSD.h
@@ -0,0 +1,35 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ This file is part of melonDS.
+
+ melonDS 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 3 of the License, or (at your option)
+ any later version.
+
+ melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef OSD_H
+#define OSD_H
+
+namespace OSD
+{
+
+bool Init(bool opengl);
+void DeInit(bool opengl);
+
+void AddMessage(u32 color, const char* text);
+
+void WindowResized(bool opengl);
+void Update(bool opengl, uiAreaDrawParams* params);
+
+}
+
+#endif // OSD_H
diff --git a/src/libui_sdl/Platform.cpp b/src/libui_sdl/Platform.cpp
index 6ebe8c3..94b3791 100644
--- a/src/libui_sdl/Platform.cpp
+++ b/src/libui_sdl/Platform.cpp
@@ -24,6 +24,7 @@
#include "PlatformConfig.h"
#include "LAN_Socket.h"
#include "LAN_PCap.h"
+#include "libui/ui.h"
#include <string>
#ifdef __WIN32__
@@ -166,7 +167,7 @@ FILE* OpenLocalFile(const char* path, const char* mode)
int len = emudirlen + 1 + pathlen + 1;
emudirpath = new char[len];
strncpy(&emudirpath[0], EmuDirectory, emudirlen);
- emudirpath[emudirlen] = '\\';
+ emudirpath[emudirlen] = '/';
strncpy(&emudirpath[emudirlen+1], path, pathlen);
emudirpath[emudirlen+1+pathlen] = '\0';
}
@@ -302,6 +303,12 @@ void Semaphore_Post(void* sema)
}
+void* GL_GetProcAddress(const char* proc)
+{
+ return uiGLGetProcAddress(proc);
+}
+
+
bool MP_Init()
{
int opt_true = 1;
diff --git a/src/libui_sdl/PlatformConfig.cpp b/src/libui_sdl/PlatformConfig.cpp
index 335fe3e..5708fc8 100644
--- a/src/libui_sdl/PlatformConfig.cpp
+++ b/src/libui_sdl/PlatformConfig.cpp
@@ -40,6 +40,9 @@ int ScreenLayout;
int ScreenSizing;
int ScreenFilter;
+int ScreenUseGL;
+int ScreenRatio;
+
int LimitFPS;
int DirectBoot;
@@ -85,10 +88,10 @@ ConfigEntry PlatformConfigFile[] =
{"Joy_X", 0, &JoyMapping[10], -1, NULL, 0},
{"Joy_Y", 0, &JoyMapping[11], -1, NULL, 0},
- {"HKKey_Lid", 0, &HKKeyMapping[HK_Lid], 0x0E, NULL, 0},
+ {"HKKey_Lid", 0, &HKKeyMapping[HK_Lid], 0x0D, NULL, 0},
{"HKKey_Mic", 0, &HKKeyMapping[HK_Mic], 0x35, NULL, 0},
{"HKKey_FastForward", 0, &HKKeyMapping[HK_FastForward], 0x0F, NULL, 0},
- {"HKKey_FastForwardToggle", 0, &HKKeyMapping[HK_FastForwardToggle], -1, NULL, 0}, // TODO: This doesn't unbind the key, just sets it to some random key
+ {"HKKey_FastForwardToggle", 0, &HKKeyMapping[HK_FastForwardToggle], -1, NULL, 0},
{"HKJoy_Lid", 0, &HKJoyMapping[HK_Lid], -1, NULL, 0},
{"HKJoy_Mic", 0, &HKJoyMapping[HK_Mic], -1, NULL, 0},
@@ -105,6 +108,9 @@ ConfigEntry PlatformConfigFile[] =
{"ScreenSizing", 0, &ScreenSizing, 0, NULL, 0},
{"ScreenFilter", 0, &ScreenFilter, 1, NULL, 0},
+ {"ScreenUseGL", 0, &ScreenUseGL, 1, NULL, 0},
+ {"ScreenRatio", 0, &ScreenRatio, 0, NULL, 0},
+
{"LimitFPS", 0, &LimitFPS, 1, NULL, 0},
{"DirectBoot", 0, &DirectBoot, 1, NULL, 0},
diff --git a/src/libui_sdl/PlatformConfig.h b/src/libui_sdl/PlatformConfig.h
index ce49b12..be29c17 100644
--- a/src/libui_sdl/PlatformConfig.h
+++ b/src/libui_sdl/PlatformConfig.h
@@ -49,6 +49,9 @@ extern int ScreenLayout;
extern int ScreenSizing;
extern int ScreenFilter;
+extern int ScreenUseGL;
+extern int ScreenRatio;
+
extern int LimitFPS;
extern int DirectBoot;
diff --git a/src/libui_sdl/font.h b/src/libui_sdl/font.h
new file mode 100644
index 0000000..8647b7a
--- /dev/null
+++ b/src/libui_sdl/font.h
@@ -0,0 +1,135 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ This file is part of melonDS.
+
+ melonDS 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 3 of the License, or (at your option)
+ any later version.
+
+ melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef FONT_H
+#define FONT_H
+unsigned short font[] = {
+ 12, 0, 0, 0,0x0C03, 0x0E07, 0x070E, 0x039C, 0x01F8, 0x00F0, 0x00F0, 0x01F8, 0x039C, 0x070E, 0x0E07, 0x0C03,
+ 12, 0, 0, 0,0x01C0, 0x00E0, 0x0060, 0x0860, 0x0C60, 0x0FE0, 0x07F0, 0x0038, 0x001C, 0x000E, 0x0007, 0x0003,
+ 12, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 12, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 12, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 12, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 12, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 12, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 12, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 12, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 12, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 12, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 12, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 12, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 12, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 12, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0,0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0000, 0x0000, 0x0003, 0x0003, 0x0000, 0x0000,
+ 9, 0, 0, 0,0x01EF, 0x01EF, 0x018C, 0x01CE, 0x00E7, 0x0063, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x00CC, 0x00CC, 0x03FF, 0x03FF, 0x00CC, 0x00CC, 0x03FF, 0x03FF, 0x00CC, 0x00CC, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x0018, 0x00FE, 0x00FF, 0x001B, 0x007F, 0x00FE, 0x00D8, 0x00FF, 0x007F, 0x0018, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0306, 0x038F, 0x01CF, 0x00E6, 0x0070, 0x0038, 0x019C, 0x03CE, 0x03C7, 0x0183, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x007C, 0x00FE, 0x00C6, 0x00EE, 0x007C, 0x037E, 0x03E7, 0x01F3, 0x03BF, 0x031E, 0x0000, 0x0000,
+ 4, 0, 0, 0,0x000F, 0x000F, 0x000C, 0x000E, 0x0007, 0x0003, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 4, 0, 0, 0,0x000C, 0x000E, 0x0007, 0x0003, 0x0003, 0x0003, 0x0003, 0x0007, 0x000E, 0x000C, 0x0000, 0x0000,
+ 4, 0, 0, 0,0x0003, 0x0007, 0x000E, 0x000C, 0x000C, 0x000C, 0x000C, 0x000E, 0x0007, 0x0003, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0030, 0x0333, 0x03B7, 0x01FE, 0x00FC, 0x00FC, 0x01FE, 0x03B7, 0x0333, 0x0030, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0030, 0x0030, 0x0030, 0x0030, 0x03FF, 0x03FF, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000, 0x0000,
+ 4, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x000F, 0x000F, 0x000C, 0x000E, 0x0007, 0x0003,
+ 10, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x03FF, 0x03FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 3, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0007, 0x0007, 0x0007, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0300, 0x0380, 0x01C0, 0x00E0, 0x0070, 0x0038, 0x001C, 0x000E, 0x0007, 0x0003, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x007E, 0x00FF, 0x00C3, 0x00C3, 0x00C3, 0x00C3, 0x00C3, 0x00C3, 0x00FF, 0x007E, 0x0000, 0x0000,
+ 4, 0, 0, 0,0x0006, 0x0007, 0x0007, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x000F, 0x000F, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x007E, 0x00FF, 0x00C3, 0x00C0, 0x00FE, 0x007F, 0x0003, 0x0003, 0x00FF, 0x00FF, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x007F, 0x00FF, 0x00C0, 0x00C0, 0x007C, 0x00FC, 0x00C0, 0x00C0, 0x00FF, 0x007F, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x0063, 0x0063, 0x0063, 0x0063, 0x0063, 0x0063, 0x00FF, 0x00FE, 0x0060, 0x0060, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x00FF, 0x00FF, 0x0003, 0x0003, 0x007F, 0x00FF, 0x00C0, 0x00C0, 0x00FF, 0x007F, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x007E, 0x007F, 0x0003, 0x0003, 0x007F, 0x00FF, 0x00C3, 0x00C3, 0x00FF, 0x007E, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x00FF, 0x00FF, 0x00C0, 0x00E0, 0x0070, 0x0038, 0x001C, 0x000C, 0x000C, 0x000C, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x007E, 0x00FF, 0x00C3, 0x00C3, 0x007E, 0x00FF, 0x00C3, 0x00C3, 0x00FF, 0x007E, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x007E, 0x00FF, 0x00C3, 0x00C3, 0x00FF, 0x00FE, 0x00C0, 0x00C0, 0x00FE, 0x007E, 0x0000, 0x0000,
+ 3, 0, 0, 0,0x0000, 0x0000, 0x0007, 0x0007, 0x0000, 0x0000, 0x0000, 0x0007, 0x0007, 0x0000, 0x0000, 0x0000,
+ 4, 0, 0, 0,0x0000, 0x0000, 0x000E, 0x000E, 0x0000, 0x0000, 0x000C, 0x000E, 0x0007, 0x0003, 0x0000, 0x0000,
+ 6, 0, 0, 0,0x0030, 0x0038, 0x001C, 0x000E, 0x0007, 0x0007, 0x000E, 0x001C, 0x0038, 0x0030, 0x0000, 0x0000,
+ 7, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x007F, 0x007F, 0x0000, 0x0000, 0x007F, 0x007F, 0x0000, 0x0000, 0x0000,
+ 6, 0, 0, 0,0x0003, 0x0007, 0x000E, 0x001C, 0x0038, 0x0038, 0x001C, 0x000E, 0x0007, 0x0003, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x007E, 0x00FF, 0x00C3, 0x00C3, 0x00F0, 0x0078, 0x0018, 0x0000, 0x0018, 0x0018, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x00FC, 0x01FE, 0x0387, 0x0333, 0x037B, 0x03FB, 0x01F3, 0x0007, 0x03FE, 0x03FC, 0x0000, 0x0000,
+ 9, 0, 0, 0,0x00FE, 0x01FF, 0x0183, 0x0183, 0x0183, 0x01FF, 0x01FF, 0x0183, 0x0183, 0x0183, 0x0000, 0x0000,
+ 9, 0, 0, 0,0x00FF, 0x01FF, 0x0183, 0x0183, 0x00FF, 0x01FF, 0x0183, 0x0183, 0x01FF, 0x00FF, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x00FE, 0x00FF, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x00FF, 0x00FE, 0x0000, 0x0000,
+ 9, 0, 0, 0,0x007F, 0x00FF, 0x01C3, 0x0183, 0x0183, 0x0183, 0x0183, 0x01C3, 0x00FF, 0x007F, 0x0000, 0x0000,
+ 9, 0, 0, 0,0x01FF, 0x01FF, 0x0003, 0x0003, 0x00FF, 0x00FF, 0x0003, 0x0003, 0x01FF, 0x01FF, 0x0000, 0x0000,
+ 9, 0, 0, 0,0x01FF, 0x01FF, 0x0003, 0x0003, 0x00FF, 0x00FF, 0x0003, 0x0003, 0x0003, 0x0003, 0x0000, 0x0000,
+ 9, 0, 0, 0,0x01FE, 0x01FF, 0x0003, 0x0003, 0x01F3, 0x01F3, 0x0183, 0x0183, 0x01FF, 0x00FE, 0x0000, 0x0000,
+ 9, 0, 0, 0,0x0183, 0x0183, 0x0183, 0x0183, 0x01FF, 0x01FF, 0x0183, 0x0183, 0x0183, 0x0183, 0x0000, 0x0000,
+ 6, 0, 0, 0,0x003F, 0x003F, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, 0x003F, 0x003F, 0x0000, 0x0000,
+ 9, 0, 0, 0,0x01F0, 0x01F0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C3, 0x00C3, 0x00FF, 0x007E, 0x0000, 0x0000,
+ 9, 0, 0, 0,0x0183, 0x01C3, 0x00E3, 0x0073, 0x003F, 0x003F, 0x0073, 0x00E3, 0x01C3, 0x0183, 0x0000, 0x0000,
+ 7, 0, 0, 0,0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x007F, 0x007F, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0303, 0x0387, 0x03CF, 0x03FF, 0x037B, 0x0333, 0x0303, 0x0303, 0x0303, 0x0303, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0303, 0x0307, 0x030F, 0x031F, 0x033B, 0x0373, 0x03E3, 0x03C3, 0x0383, 0x0303, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x01FE, 0x03FF, 0x0303, 0x0303, 0x0303, 0x0303, 0x0303, 0x0303, 0x03FF, 0x01FE, 0x0000, 0x0000,
+ 9, 0, 0, 0,0x00FF, 0x01FF, 0x0183, 0x0183, 0x01FF, 0x00FF, 0x0003, 0x0003, 0x0003, 0x0003, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x01FE, 0x03FF, 0x0303, 0x0303, 0x0333, 0x0373, 0x03E3, 0x01C3, 0x03FF, 0x037E, 0x0000, 0x0000,
+ 9, 0, 0, 0,0x00FF, 0x01FF, 0x0183, 0x0183, 0x01FF, 0x00FF, 0x0073, 0x00E3, 0x01C3, 0x0183, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x01FE, 0x01FF, 0x0003, 0x0003, 0x01FF, 0x03FE, 0x0300, 0x0300, 0x03FE, 0x01FE, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x03FF, 0x03FF, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000, 0x0000,
+ 9, 0, 0, 0,0x0183, 0x0183, 0x0183, 0x0183, 0x0183, 0x0183, 0x0183, 0x0183, 0x01FF, 0x00FE, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0303, 0x0303, 0x0303, 0x0303, 0x0303, 0x0387, 0x01CE, 0x00FC, 0x0078, 0x0030, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0303, 0x0303, 0x0303, 0x0303, 0x0333, 0x037B, 0x03FF, 0x03CF, 0x0387, 0x0303, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0303, 0x0387, 0x01CE, 0x00FC, 0x0078, 0x0078, 0x00FC, 0x01CE, 0x0387, 0x0303, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0303, 0x0387, 0x01CE, 0x00FC, 0x0078, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x03FF, 0x03FF, 0x01C0, 0x00E0, 0x0070, 0x0038, 0x001C, 0x000E, 0x03FF, 0x03FF, 0x0000, 0x0000,
+ 4, 0, 0, 0,0x000F, 0x000F, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x000F, 0x000F, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0003, 0x0007, 0x000E, 0x001C, 0x0038, 0x0070, 0x00E0, 0x01C0, 0x0380, 0x0300, 0x0000, 0x0000,
+ 4, 0, 0, 0,0x000F, 0x000F, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, 0x000F, 0x000F, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x0018, 0x003C, 0x007E, 0x00E7, 0x00C3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03FF, 0x03FF,
+ 4, 0, 0, 0,0x000F, 0x000F, 0x0003, 0x0007, 0x000E, 0x000C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 7, 0, 0, 0,0x0000, 0x0000, 0x003E, 0x007E, 0x0060, 0x007E, 0x007F, 0x0063, 0x007F, 0x007E, 0x0000, 0x0000,
+ 7, 0, 0, 0,0x0003, 0x0003, 0x0003, 0x003F, 0x007F, 0x0063, 0x0063, 0x0063, 0x007F, 0x003F, 0x0000, 0x0000,
+ 7, 0, 0, 0,0x0000, 0x0000, 0x007E, 0x007F, 0x0003, 0x0003, 0x0003, 0x0003, 0x007F, 0x007E, 0x0000, 0x0000,
+ 7, 0, 0, 0,0x0060, 0x0060, 0x0060, 0x007E, 0x007F, 0x0063, 0x0063, 0x0063, 0x007F, 0x007E, 0x0000, 0x0000,
+ 7, 0, 0, 0,0x0000, 0x0000, 0x003E, 0x007F, 0x0063, 0x007F, 0x003F, 0x0003, 0x003F, 0x003E, 0x0000, 0x0000,
+ 6, 0, 0, 0,0x003C, 0x003E, 0x0006, 0x0006, 0x001F, 0x001F, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000,
+ 7, 0, 0, 0,0x0000, 0x0000, 0x007E, 0x007F, 0x0063, 0x0063, 0x007F, 0x007E, 0x0060, 0x0060, 0x007E, 0x003E,
+ 7, 0, 0, 0,0x0003, 0x0003, 0x0003, 0x003F, 0x007F, 0x0063, 0x0063, 0x0063, 0x0063, 0x0063, 0x0000, 0x0000,
+ 2, 0, 0, 0,0x0003, 0x0003, 0x0000, 0x0000, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0000, 0x0000,
+ 7, 0, 0, 0,0x0060, 0x0060, 0x0000, 0x0000, 0x0060, 0x0060, 0x0060, 0x0060, 0x0060, 0x0063, 0x007F, 0x003E,
+ 8, 0, 0, 0,0x0003, 0x0003, 0x00E3, 0x0073, 0x003B, 0x001F, 0x001F, 0x003B, 0x0073, 0x00E3, 0x0000, 0x0000,
+ 4, 0, 0, 0,0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x000F, 0x000E, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0000, 0x0000, 0x01FF, 0x03FF, 0x0333, 0x0333, 0x0333, 0x0333, 0x0333, 0x0333, 0x0000, 0x0000,
+ 7, 0, 0, 0,0x0000, 0x0000, 0x003F, 0x007F, 0x0063, 0x0063, 0x0063, 0x0063, 0x0063, 0x0063, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x0000, 0x0000, 0x007E, 0x00FF, 0x00C3, 0x00C3, 0x00C3, 0x00C3, 0x00FF, 0x007E, 0x0000, 0x0000,
+ 7, 0, 0, 0,0x0000, 0x0000, 0x003F, 0x007F, 0x0063, 0x0063, 0x007F, 0x003F, 0x0003, 0x0003, 0x0003, 0x0003,
+ 7, 0, 0, 0,0x0000, 0x0000, 0x007E, 0x007F, 0x0063, 0x0063, 0x007F, 0x007E, 0x0060, 0x0060, 0x0060, 0x0060,
+ 7, 0, 0, 0,0x0000, 0x0000, 0x003B, 0x007F, 0x0067, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x0000, 0x0000, 0x007E, 0x007F, 0x0003, 0x007F, 0x00FE, 0x00C0, 0x00FE, 0x007E, 0x0000, 0x0000,
+ 6, 0, 0, 0,0x0006, 0x0006, 0x003F, 0x003F, 0x0006, 0x0006, 0x0006, 0x0006, 0x003E, 0x003C, 0x0000, 0x0000,
+ 7, 0, 0, 0,0x0000, 0x0000, 0x0063, 0x0063, 0x0063, 0x0063, 0x0063, 0x0063, 0x007F, 0x007E, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0000, 0x0000, 0x0303, 0x0303, 0x0303, 0x0387, 0x01CE, 0x00FC, 0x0078, 0x0030, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0000, 0x0000, 0x0303, 0x0303, 0x0333, 0x037B, 0x03FF, 0x03CF, 0x0387, 0x0303, 0x0000, 0x0000,
+ 8, 0, 0, 0,0x0000, 0x0000, 0x00C3, 0x00E7, 0x007E, 0x003C, 0x003C, 0x007E, 0x00E7, 0x00C3, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0000, 0x0000, 0x0303, 0x0307, 0x038E, 0x01DC, 0x00F8, 0x0070, 0x0038, 0x001C, 0x000E, 0x0006,
+ 8, 0, 0, 0,0x0000, 0x0000, 0x00FF, 0x00FF, 0x0070, 0x0038, 0x001C, 0x000E, 0x00FF, 0x00FF, 0x0000, 0x0000,
+ 6, 0, 0, 0,0x0038, 0x003C, 0x000C, 0x000C, 0x000F, 0x000F, 0x000C, 0x000C, 0x003C, 0x0038, 0x0000, 0x0000,
+ 2, 0, 0, 0,0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0000, 0x0000,
+ 6, 0, 0, 0,0x0007, 0x000F, 0x000C, 0x000C, 0x003C, 0x003C, 0x000C, 0x000C, 0x000F, 0x0007, 0x0000, 0x0000,
+ 10, 0, 0, 0,0x0000, 0x0000, 0x0000, 0x031C, 0x03BE, 0x01F7, 0x00E3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 11, 0, 0, 0,0x0555, 0x0000, 0x0401, 0x0000, 0x0401, 0x0000, 0x0401, 0x0000, 0x0401, 0x0000, 0x0555, 0x0000,
+};
+#endif
diff --git a/src/libui_sdl/libui/ui.h b/src/libui_sdl/libui/ui.h
index 5f40aff..e15c127 100644
--- a/src/libui_sdl/libui/ui.h
+++ b/src/libui_sdl/libui/ui.h
@@ -108,6 +108,8 @@ typedef struct uiWindow uiWindow;
#define uiWindow(this) ((uiWindow *) (this))
_UI_EXTERN char *uiWindowTitle(uiWindow *w);
_UI_EXTERN void uiWindowSetTitle(uiWindow *w, const char *title);
+_UI_EXTERN void uiWindowPosition(uiWindow *w, int *x, int *y);
+_UI_EXTERN void uiWindowSetPosition(uiWindow *w, int x, int y);
_UI_EXTERN void uiWindowContentSize(uiWindow *w, int *width, int *height);
_UI_EXTERN void uiWindowSetContentSize(uiWindow *w, int width, int height);
_UI_EXTERN int uiWindowMinimized(uiWindow *w);
@@ -326,6 +328,10 @@ _UI_ENUM(uiWindowResizeEdge) {
// TODO way to bring up the system menu instead?
};
+#define uiGLVersion(major, minor) ((major) | ((minor)<<16))
+#define uiGLVerMajor(ver) ((ver) & 0xFFFF)
+#define uiGLVerMinor(ver) ((ver) >> 16)
+
#define uiArea(this) ((uiArea *) (this))
// TODO give a better name
// TODO document the types of width and height
@@ -342,6 +348,7 @@ _UI_EXTERN void uiAreaBeginUserWindowMove(uiArea *a);
_UI_EXTERN void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge);
_UI_EXTERN void uiAreaSetBackgroundColor(uiArea *a, int r, int g, int b);
_UI_EXTERN uiArea *uiNewArea(uiAreaHandler *ah);
+_UI_EXTERN uiArea *uiNewGLArea(uiAreaHandler *ah, const unsigned int* req_versions);
_UI_EXTERN uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height);
struct uiAreaDrawParams {
@@ -509,7 +516,7 @@ _UI_EXTERN void uiDrawSave(uiDrawContext *c);
_UI_EXTERN void uiDrawRestore(uiDrawContext *c);
// bitmap API
-_UI_EXTERN uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height);
+_UI_EXTERN uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height, int alpha);
_UI_EXTERN void uiDrawBitmapUpdate(uiDrawBitmap* bmp, const void* data);
_UI_EXTERN void uiDrawBitmapDraw(uiDrawContext* c, uiDrawBitmap* bmp, uiRect* srcrect, uiRect* dstrect, int filter);
_UI_EXTERN void uiDrawFreeBitmap(uiDrawBitmap* bmp);
@@ -599,6 +606,22 @@ _UI_EXTERN void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar
_UI_EXTERN void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout);
+
+// OpenGL support
+
+typedef struct uiGLContext uiGLContext;
+
+_UI_EXTERN uiGLContext *uiAreaGetGLContext(uiArea* a);
+_UI_EXTERN void uiGLMakeContextCurrent(uiGLContext* ctx);
+_UI_EXTERN void uiGLBegin(uiGLContext* ctx);
+_UI_EXTERN void uiGLEnd(uiGLContext* ctx);
+_UI_EXTERN unsigned int uiGLGetVersion(uiGLContext* ctx);
+_UI_EXTERN void *uiGLGetProcAddress(const char* proc);
+_UI_EXTERN int uiGLGetFramebuffer(uiGLContext* ctx);
+_UI_EXTERN float uiGLGetFramebufferScale(uiGLContext* ctx);
+_UI_EXTERN void uiGLSwapBuffers(uiGLContext* ctx);
+
+
_UI_ENUM(uiModifiers) {
uiModifierCtrl = 1 << 0,
uiModifierAlt = 1 << 1,
diff --git a/src/libui_sdl/libui/unix/CMakeLists.txt b/src/libui_sdl/libui/unix/CMakeLists.txt
index 9300bcb..c69081e 100644
--- a/src/libui_sdl/libui/unix/CMakeLists.txt
+++ b/src/libui_sdl/libui/unix/CMakeLists.txt
@@ -43,6 +43,7 @@ list(APPEND _LIBUI_SOURCES
unix/text.c
unix/util.c
unix/window.c
+ unix/gl.c
)
set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE)
@@ -62,6 +63,7 @@ macro(_handle_static)
set(_oname libui-combined.o)
add_custom_command(
OUTPUT ${_oname}
+ DEPENDS ${_LIBUINAME}
COMMAND
ld -r --whole-archive ${_aname} -o ${_oname}
COMMAND
diff --git a/src/libui_sdl/libui/unix/area.c b/src/libui_sdl/libui/unix/area.c
index 2da9bab..5734b4b 100644
--- a/src/libui_sdl/libui/unix/area.c
+++ b/src/libui_sdl/libui/unix/area.c
@@ -28,6 +28,8 @@ struct areaWidgetClass {
GtkDrawingAreaClass parent_class;
};
+typedef struct uiGLContext uiGLContext;
+
struct uiArea {
uiUnixControl c;
GtkWidget *widget; // either swidget or areaWidget depending on whether it is scrolling
@@ -39,6 +41,10 @@ struct uiArea {
GtkWidget *areaWidget;
GtkDrawingArea *drawingArea;
areaWidget *area;
+
+ gboolean opengl;
+ uiGLContext *glContext;
+ unsigned int* req_versions;
int bgR, bgG, bgB;
@@ -57,6 +63,21 @@ struct uiArea {
G_DEFINE_TYPE(areaWidget, areaWidget, GTK_TYPE_DRAWING_AREA)
+int boub(GtkWidget* w) { return isAreaWidget(w); }
+void baba(GtkWidget* w)
+{
+ if (!isAreaWidget(w)) return;
+
+ areaWidget *aw = areaWidget(w);
+ uiArea *a = aw->a;
+ if (!a->opengl) return;
+
+ GdkGLContext* oldctx = gdk_gl_context_get_current();
+ uiGLMakeContextCurrent(a->glContext);
+ glFinish();
+ gdk_gl_context_make_current(oldctx);
+}
+
static void areaWidget_init(areaWidget *aw)
{
// for events
@@ -133,21 +154,28 @@ static gboolean areaWidget_draw(GtkWidget *w, cairo_t *cr)
loadAreaSize(a, &(dp.AreaWidth), &(dp.AreaHeight));
- cairo_clip_extents(cr, &clipX0, &clipY0, &clipX1, &clipY1);
- dp.ClipX = clipX0;
- dp.ClipY = clipY0;
- dp.ClipWidth = clipX1 - clipX0;
- dp.ClipHeight = clipY1 - clipY0;
-
- if (a->bgR != -1)
+ if (!a->opengl)
+ {
+ cairo_clip_extents(cr, &clipX0, &clipY0, &clipX1, &clipY1);
+ dp.ClipX = clipX0;
+ dp.ClipY = clipY0;
+ dp.ClipWidth = clipX1 - clipX0;
+ dp.ClipHeight = clipY1 - clipY0;
+
+ if (a->bgR != -1)
+ {
+ cairo_set_source_rgb(cr, a->bgR/255.0, a->bgG/255.0, a->bgB/255.0);
+ cairo_paint(cr);
+ }
+
+ // no need to save or restore the graphics state to reset transformations; GTK+ does that for us
+ (*(a->ah->Draw))(a->ah, a, &dp);
+ }
+ else
{
- cairo_set_source_rgb(cr, a->bgR/255.0, a->bgG/255.0, a->bgB/255.0);
- cairo_paint(cr);
+ areaDrawGL(w, &dp, cr, a->glContext);
}
- // no need to save or restore the graphics state to reset transformations; GTK+ does that for us
- (*(a->ah->Draw))(a->ah, a, &dp);
-
freeContext(dp.Context);
return FALSE;
}
@@ -598,7 +626,15 @@ static void areaWidget_class_init(areaWidgetClass *class)
// control implementation
-uiUnixControlAllDefaults(uiArea)
+uiUnixControlAllDefaultsExceptDestroy(uiArea)
+
+static void uiAreaDestroy(uiControl *c)
+{
+ uiArea* a = uiArea(c);
+ if (a->opengl && a->glContext) freeGLContext(a->glContext);
+ g_object_unref(uiArea(c)->widget);
+ uiFreeControl(c);
+}
void uiAreaSetBackgroundColor(uiArea *a, int r, int g, int b)
{
@@ -716,6 +752,7 @@ uiArea *uiNewArea(uiAreaHandler *ah)
a->ah = ah;
a->scrolling = FALSE;
+ a->opengl = FALSE;
a->areaWidget = GTK_WIDGET(g_object_new(areaWidgetType,
"libui-area", a,
@@ -730,6 +767,58 @@ uiArea *uiNewArea(uiAreaHandler *ah)
return a;
}
+void _areaCreateGLContext(GtkWidget* widget, gpointer data)
+{
+ uiArea* a = (uiArea*)data;
+
+ uiGLContext* ctx = NULL;
+ for (int i = 0; a->req_versions[i] && !ctx; i++)
+ {
+ int major = uiGLVerMajor(a->req_versions[i]);
+ int minor = uiGLVerMinor(a->req_versions[i]);
+
+ // we cannot support any version older than 3.2 via GDK
+ if ((major < 3) || (major == 3 && minor < 2))
+ break;
+
+ ctx = createGLContext(widget, major, minor);
+ }
+
+ a->glContext = ctx;
+}
+
+uiArea *uiNewGLArea(uiAreaHandler *ah, const unsigned int* req_versions)
+{
+ uiArea *a;
+
+ uiUnixNewControl(uiArea, a);
+
+ a->ah = ah;
+ a->scrolling = FALSE;
+ a->opengl = TRUE;
+
+ a->glContext = NULL;
+ a->req_versions = req_versions;
+ a->areaWidget = GTK_WIDGET(g_object_new(areaWidgetType,
+ "libui-area", a,
+ NULL));
+ a->area = areaWidget(a->areaWidget);
+
+ a->widget = a->areaWidget;
+
+ g_signal_connect(a->widget, "realize", G_CALLBACK(_areaCreateGLContext), a);
+
+ uiAreaSetBackgroundColor(a, -1, -1, -1);
+
+ return a;
+}
+
+uiGLContext *uiAreaGetGLContext(uiArea* a)
+{
+ if (!a) return NULL;
+ return a->glContext;
+}
+
uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height)
{
uiArea *a;
@@ -740,6 +829,7 @@ uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height)
a->scrolling = TRUE;
a->scrollWidth = width;
a->scrollHeight = height;
+ a->opengl = FALSE;
a->swidget = gtk_scrolled_window_new(NULL, NULL);
a->scontainer = GTK_CONTAINER(a->swidget);
diff --git a/src/libui_sdl/libui/unix/draw.c b/src/libui_sdl/libui/unix/draw.c
index e55397e..5befcd3 100644
--- a/src/libui_sdl/libui/unix/draw.c
+++ b/src/libui_sdl/libui/unix/draw.c
@@ -143,13 +143,13 @@ void uiDrawRestore(uiDrawContext *c)
// bitmap API
-uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height)
+uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height, int alpha)
{
uiDrawBitmap* bmp;
bmp = uiNew(uiDrawBitmap);
- bmp->bmp = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
+ bmp->bmp = cairo_image_surface_create(alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, width, height);
if (cairo_surface_status(bmp->bmp) != CAIRO_STATUS_SUCCESS)
implbug("error creating bitmap: %s",
cairo_status_to_string(cairo_surface_status(bmp->bmp)));
diff --git a/src/libui_sdl/libui/unix/gl.c b/src/libui_sdl/libui/unix/gl.c
new file mode 100644
index 0000000..e1665ee
--- /dev/null
+++ b/src/libui_sdl/libui/unix/gl.c
@@ -0,0 +1,246 @@
+// 26 may 2019
+#include "uipriv_unix.h"
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <EGL/egl.h>
+
+extern GThread* gtkthread;
+extern GMutex glmutex;
+
+struct uiGLContext
+{
+ GtkWidget* widget;
+ GdkWindow* window;
+
+ GdkGLContext *gctx;
+ int vermaj, vermin;
+
+ int width, height;
+ int scale;
+ GLuint renderbuffer[2][2];
+ GLuint framebuffer[2];
+ int backbuffer;
+};
+
+static void areaAllocRenderbuffer(uiGLContext* glctx);
+
+static PFNGLGENRENDERBUFFERSPROC _glGenRenderbuffers;
+static PFNGLDELETERENDERBUFFERSPROC _glDeleteRenderbuffers;
+static PFNGLBINDRENDERBUFFERPROC _glBindRenderbuffer;
+static PFNGLRENDERBUFFERSTORAGEPROC _glRenderbufferStorage;
+static PFNGLGETRENDERBUFFERPARAMETERIVPROC _glGetRenderbufferParameteriv;
+
+static PFNGLGENRENDERBUFFERSPROC _glGenFramebuffers;
+static PFNGLDELETERENDERBUFFERSPROC _glDeleteFramebuffers;
+static PFNGLBINDRENDERBUFFERPROC _glBindFramebuffer;
+static PFNGLFRAMEBUFFERTEXTUREPROC _glFramebufferTexture;
+static PFNGLFRAMEBUFFERRENDERBUFFERPROC _glFramebufferRenderbuffer;
+static PFNGLCHECKFRAMEBUFFERSTATUSPROC _glCheckFramebufferStatus;
+
+static int _procsLoaded = 0;
+
+static void _loadGLProcs(GdkGLContext* glctx)
+{
+ if (_procsLoaded) return;
+
+ _glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)uiGLGetProcAddress("glGenRenderbuffers");
+ _glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)uiGLGetProcAddress("glDeleteRenderbuffers");
+ _glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)uiGLGetProcAddress("glBindRenderbuffer");
+ _glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)uiGLGetProcAddress("glRenderbufferStorage");
+ _glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)uiGLGetProcAddress("glGetRenderbufferParameteriv");
+
+ _glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)uiGLGetProcAddress("glGenFramebuffers");
+ _glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)uiGLGetProcAddress("glDeleteFramebuffers");
+ _glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)uiGLGetProcAddress("glBindFramebuffer");
+ _glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)uiGLGetProcAddress("glFramebufferTexture");
+ _glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)uiGLGetProcAddress("glFramebufferRenderbuffer");
+ _glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)uiGLGetProcAddress("glCheckFramebufferStatus");
+
+ _procsLoaded = 1;
+}
+
+uiGLContext *createGLContext(GtkWidget* widget, int maj, int min)
+{
+ GdkWindow* gdkwin = gtk_widget_get_window(widget);
+
+ GError* err = NULL;
+ GdkGLContext* gctx = gdk_window_create_gl_context(gdkwin, &err);
+ if (err != NULL || gctx == NULL)
+ {
+ return NULL;
+ }
+
+ // TODO: make the set_use_es call conditional (#ifdef or smth) for older versions of gdk?
+ gdk_gl_context_set_use_es(gctx, FALSE);
+ gdk_gl_context_set_required_version(gctx, maj, min);
+
+ gboolean res = gdk_gl_context_realize(gctx, &err);
+ if (err != NULL || res == FALSE)
+ {
+ return NULL;
+ }
+
+ uiGLContext* ctx = uiNew(uiGLContext);
+
+ GtkAllocation allocation;
+ gtk_widget_get_allocation(widget, &allocation);
+ int window_scale = gdk_window_get_scale_factor(gdkwin);
+ ctx->width = allocation.width;
+ ctx->height = allocation.height;
+ ctx->scale = window_scale;
+
+ gdk_gl_context_make_current(gctx);
+ _loadGLProcs(gctx);
+ areaAllocRenderbuffer(ctx);
+ ctx->backbuffer = 0;
+
+ ctx->widget = widget;
+ ctx->window = gdkwin;
+ ctx->gctx = gctx;
+
+ return ctx;
+}
+
+void freeGLContext(uiGLContext* glctx)
+{
+ if (glctx == NULL) return;
+
+ gdk_gl_context_make_current(glctx->gctx);
+ _glDeleteRenderbuffers(4, &glctx->renderbuffer[0][0]);
+ _glDeleteFramebuffers(2, &glctx->framebuffer[0]);
+
+ gdk_gl_context_clear_current();
+ g_object_unref(glctx->gctx);
+ uiFree(glctx);
+}
+
+static void areaAllocRenderbuffer(uiGLContext* glctx)
+{
+ // TODO: create textures as a fallback if GL_RGB renderbuffer isn't supported?
+ // they say GL implementations aren't required to support a GL_RGB renderbuffer
+ // however, a GL_RGBA one would cause gdk_cairo_draw_from_gl() to fall back to glReadPixels()
+
+ _glGenRenderbuffers(4, &glctx->renderbuffer[0][0]);
+ _glGenFramebuffers(2, &glctx->framebuffer[0]);
+
+ _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][0]);
+ _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
+ //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][1]);
+ //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
+
+ _glBindFramebuffer(GL_FRAMEBUFFER, glctx->framebuffer[0]);
+ _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, glctx->renderbuffer[0][0]);
+ _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, glctx->renderbuffer[0][1]);
+
+ _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][0]);
+ _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
+ //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][1]);
+ //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
+
+ _glBindFramebuffer(GL_FRAMEBUFFER, glctx->framebuffer[1]);
+ _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, glctx->renderbuffer[1][0]);
+ _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, glctx->renderbuffer[1][1]);
+
+ //if (_glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+ // printf("FRAMEBUFFER IS BAD!! %04X\n", _glCheckFramebufferStatus(GL_FRAMEBUFFER));
+}
+
+static void areaReallocRenderbuffer(uiGLContext* glctx)
+{
+ _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][0]);
+ _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
+ //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][1]);
+ //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
+
+ _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][0]);
+ _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
+ //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][1]);
+ //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
+}
+
+void areaDrawGL(GtkWidget* widget, uiAreaDrawParams* dp, cairo_t* cr, uiGLContext* glctx)
+{
+ int window_scale = gdk_window_get_scale_factor(glctx->window);
+
+ if (glctx->width != dp->AreaWidth || glctx->height != dp->AreaHeight || glctx->scale != window_scale)
+ {
+ glctx->width = dp->AreaWidth;
+ glctx->height = dp->AreaHeight;
+ glctx->scale = window_scale;
+ areaReallocRenderbuffer(glctx);
+ }
+ else
+ {
+ gdk_cairo_draw_from_gl(cr, gtk_widget_get_window(widget),
+ glctx->renderbuffer[glctx->backbuffer][0], GL_RENDERBUFFER,
+ 1, 0, 0, glctx->width*glctx->scale, glctx->height*glctx->scale);
+ }
+}
+
+int uiGLGetFramebuffer(uiGLContext* ctx)
+{
+ return ctx->framebuffer[ctx->backbuffer];
+}
+
+float uiGLGetFramebufferScale(uiGLContext* ctx)
+{
+ return (float)ctx->scale;
+}
+
+void uiGLSwapBuffers(uiGLContext* ctx)
+{
+ ctx->backbuffer = ctx->backbuffer ? 0 : 1;
+}
+
+void uiGLMakeContextCurrent(uiGLContext* ctx)
+{
+ if (!ctx)
+ {
+ gdk_gl_context_clear_current();
+ return;
+ }
+
+ if (ctx->gctx == gdk_gl_context_get_current()) return;
+ gdk_gl_context_make_current(ctx->gctx);
+}
+
+void uiGLBegin(uiGLContext* ctx)
+{
+ if (g_thread_self() != gtkthread)
+ {
+ g_mutex_lock(&glmutex);
+ }
+}
+
+void uiGLEnd(uiGLContext* ctx)
+{
+ if (g_thread_self() != gtkthread)
+ {
+ g_mutex_unlock(&glmutex);
+ }
+}
+
+void *uiGLGetProcAddress(const char* proc)
+{
+ // TODO: consider using epoxy or something funny
+
+ void* ptr;
+
+ ptr = glXGetProcAddressARB((const GLubyte*)proc);
+ if (ptr) return ptr;
+
+ ptr = eglGetProcAddress(proc);
+ if (ptr) return ptr;
+
+ ptr = dlsym(NULL /* RTLD_DEFAULT */, proc);
+ if (ptr) return ptr;
+
+ return NULL;
+}
+unsigned int uiGLGetVersion(uiGLContext* ctx)
+{
+ if (!ctx) return 0;
+ return uiGLVersion(ctx->vermaj, ctx->vermin);
+}
+
diff --git a/src/libui_sdl/libui/unix/main.c b/src/libui_sdl/libui/unix/main.c
index 409b659..516bd76 100644
--- a/src/libui_sdl/libui/unix/main.c
+++ b/src/libui_sdl/libui/unix/main.c
@@ -5,6 +5,25 @@ uiInitOptions options;
// kind of a hack
GThread* gtkthread;
+GMutex glmutex;
+
+static void _eventfilter(GdkEvent* evt, gpointer data)
+{
+ if (evt->type == GDK_EXPOSE)
+ {
+ g_mutex_lock(&glmutex);
+ gtk_main_do_event(evt);
+ g_mutex_unlock(&glmutex);
+ return;
+ }
+
+ gtk_main_do_event(evt);
+}
+
+static void _eventfilterdestroy(gpointer data)
+{
+ printf("DELET\n");
+}
const char *uiInit(uiInitOptions *o)
{
@@ -21,6 +40,7 @@ const char *uiInit(uiInitOptions *o)
loadFutures();
gtkthread = g_thread_self();
+ g_mutex_init(&glmutex);
GList* iconlist = NULL;
iconlist = g_list_append(iconlist, gdk_pixbuf_new_from_resource("/org/kuriboland/melonDS/icon/melon_16x16.png", NULL));
@@ -31,6 +51,10 @@ const char *uiInit(uiInitOptions *o)
gtk_window_set_default_icon_list(iconlist);
+ g_mutex_init(&glmutex);
+
+ gdk_event_handler_set(_eventfilter, NULL, _eventfilterdestroy);
+
return NULL;
}
diff --git a/src/libui_sdl/libui/unix/uipriv_unix.h b/src/libui_sdl/libui/unix/uipriv_unix.h
index 33ff1e3..9b77188 100644
--- a/src/libui_sdl/libui/unix/uipriv_unix.h
+++ b/src/libui_sdl/libui/unix/uipriv_unix.h
@@ -5,7 +5,7 @@
#define GDK_VERSION_MAX_ALLOWED GDK_VERSION_3_10
#include <gtk/gtk.h>
#include <math.h>
-#include <dlfcn.h> // see drawtext.c
+#include <dlfcn.h> // see drawtext.c, gl.c
#include <langinfo.h>
#include <string.h>
#include <stdlib.h>
@@ -63,3 +63,9 @@ extern GtkCellRenderer *newCellRendererButton(void);
extern void loadFutures(void);
extern PangoAttribute *FUTURE_pango_attr_foreground_alpha_new(guint16 alpha);
extern gboolean FUTURE_gtk_widget_path_iter_set_object_name(GtkWidgetPath *path, gint pos, const char *name);
+
+// gl.c
+extern uiGLContext *createGLContext(GtkWidget* widget, int maj, int min);
+extern void freeGLContext(uiGLContext* glctx);
+extern void areaDrawGL(GtkWidget* widget, uiAreaDrawParams* dp, cairo_t* cr, uiGLContext* glctx);
+
diff --git a/src/libui_sdl/libui/unix/window.c b/src/libui_sdl/libui/unix/window.c
index 7da1134..6d5e2de 100644
--- a/src/libui_sdl/libui/unix/window.c
+++ b/src/libui_sdl/libui/unix/window.c
@@ -102,6 +102,23 @@ static void uiWindowDestroy(uiControl *c)
uiFreeControl(uiControl(w));
}
+void uiWindowSetPosition(uiWindow *w, int x, int y)
+{
+ if (!w) return;
+
+ gtk_window_move(w->window, x, y);
+}
+
+void uiWindowPosition(uiWindow *w, int *x, int *y)
+{
+ if (!w) return;
+
+ int xx, yy;
+ gtk_window_get_position(w->window, &xx, &yy);
+ if (x) *x = xx;
+ if (y) *y = yy;
+}
+
uiUnixControlDefaultHandle(uiWindow)
uiControl *uiWindowParent(uiControl *c)
@@ -442,3 +459,4 @@ uiWindow *uiNewWindow(const char *title, int width, int height, int maximized, i
return w;
}
+
diff --git a/src/libui_sdl/libui/windows/CMakeLists.txt b/src/libui_sdl/libui/windows/CMakeLists.txt
index 4695eb4..9d5313a 100644
--- a/src/libui_sdl/libui/windows/CMakeLists.txt
+++ b/src/libui_sdl/libui/windows/CMakeLists.txt
@@ -29,6 +29,7 @@ list(APPEND _LIBUI_SOURCES
windows/fontbutton.cpp
windows/fontdialog.cpp
windows/form.cpp
+ windows/gl.cpp
windows/graphemes.cpp
windows/grid.cpp
windows/group.cpp
diff --git a/src/libui_sdl/libui/windows/area.cpp b/src/libui_sdl/libui/windows/area.cpp
index 2185f25..72d5145 100644
--- a/src/libui_sdl/libui/windows/area.cpp
+++ b/src/libui_sdl/libui/windows/area.cpp
@@ -25,8 +25,11 @@ static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
}
// always recreate the render target if necessary
- if (a->rt == NULL)
- a->rt = makeHWNDRenderTarget(a->hwnd);
+ if (!a->openGL)
+ {
+ if (a->rt == NULL)
+ a->rt = makeHWNDRenderTarget(a->hwnd);
+ }
if (areaDoDraw(a, uMsg, wParam, lParam, &lResult) != FALSE)
return lResult;
@@ -34,12 +37,14 @@ static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
if (uMsg == WM_WINDOWPOSCHANGED) {
if ((wp->flags & SWP_NOSIZE) != 0)
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+ a->width = -1;
+ a->height = -1;
uiWindowsEnsureGetClientRect(a->hwnd, &client);
areaDrawOnResize(a, &client);
areaScrollOnResize(a, &client);
{
double w, h;
- loadAreaSize(a, a->rt, &w, &h);
+ loadAreaSize(a, &w, &h);
a->ah->Resize(a->ah, a, (int)w, (int)h);
}
return 0;
@@ -56,7 +61,15 @@ static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
// control implementation
-uiWindowsControlAllDefaults(uiArea)
+uiWindowsControlAllDefaultsExceptDestroy(uiArea)
+
+static void uiAreaDestroy(uiControl *c)
+{
+ uiArea* a = uiArea(c);
+ if (a->openGL && a->glcontext) freeGLContext(a->glcontext);
+ uiWindowsEnsureDestroyWindow(a->hwnd);
+ uiFreeControl(c);
+}
static void uiAreaMinimumSize(uiWindowsControl *c, int *width, int *height)
{
@@ -182,6 +195,9 @@ uiArea *uiNewArea(uiAreaHandler *ah)
uiWindowsNewControl(uiArea, a);
+ a->width = -1;
+ a->height = -1;
+
a->ah = ah;
a->scrolling = FALSE;
clickCounterReset(&(a->cc));
@@ -195,6 +211,50 @@ uiArea *uiNewArea(uiAreaHandler *ah)
uiAreaSetBackgroundColor(a, -1, -1, -1);
+ a->openGL = 0;
+
+ return a;
+}
+
+uiGLContext *uiAreaGetGLContext(uiArea* a)
+{
+ if (!a->openGL) userbug("trying to get GL context from non-GL area");
+
+ return a->glcontext;
+}
+
+uiArea *uiNewGLArea(uiAreaHandler *ah, const unsigned int* req_versions)
+{
+ uiArea *a;
+
+ uiWindowsNewControl(uiArea, a);
+
+ a->width = -1;
+ a->height = -1;
+
+ a->ah = ah;
+ a->scrolling = FALSE;
+ clickCounterReset(&(a->cc));
+
+ // a->hwnd is assigned in areaWndProc()
+ uiWindowsEnsureCreateControlHWND(0,
+ areaClass, L"",
+ 0,
+ hInstance, a,
+ FALSE);
+
+ uiAreaSetBackgroundColor(a, -1, -1, -1);
+
+ a->openGL = 1;
+
+ for (int i = 0; req_versions[i]; i++)
+ {
+ int major = uiGLVerMajor(req_versions[i]);
+ int minor = uiGLVerMinor(req_versions[i]);
+ a->glcontext = createGLContext(a, major, minor);
+ if (a->glcontext) break;
+ }
+
return a;
}
@@ -204,6 +264,9 @@ uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height)
uiWindowsNewControl(uiArea, a);
+ a->width = -1;
+ a->height = -1;
+
a->ah = ah;
a->scrolling = TRUE;
a->scrollWidth = width;
@@ -219,6 +282,8 @@ uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height)
uiAreaSetBackgroundColor(a, -1, -1, -1);
+ a->openGL = 0; // TODO, eventually???
+
// set initial scrolling parameters
areaUpdateScroll(a);
diff --git a/src/libui_sdl/libui/windows/area.hpp b/src/libui_sdl/libui/windows/area.hpp
index add62dd..cfc45a4 100644
--- a/src/libui_sdl/libui/windows/area.hpp
+++ b/src/libui_sdl/libui/windows/area.hpp
@@ -10,6 +10,8 @@ struct uiArea {
HWND hwnd;
uiAreaHandler *ah;
+ int width, height;
+
BOOL scrolling;
int scrollWidth;
int scrollHeight;
@@ -26,6 +28,9 @@ struct uiArea {
int bgR, bgG, bgB;
+ int openGL;
+ uiGLContext* glcontext;
+
ID2D1HwndRenderTarget *rt;
};
@@ -42,6 +47,10 @@ extern void areaUpdateScroll(uiArea *a);
extern BOOL areaDoEvents(uiArea *a, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult);
// areautil.cpp
-extern void loadAreaSize(uiArea *a, ID2D1RenderTarget *rt, double *width, double *height);
+extern void loadAreaSize(uiArea *a, double *width, double *height);
extern void pixelsToDIP(uiArea *a, double *x, double *y);
extern void dipToPixels(uiArea *a, double *x, double *y);
+
+// gl.cpp
+extern uiGLContext* createGLContext(uiArea* a, int vermajor, int verminor);
+extern void freeGLContext(uiGLContext* c);
diff --git a/src/libui_sdl/libui/windows/areadraw.cpp b/src/libui_sdl/libui/windows/areadraw.cpp
index a9ad477..f369255 100644
--- a/src/libui_sdl/libui/windows/areadraw.cpp
+++ b/src/libui_sdl/libui/windows/areadraw.cpp
@@ -6,6 +6,13 @@ static HRESULT doPaint(uiArea *a, ID2D1RenderTarget *rt, RECT *clip)
{
uiAreaHandler *ah = a->ah;
uiAreaDrawParams dp;
+
+ if (a->openGL)
+ {
+ //(*(ah->Draw))(ah, a, &dp);
+ return S_OK;
+ }
+
COLORREF bgcolorref;
D2D1_COLOR_F bgcolor;
D2D1_MATRIX_3X2_F scrollTransform;
@@ -13,7 +20,7 @@ static HRESULT doPaint(uiArea *a, ID2D1RenderTarget *rt, RECT *clip)
// no need to save or restore the graphics state to reset transformations; it's handled by resetTarget() in draw.c, called during the following
dp.Context = newContext(rt);
- loadAreaSize(a, rt, &(dp.AreaWidth), &(dp.AreaHeight));
+ loadAreaSize(a, &(dp.AreaWidth), &(dp.AreaHeight));
dp.ClipX = clip->left;
dp.ClipY = clip->top;
@@ -113,6 +120,9 @@ static void onWM_PAINT(uiArea *a)
static void onWM_PRINTCLIENT(uiArea *a, HDC dc)
{
+ // TODO????
+ if (a->openGL) return;
+
ID2D1DCRenderTarget *rt;
RECT client;
HRESULT hr;
@@ -143,13 +153,16 @@ BOOL areaDoDraw(uiArea *a, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lRe
// TODO only if the render target wasn't just created?
void areaDrawOnResize(uiArea *a, RECT *newClient)
{
- D2D1_SIZE_U size;
+ if (!a->openGL)
+ {
+ D2D1_SIZE_U size;
- size.width = newClient->right - newClient->left;
- size.height = newClient->bottom - newClient->top;
- // don't track the error; we'll get that in EndDraw()
- // see https://msdn.microsoft.com/en-us/library/windows/desktop/dd370994%28v=vs.85%29.aspx
- a->rt->Resize(&size);
+ size.width = newClient->right - newClient->left;
+ size.height = newClient->bottom - newClient->top;
+ // don't track the error; we'll get that in EndDraw()
+ // see https://msdn.microsoft.com/en-us/library/windows/desktop/dd370994%28v=vs.85%29.aspx
+ a->rt->Resize(&size);
+ }
// according to Rick Brewster, we must always redraw the entire client area after calling ID2D1RenderTarget::Resize() (see http://stackoverflow.com/a/33222983/3408572)
// we used to have a uiAreaHandler.RedrawOnResize() method to decide this; now you know why we don't anymore
diff --git a/src/libui_sdl/libui/windows/areaevents.cpp b/src/libui_sdl/libui/windows/areaevents.cpp
index 3ff7a47..46d6ab9 100644
--- a/src/libui_sdl/libui/windows/areaevents.cpp
+++ b/src/libui_sdl/libui/windows/areaevents.cpp
@@ -109,7 +109,7 @@ static void areaMouseEvent(uiArea *a, int down, int up, WPARAM wParam, LPARAM l
me.Y += a->vscrollpos;
}
- loadAreaSize(a, NULL, &(me.AreaWidth), &(me.AreaHeight));
+ loadAreaSize(a, &(me.AreaWidth), &(me.AreaHeight));
me.Down = down;
me.Up = up;
diff --git a/src/libui_sdl/libui/windows/areautil.cpp b/src/libui_sdl/libui/windows/areautil.cpp
index 212ea42..ea13221 100644
--- a/src/libui_sdl/libui/windows/areautil.cpp
+++ b/src/libui_sdl/libui/windows/areautil.cpp
@@ -2,20 +2,35 @@
#include "uipriv_windows.hpp"
#include "area.hpp"
-void loadAreaSize(uiArea *a, ID2D1RenderTarget *rt, double *width, double *height)
+// TODO: make those int rather than double
+void loadAreaSize(uiArea *a, double *width, double *height)
{
D2D1_SIZE_F size;
+ if (a->width != -1)
+ {
+ *width = (double)a->width;
+ *height = (double)a->height;
+ return;
+ }
+
*width = 0;
*height = 0;
if (!a->scrolling) {
- if (rt == NULL)
+ /*if (rt == NULL)
rt = a->rt;
size = realGetSize(rt);
*width = size.width;
*height = size.height;
- dipToPixels(a, width, height);
+ dipToPixels(a, width, height);*/
+ RECT rect;
+ GetWindowRect(a->hwnd, &rect);
+ *width = (double)(rect.right - rect.left);
+ *height = (double)(rect.bottom - rect.top);
}
+
+ a->width = (int)*width;
+ a->height = (int)*height;
}
void pixelsToDIP(uiArea *a, double *x, double *y)
diff --git a/src/libui_sdl/libui/windows/draw.cpp b/src/libui_sdl/libui/windows/draw.cpp
index 11a777d..9a815b9 100644
--- a/src/libui_sdl/libui/windows/draw.cpp
+++ b/src/libui_sdl/libui/windows/draw.cpp
@@ -522,7 +522,7 @@ void uiDrawRestore(uiDrawContext *c)
// bitmap API
-uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height)
+uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height, int alpha)
{
uiDrawBitmap* bmp;
HRESULT hr;
@@ -532,7 +532,8 @@ uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height)
D2D1_BITMAP_PROPERTIES bp2 = D2D1::BitmapProperties();
bp2.dpiX = 0;
bp2.dpiY = 0;
- bp2.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE);
+ bp2.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,
+ alpha ? D2D1_ALPHA_MODE_PREMULTIPLIED : D2D1_ALPHA_MODE_IGNORE);
//c->rt->BeginDraw();
diff --git a/src/libui_sdl/libui/windows/gl.cpp b/src/libui_sdl/libui/windows/gl.cpp
new file mode 100644
index 0000000..c621721
--- /dev/null
+++ b/src/libui_sdl/libui/windows/gl.cpp
@@ -0,0 +1,161 @@
+// 31 march 2019
+#include "uipriv_windows.hpp"
+#include "area.hpp"
+
+#include <GL/gl.h>
+#include <GL/wglext.h>
+
+struct uiGLContext
+{
+ uiArea* a;
+
+ HWND hwnd;
+ HDC dc;
+ HGLRC rc;
+
+ unsigned int version;
+};
+
+
+uiGLContext* createGLContext(uiArea* a, int vermajor, int verminor)
+{
+ uiGLContext* ctx;
+ BOOL res;
+
+ ctx = uiNew(uiGLContext);
+
+ ctx->a = a;
+ ctx->hwnd = a->hwnd;
+
+ PIXELFORMATDESCRIPTOR pfd;
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.nSize = sizeof(pfd);
+ pfd.nVersion = 1;
+ pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+ pfd.iPixelType = PFD_TYPE_RGBA;
+ pfd.cColorBits = 24;
+ pfd.cAlphaBits = 8;
+ pfd.cDepthBits = 24;
+ pfd.cStencilBits = 8;
+ pfd.iLayerType = PFD_MAIN_PLANE;
+
+ ctx->dc = GetDC(ctx->hwnd);
+ if (!ctx->dc)
+ {
+ uiFree(ctx);
+ return NULL;
+ }
+
+ int pixelformat = ChoosePixelFormat(ctx->dc, &pfd);
+ res = SetPixelFormat(ctx->dc, pixelformat, &pfd);
+ if (!res)
+ {
+ ReleaseDC(ctx->hwnd, ctx->dc);
+ uiFree(ctx);
+ return NULL;
+ }
+
+ ctx->rc = wglCreateContext(ctx->dc);
+ if (!ctx->rc)
+ {
+ ReleaseDC(ctx->hwnd, ctx->dc);
+ uiFree(ctx);
+ return NULL;
+ }
+
+ wglMakeCurrent(ctx->dc, ctx->rc);
+
+ if (vermajor >= 3)
+ {
+ HGLRC (*wglCreateContextAttribsARB)(HDC,HGLRC,const int*);
+ HGLRC rc_better = NULL;
+
+ wglCreateContextAttribsARB = (HGLRC(*)(HDC,HGLRC,const int*))wglGetProcAddress("wglCreateContextAttribsARB");
+ if (wglCreateContextAttribsARB)
+ {
+ int attribs[15];
+ int i = 0;
+
+ attribs[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
+ attribs[i++] = vermajor;
+ attribs[i++] = WGL_CONTEXT_MINOR_VERSION_ARB;
+ attribs[i++] = verminor;
+
+ attribs[i] = 0;
+ rc_better = wglCreateContextAttribsARB(ctx->dc, NULL, attribs);
+ }
+
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(ctx->rc);
+
+ if (!rc_better)
+ {
+ ReleaseDC(ctx->hwnd, ctx->dc);
+ uiFree(ctx);
+ return NULL;
+ }
+
+ ctx->version = uiGLVersion(vermajor, verminor);
+ ctx->rc = rc_better;
+ wglMakeCurrent(ctx->dc, ctx->rc);
+ }
+
+ return ctx;
+}
+
+void freeGLContext(uiGLContext* ctx)
+{
+ if (ctx == NULL) return;
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(ctx->rc);
+ ReleaseDC(ctx->hwnd, ctx->dc);
+ uiFree(ctx);
+}
+
+void uiGLMakeContextCurrent(uiGLContext* ctx)
+{
+ if (ctx == NULL)
+ {
+ wglMakeCurrent(NULL, NULL);
+ return;
+ }
+
+ if (wglGetCurrentContext() == ctx->rc) return;
+ int res = wglMakeCurrent(ctx->dc, ctx->rc);
+}
+
+unsigned int uiGLGetVersion(uiGLContext* ctx)
+{
+ if (ctx == NULL) return 0;
+ return ctx->version;
+}
+
+void *uiGLGetProcAddress(const char* proc)
+{
+ return (void*)wglGetProcAddress(proc);
+}
+
+void uiGLBegin(uiGLContext* ctx)
+{
+}
+
+void uiGLEnd(uiGLContext* ctx)
+{
+}
+
+void uiGLSwapBuffers(uiGLContext* ctx)
+{
+ if (ctx == NULL) return;
+ SwapBuffers(ctx->dc);
+}
+
+int uiGLGetFramebuffer(uiGLContext* ctx)
+{
+ return 0;
+}
+
+float uiGLGetFramebufferScale(uiGLContext* ctx)
+{
+ // TODO
+ return 1;
+}
diff --git a/src/libui_sdl/libui/windows/window.cpp b/src/libui_sdl/libui/windows/window.cpp
index f52e2f6..18d1171 100644
--- a/src/libui_sdl/libui/windows/window.cpp
+++ b/src/libui_sdl/libui/windows/window.cpp
@@ -363,6 +363,21 @@ static void windowMonitorRect(HWND hwnd, RECT *r)
*r = mi.rcMonitor;
}
+void uiWindowPosition(uiWindow *w, int *x, int *y)
+{
+ RECT rect;
+ if (GetWindowRect(w->hwnd, &rect) == 0)
+ logLastError(L"error getting window position");
+ *x = rect.left;
+ *y = rect.top;
+}
+
+void uiWindowSetPosition(uiWindow *w, int x, int y)
+{
+ if (SetWindowPos(w->hwnd, NULL, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER) == 0)
+ logLastError(L"error moving window");
+}
+
void uiWindowContentSize(uiWindow *w, int *width, int *height)
{
RECT r;
diff --git a/src/libui_sdl/main.cpp b/src/libui_sdl/main.cpp
index b0e89a6..ed5e80d 100644
--- a/src/libui_sdl/main.cpp
+++ b/src/libui_sdl/main.cpp
@@ -24,12 +24,16 @@
#include <SDL2/SDL.h>
#include "libui/ui.h"
+#include "../OpenGLSupport.h"
+#include "main_shaders.h"
+
#include "../types.h"
#include "../version.h"
#include "PlatformConfig.h"
#include "DlgEmuSettings.h"
#include "DlgInputConfig.h"
+#include "DlgVideoSettings.h"
#include "DlgAudioSettings.h"
#include "DlgWifiSettings.h"
@@ -42,6 +46,8 @@
#include "../Savestate.h"
+#include "OSD.h"
+
// savestate slot mapping
// 1-8: regular slots (quick access)
@@ -60,6 +66,10 @@ char* EmuDirectory;
uiWindow* MainWindow;
uiArea* MainDrawArea;
+uiAreaHandler MainDrawAreaHandler;
+
+const u32 kGLVersions[] = {uiGLVersion(3,2), uiGLVersion(3,1), 0};
+uiGLContext* GLContext;
int WindowWidth, WindowHeight;
@@ -81,6 +91,7 @@ uiMenuItem* MenuItem_ScreenGap[6];
uiMenuItem* MenuItem_ScreenLayout[3];
uiMenuItem* MenuItem_ScreenSizing[4];
+uiMenuItem* MenuItem_ScreenFilter;
uiMenuItem* MenuItem_LimitFPS;
SDL_Thread* EmuThread;
@@ -94,9 +105,28 @@ char PrevSRAMPath[1024]; // for savestate 'undo load'
bool SavestateLoaded;
+bool Screen_UseGL;
+
bool ScreenDrawInited = false;
-uiDrawBitmap* ScreenBitmap = NULL;
-u32 ScreenBuffer[256*384];
+uiDrawBitmap* ScreenBitmap[2] = {NULL,NULL};
+
+GLuint GL_ScreenShader[3];
+GLuint GL_ScreenShaderAccel[3];
+GLuint GL_ScreenShaderOSD[3];
+struct
+{
+ float uScreenSize[2];
+ u32 u3DScale;
+ u32 uFilterMode;
+
+} GL_ShaderConfig;
+GLuint GL_ShaderConfigUBO;
+GLuint GL_ScreenVertexArrayID, GL_ScreenVertexBufferID;
+float GL_ScreenVertices[2 * 3*2 * 4]; // position/texcoord
+GLuint GL_ScreenTexture;
+bool GL_ScreenSizeDirty;
+
+int GL_3DScale;
int ScreenGap = 0;
int ScreenLayout = 0;
@@ -138,7 +168,306 @@ void LoadState(int slot);
void UndoStateLoad();
void GetSavestateName(int slot, char* filename, int len);
+void CreateMainWindow(bool opengl);
+void DestroyMainWindow();
+void RecreateMainWindow(bool opengl);
+
+
+
+bool GLScreen_InitShader(GLuint* shader, const char* fs)
+{
+ if (!OpenGL_BuildShaderProgram(kScreenVS, fs, shader, "ScreenShader"))
+ return false;
+
+ glBindAttribLocation(shader[2], 0, "vPosition");
+ glBindAttribLocation(shader[2], 1, "vTexcoord");
+ glBindFragDataLocation(shader[2], 0, "oColor");
+
+ if (!OpenGL_LinkShaderProgram(shader))
+ return false;
+
+ GLuint uni_id;
+
+ uni_id = glGetUniformBlockIndex(shader[2], "uConfig");
+ glUniformBlockBinding(shader[2], uni_id, 16);
+
+ glUseProgram(shader[2]);
+ uni_id = glGetUniformLocation(shader[2], "ScreenTex");
+ glUniform1i(uni_id, 0);
+ uni_id = glGetUniformLocation(shader[2], "_3DTex");
+ glUniform1i(uni_id, 1);
+
+ return true;
+}
+
+bool GLScreen_InitOSDShader(GLuint* shader)
+{
+ if (!OpenGL_BuildShaderProgram(kScreenVS_OSD, kScreenFS_OSD, shader, "ScreenShaderOSD"))
+ return false;
+
+ glBindAttribLocation(shader[2], 0, "vPosition");
+ glBindFragDataLocation(shader[2], 0, "oColor");
+
+ if (!OpenGL_LinkShaderProgram(shader))
+ return false;
+
+ GLuint uni_id;
+
+ uni_id = glGetUniformBlockIndex(shader[2], "uConfig");
+ glUniformBlockBinding(shader[2], uni_id, 16);
+
+ glUseProgram(shader[2]);
+ uni_id = glGetUniformLocation(shader[2], "OSDTex");
+ glUniform1i(uni_id, 0);
+
+ return true;
+}
+
+bool GLScreen_Init()
+{
+ // TODO: consider using epoxy?
+ if (!OpenGL_Init())
+ return false;
+
+ const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
+ const GLubyte* version = glGetString(GL_VERSION); // version as a string
+ printf("OpenGL: renderer: %s\n", renderer);
+ printf("OpenGL: version: %s\n", version);
+
+ if (!GLScreen_InitShader(GL_ScreenShader, kScreenFS))
+ return false;
+ if (!GLScreen_InitShader(GL_ScreenShaderAccel, kScreenFS_Accel))
+ return false;
+ if (!GLScreen_InitOSDShader(GL_ScreenShaderOSD))
+ return false;
+
+ memset(&GL_ShaderConfig, 0, sizeof(GL_ShaderConfig));
+
+ glGenBuffers(1, &GL_ShaderConfigUBO);
+ glBindBuffer(GL_UNIFORM_BUFFER, GL_ShaderConfigUBO);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(GL_ShaderConfig), &GL_ShaderConfig, GL_STATIC_DRAW);
+ glBindBufferBase(GL_UNIFORM_BUFFER, 16, GL_ShaderConfigUBO);
+
+ glGenBuffers(1, &GL_ScreenVertexBufferID);
+ glBindBuffer(GL_ARRAY_BUFFER, GL_ScreenVertexBufferID);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(GL_ScreenVertices), NULL, GL_STATIC_DRAW);
+
+ glGenVertexArrays(1, &GL_ScreenVertexArrayID);
+ glBindVertexArray(GL_ScreenVertexArrayID);
+ glEnableVertexAttribArray(0); // position
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(0));
+ glEnableVertexAttribArray(1); // texcoord
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(2*4));
+
+ glGenTextures(1, &GL_ScreenTexture);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, GL_ScreenTexture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, 256*3 + 1, 192*2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, NULL);
+
+ GL_ScreenSizeDirty = true;
+
+ return true;
+}
+
+void GLScreen_DeInit()
+{
+ glDeleteTextures(1, &GL_ScreenTexture);
+
+ glDeleteVertexArrays(1, &GL_ScreenVertexArrayID);
+ glDeleteBuffers(1, &GL_ScreenVertexBufferID);
+
+ OpenGL_DeleteShaderProgram(GL_ScreenShader);
+ OpenGL_DeleteShaderProgram(GL_ScreenShaderAccel);
+ OpenGL_DeleteShaderProgram(GL_ScreenShaderOSD);
+}
+
+void GLScreen_DrawScreen()
+{
+ float scale = uiGLGetFramebufferScale(GLContext);
+
+ if (GL_ScreenSizeDirty)
+ {
+ GL_ScreenSizeDirty = false;
+
+ GL_ShaderConfig.uScreenSize[0] = WindowWidth;
+ GL_ShaderConfig.uScreenSize[1] = WindowHeight;
+ GL_ShaderConfig.u3DScale = GL_3DScale;
+
+ glBindBuffer(GL_UNIFORM_BUFFER, GL_ShaderConfigUBO);
+ void* unibuf = glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY);
+ if (unibuf) memcpy(unibuf, &GL_ShaderConfig, sizeof(GL_ShaderConfig));
+ glUnmapBuffer(GL_UNIFORM_BUFFER);
+
+ float scwidth, scheight;
+
+ float x0, y0, x1, y1;
+ float s0, s1, s2, s3;
+ float t0, t1, t2, t3;
+
+#define SETVERTEX(i, x, y, s, t) \
+ GL_ScreenVertices[4*(i) + 0] = x; \
+ GL_ScreenVertices[4*(i) + 1] = y; \
+ GL_ScreenVertices[4*(i) + 2] = s; \
+ GL_ScreenVertices[4*(i) + 3] = t;
+
+ x0 = TopScreenRect.X;
+ y0 = TopScreenRect.Y;
+ x1 = TopScreenRect.X + TopScreenRect.Width;
+ y1 = TopScreenRect.Y + TopScreenRect.Height;
+
+ scwidth = 256;
+ scheight = 192;
+
+ switch (ScreenRotation)
+ {
+ case 0:
+ s0 = 0; t0 = 0;
+ s1 = scwidth; t1 = 0;
+ s2 = 0; t2 = scheight;
+ s3 = scwidth; t3 = scheight;
+ break;
+
+ case 1:
+ s0 = 0; t0 = scheight;
+ s1 = 0; t1 = 0;
+ s2 = scwidth; t2 = scheight;
+ s3 = scwidth; t3 = 0;
+ break;
+
+ case 2:
+ s0 = scwidth; t0 = scheight;
+ s1 = 0; t1 = scheight;
+ s2 = scwidth; t2 = 0;
+ s3 = 0; t3 = 0;
+ break;
+
+ case 3:
+ s0 = scwidth; t0 = 0;
+ s1 = scwidth; t1 = scheight;
+ s2 = 0; t2 = 0;
+ s3 = 0; t3 = scheight;
+ break;
+ }
+
+ SETVERTEX(0, x0, y0, s0, t0);
+ SETVERTEX(1, x1, y1, s3, t3);
+ SETVERTEX(2, x1, y0, s1, t1);
+ SETVERTEX(3, x0, y0, s0, t0);
+ SETVERTEX(4, x0, y1, s2, t2);
+ SETVERTEX(5, x1, y1, s3, t3);
+
+ x0 = BottomScreenRect.X;
+ y0 = BottomScreenRect.Y;
+ x1 = BottomScreenRect.X + BottomScreenRect.Width;
+ y1 = BottomScreenRect.Y + BottomScreenRect.Height;
+
+ scwidth = 256;
+ scheight = 192;
+
+ switch (ScreenRotation)
+ {
+ case 0:
+ s0 = 0; t0 = 192;
+ s1 = scwidth; t1 = 192;
+ s2 = 0; t2 = 192+scheight;
+ s3 = scwidth; t3 = 192+scheight;
+ break;
+
+ case 1:
+ s0 = 0; t0 = 192+scheight;
+ s1 = 0; t1 = 192;
+ s2 = scwidth; t2 = 192+scheight;
+ s3 = scwidth; t3 = 192;
+ break;
+
+ case 2:
+ s0 = scwidth; t0 = 192+scheight;
+ s1 = 0; t1 = 192+scheight;
+ s2 = scwidth; t2 = 192;
+ s3 = 0; t3 = 192;
+ break;
+
+ case 3:
+ s0 = scwidth; t0 = 192;
+ s1 = scwidth; t1 = 192+scheight;
+ s2 = 0; t2 = 192;
+ s3 = 0; t3 = 192+scheight;
+ break;
+ }
+
+ SETVERTEX(6, x0, y0, s0, t0);
+ SETVERTEX(7, x1, y1, s3, t3);
+ SETVERTEX(8, x1, y0, s1, t1);
+ SETVERTEX(9, x0, y0, s0, t0);
+ SETVERTEX(10, x0, y1, s2, t2);
+ SETVERTEX(11, x1, y1, s3, t3);
+
+#undef SETVERTEX
+
+ glBindBuffer(GL_ARRAY_BUFFER, GL_ScreenVertexBufferID);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GL_ScreenVertices), GL_ScreenVertices);
+ }
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_BLEND);
+ glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ glViewport(0, 0, WindowWidth*scale, WindowHeight*scale);
+
+ if (GPU3D::Renderer == 0)
+ OpenGL_UseShaderProgram(GL_ScreenShader);
+ else
+ OpenGL_UseShaderProgram(GL_ScreenShaderAccel);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, uiGLGetFramebuffer(GLContext));
+
+ glClearColor(0, 0, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ if (RunningSomething)
+ {
+ int frontbuf = GPU::FrontBuffer;
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, GL_ScreenTexture);
+
+ if (GPU::Framebuffer[frontbuf][0] && GPU::Framebuffer[frontbuf][1])
+ {
+ if (GPU3D::Renderer == 0)
+ {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA_INTEGER,
+ GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][0]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256, 192, GL_RGBA_INTEGER,
+ GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][1]);
+ }
+ else
+ {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256*3 + 1, 192, GL_RGBA_INTEGER,
+ GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][0]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256*3 + 1, 192, GL_RGBA_INTEGER,
+ GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][1]);
+ }
+ }
+
+ glActiveTexture(GL_TEXTURE1);
+ if (GPU3D::Renderer != 0)
+ GPU3D::GLRenderer::SetupAccelFrame();
+
+ glBindBuffer(GL_ARRAY_BUFFER, GL_ScreenVertexBufferID);
+ glBindVertexArray(GL_ScreenVertexArrayID);
+ glDrawArrays(GL_TRIANGLES, 0, 4*3);
+ }
+ OpenGL_UseShaderProgram(GL_ScreenShaderOSD);
+ OSD::Update(true, NULL);
+
+ glFlush();
+ uiGLSwapBuffers(GLContext);
+}
void MicLoadWav(char* name)
{
@@ -402,7 +731,17 @@ int EmuThreadFunc(void* burp)
MainScreenPos[2] = 0;
AutoScreenSizing = 0;
- ScreenDrawInited = false;
+ if (Screen_UseGL)
+ {
+ uiGLMakeContextCurrent(GLContext);
+ GPU3D::InitRenderer(true);
+ uiGLMakeContextCurrent(NULL);
+ }
+ else
+ {
+ GPU3D::InitRenderer(false);
+ }
+
Touching = false;
KeyInputMask = 0xFFF;
HotkeyMask = 0;
@@ -537,10 +876,11 @@ int EmuThreadFunc(void* burp)
// microphone input
FeedMicInput();
- // emulate
- u32 nlines = NDS::RunFrame();
-
- if (EmuRunning == 0) break;
+ if (Screen_UseGL)
+ {
+ uiGLBegin(GLContext);
+ uiGLMakeContextCurrent(GLContext);
+ }
// auto screen layout
{
@@ -571,13 +911,20 @@ int EmuThreadFunc(void* burp)
}
}
- memcpy(ScreenBuffer, GPU::Framebuffer, 256*384*4);
+ // emulate
+ u32 nlines = NDS::RunFrame();
+
+ if (EmuRunning == 0) break;
+
+ if (Screen_UseGL)
+ {
+ GLScreen_DrawScreen();
+ uiGLEnd(GLContext);
+ }
uiAreaQueueRedrawAll(MainDrawArea);
// framerate limiter based off SDL2_gfx
- float framerate;
- if (nlines == 263) framerate = 1000.0f / 60.0f;
- else framerate = ((1000.0f * nlines) / 263.0f) / 60.0f;
+ float framerate = (1000.0f * nlines) / (60.0f * 263.0f);
fpslimitcount++;
u32 curtick = SDL_GetTicks();
@@ -626,9 +973,20 @@ int EmuThreadFunc(void* burp)
if (EmuRunning == 2)
{
+ if (Screen_UseGL)
+ {
+ uiGLBegin(GLContext);
+ uiGLMakeContextCurrent(GLContext);
+ GLScreen_DrawScreen();
+ uiGLEnd(GLContext);
+ //uiGLMakeContextCurrent(NULL);
+ //uiQueueMain(norp, NULL);
+ }
uiAreaQueueRedrawAll(MainDrawArea);
}
+ if (Screen_UseGL) uiGLMakeContextCurrent(NULL);
+
EmuStatus = EmuRunning;
SDL_Delay(100);
@@ -639,9 +997,21 @@ int EmuThreadFunc(void* burp)
if (joybuttons) delete[] joybuttons;
+ if (Screen_UseGL) uiGLMakeContextCurrent(GLContext);
+
NDS::DeInit();
Platform::LAN_DeInit();
+ if (Screen_UseGL)
+ {
+ OSD::DeInit(true);
+ GLScreen_DeInit();
+ }
+ else
+ OSD::DeInit(false);
+
+ if (Screen_UseGL) uiGLMakeContextCurrent(NULL);
+
return 44203;
}
@@ -650,26 +1020,35 @@ void OnAreaDraw(uiAreaHandler* handler, uiArea* area, uiAreaDrawParams* params)
{
if (!ScreenDrawInited)
{
- ScreenBitmap = uiDrawNewBitmap(params->Context, 256, 384);
+ if (ScreenBitmap[0]) uiDrawFreeBitmap(ScreenBitmap[0]);
+ if (ScreenBitmap[1]) uiDrawFreeBitmap(ScreenBitmap[1]);
+
ScreenDrawInited = true;
+ ScreenBitmap[0] = uiDrawNewBitmap(params->Context, 256, 192, 0);
+ ScreenBitmap[1] = uiDrawNewBitmap(params->Context, 256, 192, 0);
}
- if (!ScreenBitmap) return;
+ int frontbuf = GPU::FrontBuffer;
+ if (!ScreenBitmap[0] || !ScreenBitmap[1]) return;
+ if (!GPU::Framebuffer[frontbuf][0] || !GPU::Framebuffer[frontbuf][1]) return;
uiRect top = {0, 0, 256, 192};
- uiRect bot = {0, 192, 256, 192};
+ uiRect bot = {0, 0, 256, 192};
- uiDrawBitmapUpdate(ScreenBitmap, ScreenBuffer);
+ uiDrawBitmapUpdate(ScreenBitmap[0], GPU::Framebuffer[frontbuf][0]);
+ uiDrawBitmapUpdate(ScreenBitmap[1], GPU::Framebuffer[frontbuf][1]);
uiDrawSave(params->Context);
uiDrawTransform(params->Context, &TopScreenTrans);
- uiDrawBitmapDraw(params->Context, ScreenBitmap, &top, &TopScreenRect, Config::ScreenFilter==1);
+ uiDrawBitmapDraw(params->Context, ScreenBitmap[0], &top, &TopScreenRect, Config::ScreenFilter==1);
uiDrawRestore(params->Context);
uiDrawSave(params->Context);
uiDrawTransform(params->Context, &BottomScreenTrans);
- uiDrawBitmapDraw(params->Context, ScreenBitmap, &bot, &BottomScreenRect, Config::ScreenFilter==1);
+ uiDrawBitmapDraw(params->Context, ScreenBitmap[1], &bot, &BottomScreenRect, Config::ScreenFilter==1);
uiDrawRestore(params->Context);
+
+ OSD::Update(false, params);
}
void OnAreaMouseEvent(uiAreaHandler* handler, uiArea* area, uiAreaMouseEvent* evt)
@@ -820,7 +1199,8 @@ int OnAreaKeyEvent(uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* evt)
}
if (evt->Scancode == 0x57) // F11
- NDS::debug(0);
+ OSD::AddMessage(0x00FFFF, "OSD test");
+ //NDS::debug(0);
}
return 1;
@@ -847,7 +1227,7 @@ void SetupScreenRects(int width, int height)
else
sizemode = ScreenSizing;
- int screenW, screenH;
+ int screenW, screenH, gap;
if (sideways)
{
screenW = 192;
@@ -859,6 +1239,8 @@ void SetupScreenRects(int width, int height)
screenH = 192;
}
+ gap = ScreenGap;
+
uiRect *topscreen, *bottomscreen;
if (ScreenRotation == 1 || ScreenRotation == 2)
{
@@ -878,7 +1260,7 @@ void SetupScreenRects(int width, int height)
int heightreq;
int startX = 0;
- width -= ScreenGap;
+ width -= gap;
if (sizemode == 0) // even
{
@@ -916,7 +1298,7 @@ void SetupScreenRects(int width, int height)
topscreen->X = startX;
topscreen->Y = ((height - heightreq) / 2) + (heightreq - topscreen->Height);
- bottomscreen->X = topscreen->X + topscreen->Width + ScreenGap;
+ bottomscreen->X = topscreen->X + topscreen->Width + gap;
if (sizemode == 1)
{
@@ -937,7 +1319,7 @@ void SetupScreenRects(int width, int height)
int widthreq;
int startY = 0;
- height -= ScreenGap;
+ height -= gap;
if (sizemode == 0) // even
{
@@ -975,7 +1357,7 @@ void SetupScreenRects(int width, int height)
topscreen->Y = startY;
topscreen->X = (width - topscreen->Width) / 2;
- bottomscreen->Y = topscreen->Y + topscreen->Height + ScreenGap;
+ bottomscreen->Y = topscreen->Y + topscreen->Height + gap;
if (sizemode == 1)
{
@@ -1045,6 +1427,8 @@ void SetupScreenRects(int width, int height)
}
break;
}
+
+ GL_ScreenSizeDirty = true;
}
void SetMinSize(int w, int h)
@@ -1072,20 +1456,30 @@ void OnAreaResize(uiAreaHandler* handler, uiArea* area, int width, int height)
WindowWidth = width;
WindowHeight = height;
- int max = uiWindowMaximized(MainWindow);
- int min = uiWindowMinimized(MainWindow);
+ int ismax = uiWindowMaximized(MainWindow);
+ int ismin = uiWindowMinimized(MainWindow);
- Config::WindowMaximized = max;
- if (!max && !min)
+ Config::WindowMaximized = ismax;
+ if (!ismax && !ismin)
{
Config::WindowWidth = width;
Config::WindowHeight = height;
}
+
+ OSD::WindowResized(Screen_UseGL);
}
void Run()
{
+ if (GPU3D::Renderer != Config::_3DRenderer)
+ {
+ if (Screen_UseGL) uiGLMakeContextCurrent(GLContext);
+ GPU3D::DeInitRenderer();
+ GPU3D::InitRenderer(Screen_UseGL);
+ if (Screen_UseGL) uiGLMakeContextCurrent(NULL);
+ }
+
EmuRunning = 1;
RunningSomething = true;
@@ -1135,7 +1529,6 @@ void Stop(bool internal)
uiMenuItemDisable(MenuItem_Stop);
uiMenuItemSetChecked(MenuItem_Pause, 0);
- memset(ScreenBuffer, 0, 256*384*4);
uiAreaQueueRedrawAll(MainDrawArea);
SDL_PauseAudioDevice(AudioDevice, 1);
@@ -1239,6 +1632,11 @@ void LoadState(int slot)
if (!Platform::FileExists(filename))
{
+ char msg[64];
+ if (slot > 0) sprintf(msg, "State slot %d is empty", slot);
+ else sprintf(msg, "State file does not exist");
+ OSD::AddMessage(0xFFA0A0, msg);
+
EmuRunning = prevstatus;
return;
}
@@ -1279,6 +1677,11 @@ void LoadState(int slot)
NDS::RelocateSave(SRAMPath, false);
}
+ char msg[64];
+ if (slot > 0) sprintf(msg, "State loaded from slot %d", slot);
+ else sprintf(msg, "State loaded from file");
+ OSD::AddMessage(0, msg);
+
SavestateLoaded = true;
uiMenuItemEnable(MenuItem_UndoStateLoad);
}
@@ -1338,6 +1741,11 @@ void SaveState(int slot)
}
}
+ char msg[64];
+ if (slot > 0) sprintf(msg, "State saved to slot %d", slot);
+ else sprintf(msg, "State saved to file");
+ OSD::AddMessage(0, msg);
+
EmuRunning = prevstatus;
}
@@ -1362,15 +1770,29 @@ void UndoStateLoad()
NDS::RelocateSave(SRAMPath, false);
}
+ OSD::AddMessage(0, "State load undone");
+
EmuRunning = prevstatus;
}
+void CloseAllDialogs()
+{
+ DlgAudioSettings::Close();
+ DlgEmuSettings::Close();
+ DlgInputConfig::Close(0);
+ DlgInputConfig::Close(1);
+ DlgVideoSettings::Close();
+ DlgWifiSettings::Close();
+}
+
+
int OnCloseWindow(uiWindow* window, void* blarg)
{
EmuRunning = 3;
while (EmuStatus != 3);
+ CloseAllDialogs();
uiQuit();
return 1;
}
@@ -1407,7 +1829,8 @@ void OnCloseByMenu(uiMenuItem* item, uiWindow* window, void* blarg)
EmuRunning = 3;
while (EmuStatus != 3);
- uiControlDestroy(uiControl(window));
+ CloseAllDialogs();
+ DestroyMainWindow();
uiQuit();
}
@@ -1528,6 +1951,11 @@ void OnOpenHotkeyConfig(uiMenuItem* item, uiWindow* window, void* blarg)
DlgInputConfig::Open(1);
}
+void OnOpenVideoSettings(uiMenuItem* item, uiWindow* window, void* blarg)
+{
+ DlgVideoSettings::Open();
+}
+
void OnOpenAudioSettings(uiMenuItem* item, uiWindow* window, void* blarg)
{
DlgAudioSettings::Open();
@@ -1549,26 +1977,31 @@ void EnsureProperMinSize()
{
bool isHori = (ScreenRotation == 1 || ScreenRotation == 3);
+ int w0 = 256;
+ int h0 = 192;
+ int w1 = 256;
+ int h1 = 192;
+
if (ScreenLayout == 0) // natural
{
if (isHori)
- SetMinSize(384+ScreenGap, 256);
+ SetMinSize(h0+ScreenGap+h1, std::max(w0,w1));
else
- SetMinSize(256, 384+ScreenGap);
+ SetMinSize(std::max(w0,w1), h0+ScreenGap+h1);
}
else if (ScreenLayout == 1) // vertical
{
if (isHori)
- SetMinSize(192, 512+ScreenGap);
+ SetMinSize(std::max(h0,h1), w0+ScreenGap+w1);
else
- SetMinSize(256, 384+ScreenGap);
+ SetMinSize(std::max(w0,w1), h0+ScreenGap+h1);
}
else // horizontal
{
if (isHori)
- SetMinSize(384+ScreenGap, 256);
+ SetMinSize(h0+ScreenGap+h1, std::max(w0,w1));
else
- SetMinSize(512+ScreenGap, 192);
+ SetMinSize(w0+ScreenGap+w1, std::max(h0,h1));
}
}
@@ -1580,6 +2013,8 @@ void OnSetScreenSize(uiMenuItem* item, uiWindow* window, void* param)
int w = 256*factor;
int h = 192*factor;
+ // FIXME
+
if (ScreenLayout == 0) // natural
{
if (isHori)
@@ -1690,15 +2125,20 @@ void OnSetLimitFPS(uiMenuItem* item, uiWindow* window, void* blarg)
void ApplyNewSettings(int type)
{
- if (!RunningSomething) return;
+ if (!RunningSomething && type != 2) return;
int prevstatus = EmuRunning;
- EmuRunning = 2;
- while (EmuStatus != 2);
+ EmuRunning = 3;
+ while (EmuStatus != 3);
- if (type == 0) // general emu settings
+ if (type == 0) // 3D renderer settings
{
- GPU3D::SoftRenderer::SetupRenderThread();
+ if (Screen_UseGL) uiGLMakeContextCurrent(GLContext);
+ GPU3D::UpdateRendererConfig();
+ if (Screen_UseGL) uiGLMakeContextCurrent(NULL);
+
+ GL_3DScale = Config::GL_ScaleFactor; // dorp
+ GL_ScreenSizeDirty = true;
}
else if (type == 1) // wifi settings
{
@@ -1711,112 +2151,47 @@ void ApplyNewSettings(int type)
Platform::LAN_DeInit();
Platform::LAN_Init();
}
-
- EmuRunning = prevstatus;
-}
-
-
-int main(int argc, char** argv)
-{
- srand(time(NULL));
-
- printf("melonDS " MELONDS_VERSION "\n");
- printf(MELONDS_URL "\n");
-
- if (argc > 0 && strlen(argv[0]) > 0)
+ else if (type == 2) // video output method
{
- int len = strlen(argv[0]);
- while (len > 0)
+ bool usegl = Config::ScreenUseGL || (Config::_3DRenderer != 0);
+ if (usegl != Screen_UseGL)
{
- if (argv[0][len] == '/') break;
- if (argv[0][len] == '\\') break;
- len--;
- }
- if (len > 0)
- {
- EmuDirectory = new char[len+1];
- strncpy(EmuDirectory, argv[0], len);
- EmuDirectory[len] = '\0';
- }
- else
- {
- EmuDirectory = new char[2];
- strcpy(EmuDirectory, ".");
- }
- }
- else
- {
- EmuDirectory = new char[2];
- strcpy(EmuDirectory, ".");
- }
-
- // http://stackoverflow.com/questions/14543333/joystick-wont-work-using-sdl
- SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
+ if (RunningSomething)
+ {
+ if (Screen_UseGL) uiGLMakeContextCurrent(GLContext);
+ GPU3D::DeInitRenderer();
+ if (Screen_UseGL) uiGLMakeContextCurrent(NULL);
+ }
- if (SDL_Init(SDL_INIT_HAPTIC) < 0)
- {
- printf("SDL couldn't init rumble\n");
- }
- if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0)
- {
- printf("SDL shat itself :(\n");
- return 1;
- }
+ if (Screen_UseGL) uiGLMakeContextCurrent(GLContext);
+ OSD::DeInit(Screen_UseGL);
+ if (Screen_UseGL) uiGLMakeContextCurrent(NULL);
- SDL_JoystickEventState(SDL_ENABLE);
+ Screen_UseGL = usegl;
+ RecreateMainWindow(usegl);
- uiInitOptions ui_opt;
- memset(&ui_opt, 0, sizeof(uiInitOptions));
- const char* ui_err = uiInit(&ui_opt);
- if (ui_err != NULL)
- {
- printf("libui shat itself :( %s\n", ui_err);
- uiFreeInitError(ui_err);
- return 1;
+ if (RunningSomething)
+ {
+ if (Screen_UseGL) uiGLMakeContextCurrent(GLContext);
+ GPU3D::InitRenderer(Screen_UseGL);
+ if (Screen_UseGL) uiGLMakeContextCurrent(NULL);
+ }
+ }
}
-
- Config::Load();
-
- if (Config::AudioVolume < 0) Config::AudioVolume = 0;
- else if (Config::AudioVolume > 256) Config::AudioVolume = 256;
-
- if (!Platform::LocalFileExists("bios7.bin") ||
- !Platform::LocalFileExists("bios9.bin") ||
- !Platform::LocalFileExists("firmware.bin"))
+ else if (type == 3) // 3D renderer
{
- uiMsgBoxError(
- NULL,
- "BIOS/Firmware not found",
- "One or more of the following required files don't exist or couldn't be accessed:\n\n"
- "bios7.bin -- ARM7 BIOS\n"
- "bios9.bin -- ARM9 BIOS\n"
- "firmware.bin -- firmware image\n\n"
- "Dump the files from your DS and place them in the directory you run melonDS from.\n"
- "Make sure that the files can be accessed.");
-
- uiUninit();
- SDL_Quit();
- return 0;
+ if (Screen_UseGL) uiGLMakeContextCurrent(GLContext);
+ GPU3D::DeInitRenderer();
+ GPU3D::InitRenderer(Screen_UseGL);
+ if (Screen_UseGL) uiGLMakeContextCurrent(NULL);
}
- {
- FILE* f = Platform::OpenLocalFile("romlist.bin", "rb");
- if (f)
- {
- u32 data;
- fread(&data, 4, 1, f);
- fclose(f);
+ EmuRunning = prevstatus;
+}
- if ((data >> 24) == 0) // old CRC-based list
- {
- uiMsgBoxError(NULL,
- "Your version of romlist.bin is outdated.",
- "Save memory type detection will not work correctly.\n\n"
- "You should use the latest version of romlist.bin (provided in melonDS release packages).");
- }
- }
- }
+void CreateMainWindowMenu()
+{
uiMenu* menu;
uiMenuItem* menuitem;
@@ -1891,6 +2266,8 @@ int main(int argc, char** argv)
uiMenuItemOnClicked(menuitem, OnOpenInputConfig, NULL);
menuitem = uiMenuAppendItem(menu, "Hotkey config");
uiMenuItemOnClicked(menuitem, OnOpenHotkeyConfig, NULL);
+ menuitem = uiMenuAppendItem(menu, "Video settings");
+ uiMenuItemOnClicked(menuitem, OnOpenVideoSettings, NULL);
menuitem = uiMenuAppendItem(menu, "Audio settings");
uiMenuItemOnClicked(menuitem, OnOpenAudioSettings, NULL);
menuitem = uiMenuAppendItem(menu, "Wifi settings");
@@ -1972,24 +2349,19 @@ int main(int argc, char** argv)
uiMenuAppendSubmenu(menu, submenu);
}
- menuitem = uiMenuAppendCheckItem(menu, "Screen filtering");
- uiMenuItemOnClicked(menuitem, OnSetScreenFiltering, NULL);
- uiMenuItemSetChecked(menuitem, Config::ScreenFilter==1);
+
+ MenuItem_ScreenFilter = uiMenuAppendCheckItem(menu, "Screen filtering");
+ uiMenuItemOnClicked(MenuItem_ScreenFilter, OnSetScreenFiltering, NULL);
MenuItem_LimitFPS = uiMenuAppendCheckItem(menu, "Limit framerate");
uiMenuItemOnClicked(MenuItem_LimitFPS, OnSetLimitFPS, NULL);
- uiMenuItemSetChecked(MenuItem_LimitFPS, Config::LimitFPS==1);
-
-
- int w = Config::WindowWidth;
- int h = Config::WindowHeight;
- //if (w < 256) w = 256;
- //if (h < 384) h = 384;
-
- WindowWidth = w;
- WindowHeight = h;
+}
- MainWindow = uiNewWindow("melonDS " MELONDS_VERSION, w, h, Config::WindowMaximized, 1, 1);
+void CreateMainWindow(bool opengl)
+{
+ MainWindow = uiNewWindow("melonDS " MELONDS_VERSION,
+ WindowWidth, WindowHeight,
+ Config::WindowMaximized, 1, 1);
uiWindowOnClosing(MainWindow, OnCloseWindow, NULL);
uiWindowSetDropTarget(MainWindow, 1);
@@ -1998,28 +2370,189 @@ int main(int argc, char** argv)
uiWindowOnGetFocus(MainWindow, OnGetFocus, NULL);
uiWindowOnLoseFocus(MainWindow, OnLoseFocus, NULL);
- //uiMenuItemDisable(MenuItem_SaveState);
- //uiMenuItemDisable(MenuItem_LoadState);
- for (int i = 0; i < 9; i++) uiMenuItemDisable(MenuItem_SaveStateSlot[i]);
- for (int i = 0; i < 9; i++) uiMenuItemDisable(MenuItem_LoadStateSlot[i]);
- uiMenuItemDisable(MenuItem_UndoStateLoad);
-
- uiMenuItemDisable(MenuItem_Pause);
- uiMenuItemDisable(MenuItem_Reset);
- uiMenuItemDisable(MenuItem_Stop);
+ ScreenDrawInited = false;
+ bool opengl_good = opengl;
- uiAreaHandler areahandler;
- areahandler.Draw = OnAreaDraw;
- areahandler.MouseEvent = OnAreaMouseEvent;
- areahandler.MouseCrossed = OnAreaMouseCrossed;
- areahandler.DragBroken = OnAreaDragBroken;
- areahandler.KeyEvent = OnAreaKeyEvent;
- areahandler.Resize = OnAreaResize;
+ if (!opengl) MainDrawArea = uiNewArea(&MainDrawAreaHandler);
+ else MainDrawArea = uiNewGLArea(&MainDrawAreaHandler, kGLVersions);
- MainDrawArea = uiNewArea(&areahandler);
uiWindowSetChild(MainWindow, uiControl(MainDrawArea));
uiControlSetMinSize(uiControl(MainDrawArea), 256, 384);
- uiAreaSetBackgroundColor(MainDrawArea, 0, 0, 0); // TODO: make configurable?
+ uiAreaSetBackgroundColor(MainDrawArea, 0, 0, 0);
+
+ uiControlShow(uiControl(MainWindow));
+ uiControlSetFocus(uiControl(MainDrawArea));
+
+ if (opengl_good)
+ {
+ GLContext = uiAreaGetGLContext(MainDrawArea);
+ if (!GLContext) opengl_good = false;
+ }
+ if (opengl_good)
+ {
+ uiGLMakeContextCurrent(GLContext);
+ if (!GLScreen_Init()) opengl_good = false;
+ if (opengl_good)
+ {
+ OpenGL_UseShaderProgram(GL_ScreenShaderOSD);
+ OSD::Init(true);
+ }
+ uiGLMakeContextCurrent(NULL);
+ }
+
+ if (opengl && !opengl_good)
+ {
+ printf("OpenGL: initialization failed\n");
+ RecreateMainWindow(false);
+ Screen_UseGL = false;
+ }
+
+ if (!opengl) OSD::Init(false);
+}
+
+void DestroyMainWindow()
+{
+ uiControlDestroy(uiControl(MainWindow));
+
+ if (ScreenBitmap[0]) uiDrawFreeBitmap(ScreenBitmap[0]);
+ if (ScreenBitmap[1]) uiDrawFreeBitmap(ScreenBitmap[1]);
+
+ ScreenBitmap[0] = NULL;
+ ScreenBitmap[1] = NULL;
+}
+
+void RecreateMainWindow(bool opengl)
+{
+ int winX, winY, maxi;
+ uiWindowPosition(MainWindow, &winX, &winY);
+ maxi = uiWindowMaximized(MainWindow);
+ DestroyMainWindow();
+ CreateMainWindow(opengl);
+ uiWindowSetPosition(MainWindow, winX, winY);
+ uiWindowSetMaximized(MainWindow, maxi);
+}
+
+
+int main(int argc, char** argv)
+{
+ srand(time(NULL));
+
+ printf("melonDS " MELONDS_VERSION "\n");
+ printf(MELONDS_URL "\n");
+
+ if (argc > 0 && strlen(argv[0]) > 0)
+ {
+ int len = strlen(argv[0]);
+ while (len > 0)
+ {
+ if (argv[0][len] == '/') break;
+ if (argv[0][len] == '\\') break;
+ len--;
+ }
+ if (len > 0)
+ {
+ EmuDirectory = new char[len+1];
+ strncpy(EmuDirectory, argv[0], len);
+ EmuDirectory[len] = '\0';
+ }
+ else
+ {
+ EmuDirectory = new char[2];
+ strcpy(EmuDirectory, ".");
+ }
+ }
+ else
+ {
+ EmuDirectory = new char[2];
+ strcpy(EmuDirectory, ".");
+ }
+
+ // http://stackoverflow.com/questions/14543333/joystick-wont-work-using-sdl
+ SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
+
+ if (SDL_Init(SDL_INIT_HAPTIC) < 0)
+ {
+ printf("SDL couldn't init rumble\n");
+ }
+ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0)
+ {
+ printf("SDL shat itself :(\n");
+ return 1;
+ }
+
+ SDL_JoystickEventState(SDL_ENABLE);
+
+ uiInitOptions ui_opt;
+ memset(&ui_opt, 0, sizeof(uiInitOptions));
+ const char* ui_err = uiInit(&ui_opt);
+ if (ui_err != NULL)
+ {
+ printf("libui shat itself :( %s\n", ui_err);
+ uiFreeInitError(ui_err);
+ return 1;
+ }
+
+ Config::Load();
+
+ if (Config::AudioVolume < 0) Config::AudioVolume = 0;
+ else if (Config::AudioVolume > 256) Config::AudioVolume = 256;
+
+ if (!Platform::LocalFileExists("bios7.bin") ||
+ !Platform::LocalFileExists("bios9.bin") ||
+ !Platform::LocalFileExists("firmware.bin"))
+ {
+ uiMsgBoxError(
+ NULL,
+ "BIOS/Firmware not found",
+ "One or more of the following required files don't exist or couldn't be accessed:\n\n"
+ "bios7.bin -- ARM7 BIOS\n"
+ "bios9.bin -- ARM9 BIOS\n"
+ "firmware.bin -- firmware image\n\n"
+ "Dump the files from your DS and place them in the directory you run melonDS from.\n"
+ "Make sure that the files can be accessed.");
+
+ uiUninit();
+ SDL_Quit();
+ return 0;
+ }
+
+ {
+ FILE* f = Platform::OpenLocalFile("romlist.bin", "rb");
+ if (f)
+ {
+ u32 data;
+ fread(&data, 4, 1, f);
+ fclose(f);
+
+ if ((data >> 24) == 0) // old CRC-based list
+ {
+ uiMsgBoxError(NULL,
+ "Your version of romlist.bin is outdated.",
+ "Save memory type detection will not work correctly.\n\n"
+ "You should use the latest version of romlist.bin (provided in melonDS release packages).");
+ }
+ }
+ }
+
+ CreateMainWindowMenu();
+
+ MainDrawAreaHandler.Draw = OnAreaDraw;
+ MainDrawAreaHandler.MouseEvent = OnAreaMouseEvent;
+ MainDrawAreaHandler.MouseCrossed = OnAreaMouseCrossed;
+ MainDrawAreaHandler.DragBroken = OnAreaDragBroken;
+ MainDrawAreaHandler.KeyEvent = OnAreaKeyEvent;
+ MainDrawAreaHandler.Resize = OnAreaResize;
+
+ WindowWidth = Config::WindowWidth;
+ WindowHeight = Config::WindowHeight;
+
+ Screen_UseGL = Config::ScreenUseGL || (Config::_3DRenderer != 0);
+
+ GL_3DScale = Config::GL_ScaleFactor;
+ if (GL_3DScale < 1) GL_3DScale = 1;
+ else if (GL_3DScale > 8) GL_3DScale = 8;
+
+ CreateMainWindow(Screen_UseGL);
ScreenRotation = Config::ScreenRotation;
ScreenGap = Config::ScreenGap;
@@ -2032,6 +2565,14 @@ int main(int argc, char** argv)
SANITIZE(ScreenSizing, 0, 3);
#undef SANITIZE
+ for (int i = 0; i < 9; i++) uiMenuItemDisable(MenuItem_SaveStateSlot[i]);
+ for (int i = 0; i < 9; i++) uiMenuItemDisable(MenuItem_LoadStateSlot[i]);
+ uiMenuItemDisable(MenuItem_UndoStateLoad);
+
+ uiMenuItemDisable(MenuItem_Pause);
+ uiMenuItemDisable(MenuItem_Reset);
+ uiMenuItemDisable(MenuItem_Stop);
+
uiMenuItemSetChecked(MenuItem_SavestateSRAMReloc, Config::SavestateRelocSRAM?1:0);
uiMenuItemSetChecked(MenuItem_ScreenRot[ScreenRotation], 1);
@@ -2046,6 +2587,9 @@ int main(int argc, char** argv)
OnSetScreenRotation(MenuItem_ScreenRot[ScreenRotation], MainWindow, (void*)&kScreenRot[ScreenRotation]);
+ uiMenuItemSetChecked(MenuItem_ScreenFilter, Config::ScreenFilter==1);
+ uiMenuItemSetChecked(MenuItem_LimitFPS, Config::LimitFPS==1);
+
SDL_AudioSpec whatIwant, whatIget;
memset(&whatIwant, 0, sizeof(SDL_AudioSpec));
whatIwant.freq = 47340;
@@ -2114,8 +2658,6 @@ int main(int argc, char** argv)
}
}
- uiControlShow(uiControl(MainWindow));
- uiControlSetFocus(uiControl(MainDrawArea));
uiMain();
EmuRunning = 0;
@@ -2127,6 +2669,9 @@ int main(int argc, char** argv)
if (MicWavBuffer) delete[] MicWavBuffer;
+ if (ScreenBitmap[0]) uiDrawFreeBitmap(ScreenBitmap[0]);
+ if (ScreenBitmap[1]) uiDrawFreeBitmap(ScreenBitmap[1]);
+
Config::ScreenRotation = ScreenRotation;
Config::ScreenGap = ScreenGap;
Config::ScreenLayout = ScreenLayout;
@@ -2134,8 +2679,6 @@ int main(int argc, char** argv)
Config::Save();
- if (ScreenBitmap) uiDrawFreeBitmap(ScreenBitmap);
-
uiUninit();
SDL_Quit();
delete[] EmuDirectory;
diff --git a/src/libui_sdl/main_shaders.h b/src/libui_sdl/main_shaders.h
new file mode 100644
index 0000000..6504520
--- /dev/null
+++ b/src/libui_sdl/main_shaders.h
@@ -0,0 +1,250 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ This file is part of melonDS.
+
+ melonDS 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 3 of the License, or (at your option)
+ any later version.
+
+ melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef MAIN_SHADERS_H
+#define MAIN_SHADERS_H
+
+const char* kScreenVS = R"(#version 140
+
+layout(std140) uniform uConfig
+{
+ vec2 uScreenSize;
+ uint u3DScale;
+ uint uFilterMode;
+};
+
+in vec2 vPosition;
+in vec2 vTexcoord;
+
+smooth out vec2 fTexcoord;
+
+void main()
+{
+ vec4 fpos;
+ fpos.xy = ((vPosition * 2.0) / uScreenSize) - 1.0;
+ fpos.y *= -1;
+ fpos.z = 0.0;
+ fpos.w = 1.0;
+
+ gl_Position = fpos;
+ fTexcoord = vTexcoord;
+}
+)";
+
+const char* kScreenFS = R"(#version 140
+
+layout(std140) uniform uConfig
+{
+ vec2 uScreenSize;
+ uint u3DScale;
+ uint uFilterMode;
+};
+
+uniform usampler2D ScreenTex;
+
+smooth in vec2 fTexcoord;
+
+out vec4 oColor;
+
+void main()
+{
+ ivec4 pixel = ivec4(texelFetch(ScreenTex, ivec2(fTexcoord), 0));
+
+ // TODO: filters
+
+ oColor = vec4(vec3(pixel.bgr) / 255.0, 1.0);
+}
+)";
+
+const char* kScreenFS_Accel = R"(#version 140
+
+layout(std140) uniform uConfig
+{
+ vec2 uScreenSize;
+ uint u3DScale;
+ uint uFilterMode;
+};
+
+uniform usampler2D ScreenTex;
+uniform sampler2D _3DTex;
+
+smooth in vec2 fTexcoord;
+
+out vec4 oColor;
+
+void main()
+{
+ ivec4 pixel = ivec4(texelFetch(ScreenTex, ivec2(fTexcoord), 0));
+
+ ivec4 mbright = ivec4(texelFetch(ScreenTex, ivec2(256*3, int(fTexcoord.y)), 0));
+ int dispmode = mbright.b & 0x3;
+
+ if (dispmode == 1)
+ {
+ ivec4 val1 = pixel;
+ ivec4 val2 = ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(256,0), 0));
+ ivec4 val3 = ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(512,0), 0));
+
+ int compmode = val3.a & 0xF;
+ int eva, evb, evy;
+
+ if (compmode == 4)
+ {
+ // 3D on top, blending
+
+ float xpos = val3.r + fract(fTexcoord.x);
+ float ypos = mod(fTexcoord.y, 192);
+ ivec4 _3dpix = ivec4(texelFetch(_3DTex, ivec2(vec2(xpos, ypos)*u3DScale), 0).bgra
+ * vec4(63,63,63,31));
+
+ if (_3dpix.a > 0)
+ {
+ eva = (_3dpix.a & 0x1F) + 1;
+ evb = 32 - eva;
+
+ val1 = ((_3dpix * eva) + (val1 * evb)) >> 5;
+ if (eva <= 16) val1 += ivec4(1,1,1,0);
+ val1 = min(val1, 0x3F);
+ }
+ else
+ val1 = val2;
+ }
+ else if (compmode == 1)
+ {
+ // 3D on bottom, blending
+
+ float xpos = val3.r + fract(fTexcoord.x);
+ float ypos = mod(fTexcoord.y, 192);
+ ivec4 _3dpix = ivec4(texelFetch(_3DTex, ivec2(vec2(xpos, ypos)*u3DScale), 0).bgra
+ * vec4(63,63,63,31));
+
+ if (_3dpix.a > 0)
+ {
+ eva = val3.g;
+ evb = val3.b;
+
+ val1 = ((val1 * eva) + (_3dpix * evb)) >> 4;
+ val1 = min(val1, 0x3F);
+ }
+ else
+ val1 = val2;
+ }
+ else if (compmode <= 3)
+ {
+ // 3D on top, normal/fade
+
+ float xpos = val3.r + fract(fTexcoord.x);
+ float ypos = mod(fTexcoord.y, 192);
+ ivec4 _3dpix = ivec4(texelFetch(_3DTex, ivec2(vec2(xpos, ypos)*u3DScale), 0).bgra
+ * vec4(63,63,63,31));
+
+ if (_3dpix.a > 0)
+ {
+ evy = val3.g;
+
+ val1 = _3dpix;
+ if (compmode == 2) val1 += ((ivec4(0x3F,0x3F,0x3F,0) - val1) * evy) >> 4;
+ else if (compmode == 3) val1 -= (val1 * evy) >> 4;
+ }
+ else
+ val1 = val2;
+ }
+
+ pixel = val1;
+ }
+
+ if (dispmode != 0)
+ {
+ int brightmode = mbright.g >> 6;
+ if (brightmode == 1)
+ {
+ // up
+ int evy = mbright.r & 0x1F;
+ if (evy > 16) evy = 16;
+
+ pixel += ((ivec4(0x3F,0x3F,0x3F,0) - pixel) * evy) >> 4;
+ }
+ else if (brightmode == 2)
+ {
+ // down
+ int evy = mbright.r & 0x1F;
+ if (evy > 16) evy = 16;
+
+ pixel -= (pixel * evy) >> 4;
+ }
+ }
+
+ pixel.rgb <<= 2;
+ pixel.rgb |= (pixel.rgb >> 6);
+
+ // TODO: filters
+
+ oColor = vec4(vec3(pixel.rgb) / 255.0, 1.0);
+}
+)";
+
+
+const char* kScreenVS_OSD = R"(#version 140
+
+layout(std140) uniform uConfig
+{
+ vec2 uScreenSize;
+ uint u3DScale;
+ uint uFilterMode;
+};
+
+uniform ivec2 uOSDPos;
+uniform ivec2 uOSDSize;
+
+in vec2 vPosition;
+
+smooth out vec2 fTexcoord;
+
+void main()
+{
+ vec4 fpos;
+
+ vec2 osdpos = (vPosition * vec2(uOSDSize));
+ fTexcoord = osdpos;
+ osdpos += uOSDPos;
+
+ fpos.xy = ((osdpos * 2.0) / uScreenSize) - 1.0;
+ fpos.y *= -1;
+ fpos.z = 0.0;
+ fpos.w = 1.0;
+
+ gl_Position = fpos;
+}
+)";
+
+const char* kScreenFS_OSD = R"(#version 140
+
+uniform sampler2D OSDTex;
+
+smooth in vec2 fTexcoord;
+
+out vec4 oColor;
+
+void main()
+{
+ vec4 pixel = texelFetch(OSDTex, ivec2(fTexcoord), 0);
+ oColor = pixel.bgra;
+}
+)";
+
+#endif // MAIN_SHADERS_H