所以我想要完成的是通过名称(例如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,找到特定窗口的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
值会相应更改。
#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;
}
此类是来自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;
}
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;
}