-
-
Save grondilu/754822601747b9e2c992361af81e6574 to your computer and use it in GitHub Desktop.
Trying to draw a triangle in raku with recent OpenGL library
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
# 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