Hey, lytron!
Hui, das sind viele Fragen auf einmal. Hoffentlich übersehe ich nichts.
lytron hat geschrieben:... aber stattdessen vertingel ich meine Zeit mit anderen Sachen.
lytron hat geschrieben:... aber das Weiterschreiben schiebe ich auch weiter ad infinitum, weil, meh, es gibt besseres zu tun
Wir sind hier im Snesfreaks-Forum. Du solltest echt mal deine Prioritäten klären.

Nee, war nur Spaß.

Aber komm, zeig mal deinen Fortschritt im Bereich SPC700-Programmierung!

Der könnte, wenn man's recht bedenkt, bei diesem Projekt ja unter Umständen, also, ich meine, ganz eventuell, nur vielleicht und mit vielen, vielen Vorbehalten (

) durchaus hilfreich werden. Ich sag nur nochmal: Soundeffekte!
lytron hat geschrieben:Was ist "dynamisches Tile-Streaming"? Klatschst du die ebenfalls via HDMA in den VRAM? Wie viele HDMAs lässt du derzeit laufen!?! Und: Ist es überhaupt möglich, alle acht DMA-Channels für HDMA zu gebrauchen!?
Himmel, das klingt ziemlich klompiziert.

Ist es gar nicht.
Aber der Reihe nach:
Im Moment komme ich noch mit zwei HDMA-Channels aus -- einer für den Screen mode, einer für den Hintergrund der Textbox. Alle acht Kanäle auf einmal zu benutzen, ist sicherlich möglich -- guck dir mal die YouTube-Videos zu d4s' kuriosem Musikspiel an, da erwähnt er etwas in der Art (für den wirklich äußerst coolen "Blättereffekt").
Tile-Daten mittels HDMA ins VRAM zu schieben, ist zwar theoretisch möglich, für meine Zwecke wäre es aber ungeeignet, weil zum einen das Timing exakt stimmen muss und zum anderen vermutlich nicht genug Zeit bliebe, um vier Tiles à 16 Bytes zu laden.
Was ich nun mit dynamischem Tile-Streaming meine, ist die Tatsache, dass ich für die Textbox-Routine die übliche Vorgehensweise komplett umgekehrt habe.
"Üblich" (d. h. sehr verbreitet) ist, dass es eine Font gibt, die du ins VRAM lädst. Dann gibt es eine gepufferte Tilemap, in die du deine ASCII- bzw. Table-Werte schreibst, damit nach dem nächsten Vblank der gesamte Text auf dem Bildschirm erscheint.
Meine Textbox dagegen hat eine fixe Tilemap, die ganz zu Anfang während Forced blank ins VRAM geschrieben wird und die ungefähr so aussieht: $22, $24, $26, ... Die Zweierschritte rühren daher, dass Mode 5 immer zwei 8x8-Tiles zu einem einzigen 16x8-Tile zusammenzieht.
Wenn ich nun Text darstellen will, setze ich ein Bit, das in Vblank gecheckt wird. Daraufhin startet eine Subroutine, die eine bestimmte Anzahl von Textzeichen (derzeit 4) als Font-Tiles ins VRAM lädt und sich dann selbst beendet. Beim nächsten Vblank sind (via Counter-Variable) die nächsten 4 Zeichen dran, und so weiter. Das Bit wird erst gecleart, wenn der "End-of-String"-Marker ($00) erreicht wird. Außerdem gibt es ein paar Steuerzeichen (z. B. $01 = neue Zeile, geplant sind außerdem Bytes für Verzögerungen etc.).
Dafür, dass nur 4 Zeichen geladen werden, gibt es zwei Gründe: Für alle 200 Zeichen auf einmal ist Vblank zu kurz, d. h. es würde nur ein Teiltext angezeigt werden (ich hab's ausprobiert: 32 Zeichen ist bei der derzeitigen Nutzung der ~8000 Vblank-Zyklen das Maximum). Der zweite Grund liegt auf der Hand: Ich will ja ohne großen Aufwand, d. h. ohne künstlich eingebaute Delays oder so, eine Laufschrift haben.

Die Geschwindigkeit lege ich zukünftig fest, indem ich die Anzahl der zu ladenden Zeichen ändere - wahlweise etwa 1, 2, 4 oder 6 (bzw. 8 ).
Da das Ganze unabhängig vom "normalen" Spiel-Code während Vblank abläuft, kann ich zeitgleich das Bild auf- oder abblenden, Herumscrollen, Sprites manipulieren etc. pp.
Neat, huh?
lytron hat geschrieben:Machs doch wie bei Treasure Conflix und stell den NMI-Vektor auf eine WRAM-Adresse, da reservierst du dann vier Byte für ein "JSL $xxxxxx".

Finde ich persönlich recht abgefahren, aber flexibler geht's nimmer!

Das ... ist ...
brillant genial.

Danke dir für den Hinweis. Das MUSS ich einfach ausprobieren. Flexibler geht's kaum, in der Tat (und in der Theorie). Yay! Danke nochmal!
lytron hat geschrieben:Eh, schreibst du mit C oder ASM?
Die coole Antwort wäre wohl: mit beidem. Die wahre ist: nur mit ASM.
Ehrlich, ich hab mir diverse C-Implementierungen für SNES-Development angeschaut. Die meisten sind wirklich nett geworden und in jedem Fall gut gemeint. Aber ich hatte dabei immer das Gefühl, dass ich mir den Zugriff auf die Hardware damit um 99% verbaue -- um andererseits keinerlei Zugewinn zu haben! Denn ich habe von Kindesbeinen an einen Background in BASIC und COMAL, und in Assembler fühle ich mich mittlerweile sattelfest. In und über C/C++ weiß ich dagegen praktisch nichts. Diese Programmiersprache ist mir schon immer total fremd geblieben, trotz hehrer Bemühungen (deren Motivationsziel mir aber nie erklärt wurde und das ich deshalb auch vermutlich schlicht entbehren kann).
lytron hat geschrieben:Warum ich mich bisher nicht an eine eigene Engine gemacht habe, war, weil ich diese Boot-Subroutine neuschreiben will. Ich benutze derzeit immer eine, die ich aus den Tutorials übernommen habe, mit denen ich gelernt habe, und deren Schreibstil macht mir mehr und mehr graue Haare.
Wo ist der Gegensatz? Eine Engine funktioniert auch mit einer Boot-Routine aus dem Pleistozän. Sollte sie zumindest. Wenn sie gut ist.
Aber geh's doch einfach an und update die Boot-Routine. Dürfte innerhalb eines Nachmittags zu einem ziemlich coolen und vor allem schnellen Ergebnis führen. Übrigens kann ich dir nur beipflichten. Was diese Boot-Routine macht und WIE sie es macht, ist zum Teil haarsträubender Blödsinn.
Nur ein Beispiel, das Original missbraucht DMA-Register, um die Return-Adresse zu speichern. Das sieht exakt so aus:
Code: Alles auswählen
LDX $1FFD ;we clear all the mem at one point ...
STX $4372 ;so save the return address in a place that won't get overwritten
LDX $1FFF
STX $4374
[...]
LDX $4372 ;get our return address...
STX $1FFD
LDA $4374
STA $1FFF
Bei mir sehen dieselben Abschnitte mittlerweile aus wie folgt (A ist jeweils 16 bit). Die ursprüngliche 24-bit-Adresse ist unnötig, da ich die Routine innerhalb derselben ROM-Bank aufrufe.
Vorteil: Egal wo ich vorher meinen Stack hingepflanzt habe, ich kann die Routine aufrufen, ohne hardgecodete Werte abändern zu müssen -- was man ja doch allzu schnell vergisst und dann wieder mit unnötigem Debuggen büßen darf.
Code: Alles auswählen
lda 1, s ; preserve return address (using a DMA register that won't get overwritten when WRAM is cleared)
sta $4372
[...]
lda $4372 ; restore return address
sta 1, s
Abgesehen davon spare ich mit meiner Version sowohl ein paar Hardware-Zyklen als auch wertvollen (!?) ROM-Space.
lytron hat geschrieben:Den wirklichen Einstieg habe ich mit bazz' Tutorials gefunden, die bei superfamicom.org konserviert sind. Die ich nach und nach auch immer schlechter fand, je mehr ich wusste, weil einfach zu viel lapidar behandelt wird, und er gleich damit anfängt, auch WLA-DX-Makros zu schreiben, statt "einfach nur" direkten Code.
Dazu fällt mir ein, dass jeder Neuling im Bereich SNES-Programmierung im Grunde zweigleisig fahren muss, was das Lernen angeht: Zum einen gilt es, mit Assembler und mit der Hardware vertraut zu werden (PPU-Register!). Zum anderen ist es unabdingbar, die Features des benutzten Compilers kennenzulernen und zu benutzen. Um irgendwann selber bestimmen zu können, wann man welches Feature benutzt und warum.
Ein Makro zu schreiben hat am meisten Sinn, wenn ich es mit Parametern aufrufen kann (klassisches Beispiel: "Printstring 'Hello!'") oder ich gezwungen bin, sehr kurze Code-Schnipsel immer und immer wieder auszuführen, die mit zusätzlichem jsr/rts nur unnötige Hardware-Zyklen verbrauchen würden (à la "- lda REG_ISTER / bne -"). Bei längeren Passagen, zumal ohne Parameter, empfiehlt sich dagegen eher eine Subroutine.
Leute, ich schwöre es euch: Der
Quellcode der originalen PowerPak-Firmware war DIE Initialzündung für mich, um Compiler-Features verstehen und anwenden zu wollen. Der Entwickler, bunnyboy, scheint (oder schien, bis zu meinem Eingreifen) von selbigen nämlich noch nie etwas gehört zu haben: Kein Makro, keine STRUCTs weit und breit, nur hardgecodeter Schrott, wohin ich schau(t)e, und den aufzuspüren mich Tage und Wochen gekostet hat.
lytron hat geschrieben:Ich habe mein Assembler-Howto noch kleiner angesetzt: Mach den Bildschirm bunt!

Color 0 von Palette 0 verfärben, da Tilemap und Tileset auch alles nullen sind, kann man mit zwei transferierten Bytes den ganzen Screen einfärben.
Nett, aber meines Erachtens kaum nützlich für Einsteiger, weil erstens Sinn und Zweck der Übung nicht klar sind (wozu auf eine bunte Fläche starren, wenn es nicht gerade moderne Kunst sein soll?) und zweitens der Lerneffekt tangential gegen Null geht. Du lernst vielleicht zwei Register so'n bisschen kennen ($2121/$2122). Das reicht aber nicht. Du brauchst 'ne Palette. Du musst akzeptieren, dass du bestimmte (Caramba: viele!) Register mit Daten bespielen und so schrittweise ihre Verwendung verstehen musst, um ein Bild auf dem Schirm anzuzeigen.
lytron hat geschrieben:Also, du hast die Map-Tilemap und die Box-Tilemap beide im WRAM liegen und HDMAst erst die erste, dann die zweite, immer im Wechsel? Holla, das stell ich mir kopfschmerzenerregend vor.
Wäre es auch, wenn ich es so machen würde.

Vergiss nicht, dass die Tilemap-Adressen einen ganzen Frame lang gleich bleiben, es sei denn, ich ändere sie zwischendurch via HDMA. Und das tu ich nicht. Sondern ich reserviere einen Teil der BG2-Tilemap für den Text -- was ich mit dem Rest mache, bleibt mir überlassen. Der bleibt für Dachfirste, Baumkronen, Zeltplanen, Pavillons, whatever.
lytron hat geschrieben:Ich glaube, keins der bekannten "größeren" RPGs hat TextBoxen auf der Worldmap, oder?
Spiel mal Breath of Fire 2. In der Übersetzung des d4s-Teams, versteht sich.
lytron hat geschrieben:Ich freu mich auf deinen nächsten Besuch hier! ^.^
Komme leider im Augenblick aus beruflichen Gründen nicht allzu oft dazu, hier vorbeizuschauen, aber ich gelobe Besserung. Ohne Garantie.
The Dealer of Fruit hat geschrieben:Geil! Ramsis ist mal wieder am Werk!^_^ Ich finde es immer wieder faszinierend wie begabt und furchtlos du an solche Projekte herangehst (das gleiche wie mit der der Firmware für das SD2SNES).
Na, wenn schon mein Fernseher ein "Loewe" ist ...!
Lieben Gruß,
Ramsis