WebGL rotating F: Difference between revisions

Added Wren
m (pasting type correction)
(Added Wren)
Line 424:
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<!--</lang>-->
 
=={{header|Wren}}==
{{libheader|FreeGLUT}}
{{libheader|Wren-math}}
The following is based on the WebGL tutorial javascript animation code [https://webglfundamentals.org/webgl/lessons/webgl-animation.html here] but is written as an OpenGL ES 2.0 desktop application. It just uses plain colors, without any textures and looks exactly the same as the WebGL version when run.
 
Although the task description says to avoid it, I've used Freeglut to create and manage a desktop window (but no drawing nor callbacks) as that's what I'm most familiar with. However, if that's a problem I can try and use something else (such as SDL).
 
Assuming it's started from a terminal session, the only way to kill the program is by pressing Ctrl-C. The window close button doesn't work, probably due to the use of ''usleep'' to create a delay between drawing frames. It does work if I use a freeglut timer function instead but that creates callback issues (the Wren VM is not re-entrant) and I wanted to minimize the use of freeglut in any case.
 
As with any Open GL aplication, the Wren code needs to be embedded in a host application which can communicate directly with the relevant libraries and which I've written here in C.
<lang ecmascript>/* webgl_rotating_F.wren */
 
import "./math" for Math
 
var GL_ARRAY_BUFFER = 0x8892
var GL_STATIC_DRAW = 0x88E4
var GL_VERTEX_SHADER = 0x8B31
var GL_FRAGMENT_SHADER = 0x8B30
var GL_COLOR_BUFFER_BIT = 0x4000
var GL_DEPTH_BUFFER_BIT = 0x0100
var GL_CULL_FACE = 0x0B44
var GL_DEPTH_TEST = 0x0B71
var GL_UNSIGNED_BYTE = 0x1403
var GL_FLOAT = 0x1406
var GL_TRIANGLES = 0x0004
 
var GLUT_ACTION_ON_WINDOW_CLOSE = 0x01F9
var GLUT_ACTION_GLUTMAINLOOP_RETURNS = 0x0001
var GLUT_SINGLE = 0x0000
var GLUT_RGB = 0x0000
var GLUT_DEPTH = 0x0010
 
class Gl {
foreign static bufferData(target, size, data, usage)
foreign static createShader(type)
foreign static shaderSource(shader, count, string, length)
foreign static compileShader(shader)
foreign static createProgram()
foreign static attachShader(program, shader)
foreign static linkProgram(program)
foreign static getAttribLocation(program, name)
foreign static getUniformLocation(program, name)
foreign static genBuffers(n, buffers)
foreign static bindBuffer(target, buffer)
foreign static viewport(x, y, width, height)
foreign static clear(mask)
foreign static enable(cap)
foreign static useProgram(program)
foreign static drawArrays(mode, first, count)
foreign static enableVertexAttribArray(index)
foreign static vertexAttribPtr(index, size, type, normalized, stride, ptr)
foreign static uniformMatrix4fv(location, count, transpose, value)
foreign static flush()
}
 
class Glut {
foreign static initDisplayMode(mode)
foreign static initWindowSize(width, height)
foreign static createWindow(name)
foreign static setOption(eWhat, value)
}
 
class M4 {
static perspective(fieldOfViewInRadians, aspect, near, far, dst) {
if (!dst) dst = List.filled(16, 0)
 
var f = (Num.pi * 0.5 - 0.5 * fieldOfViewInRadians).tan
var rangeInv = 1 / (near - far)
 
dst[ 0] = f / aspect
dst[ 1] = 0
dst[ 2] = 0
dst[ 3] = 0
dst[ 4] = 0
dst[ 5] = f
dst[ 6] = 0
dst[ 7] = 0
dst[ 8] = 0
dst[ 9] = 0
dst[10] = (near + far) * rangeInv
dst[11] = -1
dst[12] = 0
dst[13] = 0
dst[14] = near * far * rangeInv * 2
dst[15] = 0
 
return dst
}
 
static translate(m, tx, ty, tz, dst) {
if (!dst) dst = List.filled(16, 0)
 
var m00 = m[0]
var m01 = m[1]
var m02 = m[2]
var m03 = m[3]
var m10 = m[1 * 4 + 0]
var m11 = m[1 * 4 + 1]
var m12 = m[1 * 4 + 2]
var m13 = m[1 * 4 + 3]
var m20 = m[2 * 4 + 0]
var m21 = m[2 * 4 + 1]
var m22 = m[2 * 4 + 2]
var m23 = m[2 * 4 + 3]
var m30 = m[3 * 4 + 0]
var m31 = m[3 * 4 + 1]
var m32 = m[3 * 4 + 2]
var m33 = m[3 * 4 + 3]
 
if (m != dst) {
dst[ 0] = m00
dst[ 1] = m01
dst[ 2] = m02
dst[ 3] = m03
dst[ 4] = m10
dst[ 5] = m11
dst[ 6] = m12
dst[ 7] = m13
dst[ 8] = m20
dst[ 9] = m21
dst[10] = m22
dst[11] = m23
}
 
dst[12] = m00 * tx + m10 * ty + m20 * tz + m30
dst[13] = m01 * tx + m11 * ty + m21 * tz + m31
dst[14] = m02 * tx + m12 * ty + m22 * tz + m32
dst[15] = m03 * tx + m13 * ty + m23 * tz + m33
 
return dst
}
 
static xRotate(m, angleInRadians, dst) {
if (!dst) dst = List.filled(16, 0)
 
var m10 = m[4]
var m11 = m[5]
var m12 = m[6]
var m13 = m[7]
var m20 = m[8]
var m21 = m[9]
var m22 = m[10]
var m23 = m[11]
var c = angleInRadians.cos
var s = angleInRadians.sin
 
dst[4] = c * m10 + s * m20
dst[5] = c * m11 + s * m21
dst[6] = c * m12 + s * m22
dst[7] = c * m13 + s * m23
dst[8] = c * m20 - s * m10
dst[9] = c * m21 - s * m11
dst[10] = c * m22 - s * m12
dst[11] = c * m23 - s * m13
 
if (m != dst) {
dst[ 0] = m[ 0]
dst[ 1] = m[ 1]
dst[ 2] = m[ 2]
dst[ 3] = m[ 3]
dst[12] = m[12]
dst[13] = m[13]
dst[14] = m[14]
dst[15] = m[15]
}
 
return dst
}
 
static yRotate(m, angleInRadians, dst) {
if (!dst) dst = List.filled(16, 0)
 
var m00 = m[0 * 4 + 0]
var m01 = m[0 * 4 + 1]
var m02 = m[0 * 4 + 2]
var m03 = m[0 * 4 + 3]
var m20 = m[2 * 4 + 0]
var m21 = m[2 * 4 + 1]
var m22 = m[2 * 4 + 2]
var m23 = m[2 * 4 + 3]
var c = angleInRadians.cos
var s = angleInRadians.sin
 
dst[ 0] = c * m00 - s * m20
dst[ 1] = c * m01 - s * m21
dst[ 2] = c * m02 - s * m22
dst[ 3] = c * m03 - s * m23
dst[ 8] = c * m20 + s * m00
dst[ 9] = c * m21 + s * m01
dst[10] = c * m22 + s * m02
dst[11] = c * m23 + s * m03
 
if (m != dst) {
dst[ 4] = m[ 4]
dst[ 5] = m[ 5]
dst[ 6] = m[ 6]
dst[ 7] = m[ 7]
dst[12] = m[12]
dst[13] = m[13]
dst[14] = m[14]
dst[15] = m[15]
}
 
return dst
}
 
static zRotate(m, angleInRadians, dst) {
if (!dst) dst = List.filled(16, 0)
 
var m00 = m[0 * 4 + 0]
var m01 = m[0 * 4 + 1]
var m02 = m[0 * 4 + 2]
var m03 = m[0 * 4 + 3]
var m10 = m[1 * 4 + 0]
var m11 = m[1 * 4 + 1]
var m12 = m[1 * 4 + 2]
var m13 = m[1 * 4 + 3]
var c = angleInRadians.cos
var s = angleInRadians.sin
 
dst[ 0] = c * m00 + s * m10
dst[ 1] = c * m01 + s * m11
dst[ 2] = c * m02 + s * m12
dst[ 3] = c * m03 + s * m13
dst[ 4] = c * m10 - s * m00
dst[ 5] = c * m11 - s * m01
dst[ 6] = c * m12 - s * m02
dst[ 7] = c * m13 - s * m03
 
if (m != dst) {
dst[ 8] = m[ 8]
dst[ 9] = m[ 9]
dst[10] = m[10]
dst[11] = m[11]
dst[12] = m[12]
dst[13] = m[13]
dst[14] = m[14]
dst[15] = m[15]
}
 
return dst
}
 
static scale(m, sx, sy, sz, dst) {
if (!dst) dst = List.filled(16, 0)
 
dst[ 0] = sx * m[0 * 4 + 0]
dst[ 1] = sx * m[0 * 4 + 1]
dst[ 2] = sx * m[0 * 4 + 2]
dst[ 3] = sx * m[0 * 4 + 3]
dst[ 4] = sy * m[1 * 4 + 0]
dst[ 5] = sy * m[1 * 4 + 1]
dst[ 6] = sy * m[1 * 4 + 2]
dst[ 7] = sy * m[1 * 4 + 3]
dst[ 8] = sz * m[2 * 4 + 0]
dst[ 9] = sz * m[2 * 4 + 1]
dst[10] = sz * m[2 * 4 + 2]
dst[11] = sz * m[2 * 4 + 3]
 
if (m != dst) {
dst[12] = m[12]
dst[13] = m[13]
dst[14] = m[14]
dst[15] = m[15]
}
 
return dst
}
}
 
class C {
foreign static usleep(usec)
}
 
// Fill the buffer with the values that define a letter 'F'.
var setGeometry = Fn.new {
Gl.bufferData(
GL_ARRAY_BUFFER,
4, // size of 32 bit float
[
// left column front
0, 0, 0,
0, 150, 0,
30, 0, 0,
0, 150, 0,
30, 150, 0,
30, 0, 0,
 
// top rung front
30, 0, 0,
30, 30, 0,
100, 0, 0,
30, 30, 0,
100, 30, 0,
100, 0, 0,
 
// middle rung front
30, 60, 0,
30, 90, 0,
67, 60, 0,
30, 90, 0,
67, 90, 0,
67, 60, 0,
 
// left column back
0, 0, 30,
30, 0, 30,
0, 150, 30,
0, 150, 30,
30, 0, 30,
30, 150, 30,
 
// top rung back
30, 0, 30,
100, 0, 30,
30, 30, 30,
30, 30, 30,
100, 0, 30,
100, 30, 30,
 
// middle rung back
30, 60, 30,
67, 60, 30,
30, 90, 30,
30, 90, 30,
67, 60, 30,
67, 90, 30,
 
// top
0, 0, 0,
100, 0, 0,
100, 0, 30,
0, 0, 0,
100, 0, 30,
0, 0, 30,
 
// top rung right
100, 0, 0,
100, 30, 0,
100, 30, 30,
100, 0, 0,
100, 30, 30,
100, 0, 30,
 
// under top rung
30, 30, 0,
30, 30, 30,
100, 30, 30,
30, 30, 0,
100, 30, 30,
100, 30, 0,
 
// between top rung and middle
30, 30, 0,
30, 60, 30,
30, 30, 30,
30, 30, 0,
30, 60, 0,
30, 60, 30,
 
// top of middle rung
30, 60, 0,
67, 60, 30,
30, 60, 30,
30, 60, 0,
67, 60, 0,
67, 60, 30,
 
// right of middle rung
67, 60, 0,
67, 90, 30,
67, 60, 30,
67, 60, 0,
67, 90, 0,
67, 90, 30,
 
// bottom of middle rung.
30, 90, 0,
30, 90, 30,
67, 90, 30,
30, 90, 0,
67, 90, 30,
67, 90, 0,
 
// right of bottom
30, 90, 0,
30, 150, 30,
30, 90, 30,
30, 90, 0,
30, 150, 0,
30, 150, 30,
 
// bottom
0, 150, 0,
0, 150, 30,
30, 150, 30,
0, 150, 0,
30, 150, 30,
30, 150, 0,
 
// left side
0, 0, 0,
0, 0, 30,
0, 150, 30,
0, 0, 0,
0, 150, 30,
0, 150, 0
],
GL_STATIC_DRAW
)
}
 
// Fill the buffer with colors for the 'F'.
var setColors = Fn.new {
Gl.bufferData(
GL_ARRAY_BUFFER,
1, // size of unsigned byte
[
// left column front
200, 70, 120,
200, 70, 120,
200, 70, 120,
200, 70, 120,
200, 70, 120,
200, 70, 120,
 
// top rung front
200, 70, 120,
200, 70, 120,
200, 70, 120,
200, 70, 120,
200, 70, 120,
200, 70, 120,
 
// middle rung front
200, 70, 120,
200, 70, 120,
200, 70, 120,
200, 70, 120,
200, 70, 120,
200, 70, 120,
 
// left column back
80, 70, 200,
80, 70, 200,
80, 70, 200,
80, 70, 200,
80, 70, 200,
80, 70, 200,
 
// top rung back
80, 70, 200,
80, 70, 200,
80, 70, 200,
80, 70, 200,
80, 70, 200,
80, 70, 200,
 
// middle rung back
80, 70, 200,
80, 70, 200,
80, 70, 200,
80, 70, 200,
80, 70, 200,
80, 70, 200,
 
// top
70, 200, 210,
70, 200, 210,
70, 200, 210,
70, 200, 210,
70, 200, 210,
70, 200, 210,
 
// top rung right
200, 200, 70,
200, 200, 70,
200, 200, 70,
200, 200, 70,
200, 200, 70,
200, 200, 70,
 
// under top rung
210, 100, 70,
210, 100, 70,
210, 100, 70,
210, 100, 70,
210, 100, 70,
210, 100, 70,
 
// between top rung and middle
210, 160, 70,
210, 160, 70,
210, 160, 70,
210, 160, 70,
210, 160, 70,
210, 160, 70,
 
// top of middle rung
70, 180, 210,
70, 180, 210,
70, 180, 210,
70, 180, 210,
70, 180, 210,
70, 180, 210,
 
// right of middle rung
100, 70, 210,
100, 70, 210,
100, 70, 210,
100, 70, 210,
100, 70, 210,
100, 70, 210,
 
// bottom of middle rung.
76, 210, 100,
76, 210, 100,
76, 210, 100,
76, 210, 100,
76, 210, 100,
76, 210, 100,
 
// right of bottom
140, 210, 80,
140, 210, 80,
140, 210, 80,
140, 210, 80,
140, 210, 80,
140, 210, 80,
// bottom
90, 130, 110,
90, 130, 110,
90, 130, 110,
90, 130, 110,
90, 130, 110,
90, 130, 110,
 
// left side
160, 160, 220,
160, 160, 220,
160, 160, 220,
160, 160, 220,
160, 160, 220,
160, 160, 220
],
GL_STATIC_DRAW
)
}
 
var Program
var PositionLocation
var ColorLocation
var MatrixLocation
var PositionBuffer
var ColorBuffer
 
var init = Fn.new {
// create vertex shader
var vShaderSource = """
#version 100
attribute vec4 a_position;
attribute vec4 a_color;
 
uniform mat4 u_matrix;
 
varying vec4 v_color;
 
void main() {
// Multiply the position by the matrix.
gl_Position = u_matrix * a_position;
 
// Pass the color to the fragment shader.
v_color = a_color;
}
"""
var vShader = Gl.createShader(GL_VERTEX_SHADER)
if (vShader == 0) Fiber.abort("Error creating vertex shader.")
Gl.shaderSource(vShader, 1, vShaderSource, null)
Gl.compileShader(vShader)
 
// create fragment shader
var fShaderSource = """
#version 100
precision mediump float;
 
// Passed in from the vertex shader.
varying vec4 v_color;
 
void main() {
gl_FragColor = v_color;
}
"""
var fShader = Gl.createShader(GL_FRAGMENT_SHADER)
if (fShader == 0) Fiber.abort("Error creating fragment shader.")
Gl.shaderSource(fShader, 1, fShaderSource, null)
Gl.compileShader(fShader)
 
// setup GLSL program
Program = Gl.createProgram()
Gl.attachShader(Program, vShader)
Gl.attachShader(Program, fShader)
Gl.linkProgram(Program)
 
// look up where the vertex data needs to go
PositionLocation = Gl.getAttribLocation(Program, "a_position")
ColorLocation = Gl.getAttribLocation(Program, "a_color")
// lookup uniforms
MatrixLocation = Gl.getUniformLocation(Program, "u_matrix")
// generate 2 buffer object names
var buffers = List.filled(2, 0)
Gl.genBuffers(2, buffers)
 
// Create a buffer to put positions in
PositionBuffer = buffers[0]
// Bind it to ARRAY_BUFFER
Gl.bindBuffer(GL_ARRAY_BUFFER, PositionBuffer)
// Put geometry data into buffer
setGeometry.call()
 
// Create a buffer to put colors in
ColorBuffer = buffers[1]
// Bind it to ARRAY_BUFFER
Gl.bindBuffer(GL_ARRAY_BUFFER, ColorBuffer)
// Put color data into buffer
setColors.call()
}
 
var Translation = [0, 0, -360]
var Rotation = [Math.radians(190), Math.radians(40), Math.radians(320)]
var Scale = [1, 1, 1]
var FieldOfViewRadians = Math.radians(60)
var WindowWidth = 640
var WindowHeight = 480
 
var drawScene // recursive function
drawScene = Fn.new {
Rotation[1] = Rotation[1] + 0.01
if (Rotation[1] >= 360) Rotation[1] = 0
 
// tell GLES how to convert from clip space to pixels
Gl.viewport(0, 0, WindowWidth, WindowHeight)
 
// clear the window and the depth buffer
Gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
 
// turn on culling. By default backfacing triangles will be culled
Gl.enable(GL_CULL_FACE)
 
// Enable the depth buffer
Gl.enable(GL_DEPTH_TEST)
 
// Tell it to use our program (pair of shaders)
Gl.useProgram(Program)
 
// Turn on the position attribute
Gl.enableVertexAttribArray(PositionLocation)
 
// Bind the position buffer.
Gl.bindBuffer(GL_ARRAY_BUFFER, PositionBuffer)
 
// tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
var size = 3 // 3 components per iteration
var type = GL_FLOAT // the data is 32 bit floats
var normalize = false // don't normalize the data
var stride = 0 // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0 // start at the beginning of the buffer
Gl.vertexAttribPtr(PositionLocation, size, type, normalize, stride, offset)
 
// Turn on the color attribute
Gl.enableVertexAttribArray(ColorLocation)
 
// Bind the color buffer.
Gl.bindBuffer(GL_ARRAY_BUFFER, ColorBuffer)
 
// Tell the attribute how to get data out of colorBuffer (ARRAY_BUFFER)
Gl.vertexAttribPtr(ColorLocation, size, type, normalize, stride, offset)
 
// compute the matrices
var aspect = WindowWidth / WindowHeight
var matrix = M4.perspective(FieldOfViewRadians, aspect, 1, 2000, null)
matrix = M4.translate(matrix, Translation[0], Translation[1], Translation[2], null)
matrix = M4.xRotate(matrix, Rotation[0], null)
matrix = M4.yRotate(matrix, Rotation[1], null)
matrix = M4.zRotate(matrix, Rotation[2], null)
matrix = M4.scale(matrix, Scale[0], Scale[1], Scale[2], null)
 
// set the matrix
Gl.uniformMatrix4fv(MatrixLocation, 1, false, matrix)
 
// draw the geometry
var primitiveType = GL_TRIANGLES
var count = 16 * 6
Gl.drawArrays(primitiveType, offset, count)
Gl.flush()
C.usleep(10000) // wait for 10 msec
drawScene.call()
}
 
Glut.initDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH)
Glut.initWindowSize(640, 480)
Glut.createWindow("Rotating F")
Glut.setOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS)
init.call()
drawScene.call()</lang>
<br>
We now embed the above code in the following C program, compile and run.
<lang c>/* gcc webgl_rotating_F.c -o webgl_rotating_F -lglut -lGLESv2 -lm -lwren */
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <GLES2/gl2.h>
#include <GL/freeglut.h>
#include <unistd.h>
#include "wren.h"
 
/* Gl functions */
 
void C_bufferData(WrenVM* vm) {
GLenum target = (GLenum)wrenGetSlotDouble(vm, 1);
GLsizeiptr size = (GLsizeiptr)wrenGetSlotDouble(vm, 2);
int count = wrenGetListCount(vm, 3);
GLenum usage = (GLenum)wrenGetSlotDouble(vm, 4);
float data[count];
for (int i = 0; i < count; ++i) {
wrenGetListElement(vm, 3, i, 1);
data[i] = (float)wrenGetSlotDouble(vm, 1);
if (size == 1) data[i] /= 255.0;
}
glBufferData(target, 4 * count, data, usage);
}
 
void C_createShader(WrenVM* vm) {
GLenum shaderType = (GLenum)wrenGetSlotDouble(vm, 1);
GLuint shader = glCreateShader(shaderType);
wrenSetSlotDouble(vm, 0, (double)shader);
}
 
void C_shaderSource(WrenVM* vm) {
GLuint shader = (GLuint)wrenGetSlotDouble(vm, 1);
GLsizei count = (GLsizei)wrenGetSlotDouble(vm, 2);
// assume for simplicity there will always be one shader string and the fourth parameter will be null
const GLchar *string = (const GLchar *)wrenGetSlotString(vm, 3);
glShaderSource(shader, count, &string, 0);
}
 
void C_compileShader(WrenVM* vm) {
GLuint shader = (GLuint)wrenGetSlotDouble(vm, 1);
glCompileShader(shader);
// check shader compiled ok
GLint shader_compiled;
glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_compiled);
if (shader_compiled != GL_TRUE) {
GLsizei log_length = 0;
GLchar message[1024];
glGetShaderInfoLog(shader, 1024, &log_length, message);
printf("%s\n", message);
}
}
 
void C_createProgram(WrenVM* vm) {
GLuint program = glCreateProgram();
wrenSetSlotDouble(vm, 0, (double)program);
}
 
void C_attachShader(WrenVM* vm) {
GLuint program = (GLuint)wrenGetSlotDouble(vm, 1);
GLuint shader = (GLuint)wrenGetSlotDouble(vm, 2);
glAttachShader(program, shader);
}
 
void C_linkProgram(WrenVM* vm) {
GLuint program = (GLuint)wrenGetSlotDouble(vm, 1);
// check program linked ok
glBindAttribLocation(program, 0, "position");
glBindAttribLocation(program, 1, "texcoord");
glBindAttribLocation(program, 2, "normal");
glBindAttribLocation(program, 3, "color");
glLinkProgram(program);
GLint program_linked;
glGetProgramiv(program, GL_LINK_STATUS, &program_linked);
if (program_linked != GL_TRUE) {
GLsizei log_length = 0;
GLchar message[1024];
glGetProgramInfoLog(program, 1024, &log_length, message);
printf("%s\n", message);
}
}
 
void C_getAttribLocation(WrenVM* vm) {
GLuint program = (GLuint)wrenGetSlotDouble(vm, 1);
const GLchar *name = (const GLchar *)wrenGetSlotString(vm, 2);
GLint location = glGetAttribLocation(program, name);
wrenSetSlotDouble(vm, 0, (double)location);
}
 
void C_getUniformLocation(WrenVM* vm) {
GLuint program = (GLuint)wrenGetSlotDouble(vm, 1);
const GLchar *name = (const GLchar *)wrenGetSlotString(vm, 2);
GLint location = glGetUniformLocation(program, name);
wrenSetSlotDouble(vm, 0, (double)location);
}
 
void C_genBuffers(WrenVM* vm) {
GLsizei n = (GLsizei)wrenGetSlotDouble(vm, 1);
int count = wrenGetListCount(vm, 2);
GLuint buffers[count];
glGenBuffers(n, buffers);
for (int i = 0; i < count; ++i) {
wrenSetSlotDouble(vm, 1, (double)buffers[i]);
wrenSetListElement(vm, 2, i, 1);
}
}
 
void C_bindBuffer(WrenVM* vm) {
GLenum target = (GLenum)wrenGetSlotDouble(vm, 1);
GLuint buffer = (GLuint)wrenGetSlotDouble(vm, 2);
glBindBuffer(target, buffer);
}
 
void C_viewport(WrenVM* vm) {
GLint x = (GLint)wrenGetSlotDouble(vm, 1);
GLint y = (GLint)wrenGetSlotDouble(vm, 2);
GLsizei width = (GLsizei)wrenGetSlotDouble(vm, 3);
GLsizei height = (GLsizei)wrenGetSlotDouble(vm, 4);
glViewport(x, y, width, height);
}
 
void C_clear(WrenVM* vm) {
glClearColor(1, 1, 1, 1); // always clear to white background
GLbitfield mask = (GLbitfield)wrenGetSlotDouble(vm, 1);
glClear(mask);
}
 
void C_enable(WrenVM* vm) {
GLenum cap = (GLenum)wrenGetSlotDouble(vm, 1);
glEnable(cap);
}
 
void C_useProgram(WrenVM* vm) {
GLuint program = (GLuint)wrenGetSlotDouble(vm, 1);
glUseProgram(program);
}
 
void C_drawArrays(WrenVM* vm) {
GLenum mode = (GLenum)wrenGetSlotDouble(vm, 1);
GLint first = (GLint)wrenGetSlotDouble(vm, 2);
GLsizei count = (GLsizei)wrenGetSlotDouble(vm, 3);
glDrawArrays(mode, first, count);
}
 
void C_enableVertexAttribArray(WrenVM* vm) {
GLuint index = (GLuint)wrenGetSlotDouble(vm, 1);
glEnableVertexAttribArray(index);
}
 
void C_vertexAttribPtr(WrenVM* vm) {
GLuint index = (GLuint)wrenGetSlotDouble(vm, 1);
GLint size = (GLint)wrenGetSlotDouble(vm, 2);
GLenum type = (GLenum)wrenGetSlotDouble(vm, 3);
GLboolean normalized = (GLboolean)wrenGetSlotBool(vm, 4);
GLsizei stride = (GLsizei)wrenGetSlotDouble(vm, 5);
// assume for simplicity sixth parameter will always be 0
glVertexAttribPointer(index, size, type, normalized, stride, 0);
}
 
void C_uniformMatrix4fv(WrenVM* vm) {
GLint location = (GLint)wrenGetSlotDouble(vm, 1);
GLsizei count = (GLsizei)wrenGetSlotDouble(vm, 2);
GLboolean transpose = (GLboolean)wrenGetSlotBool(vm, 3);
int len = wrenGetListCount(vm, 4);
GLfloat value[len];
for (int i = 0; i < len; ++i) {
wrenGetListElement(vm, 4, i, 1);
value[i] = (GLfloat)wrenGetSlotDouble(vm, 1);
}
glUniformMatrix4fv(location, count, transpose, value);
}
 
void C_flush(WrenVM* vm) {
glFlush();
}
 
/* Glut functions */
 
void C_initDisplayMode(WrenVM* vm) {
unsigned int mode = (unsigned int)wrenGetSlotDouble(vm, 1);
glutInitDisplayMode(mode);
}
 
void C_initWindowSize(WrenVM* vm) {
int width = (int)wrenGetSlotDouble(vm, 1);
int height = (int)wrenGetSlotDouble(vm, 2);
glutInitWindowSize(width, height);
}
 
void C_createWindow(WrenVM* vm) {
const char *name = wrenGetSlotString(vm, 1);
glutCreateWindow(name);
}
 
void C_setOption(WrenVM* vm) {
GLenum eWhat = (GLenum)wrenGetSlotDouble(vm, 1);
int value = (int)wrenGetSlotDouble(vm, 2);
glutSetOption(eWhat, value);
}
 
/* C function */
 
void C_usleep(WrenVM* vm) {
useconds_t usec = (useconds_t)wrenGetSlotDouble(vm, 1);
usleep(usec);
}
 
WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "main") == 0) {
if (strcmp(className, "Gl") == 0) {
if (isStatic && strcmp(signature, "bufferData(_,_,_,_)") == 0) return C_bufferData;
if (isStatic && strcmp(signature, "createShader(_)") == 0) return C_createShader;
if (isStatic && strcmp(signature, "shaderSource(_,_,_,_)") == 0) return C_shaderSource;
if (isStatic && strcmp(signature, "compileShader(_)") == 0) return C_compileShader;
if (isStatic && strcmp(signature, "createProgram()") == 0) return C_createProgram;
if (isStatic && strcmp(signature, "attachShader(_,_)") == 0) return C_attachShader;
if (isStatic && strcmp(signature, "linkProgram(_)") == 0) return C_linkProgram;
if (isStatic && strcmp(signature, "getAttribLocation(_,_)") == 0) return C_getAttribLocation;
if (isStatic && strcmp(signature, "getUniformLocation(_,_)") == 0) return C_getUniformLocation;
if (isStatic && strcmp(signature, "genBuffers(_,_)") == 0) return C_genBuffers;
if (isStatic && strcmp(signature, "bindBuffer(_,_)") == 0) return C_bindBuffer;
if (isStatic && strcmp(signature, "viewport(_,_,_,_)") == 0) return C_viewport;
if (isStatic && strcmp(signature, "clear(_)") == 0) return C_clear;
if (isStatic && strcmp(signature, "enable(_)") == 0) return C_enable;
if (isStatic && strcmp(signature, "useProgram(_)") == 0) return C_useProgram;
if (isStatic && strcmp(signature, "drawArrays(_,_,_)") == 0) return C_drawArrays;
if (isStatic && strcmp(signature, "flush()") == 0) return C_flush;
 
if (isStatic && strcmp(signature, "enableVertexAttribArray(_)") == 0) return C_enableVertexAttribArray;
if (isStatic && strcmp(signature, "vertexAttribPtr(_,_,_,_,_,_)") == 0) return C_vertexAttribPtr;
if (isStatic && strcmp(signature, "uniformMatrix4fv(_,_,_,_)") == 0) return C_uniformMatrix4fv;
} else if (strcmp(className, "Glut") == 0) {
if (isStatic && strcmp(signature, "initDisplayMode(_)") == 0) return C_initDisplayMode;
if (isStatic && strcmp(signature, "initWindowSize(_,_)") == 0) return C_initWindowSize;
if (isStatic && strcmp(signature, "createWindow(_)") == 0) return C_createWindow;
if (isStatic && strcmp(signature, "setOption(_,_)") == 0) return C_setOption;
} else if (strcmp(className, "C") == 0) {
if (isStatic && strcmp(signature, "usleep(_)") == 0) return C_usleep;
}
}
return NULL;
}
 
static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}
 
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}
 
char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
fread(script, 1, fsize, f);
fclose(f);
script[fsize] = 0;
return script;
}
 
static void loadModuleComplete(WrenVM* vm, const char* module, WrenLoadModuleResult result) {
if( result.source) free((void*)result.source);
}
 
WrenLoadModuleResult loadModule(WrenVM* vm, const char* name) {
WrenLoadModuleResult result = {0};
if (strcmp(name, "random") != 0 && strcmp(name, "meta") != 0) {
result.onComplete = loadModuleComplete;
char fullName[strlen(name) + 6];
strcpy(fullName, name);
strcat(fullName, ".wren");
result.source = readFile(fullName);
}
return result;
}
 
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitContextVersion(2, 0);
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignMethodFn = &bindForeignMethod;
config.loadModuleFn = &loadModule;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "webgl_rotating_F.wren";
char *script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
printf("Compile Error!\n");
break;
case WREN_RESULT_RUNTIME_ERROR:
printf("Runtime Error!\n");
break;
case WREN_RESULT_SUCCESS:
break;
}
glutMainLoop();
wrenFreeVM(vm);
free(script);
return 0;
}</lang>
9,476

edits