Das Hauptaugenmerk dieses Projekts lag darauf, dass Menschen durch Grafik auf unterhaltsame Assembly -Programmierung auf spielerische Weise lernen können. Das Framework beseitigt die Burdern of Learning Windows -GUI und das direkte X -Programmieren und das Einrichten der gesamten Kesselplatte und drücken Sie einfach auf den Boden, da einige Anweisungen ohne viel Aufwand auf dem Bildschirm festgelegt werden. Außerdem macht es Spaß, Grafikeffekte und Demos aus den 1990er Jahren zu schreiben.
Es gibt eine Vorlagendemo, mit der Sie Ihre eigene Demo -Szene erstellen können. Sie können dies als Beispiel verwenden, indem Sie den Code in Ihr eigenes Demoscen -Verzeichnis kopieren. * Demoscenes yourDemo* Alle Code müssen in das AMD64- Verzeichnis eingehen, da es sich um ein X86-64-Montageprojekt handelt. Es sollte kein C oder andere verwendete Langaugen geben . Die Quellendatei muss geändert werden, um den Zielnamen zu ändern. Das Makefile wird kopiert, aber Sie ändern die Datei nicht. Um das Projekt zu erstellen, den Sie BCZ -Befehl verwenden. Sie müssen auch die DIRS -Datei aktualisieren, um Ihre Anwendungen und Bibliotheken mit BCZ aus den Stammverzeichnissen erstellen zu lassen.
Es gibt drei Funktionen, mit denen die Engine Sie zurückrufen wird.
Es gibt drei Funktionen zu implementieren, mit denen die Engine Sie für ein Spiel zurückrufen wird.
Alle diese Funktionen werden ein einzelner Parameter übergeben, bei dem es sich um den in Master definierten Master_DEMO_Struct handelt. Dies enthält den Videopuffer für "Demo" zusammen mit der Größe des Bildschirms und einigen anderen Informationen.
Beachten Sie, dass der Schritt die tatsächliche Länge in Bytes jeder horizontalen Linie im Videopuffer ist. Es enthält einen versteckten Teil, auf den Sie nicht zurückgreifen sollten. Berechnen Sie also die Breite, um die Grenzen des Zeichnens zu berechnen, aber mit dem Schritt berechnen, wie Sie zur nächsten horizontalen Linie im Videopuffer gelangen. Sie können jedoch auch die Doppelpufferbibliothek verwenden, um Ihre Grafiken durchzuführen und mit der Doppelpuffer -API auf dem Bildschirm zu aktualisieren.
Es gibt x64 flüchtige und nicht flüchtige Register. Sie können sie sich unter MSDN ansehen: https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx Außerdem treten jeder Funktionsaufruf auf, wobei RSP auf 0xffffffffffffFFF8 auftritt. Wenn Sie vorhaben, Funktionen anzurufen, müssen Sie den Stapel auf 0xffffffffffffffff0 ausrichten, da einige Funktionen davon ausgehen, dass sie Anweisungen verwenden können, die Ausgleich wie Movaps erfordern. Wenn der Stapel nicht ausgerichtet ist, führen Sie das Risiko aus, in einem niedrigeren Funktionsaufruf zu stürzen.
Funktionsaufrufe in x86-64 erfordern, dass auf dem Stapel 4 Parameterpositionen reserviert sind. Alle Stapelreservierungen werden bereits vorgestellt .Dendpololog, damit Stapelwanderungen funktionieren können, indem der Platz an Platz verfolgt, der dem Stapel vorbehalten ist. Die ersten vier Parameter sind RCX oder XMM0, RDX oder XMM1, R8 oder XMM2 und R9 oder XMM3. Parameter über 4 müssen nach den erforderlichen 4 Stapelorten übergeben werden, die reserviert sind, unabhängig davon, wie viele Parameter übergeben werden. Die ersten 4 Parameter sind auch nicht besiedelt, da Sie die Register verwenden, um diese Parameter zu übergeben. Der Speicherplatz ist jedoch zur Verwendung von der Funktion zur Verfügung, um entweder die Parameter zu speichern, da sie in volatilen Registern sind, oder den Speicherplatz zum Speichern der Bedürfnisse nutzen.
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.
Es gibt zwei Debugg -Makros in Debug_public.inc, der erste ist debug_rsp_check_macro, das nichts tut, wenn Debug nicht gebaut wird, aber wenn Debugg erstellt wird, stellt Sie es direkt nach .endProlog und es wird RSP überprüfen, dass es ausgerichtet ist oder 3.
.ENDPROLOG
DEBUG_RSP_CHECK_MACRO
Das nächste Makro, das Sie verwenden können, ist debug_function_call, anstatt die Anrufanweisung zu verwenden. Dieses Makro wird einfach aufgerufen, wenn Debugg nicht aktiviert ist. Wenn Debugg aktiviert ist, speichert es die nichtflüchtigen Register vor Ihrem Funktionsaufruf. Nach Ihrem Functoin-Anruf überprüfen sie, dass sie korrekt sind. Es wird dann alle nichtflüchtigen Register mit Müll mit Ausnahme von Rax/XMM0 beschädigen, da sie Daten aus der Funktion zurückgeben können. Das Ziel ist, dass wenn Sie angenommen haben, dass die flüchtigen Register Informationen behalten, dies zwingt sie, hoffentlich einen Absturz oder einen Fehler zu verursachen, wenn Sie dies getan haben.
;
; Generate new random color
;
DEBUG_FUNCTION_CALL Math_rand
Im Folgenden beschreibt das Verzeichnisstrukturlayout.
Das Framework enthält verschiedene Funktionen, mit denen Sie Ihr Demo -Gebäude beschleunigen können, indem Sie grundlegende Routinefunktionen bereitstellen.
Dbuffer_create
Dbuffer_updatescreen
Dbuffer_clearBuffer
Dbuffer_free
DEBUG_IS_ENABED
Debug_function_call
DEBUG_RSP_Check_Macro
Motor_debug
Frameloop_Create
Frameloop_performframe
Frameloop_reset
Frameloop_free
Soft3d_init
Soft3D_SetCamerarotation
Soft3D_SetViewDistance
Soft3d_setViewpoint
Soft3D_SetaPectratio
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_displayfullreenAnimatedimage
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
Im Folgenden sind Beispiele für die Verwendung eines Teils der Bibliotheks- und Framework -Funktionalität in Ihrer Demo zu kodieren.
Die Schaffung der Palette ist einfach.
MOV RCX, 256
DEBUG_FUNCTION_CALL VPal_Create
TEST RAX, RAX
JZ @Failure_Exit
MOV [VirtualPallete], RAX
Sie können dann die Farben für jeden Farbindex erstellen. Das folgende Beispiel schafft eine zunehmende weiße Palette. Wenn Sie die Doppelpuffer -API verwenden, kann sie den Palettengriff aufnehmen und den Videopuffer mit den ordnungsgemäßen Farben füllen.
@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
Die Erstellung des Doppelpuffers ist einfach mit der unten definierten API unter Verwendung der 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
Der zurückgegebene Zeiger kann direkt auf die Bildschirmhöhe x Breite basierend auf der angegebenen Pixelgröße zugegriffen werden.
MOV RCX, [DoubleBufferPointer]
MOV BYTE PTR [RCX], 10h
Der Bildschirm kann dann durch einen einzelnen Funktionsaufruf aktualisiert werden.
;
; Update the screen with the buffer
;
MOV RCX, [DoubleBufferPointer]
MOV RDX, [VirtualPallete]
MOV R8, DB_FLAG_CLEAR_BUFFER
DEBUG_FUNCTION_CALL Dbuffer_UpdateScreen
Es gibt Makros und Strukturen, die in der Demoscene.inc von paramHelp_public.inc enthalten sind, die eine schnelle und einfache Möglichkeit bieten, den lokalen Stapelrahmen einzurichten. Eine Sache, an die Sie sich erinnern sollten, ist, dass Stack Space heutzutage wirklich kostenlos ist. Wenn Sie also den Stapelraum reservieren, den Sie in diesem einfachen Demo -Framework nicht benötigen, sparen Sie einige Zeit, als jeden Stapel speziell auf den Raum anzupassen, den Sie benötigen. Sie können jedoch die Ausführungszeit einschränken, indem Sie nur die Register speichern, die Sie tatsächlich verwenden möchten. In der Header -Datei befinden sich Makros, die Ihnen helfen, indem Sie Strukturen und Makros zur Reservierung und Rettung Ihrer Register bereitstellen. Wenn Sie lokale Variablen verwenden müssen, müssen Sie Ihre eigenen zusätzlichen Strukturen erstellen. Wenn Sie nur einige Register speichern möchten, müssen Sie diese möglicherweise manuell speichern, sowie die Makros gehen nur so weit und retten Sie alle Register oder einige spezifische Register.
Die STD_Function_Stack_Min ist definiert als alle nichtflüchtigen Allzweckregister und 8 Parameter für Funktionsaufrufe. Das folgende Beispiel zeigt es, um nur wenige erforderliche GP -Register zu sparen.
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
Es gibt jedoch ein Makro, mit dem Sie alle GP -Register speichern und wiederherstellen können. Ein Beispiel hierfür ist unten gezeigt.
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
Das folgende zeigt die Definitionen des Minimums und es gibt immer zwei Versionen. Die erste ist die Stapelzuweisung für die aktuelle Funktion und der zweite enthält Zugriff auf die vom Anrufer übergebenen Stapelparameter.
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
Es gibt auch eine Version, die XMM -Register sowie ein Makro enthält, um alle XMM -Register zu speichern und wiederherzustellen. Keine dieser Standardstrukturen hat jedoch lokale Variablen. Wenn Sie jedoch lokale Variablen definieren müssen, sind dies großartige Strukturen, mit denen Sie beginnen können, und dann Ihre lokalen Variablen hinzufügen. Ich würde Ihre lokalen Variablen entweder bei der "Polster" -Variable oder zwischen den Parametern und der Struktur der Speichernregister wie im folgenden Beispiel gezeigt hinzufügen. Wenn Sie lokale Variablen hinzufügen, können Sie die Polsterposition verwenden, die nicht aufbewahrt werden muss. Es ist dort, um die Ausrichtung aufrechtzuerhalten, aber Sie können Ihre lokalen Variablen anstellen, um das Ausrichtungsproblem auszugleichen. Sie stellen einfach sicher, dass Sie beim Speichern von XMM -Registern nicht auf Movaps einfallen, und verwenden Sie die Debug_RSP_Check_Macro, um sicherzustellen, dass die Stapelausrichtung beibehalten wird. Sie müssen mit dem Debug Equ Equating ausgeführt werden, um die Durchsetzung von Makro -Tests zu haben.
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