diff --git a/BeefLibs/Beefy2D/src/BFApp.bf b/BeefLibs/Beefy2D/src/BFApp.bf index e6f68a3d..81c6cc5f 100644 --- a/BeefLibs/Beefy2D/src/BFApp.bf +++ b/BeefLibs/Beefy2D/src/BFApp.bf @@ -11,6 +11,7 @@ using Beefy.utils; using Beefy.res; using Beefy.geom; using System.Threading; +using Beefy.sound; #if MONOTOUCH using MonoTouch; #endif @@ -61,6 +62,7 @@ namespace Beefy public bool mStarted; public ResourceManager mResourceManager ~ delete _; + public SoundManager mSoundManager = new SoundManager() ~ delete _; public int32 mFPSDrawCount; public int32 mFPSUpdateCount; @@ -124,6 +126,9 @@ namespace Beefy [StdCall, CLink] public static extern void BFApp_RehupMouse(); + [StdCall, CLink] + public static extern void* BFApp_GetSoundManager(); + UpdateDelegate mUpdateDelegate ~ delete _; DrawDelegate mDrawDelegate ~ delete _; @@ -467,6 +472,8 @@ namespace Beefy #endif BFApp_Init(); + mSoundManager.[Friend]mNativeSoundManager = BFApp_GetSoundManager(); + Interlocked.Fence(); mInstallDir = new String(BFApp_GetInstallDir()); diff --git a/BeefLibs/Beefy2D/src/gfx/Graphics.bf b/BeefLibs/Beefy2D/src/gfx/Graphics.bf index 17cc13c2..5c1da534 100644 --- a/BeefLibs/Beefy2D/src/gfx/Graphics.bf +++ b/BeefLibs/Beefy2D/src/gfx/Graphics.bf @@ -107,9 +107,7 @@ namespace Beefy.gfx mClipDisposeProxy.mDisposeProxyDelegate = new => PopClip; mRenderStateDisposeProxy = new DisposeProxy(); - String filePath = scope String(); - filePath.Append(BFApp.sApp.mInstallDir, "images/whiteDot.tga"); - mWhiteDot = Image.LoadFromFile(filePath); + mWhiteDot = Image.LoadFromFile("!white"); for (int32 i = 0; i < MATIX_STACK_SIZE; i++) mMatrixStack[i] = Matrix.IdentityMatrix; diff --git a/BeefLibs/Beefy2D/src/res/SoundGameObject.bf b/BeefLibs/Beefy2D/src/res/SoundGameObject.bf index a79a53dd..9f1bec72 100644 --- a/BeefLibs/Beefy2D/src/res/SoundGameObject.bf +++ b/BeefLibs/Beefy2D/src/res/SoundGameObject.bf @@ -4,8 +4,8 @@ using System.Text; namespace Beefy.res { - public class SoundGameObject + /*public class SoundGameObject { public void* mWwiseObject; - } + }*/ } diff --git a/BeefLibs/Beefy2D/src/sound/SoundInstance.bf b/BeefLibs/Beefy2D/src/sound/SoundInstance.bf new file mode 100644 index 00000000..b4b4a859 --- /dev/null +++ b/BeefLibs/Beefy2D/src/sound/SoundInstance.bf @@ -0,0 +1,43 @@ +using System; + +namespace Beefy.sound +{ + struct SoundInstance + { + [StdCall, CLink] + public static extern void* BFSoundInstance_Play(void* nativeSoundInstance, bool looping, bool autoRelease); + + [StdCall, CLink] + public static extern void BFSoundInstance_Release(void* nativeSoundInstance); + + [StdCall, CLink] + public static extern bool BFSoundInstance_IsPlaying(void* nativeSoundInstance); + + void* mNativeSoundInstance; + + public this(void* nativeSoundInstance) + { + mNativeSoundInstance = nativeSoundInstance; + } + + public void Dispose() mut + { + BFSoundInstance_Release(mNativeSoundInstance); + mNativeSoundInstance = null; + } + + public void Play(bool looping = false, bool autoRelease = false) + { + if (mNativeSoundInstance == null) + return; + BFSoundInstance_Play(mNativeSoundInstance, looping, autoRelease); + } + + public bool IsPlaying() + { + if (mNativeSoundInstance == null) + return false; + return BFSoundInstance_IsPlaying(mNativeSoundInstance); + } + } +} diff --git a/BeefLibs/Beefy2D/src/sound/SoundManager.bf b/BeefLibs/Beefy2D/src/sound/SoundManager.bf new file mode 100644 index 00000000..6fc9bb44 --- /dev/null +++ b/BeefLibs/Beefy2D/src/sound/SoundManager.bf @@ -0,0 +1,43 @@ +using System; + +namespace Beefy.sound +{ + struct SoundSource : int32 + { + public bool IsInvalid + { + get + { + return this == (.)-1; + } + } + } + + class SoundManager + { + void* mNativeSoundManager; + + [StdCall, CLink] + public static extern int32 BFSoundManager_LoadSound(void* nativeSoundManager, char8* fileName); + + [StdCall, CLink] + public static extern void* BFSoundManager_GetSoundInstance(void* nativeSoundManager, int32 sfxId); + + public SoundSource LoadSound(StringView fileName) + { + return (.)BFSoundManager_LoadSound(mNativeSoundManager, fileName.ToScopeCStr!()); + } + + public SoundInstance GetSoundInstance(SoundSource soundSource) + { + void* nativeSoundInstance = BFSoundManager_GetSoundInstance(mNativeSoundManager, (.)soundSource); + return .(nativeSoundInstance); + } + + public void PlaySound(SoundSource soundSource) + { + let soundInstance = GetSoundInstance(soundSource); + soundInstance.Play(false, true); + } + } +} diff --git a/BeefLibs/Beefy2D/src/widgets/ImageWidget.bf b/BeefLibs/Beefy2D/src/widgets/ImageWidget.bf index 4307e504..9b650b86 100644 --- a/BeefLibs/Beefy2D/src/widgets/ImageWidget.bf +++ b/BeefLibs/Beefy2D/src/widgets/ImageWidget.bf @@ -15,7 +15,7 @@ namespace Beefy.widgets { if ((mMouseOver && mMouseDown) && (mDownImage != null)) g.Draw(mDownImage); - if ((mMouseOver) && (mOverImage != null)) + else if ((mMouseOver) && (mOverImage != null)) g.Draw(mOverImage); else g.Draw(mImage); diff --git a/BeefLibs/Beefy2D/src/widgets/LabelWidget.bf b/BeefLibs/Beefy2D/src/widgets/LabelWidget.bf index 47df731f..3d4e0ea3 100644 --- a/BeefLibs/Beefy2D/src/widgets/LabelWidget.bf +++ b/BeefLibs/Beefy2D/src/widgets/LabelWidget.bf @@ -9,8 +9,9 @@ namespace Beefy.widgets public class LabelWidget : Widget { public Font mFont; - public String mLabel; + public String mLabel ~ delete _; public uint32 mColor = Color.White; + public FontAlign mAlign = .Left; public override void Draw(Graphics g) { @@ -18,7 +19,12 @@ namespace Beefy.widgets g.SetFont(mFont); using (g.PushColor(mColor)) - g.DrawString(mLabel, 0, 0); + g.DrawString(mLabel, 0, 0, mAlign, mWidth); } + + public float CalcWidth() + { + return mFont.GetWidth(mLabel); + } } } diff --git a/BeefLibs/Beefy2D/src/widgets/Widget.bf b/BeefLibs/Beefy2D/src/widgets/Widget.bf index f5573fea..16523e26 100644 --- a/BeefLibs/Beefy2D/src/widgets/Widget.bf +++ b/BeefLibs/Beefy2D/src/widgets/Widget.bf @@ -102,7 +102,7 @@ namespace Beefy.widgets { if ((value.a == 1) && (value.b == 0) && (value.c == 0) && (value.d == 1)) { - mTransformData = null; + DeleteAndNullify!(mTransformData); mX = value.tx; mY = value.ty; } @@ -142,6 +142,11 @@ namespace Beefy.widgets mOnDeleted(this); } + public void ClearTransform() + { + DeleteAndNullify!(mTransformData); + } + public void MarkDirty() { if (mWidgetWindow != null) diff --git a/BeefLibs/Beefy2D/src/widgets/WidgetWindow.bf b/BeefLibs/Beefy2D/src/widgets/WidgetWindow.bf index 2717754b..44deb6e4 100644 --- a/BeefLibs/Beefy2D/src/widgets/WidgetWindow.bf +++ b/BeefLibs/Beefy2D/src/widgets/WidgetWindow.bf @@ -428,7 +428,15 @@ namespace Beefy.widgets { var result = mOnHitTest(x, y); if (result != HitTestResult.NotHandled) + { + if (result != .Client) + { + if (mHasMouseInside) + MouseLeave(); + } + return result; + } } if (mWindowFlags.HasFlag(Flags.Resizable)) @@ -445,7 +453,7 @@ namespace Beefy.widgets if (!mHasMouseInside) return; - Widget aWidget = mRootWidget.FindWidgetByCoords(mMouseX, mMouseY); + Widget aWidget = mRootWidget.FindWidgetByCoords(mMouseX, mMouseY); if (mCaptureWidget != null) { bool didSomething = false; diff --git a/BeefLibs/SDL2/src/SDL2.bf b/BeefLibs/SDL2/src/SDL2.bf index 1e148918..cf6ddf0b 100644 --- a/BeefLibs/SDL2/src/SDL2.bf +++ b/BeefLibs/SDL2/src/SDL2.bf @@ -25,7 +25,6 @@ */ using System; -using System.Runtime.InteropServices; namespace SDL2 { diff --git a/BeefLibs/SDL2/src/SDL2_mixer.bf b/BeefLibs/SDL2/src/SDL2_mixer.bf index 06376aba..b223b910 100644 --- a/BeefLibs/SDL2/src/SDL2_mixer.bf +++ b/BeefLibs/SDL2/src/SDL2_mixer.bf @@ -28,7 +28,6 @@ #region Using Statements using System; -using System.Runtime.InteropServices; #endregion namespace SDL2 diff --git a/BeefLibs/SDL2/src/SDL2_ttf.bf b/BeefLibs/SDL2/src/SDL2_ttf.bf index 7adb1e4a..557be93f 100644 --- a/BeefLibs/SDL2/src/SDL2_ttf.bf +++ b/BeefLibs/SDL2/src/SDL2_ttf.bf @@ -25,7 +25,6 @@ */ using System; -using System.Runtime.InteropServices; namespace SDL2 { @@ -40,13 +39,13 @@ namespace SDL2 public const int32 SDL_TTF_PATCHLEVEL = 12; public const int32 UNICODE_BOM_NATIVE = 0xFEFF; - public const int32 UNICODE_BOM_SWAPPED = 0xFFFE; + public const int32 UNICODE_BOM_SWAPPED = 0xFFFE; - public const int32 TTF_STYLE_NORMAL = 0x00; - public const int32 TTF_STYLE_BOLD = 0x01; - public const int32 TTF_STYLE_ITALIC = 0x02; - public const int32 TTF_STYLE_UNDERLINE = 0x04; - public const int32 TTF_STYLE_STRIKETHROUGH = 0x08; + public const int32 TTF_STYLE_NORMAL = 0x00; + public const int32 TTF_STYLE_BOLD = 0x01; + public const int32 TTF_STYLE_ITALIC = 0x02; + public const int32 TTF_STYLE_UNDERLINE = 0x04; + public const int32 TTF_STYLE_STRIKETHROUGH = 0x08; public const int32 TTF_HINTING_NORMAL = 0; public const int32 TTF_HINTING_LIGHT = 1; diff --git a/BeefLibs/corlib/src/System/Threading/Thread.bf b/BeefLibs/corlib/src/System/Threading/Thread.bf index 0fcc6733..b2090c0d 100644 --- a/BeefLibs/corlib/src/System/Threading/Thread.bf +++ b/BeefLibs/corlib/src/System/Threading/Thread.bf @@ -181,7 +181,7 @@ namespace System.Threading StartInternal(); } -#if PLATFORM_WINDOWS +#if BF_PLATFORM_WINDOWS [CLink] static extern int32 _tls_index; #endif @@ -190,7 +190,7 @@ namespace System.Threading { get { -#if PLATFORM_WINDOWS +#if BF_PLATFORM_WINDOWS return _tls_index; #else return 0; diff --git a/BeefLibs/corlib/src/System/Windows.bf b/BeefLibs/corlib/src/System/Windows.bf index 825163a5..7882283e 100644 --- a/BeefLibs/corlib/src/System/Windows.bf +++ b/BeefLibs/corlib/src/System/Windows.bf @@ -852,6 +852,12 @@ namespace System public const int32 OFN_USESHELLITEM = 0x01000000; public const int32 CSIDL_DESKTOP = 0x0000; + public const int32 CSIDL_PROGRAMS = 0x0002; // Start Menu\Programs + public const int32 CSIDL_PERSONAL = 0x0005; // My Documents + public const int32 CSIDL_STARTUP = 0x0007; // Start Menu\Programs\Startup + public const int32 CSIDL_LOCAL_APPDATA = 0x001c;// \Local Settings\Applicaiton Data (non roaming) + public const int32 CSIDL_COMMON_APPDATA = 0x0023; // All Users\Application Data + public const int32 CSIDL_PROGRAM_FILES = 0x0026; // C:\Program Files public const int32 WM_CLOSE = 0x0010; public const int32 WM_DESTROY = 0x0002; diff --git a/BeefRT/dbg/gc.cpp b/BeefRT/dbg/gc.cpp index 68cc6a2b..94b2d1f1 100644 --- a/BeefRT/dbg/gc.cpp +++ b/BeefRT/dbg/gc.cpp @@ -589,6 +589,7 @@ BFGC::BFGC() mForceDecommit = false; mLastCollectFrame = 0; mSkipMark = false; + mGracelessShutdown = false; mMainThreadTLSPtr = NULL; mCollectIdx = 0; @@ -1933,6 +1934,14 @@ void BFGC::StopCollecting() mExiting = true; while (mRunning) { + if (BfpThread_WaitFor(mGCThread, 0)) + { + OutputDebugStr("BeefDbgRT not shut down gracefully!\n"); + mGracelessShutdown = true; + mRunning = false; + break; + } + //BFRtLock bfLock(mEphemeronTombstone); mWaitingForGC = true; // Wait for current collection to finish @@ -1970,6 +1979,9 @@ void BFGC::Shutdown() Beefy::AutoCrit autoCrit(mCritSect); + if (mGracelessShutdown) + return; + // Report any objects that aren't deleted mSweepInfo.mShowAllAsLeaks = true; Sweep(); @@ -2269,7 +2281,7 @@ void BFGC::ResumeThreads() void BFGC::PerformCollection() { BP_ZONE("TriggerCollection"); - + DWORD startTick = BFTickCount(); CollectReport collectReport; collectReport.mCollectIdx = mCollectIdx; diff --git a/BeefRT/dbg/gc.h b/BeefRT/dbg/gc.h index cb2d45f9..1acf7dbb 100644 --- a/BeefRT/dbg/gc.h +++ b/BeefRT/dbg/gc.h @@ -267,6 +267,7 @@ public: volatile bool mExiting; volatile bool mRunning; + bool mGracelessShutdown; bool mPaused; bool mShutdown; bool mWaitingForGC; // GC.Collect sets this diff --git a/BeefTools/BeefInstall/Stub/BeefProj.toml b/BeefTools/BeefInstall/Stub/BeefProj.toml index 9f9ece73..8d6daaf5 100644 --- a/BeefTools/BeefInstall/Stub/BeefProj.toml +++ b/BeefTools/BeefInstall/Stub/BeefProj.toml @@ -2,6 +2,7 @@ FileVersion = 1 [Project] Name = "Stub" +TargetType = "BeefWindowsApplication" StartupObject = "BIStub.Program" [Configs.Debug.Win64] diff --git a/BeefTools/BeefInstall/Stub/src/Program.bf b/BeefTools/BeefInstall/Stub/src/Program.bf index e5bf82e0..7f2634d2 100644 --- a/BeefTools/BeefInstall/Stub/src/Program.bf +++ b/BeefTools/BeefInstall/Stub/src/Program.bf @@ -147,6 +147,8 @@ namespace BIStub } startFunc(=> UI_Install, => UI_GetProgress, => UI_Cancel); + + Windows.FreeLibrary(lib); } void Run() @@ -155,7 +157,7 @@ namespace BIStub Directory.GetCurrentDirectory(cwd); StartUI(cwd); - CheckPE(); + /*CheckPE(); ZipFile zipFile = scope .(); zipFile.Open(@"c:\\temp\\build_1827.zip"); @@ -163,7 +165,7 @@ namespace BIStub CabFile cabFile = scope .(); cabFile.Init(); - cabFile.Copy(); + cabFile.Copy();*/ } static int Main(String[] args) diff --git a/BeefTools/BeefInstall/StubUI/BeefProj.toml b/BeefTools/BeefInstall/StubUI/BeefProj.toml index da98affb..85b15fec 100644 --- a/BeefTools/BeefInstall/StubUI/BeefProj.toml +++ b/BeefTools/BeefInstall/StubUI/BeefProj.toml @@ -1,5 +1,5 @@ FileVersion = 1 -Dependencies = {corlib = "*", Beefy2D = "*"} +Dependencies = {corlib = "*", Beefy2D = "*", SDL2 = "*"} [Project] Name = "StubUI" @@ -11,7 +11,7 @@ DefaultNamespace = "BIStubUI" TargetDirectory = "$(WorkspaceDir)/../dist" TargetName = "$(ProjectName)_d" OtherLinkFlags = "$(LinkFlags) BeefySysLib64_d.lib" -PostBuildCmds = ["Sleep(1000)", "cmd.exe /c echo Hey!", "CopyFilesIfNewer(\"$(WorkspaceDir)/../../../IDE/dist/BeefySysLib*.*\", \"$(WorkspaceDir)/../dist\")"] +BeefLibType = "DynamicDebug" DebugCommand = "$(WorkspaceDir)\\..\\dist\\Stub_d.exe" [Configs.Release.Win64] diff --git a/BeefTools/BeefInstall/StubUI/BeefSpace.toml b/BeefTools/BeefInstall/StubUI/BeefSpace.toml index bb37a711..6e820900 100644 --- a/BeefTools/BeefInstall/StubUI/BeefSpace.toml +++ b/BeefTools/BeefInstall/StubUI/BeefSpace.toml @@ -1,6 +1,6 @@ FileVersion = 1 -Projects = {StubUI = {Path = "."}, Beefy2D = "*"} -Unlocked = ["corlib"] +Projects = {StubUI = {Path = "."}, Beefy2D = "*", SDL2 = "*"} +Unlocked = ["Beefy2D", "corlib", "SDL2"] [Workspace] StartupProject = "StubUI" diff --git a/BeefTools/BeefInstall/StubUI/src/BIApp.bf b/BeefTools/BeefInstall/StubUI/src/BIApp.bf index 19a26bcf..309358cf 100644 --- a/BeefTools/BeefInstall/StubUI/src/BIApp.bf +++ b/BeefTools/BeefInstall/StubUI/src/BIApp.bf @@ -1,36 +1,124 @@ using System; using Beefy; using Beefy.widgets; +using Beefy.geom; +using Beefy.gfx; namespace BIStubUI { class BIApp : BFApp { + static int a = 123; + public function void InstallFunc(StringView dest, StringView filter); public function int ProgressFunc(); public function void CancelFunc(); + const int cWidth = 900; + const int cHeight = 620; + + public Font mHeaderFont ~ delete _; + public Font mBodyFont ~ delete _; + public Font mBtnFont ~ delete _; + public Font mBoxFont ~ delete _; + public InstallFunc mInstallFunc; public ProgressFunc mProgressFunc; public CancelFunc mCancelFunc; - Widget mRootWidget; - WidgetWindow mMainWindow; + public Board mBoard; + public Widget mRootWidget; + public WidgetWindow mMainWindow; - const int cWidth = 700; - const int cHeight = 700; + public bool mCancelling; + public bool mWantRehup; + public int32 mBoardDelay; + public bool mClosing; + + public ~this() + { + Images.Dispose(); + } public override void Init() { base.Init(); - BFWindow.Flags windowFlags = BFWindow.Flags.Border | BFWindow.Flags.SysMenu | //| BFWindow.Flags.CaptureMediaKeys | - BFWindow.Flags.Caption | BFWindow.Flags.Minimize | BFWindow.Flags.QuitOnClose; - + BFWindow.Flags windowFlags = .QuitOnClose + | .DestAlpha + ; + + GetWorkspaceRect(var workX, var workY, var workWidth, var workHeight); + mRootWidget = new Widget(); - mMainWindow = new WidgetWindow(null, "Beef Installer", 0, 0, cWidth, cHeight, windowFlags, mRootWidget); - mMainWindow.SetMinimumSize(480, 360); + mMainWindow = new WidgetWindow(null, "Beef Installer", + workX + (workWidth - cWidth)/2, workY + (workHeight - cHeight) / 2, cWidth, cHeight, windowFlags, mRootWidget); mMainWindow.mIsMainWindow = true; + mMainWindow.mOnHitTest.Add(new (absX, absY) => + { + float x = absX - mMainWindow.mX; + float y = absY - mMainWindow.mY; + + Widget aWidget = mRootWidget.FindWidgetByCoords(x, y); + if ((aWidget != null) && (aWidget != mBoard)) + return .NotHandled; + + if (Rect(60, 24, 700, 420).Contains(x, y)) + return .Caption; + + return .NotHandled; + }); + + Font CreateFont(StringView srcName, float fontSize) + { + Font font = new Font(); + font.Load(srcName, fontSize); + font.AddAlternate("Segoe UI Symbol", fontSize); + font.AddAlternate("Segoe UI Historic", fontSize); + font.AddAlternate("Segoe UI Emoji", fontSize); + return font; + } + + mHeaderFont = CreateFont("Segoe UI Bold", 42); + mBodyFont = CreateFont("Segoe UI", 22); + mBoxFont = CreateFont("Segoe UI", 18); + mBtnFont = CreateFont("Segoe UI", 32); + + Images.Init(); + Sounds.Init(); + + SetupBoard(); + } + + void SetupBoard() + { + mBoard = new .(); + mRootWidget.AddWidget(mBoard); + mBoard.Resize(0, 0, cWidth, cHeight); + mBoard.SetFocus(); + } + + public override void Update(bool batchStart) + { + base.Update(batchStart); + + if (mCancelling) + { + mClosing = true; + if ((mBoard != null) && (mBoard.mIsClosed)) + Stop(); + } + + if (mWantRehup) + { + mBoard.RemoveSelf(); + DeleteAndNullify!(mBoard); + mBoardDelay = 30; + mWantRehup = false; + } + + if ((mBoardDelay > 0) && (--mBoardDelay == 0)) + SetupBoard(); } } diff --git a/BeefTools/BeefInstall/StubUI/src/Board.bf b/BeefTools/BeefInstall/StubUI/src/Board.bf new file mode 100644 index 00000000..a6be7a10 --- /dev/null +++ b/BeefTools/BeefInstall/StubUI/src/Board.bf @@ -0,0 +1,563 @@ +using Beefy.widgets; +using Beefy.geom; +using Beefy.gfx; +using System.Diagnostics; +using System; +using System.IO; + +namespace BIStubUI +{ + class BiButtonWidget : ButtonWidget + { + public Image mImage; + public Image mImageHi; + + public override void Draw(Graphics g) + { + if (mMouseOver && mMouseDown) + g.Draw(mImageHi); + if (mMouseOver) + g.Draw(mImageHi); + else + g.Draw(mImage); + + /*using (g.PushColor(0x8000FF00)) + g.FillRect(0, 0, mWidth, mHeight);*/ + } + + public override void DrawAll(Graphics g) + { + using (g.PushColor(mDisabled ? 0xD0A0A0A0 : 0xFFFFFFFF)) + base.DrawAll(g); + } + + public override void MouseEnter() + { + base.MouseEnter(); + if (!mDisabled) + { + gApp.SetCursor(.Hand); + gApp.mSoundManager.PlaySound(Sounds.sMouseOver); + } + } + + public override void MouseDown(float x, float y, int32 btn, int32 btnCount) + { + base.MouseDown(x, y, btn, btnCount); + if (!mDisabled) + gApp.mSoundManager.PlaySound(Sounds.sButtonPress); + } + + public override void MouseLeave() + { + base.MouseLeave(); + gApp.SetCursor(.Pointer); + } + } + + class BiDialogButton : BiButtonWidget + { + public String mLabel ~ delete _; + + public override void Draw(Graphics g) + { + base.Draw(g); + + g.SetFont(gApp.mBtnFont); + g.DrawString(mLabel, 0, 14, .Centered, mWidth); + } + } + + class BiCheckbox : CheckBox + { + public State mState; + public String mLabel ~ delete _; + + public override bool Checked + { + get + { + return mState != .Unchecked; + } + + set + { + gApp.mSoundManager.PlaySound(Sounds.sChecked); + mState = value ? .Checked : .Unchecked; + } + } + + public override State State + { + get + { + return mState; + } + + set + { + mState = value; + } + } + + public override void Draw(Graphics g) + { + if (mState == .Checked) + g.Draw(Images.sChecked); + else + g.Draw(Images.sUnchecked); + + g.SetFont(gApp.mBodyFont); + using (g.PushColor(0xFF000000)) + g.DrawString(mLabel, 40, 2); + } + + public override void MouseEnter() + { + base.MouseEnter(); + gApp.SetCursor(.Hand); + } + + public override void MouseLeave() + { + base.MouseLeave(); + gApp.SetCursor(.Pointer); + } + } + + class BiInstallPathBox : Widget + { + public String mInstallPath = new .() ~ delete _; + ImageWidget mBrowseButton; + + public this() + { + mBrowseButton = new ImageWidget(); + mBrowseButton.mImage = Images.sBrowse; + mBrowseButton.mDownImage = Images.sBrowseDown; + mBrowseButton.mOnMouseClick.Add(new (mouseArgs) => + { + var folderDialog = scope FolderBrowserDialog(); + if (folderDialog.ShowDialog(mWidgetWindow).GetValueOrDefault() == .OK) + { + var selectedPath = scope String..AppendF(folderDialog.SelectedPath); + mInstallPath.Set(selectedPath); + } + }); + AddWidget(mBrowseButton); + } + + public void ResizeComponenets() + { + mBrowseButton.Resize(mWidth - 30, 2, Images.sBrowse.mWidth, Images.sBrowse.mHeight); + } + + public override void Resize(float x, float y, float width, float height) + { + base.Resize(x, y, width, height); + ResizeComponenets(); + } + + public override void Update() + { + base.Update(); + ResizeComponenets(); + } + + public override void Draw(Graphics g) + { + base.Draw(g); + + g.DrawButton(Images.sTextBox, 0, 0, mWidth); + using (g.PushColor(0xFF000000)) + { + g.SetFont(gApp.mBodyFont); + g.DrawString("Installation path", 0, -32); + g.SetFont(gApp.mBoxFont); + g.DrawString(mInstallPath, 4, 0, .Left, mWidth - 36, .Ellipsis); + } + } + } + + class Board : Widget + { + const float cBodyX = 0; + const float cBodyY = 20; + + LabelWidget mHeaderLabel; + BiButtonWidget mCloseButton; + BiDialogButton mCancelButton; + BiDialogButton mInstallButton; + BiCheckbox mInstallForAllCheckbox; + BiCheckbox mAddToStartCheckbox; + BiCheckbox mAddToDesktopCheckbox; + BiCheckbox mStartAfterCheckbox; + BiInstallPathBox mInstallPathBox; + + float mScale = 0.35f; + float mScaleVel = 0.2f; + + float mSurprisePct = 1.0f; + float mHeadRaise = 1.0f; + float mEatPct; + + int mCloseTicks; + public bool mIsClosed; + + public bool mInstalling; + public float mInstallPct = 0.5f; + + public this() + { + mHeaderLabel = new LabelWidget(); + mHeaderLabel.mLabel = new String("Beef Development Tools"); + mHeaderLabel.mAlign = .Centered; + mHeaderLabel.mColor = 0xFF000000; + mHeaderLabel.mFont = gApp.mHeaderFont; + mHeaderLabel.mMouseVisible = false; + AddWidget(mHeaderLabel); + + mCloseButton = new BiButtonWidget(); + mCloseButton.mImage = Images.sClose; + mCloseButton.mImageHi = Images.sCloseHi; + mCloseButton.mOnMouseClick.Add(new (mouseArgs) => + { + gApp.mCancelling = true; + }); + mCloseButton.mMouseInsets = new Insets(4, 4, 4, 4); + AddWidget(mCloseButton); + + mInstallForAllCheckbox = new BiCheckbox(); + mInstallForAllCheckbox.mState = .Checked; + mInstallForAllCheckbox.mLabel = new String("Install for all users"); + AddWidget(mInstallForAllCheckbox); + + mAddToStartCheckbox = new BiCheckbox(); + mAddToStartCheckbox.mState = .Checked; + mAddToStartCheckbox.mLabel = new String("Add to Start menu"); + AddWidget(mAddToStartCheckbox); + + mAddToDesktopCheckbox = new BiCheckbox(); + mAddToDesktopCheckbox.mState = .Checked; + mAddToDesktopCheckbox.mLabel = new String("Add to desktop"); + AddWidget(mAddToDesktopCheckbox); + + mStartAfterCheckbox = new BiCheckbox(); + mStartAfterCheckbox.mState = .Checked; + mStartAfterCheckbox.mLabel = new String("Run after install"); + AddWidget(mStartAfterCheckbox); + + mInstallPathBox = new BiInstallPathBox(); + AddWidget(mInstallPathBox); + + mCancelButton = new BiDialogButton(); + mCancelButton.mLabel = new .("Cancel"); + mCancelButton.mImage = Images.sButton; + mCancelButton.mImageHi = Images.sButtonHi; + mCancelButton.mOnMouseClick.Add(new (mouseArgs) => + { + gApp.mCancelling = true; + }); + mCancelButton.mMouseInsets = new Insets(4, 4, 4, 4); + AddWidget(mCancelButton); + + mInstallButton = new BiDialogButton(); + mInstallButton.mLabel = new .("Install"); + mInstallButton.mImage = Images.sButton; + mInstallButton.mImageHi = Images.sButtonHi; + mInstallButton.mOnMouseClick.Add(new (mouseArgs) => + { + StartInstall(); + }); + mInstallButton.mMouseInsets = new Insets(4, 4, 4, 4); + AddWidget(mInstallButton); + + //// + + int pidl = 0; + Windows.SHGetSpecialFolderLocation(gApp.mMainWindow.HWND, Windows.CSIDL_PROGRAM_FILES, ref pidl); + if (pidl != 0) + { + char8* selectedPathCStr = scope char8[Windows.MAX_PATH]*; + Windows.SHGetPathFromIDList(pidl, selectedPathCStr); + mInstallPathBox.mInstallPath.Set(StringView(selectedPathCStr)); + } + else + { + mInstallPathBox.mInstallPath.Set(@"C:\Program Files"); + } + mInstallPathBox.mInstallPath.Append(@"\BeefLang"); + } + + void StartInstall() + { + mInstalling = true; + mInstallButton.mDisabled = true; + mInstallButton.mMouseVisible = false; + mInstallPathBox.mVisible = false; + } + + public override void Draw(Graphics g) + { + float bodyX = cBodyX; + float bodyY = cBodyY; + + g.Draw(Images.sBody, bodyX, bodyY); + + float headRaise = mHeadRaise; + headRaise += Math.Sin(Math.Clamp((mEatPct - 0.2f) * 1.4f, 0, 1.0f) * Math.PI_f*6) * 0.02f; + + float headX = bodyX + 664 - headRaise * 6; + float headY = bodyY + 192 - headRaise * 30; + + headY += Math.Clamp(Math.Sin(Math.PI_f * mEatPct) * 3.0f, 0, 1) * 8.0f; + + Images.sHead.mPixelSnapping = .Never; + Images.sEyesOpen.mPixelSnapping = .Never; + Images.sEyesClosed.mPixelSnapping = .Never; + g.Draw(Images.sHead, headX, headY); + g.Draw((mSurprisePct > 0) ? Images.sEyesOpen : Images.sEyesClosed, headX + 70, headY + 190); + + if (mInstalling) + { + float installDiv = 1000.0f; + //mInstallPct = (mUpdateCnt % installDiv) / installDiv; + + //mInstallPct = 1.0f; + + float totalWidth = 410; + float fillWidth = totalWidth * (mInstallPct*0.9f + 0.1f); + + float barX = 200; + float barY = 280; + + float barHeight = Images.sPBBarBottom.mHeight; + using (g.PushClip(barX, barY, totalWidth, barHeight)) + { + g.DrawButton(Images.sPBBarBottom, barX, barY, totalWidth); + + Color colorLeft = 0x800288E9; + Color colorRight = 0x80FFFFFF; + g.FillRectGradient(barX, barY, fillWidth, barHeight, colorLeft, colorRight, colorLeft, colorRight); + + float pct = (mUpdateCnt % 60) / 60.0f; + + for (int i = 0; i < 16; i++) + { + Images.sPBBarHilite.mPixelSnapping = .Never; + using (g.PushColor(0x22FFFFFF)) + g.Draw(Images.sPBBarHilite, barX - 16 - totalWidth + fillWidth + (i + pct) * 26, barY + 6); + } + + g.DrawButton(Images.sPBBarEmpty, barX + fillWidth - 30, barY + 5, totalWidth - fillWidth + 40); + + g.DrawButton(Images.sPBFrameTop, barX, barY, totalWidth); + + g.DrawButton(Images.sPBFrameGlow, barX, barY, fillWidth); + } + } + + /*g.SetFont(gApp.mHdrFont); + using (g.PushColor(0xFF000000)) + g.DrawString("Beef Development Tools", 400, 20, .Centered);*/ + } + + public override void MouseMove(float x, float y) + { + if (Rect(60, 24, 700, 420).Contains(x, y)) + { + gApp.SetCursor(.SizeNESW); + } + else + { + gApp.SetCursor(.Pointer); + } + + base.MouseMove(x, y); + } + + public override void DrawAll(Graphics g) + { + int cBodyX = 0; + int cBodyY = 0; + + /*using (g.PushColor(0x80FF0000)) + g.FillRect(0, 0, mWidth, mHeight);*/ + + //float scaleX = (Math.Cos(mUpdateCnt * 0.1f) + 1.0f) * 0.5f; + //float scaleY = scaleX; + float scaleX = mScale; + float scaleY = mScale; + + if ((Math.Abs(scaleX - 1.0f) < 0.001) && (Math.Abs(scaleY - 1.0f) < 0.001)) + base.DrawAll(g); + else using (g.PushScale(scaleX, scaleY, cBodyX + 400, cBodyY + 560)) + base.DrawAll(g); + } + + public override void Update() + { + base.Update(); + + ResizeComponents(); + + if (gApp.mClosing) + { + if (mCloseTicks == 0) + { + gApp.mSoundManager.PlaySound(Sounds.sAbort); + mScaleVel = 0.055f; + } + mCloseTicks++; + + mScaleVel *= 0.90f; + mScaleVel -= 0.01f; + mScale += mScaleVel; + mSurprisePct = 1.0f; + mHeadRaise = Math.Clamp(mHeadRaise + 0.2f, 0, 1.0f); + + if (mScale <= 0) + { + mScale = 0.0f; + } + + if (mCloseTicks == 60) + mIsClosed = true; + + return; + } + + if (mUpdateCnt == 1) + gApp.mSoundManager.PlaySound(Sounds.sBoing); + + float sizeTarget = Math.Min(0.5f + mUpdateCnt * 0.05f, 1.0f); + + float scaleDiff = sizeTarget - mScale; + mScaleVel += scaleDiff * 0.05f; + mScaleVel *= 0.80f; + mScale += mScaleVel; + + mSurprisePct = Math.Max(mSurprisePct - 0.005f, 0); + if (mUpdateCnt > 240) + { + mHeadRaise = Math.Max(mHeadRaise * 0.95f - 0.01f, 0); + } + + if (mEatPct == 0.0f) + { + if ((mUpdateCnt == 600) || (mUpdateCnt % 2400 == 0)) + { + mEatPct = 0.0001f; + } + } + else + { + let prev = mEatPct; + mEatPct += 0.004f; + if ((prev < 0.2f) && (mEatPct >= 0.2f)) + gApp.mSoundManager.PlaySound(Sounds.sEating); + + if (mEatPct >= 1.0f) + { + //Debug.WriteLine("Eat done"); + mEatPct = 0; + } + } + + if (mUpdateCnt % 2200 == 0) + { + mSurprisePct = 0.5f; + } + } + + public override void UpdateAll() + { + base.UpdateAll(); + + if (mWidgetWindow.IsKeyDown(.Control)) + { + for (int i < 2) + base.UpdateAll(); + } + } + + public override void MouseDown(float x, float y, int32 btn, int32 btnCount) + { + base.MouseDown(x, y, btn, btnCount); + } + + public override void KeyDown(KeyCode keyCode, bool isRepeat) + { + base.KeyDown(keyCode, isRepeat); + + if (keyCode == .Space) + { + gApp.mWantRehup = true; + } + } + + void UpdateComponent(Widget widget, int updateOffset, float centerX = 0.5f, float centerY = 0.5f, float speedMult = 1.0f) + { + float pct = Math.Clamp((mUpdateCnt - 50 - updateOffset) * 0.25f * speedMult, 0, 1.0f); + //float pct = Math.Clamp((mUpdateCnt - 50 - updateOffset) * 0.02f, 0, 1.0f); + if (pct == 0) + { + widget.SetVisible(false); + return; + } + widget.SetVisible(true); + if (pct == 1) + { + widget.ClearTransform(); + return; + } + + Matrix matrix = .IdentityMatrix; + matrix.Translate(-widget.mWidth * centerX, -widget.mHeight * centerY); + matrix.Scale(pct, pct); + matrix.Translate(widget.mWidth * centerX, widget.mHeight * centerY); + matrix.Translate(widget.mX, widget.mY); + widget.Transform = matrix; + } + + void ResizeComponents() + { + float headerWidth = mHeaderLabel.CalcWidth(); + mHeaderLabel.Resize(cBodyX + 375 - headerWidth/2, cBodyY + 60, headerWidth, 60); + UpdateComponent(mHeaderLabel, 0, 0.5f, 2.0f, 0.4f); + + mCloseButton.Resize(cBodyX + 660, cBodyY + 55, mCloseButton.mImage.mWidth, mCloseButton.mImage.mHeight); + UpdateComponent(mCloseButton, 5); + + mInstallForAllCheckbox.Resize(cBodyX + 120, cBodyY + 136, 48, 48); + UpdateComponent(mInstallForAllCheckbox, 10); + + mAddToStartCheckbox.Resize(cBodyX + 418, cBodyY + 136, 48, 48); + UpdateComponent(mAddToStartCheckbox, 12); + + mAddToDesktopCheckbox.Resize(cBodyX + 120, cBodyY + 190, 48, 48); + UpdateComponent(mAddToDesktopCheckbox, 14); + + mStartAfterCheckbox.Resize(cBodyX + 418, cBodyY + 190, 48, 48); + UpdateComponent(mStartAfterCheckbox, 16); + + if (!mInstalling) + { + mInstallPathBox.Resize(cBodyX + 122, cBodyY + 276, 508, Images.sTextBox.mHeight); + UpdateComponent(mInstallPathBox, 5, 0.1f, 0.5f, 0.4f); + } + + mCancelButton.Resize(cBodyX + 180, cBodyY + 320, mCancelButton.mImage.mWidth, mCancelButton.mImage.mHeight); + UpdateComponent(mCancelButton, 13, 0.5f, 0.2f); + + mInstallButton.Resize(cBodyX + 404, cBodyY + 320, mInstallButton.mImage.mWidth, mInstallButton.mImage.mHeight); + UpdateComponent(mInstallButton, 15, 0.5f, 0.2f); + } + + public override void Resize(float x, float y, float width, float height) + { + base.Resize(x, y, width, height); + ResizeComponents(); + } + } +} diff --git a/BeefTools/BeefInstall/StubUI/src/Program.bf b/BeefTools/BeefInstall/StubUI/src/Program.bf index c7d22d49..274a7834 100644 --- a/BeefTools/BeefInstall/StubUI/src/Program.bf +++ b/BeefTools/BeefInstall/StubUI/src/Program.bf @@ -15,14 +15,17 @@ namespace BIStubUI Debug.WriteLine("Deinitializing StubUI"); } - [Export] + [Export, CLink] public static void Start(BIApp.InstallFunc installFunc, BIApp.ProgressFunc progressFunc, BIApp.CancelFunc cancelFunc) { gApp = new BIApp(); gApp.mInstallFunc = installFunc; gApp.mProgressFunc = progressFunc; gApp.mCancelFunc = cancelFunc; + gApp.Init(); gApp.Run(); + gApp.Shutdown(); + DeleteAndNullify!(gApp); } public static void Hello() diff --git a/BeefTools/BeefInstall/StubUI/src/Resources.bf b/BeefTools/BeefInstall/StubUI/src/Resources.bf new file mode 100644 index 00000000..04e6083a --- /dev/null +++ b/BeefTools/BeefInstall/StubUI/src/Resources.bf @@ -0,0 +1,102 @@ +using System; +using Beefy.gfx; +using System.Collections.Generic; +using Beefy.sound; + +namespace BIStubUI +{ + class Images + { + public static Image sBody; + public static Image sHead; + public static Image sEyesOpen; + public static Image sEyesClosed; + public static Image sButton; + public static Image sButtonHi; + public static Image sSmButton; + public static Image sClose; + public static Image sCloseHi; + public static Image sChecked; + public static Image sUnchecked; + public static Image sTextBox; + public static Image sBrowse; + public static Image sBrowseDown; + public static Image sPBBarBottom; + public static Image sPBBarEmpty; + public static Image sPBBarHilite; + public static Image sPBFrameGlow; + public static Image sPBFrameTop; + + static List sImages = new .() ~ delete _; + + public static Result Load(String fileName, bool additive = false) + { + let image = Image.LoadFromFile(scope String(gApp.mInstallDir, "/", fileName), additive); + if (image == null) + { + delete image; + return .Err; + } + sImages.Add(image); + return image; + } + + public static void Dispose() + { + ClearAndDeleteItems(sImages); + } + + public static Result Init() + { + sBody = Try!(Load("images/body.png")); + sHead = Try!(Load("images/head.png")); + sEyesOpen = Try!(Load("images/eyesopen.png")); + sEyesClosed = Try!(Load("images/eyesclosed.png")); + sButton = Try!(Load("images/button.png")); + sButtonHi = Try!(Load("images/button_hi.png")); + sSmButton = Try!(Load("images/smbutton.png")); + sClose = Try!(Load("images/close.png")); + sCloseHi = Try!(Load("images/close_hi.png")); + sChecked = Try!(Load("images/checked.png")); + sUnchecked = Try!(Load("images/unchecked.png")); + sTextBox = Try!(Load("images/textbox.png")); + sBrowse = Try!(Load("images/browse.png")); + sBrowseDown = Try!(Load("images/browsedown.png")); + sPBBarBottom = Try!(Load("images/pb_barbottom.png")); + sPBBarEmpty = Try!(Load("images/pb_barempty.png")); + sPBBarHilite = Try!(Load("images/pb_barhilite.png", true)); + sPBFrameGlow = Try!(Load("images/pb_frameglow.png")); + sPBFrameTop = Try!(Load("images/pb_frametop.png")); + return .Ok; + } + } + + class Sounds + { + public static SoundSource sBoing; + public static SoundSource sEating; + public static SoundSource sButtonPress; + public static SoundSource sMouseOver; + public static SoundSource sAbort; + public static SoundSource sChecked; + + public static Result Load(String fileName) + { + let source = gApp.mSoundManager.LoadSound(scope String(gApp.mInstallDir, "/", fileName)); + if (source.IsInvalid) + return .Err; + return source; + } + + public static Result Init() + { + sBoing = Try!(Load("sounds/boing.wav")); + sEating = Try!(Load("sounds/eating.wav")); + sButtonPress = Try!(Load("sounds/buttonpress.wav")); + sMouseOver = Try!(Load("sounds/mouseover.wav")); + sAbort = Try!(Load("sounds/abort.wav")); + sChecked = Try!(Load("sounds/checked.wav")); + return .Ok; + } + } +} diff --git a/BeefySysLib/BFApp.cpp b/BeefySysLib/BFApp.cpp index 5a425ce6..3405502b 100644 --- a/BeefySysLib/BFApp.cpp +++ b/BeefySysLib/BFApp.cpp @@ -30,6 +30,7 @@ BFApp::BFApp() mCursor = CURSOR_POINTER; mInProcess = false; mUpdateCnt = 0; + mNumPhysUpdates = 0; mVSynched = true; mMaxUpdatesPerDraw = 60; // 8? @@ -49,7 +50,7 @@ BFApp::~BFApp() gBFApp = NULL; delete gPerfManager; for (auto window : mPendingWindowDeleteList) - delete window; + delete window; } void BFApp::Init() @@ -170,7 +171,10 @@ void BFApp::Process() mFrameTimeAcc = 0; } - updates = std::min(updates, mMaxUpdatesPerDraw); + // Compensate for "slow start" by limiting the number of catchup-updates we can do when starting the app + int maxUpdates = BF_MIN(mNumPhysUpdates + 1, mMaxUpdatesPerDraw); + + updates = BF_MIN(updates, maxUpdates); /*if (updates > 2) OutputDebugStrF("Updates: %d TickDelta: %d\n", updates, tickNow - mLastProcessTick);*/ @@ -198,8 +202,15 @@ void BFApp::Process() } #endif + if (updates > 0) + mNumPhysUpdates++; + for (int updateNum = 0; updateNum < updates; updateNum++) + { + if (!mRunning) + break; Update(updateNum == 0); + } if ((mRunning) && (updates > 0)) Draw(); diff --git a/BeefySysLib/BFApp.h b/BeefySysLib/BFApp.h index 9363e0fd..26a8536d 100644 --- a/BeefySysLib/BFApp.h +++ b/BeefySysLib/BFApp.h @@ -9,6 +9,7 @@ typedef void (*BFApp_UpdateFunc)(bool batchStart); typedef void (*BFApp_DrawFunc)(); class BFApp; +class BFSoundManager; class RenderDevice; class BFWindow; class FileStream; @@ -46,7 +47,7 @@ public: String mInstallDir; String mDataDir; bool mDrawEnabled; - float mRefreshRate; + float mRefreshRate; int mMaxUpdatesPerDraw; bool mInProcess; @@ -54,6 +55,7 @@ public: RenderDevice* mRenderDevice; int mSysDialogCnt; int mUpdateCnt; + int mNumPhysUpdates; bool mVSynched; bool mVSyncFailed; @@ -99,6 +101,8 @@ public: virtual BFSysBitmap* LoadSysBitmap(const wchar_t* fileName) = 0; virtual FileStream* OpenBinaryFile(const StringImpl& fileName); + + virtual BFSoundManager* GetSoundManager() { return NULL; } }; extern BFApp* gBFApp; diff --git a/BeefySysLib/BFSound.cpp b/BeefySysLib/BFSound.cpp new file mode 100644 index 00000000..09be6e3e --- /dev/null +++ b/BeefySysLib/BFSound.cpp @@ -0,0 +1,72 @@ +#include "BFSound.h" + +using namespace Beefy; + +////////////////////////////////////////////////////////////////////////// + +BF_EXPORT int32 BF_CALLTYPE BFSoundManager_LoadSound(BFSoundManager* manager, const char* fileName) +{ + return manager->LoadSound(fileName); +} + +BF_EXPORT BFSoundInstance* BF_CALLTYPE BFSoundManager_GetSoundInstance(BFSoundManager* manager, int32 sfxId) +{ + return manager->GetSoundInstance(sfxId); +} + +////////////////////////////////////////////////////////////////////////// + +BF_EXPORT void BF_CALLTYPE BFSoundInstance_Release(BFSoundInstance* instance) +{ + instance->Release(); +} + +BF_EXPORT void BF_CALLTYPE BFSoundInstance_SetBaseVolume(BFSoundInstance* instance, float theBaseVolume) +{ + instance->SetBaseVolume(theBaseVolume); +} + +BF_EXPORT void BF_CALLTYPE BFSoundInstance_SetBasePan(BFSoundInstance* instance, int theBasePan) +{ + instance->SetBasePan(theBasePan); +} + +BF_EXPORT void BF_CALLTYPE BFSoundInstance_SetVolume(BFSoundInstance* instance, float theVolume) +{ + instance->SetVolume(theVolume); +} + +BF_EXPORT void BF_CALLTYPE BFSoundInstance_SetPan(BFSoundInstance* instance, int thePosition) +{ + instance->SetPan(thePosition); +} + +BF_EXPORT void BF_CALLTYPE BFSoundInstance_AdjustPitch(BFSoundInstance* instance, float theNumSteps) +{ + instance->AdjustPitch(theNumSteps); +} + +BF_EXPORT bool BF_CALLTYPE BFSoundInstance_Play(BFSoundInstance* instance, bool looping, bool autoRelease) +{ + return instance->Play(looping, autoRelease); +} + +BF_EXPORT void BF_CALLTYPE BFSoundInstance_Stop(BFSoundInstance* instance) +{ + instance->Stop(); +} + +BF_EXPORT bool BF_CALLTYPE BFSoundInstance_IsPlaying(BFSoundInstance* instance) +{ + return instance->IsPlaying(); +} + +BF_EXPORT bool BF_CALLTYPE BFSoundInstance_IsReleased(BFSoundInstance* instance) +{ + return instance->IsReleased(); +} + +BF_EXPORT float BF_CALLTYPE BFSoundInstance_GetVolume(BFSoundInstance* instance) +{ + return (float)instance->GetVolume(); +} \ No newline at end of file diff --git a/BeefySysLib/BFSound.h b/BeefySysLib/BFSound.h new file mode 100644 index 00000000..3f7e8faf --- /dev/null +++ b/BeefySysLib/BFSound.h @@ -0,0 +1,61 @@ +#pragma once + +#include "Common.h" + +NS_BF_BEGIN; + +#define MAX_SOURCE_SOUNDS 1024 +#define MAX_CHANNELS 32 + +class BFSoundInstance +{ +public: + virtual ~BFSoundInstance() {} + + virtual void Release() = 0; + + virtual void SetBaseVolume(float theBaseVolume) = 0; + virtual void SetBasePan(int theBasePan) = 0; + + virtual void SetVolume(float theVolume) = 0; + virtual void SetPan(int thePosition) = 0; //-hundredth db to +hundredth db = left to right + virtual void AdjustPitch(float theNumSteps) = 0; + + virtual bool Play(bool looping, bool autoRelease) = 0; + virtual void Stop() = 0; + virtual bool IsPlaying() = 0; + virtual bool IsReleased() = 0; + virtual float GetVolume() = 0; +}; + +class BFSoundManager +{ +public: + virtual ~BFSoundManager() {} + + virtual bool Initialized() = 0; + + virtual bool LoadSound(unsigned int theSfxID, const StringImpl& theFilename) = 0; + virtual int LoadSound(const StringImpl& theFilename) = 0; + virtual void ReleaseSound(unsigned int theSfxID) = 0; + + virtual void SetVolume(float theVolume) = 0; + virtual bool SetBaseVolume(unsigned int theSfxID, float theBaseVolume) = 0; + virtual bool SetBasePan(unsigned int theSfxID, int theBasePan) = 0; + + virtual BFSoundInstance* GetSoundInstance(unsigned int theSfxID) = 0; + + virtual void ReleaseSounds() = 0; + virtual void ReleaseChannels() = 0; + + virtual float GetMasterVolume() = 0; + virtual void SetMasterVolume(float theVolume) = 0; + + virtual void Flush() = 0; + + virtual void StopAllSounds() = 0; + virtual int GetFreeSoundId() = 0; + virtual int GetNumSounds() = 0; +}; + +NS_BF_END; \ No newline at end of file diff --git a/BeefySysLib/BeefySysLib.cpp b/BeefySysLib/BeefySysLib.cpp index 1852b17e..4efc696d 100644 --- a/BeefySysLib/BeefySysLib.cpp +++ b/BeefySysLib/BeefySysLib.cpp @@ -255,6 +255,11 @@ BF_EXPORT void BF_CALLTYPE BFApp_RehupMouse() } +BF_EXPORT BFSoundManager* BF_CALLTYPE BFApp_GetSoundManager() +{ + return gBFApp->GetSoundManager(); +} + /// BF_EXPORT void BF_CALLTYPE BFWindow_SetCallbacks(BFWindow* window, BFWindow_MovedFunc movedFunc, BFWindow_CloseQueryFunc closeQueryFunc, BFWindow_ClosedFunc closedFunc, diff --git a/BeefySysLib/BeefySysLib.vcxproj b/BeefySysLib/BeefySysLib.vcxproj index 0fcb97a7..8ee40767 100644 --- a/BeefySysLib/BeefySysLib.vcxproj +++ b/BeefySysLib/BeefySysLib.vcxproj @@ -433,6 +433,7 @@ copy /y $(OutDir)$(TargetName).lib $(SolutionDir)\BeefLibs\Beefy2D\dist\ + @@ -485,6 +486,8 @@ copy /y $(OutDir)$(TargetName).lib $(SolutionDir)\BeefLibs\Beefy2D\dist\true + + false @@ -1940,6 +1943,7 @@ copy /y $(OutDir)$(TargetName).lib $(SolutionDir)\BeefLibs\Beefy2D\dist\ + @@ -1989,6 +1993,8 @@ copy /y $(OutDir)$(TargetName).lib $(SolutionDir)\BeefLibs\Beefy2D\dist\true + + false diff --git a/BeefySysLib/BeefySysLib.vcxproj.filters b/BeefySysLib/BeefySysLib.vcxproj.filters index c9db442b..05d0d12a 100644 --- a/BeefySysLib/BeefySysLib.vcxproj.filters +++ b/BeefySysLib/BeefySysLib.vcxproj.filters @@ -688,6 +688,15 @@ src\util + + src\platform\win + + + src\platform\win + + + src\platform + @@ -1038,6 +1047,15 @@ src\util + + src\platform\win + + + src\platform\win + + + src + diff --git a/BeefySysLib/FileStream.cpp b/BeefySysLib/FileStream.cpp index 42b41009..846b564a 100644 --- a/BeefySysLib/FileStream.cpp +++ b/BeefySysLib/FileStream.cpp @@ -29,6 +29,7 @@ bool FileStream::Open(const StringImpl& filePath, const char* fopenOptions) #else mFP = fopen(filePath.c_str(), fopenOptions); #endif + mReadPastEnd = false; return mFP != NULL; } diff --git a/BeefySysLib/gfx/RenderDevice.cpp b/BeefySysLib/gfx/RenderDevice.cpp index 3b404244..bf7da085 100644 --- a/BeefySysLib/gfx/RenderDevice.cpp +++ b/BeefySysLib/gfx/RenderDevice.cpp @@ -101,10 +101,22 @@ VertexDefinition* Beefy::RenderDevice::CreateVertexDefinition(VertexDefData* ele Texture* RenderDevice::LoadTexture(const StringImpl& fileName, int flags) { int dotPos = (int)fileName.LastIndexOf('.'); - String ext = fileName.Substring(dotPos); + String ext; + if (dotPos != -1) + ext = fileName.Substring(dotPos); ImageData* imageData = NULL; - if (ext == ".tga") + bool handled = false; + bool failed = false; + + if (fileName == "!white") + { + imageData = new ImageData(); + imageData->CreateNew(1, 1, true); + imageData->mBits[0] = 0xFFFFFFFF; + handled = true; + } + else if (ext == ".tga") imageData = new TGAData(); else if (ext == ".png") imageData = new PNGData(); @@ -117,22 +129,20 @@ Texture* RenderDevice::LoadTexture(const StringImpl& fileName, int flags) BF_FATAL("Unknown texture format"); return NULL; // Unknown format } - - imageData->mWantsAlphaPremultiplied = (flags & TextureFlag_NoPremult) == 0; + + if (!handled) + { + imageData->mWantsAlphaPremultiplied = (flags & TextureFlag_NoPremult) == 0; + if (!imageData->LoadFromFile(fileName)) + { + failed = true; + BF_FATAL("Failed to load image"); + } + } Texture* aTexture = NULL; - if (imageData->LoadFromFile(fileName)) - { -// if ((int)fileName.IndexOf("fft") != -1) -// { -// BFIData bFIData; -// bFIData.Compress(imageData); -// } - + if (!failed) aTexture = LoadTexture(imageData, flags); - } - else - BF_FATAL("Failed to load image"); delete imageData; return aTexture; diff --git a/BeefySysLib/platform/win/DSoundInstance.cpp b/BeefySysLib/platform/win/DSoundInstance.cpp new file mode 100644 index 00000000..d89419f8 --- /dev/null +++ b/BeefySysLib/platform/win/DSoundInstance.cpp @@ -0,0 +1,177 @@ +#include "DSoundInstance.h" +#include "DSoundManager.h" + +using namespace Beefy; + +DSoundInstance::DSoundInstance(DSoundManager* theSoundManager, LPDIRECTSOUNDBUFFER theSourceSound) +{ + mSoundManagerP = theSoundManager; + mReleased = false; + mAutoRelease = false; + mHasPlayed = false; + mSourceSoundBuffer = theSourceSound; + mSoundBuffer = NULL; + + mBaseVolume = 1.0; + mBasePan = 0; + + mVolume = 1.0; + mPan = 0; + + mDefaultFrequency = 44100; + + HRESULT hr; + + if (mSourceSoundBuffer != NULL) + { + hr=mSoundManagerP->mDirectSound->DuplicateSoundBuffer(mSourceSoundBuffer, &mSoundBuffer); + if (hr!=DS_OK) + { + switch (hr) + { + case DSERR_ALLOCATED: MessageBoxA(0,"DSERR_ALLOCATED","Hey",MB_OK);break; + case DSERR_INVALIDCALL: MessageBoxA(0,"DSERR_INVALIDCALL","Hey",MB_OK);break; + case DSERR_INVALIDPARAM: MessageBoxA(0,"DSERR_INVALIDPARAM","Hey",MB_OK);break; + case DSERR_OUTOFMEMORY: MessageBoxA(0,"DSERR_OUTOFMEMORY","Hey",MB_OK);break; + case DSERR_UNINITIALIZED: MessageBoxA(0,"DSERR_UNINITIALIZED","Hey",MB_OK);break; + } + exit(0); + } + + mSoundBuffer->GetFrequency(&mDefaultFrequency); + } + + RehupVolume(); +} + +DSoundInstance::~DSoundInstance() +{ + if (mSoundBuffer != NULL) + mSoundBuffer->Release(); +} + +void DSoundInstance::RehupVolume() +{ + if (mSoundBuffer != NULL) + mSoundBuffer->SetVolume(mSoundManagerP->VolumeToDB(mBaseVolume * mVolume * mSoundManagerP->mMasterVolume)); +} + +void DSoundInstance::RehupPan() +{ + if (mSoundBuffer != NULL) + mSoundBuffer->SetPan(mBasePan + mPan); +} + +void DSoundInstance::Release() +{ + Stop(); + mReleased = true; +} + +void DSoundInstance::SetVolume(float theVolume) // 0 = max +{ + mVolume = theVolume; + RehupVolume(); +} + +void DSoundInstance::SetPan(int thePosition) //-db to =db = left to right +{ + mPan = thePosition; + RehupPan(); +} + +void DSoundInstance::SetBaseVolume(float theBaseVolume) +{ + mBaseVolume = theBaseVolume; + RehupVolume(); +} + +void DSoundInstance::SetBasePan(int theBasePan) +{ + mBasePan = theBasePan; + RehupPan(); +} + +bool DSoundInstance::Play(bool looping, bool autoRelease) +{ + Stop(); + + mHasPlayed = true; + mAutoRelease = autoRelease; + + if (mSoundBuffer == NULL) + { + return false; + } + + if (looping) + { + if (mSoundBuffer->Play(0, 0, DSBPLAY_LOOPING) != DS_OK) + return false; + } + else + { + if (mSoundBuffer->Play(0, 0, 0) != DS_OK) + { + return false; + } + } + + return true; +} + +void DSoundInstance::Stop() +{ + if (mSoundBuffer != NULL) + { + mSoundBuffer->Stop(); + mSoundBuffer->SetCurrentPosition(0); + mAutoRelease = false; + } +} + +//#include "DirectXErrorString.h" +void DSoundInstance::AdjustPitch(float theNumSteps) +{ + if (mSoundBuffer != NULL) + { + float aFrequencyMult = powf(1.0594630943592952645618252949463f, theNumSteps); + float aNewFrequency = mDefaultFrequency*aFrequencyMult; + if (aNewFrequency < DSBFREQUENCY_MIN) + aNewFrequency = DSBFREQUENCY_MIN; + if (aNewFrequency > DSBFREQUENCY_MAX) + aNewFrequency = DSBFREQUENCY_MAX; + + mSoundBuffer->SetFrequency((DWORD)aNewFrequency); + } +} + +bool DSoundInstance::IsPlaying() +{ + if (!mHasPlayed) + return false; + + if (mSoundBuffer == NULL) + return false; + + DWORD aStatus; + if (mSoundBuffer->GetStatus(&aStatus) == DS_OK) + // Has the sound stopped? + return ((aStatus & DSBSTATUS_PLAYING) != 0); + else + return false; +} + +bool DSoundInstance::IsReleased() +{ + if ((!mReleased) && (mAutoRelease) && (mHasPlayed) && (!IsPlaying())) + Release(); + + return mReleased; +} + +float DSoundInstance::GetVolume() +{ + return mVolume; +} + diff --git a/BeefySysLib/platform/win/DSoundInstance.h b/BeefySysLib/platform/win/DSoundInstance.h new file mode 100644 index 00000000..82bda9a3 --- /dev/null +++ b/BeefySysLib/platform/win/DSoundInstance.h @@ -0,0 +1,60 @@ +#ifndef __DSOUNDINSTANCE_H__ +#define __DSOUNDINSTANCE_H__ + +#include +#include "BFSound.h" + +//#define _LPCWAVEFORMATEX_DEFINED + +namespace Beefy +{ + +class DSoundManager; + +class DSoundInstance : public BFSoundInstance +{ + friend class DSoundManager; + +protected: + DSoundManager* mSoundManagerP; + LPDIRECTSOUNDBUFFER mSourceSoundBuffer; + LPDIRECTSOUNDBUFFER mSoundBuffer; + bool mAutoRelease; + bool mHasPlayed; + bool mReleased; + + int mBasePan; + float mBaseVolume; + + int mPan; + float mVolume; + + DWORD mDefaultFrequency; + +protected: + void RehupVolume(); + void RehupPan(); + +public: + DSoundInstance(DSoundManager* theSoundManager, LPDIRECTSOUNDBUFFER theSourceSound); + virtual ~DSoundInstance(); + virtual void Release() override; + + virtual void SetBaseVolume(float theBaseVolume) override; + virtual void SetBasePan(int theBasePan) override; + + virtual void SetVolume(float theVolume) override; + virtual void SetPan(int thePosition) override; //-hundredth db to +hundredth db = left to right + virtual void AdjustPitch(float theNumSteps) override; + + virtual bool Play(bool looping, bool autoRelease) override; + virtual void Stop() override; + virtual bool IsPlaying() override; + virtual bool IsReleased() override; + virtual float GetVolume() override; + +}; + +} + +#endif //__DSOUNDINSTANCE_H__ \ No newline at end of file diff --git a/BeefySysLib/platform/win/DSoundManager.cpp b/BeefySysLib/platform/win/DSoundManager.cpp new file mode 100644 index 00000000..5912d015 --- /dev/null +++ b/BeefySysLib/platform/win/DSoundManager.cpp @@ -0,0 +1,535 @@ +#pragma warning(disable:4996) + +#include "DSoundManager.h" +#include +#include +#include "DSoundInstance.h" +#include + +using namespace Beefy; + +static HMODULE gDSoundDLL; + +#pragma comment(lib, "dsound.lib") + +#define SOUND_FLAGS (DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_STATIC | DSBCAPS_LOCSOFTWARE | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLFREQUENCY) +DSoundManager::DSoundManager(HWND theHWnd) +{ + mLastReleaseTick = 0; + mPrimaryBuffer = NULL; + + int i; + + for (i = 0; i < MAX_SOURCE_SOUNDS; i++) + { + mSourceSounds[i] = NULL; + mBaseVolumes[i] = 1; + mBasePans[i] = 0; + } + + for (i = 0; i < MAX_CHANNELS; i++) + mPlayingSounds[i] = NULL; + + mDirectSound = NULL; + + mMasterVolume = 1.0; + + //typedef HRESULT (WINAPI *DirectSoundCreateFunc)(LPCGUID lpcGuid, LPDIRECTSOUND * ppDS, LPUNKNOWN pUnkOuter); + //DirectSoundCreateFunc aDirectSoundCreateFunc = (DirectSoundCreateFunc)GetProcAddress(gDSoundDLL,"DirectSoundCreate"); + + // Seems crazy but this was even suggested in MSDN docs for windowless applications + if (theHWnd == NULL) + theHWnd = ::GetDesktopWindow(); + + //if (aDirectSoundCreateFunc != NULL && aDirectSoundCreateFunc(NULL, &mDirectSound, NULL) == DS_OK) + + if (DirectSoundCreate(NULL, &mDirectSound, NULL) == DS_OK) + { + bool handled = false; + + if (theHWnd != NULL) + { + HRESULT aResult = mDirectSound->SetCooperativeLevel(theHWnd, DSSCL_PRIORITY); + if (SUCCEEDED(aResult)) + { + // Set primary buffer to 16-bit 44.1Khz + WAVEFORMATEX aWaveFormat; + DSBUFFERDESC aBufferDesc; + + // Set up wave format structure. + int aBitCount = 16; + int aChannelCount = 2; + int aSampleRate = 44100; + + // Set up wave format structure. + memset(&aWaveFormat, 0, sizeof(WAVEFORMATEX)); + aWaveFormat.cbSize = sizeof(WAVEFORMATEX); + aWaveFormat.wFormatTag = WAVE_FORMAT_PCM; + aWaveFormat.nChannels = aChannelCount; + aWaveFormat.nSamplesPerSec = aSampleRate; + aWaveFormat.nBlockAlign = aChannelCount * aBitCount / 8; + aWaveFormat.nAvgBytesPerSec = + aWaveFormat.nSamplesPerSec * aWaveFormat.nBlockAlign; + aWaveFormat.wBitsPerSample = aBitCount; + + // Set up DSBUFFERDESC structure. + memset(&aBufferDesc, 0, sizeof(DSBUFFERDESC)); // Zero it out. + aBufferDesc.dwSize = sizeof(DSBUFFERDESC1); + aBufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;//| DSBCAPS_CTRL3D; // Need default controls (pan, volume, frequency). + aBufferDesc.dwBufferBytes = 0; + aBufferDesc.lpwfxFormat = NULL;//(LPWAVEFORMATEX)&aWaveFormat; + + HRESULT aResult = mDirectSound->CreateSoundBuffer(&aBufferDesc, &mPrimaryBuffer, NULL); + if (aResult == DS_OK) + { + aResult = mPrimaryBuffer->SetFormat(&aWaveFormat); + } + handled = true; + } + } + + if (!handled) + { + HRESULT aResult = mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_NORMAL); + } + } +} + +DSoundManager::~DSoundManager() +{ + ReleaseChannels(); + ReleaseSounds(); + + if (mPrimaryBuffer) + mPrimaryBuffer->Release(); + + if (mDirectSound != NULL) + { + mDirectSound->Release(); + } +} + +int DSoundManager::FindFreeChannel() +{ + DWORD aTick = GetTickCount(); + if (aTick-mLastReleaseTick > 1000) + { + ReleaseFreeChannels(); + mLastReleaseTick = aTick; + } + + for (int i = 0; i < MAX_CHANNELS; i++) + { + if (mPlayingSounds[i] == NULL) + return i; + + if (mPlayingSounds[i]->IsReleased()) + { + delete mPlayingSounds[i]; + mPlayingSounds[i] = NULL; + return i; + } + } + + return -1; +} + +bool DSoundManager::Initialized() +{ +/* + if (mDirectSound!=NULL) + { + mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_NORMAL); + } +*/ + + return (mDirectSound != NULL); +} + +int DSoundManager::VolumeToDB(float theVolume) +{ + int aVol = (int) ((log10(1 + theVolume*9) - 1.0) * 2333); + if (aVol < -2000) + aVol = -10000; + + return aVol; +} + +void DSoundManager::SetVolume(float theVolume) +{ + mMasterVolume = theVolume; + + for (int i = 0; i < MAX_CHANNELS; i++) + if (mPlayingSounds[i] != NULL) + mPlayingSounds[i]->RehupVolume(); +} + +bool DSoundManager::LoadWAVSound(unsigned int theSfxID, const StringImpl& theFilename) +{ + int aDataSize; + + FILE* fp; + + fp = fopen(theFilename.c_str(), "rb"); + + if (fp <= 0) + return false; + + char aChunkType[5]; + aChunkType[4] = '\0'; + uint32 aChunkSize; + + fread(aChunkType, 1, 4, fp); + if (!strcmp(aChunkType, "RIFF") == 0) + return false; + fread(&aChunkSize, 4, 1, fp); + + fread(aChunkType, 1, 4, fp); + if (!strcmp(aChunkType, "WAVE") == 0) + return false; + + uint16 aBitCount = 16; + uint16 aChannelCount = 1; + uint32 aSampleRate = 22050; + uint8 anXor = 0; + + while (!feof(fp)) + { + fread(aChunkType, 1, 4, fp); + if (fread(&aChunkSize, 4, 1, fp) == 0) + return false; + + int aCurPos = ftell(fp); + + if (strcmp(aChunkType, "fmt ") == 0) + { + uint16 aFormatTag; + uint32 aBytesPerSec; + uint16 aBlockAlign; + + fread(&aFormatTag, 2, 1, fp); + fread(&aChannelCount, 2, 1, fp); + fread(&aSampleRate, 4, 1, fp); + fread(&aBytesPerSec, 4, 1, fp); + fread(&aBlockAlign, 2, 1, fp); + fread(&aBitCount, 2, 1, fp); + + if (aFormatTag != 1) + return false; + } + else if (strcmp(aChunkType, "data") == 0) + { + aDataSize = aChunkSize; + + mSourceDataSizes[theSfxID] = aChunkSize; + + PCMWAVEFORMAT aWaveFormat; + DSBUFFERDESC aBufferDesc; + + // Set up wave format structure. + memset(&aWaveFormat, 0, sizeof(PCMWAVEFORMAT)); + aWaveFormat.wf.wFormatTag = WAVE_FORMAT_PCM; + aWaveFormat.wf.nChannels = aChannelCount; + aWaveFormat.wf.nSamplesPerSec = aSampleRate; + aWaveFormat.wf.nBlockAlign = aChannelCount*aBitCount/8; + aWaveFormat.wf.nAvgBytesPerSec = + aWaveFormat.wf.nSamplesPerSec * aWaveFormat.wf.nBlockAlign; + aWaveFormat.wBitsPerSample = aBitCount; + // Set up DSBUFFERDESC structure. + memset(&aBufferDesc, 0, sizeof(DSBUFFERDESC)); // Zero it out. + aBufferDesc.dwSize = sizeof(DSBUFFERDESC); + //aBufferDesc.dwFlags = DSBCAPS_CTRL3D; + aBufferDesc.dwFlags = SOUND_FLAGS; //DSBCAPS_CTRLDEFAULT; + + //aBufferDesc.dwFlags = 0; + + aBufferDesc.dwBufferBytes = aDataSize; + aBufferDesc.lpwfxFormat = (LPWAVEFORMATEX)&aWaveFormat; + + if (mDirectSound->CreateSoundBuffer(&aBufferDesc, &mSourceSounds[theSfxID], NULL) != DS_OK) + { + fclose(fp); + return false; + } + + + void* lpvPtr; + DWORD dwBytes; + if (mSourceSounds[theSfxID]->Lock(0, aDataSize, &lpvPtr, &dwBytes, NULL, NULL, 0) != DS_OK) + { + fclose(fp); + return false; + } + + int aReadSize = (int)fread(lpvPtr, 1, aDataSize, fp); + fclose(fp); + + for (int i = 0; i < aDataSize; i++) + ((uint8*) lpvPtr)[i] ^= anXor; + + if (mSourceSounds[theSfxID]->Unlock(lpvPtr, dwBytes, NULL, NULL) != DS_OK) + return false; + + if (aReadSize != aDataSize) + return false; + + return true; + } + + fseek(fp, aCurPos+aChunkSize, SEEK_SET); + } + + return false; +} + +bool DSoundManager::LoadSound(unsigned int theSfxID, const StringImpl& theFilename) +{ + if ((theSfxID < 0) || (theSfxID >= MAX_SOURCE_SOUNDS)) + return false; + + ReleaseSound(theSfxID); + + if (!mDirectSound) + return true; // sounds just won't play, but this is not treated as a failure condition + + mSourceFileNames[theSfxID] = theFilename; + + StringImpl aFilename = theFilename; + + if (aFilename.EndsWith(".wav", StringImpl::CompareKind_OrdinalIgnoreCase)) + { + if (LoadWAVSound(theSfxID, aFilename)) + return true; + } + + return false; +} + +int DSoundManager::LoadSound(const StringImpl& theFilename) +{ + int i; + for (i = 0; i < MAX_SOURCE_SOUNDS; i++) + if (mSourceFileNames[i] == theFilename) + return i; + + for (i = MAX_SOURCE_SOUNDS-1; i >= 0; i--) + { + if (mSourceSounds[i] == NULL) + { + if (!LoadSound(i, theFilename)) + return -1; + else + return i; + } + } + + return -1; +} + +void DSoundManager::ReleaseSound(unsigned int theSfxID) +{ + if (mSourceSounds[theSfxID] != NULL) + { + mSourceSounds[theSfxID]->Release(); + mSourceSounds[theSfxID] = NULL; + mSourceFileNames[theSfxID] = ""; + } +} + +int DSoundManager::GetFreeSoundId() +{ + for (int i=0; i= MAX_SOURCE_SOUNDS)) + return false; + + mBaseVolumes[theSfxID] = theBaseVolume; + return true; +} + +bool DSoundManager::SetBasePan(unsigned int theSfxID, int theBasePan) +{ + if ((theSfxID < 0) || (theSfxID >= MAX_SOURCE_SOUNDS)) + return false; + + mBasePans[theSfxID] = theBasePan; + return true; +} + +BFSoundInstance* DSoundManager::GetSoundInstance(unsigned int theSfxID) +{ + if (theSfxID > MAX_SOURCE_SOUNDS) + return NULL; + + int aFreeChannel = FindFreeChannel(); + if (aFreeChannel < 0) + return NULL; + + if (mDirectSound==NULL) + { + mPlayingSounds[aFreeChannel] = new DSoundInstance(this, NULL); + } + else + { + if (mSourceSounds[theSfxID] == NULL) + return NULL; + + mPlayingSounds[aFreeChannel] = new DSoundInstance(this, mSourceSounds[theSfxID]); + } + + mPlayingSounds[aFreeChannel]->SetBasePan(mBasePans[theSfxID]); + mPlayingSounds[aFreeChannel]->SetBaseVolume(mBaseVolumes[theSfxID]); + + return mPlayingSounds[aFreeChannel]; +} + +void DSoundManager::ReleaseSounds() +{ + for (int i = 0; i < MAX_SOURCE_SOUNDS; i++) + if (mSourceSounds[i] != NULL) + { + mSourceSounds[i]->Release(); + mSourceSounds[i] = NULL; + } +} + +void DSoundManager::ReleaseChannels() +{ + for (int i = 0; i < MAX_CHANNELS; i++) + if (mPlayingSounds[i] != NULL) + { + delete mPlayingSounds[i]; + mPlayingSounds[i] = NULL; + } +} + +void DSoundManager::ReleaseFreeChannels() +{ + for (int i = 0; i < MAX_CHANNELS; i++) + if (mPlayingSounds[i] != NULL && mPlayingSounds[i]->IsReleased()) + { + delete mPlayingSounds[i]; + mPlayingSounds[i] = NULL; + } +} + +void DSoundManager::StopAllSounds() +{ + for (int i = 0; i < MAX_CHANNELS; i++) + if (mPlayingSounds[i] != NULL) + { + bool isAutoRelease = mPlayingSounds[i]->mAutoRelease; + mPlayingSounds[i]->Stop(); + mPlayingSounds[i]->mAutoRelease = isAutoRelease; + } +} + + +float DSoundManager::GetMasterVolume() +{ + MIXERCONTROLDETAILS mcd; + MIXERCONTROLDETAILS_UNSIGNED mxcd_u; + MIXERLINECONTROLS mxlc; + MIXERCONTROL mlct; + MIXERLINE mixerLine; + HMIXER hmx; + MIXERCAPS pmxcaps; + + mixerOpen((HMIXER*) &hmx, 0, 0, 0, MIXER_OBJECTF_MIXER); + mixerGetDevCaps(0, &pmxcaps, sizeof(pmxcaps)); + + mxlc.cbStruct = sizeof(mxlc); + mxlc.cbmxctrl = sizeof(mlct); + mxlc.pamxctrl = &mlct; + mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; + mixerLine.cbStruct = sizeof(mixerLine); + mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT; + mixerGetLineInfo((HMIXEROBJ) hmx, &mixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE); + mxlc.dwLineID = mixerLine.dwLineID; + mixerGetLineControls((HMIXEROBJ) hmx, &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE); + + mcd.cbStruct = sizeof(mcd); + mcd.dwControlID = mlct.dwControlID; + mcd.cChannels = 1; + mcd.cMultipleItems = 0; + mcd.cbDetails = sizeof(mxcd_u); + mcd.paDetails = &mxcd_u; + + mixerGetControlDetails((HMIXEROBJ) hmx, &mcd, 0L); + + mixerClose(hmx); + + return mxcd_u.dwValue / (float) 0xFFFF; +} + +void DSoundManager::SetMasterVolume(float theVolume) +{ + MIXERCONTROLDETAILS mcd; + MIXERCONTROLDETAILS_UNSIGNED mxcd_u; + MIXERLINECONTROLS mxlc; + MIXERCONTROL mlct; + MIXERLINE mixerLine; + HMIXER hmx; + MIXERCAPS pmxcaps; + + mixerOpen((HMIXER*) &hmx, 0, 0, 0, MIXER_OBJECTF_MIXER); + mixerGetDevCaps(0, &pmxcaps, sizeof(pmxcaps)); + + mxlc.cbStruct = sizeof(mxlc); + mxlc.cbmxctrl = sizeof(mlct); + mxlc.pamxctrl = &mlct; + mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; + mixerLine.cbStruct = sizeof(mixerLine); + mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT; + mixerGetLineInfo((HMIXEROBJ) hmx, &mixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE); + mxlc.dwLineID = mixerLine.dwLineID; + mixerGetLineControls((HMIXEROBJ) hmx, &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE); + + mcd.cbStruct = sizeof(mcd); + mcd.dwControlID = mlct.dwControlID; + mcd.cChannels = 1; + mcd.cMultipleItems = 0; + mcd.cbDetails = sizeof(mxcd_u); + mcd.paDetails = &mxcd_u; + + mxcd_u.dwValue = (int) (0xFFFF * theVolume); + mixerSetControlDetails((HMIXEROBJ) hmx, &mcd, 0L); + + mixerClose(hmx); +} + +void DSoundManager::Flush() +{ +} + +void DSoundManager::SetCooperativeWindow(HWND theHWnd, bool isWindowed) +{ + if (mDirectSound != NULL) + mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_NORMAL); +/* + if (isWindowed==true) mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_NORMAL); + else mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_EXCLUSIVE); + */ +} +#undef SOUND_FLAGS diff --git a/BeefySysLib/platform/win/DSoundManager.h b/BeefySysLib/platform/win/DSoundManager.h new file mode 100644 index 00000000..444bbd47 --- /dev/null +++ b/BeefySysLib/platform/win/DSoundManager.h @@ -0,0 +1,68 @@ +#ifndef __DSOUNDMANAGER_H__ +#define __DSOUNDMANAGER_H__ + +#include +#include "BFSound.h" + +namespace Beefy +{ + +class DSoundInstance; + +class DSoundManager : public BFSoundManager +{ + friend class DSoundInstance; + friend class DSoundMusicInterface; + +protected: + LPDIRECTSOUNDBUFFER mSourceSounds[MAX_SOURCE_SOUNDS]; + String mSourceFileNames[MAX_SOURCE_SOUNDS]; + LPDIRECTSOUNDBUFFER mPrimaryBuffer; + int32 mSourceDataSizes[MAX_SOURCE_SOUNDS]; + float mBaseVolumes[MAX_SOURCE_SOUNDS]; + int mBasePans[MAX_SOURCE_SOUNDS]; + DSoundInstance* mPlayingSounds[MAX_CHANNELS]; + float mMasterVolume; + DWORD mLastReleaseTick; + +protected: + int FindFreeChannel(); + int VolumeToDB(float theVolume); + bool LoadWAVSound(unsigned int theSfxID, const StringImpl& theFilename); + void ReleaseFreeChannels(); + +public: + LPDIRECTSOUND mDirectSound; + + DSoundManager(HWND theHWnd); + virtual ~DSoundManager(); + + virtual bool Initialized() override; + + virtual bool LoadSound(unsigned int theSfxID, const StringImpl& theFilename) override; + virtual int LoadSound(const StringImpl& theFilename) override; + virtual void ReleaseSound(unsigned int theSfxID) override; + + virtual void SetVolume(float theVolume) override; + virtual bool SetBaseVolume(unsigned int theSfxID, float theBaseVolume) override; + virtual bool SetBasePan(unsigned int theSfxID, int theBasePan) override; + + virtual BFSoundInstance* GetSoundInstance(unsigned int theSfxID); + + virtual void ReleaseSounds() override; + virtual void ReleaseChannels() override; + + virtual float GetMasterVolume() override; + virtual void SetMasterVolume(float theVolume) override; + + virtual void Flush() override; + + virtual void SetCooperativeWindow(HWND theHWnd, bool isWindowed); + virtual void StopAllSounds() override; + virtual int GetFreeSoundId() override; + virtual int GetNumSounds() override; +}; + +} + +#endif //__DSOUNDMANAGER_H__ \ No newline at end of file diff --git a/BeefySysLib/platform/win/WinBFApp.cpp b/BeefySysLib/platform/win/WinBFApp.cpp index 5fac6659..c2c1d976 100644 --- a/BeefySysLib/platform/win/WinBFApp.cpp +++ b/BeefySysLib/platform/win/WinBFApp.cpp @@ -1,7 +1,9 @@ +#include #include "WinBFApp.h" #include "DXRenderDevice.h" #include #include "../../util/BeefPerf.h" +#include "DSoundManager.h" #include #pragma comment(lib, "dwmapi.lib") @@ -130,9 +132,9 @@ WinBFWindow::WinBFWindow(BFWindow* parent, const StringImpl& title, int x, int y ::SystemParametersInfo(SPI_GETWORKAREA, NULL, &desktopRect, NULL); if (x + width >= desktopRect.right) - x = std::max((int)desktopRect.left, requestedX - width); + x = BF_MAX((int)desktopRect.left, requestedX - width); if (y + height >= desktopRect.bottom) - y = std::max((int)desktopRect.top, requestedY - height); + y = BF_MAX((int)desktopRect.top, requestedY - height); } mFlags = windowFlags; @@ -1037,11 +1039,13 @@ WinBFApp::WinBFApp() mDataDir = mInstallDir; mInMsgProc = false; + mDSoundManager = NULL; } WinBFApp::~WinBFApp() { delete mRenderDevice; + delete mDSoundManager; } void WinBFApp::Init() @@ -1670,6 +1674,13 @@ BFSysBitmap* WinBFApp::LoadSysBitmap(const WCHAR* fileName) return NULL; } +BFSoundManager* WinBFApp::GetSoundManager() +{ + if (mDSoundManager == NULL) + mDSoundManager = new DSoundManager(NULL); + return mDSoundManager; +} + void WinBFWindow::ModalsRemoved() { ::EnableWindow(mHWnd, TRUE); diff --git a/BeefySysLib/platform/win/WinBFApp.h b/BeefySysLib/platform/win/WinBFApp.h index a9f193b3..4a9cac8b 100644 --- a/BeefySysLib/platform/win/WinBFApp.h +++ b/BeefySysLib/platform/win/WinBFApp.h @@ -9,6 +9,7 @@ NS_BF_BEGIN; class RenderDevice; +class DSoundManager; typedef Dictionary PtrToHGlobalMap; typedef Dictionary StringToUIntMap; @@ -87,6 +88,7 @@ public: bool mInMsgProc; PtrToHGlobalMap mLockedHGlobalMap; StringToUIntMap mClipboardFormatMap; + DSoundManager* mDSoundManager; protected: virtual void Draw() override; @@ -112,6 +114,8 @@ public: virtual void RehupMouse() override; virtual BFSysBitmap* LoadSysBitmap(const WCHAR* fileName) override; + + virtual BFSoundManager* GetSoundManager() override; }; NS_BF_END; diff --git a/BeefySysLib/util/BeefPerf.cpp b/BeefySysLib/util/BeefPerf.cpp index 7fdcf06a..b7e90574 100644 --- a/BeefySysLib/util/BeefPerf.cpp +++ b/BeefySysLib/util/BeefPerf.cpp @@ -31,6 +31,25 @@ USING_NS_BF; #define BP_ABI_VERSION 2 BpManager* BpManager::sBpManager = NULL; +static bool gOwnsBpManager = false; +static BpThreadInfo sFakeThreadInfo; + +struct BpManagerOwner +{ + BpManager* mOwnedManager; + bool mDidShutdown; + BpManagerOwner() + { + mOwnedManager = NULL; + mDidShutdown = false; + } + ~BpManagerOwner() + { + mDidShutdown = true; + delete mOwnedManager; + } +}; +static BpManagerOwner gBpManagerOwner; BF_TLS_DECLSPEC BpThreadInfo* Beefy::BpManager::sBpThreadInfo; @@ -314,7 +333,7 @@ const char* BpCmdTarget::ToStrPtr(const char* str) return str; } -#define BPCMD_PREPARE if (!BpManager::Get()->mCollectData) return; AutoCrit autoCrit(mCritSect) +#define BPCMD_PREPARE if ((gBpManagerOwner.mDidShutdown) || (!BpManager::Get()->mCollectData)) return; AutoCrit autoCrit(mCritSect) #define GET_FROM(ptr, T) *((T*)(ptr += sizeof(T)) - 1) @@ -1527,6 +1546,8 @@ BpThreadInfo* BpManager::GetCurThreadInfo() BpThreadInfo* threadInfo = sBpThreadInfo; if (threadInfo == NULL) { + if (gBpManagerOwner.mDidShutdown) + return &sFakeThreadInfo; threadInfo = Get()->SlowGetCurThreadInfo(); sBpThreadInfo = threadInfo; } @@ -1581,13 +1602,14 @@ BpManager* BpManager::Get() BpSharedMemory* sharedMem = (BpSharedMemory*)MapViewOfFile(fileMapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(BpSharedMemory)); if (sharedMem != NULL) { - sBpManager = new BpManager(); + sBpManager = new BpManager(); sBpManager->mMutex = mutex; - sBpManager->mSharedMemoryFile = sharedMem; + sBpManager->mSharedMemoryFile = fileMapping; sharedMem->mBpManager = sBpManager; sharedMem->mABIVersion = BP_ABI_VERSION; ::UnmapViewOfFile(sharedMem); ::ReleaseMutex(mutex); + gBpManagerOwner.mOwnedManager = sBpManager; } else { @@ -1609,6 +1631,7 @@ BpManager* BpManager::Get() if (sBpManager == NULL) { sBpManager = new BpManager(); + gBpManagerOwner.mOwnedManager = sBpManager; } return sBpManager; } diff --git a/IDE/BeefProj.toml b/IDE/BeefProj.toml index c2ab63f0..4883d16c 100644 --- a/IDE/BeefProj.toml +++ b/IDE/BeefProj.toml @@ -27,7 +27,7 @@ TargetDirectory = "$(WorkspaceDir)/dist" TargetName = "BeefIDE_d" OtherLinkFlags = "$(LinkFlags) Comdlg32.lib kernel32.lib user32.lib advapi32.lib shell32.lib IDEHelper64_d.lib" CLibType = "Dynamic" -DebugCommandArguments = "-test=scripts\\Minidump.txt -testNoExit" +DebugCommandArguments = "-proddir=C:\\Beef\\IDE\\Tests\\Test1 -platform=Win32 -test=scripts\\Break.txt -testNoExit" DebugWorkingDirectory = "c:\\Beef\\IDE\\Tests\\EmptyTest" EnvironmentVars = ["_NO_DEBUG_HEAP=1"] diff --git a/IDE/Tests/Test1/scripts/HotSwap_LocateSym01.txt b/IDE/Tests/Test1/scripts/HotSwap_LocateSym01.txt new file mode 100644 index 00000000..1f31af90 --- /dev/null +++ b/IDE/Tests/Test1/scripts/HotSwap_LocateSym01.txt @@ -0,0 +1,8 @@ +ShowFile("src/HotSwap_LocateSym01.bf") +GotoText("//Test_Start") +ToggleBreakpoint() +RunWithCompiling() +ToggleCommentAt("UseMod_Mod") +Compile() +StepOver() +AssertEvalEquals("f", "7") \ No newline at end of file diff --git a/IDE/Tests/Test1/src/HotSwap_LocateSym01.bf b/IDE/Tests/Test1/src/HotSwap_LocateSym01.bf new file mode 100644 index 00000000..1191fe4c --- /dev/null +++ b/IDE/Tests/Test1/src/HotSwap_LocateSym01.bf @@ -0,0 +1,23 @@ +#pragma warning disable 168 + +namespace IDETest +{ + class HotSwap_LocateSym01 + { + static float UseMod() + { + float f = 100.0f; + /*UseMod_Mod + f = f % 31.0f; + */ + return f; + } + + public static void Test() + { + int a = 0; + //Test_Start + float f = UseMod(); + } + } +} diff --git a/IDE/Tests/Test1/src/Program.bf b/IDE/Tests/Test1/src/Program.bf index 7ede8872..b85da495 100644 --- a/IDE/Tests/Test1/src/Program.bf +++ b/IDE/Tests/Test1/src/Program.bf @@ -14,6 +14,7 @@ namespace IDETest HotSwap_Data.Test(); HotSwap_GetUnusued.Test(); HotSwap_Interfaces2.Test(); + HotSwap_LocateSym01.Test(); HotSwap_Reflection.Test(); HotSwap_TLS.Test(); InlineTester.Test(); diff --git a/IDE/Tests/TestDynCrt1/BeefProj.toml b/IDE/Tests/TestDynCrt1/BeefProj.toml new file mode 100644 index 00000000..0f5560ed --- /dev/null +++ b/IDE/Tests/TestDynCrt1/BeefProj.toml @@ -0,0 +1,8 @@ +FileVersion = 1 + +[Project] +Name = "TestStaticCrt1" +StartupObject = "TestStaticCrt1.Program" + +[Configs.Debug.Win64] +CLibType = "DynamicDebug" diff --git a/IDE/Tests/TestDynCrt1/BeefSpace.toml b/IDE/Tests/TestDynCrt1/BeefSpace.toml new file mode 100644 index 00000000..5e4738f9 --- /dev/null +++ b/IDE/Tests/TestDynCrt1/BeefSpace.toml @@ -0,0 +1,5 @@ +FileVersion = 1 +Projects = {TestStaticCrt1 = {Path = "."}} + +[Workspace] +StartupProject = "TestStaticCrt1" diff --git a/IDE/Tests/TestDynCrt1/scripts/HotSwap_LocateSym01.txt b/IDE/Tests/TestDynCrt1/scripts/HotSwap_LocateSym01.txt new file mode 100644 index 00000000..1f31af90 --- /dev/null +++ b/IDE/Tests/TestDynCrt1/scripts/HotSwap_LocateSym01.txt @@ -0,0 +1,8 @@ +ShowFile("src/HotSwap_LocateSym01.bf") +GotoText("//Test_Start") +ToggleBreakpoint() +RunWithCompiling() +ToggleCommentAt("UseMod_Mod") +Compile() +StepOver() +AssertEvalEquals("f", "7") \ No newline at end of file diff --git a/IDE/Tests/TestDynCrt1/src/HotSwap_LocateSym01.bf b/IDE/Tests/TestDynCrt1/src/HotSwap_LocateSym01.bf new file mode 100644 index 00000000..49710d72 --- /dev/null +++ b/IDE/Tests/TestDynCrt1/src/HotSwap_LocateSym01.bf @@ -0,0 +1,23 @@ +#pragma warning disable 168 + +namespace TestStaticCrt1 +{ + class HotSwap_LocateSym01 + { + static float UseMod() + { + float f = 100.0f; + /*UseMod_Mod + f = f % 31.0f; + */ + return f; + } + + public static void Test() + { + int a = 0; + //Test_Start + float f = UseMod(); + } + } +} diff --git a/IDE/Tests/TestDynCrt1/src/Program.bf b/IDE/Tests/TestDynCrt1/src/Program.bf new file mode 100644 index 00000000..eb5b7228 --- /dev/null +++ b/IDE/Tests/TestDynCrt1/src/Program.bf @@ -0,0 +1,10 @@ +namespace TestStaticCrt1 +{ + class Program + { + static void Main() + { + HotSwap_LocateSym01.Test(); + } + } +} diff --git a/IDE/dist/BeefConfig.toml b/IDE/dist/BeefConfig.toml index 0ec151cc..b9e9315d 100644 --- a/IDE/dist/BeefConfig.toml +++ b/IDE/dist/BeefConfig.toml @@ -8,4 +8,8 @@ Location = { Path = "../../BeefLibs/corlib" } [Registry.Beefy2D] Version = "1.0.0" -Location = { Path = "../../BeefLibs/Beefy2D" } \ No newline at end of file +Location = { Path = "../../BeefLibs/Beefy2D" } + +[Registry.SDL2] +Version = "1.0.0" +Location = { Path = "../../BeefLibs/SDL2" } \ No newline at end of file diff --git a/IDE/mintest/BeefProj.toml b/IDE/mintest/BeefProj.toml index acc4f96f..b0a340e4 100644 --- a/IDE/mintest/BeefProj.toml +++ b/IDE/mintest/BeefProj.toml @@ -8,7 +8,7 @@ DefaultNamespace = "Mintest" Aliases = ["corlib"] [Configs.Debug.Win64] -CLibType = "DynamicDebug" +CLibType = "Static" BeefLibType = "DynamicDebug" StackSize = 4194304 DebugCommandArguments = "hey=\"yo man\" zag= zoogles boof stoopers \"\"\"abc efg\"\"\"" diff --git a/IDE/mintest/src/main3.bf b/IDE/mintest/src/main3.bf index 2e9424e4..64b15371 100644 --- a/IDE/mintest/src/main3.bf +++ b/IDE/mintest/src/main3.bf @@ -125,15 +125,24 @@ class Blurg public static int GetInt() { + float f = 10.0f; + //f = f % 3.0f; + return 123; } public static void Hey() { + float f = 1.2f; + //f = f % 2.3f; + TestStruct ts = .(); //int val = ts..mA; ts.mA = 123; + GetInt(); + GetInt(); + VoidCall(); int val0 = GetInt(); diff --git a/IDE/src/Debugger/DebugManager.bf b/IDE/src/Debugger/DebugManager.bf index bc6909c7..426d1f3a 100644 --- a/IDE/src/Debugger/DebugManager.bf +++ b/IDE/src/Debugger/DebugManager.bf @@ -131,7 +131,7 @@ namespace IDE.Debugger static extern bool Debugger_OpenMiniDump(char8* filename); [StdCall,CLink] - static extern bool Debugger_OpenFile(char8* fileName, char8* args, char8* workingDir, void* envBlockPtr, int32 envBlockLen); + static extern bool Debugger_OpenFile(char8* launchPath, char8* targetPath, char8* args, char8* workingDir, void* envBlockPtr, int32 envBlockLen); [StdCall,CLink] static extern bool Debugger_Attach(int32 processId, AttachFlags attachFlags); @@ -405,13 +405,13 @@ namespace IDE.Debugger Debugger_FullReportMemory(); } - public bool OpenFile(String file, String args, String workingDir, Span envBlock, bool isCompiled) + public bool OpenFile(String launchPath, String targetPath, String args, String workingDir, Span envBlock, bool isCompiled) { DeleteAndNullify!(mRunningPath); - mRunningPath = new String(file); + mRunningPath = new String(launchPath); mIsRunningCompiled = isCompiled; - return Debugger_OpenFile(file, args, workingDir, envBlock.Ptr, (int32)envBlock.Length); + return Debugger_OpenFile(launchPath, targetPath, args, workingDir, envBlock.Ptr, (int32)envBlock.Length); } public void SetSymSrvOptions(String symCacheDir, String symSrvStr, SymSrvFlags symSrvFlags) diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 8c176bce..b6381420 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -9295,8 +9295,8 @@ namespace IDE //options.mDebugOptions.mCommand - String targetPath = scope String(); - ResolveConfigString(workspaceOptions, project, options, options.mDebugOptions.mCommand, "debug command", targetPath); + String launchPath = scope String(); + ResolveConfigString(workspaceOptions, project, options, options.mDebugOptions.mCommand, "debug command", launchPath); String arguments = scope String(); ResolveConfigString(workspaceOptions, project, options, "$(Arguments)", "debug command arguments", arguments); String workingDirRel = scope String(); @@ -9304,8 +9304,14 @@ namespace IDE var workingDir = scope String(); Path.GetAbsolutePath(workingDirRel, project.mProjectDir, workingDir); + String targetPath = scope .(); + ResolveConfigString(workspaceOptions, project, options, "$(TargetPath)", "Target path", targetPath); + + IDEUtils.FixFilePath(launchPath); + IDEUtils.FixFilePath(targetPath); + if (workingDir.IsEmpty) - Path.GetDirectoryPath(targetPath, workingDir); + Path.GetDirectoryPath(launchPath, workingDir); if (!Directory.Exists(workingDir)) { @@ -9333,13 +9339,13 @@ namespace IDE var envBlock = scope List(); Environment.EncodeEnvironmentVariables(envVars, envBlock); - if (targetPath.IsWhiteSpace) + if (launchPath.IsWhiteSpace) { Fail(scope String()..AppendF("No debug command specified in '{}' properties", project.mProjectName)); return false; } - if (!mDebugger.OpenFile(targetPath, arguments, workingDir, envBlock, wasCompiled)) + if (!mDebugger.OpenFile(launchPath, targetPath, arguments, workingDir, envBlock, wasCompiled)) { DeleteAndNullify!(mCompileAndRunStopwatch); return false; @@ -11338,6 +11344,11 @@ namespace IDE { scope AutoBeefPerf("IDEApp.Update"); + /*using (mWorkspace.mMonitor.Enter()) + { + + }*/ + if (mDbgFastUpdate) { RefreshRate = 240; diff --git a/IDE/src/TestManager.bf b/IDE/src/TestManager.bf index 7bc3d7da..50ef9553 100644 --- a/IDE/src/TestManager.bf +++ b/IDE/src/TestManager.bf @@ -458,7 +458,7 @@ namespace IDE var envBlock = scope List(); Environment.EncodeEnvironmentVariables(envVars, envBlock); - if (!gApp.mDebugger.OpenFile(curProjectInfo.mTestExePath, mTestInstance.mArgs, mTestInstance.mWorkingDir, envBlock, true)) + if (!gApp.mDebugger.OpenFile(curProjectInfo.mTestExePath, curProjectInfo.mTestExePath, mTestInstance.mArgs, mTestInstance.mWorkingDir, envBlock, true)) { QueueOutputLine("ERROR: Failed debug '{0}'", curProjectInfo.mTestExePath); TestFailed(); diff --git a/IDE/src/ui/LaunchDialog.bf b/IDE/src/ui/LaunchDialog.bf index 0676a03b..c527fc15 100644 --- a/IDE/src/ui/LaunchDialog.bf +++ b/IDE/src/ui/LaunchDialog.bf @@ -332,7 +332,7 @@ namespace IDE.ui var envBlock = scope List(); Environment.EncodeEnvironmentVariables(envVars, envBlock); - if (!gApp.mDebugger.OpenFile(targetPath, arguments, workingDir, envBlock, false)) + if (!gApp.mDebugger.OpenFile(targetPath, targetPath, arguments, workingDir, envBlock, false)) { gApp.Fail(scope String()..AppendF("Unable to open executable for debugging: {0}", targetPath)); return; diff --git a/IDEHelper/Backend/BeLibManger.h b/IDEHelper/Backend/BeLibManger.h index bdced24a..7073f6ac 100644 --- a/IDEHelper/Backend/BeLibManger.h +++ b/IDEHelper/Backend/BeLibManger.h @@ -70,6 +70,11 @@ public: mNextWithSameName = NULL; } + ~BeLibEntry() + { + delete mNextWithSameName; + } + void AddSymbol(const StringImpl& sym); }; diff --git a/IDEHelper/COFF.cpp b/IDEHelper/COFF.cpp index 10c52a26..650718c2 100644 --- a/IDEHelper/COFF.cpp +++ b/IDEHelper/COFF.cpp @@ -236,9 +236,7 @@ COFF::COFF(DebugTarget* debugTarget) : DbgModule(debugTarget) mCvPageBits = 31; mCvDataStream = NULL; mCvHeaderData = NULL; - mCvStrTableData = NULL; - mCvTypeSectionData = NULL; - mCvTypeSectionDataSize = -1; + mCvStrTableData = NULL; mCvPublicSymbolData = NULL; mCvGlobalSymbolData = NULL; mNewFPOData = NULL; @@ -251,10 +249,7 @@ COFF::COFF(DebugTarget* debugTarget) : DbgModule(debugTarget) mCvMappedViewOfFile = NULL; mCvMappedFileSize = 0; //mParsedProcRecs = false; - - mCvCompileUnitData = NULL; - mCvCompileUnitDataSize = 0; - + mGlobalsTargetType = NULL; mPrevScanName = NULL; mProcSymCount = 0; @@ -273,7 +268,7 @@ COFF::~COFF() { BF_ASSERT(mTempBufIdx == 0); ClosePDB(); - mDebugger->mDbgSymSrv.ReleaseRequest(mDbgSymRequest); + mDebugger->mDbgSymSrv.ReleaseRequest(mDbgSymRequest); } const char* COFF::CvCheckTargetMatch(const char* name, bool& wasBeef) @@ -3209,7 +3204,7 @@ void COFF::ParseCompileUnit_Symbols(DbgCompileUnit* compileUnit, uint8* sectionD _FlushDeferredVariableLocations(); } -CvCompileUnit* COFF::ParseCompileUnit(CvModuleInfo* moduleInfo, uint8* sectionData, int sectionSize) +CvCompileUnit* COFF::ParseCompileUnit(CvModuleInfo* moduleInfo, CvCompileUnit* compileUnit, uint8* sectionData, int sectionSize) { BP_ZONE("COFF::ParseCompileUnit"); @@ -3227,7 +3222,11 @@ CvCompileUnit* COFF::ParseCompileUnit(CvModuleInfo* moduleInfo, uint8* sectionDa int allocSizeStart = mAlloc.GetAllocSize(); - CvCompileUnit* compileUnit = new CvCompileUnit(this); + if (compileUnit == NULL) + { + compileUnit = new CvCompileUnit(this); + mCompileUnits.push_back(compileUnit); + } compileUnit->mDbgModule = this; if (moduleInfo != NULL) { @@ -3239,8 +3238,7 @@ CvCompileUnit* COFF::ParseCompileUnit(CvModuleInfo* moduleInfo, uint8* sectionDa { compileUnit->mModuleIdx = NULL; compileUnit->mName = mFilePath.c_str(); - } - mCompileUnits.push_back(compileUnit); + } uint8* data = sectionData; uint8* dataEnd = NULL; @@ -3373,9 +3371,11 @@ CvCompileUnit* COFF::ParseCompileUnit(CvModuleInfo* moduleInfo, uint8* sectionDa data = debugSubSectionsStart; dataEnd = data + taggedSize; - while (data < dataEnd) + while (true) { PTR_ALIGN(data, sectionData, 4); + if (data >= dataEnd) + break; GET_INTO(int32, lineInfoType); GET_INTO(int32, lineInfoLength); uint8* dataStart = data; @@ -3895,7 +3895,7 @@ CvCompileUnit* COFF::ParseCompileUnit(int compileUnitId) int sectionSize = 0; uint8* sectionData = CvReadStream(moduleInfo->mStream, §ionSize); - ParseCompileUnit(moduleInfo, sectionData, sectionSize); + ParseCompileUnit(moduleInfo, NULL, sectionData, sectionSize); delete sectionData; return moduleInfo->mCompileUnit; } @@ -5641,10 +5641,10 @@ void COFF::ReportMemory(MemReporter* memReporter) if (mCvHeaderData != NULL) memReporter->Add("mCvHeaderData", mCvStreamSizes[1]); - if (mCvTypeSectionData != NULL) + for (auto& entry : mCvTypeSectionData) { - if (mCvTypeSectionDataSize != -1) - memReporter->Add("mCvTypeSectionData", mCvTypeSectionDataSize); + if (entry.mSize != -1) + memReporter->Add("mCvTypeSectionData", entry.mSize); else memReporter->Add("mCvTypeSectionData", mCvStreamSizes[2]); } @@ -5784,10 +5784,12 @@ void COFF::ClosePDB() mCvHeaderData = NULL; delete mCvStrTableData; mCvStrTableData = NULL; - delete mCvTypeSectionData; - mCvTypeSectionData = NULL; - delete mCvCompileUnitData; - mCvCompileUnitData = NULL; + for (auto& entry : mCvTypeSectionData) + delete entry.mData; + mCvTypeSectionData.Clear(); + for (auto& entry : mCvCompileUnitData) + delete entry.mData; + mCvCompileUnitData.Clear(); delete mCvPublicSymbolData; mCvPublicSymbolData = NULL; delete mCvGlobalSymbolData; @@ -5806,7 +5808,8 @@ void COFF::ClosePDB() for (auto kv : mHotLibMap) delete kv.mValue; - mHotLibMap.Clear(); + mHotLibMap.Clear(); + mHotLibSymMap.Clear(); } bool COFF::LoadPDB(const String& pdbPath, uint8 wantGuid[16], int32 wantAge) @@ -5883,15 +5886,19 @@ bool COFF::CheckSection(const char* name, uint8* sectionData, int sectionSize) if (strcmp(name, ".debug$T") == 0) { mDbgFlavor = DbgFlavor_MS; - mCvTypeSectionData = sectionData; - mCvTypeSectionDataSize = sectionSize; + DbgSectionData entry; + entry.mData = sectionData; + entry.mSize = sectionSize; + mCvTypeSectionData.Add(entry); return true; } if (strcmp(name, ".debug$S") == 0) - { - mCvCompileUnitData = sectionData; - mCvCompileUnitDataSize = sectionSize; + { + DbgSectionData entry; + entry.mData = sectionData; + entry.mSize = sectionSize; + mCvCompileUnitData.Add(entry); return true; } @@ -5902,20 +5909,23 @@ void COFF::ProcessDebugInfo() { BP_ZONE("COFF::ProcessDebugInfo"); - if ((mCvTypeSectionDataSize > 0) && (mCvCompileUnitDataSize > 0)) + if ((!mCvTypeSectionData.IsEmpty()) && (!mCvCompileUnitData.IsEmpty())) { auto linkedModule = (COFF*)GetLinkedModule(); int startingTypeIdx = (int)linkedModule->mTypes.size(); InitCvTypes(); - uint8* data = mCvTypeSectionData; - GET_INTO(uint32, infoType); - BF_ASSERT(infoType == CV_SIGNATURE_C13); + for (auto entry : mCvTypeSectionData) + { + uint8* data = entry.mData; + GET_INTO(uint32, infoType); + BF_ASSERT(infoType == CV_SIGNATURE_C13); - CvInitStreamRaw(mCvTypeSectionReader, mCvTypeSectionData + 4, mCvTypeSectionDataSize - 4); - //ParseTypeData(data, mCvTypeSectionDataSize - sizeof(uint32)); - ParseTypeData(mCvTypeSectionReader, 0); + CvInitStreamRaw(mCvTypeSectionReader, entry.mData + 4, entry.mSize - 4); + //ParseTypeData(data, mCvTypeSectionDataSize - sizeof(uint32)); + ParseTypeData(mCvTypeSectionReader, 0); + } FixTypes(startingTypeIdx); linkedModule->MapTypes(startingTypeIdx); @@ -5930,7 +5940,11 @@ void COFF::ProcessDebugInfo() } }*/ - auto compileUnit = ParseCompileUnit(NULL, mCvCompileUnitData, mCvCompileUnitDataSize); + CvCompileUnit* compileUnit = NULL; + for (auto entry : mCvCompileUnitData) + { + compileUnit = ParseCompileUnit(NULL, compileUnit, entry.mData, entry.mSize); + } compileUnit->mLanguage = DbgLanguage_Beef; mMasterCompileUnit->mLanguage = DbgLanguage_Beef; MapCompileUnitMethods(compileUnit); @@ -6538,6 +6552,12 @@ addr_target COFF::LocateSymbol(const StringImpl& name) { for (auto sym : libEntry->mSymbols) { +#ifdef BF_DBG_32 + if (sym.StartsWith('_')) + mHotLibSymMap[sym.Substring(1)] = libEntry; + else + // Fallthrough +#endif mHotLibSymMap[sym] = libEntry; } libEntry = libEntry->mNextWithSameName; @@ -6626,15 +6646,27 @@ addr_target COFF::LocateSymbol(const StringImpl& name) return 0; } - BfLogDbg("Loading obj '%s' in '%s'\n", libEntry->mName.c_str(), libEntry->mLibFile->mFilePath.c_str()); +// #ifdef _DEBUG +// FILE* fpTest = fopen("c:\\temp\\locateSym.obj", "wb"); +// +// uint8* data = new uint8[libEntry->mLength]; +// +// fseek(libEntry->mLibFile->mOldFileStream.mFP, libEntry->mOldDataPos + sizeof(BeLibMemberHeader), SEEK_SET); +// fread(data, 1, libEntry->mLength, libEntry->mLibFile->mOldFileStream.mFP); +// fwrite(data, 1, libEntry->mLength, fpTest); +// fclose(fpTest); +// delete data; +// #endif + + FileSubStream fileStream; fileStream.mFP = libEntry->mLibFile->mOldFileStream.mFP; fileStream.mOffset = libEntry->mOldDataPos + sizeof(BeLibMemberHeader); fileStream.mSize = libEntry->mLength; fileStream.SetPos(0); - + DbgModule* dbgModule = new COFF(mDebugger->mDebugTarget); dbgModule->mHotIdx = mDebugger->mActiveHotIdx; dbgModule->mFilePath = libEntry->mName + "@" + libEntry->mLibFile->mFilePath; @@ -6789,21 +6821,21 @@ void COFF::ParseFrameDescriptors() } NS_BF_DBG_BEGIN -void TestCoff(void* tdata, int tdataSize, void* cuData, int cuDataSize) -{ - DebugTarget* debugTarget = new DebugTarget(NULL); - { - COFF coff(debugTarget); - coff.mCvTypeSectionData = (uint8*)tdata; - coff.mCvTypeSectionDataSize = tdataSize; - - coff.mCvCompileUnitData = (uint8*)cuData; - coff.mCvCompileUnitDataSize = cuDataSize; - - coff.ProcessDebugInfo(); - } - delete debugTarget; -} +// void TestCoff(void* tdata, int tdataSize, void* cuData, int cuDataSize) +// { +// DebugTarget* debugTarget = new DebugTarget(NULL); +// { +// COFF coff(debugTarget); +// coff.mCvTypeSectionData = (uint8*)tdata; +// coff.mCvTypeSectionDataSize = tdataSize; +// +// coff.mCvCompileUnitData = (uint8*)cuData; +// coff.mCvCompileUnitDataSize = cuDataSize; +// +// coff.ProcessDebugInfo(); +// } +// delete debugTarget; +// } void TestPDB(const String& fileName) { diff --git a/IDEHelper/COFF.h b/IDEHelper/COFF.h index 8c1bc38c..9aa6233e 100644 --- a/IDEHelper/COFF.h +++ b/IDEHelper/COFF.h @@ -202,6 +202,7 @@ public: Dictionary mSymDict; }; + class COFF : public DbgModule { public: @@ -247,8 +248,8 @@ public: SafeMemStream* mCvDataStream; CvStringTable mStringTable; - uint8* mCvHeaderData; - uint8* mCvTypeSectionData; + uint8* mCvHeaderData; + //uint8* mCvTypeSectionData uint8* mCvStrTableData; uint8* mCvPublicSymbolData; uint8* mCvGlobalSymbolData; @@ -270,9 +271,11 @@ public: const char* mPrevScanName; // For hot data - int mCvTypeSectionDataSize; - uint8* mCvCompileUnitData; - int mCvCompileUnitDataSize; + Array mCvTypeSectionData; + Array mCvCompileUnitData; + //int mCvTypeSectionDataSize; + //uint8* mCvCompileUnitData; + //int mCvCompileUnitDataSize; HANDLE mCvMappedFile; void* mCvMappedViewOfFile; @@ -292,7 +295,7 @@ public: void ParseTypeData(int sectionNum, CvStreamReader& reader, int& sectionSize, int& dataOfs, int& hashStream, int& hashAdjOffset, int& hashAdjSize, int& minVal, int& maxVal); virtual void ParseTypeData() override; void ParseCompileUnit_Symbols(DbgCompileUnit* compileUnit, uint8* sectionData, uint8* data, uint8* dataEnd, CvInlineInfoVec& inlineDataVec, bool deferInternals, DbgSubprogram* useSubprogram); - CvCompileUnit* ParseCompileUnit(CvModuleInfo* moduleInfo, uint8* sectionData, int sectionSize); + CvCompileUnit* ParseCompileUnit(CvModuleInfo* moduleInfo, CvCompileUnit* compileUnit, uint8* sectionData, int sectionSize); virtual CvCompileUnit* ParseCompileUnit(int compileUnitId) override; virtual void MapCompileUnitMethods(DbgCompileUnit* compileUnit) override; virtual void MapCompileUnitMethods(int compileUnitId) override; diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 2d5b1a94..4fa30cef 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -5049,12 +5049,7 @@ void BfCompiler::HotResolve_ReportType(BfHotTypeVersion* hotTypeVersion, HotType bool applyFlags = true; if ((flags & (BfCompiler::HotTypeFlag_ActiveFunction | BfCompiler::HotTypeFlag_Delegate | BfCompiler::HotTypeFlag_FuncPtr)) != 0) - { - // These flags only get applied if we detect we're using an old version -// auto hotTypeData = mContext->GetHotTypeData(hotTypeVersion->mTypeId); -// auto latestTypeVersion = hotTypeData->GetLatestVersion(); -// applyFlags = hotTypeVersion->mDataHash != latestTypeVersion->mDataHash; - + { applyFlags = (hotTypeVersion->mCommittedHotCompileIdx != -1) && (mHotState->mPendingDataChanges.Contains(hotTypeVersion->mTypeId)); if ((!applyFlags) && (hotTypeVersion->mCommittedHotCompileIdx != -1)) @@ -5074,12 +5069,9 @@ void BfCompiler::HotResolve_ReportType(BfHotTypeVersion* hotTypeVersion, HotType BfLogSysM("HotResolve_ReportType %p %s Flags:%X DeclHotIdx:%d\n", hotTypeVersion, mContext->TypeIdToString(hotTypeVersion->mTypeId).c_str(), flags, hotTypeVersion->mDeclHotCompileIdx); - //if ((flags & (BfCompiler::HotTypeFlag_Heap | BfCompiler::HotTypeFlag_Delegate | BfCompiler::HotTypeFlag_CanAllocate)) != 0) + for (auto member : hotTypeVersion->mMembers) { - for (auto member : hotTypeVersion->mMembers) - { - HotResolve_ReportType(member, flags, reason); - } + HotResolve_ReportType(member, flags, reason); } } @@ -5465,6 +5457,8 @@ void BfCompiler::ClearOldHotData() if (typeInst->mHotTypeData == NULL) continue; + bool foundCommittedVersion = false; + auto latestVersionHead = typeInst->mHotTypeData->GetLatestVersionHead(); for (int typeIdx = (int)typeInst->mHotTypeData->mTypeVersions.size() - 1; typeIdx >= 0; typeIdx--) { @@ -5475,8 +5469,13 @@ void BfCompiler::ClearOldHotData() continue; } - if (hotVersion->mRefCount == 1) - { + if ((!foundCommittedVersion) && (mHotState != NULL) && (hotVersion->mDeclHotCompileIdx <= mHotState->mCommittedHotCompileIdx)) + { + // Don't remove the latest committed version + foundCommittedVersion = true; + } + else if (hotVersion->mRefCount == 1) + { typeInst->mHotTypeData->mTypeVersions.RemoveAt(typeIdx); hotVersion->Deref(); BF_ASSERT(typeInst->mHotTypeData->mTypeVersions.size() > 0); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 9f154541..9113df66 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -14503,9 +14503,7 @@ void BfModule::CallChainedMethods(BfMethodInstance* methodInstance, bool reverse } void BfModule::AddHotDataReferences(BfHotDataReferenceBuilder* builder) -{ - //auto methodName = MethodToString(mCurMethodInstance, BfMethodNameFlag_OmitTypeName); - +{ BF_ASSERT(mCurMethodInstance->mIsReified); if (mCurTypeInstance->mHotTypeData == NULL) @@ -14519,8 +14517,6 @@ void BfModule::AddHotDataReferences(BfHotDataReferenceBuilder* builder) } BF_ASSERT(hotMethod->mSrcTypeVersion != NULL); - //hotMethod->mSrcTypeVersion = mCurTypeInstance->mHotTypeData->GetLatestVersion(); - //hotMethod->mSrcTypeVersion->mRefCount++; int prevSize = (int)hotMethod->mReferences.size(); int refCount = (int)(prevSize + builder->mUsedData.size() + builder->mCalledMethods.size() + builder->mDevirtualizedCalledMethods.size()); @@ -17167,14 +17163,6 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup) else if (wantsRemoveBody) mBfIRBuilder->Func_DeleteBody(mCurMethodInstance->mIRFunction); - //TODO: Can we actually do this? - /*if ((!HasCompiledOutput()) && (!mCompiler->mOptions.mExtraResolveChecks)) - { - mBfIRBuilder->Func_DeleteBody(mCurMethodInstance->mIRFunction); - mBfIRBuilder->Func_EraseFromParent(mCurMethodInstance->mIRFunction); - mCurMethodInstance->mIRFunction = BfIRFunction(); - }*/ - // We don't want to hold on to pointers to LLVMFunctions of unspecialized types. // This allows us to delete the mScratchModule LLVM module without rebuilding all // unspecialized types diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index ae2ff755..5a95eb29 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -4536,7 +4536,7 @@ void BfModule::FixIntUnknown(BfTypedValue& typedVal) void BfModule::FixIntUnknown(BfTypedValue& lhs, BfTypedValue& rhs) { - if ((lhs.mType != NULL) && (lhs.mType->IsIntUnknown())) + if ((lhs.mType != NULL) && (lhs.mType->IsIntUnknown()) && (rhs.mType != NULL) && (rhs.mType->IsInteger())) { if (CanImplicitlyCast(lhs, rhs.mType)) { @@ -4547,7 +4547,7 @@ void BfModule::FixIntUnknown(BfTypedValue& lhs, BfTypedValue& rhs) } } - if ((rhs.mType != NULL) && (rhs.mType->IsIntUnknown())) + if ((rhs.mType != NULL) && (rhs.mType->IsIntUnknown()) && (lhs.mType != NULL) && (lhs.mType->IsInteger())) { if (CanImplicitlyCast(rhs, lhs.mType)) { diff --git a/IDEHelper/DbgExprEvaluator.cpp b/IDEHelper/DbgExprEvaluator.cpp index 7109c142..2c029227 100644 --- a/IDEHelper/DbgExprEvaluator.cpp +++ b/IDEHelper/DbgExprEvaluator.cpp @@ -1121,6 +1121,9 @@ bool DbgExprEvaluator::TypeIsSubTypeOf(DbgType* srcType, DbgType* wantType, int* DbgTypedValue DbgExprEvaluator::GetBeefTypeById(int typeId) { + if (mDebugTarget->mTargetBinary == NULL) + return DbgTypedValue(); + auto typeTypeEntry = mDebugTarget->mTargetBinary->FindType("System.Type", DbgLanguage_Beef); if ((typeTypeEntry == NULL) || (typeTypeEntry->mValue == NULL)) return DbgTypedValue(); @@ -3433,9 +3436,11 @@ DbgTypedValue DbgExprEvaluator::LookupIdentifier(BfAstNode* identifierNode, bool else if (findName == "$ThreadName") return GetString(mDebugger->mActiveThread->mName); else if (findName == "$TargetName") - return GetString(GetFileName(mDebugTarget->mTargetBinary->mFilePath)); + return GetString(GetFileName(mDebugTarget->mTargetPath)); + else if (findName == "LaunchName") + return GetString(GetFileName(mDebugTarget->mLaunchBinary->mFilePath)); else if (findName == "$TargetPath") - return GetString(mDebugTarget->mTargetBinary->mFilePath); + return GetString(mDebugTarget->mTargetPath); else if (findName == "$ModuleName") return GetString(GetFileName(mDbgModule->mFilePath)); else if (findName == "$ModulePath") diff --git a/IDEHelper/DbgModule.cpp b/IDEHelper/DbgModule.cpp index fa171669..44ac5652 100644 --- a/IDEHelper/DbgModule.cpp +++ b/IDEHelper/DbgModule.cpp @@ -1922,9 +1922,7 @@ DbgModule::DbgModule(DebugTarget* debugTarget) : mDefaultCompileUnit(this) mDebugLocationData = NULL; mDebugRangesData = NULL; mDebugAbbrevData = NULL; - mDebugStrData = NULL; - mExceptionDirectoryData = NULL; - mExceptionDirectoryDataLen = 0; + mDebugStrData = NULL; mDebugAbbrevPtrData = NULL; mEHFrameData = NULL; mEHFrameAddress = 0; @@ -1986,7 +1984,8 @@ DbgModule::~DbgModule() delete mDebugAbbrevData; delete mDebugAbbrevPtrData; delete mDebugStrData; - delete mExceptionDirectoryData; + for (auto entry : mExceptionDirectory) + delete entry.mData; delete mEHFrameData; delete mOrigImageData; @@ -2123,47 +2122,50 @@ void DbgModule::ParseAbbrevData(const uint8* data) void DbgModule::ParseExceptionData() { - if (mExceptionDirectoryData == NULL) + if (mExceptionDirectory.IsEmpty()) return; BP_ZONE("DbgModule::ParseExceptionData"); - const uint8* data = mExceptionDirectoryData; - const uint8* dataEnd = data + mExceptionDirectoryDataLen; - - static int entryCount = 0; - - addr_target imageBase = GetTargetImageBase(); - - while (data < dataEnd) + for (auto entry : mExceptionDirectory) { - addr_target beginAddress = GET(uint32); - addr_target endAddress = GET(uint32); - uint32 unwindData = GET(uint32); - - //TODO: Apparently unwindData can refer to another runtime entry in the .pdata if the LSB is set to 1? + const uint8* data = entry.mData; + const uint8* dataEnd = data + entry.mSize; - beginAddress += (addr_target)imageBase; - endAddress += (addr_target)imageBase; - - int exSize = (int)(endAddress - beginAddress); - for (int exOffset = 0; true; exOffset += DBG_MAX_LOOKBACK) + static int entryCount = 0; + + addr_target imageBase = GetTargetImageBase(); + + while (data < dataEnd) { - int curSize = exSize - exOffset; - if (curSize <= 0) - break; - - BP_ALLOC_T(DbgExceptionDirectoryEntry); - DbgExceptionDirectoryEntry* exceptionDirectoryEntry = mAlloc.Alloc(); + addr_target beginAddress = GET(uint32); + addr_target endAddress = GET(uint32); + uint32 unwindData = GET(uint32); - exceptionDirectoryEntry->mAddress = beginAddress + exOffset; - exceptionDirectoryEntry->mOrigAddressOffset = exOffset; - exceptionDirectoryEntry->mAddressLength = curSize; - exceptionDirectoryEntry->mExceptionPos = (int)unwindData; - exceptionDirectoryEntry->mDbgModule = this; - mDebugTarget->mExceptionDirectoryMap.Insert(exceptionDirectoryEntry); + //TODO: Apparently unwindData can refer to another runtime entry in the .pdata if the LSB is set to 1? - entryCount++; + beginAddress += (addr_target)imageBase; + endAddress += (addr_target)imageBase; + + int exSize = (int)(endAddress - beginAddress); + for (int exOffset = 0; true; exOffset += DBG_MAX_LOOKBACK) + { + int curSize = exSize - exOffset; + if (curSize <= 0) + break; + + BP_ALLOC_T(DbgExceptionDirectoryEntry); + DbgExceptionDirectoryEntry* exceptionDirectoryEntry = mAlloc.Alloc(); + + exceptionDirectoryEntry->mAddress = beginAddress + exOffset; + exceptionDirectoryEntry->mOrigAddressOffset = exOffset; + exceptionDirectoryEntry->mAddressLength = curSize; + exceptionDirectoryEntry->mExceptionPos = (int)unwindData; + exceptionDirectoryEntry->mDbgModule = this; + mDebugTarget->mExceptionDirectoryMap.Insert(exceptionDirectoryEntry); + + entryCount++; + } } } } @@ -5310,7 +5312,9 @@ bool DbgModule::ReadCOFF(DataStream* stream, bool isHotObjectFile) targetSection->mNoTargetAlloc = true; } - if ((!mIsHotObjectFile) /*&& (!isUnwindSection)*/) + bool isExportDataDir = ((exportDataDir->mVirtualAddress != 0) && (exportDataDir->mVirtualAddress >= sectHdr.mVirtualAddress) && (exportDataDir->mVirtualAddress < sectHdr.mVirtualAddress + sectHdr.mSizeOfRawData)); + + if ((!mIsHotObjectFile) && (!isExportDataDir)) { if (((strcmp(name, ".text")) == 0) || ((strcmp(name, ".textbss")) == 0) || @@ -5341,7 +5345,7 @@ bool DbgModule::ReadCOFF(DataStream* stream, bool isHotObjectFile) targetSection->mData = data; addr_target addrOffset = sectHdr.mVirtualAddress; - if ((exportDataDir->mVirtualAddress != 0) && (exportDataDir->mVirtualAddress >= sectHdr.mVirtualAddress) && (exportDataDir->mVirtualAddress < sectHdr.mVirtualAddress + sectHdr.mSizeOfRawData)) + if (isExportDataDir) { BP_ZONE("DbgModule::ReadCOFF_SymbolMap"); @@ -5565,9 +5569,11 @@ bool DbgModule::ReadCOFF(DataStream* stream, bool isHotObjectFile) }*/ if (strcmp(name, ".pdata") == 0) - { - mExceptionDirectoryData = data; - mExceptionDirectoryDataLen = sectHdr.mSizeOfRawData; + { + DbgSectionData entry; + entry.mData = data; + entry.mSize = sectHdr.mSizeOfRawData; + mExceptionDirectory.Add(entry); } /*else if (strcmp(name, ".rdata") == 0) { diff --git a/IDEHelper/DbgModule.h b/IDEHelper/DbgModule.h index 2da19ecc..fffe4ffc 100644 --- a/IDEHelper/DbgModule.h +++ b/IDEHelper/DbgModule.h @@ -122,6 +122,12 @@ enum DbgFileExistKind : uint8 class DbgCompileUnit; +struct DbgSectionData +{ + uint8* mData; + int mSize; +}; + class DbgDebugData { public: @@ -1095,9 +1101,8 @@ public: addr_target mCodeAddress; const uint8* mDebugAbbrevData; const uint8* mDebugStrData; - const uint8** mDebugAbbrevPtrData; - const uint8* mExceptionDirectoryData; - int mExceptionDirectoryDataLen; + const uint8** mDebugAbbrevPtrData; + Array mExceptionDirectory; const uint8* mEHFrameData; const char* mStringTable; const uint8* mSymbolData; diff --git a/IDEHelper/DebugManager.cpp b/IDEHelper/DebugManager.cpp index 256c1b21..bf33bc0c 100644 --- a/IDEHelper/DebugManager.cpp +++ b/IDEHelper/DebugManager.cpp @@ -795,18 +795,18 @@ BF_EXPORT int BF_CALLTYPE Debugger_GetAddrSize() return gDebugger->GetAddrSize(); } -BF_EXPORT bool BF_CALLTYPE Debugger_OpenFile(const char* fileName, const char* args, const char* workingDir, void* envBlockPtr, int envBlockSize) +BF_EXPORT bool BF_CALLTYPE Debugger_OpenFile(const char* launchPath, const char* targetPath, const char* args, const char* workingDir, void* envBlockPtr, int envBlockSize) { BF_ASSERT(gDebugger == NULL); - if (!FileExists(fileName)) + if (!FileExists(launchPath)) { - gDebugManager->mOutMessages.push_back(StrFormat("error Unable to locate specified debug target '%s'", fileName)); + gDebugManager->mOutMessages.push_back(StrFormat("error Unable to locate specified launch target '%s'", launchPath)); return false; } DebuggerResult debuggerResult = DebuggerResult_Ok; - if ((gDebugManager->mDebugger64 != NULL) && (gDebugManager->mDebugger64->CanOpen(fileName, &debuggerResult))) + if ((gDebugManager->mDebugger64 != NULL) && (gDebugManager->mDebugger64->CanOpen(launchPath, &debuggerResult))) gDebugger = gDebugManager->mDebugger64; else gDebugger = gDebugManager->mDebugger32; @@ -814,7 +814,7 @@ BF_EXPORT bool BF_CALLTYPE Debugger_OpenFile(const char* fileName, const char* a if (gDebugger == NULL) { if (debuggerResult == DebuggerResult_WrongBitSize) - gDebugManager->mOutMessages.push_back(StrFormat("error The file 32-bit file '%s' cannot be debugged because 32-bit debugger has been disabled", fileName)); + gDebugManager->mOutMessages.push_back(StrFormat("error The file 32-bit file '%s' cannot be debugged because 32-bit debugger has been disabled", launchPath)); return false; } @@ -825,7 +825,7 @@ BF_EXPORT bool BF_CALLTYPE Debugger_OpenFile(const char* fileName, const char* a envBlock.Insert(0, (uint8*)envBlockPtr, envBlockSize); } - gDebugger->OpenFile(fileName, args, workingDir, envBlock); + gDebugger->OpenFile(launchPath, targetPath, args, workingDir, envBlock); return true; } diff --git a/IDEHelper/DebugTarget.cpp b/IDEHelper/DebugTarget.cpp index a39153ee..4db8a8d6 100644 --- a/IDEHelper/DebugTarget.cpp +++ b/IDEHelper/DebugTarget.cpp @@ -23,6 +23,7 @@ DebugTarget::DebugTarget(WinDebugger* debugger) mBfObjectVDataIntefaceSlotCount = -1; mBfObjectSize = -1; mDebugger = debugger; + mLaunchBinary = NULL; mTargetBinary = NULL; mCapturedNamesPtr = NULL; mCapturedTypesPtr = NULL; @@ -50,31 +51,113 @@ DebugTarget::~DebugTarget() mHotHeap = NULL; } -DbgModule* DebugTarget::Init(const StringImpl& fileName, intptr imageBase) +static bool PathEquals(const String& pathA, String& pathB) +{ + const char* ptrA = pathA.c_str(); + const char* ptrB = pathB.c_str(); + + while (true) + { + char cA = *(ptrA++); + char cB = *(ptrB++); + + if ((cA == 0) || (cB == 0)) + { + return (cA == 0) && (cB == 0); + } + + cA = toupper((uint8)cA); + cB = toupper((uint8)cB); + if (cA == '\\') + cA = '/'; + if (cB == '\\') + cB = '/'; + if (cA != cB) + return false; + } + return true; +} + +void DebugTarget::SetupTargetBinary() +{ + bool wantsHotHeap = mDebugger->mDbgProcessId == 0; + +#ifdef BF_DBG_32 + if (wantsHotHeap) + mHotHeap = new HotHeap(); +#else + if (wantsHotHeap) + { + // 64-bit hot loaded code needs to be placed close to the original EXE so 32-bit relative + // offsets within the hot code can still reach the old code + addr_target checkHotReserveAddr = (addr_target)mTargetBinary->mImageBase + mTargetBinary->mImageSize; + int mb = 1024 * 1024; + int reserveSize = 512 * mb; + + // Round up to MB boundary + 64MB, to help keep other DLLs at their preferred base addresses + checkHotReserveAddr = ((checkHotReserveAddr + 64 * mb) & ~(mb - 1)); + + checkHotReserveAddr = (addr_target)mTargetBinary->mImageBase; + + addr_target reservedPtr = NULL; + while ((addr_target)checkHotReserveAddr < (addr_target)mTargetBinary->mImageBase + 0x30000000) + { + reservedPtr = (addr_target)VirtualAllocEx(mDebugger->mProcessInfo.hProcess, (void*)(intptr)checkHotReserveAddr, reserveSize, MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (reservedPtr != NULL) + break; + checkHotReserveAddr += 4 * mb; + } + + if (reservedPtr != 0) + { + BF_ASSERT(mHotHeap == NULL); + mHotHeap = new HotHeap(reservedPtr, reserveSize); + } + + //TODO: Throw actual error if we can't reserve HOT area + BF_ASSERT(reservedPtr != NULL); + } +#endif +} + +void DebugTarget::CheckTargetBinary(DbgModule* module) +{ + if (mTargetBinary != NULL) + return; + if (!PathEquals(module->mFilePath, mTargetPath)) + return; + mTargetBinary = module; + if (mTargetBinary != mLaunchBinary) + SetupTargetBinary(); +} + +DbgModule* DebugTarget::Init(const StringImpl& launchPath, const StringImpl& targetPath, intptr imageBase) { BP_ZONE("DebugTarget::Init"); - AutoDbgTime dbgTime("DebugTarget::Init " + fileName); + AutoDbgTime dbgTime("DebugTarget::Init Launch:" + launchPath + " Target:" + targetPath); + mTargetPath = targetPath; FileStream fileStream; - fileStream.mFP = _wfopen(UTF8Decode(fileName).c_str(), L"rb"); + fileStream.mFP = _wfopen(UTF8Decode(launchPath).c_str(), L"rb"); if (fileStream.mFP == NULL) { - mDebugger->OutputMessage(StrFormat("Debugger failed to open binary: %s\n", fileName.c_str())); + mDebugger->OutputMessage(StrFormat("Debugger failed to open binary: %s\n", launchPath.c_str())); return NULL; } DbgModule* dwarf = new COFF(this); - mTargetBinary = dwarf; - dwarf->mDisplayName = GetFileName(fileName); - dwarf->mFilePath = fileName; + mLaunchBinary = dwarf; + dwarf->mDisplayName = GetFileName(launchPath); + dwarf->mFilePath = launchPath; dwarf->mImageBase = (intptr)imageBase; if (!dwarf->ReadCOFF(&fileStream, false)) { - mDebugger->OutputMessage(StrFormat("Debugger failed to read binary: %s\n", fileName.c_str())); + mDebugger->OutputMessage(StrFormat("Debugger failed to read binary: %s\n", launchPath.c_str())); delete dwarf; return NULL; } + CheckTargetBinary(dwarf); mDbgModules.push_back(dwarf); return dwarf; @@ -85,6 +168,7 @@ void DebugTarget::CreateEmptyTarget() auto emptyTarget = new DbgModule(this); mDbgModules.push_back(emptyTarget); mTargetBinary = emptyTarget; + mLaunchBinary = emptyTarget; } DbgModule* DebugTarget::HotLoad(const StringImpl& fileName, int hotIdx) @@ -134,7 +218,7 @@ DbgModule* DebugTarget::SetupDyn(const StringImpl& filePath, DataStream* stream, dwarf->mDisplayName = GetFileName(filePath); dwarf->mOrigImageData = new DbgModuleMemoryCache(dwarf->mImageBase, dwarf->mImageSize); - + CheckTargetBinary(dwarf); /*dbgModule->mOrigImageData = new uint8[dbgModule->mImageSize]; memset(dbgModule->mOrigImageData, 0xCC, dbgModule->mImageSize); @@ -163,11 +247,14 @@ String DebugTarget::UnloadDyn(addr_target imageBase) RemoveTargetData(); filePath = dwarf->mFilePath; + if (mTargetBinary == dwarf) + mTargetBinary = NULL; + delete dwarf; mDbgModules.erase(mDbgModules.begin() + i); return filePath; } - } + } return ""; } @@ -801,7 +888,10 @@ void DebugTarget::GetCompilerSettings() { if (!mCheckedCompilerSettings) { - DbgType* bfObjectType = GetMainDbgModule()->FindType("System.CompilerSettings", NULL, DbgLanguage_Beef); + auto dbgModule = GetMainDbgModule(); + if (dbgModule == NULL) + return; + DbgType* bfObjectType = dbgModule->FindType("System.CompilerSettings", NULL, DbgLanguage_Beef); if (bfObjectType != NULL) { bfObjectType->PopulateType(); diff --git a/IDEHelper/DebugTarget.h b/IDEHelper/DebugTarget.h index 93d3c420..5fb20f03 100644 --- a/IDEHelper/DebugTarget.h +++ b/IDEHelper/DebugTarget.h @@ -35,7 +35,10 @@ public: HotHeap* mHotHeap; int mLastHotHeapCleanIdx; - DbgModule* mTargetBinary; + String mTargetPath; + DbgModule* mLaunchBinary; + DbgModule* mTargetBinary; + //DbgModule* m Array mDbgModules; //DbgModule* mLastDWARF; HashSet mPendingSrcFileRehup; // Waiting to remove old/invalid line info @@ -69,8 +72,10 @@ protected: public: DebugTarget(WinDebugger* debugger); ~DebugTarget(); - - DbgModule* Init(const StringImpl& fileName, intptr imageBase = 0); + + DbgModule* Init(const StringImpl& launchPath, const StringImpl& targetPath, intptr imageBase = 0); + void SetupTargetBinary(); + void CheckTargetBinary(DbgModule* module); void CreateEmptyTarget(); DbgModule* HotLoad(const StringImpl& fileName, int hotIdx); DbgModule* SetupDyn(const StringImpl& filePath, DataStream* stream, intptr imageBase); diff --git a/IDEHelper/Debugger.h b/IDEHelper/Debugger.h index 06c0ca91..a496ab43 100644 --- a/IDEHelper/Debugger.h +++ b/IDEHelper/Debugger.h @@ -230,7 +230,7 @@ public: virtual void OutputRawMessage(const StringImpl& msg) = 0; virtual int GetAddrSize() = 0; virtual bool CanOpen(const StringImpl& fileName, DebuggerResult* outResult) = 0; - virtual void OpenFile(const StringImpl& fileName, const StringImpl& args, const StringImpl& workingDir, const Array& envBlock) = 0; + virtual void OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array& envBlock) = 0; virtual bool Attach(int processId, BfDbgAttachFlags attachFlags) = 0; virtual void Run() = 0; virtual void HotLoad(const Array& objectFiles, int hotIdx) = 0; diff --git a/IDEHelper/MiniDumpDebugger.cpp b/IDEHelper/MiniDumpDebugger.cpp index 10ba9f37..c0ab5a70 100644 --- a/IDEHelper/MiniDumpDebugger.cpp +++ b/IDEHelper/MiniDumpDebugger.cpp @@ -44,7 +44,10 @@ MiniDumpDebugger::MiniDumpDebugger(DebugManager* debugManager, DbgMiniDump* mini auto& module = moduleList.Modules[moduleIdx]; COFF* dbgModule = new COFF(mDebugTarget); if (mDebugTarget->mTargetBinary == NULL) + { + mDebugTarget->mLaunchBinary = dbgModule; mDebugTarget->mTargetBinary = dbgModule; + } dbgModule->mImageBase = module.BaseOfImage; dbgModule->mImageSize = module.SizeOfImage; diff --git a/IDEHelper/WinDebugger.cpp b/IDEHelper/WinDebugger.cpp index 31b5a13b..9b0b8a99 100644 --- a/IDEHelper/WinDebugger.cpp +++ b/IDEHelper/WinDebugger.cpp @@ -879,12 +879,12 @@ void WinDebugger::DebugThreadProc() if (!IsMiniDumpDebugger()) { - if (!DoOpenFile(mFileName, mArgs, mWorkingDir, mEnvBlock)) + if (!DoOpenFile(mLaunchPath, mArgs, mWorkingDir, mEnvBlock)) { if (mDbgProcessId != 0) OutputRawMessage("error Unable to attach to process"); else - OutputRawMessage(StrFormat("error Failed to launch: %s", mFileName.c_str())); + OutputRawMessage(StrFormat("error Failed to launch: %s", mLaunchPath.c_str())); mShuttingDown = true; mRunState = RunState_Terminated; } @@ -960,10 +960,11 @@ bool WinDebugger::CanOpen(const StringImpl& fileName, DebuggerResult* outResult) return canRead; } -void WinDebugger::OpenFile(const StringImpl& fileName, const StringImpl& args, const StringImpl& workingDir, const Array& envBlock) +void WinDebugger::OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array& envBlock) { BF_ASSERT(!mIsRunning); - mFileName = fileName; + mLaunchPath = launchPath; + mTargetPath = targetPath; mArgs = args; mWorkingDir = workingDir; mEnvBlock = envBlock; @@ -1000,7 +1001,8 @@ bool WinDebugger::Attach(int processId, BfDbgAttachFlags attachFlags) WCHAR fileName[MAX_PATH] = {0}; GetModuleFileNameExW(mDbgProcessHandle, mainModule, fileName, MAX_PATH); - mFileName = UTF8Encode(fileName); + mLaunchPath = UTF8Encode(fileName); + mTargetPath = mLaunchPath; mDbgProcessId = processId; mDbgProcessHandle = 0; @@ -1209,7 +1211,7 @@ bool WinDebugger::DoOpenFile(const StringImpl& fileName, const StringImpl& args, ContinueDebugEvent(); - if ((mDebugTarget->mTargetBinary != NULL) && (mDebugTarget->mTargetBinary->mOrigImageData != NULL)) + if ((mDebugTarget->mLaunchBinary != NULL) && (mDebugTarget->mLaunchBinary->mOrigImageData != NULL)) break; } @@ -1534,56 +1536,20 @@ bool WinDebugger::DoUpdate() BF_GetThreadContext(threadInfo->mHThread, &lcContext); threadInfo->mStartSP = BF_CONTEXT_SP(lcContext); - DbgModule* targetBinary = mDebugTarget->Init(mFileName, (addr_target)(intptr)mDebugEvent.u.CreateProcessInfo.lpBaseOfImage); + DbgModule* launchBinary = mDebugTarget->Init(mLaunchPath, mTargetPath, (addr_target)(intptr)mDebugEvent.u.CreateProcessInfo.lpBaseOfImage); addr_target gotImageBase = (addr_target)(intptr)mDebugEvent.u.CreateProcessInfo.lpBaseOfImage; - if (targetBinary->mImageBase != gotImageBase) + if (launchBinary->mImageBase != gotImageBase) { BF_FATAL("Image base didn't match"); } - targetBinary->mImageBase = gotImageBase; - targetBinary->mImageSize = (int)targetBinary->GetImageSize(); - targetBinary->mOrigImageData = new DbgModuleMemoryCache(targetBinary->mImageBase, targetBinary->mImageSize); + launchBinary->mImageBase = gotImageBase; + launchBinary->mImageSize = (int)launchBinary->GetImageSize(); + launchBinary->mOrigImageData = new DbgModuleMemoryCache(launchBinary->mImageBase, launchBinary->mImageSize); + + if (launchBinary == mDebugTarget->mTargetBinary) + mDebugTarget->SetupTargetBinary(); - bool wantsHotHeap = mDbgProcessId == 0; - -#ifdef BF_DBG_32 - if (wantsHotHeap) - mDebugTarget->mHotHeap = new HotHeap(); -#else - if (wantsHotHeap) - { - // 64-bit hot loaded code needs to be placed close to the original EXE so 32-bit relative - // offsets within the hot code can still reach the old code - addr_target checkHotReserveAddr = (addr_target)targetBinary->mImageBase + targetBinary->mImageSize; - int mb = 1024 * 1024; - int reserveSize = 512 * mb; - - // Round up to MB boundary + 64MB, to help keep other DLLs at their preferred base addresses - checkHotReserveAddr = ((checkHotReserveAddr + 64 * mb) & ~(mb - 1)); - - checkHotReserveAddr = (addr_target)targetBinary->mImageBase; - - addr_target reservedPtr = NULL; - while ((addr_target)checkHotReserveAddr < (addr_target)targetBinary->mImageBase + 0x30000000) - { - reservedPtr = (addr_target)VirtualAllocEx(mProcessInfo.hProcess, (void*)(intptr)checkHotReserveAddr, reserveSize, MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (reservedPtr != NULL) - break; - checkHotReserveAddr += 4 * mb; - } - - if (reservedPtr != 0) - { - BF_ASSERT(mDebugTarget->mHotHeap == NULL); - mDebugTarget->mHotHeap = new HotHeap(reservedPtr, reserveSize); - } - - //TODO: Throw actual error if we can't reserve HOT area - BF_ASSERT(reservedPtr != NULL); - } -#endif - if (mDebugEvent.u.CreateProcessInfo.hFile != NULL) CloseHandle(mDebugEvent.u.CreateProcessInfo.hFile); @@ -1700,7 +1666,7 @@ bool WinDebugger::DoUpdate() if (mDebugTarget->SetupDyn(moduleName, &stream, (intptr)mDebugEvent.u.LoadDll.lpBaseOfDll) == NULL) loadMsg += " - Failed to load"; stream.mFileHandle = 0; - } + } OutputMessage(loadMsg + "\n"); @@ -3225,7 +3191,7 @@ void WinDebugger::CheckBreakpoint(WdBreakpoint* wdBreakpoint) { if (symbolName == ".") { - targetAddr = mDebugTarget->mTargetBinary->mImageBase + mDebugTarget->mTargetBinary->mEntryPoint; + targetAddr = mDebugTarget->mLaunchBinary->mImageBase + mDebugTarget->mLaunchBinary->mEntryPoint; onlyBindFirst = true; } } @@ -4547,7 +4513,7 @@ bool WinDebugger::SetupStep(StepType stepType) } void WinDebugger::CheckNonDebuggerBreak() -{ +{ enum MessageType { MessageType_None = 0, @@ -4559,8 +4525,12 @@ void WinDebugger::CheckNonDebuggerBreak() PopulateRegisters(®isters); addr_target pcAddress = registers.GetPC(); - mDebugTarget->mTargetBinary->ParseSymbolData(); - addr_target debugMessageDataAddr = mDebugTarget->FindSymbolAddr("gBfDebugMessageData"); + addr_target debugMessageDataAddr = (addr_target)-1; + if (mDebugTarget->mTargetBinary != NULL) + { + mDebugTarget->mTargetBinary->ParseSymbolData(); + debugMessageDataAddr = mDebugTarget->FindSymbolAddr("gBfDebugMessageData"); + } if (debugMessageDataAddr != (addr_target)-1) { struct BfDebugMessageData @@ -4684,7 +4654,7 @@ void WinDebugger::CheckNonDebuggerBreak() DbgModule* dbgModule; if (mDebugTarget->FindSymbolAt(pcAddress, &symbol, &offset, &dbgModule)) { - if (symbol == "DbgBreakPoint") + if ((symbol == "DbgBreakPoint") || (symbol == "RtlUserThreadStart@8")) { showMainThread = true; } @@ -8859,15 +8829,18 @@ String WinDebugger::EvaluateContinue(DbgPendingExpr* pendingExpr, BfPassInstance if ((pendingExpr->mFormatInfo.mLanguage == DbgLanguage_Beef) && (mDebugTarget != NULL) && (mDebugTarget->mTargetBinary != NULL)) dbgModule = mDebugTarget->mTargetBinary; else - dbgModule = mEmptyDebugTarget->GetMainDbgModule(); + dbgModule = mEmptyDebugTarget->GetMainDbgModule(); } else { dbgModule = GetCallStackDbgModule(pendingExpr->mCallStackIdx); - if (!dbgModule->mDebugTarget->mIsEmpty) + if ((dbgModule != NULL) &&(!dbgModule->mDebugTarget->mIsEmpty)) dbgCompileUnit = GetCallStackCompileUnit(pendingExpr->mCallStackIdx); } + if (dbgModule == NULL) + dbgModule = mEmptyDebugTarget->GetMainDbgModule(); + if (!pendingExpr->mException.empty()) { RestoreAllRegisters(); @@ -9315,7 +9288,7 @@ String WinDebugger::Evaluate(const StringImpl& expr, DwFormatInfo formatInfo, in if (dbgSubprogram != NULL) curLanguage = dbgSubprogram->GetLanguage(); if (language != curLanguage) - { + { dbgModule = mDebugTarget->mTargetBinary; dbgSubprogram = NULL; formatInfo.mLanguage = language; @@ -10146,8 +10119,9 @@ String WinDebugger::GetThreadInfo() threadName = module->mDisplayName + " thread"; if ((mActiveThread == mExplicitStopThread) && (mActiveBreakpoint != NULL)) - { - if ((mActiveBreakpoint->mAddr < subProgram->mBlock.mLowPC) || + { + if ((subProgram == NULL) || + (mActiveBreakpoint->mAddr < subProgram->mBlock.mLowPC) || (mActiveBreakpoint->mAddr >= subProgram->mBlock.mHighPC)) break; } diff --git a/IDEHelper/WinDebugger.h b/IDEHelper/WinDebugger.h index e09f51c8..bcf53418 100644 --- a/IDEHelper/WinDebugger.h +++ b/IDEHelper/WinDebugger.h @@ -369,7 +369,8 @@ public: volatile bool mShuttingDown; volatile bool mIsRunning; bool mDestroying; - String mFileName; + String mLaunchPath; + String mTargetPath; String mArgs; String mWorkingDir; Array mEnvBlock; @@ -450,7 +451,7 @@ public: uint8 mMemCacheData[WD_MEMCACHE_SIZE]; public: - void Fail(const StringImpl& error); + void Fail(const StringImpl& error); void TryGetThreadName(WdThreadInfo* threadInfo); void ThreadRestorePause(WdThreadInfo* onlyPauseThread, WdThreadInfo* dontPauseThread); void ThreadRestoreUnpause(); @@ -479,7 +480,7 @@ public: virtual bool PopulateRegisters(CPURegisters* registers); bool RollBackStackFrame(CPURegisters* registers, bool isStackStart); bool SetHotJump(DbgSubprogram* oldSubprogram, DbgSubprogram* newSubprogram); - DbgSubprogram* TryFollowHotJump(DbgSubprogram* subprogram, addr_target addr); + DbgSubprogram* TryFollowHotJump(DbgSubprogram* subprogram, addr_target addr); bool ParseFormatInfo(DbgModule* dbgModule, const StringImpl& formatInfoStr, DwFormatInfo* formatInfo, BfPassInstance* bfPassInstance, int* assignExprOffset, String* assignExpr = NULL, String* errorString = NULL, DbgTypedValue contextTypedValue = DbgTypedValue()); String MaybeQuoteFormatInfoParam(const StringImpl& str); @@ -558,7 +559,7 @@ public: virtual void OutputRawMessage(const StringImpl& msg) override; virtual int GetAddrSize() override; virtual bool CanOpen(const StringImpl& fileName, DebuggerResult* outResult) override; - virtual void OpenFile(const StringImpl& fileName, const StringImpl& args, const StringImpl& workingDir, const Array& envBlock) override; + virtual void OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array& envBlock) override; virtual bool Attach(int processId, BfDbgAttachFlags attachFlags) override; virtual void Run() override; virtual void HotLoad(const Array& objectFiles, int hotIdx) override; diff --git a/bin/test_ide.bat b/bin/test_ide.bat index ecbf4c41..15168669 100644 --- a/bin/test_ide.bat +++ b/bin/test_ide.bat @@ -19,6 +19,10 @@ PUSHD %~dp0..\ @CALL :TEST @IF !ERRORLEVEL! NEQ 0 GOTO HADERROR +@SET TESTPATH=IDE\Tests\TestDynCrt1 +@CALL :TEST +@IF !ERRORLEVEL! NEQ 0 GOTO HADERROR + @SET TESTPATH=IDE\Tests\SlotTest @CALL :TEST @IF !ERRORLEVEL! NEQ 0 GOTO HADERROR