aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <clyne@bitgloo.com>2021-11-22 19:44:48 -0500
committerClyne Sullivan <clyne@bitgloo.com>2021-11-22 19:44:48 -0500
commitfde531e7c44ea917f745a9f800178fbe83fa19b5 (patch)
tree7b305c0bb27bf0fd30f9f0feeb7ae6dadbc8d1ae
parentc76ba69fc933a86e526855b097907a728e24568b (diff)
more refactor; draw samples grid and cursor; gen load fixes
-rw-r--r--Makefile2
-rw-r--r--source/circular.hpp32
-rw-r--r--source/device.cpp151
-rw-r--r--source/device_formula.cpp12
-rw-r--r--source/file.cpp6
-rw-r--r--source/gui.cpp6
-rw-r--r--source/gui_device.cpp129
-rw-r--r--source/imgui/TextEditor.cpp356
-rw-r--r--source/imgui/TextEditor.h6
-rw-r--r--source/imgui/imgui.h6
-rw-r--r--source/logview.cpp82
-rw-r--r--source/logview.h80
-rw-r--r--source/main.cpp143
13 files changed, 389 insertions, 622 deletions
diff --git a/Makefile b/Makefile
index 26e0208..81e580d 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@ $(OUTPUT): $(OFILES)
clean:
@echo " CLEAN"
- @rm $(OFILES) $(OUTPUT)
+ @rm -f $(OFILES) $(OUTPUT)
%.o: %.cpp
@echo " CXX " $<
diff --git a/source/circular.hpp b/source/circular.hpp
new file mode 100644
index 0000000..33b8ee0
--- /dev/null
+++ b/source/circular.hpp
@@ -0,0 +1,32 @@
+#ifndef CIRCULAR_HPP
+#define CIRCULAR_HPP
+
+#include <iterator>
+
+template<template<typename> class Container, typename T>
+class CircularBuffer
+{
+public:
+ CircularBuffer(Container<T>& container) :
+ m_begin(std::begin(container)),
+ m_end(std::end(container)),
+ m_current(std::begin(container)) {}
+
+ void put(const T& value) noexcept {
+ *m_current = value;
+ if (++m_current == m_end)
+ m_current = m_begin;
+ }
+
+ std::size_t size() const noexcept {
+ return std::distance(m_begin, m_end);
+ }
+
+private:
+ Container<T>::iterator m_begin;
+ Container<T>::iterator m_end;
+ Container<T>::iterator m_current;
+};
+
+#endif // CIRCULAR_HPP
+
diff --git a/source/device.cpp b/source/device.cpp
index df3f361..abcc88a 100644
--- a/source/device.cpp
+++ b/source/device.cpp
@@ -11,10 +11,12 @@
#include "stmdsp.hpp"
+#include "circular.hpp"
#include "imgui.h"
#include "wav.hpp"
#include <array>
+#include <cctype>
#include <charconv>
#include <cmath>
#include <deque>
@@ -30,7 +32,7 @@
extern std::string tempFileName;
extern void log(const std::string& str);
-extern std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string_view);
+extern std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string&);
std::shared_ptr<stmdsp::device> m_device;
@@ -62,14 +64,16 @@ static std::vector<stmdsp::dacsample_t> tryReceiveChunk(
std::shared_ptr<stmdsp::device> device,
auto readFunc)
{
- int tries = -1;
- do {
+ for (int tries = 0; tries < 100; ++tries) {
+ if (!device->is_running())
+ break;
+
const auto chunk = readFunc(device.get());
if (!chunk.empty())
return chunk;
else
std::this_thread::sleep_for(std::chrono::microseconds(20));
- } while (++tries < 100 && device->is_running());
+ }
return {};
}
@@ -94,15 +98,13 @@ static void drawSamplesTask(std::shared_ptr<stmdsp::device> device)
const auto bufferTime = getBufferPeriod(device);
- std::unique_lock<std::timed_mutex> lockDraw (mutexDrawSamples, std::defer_lock);
- std::unique_lock<std::timed_mutex> lockDevice (mutexDeviceLoad, std::defer_lock);
-
- auto addToQueue = [&lockDraw](auto& queue, const auto& chunk) {
- lockDraw.lock();
+ const auto addToQueue = [](auto& queue, const auto& chunk) {
+ std::scoped_lock lock (mutexDrawSamples);
std::copy(chunk.cbegin(), chunk.cend(), std::back_inserter(queue));
- lockDraw.unlock();
};
+ std::unique_lock<std::timed_mutex> lockDevice (mutexDeviceLoad, std::defer_lock);
+
while (device && device->is_running()) {
const auto next = std::chrono::high_resolution_clock::now() + bufferTime;
@@ -112,7 +114,7 @@ static void drawSamplesTask(std::shared_ptr<stmdsp::device> device)
lockDevice.unlock();
addToQueue(drawSamplesQueue, chunk);
- if (logSamplesFile.good()) {
+ if (logSamplesFile.is_open()) {
for (const auto& s : chunk)
logSamplesFile << s << '\n';
}
@@ -145,29 +147,29 @@ static void feedSigGenTask(std::shared_ptr<stmdsp::device> device)
std::vector<stmdsp::dacsample_t> wavBuf (device->get_buffer_size() * 2, 2048);
- std::unique_lock<std::timed_mutex> lockDevice (mutexDeviceLoad, std::defer_lock);
+ {
+ std::scoped_lock lock (mutexDeviceLoad);
+ device->siggen_upload(wavBuf.data(), wavBuf.size());
+ device->siggen_start();
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ }
- lockDevice.lock();
- device->siggen_upload(wavBuf.data(), wavBuf.size());
wavBuf.resize(wavBuf.size() / 2);
- device->siggen_start();
- std::this_thread::sleep_for(std::chrono::milliseconds(1));
- lockDevice.unlock();
-
std::vector<int16_t> wavIntBuf (wavBuf.size());
while (device->is_siggening()) {
const auto next = std::chrono::high_resolution_clock::now() + delay;
wavOutput.next(wavIntBuf.data(), wavIntBuf.size());
- auto src = wavIntBuf.cbegin();
- std::generate(wavBuf.begin(), wavBuf.end(),
- [&src] { return static_cast<stmdsp::dacsample_t>(*src++ / 16 + 2048); });
+ std::transform(wavIntBuf.cbegin(), wavIntBuf.cend(),
+ wavBuf.begin(),
+ [](auto i) { return static_cast<stmdsp::dacsample_t>(i / 16 + 2048); });
- lockDevice.lock();
- while (!device->siggen_upload(wavBuf.data(), wavBuf.size()))
- std::this_thread::sleep_for(uploadDelay);
- lockDevice.unlock();
+ {
+ std::scoped_lock lock (mutexDeviceLoad);
+ while (!device->siggen_upload(wavBuf.data(), wavBuf.size()))
+ std::this_thread::sleep_for(uploadDelay);
+ }
std::this_thread::sleep_until(next);
}
@@ -179,10 +181,9 @@ static void statusTask(std::shared_ptr<stmdsp::device> device)
return;
while (device->connected()) {
- std::unique_lock<std::timed_mutex> lockDevice (mutexDeviceLoad, std::defer_lock);
- lockDevice.lock();
+ mutexDeviceLoad.lock();
const auto [status, error] = device->get_status();
- lockDevice.unlock();
+ mutexDeviceLoad.unlock();
if (error != stmdsp::Error::None) {
switch (error) {
@@ -214,7 +215,7 @@ void deviceLoadAudioFile(const std::string& file)
void deviceLoadLogFile(const std::string& file)
{
logSamplesFile = std::ofstream(file);
- if (logSamplesFile.good())
+ if (logSamplesFile.is_open())
log("Log file ready.");
else
log("Error: Could not open log file.");
@@ -261,7 +262,7 @@ bool deviceConnect()
if (!m_device) {
stmdsp::scanner scanner;
- if (auto devices = scanner.scan(); !devices.empty()) {
+ if (const auto devices = scanner.scan(); !devices.empty()) {
try {
m_device.reset(new stmdsp::device(devices.front()));
} catch (...) {
@@ -307,7 +308,7 @@ void deviceStart(bool measureCodeTime, bool logResults, bool drawSamples)
std::this_thread::sleep_for(std::chrono::microseconds(150));
m_device->continuous_stop();
}
- if (logSamplesFile.good()) {
+ if (logSamplesFile.is_open()) {
logSamplesFile.close();
log("Log file saved and closed.");
}
@@ -329,12 +330,9 @@ void deviceAlgorithmUpload()
{
if (!m_device) {
log("No device connected.");
- return;
} else if (m_device->is_running()) {
- return;
- }
-
- if (std::ifstream algo (tempFileName + ".o"); algo.good()) {
+ log("Cannot upload algorithm while running.");
+ } else if (std::ifstream algo (tempFileName + ".o"); algo.is_open()) {
std::ostringstream sstr;
sstr << algo.rdbuf();
auto str = sstr.str();
@@ -350,7 +348,9 @@ void deviceAlgorithmUnload()
{
if (!m_device) {
log("No device connected.");
- } else if (!m_device->is_running()) {
+ } else if (m_device->is_running()) {
+ log("Cannot unload algorithm while running.");
+ } else {
m_device->unload_filter();
log("Algorithm unloaded.");
}
@@ -361,85 +361,82 @@ void deviceGenLoadList(const std::string_view list)
std::vector<stmdsp::dacsample_t> samples;
auto it = list.cbegin();
- while (it != list.cend() && samples.size() < stmdsp::SAMPLES_MAX * 2) {
- const auto end = list.find_first_not_of("0123456789",
- std::distance(list.cbegin(), it));
- const auto itend = end != std::string_view::npos ? list.cbegin() + end
- : list.cend();
+ while (it != list.cend()) {
+ const auto itend = std::find_if(it, list.cend(),
+ [](char c) { return !isdigit(c); });
+
unsigned long n;
- const auto [ptr, ec] = std::from_chars(it, itend, n);
- if (ec != std::errc())
+ const auto ec = std::from_chars(it, itend, n).ec;
+ if (ec != std::errc()) {
+ log("Error: Bad data in sample list.");
+ break;
+ } else if (n > 4095) {
+ log("Error: Sample data value larger than max of 4095.");
break;
+ } else {
+ samples.push_back(n & 4095);
+ if (samples.size() >= stmdsp::SAMPLES_MAX * 2) {
+ log("Error: Too many samples for signal generator.");
+ break;
+ }
+ }
- samples.push_back(n & 4095);
it = itend;
}
- if (samples.size() <= stmdsp::SAMPLES_MAX * 2) {
+ if (it == list.cend()) {
// DAC buffer must be of even size
if (samples.size() % 2 != 0)
samples.push_back(samples.back());
- if (m_device)
- m_device->siggen_upload(samples.data(), samples.size());
+ m_device->siggen_upload(samples.data(), samples.size());
log("Generator ready.");
- } else {
- log("Error: Too many samples for signal generator.");
}
}
-void deviceGenLoadFormula(std::string_view formula)
+void deviceGenLoadFormula(const std::string& formula)
{
auto samples = deviceGenLoadFormulaEval(formula);
if (!samples.empty()) {
- if (m_device)
- m_device->siggen_upload(samples.data(), samples.size());
-
+ m_device->siggen_upload(samples.data(), samples.size());
log("Generator ready.");
} else {
log("Error: Bad formula.");
}
}
-void pullFromQueue(
+std::size_t pullFromQueue(
std::deque<stmdsp::dacsample_t>& queue,
- std::vector<stmdsp::dacsample_t>& buffer,
- decltype(buffer.begin())& bufferCursor,
+ CircularBuffer<std::vector, stmdsp::dacsample_t>& circ,
double timeframe)
{
- if (buffer.size() != drawSamplesBufferSize) {
- buffer.resize(drawSamplesBufferSize);
- bufferCursor = buffer.begin();
- }
+ if (circ.size() != drawSamplesBufferSize)
+ return drawSamplesBufferSize;
std::scoped_lock lock (mutexDrawSamples);
- auto count = drawSamplesBufferSize / (60. * timeframe) * 1.025;
- count = std::min(drawSamplesInputQueue.size(),
- static_cast<std::size_t>(count));
- for (auto i = count; i; --i) {
- *bufferCursor = queue.front();
+ const auto desiredCount = drawSamplesBufferSize / (60. * timeframe) * 1.025;
+ auto count = std::min(queue.size(), static_cast<std::size_t>(desiredCount));
+ while (count--) {
+ circ.put(queue.front());
queue.pop_front();
-
- if (++bufferCursor == buffer.end())
- bufferCursor = buffer.begin();
}
+
+ return 0;
}
-void pullFromDrawQueue(
- std::vector<stmdsp::dacsample_t>& buffer,
- decltype(buffer.begin())& bufferCursor,
+std::size_t pullFromDrawQueue(
+ CircularBuffer<std::vector, stmdsp::dacsample_t>& circ,
double timeframe)
{
- pullFromQueue(drawSamplesQueue, buffer, bufferCursor, timeframe);
+ return pullFromQueue(drawSamplesQueue, circ, timeframe);
}
-void pullFromInputDrawQueue(
- std::vector<stmdsp::dacsample_t>& buffer,
- decltype(buffer.begin())& bufferCursor,
+std::size_t pullFromInputDrawQueue(
+ CircularBuffer<std::vector, stmdsp::dacsample_t>& circ,
double timeframe)
{
- pullFromQueue(drawSamplesInputQueue, buffer, bufferCursor, timeframe);
+ return pullFromQueue(drawSamplesInputQueue, circ, timeframe);
}
diff --git a/source/device_formula.cpp b/source/device_formula.cpp
index 5c1ca16..c94eab7 100644
--- a/source/device_formula.cpp
+++ b/source/device_formula.cpp
@@ -5,7 +5,7 @@
#include <string_view>
#include <vector>
-std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string_view formulaString)
+std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string& formulaString)
{
double x = 0;
@@ -16,13 +16,17 @@ std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string_view
symbol_table.add_variable("x", x);
symbol_table.add_constants();
expression.register_symbol_table(symbol_table);
- parser.compile(std::string(formulaString), expression);
+ parser.compile(formulaString, expression);
std::vector<stmdsp::dacsample_t> samples (stmdsp::SAMPLES_MAX);
- std::generate(samples.begin(), samples.end(),
- [&] { ++x; return static_cast<stmdsp::dacsample_t>(expression.value()); });
+ auto genFun = [&x, &expression] {
+ stmdsp::dacsample_t s = expression.value();
+ ++x;
+ return s;
+ };
+ std::generate(samples.begin(), samples.end(), genFun);
return samples;
}
diff --git a/source/file.cpp b/source/file.cpp
index dfd9148..a5ef1d8 100644
--- a/source/file.cpp
+++ b/source/file.cpp
@@ -26,6 +26,8 @@
#include <string>
#include <vector>
+#include <SDL2/SDL.h>
+
extern TextEditor editor;
extern void log(const std::string& str);
@@ -133,8 +135,8 @@ void fileRenderMenu()
ImGui::Separator();
if (ImGui::MenuItem("Quit")) {
- extern bool done;
- done = true;
+ SDL_Event quitEvent (SDL_QUIT);
+ SDL_PushEvent(&quitEvent);
}
ImGui::EndMenu();
diff --git a/source/gui.cpp b/source/gui.cpp
index 9720442..515d471 100644
--- a/source/gui.cpp
+++ b/source/gui.cpp
@@ -108,8 +108,10 @@ void guiRender(void (*func)())
SDL_GL_SwapWindow(window);
}
-void guiHandleEvents(bool& done)
+bool guiHandleEvents()
{
+ bool done = false;
+
for (SDL_Event event; SDL_PollEvent(&event);) {
ImGui_ImplSDL2_ProcessEvent(&event);
if (event.type == SDL_QUIT)
@@ -117,6 +119,8 @@ void guiHandleEvents(bool& done)
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
done = true;
}
+
+ return done;
}
void guiShutdown()
diff --git a/source/gui_device.cpp b/source/gui_device.cpp
index 5399c8b..a1d0555 100644
--- a/source/gui_device.cpp
+++ b/source/gui_device.cpp
@@ -1,3 +1,4 @@
+#include "circular.hpp"
#include "imgui.h"
#include "imgui_internal.h"
#include "ImGuiFileDialog.h"
@@ -5,6 +6,7 @@
#include "stmdsp.hpp"
#include <array>
+#include <cstdio>
#include <memory>
#include <string>
#include <string_view>
@@ -15,7 +17,7 @@ extern std::shared_ptr<stmdsp::device> m_device;
void deviceAlgorithmUnload();
void deviceAlgorithmUpload();
bool deviceConnect();
-void deviceGenLoadFormula(std::string_view list);
+void deviceGenLoadFormula(const std::string& list);
void deviceGenLoadList(std::string_view list);
bool deviceGenStartToggle();
void deviceLoadAudioFile(const std::string& file);
@@ -24,13 +26,11 @@ void deviceSetSampleRate(unsigned int index);
void deviceSetInputDrawing(bool enabled);
void deviceStart(bool measureCodeTime, bool logResults, bool drawSamples);
void deviceUpdateDrawBufferSize(double timeframe);
-void pullFromDrawQueue(
- std::vector<stmdsp::dacsample_t>& buffer,
- decltype(buffer.begin())& bufferCursor,
+std::size_t pullFromDrawQueue(
+ CircularBuffer<std::vector, stmdsp::dacsample_t>& circ,
double timeframe);
-void pullFromInputDrawQueue(
- std::vector<stmdsp::dacsample_t>& buffer,
- decltype(buffer.begin())& bufferCursor,
+std::size_t pullFromInputDrawQueue(
+ CircularBuffer<std::vector, stmdsp::dacsample_t>& circ,
double timeframe);
static std::string sampleRatePreview = "?";
@@ -56,11 +56,8 @@ void deviceRenderMenu()
};
if (ImGui::BeginMenu("Run")) {
- const bool isConnected = m_device ? true : false;
- const bool isRunning = isConnected && m_device->is_running();
-
static std::string connectLabel ("Connect");
- addMenuItem(connectLabel, !isConnected || !isRunning, [&] {
+ addMenuItem(connectLabel, !m_device || !m_device->is_running(), [&] {
if (deviceConnect()) {
connectLabel = "Disconnect";
sampleRatePreview =
@@ -68,9 +65,15 @@ void deviceRenderMenu()
deviceUpdateDrawBufferSize(drawSamplesTimeframe);
} else {
connectLabel = "Connect";
+ measureCodeTime = false;
+ logResults = false;
+ drawSamples = false;
}
});
+ const bool isConnected = m_device ? true : false;
+ const bool isRunning = isConnected && m_device->is_running();
+
ImGui::Separator();
static std::string startLabel ("Start");
@@ -153,12 +156,11 @@ void deviceRenderToolbar()
void deviceRenderWidgets()
{
- static std::string siggenInput;
+ static std::string siggenInput (32768, '\0');
static int siggenOption = 0;
if (popupRequestSiggen) {
popupRequestSiggen = false;
- siggenInput.clear();
ImGui::OpenPopup("siggen");
} else if (popupRequestBuffer) {
popupRequestBuffer = false;
@@ -166,15 +168,19 @@ void deviceRenderWidgets()
} else if (popupRequestLog) {
popupRequestLog = false;
ImGuiFileDialog::Instance()->OpenModal(
- "ChooseFileLogGen", "Choose File", ".csv", ".");
+ "ChooseFileLog", "Choose File", ".csv", ".");
}
if (ImGui::BeginPopup("siggen")) {
- if (ImGui::RadioButton("List", &siggenOption, 0))
- siggenInput.clear();
+ if (ImGui::RadioButton("List", &siggenOption, 0)) {
+ siggenInput.resize(32768);
+ siggenInput[0] = '\0';
+ }
ImGui::SameLine();
- if (ImGui::RadioButton("Formula", &siggenOption, 1))
- siggenInput.clear();
+ if (ImGui::RadioButton("Formula", &siggenOption, 1)) {
+ siggenInput.resize(1024);
+ siggenInput[0] = '\0';
+ }
ImGui::SameLine();
if (ImGui::RadioButton("Audio File", &siggenOption, 2))
siggenInput.clear();
@@ -183,7 +189,7 @@ void deviceRenderWidgets()
if (ImGui::Button("Choose File")) {
// This dialog will override the siggen popup, closing it.
ImGuiFileDialog::Instance()->OpenModal(
- "ChooseFileLogGen", "Choose File", ".wav", ".");
+ "ChooseFileGen", "Choose File", ".wav", ".");
}
} else {
ImGui::Text(siggenOption == 0 ? "Enter a list of numbers:"
@@ -201,10 +207,10 @@ void deviceRenderWidgets()
if (ImGui::Button("Save")) {
switch (siggenOption) {
case 0:
- deviceGenLoadList(siggenInput);
+ deviceGenLoadList(siggenInput.substr(0, siggenInput.find('\0')));
break;
case 1:
- deviceGenLoadFormula(siggenInput);
+ deviceGenLoadFormula(siggenInput.substr(0, siggenInput.find('\0')));
break;
case 2:
break;
@@ -238,18 +244,27 @@ void deviceRenderWidgets()
ImGui::EndPopup();
}
- if (ImGuiFileDialog::Instance()->Display("ChooseFileLogGen",
+ if (ImGuiFileDialog::Instance()->Display("ChooseFileLog",
ImGuiWindowFlags_NoCollapse,
ImVec2(460, 540)))
{
if (ImGuiFileDialog::Instance()->IsOk()) {
- auto filePathName = ImGuiFileDialog::Instance()->GetFilePathName();
- auto ext = filePathName.substr(filePathName.size() - 4);
+ const auto filePathName = ImGuiFileDialog::Instance()->GetFilePathName();
+ deviceLoadLogFile(filePathName);
+ } else {
+ logResults = false;
+ }
+
+ ImGuiFileDialog::Instance()->Close();
+ }
- if (ext.compare(".wav") == 0)
- deviceLoadAudioFile(filePathName);
- else if (ext.compare(".csv") == 0)
- deviceLoadLogFile(filePathName);
+ if (ImGuiFileDialog::Instance()->Display("ChooseFileGen",
+ ImGuiWindowFlags_NoCollapse,
+ ImVec2(460, 540)))
+ {
+ if (ImGuiFileDialog::Instance()->IsOk()) {
+ const auto filePathName = ImGuiFileDialog::Instance()->GetFilePathName();
+ deviceLoadAudioFile(filePathName);
}
ImGuiFileDialog::Instance()->Close();
@@ -260,9 +275,9 @@ void deviceRenderDraw()
{
if (drawSamples) {
static std::vector<stmdsp::dacsample_t> buffer;
- static decltype(buffer.begin()) bufferCursor;
static std::vector<stmdsp::dacsample_t> bufferInput;
- static decltype(bufferInput.begin()) bufferInputCursor;
+ static auto bufferCirc = CircularBuffer(buffer);
+ static auto bufferInputCirc = CircularBuffer(bufferInput);
static bool drawSamplesInput = false;
static unsigned int yMinMax = 4095;
@@ -295,16 +310,50 @@ void deviceRenderDraw()
yMinMax = std::min(4095u, (yMinMax << 1) | 1);
}
- pullFromDrawQueue(buffer, bufferCursor, drawSamplesTimeframe);
- if (drawSamplesInput)
- pullFromInputDrawQueue(bufferInput, bufferInputCursor, drawSamplesTimeframe);
+ auto newSize = pullFromDrawQueue(bufferCirc, drawSamplesTimeframe);
+ if (newSize > 0) {
+ buffer.resize(newSize);
+ bufferCirc = CircularBuffer(buffer);
+ pullFromDrawQueue(bufferCirc, drawSamplesTimeframe);
+ }
+
+ if (drawSamplesInput) {
+ auto newSize = pullFromInputDrawQueue(bufferInputCirc, drawSamplesTimeframe);
+ if (newSize > 0) {
+ bufferInput.resize(newSize);
+ bufferInputCirc = CircularBuffer(bufferInput);
+ pullFromInputDrawQueue(bufferInputCirc, drawSamplesTimeframe);
+ }
+ }
auto drawList = ImGui::GetWindowDrawList();
ImVec2 p0 = ImGui::GetWindowPos();
auto size = ImGui::GetWindowSize();
p0.y += 65;
size.y -= 70;
- drawList->AddRectFilled(p0, {p0.x + size.x, p0.y + size.y}, IM_COL32(0, 0, 0, 255));
+ drawList->AddRectFilled(p0, {p0.x + size.x, p0.y + size.y}, IM_COL32_BLACK);
+
+ const auto lcMinor = ImGui::GetColorU32(IM_COL32(40, 40, 40, 255));
+ const auto lcMajor = ImGui::GetColorU32(IM_COL32(140, 140, 140, 255));
+
+ {
+ const float yinc = (3. / 3.3) * size.y / 12.f;
+ const float center = p0.y + size.y / 2;
+ drawList->AddLine({p0.x, center}, {p0.x + size.x, center}, ImGui::GetColorU32(IM_COL32_WHITE));
+ for (int i = 1; i < 7; ++i) {
+ drawList->AddLine({p0.x, center + i * yinc}, {p0.x + size.x, center + i * yinc}, (i % 2) ? lcMinor : lcMajor);
+ drawList->AddLine({p0.x, center - i * yinc}, {p0.x + size.x, center - i * yinc}, (i % 2) ? lcMinor : lcMajor);
+ }
+ }
+ {
+ const float xinc = size.x / 16.f;
+ const float center = p0.x + size.x / 2;
+ drawList->AddLine({center, p0.y}, {center, p0.y + size.y}, ImGui::GetColorU32(IM_COL32_WHITE));
+ for (int i = 1; i < 8; ++i) {
+ drawList->AddLine({center + i * xinc, p0.y}, {center + i * xinc, p0.y + size.y}, (i % 2) ? lcMinor : lcMajor);
+ drawList->AddLine({center - i * xinc, p0.y}, {center - i * xinc, p0.y + size.y}, (i % 2) ? lcMinor : lcMajor);
+ }
+ }
const float di = static_cast<float>(buffer.size()) / size.x;
const float dx = std::ceil(size.x / static_cast<float>(buffer.size()));
@@ -334,6 +383,18 @@ void deviceRenderDraw()
}
}
+ const auto mouse = ImGui::GetMousePos();
+ if (mouse.x > p0.x && mouse.x < p0.x + size.x &&
+ mouse.y > p0.y && mouse.y < p0.y + size.y)
+ {
+ const std::size_t si = (mouse.x - p0.x) / size.x * buffer.size();
+ const float s = buffer[si] / 4095.f * 6.6f - 3.3f;
+ char buf[12];
+ snprintf(buf, 16, " %1.3fV", s);
+ drawList->AddLine({mouse.x, p0.y}, {mouse.x, p0.y + size.y}, IM_COL32(255, 255, 0, 255));
+ drawList->AddText(ImGui::GetMousePos(), IM_COL32(210, 210, 0, 255), buf);
+ }
+
ImGui::End();
}
}
diff --git a/source/imgui/TextEditor.cpp b/source/imgui/TextEditor.cpp
index 02966f0..b45a21e 100644
--- a/source/imgui/TextEditor.cpp
+++ b/source/imgui/TextEditor.cpp
@@ -50,7 +50,7 @@ TextEditor::TextEditor()
, mStartTime(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count())
{
SetPalette(GetDarkPalette());
- SetLanguageDefinition(LanguageDefinition::HLSL());
+ SetLanguageDefinition(LanguageDefinition::CPlusPlus());
mLines.push_back(Line());
}
@@ -2804,357 +2804,3 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::CPlusPlus(
return langDef;
}
-const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::HLSL()
-{
- static bool inited = false;
- static LanguageDefinition langDef;
- if (!inited)
- {
- static const char* const keywords[] = {
- "AppendStructuredBuffer", "asm", "asm_fragment", "BlendState", "bool", "break", "Buffer", "ByteAddressBuffer", "case", "cbuffer", "centroid", "class", "column_major", "compile", "compile_fragment",
- "CompileShader", "const", "continue", "ComputeShader", "ConsumeStructuredBuffer", "default", "DepthStencilState", "DepthStencilView", "discard", "do", "double", "DomainShader", "dword", "else",
- "export", "extern", "false", "float", "for", "fxgroup", "GeometryShader", "groupshared", "half", "Hullshader", "if", "in", "inline", "inout", "InputPatch", "int", "interface", "line", "lineadj",
- "linear", "LineStream", "matrix", "min16float", "min10float", "min16int", "min12int", "min16uint", "namespace", "nointerpolation", "noperspective", "NULL", "out", "OutputPatch", "packoffset",
- "pass", "pixelfragment", "PixelShader", "point", "PointStream", "precise", "RasterizerState", "RenderTargetView", "return", "register", "row_major", "RWBuffer", "RWByteAddressBuffer", "RWStructuredBuffer",
- "RWTexture1D", "RWTexture1DArray", "RWTexture2D", "RWTexture2DArray", "RWTexture3D", "sample", "sampler", "SamplerState", "SamplerComparisonState", "shared", "snorm", "stateblock", "stateblock_state",
- "static", "string", "struct", "switch", "StructuredBuffer", "tbuffer", "technique", "technique10", "technique11", "texture", "Texture1D", "Texture1DArray", "Texture2D", "Texture2DArray", "Texture2DMS",
- "Texture2DMSArray", "Texture3D", "TextureCube", "TextureCubeArray", "true", "typedef", "triangle", "triangleadj", "TriangleStream", "uint", "uniform", "unorm", "unsigned", "vector", "vertexfragment",
- "VertexShader", "void", "volatile", "while",
- "bool1","bool2","bool3","bool4","double1","double2","double3","double4", "float1", "float2", "float3", "float4", "int1", "int2", "int3", "int4", "in", "out", "inout",
- "uint1", "uint2", "uint3", "uint4", "dword1", "dword2", "dword3", "dword4", "half1", "half2", "half3", "half4",
- "float1x1","float2x1","float3x1","float4x1","float1x2","float2x2","float3x2","float4x2",
- "float1x3","float2x3","float3x3","float4x3","float1x4","float2x4","float3x4","float4x4",
- "half1x1","half2x1","half3x1","half4x1","half1x2","half2x2","half3x2","half4x2",
- "half1x3","half2x3","half3x3","half4x3","half1x4","half2x4","half3x4","half4x4",
- };
- for (auto& k : keywords)
- langDef.mKeywords.insert(k);
-
- static const char* const identifiers[] = {
- "abort", "abs", "acos", "all", "AllMemoryBarrier", "AllMemoryBarrierWithGroupSync", "any", "asdouble", "asfloat", "asin", "asint", "asint", "asuint",
- "asuint", "atan", "atan2", "ceil", "CheckAccessFullyMapped", "clamp", "clip", "cos", "cosh", "countbits", "cross", "D3DCOLORtoUBYTE4", "ddx",
- "ddx_coarse", "ddx_fine", "ddy", "ddy_coarse", "ddy_fine", "degrees", "determinant", "DeviceMemoryBarrier", "DeviceMemoryBarrierWithGroupSync",
- "distance", "dot", "dst", "errorf", "EvaluateAttributeAtCentroid", "EvaluateAttributeAtSample", "EvaluateAttributeSnapped", "exp", "exp2",
- "f16tof32", "f32tof16", "faceforward", "firstbithigh", "firstbitlow", "floor", "fma", "fmod", "frac", "frexp", "fwidth", "GetRenderTargetSampleCount",
- "GetRenderTargetSamplePosition", "GroupMemoryBarrier", "GroupMemoryBarrierWithGroupSync", "InterlockedAdd", "InterlockedAnd", "InterlockedCompareExchange",
- "InterlockedCompareStore", "InterlockedExchange", "InterlockedMax", "InterlockedMin", "InterlockedOr", "InterlockedXor", "isfinite", "isinf", "isnan",
- "ldexp", "length", "lerp", "lit", "log", "log10", "log2", "mad", "max", "min", "modf", "msad4", "mul", "noise", "normalize", "pow", "printf",
- "Process2DQuadTessFactorsAvg", "Process2DQuadTessFactorsMax", "Process2DQuadTessFactorsMin", "ProcessIsolineTessFactors", "ProcessQuadTessFactorsAvg",
- "ProcessQuadTessFactorsMax", "ProcessQuadTessFactorsMin", "ProcessTriTessFactorsAvg", "ProcessTriTessFactorsMax", "ProcessTriTessFactorsMin",
- "radians", "rcp", "reflect", "refract", "reversebits", "round", "rsqrt", "saturate", "sign", "sin", "sincos", "sinh", "smoothstep", "sqrt", "step",
- "tan", "tanh", "tex1D", "tex1D", "tex1Dbias", "tex1Dgrad", "tex1Dlod", "tex1Dproj", "tex2D", "tex2D", "tex2Dbias", "tex2Dgrad", "tex2Dlod", "tex2Dproj",
- "tex3D", "tex3D", "tex3Dbias", "tex3Dgrad", "tex3Dlod", "tex3Dproj", "texCUBE", "texCUBE", "texCUBEbias", "texCUBEgrad", "texCUBElod", "texCUBEproj", "transpose", "trunc"
- };
- for (auto& k : identifiers)
- {
- Identifier id;
- id.mDeclaration = "Built-in function";
- langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
- }
-
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[ \\t]*#[ \\t]*[a-zA-Z_]+", PaletteIndex::Preprocessor));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\'\\\\?[^\\']\\'", PaletteIndex::CharLiteral));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation));
-
- langDef.mCommentStart = "/*";
- langDef.mCommentEnd = "*/";
- langDef.mSingleLineComment = "//";
-
- langDef.mCaseSensitive = true;
- langDef.mAutoIndentation = true;
-
- langDef.mName = "HLSL";
-
- inited = true;
- }
- return langDef;
-}
-
-const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::GLSL()
-{
- static bool inited = false;
- static LanguageDefinition langDef;
- if (!inited)
- {
- static const char* const keywords[] = {
- "auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long", "register", "restrict", "return", "short",
- "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while", "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", "_Imaginary",
- "_Noreturn", "_Static_assert", "_Thread_local"
- };
- for (auto& k : keywords)
- langDef.mKeywords.insert(k);
-
- static const char* const identifiers[] = {
- "abort", "abs", "acos", "asin", "atan", "atexit", "atof", "atoi", "atol", "ceil", "clock", "cosh", "ctime", "div", "exit", "fabs", "floor", "fmod", "getchar", "getenv", "isalnum", "isalpha", "isdigit", "isgraph",
- "ispunct", "isspace", "isupper", "kbhit", "log10", "log2", "log", "memcmp", "modf", "pow", "putchar", "putenv", "puts", "rand", "remove", "rename", "sinh", "sqrt", "srand", "strcat", "strcmp", "strerror", "time", "tolower", "toupper"
- };
- for (auto& k : identifiers)
- {
- Identifier id;
- id.mDeclaration = "Built-in function";
- langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
- }
-
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[ \\t]*#[ \\t]*[a-zA-Z_]+", PaletteIndex::Preprocessor));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\'\\\\?[^\\']\\'", PaletteIndex::CharLiteral));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation));
-
- langDef.mCommentStart = "/*";
- langDef.mCommentEnd = "*/";
- langDef.mSingleLineComment = "//";
-
- langDef.mCaseSensitive = true;
- langDef.mAutoIndentation = true;
-
- langDef.mName = "GLSL";
-
- inited = true;
- }
- return langDef;
-}
-
-const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::C()
-{
- static bool inited = false;
- static LanguageDefinition langDef;
- if (!inited)
- {
- static const char* const keywords[] = {
- "auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long", "register", "restrict", "return", "short",
- "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while", "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", "_Imaginary",
- "_Noreturn", "_Static_assert", "_Thread_local"
- };
- for (auto& k : keywords)
- langDef.mKeywords.insert(k);
-
- static const char* const identifiers[] = {
- "abort", "abs", "acos", "asin", "atan", "atexit", "atof", "atoi", "atol", "ceil", "clock", "cosh", "ctime", "div", "exit", "fabs", "floor", "fmod", "getchar", "getenv", "isalnum", "isalpha", "isdigit", "isgraph",
- "ispunct", "isspace", "isupper", "kbhit", "log10", "log2", "log", "memcmp", "modf", "pow", "putchar", "putenv", "puts", "rand", "remove", "rename", "sinh", "sqrt", "srand", "strcat", "strcmp", "strerror", "time", "tolower", "toupper"
- };
- for (auto& k : identifiers)
- {
- Identifier id;
- id.mDeclaration = "Built-in function";
- langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
- }
-
- langDef.mTokenize = [](const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end, PaletteIndex & paletteIndex) -> bool
- {
- paletteIndex = PaletteIndex::Max;
-
- while (in_begin < in_end && isascii(*in_begin) && isblank(*in_begin))
- in_begin++;
-
- if (in_begin == in_end)
- {
- out_begin = in_end;
- out_end = in_end;
- paletteIndex = PaletteIndex::Default;
- }
- else if (TokenizeCStyleString(in_begin, in_end, out_begin, out_end))
- paletteIndex = PaletteIndex::String;
- else if (TokenizeCStyleCharacterLiteral(in_begin, in_end, out_begin, out_end))
- paletteIndex = PaletteIndex::CharLiteral;
- else if (TokenizeCStyleIdentifier(in_begin, in_end, out_begin, out_end))
- paletteIndex = PaletteIndex::Identifier;
- else if (TokenizeCStyleNumber(in_begin, in_end, out_begin, out_end))
- paletteIndex = PaletteIndex::Number;
- else if (TokenizeCStylePunctuation(in_begin, in_end, out_begin, out_end))
- paletteIndex = PaletteIndex::Punctuation;
-
- return paletteIndex != PaletteIndex::Max;
- };
-
- langDef.mCommentStart = "/*";
- langDef.mCommentEnd = "*/";
- langDef.mSingleLineComment = "//";
-
- langDef.mCaseSensitive = true;
- langDef.mAutoIndentation = true;
-
- langDef.mName = "C";
-
- inited = true;
- }
- return langDef;
-}
-
-const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::SQL()
-{
- static bool inited = false;
- static LanguageDefinition langDef;
- if (!inited)
- {
- static const char* const keywords[] = {
- "ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER", "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY", "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE", "PROCEDURE",
- "AUTHORIZATION", "FILLFACTOR", "PUBLIC", "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ", "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE", "RECONFIGURE",
- "BROWSE", "FROM", "REFERENCES", "BULK", "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE", "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN", "CHECK", "GROUP", "REVOKE",
- "CHECKPOINT", "HAVING", "RIGHT", "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY", "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL", "COLLATE", "IDENTITYCOL", "RULE",
- "COLUMN", "IF", "SAVE", "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT", "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT", "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER",
- "CONTINUE", "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE", "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER", "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT", "TEXTSIZE",
- "CURRENT_TIME", "LIKE", "THEN", "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD", "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK", "TRANSACTION",
- "DBCC", "NONCLUSTERED", "TRIGGER", "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL", "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF", "UNIQUE", "DENY", "OFF", "UPDATE",
- "DESC", "OFFSETS", "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN", "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE", "OPENQUERY", "VARYING","DROP", "OPENROWSET", "VIEW",
- "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN", "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL", "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT"
- };
-
- for (auto& k : keywords)
- langDef.mKeywords.insert(k);
-
- static const char* const identifiers[] = {
- "ABS", "ACOS", "ADD_MONTHS", "ASCII", "ASCIISTR", "ASIN", "ATAN", "ATAN2", "AVG", "BFILENAME", "BIN_TO_NUM", "BITAND", "CARDINALITY", "CASE", "CAST", "CEIL",
- "CHARTOROWID", "CHR", "COALESCE", "COMPOSE", "CONCAT", "CONVERT", "CORR", "COS", "COSH", "COUNT", "COVAR_POP", "COVAR_SAMP", "CUME_DIST", "CURRENT_DATE",
- "CURRENT_TIMESTAMP", "DBTIMEZONE", "DECODE", "DECOMPOSE", "DENSE_RANK", "DUMP", "EMPTY_BLOB", "EMPTY_CLOB", "EXP", "EXTRACT", "FIRST_VALUE", "FLOOR", "FROM_TZ", "GREATEST",
- "GROUP_ID", "HEXTORAW", "INITCAP", "INSTR", "INSTR2", "INSTR4", "INSTRB", "INSTRC", "LAG", "LAST_DAY", "LAST_VALUE", "LEAD", "LEAST", "LENGTH", "LENGTH2", "LENGTH4",
- "LENGTHB", "LENGTHC", "LISTAGG", "LN", "LNNVL", "LOCALTIMESTAMP", "LOG", "LOWER", "LPAD", "LTRIM", "MAX", "MEDIAN", "MIN", "MOD", "MONTHS_BETWEEN", "NANVL", "NCHR",
- "NEW_TIME", "NEXT_DAY", "NTH_VALUE", "NULLIF", "NUMTODSINTERVAL", "NUMTOYMINTERVAL", "NVL", "NVL2", "POWER", "RANK", "RAWTOHEX", "REGEXP_COUNT", "REGEXP_INSTR",
- "REGEXP_REPLACE", "REGEXP_SUBSTR", "REMAINDER", "REPLACE", "ROUND", "ROWNUM", "RPAD", "RTRIM", "SESSIONTIMEZONE", "SIGN", "SIN", "SINH",
- "SOUNDEX", "SQRT", "STDDEV", "SUBSTR", "SUM", "SYS_CONTEXT", "SYSDATE", "SYSTIMESTAMP", "TAN", "TANH", "TO_CHAR", "TO_CLOB", "TO_DATE", "TO_DSINTERVAL", "TO_LOB",
- "TO_MULTI_BYTE", "TO_NCLOB", "TO_NUMBER", "TO_SINGLE_BYTE", "TO_TIMESTAMP", "TO_TIMESTAMP_TZ", "TO_YMINTERVAL", "TRANSLATE", "TRIM", "TRUNC", "TZ_OFFSET", "UID", "UPPER",
- "USER", "USERENV", "VAR_POP", "VAR_SAMP", "VARIANCE", "VSIZE "
- };
- for (auto& k : identifiers)
- {
- Identifier id;
- id.mDeclaration = "Built-in function";
- langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
- }
-
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\\'[^\\\']*\\\'", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation));
-
- langDef.mCommentStart = "/*";
- langDef.mCommentEnd = "*/";
- langDef.mSingleLineComment = "//";
-
- langDef.mCaseSensitive = false;
- langDef.mAutoIndentation = false;
-
- langDef.mName = "SQL";
-
- inited = true;
- }
- return langDef;
-}
-
-const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::AngelScript()
-{
- static bool inited = false;
- static LanguageDefinition langDef;
- if (!inited)
- {
- static const char* const keywords[] = {
- "and", "abstract", "auto", "bool", "break", "case", "cast", "class", "const", "continue", "default", "do", "double", "else", "enum", "false", "final", "float", "for",
- "from", "funcdef", "function", "get", "if", "import", "in", "inout", "int", "interface", "int8", "int16", "int32", "int64", "is", "mixin", "namespace", "not",
- "null", "or", "out", "override", "private", "protected", "return", "set", "shared", "super", "switch", "this ", "true", "typedef", "uint", "uint8", "uint16", "uint32",
- "uint64", "void", "while", "xor"
- };
-
- for (auto& k : keywords)
- langDef.mKeywords.insert(k);
-
- static const char* const identifiers[] = {
- "cos", "sin", "tab", "acos", "asin", "atan", "atan2", "cosh", "sinh", "tanh", "log", "log10", "pow", "sqrt", "abs", "ceil", "floor", "fraction", "closeTo", "fpFromIEEE", "fpToIEEE",
- "complex", "opEquals", "opAddAssign", "opSubAssign", "opMulAssign", "opDivAssign", "opAdd", "opSub", "opMul", "opDiv"
- };
- for (auto& k : identifiers)
- {
- Identifier id;
- id.mDeclaration = "Built-in function";
- langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
- }
-
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\'\\\\?[^\\']\\'", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation));
-
- langDef.mCommentStart = "/*";
- langDef.mCommentEnd = "*/";
- langDef.mSingleLineComment = "//";
-
- langDef.mCaseSensitive = true;
- langDef.mAutoIndentation = true;
-
- langDef.mName = "AngelScript";
-
- inited = true;
- }
- return langDef;
-}
-
-const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::Lua()
-{
- static bool inited = false;
- static LanguageDefinition langDef;
- if (!inited)
- {
- static const char* const keywords[] = {
- "and", "break", "do", "", "else", "elseif", "end", "false", "for", "function", "if", "in", "", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while"
- };
-
- for (auto& k : keywords)
- langDef.mKeywords.insert(k);
-
- static const char* const identifiers[] = {
- "assert", "collectgarbage", "dofile", "error", "getmetatable", "ipairs", "loadfile", "load", "loadstring", "next", "pairs", "pcall", "print", "rawequal", "rawlen", "rawget", "rawset",
- "select", "setmetatable", "tonumber", "tostring", "type", "xpcall", "_G", "_VERSION","arshift", "band", "bnot", "bor", "bxor", "btest", "extract", "lrotate", "lshift", "replace",
- "rrotate", "rshift", "create", "resume", "running", "status", "wrap", "yield", "isyieldable", "debug","getuservalue", "gethook", "getinfo", "getlocal", "getregistry", "getmetatable",
- "getupvalue", "upvaluejoin", "upvalueid", "setuservalue", "sethook", "setlocal", "setmetatable", "setupvalue", "traceback", "close", "flush", "input", "lines", "open", "output", "popen",
- "read", "tmpfile", "type", "write", "close", "flush", "lines", "read", "seek", "setvbuf", "write", "__gc", "__tostring", "abs", "acos", "asin", "atan", "ceil", "cos", "deg", "exp", "tointeger",
- "floor", "fmod", "ult", "log", "max", "min", "modf", "rad", "random", "randomseed", "sin", "sqrt", "string", "tan", "type", "atan2", "cosh", "sinh", "tanh",
- "pow", "frexp", "ldexp", "log10", "pi", "huge", "maxinteger", "mininteger", "loadlib", "searchpath", "seeall", "preload", "cpath", "path", "searchers", "loaded", "module", "require", "clock",
- "date", "difftime", "execute", "exit", "getenv", "remove", "rename", "setlocale", "time", "tmpname", "byte", "char", "dump", "find", "format", "gmatch", "gsub", "len", "lower", "match", "rep",
- "reverse", "sub", "upper", "pack", "packsize", "unpack", "concat", "maxn", "insert", "pack", "unpack", "remove", "move", "sort", "offset", "codepoint", "char", "len", "codes", "charpattern",
- "coroutine", "table", "io", "os", "string", "utf8", "bit32", "math", "debug", "package"
- };
- for (auto& k : identifiers)
- {
- Identifier id;
- id.mDeclaration = "Built-in function";
- langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
- }
-
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\\'[^\\\']*\\\'", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation));
-
- langDef.mCommentStart = "--[[";
- langDef.mCommentEnd = "]]";
- langDef.mSingleLineComment = "--";
-
- langDef.mCaseSensitive = true;
- langDef.mAutoIndentation = false;
-
- langDef.mName = "Lua";
-
- inited = true;
- }
- return langDef;
-}
diff --git a/source/imgui/TextEditor.h b/source/imgui/TextEditor.h
index bd52e13..e0e86cd 100644
--- a/source/imgui/TextEditor.h
+++ b/source/imgui/TextEditor.h
@@ -174,12 +174,6 @@ public:
}
static const LanguageDefinition& CPlusPlus();
- static const LanguageDefinition& HLSL();
- static const LanguageDefinition& GLSL();
- static const LanguageDefinition& C();
- static const LanguageDefinition& SQL();
- static const LanguageDefinition& AngelScript();
- static const LanguageDefinition& Lua();
};
TextEditor();
diff --git a/source/imgui/imgui.h b/source/imgui/imgui.h
index 182c46a..8d2b376 100644
--- a/source/imgui/imgui.h
+++ b/source/imgui/imgui.h
@@ -243,9 +243,9 @@ typedef unsigned long long ImU64; // 64-bit unsigned integer (post C++11)
IM_MSVC_RUNTIME_CHECKS_OFF
struct ImVec2
{
- float x, y;
- ImVec2() { x = y = 0.0f; }
- ImVec2(float _x, float _y) { x = _x; y = _y; }
+ float x = 0.f, y = 0.f;
+ constexpr ImVec2() = default;
+ constexpr ImVec2(float _x, float _y) : x(_x), y(_y) {}
float operator[] (size_t idx) const { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine.
float& operator[] (size_t idx) { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine.
#ifdef IM_VEC2_CLASS_EXTRA
diff --git a/source/logview.cpp b/source/logview.cpp
new file mode 100644
index 0000000..267cecb
--- /dev/null
+++ b/source/logview.cpp
@@ -0,0 +1,82 @@
+#include "logview.h"
+
+LogView::LogView()
+{
+ Clear();
+}
+
+void LogView::Clear()
+{
+ Buf.clear();
+ LineOffsets.clear();
+ LineOffsets.push_back(0);
+ updated = false;
+}
+
+void LogView::AddLog(const std::string& str)
+{
+ AddLog(str.c_str());
+}
+
+void LogView::AddLog(const char* fmt, ...)
+{
+ int old_size = Buf.size();
+ va_list args;
+ va_start(args, fmt);
+ Buf.appendfv(fmt, args);
+ Buf.appendfv("\n", args);
+ va_end(args);
+ for (int new_size = Buf.size(); old_size < new_size; old_size++)
+ if (Buf[old_size] == '\n')
+ LineOffsets.push_back(old_size + 1);
+ updated = true;
+}
+
+void LogView::Draw(const char* title, bool* p_open, ImGuiWindowFlags flags)
+{
+ if (!ImGui::Begin(title, p_open, flags))
+ {
+ ImGui::End();
+ return;
+ }
+
+ ImGui::Text("Log ");
+ ImGui::SameLine();
+ if (ImGui::Button("Clear"))
+ Clear();
+ ImGui::SameLine();
+ if (ImGui::Button("Copy"))
+ ImGui::LogToClipboard();
+ ImGui::Separator();
+ ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
+
+
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
+ const char* buf = Buf.begin();
+ const char* buf_end = Buf.end();
+
+ ImGuiListClipper clipper;
+ clipper.Begin(LineOffsets.Size);
+
+ while (clipper.Step())
+ {
+ for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
+ {
+ const char* line_start = buf + LineOffsets[line_no];
+ const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
+ ImGui::TextUnformatted(line_start, line_end);
+ }
+ }
+ clipper.End();
+
+ ImGui::PopStyleVar();
+
+ if (updated) {
+ ImGui::SetScrollHereY();
+ updated = false;
+ }
+
+ ImGui::EndChild();
+ ImGui::End();
+}
+
diff --git a/source/logview.h b/source/logview.h
index 4ab2c94..3c6acf1 100644
--- a/source/logview.h
+++ b/source/logview.h
@@ -3,87 +3,23 @@
#include <string>
+#include "imgui.h"
+
// Adapted from ExampleAppLog from imgui_demo.cpp
class LogView
{
public:
- LogView()
- {
- Clear();
- }
-
- void Clear()
- {
- Buf.clear();
- LineOffsets.clear();
- LineOffsets.push_back(0);
- }
-
- void AddLog(const std::string& str)
- {
- AddLog(str.c_str());
- }
-
- void AddLog(const char* fmt, ...) IM_FMTARGS(2)
- {
- int old_size = Buf.size();
- va_list args;
- va_start(args, fmt);
- Buf.appendfv(fmt, args);
- Buf.appendfv("\n", args);
- va_end(args);
- for (int new_size = Buf.size(); old_size < new_size; old_size++)
- if (Buf[old_size] == '\n')
- LineOffsets.push_back(old_size + 1);
- }
-
- void Draw(const char* title, bool* p_open = NULL, ImGuiWindowFlags flags = 0)
- {
- if (!ImGui::Begin(title, p_open, flags))
- {
- ImGui::End();
- return;
- }
-
- ImGui::Text("Log ");
- ImGui::SameLine();
- if (ImGui::Button("Clear"))
- Clear();
- ImGui::SameLine();
- if (ImGui::Button("Copy"))
- ImGui::LogToClipboard();
- ImGui::Separator();
- ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
-
-
- ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
- const char* buf = Buf.begin();
- const char* buf_end = Buf.end();
- ImGuiListClipper clipper;
- clipper.Begin(LineOffsets.Size);
- while (clipper.Step())
- {
- for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
- {
- const char* line_start = buf + LineOffsets[line_no];
- const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
- ImGui::TextUnformatted(line_start, line_end);
- }
- }
- clipper.End();
-
- ImGui::PopStyleVar();
-
- if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
- ImGui::SetScrollHereY(1.0f);
+ LogView();
- ImGui::EndChild();
- ImGui::End();
- }
+ void Clear();
+ void AddLog(const std::string& str);
+ void AddLog(const char* fmt, ...) IM_FMTARGS(2);
+ void Draw(const char* title, bool* p_open = NULL, ImGuiWindowFlags flags = 0);
private:
ImGuiTextBuffer Buf;
ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls.
+ bool updated;
};
#endif // LOGVIEW_H
diff --git a/source/main.cpp b/source/main.cpp
index 20c8ea1..5eac338 100644
--- a/source/main.cpp
+++ b/source/main.cpp
@@ -25,27 +25,24 @@
extern ImFont *fontSans;
extern ImFont *fontMono;
-extern bool guiInitialize();
-extern void guiHandleEvents(bool& done);
-extern void guiShutdown();
-extern void guiRender(void (*func)());
+bool guiInitialize();
+bool guiHandleEvents();
+void guiShutdown();
+void guiRender(void (*func)());
-extern void fileRenderMenu();
-extern void fileRenderDialog();
-extern void fileInit();
+void fileRenderMenu();
+void fileRenderDialog();
+void fileInit();
-extern void codeEditorInit();
-extern void codeRenderMenu();
-extern void codeRenderToolbar();
-extern void codeRenderWidgets();
+void codeEditorInit();
+void codeRenderMenu();
+void codeRenderToolbar();
+void codeRenderWidgets();
-extern void deviceRenderDraw();
-extern void deviceRenderMenu();
-extern void deviceRenderToolbar();
-extern void deviceRenderWidgets();
-
-// Globals that live here
-bool done = false;
+void deviceRenderDraw();
+void deviceRenderMenu();
+void deviceRenderToolbar();
+void deviceRenderWidgets();
static LogView logView;
@@ -54,6 +51,8 @@ void log(const std::string& str)
logView.AddLog(str);
}
+static void renderWindow();
+
int main(int, char **)
{
if (!guiInitialize())
@@ -62,62 +61,72 @@ int main(int, char **)
codeEditorInit();
fileInit();
- while (!done) {
- auto endTime = std::chrono::steady_clock::now() +
- std::chrono::milliseconds(static_cast<unsigned int>(std::floor(1000. / 60.)));
-
- guiHandleEvents(done);
-
- // Start the new window frame and render the menu bar.
- ImGui_ImplOpenGL2_NewFrame();
- ImGui_ImplSDL2_NewFrame();
- ImGui::NewFrame();
+ while (1) {
+ constexpr std::chrono::duration<double> fpsDelay (1. / 60.);
+ const auto endTime = std::chrono::steady_clock::now() + fpsDelay;
- if (ImGui::BeginMainMenuBar()) {
- fileRenderMenu();
- deviceRenderMenu();
- codeRenderMenu();
- ImGui::EndMainMenuBar();
+ const bool isDone = guiHandleEvents();
+ if (!isDone) {
+ renderWindow();
+ std::this_thread::sleep_until(endTime);
+ } else {
+ break;
}
+ }
- // Begin the main view which the controls will be drawn onto.
- ImGui::SetNextWindowPos({0, 22});
- ImGui::SetNextWindowSize({WINDOW_WIDTH, WINDOW_HEIGHT - 22 - 200});
- ImGui::Begin("main", nullptr,
- ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration |
- ImGuiWindowFlags_NoBringToFrontOnFocus);
-
- // Render main controls (order is important).
- {
- ImGui::PushFont(fontSans);
- codeRenderToolbar();
- deviceRenderToolbar();
- fileRenderDialog();
- deviceRenderWidgets();
- ImGui::PopFont();
-
- ImGui::PushFont(fontMono);
- codeRenderWidgets();
- ImGui::SetNextWindowPos({0, WINDOW_HEIGHT - 200});
- ImGui::SetNextWindowSize({WINDOW_WIDTH, 200});
- logView.Draw("log", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus);
- ImGui::PopFont();
- }
+ guiShutdown();
+ return 0;
+}
- ImGui::End();
+void renderWindow()
+{
+ // Start the new window frame and render the menu bar.
+ ImGui_ImplOpenGL2_NewFrame();
+ ImGui_ImplSDL2_NewFrame();
+ ImGui::NewFrame();
+
+ if (ImGui::BeginMainMenuBar()) {
+ fileRenderMenu();
+ deviceRenderMenu();
+ codeRenderMenu();
+ ImGui::EndMainMenuBar();
+ }
- deviceRenderDraw();
+ // Begin the main view which the controls will be drawn onto.
+ constexpr float LOGVIEW_HEIGHT = 200;
+ constexpr ImVec2 WINDOW_POS (0, 22);
+ constexpr ImVec2 WINDOW_SIZE (WINDOW_WIDTH, WINDOW_HEIGHT - 22 - LOGVIEW_HEIGHT);
+ ImGui::SetNextWindowPos(WINDOW_POS);
+ ImGui::SetNextWindowSize(WINDOW_SIZE);
+ ImGui::Begin("main", nullptr,
+ ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration |
+ ImGuiWindowFlags_NoBringToFrontOnFocus);
+
+ // Render main controls (order is important).
+ {
+ ImGui::PushFont(fontSans);
+ codeRenderToolbar();
+ deviceRenderToolbar();
+ fileRenderDialog();
+ deviceRenderWidgets();
+ ImGui::PopFont();
+
+ ImGui::PushFont(fontMono);
+ codeRenderWidgets();
+ ImGui::SetNextWindowPos({0, WINDOW_HEIGHT - LOGVIEW_HEIGHT});
+ ImGui::SetNextWindowSize({WINDOW_WIDTH, LOGVIEW_HEIGHT});
+ logView.Draw("log", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus);
+ ImGui::PopFont();
+ }
- // Draw everything to the screen.
- ImGui::Render();
- guiRender([] {
- ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
- });
+ ImGui::End();
- std::this_thread::sleep_until(endTime);
- }
+ deviceRenderDraw();
- guiShutdown();
- return 0;
+ // Draw everything to the screen.
+ ImGui::Render();
+ guiRender([] {
+ ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
+ });
}