mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 14:50:41 -07:00
Initial commit for GitHub migration based on spice2x-25-03-03
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
#include <map>
|
||||
|
||||
#include "iidx_seg.h"
|
||||
#include "games/io.h"
|
||||
#include "games/iidx/iidx.h"
|
||||
#include "util/logging.h"
|
||||
|
||||
namespace overlay::windows {
|
||||
|
||||
uint32_t IIDX_SEGMENT_FONT_SIZE = 64;
|
||||
std::optional<uint32_t> IIDX_SEGMENT_FONT_COLOR = std::nullopt;
|
||||
std::string IIDX_SEGMENT_LOCATION = "bottom";
|
||||
|
||||
static const size_t TICKER_SIZE = 9;
|
||||
static const ImVec4 DARK_GRAY(0.1f, 0.1f, 0.1f, 1.f);
|
||||
static const ImVec4 RED(1.f, 0.f, 0.f, 1.f);
|
||||
static const int PADDING_Y = 8;
|
||||
static const int PADDING_X = 4;
|
||||
|
||||
static const std::map<char, std::pair<char, char>> CHARMAP = {\
|
||||
// period - add a space afterwards (game sends 'm' for period)
|
||||
{'m', {'.', ' '}},
|
||||
// exclamation mark (use ./ to make it look like one)
|
||||
{'!', {'.', '/'}},
|
||||
// font doesn't have tilde so using a dash instead
|
||||
{'~', {'-', '\0'}},
|
||||
};
|
||||
|
||||
IIDXSegmentDisplay::IIDXSegmentDisplay(SpiceOverlay *overlay) : Window(overlay) {
|
||||
if (!DSEG_FONT) {
|
||||
log_fatal("iidx_seg", "DSEG_FONT is null");
|
||||
}
|
||||
|
||||
this->title = "IIDX LED Segment Display";
|
||||
this->toggle_button = games::OverlayButtons::ToggleSubScreen;
|
||||
this->remove_window_padding = true;
|
||||
this->size_max = ImVec2(ImGui::GetIO().DisplaySize.x, ImGui::GetIO().DisplaySize.y);
|
||||
this->flags = ImGuiWindowFlags_NoTitleBar
|
||||
| ImGuiWindowFlags_NoScrollbar
|
||||
| ImGuiWindowFlags_NoResize
|
||||
| ImGuiWindowFlags_NoNavFocus
|
||||
| ImGuiWindowFlags_NoNavInputs
|
||||
| ImGuiWindowFlags_NoDocking;
|
||||
|
||||
if (IIDX_SEGMENT_FONT_COLOR.has_value()) {
|
||||
const auto rgb = IIDX_SEGMENT_FONT_COLOR.value();
|
||||
const auto rgba = IM_COL32_A_MASK | rgb;
|
||||
this->color = ImGui::ColorConvertU32ToFloat4(rgba);
|
||||
} else {
|
||||
this->color = RED;
|
||||
}
|
||||
}
|
||||
|
||||
void IIDXSegmentDisplay::calculate_initial_window() {
|
||||
// ImGui::CalcTextSize doesn't seem to work here, so manually calculate
|
||||
ImGui::PushFont(DSEG_FONT);
|
||||
this->init_size = ImGui::CalcTextSize("~.~.~.~.~.~.~.~.~.");
|
||||
this->init_size.x += PADDING_X * 2;
|
||||
this->init_size.y += PADDING_Y * 2;
|
||||
ImGui::PopFont();
|
||||
|
||||
// initial horizontal position
|
||||
if (IIDX_SEGMENT_LOCATION.find("left") != std::string::npos) {
|
||||
this->init_pos.x = 0;
|
||||
} else if (IIDX_SEGMENT_LOCATION.find("right") != std::string::npos) {
|
||||
this->init_pos.x = ImGui::GetIO().DisplaySize.x - this->init_size.x;
|
||||
} else {
|
||||
// center
|
||||
this->init_pos.x = ImGui::GetIO().DisplaySize.x / 2 - this->init_size.x / 2;
|
||||
}
|
||||
|
||||
// initial vertical position
|
||||
if (IIDX_SEGMENT_LOCATION.rfind("top", 0) == 0) {
|
||||
this->init_pos.y = 0;
|
||||
} else {
|
||||
// bottom
|
||||
this->init_pos.y = ImGui::GetIO().DisplaySize.y - this->init_size.y;
|
||||
}
|
||||
}
|
||||
|
||||
void IIDXSegmentDisplay::build_content() {
|
||||
char input_ticker[TICKER_SIZE];
|
||||
|
||||
// get ticker content from game
|
||||
games::iidx::IIDX_LED_TICKER_LOCK.lock();
|
||||
memcpy(input_ticker, games::iidx::IIDXIO_LED_TICKER, TICKER_SIZE);
|
||||
games::iidx::IIDX_LED_TICKER_LOCK.unlock();
|
||||
|
||||
// since every input character can result in up to two characters,
|
||||
// need double size for output
|
||||
const size_t TICKER_OUTPUT_SIZE = TICKER_SIZE * 2 + 1;
|
||||
char output_ticker[TICKER_OUTPUT_SIZE];
|
||||
int output_ticker_index = 0;
|
||||
|
||||
// look at each input char and convert into output char(s)
|
||||
for (const auto c : input_ticker) {
|
||||
// see if there is an applicable rule for this input character
|
||||
if (0 == CHARMAP.count(c)) {
|
||||
// if not, copy the first character and keep going
|
||||
output_ticker[output_ticker_index] = c;
|
||||
output_ticker_index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// there is a replacement rule for this input character
|
||||
auto replacements = CHARMAP.at(c);
|
||||
|
||||
// replace the first character...
|
||||
output_ticker[output_ticker_index] = replacements.first;
|
||||
output_ticker_index += 1;
|
||||
|
||||
// and optionally add the second character
|
||||
if (replacements.second != '\0') {
|
||||
output_ticker[output_ticker_index] = replacements.second;
|
||||
output_ticker_index += 1;
|
||||
}
|
||||
}
|
||||
if ((int)TICKER_OUTPUT_SIZE <= output_ticker_index) {
|
||||
log_fatal("iidx_seg", "{} is beyond array bounds", output_ticker_index);
|
||||
}
|
||||
|
||||
// terminating null...
|
||||
output_ticker[output_ticker_index] = '\0';
|
||||
|
||||
// finally, draw UI elements
|
||||
draw_ticker(output_ticker);
|
||||
}
|
||||
|
||||
void IIDXSegmentDisplay::draw_ticker(char *ticker_string) {
|
||||
ImGui::PushFont(DSEG_FONT);
|
||||
|
||||
const auto pos = ImVec2(PADDING_X, PADDING_Y);
|
||||
|
||||
// to imitate LED "off"
|
||||
ImGui::SetCursorPos(pos);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, DARK_GRAY);
|
||||
ImGui::TextUnformatted("~.~.~.~.~.~.~.~.~.");
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
// ... then draw the LED "on" above it
|
||||
ImGui::SetCursorPos(pos);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, this->color);
|
||||
ImGui::TextUnformatted(ticker_string);
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
ImGui::PopFont();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user