Manipulationen des RSC-Files, Teil 1

Haben Sie nicht auch schon einmal vergessen, das obligatorische RSC-File mit zu kopieren? Oder stört es Sie, daß das File, programmiert man unsauber, immer auf dem Laufwerk A gesucht wird?

Ist Ihnen der einfache String im Menü auch zu langweilig? Hätten Sie dort gern ein Bildchen? Oder wünschen Sie ein wenig Bewegung in der GEM-Dialogbox?

Wenn Sie alles mit „Ja“ beantwortet haben, dann sollten Sie diesen und die folgenden Artikel lesen!

Über den Aufbau eines RSC-Files ist in den vergangenen Ausgaben von ST-Computer ausführlich berichtet worden. Lesen Sie bitte über den Kopf dieser Datei nach. Er enthält alle Zeiger auf die ausgewählten Objekttypen, welche wiederum, je nach Typ, Zeiger auf verwendete Strukturen wie IconBlocks, BitBlocks, Tedinfos und Texte enthalten können. In diesen Blocks stehen dann wiederum Zeiger auf die dazugehörenden Texte, Grafiken und selbstdefinierte Programmteile.

Ein Unterschied ist bei den Zeigern zu beachten: Die Zeiger, gleichbedeutend mit Adressen, im Header sind 16 Bit breit. Damit lassen sich nur relative Entfernungen bis zu 32 KB nach vom und nach hinten anspringen. Das ist auch ein Grund, weshalb eine RSC-Datei nicht größer als Maxinteger, 32 KB, sein kann (der andere Grund: die Länge steht im Header in 16 Bits. Damit wären allerdings 64 KB möglich).

Die Adressen in den Objekten und in den Blöcken sind jedoch 32 Bit breit. Folglich kann von dort aus der ganze Atari-Speicher erreicht werden. Dieser Umstand wird oft dazu genutzt, eigene Grafiken oder sog. UserBlocks erst nach dem Start des Programmes zu aktivieren. Von einem beliebigen Objekt, das mit dem RSC-Editor z.B. nur als I-Box erzeugt wurde, wird per Programm der Typ geändert und sein Obj_Spec als Adresse auf den eigenen Grafikblock umgebogen. Ich werde darauf beim Verändern eines Menüeintrages in ein Bildchen und beim Herumwandern des gleichen Bildes um eine Dialogbox zurückkommen. Nun zur Befriedigung der ersten, von Ihnen hoffentlich mit „Ja“ beantworteten Frage:

Resourcen ohne Resource-Datei

Mit dem Resource-Editor wird ein einfacher Dialog (Bild) erzeugt. Die Ausgabe wird auf Pascal geschaltet. Es werden 2 Dateien abgelegt: eine Textdatei mit den von Ihnen ausgewählten Konstantennamen sowie die Resource-Datei mit der Extension *.RSC. Die Textdatei kann per Include-Anweisung in Ihr Programm eingebunden werden. Besser noch: Sie benennen diese Datei zur Unit um und übersetzen sie gesondert. Damit können Sie bei größeren Projekten von anderen Units auf sie zugreifen. Der Implementationsteil bleibt dabei leer.

Benennen Sie die einzelnen Objekte des Dialogbaumes mit den Namen, die Sie im Testprogramm (Listing 3) finden. Auf den Dialog werde ich noch einmal zur Demonstration von Bewegungen während des Dialogaufrufes zurückkommen. Die Konstanten habe ich hier der Bequemlichkeit halber direkt in das kleine Beispielprogramm (Listing 3) eingefügt. Die RSC-Datei wird nun mit dem Programm (Listing 1) in eine Unit mit Definitions- und Implementationsteil umgewandelt.

Der RSCMaker

Per Fileselektorbox wird eine RSC-Datei eingelesen. Dazu wird entsprechender Speicher angefordert. Diese Hex-Datei wird nun analysiert. Aus dem Kopf läßt sich ermitteln, wieviel Objekte vorhanden sind und bei welcher relativen Adresse (bezogen auf den Anfang der RSC-Datei) sie beginnen. Alle Werte werden im Definitionsteil für das gesonderte Hauptprogramm bereitgestellt.

Es reicht die Angabe der Adresse des ersten Objektes. Diesen Zeiger nenne ich in meiner GEM-Library PtrObjTree, einen Zeiger auf einen Objektbaum. Die weiteren Konstanten, Typen und Variablen können evtl, auch benötigt werden (ich brauchte sie allerdings noch nie).

Der Definition folgt die Implementation, das eigentliche Programm. Warum wird diese nun benötigt?

Es stellt zum einen dem Compiler alle Daten des RSC-Files als ASCII-Datei zur Übersetzung zur Verfügung. Beim Maxon-Pascal werden solche Daten mit ASM .. END geklammert, bei anderen Compilern sind es die Wörter INLINE oder CODE. Diese Anweisungen bewirken, daß die folgenden ASCII-Werte wieder in Hexcode rückverwandelt werden, machen also das Gegenteil von dem. was ein Teil des RSC-Makers bewirkt.

Die Anweisung IntToHex ist in einer gesonderten UnitNumConv enthalten. Dort wird aus einer Integerzahl die Form $ABCD als ASCII-String erzeugt. Die Unit NumConv befindet sich auf der Diskette.

Der Implementationsteil reloziert zum anderen alle RSC-Daten, sofern es sich um 32-Bit-Adressen handelt.

Diese stellt der RSC-Editor nur als relative Adressen, bezogen auf den Dateianfang, bereit. Nach dem Start des Programmes, das die hier erzeugte Unit einbindet, wird zuerst die aktuelle absolute Adresse des Hex-Blockes ermittelt. Zu dieser werden dann die relativen Werte addiert. Das ist übrigens auch eine der Arbeiten der AES-Funktion RscLoad().! Jene hat darüber hinaus aber noch die Aufgabe, Platz für die zu ladende RSC-Datei zu reservieren. Letzteres entfällt bei unserem Vorgehen, da sich die Datei ja bereits im Speicher befindet. Die 16-Bit-Adressen brauchen, da sie vom Dateianfang aus zeigen, nicht verändert zu werden.

Was aus Ihrer RSC-Datei geworden ist, sehen Sie im Listing 2.

Alle Kommentare und Absätze in der Prozedur rsdata habe ich nachträglich manuell eingetragen. Damit soll es Ihnen leichter gemacht werden, den Zusammenhang dieser Prozedur mit dem RSC-Bild zu erkennen. Suchen Sie Ihre Strings und wo deren Adressen stehen. Sehen Sie sich den Umweg über die Struktur TEDINFO beim Typ G_BOXTEXT an!

Eine allgemeine Anmerkung zum Listing: Wie Sie sicherlich erkannt haben, stimmen die GEM-Aufrufe nicht so ganz mit dem überein, was Sie aus dem Pascal-Handbuch kennen. Das Programm war ursprünglich in Megamax-Modula 2 geschrieben. Mir haben in dieser Sprache die einfacheren Aufrufe gefallen. So werden, wo möglich, keine Felder übergeben sondern Verbünde z.B für Punkte und Rechtecke. Auf der Diskette finden Sie die Units für AES und VDI als Quell-Listing. Wenn Sie diese nicht verwenden wollen: es sind nur wenige Aufrufe im Programm wie InitGem, FormAlert und FileSelect. Die Anpassung an die Original-Pascal-Units dürfte deswegen kein Problem darstellen.

In der nächsten Folge wird ein Bildchen (ein Hündchen, Stad-sei-Dank) in eine Menüleiste eingefügt.

Literatur:

Handbuch Maxon-Pascal
Handbuch Megamax Modula 2, ASH
Aumiller, Luda, Möllmann: GEM-Programmierung in C, Verlag Markt&Technik
Diverse Artikel in ST-Computer


(**************************************************
*                                                 *
*               Listing 1                         *
*                                                 *
* Programm zum Erzeugen einer Unit aus            *
* RSC-Files, wie sie ein RSC-Editor erzeugt.      *
* Erspart das jeweils zweite File m. der Exten-   *
* sion .RSC, das bei Verwendung von Dialogen,.    *
* Menus etc zwangsläufig zu jedem Programm        *
* gehört und welches natürlich nie auf der        *
* gleichen Ebene gefunden wird, von der das       *
* Hauptprogramm gestartet wurde.                  *
* geschrieben in Megamax Modula 2, umgesetzt      *
* in Maxon Pascal                                 *
* Die Strings wurden wegen d 49 Zeichen/Zeile     *
* stellenweise geteilt.                           *
*                                                 *
* (c) 1991 MAXON Computer                         *
* Bruno Volkmer          1990/1991                *
*                                                 *
**************************************************) 
PROGRAM RSCMkPas;

(*$F+*)
Uses Dos, AES, VDI, GEM, NumConv, GrafBase;

TYPE tBuffer   = ^wordArray;
     wordArray = ARRAY [0..15999] OF INTEGER; 
     ADDRESS   = POINTER;

VAR  handle             : DeviceHandle;
     inpath,inname, 
     infile,egal,Pfad, 
     outname, outpath, 
     modname        : STRING;
     fhandle        : File;     (* Filehandler      *)
     f              : TEXT;
     RscLaenge,
     gelesen        : INTEGER;  (* RSC-Länge        *)
     Buffer         : tBuffer;  (* Puffer RSC       *)
     ok,success     : BOOLEAN,  (* allg VARs        *)
     nIcons, nObjects,          (* n = Anzahl der.  *)
     nBitBlk, nFreeImg,         (* . Objekte eines  *)
     nTrees, dummy,             (* .. Typs          *)
     nFreeStr, nTeds: INTEGER;
     stat           : INTEGER,  (* File-Stat        *)
     iconsdrin      : BOOLEAN;  (* Icons ?          *)
     ImpStr,
     HexString      : String;   (* Hilfsst.         *)
     but            : INTEGER;  (* FormAlert        *)

(************************************************
* Einlesen des vom RSC-Editor erzeugten RSC-    *
* Files Vorgabeextension zum Lesen ist * RSC.,  *
*************************************************)

FUNCTION RscFileRead:BOOLEAN;
BEGIN
    inpath := '\*.RSC'; 
    inname := '        .RSC';
    SelectFile(inpath,inname,ok);
    IF ok THEN BEGIN    (* wenn nicht abgebroch. *) 
        modname := inname; (* Filename aufheben. *)
        FSplit (inpath,inpath, egal, egal); 
        inname = inpath + inname;
        (*$I-*)
        Reset(fhandle,inname); (*  Datei öffnen  *)
        (*$I+*)
        IF IoResult = 0 THEN BEGIN
            RscLaenge := FileSize(fhandle);
            GetMem(Buffer,RscLaenge);
            BlockRead(fhandle,Buffer^,RscLaenge,gelesen);
            Close(fhandle);     (* und Schließen  *)
            RscFileRead := TRUE 
        END
    ELSE  RscFileRead := FALSE;
    END ELSE RscFileRead := FALSE;
END (* RscFileRead *);

(************************************************ 
 Ausgabedatei zum Schreiben erzeugen und Öffnen. 
 Es wird der Name der RSC-Datei verwendet, 
 wobei das RSC entfernt wird und durch .PAS 
 ersetzt wird. 
************************************************)

FUNCTION DateiOeffnen:BOOLEAN;
VAR posit:BYTE;
BEGIN 
    outname = inname;
    posit = Pos ( 'RSC',outname); (* 'RSC' suchen *)
    IF posit > 0 THEN BEGIN (* wenn gefunden...   *)
        Delete(outname,posit,3);  (* RSC löschen  *) 
        outname := outname + 'PAS'; (* dafür 'PAS' anhängen *)
        Rewrite(f,outname);         (* neue Datei *)
    END;
        IF IoResult <> 0 THEN DateiOeffnen := FALSE 
        ELSE DateiOeffnen := TRUE;  (* Fehler?    *)
END (* DateiOeffnen *);

(************************************************ 
    Ab hier wird das Interfaceteil erzeugt, 
    Objekttypen werden aus der Unit Gem geholt 
************************************************)

PROCEDURE MachDefKopf;
VAR posit : BYTE;
BEGIN 
    WriteLn(f);
    posit = Pos('.',modname);
    Delete(modname,posit, 4);
    Write(f,'Unit ');Write(f,modname);
    WriteLn(f,';') ;
    WriteLn(f); WriteLn(f);
    WriteLn(f,'(*Erzeugt vom Ressourcemacher 1.1*) ');
    WriteLn(f,'(* B.Volkmer, 1991 *) ');
    WriteLn(f);
    Write(f,'(* Version des RessourceFiles : ');
    HexString := IntToHex(Buffer^[0]);
    WriteLn(f,HexString,' *) ');
    
    WriteLn(f,'(*$F+*)');
    WriteLn(f,'INTERFACE');
    WriteLn(f); WriteLn(f,'Uses Gem, Bios.');
    WriteLn(f);

END (*MachDefKopf*);


PROCEDURE MachTypes;
BEGIN 
    WriteLn(f);
    WriteLn(f,'TYPE');
    IF nObjects <> 0 THEN 
        WriteLn(f,' TreeArray = ARRAY[0..nTrees] OF POINTER;'); 
    IF nFreeStr <> 0 THEN 
        WriteLn (f,' StringArray =ARRAY[0..nFreeStr] OF POINTER;'); 
    IF nFreeImg <> 0 THEN 
        WriteLn(f,' ImgArray = ARRAY[0..nFreeImg] OF POINTER;'); 
    IF nTeds <> 0 THEN 
        WriteLn(f,' TedlnfoArray = ARRAY[0..nTeds] OF TEdInfo;'); 
    IF nIcons <> 0 THEN 
        WriteLn(f,'IconBlkArray =ARRAY[0..nIcons] OF IconBlock;'); 
    IF nBitBlk <> 0 THEN 
        WriteLn(f,' BitBlkArray = ARRAY[0..nBits] OF BitBlock;'); 
    IF nObjects <> 0 THEN 
        WriteLn(f,'ObjAddrArray = ARRAY[0..nObjects] OF Object;'); 
    WriteLn(f);

END (*MachTypes *);

(************************************************ 
 Erzeugung der Konstanten im Interfaceteil 
********************************»***************)

PROCEDURE MachDefConst;

    PROCEDURE MachConst(txt:String;
                        point,flag:INTEGER; 
                        VAR nX:INTEGER);

    VAR wert : INTEGER, 
        stri : String;
    BEGIN
        wert := Buffer^[point]; 
        nX   := wert; 
        flag := Buffer^[flag];
        IF flag <> 0 THEN BEGIN 
            Str(wert:5,stri);
            WriteLn(f,'  ',txt,stri,';');
        END;
    END (*MachConst*);

BEGIN (* MachDefConst *)

    WriteLn(f);
    WriteLn(f,'CONST');
    MachConst('nObjects = ',10,10,nObjects);
    MachConst('nTrees   = ',11,11,nTrees);
    MachConst('nTeds    = ',12,12,nTeds);
    MachConst('nIcons   = ',13,13,nIcons);
    MachConst('nBits    = ',14,14,nBitBlk);
    MachConst('nFreeStr = ',15,15,nFreeStr);
    MachConst('nFreeImg = ',16,16,nFreeImg);

    MachConst('xObjects = ',1,10, dummy);
    MachConst('xTrees   = ',9,9,  dummy);
    MachConst('xTEds    = ',2,12, dummy)
    MachConst('xIcons   = ',3,13, dummy);
    MachConst('xBits    = ',4,14, dummy);
    MachConst('xFreeStr = ',5,15, dummy);
    MachConst('xFreeImg = ',8,16, dummy);

END (* MachDefConst *);

(************************************************ 
  Erzeugung der Variablen im Interfaceteil 
********************************************»***)

PROCEDURE MachDefVars;
BEGIN 
    WriteLn(f);
    WriteLn(f,'VAR');
    IF nObjects <> 0 THEN
        WriteLn(f, ' TreeAddr : ^TreeArray;');
    IF nFreeStr <> 0 THEN 
        WriteLn (f, ' StringAddr : ^StringArray; ');
    IF nFreeImg <> 0 THEN 
        WriteLn(f, ' ImgAddr : ^ImgAddrArray;');
    IF nTeds <> 0 THEN 
        WriteLn(f, ' TedInfoAddr : ^TedInfoArray;');
    IF nIcons <> 0 THEN 
        WriteLn (f, ' IconBlkAddr : ^IconBlkArray;');
    IF nBitBlk <> 0 THEN 
        WriteLn(f, ' BitBlkAddr : ^BitBlkArray;');

    IF nObjects <> 0 THEN 
        WriteLn(f, ' ObgectAddr : ^ObjAddrArray;');
    WriteLn(f);

END (*MachDefVars *) ;

(************************************»*********** 
  ab hier wird die Implementation erzeugt. 
***************************»********************)

PROCEDURE MachImpKopf;
BEGIN

WriteLn(f); WriteLn(f,'IMPLEMENTATION');
WriteLn(f);
END (*MachImpKopf *);

(************************************************ 
  und ein paar Konstante in der Implementation 
********************************************»***)

PROCEDURE MachImpConst;
BEGIN
WriteLn(f);
WriteLn(f,'CONST');
WriteLn(f,'  GBOX  = 20; USERBLK  = 24;');
WriteLn(f,'  GIBOX = 25; GBOXCHAR = 27;');
WriteLn(f);

IF (Buffer^[13] <> 0) OR (Buffer^[14] <> 0) THEN 
BEGIN
    iconsdrin := TRUE;
    WriteLn(f,'  GIMAGE = 23; GICON = 31;');
 END;
END (*MachImpConst *);

(************************************************ 
  ein paar Variable gibts auch im Imp.Teil 
************************************************)

PROCEDURE MachImpVars;
BEGIN
    WriteLn(f); WriteLn(f,'VAR');
    WriteLn(f,'  i              : INTEGER;');
    WriteLn(f,'  chW,chH,rezol  : INTEGER;'),
    WriteLn(f,'  RSDATA         : POINTER;');
    WriteLn(f);
END (*MachImpVars *);

(************************************************* 
  Prozedur liest Hexcodes der RSC-datei aus dem 
  Buffer, in den die Datei geladen wurde. 
  Sie erzeugt dann ASCII- Code und formatiert ihn. 
*************************************************)

PROCEDURE MachASCIIausHex;
                        (* der RSC-Daten als Hexcode *) 
VAR i,max,w : INTEGER;
    ok      : BOOLEAN;
BEGIN
    max := gelesen - 1;
    WriteLn(f);
    WriteLn(f,'VAR rsdta : POINTER,');
    WriteLn(f,'PROCEDURE rscdata;');
    WriteLn(f,'  ASSEMBLER; ');
    WriteLn(f,'  ASM');
    WriteLn(f,'   LEA @start,A0');
    WriteLn(f,'   MOVE.L A0,rsdta');
    WriteLn(f,'   BRA @fertig'); ;
    WriteLn(f,'@start:');

    max := max DIV 2;
    FOR i := 0 TO max DO BEGIN 
        w := Buffer^[i];
        HexString = IntToHex(w);
        IF i MOD 8=0 THEN
            HexString := '   DC.W '+HexString;
        Write(f,HexString);
        IF (i+1) MOD 8=0 THEN WriteLn(f)
        ELSE BEGIN
            IF i + 1 > max THEN ELSE 
            Write(f,',');
        END;
    END;
    WriteLn(f);
    WriteLn(f,'@fertig ');
    WriteLn(f,' END;'); WriteLn(f);
END (*MachASCIIausHex *);

(************************************************ 
 Hier wird das eigentliche Programm zusammengestellt
*************************************************)

PROCEDURE MachPgm;
BEGIN
WriteLn(f); WriteLn(f);
WriteLn(f,'BEGIN');
WriteLn(f,' rscdata;');
IF nTrees <> 0 THEN BEGIN 
    WriteLn(f,' (*Liste der Objektbaum-Adressen relozieren*)'); 
    WriteLn(f);
    WriteLn(f,' RSDATA := rsdta;');
    WriteLn(f,' TreeAddr = POINTER(LONGINT(RSDATA)','+LONGINT(xTrees));'); 
    WriteLn(f,' FOR i := 0 TO nTrees-1 DO');
    WriteLn(f,'     TreeAddr^[i] = POINTER(LONGINT','(TreeAddr^[i])+LONGINT( RSDATA));');
END;

IF nTeds <> 0 THEN BEGIN 
    WriteLn(f,'(* Adressen innerhalb TEDinfos reolzieren *)'); 
    WriteLn(f,'TedInfoAddr := POINTER(LONGINT',' (RSDATA)+LONGINT(xTEds));'); 
    WriteLn(f,'  FOR i := 0 TO nTeds - 1 DO '); 
    WriteLn(f,'   WITH TedInfoAddr^[i] DO BEGIN'); 
    WriteLn(f,'     validPtr := POINTER(LONGINT','(validPtr)+LONGINT(RSDATA));'); 
    WriteLn(f,'     tmpltPtr := POINTER(LONGINT','(tmpltPtr)+LONGINT(RSDATA));'); 
    WriteLn(f,'     textPtr = POINTER(LONGINT' ,'(textPtr)+LONGINT(RSDATA));');
    WriteLn(f,'     END;');
END;

IF nIcons <> 0 THEN BEGIN 
    WriteLn(f,' (* Adressen in IconBlocks relozieren *)'); 
    WriteLn(f,'  IconBlkAddr = POINTER(LONGINT','(RSDATA)+LONGINT(xIcons));'); 
    WriteLn(f,'  FOR i = 0 TO nIcons - 1 DO '); 
    WriteLn(f,'  WITH IconBlkAddr^[i] DO BEGIN'); 
    WriteLn(f,'   data = POINTER(LONGINT(data)+','LONGINT(RSDATA));') 
    WriteLn(f,'   mask = POINTER(LONGINT(mask)+ ','LONGINT(RSDATA));'); 
    WriteLn(f,'   txt  = POINTER(LONGINT(txt)+','LONGINT(RSDATA));');
    WriteLn(f,'  END;');
END;

IF nBitBlk <> 0 THEN BEGIN 
    WriteLn(f);
    WriteLn(f,'(* Adressen in BitBlocks relozieren *)'); 
    WriteLn(f,'  BitBlkAddr = POINTER(LONGINT','(RSDATA)+LONGINT(xBits));'): 
    WriteLn(f,'  FOR i := 0 TO nBits - 1 DO '); 
    WriteLn(f,'   WITH BitBlkAddr*[i] DO')
    WriteLn(f,'    data = POINTER(LONGINT(data)','+LONGINT(RSDATA));');
END;

IF nObjects <> 0 THEN BEGIN 
    WriteLn(f);
    WriteLn(f,'(* Object-Specs relozieren, falls notwendig *)'); 
    WriteLn(f,'  ObjectAddr := POINTER(LONGINT','(RSDATA)+LONGINT(xObjects));'); 
    WriteLn(f,'  FOR i = 0 TO nObjects-1 DO BEGIN'); 
    WriteLn(f,'  WITH ObjectAddr^[i] DO BEGIN'); 
    WriteLn(f,'   IF (typ <> GBOX) AND ','(typ <> GIBOX) AND'); 
    WriteLn(f,'     (typ <> USERBLK) AND'):
    WriteLn(f,'     (typ <> GBOXCHAR) THEN');
    WriteLn(f,'     spec.more := POINTER(LONGINT','(spec.more)+LONGINT(RSDATA));'); 
    WriteLn(f,'     chW := 8; chH := 16;');
    WriteLn(f,'     rezol := GetRez;');
    WriteLn(f,'     IF rezol < 2 THEN chH := 8,'); 
    WriteLn(f,'     WITH space DO BEGIN');
    WriteLn(f,'      y:=(y MOD 256) * chH +','(y DIV 256);'); 
    WriteLn(f,'      x:=(x MOD 256) * chW +','(x DIV 256);'); 
    WriteLn(f,'      h:=(h MOD 256) * chH +','(h DIV 256);'); 
    WriteLn(f,'      w:=(w MOD 256) * chW +','(w DIV 256);');

    WriteLn(f,'   END;');
    WriteLn(f,'  END;').
    WriteLn(f,' END;');
END;

IF nFreeStr <> 0 THEN BEGIN 
    WriteLn(f,'(* Addressen der freien Strings relozieren *)'); 
    WriteLn(f,' StringAddr := POINTER(LONGINT','(RSDATA)+LONGINT(xFreeStr));'); 
    WriteLn(f,'  FOR i := 0 TO nFreeStr - 1 DO'); 
    WriteLn(f,'   StringAddr^[i] := POINTER(LONGINT','(StringAddr^[i])+LONGINT(RSDATA));');
END;

IF nFreeImg <> 0 THEN BEGIN 
    WriteLn(f,'(* Adressen der Freeimages relozieren *)'); 
    WriteLn(f,' ImgAddr := POINTER(LONGINT(RSDATA)+','LONGINT(xFreeImg));'); 
    WriteLn(f,' FOR i := 0 TO nFreeImg - 1 DO'); 
    WriteLn(f,' ImgAddr^[i] := POINTER(LONGINT','(ImgAddr^[i])+LONGINT(RSDATA));');
END;

END (* MachPgm *);

(************************************************ 
  weils oben auch so aussieht
*************************************************)

PROCEDURE MachImpEnde,
BEGIN
WriteLn(f,'END.');
END (* MachImpEnde *);

(************************************************ 
  Datei schließen
************************************************)

PROCEDURE DateiSchliessen;
BEGIN 
    Close(f);
END (* DateiSchliessen *);

BEGIN (************ Hauptprogramm ***************)

    InitGem(RC,handle,ok),
            (* notwendig wegen F.Selektor-Box *)
    IF ok THEN BEGIN
        IF GemError = 0 THEN BEGIN 
            iconsdnn := FALSE; 
            but := 1;
            REPEAT
                IF RscFileRead THEN BEGIN
                                (* RSC-Datei aussuchen *)
                    IF DateiOeffnen THEN BEGIN;
                                    (* und ggfs einlesen   *)
                        MachDefKopf;
                            (* Kopf Interfaceteil erzeugen *)
                        MachDefConst;  (* Konstanten eintragen*) 
                        MachTypes;
                        MachDefVars;   (* Variablen eintragen *)
                        MachImpKopf;   (* Kopf Impl. erzeugen *)
                        MachImpConst;  (* Konstanten eintragen*)
                        MachImpVars;   (* Variablen hinzufugen*)
                        MachASCIIausHex;
                            (* RSC-Datei als INLINE-Proz.     *)
                        MachPgm;  (* das eigentliche Programm *) 
                        MachImpEnde;  (* Impl.Teil schließen  *) 
                        DateiSchliessen;
                    END
                    ELSE
                        FormAlert(1,'[3][Ausgabedatei läßt sich|nicht öffnen][Pech]',but)
                END
                ELSE
                    FormAlert(1,'[3][Fehler bei der|Eingabe][Abbruch|nochmal]',but);

            UNTIL but = 1; (* abbruch *)
        END;
        ExitGem(handle);
    END;
END (* RSCMkPas *) .

(***********************************************)

(************************************************
*                                               *  
*             Listing 2                         *
*                                               *  
* Die vom RSC-Maker erzeugte Unit.              *
*                                               *  
* Keine Angst, diesen Text brauchen Sie nicht   *
* einzutippen!                                  *
* Das erledigt der RSC-Maker für Sie!           *
*                                               *  
* Das Listing wurde mit Hand nachbearbeitet, um *
* die Zusammenhänge zu verdeutlichen und um die *
* Vorgabe, 49 Zeichen pro Zeile, einzuhalten    *
*                                               *  
************************************************)

Unit RSMTEST;

(* Erzeugt vom Ressourcemacher 1.01 *)
(* B.Volkmer, 1991 *)

(* Version des RessourceFiles : $0001 *)
(*$F+*)
INTERFACE

Uses Gem, Bios;
                (* Gem-Unit auf Diskette *)
                (* darin nur Typdeklarationen *)

CONST
    nObjects =   5;
    nTrees   =   1;
    nTeds    =   1;
    xObjects =  94;
    xTrees   = 214;
    xTEds    =  66;

TYPE
    TreeArray    = ARRAY[0..nTrees]     OF POINTER;
    TedInfoArray = ARRAY[0..nTeds]      OF TEdInfo;
    ObjAddrArray = ARRAY[0..nObjects]   OF Object;


VAR
    TreeAddr    : ^TreeArray;
    TedInfoAddr : ^TedInfoArray;
    ObjectAddr  : ^ObjAddrArray;

IMPLEMENTATION

CONST
    GBOX  = 20; USERBLK  = 24;
    GIBOX = 25; GBOXCHAR = 27;

VAR
    i               : INTEGER;
    chW,chH,rezol   : INTEGER;
    RSDATA          : POINTER;

VAR rsdta : POINTER;
PROCEDURE rscdata;
    ASSEMBLER;
    ASM
        LEA  @start,A0 
        MOVE.L A0,rsdta 
        BRA  @fertig 
@start:
        DC.W $0001          (* Version              *)
        DC.W $005E          (* Zeiger auf 1. Objekt *)
        DC.W $0042          (* zeigt auf 1. TEDINFO *)
        DC.W $005E          (* A auf 1. IconBlock,  *)
        DC.W $0042,$0042    (* BitBl. und fr. Strings*)
        DC.W $0024          (* zeigt auf 1. String  *)
        DC.W $0042,$0042    (* Image, freie Image, nix*)
        DC.W $00D6          (* Zeiger auf Baumadressen*)
        DC.W $0005          (* Anzahl der Objekte   *)
        DC.W $0001          (* Anzahl der Baume     *)
        DC.W $0001          (* Anzahl der TEDINFOs  *)
        DC.W $0000,$0000,$0000,$0000 (* Rest,nix    *)
        DC.W $00DA          (* Länge der RSC-Datei  *)

                            (* Text "Hallo Atari"   *)
        (* 24 *) DC.W $4861,$6C6C,$6F20,$4174H 
                 DC.W $6172,$6900

        (* 30 *) DC.B $00               (* Maske    *)
        (* 31 *) DC.B $00               (* Valid    *)
        (* 32 *) DC.W $4B6E,$6F70,$6620,$3100
                                        (* "Knopf 1"*)
        (* 3A *) DC.W $4B6E,$6F70,$6620,$3200
                            (* "Knopf 2"*)

        (* TEDINFO *)

        (* 42 *) DC.W $0000,$0024   (* Zeiger Text  *)
                 DC.W $0000.$0030   (* Zeiger Maske *)
                 DC.W $0000,$0031   (* Zeiger Valid *)
                 DC.W $0003         (* Font IBM     *)
                 DC.W $0006         (* reserviert   *)
                 DC.W $0000         (* Just. links  *)
                 DC.W $1180         (* Farbe        *)
                 DC.W $0000         (* reserviert   *)
                 DC.W $FFFC (* Rahmendicke -4,außen *) 
                 DC.W $000C         (* Länge Text,12*)
                 DC.W $0001         (* Länge Maske,1*)

        (* 1. Objekt beginnt bei 5E *)
                (* next, head, tail *)

        (* 5E *) DC.W $FFFF,$0001,$0002
                 DC.W $0014        (* Typ 20 = G_BOX*)
                 DC.W $0000,$0010     (* flag, state*)
                 DC.W $0002,$1100            (* spec*)
                 DC W $0001,$0001,$0017, $0006
                                              (*Maße*)

        (* 76 *) DC.W $0002,$FFFF,$FFFFH
                 DC.W $0016   (* Typ 22 = G_BOXTEXT *)
                 DC.W $0000,$0030   (* flags, state *)
                 DC.W $0000,$0042    (* Adr Tedlnfo *)
                 DC.W $0006,$0001,$000B,$0001H

        (* 8E *) DC.W $0000,$0003,$0004
                 DC.W $0019      (* Typ 25 = G_IBOX *)
                 DC.W $0000,$0000    (* flags,state *)
                 DC.W $0001,$1100           (* spec *)
                 DC.W $0001,$0003,$0015,$0802

        (* A6 *) DC.W $0004,$FFFF,$FFFF
                 DC.W $001A    (* Typ 26 = G_BUTTON *)
                 DC.W $0017,$0000   (* flags, state *)
                 DC.W $0000,$0032     (* Stringadr. *)
                 DC.W $0001,$0001,$0009,$0001

        (* BE *) DC.W $0002,$FFFF,$FFFF
                 DC.W $001A    (* Typ 26 = G_BUTTON *)
                 DC.W $0035,$0000   (* flags, state *)
                 DC.W $0000,$003A     (* Stringadr. *)
                 DC.W $000B,$0001,$0009,$0001

        (* D6 *) DC.W $0000,$005E   (*^auf 1. Objekt *) 
@fertig:
END;


BEGIN                   (***** Hauptprogramm ********)
    rscdata;               (* rsdata bekannt machen *)
(* Liste der Objektbaum-Adressen relozieren *) 
    RSDATA := rsdta;
    TreeAddr := POINTER(LONGINT(RSDATA)+LONGINT(xTrees)); 
    FOR i := 0 TO nTrees-1 DO 
        TreeAddr^[i]:= POINTER(LONGINT(TreeAddr^[i])+LONGINT(RSDATA)); 
(* Adressen innerhalb der TEDinfos reolzieren *) 
TedInfoAddr = POINTER(LONGINT(RSDATA)+LONGINT(xTEds));
    FOR i := 0 TO nTeds - 1 DO 
        WITH TedInfoAddr^[i] DO BEGIN
            validPtr := POINTER(LONGINT(validPtr)+LONGINT(RSDATA)); 
            tmpltPtr := POINTER(LONGINT(tmpltPtr)+LONGINT(RSDATA)); 
            textPtr  := POINTER(LONGINT(textPtr)+LONGINT(RSDATA));
        END;

(* Object-Specs relozieren, falls notwendig *)
    ObjectAddr = POINTER(LONGINT(RSDATA)+LONGINT(xObjects)); 
    FOR i := 0 TO nObjects-1 DO BEGIN
        WITH ObjectAddrA(i] DO BEGIN 
            IF (typ <> GBOX) AND (typ <> GIBOX) AND (typ <> USERBLK) AND (typ <> GBOXCHAR) THEN
                spec.more := POINTER(LONGINT(spec.more)+LONGINT(RSDATA));

            chW = 8; chH := 16; 
            rezol := GetRez;
            IF rezol < 2 THEN chH := 8;
            WITH space DO BEGIN
                y:=(y MOD 256) * chH + (y DIV 256);
                x:=(x MOD 256) * chW + (x DIV 256);
                h:=(h MOD 256) * chH + (h DIV 256);
                w:=(w MOD 256) * chW + (w DIV 256);
            END;
        END;
    END;
END.

(***********************************************)

(************************************************
*                   Listing 3                   *
* kleines Beispielprogramm zum Testen des       *
* RSCMaker - Ergebnisses                        *
************************************************)


PROGRAM RsmBeispiel;

USES VDI, AES, GEM, GrafBase, RSMTEST;

(* Die Konstantendatei des RSC-Editors wird hier 
   der Übersichtlichkeit wegen gleich eingefügt *)

CONST
    Rsmdial = 0, (* Formular/Dialog *)
    Rsmtext = 1; (* BOXTEXT in Baum RSMDIAL *)
    Rsmkn1  = 3; (* BUTTON in Baum RSMDIAL *)
    Rsmkn2  = 4; (* BUTTON in Baum RSMDIAL *)

VAR
    handle  : INTEGER; 
    ok      : BOOLEAN;
    baum    : PtrObjTree; 
    ecke    : Rectangle;
    Button  : INTEGER;

BEGIN
    InitGem(RC,handle,ok);
    IF ok THEN BEGIN
        IF GemError = 0 THEN BEGIN 
            baum := TreeAddr^[Rsmdial];
            FormCenter(baum, ecke);
            FormDial(reserveForm,ecke,ecke);
            DrawObject(baum,0,8,ecke);
            FormDo(baum,0,Button);
            FormDial(freeForm,ecke,ecke);
        END;
        ExitGem(handle);
    END;
END (* RsmBeispiel *) 

(***********************************************)


Bruno Volkmer
Aus: ST-Computer 12 / 1991, Seite 144

Links

Copyright-Bestimmungen: siehe Über diese Seite