Drawing on the computer screen using OpenGL

       Anyone who has studied OpenGL knows that if you want to use OpenGL functions for drawing, you must create a display window. Every time you draw, the first thing to do is probably to create a window. Some people must have thought about it like me: Can I not draw on that dark window, but draw directly on the computer screen, just like those icons on the desktop. I've searched all the OpenGL functions, and none of them support this approach. I think it probably won't work, so I put the idea of ​​​​drawing on the screen on hold. Until one day, I learned GDI and tried to take a screenshot. At that time, I was thinking that since the pixel buffer data can be read, the pixel buffer must also be set. The principle of GDI and OpenGL drawing is not to write to the pixel buffer of the window. ? So I deeply understood the relationship between GDI, OpenGL, operating system, and windows, and finally realized it! OpenGL only provides drawing methods, but it cannot create windows. Creating windows is a matter for the operating system. Any visible interface is a window, including console windows, application software interfaces, text boxes, buttons, and menu bars. . . . Of course, there is the ultimate window -- the computer screen. Since they are windows, they all have a common feature, that is, they all have pixel buffers, that is, they can draw. It is feasible to use OpenGL to draw on the computer screen, the key is how to operate, let's explain how to draw on the screen.

1. Create an OpenGL rendering environment (Render Context)

           To use OpenGL drawing, not only need a window, but also need a rendering environment. The computer screen is the window, it has always been there, so there is no need to create a window, and creating an OpenGL rendering environment for the window is the key to drawing. In the windows system, several win API functions are needed to create a rendering environment. The operation steps are: obtain the window device environment (DC, device context), select the pixel format, set the pixel format, and create a rendering environment (RC, render context) . The win API and wgl functions used are as follows:

(1) Obtain the window device environment (DC), hWnd is the window handle, if it is NULL, it means to obtain the DC of the screen. See MSDN for details: GetDC

HDC GetDC(HWND hWnd);

(2) Select the appropriate pixel format for the specified device context (DC), the hdc parameter is the DC handle, and the ppfd pixel format descriptor. Returns a non-zero pixel format index number if a pixel format matching the specified DC is found, otherwise returns 0. See MSDN ChoosePixelFormat for details

int ChoosePixelFormat(HDC  hdc, CONST PIXELFORMATDESCRIPTOR *  ppfd );

A pixel format descriptor is a structure defined as follows:

/* Pixel format descriptor */
typedef struct tagPIXELFORMATDESCRIPTOR
{
    WORD  nSize;
    WORD  nVersion;
    DWORD dwFlags;
    BYTE  iPixelType;
    BYTE  cColorBits;
    BYTE  cRedBits;
    BYTE  cRedShift;
    BYTE  cGreenBits;
    BYTE  cGreenShift;
    BYTE  cBlueBits;
    BYTE  cBlueShift;
    BYTE  cAlphaBits;
    BYTE  cAlphaShift;
    BYTE  cAccumBits;
    BYTE  cAccumRedBits;
    BYTE  cAccumGreenBits;
    BYTE  cAccumBlueBits;
    BYTE  cAccumAlphaBits;
    BYTE  cDepthBits;
    BYTE  cStencilBits;
    BYTE  cAuxBuffers;
    BYTE  iLayerType;
    BYTE  bReserved;
    DWORD dwLayerMask;
    DWORD dwVisibleMask;
    DWORD dwDamageMask;
} PIXELFORMATDESCRIPTOR, *PPIXELFORMATDESCRIPTOR, FAR *LPPIXELFORMATDESCRIPTOR;

The meaning and value range of each member in the pixel book format descriptor are described in detail on the Internet or in Microsoft's MSDN.

(3) Set the pixel format for the specified device context (DC). The second parameter iPixelFormat is obtained through the ChoosePixelFormat function. See MSDN for details: SetPixelFormat

BOOL SetPixelFormat(HDC  hdc,int  iPixelFormat,CONST PIXELFORMATDESCRIPTOR *  ppfd );

(4) Create a rendering environment (create render context). Creating an OpenGL rendering environment requires a wgl function, which is included in the gl\GL.h header file. See MSDN for details: wglCreateContext

HGLRC wglCreateContext(HDC  hdc);

2. Programming example

            This program example is written using VS. Considering that the example is very simple, only the OpenGL function of version 1.1 is used, so the OpenGL programming environment configuration is not performed here, but the OpenGL library that comes with VS is used. There are two header files that need to be referenced. The win API needs to include Windows.h, and the wgl function and OpenGL function need to include the gl\GL.h header file. Since there is no need to create a window, the creation project can be win32. For convenience, I use the console project I am most familiar with. The example code is as follows:

#include<Windows.h>
#include<gl\GL.h>

int main()
{
	PIXELFORMATDESCRIPTOR pfd;
	pfd.nSize = 40;
	pfd.nVersion = 1;
    //支持绘制到窗口、支持OPENGL、支持GDI
	pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_SUPPORT_GDI;
	pfd.iPixelType = PFD_TYPE_RGBA;
	pfd.cColorBits = 0;
	pfd.cRedBits = 0;
	pfd.cRedShift = 0;
	pfd.cGreenBits = 0;
	pfd.cGreenShift = 0;
	pfd.cBlueBits = 0;
	pfd.cBlueShift = 0;
	pfd.cAlphaBits = 0;
	pfd.cAlphaShift = 0;
	pfd.cAccumBits = 0;
	pfd.cAccumRedBits = 0;
	pfd.cAccumGreenBits = 0;
	pfd.cAccumBlueBits = 0;
	pfd.cAccumAlphaBits = 0;
	pfd.cDepthBits = 0;
	pfd.cStencilBits = 0;
	pfd.cAuxBuffers = 0;
	pfd.iLayerType = PFD_MAIN_PLANE;
	pfd.bReserved = 0;
	pfd.dwLayerMask = 0;
	pfd.dwVisibleMask = 0;
	pfd.dwDamageMask = 0;
	
    //获取屏幕的设备环境
	HDC hdc = GetDC(NULL);
    //选择像素格式
	int pixelFormat = ChoosePixelFormat(hdc, &pfd);
    //设置像素格式
	SetPixelFormat(hdc, pixelFormat, &pfd);
    //创建OpenGL渲染环境
	HGLRC hglrc = wglCreateContext(hdc);
	//为当前线程指定设备环境和渲染环境
	wglMakeCurrent(hdc, hglrc);
	int i = 0;
	while (i<1000)
	{

		i++;
		glViewport(0, 0, 800, 800);
		//glClear(GL_COLOR_BUFFER_BIT);
		glColor3f(1.0f, 0.0f, 0.0f);
		glBegin(GL_TRIANGLES);
		glVertex2f(-0.5f, -0.5f);
		glVertex2f(0.0f, 0.5f);
		glVertex2f(0.5f, -0.5f);
		glEnd();
		glFlush();
	}
	return 0;
}

Run the above code, you can see a red triangle is displayed on the screen:

Three things to pay attention to

        1. When setting the pixel format, others can use the default, all set to 0, but this item must be set to pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_SUPPORT_GDI; if you want to draw to the screen, you must choose to support OpenGL and support GDI, GDI and double buffering are incompatible, so if PFD_SUPPORT_GDI is selected, PFD_DOUBLEBUFFER cannot be selected. In other words, if you want to draw to the screen, you can't use double buffering.

       2. When using the OpenGL library that comes with VS, be sure to add the opengl32.lib additional dependency in the linker of the project properties, otherwise there will be a connection error "Unable to resolve external reference" and other errors when compiling.

Guess you like

Origin blog.csdn.net/qq_28249373/article/details/89949253