介绍
rgfw是一个轻量级的单头窗口库,它的源代码可以在这里找到。
本教程基于其源代码。
软件渲染的基本思想很简单。归根结底就是绘制到缓冲区并将其传输到屏幕。
然而,使用低级 api 时软件渲染会更加复杂,因为您必须
正确初始化渲染上下文,告诉 api 如何期望数据。然后要绘制就必须使用api的函数
blit 到屏幕,这可能很复杂。
本教程解释了rgfw如何处理软件渲染,以便您可以了解如何自己实现。
注意:macos 代码将在编写时考虑到 cocoa c 包装器(请参阅 rgfw.h 或 silicon.h)
概述
所需步骤的快速概述
- 初始化缓冲区和渲染上下文
- 绘制到缓冲区
- 将缓冲区传输到屏幕
- 免费剩余数据
第 1 步(初始化缓冲区和渲染上下文)
注意:您可能希望缓冲区的大小大于窗口,这样您就可以缩放缓冲区的大小而无需重新分配它。
在 x11 上,您首先创建一个视觉(或像素格式)来告诉窗口如何处理绘制数据。
然后为缓冲区创建一个位图来渲染,rgfw 使用 ximage 结构作为位图。
接下来,您使用显示和窗口数据创建图形上下文 (gc)。 gc是用来告诉x11如何给
窗口绘制数据。
这也是你可以分配缓冲区的地方。必须为除 windows 之外的每个平台分配缓冲区。
为此,您需要使用 xmatchvisualinfo、xcreateimage 和 xcreategc
xvisualinfo vi; vi.visual = defaultvisual(display, defaultscreen(display)); xmatchvisualinfo(display, defaultscreen(display), 32, truecolor, &vi); ximage* bitmap = xcreateimage( display, xdefaultvisual(display, vi.screen), vi.depth, zpixmap, 0, null, rgfw_buffersize.w, rgfw_buffersize.h, 32, 0 ); /* ..... */ /* now this visual can be used to create a window and colormap */ xsetwindowattributes swa; colormap cmap; swa.colormap = cmap = xcreatecolormap((display*) display, defaultrootwindow(display), vi.visual, allocnone); swa.background_pixmap = none; swa.border_pixel = 0; swa.event_mask = event_mask; swa.background_pixel = 0; window window = xcreatewindow((display*) display, defaultrootwindow((display*) display), x, y, w, h, 0, vi.depth, inputoutput, vi.visual, cwcolormap | cwborderpixel | cwbackpixel | cweventmask, &swa); /* .... */ gc gc = xcreategc(display, window, 0, null); u8* buffer = (u8*)malloc(rgfw_buffersize.w * rgfw_buffersize.h * 4);
登录后复制
在 windows 上,您将首先创建位图标头,该标头用于创建指定格式的位图。
格式结构用于告诉 windows api 如何将缓冲区渲染到屏幕上。
接下来,创建一个分配在内存中的绘图上下文句柄(hdc),用于稍后选择位图。
注意:windows 不需要分配缓冲区,因为 winapi 会为我们处理该内存。您也可以手动分配内存。
相关文档:bitmapv5header、createdibsection 和 createcompatibledc
bitmapv5header bi; zeromemory(&bi, sizeof(bi)); bi.bv5size = sizeof(bi); bi.bv5width = rgfw_buffersize.w; bi.bv5height = -((long) rgfw_buffersize.h); bi.bv5planes = 1; bi.bv5bitcount = 32; bi.bv5compression = bi_bitfields; // where it can expect to find the rgba data // (note: this might need to be changed according to the endianness) bi.bv5bluemask = 0x00ff0000; bi.bv5greenmask = 0x0000ff00; bi.bv5redmask = 0x000000ff; bi.bv5alphamask = 0xff000000; u8* buffer; hbitmap bitmap = createdibsection(hdc, (bitmapinfo*) &bi, dib_rgb_colors, (void**) &buffer, null, (dword) 0); hdc hdcmem = createcompatibledc(hdc);
登录后复制
在macos上,没有太多设置,大部分工作都是在渲染过程中完成的。
你只需要分配缓冲区数据即可。
u8* buffer = malloc(rgfw_buffersize.w * rgfw_buffersize.h * 4);
登录后复制
第2步(绘制到缓冲区)
在本教程中,我将使用 silk.h 绘制到缓冲区。 silk.h是一个单头软件渲染图形库。
首先包括丝绸,
#define silk_pixelbuffer_width w #define silk_pixelbuffer_height h #define silk_implementation #include "silk.h"
登录后复制
现在可以使用silk渲染了。
846467155365
步骤 3(将缓冲区传输到屏幕)
在x11上,首先将位图数据设置到缓冲区。
位图数据将使用bgr渲染,所以你必须
如果要使用 rgb,请转换数据。那你就得用xputimage
使用gc将ximage绘制到窗口。
相关文档:xputimage
bitmap->data = (char*) buffer; #ifndef rgfw_x11_dont_convert_bgr u32 x, y; for (y = 0; y data[index]; bitmap->data[index] = buffer[index + 2]; bitmap->data[index + 2] = red; } } #endif xputimage(display, (window)window, gc, bitmap, 0, 0, 0, 0, rgfw_buffersize.w, rgfw_buffersize.h);
登录后复制
在 windows 上,您必须首先选择位图并确保保存最后选择的对象,以便稍后可以重新选择它。
现在您可以将位图传输到屏幕并重新选择旧位图。
相关文档:selectobject 和 bitblt
hgdiobj oldbmp = selectobject(hdcmem, bitmap); bitblt(hdc, 0, 0, window_width, window_height, hdcmem, 0, 0, srccopy); selectobject(hdcmem, oldbmp);
登录后复制
在macos上,根据您的窗口设置视图的calayer,这用于将图像渲染到屏幕上。
接下来,使用缓冲区创建图像(位图)。
最后,您可以将图像添加到图层的图形上下文中,并将图层绘制并刷新到屏幕上。
相关文档:cgcolorspacecreatedevicergb、cgbitmapcontextcreate、cgbitmapcontextcreateimage、cgcolorspacerelease、cgcontextrelease、
calayer、nsgraphicscontext、cgcontextdrawimage、flushgraphics 和 cgimagerelease
cgimageref createimagefrombytes(unsigned char *buffer, int width, int height) { // define color space cgcolorspaceref colorspace = cgcolorspacecreatedevicergb(); // create bitmap context cgcontextref context = cgbitmapcontextcreate( buffer, width, height, 8, rgfw_buffersize.w * 4, colorspace, kcgimagealphapremultipliedlast); // create image from bitmap context cgimageref image = cgbitmapcontextcreateimage(context); // release the color space and context cgcolorspacerelease(colorspace); cgcontextrelease(context); return image; } ... void* view = nswindow_contentview(window); void* layer = objc_msgsend_id(view, sel_registername("layer")); ((void(*)(id, sel, nsrect))objc_msgsend)(layer, sel_registername("setframe:"), (nsrect){{0, 0}, {window_width, window_height}}); cgimageref image = createimagefrombytes(buffer, window_width, window_height); // get the current graphics context id graphicscontext = objc_msgsend_class(objc_getclass("nsgraphicscontext"), sel_registername("currentcontext")); // get the cgcontext from the current nsgraphicscontext id cgcontext = objc_msgsend_id(graphicscontext, sel_registername("graphicsport")); // draw the image in the context nsrect bounds = (nsrect){{0,0}, {window_width, window_height}}; cgcontextdrawimage((void*)cgcontext, *(cgrect*)&bounds, image); // flush the graphics context to ensure the drawing is displayed objc_msgsend_id(graphicscontext, sel_registername("flushgraphics")); objc_msgsend_void_id(layer, sel_registername("setcontents:"), (id)image); objc_msgsend_id(layer, sel_registername("setneedsdisplay")); cgimagerelease(image);
登录后复制
步骤 4(免费剩余数据)
渲染完成后,您应该使用相应的api函数释放位图和图像数据。
在 x11 和 macos 上,您还应该释放缓冲区。
在x11上你必须使用xdestoryimage和xfreegc。
288254941586
在windows上,必须使用deletedc和deleteobject。
deletedc(hdcmem); deleteobject(bitmap);
登录后复制
macos 上必须使用release.
release(bitmap); release(image); free(buffer);
登录后复制
完整的例子
x11
// this can be compiled with // gcc x11.c -lx11 -lm#include <x11>#include <x11>#include <stdio.h>#include <stdlib.h>#define silk_pixelbuffer_width 500#define silk_pixelbuffer_height 500#define silk_implementation#include "silk.h"int main() { display* display = xopendisplay(null); xvisualinfo vi; vi.visual = defaultvisual(display, defaultscreen(display)); xmatchvisualinfo(display, defaultscreen(display), 32, truecolor, &vi); ximage* bitmap = xcreateimage( display, xdefaultvisual(display, vi.screen), vi.depth, zpixmap, 0, null, 500, 500, 32, 0 ); /* ..... */ /* now this visual can be used to create a window and colormap */ xsetwindowattributes swa; colormap cmap; swa.colormap = cmap = xcreatecolormap((display*) display, defaultrootwindow(display), vi.visual, allocnone); swa.background_pixmap = none; swa.border_pixel = 0; swa.event_mask = cwcolormap | cwborderpixel | cwbackpixel | cweventmask; swa.background_pixel = 0; window window = xcreatewindow((display*) display, defaultrootwindow((display*) display), 500, 500, 500, 500, 0, vi.depth, inputoutput, vi.visual, cwcolormap | cwborderpixel | cwbackpixel | cweventmask, &swa); /* .... */ gc gc = xcreategc(display, window, 0, null); u8* buffer = (u8*)malloc(500 * 500 * 4); xselectinput(display, window, exposuremask | keypressmask); xmapwindow(display, window); xevent event; for (;;) { xnextevent(display, &event); silkclearpixelbuffercolor((pixel*)buffer, 0x11aa0033); silkdrawcircle( (pixel*)buffer, (vec2i) { silk_pixelbuffer_width, silk_pixelbuffer_height }, silk_pixelbuffer_width, (vec2i) { silk_pixelbuffer_center_x, silk_pixelbuffer_center_y - 60}, 60, 0xff0000ff ); bitmap->data = (char*) buffer; #ifndef rgfw_x11_dont_convert_bgr u32 x, y; for (y = 0; y data[index]; bitmap->data[index] = buffer[index + 2]; bitmap->data[index + 2] = red; } } #endif xputimage(display, (window) window, gc, bitmap, 0, 0, 0, 0, 500, 500); } xdestroyimage(bitmap); xfreegc(display, gc); free(buffer);}</stdlib.h></stdio.h></x11></x11>
登录后复制
视窗
// This can be compiled with// gcc win32.c -lgdi32 -lm#include <windows.h>#include <stdio.h>#include <stdint.h>#include <assert.h>#define SILK_PIXELBUFFER_WIDTH 500#define SILK_PIXELBUFFER_HEIGHT 500#define SILK_IMPLEMENTATION#include "silk.h"int main() { WNDCLASS wc = {0}; wc.lpfnWndProc = DefWindowProc; // Default window procedure wc.hInstance = GetModuleHandle(NULL); wc.lpszClassName = "SampleWindowClass"; RegisterClass(&wc); HWND hwnd = CreateWindowA(wc.lpszClassName, "Sample Window", 0, 500, 500, 500, 500, NULL, NULL, wc.hInstance, NULL); BITMAPV5HEADER bi = { 0 }; ZeroMemory(&bi, sizeof(bi)); bi.bV5Size = sizeof(bi); bi.bV5Width = 500; bi.bV5Height = -((LONG) 500); bi.bV5Planes = 1; bi.bV5BitCount = 32; bi.bV5Compression = BI_BITFIELDS; // where it can expect to find the RGB data // (note: this might need to be changed according to the endianness) bi.bV5BlueMask = 0x00ff0000; bi.bV5GreenMask = 0x0000ff00; bi.bV5RedMask = 0x000000ff; bi.bV5AlphaMask = 0xff000000; u8* buffer; HDC hdc = GetDC(hwnd); HBITMAP bitmap = CreateDIBSection(hdc, (BITMAPINFO*) &bi, DIB_RGB_COLORS, (void**) &buffer, NULL, (DWORD) 0); HDC hdcMem = CreateCompatibleDC(hdc); ShowWindow(hwnd, SW_SHOW); UpdateWindow(hwnd); MSG msg; BOOL running = TRUE; while (running) { if (PeekMessageA(&msg, hwnd, 0u, 0u, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } running = IsWindow(hwnd); silkClearPixelBufferColor((pixel*)buffer, 0x11AA0033); silkDrawCircle( (pixel*)buffer, (vec2i) { SILK_PIXELBUFFER_WIDTH, SILK_PIXELBUFFER_HEIGHT }, SILK_PIXELBUFFER_WIDTH, (vec2i) { SILK_PIXELBUFFER_CENTER_X, SILK_PIXELBUFFER_CENTER_Y - 60}, 60, 0xff0000ff ); HGDIOBJ oldbmp = SelectObject(hdcMem, bitmap); BitBlt(hdc, 0, 0, 500, 500, hdcMem, 0, 0, SRCCOPY); SelectObject(hdcMem, oldbmp); } DeleteDC(hdcMem); DeleteObject(bitmap); return 0;}</assert.h></stdint.h></stdio.h></windows.h>
登录后复制
以上就是RGFW 底层:软件渲染的详细内容,更多请关注叮当号网其它相关文章!
文章来自互联网,只做分享使用。发布者:张大嘴,转转请注明出处:https://www.dingdanghao.com/article/731362.html