453 lines
15 KiB
C++
453 lines
15 KiB
C++
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <handleapi.h>
|
|
#include <thread>
|
|
#include <windows.h>
|
|
#include "include/glad/glad.h"
|
|
#include "include/glfw/glfw3.h"
|
|
#include <iostream>
|
|
#include "include/glm/gtc/quaternion.hpp"
|
|
#include "include/imgui/imgui.h"
|
|
#include "include/imgui/imgui_impl_glfw.h"
|
|
#include "include/imgui/imgui_impl_opengl3.h"
|
|
#include "serialcomm.hpp"
|
|
#include <string>
|
|
#include <mutex>
|
|
#include "visualization.hpp"
|
|
#include <vector>
|
|
#include "include/glm/glm.hpp"
|
|
#include "include/glm/gtc/matrix_transform.hpp"
|
|
#include "include/glm/gtc/type_ptr.hpp"
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
#include "include/stb/stb_image.h"
|
|
#include "include/glm/gtc/type_ptr.hpp"
|
|
|
|
|
|
// global variables for the communication between threads (gui, serial)
|
|
std::mutex g_mutex;
|
|
Quaternion g_currQuat = {1.0f, 0.0f, 0.0f, 0.0f};
|
|
std::vector<Quaternion> g_quadHistory;
|
|
bool g_running = false;
|
|
HANDLE g_serialHandle = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
// shader
|
|
const char *vertexShaderSource = "#version 330 core\n"
|
|
"layout (location = 0) in vec3 aPos;\n"
|
|
"layout (location = 1) in vec2 aTexCoord;\n"
|
|
"uniform mat4 transformMatrix;\n"
|
|
|
|
"uniform mat4 model;\n"
|
|
"uniform mat4 view;\n"
|
|
"uniform mat4 projection;\n"
|
|
|
|
"out vec2 TexCoord;\n"
|
|
|
|
"void main()\n"
|
|
"{\n"
|
|
" gl_Position = projection * view * model *vec4(aPos, 1.0);\n"
|
|
" TexCoord = aTexCoord;\n"
|
|
"}\0";
|
|
|
|
const char *fragmentShaderSource = "#version 330 core\n"
|
|
"out vec4 FragColor;\n"
|
|
"in vec2 TexCoord;\n"
|
|
"uniform sampler2D ourTexture;\n"
|
|
|
|
"void main()\n"
|
|
"{\n"
|
|
" FragColor = texture(ourTexture, TexCoord);\n"
|
|
"}\0";
|
|
|
|
|
|
// handle the serial communication wioth the stm32 in a separate thread
|
|
void serialParserThread() {
|
|
// define communication variables
|
|
const char* portName = "COM3";
|
|
DWORD baudRate = CBR_115200;
|
|
char buffer[64];
|
|
DWORD bytesRead;
|
|
std::string incompleteDataBuffer;
|
|
|
|
// establish communication to stm32
|
|
g_serialHandle = initSerialPort(portName, baudRate);
|
|
if (g_serialHandle == INVALID_HANDLE_VALUE){
|
|
g_running = false;
|
|
std::cout << "Serial connection FAILED" << std::endl;
|
|
return;
|
|
} else {std::cout << "Serial connection succesfully established" << std::endl;}
|
|
|
|
// serial reading loop
|
|
while (g_running) {
|
|
if (readSerialData(g_serialHandle, buffer, sizeof(buffer), bytesRead)) {
|
|
if (bytesRead > 0) {
|
|
// add newly arrived data to buffer
|
|
buffer[bytesRead] = '\0';
|
|
incompleteDataBuffer += buffer;
|
|
|
|
// process any complete lines in the buffer
|
|
size_t pos;
|
|
while ((pos = incompleteDataBuffer.find('\n')) != std::string::npos) {
|
|
// create substring of completed line and erase it from incompleteDataBuffer
|
|
std::string completeLine = incompleteDataBuffer.substr(0, pos);
|
|
incompleteDataBuffer.erase(0, pos + 1);
|
|
|
|
// now parse the quaternions from line
|
|
Quaternion quat;
|
|
if (parseQuaternion(completeLine, quat)) {
|
|
// lock mutex while updating it
|
|
std::lock_guard<std::mutex> lock(g_mutex);
|
|
g_currQuat = quat;
|
|
g_quadHistory.push_back(quat);
|
|
if (g_quadHistory.size() > 200) {
|
|
g_quadHistory.erase(g_quadHistory.begin());
|
|
}
|
|
|
|
std::cout << "w: " << g_currQuat.w << "x: " << g_currQuat.x << "y: " << g_currQuat.y << "z: " << g_currQuat.z << std::endl;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// close and exit the thread
|
|
CloseHandle(g_serialHandle);
|
|
std::cout << "Serial communication thread exiting" << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main() {
|
|
// Locap copy of quaternion
|
|
Quaternion lQuad;
|
|
|
|
// initialize main window
|
|
GLFWwindow* window = initWindow();
|
|
if (!window) {
|
|
std::cerr << "Window initialization failed in mainthread" << std::endl;
|
|
return 1;
|
|
} else {std::cout << "Window initialization succesful in mainthread" << std::endl;}
|
|
|
|
// compile the shaders
|
|
int success;
|
|
char errorLog[512];
|
|
unsigned int vertexShader;
|
|
unsigned int fragmentShader;
|
|
|
|
vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
|
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
|
|
glCompileShader(vertexShader);
|
|
|
|
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
|
|
if(!success) {
|
|
glGetShaderInfoLog(vertexShader, 512, NULL, errorLog);
|
|
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << errorLog << std::endl;
|
|
}
|
|
|
|
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
|
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
|
|
glCompileShader(fragmentShader);
|
|
|
|
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
|
|
if(!success) {
|
|
glGetShaderInfoLog(fragmentShader, 512, NULL, errorLog);
|
|
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << errorLog << std::endl;
|
|
}
|
|
|
|
|
|
// link the shaders
|
|
unsigned int shaderProgramm = glCreateProgram();
|
|
glAttachShader(shaderProgramm, vertexShader);
|
|
glAttachShader(shaderProgramm, fragmentShader);
|
|
glLinkProgram(shaderProgramm);
|
|
glGetProgramiv(shaderProgramm, GL_LINK_STATUS, &success);
|
|
if(!success) {
|
|
glGetShaderInfoLog(shaderProgramm, 512, NULL, errorLog);
|
|
std::cout << "ERROR::LINKING::SHADER::COMPILATION_FAILED\n" << errorLog << std::endl;
|
|
}
|
|
glUseProgram(shaderProgramm);
|
|
glDeleteShader(vertexShader);
|
|
glDeleteShader(fragmentShader);
|
|
|
|
// texture stuff
|
|
unsigned int texture;
|
|
glGenTextures(1, &texture);
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
|
|
|
// texture wrapping and filtering
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
// now load and create the texture
|
|
int imWidth, imHeigth, imNrChannels;
|
|
stbi_set_flip_vertically_on_load(true);
|
|
unsigned char *data = stbi_load("kekusmaximus.jpg", &imWidth, &imHeigth, &imNrChannels, 0);
|
|
if (data) {
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imWidth, imHeigth, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
|
|
glGenerateMipmap(GL_TEXTURE_2D);
|
|
} else {
|
|
std::cout << "Failed to load texture" << std::endl;
|
|
}
|
|
stbi_image_free(data);
|
|
|
|
// configure depth settings for 3D
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
// only screen coordinates between -1 and 1 are visible, (0, 0, 0) being display centerpoint
|
|
float vertexData[] = {
|
|
// Front face
|
|
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // 0
|
|
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // 1
|
|
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // 2
|
|
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, // 3
|
|
|
|
// Back face
|
|
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // 4
|
|
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, // 5
|
|
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // 6
|
|
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // 7
|
|
|
|
// Left face
|
|
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // 8
|
|
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // 9
|
|
-0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // 10
|
|
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // 11
|
|
|
|
// Right face
|
|
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // 12
|
|
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, // 13
|
|
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // 14
|
|
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, // 15
|
|
|
|
// Bottom face
|
|
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // 16
|
|
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, // 17
|
|
0.5f, -0.5f, 0.5f, 1.0f, 1.0f, // 18
|
|
-0.5f, -0.5f, 0.5f, 0.0f, 1.0f, // 19
|
|
|
|
// Top face
|
|
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, // 20
|
|
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // 21
|
|
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // 22
|
|
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f // 23
|
|
};
|
|
|
|
unsigned int vertexIndices[] = {
|
|
// Front face
|
|
0, 1, 2, 2, 3, 0,
|
|
// Back face
|
|
4, 5, 6, 6, 7, 4,
|
|
// Left face
|
|
8, 9, 10, 10, 11, 8,
|
|
// Right face
|
|
12, 13, 14, 14, 15, 12,
|
|
// Bottom face
|
|
16, 17, 18, 18, 19, 16,
|
|
// Top face
|
|
20, 21, 22, 22, 23, 20
|
|
};
|
|
|
|
// create vertex/element buffer object VBO to store data on GPU
|
|
unsigned int VBO, VAO, EBO;
|
|
|
|
glGenVertexArrays(1, &VAO);
|
|
glGenBuffers(1, &VBO);
|
|
glGenBuffers(1, &EBO);
|
|
|
|
glBindVertexArray(VAO);
|
|
|
|
// bind vertex to VBO buffer
|
|
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
|
|
|
|
// bind indices to EBO buffer
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(vertexIndices), vertexIndices, GL_STATIC_DRAW);
|
|
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void*)0);
|
|
glEnableVertexAttribArray(0);
|
|
|
|
// add texture coordinates
|
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
|
|
glEnableVertexAttribArray(1);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindVertexArray(0);
|
|
|
|
|
|
// setup Dear ImGui context
|
|
IMGUI_CHECKVERSION();
|
|
ImGui::CreateContext();
|
|
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableSetMousePos;
|
|
|
|
// setup platform/renderer backends
|
|
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
|
ImGui_ImplOpenGL3_Init();
|
|
|
|
// Start serial parsing thread
|
|
// pass the address of the code in memory so that thread can start its instance of the function
|
|
//std::thread parserThread(serialParserThread);
|
|
std::thread* parserThread = nullptr;
|
|
|
|
// set rendering state of window
|
|
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
|
|
|
|
// glm quad to test purposes
|
|
|
|
|
|
// main rendering loop for the ui
|
|
while (!glfwWindowShouldClose(window)) {
|
|
// process new events from window evevnt queue
|
|
glfwPollEvents();
|
|
// clear the color buffer == clear the screen / / GL_DEPTH_BUFFER_BIT would be for 3D rendering
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
// activate and bind texture before draw
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
|
|
|
glUseProgram(shaderProgramm);
|
|
|
|
// use the texture actually
|
|
glUniform1i(glGetUniformLocation(shaderProgramm, "outTexture"), 0);
|
|
|
|
// create the transformations - TRS order (translate, rotate, scale) for proper transformation
|
|
// create identity matrix
|
|
glm::mat4 transformMatrix = glm::mat4(1.0f);
|
|
transformMatrix = glm::translate(transformMatrix, glm::vec3(0.3f, 0.1f, 0.0f));
|
|
transformMatrix = glm::rotate(transformMatrix, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
|
|
|
|
glm::mat4 model = glm::mat4(1.0f);
|
|
glm::mat4 view = glm::mat4(1.0f);
|
|
glm::mat4 projection = glm::mat4(1.0f);
|
|
// apply MVP
|
|
//model = glm::rotate(model, (float)glfwGetTime() * glm::radians(50.0f), glm::vec3(0.5f, 1.0f, 0.0f));
|
|
|
|
// this needs to be deleted and redone
|
|
glm::quat kekus_q(g_currQuat.w, g_currQuat.x, g_currQuat.y, g_currQuat.z);
|
|
|
|
|
|
model = glm::mat4_cast(kekus_q);
|
|
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
|
|
projection = glm::perspective(glm::radians(45.0f), (float)1280 / (float)720, 0.1f, 100.f);
|
|
|
|
|
|
// get uniform matrix location and set matrix
|
|
// unsigned int transformLoc = glGetUniformLocation(shaderProgramm, "transformMatrix");
|
|
// glad_glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transformMatrix));
|
|
unsigned int modelLoc = glGetUniformLocation(shaderProgramm, "model");
|
|
unsigned int viewLoc = glGetUniformLocation(shaderProgramm, "view");
|
|
unsigned int projLoc = glGetUniformLocation(shaderProgramm, "projection");
|
|
//shaderProgramm.setMat4("projection", projection);
|
|
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
|
|
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
|
|
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
|
|
|
|
// OpenGL 3D Render
|
|
glBindVertexArray(VAO);
|
|
//glDrawArrays(GL_TRIANGLES, 0, 3);
|
|
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
|
|
//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
|
|
|
// start imgui frame
|
|
ImGui_ImplOpenGL3_NewFrame();
|
|
ImGui_ImplGlfw_NewFrame();
|
|
ImGui::NewFrame();
|
|
|
|
|
|
// accessing g_currQuat through the mutex protection
|
|
// limited scope block just for the mutex operations
|
|
{
|
|
std::lock_guard<std::mutex> lock(g_mutex);
|
|
lQuad = g_currQuat;
|
|
|
|
static int frame_count = 0;
|
|
if (frame_count++ % 60 == 0) {
|
|
std::cout << "Rendering frame with quaternion: "
|
|
<< "w: " << g_currQuat.w << " x: " << g_currQuat.x
|
|
<< " y: " << g_currQuat.y << " z: " << g_currQuat.z << std::endl;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ImGui::Text("Hello Daddy, I'm here to serve");
|
|
ImGui::Text("w: %.4f x: %.4f y: %.4f z: %.4f", lQuad.w, lQuad.x, lQuad.y, lQuad.z);
|
|
ImGui::Text("Connection to MCU: ");
|
|
|
|
ImGui::BeginDisabled(parserThread != nullptr);
|
|
if (ImGui::Button("Connect")) {
|
|
g_running = true;
|
|
parserThread = new std::thread(serialParserThread);
|
|
}
|
|
ImGui::EndDisabled();
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::BeginDisabled(parserThread == nullptr);
|
|
if (ImGui::Button("Disconnect")) {
|
|
g_running = false;
|
|
parserThread -> join();
|
|
delete parserThread;
|
|
parserThread = nullptr;
|
|
}
|
|
ImGui::EndDisabled();
|
|
|
|
|
|
// create scrolling section for last 200 measurements
|
|
ImGui::BeginChild("History", ImVec2(0, 300), true, ImGuiWindowFlags_HorizontalScrollbar);
|
|
// loop through quadHistory vector and display each element as line
|
|
for (uint32_t i = 0; i < g_quadHistory.size(); i++) {
|
|
const Quaternion& q = g_quadHistory[i];
|
|
ImGui::Text("w: %.4f x: %.4f y: %.4f z: %.4f", q.w, q.x, q.y, q.z);
|
|
}
|
|
// enable autoscroll to newest entry
|
|
if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) {
|
|
ImGui::SetScrollHereY(1.0f);
|
|
}
|
|
ImGui::EndChild();
|
|
|
|
// render the frame
|
|
ImGui::Render();
|
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
|
// swap the buffers to display what was rendered
|
|
glfwSwapBuffers(window);
|
|
glfwPollEvents();
|
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(16));
|
|
}
|
|
|
|
// set the parsing thread to exit and wait for it
|
|
// g_running = false;
|
|
//if (parserThread.joinable()) {
|
|
// parserThread.join();
|
|
//}
|
|
|
|
// clean up ImGui
|
|
ImGui_ImplOpenGL3_Shutdown();
|
|
ImGui_ImplGlfw_Shutdown();
|
|
ImGui::DestroyContext();
|
|
|
|
// clean up OpenGL
|
|
glDeleteVertexArrays(1, &VAO);
|
|
glDeleteBuffers(1, &VBO);
|
|
glDeleteBuffers(1, &EBO);
|
|
glDeleteProgram(shaderProgramm);
|
|
|
|
// clean up the window
|
|
glfwDestroyWindow(window);
|
|
glfwTerminate();
|
|
|
|
|
|
|
|
return 0;
|
|
} |