【问题标题】:Draw on top of the screen (Windows) with SFML使用 SFML 在屏幕顶部绘制 (Windows)
【发布时间】:2019-10-03 23:00:07
【问题描述】:

在 Windows 上,您可以使用 GDI 在所有内容之上绘制,使用 null 的绘制上下文:

HDC hdc = GetDC(NULL);

我希望对 SFML 做同样的事情,但是如果我尝试一些等效的方法(使用 NULL 作为参数创建渲染窗口,在将其转换为 hwnd 之后),任何地方都不会绘制任何内容。 我正在尝试使用 sfml 吗?

【问题讨论】:

  • SFML 无法做到这一点。
  • 悲伤而快速的回答,ty @JesperJuhl
  • 根据文档,您可以从本机窗口句柄 HWND (sfml-dev.org/documentation/2.5.1/classsf_1_1Window.php & sfml-dev.org/documentation/2.5.1/…) 创建一个 SFML 窗口,所以像 auto root_window = sf::Window(NULL, ...); 这样的东西可能会工作,但我不有 Windows,所以我无法测试。
  • @Barnack 如果你想要 OpenGL,你需要一个窗口期....但是你可以结合 GDI 和 OpenGl,以便通过 OpenGL(和不可见窗口)将屏幕上的东西渲染为位图并将其复制到桌面使用 GDI 的画布。此外,我对 WinAPI 并不流利,但也有可能告诉 Windows 忽略解决方法窗口的鼠标单击、键击和焦点事件(如禁用鼠标挂钩等)......通过禁用窗口......跨度>
  • @Barnack 确实尝试先实现它......看起来它的工作我用简单的例子添加了答案(远非完美)

标签: c++ windows graphics sfml


【解决方案1】:

如果你想要OpenGL,你需要一个窗口期。但是窗口不需要在屏幕上可见。您可以将 GDIOpenGL 结合在一起来实现您的目标。

  1. 通过 OpenGL 将屏幕外的内容渲染为位图

    使用与桌面分辨率相同的隐形窗口。如果窗口不可见,它将不会对鼠标或键盘事件做出反应...

  2. 将 GL 映像复制到 CPU 端内存中

    简单的glReadPixels 就可以了。

  3. 将图像复制到桌面(使用 GDI 位图)

    只需将原始图像数据转换/复制到与 GDI 兼容的位图,然后简单地将其绘制到桌面画布上。所以不再像标准 GL 应用程序中那样使用SwapBuffers(hdc);

我在 C++/VCL 环境中编码,所以我没有纯 WinAPI/GDI 知识(VCL 为我做,但代码应该与名称非常相似并且传递的操作数可能会有所不同,但不会太大)。

这是我带来的:

//---------------------------------------------------------------------------
#include <vcl.h>
#include <gl\gl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1  *Form1;                 // VCL Application window object
TCanvas *scr=NULL;              // Desktop
DWORD   *txr=NULL;              // memory for GPU->CPU image transfer
Graphics::TBitmap *bmp=NULL;    // bitmap for CPU->Desktop image transfer
int     xs,ys;                  // desktop resolution
HDC     hdc=NULL;               // device context for GL
HGLRC   hrc=NULL;               // rendering context for GL
//---------------------------------------------------------------------------
void gl_draw()
    {
    if (scr==NULL) return;
    if (bmp==NULL) return;
    if (txr==NULL) return;

    glClearColor(0.0,0.0,0.0,0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_CULL_FACE);

    // desktop pixel units
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glTranslatef(-1.0,+1.0,0.0);
    glScalef(2.0/float(xs),-2.0/float(ys),1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // render rectangle
    GLfloat fx=xs/2,fy=ys/2,fz=0.0,fa=(xs/2)-10,fb=(ys/2)-10;
    glColor3f(1.0,1.0,1.0);
    glBegin(GL_LINE_LOOP);
    glVertex3f(fx-fa,fy-fb,fz);
    glVertex3f(fx-fa,fy+fb,fz);
    glVertex3f(fx+fa,fy+fb,fz);
    glVertex3f(fx+fa,fy-fb,fz);
    glEnd();

    if (Form1->Visible)     // normal window GL render
        {
        glFlush();
        SwapBuffers(hdc);
        }
    else{                   // copy GL image directly to desktop
        // copy GL image to CPU side memory
        glFlush();
        glReadPixels(0,0,xs,ys,GL_RGBA,GL_UNSIGNED_BYTE,txr);
        // copy it to bitmap
        int x,y,a; DWORD *p;
        for (a=0,y=0;y<ys;y++)
         for (p=(DWORD*)bmp->ScanLine[y],x=0;x<xs;x++,a++)
          p[x]=txr[a];
        // render it to desktop
        scr->Draw(0,0,bmp);
        }

    }
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
    {
    // desktop
    scr=new TCanvas();
    scr->Handle=GetDC(NULL);
    xs=scr->ClipRect.Width();
    ys=scr->ClipRect.Height()-31;           // leave taskbar out of it
    // BMP
    bmp=new Graphics::TBitmap;
    bmp->HandleType=bmDIB;
    bmp->PixelFormat=pf32bit;
    bmp->SetSize(xs,ys);
    // txr buffer
    txr=new DWORD[xs*ys];
    // window
    BorderStyle=bsNone;
    SetBounds(0,0,xs,ys);
    // GL init
    hdc = GetDC(Handle);                    // get device context for this App window
    PIXELFORMATDESCRIPTOR pfd;
    ZeroMemory( &pfd, sizeof( pfd ) );      // set the pixel format for the DC
    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 = 24;
    pfd.iLayerType = PFD_MAIN_PLANE;
    SetPixelFormat(hdc,ChoosePixelFormat(hdc, &pfd),&pfd);
    hrc = wglCreateContext(hdc);            // create current rendering context
    if(hrc == NULL)
        {
        ShowMessage("Could not initialize OpenGL Rendering context !!!");
        Application->Terminate();
        }
    if(wglMakeCurrent(hdc, hrc) == false)
        {
        ShowMessage("Could not make current OpenGL Rendering context !!!");
        wglDeleteContext(hrc);          // destroy rendering context
        Application->Terminate();
        }
    glViewport(0,0,xs,ys);
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
    {
    // GL exit
    wglMakeCurrent(NULL, NULL);     // release current rendering context
    wglDeleteContext(hrc);          // destroy rendering context
    // release buffers
    if (scr){ delete scr; scr=NULL; }
    if (bmp){ delete bmp; bmp=NULL; }
    if (txr){ delete[] txr; txr=NULL; }
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
    {
    gl_draw();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
    {
    if (Visible) Visible=false; // hide
    gl_draw();
    }
//---------------------------------------------------------------------------

它的单个表单 VCL 应用程序带有单个计时器。它创建 GL 上下文,并在第一次机会时变得不可见。然后它会定期用黑色背景和白色矩形边框覆盖桌面...

因此,您需要将 VCL 内容(Form1 和事件)移植到您的环境中。此外,您可能想为该行添加透明度:

scr->Draw(0,0,bmp);

read the desktop image 并将其用作 GL 渲染的背景纹理。

PS。纯 GDI 渲染更简单,可能比这更快,但您需要 GL,所以 ...

【讨论】:

    猜你喜欢
    • 2012-12-21
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    • 2010-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多