Créer 1k d'intro Chaos pour ZX-Spectrum


Au départ, je n'avais pas prévu de faire une démo à Chaos Constrictions 2018 , cependant, 2-3 semaines avant cc, j'ai réalisé que je ne pouvais pas aller à une soirée de démonstration les mains vides, et j'ai décidé d'écrire une courte démo pour 386 / EGA / DOS .

Ayant compilé en Turbo-C sous DOS ma bibliothèque AnotherGraphicsLibrary , qui s'intègre idéalement dans la structure du plan de battement du mode EGA , j'ai été déçu par les freins, en particulier les freins EGA . La démonstration sous la forme dans laquelle j'aimerais le voir, pour cette période très limitée, était impossible à faire.

Cependant, je ne pouvais pas abandonner et ne rien faire. Et puis je me suis souvenu que je voulais depuis longtemps participer aux concours de démonstration de ZX-Spectrum . Et depuis que j'ai obtenu deux reals de 48k l'année dernière, j'ai pu avoir du plaisir à créer une démo. Soit dit en passant - pour moi, la chose la plus importante dans l'écriture d'une démo est de tester dans la vie réelle, les émulsifiants ne procurent pas un tel plaisir du processus, c'est un sentiment très merveilleux quand, après le prochain changement de code, vous téléchargez la démo dans la vie réelle, et vous voyez comment le vrai matériel mélange les octets dans effet de dessin de mémoire.

Comme je n'ai que 48k de reals, j'ai décidé de faire une démo pour 48k . Et en raison du temps limité et du manque de développements, le choix s'est porté sur la création d'une intro 1k (démo de seulement 1 kilo-octet, soit 1024 octets).

La dernière fois, j'ai poussé le z80 asm dans EmuZWin - un excellent émulateur avec assembleur intégré. Mais malheureusement, EmuZWin ne fonctionne pas sur quelque chose de plus élevé que Windows XP , ou il est bogué.
Après avoir examiné diverses options, je me suis arrêté sur un tas de programmes Unreal + sjAsm + Notepad ++ , qui, à mon avis, sont beaucoup plus faciles que EmuZWin en termes de commodité, mais sont, en revanche, vivants.

En écrivant cette introduction, j'ai réalisé, directement dans la source, un journal de développement, sur la base duquel le texte suivant a été écrit:

Bonjour tout le monde!

Que dois-je écrire en premier, ayant une expérience presque nulle dans l' asm z80 ? C'est vrai, la sortie d'un sprite 5x5 est familière ou 40x40 pixels, pour l'un des effets (ironiquement, à l'avenir, afin de tenir dans 1k, cette partie inachevée a été jetée de l'intro).

Étonnamment, il était assez facile de le faire à partir de zéro en utilisant l'étiquette d'adresse de ligne pré-générée à l'aide de Down HL .

Oh, les registres d'index, à quel point ils sont pratiques, mais qui sont plus lents, consomment littéralement des barres. J'ai dû jeter leur utilisation d'un tas d'endroits.

Toujours ici, au tout début, je suis tombé sur des pépins sjAsm incroyables, ou plutôt sa dernière version. Le surréalisme dans Unreal a montré une séquence de commandes absolument folle. J'ai téléchargé l'avant-dernière version - il était déjà possible de vivre avec.



Il est clair que vous ne pouvez pas mettre un nombre suffisant de sprites précédemment dessinés dans 1k, j'ai donc décidé de les générer dynamiquement. Et pas de toute façon, mais dessinez en utilisant des polygones.

Par conséquent, la deuxième procédure que j'ai écrite était la procédure pour dessiner un triangle. Pour la plupart, c'était un portage de leur propre code écrit en C. Avec la seule différence globale par rapport à la version C , les lignes de balayage des polygones sont générées en premier, puis elles sont dessinées sur ces lignes de balayage.

Après les langages de haut niveau, vous obtenez un certain plaisir de jr aka goto :

.sort_me_please: ld de,(tr_x2) ld bc,(tr_x0) ld a,d cp b jr nc,.skip1 ld (tr_x2),bc ld (tr_x0),de .skip1: ld de,(tr_x1) ld bc,(tr_x0) ld a,d cp b jr nc,.skip2 ld (tr_x0),de ld (tr_x1),bc jr .sort_me_please .skip2: ld de,(tr_x2) ld bc,(tr_x1) ld a,d cp b jr nc,.skip3 ld (tr_x2),bc ld (tr_x1),de jr .sort_me_please .skip3: 

J'ai été un peu choqué par le fait qu'il s'est avéré à un moment raisonnable d'écrire un draw_triangle de travail sur z80 asm , qui dessine un polygone pixel par pixel et sans trous lors de la connexion des polygones.


Bonjour triangles!

Particules



En raison de la présence d'un générateur d'étiquettes de ligne d'écran, j'ai écrit une procédure de sortie de point plutôt incurvée et lente en utilisant cette étiquette. La procédure a deux points d'entrée - juste l'inverse du pixel, et l'inverse du pixel avec le remplissage avec INK + BRIGHT + et la couleur spécifiée dans l'un des registres.

Au stade de la création d'un effet avec des particules, j'ai découvert que l'exemple avec les structures des exemples dans le wiki sjAsm ne fonctionne tout simplement pas. Google a soulevé un sujet sur le site zx-pk.ru , où ce problème est décrit, et il n'y a pas de solution - ha, très bien - un autre problème.

J'ai décidé de tout faire clairement - mettre à jour les coordonnées indépendamment du rendu, par interruption. Ouais ... plus octets pour générer une table d'interruption.

Il y avait peu de particules à ce stade, et elles rentrent à peine dans le cadre - c'est d'ailleurs la lenteur de ma procédure de sortie du point de pourcentage)) Mais l'utilisation d'une table commune avec des sprites ne m'a pas permis de la jeter et de la préparer, car cela a considérablement économisé de l'espace sur la nécessité d'un seul générateur de table. Et mon amour pour les vélos aussi :)

Trop peu de particules ... ont augmenté leur nombre, mais le rendu est maintenant engraissé à deux images.


Test sur Peters WS64 , que j'ai eu sur le dernier cc et réparé cet hiver :)

À propos, déjà à ce stade, les points se sont transformés en points horizontaux audacieux 2: 1 , comme sur le Commodore 64 . Cela s'est produit en raison du petit nombre initial de particules et de mon insatisfaction quant au fait qu'elles étaient assez invisibles lorsqu'elles étaient utilisées dans la vie réelle. Résolu le problème en remplaçant la plaque

 db 128,64,32,16,8,4,2,1; 

sur

 db 192,192,96,24,12,6,3,3; 

ce qui a aggravé la précision du positionnement et rendu le vol un peu saccadé, mais a augmenté la visibilité. Ici, il a également joué dans la main que les particules sont tombées de haut en bas - leur vision s'est tachée verticalement.

Les particules tombent incidemment chacune à sa propre vitesse aléatoire, et deux octets sont utilisés pour stocker les coordonnées Y.

Sprites

J'ai jeté la pièce inachevée de la partie sprite, réalisant que je ne pouvais pas tenir en 1k avec elle.

De plus, il y avait déjà un manque d'espace, donc je me suis souvenu du merveilleux article d'Introspek sur les packers, j'ai choisi zx7 comme packer, ce qui a permis d'économiser environ 110 octets. Soit dit en passant, peut-être que quelqu'un connaît un packer plus approprié pour une intro 1k?

Constructions du chaos



Étant donné que j'avais déjà une procédure de sortie d'un polygone, cela semblait être une bonne idée de diviser le logo cc en polygones et de les afficher un par un.

J'ai écrit un code de test qui affiche plusieurs polygones - tout fonctionnait comme je le souhaitais - très bien.

Pour vérifier si mon idée s'inscrit dans 1k , a généré un certain nombre de polygones aléatoires, selon les estimations, un nombre suffisant pour le logo, et l'a conduit à la source. Compilé, et fait en sorte que - excellente - intro, sous cette forme, rentre dans la limite de 1024 octets.


Photo de la vie, reconnaissez-vous l'appareil sur la table? :)))

J'ai décidé de tester à nouveau l'intro semi-finie, déjà avec des polygones, et un packer, téléchargé sur real et ... obtenu une réinitialisation. Tout d'abord, j'ai commencé à pécher parce que j'avais oublié d'initialiser la mémoire quelque part, d'où, où tout fonctionne bien sur l'émulateur 0x00 , dans la vie réelle, il y a des ordures provoquant une réinitialisation.

Rien de mieux pour trouver un endroit problématique que la méthode de la demi-division et l' arrêt que je n'ai pas pu trouver.

Porté avec une remise à zéro sur réel pendant deux heures, il n'y avait aucun moyen de localiser le pépin ...
Il s'est avéré que ce n'était pas dans mon code, c'était dans l'enrichisseur de son inclus sur le téléphone à partir duquel j'ai chargé les WAV. Un améliorateur à partir d'un flux binaire dans un fichier WAV a généré un flux de délire.

Dès que je l'ai éteint, tout a fonctionné comme par magie.

Il a décrit le logo dans l'éditeur graphique d' erreurs greenpixel, le divisant en un tas de triangles, et a conduit manuellement les coordonnées à la source. Après avoir farci complètement le logo de Chaos Constructions et l'avoir fait fonctionner dans la vraie vie - j'étais heureux - il avait l'air plutôt bien.


Le premier affichage de logo sur réel

Cependant, j'ai trop peu de polygones aléatoires et sur le vrai logo, il y avait une limite de 1k pour 150 octets. Et cela malgré le fait que l'effet de particules n'était toujours pas terminé et que la transition entre les pièces était nette.

Pour se coucher ce jour-là, à cause de l'agitation des pépins, il s'est avéré dès 8 heures du matin 8)

Et oui, j'ai essayé d'optimiser la taille en stockant séparément les coordonnées et les indices de sommet, mais le packer ne l'aimait pas beaucoup, ce qui n'a fait qu'augmenter la taille.

Finale



J'ai trouvé comment diversifier la sortie du logo, pour cela, il n'a fallu presque rien d'autre que deux étiquettes de pixels supplémentaires:

 fake_points1: db 1,2,4,8,16,32,64,128; 1 ch fake_points2: db 32,8,128,2,16,1,64,4; 2 ch normal_points: db 128,64,32,16,8,4,2,1; 3 ch 

Cela a donné un effet cool d'augmenter les détails du rendu du logo, ou le manque initial de détails et une augmentation progressive de la netteté.

Et enfin, j'ai fait la version finale avec toutes les transitions, jetant un tas de tout. Dans le processus, j'ai trouvé un problème dans la procédure pour dessiner un triangle - si les deux sommets ont les mêmes coordonnées Y , alors le triangle est dessiné de manière tordue (il ressemble à la division par 0 lors du calcul de dx ), contourné avec un hack temporaire.


Test de la version finale sur Leningrad 48

Optimisation de la taille


Les doubles chiffres sont des «octets supplémentaires»

94 octets supplémentaires ...

Le moment est venu de couper la préservation / restauration «culturelle» des registres des procédures d'entrée / sortie, loin de partout où cela est nécessaire, mais la mémoire est en train de manger.

86 octets ...

Testé dans la vraie vie - ça marche! Il a battu un peu plus de mémoire, corrigeant simultanément un bug divisé par 0 - 63 octets!

57 octets ...

Ajout d'une boucle.

 random_store: start: 

En passant, la boucle se fait au niveau du déballage, comme comme source d'entropie pour le RNG , plusieurs octets du code d'initialisation ont été utilisés (pour économiser de l'espace), ce que le RNG a gâché pendant la première partie. Par conséquent, pour le bouclage, après la fin de l'intro, il y a ret , eh bien, puis un autre déballage et transition vers le code décompressé ...

Il n'a pas été possible de se débarrasser des 48 derniers octets, j'ai dû couper le gestionnaire d'interruption, mais bravo! En peluche! Même 1 octet supplémentaire est resté.

Et comme il n'y a pas d'interruption, il peut être noté pour les images, et il est difficile de voir la section efficace du faisceau à un pixel dans le premier effet, j'ai donc augmenté le nombre de particules par œil, avec un compromis entre vitesse et divertissement.

Piquer encore plus fort, déplacer stupidement le code et les données d'un endroit à un autre, aidant le packer. Ce qui a pris du temps :)

Cela a libéré environ 10 octets dans lesquels j'ai collé une parodie du son. Khk, khe, son - c'est à certains endroits, à l'oreille insérée:

  ifdef UseSound ld a,d and #10 out (#FE),a endif 

Je n'ai pas «cloué» le son, mais j'ai fait une définition, obtenant ainsi deux versions de l'intro, avec et sans son. En cela sans son, en "extra" octets entassés

 db 'e','r','r','o','r' 

J'ai collecté trd et tap , et téléchargé tout sur le site Web cc .

Hourra - je participe à demopati!

Postface

Il s'est avéré être drôle avec le son, quelqu'un sur la place a dit "son clair", quelqu'un m'a regardé étrangement, et sur une pochette j'ai trouvé ce qui suit:



Et ça:



En général, je ne comprenais pas si quelqu'un aimait ou non le son de 10 octets :)

Et le dernier - c'est dommage que la compétition 1k n'ait pas eu lieu cette année, le travail s'est avéré être décent, à mon avis, mais c'est difficile de rivaliser avec 640k , mais je voulais vraiment participer.

Écrivez des démos, écrivez 1k!

Et voici ce qui a fini (ps, prenez soin de vos oreilles):



Version silencieuse:

Source: https://habr.com/ru/post/fr421837/


All Articles