RGFW 底层:软件渲染

介绍rgfw是一个轻量级的单头窗口库,它的源代码可以在这里找到。
本教程基于其源代码。软件渲染的基本思想很简单。归根结底就是绘制到缓冲区并将其传输到屏幕。
然而,使用低级 api 时软件渲染会更加复杂,因为您必须
正确初始化渲染上下文,告

rgfw 底层:软件渲染

介绍

rgfw是一个轻量级的单头窗口库,它的源代码可以在这里找到。
本教程基于其源代码。

软件渲染的基本思想很简单。归根结底就是绘制到缓冲区并将其传输到屏幕。
然而,使用低级 api 时软件渲染会更加复杂,因为您必须
正确初始化渲染上下文,告诉 api 如何期望数据。然后要绘制就必须使用api​​的函数
blit 到屏幕,这可能很复杂。

本教程解释了rgfw如何处理软件渲染,以便您可以了解如何自己实现。

注意:macos 代码将在编写时考虑到 cocoa c 包装器(请参阅 rgfw.h 或 silicon.h)

概述

所需步骤的快速概述

  1. 初始化缓冲区和渲染上下文
  2. 绘制到缓冲区
  3. 将缓冲区传输到屏幕
  4. 免费剩余数据

第 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渲染了。

84646715536​​5

步骤 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 和 cgi​​magerelease

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。

2882​​54941586

在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, &amp;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, &amp;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, &amp;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-&gt;data = (char*) buffer;        #ifndef rgfw_x11_dont_convert_bgr            u32 x, y;            for (y = 0; y data[index];                    bitmap-&gt;data[index] = buffer[index + 2];                    bitmap-&gt;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(&amp;wc);    HWND hwnd = CreateWindowA(wc.lpszClassName, "Sample Window", 0,            500, 500, 500, 500,            NULL, NULL, wc.hInstance, NULL);    BITMAPV5HEADER bi = { 0 };    ZeroMemory(&amp;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*) &amp;bi,        DIB_RGB_COLORS,        (void**) &amp;buffer,        NULL,        (DWORD) 0);    HDC hdcMem = CreateCompatibleDC(hdc);       ShowWindow(hwnd, SW_SHOW);    UpdateWindow(hwnd);    MSG msg;    BOOL running = TRUE;    while (running) {        if (PeekMessageA(&amp;msg, hwnd, 0u, 0u, PM_REMOVE)) {            TranslateMessage(&amp;msg);            DispatchMessage(&amp;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

(0)
上一篇 2024-08-20 12:01
下一篇 2024-08-20 12:01

相关推荐

联系我们

在线咨询: QQ交谈

邮件:442814395@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信公众号