将窗口纹理从HWND加载到OpenGL纹理中

时间:2015-08-24 15:19:40

标签: c++ winapi opengl hwnd

所以我想要完成的是通过名称(例如Slack)获取窗口句柄并将窗口像素信息复制到OpenGL纹理中。

我一直在学习C ++和OpenGL,因为我一直在努力实现这一目标。在此之前,我主要使用Java 我设法将一只可爱的小猫的照片加载到纹理中并在四边形上显示 我还找到了特定窗口的HWND句柄。

我遇到的问题是从窗口加载像素信息并将其显示在四边形上。最终目标是在其他地方使用纹理,但要确保我能够在四边形上显示纹理。

问题
在WindowTextureFactory下面有两个函数,我设法从几个来源拼凑起来。我确定这是我的错误来源。 第一个CreateVideoTexture(...)导致以下错误:

Exception thrown at 0x0F61615B (ucrtbased.dll) in program.exe: 0xC0000005:
Access violation reading location 0x0518FFF0.

当我在此行的TextureLoader中稍后使用数据时 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

虽然第二个CreateVideoTextureAlt(...),似乎什么也没做。我只是得到一个黑色四边形。

那么我做错了什么?

我已经包含了很多代码,我可能会详细介绍。我花了很多时间到达现在的位置,我想确保我不会在某个地方犯错误。

- WindowManager -

启动WindowManager,找到特定窗口的HWND。我已经硬编码" spotify"作为开头的窗口名称。

#include "WindowManager.h"

HWND mHwnd;
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);

WindowManager::WindowManager()
{
    EnumWindows(EnumWindowsProc, NULL);
}

SIZE WindowManager::getSizeForHwnd(HWND hwnd)
{
    RECT rect;
    SIZE size;
    BOOL success = GetWindowRect(hwnd, &rect);

    if (!success)
    {
        int errorCode = GetLastError();
        std::cout << "Call failed to GetWindowRect() with error code: " + std::to_string(errorCode) << std::endl;
    }

    size.cx = rect.right - rect.left;
    size.cy = rect.bottom - rect.top;

    std::cout << "Size: " << size.cx << "x" << size.cy << std::endl;

    return size;
}

HWND WindowManager::getHwnd()
{
    return mHwnd;
}

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
    char class_name[80];
    char title[80];

    GetWindowText(hwnd, title, sizeof(title));

    std::string x = title;

    std::transform(x.begin(), x.end(), x.begin(), ::tolower);

    if (!x.compare("spotify"))
    {
        mHwnd = hwnd;
    }

    return TRUE;
}

像这样使用这个类

WindowManager wManager;
HWND hwnd = wManager.getHwnd();
SIZE size = wManager.getSizeForHwnd(hwnd);

我现在有了Spotify窗口的句柄。如果我调整Spotify窗口并再次运行程序,SIZE值会相应更改。

- WindowTextureFactory -

#include "WindowTextureFactory.h"

WindowTextureFactory::WindowTextureFactory() { }

WindowTextureFactory::~WindowTextureFactory() { }

unsigned char* WindowTextureFactory::CreateVideoTexture(HWND hwnd, SIZE bmpSize)
{
    if (!bmpSize.cx || !bmpSize.cy)
    {
        std::cout << "Error creating window texture in CreateVideoTexture(...)" << std::endl;
        return nullptr;
    }

    BITMAPINFO bmi;
    auto& hdr = bmi.bmiHeader;
    hdr.biSize = sizeof(bmi.bmiHeader);
    hdr.biWidth = bmpSize.cx;
    hdr.biHeight = -bmpSize.cy;
    hdr.biPlanes = 1;
    hdr.biBitCount = 32;
    hdr.biCompression = BI_RGB;
    hdr.biSizeImage = 0;
    hdr.biXPelsPerMeter = 0;
    hdr.biYPelsPerMeter = 0;
    hdr.biClrUsed = 0;
    hdr.biClrImportant = 0;

    unsigned char* bitmapBits;
    HDC hdc = GetWindowDC(hwnd);
    HDC hBmpDc = CreateCompatibleDC(hdc);

    BITMAP bm;
    HBITMAP hBmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**) &bitmapBits, nullptr, 0);

    SelectObject(hBmpDc, hBmp);

    BOOL success = BitBlt(hBmpDc, 0, 0, bmpSize.cx, bmpSize.cy, hdc, 0, 0, SRCCOPY);

    if (!success)
    {
        std::cout << "BitBlt failed" << std::endl;
    }

    return bitmapBits;
}

unsigned char* WindowTextureFactory::CreateVideoTextureAlt(HWND hwnd, SIZE bmpSize)
{
    HDC hdc = GetDC(hwnd);
    HDC hBmpDc = CreateCompatibleDC(hdc);

    BITMAP bmp;
    HBITMAP hBmp = CreateCompatibleBitmap(hBmpDc, bmpSize.cx, bmpSize.cy);

    GetObject(hBmp, sizeof(BITMAP), &bmp);
    SelectObject(hBmpDc, hBmp);

    BOOL success = BitBlt(hBmpDc, 0, 0, bmpSize.cx, bmpSize.cy, hdc, 0, 0, SRCCOPY);

    if (!success)
    {
        std::cout << "BitBlt failed" << std::endl;
    }

    return (unsigned char*) bmp.bmBits;
}

- TextureLoader -

此类是来自in2gpu.com's OpenGL guide的另一个版本的略微更改版本。它在加载外部.bmp文件时效果很好。

#include "TextureLoader.h"

TextureLoader::TextureLoader() { }

TextureLoader::~TextureLoader() { }

unsigned int TextureLoader::LoadTexture(unsigned char* data, unsigned int width, unsigned int height)
{
    //create the OpenGL texture
    unsigned int gl_texture_object = 0;
    glGenTextures(1, &gl_texture_object);
    glBindTexture(GL_TEXTURE_2D, gl_texture_object);

    //filtering
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);

    float maxAnisotropy;
    glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAnisotropy);

    //when we work with textures of sizes not divisible by 4 we have to use the line reader
    //which loads the textures in OpenGL so as it can work with a 1 alligned memory (default is 4)
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    //Generates texture
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

    //eliminates the array from the RAM
    delete data;

    //creates the mipmap hierarchy
    glGenerateMipmap(GL_TEXTURE_2D);

    //returns the texture object
    return gl_texture_object;
}

- 碎片&amp;顶点着色器 -

Vertex_Shader_T.glsl

#version 450 core

layout(location = 0) in vec3 vert;
layout(location = 1) in vec2 vertTexCoord;
out vec2 fragTexCoord;

void main()
{
    fragTexCoord = vertTexCoord;

    gl_Position = vec4(vert, 1);
}

Fragment_Shader_T.glsl

#version 450 core

uniform sampler2D tex; // texture
in vec2 fragTexCoord; // texture coord
layout(location = 0) out vec4 finalColor; // pixel color output

void main()
{
    finalColor = texture(tex, fragTexCoord);
}

- 主要 -

#pragma once
#include "Core\Shader_Loader.h"
#include "Core\GameModels.h"
#include "Core\TextureLoader.h"
#include "Core\WindowManager.h"
#include "Core\WindowTextureFactory.h"

Models::GameModels* gameModels;
GLuint program;

void renderScene(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0.6f, 0.6f, 0.6f, 1.0f);

    glBindVertexArray(gameModels->GetModel("quad"));
    glUseProgram(program);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glutSwapBuffers();
}

void closeCallback()
{
    std::cout << "GLUT:\t Finished" << std::endl;
    glutLeaveMainLoop();
}

void Init()
{
    glEnable(GL_DEPTH_TEST);

    gameModels = new Models::GameModels();
    gameModels->CreateQuadModel("quad");

    // load and compile shaders
    Core::Shader_Loader shaderLoader;
    program = shaderLoader.CreateProgram("Shaders\\Vertex_Shader_T.glsl", "Shaders\\Fragment_Shader_T.glsl");
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}

void texturize()
{
    Core::TextureLoader textureLoader;

    WindowTextureFactory factory;
    WindowManager wManager;
    HWND hwnd = wManager.getHwnd();
    SIZE size = wManager.getSizeForHwnd(hwnd);
    unsigned char* data = factory.CreateVideoTexture(hwnd, size);

    unsigned int texture = textureLoader.LoadTexture(data, size.cx, size.cy);

    GLint loc = glGetUniformLocation(program, "tex");

    if (loc != -1)
    {
        glUniform1f(loc, 0.432f);
    }

    glUniform1i(texture, 0);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
}

int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(500, 500);
    glutInitWindowSize(800, 600);
    glutCreateWindow("OpenGL Window");
    glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);

    glewInit();

    if (glewIsSupported("GL_VERSION_4_5"))
    {
        std::cout << " OpenGL Version is 4.5\n ";
    }
    else
    {
        std::cout << "OpenGL 4.5 not supported\n ";
    }

    Init();

    // Callbacks
    glutDisplayFunc(renderScene);
    glutCloseFunc(closeCallback);

    texturize();

    glutMainLoop();

    delete gameModels;
    glDeleteProgram(program);
    return 0;
}

0 个答案:

没有答案