首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

Win32 組合語言繪圖實戰:用 GDI 繪製太極八卦圖

     編輯:組合語言

專案背景

在學習 Win32 組合語言圖形程式設計時,嘗試以 GDI API 復刻 C# 版太極八卦圖繪製邏輯。本文完整展示從算法分析到 MASM32 實作的全過程。

算法分析:八卦圖幾何構成

半徑 R 為基準參數,圖形包含 6 個基本圖元:

  1. 外圓:半徑 R
  2. 左半圓 (白):中心 (0,0),起始角 -90°,掃掠 -180°
  3. 右半圓 (黑):中心 (0,0),起始角 90°,掃掠 -180°
  4. 上小圓 (白):中心 (R/2, R/4),半徑 R/4
  5. 下小圓 (黑):中心 (R/2, 3R/4),半徑 R/4
  6. 左小圓 (黑):中心 (9R/20, R/5),半徑 R/20
  7. 右小圓 (白):中心 (9R/20, 7R/10),半徑 R/20

GDI API 對應關係

核心繪圖程序:_PaintTaiJi

_PaintTaiJi proc
  LOCAL hBrush:HBRUSH   ; 黑畫刷
  LOCAL wBrush:HBRUSH   ; 白畫刷
  LOCAL hPen:HPEN       ; 白畫筆

  ; 1. 繪製外圓邊框
  invoke Ellipse, hDc, 0, 0, 200, 200

  ; 2. 取得系統預設畫刷
  invoke GetStockObject, BLACK_BRUSH
  mov hBrush, eax
  invoke GetStockObject, WHITE_BRUSH    ; 注意:原碼用 DC_BRUSH 非標準,此處修正
  mov wBrush, eax

  ; 3. 左半扇形 (黑)
  invoke SelectObject, hDc, hBrush
  invoke Pie, hDc, 0, 0, 200, 200, 100, 0, 100, 200

  ; 4. 右下小圓 (白) - 修飾右半圓邊界
  invoke Ellipse, hDc, 50, 100, 150, 200

  ; 5. 切換白畫刷
  invoke SelectObject, hDc, wBrush

  ; 6. 右上小扇形 (白)
  invoke Pie, hDc, 50, 0, 150, 100, 100, 0, 100, 100

  ; 7. 上小白圓 (陰中之陽)
  invoke Ellipse, hDc, 95, 145, 105, 155

  ; 8. 擦除上小圓殘留邊框 (白線覆蓋)
  invoke MoveToEx, hDc, 100, 1, NULL
  xor eax, eax
  mov ah, 255
  mov al, 255
  shl eax, 8
  mov al, 255              ; eax = 0x00FFFFFF (白色)
  invoke CreatePen, PS_SOLID, 2, eax
  mov hPen, eax
  invoke SelectObject, hDc, hPen
  invoke LineTo, hDc, 99, 99

  ; 9. 下小黑圓 (陽中之陰)
  invoke SelectObject, hDc, hBrush
  invoke Ellipse, hDc, 95, 45, 105, 55

  ret
_PaintTaiJi endp

完整 MASM32 專案程式碼

.386
.model flat, stdcall
option casemap:none

include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include gdi32.inc
includelib gdi32.lib

.data?
  hInstance dd ?
  hWinMain  dd ?
  stPs      PAINTSTRUCT <>
  stRect    RECT <>
  hDc       dd ?

.const
  szClassName db 'MyTaiJi', 0
  szCaptionMain db '組合語言繪製太極八卦圖', 0

.code

;--- 視窗程序 ---
_ProcWinMain proc uses ebx edi esi, hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
  mov eax, uMsg
  .if eax == WM_PAINT
    invoke BeginPaint, hWnd, addr stPs
    mov hDc, eax
    invoke GetClientRect, hWnd, addr stRect
    call _PaintTaiJi
    invoke EndPaint, hWnd, addr stPs
  .elseif eax == WM_CLOSE
    invoke DestroyWindow, hWinMain
    invoke PostQuitMessage, NULL
  .else
    invoke DefWindowProc, hWnd, uMsg, wParam, lParam
    ret
  .endif
  xor eax, eax
  ret
_ProcWinMain endp

;--- 建立視窗與訊息迴圈 ---
_WinMain proc
  local @stWndClass:WNDCLASSEX
  local @stMsg:MSG

  invoke GetModuleHandle, NULL
  mov hInstance, eax

  invoke RtlZeroMemory, addr @stWndClass, sizeof @stWndClass
  invoke LoadCursor, NULL, IDC_ARROW
  mov @stWndClass.hCursor, eax
  push hInstance
  pop @stWndClass.hInstance
  mov @stWndClass.cbSize, sizeof WNDCLASSEX
  mov @stWndClass.style, CS_HREDRAW or CS_VREDRAW
  mov @stWndClass.lpfnWndProc, offset _ProcWinMain
  mov @stWndClass.hbrBackground, COLOR_WINDOW + 1
  mov @stWndClass.lpszClassName, offset szClassName
  invoke RegisterClassEx, addr @stWndClass

  invoke CreateWindowEx, WS_EX_CLIENTEDGE, \
    offset szClassName, offset szCaptionMain, \
    WS_OVERLAPPEDWINDOW, \
    100, 100, 600, 400, \
    NULL, NULL, hInstance, NULL
  mov hWinMain, eax

  invoke ShowWindow, hWinMain, SW_SHOWNORMAL
  invoke UpdateWindow, hWinMain

  .while TRUE
    invoke GetMessage, addr @stMsg, NULL, 0, 0
    .break .if eax == 0
    invoke TranslateMessage, addr @stMsg
    invoke DispatchMessage, addr @stMsg
  .endw
  ret
_WinMain endp

;--- 程式入口 ---
start:
  call _WinMain
  invoke ExitProcess, NULL
end start

關鍵技術細節

  1. 座標系統:GDI 使用邏輯座標,原點在客戶區左上角,X 向右、Y 向下
  2. Pie 參數:`Pie(hdc, x1, y1, x2, y2, x3, y3, x4, y4)` 以矩形 `(x1,y1)-(x2,y2)` 為邊界,`(x3,y3)` 為起始弧端點,`(x4,y4)` 為結束弧端點
  3. GDI 物件管理:`SelectObject` 返回舊物件,繪圖結束應恢復 (本範例為簡化省略)
  4. 色彩格式:`CreatePen` 參數為 `COLORREF` (0x00BBGGRR),白色 = 0x00FFFFFF
  5. 編譯環境:MASM32 v8+ / RadASM / Windows XP SP2 以上

執行結果

太極八卦圖執行結果

延伸練習

  • 加入 `WM_SIZE` 處理,支援視窗縮放時圖形自適應
  • 使用 `SetWorldTransform` 實現旋轉動畫
  • 嘗試用 `Path` API (BeginPath/EndPath/StrokeAndFillPath) 重構繪圖邏輯
  • 移植至 x64 組合語言 (調整呼叫慣例、暫存器使用)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
C# GDI+Win32 GDI用途
Graphics.FillPiePie繪製填充扇形 (半圓)
Graphics.FillEllipseEllipse + 畫刷繪製填充橢圓/圓
Brushes.White/BlackGetStockObject(WHITE_BRUSH/BLACK_BRUSH)取得系統預設畫刷
PenCreatePen / GetStockObject建立/取得畫筆
-SelectObject將 GDI 物件選入 DC
-MoveToEx/LineTo繪製直線 (修飾細節)