Wie war das damals mit der Spieleprogrammierung?

Diskussion zum Thema Programmierung unter DOS (Intel x86)
markusk
Norton Commander
Beiträge: 132
Registriert: Fr 19. Apr 2013, 11:12

Wie war das damals mit der Spieleprogrammierung?

Beitrag von markusk »

Hallo,

Ich kehre grad wieder ein wenig zurück zu den Anfängen meiner Programmiererkarriere, zumindest unter DOS, denn mein allererstes Programm hab ich schon viel früher in BASIC auf einem Commodore C16 geschrieben. Auf dem PC hab ich dann mit GW Basic, Turbo Pascal, Turbo C und ein wenig Assembler weitergemacht.

Was mich interessieren würde: Wie wurde damals die Grafik für die Spiele programmiert? Wenn ich da sehe wie unzählige unterschiedlich aussehende Figuren rasend schnell ohne Flimmern über den Bildschirm jagen, die gleichzeitig eine ganze Flut an Geschoßen durch die Gegend ballern, bei einem Treffer Teile animiert rumfliegen dann hab ich mich schon immer gefragt wie das alles realisiert wird.

Wie wurde das Aussehen der Objekte definiert und wie wurden diese ganzen Bewegungen und Animationen programmiert die so fließend und flimmerfrei abliefen? Und das noch dazu alles auf Rechnern die nicht gerade vor Rechenpower strotzten. Sicher, wenn man weiß wie kann man aus jedem Rechner das Maximum rausholen, aber bei Spielen kamen ja noch viele andere Aspekte dazu, neben der erwähnten Grafik ja auch Sound etc.

Wurde da irgendwelche Zusatzsoftware zum Entwerfen der Grafiken verwendet? Und wie wurde das im Spiel dann so ruckel- und flimmerfrei animiert?

Assembler schön und gut, aber das allein war es sicher nicht.

Lg, Markus
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Wie war das damals mit der Spieleprogrammierung?

Beitrag von zatzen »

Wenn ich zurückdenke an die 286er-Zeiten, dann erinnere ich mich da kaum an besonders wilde Grafikorgien. Entweder waren die bewegten Objekte klein (z.B. Lemmings - und hier gab es auf dem PC nicht das pompöse Intro wie auf dem Amiga) oder es ging eher gemächlich zu (z.B. Lucasfilm/Arts Adventures, Monkey Island I, II). Für Jump&Runs wurde auch oft gerne EGA Grafik genutzt - weniger Daten, und ruckelfreies Scrolling durch Nutzung mehrerer Bildschirmseiten.
Ein VGA-Jump&Run wie Trolls beispielweise, lief dann erst auf einem 386er oder 486er richtig flüssig. Ob es nun schlecht programmiert war sei mal dahingestellt, aber hier haben wir eben VGA mit vielen großen Sprites UND Scrolling.
Klar kann man auch in Assembler schlecht programmieren, aber es sollte die Grundlage sein, dass etwas eine gute Performance haben kann.
Zusatzsoftware zum Entwerfen der Grafik gab es bei den alten Sierra Adventures, aber eher zum Zweck der Datenreduzierung. Hintergründe wurden nicht als Bitmap gespeichert, sondern man zeichnete sie in einem speziellen Programm, das sich die einzelnen Schritte merkte, und im Spiel wurde das dann dementsprechend nachgezeichnet.
Ansonsten sind Bitmaps eigentlich am schnellsten, zumindest wenn sie komplex sind und nicht viel gleiche Flächen enthalten, denn das könnte man per Lauflängencodierung zusammenraffen und somit beschleunigen und in einer schnellen Assemblerroutine decodieren.

Aber sicherlich, es ist schon erstaunlich was gut programmierte Spiele alles leisten konnten.
Nur muss man eben auch die Plattform beachten. Ein 486er ist Performance-mäßig schon locker in der Lage, Multimedia-mäßig mit einem Amiga 500 mitzuhalten, das zeigen entsprechende Portierungen wie Pinball Dreams.

Prehistorik ist noch ein Spiel das auf einem 286er funktionierte. AdLib Musik (also keine Prozessorbeanspruchung wegen der Musik), einfache PCM Soundeffekte (auch keine Prozessorbeanspruchung da simpel per DMA Transfer ausgelöst). Grafisch passiert da doch relativ viel, und es ist VGA, aber es hat kein Scrolling. Ich glaube auch nicht dass immer der gesamte Hintergrund restauriert wird, das wäre viel zu langsam. Ich finde das interessant, da ich ja selber auch nochmal ein Spiel machen will.
mov ax, 13h
int 10h

while vorne_frei do vor;
funkheld
HELP.COM-Benutzer
Beiträge: 27
Registriert: Di 25. Feb 2020, 10:42

Re: Wie war das damals mit der Spieleprogrammierung?

Beitrag von funkheld »

Die meisten Spiele wurden in ASM geschrieben.
Aber für den Laien war der Aufbau des ASM nicht nachvollziehbar , es sollte nur funktionieren.
Man kann so ein Spiel nicht sauber lokalisieren, nach dem Motto: Vielleicht kann ich von dem ASM noch lernen.

Das Flimmerfreie erzielte man durch Flipping der Teilgrafik.
Dann fing das Aufrüsten der PC an....das Spiel musste ja schön aussehen.
Der Grafikkartenboom fing an und der Soundkartenboom.

Gruss
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Wie war das damals mit der Spieleprogrammierung?

Beitrag von zatzen »

Hallo funkheld!

Kannst Du das mit dem Flipping noch ein wenig erklären?

ich glaube, spiegeln meinst Du nicht.

Es wäre für mich sehr interessant weil ich gerne noch kreativ im Bereich Spiele sein würde und noch eine Lösung für möglichst schnelle Grafik suche, d.h. eine Alternative dazu, pro Frame den ganzen Hintergrund zu restaurieren und dann alle Sprites neu zu zeichnen, d.h. in einen Grafikpuffer, und diesen dann erst in den Grafikspeicher zu kopieren.

Grüße
Zatzen
mov ax, 13h
int 10h

while vorne_frei do vor;
funkheld
HELP.COM-Benutzer
Beiträge: 27
Registriert: Di 25. Feb 2020, 10:42

Re: Wie war das damals mit der Spieleprogrammierung?

Beitrag von funkheld »

Da gibt es mehrere Wörter dafür : Screen umschalten zb. Beim Spiegeln bleib jedes Teil auf seinen eigenen Ort und wird nur kopiert.

Na , was du da vor hast ist nicht einfach.
Die Seite vom VGA 320x200 mit 256 Farben hat schon 64000 Übertragungspunkte.

Da werden nicht alle Sprites neu geschrieben , sondern nur die , die sich bewegen.
Ansonsten kannste Schäfchen zählen.

Ich hatte das auch mal vor 14 Tagen vorgehabt mit dem Turbo-Pascal 6.1. mit den 64000 Byte kopieren.
Spritebewegung sehr langsam. Wenn du die Zeit verkürzen möchtest kannst du die Verschiebepunkzahl erhöhen.
Wenn es zuviele werden , taugt die Bewegung nichts mehr.

Habe es auch mal mit Turbo C++ 3.0 versucht , bringt nicht die erwartete Geschwindikeit.
Die einfachen VGA-Karten mit 256kb können kein Screen umschalten wenn er auf 256 Farben spielt.
Ich bleibe bei Turbo Pascal 6.1 und werde mal was ausdenken bei mir, wie man es machen kann.

Die beiden Sprachen können auch ASM-Code aufnehmen, wird aber auch in Grenzen bleiben mit der Bewegung.
Ich bin kein Profi und bewege mich auf niedrigen Grund .


Gruss
Zuletzt geändert von funkheld am Mi 11. Mär 2020, 19:59, insgesamt 1-mal geändert.
DOSferatu
DOS-Übermensch
Beiträge: 1220
Registriert: Di 25. Sep 2007, 12:05
Kontaktdaten:

Re: Wie war das damals mit der Spieleprogrammierung?

Beitrag von DOSferatu »

zatzen hat geschrieben:
Kannst Du das mit dem Flipping noch ein wenig erklären?

Es wäre für mich sehr interessant weil ich gerne noch kreativ im Bereich Spiele sein würde und noch eine Lösung für möglichst schnelle Grafik suche, d.h. eine Alternative dazu, pro Frame den ganzen Hintergrund zu restaurieren und dann alle Sprites neu zu zeichnen, d.h. in einen Grafikpuffer, und diesen dann erst in den Grafikspeicher zu kopieren.
Hallo zatzen!

Wie die es damals gemacht haben, daß das trotz langsamer Rechner so performt hat: Da waren spezielle Magic-Chips in alle PCs eingebaut, deren Leiterbahnen mit Elfenstaub behandelt waren. Leider werden die seit ca. 1992 nicht mehr hergestellt und nun muß man auf konventionelle Möglichkeiten zurückgreifen, die vor allem viel Nachdenken und Arbeiten beinhalten...
[scnr]

Nö... also, ich erkläre es mal:
(Und, entschuldige, daß ich schon wieder in dieses Horn blase)

Der Grund, wieso die Leute damals auf langsamen Maschinen diese Dinge trotzdem "in Echtzeit" hinbekommen haben, ist, weil sie kreative Alternativen zum MCGA gefunden haben - also Mode-Y, Mode-X, Softscrollregister und allgemein an Grafikkartenregister- /Modes herumzu-tweaken - also all die Dinge, die Du nicht machen willst, weil "will nur meinen MCGA und sonst nichts und trotzdem soll alles so performen wie bei den Tweakern".

Dieses Gemurks an den CGA/EGA/VGA-Registern hätten die nicht gemacht, wenn es auch ohne schnell genug gewesen wäre...

Schade, daß ich nicht die Zeit habe, sonst würde ich Dir mal ein kleines Demo machen:
Wenn man weiß, wie es geht, kann man z.B. (mit Mode-Y) einen 4-Bildschirme-Screen haben (z.B. alle 2x2 Quadrat angeordnet, oder alle 4 nebeneinander oder übereinander) und mit Hilfe von Softscrollregistern und Positionsverschiebungen kann man das Ding in quasi Nullzeit in alle Richtungen scrollen, ohne etwas umkopieren zu müssen. (Thema: Scanline).
Oder eben NOCH größere "Bilder"/Levels, und dabei nur alles was da ist, scrollen und nur der "Streifen", der neu reingescrollt wird, zusätzlich dran-berechnen...

Wenn man's noch schneller haben will, kann man sogar Textmode nehmen - modifizierter Zeichensatz, auch Softscroll... usw...

Das Schreiben in den Grafikkartenspeicher ist nunmal das Nadelöhr an der ganzen Geschichte und wenn man einerseits scrollen will, andererseits aber vom MCGA nicht wegkommt, bleibt einem nur entweder das ganze Bild immer wieder neu generieren UND dann von einem Puffer in den MCGA kopieren -ODER- alle Levelelemente, die "nicht Leerraum" sind, einzeln bewegen (und den Zwischenraum (den "Himmel") quasi freilassen... Aber mit all den komplizierten "Umwegen", die man dann macht, um das Level komplizierter anzuordnen und zu verwalten, nur um beim 1-Screen-MCGA bleiben zu können, frißt man die gesparte "Rasterzeit", die durch weniger VGA-Zugriffe entstehen wieder mit komplexeren CPU-Berechnungen auf.

Typen wie id-Software (vor allem natürlich John Carmack!) haben selbst diesen hundsmiserabel anzusteuernden EGA-Grafikmode dazu gekriegt, softscrollende Spiele darzustellen, mit Sprites und so (Commander Keen). Und Carmack ist ja nicht deswegen der totale Held, weil er immer die simpelste Methode genommen hat und es dann irgendwelche ruckeligen krummen Sachen geworden sind, sondern weil er das Gegenteil gemacht hat: Die Grenzen des Systems bis zum Anschlag ausgelotet.

Und - um damit die eingehende Frage dieses Thread zu beantworten: DAS ist es, wie die damals die Spiele gemacht haben! Wenn man sieht, was Leute irgendwann aus dieser Kiste C64 herausgeholt haben, ein Rechner von 1982 mit Technik vom Ende der 70er... dann kann man sich vorstellen, was eigentlich alles geht und was NOCH VIEL MEHR gehen müßte mit 'ner Maschine mit der 50-fachen CPU-Geschwindigkeit und einer Grafikhardware mit viel mehr Einstellmöglichkeiten... -

Und da muß man auch nicht immer mit der dem C64-gegenüber-PC einzigen Rechtfertigung kommen: "Der C64 hatte ja Hardware-Sprites." - Ja, stimmt! Hatte er. ACHT Stück. 24x21 Pixel (mono) oder 12x21 Pixel (3farbig). Wer sich damit vergleichen will - will sagen: auf einem 286er oder 386er nichtmal acht ca. 20x20-Pixel Sprites in Software hinzukriegen - auf ner 10x bis 50x so schnellen Maschine (mit CPUs, die viel mehr Befehle haben, inkl. Hardware-Multiplikation/Division - auch wenn man die für Sprites nicht braucht...) - naja. Was soll man da sagen? Wenn der C64 mal mehr als 8 Sprites oder größere "Sprites" dargestellt hat, war das übrigens NICHT "Hardware"... Genauso wie z.B. ruckelfreies 8-Wege-Scrollen von VOLLGRAFIK auf dieser 8-Bit-Maschine NICHT "Hardware" war.

Also, ja: Man kann auch auf einem PC mit seiner komischen VGA ziemlich coole Dinge tun. Man muß es aber wollen.

Ich könnte Dir z.B. einen 160x200 Mode hinbauen, der dafür aber 2 Bildschirmseiten hat und trotzdem "plain" (also alle Pixel direkt neben/-übereinander), sozusagen ein "halber MCGA" mit 2 Seiten (für Double-Buffering). Mit einem weiteren Trick kann man auch daraus wieder einen 320x200 Mode mit 2 Seiten machen, allerdings dann mit nur 16 (statt 256) Farben: Jedes Byte enthält dann 2 Pixel (im High- und Low-Nybble).

Aber alles was in VGA "plain" ist, greift nunmal max. auf 65536 Bytes zu, weil dazu die 4x65536 "zusammengeschaltet" werden, weil der MCGA ja so ein weiterentwickelter CGA ist. Um die vollen 4x65536 Bytes (also 262144 Bytes, bzw. 256kByte), die eine VGA EIGENTLICH hat, zugreifen zu können, muß dieses "chaining" aufgelöst werden. Allerdings hat man dann eben die komische Mode-Y Anordnung, auf die man sich eben einlassen muß, wenn man das haben will, dafür aber 262144 Pixel, die man (fast) so anordnen kann wie man will - alles eine Frage von Scanlines und VGA-Registern. Da geht auch sowas wie 400x300 oder 256x256 oder 512x512... Solange das Produkt <=262144 ist, reicht es für ein Bild. Und wenn das Produkt <=131072 (128kByte) ist, reicht es für ZWEI Bilder.

Ich hatte ehrlich schonmal überlegt, so ein Textmode-Spiel zu machen, wo ich die Figuren ("Sprites") dann aus Zeichen zusammensetze, die aber innerhalb "rotiert" werden, um quasi alle "weichen" Positionen zu erreichen. Und die Hintergründe dann "hard-scrollen" will sagen: bei jedem 8. Schritt wird "umkopiert" (oder Bildanfang-Pointer verschoben!) und die restlichen 7 Schritte machen die Softscroll-Register. Das gleiche geht auch in MCGA/Mode-Y usw. Nur weil die Pixel da doppelt-breit sind (gegenüber der Pixelclock) hat das Register da nur 4 Einstellungen (0,2,4,6), weil die "ungeraden" komische Effekte erzeugen. Eigentlich ist dem VGA-Softscroll-Register nicht nur 8, sondern sogar 9 Schritte (0-8) möglich, weil es ja auch 9 Pixel breite Zeichen im Textmode haben kann. Allerdings kann man den Textmode auch auf 8er forcieren - wäre für so ein Textmode-Spiel wahrscheinlich auch schicker.

Naja, langer Text schon wieder - ich weiß. Wollte damit nur sagen: Das - und vieles andere - sind die Sachen, die damals gemacht wurden, um "Rasterzeit" zu sparen, um also z.B. ruckelfreies Scrolling selbst mit den damaligen Maschinen hinzukriegen. Schonmal Turrican 2 für PC gesehen? Der tweakt da übrigens die VGA wie total böse - aber das Ergebnis rechtfertigt es ja auch.

So, das soll's von mir dazu erstmal gewesen sein.

P.S.: Ach ja, das "Flipping": - Ich glaube, funkheld meinte damit (u.a.) eben das Double-Buffering - also Zeichnen auf einem "Bild", während das andere angezeigt wird und dann umschalten. Bei zusätzlicher Beachtung des Vertical Retrace konnte das eben gehen - zusammen mit einigen anderen der obengenannten Dinge.
funkheld
HELP.COM-Benutzer
Beiträge: 27
Registriert: Di 25. Feb 2020, 10:42

Re: Wie war das damals mit der Spieleprogrammierung?

Beitrag von funkheld »

Ich könnte Dir z.B. einen 160x200 Mode hinbauen, der dafür aber 2 Bildschirmseiten hat und trotzdem "plain"
He....das suche ich, habe ich mit meinem Turbo Pascal nicht hinbekommen obwohl da auch ASM nutzen kann.

Wäre schön , wenn du das mal für einen Laien rüber bringen könntest.
Ich Spiele mit der einfachen VGA-256kb.

Man kann glaube ich dann immer 2 Screens benutzen von den Vier.

Danke.
GRuss
DOSferatu
DOS-Übermensch
Beiträge: 1220
Registriert: Di 25. Sep 2007, 12:05
Kontaktdaten:

Re: Wie war das damals mit der Spieleprogrammierung?

Beitrag von DOSferatu »

funkheld hat geschrieben:
Ich könnte Dir z.B. einen 160x200 Mode hinbauen, der dafür aber 2 Bildschirmseiten hat und trotzdem "plain"
He....das suche ich, habe ich mit meinem Turbo Pascal nicht hinbekommen obwohl da auch ASM nutzen kann.

Wäre schön , wenn du das mal für einen Laien rüber bringen könntest.
Ja, wie gesagt, dazu muß man die entsprechenden VGA-Register tweaken. Normalerweise setzt man dazu erstmal den normalen MCGA (mov AX,$13; int $10) und danach murkst man mit den Registern rum, die Scanline, Overscan, Pixeltakt und ähnlichen Kram vorgeben. Bei URALTEN Monitoren sollte man vorsichtig sein mit falschen/ungültigen/sinnlosen Wertekombinationen, die könnten sich da zerlegen. Aber die meisten "neueren" (und damit meine ich: schon Anfang der 90er oder so) schalten eigentlich schon ab, wenn die Werte nicht darstellbar sind. Also diese uralten Krücken, die da implodieren, hat wohl kaum noch einer - nichtmal der überzeugteste Retro-Freak. Und wenn man keine doofen Werte nimmt, passiert auch nichts Schlimmes.
funkheld hat geschrieben:Ich Spiele mit der einfachen VGA-256kb.
Natürlich habe ich das nicht alles im Kopf. Aber habe das alles hier. Ich habe mal irgendwann ein Tool geschrieben, das meine selbst Grafik-Unit benutzt. Diese kann 172 verschiedene Modi darstellen (MCGA und Mode-X. Es sind natürlich ein paar mehr Mode-X als MCGA). Auflösungen von 128x150 bis 512x512. Mit mehr oder weniger Bildschirmseiten - je nachdem, was die 256kB hergeben.
funkheld hat geschrieben:Man kann glaube ich dann immer 2 Screens benutzen von den Vier.
Naja, bei 160x200 PLAIN benutzt man ja nur knapp 32kB, also 64kB für 2 Screen. Im PLAIN Modus (also quasi wie MCGA) ist ja alles chained, dafür dann eben alle Pixel hintereinander. Bei 160 halbiert man einfach die Pixelfrequenz UND die Scanline gegenüber 320. Da hat man dann doppelt breite Pixel (sieht aus wie beim C64 Multicolor-Mode). Und wenn man dann wieder mit einem anderen Register die Pixel "halbiert" hätte man wieder 320, dafür dann aber nur 4bit pro Pixel.

Vielleicht lade ich mal das kleine Testtool auf meinen Webspace hoch. Da kann man die ganzen Modi angucken. Müßte dann noch kurz dazuschreiben, welche Tasten man da benutzen kann.

Im auf VGA-Register zuzugreifen, muß man die "Lese-/Schreibsperre" lösen (das is auch nur 'n Register). Die ist dazu da, um abwärtskompatibel zu CGA/EGA zu sein. Und die Werte (Scanline, Overscan, Frequenz) sind teils bitweise auf verschiedene Register verteilt (so wie es damals am günstigsten war, in die Register reinzuquetschen. Aber da schreibt man sich eben eine Subroutine, die die Werte dann entsprechend selbst auf die Register aufteilt, um sich das Gefrickel zu sparen.

MODE-Y:
Der normale Mode-X (eigentlich Mode-Y, der das Chaining entfernt) sind nur 3 Registerzugriffe. Der macht dann aus einem 320x200x256 MCGA einen 320x200x256 mit 4 Screens. (Eigentlich ist es EIN Screen, der 320 Pixel breit ist und 819,2 Zeilen hoch. Man gibt mit Registern an, wo die Screenanzeige starten soll, so entstehen 4 "untereinander liegende" Bilder,) Und diese Bilder haben eben dann zwar nur 16000 Adressen, aber man kann die Planes umschalten. Und jede Plane ist eine SPALTE der Pixel. D.h. die Pixel gehören nacheinander zu: 0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3,,..., d.h. immer jeder 4. Pixel gehört wieder zur gleichen Plane. 4 nebeneinanderliegende Pixel haben also die gleiche Speicheradresse. Man kann Planes aber nicht nur einzeln aktivieren, sondern auch bitweise zusammenschalten, dann werden mehrere gleichzeitig beschrieben. Beim Lesen geht das nicht (da werden die immer einzeln angesprochen - was aber auch klar sein dürfte - denn jede Plane kann ja etwas anderes enthalten - was sollte bei kombiniertem Lesen als Wert zurückgegeben werden?)
Wenn man also z.B. einen 32bit-Zugriff macht UND alle 4 Planes kombiniert, kann man mit einem Zugriff 16 Pixel setzen (natürlich sind dann immer jeweils 4 nebeneinanderliegende gleichfarbig).

Naja, und WEIL Mode-Y so diese spaltenweise Anordnung hat, sind meine Level-/Sprite usw. Routinen (also alles was quasi 2D-Spiel-mäßig ist) auf diese senkrechte Anordnung optimiert, um die Plane-Wechsel zu minimieren. Ich habe dazu auch so ein "senkrechtes" Grafikformat erfunden, das auch "leere" (ausgelassene) Pixel erlaubt - damit ist z.B. das große XPYDERZ-Logo in meinem gleichnamigen Spiel gemacht...

Naja, OK. Zuviel der Worte. Ich code hier schon jahre-/jahrzehntelang allein vor mich hin - natürlich habe ich nicht alles, was ich mache, selbst erfunden. Vieles auch nachgelesen und dann weiterentwickelt. Inzwischen habe ich so viele nützliche Pascal-Units gebaut (wobei diese, je neuer sie sind, umso mehr Assembler-Anteil enthalten)...

Und derzeit habe ich quasi den "Rahmen" für so 2D-Spiele schon fertig und bin gerade am Entwickeln eines Editors, um Levels/Sprites und dann auch Musiken/Effekte und alles was sonst so gebraucht wird, zu entwickeln, um das alles zu kombinieren.

Mir ist natürlich durchaus bewußt, daß das alles vom rein ökonomischen Standpunkt her der ganzen Mühe nicht wert ist - aber was interessiert mich das schon? Es ist ein Hobby - und aus einer alten Maschine mit systemnahen Dingen coole Dinge herauszuholen reizt mich viel mehr als es mit irgendwelchen Gigahertz-Kisten und vorgefertigten skriptbasierten hunderte MB großen Frameworks wäre. Ich bin natürlich kein John Carmack - ich bemühe mich zwar um Eleganz und Effizienz, aber ich bin ja kein Genie. Aber ich versuche natürlich, mich da immer etwas weiter zu entwickeln. Nur sind so Dinge wie WINDOWS und ähnlicher Blödsinn für mich keine Weiterentwicklung, die mich inetressiert. "Größer und langsamer" ist NICHT die Richtung, die mir vorschwebt bei meiner Software-Entwicklung.

Vielleicht finde ich morgen/übermorgen mal kurz die Gelegenheit, um das Tool da hochzuladen UND kurz zu erklären und auch die 3 VGA-Portzugriffe, um aus einem MCGA 320x200 einen Mode-Y 320x200 zu machen.
funkheld
HELP.COM-Benutzer
Beiträge: 27
Registriert: Di 25. Feb 2020, 10:42

Re: Wie war das damals mit der Spieleprogrammierung?

Beitrag von funkheld »

Hallo, danke für deine Erklärung .

Mit meinem 70 jahren habe ich Schwierigkeiten dieses alles zu begreifen.
Hast es aber schön erklärt.

Freue mich schon , wenn du das Tool mit einer Erklärung hier reinstellen könntest.
Kann es kaum erwarten. Dieser Aufbau ist eigentlich sehr spannend wenn man deine Schaltungsvarianten hier raushört.

Es ist ja etwas um richtig Experiemente zu machen.
Bei 160 halbiert man einfach die Pixelfrequenz UND die Scanline ...Register
Klasse, danke.
Eine Auflistung der Register und deren Eigenschaften dafür habe ich nie so richtig entdeckt.

Vielleicht bleibe ich heute Nacht gleich auf....
Mir ist natürlich durchaus bewußt, daß das alles vom rein ökonomischen Standpunkt her der ganzen Mühe nicht wert ist - aber was interessiert mich das schon?
He, so denke ich auch.....der Spaß und das Erreichen ist für mich das Ziel.
Ich weiss auch, das mein Gemurkse wo ich mehrere Stunden dranhänge keinen interessiert .
Und ich freue mich darüber....



Gruss
funkheld
HELP.COM-Benutzer
Beiträge: 27
Registriert: Di 25. Feb 2020, 10:42

Re: Wie war das damals mit der Spieleprogrammierung?

Beitrag von funkheld »

Ich hatte hier vor kurzen mal was gemacht, kam aber nicht zum Ziel mit der Schalterei und verschiedenen Auflösungen.
Hatte ich dann wieder aufgegeben weil ich dachte das Turbo Pascal schnallt das nicht.
Und mir fehlten die genauen Registerbeschreibungen.

Code: Alles auswählen

program vgamx;

uses Crt, Dos;
  
const
  sc_index     = $3c4;
  sc_data      = $3c5;
  crtc_index   = $3d4;
  crtc_data    = $3d5;
  map_mask     = $02;
  memory_mode  = $04;
  mode_control = $17;
  underline_location = $14;
  
  high_address = $0c;     
  low_address  = $0d;    
  
var
  vga_page0 : word;
  vga_page1 : word;
  vga_page2 : word;
  vga_page3 : word;
  vga    : word;
  vga_mx : word;
  x,y    : word;
  ch     : char;
  col    : byte;
  
Procedure SetText;  
BEGIN
  asm
    mov ax,0003h
    int 10h
  end;
END;  
  
procedure setModeY;
var
  regs: Registers;
  
begin
  with regs do
  begin
    AH := $0;
    AL := $13;
    intr($10, regs);
  end;
  
  vga_page0 := 0;
  vga_page1 := 16000;
  vga_page2 := 32000;
  vga_page3 := 48000;
  
  port[sc_index] := memory_mode;
  port[sc_data] := $06;
  
  port[crtc_index] := underline_location;
  port[crtc_data] := $00;
  
  port[crtc_index] := mode_control;
  port[crtc_data] := $e3;
  
  port[sc_index] := map_mask;
  port[sc_data] := $ff;
  
  Fillchar (Mem [vga:0],$8000,0);
  Fillchar (Mem [vga:$8000],$8000,0);
end;

procedure SetPixel( page : word ; x: word; y: word; c: byte);
begin
  port[sc_index] := map_mask;
  port[sc_data] := 1 shr (x and 3 );
  vga_mx:=vga+page;
  Mem [vga_mx:(2 shr (320*y)) + ( 2 shr x)]:=12;
end;

procedure page_flip(page1 : word ; page2 :word);
var
  temp:word;
  hi_a:word;
  lo_a:word;
  
begin
  temp := page1;
  page1 := page2;
  page2 := temp; 
  
  hi_a := high_address or (page1 and $ff00);
  lo_a := low_address or (8 shl page1 );
  
  port[crtc_index] := hi_a;
  port[crtc_index] := lo_a;
end;

begin

  vga:=$a000;
  setModeY;
  
  repeat 
    ch := ReadKey;
    
    case ch of   
      'a': begin
         For x:=0 to 199 do
         begin
           col := 12;
           setpixel(vga_page1,x,x,col);
         end;  
       end;
       
      'r':begin 
         page_flip(vga_page0,vga_page1)
       end;
    end;
  until ch = #27;
  settext;
end.
funkheld
HELP.COM-Benutzer
Beiträge: 27
Registriert: Di 25. Feb 2020, 10:42

Re: Wie war das damals mit der Spieleprogrammierung?

Beitrag von funkheld »

Ich brauche bitte die Hilfe für den Screen 320x200 mit 256 Farben für MODE X.
Ich möchte die Screens dann alle 4 unabhängig selber beschreiben und dann jeweils umschalten oder auch nur die Daten umsortieren.
Ich mache keine Experimente mit größeren Screens wie oben angegeben.

Das ist für mich Fremd :
- die Verkettung abschalten
- einen bestimmten Screen festlegen zum schreiben und lesen
- eine bestimmten Screen sichbar schalten

Und wie sind Bytes bitte aufgeteilt , 4 Bit da und 4 Bit hier.....hm...
Wie muß man bitte den Pixel umrechnen auf die verschiedenen Ebenen...hmm.

Die Mathematik bekomme ich mit den Pascal-Befehlen wohl hin.

Danke.
Gruss
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Wie war das damals mit der Spieleprogrammierung?

Beitrag von zatzen »

Hallo funkheld!
funkheld hat geschrieben:Ich hatte das auch mal vor 14 Tagen vorgehabt mit dem Turbo-Pascal 6.1. mit den 64000 Byte kopieren.
Spritebewegung sehr langsam. Wenn du die Zeit verkürzen möchtest kannst du die Verschiebepunkzahl erhöhen.
Wenn es zuviele werden , taugt die Bewegung nichts mehr.
Mit Assembler-Prozeduren (innerhalb Pascal) geht das schon relativ zügig, aber die Framerates sind dann auf einem 486 natürlich nicht wirklich flüssig. Zudem möchte ich parallel noch mehrkanälig gemischte Sample-Musik + Soundeffekte dazu generieren. Ich habe mal eine kleine Grafik-Sound Demo gemacht, die aber nicht den gesamten Bildschirmbereich aktualisiert und auf einer mäßigen Framerate läuft: https://youtu.be/uhuQgSfkg5M


Hallo DOSferatu!

Ich halte nicht grundsätzlich an MCGA fest, mir ist bloß aufgefallen über die Jahre, dass so gut wie alle tollen Spiele in 320x200x256 gehalten waren, und Mode-X brachte ich immer direkt mit 320x240 in Verbindung, und da dachte ich mir das wäre direkt ein Problem weil man dann 76800 Bytes braucht. Natürlich ist es auch einfach sehr bequem wenn man nur "mov ax, 13h; int 10h" schreiben muss und danach an $A000:0000 Pixel schreibt. Und was Scrolling angeht, da hat sich bei mir ein Gerücht festgesetzt, dass das per Registersteuerung im VGA-Modus gar nicht möglich wäre sondern nur bei EGA, da dort viel Speicher vorhanden wäre aber eben nur 32000 Byte pro Bild benötigt werden.
Ich muss mich jetzt auch in Hinblick meiner Formate wie ZVID2 mit alternativer Grafikprogrammierung beschäftigen, denn wenn der Unchained-Mode eine spaltenweise Beschreibung des Speichers verlangt muss ich ZVID2 ganz anders aufziehen.
Wenn meine Fähigkeiten ausreichen mache ich also gerne in Zukunft etwas im Unchained Mode, würde es aber bei 320x200 belassen. Alternativ waren meine letzten Gedanken, die Problematik in MCGA Umgebung zu lösen, nur den Hintergrund zu restaurieren der überschrieben wird, und dann wiederum nur die Bildschirmbereiche in den Grafikspeicher zu aktualisieren, die verändert wurden. Theoretisch und angenähert machbar wäre das, indem man alles in 8x8 Blöcke unterteilt und beim Setzen von Sprites vermerkt welche Bereiche betroffen sind. Aber umständlich, und geht nur ohne Scrolling, und tendentiell braucht man dann auch einen 64000 Byte Puffer für den Hintergrund.

Trotzdem bleibt die Frage, wenn ich jetzt nicht total schwer von kapee bin, auch im Unchained Mode: Wie kann man auf elegante Weise nur den Bildschirmbereich eines Sprites aktualisieren, ohne wegen ein paar Sprites die sich bewegen den ganzen Hintergrund neu zeichnen zu müssen? Ich bin vor kurzer Zeit auf ein kleines Tutorial gestoßen wo gesagt wurde, man könne vor setzen des Sprites den Hintergrund einlesen, dann das Sprite setzen, warten, schnell mit dem eingelesenen Hintergrund löschen, usw. Vielleicht funktioniert das so wenn wenig Grafikdatenverkehr ist, aber ansonsten flackert das bestimmt wie verrückt.
mov ax, 13h
int 10h

while vorne_frei do vor;
funkheld
HELP.COM-Benutzer
Beiträge: 27
Registriert: Di 25. Feb 2020, 10:42

Re: Wie war das damals mit der Spieleprogrammierung?

Beitrag von funkheld »

Im Unchained Mode kann man doch im Hintergrund schreiben und dann den Screen sichtbar schalten.
Es gibt auch Befehle wo man auf den Strahlenrücklauf wartet und dann arbeitet man solange der Rücklauf aktiv ist.

Gruss
funkheld
HELP.COM-Benutzer
Beiträge: 27
Registriert: Di 25. Feb 2020, 10:42

Re: Wie war das damals mit der Spieleprogrammierung?

Beitrag von funkheld »

Habe den Mode X in einfacher Version 320x200 256 Farben noch mal versucht in TP klappt nicht.

Register freischalten......hmmm...wieder was neues.

2 beschreibe ich und die beiden schalte ich dann um...funktioniert nicht.
Hmmm..
Vieleicht kann hier mal bitte DOSferatu helfen?

Danke.
Gruss

Code: Alles auswählen

program vgamx;

uses Crt, Dos;
 
const
  
  vgapage      = $a000;
  
  seq_addr     = $3c4;
  seq_data     = $3c5;
  
  crtc_addr    = $3d4;
  crtc_data    = $3d5;
 
var
  activ_page,activ_page1,activ_page2:word;
  x : word;
  
  color: byte;
  
  ch: char;
  
Procedure SetText; 
BEGIN
  asm
    mov ax,0003h
    int 10h
  end;
END; 
 
procedure vgamode;
var
  regs: Registers;
 begin
  with regs do
  begin
    AH := $0;
    AL := $13;
    intr($10, regs);
  end;
end; 

procedure unchained;
begin
  port[seq_addr] := $04;
  port[seq_data] := $06;
 
  portw[seq_addr] := $ff02;
 
  port[crtc_addr] := $14;
  port[crtc_data] := $00;
  
  port[crtc_addr] := $17;
  port[crtc_data] := $e3; 
end;

procedure page_flip(page1 : word; page2 : word);
var
  hiad :word;
  lowad :word;
  temp : word;
  
begin 
  temp :=page1;
  page1:=page2;
  page2:=temp;
  
  hiad:= $0c or (page1 and $ff00);
  lowad:= $0d or (page1 shl 8);

  portw[crtc_addr] :=hiad;
  portw[crtc_addr] :=lowad;
end;  

procedure SetPixel(x: word; y: word; c: byte);
begin
  port[seq_addr] :=$02;
  portw[seq_data]:= (x and 3) shl 1;
  
  Mem [vgapage:activ_page+(y shl 6)+(y shl 4)+(x shr 2)] :=c;
end;

begin
  vgamode;
  unchained;
  
  repeat
    ch := ReadKey;
   
    case ch of   
      'q': begin
         color := 12;
         activ_page :=16000;
         activ_page1 :=16000;
         
         For x:=0 to 199 do
         begin         
           setpixel(x,x,color);
         end; 
       end;
       
      'w': begin
         color := 14;
         activ_page :=32000;
         activ_page1 :=32000;
        
         For x:=0 to 199 do
         begin         
           setpixel(x,x div 2,color);
         end; 
       end;
       
      'f':begin
         page_flip(activ_page1,activ_page2);
       end;
       
      'u':begin
         unchained;
       end;
    end;
  until ch = #27;
  settext;
end.
In Borland c ++ 3.0 funktioniert es:

Code: Alles auswählen

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <mem.h>
#include <conio.h>

#define SC_INDEX            0x03c4    
#define SC_DATA             0x03c5
#define CRTC_INDEX        0x03d4    
#define CRTC_DATA         0x03d5

typedef unsigned char  byte;
typedef unsigned short word;
typedef unsigned long  dword;

word x,y;
word active_page,active_page1, active_page2 ;

byte *VGA=(byte *)0xA0000000L;       
                                         
void SetTextMode ()
{
    _AH = 0;
    _AL = 0x03;
    geninterrupt (0x10);
}

void SetMode13h ()
{
    _AH = 0;
    _AL = 0x13;
    geninterrupt (0x10);
}

void set_unchained_mode(void)
{
  word i;
  dword *ptr=(dword *)VGA;           

  outp(SC_INDEX, 0x04);       
  outp(SC_DATA,  0x06);

  outpw(SC_INDEX, 0xff02);      

  for(i=0;i<0x4000;i++)   
   *ptr++ = 0;

  outp(CRTC_INDEX,0x14);
  outp(CRTC_DATA, 0x00);

  outp(CRTC_INDEX,0x17);     
  outp(CRTC_DATA, 0xe3);
}

void page_flip(word *page1,word *page2)
{
  word high_add,low_add;
  word temp;

  temp=*page1;
  *page1=*page2;
  *page2=temp;

  high_add = 0x0c | (*page1 & 0xff00);
  low_add  = 0x0d | (*page1 << 8);

  outpw(CRTC_INDEX, high_add);
  outpw(CRTC_INDEX, low_add);
}

void plot_pixel(int x,int y,byte color)
{	
  outp(SC_INDEX,0x02);         
  outp(SC_DATA,  1 << (x&3) );
  VGA[active_page+(y<<6)+(y<<4)+(x>>2)]=color;
}

int main()
{
  byte cmd;
  byte col;
	
  SetMode13h ();       
  set_unchained_mode(); 
	
  do	{
        cmd = getch();
			
       switch (cmd)
       {
         case 'q': 
            col=12;        
            active_page =16000;
            active_page1 =16000;
            for(x=0;x <=199;x++)
            {
              plot_pixel(x,x,col);
            } 
	 break;
         
         case 'w': 
            col=14;
            active_page = 32000;
            active_page2 =32000;
	    for(x=0;x <=199;x++)
	    {
	     plot_pixel(x,x/2,col);
	    }				 } 
	 break;
        
	 case 'f':
  	    page_flip(&active_page1,&active_page2);
	 break; 
         
         case 'u':
  	    set_unchained_mode();
	 break; 						 
       }
					
   } while (cmd != 'x'); 			
}
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Wie war das damals mit der Spieleprogrammierung?

Beitrag von zatzen »

Nur kurz ein paar Gedanken, @DOSferatu:
Ich habe mir Turrican II für DOS auf Youtube angesehen, und die flüssigen Bewegungen sind natürlich beeindruckend, wobei ich nicht weiss auf welchem Computertyp das ganze gelaufen ist, mit einem Pentium wäre soetwas ja auch ohne allzu große Trickserei annähernd möglich.
Für mich stellt sich nun die Frage, muss ich mir wirklich zum Ziel setzen derart effektiv zu programmieren? Damit ginge auch einher mich von meinen Speicherplatz-schonenenden aber weniger performanten Formaten zu verabschieden. Es kommt hinzu dass ich so ein Spiel wie Turrican zwar beeindruckend finde aber es selber gar nicht spielen wollen würde.
Und der logische nächste Schritt an mein Kotzman II anzuknüpfen ist nicht unbedingt das Ziel, es mit "weltklasse" Programmierern aufnehmen zu können, die zudem noch ein Team haben, allein schon getrennt nach Grafik und Sound, so dass sie sich voll und ganz aufs Programmieren konzentrieren können.
Nunja, ich könnte zum einen dieses Sound-Memory realisieren, zum anderen ein Jump&Run im Stil grob ähnlich wie Donkey Kong, ohne Scrolling, kleine Sprites und nicht zu viele davon, aber grafisch etwas großzügiger gestaltet und mit Hintergrundgrafik, vielleicht so, dass je nachdem ein wenig Dungeon-Feeling aufkommt, oder auch irgendwelche Landschaften, bloß nicht so steril wie die frühen Arcade-Spiele.
Du hast noch nicht Deine Meinung zu meiner vielleicht gar nicht so guten Idee geäußert, nur den Hintergrund zu restaurieren der überschrieben wurde und nur in den Grafikspeicher zu kopieren, was geändert wurde. Je nach Sprite-geschehen kommt mir diese Idee aber so vor, als könnte sie sogar schneller sein als Double-Buffering bzw. Page-Flipping bei dem man immer den ganzen Hintergrund restauriert. Ich kann mich da aber auch katastrophal irren. Bloß, gegenüber kompletten Hintergrund restaurieren UND den Puffer in den Grafikspeicher kopieren ist dieses "nur kopieren was sich geändert hat" wohl schneller.
Also, ich muss mich selbst einfach richtig einschätzen, ich will ja letztlich auch mal produktiv sein, bin aber nunmal ein Amateur und mache manche komische und vielleicht unnötige Dinge wie ZVID2 und ZSM einfach weil sie mir Spaß machen. Irgendwo zwischen "schlecht und super-unperformant programmiert" und "bis aufs letzte Bit getweakt und auf Geschwindigkeit optimiert" befinde ich mich, vielleicht auch näher am ersteren. Ich arbeite erstmal mit dem was ich habe und beherrsche, und sehe dann weiter. Ich bin interessiert an fortgeschrittener VGA-Programmierung, aber ich glaube das würde mich im Moment ziemlich überfordern, wo mein letzter Stand soetwas wie Kotzman II ist...
mov ax, 13h
int 10h

while vorne_frei do vor;
Antworten