'----------------------------------------------------------------------------------------------------------------------------------------------------
' DrawFrame + DrawPlayer demonstration
'
' ver. 1.0.1
' by Daniel Janec, 2020
' DrawFrame sub adds the "K", "V" and "Q" statements to the Draw sub statement set to handle mostly animation
' Syntax:
' DrawFrame ( sourceString$, frameTime, size )
' Parameters:
' sourceString$ - a string containing Draw statements and new/modified Drawferame statements described bellow
' frameTime - in seconds, specifying the time, in which animated statements are drawed
' size - draw magnifying factor, 1 is original size, 2 is double, 0.5 is half size etc.
'
' Syntax of the new or modified DrawFrame statements:
' K [id [ _ idRelativeK ] : ] [+/-] startTime; [+/-] endTime [ [# / *] [repeatCount] ]
' Defines time interval "id" used for grapihical statements animation, starting at strartTime sec, ending at endTime sec,
' optionaly repeating animation repeatCount times (or indefinetly if omitted) by using "*" for straight repeat or "#" for back-and-forth repeat.
' Also sets this interval for next animated statements.
' If "_" is used, the "+" or "-" sign can by used in time definition to set startTime/endTime relatively to another defined K interval "idReativeK".
'
' K [id]
' Sets defined interval "id" for next animated statements
' Following statements written in form X [!] x1,y1; [!] x2;y2 (e.g. M 100,100;200;200) will be animated accordingly to the frametime parameter of Drawframe; acquiring x1, y1 values at startTime and x2, y2 at endTime
'
' Q [id] [ : startTime [ ; endTime ] ] ] [ * [repeatCount] ] [ ( commandSequenceString ) ]
' Defines the "id" named sequence of statements commandSequenceString and repeats it repeatCount times.
' If startTime and/or endTime are defined, this sequence does not apply outside of this time interval.
'
' V angle
' Turns the draw direction relatively to actual direction by <angle> degrees
'
' S size %
' Extends the S statement usage by % option.
' Sets the drawing size relatively to the last absolute size set - to the <size>% of it
'
' DrawPlayer controls:
' Left / Right arrow: skip back / forward in time
' Up / Down arrow: increase / decrease playback speed
' Space: pause / play
' R: toggle reverse playback on/off
' + / -: increase / decrease size picture size
'
'----------------------------------------------------------------------------------------------------------------------------------------------------
'----------------------------------------------------------------------------------------------------------------------------------------------------
' The Tree string
'----------------------------------------------------------------------------------------------------------------------------------------------------
leaf1$ = "Q1:17;* (V30 K11:17;17.5 S1%;!40% K11:17.5;19 S!40%;50% V-90 K12 V-10;10 U50 V-800U20 V30U20 V30U20 V20U40 V20U40 V20U50 V100U50 V20U40 V20U40 V20U20 V30U20 V30U20 V-800 K12 U50;47 V180 K12 V10;-10 V90 V-30 S100%)"
smallimb2$ = "Q2:7;* (V-90 K22:7;14 S1%;100% U100 K23:40;44 BM+0,+0;-4000,-100 K12:22;22.2# Q1 K23 BM+0,+0;+4000,+100 K22 S1%;100% U200 K23:47;49 BM+0,+0;-4000,-100 K12:22.1;22.3# Q1 K23 BM+0,+0;+4000,+100 K22 S1%;100% U100 V90 U10 V90 V-90 K23:49;51 BM+0,+0;-4000,-100 K12:22.2;22.4# Q1 K23 BM+0,+0;+4000,+100 K22 S1%;100% V90 U200 V-60 K23:49.5;51.5 BM+0,+0;-4000,-100 K12:22.3;22.5# Q1 K23 BM+0,+0;+4000,+100 K22 S1%;100% V60 U200 V-90 S100%)"
biglimb3$ = "Q3:4;* (V-88 K31:4.0;11 S1%;100% U250 K32:25;25.4# V30;50 Q2 K32 V-30;-50 K31 S1%;100% U200 V88 K33:25.1;25.5# V-35;-15 Q2 K33 V35;15 V88 K34:25.2;25.6# V-40;-20 Q2 K34 V40;20 K31 S1%;100% U450 V92 V-180 S100%)"
trunk4$ = "Q4 (K41:0;10 S1%;100% U500 K42:28.9;29.3# V30;40 Q3 K42 V-30;-40 K41 S1%;100% U400 V88 K43:29;29.4# V0;5 Q3 K43 V0;-5 V88 K41 S1%;100% U200 K44:29.1;29.5# V-30;-20 Q3 K44 V30;20 K41 S1%;100% M+0,+0;-10,-10 K45:17;17.6 M+0,+0;-25,-20 U700 V92 V92 S100%)"
cloud5$ = "Q51:17; (Q5*8(U30-V30) S150% V200 Q5*6 S130% V230 Q5*6 S120% V210 Q5*8 S160% V220 Q5*6 S160% V235 Q5*6) S2"
clip$ = "S2 BM1200,1000" + leaf1$ + smallimb2$ + biglimb3$ + "K1:0;10#C35;52 L400 K101:24.9;25.3# M-3,-0;+3,+0 " + trunk4$ + " K101 M+3,+0;-3,-0 M910,1000 L400 K102:17;23 BM2500,50;1400,100 TA90 K51:0;0.3# S2;2.05 " + cloud5$ + " TA0 K103:20;30 BM0,0 BM-800,+100;+500,+300 TA90 K51:0;0.3# S3;3.05 Q51"
'----------------------------------------------------------------------------------------------------------------------------------------------------
' Examples of clip strings
'----------------------------------------------------------------------------------------------------------------------------------------------------
'clip$ = "BM500,300 Q1*12( U20 V30 )" '1 circle
'clip$ = "B M500,300 Q2*6( BU100 Q1*12( U20 V30 ) BD100 V60 )" '6 circles queued in round
'clip$ = "B M500,300 K1:0;3# V0;360 Q2*6( BU50 Q1*12( U10 V30 ) BD50 V60 )" '6 circles queued in round rotating
'clip$ = "B M500,300 K1:0;3* V0;360 Q2*6( K2:0;2# BU50;200 Q1*12( U10 V30 ) BD50;200 V60 )" '6 circles queued in round rotating and swingigng towards centre
'clip$ = "B M500,300 K2:0;2# K1:0;3* V0;360 Q2*6( K2_2:+0.2;+0.2# BU50;200 Q1*12( U10 V30 ) BD50;200 V60 )" '6 circles queued in round rotating and swingigng towards centre in different phase
'clip$ = "B M500,300 K2:0;1# K1:0;3* V0;360 Q2*6( K2_2:+0.2;+0.2# BU50;200 S100%;300% Q1*12( U10 V30 ) S100% BD50;200 V60 )" '6 circles queued in round rotating and swingigng towards centre in different phase changing size
'----------------------------------------------------------------------------------------------------------------------------------------------------
' The Dog string
'----------------------------------------------------------------------------------------------------------------------------------------------------
' Q0 - dog positioning
' Q2 - dog walking
' Q3 - dog head shape, Q31 - head running
' Q4 - dog ear shape, Q41 - ear running
' Q5 - dog tail shape, Q51 - tail running
' Q7 - dog foot shape, Q71 - foot running
'clip$ = "S2 BM1900,518 L3500 Q0*(K0:0;10 BM1800,400;300,400 TA0) Q7*(L40 D20 R40 U20) Q71*(BM+20,+180 K71_71:-0.5;-0.5* K72_71:+0;-0.5# K71 V0;360 BD40 V360;0 K72 V-10;30 Q7) K41:0;0.25#"+_
' "Q4*(L40M+20,-40M+20,40) Q41*(K41_41:+0.05;+0.05# V-35;15 Q4 V35;-15) " + _
' "Q5*(R50 U40 L50 D40) Q51*(K51:0;0.25# V10;30 BM+100,-40 Q5)" + _
' "Q3*(BM-20,-110 L200D120R200U120 BM-70,+30 R20D20L20U20 BM-120,-20 R30D30L30U30) Q31*(K32:4;4.5 V0;50 K33_32:+3;+2.8 V!0;-50 K32 BM+0,0;-50,20 K33 BM+0,0;+50,-20 K31:0;0.25# BD-20;10 Q3 BM+140,-30 Q41 BR60 Q41) "+ _
' "Q2(Q0 K21:-0.125;0.125# BU0;40 D150R250U150L250 BM+200,+70 Q51 K71:0;1* Q0 Q71 Q0 Q71 Q0BM+250,0 Q71 Q0BM+250,+0 Q71 Q0 Q31)
'----------------------------------------------------------------------------------------------------------------------------------------------------
DrawPlayer clip$
, 0, 60, 30, _WIDTH / 1920, 1
'----------------------------------------------------------------------------------------------------------------------------------------------------
'Player demonstration
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB DrawPlayer
(movie$
, playfromtime
, playtotime
, fps
, size
, speed
) t = playfromtime * fps
dir = 1
_PRINTSTRING (0, 5), "size:" + STR$(RoundDec
(size
, 2)) + " speed:" + STR$(dir
* speed
) + "x time:" + STR$(RoundDec
(t
/ fps
* speed
, 2)) DrawFrame movie$, t / fps * speed, size
IF k
= 20480 AND speed
> 0.1 THEN speed
= speed
/ 2: t
= t
* 2 IF k
= 18432 AND speed
< 100 THEN speed
= speed
* 2: t
= t
/ 2 IF k
= 19200 THEN t
= t
- 2 * fps
IF k
= 19712 THEN t
= t
+ 2 * fps
IF k
= 43 THEN size
= size
+ 0.01 IF k
= 45 THEN size
= size
- 0.01 t = t + dir
IF size
< 0.01 THEN size
= 0.01 IF t
> playtotime
* fps
/ speed
THEN t
= playtotime
* fps
/ speed
'----------------------------------------------------------------------------------------------------------------------------------------------------
'Sub & Function definitions
'----------------------------------------------------------------------------------------------------------------------------------------------------
CONST CMD_LEN_MAX
= 1000 'max. command sequence length definable using statement Q()
TYPE TKFset
'Key frame set type
TYPE TCmdSeq
'Command Sequence
TYPE TDrawState
'global Draw state SrcLen
AS LONG 'Source string length SrcPos
AS LONG 'Source string last read char position ActKFSetIdx
AS INTEGER 'KFset index applied to actual statement if KF enabled ActTA
AS SINGLE 'Actual parameter value of previous TA statement (in degrees) ActS
AS SINGLE 'Actual parameter value of previous "S" statement usage ErrDsc
AS STRING * 50 'Error description
DIM c$
, code$
, label$
, x1$
, y1$
, x2$
, y2$
, sgnx1$
, sgny1$
, rep$
, repcnt$
, par$
, exclfrom$
, exclto$
, csstart$
, percx1$
, percx2$
DIM stat$
, ParseStatement$
' Actual statement being read from source draw string
SrcStr = SrcStrOrig
TrgStr = ""
stat$ = ""
prevchar = ""
SrcStr = SrcStr + "&"
DS.SrcPos = 0
DS.ActKFSetIdx = 0
DS.ActTA = 0
DS.ActS = 4
DS.SrcPos = DS.SrcPos + 1
char
= MID$(SrcStr
, DS.SrcPos
, 1) '-------------------------------------------Parser begin-----------------------------------------------------------
stat$ = stat$ + "&"
ParseStatement$ = ""
readstate = 0
KFenabled = 0
omitstate = 0
par$ = "": code$ = "": label$ = "": x1$ = "": y1$ = "": x2$ = "": y2$ = "": sgnx1$ = "": sgny1$ = "": sgnx2$ = ""
rep$ = "": repcnt$ = "": par$ = "": exclfrom$ = "": exclto$ = "": csstart$ = "": percx1$ = "": percx2$ = "": rel$ = "": krel$ = ""
x = 0: y = 0: x1 = 0: y1 = 0: x2 = 0: y2 = 0: kid = 0: csid = 0
code$ = code$ + c$
label$ = par$: par$ = "": rel$ = c$: readstate = 11
label$ = par$: par$ = "": readstate = 1
x1$ = par$: par$ = "": readstate = 2
x1$ = par$: par$ = "": readstate = 3
KFenabled = 1
exclfrom$ = c$
par$ = par$ + c$
sgnx1$ = c$
par$ = par$ + c$
percx1$ = percx1$ + c$
label$ = par$: par$ = "": rep$ = c$: readstate = 5
label$ = par$: csstart$ = c$: readstate = 10
x1$ = par$: par$ = "": readstate = 10
par$ = par$ + c$
krel$ = par$: par$ = "": readstate = 1
x1$ = par$: par$ = "": readstate = 2
x1$ = par$: par$ = "": readstate = 3
KFenabled = 1
exclfrom$ = c$
par$ = par$ + c$
sgnx1$ = c$
par$ = par$ + c$
percx1$ = percx1$ + c$
x1$ = par$: csstart$ = c$: readstate = 10
x1$ = par$: par$ = "": readstate = 10
y1$ = par$: par$ = "": readstate = 3
KFenabled = 1
par$ = par$ + c$
sgny1$ = c$
par$ = par$ + c$
y1$ = par$: par$ = "": readstate = 10
x2$ = par$: par$ = "": readstate = 4
x2$ = par$: par$ = "": rep$ = c$: readstate = 5
x2$ = par$: par$ = "": rep$ = c$: readstate = 5
exclto$ = c$
par$ = par$ + c$
sgnx2$ = c$
par$ = par$ + c$
percx2$ = percx2$ + c$
x2$ = par$: csstart$ = c$: readstate = 10
x2$ = par$: par$ = "": readstate = 10
y2$ = par$: par$ = "": rep$ = c$: readstate = 5
y2$ = par$: par$ = "": rep$ = c$: readstate = 5
CASE "0" TO "9", "+", "-", ".":
par$ = par$ + c$
y2$ = par$: par$ = "": readstate = 10
CASE "0" TO "9", "+", "-", ".":
par$ = par$ + c$
repcnt$ = par$: par$ = "": csstart$ = c$: readstate = 10
repcnt$ = par$: par$ = "": readstate = 10
IF readstate
= 99 THEN DS.ErrDsc
= "Error in statement: " + LEFT$(stat$
, LEN(stat$
) - 1) ELSE DS.ErrDsc
= "" IF x2$
<> "" THEN ' defining KFset tsdelta = 0: tedelta = 0
KFset(kid).id = kid
KFset(kid).defined = 1
IF sgnx1$
<> "" THEN tsdelta
= KFset
(krel
).timestart
IF sgnx2$
<> "" THEN tedelta
= KFset
(krel
).timeend
KFset
(kid
).timestart
= VAL(x1$
) + tsdelta
KFset
(kid
).timeend
= VAL(x2$
) + tedelta
KFset(kid).repeat = rep$
KFset
(kid
).repeatcount
= VAL(repcnt$
) DS.ActKFSetIdx = kid
IF label$
= "" AND x1$
<> "" THEN label$
= x1$
DS.ActKFSetIdx = kid
CmdSeq
(csid
).timestart
= VAL(x1$
) CmdSeq
(csid
).timeend
= VAL(x2$
) CmdSeq(csid).id = csid
IF repcnt$
<> "" THEN CmdSeq
(csid
).repeatcount
= VAL(repcnt$
)
ipos = 0
IF csstart$
= "(" THEN ' defining command sequence parcnt = 1: c$ = ""
DO ' Find corresponding right parenthes in the source string ipos = ipos + 1
c$
= MID$(SrcStr$
, DS.SrcPos
+ ipos
, 1) IF c$
= "(" THEN parcnt
= parcnt
+ 1 IF c$
= ")" THEN parcnt
= parcnt
- 1 LOOP UNTIL (c$
= ")" AND parcnt
= 0) OR DS.SrcPos
+ ipos
>= DS.SrcLen
OR ipos
>= CMD_LEN_MAX
CmdSeq
(csid
).CmdStr
= MID$(SrcStr
, DS.SrcPos
, ipos
) CmdSeq(csid).defined = 1
CmdSeq(csid).defined = 0
ELSE 'Referencing command sequence
IF CmdSeq
(csid
).defined
= 1 THEN 'modify source string if command sequence defined IF CmdSeq
(csid
).repeatcount
> 0 THEN rpt = CmdSeq(csid).repeatcount
rpt = 0
rpt = 1
IF CmdSeq
(csid
).timeend
<> 0 AND (frametime
< CmdSeq
(csid
).timestart
OR frametime
> CmdSeq
(csid
).timeend
) THEN rpt
= 0 IF frametime
< CmdSeq
(csid
).timestart
THEN rpt
= 0 cmdrpt$ = ""
SrcStr
= RTRIM$(cmdrpt$
) + RIGHT$(SrcStr
, DS.SrcLen
- DS.SrcPos
- ipos
+ 1) DS.SrcPos = 0
char = ""
ELSE 'do for other graphics statements kid = DS.ActKFSetIdx
IF KFenabled
= 1 AND KFset
(kid
).defined
= 1 THEN 'change parameters if statement is keyframed fk = (frametime - KFset(kid).timestart) / (KFset(kid).timeend - KFset(kid).timestart)
IF (frametime
>= KFset
(kid
).timestart
AND frametime
<= KFset
(kid
).timeend
) THEN IF x1$
<> "" THEN x1
= x1
+ (x2
- x1
) * fk
IF y1$
<> "" THEN y1
= y1
+ (y2
- y1
) * fk
period
= INT((frametime
- KFset
(kid
).timestart
) / (KFset
(kid
).timeend
- KFset
(kid
).timestart
)) IF (KFset
(kid
).repeat
= "*" OR KFset
(kid
).repeat
= "#") AND (period
< KFset
(kid
).repeatcount
OR KFset
(kid
).repeatcount
= 0) THEN fk = (KFset(kid).timeend - frametime + period * (KFset(kid).timeend - KFset(kid).timestart)) / (KFset(kid).timeend - KFset(kid).timestart)
fk = (frametime - KFset(kid).timestart - period * (KFset(kid).timeend - KFset(kid).timestart)) / (KFset(kid).timeend - KFset(kid).timestart)
IF x1$
<> "" THEN x1
= x1
+ (x2
- x1
) * fk
IF y1$
<> "" THEN y1
= y1
+ (y2
- y1
) * fk
IF KFset
(kid
).repeat
= "#" AND KFset
(kid
).repeatcount
MOD 2 = 0 THEN ELSEIF (frametime
< KFset
(kid
).timestart
AND exclfrom$
<> "!") THEN omitstate = 0
omitstate = 1
x1 = RoundDec(x1, 6)
DS.ActTA = x1
IF (DS.ActTA
> 360) OR (DS.ActTA
< -360) THEN DS.ActTA
= DS.ActTA
+ (DS.ActTA
> 0) * 360 DS.ActTA = DS.ActTA + RoundDec(x1, 6)
IF (DS.ActTA
> 360) OR (DS.ActTA
< -360) THEN DS.ActTA
= DS.ActTA
+ (DS.ActTA
> 0) * 360 code$ = "TA"
x1 = RoundDec(DS.ActTA, 6)
CASE "M", "D", "E", "F", "G", "H", "L", "R", "U":
x1 = RoundDec(x1 * size, 4)
y1 = RoundDec(y1 * size, 4)
x1 = RoundDec(x1 * DS.ActS / 100, 5)
DS.ActS = x1
ParseStatement$ = code$
ParseStatement$
= ParseStatement$
+ sgnx1$
+ LTRIM$(STR$(x1
)) IF y1$
<> "" THEN ParseStatement$
= ParseStatement$
+ "," + sgny1$
+ LTRIM$(STR$(y1
)) ParseStatement$ = ""
''---DEBUG BEGIN-----------
'IF CmdSeq(csid).defined = 1 THEN cmd$ = RTRIM$(CmdSeq(csid).CmdStr) ELSE cmd$ = ""
'PRINT
'PRINT stat$ + " > ", , code$ + "/" + label$ + "/" + x1$ + "/" + y1$ + "/" + x2$ + "/" + y2$ + "/" + exclfrom$ + "/" + exclto$ + "/" + rep$ + "/" + repcnt$
'PRINT "TrgStr: "; TrgStr
'PRINT "SrcStr: "; SrcStr
'PRINT "cmd$: ", cmd$
'PRINT "DS.Srcpos", DS.SrcPos
'PRINT "ParseStatement$: ", ParseStatement$
'IF stat$ = "Q1*(&" OR stat$ = "Q1(&" THEN stopable = 1
'IF stopable THEN
' DO
' LOOP UNTIL _KEYHIT = 32
'END IF
''---DEBUG END-------------
'-------------------------------------------Parser end-----------------------------------------------------------
TrgStr = TrgStr + ParseStatement$
stat$ = ""
stat$ = stat$ + char
prevchar = char
'PRINT SrcStr '---DEBUG code----
'PRINT TrgStr '---DEBUG code----
'----------------------------------------------------------------------------------------------------------------------------------------------------
RoundDec
= _ROUND(x
* 10 ^ n
) / (10 ^ n
)
'----------------------------------------------------------------------------------------------------------------------------------------------------