El enfoque principal de este proyecto era que las personas pudieran aprender la programación de ensamblaje de una manera divertida haciendo gráficos. El marco elimina el burdern de aprender la GUI de Windows y la programación directa de X y configurar toda la placa de la caldera y simplemente comenzar a correr como con algunas instrucciones que pueden ver que los píxeles se establecen en la pantalla sin mucho esfuerzo. Además, es divertido escribir efectos gráficos de estilo de los 1990 y demostraciones.
Hay una demostración de plantilla que puede usar para crear su propia escena de demostración. Puede usar esto como ejemplo copiando el código a su propio directorio de Demoscene. * Demoscenes YourDemo* Todo el código deberá ir al directorio AMD64 , ya que este es un proyecto de ensamblaje x86-64, no debería haber ningún C u otros Langauges utilizados . El archivo de fuentes necesitará modificarse para cambiar el nombre de destino. Se copia el makefile pero no modifica el archivo de fabricación. Para construir el proyecto, utiliza el comando BCZ . También deberá actualizar el archivo DIRS para que sus aplicaciones y bibliotecas se construyan utilizando BCZ a partir de los directorios raíz.
Hay tres funciones para implementar que el motor usará para devolverle la llamada.
Hay tres funciones para implementar que el motor usará para devolverle la llamada para un juego.
Todas estas funciones se pasan por un solo parámetro que es el Master_Demo_struct como se define en Master. Enc , esto incluye el búfer de video para "demostración" junto con el tamaño de la pantalla y alguna otra información.
Tenga en cuenta que el paso es la longitud real en los bytes de cada línea horizontal en el búfer de video. Incluye una porción oculta en la que no debes recurrir. Por lo tanto, use el ancho para calcular los límites del dibujo, pero use el paso para calcular cómo llegar a la siguiente línea horizontal en el búfer de video. Sin embargo, también puede usar la biblioteca de doble búfer para realizar sus gráficos y actualizarlo en la pantalla utilizando la API de doble búfer.
Hay registros X64 volátiles y no volátiles. Puede mirarlos en MSDN: https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx También, cada llamada de función ocurrirá con RSP alineada a 0xfffffffffffff8. Si planea llamar a cualquier función, debe alinear la pila a 0xfffffffffffff0, ya que algunas funciones asumirán que pueden usar instrucciones que requieren alineación como los muebles. Si la pila no está alineada, corre el riesgo de bloquearse en una llamada de función más baja.
Las llamadas de función en x86-64 requieren que haya 4 ubicaciones de parámetros reservadas en la pila. Todas las reservas de pila se realizan antes. Los primeros cuatro parámetros son RCX o XMM0, RDX o XMM1, R8 o XMM2 y R9 o XMM3. Los parámetros más allá de 4 deben aprobarse en la pila después de las 4 ubicaciones de pila requeridas que están reservadas sin importar cuántos parámetros pasen. Los primeros 4 parámetros tampoco están poblados, ya que usa los registros para pasar esos parámetros. Sin embargo, el espacio está disponible para su uso por la función que se llama para guardar los parámetros, ya que están en registros volátiles o usan el espacio para guardar lo que necesite.
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.
Hay dos macros de depuración en debug_public.inc, la primera es debug_rsp_check_macro que no hace nada si no se construye la depuración, pero cuando se construye la depuración, lo pones directamente después.
.ENDPROLOG
DEBUG_RSP_CHECK_MACRO
La siguiente macro que puede usar es debug_function_call en lugar de usar la instrucción de llamadas. Esta macro es simplemente llamar cuando la depuración no está habilitada. Cuando la depuración está habilitada, guardará los registros no volátiles antes de su llamada de función, luego, después de que su función de FunccToin, verifique que sean correctos. Luego corromperá todos los registros no volátiles con basura, excepto RAX/XMM0, ya que pueden devolver los datos de la función. El objetivo es que si ha asumido los registros volátiles retenidos, esto los obliga a causar un bloqueo o un error si lo ha hecho.
;
; Generate new random color
;
DEBUG_FUNCTION_CALL Math_rand
A continuación se describe el diseño de la estructura del directorio.
El marco contiene varias funciones que puede usar para acelerar su edificio de demostración proporcionando una funcionalidad de rutina básica.
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_SetCamerarTation
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_DisplayfullScreenanimatedImage
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
Los siguientes son ejemplos de codificación de cómo usar parte de la funcionalidad de biblioteca y marco en su demostración.
La creación de la paleta es simple, solo suministra la cantidad de colores y guarda la dirección de devolución como mango de paleta.
MOV RCX, 256
DEBUG_FUNCTION_CALL VPal_Create
TEST RAX, RAX
JZ @Failure_Exit
MOV [VirtualPallete], RAX
Luego puede generar los colores para cada índice de color. El siguiente ejemplo crea una paleta blanca creciente. Si está utilizando la API de doble búfer, puede tomar el mango de la paleta y llenar el búfer de video con los colores de Apropraite.
@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
La creación del doble búfer es simple usando la API como se define a continuación.
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
Se puede acceder directamente al puntero devuelto como el ancho de la altura de la pantalla X en función del tamaño del píxel especificado.
MOV RCX, [DoubleBufferPointer]
MOV BYTE PTR [RCX], 10h
La pantalla se puede actualizar mediante una sola llamada de función.
;
; Update the screen with the buffer
;
MOV RCX, [DoubleBufferPointer]
MOV RDX, [VirtualPallete]
MOV R8, DB_FLAG_CLEAR_BUFFER
DEBUG_FUNCTION_CALL Dbuffer_UpdateScreen
Hay macros y estructuras incluidas en DemosScene.InC por paramhelp_public.inc que proporcionan una forma rápida y fácil de configurar el marco de la pila local. Una cosa para recordar es que el espacio de la pila es realmente gratuito en estos días, por lo que reservar el espacio de la pila que no necesita en este simple marco de demostración ahorrará algún tiempo que adaptar cada pila específicamente al espacio que necesita. Sin embargo, puede limitar el tiempo de ejecución solo guardando los registros que realmente planea usar. Hay macros en el archivo de encabezado para ayudar con esto al proporcionarle estructuras y macros para reservar y guardar sus registros. Si necesita usar variables locales, necesitará crear sus propias estructuras adicionales y si solo desea guardar unos pocos registros, es posible que necesite guardarlas manualmente, así como las macros, solo lleguen tan lejos y guarden todos los registros o algunos registros específicos.
El std_function_stack_min se define como todos los registros de propósito general no volátiles y 8 parámetros para las llamadas de funciones. El siguiente ejemplo muestra que lo usa para guardar solo unos pocos registros de GP requeridos.
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
Sin embargo, hay una macro que le permite guardar y restaurar todos los registros de GP. Un ejemplo de esto se muestra a continuación.
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
El siguiente muestra las definiciones del mínimo y siempre hay dos versiones. La primera es la asignación de pila para la función actual y el segundo incluye el acceso a los parámetros de pila que le pasan desde la persona que llama.
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
También hay una versión que incluye registros XMM, así como una macro para guardar y restaurar todos los registros XMM. Sin embargo, ninguna de estas estructuras estándar tiene variables locales. Sin embargo, si necesita definir variables locales, estas son excelentes estructuras para comenzar y luego agregar sus variables locales. Agregaría sus variables locales, ya sea donde está la variable "relleno" o entre los parámetros y la estructura de registros de guardado como se muestra en el siguiente ejemplo. Si está agregando variables locales, puede usar la posición de relleno, no es necesario mantener. Está ahí para mantener la alineación, pero puede organizar sus variables locales para compensar el problema de alineación, solo asegúrese de no atrapar en los movimientos al guardar registros de XMM y usar el debug_rsp_check_macro para garantizar que se mantenga la alineación de la apuesta. Deberá ejecutar con depug ecuab habilitado para tener la aplicación de la prueba macro.
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