From f8c0f1afda78ef63af18850734006b1ba6c91a87 Mon Sep 17 00:00:00 2001 From: Stranger1992 <84292688+Stranger1992@users.noreply.github.com> Date: Sun, 27 Apr 2025 09:30:01 +0100 Subject: [PATCH 01/16] Update bug_report.yaml Cleaned up the bug report and streamlined the process of creating it. --- .github/ISSUE_TEMPLATE/bug_report.yaml | 155 +++++++++++-------------- 1 file changed, 70 insertions(+), 85 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index e123eab748..87d8f72a88 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -1,99 +1,84 @@ name: Bug report -description: Create a report to help us understand and diagnose your issue. Your contribution is welcomed and valued! It is highly recommended that you are using the latest version before submitting a bug report. -title: "[ bug Report ]" -labels: Awaiting Triage +description: Create a report to help us understand and triage your issue. +title: "" +labels: + - Awaiting Triage body: + - type: markdown + attributes: + value: | + ## Bug Report -- type: markdown - attributes: - value: | - Please follow this document in order to report a bug. It is highly recommended that you are using the latest version before submitting a bug report. + Please follow this document carefully to report a bug. -- type: dropdown - attributes: - label: TombEngine version - description: | - Please select the TombEngine Version from the dropdown list. - options: - - Development Build - - v1.8.0 (latest version) - - v1.7.1 - - v1.7.0 - - v1.5 - validations: - required: true + > **Important**: It is highly recommended that you use the latest version before submitting a bug report. -- type: dropdown - attributes: - label: Tomb Editor version - description: | - Please select the Tomb Editor version used from the dropdown list. - options: - - Development Build - - v1.8.0 (latest version) - - v1.7.2 - - v1.7.1 - - v1.7.0 - validations: - required: true + - type: dropdown + attributes: + label: TombEngine Version + description: | + Please select the TombEngine version you are using. + options: + - v1.8.1 (latest release) + - v1.8.0 + validations: + required: true -- type: textarea - attributes: - label: Describe the bug - description: | - Please provide A clear and concise description of what the bug is. - placeholder: | - Your bug report here. - validations: - required: true + - type: checkboxes + attributes: + label: Development Version + description: Are you submitting this report from a development build that has not been officially released? + options: + - label: Yes + - label: No + validations: + required: true -- type: textarea - attributes: - label: To Reproduce - description: | - To reproduce the behaviour, please provide detailed steps for the development team to follow. This can be done through screenshots or a written guide + - type: textarea + attributes: + label: Describe the Bug + description: | + Please provide a clear and concise description of what the issue is. + placeholder: | + Your bug report here. + validations: + required: true - **If the bug cannot be reproduced, and if the issue is not adequately explained, it will be closed without further investigation** - placeholder: | - Provide detailed reproducible steps here. - validations: - required: true + - type: textarea + attributes: + label: To Reproduce + description: | + Please provide detailed steps to reproduce the issue. + + **Note**: If the bug cannot be reproduced or the issue is not clearly explained, it may be closed without further investigation. + placeholder: | + Step-by-step reproduction instructions here. + validations: + required: true -- type: textarea - attributes: - label: Expected Behaviour - description: | - A clear and concise description of what you expected to happen. - placeholder: | - A description of what should happen here. - validations: - required: true + - type: textarea + attributes: + label: Expected Behaviour + description: | + What did you expect to happen? -- type: textarea - attributes: - label: Additional Content - description: | - Add any other context about the problem here. + **Note**: If the bug cannot be reproduced or the issue is not clearly explained, it may be closed without further investigation. + placeholder: | + A description of what should happen here. + validations: + required: true - * Are you testing an build of a TombEngine that has not yet been released? If so please give some context. - * Did you get any asset from the TombEngine website that has presented a bug? - placeholder: | - A description of any additional content here. - validations: - required: false - -- type: textarea - attributes: - label: Minimal reproduction project - description: | - **Please upload a .zip file containing your level and all assets needed to compile the level and a cut-down version of your level where the bug presents itself** - The project can be uploaded as a zip file (10 mb max) or provide a link from google drive, dropbox etc. - **Note** if you do not provide this, your issue may be rejected - placeholder: | - Download link to your project - validations: - required: true - + - type: textarea + attributes: + label: Minimal Reproduction Project + description: | + Please upload a .zip file (10 MB max) containing your level and all assets needed to compile the level, including a minimal version where the bug occurs. + Alternatively, provide a download link from a cloud storage service (e.g., Google Drive, Dropbox). + > **Important**: If you do not provide a minimal reproduction project, your issue may be rejected. + placeholder: | + Download link to your project or attach a .zip file. + validations: + required: true From 05949c1cb2ddd91dca0dd05d6c816c362e16f141 Mon Sep 17 00:00:00 2001 From: Stranger1992 <84292688+Stranger1992@users.noreply.github.com> Date: Sun, 27 Apr 2025 09:31:36 +0100 Subject: [PATCH 02/16] Update bug_report.yaml --- .github/ISSUE_TEMPLATE/bug_report.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 87d8f72a88..b4df0b7948 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -1,6 +1,5 @@ name: Bug report description: Create a report to help us understand and triage your issue. -title: "" labels: - Awaiting Triage @@ -30,8 +29,8 @@ body: label: Development Version description: Are you submitting this report from a development build that has not been officially released? options: - - label: Yes - - label: No + - label: "I am using an unofficial development version." + - label: "I am using an official release." validations: required: true From cd4c9b4645167c381c1755a9a8402fde5febad19 Mon Sep 17 00:00:00 2001 From: Stranger1992 <84292688+Stranger1992@users.noreply.github.com> Date: Sun, 27 Apr 2025 09:33:01 +0100 Subject: [PATCH 03/16] Update bug_report.yaml --- .github/ISSUE_TEMPLATE/bug_report.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index b4df0b7948..cbf6c1e59e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -15,7 +15,7 @@ body: - type: dropdown attributes: - label: TombEngine Version + label: Tomb Engine Version description: | Please select the TombEngine version you are using. options: From 94e095fb5342451c14d799c4d4540888201409dd Mon Sep 17 00:00:00 2001 From: Stranger1992 <84292688+Stranger1992@users.noreply.github.com> Date: Sun, 1 Jun 2025 15:55:25 +0100 Subject: [PATCH 04/16] Update bug_report.yaml --- .github/ISSUE_TEMPLATE/bug_report.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index cbf6c1e59e..592411413b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -19,7 +19,8 @@ body: description: | Please select the TombEngine version you are using. options: - - v1.8.1 (latest release) + - v1.9.0 (Pre-release) + - v1.8.1 (latest public release) - v1.8.0 validations: required: true @@ -31,6 +32,7 @@ body: options: - label: "I am using an unofficial development version." - label: "I am using an official release." + - label: "I am using an official pre-release." validations: required: true From 37001e5be9aec936abb065f5e165191b8bc3c744 Mon Sep 17 00:00:00 2001 From: Stranger1992 <84292688+Stranger1992@users.noreply.github.com> Date: Sat, 14 Jun 2025 07:57:44 +0100 Subject: [PATCH 05/16] Update README.md Added reference to skinning support. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5f699f1622..76a8ebd63f 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ - *Lua* as the native scripting language. - Many objects from the original series (1-5). - Support for high framerate, antialiasing, mipmapping, and SSAO. +- Full skinning support for all objects - Full diagonal geometry support. - Uncapped map size. - A streamlined player control scheme. @@ -38,4 +39,4 @@ Once done, you should be able to build a level with *Tomb Editor* and run it in Contributions are welcome. If you would like to participate in development to any degree, whether that be through suggestions, bug reports, or code, join our [Discord server](https://discord.gg/h5tUYFmres). # Disclaimer -Tomb Engine uses modified MIT license for non-commercial use only. For more information, see [license](https://github.com/TombEngine/TombEngine?tab=License-1-ov-file#readme). Tomb Engine is unaffiliated with the Crystal Dynamics group of companies or Embracer Group AB. *Tomb Raider* is a trademark of the Crystal Dynamics group of companies. Tomb Engine team is not responsible for illegal use of this source code and built binaries alone or in combination with third-party assets or components. This source code is released as-is and continues to be maintained by non-paid contributors in their free time. \ No newline at end of file +Tomb Engine uses modified MIT license for non-commercial use only. For more information, see [license](https://github.com/TombEngine/TombEngine?tab=License-1-ov-file#readme). Tomb Engine is unaffiliated with the Crystal Dynamics group of companies or Embracer Group AB. *Tomb Raider* is a trademark of the Crystal Dynamics group of companies. Tomb Engine team is not responsible for illegal use of this source code and built binaries alone or in combination with third-party assets or components. This source code is released as-is and continues to be maintained by non-paid contributors in their free time. From ca30a69814e6f4731b727a31b9941f034e5a9556 Mon Sep 17 00:00:00 2001 From: Stranger1992 <84292688+Stranger1992@users.noreply.github.com> Date: Wed, 18 Jun 2025 18:45:28 +0100 Subject: [PATCH 06/16] Update bug_report.yaml --- .github/ISSUE_TEMPLATE/bug_report.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 592411413b..333c429a24 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -19,9 +19,9 @@ body: description: | Please select the TombEngine version you are using. options: - - v1.9.0 (Pre-release) - - v1.8.1 (latest public release) - - v1.8.0 + - Development build + - v1.9.0 (latest public release) + - v1.8.1 validations: required: true From d268f6659de17bf56a8b278005e77b0002f3d2af Mon Sep 17 00:00:00 2001 From: Lwmte <3331699+Lwmte@users.noreply.github.com> Date: Sun, 22 Jun 2025 11:09:39 +0300 Subject: [PATCH 07/16] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 76a8ebd63f..88b45dd54d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ - *Lua* as the native scripting language. - Many objects from the original series (1-5). - Support for high framerate, antialiasing, mipmapping, and SSAO. -- Full skinning support for all objects +- Full skinning support for all objects. - Full diagonal geometry support. - Uncapped map size. - A streamlined player control scheme. From 6aea42463613a7d62493914745586386dfe1d8c4 Mon Sep 17 00:00:00 2001 From: Stranger1992 <84292688+Stranger1992@users.noreply.github.com> Date: Sun, 17 Aug 2025 12:55:52 +0100 Subject: [PATCH 08/16] Update bug_report.yaml --- .github/ISSUE_TEMPLATE/bug_report.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 333c429a24..755bfb370a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -20,8 +20,8 @@ body: Please select the TombEngine version you are using. options: - Development build - - v1.9.0 (latest public release) - - v1.8.1 + - v1.9.2 (latest public release) + - v1.9.1 validations: required: true From 50ea441f83673245a610ede060b366df1d9e1fe4 Mon Sep 17 00:00:00 2001 From: Stranger1992 <84292688+Stranger1992@users.noreply.github.com> Date: Tue, 11 Nov 2025 21:45:38 +0000 Subject: [PATCH 09/16] Update bug_report.yaml --- .github/ISSUE_TEMPLATE/bug_report.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 755bfb370a..90c42f4091 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -20,8 +20,8 @@ body: Please select the TombEngine version you are using. options: - Development build - - v1.9.2 (latest public release) - - v1.9.1 + - v1.10.0 (latest public release) + - v1.9.2 validations: required: true From 8e09754f1404068d4d5ab9ca8448e0602cac7532 Mon Sep 17 00:00:00 2001 From: Stranger1992 <84292688+Stranger1992@users.noreply.github.com> Date: Sun, 23 Nov 2025 22:40:09 +0000 Subject: [PATCH 10/16] Updated Bug Report form for 1.10.1 --- .github/ISSUE_TEMPLATE/bug_report.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 90c42f4091..8c6effd1d7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -20,8 +20,8 @@ body: Please select the TombEngine version you are using. options: - Development build - - v1.10.0 (latest public release) - - v1.9.2 + - v1.10.1 (latest public release) + - v1.10.0 validations: required: true From 308a42c1f989fdfe669492615819452b48b77572 Mon Sep 17 00:00:00 2001 From: Lwmte <3331699+Lwmte@users.noreply.github.com> Date: Sun, 15 Mar 2026 12:04:17 +0100 Subject: [PATCH 11/16] Update bug_report.yaml --- .github/ISSUE_TEMPLATE/bug_report.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 8c6effd1d7..7bd666036e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -20,8 +20,8 @@ body: Please select the TombEngine version you are using. options: - Development build - - v1.10.1 (latest public release) - - v1.10.0 + - v1.11 (latest public release) + - v1.10.1 validations: required: true From 0954dbe7908e0d8a103af6b72d32cd776f3a2ec7 Mon Sep 17 00:00:00 2001 From: Stranger1992 <84292688+Stranger1992@users.noreply.github.com> Date: Tue, 17 Mar 2026 02:15:59 +0000 Subject: [PATCH 12/16] Add cross-repo dependency check workflow This workflow checks for cross-repo dependencies in pull requests and sets the commit status accordingly. This is for merging branches in the Tomb Editor and Tomb Engine repo that require both sides to be merged before the changes are completed. --- .github/workflows/cross-repo-dependency.yml | 78 +++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 .github/workflows/cross-repo-dependency.yml diff --git a/.github/workflows/cross-repo-dependency.yml b/.github/workflows/cross-repo-dependency.yml new file mode 100644 index 0000000000..a5bea6db84 --- /dev/null +++ b/.github/workflows/cross-repo-dependency.yml @@ -0,0 +1,78 @@ +name: Cross repo dependency + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + pull_request_review: + types: [submitted] + +jobs: + check-linked-pr: + runs-on: ubuntu-latest + steps: + - name: Check for dependency and set status + uses: actions/github-script@v7 + with: + script: | + const pr = context.payload.pull_request; + const body = pr.body || ""; + + // Look for: Depends on: org/repo#123 + const match = body.match(/Depends on:\s+([\w-]+)\/([\w-]+)#(\d+)/); + + const owner = context.repo.owner; + const repo = context.repo.repo; + const sha = pr.head.sha; + + if (!match) { + // No dependency → pass + await github.rest.repos.createCommitStatus({ + owner, + repo, + sha, + state: "success", + context: "cross-repo-dependency", + description: "No cross-repo dependency" + }); + return; + } + + const depOwner = match[1]; + const depRepo = match[2]; + const depNumber = Number(match[3]); + + // Get linked PR + const linked = await github.rest.pulls.get({ + owner: depOwner, + repo: depRepo, + pull_number: depNumber + }); + + // Get reviews to see if it has at least one APPROVED + const reviews = await github.rest.pulls.listReviews({ + owner: depOwner, + repo: depRepo, + pull_number: depNumber + }); + + const approved = reviews.data.some(r => r.state === "APPROVED"); + + // mergeable can be null while GitHub is still calculating; treat that as not ready + const mergeable = linked.data.mergeable === true; + + let state = "pending"; + let description = "Waiting for linked PR to be approved and mergeable"; + + if (approved && mergeable) { + state = "success"; + description = `Linked PR ${depOwner}/${depRepo}#${depNumber} is approved and mergeable`; + } + + await github.rest.repos.createCommitStatus({ + owner, + repo, + sha, + state, + context: "cross-repo-dependency", + description + }); From 25b81d825a566248f3d2f29fb42d199b6fdd07bd Mon Sep 17 00:00:00 2001 From: Stranger1992 <84292688+Stranger1992@users.noreply.github.com> Date: Tue, 17 Mar 2026 02:30:41 +0000 Subject: [PATCH 13/16] Refactor dependency check workflow steps Refactor cross-repo dependency check to improve clarity and functionality. --- .github/workflows/cross-repo-dependency.yml | 79 ++++++++++++--------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/.github/workflows/cross-repo-dependency.yml b/.github/workflows/cross-repo-dependency.yml index a5bea6db84..afad434580 100644 --- a/.github/workflows/cross-repo-dependency.yml +++ b/.github/workflows/cross-repo-dependency.yml @@ -10,68 +10,77 @@ jobs: check-linked-pr: runs-on: ubuntu-latest steps: - - name: Check for dependency and set status + - name: Check for dependency + id: parse uses: actions/github-script@v7 with: script: | - const pr = context.payload.pull_request; - const body = pr.body || ""; - - // Look for: Depends on: org/repo#123 + const body = context.payload.pull_request.body || ""; const match = body.match(/Depends on:\s+([\w-]+)\/([\w-]+)#(\d+)/); - const owner = context.repo.owner; - const repo = context.repo.repo; - const sha = pr.head.sha; - if (!match) { - // No dependency → pass - await github.rest.repos.createCommitStatus({ - owner, - repo, - sha, - state: "success", - context: "cross-repo-dependency", - description: "No cross-repo dependency" - }); + // No dependency → do NOT create a status check + core.setOutput("skip", "true"); return; } - const depOwner = match[1]; - const depRepo = match[2]; - const depNumber = Number(match[3]); + core.setOutput("skip", "false"); + core.setOutput("depOwner", match[1]); + core.setOutput("depRepo", match[2]); + core.setOutput("depNumber", match[3]); + + - name: Exit early if no dependency + if: steps.parse.outputs.skip == 'true' + run: echo "No dependency found — skipping." + + - name: Check linked PR status + if: steps.parse.outputs.skip == 'false' + id: check + uses: actions/github-script@v7 + with: + script: | + const owner = steps.parse.outputs.depOwner; + const repo = steps.parse.outputs.depRepo; + const number = Number(steps.parse.outputs.depNumber); - // Get linked PR const linked = await github.rest.pulls.get({ - owner: depOwner, - repo: depRepo, - pull_number: depNumber + owner, + repo, + pull_number: number }); - // Get reviews to see if it has at least one APPROVED const reviews = await github.rest.pulls.listReviews({ - owner: depOwner, - repo: depRepo, - pull_number: depNumber + owner, + repo, + pull_number: number }); const approved = reviews.data.some(r => r.state === "APPROVED"); - - // mergeable can be null while GitHub is still calculating; treat that as not ready const mergeable = linked.data.mergeable === true; + core.setOutput("approved", approved); + core.setOutput("mergeable", mergeable); + + - name: Set dependency status + if: steps.parse.outputs.skip == 'false' + uses: actions/github-script@v7 + with: + script: | + const approved = steps.check.outputs.approved === 'true'; + const mergeable = steps.check.outputs.mergeable === 'true'; + let state = "pending"; let description = "Waiting for linked PR to be approved and mergeable"; if (approved && mergeable) { state = "success"; - description = `Linked PR ${depOwner}/${depRepo}#${depNumber} is approved and mergeable`; + description = "Linked PR is approved and mergeable"; } await github.rest.repos.createCommitStatus({ - owner, - repo, - sha, + owner: context.repo.owner, + repo: context.repo.repo, + sha: context.payload.pull_request.head.sha, state, context: "cross-repo-dependency", description From 28306e3e3f5ebea8c19a3006b7b9169407874258 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 00:07:38 +0000 Subject: [PATCH 14/16] Fix merge conflicts: Update RendererString for Vector2 Scale and new features Agent-Logs-Url: https://github.com/TrainWrack/TombEngine/sessions/eeb30453-a1e0-423e-9279-9fc2a1199c56 Co-authored-by: TrainWrack <120750885+TrainWrack@users.noreply.github.com> --- TombEngine/Game/effects/DisplaySprite.cpp | 26 ++++ TombEngine/Game/effects/DisplaySprite.h | 9 ++ TombEngine/Renderer/Renderer.h | 3 + TombEngine/Renderer/RendererString.cpp | 119 ++++++++++++++++-- .../Structures/RendererStringToDraw.h | 11 +- 5 files changed, 154 insertions(+), 14 deletions(-) diff --git a/TombEngine/Game/effects/DisplaySprite.cpp b/TombEngine/Game/effects/DisplaySprite.cpp index dd3713d6b3..0b195cf683 100644 --- a/TombEngine/Game/effects/DisplaySprite.cpp +++ b/TombEngine/Game/effects/DisplaySprite.cpp @@ -13,6 +13,30 @@ namespace TEN::Effects::DisplaySprite { std::vector DisplaySprites = {}; + static bool g_hasActiveDisplayScissor = false; + static TEN::Renderer::Structures::RendererRectangle g_activeDisplayScissorRect = {}; + + void SetActiveDisplayScissor(const TEN::Renderer::Structures::RendererRectangle& rect) + { + g_hasActiveDisplayScissor = true; + g_activeDisplayScissorRect = rect; + } + + void ClearActiveDisplayScissor() + { + g_hasActiveDisplayScissor = false; + } + + bool HasActiveDisplayScissor() + { + return g_hasActiveDisplayScissor; + } + + const TEN::Renderer::Structures::RendererRectangle& GetActiveDisplayScissor() + { + return g_activeDisplayScissorRect; + } + void AddDisplaySprite(GAME_OBJECT_ID objectID, int spriteID, const Vector2& pos, short orient, const Vector2& scale, const Vector4& color, int priority, DisplaySpriteAlignMode alignMode, DisplaySpriteScaleMode scaleMode, BlendMode blendMode, DisplaySpritePhase source) @@ -29,6 +53,8 @@ namespace TEN::Effects::DisplaySprite displaySprite.ScaleMode = scaleMode; displaySprite.BlendMode = blendMode; displaySprite.Source = source; + displaySprite.HasScissor = g_hasActiveDisplayScissor; + displaySprite.ScissorRect = g_activeDisplayScissorRect; DisplaySprites.push_back(displaySprite); } diff --git a/TombEngine/Game/effects/DisplaySprite.h b/TombEngine/Game/effects/DisplaySprite.h index cb325ea63b..103310fe52 100644 --- a/TombEngine/Game/effects/DisplaySprite.h +++ b/TombEngine/Game/effects/DisplaySprite.h @@ -2,6 +2,7 @@ #include "Math/Math.h" #include "Objects/game_object_ids.h" #include "Renderer/RendererEnums.h" +#include "Renderer/Structures/RendererRectangle.h" namespace TEN::Effects::DisplaySprite { @@ -47,6 +48,9 @@ namespace TEN::Effects::DisplaySprite BlendMode BlendMode = BlendMode::AlphaBlend; DisplaySpritePhase Source = DisplaySpritePhase::Control; + + bool HasScissor = false; + TEN::Renderer::Structures::RendererRectangle ScissorRect = {}; }; // Result of display sprite layout calculation. @@ -65,6 +69,11 @@ namespace TEN::Effects::DisplaySprite void ClearAllDisplaySprites(); void ClearDrawPhaseDisplaySprites(); + void SetActiveDisplayScissor(const TEN::Renderer::Structures::RendererRectangle& rect); + void ClearActiveDisplayScissor(); + bool HasActiveDisplayScissor(); + const TEN::Renderer::Structures::RendererRectangle& GetActiveDisplayScissor(); + // Calculate complete layout data for a display sprite. // // NOTE: This function is defined inline in the header for performance reasons. diff --git a/TombEngine/Renderer/Renderer.h b/TombEngine/Renderer/Renderer.h index 030f91b5fb..81d073aeac 100644 --- a/TombEngine/Renderer/Renderer.h +++ b/TombEngine/Renderer/Renderer.h @@ -429,6 +429,7 @@ namespace TEN::Renderer void InitializeGameBars(); void InitializeMenuBars(int y); void InitializeSky(); + void AddStringInternal(const std::string& string, const Vector2& pos, const Vector2& prevPos, const Vector2& area, const Color& color, const Vector2& scale, float rotation, int flags, int priority, BlendMode blendMode); void DrawAllStrings(); void PrepareDynamicLight(RendererLight& light); void PrepareLaserBarriers(RenderView& view); @@ -741,6 +742,8 @@ namespace TEN::Renderer void AddString(const std::string& string, const Vector2& pos, const Color& color, float scale, int flags); void AddString(const std::string& string, const Vector2& pos, const Vector2& area, const Color& color, float scale, int flags); void AddString(const std::string& string, const Vector2& currentPos, const Vector2& prevPos, const Vector2& area, const Color& color, float scale, int flags); + void AddString(const std::string& string, const Vector2& pos, const Vector2& prevPos, const Vector2& area, const Color& color, const Vector2& scale, float rotation, int flags, int priority, BlendMode blendMode); + Vector2 GetDisplayStringSize(const std::string& text, const Vector2& scale = Vector2::One) const; void AddDebugString(const std::string& string, const Vector2& pos, const Color& color, float scale, RendererDebugPage page = RendererDebugPage::None); void FreeRendererData(); void AddDynamicPointLight(const Vector3& pos, float radius, const Color& color, bool castShadows, int hash = 0); diff --git a/TombEngine/Renderer/RendererString.cpp b/TombEngine/Renderer/RendererString.cpp index a064e7c947..6777db3e6e 100644 --- a/TombEngine/Renderer/RendererString.cpp +++ b/TombEngine/Renderer/RendererString.cpp @@ -1,9 +1,15 @@ #include "framework.h" #include "Renderer/Renderer.h" +#include + +#include "Game/effects/DisplaySprite.h" #include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h" #include "Specific/trutils.h" +using namespace TEN::Effects::DisplaySprite; +using namespace TEN::Utils; + namespace TEN::Renderer { void Renderer::AddDebugString(const std::string& string, const Vector2& pos, const Color& color, float scale, RendererDebugPage page) @@ -24,6 +30,26 @@ namespace TEN::Renderer AddString(string, Vector2(x, y), Color(color), 1.0f, flags); } + Vector2 Renderer::GetDisplayStringSize(const std::string& text, const Vector2& scale) const + { + if (text.empty() || _gameFont == nullptr) + return Vector2::Zero; + + auto screenRes = GetScreenResolution(); + auto factor = Vector2((float)screenRes.x / DISPLAY_SPACE_RES.x, (float)screenRes.y / DISPLAY_SPACE_RES.y); + float uiScale = (screenRes.x > screenRes.y) ? factor.y : factor.x; + float fontSpacing = _gameFont->GetLineSpacing(); + float fontScale = REFERENCE_FONT_SIZE / fontSpacing; + auto stringScale = Vector2(uiScale * fontScale) * scale; + float baseScale = stringScale.y; + + auto wtext = TEN::Utils::ToWString(text); + auto measured = Vector2(_gameFont->MeasureString(wtext.c_str())) * baseScale; + + // Convert pixel size back to display space (800x600 units). + return Vector2(measured.x / factor.x, measured.y / factor.y); + } + void Renderer::AddString(const std::string& string, const Vector2& pos, const Color& color, float scale, int flags) { AddString(string, pos, Vector2::Zero, Color(color), scale, flags); @@ -34,7 +60,21 @@ namespace TEN::Renderer AddString(string, pos, pos, area, color, scale, flags); } + void Renderer::AddString(const std::string& string, const Vector2& pos, const Vector2& prevPos, const Vector2& area, + const Color& color, const Vector2& scale, float rotation, int flags, + int priority, BlendMode blendMode) + { + AddStringInternal(string, pos, prevPos, area, color, scale, rotation, flags, priority, blendMode); + } + void Renderer::AddString(const std::string& string, const Vector2& pos, const Vector2& prevPos, const Vector2& area, const Color& color, float scale, int flags) + { + AddStringInternal(string, pos, prevPos, area, color, Vector2(scale), 0.0f, flags, 0, BlendMode::AlphaBlend); + } + + void Renderer::AddStringInternal(const std::string& string, const Vector2& pos, const Vector2& prevPos, const Vector2& area, + const Color& color, const Vector2& scale, float rotation, int flags, + int priority, BlendMode blendMode) { if (_isLocked) return; @@ -49,8 +89,9 @@ namespace TEN::Renderer float uiScale = (screenRes.x > screenRes.y) ? factor.y : factor.x; float fontSpacing = _gameFont->GetLineSpacing(); float fontScale = REFERENCE_FONT_SIZE / fontSpacing; - float stringScale = (uiScale * fontScale) * scale; - float spaceWidth = Vector3(_gameFont->MeasureString(L" ")).x * stringScale; + auto stringScale = Vector2(uiScale * fontScale) * scale; + float baseScale = stringScale.y; + float spaceWidth = Vector3(_gameFont->MeasureString(L" ")).x * baseScale; std::vector stringLines; @@ -74,7 +115,7 @@ namespace TEN::Renderer for (const auto& word : words) { - float wordWidth = Vector3(_gameFont->MeasureString(word.c_str())).x * stringScale; + float wordWidth = Vector3(_gameFont->MeasureString(word.c_str())).x * baseScale; if (!currentLine.empty() && (currentLineWidth + wordWidth + spaceWidth > area.x * factor.x)) { @@ -107,9 +148,9 @@ namespace TEN::Renderer for (const auto& line : stringLines) { if (line.empty()) - totalHeight += fontSpacing * stringScale; + totalHeight += fontSpacing * baseScale; else - totalHeight += Vector2(_gameFont->MeasureString(line.c_str())).y * stringScale; + totalHeight += Vector2(_gameFont->MeasureString(line.c_str())).y * stringScale.y; } // Calculate maximum textbox height. @@ -142,9 +183,15 @@ namespace TEN::Renderer rString.Position = Vector2::Zero; rString.Color = color; rString.Scale = stringScale; + rString.Rotation = rotation; + rString.Priority = priority; + rString.Blend = blendMode; + rString.HasScissor = HasActiveDisplayScissor(); + if (rString.HasScissor) + rString.ScissorRect = GetActiveDisplayScissor(); // Measure string. - auto stringSize = line.empty() ? Vector2(0, fontSpacing * rString.Scale) : Vector2(_gameFont->MeasureString(line.c_str())) * rString.Scale; + auto stringSize = line.empty() ? Vector2(0, fontSpacing * rString.Scale.y) : Vector2(_gameFont->MeasureString(line.c_str())) * rString.Scale.y; // If height clipping enabled, stop drawing when exceeding maxHeight. if (maxHeight > 0.0f && (yOffset + stringSize.y) > maxHeight) @@ -164,7 +211,7 @@ namespace TEN::Renderer else { // Calculate indentation to account for string scaling. - auto indent = line.empty() ? 0 : _gameFont->FindGlyph(line.at(0))->XAdvance * rString.Scale; + auto indent = line.empty() ? 0 : _gameFont->FindGlyph(line.at(0))->XAdvance * rString.Scale.y; rString.Position.x = pos.x * factor.x + indent; rString.PrevPosition.x = prevPos.x * factor.x + indent; @@ -194,35 +241,81 @@ namespace TEN::Renderer if (_stringsToDraw.empty()) return; - SetBlendMode(BlendMode::AlphaBlend); + // Sort by priority (lower priority draws first, i.e. behind higher). + std::stable_sort(_stringsToDraw.begin(), _stringsToDraw.end(), + [](const auto& a, const auto& b) { return a.Priority < b.Priority; }); float shadowOffset = 1.5f / (REFERENCE_FONT_SIZE / _gameFont->GetLineSpacing()); auto shadowColor = (Vector4)g_GameFlow->GetSettings()->UI.ShadowTextColor; - _spriteBatch->Begin(); + ResetScissor(); + _spriteBatch->Begin(SpriteSortMode_Deferred, nullptr, nullptr, nullptr, _cullNoneRasterizerState.Get()); + + auto currentBlend = BlendMode::AlphaBlend; + SetBlendMode(currentBlend); + + bool currentHasScissor = false; + auto currentScissor = RendererRectangle{}; for (const auto& rString : _stringsToDraw) { + // Switch blend mode per string if needed. + if (rString.Blend != currentBlend) + { + _spriteBatch->End(); + currentBlend = rString.Blend; + SetBlendMode(currentBlend); + _spriteBatch->Begin(SpriteSortMode_Deferred, nullptr, nullptr, nullptr, _cullNoneRasterizerState.Get()); + } + + // Handle scissor rect changes. + bool scissorChanged = (rString.HasScissor != currentHasScissor) || + (rString.HasScissor && + (rString.ScissorRect.Left != currentScissor.Left || + rString.ScissorRect.Top != currentScissor.Top || + rString.ScissorRect.Right != currentScissor.Right || + rString.ScissorRect.Bottom != currentScissor.Bottom)); + + if (scissorChanged) + { + _spriteBatch->End(); + + if (rString.HasScissor) + SetScissor(rString.ScissorRect); + else + ResetScissor(); + + currentHasScissor = rString.HasScissor; + currentScissor = rString.ScissorRect; + _spriteBatch->Begin(SpriteSortMode_Deferred, nullptr, nullptr, nullptr, _cullNoneRasterizerState.Get()); + } + auto drawPos = Vector2::Lerp(rString.PrevPosition, rString.Position, GetInterpolationFactor()); // Draw shadow. if (rString.Flags & (int)PrintStringFlags::Outline) { + auto shadowPos = Vector2(drawPos.x + shadowOffset * rString.Scale.y, drawPos.y + shadowOffset * rString.Scale.y); + _gameFont->DrawString( _spriteBatch.get(), rString.String.c_str(), - Vector2(drawPos.x + shadowOffset * rString.Scale, drawPos.y + shadowOffset * rString.Scale), + shadowPos, (shadowColor * rString.Color.w * shadowColor.w) * ScreenFadeCurrent, - 0.0f, Vector4::Zero, rString.Scale); + 0.0f, Vector2::Zero, rString.Scale.y); } // Draw string. _gameFont->DrawString( _spriteBatch.get(), rString.String.c_str(), - Vector2(drawPos.x, drawPos.y), + drawPos, (rString.Color * rString.Color.w) * ScreenFadeCurrent, - 0.0f, Vector4::Zero, rString.Scale); + 0.0f, Vector2::Zero, rString.Scale.y); } _spriteBatch->End(); + + // Reset scissor if it was active. + if (currentHasScissor) + ResetScissor(); } } diff --git a/TombEngine/Renderer/Structures/RendererStringToDraw.h b/TombEngine/Renderer/Structures/RendererStringToDraw.h index 379dba178d..93a28572d8 100644 --- a/TombEngine/Renderer/Structures/RendererStringToDraw.h +++ b/TombEngine/Renderer/Structures/RendererStringToDraw.h @@ -1,6 +1,9 @@ #pragma once #include +#include "Renderer/RendererEnums.h" +#include "Renderer/Structures/RendererRectangle.h" + namespace TEN::Renderer::Structures { using namespace DirectX::SimpleMath; @@ -12,6 +15,12 @@ namespace TEN::Renderer::Structures int Flags; std::wstring String; Vector4 Color; - float Scale; + Vector2 Scale; + float Rotation = 0.0f; + int Priority = 0; + BlendMode Blend = BlendMode::AlphaBlend; + + bool HasScissor = false; + RendererRectangle ScissorRect = {}; }; } From 35934cafb258c2353ebc4fae807800ee6b5e4843 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 00:08:35 +0000 Subject: [PATCH 15/16] Fix DrawString calls to use Vector2 scale and rotation Agent-Logs-Url: https://github.com/TrainWrack/TombEngine/sessions/eeb30453-a1e0-423e-9279-9fc2a1199c56 Co-authored-by: TrainWrack <120750885+TrainWrack@users.noreply.github.com> --- TombEngine/Renderer/RendererString.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TombEngine/Renderer/RendererString.cpp b/TombEngine/Renderer/RendererString.cpp index 6777db3e6e..949dbd3450 100644 --- a/TombEngine/Renderer/RendererString.cpp +++ b/TombEngine/Renderer/RendererString.cpp @@ -301,7 +301,7 @@ namespace TEN::Renderer _spriteBatch.get(), rString.String.c_str(), shadowPos, (shadowColor * rString.Color.w * shadowColor.w) * ScreenFadeCurrent, - 0.0f, Vector2::Zero, rString.Scale.y); + rString.Rotation, Vector2::Zero, rString.Scale); } // Draw string. @@ -309,7 +309,7 @@ namespace TEN::Renderer _spriteBatch.get(), rString.String.c_str(), drawPos, (rString.Color * rString.Color.w) * ScreenFadeCurrent, - 0.0f, Vector2::Zero, rString.Scale.y); + rString.Rotation, Vector2::Zero, rString.Scale); } _spriteBatch->End(); From 8661bc851fb5cb7ec8f4996ed483dc77ee70baec Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 00:09:31 +0000 Subject: [PATCH 16/16] Add scissor support to RendererSprite2D structure Agent-Logs-Url: https://github.com/TrainWrack/TombEngine/sessions/eeb30453-a1e0-423e-9279-9fc2a1199c56 Co-authored-by: TrainWrack <120750885+TrainWrack@users.noreply.github.com> --- TombEngine/Renderer/Structures/RendererSprite2D.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/TombEngine/Renderer/Structures/RendererSprite2D.h b/TombEngine/Renderer/Structures/RendererSprite2D.h index 50c4ecb011..ed4389dbd2 100644 --- a/TombEngine/Renderer/Structures/RendererSprite2D.h +++ b/TombEngine/Renderer/Structures/RendererSprite2D.h @@ -2,6 +2,7 @@ #include "Renderer/Structures/RendererSprite.h" #include "Renderer/RendererEnums.h" +#include "Renderer/Structures/RendererRectangle.h" namespace TEN::Renderer::Structures { @@ -18,5 +19,8 @@ namespace TEN::Renderer::Structures BlendMode BlendMode = BlendMode::AlphaBlend; Vector2 AspectCorrection = Vector2::One; + + bool HasScissor = false; + RendererRectangle ScissorRect = {}; }; }