diff options
author | Arisotura <thetotalworm@gmail.com> | 2019-05-25 20:42:27 +0200 |
---|---|---|
committer | Arisotura <thetotalworm@gmail.com> | 2019-05-25 20:42:27 +0200 |
commit | 94f5ecb64714c3a4026bebe4f81a99ca4dba0362 (patch) | |
tree | cfc88ac94ce13bb1332aadde9f15c6eb4e61aee5 /src/libui_sdl | |
parent | 63e42bf90fa9d78c92123dcbc9c2b8ca5bb5e3ba (diff) | |
parent | 9ed1dda9ca18e571fc6613885ac944bbb938cd9a (diff) |
Merge branch 'blackmagic'
BAHAHAHHAHAHAHAAHAHAHAHHH
HARK HARK HARK HARK HA-*~
Diffstat (limited to 'src/libui_sdl')
-rw-r--r-- | src/libui_sdl/DlgVideoSettings.cpp | 309 | ||||
-rw-r--r-- | src/libui_sdl/DlgVideoSettings.h | 29 | ||||
-rw-r--r-- | src/libui_sdl/Platform.cpp | 7 | ||||
-rw-r--r-- | src/libui_sdl/PlatformConfig.cpp | 6 | ||||
-rw-r--r-- | src/libui_sdl/PlatformConfig.h | 3 | ||||
-rw-r--r-- | src/libui_sdl/libui/ui.h | 19 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/area.cpp | 73 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/area.hpp | 11 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/areadraw.cpp | 27 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/areaevents.cpp | 2 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/areautil.cpp | 21 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/gl.cpp | 142 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/window.cpp | 15 | ||||
-rw-r--r-- | src/libui_sdl/main.cpp | 756 | ||||
-rw-r--r-- | src/libui_sdl/main_shaders.h | 201 |
15 files changed, 1437 insertions, 184 deletions
diff --git a/src/libui_sdl/DlgVideoSettings.cpp b/src/libui_sdl/DlgVideoSettings.cpp new file mode 100644 index 0000000..329c79e --- /dev/null +++ b/src/libui_sdl/DlgVideoSettings.cpp @@ -0,0 +1,309 @@ +/* + 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)); + } +} + + +int OnCloseWindow(uiWindow* window, void* blarg) +{ + 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); +} + +void OnGLDisplayChanged(uiCheckbox* cb, void* blarg) +{ + Config::ScreenUseGL = uiCheckboxChecked(cb); + ApplyNewSettings(2); + uiControlSetFocus(uiControl(cb)); +} + +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) +{ + 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); + + 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)); +} + +} diff --git a/src/libui_sdl/DlgVideoSettings.h b/src/libui_sdl/DlgVideoSettings.h new file mode 100644 index 0000000..cd3d1b1 --- /dev/null +++ b/src/libui_sdl/DlgVideoSettings.h @@ -0,0 +1,29 @@ +/* + 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(); + +} + +#endif // DLGVIDEOSETTINGS_H diff --git a/src/libui_sdl/Platform.cpp b/src/libui_sdl/Platform.cpp index 6ebe8c3..e3035b3 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__ @@ -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 2daf746..f700ecb 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; @@ -101,6 +104,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 ed31e18..013a0a7 100644 --- a/src/libui_sdl/PlatformConfig.h +++ b/src/libui_sdl/PlatformConfig.h @@ -48,6 +48,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/libui/ui.h b/src/libui_sdl/libui/ui.h index 5f40aff..d2e9960 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 { @@ -599,6 +606,18 @@ _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 unsigned int uiGLGetVersion(uiGLContext* ctx); +_UI_EXTERN void *uiGLGetProcAddress(const char* proc); +_UI_EXTERN void uiGLSwapBuffers(uiGLContext* ctx); + + _UI_ENUM(uiModifiers) { uiModifierCtrl = 1 << 0, uiModifierAlt = 1 << 1, 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/gl.cpp b/src/libui_sdl/libui/windows/gl.cpp new file mode 100644 index 0000000..1e3732c --- /dev/null +++ b/src/libui_sdl/libui/windows/gl.cpp @@ -0,0 +1,142 @@ +// 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 uiGLSwapBuffers(uiGLContext* ctx) +{ + if (ctx == NULL) return; + SwapBuffers(ctx->dc); +} 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 3eea39c..c086bbf 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" @@ -60,6 +64,10 @@ char* EmuDirectory; uiWindow* MainWindow; uiArea* MainDrawArea; +uiAreaHandler MainDrawAreaHandler; + +const u32 kGLVersions[] = {uiGLVersion(3,1), 0}; +uiGLContext* GLContext; int WindowWidth, WindowHeight; @@ -81,6 +89,9 @@ uiMenuItem* MenuItem_ScreenGap[6]; uiMenuItem* MenuItem_ScreenLayout[3]; uiMenuItem* MenuItem_ScreenSizing[4]; +uiMenuItem* MenuItem_ScreenFilter; +uiMenuItem* MenuItem_LimitFPS; + SDL_Thread* EmuThread; int EmuRunning; volatile int EmuStatus; @@ -92,9 +103,27 @@ 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]; +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; @@ -135,7 +164,262 @@ 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; + + 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); + + glBindAttribLocation(shader[2], 0, "vPosition"); + glBindAttribLocation(shader[2], 1, "vTexcoord"); + glBindFragDataLocation(shader[2], 0, "oColor"); + + return true; +} + +bool GLScreen_Init() +{ + if (!OpenGL_Init()) + return false; + + if (!GLScreen_InitShader(GL_ScreenShader, kScreenFS)) + return false; + if (!GLScreen_InitShader(GL_ScreenShaderAccel, kScreenFS_Accel)) + 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); +} + +void GLScreen_DrawScreen() +{ + 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, WindowHeight); + + if (GPU3D::Renderer == 0) + OpenGL_UseShaderProgram(GL_ScreenShader); + else + OpenGL_UseShaderProgram(GL_ScreenShaderAccel); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + + 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); + + glFlush(); + uiGLSwapBuffers(GLContext); +} void MicLoadWav(char* name) { @@ -399,7 +683,18 @@ 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); + GPU::SetDisplaySettings(false); + } + Touching = false; KeyInputMask = 0xFFF; HotkeyMask = 0; @@ -513,10 +808,7 @@ int EmuThreadFunc(void* burp) // microphone input FeedMicInput(); - // emulate - u32 nlines = NDS::RunFrame(); - - if (EmuRunning == 0) break; + if (Screen_UseGL) uiGLMakeContextCurrent(GLContext); // auto screen layout { @@ -547,13 +839,16 @@ 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(); 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(); @@ -602,9 +897,16 @@ int EmuThreadFunc(void* burp) if (EmuRunning == 2) { + if (Screen_UseGL) + { + uiGLMakeContextCurrent(GLContext); + GLScreen_DrawScreen(); + } uiAreaQueueRedrawAll(MainDrawArea); } + if (Screen_UseGL) uiGLMakeContextCurrent(NULL); + EmuStatus = EmuRunning; SDL_Delay(100); @@ -618,6 +920,8 @@ int EmuThreadFunc(void* burp) NDS::DeInit(); Platform::LAN_DeInit(); + if (Screen_UseGL) GLScreen_DeInit(); + return 44203; } @@ -626,25 +930,32 @@ 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); + ScreenBitmap[1] = uiDrawNewBitmap(params->Context, 256, 192); } - 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); } @@ -804,7 +1115,7 @@ void SetupScreenRects(int width, int height) else sizemode = ScreenSizing; - int screenW, screenH; + int screenW, screenH, gap; if (sideways) { screenW = 192; @@ -816,6 +1127,8 @@ void SetupScreenRects(int width, int height) screenH = 192; } + gap = ScreenGap; + uiRect *topscreen, *bottomscreen; if (ScreenRotation == 1 || ScreenRotation == 2) { @@ -835,7 +1148,7 @@ void SetupScreenRects(int width, int height) int heightreq; int startX = 0; - width -= ScreenGap; + width -= gap; if (sizemode == 0) // even { @@ -873,7 +1186,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) { @@ -894,7 +1207,7 @@ void SetupScreenRects(int width, int height) int widthreq; int startY = 0; - height -= ScreenGap; + height -= gap; if (sizemode == 0) // even { @@ -932,7 +1245,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) { @@ -1002,6 +1315,8 @@ void SetupScreenRects(int width, int height) } break; } + + GL_ScreenSizeDirty = true; } void SetMinSize(int w, int h) @@ -1092,7 +1407,6 @@ void Stop(bool internal) uiMenuItemDisable(MenuItem_Stop); uiMenuItemSetChecked(MenuItem_Pause, 0); - memset(ScreenBuffer, 0, 256*384*4); uiAreaQueueRedrawAll(MainDrawArea); SDL_PauseAudioDevice(AudioDevice, 1); @@ -1364,7 +1678,7 @@ void OnCloseByMenu(uiMenuItem* item, uiWindow* window, void* blarg) EmuRunning = 3; while (EmuStatus != 3); - uiControlDestroy(uiControl(window)); + DestroyMainWindow(); uiQuit(); } @@ -1485,6 +1799,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(); @@ -1506,26 +1825,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)); } } @@ -1537,6 +1861,8 @@ void OnSetScreenSize(uiMenuItem* item, uiWindow* window, void* param) int w = 256*factor; int h = 192*factor; + // FIXME + if (ScreenLayout == 0) // natural { if (isHori) @@ -1646,15 +1972,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 { @@ -1667,112 +1998,44 @@ 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) - { - 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 + bool usegl = Config::ScreenUseGL || (Config::_3DRenderer != 0); + if (usegl != Screen_UseGL) { - 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"); + Screen_UseGL = usegl; - 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 (RunningSomething) + { + if (usegl) uiGLMakeContextCurrent(GLContext); + GPU3D::DeInitRenderer(); + if (usegl) uiGLMakeContextCurrent(NULL); + } - SDL_JoystickEventState(SDL_ENABLE); + 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; @@ -1847,6 +2110,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"); @@ -1928,24 +2193,18 @@ int main(int argc, char** argv) uiMenuAppendSubmenu(menu, submenu); } - menuitem = uiMenuAppendCheckItem(menu, "Screen filtering"); - uiMenuItemOnClicked(menuitem, OnSetScreenFiltering, NULL); - uiMenuItemSetChecked(menuitem, Config::ScreenFilter==1); - - menuitem = uiMenuAppendCheckItem(menu, "Limit framerate"); - uiMenuItemOnClicked(menuitem, OnSetLimitFPS, NULL); - uiMenuItemSetChecked(menuitem, Config::LimitFPS==1); + MenuItem_ScreenFilter = uiMenuAppendCheckItem(menu, "Screen filtering"); + uiMenuItemOnClicked(MenuItem_ScreenFilter, OnSetScreenFiltering, NULL); + MenuItem_LimitFPS = uiMenuAppendCheckItem(menu, "Limit framerate"); + uiMenuItemOnClicked(MenuItem_LimitFPS, OnSetLimitFPS, NULL); +} - 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); @@ -1954,28 +2213,182 @@ 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; + uiGLMakeContextCurrent(NULL); + } + + if (opengl && !opengl_good) + { + printf("OpenGL: initialization failed\n"); + RecreateMainWindow(false); + Screen_UseGL = 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; @@ -1988,6 +2401,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); @@ -2002,6 +2423,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; @@ -2070,8 +2494,6 @@ int main(int argc, char** argv) } } - uiControlShow(uiControl(MainWindow)); - uiControlSetFocus(uiControl(MainDrawArea)); uiMain(); EmuRunning = 0; @@ -2090,8 +2512,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..f03931c --- /dev/null +++ b/src/libui_sdl/main_shaders.h @@ -0,0 +1,201 @@ +/* + 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.xy * 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); +} +)"; + +#endif // MAIN_SHADERS_H |