L'objectif principal de ce projet était que les gens puissent apprendre la programmation d'assemblage de manière amusante en faisant des graphismes. Le cadre supprime le burdern de l'apprentissage de l'interface graphique Windows et de la programmation Direct X et de la configuration de toute la plaque de chaudière et appuyez simplement sur le sol en cours d'exécution, comme pour quelques instructions, ils peuvent voir des pixels être réglés à l'écran sans trop d'effort. De plus, il est amusant d'écrire des effets et des démos graphiques de style des années 1990.
Il existe une démo de modèle que vous pouvez utiliser pour créer votre propre scène de démonstration. Vous pouvez l'utiliser comme exemple en copiant le code dans votre propre répertoire Demoscene. * DemoScenes youdemo * Tout le code devra accéder au répertoire AMD64 car il s'agit d'un projet d'assemblage X86-64 Il ne devrait pas y avoir de C ou d'autres langauges utilisés . Le fichier de sources devra modifier le nom de la cible. Le makefile est copié mais vous ne modifiez pas le fichier de fabrication. Pour construire le projet, vous utilisez la commande BCZ . Vous devrez également mettre à jour le fichier DIRS afin de faire construire vos applications et bibliothèques à l'aide de BCZ à partir des répertoires racine.
Il existe trois fonctions pour implémenter que le moteur utilisera pour vous rappeler.
Il y a trois fonctions à implémenter que le moteur utilisera pour vous rappeler pour un jeu.
Toutes ces fonctions sont transmises un seul paramètre qui est le maître_demo_struct tel que défini dans Master.inc Cela inclut le tampon vidéo pour "démo" ainsi que la taille de l'écran et d'autres informations.
Notez que la foulée est la longueur réelle en octets de chaque ligne horizontale dans le tampon vidéo. Il comprend une partie cachée sur laquelle vous ne devriez pas tirer. Utilisez donc la largeur pour calculer les limites du dessin, mais utilisez la foulée pour calculer comment accéder à la ligne horizontale suivante dans le tampon vidéo. Cependant, vous pouvez également utiliser la bibliothèque à double tampon pour effectuer vos graphiques et le mettre à jour sur l'écran à l'aide de l'API à double tampon.
Il y a x64 registres volatils et non volatils. Vous pouvez les consulter sur MSDN: https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx également, chaque appel de fonction se produira avec RSP aligné sur 0xffffffffffffff8. Si vous prévoyez d'appeler des fonctions, vous devez aligner la pile à 0xfffffffffffffff0 car certaines fonctions supposeront qu'ils peuvent utiliser des instructions qui nécessitent un alignemnt telles que Movaps. Si la pile n'est pas alignée, vous exécutez le risque de s'écraser dans un appel de fonction inférieur.
Les appels de fonction dans x86-64 exigent qu'il existe 4 emplacements de paramètres réservés sur la pile. Toutes les réservations de pile sont effectuées avant .endprolog afin que les promenades de pile puissent fonctionner en suivant la quantité d'espace réservée à la pile. Les quatre premiers paramètres sont RCX ou XMM0, RDX ou XMM1, R8 ou XMM2 et R9 ou XMM3. Les paramètres au-delà de 4 doivent être transmis sur la pile après les 4 emplacements de pile requis qui sont réservés, quel que soit le nombre de paramètres passés. Les 4 premiers paramètres ne sont pas non plus peuplés lorsque vous utilisez les registres pour transmettre ces paramètres. Cependant, l'espace est disponible pour une utilisation par la fonction appelée pour enregistrer les paramètres car ils sont dans des registres volatils ou utilisent l'espace pour enregistrer tout ce dont il a besoin.
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.
Il y a deux macros de débogage dans Debug_Public.inc, la première est Debug_RSP_CHECK_MACRO qui ne fait rien si Debug n'est pas construit, mais lorsque Debug est construit, vous le mettez directement après .endprolog et il vérifiera RSP qu'il est aligné ou int 3.
.ENDPROLOG
DEBUG_RSP_CHECK_MACRO
La macro suivante que vous pouvez utiliser est Debug_Function_Call au lieu d'utiliser l'instruction d'appel. Cette macro est simplement appelée lorsque le débogage n'est pas activé. Lorsque le débogage est activé, il enregistrera les registres non volatils avant votre appel de fonction, une fois que votre appel Functoin, cela vérifiera qu'ils sont corrects. Il corrompra ensuite tous les registres non volatils avec des ordures, à l'exception de Rax / XMM0 car ils peuvent retourner les données de la fonction. L'objectif est que si vous avez supposé que les registres volatils ont conservé des informations, cela les oblige à, espérons-le, à provoquer un crash ou un bogue si vous l'avez fait.
;
; Generate new random color
;
DEBUG_FUNCTION_CALL Math_rand
Ce qui suit décrit la disposition de la structure du répertoire.
Le cadre contient diverses fonctions que vous pouvez utiliser pour accélérer votre création de démo en fournissant une fonctionnalité de routine de base.
Dbuffer_create
Dbuffer_updatescreen
Dbuffer_clearbuffer
Dbuffer_free
Debug_is_enabled
Debug_Function_Call
DEBUG_RSP_CHECK_MACRO
Moteur_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_DRAWCICCLE
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
Voici des exemples de codage de la façon d'utiliser certaines des fonctionnalités de la bibliothèque et du framework dans votre démo.
La création de la palette est simple, vous fournissez simplement le nombre de couleurs et enregistrez l'adresse de retour comme poignée de palette.
MOV RCX, 256
DEBUG_FUNCTION_CALL VPal_Create
TEST RAX, RAX
JZ @Failure_Exit
MOV [VirtualPallete], RAX
Vous pouvez ensuite générer les couleurs pour chaque index de couleur. L'exemple ci-dessous crée une palette blanche croissante. Si vous utilisez l'API à double tampon, il peut prendre la poignée de la palette et remplir le tampon vidéo avec les couleurs appropriées.
@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 création du double tampon est simple en utilisant l'API telle que définie ci-dessous.
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
Le pointeur renvoyé peut être directement accessible en tant que largeur de hauteur d'écran en fonction de la taille des pixels spécifiée.
MOV RCX, [DoubleBufferPointer]
MOV BYTE PTR [RCX], 10h
L'écran peut ensuite être mis à jour par un seul appel de fonction.
;
; Update the screen with the buffer
;
MOV RCX, [DoubleBufferPointer]
MOV RDX, [VirtualPallete]
MOV R8, DB_FLAG_CLEAR_BUFFER
DEBUG_FUNCTION_CALL Dbuffer_UpdateScreen
Il existe des macros et des structures incluses dans le démoscene.inc par paramhelp_public.inc qui fournissent un moyen rapide et facile de configurer le cadre de pile local. Une chose à retenir est que l'espace de pile est vraiment gratuit ces jours-ci, donc réserver un espace de pile dont vous n'avez pas besoin dans ce cadre de démonstration simple va gagner du temps que d'adapter chaque pile spécifiquement à l'espace dont vous avez besoin. Cependant, vous pouvez limiter le temps d'exécution en enregistrant uniquement les registres que vous prévoyez réellement d'utiliser. Il existe des macros dans le fichier d'en-tête pour vous aider en vous fournissant des structures et des macros pour réserver et enregistrer vos registres. Si vous avez besoin d'utiliser des variables locales, vous devrez créer vos propres structures supplémentaires et si vous souhaitez seulement enregistrer quelques registres, vous devrez peut-être les enregistrer manuellement ainsi que les macros ne vont que si loin et enregistrer tous les registres ou quelques registres spécifiques.
Le std_function_stack_min est défini comme tous les registres généraux non volatils et 8 paramètres pour les appels de fonction. L'exemple ci-dessous montre l'utilisation pour enregistrer uniquement quelques registres GP requis.
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
Cependant, il existe une macro qui vous permet de simplement enregistrer et restaurer tous les registres GP. Un exemple de ceci est illustré ci-dessous.
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
Ce qui est ci-dessous montre les définitions du minimum et il y a toujours deux versions. Le premier est l'allocation de pile pour la fonction actuelle et le second comprend l'accès aux paramètres de pile qui y sont transmis depuis l'appelant.
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
Il existe également une version qui comprend des registres XMM ainsi qu'une macro pour enregistrer et restaurer tous les registres XMM. Cependant, aucune de ces structures standard n'a de variables locales. Si vous avez besoin de définir des variables locales, ce sont de superbes structures pour commencer, puis ajouter vos variables locales. J'ajouterais vos variables locales soit où la variable "rembourrage" est ou entre les paramètres et la structure des registres de sauvegarde comme indiqué dans l'exemple ci-dessous. Si vous ajoutez des variables locales, vous pouvez utiliser la position de rembourrage, il n'a pas besoin d'être conservé. Il est là pour maintenir l'alignement, mais vous pouvez organiser vos variables locales pour compenser le problème d'alignement, assurez-vous simplement de ne pas piéger les MOVAP lors de l'enregistrement des registres XMM et utilisez le débogage_rsp_check_macro pour garantir que l'alignement de pile est maintenu. Vous devrez exécuter avec Debug EquECTIVE ALLABLE AVEC LA MACRO TEST ENFORMATION.
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