该项目的主要重点是让人们能够通过制作图形来以有趣的方式学习组装编程。该框架删除了学习Windows GUI和Direct X编程的Burdern,并设置了所有锅炉板,然后按照几个说明,可以看到像素完全可以在屏幕上设置在屏幕上,而无需太多努力。另外,编写1990年代风格的图形效果和演示很有趣。
有一个模板演示,您可以用来创建自己的演示场景。您可以通过将代码复制到自己的删除目录来将其用作示例。 * demoscenes yourdemo*所有代码都需要进入AMD64目录,因为这是一个X86-64汇编项目,不应使用任何C或其他Langauges 。源文件将需要修改以更改目标名称。复制MakeFile,但您不修改Make File。要构建项目,您使用BCZ命令。您还需要更新DIRS文件,以便使用Root Directories使用BCZ构建应用程序和库。
发动机将使用三个函数来给您回电。
发动机将使用三个函数来给您回电。
所有这些函数都传递了一个单个参数,该参数是Master.inc中定义的Master_Demo_struct.inc 。这包括“演示”的视频缓冲区以及屏幕的大小以及其他一些信息。
请注意,步幅是视频缓冲区中每条水平线的字节中的实际长度。它包括您不应该画的隐藏部分。因此,使用宽度来计算图纸的边界,但使用大步计算如何到达视频缓冲区中的下一条水平线。但是,您也可以使用双缓冲区库执行图形,并使用Double Buffer API将其更新到屏幕。
有X64挥发性和非挥发性登记册。您可以在MSDN上查看它们:https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx,每个函数调用都将在RSP对准0xffffffffffffffffffffffffffffffff8时发生。如果您打算调用任何功能,则必须将堆栈与0xffffffffffffffff0对齐,因为某些功能会假定他们可以使用需要Alignemnt(例如移动)的指令。如果堆栈不对齐,则可能会在某些较低功能调用中崩溃的风险。
X86-64中的功能调用要求堆栈中保留了4个参数位置。所有堆栈预订都在.entprolog之前完成,以便通过跟踪堆栈中保留的空间数量来工作。前四个参数是RCX或XMM0,RDX或XMM1,R8或XMM2和R9或XMM3。在所需的4个堆栈位置保留后,无论传递多少个参数,都必须在堆栈上传递4之外的参数。当您使用寄存器传递这些参数时,前4个参数也没有填充。但是,该空间可用于被调用的函数来保存参数,因为它们处于挥发性寄存器中,或者使用该空间来保存所需的一切。
Parameter N (Not Required, must be populated with Nth parameter if exists)
...
Parameter 5 (Not Required, must be populated with 5th parameter if exists)
Parameter 4 (Required, but not populated use register)
Parameter 3 (Required, but not populated use register)
Parameter 2 (Required, but not populated use register)
Parameter 1 (Required, but not populated use register)
Return Address
Save registers
Locals
Parameter Frame for Function Calls in this function.
在debug_public.inc中有两个debug宏,第一个是debug_rsp_check_macro,如果不是构建调试,则无能为力,但是当debug构建时,您直接将其放在.end.end.end.end.end.end.end.end.end.end.clog之后,并且会检查RSP是否对齐或INT 3。
.ENDPROLOG
DEBUG_RSP_CHECK_MACRO
您可以使用的下一个宏是debug_function_call,而不是使用呼叫指令。当不启用调试时,此宏仅是调用的。启用调试后,它将在您的功能调用之前保存非挥发寄存器,然后在您的函数函数调用后,它将验证它们是正确的。然后,除了RAX/XMM0之外,它将损坏所有具有垃圾的非挥发寄存器,因为它们可以从功能中返回数据。目的是,如果您假设挥发性寄存器保留了信息,则迫使他们有望造成崩溃或错误,如果您这样做。
;
; Generate new random color
;
DEBUG_FUNCTION_CALL Math_rand
以下描述了目录结构布局。
该框架包含各种功能,您可以通过提供基本的常规功能来加速演示构建。
dbuffer_create
dbuffer_updatescreen
dbuffer_clearbuffer
dbuffer_free
debug_is_enabled
debug_function_call
debug_rsp_check_macro
Engine_debug
frameloop_create
Frameloop_performframe
frameloop_reset
frameloop_free
SOFT3D_INIT
SOFT3D_SETCAMERAROTATION
SOFT3D_SETVIEWDISTANCE
SOFT3D_SETVIEWPOINT
SOFT3D_SETASPECTRATIO
SOFT3D_CONVERT3DTO2D
SOFT3D_CLOSE
vpal_create
VPAL_SETCOLORINDEX
vpal_getColorIndex
vpal_rotate
vpal_rotatereset
vpal_free
prm_drawcircle
prm_drawline
gameengine_init
gameengine_printword
gameengine_loadgif
gameengine_convertimagetosprite
gameengine_displayfullscreenanimatimateImage
gameengine_displayCenteredImage
gameengine_free
inputx64_registerKeypress
inputx64_registerKeyRelease
gif_open
gif_close
gif_numberofimages
gif_getImagesize
gif_getImageWidth
gif_getImageHeight
gif_getimage32bpp
gif_getimage32bpprealtime
GIF_GETALLIMAGE32BPP
以下是如何在演示中使用一些库和框架功能的编码示例。
调色板的创建很简单,您只需提供颜色的数量,然后将返回地址保存为调色板手柄。
MOV RCX, 256
DEBUG_FUNCTION_CALL VPal_Create
TEST RAX, RAX
JZ @Failure_Exit
MOV [VirtualPallete], RAX
然后,您可以为每个颜色索引生成颜色。下面的示例会产生越来越多的白色调色板。如果您使用的是双缓冲区API,则可以采用调色板的手柄并填充视频缓冲区,并带有适当的颜色。
@CreateWhitePalette:
MOV RAX, R12
MOV AH, AL
SHL RAX, 8
MOV AL, AH
MOV R8, RAX
MOV RDX, R12
MOV RCX, [VirtualPallete]
DEBUG_FUNCTION_CALL VPal_SetColorIndex
INC R12
CMP R12, 256
JB @CreateWhitePalette
使用以下定义的API简单的双缓冲区的创建非常简单。
MOV RDX, 1 ; 1 Byte Per pixels
MOV RCX, RSI ; MASTER_DEMO_STRUCT
DEBUG_FUNCTION_CALL DBuffer_Create
MOV [DoubleBufferPointer], RAX
TEST RAX, RAX
JZ @Failure_Exit
可以根据指定的像素大小直接访问返回的指针作为屏幕高度x宽度。
MOV RCX, [DoubleBufferPointer]
MOV BYTE PTR [RCX], 10h
然后可以通过单个功能调用更新屏幕。
;
; Update the screen with the buffer
;
MOV RCX, [DoubleBufferPointer]
MOV RDX, [VirtualPallete]
MOV R8, DB_FLAG_CLEAR_BUFFER
DEBUG_FUNCTION_CALL Dbuffer_UpdateScreen
paramhelp_public.inc中的demoscene.inc中包含宏和结构,提供了一种快速简便的方法来设置本地堆栈框架。要记住的一件事是,如今,堆栈空间确实是免费的,因此在这个简单的演示框架中,您不需要的堆栈空间将节省一些时间,而不是将每个堆栈专门针对所需的空间量身定制。但是,您只能保存实际计划使用的寄存器来限制执行时间。标题文件中有宏可以通过为您提供结构和宏来保存和保存寄存器来提供帮助。如果您需要使用本地变量,则需要创建自己的其他结构,如果您只想保存一些寄存器,则可能需要手动保存这些寄存器以及宏只有距离远处并保存所有寄存器或一些特定的寄存器。
std_function_stack_min定义为所有非挥发性通用寄存器和8个用于函数调用的参数。下面的示例显示了使用它仅保存几个必需的GP寄存器。
alloc_stack(SIZEOF STD_FUNCTION_STACK_MIN)
save_reg rdi, STD_FUNCTION_STACK_MIN.SaveRegs.SaveRdi
save_reg rbx, STD_FUNCTION_STACK_MIN.SaveRegs.SaveRbx
save_reg rsi, STD_FUNCTION_STACK_MIN.SaveRegs.SaveRsi
save_reg r12, STD_FUNCTION_STACK_MIN.SaveRegs.SaveR12
.ENDPROLOG
DEBUG_RSP_CHECK_MACRO
... Function Code ...
MOV RSI, STD_FUNCTION_STACK_MIN.SaveRegs.SaveRsi[RSP]
MOV RDI, STD_FUNCTION_STACK_MIN.SaveRegs.SaveRdi[RSP]
MOV rbx, STD_FUNCTION_STACK_MIN.SaveRegs.SaveRbx[RSP]
MOV r12, STD_FUNCTION_STACK_MIN.SaveRegs.SaveR12[RSP]
ADD RSP, SIZE STD_FUNCTION_STACK_MIN
MOV EAX, 1
RET
但是,有一个宏可以使您可以保存和还原所有GP寄存器。一个例子如下所示。
alloc_stack(SIZEOF STD_FUNCTION_STACK_MIN)
SAVE_ALL_STD_REGS STD_FUNCTION_STACK_MIN
.ENDPROLOG
DEBUG_RSP_CHECK_MACRO
... Function Code ...
RESTORE_ALL_STD_REGS STD_FUNCTION_STACK_MIN
ADD RSP, SIZE STD_FUNCTION_STACK_MIN
MOV EAX, 1
RET
下面显示了最低限度的定义,并且总有两个版本。第一个是当前功能的堆栈分配,第二个包括对从呼叫者传递给它的堆栈参数的访问。
STD_FUNCTION_STACK_MIN struct
Parameters LOCAL_PARAMETER_FRAME8 <?>
SaveRegs SAVE_REGISTERS_FRAME <?>
Padding dq ?
STD_FUNCTION_STACK_MIN ends
STD_FUNCTION_STACK_MIN_PARAMS struct
Parameters LOCAL_PARAMETER_FRAME8 <?>
SaveRegs SAVE_REGISTERS_FRAME <?>
Padding dq ?
FuncParams FUNCTION_PARAMETERS_FRAME <?>
STD_FUNCTION_STACK_MIN_PARAMS ends
还有一个版本,其中包括XMM寄存器以及一个宏来保存和还原所有XMM寄存器。但是,这些标准结构都没有局部变量。但是,如果您需要定义局部变量,则这些是可以开始的绝佳结构,然后添加您的本地变量。我将在“填充”变量为或参数和保存寄存器结构之间添加您的本地变量,如下示例所示。如果要添加本地变量,则可以使用填充位置,而无需保留。它在那里保持对齐方式,但是您可以安排本地变量以弥补对齐问题,只需确保在保存XMM寄存器时不要陷入移动中,并使用debug_rsp_check_macro来确保保持堆栈对齐。您将需要使用debug equabled运行宏测试执行。
DEMO_FUNCTION_STACK_MIN_PARAMS struct
Parameters LOCAL_PARAMETER_FRAME8 <?>
; Local Variables Here
SaveRegs SAVE_REGISTERS_FRAME <?>
; Or Local Variables Here
FuncParams FUNCTION_PARAMETERS_FRAME <?>
DEMO_FUNCTION_STACK_MIN_PARAMS ends