Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions cont/base/springcontent/shaders/GLSL/ModelVertProgGL4.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ Transform Lerp(Transform t0, Transform t1, float a) {

void GetModelSpaceVertex(out vec4 msPosition, out vec3 msNormal)
{
bool staticModel = (matrixMode > 0);
bool staticModel = (matrixMode == MATMODE_STATIC || matrixMode == MATMODE_ARRAY);

vec4 piecePos = vec4(pos, 1.0);
vec4 normal4 = vec4(normal, 0.0);
Expand All @@ -271,7 +271,10 @@ void GetModelSpaceVertex(out vec4 msPosition, out vec3 msNormal)

Transform tx;
if (staticModel) {
tx = transforms[instData.x + bID0];
// pieces always come from the bind-pose block (instData.w). In ARRAY_MATMODE
// instData.x is the per-instance world transform, not the bind pose; for static
// model submits instData.x == instData.w anyway, so instData.w is correct for both.
tx = transforms[instData.w + bID0];
} else {
// do interpolation
tx = Lerp(
Expand Down Expand Up @@ -327,16 +330,20 @@ void GetModelSpaceVertex(out vec4 msPosition, out vec3 msNormal)

void main(void)
{
bool staticModel = (matrixMode > 0);

vec4 modelPos;
vec3 modelNormal;
GetModelSpaceVertex(modelPos, modelNormal);

if (staticModel) {
if (matrixMode == MATMODE_ARRAY) {
// static instanced: per-instance world transform read from the SSBO (no interpolation)
Transform wtx = transforms[instData.x + 0u];
worldPos = ApplyTransform(wtx, modelPos);
wtx.trSc = vec4(0, 0, 0, 1); //nullify the translation part for the normal
worldNormal = ApplyTransform(wtx, modelNormal);
} else if (matrixMode == MATMODE_STATIC) {
worldPos = staticModelMatrix * modelPos;
worldNormal = mat3(staticModelMatrix) * modelNormal;
} else {
} else { // MATMODE_NORMAL
// do interpolation
Transform tx = Lerp(
transforms[instData.x + 0u],
Expand Down
5 changes: 5 additions & 0 deletions doc/site/content/changelogs/_index.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ This is the bleeding-edge changelog since version 2026.06, for **pre-release 202
- Added cancelcommand action
- Added GetPrevFrameChecksum() to the Lua API [PR 2922](https://github.com/beyond-all-reason/RecoilEngine/pull/2922)
- Fixes to Spring.SetMapShader [PR 3127](https://github.com/beyond-all-reason/RecoilEngine/pull/3127)
- MouseHandler: route XButtons (Mouse4/5) as keybinds instead of mouse ownership [PR 2613](https://github.com/beyond-all-reason/RecoilEngine/pull/2613)

## Misc
- Restored lowercasing in FileSystem::GetExtension
Expand All @@ -80,6 +81,7 @@ This is the bleeding-edge changelog since version 2026.06, for **pre-release 202
- Fix stale spGetActionHotKeys returns [PR 3082](https://github.com/beyond-all-reason/RecoilEngine/pull/3082)
- Use a portable type cast in MemPoolTypes logging
- Support alternate file extensions for replays [PR 2975](https://github.com/beyond-all-reason/RecoilEngine/pull/2975)
- Throw error and stop processing if modrules parsing fails

## Rendering
- Added sorting icon names before adding to atlas so insertion order is consistent across runs.
Expand All @@ -96,6 +98,8 @@ This is the bleeding-edge changelog since version 2026.06, for **pre-release 202
- Debug logs for loading splat normals
- Fix SMF DNTS gating and fallback textures
- Add mapoptions for blank map splats
- Performance improvements with drawing ghosted buildings [PR 3110](https://github.com/beyond-all-reason/RecoilEngine/pull/3110)
- Changed ghosted buildings are drawn based on the last team was seen with and so which team ownership doesn't show automatically on the ghost. [PR 3108](https://github.com/beyond-all-reason/RecoilEngine/pull/3108)

## Simulation
- Sanitize NaNs in CHoverAirMoveType::UpdateMoveRate()
Expand All @@ -106,3 +110,4 @@ This is the bleeding-edge changelog since version 2026.06, for **pre-release 202
- Fixed edge scrolling threshold [Issue 2987](https://github.com/beyond-all-reason/RecoilEngine/issues/2987)
- Dump state handles resource packs
- Fix units having the wrong path id after loading a save game. [PR 3120](https://github.com/beyond-all-reason/RecoilEngine/pull/3120)
- Avoid UB in float-to-short angle casts (fixes arm64/x86 desync) [PR 3075](https://github.com/beyond-all-reason/RecoilEngine/pull/3075)
6 changes: 2 additions & 4 deletions doc/site/content/changelogs/changelog-2026-06.markdown
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
+++
title = "Running changelog"
[cascade]
[cascade.params]
type = "docs"
title = "Release 2026.06"
aliases = ['/changelogs/changelog-2026-06']
+++

This is the bleeding-edge changelog since version 2025.06, for **pre-release 2026.06**.
Expand Down
5 changes: 4 additions & 1 deletion doc/site/mise.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[settings.npm]
package_manager = "npm"

[tools]
# We only install tools required for each task on each task, unless all tasks use a tool here
# For CI when we need to install and cache all tools, see mise.ci.toml
Expand Down Expand Up @@ -101,7 +104,7 @@

[tasks.lua_library]
description = "Generate Lua Docs"
tools."npm:lua-doc-extractor" = "{{env.LUA_DOC_EXTRACTOR_VERSION}}"
tools."npm:lua-doc-extractor" = { version = "{{env.LUA_DOC_EXTRACTOR_VERSION}}", allow_low_downloads = true }
dir = "../../"
run = [
"lua-doc-extractor --src \"{{vars.lua_doc_paths}}\" --dest {{vars.lua_doc_gen_dest}} --repo \"${LUA_DOC_EXTRACTOR_SOURCE_REF}\""
Expand Down
2 changes: 1 addition & 1 deletion rts/Game/UI/MiniMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ void CMiniMap::ConfigCommand(const std::string& line)
const bool wantMaximized = (words.size() >= 2) ? !!atoi(words[1].c_str()) : !isMaximized;

if (isMaximized != wantMaximized)
ToggleMaximized(StrCaseStr(words[0].c_str(), "maxspect") == 0);
ToggleMaximized(hashStringLower(words[0].c_str()) != hashString("maxspect"));
} break;

case hashString("mouseevents"): {
Expand Down
34 changes: 34 additions & 0 deletions rts/Game/UI/MouseHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,24 @@ void CMouseHandler::MousePress(int x, int y, int button)

pressedBitMask |= 1 << button;

const bool isXButton = (button == SDL_BUTTON_X1 || button == SDL_BUTTON_X2);
if (isXButton) {

// 1. Lua first
if (luaInputReceiver->MousePress(x, y, button)) {
return;
}

// 2. GameInputReceiver via the same path as mouse buttons
auto activeControllerReceiver = (activeController == nullptr) ? nullptr : activeController->GetInputReceiver();
if (activeControllerReceiver && activeControllerReceiver->MousePress(x, y, button)) {
// NOTE: X‑buttons bypass ownership so they can be pressed/released without stealing or confusing activeReceiver
return;
}
return;
}


if (activeReceiver != nullptr && activeReceiver->MousePress(x, y, button))
return;

Expand Down Expand Up @@ -530,6 +548,22 @@ void CMouseHandler::MouseRelease(int x, int y, int button)
return;
}

const bool isXButton = (button == SDL_BUTTON_X1 || button == SDL_BUTTON_X2);
if (isXButton) {

// 1. Lua first
luaInputReceiver->MouseRelease(x, y, button);

// 2. GameInputReceiver via the same path as mouse buttons
auto activeControllerReceiver = (activeController == nullptr) ? nullptr : activeController->GetInputReceiver();
if (activeControllerReceiver) {
activeControllerReceiver->MouseRelease(x, y, button);
}

// 3. Skip ownership funnel
return;
}

if (activeReceiver != nullptr) {
activeReceiver->MouseRelease(x, y, button);

Expand Down
4 changes: 4 additions & 0 deletions rts/Rendering/Common/ModelDrawerState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,10 @@ CModelDrawerStateGL4::CModelDrawerStateGL4()
modelShaders[n]->SetFlag("GBUFFER_MISCTEX_IDX", GL::GeometryBuffer::ATTACHMENT_MISCTEX);
modelShaders[n]->SetFlag("GBUFFER_ZVALTEX_IDX", GL::GeometryBuffer::ATTACHMENT_ZVALTEX);

// name the matrix-mode values the shader compares against, so it reads modes by name
modelShaders[n]->SetFlag("MATMODE_STATIC", static_cast<int>(ShaderMatrixModes::STATIC_MATMODE));
modelShaders[n]->SetFlag("MATMODE_ARRAY", static_cast<int>(ShaderMatrixModes::ARRAY_MATMODE));

modelShaders[n]->Link();
modelShaders[n]->Enable();
modelShaders[n]->Disable();
Expand Down
47 changes: 36 additions & 11 deletions rts/Rendering/Models/3DModelVAO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,14 +286,28 @@ void S3DModelVAO::DrawElements(GLenum prim, uint32_t vboIndxStart, uint32_t vboI
glDrawElements(prim, vboIndxCount, GL_UNSIGNED_INT, indxVBO.GetPtr(vboIndxStart * sizeof(uint32_t)));
}

bool S3DModelVAO::EmplaceInstance(uint32_t indexStart, uint32_t indexCount, uint32_t traIndex, uint16_t paletteIndex, uint16_t numPieces, uint32_t uniIndex, uint32_t bposeIndex)
{
RECOIL_DETAILED_TRACY_ZONE;
if (traIndex == TransformsMemStorage::INVALID_INDEX || bposeIndex == TransformsMemStorage::INVALID_INDEX)
return false;

modelDataToInstance[SIndexAndCount{ indexStart, indexCount }].emplace_back(SInstanceData(
traIndex,
paletteIndex,
numPieces,
uniIndex,
bposeIndex
));

return true;
}

template<typename TObj>
bool S3DModelVAO::AddToSubmissionImpl(const TObj* obj, uint32_t indexStart, uint32_t indexCount, uint16_t paletteIndex)
{
RECOIL_DETAILED_TRACY_ZONE;
const auto traIndex = transformsUploader.GetElemOffset(obj);
if (traIndex == TransformsMemStorage::INVALID_INDEX)
return false;

const auto uniIndex = modelUniformsStorage.GetObjOffset(obj); //doesn't need to exist for defs and models. Don't check for validity

uint16_t numPieces = 0;
Expand All @@ -307,19 +321,14 @@ bool S3DModelVAO::AddToSubmissionImpl(const TObj* obj, uint32_t indexStart, uint
bposeIndex = transformsUploader.GetElemOffset(obj->model);
}

if (bposeIndex == TransformsMemStorage::INVALID_INDEX)
return false;

auto& modelInstanceData = modelDataToInstance[SIndexAndCount{ indexStart, indexCount }];
modelInstanceData.emplace_back(SInstanceData(
return EmplaceInstance(
indexStart, indexCount,
static_cast<uint32_t>(traIndex),
paletteIndex,
numPieces,
static_cast<uint32_t>(uniIndex),
static_cast<uint32_t>(bposeIndex)
));

return true;
);
}

bool S3DModelVAO::AddToSubmission(const S3DModel* model, uint16_t paletteIndex)
Expand Down Expand Up @@ -363,6 +372,22 @@ bool S3DModelVAO::AddToSubmission(const UnitDef* unitDef, uint16_t paletteIndex)
return AddToSubmissionImpl(unitDef, model->indxStart, model->indxCount, paletteIndex);
}

bool S3DModelVAO::AddStaticInstance(const S3DModel* model, uint32_t worldTransformOffset, uint16_t paletteIndex)
{
RECOIL_DETAILED_TRACY_ZONE;
assert(model);

// the world transform is the caller-supplied slot; pieces are read from the model bind pose
return EmplaceInstance(
model->indxStart, model->indxCount,
worldTransformOffset,
paletteIndex,
static_cast<uint16_t>(model->numPieces),
static_cast<uint32_t>(modelUniformsStorage.GetObjOffset(model)),
static_cast<uint32_t>(transformsUploader.GetElemOffset(model))
);
}


void S3DModelVAO::Submit(GLenum mode, bool bindUnbind)
{
Expand Down
14 changes: 14 additions & 0 deletions rts/Rendering/Models/3DModelVAO.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ class S3DModelVAO {
bool AddToSubmission(const CFeature* feature);

bool AddToSubmission(const UnitDef* unitDef, uint16_t paletteIndex);

bool AddStaticInstance(const S3DModel* model, uint32_t worldTransformOffset, uint16_t paletteIndex);

void Submit(GLenum mode = GL_TRIANGLES, bool bindUnbind = false);

bool SubmitImmediately(const S3DModel* model, uint16_t paletteIndex, GLenum mode = GL_TRIANGLES, bool bindUnbind = false);
Expand Down Expand Up @@ -102,6 +105,17 @@ class S3DModelVAO {
uint32_t indexCount,
uint16_t paletteIndex
);
// build one SInstanceData from already-resolved offsets and queue it for the next Submit();
// returns false (drawing nothing) if the world transform or bind pose is unavailable.
bool EmplaceInstance(
uint32_t indexStart,
uint32_t indexCount,
uint32_t traIndex,
uint16_t paletteIndex,
uint16_t numPieces,
uint32_t uniIndex,
uint32_t bposeIndex
);
void EnableAttribs(bool inst) const;
void DisableAttribs() const;
private:
Expand Down
Loading
Loading