This commit is contained in:
andrewchilicki
2025-02-08 16:37:29 -05:00
parent 7e0e9d2592
commit 1485f1325e
9 changed files with 183 additions and 257 deletions

View File

@ -25,8 +25,7 @@ public:
void drawImGuiImage(const std::string& imagePath, float scale, std::optional<ImVec4> tint) final
{
auto filePath = assetDir + imagePath;
if (auto image = getImageForFile(filePath))
{
if (auto image = getImageForFile(filePath)) {
ImGui::Image((ImTextureID)(intptr_t)image->texture, ImVec2(image->width*scale, image->height*scale),
ImVec2(0,0), ImVec2(1,1), tint.value_or(ImVec4(1,1,1,1)));
}
@ -35,8 +34,7 @@ public:
std::pair<int, int> getImageSize(const std::string &imagePath) final
{
auto filePath = assetDir + imagePath;
if (auto image = getImageForFile(filePath))
{
if (auto image = getImageForFile(filePath)) {
return std::make_pair(image->width, image->height);
}
return std::make_pair(0, 0);
@ -44,8 +42,7 @@ public:
std::optional<Image> getImageForFile(const std::string& filePath)
{
if (auto it = imageCache.find(filePath); it != imageCache.end())
{
if (auto it = imageCache.find(filePath); it != imageCache.end()) {
// Return from cache
return it->second;
}
@ -58,8 +55,7 @@ public:
{
// Load texture from file
FILE* f = fopen(filePath.c_str(), "rb");
if (f == NULL)
{
if (f == NULL) {
std::cerr << "Failed to open file " << filePath << std::endl;
return std::nullopt;
}
@ -96,8 +92,9 @@ public:
int image_width = 0;
int image_height = 0;
unsigned char* image_data = stbi_load_from_memory((const unsigned char*)data, (int)data_size, &image_width, &image_height, NULL, 4);
if (image_data == NULL)
if (image_data == NULL) {
return false;
}
GLuint image_texture;
glGenTextures(1, &image_texture);

View File

@ -26,46 +26,36 @@ public:
bool activeGroupStillVisible = false;
bool newActiveBadGroup = false;
for (auto it = badGroups.begin(); it != badGroups.end(); )
{
if (it->second->numberIds.empty())
{
for (auto it = badGroups.begin(); it != badGroups.end(); ) {
if (it->second->numberIds.empty()) {
it = badGroups.erase(it);
}
else
{
} else {
++it;
}
}
// Update visible groups and check if active group is still visible
for (const auto &[groupId, badGroup] : badGroups)
{
for (const auto &numId : badGroup->numberIds)
{
for (const auto &[groupId, badGroup] : badGroups) {
for (const auto &numId : badGroup->numberIds) {
auto num = numberIdMap.at(numId);
if (num->displayInfos.isVisible)
{
if (num->displayInfos.isVisible) {
visibleBadGroups.emplace(groupId);
if (badGroup->isActive && groupId == *activeBadGroup)
{
if (badGroup->isActive && groupId == *activeBadGroup) {
activeGroupStillVisible = true;
}
}
}
}
if (activeBadGroup && !activeGroupStillVisible)
{
if (activeBadGroup && !activeGroupStillVisible) {
activeBadGroup.reset();
newActiveBadGroup = true;
newBadGroupCountdown = randomNumber(5, 15) * 100;
}
// Select a new active group if necessary
if (!activeBadGroup && !visibleBadGroups.empty() && newBadGroupCountdown == 0)
{
if (!activeBadGroup && !visibleBadGroups.empty() && newBadGroupCountdown == 0) {
auto randomIndex = randomNumber(0, static_cast<int>(visibleBadGroups.size()) - 1);
auto it = visibleBadGroups.begin();
std::advance(it, randomIndex);
@ -73,39 +63,27 @@ public:
}
// Update active groups / their scale
for (const auto &[groupId, badGroup] : badGroups)
{
for (const auto &[groupId, badGroup] : badGroups) {
badGroup->isActive = activeBadGroup && groupId == *activeBadGroup;
if (badGroup->isActive)
{
if (newActiveBadGroup)
{
if (badGroup->isActive) {
if (newActiveBadGroup) {
badGroup->scale = 0;
}
else
{
if (!badGroup->reachedMax)
{
if (badGroup->scale < 0.23)
{
} else {
if (!badGroup->reachedMax) {
if (badGroup->scale < 0.23) {
badGroup->scale += (0.0001 * randomNumber(1, 10));
}
} else
{
} else {
badGroup->scale -= (0.0001 * randomNumber(1, 10));
}
if (badGroup->scale >= 0.23)
{
if (!badGroup->superActive || badGroup->scale >= 0.24)
{
if (badGroup->scale >= 0.23) {
if (!badGroup->superActive || badGroup->scale >= 0.24) {
badGroup->reachedMax = true;
} else
{
} else {
badGroup->scale += 0.00001;
}
} else if (badGroup->scale <= 0.0)
{
} else if (badGroup->scale <= 0.0) {
badGroup->isActive = false;
badGroup->superActive = false;
badGroup->reachedMax = false;
@ -113,24 +91,20 @@ public:
newBadGroupCountdown = randomNumber(5, 15) * 100;
}
}
} else
{
} else {
badGroup->scale = 0;
}
}
if (newBadGroupCountdown > 0)
{
if (newBadGroupCountdown > 0) {
newBadGroupCountdown--;
}
}
NumberPtr getGridNumber(int x, int y) final
{
if (auto itr = grid.find(x); itr != grid.end())
{
if (auto itr2 = itr->second.find(y); itr2 != itr->second.end())
{
if (auto itr = grid.find(x); itr != grid.end()) {
if (auto itr2 = itr->second.find(y); itr2 != itr->second.end()) {
return itr2->second;
}
}
@ -139,8 +113,7 @@ public:
NumberPtr getGridNumber(int id) final
{
if (auto itr = numberIdMap.find(id); itr != numberIdMap.end())
{
if (auto itr = numberIdMap.find(id); itr != numberIdMap.end()) {
return itr->second;
}
return nullptr;
@ -170,16 +143,13 @@ private:
{
int numberId = 0;
std::set<int> badNumbers;
for (int x = 0; x < size; x++)
{
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++) {
for (int y = 0; y < size; y++) {
grid[x][y] = std::make_shared<Number>(numberId, x, y, randomNumber(0,9), randomBool());
numberIdMap[numberId] = grid[x][y];
// Determine if bad
if (perlinBadNumbers.noise2D_01(x*badScale,y*badScale) > badThresh)
{
if (perlinBadNumbers.noise2D_01(x*badScale,y*badScale) > badThresh) {
badNumbers.insert(numberId);
}
@ -188,44 +158,34 @@ private:
}
// Assign 'bad groups'
auto checkAdjacent = [&](int x, int y) -> BadGroupPtr
{
if (auto gridNum = getGridNumber(x, y))
{
auto checkAdjacent = [&](int x, int y) -> BadGroupPtr {
if (auto gridNum = getGridNumber(x, y)) {
return gridNum->badGroup;
}
return nullptr;
};
int badGroup = 0;
for (const auto &badNumId : badNumbers)
{
for (const auto &badNumId : badNumbers) {
auto gridNumber = numberIdMap.at(badNumId);
if (!gridNumber->badGroup)
{
for (int checkX = -1; checkX <= 1; checkX++)
{
for (int checkY = -1; checkY <= 1; checkY++)
{
if (checkX == 0 && checkY == 0)
{
if (!gridNumber->badGroup) {
for (int checkX = -1; checkX <= 1; checkX++) {
for (int checkY = -1; checkY <= 1; checkY++) {
if (checkX == 0 && checkY == 0) {
continue;
}
if (auto badGroupPtr = checkAdjacent(gridNumber->gridX + checkX, gridNumber->gridY + checkY))
{
if (auto badGroupPtr = checkAdjacent(gridNumber->gridX + checkX, gridNumber->gridY + checkY)) {
gridNumber->badGroup = badGroupPtr;
gridNumber->badGroup->numberIds.emplace_back(gridNumber->id);
break;
}
}
if (gridNumber->badGroup)
{
if (gridNumber->badGroup) {
break;
}
}
if (!gridNumber->badGroup)
{
if (!gridNumber->badGroup) {
gridNumber->badGroup = std::make_shared<BadGroup>(badGroup++, std::vector{gridNumber->id}, randomNumber(0,4));
badGroups.emplace(badGroup, gridNumber->badGroup);
}

View File

@ -11,7 +11,7 @@
namespace ColorValues
{
ImColor lumonBlue = ImColor(101,213,235,255);
ImColor lumonBlue = ImColor(157,227,235,255);
}
class UIManagerImpl : public UIManager
@ -39,26 +39,25 @@ public:
void update() final
{
if (ImGui::IsKeyPressed(ImGuiKey_Tab))
{
debugMode = !debugMode;
// Toggle settings mode with 'TAB'
if (ImGui::IsKeyPressed(ImGuiKey_Tab)) {
settingsMode = !settingsMode;
}
if (ImGui::IsKeyPressed(ImGuiKey_I))
{
// Toggle idle mode with 'I'
if (ImGui::IsKeyPressed(ImGuiKey_I)) {
idleMode = !idleMode;
}
if (idleMode)
{
if (idleMode) {
idleScreen->update();
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left))
{
// Exit idle mode with 'LEFT CLICK'
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
idleMode = false;
numbersPanel->triggerLoadAnimation();
}
} else
{
} else {
numbersPanel->update();
}
}
@ -76,22 +75,18 @@ public:
ImGui::SetNextWindowSize(ImVec2(viewportSize.x, viewportSize.y));
if (ImGui::Begin("Main", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse))
{
if (idleMode)
{
if (idleMode) {
idleScreen->drawIdleScreen();
} else
{
} else {
numbersPanel->drawNumbersPanel();
}
}
ImGui::End();
if (debugMode)
{
if (settingsMode) {
ImGui::SetNextWindowPos(viewportPos);
ImGui::SetNextWindowSize(ImVec2(viewportSize.x * settingsWidthRatio, viewportSize.y));
if (ImGui::Begin("Settings"))
{
if (ImGui::Begin("Settings")) {
numbersPanel->drawSettings();
}
ImGui::End();
@ -107,11 +102,10 @@ public:
private:
std::shared_ptr<ImageDisplay> imageDisplay;
std::shared_ptr<NumbersPanel> numbersPanel;
std::shared_ptr<IdleScreen> idleScreen;
bool debugMode = false;
bool settingsMode = false;
bool idleMode = false;
};

View File

@ -13,10 +13,8 @@ namespace ColorValues
class UIManager {
public:
virtual void init() = 0;
virtual void draw() = 0;
virtual void update() = 0;
virtual void cleanup() = 0;
virtual ~UIManager() = default;

View File

@ -3,7 +3,6 @@
#include "ImageDisplay.h"
#include <imgui.h>
#include <iostream>
#include <ostream>
#include "../UIManager.h"
@ -18,10 +17,9 @@ public:
void update() final
{
// Adjust logo scale and speed based on viewport size so it is consistent
// Want scale proportionally to the window size
auto viewportSize = ImGui::GetMainViewport()->Size;
if (lastViewportSize.x != viewportSize.x || lastViewportSize.y != viewportSize.y)
{
if (lastViewportSize.x != viewportSize.x || lastViewportSize.y != viewportSize.y) {
float displaySizeScalePrev = lastViewportSize.x/1280.f;
float displaySizeScale = viewportSize.x/1280.f;
float adjustedScale = displaySizeScale / displaySizeScalePrev;
@ -46,19 +44,15 @@ public:
ImVec2 minPosition = ImVec2(windowPos.x, windowPos.y);
ImVec2 maxPosition = ImVec2(windowPos.x + windowSize.x - scale*logoSize.x, windowPos.y + windowSize.y - scale*logoSize.y);
if (currentLogoPosition.x >= maxPosition.x)
{
if (currentLogoPosition.x >= maxPosition.x) {
nextOffset.x = -1;
} else if (currentLogoPosition.x < minPosition.x)
{
} else if (currentLogoPosition.x < minPosition.x) {
nextOffset.x = 1;
}
if (currentLogoPosition.y >= maxPosition.y)
{
if (currentLogoPosition.y >= maxPosition.y) {
nextOffset.y = -1;
} else if (currentLogoPosition.y < minPosition.y)
{
} else if (currentLogoPosition.y < minPosition.y) {
nextOffset.y = 1;
}

View File

@ -23,14 +23,12 @@ public:
// Update max bad groups for each bin
auto badGroups = numberGrid->getBadGroups();
for (auto &[id, group] : badGroups)
{
for (auto &[id, group] : badGroups) {
bins[group->binIdx].maxBadGroups++;
}
// Load settings
if (auto loadedSettings = loadSettings(settingsSavePath))
{
if (auto loadedSettings = loadSettings(settingsSavePath)) {
displaySettings = loadedSettings->displaySettings;
controlSettings = loadedSettings->controlSettings;
std::cout << "Successfully loaded settings from disk." << std::endl;
@ -43,8 +41,7 @@ public:
ImGuiIO& io = ImGui::GetIO();
font = io.Fonts->AddFontFromFileTTF("./assets/Montserrat-Bold.ttf", 50.f);
io.Fonts->Build();
if (font == nullptr)
{
if (font == nullptr) {
font = ImGui::GetDefaultFont();
std::cerr << "Failed to load 'Montserrat-Bold' font." << std::endl;
}
@ -82,29 +79,26 @@ public:
void triggerLoadAnimation() final
{
// Reset 'regenerate scale' on all numbers
for (auto &[x, gridY] : numberGrid->getGrid())
{
for (auto &[y, gridNumber] : gridY)
{
for (auto &[x, gridY] : numberGrid->getGrid()) {
for (auto &[y, gridNumber] : gridY) {
gridNumber->regenerateScale = 0.f;
}
}
}
private:
std::optional<int> drawNumbersGrid(const ImVec2& windowPos, const ImVec2& windowSize, const ImVec2& mousePos, bool updateDisplayInfos)
{
std::optional<int> refiningToBin = std::nullopt;
for (auto &[x, gridY] : numberGrid->getGrid())
{
for (auto &[y, gridNumber] : gridY)
{
for (auto &[x, gridY] : numberGrid->getGrid()) {
for (auto &[y, gridNumber] : gridY) {
std::string numberToDraw = "numbers/" + std::to_string(gridNumber->num) + ".png";
auto [width, height] = imageDisplay->getImageSize(numberToDraw);
double badScale = gridNumber->badGroup ? gridNumber->badGroup->scale : 0.0;
if (updateDisplayInfos)
{
if (updateDisplayInfos) {
// Only need to update when viewport has changed
ImVec2 localNumberPos = ImVec2((x * displaySettings.gridSpacing + panelOffset.x)*panelScale, (y * displaySettings.gridSpacing + panelOffset.y)*panelScale);
gridNumber->displayInfos.centerX = localNumberPos.x + windowPos.x;
gridNumber->displayInfos.centerY = localNumberPos.y + windowPos.y;
@ -114,104 +108,97 @@ private:
double heightOffset = (baseNumberScale*height/2.f);
gridNumber->displayInfos.isVisible = gridNumber->displayInfos.centerX + widthOffset < windowPos.x + windowSize.x && gridNumber->displayInfos.centerX - widthOffset > windowPos.x &&
gridNumber->displayInfos.centerY + heightOffset < windowPos.y + windowSize.y - displayPresets.numberWindowBufferBottom && gridNumber->displayInfos.centerY - heightOffset > windowPos.y + displayPresets.numberWindowBufferTop;
}
if (!gridNumber->displayInfos.isVisible)
{
// Don't draw numbers out of viewport
if (!gridNumber->displayInfos.isVisible) {
continue;
}
auto centerPos = ImVec2(gridNumber->displayInfos.centerX, gridNumber->displayInfos.centerY);
if (gridNumber->badGroup && gridNumber->badGroup->refined)
{
float startX = gridNumber->displayInfos.centerX;
float startY = gridNumber->displayInfos.centerY;
if (gridNumber->displayInfos.refinedX == -1)
{
gridNumber->displayInfos.refinedX = startX;
gridNumber->displayInfos.refinedY = startY;
}
auto binIdx = gridNumber->badGroup->binIdx;
if (binIdx > 4)
{
std::cout << "Error: Bin index greater than expected. Setting to max." << std::endl;
binIdx = 4;
}
float distX = bins[binIdx].pos.x - gridNumber->displayInfos.refinedX;
float distY = bins[binIdx].pos.y - gridNumber->displayInfos.refinedY;
float distance = sqrt(distX * distX + distY * distY);
const float moveSpeed = 3.0f;
if (distance > moveSpeed)
{
float dirX = distX / distance;
float dirY = distY / distance;
gridNumber->displayInfos.refinedX += dirX * moveSpeed;
gridNumber->displayInfos.refinedY += dirY * moveSpeed;
centerPos = ImVec2(gridNumber->displayInfos.refinedX, gridNumber->displayInfos.refinedY);
refiningToBin = gridNumber->badGroup->binIdx;
}
else
{
gridNumber->badGroup.reset(); // No longer a bad number
gridNumber->num = numberGrid->randomNumber(0,9);
gridNumber->regenerateScale = 0.f;
}
}
// Animate number on screen
float numberAlpha = 255;
if (gridNumber->regenerateScale < 1.f)
{
if (gridNumber->regenerateScale < 1.f) {
gridNumber->regenerateScale += numberGrid->randomNumber(0,10)*0.001f;
numberAlpha = static_cast<int>(std::clamp(gridNumber->regenerateScale*2.f*255.f, 0.f, 255.f));
}
// Offset from noise scale
double noiseScale = perlin.noise3D((x * displaySettings.noiseScale), (y * displaySettings.noiseScale), t*displaySettings.noiseSpeed);
if (gridNumber->displayInfos.horizontalOffset)
{
if (gridNumber->displayInfos.horizontalOffset) {
centerPos.x += noiseScale*displaySettings.noiseScaleOffset;
} else
{
} else {
centerPos.y += noiseScale*displaySettings.noiseScaleOffset;
}
// Colour
auto col = ColorValues::lumonBlue.Value;
col.w = numberAlpha;
if (revealMap && gridNumber->badGroup)
{
if (revealMap && gridNumber->badGroup) {
col = gridNumber->badGroup->isActive ? ImVec4(255,255,0,numberAlpha) : ImVec4(255,0,0,255);
}
// Scale from mouse hovering
auto numberScale = getScaleFromCursor(centerPos, mousePos);
if (gridNumber->badGroup && gridNumber->badGroup->isActive)
{
if (numberScale > 1.0f)
{
gridNumber->badGroup->superActive = true;
// Handle if part of bad group
if (gridNumber->badGroup) {
if (gridNumber->badGroup->isActive) {
// Make number 'super active'
if (numberScale > 1.0f) {
gridNumber->badGroup->superActive = true;
}
// Mark as refined on 'LEFT CLICK'
if (numberScale >= (0.5f + displaySettings.mouseScaleMultiplier) && ImGui::IsKeyDown(ImGuiKey_MouseLeft)) {
gridNumber->badGroup->refined = true;
bins[gridNumber->badGroup->binIdx].badGroupsRefined++;
}
}
if (numberScale >= (0.5f + displaySettings.mouseScaleMultiplier) && ImGui::IsKeyDown(ImGuiKey_MouseLeft))
{
gridNumber->badGroup->refined = true;
bins[gridNumber->badGroup->binIdx].badGroupsRefined++;
// Add jitter to 'super active' bad numbers
if (gridNumber->badGroup->superActive) {
centerPos.x += numberGrid->randomNumber(-10, 10)*badScale;
centerPos.y += numberGrid->randomNumber(-10, 10)*badScale;
}
// Animate position if number has been refined
if (gridNumber->badGroup->refined) {
float startX = gridNumber->displayInfos.centerX;
float startY = gridNumber->displayInfos.centerY;
if (gridNumber->displayInfos.refinedX == -1) {
gridNumber->displayInfos.refinedX = startX;
gridNumber->displayInfos.refinedY = startY;
}
auto binIdx = gridNumber->badGroup->binIdx;
if (binIdx > 4) {
std::cout << "Error: Bin index greater than expected. Setting to max." << std::endl;
binIdx = 4;
}
float distX = bins[binIdx].pos.x - gridNumber->displayInfos.refinedX;
float distY = bins[binIdx].pos.y - gridNumber->displayInfos.refinedY;
float distance = sqrt(distX * distX + distY * distY);
if (distance > displaySettings.refinedToBinSpeed) {
float dirX = distX / distance;
float dirY = distY / distance;
gridNumber->displayInfos.refinedX += dirX * displaySettings.refinedToBinSpeed;
gridNumber->displayInfos.refinedY += dirY * displaySettings.refinedToBinSpeed;
centerPos = ImVec2(gridNumber->displayInfos.refinedX, gridNumber->displayInfos.refinedY);
refiningToBin = gridNumber->badGroup->binIdx;
} else {
gridNumber->badGroup.reset(); // No longer a bad number
gridNumber->num = numberGrid->randomNumber(0,9);
gridNumber->regenerateScale = 0.f;
}
}
}
if (gridNumber->badGroup && gridNumber->badGroup->superActive)
{
centerPos.x += numberGrid->randomNumber(-10, 10)*badScale;
centerPos.y += numberGrid->randomNumber(-10, 10)*badScale;
}
// Draw number
float combinedScale = gridNumber->regenerateScale*displaySettings.imageScale*numberScale*panelScale + badScale;
ImGui::SetCursorPos(ImVec2(centerPos.x - ImGui::GetWindowPos().x - ((width*combinedScale)/2.f), centerPos.y - ImGui::GetWindowPos().y - ((height*combinedScale)/2.f)));
imageDisplay->drawImGuiImage(numberToDraw, combinedScale, col);
@ -226,10 +213,11 @@ private:
{
std::string binPercentPath = "bins/bin-percent.png";
auto [widthP, heightP] = imageDisplay->getImageSize(binPercentPath);
for (auto &b : bins)
{
for (auto &b : bins) {
// Scale based on viewport size
auto pos = b.updatePos(windowSize, windowPos, displayPresets.numberWindowBufferBottom - displayPresets.binOffset);
// Draw bin images
std::string binPath = "bins/bin0" + std::to_string(b.id) + ".png";
auto [width, height] = imageDisplay->getImageSize(binPath);
ImGui::SetCursorPos(ImVec2(pos.x - windowPos.x - (width*displayPresets.binImageScale/2.f), pos.y - windowPos.y - (height*displayPresets.binImageScale/2.f)));
@ -239,6 +227,7 @@ private:
ImGui::SetCursorPos(ImVec2(percentPos.x - windowPos.x - (widthP*displayPresets.binImageScale/2.f), percentPos.y - windowPos.y - (heightP*displayPresets.binImageScale/2.f)));
imageDisplay->drawImGuiImage(binPercentPath, displayPresets.binImageScale, ColorValues::lumonBlue);
// Draw percentage bar and text
ImVec2 trCorner = ImVec2(percentPos.x - (widthP*displayPresets.binImageScale/2.f), percentPos.y - (heightP*displayPresets.binImageScale/2.f));
ImVec2 brCorner = ImVec2(percentPos.x + (widthP*displayPresets.binImageScale/2.f), percentPos.y + (heightP*displayPresets.binImageScale/2.f));
@ -249,9 +238,8 @@ private:
drawList->AddRectFilled(trCorner, ImVec2(trCorner.x + ((brCorner.x - trCorner.x)* percentD), brCorner.y), ImColor(ColorValues::lumonBlue.Value.x, ColorValues::lumonBlue.Value.y, ColorValues::lumonBlue.Value.z, 0.3f));
// Bin open
if (numberRefiningToBin && *numberRefiningToBin == b.id - 1)
{
// Animate bin open
if (numberRefiningToBin && *numberRefiningToBin == b.id - 1) {
std::string binOpenPath = "bins/bin-open.png";
auto [widthO, heightO] = imageDisplay->getImageSize(binOpenPath);
ImGui::SetCursorPos(ImVec2(pos.x - windowPos.x - (widthO*displayPresets.binImageScale/2.f), pos.y - windowPos.y - (heightO*displayPresets.binImageScale/2.f) - (height*displayPresets.binImageScale)));
@ -268,6 +256,7 @@ private:
drawList->AddRect(headerBoxMin, headerBoxMax, ColorValues::lumonBlue);
ImVec2 headerTextPos = ImVec2(headerBoxMin.x + 25.f, (headerBoxMin.y+headerBoxMax.y)/2.f - displayPresets.fontSize/2.f);
drawList->AddText(font, displayPresets.fontSize, headerTextPos, ColorValues::lumonBlue, "@andrewchilicki");
// Lumon logo
std::string logoPath = "lumon-logo.png";
auto [widthH, heightH] = imageDisplay->getImageSize(logoPath);
@ -275,8 +264,7 @@ private:
imageDisplay->drawImGuiImage(logoPath, displayPresets.headerImageScale, ColorValues::lumonBlue);
// Horizontal lines
auto drawLine = [&](const float y)
{
auto drawLine = [&](const float y) {
drawList->AddLine(ImVec2(windowPos.x, y), ImVec2(windowPos.x + windowSize.x, y), ColorValues::lumonBlue, displayPresets.lineThickness);
};
@ -294,40 +282,33 @@ private:
static bool viewportInit = false;
bool viewportChanged = !viewportInit;
// Handle arrow key input
if (ImGui::IsKeyPressed(ImGuiKey_LeftArrow))
{
if (ImGui::IsKeyPressed(ImGuiKey_LeftArrow)) {
panelOffset.x += controlSettings.arrowSensitivity;
viewportChanged = true;
} else if (ImGui::IsKeyPressed(ImGuiKey_RightArrow))
{
} else if (ImGui::IsKeyPressed(ImGuiKey_RightArrow)) {
panelOffset.x -= controlSettings.arrowSensitivity;
viewportChanged = true;
}
if (ImGui::IsKeyPressed(ImGuiKey_UpArrow))
{
if (ImGui::IsKeyPressed(ImGuiKey_UpArrow)) {
panelOffset.y += controlSettings.arrowSensitivity;
viewportChanged = true;
} else if (ImGui::IsKeyPressed(ImGuiKey_DownArrow))
{
} else if (ImGui::IsKeyPressed(ImGuiKey_DownArrow)) {
panelOffset.y -= controlSettings.arrowSensitivity;
viewportChanged = true;
}
// Handle zoom
if (ImGui::IsKeyPressed(ImGuiKey_Comma))
{
if (ImGui::IsKeyPressed(ImGuiKey_Comma)) {
panelScale -= controlSettings.zoomSensitivity;
viewportChanged = true;
} else if (ImGui::IsKeyPressed(ImGuiKey_Period))
{
} else if (ImGui::IsKeyPressed(ImGuiKey_Period)) {
panelScale += controlSettings.zoomSensitivity;
viewportChanged = true;
}
// panelScale = std::clamp(panelScale, 0.8f, 1.8f);
panelScale = std::clamp(panelScale, displaySettings.minZoomScale, displaySettings.maxZoomScale);
if (viewportChanged)
{
if (viewportChanged) {
// Clamp movement to within grid boundaries
float gridWidthScaled = gridSize * displaySettings.gridSpacing * panelScale;
float gridHeightScaled = gridSize * displaySettings.gridSpacing * panelScale;
@ -337,8 +318,7 @@ private:
float minOffsetY = -gridHeightScaled + windowSize.y - displayPresets.numberWindowBufferTop;
float maxOffsetY = displayPresets.numberWindowBufferTop;
if (!viewportInit)
{
if (!viewportInit) {
// Start at center of grid
panelOffset.x = (windowSize.x - gridWidthScaled) / 2.0f / panelScale;
panelOffset.y = (windowSize.y - gridHeightScaled) / 2.0f / panelScale;
@ -355,8 +335,7 @@ private:
void drawSettings() final
{
ImGui::SetWindowFontScale(displayPresets.settingsFontScale);
if (ImGui::Button("Save Settings"))
{
if (ImGui::Button("Save Settings")) {
saveSettings(Settings{displaySettings, controlSettings}, settingsSavePath);
}
ImGui::Separator();
@ -366,6 +345,9 @@ private:
ImGui::InputFloat("Numbers Grid Spacing", &displaySettings.gridSpacing);
ImGui::InputFloat("Mouse Scale Radius", &displaySettings.mouseScaleRadius);
ImGui::InputFloat("Mouse Scale Multiplier", &displaySettings.mouseScaleMultiplier);
ImGui::InputFloat("Min Scale Multiplier", &displaySettings.minZoomScale);
ImGui::InputFloat("Max Scale Multiplier", &displaySettings.maxZoomScale);
ImGui::InputFloat("Refined to Bin Speed", &displaySettings.refinedToBinSpeed);
ImGui::Text("Noise:");
ImGui::InputFloat("Noise Speed", &displaySettings.noiseSpeed);
ImGui::InputFloat("Noise Scale", &displaySettings.noiseScale);
@ -380,11 +362,12 @@ private:
bool updateDisplaySettings(PresetDisplaySettings &settings, float globalScale)
{
// Want preset display settings to scale proportionally to the window size
auto viewportSize = ImGui::GetMainViewport()->Size;
if (lastViewportSize.x == viewportSize.x && lastViewportSize.y == viewportSize.y && lastGlobalScale == globalScale)
{
if (lastViewportSize.x == viewportSize.x && lastViewportSize.y == viewportSize.y && lastGlobalScale == globalScale) {
return false;
}
float displaySizeScalePrev = lastViewportSize.x/1280.f * lastGlobalScale;
float displaySizeScale = viewportSize.x/1280.f * globalScale;
float newScale = displaySizeScale / displaySizeScalePrev;
@ -415,8 +398,7 @@ private:
float distY = mousePos.y - globalNumberPos.y;
float distance = sqrt(distX * distX + distY * distY);
if (distance < displaySettings.mouseScaleRadius)
{
if (distance < displaySettings.mouseScaleRadius) {
return 1.0f + (displaySettings.mouseScaleRadius - distance) / displaySettings.mouseScaleRadius * displaySettings.mouseScaleMultiplier;
}
return 1.0f;
@ -443,6 +425,7 @@ private:
// Debug options
bool revealMap = false;
// TODO - Move to class
struct Bin
{
int id;
@ -451,8 +434,7 @@ private:
int badGroupsRefined = 0;
int maxBadGroups = 0;
ImVec2 updatePos(const ImVec2 &windowSize, const ImVec2 &windowPos, float offsetY)
{
ImVec2 updatePos(const ImVec2 &windowSize, const ImVec2 &windowPos, float offsetY) {
pos = ImVec2(windowPos.x + (windowSize.x / 6)*id, windowPos.y + windowSize.y - offsetY);
return pos;
}

View File

@ -6,14 +6,13 @@ class ImageDisplay;
class NumbersPanel {
public:
virtual void init() = 0;
virtual void update() = 0;
virtual void drawNumbersPanel() = 0;
virtual void drawSettings() = 0;
virtual void triggerLoadAnimation() = 0;
virtual void drawSettings() = 0;
virtual ~NumbersPanel() = default;
};

View File

@ -7,6 +7,7 @@
struct PresetDisplaySettings
{
// Preset sizing and offsets for UI
float numberWindowBufferTop = 125.f;
float numberWindowBufferBottom = 115.f;
@ -57,8 +58,7 @@ inline void saveSettingsJson(const nlohmann::json& settingsJson, const std::stri
file.flush();
file.close();
std::cout << "Settings saved to disk." << std::endl;
}
catch (const std::exception& e) {
} catch (const std::exception& e) {
std::cerr << "Error saving settings: " << e.what() << std::endl;
}
}
@ -72,20 +72,27 @@ struct DisplaySettings
float mouseScaleRadius = 100.f;
float mouseScaleMultiplier = 2.f;
float maxZoomScale = 0.8f;
float minZoomScale = 0.2f;
float noiseSpeed = 0.004f;
float noiseScale = 1.f;
float noiseScaleOffset = 15;
float refinedToBinSpeed = 3.0f;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(DisplaySettings,
globalScale,
imageScale,
gridSpacing,
mouseScaleRadius,
mouseScaleMultiplier,
maxZoomScale,
minZoomScale,
noiseSpeed,
noiseScale,
noiseScaleOffset
noiseScaleOffset,
refinedToBinSpeed
);
};
@ -107,26 +114,21 @@ struct Settings
inline std::optional<Settings> loadSettings(const std::string& jsonPath)
{
try
{
if (auto json = loadSettingsFromJson(jsonPath))
{
try {
if (auto json = loadSettingsFromJson(jsonPath)) {
return json->get<Settings>();
}
} catch (const std::exception& e)
{
} catch (const std::exception& e) {
std::cerr << "Error loading settings: " << e.what() << std::endl;
}
return std::nullopt;
}
inline void saveSettings(const Settings& settings, const std::string& jsonPath)
{
try
{
try {
nlohmann::json json = settings;
saveSettingsJson(json, jsonPath);
} catch (const std::exception& e)
{
} catch (const std::exception& e) {
std::cerr << "Error saving settings: " << e.what() << std::endl;
}
}

View File

@ -1,11 +1,11 @@
#include "UI/UIManager.h"
#include "imgui.h"
#include "backends/imgui_impl_glfw.h"
#include <GLFW/glfw3.h>
#include <imgui_impl_opengl3.h>
#include <iostream>
#include "UI/UIManager.h"
void glfw_error_callback(int error, const char* description) {
std::cerr << "GLFW Error (" << error << "): " << description << std::endl;
}