Mode X und EGA Parrallax

  • wenn ich im Compiler Register Variables auf none stelle, dann funktioniert es auch.


    Ist das zufall oder hat hier der Compiler meine Variable geschreddert?

    Eher umgekehrt. Wenn du dem Compiler sagst, er kann Register für Variablen und Zwischenergebnisse verwenden, dann musst du auch mit ihm darüber kommunizieren, wer wann welche Register wofür verwendet. DX und AX werden eigentlich immer als "enthalten irgendwas was man in dem Moment berechnet" verwendet, also fast nie um längere Zeit irgendwelche Variablen aufzubewahren. Die kannst du in asm-Blöcken ziemlich hemmungslos verwenden.


    Der asm-Code von XMScopy verändert aber auch BX (eigentlich nur BL) und geht davon aus, dass SI auf irgendeinen Speicherbereich zeigt, in dem du deine EMM Structure zusammenbauen kannst. Das ist schlecht. Dein asm-Code sollte mit PUSH BX und PUSH SI anfangen und mit POP SI und POP BX aufhören, damit er nicht BX und SI verändert, die vielleicht gerade vom Compiler anderen Zwecken zugewiesen worden sind.


    Zusätzlich solltest du DS und SI auf einen Ort zeigen lassen, von dem du SICHER weisst, dass du dort deine EMM Structure hinschreiben darfst. Sonst kann DS:[SI] bis inkl. DS:[SI+15] (oder in Borland Stil: word ptr 14[SI] irgendwelche völlig anderen Daten oder sogar Code enthalten, die du jedes Mal zerstörst, wenn du XMScopy benutzt.


    Du könntest zum Beispiel einen Array von acht 16-Bit Worten namens EMMstructure anlegen, wahlweise global oder auf dem Stack, und dann in deinem asm-Block DS und SI auf die Adresse dieses Arrays einstellen. Je nach Speichermodell musst du zusätzlich unbedingt darauf achten, dass der Compiler die Segmente nicht durcheinanderbringt.


    Aktuell erwähnst du für XMStest, XMSfehler und die ganzen an XMScopy übergebenen Sachen nie ein Segment und für die Struktur ab DS:SI auch nicht. Also nimmst du wahrscheinlich an, dass sie alle im gleichen Segment sind. Das funktioniert nur in einem Speichermodell, in dem fast alle Variablen near sind und sich mit dem Stack die gleichen 64 kB teilen. Vielleicht kümmert sich auch der Compiler selbst teilweise darum, indem er deinen asm-Code um passende DS: oder ES: oder SS: Angaben ergänzt, aber wie Borland das handhabt, weiss ich nicht. Jedenfalls muss deine Struktur auf DS:SI entweder so liegen, dass sie das gleiche DS hat wie XMStest, XMSfehler und die Argumente von XMScopy, oder du müsstest überall explizit mit den verschiedenen Segmenten umgehen und ein PUSH DS und POP DS am Anfang und Ende von deinem asm-Block ergänzen.


    Ich würde dir sehr empfehlen, den ganzen Zirkus rund um die EMM Structure in den C-Anteil von XMScopy zu verschieben. Also ganz gemütlich die komplette EMM Structure in C produzieren und dann dem asm-Block nur noch die Adresse der EMM Structure übergeben statt der vielen kleinen Variablen die du jetzt alle einzeln in Assembler dort rein bastelst. Das in C zu machen spart eine Menge Stress und potentieller Bugs.

  • Das sind die kompletten XMS Funktionen...

    XMShandle ist eine Globale Variable in der jedes mal ein Wert hinterlegt wird wenn ein XMS handle reserviert wird.

    ...Das Programm verselbständigte sich aber irgendwo und hat dort ab und an einfach den Handle 1 in andere Werte geändert.

    Wenn man DOSBOX startet wird der erste Handle immer als 1 angelegt. zu testzwecken hatte ich deshalb einfach sturr gegen XMShandle !=1 geprüft um die Quelle des Fehlers zu finden.


    Beim starten des Spiels kommt noch ohne Grafik ein Info Fenster

    hier sieht man ob der XMS korrekt initialisiert wurde.

    Wenn es zu fehlern kommt wird das Programm auch sofort beendet mit einer Rückmeldung.


    Hier nochmal alle XMS Funktionen ...bis auf die Spiel spezifischen wo dann Texturen und Pixel abgefragt werden.

    Variablen am Anfang sind Global da werden beim initialisieren Informationen über Fehler hinterlegt.

    zusätzlich geben die Funktionen eine 1 zurück wenn alles korrekt funktioniert hat.


    Der Fehler welcher Auftrat war für mich nicht reproduzierbar, ich hatte Zeitweise alle Grafik Funktionen und alles drumherum was schon seit Monaten läuft deaktiviert und trotzdem wurde die Globale Variable XMShandle einfach von 1 auf was anderes geändert.

    Ich habe jetzt Einstellungen im compiler geändert, seitdem scheint ruhe zu sein.

    Jetzt werden alle Texturen korrekt kopiert und ich konnte auch die ziemlich vermurksten Test Funktionen durch die Funktionen aus dem MAP Editor ersetzen.


    Ich hatte zwischendurch auch sturr die Adressen mitm Rechner ausgerechnet und als Zahl in der Funktion eingetragen, dann schredderter der mir trotzdem den Wert aus der XMShandle Variabel, das war schon sehr kurios.


    Es läuft jetzt und alle Texturen werden korrekt angezeigt, also wurden die Adressen vorher auch eigentlich schon richtig hinterlegt.


    Register Variables auf none gesetzt und der Code funktionierte wieder.


    Merkwürdig ist nur das der Map Editor die selbe XMS Datei includiert und dabei lief alles mit den selben compiler einstellungen wobei das Spiel nicht läuft.


    Mitlerweile läuft es ja zum Glück.

    auf dem 386 habe ich noch ca. 13FPS wenn ich das Spiel zwinge bei jeder Textur anfrage diese aus dem XMS rüber zu kopieren.


    Ich habe aber einen Textur Puffer für 62 Texturen erstellt, wo angefragte Texturen rein geladen werden vom XMS.


    Bei einer Textur Anfrage wird geprüft ob eine Textur im Puffer ist oder nicht. Hierzu wird jeder Textur Nummer eine Speicherplatz Nummer hinterlegt 0 heisst nicht gepuffert.

    Dann wird sie neu in den Puffer geladen bei einer Anfrage.

    Der Puffer wechselt einfach beim laden immer einen Speicherplatz weiter.

    Dadurch können zwar benötigte Texturen überschrieben werden, aber bei 62 Texturen kommt das dennoch selten genug vor so das eigentlich immer permanent die Sichtbaren Texturen sich im Puffer ansammeln und von dort aus verwendet werden.


    Ich muss nur noch die Textur Speicherplätze von 8 bit auf 16bit ändern damit 65536 anstelle der bisherigen 256 (tatsächlich nur 200) Texturen verwendet werden können, der Rest ist schon im editor und im Spiel Funktioniert schon.


    Somit kann man zu jeder Zeit jede Textur überall für verwenden.

    Wenn ich jetzt noch den Char Speicher anpasse und den Chars noch 60 Plätze zum Puffern gebe dann habe ich im unteren Speicher auf einmal wieder ca. 348kb mehr zur verfügung. >420KB sind dann noch frei, das sollte dann für den Rest noch locker reichen.

    Und ich kann mir 100 Charaktere basteln wenn ich lust und Laune habe sind 2,052MB im Speicher 2000 Texturen. Das sollte reichen.


  • Ich würde dir sehr empfehlen, den ganzen Zirkus rund um die EMM Structure in den C-Anteil von XMScopy zu verschieben. Also ganz gemütlich die komplette EMM Structure in C produzieren und dann dem asm-Block nur noch die Adresse der EMM Structure übergeben statt der vielen kleinen Variablen die du jetzt alle einzeln in Assembler dort rein bastelst. Das in C zu machen spart eine Menge Stress und potentieller Bugs.

    ...ich versuche das mal um zu setzen. Damit es später keine Probleme gibt.

  • Also ich würde trotzdem sagen:

    Zusätzlich solltest du DS und SI auf einen Ort zeigen lassen, von dem du SICHER weisst, dass du dort deine EMM Structure hinschreiben darfst...



    Ich würde dir sehr empfehlen, den ganzen Zirkus rund um die EMM Structure in den C-Anteil von XMScopy zu verschieben. Also ganz gemütlich die komplette EMM Structure in C produzieren und dann dem asm-Block nur noch die Adresse der EMM Structure übergeben statt der vielen kleinen Variablen die du jetzt alle einzeln in Assembler dort rein bastelst. Das in C zu machen spart eine Menge Stress und potentieller Bugs.

    Bisher wird SI irgendwie überhaupt nicht gesetzt, das kommt mir sehr verdächtig vor. Und in C ist die ganze XMScopy Sache einfach sehr viel einfacher.


    Je nach Compiler kann man sich oft sparen, AX zu sichern. Bei GNU C kann man sogar ganze Funktionen in Assembler schreiben und dann angeben, welcher Parameter/Argument in welchem Register übergeben werden soll, inklusive dem Rückgabewert. Das spart oft zusätzliche Zwischenlager in Variablen.

  • Beitrag von Markus ()

    Dieser Beitrag wurde vom Autor aus folgendem Grund gelöscht: ...obsolet ().
  • Beitrag von Markus ()

    Dieser Beitrag wurde vom Autor aus folgendem Grund gelöscht: ...obsolet ().
  • ...hat wieder Stunden gedauert...


    den code von mceric konnte ich leider so nicht übernehmen, die Daten landen warum auch immer scheinbar nicht über das Struct bei SI...habe wieder Stunden damit verbracht das zu testen.



    ich hoffe ich habe nicht neue Fehler eingebaut, korrigiert mich gerne.

    Es scheint nur zu funktionieren wenn ich nach der Zuteilung des Pointers, die Daten danach erst wie gewohnt rein schiebe.


    Ich hatte etliche versuche gemacht es anders zu machen, mit Stuct und mit Arrays... nichts funktionierte, leider.

    Code
    mov si,offset XMSsi //<<< Pointer zu einem Array welches gross genug für di Daten ist unsigned int[10]!

    SI ist ein Zeiger Register ich denke ich habe das jetzt richtig begriffen... meine Assembler Kenntnisse sind halt leider was sehr dürftig und das ist verdammt lange her.


    Nun zum Spiel...

    im Bild wird oben Links der Inhalt des Arrays angezeigt, der Assembler Code füttert das Array brav mit den Werten. Korrigiert mich wenn ich falsch liege, ich gehe davon aus das durch den Pointer jetzt alles Werte richtig abgelegt werden müssen.


    hier der Code der Funktion.


    push pop habe ich brav eingebaut und einen Pointer zu einem Array welches die korrekte grösse hat es sind im Grunde 10x 16bit!

  • Code
    mov si,offset XMSsi //<<< Pointer zu einem Array welches gross genug für di Daten ist unsigned int[10]!

    SI ist ein Zeiger Register... Pointer zu einem Array welches die korrekte grösse hat es sind im Grunde 10x 16bit ...

    Also wenn der Array nicht "far" ist, müsste es so deutlich besser funktionieren, weil du jetzt SI auf eine definierte und dafür gedachte Stelle für deine Daten zeigen lässt :)


    Aber: Wieso machst du XMSsi global und zehn 16-Bit Worte (unsigned int) lang? Eigentlich müssten 8 statt 10 reichen.


    Für die Lesbarkeit solltest du XMSsi wenigstens innerhalb von XMScopy definieren, sogar wenn es im globalen RAM bleiben muss. Dann steht es wenigstens im Quelltext an der richtigen Stelle und ist nur innerhalb von XMScopy ansprechbar und nicht mehr global:


    Code
    int XMScopy(unsigned int XMSqh ,unsigned int XMSqo,unsigned int XMSqs,unsigned int XMSzh,unsigned int XMSzo,unsigned int XMSzs,unsigned long XMSb ){
        static unsigned int near XMSsi[8];
    ...


    Das ausdrückliche "near" ist wahrscheinlich unnötig.


    Wenn bei dir Stack Segment = Daten Segment ist, kannst du den XMSsi Array sogar ganz in die XMScopy Funktion verschieben, statt ihn global zu machen.


    Eigentlich spricht absolut nichts dagegen, die Variable im C-Code zu befüllen. Das ist viel lesbarer als die ganzen "mov ax, VARIABLE" und "mov word ptr OFFSET[si]" Zeilen:

    Code
    XMSsi[0] = XMSbl; // untere 16 bit Laenge
    XMSsi[1] = XMSbh; // obere 16 bit Laenge
    XMSsi[2] = XMSqh; // Quellhandle
    XMSsi[3] = XMSqo; // Quelloffset (DOS) oder untere 16 bit davon (XMS)
    XMSsi[4] = XMSqs; // Quellsegment (DOS) oder obere 16 bit des Offsets (XMS)
    XMSsi[5] = XMSzh; // Zielhandle
    XMSsi[6] = XMSzo; // Zieloffset (DOS) oder untere 16 bit davon (XMS)
    XMSsi[7] = XMSzs; // Zielsegment (DOS) oder obere 16 bit des Offsets (XMS)


    Du solltest die Variable aber sowieso auch nicht XMSsi nennen. Sie hat keinerlei besondere Beziehung zu SI. Nenne sie lieber EMMstructure oder so ähnlich.


    SI ist nicht immer ein Zeiger-Register, aber du übergibst dem XMS Treiber einen far Zeiger auf die EMM Datenstruktur mit Informationen über die zu kopierenden XMS Bereiche in DS:SI, also wird es in dem Moment als Zeiger verwendet. Wenn die Variable far wäre, müsstest du also auch noch ds = seg XMSsi machen, aber das gibt ggf. einen Konflikt mit der Art, in der du call XMSvec machst. Also mach sie lieber nicht far ;)

  • Wenn ich jetzt XMSsi in die Funktion packe funktioniert der Code nicht, habe ich grad festgestellt.

    Auch nicht wenn du es static machst?


    Wenn du es dort lässt wo du es ursprünglich hattest, funktioniert es dann wenigstens, einen Teil des Assembler-Krams wie vorgeschlagen durch C zu ersetzen?


    Und wenn irgendwas in irgendeiner Situation nicht funktioniert, kannst du dann das nicht funktionieren genauer beschreiben oder debuggen? Was genau geht wie schief?

  • Als Static funktioniert es.

    Ansonsten tut der Assembler teil so als ob das Array nicht existiert, weder lesen noch schreiben, aber auch keine Fehler Meldung.




    Ich habe Spiel und Editor jetzt so weit das ich 1000 Texturen verwenden kann, je nach Speicher kann ich auch noch ca. 64000 Texturen verwenden.

    Der Rechner ladet immer nur einzelne Texturen in den unteren speicher nach wenn diese auch benötigt werden.



    rum gammeln mit 37FPS und mit Kevin und Berta im Bild bei Bewegung noch 14FPS.


    ...wobei ich hier noch das Frame restaurieren über latch copy umsetzen möchte später, spart sehr viel Rechenleistung und ich habe jetzt genug speicher frei dafür.


    ich habe auch angefangen für "funktions" Pakete einzelne Dateien zu verwenden im Projekt.

    So kann ich die XMS Funktionen z.B. in allen Programmen verwenden in denen ich XMS benötige.

  • Als Static funktioniert es.

    Ansonsten tut der Assembler teil so als ob das Array nicht existiert, weder lesen noch schreiben, aber auch keine Fehler Meldung.

    Sehr schön, dann wird es mit static schon mal übersichtlicher :)


    Was genau meinst du mit "Assembler tut als ob Array nicht existiert"?


    Woran merkst du das?

    Wie sieht der Assembler-Teil jetzt aus, wie sieht die ganze XMScopy jetzt aus?

    Machst du diese

    Code
    XMSsi[0] = XMSbl;
    // etc.

    etc. Sachen jetzt endlich in C? :)


    Bevor du die 64000 Texturen fertig zeichnest, würde ich auch gerne nochmal nach Optimierungsgelegenheiten für die FPS gucken ;)

  • optimieren schadet nicht, ich werde die Tage aber erstmal aufräumen.

    Es gibt noch ein paar Datenleichen durch den Umbau, ungenutzte Variable und auch ganze Funktionen die weg können, weil unnötig.

    Im Map Editor will ich auch endlich die Textur Funktionen vom Spiel übernehmen, die hatten wir ja schonmal überarbeitet.

    Die Mode-X Grafik routinen sollen auch endlich in eine eigene Datei ausgelagert werden.




  • Das ist jetzt angenehm wenig Assembler in XMScopy :)


    Die [10] kannst du denke ich auf [8] reduzieren.


    Braucht Borland diese Kombination "; // Kommentar" oder reicht da ein "; Kommentar" in Assembler-Blöcken?


    In C++ Code wäre es "// Kommentar" und in C "/* Kommentar */" aber oft ist C++ Stil auch in C erlaubt.


    Das mit XMStest und XMSfehler ist irgendwie noch nicht optimal, ist aber nicht so schlimm.


    Hilfreicher wäre wahrscheinlich, den 8 nur in XMScopy verwendeten XMSxyz Variablen und Parametern vielsagendere Namen zu geben. Insbesondere weniger kurze.

  • im Assembler Bereich langt // XYZ /* XYZ */ im C/c++ teil müssen die lästigen ; immer zum trennen rein.

    Muss ich noch auf 8 ändern.

    Im C/C++ müssen die ; ans Ende von Befehlen, ja, aber in normalem Assembler macht man Kommentare mit ";" und nicht mit "//" oder "/* */", daher die Frage.

    Interessant dass in Assembler-Blöcken in Borland Kommentare im C/C++ Stil erlaubt sind.

  • 36 neue Texturen unter dem Motto "Castle" um die Städte was aus zubauen.



    Turm nochmal was tiefer gemacht, weil sonst bei der Ansicht das ganze zu hoch wird... die typische 2 1/2D ? RPG Perspektive ist halt etwas speziell.

    Zu hohe Gebäude verdecken einfach zu viel vom Gelände, das ist zwar realistischer... aber total unpraktisch.


    23:45 ...Details machen den Unterschied, verfeindern und kleine Fenster Sprites zum drauf pappen.


    kleines update... Texturen nochmals angepasst, war nicht ganz zufrieden mit den Kopfstein Texturen. Die kleinen wirken besser und es passt eher vom grössenverhältniss.

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!