RGFW 底层:软件渲染

2024-08-20 0 991

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

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上,没有太多设置,大部分工作都是在渲染过程中完成的。

你只需要分配缓冲区数据即可。

1

u8* buffer = malloc(rgfw_buffersize.w * rgfw_buffersize.h * 4);

第2步(绘制到缓冲区)

在本教程中,我将使用 silk.h 绘制到缓冲区。 silk.h是一个单头软件渲染图形库。

首先包括丝绸,

1

2

3

4

#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

1

2

3

4

5

6

7

8

9

10

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

1

2

3

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

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。

1

2

deletedc(hdcmem);

deleteobject(bitmap);

macos 上必须使用release.

1

2

3

release(bitmap);

release(image);

free(buffer);

完整的例子

x11

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

// 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>

视窗

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

// 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>

登录后复制

 

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

免责声明
1. 本站所有资源来源于用户上传和网络等,如有侵权请邮件联系本站整改team@lcwl.fun!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系本站工作人员处理!
6. 本站资源售价或VIP只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 因人力时间成本问题,部分源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别!
9.本站所有源码资源都是经过本站工作人员人工亲测可搭建的,保证每个源码都可以正常搭建,但不保证源码内功能都完全可用,源码属于可复制的产品,无任何理由退款!

网站搭建学习网 C RGFW 底层:软件渲染 https://www.xuezuoweb.com/14411.html

常见问题
  • 本站所有的源码都是经过平台人工部署搭建测试过可用的
查看详情
  • 购买源码资源时购买了带主机的套餐是指可以享受源码和所选套餐型号的主机两个产品,在本站套餐里开通主机可享优惠,最高免费使用主机
查看详情

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务

Fa快捷助手
手机编程软件开发

在手机上用手点一点就能轻松做软件

去做软件
链未云主机
免备案香港云主机

开通主机就送域名的免备案香港云主机

去使用
链未云服务器
免备案香港云服务器

支持售后、超低价、稳定的免备案香港云服务器

去使用