从零开始手敲次世代游戏引擎(九)

从零开始手敲次世代游戏引擎(九)

上一篇我们在Linux上面通过XCB创建了一个基本的窗口。

既然画布已经准备好,接下来就应该是准备画笔进行作画的阶段了。让我们在Windows和Linux这两个版本的窗口上各自绘制一个矩形。

首先我们来看Windows版本。依然回到我们的Platform\Windows目录。上一次我们是使用我们自己编译的Clang工具链进行编译的。这次我们用Visual Studio自带的cl.exe进行编译:

D:\wenli\Source\Repos\GameEngineFromScratch\Platform\Windows>cl -l user32.lib helloengine_win.c
用于 x86  Microsoft (R) C/C++ 优化编译器 19.11.25506 
版权所有(C) Microsoft Corporation保留所有权利

cl: 命令行 warning D9002 :忽略未知选项-l
helloengine_win.c
Microsoft (R) Incremental Linker Version 14.11.25506.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:helloengine_win.exe
user32.lib
helloengine_win.obj

可以看到,编译正常,没有任何问题。这是因为我们的代码是严格按照C/C++标准写的,Clang这方面的检查比Visual C++要严格很多,因此在Clang上面能够编译的代码,在Visual C++上面一般也是没有任何问题可以编译的。(当然,严格来说,Clang可以兼容gcc的一些gnu扩展。这些扩展是Visual C++所不能接受的。因此,并不是说Clang可以通过的代码VC++就一定能通过,这里面还有一个条件就是不要使用任何编译器特定的扩展)

好了,下面给我们的helloengine_win.c添加几行绘图指令(下面是通过git diff显示的文件变化情况。左侧有一个+号的行是本次新加的)

D:\wenli\Source\Repos\GameEngineFromScratch\Platform\Windows>git diff helloengine_win.c
diff --git a/Platform/Windows/helloengine_win.c b/Platform/Windows/helloengine_win.c
index 041462a..b996344 100644
--- a/Platform/Windows/helloengine_win.c
+++ b/Platform/Windows/helloengine_win.c
@@ -77,6 +77,17 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara
     // sort through and find what code to run for the message given
     switch(message)
     {
+       case WM_PAINT:
+           {
+               PAINTSTRUCT ps;
+               HDC hdc = BeginPaint(hWnd, &ps);
+               RECT rec = { 20, 20, 60, 80 };
+               HBRUSH brush = (HBRUSH) GetStockObject(BLACK_BRUSH);
+
+               FillRect(hdc, &rec, brush);
+
+               EndPaint(hWnd, &ps);
+           } break;
         // this message is read when the window is closed
         case WM_DESTROY:
             {

然后编译这个程序。因为我们使用了GetStockObject这个函数,这个函数属于GDI接口(就是我前面提到过的,因为爆慢而最后导致不得不推出Direct X的接口),我们需要在编译的时候加上gdi32.lib这个库。

D:\wenli\Source\Repos\GameEngineFromScratch\Platform\Windows>cl user32.lib gdi32.lib helloengine_win.c

运行生成的程序,看到如下画面:


很好,如果我们再在右边画个方块,中间画个圆圈,并且加入一点碰撞计算的代码和键盘操作代码的话,那么一个Ping-pong游戏(乒乓游戏)就完成了。那就到达了二十几岁乔布斯走过的地方:)

不过不要忘了我们目前是在图形支线任务里面。所以让我们暂时不要去管碰撞计算,也不要管键盘操作。让我们Save我们的代码,然后切换到Linux平台。

D:\wenli\Source\Repos\GameEngineFromScratch\Platform\Windows>git add helloengine_win.c

D:\wenli\Source\Repos\GameEngineFromScratch\Platform\Windows>git commit -m "in the middle of article_9"
[master 7f05a0e] in the middle of article_9
 1 file changed, 11 insertions(+)

首先,让我们如下修改我们的helloengine_xcb.c:

diff --git a/Platform/Linux/helloengine_xcb.c b/Platform/Linux/helloengine_xcb.c
index 62cb467..7e44b48 100644
--- a/Platform/Linux/helloengine_xcb.c
+++ b/Platform/Linux/helloengine_xcb.c
@@ -75,6 +75,11 @@ int main(void) {
        while((pEvent = xcb_wait_for_event(pConn)) && !isQuit) {
                switch(pEvent->response_type & ~0x80) {
                case XCB_EXPOSE:
+                   {
+                       xcb_rectangle_t rect = { 20, 20, 60, 80 };
+                       xcb_poly_fill_rectangle(pConn, window, foreground, 1, &rect);
+                       xcb_flush(pConn);
+                   }
                        break;
                case XCB_KEY_PRESS:
                        isQuit = 1;
@@ -83,6 +88,8 @@ int main(void) {
                free(pEvent);
        }

+       xcb_disconnect(pConn);
+
        return 0;

最后的xcb_disconnect是上次漏掉的,补上。任何事情要善始善终,Connect了就一定要Disconnect。

注意这里有一个小小的Trick。因为我们的文件后缀名为.c,所以Clang会将我们的代码作为C代码来编译。在C代码当中,变量的定义必须出现在每个block的开始,而不能夹杂在语句之间。但是,有些变量我们只有在函数当中某个地方才会使用,放在函数体的头上也怪怪的。比如这个rect。

所以,我们在这里使用了{},将这部分声明为一个语句块,也就是block。这样我们就可以在这里面申明变量了。

当然,还有一个简便的方法。你可以把文件后缀改为.cpp。因为所有合法的.c都是合法的.cpp,而C++允许在语句中间申明变量。

不过我依然不鼓励这么做。就像我前面说的,要脱离Visual Studio。舒服的环境只会使人模棱两可。我们首先应该精确地掌握各种概念,在这个基础之上,选择舒服方便的方法,才是正确的。

好了,编译这个代码:

tim@iZuf6iup3mphicesefdwajZ:~/src/GameEngineFromScratch/Platform/Linux$ clang -lxcb -o helloengine_xcb helloengine_xcb.c

执行它,看到如下画面:


好了,我们在Linux上面也实现了同样的效果。保存我们的代码,准备迈出下一步。

tim@iZuf6iup3mphicesefdwajZ:~/src/GameEngineFromScratch/Platform/Linux$ git status
# On branch article_8
# Your branch is ahead of 'origin/article_8' by 1 commit.
#   (use "git push" to publish your local commits)
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   helloengine_xcb.c
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       helloengine_xcb
no changes added to commit (use "git add" and/or "git commit -a")
tim@iZuf6iup3mphicesefdwajZ:~/src/GameEngineFromScratch/Platform/Linux$ git add helloengine_xcb.c
tim@iZuf6iup3mphicesefdwajZ:~/src/GameEngineFromScratch/Platform/Linux$ git commit -m "end of article_9"
[article_8 c502b89] end of article_9
 1 file changed, 7 insertions(+)

(-- EOF --)

参考引用:

  1. Basic Graphics Programming With The XCB Library
  2. tutorial
  3. XCB - Wikipedia


本作品采用知识共享署名 4.0 国际许可协议进行许可。

编辑于 2018-09-01 16:44