Draw a rotating cube: Difference between revisions
No edit summary |
|||
(103 intermediate revisions by 38 users not shown) | |||
Line 9: | Line 9: | ||
;Related tasks |
;Related tasks |
||
* [[Draw_a_cuboid|Draw a cuboid]] |
* [[Draw_a_cuboid|Draw a cuboid]] |
||
* [[Write_language_name_in_3D_ASCII|write language name in 3D ASCII]] |
|||
<br><br> |
<br><br> |
||
=={{header| |
=={{header|Ada}}== |
||
{{libheader|SDLAda}} |
|||
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. |
|||
{{trans|Go}} |
|||
<syntaxhighlight lang="ada">with Ada.Numerics.Elementary_Functions; |
|||
with SDL.Video.Windows.Makers; |
|||
<lang futurebasic> |
|||
with SDL.Video.Renderers.Makers; |
|||
include "Tlbx agl.incl" |
|||
with SDL.Events.Events; |
|||
include "Tlbx glut.incl" |
|||
procedure Rotating_Cube is |
|||
output file "Rotating Cube" |
|||
Width : constant := 500; |
|||
local fn AnimateCube |
|||
Height : constant := 500; |
|||
'~'1 |
|||
Offset : constant := 500.0 / 2.0; |
|||
begin globals |
|||
dim as double sRotation |
|||
end globals |
|||
Window : SDL.Video.Windows.Window; |
|||
// Speed of rotation |
|||
Renderer : SDL.Video.Renderers.Renderer; |
|||
sRotation += 2.9 |
|||
Event : SDL.Events.Events.Events; |
|||
glMatrixMode( _GLMODELVIEW ) |
|||
Quit : Boolean := False; |
|||
type Node_Id is new Natural; |
|||
glLoadIdentity() |
|||
type Point_3D is record X, Y, Z : Float; end record; |
|||
glTranslated( 0.0, 0.0, 0.0 ) |
|||
type Edge_Type is record A, B : Node_Id; end record; |
|||
glRotated( sRotation, -0.45, -0.8, -0.6 ) |
|||
glColor3d( 1.0, 0.0, 0.3 ) |
|||
glLineWidth( 1.5 ) |
|||
glutWireCube( 1.0 ) |
|||
end fn |
|||
Nodes : array (Node_Id range <>) of Point_3D := |
|||
// Main program |
|||
((-100.0, -100.0, -100.0), (-100.0, -100.0, 100.0), (-100.0, 100.0, -100.0), |
|||
dim as GLint attrib(2) |
|||
(-100.0, 100.0, 100.0), (100.0, -100.0, -100.0), (100.0, -100.0, 100.0), |
|||
dim as CGrafPtr port |
|||
(100.0, 100.0, -100.0), (100.0, 100.0, 100.0)); |
|||
dim as AGLPixelFormat fmt |
|||
Edges : constant array (Positive range <>) of Edge_Type := |
|||
dim as AGLContext glContext |
|||
((0, 1), (1, 3), (3, 2), (2, 0), (4, 5), (5, 7), |
|||
dim as EventRecord ev |
|||
(7, 6), (6, 4), (0, 4), (1, 5), (2, 6), (3, 7)); |
|||
dim as GLboolean yesOK |
|||
use Ada.Numerics.Elementary_Functions; |
|||
window 1, @"Rotating Cube", (0,0) - (500,500) |
|||
procedure Rotate_Cube (AngleX, AngleY : in Float) is |
|||
attrib(0) = _AGLRGBA |
|||
SinX : constant Float := Sin (AngleX); |
|||
attrib(1) = _AGLDOUBLEBUFFER |
|||
CosX : constant Float := Cos (AngleX); |
|||
attrib(2) = _AGLNONE |
|||
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 |
|||
fmt = fn aglChoosePixelFormat( 0, 0, attrib(0) ) |
|||
use type SDL.Events.Event_Types; |
|||
glContext = fn aglCreateContext( fmt, 0 ) |
|||
begin |
|||
aglDestroyPixelFormat( fmt ) |
|||
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 |
|||
port = window( _wndPort ) |
|||
use SDL.C; |
|||
yesOK = fn aglSetDrawable( glContext, port ) |
|||
Pi : constant := Ada.Numerics.Pi; |
|||
yesOK = fn aglSetCurrentContext( glContext ) |
|||
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)); |
|||
glClearColor( 0.0, 0.0, 0.0, 0.0 ) |
|||
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;</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}}== |
|||
Requires [https://www.autohotkey.com/boards/viewtopic.php?f=6&t=6517&start=320 Gdip Library] |
|||
<syntaxhighlight lang="autohotkey">; --------------------------------------------------------------- |
|||
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 |
|||
; ---------------------------------------------------------------</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}}== |
|||
Rotating wireframe cube in [https://www.opengl.org/ OpenGL], windowing implementation via [http://freeglut.sourceforge.net/ freeglut] |
|||
<syntaxhighlight lang="c"> |
|||
#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; |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|C sharp|C#}}== |
|||
{{trans|Java}} |
|||
<syntaxhighlight lang="csharp">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); |
|||
} |
|||
} |
|||
} |
|||
}</syntaxhighlight> |
|||
=={{header|Delphi}}== |
|||
{{libheader| Winapi.Windows}} |
|||
{{libheader| Vcl.Graphics}} |
|||
{{libheader| Vcl.Controls}} |
|||
{{libheader| Vcl.Forms}} |
|||
{{libheader| Vcl.ExtCtrls}} |
|||
{{libheader| System.Math}} |
|||
{{libheader| System.Classes}} |
|||
{{Trans|Javascript}} |
|||
<syntaxhighlight lang="delphi"> |
|||
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.</syntaxhighlight> |
|||
Resource Form |
|||
<syntaxhighlight lang="delphi"> |
|||
object Form1: TForm1 |
|||
OnCreate = FormCreate |
|||
object tmr1: TTimer |
|||
Interval = 17 |
|||
OnTimer = tmr1Timer |
|||
end |
|||
end |
|||
</syntaxhighlight> |
|||
=={{header|EasyLang}}== |
|||
Draws only the visible edges |
|||
[https://easylang.online/show/#cod=jZTbboMwDIbv8xSWdteqaITSg7Q9ScUFKmkVCcJG0Ub29LNN0gTGtqZVTe3Pvx0TMG2lTsWpgFc44WeTum9x/3O/jv3eHeMRHcGeLYSqrnGpFCQDErZst5CxzZxGDju2OziwPcCe7R4jo3Du8ncub+90DlzuCcRb157hdi5rBRdIIBEAcGk70NhCCn0LtTJg3AQo6OKVj2fOiYsxXZyqAlavcHEBlkxEMpbq2r7sFZTmOtCP9TVv2gwoiYZj5Dq3N3KhubswbANlHWUDZR/pn1R9r6l3fkXOzDsDhdEBVmNPG4RX3LHDbJQrY8Evn7Lm7Cgl4IjZEbNB2c6wrAhqFtVshNFseZcVHpxsHHPVlZ9+tOdalR1dNKhxPB75kuazSR+Zlr7EXbxAE254szQzr66n95+UaPDLNf3BDzXZ40ff6CCO29QDOT0ho8pYYu1q4FJ1JCT/FUp/FQp7oM7NdFzV5MH4a1vwc2eYbXQBmDjpc3SHNFxD6qcdBKY947KLkJwpyTkkF5QWoZlS034oamwN+TPVJjsBam0U1RsBOQOS6XgTMb6IZC7ca2KbQ9mXBm7vXQ9S0KkWLT37usEwZTkwBZZlIBHf Run it] |
|||
<syntaxhighlight lang="text"> |
|||
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 |
|||
. |
|||
</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}}== |
|||
<syntaxhighlight lang="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</syntaxhighlight> |
|||
=={{header|FutureBasic}}== |
|||
<syntaxhighlight lang="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 |
|||
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}}== |
|||
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... |
|||
<syntaxhighlight lang="go">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 |
|||
}</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. |
||
< |
<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 253: | 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 ()</ |
return ()</syntaxhighlight> |
||
Link to live demo: https://dc25.github.io/drawRotatingCubeHaskell/ |
Link to live demo: https://dc25.github.io/drawRotatingCubeHaskell/ |
||
=={{header|J}}== |
|||
Derived from J's [https://github.com/jsoftware/demos_qtdemo/blob/master/shader.ijs qt shader demo]: |
|||
<syntaxhighlight lang="j">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''</syntaxhighlight> |
|||
A variation which did not use opengl would probably be much more concise. |
|||
=={{header|Java}}== |
=={{header|Java}}== |
||
[[File:rotating_cube_java.png|200px|thumb|right]] |
[[File:rotating_cube_java.png|200px|thumb|right]] |
||
< |
<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 350: | Line 1,788: | ||
}); |
}); |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|JavaScript}}== |
|||
{{trans|Java}} |
|||
<syntaxhighlight lang="javascript"><!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></syntaxhighlight> |
|||
=={{header|Julia}}== |
|||
Run at the Julia REPL command line. |
|||
<syntaxhighlight lang="julia">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</syntaxhighlight> |
|||
=={{header|Kotlin}}== |
|||
{{trans|Java}} |
|||
<syntaxhighlight lang="scala">// 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 |
|||
} |
|||
}</syntaxhighlight> |
|||
=={{header|Lua}}== |
|||
<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 = { |
|||
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</syntaxhighlight> |
|||
{{out}} |
|||
<pre style="font-size:50%">Frame 1: |
|||
················································································ |
|||
······································██········································ |
|||
····································██████······································ |
|||
··································████····██···································· |
|||
································██··██······██·································· |
|||
······························██····██········██································ |
|||
····························██······██··········██······························ |
|||
····························██······██············██···························· |
|||
··························██······██················██·························· |
|||
························██········██··················██························ |
|||
······················██········████····················██······················ |
|||
····················██········██····██····················██···················· |
|||
··················██········██········██····················██·················· |
|||
················██········██············██····················██················ |
|||
··············██········██················██················████················ |
|||
··············████····██····················██············██····██·············· |
|||
············██····████························██········██······██·············· |
|||
··········██······████··························██····██········██·············· |
|||
··········██····██····████························████············██············ |
|||
········██····██··········██······················████············██············ |
|||
········██··██··············██················████····██··········██············ |
|||
······██··██··················████··········██··········██··········██·········· |
|||
······████························██······██··············████······██·········· |
|||
····████····························██████····················██····██·········· |
|||
····██································██························██··██·········· |
|||
··██··································██··························██··██········ |
|||
····██································██····························████········ |
|||
······████····························██························████············ |
|||
··········██··························██······················██················ |
|||
············████······················██··················████·················· |
|||
················████··················██··············████······················ |
|||
····················██················██············██·························· |
|||
······················████············██········████···························· |
|||
··························██··········██······██································ |
|||
····························████······██··████·································· |
|||
································████··████······································ |
|||
····································████········································ |
|||
················································································ |
|||
················································································ |
|||
················································································ |
|||
Frame 60: |
|||
················································································ |
|||
······································██········································ |
|||
····································██████······································ |
|||
··································██··██··██···································· |
|||
······························████····██····████································ |
|||
····························██········██········██······························ |
|||
························████··········██··········████·························· |
|||
····················████··············██··············██························ |
|||
··················██··················██················██······················ |
|||
··············████····················██··················████·················· |
|||
············██························██······················██················ |
|||
········████··························██························████············ |
|||
····████······························██····························████········ |
|||
····████······························██····························████········ |
|||
······████····························████························████·········· |
|||
······██··██························██····██····················██··██·········· |
|||
········██··██····················██········████··············██····██·········· |
|||
········██····██··············████··············██··········██····██············ |
|||
········██······██··········██····················██······██······██············ |
|||
··········██······██······██························██████········██············ |
|||
··········██········██████····························████······██·············· |
|||
··········██········████····························██····██····██·············· |
|||
············██··████····██························██········████················ |
|||
············████··········████··················██············██················ |
|||
··············██··············██··············██············██·················· |
|||
················██··············██··········██············██···················· |
|||
··················██··············██······██············██······················ |
|||
····················██··············██████············██························ |
|||
······················██··············██············██·························· |
|||
························██············██············██·························· |
|||
··························██··········██··········██···························· |
|||
····························██········██········██······························ |
|||
······························██······██······██································ |
|||
································██····██····██·································· |
|||
··································██··██··██···································· |
|||
····································██████······································ |
|||
······································██········································ |
|||
················································································ |
|||
················································································ |
|||
················································································</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}}== |
||
< |
<syntaxhighlight lang="maple">plots:-display( |
||
seq( |
seq( |
||
plots:-display( |
plots:-display( |
||
Line 359: | 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 );</ |
insequence=true );</syntaxhighlight> |
||
=={{header| |
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
||
<syntaxhighlight lang="mathematica">Dynamic[ |
|||
Included in the distribution as demo\pGUI\iup3Dgl.exw |
|||
Graphics3D[ |
|||
<lang Phix>-- |
|||
GeometricTransformation[ |
|||
-- iup3Dgl.exw |
|||
GeometricTransformation[Cuboid[], RotationTransform[Pi/4, {1, 1, 0}]], |
|||
-- |
|||
RotationTransform[Clock[2 Pi], {0, 0, 1}] |
|||
-- Simple example of use of 3D OpenGL and IUP. |
|||
], |
|||
-- |
|||
Boxed -> False]]</syntaxhighlight> |
|||
-- Creates a dialog with one canvas and draws a rotating cube in it. |
|||
-- |
|||
-- Author: Marcelo Gattass, Nov 9 2009. |
|||
-- Translated to Phix by Pete Lomax, May 25 2016 |
|||
-- |
|||
=={{header|MiniScript}}== |
|||
include pGUI.e |
|||
{{works with|Mini Micro}} |
|||
include opengl.e |
|||
include glu.e |
|||
<syntaxhighlight lang="MiniScript">import "mathUtil" |
|||
--#withtype Ihandle |
|||
scale = 250 |
|||
radius = sqrt(scale^2) |
|||
Face = new Sprite |
|||
Ihandle canvas; /* canvas handle */ |
|||
Face.image = file.loadImage("/sys/pics/shapes/SquareThin.png") |
|||
integer width = 640, /* width and height of the canvas */ |
|||
height = 480; |
|||
atom t = 0; /* animation time */ |
|||
clear; gfx.clear color.gray |
|||
/*------------------------------------------*/ |
|||
sprites = display(4).sprites |
|||
/* Auxiliary functions to draw a color cube */ |
|||
/*------------------------------------------*/ |
|||
// build a sprite for each side |
|||
constant vertices = {{-1,-1, 1}, {-1, 1, 1}, {1, 1, 1}, {1,-1, 1}, |
|||
for i in range(0, 3) |
|||
{-1,-1,-1}, {-1, 1,-1}, {1, 1,-1}, {1,-1,-1}}; |
|||
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 |
|||
procedure polygon(integer a, integer b, integer c, integer d) |
|||
// around the Y axis, then project to the screen. |
|||
glBegin(GL_POLYGON); |
|||
rotateAndProject = function(point3d, rotDegrees) |
|||
glVertex3d(vertices[a+1]); |
|||
radians = rotDegrees * pi/180 |
|||
glVertex3d(vertices[b+1]); |
|||
cosAng = cos(radians); sinAng = sin(radians) |
|||
glVertex3d(vertices[c+1]); |
|||
// First, rotate around the Y axis in 3D space |
|||
glVertex3d(vertices[d+1]); |
|||
x = point3d[0] * cosAng - point3d[2] * sinAng |
|||
glEnd(); |
|||
y = point3d[1] |
|||
end procedure |
|||
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. |
|||
procedure colorCube() |
|||
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 |
|||
glColor3f({1,0,0}); |
|||
rot = 0 |
|||
glNormal(1,0,0); |
|||
while not key.pressed("escape") and not key.pressed("q") |
|||
polygon(2,3,7,6); |
|||
yield |
|||
positionSprites rot |
|||
rot = rot + 1 |
|||
end while |
|||
key.clear</syntaxhighlight> |
|||
{{output}} |
|||
glColor3f({0,1,0}); |
|||
[[File:MiniScript-spnning-cube.gif|alt=MiniScript spinning cube solution|MiniScript spinning cube solution]] |
|||
glNormal(0,1,0); |
|||
polygon(1,2,6,5); |
|||
=={{header|Nim}}== |
|||
glColor3f({0,0,1}); |
|||
{{trans|Ada}} |
|||
glNormal(0,0,1); |
|||
{{libheader|SDL2}} |
|||
polygon(0,3,2,1); |
|||
<syntaxhighlight lang="nim">import math |
|||
import sdl2 |
|||
const |
|||
Width = 500 |
|||
Height = 500 |
|||
Offset = 500 / 2 |
|||
var nodes = [(x: -100.0, y: -100.0, z: -100.0), |
|||
glColor3f({1,0,1}); |
|||
(x: -100.0, y: -100.0, z: 100.0), |
|||
(x: -100.0, y: 100.0, z: -100.0), |
|||
polygon(3,0,4,7); |
|||
(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 |
|||
glColor3f({1,1,0}); |
|||
window: WindowPtr |
|||
glNormal(0,0,-1); |
|||
renderer: RendererPtr |
|||
polygon(4,5,6,7); |
|||
event: Event |
|||
endSimulation = false |
|||
#--------------------------------------------------------------------------------------------------- |
|||
glColor3f({0,1,1}); |
|||
glNormal(-1,0,0); |
|||
polygon(5,4,0,1); |
|||
proc rotateCube(angleX, angleY: float) = |
|||
end procedure |
|||
let |
|||
sinX = sin(angleX) |
|||
cosX = cos(angleX) |
|||
sinY = sin(angleY) |
|||
cosY = cos(angleY) |
|||
for node in nodes.mitems: |
|||
/* function called when the canvas is exposed in the screen */ |
|||
var (x, y, z) = node |
|||
function repaint_cb(Ihandle self) |
|||
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 |
|||
#--------------------------------------------------------------------------------------------------- |
|||
IupGLMakeCurrent(self); |
|||
glClearColor(0.3, 0.3, 0.3, 1.0); /* White */ |
|||
glClear(or_bits(GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT)); |
|||
glEnable(GL_DEPTH_TEST); |
|||
proc pollQuit(): bool = |
|||
glMatrixMode(GL_MODELVIEW); |
|||
while pollEvent(event): |
|||
glPushMatrix(); /* saves current model view in a stack */ |
|||
if event.kind == QuitEvent: |
|||
glTranslate(0.0, 0.0 , 0.0); |
|||
return true |
|||
glScalef({1.0, 1.0, 1.0}); |
|||
glRotate(t,1,0,1); |
|||
colorCube(); |
|||
#--------------------------------------------------------------------------------------------------- |
|||
glPopMatrix(); |
|||
proc drawCube(): bool = |
|||
IupGLSwapBuffers(self); /* change the back buffer with the front buffer */ |
|||
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 |
|||
#——————————————————————————————————————————————————————————————————————————————————————————————————— |
|||
return IUP_DEFAULT; /* returns the control to the main loop */ |
|||
end function |
|||
if sdl2.init(INIT_EVERYTHING) == SdlError: |
|||
/* function called in the event of changes in the width or in the height of the canvas */ |
|||
quit(QuitFailure) |
|||
function resize_cb(Ihandle self, integer new_width, integer new_height) |
|||
window = createWindow("Rotating cube", 10, 10, 500, 500, 0) |
|||
IupGLMakeCurrent(self); /* Make the canvas current in OpenGL */ |
|||
renderer = createRenderer(window, -1, Renderer_Accelerated) |
|||
while not endSimulation: |
|||
/* define the entire canvas as the viewport */ |
|||
endSimulation = drawCube() |
|||
glViewport(0,0,new_width,new_height); |
|||
window.destroy()</syntaxhighlight> |
|||
=={{header|Objeck}}== |
|||
/* transformation applied to each vertex */ |
|||
{{libheader|SDL2}} |
|||
glMatrixMode(GL_MODELVIEW); |
|||
{{trans|Ada}} |
|||
glLoadIdentity(); /* identity, i. e. no transformation */ |
|||
<syntaxhighlight lang="objeck">#~ |
|||
Rotating Cube |
|||
~# |
|||
use Collection.Generic; |
|||
/* projection transformation (orthographic in the xy plane) */ |
|||
use Game.SDL2; |
|||
glMatrixMode(GL_PROJECTION); |
|||
use Game.Framework; |
|||
glLoadIdentity(); |
|||
gluPerspective(60,4/3,1,15); |
|||
gluLookAt({3,3,3}, {0,0,0}, {0,0,1}); |
|||
class RotatingCube { |
|||
/* update canvas size and repaint */ |
|||
# game framework |
|||
width = new_width; |
|||
@framework : GameFramework; |
|||
height = new_height; |
|||
@initialized : Bool; |
|||
return repaint_cb(canvas); |
|||
end function |
|||
@nodes : Float[,]; |
|||
function idle_cd() |
|||
@edges : Int[,]; |
|||
return repaint_cb(canvas); |
|||
end function |
|||
New() { |
|||
function exit_cb() |
|||
@initialized := true; |
|||
printf(1,"Function to free memory and do finalizations...\n"); |
|||
@framework := GameFramework->New(GameConsts->SCREEN_WIDTH, GameConsts->SCREEN_HEIGHT, "Rotating Cube"); |
|||
return IUP_CLOSE; |
|||
end function |
|||
@nodes := [[-100.0, -100.0, -100.0], [-100.0, -100.0, 100.0], [-100.0, 100.0, -100.0], |
|||
function esc_close(Ihandle /*ih*/, atom c) |
|||
[-100.0, 100.0, 100.0], [100.0, -100.0, -100.0], [100.0, -100.0, 100.0], |
|||
-- (I like all my demos to close when escape is keyed) |
|||
[100.0, 100.0, -100.0], [100.0, 100.0, 100.0]]; |
|||
if c=K_ESC then return IUP_CLOSE end if |
|||
return IUP_CONTINUE |
|||
end function |
|||
@edges := [[0, 1], [1, 3], [3, 2], [2, 0], [4, 5], [5, 7], |
|||
function initDialog() |
|||
[7, 6], [6, 4], [0, 4], [1, 5], [2, 6], [3, 7]]; |
|||
} |
|||
Ihandle dialog; /* dialog containing the canvas */ |
|||
function : Main(args : String[]) ~ Nil { |
|||
canvas = IupGLCanvas("repaint_cb", Icallback("repaint_cb")); /* create _canvas and define its repaint callback */ |
|||
RotatingCube->New()->Play(); |
|||
} |
|||
method : Play() ~ Nil { |
|||
IupSetAttribute(canvas,"IUP_RASTERSIZE","640x480"); /* define the size in pixels */ |
|||
if(@initialized) { |
|||
IupSetAttribute(canvas,"IUP_BUFFER","IUP_DOUBLE"); /* define that this OpenGL _canvas has double buffer (front and back) */ |
|||
# initialization |
|||
@framework->SetClearColor(Color->New(0, 0, 0)); |
|||
RotateCube(Float->Pi(), 2.0->SquareRoot()->ArcTan()); |
|||
quit := false; |
|||
/* bind callback actions with callback functions */ |
|||
e := @framework->GetEvent(); |
|||
IupSetCallback(canvas, "RESIZE_CB",Icallback("resize_cb")); |
|||
while(<>quit) { |
|||
@framework->FrameStart(); |
|||
@framework->Clear(); |
|||
# process input |
|||
while(e->Poll() <> 0) { |
|||
if(e->GetType() = EventType->SDL_QUIT) { |
|||
quit := true; |
|||
}; |
|||
}; |
|||
#draw |
|||
/* create the dialog and set its attributes */ |
|||
DrawCube(); |
|||
dialog = IupDialog(canvas, "SIZE=640x480"); |
|||
IupSetAttribute(dialog, "TITLE", "IUP_3D_OpenGL"); |
|||
@framework->FrameEnd(); |
|||
IupSetCallback(dialog, "CLOSE_CB", Icallback("exit_cb")); |
|||
IupSetGlobalFunction("IDLE_ACTION", Icallback("idle_cd")); |
|||
IupSetCallback(dialog, "K_ANY", Icallback("esc_close")) |
|||
# render |
|||
@framework->Show(); |
|||
end function |
|||
Timer->Delay(200); |
|||
procedure main() |
|||
Ihandle dialog; |
|||
RotateCube (Float->Pi() / 180.0, 0.0); |
|||
IupOpen(); /* opens the IUP lib */ |
|||
}; |
|||
} |
|||
else { |
|||
"--- Error Initializing Environment ---"->ErrorLine(); |
|||
return; |
|||
}; |
|||
leaving { |
|||
IupGLCanvasOpen(); /* enable use of OpenGL to draw in canvas */ |
|||
@framework->FreeShapes(); |
|||
}; |
|||
} |
|||
method : RotateCube(angleX : Float, angleY : Float) ~ Nil { |
|||
dialog = initDialog(); /* create the dialog and canvas */ |
|||
sinX := angleX->Sin(); |
|||
IupShowXY(dialog, IUP_CENTER, IUP_CENTER); /* show in the center of screen */ |
|||
cosX := angleX->Cos(); |
|||
sinY := angleY->Sin(); |
|||
cosY := angleY->Cos(); |
|||
node_sizes := @nodes->Size(); |
|||
size := node_sizes[0]; |
|||
for(i := 0; i < size; i += 1;) { |
|||
IupMainLoop(); /* give program control to IUP until a return IUP_CLOSE */ |
|||
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 { |
|||
IupClose(); /* closes the IUP lib */ |
|||
edge_sizes := @edges->Size(); |
|||
end procedure |
|||
size := edge_sizes[0]; |
|||
@framework->GetRenderer()->SetDrawColor(0, 220, 0, 0); |
|||
main()</lang> |
|||
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 |
|||
}</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|PascalABC.NET}}== |
|||
<syntaxhighlight lang="delphi"> |
|||
uses Graph3D; |
|||
begin |
|||
var Cube := Box(Origin,Sz3D(3,3,3),Colors.Green); |
|||
Cube.AnimRotate(OrtZ,180).Forever.Begin |
|||
end. |
|||
</syntaxhighlight> |
|||
=={{header|Perl}}== |
|||
<syntaxhighlight lang="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); |
|||
}</syntaxhighlight> |
|||
=={{header|Phix}}== |
|||
{{libheader|Phix/pGUI}} |
|||
{{libheader|Phix/online}} |
|||
You can run this online [http://phix.x10.mx/p2js/drawrotatingcube.htm here]. |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<span style="color: #000080;font-style:italic;">-- |
|||
-- 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). |
|||
--</span> |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">title</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Draw a Rotating Cube"</span> |
|||
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas</span> |
|||
<span style="color: #004080;">cdCanvas</span> <span style="color: #000000;">cd_canvas</span> |
|||
<span style="color: #000080;font-style:italic;">-- |
|||
-- 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.) |
|||
--</span> |
|||
<span style="color: #008080;">enum</span> <span style="color: #000000;">X</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">Y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">Z</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">l</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">100</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">corners</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{+</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,+</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,+</span><span style="color: #000000;">l</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- 1 (front top right)</span> |
|||
<span style="color: #0000FF;">{+</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,+</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">l</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- 2 (back top "right")</span> |
|||
<span style="color: #0000FF;">{+</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">l</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- 3 (back btm "right")</span> |
|||
<span style="color: #0000FF;">{+</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,+</span><span style="color: #000000;">l</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- 4 (front btm right)</span> |
|||
<span style="color: #0000FF;">{-</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,+</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,+</span><span style="color: #000000;">l</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- 5 (front top left)</span> |
|||
<span style="color: #0000FF;">{-</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,+</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">l</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- 6 (back top "left")</span> |
|||
<span style="color: #0000FF;">{-</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">l</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- 7 (back btm "left")</span> |
|||
<span style="color: #0000FF;">{-</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,+</span><span style="color: #000000;">l</span><span style="color: #0000FF;">}}</span> <span style="color: #000080;font-style:italic;">-- 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.</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">faces</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #004600;">CD_RED</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- right</span> |
|||
<span style="color: #0000FF;">{</span><span style="color: #004600;">CD_YELLOW</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- top</span> |
|||
<span style="color: #0000FF;">{</span><span style="color: #004600;">CD_DARK_GREEN</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- front</span> |
|||
<span style="color: #0000FF;">{</span><span style="color: #004600;">CD_BLUE</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- back</span> |
|||
<span style="color: #0000FF;">{</span><span style="color: #004600;">CD_WHITE</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- bottom |
|||
-- {CD_ORANGE, 5,6,7,8}} -- left</span> |
|||
<span style="color: #0000FF;">{</span><span style="color: #004600;">CD_ORANGE</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">}}</span> <span style="color: #000080;font-style:italic;">-- left |
|||
-- rotation angles, 0..359, on a timer</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">rx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">45</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- initially makes cube like a H</span> |
|||
<span style="color: #000000;">ry</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">35</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- " " " italic H</span> |
|||
<span style="color: #000000;">rz</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">naxes</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Z</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- (rotate about the X-axis)</span> |
|||
<span style="color: #0000FF;">{</span><span style="color: #000000;">X</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Z</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- (rotate about the Y-axis)</span> |
|||
<span style="color: #0000FF;">{</span><span style="color: #000000;">X</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">}}</span> <span style="color: #000080;font-style:italic;">-- (rotate about the Z-axis)</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">rotate</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">points</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">angle</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">axis</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">-- |
|||
-- rotate points by the specified angle about the given axis |
|||
--</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">radians</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">angle</span><span style="color: #0000FF;">*</span><span style="color: #004600;">CD_DEG2RAD</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">sin_t</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sin</span><span style="color: #0000FF;">(</span><span style="color: #000000;">radians</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #000000;">cos_t</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cos</span><span style="color: #0000FF;">(</span><span style="color: #000000;">radians</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">naxes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">axis</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">points</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">x</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">points</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">],</span> |
|||
<span style="color: #000000;">y</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">points</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #000000;">points</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">*</span><span style="color: #000000;">cos_t</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">*</span><span style="color: #000000;">sin_t</span> |
|||
<span style="color: #000000;">points</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">*</span><span style="color: #000000;">cos_t</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">*</span><span style="color: #000000;">sin_t</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">points</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">projection</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">points</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">-- |
|||
-- project points from {0,0,d} onto the perpendicular plane through {0,0,0} |
|||
--</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">points</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">z</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">points</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span> |
|||
<span style="color: #000000;">denom</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">-</span><span style="color: #000000;">z</span><span style="color: #0000FF;">/</span><span style="color: #000000;">d</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">points</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">X</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">/</span><span style="color: #000000;">denom</span> |
|||
<span style="color: #000000;">points</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">/</span><span style="color: #000000;">denom</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">points</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">nearest</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">points</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">-- |
|||
-- return the index of the nearest point (highest z value) |
|||
--</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #7060A8;">largest</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">vslice</span><span style="color: #0000FF;">(</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Z</span><span style="color: #0000FF;">),</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">draw_cube</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">cx</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cy</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">-- {cx,cy} is the centre point of the canvas</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">points</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">corners</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">points</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rotate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">X</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">points</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rotate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ry</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">points</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rotate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rz</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Z</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">points</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">projection</span><span style="color: #0000FF;">(</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">np</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">nearest</span><span style="color: #0000FF;">(</span><span style="color: #000000;">points</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">-- |
|||
-- 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.) |
|||
--</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">faceset</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">faces</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">fi</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">faces</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">np</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fi</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- k:=2..5, or 0</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">diag</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">k</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">2</span> <span style="color: #000080;font-style:italic;">-- {2,3,4,5} --> {4,5,2,3} |
|||
-- aka swap 2<=>4 & 3<=>5</span> |
|||
<span style="color: #000000;">diag</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">fi</span><span style="color: #0000FF;">[</span><span style="color: #000000;">diag</span><span style="color: #0000FF;">]</span> <span style="color: #000080;font-style:italic;">-- 1..8, diagonally opp. np</span> |
|||
<span style="color: #000000;">faceset</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">faceset</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">points</span><span style="color: #0000FF;">[</span><span style="color: #000000;">diag</span><span style="color: #0000FF;">][</span><span style="color: #000000;">Z</span><span style="color: #0000FF;">],</span><span style="color: #000000;">i</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #000080;font-style:italic;">-- else |
|||
-- faceset = append(faceset,{-9999,i})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #000000;">faceset</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">faceset</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">faceset</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">face</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">faces</span><span style="color: #0000FF;">[</span><span style="color: #000000;">faceset</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]]</span> |
|||
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cd_canvas</span><span style="color: #0000FF;">,</span><span style="color: #000000;">face</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #000080;font-style:italic;">-- first fill sides (with bresenham edges), then |
|||
-- redraw edges, but anti-aliased aka smoother</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">modes</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #004600;">CD_FILL</span><span style="color: #0000FF;">,</span><span style="color: #004600;">CD_CLOSED_LINES</span><span style="color: #0000FF;">}</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">modes</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #7060A8;">cdCanvasBegin</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cd_canvas</span><span style="color: #0000FF;">,</span><span style="color: #000000;">modes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">m</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">fdx</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #000000;">5</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">pt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">points</span><span style="color: #0000FF;">[</span><span style="color: #000000;">face</span><span style="color: #0000FF;">[</span><span style="color: #000000;">fdx</span><span style="color: #0000FF;">]]</span> |
|||
<span style="color: #7060A8;">cdCanvasVertex</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cd_canvas</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">pt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">],</span><span style="color: #000000;">cy</span><span style="color: #0000FF;">-</span><span style="color: #000000;">pt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #7060A8;">cdCanvasEnd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cd_canvas</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">canvas_action_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">cdCanvasActivate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cd_canvas</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">cdCanvasClear</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cd_canvas</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">w</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">h</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetIntInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DRAWSIZE"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">draw_cube</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">w</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">),</span><span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">h</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">))</span> |
|||
<span style="color: #7060A8;">cdCanvasFlush</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cd_canvas</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">canvas_map_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">IupGLMakeCurrent</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">cd_canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_IUP</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">else</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetDouble</span><span style="color: #0000FF;">(</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"SCREENDPI"</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">25.4</span> |
|||
<span style="color: #000000;">cd_canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_GL</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"10x10 %g"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #7060A8;">cdCanvasSetBackground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cd_canvas</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_PARCHMENT</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">canvas_resize_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*canvas*/</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">canvas_width</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas_height</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetIntInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DRAWSIZE"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetDouble</span><span style="color: #0000FF;">(</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"SCREENDPI"</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">25.4</span> |
|||
<span style="color: #7060A8;">cdCanvasSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cd_canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"SIZE"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"%dx%d %g"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">canvas_width</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas_height</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">timer_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandln</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">-- (feel free to add a bit more randomness here, maybe)</span> |
|||
<span style="color: #000000;">rx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">359</span><span style="color: #0000FF;">,</span><span style="color: #000000;">360</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ry</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ry</span><span style="color: #0000FF;">+</span><span style="color: #000000;">359</span><span style="color: #0000FF;">,</span><span style="color: #000000;">360</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">rz</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rz</span><span style="color: #0000FF;">+</span><span style="color: #000000;">359</span><span style="color: #0000FF;">,</span><span style="color: #000000;">360</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">IupRedraw</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_IGNORE</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">main</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #000000;">canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGLCanvas</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RASTERSIZE=640x480"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">IupSetCallbacks</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"ACTION"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"canvas_action_cb"</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #008000;">"MAP_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"canvas_map_cb"</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #008000;">"RESIZE_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"canvas_resize_cb"</span><span style="color: #0000FF;">)})</span> |
|||
<span style="color: #000000;">dlg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`TITLE="%s"`</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">title</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"RASTERSIZE"</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">NULL</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">hTimer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupTimer</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"timer_cb"</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">30</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span> |
|||
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span> |
|||
<!--</syntaxhighlight>--> |
|||
=={{header|PostScript}}== |
=={{header|PostScript}}== |
||
'''Don't send this to your printer!''' |
'''Don't send this to your printer!''' |
||
< |
<syntaxhighlight lang="postscript">%!PS-Adobe-3.0 |
||
%%BoundingBox: 0 0 400 400 |
%%BoundingBox: 0 0 400 400 |
||
Line 571: | Line 2,861: | ||
0 {3.2 add dup page } loop |
0 {3.2 add dup page } loop |
||
%%EOF</ |
%%EOF</syntaxhighlight> |
||
=={{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. |
|||
<syntaxhighlight lang="processing">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); |
|||
}</syntaxhighlight> |
|||
=={{header|Python}}== |
=={{header|Python}}== |
||
Line 580: | Line 2,891: | ||
====Short version==== |
====Short version==== |
||
< |
<syntaxhighlight lang="python">from visual import * |
||
scene.title = "VPython: Draw a rotating cube" |
scene.title = "VPython: Draw a rotating cube" |
||
Line 598: | Line 2,909: | ||
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 605: | Line 2,916: | ||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
< |
<syntaxhighlight lang="racket">#lang racket/gui |
||
(require math/matrix math/array) |
(require math/matrix math/array) |
||
Line 674: | Line 2,985: | ||
(send c refresh)) |
(send c refresh)) |
||
(define t (new timer% [notify-callback refresh] [interval 35] [just-once? #f]))</ |
(define t (new timer% [notify-callback refresh] [interval 35] [just-once? #f]))</syntaxhighlight> |
||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
{{works with|Rakudo|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 [[wp:Libcaca|Libcaca]], the '''C'''olor '''A'''S'''C'''II '''A'''rt library to generate a rotating cube in an ASCII terminal. |
|||
<syntaxhighlight lang="raku" line>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; |
|||
} |
|||
}</syntaxhighlight> |
|||
=={{header|Ring}}== |
|||
<syntaxhighlight lang="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() |
|||
</syntaxhighlight> |
|||
[https://www.mediafire.com/view/xjimb82x8lvfwd9/RotatingCube.jpg/file Rotating a Cube] |
|||
=={{header|Scala}}== |
|||
===Java Swing Interoperability=== |
|||
{{libheader|Scala Java Swing interoperability}} |
|||
{{libheader|Scala GUI Animation}} |
|||
{{works with|Scala|2.13}} |
|||
<syntaxhighlight lang="scala">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) |
|||
} |
|||
}</syntaxhighlight> |
|||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
Line 685: | Line 3,271: | ||
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. |
||
<syntaxhighlight lang="tcl"># matrix operation support: |
|||
<lang Tcl> |
|||
# matrix operation support: |
|||
package require math::linearalgebra |
package require math::linearalgebra |
||
namespace import ::math::linearalgebra::matmul |
namespace import ::math::linearalgebra::matmul |
||
Line 818: | Line 3,403: | ||
} |
} |
||
set ::world [make_cube 100] |
set ::world [make_cube 100] |
||
tick</syntaxhighlight> |
|||
tick |
|||
</lang> |
|||
=={{header|TI-83 BASIC}}== |
=={{header|TI-83 BASIC}}== |
||
< |
<syntaxhighlight lang="ti83b">:-1→Xmin:1→Xmax |
||
:-1→Ymin:1→Ymax |
:-1→Ymin:1→Ymax |
||
:AxesOff |
:AxesOff |
||
Line 844: | Line 3,428: | ||
:Line(.3,FV,-.3,-PV |
:Line(.3,FV,-.3,-PV |
||
:End |
:End |
||
:End</ |
: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). |
||
Finance variables are much faster than normal variables. |
Finance variables are much faster than normal variables. |
||
=={{header|Wren}}== |
|||
{{trans|Kotlin}} |
|||
{{libheader|DOME}} |
|||
<syntaxhighlight lang="wren">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)</syntaxhighlight> |
|||
=={{header|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. |
|||
<syntaxhighlight lang="xpl0">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 |
|||
]</syntaxhighlight> |
|||
{{out}} |
|||
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 06:24, 18 July 2024
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
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
El programa requiere de la ejecución con "rxvt" de Linux: rxvt -g 500x250 -fn "xft:FantasqueSansMono-Regular:pixelsize=1" -e ./bin/cubo
#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
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
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
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#
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
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
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.
// 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
<!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
// 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
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
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:
Nim
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
#~
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
PascalABC.NET
uses Graph3D;
begin
var Cube := Box(Origin,Sz3D(3,3,3),Colors.Green);
Cube.AnimRotate(OrtZ,180).Forever.Begin
end.
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
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
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)
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()
Scala
Java Swing Interoperability
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
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
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);
}
}
}
- Programming Tasks
- Solutions by Programming Task
- Ada
- SDLAda
- Amazing Hopper
- AutoHotkey
- BASIC
- BASIC256
- Chipmunk Basic
- GW-BASIC
- MSX Basic
- C
- C sharp
- Delphi
- Winapi.Windows
- Vcl.Graphics
- Vcl.Controls
- Vcl.Forms
- Vcl.ExtCtrls
- System.Math
- System.Classes
- EasyLang
- Evaldraw
- Pages with broken file links
- FreeBASIC
- FutureBasic
- Go
- Haskell
- J
- Java
- JavaScript
- Julia
- Kotlin
- Lua
- M2000 Interpreter
- Maple
- Mathematica
- Wolfram Language
- MiniScript
- Nim
- SDL2
- Objeck
- OxygenBasic
- PascalABC.NET
- Perl
- Phix
- Phix/pGUI
- Phix/online
- PostScript
- Processing
- Python
- VPython
- Racket
- Raku
- Ring
- Scala
- Scala Java Swing interoperability
- Scala GUI Animation
- Tcl
- TI-83 BASIC
- Wren
- DOME
- XPL0
- Yabasic
- Zig
- Raylib
- Geometry