OpenGL/Utah teapot
This is a way to render the classic Utah Teapot using OpenGL library.
See also: Utah Teapot wikipage.
C
As well explained on the Wikipedia page ( link above ), the teapot played such an important role in the development of Computer Graphics, that Mark Kilgard honoured it by giving it it's own primitive drawing functions. freeglut did even better and implemented the rest of the tea set, yes, the API also provides a cup and a spoon.
This implementation sticks to the task requirements and only shows the teapot, it's rotating, so you can enjoy it's magnificence from all possible viewpoints and perspectives.
#include<gl/freeglut.h>
double rot = 0;
float matCol[] = {1,0,0,0};
void display(){
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(30,1,1,0);
glRotatef(rot,0,1,1);
glMaterialfv(GL_FRONT,GL_DIFFUSE,matCol);
glutWireTeapot(0.5);
glPopMatrix();
glFlush();
}
void onIdle(){
rot += 0.01;
glutPostRedisplay();
}
void init(){
float pos[] = {1,1,1,0};
float white[] = {1,1,1,0};
float shini[] = {70};
glClearColor(.5,.5,.5,0);
glShadeModel(GL_SMOOTH);
glLightfv(GL_LIGHT0,GL_AMBIENT,white);
glLightfv(GL_LIGHT0,GL_DIFFUSE,white);
glMaterialfv(GL_FRONT,GL_SHININESS,shini);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
}
int main(int argC, char* argV[])
{
glutInit(&argC,argV);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH);
glutInitWindowSize(900,700);
glutCreateWindow("The Amazing, Rotating Utah Teapot brought to you in OpenGL via freeglut.");
init();
glutDisplayFunc(display);
glutIdleFunc(onIdle);
glutMainLoop();
return 0;
}
FreeBASIC
#include "fbgfx.bi"
#include once "GL/glut.bi"
Dim Shared As Double rot = 0.0
Sub onIdle Cdecl ()
rot += 0.01
glutPostRedisplay()
End Sub
Sub display Cdecl ()
Dim matCol(0 To 3) As Const GLfloat = {1, 0, 0, 0}
glClear GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT
glPushMatrix()
glRotatef(30, 1, 1, 0)
glRotatef(rot, 0, 1, 1)
glMaterialfv GL_FRONT, GL_DIFFUSE, @matCol(0)
glutWireTeapot(0.5)
glPopMatrix()
glFlush()
End Sub
Sub init Cdecl ()
Dim white(0 To 3) As Const GLfloat = {1, 1, 1, 0}
Dim shini(1) As Const GLfloat = {70}
glClearColor(0.5, 0.5, 0.5, 0)
glShadeModel(GL_SMOOTH)
glLightfv(GL_LIGHT0, GL_AMBIENT, @white(0))
glLightfv(GL_LIGHT0, GL_DIFFUSE, @white(0))
glMaterialfv(GL_FRONT, GL_SHININESS, @shini(0))
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_DEPTH_TEST)
End Sub
Var argc = Cint(0)
glutInit(0, Strptr( " " ))
glutInitDisplayMode GLUT_SINGLE Or GLUT_RGB Or GLUT_DEPTH
glutInitWindowSize(900, 700)
glutCreateWindow("Utah Teapot")
glutIdleFunc(@onIdle)
glutDisplayFunc(@display)
init()
glutMainLoop()
Go
Although there are a number of third party Go bindings for OpenGL, the following uses 'cgo' to interface directly with the C libraries.
package main
/*
#cgo LDFLAGS: -lGL -lGLU -lglut
#include <stdlib.h>
#include <GL/freeglut.h>
extern void display();
extern void onIdle();
typedef void (*callback) ();
static inline callback displayFunc() {
return display;
}
static inline callback idleFunc() {
return onIdle;
}
*/
import "C"
import "unsafe"
var rot = 0.0
var matCol = [4]C.float{1, 0, 0, 0}
//export display
func display() {
C.glClear(C.GL_COLOR_BUFFER_BIT | C.GL_DEPTH_BUFFER_BIT)
C.glPushMatrix()
C.glRotatef(30, 1, 1, 0)
C.glRotatef(C.float(rot), 0, 1, 1)
C.glMaterialfv(C.GL_FRONT, C.GL_DIFFUSE, &matCol[0])
C.glutWireTeapot(0.5)
C.glPopMatrix()
C.glFlush()
}
//export onIdle
func onIdle() {
rot += 0.01
C.glutPostRedisplay()
}
func initialize() {
white := [4]C.float{1, 1, 1, 0}
shini := [1]C.float{70}
C.glClearColor(0.5, 0.5, 0.5, 0)
C.glShadeModel(C.GL_SMOOTH)
C.glLightfv(C.GL_LIGHT0, C.GL_AMBIENT, &white[0])
C.glLightfv(C.GL_LIGHT0, C.GL_DIFFUSE, &white[0])
C.glMaterialfv(C.GL_FRONT, C.GL_SHININESS, &shini[0])
C.glEnable(C.GL_LIGHTING)
C.glEnable(C.GL_LIGHT0)
C.glEnable(C.GL_DEPTH_TEST)
}
func main() {
argc := C.int(0)
C.glutInit(&argc, nil)
C.glutInitDisplayMode(C.GLUT_SINGLE | C.GLUT_RGB | C.GLUT_DEPTH)
C.glutInitWindowSize(900, 700)
tl := "The Amazing, Rotating Utah Teapot brought to you in OpenGL via freeglut."
tlc := C.CString(tl)
C.glutCreateWindow(tlc)
initialize()
C.glutDisplayFunc(C.displayFunc())
C.glutIdleFunc(C.idleFunc())
C.glutMainLoop()
C.free(unsafe.Pointer(tlc))
}
J
Direct translation from C.
NB. Teapot using freeglut
require '~Projects/freeglut/gldefs.ijs'
f=: 1.1-1.1
void=: 0$''
rot=: f+0
matCol=: f+1 0 0 0
cb1=: cdcb '+ x x'
cb2=: cdcb '+ x x x'
cdcallback=: 3 : 0
y=. 15!:17''
select. #y
case. 1 do. display 0
case. 2 do. onIdle 0
end.
)
display=: 3 : 0
glClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT)
glPushMatrix void
glRotatef((30+f);(1+f);(1+f);f)
glRotatef(rot;f;(1+f);(1+f))
glMaterialfv(GL_FRONT;GL_DIFFUSE;<matCol)
glutWireTeapot(0.5)
glPopMatrix void
glFlush void
)
onIdle=: 3 : 0
rot=: rot+0.01
glutPostRedisplay void
)
init=: 3 : 0
pos=. f+1,1,1,0
white=. f+1,1,1,0
shini=. ,f+70
glClearColor(0.5;0.5;0.5;f)
glShadeModel(GL_SMOOTH)
glLightfv(GL_LIGHT0;GL_AMBIENT;white)
glLightfv(GL_LIGHT0;GL_DIFFUSE;white)
glMaterialfv(GL_FRONT;GL_SHININESS;shini)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_DEPTH_TEST)
)
main=: 3 : 0
argC=. ,2-2
argV=.<,0{a.
glutInit(argC;argV)
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE;GLUT_ACTION_GLUTMAINLOOP_RETURNS)
glutInitDisplayMode(GLUT_SINGLE+GLUT_RGB+GLUT_DEPTH)
glutInitWindowSize(900;700)
glutCreateWindow(<'The Amazing, Rotating Utah Teapot brought to you in OpenGL via freeglut.')
init void
glutDisplayFunc(cb1)
glutIdleFunc(cb2)
glutMainLoop void
void
)
Julia
Makie implements OpenGL shading graphics as part of its plotting functionality. The files are from the University of Utah site.
using Makie, FileIO, InfoZIP
if stat("newell_teaset/teapot.obj").size == 0
download("https://www.cs.utah.edu/~natevm/newell_teaset/newell_teaset.zip", "newell_teaset.zip")
InfoZIP.unzip("newell_teaset.zip")
end
utah_teapot = FileIO.load("newell_teaset/teapot.obj")
scene = plot(utah_teapot; color = :aquamarine, shading=true, show_axis=false)
rotate!(scene, Quaternion(0.6, 0.2, 0.2, 4.0))
display(scene)
Kotlin
Assuming that freeglut is already installed on your system in the default location(s), you first need to build opengl.klib using the following .def file and the cinterop tool:
// opengl.def headers = /usr/include/GL/glut.h compilerOpts = -I/usr/include linkerOpts = -L/usr/lib/x86_64-linux-gnu -lglut -lGL -lGLU
You then need to compile the following Kotlin program, linking against opengl.klib, and run the resulting .kexe file to view the rotating teapot.
// Kotlin Native v0.6
import kotlinx.cinterop.*
import opengl.*
var rot = 0f
val matCol = floatArrayOf(1f, 0f, 0f, 0f)
fun display() {
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
glPushMatrix()
glRotatef(30f, 1f, 1f, 0f)
glRotatef(rot, 0f, 1f, 1f)
glMaterialfv(GL_FRONT, GL_DIFFUSE, matCol.toCValues())
glutWireTeapot(0.5)
glPopMatrix()
glFlush()
}
fun onIdle() {
rot += 0.1f
glutPostRedisplay()
}
fun init() {
val white = floatArrayOf(1f, 1f, 1f, 0f)
val shini = floatArrayOf(70f)
glClearColor(0.5f, 0.5f, 0.5f, 0f);
glShadeModel(GL_SMOOTH)
glLightfv(GL_LIGHT0, GL_AMBIENT, white.toCValues())
glLightfv(GL_LIGHT0, GL_DIFFUSE, white.toCValues())
glMaterialfv(GL_FRONT, GL_SHININESS, shini.toCValues())
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_DEPTH_TEST)
}
fun main(args: Array<String>) {
memScoped {
val argc = alloc<IntVar>().apply { value = 0 }
glutInit(argc.ptr, null)
}
glutInitDisplayMode(GLUT_SINGLE or GLUT_RGB or GLUT_DEPTH)
glutInitWindowSize(900, 700)
val title = "The Amazing, Rotating Utah Teapot brought to you in OpenGL via freeglut."
glutCreateWindow(title)
init()
glutDisplayFunc(staticCFunction(::display))
glutIdleFunc(staticCFunction(::onIdle))
glutMainLoop()
}
Nim
import opengl, opengl/glut
var
rot = 0.0
matCol = [GLfloat 1, 0, 0, 0]
proc onIdle() {.cdecl.} =
rot += 0.01
glutPostRedisplay()
proc display() {.cdecl.} =
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
glPushMatrix()
glRotatef(30, 1, 1, 0)
glRotatef(rot, 0, 1, 1)
glMaterialfv(GL_FRONT, GL_DIFFUSE, addr(matCol[0]))
glutWireTeapot(0.5)
glPopMatrix()
glFlush()
var argc: cint = 0
glutInit(addr(argc), nil)
glutInitDisplayMode(GLUT_SINGLE or GLUT_RGB or GLUT_DEPTH)
glutInitWindowSize(900, 700)
discard glutCreateWindow("Utah Teapot")
glutIdleFunc(onIdle)
glutDisplayFunc(display)
loadExtensions()
glutMainLoop()
Ol
; initial data:
(define vertices '(
( 0.2000 0.0000 2.70000 ) ( 0.2000 -0.1120 2.70000 )
( 0.1120 -0.2000 2.70000 ) ( 0.0000 -0.2000 2.70000 )
( 1.3375 0.0000 2.53125 ) ( 1.3375 -0.7490 2.53125 )
( 0.7490 -1.3375 2.53125 ) ( 0.0000 -1.3375 2.53125 )
( 1.4375 0.0000 2.53125 ) ( 1.4375 -0.8050 2.53125 )
( 0.8050 -1.4375 2.53125 ) ( 0.0000 -1.4375 2.53125 )
( 1.5000 0.0000 2.40000 ) ( 1.5000 -0.8400 2.40000 )
( 0.8400 -1.5000 2.40000 ) ( 0.0000 -1.5000 2.40000 )
( 1.7500 0.0000 1.87500 ) ( 1.7500 -0.9800 1.87500 )
( 0.9800 -1.7500 1.87500 ) ( 0.0000 -1.7500 1.87500 )
( 2.0000 0.0000 1.35000 ) ( 2.0000 -1.1200 1.35000 )
( 1.1200 -2.0000 1.35000 ) ( 0.0000 -2.0000 1.35000 )
( 2.0000 0.0000 0.90000 ) ( 2.0000 -1.1200 0.90000 )
( 1.1200 -2.0000 0.90000 ) ( 0.0000 -2.0000 0.90000 )
( -2.0000 0.0000 0.90000 ) ( 2.0000 0.0000 0.45000 )
( 2.0000 -1.1200 0.45000 ) ( 1.1200 -2.0000 0.45000 )
( 0.0000 -2.0000 0.45000 ) ( 1.5000 0.0000 0.22500 )
( 1.5000 -0.8400 0.22500 ) ( 0.8400 -1.5000 0.22500 )
( 0.0000 -1.5000 0.22500 ) ( 1.5000 0.0000 0.15000 )
( 1.5000 -0.8400 0.15000 ) ( 0.8400 -1.5000 0.15000 )
( 0.0000 -1.5000 0.15000 ) ( -1.6000 0.0000 2.02500 )
( -1.6000 -0.3000 2.02500 ) ( -1.5000 -0.3000 2.25000 )
( -1.5000 0.0000 2.25000 ) ( -2.3000 0.0000 2.02500 )
( -2.3000 -0.3000 2.02500 ) ( -2.5000 -0.3000 2.25000 )
( -2.5000 0.0000 2.25000 ) ( -2.7000 0.0000 2.02500 )
( -2.7000 -0.3000 2.02500 ) ( -3.0000 -0.3000 2.25000 )
( -3.0000 0.0000 2.25000 ) ( -2.7000 0.0000 1.80000 )
( -2.7000 -0.3000 1.80000 ) ( -3.0000 -0.3000 1.80000 )
( -3.0000 0.0000 1.80000 ) ( -2.7000 0.0000 1.57500 )
( -2.7000 -0.3000 1.57500 ) ( -3.0000 -0.3000 1.35000 )
( -3.0000 0.0000 1.35000 ) ( -2.5000 0.0000 1.12500 )
( -2.5000 -0.3000 1.12500 ) ( -2.6500 -0.3000 0.93750 )
( -2.6500 0.0000 0.93750 ) ( -2.0000 -0.3000 0.90000 )
( -1.9000 -0.3000 0.60000 ) ( -1.9000 0.0000 0.60000 )
( 1.7000 0.0000 1.42500 ) ( 1.7000 -0.6600 1.42500 )
( 1.7000 -0.6600 0.60000 ) ( 1.7000 0.0000 0.60000 )
( 2.6000 0.0000 1.42500 ) ( 2.6000 -0.6600 1.42500 )
( 3.1000 -0.6600 0.82500 ) ( 3.1000 0.0000 0.82500 )
( 2.3000 0.0000 2.10000 ) ( 2.3000 -0.2500 2.10000 )
( 2.4000 -0.2500 2.02500 ) ( 2.4000 0.0000 2.02500 )
( 2.7000 0.0000 2.40000 ) ( 2.7000 -0.2500 2.40000 )
( 3.3000 -0.2500 2.40000 ) ( 3.3000 0.0000 2.40000 )
( 2.8000 0.0000 2.47500 ) ( 2.8000 -0.2500 2.47500 )
( 3.5250 -0.2500 2.49375 ) ( 3.5250 0.0000 2.49375 )
( 2.9000 0.0000 2.47500 ) ( 2.9000 -0.1500 2.47500 )
( 3.4500 -0.1500 2.51250 ) ( 3.4500 0.0000 2.51250 )
( 2.8000 0.0000 2.40000 ) ( 2.8000 -0.1500 2.40000 )
( 3.2000 -0.1500 2.40000 ) ( 3.2000 0.0000 2.40000 )
( 0.0000 0.0000 3.15000 ) ( 0.8000 0.0000 3.15000 )
( 0.8000 -0.4500 3.15000 ) ( 0.4500 -0.8000 3.15000 )
( 0.0000 -0.8000 3.15000 ) ( 0.0000 0.0000 2.85000 )
( 1.4000 0.0000 2.40000 ) ( 1.4000 -0.7840 2.40000 )
( 0.7840 -1.4000 2.40000 ) ( 0.0000 -1.4000 2.40000 )
( 0.4000 0.0000 2.55000 ) ( 0.4000 -0.2240 2.55000 )
( 0.2240 -0.4000 2.55000 ) ( 0.0000 -0.4000 2.55000 )
( 1.3000 0.0000 2.55000 ) ( 1.3000 -0.7280 2.55000 )
( 0.7280 -1.3000 2.55000 ) ( 0.0000 -1.3000 2.55000 )
( 1.3000 0.0000 2.40000 ) ( 1.3000 -0.7280 2.40000 )
( 0.7280 -1.3000 2.40000 ) ( 0.0000 -1.3000 2.40000 )))
(define Rim: '(
( 102 103 104 105 4 5 6 7
8 9 10 11 12 13 14 15 )))
(define Body: '(
( 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 )
( 24 25 26 27 29 30 31 32
33 34 35 36 37 38 39 40 )))
(define Lid: '(
( 96 96 96 96 97 98 99 100
101 101 101 101 0 1 2 3 )
( 0 1 2 3 106 107 108 109
110 111 112 113 114 115 116 117 )))
(define Handle: '(
( 41 42 43 44 45 46 47 48
49 50 51 52 53 54 55 56 )
( 53 54 55 56 57 58 59 60
61 62 63 64 28 65 66 67 )))
(define Spout: '(
( 68 69 70 71 72 73 74 75
76 77 78 79 80 81 82 83 )
( 80 81 82 83 84 85 86 87
88 89 90 91 92 93 94 95 )))
; render pass:
(define knots '(0 0 0 0 1 1 1 1))
(let ((render (lambda (surface)
(gluBeginSurface teapot)
(gluNurbsSurface teapot 8 knots 8 knots (* 4 3) 3 (fold append '() (map (lambda (n) (nth vertices n)) surface)) 4 4 GL_MAP2_VERTEX_3)
(gluEndSurface teapot))))
(for-each render Rim:)
(for-each render Body:)
(for-each render Lid:)
(glScalef -1 1 1)
(for-each render Rim:)
(for-each render Body:)
(for-each render Lid:)
(glScalef -1 -1 1)
(for-each render Rim:)
(for-each render Body:)
(for-each render Lid:)
(glScalef -1 1 1)
(for-each render Rim:)
(for-each render Body:)
(for-each render Lid:)
(for-each render Handle:)
(for-each render Spout:)
(glScalef 1 -1 1)
(for-each render Handle:)
(for-each render Spout:))
Phix
without js -- (freeglut, allocate, poke, OpenGL 1.0) include GL/gl.e include GL/freeglut.e atom rot = 0; atom matCol = allocate(16) poke(matCol, atom_to_float32(1) & atom_to_float32(0) & atom_to_float32(0) & atom_to_float32(0) ) function display() glClear(or_bits(GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT)) glPushMatrix() glRotatef(30,1,1,0) glRotatef(rot,0,1,1) glMaterialfv(GL_FRONT,GL_DIFFUSE,matCol) glutWireTeapot(0.5) glPopMatrix() glFlush() return 0 end function function onIdle() rot += 0.01 glutPostRedisplay() return 0 end function procedure init() atom white = allocate(16) poke(white, atom_to_float32(1) & atom_to_float32(1) & atom_to_float32(1) & atom_to_float32(0) ) atom shini = allocate(4) poke(shini, atom_to_float32(70) ) glClearColor(.5,.5,.5,0) glShadeModel(GL_SMOOTH) glLightfv(GL_LIGHT0,GL_AMBIENT,white) glLightfv(GL_LIGHT0,GL_DIFFUSE,white) glMaterialfv(GL_FRONT,GL_SHININESS,shini) glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) glEnable(GL_DEPTH_TEST) end procedure procedure main() glutInit() glutInitDisplayMode(or_all({GLUT_SINGLE,GLUT_RGB,GLUT_DEPTH})) glutInitWindowSize(900,700) {} = glutCreateWindow("The Amazing, Rotating Utah Teapot brought to you in OpenGL via freeglut.") init() glutDisplayFunc(call_back(routine_id("display"))) glutIdleFunc(call_back(routine_id("onIdle"))) glutMainLoop() end procedure main()
To run this, you will need the freeglut package from PCAN
Raku
# 20210524 Raku programming solution
use NativeCall;
my $rot = 0e0;
# https://www.khronos.org/opengl/wiki/OpenGL_Type
enum GLenum (
GL_SMOOTH => 0x1D01, GL_LIGHT0 => 0x4000, GL_AMBIENT => 0x1200,
GL_DIFFUSE => 0x1201, GL_FRONT => 0x0404, GL_SHININESS => 0x1601,
GL_LIGHTING => 0x0B50, GL_DEPTH_TEST => 0x0B71,
);
enum GLbitfield ( GL_COLOR_BUFFER_BIT => 0x00004000, GL_DEPTH_BUFFER_BIT => 0x00000100, );
enum GLUTdisplay_mode ( GLUT_RGB => 0x0000, GLUT_SINGLE => 0x0000, GLUT_DEPTH => 0x0010, );
constant $lib = 'glut';
sub glutInit(CArray[uint32], CArray[Str]) is native($lib) {*};
sub glutInitDisplayMode(uint32 $mode) is native($lib) {*};
sub glutInitWindowSize(int32 $width, int32 $height) is native($lib) {*};
sub glutCreateWindow(Str $str) is native($lib) {*};
sub glutDisplayFunc(&func ()) is native($lib) {*};
sub glutWireTeapot(num64 $size) is native($lib) {*};
sub glutIdleFunc(&func ()) is native($lib) {*};
sub glutPostRedisplay() is native($lib) {*};
sub glutMainLoop() is native($lib) {*};
constant $gllib = 'GL';
sub glClearColor(num32 $red, num32 $green, num32 $blue, num32 $alpha) is native($gllib) {*};
sub glShadeModel(int32) is native($gllib) {*};
sub glEnable(int32) is native($gllib) {*};
sub glClear(int32) is native($gllib) {*};
sub glRotatef(num32 $angle, num32 $x, num32 $y, num32 $z) is native($gllib) {*};
sub glPushMatrix() is native($gllib) {*};
sub glPopMatrix() is native($gllib) {*};
sub glFlush() is native($gllib) {*};
sub glLightfv (int32, int32, CArray[num32]) is native($gllib) {*};
sub glMaterialfv(int32, int32, CArray[num32]) is native($gllib) {*};
sub init {
glClearColor(.5e0,.5e0,.5e0,0e0);
glShadeModel(GL_SMOOTH);
glLightfv(GL_LIGHT0,GL_AMBIENT,CArray[num32].new: 1e0,1e0,1e0,0e0); # white
glLightfv(GL_LIGHT0,GL_DIFFUSE,CArray[num32].new: 1e0,1e0,1e0,0e0); # white
glMaterialfv(GL_FRONT,GL_SHININESS,CArray[num32].new: 70e0); # skinless so no effect ?
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
}
sub display {
glClear(GL_COLOR_BUFFER_BIT+|GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(30e0,1e0,1e0,0e0);
glRotatef($rot,0e0,1e0,1e0);
glMaterialfv(GL_FRONT,GL_DIFFUSE, CArray[num32].new: 0e0,1e0,0e0,0e0); # green
glutWireTeapot(.5e0);
glPopMatrix();
glFlush();
}
sub onIdle {
$rot += 0.1e0; # changed from 0.01 for faster rotation rate
glutPostRedisplay();
}
glutInit(CArray[uint32].new,CArray[Str].new);
glutInitDisplayMode(GLUT_SINGLE+|GLUT_RGB+|GLUT_DEPTH);
glutInitWindowSize(900,700);
glutCreateWindow("The Amazing, Rotating Utah Teapot brought to you in OpenGL via freeglut.");
init();
glutDisplayFunc(&display);
glutIdleFunc(&onIdle);
glutMainLoop();
Output: (Offsite Media file)
Wren
As it's not currently possible for Wren-cli to access OpenGL directly, we embed a Wren script in a C application to complete this task. See the OpenGL#Wren task for some of the issues involved here.
/* OpenGL_Utah_teapot.wren */
var Rot = 0
var MatCol = [1, 0, 0, 0]
var GL_COLOR_BUFFER_BIT = 0x4000
var GL_DEPTH_BUFFER_BIT = 0x0100
var GL_SMOOTH = 0x1d01
var GL_FRONT = 0x0404
var GL_DIFFUSE = 0x1201
var GL_LIGHT0 = 0x4000
var GL_AMBIENT = 0x1200
var GL_LIGHTING = 0x0b50
var GL_SHININESS = 0x1601
var GL_DEPTH_TEST = 0x0B71
var GLUT_SINGLE = 0x0000
var GLUT_RGB = 0x0000
var GLUT_DEPTH = 0x0010
var GLUT_ACTION_ON_WINDOW_CLOSE = 0x01f9
var GLUT_ACTION_GLUTMAINLOOP_RETURNS = 0x0001
class GL {
foreign static clearColor(red, green, blue, alpha)
foreign static clear(mask)
foreign static shadeModel(mode)
foreign static pushMatrix()
foreign static rotatef(angle, x, y, z)
foreign static materialfv(face, pname, params)
foreign static popMatrix()
foreign static flush()
foreign static lightfv(light, pname, params)
foreign static enable(cap)
}
class Glut {
foreign static initDisplayMode(mode)
foreign static initWindowSize(width, height)
foreign static createWindow(name)
foreign static displayFunc(clazz, method)
foreign static idleFunc(clazz, method)
foreign static postRedisplay()
foreign static wireTeapot(dSize)
foreign static setOption(eWhat, value)
}
class GLCallbacks {
static display() {
GL.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
GL.pushMatrix()
GL.rotatef(30, 1, 1, 0)
GL.rotatef(Rot, 0, 1, 1)
GL.materialfv(GL_FRONT, GL_DIFFUSE, MatCol)
Glut.wireTeapot(0.5)
GL.popMatrix()
GL.flush()
}
static onIdle() {
Rot = Rot + 0.01
Glut.postRedisplay()
}
}
var init = Fn.new {
var white = [1, 1, 1, 0]
var shini = [70]
GL.clearColor(0.5, 0.5, 0.5, 0)
GL.shadeModel(GL_SMOOTH)
GL.lightfv(GL_LIGHT0, GL_AMBIENT, white)
GL.lightfv(GL_LIGHT0, GL_DIFFUSE, white)
GL.materialfv(GL_FRONT, GL_SHININESS, shini)
GL.enable(GL_LIGHTING)
GL.enable(GL_LIGHT0)
GL.enable(GL_DEPTH_TEST)
}
Glut.initDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH)
Glut.initWindowSize(900, 700)
Glut.createWindow("The Amazing, Rotating Utah Teapot brought to you in OpenGL via freeglut.")
init.call()
Glut.displayFunc("GLCallbacks", "display()")
Glut.idleFunc("GLCallbacks", "onIdle()")
Glut.setOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS)
We now embed this Wren script in the following C program, compile and run it.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <GL/gl.h>
#include <GL/freeglut.h>
#include "wren.h"
/* C <=> Wren interface functions */
WrenVM *vm;
const char *displayClass, *displayMethod, *idleClass, *idleMethod;
void display() {
wrenEnsureSlots(vm, 1);
wrenGetVariable(vm, "main", displayClass, 0);
WrenHandle *method = wrenMakeCallHandle(vm, displayMethod);
wrenCall(vm, method);
wrenReleaseHandle(vm, method);
}
void idle() {
wrenEnsureSlots(vm, 1);
wrenGetVariable(vm, "main", idleClass, 0);
WrenHandle *method = wrenMakeCallHandle(vm, idleMethod);
wrenCall(vm, method);
wrenReleaseHandle(vm, method);
}
void C_clearColor(WrenVM* vm) {
GLclampf red = (GLclampf)wrenGetSlotDouble(vm, 1);
GLclampf green = (GLclampf)wrenGetSlotDouble(vm, 2);
GLclampf blue = (GLclampf)wrenGetSlotDouble(vm, 3);
GLclampf alpha = (GLclampf)wrenGetSlotDouble(vm, 4);
glClearColor(red, green, blue, alpha);
}
void C_clear(WrenVM* vm) {
GLbitfield mask = (GLbitfield)wrenGetSlotDouble(vm, 1);
glClear(mask);
}
void C_shadeModel(WrenVM* vm) {
GLenum mode = (GLenum)wrenGetSlotDouble(vm, 1);
glShadeModel(mode);
}
void C_pushMatrix(WrenVM* vm) {
glPushMatrix();
}
void C_rotatef(WrenVM* vm) {
GLdouble angle = (GLdouble)wrenGetSlotDouble(vm, 1);
GLdouble x = (GLdouble)wrenGetSlotDouble(vm, 2);
GLdouble y = (GLdouble)wrenGetSlotDouble(vm, 3);
GLdouble z = (GLdouble)wrenGetSlotDouble(vm, 4);
glRotatef(angle, x, y, z);
}
void C_materialfv(WrenVM* vm) {
GLenum face = (GLenum)wrenGetSlotDouble(vm, 1);
GLenum pname = (GLenum)wrenGetSlotDouble(vm, 2);
int count = wrenGetListCount(vm, 3);
GLfloat params[count];
int i;
for (i = 0; i < count; ++i) {
wrenGetListElement(vm, 3, i, 1);
params[i] = (GLfloat)wrenGetSlotDouble(vm, 1);
}
glMaterialfv(face, pname, (const GLfloat*)params);
}
void C_popMatrix(WrenVM* vm) {
glPopMatrix();
}
void C_flush(WrenVM* vm) {
glFlush();
}
void C_lightfv(WrenVM* vm) {
GLenum light = (GLenum)wrenGetSlotDouble(vm, 1);
GLenum pname = (GLenum)wrenGetSlotDouble(vm, 2);
int count = wrenGetListCount(vm, 3);
GLfloat params[count];
int i;
for (i = 0; i < count; ++i) {
wrenGetListElement(vm, 3, i, 1);
params[i] = (GLfloat)wrenGetSlotDouble(vm, 1);
}
glLightfv(light, pname, (const GLfloat*)params);
}
void C_enable(WrenVM* vm) {
GLenum cap = (GLenum)wrenGetSlotDouble(vm, 1);
glEnable(cap);
}
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_displayFunc(WrenVM* vm) {
displayClass = wrenGetSlotString(vm, 1);
displayMethod = wrenGetSlotString(vm, 2);
glutDisplayFunc(&display);
}
void C_idleFunc(WrenVM* vm) {
idleClass = wrenGetSlotString(vm, 1);
idleMethod = wrenGetSlotString(vm, 2);
glutIdleFunc(&idle);
}
void C_postRedisplay(WrenVM* vm) {
glutPostRedisplay();
}
void C_wireTeapot(WrenVM* vm) {
GLdouble dSize = (GLdouble)wrenGetSlotDouble(vm, 1);
glutWireTeapot(dSize);
}
void C_setOption(WrenVM* vm) {
GLenum eWhat = (GLenum)wrenGetSlotDouble(vm, 1);
int value = (int)wrenGetSlotDouble(vm, 2);
glutSetOption(eWhat, value);
}
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, "clearColor(_,_,_,_)") == 0) return C_clearColor;
if (isStatic && strcmp(signature, "clear(_)") == 0) return C_clear;
if (isStatic && strcmp(signature, "shadeModel(_)") == 0) return C_shadeModel;
if (isStatic && strcmp(signature, "pushMatrix()") == 0) return C_pushMatrix;
if (isStatic && strcmp(signature, "rotatef(_,_,_,_)") == 0) return C_rotatef;
if (isStatic && strcmp(signature, "materialfv(_,_,_)") == 0) return C_materialfv;
if (isStatic && strcmp(signature, "popMatrix()") == 0) return C_popMatrix;
if (isStatic && strcmp(signature, "flush()") == 0) return C_flush;
if (isStatic && strcmp(signature, "lightfv(_,_,_)") == 0) return C_lightfv;
if (isStatic && strcmp(signature, "enable(_)") == 0) return C_enable;
} 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, "displayFunc(_,_)") == 0) return C_displayFunc;
if (isStatic && strcmp(signature, "idleFunc(_,_)") == 0) return C_idleFunc;
if (isStatic && strcmp(signature, "postRedisplay()") == 0) return C_postRedisplay;
if (isStatic && strcmp(signature, "wireTeapot(_)") == 0) return C_wireTeapot;
if (isStatic && strcmp(signature, "setOption(_,_)") == 0) return C_setOption;
}
}
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;
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignMethodFn = &bindForeignMethod;
vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "OpenGL_Utah_teapot.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;
}
- Output:
Same as C example.