Page 1 of 1

Save/Restore the GRAPHICS MODE

Posted: Tue Aug 14, 2018 4:41 pm
by matt7
Functions provided:
  • GET_GRAPHICS_MODE$ () detects the current graphics mode and returns it as a string (e.g. "NORMAL", "MULTIPLY", "SCREEN", etc.).
  • SET_GRAPHICS_MODE (gm$) sets the graphics mode based on the input string.
  • SAVE_GRAPHICS_MODE () calls GET_GRAPHICS_MODE$ and stores the returned mode string so that the graphics mode can be restored to that mode at a later time using RESTORE_GRAPHICS_MODE.
  • RESTORE_GRAPHICS_MODE () uses the mode string stored by SAVE_GRAPHICS_MODE and calls SET_GRAPHICS_MODE(gm$).
Code:

Library File

Code: Select all

'g'
/*
    GET_GRAPHICS_MODE$ ()
    SET_GRAPHICS_MODE (gm$)
    SAVE_GRAPHICS_MODE ()
    RESTORE_GRAPHICS_MODE ()


Functions for detecting, setting, saving, and restoring the graphics mode.

'==============================================================

GET_GRAPHICS_MODE$ detects the current graphics mode and returns it as a string (e.g. "NORMAL", "MULTIPLY", "SCREEN", etc.).

SET_GRAPHICS_MODE sets the graphics mode based on the input string.

  Inputs
  ------

      gm$    Graphics mode string (e.g. "MULTIPLY")

'==============================================================

SAVE_GRAPHICS_MODE calls GET_GRAPHICS_MODE$ and stores the returned mode string so that the graphics mode can be restored to that mode at a later time using RESTORE_GRAPHICS_MODE.

RESTORE_GRAPHICS_MODE uses the mode string stored by SAVE_GRAPHICS_MODE and calls SET_GRAPHICS_MODE(gm$).

'==============================================================
*/
''
DEF GET_GRAPHICS_MODE$ ()

  r1 = 0.7  !  r2 = 0.1
  g1 = 0.0  !  g2 = 0.3
  b1 = 1.0  !  b2 = 0.7
  a1 = 0.2  !  a2 = 0.9

  nScan$ = "get_graphics_mode_scan"
  SPRITE nScan$ SCAN 0, 0, 2, 2

  DRAW PIXEL 0, 0 COLOR r1, g1, b1, a1

  nStamp$ = "get_graphics_mode_stamp"
  SPRITE nStamp$ BEGIN 1, 1
    GRAPHICS CLEAR r2, g2, b2, a2
  SPRITE END
  SPRITE nStamp$ STAMP
  
  GET PIXEL 0, 0 COLOR r, g, b, a

  r$ = INT(r*255)
  g$ = INT(g*255)
  b$ = INT(b*255)
  a$ = INT(a*255)
  c$ = r$ & "-" & g$ & "-" & b$ & "-" & a$

  IF c$ = "28-75-180-235" THEN gm$ = "NORMAL"
  IF c$ = "26-60-180-235" THEN gm$ = "MULTIPLY"
  IF c$ = "59-75-194-235" THEN gm$ = "SCREEN"
  IF c$ = "44-60-194-235" THEN gm$ = "OVERLAY"
  IF c$ = "28-60-180-235" THEN gm$ = "DARKEN"
  IF c$ = "58-75-194-235" THEN gm$ = "LIGHTEN"
  IF c$ = "61-60-255-235" THEN gm$ = "COLORDODGE"
  IF c$ = "0-0-194-235"   THEN gm$ = "COLORBURN"
  IF c$ = "49-60-194-235" THEN gm$ = "SOFTLIGHT"
  IF c$ = "30-60-194-235" THEN gm$ = "HARDLIGHT"
  IF c$ = "52-75-160-235" THEN gm$ = "DIFFERENCE"
  IF c$ = "55-75-160-235" THEN gm$ = "EXCLUSION"
  IF c$ = "23-76-194-235" THEN gm$ = "HUE"
  IF c$ = "50-66-181-235" THEN gm$ = "SATURATION"
  IF c$ = "29-76-181-235" THEN gm$ = "COLOR"
  IF c$ = "52-60-187-235" THEN gm$ = "LUMINOSITY"
  IF c$ = "0-0-0-0"       THEN gm$ = "CLEAR"
  IF c$ = "26-77-179-230" THEN gm$ = "COPY"
  IF c$ = "28-78-183-46"  THEN gm$ = "SOURCEIN"
  IF c$ = "26-78-179-184" THEN gm$ = "SOURCEOUT"
  IF c$ = "40-65-185-51"  THEN gm$ = "SOURCEATOP"
  IF c$ = "58-60-194-235" THEN gm$ = "DESTOVER"
  IF c$ = "177-0-255-46"  THEN gm$ = "DESTIN"
  IF c$ = "204-0-255-5"   THEN gm$ = "DESTOUT"
  IF c$ = "54-61-193-230" THEN gm$ = "DESTATOP"
  IF c$ = "28-74-179-189" THEN gm$ = "XOR"
  IF c$ = "32-43-186-255" THEN gm$ = "PLUSDARKER"
  IF c$ = "58-69-212-255" THEN gm$ = "PLUSLIGHTER"

  GRAPHICS MODE COPY
  SPRITE nScan$ STAMP
  SET_GRAPHICS_MODE(gm$)

  RETURN gm$

END DEF

'==============================================================

DEF SET_GRAPHICS_MODE (gm$)

  gm$ = CAPSTR$(gm$)

  IF gm$ = "NORMAL"      THEN GRAPHICS MODE NORMAL
  IF gm$ = "MULTIPLY"    THEN GRAPHICS MODE MULTIPLY
  IF gm$ = "SCREEN"      THEN GRAPHICS MODE SCREEN
  IF gm$ = "OVERLAY"     THEN GRAPHICS MODE OVERLAY
  IF gm$ = "DARKEN"      THEN GRAPHICS MODE DARKEN
  IF gm$ = "LIGHTEN"     THEN GRAPHICS MODE LIGHTEN
  IF gm$ = "COLORDODGE"  THEN GRAPHICS MODE COLORDODGE
  IF gm$ = "COLORBURN"   THEN GRAPHICS MODE COLORBURN
  IF gm$ = "SOFTLIGHT"   THEN GRAPHICS MODE SOFTLIGHT
  IF gm$ = "HARDLIGHT"   THEN GRAPHICS MODE HARDLIGHT
  IF gm$ = "DIFFERENCE"  THEN GRAPHICS MODE DIFFERENCE
  IF gm$ = "EXCLUSION"   THEN GRAPHICS MODE EXCLUSION
  IF gm$ = "HUE"         THEN GRAPHICS MODE HUE
  IF gm$ = "SATURATION"  THEN GRAPHICS MODE SATURATION
  IF gm$ = "COLOR"       THEN GRAPHICS MODE COLOR
  IF gm$ = "LUMINOSITY"  THEN GRAPHICS MODE LUMINOSITY
  IF gm$ = "CLEAR"       THEN GRAPHICS MODE CLEAR
  IF gm$ = "COPY"        THEN GRAPHICS MODE COPY
  IF gm$ = "SOURCEIN"    THEN GRAPHICS MODE SOURCEIN
  IF gm$ = "SOURCEOUT"   THEN GRAPHICS MODE SOURCEOUT
  IF gm$ = "SOURCEATOP"  THEN GRAPHICS MODE SOURCEATOP
  IF gm$ = "DESTOVER"    THEN GRAPHICS MODE DESTOVER
  IF gm$ = "DESTIN"      THEN GRAPHICS MODE DESTIN
  IF gm$ = "DESTOUT"     THEN GRAPHICS MODE DESTOUT
  IF gm$ = "DESTATOP"    THEN GRAPHICS MODE DESTATOP
  IF gm$ = "XOR"         THEN GRAPHICS MODE XOR
  IF gm$ = "PLUSDARKER"  THEN GRAPHICS MODE PLUSDARKER
  IF gm$ = "PLUSLIGHTER" THEN GRAPHICS MODE PLUSLIGHTER

END DEF

'==============================================================

DEF SAVE_GRAPHICS_MODE ()

  gm$ = GET_GRAPHICS_MODE$()

END DEF

'==============================================================

DEF RESTORE_GRAPHICS_MODE ()

  SET_GRAPHICS_MODE(SAVE_GRAPHICS_MODE.gm$)

END DEF

'==============================================================
Test File

Code: Select all

{graphics_modes}

GRAPHICS CLEAR
GRAPHICS

DRAW ALPHA 0
FILL ALPHA 0

DIM gm$(28)
gm$(0) = "NORMAL"
gm$(1) = "MULTIPLY"
gm$(2) = "SCREEN"
gm$(3) = "OVERLAY"
gm$(4) = "DARKEN"
gm$(5) = "LIGHTEN"
gm$(6) = "COLORDODGE"
gm$(7) = "COLORBURN"
gm$(8) = "SOFTLIGHT"
gm$(9) = "HARDLIGHT"
gm$(10) = "DIFFERENCE"
gm$(11) = "EXCLUSION"
gm$(12) = "HUE"
gm$(13) = "SATURATION"
gm$(14) = "COLOR"
gm$(15) = "LUMINOSITY"
gm$(16) = "CLEAR"
gm$(17) = "COPY"
gm$(18) = "SOURCEIN"
gm$(19) = "SOURCEOUT"
gm$(20) = "SOURCEATOP"
gm$(21) = "DESTOVER"
gm$(22) = "DESTIN"
gm$(23) = "DESTOUT"
gm$(24) = "DESTATOP"
gm$(25) = "XOR"
gm$(26) = "PLUSDARKER"
gm$(27) = "PLUSLIGHTER"

FOR i = 0 TO 27

  SET_GRAPHICS_MODE(gm$(i))
  gm_detected$ = GET_GRAPHICS_MODE$()

  IF gm$(i) = gm_detected$ THEN
    ' Test passed
    t$ &= "."
  ELSE
    ' Test failed
    t$ &= "F" & CHR$(13)
    t$ &= gm$(i) & " -> " & gm_detected$ & CHR$(13)
  END IF

NEXT i

PAUSE 1

TEXT
PRINT t$
Background/Details:

A while ago I requested a new command GET GRAPHICS MODE M$ and the ability to use a string variable when setting the graphics mode (requested here). Since then I've just resigned myself to knowing that I cannot preserve the graphics mode if I have a function that needs to set it to a specific mode.

Then I stumbled on Joel's post where he shared his save_graphic_params library function, with his clever method of saving a portion of the graphics window to an image, drawing to that space, using the GET PIXEL COLOR command to detect what the graphics settings are set to, and then drawing the saved image back onto the screen. I thought this was really cool, but I realized that it assumes that the graphics mode is set to NORMAL and that the portion of the screen being saved and redrawn is fully opaque.

This inspired me to try and write my own library functions for saving/restoring the graphics mode, and the goal was that it would detect the graphics mode without doing anything like setting the FILL COLOR and FILL ALPHA. I wanted this function to be able to be used by Joel's library so it could set graphics mode to NORMAL for drawing, set it to COPY for drawing back the portion of the screen that was saved (preserving transparency), and then return it back to the original mode. I went back a forth a few times between being hopeful and believing it was impossible, but I finally discovered the right combination of smart Basic features that enable the graphics mode to be detected without setting any graphics parameters like FILL COLOR or FILL ALPHA:
  1. The arguments for the DRAW PIXEL COLOR command are absolute (r, g, b, and a are not affected by the graphics mode or draw/fill settings). Therefore, this command can be used to draw a specific and known base color to the graphics window without using FILL COLOR or FILL ALPHA.
  2. Because sprites are "separate graphics layers," they have their own graphics mode independent of the main graphics window, so when drawing to a sprite the graphics mode defaults to NORMAL (and when calling SPRITE END and returning to the main graphics window, the main graphics mode is preserved). This fact can be used to create a sprite that is filled with a second color by using GRAPHICS CLEAR R, G, B, A, which doesn't require the use of FILL COLOR and FILL ALPHA.
  3. Stamping a sprite is dependent on the graphics mode, so we can stamp the sprite from #2 over the pixels drawn in #1, read the resulting R, G, B, and alpha values, and then determine the graphics mode.
The above steps could be done several times to systematically walk through each mode or group of related modes, but instead, I wanted to find two RGBA values that when combined would result in completely unique RGBA values for each graphics mode. Through trial and error, I found two colors that would give me this, so those two colors are hardcoded into the library and the resulting RGBA values for each graphics mode are also hardcoded.

Re: Save/Restore the GRAPHICS MODE

Posted: Thu Aug 16, 2018 8:09 am
by rbytes
Nicely done, matt7.

It seems to me that there is no limit to the ingenuity that can be applied in SmartBASIC to achieve almost any function imaginable. That is a credit to its creator, Mr. Kibernetik.