Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

Advanced search

1025782 Posts in 41109 Topics- by 32713 Members - Latest Member: CarlaWolfe

July 23, 2014, 05:44:19 AM
TIGSource ForumsFeedbackDevLogsWeirwood Grove - a programmable toy
Pages: [1] 2
Author Topic: Weirwood Grove - a programmable toy  (Read 2383 times)
Level 0

View Profile WWW Email
« on: January 04, 2013, 05:54:56 AM »

This project isn't really a game. But as long as it's fun to play with, I hope that doesn't matter.

I've started to develop a simple scripting language that combines concepts from turtle grahpics and L-System. The idea is that by writing a script you control the generation of a line-based drawing.

I hope for my scripts to be easyer to understand then grammar based implementations of L-Systems. Then, the way it's implemented right now you can edit the script in you favorite text editor and whenever you save the interpreter will update. More importantly the interpreter is quite fast, capable of rendering many frames per second and so (thanks to the implementation of a time() function) you can make your drawing animated.

Screencaptured Video http://www.youtube.com/watch?v=6OgOiYmSvYg

Download the application here. Start Grove.exe. Drag&Drop some scripts from the example folder to the application. You can edit the script while Grove executes it and it will adapt at run time. If you want to know more have a look at the tutorial.
« Last Edit: April 28, 2013, 01:48:32 AM by lithander » Logged

Level 10

high-heeled cyberbully

View Profile
« Reply #1 on: January 04, 2013, 07:43:36 AM »

Does it do .gif output? (I'll try it later when I'm on my own computer.)

Level 5

View Profile WWW
« Reply #2 on: January 04, 2013, 09:00:28 AM »

Pretty epic. The second one reminds me of the Julia set.

Level 0

View Profile WWW Email
« Reply #3 on: January 04, 2013, 04:33:55 PM »

Outputting is a really nice idea but unless I find a C++ compatible lib that's easy enough to use I'd rather not bother with the gif codec.

The 2nd image is called Dragon Curve and like the Julia set it could be considered a fractal, I guess.

Level 0

View Profile WWW
« Reply #4 on: January 04, 2013, 06:06:48 PM »

Very nice. I just wrote a similar tool for creating procedural content using C# scripting. For now I've been happy with minimalist code/results/image views, but I can imagine a ton of possible features.

Some ideas:
- Detect numeric literals in code window and provide sliders.
- Show a row of preview panes populated randomly with params (literals?) close to those in your current code, allowing user to pick/navigate to these variations.
- Strange attractors!

Level 0

View Profile WWW Email
« Reply #5 on: January 05, 2013, 05:37:46 AM »

Gears, what you posted about Eval2D sounds realy interesting. Would you consider to release that tool for others to play around with? Does it have dependancies on UnityEngine.dll or is it a stand-alone tool?

I guess the way you did it - selecting and combining components that fit your needs instead of implementing a scripting language from scratch - is a more efficient approach then mine. But my excuse for reinventing the wheel is that I really enjoy doing that low-level stuff like writing a script parser or expressions that are fast to evaluate. I'm currently working on logical expression to be able to add conditions to the script. It's liberating and fun to think of what style of operators I prefered in all the programming languages I've worked with and just use exactly that or a mix. (I'm going with pascal-style logical operators) This is an approach I could never justify to take for a project at work! Smiley

What I'm not sure yet is wether I add some if-then-else operators (including code-block markers e.g. endif) or rather stay assembler-inspired and use some obscure opp-codes to jump and skip instructions in the sequence. Both isn't really intuitive and easy to change on a per-line basis so I'm still pondering alternatives. If anybody has a preference here I'm open for suggestions.

Btw, if you like my LSystem toy or gears Eval2D you should check this out, too: http://www.iquilezles.org/apps/shadertoy/

Level 0

View Profile WWW
« Reply #6 on: January 05, 2013, 07:27:54 PM »

Yeah, I plan to release it soon. It's dependent on Windows/DX9 (WPF) and .NET 4.5, but not Unity.

It's awesome that you're creating your own language. From the little I know about language design, it sounds like your going from the Turing direction to build an assembler-like language rather than from lambda calculus for something more functional. It would be interesting to try both and see which is more intuitive for this. I can also imagine putting a visual editor on top of the language to reach a broader audience.

Level 0

View Profile WWW Email
« Reply #7 on: January 06, 2013, 01:57:45 PM »

My original inspiration was to combine the idea of Turtle Graphics (which maps well to a lot of drawing-related API's) imperative programming and Lindenmayer-Systems. (which I find fascinating but hard to work with the way they are typically notated)

I'm not quite sure how a functional approach would fit into that. I'm not used to working in functional languages. Could you give an example?

Level 0

View Profile WWW
« Reply #8 on: January 07, 2013, 02:07:08 PM »

I could imagine a writing a function f(angle) that returns a function g(point) that calculates a point based on a previous point. f takes an angle parameter and returns a function that calculates a point one unit away from the input point in a direction according to the angle param. Now that we have a function with the signature g(point), we could pass that into another function h that returns a sequence of points by recursively applying g.

It's really just having functions with first class status that can be passed to and returned from other functions, with features like currying or closures to facilitate this. There's also the strong tendency to work with immutable objects, which can make code easier to reason about and safer to write for parallel execution.

Level 0

View Profile WWW Email
« Reply #9 on: January 08, 2013, 02:02:39 PM »

Gears, I fear I was a little unclear. Sad I know the ideas behind functional languages. And I worked with PROLOG enough to know that in there are problems that are a lot easier to solve with a functional approach.

What I meant was that I don't see how they would fit in the context of L-Systems. The interesting part are the production-rules. It intrigues me how complexity emerges from even a simple ruleset. I'm curious to learn how adding features like conditions, chance, context-sensitivity to the productions will effect the expresiveness. And I always wonder how I can design the scripting language so that deliberately tweaking a script towards a desired outcome is as easy and fun as possible. In other words how to add complexity but preserving readability and maintainability.

These are the questions I'm pondering. And I'm not sure how a functional approach would improve things. Parametric grammers (no new idea, Lindenmayer suggested them himself) would go into that direction but I think the readability-cost is quite high.

Promise: My next post will be an progress-update! Smiley

Level 0

View Profile WWW Email
« Reply #10 on: January 17, 2013, 07:03:36 AM »

I captured a Video of the current build.


The most important changes I did in the last days are support for logical expressions and commands that allow flow control. After actually sitting down with pencil and paper for an hour I found that I could get all the behavior you're used to (if-then-else and loops in various flavours) working by just three atomic commands: Gate (which will skip code in the same block of it's condition evaluates false), Break (which skips to the end of the current code block) and Repeat (which jumps to the beginning of the code block).
By focusing on blocks of code (which are formed by indenting lines with Tab) I even could get away without calculating jumping offsets (while parsing) or placing explicit jump marks. Smiley
Based on how complicated things are in x86 assembler or virtual machines like Java's I really didn't expect to find such a lean solution.

And here's the code that produced the animation in the above video. (It's a mess but gives an idea how Grove scripts are structured)

set t, abs(cos(time()*60))
set tt, 3+3*floor(0.5+((time()*120)/360)%5)
out tt
set mg, 7
set ibase, min(mg+1, (11*t)%11)-0.01
set iterations, floor(ibase)
out iterations
set growth, frac(ibase)
out growth

set r, -3
repeat tt
raise r
pos 5*t, 7*t
set i, 0
set d, ibase*(1.5-t)
dir r*sin(time()*50)*720/tt+time()*36
grow Trunk X, iterations

rgb 0.6-(i/iterations), 0.1+0.7*i/iterations, 0

raise i
if i=iterations
hsv t,1,1
if i=mg
sze d*(1+growth*5)
mov d*growth
run color
sze d
mov d
set d, d*(0.75+0.02*sin(t*150))
rot -45

rot 45+sin(t*100)*3

X => BranchA F X BranchB F X

Level 4

stealth ferret platformer

View Profile WWW Email
« Reply #11 on: January 17, 2013, 06:43:05 PM »

very cool! I'd love to play with this :D

♪ ♫ ♪ ♫ ~~~> http://jamesprimate.tk
Level 0

View Profile WWW Email
« Reply #12 on: January 18, 2013, 09:33:03 AM »

I've uploaded an up-to-date build including a little documentation that should get you started with understanding and writing your own scripts! (Readme.txt)


Level 0

View Profile WWW Email
« Reply #13 on: March 17, 2013, 12:48:06 PM »

No fundamental changes to report but I made a bunch of small improvements over the last weeks.

- Productions can be tagged and applied selectively
- Productions may have conditions
- Productions can have code appended executed whenever the production activates
- optional profiling ("S" Key)
- fullscreen mode ("F" Key)
- Bloom PostFX ("B" Key)
- random() function and Shuffle command to seed the random number generation
- Visible command to draw transparent lines or none at all
- Bugs&Memory-Leak Fixes

... and most importantly: Documentation

I pretty much documented every feature and command and started to write some tutorials. (So far 6 parts) It's all txt files but a lot of them! Smiley If questions remain feel free to ask.

Download the current build + Documentation and Examples

Now is a good time to have a look 'cause I'm feature complete. And if anyone want's more tutorials give me a tell. Don't want to write more of them if no one 's gonna read them.
« Last Edit: March 17, 2013, 12:58:19 PM by lithander » Logged

Level 0

View Profile WWW Email
« Reply #14 on: April 27, 2013, 04:22:54 PM »

I give up on the L-System front. I'm quite happy with what I achieved so far but my motivation has burned out too much to push it further. Here's a screen capture of a demo I've scripted in the last week. All the animations visible in the above video are real time generated, rendered at 60 FPS in my Grove Script interpreter and captured with hypercam. As the script is only 1KB big, the perceived complexity and the way the result is randomized is a nice demonstration of the power of L-Systems and emergence.


And this is how the script of the demo looks like:

//set some basic constant parameters to be used in expressions
//feel free to play with the values and see how the animation
set speed, 15
set pause, 15
set fadetime, 15
set budstep, 5
set maxage, 80
set leafAge, 5
//let the size of the structure adapt with window size
set step, 0.4*_height/480

//these variables change every frame because they all depend on the current
//value of the time() function.
//Thanks to the modulo operate age wraps around at maxage.
set age, (speed*time()) % maxage
set fade, min(1, (maxage-age-pause) / fadetime)
out fade
set age, 2.5*age^0.55
set frac, max(0.01, frac(age))

//each structure should look unique.
//So we use a different random seed for every new structure
out 'rnd seed, floor(time()*speed/(maxage))
shuffle floor(time()*speed/(maxage))

//init the turtle
dir random(360)
pos 0, step*(5*age-100)

//set the axiom of the 'plant' structre
seed plant, A(0,0,1)
//apply the ruleset 'r1' as often as the plant is old.
repeat age
grow plant, r1

//fun info: how many buds were generated?
out budCnt

//render 'plant' twice - mirrored.
rotate -45
run plant
rotate 135
run plant

//Now the Tokens that the L-System operates upon are defined.

//light blue tips of the structure
#A(age, angle)
run shade(leafAge/frac)
size frac^0.5
move step*frac^0.5, angle

//what becomes of A in the next cycle - a simple curve
#B(t, angle)
run shade(leafAge/(t+frac))
size (t+frac)^0.5
move step*(t+frac)^0.5, angle

//B becomes C when it's old enough to spawn leaves - does the same thing, though
#C(t, angle)
run B(t, angle)

//a growing leaf
#L(t, angle)
run leaf(t+frac, angle)

//a finalized leaf
#xL(t, angle)
run leaf(t, angle)

//a growing bud
#Y(t, spread, angle)
run bud(0.3*(t+frac), (spread+frac)*budstep, 0.1*angle)

//a finalized bud
#xY(t, spread, angle)
run bud(0.3*(t+frac), (spread+frac)*budstep, 0.1*angle)

//render a bud
#bud(len, angle, curve)
run budshade(1/len)
//left side
size 2*len^0.3
rotate angle
move len^0.3, angle
size len/2
rotate -90
move len, -angle
//right side
size 2*len^0.3
rotate -angle
move len^0.3, -angle
size len
rotate 90
move len, angle
rotate curve
move 0.55*len^0.7

//render a leaf
#leaf(len, ang)
size 1
rotate 10*ang*len^0.6
move 0.5*len^0.3
move len^0.6, ang*(60+len*5)
rotate 180 - ang*0.4*(60+len*10)
move 0.5*len^0.5, -ang*(len*5)
move 0.7*len^0.5, ang*(len*10)

//color buds
visible alpha * fade
rgb 1.0-0.8*alpha*alpha, 0.6*alpha+0.2, 0.2*alpha*alpha

//color rest
visible alpha * fade
rgb 1.0-0.5*alpha, 0.5*alpha+0.5, 0.3*alpha



//The rules are evaluated in the order of appearance.
//rare rules appear first, if all are skipped the general case is usually to just grow the existing tokens
//higher c makes a vine less likely to bend or split but increases chance to spawn buds
A(i, j, c) : rnd(0, c) > 2+budCnt -> B(1, j) Y(0, 1, j)
raise budCnt, 1
//if old enough there's a chance to split into 3
A(i, j, c) : i > c and rnd() < 0.5/c -> B(1, j) [ A(0, rnd(-40,-60), c+2) ] [ A(0, rnd(40,60), c+2) ] A(0, 0, c+1)
//...or into 2
A(i, j, c) : i > c and rnd() < 0.5/c -> B(1, j) [ A(0, rnd(-40,-60), c+1) ] A(0, rnd(40,60), c+1)
//or just change the direction
A(i, j, c) -> B(1, j) A(i+1, j+rnd(-90, 90)/(c+1), c)
//based on the curvature leaves spawn on different sides
B(i, j) : j < 0 and i = leafAge-1 -> C(i+1, j) [ L(0, 1) ]
B(i, j) : j > 0 and i = leafAge-1 -> C(i+1, j) [ L(0, -1) ]
//and of course everything needs to grows
Y(i, j, k) -> Y(i+1, j+1, k) xY(i, j, k)
B(i, j) -> B(i+1, j)
C(i, j) -> C(i+1, j)
L(i, j) : i > 1+rnd(7) -> xL(i+1, j)
L(i, j) -> L(i+1, j)
« Last Edit: April 28, 2013, 01:41:25 AM by lithander » Logged

Pages: [1] 2
Jump to:  

Theme orange-lt created by panic