Giter Club home page Giter Club logo

glfw-cpp's Introduction

glfw-cpp

A C++ wrapper for GLFW with RAII support and with multi-window and multithreading in mind.

This wrapper is personalized and written to suit my needs. This is not a wrapper that is a one-to-one "port" of glfw C-API to C++ API. This repository will be updated iteratively as needed. I mainly use this repository to facilitate my graphics programming project that requires painless window management. You can see my projects here:

TODO

  • Add event queue mechanism in addition to callback on input handling per window (see)
  • Handle GLFW internal error
    • GLFW internal errors are mainly occurs from invalid enumeration passed into a function, invalid value for an enum passed into a function, and failure in maintaining invariants (like GLFW is initialized or not).
    • This library is a C++ library so errors from passing invalid enumeration and/or invalid value for an enum is avoided by using the stricter type-system of C++.
    • This library also is trying it's best in maintaining the invariants so hopefully the errors that surface from these are also avoided.
    • That leaves out platform-related errors which I can report easily as exceptions.
  • Add the ability to handle window events in separate thread from Window and WindowManager
  • Eliminate glfw_cpp::WindowManager move limitation

Dependencies

  • C++20
  • GLFW 3.3

You can use your system package manager or c++ package manager like conan (see example) or even manually clone the GLFW repository and call add_subdirectory to add the GLFW dependency.

Usage

Setting up

You can clone this repository (or add as submodule) inside your project. I recommend using FetchContent though as it is easier to do.

# If you are using FetchContent
include(FetchContent)
FetchContent_Declare(
  glfw-cpp
  GIT_REPOSITORY https://github.com/mrizaln/glfw-cpp
  GIT_TAG main)

# set this variable to ON to enable Vulkan support (requires Vulkan loader and headers)
option(GLFW_CPP_VULKAN_SUPPORT "vulkan support" ON)
FetchContent_MakeAvailable(glfw-cpp)

# # If you clone/submodule the repository
# add_subdirectory(path/to/the/cloned/repository)

add_executable(main main.cpp)
target_link_libraries(main PRIVATE glfw-cpp)  # you don't need to link to glfw here, glfw-cpp already link to it

Option

This library supports Vulkan, just set GLFW_CPP_VULKAN_SUPPORT before adding this repository to the project to enable it. Note that it requires Vulkan loader and the headers to compile.

Example

Using this library is as simple as

single.cpp

#include <glad/glad.h>
#include <glfw_cpp/glfw_cpp.hpp>

#include <iostream>
#include <cmath>

namespace glfw = glfw_cpp;

int main()
{
    // init() calls glfwInit() internally and Instance::Handle will call glfwTerminate() on dtor.
    // Note that the graphics API can't be changed later, this is a design choice.
    glfw::Instance::Handle instance = glfw::init(glfw::Api::OpenGL{
        .m_major   = 3,
        .m_minor   = 3,
        .m_profile = glfw::Api::OpenGL::Profile::CORE,
        .m_loader  = [](glfw::Api::GlContext /* handle */,
                       glfw::Api::GlGetProc proc) { gladLoadGLLoader((GLADloadproc)proc); },
    });

    // WindowManager is responsible for managing windows (think of window group)
    glfw::WindowManager wm = instance->createWindowManager();

    // graphics API hints are omitted from the WindowHint, only other relevant hints are included.
    glfw::WindowHint hint = {};    // use default hint

    glfw::Window window = wm.createWindow(hint, "Learn glfw-cpp", 800, 600);

    window.run([&, elapsed = 0.0F](const glfw::EventQueue& events) mutable {
        // events
        for (const glfw::Event& event : events) {
            if (auto* e = event.getIf<glfw::Event::KeyPressed>()) {
                if (e->m_key == glfw::KeyCode::Q) {
                    window.requestClose();
                }
            } else if (auto* e = event.getIf<glfw::Event::FramebufferResized>()) {
                glViewport(0, 0, e->m_width, e->m_height);
            }
        }

        // continuous key input (for movement for example)
        {
            using K          = glfw::KeyCode;
            const auto& keys = window.properties().m_keyState;

            if (keys.allPressed({ K::H, K::J, K::L, K::K })) {
                std::cout << "HJKL key pressed all at once";
            }

            if (keys.isPressed(K::LEFT_SHIFT) && keys.anyPressed({ K::W, K::A, K::S, K::D })) {
                std::cout << "WASD key pressed with shift key being held";
            } else if (keys.anyPressed({ K::W, K::A, K::S, K::D })) {
                std::cout << "WASD key pressed";
            }
        }

        elapsed += static_cast<float>(window.deltaTime());

        // funny color cycle
        const float r = (std::sin(23.0F / 8.0F * elapsed) + 1.0F) * 0.1F + 0.4F;
        const float g = (std::cos(13.0F / 8.0F * elapsed) + 1.0F) * 0.2F + 0.3F;
        const float b = (std::sin(41.0F / 8.0F * elapsed) + 1.5F) * 0.2F;

        glClearColor(r, g, b, 1.0F);
        glClear(GL_COLOR_BUFFER_BIT);

        wm.pollEvents();
    });
}

No manual cleanup necessary, the classes defined already using RAII pattern.

One thing to keep in mind is that you need to make sure that glfw_cpp::Instance::Handle outlive glfw_cpp::WindowManager and glfw_cpp::WindowManager outlive glfw_cpp::Windows in order for the program to be well defined and not crashing.

The above example is a single-threaded, one window example. For a multi-window and multithreaded example, you can see here or here directory (I also use a different OpenGL loader library there).

Limitation

One limitation is that glfw_cpp::WindowManager should not be moved after it created glfw_cpp::Windows since each window created from it has a pointer to the glfw_cpp::WindowManager. If you are doing that it may leads to undefined behavior (dereferencing a pointer to a destroyed glfw_cpp::WindowManager for example). If the glfw_cpp::WindowManager hasn't created any glfw_cpp::Windows (or they are already destroyed) it is okay to move it.

glfw-cpp's People

Contributors

mrizaln avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.