Skip to content
Open
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
13 changes: 12 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ else()
add_compile_definitions(MMAPPER_PACKAGE_TYPE="${PACKAGE_TYPE_NORMALIZED}")
endif()

# Required for newer GLM versions that mark gtx/ extensions as experimental
add_compile_definitions(GLM_ENABLE_EXPERIMENTAL)

set(MMAPPER_QT_COMPONENTS Core Widgets Network OpenGL OpenGLWidgets Test)
if(WITH_WEBSOCKET)
list(APPEND MMAPPER_QT_COMPONENTS WebSockets)
Expand All @@ -78,6 +81,11 @@ if(Qt6OpenGL_FOUND)
if(EMSCRIPTEN)
set(QT_HAS_GLES TRUE)
set(QT_HAS_OPENGL FALSE)
elseif(APPLE)
# Force OpenGL on macOS - the try_compile check can fail with some Qt versions
# but macOS always has OpenGL 3.3 support via the core profile
set(QT_HAS_GLES FALSE)
set(QT_HAS_OPENGL TRUE)
else()
file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckQtGLES30.cpp
"#include <QOpenGLExtraFunctions>
Expand Down Expand Up @@ -423,7 +431,10 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wno-extra-semi-stmt) # enabled only for src/ directory

# require explicit template parameters when deduction guides are missing
add_compile_options(-Werror=ctad-maybe-unsupported)
# NOTE: Disabled for Qt 6.10+ because moc-generated code uses CTAD without deduction guides
if(Qt6_VERSION VERSION_LESS "6.10.0")
add_compile_options(-Werror=ctad-maybe-unsupported)
endif()

# always errors
add_compile_options(-Werror=cast-qual) # always a mistake unless you added the qualifier yourself.
Expand Down
32 changes: 23 additions & 9 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ if(EMSCRIPTEN)
-sFULL_ES3=1
-sMAX_WEBGL_VERSION=2
-sMIN_WEBGL_VERSION=2
-sASSERTIONS
-sASSERTIONS=0
-sASYNCIFY
-Os
)
Expand Down Expand Up @@ -1133,14 +1133,28 @@ if(APPLE)
# Bundle the libraries with the binary
find_program(MACDEPLOYQT_APP macdeployqt)
message(" - macdeployqt path: ${MACDEPLOYQT_APP}")
add_custom_command(
TARGET mmapper
POST_BUILD
COMMAND ${MACDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/mmapper.app -libpath ${QTKEYCHAIN_LIBRARY_DIR}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Deploying the Qt Framework onto the bundle"
VERBATIM
)
# Qt 6.8+ has a bug where macdeployqt -libpath fails with "Missing library search path"
# The library is still found via @rpath, so we can safely omit -libpath for Qt 6.8+
if(Qt6Core_VERSION VERSION_GREATER_EQUAL "6.8.0")
message(" - Qt 6.8+ detected: skipping -libpath option (macdeployqt bug workaround)")
add_custom_command(
TARGET mmapper
POST_BUILD
COMMAND ${MACDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/mmapper.app
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Deploying the Qt Framework onto the bundle"
VERBATIM
)
else()
add_custom_command(
TARGET mmapper
POST_BUILD
COMMAND ${MACDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/mmapper.app -libpath ${QTKEYCHAIN_LIBRARY_DIR}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Deploying the Qt Framework onto the bundle"
VERBATIM
)
endif()

# Codesign the bundle without a personal certificate
find_program(CODESIGN_APP codesign)
Expand Down
10 changes: 9 additions & 1 deletion src/clock/mumeclock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,15 @@ class NODISCARD QME final

public:
NODISCARD static int keyToValue(const QString &key) { return g_qme.keyToValue(key.toUtf8()); }
NODISCARD static QString valueToKey(const int value) { return g_qme.valueToKey(value); }
NODISCARD static QString valueToKey(const int value)
{
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
// Qt 6.10+ changed valueToKey() signature from int to quint64
return g_qme.valueToKey(static_cast<quint64>(value));
#else
return g_qme.valueToKey(value);
#endif
}
NODISCARD static int keyCount() { return g_qme.keyCount(); }
};

Expand Down
62 changes: 56 additions & 6 deletions src/display/MapCanvasData.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <QOpenGLTexture>
#include <QWidget>
#include <QWindow>
#include <QtGui/QMatrix4x4>
#include <QtGui/QMouseEvent>
#include <QtGui/qopengl.h>
Expand Down Expand Up @@ -97,10 +98,53 @@ struct NODISCARD ScaleFactor final
}
};

// Abstraction to get size from either QWidget or QWindow
struct NODISCARD SizeSource final
{
private:
QWidget *m_widget = nullptr;
QWindow *m_window = nullptr;

public:
explicit SizeSource(QWidget &widget)
: m_widget{&widget}
{}
explicit SizeSource(QWindow &window)
: m_window{&window}
{}

NODISCARD int width() const
{
if (m_widget)
return m_widget->width();
if (m_window)
return m_window->width();
return 0;
}

NODISCARD int height() const
{
if (m_widget)
return m_widget->height();
if (m_window)
return m_window->height();
return 0;
}

NODISCARD QRect rect() const
{
if (m_widget)
return m_widget->rect();
if (m_window)
return QRect(0, 0, m_window->width(), m_window->height());
return QRect();
}
};

struct NODISCARD MapCanvasViewport
{
private:
QWidget &m_sizeWidget;
SizeSource m_sizeSource;

public:
glm::mat4 m_viewProj{1.f};
Expand All @@ -109,16 +153,22 @@ struct NODISCARD MapCanvasViewport
int m_currentLayer = 0;

public:
explicit MapCanvasViewport(QWidget &sizeWidget)
: m_sizeWidget{sizeWidget}
explicit MapCanvasViewport(QWidget &sizeSource)
: m_sizeSource{sizeSource}
{}

#ifdef __EMSCRIPTEN__
explicit MapCanvasViewport(QWindow &sizeSource)
: m_sizeSource{sizeSource}
{}
#endif

public:
NODISCARD auto width() const { return m_sizeWidget.width(); }
NODISCARD auto height() const { return m_sizeWidget.height(); }
NODISCARD auto width() const { return m_sizeSource.width(); }
NODISCARD auto height() const { return m_sizeSource.height(); }
NODISCARD Viewport getViewport() const
{
const auto &r = m_sizeWidget.rect();
const auto &r = m_sizeSource.rect();
return Viewport{glm::ivec2{r.x(), r.y()}, glm::ivec2{r.width(), r.height()}};
}
NODISCARD float getTotalScaleFactor() const { return m_scaleFactor.getTotal(); }
Expand Down
29 changes: 26 additions & 3 deletions src/display/MapCanvasRoomDrawer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "../configuration/NamedConfig.h"
#include "../configuration/configuration.h"
#include "../global/Array.h"
#include "../global/ConfigConsts-Computed.h"
#include "../global/ConfigConsts.h"
#include "../global/EnumIndexedArray.h"
#include "../global/Flags.h"
Expand Down Expand Up @@ -1119,17 +1120,30 @@ FutureSharedMapBatchFinisher generateMapDataFinisher(const mctp::MapCanvasTextur
{
const auto visitRoomOptions = getVisitRoomOptions();

return std::async(std::launch::async,
// WASM: Use deferred (synchronous) execution to avoid context invalidation during async.
// Desktop: Use async execution for better performance.
constexpr auto launchPolicy = (CURRENT_PLATFORM == PlatformEnum::Wasm) ? std::launch::deferred
: std::launch::async;

return std::async(launchPolicy,
[textures, font, map, visitRoomOptions]() -> SharedMapBatchFinisher {
// WASM: Check if WebGL context was lost before starting
if constexpr (CURRENT_PLATFORM == PlatformEnum::Wasm) {
if (MapCanvas::isWasmContextLost()) {
qWarning() << "[generateMapDataFinisher] context lost, aborting";
return SharedMapBatchFinisher{};
}
}

ThreadLocalNamedColorRaii tlRaii{visitRoomOptions.canvasColors,
visitRoomOptions.colorSettings};
DECL_TIMER(t, "[ASYNC] generateAllLayerMeshes");
DECL_TIMER(t, "generateAllLayerMeshes");

ProgressCounter dummyPc;
map.checkConsistency(dummyPc);

const auto layerToRooms = std::invoke([map]() -> LayerToRooms {
DECL_TIMER(t2, "[ASYNC] generateBatches.layerToRooms");
DECL_TIMER(t2, "generateBatches.layerToRooms");
LayerToRooms ltr;
map.getRooms().for_each([&map, &ltr](const RoomId id) {
const auto &r = map.getRoomHandle(id);
Expand All @@ -1140,6 +1154,15 @@ FutureSharedMapBatchFinisher generateMapDataFinisher(const mctp::MapCanvasTextur
return ltr;
});

// WASM: Check again before the expensive mesh generation
if constexpr (CURRENT_PLATFORM == PlatformEnum::Wasm) {
if (MapCanvas::isWasmContextLost()) {
qWarning() << "[generateMapDataFinisher] context lost before "
"mesh gen, aborting";
return SharedMapBatchFinisher{};
}
}

auto result = std::make_shared<InternalData>();
auto &data = deref(result);
generateAllLayerMeshes(data,
Expand Down
Loading
Loading