Amiga-Dresden
Erste Erfahrungen mit AmigaOS-Programmierung - Druckversion

+- Amiga-Dresden (https://amiga-dresden.de)
+-- Forum: Amiga Software und mehr (https://amiga-dresden.de/forumdisplay.php?fid=11)
+--- Forum: Amiga Software (https://amiga-dresden.de/forumdisplay.php?fid=26)
+--- Thema: Erste Erfahrungen mit AmigaOS-Programmierung (/showthread.php?tid=863)

Seiten: 1 2


Erste Erfahrungen mit AmigaOS-Programmierung - Sen - 19.07.2020

Ich hatte vor zwei Tagen mit einem kleinen Programm angefangen...
Es macht noch nicht viel, es stellt bis jetzt nur ein Paar "Sterne" auf dem Bildschirm da.
Zunächst war die Frage, wie ich denn Anwendungen kompiliere, und da alle meine A500 nur einen "normalen" 68000 installiert haben, würde das etwas lange dauern. Deshalb kommt für mich nur Cross-Compiling in Frage.
Ein entspechender Compiler war auch nicht schwer zu finden. Ich habe mich für die Amiga-GCC-Toolchain entschieden, da ich sowieso auf Debian/Linux programmiere und dort der gcc nativ läuft. Man kann sich die ganzen Tools einzeln runterladen und kompilieren, aber ich habe mich für eine Variante entschieden, die nur ein Paar Befehle zum Kompilieren und Einrichten braucht.
Diese ist unter https://github.com/bebbo/amiga-gcc zu finden.
Als nächstes brauchte ich einen Emulator, um das Programm schneller (und gemütlicher) laden zu können.
FS-UAE war die einzige richtige Wahl für Debian, den hatte ich auch früher verwendet.
Nun brauchte ich noch ausreichend Dokumentation, die ist hauptsächlich in den Headern der AmigaOS-Bibilotheken vom Compiler und in den Autodocs
(https://wiki.amigaos.net/wiki/Autodocs:Main) zu finden.
Die erste Programmversion sollte nur ein Fenster aufmachen und einen Text darstellen, mehr nicht. Also mit Hilfe der Docs und Informationen aus dem Netz
Programm geschrieben, mit cross-gcc kompiliert, erstmal Guru 4. Fehler korrigiert, immer noch gleicher Guru. Dann nochmal Alles überarbeitet, Compileroptionen für Prozessor angeben, Startupcode manuell verändert, nütze alles Nichts. Ein Guru nach dem Anderen. Dann habe ich die Dateigröße im ADF gesehen: immer noch die gleiche vom ersten Versuch. ADF-Opus abgecheckt, hatte immer die ADF korrekt verändert. Dann wieder Emulator gestartet, der hatte doch nicht etwa tatsächlich die ADF zurückgesetzt! Im Emulatorordner geschaut, Cache-Datei gefunden und gelöscht. Läuft, Text und Fenster sind da.
Und hat nur zwei bis drei Stunden gedauert, Danke Cache-Funktion! X(

Was lernt man daraus: 1. Software kann nützliche aber nervige Funktionen enthalten; 2. Gleich im Emulator einen Ordner als HDD einbinden...
Nun zu Heute:
Ich habe die Funktionen von Intuition und Graphics schnell verstanden, aber mein Programm könnte schneller sein, also so schnell wie ein A500 es schafft.
Das Programm ist aktuell so aufgebaut:
- Lade Intuition und Graphics und zusätzlich noch Timer für eine feste Framerate.
- Öffne Screen mit 5 bits (32 Farben) und setze Farbpalette
- Öffne Fenter im Screen mit maximaler Größe (320x200/LORES), setze Cursor auf eine 0x0 große Bitmap um ihn auszublenden
- Initialisiere Backbuffer zum Zeichnen
- Init. Timer auf 25 TPS

- In einer Endlosschleife:

- Setze RSEED, Zeichne 10 Sterne auf Buffer, mit zufälligen Positionen und Farbe, verschoben auf X und Y um Zeit / 2
- Positionen und Farben sind immer die gleichen (mit offset) da SRAND mit dem gleichen Seed aufgerufen wurde.
- Blitte Backbuffer auf Screen
- Warte auf Timer

Da das Fenster kein CLOSE oder CTRL-C empfangen kann (da in den WFLAGS deaktiviert), läuft die Schleife für immer, aber sollte etwas nicht funktionieren, werden alle Ressourcen freigegeben und das Programm ohne Crash beendet.
Ich werde erstmal daran weiter arbeiten, das Programm effizienter zu machen und ein Paar richtige "Features" einzubauen.
Aber für den Anfang reichts. Vielleicht wird was draus Big Grin

Bilder:


- Jochen - 19.07.2020

Sehr cool!
Ach du testest das gleich per Emu... ja, das geht auch. Hast du einen 1200er oder 600er auch da? Da kannst du ja sehr einfach eine CF über den PCMCIA einbinden und auch per Hotplug rein und raus nehmen, um Daten vom PC rüber zu schaufeln.
Geht auch mit normalen IDE-Controllern, da aber nicht per HotPlug. Smile

Sehr schön, dass du auch gleich noch Quellen und Fehlerlösungen offengelegt hast. Klasse! :thumbsup:

Wir wollen mehr sehen ... :thumbup:


- CB1JCY - 19.07.2020

Bää...wieder Einer, der den Amiga am System vorbei programmiert? Wink
Ich hatte mich auch mal n bissl mit Assembler auf Amiga beschäftigt. Brav (müslifressermäßig) an die Literatur gehalten und als erstes Speicher vom BS angefordert...
Mit C hab ich da aber nichts gemacht. Da werden vieleicht solche Selbstverständlichkeiten in einem Multitaskingsystem nebenbei mit gemacht?
Schreibe bitte weiter über Deine Erfolge und lass uns evl. auch an ein par Codeschnipseln teilhaben.
Emulator: Ich habe dafür Windowsrechner unter den Pfoten. Da ist der WinUAE sehr gut. Mal schnell was berechnen lassen, geht gut.
In der Cloud findest Du auch nützliche Literatur. Das "Amiga intern" kannste Dir da mal ansehen.Weiterhin viel Erfolg dazu.

Gruß CB1JCÝ


- Jochen - 19.07.2020

Das ganze Betriebssystem des Amiga ist C programmiert... wer sich mit so Sachen wie Assembler abgibt, wird zwar mit Glück sehr effiziente Sachen machen können, aber nichts nützliches. Wink
Dafür gibt es ja Hochsprachen, damit man sich um das kümmern kann, was man als Ziel hat, und eben nicht beim Urschleim anfängt... Big Grin

Demos sind sicher in Assembler, aber eben auch sehr speziell und legen dann auch ziemlich schnell n Crash hin, wenn die Umgebungsvariablen nicht haarklein genormt passen. Daher laufen viele Demos leider auch nur auf bestimmten Rechnern mit bestimmter Config und schon ein anderes Kickrom kann die Karre umkippen.

Daher, Nützliches programmieren => Hochsprache
Spielerei und wackelige Ergebnisse => Assembler

:thumbup:


- CB1JCY - 19.07.2020

Warum Demos wohl in Assembler gemacht sind? Sehr viele Demos sind systemkonform geschrieben, allerdings oft nir auf bestimmten Prozessoren/Kickstarts lauffähig. Da ist C= nicht unschuldig wenn Einsprungadressen und -Bedingeungen verändert wurden.

Warum bei mir Assemblerversuche (mehr wars beim Amiga nicht)?
Weil ich in den 80igern meinen Plus4 auch in Assembler programmiert hatte. Der TED-Mon lud ja gerdezu ein.
Ich will aber hier keine Diskussion über Programmiersprachen losbrechen. Jede hat ihre Vor-und Nachteile.

@Jochen: Immer diese Mähr, dass das Amige-BS in C programmiert worden sei. Lies mal nach:
https://de.wikipedia.org/wiki/AmigaOS
Tongue
Zitat: Spielerei und wackelige Ergebnisse => Assembler
Du bist ein Kind der 80iger- und hast programmieren in den 90igern gelernt. Daher verstehe ich diese Meinung, akzeptiere Diese aber nicht so. Es gab Zeiten, da wurden Programme noch binär gesetzt. Assembler war ab den 70igern schon ein Fortschritt. Hier, in einem Retroforum, sollte man den einfacheren Programmiertools Respekt zollen. Sooo wacklig waren meine mit TEDMon geschriebenen Sachen auf dem Plussi nun auch nicht. Sie waren nur nicht so umfangreich, erfüllten aber, soweit ich testen konnte, fehlerfrei, ihren Zweck. (Es gibt keine fehlerfreien Programme.)
Übrigens: Als ich mit Delphi programmiert hatte, war ich erstaunt, was im Compilat alles sinnlos mitgeschleppt wurde.


Soo für Heute Schluss (bissel spät geworden) - Sen - 20.07.2020

Habe noch nen ollen Würfel gezaubert, mit krassen 2 FPS!
(Vielleicht lieber eine andere Methode zum Rendern)
Naja, werde mir Morgen auch mal m68k-Assembler ansehen (wenn ichs verstehe, aber bestimmt).


- Jochen - 20.07.2020

Hmm, kann da nix lesen, wie das programmiert wurde!?

Naja, mag für kleine Programme damals gereicht haben, aber bei Assembler fängste ja bei jeder Operation im Urschleim an und ich möchte mir gar nicht vorstellen, was so ein drehender Würfel für einen Aufwand dargestellt hätte.
Wers mag, solls machen, aber nicht die moderneren Sprachen bashen, denn die gibts nicht umsonst denn auch diese basieren natürlich auf Assembler, aber man schreibt sich nicht jedes mal den Urschleim neu, sondern verwendet quasi fertige Codeschnipsel, die da eben Befehle darstelle und diese werden beim compilieren dann ja auch wieder optimiert und auf Maschinensprache zurückgeführt. Wink

Wie gesagt, wer will kann gern Assembler machen, aber nicht jeder ist so masochistisch veranlagt... Big Grin


- Sen - 20.07.2020

Benötigt war nur eine Vektor-Mathe-Bibilothek, daraus die Funktionen, sind nur 2 Dateien mehr zu kompilieren.
In den globalen Variablen ist ein konstantes DOUBLE-Array mit Würfel-Eckpunkten hinterlegt. (12[Linien]*2[Punkte]*3[Koordinaten])

Im Render-Struct:

Code:
    mfloat_t position[VEC3_SIZE]; // Kameraposition
    mfloat_t target[VEC3_SIZE]; // Kameraziel
    mfloat_t up[VEC3_SIZE];  // Kamera-Up(gibt an an welcher Achse es hoch geht)
    mfloat_t view[MAT4_SIZE];  // Kameramatrix für die Sichtrichtung
    mfloat_t perspective[MAT4_SIZE];  // Kameramatrix für die Perspektive
    mfloat_t rotation[MAT4_SIZE]; // Matrix für Rotation des Würfels
    mfloat_t raxis[VEC3_SIZE]; // Rotationsachse
    mfloat_t scale[MAT4_SIZE]; // Matrix zum verkleinern des Würfels
    mfloat_t scalar[VEC3_SIZE]; // Skalierfaktor
    mfloat_t transform[MAT4_SIZE]; // Transformationsmatrix aus Sicht und Perspektive
    mfloat_t model[MAT4_SIZE]; // Modellmatrix aus Rotation und Skalierung
    mfloat_t total[MAT4_SIZE]; // Hauptmatrix aus Transformation und Modell
    mfloat_t vertexA[VEC4_SIZE]; // Erster Vertex der Linie
    mfloat_t vertexB[VEC4_SIZE]; // Zweiter
Im Render-Init (1x berechnet):

Code:
mat4_look_at(rd->view,vec3(rd->position, 0.0, 0.0, -10.0),vec3(rd->target, 0.0, 0.0, 0.0),vec3(rd->up, 0.0, 1.0, 0.0)); // Berechnung der Sichtmatrix
        mat4_perspective(rd->perspective, to_radians(70.0), 320.0/200.0, 0.1, 20.0); // Perspektive
        mat4_identity(rd->scale); // Skalierung auf 1
        mat4_scaling(rd->scale,rd->scale,vec3(rd->scalar,0.25,0.25,0.25)); // Skalierungsmatrix
        mat4_identity(rd->rotation); // Rotation auf 1
        mat4_rotation_axis(rd->rotation,vec3(rd->raxis,0.5,0.1,0.2),to_radians(0.0)); // Rotationsmatrix
        mat4_multiply(rd->transform, rd->perspective, rd->view); // Transformationsmatrix == Sicht * Perspektive
Im Render-Loop:
Code:
SetRast(renderTarget,BLACK); // Bildschirm schwarz

        mat4_identity(rd->rotation); // Rotation auf 1
        mat4_rotation_axis(rd->rotation,vec3(rd->raxis,0.5,0.1,0.2),to_radians(currentStep * 360.0)); // Rotation entlang der Achse um SEKUNDEN/16*360
        // currentStep sind die vergangenen Sekunden seit dem letzten Rendervorgang (höchstens 1.0)
        mat4_multiply(rd->model, rd->scale, rd->rotation); // Modell = Skalierung * Rotation
        mat4_multiply(rd->total, rd->transform, rd->model); // Haupt = Transformation * Modell

        SetAPen(renderTarget,WHITE); // Weiss zeichnen
        for(int i = 0;i < CUBE_LINES;i++) { // 12 Linien rendern
            for(int d = 0;d < 3;d++) { // Kopieren der Punkte in die Vertexe
                rd->vertexA[d] = cubePoints[i*6+d];
                rd->vertexB[d] = cubePoints[i*6+d+3];
            }
            rd->vertexA[3] = 1.0; // W muss 1 sein
            rd->vertexB[3] = 1.0;

            vec4_multiply_mat4(rd->vertexA,rd->vertexA,rd->total); // Multiplikation Matrix mit Punkten -> neue Koordinaten
            vec4_multiply_mat4(rd->vertexB,rd->vertexB,rd->total);
            

            WORD xA = ((WORD)(((rd->vertexA[0] + 1.0) / 2.0) * 320.0)); // Koordinaten -1.0...1.0 -> Pixelkoordinaten (Y umgedreht)
            WORD yA = ((WORD)(((rd->vertexA[1] + 1.0) / 2.0) * 200.0));
            WORD xB = ((WORD)(((rd->vertexB[0] + 1.0) / 2.0) * 320.0));
            WORD yB = ((WORD)(((rd->vertexB[1] + 1.0) / 2.0) * 200.0));
            if(rd->vertexA[2] < 0.0 || rd->vertexB[2] < 0.0) { // Baufaellig: Prüfen ob Koordinaten (oben Z, unten X und Y) im Bereich liegen (noch nicht benötigt)
                continue;
            }
            if((xA >= 320 || xB >= 320) || (yA >= 200 || yB >= 200) || (xA < 0 || xB < 0) || (yA < 0 || yB < 0)) {
                continue;
            }
            Move(renderTarget,(LONG)xA,(LONG)yA); // Gehe zu Punkt A
            Draw(renderTarget,(LONG)xB,(LONG)yB); // Zeichne bis Punkt B
        }
Naja, OpenGL ist da besser, da es die GraKa nutzt, aber der A500 hat keine, und auch keine FPU, so sind die Fließkommazahlen lahm.
PS: läuft mit diesem Code jetzt 2 FPS schneller Big Grin (vorher Alles im Loop berechnet)!


- Jochen - 20.07.2020

Naja, die CustomChips im Amiga haben, soweit ich weiß, spezielle Recheneinheiten für sowas. Ansonsten hätte man die 3D Spiele auf dem Amiga nie so hin bekommen, wenn alles der 68000er hätte rechnen sollen. Aber dafür braucht man sicher spezielle Bibliotheken ...


- Sen - 20.07.2020

Jochen,index.php?page=Thread&postID=8638#post8638' schrieb:Aber dafür braucht man sicher spezielle Bibliotheken ...
Eigentlich nicht, graphics.library hat ein Paar Funktionen für den Blitter und Copper und Sprites, diese sollten ausreichen, um das Programm schneller zu machen, und sogar die Flächen zu füllen. Aber: In der technischen Dokumentation habe ich über die Register gelesen, die man mit Assembler erreichen könnte, die man mit der 1.3er Graphics-Lib und auch späteren nicht oder nur indirekt (mit mehr Operationen) ansteuern kann. Die Funktionen nehmen einem Vieles ab, aber es scheint so, dass die Lib wirklich nur für kleinere, "normale" Anwendungen ausreicht (also z.B. für die WB und Anwendungen dafür, keine Spiele/Demos). Man hat zwar Zugriff auf die Koprozessoren, aber man kann sich zum Beispiel den Draw-Modus des Blitters nicht aussuchen, der wird automatisch gesetzt (und noch mehr). Wenn du jetzt nämlich so eine Funktion aufrufst, machen viele davon mehr als benötigt, und schlucken Zeit vom Koprozessor und 68k. Und ich vermute mal, da die meisten Demos auf 500ern laufen sollen, dass die Effizienz eine Große Rolle spielt, da viele Leute einen 500er hatten und nicht mehr.
Ich könnte jetzt trotzdem diese Funktionen verwenden, aber ich werde wirklich erstmal etwas weiter ASM lernen und mich auch mal mit den Koprozessoren weiter auseinandersetzen. Ausserdem: Ich kann C und ASM auch in eine Datei stecken, mit
Code:
asm("move ...");
. Ich kann dort quasi auch zu(r Adresse) einer C-Funktion springen, mit jmp _FUNKTION, muss natürlich die Funktionsparameter vorher auch richtig setzen, usw. usw. (lerne noch dazu).
Also:
Allgemeine Berechnungen (m68k) ==> C-Funktion
Alles mit Grafik und Zugriff auf irgendwas Anderes ==> ASM-Routine
So sollte ichs hinkriegen.
Aber erstmal werde ich an meinen Projekten am anderen PC weitermachen, Dateiformate, Bildverarbeitung usw. (aber nur in C, x86 hat mir zu viele Instruktionen zum lernen Big Grin ).
Oder ich krame meine OpenGL-Demo wieder raus (mit 300+ FPS!)...