Created
May 17, 2013 00:02
-
-
Save vividsnow/5596062 to your computer and use it in GitHub Desktop.
random stuff from live coding session using https://github.com/vividsnow/perl-live
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# some handy modules to print things | |
use Data::Dump 'dd'; | |
use DDP colored => 1, filters => { -external => [ 'PDL' ] }; | |
dd my $h = bless { a => 1 }, 'test'; | |
p $h | |
# ok - lets test scoping | |
say my $v = 0; | |
sub inc { state $i = 2; $v+=$i }; | |
my $inc = sub { $v++ }; | |
say $inc->(); | |
say inc; | |
do { | |
my $v; | |
$v = 25; | |
say "inside $v"; | |
}; | |
say "ouside $v"; | |
# now some PDL stuff | |
use PDL; | |
use PDL::Graphics::Simple; | |
p my $data = random(4,5) * sequence(4,5); | |
imag random(500,150); | |
use aliased 'Math::SegmentedEnvelope' => 'envelope'; | |
map { line pdl envelope->new(is_morph=>1)->table(256) } 1..10; | |
hold; | |
release; | |
# we are in AnyEvent loop so.. | |
my @codes; | |
my $w = AE::timer 0, 1, sub { map $_->(), @codes }; | |
push @codes, sub { say 'hello world' }; | |
undef $w; # stop timer | |
# or other AnyEvent stuff | |
use AnyEvent::Util; | |
( | |
fork_call { | |
dd "start.."; | |
my $s = random(250,50,500); | |
"done!"; | |
} sub { dd shift } | |
) # use C-M-x keybinding to eval everything between braces | |
use IO::Socket; | |
my ($s1, $s2) = IO::Socket->socketpair(AF_UNIX, SOCK_STREAM, PF_UNIX); | |
my $sr1 = AE::io $s1, 0, sub { print "on s1: ", scalar <$s1> }; | |
my $sr2 = AE::io $s2, 0, sub { print "on s2: ", scalar <$s2> }; | |
say $s2 'hi'; | |
use AnyEvent::Fork; | |
( | |
AnyEvent::Fork->new->eval(' | |
use PDL; | |
sub run { | |
my ($fh, $sock) = @_; | |
for (1..5) { | |
random((250)x3)->pow(3)->dims; | |
syswrite $sock, "fork-work - ok\n" | |
} | |
}') | |
->send_fh($s2)->run('run') | |
) | |
# live modification of http app | |
use Plack::Builder; | |
use Twiggy::Server; | |
my $r = sub { say 'got req'; join ' | ', (rand)x4; }; | |
my $app = builder { | |
mount '/point' => sub { [200,[],[$r->()." what's up?\n"]] }, | |
mount '/' => sub { [200,[],[$r->()." test\n"]] }, | |
mount '/other' => sub { [200,[],[$r->()." hi\n"]] }, | |
mount '/else' => sub { [200,[],[$r->()." else\n"]] } | |
}; | |
my $server = Twiggy::Server->new(qw(port 9030)); | |
$server->register_service($app); | |
$server->{exit_guard}->end; # stop listen | |
# another web server using AnyEvent::HTTPD | |
use AnyEvent::HTTPD; | |
use vars qw($hd $cb @cbs);#another approach for persist state - predefine globals | |
$hd = AnyEvent::HTTPD->new(port => 9020); | |
$cb = $hd->reg_cb( map { my $n = $_; '/'.$n => sub { | |
$_[1]->respond({ content => ['text/plain', "hi, ".ucfirst($n)."\n"] }) | |
} } qw(one two tri) ); | |
$hd->unreg_cb($cb); | |
# lets speak to SuperCollider using OSC | |
use Net::LibLO; | |
# same from perl | |
my $lo = Net::LibLO->new; | |
$lo->send(57120, '/beep', 'i', 100 * int rand(10) + 1); | |
# let it beep on http request | |
my $i = 0; | |
push my @cbs, $hd->reg_cb('/kick' => sub { | |
$lo->send(57120, '/beep', 'i', 100 * int rand(10) + 1); | |
$_[1]->respond({content => ['text/plain',"i beeped ".$i++." times\n"]}); | |
}) | |
# lets respond SuperCollider messages | |
$lo->add_method('/respond', "i", sub { dd splice(@_,5) }); | |
say $lo->get_port; | |
my $osc_watch = AE::timer 0, 1/60, sub { $lo->recv_noblock }; | |
# ok - now some OpenGL stuff | |
# init context | |
use OpenGL ':all'; | |
use Async::Interrupt; | |
my %c = ( # window config | |
box => [(0)x2,450,220], | |
a => 60, np => 1, nf => 15 # view angle, near/far plane | |
); | |
glutInit(); | |
glutInitWindowSize(@{$c{box}}[2,3]); glutInitWindowPosition(@{$c{box}}[0,1]); | |
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_ALPHA|GLUT_DEPTH); | |
glutSetWindow(glutCreateWindow('perl live demo')); | |
glShadeModel(GL_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); | |
glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR); | |
glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); | |
glutReshapeFunc(sub { | |
my @box = map glutGet(eval 'GLUT_WINDOW_'.$_), qw(WIDTH HEIGHT); | |
glViewport(0,0, @box); | |
glMatrixMode(GL_PROJECTION); | |
glLoadIdentity(); | |
gluPerspective($c{a}, $box[0]/$box[1], $c{np}, $c{nf}); | |
glMatrixMode(GL_MODELVIEW); | |
}); | |
glutKeyboardFunc(sub { | |
my (@pos, $fullscreen); | |
my %key_action = ( | |
p => sub { # quit | |
glutKeyboardFunc(0); glutReshapeFunc(0); | |
glutDestroyWindow(glutGetWindow()); | |
}, | |
f => sub { $fullscreen = $fullscreen ? do { # toggle fullscreen | |
glutReshapeWindow(@pos[2,3]); | |
glutPositionWindow(@pos[0,1]); 0 | |
} : do { | |
@pos = map glutGet(eval "GLUT_WINDOW_".$_), qw(X Y WIDTH HEIGHT); | |
#glutFullScreen(); 1; | |
glutReshapeWindow(1280,720); glutPositionWindow(0,0); 1 | |
} }, | |
a => sub { say 'opengl key press' } | |
); | |
sub { if (my $cb = $key_action{chr $_[0]}) { $cb->() } } | |
}->()); | |
my $start = AE::now; | |
my (@draw, @backup); | |
glutDisplayFunc(sub { my $dt = AE::now - $start; | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
glClearColor(0, 0, 0, 0); | |
glLoadIdentity(); | |
map { glPushMatrix; $_->($dt); glPopMatrix } @draw; | |
glutSwapBuffers(); | |
}); | |
my $gl_watch = AE::timer(0, 1/60, sub { | |
glutMainLoopEvent; | |
glutPostRedisplay if glutGetWindow; | |
}); | |
# ok - gl context! | |
# some aliases | |
( | |
*pum = \&glPushMatrix; | |
*clr = \&glColor4f; | |
*mov = \&glTranslatef; | |
*scl = \&glScaled; | |
*rot = \&glRotatef; | |
*ver = \&glVertex3f; | |
*pom = \&glPopMatrix; | |
*wsphere = \&glutWireSphere; | |
sub points { glBegin(GL_POINTS); shift->(); glEnd } | |
sub lines { glBegin(GL_LINES); shift->(); glEnd } | |
sub iso { glPushAttrib(GL_ALL_ATTRIB_BITS); shift->(); glPopAttrib } | |
) | |
# some time dependent variable | |
my $square_size; | |
my $w1 = AE::timer(0, 1/60, sub { | |
state $started = AE::now; state $e = envelope->new(is_morph => 1); | |
$square_size = $e->at(AE::now - $started); | |
}); | |
undef $w1; | |
use Math::Trig 'pi'; | |
( | |
push @draw, sub { my $ts = shift; | |
mov qw(0 0 -4); | |
clr qw(0.6 0.2 0.4 1); | |
scl (($square_size * 2.5)x2, 1); | |
rot (($ts + pi/3.4)*360, 0, 0, 1); | |
wsphere (0.5,(5)x2); scl ((0.1)x3); | |
} | |
) | |
# etc.. | |
# time for shaders :) | |
# quick shader program | |
( | |
my $shader = sub { | |
my $id = glCreateProgramObjectARB; | |
my @objects = map { | |
glAttachObjectARB($id, $_); | |
glShaderSourceARB_p($_, shift); $_; | |
} map { | |
glCreateShaderObjectARB(eval 'GL_'.uc($_).'_SHADER'); | |
} qw(fragment vertex); | |
glLinkProgramARB($id); | |
wantarray ? ($id, @objects) : $id; | |
}->(<<FRAG | |
uniform float time = 0.; | |
void main(void) { | |
float d = distance(vec2(0.5), gl_PointCoord); | |
if (d >= 0.5) { discard; } | |
gl_FragColor = vec4(gl_Color.rgb, (1. - pow(d*2.,2.)) * gl_Color.a * (cos(time) * 0.5 + 0.5)); | |
} | |
FRAG | |
, <<VERT | |
void main(void) { | |
gl_Position = ftransform(); | |
gl_FrontColor = gl_Color; | |
gl_PointSize = gl_Point.size; | |
} | |
VERT | |
); | |
) | |
# some routines to check state | |
map {say glGetInfoLogARB_p($_)} glGetAttachedObjectsARB_p($shader), $shader; | |
say gluErrorString(glGetError); | |
# and cleanup | |
map { glDeleteObjectARB($_) } glGetAttachedObjectsARB_p($shader), $shader; | |
map { glDeleteProgramsARB_p($_) } $shader; | |
# backup current draws | |
push my @backup, splice @draw; | |
# revert | |
push @draw, splice @backup; | |
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); | |
glEnable(GL_POINT_SPRITE); | |
# shader test | |
(push @draw, sub { | |
my $ts = shift; | |
mov(-1,1,-5); | |
glUseProgramObjectARB($shader); | |
glUniform1fARB(glGetUniformLocationARB_p($shader, 'time'), $ts*7); | |
glPointSize(glutGet(GLUT_WINDOW_HEIGHT) * 0.4 * sin($ts) ** 2); | |
glBegin(GL_POINTS); | |
clr(cos($ts/2)/3+0.5,sin($ts*2)/3+0.5,cos($ts*5)/3+0.5,1); | |
glVertex3f(0,0,0); | |
glEnd; | |
glUseProgramObjectARB(0); | |
}) | |
pop @draw; | |
# :) gl is fun | |
# ok - now gui showcase | |
undef $w1; # stop sizing | |
# GUIs! | |
use Gtk2; | |
Gtk2->init; | |
$gtk::window = Gtk2::Window->new ('toplevel'); | |
$gtk::window->add (do { | |
my $button = Gtk2::Button->new ('Quit!'); | |
$button->signal_connect (clicked => sub { print "gtk click\n" }); | |
$button; | |
} ); | |
$gtk::window->show_all; | |
use Wx; | |
use Wx::Event qw(EVT_BUTTON); | |
$wx::app = Wx::SimpleApp->new; | |
$wx::button = Wx::Button->new( | |
Wx::Panel->new($wx::frame = Wx::Frame->new( undef, -1, "wx" ), -1), | |
-1, 'Click me!', [30, 20], [-1, -1] | |
); | |
EVT_BUTTON( $wx::frame, $wx::button, sub { print "wx click\n" } ); | |
$wx::frame->Show(1); | |
use Prima qw(Application Buttons); | |
$'prima = Prima::MainWindow->new( | |
text => 'Hello world!', | |
size => [ 200, 200], | |
)->insert( | |
Button => centered => 1, | |
text => 'Hello world!', | |
onClick => sub { print "prima click\n" }, | |
); | |
use Tk; | |
$tk::mw = MainWindow->new; | |
$tk::mw->Button ( | |
-text => "Hello World!", | |
-command => sub { print "tk click\n" } | |
)->pack; | |
# and SDL | |
use SDL; | |
use SDLx::App; | |
use SDL::Event; | |
use SDL::Events; | |
$sdl::event = SDL::Event->new; | |
$sdl::app = SDLx::App->new( | |
title => 'sdl', width => 150, height => 80, depth => 32 | |
); | |
$sdl::poll = sub { while ( SDL::Events::poll_event($sdl::event) ) { | |
print "sdl click\n" if $sdl::event->type eq SDL_MOUSEBUTTONDOWN; | |
}}; | |
# watch for their events | |
my $gui_events = AE::timer 0, 1/20, sub { | |
Gtk2->main_iteration_do(""); | |
$wx::app->Yield; | |
$::application->yield; | |
DoOneEvent(Tk::DONT_WAIT() | Tk::ALL_EVENTS()); | |
$sdl::poll->(); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment