diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c77b47b7e..6c5fea9bd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,6 +26,32 @@ jobs: sudo apt-get update sudo apt-get install llvm-19-dev - run: bin/build.sh + build-linux-ide: + name: Build IDE on Linux + runs-on: ubuntu-latest + timeout-minutes: 60 + steps: + - run: | + sudo apt-get update + sudo apt-get install build-essential git make \ + pkg-config cmake ninja-build gnome-desktop-testing libasound2-dev libpulse-dev \ + libaudio-dev libfribidi-dev libjack-dev libsndio-dev libx11-dev libxext-dev \ + libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libxtst-dev \ + libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \ + libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev libthai-dev \ + libpipewire-0.3-dev libwayland-dev libdecor-0-dev liburing-dev + git clone https://github.com/libsdl-org/SDL.git + cd SDL + mkdir build && cd build + cmake .. + cmake --build . --parallel + sudo cmake --install . + name: Build SDL3 + - uses: actions/checkout@v5 + - run: | + sudo apt-get update + sudo apt-get install llvm-19-dev libsystemd-dev libcurl4-openssl-dev + - run: bin/build.sh ide build-macos: name: Build on macOS strategy: diff --git a/BeefBuild/BeefProj.toml b/BeefBuild/BeefProj.toml index 0fc316c1a..6c56885f0 100644 --- a/BeefBuild/BeefProj.toml +++ b/BeefBuild/BeefProj.toml @@ -40,7 +40,7 @@ TargetName = "$(ProjectName)_d" OtherLinkFlags = "$(LinkFlags) ./libIDEHelper_d.a ./libBeefySysLib_d.a ./libhunspell.so $(Var IDEHelperLibs) -Wl,-rpath -Wl,$ORIGIN" CLibType = "Dynamic" PreBuildCmds = ["ReadFile(\"$(WorkspaceDir)/../IDE/dist/IDEHelper_libs_d.txt\", \"IDEHelperLibs\")"] -DebugCommandArguments = "-proddir=..\\ -config=Debug -platform=Win64" +DebugCommandArguments = "-proddir=..\\ -config=Debug -platform=Linux64" DebugWorkingDirectory = "$(WorkspaceDir)/../IDE/dist" PreprocessorMacros = ["DEBUG", "CLI"] @@ -58,7 +58,7 @@ TargetDirectory = "$(WorkspaceDir)/../IDE/dist" OtherLinkFlags = "$(LinkFlags) ./libIDEHelper.a ./libBeefySysLib.a ./libhunspell.so $(Var IDEHelperLibs) -Wl,-rpath -Wl,$ORIGIN" CLibType = "Dynamic" PreBuildCmds = ["ReadFile(\"$(WorkspaceDir)/../IDE/dist/IDEHelper_libs.txt\", \"IDEHelperLibs\")"] -DebugCommandArguments = "-proddir=..\\ -config=Debug -platform=Win64" +DebugCommandArguments = "-proddir=..\\ -config=Debug -platform=Linux64" DebugWorkingDirectory = "$(WorkspaceDir)/../IDE/dist" PreprocessorMacros = ["CLI"] diff --git a/BeefLibs/Beefy2D/BeefProj.toml b/BeefLibs/Beefy2D/BeefProj.toml index f7bbe7043..f9dcf2f53 100644 --- a/BeefLibs/Beefy2D/BeefProj.toml +++ b/BeefLibs/Beefy2D/BeefProj.toml @@ -16,6 +16,12 @@ CLibType = "Static" BeefLibType = "Static" PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64_d.dll\")", "CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64_d.pdb\")"] +[Configs.Debug.Linux64] +OtherLinkFlags = "$(LinkFlags) \"$(ProjectDir)/dist/libBeefySysLib_d.a\"" +CLibType = "Static" +BeefLibType = "Static" +PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/libBeefySysLib_d.a\")"] + [Configs.Release.Win32] OtherLinkFlags = "" PreprocessorMacros = ["RELEASE", "BF32"] @@ -24,6 +30,12 @@ PreprocessorMacros = ["RELEASE", "BF32"] OtherLinkFlags = "$(LinkFlags) \"$(ProjectDir)/dist/BeefySysLib64.lib\"" PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64.dll\")", "CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64.pdb\")"] +[Configs.Release.Linux64] +OtherLinkFlags = "$(LinkFlags) \"$(ProjectDir)/dist/libBeefySysLib.a\"" +CLibType = "Static" +BeefLibType = "Static" +PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/libBeefySysLib.a\")"] + [Configs.Paranoid.Win32] CLibType = "Static" BeefLibType = "Static" diff --git a/BeefLibs/Beefy2D/src/BFWindow.bf b/BeefLibs/Beefy2D/src/BFWindow.bf index f5cbe2a56..5079a0465 100644 --- a/BeefLibs/Beefy2D/src/BFWindow.bf +++ b/BeefLibs/Beefy2D/src/BFWindow.bf @@ -52,6 +52,7 @@ namespace Beefy AcceptFiles = 0x1000'0000, NoShow = 0x2000'0000, NoMouse = 0x4000'0000, + Tooltip = 0x8000'0000 }; [AllowDuplicates] diff --git a/BeefLibs/Beefy2D/src/gfx/Font.bf b/BeefLibs/Beefy2D/src/gfx/Font.bf index 005c00b23..6201c14e6 100644 --- a/BeefLibs/Beefy2D/src/gfx/Font.bf +++ b/BeefLibs/Beefy2D/src/gfx/Font.bf @@ -1,4 +1,5 @@ using System; +using System.Interop; using System.Collections; using System.Text; using System.IO; @@ -259,6 +260,86 @@ namespace Beefy.gfx List mFontEffectStack ~ delete _; DisposeProxy mFontEffectDisposeProxy = new .(new () => { PopFontEffect(); }) ~ delete _; +#if BF_PLATFORM_LINUX + + const String FONTCONFIG_LIB = "libfontconfig.so"; + static bool IsFontconfigAvailable { get; private set; } = true; + + [AlwaysInclude, StaticInitPriority(100)] + private static class FontconfigAllowFail + { + static this() + { + Runtime.AddErrorHandler(new (stage, error) => { + if (stage == .PreFail) + { + if (let err = error as Runtime.LoadSharedLibraryError && err.mPath == FONTCONFIG_LIB) + { + SelfOuter.IsFontconfigAvailable = false; + return .Ignore; + } + } + + return .ContinueFailure; + }); + } + } + + struct FcConfig; + struct FcPattern; + struct FcObjectSet; + + [CRepr] + struct FcFontSet + { + public c_int nfont; + public c_int sfont; + public FcPattern** fonts; + } + + enum FcResult : c_int + { + Match, + NoMatch, + TypeMismatch, + NoId, + OutOfMemory + } + + const String FC_FAMILY = "family"; + const String FC_STYLE = "style"; + const String FC_WEIGHT = "weight"; + const String FC_SLANT = "slant"; + const String FC_FILE = "file"; + + [CLink, Import(FONTCONFIG_LIB)] + static extern c_int FcInit(); + [CLink, Import(FONTCONFIG_LIB)] + static extern void FcFini(); + + [CLink, Import(FONTCONFIG_LIB)] + static extern FcPattern* FcPatternCreate(); + [CLink, Import(FONTCONFIG_LIB)] + static extern void FcPatternDestroy(FcPattern* p); + + [CLink, Import(FONTCONFIG_LIB)] + static extern FcObjectSet* FcObjectSetBuild(c_char* first, ...); + [CLink, Import(FONTCONFIG_LIB)] + static extern void FcObjectSetDestroy(FcObjectSet* os); + + [CLink, Import(FONTCONFIG_LIB)] + static extern FcFontSet* FcFontList(FcConfig* config, FcPattern* p, FcObjectSet* os); + [CLink, Import(FONTCONFIG_LIB)] + static extern void FcFontSetDestroy(FcFontSet* fs); + + [CLink, Import(FONTCONFIG_LIB)] + static extern FcResult FcPatternGetString(FcPattern* p, c_char* object, c_int n, char8** s); + + [CLink, Import(FONTCONFIG_LIB)] + static extern FcResult FcPatternGetInteger(FcPattern* p, c_char* object, c_int n, c_int *i); + +#endif + public this() { } @@ -288,84 +369,156 @@ namespace Beefy.gfx static void BuildFontNameCache() { -#if BF_PLATFORM_WINDOWS using (sMonitor.Enter()) { sFontNameMap = new .(); - for (int pass < 2) +#if BF_PLATFORM_WINDOWS + + for (int pass < 2) + { + Windows.HKey hkey; + + if (pass == 0) { - Windows.HKey hkey; + if (Windows.RegOpenKeyExA(Windows.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts", 0, + Windows.KEY_QUERY_VALUE | Windows.KEY_WOW64_32KEY | Windows.KEY_ENUMERATE_SUB_KEYS, out hkey) != Windows.S_OK) + continue; + } + else + { + if (Windows.RegOpenKeyExA(Windows.HKEY_CURRENT_USER, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts", 0, + Windows.KEY_QUERY_VALUE | Windows.KEY_WOW64_32KEY | Windows.KEY_ENUMERATE_SUB_KEYS, out hkey) != Windows.S_OK) + continue; + } - if (pass == 0) + defer Windows.RegCloseKey(hkey); + + for (int32 i = 0; true; i++) + { + char16[256] fontNameArr; + uint32 nameLen = 255; + uint32 valType = 0; + + char16[256] data; + uint32 dataLen = 256 * 2; + int32 result = Windows.RegEnumValueW(hkey, i, &fontNameArr, &nameLen, null, &valType, &data, &dataLen); + if (result == 0) { - if (Windows.RegOpenKeyExA(Windows.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts", 0, - Windows.KEY_QUERY_VALUE | Windows.KEY_WOW64_32KEY | Windows.KEY_ENUMERATE_SUB_KEYS, out hkey) != Windows.S_OK) - continue; + if (valType == 1) + { + String fontName = scope String(&fontNameArr); + int parenPos = fontName.IndexOf(" ("); + if (parenPos != -1) + fontName.RemoveToEnd(parenPos); + fontName.ToUpper(); + String fontPath = scope String(&data); + if ((!fontPath.EndsWith(".TTF", .OrdinalIgnoreCase)) && (!fontPath.EndsWith(".TTC", .OrdinalIgnoreCase))) + continue; + + if (fontName.Contains('&')) + { + int collectionIdx = 0; + for (var namePart in fontName.Split('&', .RemoveEmptyEntries)) + { + namePart.Trim(); + if (sFontNameMap.TryAddAlt(namePart, var keyPtr, var valuePtr)) + { + *keyPtr = new String(namePart); + *valuePtr = new $"{fontPath}@{collectionIdx}"; + collectionIdx++; + } + } + } + else if (sFontNameMap.TryAdd(fontName, var keyPtr, var valuePtr)) + { + *keyPtr = new String(fontName); + *valuePtr = new String(fontPath); + } + } } else { - if (Windows.RegOpenKeyExA(Windows.HKEY_CURRENT_USER, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts", 0, - Windows.KEY_QUERY_VALUE | Windows.KEY_WOW64_32KEY | Windows.KEY_ENUMERATE_SUB_KEYS, out hkey) != Windows.S_OK) + if (result == Windows.ERROR_MORE_DATA) continue; + + break; } + } + } +#elif BF_PLATFORM_LINUX + if (!IsFontconfigAvailable) + return; - defer Windows.RegCloseKey(hkey); + if (FcInit() == 0) + return; + + defer FcFini(); + + let pattern = FcPatternCreate(); + defer FcPatternDestroy(pattern); + let objectset = FcObjectSetBuild(FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_SLANT, FC_FILE, null); + defer FcObjectSetDestroy(objectset); - for (int32 i = 0; true; i++) + let fontSet = FcFontList(null, pattern, objectset); + if (fontSet == null) + return; + defer FcFontSetDestroy(fontSet); + + for (let i < fontSet.nfont) + { + let font = fontSet.fonts[i]; + + char8* pFile = null; + if (FcPatternGetString(font, FC_FILE, 0, &pFile) != .Match) + { + continue; + } + + char8* pFamily = null; + if (FcPatternGetString(font, FC_FAMILY, 0, &pFamily) != .Match) + { + continue; + } + + char8* pStyle = null; + FcPatternGetString(font, FC_STYLE, 0, &pStyle); + c_int weight = 0; + let isRegular = (FcPatternGetInteger(font, FC_WEIGHT, 0, &weight) == .Match) && (weight == 80); + c_int slant = 0; + let isRoman = (FcPatternGetInteger(font, FC_SLANT, 0, &slant) == .Match) && (slant == 0); + + let filepath = StringView(pFile); + let familyName = StringView(pFamily); + + String fontName = scope .(48); + fontName.Append(familyName); + if (pStyle != null) { - char16[256] fontNameArr; - uint32 nameLen = 255; - uint32 valType = 0; - - char16[256] data; - uint32 dataLen = 256 * 2; - int32 result = Windows.RegEnumValueW(hkey, i, &fontNameArr, &nameLen, null, &valType, &data, &dataLen); - if (result == 0) + if (isRegular && isRoman) { - if (valType == 1) + fontName.ToUpper(); + + if (sFontNameMap.TryAdd(fontName, let pKey, let pVal)) { - String fontName = scope String(&fontNameArr); - int parenPos = fontName.IndexOf(" ("); - if (parenPos != -1) - fontName.RemoveToEnd(parenPos); - fontName.ToUpper(); - String fontPath = scope String(&data); - if ((!fontPath.EndsWith(".TTF", .OrdinalIgnoreCase)) && (!fontPath.EndsWith(".TTC", .OrdinalIgnoreCase))) - continue; - - if (fontName.Contains('&')) - { - int collectionIdx = 0; - for (var namePart in fontName.Split('&', .RemoveEmptyEntries)) - { - namePart.Trim(); - if (sFontNameMap.TryAddAlt(namePart, var keyPtr, var valuePtr)) - { - *keyPtr = new String(namePart); - *valuePtr = new $"{fontPath}@{collectionIdx}"; - collectionIdx++; - } - } - } - else if (sFontNameMap.TryAdd(fontName, var keyPtr, var valuePtr)) - { - *keyPtr = new String(fontName); - *valuePtr = new String(fontPath); - } + (*pKey) = new String(fontName); + (*pVal) = new String(filepath); } } - else - { - if (result == Windows.ERROR_MORE_DATA) - continue; - break; - } + fontName..Append(' ').Append(pStyle); + } + + fontName.ToUpper(); + + if (sFontNameMap.TryAdd(fontName, let pKey, let pVal)) + { + (*pKey) = new String(fontName); + (*pVal) = new String(filepath); } - } - } + } #endif + } } public static void ClearFontNameCache() @@ -536,9 +689,9 @@ namespace Beefy.gfx BuildFontNameCache(); String pathStr; let lookupStr = scope String(fontName)..ToUpper(); -#if BF_PLATFORM_WINDOWS if (sFontNameMap.TryGetValue(lookupStr, out pathStr)) { +#if BF_PLATFORM_WINDOWS if (!pathStr.Contains(':')) { char8[256] windowsDir; @@ -546,14 +699,26 @@ namespace Beefy.gfx path.Append(&windowsDir); path.Append(@"\Fonts\"); } +#endif path.Append(pathStr); return; } -#endif if ((sFontFailMap != null) && (sFontFailMap.TryGetValue(lookupStr, out pathStr))) { - path.Append(pathStr); + StringView lastPath = pathStr; + for (let fontFailName in pathStr.Split('\0', .RemoveEmptyEntries)) + { + let failName = scope String(fontFailName)..ToUpper(); + if (sFontNameMap.TryGetValue(failName, out pathStr)) + { + GetFontPath(fontFailName, path); + return; + } + lastPath = fontFailName; + } + + path.Append(lastPath); return; } } diff --git a/BeefLibs/Beefy2D/src/theme/dark/DarkTooltip.bf b/BeefLibs/Beefy2D/src/theme/dark/DarkTooltip.bf index 3fe64668b..abf95b828 100644 --- a/BeefLibs/Beefy2D/src/theme/dark/DarkTooltip.bf +++ b/BeefLibs/Beefy2D/src/theme/dark/DarkTooltip.bf @@ -71,7 +71,7 @@ namespace Beefy.theme.dark screenX += relWidget.mWidgetWindow.mClientX; screenY += relWidget.mWidgetWindow.mClientY; - BFWindow.Flags windowFlags = BFWindow.Flags.ClientSized | BFWindow.Flags.PopupPosition | BFWindow.Flags.NoActivate | BFWindow.Flags.DestAlpha; + BFWindow.Flags windowFlags = BFWindow.Flags.ClientSized | BFWindow.Flags.PopupPosition | BFWindow.Flags.NoActivate | BFWindow.Flags.DestAlpha | BFWindow.Flags.Tooltip; WidgetWindow widgetWindow = new WidgetWindow(relWidget.mWidgetWindow, "Tooltip", (int32)(screenX), (int32)(screenY), diff --git a/BeefLibs/corlib/src/IO/FolderBrowserDialog.bf b/BeefLibs/corlib/src/IO/FolderBrowserDialog.bf index 7c8e6d044..101a83842 100644 --- a/BeefLibs/corlib/src/IO/FolderBrowserDialog.bf +++ b/BeefLibs/corlib/src/IO/FolderBrowserDialog.bf @@ -246,7 +246,14 @@ public class FolderBrowserDialog : CommonDialog } set { - mInitialDir.Set(value); + if(mInitialDir == null) + { + mInitialDir = new .(value); + } + else + { + mInitialDir.Set(value); + } } } diff --git a/BeefTools/ImgCreate/CMakeLists.txt b/BeefTools/ImgCreate/CMakeLists.txt new file mode 100644 index 000000000..b806eb30e --- /dev/null +++ b/BeefTools/ImgCreate/CMakeLists.txt @@ -0,0 +1,109 @@ +cmake_minimum_required(VERSION 3.5) + +################### Variables. #################### +# Change if you want modify path or other values. # +################################################### + +set(PROJECT_NAME ImgCreate) +# Output Variables +set(OUTPUT_DEBUG Debug/bin) +set(CMAKE_DEBUG_POSTFIX "_d") +set(OUTPUT_RELEASE Release/bin) + +############## CMake Project ################ +# The main options of project # +############################################# + +project(${PROJECT_NAME} CXX C) + +# Define Debug by default. +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Debug") + message(STATUS "Build type not specified: Use Debug by default.") +endif(NOT CMAKE_BUILD_TYPE) + +include_directories( + . + ../../ + ../../BeefySysLib/ +) + +file(GLOB SRC_FILES + ../../BeefySysLib/Common.cpp + ../../BeefySysLib/BFApp.cpp + ../../BeefySysLib/BFWindow.cpp + ../../BeefySysLib/DataStream.cpp + ../../BeefySysLib/FileStream.cpp + ../../BeefySysLib/util/Hash.cpp + ../../BeefySysLib/util/UTF8.cpp + ../../BeefySysLib/util/String.cpp + ../../BeefySysLib/util/PerfTimer.cpp + ../../BeefySysLib/util/CubicFuncSpline.cpp + ../../BeefySysLib/util/Vector.cpp + ../../BeefySysLib/img/ImageAdjustments.cpp + ../../BeefySysLib/img/ImageData.cpp + ../../BeefySysLib/img/ImageUtils.cpp + ../../BeefySysLib/img/ImgEffects.cpp + ../../BeefySysLib/img/PNGData.cpp + ../../BeefySysLib/img/PSDReader.cpp + ../../BeefySysLib/third_party/png/png.c + ../../BeefySysLib/third_party/png/pngerror.c + ../../BeefySysLib/third_party/png/pngget.c + ../../BeefySysLib/third_party/png/pngmem.c + ../../BeefySysLib/third_party/png/pngpread.c + ../../BeefySysLib/third_party/png/pngread.c + ../../BeefySysLib/third_party/png/pngrio.c + ../../BeefySysLib/third_party/png/pngrtran.c + ../../BeefySysLib/third_party/png/pngrutil.c + ../../BeefySysLib/third_party/png/pngset.c + ../../BeefySysLib/third_party/png/pngtrans.c + ../../BeefySysLib/third_party/png/pngvcrd.c + ../../BeefySysLib/third_party/png/pngwio.c + ../../BeefySysLib/third_party/png/pngwrite.c + ../../BeefySysLib/third_party/png/pngwtran.c + ../../BeefySysLib/third_party/png/pngwutil.c + ../../BeefySysLib/third_party/utf8proc/utf8proc.c + ../../BeefySysLib/third_party/zlib/adler32.c + ../../BeefySysLib/third_party/zlib/compress.c + ../../BeefySysLib/third_party/zlib/crc32.c + ../../BeefySysLib/third_party/zlib/deflate.c + ../../BeefySysLib/third_party/zlib/gzio.c + ../../BeefySysLib/third_party/zlib/infblock.c + ../../BeefySysLib/third_party/zlib/infcodes.c + ../../BeefySysLib/third_party/zlib/inffast.c + ../../BeefySysLib/third_party/zlib/inflate.c + ../../BeefySysLib/third_party/zlib/inftrees.c + ../../BeefySysLib/third_party/zlib/infutil.c + ../../BeefySysLib/third_party/zlib/trees.c + ../../BeefySysLib/third_party/zlib/uncompr.c + ../../BeefySysLib/third_party/zlib/zutil.c + ../../BeefySysLib/third_party/putty/wildcard.c +) + +if (${WIN32}) + include_directories( + ../../BeefySysLib/platform/win32 + ) + file(GLOB SRC_FILES_OS + ../../BeefySysLib/platform/win32/BFPlatform.cpp + ../../BeefySysLib/platform/win32/Platform.cpp + ) +elseif (${APPLE}) + include_directories( + ../../BeefySysLib/platform/darwin + ) + file(GLOB SRC_FILES_OS + ../../BeefySysLib/platform/darwin/BFPlatform.cpp + ../../BeefySysLib/platform/darwin/DarwinCommon.cpp + ) +else() + include_directories( + ../../BeefySysLib/platform/linux + ) + file(GLOB SRC_FILES_OS + ../../BeefySysLib/platform/linux/BFPlatform.cpp + ../../BeefySysLib/platform/linux/LinuxCommon.cpp + ) +endif() + +add_executable(${PROJECT_NAME} ImgCreate.cpp ${SRC_FILES_OS} ${SRC_FILES}) \ No newline at end of file diff --git a/BeefTools/ImgCreate/ImgCreate.cpp b/BeefTools/ImgCreate/ImgCreate.cpp index 7f4cb08b4..c5a12ca75 100644 --- a/BeefTools/ImgCreate/ImgCreate.cpp +++ b/BeefTools/ImgCreate/ImgCreate.cpp @@ -2,7 +2,6 @@ #include "BeefySysLib/util/Array.h" #include "BeefySysLib/img/PSDReader.h" #include "BeefySysLib/img/PNGData.h" -#include USING_NS_BF; @@ -290,8 +289,11 @@ int main() }; if (isThemeDir) - _mkdir("cache"); - + { + BfpFileResult result; + BfpDirectory_Create("cache", &result); + } + for (int size = 0; size < 3; size++) { int scale = 1 << size; diff --git a/BeefTools/ImgCreate/build.sh b/BeefTools/ImgCreate/build.sh new file mode 100755 index 000000000..c8da72e9a --- /dev/null +++ b/BeefTools/ImgCreate/build.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +PATH=/usr/local/bin:$PATH:$HOME/bin +SCRIPTPATH=$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P) + +echo Building from $SCRIPTPATH +cd $SCRIPTPATH + +if command -v ninja >/dev/null 2>&1 ; then + if [ ! -d build ] || [ -f build/build.ninja ]; then + USE_NINJA="-GNinja" + else + echo "Ninja couldn't be enabled for this build, consider doing a clean build to start using Ninja for faster build speeds." + fi +fi + +if [ ! -d build ]; then + mkdir build +fi + +cd build +cmake $USE_NINJA -DCMAKE_BUILD_TYPE=RelWithDebInfo ../ +cmake --build . + +cd $SCRIPTPATH/../../IDE/dist/images +ln -s -f $SCRIPTPATH/build/ImgCreate ImgCreate \ No newline at end of file diff --git a/BeefySysLib/BFWindow.h b/BeefySysLib/BFWindow.h index 5196dcdfd..bd5a846c1 100644 --- a/BeefySysLib/BFWindow.h +++ b/BeefySysLib/BFWindow.h @@ -57,7 +57,8 @@ enum BFWINDOW_ALLOW_FULLSCREEN = 0x8000000, BFWINDOW_ACCEPTFILES = 0x10000000, BFWINDOW_NOSHOW = 0x20000000, - BFWINDOW_NO_MOUSE = 0x40000000 + BFWINDOW_NO_MOUSE = 0x40000000, + BFWINDOW_TOOLTIP = 0x80000000 }; diff --git a/BeefySysLib/BeefySysLib.cpp b/BeefySysLib/BeefySysLib.cpp index 3c6858c92..993da6132 100644 --- a/BeefySysLib/BeefySysLib.cpp +++ b/BeefySysLib/BeefySysLib.cpp @@ -15,9 +15,9 @@ #include "util/AllocDebug.h" -#ifdef BF_PLATFORM_WINDOWS -#include "platform/sdl/SdlBFApp.h" -#endif +//#ifdef BF_PLATFORM_WINDOWS +//#include "platform/sdl/SdlBFApp.h" +//#endif //#include "third_party/freetype/include/ft2build.h" //#include FT_FREETYPE_H @@ -92,23 +92,23 @@ BF_EXPORT void BF_CALLTYPE BFApp_GetWorkspaceRectFrom(int fromX, int fromY, int static bool gForceSDL = false; -BF_EXPORT void BF_CALLTYPE BFApp_SetOptionString(const char* name, const char* value) -{ - if (strcmp(name, "SDL") == 0) - { - gForceSDL = strcmp(value, "1") == 0; - } -} +//BF_EXPORT void BF_CALLTYPE BFApp_SetOptionString(const char* name, const char* value) +//{ +// if (strcmp(name, "SDL") == 0) +// { +// gForceSDL = strcmp(value, "1") == 0; +// } +//} BF_EXPORT void BF_CALLTYPE BFApp_Create() { -#ifdef BF_PLATFORM_WINDOWS - if (gForceSDL) - { - new SdlBFApp(); - return; - } -#endif +//#ifdef BF_PLATFORM_WINDOWS +// if (gForceSDL) +// { +// new SdlBFApp(); +// return; +// } +//#endif new PlatformBFApp(); } diff --git a/BeefySysLib/BeefySysLib.vcxproj b/BeefySysLib/BeefySysLib.vcxproj index 1f2c7ef21..8ad7d86a3 100644 --- a/BeefySysLib/BeefySysLib.vcxproj +++ b/BeefySysLib/BeefySysLib.vcxproj @@ -221,8 +221,8 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\" Level3 Disabled - FFI_STATIC_BUILD;zBF_FORCE_SDL;BP_DYNAMIC;BFP_NOEXPORT;WIN32;_DEBUG;_WINDOWS;_USRDLL;BFSYSLIB_DYNAMIC;BF_NO_FBX;FT2_BUILD_LIBRARY;%(PreprocessorDefinitions) - ./;./platform/win/;./platform/sdl/;third_party/agg-2.4/include;third_party/agg-2.4/include/platform/win32;third_party/;third_party/libffi/x86_64-pc-cygwin;third_party/libffi/x86_64-pc-cygwin/include;third_party/libffi/include;third_party/SDL2-2.0.1/include;../extern/fbxsdk/include;third_party/freetype/include;../BeefLibs/SDL2/include + FFI_STATIC_BUILD;BP_DYNAMIC;BFP_NOEXPORT;WIN32;_DEBUG;_WINDOWS;_USRDLL;BFSYSLIB_DYNAMIC;BF_NO_FBX;FT2_BUILD_LIBRARY;%(PreprocessorDefinitions) + ./;./platform/win/;third_party/agg-2.4/include;third_party/agg-2.4/include/platform/win32;third_party/;third_party/libffi/x86_64-pc-cygwin;third_party/libffi/x86_64-pc-cygwin/include;third_party/libffi/include;third_party/SDL2-2.0.1/include;../extern/fbxsdk/include;third_party/freetype/include MultiThreadedDebug false false @@ -235,7 +235,6 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"false 0x100000000 $(OutDir)$(TargetName).lib - ../BeefLibs/SDL2/dist @@ -351,7 +350,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"true FFI_STATIC_BUILD;BP_DYNAMIC;BFP_NOEXPORT;WIN32;NDEBUG;_WINDOWS;_USRDLL;BFSYSLIB_DYNAMIC;BF_NO_FBX;FT2_BUILD_LIBRARY;%(PreprocessorDefinitions) MultiThreaded - ./;./platform/win/;./platform/sdl/;third_party/agg-2.4/include;third_party/agg-2.4/include/platform/win32;third_party/;third_party/libffi/x86_64-pc-cygwin;third_party/libffi/x86_64-pc-cygwin/include;third_party/libffi/include;third_party/SDL2-2.0.1/include;../extern/fbxsdk/include;third_party/freetype/include;../BeefLibs/SDL2/include + ./;./platform/win/;third_party/agg-2.4/include;third_party/agg-2.4/include/platform/win32;third_party/;third_party/libffi/x86_64-pc-cygwin;third_party/libffi/x86_64-pc-cygwin/include;third_party/libffi/include;third_party/SDL2-2.0.1/include;../extern/fbxsdk/include;third_party/freetype/include false true @@ -364,7 +363,6 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"imm32.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) false $(OutDir)$(TargetName).lib - ../BeefLibs/SDL2/dist @@ -482,21 +480,21 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"true true true - false + true true true - false - false + true + true true true true true - false + true true - false - false + true + true @@ -2015,19 +2013,19 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"true true true - false + true true - false - false + true + true true true true - false + true true - false - false + true + true diff --git a/BeefySysLib/CMakeLists.txt b/BeefySysLib/CMakeLists.txt index 08ee16ffb..a7cc08bc6 100644 --- a/BeefySysLib/CMakeLists.txt +++ b/BeefySysLib/CMakeLists.txt @@ -327,10 +327,11 @@ else() endif() if (DEFINED BF_ENABLE_SDL) - file(GLOB SRC_FILES_OS + file(GLOB SRC_FILES_SDL platform/sdl/SdlBFApp.cpp platform/sdl/GLRenderDevice.cpp ) + list(APPEND SRC_FILES_OS ${SRC_FILES_SDL}) endif() # Add library to build. diff --git a/BeefySysLib/platform/linux/LinuxCommon.h b/BeefySysLib/platform/linux/LinuxCommon.h index 466ce3552..680d899c4 100644 --- a/BeefySysLib/platform/linux/LinuxCommon.h +++ b/BeefySysLib/platform/linux/LinuxCommon.h @@ -25,6 +25,7 @@ #include #include #include +#include //#define offsetof(type, member) __builtin_offsetof (type, member) diff --git a/BeefySysLib/platform/linux/PlatformApp.h b/BeefySysLib/platform/linux/PlatformApp.h index 86af1ee8f..2cbaba04c 100644 --- a/BeefySysLib/platform/linux/PlatformApp.h +++ b/BeefySysLib/platform/linux/PlatformApp.h @@ -1,6 +1,8 @@ #pragma once +#ifdef BF_ENABLE_SDL #include "../sdl/SdlBFApp.h" +#endif #include "../HeadlessApp.h" NS_BF_BEGIN; diff --git a/BeefySysLib/platform/sdl/GLRenderDevice.cpp b/BeefySysLib/platform/sdl/GLRenderDevice.cpp index 28d3a5583..e71420339 100644 --- a/BeefySysLib/platform/sdl/GLRenderDevice.cpp +++ b/BeefySysLib/platform/sdl/GLRenderDevice.cpp @@ -1,9 +1,10 @@ #include "GLRenderDevice.h" +#include "BFApp.h" #include "SdlBFApp.h" #include "BFWindow.h" #include "img/ImageData.h" #include "util/PerfTimer.h" -#include +#include USING_NS_BF; @@ -11,7 +12,7 @@ USING_NS_BF; #define NOT_IMPL throw "Not implemented" #endif -//#pragma comment(lib, "SDL2.lib") +//#pragma comment(lib, "SDL3.lib") #ifdef _WIN32 #ifdef BF_PLATFORM_OPENGL_ES2 @@ -39,12 +40,16 @@ USING_NS_BF; #endif extern void* (SDLCALL* bf_SDL_GL_GetProcAddress)(const char* proc); -extern void (SDLCALL* bf_SDL_GetWindowSize)(SDL_Window* window, int* w, int* h); -extern void (SDLCALL* bf_SDL_GL_SwapWindow)(SDL_Window* window); +extern bool (SDLCALL* bf_SDL_GetWindowSizeInPixels)(SDL_Window* window, int* w, int* h); +extern bool (SDLCALL* bf_SDL_GL_SwapWindow)(SDL_Window* window); +extern bool (SDLCALL* bf_SDL_GL_MakeCurrent)(SDL_Window* window, SDL_GLContext context); +extern SDL_GLContext (SDLCALL* bf_SDL_GL_GetCurrentContext)(); +extern const char* (SDLCALL* bf_SDL_GetError)(void); -typedef void (APIENTRYP GL_DEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam); +extern SDL_DisplayID (SDLCALL* bf_SDL_GetDisplayForWindow)(SDL_Window *window); +extern const SDL_DisplayMode* (SDLCALL* bf_SDL_GetCurrentDisplayMode)(SDL_DisplayID displayID); -static void (APIENTRYP bf_glDebugMessageCallback)(GL_DEBUGPROC callback, const void* userParam); +static GLenum (APIENTRYP bf_glGetError)(); static void (APIENTRYP bf_glActiveTexture)(GLenum texture); static void (APIENTRYP bf_glGenVertexArrays)(GLsizei n, GLuint* buffers); static void (APIENTRYP bf_glBindVertexArray)(GLenum target); @@ -107,10 +112,104 @@ static void (APIENTRYP bf_glGetObjectParameterivARB)(GLint obj, GLenum pname, GL static void (APIENTRYP bf_glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); static void (APIENTRYP bf_glClientActiveTexture)(GLenum texture); +static void (APIENTRYP bf_glGenTextures)(GLsizei n, GLuint *textures); +static void (APIENTRYP bf_glBindTexture)(GLenum target, GLuint texture); +static void (APIENTRYP bf_glPixelStorei)(GLenum pname, GLint param); +static void (APIENTRYP bf_glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +static void (APIENTRYP bf_glTexParameteri)(GLenum target, GLenum pname, GLint param); +static void (APIENTRYP bf_glDisable)(GLenum cap); +static void (APIENTRYP bf_glEnable)(GLenum cap); +static void (APIENTRYP bf_glCullFace)(GLenum mode); +static void (APIENTRYP bf_glDepthFunc)(GLenum mode); +static void (APIENTRYP bf_glDepthMask)(GLboolean flag); +static void (APIENTRYP bf_glPolygonMode)(GLenum face, GLenum mode); +static void (APIENTRYP bf_glBlendFunc)(GLenum sfactor, GLenum dfactor); +static void (APIENTRYP bf_glScissor)(GLint x, GLint y, GLsizei width, GLsizei height); +static void (APIENTRYP bf_glViewport)(GLint x, GLint y, GLsizei width, GLsizei height); +static void (APIENTRYP bf_glFramebufferTexture)(GLenum target, GLenum attachment, GLuint texture, GLint level); +static void (APIENTRYP bf_glDrawBuffers)(GLsizei n, const GLenum *bufs); +static GLenum (APIENTRYP bf_glCheckFramebufferStatus)(GLenum target); +static void (APIENTRYP bf_glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +static void (APIENTRYP bf_glBindFramebuffer)(GLenum target, GLuint framebuffer); +static void (APIENTRYP bf_glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +static void (APIENTRYP bf_glClearDepth)(GLdouble depth); +static void (APIENTRYP bf_glClear)(GLbitfield mask); + #if !defined BF_PLATFORM_OPENGL_ES2 static void (APIENTRYP bf_glGetVertexAttribdv)(GLuint index, GLenum pname, GLdouble *params); #endif +enum class DebugSource : uint32 +{ + API = 0x8246, + WindowSystem = 0x8247, + ShaderCompiler = 0x8248, + ThirdParty = 0x8249, + Application = 0x824A, + Other = 0x824B +}; + +enum class DebugType : uint32 +{ + Error = 0x824C, + DeprecatedBehavior = 0x824D, + UndefinedBehavior = 0x824E, + Portability = 0x824F, + Performance = 0x8250, + Other = 0x8251, + Marker = 0x8268, +}; + +enum class DebugSeverity : uint32 +{ + High = 0x9146, + Medium = 0x9147, + Low = 0x9148, + Notification = 0x826B +}; + +typedef void(*DEBUGPROC)(DebugSource source, DebugType type, uint32 id, DebugSeverity severity, uint32 length, char* message, void* userParam); +static void (APIENTRYP bf_glDebugMessageCallback)(DEBUGPROC fn, void* userdata); + +static void APIENTRY DebugMessageCallback(DebugSource source, DebugType type, uint32 id, DebugSeverity severity, uint32 length, char* message, void* userParam) +{ + if (type == DebugType::Marker || severity == DebugSeverity::Notification) + return; + + switch (type) + { + case DebugType::Error: + OutputDebugStr("[Error] "); + break; + case DebugType::DeprecatedBehavior: + OutputDebugStr("[DeprecatedBehavior] "); + break; + + case DebugType::UndefinedBehavior: + OutputDebugStr("[UndefinedBehavior] "); + break; + + case DebugType::Portability: + OutputDebugStr("[Portability] "); + break; + + case DebugType::Performance: + OutputDebugStr("[Performance] "); + break; + + case DebugType::Other: + OutputDebugStr("[Other] "); + break; + + case DebugType::Marker: + OutputDebugStr("[Marker] "); + break; + } + + OutputDebugStr(message); + OutputDebugStrF(" %d\n", id); +} + /// static int GetPowerOfTwo(int input) @@ -221,11 +320,17 @@ void GLTexture::Blt(ImageData* imageData, int x, int y) } else { - glBindTexture(GL_TEXTURE_2D, mGLTexture); - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, imageData->mWidth, imageData->mHeight, GL_RGBA, GL_UNSIGNED_BYTE, imageData->mBits); + bf_glBindTexture(GL_TEXTURE_2D, mGLTexture); + bf_glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, imageData->mWidth, imageData->mHeight, GL_RGBA, GL_UNSIGNED_BYTE, imageData->mBits); } } +void GLTexture::SetBits(int destX, int destY, int destWidth, int destHeight, int srcPitch, uint32 *bits) +{ + bf_glBindTexture(GL_TEXTURE_2D, mGLTexture); + bf_glTexSubImage2D(GL_TEXTURE_2D, 0, destX, destY, destWidth, destHeight, GL_RGBA, GL_UNSIGNED_BYTE, bits); +} + /// GLDrawBatch::GLDrawBatch() : DrawBatch() @@ -239,13 +344,6 @@ GLDrawBatch::~GLDrawBatch() extern int gBFDrawBatchCount; -struct GLVertex3D -{ - float x, y, z; - float u, v; - uint32 color; -}; - void GLDrawBatch::Render(RenderDevice* renderDevice, RenderWindow* renderWindow) { if (mIdxIdx == 0) @@ -258,34 +356,35 @@ void GLDrawBatch::Render(RenderDevice* renderDevice, RenderWindow* renderWindow) if (glRenderDevice->mGLVAO == 0) { + if (glRenderDevice->mGLVertexBuffer == 0) + { + bf_glGenBuffers(1, &glRenderDevice->mGLVertexBuffer); + bf_glGenBuffers(1, &glRenderDevice->mGLIndexBuffer); + } + + bf_glBindBuffer(GL_ARRAY_BUFFER, glRenderDevice->mGLVertexBuffer); bf_glGenVertexArrays(1, &glRenderDevice->mGLVAO); bf_glBindVertexArray(glRenderDevice->mGLVAO); - bf_glGenBuffers(1, &glRenderDevice->mGLVertexBuffer); - bf_glGenBuffers(1, &glRenderDevice->mGLIndexBuffer); + bf_glEnableVertexAttribArray(curShader->mAttribPosition); + bf_glVertexAttribPointer(curShader->mAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(DefaultVertex3D), (void*)offsetof(DefaultVertex3D, x)); + bf_glEnableVertexAttribArray(curShader->mAttribTexCoord0); + bf_glVertexAttribPointer(curShader->mAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(DefaultVertex3D), (void*)offsetof(DefaultVertex3D, u)); + bf_glEnableVertexAttribArray(curShader->mAttribColor); + bf_glVertexAttribPointer(curShader->mAttribColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(DefaultVertex3D), (void*)offsetof(DefaultVertex3D, color)); } - - auto glVertices = (GLVertex3D*)mVertices; + bf_glBindVertexArray(glRenderDevice->mGLVAO); + auto glVertices = (DefaultVertex3D*)mVertices; bf_glBindBuffer(GL_ARRAY_BUFFER, glRenderDevice->mGLVertexBuffer); - bf_glBufferData(GL_ARRAY_BUFFER, mVtxIdx * sizeof(GLVertex3D), mVertices, GL_STREAM_DRAW); - - bf_glEnableVertexAttribArray(curShader->mAttribPosition); - bf_glVertexAttribPointer(curShader->mAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLVertex3D), (void*)offsetof(GLVertex3D, x)); - bf_glEnableVertexAttribArray(curShader->mAttribTexCoord0); - bf_glVertexAttribPointer(curShader->mAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex3D), (void*)offsetof(GLVertex3D, u)); - bf_glEnableVertexAttribArray(curShader->mAttribColor); - bf_glVertexAttribPointer(curShader->mAttribColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GLVertex3D), (void*)offsetof(GLVertex3D, color)); + bf_glBufferData(GL_ARRAY_BUFFER, mVtxIdx * sizeof(DefaultVertex3D), mVertices, GL_STREAM_DRAW); + bf_glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glRenderDevice->mGLIndexBuffer); + bf_glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIdxIdx * sizeof(int16), mIndices, GL_STREAM_DRAW); if (mRenderState != renderDevice->mPhysRenderState) renderDevice->PhysSetRenderState(mRenderState); - bf_glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glRenderDevice->mGLIndexBuffer); - bf_glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIdxIdx * sizeof(int16), mIndices, GL_STREAM_DRAW); bf_glDrawElements(GL_TRIANGLES, mIdxIdx, GL_UNSIGNED_SHORT, NULL); - - bf_glBufferData(GL_ELEMENT_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW); - bf_glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW); } GLDrawLayer::GLDrawLayer() @@ -337,16 +436,11 @@ static void BFGetGLProc(T& proc, const char* name) #define BF_GET_GLPROC(name) BFGetGLProc(bf_##name, #name) -void GL_DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) -{ - NOP; -} - GLRenderWindow::GLRenderWindow(GLRenderDevice* renderDevice, SDL_Window* sdlWindow) { if (bf_glGenBuffers == NULL) { - BF_GET_GLPROC(glDebugMessageCallback); + BF_GET_GLPROC(glGetError); BF_GET_GLPROC(glActiveTexture); BF_GET_GLPROC(glGenVertexArrays); BF_GET_GLPROC(glBindVertexArray); @@ -407,11 +501,49 @@ GLRenderWindow::GLRenderWindow(GLRenderDevice* renderDevice, SDL_Window* sdlWind BF_GET_GLPROC(glGetObjectParameterivARB); BF_GET_GLPROC(glCompressedTexImage2D); BF_GET_GLPROC(glClientActiveTexture); + BF_GET_GLPROC(glGenTextures); + BF_GET_GLPROC(glBindTexture); + BF_GET_GLPROC(glPixelStorei); + BF_GET_GLPROC(glTexImage2D); + BF_GET_GLPROC(glTexParameteri); + BF_GET_GLPROC(glDisable); + BF_GET_GLPROC(glEnable); + BF_GET_GLPROC(glCullFace); + BF_GET_GLPROC(glDepthMask); + BF_GET_GLPROC(glPolygonMode); + BF_GET_GLPROC(glDepthFunc); + BF_GET_GLPROC(glBlendFunc); + BF_GET_GLPROC(glScissor); + BF_GET_GLPROC(glViewport); + BF_GET_GLPROC(glFramebufferTexture); + BF_GET_GLPROC(glDrawBuffers); + BF_GET_GLPROC(glCheckFramebufferStatus); + BF_GET_GLPROC(glTexSubImage2D); + BF_GET_GLPROC(glBindFramebuffer); + BF_GET_GLPROC(glClearColor); + BF_GET_GLPROC(glClearDepth); + BF_GET_GLPROC(glClear); #if !defined BF_PLATFORM_OPENGL_ES2 BF_GET_GLPROC(glGetVertexAttribdv); #endif - } + +#if defined(_DEBUG) && !defined(BF_PLATFORM_OPENGL_ES2) + + BF_GET_GLPROC(glDebugMessageCallback); + if (bf_glDebugMessageCallback != NULL) + { + bf_glEnable(GL_DEBUG_OUTPUT); + bf_glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + bf_glDebugMessageCallback(&DebugMessageCallback, NULL); + } +#endif + + } + +#ifndef BF_PLATFORM_OPENGL_ES2 + //glEnableClientState(GL_INDEX_ARRAY); +#endif mSDLWindow = sdlWindow; mRenderDevice = renderDevice; @@ -427,10 +559,25 @@ GLRenderWindow::~GLRenderWindow() void GLRenderWindow::PhysSetAsTarget() { - GLfloat matrix[4][4]; - CreateOrthographicOffCenter(0.0f, (float)mWidth, (float)mHeight, 0.0f, -100.0f, 100.0f, matrix); - glViewport(0, 0, (GLsizei)mWidth, (GLsizei)mHeight); + bf_SDL_GL_MakeCurrent(mSDLWindow, ((SdlBFApp*)gBFApp)->mGLContext); + + bf_glEnable(GL_BLEND); + bf_glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + if (mResizePending) + { + Resized(); + } + + bf_glViewport(0, 0, (GLsizei)mWidth, (GLsizei)mHeight); + bf_glScissor(0, 0, (GLsizei)mWidth, (GLsizei)mHeight); + + if (!mHasBeenDrawnTo) + { + bf_glClearColor(0, 0, 0, 0); + bf_glClearDepth(1); + bf_glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } mHasBeenDrawnTo = true; } @@ -449,70 +596,38 @@ void GLRenderWindow::Resized() mRenderDevice->mResizeCount++; mResizeNum = mRenderDevice->mResizeCount; - bf_SDL_GetWindowSize(mSDLWindow, &mWidth, &mHeight); - - //NOT_IMPL; - /*if (mGLSwapChain != NULL) - { - mGLRenderTargetView->Release(); - mGLBackBuffer->Release(); - GLCHECK(mGLSwapChain->ResizeBuffers(1, mWidth, mHeight, GLGI_FORMAT_R8G8B8A8_UNORM, 0)); - - GLCHECK(mGLSwapChain->GetBuffer(0, __uuidof(IGL10Texture2D), (LPVOID*)&mGLBackBuffer)); - GLCHECK(mRenderDevice->mGLDevice->CreateRenderTargetView(mGLBackBuffer, NULL, &mGLRenderTargetView)); - }*/ + bf_SDL_GetWindowSizeInPixels(mSDLWindow, &mWidth, &mHeight); + mResizePending = false; } void GLRenderWindow::Present() { bf_SDL_GL_SwapWindow(mSDLWindow); - //GLCHECK(mGLSwapChain->Present((mWindow->mFlags & BFWINDOW_VSYNC) ? 1 : 0, 0)); } void GLRenderWindow::CopyBitsTo(uint32* dest, int width, int height) { mCurDrawLayer->Flush(); - NOT_IMPL; - /*GL10_TEXTURE2D_DESC texDesc; - texDesc.ArraySize = 1; - texDesc.BindFlags = 0; - texDesc.CPUAccessFlags = 0; - texDesc.Format = GLGI_FORMAT_R8G8B8A8_UNORM; - texDesc.Width = width; - texDesc.Height = height; - texDesc.MipLevels = 1; - texDesc.MiscFlags = 0; - texDesc.SampleDesc.Count = 1; - texDesc.SampleDesc.Quality = 0; - texDesc.Usage = GL10_USAGE_STAGING; - texDesc.CPUAccessFlags = GL10_CPU_ACCESS_READ; - - IGL10Texture2D *texture; - GLCHECK(mRenderDevice->mGLDevice->CreateTexture2D(&texDesc, 0, &texture)); - mRenderDevice->mGLDevice->CopyResource(texture, mGLBackBuffer); - - GL10_MAPPED_TEXTURE2D mapTex; - GLCHECK(texture->Map(GL10CalcSubresource(0, 0, 1), GL10_MAP_READ, 0, &mapTex)); - uint8* srcPtr = (uint8*) mapTex.pData; - uint8* destPtr = (uint8*) dest; - for (int y = 0; y < height; y++) - { - memcpy(destPtr, srcPtr, width*sizeof(uint32)); - srcPtr += mapTex.RowPitch; - destPtr += width * 4; - } - texture->Unmap(0); - texture->Release();*/ +} + +float GLRenderWindow::GetRefreshRate() +{ + SDL_DisplayID displayID = bf_SDL_GetDisplayForWindow(mSDLWindow); + const SDL_DisplayMode *mode = bf_SDL_GetCurrentDisplayMode(displayID); + + if (mode != NULL) + return mode->refresh_rate; + + return RenderWindow::GetRefreshRate(); } /// GLRenderDevice::GLRenderDevice() { - //mGLDevice = NULL; mCurShader = NULL; - mGLVAO = 0; + mGLVAO = 0; mGLVertexBuffer = 0; mGLIndexBuffer = 0; mBlankTexture = 0; @@ -527,84 +642,22 @@ bool GLRenderDevice::Init(BFApp* app) { SdlBFApp* winApp = (SdlBFApp*) app; - //RenderState* glRenderState; - if (mDefaultRenderState == NULL) - { - auto dxRenderState = (RenderState*)CreateRenderState(NULL); + BF_ASSERT(mDefaultRenderState == NULL); + auto renderState = (RenderState*)CreateRenderState(NULL); - mDefaultRenderState = dxRenderState; - mDefaultRenderState->mDepthFunc = DepthFunc_Less; - mDefaultRenderState->mWriteDepthBuffer = true; - - mPhysRenderState = mDefaultRenderState; - } - else - { - //glRenderState = (DXRenderState*)mDefaultRenderState; - //glRenderState->ReinitNative(); - } - - /// - - ////Use GL10_CREATE_DEVICE_DEBUG for PIX - //GLCHECK(GL10CreateDevice(NULL, GL10_DRIVER_TYPE_HARDWARE, NULL, GL10_CREATE_DEVICE_DEBUG, GL10_SDK_VERSION, &mGLDevice)); - ////GLCHECK(GL10CreateDevice(NULL, GL10_DRIVER_TYPE_HARDWARE, NULL, 0, GL10_SDK_VERSION, &mGLDevice)); - - //IGLGIDevice* pGLGIDevice = NULL; - //GLCHECK(mGLDevice->QueryInterface(__uuidof(IGLGIDevice), reinterpret_cast(&pGLGIDevice))); - - //IGLGIAdapter* pGLGIAdapter = NULL; - //GLCHECK(pGLGIDevice->GetParent(__uuidof(IGLGIAdapter), reinterpret_cast(&pGLGIAdapter))); - - //IGLGIFactory* pGLGIFactory = NULL; - //GLCHECK(pGLGIAdapter->GetParent(__uuidof(IGLGIFactory), reinterpret_cast(&mGLGIFactory))); - - ////set rasterizer - //GL10_RASTERIZER_DESC rasterizerState; - //rasterizerState.CullMode = GL10_CULL_NONE; - //rasterizerState.FillMode = GL10_FILL_SOLID; - //rasterizerState.FrontCounterClockwise = true; - // rasterizerState.DepthBias = false; - // rasterizerState.DepthBiasClamp = 0; - // rasterizerState.SlopeScaledDepthBias = 0; - // rasterizerState.DepthClipEnable = false; - // rasterizerState.ScissorEnable = true; - // //TODO:rasterizerState.MultisampleEnable = false; - //rasterizerState.MultisampleEnable = true; - // rasterizerState.AntialiasedLineEnable = true; - // - //mGLDevice->CreateRasterizerState( &rasterizerState, &mGLRasterizerStateClipped); - // - //rasterizerState.ScissorEnable = false; - //mGLDevice->CreateRasterizerState( &rasterizerState, &mGLRasterizerStateUnclipped); - //mGLDevice->RSSetState(mGLRasterizerStateUnclipped); - // - //IGL10BlendState* g_pBlendState = NULL; - - //GL10_BLEND_DESC BlendState; - //ZeroMemory(&BlendState, sizeof(GL10_BLEND_DESC)); - //BlendState.BlendEnable[0] = TRUE; - ////BlendState.SrcBlend = GL10_BLEND_SRC_ALPHA; - //BlendState.SrcBlend = GL10_BLEND_ONE; - - //BlendState.DestBlend = GL10_BLEND_INV_SRC_ALPHA; - //BlendState.BlendOp = GL10_BLEND_OP_ADD; - //BlendState.SrcBlendAlpha = GL10_BLEND_ONE; - //BlendState.DestBlendAlpha = GL10_BLEND_ONE; - //BlendState.BlendOpAlpha = GL10_BLEND_OP_ADD; - //BlendState.RenderTargetWriteMask[0] = GL10_COLOR_WRITE_ENABLE_ALL; - //mGLDevice->CreateBlendState(&BlendState, &mGLNormalBlendState); - - //BlendState.DestBlend = GL10_BLEND_ONE; - //mGLDevice->CreateBlendState(&BlendState, &mGLAdditiveBlendState); - - //PhysSetAdditive(false); + mDefaultRenderState = renderState; + mDefaultRenderState->mDepthFunc = DepthFunc_Less; + mDefaultRenderState->mWriteDepthBuffer = true; + mPhysRenderState = mDefaultRenderState; return true; } void GLRenderDevice::FrameStart() { + if (mRenderWindowList.IsEmpty()) + return; + mCurRenderTarget = NULL; mPhysRenderWindow = NULL; @@ -613,6 +666,10 @@ void GLRenderDevice::FrameStart() aRenderWindow->mHasBeenDrawnTo = false; aRenderWindow->mHasBeenTargeted = false; } + + bf_glDisable(GL_SCISSOR_TEST); + bf_glDisable(GL_CULL_FACE); + bf_glDisable(GL_DEPTH_TEST); } void GLRenderDevice::FrameEnd() @@ -656,7 +713,7 @@ Shader* GLRenderDevice::LoadShader(const StringImpl& fileName, VertexDefinition* { GLShader* glShader = new GLShader(); - glShader->mVertexSize = sizeof(GLVertex3D); + glShader->mVertexSize = sizeof(DefaultVertex3D); glShader->mGLVertexShader = bf_glCreateShader(GL_VERTEX_SHADER); glShader->mGLFragmentShader = bf_glCreateShader(GL_FRAGMENT_SHADER); @@ -711,6 +768,7 @@ Shader* GLRenderDevice::LoadShader(const StringImpl& fileName, VertexDefinition* glShader->mAttribColor = bf_glGetAttribLocation(glShader->mGLProgram, "color"); glShader->mAttribTex0 = bf_glGetUniformLocation(glShader->mGLProgram, "tex"); glShader->mAttribTex1 = bf_glGetUniformLocation(glShader->mGLProgram, "tex2"); + glShader->mScreenUniformLoc = bf_glGetUniformLocation(glShader->mGLProgram, "screenMatrix"); return glShader; } @@ -721,29 +779,90 @@ void GLRenderDevice::PhysSetRenderState(RenderState* renderState) if (mCurShader != NULL) { bf_glUseProgram(mCurShader->mGLProgram); - - GLRenderDevice* aRenderDevice = (GLRenderDevice*)gBFApp->mRenderDevice; - - //TODO: Cache more - - GLfloat matrix[4][4]; - CreateOrthographicOffCenter(0.0f, (float)mPhysRenderWindow->mWidth, (float)mPhysRenderWindow->mHeight, 0.0f, -100.0f, 100.0f, matrix); - GLint matrixLoc = bf_glGetUniformLocation(mCurShader->mGLProgram, "screenMatrix"); - //BF_ASSERT(matrixLoc >= 0); - if (matrixLoc >= 0) - bf_glUniformMatrix4fv(matrixLoc, 1, false, (float*)matrix); + if (mCurShader->mScreenUniformLoc >= 0) + { + GLfloat matrix[4][4]; + CreateOrthographicOffCenter(0.0f, (float)mPhysRenderWindow->mWidth, (float)mPhysRenderWindow->mHeight, 0.0f, -100.0f, 100.0f, matrix); + bf_glUniformMatrix4fv(mCurShader->mScreenUniformLoc, 1, false, (float*)matrix); + } } if (renderState->mClipped) { - glEnable(GL_SCISSOR_TEST); - glScissor((GLsizei)renderState->mClipRect.x, - mPhysRenderWindow->mHeight - (GLsizei)renderState->mClipRect.y - (GLsizei)renderState->mClipRect.height, - (GLsizei)renderState->mClipRect.width, (GLsizei)renderState->mClipRect.height); + bf_glEnable(GL_SCISSOR_TEST); + bf_glScissor((GLsizei)renderState->mClipRect.x, + mPhysRenderWindow->mHeight - (GLsizei)renderState->mClipRect.y - (GLsizei)renderState->mClipRect.height, + (GLsizei)renderState->mClipRect.width, (GLsizei)renderState->mClipRect.height); } else { - glDisable(GL_SCISSOR_TEST); + bf_glDisable(GL_SCISSOR_TEST); + } + + if (renderState->mCullMode != mPhysRenderState->mCullMode) + { + switch (renderState->mCullMode) + { + case CullMode_None: + bf_glDisable(GL_CULL_FACE); + break; + case CullMode_Front: + bf_glEnable(GL_CULL_FACE); + bf_glCullFace(GL_FRONT); + break; + case CullMode_Back: + bf_glEnable(GL_CULL_FACE); + bf_glCullFace(GL_BACK); + break; + } + } + + if (renderState->mDepthFunc != mPhysRenderState->mDepthFunc) + { + bf_glDepthMask(renderState->mWriteDepthBuffer ? GL_TRUE : GL_FALSE); + + switch (renderState->mDepthFunc) + { + case DepthFunc_Never: + bf_glDisable(GL_DEPTH_TEST); + break; + case DepthFunc_Less: + bf_glDepthFunc(GL_LESS); + bf_glEnable(GL_DEPTH_TEST); + break; + case DepthFunc_LessEqual: + bf_glDepthFunc(GL_LEQUAL); + bf_glEnable(GL_DEPTH_TEST); + break; + case DepthFunc_Equal: + bf_glDepthFunc(GL_EQUAL); + bf_glEnable(GL_DEPTH_TEST); + break; + case DepthFunc_Greater: + bf_glDepthFunc(GL_GREATER); + bf_glEnable(GL_DEPTH_TEST); + break; + case DepthFunc_NotEqual: + bf_glDepthFunc(GL_NOTEQUAL); + bf_glEnable(GL_DEPTH_TEST); + break; + case DepthFunc_GreaterEqual: + bf_glDepthFunc(GL_GEQUAL); + bf_glEnable(GL_DEPTH_TEST); + break; + case DepthFunc_Always: + bf_glDepthFunc(GL_ALWAYS); + bf_glEnable(GL_DEPTH_TEST); + break; + } + } + + if ((renderState->mWireframe != mPhysRenderState->mWireframe)) + { + if (renderState->mWireframe) + bf_glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + else + bf_glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } mPhysRenderState = renderState; @@ -751,15 +870,56 @@ void GLRenderDevice::PhysSetRenderState(RenderState* renderState) Texture* GLRenderDevice::CreateRenderTarget(int width, int height, bool destAlpha) { + // GLTexture* texture = new GLTexture(); + // GLuint id; + // bf_glGenTextures(1, &id); + // bf_glBindTexture(GL_TEXTURE_2D, id); + // bf_glTexImage2D(GL_TEXTURE_2D, 0, (destAlpha ? GL_RGBA : GL_RGB), width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + // bf_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // bf_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + // + // GLuint depthrenderbuffer; + // bf_glGenRenderbuffers(1, &depthrenderbuffer); + // bf_glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer); + // bf_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); + // bf_glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbuffer); + // texture->mGLTexture = id; + // texture->mGLTexture2 = depthrenderbuffer; + // texture->AddRef(); + // return texture; NOT_IMPL; } +Texture* GLRenderDevice::CreateDynTexture(int width, int height) +{ + auto context = bf_SDL_GL_GetCurrentContext(); + auto err = bf_SDL_GetError(); + GLuint texture = 0; + bf_glGenTextures(1, &texture); + auto result = bf_glGetError(); + + bf_glBindTexture(GL_TEXTURE_2D, texture); + bf_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + bf_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + bf_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + bf_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + bf_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + GLTexture* glTexture = new GLTexture(); + glTexture->mGLTexture = texture; + glTexture->mGLTexture2 = 0; + glTexture->mRenderDevice = this; + glTexture->mWidth = width; + glTexture->mHeight = height; + glTexture->AddRef(); + return glTexture; +} + void GLRenderDevice::SetRenderState(RenderState* renderState) { mCurRenderState = renderState; } - void GLSetTextureCmd::Render(RenderDevice* renderDevice, RenderWindow* renderWindow) { /*#ifdef BF_PLATFORM_OPENGL_ES2 @@ -785,12 +945,12 @@ void GLSetTextureCmd::Render(RenderDevice* renderDevice, RenderWindow* renderWin if (glRenderDevice->mBlankTexture == 0) { - glGenTextures(1, &glRenderDevice->mBlankTexture); - glBindTexture(GL_TEXTURE_2D, glRenderDevice->mBlankTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + bf_glGenTextures(1, &glRenderDevice->mBlankTexture); + bf_glBindTexture(GL_TEXTURE_2D, glRenderDevice->mBlankTexture); + bf_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + bf_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + bf_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + bf_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); /*if (bf_glCompressedTexImage2D != NULL) { @@ -801,10 +961,10 @@ void GLSetTextureCmd::Render(RenderDevice* renderDevice, RenderWindow* renderWin else*/ { uint16 color = 0; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, + bf_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, &color); } - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + bf_glPixelStorei(GL_UNPACK_ALIGNMENT, 1); } if (glTexture->mImageData != NULL) @@ -817,12 +977,12 @@ void GLSetTextureCmd::Render(RenderDevice* renderDevice, RenderWindow* renderWin for (int texNum = 0; texNum < 2/*texCount*/; texNum++) { GLuint glTextureID; - glGenTextures(1, &glTextureID); - glBindTexture(GL_TEXTURE_2D, glTextureID); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + bf_glGenTextures(1, &glTextureID); + bf_glBindTexture(GL_TEXTURE_2D, glTextureID); + bf_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + bf_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + bf_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + bf_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); //if (imageData->mHWBits != NULL) //{ @@ -837,11 +997,11 @@ void GLSetTextureCmd::Render(RenderDevice* renderDevice, RenderWindow* renderWin //} //else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glTexture->mImageData->mWidth, glTexture->mImageData->mHeight, 0, + bf_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glTexture->mImageData->mWidth, glTexture->mImageData->mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, glTexture->mImageData->mBits); } - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + bf_glPixelStorei(GL_UNPACK_ALIGNMENT, 1); if (texNum == 0) glTexture->mGLTexture = glTextureID; @@ -855,5 +1015,5 @@ void GLSetTextureCmd::Render(RenderDevice* renderDevice, RenderWindow* renderWin bf_glActiveTexture(GL_TEXTURE0 + mTextureIdx); //glUniform1i(curShader->mAttribTex0, 0); - glBindTexture(GL_TEXTURE_2D, glTexture->mGLTexture); + bf_glBindTexture(GL_TEXTURE_2D, glTexture->mGLTexture); } diff --git a/BeefySysLib/platform/sdl/GLRenderDevice.h b/BeefySysLib/platform/sdl/GLRenderDevice.h index 241ff57fc..76219638b 100644 --- a/BeefySysLib/platform/sdl/GLRenderDevice.h +++ b/BeefySysLib/platform/sdl/GLRenderDevice.h @@ -4,9 +4,9 @@ #include "util/Dictionary.h" #ifdef BF_PLATFORM_OPENGL_ES2 -#include +#include #else -#include +#include #endif #include "gfx/Shader.h" @@ -28,14 +28,14 @@ class GLTexture : public Texture GLuint mGLTexture; GLuint mGLTexture2; ImageData* mImageData; - //IGL10RenderTargetView* mGLRenderTargetView; public: GLTexture(); - ~GLTexture(); + virtual ~GLTexture(); - virtual void PhysSetAsTarget(); + virtual void PhysSetAsTarget() override; virtual void Blt(ImageData* imageData, int x, int y) override; + virtual void SetBits(int destX, int destY, int destWidth, int destHeight, int srcPitch, uint32 *bits) override; }; class GLShaderParam : public ShaderParam @@ -47,7 +47,7 @@ class GLShaderParam : public ShaderParam GLShaderParam(); ~GLShaderParam(); - virtual void SetTexture(Texture* texture); + virtual void SetTexture(Texture* texture) override; virtual void SetFloat4(float x, float y, float z, float w) override; }; @@ -56,18 +56,17 @@ typedef Dictionary GLShaderParamMap; class GLShader : public Shader { public: - //IGL10Effect* mGLEffect; - - GLuint mGLVertexShader; - GLuint mGLFragmentShader; - GLuint mGLProgram; - GLint mAttribPosition; - GLint mAttribTexCoord0; - GLint mAttribColor; - GLint mAttribTex0; - GLint mAttribTex1; + GLuint mGLVertexShader; + GLuint mGLFragmentShader; + GLuint mGLProgram; + GLint mAttribPosition; + GLint mAttribTexCoord0; + GLint mAttribColor; + GLint mAttribTex0; + GLint mAttribTex1; + GLint mScreenUniformLoc; - GLShaderParamMap mParamsMap; + GLShaderParamMap mParamsMap; public: GLShader(); @@ -90,7 +89,7 @@ class GLSetTextureCmd : public RenderCmd class GLDrawBatch : public DrawBatch { public: - //IGL10Buffer* mGLBuffer; + public: GLDrawBatch(); @@ -126,13 +125,14 @@ class GLRenderWindow : public RenderWindow public: GLRenderWindow(GLRenderDevice* renderDevice, SDL_Window* sdlWindow); - ~GLRenderWindow(); + virtual ~GLRenderWindow(); void SetAsTarget() override; void Resized() override; - virtual void Present() override; + void Present() override; void CopyBitsTo(uint32* dest, int width, int height); + float GetRefreshRate() override; }; class GLRenderDevice : public RenderDevice @@ -167,7 +167,7 @@ class GLRenderDevice : public RenderDevice Shader* LoadShader(const StringImpl& fileName, VertexDefinition* vertexDefinition) override; Texture* CreateRenderTarget(int width, int height, bool destAlpha) override; - virtual Texture* CreateDynTexture(int width, int height) override { return NULL; } + virtual Texture* CreateDynTexture(int width, int height) override; virtual void SetRenderState(RenderState* renderState) override; /*void SetShader(Shader* shader) override; diff --git a/BeefySysLib/platform/sdl/SdlBFApp.cpp b/BeefySysLib/platform/sdl/SdlBFApp.cpp index d310f6db7..428517278 100644 --- a/BeefySysLib/platform/sdl/SdlBFApp.cpp +++ b/BeefySysLib/platform/sdl/SdlBFApp.cpp @@ -1,7 +1,26 @@ #include "SdlBFApp.h" +#include "BFApp.h" +#include "Common.h" #include "GLRenderDevice.h" #include "platform/PlatformHelper.h" -#include +#include "platform/PlatformInterface.h" +#include "img/PNGData.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include USING_NS_BF; @@ -10,39 +29,122 @@ USING_NS_BF; #pragma comment(lib, "imm32.lib") #pragma comment(lib, "version.lib") -SDL_Window* (SDLCALL* bf_SDL_CreateWindow)(const char* title, int x, int y, int w, int h, Uint32 flags); -int (SDLCALL* bf_SDL_GL_SetAttribute)(SDL_GLattr attr, int value); -Uint32 (SDLCALL* bf_SDL_GetWindowID)(SDL_Window* window); +bool (SDLCALL* bf_SDL_Init)(SDL_InitFlags flags); +void (SDLCALL* bf_SDL_Quit)(void); +void* (SDLCALL* bf_SDL_malloc)(size_t size); +void (SDLCALL* bf_SDL_free)(void* mem); +void (SDLCALL* bf_SDL_memset)(void* dest, int c, size_t len); +void* (SDLCALL* bf_SDL_memcpy)(void *dst, const void *src, size_t len); + +SDL_PropertiesID (SDLCALL* bf_SDL_CreateProperties)(void); +void (SDLCALL* bf_SDL_DestroyProperties)(SDL_PropertiesID props); + +bool (SDLCALL* bf_SDL_SetNumberProperty)(SDL_PropertiesID props, const char* name, int64_t value); +bool (SDLCALL* bf_SDL_SetBooleanProperty)(SDL_PropertiesID props, const char* name, bool value); +bool (SDLCALL* bf_SDL_SetStringProperty)(SDL_PropertiesID props, const char* name, const char* value); +bool (SDLCALL* bf_SDL_SetPointerProperty)(SDL_PropertiesID props, const char *name, void *value); + +SDL_Window* (SDLCALL* bf_SDL_CreateWindowWithProperties)(SDL_PropertiesID props); +SDL_WindowID (SDLCALL* bf_SDL_GetWindowID)(SDL_Window* window); void (SDLCALL* bf_SDL_DestroyWindow)(SDL_Window* window); -int (SDLCALL* bf_SDL_Init)(Uint32 flags); -void (SDLCALL* bf_SDL_GetWindowPosition)(SDL_Window* window,int* x, int* y); +bool (SDLCALL* bf_SDL_SyncWindow)(SDL_Window* window); +bool (SDLCALL* bf_SDL_GetWindowPosition)(SDL_Window* window,int* x, int* y); +bool (SDLCALL* bf_SDL_SetWindowPosition)(SDL_Window* window, int x, int y); +bool (SDLCALL* bf_SDL_GetWindowSizeInPixels)(SDL_Window* window, int* w, int* h); +bool (SDLCALL* bf_SDL_GetWindowSize)(SDL_Window* window, int* w, int* h); +bool (SDLCALL* bf_SDL_SetWindowSize)(SDL_Window* window, int w, int h); +bool (SDLCALL* bf_SDL_SetWindowMinimumSize)(SDL_Window* window, int min_w, int min_h); +bool (SDLCALL* bf_SDL_SetWindowTitle)(SDL_Window* window, const char* title); +bool (SDLCALL* bf_SDL_SetWindowIcon)(SDL_Window* window, SDL_Surface* icon); +SDL_Window* (SDLCALL* bf_SDL_GetMouseFocus)(); + +bool (SDLCALL* bf_SDL_ShowCursor)(void); +bool (SDLCALL* bf_SDL_HideCursor)(void); + char* (SDLCALL* bf_SDL_GetClipboardText)(void); -int (SDLCALL* bf_SDL_SetClipboardText)(const char* text); -void* (SDLCALL* bf_SDL_GL_GetProcAddress)(const char* proc); -void (SDLCALL* bf_SDL_GetWindowSize)(SDL_Window* window, int* w, int* h); -void (SDLCALL* bf_SDL_GL_SwapWindow)(SDL_Window* window); -void (SDLCALL* bf_SDL_free)(void* mem); -void (SDLCALL* bf_SDL_SetWindowPosition)(SDL_Window* window, int x, int y); -int (SDLCALL* bf_SDL_PollEvent)(SDL_Event* event); +bool (SDLCALL* bf_SDL_SetClipboardText)(const char* text); +void* (SDLCALL* bf_SDL_GetClipboardData)(const char *mime_type, size_t *size); +bool (SDLCALL* bf_SDL_SetClipboardData)(SDL_ClipboardDataCallback callback, SDL_ClipboardCleanupCallback cleanup, void *userdata, const char **mime_types, size_t num_mime_types); +bool (SDLCALL* bf_SDL_StartTextInput)(SDL_Window* window); +bool (SDLCALL* bf_SDL_StopTextInput)(SDL_Window* window); + +bool (SDLCALL* bf_SDL_PollEvent)(SDL_Event* event); +bool (SDLCALL* bf_SDL_PushEvent)(SDL_Event* event); +void (SDLCALL* bf_SDL_PumpEvents)(void); +int (SDLCALL* bf_SDL_PeepEvents)(SDL_Event *events, int numevents, SDL_EventAction action, Uint32 minType, Uint32 maxType); +bool (SDLCALL* bf_SDL_SetError)(const char *fmt, ...); const char* (SDLCALL* bf_SDL_GetError)(void); + +bool (SDLCALL* bf_SDL_SetHint)(const char *name, const char *value); + +SDL_DisplayID (SDLCALL* bf_SDL_GetPrimaryDisplay)(void); +SDL_DisplayID* (SDLCALL* bf_SDL_GetDisplays)(int* count); +bool (SDLCALL* bf_SDL_GetDisplayBounds)(SDL_DisplayID displayID, SDL_Rect* rect); +SDL_DisplayMode* (SDLCALL* bf_SDL_GetDesktopDisplayMode)(SDL_DisplayID displayID); +bool (SDLCALL* bf_SDL_HasRectIntersection)(const SDL_Rect* A, const SDL_Rect* B); +SDL_DisplayID (SDLCALL* bf_SDL_GetDisplayForWindow)(SDL_Window *window); +const SDL_DisplayMode* (SDLCALL* bf_SDL_GetCurrentDisplayMode)(SDL_DisplayID displayID); + +SDL_Surface* (SDLCALL* bf_SDL_CreateSurfaceFrom)(int width, int height, SDL_PixelFormat format, void *pixels, int pitch); + SDL_GLContext (SDLCALL* bf_SDL_GL_CreateContext)(SDL_Window* window); -void (SDLCALL* bf_SDL_Quit)(void); +SDL_GLContext (SDLCALL* bf_SDL_GL_GetCurrentContext)(); +SDL_Window* (SDLCALL* bf_SDL_GL_GetCurrentWindow)(); +bool (SDLCALL* bf_SDL_GL_MakeCurrent)(SDL_Window* window, SDL_GLContext context); +bool (SDLCALL* bf_SDL_GL_SetAttribute)(SDL_GLAttr attr, int value); +void* (SDLCALL* bf_SDL_GL_GetProcAddress)(const char* proc); +bool (SDLCALL* bf_SDL_GL_SwapWindow)(SDL_Window* window); + +static SDL_Cursor* (SDLCALL* bf_SDL_GetDefaultCursor)(); +static SDL_Cursor* (SDLCALL* bf_SDL_CreateSystemCursor)(SDL_SystemCursor id); +static bool (SDLCALL* bf_SDL_SetCursor)(SDL_Cursor* cursor); +static SDL_WindowFlags (SDLCALL* bf_SDL_GetWindowFlags)(SDL_Window *window); +static bool (SDLCALL* bf_SDL_HideWindow)(SDL_Window *window); +static bool (SDLCALL* bf_SDL_RestoreWindow)(SDL_Window *window); +static bool (SDLCALL* bf_SDL_MinimizeWindow)(SDL_Window *window); +static bool (SDLCALL* bf_SDL_MaximizeWindow)(SDL_Window *window); +static bool (SDLCALL* bf_SDL_ShowWindow)(SDL_Window *window); +static bool (SDLCALL* bf_SDL_RaiseWindow)(SDL_Window* window); + +struct AdjustedMonRect +{ + int mMonCount; + int mX; + int mY; + int mWidth; + int mHeight; +}; + +static int bfMouseBtnOf[4] = {NULL, 0, 2, 1}; // Translate SDL mouse buttons to what Beef expects. + +static const char* mimeTypes[] = +{ + "text/plain;charset=utf-8", + "text/vnd.beeflang.bf-text", + "text/vnd.beeflang.file-list" +}; static HMODULE gSDLModule; +static HMODULE gSDLImageModule; static HMODULE GetSDLModule(const StringImpl& installDir) { if (gSDLModule == NULL) { - String loadPath = installDir + "SDL2.dll"; +#if defined (BF_PLATFORM_WINDOWS) + String loadPath = installDir + "SDL3.dll"; gSDLModule = ::LoadLibraryA(loadPath.c_str()); +#elif defined (BF_PLATFORM_LINUX) + String loadPath = "libSDL3.so"; + gSDLModule = dlopen(loadPath.c_str(), RTLD_LAZY); +#endif if (gSDLModule == NULL) { #ifdef BF_PLATFORM_WINDOWS - ::MessageBoxA(NULL, "Failed to load SDL2.dll", "FATAL ERROR", MB_OK | MB_ICONERROR); + ::MessageBoxA(NULL, "Failed to load SDL3.dll", "FATAL ERROR", MB_OK | MB_ICONERROR); ::ExitProcess(1); #endif - BF_FATAL("Failed to load SDL2.dll"); + BF_FATAL("Failed to load libSDL3.so"); } } return gSDLModule; @@ -51,64 +153,113 @@ static HMODULE GetSDLModule(const StringImpl& installDir) template static void BFGetSDLProc(T& proc, const char* name, const StringImpl& installDir) { +#if defined (BF_PLATFORM_WINDOWS) proc = (T)::GetProcAddress(GetSDLModule(installDir), name); +#elif defined (BF_PLATFORM_LINUX) + proc = (T)dlsym(GetSDLModule(installDir), name); +#endif } #define BF_GET_SDLPROC(name) BFGetSDLProc(bf_##name, #name, mInstallDir) +static SDL_Surface* gAppIconSurface; + +BF_EXPORT void BF_CALLTYPE BFApp_RegisterAppIcon(uint8* imageData, int size) +{ + PNGData* image = new PNGData(); + image->LoadFromMemory(imageData, size); + gAppIconSurface = bf_SDL_CreateSurfaceFrom(image->mWidth, image->mHeight, SDL_PIXELFORMAT_ABGR8888, image->mBits, image->mWidth*4); +} + SdlBFWindow::SdlBFWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags) { - int sdlWindowFlags = 0; - if (windowFlags & BFWINDOW_RESIZABLE) - sdlWindowFlags |= SDL_WINDOW_RESIZABLE; - sdlWindowFlags |= SDL_WINDOW_OPENGL; - if (windowFlags & BFWINDOW_FULLSCREEN) - sdlWindowFlags |= SDL_WINDOW_FULLSCREEN; -#ifdef BF_PLATFORM_FULLSCREEN - sdlWindowFlags |= SDL_WINDOW_FULLSCREEN; -#endif + SDL_PropertiesID props = bf_SDL_CreateProperties(); + + bf_SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true); + bf_SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, (windowFlags & BFWINDOW_RESIZABLE) != 0); + bf_SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, (windowFlags & BFWINDOW_FULLSCREEN) != 0); + bf_SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN, (windowFlags & BFWINDOW_BORDER) == 0); + bf_SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_TOOLTIP_BOOLEAN, (windowFlags & BFWINDOW_TOOLTIP) != 0); + bf_SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_TRANSPARENT_BOOLEAN, (windowFlags & BFWINDOW_DEST_ALPHA) != 0); + bf_SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_MENU_BOOLEAN, (windowFlags & BFWINDOW_FAKEFOCUS) != 0); + bf_SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN, (windowFlags & BFWINDOW_FAKEFOCUS) == 0); + bf_SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_MODAL_BOOLEAN, (windowFlags & BFWINDOW_MODAL) != 0); + bf_SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN, (windowFlags & BFWINDOW_TOPMOST) != 0); - mSDLWindow = bf_SDL_CreateWindow(title.c_str(), x, y, width, height, sdlWindowFlags); + if (parent != NULL) + { + SDL_Window* parentWindow = ((SdlBFWindow*)parent)->mSDLWindow; + bf_SDL_SetPointerProperty(props, SDL_PROP_WINDOW_CREATE_PARENT_POINTER, parentWindow); + if ((windowFlags & BFWINDOW_TOOLTIP | BFWINDOW_FAKEFOCUS) != 0) // Tooltips and menus have relative positioning to their parent. + { + int parentX, parentY; + bf_SDL_GetWindowPosition(parentWindow, &parentX, &parentY); + x -= parentX; + y -= parentY; + } + } -#ifndef BF_PLATFORM_OPENGL_ES2 - bf_SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - bf_SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); - bf_SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + if (windowFlags) +#ifdef BF_PLATFORM_FULLSCREEN + bf_SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, true); #endif - if (!bf_SDL_GL_CreateContext(mSDLWindow)) - { - String str = StrFormat( -#ifdef BF_PLATFORM_OPENGL_ES2 - "Unable to create SDL OpenGLES context: %s" -#else - "Unable to create SDL OpenGL context: %s" -#endif - , bf_SDL_GetError()); + bf_SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, x); + bf_SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, y); + bf_SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, width); + bf_SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, height); + bf_SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, title.c_str()); + mSDLWindow = bf_SDL_CreateWindowWithProperties(props); - BF_FATAL(str.c_str()); - bf_SDL_Quit(); - exit(2); - } + bf_SDL_DestroyProperties(props); +// printf("Created %i : %s\n", bf_SDL_GetWindowID(mSDLWindow), title.c_str()); + + if (gAppIconSurface) + bf_SDL_SetWindowIcon(mSDLWindow, gAppIconSurface); + bf_SDL_StartTextInput(mSDLWindow); #ifndef BF_PLATFORM_OPENGL_ES2 - glEnable(GL_DEBUG_OUTPUT); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + int contextFlags = SDL_GL_CONTEXT_PROFILE_CORE; +#ifdef _DEBUG + contextFlags |= SDL_GL_CONTEXT_DEBUG_FLAG; #endif - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - -#ifndef BF_PLATFORM_OPENGL_ES2 - //glEnableClientState(GL_INDEX_ARRAY); + bf_SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + bf_SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); + bf_SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, contextFlags); #endif + auto sdlApp = (SdlBFApp*)gBFApp; + if(sdlApp->mGLContext == NULL) + { + sdlApp->mGLContextWindow = mSDLWindow; + sdlApp->mGLContext = bf_SDL_GL_CreateContext(mSDLWindow); + if (sdlApp->mGLContext == NULL) + { + String str = StrFormat( + #ifdef BF_PLATFORM_OPENGL_ES2 + "Unable to create SDL OpenGLES context: %s" + #else + "Unable to create SDL OpenGL context: %s" + #endif + , bf_SDL_GetError()); + + + BF_FATAL(str.c_str()); + bf_SDL_Quit(); + exit(2); + } + } + mIsMouseInside = false; + mIsMouseVisible = true; + mHasPositionInit = false; mRenderWindow = new GLRenderWindow((GLRenderDevice*)gBFApp->mRenderDevice, mSDLWindow); mRenderWindow->mWindow = this; gBFApp->mRenderDevice->AddRenderWindow(mRenderWindow); + mParent = parent; if (parent != NULL) parent->mChildren.push_back(this); } @@ -116,96 +267,133 @@ SdlBFWindow::SdlBFWindow(BFWindow* parent, const StringImpl& title, int x, int y SdlBFWindow::~SdlBFWindow() { if (mSDLWindow != NULL) - TryClose(); + Destroy(); } -bool SdlBFWindow::TryClose() +void SdlBFWindow::Destroy() { +// printf("Destroy %i\n", bf_SDL_GetWindowID(this->mSDLWindow)); + SdlBFApp* app = (SdlBFApp*)gBFApp; app->mSdlWindowMap.Remove(bf_SDL_GetWindowID(mSDLWindow)); + SDL_Window* currentContextWindow = bf_SDL_GL_GetCurrentWindow(); + + bf_SDL_StopTextInput(mSDLWindow); bf_SDL_DestroyWindow(mSDLWindow); + + // Make sure we have valid gl context in case we call any GL functions between frames + auto sdlApp = (SdlBFApp*)gBFApp; + if ((currentContextWindow == mSDLWindow) && (mSDLWindow != sdlApp->mGLContextWindow)) + { + bf_SDL_GL_MakeCurrent(sdlApp->mGLContextWindow, sdlApp->mGLContext); + } mSDLWindow = NULL; - return true; } -static int SDLConvertScanCode(int scanCode) +bool SdlBFWindow::TryClose() +{ +// printf("TryClose %i\n", bf_SDL_GetWindowID(this->mSDLWindow)); + + mLostFocusFunc(this); + if(this->mParent != NULL) + { + mGotFocusFunc(this->mParent); + } + + gBFApp->RemoveWindow(this); + return mSDLWindow == NULL; +} + +static void RefreshMouseVisibility(SdlBFWindow* window) +{ + if (window->mIsMouseVisible) + { + bf_SDL_ShowCursor(); + } + else + { + bf_SDL_HideCursor(); + } +} + +static int SDLConvertKeyCode(SDL_Keycode scanCode) { - if ((scanCode >= SDL_SCANCODE_A) && (scanCode <= SDL_SCANCODE_Z)) - return (scanCode - SDL_SCANCODE_A) + 'A'; - if ((scanCode >= SDL_SCANCODE_1) && (scanCode <= SDL_SCANCODE_9)) - return (scanCode - SDL_SCANCODE_1) + '1'; + if ((scanCode >= SDLK_A) && (scanCode <= SDLK_Z)) + return (scanCode - SDLK_A) + 'A'; + if ((scanCode >= SDLK_1) && (scanCode <= SDLK_9)) + return (scanCode - SDLK_1) + '1'; switch (scanCode) { - case SDL_SCANCODE_9: return '0'; - case SDL_SCANCODE_CANCEL: return 0x03; - case SDL_SCANCODE_AC_BACK: return 0x08; - case SDL_SCANCODE_TAB: return 0x09; - case SDL_SCANCODE_CLEAR: return 0x0C; - case SDL_SCANCODE_RETURN: return 0x0D; - case SDL_SCANCODE_LSHIFT: return 0x10; - case SDL_SCANCODE_RSHIFT: return 0x10; - case SDL_SCANCODE_LCTRL: return 0x11; - case SDL_SCANCODE_RCTRL: return 0x11; - case SDL_SCANCODE_MENU: return 0x12; - case SDL_SCANCODE_PAUSE: return 0x13; - case SDL_SCANCODE_LANG1: return 0x15; - case SDL_SCANCODE_LANG2: return 0x15; - case SDL_SCANCODE_LANG3: return 0x17; - case SDL_SCANCODE_LANG4: return 0x18; - case SDL_SCANCODE_LANG5: return 0x19; - case SDL_SCANCODE_LANG6: return 0x19; - case SDL_SCANCODE_ESCAPE: return 0x1B; - case SDL_SCANCODE_SPACE: return 0x20; - case SDL_SCANCODE_PAGEUP: return 0x21; - case SDL_SCANCODE_PAGEDOWN: return 0x22; - case SDL_SCANCODE_END: return 0x23; - case SDL_SCANCODE_HOME: return 0x24; - case SDL_SCANCODE_LEFT: return 0x25; - case SDL_SCANCODE_UP: return 0x26; - case SDL_SCANCODE_RIGHT: return 0x27; - case SDL_SCANCODE_DOWN: return 0x28; - case SDL_SCANCODE_SELECT: return 0x29; - case SDL_SCANCODE_PRINTSCREEN: return 0x2A; - case SDL_SCANCODE_EXECUTE: return 0x2B; - case SDL_SCANCODE_INSERT: return 0x2D; - case SDL_SCANCODE_DELETE: return 0x2E; - case SDL_SCANCODE_HELP: return 0x2F; - case SDL_SCANCODE_LGUI: return 0x5B; - case SDL_SCANCODE_RGUI: return 0x5C; - case SDL_SCANCODE_KP_0: return 0x60; - case SDL_SCANCODE_KP_1: return 0x61; - case SDL_SCANCODE_KP_2: return 0x62; - case SDL_SCANCODE_KP_3: return 0x63; - case SDL_SCANCODE_KP_4: return 0x64; - case SDL_SCANCODE_KP_5: return 0x65; - case SDL_SCANCODE_KP_6: return 0x66; - case SDL_SCANCODE_KP_7: return 0x67; - case SDL_SCANCODE_KP_8: return 0x68; - case SDL_SCANCODE_KP_9: return 0x69; - case SDL_SCANCODE_KP_MULTIPLY: return 0x6A; - case SDL_SCANCODE_KP_PLUS: return 0x6B; - case SDL_SCANCODE_SEPARATOR: return 0x6C; - case SDL_SCANCODE_KP_MINUS: return 0x6D; - case SDL_SCANCODE_KP_PERIOD: return 0x6E; - case SDL_SCANCODE_KP_DIVIDE: return 0x6F; - case SDL_SCANCODE_F1: return 0x70; - case SDL_SCANCODE_F2: return 0x71; - case SDL_SCANCODE_F3: return 0x72; - case SDL_SCANCODE_F4: return 0x73; - case SDL_SCANCODE_F5: return 0x74; - case SDL_SCANCODE_F6: return 0x75; - case SDL_SCANCODE_F7: return 0x76; - case SDL_SCANCODE_F8: return 0x77; - case SDL_SCANCODE_F9: return 0x78; - case SDL_SCANCODE_F10: return 0x79; - case SDL_SCANCODE_F11: return 0x7A; - case SDL_SCANCODE_F12: return 0x7B; - case SDL_SCANCODE_NUMLOCKCLEAR: return 0x90; - case SDL_SCANCODE_SCROLLLOCK: return 0x91; - case SDL_SCANCODE_GRAVE: return 0xC0; - //case SDL_SCANCODE_COMMAND: return 0xF0; + case SDLK_CANCEL: return 0x03; + case SDLK_BACKSPACE: return 0x08; + case SDLK_TAB: return 0x09; + case SDLK_CLEAR: return 0x0C; + case SDLK_RETURN: return 0x0D; + case SDLK_LSHIFT: return 0x10; + case SDLK_RSHIFT: return 0x10; + case SDLK_LCTRL: return 0x11; + case SDLK_RCTRL: return 0x11; + case SDLK_LALT: return 0x12; + case SDLK_RALT: return 0x12; + case SDLK_PAUSE: return 0x13; + case SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LANG1): return 0x15; + case SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LANG2): return 0x15; + case SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LANG3): return 0x17; + case SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LANG4): return 0x18; + case SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LANG5): return 0x19; + case SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LANG6): return 0x19; + case SDLK_ESCAPE: return 0x1B; + case SDLK_SPACE: return 0x20; + case SDLK_PAGEUP: return 0x21; + case SDLK_PAGEDOWN: return 0x22; + case SDLK_END: return 0x23; + case SDLK_HOME: return 0x24; + case SDLK_LEFT: return 0x25; + case SDLK_UP: return 0x26; + case SDLK_RIGHT: return 0x27; + case SDLK_DOWN: return 0x28; + case SDLK_SELECT: return 0x29; + case SDLK_PRINTSCREEN: return 0x2A; + case SDLK_EXECUTE: return 0x2B; + case SDLK_INSERT: return 0x2D; + case SDLK_DELETE: return 0x2E; + case SDLK_HELP: return 0x2F; + case SDLK_LGUI: return 0x5B; + case SDLK_RGUI: return 0x5C; + case SDLK_KP_0: return 0x60; + case SDLK_KP_1: return 0x61; + case SDLK_KP_2: return 0x62; + case SDLK_KP_3: return 0x63; + case SDLK_KP_4: return 0x64; + case SDLK_KP_5: return 0x65; + case SDLK_KP_6: return 0x66; + case SDLK_KP_7: return 0x67; + case SDLK_KP_8: return 0x68; + case SDLK_KP_9: return 0x69; + case SDLK_KP_MULTIPLY: return 0x6A; + case SDLK_KP_PLUS: return 0x6B; + case SDLK_SEPARATOR: return 0x6C; + case SDLK_KP_MINUS: return 0x6D; + case SDLK_KP_PERIOD: return 0x6E; + case SDLK_KP_DIVIDE: return 0x6F; + case SDLK_F1: return 0x70; + case SDLK_F2: return 0x71; + case SDLK_F3: return 0x72; + case SDLK_F4: return 0x73; + case SDLK_F5: return 0x74; + case SDLK_F6: return 0x75; + case SDLK_F7: return 0x76; + case SDLK_F8: return 0x77; + case SDLK_F9: return 0x78; + case SDLK_F10: return 0x79; + case SDLK_F11: return 0x7A; + case SDLK_F12: return 0x7B; + case SDLK_NUMLOCKCLEAR: return 0x90; + case SDLK_SCROLLLOCK: return 0x91; + case SDLK_GRAVE: return 0xC0; + //case SDLK_COMMAND: return 0xF0; } return 0; } @@ -218,6 +406,7 @@ SdlBFApp::SdlBFApp() { mRunning = false; mRenderDevice = NULL; + mSdlClipboardData = new SdlClipboardData(); Beefy::String exePath; BfpGetStrHelper(exePath, [](char* outStr, int* inOutStrSize, BfpResult* result) @@ -238,35 +427,98 @@ SdlBFApp::SdlBFApp() mInstallDir += "/"; - if (bf_SDL_CreateWindow == NULL) + mIsControlDown = false; + + if (bf_SDL_Init == NULL) { - BF_GET_SDLPROC(SDL_CreateWindow); - BF_GET_SDLPROC(SDL_GL_SetAttribute); + BF_GET_SDLPROC(SDL_Init); + BF_GET_SDLPROC(SDL_Quit); + BF_GET_SDLPROC(SDL_malloc); + BF_GET_SDLPROC(SDL_free); + BF_GET_SDLPROC(SDL_memset); + BF_GET_SDLPROC(SDL_memcpy); + + BF_GET_SDLPROC(SDL_CreateProperties); + BF_GET_SDLPROC(SDL_DestroyProperties); + BF_GET_SDLPROC(SDL_SetNumberProperty); + BF_GET_SDLPROC(SDL_SetBooleanProperty); + BF_GET_SDLPROC(SDL_SetStringProperty); + BF_GET_SDLPROC(SDL_SetPointerProperty); + + BF_GET_SDLPROC(SDL_CreateWindowWithProperties); BF_GET_SDLPROC(SDL_GetWindowID); BF_GET_SDLPROC(SDL_DestroyWindow); - BF_GET_SDLPROC(SDL_Init); + BF_GET_SDLPROC(SDL_SyncWindow); BF_GET_SDLPROC(SDL_GetWindowPosition); + BF_GET_SDLPROC(SDL_SetWindowPosition); + BF_GET_SDLPROC(SDL_GetWindowSizeInPixels); + BF_GET_SDLPROC(SDL_GetWindowSize); + BF_GET_SDLPROC(SDL_SetWindowSize); + BF_GET_SDLPROC(SDL_SetWindowMinimumSize); + BF_GET_SDLPROC(SDL_SetWindowTitle); + BF_GET_SDLPROC(SDL_SetWindowIcon); + BF_GET_SDLPROC(SDL_GetMouseFocus); + + BF_GET_SDLPROC(SDL_ShowCursor); + BF_GET_SDLPROC(SDL_HideCursor); + BF_GET_SDLPROC(SDL_GetClipboardText); BF_GET_SDLPROC(SDL_SetClipboardText); - BF_GET_SDLPROC(SDL_GL_GetProcAddress); - BF_GET_SDLPROC(SDL_GetWindowSize); - BF_GET_SDLPROC(SDL_GL_SwapWindow); - BF_GET_SDLPROC(SDL_free); - BF_GET_SDLPROC(SDL_SetWindowPosition); + BF_GET_SDLPROC(SDL_GetClipboardData); + BF_GET_SDLPROC(SDL_SetClipboardData); + BF_GET_SDLPROC(SDL_StartTextInput); + BF_GET_SDLPROC(SDL_StopTextInput); + BF_GET_SDLPROC(SDL_PollEvent); + BF_GET_SDLPROC(SDL_PushEvent); + BF_GET_SDLPROC(SDL_PumpEvents); + BF_GET_SDLPROC(SDL_PeepEvents); + BF_GET_SDLPROC(SDL_SetError); BF_GET_SDLPROC(SDL_GetError); + + BF_GET_SDLPROC(SDL_SetHint); + + BF_GET_SDLPROC(SDL_GetPrimaryDisplay); + BF_GET_SDLPROC(SDL_GetDisplays); + BF_GET_SDLPROC(SDL_GetDisplayBounds); + BF_GET_SDLPROC(SDL_GetDesktopDisplayMode); + BF_GET_SDLPROC(SDL_HasRectIntersection); + BF_GET_SDLPROC(SDL_GetDisplayForWindow); + BF_GET_SDLPROC(SDL_GetCurrentDisplayMode); + + BF_GET_SDLPROC(SDL_CreateSurfaceFrom); + BF_GET_SDLPROC(SDL_GL_CreateContext); - BF_GET_SDLPROC(SDL_Quit); + BF_GET_SDLPROC(SDL_GL_GetCurrentContext); + BF_GET_SDLPROC(SDL_GL_GetCurrentWindow); + BF_GET_SDLPROC(SDL_GL_MakeCurrent); + BF_GET_SDLPROC(SDL_GL_SetAttribute); + BF_GET_SDLPROC(SDL_GL_GetProcAddress); + BF_GET_SDLPROC(SDL_GL_SwapWindow); + + BF_GET_SDLPROC(SDL_GetDefaultCursor); + BF_GET_SDLPROC(SDL_CreateSystemCursor); + BF_GET_SDLPROC(SDL_SetCursor); + BF_GET_SDLPROC(SDL_GetWindowFlags); + BF_GET_SDLPROC(SDL_HideWindow); + BF_GET_SDLPROC(SDL_RestoreWindow); + BF_GET_SDLPROC(SDL_MinimizeWindow); + BF_GET_SDLPROC(SDL_MaximizeWindow); + BF_GET_SDLPROC(SDL_ShowWindow); + BF_GET_SDLPROC(SDL_RaiseWindow); } mDataDir = mInstallDir; - if (bf_SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < 0) + if (bf_SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD) < 0) BF_FATAL(StrFormat("Unable to initialize SDL: %s", bf_SDL_GetError()).c_str()); + + bf_SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); } SdlBFApp::~SdlBFApp() { + delete mSdlClipboardData; } SdlBFWindow* SdlBFApp::GetSdlWindowFromId(uint32 id) @@ -276,85 +528,177 @@ SdlBFWindow* SdlBFApp::GetSdlWindowFromId(uint32 id) return window; } -void SdlBFApp::Init() +void SdlBFApp::ProcessSDLEvents() { - mRunning = true; - mInMsgProc = false; - - mRenderDevice = new GLRenderDevice(); - mRenderDevice->Init(this); -} - -void SdlBFApp::Run() -{ - while (mRunning) + SDL_Event sdlEvent; + while (bf_SDL_PollEvent(&sdlEvent)) { - SDL_Event sdlEvent; - while (true) + switch (sdlEvent.type) { - { - //Beefy::DebugTimeGuard suspendTimeGuard(30, "BFApp::Run1"); - if (!bf_SDL_PollEvent(&sdlEvent)) - break; - } - - //Beefy::DebugTimeGuard suspendTimeGuard(30, "BFApp::Run2"); - - switch (sdlEvent.type) + case SDL_EVENT_WINDOW_CLOSE_REQUESTED: { - case SDL_QUIT: - //gBFApp->RemoveWindow(sdlEvent.window); - Shutdown(); - break; - case SDL_MOUSEBUTTONUP: - { - SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.button.windowID); - if (sdlBFWindow != NULL) - sdlBFWindow->mMouseUpFunc(sdlBFWindow, sdlEvent.button.x, sdlEvent.button.y, sdlEvent.button.button); - } - break; - case SDL_MOUSEBUTTONDOWN: - { - SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.button.windowID); - if (sdlBFWindow != NULL) - sdlBFWindow->mMouseDownFunc(sdlBFWindow, sdlEvent.button.x, sdlEvent.button.y, sdlEvent.button.button, 1); - } - break; - case SDL_MOUSEMOTION: + SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.window.windowID); + if(sdlBFWindow != NULL) + if (sdlBFWindow->mCloseQueryFunc(sdlBFWindow) != 0) + gBFApp->RemoveWindow(sdlBFWindow); + } + break; + case SDL_EVENT_WINDOW_FOCUS_GAINED: + { + SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.window.windowID); + if(sdlBFWindow != NULL) + sdlBFWindow->mGotFocusFunc(sdlBFWindow); + } + break; + case SDL_EVENT_WINDOW_FOCUS_LOST: + { + SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.window.windowID); + if(sdlBFWindow != NULL) { - SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.button.windowID); - if (sdlBFWindow != NULL) - sdlBFWindow->mMouseMoveFunc(sdlBFWindow, sdlEvent.button.x, sdlEvent.button.y); + sdlBFWindow->mLostFocusFunc(sdlBFWindow); + mIsControlDown = false; } - break; - case SDL_KEYDOWN: + } + break; + case SDL_EVENT_MOUSE_BUTTON_UP: + { + SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.button.windowID); + if (sdlBFWindow != NULL) + sdlBFWindow->mMouseUpFunc(sdlBFWindow, sdlEvent.button.x, sdlEvent.button.y, bfMouseBtnOf[sdlEvent.button.button]); + } + break; + case SDL_EVENT_MOUSE_BUTTON_DOWN: + { + SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.button.windowID); + if (sdlBFWindow != NULL) + sdlBFWindow->mMouseDownFunc(sdlBFWindow, sdlEvent.button.x, sdlEvent.button.y, bfMouseBtnOf[sdlEvent.button.button], sdlEvent.button.clicks); + } + break; + case SDL_EVENT_MOUSE_MOTION: + { + SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.button.windowID); + if (sdlBFWindow != NULL) + sdlBFWindow->mMouseMoveFunc(sdlBFWindow, sdlEvent.button.x, sdlEvent.button.y); + } + break; + case SDL_EVENT_MOUSE_WHEEL: + { + uint ucNumLines = 3; // Default + SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.wheel.windowID); + if(sdlBFWindow != NULL) + sdlBFWindow->mMouseWheelFunc(sdlBFWindow, sdlEvent.wheel.mouse_x, sdlEvent.wheel.mouse_y, sdlEvent.wheel.x, sdlEvent.wheel.y * (float)ucNumLines); + } + break; + case SDL_EVENT_WINDOW_MOUSE_ENTER: + { + SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.window.windowID); + if(sdlBFWindow != NULL) + RefreshMouseVisibility(sdlBFWindow); + } + break; + case SDL_EVENT_WINDOW_DESTROYED: + { + SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(bf_SDL_GetWindowID(bf_SDL_GetMouseFocus())); + if(sdlBFWindow != NULL) + RefreshMouseVisibility(sdlBFWindow); + } + break; + case SDL_EVENT_KEY_DOWN: + { + SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.key.windowID); + if (sdlBFWindow != NULL) { - SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.key.windowID); - if (sdlBFWindow != NULL) + sdlBFWindow->mKeyDownFunc(sdlBFWindow, SDLConvertKeyCode(sdlEvent.key.key), sdlEvent.key.repeat); + switch (sdlEvent.key.key) // These keys are not handled by SDL_TEXTINPUT { - sdlBFWindow->mKeyDownFunc(sdlBFWindow, SDLConvertScanCode(sdlEvent.key.keysym.scancode), sdlEvent.key.repeat); + case SDLK_RETURN: + sdlBFWindow->mKeyCharFunc(sdlBFWindow, '\n'); + break; + case SDLK_BACKSPACE: + sdlBFWindow->mKeyCharFunc(sdlBFWindow, mIsControlDown ? '\x7F' : '\b'); + break; + case SDLK_TAB: + sdlBFWindow->mKeyCharFunc(sdlBFWindow, '\t'); + break; + case SDLK_LCTRL: + mIsControlDown = true; + break; + + default:; } } - break; - case SDL_TEXTINPUT: + } + break; + case SDL_EVENT_TEXT_INPUT: + { + SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.text.windowID); + if (sdlBFWindow != NULL) { - SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.key.windowID); - if (sdlBFWindow != NULL) - { - sdlBFWindow->mKeyCharFunc(sdlBFWindow, *(wchar_t*)sdlEvent.text.text); - } + const auto wideString = Beefy::UTF8Decode(sdlEvent.text.text); + for (int i = 0; i < wideString.length(); i++) + sdlBFWindow->mKeyCharFunc(sdlBFWindow, wideString[i]); } - break; - case SDL_KEYUP: + } + break; + case SDL_EVENT_KEY_UP: + { + SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.key.windowID); + if (sdlBFWindow != NULL) + sdlBFWindow->mKeyUpFunc(sdlBFWindow, SDLConvertKeyCode(sdlEvent.key.key)); + + if (sdlEvent.key.key == SDLK_LCTRL) + mIsControlDown = false; + } + break; + case SDL_EVENT_WINDOW_MOVED: + case SDL_EVENT_WINDOW_RESIZED: + { + SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.window.windowID); + if (sdlBFWindow != NULL) { - SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.key.windowID); - if (sdlBFWindow != NULL) - sdlBFWindow->mKeyUpFunc(sdlBFWindow, SDLConvertScanCode(sdlEvent.key.keysym.scancode)); + sdlBFWindow->mMovedFunc(sdlBFWindow); + + // if (sdlBFWindow->mHasPositionInit) + // { + // if (sdlEvent.type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) + // sdlBFWindow->mRenderWindow->Resized(); + // + // + // } + // else + // { + // sdlBFWindow->mHasPositionInit = true; + // } } - break; } + break; + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: + { + SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.window.windowID); + if (sdlBFWindow != NULL) + sdlBFWindow->mRenderWindow->Resized(); + } + break; } + } +} + +void SdlBFApp::Init() +{ + mRunning = true; + mInMsgProc = false; +// bf_SDL_SetHint(SDL_HINT_EVENT_LOGGING, "1"); + + mRenderDevice = new GLRenderDevice(); + mRenderDevice->Init(this); +} + +void SdlBFApp::Run() +{ + while (mRunning) + { + ProcessSDLEvents(); Process(); } } @@ -366,12 +710,6 @@ void SdlBFApp::Draw() { //Beefy::DebugTimeGuard suspendTimeGuard(30, "SdlBFApp::Draw"); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glClearColor(1.0f, 0.0f, 1.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - gPixelsDrawn = 0; gBFDrawBatchCount = 0; @@ -396,36 +734,99 @@ void SdlBFWindow::GetPosition(int* x, int* y, int* width, int* height, int* clie { bf_SDL_GetWindowPosition(mSDLWindow, x, y); bf_SDL_GetWindowSize(mSDLWindow, width, height); - *clientWidth = *width; - *clientHeight = *height; + + if (clientX) + *clientX = *x; + if (clientY) + *clientY = *y; + bf_SDL_GetWindowSizeInPixels(mSDLWindow, clientWidth, clientHeight); } void SdlBFApp::PhysSetCursor() { - + static SDL_Cursor* cursors[] = + { + bf_SDL_GetDefaultCursor(), + bf_SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_POINTER), + bf_SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_MOVE), + bf_SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_TEXT), + + bf_SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NOT_ALLOWED), + bf_SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_MOVE), + bf_SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NESW_RESIZE), + bf_SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NS_RESIZE), + bf_SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NWSE_RESIZE), + bf_SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_EW_RESIZE), + bf_SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT), + NULL + }; + + bf_SDL_SetCursor(cursors[mCursor]); } void SdlBFWindow::SetClientPosition(int x, int y) { bf_SDL_SetWindowPosition(mSDLWindow, x, y); +} +void SdlBFWindow::Resize(int x, int y, int width, int height, ShowKind showKind) +{ + bf_SDL_SetWindowPosition(mSDLWindow, x, y); + bf_SDL_SyncWindow(mSDLWindow); + bf_SDL_SetWindowSize(mSDLWindow, width, height); + bf_SDL_SyncWindow(mSDLWindow); + Show(showKind); + bf_SDL_SyncWindow(mSDLWindow); + + if (mRenderWindow != NULL) + mRenderWindow->Resized(); if (mMovedFunc != NULL) mMovedFunc(this); } +void SdlBFWindow::GetPlacement(int* normX, int* normY, int* normWidth, int* normHeight, int* showKind) +{ + bf_SDL_GetWindowPosition(mSDLWindow, normX, normY); + bf_SDL_GetWindowSize(mSDLWindow, normWidth, normHeight); + SDL_WindowFlags flags = bf_SDL_GetWindowFlags(mSDLWindow); + if ((flags & SDL_WINDOW_HIDDEN) == SDL_WINDOW_HIDDEN) + *showKind = ShowKind_Hide; + else if ((flags & SDL_WINDOW_MAXIMIZED) == SDL_WINDOW_MAXIMIZED) + *showKind = ShowKind_ShowMaximized; + else if ((flags & SDL_WINDOW_MINIMIZED) == SDL_WINDOW_MINIMIZED) + *showKind = ShowKind_ShowMinimized; + else + *showKind = ShowKind_ShowNormal; +} + void SdlBFWindow::SetAlpha(float alpha, uint32 destAlphaSrcMask, bool isMouseVisible) { // Not supported } -uint32 SdlBFApp::GetClipboardFormat(const StringImpl& format) +const char* SdlBFApp::GetClipboardFormat(const StringImpl& format) { - return /*CF_TEXT*/1; + if (format == "text" || format == "atext") + { + return "text/plain;charset=utf-8"; + } + if (format == "bf_text") + { + return "text/vnd.beeflang.bf-text"; + } + if (format == "code/file-list") + { + return "text/vnd.beeflang.file-list"; + } + return format.c_str(); } void* SdlBFApp::GetClipboardData(const StringImpl& format, int* size) { - return bf_SDL_GetClipboardText(); + size_t outSize; + void* data = bf_SDL_GetClipboardData(GetClipboardFormat(format), &outSize); + *size = outSize; + return data; } void SdlBFApp::ReleaseClipboardData(void* ptr) @@ -433,9 +834,39 @@ void SdlBFApp::ReleaseClipboardData(void* ptr) bf_SDL_free(ptr); } +const void* SDLClipboardCallback(void* userData, const char* mimeType, size_t* outSize) +{ + SdlClipboardData* clipboard = *(SdlClipboardData**)userData; + + void* data; + if (clipboard->TryGetValue(StringImpl::MakeRef(mimeType), &data)) + { + *outSize = strlen((const char*) data); + } + return data; +} + void SdlBFApp::SetClipboardData(const StringImpl& format, const void* ptr, int size, bool resetClipboard) { - bf_SDL_SetClipboardText((const char*)ptr); + void* buffer = bf_SDL_malloc(size); + if (buffer == NULL) + { + bf_SDL_SetError("Out of memory for clipboard"); + } + else + { + StringImpl mime = StringImpl::MakeRef(GetClipboardFormat(format)); + + void* previous; + if (mSdlClipboardData->TryGetValue(mime, &previous)) + { + bf_SDL_free(previous); + } + bf_SDL_memcpy(buffer, ptr, size); + (*mSdlClipboardData)[mime] = buffer; + + bf_SDL_SetClipboardData(SDLClipboardCallback, NULL, &mSdlClipboardData, mimeTypes, 3); + } } BFMenu* SdlBFWindow::AddMenuItem(BFMenu* parent, int insertIdx, const char* text, const char* hotKey, BFSysBitmap* bitmap, bool enabled, int checkState, bool radioCheck) @@ -458,6 +889,68 @@ void SdlBFWindow::ModalsRemoved() //::SetFocus(mHWnd); } +void SdlBFWindow::Show(ShowKind showKind) +{ + switch (showKind) + { + case BFWindow::ShowKind_Hide: + bf_SDL_HideWindow(mSDLWindow); + break; + case BFWindow::ShowKind_Normal: + bf_SDL_RestoreWindow(mSDLWindow); + break; + case BFWindow::ShowKind_Minimized: + bf_SDL_MinimizeWindow(mSDLWindow); + break; + case BFWindow::ShowKind_Maximized: + bf_SDL_MaximizeWindow(mSDLWindow); + break; + case BFWindow::ShowKind_Show: + bf_SDL_ShowWindow(mSDLWindow); + break; + case BFWindow::ShowKind_ShowNormal: + bf_SDL_RestoreWindow(mSDLWindow); + bf_SDL_ShowWindow(mSDLWindow); + break; + case BFWindow::ShowKind_ShowMinimized: + bf_SDL_MinimizeWindow(mSDLWindow); + bf_SDL_ShowWindow(mSDLWindow); + break; + case BFWindow::ShowKind_ShowMaximized: + bf_SDL_MaximizeWindow(mSDLWindow); + bf_SDL_ShowWindow(mSDLWindow); + break; + } +} + +void SdlBFWindow::SetForeground() +{ + bf_SDL_RaiseWindow(mSDLWindow); +} + +void SdlBFWindow::SetTitle(const char* title) +{ + bf_SDL_SetWindowTitle(mSDLWindow, title); +} + +void SdlBFWindow::SetMinimumSize(int minWidth, int minHeight, bool clientSized) +{ + bf_SDL_SetWindowMinimumSize(mSDLWindow, minWidth, minHeight); +} + +void SdlBFWindow::SetMouseVisible(bool isMouseVisible) +{ + mIsMouseVisible = isMouseVisible; + if (isMouseVisible) + { + bf_SDL_ShowCursor(); + } + else + { + bf_SDL_HideCursor(); + } +} + DrawLayer* SdlBFApp::CreateDrawLayer(BFWindow* window) { GLDrawLayer* drawLayer = new GLDrawLayer(); @@ -473,14 +966,98 @@ DrawLayer* SdlBFApp::CreateDrawLayer(BFWindow* window) void SdlBFApp::GetDesktopResolution(int& width, int& height) { - width = 1024; - height = 768; + SDL_DisplayID display = bf_SDL_GetPrimaryDisplay(); + if (display != 0) + { + SDL_DisplayMode* displayMode = bf_SDL_GetDesktopDisplayMode(display); + if (displayMode != NULL) { + width = displayMode->w; + height = displayMode->h; + } + } +} + +static bool InflateRectToMonitor(SDL_DisplayID monitor, AdjustedMonRect* inflatedRect) +{ + SDL_Rect bounds; + if(!bf_SDL_GetDisplayBounds(monitor, &bounds)) + return false; + + inflatedRect->mMonCount++; + if (inflatedRect->mMonCount == 1) + { + inflatedRect->mX = bounds.x; + inflatedRect->mY = bounds.y; + inflatedRect->mWidth = bounds.w; + inflatedRect->mHeight = bounds.h; + } + else + { + int minLeft = BF_MIN(inflatedRect->mX, bounds.x); + int minTop = BF_MIN(inflatedRect->mY, bounds.y); + int maxRight = BF_MAX(inflatedRect->mX + inflatedRect->mWidth, bounds.x + bounds.w); + int maxBottom = BF_MAX(inflatedRect->mY + inflatedRect->mHeight, bounds.y + bounds.h); + + inflatedRect->mX = minLeft; + inflatedRect->mY = minTop; + inflatedRect->mWidth = maxRight - minLeft; + inflatedRect->mHeight = maxBottom - minTop; + } + + return true; } void SdlBFApp::GetWorkspaceRect(int& x, int& y, int& width, int& height) { - x = 0; - y = 0; - width = 1024; - height = 768; + AdjustedMonRect inflateRect = { 0 }; + + int displayCount; + SDL_DisplayID* displays = bf_SDL_GetDisplays(&displayCount); + if (!displays) + return; + + for (int i = 0; i < displayCount; i++) + { + InflateRectToMonitor(displays[i], &inflateRect); + } + bf_SDL_free(displays); + + x = inflateRect.mX; + y = inflateRect.mY; + width = inflateRect.mWidth; + height = inflateRect.mHeight; +} + +void SdlBFApp::GetWorkspaceRectFrom(int fromX, int fromY, int fromWidth, int fromHeight, int& outX, int& outY, int& outWidth, int& outHeight) +{ + SDL_Rect bounds; + SDL_Rect clip = {fromX, fromY, fromWidth == 0 ? 1 : fromWidth, fromHeight == 0 ? 1 : fromHeight}; + AdjustedMonRect inflateRect = { 0 }; + + int displayCount; + SDL_DisplayID* displays = bf_SDL_GetDisplays(&displayCount); + if (displays == NULL) + return; + + for (int i = 0; i < displayCount; i++) + { + bf_SDL_GetDisplayBounds(displays[i], &bounds); + if (bf_SDL_HasRectIntersection(&clip, &bounds)) + { + InflateRectToMonitor(displays[i], &inflateRect); + } + } + bf_SDL_free(displays); + + if (inflateRect.mMonCount == 0) + { + GetWorkspaceRect(outX, outY, outWidth, outHeight); + return; + } + + outX = inflateRect.mX; + outY = inflateRect.mY; + outWidth = inflateRect.mWidth; + outHeight = inflateRect.mHeight; } + diff --git a/BeefySysLib/platform/sdl/SdlBFApp.h b/BeefySysLib/platform/sdl/SdlBFApp.h index f22f45fb8..106856d90 100644 --- a/BeefySysLib/platform/sdl/SdlBFApp.h +++ b/BeefySysLib/platform/sdl/SdlBFApp.h @@ -2,6 +2,7 @@ #include "BFApp.h" #include "BFWindow.h" +#include #include #include "util/Dictionary.h" @@ -17,19 +18,21 @@ class SdlBFWindow : public BFWindow SDL_Window* mSDLWindow; bool mIsMouseInside; int mModalCount; + bool mHasPositionInit; + bool mIsMouseVisible; public: SdlBFWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags); ~SdlBFWindow(); - virtual void* GetUnderlying() {return mSDLWindow; }; - virtual void Destroy() { } + virtual void* GetUnderlying() { return mSDLWindow; }; + virtual void Destroy() override; - virtual void SetTitle(const char* title) override {} - virtual void SetMinimumSize(int minWidth, int minHeight, bool clientSized) override {} - virtual void GetPlacement(int* normX, int* normY, int* normWidth, int* normHeight, int* showKind) override { } - virtual void Resize(int x, int y, int width, int height, ShowKind showKind) override {} - virtual void SetMouseVisible(bool isMouseVisible) override {} + virtual void SetTitle(const char* title) override; + virtual void SetMinimumSize(int minWidth, int minHeight, bool clientSized) override; + virtual void GetPlacement(int* normX, int* normY, int* normWidth, int* normHeight, int* showKind) override; + virtual void Resize(int x, int y, int width, int height, ShowKind showKind) override; + virtual void SetMouseVisible(bool isMouseVisible) override; virtual bool TryClose() override; virtual void GetPosition(int* x, int* y, int* width, int* height, int* clientX, int* clientY, int* clientWidth, int* clientHeight) override; @@ -43,24 +46,30 @@ class SdlBFWindow : public BFWindow virtual void ModalsRemoved() override; - virtual void Show(ShowKind showKind) {} - virtual void SetForeground() override {}; + virtual void Show(ShowKind showKind) override; + virtual void SetForeground() override; }; typedef Dictionary SdlWindowMap; +typedef Dictionary SdlClipboardData; class SdlBFApp : public BFApp { public: bool mInMsgProc; + bool mIsControlDown; SdlWindowMap mSdlWindowMap; + SdlClipboardData* mSdlClipboardData; + SDL_GLContext mGLContext; + SDL_Window* mGLContextWindow; protected: virtual void Draw() override; virtual void PhysSetCursor() override; - uint32 GetClipboardFormat(const StringImpl& format); + const char* GetClipboardFormat(const StringImpl& format); SdlBFWindow* GetSdlWindowFromId(uint32 id); + void ProcessSDLEvents(); public: SdlBFApp(); @@ -79,6 +88,7 @@ class SdlBFApp : public BFApp virtual BFSysBitmap* LoadSysBitmap(const wchar_t* fileName) override; virtual void GetDesktopResolution(int& width, int& height) override; virtual void GetWorkspaceRect(int& x, int& y, int& width, int& height) override; + virtual void GetWorkspaceRectFrom(int fromX, int fromY, int fromWidth, int fromHeight, int& outX, int& outY, int& outWidth, int& outHeight) override; }; NS_BF_END; \ No newline at end of file diff --git a/IDE/BeefProj.toml b/IDE/BeefProj.toml index 3ae2269e3..f161cac00 100644 --- a/IDE/BeefProj.toml +++ b/IDE/BeefProj.toml @@ -29,6 +29,16 @@ DebugWorkingDirectory = "$(ProjectDir)\\.." EnvironmentVars = ["_NO_DEBUG_HEAP=1"] PreprocessorMacros = ["DEBUG,HASGIT"] +[Configs.Debug.Linux64] +TargetDirectory = "$(ProjectDir)/dist" +TargetName = "BeefIDE_d" +OtherLinkFlags = "$(LinkFlags) libIDEHelper_d.a libBeefySysLib_d.a libhunspell.so $(Var IDEHelperLibs)" +PreBuildCmds = ["ReadFile(\"$(WorkspaceDir)/dist/IDEHelper_libs_d.txt\", \"IDEHelperLibs\")"] +DebugCommandArguments = "-proddir=\"$(ProjectDir)\\..\\BeefBuild\"" +DebugWorkingDirectory = "$(ProjectDir)\\.." +EnvironmentVars = ["_NO_DEBUG_HEAP=1"] +PreprocessorMacros = ["DEBUG,HASGIT"] + [Configs.Release.Win32] TargetName = "" OtherLinkFlags = "" @@ -42,6 +52,16 @@ DebugWorkingDirectory = "$(ProjectDir)\\dist" EnvironmentVars = ["z_NO_DEBUG_HEAP=1"] PreprocessorMacros = ["RELEASE,HASGIT"] +[Configs.Release.Linux64] +TargetDirectory = "$(ProjectDir)/dist" +TargetName = "BeefIDE" +OtherLinkFlags = "libBeefRT.a libIDEHelper.a libBeefySysLib.a libhunspell.so $(Var IDEHelperLibs)" +PreBuildCmds = ["ReadFile(\"$(WorkspaceDir)/dist/IDEHelper_libs_d.txt\", \"IDEHelperLibs\")"] +DebugCommandArguments = "-proddir=\"$(ProjectDir)\\..\\BeefBuild\"" +DebugWorkingDirectory = "$(ProjectDir)\\dist" +EnvironmentVars = ["z_NO_DEBUG_HEAP=1"] +PreprocessorMacros = ["RELEASE,HASGIT"] + [Configs.Debug2.Win32] TargetName = "" OtherLinkFlags = "" diff --git a/IDE/BeefSpace.toml b/IDE/BeefSpace.toml index ee0fb2195..5335932f5 100644 --- a/IDE/BeefSpace.toml +++ b/IDE/BeefSpace.toml @@ -15,6 +15,9 @@ ConfigSelections = {IDEHelper = {Enabled = false}} [Configs.Debug.Win64] EnableSideStack = true +[Configs.Debug.Linux64] +EnableSideStack = true + [Configs.Release.Win32] BfOptimizationLevel = "OgPlus" EmitDebugInfo = "No" @@ -25,6 +28,10 @@ ConfigSelections = {IDEHelper = {Enabled = false}} BfOptimizationLevel = "O3" AllocStackTraceDepth = 0 +[Configs.Release.Linux64] +BfOptimizationLevel = "O3" +AllocStackTraceDepth = 0 + [Configs.Debug-IDE.Win32] EmitDebugInfo = "No" EmitDynamicCastCheck = false @@ -43,6 +50,15 @@ EmitObjectAccessCheck = false EnableRealtimeLeakCheck = false ConfigSelections = {IDE = {Config = "Debug"}, Beefy2D = {Config = "Debug"}, IDEHelper = {Config = "Debug"}, Debugger64 = {Config = "Debug"}, BeefySysLib = {Config = "Debug"}} +[Configs.Debug-IDE.Linux64] +BfOptimizationLevel = "O0" +EmitDebugInfo = "No" +EmitDynamicCastCheck = false +EnableObjectDebugFlags = false +EmitObjectAccessCheck = false +EnableRealtimeLeakCheck = false +ConfigSelections = {IDE = {Config = "Debug"}, Beefy2D = {Config = "Debug"}, IDEHelper = {Config = "Debug"}, Debugger64 = {Config = "Debug"}, BeefySysLib = {Config = "Debug"}} + [Configs.Debug2.Win32] EmitDebugInfo = "No" EmitDynamicCastCheck = false @@ -56,6 +72,10 @@ ConfigSelections = {Beefy2D = {Config = "Debug"}, IDEHelper = {Config = "Debug"} PreprocessorMacros = ["NEWFONT"] ConfigSelections = {Beefy2D = {Config = "Debug"}, IDEHelper = {Enabled = false, Config = "Debug"}, Debugger64 = {Enabled = false, Config = "Debug"}, BeefySysLib = {Enabled = false, Config = "Debug"}} +[Configs.Debug2.Linux64] +PreprocessorMacros = ["NEWFONT"] +ConfigSelections = {Beefy2D = {Config = "Debug"}, IDEHelper = {Enabled = false, Config = "Debug"}, Debugger64 = {Enabled = false, Config = "Debug"}, BeefySysLib = {Enabled = false, Config = "Debug"}} + [Configs.Paranoid.Win32] EmitDynamicCastCheck = false EnableObjectDebugFlags = false @@ -73,6 +93,15 @@ EnableSideStack = false COptimizationLevel = "O2" ConfigSelections = {IDEHelper = {Config = "Debug"}, Debugger64 = {Config = "Debug"}, BeefySysLib = {Config = "Debug"}} +[Configs.Paranoid.Linux64] +EmitDynamicCastCheck = false +EnableObjectDebugFlags = false +EmitObjectAccessCheck = false +EnableRealtimeLeakCheck = false +EnableSideStack = false +COptimizationLevel = "O2" +ConfigSelections = {IDEHelper = {Config = "Debug"}, Debugger64 = {Config = "Debug"}, BeefySysLib = {Config = "Debug"}} + [Configs.Test.Win32] EmitDynamicCastCheck = false EnableObjectDebugFlags = false @@ -87,6 +116,13 @@ EmitObjectAccessCheck = false EnableRealtimeLeakCheck = false COptimizationLevel = "O2" +[Configs.Test.Linux64] +EmitDynamicCastCheck = false +EnableObjectDebugFlags = false +EmitObjectAccessCheck = false +EnableRealtimeLeakCheck = false +COptimizationLevel = "O2" + [Configs.Debug3.Win32] EmitDebugInfo = "No" EmitDynamicCastCheck = false @@ -100,6 +136,10 @@ AllocStackTraceDepth = 0 BfOptimizationLevel = "O0" ConfigSelections = {Beefy2D = {Config = "Debug"}, IDEHelper = {Config = "Debug"}, Debugger64 = {Config = "Debug"}, BeefySysLib = {Config = "Debug"}} +[Configs.Debug3.Linux64] +BfOptimizationLevel = "O0" +ConfigSelections = {Beefy2D = {Config = "Debug"}, IDEHelper = {Config = "Debug"}, Debugger64 = {Config = "Debug"}, BeefySysLib = {Config = "Debug"}} + [Configs.Debug_NoDeps.Win32] InitLocalVariables = true EmitObjectAccessCheck = false @@ -110,3 +150,7 @@ ConfigSelections = {IDEHelper = {Enabled = false, Config = "Debug"}, IDE = {Conf [Configs.Debug_NoDeps.Win64] EnableSideStack = true ConfigSelections = {IDE = {Config = "Debug"}, Beefy2D = {Config = "Debug"}, IDEHelper = {Enabled = false, Config = "Debug"}, Debugger64 = {Enabled = false, Config = "Debug"}, BeefySysLib = {Enabled = false, Config = "Debug"}} + +[Configs.Debug_NoDeps.Linux64] +EnableSideStack = true +ConfigSelections = {IDE = {Config = "Debug"}, Beefy2D = {Config = "Debug"}, IDEHelper = {Enabled = false, Config = "Debug"}, Debugger64 = {Enabled = false, Config = "Debug"}, BeefySysLib = {Enabled = false, Config = "Debug"}} diff --git a/IDE/Resources/BeefIDE.desktop b/IDE/Resources/BeefIDE.desktop new file mode 100644 index 000000000..5f15084fd --- /dev/null +++ b/IDE/Resources/BeefIDE.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Type=Application +Exec=beefide +Path=/opt/BeefLang/bin +Terminal=false + +Name=Beef IDE +Comment=IDE for the Beef programming language +Version=0.43.6 +Categories=Application;Development;IDE; +Icon=beeflang diff --git a/IDE/Resources/beeflang.png b/IDE/Resources/beeflang.png new file mode 100644 index 000000000..585bd4d16 Binary files /dev/null and b/IDE/Resources/beeflang.png differ diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index ab46f5493..001223c8f 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -121,6 +121,14 @@ namespace IDE public static String sRTVersionStr = "042"; public const String cVersion = "0.43.6"; +#if BF_PLATFORM_LINUX + public const uint8[?] cAppIcon = [IgnoreErrors]{ Compiler.ReadBinary("Resources/beeflang.png") }; + + [CallingConvention(.Stdcall), CLink] + static extern void BFApp_RegisterAppIcon(uint8* imageData, int size); +#endif + + #if BF_PLATFORM_WINDOWS public static readonly String sPlatform64Name = "Win64"; public static readonly String sPlatform32Name = "Win32"; @@ -6063,7 +6071,13 @@ namespace IDE { scope AutoBeefPerf("IDEApp.CreateMenu"); - SysMenu root = mMainWindow.mSysMenu; + SysMenu root; +#if BF_PLATFORM_WINDOWS + root = mMainWindow.mSysMenu; +#else + root = mMainFrame.mMenuBar.mSysMenuRoot; + defer mMainFrame.RehupSize(); +#endif String keyStr = scope String(); @@ -6147,11 +6161,18 @@ namespace IDE void AddLineEndingKind(String name, LineEndingKind lineEndingKind) { + bool allowLast; +#if !BF_PLATFORM_WINDOWS + allowLast = true; +#else + allowLast = false; +#endif + lineEndingMenu.AddMenuItem(name, null, new (menu) => { var sysMenu = (SysMenu)menu; - var sourceViewPanel = GetActiveSourceViewPanel(); + var sourceViewPanel = GetActiveSourceViewPanel(allowLast); if (sourceViewPanel != null) { if (sourceViewPanel.mEditData.mLineEndingKind != lineEndingKind) @@ -6166,7 +6187,7 @@ namespace IDE { var sysMenu = (SysMenu)menu; - var sourceViewPanel = GetActiveSourceViewPanel(); + var sourceViewPanel = GetActiveSourceViewPanel(allowLast); if (sourceViewPanel != null) { sysMenu.Modify(null, null, null, true, (sourceViewPanel.mEditData.mLineEndingKind == lineEndingKind) ? 1 : 0, true); @@ -12895,6 +12916,11 @@ namespace IDE mGitManager.Init(); +#if BF_PLATFORM_LINUX + let icon = (Span)cAppIcon; + BFApp_RegisterAppIcon(icon.Ptr, icon.Length); +#endif + //Yoop(); /*for (int i = 0; i < 100*1024*1024; i++) @@ -12934,7 +12960,8 @@ namespace IDE #endif } - Font.AddFontFailEntry("Segoe UI", scope String()..AppendF("{}fonts/NotoSans-Regular.ttf", mInstallDir)); + Font.AddFontFailEntry("Segoe UI", scope $"Noto Sans\0{mInstallDir}fonts/NotoSans-Regular.ttf"); + Font.AddFontFailEntry("Segoe UI Bold", scope $"Noto Sans Bold\0{mInstallDir}fonts/NotoSans-Bold.ttf"); DarkTheme aTheme = new DarkTheme(); mSettings.mUISettings.Apply(); // Apply again to set actual theme @@ -13746,7 +13773,9 @@ namespace IDE DeleteAndNullify!(mBfBuildSystem); /// +#if BF_PLATFORM_WINDOWS mDebugger.FullReportMemory(); +#endif var workspaceBuildDir = scope String(); GetWorkspaceBuildDir(workspaceBuildDir); diff --git a/IDE/src/Settings.bf b/IDE/src/Settings.bf index e1a9cc5be..ef37a5823 100644 --- a/IDE/src/Settings.bf +++ b/IDE/src/Settings.bf @@ -532,7 +532,14 @@ namespace IDE mColors.Deserialize(sd); } - String imgCreatePath = scope String(gApp.mInstallDir, "images/ImgCreate.exe"); + const String EXECUTABLE_PATH = +#if BF_PLATFORM_WINDOWS + "images/ImgCreate.exe"; +#else + "images/ImgCreate"; +#endif + + String imgCreatePath = scope String(gApp.mInstallDir, EXECUTABLE_PATH); let imgCreateExeTime = File.GetLastWriteTime(imgCreatePath).GetValueOrDefault(); for (let theme in mTheme) diff --git a/IDE/src/ui/AutoComplete.bf b/IDE/src/ui/AutoComplete.bf index 76eebe55f..5ce070a9b 100644 --- a/IDE/src/ui/AutoComplete.bf +++ b/IDE/src/ui/AutoComplete.bf @@ -288,7 +288,7 @@ namespace IDE.ui return; } - if ((mAutoComplete.mIgnoreMove == 0) && (mWidgetWindow != null) && (!mWidgetWindow.mHasClosed)) + if ((mAutoComplete.mIgnoreMove == 0) && (mWidgetWindow != null) && (!mWidgetWindow.mHasClosed) && (mWidgetWindow.HasParent(window))) mAutoComplete.Close(); } @@ -381,7 +381,6 @@ namespace IDE.ui using (g.PushColor(0xFFFFFFFF)) g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.Menu), 0, 0, boxWidth - GS!(6), drawHeight - GS!(8)); } - g.SetFont(IDEApp.sApp.mCodeFont); /*using (g.PushColor(0x80FF0000)) @@ -1527,7 +1526,7 @@ namespace IDE.ui { //Debug.WriteLine($"UpdateWindow Create {screenX},{screenY}"); - BFWindow.Flags windowFlags = BFWindow.Flags.ClientSized | BFWindow.Flags.PopupPosition | BFWindow.Flags.NoActivate | BFWindow.Flags.NoMouseActivate | BFWindow.Flags.DestAlpha; + BFWindow.Flags windowFlags = BFWindow.Flags.ClientSized | BFWindow.Flags.PopupPosition | BFWindow.Flags.NoActivate | BFWindow.Flags.NoMouseActivate | BFWindow.Flags.DestAlpha | BFWindow.Flags.Tooltip; widgetWindow = new WidgetWindow(mTargetEditWidget.mWidgetWindow, "Autocomplete", (int32)screenX, (int32)screenY, @@ -2052,7 +2051,7 @@ namespace IDE.ui if (changedAfterInfo) { mAutoCompleteListWidget.mSelectIdx = -1; - + if ((curString.Length == 0) && (!mIsMember) && (mInvokeSrcPositions == null)) { mPopulating = false; diff --git a/IDE/src/ui/HoverWatch.bf b/IDE/src/ui/HoverWatch.bf index f73c4886f..4cf91733f 100644 --- a/IDE/src/ui/HoverWatch.bf +++ b/IDE/src/ui/HoverWatch.bf @@ -459,20 +459,23 @@ namespace IDE.ui { base.Update(); - for (let item in mListView.GetRoot().mChildItems) - { - let listViewItem = (HoverListViewItem)item; - if (listViewItem.mWatchEntry?.mIsPending == true) - { - if ((gApp.mDebugger.IsPaused(true)) && (!gApp.mDebugger.HasMessages())) - { - let listView = (HoverListView)listViewItem.mListView; - DoListViewItem(listView, listViewItem, listViewItem.mWatchEntry.mName, listViewItem.mWatchEntry.mEvalStr, true); - FinishListView(listView, listView.mX, listView.mY, true); - gApp.RefreshVisibleViews(); - } - } - } + if(mListView != null) + { + for (let item in mListView.GetRoot().mChildItems) + { + let listViewItem = (HoverListViewItem)item; + if (listViewItem.mWatchEntry?.mIsPending == true) + { + if ((gApp.mDebugger.IsPaused(true)) && (!gApp.mDebugger.HasMessages())) + { + let listView = (HoverListView)listViewItem.mListView; + DoListViewItem(listView, listViewItem, listViewItem.mWatchEntry.mName, listViewItem.mWatchEntry.mEvalStr, true); + FinishListView(listView, listView.mX, listView.mY, true); + gApp.RefreshVisibleViews(); + } + } + } + } if (mCloseDelay > 1) mCloseDelay--; @@ -1082,7 +1085,7 @@ namespace IDE.ui var parentWidget = GetParentWidget(); - BFWindow.Flags windowFlags = BFWindow.Flags.ClientSized /*| BFWindow.Flags.PopupPosition*/ | BFWindow.Flags.NoActivate | BFWindow.Flags.DestAlpha; + BFWindow.Flags windowFlags = BFWindow.Flags.ClientSized /*| BFWindow.Flags.PopupPosition*/ | BFWindow.Flags.NoActivate | BFWindow.Flags.DestAlpha | BFWindow.Flags.Tooltip; #unwarn WidgetWindow widgetWindow = new WidgetWindow(parentWidget.mWidgetWindow, "HoverWatch", @@ -1108,11 +1111,7 @@ namespace IDE.ui autocomplete = watchEditWidgetContent.mAutoComplete; } - if (autocomplete != null) - autocomplete.SetIgnoreMove(true); mWidgetWindow.Resize((int32)(mOrigScreenX - mTaskbarXOffset + minX), (int32)(mOrigScreenY - mTaskbarYOffset + minY), (int32)(maxX - minX), (int32)(maxY - minY)); - if (autocomplete != null) - autocomplete.SetIgnoreMove(false); } } @@ -1686,7 +1685,7 @@ namespace IDE.ui /*float screenWidth = mListView.mWidth + 8; float screenHeight = mListView.mHeight + 8; - BFWindow.Flags windowFlags = BFWindow.Flags.ClientSized /*| BFWindow.Flags.PopupPosition*/ | BFWindow.Flags.NoActivate | BFWindow.Flags.DestAlpha; + BFWindow.Flags windowFlags = BFWindow.Flags.ClientSized /*| BFWindow.Flags.PopupPosition*/ | BFWindow.Flags.NoActivate | BFWindow.Flags.DestAlpha | BFWindow.Flags.Tooltip; #unwarn WidgetWindow widgetWindow = new WidgetWindow(parentWidget.mWidgetWindow, "HoverWatch", diff --git a/IDE/src/ui/MainFrame.bf b/IDE/src/ui/MainFrame.bf index 966e9872a..d76fcdd32 100644 --- a/IDE/src/ui/MainFrame.bf +++ b/IDE/src/ui/MainFrame.bf @@ -15,12 +15,20 @@ namespace IDE.ui public StatusBar mStatusBar; public DarkDockingFrame mDockingFrame; +#if !BF_PLATFORM_WINDOWS + public MenuBar mMenuBar; +#endif + public this() { mStatusBar = new StatusBar(); AddWidget(mStatusBar); mDockingFrame = (DarkDockingFrame)ThemeFactory.mDefault.CreateDockingFrame(); AddWidget(mDockingFrame); +#if !BF_PLATFORM_WINDOWS + mMenuBar = new MenuBar(); + AddWidget(mMenuBar); +#endif } public void Reset() @@ -40,8 +48,15 @@ namespace IDE.ui public override void Resize(float x, float y, float width, float height) { base.Resize(x, y, width, height); - int32 statusHeight = GS!(20); + + int32 statusHeight = GS!(20); +#if !BF_PLATFORM_WINDOWS + int32 menuHeight = GS!(20); + mDockingFrame.Resize(0, menuHeight, width, height - statusHeight - menuHeight); + mMenuBar.Resize(0, 0, width, menuHeight); +#else mDockingFrame.Resize(0, 0, width, height - statusHeight); +#endif mStatusBar.Resize(0, mHeight - statusHeight, width, statusHeight); } } diff --git a/IDE/src/ui/MenuBar.bf b/IDE/src/ui/MenuBar.bf new file mode 100644 index 000000000..9aa42a9ee --- /dev/null +++ b/IDE/src/ui/MenuBar.bf @@ -0,0 +1,259 @@ +using Beefy; +using Beefy.gfx; +using Beefy.widgets; +using Beefy.theme.dark; +using Beefy.geom; +using IDE; +using IDE.util; +using System; +using System.Diagnostics; +using System.Collections; +using Beefy.sys; + +namespace IDE.ui; + +public class MenuBar : Widget +{ + class UISysMenu : SysMenu + { + public override SysMenu AddMenuItem(String text, String hotKey = null, MenuItemSelectedHandler menuItemSelectedHandler = null, + MenuItemUpdateHandler menuItemUpdateHandler = null, SysBitmap bitmap = null, bool enabled = true, int32 checkState = -1, bool radioCheck = false) + { + if (mChildren == null) + mChildren = new List(); + + UISysMenu sysMenu = new UISysMenu(); + if (text != null) + { + sysMenu.mText = new String(text); + let bindIndex = sysMenu.mText.IndexOf('&'); + if (bindIndex != -1) + sysMenu.mText.Remove(bindIndex); + } + if ((hotKey != null) && (hotKey.Length != 0) && ((hotKey.Length > 1 ) || (hotKey[0] != '#'))) + { + sysMenu.mHotKey = new String(hotKey); + sysMenu.mHotKey.TrimStart('#'); + } + + sysMenu.mBitmap = bitmap; + sysMenu.mEnabled = enabled; + sysMenu.mCheckState = checkState; + sysMenu.mRadioCheck = radioCheck; + if (menuItemSelectedHandler != null) + sysMenu.mOnMenuItemSelected.Add(menuItemSelectedHandler); + if (menuItemUpdateHandler != null) + sysMenu.mOnMenuItemUpdate.Add(menuItemUpdateHandler); + sysMenu.mNativeBFMenu = null; + sysMenu.mParent = this; + sysMenu.mWindow = mWindow; + mChildren.Add(sysMenu); + + return sysMenu; + } + + public override void Modify(String text, String hotKey = null, SysBitmap bitmap = null, bool enabled = true, int32 checkState = -1, bool radioCheck = false) + { + if (((Object)mText != text) && (text != null)) + { + if (text.Length > 0) + { + String.NewOrSet!(mText, text); + let bindIndex = mText.IndexOf('&'); + if (bindIndex != -1) + mText.Remove(bindIndex); + } + else + DeleteAndNullify!(mText); + } + + if (((Object)mHotKey != hotKey) && (hotKey != null)) + { + if ((hotKey.Length > 0) && ((hotKey.Length > 1 ) || (hotKey[0] != '#'))) + { + String.NewOrSet!(mHotKey, hotKey); + mHotKey.TrimStart('#'); + } + else + DeleteAndNullify!(mHotKey); + } + mBitmap = bitmap; + mEnabled = enabled; + mCheckState = checkState; + mRadioCheck = radioCheck; + } + } + + public class UISysMenuRoot : UISysMenu + { + public MenuBar mRootMenuBar; + public this() + { + + } + + public override SysMenu AddMenuItem(String text, String hotKey = null, MenuItemSelectedHandler menuItemSelectedHandler = null, MenuItemUpdateHandler menuItemUpdateHandler = null, + SysBitmap bitmap = null, bool enabled = true, int32 checkState = -1, bool radioCheck = false) + { + let item = base.AddMenuItem(text, hotKey, menuItemSelectedHandler, menuItemUpdateHandler, bitmap, enabled, checkState, radioCheck); + let button = new Button(); + button.Label = text; + button.mSysMenu = item; + button.mOnMouseClick.Add(new (evt) => { + mOnMenuItemSelected(this); + mRootMenuBar.ShowMenu(button); + }); + mRootMenuBar.AddItemButton(button); + return item; + } + } + + public class Button : ButtonWidget + { + private String mLabel ~ delete _; + + public StringView Label + { + get + { + return mLabel; + } + + set + { + String.NewOrSet!(mLabel, value); + } + } + + public SysMenu mSysMenu; + + public override void Draw(Graphics g) + { + base.Draw(g); + + if (mMouseOver) + { + using (g.PushColor(0x40FFFFFF)) + { + g.FillRect(0, 0, mWidth, mHeight); + } + } + + g.SetFont(DarkTheme.sDarkTheme.mSmallFont); + if (mLabel != null) + { + using (g.PushColor(mDisabled ? 0x80FFFFFF : Color.White)) + { + using (g.PushColor(DarkTheme.COLOR_TEXT)) + DarkTheme.DrawUnderlined(g, mLabel, GS!(2), (mHeight - GS!(20)) / 2, .Centered, mWidth - GS!(4), .Truncate); + } + } + } + } + + + public append List