Eigenes Videoformat

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

Re: Eigenes Videoformat

Beitragvon DOSferatu » Di 13. Aug 2019, 08:02

zatzen hat geschrieben:Ich antworte später ausführlicher.

Na gut...

zatzen hat geschrieben:Nur schon einmal so viel:
Ich habe etwas experimentiert und ZVID2 für lohnenswert und funktional befunden.
Die Freepascal Routine funktioniert mit clipping an allen Bildschirmseiten und spiegeln, ich muss jetzt nur noch das Format strukturieren,

Ich habe schon mehrmals versucht, Freepascal (auch neuere Versionen) zu benutzen, aber mein Zeug compiliert da nicht. Vielleicht programmiere ich zu seltsam. Ich glaube, die supporten immer noch nicht die mem[] und port[] Dinge - weiß gerade nicht genau, ich glaube, es gab auch noch andere Probleme. Mir vergeht irgendwie die Lust, die Units, die ich in den letzen 25 Jahren geschrieben habe, jetzt auch noch für FreePascal (das angeblich 100% kompatibel zu Borland/Turbo Pascal ist) anzupassen. Aber egal.

zatzen hat geschrieben: und dafür muss ich folgendes klären:
Wenn ich mit getmem Speicher reserviere, in welchem Rahmen wird sich dann das zugeordnete
Offset befinden? Bleibt es unterhalb von 16, unterhalb von 8 oder sogar verlässlich bei 0 ?
Oder kann es sogar passieren, dass es Werte >= 16 annimmt, etwa wenn man nur kleine
Mengen reserviert?

Kann ich nicht genau sagen - aber ein entsprechendes Testprogramm, das viele "krumme" Speichergrößen reserviert und dann den Offset des zugewiesenen Pointers testet/ausgibt, könnte das leicht klären. Es sollte kein Hexenwerk sein, so etwas zu schreiben.

zatzen hat geschrieben:Ich würde das ganze gern im Zweifelsfall so zurechtstutzen beim Laden eine ZV2 Datei, dass ich in der ASM Routine von absoluten Verhältnissen ausgehen kann.
Also bspw. mit getmem den benötigten Speicher + 16 reservieren, und Die Daten
dann an (segment+1:0000) laden.

Klar, mach ich auch immer so - und meine eigene Speicherverwaltung liefert sowieso ausschließlich Pointer mit Offset=0.

Ich habe mal "irgendwo gelesen", daß GetMem immer in minimal 8er-Schritten reserviert - aber ich weiß nicht mehr, wo das war und ob das stimmt - ich verlasse mich da auf nichts.

Aber: Wie Du ja weißt, sind die Segmentanfänge alle 16 Bytes im Speicher, so daß also der Pointer 1234:16 genau auf die gleiche Speicherstelle zeigt, wie der Pointer 1235:0 und der Pointer 1233:32... usw.

Ich mache da immer so etwas, das ich selbst als "Normalisieren des Pointers" bezeichne:

Code: Alles auswählen

procedure PNormalize(var P:Pointer);
var PX:record O,S:word;end absolute P;
begin
with PX do begin inc(P,O shr 4);O:=O and 15;end;
end;

Der Pointer zeigt damit auf die gleiche Adresse, aber sein Offset ist immer nur 0 bis 15.

Jetzt weiß ich nicht, ob FreeMem, bei dem man ja den Pointer angeben muß, GENAU den von GetMem zugewiesenen Pointer braucht, oder auch mit diesem "normalisierten" zurechtkäme. Da kann man sich natürlich auch einen zweiten Pointer machen (vorher in einen anderen kopieren und den normalisieren) ODER man macht das Ganze als Funktion:

Code: Alles auswählen

function GetPNormalize(P:Pointer):Pointer;
var PX:record O,S:word;end absolute P;
begin
with PX do begin inc(P,O shr 4);O:=O and 15;end;
GetPNormalize:=P;
end;


Ja, in Assembler kann man das natürlich mit weniger Geraffel und etwas eleganter machen (wie man - meiner Meinung nach - VIELES in Assembler kürzer und eleganter machen kann als in vielen Hochsprachen - obwohl es ja offiziell angeblich umgekehrt ist), aber es soll hier verdeutlichen, was ich meine/wie es funktioniert.

Falls man sowieso nur ein "Null-Offset-Segment" haben will, braucht man zwar trotzdem auch den Pointer (damit man ihn mit FreeMem wieder freigeben kann), aber da könnte man z.B. das machen:

Code: Alles auswählen

function GetMemSeg(var P:Pointer;SZ:word):word;
var PX:record O,S:word;end absolute P;
begin GetMem(P,SZ+15);
with PX do GetMemSeg:=S+(O shr 4)+ord((O and 15)<>0);
end;


Erklärung (falls nötig) : Man reserviert 15 Bytes mehr als man braucht - für den Fall, daß der Offset an einem "krummen" Wert landet. 15 ist ausreichend, es braucht nicht 16.
Dann weist man dem Segment den "normalisierten" Wert zu. Das ganz letzte (ab "ord") bedeutet: Der Begriff innerhalb ord(), also (O and 15)<>0 ergibt einen Wahrheitswert FALSE oder TRUE und ord() macht daraus 0 oder 1, d.h. falls der Offset trotz Normalisierung "krumm" wäre, daß man dann zum Segment 1 addiert.

Ich hoffe, ich konnte es einigermaßen verständlich ausdrücken. Man kann das Ganze natürlich auch anders darstellen oder machen - aber für jeden, der erst einmal verstanden hat, wie das segmentierte x86-Speichermodell funktioniert, sollte es kein Problem sein, "glatte" Segmente zu reservieren/benutzen.

Man muß natürlich bei o.g. Function dann darauf achten, bei FreeMem die Größe+15 freizugeben. Und außerdem habe ich in o.g. Function auch keine Prüfung drin für den Fall, daß der Speicher nicht reicht oder die gewünschte Größe > 65521 wird - das kriegt man sicher selbst raus, falls man's braucht.
Benutzeravatar
zatzen
BIOS-Flasher
Beiträge: 372
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Eigenes Videoformat

Beitragvon zatzen » Di 13. Aug 2019, 16:30

Vielen Dank für die schnelle Antwort!

Sehr elegant das "inc(P,O shr 4)" da bin ich gar nicht drauf gekommen.

Ich muss aber überlegen ob ich nicht doch in der ASM Routine ein paar Takte und Zeilen mehr einbringe (außerhalb innerer
Schleifen), es wäre nämlich auch reizvoll hinsichtlich der Einfachheit, die ZV2's ganz standardmäßig reinzuladen und nicht
mit spezialisierten Routinen.

Was Freepascal angeht, wenn man das in Windows benutzt, dann ist das ja auf Protected Mode und 32 Bit ausgelegt, von
Befehlen wie mem[] oder port wird eindeutig abgeraten. Im Gegensatz zu Turbo Pascal für Dos kann man bei Freepascal
einfach ein Array von z.B. 1 GB anlegen, und so gehe ich dann auch vor wenn ich in Freepascal programmiere. Einfach
Arrays in beliebiger Größe, meistens dynamisch die Größe über setlength festgelegt. Getmem ist wohl möglich, aber
mehr oder weniger unnötig weil man ja 4 GB Speicher hat und somit die Unterscheidung von Codesegment, Datensegment
und Heap gewissermaßen hinfällig wird. Ich programmiere in FPC meist datenverarbeitende Tools, und da kommt es
mir nicht so sehr auf die Performance an, es soll nur möglichst unkompliziert zu programmieren sein und funktionieren.
Freepascal wird nur zu Turbo Pascal kompatibel sein, wenn man ziemlich hardwarefern programmiert, bzw. muss
man einfach das lineare(?) Speichermodell von Freepascal berücksichtigen.
DOSferatu
DOS-Übermensch
Beiträge: 1161
Registriert: Di 25. Sep 2007, 12:05
Kontaktdaten:

Re: Eigenes Videoformat

Beitragvon DOSferatu » Di 13. Aug 2019, 18:56

zatzen hat geschrieben:Sehr elegant das "inc(P,O shr 4)" da bin ich gar nicht drauf gekommen.

Wäre noch eleganter, wenn ich mich nicht verschrieben hätte.
Es muß selbstverständlich heißen:

Code: Alles auswählen

inc(S,O shr 4);
drzeissler
DOS-Gott
Beiträge: 3236
Registriert: Mo 8. Feb 2010, 16:59

Re: Eigenes Videoformat

Beitragvon drzeissler » Di 20. Aug 2019, 11:20

Bei YT gibt es einen, der ein FullscreenVideo mit Ton (Beavis&Butthead) auf einem 286/8 oder 10Mhz in VGA laufen lässt. Sowas wäre mal echt interessant. Das wäre ein cooles Feature für ein A2286/8.
CPU: 486 DX2/66 MOBO: SNI-D882 RAM: 3x16MB - FDD: 3,5" 1,44MB HDD: 6,4GB Seagate ISA(1): Audican32Plus PCI(1): 3com TX 905 OS: MsDos622 - Win95a - WinNT 3.51
Benutzeravatar
zatzen
BIOS-Flasher
Beiträge: 372
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Eigenes Videoformat

Beitragvon zatzen » Do 29. Aug 2019, 22:21

drzeissler hat geschrieben:Bei YT gibt es einen, der ein FullscreenVideo mit Ton (Beavis&Butthead) auf einem 286/8 oder 10Mhz in VGA laufen lässt. Sowas wäre mal echt interessant. Das wäre ein cooles Feature für ein A2286/8.

Das wäre wirklich mal interessant zu sehen. Ich konnte es leider auf Youtube nicht finden. Gibt so viele Videos...
Und Zusätze wie 286 oder vintage helfen auch nicht. Ich selber könnte das nur unter großem Datenaufkommen
realisieren. Fürs Bild meinetwegen 15 fps und pro Bild im Schnitt 15-25 KB - 320x200 und mit eigener Palette für jedes
Bild, 256 oder 128 Farben, da die Palette für jedes Bild gewechselt werden müsste, immer im Wechsel wenn gerade
nur Farben verwendet werden die nicht geändert werden. Oder man macht Qualitäteinbußen und verwendet
eine generalisierte Palette mit 256 festfarben, dann wäre auch Delta-Kodierung denkbar.

DOSferatu hat geschrieben:Aber es gibt eben Sachen, ohne die das Spiel NICHT funktionieren würde und bevor diese nicht funktionieren/eingebaut sind, kann man sich nicht über die "Zusatzfeatures" hermachen. Wenn die zwar funktionieren, aber für die unbedingt zur Funktion notwendigen Sachen kein Speicher/Rechenzeit/usw. mehr da ist, bekommt man das Programm/Spiel nicht fertig. Deshalb ist es so wichtig, erst sicherzustellen, daß das Grundgerüst, aus dem das Spiel besteht, lauffähig zu bekommen, bevor man überlegt, wieviel Speicher/Rechenzeit usw. man für die "Süßigkeiten" einsetzen will.

Für's erste backe ich kleine Brötchen. D.h. die Grafik wird am Ende vielleicht keine 100 KB füllen (zumindest während
eines Levels), und mit Nutzung von ZVID2 fast nur die Hälfte davon. Zurückblickend auf Kotzman II war der
Programmcode auch nicht so sonderlich groß, naja es ist 24 Jahre her und ich kann mich auch nicht mehr so exakt dran
erinnern. Jedenfalls denke ich dass ich es mir am Ende sogar leisten kann, mehr Sounddaten als Grafikdaten
unterzubringen, einfach weil noch Platz sein wird. Und wenn nicht, dann werden die Sounddaten eben entsprechend
kleiner und kompromittierter, das ist alles kein Problem. Sound kommt am Schluss oder wird zwischendrin angepasst,
wenn's mit dem Speicher eng wird, da ist man flexibel. Und ich bin kein "Pro", habe keinen Wettbewerb zu gewinnen,
daher kann ich einfach mal nach Lust und Laune loslegen und ein Spiel machen das vielleicht etwas sonderbar ist.
Wenn ich denn mal loslege. Ich habe in letzter Zeit mal wieder ein wenig gepixelt und merke dass ich das noch ganz gut
kann, vielleicht sogar besser als früher.
Aber es kommt noch das Prokrastinieren dazu, und ich bin auch mehr abgelenkt als zu Kotzman II Zeiten, weil ich mehr
Hobbys habe als damals.

DOSferatu hat geschrieben:[anm. Stichwort Datenkompression] Wenn man viele Animationsphasen hat, aber wegen Performanceproblemen gar nicht die Framerate erzeugen kann, um diese ruckelfrei darzustellen, sondern deshalb Phasen auslassen muß, wird das Ganze wie eine Schlange, die sich selbst in den Schwanz beißt...

Einerseits hast Du Recht, und ich habe auch schon überlegt ob ich alles was nicht animiert ist, also soetwas wie
Kachelelemente, als simple Bitmaps im Speicher halte und mit einfachen Kopierroutinen in den Puffer haue.
Aber ich finde man muss erstmal sehen wie die Kompression performt.
Im Prinzip kommt die Verlangsamung durch SHR, AND und MOV Befehle und das Vorbereiten von Offset-Registern
Zustande. Das sind durchaus eine handvoll Takte. Allerdings war ich erstaunt, in dem ASM Guide zu lesen, dass STOSB
auch auf einem 486er 5 Takte braucht. Also wenn jemand damit arbeitet, könnte das auch recht langsam werden.
Oder ich übersehe da etwas, dass "MOV ES:[DI], AL ; INC DI" doch nicht schneller (obwohl nur 2 Takte) ist...
Ich musste nur dran denken, weil ich früher oft STOSB verwendete, da es so praktisch ist wenn man das nicht so
ausformulieren muss mit MOV und INC. REP STOSx/MOVSx ist wohl wieder eine andere Sache, was die Performance angeht.
Wie Du schreibst, der Nutzen ergibt sich erst ab einer bestimmten Datenmenge.

Ich werde auch erst einmal versuchen, alle Sprites mit derselben Routine darzustellen, nämlich ZVID2.
Diese enthält praktischerweise ein solides blockweises Clipping, man braucht sich letztlich gar nicht mehr drum
kümmern wo das Sprite auf dem Bildschirm landet, egal ob links, rechts unten oder oben raus oder in einer Ecke,
oder ob es überhaupt noch im sichtbaren Bereich ist, das kann die Routine alles sicher abfangen. Für mich ein kleines
Novum. Ich muss nur ringsherum den Puffer 3 Pixel größer machen als das letztlich sichtbare Bild.
Es wird sich zeigen was letztlich unterm Strich schneller ist - die Grafikobjekte vor Aufruf der Routine auf Sichtbarkeit
prüfen (innerhalb des Screens wenigstens noch ein Stückchen zu sehen), oder einfach alles ungeprüft der Routine
weitergeben, die sich dann bei nicht-Sichtbarkeit nach ein paar handvoll Takten und vielleicht zwei Sprüngen sofort
wieder verabschiedet.
An dieser Stelle wäre noch gut zu wissen um einen Sprung sparen zu können, wenn Du es gerade aus dem
Ärmel schütteln kannst: Mit welchen Assembler-Befehlen kann ich eine Pascal-ASM-Prozedur verlassen?
Oder ist das unklar weil man letztlich nicht sagen kann ob RET oder RETF nötig ist?

Zeichnen/Löschen Methode, nur wenn sich etwas geändert hat: Um in den Puffer zu schreiben ist das ein fummeliges
Unterfangen, aber wenn man sich z.B. ein 1000 Byte (40x25 8x8) Datenfeld anlegt wo man vermerkt ob etwas geändert
wurde... Also nur so ein Gedankenanstoß, ohne die Umsetzung wirklich durchdacht zu haben - dann könnte man
wenigstens beim Kopieren in den Grafikspeicher sparen. Bringt aber spätestens bei Scrollings nichts mehr und ist wohl
auch nur wieder mit mehr Rechenaufwand verbunden. Aber nur so ein Gedanke.

DOSferatu hat geschrieben:Naja, mit 44100 Hz müssen aber doppelt so viele Daten pro Sekunde berechnet werden als mit 22050 Hz - das sollte doch klar sein, oder? Also auch doppelt so viele pro Frame.

Ja, das stimmt. Ich bezog das nur irgendwie auf den Speicherbedarf für die Sounddaten. Und da kann man ja auch
einfach 8 kHz in 44.1 kHz reinmischen. Und ein 2 KB Puffer (ca. 44100 Hz bei 20 fps) tut speichermäßig ja auch keinem
weh, aber klar, es geht Dir um Performance. Aber Mixrate ist bei mir ja verstellbar bis auf 11 kHz runter.

Und ja, Du plädierst für größere Soundpuffer für bessere Performance, und Deine Bild-Ton-Verschiebungstoleranz liegt
bei glaube ich 200 ms, also 1/5tel Sekunde. Ist für mich eben leider nicht akzepabel wenn ich z.B. eine Explosion zuerst
nur sehe und dann erst der Ton verspätet kommt, so als wäre ich hundert Meter davon entfernt.
Es ist einfach so, ich habe einiges mit Video und Ton gemacht. Wenn es dort einen Versatz gibt, selbst nur 50 ms, dann
ist das schon ärgerlich. Und ich möchte mir für ein Spiel einfach diese Präzision ermöglichen.
Ich habe mir letztens Prince Of Persia II angesehen, da ist der Ton punktgenau. Möglicherweise weil sie Adlib verwenden
und den Digisound ohne Puffer realisieren, immer nur ein Sound gleichzeitig durch direkten "DMA Auftrag" im
Hintergrund wenn man so will.

Auch wenn ich beginne, ein variables Timing zu verstehen, werde ich erstmal, auch zugunsten des synchronen Sounds,
das ganze mit dem Interrupt des Soundpuffers timen. Hab ich ja schon oft genug gesagt. Es verschwendet Performance-
Potential, ich muss immer vom Worst-Case ausgehen, was auch dazu führen wird dass das Spiel insgesamt eher
bescheiden ausfallen wird was die Rechenleistung angeht, auch oft gesagt: Ich denke an sowas wie Captain Comic, für
das damals völlig ein 286er ausreichte, und ich würde davon ausgehen dass ein ähnlich geartetes Spiel mit etwas mehr
Framerate und höher auflösendem Scrolling, und meinen extra Features wie ZSM und ZVID auf einem 486er zu realisieren
wäre.

Das mit den Steuerungsbits könnte ich aber übernehmen, wobei da vielleicht auch einfach Boolean Variablen gehen, die
paar Byte kann man ja noch haben, hängt wohl auch davon ab wie es letztlich im Programm interpretiert wird, wenn man
alles in ein Byte packt hat es vielleicht bei Assembler Vorteile.

Danke jedenfalls für die ausführliche Darstellung, ich müsste mir solche Erklärungen mal irgendwo außerhalb des Forums
archivieren, damit ich gezielter und ohne zu suchen darauf zugreifen kann.

ZVID2: Das ist alles nur "because I can" ("...and want").
Richtig sinnvoll wäre es nur für ein Adventure wo es nicht auf Geschwindigkeit aber auf viel Speicher ankommt.
Ich schätze die Kunst, Sprites zu skalieren und zu drehen, aber ich persönlich mag die optischen Resultate meistens
nicht, eine gepixelte Grafik muss für mich ihre Konsistenz bewahren, eher würde ich für Drehungen ein paar Phasen
pixeln. Das alles vielleicht auch, weil ich mit Spielen aufgewachsen bin, in denen nicht gedreht und skaliert wurde (bis
auf manche Momente in Monkey Island z.B). Das "wilde" Skalieren, Stauchen und Drehen erfuhr ich erst bei Duke Nukem
3D, und dieses Spiel hatte für mich nicht mehr den Zauber einer homogenen Pixel-Landschaft, es war alles eher nur noch
zweckmäßig und informativ, voller Aliasing und unförmig aufgeblasenen Pixeln. Dreh- und skalierbar kann ein Segen sein,
wenn man nicht so ein hohes Bedürfnis an die "Integrität" der Pixel hat. Es ist auch eine Stilfrage - spätestens bei
Echtzeit-Vektorgrafik wie bei "Alone In The Dark" braucht man nicht mehr über Aliasing oder soetwas meckern.
Und auch verschiedene Paletten können höchst praktisch sein, das hat auch das gute alte NES ja so gemacht bei einigen
Spielen. Mich haben zu der Zeit als ich begann zu programmieren aber vor allem Adventures geprägt, wo jede Figur ganz
konkret und individuell war. Daher gehe ich so auch an eigene Spiele heran, jeder Figur, jeder Gegner, hat seine
individuellen Sprites - ich hatte also nie den Wunsch etwas anders einzufärben oder auch s.o. zu skalieren oder zu
drehen, daher habe ich mich bislang einfach nur damit beschäftigt, etwas komprimiert zu speichern, damit ich möglichst
viel Grafik bewerkstelligen kann.
Ausreichen würde für meine Zwecke in gewissem Rahmen wohl auch einfach eine RLE Kompression, aber ich bin eben
etwas verspielt. Ich glaube, Datenformate oder Kompressionen zu erfinden fasziniert mich alleine schon genug, siehe
ZSM... Ich hätte ja auch einfach einen abgespeckten MOD-Player schreiben können, aber das wäre mir zu viel sinnlos
das Rad neu erfinden gewesen.
Dein Image-Einpass-Programm nimmt in etwa die Stelle ein, die bei mir der ZVID2 Encoder hat. Natürlich eher schlecht
vergleichbar, aber vom Aufwand her könnte es in etwa hinkommen.

DOSferatu hat geschrieben:Und - so traurig das jetzt vielleicht klingt - auch Du wirst wohl Byte für Byte arbeiten müssen.

Ja, das war schlecht nachgedacht. Selbst wenn ich das bei nicht-Transparenz vielleicht so machen könnte - es bringt
nichts, erst ein 32 Bit Register mit Bytes vollzuschieben um es dann mit einem Rutsch in den Speicher zu knallen.
Das ganze trifft nur für den Fall zu, wenn ein ganzer Block einfarbig und nicht transparent ist.
Dann werde ich das so machen.

DOSferatu hat geschrieben:Ich habe schon öfter mal bereut, manches von meinem alten Zeug "zu dicht komprimiert" zu haben, so daß kein Platz für Erweiterungen mehr da war und habe mich andererseits jedes Mal gefreut, wenn ein altes Format noch Dinge "offen gelassen" hatte, so daß ich es noch weiter verwenden und erweitern konnte.

Mehr oder weniger könnte ich ZSM bereuen, es wäre schwer das Format abwärtskompatibel zu erweitern - denke ich
mal. Aber ich habe auch nicht so viele "Fans" dass das für mich wichtig wäre. Wenn ich für ein Spiel mehr Funktionen
bräuchte, würde ich eine neue Version machen, die dann eben mit dem bisherigen Player nicht mehr kompatibel wäre.

DOSferatu hat geschrieben:Wenn ich heutzutage ein Format benutze, will ich NICHT mehr (wie leider früher manchmal!) alles "um das Format", bzw. "um diese Routine herum" bauen müssen. Da finde ich es inzwischen besser, Zeug so zu machen, daß man es "nur noch einzubauen" braucht und es quasi alles, was es braucht, selbst macht, bzw. "von selbst mitbringt".

Auch deswegen jetzt ZVID2, was neben ein paar Variablen nur aus einer Prozedur bestehen wird. Mal abgesehen von
Initialisierungs-Routinen, die aber auch nur Sachen machen die man auch "zu Fuß" machen könnte. ZVID(1) war eine
ultra-komplizierte Orgie aus Prozeduren und haufenweise Pointern.

DOSferatu hat geschrieben:Naja, daß für "flächige Dinge" (wie Sprites, Rechtecke/Polygone) der fortwährende Zugriff auf eine generalisierte Pixelroutine (die jedes Mal aus Koordinaten die Pixelposition ausrechnet und für den Grafikmode entsprechend die Daten setzt für den Pixel) eine Scheißidee (weil langsam) war, habe ich schon recht schnell herausgefunden.

Ich meine nicht Punkt für Punkt, was in QuickBASIC mit PSET(x, y, color) gemacht wurde. Sondern das Grafik-PUT, man
muss auf ein Integer-Array mit einer Bitmap (für VGA 1 Byte pro Pixel) verweisen und dann die Koordinaten der oberen
linken Ecke. Was PUT macht dürfte etwa das gleiche sein wie rep stosb und das eben für mehrere Zeilen, d.h. es ist
eigentlich sehr schnell. Aber wenn man das auf einem 286er macht, mit einem 32x32 Sprite und es mit nur 1 Pixel
jeweiligen Versatz animiert, dann dauert es schon ein paar Sekunden bis das Ding über den Bildschirm gewandert ist.
Oder es war doch ziemlich schnell und ich habe es mit Sound 0, .1 ausgebremst. Ist fast 30 Jahre her...

DOSferatu hat geschrieben:Um zu merken, daß es wirklich funktioniert, reicht es nicht, zu sehen, ob die Steuerung alleine oder die Grafik alleine oder der Sound alleine funktionieren. Erst, wenn ALLES ZUSAMMEN arbeitet und immer noch funktioniert, DANN wird's ein brauchbares Spiel.

Ich bin relativ optimistisch. Ich habe ja doch ein paar Spiele und Demos programmiert, wenn auch nicht immer die
tollsten. Der Pentium 200 MMX den ich seit 1997 habe hat natürlich alles gefressen.
Das verzerrt die Erwartung an einen 486er ein wenig.

DOSferatu hat geschrieben:Daß ich JETZT so einen "Aufwand" betreibe, einen einigermaßen gescheiten "Rahmen" für Spiele zu schaffen, liegt daran, daß zum Schluß nicht bei jeder neuen Spielidee wieder von Null angefangen werden soll, im Sinne von: Wo krieg ich den ganzen Speicher her? Wie baue ich das Zeug so zusammen, daß es funktioniert ohne abzuschmieren oder rumzuruckeln? Also quasi soll dieser ganze Kram schon so "getestet und für gut befunden" sein, daß man ein Spiel drauf entwickeln kann OHNE jedes Mal komplett neue Routinen bauen zu müssen, die eigentlich das gleiche machen wie die des letzten Spiels.

Ja, da stimme ich Dir absolut zu. Wenn man sich manches klassische NES Spiel ansieht, scheint es auch so, als hätten die
immer wieder die gleiche Engine genommen. Das meine ich absolut nicht negativ, sondern es ist professionell wenn man
sich einen Standard schafft für den man Spiele designen kann. Fast so, als würde man sich dadurch Hardware erschaffen.
Ich wollte ja auch vor ein paar Jahren schon so ein Game-System schaffen, was ich dann während einer
Spieleentwicklung erweitern wollte. Ich habe da aber nicht so klare Vorstellungen wie Du, und bin ersteinmal froh dass
ich einen Sound-Standard habe, und mal sehen wie ZVID2 wird. Letzteres nimmt mir auch die Sorgen ab, wie ich Grafik
in das Spiel bekomme und dabei noch bestmöglich Speicher spare - ich muss sie nur auf den Heap laden und die Routine
mit entsprechenden Parametern aufrufen.

DOSferatu hat geschrieben:Meiner Erfahrung nach scheinen sehr viele (spätere) Coder, vor allem im 3D-Bereich, das so wie ich zu machen: Die FPS-Raten der Spiele sind variabel und hängen davon ab, wie aufwendig gerade berechnet werden muß.

Ich hab ja ne Zeit lang mit ein paar Jungs 3D Spiele gezockt. Ich habe einen Spruch im Kopf: "Framerate is God".
Kennt man vielleicht nicht, hab ich aber irgendwie mal gehört. Bei 3D Ego Shootern sind Framerates von unter 70 schon
nicht mehr tolerabel, und als die ersten LCDs gängig wurden, wurde trotzdem noch an Röhren gespielt, weil die schneller
sind. Und wir haben in 320x200 gespielt, mit Pentiums...

Ich stimme Dir absolut zu, dass das objektiv gesehen besser ist mit variabler Framerate. Für mich ist es nur großes
Neuland zusätzlich dazu dass ich ein Spiel zu bewerkstelligen hätte, und der Trade-Off wäre die Ton-Asynchronität.
Wenn also mein Spiel am Ende auch mit seinen bescheidenen 15-20 fps auf einem 486er ohne Engpässe durchläuft MIT
synchronem Ton, dann ist das für mich sehr zufriedenstellend.
Kotzman II hat technisch sehr viel mehr Rückschläge, ich hätte mir noch gewünscht:
- Sprachausgabe (gescheitert an Unfähigkeit die Soundblasterkarte zu programmieren)
- Musik während der Levels (gescheitert daran, dass ich die Adlib-Kanäle für die Soundeffekte brauchte)
- transparente Sprites (ich konnte kein ASM, geschweige denn innerhalb BASIC)
- jedes Level braucht seine eigene .EXE (in Ermangelung von Heap)
- für die Animationen am Ende eines Levels musste ich mir eine Scriptsprache erfinden, weil die Basic-Befehle nicht
mehr ins Programm passten
Es ist alles sehr improvisiert. Angefangen hat das mit dem Level mit diesem komischen Ding, ich fand es später einfach
so dumm nur Schlüssel zu sammeln und durch ein Labyrinth zu hopsen, dass ich einen Save-State eingebracht habe um
es zu überspringen. Rausnehmen wollte ich es aber auch nicht, weil sonst die Story kaputt gewesen wäre bzw. subjektiv
nimmt man nicht gerne etwas weg woran man länger gesessen hat.
Jedenfalls habe ich unheimlich etwas nachzuholen, wenn ich noch einmal ein Spiel machen werde. Digitaler Sound ist
und war immer etwas das mich fasziniert hat, vielleicht auch weil er bis Anfang/Mitte der 90er so spärlich eingesetzt
wurde.

DOSferatu hat geschrieben:Ich muß aber auch dazu sagen, daß oft mit viel größerer Farbtiefe gearbeitet wird als überhaupt nötig.

Gebe ich Dir absolut recht, dass für Sprites 8 Bit indizierte Palette dick ausreicht, es sei denn die Sprites sind
fotorealistisch und bildschirmfüllend. Es gibt aber einen Bereich, wo man nie genug Farbtiefe haben kann:
Beispielsweise bei der Digitalisierung von Dias. Wenn man da "nur" 24 Bit hat, und ein stark unterbelichtetes Dia,
kann es passieren dass beim Aufhellen Artefakte auftreten, quasi Treppenstufen, weil sich die Helligkeitswerte nur noch
um ein paar Bit drehen. Das ist auch im Audio-Bereich so. Man arbeitet am besten bei der Bearbeitung mit 32 Bit
Floating Point, um es dann am Ende, quasi für den Verbraucher, auf 16 Bit herunterzurechnen, nachdem man es gut
ausgesteuert hat. Unsere Ohren sind offenbar weitaus dynamischer als die Augen: 8 Bit pro Farbkanal reichen
für "True Color", aber 8 Bit für Ton sind mehr schlecht als recht, zumindest aus HiFi-Sicht.

Ja, Max Headroom... Headroom ist auch ein Begriff aus der Audiotechnik, und bei 32 Bit Float hat man praktisch beliebig
viel davon. Das ist auch ein Grund warum man 32 Bit nimmt während der Bearbeitung.


PS: Wird mein Text eigentlich wirr umgebrochen weil ich den Zeilenumbruch selbst mache?
Soll ich das lieber demnächst sein lassen?
drzeissler
DOS-Gott
Beiträge: 3236
Registriert: Mo 8. Feb 2010, 16:59

Re: Eigenes Videoformat

Beitragvon drzeissler » Fr 30. Aug 2019, 13:07

CPU: 486 DX2/66 MOBO: SNI-D882 RAM: 3x16MB - FDD: 3,5" 1,44MB HDD: 6,4GB Seagate ISA(1): Audican32Plus PCI(1): 3com TX 905 OS: MsDos622 - Win95a - WinNT 3.51
DOSferatu
DOS-Übermensch
Beiträge: 1161
Registriert: Di 25. Sep 2007, 12:05
Kontaktdaten:

Re: Eigenes Videoformat

Beitragvon DOSferatu » So 15. Sep 2019, 15:57

zatzen hat geschrieben:
drzeissler hat geschrieben:Bei YT gibt es einen, der ein FullscreenVideo mit Ton (Beavis&Butthead) auf einem 286/8 oder 10Mhz in VGA laufen lässt. Sowas wäre mal echt interessant. Das wäre ein cooles Feature für ein A2286/8.

Das wäre wirklich mal interessant zu sehen. Ich konnte es leider auf Youtube nicht finden. Gibt so viele Videos... Und Zusätze wie 286 oder vintage helfen auch nicht.

Zum Glück hat drzeissler den Link noch dreingeschrieben.

zatzen hat geschrieben:Oder man macht Qualitäteinbußen und verwendet eine generalisierte Palette mit 256 festfarben, dann wäre auch Delta-Kodierung denkbar.

Naja - nun ist Beavis and Butt-Head ja klassischer Zeichentrick - was bedeutet: Framerate ist sowieso sehr niedrig und Farbanzahl könnte man hier herunterdampfen.

zatzen hat geschrieben:Für's erste backe ich kleine Brötchen. D.h. die Grafik wird am Ende vielleicht keine 100 KB füllen (zumindest während eines Levels), und mit Nutzung von ZVID2 fast nur die Hälfte davon. Zurückblickend auf Kotzman II war der Programmcode auch nicht so sonderlich groß, naja es ist 24 Jahre her und ich kann mich auch nicht mehr so exakt dran erinnern.

Kommt eben immer drauf an, was für ein Spiel man machen will - und auch WIE. Wie 8-Bit-Guy gezeigt hat, kann man auch ein Spiel für einen XT (4,77 Mhz) komplett in Assembler als monolithisches Teil zusammenbauen. Das "andere Ende" ist, einen generalisierten "Game-Maker" zu benutzen. Und alles, was dazwischenliegt, ist ebenfalls möglich.

Ich persönlich habe mich dazu entschieden, über längere Zeit wiederverwendbare Routinen zu bauen, um meine arg begrenzte Zeit und Energie nicht dazu benutzen zu müssen "immer wieder das Gleiche" zu programmieren (was ich in meinem Leben leider schon oft genug getan habe). Aber persönliche Entscheidungen meinerseits sind natürlich nicht das Maß irgendwelcher Dinge. Inzwischen zweifle ich auch daran, ob ich noch jemals dazu kommen werde, eine meiner Spielideen in ein fertiges Produkt zu gießen. Das mag aber auch daran liegen, daß in den letzten Wochen mein Elan mal wieder einen Tiefpunkt erreicht hat. Das kann sich auch wieder ändern - der Herbst kommt, die Temperaturen sind endlich nicht mehr unerträglich... so etwas kann schon helfen.

zatzen hat geschrieben:Und ich bin kein "Pro", habe keinen Wettbewerb zu gewinnen, daher kann ich einfach mal nach Lust und Laune loslegen und ein Spiel machen das vielleicht etwas sonderbar ist.
Wenn ich denn mal loslege. Ich habe in letzter Zeit mal wieder ein wenig gepixelt und merke dass ich das noch ganz gut kann, vielleicht sogar besser als früher.
Aber es kommt noch das Prokrastinieren dazu, und ich bin auch mehr abgelenkt als zu Kotzman II Zeiten, weil ich mehr Hobbys habe als damals.

Naja, bei mir liegt die Prokrastination eher daran, daß mir derzeit etwas die Freude fehlt. Ich möchte - nach all der Mühe, die ich mir mit den Puzzleteilen für meine Spielengine(s) gegeben habe - jetzt nicht irgendeinen uninspirierten Mist zusammenmurksen.

zatzen hat geschrieben:Einerseits hast Du Recht, und ich habe auch schon überlegt ob ich alles was nicht animiert ist, also soetwas wie Kachelelemente, als simple Bitmaps im Speicher halte und mit einfachen Kopierroutinen in den Puffer haue. Aber ich finde man muss erstmal sehen wie die Kompression performt.

Klar.

zatzen hat geschrieben:...STOSB...
Wie Du schreibst, der Nutzen ergibt sich erst ab einer bestimmten Datenmenge.

Naja, die ganzen MOVSx, LODSx, STOSx sind ja hauptsächlich dazu da, diese Kopierfunktionen zu benutzen (mit REP...). Bei allem, was sowieso "einzeln" passiert, muß man eben "Takte zählen", um zu sehen, ob sich's lohnt. Der kleine Nachteil für mich ist ja immer, daß das Zielregister nicht variabel ist (sondern standardmäßig ES sein muß) und es auch immer nur mit SI/DI funktioniert. Das ist nur dann gut, wenn man diese Register nicht andauernd auch woanders braucht.
Außerdem benutze ich z.B. gern BX, weil das im Gegensatz zu BP/SI/DI "teilbar" ist (in BL/BH) und man dadurch verschiedene andere schicke Tricks anwenden kann.

zatzen hat geschrieben:Ich werde auch erst einmal versuchen, alle Sprites mit derselben Routine darzustellen, nämlich ZVID2.
Diese enthält praktischerweise ein solides blockweises Clipping, man braucht sich letztlich gar nicht mehr drum kümmern wo das Sprite auf dem Bildschirm landet, egal ob links, rechts unten oder oben raus oder in einer Ecke, oder ob es überhaupt noch im sichtbaren Bereich ist, das kann die Routine alles sicher abfangen. Für mich ein kleines Novum. Ich muss nur ringsherum den Puffer 3 Pixel größer machen als das letztlich sichtbare Bild.

Dem entnehme ich, daß die Spriteroutine beim Entpacken 4x4-kachelweise abfragt, ob sich die nächste Kachel innerhalb des sichtbaren Bildausschnitts befindet?

Meine Spriteroutine berechnet vorher die Grenzen (d.h. ein - evtl gedrehtes - "Rechteck") und zeichnet dann nur diesen Bereich - mit entsprechenden "Abschnittkanten" an den Seiten, falls es sich am Rand befindet.

Wenn ich HEUTE eine Spriteroutine programmieren würde (meine sind von 2004), würde ich aber vieles wesentlich eleganter machen. Außerdem würde der geringfügige Pascal-Anteil aus den Routinen verschwinden. Aber ich zwinge mich, das seinzulassen, damit ich endlich mal irgendwann mit einem Spiel anfange.

zatzen hat geschrieben:An dieser Stelle wäre noch gut zu wissen um einen Sprung sparen zu können, wenn Du es gerade aus dem Ärmel schütteln kannst: Mit welchen Assembler-Befehlen kann ich eine Pascal-ASM-Prozedur verlassen?
Oder ist das unklar weil man letztlich nicht sagen kann ob RET oder RETF nötig ist?

Man kann IMMER sagen, ob RET oder RETF nötig ist, weil eine Routine nur ENTWEDER near ODER far compiliert wird, denn danach wird ja entschieden, welchen Return der Compiler selbst ans Ende setzt. Mit Compilerschaltern - oder den Begriffen near; oder far; (nach dem Header) kann man das auch festlegen. In Units wird meines Wissens immer FAR benutzt (kann mich irren) - weil ja die Routinen von überall aufrufbar sein müssen. Könnte aber auch sein, daß es eine Einstellung gibt, die, wenn der Code insgesamt <64kB wird, automatisch alles NEAR setzt.
"Einfachste" Möglichkeit, das im Zweifel rauszufinden: An das Ende der Routine vor das END; schreiben: asm db "Beispiel";end; (also irgendeinen String).
Dieses Programm dann NICHT ausführen! Sondern nur compilieren und dann die EXE mit einem Hex-Editor ansehen und nach dem "Beispiel" suchen und allem, was danach kommt.

ACHTUNG! Sollte die Routine ein sogenanntes "Stack-Frame" einrichten (was immer passiert, wenn man entweder Parameter im Header übergibt ODER Variablen in der Routine deklariert ODER beides) dann muß: 1. am Ende vor dem RET (bzw RETF) noch ein LEAVE stehen und außerdem muß man ein spezielles Return benutzen, nämlich das, bei dem man noch einen Wert danach angeben kann. (Der Wert ist die Anzahl Bytes, die alle Dinge, die man im Header übergeben hat, zusammen brauchen - wobei Byte-Variablen trotzdem 2 Bytes brauchen.)

Wenn man nicht genau weiß, was man tut, ist es hier wohl besser, das obengenannte (mit dem String) zu machen und dann das, was der Hex-Editor bis zum Return bzw Return+Rückgabebytes da hat, 1zu1 auch so zu machen.

Eine andere Möglichkeit ist, einfach ans Ende der Routine zu springen und den normalen Returnprozeß der Routine ausführen zu lassen.

zatzen hat geschrieben:Zeichnen/Löschen Methode, nur wenn sich etwas geändert hat: [...]

Naja, es kommt immer auf den "Trade-Off" an, was man da spart. Wenn die Routine, die das prüft und auswertet, am Ende komplizierter ist (und damit mehr Zeit braucht) als "stupides Kopieren", dann bringt die Mühe nichts. Aber Ausprobieren schadet ja nichts.

Da meine Spiele sowieso auf Scrolling ausgelegt sein werden, habe ich selbst dergleichen noch nie in Erwägung gezogen. Und da ich ja Mode-X (bzw auch Mode-Y) benutze, arbeite ich auch bei Grafik mit Mehrfach-Buffering (3fach/4fach), d.h. ich schreibe immer direkt in den Grafikspeicher, also ohne vorher im Heap-RAM zu puffern. Nachteil bei mir ist, daß ich dadurch einige Pixel mehrfach in die Grafikkarte schreibe (Hintergrund und darüberliegende Sprites), was bei RAM-Puffer nicht passieren würde (da schreibt man nur genauso viele Pixel in die Grafikkarte, wie die Größe des Bildes ist und kann zusätzlich auch mit 32bit-Transfer arbeiten). Dafür schreibe ich nicht in RAM und dann nochmal in die Grafikkarte (und brauche keinen RAM-Puffer). Was nun am Ende besser ist... - ich würde sagen: Kommt drauf an. Hängt auch etwas von der Hardware ab.

zatzen hat geschrieben:
DOSferatu hat geschrieben:Naja, mit 44100 Hz müssen aber doppelt so viele Daten pro Sekunde berechnet werden als mit 22050 Hz - das sollte doch klar sein, oder? Also auch doppelt so viele pro Frame.

Ja, das stimmt. Ich bezog das nur irgendwie auf den Speicherbedarf für die Sounddaten. Und da kann man ja auch einfach 8 kHz in 44.1 kHz reinmischen. Und ein 2 KB Puffer (ca. 44100 Hz bei 20 fps) tut speichermäßig ja auch keinem weh, aber klar, es geht Dir um Performance. Aber Mixrate ist bei mir ja verstellbar bis auf 11 kHz runter.

Naja, Performance hin oder her - mir geht es vor allem darum, daß "alles zusammen" noch funktionieren kann, ohne daß der Sound stottert oder Eingaben des Spielers "verlorengehen". Beides wäre beim Spielen echt ... doof.

Dazu nochmal die Frage: Wenn der IRQ signalisiert: Daten alle/abgespielt und zum neuen Puffer wechselt, WO generierst Du dann die Daten für den alten (nächsten) Puffer? Direkt in der IRQ-Routine oder setzt Du nur ein Flag und generierst in der Hauptschleife (außerhalb des Interrupts)?

zatzen hat geschrieben:Und ja, Du plädierst für größere Soundpuffer für bessere Performance, und Deine Bild-Ton-Verschiebungstoleranz liegt bei glaube ich 200 ms, also 1/5tel Sekunde. Ist für mich eben leider nicht akzepabel wenn ich z.B. eine Explosion zuerst nur sehe und dann erst der Ton verspätet kommt, so als wäre ich hundert Meter davon entfernt.

Bisher habe ich noch nie alles zusammen in Funktion erlebt, wie es am Ende wird, muß ich erstmal sehen.

Nur, wie ich schon mal bemerkt habe: Wenn man am "einen Ende" (Sound) immer genauer dreht, wird es am "anderen Ende" (Grafik) immer ungenauer und umgekehrt. Das ist wie die berühmte Unschärferelation (je genauer man mißt, wo man sich befindet, umso ungenauer kann man seine Geschwindigkeit messen - und umgekehrt).

Will sagen: Wenn man sehr kurze Soundpuffer hat, muß man sehr oft die Routine aufrufen, die den Puffer füllt, braucht also dafür Performance. Wenn man Performance braucht, hat man weniger Performance für den Refresh der Grafik übrig. Wenn die Grafik geringe Framerate hat, dann stellt sich die Frage: Wenn der Sound "synchron" zur Grafilk sein soll, die Grafik dann aber nur 5 FPS hat - zu WAS soll der Sound dann synchron sein? Da würde dann eine 200ms-Synchronität ausreichen, weil öfter ändert sich das Bild ja nicht. Andererseits, wenn man, für volle Framerate die Soundpuffer zu groß macht, so daß der Puffer vielleicht eine Viertelsekunde faßt, dann werden nur alle Viertelsekunde neue Soundeffekte in den Puffer einberechnet und der Knall (oder was auch immer) hat auf der Grafik schon stattgefunden und dann wird der Effekt erst eincodiert - und dann erst im NÄCHSTEN Soundframe ausgeführt (also dann im Worst Case erst eine HALBE Sekunde später als es grafisch zu sehen ist. - Wäre genau so blöd.

Also ist hier der Mittelweg wieder die beste Methode. Die "Besonderheit" des PC ist ja - zumindest bei Digitalsound - daß Sound nie sofort ausgegeben wird, wenn er erzeugt wird, sondern erst in einen Puffer gelegt wird und erst wenn dieser voll ist (und der andere Puffer abgespielt ist) der Sound gespielt wird.

Da stellt sich nun also für mich die Frage, ob/wann ich die Routine aufrufe, die Sound generiert. Bei mir ist es ja so, daß die Berechnung der Grafikanzeige z.B. nichts mit der Steuerung zu tun hat (wird beides nacheinander ausgeführt in der Hauptschleife). Der Plan sah auch vor, daß der Aufruf der Soundgenerator-Routine (ISM) auch in der Hauptschleife erfolgt - und zwar immer dann, wenn der Soundkarten-IRQ ein Flag gesetzt hat (für Puffer leer).

Aber vielleicht ist das die falsche Methode? Bisher habe ich noch nie Spiele mit Digital-Soundeffekten gemacht. Bei Musik wäre es ja egal, die muß in einem Spiel nicht framesynchron zur Grafik sein (und bei einem Film würde man den Zeitversatz einfach mit einplanen). Das ist ja das Problem: Bei einem Spiel kann man den Zeitversatz des Sounds (der durch das Doublebuffering entsteht) nicht voraussehen, weil man ja nicht vorher wissen/planen kann, was der Spieler macht. Da fragt man sich, wie das andere Leute machen.

Wieso ich nicht allzu kleine Puffer will, liegt nur daran, daß noch dazwischen genügend Zeit bleiben muß für den Rest (Grafik, Steuerung) und nicht der (kleine) Soundpuffer schon ZWEIMAL leer ist, bevor man EINMAL die Grafik gezeichnet hat und somit der Sound zu stottern anfinge.

Daher die Frage, ob Du den Soundgenerator im IRQ startest (d.h. zum Neugenerieren des Sounds die Grafik-/Steuerroutinen unterbrichst und das Generieren direkt im Interrupt machst).

zatzen hat geschrieben:Es ist einfach so, ich habe einiges mit Video und Ton gemacht. Wenn es dort einen Versatz gibt, selbst nur 50 ms, dann ist das schon ärgerlich. Und ich möchte mir für ein Spiel einfach diese Präzision ermöglichen.

Ja, wie gesagt, ist es nur (im Gegensatz zu einem Film) schwer, bei etwas Interaktivem (wie einem Spiel), "vorauszusagen", welcher Sound kommen muß, weil das ja davon anhängt, was der Spieler macht. Wenn der Spieler etwas drückt, was im Ergebnis einen bestimmten Sound auslösen würde, muß das ja erst die Steuerroutine durchlaufen, die dann den entsprechenden "hier Sound X abspielen" Befehl in einen Puffer schreibt, damit bei der nächsten Puffergenerierung dies berücksichtigt werden kann - und der Puffer, der diesen Sound enthält wird dann beim übernächsten Mal (nachdem der gerade aktuelle Puffer abgespielt ist), abgespielt.

Das würde zwar für kurze Puffer sprechen - die z.B. auch zur Not so kurz sind, daß sie im Zweifelsfall mehrmals die Grafik- oder Steuerroutine unterbrechen könnten... - ABER: Dabei muß man beachten, daß, während das System im Hauptprogramm die Grafik zeichnet, sowieso keine NEUEN Sounds dazukommen, weil die Grafikroutine keine neuen Sounds aufruft/triggert... Während das System also damit beschäftigt ist, die Grafik zu bauen (und deshalb derzeit keine Steuerung oder andere Dinge ausführt), kommen auch keine NEUEN Sounds dazu...

Alles Dinge, über die ich mir schon so meine Gedanken gemacht habe... Es muß am Ende eine in sich konsistente Hauptschleife entstehen, die nicht sinnloserweise Unterbrechungen für eine "Pseudo-Genauigkeit" erzeugt, die am Ende nur Performance kostet und nichts erreicht.

zatzen hat geschrieben:Ich habe mir letztens Prince Of Persia II angesehen, da ist der Ton punktgenau. Möglicherweise weil sie Adlib verwenden und den Digisound ohne Puffer realisieren, immer nur ein Sound gleichzeitig durch direkten "DMA Auftrag" im Hintergrund wenn man so will.

Genau deswegen. Und aus meiner Erinnerung heraus muß ich sagen, daß ich den Sound in PoP NICHT 100% synchron empfunden habe (die Schritte, das Trinken, die Schwertschläge)

zatzen hat geschrieben:Auch wenn ich beginne, ein variables Timing zu verstehen, werde ich erstmal, auch zugunsten des synchronen Sounds, das ganze mit dem Interrupt des Soundpuffers timen. Hab ich ja schon oft genug gesagt. Es verschwendet Performance-Potential, ich muss immer vom Worst-Case ausgehen, was auch dazu führen wird dass das Spiel insgesamt eher bescheiden ausfallen wird was die Rechenleistung angeht, auch oft gesagt: Ich denke an sowas wie Captain Comic, für das damals völlig ein 286er ausreichte, und ich würde davon ausgehen dass ein ähnlich geartetes Spiel mit etwas mehr Framerate und höher auflösendem Scrolling, und meinen extra Features wie ZSM und ZVID auf einem 486er zu realisieren wäre.

Schauen wir mal. Bei dem Zeug, das ich so da habe, bin ich mir nicht sicher, wie das am Ende insgesamt performen wird - hängt ja von sehr vielen Faktoren ab. Ich befürchte, daß der Riesenklotz von Routinen, die ich hier mitschleppe für Grafik, Sound, Steuerung und "das Leben, das Universum und den ganzen Rest"[tm] am Ende insgesamt die Performance killen wird und am Ende alles unspielbar werden wird. Wie ich ja bereits mal sagte: Nur weil irgend ein "Einzelteil" gut funktioniert (und performt), muß das nicht heißen, daß alle Teile zusammen das auch tun.

Du - als jemand aus der Sound-Ecke - scheinst bei der Spiele-Entwicklung/-planung ziemlich auf den Sound-Anteil fixiert zu sein. Will sagen: Wenn die Grafik klotzig oder ruckelig wird oder in einem verkleinerten Fenster dargestellt werden muß oder das Gameplay eventuell zu "simpel" zu werden könnte, das scheint für Dich alles kein Problem zu sein - solange der Sound dabei in hoher Qualität und Synchronität daherkommt. (Kann ich nicht mit Sicherheit sagen - wirkt aber subjektiv auf mich oft so.)

Ich bin mir nicht sicher, ob das ein geeigneter Ansatz ist, ein Spiel zu entwickeln - andererseits habe ich selbst noch kein wirklich gescheites Spiel gebaut und ich kenne auch keinen der "Großen", die sogar mal so gute Spiele gemacht haben, daß man sie verkaufen (statt nur verschenken) konnte - will sagen: Ich beurteile das auch nur aus meiner reinen Amateur-/Hobby-Schiene.

Wie ich schon öfters erwähnte: Wenn ein Spiel nur 10 FPS hat, dann braucht schon aus rein logischer Sicht die Soundgenauigkeit nicht höher als 100 ms sein und selbst bei knapp 200 ms würde man maximal 1 Grafikframe verpassen. (Soviel zur "Synchronität"...) Außerdem kann der Soundgenerator erst dann "wissen", welchen Effekt er reinmixen soll, wenn das Steuerung das aktiviert hat - und die Steuerung kann das erst wissen, wenn das Spiel weitergelaufen ist und dieser Weiterlauf ist ja kein vorberechneter "Film", sondern ein interaktives Spiel - und hängt ständig von der Eingabe des Spielers ab. Somit ist also jede Reaktion aufeinander immer verzögert.

ABER: Auch der Grafikgenerator (d.h. die Routine, die das Grafikframe erzeugt), hat ja das gleiche "Problem": Auch diese kann erst "wissen", was sie darstellen soll, wenn die Steuerung (die "Spielsituation") vorhanden ist und wird erst angezeigt, nachdem die letzte (vorhergehende) Grafik generiert wurde. Auch dann, wenn man kein eigentliches "Double-Buffering" bei der Grafik macht (wie ich, der dafür direkt in verschiedene "Seiten" des Grafikspeichers schreibt), ist das Generieren der Grafik in einem RAM-Puffer und anschließendes Kopieren in den Grafikspeicher ebenfalls eine Art von "Double-Buffering" mit ähnlicher Wirkweise - und in beiden Fällen dient es dazu, den Spieler nicht den "Zwischen-Aufbau" der Grafik sehen zu lassen, damit es wie eine Bewegung aussieht. Also: Verzögerung auch bei der Grafik.

Was ich damit sagen will, ist, daß sowohl der Sound, als auch die Grafik verzögert ausgegeben werden im Verhältnis zur Spielsituation. Und, wie Mr. Spock sagen würde: "Das ist nur logisch." - denn die Wirkung kann zeitlich nie VOR der Ursache liegen.

Also muß man aufpassen, daß man nicht das ganze Spiel "um die Grafik herum" oder "um den Sound herum" programmiert - denn, wenn man einem Aspekt zu viel Rechenzeit zuteilt, wird alles andere dadurch ausgebremst. (Und übrigens: Speziell die Spiel-STEUERUNG sollte NIE ausgebremst werden - so ein "hakeliges" Spiel würde keiner spielen wollen.)

zatzen hat geschrieben:Das mit den Steuerungsbits könnte ich aber übernehmen, wobei da vielleicht auch einfach Boolean Variablen gehen, die paar Byte kann man ja noch haben, hängt wohl auch davon ab wie es letztlich im Programm interpretiert wird, wenn man alles in ein Byte packt hat es vielleicht bei Assembler Vorteile.

Ja, wie gesagt, ICH hatte mich für Bitmuster entschieden - einfach, weil es mehr als 8, 16, 24 oder 32 (was schon mächtig übertrieben wäre) verschiedene "Tasten"/Steuerelemente wohl nicht in einem Spiel geben wird - und vor allem, weil man dadurch die Steuerbitmuster (z.B. Bytes oer Words) in einen Ringpuffer legen kann, so daß für jeden "Tick" ein Steuerbitmuster vorliegt und man damit eventuelle Unsynchronität ausgleichen kann. Grund: Während Grafik/Sound generiert werden, arbeiten ja die Steuerroutinen gerade nicht. Sollte eines davon zu lange dauern (und deshalb die Steuerroutine mehrmals aufgerufen werden müssen, um wieder zeitlich "hinterherzukommen", sollten auch genauso viele Bitmuster zur Verfügung stehen.

Natürlich könnte man auch OHNE Ringpuffer arbeiten und immer nur ein "allgemeines Bitmuster" irgendwo ablegen (oder eben Boolean-Array) - aber dann entspricht die Genauigkeit der Steuerung nur maximal der Framerate der Grafik und kurze Tastendrücke werden eventuell nicht mehr berücksichtigt. (Erklärung: Wenn Generieren von Sound und/oder Grafik mal etwas länger dauert und der Spieler in dieser Zeit eine Taste drückt UND losläßt, wird das "Tasten-Bit" zwischenzeitlich auf 1 und gleich wieder auf 0 gesetzt und für die Steuerroutine sähe es aus, als wäre gar nichts passiert.)

zatzen hat geschrieben:Danke jedenfalls für die ausführliche Darstellung, ich müsste mir solche Erklärungen mal irgendwo außerhalb des Forums archivieren, damit ich gezielter und ohne zu suchen darauf zugreifen kann.

Naja, ich bin auch kein Experte; und ich weiß auch nicht, wie es die wirklichen Experten machen. Ich gebe nur meine Erfahrungen wider, die ich selbst über die Jahre/Jahrzehnte gesammelt habe und Vorgehensweisen, die bei mir funktioniert haben. Und wenn es funktioniert, kann es ja nicht so falsch sein.

zatzen hat geschrieben:ZVID2: Das ist alles nur "because I can" ("...and want").
Richtig sinnvoll wäre es nur für ein Adventure wo es nicht auf Geschwindigkeit aber auf viel Speicher ankommt. Ich schätze die Kunst, Sprites zu skalieren und zu drehen, aber ich persönlich mag die optischen Resultate meistens nicht, eine gepixelte Grafik muss für mich ihre Konsistenz bewahren, eher würde ich für Drehungen ein paar Phasen pixeln. Das alles vielleicht auch, weil ich mit Spielen aufgewachsen bin, in denen nicht gedreht und skaliert wurde (bis auf manche Momente in Monkey Island z.B).

Ja, kennt man. Die "alten" Spiele (auf alten Konsolen usw.) hatten noch kein Drehen/Skalieren, weil es hardwaremäßig nicht möglich war (und softwaremäßig nicht performt hätte) und diese hatten sogar für 90° Drehungen vorgepixelte/vorgedrehte Sprites. (Wobei bei Drehungen um 90°/180°/270° ja nichts verlorengehen würde.) Ich muß aber sagen, daß ich bei Drehungen um 45° oder 22,5° (Viertel/Achtel) selbst auch nicht viel besser pixeln könnte, als es meine Drehroutinen automatisch machen. Was man bei skalierbaren/drehbaren Sprites generell vermeiden solllte, ist, Farbübergänge selbst zu dither-pixeln. Geditherte Flächen zu drehen sieht nicht gut aus, da entstehen üble Moiré-Effekte. Allerdings geben Sprites, die für Auflösungen von 320x200 und so zwischen 4 und 32 Farben sowieso nicht viel Möglichkeit des Ditherns her, ohne daß es (selbst ungedreht) schon nicht mehr gut aussieht.

zatzen hat geschrieben:Das "wilde" Skalieren, Stauchen und Drehen erfuhr ich erst bei Duke Nukem 3D, und dieses Spiel hatte für mich nicht mehr den Zauber einer homogenen Pixel-Landschaft, es war alles eher nur noch zweckmäßig und informativ, voller Aliasing und unförmig aufgeblasenen Pixeln.

Ja, das bringt die 3D-Geschichte so mit sich - es muß ja quasi ALLES skaliert/gezerrt werden, damit es optisch paßt. Allerdings ist es nun auch so, daß sehr naheliegende Objekte eben dadurch vergrößerte Pixel bekamen. Der Grund ist ganz einfach: Die Größe der Texturen war begrenzt - so ein DOS-Rechner hatte nicht gigabyte-weise Speicher. Wenn man alles bei 50 cm Abstand zum Spieler immer noch "vollgepixelt" (ohne Vergrößerung) hätte haben wollen, hätte man riesige Texturen gebraucht.

Heutzutage wird dem durch Anti-Aliasing und Bump-Mapping entgegengewirkt UND größere Texturen - allerdings erfordert das WESENTLICH mehr Rechenleistung als so ein 486er aufbringen kann und diese Rechenleistung wird selbst auf "modernen" Rechnern nicht von der CPU erbracht, sondern von der GPU in der Grafikkarte.

Nur: Einerseits höchste grafische Qualität wollen - ohne eventuelle "Artefakte" vom Drehen oder Skalieren - andererseits aber zufrieden sein mit ruckeligen 8-10 FPS, evtl. verkleinertem Bildausschnitt und 16-Farb-Grafik... das paßt alles irgendwie nicht zusammen. Einerseits wenig Grafikspeicher wollen und alles zusammenpacken, damit viel Platz für Samples bleibt, andererseits auch gedrehte Phasen einzeln pixeln, was wieder mehr Platz braucht... - Es geht eben nicht alles gleichzeitig.

Ich habe mich längst damit abgefunden, daß ich mit den technischen Mitteln, meinen Fähigkeiten und meiner Zeit niemals das "Spiel des Jahrhunderts" erschaffen können werde - da bin ich froh, mir ein paar Mittel geschaffen zu haben, die einen Teil der Dinge "automatisieren".

zatzen hat geschrieben:Dreh- und skalierbar kann ein Segen sein, wenn man nicht so ein hohes Bedürfnis an die "Integrität" der Pixel hat. Es ist auch eine Stilfrage - spätestens bei Echtzeit-Vektorgrafik wie bei "Alone In The Dark" braucht man nicht mehr über Aliasing oder soetwas meckern.

Meine Routinen haben übrigens eine Option, automatisch zu dithern (NACH dem Drehen/Skalieren!). Weiß nicht, ob Du schon gesehen hast, wie das aussieht, aber vielleicht würde Dir das sogar gefallen. Und das Dither ist nicht nur so 2-stufig (also nur "Schachbrett"), sondern ineinander übergehendes 16-stufiges Dither, d.h. erst ab einer Vergrößerung um über 16-fach gibt es gleiche "Ditherfläche", die man also erst ab mindestens 32-facher Vergrößerung auch optisch wahrnimmt (und so sehr vergrößert man bei 320er Auflösung ohnehin nicht).

D.h. auf Wunsch sieht die Drehung/Skalierung bei mir NICHT aus wie "quadratische Pixelflächen", sondern wie geditherte Übergänge.

zatzen hat geschrieben:Und auch verschiedene Paletten können höchst praktisch sein, das hat auch das gute alte NES ja so gemacht bei einigen Spielen. Mich haben zu der Zeit als ich begann zu programmieren aber vor allem Adventures geprägt, wo jede Figur ganz konkret und individuell war. Daher gehe ich so auch an eigene Spiele heran, jeder Figur, jeder Gegner, hat seine
individuellen Sprites - ich hatte also nie den Wunsch etwas anders einzufärben oder auch s.o. zu skalieren oder zu drehen, daher habe ich mich bislang einfach nur damit beschäftigt, etwas komprimiert zu speichern, damit ich möglichst viel Grafik bewerkstelligen kann.

Ja, die "möglichst viel Grafik" muß auch erstmal jemand pixeln. Und, daß z.B. bei Super Mario die verschiedenfarbigen "Schildkröten" oder "Pilze" alle offenbar das gleiche Spritemuster, nur mit unterschiedlicher Palette haben, finde ich jetzt nicht so störend.

OK - klar könnte man auch jede Figur einzeln pixeln, selbst welche der gleichen "Art", damit die sogar unterschiedliche Gesichter haben... Wäre nett - nur verliert man sich da in Kleinigkeiten, die dem Spieler kaum auffallen werden oder kaum das Erlebnis erhöhen werden, nur weil's keine 2 Figuren gibt, die gleich aussiehen. Wenn man auf 320er Auflösung arbeitet, ergeben sich ohnehin nicht unheimlich viele Möglichkeiten, einer Figur z.B. noch ausreichend "Gesicht" und "Mimik" zu verpassen. - Ist eben meine Meinung dazu.

Ich bin kein Superexperte und kann daher keine Schachcomputer-mäßige KI zustandebringen - daher muß ein Spiel, um herausfordernd zu sein, auch mal mit einer größeren Anzahl Gegner aufwarten können. Aber die pixle ich dann sicher NICHT alle einzeln. Es geht ja auch nicht NUR darum, ob Grafikspeicher gespart wird oder nicht, sondern auch darum, ein Spiel mal in endlicher Zeit fertigzubekommen. Das bedeutet nicht, ob man zu faul wäre, so viel zu pixeln - sondern eher, ob es die Mühe auch wert wäre; aber das muß natürlich auch jeder selbst wissen.

zatzen hat geschrieben:Ausreichen würde für meine Zwecke in gewissem Rahmen wohl auch einfach eine RLE Kompression, aber ich bin eben etwas verspielt. Ich glaube, Datenformate oder Kompressionen zu erfinden fasziniert mich alleine schon genug, siehe ZSM... Ich hätte ja auch einfach einen abgespeckten MOD-Player schreiben können, aber das wäre mir zu viel sinnlos
das Rad neu erfinden gewesen.

Naja, ich habe ja, wie erwähnt, auch schon eine Menge Formate entwickelt - bei mir ergab sich das aber immer eher "aus der Notwendigkeit heraus", nicht nur, "weil ich gern ein Format entwickeln wollte". Bei mir war es auch immer so, daß ich nicht etwas (Format/Protokoll)
entwickelt habe, nur um irgend etwas "um das Format herum" zu bauen, damit das Format "seine Daseinsberechtigung hat", sondern eher immer umgekehrt: Daß ich etwas machen wollte und daher überlegt habe, was ich brauche.

Bei Xpyderz wurde irgendwann der "Sprite-Speicher" knapp und gleichzeitig ergab sich, daß sowieso alle "Elemente" (Hintergrundkacheln, Sprites) kaum mehr als knapp 16 Farben haben - also entstand die Idee, statt verschwenderischem 8bit einfach auf 4bit mit Paletten zu wechseln UND Figuren mit gleichem Image, die nur unterschiedliche Farben haben (z.B. Spinnen) zusammenzufassen - et voilà: über 50% Speicherersparnis ohne Einschränkungen an der bisherigen Grafik und trotzdem wahlfreier Pixelzugriff, Drehbarkeit, Skalierbarkeit beibehalten. D.h. die neuen Routinen wurden entwickelt, um ein bestehendes Problem zu lösen.

GameSys2 ist aus einem ähnlichen Grund entstanden: Irgendwann ist mir aufgefallen, daß ich für Steuerung der Figuren immer wieder gleichen/ähnlichen Code benutze und den Speicher damit vollknalle, ebenfalls die ganze Geschichte mit den Kollisionsabfragen usw., obwohl sich die Bewegungen hauptsächlich nur von Geschwindigkeit, Anzahl Hitpoints usw. unterscheiden. Gleichzeitig hatte ich für die Figuren große homogene Arrays angelegt, obwohl manche Figurentypen gar nicht alle Werte brauchten (also sinnlose Nullen im Speicher) und andere Figurentypen versucht haben, mit den paar Werten auszukommen und am liebsten noch mehr gehabt hätten (was bei den Figuren mit wenigen Werten zu noch mehr "sinnlosen Nullen" geführt hätte).

Weil nun aber die Steuerung und Kollisionsabfrage von 2D-Figuren ja nun eigentlich kein Hexenwerk ist, würde auch ein Art "VM" das erledigen können, die die eigentliche Arbeit in schnellen Assembler-Routinen erledigt und über generalisierte Befehle steuerbar ist. Meine Befürchtung, daß diese indirektere Weise Performance kosten würde, hat sich bisher nicht bestätigt - und zusätzlich erhält nun jeder Figurentyp seinen "Variablenstack", der nur so groß sein muß, wie wirklich benötigt. So können viele kleine Figuren oder "Effekt-Sprites", die einfache Bewegungsmuster haben, ermöglicht werden, die nicht mehr können müssen - und nicht mehr Speicher brauchen - als es nötig ist.

Und auch ISM wurde ja (bekanntlich) nicht deshalb von mir entwickelt, damit ich "irgend etwas habe, um damit Musik zu machen", sondern einzig aus der Vorlage heraus, daß meine Spiele bisher keine Musiken/Klangeffekte hatten und ich diesem Manko Abhilfe schaffen wollte, ohne (wie bisher) für jedes neue Spiel irgendeine Lösung zusammenzukrüppeln.

Das Gleiche ist mit der Abfrage der Steuertasten/Joystick usw. passiert: Irgendwann merkt man, daß es gar nicht so viele Möglichkeiten gibt, das abzufragen und daß man trotzdem für jedes neue Spiel Zeit verschwendet, den Kram einzeln einzubauen.

Und das "SLOT" ist im Prinzip nur dazu da: Es gibt ja gar nicht so viele Möglichkeiten, die ganzen möglichen Subroutinen gemeinsam so zu benutzen, daß alle zusammen als Verbund funktionieren. Also wäre es ja die beste Idee, das Ganze gleich einmal richtig zu machen, zu testen bis es funktioniert und dann zu benutzen, als für jedes neue Projekt herumzuprobieren, wie es am besten gehen könnte. Und da sowieso Spiele in der Art der Konsolenspiele der späten 80er und frühen 90er angedacht waren, wäre es also ganz gut, wenn da alles, was so ein Konsolenspiel braucht und was so Konsolen in Hardware haben (der PC aber nicht), irgendwie "gleich da wäre". Die Konsolen allein haben ja meist gar nichts gemacht - erst, wenn man das Spiel eingelegt/eingesteckt hat in den Modulsteckplatz (Slot) - und genau so ist es mit meinem "Spiel-Rahmen", der nur die theoretische Funktionalität vorgibt, aber ohne Spieldaten kein Spiel ist - und deshalb heißt er auch SLOT.

Also ist in meinem Fall alles so passiert, weil ich schon Spiele gemacht habe, gesehen, was die Schwierigkeiten/Probleme waren und wie es besser lösbar (oder überhaupt lösbar) wäre. Ich habe eher selten (könnte mich jetzt an keinen Fall erinnern, wo es so war) ein Programm oder ein Format "um seiner selbst Willen" entwickelt, um dann "nach irgend etwas zu suchen, wo ich es einbauen/benutzen kann", sondern es war eigentlich immer umgekehrt.

Ich hätte bei dem ganzen Aufwand, den ich inzwischen für den ganzen Kram betrieben habe, schon längst meine Spielideen in direktem Code umgesetzt haben können: Das "Mehrfigur-Jump'n'run", das Raumgleiter-Shoot'em'up, ein Rennspiel... - aber ich habe mich letztendlich dagegen entschieden; ...

... und zwar einzig aus meinen Erfahrungen von Xpyderz heraus: Ich würde ja dann wieder nur 20% Zeug haben, das ich einbauen könnte und den ganzen "Rest" wieder dazucoden - wahrscheinlich "erstmal" in Pascal; und dann würde es auch Pascal bleiben, weil es zu viel Gemurks und "Drumherum-Gecode" wäre, um etwas Gescheites in Assembler daraus zu machen... Und am Ende hätte ich 3-5 Jahre (wie bei Xpyderz) herumgemurkst (obwohl ich da netto nicht mal EIN Jahr gebraucht habe), um einzelne Details "geradezubiegen", in endlosen Test-/Debug-Sessions... Und die ganze schöne Spielidee wäre am Ende nur in einem genauso unfertigen Ding verbraten, wie es bei Xpyderz der Fall ist.

Leider hatte ich unterschätzt, was es mit sich bringt, wenn mal älter wird und den ganzen Tag einen Job zu bewältigen hat: Ich komme kaum noch zum Programmieren. Selbst dann, wenn ich mal Zeit hätte, bin ich oft müde oder einfallslos und uninspiriert - und bei mir liegt es NICHT mal daran, daß ich "so viele andere Hobbys" hätte, denn das ist nicht der Fall. Tja, da sollte man wohl nicht ZU gespannt auf mein nächstes Spiel warten...

Momentan ist eigentlich ALLES fertig, was ich für ein Spiel brauche, ja, dieses Mal wirklich ALLES. Ich muß jetzt nur noch eine möglichst elegante, zeit-und-platz-sparende Methode finden, die ganzen "losen Enden" in SLOT zu einer zusammenhängenden Maschine zusammenzubauen, bei der erstmal KEINE blöden "Workarounds" mehr nötig sind, damit sie läuft.

Es ist so wie oft: Einen laufenden Prozeß kriege ich leichter hin, als die "Vorarbeit, ihn anlaufen zu lassen" - will sagen: Ein gescheites Datenformat für ein "Level" habe ich zwar - aber so richtig gefällt mir das noch nicht - das ist schon wieder viel zu kompliziert gedacht... habe gerade so eine Idee gehabt für ein Level, das aus "internen" und "externen" Daten bestehen kann: eine negative "Position" würde dazu dienen, stattdessen externe Daten zu laden... (Externe Daten = Daten, die von mehreren Levels gleichzeitig benutzt werden können und daher nicht einzeln in jedem Levelfile vorliegen müssen - inklusive Erkennung, ob sie schon geladen sind. Mal sehen...)

zatzen hat geschrieben:Dein Image-Einpass-Programm nimmt in etwa die Stelle ein, die bei mir der ZVID2 Encoder hat. Natürlich eher schlecht vergleichbar, aber vom Aufwand her könnte es in etwa hinkommen.

Naja, das Ding ist ja nur dazu da, damit man das nicht von Hand machen muß. Da werd ich wohl noch mal was Neues bauen, weil das noch einige Dinge hat, die unpraktisch sind. Der Aufwand des "Zusammenbauens" des Spiels soll "so automatisch wie möglich" sein - damit z.B. das Testen des Spiels nicht jedes Mal in ewiges manuelles Gebastel ausartet.

zatzen hat geschrieben:
DOSferatu hat geschrieben:Und - so traurig das jetzt vielleicht klingt - auch Du wirst wohl Byte für Byte arbeiten müssen.

Ja, das war schlecht nachgedacht. Selbst wenn ich das bei nicht-Transparenz vielleicht so machen könnte - es bringt nichts, erst ein 32 Bit Register mit Bytes vollzuschieben um es dann mit einem Rutsch in den Speicher zu knallen.
Das ganze trifft nur für den Fall zu, wenn ein ganzer Block einfarbig und nicht transparent ist.
Dann werde ich das so machen.

Naja, ich will das Ganze nicht schlechtreden und JA - 32bit-Kopieren in den Speicher kann (wenn schlau gemacht) einige Zeitersparnis bringen, ABER:
Selbst dann (bei einfarbigem Block) ist es wahrscheinlich unnötig. Weil:
1. Wie oft kommt das vor?
2. Die Routine, die prüft, ob ein gleichfarbiger Block vorliegt, braucht wahrscheinlich mehr Platz UND Zeit, als es die Sache wert ist.
Oder meinst Du, daß ein ganzer 4x4-Block einfarbig ist? Naja... Einerseits alles handpixeln wollen und bei Skalierungen die klotzigen Flächen monieren (bzw. bei Drehungen die Pixelgenauigkeit) und andererseits große einfarbige Flächen in Sprites wollen... das widerspricht sich ja schon irgendwie.

Ich sag's mal so (persönliche Erfahrung) : Wenn man Sprites für 320er Auflösung macht, kommen so "Flächen" - selbst in 4x4 Größe - in Sprites nur äußerst selten vor und selbst WENN, dann fangen sie vielleicht gerade zufällig NICHT an einer glatten 4er-Position im Sprite an. Meiner bescheidenen Meinung nach sollte man, damit Sprites in so geringer Auflösung noch einigermaßen "schön aussehen", klobige "Umrandungen" oder "Flächen" weitestgehend vermeiden.

zatzen hat geschrieben:
DOSferatu hat geschrieben:Ich habe schon öfter mal bereut, manches von meinem alten Zeug "zu dicht komprimiert" zu haben, so daß kein Platz für Erweiterungen mehr da war und habe mich andererseits jedes Mal gefreut, wenn ein altes Format noch Dinge "offen gelassen" hatte, so daß ich es noch weiter verwenden und erweitern konnte.

Mehr oder weniger könnte ich ZSM bereuen, es wäre schwer das Format abwärtskompatibel zu erweitern - denke ich mal. Aber ich habe auch nicht so viele "Fans" dass das für mich wichtig wäre. Wenn ich für ein Spiel mehr Funktionen bräuchte, würde ich eine neue Version machen, die dann eben mit dem bisherigen Player nicht mehr kompatibel wäre.

Ach naja - dabei geht's mir auch nicht um "Fans" oder so - es gibt derzeit außer mir selbst keine weiteren Leute, die mein Zeug in ihren eigenen Projekten verwenden. Mir geht es dabei mehr um mich selbst: Ich will nicht andauernd auch noch Konverter für meinen Kram schreiben müssen, weil mein Zeug nicht mal zu sich selbst kompatibel ist - ich bin auch mal froh, wenn ich etwas, das ich gemacht habe, auch noch mal weiterverwenden kann.

Das liegt bei mir alles daran, daß ich merke, wie viel Zeit ich damit verbracht habe, immer wieder irgendwelches Zeug zu bauen und wenn ich dann ein Projekt gemacht habe, hatte ich 15 Jahre lang programmiertes Zeug herumliegen, in das viel Mühe gesteckt wurde - und das ich dann NICHT benutzen konnte/wollte, sondern extra für das Projekt dann doch wieder eigenen Code geschrieben habe. Da kommt man sich dann irgendwann schon selber doof vor.

zatzen hat geschrieben:
DOSferatu hat geschrieben:Wenn ich heutzutage ein Format benutze, will ich NICHT mehr (wie leider früher manchmal!) alles "um das Format", bzw. "um diese Routine herum" bauen müssen. Da finde ich es inzwischen besser, Zeug so zu machen, daß man es "nur noch einzubauen" braucht und es quasi alles, was es braucht, selbst macht, bzw. "von selbst mitbringt".

Auch deswegen jetzt ZVID2, was neben ein paar Variablen nur aus einer Prozedur bestehen wird. Mal abgesehen von Initialisierungs-Routinen, die aber auch nur Sachen machen die man auch "zu Fuß" machen könnte. ZVID(1) war eine ultra-komplizierte Orgie aus Prozeduren und haufenweise Pointern.

Tja, wie erwähnt, hatte ich damals auch schon öfter so "Riesenpuzzles" gebaut: Riesige komplizierte Apparate von Subroutinen/Units, in die viel Mühe geflossen ist, die trotz Komplexität funktioniert haben und auf die man (leider zu Unrecht!) stolz war (wegen der ganzen Mühe). Aber, "am Ende des Tages" hat man dann irgendein Teil, was kompliziert, groß und langsam ist, ein ganzes Segment belegt und vielleicht zusätzlich noch riesige Tabellen braucht usw... und das, wo man es einbauen will. braucht kaum eine der "Fähigkeiten" dieser "Superwaffe"...

Inzwischen (wie Du so schön sagst), backe ich eher bei so Routinen "kleinere Brötchen", weil "komplex" mir manchmal schon selbst "ZU komplex" wird und der Nutzen am Ende minimal. Vor allem (kann bei DIr anders sein), war es bei mir IMMER so: Komplexe Subroutinen waren immer schlecht irgendwo einzubauen - sie brauchten vom Hauptprogramm immer auch umfangreiches Init und Datenvorbereitung... Das war dann wie so eine Krake, die das ganze restliche Programm mit seinen "zu befriedigenden Befindlichkeiten" beherrscht.

Inzwischen versuche ich, wie schon in einem meiner letzten Beiträge geschrieben, alles möglichst so zu bauen, daß man es nur noch "einhängen muß" und es funktioniert von alleine - OHNE, daß das Hauptprogramm so ein Ding die ganze Zeit "babysitten" muß, damit es funktioniert.

zatzen hat geschrieben:
DOSferatu hat geschrieben:Naja, daß für "flächige Dinge" (wie Sprites, Rechtecke/Polygone) der fortwährende Zugriff auf eine generalisierte Pixelroutine (die jedes Mal aus Koordinaten die Pixelposition ausrechnet und für den Grafikmode entsprechend die Daten setzt für den Pixel) eine Scheißidee (weil langsam) war, habe ich schon recht schnell herausgefunden.

Ich meine nicht Punkt für Punkt, was in QuickBASIC mit PSET(x, y, color) gemacht wurde. Sondern das Grafik-PUT, man muss auf ein Integer-Array mit einer Bitmap (für VGA 1 Byte pro Pixel) verweisen und dann die Koordinaten der oberen linken Ecke. Was PUT macht dürfte etwa das gleiche sein wie rep stosb und das eben für mehrere Zeilen, d.h. es ist eigentlich sehr schnell.

Achso. Kannte ich gar nicht. Liegt wohl daran, daß ich auf PC nie BASIC programmiert habe (außer mal dieses eine kleine Dings in VB6 unter Windows, zusammen mit einem Kumpel). Aber unter DOS habe ich auf PC gleich mit (Borland) Turbo-Pascal angefangen. Die "Grafikfähigkeiten" von dem, was Borland da mitgeliefert hat, sind aber eher ein Witz. Naja, mag auch daran liegen, wie alt die letzte Version von BP ist. Jedenfalls hatte ich da sehr schnell erkannt: Das ist nix für mich - da muß ich etwas eigenes bauen.

zatzen hat geschrieben:Aber wenn man das auf einem 286er macht, mit einem 32x32 Sprite und es mit nur 1 Pixel jeweiligen Versatz animiert, dann dauert es schon ein paar Sekunden bis das Ding über den Bildschirm gewandert ist. Oder es war doch ziemlich schnell und ich habe es mit Sound 0, .1 ausgebremst. Ist fast 30 Jahre her...

Naja, die "der Spriterahmen löscht das Sprite" Methode habe ich noch nie irgendwo angewendet, deshalb kann ich dazu nichts sagen. Und die Methode, daß das Sprite den Hintergrund löscht und wiederherstellt, habe ich bisher ausschließlich für meine Mauspfeile benutzt. - Bei EINEM Sprite scheint mir das noch vertretbar.

zatzen hat geschrieben:
DOSferatu hat geschrieben:Um zu merken, daß es wirklich funktioniert, reicht es nicht, zu sehen, ob die Steuerung alleine oder die Grafik alleine oder der Sound alleine funktionieren. Erst, wenn ALLES ZUSAMMEN arbeitet und immer noch funktioniert, DANN wird's ein brauchbares Spiel.

Ich bin relativ optimistisch. Ich habe ja doch ein paar Spiele und Demos programmiert, wenn auch nicht immer die tollsten. Der Pentium 200 MMX den ich seit 1997 habe hat natürlich alles gefressen. Das verzerrt die Erwartung an einen 486er ein wenig.

Naja, ich sehe ja, wie wenig schon mein Xpyderz performt (hattest Du ja auch selbst getestet). Und Xpyderz hat noch direktgecodete Steuerung (kein GameSys2) und auch keinerlei Sounds. Da möchte man gar nicht wissen, wie schlimm das jetzt mit allem zusammen (in SLOT) wird - mein Optimismus hält sich da derzeit noch in Grenzen.

Ich muß dazu aber sagen: "Wird schon reichen" war noch nie so mein Credo. Ich denke IMMER: Wenn ich noch ein bißchen mehr spare (Speicher/Rechenzeit), dann bleibt für den Zweifelsfall noch "Luft nach oben". Alles so "gerade so auf Kante" bauen, das wäre mir "zu gefährlich". Und ein Pentium 200 MMX ist nicht gerade mein Zielsystem.

zatzen hat geschrieben:
DOSferatu hat geschrieben:[...]Also quasi soll dieser ganze Kram schon so "getestet und für gut befunden" sein, daß man ein Spiel drauf entwickeln kann OHNE jedes Mal komplett neue Routinen bauen zu müssen, die eigentlich das gleiche machen wie die des letzten Spiels.

Ja, da stimme ich Dir absolut zu. Wenn man sich manches klassische NES Spiel ansieht, scheint es auch so, als hätten die immer wieder die gleiche Engine genommen. Das meine ich absolut nicht negativ, sondern es ist professionell wenn man sich einen Standard schafft für den man Spiele designen kann. Fast so, als würde man sich dadurch Hardware erschaffen.

Ja, das ist die Idee dahinter.

zatzen hat geschrieben:Ich wollte ja auch vor ein paar Jahren schon so ein Game-System schaffen, was ich dann während einer Spieleentwicklung erweitern wollte. Ich habe da aber nicht so klare Vorstellungen wie Du, und bin ersteinmal froh dass ich einen Sound-Standard habe, und mal sehen wie ZVID2 wird. Letzteres nimmt mir auch die Sorgen ab, wie ich Grafik in das Spiel bekomme und dabei noch bestmöglich Speicher spare - ich muss sie nur auf den Heap laden und die Routine
mit entsprechenden Parametern aufrufen.

Ja, wie erwähnt: Selbst das will ich ja schon "automatisieren": Die Steuerung übernimmt GameSys2, die Anzeige passiert in einer Schleife, an der ich für das jeweilige Spiel nichts ändere. Was, ob, wo und wie angezeigt werden soll, wird vom VM-Code in GameSys2 definiert, das hat meine Hauptroutine nicht zu interessieren. Die soll nur das Anzeigen, was in den Daten steht. Früher[tm] habe ich viel weniger "modular" programmiert - nur dann ist man eben dazu verdammt, für jedes Spiel eine eierlegende Wollmilchsau zu bauen, die alles (Anzeige, Steuerung, Kollision, Eingabe/Abfrage, usw...) gleichzeitig macht - und irgendwann wird man es leid, immer wieder das gleiche zu coden, wenn es schonmal funktioniert hat.

zatzen hat geschrieben:
DOSferatu hat geschrieben:Meiner Erfahrung nach scheinen sehr viele (spätere) Coder, vor allem im 3D-Bereich, das so wie ich zu machen: Die FPS-Raten der Spiele sind variabel und hängen davon ab, wie aufwendig gerade berechnet werden muß.

Ich hab ja ne Zeit lang mit ein paar Jungs 3D Spiele gezockt. Ich habe einen Spruch im Kopf: "Framerate is God".
Kennt man vielleicht nicht, hab ich aber irgendwie mal gehört. Bei 3D Ego Shootern sind Framerates von unter 70 schon nicht mehr tolerabel, und als die ersten LCDs gängig wurden, wurde trotzdem noch an Röhren gespielt, weil die schneller sind. Und wir haben in 320x200 gespielt, mit Pentiums...

Ja, verwöhnte KIDS haben diese Einstellung.
Für Singleplayer geht auch weniger. Bei Multiplayer ist natürlich eine geringe Framerate gefährlich - und zwar weniger, weil es "nicht so schön/flüssig aussieht", sondern eher, weil einem bei SEHR ruckeliger Framerate bestimmte Dinge entgehen könnten und man also nicht so schnell/genau auf die Gegner reagieren könnte.

Für MICH zählt alles bis 10 FPS noch immer als "gut spielbar", selbst dann, wenn es gelegentlich zwischendurch auch mal auf 5 FPS einbricht. Aber ich bin ja auch kein verwöhntes Kiddie.


zatzen hat geschrieben:Ich stimme Dir absolut zu, dass das objektiv gesehen besser ist mit variabler Framerate. Für mich ist es nur großes Neuland zusätzlich dazu dass ich ein Spiel zu bewerkstelligen hätte, und der Trade-Off wäre die Ton-Asynchronität.
Wenn also mein Spiel am Ende auch mit seinen bescheidenen 15-20 fps auf einem 486er ohne Engpässe durchläuft MIT synchronem Ton, dann ist das für mich sehr zufriedenstellend.

Naja, wie gesagt: Zur Synchronität habe ich mich ja schon oben ausführlich geäußert. Ich werde mal sehen, wie weit ich mit "meiner Methode" kommen werde und ob mein Zeug dann "zu unsynchron" wird, um noch glaubwürdig spielbar zu sein. Kann ich jetzt leider noch nicht sagen, da noch nicht zusammenhängend getestet. Ich werde aber wohl den "Tonversatz" (also die Puffergröße), genau wie die Ton-Samplerate einstellbar machen, damit auch auf langsamen Rechnern noch gespielt werden kann.

Bei der Grafik wäre alles, was ich einstellbar machen könnte, die Bildauflösung - nur... naja, 320er Auflösung IST ja nun schon nicht gerade "fein" - ob man da dann noch auf 160 gehen sollte (wie bei Xpyderz)? Mal sehen. Genau wie bei Sound, wo es Untergrenzen gibt, die sogar ICH unerträglich finden würde, gibt es das auch bei Grafik. Und verkleinerter Bildausschnitt macht nur bei 3D-Spielen Sinn, wo sowieso alles skaliert wird. Bei 2D weiß ich nicht, ob ich da wirklich in so einem 160x100 oder 80x50 Fenster oder so noch Lust hätte, das zu spielen.

zatzen hat geschrieben:Kotzman II hat technisch sehr viel mehr Rückschläge, ich hätte mir noch gewünscht:
- Sprachausgabe (gescheitert an Unfähigkeit die Soundblasterkarte zu programmieren)

Inwiefern? Für die Zwischensequenzen oder auch im Spielverlauf?

zatzen hat geschrieben:- für die Animationen am Ende eines Levels musste ich mir eine Scriptsprache erfinden, weil die Basic-Befehle nicht mehr ins Programm passten

Das würde ich sowieso so machen, EGAL ob es reinpaßt oder nicht. Animationen als Programm (EXE) "hardcoden" halte ich - zumindest auf PC - für Mega-Schwachsinn.

zatzen hat geschrieben:Digitaler Sound ist und war immer etwas das mich fasziniert hat, vielleicht auch weil er bis Anfang/Mitte der 90er so spärlich eingesetzt wurde.

Ja, ich weiß.
Allerdings fand ich Spiele immer eher öde, die nur "wegen der Effekte" (z.B. Digisound/Sprachausgabe oder Grafik als vorgerenderte Filme) so viel Speicher/Platz brauchten, daß für einen eigentlichen Spielinhalt kein Platz mehr da war. Das waren für mich "Blender", die wegen der Effekthascherei dann leider kaum noch spielbaren Inhalt hatten - das kann man kurz angucken/anhören und bewundern - aber für ein längerfristiges Spielerlebnis hat das kaum je etwas getaugt.

Anfang der 90er kam viel so vorgerenderter Kram raus... Aber nichts davon hat mich irgendwie vom Hocker gerissen, weil der spielerische Aspekt dabei leider immer vernachlässigt wurde. Und das Gleiche wäre es für mich, wenn ein Spiel tolle Soundausgabe (und Sprachausgabe) hätte, aber wegen des ganzen Aufwands und Platz der ganze Rest nur irgendeine uninspirierte Grütze wäre, die nur "um den Sound herum" gebaut wäre.

Wenn ein Spiel nur 4-farbig ist und ein wenig Speaker-Gepiepe hätte, dafür aber eine tolle Spielidee und interessante Umsetzung, würde ich das länger/lieber spielen als eben o.g. "Blender".

zatzen hat geschrieben:
DOSferatu hat geschrieben:Ich muß aber auch dazu sagen, daß oft mit viel größerer Farbtiefe gearbeitet wird als überhaupt nötig.

Gebe ich Dir absolut recht, dass für Sprites 8 Bit indizierte Palette dick ausreicht, es sei denn die Sprites sind fotorealistisch und bildschirmfüllend.

Naja, Sprite-Spiele einerseits und Fotorealismus andererseits sind für mich zwei Dinge, die nichts miteinander zu tun haben.

zatzen hat geschrieben:Es gibt aber einen Bereich, wo man nie genug Farbtiefe haben kann: Beispielsweise bei der Digitalisierung von Dias. Wenn man da "nur" 24 Bit hat, und ein stark unterbelichtetes Dia, kann es passieren dass beim Aufhellen Artefakte auftreten, quasi Treppenstufen, weil sich die Helligkeitswerte nur noch um ein paar Bit drehen.

Ja, ich weiß. Das sind technische Sonderfälle - das hat aber nichts mit Spielen zu tun. Und irgendwelche "Zwischenberechnungs-Stufen" gehören auch dazu. Am Ende wird das Dia dann aber wohl doch als 24bit-Grafik (oder als Foto) vorliegen. Was soll man auch mit einem 48-Bit Grafikformat, das man nirgends anzeigen kann oder das bei der Anzeige sowieso auf 24-Bit runtergerechnet wird? Man braucht Programme, die es anzeigen/runterrechnen können. Man braucht Rechenzeit zum Runterrechnen, man braucht mehr Platz für Daten, die man sowieso nicht sieht...

zatzen hat geschrieben:Das ist auch im Audio-Bereich so. Man arbeitet am besten bei der Bearbeitung mit 32 Bit Floating Point, um es dann am Ende, quasi für den Verbraucher, auf 16 Bit herunterzurechnen, nachdem man es gut ausgesteuert hat. Unsere Ohren sind offenbar weitaus dynamischer als die Augen: 8 Bit pro Farbkanal reichen für "True Color", aber 8 Bit für Ton sind mehr schlecht als recht, zumindest aus HiFi-Sicht.

Vergleiche mal nicht Deine Ohren mit den Ohren aller anderen Leute... - Mir reichen 8 Bit oft dicke aus und mit Fließkomma arbeite ich am liebsten... GAR NICHT.

Andererseits wirft man da natürlich auch mehrere Dinge, die NICHTS miteinander zu tun haben, in den gleichen Topf: Spiele mit Konsolengrafik und Konsolenmusik (Konsole vor 1994) einerseits und Tonbearbeitung für Orchestermusik andererseits haben NIX - aber auch GAR NIX miteinander zu tun und ich werde NIEMALS (ja, NIEMALS!) für Grafiken - selbst für Source-Bearbeitungen - mehr als 24Bit-Bilder benutzen (und auch nur, um sie dann an eine 8-Bit-Palette anzupassen) und für Sound wird es bei mir auch NIEMALS (ja, NIEMALS!) auf Fließkomma hinauslaufen - und wahrscheinlich auch nicht mal auf irgend etwas über 8-Bit ... und VIELLEICHT - aber nur vielleicht - gibt es mal IRGENDWANN Soundroutinen (ISM), die so etwas wie Stereo unterstützen. (Es gibt bereits vorgesehene Bits/Befehle dafür.)

Bei mir liegt es eben daran, daß meine Zielsetzung bestimmte Obergrenzen hat - und solange ich diese Obergrenzen nicht einmal ansatzweise technisch erreiche, hat es überhaupt keinen Zweck, darüber zu gehen. Und die Art "Musik", die ich mache (oder zu machen imstande bin), rechtfertigt weder 16-Bit, noch irgendwelche Fließkomma-Dinge - nicht einmal in irgendwelchen Source-Daten. Und die Art Grafik, die ich mache (gepixelt) - da sind 16,7 Millionen Farben schon der reinste Schwachsinn (wer pixelt mit so vielen Farben?) und alles darüber ist der Erwähnung nicht einmal wert.

zatzen hat geschrieben:Headroom ist auch ein Begriff aus der Audiotechnik, und bei 32 Bit Float hat man praktisch beliebig viel davon. Das ist auch ein Grund warum man 32 Bit nimmt während der Bearbeitung.

Naja, man hat nicht "beliebig viel", sondern ca. 4,2 Millarden Möglichkeiten pro Frame (etwas weniger, weil Float auch eine Reihe "ungültige" Kombinationen enthält). Aber naja, ich bin weder professioneller Musiker noch professioneller Grafiker noch professioneller Programmierer - noch professionell in IRGEND ETWAS und bin daher auch nicht so abgehoben, zu meinen, ich bräuchte derart exorbitante Dinge für das bescheidene bißchen Müll, das ich so fabriziere.

Mein Malprogramm ist selbstgemacht - total freaky und hotkeyverseucht, das würde kein "Grafiker" heutzutage mit der Kneifzange anfassen... - aber mir reicht es. Mein Musik/Sound-Editor ist selbstgemacht - ebenfalls freaky und hotkeyverseucht, das würde auch kein "Musiker" heutzutage auch nur angucken. NICHTS, was ich mache, genügt IRGENDWELCHEN professionellen Ansprüchen - aber:

Ich käme mir auch eher albern vor, die Grafiken für meine Spiele mit Photoshop zu erstellen oder den Sound für meine Spiele auf einer professionellen Soundanlage zu erstellen - das ist so lächerlich wie im 5-Sterne-Restaurant Pommes rot/weiß zu bestellen. Konsolenartige "Brachialmusik" erst in 20facher Orchesterqualität zu erzeugen, nur um sie dann auf 4-Bit-Sound runterzukonvertieren... da müßt mein Herz 'n Affe sein...

Mal eine Frage zum Thema Sprachausgabe für Deine Spiele (weil Du das so oft erwähnst) :
Wie würdest Du das realisieren? Ich meine damit NICHT die technische Seite - Du hast ja sicher hervorragendes Soundequipment, um das in super Qualität aufzunehmen und zu Entrauschen usw... - sondern eher:
Wenn Du mehrere Figuren/Charaktere im Spiel haben solltest: Wer soll die Charaktere sprechen? Kennst Du so viele Leute, die Zeit UND Lust hätten, bei so etwas mitzumachen und sich zusätzlich auf den Weg zu Deinem Mikro machen würden, um viele lange Texte mit vernünftiger Betonung/Tonlage einzusprechen?

Ich für meinen Teil habe da keine Leute, die Zeit UND Lust UND Talent UND Gelegenheit hätten, da mitzumachen - und wenn man alles selbst einspricht: Selbst wenn man alles selbst spricht und da mit Verzerrung arbeitet, ist der "Akzent"/"Sprechgeschwindigkeit" immer die gleiche, da muß man schon SEHR VIEL Arbeit reinstecken, um wie verschiedene Leute zu klingen. Und nicht umsonst gibt es ja professionelle Sprecher (die, weil sie professionell sind, eben auch so viel kosten wie jemand, der professionell ist).

Wie "Sprachausgabe" mit "irgendnem Heini von der Straße" klingt, kann man sich anhören, wenn man sich die Versionen der allerersten deutsch synchronisierten Anime anhört. Ich meine NICHT die, die im TV liefen! Das TV hat ja geübte Sprecher. Sondern die, die es so zu kaufen gab (damals noch auf VHS). Wenn man SOLCHE Sprachausgabe haben will, von irgendwelchen Torfköppen, die man so privat über irgendwen kennt... Dann werden viele Spieler die Sprachausgabe zugunsten von Untertiteln abschalten und man hat sich die Mühe mit der Sprachausgabe umsonst gemacht.

zatzen hat geschrieben:PS: Wird mein Text eigentlich wirr umgebrochen weil ich den Zeilenumbruch selbst mache? Soll ich das lieber demnächst sein lassen?

Ja, Dein Text wird wirr umgebrochen und ich muß das jedes Mal nach-ändern um kein "Kamm-Quoting" zu haben. Da das Forum/der Browser den Text sowieso umbricht und zwar je nach eingestellter Textgröße trotzdem vernünftig, sind meiner Meinung nach zusätzlich selbstgemachte Umbrüche so nötig wie ein drittes Nasenloch.

Ich wollte bisher nichts dazu sagen, weil ich dachte, dieser Umbruchwahnsinn hätte bei Dir irgendwelche technischen Gründe und da will man ja nun nicht deswegen nerven; aber wo Du jetzt schon so fragst...

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 0 Gäste