Skip to content
Snippets Groups Projects
Commit 8fadbfa9 authored by Armin Co's avatar Armin Co
Browse files

Reset master for new QPong version.

parent 456a8a9c
No related branches found
No related tags found
No related merge requests found
Showing
with 0 additions and 1960 deletions
build
.vscode
\ No newline at end of file
[submodule "libs/googletest"]
path = libs/googletest
url = https://github.com/google/googletest.git
[submodule "libs/imgui"]
path = libs/imgui
url = https://github.com/armin-co/imgui.git
[submodule "libs/cpp_starter_project"]
path = libs/cpp_starter_project
url = https://github.com/armin-co/cpp_starter_project.git
#
[submodule "libs/spdlog"]
path = libs/spdlog
url = https://github.com/gabime/spdlog
# CMake file for the QPong project.
project(QPong)
cmake_minimum_required(VERSION 3.10)
# Options
option(create_test "Build all tests." OFF)
# Use modern C++!
set(CMAKE_CXX_STANDARD 17)
# @todo It will not run in debug mode only in release mode.
set(CMAKE_BUILD_TYPE Release)
# PkgConfig
find_package(PkgConfig REQUIRED)
# On macOS some things are different ^^
if(APPLE)
link_directories(/usr/local/lib)
include_directories(/usr/local/include)
# This may be necessary on some systems.
message("ATTENTION: You probably have to export the PKG_CONFIG_PATH.")
message("For example: $ export PKG_CONFIG_PATH=\"/usr/local/lib:/usr/local/opt/zlib/lib/pkgconfig\"")
endif()
# logging library spdlog
add_subdirectory(libs/spdlog)
# Add qpong lib for core qpong functionality
add_subdirectory(qpong_core)
include_directories(qpong_core)
# Dear ImGui and SDL based application
add_subdirectory(imgui_sdl_app)
# Dear ImGui and GLFW based application
add_subdirectory(imgui_glfw_app)
# Add dir with gtk qpong app
add_subdirectory(gtk_qpong_app)
# Add some unit tests
# not many yet ^^
if (create_test)
add_subdirectory(libs/googletest)
add_subdirectory(tests)
endif()
This diff is collapsed.
# QPong – Quanten-Pong
#### This is the new pong ;)
A new kind of pong. It will feel familiar but different.
If you want two know more about what is happening behind the scenes visit [https://gitlab.cvh-server.de/pgerwinski/diss](https://gitlab.cvh-server.de/pgerwinski/diss).
If youu play the game you will have to control bats as in the original pong game. But instead of a ball there is a quantum particle that you will have to hit.
The image on the left handside is where you play in it shows the particles "position". The image on the right handside shows the impulse of the particle.
Have fun!
Controls for Player 1: A & Q and for Player two P & L.
---
Dependencies:
* cmake
* libgtkmm-3.0-dev
* libfftw3-dev
* libsdl2-dev
* libglfw3-dev
* libglm-dev
---
### Build and run
````
mkdir build && cd build
cmake ..
make -j6
./gtk_qpong_app/qpong.app
````
## TODOS
- ImageBuffer in die Klasse Particle ziehen,
- Methoden bereitstellen zum Abrufen der ImageBuffer
- ParticleImage muss das Particle Objekt kennen, um die ImageBuffer abrufen zu können.
- Umbauen der Klasse Particle zu einer Klasse Simulation Environemnt
## Erweiterungsideen
- Konfiguration über die GUI, evt. mit speichern
- Spalt & Interferenz
- Controller-Schnittstelle (für z.B. Mikrofon, Joysticks oder Potis)
- Einfangen des Teilchens verhindern durch eine Vignette im Impulsraum.
\ No newline at end of file
# Setup GTK configuration
pkg_check_modules(GTKMM gtkmm-3.0)
link_directories(${GTKMM_LIBRARY_DIRS})
# get all GTKMM dependencies and configuration
include_directories(${GTKMM_INCLUDE_DIRS})
# create the application
add_executable( qpong.app
main.cpp
QWindow.cpp
QDrawingArea.cpp
ParticleImage.cpp
)
find_package(Threads)
# link all necessary libs to the target
target_link_libraries( qpong.app
qpong_core
spdlog
${CMAKE_THREAD_LIBS_INIT}
${GTKMM_LIBRARIES}
fftw3
fftw3_omp
m # math
)
///
/// @file ParticleImage.cpp
/// @author Armin Co
///
#include "ParticleImage.hpp"
#include "Common.hpp"
using namespace QPong;
constexpr int bytesPerPixel = 3;
constexpr int bitsPerSample = 8;
ParticleImage::ParticleImage()
: ImageBuffer()
{
m_pixbuf = new uChar[QPong::arraySize * bytesPerPixel];
}
Glib::RefPtr<Gdk::Pixbuf> ParticleImage::getPixbuf()
{
for (unsigned i = 0; i < QPong::arraySize * bytesPerPixel;)
{
QColor c = getValue(i/bytesPerPixel);
m_pixbuf[i++] = static_cast<uChar>(c.r * 255);
m_pixbuf[i++] = static_cast<uChar>(c.g * 255);
m_pixbuf[i++] = static_cast<uChar>(c.b * 255);
}
Glib::RefPtr<Gdk::Pixbuf> pb = Gdk::Pixbuf::create_from_data(m_pixbuf, Gdk::Colorspace::COLORSPACE_RGB, false, bitsPerSample, QPong::arrayWidth, QPong::arrayHeight, QPong::arrayWidth * bytesPerPixel);
pb = pb->scale_simple(768, 768, Gdk::InterpType::INTERP_NEAREST);
return pb;
}
\ No newline at end of file
///
/// @file ParticleImage.hpp
/// @author Armin Co
///
/// @brief Class to wrap one dimensional array.
///
#ifndef QPONG_PARTICLE_IMAGE_HPP
#define QPONG_PARTICLE_IMAGE_HPP
#include <gtkmm.h>
#include "ImageBuffer.hpp"
/// @brief Wraps an one dimensional array.
/// Values can be accessed as in 2D.
///
class ParticleImage : public QPong::ImageBuffer
{
public:
ParticleImage();
Glib::RefPtr<Gdk::Pixbuf> getPixbuf();
private:
using uChar = unsigned char;
uChar* m_pixbuf;
};
#endif
\ No newline at end of file
///
/// @file QDrawingArea.cpp
/// @author Armin Co
///
#include "QDrawingArea.hpp"
QDrawingArea::QDrawingArea()
{
m_dispatcher.connect(sigc::mem_fun(*this, &QDrawingArea::queue_draw));
}
void QDrawingArea::redraw()
{
m_dispatcher.emit();
}
void QDrawingArea::setPixbuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf)
{
m_image = pixbuf;
}
bool QDrawingArea::on_draw(const Cairo::RefPtr<Cairo::Context> &cr)
{
cr->save();
if (!m_image)
{
return true;
}
Gdk::Cairo::set_source_pixbuf(cr, m_image, 0, 0);
cr->paint();
cr->restore();
return true;
}
///
/// @file QDrawingArea.hpp
/// @author Armin Co
///
/// @brief QDrawingArea is a class which can show a Gdk::Pixbuf.
///
#ifndef QPONG_DRAWING_AREA_HPP
#define QPONG_DRAWING_AREA_HPP
#include <gtkmm.h>
#include <gdkmm.h>
/// @brief QDrawingArea is derived from Gtk::DrawingArea.
/// An object of this class stores a reference to Gdk::Pixbuf which can be shown and updated.
///
class QDrawingArea : public Gtk::DrawingArea
{
public:
QDrawingArea();
virtual ~QDrawingArea(){};
/// @brief Request a redraw of the drawing area.
///
void redraw();
/// @brief Set a new pixbuf reference.
///
void setPixbuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf);
protected:
/// @brief Signal handler which is called when a redraw of the drawing area is requested.
///
bool on_draw(const Cairo::RefPtr<Cairo::Context> &cr) override;
private:
Glib::RefPtr<Gdk::Pixbuf> m_image; ///< Reference a pixbuf.
Glib::Dispatcher m_dispatcher; ///< Dispatcher is used to trigger thread safe redraws.
};
#endif
\ No newline at end of file
#include <iostream>
#include <iomanip>
#include <chrono>
#include "QWindow.hpp"
using namespace QPong;
bool propagating = true;
int propRate = 0;
int renderRate = 0;
bool qPressed = false;
bool aPressed = false;
bool upPressed = false;
bool downPressed = false;
/// @brief This functino has to run in its own thread and propagates the particle as fast as possible.
///
void QWindow::simulation()
{
do
{
auto start = std::chrono::system_clock::now();
m_particle->propagate();
propRate = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start).count();
if (qPressed)
m_players[Player::Id::One]->move(Player::Direction::Up);
if (aPressed)
m_players[Player::Id::One]->move(Player::Direction::Down);
if (upPressed)
m_players[Player::Id::Two]->move(Player::Direction::Up);
if (downPressed)
m_players[Player::Id::Two]->move(Player::Direction::Down);
// Limit the speed of the simulation.
auto dt = std::chrono::system_clock::now() - start;
auto dtMillis = std::chrono::duration_cast<std::chrono::milliseconds>(dt).count();
constexpr int propTime = 6;
if (dtMillis < propTime)
{
std::this_thread::sleep_for(std::chrono::milliseconds(propTime - dtMillis));
}
}
while (propagating);
}
/// @brief This function has to run in its own thread an will redraw the canvas every ~25ms.
///
void render(QWindow *w)
{
do
{
using namespace std::chrono_literals;
auto start = std::chrono::system_clock::now();
std::this_thread::sleep_for(15ms);
w->updateView();
renderRate = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start).count();
} while (true);
}
QWindow::QWindow()
: m_button{"Initialise Particle"}
, m_label("Hi, you are playing QPong and this is a label!")
, m_scorePlayerOne("0")
, m_scorePlayerTwo("0")
{
set_border_width(5);
constexpr double playerOneStartX = -0.7;
constexpr double playerTwoStartX = 0.7;
m_players.insert(std::make_pair<Player::Id, std::shared_ptr<Player>>(Player::Id::One, std::make_shared<Player>(Player::Id::One, Player::Position{-0.7, 0})));
m_players.insert(std::make_pair<Player::Id, std::shared_ptr<Player>>(Player::Id::Two, std::make_shared<Player>(Player::Id::Two, Player::Position{ 0.7, 0.4})));
m_momentum = new ParticleImage;
m_position = new ParticleImage;
m_particle = new Particle(m_momentum, m_position, m_players);
add(m_box);
m_box.pack_start(m_vBox);
m_vBox.pack_start(m_button, Gtk::PACK_SHRINK);
m_vBox.pack_start(m_label, Gtk::PACK_SHRINK);
m_fpsBox.pack_start(m_renderRate, Gtk::PACK_EXPAND_WIDGET);
m_fpsBox.pack_start(m_proppergatingRate, Gtk::PACK_EXPAND_WIDGET);
m_vBox.pack_start(m_fpsBox, Gtk::PACK_SHRINK);
m_scoreBox.pack_start(m_scorePlayerOne, Gtk::PACK_EXPAND_WIDGET);
m_scoreBox.pack_start(m_scorePlayerTwo, Gtk::PACK_EXPAND_WIDGET);
m_vBox.pack_start(m_scoreBox, Gtk::PACK_SHRINK);
m_hBox.pack_start(m_positionArea, Gtk::PACK_EXPAND_WIDGET);
m_hBox.pack_start(m_momentumArea, Gtk::PACK_EXPAND_WIDGET);
m_vBox.pack_start(m_hBox);
m_label.set_margin_top(5);
m_label.set_margin_bottom(5);
m_proppergatingRate.set_text("0");
m_renderRate.set_text("0");
m_renderRate.set_margin_top(5);
m_renderRate.set_margin_bottom(5);
m_proppergatingRate.set_margin_top(5);
m_proppergatingRate.set_margin_bottom(5);
m_button.signal_clicked().connect(sigc::mem_fun(*this, &QWindow::onButtonPress));
this->signal_key_press_event().connect( sigc::mem_fun( *this, &QWindow::onKeyPress));
this->signal_key_release_event().connect(sigc::mem_fun(*this, &QWindow::onKeyPress));
m_guiDispatcher.connect(sigc::mem_fun(*this, &QWindow::updateGui));
m_areaDispatcher.connect(sigc::mem_fun(*this, &QWindow::updateImage));
while (m_particle->notReady())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
m_propagatingThread = std::thread(&QWindow::simulation, this);
m_propagatingThread.detach();
std::thread rendering(render, this);
rendering.detach();
m_box.show_all();
}
unsigned guiUpdates = 0;
void QWindow::updateGui()
{
guiUpdates++;
if (guiUpdates % 10 == 0)
{
std::stringstream ss;
ss << "image update rate: ";
ss << 1000 / renderRate;
m_renderRate.set_text(ss.str());
ss = std::stringstream();
ss << "simulation rate: ";
ss << 1000 / propRate;
m_proppergatingRate.set_text(ss.str());
ss = std::stringstream();
ss << "Score Player 1: ";
auto score = m_players[Player::Id::One]->getScore();
ss << std::setprecision(2) << std::setw(7) << score << "%";
if (score > 50.0)
{
ss << std::endl << "GEWONNEN!";
ss << std::endl << "Zum Neustarten Partikel neu initialisieren";
}
m_scorePlayerOne.set_text(ss.str());
ss = std::stringstream();
ss << "Score Player 2: ";
score = m_players[Player::Id::Two]->getScore();
ss << std::setprecision(2) << std::setw(7) << score << "%";
if (score > 50.0)
{
ss << std::endl << "GEWONNEN!";
ss << std::endl << "Zum Neustarten Partikel neu initialisieren";
}
m_scorePlayerTwo.set_text(ss.str());
}
}
bool QWindow::onKeyPress(GdkEventKey* event)
{
constexpr int q = 113;
constexpr int a = 97;
constexpr int ue = 252;
constexpr int oe = 246;
constexpr int p = 112;
constexpr int l = 108;
if (event->type == GdkEventType::GDK_KEY_PRESS)
{
if (event->keyval == q)
qPressed = true;
if (event->keyval == a)
aPressed = true;
if (event->keyval == p)
upPressed = true;
if (event->keyval == l)
downPressed = true;
}
else if (event->type == GdkEventType::GDK_KEY_RELEASE)
{
if (event->keyval == q)
qPressed = false;
if (event->keyval == a)
aPressed = false;
if (event->keyval == p)
upPressed = false;
if (event->keyval == l)
downPressed = false;
}
return true;
}
void QWindow::updateView()
{
m_areaDispatcher.emit();
m_guiDispatcher.emit();
}
void QWindow::updateImage()
{
m_positionArea.setPixbuf(m_position->getPixbuf());
m_momentumArea.setPixbuf(m_momentum->getPixbuf());
m_positionArea.redraw();
m_momentumArea.redraw();
}
void QWindow::onButtonPress()
{
propagating = false;
std::this_thread::sleep_for((std::chrono::seconds)1);
m_particle->initMomentum();
for (auto player : m_players)
{
player.second->reset();
}
m_propagatingThread = std::thread(&QWindow::simulation, this);
propagating = true;
m_propagatingThread.detach();
}
\ No newline at end of file
///
/// @file QWindow.hpp
/// @author Armin Co
///
#ifndef Q_WINDOW_HPP
#define Q_WINDOW_HPP
#include <thread>
#include <map>
#include <memory>
#include <gtkmm.h>
#include "Particle.hpp"
#include "ParticleImage.hpp"
#include "QDrawingArea.hpp"
/// @brief Definition of the QPong window
///
class QWindow : public Gtk::Window
{
public:
/// @brief Constructor of the window
///
QWindow();
/// @brief Virtual destructor of the window.
///
virtual ~QWindow(){}
/// @brief Sends a signal to GTK to update drawing areas.
void updateView();
protected:
/// @brief signal handlers
///
void onButtonPress();
bool onKeyPress(GdkEventKey* event);
private:
/// @brief Updates the QDrawingArea for position and momentum.
///
void updateImage();
/// @brief Update all labels from the gui.
///
void updateGui();
/// @brief Loop throug iteratins of the simulation
///
void simulation();
Gtk::Box m_box;
Gtk::VBox m_vBox;
Gtk::HBox m_hBox;
Gtk::Box m_fpsBox;
Gtk::Label m_label;
Gtk::Button m_button;
Gtk::Label m_renderRate;
Gtk::Label m_proppergatingRate;
Gtk::Box m_scoreBox;
Gtk::Label m_scorePlayerOne;
Gtk::Label m_scorePlayerTwo;
Glib::Dispatcher m_guiDispatcher;
Glib::Dispatcher m_areaDispatcher;
QDrawingArea m_positionArea;
QDrawingArea m_momentumArea;
QPong::Particle *m_particle;
std::thread m_propagatingThread;
ParticleImage *m_momentum;
ParticleImage *m_position;
ParticleImage *m_obstacle;
std::map<QPong::Player::Id, std::shared_ptr<QPong::Player>> m_players;
};
#endif
\ No newline at end of file
///
/// @file main.cpp
/// @author Armin Co
///
/// @brief The QPong game.
///
#include <iostream>
#include <thread>
#include <spdlog/spdlog.h>
#include <gtkmm.h>
#include "QWindow.hpp"
/// @brief MAIN
///
int main(int argc, char* argv[])
{
spdlog::info("QPong - Let's play quantum pong ;)");
spdlog::info("How To:");
spdlog::info("The bats of player one and two must be moved manually. They can be moved eather up or down.");
spdlog::info("Controls player 1:");
spdlog::info(" up: Q");
spdlog::info(" down: A");
spdlog::info("Controls player 2:");
spdlog::info(" up: P");
spdlog::info(" down: L");
std::cout << std::endl;
spdlog::info("starting in two seconds - get ready!");
spdlog::info("two restart the game: press 'enter', the 'space bar' or click the button 'Initialise Paritcle' with the mouse pointer.");
std::this_thread::sleep_for(std::chrono::seconds{2});
auto app = Gtk::Application::create(argc, argv, "de.armin-co.qpong");
QWindow window;
window.set_default_size(1920, 1080);
return app->run(window);
}
# Dear ImGui include dirs
include_directories(
../libs/imgui
../libs/imgui/examples
../libs/imgui/examples/libs/gl3w
)
# Main Dear ImGui src files.
set(
dear_im_gui_srcs
../libs/imgui/imgui.cpp
../libs/imgui/imgui_draw.cpp
../libs/imgui/imgui_widgets.cpp
)
# Impl files from Dear ImGui.
set(
dear_im_gui_impl_srcs
../libs/imgui/examples/imgui_impl_glfw.cpp
../libs/imgui/examples/imgui_impl_opengl3.cpp
)
# Dear ImGui lib
add_library(
dear_im_gui_glfw
${dear_im_gui_srcs}
${dear_im_gui_impl_srcs}
../libs/imgui/examples/libs/gl3w/GL/gl3w.c
)
# Application base on Dear ImGui
add_executable(
imgui_glfw_playground.app
imgui_glfw_playground.cpp
LoadShaders.cpp
)
add_custom_command(TARGET imgui_glfw_playground.app PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/imgui_glfw_app/shaders $<TARGET_FILE_DIR:imgui_glfw_playground.app>)
pkg_check_modules(GLFW glfw3)
include_directories(${GLFW_INCLUDE_DIRS})
message(${GLFW_LIBRARIES})
# Link everything together
target_link_libraries(
imgui_glfw_playground.app
dear_im_gui_glfw
qpong_core
${GLFW_LIBRARIES}
)
# Include macOS specific things.
if(APPLE)
# dependencies for macOS
# brew install glfw
# brew install glm
find_library(COCOA_LIBRARY Cocoa REQUIRED)
find_library(IOKIT_LIBRARY IOKit REQUIRED)
find_library(COREVID_LIBRARY CoreVideo REQUIRED)
find_library(OPENGL_LIBRARY OpenGL REQUIRED)
message(${COCOA_LIBRARY})
message(${IOKIT_LIBRARY})
message(${COREVID_LIBRARY})
message(${OPENGL_LIBRARY})
target_link_libraries(
imgui_glfw_playground.app
${COCOA_LIBRARY}
${IOKIT_LIBRARY}
${COREVID_LIBRARY}
${OPENGL_LIBRARY}
)
else(APPLE)
find_package(OpenGL REQUIRED)
target_link_libraries(imgui_glfw_playground.app OpenGL::GL ${CMAKE_DL_LIBS})
endif()
#include "LoadShaders.hpp"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <GL/gl3w.h>
unsigned int LoadShaders(const char * vertex_file_path,const char * fragment_file_path){
// Create the shaders
unsigned int VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
unsigned int FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
// Read the Vertex Shader code from the file
std::string VertexShaderCode;
std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
if(VertexShaderStream.is_open()){
std::stringstream sstr;
sstr << VertexShaderStream.rdbuf();
VertexShaderCode = sstr.str();
VertexShaderStream.close();
}else{
printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !\n", vertex_file_path);
getchar();
return 0;
}
// Read the Fragment Shader code from the file
std::string FragmentShaderCode;
std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
if(FragmentShaderStream.is_open()){
std::stringstream sstr;
sstr << FragmentShaderStream.rdbuf();
FragmentShaderCode = sstr.str();
FragmentShaderStream.close();
}
GLint Result = GL_FALSE;
int InfoLogLength;
// Compile Vertex Shader
printf("Compiling shader : %s\n", vertex_file_path);
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID);
// Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> VertexShaderErrorMessage(InfoLogLength+1);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
printf("%s\n", &VertexShaderErrorMessage[0]);
}
// Compile Fragment Shader
printf("Compiling shader : %s\n", fragment_file_path);
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
glCompileShader(FragmentShaderID);
// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
printf("%s\n", &FragmentShaderErrorMessage[0]);
}
// Link the program
printf("Linking program\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> ProgramErrorMessage(InfoLogLength+1);
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
printf("%s\n", &ProgramErrorMessage[0]);
}
glDetachShader(ProgramID, VertexShaderID);
glDetachShader(ProgramID, FragmentShaderID);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
return ProgramID;
}
/// @brief LoadShader from filesystem.
///
/// @param vertex_file_path Path to the vertex shader file
/// @param fragment_file_path Path to the fragment shader file
/// @return Returns the id of the shader
///
unsigned int LoadShaders(const char * vertex_file_path,const char * fragment_file_path);
\ No newline at end of file
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
#include <stdio.h>
#include <GL/gl3w.h> // Initialize with gl3wInit()
#include <GLFW/glfw3.h>
#include <iostream>
#include "LoadShaders.hpp"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
static void glfw_error_callback(int error, const char* description)
{
fprintf(stderr, "Glfw Error %d: %s\n", error, description);
}
void drawGui()
{
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
static float f = 0.0f;
static int counter = 0;
ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")){ // Buttons return true when clicked (most widgets return true when edited/activated)
counter++;
}
ImGui::SameLine();
ImGui::Text("counter = %d", counter);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::End();
}
int main(int, char**)
{
// Setup window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
return 1;
// Decide GL+GLSL versions
#if __APPLE__
// GL 3.2 + GLSL 150
const char* glsl_version = "#version 150";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
#else
// GL 3.0 + GLSL 130
const char* glsl_version = "#version 130";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
#endif
// Create window with graphics context
GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+OpenGL3 example", NULL, NULL);
if (window == NULL)
return 1;
glfwMakeContextCurrent(window);
glfwSwapInterval(1); // Enable vsync
// Initialize OpenGL loader
bool err = gl3wInit() != 0;
if (err)
{
fprintf(stderr, "Failed to initialize OpenGL loader!\n");
return 1;
}
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
// Setup Dear ImGui style
ImGui::StyleColorsDark();
// Setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init(glsl_version);
// unsigned int vertexArrayId {}; // Store a vertex array id.
// glGenVertexArrays(1, &vertexArrayId); // Receive a id.
// glBindVertexArray(vertexArrayId); // Bind that id.
static const float g_vertex_buffer_data_triangle[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
static GLfloat g_color_buffer_data_triangle[12*3*3];
for (int v = 0; v < 12*3 ; v++){
g_color_buffer_data_triangle[3*v+0] = 0.1f;
g_color_buffer_data_triangle[3*v+1] = 0.5f;
g_color_buffer_data_triangle[3*v+2] = 0.7f;
}
static const GLfloat g_vertex_buffer_data_cube[] = {
-1.0f,-1.0f,-1.0f, // triangle 1 : begin
-1.0f,-1.0f, 1.0f,
-1.0f, 1.0f, 1.0f, // triangle 1 : end
1.0f, 1.0f,-1.0f, // triangle 2 : begin
-1.0f,-1.0f,-1.0f,
-1.0f, 1.0f,-1.0f, // triangle 2 : end
1.0f,-1.0f, 1.0f,
-1.0f,-1.0f,-1.0f,
1.0f,-1.0f,-1.0f,
1.0f, 1.0f,-1.0f,
1.0f,-1.0f,-1.0f,
-1.0f,-1.0f,-1.0f,
-1.0f,-1.0f,-1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f,-1.0f,
1.0f,-1.0f, 1.0f,
-1.0f,-1.0f, 1.0f,
-1.0f,-1.0f,-1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f,-1.0f, 1.0f,
1.0f,-1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f,-1.0f,-1.0f,
1.0f, 1.0f,-1.0f,
1.0f,-1.0f,-1.0f,
1.0f, 1.0f, 1.0f,
1.0f,-1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f,-1.0f,
-1.0f, 1.0f,-1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f,-1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
1.0f,-1.0f, 1.0f
};
static const GLfloat g_color_buffer_data_cube[] = {
0.583f, 0.771f, 0.014f,
0.609f, 0.115f, 0.436f,
0.327f, 0.483f, 0.844f,
0.822f, 0.569f, 0.201f,
0.435f, 0.602f, 0.223f,
0.310f, 0.747f, 0.185f,
0.597f, 0.770f, 0.761f,
0.559f, 0.436f, 0.730f,
0.359f, 0.583f, 0.152f,
0.483f, 0.596f, 0.789f,
0.559f, 0.861f, 0.639f,
0.195f, 0.548f, 0.859f,
0.014f, 0.184f, 0.576f,
0.771f, 0.328f, 0.970f,
0.406f, 0.615f, 0.116f,
0.676f, 0.977f, 0.133f,
0.971f, 0.572f, 0.833f,
0.140f, 0.616f, 0.489f,
0.997f, 0.513f, 0.064f,
0.945f, 0.719f, 0.592f,
0.543f, 0.021f, 0.978f,
0.279f, 0.317f, 0.505f,
0.167f, 0.620f, 0.077f,
0.347f, 0.857f, 0.137f,
0.055f, 0.953f, 0.042f,
0.714f, 0.505f, 0.345f,
0.783f, 0.290f, 0.734f,
0.722f, 0.645f, 0.174f,
0.302f, 0.455f, 0.848f,
0.225f, 0.587f, 0.040f,
0.517f, 0.713f, 0.338f,
0.053f, 0.959f, 0.120f,
0.393f, 0.621f, 0.362f,
0.673f, 0.211f, 0.457f,
0.820f, 0.883f, 0.371f,
0.982f, 0.099f, 0.879f
};
unsigned int vertexBufferCube {};
glGenBuffers(1, &vertexBufferCube);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferCube);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data_cube), g_vertex_buffer_data_cube, GL_STATIC_DRAW);
unsigned int colorBufferCube {};
glGenBuffers(1, &colorBufferCube);
glBindBuffer(GL_ARRAY_BUFFER, colorBufferCube);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data_cube), g_color_buffer_data_cube, GL_STATIC_DRAW);
unsigned int vertexBufferTriangle {};
glGenBuffers(1, &vertexBufferTriangle);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferTriangle);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data_triangle), g_vertex_buffer_data_triangle, GL_STATIC_DRAW);
unsigned int colorBufferTriangle {};
glGenBuffers(1, &colorBufferTriangle);
glBindBuffer(GL_ARRAY_BUFFER, colorBufferTriangle);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data_triangle), g_color_buffer_data_triangle, GL_STATIC_DRAW);
unsigned int shaderId = LoadShaders("SimpleVertexShader.glsl", "FragmentShader.glsl");
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
int width, height;
glfwGetFramebufferSize(window, &width, &height);
// Projection matrix : 45° Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
glm::mat4 Projection = glm::perspective(glm::radians(150.0f), (float) width / (float)height, 0.1f, 100.0f);
glm::mat4 ProjectionTriangle = glm::perspective(glm::radians(30.0f), (float) width / (float)height, 0.1f, 100.0f);
// Camera matrix
glm::mat4 View = glm::lookAt(
glm::vec3(4,3,3), // Camera is at (4,3,3), in World Space
glm::vec3(0,0,0), // and looks at the origin
glm::vec3(0,1,0) // Head is up (set to 0,-1,0 to look upside-down)
);
// Model matrix : an identity matrix (model will be at the origin)
glm::mat4 Model = glm::mat4(1.0f);
// Our ModelViewProjection : multiplication of our 3 matrices
glm::mat4 mvp = Projection * View * Model; // Remember, matrix multiplication is the other way around
glm::mat4 mvpTriangle = ProjectionTriangle * View * Model;
// Get a handle for our "MVP" uniform
// Only during the initialisation
// GLuint MatrixID = glGetUniformLocation(shaderId, "MVP");
// GLuint MatrixIDT = glGetUniformLocation(shaderId, "MVPT");
unsigned int MatrixIDCube = glGetUniformLocation(shaderId, "MVP");
unsigned int MatrixIDTriangle = glGetUniformLocation(shaderId, "MVPT");
// Main loop
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// Draw GUI with Dear ImGui.
drawGui();
// Rendering
ImGui::Render();
{
// int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
glClearColor(0.1f, 0.2f, 0.2f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Send our transformation to the currently bound shader, in the "MVP" uniform
// This is done in the main loop since each model will have a different MVP matrix (At least for the M part)
glUniformMatrix4fv(MatrixIDCube, 1, GL_FALSE, &mvp[0][0]);
glUseProgram(shaderId);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferCube);
glVertexAttribPointer(
0,
3,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colorBufferCube);
glVertexAttribPointer(
1,
3,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
// glUniformMatrix4fv(MatrixIDCube, 1, GL_FALSE, &mvp[0][0]);
glDrawArrays(GL_TRIANGLES, 0, sizeof(g_vertex_buffer_data_cube)/3);
// glDisableVertexAttribArray(0);
// glDisableVertexAttribArray(1);
// glUniformMatrix4fv(MatrixIDTriangle, 1, GL_FALSE, &mvpTriangle[0][0]);
// glUseProgram(shaderId);
// glEnableVertexAttribArray(0);
// glBindBuffer(GL_ARRAY_BUFFER, vertexBufferTriangle);
// glVertexAttribPointer(
// 0,
// 3,
// GL_FLOAT,
// GL_FALSE,
// 0,
// (void*)0
// );
// glEnableVertexAttribArray(1);
// glBindBuffer(GL_ARRAY_BUFFER, colorBufferTriangle);
// glVertexAttribPointer(
// 1,
// 3,
// GL_FLOAT,
// GL_FALSE,
// 0,
// (void*)0
// );
// glDrawArrays(GL_TRIANGLES, 0, sizeof(g_vertex_buffer_data_triangle)/3);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
}
// Cleanup
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
#version 330
in vec3 fragmentColor;
out vec3 outColor;
void main(){
outColor = fragmentColor;
}
\ No newline at end of file
#version 330 core
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec3 vertexColor;
out vec3 fragmentColor;
uniform mat4 MVP;
void main(){
gl_Position = MVP * vec4(vertexPosition_modelspace, 1);
fragmentColor = vertexColor;
}
\ No newline at end of file
# Dear ImGui include dirs
include_directories(
../libs/imgui
../libs/imgui/examples
../libs/imgui/examples/libs/gl3w
)
# Main Dear ImGui src files.
set(
dear_im_gui_srcs
../libs/imgui/imgui.cpp
../libs/imgui/imgui_draw.cpp
../libs/imgui/imgui_widgets.cpp
)
# Impl files from Dear ImGui.
set(
dear_im_gui_impl_srcs
../libs/imgui/examples/imgui_impl_sdl.cpp
../libs/imgui/examples/imgui_impl_opengl3.cpp
)
# Dear ImGui lib
add_library(
dear_im_gui
${dear_im_gui_srcs}
${dear_im_gui_impl_srcs}
../libs/imgui/examples/libs/gl3w/GL/gl3w.c
)
# Application base on Dear ImGui
add_executable(
imgui_playground.app
imgui_playground.cpp
)
# Add all SDL2 dependencies.
find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIRS})
# Link everything together
target_link_libraries(
imgui_playground.app
dear_im_gui
${SDL2_LIBRARIES}
qpong_core
)
# Include macOS specific things.
if(APPLE)
find_library(COCOA_LIBRARY Cocoa REQUIRED)
find_library(IOKIT_LIBRARY IOKit REQUIRED)
find_library(COREVID_LIBRARY CoreVideo REQUIRED)
message(${COCOA_LIBRARY})
message(${IOKIT_LIBRARY})
message(${COREVID_LIBRARY})
target_link_libraries(
imgui_playground.app
${COCOA_LIBRARY}
${IOKIT_LIBRARY}
${COREVID_LIBRARY}
)
else(APPLE)
find_package(OpenGL REQUIRED)
target_link_libraries(imgui_playground.app OpenGL::GL ${CMAKE_DL_LIBS})
endif()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment