本文共 19606 字,大约阅读时间需要 65 分钟。
The tile control is already made, now it's time for the drawing of the tiles. The tile image can be one of these images:
图块已经被创建了,现在是画图块的时候了。图块的图象可以是这些图象中的一个:
For now we will use the numbered tiles, the bitmap stuff will be added later. Furthermore, there are 4 color schemes.
现在,我们将使用编号的图块,位图的内容将在后面添加。此外,还有4种颜色。
We'll use device contexts many times. A device context is a set of graphic s that affect the output. These graphic objects can be pens, bitmaps, brushes, palette etc. The device contexts we use are:
我们将多次使用device context(设备环境)。一个device context是一些影响输出的图形物体的集合。这些物体可以是pen,bitmap,brushes,palette等。我们使用的device context有:
First the bitmap the user chooses, (the numbered tiles, which are drawn at runtime, the demo bitmap or a user bitmap), is put in the ImageDC. Then the 3D effect of the tiles (highlites and shadows) are drawn on the bitmap in the DC. Now remember this: The imageDC will not change from here, only if the user s another tile type. The drawing is done tile by tile on the back buffer. For each tile, the tile is extracted from the ImageDC, then placed at the current position of that tile. An array will hold the tile positions.
首先,用户选择的图片(在运行时绘出的编号图块,演示图片,或用户图片)被放入图象DC。然后图块的3d效果在DC中绘在图片上。现在记住这个:在这,图象DC不会改变。只有当用户选择了另一个图块类型时才会。绘画工作是在back buffer中一图块一图块的完成的。对于每个图块,那个图块从图象DC中展开,然后放入那个图块的当前位置。一个数组将保存这些图块的位置。
A new procedure is introduced, InitBitmaps:
引入一个新的过程,InitBitmap:
InitBitmaps PROTO STDCALL :D
[in your .data?]BackBufferDC dd ?hBackBuffer dd ?ImageDC dd ?hImage dd ? hBackgroundColor dd ?hTileColor dd ?hFont dd ?TextColor dd ?[in your .data]FontFace "Arial",0[in your .code];================================================================================; Init Bitmaps;================================================================================InitBitmaps proc hWnd:DWORD; Create DC's for backbuffer and current image invoke CreateCompatibleDC, NULL mov BackBufferDC, eax invoke CreateCompatibleDC, NULL mov ImageDC, eax; Create bitmap for backbuffer: invoke GetDC, hWnd push eax invoke CreateCompatibleBitmap, eax, 200+20,200+20 mov hBackBuffer, eax pop eax invoke ReleaseDC, hWnd, eax invoke SelectObject, BackBufferDC, hBackBuffer ; Create Arial font for the numbers invoke CreateFont, -30, NULL, NULL, NULL, FW_EXTRABOLD, FALSE, FALSE, FALSE, NULL, NULL, NULL, NULL, NULL, ADDR FontFace mov hFont, eax; Select font in Image DC invoke SelectObject, ImageDC, hFont invoke CreateSolidBrush, 0FF8000h mov hBackgroundColor, eax invoke CreateSolidBrush, 0FF8080h mov hTileColor, eax mov TextColor, 0800000hretInitBitmaps endpLet's examine the procedure step by step:
让我们一步步的看这个过程:
invoke CreateCompatibleDC, NULL
mov BackBufferDC, eax invoke CreateCompatibleDC, NULL mov ImageDC, eaxCreateCompatibleDC creates a new DC that is compatible with a given window. If NULL is given as parameter (window handle), it is compatible with the default window. One DC is created for the backbuffer, the handle is stored in BackBufferDC. The other is for the image DC, stored in ImageDC.
CreateCompatibleDC创建一个和给定的窗口兼容的新的DC。如果NULL作为参数(窗口句柄)给出,它是和缺省窗口兼容。一个为back buffer创建的DC的句柄保存在backbufferDC中。另一个是图象DC,存于ImageDC中。
; Create bitmap for backbuffer:
invoke GetDC, hWnd push eax invoke CreateCompatibleBitmap, eax, 200+20,200+20 mov hBackBuffer, eax pop eax invoke ReleaseDC, hWnd, eax invoke SelectObject, BackBufferDC, hBackBufferCreateCompatibleBitmap creates a new bitmap object that is compatible with a given DC. First we get the DC of the main window with GetDC. The handle is pushed onto the stack to save it for ReleaseDC. CreateCompatibleBitmap is then called, with the main window DC as DC, and 220x220 as bitmap size. The extra 20 pixels are for the margins. The bitmap handle is saved in hBackBuffer, the window DC handle is popped of the stack again and released (ReleaseDC should always be used with GetDC). Finally, SelectObject selects a graphic object in a DC. Here, the bitmap just created is put in the backbuffer DC.
CreateCompatibleBitmap创建一个和给定的DC兼容的图片。首先我们用GetDC获得主窗口的DC。这个句柄为ReleaseDC压入栈中保存。然后用主窗口的DC和220×220作为图片大小CreateCompatibleBitmap。额外的20象素用于边框。图片句柄存于hBackBuffer,窗口DC句柄再被弹出栈然后释放(ReleaseDC总是和GetDC一起使用)最后,SelectObject在DC中选择一个图片对象。这儿,刚创建的bitmap被放入backbufferDC中。
; Create Arial font for the numbers
invoke CreateFont, -30, NULL, NULL, NULL, FW_EXTRABOLD, FALSE, FALSE, FALSE, NULL, NULL, NULL, NULL, NULL, ADDR FontFace mov hFont, eax; Select font in Image DC invoke SelectObject, ImageDC, hFontTo draw the numbers on the tiles, we need a font. CreateFont creates such a font. Look it up in your reference, FontFace is the name of the font, "Arial". -30 is a size for the font. The handle for the font is saved in hFont and then the font is selected in the ImageDC so we can write with the font on the image DC.
要在图块上画数字,我们要字体。CreateFont创建这样一个字体。在你的参考中查找它。FontFace是字体名,“Arial”,-30是字体的大小。字体的句柄存于hFont中然后字体被ImageDC选择因而我们可以在imageDC中用这个字体写字了。
invoke CreateSolidBrush, 00FFFFFFh
mov hBackgroundColor, eax invoke CreateSolidBrush, 00FF0000h mov hTileColor, eax mov TextColor, 000000hFinally, a few brush handles are made, they are not selected in any DC right now, but they will be later. CreateSolidBrush creates a brush with a certain color, you can use the handle to draw things (lines etc) with the brush. TextColor is not a brush, it's just a color value (we don't need a brush for the text color, only the color value).
最后,一个画刷的句柄被创建,它们现在没有被任何DC选择,但在以后会。CreateSolidBrush创建一个有一定颜色的画刷,你可以用这个句柄来用刷子画东西(比如直线)。TextColor不是刷子,它只是颜色值(我们不因文本颜色需要刷子,只是颜色值)
Note: the image bitmap is not created yet, the DC is already available, but as the user can choose the type of bitmap, this bitmap is made when the user selects a type, then it is selected in the DC.
注意:图象图片仍未被创建,DC已经存在了。但用户可以选择图片类型。图片在用户选择类型时创建,然后在DC中被选择。
A function to free all these handles is necessary too:
一个用于释放所有这些句柄的也是必要的:
DeleteBitmaps PROTO STDCALL
;================================================================================; Delete Bitmaps;================================================================================DeleteBitmaps proc invoke DeleteDC, BackBufferDC invoke DeleteDC, ImageDC invoke DeleteObject, hImage invoke DeleteObject, hBackBuffer invoke DeleteObject, hFont invoke DeleteObject, hBackgroundColor invoke DeleteObject, hTileColorretDeleteBitmaps endpThen both functions should be called:
然后要调用两个函数:
...
.IF eax==WM_CREATE invoke InitControls, hWnd invoke InitBitmaps, hWnd ;<<.ELSEIF eax==WM_DESTROY invoke DeleteBitmaps ;<< invoke PostQuitMessage, NULL...On creation of the main window, the bitmaps and DCs are initialized, before destroying, the bitmaps and DCs are deleted again.
在主窗口的创建过程中,图片和DC被初始化。在窗口摧毁前,图片和DC被再次删除。
Create a new procedure, SetBitmap:
创建一个新的过程,SetBitmap:
[in mosaic.inc]
IMAGETYPE_STANDARD equ 0IMAGETYPE_NUMBERS equ 1IMAGETYPE_BITMAP equ 2[in .data?]
CurImageType dd ? ;Current image type[in .code]
SetBitmap PROTO STDCALL :DWORD, :DWORD;================================================================================; Set Bitmap;================================================================================SetBitmap proc hWnd:DWORD, ImageType:DWORD mov eax, ImageType .IF eax==IMAGETYPE_NUMBERS ;--- delete old image --- invoke DeleteObject, hImage ;--- Get DC --- invoke GetDC, hWnd push eax ;--- Create new bitmap for the numbers bitmap --- invoke CreateCompatibleBitmap, eax, 200, 200 mov hImage, eax pop eax ;--- Release DC --- invoke ReleaseDC, hWnd, eax ;--- Select new bitmap in DC --- invoke SelectObject, ImageDC, hImage ;--- Draw numbers on the bitmap --- invoke DrawNumbers ;--- Create the 3D effect on the bitmap --- invoke CreateTiles .ENDIF ;--- Set the new image type --- mov eax, ImageType mov CurImageType, eaxretSetBitmap endpThe SetBitmap procedure selects the type of image to use for the tiles. The procedure takes 2 parameters: hWnd, the handle of the main window, and ImageType, which can be one of these constants: IMAGETYPE_STANDARD, IMAGETYPE_NUMBERS, IMAGETYPE_BITMAP. These constants are defined in the include file. Right now, the procedure only reacts to IMAGETYPE_NUMBERS, we will implement the other two later. When the numbers image type is chosen, the old image (hImage) is deleted, and a new one is created with CreateCompatibleBitmap. Then two functions are called, DrawNumbers and CreateTiles, which are defined in the code below. DrawNumbers just draws an array of numbers on the new bitmap. CreateTiles draws the 3D effect on the bitmap. The CreateTiles procedure will be used for the other two image types too.
SetBitmap过程选择了用于图块的图象类型。过程带2个参数,hWnd主窗口句柄和图片类型。图片类型可以为这些常数中的一个:IMAGETYPE_STANDARD, IMAGETYPE_NUMBERS, IMAGETYPE_BITMAP。这些常数在包含中定义了。当前,过程仅对IMAGETYPE_NUMBERS作出反应,我们将在后面实现另外的两个。当编号图片类型被选择,旧的图象(hImage)被删除,而新的由CreateCompatibleBitmap创建。然后两个函数被调用,DrawNumbers 和 CreateTiles,它们在下面的代码中定义。Draw Numbers只是在新的图片上画上数字。CreateTiles在图片上画上3D效果。CreateTile过程也将在其他的两种图象类型中使用。
GetCoordinates PROTO STDCALL :DWORD
DrawNumbers PROTO STDCALL.dataNumberFormat db "%lu",0Rect200 RECT <0,0,200,200>.data?Buffer db 200 dup (?).code;================================================================================; Draw Numbers;================================================================================DrawNumbers proc uses ebx ediLOCAL TempRect:RECT ; --- Set the textcolor of ImageDC to TextColor --- invoke SetTextColor, ImageDC, TextColor ; --- Fill the imageDC with the tile color brush --- invoke FillRect, ImageDC, ADDR Rect200, hTileColor ; --- Set the background mode to transparent (for the text) --- invoke SetBkMode, ImageDC, TRANSPARENT ; --- L through all the numbers and draw them one by one --- xor ebx, ebx .WHILE ebx<16 mov eax, ebx inc eax invoke GetCoordinates, eax mov dx, ax ; dx = row shr eax, 16 ; ax = column and edx, 0ffffh ; make sure that edx = dx imul edx, edx, 50;} Multipy edx as well as eax with 50 imul eax, 50 ;} mov TempRect.left, eax mov TempRect.top, edx add eax, 50 add edx, 50 mov TempRect.right, eax mov TempRect.bottom, edx mov eax, ebx inc eax invoke wsprintf, ADDR Buffer, ADDR NumberFormat, eax invoke DrawText, ImageDC, ADDR Buffer, -1, ADDR TempRect, DT_CENTER or DT_SINGLELINE or DT_VCENTER inc ebx .ENDWretDrawNumbers endp;================================================================================; GetCoordinates;================================================================================GetCoordinates proc dwTile:DWORD mov eax, dwTile dec eax cdq mov ecx, 4 div ecx ;eax=quotient = row ;edx=remainder = column shl edx, 16 add eax, edxretGetCoordinates endpTwo new procedures here, GetCoordinates is a little procedure that will be used several times in the program. It uses a 0-based index of the tiles (tile 0, tile 1, tile 2) etc. and returns the row of the tile (0,1,2,3) in the low word of eax, the column of the tile (0,1,2,3) in the high word of eax. The calculation is quite simple. Div the tile index by 4, the remainder will be the column, the quotient the row of the tile. The shl instruction shifts the colomn in the high word (shift 16 bits left), and add adds the row.
这儿有两个过程,GetCoordinates是一个将在中多次使用的小过程。它使用0开始的图块(图块0,图块1,图块2)等,并在eax的低字中返回图块所在的排(0,1,2,3),在eax的高字中返回图片所在的纵行(0,1,2,3)。计算很简单,把图块的索引除4,余数为纵行数,商为图块所在的排数。Shl指令移动高字中的行数(左移16位),而add加上排数。
The DrawNumbers procedure works like this:
DrawNumbers过程的工作原理如下:
Set textcolor to the value of the TextColor variable
Fill the complete bitmap with the tilecolor brush (rect200 is a RECT structure that defines the area of 200x200 pixels starting at (0,0))Set the background mode to TRANSPARENT to prevent an ugly background around the text.设置文本颜色为TextColor变量的值。用图块颜色的刷子填充完整的图片(rect200是一个定义了从(0,0)开始的200×200象素区域的结构)设置背景模式为TRANSPARENT,以防止难看字背景的空色。
The tile loop:
Tile循环
Loop from 0 to 15 {
- GetCoordinates(currentloopvalue) - Extract row and column from return value multiply the row and the column with 50 (this gives the image coordinates of the tile) - Fill a RECT structure (TempRect) with the coordinates of the tile. - Use wsprintf to convert the tile number into text. (NumberFormat is the format the number should be outputted in, buffer is a temporary buffer) - Use DrawText to draw the number at the right coordinates}从0到15开始循环{
-获得坐标(当前的循环值)
-从返回值中解开行和列的值。用行数和列数乘以50(这给出了图块的图象坐标)-用图块坐标填写RECT结构(临时结构)-使用wsPrint把图块数翻译为文本。(NumberFormat是数字应被输出的给世,buffer是一个临时缓存)-使用DrawText在恰当处绘出数字。CreateTiles draws the button-style 3D effect on the tiles by drawing black & white lines at the right places:
CreateTiles通过在恰当地方会上黑和白的线条在图块上绘出3D效果。
CreateTiles PROTO STDCALL
;================================================================================; Create Tiles;================================================================================CreateTiles proc uses ebx esi edi invoke GetStockObject, BLACK_PEN invoke SelectObject, ImageDC, eax; Dark lines, vertical. x = 50k - 1 (k=1,2,3,4); ebx = k; esi = x xor ebx, ebx inc ebx ; ebx is 1 now .WHILE ebx<5 ; (ebx= 1,2,3,4) mov eax, 50 mul ebx mov esi, eax dec esi invoke MoveToEx, ImageDC, esi, 0, NULL invoke Lo, ImageDC, esi, 199 inc ebx .ENDW; Dark lines, horizontal. y = 50k - 1 (k=1,2,3,4); ebx = k; esi = y xor ebx, ebx inc ebx ; ebx is 1 now .WHILE ebx<5 ; (ebx= 1,2,3,4) mov eax, 50 mul ebx mov esi, eax dec esi invoke MoveToEx, ImageDC, 0, esi, NULL invoke LineTo, ImageDC, 199, esi inc ebx .ENDW invoke GetStockObject, WHITE_PEN invoke SelectObject, ImageDC, eax; Light lines, vertical. x = 50k (k=0,1,2,3); ebx = k; esi = x xor ebx, ebx .WHILE ebx<4 ; (ebx= 0,1,2,3) mov eax, 50 mul ebx mov esi, eax invoke MoveToEx, ImageDC, esi, 0, NULL invoke LineTo, ImageDC, esi, 199 inc ebx .ENDW; Light lines, horizontal. y = 50k (k=0,1,2,3); ebx = k; esi = y xor ebx, ebx ; ebx is 1 now .WHILE ebx<4 ; (ebx= 0,1,2,3) mov eax, 50 mul ebx mov esi, eax invoke MoveToEx, ImageDC, 0, esi, NULL invoke LineTo, ImageDC, 199, esi inc ebx .ENDW retCreateTiles endpThis procedure is quite easy to understand. It draws 4 sets of lines. Each line is drawn by first getting a brush with GetStockObject (retrieves a standard brush color from windows). This brush is selected in the imagedc. Then the current point is moved to the startpoint of the line with MoveToEx, and the line is drawn with LineTo.
这个过程很容易理解。它画4条线。每条线先由GetStockObject获得刷子(从窗口取得标准刷颜色)。这个刷子在imageDC中被选择然后当前位置被MoveToEX移到线的起点,而线由LineTo绘出。
The procudure below will be used in the future too, but the code of it is temporary right now, it just draws the image DC on the static control to show if your code worked. Furthermore, some additional procedures are introduced to initialize everything correctly.
下面的过程也将在以后使用。但它的代码现在暂时是正确的。它只是在静态控件上画imageDC来显示你的代码是否在工作。此外,附加的过程被用来正确的初始化每一件东西:
DrawProc PROTO STDCALL :DWORD, :DWORD
InitGame PROTO STDCALL :DWORD[in .code];================================================================================; Draw Numbers;================================================================================DrawProc proc uses ebx edi esi hWnd:DWORD, hDC:DWORD invoke BitBlt, hDC, 9, 9, 220, 220, ImageDC, 0, 0, SRCCOPYretDrawProc endp;================================================================================; InitGame;================================================================================InitGame proc hWnd:DWORD invoke SetBitmap, hWnd, IMAGETYPE_NUMBERSretInitGame endp[In the WM_CREATE handler of WndProc, below 'invoke InitBitmaps, hWnd'] invoke InitGame, hWnd[In the messagehandler in WndProc, between the other ELSEIFs] .ELSEIF eax==WM_DRAWITEM mov eax, wParam .IF eax==CID_STATIC push ebx mov ebx, lParam assume ebx:ptr DRAWITEMSTRUCT invoke DrawProc, hWnd, [ebx].hdc assume ebx:nothing pop ebx xor eax, eax inc eax .ELSE xor eax, eax .ENDIFThe DrawProc and InitGame are fairly easy to understand. BitBlt copies a part of a bitmap from one DC to another. Here the complete bitmap in ImageDC is copied to the DC of the static control window.
DrawProc和InitGame相当容易理解。BitBlt从一个DC拷贝一部分图片到另一个中。这儿,ImageDC中的完整的图片被拷贝到静态控件窗口的DC中。
The WM_DRAWITEM message requires some more explanation:
WM_DRAWITEM is sent to the main window when one of the owner-drawn controls needs to be drawn. An owner-drawn control is a control that is drawn by the program instead of windows. When this message is sent, wParam contains the ID of the control that needs to be drawn. Here the .IF eax==CID_STATIC finds out if it is the static control (the tiles window) that needs to be drawn. If not (.ELSE), 0 is returned from WndProc (xor eax, eax). 0 tells windows that the message is not handled by the program. lParam is a pointer to a DRAWITEMSTRUCT.WM_DRAWITEM消息需要更多一些的解释:
当一个owner-drawn控件需要绘出时,WM_DRAWITEM被发往主窗口。一个owner-drawn控件是一个由程序而不是由Windows来绘出的控件。消息被发送时,wParam包含了需要绘出的控件的ID。这儿,.IF eax== CID_STATIC找出它是否是需要绘出的静态控件(图块窗口)。如果不是(.ELSE),WndProc返回0(xor eax, eax)。0告诉Windows这个消息没有被程序处理。Iparam是一个指向DRAWITEMSTRUCT的指针。mov ebx, lParam
assume ebx:ptr DRAWITEMSTRUCT invoke DrawProc, hWnd, [ebx].hdc assume ebx:nothingFirst, lParam is put in ebx. Now ebx is a pointer to the DRAWITEMSTRUCT structure. The assume statement gives masm more information about the register. assume ebx:ptr DRAWITEMSTRUCT tells masm that ebx is a pointer to a DRAWITEMSTRUCT structure. Now you can use the structure members directly on ebx. hdc is one of these members, it contains the handle to the device context of the window. The control will show whatever there is on that DC. This DC is passed to DrawProc. Don't forget to tell masm to assume nothing for ebx (assume ebx:nothing), otherwise masm thinks ebx is a pointer to DRAWITEMSTRUCT throughout the whole program. Very important is that you should save ebx in your procedures (that's why the push ebx/pop ebx instructions are included). Windows assumes the values of the ebx, esi and edi registers do not change when your window procedure is called by windows (this applies to all callback functions in windows, always save ebx, esi & edi).
首先,Iparam被放入ebx。现在ebx是一个指向DRAWITEMSTRUCT结构的指针。Assume语句告诉masm关于寄存器的更多信息。Assume ebx:ptr DRAWITEMSTRUCT告诉masm ebx是一个指向DRAWITEMSTRUCT结构的指针。现在你可以使用ebx中的结构成员了。控件将告诉你在那个DC中有什么。这个DC被传递给DrawProc。不要忘记告诉masm assume nothing fo ebx(assume ebx:nothing),否则masm在整个程序都会认为ebx是指向DRAWITEMSTRUCT的指针。非常重要的是你应该在你的过程中保存ebx(这是包含push ebx/pop ebx指令的原因)。Windows假定在你的窗口过程被windows调用时,ebx,esi和edi寄存器的值不会改变(这对Windows中的所有回调函数都是这样,总是保存ebx,esi和edi)
The current project files are here: ?file=mosaic.mosaic4">mosaic4.zip
当前的工程文件在这儿:mosaic4.zip
If you assemble the program and run it, you should see this:
如果你汇序并运行它,你将看到:
ectratio="t" v:ext="edit">
As you can see, the tiles are drawn correctly.
正如你可以看到哦,图块被正确的绘出。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10748419/viewspace-981761/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/10748419/viewspace-981761/