duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

commit 2efce296a641f7d8802b3175e26a6badadf8a6e7
parent 8b6f030f0a4b88eff65397aa571bc87da9b13b22
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Sun, 25 Dec 2022 10:14:39 -0500

sys/screen: new subsystem

See doc/screen

Diffstat:
Mfs/doc/dirs.txt | 2+-
Afs/doc/screen.fs | 44++++++++++++++++++++++++++++++++++++++++++++
Mfs/drv/pc/vesa.fs | 37+++++++++++++++++++++++++------------
Mfs/emul/uxn/gui.fs | 25+++++++++++++------------
Afs/gr/draw.fs | 17+++++++++++++++++
Dfs/sys/draw.fs | 15---------------
Afs/sys/screen.fs | 21+++++++++++++++++++++
Mfs/xcomp/i386/pc/init.fs | 3++-
8 files changed, 123 insertions(+), 41 deletions(-)

diff --git a/fs/doc/dirs.txt b/fs/doc/dirs.txt @@ -21,8 +21,8 @@ a wide root directory structure based on general topics of the included code. /drv Drivers /emul Emulators /fs Filesystems +/gr Graphics /lib Miscellanous little routines -/pic Picture processing /sys Subsystems /tests Automated tests /text Text processing diff --git a/fs/doc/screen.fs b/fs/doc/screen.fs @@ -0,0 +1,44 @@ +# Screen subsystem + +The screen subsystem represents a matrix of pixels on a screen, which allows us +to draw graphics. The screen can be activated and deactivated to switch between +graphical and text modes, if the underlying hardware supports this. + +This subsystem rests on a hardware specific driver that takes care of the gory +details. The screen subsystem doesn't handle configuration of the display, which +has to be done directly through the driver. + +The screen subsystem defines the Screen structure as well as a "screen" +structbind to it. During initialization, what you'll want to do is create an +instance of the Screen from the driver and bind it to "screen". + +## Driver implementation + +To implement the screen, we need an underlying driver to extend it and implement +its methods, namely: + +:activate ( self -- ) + Enable the graphics mode. We expect this word to set appropriate fields such + as "width" and "height". + +:deactivate ( self -- ) + If the hardware supports it, bring back the display to text mode. + +:pixel' ( x y self -- a ) + Yield the address corresponding to the specified x and y coordinates. + +:rgbcolor ( r8 g8 b8 self -- n ) + Transform the RGB color into a number corresponding to the in-memory format. + +## API + +Fields: + +width Screen width +height Screen height +bpp Screen bits per plane + +Methods: + +:pixel! ( color a self -- ) + Set a pixel at address "a" (from ":pixel'") to "color" (from ":rgbcolor"). diff --git a/fs/drv/pc/vesa.fs b/fs/drv/pc/vesa.fs @@ -1,5 +1,7 @@ \ VESA driver \ TODO: for now, we only support 24bpp modes +require /sys/screen.fs +?f<< /drv/pc/vga.fs ?f<< /lib/fmt.fs struct[ VBEInfo @@ -95,17 +97,28 @@ here VBEModeInfo SZ allot structbind VBEModeInfo _curmode drop rdrop begin ( -1 ... ) dup 0>= while _.mode repeat ( -1 ) drop ; -: vesamode! ( modenum -- ) - dup _modeinfo _curmode :self VBEModeInfo SZ move - 0 swap $4000 or $4f02 int10h ( di bx ax ) - $4f = _assert 2drop ; +$112 value vesamode -\ API -: scrwidth _curmode width ; -: scrheight _curmode height ; : pixelbytes _curmode bpp >> >> >> ; -: pixel' ( x y -- a ) - _curmode pitch * swap pixelbytes * + _curmode framebuffer + ; -\ TODO: support more than 24bpp -: rgbcolor ( r8 g8 b8 -- n ) swap 8 lshift or swap 16 lshift or ; -: pixel! ( color a -- ) over >r 16b !+ r> 16 rshift swap c! ; + +extends Screen struct[ VESAScreen + : _activate ( self -- ) + vesamode _modeinfo _curmode :self VBEModeInfo SZ move + 0 vesamode $4000 or $4f02 int10h ( self di bx ax ) + $4f = _assert 2drop ( self ) + _curmode width over to width + _curmode height over to height + _curmode bpp swap to bpp ; + + : _deactivate ( self -- ) drop vgatext! ; + + : _pixel' ( x y self -- a ) drop + _curmode pitch * swap pixelbytes * + _curmode framebuffer + ; + + \ TODO: support more than 24bpp + : _rgbcolor ( r8 g8 b8 self -- color ) drop + swap 8 lshift or swap 16 lshift or ; + + : :new ( -- screen ) + :newbase ['] _activate , ['] _deactivate , ['] _pixel' , ['] _rgbcolor , ; +]struct diff --git a/fs/emul/uxn/gui.fs b/fs/emul/uxn/gui.fs @@ -1,6 +1,7 @@ \ Varvara GUI devices implementation -require /sys/draw.fs +require /sys/screen.fs ?f<< /lib/bit.fs +?f<< /gr/draw.fs ?f<< /emul/uxn/varvara.fs \ FG Mask: to properly handle FG/BG logic, we need to know which pixels are @@ -11,7 +12,7 @@ require /sys/draw.fs create _fgmask FGMASKSZ allot : _fg' ( x y -- bit a ) - scrwidth * + 8 /mod ( bit a ) _fgmask + ; + screen width * + 8 /mod ( bit a ) _fgmask + ; : _fg! ( x y id -- ) >r _fg' dup c@ ( bit a n ) rot r> if bit1! else bit0! then ( a n ) @@ -26,20 +27,20 @@ create _fgmask FGMASKSZ allot 0 uxn_dev Device dat 8 + ( 'r ) dup short@ r@ _extract ( 'r r8 ) swap 1+ 1+ dup short@ r@ _extract ( r8 'g g8 ) - swap 1+ 1+ short@ r> _extract ( r8 g8 b8 ) rgbcolor ; + swap 1+ 1+ short@ r> _extract ( r8 g8 b8 ) screen :rgbcolor ; : _drawpixel ( x y pixel -- ) 3 and screencolor ( x y color ) - rot> pixel' pixel! ; + rot> screen :pixel' screen :pixel! ; : _drawlayer ( x y pixel fg? -- ) if >r 2dup r@ _fg! r> _drawpixel else >r 2dup _fg? if 2drop rdrop else r> _drawpixel then then ; :c void _drawlayer(ushort x, ushort y, uchar pixel, int fg); : screendei ( dev port -- c ) case - $2 of = drop scrwidth 8 rshift endof - $3 of = drop scrwidth $ff and endof - $4 of = drop scrheight 8 rshift endof - $5 of = drop scrheight $ff and endof + $2 of = drop screen width 8 rshift endof + $3 of = drop screen width $ff and endof + $4 of = drop screen height 8 rshift endof + $5 of = drop screen height $ff and endof Device dat r@ + c@ endcase ; : _pixel ( dev -- ) >r \ V1=dev @@ -100,7 +101,7 @@ create _fgmask FGMASKSZ allot : screendeo ( dev port -- ) 0 to@! rgbchanged if \ we need to fill the screen with the new color - 0 screencolor scrwidth scrheight 0 0 drawrect then + 0 screencolor screen width screen height 0 0 drawrect then case ( dev ) \ V1=case $e of = _pixel endof $f of = _sprite endof @@ -108,6 +109,7 @@ create _fgmask FGMASKSZ allot \ Check for key presses and return whether the GUI program should exit (when ESC \ is pressed). +\ TODO depend on a more generic version ps2@? : controllerloop ( -- f ) ps2@? if $8 uxn_dev >r \ V1=dev @@ -123,13 +125,12 @@ create _fgmask FGMASKSZ allot r> Device dat short@ ?dup if uxn_exec then ( f ) else 0 then ; -\ TODO depend on more generic versions of vesamode! vgatext! and ps2@? : gui_init _fgmask FGMASKSZ 0 fill $2 ['] screendei ['] screendeo uxn_set_dev - $112 vesamode! ; + screen :activate ; -: gui_deinit vgatext! ; +: gui_deinit screen :deactivate ; : uxn_gui ( -- ) uxn_init varvara_init gui_init $100 uxn_exec begin ( ) diff --git a/fs/gr/draw.fs b/fs/gr/draw.fs @@ -0,0 +1,17 @@ +require /sys/screen.fs + +\ TODO: "pixelbytes" is specific to drv/pc/vesa and is the wrong approach +\ anyways. +: drawrect ( color w h x y -- ) + >r >r rot> >r >r \ V1=y V2=x V3=w V4=color + ( h ) >r begin ( ) + V2 V1 screen :pixel' ( a ) V3 >r begin ( a ) + V4 over screen :pixel! pixelbytes + next ( a ) drop + 1 to+ V1 next + rfree ; + +: recttest + 255 0 0 screen :rgbcolor ( color ) + 42 42 ( color w h ) + screen width >> 21 - + screen height >> 21 - ( color w h x y ) drawrect ; diff --git a/fs/sys/draw.fs b/fs/sys/draw.fs @@ -1,15 +0,0 @@ -\ Draw subsystem - -: drawrect ( color w h x y -- ) - >r >r rot> >r >r \ V1=y V2=x V3=w V4=color - ( h ) >r begin ( ) - V2 V1 pixel' ( a ) V3 >r begin ( a ) - V4 over pixel! pixelbytes + next ( a ) drop - 1 to+ V1 next - rfree ; - -: recttest - 255 0 0 rgbcolor ( color ) - 42 42 ( color w h ) - scrwidth >> 21 - - scrheight >> 21 - ( color w h x y ) drawrect ; diff --git a/fs/sys/screen.fs b/fs/sys/screen.fs @@ -0,0 +1,21 @@ +\ Screen subsystem. see doc/screen + +struct[ Screen + sfield width + sfield height + sfield bpp + smethod :activate ( self -- ) + smethod :deactivate ( self -- ) + smethod :pixel' ( x y self -- a ) + smethod :rgbcolor ( r8 g8 b8 self -- n ) + + \ Creates the first part of the screen structure, but leaves the method fields + \ to the caller. + : :newbase ( -- partial-screen ) here 0 , 0 , 0 , ; + + \ TODO: support more than 24bpp + : :pixel! ( color a self -- ) + drop over >r 16b !+ r> 16 rshift swap c! ; +]struct + +0 structbind Screen screen diff --git a/fs/xcomp/i386/pc/init.fs b/fs/xcomp/i386/pc/init.fs @@ -59,5 +59,6 @@ f<< /sys/loop.fs f<< /drv/pc/a20.fs a20$ +f<< /sys/screen.fs f<< /drv/pc/vesa.fs -f<< /sys/draw.fs +VESAScreen :new ' screen rebind