Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to adapt native OpenGL code with native Camera capture to Magnum, ImGui, MagnumGL. #58

Closed
al-sabr opened this issue Mar 22, 2019 · 1 comment

Comments

@al-sabr
Copy link

al-sabr commented Mar 22, 2019

Greeting @mosra I found an amazing code which wraps Camera capture and there is an example with OpenGL displaying the raw data coming from the camera.

Since I don't know yet how to integrate OpenGL, Magnum, and display all of above inside of ImGui I'm wondering if you can give me some guidance.

This is the original code : https://www.codeproject.com/Articles/776058/Capturing-Live-video-from-Web-camera-on-Windows-an`

The part which interests me is Update on VS2013Express for Desktop

How do I need to think to be able to adapt that code for ImGui, Magnum, OpeGL Wrapper and camera capture?

Thank you for your suggestion.

#define WIN32_LEAN_AND_MEAN    

#include <windows.h>

#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <gl/gl.h>
#include <memory>
#include <vector>
#include "../videoInput/videoInput.h"

#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "../videoInput/Debug/videoInput.lib")

#define GL_BGR                            0x80E0

/**************************
* Function Declarations
*
**************************/

LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
    WPARAM wParam, LPARAM lParam);
void EnableOpenGL(HWND hWnd, HDC *hDC, HGLRC *hRC);
void DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC);

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPTSTR    lpCmdLine,
    _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    /* initialisation videoinput */
    using namespace std;
    vector<Device> listOfDevices;
    ResultCode::Result result = videoInput::getInstance().getListOfDevices(listOfDevices);
    if (listOfDevices.size() == 0)
        return -1;
    DeviceSettings deviceSettings;
    deviceSettings.symbolicLink = listOfDevices[0].symbolicName;
    deviceSettings.indexStream = 0;
    deviceSettings.indexMediaType = 0;
    CaptureSettings captureSettings;
    captureSettings.pIStopCallback = 0;
    captureSettings.readMode = ReadMode::SYNC;
    captureSettings.videoFormat = CaptureVideoFormat::RGB24;
    MediaType MT = listOfDevices[0].listStream[0].listMediaType[0];
    unique_ptr<unsigned char> frame(new unsigned char[3 * MT.width * MT.height]);

    ReadSetting readSetting;
    readSetting.symbolicLink = deviceSettings.symbolicLink;
    readSetting.pPixels = frame.get();
    result = videoInput::getInstance().setupDevice(deviceSettings, captureSettings);
    ResultCode::Result readState = videoInput::getInstance().readPixels(readSetting);
    
    /* check access to the video device */
    if (readState != ResultCode::READINGPIXELS_DONE)
        return -1;

    float halfQuadWidth = 0.75;
    float halfQuadHeight = 0.75;

    WNDCLASS wc;
    HWND hWnd;
    HDC hDC;
    HGLRC hRC;
    MSG msg;
    BOOL bQuit = FALSE;
    float theta = 0.0f;

    /* register window class */
    wc.style = CS_OWNDC;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = L"OpenGLWebCamCapture";
    RegisterClass(&wc);

    /* create main window */
    hWnd = CreateWindow(
        L"OpenGLWebCamCapture", L"OpenGLWebCamCapture Sample",
        WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE,
        0, 0, MT.width, MT.height,
        NULL, NULL, hInstance, NULL);

    /* enable OpenGL for the window */
    EnableOpenGL(hWnd, &hDC, &hRC);

    GLuint textureID;
    glGenTextures(1, &textureID);

    // "Bind" the newly created texture : all future texture functions will modify this texture
    glBindTexture(GL_TEXTURE_2D, textureID);

    // Give the image to OpenGL
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, MT.width, MT.height, 0, GL_BGR, GL_UNSIGNED_BYTE, frame.get());

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

    /* program main loop */
    while (!bQuit)
    {
        /* check for messages */
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            /* handle or dispatch messages */
            if (msg.message == WM_QUIT)
            {
                bQuit = TRUE;
            }
            else
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        else
        {
            /* OpenGL animation code goes here */

            ResultCode::Result readState = videoInput::getInstance().readPixels(readSetting);

            if (readState != ResultCode::READINGPIXELS_DONE)
                break;

            glClear(GL_COLOR_BUFFER_BIT);
            glLoadIdentity();

            glBindTexture(GL_TEXTURE_2D, textureID);

            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, MT.width, 
                    MT.height, GL_BGR, GL_UNSIGNED_BYTE, frame.get());

            glBegin(GL_QUADS);      // Beginning of drawing of Square.

            glTexCoord2f(0, 1);  glVertex2f(-halfQuadWidth, -halfQuadHeight);    // Bottom Left
            glTexCoord2f(1, 1);  glVertex2f(halfQuadWidth, -halfQuadHeight);    // Bottom right
            glTexCoord2f(1, 0);  glVertex2f(halfQuadWidth, halfQuadHeight);        // Top right
            glTexCoord2f(0, 0);  glVertex2f(-halfQuadWidth, halfQuadHeight);    // Top Left
            glEnd();

            SwapBuffers(hDC);

            Sleep(1);
        }
    }

    /* shutdown OpenGL */
    DisableOpenGL(hWnd, hDC, hRC);

    /* destroy the window explicitly */
    DestroyWindow(hWnd);

    /* release captured webcam */
    videoInput::getInstance().closeDevice(deviceSettings);

    return msg.wParam;
}

/********************
* Window Procedure
*
********************/

LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
    WPARAM wParam, LPARAM lParam)
{

    switch (message)
    {
    case WM_CREATE:
        return 0;
    case WM_CLOSE:
        PostQuitMessage(0);
        return 0;

    case WM_DESTROY:
        return 0;

    case WM_KEYDOWN:
        switch (wParam)
        {
        case VK_ESCAPE:
            PostQuitMessage(0);
            return 0;
        }
        return 0;

    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
}

/*******************
* Enable OpenGL
*
*******************/

void EnableOpenGL(HWND hWnd, HDC *hDC, HGLRC *hRC)
{
    PIXELFORMATDESCRIPTOR pfd;
    int iFormat;

    /* get the device context (DC) */
    *hDC = GetDC(hWnd);

    /* set the pixel format for the DC */
    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 = 24;
    pfd.cDepthBits = 16;
    pfd.iLayerType = PFD_MAIN_PLANE;
    iFormat = ChoosePixelFormat(*hDC, &pfd);
    SetPixelFormat(*hDC, iFormat, &pfd);

    /* create and enable the render context (RC) */
    *hRC = wglCreateContext(*hDC);
    wglMakeCurrent(*hDC, *hRC);

    glEnable(GL_TEXTURE_2D);            // Enable of texturing for OpenGL

}

/******************
* Disable OpenGL
*
******************/

void DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC)
{
    wglMakeCurrent(NULL, NULL);
    wglDeleteContext(hRC);
    ReleaseDC(hWnd, hDC);
}
@al-sabr al-sabr changed the title How to adapt native OpenGL code with native Camera capture. How to adapt native OpenGL code with native Camera capture to Magnum, ImGui, MagnumGL. Mar 22, 2019
@mosra
Copy link
Owner

mosra commented Mar 22, 2019

Well, I already listed the high-level concepts for you in mosra/magnum#327. All you need to do is:

  • try out a few different examples, so you get the idea how rendering works, how textures work, how input events work, how to loop and display different things each frame, etc.
  • that will probably imply that you need to read up on basic GPU programming concepts, how is the memory management there, what is a buffer, what is a mesh, what is a texture, what is a framebuffer, what does a shader do etc.
  • then, read up on the APIs I referenced
  • after you're a bit more sure about what you are doing, you can try displaying a single frame (load a PNG, for example) via a texture passed to ImGui
  • then, the final step is cutting out just the camera-related stuff from the above snippet and getting some RGB(A) image out of it, which you use instead of the stationary image in the previous step. And you throw everything else from the above snippet away -- it's using old GL 1.1 and is full of other very bad practices.

That's it, I'm sorry but I can't help you any further. My free time is quite limited and I have to prioritize what I spend my time on, so rewriting the above snippet with Magnum is absolutely out of question (besides that, I'm not on Windows and I have zero experience with their camera APIs).

Moreover, if you have no prior experience with OpenGL, giving you a ready-made thing wouldn't help you much anyway, since both this and the magnum version would be equivalently opaque pieces of code that "does something", but you'll have no idea why and how either way.

Again, as I mentioned in mosra/magnum#327, for general discussion the Gitter channel is the preferred form of communication.


"give a man a fish and you feed him for a day;" ... you know the rest.

@mosra mosra added this to the 2019.0b milestone May 28, 2019
@mosra mosra closed this as completed May 28, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants