MODULE DD2BIN; (* Title : DD2BIN.MOD LastEdit: 11/04/88 Author : Kim Moser System : JPI's TopSpeed Modula-2 with PMI's Repertoire 1.5c Descrip : Displays C-64 Doodle file in IBM EGA 200x320 16-color mode Usage : DD2BIN 320x200|640x200 | (640x350 [H])) File name may include wildcards. EGA mode must be either '640x350' or '640x200' or '320x200'. 'H' indicates that picture should be half-size (i.e. 1:1 pixel ratio, but fits in corner of screen). Note that 640x350 is the only mode that can be 'halfed'. 12/23/88: Added line in initialization to set C64ColorMap[0] to CHR(0); This wasn't done before, resulting in black being mapped to a random color. *) (* JPI *) FROM SYSTEM IMPORT SIZE, ADR, BYTE, WORD, Out; FROM IO IMPORT WrStr, WrLn; (* Repertoire *) IMPORT InitJPI; FROM Drectory IMPORT FileInfoRec, FindFirstFile, FindNextFile; FROM FileIO IMPORT OpenFile, SetFilePtr, BlockRead, CloseHandle, FileExists, CreateFile, BlockWrite, FileOffSet; FROM StringIO IMPORT ErrorMessage; FROM EnvironUtils IMPORT ParsedParam; FROM SmartScreen IMPORT ScreenMode, ScreenModeType, ScreenModeNow; FROM LowLevel IMPORT ShiftLeft, ShiftRight, Fill; FROM StrEdit IMPORT AssignStr, Append, SetLength; FROM M2Strings IMPORT CompareStr, Pos; FROM KbdInput IMPORT KeyHit, AnyKeyNum; (* For speed: *) (*$I-,O-,R-,S-,Z-*) CONST Escape = 27; (* Ordinal value of escape key *) TYPE bits = RECORD (* For easy conversion between data types *) (* All fields occupy the same 16 bits of storage *) CASE a: CARDINAL OF 1: b1: BYTE; b2: BYTE; | 2: ch1: CHAR; ch2: CHAR; | 3: s: SET OF [0..15]; | 4: c: CARDINAL; | 5: w: WORD; | 6: b: BITSET; END; END; (* TYPEs for EGA plot/peek routines: *) tinyint = [0..7]; bs = SET OF tinyint; bp = POINTER TO bs; VAR (* MAIN *) VidSeg: CARDINAL; SaveRequested: BOOLEAN; HalfRequested: BOOLEAN; RequestedMode: ScreenModeType; (* What mode requested *) Planes: CARDINAL; (* 0=b/w, 3=color *) (* These vars are set according to the requested mode: *) EGAwidth, EGAdepth: CARDINAL; BPR: CARDINAL; (* Bytes-per-row in EGA mode; 40 = 200x320, 80 = all others *) multX, multY: CARDINAL; (* What to multiply x and y by *) incX, incY: CARDINAL; SideToSide, TopToBottom: BOOLEAN; (* Whether pixels should be put next to each other, and on top of each other when plotting *) OldScreenMode: ScreenModeType; DoodleFileSpec: ARRAY [0..79] OF CHAR; (* Arbitrary length *) InfoRec: FileInfoRec; DoodleColorBuffer: ARRAY [0..24],[0..39] OF BYTE; (* Color buffer *) (* Assumes arrays are mapped by row *) DoodlePicBuffer: ARRAY [0..24],[0..39],[0..7] OF BYTE; (* Picture buffer *) (* Assumes arrays are mapped by row *) C64ColorMap: ARRAY [0..15] OF CHAR; (***************************************************************************** I/O procedures: *****************************************************************************) PROCEDURE WrStrLn( s: ARRAY OF CHAR ); BEGIN WrStr( s ); WrLn(); END WrStrLn; PROCEDURE Usage(); BEGIN WrStrLn( 'DD2BIN v1.0 Copyright (c) 1988 Kim Moser All Rights Reserved' ); WrStrLn( 'Displays C-64 Doodle file in EGA mode specified.' ); WrLn(); WrStrLn( 'Usage: DD2BIN 320x200|640x200 | (640x350 [H]))' ); END Usage; PROCEDURE Warn( s: ARRAY OF CHAR ); (* Warn user with message 's' *) BEGIN ScreenMode( OldScreenMode ); (* Restore old screen mode *) WrStr( 'DD2BIN: ' ); WrStrLn( s ); END Warn; (***************************************************************************** Graphics procedures: *****************************************************************************) PROCEDURE HitAnyKey(): CARDINAL; VAR BEGIN RETURN KeyHit( AnyKeyNum ); END HitAnyKey; PROCEDURE Dot( x,y,c : CARDINAL); (* Also VGA *) (* CONST EGAWidth=320; Depth=200; *) VAR t:bs; p,b (*,s*):CARDINAL; BEGIN (* IF (x < EGAWidth) AND (y < Depth) THEN *) b := 1 << (7-(x MOD 8)); p := y*BPR+(x DIV 8); Out( 3CEH,8); Out( 3CFH,SHORTCARD(b)); Out( 3C4H,2);Out( 3C5H,0FH); (* s := 0A000H; *) t := [VidSeg:p bp]^; [VidSeg:p bp]^ := bs{}; Out( 3C4H,2) ;Out( 3C5H,SHORTCARD(c)); [VidSeg:p bp]^ := bs{0..7}; Out( 3CEH,8);Out( 3CFH,0FFH); Out( 3C4H,2);Out( 3C5H,0FH); (* END; *) END Dot; PROCEDURE SelectPlane( p: CARDINAL ); (* Selects EGA plane 'p' [assumes 0<=p<=3] *) BEGIN Out( 3CEH, 4 ); (* read map sel *) Out( 3CFH, SHORTCARD(p) ); END SelectPlane; PROCEDURE Save(): BOOLEAN; (* Returns TRUE if successfully saved, else FALSE *) VAR f: CARDINAL; p: CARDINAL; SaveFileName, msg: ARRAY [0..80] OF CHAR; PROCEDURE CloseFile(); BEGIN IF CloseHandle( f ) <> NoError THEN END; END CloseFile; BEGIN (*J9 9 9 9 9 999999999'99999999 9!9"9#9$9%9&9<9:9;99=9>9?9@9A9B9C9D9E9F9G9H9I9J9K9L9M9N9O9P9Q9R9S9T9U9V9W9X9Y9Z9[9\9]9^9_9`9a9b9c9d9e9f9g9h9i9j9k9l9m9n9o9p9q9r9s9t9u9v9w9x9y9z9{9|9}9~99999999999999999999999999999999999999999999999999999999999:999999999999999999999999:d::::: : : : :::::::::::::::: :!:":#:$:%:&:':(:):*:+:,:-:.:/:0:1:2:3:4:5:6:7:8:9:;:<:=:>:?:@:A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q:R:S:T:U:V:W:X:Y:Z:[:\:]:^:_:`:a:b:c:d:e:f:g:h:i:j:l:m:n:o:p:q:r:s:t:w:v:x:y:z:{:|:}:~::::::::::3;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;; ;;;;;;;;;;;;;;; ;!;";#;$;%;';(;);*;.;2;4;5;6;;9;:;;;<;=;>;?;@;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;W;X;Y;Z;[;\;];^;_;`;a;b;d;e;f;g;h;i;j;k;l;m;n;q;r;t;v;x;y;{;|;};;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<<<<*<<<<<<< <"<}D#<$<%<&<'<(<)<<<=<>>>>>>>>> > > > > >>>>>>>>>>>>>>>>>>> >!>">#>$>%>&>'>(>)>*>+>,>->.>/>0>1>2>3>4>5>6>7>8>9>:>;><>=>>>?>@>A>B>C>D>E>F>G>H>I>J>K>z>{>|>}>~>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????? ? ? ? ? ??????????????????? ?!?"?#?$?%?&?'?(?)?*?+?,?-?.?/?0?1?2?3?4?5?6?7?9?:?;????@?A?B?C?D?E?F?G?H?I?J?K?L?M?N?O?P?Q?R?S?T?U?V?W?X?Y?Z?[?\?]?^?_?`?a?b?c?d?e?f?g?h?i?j?k?l?m?n?o?p?q?r?t?u?v?w?x?y?z?{?|?}?~????????????????????????????????????????????????????????????????????????????????????????????????????G@@@@@@@ @ @ @@ @@@@@@@@@@@@@@@@@ @!@"@#@$@%@&@'@(@)@*@+@,@-@.@/@0@1@2@3@4@5@6@7@8@9@:@;@<@=@>@?@@@A@B@C@D@E@F@G@H@I@J@K@L@M@N@O@P@Q@R@S@T@U@V@W@X@Y@Z@[@\@]@^@_@jF color *) Warn( 'Unable to read color (possibly non-Doodle file).' ); CloseFile(); RETURN FALSE; END; SetFilePtr( f, FromCurrent, VAL(LONGINT,24) ); (* Skip load address *) IF BlockRead( f, ADR(DoodlePicBuffer), SIZE(DoodlePicBuffer) ) <> NoError THEN; (* Read pic *) Warn( 'Unable to read picture (possibly non-Doodle file).' ); CloseFile(); RETURN FALSE; END; CloseFile(); RETURN TRUE; END ReadFile; (*******************************************************G!B"B#B$B%B&B'B(B)B*B+B,B-B.BuBvBwBxByB|B}B~BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCHCCCCCCACCCCCC 0 TO 7 DO (* Process all pixels per 'line' *) IF ((7-x) IN b.s) THEN (* Use foreground color *) PixelColor := ForeColor; ELSE (* Use background color *) PixelColor := BackColor; END; ColorCard := ORD( C64ColorMap[ORD(PixelColor)] ); Dot( theX, theY, ColorCard ); IF SideToSide THEN (* Plot them side-by side *) Dot( theX+1, theY, ColorCard ); END; IF NOT ( (RequestedMode=EGA64color) AND (NOT HalfRequested) AND (((Row*8+y+1+1) MOD 4)=0) ) THEN IF TopToBottom THEN (* Plot them top-to-bottom *) Dot( theX, theY+1, ColorCard ); END; IF SideToSide AND TopToBottom THEN Dot( theX+1, theY+1, ColorCard ); END; END; INC( theX, incX ); END; END; END; END; (* Out( 3CEH,8);Out( 3CFH,0FFH); Out( 3C4H,2);Out( 3C5H,0FH); *) END DoEGA; PROCEDURE Init(); VAR i: CARDINAL; BEGIN (* Initialize: *) (* Normal colors: # C64 IBM IBM equivalent -- ----- ----- -------------- 0 black black 0 + 1 white blue 15 2 red green 4 3 cyan cyan 3 4 purple red 5 5 green magenta 2 6 blue brown 1 7 yellow light grey 14 8 orange dark grey 12 & 9 brown light blue 6 10 light red (pink) light green 12 & 11 gray 1 light cyan 0 + 12 gray 2 light red 7 % 13 light green light magenta 10 14 light blue yellow 9 15 gray 3 bright white 7 % *) (* (* Init default C64 color map: *) FOR i := 0 TO 15 DO C64ColorMap[i] := CHR(i); END; *) C64ColorMap[0] := CHR(0); C64ColorMap[1] := CHR(15); C64ColorMap[2] := CHR(4); C64ColorMap[3] := CHR(3); C64ColorMap[4] := CHR(5); C64ColorMap[5] := CHR(2); C64ColorMap[6] := CHR(1); C64ColorMap[7] := CHR(14); C64ColorMap[8] := CHR(12); C64ColorMap[9] := CHR(6); C64ColorMap[10] := CHR(12); C64ColorMap[11] := CHR(0); (*8 *) C64ColorMap[12] := CHR(7); C64ColorMap[13] := CHR(10); C64ColorMap[14] := CHR(9); C64ColorMap[15] := CHR(7); OldScreenMode := ScreenModeNow; (* Save screen mode *) SaveRequested := FALSE; (* Default *) HalfRequested := FALSE; (* Default *) VidSeg := 0A000H; SetRequestedMode( EGA320 ); (* Default *) END Init; PROCEDURE ParseParams(): BOOLEAN; (* Returns TRUE if all params okay, else FALSE *) VAR param2, param3, DumStr: ARRAY [0..80] OF CHAR; i: CARDINAL; BEGIN IF NOT ( ParsedParam(1,DoodleFileSpec) AND ParsedParam(2,param2) ) THEN (* Filespec and mode not specified *) RETURN FALSE; END; IF CompareStr( param2, '640x200' )=0 THEN SetRequestedMode( EGA640 ); ELSIF CompareStr( param2, '320x200' )=0 THEN SetRequestedMode( EGA320 ); ELSIF CompareStr( param2, '640x350' )=0 THEN SetRequestedMode( EGA64color ); ELSE (* Bad video mode *) RETURN FALSE; END; HalfRequested := ( ParsedParam( 3, param3 ) AND (CAP(param3[0])='H') ); IF HalfRequested THEN i := 4; (* Next parameter to look for *) IF (CompareStr(param2,'640x350')=0) THEN (* Half requested, so set appropriate stuff: *) incX := 1; incY := 1; multX := 1; multY := 1; SideToSide := FALSE; TopToBottom := FALSE; ELSE (* Half requested, but mode requested was not 640x350 *) RETURN FALSE; END; ELSE i := 3; (* Next parameter to look for *) END; SaveRequested := ( ParsedParam(i,DumStr) AND (CAP(DumStr[0])='S') ); Planes := 3; (* Default: Color *) IF SaveRequested AND ParsedParam(i+1,DumStr) THEN IF ( CAP(DumStr[0]) = 'B' ) THEN Planes := 0; ELSE RETURN FALSE; END; END; RETURN TRUE; END ParseParams; PROCEDURE ClearPage(); VAR p: CARDINAL; BEGIN FOR p := 0 TO 3 DO (* Clear all planes *) SelectPlane( p ); Fill( [VidSeg:0], BPR*EGAdepth, BYTE(0) ); END; END ClearPage; BEGIN (* MAIN *) Init(); IF NOT ParseParams() THEN Usage(); ELSE IF FindFirstFile( DoodleFileSpec, InfoRec ) = NoMoreFiles THEN Warn( 'Unable to find C-64 file.' ); RETURN; END; LOOP (* Process all files *) IF NOT ReadFile() THEN (* If this happens, it means that ReadFile() encountered a non-Doodle file, or had some other problem reading the file. The file SHOULD exist, though, since FindFirstFile() and FindNextFile() makes sure it does. *) EXIT; END; ScreenMode( RequestedMode ); DoEGA(); IF SaveRequested AND Save() THEN END; CASE HitAnyKey() OF Escape, ORD('q'), ORD('Q'): EXIT; ELSE (* Do nothing *) END; ClearPage(); IF FindNextFile( InfoRec ) = NoMoreFiles THEN EXIT END; END; ScreenMode( OldScreenMode ); (* Restore old screen mode *) END; END DD2BIN.