commit 4a14081337b37338ed78f5f44582fa0008b8e2cb
parent bc37867cd095f942b7f204c41e2ab24d1ad48a53
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Sat, 31 Dec 2022 20:32:44 -0500
gr/plane: new unit
see doc/gr/plane
Diffstat:
13 files changed, 132 insertions(+), 74 deletions(-)
diff --git a/fs/doc/gr/color.txt b/fs/doc/gr/color.txt
@@ -37,3 +37,7 @@ COLOR_RGB24 = $01
r8g8b8>rgb24 ( r8 g8 b8 -- n )
Convert 3 8-bit RGB components into a COLOR_RGB24 encoding.
+
+colorbpp ( id -- bpp )
+ Returns the bpp (bits per plane) value, that is, the number of bits that each
+ pixel of that encoding takes, for the specified encoding ID.
diff --git a/fs/doc/gr/plane.txt b/fs/doc/gr/plane.txt
@@ -0,0 +1,41 @@
+# Plane
+
+A plane is a filled Rect (gr/rect). It extends Rect and adds a color buffer to
+it, one color per pixel. The size of the buffer depends on its color encoding
+(see gr/color).
+
+The buffer is a sequence of horizontal lines with each line being "pitch" bytes
+in size, beginning with the top line. Each line is a sequence of pixels, with
+the size in bytes of each pixel depending on the color encoding, beginning with
+the leftmost pixel.
+
+Drawing on a plane is stateful. You set "tx" and "ty" (your target point), set
+the active color with the "color" field and then call the appropriate drawing
+method.
+
+## API
+
+Fields:
+
+encoding A color encoding ID from gr/color
+pitch Size in bytes of each line
+tx Target point X
+ty Target point Y
+color Color that is currently drawn
+buffer Pointer to the pixel buffer
+
+Methods:
+
+:new ( width height encoding -- plane )
+ Create a new plane and calculate pitch from color encoding. Does not allocate
+ a buffer and initializes it to 0.
+
+:allotbuf ( self -- )
+ Allocate a new buffer of the proper size (considering height and pitch) and
+ set "buffer" to it.
+
+:pixel! ( self -- )
+ Set a pixel at tx,ty to the value of field "color".
+
+:fill ( width height self -- ) \ TODO
+ Fill the area in the rect tx,ty,width,height with field "color".
diff --git a/fs/doc/gr/rect.fs b/fs/doc/gr/rect.txt
diff --git a/fs/doc/sys/screen.fs b/fs/doc/sys/screen.fs
@@ -1,42 +0,0 @@
-# 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.
-
-## API
-
-Fields:
-
-width Screen width
-height Screen height
-bpp Screen bits per plane
-color Color (from gr/color) that will be drawn
-
-Methods:
-
-:pixel! ( x y self -- )
- Set a pixel at x,y to the value of field "color".
diff --git a/fs/doc/sys/screen.txt b/fs/doc/sys/screen.txt
@@ -0,0 +1,29 @@
+# Screen subsystem
+
+The screen subsystem represents a Plane (gr/plane) drawn on a physical screen
+device. 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 Plane fields
+ such as width, height, encoding, pitch and buffer.
+
+:deactivate ( self -- )
+ If the hardware supports it, bring back the display to text mode.
+
+## API
+
+The Screen, except for driver method, has no additional API compared to Plane.
diff --git a/fs/drv/pc/vesa.fs b/fs/drv/pc/vesa.fs
@@ -99,8 +99,6 @@ here VBEModeInfo SZ allot structbind VBEModeInfo _curmode
$112 value vesamode
-: pixelbytes _curmode bpp >> >> >> ;
-
extends Screen struct[ VESAScreen
: _activate ( self -- )
vesamode _modeinfo _curmode :self VBEModeInfo SZ move
@@ -108,13 +106,12 @@ extends Screen struct[ VESAScreen
$4f = _assert 2drop ( self )
_curmode width over to width
_curmode height over to height
- _curmode bpp swap to bpp ;
+ _curmode pitch over to pitch
+ _curmode framebuffer swap to buffer ;
: _deactivate ( self -- ) drop vgatext! ;
- : _pixel' ( x y self -- a ) drop
- _curmode pitch * swap pixelbytes * + _curmode framebuffer + ;
-
: :new ( -- screen )
- :newbase ['] _activate , ['] _deactivate , ['] _pixel' , ;
+ 0 0 COLOR_RGB24 Screen :new
+ ['] _activate , ['] _deactivate , ;
]struct
diff --git a/fs/emul/uxn/gui.fs b/fs/emul/uxn/gui.fs
@@ -29,7 +29,8 @@ create _fgmask FGMASKSZ allot
swap 1+ 1+ dup short@ r@ _extract ( r8 'g g8 )
swap 1+ 1+ short@ r> _extract ( r8 g8 b8 ) r8g8b8>rgb24 ;
: _drawpixel ( x y pixel -- )
- 3 and screencolor to screen color ( x y ) screen :pixel! ;
+ 3 and screencolor to screen color ( x y )
+ to screen ty to screen tx 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 ;
@@ -100,7 +101,8 @@ create _fgmask FGMASKSZ allot
: screendeo ( dev port -- )
0 to@! rgbchanged if \ we need to fill the screen with the new color
- 0 screencolor screen width screen height 0 0 drawrect then
+ 0 screencolor to screen color
+ screen width screen height 0 0 drawrect then
case ( dev ) \ V1=case
$e of = _pixel endof
$f of = _sprite endof
diff --git a/fs/gr/color.fs b/fs/gr/color.fs
@@ -1,3 +1,5 @@
$01 const COLOR_RGB24
: r8g8b8>rgb24 ( r8 g8 b8 -- n ) swap 8 lshift or swap 16 lshift or ;
+
+: colorbpp ( id -- bpp ) drop 24 ;
diff --git a/fs/gr/draw.fs b/fs/gr/draw.fs
@@ -2,11 +2,12 @@ require /sys/screen.fs
?f<< /gr/color.fs
: drawrect ( w h x y -- )
- >r >r \ V1=y V2=x
- ( h ) >r begin ( w ) dup >r begin ( w )
- V2 r@ + 1- V1 screen :pixel! next
- 1 to+ V1 next ( w )
- drop rfree ;
+ to screen ty ( w h x )
+ swap >r begin ( w x )
+ dup to screen tx over >r begin ( w x )
+ screen :pixel! 1 to+ screen tx next
+ 1 to+ screen ty next ( w x )
+ 2drop ;
: recttest
255 0 0 r8g8b8>rgb24 to screen color
diff --git a/fs/gr/plane.fs b/fs/gr/plane.fs
@@ -0,0 +1,33 @@
+\ This code is currently used to write directly to the memory buffer of
+\ graphical cards. Maybe that at some point, this scheme will break, but we'll
+\ adjust then.
+
+?f<< /gr/rect.fs
+?f<< /gr/color.fs
+
+\ TODO: support more than 24bpp
+extends Rect struct[ Plane
+ sfield encoding
+ sfield pitch
+ sfield tx
+ sfield ty
+ sfield color
+ sfield buffer
+
+ : _colorbytes ( id -- nbytes ) colorbpp >> >> >> ;
+
+ : :new ( width height encoding -- plane )
+ >r >r >r 0 0 r> r> Rect :new ( rect )
+ r> ( encoding ) dup , _colorbytes over Rect width * ( pitch ) ,
+ 0 ( tx ) , 0 ( ty ) , 0 ( color ) , 0 ( buffer ) , ;
+
+ : :allotbuf ( self -- ) >r \ V1=self
+ here r@ pitch r@ height * allot r> to buffer ;
+
+ : _addr ( self -- a ) >r \ V1=self
+ r@ ty r@ pitch * r@ encoding _colorbytes r@ tx * + r> buffer + ;
+
+ : :pixel! ( self -- ) >r \ V1=self
+ r@ color r@ _addr 16b !+ r> color 16 rshift swap c! ;
+
+]struct
diff --git a/fs/sys/screen.fs b/fs/sys/screen.fs
@@ -1,19 +1,9 @@
-struct[ Screen
- sfield width
- sfield height
- sfield bpp
- \ TODO: support more than 24bpp
- sfield color
+?f<< /gr/plane.fs
+?f<< /gr/color.fs
+
+extends Plane struct[ Screen
smethod :activate ( self -- )
smethod :deactivate ( self -- )
- smethod :pixel' ( x y self -- a )
-
- \ Creates the first part of the screen structure, but leaves the method fields
- \ to the caller.
- : :newbase ( -- partial-screen ) here 0 , 0 , 0 , 0 , ;
-
- : :pixel! ( x y self -- ) >r \ V1=self
- r@ :pixel' r@ color swap 16b !+ r> color 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,6 +59,7 @@ f<< /sys/loop.fs
f<< /drv/pc/a20.fs
a20$
+f<< /sys/scratch.fs
f<< /sys/screen.fs
f<< /drv/pc/vesa.fs
VESAScreen :new ' screen rebind
diff --git a/fs/xcomp/init.fs b/fs/xcomp/init.fs
@@ -1,7 +1,7 @@
\ Common part of init.fs. Machine-independent
\ As a user, you'll want to adapt this to your needs.
-f<< sys/scratch.fs
-f<< lib/fmt.fs
-f<< lib/diag.fs
-f<< sys/rdln.fs
+?f<< /sys/scratch.fs
+f<< /lib/fmt.fs
+f<< /lib/diag.fs
+f<< /sys/rdln.fs
: init S" Dusk OS\n" stype .free rdln$ stdio$ quit ;