Skip to content

Instantly share code, notes, and snippets.

@mohawk2
Forked from vividsnow/pdl-opengl.pl
Created January 19, 2025 19:34
Show Gist options
  • Save mohawk2/097de6f55c66d570476903782876df34 to your computer and use it in GitHub Desktop.
Save mohawk2/097de6f55c66d570476903782876df34 to your computer and use it in GitHub Desktop.
pdl opengl example
#!/usr/bin/env perl
use v5.40; use warnings;
use Syntax::Keyword::Match;
use OpenGL ':all';
use PDL;
use PDL::Constants qw'PI E I';
use PDL::Transform;
use Time::HiRes qw'gettimeofday tv_interval';
use IPC::Open2 'open2';
my $window; my $w = 800; my $h = 600; my $x = 0; my $y = 0;
my %ctl = (
angle => 0,
angle_dt => 0,
k => 1,
cam => [[0,0,3],[0,0,-1],0], # pos dir tilt
bg => [0,0,0], # background color
z => 1
);
my @ids;
my $number_of_points = 2048;
my $e_init = null;
my $e_state = null;
my $vertices = null;
my $st;
init();
sub display {
state $s = 0;
glClearColor(0.1, 0.2, 0.1, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt($ctl{cam}[0][0], $ctl{cam}[0][1], $ctl{cam}[0][2], 0, 0, 0, 0, 1, 0);
glRotatef(-$ctl{angle},0,0,1);
glScalef($ctl{z},$ctl{z},0.5); # minimize z component
glBindBufferARB(GL_ARRAY_BUFFER_ARB, $ids[0]);
# my $data = OpenGL::Array->new_scalar(GL_FLOAT, $vertices->get_dataref, $vertices->dim(0) * 4); # 4 is float size in bytes
# glBufferDataARB_p(GL_ARRAY_BUFFER_ARB, $data, GL_DYNAMIC_DRAW_ARB);
# or :
glBufferDataARB_s(GL_ARRAY_BUFFER_ARB, $vertices->dim(0) * 4, $vertices->get_dataref, GL_DYNAMIC_DRAW_ARB);
glInterleavedArrays_c(GL_C4F_N3F_V3F, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, $st->dim(2));
$s = sin(do { $ctl{angle} = ($ctl{angle} + $ctl{angle_dt}) % 360; $ctl{angle} / 180 * PI });
glutSwapBuffers();
}
sub key_event ($code, @) {
match (chr($code) : eq) {
case ('q') { term() }
case ('f') { glutFullScreen() }
case ('e') { glShadeModel(GL_FLAT) }
case ('d') { glShadeModel(GL_SMOOTH) }
case ('w') {
glutReshapeWindow($w, $h);
glutPositionWindow($x, $y);
}
case ('a') { $ctl{k} += 0.1 }
case ('s') { $ctl{k} -= 0.1 }
case ('u') { $ctl{z} *= 2 }
case ('i') { $ctl{z} /= 2 }
case ('z') { $ctl{angle_dt} += 1 }
case ('x') { $ctl{angle_dt} -= 1 }
case ('c') { $ctl{angle_dt} *= -1 }
case ('r') {
init_data();
#$e_init->slice('0,0:1,:') *= 0;
#$e_init->slice('0,0:1,:') += random(1, 2, $number_of_points);
}
case ('t') { triangulate(1) }
case ('l') { glEnable(GL_LIGHTING) }
case ('L') { glDisable(GL_LIGHTING) }
case ('k') { glEnable(GL_COLOR_MATERIAL) }
case ('K') { glDisable(GL_COLOR_MATERIAL) }
default { say $code, ': ', chr($code) }
}
}
sub keyup_event ($code, @) { say "$code - ".chr($code) }
sub key_special_event {
my ($code) = @_;
match ($code : ==) {
case (GLUT_KEY_LEFT) { $ctl{cam}[0][0] -= 1 }
case (GLUT_KEY_RIGHT) { $ctl{cam}[0][0] += 1 }
case (GLUT_KEY_UP) { $ctl{cam}[0][1] += 1 }
case (GLUT_KEY_DOWN) { $ctl{cam}[0][1] -= 1 }
default { say 'code: ', $code }
}
#say glutGetModifiers(); # shift - 001 ctrl - 010 alt 100
}
sub camera {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(35, glutGet(GLUT_WINDOW_WIDTH)/glutGet(GLUT_WINDOW_HEIGHT), 2, 10);
#glOrtho(-0.5, 0.5, -0.5, 0.5, 0, 3);
glMatrixMode(GL_MODELVIEW);
}
sub init {
glutInit();
glutInitWindowSize($w, $h);
glutInitWindowPosition($x, $y);
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_ALPHA|GLUT_DEPTH);
$window = glutCreateWindow('test');
glutSetCursor(GLUT_CURSOR_NONE);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glutReshapeFunc(sub {
glViewport(0,0, glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT));
camera();
});
glutDisplayFunc(\&display);
glutKeyboardFunc(\&key_event);
glutSpecialFunc(\&key_special_event);
glutKeyboardUpFunc(\&keyup_event);
state $light = [[(1) x 3, 1], [(0.1) x 3, 1]];
glMaterialfv_p(GL_FRONT, GL_SPECULAR, @{$light->[0]});
glLightfv_p(GL_LIGHT0, GL_AMBIENT, @{$light->[1]});
glLightfv_p(GL_LIGHT0, GL_SPECULAR, @{$light->[1]});
glLightModelfv_p(GL_LIGHT_MODEL_AMBIENT, @{$light->[0]});
glLightfv_p(GL_LIGHT0, GL_POSITION, 0, 0, 100, 0);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
#glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
glEnable(GL_LIGHT0);
#glEnable(GL_DEPTH_TEST);
init_data();
refresh();
recalc();
@ids = glGenBuffersARB_p(1);
glutIdleFunc(\&looping);
say 'entering loop';
glutMainLoop();
};
sub looping {
recalc();
refresh();
}
sub refresh { glutPostRedisplay() }
sub init_data {
$e_init = randsym(float, 4, 10, $number_of_points); # amp, freq, phase, add : coord->XYZ normal->UVW color->RGBA : num_of_points
$e_init->slice('0,:,:') *= (0.5 - abs($e_init->slice('3,:,:') - 0.5)); # amp *= ( 0.5 - abs(add - 0.5) )
$e_init->slice('0:2,0:1,:') *= 0; # no move XY position, freq and amp=0 or do non realtime version with triangualtion on each step?
my $xy = $e_init->slice('3,0:1,:');
do { # assume x - is radius, and y - is angle, and recalc X,Y
my $angle = $xy->slice('0,1,:')->mult(PI*2,0)->copy;
my $rad = $xy->slice('0,0,:')->copy->pow(4/1.5); # outer is more outer
$xy->slice('0,0,:') .= $rad * $angle->sin;
$xy->slice('0,1,:') .= $rad * $angle->cos;
};
}
sub recalc {
state $last_t = [gettimeofday];
$e_state =
$e_init->slice(0)
* sin(
tv_interval($last_t)
* (PI ** $ctl{k})
* $e_init->slice(1)
+ $e_init->slice(2)
)
+ $e_init->slice(3);
triangulate();
}
sub triangulate { # get vertices - return vertices indexes
my ($force) = @_;
state $cache;
if (!$cache || $force) {
my $pid = open2(my $out, my $in, 'qdelaunay i');
say $in join("\n", 2, $e_state->dim(2), $e_state->slice('0,0:1,:')->list);
close $in;
my @lines = <$out>; shift @lines; chomp @lines; close $out;
waitpid $pid, 0;
$cache = [map split(/\s+/, $_), @lines];
}
$st = $e_state->dice(0, [6,7,8,9,3,4,5,0,1,2], $cache);
$vertices = $st->flat->float;
}
sub term {
glutKeyboardFunc(0);
glutSpecialFunc(0);
glutReshapeFunc(0);
glutDestroyWindow($window);
glutLeaveMainLoop();
exit(0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment