148 lines
3.2 KiB
Forth
Executable File
148 lines
3.2 KiB
Forth
Executable File
#! /usr/bin/env ueforth
|
|
|
|
\ Copyright 2022 Bradley D. Nelson
|
|
\
|
|
\ Licensed under the Apache License, Version 2.0 (the "License");
|
|
\ you may not use this file except in compliance with the License.
|
|
\ You may obtain a copy of the License at
|
|
\
|
|
\ http://www.apache.org/licenses/LICENSE-2.0
|
|
\
|
|
\ Unless required by applicable law or agreed to in writing, software
|
|
\ distributed under the License is distributed on an "AS IS" BASIS,
|
|
\ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
\ See the License for the specific language governing permissions and
|
|
\ limitations under the License.
|
|
|
|
also graphics
|
|
also structures
|
|
|
|
struct ScanSpan
|
|
ptr field ->next
|
|
ptr field ->edge
|
|
|
|
1024 constant max-scanlines
|
|
create scanlines max-scanlines cells allot
|
|
scanlines max-scanlines cells erase
|
|
0 value free-edges
|
|
|
|
: new-edge ( n next -- a )
|
|
free-edges if
|
|
free-edges dup ->next @ to free-edges
|
|
else
|
|
ScanSpan allocate throw
|
|
then
|
|
{ np }
|
|
np ->next !
|
|
np ->edge !
|
|
np
|
|
;
|
|
: row-span ( y -- a ) cells scanlines + ;
|
|
: add-edge { x y }
|
|
y row-span { yp }
|
|
begin yp @ while
|
|
x yp @ ->edge @ <= if
|
|
x yp @ new-edge yp !
|
|
exit
|
|
then
|
|
yp @ ->next to yp
|
|
repeat
|
|
x yp @ new-edge yp !
|
|
;
|
|
: remove-edge ( y -- x )
|
|
row-span { yp }
|
|
yp @ 0= if 10000 exit then
|
|
yp @ { old }
|
|
yp @ ->edge @
|
|
yp @ ->next @ yp !
|
|
free-edges old ->next !
|
|
old to free-edges
|
|
;
|
|
: draw-row { y }
|
|
begin y row-span @ while
|
|
y remove-edge y remove-edge over - y swap 1 box
|
|
repeat
|
|
;
|
|
: draw-spans max-scanlines 0 do i draw-row loop ;
|
|
|
|
: 2span { a b -- n } a b max a b min - ;
|
|
: 3span { a b c -- n } a b max c max a b min c min - ;
|
|
: raw-bezier 0 0 { x1 y1 x2 y2 x3 y3 d xn yn }
|
|
y1 d rshift y2 d rshift y3 d rshift 3span 2 < if
|
|
y1 d rshift y3 d rshift 2span if
|
|
y1 y3 = if
|
|
x1 x3 + 2/ d lshift y1 d rshift add-edge
|
|
exit
|
|
then
|
|
y1 y3 < if
|
|
x1 x3 x1 - y1 1 d lshift 1- and y3 y1 - */ - d rshift
|
|
y1 d rshift add-edge
|
|
else
|
|
x3 x1 x3 - y3 1 d lshift 1- and y1 y3 - */ - d rshift
|
|
y3 d rshift add-edge
|
|
then
|
|
then
|
|
else
|
|
x1 x2 2* + x3 + to xn
|
|
y1 y2 2* + y3 + to yn
|
|
x1 4* y1 4* x1 x2 + 2* y1 y2 + 2* xn yn d 2 + recurse
|
|
xn yn x2 x3 + 2* y2 y3 + 2* x3 4* y3 4* d 2 + recurse
|
|
then
|
|
;
|
|
|
|
(
|
|
: line 0 0 { x1 y1 x2 y2 dx dy }
|
|
y1 y2 > if
|
|
y1 y2 to y1 to y2
|
|
x1 x2 to x1 to x2
|
|
then
|
|
y2 y1 - 0.>> to dy
|
|
x2 x1 - to dx
|
|
dy 0 ?do
|
|
x1 dx i dy */ + 0.>> y1 0.>> i + add-edge
|
|
loop
|
|
;
|
|
)
|
|
|
|
: bezier 0 raw-bezier ;
|
|
|
|
: line ( x1 y1 x2 y2 ) 2dup bezier ;
|
|
|
|
0 value pen-x 0 value pen-y
|
|
: move-to { x y } x to pen-x y to pen-y ;
|
|
: line-to { x y } pen-x pen-y x y line x y move-to ;
|
|
: bezier-to { x' y' x y } pen-x pen-y x' y' x y bezier x y move-to ;
|
|
|
|
-1 -1 window
|
|
|
|
$ff0000 constant red
|
|
$ffff00 constant yellow
|
|
$ffffff constant white
|
|
$000000 constant black
|
|
$0000bb constant blue
|
|
|
|
: draw
|
|
black to color 0 0 width height box
|
|
yellow to color 0 0 width 2/ height 2/ box
|
|
|
|
red to color
|
|
width 3 / 100 move-to
|
|
mouse-x 1 mouse-x mouse-y bezier-to
|
|
mouse-x 2/ 1 line-to
|
|
300 200 200 400 bezier-to
|
|
1 mouse-y 2 3 */ line-to
|
|
width 3 / 100 line-to
|
|
blue to color draw-spans
|
|
|
|
flip
|
|
;
|
|
|
|
: run
|
|
begin
|
|
poll
|
|
IDLE event = if draw then
|
|
event FINISHED = until
|
|
bye
|
|
;
|
|
run
|