Single-header single-function C/C++ immediate-mode camera for your graphics demos

Overview

flythrough_camera

demonstration

Single-header single-function C/C++ immediate-mode camera for your graphics demos

Just call flythrough_camera_update once per frame.

Simple Example

Below is a fully-functional example program that works under command prompt.

Create a new Visual Studio project, drop this file in it, and it should just work.

#include int main() { printf("flythrough_camera test:\n"); printf("hold right click, then move the mouse and press WASD/space/left ctrl\n"); float pos[3] = { 0.0f, 0.0f, 0.0f }; float look[3] = { 0.0f, 0.0f, 1.0f }; const float up[3] = { 0.0f, 1.0f, 0.0f }; LARGE_INTEGER then, now, freq; QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&then); POINT oldcursor; GetCursorPos(&oldcursor); while (!GetAsyncKeyState(VK_ESCAPE)) { QueryPerformanceCounter(&now); float delta_time_sec = (float)(now.QuadPart - then.QuadPart) / freq.QuadPart; POINT cursor; GetCursorPos(&cursor); // only move and rotate camera when right mouse button is pressed float activated = GetAsyncKeyState(VK_RBUTTON) ? 1.0f : 0.0f; float view[16]; flythrough_camera_update( pos, look, up, view, delta_time_sec, 100.0f * (GetAsyncKeyState(VK_LSHIFT) ? 2.0f : 1.0f) * activated, 0.5f * activated, 80.0f, cursor.x - oldcursor.x, cursor.y - oldcursor.y, GetAsyncKeyState('W'), GetAsyncKeyState('A'), GetAsyncKeyState('S'), GetAsyncKeyState('D'), GetAsyncKeyState(VK_SPACE), GetAsyncKeyState(VK_LCONTROL), FLYTHROUGH_CAMERA_LEFT_HANDED_BIT); if (activated) { printf("\n"); printf("pos: %f, %f, %f\n", pos[0], pos[1], pos[2]); printf("look: %f, %f, %f\n", look[0], look[1], look[2]); printf("view: %f %f %f %f\n" " %f %f %f %f\n" " %f %f %f %f\n" " %f %f %f %f\n", view[0], view[1], view[2], view[3], view[4], view[5], view[6], view[7], view[8], view[9], view[10], view[11], view[12], view[13], view[14], view[15]); Sleep(100); } then = now; oldcursor = cursor; } return 0; }">
#define FLYTHROUGH_CAMERA_IMPLEMENTATION
#include "flythrough_camera.h"

#include 
    
     
#include 
     
      

int main()
{
    printf("flythrough_camera test:\n");
    printf("hold right click, then move the mouse and press WASD/space/left ctrl\n");

    float pos[3] = { 0.0f, 0.0f, 0.0f };
    float look[3] = { 0.0f, 0.0f, 1.0f };
    const float up[3] = { 0.0f, 1.0f, 0.0f };

    LARGE_INTEGER then, now, freq;
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&then);

    POINT oldcursor;
    GetCursorPos(&oldcursor);

    while (!GetAsyncKeyState(VK_ESCAPE))
    {
        QueryPerformanceCounter(&now);
        float delta_time_sec = (float)(now.QuadPart - then.QuadPart) / freq.QuadPart;

        POINT cursor;
        GetCursorPos(&cursor);

        // only move and rotate camera when right mouse button is pressed
        float activated = GetAsyncKeyState(VK_RBUTTON) ? 1.0f : 0.0f;

        float view[16];
        flythrough_camera_update(
            pos, look, up, view,
            delta_time_sec,
            100.0f * (GetAsyncKeyState(VK_LSHIFT) ? 2.0f : 1.0f) * activated,
            0.5f * activated,
            80.0f,
            cursor.x - oldcursor.x, cursor.y - oldcursor.y,
            GetAsyncKeyState('W'), GetAsyncKeyState('A'), GetAsyncKeyState('S'), GetAsyncKeyState('D'),
            GetAsyncKeyState(VK_SPACE), GetAsyncKeyState(VK_LCONTROL),
            FLYTHROUGH_CAMERA_LEFT_HANDED_BIT);

        if (activated)
        {
            printf("\n");
            printf("pos: %f, %f, %f\n", pos[0], pos[1], pos[2]);
            printf("look: %f, %f, %f\n", look[0], look[1], look[2]);
            printf("view: %f %f %f %f\n"
                   "      %f %f %f %f\n"
                   "      %f %f %f %f\n"
                   "      %f %f %f %f\n",
                 view[0],  view[1],  view[2],  view[3],
                 view[4],  view[5],  view[6],  view[7],
                 view[8],  view[9], view[10], view[11],
                view[12], view[13], view[14], view[15]);
            
            Sleep(100);
        }

        then = now;
        oldcursor = cursor;
    }

    return 0;
}

     
    

OpenGL Example

openglexample

Below is a fully-functional example program that works using OpenGL.

Create a new Visual Studio project, drop this file in it, and it should just work.

#include #include #include #pragma comment(lib, "OpenGL32.lib") #pragma comment(lib, "glu32.lib") LRESULT CALLBACK MyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CLOSE: ExitProcess(0); default: return DefWindowProc(hWnd, message, wParam, lParam); } } int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { printf("flythrough_camera test:\n"); printf("hold right click, then move the mouse and press WASD/space/left ctrl\n"); WNDCLASSEX wc; ZeroMemory(&wc, sizeof(wc)); wc.cbSize = sizeof(wc); wc.style = CS_OWNDC; wc.lpfnWndProc = MyWndProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND; wc.lpszClassName = TEXT("WindowClass"); RegisterClassEx(&wc); RECT wr = { 0, 0, 640, 480 }; AdjustWindowRect(&wr, 0, FALSE); HWND hWnd = CreateWindowEx( 0, TEXT("WindowClass"), TEXT("BasicGL"), WS_OVERLAPPEDWINDOW, 0, 0, wr.right - wr.left, wr.bottom - wr.top, 0, 0, hInstance, 0); PIXELFORMATDESCRIPTOR pfd; ZeroMemory(&pfd, sizeof(pfd)); pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 32; pfd.cDepthBits = 24; pfd.cStencilBits = 8; pfd.iLayerType = PFD_MAIN_PLANE; HDC hDC = GetDC(hWnd); int chosenPixelFormat = ChoosePixelFormat(hDC, &pfd); SetPixelFormat(hDC, chosenPixelFormat, &pfd); HGLRC hGLRC = wglCreateContext(hDC); wglMakeCurrent(hDC, hGLRC); ShowWindow(hWnd, SW_SHOWNORMAL); float pos[3] = { 0.0f, 0.0f, 0.0f }; float look[3] = { 0.0f, 0.0f, 1.0f }; const float up[3] = { 0.0f, 1.0f, 0.0f }; LARGE_INTEGER then, now, freq; QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&then); POINT oldcursor; GetCursorPos(&oldcursor); while (!GetAsyncKeyState(VK_ESCAPE)) { MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } QueryPerformanceCounter(&now); float delta_time_sec = (float)(now.QuadPart - then.QuadPart) / freq.QuadPart; POINT cursor; GetCursorPos(&cursor); // only move and rotate camera when right mouse button is pressed float activated = GetAsyncKeyState(VK_RBUTTON) ? 1.0f : 0.0f; float view[16]; flythrough_camera_update( pos, look, up, view, delta_time_sec, 10.0f * (GetAsyncKeyState(VK_LSHIFT) ? 2.0f : 1.0f) * activated, 0.5f * activated, 80.0f, cursor.x - oldcursor.x, cursor.y - oldcursor.y, GetAsyncKeyState('W'), GetAsyncKeyState('A'), GetAsyncKeyState('S'), GetAsyncKeyState('D'), GetAsyncKeyState(VK_SPACE), GetAsyncKeyState(VK_LCONTROL), 0); if (activated) { printf("\n"); printf("pos: %f, %f, %f\n", pos[0], pos[1], pos[2]); printf("look: %f, %f, %f\n", look[0], look[1], look[2]); printf("view: %f %f %f %f\n" " %f %f %f %f\n" " %f %f %f %f\n" " %f %f %f %f\n", view[0], view[1], view[2], view[3], view[4], view[5], view[6], view[7], view[8], view[9], view[10], view[11], view[12], view[13], view[14], view[15]); } glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(70.0, (double)(wr.right - wr.left) / (wr.bottom - wr.top), 0.001, 100.0); glMatrixMode(GL_MODELVIEW); glLoadMatrixf(view); glBegin(GL_TRIANGLES); glColor3ub(255, 0, 0); glVertex3f(-1.0f, -1.0f, 10.0f); glColor3ub(0, 255, 0); glVertex3f(1.0f, -1.0f, 10.0f); glColor3ub(0, 0, 255); glVertex3f(0.0f, 1.0f, 10.0f); glEnd(); SwapBuffers(hDC); then = now; oldcursor = cursor; } return 0; }">
#define FLYTHROUGH_CAMERA_IMPLEMENTATION
#include "flythrough_camera.h"

#include 
      
       
#include 
       
        
#include 
        
         
#include 
         
          

#pragma comment(lib, "OpenGL32.lib")
#pragma comment(lib, "glu32.lib")

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CLOSE:
        ExitProcess(0);
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
}

int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    printf("flythrough_camera test:\n");
    printf("hold right click, then move the mouse and press WASD/space/left ctrl\n");
    
    WNDCLASSEX wc;
    ZeroMemory(&wc, sizeof(wc));
    wc.cbSize = sizeof(wc);
    wc.style = CS_OWNDC;
    wc.lpfnWndProc = MyWndProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
    wc.lpszClassName = TEXT("WindowClass");
    RegisterClassEx(&wc);

    RECT wr = { 0, 0, 640, 480 };
    AdjustWindowRect(&wr, 0, FALSE);
    HWND hWnd = CreateWindowEx(
        0, TEXT("WindowClass"),
        TEXT("BasicGL"),
        WS_OVERLAPPEDWINDOW,
        0, 0, wr.right - wr.left, wr.bottom - wr.top,
        0, 0, hInstance, 0);

    PIXELFORMATDESCRIPTOR pfd;
    ZeroMemory(&pfd, sizeof(pfd));
    pfd.nSize = sizeof(pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 32;
    pfd.cDepthBits = 24;
    pfd.cStencilBits = 8;
    pfd.iLayerType = PFD_MAIN_PLANE;

    HDC hDC = GetDC(hWnd);

    int chosenPixelFormat = ChoosePixelFormat(hDC, &pfd);
    SetPixelFormat(hDC, chosenPixelFormat, &pfd);

    HGLRC hGLRC = wglCreateContext(hDC);
    wglMakeCurrent(hDC, hGLRC);

    ShowWindow(hWnd, SW_SHOWNORMAL);

    float pos[3] = { 0.0f, 0.0f, 0.0f };
    float look[3] = { 0.0f, 0.0f, 1.0f };
    const float up[3] = { 0.0f, 1.0f, 0.0f };

    LARGE_INTEGER then, now, freq;
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&then);

    POINT oldcursor;
    GetCursorPos(&oldcursor);

    while (!GetAsyncKeyState(VK_ESCAPE))
    {
        MSG msg;
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        QueryPerformanceCounter(&now);
        float delta_time_sec = (float)(now.QuadPart - then.QuadPart) / freq.QuadPart;

        POINT cursor;
        GetCursorPos(&cursor);

        // only move and rotate camera when right mouse button is pressed
        float activated = GetAsyncKeyState(VK_RBUTTON) ? 1.0f : 0.0f;

        float view[16];
        flythrough_camera_update(
            pos, look, up, view,
            delta_time_sec,
            10.0f * (GetAsyncKeyState(VK_LSHIFT) ? 2.0f : 1.0f) * activated,
            0.5f * activated,
            80.0f,
            cursor.x - oldcursor.x, cursor.y - oldcursor.y,
            GetAsyncKeyState('W'), GetAsyncKeyState('A'), GetAsyncKeyState('S'), GetAsyncKeyState('D'),
            GetAsyncKeyState(VK_SPACE), GetAsyncKeyState(VK_LCONTROL),
            0);

        if (activated)
        {
            printf("\n");
            printf("pos: %f, %f, %f\n", pos[0], pos[1], pos[2]);
            printf("look: %f, %f, %f\n", look[0], look[1], look[2]);
            printf("view: %f %f %f %f\n"
                   "      %f %f %f %f\n"
                   "      %f %f %f %f\n"
                   "      %f %f %f %f\n",
                 view[0],  view[1],  view[2],  view[3],
                 view[4],  view[5],  view[6],  view[7],
                 view[8],  view[9], view[10], view[11],
                view[12], view[13], view[14], view[15]);
        }

        glClear(GL_COLOR_BUFFER_BIT);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(70.0, (double)(wr.right - wr.left) / (wr.bottom - wr.top), 0.001, 100.0);

        glMatrixMode(GL_MODELVIEW);
        glLoadMatrixf(view);

        glBegin(GL_TRIANGLES);
        glColor3ub(255, 0, 0);
        glVertex3f(-1.0f, -1.0f, 10.0f);
        glColor3ub(0, 255, 0);
        glVertex3f(1.0f, -1.0f, 10.0f);
        glColor3ub(0, 0, 255);
        glVertex3f(0.0f, 1.0f, 10.0f);
        glEnd();

        SwapBuffers(hDC);

        then = now;
        oldcursor = cursor;
    }

    return 0;
}

         
        
       
      
You might also like...
Event Camera Calibration

Event Camera Calibration 'modules/camera_calibration/cv_calib' is the conventional camera calibration module. 'modules/camera_calibration/dbscan' is t

Basic framework for D3D11 init, model/texture loading, shader compilation and camera movement.

reed-framework Basic framework for D3D11 init, model/texture loading, camera movement, etc. Instructions: #include framework.h Link with framework.l

Easily view the unexplored korok seeds and locations in your BotW savefile on your Switch
Easily view the unexplored korok seeds and locations in your BotW savefile on your Switch

BotW Unexplored Easily view what hasn't been discovered in your Breath of the Wild savefile, on your Nintendo Switch. The korok seeds that haven't bee

Single header C library for rendering truetype text to the screen
Single header C library for rendering truetype text to the screen

kc_truetypeassembler.h Single header C library for assembling textured quads for text rendering using a graphics API. It generates a vertices and text

This is a single-header, multithreaded C++ library for simulating the effect of hydraulic erosion on height maps.
This is a single-header, multithreaded C++ library for simulating the effect of hydraulic erosion on height maps.

TinyErode This is a single-header, multithreaded C++ library for simulating the effect of hydraulic erosion on height maps. The algorithm is based on

A modern, feature-rich single header C++ interface system for GLFW
A modern, feature-rich single header C++ interface system for GLFW

A modern, feature-rich single header C++ interface system for GLFW

Single header KTX/DDS reader

dds-ktx: Portable single header DDS/KTX reader for C/C++ @septag Parses from memory blob. No allocations No dependencies Single-header for easy integr

Epoxy is a library for handling OpenGL function pointer management for you

Epoxy is a library for handling OpenGL function pointer management for you. It hides the complexity of dlopen(), dlsym(), glXGetProcAddress(), eglGetP

A C++ port of Wave Function Collapse Tiling

Wave Function Collapse in C++ This is a C++ port of https://github.com/mxgmn/WaveFunctionCollapse. All sample images come from https://github.com/mxgm

Owner
Nicolas Guillemot
Nicolas Guillemot
An immediate-mode, renderer agnostic, lightweight debug drawing API for C++

Debug Draw An immediate-mode, renderer agnostic, lightweight debug drawing API for C++. License This software is in the public domain. Where that dedi

Guilherme Lampert 457 Dec 24, 2022
Im3d is a small, self-contained library for immediate mode rendering of basic primitives

Im3d is a small, self-contained library for immediate mode rendering of basic primitives (points, lines, triangles), plus an immediate mode UI which provides 3d manipulation 'gizmos' and other tools. It is platform and graphics API agnostic and designed to be compatible with VR.

John Chapman 835 Jan 2, 2023
This Project Implement an interactive camera for 3D model using Quaternion. It have some advantages over eulerian camera like no gimbal lock and faster to compute.

Quaternion-Camera This Project Implement an interactive camera for 3D model using Quaternion. It have some advantages over eulerian camera like no gim

Phan Sang 8 Nov 10, 2022
Low Level Graphics Library (LLGL) is a thin abstraction layer for the modern graphics APIs OpenGL, Direct3D, Vulkan, and Metal

Low Level Graphics Library (LLGL) Documentation NOTE: This repository receives bug fixes only, but no major updates. Pull requests may still be accept

Lukas Hermanns 1.5k Jan 8, 2023
A terminal-based graphics library for both 2D and 3D graphics.

TermGL A terminal-based graphics library for both 2D and 3D graphics. Written in C, created for terminals supporting ANSI escape codes. Table of Conte

null 215 Dec 28, 2022
kaun is a replacement for löve's built-in love.graphics module intended for 3D graphics

kaun kaun is a replacement for löve's built-in love.graphics module intended for 3D graphics. It is a Lua module you can require from a shared library

Joel Schumacher 4 Apr 5, 2021
This repo contains the DirectX Graphics samples that demonstrate how to build graphics intensive applications on Windows.

DirectX-Graphics-Samples This repo contains the DirectX 12 Graphics samples that demonstrate how to build graphics intensive applications for Windows

Microsoft 4.9k Dec 26, 2022
Cross-platform, graphics API agnostic, "Bring Your Own Engine/Framework" style rendering library.

bgfx - Cross-platform rendering library GitHub Discussions Discord Chat What is it? Cross-platform, graphics API agnostic, "Bring Your Own Engine/Fram

Бранимир Караџић 12.6k Jan 8, 2023
A minimal Direct3D 12 example that draws an animated triangle, written entirely in C-style C++, and all taking place inside a single function.

A minimal Direct3D 12 example that draws an animated triangle, written entirely in C-style C++, and all taking place inside a single function.

Taoufik Rida Bouftass 7 May 3, 2022
A 3D Printable Retro-style Raspberry Pi HQ Camera

3D Printable Retro-style Raspberry Pi HQ Camera

Ping-Hsun 416 Jan 4, 2023