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
2 changes: 1 addition & 1 deletion src/display/Connections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ void ConnectionDrawer::ConnectionFakeGL::drawLineStrip(const std::vector<glm::ve
const float extension = CONNECTION_LINE_WIDTH * 0.5f;

// Helper lambda to generate a quad between two points with a specific color.
auto generateQuad = [&](const glm::vec3 &p1, const glm::vec3 &p2, const Color quad_color) {
auto generateQuad = [this](const glm::vec3 &p1, const glm::vec3 &p2, const Color quad_color) {
auto &verts = deref(m_currentBuffer).quadVerts;

const glm::vec3 segment = p2 - p1;
Expand Down
9 changes: 5 additions & 4 deletions src/display/Infomarks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ BatchedInfomarksMeshes MapCanvas::getInfomarksMeshes()
{
const auto &map = m_data.getCurrentMap();
const auto &db = map.getInfomarkDb();
db.getIdSet().for_each([&](const InfomarkId id) {
db.getIdSet().for_each([&db, &result](const InfomarkId id) {
InfomarkHandle mark{db, id};
const int layer = mark.getPosition1().z;
const auto it = result.find(layer);
Expand All @@ -125,8 +125,9 @@ BatchedInfomarksMeshes MapCanvas::getInfomarksMeshes()
for (auto &it : result) {
const int layer = it.first;
InfomarksBatch batch{getOpenGL(), getGLFont()};
db.getIdSet().for_each(
[&](const InfomarkId id) { drawInfomark(batch, InfomarkHandle{db, id}, layer); });
db.getIdSet().for_each([this, &batch, &db, layer](const InfomarkId id) {
drawInfomark(batch, InfomarkHandle{db, id}, layer);
});
it.second = batch.getMeshes();
}

Expand Down Expand Up @@ -370,7 +371,7 @@ void MapCanvas::paintSelectedInfomarks()

const auto &map = m_data.getCurrentMap();
const InfomarkDb &db = map.getInfomarkDb();
db.getIdSet().for_each([&](const InfomarkId id) {
db.getIdSet().for_each([&db, &drawSelectionPoints](const InfomarkId id) {
InfomarkHandle marker{db, id};
drawSelectionPoints(marker);
});
Expand Down
87 changes: 45 additions & 42 deletions src/display/Textures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@
#include <vector>

#include <glm/glm.hpp>

#include <QMessageLogContext>
#include <glm/gtx/compatibility.hpp>

MMTextureId allocateTextureId()
{
Expand Down Expand Up @@ -368,61 +367,62 @@ NODISCARD static std::vector<QImage> createDottedWallImages(const ExitDirEnum di
return images;
}

NODISCARD static QImage createTileableValueNoiseImage(int size)
NODISCARD static QImage createTileableValueNoiseImage(const int size)
{
QImage img(size, size, QImage::Format_RGBA8888);

// Constants 127.1/311.7 provide high-frequency distribution to prevent Moire patterns
auto hash = [](float x, float y) -> float {
float dot = x * 127.1f + y * 311.7f;
float fract = std::sin(dot) * 43758.5453123f;
static auto hash = [](const float x, const float y) -> float {
const float dot = x * 127.1f + y * 311.7f;
const float fract = std::sin(dot) * 43758.5453123f;
return fract - std::floor(fract);
};

auto lerp = [](float a, float b, float t) -> float { return a + t * (b - a); };

// https://en.wikipedia.org/wiki/Smoothstep#Variations
// Perlin's quintic curve ($6t^5-15t^4+10t^3$) ensures smooth C2 continuity at grid boundaries
auto smooth = [](float t) -> float { return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); };
static auto smootherstep = [](const float t) -> float {
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
};

// Double modulo ensures positive wrapping for seamless tiling
auto get_wrapped_hash = [size](const int i, const int j) -> float {
const auto wi = static_cast<float>((i % size + size) % size);
const auto wj = static_cast<float>((j % size + size) % size);
return hash(wi, wj);
};

for (int y = 0; y < size; ++y) {
// scanLine avoids QImage's internal per-pixel coordinate-to-pointer overhead
uchar *line = img.scanLine(y);

for (int x = 0; x < size; ++x) {
float xx = static_cast<float>(x);
float yy = static_cast<float>(y);

float ix = std::floor(xx);
float iy = std::floor(yy);
float fx = xx - ix;
float fy = yy - iy;

float sx = smooth(fx);
float sy = smooth(fy);

// Double modulo ensures positive wrapping for seamless tiling
auto get_wrapped_hash = [&](int i, int j) {
float wi = static_cast<float>((i % size + size) % size);
float wj = static_cast<float>((j % size + size) % size);
return hash(wi, wj);
};
const auto xx = static_cast<float>(x);
const auto yy = static_cast<float>(y);

int iix = static_cast<int>(ix);
int iiy = static_cast<int>(iy);
const float ix = std::floor(xx);
const float iy = std::floor(yy);
const float fx = xx - ix;
const float fy = yy - iy;

const float sx = smootherstep(fx);
const float sy = smootherstep(fy);

const int iix = static_cast<int>(ix);
const int iiy = static_cast<int>(iy);

// Fetch corners for bilinear interpolation
float a = get_wrapped_hash(iix, iiy);
float b = get_wrapped_hash(iix + 1, iiy);
float c = get_wrapped_hash(iix, iiy + 1);
float d = get_wrapped_hash(iix + 1, iiy + 1);
const float a = get_wrapped_hash(iix, iiy);
const float b = get_wrapped_hash(iix + 1, iiy);
const float c = get_wrapped_hash(iix, iiy + 1);
const float d = get_wrapped_hash(iix + 1, iiy + 1);

float v = lerp(lerp(a, b, sx), lerp(c, d, sx), sy);
const float v = glm::lerp(glm::lerp(a, b, sx), glm::lerp(c, d, sx), sy);

// Casting to uchar provides implicit floor and branchless clamping
uchar val = static_cast<uchar>(std::clamp(v * 255.0f, 0.0f, 255.0f));
const auto val = static_cast<uchar>(std::clamp(v * 255.0f, 0.0f, 255.0f));

// Direct pointer offset for RGBA8888 interleaved memory
int offset = x * 4;
const int offset = x * 4;
line[offset] = val; // R
line[offset + 1] = val; // G
line[offset + 2] = val; // B
Expand Down Expand Up @@ -610,7 +610,8 @@ void MapCanvas::initTextures()
}
};

auto initGroup = [&](const std::string_view groupName, auto &&...sources) {
auto initGroup = [&maybeCreateArray2](const std::string_view groupName,
auto &&...sources) -> SharedMMTexture {
SharedMMTexture pArrayTex;
auto thing = combine(std::forward<decltype(sources)>(sources)...);
maybeCreateArray2(groupName, thing, pArrayTex);
Expand All @@ -633,12 +634,14 @@ void MapCanvas::initTextures()
textures.exit_down,
textures.exit_up);

auto maybeCreateArray =
[&](const std::string_view groupName, auto &thing, SharedMMTexture &pArrayTex) {
if (pArrayTex)
return;
pArrayTex = initGroup(groupName, thing);
};
auto maybeCreateArray = [&initGroup](const std::string_view groupName,
auto &thing,
SharedMMTexture &pArrayTex) {
if (pArrayTex) {
return;
}
pArrayTex = initGroup(groupName, thing);
};

#define XTEX(_TYPE, _NAME) maybeCreateArray(#_NAME, textures._NAME, textures._NAME##_Array);
XFOREACH_MAPCANVAS_TEXTURES(XTEX)
Expand Down
11 changes: 7 additions & 4 deletions src/display/mapcanvas_gl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,7 @@ void MapCanvas::Diff::maybeAsyncUpdate(const Map &saved, const Map &current)

// Handle rooms needing a server ID or that are temporary
if (showNeedsServerId) {
current.getRooms().for_each([&](auto id) {
current.getRooms().for_each([&current, &drawQuad](auto id) {
if (auto h = current.getRoomHandle(id)) {
if (h.isTemporary()) {
drawQuad(h.getRaw(), NamedColorEnum::HIGHLIGHT_TEMPORARY);
Expand All @@ -634,9 +634,12 @@ void MapCanvas::Diff::maybeAsyncUpdate(const Map &saved, const Map &current)
// Handle changed rooms
if (showChanged) {
ProgressCounter dummyPc;
Map::foreachChangedRoom(dummyPc, saved, current, [&](const RawRoom &room) {
drawQuad(room, NamedColorEnum::HIGHLIGHT_UNSAVED);
});
Map::foreachChangedRoom(dummyPc,
saved,
current,
[&drawQuad](const RawRoom &room) {
drawQuad(room, NamedColorEnum::HIGHLIGHT_UNSAVED);
});
}

if (highlights.empty()) {
Expand Down
14 changes: 5 additions & 9 deletions src/global/NamedColors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,18 @@ struct NODISCARD GlobalData final
m_initialized[NamedColorEnum::TRANSPARENT] = true;

// Sane defaults for weather colors
std::ignore = setColor(NamedColorEnum::WEATHER_DAWN,
Color(102, 76, 51, 25)); // 0.4, 0.3, 0.2, 0.1
std::ignore = setColor(NamedColorEnum::WEATHER_DUSK,
Color(76, 51, 102, 51)); // 0.3, 0.2, 0.4, 0.2
std::ignore = setColor(NamedColorEnum::WEATHER_NIGHT,
Color(13, 13, 51, 89)); // 0.05, 0.05, 0.2, 0.35
std::ignore = setColor(NamedColorEnum::WEATHER_NIGHT_MOON,
Color(13, 13, 64, 77)); // 0.05, 0.05, 0.25, 0.3
setColor(NamedColorEnum::WEATHER_DAWN, Color(102, 76, 51, 25)); // 0.4, 0.3, 0.2, 0.1
setColor(NamedColorEnum::WEATHER_DUSK, Color(76, 51, 102, 51)); // 0.3, 0.2, 0.4, 0.2
setColor(NamedColorEnum::WEATHER_NIGHT, Color(13, 13, 51, 89)); // 0.05, 0.05, 0.2, 0.35
setColor(NamedColorEnum::WEATHER_NIGHT_MOON, Color(13, 13, 64, 77)); // 0.05, 0.05, 0.25, 0.3
}

public:
NODISCARD bool isInitialized(const NamedColorEnum id) const { return m_initialized[id]; }

public:
NODISCARD Color getColor(const NamedColorEnum id) { return m_colors.at(getIndex(id)); }
NODISCARD bool setColor(const NamedColorEnum id, Color c)
ALLOW_DISCARD bool setColor(const NamedColorEnum id, const Color c)
{
if (id == NamedColorEnum::DEFAULT || id == NamedColorEnum::TRANSPARENT) {
return false;
Expand Down
2 changes: 1 addition & 1 deletion src/global/emojis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ static void importEmojis(const QByteArray &bytes, const QString &filename)
auto &emojis = getEmojis();
emojis.reset();
size_t num_output_emojis = 0;
auto report = [&](const QString &shortCode, const QString &hex) {
auto report = [&emojis](const QString &shortCode, const QString &hex) {
if (auto opt_emoji = getUnicode(hex)) {
for (const char32_t c : *opt_emoji) {
if (isAsciiOrLatin1ControlCode(c)) {
Expand Down
4 changes: 3 additions & 1 deletion src/group/groupwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,9 @@ QVariant GroupModel::dataForCharacter(const SharedGroupChar &pCharacter,
break;

case Qt::ToolTipRole: {
const auto getRatioTooltip = [&](int numerator, int denomenator) -> QVariant {
const auto getRatioTooltip =
[&character, &column, &formatStat](const int numerator,
const int denomenator) -> QVariant {
if (character.getType() == CharacterTypeEnum::NPC) {
return QVariant();
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/group/mmapper2group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ bool Mmapper2Group::updateChar(SharedGroupChar sharedCh, const JsonObj &obj)
}

if (!ch.getColor().isValid()) {
auto getColor = [&]() -> QColor {
auto getColor = [this, &ch]() -> QColor {
const auto &settings = getConfig().groupManager;
if (ch.isNpc() && settings.npcColorOverride) {
return settings.npcColor;
Expand Down
12 changes: 7 additions & 5 deletions src/mainwindow/UpdateDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,18 @@ namespace { // anonymous
NODISCARD const char *getArchitectureRegexPattern()
{
// See Qt documentation for expected keys
const std::array<std::pair<const char *, const char *>, 4> archPatterns = {
static const std::array<std::pair<const char *, const char *>, 4> archPatterns = {
{{"arm64", "(arm64|aarch64)"},
{"x86_64", "(x86_64|amd64|x64)"},
{"i386", "(i386|x86(?!_64))"},
{"arm", "(arm(?!64)|armhf)"}}};

auto findPattern = [&](const QString &arch) -> const char * {
auto it = std::find_if(archPatterns.begin(), archPatterns.end(), [&arch](const auto &pair) {
return mmqt::toStdStringUtf8(arch) == pair.first;
});
static auto findPattern = [](const QString &arch) -> const char * {
const auto it = std::find_if(archPatterns.begin(),
archPatterns.end(),
[&arch](const auto &pair) {
return mmqt::toStdStringUtf8(arch) == pair.first;
});
return (it != archPatterns.end()) ? it->second : nullptr;
};

Expand Down
2 changes: 1 addition & 1 deletion src/mainwindow/findroomsdlg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ void FindRoomsDlg::slot_findClicked()
try {
RoomFilter filter(text, cs, regex, kind);
const Map &map = m_mapData.getCurrentMap();
map.getRooms().for_each([&](const auto roomId) {
map.getRooms().for_each([this, &filter, &map](const auto roomId) {
const auto &room = map.getRoomHandle(roomId);
if (!filter.filter(room.getRaw())) {
return;
Expand Down
10 changes: 5 additions & 5 deletions src/map/Map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ void Map::printMulti(ProgressCounter &pc, AnsiOstream &os) const

std::set<ExternalRoomId> rooms;
pc.setNewTask(ProgressMsg{"phase 1: scanning rooms"}, getRoomsCount());
getRooms().for_each([&](const RoomId here) {
getRooms().for_each([&pc, &rooms, &w](const RoomId here) {
const auto &room = deref(w.getRoom(here));
const auto hereExternal = w.convertToExternal(here);
for (const ExitDirEnum dir : ALL_EXITS_NESWUD) {
Expand Down Expand Up @@ -443,7 +443,7 @@ void Map::printUnknown(ProgressCounter &pc, AnsiOstream &os) const
{
std::set<ExternalRoomId> set;
pc.setNewTask(ProgressMsg{"scanning rooms"}, getRoomsCount());
getRooms().for_each([&](const RoomId id) {
getRooms().for_each([this, &pc, &set](const RoomId id) {
const auto &room = getRoomHandle(id);
if (!room.getExit(ExitDirEnum::UNKNOWN).outIsEmpty()
|| !room.getExit(ExitDirEnum::UNKNOWN).inIsEmpty()) {
Expand Down Expand Up @@ -1184,7 +1184,7 @@ Map Map::merge(ProgressCounter &pc,
marks.reserve(currentMap.getMarksCount() + newMarks.size());

pc.setCurrentTask(ProgressMsg{"creating combined map: old rooms"});
currentMap.getRooms().for_each([&](const RoomId id) {
currentMap.getRooms().for_each([&currentMap, &pc, &rooms](const RoomId id) {
const RoomHandle &room = currentMap.getRoomHandle(id);
rooms.emplace_back(room.getRawCopyExternal());
pc.step();
Expand All @@ -1198,7 +1198,7 @@ Map Map::merge(ProgressCounter &pc,

pc.setCurrentTask(ProgressMsg{"creating combined map: old marks"});
const auto &db = currentMap.getInfomarkDb();
db.getIdSet().for_each([&](const auto id) {
db.getIdSet().for_each([&db, &marks, &pc](const auto id) {
marks.emplace_back(db.getRawCopy(id));
pc.step();
});
Expand Down Expand Up @@ -1233,7 +1233,7 @@ void Map::foreachChangedRoom(ProgressCounter &pc,
const std::function<void(const RawRoom &room)> &callback)
{
pc.increaseTotalStepsBy(current.getRoomsCount());
current.getRooms().for_each([&](const RoomId id) {
current.getRooms().for_each([&callback, &current, &pc, &saved](const RoomId id) {
const auto r = current.findRoomHandle(id);
if (!r) {
assert(false);
Expand Down
2 changes: 1 addition & 1 deletion src/map/ParseTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ RoomIdSet getRooms(const Map &map, const ParseTree &tree, const ParseEvent &even

RoomIdSet results;
size_t numReported = 0;
set.for_each([&](const RoomId id) {
set.for_each([&map, &numReported, &results, &tryReport](const RoomId id) {
if (const auto optRoom = map.findRoomHandle(id)) {
if (tryReport(optRoom)) {
results.insert(id);
Expand Down
18 changes: 11 additions & 7 deletions src/map/Remapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "Remapping.h"

#include "../global/AnsiOstream.h"
#include "../global/ConfigConsts.h"
#include "../global/Timer.h"
#include "../global/logging.h"
#include "../global/progresscounter.h"
Expand Down Expand Up @@ -166,12 +167,15 @@ Remapping Remapping::computeFrom(const std::vector<ExternalRawRoom> &input)

remapping.m_intToExt.init(intToExt.data(), intToExt.size());

assert(next.asUint32() == seen.size());
assert(next.asUint32() == remapping.m_intToExt.size());
assert(next.asUint32() == remapping.m_extToInt.size());
if constexpr (IS_DEBUG_BUILD) {
assert(next.asUint32() == seen.size());
assert(next.asUint32() == remapping.m_intToExt.size());
assert(next.asUint32() == remapping.m_extToInt.size());

remapping.m_extToInt.for_each(
[&](const auto &kv) { assert(remapping.m_intToExt.at(kv.second) == kv.first); });
remapping.m_extToInt.for_each([&remapping](const auto &kv) {
assert(remapping.m_intToExt.at(kv.second) == kv.first);
});
}

return remapping;
}
Expand All @@ -185,7 +189,7 @@ ExternalRoomId Remapping::getNextExternal() const
const auto any = m_extToInt.begin()->first;
ExternalRoomId highest = any;

m_intToExt.for_each([&](auto x) {
m_intToExt.for_each([&highest](const ExternalRoomId x) {
if (x != INVALID_EXTERNAL_ROOMID) {
if (x > highest) {
highest = x;
Expand Down Expand Up @@ -276,7 +280,7 @@ void Remapping::compact(ProgressCounter &pc, const ExternalRoomId firstId)
ImmUnorderedMap<ExternalRoomId, RoomId> newExtToInt;

pc.increaseTotalStepsBy(m_extToInt.size());
m_extToInt.for_each([&](const auto &kv) {
m_extToInt.for_each([this, &newExtToInt, &next, &pc](const auto &kv) {
m_intToExt.set(kv.second, next);
newExtToInt.set(next, kv.second);
next = next.next();
Expand Down
Loading
Loading