more refactor; draw samples grid and cursor; gen load fixes

pull/1/head
Clyne 3 years ago
parent c76ba69fc9
commit fde531e7c4

@ -24,7 +24,7 @@ $(OUTPUT): $(OFILES)
clean: clean:
@echo " CLEAN" @echo " CLEAN"
@rm $(OFILES) $(OUTPUT) @rm -f $(OFILES) $(OUTPUT)
%.o: %.cpp %.o: %.cpp
@echo " CXX " $< @echo " CXX " $<

@ -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

@ -11,10 +11,12 @@
#include "stmdsp.hpp" #include "stmdsp.hpp"
#include "circular.hpp"
#include "imgui.h" #include "imgui.h"
#include "wav.hpp" #include "wav.hpp"
#include <array> #include <array>
#include <cctype>
#include <charconv> #include <charconv>
#include <cmath> #include <cmath>
#include <deque> #include <deque>
@ -30,7 +32,7 @@
extern std::string tempFileName; extern std::string tempFileName;
extern void log(const std::string& str); 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; std::shared_ptr<stmdsp::device> m_device;
@ -62,14 +64,16 @@ static std::vector<stmdsp::dacsample_t> tryReceiveChunk(
std::shared_ptr<stmdsp::device> device, std::shared_ptr<stmdsp::device> device,
auto readFunc) auto readFunc)
{ {
int tries = -1; for (int tries = 0; tries < 100; ++tries) {
do { if (!device->is_running())
break;
const auto chunk = readFunc(device.get()); const auto chunk = readFunc(device.get());
if (!chunk.empty()) if (!chunk.empty())
return chunk; return chunk;
else else
std::this_thread::sleep_for(std::chrono::microseconds(20)); std::this_thread::sleep_for(std::chrono::microseconds(20));
} while (++tries < 100 && device->is_running()); }
return {}; return {};
} }
@ -94,15 +98,13 @@ static void drawSamplesTask(std::shared_ptr<stmdsp::device> device)
const auto bufferTime = getBufferPeriod(device); const auto bufferTime = getBufferPeriod(device);
std::unique_lock<std::timed_mutex> lockDraw (mutexDrawSamples, std::defer_lock); const auto addToQueue = [](auto& queue, const auto& chunk) {
std::unique_lock<std::timed_mutex> lockDevice (mutexDeviceLoad, std::defer_lock); std::scoped_lock lock (mutexDrawSamples);
auto addToQueue = [&lockDraw](auto& queue, const auto& chunk) {
lockDraw.lock();
std::copy(chunk.cbegin(), chunk.cend(), std::back_inserter(queue)); 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()) { while (device && device->is_running()) {
const auto next = std::chrono::high_resolution_clock::now() + bufferTime; 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(); lockDevice.unlock();
addToQueue(drawSamplesQueue, chunk); addToQueue(drawSamplesQueue, chunk);
if (logSamplesFile.good()) { if (logSamplesFile.is_open()) {
for (const auto& s : chunk) for (const auto& s : chunk)
logSamplesFile << s << '\n'; 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::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);
lockDevice.lock();
device->siggen_upload(wavBuf.data(), wavBuf.size()); device->siggen_upload(wavBuf.data(), wavBuf.size());
wavBuf.resize(wavBuf.size() / 2);
device->siggen_start(); device->siggen_start();
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1));
lockDevice.unlock(); }
wavBuf.resize(wavBuf.size() / 2);
std::vector<int16_t> wavIntBuf (wavBuf.size()); std::vector<int16_t> wavIntBuf (wavBuf.size());
while (device->is_siggening()) { while (device->is_siggening()) {
const auto next = std::chrono::high_resolution_clock::now() + delay; const auto next = std::chrono::high_resolution_clock::now() + delay;
wavOutput.next(wavIntBuf.data(), wavIntBuf.size()); wavOutput.next(wavIntBuf.data(), wavIntBuf.size());
auto src = wavIntBuf.cbegin(); std::transform(wavIntBuf.cbegin(), wavIntBuf.cend(),
std::generate(wavBuf.begin(), wavBuf.end(), wavBuf.begin(),
[&src] { return static_cast<stmdsp::dacsample_t>(*src++ / 16 + 2048); }); [](auto i) { return static_cast<stmdsp::dacsample_t>(i / 16 + 2048); });
lockDevice.lock(); {
std::scoped_lock lock (mutexDeviceLoad);
while (!device->siggen_upload(wavBuf.data(), wavBuf.size())) while (!device->siggen_upload(wavBuf.data(), wavBuf.size()))
std::this_thread::sleep_for(uploadDelay); std::this_thread::sleep_for(uploadDelay);
lockDevice.unlock(); }
std::this_thread::sleep_until(next); std::this_thread::sleep_until(next);
} }
@ -179,10 +181,9 @@ static void statusTask(std::shared_ptr<stmdsp::device> device)
return; return;
while (device->connected()) { while (device->connected()) {
std::unique_lock<std::timed_mutex> lockDevice (mutexDeviceLoad, std::defer_lock); mutexDeviceLoad.lock();
lockDevice.lock();
const auto [status, error] = device->get_status(); const auto [status, error] = device->get_status();
lockDevice.unlock(); mutexDeviceLoad.unlock();
if (error != stmdsp::Error::None) { if (error != stmdsp::Error::None) {
switch (error) { switch (error) {
@ -214,7 +215,7 @@ void deviceLoadAudioFile(const std::string& file)
void deviceLoadLogFile(const std::string& file) void deviceLoadLogFile(const std::string& file)
{ {
logSamplesFile = std::ofstream(file); logSamplesFile = std::ofstream(file);
if (logSamplesFile.good()) if (logSamplesFile.is_open())
log("Log file ready."); log("Log file ready.");
else else
log("Error: Could not open log file."); log("Error: Could not open log file.");
@ -261,7 +262,7 @@ bool deviceConnect()
if (!m_device) { if (!m_device) {
stmdsp::scanner scanner; stmdsp::scanner scanner;
if (auto devices = scanner.scan(); !devices.empty()) { if (const auto devices = scanner.scan(); !devices.empty()) {
try { try {
m_device.reset(new stmdsp::device(devices.front())); m_device.reset(new stmdsp::device(devices.front()));
} catch (...) { } catch (...) {
@ -307,7 +308,7 @@ void deviceStart(bool measureCodeTime, bool logResults, bool drawSamples)
std::this_thread::sleep_for(std::chrono::microseconds(150)); std::this_thread::sleep_for(std::chrono::microseconds(150));
m_device->continuous_stop(); m_device->continuous_stop();
} }
if (logSamplesFile.good()) { if (logSamplesFile.is_open()) {
logSamplesFile.close(); logSamplesFile.close();
log("Log file saved and closed."); log("Log file saved and closed.");
} }
@ -329,12 +330,9 @@ void deviceAlgorithmUpload()
{ {
if (!m_device) { if (!m_device) {
log("No device connected."); log("No device connected.");
return;
} else if (m_device->is_running()) { } else if (m_device->is_running()) {
return; log("Cannot upload algorithm while running.");
} } else if (std::ifstream algo (tempFileName + ".o"); algo.is_open()) {
if (std::ifstream algo (tempFileName + ".o"); algo.good()) {
std::ostringstream sstr; std::ostringstream sstr;
sstr << algo.rdbuf(); sstr << algo.rdbuf();
auto str = sstr.str(); auto str = sstr.str();
@ -350,7 +348,9 @@ void deviceAlgorithmUnload()
{ {
if (!m_device) { if (!m_device) {
log("No device connected."); 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(); m_device->unload_filter();
log("Algorithm unloaded."); log("Algorithm unloaded.");
} }
@ -361,85 +361,82 @@ void deviceGenLoadList(const std::string_view list)
std::vector<stmdsp::dacsample_t> samples; std::vector<stmdsp::dacsample_t> samples;
auto it = list.cbegin(); auto it = list.cbegin();
while (it != list.cend() && samples.size() < stmdsp::SAMPLES_MAX * 2) { while (it != list.cend()) {
const auto end = list.find_first_not_of("0123456789", const auto itend = std::find_if(it, list.cend(),
std::distance(list.cbegin(), it)); [](char c) { return !isdigit(c); });
const auto itend = end != std::string_view::npos ? list.cbegin() + end
: list.cend();
unsigned long n; unsigned long n;
const auto [ptr, ec] = std::from_chars(it, itend, n); const auto ec = std::from_chars(it, itend, n).ec;
if (ec != std::errc()) if (ec != std::errc()) {
log("Error: Bad data in sample list.");
break; break;
} else if (n > 4095) {
log("Error: Sample data value larger than max of 4095.");
break;
} else {
samples.push_back(n & 4095); samples.push_back(n & 4095);
if (samples.size() >= stmdsp::SAMPLES_MAX * 2) {
log("Error: Too many samples for signal generator.");
break;
}
}
it = itend; it = itend;
} }
if (samples.size() <= stmdsp::SAMPLES_MAX * 2) { if (it == list.cend()) {
// DAC buffer must be of even size // DAC buffer must be of even size
if (samples.size() % 2 != 0) if (samples.size() % 2 != 0)
samples.push_back(samples.back()); 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."); 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); auto samples = deviceGenLoadFormulaEval(formula);
if (!samples.empty()) { 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."); log("Generator ready.");
} else { } else {
log("Error: Bad formula."); log("Error: Bad formula.");
} }
} }
void pullFromQueue( std::size_t pullFromQueue(
std::deque<stmdsp::dacsample_t>& queue, std::deque<stmdsp::dacsample_t>& queue,
std::vector<stmdsp::dacsample_t>& buffer, CircularBuffer<std::vector, stmdsp::dacsample_t>& circ,
decltype(buffer.begin())& bufferCursor,
double timeframe) double timeframe)
{ {
if (buffer.size() != drawSamplesBufferSize) { if (circ.size() != drawSamplesBufferSize)
buffer.resize(drawSamplesBufferSize); return drawSamplesBufferSize;
bufferCursor = buffer.begin();
}
std::scoped_lock lock (mutexDrawSamples); std::scoped_lock lock (mutexDrawSamples);
auto count = drawSamplesBufferSize / (60. * timeframe) * 1.025; const auto desiredCount = drawSamplesBufferSize / (60. * timeframe) * 1.025;
count = std::min(drawSamplesInputQueue.size(), auto count = std::min(queue.size(), static_cast<std::size_t>(desiredCount));
static_cast<std::size_t>(count)); while (count--) {
for (auto i = count; i; --i) { circ.put(queue.front());
*bufferCursor = queue.front();
queue.pop_front(); queue.pop_front();
if (++bufferCursor == buffer.end())
bufferCursor = buffer.begin();
} }
return 0;
} }
void pullFromDrawQueue( std::size_t pullFromDrawQueue(
std::vector<stmdsp::dacsample_t>& buffer, CircularBuffer<std::vector, stmdsp::dacsample_t>& circ,
decltype(buffer.begin())& bufferCursor,
double timeframe) double timeframe)
{ {
pullFromQueue(drawSamplesQueue, buffer, bufferCursor, timeframe); return pullFromQueue(drawSamplesQueue, circ, timeframe);
} }
void pullFromInputDrawQueue( std::size_t pullFromInputDrawQueue(
std::vector<stmdsp::dacsample_t>& buffer, CircularBuffer<std::vector, stmdsp::dacsample_t>& circ,
decltype(buffer.begin())& bufferCursor,
double timeframe) double timeframe)
{ {
pullFromQueue(drawSamplesInputQueue, buffer, bufferCursor, timeframe); return pullFromQueue(drawSamplesInputQueue, circ, timeframe);
} }

@ -5,7 +5,7 @@
#include <string_view> #include <string_view>
#include <vector> #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; 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_variable("x", x);
symbol_table.add_constants(); symbol_table.add_constants();
expression.register_symbol_table(symbol_table); 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::vector<stmdsp::dacsample_t> samples (stmdsp::SAMPLES_MAX);
std::generate(samples.begin(), samples.end(), auto genFun = [&x, &expression] {
[&] { ++x; return static_cast<stmdsp::dacsample_t>(expression.value()); }); stmdsp::dacsample_t s = expression.value();
++x;
return s;
};
std::generate(samples.begin(), samples.end(), genFun);
return samples; return samples;
} }

@ -26,6 +26,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <SDL2/SDL.h>
extern TextEditor editor; extern TextEditor editor;
extern void log(const std::string& str); extern void log(const std::string& str);
@ -133,8 +135,8 @@ void fileRenderMenu()
ImGui::Separator(); ImGui::Separator();
if (ImGui::MenuItem("Quit")) { if (ImGui::MenuItem("Quit")) {
extern bool done; SDL_Event quitEvent (SDL_QUIT);
done = true; SDL_PushEvent(&quitEvent);
} }
ImGui::EndMenu(); ImGui::EndMenu();

@ -108,8 +108,10 @@ void guiRender(void (*func)())
SDL_GL_SwapWindow(window); SDL_GL_SwapWindow(window);
} }
void guiHandleEvents(bool& done) bool guiHandleEvents()
{ {
bool done = false;
for (SDL_Event event; SDL_PollEvent(&event);) { for (SDL_Event event; SDL_PollEvent(&event);) {
ImGui_ImplSDL2_ProcessEvent(&event); ImGui_ImplSDL2_ProcessEvent(&event);
if (event.type == SDL_QUIT) 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)) if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
done = true; done = true;
} }
return done;
} }
void guiShutdown() void guiShutdown()

@ -1,3 +1,4 @@
#include "circular.hpp"
#include "imgui.h" #include "imgui.h"
#include "imgui_internal.h" #include "imgui_internal.h"
#include "ImGuiFileDialog.h" #include "ImGuiFileDialog.h"
@ -5,6 +6,7 @@
#include "stmdsp.hpp" #include "stmdsp.hpp"
#include <array> #include <array>
#include <cstdio>
#include <memory> #include <memory>
#include <string> #include <string>
#include <string_view> #include <string_view>
@ -15,7 +17,7 @@ extern std::shared_ptr<stmdsp::device> m_device;
void deviceAlgorithmUnload(); void deviceAlgorithmUnload();
void deviceAlgorithmUpload(); void deviceAlgorithmUpload();
bool deviceConnect(); bool deviceConnect();
void deviceGenLoadFormula(std::string_view list); void deviceGenLoadFormula(const std::string& list);
void deviceGenLoadList(std::string_view list); void deviceGenLoadList(std::string_view list);
bool deviceGenStartToggle(); bool deviceGenStartToggle();
void deviceLoadAudioFile(const std::string& file); void deviceLoadAudioFile(const std::string& file);
@ -24,13 +26,11 @@ void deviceSetSampleRate(unsigned int index);
void deviceSetInputDrawing(bool enabled); void deviceSetInputDrawing(bool enabled);
void deviceStart(bool measureCodeTime, bool logResults, bool drawSamples); void deviceStart(bool measureCodeTime, bool logResults, bool drawSamples);
void deviceUpdateDrawBufferSize(double timeframe); void deviceUpdateDrawBufferSize(double timeframe);
void pullFromDrawQueue( std::size_t pullFromDrawQueue(
std::vector<stmdsp::dacsample_t>& buffer, CircularBuffer<std::vector, stmdsp::dacsample_t>& circ,
decltype(buffer.begin())& bufferCursor,
double timeframe); double timeframe);
void pullFromInputDrawQueue( std::size_t pullFromInputDrawQueue(
std::vector<stmdsp::dacsample_t>& buffer, CircularBuffer<std::vector, stmdsp::dacsample_t>& circ,
decltype(buffer.begin())& bufferCursor,
double timeframe); double timeframe);
static std::string sampleRatePreview = "?"; static std::string sampleRatePreview = "?";
@ -56,11 +56,8 @@ void deviceRenderMenu()
}; };
if (ImGui::BeginMenu("Run")) { if (ImGui::BeginMenu("Run")) {
const bool isConnected = m_device ? true : false;
const bool isRunning = isConnected && m_device->is_running();
static std::string connectLabel ("Connect"); static std::string connectLabel ("Connect");
addMenuItem(connectLabel, !isConnected || !isRunning, [&] { addMenuItem(connectLabel, !m_device || !m_device->is_running(), [&] {
if (deviceConnect()) { if (deviceConnect()) {
connectLabel = "Disconnect"; connectLabel = "Disconnect";
sampleRatePreview = sampleRatePreview =
@ -68,9 +65,15 @@ void deviceRenderMenu()
deviceUpdateDrawBufferSize(drawSamplesTimeframe); deviceUpdateDrawBufferSize(drawSamplesTimeframe);
} else { } else {
connectLabel = "Connect"; 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(); ImGui::Separator();
static std::string startLabel ("Start"); static std::string startLabel ("Start");
@ -153,12 +156,11 @@ void deviceRenderToolbar()
void deviceRenderWidgets() void deviceRenderWidgets()
{ {
static std::string siggenInput; static std::string siggenInput (32768, '\0');
static int siggenOption = 0; static int siggenOption = 0;
if (popupRequestSiggen) { if (popupRequestSiggen) {
popupRequestSiggen = false; popupRequestSiggen = false;
siggenInput.clear();
ImGui::OpenPopup("siggen"); ImGui::OpenPopup("siggen");
} else if (popupRequestBuffer) { } else if (popupRequestBuffer) {
popupRequestBuffer = false; popupRequestBuffer = false;
@ -166,15 +168,19 @@ void deviceRenderWidgets()
} else if (popupRequestLog) { } else if (popupRequestLog) {
popupRequestLog = false; popupRequestLog = false;
ImGuiFileDialog::Instance()->OpenModal( ImGuiFileDialog::Instance()->OpenModal(
"ChooseFileLogGen", "Choose File", ".csv", "."); "ChooseFileLog", "Choose File", ".csv", ".");
} }
if (ImGui::BeginPopup("siggen")) { if (ImGui::BeginPopup("siggen")) {
if (ImGui::RadioButton("List", &siggenOption, 0)) if (ImGui::RadioButton("List", &siggenOption, 0)) {
siggenInput.clear(); siggenInput.resize(32768);
siggenInput[0] = '\0';
}
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::RadioButton("Formula", &siggenOption, 1)) if (ImGui::RadioButton("Formula", &siggenOption, 1)) {
siggenInput.clear(); siggenInput.resize(1024);
siggenInput[0] = '\0';
}
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::RadioButton("Audio File", &siggenOption, 2)) if (ImGui::RadioButton("Audio File", &siggenOption, 2))
siggenInput.clear(); siggenInput.clear();
@ -183,7 +189,7 @@ void deviceRenderWidgets()
if (ImGui::Button("Choose File")) { if (ImGui::Button("Choose File")) {
// This dialog will override the siggen popup, closing it. // This dialog will override the siggen popup, closing it.
ImGuiFileDialog::Instance()->OpenModal( ImGuiFileDialog::Instance()->OpenModal(
"ChooseFileLogGen", "Choose File", ".wav", "."); "ChooseFileGen", "Choose File", ".wav", ".");
} }
} else { } else {
ImGui::Text(siggenOption == 0 ? "Enter a list of numbers:" ImGui::Text(siggenOption == 0 ? "Enter a list of numbers:"
@ -201,10 +207,10 @@ void deviceRenderWidgets()
if (ImGui::Button("Save")) { if (ImGui::Button("Save")) {
switch (siggenOption) { switch (siggenOption) {
case 0: case 0:
deviceGenLoadList(siggenInput); deviceGenLoadList(siggenInput.substr(0, siggenInput.find('\0')));
break; break;
case 1: case 1:
deviceGenLoadFormula(siggenInput); deviceGenLoadFormula(siggenInput.substr(0, siggenInput.find('\0')));
break; break;
case 2: case 2:
break; break;
@ -238,18 +244,27 @@ void deviceRenderWidgets()
ImGui::EndPopup(); ImGui::EndPopup();
} }
if (ImGuiFileDialog::Instance()->Display("ChooseFileLogGen", if (ImGuiFileDialog::Instance()->Display("ChooseFileLog",
ImGuiWindowFlags_NoCollapse, ImGuiWindowFlags_NoCollapse,
ImVec2(460, 540))) ImVec2(460, 540)))
{ {
if (ImGuiFileDialog::Instance()->IsOk()) { if (ImGuiFileDialog::Instance()->IsOk()) {
auto filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); const auto filePathName = ImGuiFileDialog::Instance()->GetFilePathName();
auto ext = filePathName.substr(filePathName.size() - 4); deviceLoadLogFile(filePathName);
} else {
logResults = false;
}
if (ext.compare(".wav") == 0) ImGuiFileDialog::Instance()->Close();
}
if (ImGuiFileDialog::Instance()->Display("ChooseFileGen",
ImGuiWindowFlags_NoCollapse,
ImVec2(460, 540)))
{
if (ImGuiFileDialog::Instance()->IsOk()) {
const auto filePathName = ImGuiFileDialog::Instance()->GetFilePathName();
deviceLoadAudioFile(filePathName); deviceLoadAudioFile(filePathName);
else if (ext.compare(".csv") == 0)
deviceLoadLogFile(filePathName);
} }
ImGuiFileDialog::Instance()->Close(); ImGuiFileDialog::Instance()->Close();
@ -260,9 +275,9 @@ void deviceRenderDraw()
{ {
if (drawSamples) { if (drawSamples) {
static std::vector<stmdsp::dacsample_t> buffer; static std::vector<stmdsp::dacsample_t> buffer;
static decltype(buffer.begin()) bufferCursor;
static std::vector<stmdsp::dacsample_t> bufferInput; 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 bool drawSamplesInput = false;
static unsigned int yMinMax = 4095; static unsigned int yMinMax = 4095;
@ -295,16 +310,50 @@ void deviceRenderDraw()
yMinMax = std::min(4095u, (yMinMax << 1) | 1); yMinMax = std::min(4095u, (yMinMax << 1) | 1);
} }
pullFromDrawQueue(buffer, bufferCursor, drawSamplesTimeframe); auto newSize = pullFromDrawQueue(bufferCirc, drawSamplesTimeframe);
if (drawSamplesInput) if (newSize > 0) {
pullFromInputDrawQueue(bufferInput, bufferInputCursor, drawSamplesTimeframe); 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(); auto drawList = ImGui::GetWindowDrawList();
ImVec2 p0 = ImGui::GetWindowPos(); ImVec2 p0 = ImGui::GetWindowPos();
auto size = ImGui::GetWindowSize(); auto size = ImGui::GetWindowSize();
p0.y += 65; p0.y += 65;
size.y -= 70; 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 di = static_cast<float>(buffer.size()) / size.x;
const float dx = std::ceil(size.x / static_cast<float>(buffer.size())); 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(); ImGui::End();
} }
} }

@ -50,7 +50,7 @@ TextEditor::TextEditor()
, mStartTime(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()) , mStartTime(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count())
{ {
SetPalette(GetDarkPalette()); SetPalette(GetDarkPalette());
SetLanguageDefinition(LanguageDefinition::HLSL()); SetLanguageDefinition(LanguageDefinition::CPlusPlus());
mLines.push_back(Line()); mLines.push_back(Line());
} }
@ -2804,357 +2804,3 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::CPlusPlus(
return langDef; 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;
}

@ -174,12 +174,6 @@ public:
} }
static const LanguageDefinition& CPlusPlus(); 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(); TextEditor();

@ -243,9 +243,9 @@ typedef unsigned long long ImU64; // 64-bit unsigned integer (post C++11)
IM_MSVC_RUNTIME_CHECKS_OFF IM_MSVC_RUNTIME_CHECKS_OFF
struct ImVec2 struct ImVec2
{ {
float x, y; float x = 0.f, y = 0.f;
ImVec2() { x = y = 0.0f; } constexpr ImVec2() = default;
ImVec2(float _x, float _y) { x = _x; y = _y; } 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) 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. 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 #ifdef IM_VEC2_CLASS_EXTRA

@ -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();
}

@ -3,87 +3,23 @@
#include <string> #include <string>
#include "imgui.h"
// Adapted from ExampleAppLog from imgui_demo.cpp // Adapted from ExampleAppLog from imgui_demo.cpp
class LogView class LogView
{ {
public: public:
LogView() 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);
ImGui::EndChild(); void Clear();
ImGui::End(); 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: private:
ImGuiTextBuffer Buf; ImGuiTextBuffer Buf;
ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls. ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls.
bool updated;
}; };
#endif // LOGVIEW_H #endif // LOGVIEW_H

@ -25,27 +25,24 @@
extern ImFont *fontSans; extern ImFont *fontSans;
extern ImFont *fontMono; extern ImFont *fontMono;
extern bool guiInitialize(); bool guiInitialize();
extern void guiHandleEvents(bool& done); bool guiHandleEvents();
extern void guiShutdown(); void guiShutdown();
extern void guiRender(void (*func)()); void guiRender(void (*func)());
extern void fileRenderMenu(); void fileRenderMenu();
extern void fileRenderDialog(); void fileRenderDialog();
extern void fileInit(); void fileInit();
extern void codeEditorInit(); void codeEditorInit();
extern void codeRenderMenu(); void codeRenderMenu();
extern void codeRenderToolbar(); void codeRenderToolbar();
extern void codeRenderWidgets(); void codeRenderWidgets();
extern void deviceRenderDraw(); void deviceRenderDraw();
extern void deviceRenderMenu(); void deviceRenderMenu();
extern void deviceRenderToolbar(); void deviceRenderToolbar();
extern void deviceRenderWidgets(); void deviceRenderWidgets();
// Globals that live here
bool done = false;
static LogView logView; static LogView logView;
@ -54,6 +51,8 @@ void log(const std::string& str)
logView.AddLog(str); logView.AddLog(str);
} }
static void renderWindow();
int main(int, char **) int main(int, char **)
{ {
if (!guiInitialize()) if (!guiInitialize())
@ -62,12 +61,25 @@ int main(int, char **)
codeEditorInit(); codeEditorInit();
fileInit(); fileInit();
while (!done) { while (1) {
auto endTime = std::chrono::steady_clock::now() + constexpr std::chrono::duration<double> fpsDelay (1. / 60.);
std::chrono::milliseconds(static_cast<unsigned int>(std::floor(1000. / 60.))); const auto endTime = std::chrono::steady_clock::now() + fpsDelay;
const bool isDone = guiHandleEvents();
if (!isDone) {
renderWindow();
std::this_thread::sleep_until(endTime);
} else {
break;
}
}
guiHandleEvents(done); guiShutdown();
return 0;
}
void renderWindow()
{
// Start the new window frame and render the menu bar. // Start the new window frame and render the menu bar.
ImGui_ImplOpenGL2_NewFrame(); ImGui_ImplOpenGL2_NewFrame();
ImGui_ImplSDL2_NewFrame(); ImGui_ImplSDL2_NewFrame();
@ -81,8 +93,11 @@ int main(int, char **)
} }
// Begin the main view which the controls will be drawn onto. // Begin the main view which the controls will be drawn onto.
ImGui::SetNextWindowPos({0, 22}); constexpr float LOGVIEW_HEIGHT = 200;
ImGui::SetNextWindowSize({WINDOW_WIDTH, WINDOW_HEIGHT - 22 - 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, ImGui::Begin("main", nullptr,
ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoBringToFrontOnFocus); ImGuiWindowFlags_NoBringToFrontOnFocus);
@ -98,8 +113,8 @@ int main(int, char **)
ImGui::PushFont(fontMono); ImGui::PushFont(fontMono);
codeRenderWidgets(); codeRenderWidgets();
ImGui::SetNextWindowPos({0, WINDOW_HEIGHT - 200}); ImGui::SetNextWindowPos({0, WINDOW_HEIGHT - LOGVIEW_HEIGHT});
ImGui::SetNextWindowSize({WINDOW_WIDTH, 200}); ImGui::SetNextWindowSize({WINDOW_WIDTH, LOGVIEW_HEIGHT});
logView.Draw("log", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus); logView.Draw("log", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopFont(); ImGui::PopFont();
} }
@ -113,11 +128,5 @@ int main(int, char **)
guiRender([] { guiRender([] {
ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
}); });
std::this_thread::sleep_until(endTime);
}
guiShutdown();
return 0;
} }

Loading…
Cancel
Save