Draw a rotating cube: Difference between revisions

From Rosetta Code
Content added Content deleted
(J: bugfix (version dependency -- case sensitive name))
m (→‎Zig: Update "works with". Simplify two lines involving casting and math.)
 
(28 intermediate revisions by 13 users not shown)
Line 15: Line 15:
{{libheader|SDLAda}}
{{libheader|SDLAda}}
{{trans|Go}}
{{trans|Go}}
<lang Ada>with Ada.Numerics.Elementary_Functions;
<syntaxhighlight lang="ada">with Ada.Numerics.Elementary_Functions;


with SDL.Video.Windows.Makers;
with SDL.Video.Windows.Makers;
Line 119: Line 119:
Window.Finalize;
Window.Finalize;
SDL.Finalise;
SDL.Finalise;
end Rotating_Cube;</lang>
end Rotating_Cube;</syntaxhighlight>

=={{header|Amazing Hopper}}==
{{Trans|BASIC256}}
{{Trans|FreeBASIC}}
<p>El programa requiere de la ejecución con "rxvt" de Linux:

rxvt -g 500x250 -fn "xft:FantasqueSansMono-Regular:pixelsize=1" -e ./bin/cubo
</p>
[[File:Captura_de_pantalla_de_2022-10-11_12-38-33.png|200px|thumb|rigth|Caption]]
<syntaxhighlight lang="txt">
#context-free Draw a cube
Loop for (i=1, #(i<=3), ++i)
Draw a line (size_2, {size_2} Minus(scale_zoff), [i] Get 'x',\
{size_2} Minus(scale x zoff) )
Draw a line (size_2, {size_2} Plus(scale_zoff), [{7}Minus(i)] Get 'x' ,\
{size_2} Plus(scale x zoff) )
Draw a line ([i] Get 'x', {size_2} Minus(scale x zoff),\
[Minusone(i) Module(3) Plus(4)] Get 'x', {size_2} Plus(scale x zoff) )
Draw a line ([i] Get 'x', {size_2} Minus(scale x zoff), \
[{i} Module(3) Plus(4)] Get 'x', {size_2} Plus(scale x zoff) )
Next
Return\\

#context-free Delete old cube
Color back '0', Draw a cube
Return\\

#context-free Setting values of program
Set( Div(M_PI,6), Mul(5,Div(M_PI,6)), Mul(3,M_PI_2), Mul(11,Div(M_PI,6)),\
M_PI_2, Mul(7,Div(M_PI,6)) )
Append to list 'cylphi'
/* pre-cálculos */
Let ( dt := Div(1,30 ))
Let (size_2 := Div( SIZE, 2))
Let (scale_zoff := Div( SCALE,zoff))
Let (scale x zoff := Mul (SCALE, zoff))
Return \\

#include <jambo.h>

/*
Execute with:
$ rxvt -g 250x250 -fn "xft:FantasqueSansMono-Regular:pixelsize=1" -e hopper jm/cubo.jambo
*/

#define SCALE 50
#define SIZE 200
#define zoff 0.5773502691896257645091487805019574556
#define cylr 1.6329931618554520654648560498039275946

Main
Set break
theta=0, dtheta=1.5, lasttime=0, dt=0 , timer=0
size_2=0, scale_zoff=0, scale x zoff=0, cylphi = {}

Dim (6) as zeros (x)
Setting values of program
Cls
/* Draw a cube */
Loop while ( Not (Keypressed))
Tic(lasttime)
Loop for( i=1, #(i<=6), ++i )
Add( size_2, Mul( Mul(SCALE,cylr), Cos( [i] Get 'cylphi' Plus 'theta')) )
Put 'x'
Next
Color back '15', Draw a cube
Loop
Timecpu(timer)
While ( This 'timer' Compared to 'Add(lasttime, dt)' Is less )
Let ( theta := Add( theta, Mul( dtheta, Sub(timer, lasttime))))
Sleep (0.01)
Delete old cube
Back
End

Subrutines

</syntaxhighlight>


=={{header|AutoHotkey}}==
=={{header|AutoHotkey}}==
Requires [https://www.autohotkey.com/boards/viewtopic.php?f=6&t=6517&start=320 Gdip Library]
Requires [https://www.autohotkey.com/boards/viewtopic.php?f=6&t=6517&start=320 Gdip Library]
<lang AutoHotkey>; ---------------------------------------------------------------
<syntaxhighlight lang="autohotkey">; ---------------------------------------------------------------
cubeSize := 200
cubeSize := 200
deltaX := A_ScreenWidth/2
deltaX := A_ScreenWidth/2
Line 436: Line 519:
ExitApp
ExitApp
Return
Return
; ---------------------------------------------------------------</lang>
; ---------------------------------------------------------------</syntaxhighlight>


=={{header|BASIC}}==
==={{header|BASIC256}}===
<syntaxhighlight lang="basic256">global escala
global tam
global zoff
global cylr

escala = 50
tam = 320
zoff = 0.5773502691896257645091487805019574556
cylr = 1.6329931618554520654648560498039275946

clg
graphsize tam, tam

dim x(6)
theta = 0.0
dtheta = 1.5
dt = 1.0 / 30
dim cylphi = {PI/6, 5*PI/6, 3*PI/2, 11*PI/6, PI/2, 7*PI/6}

while key = ""
lasttime = msec
for i = 0 to 5
x[i] = tam/2 + escala *cylr * cos(cylphi[i] + theta)
next i
clg
call drawcube(x)

while msec < lasttime + dt
end while
theta += dtheta*(msec-lasttime)
pause .4
call drawcube(x)
end while

subroutine drawcube(x)
for i = 0 to 2
color rgb(0,0,0) #black
line tam/2, tam/2 - escala / zoff, x[i], tam/2 - escala * zoff
line tam/2, tam/2 + escala / zoff, x[5-i], tam/2 + escala * zoff
line x[i], tam/2 - escala * zoff, x[(i % 3) + 3], tam/2 + escala * zoff
line x[i], tam/2 - escala * zoff, x[((i+1)%3) + 3], tam/2 + escala * zoff
next i
end subroutine</syntaxhighlight>

==={{header|Chipmunk Basic}}===
{{works with|Chipmunk Basic|3.6.4}}
<syntaxhighlight lang="qbasic">100 cls
110 graphics 0
120 graphics color 0,0,0
130 while true
140 graphics cls
150 x = cos(t)*20
160 y = sin(t)*18
170 r = sin(t+t)
180 moveto (x+40),(y+40-r)
190 lineto (-y+40),(x+40-r)
200 moveto (-y+40),(x+40-r)
210 lineto (-x+40),(-y+40-r)
220 moveto (-x+40),(-y+40-r)
230 lineto (y+40),(-x+40-r)
240 moveto (y+40),(-x+40-r)
250 lineto (x+40),(y+40-r)
260 moveto (x+40),(y+20+r)
270 lineto (-y+40),(x+20+r)
280 moveto (-y+40),(x+20+r)
290 lineto (-x+40),(-y+20+r)
300 moveto (-x+40),(-y+20+r)
310 lineto (y+40),(-x+20+r)
320 moveto (y+40),(-x+20+r)
330 lineto (x+40),(y+20+r)
340 moveto (x+40),(y+40-r)
350 lineto (x+40),(y+20+r)
360 moveto (-y+40),(x+40-r)
370 lineto (-y+40),(x+20+r)
380 moveto (-x+40),(-y+40-r)
390 lineto (-x+40),(-y+20+r)
400 moveto (y+40),(-x+40-r)
410 lineto (y+40),(-x+20+r)
420 for i = 1 to 1000 : next i
430 t = t+0.15
440 wend</syntaxhighlight>

==={{header|GW-BASIC}}===
{{works with|PC-BASIC|any}}
<syntaxhighlight lang="qbasic">100 SCREEN 2
110 WHILE 1
120 CLS
130 X = COS(T)*20
140 Y = SIN(T)*18
150 R = SIN(T+T)
160 LINE (( X+40),( Y+40-R))-((-Y+40),( X+40-R))
170 LINE ((-Y+40),( X+40-R))-((-X+40),(-Y+40-R))
180 LINE ((-X+40),(-Y+40-R))-(( Y+40),(-X+40-R))
190 LINE (( Y+40),(-X+40-R))-(( X+40),( Y+40-R))
200 LINE (( X+40),( Y+20+R))-((-Y+40),( X+20+R))
210 LINE ((-Y+40),( X+20+R))-((-X+40),(-Y+20+R))
220 LINE ((-X+40),(-Y+20+R))-(( Y+40),(-X+20+R))
230 LINE (( Y+40),(-X+20+R))-(( X+40),( Y+20+R))
240 LINE (( X+40),( Y+40-R))-(( X+40),( Y+20+R))
250 LINE ((-Y+40),( X+40-R))-((-Y+40),( X+20+R))
260 LINE ((-X+40),(-Y+40-R))-((-X+40),(-Y+20+R))
270 LINE (( Y+40),(-X+40-R))-(( Y+40),(-X+20+R))
280 T = T+.15
290 WEND</syntaxhighlight>

==={{header|MSX Basic}}===
{{works with|MSX BASIC|any}}
<syntaxhighlight lang="qbasic">100 SCREEN 2
110 COLOR 15
120 CLS
130 X = COS(T)*20
140 Y = SIN(T)*18
150 R = SIN(T+T)
160 LINE (( X+40),( Y+40-R))-((-Y+40),( X+40-R))
170 LINE ((-Y+40),( X+40-R))-((-X+40),(-Y+40-R))
180 LINE ((-X+40),(-Y+40-R))-(( Y+40),(-X+40-R))
190 LINE (( Y+40),(-X+40-R))-(( X+40),( Y+40-R))
200 LINE (( X+40),( Y+20+R))-((-Y+40),( X+20+R))
210 LINE ((-Y+40),( X+20+R))-((-X+40),(-Y+20+R))
220 LINE ((-X+40),(-Y+20+R))-(( Y+40),(-X+20+R))
230 LINE (( Y+40),(-X+20+R))-(( X+40),( Y+20+R))
240 LINE (( X+40),( Y+40-R))-(( X+40),( Y+20+R))
250 LINE ((-Y+40),( X+40-R))-((-Y+40),( X+20+R))
260 LINE ((-X+40),(-Y+40-R))-((-X+40),(-Y+20+R))
270 LINE (( Y+40),(-X+40-R))-(( Y+40),(-X+20+R))
280 FOR I = 1 TO 40 : NEXT I
290 T = T+0.15
300 GOTO 120</syntaxhighlight>


=={{header|C}}==
=={{header|C}}==
Rotating wireframe cube in [https://www.opengl.org/ OpenGL], windowing implementation via [http://freeglut.sourceforge.net/ freeglut]
Rotating wireframe cube in [https://www.opengl.org/ OpenGL], windowing implementation via [http://freeglut.sourceforge.net/ freeglut]
<syntaxhighlight lang="c">
<lang C>
#include<gl/freeglut.h>
#include<gl/freeglut.h>


Line 504: Line 719:
return 0;
return 0;
}
}
</syntaxhighlight>
</lang>


=={{header|C sharp|C#}}==
=={{header|C sharp|C#}}==
{{trans|Java}}
{{trans|Java}}
<lang csharp>using System;
<syntaxhighlight lang="csharp">using System;
using System.Drawing;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Drawing2D;
Line 604: Line 819:
}
}
}
}
}</lang>
}</syntaxhighlight>
=={{header|Delphi}}==
=={{header|Delphi}}==
{{libheader| Winapi.Windows}}
{{libheader| Winapi.Windows}}
Line 614: Line 829:
{{libheader| System.Classes}}
{{libheader| System.Classes}}
{{Trans|Javascript}}
{{Trans|Javascript}}
<syntaxhighlight lang="delphi">
<lang Delphi>
unit main;
unit main;


Line 722: Line 937:
end;
end;


end.</lang>
end.</syntaxhighlight>
Resource Form
Resource Form
<syntaxhighlight lang="delphi">
<lang Delphi>
object Form1: TForm1
object Form1: TForm1
OnCreate = FormCreate
OnCreate = FormCreate
Line 732: Line 947:
end
end
end
end
</syntaxhighlight>
</lang>




Line 739: Line 954:
Draws only the visible edges
Draws only the visible edges


[https://easylang.dev/show/#cod=jZTbboMwDIbv8xSWdteqaITSg7Q9ScUFKmkVCcJG0Ub29LNN0gTGtqZVTe3Pvx0TMG2lTsWpgFc44WeTum9x/3O/jv3eHeMRHcGeLYSqrnGpFCQDErZst5CxzZxGDju2OziwPcCe7R4jo3Du8ncub+90DlzuCcRb157hdi5rBRdIIBEAcGk70NhCCn0LtTJg3AQo6OKVj2fOiYsxXZyqAlavcHEBlkxEMpbq2r7sFZTmOtCP9TVv2gwoiYZj5Dq3N3KhubswbANlHWUDZR/pn1R9r6l3fkXOzDsDhdEBVmNPG4RX3LHDbJQrY8Evn7Lm7Cgl4IjZEbNB2c6wrAhqFtVshNFseZcVHpxsHHPVlZ9+tOdalR1dNKhxPB75kuazSR+Zlr7EXbxAE254szQzr66n95+UaPDLNf3BDzXZ40ff6CCO29QDOT0ho8pYYu1q4FJ1JCT/FUp/FQp7oM7NdFzV5MH4a1vwc2eYbXQBmDjpc3SHNFxD6qcdBKY947KLkJwpyTkkF5QWoZlS034oamwN+TPVJjsBam0U1RsBOQOS6XgTMb6IZC7ca2KbQ9mXBm7vXQ9S0KkWLT37usEwZTkwBZZlIBHf Run it]
[https://easylang.online/apps/_rotating-cube.html Run it]


<syntaxhighlight lang="text">
<lang>node[][] &= [ -1 -1 -1 ]
node[][] &= [ -1 -1 1 ]
node[][] = [ [ -1 -1 -1 ] [ -1 -1 1 ] [ -1 1 -1 ] [ -1 1 1 ] [ 1 -1 -1 ] [ 1 -1 1 ] [ 1 1 -1 ] [ 1 1 1 ] ]
edge[][] = [ [ 1 2 ] [ 2 4 ] [ 4 3 ] [ 3 1 ] [ 5 6 ] [ 6 8 ] [ 8 7 ] [ 7 5 ] [ 1 5 ] [ 2 6 ] [ 3 7 ] [ 4 8 ] ]
node[][] &= [ -1 1 -1 ]
node[][] &= [ -1 1 1 ]
node[][] &= [ 1 -1 -1 ]
node[][] &= [ 1 -1 1 ]
node[][] &= [ 1 1 -1 ]
node[][] &= [ 1 1 1 ]
#
#
proc scale f . .
edge[][] &= [ 0 1 ]
for i = 1 to len node[][]
edge[][] &= [ 1 3 ]
for d = 1 to 3
edge[][] &= [ 3 2 ]
edge[][] &= [ 2 0 ]
node[i][d] *= f
edge[][] &= [ 4 5 ]
.
.
edge[][] &= [ 5 7 ]
edge[][] &= [ 7 6 ]
edge[][] &= [ 6 4 ]
edge[][] &= [ 0 4 ]
edge[][] &= [ 1 5 ]
edge[][] &= [ 2 6 ]
edge[][] &= [ 3 7 ]
#
func scale f . .
for i range len node[][]
swap n[] node[i][]
n[0] *= f
n[1] *= f
n[2] *= f
swap n[] node[i][]
.
.
.
func rotate angx angy . .
proc rotate angx angy . .
sinx = sin angx
sinx = sin angx
cosx = cos angx
cosx = cos angx
siny = sin angy
siny = sin angy
cosy = cos angy
cosy = cos angy
for i range len node[][]
for i = 1 to len node[][]
swap n[] node[i][]
x = node[i][1]
x = n[0]
z = node[i][3]
y = n[1]
node[i][1] = x * cosx - z * sinx
z = n[2]
y = node[i][2]
n[0] = x * cosx - z * sinx
z = z * cosx + x * sinx
n[2] = z * cosx + x * sinx
node[i][2] = y * cosy - z * siny
node[i][3] = z * cosy + y * siny
z = n[2]
.
n[1] = y * cosy - z * siny
n[2] = z * cosy + y * siny
swap n[] node[i][]
.
.
.
len nd[] 3
len nd[] 3
func draw . .
proc draw . .
clear
clear_screen
m = 999
m = 999
mi = -1
mi = -1
for i range len node[][]
for i = 1 to len node[][]
if node[i][2] < m
if node[i][3] < m
m = node[i][2]
m = node[i][3]
mi = i
mi = i
.
.
ix = 0
for i range len edge[][]
if edge[i][0] = mi
nd[ix] = edge[i][1]
ix += 1
elif edge[i][1] = mi
nd[ix] = edge[i][0]
ix += 1
.
.
for ni range len nd[]
for i range len edge[][]
if edge[i][0] = nd[ni] or edge[i][1] = nd[ni]
x1 = node[edge[i][0]][0]
y1 = node[edge[i][0]][1]
x2 = node[edge[i][1]][0]
y2 = node[edge[i][1]][1]
move_pen x1 + 50 y1 + 50
draw_line x2 + 50 y2 + 50
.
.
.
.
.
ix = 1
for i = 1 to len edge[][]
if edge[i][1] = mi
nd[ix] = edge[i][2]
ix += 1
elif edge[i][2] = mi
nd[ix] = edge[i][1]
ix += 1
.
.
for ni = 1 to len nd[]
for i = 1 to len edge[][]
if edge[i][1] = nd[ni] or edge[i][2] = nd[ni]
x1 = node[edge[i][1]][1]
y1 = node[edge[i][1]][2]
x2 = node[edge[i][2]][1]
y2 = node[edge[i][2]][2]
move x1 + 50 y1 + 50
line x2 + 50 y2 + 50
.
.
.
.
.
call scale 25
scale 25
call rotate 45 atan sqrt 2
rotate 45 atan sqrt 2
call draw
draw
on animate
on animate
call rotate 1 0
rotate 1 0
call draw
draw
.
.</lang>
</syntaxhighlight>

=={{header|Evaldraw}}==

Based on the solution in draw cuboid.
Draws a filled cube with a texture on each face.

[[File:Evaldraw cube rotate.gif|thumb|alt=Rotating 3D cube|Rotating cube with texture. Makes use of rudimentary glBegin(GL_QUADS) function]]

<syntaxhighlight lang="C">
// We can define our own vec3 struct
struct vec3{x,y,z;}
static modelMatrix[9];
() {
cls(0x828282); // clear screen
clz(1e32); // clear depth buffer
setcam(0,0,-3,0,0); // set camera some units back
// create two local arrays to hold rotation matrices
double roty[9], rotz[9];
static otim;
tim=klock(0); dt=tim-otim; otim=tim;
static degrees = 0;
degrees+=200*dt;
rads = degrees/180*pi;
rotateZ( rotz, rads );
rotateY( roty, rads );
// evaldraw does support some GL-like drawing
// modes, but any transformations must be done by hand
// Here we use a global model matrix that
// transforms vertices created by the myVertex function
mult(modelMatrix, roty, rotz);
glSetTex("cloud.png");
drawcuboid(0,0,0,1,1,1);
}

drawcuboid(x,y,z,sx,sy,sz) {
glBegin(GL_QUADS);
setcol(192,32,32);
glTexCoord(0,0); myVertex(x-sx,y-sy,z-sz);
glTexCoord(1,0); myVertex(x+sx,y-sy,z-sz);
glTexCoord(1,1); myVertex(x+sx,y+sy,z-sz);
glTexCoord(0,1); myVertex(x-sx,y+sy,z-sz);
setcol(32,192,32);
glTexCoord(0,0); myVertex(x-sx,y-sy,z+sz);
glTexCoord(1,0); myVertex(x-sx,y-sy,z-sz);
glTexCoord(1,1); myVertex(x-sx,y+sy,z-sz);
glTexCoord(0,1); myVertex(x-sx,y+sy,z+sz);
setcol(32,32,192);
glTexCoord(0,0); myVertex(x+sx,y-sy,z+sz);
glTexCoord(1,0); myVertex(x-sx,y-sy,z+sz);
glTexCoord(1,1); myVertex(x-sx,y+sy,z+sz);
glTexCoord(0,1); myVertex(x+sx,y+sy,z+sz);
setcol(192,192,32);
glTexCoord(0,0); myVertex(x+sx,y-sy,z-sz);
glTexCoord(1,0); myVertex(x+sx,y-sy,z+sz);
glTexCoord(1,1); myVertex(x+sx,y+sy,z+sz);
glTexCoord(0,1); myVertex(x+sx,y+sy,z-sz);

setcol(192,32,192);
glTexCoord(0,0); myVertex(x-sx,y-sy,z+sz);
glTexCoord(1,0); myVertex(x+sx,y-sy,z+sz);
glTexCoord(1,1); myVertex(x+sx,y-sy,z-sz);
glTexCoord(0,1); myVertex(x-sx,y-sy,z-sz);

setcol(32,192,192);
glTexCoord(0,0); myVertex(x-sx,y+sy,z-sz);
glTexCoord(1,0); myVertex(x+sx,y+sy,z-sz);
glTexCoord(1,1); myVertex(x+sx,y+sy,z+sz);
glTexCoord(0,1); myVertex(x-sx,y+sy,z+sz);
glEnd();
}
myVertex(x,y,z) {
// Initialize a struct value
vec3 v = {x,y,z};
// Apply global model matrix transformation
transformPoint(v, modelMatrix);
// Submit the vertex to draw list
glVertex(v.x, v.y, v.z);
}
rotateY(m[9], r) {
c = cos(r); s=sin(r);
m[0] = c; m[1] = 0; m[2] = s;
m[3] = 0; m[4] = 1; m[5] = 0;
m[6] = -s; m[7] = 0; m[8] = c;
}

rotateZ(m[9], r) {
c = cos(r); s=sin(r);
m[0] = c; m[1] = -s; m[2] = 0;
m[3] = s; m[4] = c; m[5] = 0;
m[6] = 0; m[7] = 0; m[8] = 1;
}
transformPoint(vec3 v, m[9]) {
x2 = v.x * m[0] + v.y * m[1] + v.z * m[2];
y2 = v.x * m[3] + v.y * m[4] + v.z * m[5];
z2 = v.x * m[6] + v.y * m[7] + v.z * m[8];
// Mutate the struct v with new values
v.x=x2; v.y=y2; v.z=z2;
}
mult(c[9],a[9],b[9]) { // C = AB
// multiply a row in A with a column in B
for(i=0; i<3; i++)
for(j=0; j<3; j++) {
sum = 0.0;
for(k=0; k<3; k++) {
sum += A[k*3+i] * B[k*3+j];
}
C[i*3+j] = sum;
}
}
</syntaxhighlight>


=={{header|FreeBASIC}}==
=={{header|FreeBASIC}}==
<lang freebasic>#define PI 3.14159265358979323
<syntaxhighlight lang="freebasic">#define PI 3.14159265358979323
#define SCALE 50
#define SCALE 50
#define SIZE 320
#define SIZE 320
Line 865: Line 1,176:
drawcube x(),0
drawcube x(),0
wend
wend
end</lang>
end</syntaxhighlight>


=={{header|FutureBasic}}==
=={{header|FutureBasic}}==
<syntaxhighlight lang="futurebasic">
[[File:rotating_cube.jpg|200px|thumb|right]]
include "Tlbx SceneKit.incl"
Among the capabilities of FutureBasic (or FB as it's called by its developers) is the ability to compile Open GL code as demonstrated here.


_window = 1
<lang futurebasic>
begin enum output 1
include "Tlbx agl.incl"
_sceneView
include "Tlbx glut.incl"
end enum


local fn RotatingCubeScene as SCNSceneRef
output file "Rotating Cube"
SCNSceneRef scene = fn SCNSceneInit
SCNNodeRef rootNode = fn SCNSceneRootNode( scene )
SCNCameraRef camera = fn SCNCameraInit
SCNNodeRef cameraNode = fn SCNNodeInit
SCNNodeSetCamera( cameraNode, camera )
SCNNodeAddChildNode( rootNode, cameraNode )
SCNVector3 cameraPos = {0.0, 0.0, 10.0}
SCNNodeSetPosition( cameraNode, cameraPos )
SCNNodeRef lightNode = fn SCNNodeInit
SCNLightRef light = fn SCNLightInit
SCNLightSetType( light, SCNLightTypeOmni )
SCNNodeSetPosition( lightNode, fn SCNVector3Make( 0.0, 10.0, 10.0 ) )
SCNNodeAddChildNode( rootNode, lightNode )
SCNNodeRef ambientLightNode = fn SCNNodeInit
SCNLightRef ambientLight = fn SCNLightInit
SCNLightSetType( ambientLight, SCNLightTypeAmbient )
SCNLightSetColor( ambientLight, fn ColorGray )
SCNNodeSetLight( ambientLightNode, ambientLight )
SCNNodeAddChildNode( rootNode, ambientLightNode )
SCNBoxRef boxGeometry = fn SCNBoxInit( 4.0, 4.0, 4.0, 0.0 )
SCNNodeRef boxNode = fn SCNNodeWithGeometry( boxGeometry )
SCNMaterialRef side1 = fn SCNMaterialInit
SCNMaterialRef side2 = fn SCNMaterialInit
SCNMaterialRef side3 = fn SCNMaterialInit
SCNMaterialRef side4 = fn SCNMaterialInit
SCNMaterialRef side5 = fn SCNMaterialInit
SCNMaterialRef side6 = fn SCNMaterialInit
SCNMaterialPropertySetContents( fn SCNMaterialMultiply( side1 ), fn ColorBlue )
SCNMaterialPropertySetContents( fn SCNMaterialMultiply( side2 ), fn ColorOrange )
SCNMaterialPropertySetContents( fn SCNMaterialMultiply( side3 ), fn ColorRed )
SCNMaterialPropertySetContents( fn SCNMaterialMultiply( side4 ), fn ColorGreen )
SCNMaterialPropertySetContents( fn SCNMaterialMultiply( side5 ), fn ColorYellow )
SCNMaterialPropertySetContents( fn SCNMaterialMultiply( side6 ), fn ColorCyan )
SCNGeometrySetMaterials( boxGeometry, @[side1,side2,side3,side4,side5,side6] )
SCNNodeAddChildNode( rootNode, boxNode )
SCNActionableRunAction( boxNode, fn SCNActionRepeatActionForever( fn SCNActionRotateByAngle( M_PI, fn SCNVector3Make( 0.0, 25.0, 5.0 ), 5.0 ) ) )
end fn = scene


local fn AnimateCube
void local fn BuildWindow
window _window, @"Rosetta Code Rotating Cube", ( 0, 0, 600, 600 )
'~'1
scnview _sceneView, fn RotatingCubeScene, ( 0, 0, 600, 600 )
begin globals
SCNViewSetBackgroundColor( _sceneView, fn ColorBlack )
dim as double  sRotation
SCNViewSetAllowsCameraControl( _sceneView, YES )
end globals
end fn


void local fn DoDialog( ev as long, tag as long, wnd as long )
// Speed of rotation
select (ev)
sRotation += 2.9
case _windowWillClose : end
glMatrixMode( _GLMODELVIEW )
end select

glLoadIdentity()
glTranslated( 0.0, 0.0, 0.0 )
glRotated( sRotation, -0.45, -0.8, -0.6 )
glColor3d( 1.0, 0.0, 0.3 )
glLineWidth( 1.5 )
glutWireCube( 1.0 )
end fn
end fn


on dialog fn DoDialog
// Main program
dim as GLint           attrib(2)
dim as CGrafPtr        port
dim as AGLPixelFormat  fmt
dim as AGLContext      glContext
dim as EventRecord     ev
dim as GLboolean       yesOK


fn BuildWindow
window 1, @"Rotating Cube", (0,0) - (500,500)


attrib(0) = _AGLRGBA
attrib(1) = _AGLDOUBLEBUFFER
attrib(2) = _AGLNONE

fmt = fn aglChoosePixelFormat( 0, 0, attrib(0) )
glContext = fn aglCreateContext( fmt, 0 )
aglDestroyPixelFormat( fmt )

port = window( _wndPort )
yesOK = fn aglSetDrawable( glContext, port )
yesOK = fn aglSetCurrentContext( glContext )

glClearColor( 0.0, 0.0, 0.0, 0.0 )

poke long event - 8, 1
do
glClear( _GLCOLORBUFFERBIT )
fn AnimateCube
aglSwapBuffers( glContext )
HandleEvents
HandleEvents
</syntaxhighlight>
until gFBQuit
{{output}}
</lang>
[[File:FutureBasic Rotating Cube.png]]


=={{header|Go}}==
=={{header|Go}}==
As of Go 1.9, it looks as if the only standard library supporting animated graphics is image/gif - so we create an animated GIF...
As of Go 1.9, it looks as if the only standard library supporting animated graphics is image/gif - so we create an animated GIF...
<lang Go>package main
<syntaxhighlight lang="go">package main


import (
import (
Line 1,034: Line 1,362:
}
}
return x
return x
}</lang>
}</syntaxhighlight>


=={{header|Haskell}}==
=={{header|Haskell}}==
This implementation compiles to JavaScript that runs in a browser using the [https://github.com/ghcjs/ghcjs ghcjs compiler ] . The [https://github.com/reflex-frp/reflex-dom reflex-dom ] library is used to help with svg rendering and animation.
This implementation compiles to JavaScript that runs in a browser using the [https://github.com/ghcjs/ghcjs ghcjs compiler ] . The [https://github.com/reflex-frp/reflex-dom reflex-dom ] library is used to help with svg rendering and animation.


<lang Haskell>{-# LANGUAGE RecursiveDo #-}
<syntaxhighlight lang="haskell">{-# LANGUAGE RecursiveDo #-}
import Reflex.Dom
import Reflex.Dom
import Data.Map as DM (Map, lookup, insert, empty, fromList)
import Data.Map as DM (Map, lookup, insert, empty, fromList)
Line 1,218: Line 1,546:
elDynAttrSVG a2 a3 a4 = do
elDynAttrSVG a2 a3 a4 = do
elDynAttrNS' (Just "http://www.w3.org/2000/svg") a2 a3 a4
elDynAttrNS' (Just "http://www.w3.org/2000/svg") a2 a3 a4
return ()</lang>
return ()</syntaxhighlight>


Link to live demo: https://dc25.github.io/drawRotatingCubeHaskell/
Link to live demo: https://dc25.github.io/drawRotatingCubeHaskell/
Line 1,226: Line 1,554:
Derived from J's [https://github.com/jsoftware/demos_qtdemo/blob/master/shader.ijs qt shader demo]:
Derived from J's [https://github.com/jsoftware/demos_qtdemo/blob/master/shader.ijs qt shader demo]:


<lang J>require'gl2 gles ide/qt/opengl'
<syntaxhighlight lang="j">require'gl2 gles ide/qt/opengl'
coinsert'jgl2 jgles qtopengl'
coinsert'jgl2 jgles qtopengl'


Line 1,363: Line 1,691:
colorData=: unitCube NB. corresponding colors
colorData=: unitCube NB. corresponding colors


rotcube''</lang>
rotcube''</syntaxhighlight>


A variation which did not use opengl would probably be much more concise.
A variation which did not use opengl would probably be much more concise.
Line 1,369: Line 1,697:
=={{header|Java}}==
=={{header|Java}}==
[[File:rotating_cube_java.png|200px|thumb|right]]
[[File:rotating_cube_java.png|200px|thumb|right]]
<lang java>import java.awt.*;
<syntaxhighlight lang="java">import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionEvent;
import static java.lang.Math.*;
import static java.lang.Math.*;
Line 1,460: Line 1,788:
});
});
}
}
}</lang>
}</syntaxhighlight>


=={{header|JavaScript}}==
=={{header|JavaScript}}==
{{trans|Java}}
{{trans|Java}}
<lang javascript><!DOCTYPE html>
<syntaxhighlight lang="javascript"><!DOCTYPE html>
<html lang="en">
<html lang="en">
<head>
<head>
Line 1,552: Line 1,880:


</body>
</body>
</html></lang>
</html></syntaxhighlight>


=={{header|Julia}}==
=={{header|Julia}}==
Run at the Julia REPL command line.
Run at the Julia REPL command line.
<lang Julia>using Makie, LinearAlgebra
<syntaxhighlight lang="julia">using Makie, LinearAlgebra


N = 40
N = 40
Line 1,568: Line 1,896:
Makie.rotate!(rect, Quaternionf0(arr[1], arr[2], arr[3], arr[4]))
Makie.rotate!(rect, Quaternionf0(arr[1], arr[2], arr[3], arr[4]))
sleep(interval)
sleep(interval)
end</lang>
end</syntaxhighlight>


=={{header|Kotlin}}==
=={{header|Kotlin}}==
{{trans|Java}}
{{trans|Java}}
<lang scala>// version 1.1
<syntaxhighlight lang="scala">// version 1.1


import java.awt.*
import java.awt.*
Line 1,672: Line 2,000:
f.isVisible = true
f.isVisible = true
}
}
}</lang>
}</syntaxhighlight>
=={{header|Lua}}==
=={{header|Lua}}==
<lang lua>local abs,atan,cos,floor,pi,sin,sqrt = math.abs,math.atan,math.cos,math.floor,math.pi,math.sin,math.sqrt
<syntaxhighlight lang="lua">local abs,atan,cos,floor,pi,sin,sqrt = math.abs,math.atan,math.cos,math.floor,math.pi,math.sin,math.sqrt
local bitmap = {
local bitmap = {
init = function(self, w, h, value)
init = function(self, w, h, value)
Line 1,766: Line 2,094:
screen:clear()
screen:clear()
bitmap:render()
bitmap:render()
end</lang>
end</syntaxhighlight>
{{out}}
{{out}}
<pre style="font-size:50%">Frame 1:
<pre style="font-size:50%">Frame 1:
Line 1,850: Line 2,178:
················································································
················································································
················································································</pre>
················································································</pre>

=={{header|M2000 Interpreter}}==
[[File:Cube.png|thumb|Cube Example]]
Draw on M2000 console. Using of GDI+ for smooth lines. Using Every {} structure and Refresh 100 to immediate refresh double buffer, and set 100ms for the next auto refresh. So we erase the screen without refresh and draw again after dt time. Cube has 6 more lines for fancy drawing. Also time displayed. We can move the cube (and accelarate the rotation as we press a mouse button).

















<syntaxhighlight lang="m2000 interpreter">
Module Cube3D {
form 80, 32
smooth on // enable GDI+ smooth lines
zoff=0.5773502691896257645091487805019574556@
cylr=1.6329931618554520654648560498039275946@
oX=scale.x div 2 : oY=scale.y div 2
SCALE=min.data(oX, oY)/2*.6
gradient 0
theta = 0.0 : dtheta = 1.5 : dt = 1000/60
ScZof=SCALE/zoff
ScZofM=SCALE*zoff
dim cylphi(), x()
c =(PI/6, 5*PI/6, 3*PI/2, 11*PI/6, PI/2, 7*PI/6) : c*=180/Pi : cylphi()=c // cos() take Degree
every DT {
if mouse then (oX, oY)=(mouse.x,mouse.y) : dtheta*=1.05 else dtheta = 1.5
dim x(6)=oX : for i=0 to 5: x(i) += SCALE*cylr*cos(cylphi(i)+theta):next
drawcube() : refresh 100 : IF keypress(32) then exit
theta += dtheta : gradient 0, 5: cursor 0,0
Print "Press space to exit",,"Press any mouse button to move cube",,Time$(Now)
}
sub drawcube()
for i= 0 to 2
move x(i), oY-ScZofM:draw to oX,oY-ScZof, 11
move oX,ScZof+oY:draw to x(i),oY-ScZofM, 9
move oX,oY+ ScZof:draw to x(5-i),ScZofM+oY
move x(i),oY-ScZofM:draw to x(i mod 3 + 3),oY+ScZofM, 15
move oX,oY-ScZof:draw to x(i mod 3 + 3), oY+ScZofM, 7
move x(i),oY-ScZofM:draw to x((i+1) mod 3 + 3),oY+ScZofM, 13
next
end sub
}
Cube3D
</syntaxhighlight>


=={{header|Maple}}==
=={{header|Maple}}==
<lang maple>plots:-display(
<syntaxhighlight lang="maple">plots:-display(
seq(
seq(
plots:-display(
plots:-display(
Line 1,858: Line 2,241:
axes=none, scaling=constrained, orientation=[0,45,i] ),
axes=none, scaling=constrained, orientation=[0,45,i] ),
i = 0..360, 20 ),
i = 0..360, 20 ),
insequence=true );</lang>
insequence=true );</syntaxhighlight>


=={{header|Mathematica}}/{{header|Wolfram Language}}==
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<lang Mathematica>Dynamic[
<syntaxhighlight lang="mathematica">Dynamic[
Graphics3D[
Graphics3D[
GeometricTransformation[
GeometricTransformation[
Line 1,867: Line 2,250:
RotationTransform[Clock[2 Pi], {0, 0, 1}]
RotationTransform[Clock[2 Pi], {0, 0, 1}]
],
],
Boxed -> False]]</lang>
Boxed -> False]]</syntaxhighlight>

=={{header|MiniScript}}==
{{works with|Mini Micro}}

<syntaxhighlight lang="MiniScript">import "mathUtil"
scale = 250
radius = sqrt(scale^2)

Face = new Sprite
Face.image = file.loadImage("/sys/pics/shapes/SquareThin.png")

clear; gfx.clear color.gray
sprites = display(4).sprites

// build a sprite for each side
for i in range(0, 3)
sp = new Face
sp.x = 480; sp.y = 320
yBot = -sin(pi/4)
yTop = sin(pi/4)
cosAngL = cos(i*pi/2); sinAngL = sin(i*pi/2)
cosAngR = cos((i+1)*pi/2); sinAngR = sin((i+1)*pi/2)
sp.corners3d = [
[cosAngL, yBot, sinAngL], [cosAngR, yBot, sinAngR],
[cosAngR, yTop, sinAngR], [cosAngL, yTop, sinAngL] ]
sp.color = [color.yellow, color.aqua, color.pink, color.lime][i]
sprites.push sp
end for
// ...and one for the top
top = new Face
top.x = 480; top.y = 320
top.corners3d = []
for i in range(0, 3)
top.corners3d.push [cos(i*pi/2), sin(pi/4), sin(i*pi/2)]
end for
sprites.push top

// Rotate the given [x,y,z] point by some number of degrees
// around the Y axis, then project to the screen.
rotateAndProject = function(point3d, rotDegrees)
radians = rotDegrees * pi/180
cosAng = cos(radians); sinAng = sin(radians)
// First, rotate around the Y axis in 3D space
x = point3d[0] * cosAng - point3d[2] * sinAng
y = point3d[1]
z = point3d[0] * sinAng + point3d[2] * cosAng
// Then, project this to the screen
result = [480 + x * scale, 320 + y * scale + z*0]
p = (8 - z) / 8 // (perspective factor)
return mathUtil.lerp2d(result, [480,800], 1-p)
end function

// Position all the sprites where they should be on screen for the given rotation.
positionSprites = function(rotDegrees)
for sp in sprites
corners = []
for i in range(0,3)
corners.push rotateAndProject(sp.corners3d[i], rotDegrees)
end for
sp.setCorners corners
if sp == top then continue
if corners[1][0] > corners[0][0] then
sp.tint = sp.color
else
sp.tint = color.clear
end if
end for
end function

// Main program
rot = 0
while not key.pressed("escape") and not key.pressed("q")
yield
positionSprites rot
rot = rot + 1
end while
key.clear</syntaxhighlight>

{{output}}
[[File:MiniScript-spnning-cube.gif|alt=MiniScript spinning cube solution|MiniScript spinning cube solution]]


=={{header|Nim}}==
=={{header|Nim}}==
{{trans|Ada}}
{{trans|Ada}}
{{libheader|SDL2}}
{{libheader|SDL2}}
<lang Nim>import math
<syntaxhighlight lang="nim">import math
import sdl2
import sdl2


Line 1,952: Line 2,415:
while not endSimulation:
while not endSimulation:
endSimulation = drawCube()
endSimulation = drawCube()
window.destroy()</lang>
window.destroy()</syntaxhighlight>


=={{header|Objeck}}==
=={{header|Objeck}}==
{{libheader|SDL2}}
{{libheader|SDL2}}
{{trans|Ada}}
{{trans|Ada}}
<lang objeck>#~
<syntaxhighlight lang="objeck">#~
Rotating Cube
Rotating Cube
~#
~#
Line 2,078: Line 2,541:
SCREEN_HEIGHT := 600,
SCREEN_HEIGHT := 600,
DRAW_OFFSET := 300
DRAW_OFFSET := 300
}</lang>
}</syntaxhighlight>

=={{header|OxygenBasic}}==
Using An OpenGl-based console
<syntaxhighlight lang="text">
% Title "Rotating Cube"
% Animated
% PlaceCentral
uses ConsoleG

sub main
========
cls 0.0, 0.5, 0.7
shading
scale 7
pushstate
GoldMaterial.act
static float ang
rotateX ang
rotateY ang
go cube
popstate
ang+=.5 : if ang>=360 then ang-=360
end sub

EndScript
</syntaxhighlight>


=={{header|Perl}}==
=={{header|Perl}}==
<lang perl>#!/usr/bin/perl
<syntaxhighlight lang="perl">#!/usr/bin/perl


use strict; # http://www.rosettacode.org/wiki/Draw_a_rotating_cube
use strict; # http://www.rosettacode.org/wiki/Draw_a_rotating_cube
Line 2,111: Line 2,600:
$c->createLine( $mid, $height, @points[10, 11], -width => 5,);
$c->createLine( $mid, $height, @points[10, 11], -width => 5,);
$mw->after($wait, \&draw);
$mw->after($wait, \&draw);
}</lang>
}</syntaxhighlight>


=={{header|Phix}}==
=={{header|Phix}}==
Line 2,117: Line 2,606:
{{libheader|Phix/online}}
{{libheader|Phix/online}}
You can run this online [http://phix.x10.mx/p2js/drawrotatingcube.htm here].
You can run this online [http://phix.x10.mx/p2js/drawrotatingcube.htm here].
<!--<lang Phix>(phixonline)-->
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">--
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\DrawRotatingCube.exw
-- demo\rosetta\DrawRotatingCube.exw
Line 2,321: Line 2,810:
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<!--</lang>-->
<!--</syntaxhighlight>-->


=={{header|PostScript}}==
=={{header|PostScript}}==
'''Don't send this to your printer!'''
'''Don't send this to your printer!'''
<lang postscript>%!PS-Adobe-3.0
<syntaxhighlight lang="postscript">%!PS-Adobe-3.0
%%BoundingBox: 0 0 400 400
%%BoundingBox: 0 0 400 400


Line 2,361: Line 2,850:


0 {3.2 add dup page } loop
0 {3.2 add dup page } loop
%%EOF</lang>
%%EOF</syntaxhighlight>


=={{header|Processing}}==
=={{header|Processing}}==
Create a cube in Processing with box(), rotate the scene with rotate(), and drive the rotation with either the built-in millis() or frameCount timers.
Create a cube in Processing with box(), rotate the scene with rotate(), and drive the rotation with either the built-in millis() or frameCount timers.


<lang Processing>void setup() {
<syntaxhighlight lang="processing">void setup() {
size(500, 500, P3D);
size(500, 500, P3D);
}
}
Line 2,382: Line 2,871:
// draw box
// draw box
box(300, 300, 300);
box(300, 300, 300);
}</lang>
}</syntaxhighlight>


=={{header|Python}}==
=={{header|Python}}==
Line 2,391: Line 2,880:


====Short version====
====Short version====
<lang python>from visual import *
<syntaxhighlight lang="python">from visual import *
scene.title = "VPython: Draw a rotating cube"
scene.title = "VPython: Draw a rotating cube"


Line 2,409: Line 2,898:
rate(50)
rate(50)
cube.rotate( angle=0.005, axis=(0,1,0) )
cube.rotate( angle=0.005, axis=(0,1,0) )
</syntaxhighlight>
</lang>


<!--
<!--
Line 2,416: Line 2,905:


=={{header|Racket}}==
=={{header|Racket}}==
<lang racket>#lang racket/gui
<syntaxhighlight lang="racket">#lang racket/gui
(require math/matrix math/array)
(require math/matrix math/array)


Line 2,485: Line 2,974:
(send c refresh))
(send c refresh))


(define t (new timer% [notify-callback refresh] [interval 35] [just-once? #f]))</lang>
(define t (new timer% [notify-callback refresh] [interval 35] [just-once? #f]))</syntaxhighlight>


=={{header|Raku}}==
=={{header|Raku}}==
Line 2,492: Line 2,981:
Raku has no native graphics libraries built in, but makes it fairly easy to bind to third party libraries. Here we'll use bindings to [[wp:Libcaca|Libcaca]], the '''C'''olor '''A'''S'''C'''II '''A'''rt library to generate a rotating cube in an ASCII terminal.
Raku has no native graphics libraries built in, but makes it fairly easy to bind to third party libraries. Here we'll use bindings to [[wp:Libcaca|Libcaca]], the '''C'''olor '''A'''S'''C'''II '''A'''rt library to generate a rotating cube in an ASCII terminal.


<lang perl6>use Terminal::Caca;
<syntaxhighlight lang="raku" line>use Terminal::Caca;
given my $canvas = Terminal::Caca.new {
given my $canvas = Terminal::Caca.new {
.title('Rosetta Code - Rotating cube - Press any key to exit');
.title('Rosetta Code - Rotating cube - Press any key to exit');
Line 2,584: Line 3,073:
.cleanup;
.cleanup;
}
}
}</lang>
}</syntaxhighlight>


=={{header|Ring}}==
=={{header|Ring}}==
<lang ring>
<syntaxhighlight lang="ring">
#===================================================================#
#===================================================================#
# Based on Original Sample from RayLib (https://www.raylib.com/)
# Based on Original Sample from RayLib (https://www.raylib.com/)
Line 2,665: Line 3,154:


CloseWindow()
CloseWindow()
</syntaxhighlight>
</lang>
[https://www.mediafire.com/view/xjimb82x8lvfwd9/RotatingCube.jpg/file Rotating a Cube]
[https://www.mediafire.com/view/xjimb82x8lvfwd9/RotatingCube.jpg/file Rotating a Cube]


Line 2,673: Line 3,162:
{{libheader|Scala GUI Animation}}
{{libheader|Scala GUI Animation}}
{{works with|Scala|2.13}}
{{works with|Scala|2.13}}
<lang Scala>import java.awt.event.ActionEvent
<syntaxhighlight lang="scala">import java.awt.event.ActionEvent
import java.awt._
import java.awt._


Line 2,760: Line 3,249:
}
}


}</lang>
}</syntaxhighlight>


=={{header|Tcl}}==
=={{header|Tcl}}==
Line 2,771: Line 3,260:
See [http://wiki.tcl.tk/14283 this wiki page] (and others linked from it) for many similar examples.
See [http://wiki.tcl.tk/14283 this wiki page] (and others linked from it) for many similar examples.


<lang Tcl># matrix operation support:
<syntaxhighlight lang="tcl"># matrix operation support:
package require math::linearalgebra
package require math::linearalgebra
namespace import ::math::linearalgebra::matmul
namespace import ::math::linearalgebra::matmul
Line 2,903: Line 3,392:
}
}
set ::world [make_cube 100]
set ::world [make_cube 100]
tick</lang>
tick</syntaxhighlight>


=={{header|TI-83 BASIC}}==
=={{header|TI-83 BASIC}}==
<lang ti83b>:-1→Xmin:1→Xmax
<syntaxhighlight lang="ti83b">:-1→Xmin:1→Xmax
:-1→Ymin:1→Ymax
:-1→Ymin:1→Ymax
:AxesOff
:AxesOff
Line 2,928: Line 3,417:
:Line(.3,FV,-.3,-PV
:Line(.3,FV,-.3,-PV
:End
:End
:End</lang>
:End</syntaxhighlight>


I%, PV, and FV are all finance variables that can be found in the finance menu (inside the APPS menu on TI-83+ and up).
I%, PV, and FV are all finance variables that can be found in the finance menu (inside the APPS menu on TI-83+ and up).
Line 2,936: Line 3,425:
{{trans|Kotlin}}
{{trans|Kotlin}}
{{libheader|DOME}}
{{libheader|DOME}}
<lang ecmascript>import "graphics" for Canvas, Color
<syntaxhighlight lang="wren">import "graphics" for Canvas, Color
import "dome" for Window
import "dome" for Window
import "math" for Math
import "math" for Math
Line 3,030: Line 3,519:
}
}


var Game = RotatingCube.new(640, 640)</lang>
var Game = RotatingCube.new(640, 640)</syntaxhighlight>


=={{header|XPL0}}==
=={{header|XPL0}}==
The main challenge was figuring out the initial coordinates of the cube.
The main challenge was figuring out the initial coordinates of the cube.
Zometool came to the rescue. The program runs much smoother than the animated gif.
Zometool came to the rescue. The program runs much smoother than the animated gif.
<lang XPL0>def Size=100., Speed=0.05; \drawing size and rotation speed
<syntaxhighlight lang="xpl0">def Size=100., Speed=0.05; \drawing size and rotation speed
real X, Y, Z, Farthest; \arrays: 3D coordinates of vertices
real X, Y, Z, Farthest; \arrays: 3D coordinates of vertices
int I, J, K, ZI, Edge;
int I, J, K, ZI, Edge;
Line 3,063: Line 3,552:
until KeyHit; \run until a key is struck
until KeyHit; \run until a key is struck
SetVid(3); \restore normal text mode
SetVid(3); \restore normal text mode
]</lang>
]</syntaxhighlight>


{{out}}
{{out}}
http://www.xpl0.org/rotcube2.gif
http://www.xpl0.org/rotcube2.gif

=={{header|Yabasic}}==
<syntaxhighlight lang="yabasic">// Rosetta Code problem: http://rosettacode.org/wiki/Draw_a_rotating_cube
// adapted to Yabasic by Galileo, 05/2022

// GFA Punch (code from tigen.ti-fr.com/)
// Carré 3D en rotation

open window 50, 70
backcolor 0,0,0
clear window
color 255,255,255

do
clear window
x = COS(T) * 20
y = SIN(T) * 18
r = SIN(T + T)
line (x + 40), (y + 40 - r), (-y + 40), (x + 40 - r)
line (-y + 40), (x + 40 - r), (-x + 40), (-y + 40 - r)
line (-x + 40), (-y + 40 - r), (y + 40), (-x + 40 - r)
line (y + 40), (-x + 40 - r), (x + 40), (y + 40 - r)
line (x + 40), (y + 20 + r), (-y + 40), (x + 20 + r)
line (-y + 40), (x + 20 + r), (-x + 40), (-y + 20 + r)
line (-x + 40), (-y + 20 + r), (y + 40), (-x + 20 + r)
line (y + 40), (-x + 20 + r), (x + 40), (y + 20 + r)
line (x + 40), (y + 40 - r), (x + 40), (y + 20 + r)
line (-y + 40), (x + 40 - r), (-y + 40), (x + 20 + r)
line (-x + 40), (-y + 40 - r), (-x + 40), (-y + 20 + r)
line (y + 40), (-x + 40 - r), (y + 40), (-x + 20 + r)

pause 0.02
T = T + 0.15
loop</syntaxhighlight>

=={{header|Zig}}==
{{libheader|Raylib}}
{{works with|Zig|0.11.0}} {{works with|Raylib|4.6}}
<syntaxhighlight lang="zig">const std = @import("std");
const c = @cImport({
@cInclude("raylib.h");
@cInclude("rlgl.h");
});

const dark_mode = true;
const show_grid = false;

pub fn main() !void {
const screen_width = 640;
const screen_height = 360;

const cube_side = 1;
const size = c.Vector3{ .x = cube_side, .y = cube_side, .z = cube_side };
const position = c.Vector3{ .x = 0, .y = 0, .z = 0 };
const x_rot = 45;
const y_center: f32 = std.math.sqrt(3.0) * cube_side / 2.0;
const z_rot = std.math.radiansToDegrees(f32, std.math.atan(@as(f32, std.math.sqrt1_2)));

c.SetConfigFlags(c.FLAG_WINDOW_RESIZABLE | c.FLAG_VSYNC_HINT);
c.InitWindow(screen_width, screen_height, "Draw a Rotating Cube");
defer c.CloseWindow();

var camera = c.Camera{
.position = .{ .x = 3, .y = 3, .z = 3 },
.target = .{ .x = 0, .y = y_center, .z = 0 }, // Center of cube
.up = .{ .x = 0, .y = 1, .z = 0 },
.fovy = 45, // Camera field-of-view Y
.projection = c.CAMERA_PERSPECTIVE,
};

c.SetTargetFPS(60);

while (!c.WindowShouldClose()) // Detect window close button or ESC key
{
c.UpdateCamera(&camera, c.CAMERA_ORBITAL);

c.BeginDrawing();
defer c.EndDrawing();

c.ClearBackground(if (dark_mode) c.BLACK else c.RAYWHITE);
{
c.BeginMode3D(camera);
defer c.EndMode3D();
{
c.rlPushMatrix();
defer c.rlPopMatrix();
c.rlTranslatef(0, y_center, 0);
c.rlRotatef(z_rot, 0, 0, 1);
c.rlRotatef(x_rot, 1, 0, 0);
c.DrawCubeWiresV(position, size, if (dark_mode) c.LIME else c.BLACK);
}
if (show_grid) c.DrawGrid(12, 0.75);
}
}
}</syntaxhighlight>


[[Category:Geometry]]
[[Category:Geometry]]

Latest revision as of 14:01, 3 January 2024

Task
Draw a rotating cube
You are encouraged to solve this task according to the task description, using any language you may know.
Task

Draw a rotating cube.

It should be oriented with one vertex pointing straight up, and its opposite vertex on the main diagonal (the one farthest away) straight down. It can be solid or wire-frame, and you can use ASCII art if your language doesn't have graphical capabilities. Perspective is optional.

Related tasks



Ada

Library: SDLAda
Translation of: Go
with Ada.Numerics.Elementary_Functions;

with SDL.Video.Windows.Makers;
with SDL.Video.Renderers.Makers;
with SDL.Events.Events;

procedure Rotating_Cube is

   Width  : constant := 500;
   Height : constant := 500;
   Offset : constant := 500.0 / 2.0;

   Window   : SDL.Video.Windows.Window;
   Renderer : SDL.Video.Renderers.Renderer;
   Event    : SDL.Events.Events.Events;
   Quit     : Boolean := False;

   type Node_Id   is new Natural;
   type Point_3D  is record X, Y, Z : Float;   end record;
   type Edge_Type is record A, B    : Node_Id; end record;

   Nodes : array (Node_Id range <>) of Point_3D :=
     ((-100.0, -100.0, -100.0), (-100.0, -100.0, 100.0), (-100.0, 100.0, -100.0),
      (-100.0, 100.0, 100.0),   (100.0, -100.0, -100.0), (100.0, -100.0, 100.0),
      (100.0, 100.0, -100.0),   (100.0, 100.0, 100.0));
   Edges : constant array (Positive range <>) of Edge_Type :=
     ((0, 1), (1, 3), (3, 2), (2, 0), (4, 5), (5, 7),
      (7, 6), (6, 4), (0, 4), (1, 5), (2, 6), (3, 7));

   use Ada.Numerics.Elementary_Functions;

   procedure Rotate_Cube (AngleX, AngleY : in Float) is
      SinX : constant Float := Sin (AngleX);
      CosX : constant Float := Cos (AngleX);
      SinY : constant Float := Sin (AngleY);
      CosY : constant Float := Cos (AngleY);
      X, Y, Z : Float;
   begin
      for Node of Nodes loop
         X := Node.X;
         Y := Node.Y;
         Z := Node.Z;
         Node.X := X * CosX - Z * SinX;
         Node.Z := Z * CosX + X * SinX;
         Z := Node.Z;
         Node.Y := Y * CosY - Z * SinY;
         Node.Z := Z * CosY + Y * SinY;
      end loop;
   end Rotate_Cube;

   function Poll_Quit return Boolean is
      use type SDL.Events.Event_Types;
   begin
      while SDL.Events.Events.Poll (Event) loop
         if Event.Common.Event_Type = SDL.Events.Quit then
            return True;
         end if;
      end loop;
      return False;
   end Poll_Quit;

   procedure Draw_Cube (Quit : out Boolean) is
      use SDL.C;
      Pi : constant := Ada.Numerics.Pi;
      Xy1, Xy2 : Point_3D;
   begin
      Rotate_Cube (Pi / 4.0, Arctan (Sqrt (2.0)));
      for Frame in 0 .. 359 loop
         Renderer.Set_Draw_Colour ((0, 0, 0, 255));
         Renderer.Fill (Rectangle => (0, 0, Width, Height));

         Renderer.Set_Draw_Colour ((0, 220, 0, 255));
         for Edge of Edges loop
            Xy1 := Nodes (Edge.A);
            Xy2 := Nodes (Edge.B);
            Renderer.Draw (Line => ((int (Xy1.X + Offset), int (Xy1.Y + Offset)),
                                    (int (Xy2.X + Offset), int (Xy2.Y + Offset))));
         end loop;
         Rotate_Cube (Pi / 180.0, 0.0);
         Window.Update_Surface;
         Quit := Poll_Quit;
         exit when Quit;
         delay 0.020;
      end loop;
   end Draw_Cube;

begin
   if not SDL.Initialise (Flags => SDL.Enable_Screen) then
      return;
   end if;

   SDL.Video.Windows.Makers.Create (Win      => Window,
                                    Title    => "Rotating cube",
                                    Position => SDL.Natural_Coordinates'(X => 10, Y => 10),
                                    Size     => SDL.Positive_Sizes'(Width, Height),
                                    Flags    => 0);
   SDL.Video.Renderers.Makers.Create (Renderer, Window.Get_Surface);

   while not Quit loop
      Draw_Cube (Quit);
   end loop;

   Window.Finalize;
   SDL.Finalise;
end Rotating_Cube;

Amazing Hopper

Translation of: BASIC256
Translation of: FreeBASIC

El programa requiere de la ejecución con "rxvt" de Linux: rxvt -g 500x250 -fn "xft:FantasqueSansMono-Regular:pixelsize=1" -e ./bin/cubo

Caption
#context-free Draw a cube
   Loop for (i=1, #(i<=3), ++i)
      Draw a line (size_2, {size_2} Minus(scale_zoff), [i] Get 'x',\
                   {size_2} Minus(scale x zoff) )
      Draw a line (size_2, {size_2} Plus(scale_zoff), [{7}Minus(i)] Get 'x' ,\
                   {size_2} Plus(scale x zoff) )
      Draw a line ([i] Get 'x', {size_2} Minus(scale x zoff),\
                   [Minusone(i) Module(3) Plus(4)] Get 'x', {size_2} Plus(scale x zoff) )
      Draw a line ([i] Get 'x', {size_2} Minus(scale x zoff), \
                   [{i} Module(3) Plus(4)] Get 'x', {size_2} Plus(scale x zoff) )
   Next
Return\\

#context-free Delete old cube
   Color back '0', Draw a cube
Return\\

#context-free Setting values of program
   Set( Div(M_PI,6), Mul(5,Div(M_PI,6)), Mul(3,M_PI_2), Mul(11,Div(M_PI,6)),\
        M_PI_2, Mul(7,Div(M_PI,6)) )
   Append to list 'cylphi'
   
   /* pre-cálculos */
   Let ( dt := Div(1,30 ))
   Let (size_2 := Div( SIZE, 2))
   Let (scale_zoff := Div( SCALE,zoff))
   Let (scale x zoff := Mul (SCALE, zoff))
Return \\

#include <jambo.h>

/*
Execute with:
  $ rxvt -g 250x250 -fn "xft:FantasqueSansMono-Regular:pixelsize=1" -e hopper jm/cubo.jambo
*/

#define SCALE 50
#define SIZE 200
#define zoff 0.5773502691896257645091487805019574556
#define cylr 1.6329931618554520654648560498039275946

Main
   Set break
   theta=0, dtheta=1.5, lasttime=0, dt=0 , timer=0
   size_2=0, scale_zoff=0, scale x zoff=0, cylphi = {}

   Dim (6) as zeros (x)
   
   Setting values of program 
      
   Cls
   /* Draw a cube */
   Loop while ( Not (Keypressed))
       Tic(lasttime)
       Loop for( i=1, #(i<=6), ++i )
           Add( size_2, Mul( Mul(SCALE,cylr), Cos( [i] Get 'cylphi' Plus 'theta')) )
           Put 'x'
       Next
       Color back '15', Draw a cube
       
       Loop 
           Timecpu(timer)
       While ( This 'timer' Compared to 'Add(lasttime, dt)' Is less )
       
       Let ( theta := Add( theta, Mul( dtheta, Sub(timer, lasttime)))) 
       Sleep (0.01)
       Delete old cube
   Back
End

Subrutines

AutoHotkey

Requires Gdip Library

; ---------------------------------------------------------------
cubeSize	:= 200
deltaX		:= A_ScreenWidth/2
deltaY		:= A_ScreenHeight/2
keyStep		:= 1
mouseStep	:= 0.2
zoomStep	:= 1.1
playSpeed	:= 1
playTimer	:= 10
penSize		:= 5

/*
HotKeys:
!p::			Play/Stop
!x::			change play to x-axis
!y::			change play to y-axis
!z::			change play to z-axis
!NumpadAdd::	Zoom in
!WheelUp::		Zoom in
!NumpadSub::	Zoom out
!WheelDown::	Zoom out
!LButton::		Rotate X-axis, follow mouse
!Up::			Rotate X-axis, CCW
!Down::			Rotate X-axis, CW
!LButton::		Rotate Y-axis, follow mouse
!Right::		Rotate Y-axis, CCW
!Left::			Rotate Y-axis, CW
!RButton::		Rotate Z-axis, follow mouse
!PGUP::			Rotate Z-axis, CW
!PGDN::			Rotate Z-axis, CCW
+LButton::		Move, follow mouse
^esc::			Exitapp
*/
visualCube =
(
			1+--------+5
			 |\         \
			 | 2+--------+6
			 |  |        |
			3+  |   7+   |  
			  \ |        |
			   4+--------+8
)

SetBatchLines, -1
coord := cubeSize/2
nodes	:=[[-coord, -coord, -coord]
		,  [-coord, -coord,  coord]
		,  [-coord,  coord, -coord]
		,  [-coord,  coord,  coord]
		,  [ coord, -coord, -coord]
		,  [ coord, -coord,  coord]
		,  [ coord,  coord, -coord]
		,  [ coord,  coord,  coord]]
		
edges	:= [[1, 2], [2, 4], [4, 3], [3, 1]
		,   [5, 6], [6, 8], [8, 7], [7, 5]
		,   [1, 5], [2, 6], [3, 7], [4, 8]]

faces 	:= [[1,2,4,3], [2,4,8,6], [1,2,6,5], [1,3,7,5], [5,7,8,6], [3,4,8,7]]

CP := [(nodes[8,1]+nodes[1,1])/2 , (nodes[8,2]+nodes[1,2])/2]

rotateX3D(-30)
rotateY3D(30)
Gdip1()
draw()
return

; --------------------------------------------------------------
draw() {
	global
	D := ""
	for i, n in nodes
		D .= Sqrt((n.1-CP.1)**2 + (n.2-CP.2)**2) "`t:" i ":`t" n.3 "`n"
	Sort, D, N
	p1 := StrSplit(StrSplit(D, "`n", "`r").1, ":").2
	p2 := StrSplit(StrSplit(D, "`n", "`r").2, ":").2
	hiddenNode := nodes[p1,3] < nodes[p2,3] ? p1 : p2
	
	; Draw Faces
	loop % faces.count() {
		n1 := faces[A_Index, 1]
		n2 := faces[A_Index, 2]
		n3 := faces[A_Index, 3]
		n4 := faces[A_Index, 4]
		if (n1 = hiddenNode) || (n2 = hiddenNode) || (n3 = hiddenNode) || (n4 = hiddenNode)
			continue
		points := nodes[n1,1]+deltaX "," nodes[n1,2]+deltaY
			. "|" nodes[n2,1]+deltaX "," nodes[n2,2]+deltaY
			. "|" nodes[n3,1]+deltaX "," nodes[n3,2]+deltaY
			. "|" nodes[n4,1]+deltaX "," nodes[n4,2]+deltaY
		Gdip_FillPolygon(G, FaceBrush%A_Index%, Points)
	}
	
	; Draw Node-Numbers
	;~ loop % nodes.count() {
		;~ Gdip_FillEllipse(G, pBrush, nodes[A_Index, 1]+deltaX, nodes[A_Index, 2]+deltaY, 4, 4)
		;~ Options := "x" nodes[A_Index, 1]+deltaX " y" nodes[A_Index, 2]+deltaY "c" TextColor " Bold s" size
		;~ Gdip_TextToGraphics(G, A_Index, Options, Font)
	;~ }
	
	; Draw Edges
	loop % edges.count() {
		n1 := edges[A_Index, 1]
		n2 := edges[A_Index, 2]
		if (n1 = hiddenNode) || (n2 = hiddenNode)
			continue
		Gdip_DrawLine(G, pPen, nodes[n1,1]+deltaX, nodes[n1,2]+deltaY, nodes[n2,1]+deltaX, nodes[n2,2]+deltaY)
	}
	UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height)
}

; ---------------------------------------------------------------
rotateZ3D(theta) { ; Rotate shape around the z-axis
	global
	theta *= 3.141592653589793/180
	sinTheta := sin(theta)
	cosTheta := cos(theta)
	loop % nodes.count() {
		x := nodes[A_Index,1]
		y := nodes[A_Index,2]
		nodes[A_Index,1] := x*cosTheta - y*sinTheta
		nodes[A_Index,2] := y*cosTheta + x*sinTheta
	}
	Redraw()
}

; ---------------------------------------------------------------
rotateX3D(theta) { ; Rotate shape around the x-axis
	global
	theta *= 3.141592653589793/180
	sinTheta := sin(theta)
	cosTheta := cos(theta)
	loop % nodes.count() {
		y := nodes[A_Index, 2]
		z := nodes[A_Index, 3]
		nodes[A_Index, 2] := y*cosTheta - z*sinTheta
		nodes[A_Index, 3] := z*cosTheta + y*sinTheta
	}
	Redraw()
}

; ---------------------------------------------------------------
rotateY3D(theta) { ; Rotate shape around the y-axis
	global
	theta *= 3.141592653589793/180
	sinTheta := sin(theta)
	cosTheta := cos(theta)
	loop % nodes.count() {
		x := nodes[A_Index, 1]
		z := nodes[A_Index, 3]
		nodes[A_Index, 1] := x*cosTheta + z*sinTheta
		nodes[A_Index, 3] := z*cosTheta - x*sinTheta
	}
	Redraw()
}

; ---------------------------------------------------------------
Redraw(){
	global
	gdip2()
	gdip1()
	draw()
}

; ---------------------------------------------------------------
gdip1(){
	global
	If !pToken := Gdip_Startup()
	{
		MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
		ExitApp
	}
	OnExit, Exit
	Width := A_ScreenWidth, Height := A_ScreenHeight
	Gui, 1: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop
	Gui, 1: Show, NA
	hwnd1 := WinExist()
	hbm := CreateDIBSection(Width, Height)
	hdc := CreateCompatibleDC()
	obm := SelectObject(hdc, hbm)
	G := Gdip_GraphicsFromHDC(hdc)
	Gdip_SetSmoothingMode(G, 4)
	TextColor:="FFFFFF00", size := 18
	Font := "Arial"
	Gdip_FontFamilyCreate(Font)
	pBrush := Gdip_BrushCreateSolid(0xFFFF00FF)
	FaceBrush1 := Gdip_BrushCreateSolid(0xFF0000FF)	; blue
	FaceBrush2 := Gdip_BrushCreateSolid(0xFFFF0000) ; red
	FaceBrush3 := Gdip_BrushCreateSolid(0xFFFFFF00) ; yellow
	FaceBrush4 := Gdip_BrushCreateSolid(0xFFFF7518) ; orange
	FaceBrush5 := Gdip_BrushCreateSolid(0xFF00FF00) ; lime
	FaceBrush6 := Gdip_BrushCreateSolid(0xFFFFFFFF) ; white
	pPen := Gdip_CreatePen(0xFF000000, penSize)
}

; ---------------------------------------------------------------
gdip2(){
	global
	Gdip_DeleteBrush(pBrush)
	Gdip_DeletePen(pPen)
	SelectObject(hdc, obm)
	DeleteObject(hbm)
	DeleteDC(hdc)
	Gdip_DeleteGraphics(G)
}
; Viewing Hotkeys ----------------------------------------------
; HotKey Play/Stop ---------------------------------------------
!p::
SetTimer, rotateTimer, % (toggle:=!toggle)?playTimer:"off"
return

rotateTimer:
axis := !axis ? "Y" : axis
rotate%axis%3D(playSpeed)
return

!x::
!y::
!z::
axis := SubStr(A_ThisHotkey, 2, 1)
return

; HotKey Zoom in/out -------------------------------------------
!NumpadAdd::
!NumpadSub::
!WheelUp::
!WheelDown::
loop % nodes.count()
{
	nodes[A_Index, 1] := nodes[A_Index, 1] * (InStr(A_ThisHotkey, "Add") || InStr(A_ThisHotkey, "Up") ? zoomStep : 1/zoomStep)
	nodes[A_Index, 2] := nodes[A_Index, 2] * (InStr(A_ThisHotkey, "Add") || InStr(A_ThisHotkey, "Up") ? zoomStep : 1/zoomStep)
	nodes[A_Index, 3] := nodes[A_Index, 3] * (InStr(A_ThisHotkey, "Add") || InStr(A_ThisHotkey, "Up") ? zoomStep : 1/zoomStep)
}
Redraw()
return

; HotKey Rotate around Y-Axis ----------------------------------
!Right::
!Left::
rotateY3D(keyStep * (InStr(A_ThisHotkey,"right") ? 1 : -1))
return

; HotKey Rotate around X-Axis ----------------------------------
!Up::
!Down::
rotateX3D(keyStep * (InStr(A_ThisHotkey, "Up") ? 1 : -1))
return

; HotKey Rotate around Z-Axis ----------------------------------
!PGUP::
!PGDN::
rotateZ3D(keyStep * (InStr(A_ThisHotkey, "UP") ? 1 : -1))
return

; HotKey, Rotate around X/Y-Axis -------------------------------
!LButton::
MouseGetPos, pmouseX, pmouseY
while GetKeyState("Lbutton", "P")
{
	MouseGetPos, mouseX, mouseY
	DeltaMX := mouseX - pmouseX
	DeltaMY := pmouseY - mouseY
	if (DeltaMX || DeltaMY)
	{
		MouseGetPos, pmouseX, pmouseY
		rotateY3D(DeltaMX)
		rotateX3D(DeltaMY)
	}
}
return

; HotKey Rotate around Z-Axis ----------------------------------
!RButton::
MouseGetPos, pmouseX, pmouseY
while GetKeyState("Rbutton", "P")
{
	MouseGetPos, mouseX, mouseY
	DeltaMX := mouseX - pmouseX
	DeltaMY := mouseY - pmouseY
	DeltaMX *= mouseY < deltaY ? mouseStep : -mouseStep 
	DeltaMY *= mouseX > deltaX ? mouseStep : -mouseStep 
	if (DeltaMX || DeltaMY)
	{
		MouseGetPos, pmouseX, pmouseY
		rotateZ3D(DeltaMX)
		rotateZ3D(DeltaMY)
	}
}
return

; HotKey, Move -------------------------------------------------
+LButton::
MouseGetPos, pmouseX, pmouseY
while GetKeyState("Lbutton", "P")
{
	MouseGetPos, mouseX, mouseY
	deltaX += mouseX - pmouseX
	deltaY += mouseY - pmouseY
	pmouseX := mouseX
	pmouseY := mouseY
	Redraw()
}
return

; ---------------------------------------------------------------
^esc::
Exit:
gdip2()
Gdip_Shutdown(pToken)
ExitApp
Return
; ---------------------------------------------------------------


BASIC

BASIC256

global escala
global tam
global zoff
global cylr

escala = 50
tam = 320
zoff = 0.5773502691896257645091487805019574556
cylr = 1.6329931618554520654648560498039275946

clg
graphsize tam, tam

dim x(6)
theta = 0.0
dtheta = 1.5
dt = 1.0 / 30
dim cylphi = {PI/6, 5*PI/6, 3*PI/2, 11*PI/6, PI/2, 7*PI/6}

while key = ""
    lasttime = msec
    for i = 0 to 5
        x[i] = tam/2 + escala *cylr * cos(cylphi[i] + theta)
    next i
    clg
    call drawcube(x)

    while msec < lasttime + dt
    end while
    theta += dtheta*(msec-lasttime)
    pause .4
    call drawcube(x)
end while

subroutine drawcube(x)
    for i = 0 to 2
        color rgb(0,0,0)  #black
        line tam/2, tam/2 - escala / zoff, x[i], tam/2 - escala * zoff
        line tam/2, tam/2 + escala / zoff, x[5-i], tam/2 + escala * zoff
        line  x[i], tam/2 - escala * zoff, x[(i % 3) + 3], tam/2 + escala * zoff
        line  x[i], tam/2 - escala * zoff, x[((i+1)%3) + 3], tam/2 + escala * zoff
    next i
end subroutine

Chipmunk Basic

Works with: Chipmunk Basic version 3.6.4
100 cls
110 graphics 0
120 graphics color 0,0,0
130 while true
140   graphics cls
150   x = cos(t)*20
160   y = sin(t)*18
170   r = sin(t+t)
180   moveto (x+40),(y+40-r)
190   lineto (-y+40),(x+40-r)
200   moveto (-y+40),(x+40-r)
210   lineto (-x+40),(-y+40-r)
220   moveto (-x+40),(-y+40-r)
230   lineto (y+40),(-x+40-r)
240   moveto (y+40),(-x+40-r)
250   lineto (x+40),(y+40-r)
260   moveto (x+40),(y+20+r)
270   lineto (-y+40),(x+20+r)
280   moveto (-y+40),(x+20+r)
290   lineto (-x+40),(-y+20+r)
300   moveto (-x+40),(-y+20+r)
310   lineto (y+40),(-x+20+r)
320   moveto (y+40),(-x+20+r)
330   lineto (x+40),(y+20+r)
340   moveto (x+40),(y+40-r)
350   lineto (x+40),(y+20+r)
360   moveto (-y+40),(x+40-r)
370   lineto (-y+40),(x+20+r)
380   moveto (-x+40),(-y+40-r)
390   lineto (-x+40),(-y+20+r)
400   moveto (y+40),(-x+40-r)
410   lineto (y+40),(-x+20+r)
420   for i = 1 to 1000 : next i
430   t = t+0.15
440 wend

GW-BASIC

Works with: PC-BASIC version any
100 SCREEN 2
110 WHILE 1
120   CLS
130   X = COS(T)*20
140   Y = SIN(T)*18
150   R = SIN(T+T)
160   LINE (( X+40),( Y+40-R))-((-Y+40),( X+40-R))
170   LINE ((-Y+40),( X+40-R))-((-X+40),(-Y+40-R))
180   LINE ((-X+40),(-Y+40-R))-(( Y+40),(-X+40-R))
190   LINE (( Y+40),(-X+40-R))-(( X+40),( Y+40-R))
200   LINE (( X+40),( Y+20+R))-((-Y+40),( X+20+R))
210   LINE ((-Y+40),( X+20+R))-((-X+40),(-Y+20+R))
220   LINE ((-X+40),(-Y+20+R))-(( Y+40),(-X+20+R))
230   LINE (( Y+40),(-X+20+R))-(( X+40),( Y+20+R))
240   LINE (( X+40),( Y+40-R))-(( X+40),( Y+20+R))
250   LINE ((-Y+40),( X+40-R))-((-Y+40),( X+20+R))
260   LINE ((-X+40),(-Y+40-R))-((-X+40),(-Y+20+R))
270   LINE (( Y+40),(-X+40-R))-(( Y+40),(-X+20+R))
280   T = T+.15
290 WEND

MSX Basic

Works with: MSX BASIC version any
100 SCREEN 2
110 COLOR 15
120   CLS
130   X = COS(T)*20
140   Y = SIN(T)*18
150   R = SIN(T+T)
160   LINE (( X+40),( Y+40-R))-((-Y+40),( X+40-R))
170   LINE ((-Y+40),( X+40-R))-((-X+40),(-Y+40-R))
180   LINE ((-X+40),(-Y+40-R))-(( Y+40),(-X+40-R))
190   LINE (( Y+40),(-X+40-R))-(( X+40),( Y+40-R))
200   LINE (( X+40),( Y+20+R))-((-Y+40),( X+20+R))
210   LINE ((-Y+40),( X+20+R))-((-X+40),(-Y+20+R))
220   LINE ((-X+40),(-Y+20+R))-(( Y+40),(-X+20+R))
230   LINE (( Y+40),(-X+20+R))-(( X+40),( Y+20+R))
240   LINE (( X+40),( Y+40-R))-(( X+40),( Y+20+R))
250   LINE ((-Y+40),( X+40-R))-((-Y+40),( X+20+R))
260   LINE ((-X+40),(-Y+40-R))-((-X+40),(-Y+20+R))
270   LINE (( Y+40),(-X+40-R))-(( Y+40),(-X+20+R))
280   FOR I = 1 TO 40 : NEXT I
290   T = T+0.15
300 GOTO 120

C

Rotating wireframe cube in OpenGL, windowing implementation via freeglut

#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);
	glutWireCube(1);
	glPopMatrix();
	glFlush();
}


void onIdle(){
	rot += 0.1;
	glutPostRedisplay();
}

void reshape(int w,int h){
	float ar = (float) w / (float) h ;
	
	glViewport(0,0,(GLsizei)w,(GLsizei)h);
	glTranslatef(0,0,-10);
	glMatrixMode(GL_PROJECTION);
	gluPerspective(70,(GLfloat)w/(GLfloat)h,1,12);
	glLoadIdentity();
	glFrustum ( -1.0, 1.0, -1.0, 1.0, 10.0, 100.0 ) ;
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

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(600,500);
	glutCreateWindow("Rossetta's Rotating Cube");
	init();
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutIdleFunc(onIdle);
	glutMainLoop();
	return 0;
}

C#

Translation of: Java
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Windows.Threading;

namespace RotatingCube
{
    public partial class Form1 : Form
    {
        double[][] nodes = {
            new double[] {-1, -1, -1}, new double[] {-1, -1, 1}, new double[] {-1, 1, -1},
            new double[] {-1, 1, 1}, new double[] {1, -1, -1}, new double[] {1, -1, 1},
            new double[] {1, 1, -1}, new double[] {1, 1, 1} };

        int[][] edges = {
            new int[] {0, 1}, new int[] {1, 3}, new int[] {3, 2}, new int[] {2, 0}, new int[] {4, 5},
            new int[] {5, 7}, new int[] {7, 6}, new int[] {6, 4}, new int[] {0, 4}, new int[] {1, 5},
            new int[] {2, 6}, new int[] {3, 7}};

        public Form1()
        {
            Width = Height = 640;
            StartPosition = FormStartPosition.CenterScreen;
            SetStyle(
                ControlStyles.AllPaintingInWmPaint |
                ControlStyles.UserPaint |
                ControlStyles.DoubleBuffer,
                true);

            Scale(100, 100, 100);
            RotateCuboid(Math.PI / 4, Math.Atan(Math.Sqrt(2)));

            var timer = new DispatcherTimer();
            timer.Tick += (s, e) => { RotateCuboid(Math.PI / 180, 0); Refresh(); };
            timer.Interval = new TimeSpan(0, 0, 0, 0, 17);
            timer.Start();
        }

        private void RotateCuboid(double angleX, double angleY)
        {
            double sinX = Math.Sin(angleX);
            double cosX = Math.Cos(angleX);

            double sinY = Math.Sin(angleY);
            double cosY = Math.Cos(angleY);

            foreach (var node in nodes)
            {
                double x = node[0];
                double y = node[1];
                double z = node[2];

                node[0] = x * cosX - z * sinX;
                node[2] = z * cosX + x * sinX;

                z = node[2];

                node[1] = y * cosY - z * sinY;
                node[2] = z * cosY + y * sinY;
            }
        }

        private void Scale(int v1, int v2, int v3)
        {
            foreach (var item in nodes)
            {
                item[0] *= v1;
                item[1] *= v2;
                item[2] *= v3;
            }
        }

        protected override void OnPaint(PaintEventArgs args)
        {
            var g = args.Graphics;
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.Clear(Color.White);

            g.TranslateTransform(Width / 2, Height / 2);

            foreach (var edge in edges)
            {
                double[] xy1 = nodes[edge[0]];
                double[] xy2 = nodes[edge[1]];
                g.DrawLine(Pens.Black, (int)Math.Round(xy1[0]), (int)Math.Round(xy1[1]),
                        (int)Math.Round(xy2[0]), (int)Math.Round(xy2[1]));
            }

            foreach (var node in nodes)
            {
                g.FillEllipse(Brushes.Black, (int)Math.Round(node[0]) - 4,
                    (int)Math.Round(node[1]) - 4, 8, 8);
            }
        }
    }
}

Delphi

Library: Vcl.Forms
Library: System.Math
Translation of: Javascript
unit main;

interface

uses
  Winapi.Windows, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.ExtCtrls,
  System.Math, System.Classes;

type
  TForm1 = class(TForm)
    tmr1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure tmr1Timer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  nodes: TArray<TArray<double>> = [[-1, -1, -1], [-1, -1, 1], [-1, 1, -1], [-1,
    1, 1], [1, -1, -1], [1, -1, 1], [1, 1, -1], [1, 1, 1]];
  edges: TArray<TArray<Integer>> = [[0, 1], [1, 3], [3, 2], [2, 0], [4, 5], [5,
    7], [7, 6], [6, 4], [0, 4], [1, 5], [2, 6], [3, 7]];

implementation

{$R *.dfm}

procedure Scale(factor: TArray<double>);
begin
  if Length(factor) <> 3 then
    exit;
  for var i := 0 to High(nodes) do
    for var f := 0 to High(factor) do
      nodes[i][f] := nodes[i][f] * factor[f];
end;

procedure RotateCuboid(angleX, angleY: double);
begin
  var sinX := sin(angleX);
  var cosX := cos(angleX);
  var sinY := sin(angleY);
  var cosY := cos(angleY);

  for var i := 0 to High(nodes) do
  begin
    var x := nodes[i][0];
    var y := nodes[i][1];
    var z := nodes[i][2];

    nodes[i][0] := x * cosX - z * sinX;
    nodes[i][2] := z * cosX + x * sinX;

    z := nodes[i][2];

    nodes[i][1] := y * cosY - z * sinY;
    nodes[i][2] := z * cosY + y * sinY;
  end;
end;

function DrawCuboid(x, y, w, h: Integer): TBitmap;
var
  offset: TPoint;
begin
  Result := TBitmap.Create;
  Result.SetSize(w, h);
  rotateCuboid(PI / 180, 0);
  offset := TPoint.Create(x, y);
  with Result.canvas do
  begin
    Brush.Color := clBlack;
    Pen.Color := clWhite;

    Lock;
    FillRect(ClipRect);

    for var edge in edges do
    begin
      var p1 := (nodes[edge[0]]);
      var p2 := (nodes[edge[1]]);
      moveTo(trunc(p1[0]) + offset.x, trunc(p1[1]) + offset.y);
      lineTo(trunc(p2[0]) + offset.x, trunc(p2[1]) + offset.y);
    end;
    Unlock;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ClientHeight := 360;
  ClientWidth := 640;
  DoubleBuffered := true;
  scale([100, 100, 100]);
  rotateCuboid(PI / 4, ArcTan(sqrt(2)));
end;

procedure TForm1.tmr1Timer(Sender: TObject);
var
  buffer: TBitmap;
begin
  buffer := DrawCuboid(ClientWidth div 2, ClientHeight div 2, ClientWidth, ClientHeight);
  Canvas.Draw(0, 0, buffer);
  buffer.Free;
end;

end.

Resource Form

object Form1: TForm1
  OnCreate = FormCreate
  object tmr1: TTimer
    Interval = 17
    OnTimer = tmr1Timer
  end
end


EasyLang

Draws only the visible edges

Run it

node[][] = [ [ -1 -1 -1 ] [ -1 -1 1 ] [ -1 1 -1 ] [ -1 1 1 ] [ 1 -1 -1 ] [ 1 -1 1 ] [ 1 1 -1 ] [ 1 1 1 ] ]
edge[][] = [ [ 1 2 ] [ 2 4 ] [ 4 3 ] [ 3 1 ] [ 5 6 ] [ 6 8 ] [ 8 7 ] [ 7 5 ] [ 1 5 ] [ 2 6 ] [ 3 7 ] [ 4 8 ] ]
# 
proc scale f . .
   for i = 1 to len node[][]
      for d = 1 to 3
         node[i][d] *= f
      .
   .
.
proc rotate angx angy . .
   sinx = sin angx
   cosx = cos angx
   siny = sin angy
   cosy = cos angy
   for i = 1 to len node[][]
      x = node[i][1]
      z = node[i][3]
      node[i][1] = x * cosx - z * sinx
      y = node[i][2]
      z = z * cosx + x * sinx
      node[i][2] = y * cosy - z * siny
      node[i][3] = z * cosy + y * siny
   .
.
len nd[] 3
proc draw . .
   clear
   m = 999
   mi = -1
   for i = 1 to len node[][]
      if node[i][3] < m
         m = node[i][3]
         mi = i
      .
   .
   ix = 1
   for i = 1 to len edge[][]
      if edge[i][1] = mi
         nd[ix] = edge[i][2]
         ix += 1
      elif edge[i][2] = mi
         nd[ix] = edge[i][1]
         ix += 1
      .
   .
   for ni = 1 to len nd[]
      for i = 1 to len edge[][]
         if edge[i][1] = nd[ni] or edge[i][2] = nd[ni]
            x1 = node[edge[i][1]][1]
            y1 = node[edge[i][1]][2]
            x2 = node[edge[i][2]][1]
            y2 = node[edge[i][2]][2]
            move x1 + 50 y1 + 50
            line x2 + 50 y2 + 50
         .
      .
   .
.
scale 25
rotate 45 atan sqrt 2
draw
on animate
   rotate 1 0
   draw
.

Evaldraw

Based on the solution in draw cuboid. Draws a filled cube with a texture on each face.

Rotating 3D cube
Rotating cube with texture. Makes use of rudimentary glBegin(GL_QUADS) function
// We can define our own vec3 struct
struct vec3{x,y,z;}
static modelMatrix[9];
() {
   cls(0x828282); // clear screen
   clz(1e32); // clear depth buffer
   setcam(0,0,-3,0,0); // set camera some units back
   
   // create two local arrays to hold rotation matrices
   double roty[9], rotz[9];
   
   static otim;
   tim=klock(0); dt=tim-otim; otim=tim;
   static degrees = 0;
   degrees+=200*dt;
   rads = degrees/180*pi;
   rotateZ( rotz, rads );
   rotateY( roty, rads );
   
   // evaldraw does support some GL-like drawing
   // modes, but any transformations must be done by hand
   // Here we use a global model matrix that
   // transforms vertices created by the myVertex function
   mult(modelMatrix, roty, rotz);
   glSetTex("cloud.png");
   drawcuboid(0,0,0,1,1,1);
}

drawcuboid(x,y,z,sx,sy,sz) {
   glBegin(GL_QUADS);
   setcol(192,32,32);
   glTexCoord(0,0); myVertex(x-sx,y-sy,z-sz);
   glTexCoord(1,0); myVertex(x+sx,y-sy,z-sz);
   glTexCoord(1,1); myVertex(x+sx,y+sy,z-sz);
   glTexCoord(0,1); myVertex(x-sx,y+sy,z-sz);
   
   setcol(32,192,32);
   glTexCoord(0,0); myVertex(x-sx,y-sy,z+sz);
   glTexCoord(1,0); myVertex(x-sx,y-sy,z-sz);
   glTexCoord(1,1); myVertex(x-sx,y+sy,z-sz);
   glTexCoord(0,1); myVertex(x-sx,y+sy,z+sz);
   
   setcol(32,32,192);
   glTexCoord(0,0); myVertex(x+sx,y-sy,z+sz);
   glTexCoord(1,0); myVertex(x-sx,y-sy,z+sz);
   glTexCoord(1,1); myVertex(x-sx,y+sy,z+sz);
   glTexCoord(0,1); myVertex(x+sx,y+sy,z+sz);
   
   setcol(192,192,32);
   glTexCoord(0,0); myVertex(x+sx,y-sy,z-sz);
   glTexCoord(1,0); myVertex(x+sx,y-sy,z+sz);
   glTexCoord(1,1); myVertex(x+sx,y+sy,z+sz);
   glTexCoord(0,1); myVertex(x+sx,y+sy,z-sz);

   setcol(192,32,192);
   glTexCoord(0,0); myVertex(x-sx,y-sy,z+sz);
   glTexCoord(1,0); myVertex(x+sx,y-sy,z+sz);
   glTexCoord(1,1); myVertex(x+sx,y-sy,z-sz);
   glTexCoord(0,1); myVertex(x-sx,y-sy,z-sz);

   setcol(32,192,192);
   glTexCoord(0,0); myVertex(x-sx,y+sy,z-sz);
   glTexCoord(1,0); myVertex(x+sx,y+sy,z-sz);
   glTexCoord(1,1); myVertex(x+sx,y+sy,z+sz);
   glTexCoord(0,1); myVertex(x-sx,y+sy,z+sz);
   glEnd(); 
}
myVertex(x,y,z) {
  // Initialize a struct value
  vec3 v = {x,y,z};
  
  // Apply global model matrix transformation
  transformPoint(v, modelMatrix);
  
  // Submit the vertex to draw list
  glVertex(v.x, v.y, v.z);
}
rotateY(m[9], r) {
   c = cos(r); s=sin(r);
   m[0] = c; m[1] = 0; m[2] = s;
   m[3] = 0; m[4] = 1;  m[5] = 0;
   m[6] = -s; m[7] = 0;  m[8] = c;
}

rotateZ(m[9], r) {
   c = cos(r); s=sin(r);
   m[0] = c; m[1] = -s; m[2] = 0;
   m[3] = s; m[4] = c;  m[5] = 0;
   m[6] = 0; m[7] = 0;  m[8] = 1;
}
transformPoint(vec3 v, m[9]) {
   x2 = v.x * m[0] + v.y * m[1] + v.z * m[2];
   y2 = v.x * m[3] + v.y * m[4] + v.z * m[5];
   z2 = v.x * m[6] + v.y * m[7] + v.z * m[8];
   // Mutate the struct v with new values
   v.x=x2; v.y=y2; v.z=z2;
}
mult(c[9],a[9],b[9]) { // C = AB
   // multiply a row in A with a column in B
   for(i=0; i<3; i++)
      for(j=0; j<3; j++) {
         sum = 0.0;
         for(k=0; k<3; k++) {
            sum += A[k*3+i] * B[k*3+j];
         }
         C[i*3+j] = sum;
      }
}

FreeBASIC

#define PI 3.14159265358979323
#define SCALE 50
#define SIZE 320
#define zoff 0.5773502691896257645091487805019574556
#define cylr 1.6329931618554520654648560498039275946
screenres SIZE, SIZE, 4

dim as double theta = 0.0, dtheta = 1.5, x(0 to 5), lasttime, dt = 1./30

dim as double cylphi(0 to 5) = {PI/6, 5*PI/6, 3*PI/2, 11*PI/6, PI/2, 7*PI/6}

sub drawcube( x() as double, colour as uinteger )
    for i as uinteger = 0 to 2
        line (SIZE/2, SIZE/2-SCALE/zoff) - (x(i), SIZE/2-SCALE*zoff), colour
        line (SIZE/2, SIZE/2+SCALE/zoff) - (x(5-i), SIZE/2+SCALE*zoff), colour
        line ( x(i), SIZE/2-SCALE*zoff ) - ( x(i mod 3 + 3), SIZE/2+SCALE*zoff ), colour
        line ( x(i), SIZE/2-SCALE*zoff ) - ( x((i+1) mod 3 + 3), SIZE/2+SCALE*zoff ), colour
    next i
end sub

while inkey=""
    lasttime = timer
    for i as uinteger = 0 to 5
        x(i) = SIZE/2 + SCALE*cylr*cos(cylphi(i)+theta)
    next i
    drawcube x(), 15
    
    while timer < lasttime + dt
    wend
    theta += dtheta*(timer-lasttime)
    drawcube x(),0
wend
end

FutureBasic

include "Tlbx SceneKit.incl"

_window = 1
begin enum output 1
  _sceneView
end enum

local fn RotatingCubeScene as SCNSceneRef
  SCNSceneRef   scene = fn SCNSceneInit
  SCNNodeRef rootNode = fn SCNSceneRootNode( scene )
  
  SCNCameraRef camera = fn SCNCameraInit
  SCNNodeRef cameraNode = fn SCNNodeInit
  SCNNodeSetCamera( cameraNode, camera )
  SCNNodeAddChildNode( rootNode, cameraNode )
  
  SCNVector3 cameraPos = {0.0, 0.0, 10.0}
  SCNNodeSetPosition( cameraNode, cameraPos )
  
  SCNNodeRef lightNode = fn SCNNodeInit
  SCNLightRef    light = fn SCNLightInit
  SCNLightSetType( light, SCNLightTypeOmni )
  SCNNodeSetPosition( lightNode, fn SCNVector3Make( 0.0, 10.0, 10.0 ) )
  SCNNodeAddChildNode( rootNode, lightNode )
  
  SCNNodeRef    ambientLightNode = fn SCNNodeInit
  SCNLightRef       ambientLight = fn SCNLightInit
  SCNLightSetType(  ambientLight, SCNLightTypeAmbient )
  SCNLightSetColor( ambientLight, fn ColorGray )
  SCNNodeSetLight( ambientLightNode, ambientLight )
  SCNNodeAddChildNode( rootNode, ambientLightNode )
  
  SCNBoxRef  boxGeometry = fn SCNBoxInit( 4.0, 4.0, 4.0, 0.0 )
  SCNNodeRef boxNode = fn SCNNodeWithGeometry( boxGeometry )
  
  SCNMaterialRef side1 = fn SCNMaterialInit
  SCNMaterialRef side2 = fn SCNMaterialInit
  SCNMaterialRef side3 = fn SCNMaterialInit
  SCNMaterialRef side4 = fn SCNMaterialInit
  SCNMaterialRef side5 = fn SCNMaterialInit
  SCNMaterialRef side6 = fn SCNMaterialInit
  
  SCNMaterialPropertySetContents( fn SCNMaterialMultiply( side1 ), fn ColorBlue   )
  SCNMaterialPropertySetContents( fn SCNMaterialMultiply( side2 ), fn ColorOrange )
  SCNMaterialPropertySetContents( fn SCNMaterialMultiply( side3 ), fn ColorRed    )
  SCNMaterialPropertySetContents( fn SCNMaterialMultiply( side4 ), fn ColorGreen  )
  SCNMaterialPropertySetContents( fn SCNMaterialMultiply( side5 ), fn ColorYellow )
  SCNMaterialPropertySetContents( fn SCNMaterialMultiply( side6 ), fn ColorCyan   )
  
  SCNGeometrySetMaterials( boxGeometry, @[side1,side2,side3,side4,side5,side6] )
  SCNNodeAddChildNode( rootNode, boxNode )
  SCNActionableRunAction( boxNode, fn SCNActionRepeatActionForever( fn SCNActionRotateByAngle( M_PI, fn SCNVector3Make( 0.0, 25.0, 5.0 ), 5.0 ) ) )
end fn = scene

void local fn BuildWindow
  window _window, @"Rosetta Code Rotating Cube", ( 0, 0, 600, 600 )
  scnview _sceneView, fn RotatingCubeScene, ( 0, 0, 600, 600 )
  SCNViewSetBackgroundColor( _sceneView, fn ColorBlack )
  SCNViewSetAllowsCameraControl( _sceneView, YES )
end fn

void local fn DoDialog( ev as long, tag as long, wnd as long )
  select (ev)
    case _windowWillClose : end
  end select
end fn

on dialog fn DoDialog

fn BuildWindow

HandleEvents
Output:

Go

As of Go 1.9, it looks as if the only standard library supporting animated graphics is image/gif - so we create an animated GIF...

package main

import (
	"image"
	"image/color"
	"image/gif"
	"log"
	"math"
	"os"
)

const (
	width, height = 640, 640
	offset        = height / 2
	fileName      = "rotatingCube.gif"
)

var nodes = [][]float64{{-100, -100, -100}, {-100, -100, 100}, {-100, 100, -100}, {-100, 100, 100},
	{100, -100, -100}, {100, -100, 100}, {100, 100, -100}, {100, 100, 100}}
var edges = [][]int{{0, 1}, {1, 3}, {3, 2}, {2, 0}, {4, 5}, {5, 7}, {7, 6},
	{6, 4}, {0, 4}, {1, 5}, {2, 6}, {3, 7}}

func main() {
	var images []*image.Paletted
	fgCol := color.RGBA{0xff, 0x00, 0xff, 0xff}
	var palette = []color.Color{color.RGBA{0x00, 0x00, 0x00, 0xff}, fgCol}
	var delays []int

	imgFile, err := os.Create(fileName)
	if err != nil {
		log.Fatal(err)
	}
	defer imgFile.Close()

	rotateCube(math.Pi/4, math.Atan(math.Sqrt(2)))
	var frame float64
	for frame = 0; frame < 360; frame++ {
		img := image.NewPaletted(image.Rect(0, 0, width, height), palette)
		images = append(images, img)
		delays = append(delays, 5)
		for _, edge := range edges {
			xy1 := nodes[edge[0]]
			xy2 := nodes[edge[1]]
			drawLine(int(xy1[0])+offset, int(xy1[1])+offset, int(xy2[0])+offset, int(xy2[1])+offset, img, fgCol)
		}
		rotateCube(math.Pi/180, 0)
	}
	if err := gif.EncodeAll(imgFile, &gif.GIF{Image: images, Delay: delays}); err != nil {
		imgFile.Close()
		log.Fatal(err)
	}

}

func rotateCube(angleX, angleY float64) {
	sinX := math.Sin(angleX)
	cosX := math.Cos(angleX)
	sinY := math.Sin(angleY)
	cosY := math.Cos(angleY)
	for _, node := range nodes {
		x := node[0]
		y := node[1]
		z := node[2]
		node[0] = x*cosX - z*sinX
		node[2] = z*cosX + x*sinX
		z = node[2]
		node[1] = y*cosY - z*sinY
		node[2] = z*cosY + y*sinY
	}
}

func drawLine(x0, y0, x1, y1 int, img *image.Paletted, col color.RGBA) {
	dx := abs(x1 - x0)
	dy := abs(y1 - y0)
	var sx, sy int = -1, -1
	if x0 < x1 {
		sx = 1
	}
	if y0 < y1 {
		sy = 1
	}
	err := dx - dy
	for {
		img.Set(x0, y0, col)
		if x0 == x1 && y0 == y1 {
			break
		}
		e2 := 2 * err
		if e2 > -dy {
			err -= dy
			x0 += sx
		}
		if e2 < dx {
			err += dx
			y0 += sy
		}
	}
}

func abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

Haskell

This implementation compiles to JavaScript that runs in a browser using the ghcjs compiler . The reflex-dom library is used to help with svg rendering and animation.

{-# LANGUAGE RecursiveDo #-} 
import Reflex.Dom 
import Data.Map as DM (Map, lookup, insert, empty, fromList)
import Data.Matrix 
import Data.Time.Clock 
import Control.Monad.Trans 

size = 500
updateFrequency = 0.2
rotationStep = pi/10

data Color = Red | Green | Blue | Yellow | Orange | Purple | Black deriving (Show,Eq,Ord,Enum)

zRot :: Float -> Matrix Float
zRot rotation = 
    let c = cos rotation
        s = sin rotation
    in fromLists [[ c,  s,  0,  0 ]
                 ,[-s,  c,  0,  0 ]
                 ,[ 0,  0,  1,  0 ]
                 ,[ 0,  0,  0,  1 ]
                 ]

xRot :: Float -> Matrix Float
xRot rotation = 
    let c = cos rotation
        s = sin rotation
    in fromLists [[ 1,  0,  0,  0 ]
                 ,[ 0,  c,  s,  0 ]
                 ,[ 0, -s,  c,  0 ]
                 ,[ 0,  0,  0,  1 ]
                 ]

yRot :: Float -> Matrix Float
yRot rotation = 
    let c = cos rotation
        s = sin rotation
    in fromLists [[ c,  0, -s,  0 ]
                 ,[ 0,  1,  0,  0 ]
                 ,[ s,  0,  c,  0 ]
                 ,[ 0,  0,  0,  1 ]
                 ]

translation :: (Float,Float,Float) -> Matrix Float
translation (x,y,z) =
    fromLists  [[ 1,  0,  0,  0 ]
               ,[ 0,  1,  0,  0 ]
               ,[ 0,  0,  1,  0 ]
               ,[ x,  y,  z,  1 ]
               ]

scale :: Float -> Matrix Float
scale s =
    fromLists  [[ s,  0,  0,  0 ]
               ,[ 0,  s,  0,  0 ]
               ,[ 0,  0,  s,  0 ]
               ,[ 0,  0,  0,  1 ]
               ]

-- perspective transformation; 
perspective :: Matrix Float
perspective = 
    fromLists  [[ 1,  0,  0,  0 ]
               ,[ 0,  1,  0,  0 ]
               ,[ 0,  0,  1,  1 ]
               ,[ 0,  0,  1,  1 ] ]

transformPoints :: Matrix Float -> Matrix Float -> [(Float,Float)]
transformPoints transform points = 
    let result4d = points `multStd2` transform
        result2d = (\[x,y,z,w] -> (x/w,y/w)) <$> toLists result4d
    in result2d

showRectangle :: MonadWidget t m => Float -> Float -> Float -> Float -> Color -> Dynamic t (Matrix Float) -> m ()
showRectangle x0 y0 x1 y1 faceColor dFaceView = do
    let points = fromLists [[x0,y0,0,1],[x0,y1,0,1],[x1,y1,0,1],[x1,y0,0,1]]
        pointsToString = concatMap (\(x,y) -> show x ++ ", " ++ show y ++ " ") 
    dAttrs <- mapDyn (\fvk -> DM.fromList [ ("fill", show faceColor)
                                          , ("points", pointsToString (transformPoints fvk points))
                                          ] ) dFaceView
    elDynAttrSVG "polygon" dAttrs $ return ()

showUnitSquare :: MonadWidget t m => Color -> Float -> Dynamic t (Matrix Float) -> m ()
showUnitSquare faceColor margin dFaceView = 
    showRectangle margin margin (1.0 - margin) (1.0 - margin) faceColor dFaceView

-- show colored square on top of black square for outline effect
showFace :: MonadWidget t m => Color -> Dynamic t (Matrix Float) -> m ()
showFace faceColor dFaceView = do  
    showUnitSquare Black 0 dFaceView
    showUnitSquare faceColor 0.03 dFaceView

facingCamera :: [Float] -> Matrix Float -> Bool
facingCamera viewPoint modelTransform =
    let cross [x0,y0,z0] [x1,y1,z1] = [y0*z1-z0*y1, z0*x1-x0*z1, x0*y1-y0*x1 ] 
        dot v0 v1 = sum $ zipWith (*) v0 v1
        vMinus = zipWith (-) 

        untransformedPoints = fromLists [ [0,0,0,1]   -- lower left 
                                        , [1,0,0,1]   -- lower right 
                                        , [0,1,0,1] ] -- upper left 

        transformedPoints = toLists $ untransformedPoints `multStd2` modelTransform
        pt00 = take 3 $ head transformedPoints         -- transformed lower left
        pt10 = take 3 $ transformedPoints !! 1         -- transformed upper right
        pt01 = take 3 $ transformedPoints !! 2         -- transformed upper left
        
        tVec_10_00 = pt10 `vMinus` pt00                -- lower right to lower left
        tVec_01_00 = pt01 `vMinus` pt00                -- upper left to lower left
        perpendicular = tVec_10_00 `cross` tVec_01_00  -- perpendicular to face
        cameraToPlane = pt00 `vMinus` viewPoint        -- line of sight to face

        -- Perpendicular points away from surface;
        -- Camera vector points towards surface
        -- Opposed vectors means that face will be visible.
    in cameraToPlane `dot` perpendicular < 0

faceView :: Matrix Float -> Matrix Float -> (Bool, Matrix Float)
faceView modelOrientation faceOrientation = 
    let modelTransform =            translation (-1/2,-1/2,1/2) -- unit square to origin + z offset
                         `multStd2` faceOrientation             -- orientation specific to each face
                         `multStd2` scale (1/2)                 -- shrink cube to fit in view.
                         `multStd2` modelOrientation            -- position the entire cube

        
        isFacingCamera = facingCamera [0,0,-1] modelTransform   -- backface elimination

        -- combine to get single transform from 2d face to 2d display
        viewTransform =            modelTransform
                        `multStd2` perspective
                        `multStd2` scale size                       -- scale up to svg box scale
                        `multStd2` translation (size/2, size/2, 0)  -- move to center of svg box

    in (isFacingCamera, viewTransform)

updateFaceViews :: Matrix Float -> Map Color (Matrix Float) -> (Color, Matrix Float) -> Map Color (Matrix Float)
updateFaceViews modelOrientation prevCollection (faceColor, faceOrientation) = 
    let (isVisible, newFaceView) = faceView modelOrientation faceOrientation
    in  if isVisible 
        then insert faceColor newFaceView prevCollection
        else prevCollection

faceViews :: Matrix Float -> Map Color (Matrix Float)
faceViews modelOrientation  =
    foldl (updateFaceViews modelOrientation) empty 
          [ (Purple , xRot (0.0) )  
          , (Yellow , xRot (pi/2) )  
          , (Red    , yRot (pi/2) )  
          , (Green  , xRot (-pi/2) )  
          , (Blue   , yRot (-pi/2) )  
          , (Orange , xRot (pi) )
          ]

viewModel :: MonadWidget t m => Dynamic t (Matrix Float) -> m ()
viewModel modelOrientation = do
    faceMap <- mapDyn faceViews modelOrientation
    listWithKey faceMap showFace
    return ()

view :: MonadWidget t m => Dynamic t (Matrix Float) -> m ()
view modelOrientation = do
    el "h1" $ text "Rotating Cube"
    elDynAttrSVG "svg" 
        (constDyn $  DM.fromList [ ("width",  show size), ("height", show size) ]) 
        $ viewModel modelOrientation

main = mainWidget $ do 
    let initialOrientation = xRot (pi/4) `multStd2` zRot (atan(1/sqrt(2)))
        update _ modelOrientation = modelOrientation `multStd2` (yRot (rotationStep) ) 

    tick <- tickLossy  updateFrequency =<< liftIO getCurrentTime
    rec
        view modelOrientation
        modelOrientation <- foldDyn update initialOrientation tick
    return ()

-- At end because of Rosetta Code handling of unmatched quotes.
elDynAttrSVG a2 a3 a4 = do 
    elDynAttrNS' (Just "http://www.w3.org/2000/svg") a2 a3 a4
    return ()

Link to live demo: https://dc25.github.io/drawRotatingCubeHaskell/

J

Derived from J's qt shader demo:

require'gl2 gles ide/qt/opengl'
coinsert'jgl2 jgles qtopengl'

rotcube=: {{
  if.0=nc<'sprog'do.return.end.
  fixosx=. 'opengl';'opengl',('DARWIN'-:UNAME)#' version 4.1'
  wd 'pc rot; minwh 300 300; cc cube opengl flush' rplc fixosx
  HD=: ".wd 'qhwndc cube'
  wd 'ptimer 17; pshow'
}}

rot_close=: {{
  wd 'ptimer 0'
  glDeleteBuffers ::0: 2; vbo
  glDeleteProgram ::0: sprog
  erase 'sprog'
  wd 'pclose'
}}

cstr=: {{if.y do.memr y,0 _1 2 else.EMPTY end.}}
gstr=: {{cstr>{.glGetString y}}
diag=: {{p[echo y,': ',p=.gstr".y}}

blitf=: {{
  dat=. 1 fc,y NB. short floats
  glBindBuffer GL_ARRAY_BUFFER; x{vbo
  glBufferData GL_ARRAY_BUFFER; (#dat); (symdat<'dat'); GL_STATIC_DRAW
}}

rot_cube_initialize=: {{
  erase'sprog'
  if.0=#diag 'GL_VERSION' do.echo 'cannot retrieve GL_VERSION' return.end.
  diag each;:'GL_VENDOR GL_RENDERER GL_SHADING_LANGUAGE_VERSION'
  GLSL=:wglGLSL''
  wglPROC''
  'err program'=. gl_makeprogram VSRC ;&fixversion FSRC
  if.#err do. echo 'err: ', err return.end.
  if. GLSL>120 do.vao=: >{:glGenVertexArrays 1;,_1 end.
  assert _1~:vertexAttr=: >{.glGetAttribLocation program;'vertex'
  assert _1~:colorAttr=: >{.glGetAttribLocation program;'color'
  assert _1~:mvpUni=: >{.glGetUniformLocation program;'mvp'
  vbo=: >{:glGenBuffers 2;2#_1
  0 blitf vertexData
  1 blitf colorData
  sprog=: program
}}

VSRC=: {{)n
  #version $version
  $v_in $highp vec3 vertex;
  $v_in $lowp vec3 color;
  $v_out $lowp vec4 v_color;
  uniform mat4 mvp;
  void main(void) {
    gl_Position= mvp * vec4(vertex,1.0);
    v_color= vec4(color,1.0);
  }
}}

FSRC=: {{)n
  #version $version
  $f_in $lowp vec4 v_color;
  $fragColor
  void main(void) {
    $gl_fragColor= v_color;
  }
}}

fixversion=: {{
  NB. cope with host shader language version
  r=.   '$version';GLSL,&":;(GLSL>:300)#(*GLES_VERSION){' core';' es'
  f1=. GLSL<:120
  r=.r, '$v_in';f1{'in';'attribute'
  r=.r, '$v_out';f1{'out';'varying'
  r=.r, '$f_in';f1{'in';'varying'
  r=.r, '$highp ';f1#(*GLES_VERSION)#'highp'
  r=.r, '$lowp ';f1#(*GLES_VERSION)#'lowp'
  f2=.(330<:GLSL)+.(300<:GLSL)**GLES_VERSION
  r=.r, '$gl_fragColor';f2{'gl_FragColor';'fragColor'
  r=.r, '$fragColor';f2#'out vec4 fragColor;'
  y rplc r
}}

rot_timer=: {{
  try.
    gl_sel HD
    gl_paint''
  catch.
     echo 'error in rot_timer',LF,13!:12''
     wd'ptimer 0'
  end.
}}

zeroVAttr=: {{
  glEnableVertexAttribArray y
  glBindBuffer GL_ARRAY_BUFFER; x{vbo
  glVertexAttribPointer y; 3; GL_FLOAT; 0; 0; 0
}}

mp=: +/ .*
ref=: (gl_Translate 0 0 _10) mp glu_LookAt 0 0 1,0 0 0,1 0 0
rot_cube_paint=: {{
  try.
    if.nc<'sprog' do.return.end.
    wh=. gl_qwh''
    glClear GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT [glClearColor 0 0 0 0+%3
    glUseProgram sprog
    glEnable each GL_DEPTH_TEST, GL_CULL_FACE, GL_BLEND
    glBlendFunc GL_SRC_ALPHA; GL_ONE_MINUS_SRC_ALPHA
    mvp=. (gl_Rotate (360|60*6!:1''),1 0 0)mp ref mp gl_Perspective 30, (%/wh),1 20
    glUniformMatrix4fv mvpUni; 1; GL_FALSE; mvp 
    if. GLSL>120 do. glBindVertexArray {.vao end.
    0 zeroVAttr vertexAttr
    1 zeroVAttr colorAttr
    glDrawArrays GL_TRIANGLES; 0; 36
    glUseProgram 0
  catch.
    echo 'error in rot_cube_paint',LF,13!:12''
    wd'ptimer 0'
  end.
}}

NB. oriented triangle representation of unit cube
unitCube=:  #:(0 1 2, 2 1 3)&{@".;._2 {{)n
  2 3 0 1 NB. unit cube corner indices
  3 7 1 5 NB. 0: origin
  4 0 5 1 NB. 1, 2, 4: unit distance along each axis
  6 2 4 0 NB. 3, 5, 6, 7:  combinations of axes
  7 6 5 4
  7 3 6 2
}}

NB. orient cube so diagonal is along first axis
daxis=: (_1^5 6 e.~i.3 3)*%:6%~2 0 4,2 3 1,:2 3 1
vertexData=:(_1^unitCube)mp daxis NB. cube with center at origin
colorData=: unitCube NB. corresponding colors

rotcube''

A variation which did not use opengl would probably be much more concise.

Java

import java.awt.*;
import java.awt.event.ActionEvent;
import static java.lang.Math.*;
import javax.swing.*;

public class RotatingCube extends JPanel {
    double[][] nodes = {{-1, -1, -1}, {-1, -1, 1}, {-1, 1, -1}, {-1, 1, 1},
    {1, -1, -1}, {1, -1, 1}, {1, 1, -1}, {1, 1, 1}};

    int[][] edges = {{0, 1}, {1, 3}, {3, 2}, {2, 0}, {4, 5}, {5, 7}, {7, 6},
    {6, 4}, {0, 4}, {1, 5}, {2, 6}, {3, 7}};

    public RotatingCube() {
        setPreferredSize(new Dimension(640, 640));
        setBackground(Color.white);

        scale(100);
        rotateCube(PI / 4, atan(sqrt(2)));

        new Timer(17, (ActionEvent e) -> {
            rotateCube(PI / 180, 0);
            repaint();
        }).start();
    }

    final void scale(double s) {
        for (double[] node : nodes) {
            node[0] *= s;
            node[1] *= s;
            node[2] *= s;
        }
    }

    final void rotateCube(double angleX, double angleY) {
        double sinX = sin(angleX);
        double cosX = cos(angleX);

        double sinY = sin(angleY);
        double cosY = cos(angleY);

        for (double[] node : nodes) {
            double x = node[0];
            double y = node[1];
            double z = node[2];

            node[0] = x * cosX - z * sinX;
            node[2] = z * cosX + x * sinX;

            z = node[2];

            node[1] = y * cosY - z * sinY;
            node[2] = z * cosY + y * sinY;
        }
    }

    void drawCube(Graphics2D g) {
        g.translate(getWidth() / 2, getHeight() / 2);

        for (int[] edge : edges) {
            double[] xy1 = nodes[edge[0]];
            double[] xy2 = nodes[edge[1]];
            g.drawLine((int) round(xy1[0]), (int) round(xy1[1]),
                    (int) round(xy2[0]), (int) round(xy2[1]));
        }

        for (double[] node : nodes) 
            g.fillOval((int) round(node[0]) - 4, (int) round(node[1]) - 4, 8, 8);        
    }

    @Override
    public void paintComponent(Graphics gg) {
        super.paintComponent(gg);
        Graphics2D g = (Graphics2D) gg;
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        drawCube(g);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setTitle("Rotating Cube");
            f.setResizable(false);
            f.add(new RotatingCube(), BorderLayout.CENTER);
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        });
    }
}

JavaScript

Translation of: Java
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <style>
        canvas {
            background-color: black;
        }
    </style>
</head>
<body>
    <canvas></canvas>
    <script>
        var canvas = document.querySelector("canvas");
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        var g = canvas.getContext("2d");

        var nodes = [[-1, -1, -1], [-1, -1, 1], [-1, 1, -1], [-1, 1, 1],
        [1, -1, -1], [1, -1, 1], [1, 1, -1], [1, 1, 1]];

        var edges = [[0, 1], [1, 3], [3, 2], [2, 0], [4, 5], [5, 7], [7, 6],
        [6, 4], [0, 4], [1, 5], [2, 6], [3, 7]];

        function scale(factor0, factor1, factor2) {
            nodes.forEach(function (node) {
                node[0] *= factor0;
                node[1] *= factor1;
                node[2] *= factor2;
            });
        }

        function rotateCuboid(angleX, angleY) {

            var sinX = Math.sin(angleX);
            var cosX = Math.cos(angleX);

            var sinY = Math.sin(angleY);
            var cosY = Math.cos(angleY);

            nodes.forEach(function (node) {
                var x = node[0];
                var y = node[1];
                var z = node[2];

                node[0] = x * cosX - z * sinX;
                node[2] = z * cosX + x * sinX;

                z = node[2];

                node[1] = y * cosY - z * sinY;
                node[2] = z * cosY + y * sinY;
            });
        }

        function drawCuboid() {
            g.save();
            
            g.clearRect(0, 0, canvas.width, canvas.height);
            g.translate(canvas.width / 2, canvas.height / 2);
            g.strokeStyle = "#FFFFFF";
            g.beginPath();

            edges.forEach(function (edge) {
                var p1 = nodes[edge[0]];
                var p2 = nodes[edge[1]];
                g.moveTo(p1[0], p1[1]);
                g.lineTo(p2[0], p2[1]);
            });
            
            g.closePath();
            g.stroke();

            g.restore();
        }

        scale(200, 200, 200);
        rotateCuboid(Math.PI / 4, Math.atan(Math.sqrt(2)));

        setInterval(function() {
            rotateCuboid(Math.PI / 180, 0);
            drawCuboid();
        }, 17);

    </script>

</body>
</html>

Julia

Run at the Julia REPL command line.

using Makie, LinearAlgebra

N = 40
interval = 0.10

scene = mesh(FRect3D(Vec3f0(-0.5), Vec3f0(1)), color = :skyblue2)
rect = scene[end]

for rad in 0.5:1/N:8.5
    arr = normalize([cospi(rad/2), 0, sinpi(rad/2), -sinpi(rad/2)])
    Makie.rotate!(rect, Quaternionf0(arr[1], arr[2], arr[3], arr[4]))
    sleep(interval)
end

Kotlin

Translation of: Java
// version 1.1

import java.awt.*
import javax.swing.*

class RotatingCube : JPanel() {
    private val nodes = arrayOf(
        doubleArrayOf(-1.0, -1.0, -1.0),
        doubleArrayOf(-1.0, -1.0,  1.0),
        doubleArrayOf(-1.0,  1.0, -1.0),
        doubleArrayOf(-1.0,  1.0,  1.0),
        doubleArrayOf( 1.0, -1.0, -1.0),
        doubleArrayOf( 1.0, -1.0,  1.0),
        doubleArrayOf( 1.0,  1.0, -1.0),
        doubleArrayOf( 1.0,  1.0,  1.0)
    )
    private val edges = arrayOf(
        intArrayOf(0, 1),
        intArrayOf(1, 3),
        intArrayOf(3, 2),
        intArrayOf(2, 0),
        intArrayOf(4, 5),
        intArrayOf(5, 7),
        intArrayOf(7, 6),
        intArrayOf(6, 4),
        intArrayOf(0, 4),
        intArrayOf(1, 5),
        intArrayOf(2, 6),
        intArrayOf(3, 7)
    )

    init {
        preferredSize = Dimension(640, 640)
        background = Color.white
        scale(100.0)
        rotateCube(Math.PI / 4.0, Math.atan(Math.sqrt(2.0)))
        Timer(17) {
            rotateCube(Math.PI / 180.0, 0.0)
            repaint()
        }.start()
    }

    private fun scale(s: Double) {
        for (node in nodes) {
            node[0] *= s
            node[1] *= s
            node[2] *= s
        }
    }

    private fun rotateCube(angleX: Double, angleY: Double) {
        val sinX = Math.sin(angleX)
        val cosX = Math.cos(angleX)
        val sinY = Math.sin(angleY)
        val cosY = Math.cos(angleY)
        for (node in nodes) {
            val x = node[0]
            val y = node[1]
            var z = node[2]
            node[0] = x * cosX - z * sinX
            node[2] = z * cosX + x * sinX
            z = node[2]
            node[1] = y * cosY - z * sinY
            node[2] = z * cosY + y * sinY
        }
    }

    private fun drawCube(g: Graphics2D) {
        g.translate(width / 2, height / 2)
        for (edge in edges) {
            val xy1 = nodes[edge[0]]
            val xy2 = nodes[edge[1]]
            g.drawLine(Math.round(xy1[0]).toInt(), Math.round(xy1[1]).toInt(),
                       Math.round(xy2[0]).toInt(), Math.round(xy2[1]).toInt())
        }
        for (node in nodes) {
            g.fillOval(Math.round(node[0]).toInt() - 4, Math.round(node[1]).toInt() - 4, 8, 8)
        }
    }

    override public fun paintComponent(gg: Graphics) {
        super.paintComponent(gg)
        val g = gg as Graphics2D
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
        g.color = Color.blue
        drawCube(g)
    }
}

fun main(args: Array<String>) {
    SwingUtilities.invokeLater {
        val f = JFrame()
        f.defaultCloseOperation = JFrame.EXIT_ON_CLOSE
        f.title = "Rotating cube"
        f.isResizable = false
        f.add(RotatingCube(), BorderLayout.CENTER)
        f.pack()
        f.setLocationRelativeTo(null)
        f.isVisible = true
    }
}

Lua

local abs,atan,cos,floor,pi,sin,sqrt = math.abs,math.atan,math.cos,math.floor,math.pi,math.sin,math.sqrt
local bitmap = {
  init = function(self, w, h, value)
    self.w, self.h, self.pixels = w, h, {}
    for y=1,h do self.pixels[y]={} end
    self:clear(value)
  end,
  clear = function(self, value)
    for y=1,self.h do
      for x=1,self.w do
        self.pixels[y][x] = value or "  "
      end
    end
  end,
  set = function(self, x, y, value)
    x,y = floor(x),floor(y)
    if x>0 and y>0 and x<=self.w and y<=self.h then
      self.pixels[y][x] = value or "#"
    end
  end,
  line = function(self, x1, y1, x2, y2, c)
    x1,y1,x2,y2 = floor(x1),floor(y1),floor(x2),floor(y2)
    local dx, sx = abs(x2-x1), x1<x2 and 1 or -1
    local dy, sy = abs(y2-y1), y1<y2 and 1 or -1
    local err = floor((dx>dy and dx or -dy)/2)
    while(true) do
      self:set(x1, y1, c)
      if (x1==x2 and y1==y2) then break end
      if (err > -dx) then
        err, x1 = err-dy, x1+sx
        if (x1==x2 and y1==y2) then
          self:set(x1, y1, c)
          break
        end
      end
      if (err < dy) then
        err, y1 = err+dx, y1+sy
      end
    end
  end,  
  render = function(self)
    for y=1,self.h do
      print(table.concat(self.pixels[y]))
    end
  end,
}
screen = {
  clear = function()
    os.execute("cls") -- or? os.execute("clear"), or? io.write("\027[2J\027[H"), or etc?
  end,
}
local camera = { fl = 2.5 }
local L = 0.5
local cube = {
  verts = { {L,L,L}, {L,-L,L}, {-L,-L,L}, {-L,L,L}, {L,L,-L}, {L,-L,-L}, {-L,-L,-L}, {-L,L,-L} },
  edges = { {1,2}, {2,3}, {3,4}, {4,1}, {5,6}, {6,7}, {7,8}, {8,5}, {1,5}, {2,6}, {3,7}, {4,8} },
  rotate = function(self, rx, ry)
    local cx,sx = cos(rx),sin(rx)
    local cy,sy = cos(ry),sin(ry)
    for i,v in ipairs(self.verts) do
      local x,y,z = v[1],v[2],v[3]
      v[1], v[2], v[3] = x*cx-z*sx, y*cy-x*sx*sy-z*cx*sy, x*sx*cy+y*sy+z*cx*cy
    end
  end,
}
local renderer = {
  render = function(self, shape, camera, bitmap)
    local fl = camera.fl
    local ox, oy = bitmap.w/2, bitmap.h/2
    local mx, my = bitmap.w/2, bitmap.h/2
    local rpverts = {}
    for i,v in ipairs(shape.verts) do
      local x,y,z = v[1],v[2],v[3]
      local px = ox + mx * (fl*x)/(fl-z)
      local py = oy + my * (fl*y)/(fl-z)
      rpverts[i] = { px,py }
    end
    for i,e in ipairs(shape.edges) do
      local v1, v2 = rpverts[e[1]], rpverts[e[2]]
      bitmap:line( v1[1], v1[2], v2[1], v2[2], "██" )
    end
  end
}
--
bitmap:init(40,40)
cube:rotate(pi/4, atan(sqrt(2)))
for i=1,60 do
  cube:rotate(pi/60,0)
  bitmap:clear("··")
  renderer:render(cube, camera, bitmap)
  screen:clear()
  bitmap:render()
end
Output:
Frame 1:
················································································
······································██········································
····································██████······································
··································████····██····································
································██··██······██··································
······························██····██········██································
····························██······██··········██······························
····························██······██············██····························
··························██······██················██··························
························██········██··················██························
······················██········████····················██······················
····················██········██····██····················██····················
··················██········██········██····················██··················
················██········██············██····················██················
··············██········██················██················████················
··············████····██····················██············██····██··············
············██····████························██········██······██··············
··········██······████··························██····██········██··············
··········██····██····████························████············██············
········██····██··········██······················████············██············
········██··██··············██················████····██··········██············
······██··██··················████··········██··········██··········██··········
······████························██······██··············████······██··········
····████····························██████····················██····██··········
····██································██························██··██··········
··██··································██··························██··██········
····██································██····························████········
······████····························██························████············
··········██··························██······················██················
············████······················██··················████··················
················████··················██··············████······················
····················██················██············██··························
······················████············██········████····························
··························██··········██······██································
····························████······██··████··································
································████··████······································
····································████········································
················································································
················································································
················································································
Frame 60:
················································································
······································██········································
····································██████······································
··································██··██··██····································
······························████····██····████································
····························██········██········██······························
························████··········██··········████··························
····················████··············██··············██························
··················██··················██················██······················
··············████····················██··················████··················
············██························██······················██················
········████··························██························████············
····████······························██····························████········
····████······························██····························████········
······████····························████························████··········
······██··██························██····██····················██··██··········
········██··██····················██········████··············██····██··········
········██····██··············████··············██··········██····██············
········██······██··········██····················██······██······██············
··········██······██······██························██████········██············
··········██········██████····························████······██··············
··········██········████····························██····██····██··············
············██··████····██························██········████················
············████··········████··················██············██················
··············██··············██··············██············██··················
················██··············██··········██············██····················
··················██··············██······██············██······················
····················██··············██████············██························
······················██··············██············██··························
························██············██············██··························
··························██··········██··········██····························
····························██········██········██······························
······························██······██······██································
································██····██····██··································
··································██··██··██····································
····································██████······································
······································██········································
················································································
················································································
················································································

M2000 Interpreter

Cube Example

Draw on M2000 console. Using of GDI+ for smooth lines. Using Every {} structure and Refresh 100 to immediate refresh double buffer, and set 100ms for the next auto refresh. So we erase the screen without refresh and draw again after dt time. Cube has 6 more lines for fancy drawing. Also time displayed. We can move the cube (and accelarate the rotation as we press a mouse button).









Module Cube3D {
	form 80, 32
	smooth on   // enable GDI+ smooth lines
	zoff=0.5773502691896257645091487805019574556@
	cylr=1.6329931618554520654648560498039275946@
	oX=scale.x div 2 : oY=scale.y div 2
	SCALE=min.data(oX, oY)/2*.6
	gradient 0
	theta = 0.0 : dtheta = 1.5 : dt = 1000/60
	ScZof=SCALE/zoff
	ScZofM=SCALE*zoff
	dim cylphi(), x()
	c =(PI/6, 5*PI/6, 3*PI/2, 11*PI/6, PI/2, 7*PI/6) : c*=180/Pi : cylphi()=c // cos() take Degree
	every DT {
		if mouse then (oX, oY)=(mouse.x,mouse.y) : dtheta*=1.05 else dtheta = 1.5
		dim x(6)=oX : for i=0 to 5: x(i) += SCALE*cylr*cos(cylphi(i)+theta):next
		drawcube() : refresh 100 : IF keypress(32) then exit
		theta += dtheta : gradient 0, 5: cursor 0,0
		Print "Press space to exit",,"Press any mouse button to move cube",,Time$(Now)
	}
	sub drawcube()
		for i= 0 to 2
			move x(i), oY-ScZofM:draw to oX,oY-ScZof, 11
			move oX,ScZof+oY:draw to x(i),oY-ScZofM, 9
			move oX,oY+ ScZof:draw to x(5-i),ScZofM+oY
			move x(i),oY-ScZofM:draw to x(i mod 3 + 3),oY+ScZofM, 15
			move oX,oY-ScZof:draw to x(i mod 3 + 3), oY+ScZofM, 7
			move x(i),oY-ScZofM:draw to x((i+1) mod 3 + 3),oY+ScZofM, 13
		next
	end sub
}
Cube3D

Maple

plots:-display( 
    seq( 
        plots:-display( 
            plottools[cuboid]( [0,0,0], [1,1,1] ), 
        axes=none, scaling=constrained, orientation=[0,45,i] ), 
    i = 0..360, 20 ), 
insequence=true );

Mathematica/Wolfram Language

Dynamic[
    Graphics3D[
      GeometricTransformation[
       GeometricTransformation[Cuboid[], RotationTransform[Pi/4, {1, 1, 0}]], 
       RotationTransform[Clock[2 Pi], {0, 0, 1}]
      ], 
      Boxed -> False]]

MiniScript

Works with: Mini Micro
import "mathUtil"
scale = 250
radius = sqrt(scale^2)

Face = new Sprite
Face.image = file.loadImage("/sys/pics/shapes/SquareThin.png")

clear; gfx.clear color.gray
sprites = display(4).sprites

// build a sprite for each side
for i in range(0, 3)	
	sp = new Face
	sp.x = 480; sp.y = 320
	yBot = -sin(pi/4)
	yTop =  sin(pi/4)
	cosAngL = cos(i*pi/2);     sinAngL = sin(i*pi/2)
	cosAngR = cos((i+1)*pi/2); sinAngR = sin((i+1)*pi/2)
	sp.corners3d = [
	 [cosAngL, yBot, sinAngL], [cosAngR, yBot, sinAngR],
	 [cosAngR, yTop, sinAngR], [cosAngL, yTop, sinAngL] ]	
	sp.color = [color.yellow, color.aqua, color.pink, color.lime][i]
	sprites.push sp
end for
// ...and one for the top
top = new Face
top.x = 480; top.y = 320
top.corners3d = []
for i in range(0, 3)
	top.corners3d.push [cos(i*pi/2), sin(pi/4), sin(i*pi/2)]
end for
sprites.push top

// Rotate the given [x,y,z] point by some number of degrees
// around the Y axis, then project to the screen.
rotateAndProject = function(point3d, rotDegrees)
	radians = rotDegrees * pi/180
	cosAng = cos(radians); sinAng = sin(radians)
	// First, rotate around the Y axis in 3D space
	x = point3d[0] * cosAng - point3d[2] * sinAng
	y = point3d[1]
	z = point3d[0] * sinAng + point3d[2] * cosAng
	// Then, project this to the screen
	result = [480 + x * scale, 320 + y * scale + z*0]
	p = (8 - z) / 8  // (perspective factor)
	return mathUtil.lerp2d(result, [480,800], 1-p)
end function

// Position all the sprites where they should be on screen for the given rotation.
positionSprites = function(rotDegrees)
	for sp in sprites
		corners = []
		for i in range(0,3)
			corners.push rotateAndProject(sp.corners3d[i], rotDegrees)
		end for
		sp.setCorners corners
		if sp == top then continue
		if corners[1][0] > corners[0][0] then
			sp.tint = sp.color
		else
			sp.tint = color.clear
		end if
	end for	
end function

// Main program
rot = 0
while not key.pressed("escape") and not key.pressed("q")
	yield
	positionSprites rot
	rot = rot + 1
end while
key.clear
Output:

MiniScript spinning cube solution

Nim

Translation of: Ada
Library: SDL2
import math
import sdl2

const
  Width = 500
  Height = 500
  Offset = 500 / 2

var nodes = [(x: -100.0, y: -100.0, z: -100.0),
             (x: -100.0, y: -100.0, z:  100.0),
             (x: -100.0, y:  100.0, z: -100.0),
             (x: -100.0, y:  100.0, z:  100.0),
             (x:  100.0, y: -100.0, z: -100.0),
             (x:  100.0, y: -100.0, z:  100.0),
             (x:  100.0, y:  100.0, z:  -100.0),
             (x:  100.0, y:  100.0, z:   100.0)]

const Edges = [(a: 0, b: 1), (a: 1, b: 3), (a: 3, b: 2), (a: 2, b: 0),
               (a: 4, b: 5), (a: 5, b: 7), (a: 7, b: 6), (a: 6, b: 4),
               (a: 0, b: 4), (a: 1, b: 5), (a: 2, b: 6), (a: 3, b: 7)]

var
  window: WindowPtr
  renderer: RendererPtr
  event: Event
  endSimulation = false

#---------------------------------------------------------------------------------------------------

proc rotateCube(angleX, angleY: float) =
  let
    sinX = sin(angleX)
    cosX = cos(angleX)
    sinY = sin(angleY)
    cosY = cos(angleY)

  for node in nodes.mitems:
    var (x, y, z) = node
    node.x = x * cosX - z * sinX
    node.z = z * cosX + x * sinX
    z = node.z
    node.y = y * cosY - z * sinY
    node.z = z * cosY + y * sinY

#---------------------------------------------------------------------------------------------------

proc pollQuit(): bool =
  while pollEvent(event):
    if event.kind == QuitEvent:
      return true

#---------------------------------------------------------------------------------------------------

proc drawCube(): bool =
  var rect: Rect = (cint(0), cint(0), cint(Width), cint(Height))
  rotateCube(PI / 4, arctan(sqrt(2.0)))
  for frame in 0..359:
    renderer.setDrawColor((0u8, 0u8, 0u8, 255u8))
    renderer.fillRect(addr(rect))
    renderer.setDrawColor((0u8, 220u8, 0u8, 255u8))
    for edge in Edges:
      let xy1 = nodes[edge.a]
      let xy2 = nodes[edge.b]
      renderer.drawLine(cint(xy1.x + Offset), cint(xy1.y + Offset),
                        cint(xy2.x + Offset), cint(xy2.y + Offset))
    rotateCube(PI / 180, 0)
    renderer.present()
    if pollQuit(): return true
    delay 10

#———————————————————————————————————————————————————————————————————————————————————————————————————

if sdl2.init(INIT_EVERYTHING) == SdlError:
  quit(QuitFailure)

window = createWindow("Rotating cube", 10, 10, 500, 500, 0)
renderer = createRenderer(window, -1, Renderer_Accelerated)

while not endSimulation:
  endSimulation = drawCube()
window.destroy()

Objeck

Library: SDL2
Translation of: Ada
#~
Rotating Cube
~#

use Collection.Generic;
use Game.SDL2;
use Game.Framework;

class RotatingCube {
  # game framework
  @framework : GameFramework;
  @initialized : Bool;

  @nodes : Float[,];
  @edges : Int[,];

  New() {
    @initialized := true;
    @framework := GameFramework->New(GameConsts->SCREEN_WIDTH, GameConsts->SCREEN_HEIGHT, "Rotating Cube");

    @nodes := [[-100.0, -100.0, -100.0], [-100.0, -100.0, 100.0], [-100.0, 100.0, -100.0],
       [-100.0, 100.0, 100.0],   [100.0, -100.0, -100.0], [100.0, -100.0, 100.0],
       [100.0, 100.0, -100.0],   [100.0, 100.0, 100.0]];

        @edges := [[0, 1], [1, 3], [3, 2], [2, 0], [4, 5], [5, 7],
           [7, 6], [6, 4], [0, 4], [1, 5], [2, 6], [3, 7]];

  }

  function : Main(args : String[]) ~ Nil {
    RotatingCube->New()->Play();
  }

  method : Play() ~ Nil {
    if(@initialized) {
      # initialization
      @framework->SetClearColor(Color->New(0, 0, 0));
      RotateCube(Float->Pi(), 2.0->SquareRoot()->ArcTan());

      quit := false;
      e := @framework->GetEvent();
      while(<>quit) {
        @framework->FrameStart();
        @framework->Clear();
        
        # process input
        while(e->Poll() <> 0) {
          if(e->GetType() = EventType->SDL_QUIT) {
            quit := true;
          };
        };

        #draw
        DrawCube();

        @framework->FrameEnd();

        # render
        @framework->Show();

        Timer->Delay(200);

        RotateCube (Float->Pi() / 180.0, 0.0);
      };
    }
    else {
      "--- Error Initializing Environment ---"->ErrorLine();
      return;
    };

    leaving {
      @framework->FreeShapes();
    };
  }

  method : RotateCube(angleX : Float, angleY : Float) ~ Nil {
    sinX := angleX->Sin();
        cosX := angleX->Cos();
 
        sinY := angleY->Sin();
        cosY := angleY->Cos();
 
    node_sizes := @nodes->Size();
    size := node_sizes[0];

        for(i := 0; i < size; i += 1;) {
            x := @nodes[i, 0];
            y := @nodes[i, 1];
            z := @nodes[i, 2];
 
            @nodes[i, 0] := x * cosX - z * sinX;
            @nodes[i, 2] := z * cosX + x * sinX;
 
            z := @nodes[i, 2];
 
            @nodes[i, 1] := y * cosY - z * sinY;
            @nodes[i, 2] := z * cosY + y * sinY;
        }; 
  }

  method : DrawCube() ~ Nil {
    edge_sizes := @edges->Size();
    size := edge_sizes[0];

    @framework->GetRenderer()->SetDrawColor(0, 220, 0, 0);
    for(i := 0; i < size; i += 1;) {
      x0y0  := @nodes[@edges[i, 0], 0];
      x0y1  := @nodes[@edges[i, 0], 1];

      x1y0  := @nodes[@edges[i, 1], 0];
      x1y1  := @nodes[@edges[i, 1], 1];

      @framework->GetRenderer()->DrawLine(x0y0 + GameConsts->DRAW_OFFSET, x0y1 + GameConsts->DRAW_OFFSET, x1y0 + GameConsts->DRAW_OFFSET, x1y1 + GameConsts->DRAW_OFFSET);
    };
  }
}

consts GameConsts {
  SCREEN_WIDTH := 600,
  SCREEN_HEIGHT := 600,
  DRAW_OFFSET := 300
}

OxygenBasic

Using An OpenGl-based console

  % Title "Rotating Cube"
  % Animated
  % PlaceCentral
  uses ConsoleG

  sub main
  ========
  cls 0.0, 0.5, 0.7
  shading
  scale 7
  pushstate
    GoldMaterial.act
    static float ang
    rotateX ang
    rotateY ang
    go cube
  popstate
  ang+=.5 : if ang>=360 then ang-=360
  end sub

  EndScript

Perl

#!/usr/bin/perl

use strict;              # http://www.rosettacode.org/wiki/Draw_a_rotating_cube
use warnings;
use Tk;
use Time::HiRes qw( time );

my $size = 600;
my $wait = int 1000 / 30;
my ($height, $width) = ($size, $size * sqrt 8/9);
my $mid = $width / 2;
my $rot = atan2(0, -1) / 3;                   # middle corners every 60 degrees

my $mw = MainWindow->new;
my $c = $mw->Canvas(-width => $width, -height => $height)->pack;
$c->Tk::bind('<ButtonRelease>' => sub {$mw->destroy});          # click to exit
draw();
MainLoop;

sub draw
  {
  my $angle = time - $^T;                    # full rotation every 2*PI seconds
  my @points = map { $mid + $mid * cos $angle + $_ * $rot,
    $height * ($_ % 2 + 1) / 3 } 0 .. 5;
  $c->delete('all');
  $c->createLine( @points[-12 .. 1], $mid, 0, -width => 5,);
  $c->createLine( @points[4, 5], $mid, 0, @points[8, 9], -width => 5,);
  $c->createLine( @points[2, 3], $mid, $height, @points[6, 7], -width => 5,);
  $c->createLine( $mid, $height, @points[10, 11], -width => 5,);
  $mw->after($wait, \&draw);
  }

Phix

Library: Phix/pGUI
Library: Phix/online

You can run this online here.

--
-- demo\rosetta\DrawRotatingCube.exw
-- =================================
--
-- credits: http://petercollingridge.appspot.com/3D-tutorial/rotating-objects
--          https://github.com/ssloy/tinyrenderer/wiki/Lesson-4:-Perspective-projection
--
-- Aside: low CPU usage, at least when using a 30ms timer (33 FPS, which is plenty).
--
with javascript_semantics
include pGUI.e

constant title = "Draw a Rotating Cube"
Ihandle dlg, canvas
cdCanvas cd_canvas

--
-- First, define 8 corners equidistant from {0,0,0}:
--
--          6-----2
--      5-----1   3
--      8-----4  
--
-- ie the right face is 1-2-3-4 clockwise, and the left face
--  is 5-6-7-8 counter-clockwise (unless using x-ray vision).
-- (since this is not drawing textures, clockwise-ness does 
--  not matter, as shown by the corrected orange face, but
--  it will if you (figure out how to) apply any textures.)
-- (a quick (online) study of opengl texture documentation
--  should convince you that stuff is best left to opengl.)
--
enum X, Y, Z
constant l = 100
constant corners = {{+l,+l,+l},     -- 1 (front top right)
                    {+l,+l,-l},     -- 2 (back top "right")
                    {+l,-l,-l},     -- 3 (back btm "right")
                    {+l,-l,+l},     -- 4 (front btm right)
                    {-l,+l,+l},     -- 5 (front top left)
                    {-l,+l,-l},     -- 6 (back top "left")
                    {-l,-l,-l},     -- 7 (back btm "left")
                    {-l,-l,+l}}     -- 8 (front btm left)
-- I put left/right in quotes for the back face as a reminder
-- those match the above diagram, but of course they would be
-- swapped were you looking "at" the face/rotated it by 180.

constant faces = {{CD_RED,          1,2,3,4},   -- right
                  {CD_YELLOW,       1,5,6,2},   -- top
                  {CD_DARK_GREEN,   1,4,8,5},   -- front
                  {CD_BLUE,         2,3,7,6},   -- back
                  {CD_WHITE,        3,4,8,7},   -- bottom
--                {CD_ORANGE,       5,6,7,8}}   -- left
                  {CD_ORANGE,       8,7,6,5}}   -- left

-- rotation angles, 0..359, on a timer
atom rx = 45,   -- initially makes cube like a H
     ry = 35,   --     "	   "    "	italic H
     rz = 0

constant naxes = {{Y,Z},    -- (rotate about the X-axis)
                  {X,Z},    -- (rotate about the Y-axis)
                  {X,Y}}    -- (rotate about the Z-axis)

function rotate(sequence points, atom angle, integer axis)
--
-- rotate points by the specified angle about the given axis
--
    atom radians = angle*CD_DEG2RAD,
         sin_t = sin(radians),
         cos_t = cos(radians)
    integer {nx,ny} = naxes[axis]
    for i=1 to length(points) do
        atom x = points[i][nx],
             y = points[i][ny]
        points[i][nx] = x*cos_t - y*sin_t
        points[i][ny] = y*cos_t + x*sin_t
    end for
    return points
end function

function projection(sequence points, atom d)
--
-- project points from {0,0,d} onto the perpendicular plane through {0,0,0}
--
    for i=1 to length(points) do
        atom {x,y,z} = points[i],
             denom = (1-z/d)
        points[i][X] = x/denom
        points[i][Y] = y/denom
    end for
    return points
end function

function nearest(sequence points)
--
-- return the index of the nearest point (highest z value)
--
    return largest(vslice(points,Z),true)
end function

procedure draw_cube(integer cx, cy)
    -- {cx,cy} is the centre point of the canvas
    sequence points = deep_copy(corners)
    points = rotate(points,rx,X)
    points = rotate(points,ry,Y)
    points = rotate(points,rz,Z)
    points = projection(points,1000)
    integer np = nearest(points)
    --
    -- find the three faces that contain the nearest point,
    -- then for each of those faces let diag be the point
    -- that is diagonally opposite said nearest point, and
    -- order by/draw those faces furthest diag away first.
    --  (one or two of them may be completely obscured due 
    --   to the effects of the perspective projection.)
    --  (you could of course draw all six faces, as long as
    --   the 3 furthest are draw first/obliterated, which
    --   is what that commented-out "else" would achieve.)
    --
    sequence faceset = {}
    for i=1 to length(faces) do
        sequence fi = faces[i]
        integer k = find(np,fi)       -- k:=2..5, or 0
        if k then
            integer diag = mod(k,4)+2 -- {2,3,4,5} --> {4,5,2,3}
                                      -- aka swap 2<=>4 & 3<=>5
            diag = fi[diag] -- 1..8, diagonally opp. np
            faceset = append(faceset,{points[diag][Z],i})
--      else
--          faceset = append(faceset,{-9999,i})
        end if
    end for
    faceset = sort(faceset)
    for i=1 to length(faceset) do
        sequence face = faces[faceset[i][2]]
        cdCanvasSetForeground(cd_canvas,face[1])
        -- first fill sides (with bresenham edges), then
        -- redraw edges, but anti-aliased aka smoother
        sequence modes = {CD_FILL,CD_CLOSED_LINES}
        for m=1 to length(modes) do
            cdCanvasBegin(cd_canvas,modes[m])
            for fdx=2 to 5 do
                sequence pt = points[face[fdx]]
                cdCanvasVertex(cd_canvas,cx+pt[X],cy-pt[Y])
            end for
            cdCanvasEnd(cd_canvas)
        end for
    end for
end procedure

function canvas_action_cb(Ihandle canvas)
    cdCanvasActivate(cd_canvas)
    cdCanvasClear(cd_canvas)
    integer {w, h} = IupGetIntInt(canvas, "DRAWSIZE")
    draw_cube(floor(w/2),floor(h/2))
    cdCanvasFlush(cd_canvas)
    return IUP_DEFAULT
end function

function canvas_map_cb(Ihandle canvas)
    IupGLMakeCurrent(canvas)
    if platform()=JS then
        cd_canvas = cdCreateCanvas(CD_IUP, canvas)
    else
        atom res = IupGetDouble(NULL, "SCREENDPI")/25.4
        cd_canvas = cdCreateCanvas(CD_GL, "10x10 %g", {res})
    end if
    cdCanvasSetBackground(cd_canvas, CD_PARCHMENT)
    return IUP_DEFAULT
end function

function canvas_resize_cb(Ihandle /*canvas*/)
    integer {canvas_width, canvas_height} = IupGetIntInt(canvas, "DRAWSIZE")
    atom res = IupGetDouble(NULL, "SCREENDPI")/25.4
    cdCanvasSetAttribute(cd_canvas, "SIZE", "%dx%d %g", {canvas_width, canvas_height, res})
    return IUP_DEFAULT
end function

function timer_cb(Ihandln /*ih*/)
    -- (feel free to add a bit more randomness here, maybe)
    rx = mod(rx+359,360)
    ry = mod(ry+359,360)
    rz = mod(rz+359,360)
    IupRedraw(canvas)
    return IUP_IGNORE
end function

procedure main()
    IupOpen()
    canvas = IupGLCanvas("RASTERSIZE=640x480")
    IupSetCallbacks(canvas, {"ACTION", Icallback("canvas_action_cb"),
                             "MAP_CB", Icallback("canvas_map_cb"),
                             "RESIZE_CB", Icallback("canvas_resize_cb")})
    dlg = IupDialog(canvas,`TITLE="%s"`,{title})
    IupShow(dlg)
    IupSetAttribute(canvas, "RASTERSIZE", NULL)
    Ihandle hTimer = IupTimer(Icallback("timer_cb"), 30)
    if platform()!=JS then
        IupMainLoop()
        IupClose()
    end if
end procedure

main()

PostScript

Don't send this to your printer!

%!PS-Adobe-3.0
%%BoundingBox: 0 0 400 400

/ed { exch def } def
/roty { dup sin /s ed cos /c ed [[c 0 s neg] [0 1 0] [s 0 c]] } def
/rotz { dup sin /s ed cos /c ed [[c s neg 0] [s c 0] [0 0 1]] } def
/dot { /a ed /b ed
	a 0 get b 0 get mul
	a 1 get b 1 get mul
	a 2 get b 2 get mul
	add add } def

/mmul {	/v ed [exch {v dot} forall] } def
/transall { /m ed [exch {m exch mmul}forall] } def

/vt
	[[1  1  1] [-1  1  1]
	 [1 -1  1] [-1 -1  1]
	 [1  1 -1] [-1  1 -1]
	 [1 -1 -1] [-1 -1 -1]]
	-45 roty transall
	2 sqrt 1 atan rotz transall
def

/xy { exch get {} forall pop } def
/page {
	/a ed /v vt a roty transall def
	0 setlinewidth 100 100 scale 2 2 translate
	/edge { v xy moveto v xy lineto stroke } def

	0 1 2 3 4 5 6 7 0 2 1 3 4 6 5 7 0 4 1 5 2 6 3 7
	1 1 12 { pop edge } for
	showpage
} def

0 {3.2 add dup page } loop
%%EOF

Processing

Create a cube in Processing with box(), rotate the scene with rotate(), and drive the rotation with either the built-in millis() or frameCount timers.

void setup() {
  size(500, 500, P3D);
}
void draw() {
  background(0);
  // position
  translate(width/2, height/2, -width/2);
  // optional fill and lighting colors
  noStroke();
  strokeWeight(4);
  fill(192, 255, 192);
  pointLight(255, 255, 255, 0, -500, 500);
  // rotation driven by built-in timer
  rotateY(millis()/1000.0);
  // draw box
  box(300, 300, 300);
}

Python

Library: VPython

Works with: Python version 2.7.9

See also: Draw_a_cuboid

Short version

from visual import *
scene.title = "VPython: Draw a rotating cube"

scene.range = 2
scene.autocenter = True

print "Drag with right mousebutton to rotate view."
print "Drag up+down with middle mousebutton to zoom."

deg45 = math.radians(45.0)  # 0.785398163397

cube = box()    # using defaults, see http://www.vpython.org/contents/docs/defaults.html 
cube.rotate( angle=deg45, axis=(1,0,0) )
cube.rotate( angle=deg45, axis=(0,0,1) )

while True:                 # Animation-loop
    rate(50)
    cube.rotate( angle=0.005, axis=(0,1,0) )


Racket

#lang racket/gui
(require math/matrix math/array)

(define (Rx θ)
  (matrix [[1.0    0.0        0.0]
           [0.0 (cos θ) (- (sin θ))]
           [0.0 (sin θ)    (cos θ)]]))

(define (Ry θ)
  (matrix [[   (cos θ)  0.0 (sin θ)]
           [      0.0   1.0    0.0 ]
           [(- (sin θ)) 0.0 (cos θ)]]))

(define (Rz θ)
  (matrix [[(cos θ) (- (sin θ)) 0.0]
           [(sin θ)    (cos θ)  0.0]
           [   0.0        0.0   1.0]]))

(define base-matrix
  (matrix* (identity-matrix 3 100.0)
           (Rx (- (/ pi 2) (atan (sqrt 2))))
           (Rz (/ pi 4.0))))

(define (current-matrix)
  (matrix* (Ry (/ (current-inexact-milliseconds) 1000.))
           base-matrix))

(define corners 
  (for*/list ([x '(-1.0 1.0)]
              [y '(-1.0 1.0)]
              [z '(-1.0 1.0)])
    (matrix [[x] [y] [z]])))

(define lines 
  '((0 1) (0 2) (0 4) (1 3) (1 5)
    (2 3) (2 6) (3 7) (4 5) (4 6)
    (5 7) (6 7)))

(define ox 200.)
(define oy 200.)

(define (draw-line dc a b)
  (send dc draw-line
        (+ ox (array-ref a #(0 0)))
        (+ oy (array-ref a #(1 0)))
        (+ ox (array-ref b #(0 0)))
        (+ oy (array-ref b #(1 0)))))

(define (draw-cube c dc)
  (define-values (w h) (send dc get-size))
  (set! ox (/ w 2))
  (set! oy (/ h 2))
  (define cs (for/vector ([c (in-list corners)]) 
               (matrix* (current-matrix) c)))
  (for ([l (in-list lines)])
    (match-define (list i j) l)
    (draw-line dc (vector-ref cs i) (vector-ref cs j))))

(define f (new frame%  [label "cube"]))
(define c (new canvas% [parent f] [min-width 400] [min-height 400] [paint-callback draw-cube]))
(send f show #t)

(send* (send c get-dc)
  (set-pen "black" 1 'solid)
  (set-smoothing 'smoothed))

(define (refresh)
  (send c refresh))

(define t (new timer% [notify-callback refresh] [interval 35] [just-once? #f]))

Raku

(formerly Perl 6)

Works with: Rakudo version 2018.12

Raku has no native graphics libraries built in, but makes it fairly easy to bind to third party libraries. Here we'll use bindings to Libcaca, the Color ASCII Art library to generate a rotating cube in an ASCII terminal.

use Terminal::Caca;
given my $canvas = Terminal::Caca.new {
    .title('Rosetta Code - Rotating cube - Press any key to exit');

    sub scale-and-translate($x, $y, $z) {
        $x * 5 / ( 5 + $z ) * 15 + 40,
        $y * 5 / ( 5 + $z ) *  7 + 15,
        $z;
    }

    sub rotate3d-x( $x, $y, $z, $angle ) {
        my ($cosθ, $sinθ) = cis( $angle * π / 180.0 ).reals;
        $x,
        $y * $cosθ - $z * $sinθ,
        $y * $sinθ + $z * $cosθ;
    }

    sub rotate3d-y( $x, $y, $z, $angle ) {
        my ($cosθ, $sinθ) = cis( $angle * π / 180.0 ).reals;
        $x * $cosθ - $z * $sinθ,
        $y,
        $x * $sinθ + $z * $cosθ;
    }

    sub rotate3d-z( $x, $y, $z, $angle ) {
        my ($cosθ, $sinθ) = cis( $angle * π / 180.0 ).reals;
        $x * $cosθ - $y * $sinθ,
        $x * $cosθ + $y * $sinθ,
        $z;
    }

    # Unit cube from polygon mesh, aligned to axes
    my @mesh =
      [ [1, 1, -1], [-1, -1, -1], [-1,  1, -1] ], # far face
      [ [1, 1, -1], [-1, -1, -1], [ 1, -1, -1] ],
      [ [1, 1,  1], [-1, -1,  1], [-1,  1,  1] ], # near face
      [ [1, 1,  1], [-1, -1,  1], [ 1, -1,  1] ];
      @mesh.push: [$_».rotate( 1)».Array] for @mesh[^4]; # positive and
      @mesh.push: [$_».rotate(-1)».Array] for @mesh[^4]; # negative rotations

    # Rotate to correct orientation for task
    for ^@mesh X ^@mesh[0] -> ($i, $j) {
        @(@mesh[$i;$j]) = rotate3d-x |@mesh[$i;$j], 45;
        @(@mesh[$i;$j]) = rotate3d-z |@mesh[$i;$j], 40;
    }

    my @colors = red, blue, green, cyan, magenta, yellow;

    loop {
        for ^359 -> $angle {
            .color( white, white );
            .clear;

            # Flatten 3D into 2D and rotate for all faces
            my @faces-z;
            my $c-index = 0;
            for @mesh -> @triangle {
                my @points;
                my $sum-z = 0;
                for @triangle -> @node {
                    my ($px, $py, $z) = scale-and-translate |rotate3d-y |@node, $angle;
                    @points.append: $px.Int, $py.Int;
                    $sum-z += $z;
                }

                @faces-z.push: %(
                    color  => @colors[$c-index++ div 2],
                    points => @points,
                    avg-z  => $sum-z / +@points;
                );
            }

            # Draw all faces
            # Sort by z to draw farthest first
            for @faces-z.sort( -*.<avg-z> ) -> %face {
                # Draw filled triangle
                .color( %face<color>, %face<color> );
                .fill-triangle( |%face<points> );
                # And frame
                .color( black, black );
                .thin-triangle( |%face<points> );
            }

            .refresh;
            exit if .wait-for-event(key-press);
        }
    }

    # Cleanup on scope exit
    LEAVE {
        .cleanup;
    }
}

Ring

#===================================================================#
# Based on Original Sample from RayLib (https://www.raylib.com/)
# Ported to RingRayLib by Ring Team
#===================================================================#

load "raylib.ring"

screenWidth = 800
screenHeight = 450

InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d picking")

camera = Camera3D(
	10, 10, 10,
	0, 0, 0 ,
	0, 1, 0 ,
	45,
	CAMERA_PERSPECTIVE
)

cubePosition = Vector3( 0, 1, 0 )
cubeSize = Vector3( 2, 2, 2 )

ray = Ray(0,0,0,0,0,0)

collision = false

SetCameraMode(camera, CAMERA_FREE) 

SetTargetFPS(60)

while !WindowShouldClose()

        UpdateCamera(camera)

        if IsMouseButtonPressed(MOUSE_LEFT_BUTTON)
            if !collision
                ray = GetMouseRay(GetMousePosition(), camera)

                collision = CheckCollisionRayBox(ray,
 		BoundingBox( cubePosition.x - cubeSize.x/2, cubePosition.y - cubeSize.y/2, cubePosition.z - cubeSize.z/2,
    		cubePosition.x + cubeSize.x/2, cubePosition.y + cubeSize.y/2, cubePosition.z + cubeSize.z/2 ) )
            else collision = false
 	    ok
	ok

        BeginDrawing()

            ClearBackground(RAYWHITE)

            BeginMode3D(camera)

                if collision
                    DrawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, RED)
                    DrawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, MAROON)

                    DrawCubeWires(cubePosition, cubeSize.x + 0.2f, cubeSize.y + 0.2f, cubeSize.z + 0.2f, GREEN)
                else
                    DrawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, GRAY)
                    DrawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, DARKGRAY)
                ok

                DrawRay(ray, MAROON)
                DrawGrid(10, 1)

            EndMode3D()

            DrawText("Try selecting the box with mouse!", 240, 10, 20, DARKGRAY)

            if collision  DrawText("BOX SELECTED", (screenWidth - MeasureText("BOX SELECTED", 30)) / 2, screenHeight * 0.1f, 30, GREEN) ok

            DrawFPS(10, 10)

        EndDrawing()
end

CloseWindow()

Rotating a Cube

Scala

Java Swing Interoperability

Works with: Scala version 2.13
import java.awt.event.ActionEvent
import java.awt._

import javax.swing.{JFrame, JPanel, Timer}

import scala.math.{Pi, atan, cos, sin, sqrt}

object RotatingCube extends App {

  class RotatingCube extends JPanel {
    private val vertices: Vector[Array[Double]] =
      Vector(Array(-1, -1, -1), Array(-1, -1, 1), Array(-1, 1, -1),
        Array(-1, 1, 1), Array(1, -1, -1), Array(1, -1, 1), Array(1, 1, -1), Array(1, 1, 1))

    private val edges: Vector[(Int, Int)] =
      Vector((0, 1), (1, 3), (3, 2), (2, 0), (4, 5), (5, 7),
        (7, 6), (6, 4), (0, 4), (1, 5), (2, 6), (3, 7))

    setPreferredSize(new Dimension(640, 640))
    setBackground(Color.white)
    scale(100)
    rotateCube(Pi / 4, atan(sqrt(2)))

    new Timer(17, (_: ActionEvent) => {
      rotateCube(Pi / 180, 0)
      repaint()
    }).start()

    override def paintComponent(gg: Graphics): Unit = {
      def drawCube(g: Graphics2D): Unit = {
        g.translate(getWidth / 2, getHeight / 2)
        for {edge <- edges
             xy1: Array[Double] = vertices(edge._1)
             xy2: Array[Double] = vertices(edge._2)
             } {
          g.drawLine(xy1(0).toInt, xy1(1).toInt, xy2(0).toInt, xy2(1).toInt)
          g.fillOval(xy1(0).toInt -4, xy1(1).toInt - 4, 8, 8)
          g.setColor(Color.black)
        }
      }

      super.paintComponent(gg)
      val g: Graphics2D = gg.asInstanceOf[Graphics2D]
      g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
      drawCube(g)
    }

    private def scale(s: Double): Unit = {
      for {node <- vertices
           i <- node.indices
           } node(i) *= s
    }

    private def rotateCube(angleX: Double, angleY: Double): Unit = {
      def sinCos(x: Double) = (sin(x), cos(x))

      val ((sinX, cosX), (sinY, cosY)) = (sinCos(angleX), sinCos(angleY))

      for {
        node <- vertices
        x: Double = node(0)
        y: Double = node(1)
      } {
        def f(p: Double, q: Double)(a: Double, b: Double) = a * p + b * q

        def fx(a: Double, b: Double) = f(cosX, sinX)(a, b)

        def fy(a: Double, b: Double) = f(cosY, sinY)(a, b)

        node(0) = fx(x, -node(2))
        val z = fx(node(2), x)
        node(1) = fy(y, -z)
        node(2) = fy(z, y)
      }
    }

  }

  new JFrame("Rotating Cube") {
    add(new RotatingCube(), BorderLayout.CENTER)
    pack()
    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE)
    setLocationRelativeTo(null)
    setResizable(false)
    setVisible(true)
  }

}

Tcl

See also Draw a cuboid. This implementation uses tcllib's Linear Algebra module for some matrix ops to handle the screen transform and (animated!) rotation. Rendering is in a Tk canvas.

The *Matrix* procedure is something unique to Tcl: it's essentially a control construct that leverages *expr* to make declaring matrices much more convenient than hand-rolling lists.

There is a bit of wander in the top and bottom points, which might just be due to rounding error in the cube's initial "rotation into position".

See this wiki page (and others linked from it) for many similar examples.

# matrix operation support:
package require math::linearalgebra
namespace import ::math::linearalgebra::matmul
namespace import ::math::linearalgebra::crossproduct
namespace import ::math::linearalgebra::dotproduct
namespace import ::math::linearalgebra::sub

# returns a cube as a list of faces,
# where each face is a list of (3space) points
proc make_cube {{radius 1}} {
    set dirs {
        A { 1  1  1}
        B { 1  1 -1}
        C { 1 -1 -1}
        D { 1 -1  1}
        E {-1  1  1}
        F {-1  1 -1}
        G {-1 -1 -1}
        H {-1 -1  1}
    }
    set faces {
        {A B C D}
        {D C G H}
        {H G F E}
        {E F B A}
        {A D H E}
        {C B F G}
    }
    lmap fa $faces {
        lmap dir $fa {
            lmap x [dict get $dirs $dir] {
                expr {1.0 * $x * $radius}
            }
        }
    }
}

# a matrix constructor
proc Matrix {m} {
    tailcall lmap row $m {
        lmap e $row {
            expr 1.0*($e)
        }
    }
}

proc identity {} {
    Matrix {
        {1 0 0}
        {0 1 0}
        {0 0 1}
    }
}

# some matrices useful for animation:
proc rotateZ {theta} {
    Matrix {
        { cos($theta) -sin($theta)  0 }
        { sin($theta)  cos($theta)  0 }
        { 0            0            1 }
    }
}
proc rotateY {theta} {
    Matrix {
        { sin($theta)  0  cos($theta) }
        { 0            1            0 }
        { cos($theta)  0 -sin($theta) }
    }
}
proc rotateX {theta} {
    Matrix {
        { 1            0            0 }
        { 0  cos($theta) -sin($theta) }
        { 0  sin($theta)  cos($theta) }
    }
}

proc camera {flen} {
    Matrix {
        { $flen  0      0 }
        { 0      $flen  0 }
        { 0      0      0 }
    }
}

proc render {canvas object} {

    set W   [winfo width  $canvas]
    set H   [winfo height $canvas]

    set fl  1.0
    set t   [expr {[clock microseconds] / 1000000.0}]

    set transform [identity]
    set transform [matmul $transform [rotateX [expr {atan(1)}]]]
    set transform [matmul $transform [rotateZ [expr {atan(1)}]]]

    set transform [matmul $transform [rotateY $t]]
    set transform [matmul $transform [camera $fl]]

    foreach face $object {
        # do transformations into screen space:
        set points [lmap p $face { matmul $p $transform }]
        # calculate a normal
        set o       [lindex $points 0]
        set v1 [sub [lindex $points 1] $o]
        set v2 [sub [lindex $points 2] $o]
        set normal [crossproduct $v1 $v2]

        set cosi   [dotproduct $normal {0 0 -1.0}]
        if {$cosi <= 0} { ;# rear-facing!
            continue
        }

        set points [lmap p $points {
            lassign $p x y
            list [expr {$x + $W/2}] [expr {$y + $H/2}]
        }]
        set points [concat {*}$points]
        $canvas create poly $points -outline black -fill red
    }
}

package require Tk
pack [canvas .c] -expand yes -fill both 

proc tick {} {
    .c delete all
    render .c $::world
    after 50 tick
}
set ::world [make_cube 100]
tick

TI-83 BASIC

:-1→Xmin:1→Xmax
:-1→Ymin:1→Ymax
:AxesOff
:Degrees
:While 1
:For(X,0,359,5
:sin(X-120→I%
:sin(X→PV
:sin(X+120→FV
:Line(0,1,I%,.3
:Line(0,1,PV,.3
:Line(0,1,FV,.3
:Line(0,-1,-I%,-.3
:Line(0,-1,-PV,-.3
:Line(0,-1,-FV,-.3
:Line(.3,I%,-.3,-PV
:Line(.3,I%,-.3,-FV
:Line(.3,PV,-.3,-I%
:Line(.3,PV,-.3,-FV
:Line(.3,FV,-.3,-I%
:Line(.3,FV,-.3,-PV
:End
:End

I%, PV, and FV are all finance variables that can be found in the finance menu (inside the APPS menu on TI-83+ and up). Finance variables are much faster than normal variables.

Wren

Translation of: Kotlin
Library: DOME
import "graphics" for Canvas, Color
import "dome" for Window
import "math" for Math

var Nodes = [
    [-1, -1, -1],
    [-1, -1,  1],
    [-1,  1, -1],
    [-1,  1,  1],
    [ 1, -1, -1],
    [ 1, -1,  1],
    [ 1,  1, -1],
    [ 1,  1,  1]
]

var Edges = [
    [0, 1],
    [1, 3],
    [3, 2],
    [2, 0],
    [4, 5],
    [5, 7],
    [7, 6],
    [6, 4],
    [0, 4],
    [1, 5],
    [2, 6],
    [3, 7]
]

class RotatingCube {
    construct new(width, height) {
        Window.title = "Rotating cube"
        Window.resize(width, height)
        Canvas.resize(width, height)
        _width = width
        _height = height
        _fore = Color.blue
    }

    init() {
        scale(100)
        rotateCube(Num.pi / 4, Math.atan(2.sqrt))
        drawCube()
    }

    update() {
        rotateCube(Num.pi / 180, 0)
    }

    draw(alpha) {
        drawCube()
    }

    scale(s) {
        for (node in Nodes) {
            node[0] = node[0] * s
            node[1] = node[1] * s
            node[2] = node[2] * s
        }
    }

    drawCube() {
        Canvas.cls(Color.white)
        Canvas.offset(_width / 2, _height / 2)
        for (edge in Edges) {
            var xy1 = Nodes[edge[0]]
            var xy2 = Nodes[edge[1]]
            Canvas.line(Math.round(xy1[0]), Math.round(xy1[1]),
                        Math.round(xy2[0]), Math.round(xy2[1]), _fore)
        }
        for (node in Nodes) {
            Canvas.rectfill(Math.round(node[0]) - 4, Math.round(node[1]) - 4, 8, 8, _fore)
        }
    }

    rotateCube(angleX, angleY) {
        var sinX = Math.sin(angleX)
        var cosX = Math.cos(angleX)
        var sinY = Math.sin(angleY)
        var cosY = Math.cos(angleY)
        for (node in Nodes) {
            var x = node[0]
            var y = node[1]
            var z = node[2]
            node[0] = x * cosX - z * sinX
            node[2] = z * cosX + x * sinX
            z = node[2]
            node[1] = y * cosY - z * sinY
            node[2] = z * cosY + y * sinY
        }
    }
}

var Game = RotatingCube.new(640, 640)

XPL0

The main challenge was figuring out the initial coordinates of the cube. Zometool came to the rescue. The program runs much smoother than the animated gif.

def  Size=100., Speed=0.05;             \drawing size and rotation speed
real X, Y, Z, Farthest;                 \arrays: 3D coordinates of vertices
int  I, J, K, ZI, Edge;
def  R2=sqrt(2.), R3=sqrt(3.), R13=sqrt(1./3.), R23=sqrt(2./3.), R232=R23*2.;
\vertex:0       1       2       3       4       5       6       7
[X:= [  0.,     R2,     0.,    -R2,     0.,     R2,     0.,    -R2];
 Y:= [ -R3,    -R13,    R13,   -R13,   -R13,    R13,    R3,     R13];
 Z:= [  0.,    -R23,   -R232,  -R23,    R232,   R23,    0.,     R23];
Edge:= [0,1, 1,2, 2,3, 3,0, 4,5, 5,6, 6,7, 7,4, 0,4, 1,5, 2,6, 3,7];
SetVid($101);                           \set 640x480x8 graphics
repeat  Farthest:= 0.0;                 \find the farthest vertex
        for I:= 0 to 8-1 do
            if Z(I) > Farthest then [Farthest:= Z(I);  ZI:= I];
        Clear;                          \erase screen
        for I:= 0 to 2*12-1 do          \for all the vertices...
            [J:= Edge(I);  I:= I+1;     \get vertex numbers for edge
            Move(Fix(X(J)*Size)+640/2, Fix(Y(J)*Size)+480/2);
            K:= Edge(I);
            Line(Fix(X(K)*Size)+640/2, Fix(Y(K)*Size)+480/2,
                if J=ZI ! K=ZI then $F001 \dashed blue\ else $0C \red\);
            ];
        DelayUS(55000);
        for I:= 0 to 8-1 do
            [X(I):= X(I) + Z(I)*Speed;  \rotate vertices about Y axis
             Z(I):= Z(I) - X(I)*Speed;  \ (which rotates in X-Z plane)
            ];
until KeyHit;                           \run until a key is struck
SetVid(3);                              \restore normal text mode
]
Output:

http://www.xpl0.org/rotcube2.gif

Yabasic

// Rosetta Code problem: http://rosettacode.org/wiki/Draw_a_rotating_cube
// adapted to Yabasic by Galileo, 05/2022

// GFA Punch (code from tigen.ti-fr.com/)
// Carré 3D en rotation

open window 50, 70
backcolor 0,0,0
clear window
color 255,255,255

do
  clear window
  x = COS(T) * 20
  y = SIN(T) * 18
  r = SIN(T + T) 
  
  line (x + 40), (y + 40 - r), (-y + 40), (x + 40 - r)
  line (-y + 40), (x + 40 - r), (-x + 40), (-y + 40 - r)
  line (-x + 40), (-y + 40 - r), (y + 40), (-x + 40 - r)
  line (y + 40), (-x + 40 - r), (x + 40), (y + 40 - r)
  
  line (x + 40), (y + 20 + r), (-y + 40), (x + 20 + r)
  line (-y + 40), (x + 20 + r), (-x + 40), (-y + 20 + r)
  line (-x + 40), (-y + 20 + r), (y + 40), (-x + 20 + r)
  line (y + 40), (-x + 20 + r), (x + 40), (y + 20 + r)
  line (x + 40), (y + 40 - r), (x + 40), (y + 20 + r)
  line (-y + 40), (x + 40 - r), (-y + 40), (x + 20 + r)
  line (-x + 40), (-y + 40 - r), (-x + 40), (-y + 20 + r)
  line (y + 40), (-x + 40 - r), (y + 40), (-x + 20 + r)

  pause 0.02
  T = T + 0.15
loop

Zig

Library: Raylib
Works with: Zig version 0.11.0
Works with: Raylib version 4.6
const std = @import("std");
const c = @cImport({
    @cInclude("raylib.h");
    @cInclude("rlgl.h");
});

const dark_mode = true;
const show_grid = false;

pub fn main() !void {
    const screen_width = 640;
    const screen_height = 360;

    const cube_side = 1;
    const size = c.Vector3{ .x = cube_side, .y = cube_side, .z = cube_side };
    const position = c.Vector3{ .x = 0, .y = 0, .z = 0 };
    const x_rot = 45;
    const y_center: f32 = std.math.sqrt(3.0) * cube_side / 2.0;
    const z_rot = std.math.radiansToDegrees(f32, std.math.atan(@as(f32, std.math.sqrt1_2)));

    c.SetConfigFlags(c.FLAG_WINDOW_RESIZABLE | c.FLAG_VSYNC_HINT);
    c.InitWindow(screen_width, screen_height, "Draw a Rotating Cube");
    defer c.CloseWindow();

    var camera = c.Camera{
        .position = .{ .x = 3, .y = 3, .z = 3 },
        .target = .{ .x = 0, .y = y_center, .z = 0 }, // Center of cube
        .up = .{ .x = 0, .y = 1, .z = 0 },
        .fovy = 45, // Camera field-of-view Y
        .projection = c.CAMERA_PERSPECTIVE,
    };

    c.SetTargetFPS(60);

    while (!c.WindowShouldClose()) // Detect window close button or ESC key
    {
        c.UpdateCamera(&camera, c.CAMERA_ORBITAL);

        c.BeginDrawing();
        defer c.EndDrawing();

        c.ClearBackground(if (dark_mode) c.BLACK else c.RAYWHITE);
        {
            c.BeginMode3D(camera);
            defer c.EndMode3D();
            {
                c.rlPushMatrix();
                defer c.rlPopMatrix();
                c.rlTranslatef(0, y_center, 0);
                c.rlRotatef(z_rot, 0, 0, 1);
                c.rlRotatef(x_rot, 1, 0, 0);
                c.DrawCubeWiresV(position, size, if (dark_mode) c.LIME else c.BLACK);
            }
            if (show_grid) c.DrawGrid(12, 0.75);
        }
    }
}