Skip to content

Instantly share code, notes, and snippets.

@grondilu
Last active January 7, 2023 21:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save grondilu/754822601747b9e2c992361af81e6574 to your computer and use it in GitHub Desktop.
Save grondilu/754822601747b9e2c992361af81e6574 to your computer and use it in GitHub Desktop.
Trying to draw a triangle in raku with recent OpenGL library
# Drawing OpenGL primitives in raku can be done with old OpenGL versions,
# using the so called L<fixed function pipeline|https://www.khronos.org/opengl/wiki/Fixed_Function_Pipeline>.
# This is showcased on L<Rosetta code|https://rosettacode.org/wiki/OpenGL#Raku>.
# However, here I'm trying to do it with recent opengl versions,
# which require compiling a shader program.
# I'm trying to implement this tutorial : L<https://learnopengl.com/Getting-started/Hello-Triangle>
# Frustratingly enough, it I<almost> works : it shows the window,
# clears the screen with the requested color, but it doesn't draw
# the primitive (a triangle).
# Any help?
use NativeCall;
package GLFW {
constant $lib = ('glfw', v3);
our class Window is repr('CPointer') {}
our class Monitor is repr('CPointer') {}
our constant RELEASE = 0;
our constant PRESS = 1;
our constant REPEAT = 2;
our enum KEY_CODE (
KEY_ESCAPE => 256,
);
our sub init(--> int32) is native($lib) is symbol('glfwInit') {*}
our sub terminate(--> int32) is native($lib) is symbol('glfwTerminate') {*}
our sub setErrorCallback(&callback (int32, Str)) is native($lib) is symbol('glfwSetErrorCallback') {*}
our sub createWindow(int32, int32, Str, Monitor, Window --> Window) is native($lib) is symbol('glfwCreateWindow') {*}
our sub destroyWindow(Window) is native($lib) is symbol('glfwDestroyWindow') {*}
our sub makeContextCurrent(Window) is native($lib) is symbol('glfwMakeContextCurrent') {*}
our sub windowShouldClose(Window --> int32) is native($lib) is symbol('glfwWindowShouldClose') {*}
our sub setWindowShouldClose(Window, Bool --> int32) is native($lib) is symbol('glfwSetWindowShouldClose') {*}
our sub pollEvents is native($lib) is symbol('glfwPollEvents') {*}
our sub swapBuffers(Window) is native($lib) is symbol('glfwSwapBuffers') {*}
our sub getKey(Window, int32 --> int32) is native($lib) is symbol('glfwGetKey') {*}
our sub getFramebufferSize(Window, uint32 is rw, uint32 is rw) is native($lib) is symbol('glfwGetFramebufferSize') {*}
}
package GL {
constant $gllib = 'GL';
our constant COLOR_BUFFER_BIT = 0x00004000;
our constant ARRAY_BUFFER = 0x8892;
our constant STATIC_DRAW = 0x88E4;
our constant VERTEX_SHADER = 0x8B31;
our constant FRAGMENT_SHADER = 0x8B30;
our constant SHADER_SOURCE_LENGTH = 0x8B88;
our constant INFO_LOG_LENGTH = 0x8B84;
our constant COMPILE_STATUS = 0x8B81;
our constant LINK_STATUS = 0x8B82;
our constant FLOAT = 0x1406;
our constant FALSE = 0;
our enum PrimitiveMode(
POINTS => 0x0000,
LINES => 0x0001,
LINE_LOOP => 0x0002,
LINE_STRIP => 0x0003,
TRIANGLES => 0x0004,
TRIANGLE_STRIP => 0x0005,
TRIANGLE_FAN => 0x0006,
QUADS => 0x0007,
QUAD_STRIP => 0x0008,
POLYGON => 0x0009
);
our enum MatrixMode(
MATRIX_MODE => 0x0BA0,
MODELVIEW => 0x1700,
PROJECTION => 0x1701,
TEXTURE => 0x1702
);
our sub clearColor(num32, num32, num32, num32) is native($gllib) is symbol('glClearColor') {*}
our sub clear(int32) is native($gllib) is symbol('glClear') {*}
our sub genVertexArrays(int32, uint32 is rw) is native($gllib) is symbol('glGenVertexArrays') {*}
our sub bindVertexArray(uint32) is native($gllib) is symbol('glBindVertexArray') {*}
our sub genBuffers(int32, uint32 is rw) is native($gllib) is symbol('glGenBuffers') {*}
our sub bindBuffer(int32, uint32) is native($gllib) is symbol('glBindBuffer') {*}
our sub bufferData(int32, uint32, CArray[num64], int32) is native($gllib) is symbol('glBufferData') {*}
our sub createShader(uint32 --> uint32) is native($gllib) is symbol('glCreateShader') {*}
our sub deleteShader(uint32) is native($gllib) is symbol('glDeleteShader') {*}
our sub shaderSource(uint32, uint32, CArray[Str], int32) is native($gllib) is symbol('glShaderSource') {*}
our sub compileShader(uint32) is native($gllib) is symbol('glCompileShader') {*}
our sub getShaderiv(uint32, uint32, int32 is rw) is native($gllib) is symbol('glGetShaderiv') {*}
our sub getShaderInfoLog(uint32, uint32, uint32, CArray[uint8]) is native($gllib) is symbol('glGetShaderInfoLog') {*}
our sub getProgramiv(uint32, uint32, int32 is rw) is native($gllib) is symbol('glGetProgramiv') {*}
our sub getProgramInfoLog(uint32, uint32, uint32, CArray[uint8]) is native($gllib) is symbol('glGetProgramInfoLog') {*}
our sub createProgram(--> uint32) is native($gllib) is symbol('glCreateProgram') {*}
our sub attachShader(uint32, uint32) is native($gllib) is symbol('glAttachShader') {*}
our sub linkProgram (uint32) is native($gllib) is symbol('glLinkProgram' ) {*}
our sub useProgram (uint32) is native($gllib) is symbol('glUseProgram') {*}
our sub vertexAttribPointer(uint32, int32, uint32, bool, uint32, Pointer)
is native($gllib) is symbol('glVertexAttribPointer') {*}
our sub enableVertexAttribArray(uint32) is native($gllib) is symbol('glEnableVertexAttribArray') {*}
our sub drawArrays(uint32, uint32, uint32) is native($gllib) is symbol('glDrawArrays') {*}
our sub viewport(uint32, uint32, uint32, uint32) is native($gllib) is symbol('glViewport') {*}
}
my @vertices := CArray[num64].new;
@vertices[$++] = .Num for
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
0.0, 0.5, 0.0
;
GLFW::setErrorCallback(sub ($code, $msg) { warn "err $code: $msg" });
if GLFW::init() {
if my $w = GLFW::createWindow(640, 480, "Test window", Nil, Nil) {
GLFW::makeContextCurrent($w);
my uint32 ($width, $height);
GLFW::getFramebufferSize($w, $width, $height);
GL::viewport(0, 0, $width, $height);
note "with = $width, height = $height";
GL::clearColor(2e-1, 2e-1, 5e-1, 1e0);
# SHADER PROGRAM
my uint32 $shaderProgram = GL::createProgram();
{
# VERTEX SHADER
my uint32 $vertexShader = GL::createShader(GL::VERTEX_SHADER);
{
my @vertexShaderSources := CArray[Str].new;
@vertexShaderSources[0] = q:to/EOF/;
#version 330 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
EOF
GL::shaderSource($vertexShader, 1, @vertexShaderSources, Nil);
GL::compileShader($vertexShader);
GL::getShaderiv($vertexShader, GL::COMPILE_STATUS, my int32 $success);
unless $success {
GL::getShaderiv($vertexShader, GL::INFO_LOG_LENGTH, my int32 $length);
my $infoLog = CArray[uint8].allocate($length);
GL::getShaderInfoLog($vertexShader, $length, Nil, $infoLog);
note blob8.new($infoLog.list[0..^($length - 1)]).decode('ascii');
}
}
# FRAGMENT SHADER
my uint32 $fragmentShader = GL::createShader(GL::FRAGMENT_SHADER);
{
my @fragmentShaderSources := CArray[Str].new;
@fragmentShaderSources[0] = q:to/EOF/;
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
EOF
GL::shaderSource($fragmentShader, 1, @fragmentShaderSources, Nil);
GL::compileShader($fragmentShader);
GL::getShaderiv($fragmentShader, GL::COMPILE_STATUS, my int32 $success);
unless $success {
GL::getShaderiv($fragmentShader, GL::INFO_LOG_LENGTH, my int32 $length);
my $infoLog = CArray[uint8].allocate($length);
GL::getShaderInfoLog($fragmentShader, $length, Nil, $infoLog);
note blob8.new($infoLog.list[0..^($length - 1)]).decode('ascii');
}
}
# ATTACH AND LINK SHADERS
{
GL::attachShader($shaderProgram, $vertexShader);
GL::attachShader($shaderProgram, $fragmentShader);
GL::linkProgram($shaderProgram);
GL::getProgramiv($shaderProgram, GL::LINK_STATUS, my int32 $success);
unless $success {
GL::getShaderiv($shaderProgram, GL::INFO_LOG_LENGTH, my int32 $length);
my $infoLog = CArray[uint8].allocate($length);
GL::getShaderInfoLog($shaderProgram, $length, Nil, $infoLog);
note blob8.new($infoLog.list[0..^($length - 1)]).decode('ascii');
}
GL::deleteShader($vertexShader);
GL::deleteShader($fragmentShader);
}
}
my uint32 ($bvo, $vao);
GL::genVertexArrays(1, $vao);
GL::bindVertexArray($vao);
GL::genBuffers(1, $bvo);
GL::bindBuffer(GL::ARRAY_BUFFER, $bvo);
GL::bufferData(GL::ARRAY_BUFFER, @vertices.elems, @vertices, GL::STATIC_DRAW);
GL::vertexAttribPointer(0, 3, GL::FLOAT, GL::FALSE, 3 * 8, Pointer.new);
GL::enableVertexAttribArray(0);
until GLFW::windowShouldClose($w) {
processInput($w);
GL::clear(GL::COLOR_BUFFER_BIT);
GL::useProgram($shaderProgram);
GL::bindVertexArray($vao);
GL::drawArrays(GL::TRIANGLES, 0, 3);
GLFW::pollEvents;
GLFW::swapBuffers($w);
}
GLFW::destroyWindow($w);
} else { note 'Failed to create window' }
} else { die "could not initiate GLFW"; }
sub processInput($window) {
with GLFW::getKey($window, GLFW::KEY_ESCAPE) {
when GLFW::PRESS {
note "Escape key pressed, closing window.";
GLFW::setWindowShouldClose($window, True);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment