Browse Source

DOS-like fullscreen aspect ratio 5:6; Graph settings refactored

Arthur Yefimov 3 years ago
parent
commit
d438706b05
5 changed files with 139 additions and 158 deletions
  1. 0 1
      src/FreeOberon.Mod
  2. 98 128
      src/Graph.Mod
  3. 3 1
      src/SDL2.Mod
  4. 4 0
      src/SDL2.h0
  5. 34 28
      src/Terminal.Mod

+ 0 - 1
src/FreeOberon.Mod

@@ -1070,7 +1070,6 @@ VAR success, fs, sw: BOOLEAN;
 BEGIN
 BEGIN
   success := FALSE;
   success := FALSE;
   ParseArgs(fs, sw, w, h, fnames);
   ParseArgs(fs, sw, w, h, fnames);
-  ;Out.String('SIZE '); Out.Int(w, 0); Out.Int(h, 5); Out.Ln;
   IF T.Init(fs, sw, w, h) THEN
   IF T.Init(fs, sw, w, h) THEN
     InitIDE;
     InitIDE;
     needWindowed := TRUE;
     needWindowed := TRUE;

+ 98 - 128
src/Graph.Mod

@@ -29,13 +29,15 @@ CONST
   drawSpriteLit*    = 1;
   drawSpriteLit*    = 1;
   drawSpriteTrans*  = 2;
   drawSpriteTrans*  = 2;
 
 
-  (* Settings *)
+  (* Settings, see global varialbe settings *)
   fullscreen*  = 0;
   fullscreen*  = 0;
   buffered*    = 1;
   buffered*    = 1;
   spread*      = 2;
   spread*      = 2;
   sharpPixels* = 3;
   sharpPixels* = 3;
   software*    = 4;
   software*    = 4;
   initMouse*   = 8;
   initMouse*   = 8;
+  noPng* = 11;
+  noJpg* = 12;
 
 
   (* Event Types *)
   (* Event Types *)
   quit*        = 1;
   quit*        = 1;
@@ -246,11 +248,10 @@ VAR
   events: EventQueue;
   events: EventQueue;
   keyPressed: INTEGER;
   keyPressed: INTEGER;
 
 
+  settings, initSettings: SET; (* See constants above *)
   sizeStepX, sizeStepY: INTEGER;
   sizeStepX, sizeStepY: INTEGER;
-  wantW, wantH: INTEGER;
-  wantFullscreen, wantBuffer, wantSpread: BOOLEAN;
-  wantSharpPixels, wantSoftware: BOOLEAN;
-  wantMouse: BOOLEAN;
+  scaleX, scaleY: REAL;
+  scrW, scrH: INTEGER;
   wantFPS: INTEGER;
   wantFPS: INTEGER;
   buffer: Bitmap;
   buffer: Bitmap;
   lastFlip: INTEGER;
   lastFlip: INTEGER;
@@ -279,51 +280,41 @@ PROCEDURE -AAIncludeSDL2h0 '#include "SDL2.h0"';
 PROCEDURE GetError*(VAR s: ARRAY OF CHAR);
 PROCEDURE GetError*(VAR s: ARRAY OF CHAR);
 TYPE P = POINTER TO ARRAY 10240 OF CHAR;
 TYPE P = POINTER TO ARRAY 10240 OF CHAR;
 VAR p: P;
 VAR p: P;
-BEGIN
-  p := SYSTEM.VAL(P, SDL.GetError());
-  s := p^$
+BEGIN p := SYSTEM.VAL(P, SDL.GetError()); s := p^$
 END GetError;
 END GetError;
 
 
 PROCEDURE Settings*(w, h: INTEGER; flags: SET);
 PROCEDURE Settings*(w, h: INTEGER; flags: SET);
-BEGIN (*!TODO: Refactor, save options in a SET?*)
-  wantW := w; wantH := h;
-  wantFullscreen := fullscreen IN flags;
-  wantBuffer := buffered IN flags;
-  wantSpread := spread IN flags;
-  wantSharpPixels := sharpPixels IN flags;
-  wantSoftware := software IN flags;
-  wantMouse := initMouse IN flags;
-  showMouse := wantMouse
+BEGIN scrW := w; scrH := h;
+  initSettings := flags;
+  showMouse := initMouse IN flags
 END Settings;
 END Settings;
 
 
 PROCEDURE SetSizeStep*(w, h: INTEGER);
 PROCEDURE SetSizeStep*(w, h: INTEGER);
-BEGIN
-  sizeStepX := w; sizeStepY := h
+BEGIN sizeStepX := w; sizeStepY := h
 END SetSizeStep;
 END SetSizeStep;
 
 
-PROCEDURE SetFPS*(fps: INTEGER);
+PROCEDURE ApplyScale;
 BEGIN
 BEGIN
-  IF fps <= 0 THEN fps := -1 END;
+  SDL.RenderSetLogicalSize(renderer,
+    SHORT(ENTIER(scrW * scaleX)), SHORT(ENTIER(scrH * scaleY)));
+END ApplyScale;
+
+PROCEDURE SetScale*(x, y: REAL);
+BEGIN scaleX := x; scaleY := y;
+  IF renderer # 0 THEN ApplyScale END
+END SetScale;
+
+PROCEDURE SetFPS*(fps: INTEGER);
+BEGIN IF fps <= 0 THEN fps := -1 END;
   wantFPS := fps
   wantFPS := fps
 END SetFPS;
 END SetFPS;
 
 
 PROCEDURE GetDesktopResolution*(VAR w, h: INTEGER);
 PROCEDURE GetDesktopResolution*(VAR w, h: INTEGER);
 VAR mode: SDL.DisplayMode;
 VAR mode: SDL.DisplayMode;
-BEGIN
-  SDL.GetDesktopDisplayMode(0, mode);
+BEGIN SDL.GetDesktopDisplayMode(0, mode);
   w := mode.w; h := mode.h
   w := mode.w; h := mode.h
 END GetDesktopResolution;
 END GetDesktopResolution;
 
 
-PROCEDURE CheckWantedScreenSize;
-BEGIN
-  IF (wantW = -1) OR (wantH = -1) THEN
-    GetDesktopResolution(wantW, wantH);
-    IF ~wantFullscreen THEN
-      DEC(wantW, 20); DEC(wantH, 50)
-    END
-  END
-END CheckWantedScreenSize;
-
 (* Flip Region *)
 (* Flip Region *)
 PROCEDURE SetRegion*(x, y, w, h: INTEGER);
 PROCEDURE SetRegion*(x, y, w, h: INTEGER);
 BEGIN
 BEGIN
@@ -332,8 +323,7 @@ BEGIN
 END SetRegion;
 END SetRegion;
 
 
 PROCEDURE UnsetRegion*;
 PROCEDURE UnsetRegion*;
-BEGIN
-  flipRegion.w := -1
+BEGIN flipRegion.w := -1
 END UnsetRegion;
 END UnsetRegion;
 
 
 PROCEDURE AddRegion*(x, y, w, h: INTEGER);
 PROCEDURE AddRegion*(x, y, w, h: INTEGER);
@@ -371,33 +361,27 @@ BEGIN RETURN SDL.MapRGB(bmp.surface.format, SHORT(r), SHORT(g), SHORT(b))
 END BmpCol;
 END BmpCol;
 
 
 PROCEDURE ClearToColor*(bmp: Bitmap; color: INTEGER);
 PROCEDURE ClearToColor*(bmp: Bitmap; color: INTEGER);
-BEGIN
-  SDL.FillRectNil(bmp.surface, color)
+BEGIN SDL.FillRectNil(bmp.surface, color)
 END ClearToColor;
 END ClearToColor;
 
 
 PROCEDURE ClearBitmap*(bmp: Bitmap);
 PROCEDURE ClearBitmap*(bmp: Bitmap);
-BEGIN
-  ClearToColor(bmp, MakeCol(0, 0, 0))
+BEGIN ClearToColor(bmp, MakeCol(0, 0, 0))
 END ClearBitmap;
 END ClearBitmap;
 
 
 PROCEDURE ClearScreenToColor*(color: INTEGER);
 PROCEDURE ClearScreenToColor*(color: INTEGER);
-BEGIN
-  ClearToColor(screen, color)
+BEGIN ClearToColor(screen, color)
 END ClearScreenToColor;
 END ClearScreenToColor;
 
 
 PROCEDURE ClearScreen*;
 PROCEDURE ClearScreen*;
-BEGIN
-  ClearToColor(screen, MakeCol(0, 0, 0))
+BEGIN ClearToColor(screen, MakeCol(0, 0, 0))
 END ClearScreen;
 END ClearScreen;
 
 
 PROCEDURE LockBitmap*(bmp: Bitmap);
 PROCEDURE LockBitmap*(bmp: Bitmap);
-BEGIN
-  SDL.LockSurface(bmp.surface)
+BEGIN SDL.LockSurface(bmp.surface)
 END LockBitmap;
 END LockBitmap;
 
 
 PROCEDURE UnlockBitmap*(bmp: Bitmap);
 PROCEDURE UnlockBitmap*(bmp: Bitmap);
-BEGIN
-  SDL.UnlockSurface(bmp.surface)
+BEGIN SDL.UnlockSurface(bmp.surface)
 END UnlockBitmap;
 END UnlockBitmap;
 
 
 PROCEDURE PutPixelFast*(bmp: Bitmap; x, y, color: INTEGER);
 PROCEDURE PutPixelFast*(bmp: Bitmap; x, y, color: INTEGER);
@@ -511,8 +495,7 @@ END RectFill;
 
 
 PROCEDURE Circle*(b: Bitmap; cx, cy, r, col: INTEGER);
 PROCEDURE Circle*(b: Bitmap; cx, cy, r, col: INTEGER);
 VAR x, y, d: INTEGER;
 VAR x, y, d: INTEGER;
-BEGIN
-  x := 0; y := r; d := 3 - 2 * r;
+BEGIN x := 0; y := r; d := 3 - 2 * r;
   WHILE x <= y DO
   WHILE x <= y DO
     PutPixel(b, cx + x, cy + y, col);
     PutPixel(b, cx + x, cy + y, col);
     PutPixel(b, cx + y, cy + x, col);
     PutPixel(b, cx + y, cy + x, col);
@@ -531,8 +514,7 @@ END Circle;
 
 
 PROCEDURE CircleFill*(b: Bitmap; cx, cy, r, col: INTEGER);
 PROCEDURE CircleFill*(b: Bitmap; cx, cy, r, col: INTEGER);
 VAR x, y, d: INTEGER;
 VAR x, y, d: INTEGER;
-BEGIN
-  x := 0; y := r; d := 3 - 2 * r;
+BEGIN x := 0; y := r; d := 3 - 2 * r;
   WHILE x <= y DO
   WHILE x <= y DO
     HLine(b, cx - x, cy + y, cx + x, col);
     HLine(b, cx - x, cy + y, cx + x, col);
     HLine(b, cx - y, cy + x, cx + y, col);
     HLine(b, cx - y, cy + x, cx + y, col);
@@ -576,14 +558,12 @@ BEGIN NEW(bmp);
 RETURN bmp END CreateBitmap;
 RETURN bmp END CreateBitmap;
 
 
 PROCEDURE DestroyBitmap*(bmp: Bitmap);
 PROCEDURE DestroyBitmap*(bmp: Bitmap);
-BEGIN
-  SDL.FreeSurface(bmp.surface)
+BEGIN SDL.FreeSurface(bmp.surface)
 END DestroyBitmap;
 END DestroyBitmap;
 
 
 PROCEDURE LoadBitmap*(filename: ARRAY OF CHAR): Bitmap;
 PROCEDURE LoadBitmap*(filename: ARRAY OF CHAR): Bitmap;
 VAR bmp: Bitmap;
 VAR bmp: Bitmap;
-BEGIN
-  NEW(bmp); bmp.surface := SDL.ImgLoad(filename);
+BEGIN NEW(bmp); bmp.surface := SDL.ImgLoad(filename);
   IF bmp.surface = NIL THEN bmp := NIL
   IF bmp.surface = NIL THEN bmp := NIL
   ELSE bmp.w := bmp.surface.w; bmp.h := bmp.surface.h END ;
   ELSE bmp.w := bmp.surface.w; bmp.h := bmp.surface.h END ;
 RETURN bmp END LoadBitmap;
 RETURN bmp END LoadBitmap;
@@ -643,8 +623,7 @@ BEGIN
 END DrawCharacterEx;
 END DrawCharacterEx;
 
 
 PROCEDURE SetColorKey*(bmp: Bitmap; color: INTEGER);
 PROCEDURE SetColorKey*(bmp: Bitmap; color: INTEGER);
-BEGIN
-  SDL.SetColorKey(bmp.surface, 1, color)
+BEGIN SDL.SetColorKey(bmp.surface, 1, color)
 END SetColorKey;
 END SetColorKey;
 
 
 (* Font *)
 (* Font *)
@@ -652,8 +631,7 @@ END SetColorKey;
 PROCEDURE LoadFont*(filename: ARRAY OF CHAR; charW, charH: INTEGER): Font;
 PROCEDURE LoadFont*(filename: ARRAY OF CHAR; charW, charH: INTEGER): Font;
 VAR bmp: Bitmap; font: Font;
 VAR bmp: Bitmap; font: Font;
     x, y, sx, sy, tmp: INTEGER;
     x, y, sx, sy, tmp: INTEGER;
-BEGIN
-  bmp := LoadBitmap(filename);
+BEGIN bmp := LoadBitmap(filename);
   IF bmp = NIL THEN font := NIL
   IF bmp = NIL THEN font := NIL
   ELSE
   ELSE
     bmp.surface := SDL.ConvertSurface(bmp.surface,
     bmp.surface := SDL.ConvertSurface(bmp.surface,
@@ -683,8 +661,7 @@ RETURN font END LoadFont;
 PROCEDURE DrawCharacter*(dest: Bitmap; font: Font;
 PROCEDURE DrawCharacter*(dest: Bitmap; font: Font;
   x, y: INTEGER; ch: CHAR; fg: INTEGER);
   x, y: INTEGER; ch: CHAR; fg: INTEGER);
 VAR fx, fy, r, g, b: INTEGER; dstRect: SDL.Rect;
 VAR fx, fy, r, g, b: INTEGER; dstRect: SDL.Rect;
-BEGIN
-  dstRect.x := x; dstRect.y := y;
+BEGIN dstRect.x := x; dstRect.y := y;
   fx := ORD(ch) MOD font.charsInRow;
   fx := ORD(ch) MOD font.charsInRow;
   fy := ORD(ch) DIV font.charsInRow;
   fy := ORD(ch) DIV font.charsInRow;
   ColorToRGB(fg, r, g, b);
   ColorToRGB(fg, r, g, b);
@@ -696,8 +673,7 @@ END DrawCharacter;
 PROCEDURE DrawString*(dest: Bitmap; font: Font;
 PROCEDURE DrawString*(dest: Bitmap; font: Font;
   x, y: INTEGER; s: ARRAY OF CHAR; fg: INTEGER);
   x, y: INTEGER; s: ARRAY OF CHAR; fg: INTEGER);
 VAR i, cx: INTEGER;
 VAR i, cx: INTEGER;
-BEGIN
-  i := 0; cx := x;
+BEGIN i := 0; cx := x;
   WHILE (s[i] # 0X) & (cx < dest.w) DO
   WHILE (s[i] # 0X) & (cx < dest.w) DO
     DrawCharacter(dest, font, cx, y, s[i], fg);
     DrawCharacter(dest, font, cx, y, s[i], fg);
     INC(i); INC(cx, font.charW)
     INC(i); INC(cx, font.charW)
@@ -713,8 +689,7 @@ BEGIN SDL.StopTextInput
 END StopTextInput;
 END StopTextInput;
 
 
 PROCEDURE QueueEvent;
 PROCEDURE QueueEvent;
-BEGIN
-  INC(events.len); INC(events.last);
+BEGIN INC(events.len); INC(events.last);
   IF events.last = LEN(events.buf) THEN events.last := 0 END
   IF events.last = LEN(events.buf) THEN events.last := 0 END
 END QueueEvent;
 END QueueEvent;
 
 
@@ -752,7 +727,7 @@ RETURN c END DecodeChar;
 
 
 PROCEDURE PumpTextEvent(event: SDL.Event);
 PROCEDURE PumpTextEvent(event: SDL.Event);
 VAR sym: INTEGER;
 VAR sym: INTEGER;
-    e: SDL.TextInputEvent;
+  e: SDL.TextInputEvent;
 BEGIN
 BEGIN
   IF events.len < LEN(events.buf) THEN
   IF events.len < LEN(events.buf) THEN
     e := SYSTEM.VAL(SDL.TextInputEvent, SYSTEM.ADR(event));
     e := SYSTEM.VAL(SDL.TextInputEvent, SYSTEM.ADR(event));
@@ -837,8 +812,7 @@ BEGIN IF SDL.GetMouseState(x, y) = 0 THEN END
 END GetRealMousePos;
 END GetRealMousePos;
 
 
 PROCEDURE GetMousePos*(VAR x, y: INTEGER);
 PROCEDURE GetMousePos*(VAR x, y: INTEGER);
-BEGIN
-  x := mouseX; y := mouseY
+BEGIN x := mouseX; y := mouseY
 END GetMousePos;
 END GetMousePos;
 
 
 PROCEDURE GetMouseButtons*(): SET;
 PROCEDURE GetMouseButtons*(): SET;
@@ -887,57 +861,51 @@ BEGIN
 RETURN mousePointer END GetMousePointer;
 RETURN mousePointer END GetMousePointer;
 
 
 PROCEDURE SetStdMousePointer*;
 PROCEDURE SetStdMousePointer*;
-BEGIN
-  SetMousePointer(stdMousePointer, 0, 0)
+BEGIN SetMousePointer(stdMousePointer, 0, 0)
 END SetStdMousePointer;
 END SetStdMousePointer;
 
 
 PROCEDURE InitMouseData;
 PROCEDURE InitMouseData;
-BEGIN
-  CreateStdMousePointer;
-  SetStdMousePointer
+BEGIN CreateStdMousePointer; SetStdMousePointer
 END InitMouseData;
 END InitMouseData;
 
 
 (* Misc *)
 (* Misc *)
 PROCEDURE SetWindowTitle*(title: ARRAY OF CHAR);
 PROCEDURE SetWindowTitle*(title: ARRAY OF CHAR);
-BEGIN
-  SDL.SetWindowTitle(window, title)
+BEGIN SDL.SetWindowTitle(window, title)
 END SetWindowTitle;
 END SetWindowTitle;
 
 
 PROCEDURE SwitchToWindowed*;
 PROCEDURE SwitchToWindowed*;
 BEGIN
 BEGIN
-  IF wantFullscreen THEN
+  IF fullscreen IN settings THEN
     SDL.SetWindowSize(window, screen.w, screen.h);
     SDL.SetWindowSize(window, screen.w, screen.h);
     IF SDL.SetWindowFullscreen(window, {}) = 0 THEN
     IF SDL.SetWindowFullscreen(window, {}) = 0 THEN
-      wantFullscreen := FALSE
+      EXCL(settings, fullscreen)
     END
     END
   END
   END
 END SwitchToWindowed;
 END SwitchToWindowed;
 
 
 PROCEDURE SwitchToFullscreen*;
 PROCEDURE SwitchToFullscreen*;
 BEGIN
 BEGIN
-  IF ~wantFullscreen THEN
+  IF ~(fullscreen IN settings) THEN
     IF SDL.SetWindowFullscreen(window, SDL.windowFullscreenDesktop) = 0 THEN
     IF SDL.SetWindowFullscreen(window, SDL.windowFullscreenDesktop) = 0 THEN
-      wantFullscreen := TRUE
+      INCL(settings, fullscreen)
     END
     END
   END
   END
 END SwitchToFullscreen;
 END SwitchToFullscreen;
 
 
 PROCEDURE ToggleFullscreen*;
 PROCEDURE ToggleFullscreen*;
 BEGIN
 BEGIN
-  IF wantFullscreen THEN SwitchToWindowed
+  IF fullscreen IN settings THEN SwitchToWindowed
   ELSE SwitchToFullscreen
   ELSE SwitchToFullscreen
   END
   END
 END ToggleFullscreen;
 END ToggleFullscreen;
 
 
 PROCEDURE Delay*(n: INTEGER);
 PROCEDURE Delay*(n: INTEGER);
-BEGIN
-  SDL.Delay(n)
+BEGIN SDL.Delay(n)
 END Delay;
 END Delay;
 
 
 PROCEDURE HandleMouseButton(VAR event: SDL.Event);
 PROCEDURE HandleMouseButton(VAR event: SDL.Event);
 VAR e: SDL.MouseButtonEvent;
 VAR e: SDL.MouseButtonEvent;
 BEGIN
 BEGIN
-
 END HandleMouseButton;
 END HandleMouseButton;
 
 
 PROCEDURE PumpQuit;
 PROCEDURE PumpQuit;
@@ -950,7 +918,7 @@ END PumpQuit;
 
 
 PROCEDURE PumpMouseMove(VAR event: SDL.Event);
 PROCEDURE PumpMouseMove(VAR event: SDL.Event);
 VAR e: SDL.MouseMotionEvent;
 VAR e: SDL.MouseMotionEvent;
-    newX, newY: INTEGER;
+  newX, newY: INTEGER;
 BEGIN
 BEGIN
   e := SYSTEM.VAL(SDL.MouseMotionEvent, SYSTEM.ADR(event));
   e := SYSTEM.VAL(SDL.MouseMotionEvent, SYSTEM.ADR(event));
   newX := e.x; newY := e.y;
   newX := e.x; newY := e.y;
@@ -1098,8 +1066,7 @@ VAR mx, my: INTEGER; (* Mouse bitmap X Y *)
   END PrepareMouse;
   END PrepareMouse;
 
 
   PROCEDURE CleanMouse;
   PROCEDURE CleanMouse;
-  BEGIN
-    (* Restore image under mouse in buffer *)
+  BEGIN (* Restore image under mouse in buffer *)
     Blit(underMouse, screen, 0, 0,
     Blit(underMouse, screen, 0, 0,
       underMouse.w, underMouse.h, mx, my);
       underMouse.w, underMouse.h, mx, my);
     needRedrawMouse := FALSE
     needRedrawMouse := FALSE
@@ -1142,20 +1109,17 @@ RETURN SHORT(Platform.Time()) END Time;
 (* Set random seed value. Any values are allowed, although
 (* Set random seed value. Any values are allowed, although
    values not in [1..2^31-2] will be mapped into this range. *)
    values not in [1..2^31-2] will be mapped into this range. *)
 PROCEDURE PutSeed*(newSeed: INTEGER);
 PROCEDURE PutSeed*(newSeed: INTEGER);
-BEGIN
-  newSeed := newSeed MOD randomModulo;
+BEGIN newSeed := newSeed MOD randomModulo;
   IF newSeed = 0 THEN randomSeed := 1
   IF newSeed = 0 THEN randomSeed := 1
   ELSE randomSeed := newSeed
   ELSE randomSeed := newSeed
   END
   END
 END PutSeed;
 END PutSeed;
 
 
 PROCEDURE NextRND;
 PROCEDURE NextRND;
-CONST
-  a = 16807;
+CONST a = 16807;
   q = 127773; (* m div a *)
   q = 127773; (* m div a *)
   r = 2836;   (* m mod a *)
   r = 2836;   (* m mod a *)
-VAR
-  lo, hi, test: INTEGER;
+VAR lo, hi, test: INTEGER;
 BEGIN
 BEGIN
   hi := randomSeed DIV q;
   hi := randomSeed DIV q;
   lo := randomSeed MOD q;
   lo := randomSeed MOD q;
@@ -1165,7 +1129,7 @@ BEGIN
   END
   END
 END NextRND;
 END NextRND;
 
 
-(* Calculates a new number. range has to be in the intervall
+(* Calculates a new number. range has to be included in
    [1..2^31-2]. Result is a number from 0, 1, ... , range-1. *)
    [1..2^31-2]. Result is a number from 0, 1, ... , range-1. *)
 PROCEDURE Random*(range: INTEGER): INTEGER;
 PROCEDURE Random*(range: INTEGER): INTEGER;
 BEGIN NextRND ;
 BEGIN NextRND ;
@@ -1185,59 +1149,62 @@ END Randomize;
 PROCEDURE Init*(): Bitmap;
 PROCEDURE Init*(): Bitmap;
 VAR flags: SET; success: BOOLEAN; w, h, nw, nh: INTEGER;
 VAR flags: SET; success: BOOLEAN; w, h, nw, nh: INTEGER;
     s: ARRAY 2000 OF CHAR;
     s: ARRAY 2000 OF CHAR;
-BEGIN screen := NIL;
+BEGIN screen := NIL; settings := initSettings;
   IF SDL.Init({SDL.initVideo}) = 0 THEN
   IF SDL.Init({SDL.initVideo}) = 0 THEN
     flags := {};
     flags := {};
-    IF wantFullscreen THEN
+    IF fullscreen IN settings THEN
       flags := flags + SDL.windowFullscreenDesktop;
       flags := flags + SDL.windowFullscreenDesktop;
-      IF (wantW <= 0) OR (wantH <= 0) THEN
-        GetDesktopResolution(wantW, wantH)
-      ELSIF wantSpread THEN
+      IF (scrW <= 0) OR (scrH <= 0) THEN
+        GetDesktopResolution(scrW, scrH);
+        scrW := SHORT(ENTIER(scrW / scaleX));
+        scrH := SHORT(ENTIER(scrH / scaleY))
+      ELSIF spread IN settings THEN
         GetDesktopResolution(w, h);
         GetDesktopResolution(w, h);
-        IF wantSharpPixels THEN
-          nw := w DIV wantW; nh := h DIV wantH;
-          IF nw < nh THEN
-            wantW := w DIV nw; wantH := h DIV nw;
-          ELSE
-            wantW := w DIV nh; wantH := h DIV nh;
+        w := SHORT(ENTIER(w / scaleX)); h := SHORT(ENTIER(h / scaleY));
+        IF sharpPixels IN settings THEN
+          nw := w DIV scrW; nh := h DIV scrH;
+          IF nw < nh THEN scrW := w DIV nw; scrH := h DIV nw
+          ELSE scrW := w DIV nh; scrH := h DIV nh
           END
           END
         END;
         END;
-        IF w / h > wantW / wantH THEN wantW := w * wantH DIV h
-        ELSE wantH := h * wantW DIV w
+        IF w / h > scrW / scrH THEN scrW := w * scrH DIV h
+        ELSE scrH := h * scrW DIV w
         END
         END
       END
       END
-    ELSIF (wantW <= 0) OR (wantH <= 0) THEN wantW := 640; wantH := 400
+    ELSIF (scrW <= 0) OR (scrH <= 0) THEN scrW := 640; scrH := 400
     END;
     END;
-    IF sizeStepX # 1 THEN wantW := wantW DIV sizeStepX * sizeStepX END;
-    IF sizeStepY # 1 THEN wantH := wantH DIV sizeStepY * sizeStepY END;
+    IF sizeStepX # 1 THEN scrW := scrW DIV sizeStepX * sizeStepX END;
+    IF sizeStepY # 1 THEN scrH := scrH DIV sizeStepY * sizeStepY END;
     window := SDL.CreateWindow('',
     window := SDL.CreateWindow('',
       SDL.windowPosUndefined, SDL.windowPosUndefined,
       SDL.windowPosUndefined, SDL.windowPosUndefined,
-      wantW, wantH, flags);
+      scrW, scrH, flags);
     IF window # 0 THEN
     IF window # 0 THEN
-      IF wantSoftware THEN flags := {SDL.rendererSoftware}
+      IF software IN settings THEN flags := {SDL.rendererSoftware}
       ELSE flags := {SDL.rendererAccelerated}
       ELSE flags := {SDL.rendererAccelerated}
       END;
       END;
       INCL(flags, SDL.rendererPresentVsync);
       INCL(flags, SDL.rendererPresentVsync);
       renderer := SDL.CreateRenderer(window, -1, flags);
       renderer := SDL.CreateRenderer(window, -1, flags);
-      IF wantSharpPixels THEN
+      IF sharpPixels IN settings THEN
         SDL.SetHint(SDL.hintRenderScaleQuality, '0')
         SDL.SetHint(SDL.hintRenderScaleQuality, '0')
-      ELSE
-        SDL.SetHint(SDL.hintRenderScaleQuality, '1')
+      ELSE SDL.SetHint(SDL.hintRenderScaleQuality, '1')
       END;
       END;
-      SDL.RenderSetLogicalSize(renderer, wantW, wantH);
-      screen := CreateBitmap(wantW, wantH);
+      ApplyScale;
+      screen := CreateBitmap(scrW, scrH);
       screenTexture := 0;
       screenTexture := 0;
       UnsetRegion;
       UnsetRegion;
       SDL.ShowCursor(0);
       SDL.ShowCursor(0);
-      IF wantMouse THEN InitMouseData END;
-      flags := {SDL.imgInitPng, SDL.imgInitJpg};
-      IF flags - SDL.ImgInit(flags) # {} THEN
-        Out.String('Could not initialize PNG or JPG: ');
-        GetError(s); Out.String(s); Out.Ln
+      IF initMouse IN settings THEN InitMouseData END;
+      IF {noPng, noJpg} - settings # {} THEN flags := {};
+        IF ~(noPng IN settings) THEN INCL(flags, SDL.imgInitPng) END;
+        IF ~(noJpg IN settings) THEN INCL(flags, SDL.imgInitJpg) END;
+        IF flags - SDL.ImgInit(flags) # {} THEN
+          Out.String('Could not initialize image format support.'); Out.Ln;
+          GetError(s); Out.String(s); Out.Ln
+        END
       END;
       END;
-      Randomize;
       keyPressed := 0;
       keyPressed := 0;
-      lastFlip := -1
+      lastFlip := -1;
+      Randomize
     END
     END
   END ;
   END ;
 RETURN screen END Init;
 RETURN screen END Init;
@@ -1248,18 +1215,21 @@ BEGIN
     SDL.DestroyTexture(screenTexture);
     SDL.DestroyTexture(screenTexture);
     screenTexture := 0
     screenTexture := 0
   END;
   END;
+  IF renderer # 0 THEN
+    SDL.DestroyRenderer(renderer);
+    renderer := 0
+  END;
   SDL.Quit
   SDL.Quit
 END Close;
 END Close;
 
 
 BEGIN
 BEGIN
-  wantW := 640; wantH := 400;
+  scrW := 640; scrH := 400;
   sizeStepX := 1; sizeStepY := 1;
   sizeStepX := 1; sizeStepY := 1;
-  wantFullscreen := TRUE; wantSpread := TRUE;
-  wantBuffer := FALSE; buffer := NIL; wantFPS := 60;
-  wantSharpPixels := TRUE;
+  initSettings := {fullscreen, spread, sharpPixels};
+  renderer := 0; buffer := NIL; wantFPS := 60;
   mousePointer := NIL; lastBlitMouseOutside := FALSE;
   mousePointer := NIL; lastBlitMouseOutside := FALSE;
   mouseFocusX := 0; mouseFocusY := 0;
   mouseFocusX := 0; mouseFocusY := 0;
+  scaleX := 1; scaleY := 1;
   events.first := 0; events.last := -1; events.len := 0;
   events.first := 0; events.last := -1; events.len := 0;
   randomSeed := 1; keyPressed := 0
   randomSeed := 1; keyPressed := 0
 END Graph.
 END Graph.
-

+ 3 - 1
src/SDL2.Mod

@@ -439,7 +439,9 @@ PROCEDURE -RenderCopyNil*(renderer: Renderer; texture: Texture)
     "SDL_RenderCopyEx((void * )renderer, (void * )texture, srcRect, dstRect, angle, center, flip)";*)
     "SDL_RenderCopyEx((void * )renderer, (void * )texture, srcRect, dstRect, angle, center, flip)";*)
 PROCEDURE -SetRenderDrawBlendMode*(renderer: Renderer; blendMode: SET)
 PROCEDURE -SetRenderDrawBlendMode*(renderer: Renderer; blendMode: SET)
     "SDL_SetRenderDrawBlendMode(void *)renderer, blendMode)";
     "SDL_SetRenderDrawBlendMode(void *)renderer, blendMode)";
-PROCEDURE -DestroyRenderer(renderer: ADRINT)
+PROCEDURE -RenderSetScale*(renderer: Renderer; scaleX, scaleY: REAL)
+    "SDL_RenderSetScale((void *)renderer, scaleX, scaleY)";
+PROCEDURE -DestroyRenderer*(renderer: ADRINT)
     "SDL_DestroyRenderer((void *)renderer)";
     "SDL_DestroyRenderer((void *)renderer)";
 
 
 (* Misc *)
 (* Misc *)

+ 4 - 0
src/SDL2.h0

@@ -64,6 +64,10 @@ extern int SDL_RenderSetLogicalSize(void *, int, int);
 extern int SDL_SetColorKey(void *, int, UINT32);
 extern int SDL_SetColorKey(void *, int, UINT32);
 extern SDL_bool SDL_SetHint(void *, void *);
 extern SDL_bool SDL_SetHint(void *, void *);
 extern int SDL_SetRenderDrawBlendMode(void *, SDL_BlendMode);
 extern int SDL_SetRenderDrawBlendMode(void *, SDL_BlendMode);
+
+extern int SDL_RenderSetScale(void *renderer, float scaleX, float scaleY);
+extern void SDL_DestroyRenderer(void *renderer);
+
 extern int SDL_SetRenderDrawColor(void *, UINT8, UINT8, UINT8, UINT8);
 extern int SDL_SetRenderDrawColor(void *, UINT8, UINT8, UINT8, UINT8);
 extern int SDL_SetSurfaceColorMod(void *, UINT8, UINT8, UINT8);
 extern int SDL_SetSurfaceColorMod(void *, UINT8, UINT8, UINT8);
 extern int SDL_SetWindowFullscreen(void *, UINT32);
 extern int SDL_SetWindowFullscreen(void *, UINT32);

+ 34 - 28
src/Terminal.Mod

@@ -44,16 +44,24 @@ VAR
   needRedraw: BOOLEAN;
   needRedraw: BOOLEAN;
 
 
   isFullscreen-: BOOLEAN;
   isFullscreen-: BOOLEAN;
+  pixelPerfect-: BOOLEAN; (* TRUE if G.Settings width or height was zero *)
 
 
 PROCEDURE Redraw*;
 PROCEDURE Redraw*;
 BEGIN needRedraw := TRUE
 BEGIN needRedraw := TRUE
 END Redraw;
 END Redraw;
 
 
+PROCEDURE SetScale;
+BEGIN
+  IF isFullscreen & ~pixelPerfect THEN G.SetScale(5/6, 1)
+  ELSE G.SetScale(1, 1)
+  END
+END SetScale;
+
 PROCEDURE ToggleFullscreen*;
 PROCEDURE ToggleFullscreen*;
 BEGIN
 BEGIN
   IF isFullscreen THEN G.SwitchToWindowed ELSE G.SwitchToFullscreen END;
   IF isFullscreen THEN G.SwitchToWindowed ELSE G.SwitchToFullscreen END;
-  Redraw;
-  isFullscreen := ~isFullscreen
+  isFullscreen := ~isFullscreen;
+  SetScale; Redraw
 END ToggleFullscreen;
 END ToggleFullscreen;
 
 
 PROCEDURE ExpandColor*(color: INTEGER): INTEGER;
 PROCEDURE ExpandColor*(color: INTEGER): INTEGER;
@@ -114,7 +122,7 @@ END DrawMouse;
    Returns TRUE if anything has been drawn. *)
    Returns TRUE if anything has been drawn. *)
 PROCEDURE Draw*(): BOOLEAN;
 PROCEDURE Draw*(): BOOLEAN;
 VAR x, y, color: INTEGER;
 VAR x, y, color: INTEGER;
-    drawn: BOOLEAN;
+  drawn: BOOLEAN;
 BEGIN
 BEGIN
   drawn := needRedraw;
   drawn := needRedraw;
   IF needRedraw THEN
   IF needRedraw THEN
@@ -175,25 +183,22 @@ BEGIN
 END ShowCursor;
 END ShowCursor;
 
 
 PROCEDURE GoToXY*(x, y: INTEGER);
 PROCEDURE GoToXY*(x, y: INTEGER);
-BEGIN
+BEGIN needRedraw := TRUE;
   IF x < 0 THEN x := 0 ELSIF x >= charsX THEN x := charsX - 1 END;
   IF x < 0 THEN x := 0 ELSIF x >= charsX THEN x := charsX - 1 END;
   IF y < 0 THEN y := 0 ELSIF y >= charsY THEN y := charsY - 1 END;
   IF y < 0 THEN y := 0 ELSIF y >= charsY THEN y := charsY - 1 END;
   chars[cursorY, cursorX].updated := TRUE;
   chars[cursorY, cursorX].updated := TRUE;
-  cursorX := x; cursorY := y;
-  needRedraw := TRUE
+  cursorX := x; cursorY := y
 END GoToXY;
 END GoToXY;
 
 
 PROCEDURE MouseXY*(x, y: INTEGER);
 PROCEDURE MouseXY*(x, y: INTEGER);
-BEGIN
-  needRedraw := TRUE;
+BEGIN needRedraw := TRUE;
   chars[mouseY, mouseX].updated := TRUE;
   chars[mouseY, mouseX].updated := TRUE;
   mouseX := x; mouseY := y;
   mouseX := x; mouseY := y;
   chars[mouseY, mouseX].updated := TRUE
   chars[mouseY, mouseX].updated := TRUE
 END MouseXY;
 END MouseXY;
 
 
 PROCEDURE ResizeScreen;
 PROCEDURE ResizeScreen;
-BEGIN
-  NEW(chars, charsY, charsX)
+BEGIN NEW(chars, charsY, charsX)
 END ResizeScreen;
 END ResizeScreen;
 
 
 PROCEDURE SetCharColor*(x, y: INTEGER; fg, bg: INTEGER);
 PROCEDURE SetCharColor*(x, y: INTEGER; fg, bg: INTEGER);
@@ -246,8 +251,7 @@ END CharFill;
 
 
 PROCEDURE ClearScreen*;
 PROCEDURE ClearScreen*;
 VAR x, y: INTEGER;
 VAR x, y: INTEGER;
-BEGIN
-  needRedraw := TRUE;
+BEGIN needRedraw := TRUE;
   FOR y := 0 TO charsY - 1 DO
   FOR y := 0 TO charsY - 1 DO
     FOR x := 0 TO charsX - 1 DO
     FOR x := 0 TO charsX - 1 DO
       IF (chars[y, x].ch # ' ') OR
       IF (chars[y, x].ch # ' ') OR
@@ -264,8 +268,7 @@ END ClearScreen;
 
 
 PROCEDURE ScrollScreen(lines: INTEGER);
 PROCEDURE ScrollScreen(lines: INTEGER);
 VAR x, y: INTEGER;
 VAR x, y: INTEGER;
-BEGIN
-  needRedraw := TRUE;
+BEGIN needRedraw := TRUE;
   FOR y := 0 TO charsY - 1 - lines DO
   FOR y := 0 TO charsY - 1 - lines DO
     FOR x := 0 TO charsX - 1 DO
     FOR x := 0 TO charsX - 1 DO
       chars[y, x] := chars[y + lines, x];
       chars[y, x] := chars[y + lines, x];
@@ -276,8 +279,7 @@ BEGIN
 END ScrollScreen;
 END ScrollScreen;
 
 
 PROCEDURE Ln*;
 PROCEDURE Ln*;
-BEGIN
-  needRedraw := TRUE;
+BEGIN needRedraw := TRUE;
   chars[cursorY, cursorX].updated := TRUE;
   chars[cursorY, cursorX].updated := TRUE;
   cursorX := 0;
   cursorX := 0;
   IF cursorY = charsY - 1 THEN ScrollScreen(1)
   IF cursorY = charsY - 1 THEN ScrollScreen(1)
@@ -296,8 +298,7 @@ BEGIN
 END Backspace;
 END Backspace;
 
 
 PROCEDURE Write*(ch: CHAR);
 PROCEDURE Write*(ch: CHAR);
-BEGIN
-  needRedraw := TRUE;
+BEGIN needRedraw := TRUE;
   IF ch = 0AX THEN Ln
   IF ch = 0AX THEN Ln
   ELSIF ch # 0DX THEN
   ELSIF ch # 0DX THEN
     PutChar(cursorX, cursorY, ch, 7, 0);
     PutChar(cursorX, cursorY, ch, 7, 0);
@@ -314,19 +315,24 @@ BEGIN i := 0; needRedraw := TRUE;
 END WriteString;
 END WriteString;
 
 
 PROCEDURE LoadMedia(): BOOLEAN;
 PROCEDURE LoadMedia(): BOOLEAN;
-BEGIN font := G.LoadFont('data/images/font.bmp', charW, charH) ;
+CONST fontFile = 'data/images/font.bmp';
+BEGIN font := G.LoadFont(fontFile, charW, charH);
+  IF font = NIL THEN Out.String('Could not load font file "');
+    Out.String(fontFile); Out.String('".'); Out.Ln
+  END ;
 RETURN font # NIL END LoadMedia;
 RETURN font # NIL END LoadMedia;
 
 
 PROCEDURE Init*(fullscreen, software: BOOLEAN; w, h: INTEGER): BOOLEAN;
 PROCEDURE Init*(fullscreen, software: BOOLEAN; w, h: INTEGER): BOOLEAN;
-VAR success: BOOLEAN; options: SET;
-BEGIN
-  success := FALSE; isFullscreen := fullscreen;
-  options := {G.buffered, G.initMouse, G.spread};
-  IF fullscreen THEN INCL(options, G.fullscreen) END;
-  IF software THEN INCL(options, G.software) END;
-  IF w < 0 THEN w := 96 ELSIF (w # 0) & (w < 10) THEN w := 10 END;
-  IF h < 0 THEN h := 27 ELSIF (h # 0) & (h < 10) THEN h := 10 END;
-  G.Settings(w * 8, h * 16, options);
+VAR success: BOOLEAN; settings: SET;
+BEGIN success := FALSE; isFullscreen := fullscreen;
+  settings := {G.buffered, G.initMouse, G.spread, G.noJpg};
+  IF fullscreen THEN INCL(settings, G.fullscreen) END;
+  IF software THEN INCL(settings, G.software) END;
+  IF w < 0 THEN w := 107 ELSIF (w # 0) & (w < 10) THEN w := 20 END;
+  IF h < 0 THEN h := 25 ELSIF (h # 0) & (h < 10) THEN h := 10 END;
+  pixelPerfect := (w = 0) OR (h = 0);
+  G.Settings(w * 8, h * 16, settings);
+  SetScale;
   G.SetSizeStep(charW, charH);
   G.SetSizeStep(charW, charH);
   screen := G.Init();
   screen := G.Init();
   IF screen # NIL THEN
   IF screen # NIL THEN