Hello, Guest the thread was viewed3.1k times and contains 6 replies

last post from ThomBraxton at the

Mehrere Bilder in einer Datei unterbringen

  • Hallo Leute,


    mal wieder eine Frage an die Profis. Wie kann man auf einem C128 mehrere Bilder in einer Datei unterbringen und welchen Dateityp nimmt man dafür? Macht eine relationale Datenbank dabei Sinn oder ist der Zugriff darauf zu langsam? Ich möchte auf die Bilder direkt zugreifen können, möchte mir aber das Directory nicht mit vielen kleinen Bildern zumüllen, sondern alles übersichtlich kompakt gestalten. Es geht in meinem Fall um ein angedachtes Point&Click/Jump&Run-Adventure, bei dem die gepixelten Bilder gut sortiert, am Besten mit Direktzugriff in möglichst wenig Einzeldateien gespeichert sind. Was sind Eure Vorschläge? Gibt es Tools, die einem die Arbeit abnehmen/erleichtern?


    Liebe Grüße!
    ThomBraxton

  • Eine Frage vorweg: An welchen Stellen und wie oft und in welcher Menge wird voraussichtlich nachgeladen? Auf welchem Wege denkst Du generell die Daten in den C64 zu laden? Per Kernalload oder per Schnellader?


    Ich gehe mal davon aus, daß die zu ladenden Datensätze verschieden groß sind, zumal wahrscheinlich bei den Bildern ein Packer zum Einsatz kommen wird. Relationale Dateien bringen daher nicht unbedingt den gewünschten Effekt, da diese eine feste Datensatzgröße verlangen. Eine typische Lösung bestände darin, die tatsächliche Größe der Unterdateien zu ignorieren und stur für die Gesamtdatei eine Datensatzgröße von z. B. 16 Bytes einzurichten. Damit lassen sich die Daten häppchenweise laden. Bei einer Datensatzgröße der genannten 16 Bytes hätte man lediglich einen maximalen Verlust von 15 Bytes am Ende der Datei, was durchaus verschmerzbar wäre. Ein Nachteil bei relationalen Dateien könnte sein, daß sie von dem SD2IEC nicht vollständig unterstützt werden. (Hier fand ich widersprüchliche Angaben. Vielleicht könnte das jemand klären, der sich damit auskennt.)


    Eine andere anfangs etwas aufwendigere Methode wäre, die Datei auf der Diskette sektorweise zu scannen und (einmalig) eine Sektorlink-Liste zu erzeugen, anhand der sich der Lader selber durch die Sektoren hangeln kann. Die Daten würden dann mittels klassischem Sektorread gelesen (s. Handbuch zur Floppy).


    Voraussetzung für diese Verfahren ist jedoch auf jeden Fall, daß bei der Erzeugung der großen Gesamtdatei die Offsets aller Unterdateien sowie deren Länge in einer Liste gemerkt werden. Ob es dafür bereits ein Tool gibt, glaube ich eher nicht, aber es wäre auch kein Problem, dieses in einer Programmiersprache Deiner Wahl (C, Java, Python...) selbst zu erstellen.


    Nebenbei: Wenn Du auf das Dateisystem verzichten kannst, kannst Du die Daten auch direkt in die Sektoren speichern und mittels Sektorread lesen. (So arbeitet z. B. das Spiel "Gruds in Space".) Mit leichten Anpassungen läßt sich das auch auf d81 übertragen. In Kombination mit einem Fastloader wäre dies sogar die schnellste Lösung.

  • Wie oben geschrieben soll es ein Programm für den C128 werden. Das lässt sich auch bestimmt leicht auf den C64 übertragen. Aber ich möchte mal für meine alte Möhre etwas Spielbares schaffen. Zumal auf einer 1571 der Diskzugriff von Hause aus schneller wäre. Deshalb von mir die Frage, wie ich viele Bilder, die selten Full-Screen-Format haben, sondern meist mittels Split-Screen (Oben Grafik unten Text) dargestellt werden sollen, irgendwie in eine Sammel-Datei unterbringen kann.
    Wenn ich das also richtig verstehe, sollte ich eine Datei schaffen, deren Datensatzgröße begrenzen und die Bildinformationen dann häppchenweise dort ablegen. Somit könnte man dann berechnen, wo das eine Bild endet und das nächste beginnt. Aber kann ich denn in dieser Datei dann direkt auf den Datensatz zugreifen, wie in einer relationalen Datenbank oder muss ich mich sequentiell durch die Datei hangeln?



    Und dann wäre da noch die Sache mit dem Komprimieren! Davon habe ich noch gar keinen Plan, wie das mit dem Packen und Entpacken funktionieren soll.



    Liebe Grüße!
    ThomBraxton

  • Aber ich möchte mal für meine alte Möhre etwas Spielbares schaffen.

    Sehr löblich, aber in Basic oder Assembler?

    Zumal auf einer 1571 der Diskzugriff von Hause aus schneller wäre. Deshalb von mir die Frage, wie ich viele Bilder, die selten Full-Screen-Format haben, sondern meist mittels Split-Screen (Oben Grafik unten Text) dargestellt werden sollen, irgendwie in eine Sammel-Datei unterbringen kann.

    Ein Beispiel zur Verwendung des Burstmodus der 1571 findet sich im Floppy-Bedienungshandbuch ab S. 129. Im dort abgedruckten Listing findet sich jedoch auch der Befehl "SEI" und damit der deutliche Hinweis, daß sich ein Splitscreen mit dem Burstmodus nicht verträgt. Als Beispiel kann man beim C128 mal den Befehl "graphic4" eingeben, der mittels Rasterinterrupt Graphik und Text trennt, und dann einen Diskettenbefehl ausführen. Deswegen fragte ich nach dem genauen Einsatz des Nachladens. Entweder Du lädst nur dann nach, wenn der Spieler einen Ort komplett wechselt, und schaltest dabei den Bildschim aus oder Du bekommst Geflimmer.


    Meine Empfehlung wäre wie folgt:
    1.) Reserviere im Speicher einen größeren Bereich, in dem Du einen Diskettencache einrichtest bestehend aus mehreren Einzelpuffern zu je 256 Bytes für z. B. 8 Sektoren. Hier werden jeweils die zuletzt gelesenen Sektoren nach dem LRU-Prinzip abgelegt, d. h. zu jedem Puffer gibt es die Angaben a) Spur, b) Spurensektor, c) Wann zuletzt benutzt. Merke: Der schnellste Lader ist der, der nicht nachlädt.
    2.) Schreibe eine Routine, die Dir einen Sektor von der Diskette in einen Puffer des Diskettencaches lädt.
    3.) Schreibe eine Routine, die prüft, ob ein gewünschter Sektor (angegeben durch Spur und Spurensektor) in einem Puffer des Diskettencache vorhanden ist. Falls ja, gib die Adresse des Puffers zurück. Falls nein: Schau welcher Puffer am längsten nicht mehr gebraucht wurde und lade mit der Routine aus 2) in diesen Puffer den neuen gewünschten Sektor und passe die Angaben aller Puffer neu an. Gib dann die Adresse dieses Puffers zurück.
    4.) Sofern nicht ein Tool bei der Programmerstellung die Diskette bereits gescannt und eine Liste mit allen Sektorlinks erstellt hat, benötigst Du eine Routine, die zu Beginn des Programms diese Liste dynamisch erstellt. Das dauert etwas, da jeder Sektor in das Floppyram geladen und von dort die ersten beiden Bytes (der Sektorlink) zum C64 übertragen werden muß. Wenn Du nur eine Datei verwendest, kannst Du die Sektorliste auch beschränken auf die Sektoren der Datei. Dafür brauchst Du nur Anfangsspur und Anfangssektor der Datei.
    5.) Schreibe eine Routine, welche folgende Parameter übernimmt: 1.) Anfang der zu ladenden Daten (genannt Offset) gemessen in Bytes und bezogen auf den Anfang der großen Gesamtdatei (0), aber dabei ohne Sektorlinks mitzuzählen. Grundlage für die Zählung ist nur die reine Datei. Die Angabe des Datenanfangs sollte aus 3 Bytes bestehen, d. h. 0 bis 16777215. 2.) Länge der zu ladenden Daten. Hierfür reichen 2 Bytes.
    Diese Routine beginnt mit der Suche nach dem ersten Sektor für die Daten. Hierfür wird die Liste mit den Sektorlinks für die Datei durchlaufen. Solange der Offset >= 254 ist, gehe weiter zum nächsten Sektor und ziehe vom Offset 254 ab. Anschließend hast Du den ersten Sektor mit den Daten und auch den Offset innerhalb des Sektors (Achtung! +2 wegen Sektorlink). Rufe die Routine bei 3) auf, um die Adresse des Sektors im Puffer zu erfahren und dabei gegebenenfalls den Sektor in den Puffer zu laden. Kopiere jetzt die Daten aus dem Puffer. Sollte dabei das Ende des Puffers erreicht werden, ermittle den Nachfolgesektor und wiederhole die Schritte ab dem Punkt, wo mittels Routine 3) der Sektor geladen wird.
    6.) Für Entpacker wäre es günstig, eine Routine zu haben, die anders als 5) nicht sofort die ganzen Daten kopiert, sondern lediglich ein Byte im Akkumulator zurückliefert. (Achte darauf, daß diese Routine die Register X und Y rettet.) Diese Routine liest von der Adresse aus 3) ein Byte und erhöht danach die Adresse um 1. Ist dabei das Ende des Sektorpuffers für diesen Sektor erreicht, ermittle den Nachfolgesektor und lade diesen in den Diskettencache. Setze daraufhin die Adresse auf diesen neuen Puffer.
    Eine Schleife über diese Routine liefert dann nach und nach die Bytes von der Diskette.


    Hinweis:
    1.) Man kann den Diskcache auch so arrangieren, daß er stets alle Sektoren einer Spur enthält. Wird ein Sektor von einer anderen Spur gewünscht, wird die gesamte neue Spur vorausschauend in den Cache geladen. Am besten jedoch hat man hiervon mindestens 2, d. h. 2 vollständige Spuren liegen gecacht im Speicher vor, damit auch das Zurückgehen in einen vorherigen Raum beschleunigt ausgeführt werden kann.
    2.) Wie bereits erwähnt kann man sich die Sektorlinkliste ersparen, wenn man auf Dateien verzichtet und die Daten direkt in die Sektoren der Diskette speichert.

  • Aber kann ich denn in dieser Datei dann direkt auf den Datensatz zugreifen, wie in einer relationalen Datenbank oder muss ich mich sequentiell durch die Datei hangeln?

    Na, ja. Die Datei und der Eintrag im Directory stellen für sich genommen erstmal sicher, daß die Diskette ein Validate "überlebt", d.h. die zu der Datei gehörenden Sektoren belegt sind und bleiben. Über OPEN mit SEQ bekommst Du die Datei dann aber erst mal nur an einem Stück geliefert und mußt alles was dich am Anfang nicht interessiert überlesen. Damit ist also noch nichts gewonnen.


    Die Idee von M.J. zielt jetzt darauf ab, daß Du dich mit der Struktur von CBM DOS etwas genauer vertraut machst, so daß Du zunächst ausgehend vom Directory-Eintrag der Datei alle Sektoren der Datei mit Track- und Sektornummer identifizierst. die in deinem Programm vorhältst und dann mit U1 (Block-Read) und evtl. U2 (Block-Write) die Daten direkt aus den Sektoren zugreifst. Wie das genau geht, kannst Du im Handbuch nachlesen. Nachteil hier: die ersten zwei Bytes von jedem Block (der zu einer Datei gehört) enthalten die Verlinkung, die zwei Bytes kannst Du also nicht für eigene Zwecke nutzen. Etwas lästig, weil so jeder Block mit 254 Bytes eine etwas krumme "Nutzlast" hat.


    Der Witz bei RELativen Dateien ist nun, daß dir das CBM DOS hier die Ermittlung dieser Sektorliste abnimmt! Genau diese Liste wird nebenher in den sogenannten Side-Sektor-Blöcken geführt. Anderer Nachteil: REL-Dateien sind nicht direkt byte-adressierbar, sondern im wesentlichen Record-basiert: die Größe des Records wird bei der Erstellung angegeben (... und sollte übrigens nicht 42 oder 63 sein ...) und danach wird immer erst auf einen Record "positioniert" und dieser dann in einem Rutsch (d.h. zwischen zwei Aufrufen von jeweils CHKOUT und CLRCH, bzw. CHKIN und CLRCH) gelesen. Natürlich kannst Du die Recordlänge sinnvoll zwischen 2 und 254 wählen (mit den oben erwähnten Ausnahmen) evtl. ist für deine Zwecke 128 als 2er-Potenz ganz brauchbar.


    Zuguterletzt kannst Du komplett auf das Dateisystem verzichten und Sektoren auf einer frisch formatierten Diskette erstmal vorab mit "B-A" allozieren. Es gibt dann keine Datei, die auf diese Sektoren verweist, dafür kannst Du jetzt alle 256 Bytes jedes Sektors frei mit U1 und U2 nutzen. Nur validieren darfst Du eine solche Diskette dann nicht mehr: machst Du danach schreibende Zugriffe auf die Disk, so werden möglicherweise Daten von deinen Direktzugriffs-Sektoren überschrieben.


    ...


    Und dann gibt es auch noch sowas wie IFFL. Damit lassen sich ebenfalls mehrere, unterschiedlich lange Dateien in einer unterbringen, mit integrierter Kompression, Schnelllader und direktem Zugriff auf die jeweiligen Einzeldateien. Netterweise wird damit auch der übliche Sektor"verschnitt" am Ende jeder Datei minimiert (gibt ja nur noch die eine Datei). IFFL wurde damals gerne in Cracks zum Levelcrunchen verwendet - scheint also deinem Anwendungszweck am nächsten zu liegen. Aber auch da gilt: einarbeiten.




    Edit: ach so ja, und das hier noch - mit einer 1581 kannst Du Files mit dem Dateityp CBM als Partitionen, bzw. Unterverzeichnisse nutzen. Damit kann man das Hauptverzeichnis auch sehr schön entrümpeln. Hat nur außer mir wohl kaum wer anders mal genutzt. :(