Compare commits

...

5 Commits

Author SHA1 Message Date
illyum
6e0cc49826 (Feat): Demo dmx engine 2024-08-16 02:19:18 -06:00
illyum
f8341ff8f2 (Feat): Create basic terminal logger 2024-08-16 02:18:53 -06:00
illyum
0858e70121 (Chore): Delete unused file 2024-08-16 02:18:21 -06:00
illyum
0f5c1da12f (Feat): Implement DMX Engine 2024-08-16 02:17:43 -06:00
illyum
3e73cd63bb (Chore): Include all files dynamically 2024-08-16 02:16:34 -06:00
9 changed files with 312 additions and 30 deletions

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.24)
project(RaylibDmx)
set(CMAKE_CXX_STANDARD 26)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# nvim/fleet users (ONLY WORKS WITH MINGW/NINJA BUILDERS)
@ -64,19 +64,22 @@ FetchContent_Declare(
)
FetchContent_MakeAvailable(rlimgui)
file(GLOB_RECURSE SOURCES "src/*.cpp")
add_executable(${PROJECT_NAME} ${SOURCES})
# Add source files
file(GLOB_RECURSE PROJECT_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_LIST_DIR}/src/*.cpp")
set(PROJECT_INCLUDE "${CMAKE_CURRENT_LIST_DIR}/src")
target_link_libraries(${PROJECT_NAME} raylib)
# Declare the executable
add_executable(${PROJECT_NAME})
target_sources(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCES})
target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_INCLUDE})
set(RLIMGUI_SOURCES
${rlimgui_SOURCE_DIR}/rlImGui.cpp
)
# Link with Raylib
target_link_libraries(${PROJECT_NAME} PRIVATE raylib)
# Create rlImGui lib
add_library(rlImGui STATIC ${RLIMGUI_SOURCES})
# Create rlImGui library
add_library(rlImGui STATIC ${rlimgui_SOURCE_DIR}/rlImGui.cpp)
target_include_directories(rlImGui PUBLIC ${rlimgui_SOURCE_DIR} ${imgui_SOURCE_DIR})
target_link_libraries(rlImGui raylib ImGui)
target_link_libraries(rlImGui PRIVATE raylib ImGui)
# Link ImGui and rlImGui
target_link_libraries(${PROJECT_NAME} ImGui rlImGui)
# Link ImGui and rlImGui with the executable
target_link_libraries(${PROJECT_NAME} PRIVATE ImGui rlImGui)

27
src/BasicLogger.cpp Normal file
View File

@ -0,0 +1,27 @@
//
// Created by illyum on 8/15/2024.
//
#include "BasicLogger.h"
#include <iostream>
// Set default verbosity
LogPriority BasicLogger::verbosity = TraceP;
void BasicLogger::Log(LogPriority priority, const char *message) {
if (priority >= verbosity) {
switch (priority) {
case TraceP: std::cout << "Trace: \t"; break;
case DebugP: std::cout << "Debug: \t"; break;
case InfoP: std::cout << "Info: \t"; break;
case WarnP: std::cout << "Warn: \t"; break;
case ErrorP: std::cout << "Error: \t"; break;
case FatalP: std::cout << "Fatal: \t"; break;
}
std::cout << message << "\n";
}
}
void BasicLogger::SetVerbosity(LogPriority new_priority) {
verbosity = new_priority;
}

22
src/BasicLogger.h Normal file
View File

@ -0,0 +1,22 @@
//
// Created by illyum on 8/15/2024.
//
#ifndef BASICLOGGER_H
#define BASICLOGGER_H
enum LogPriority {
TraceP, DebugP, InfoP, WarnP, ErrorP, FatalP
};
class BasicLogger {
private:
static LogPriority verbosity;
public:
static void Log(LogPriority priority, const char *message);
static void SetVerbosity(LogPriority new_priority);
};
#endif //BASICLOGGER_H

11
src/DmxWriter.cpp Normal file
View File

@ -0,0 +1,11 @@
//
// Created by illyum on 8/16/2024.
//
#include "DmxWriter.h"
DmxWriter::DmxWriter(DMXEngine& engine) : dmxEngine(engine) {}
void DmxWriter::setChannel(int channel, unsigned char value) {
dmxEngine.setChannelValue(channel, value);
}

19
src/DmxWriter.h Normal file
View File

@ -0,0 +1,19 @@
//
// Created by illyum on 8/16/2024.
//
#ifndef DMXWRITER_H
#define DMXWRITER_H
#include "dmx.h"
class DmxWriter {
public:
DmxWriter(DMXEngine& engine);
void setChannel(int channel, unsigned char value);
private:
DMXEngine& dmxEngine;
};
#endif // DMXWRITER_H

View File

@ -1,3 +1,117 @@
//
// Created by illyum on 8/15/2024.
//
#include "dmx.h"
#include <iostream>
#include <chrono>
#include <thread>
#include "windows.h"
DMXEngine::DMXEngine(const char* portName, int baudRate, int dataSize)
: running(false), buffer(dataSize, 0) {
hSerial = CreateFileA(portName, GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hSerial == INVALID_HANDLE_VALUE) {
std::cerr << "Error opening " << portName << " port" << std::endl;
exit(EXIT_FAILURE);
}
configurePort();
}
DMXEngine::~DMXEngine() {
if (running) {
stop();
}
CloseHandle(hSerial);
}
void DMXEngine::configurePort() {
DCB dcbSerialParams = { 0 };
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (!GetCommState(hSerial, &dcbSerialParams)) {
std::cerr << "Error getting COM port state" << std::endl;
CloseHandle(hSerial);
exit(EXIT_FAILURE);
}
dcbSerialParams.BaudRate = 250000;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = TWOSTOPBITS;
dcbSerialParams.Parity = NOPARITY;
if (!SetCommState(hSerial, &dcbSerialParams)) {
std::cerr << "Error setting COM port state" << std::endl;
CloseHandle(hSerial);
exit(EXIT_FAILURE);
}
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (!SetCommTimeouts(hSerial, &timeouts)) {
std::cerr << "Error setting COM port timeouts" << std::endl;
CloseHandle(hSerial);
exit(EXIT_FAILURE);
}
}
void DMXEngine::start() {
running = true;
dmxThread = std::thread(dmxThreadFunc, this);
}
void DMXEngine::stop() {
running = false;
if (dmxThread.joinable()) {
dmxThread.join();
}
DMXEngine::dumpZeros();
}
void DMXEngine::setChannelValue(int channel, unsigned char value) {
if (channel >= 0 && channel < buffer.size()) {
buffer[channel] = value;
}
}
void DMXEngine::sendDMXData() {
while (running) {
// Break condition
EscapeCommFunction(hSerial, SETBREAK);
std::this_thread::sleep_for(std::chrono::milliseconds(1));
EscapeCommFunction(hSerial, CLRBREAK);
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // MAB
DWORD bytesWritten;
unsigned char startCode = 0;
WriteFile(hSerial, &startCode, 1, &bytesWritten, NULL);
WriteFile(hSerial, buffer.data(), buffer.size(), &bytesWritten, NULL);
std::this_thread::sleep_for(std::chrono::milliseconds(25));
}
}
void DMXEngine::dumpZeros() {
std::fill(buffer.begin(), buffer.end(), 0);
EscapeCommFunction(hSerial, SETBREAK);
std::this_thread::sleep_for(std::chrono::milliseconds(1));
EscapeCommFunction(hSerial, CLRBREAK);
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // MAB
DWORD bytesWritten;
unsigned char startCode = 0;
WriteFile(hSerial, &startCode, 1, &bytesWritten, NULL);
WriteFile(hSerial, buffer.data(), buffer.size(), &bytesWritten, NULL);
}
void DMXEngine::dmxThreadFunc(DMXEngine* engine) {
engine->sendDMXData();
}

View File

@ -2,7 +2,38 @@
// Created by illyum on 8/15/2024.
//
#ifndef RAYLIBDMX_DMX_H
#define RAYLIBDMX_DMX_H
#ifndef DMX_H
#define DMX_H
#endif //RAYLIBDMX_DMX_H
#include <vector>
#include <tuple>
#include <atomic>
#include <thread>
struct DMXFixture {
unsigned char r, g, b;
int channel;
};
class DMXEngine {
public:
explicit DMXEngine(const char* portName, int baudRate = 250000, int dataSize = 512);
~DMXEngine();
void start();
void stop();
void setChannelValue(int channel, unsigned char value);
private:
void sendDMXData();
void dumpZeros();
void configurePort();
static void dmxThreadFunc(DMXEngine* engine);
void* hSerial;
std::atomic<bool> running;
std::vector<unsigned char> buffer;
std::thread dmxThread;
};
#endif // DMX_H

View File

@ -2,20 +2,35 @@
#include "rlImGui.h"
#include "panel.h"
#include "imgui.h"
#include "dmx.h"
#include "DmxWriter.h"
#include "BasicLogger.h"
#include <cstdlib>
#include <ctime>
void DrawImGui();
int main() {
DMXEngine dmxEngine("\\\\.\\COM3");
dmxEngine.start();
DmxWriter dmxWriter(dmxEngine);
// Initialize random seed
srand(static_cast<unsigned int>(time(0)));
const int screenWidth = 1920;
const int screenHeight = 1080;
InitWindow(screenWidth, screenHeight, "DMX Raylib UI");
SetTargetFPS(60);
SetTargetFPS(165);
rlImGuiSetup(true); // Use true for dark theme, false for light theme
rlImGuiSetup(true);
Panel timelinePanel = {{0, 0, screenWidth * 0.75f, screenHeight * 0.6f}, "Timeline", LIGHTGRAY, DARKGRAY, true};
Panel propertiesPanel = {{screenWidth * 0.75f, 0, screenWidth * 0.25f, screenHeight}, "Properties", LIGHTGRAY, DARKGRAY, true};
std::string randomColors;
while (!WindowShouldClose()) {
timelinePanel.Update();
propertiesPanel.Update();
@ -23,20 +38,68 @@ int main() {
BeginDrawing();
ClearBackground(RAYWHITE);
rlImGuiBegin();
bool open = true;
ImGui::ShowDemoWindow(&open);
rlImGuiEnd();
if (timelinePanel.isVisible) timelinePanel.Draw();
if (propertiesPanel.isVisible) propertiesPanel.Draw();
rlImGuiBegin();
ImGui::Begin("Random Color Clicker");
if (ImGui::Button("Random Color!")) {
unsigned char r = static_cast<unsigned char>(rand() % 256);
unsigned char g = static_cast<unsigned char>(rand() % 256);
unsigned char b = static_cast<unsigned char>(rand() % 256);
dmxWriter.setChannel(0, r);
dmxWriter.setChannel(1, g);
dmxWriter.setChannel(2, b);
randomColors = "Sent DMX Color - R: " + std::to_string(r) +
", G: " + std::to_string(g) +
", B: " + std::to_string(b);
}
ImGui::Text("%s", randomColors.c_str());
// End the window
ImGui::End();
rlImGuiEnd();
// Draw FPS on the screen
DrawFPS(3, screenHeight - 20);
EndDrawing();
}
BasicLogger::Log(DebugP, "Stopping DMX Engine...");
dmxEngine.stop();
BasicLogger::Log(DebugP, "Shutting down rlImGui...");
rlImGuiShutdown();
BasicLogger::Log(DebugP, "Closing Window...");
CloseWindow();
return 0;
}
void DrawImGui() {
rlImGuiBegin();
// Begin a new window with a title
ImGui::Begin("My Custom Window");
// Add a button with a label
if (ImGui::Button("Click Me"))
{
// Action to be performed when the button is clicked
ImGui::Text("Button Clicked!");
}
// End the window
ImGui::End();
// bool open = true;
// ImGui::ShowDemoWindow(&open);
rlImGuiEnd();
}

View File

@ -1,8 +0,0 @@
//
// Created by illyum on 8/15/2024.
//
#ifndef RAYLIBDMX_WINAPI_WRAPPER_H
#define RAYLIBDMX_WINAPI_WRAPPER_H
#endif //RAYLIBDMX_WINAPI_WRAPPER_H