
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.
withAda.Numerics.Elementary_Functions;withSDL.Video.Windows.Makers;withSDL.Video.Renderers.Makers;withSDL.Events.Events;procedureRotating_CubeisWidth: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;typeNode_IdisnewNatural;typePoint_3DisrecordX,Y,Z:Float;end record;typeEdge_TypeisrecordA,B:Node_Id;end record;Nodes:array(Node_Idrange<>)ofPoint_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:constantarray(Positiverange<>)ofEdge_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));useAda.Numerics.Elementary_Functions;procedureRotate_Cube(AngleX,AngleY:inFloat)isSinX:constantFloat:=Sin(AngleX);CosX:constantFloat:=Cos(AngleX);SinY:constantFloat:=Sin(AngleY);CosY:constantFloat:=Cos(AngleY);X,Y,Z:Float;beginforNodeofNodesloopX:=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;endloop;endRotate_Cube;functionPoll_QuitreturnBooleanisusetypeSDL.Events.Event_Types;beginwhileSDL.Events.Events.Poll(Event)loopifEvent.Common.Event_Type=SDL.Events.QuitthenreturnTrue;endif;endloop;returnFalse;endPoll_Quit;procedureDraw_Cube(Quit:outBoolean)isuseSDL.C;Pi:constant:=Ada.Numerics.Pi;Xy1,Xy2:Point_3D;beginRotate_Cube(Pi/4.0,Arctan(Sqrt(2.0)));forFramein0..359loopRenderer.Set_Draw_Colour((0,0,0,255));Renderer.Fill(Rectangle=>(0,0,Width,Height));Renderer.Set_Draw_Colour((0,220,0,255));forEdgeofEdgesloopXy1:=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))));endloop;Rotate_Cube(Pi/180.0,0.0);Window.Update_Surface;Quit:=Poll_Quit;exitwhenQuit;delay0.020;endloop;endDraw_Cube;beginifnotSDL.Initialise(Flags=>SDL.Enable_Screen)thenreturn;endif;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);whilenotQuitloopDraw_Cube(Quit);endloop;Window.Finalize;SDL.Finalise;endRotating_Cube;
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) ) NextReturn\\#context-free Delete old cube Color back '0', Draw a cubeReturn\\#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.6329931618554520654648560498039275946Main 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 BackEndSubrutinesRequiresGdip Library
; ---------------------------------------------------------------cubeSize:=200deltaX:=A_ScreenWidth/2deltaY:=A_ScreenHeight/2keyStep:=1mouseStep:=0.2zoomStep:=1.1playSpeed:=1playTimer:=10penSize:=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,-1coord:=cubeSize/2nodes:=[[-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(){globalD:=""fori,ninnodesD.=Sqrt((n.1-CP.1)**2+(n.2-CP.2)**2)"`t:"i":`t"n.3"`n"Sort,D,Np1:=StrSplit(StrSplit(D,"`n","`r").1,":").2p2:=StrSplit(StrSplit(D,"`n","`r").2,":").2hiddenNode:=nodes[p1,3]<nodes[p2,3]?p1:p2; Draw Facesloop%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)continuepoints:=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]+deltaYGdip_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 Edgesloop%edges.count(){n1:=edges[A_Index,1]n2:=edges[A_Index,2]if(n1=hiddenNode)||(n2=hiddenNode)continueGdip_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-axisglobaltheta*=3.141592653589793/180sinTheta:=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*sinThetanodes[A_Index,2]:=y*cosTheta+x*sinTheta}Redraw()}; ---------------------------------------------------------------rotateX3D(theta){ ; Rotate shape around the x-axisglobaltheta*=3.141592653589793/180sinTheta:=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*sinThetanodes[A_Index,3]:=z*cosTheta+y*sinTheta}Redraw()}; ---------------------------------------------------------------rotateY3D(theta){ ; Rotate shape around the y-axisglobaltheta*=3.141592653589793/180sinTheta:=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*sinThetanodes[A_Index,3]:=z*cosTheta-x*sinTheta}Redraw()}; ---------------------------------------------------------------Redraw(){globalgdip2()gdip1()draw()}; ---------------------------------------------------------------gdip1(){globalIf!pToken:=Gdip_Startup(){MsgBox,48,gdipluserror!,Gdiplusfailedtostart.PleaseensureyouhavegdiplusonyoursystemExitApp}OnExit,ExitWidth:=A_ScreenWidth,Height:=A_ScreenHeightGui,1:-Caption+E0x80000+LastFound+OwnDialogs+Owner+AlwaysOnTopGui,1:Show,NAhwnd1:=WinExist()hbm:=CreateDIBSection(Width,Height)hdc:=CreateCompatibleDC()obm:=SelectObject(hdc,hbm)G:=Gdip_GraphicsFromHDC(hdc)Gdip_SetSmoothingMode(G,4)TextColor:="FFFFFF00",size:=18Font:="Arial"Gdip_FontFamilyCreate(Font)pBrush:=Gdip_BrushCreateSolid(0xFFFF00FF)FaceBrush1:=Gdip_BrushCreateSolid(0xFF0000FF); blueFaceBrush2:=Gdip_BrushCreateSolid(0xFFFF0000) ; redFaceBrush3:=Gdip_BrushCreateSolid(0xFFFFFF00) ; yellowFaceBrush4:=Gdip_BrushCreateSolid(0xFFFF7518) ; orangeFaceBrush5:=Gdip_BrushCreateSolid(0xFF00FF00) ; limeFaceBrush6:=Gdip_BrushCreateSolid(0xFFFFFFFF) ; whitepPen:=Gdip_CreatePen(0xFF000000,penSize)}; ---------------------------------------------------------------gdip2(){globalGdip_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"returnrotateTimer:axis:=!axis?"Y":axisrotate%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,pmouseYwhileGetKeyState("Lbutton","P"){MouseGetPos,mouseX,mouseYDeltaMX:=mouseX-pmouseXDeltaMY:=pmouseY-mouseYif(DeltaMX||DeltaMY){MouseGetPos,pmouseX,pmouseYrotateY3D(DeltaMX)rotateX3D(DeltaMY)}}return; HotKey Rotate around Z-Axis ----------------------------------!RButton::MouseGetPos,pmouseX,pmouseYwhileGetKeyState("Rbutton","P"){MouseGetPos,mouseX,mouseYDeltaMX:=mouseX-pmouseXDeltaMY:=mouseY-pmouseYDeltaMX*=mouseY<deltaY?mouseStep:-mouseStepDeltaMY*=mouseX>deltaX?mouseStep:-mouseStepif(DeltaMX||DeltaMY){MouseGetPos,pmouseX,pmouseYrotateZ3D(DeltaMX)rotateZ3D(DeltaMY)}}return; HotKey, Move -------------------------------------------------+LButton::MouseGetPos,pmouseX,pmouseYwhileGetKeyState("Lbutton","P"){MouseGetPos,mouseX,mouseYdeltaX+=mouseX-pmouseXdeltaY+=mouseY-pmouseYpmouseX:=mouseXpmouseY:=mouseYRedraw()}return; ---------------------------------------------------------------^esc::Exit:gdip2()Gdip_Shutdown(pToken)ExitAppReturn; ---------------------------------------------------------------
global escalaglobal tamglobal zoffglobal cylrescala = 50tam = 320zoff = 0.5773502691896257645091487805019574556cylr = 1.6329931618554520654648560498039275946clggraphsize tam, tamdim x(6)theta = 0.0dtheta = 1.5dt = 1.0 / 30dim 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 whilesubroutine 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 iend subroutine100cls110graphics0120graphicscolor0,0,0130whiletrue140graphicscls150x=cos(t)*20160y=sin(t)*18170r=sin(t+t)180moveto(x+40),(y+40-r)190lineto(-y+40),(x+40-r)200moveto(-y+40),(x+40-r)210lineto(-x+40),(-y+40-r)220moveto(-x+40),(-y+40-r)230lineto(y+40),(-x+40-r)240moveto(y+40),(-x+40-r)250lineto(x+40),(y+40-r)260moveto(x+40),(y+20+r)270lineto(-y+40),(x+20+r)280moveto(-y+40),(x+20+r)290lineto(-x+40),(-y+20+r)300moveto(-x+40),(-y+20+r)310lineto(y+40),(-x+20+r)320moveto(y+40),(-x+20+r)330lineto(x+40),(y+20+r)340moveto(x+40),(y+40-r)350lineto(x+40),(y+20+r)360moveto(-y+40),(x+40-r)370lineto(-y+40),(x+20+r)380moveto(-x+40),(-y+40-r)390lineto(-x+40),(-y+20+r)400moveto(y+40),(-x+40-r)410lineto(y+40),(-x+20+r)420fori=1to1000:nexti430t=t+0.15440wend
100SCREEN2110WHILE1120CLS130X=COS(T)*20140Y=SIN(T)*18150R=SIN(T+T)160LINE((X+40),(Y+40-R))-((-Y+40),(X+40-R))170LINE((-Y+40),(X+40-R))-((-X+40),(-Y+40-R))180LINE((-X+40),(-Y+40-R))-((Y+40),(-X+40-R))190LINE((Y+40),(-X+40-R))-((X+40),(Y+40-R))200LINE((X+40),(Y+20+R))-((-Y+40),(X+20+R))210LINE((-Y+40),(X+20+R))-((-X+40),(-Y+20+R))220LINE((-X+40),(-Y+20+R))-((Y+40),(-X+20+R))230LINE((Y+40),(-X+20+R))-((X+40),(Y+20+R))240LINE((X+40),(Y+40-R))-((X+40),(Y+20+R))250LINE((-Y+40),(X+40-R))-((-Y+40),(X+20+R))260LINE((-X+40),(-Y+40-R))-((-X+40),(-Y+20+R))270LINE((Y+40),(-X+40-R))-((Y+40),(-X+20+R))280T=T+.15290WEND
100SCREEN2110COLOR15120CLS130X=COS(T)*20140Y=SIN(T)*18150R=SIN(T+T)160LINE((X+40),(Y+40-R))-((-Y+40),(X+40-R))170LINE((-Y+40),(X+40-R))-((-X+40),(-Y+40-R))180LINE((-X+40),(-Y+40-R))-((Y+40),(-X+40-R))190LINE((Y+40),(-X+40-R))-((X+40),(Y+40-R))200LINE((X+40),(Y+20+R))-((-Y+40),(X+20+R))210LINE((-Y+40),(X+20+R))-((-X+40),(-Y+20+R))220LINE((-X+40),(-Y+20+R))-((Y+40),(-X+20+R))230LINE((Y+40),(-X+20+R))-((X+40),(Y+20+R))240LINE((X+40),(Y+40-R))-((X+40),(Y+20+R))250LINE((-Y+40),(X+40-R))-((-Y+40),(X+20+R))260LINE((-X+40),(-Y+40-R))-((-X+40),(-Y+20+R))270LINE((Y+40),(-X+40-R))-((Y+40),(-X+20+R))280FORI=1TO40:NEXTI290T=T+0.15300GOTO120
Rotating wireframe cube inOpenGL, windowing implementation viafreeglut
#include<gl/freeglut.h>doublerot=0;floatmatCol[]={1,0,0,0};voiddisplay(){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();}voidonIdle(){rot+=0.1;glutPostRedisplay();}voidreshape(intw,inth){floatar=(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();}voidinit(){floatpos[]={1,1,1,0};floatwhite[]={1,1,1,0};floatshini[]={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);}intmain(intargC,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();return0;}
usingSystem;usingSystem.Drawing;usingSystem.Drawing.Drawing2D;usingSystem.Windows.Forms;usingSystem.Windows.Threading;namespaceRotatingCube{publicpartialclassForm1:Form{double[][]nodes={newdouble[]{-1,-1,-1},newdouble[]{-1,-1,1},newdouble[]{-1,1,-1},newdouble[]{-1,1,1},newdouble[]{1,-1,-1},newdouble[]{1,-1,1},newdouble[]{1,1,-1},newdouble[]{1,1,1}};int[][]edges={newint[]{0,1},newint[]{1,3},newint[]{3,2},newint[]{2,0},newint[]{4,5},newint[]{5,7},newint[]{7,6},newint[]{6,4},newint[]{0,4},newint[]{1,5},newint[]{2,6},newint[]{3,7}};publicForm1(){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)));vartimer=newDispatcherTimer();timer.Tick+=(s,e)=>{RotateCuboid(Math.PI/180,0);Refresh();};timer.Interval=newTimeSpan(0,0,0,0,17);timer.Start();}privatevoidRotateCuboid(doubleangleX,doubleangleY){doublesinX=Math.Sin(angleX);doublecosX=Math.Cos(angleX);doublesinY=Math.Sin(angleY);doublecosY=Math.Cos(angleY);foreach(varnodeinnodes){doublex=node[0];doubley=node[1];doublez=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;}}privatevoidScale(intv1,intv2,intv3){foreach(variteminnodes){item[0]*=v1;item[1]*=v2;item[2]*=v3;}}protectedoverridevoidOnPaint(PaintEventArgsargs){varg=args.Graphics;g.SmoothingMode=SmoothingMode.HighQuality;g.Clear(Color.White);g.TranslateTransform(Width/2,Height/2);foreach(varedgeinedges){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(varnodeinnodes){g.FillEllipse(Brushes.Black,(int)Math.Round(node[0])-4,(int)Math.Round(node[1])-4,8,8);}}}}
unitmain;interfaceusesWinapi.Windows,Vcl.Graphics,Vcl.Controls,Vcl.Forms,Vcl.ExtCtrls,System.Math,System.Classes;typeTForm1=class(TForm)tmr1:TTimer;procedureFormCreate(Sender:TObject);proceduretmr1Timer(Sender:TObject);private{ Private declarations }public{ Public declarations }end;varForm1: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}procedureScale(factor:TArray<double>);beginifLength(factor)<>3thenexit;forvari:=0toHigh(nodes)doforvarf:=0toHigh(factor)donodes[i][f]:=nodes[i][f]*factor[f];end;procedureRotateCuboid(angleX,angleY:double);beginvarsinX:=sin(angleX);varcosX:=cos(angleX);varsinY:=sin(angleY);varcosY:=cos(angleY);forvari:=0toHigh(nodes)dobeginvarx:=nodes[i][0];vary:=nodes[i][1];varz:=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;functionDrawCuboid(x,y,w,h:Integer):TBitmap;varoffset:TPoint;beginResult:=TBitmap.Create;Result.SetSize(w,h);rotateCuboid(PI/180,0);offset:=TPoint.Create(x,y);withResult.canvasdobeginBrush.Color:=clBlack;Pen.Color:=clWhite;Lock;FillRect(ClipRect);forvaredgeinedgesdobeginvarp1:=(nodes[edge[0]]);varp2:=(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;procedureTForm1.FormCreate(Sender:TObject);beginClientHeight:=360;ClientWidth:=640;DoubleBuffered:=true;scale([100,100,100]);rotateCuboid(PI/4,ArcTan(sqrt(2)));end;procedureTForm1.tmr1Timer(Sender:TObject);varbuffer:TBitmap;beginbuffer:=DrawCuboid(ClientWidthdiv2,ClientHeightdiv2,ClientWidth,ClientHeight);Canvas.Draw(0,0,buffer);buffer.Free;end;end.
Resource Form
objectForm1:TForm1OnCreate=FormCreateobjecttmr1:TTimerInterval=17OnTimer=tmr1Timerendend
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[] 3proc draw . gclear 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] gline x1 + 50 y1 + 50 x2 + 50 y2 + 50 . ..scale 25rotate 45 atan sqrt 2drawon animate rotate 1 0 draw.
Based on the solution in draw cuboid.Draws a filled cube with a texture on each face.
// We can define our own vec3 structstructvec3{x,y,z;}staticmodelMatrix[9];(){cls(0x828282);// clear screenclz(1e32);// clear depth buffersetcam(0,0,-3,0,0);// set camera some units back// create two local arrays to hold rotation matricesdoubleroty[9],rotz[9];staticotim;tim=klock(0);dt=tim-otim;otim=tim;staticdegrees=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 functionmult(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 valuevec3v={x,y,z};// Apply global model matrix transformationtransformPoint(v,modelMatrix);// Submit the vertex to draw listglVertex(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(vec3v,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 valuesv.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 Bfor(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;}}
#definePI3.14159265358979323#defineSCALE50#defineSIZE320#definezoff0.5773502691896257645091487805019574556#definecylr1.6329931618554520654648560498039275946screenresSIZE,SIZE,4dimasdoubletheta=0.0,dtheta=1.5,x(0to5),lasttime,dt=1./30dimasdoublecylphi(0to5)={PI/6,5*PI/6,3*PI/2,11*PI/6,PI/2,7*PI/6}subdrawcube(x()asdouble,colourasuinteger)foriasuinteger=0to2line(SIZE/2,SIZE/2-SCALE/zoff)-(x(i),SIZE/2-SCALE*zoff),colourline(SIZE/2,SIZE/2+SCALE/zoff)-(x(5-i),SIZE/2+SCALE*zoff),colourline(x(i),SIZE/2-SCALE*zoff)-(x(imod3+3),SIZE/2+SCALE*zoff),colourline(x(i),SIZE/2-SCALE*zoff)-(x((i+1)mod3+3),SIZE/2+SCALE*zoff),colournextiendsubwhileinkey=""lasttime=timerforiasuinteger=0to5x(i)=SIZE/2+SCALE*cylr*cos(cylphi(i)+theta)nextidrawcubex(),15whiletimer<lasttime+dtwendtheta+=dtheta*(timer-lasttime)drawcubex(),0wendend
FB 7.0.35 macOS 14.7.2 Sonoma
include "Tlbx SceneKit.incl"_window = 1begin enum output 1 _sceneViewend enumlocal 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 = scenevoid 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 fnvoid local fn DoDialog( ev as long, tag as long, wnd as long ) select (ev) case _windowWillClose : end end selectend fnon dialog fn DoDialogfn BuildWindowHandleEventsAs of Go 1.9, it looks as if the only standard library supporting animated graphics is image/gif - so we create an animated GIF...
packagemainimport("image""image/color""image/gif""log""math""os")const(width,height=640,640offset=height/2fileName="rotatingCube.gif")varnodes=[][]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}}varedges=[][]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}}funcmain(){varimages[]*image.PalettedfgCol:=color.RGBA{0xff,0x00,0xff,0xff}varpalette=[]color.Color{color.RGBA{0x00,0x00,0x00,0xff},fgCol}vardelays[]intimgFile,err:=os.Create(fileName)iferr!=nil{log.Fatal(err)}deferimgFile.Close()rotateCube(math.Pi/4,math.Atan(math.Sqrt(2)))varframefloat64forframe=0;frame<360;frame++{img:=image.NewPaletted(image.Rect(0,0,width,height),palette)images=append(images,img)delays=append(delays,5)for_,edge:=rangeedges{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)}iferr:=gif.EncodeAll(imgFile,&gif.GIF{Image:images,Delay:delays});err!=nil{imgFile.Close()log.Fatal(err)}}funcrotateCube(angleX,angleYfloat64){sinX:=math.Sin(angleX)cosX:=math.Cos(angleX)sinY:=math.Sin(angleY)cosY:=math.Cos(angleY)for_,node:=rangenodes{x:=node[0]y:=node[1]z:=node[2]node[0]=x*cosX-z*sinXnode[2]=z*cosX+x*sinXz=node[2]node[1]=y*cosY-z*sinYnode[2]=z*cosY+y*sinY}}funcdrawLine(x0,y0,x1,y1int,img*image.Paletted,colcolor.RGBA){dx:=abs(x1-x0)dy:=abs(y1-y0)varsx,syint=-1,-1ifx0<x1{sx=1}ify0<y1{sy=1}err:=dx-dyfor{img.Set(x0,y0,col)ifx0==x1&&y0==y1{break}e2:=2*errife2>-dy{err-=dyx0+=sx}ife2<dx{err+=dxy0+=sy}}}funcabs(xint)int{ifx<0{return-x}returnx}
This implementation compiles to JavaScript that runs in a browser using theghcjs compiler . Thereflex-dom library is used to help with svg rendering and animation.
{-# LANGUAGE RecursiveDo #-}importReflex.DomimportData.MapasDM(Map,lookup,insert,empty,fromList)importData.MatriximportData.Time.ClockimportControl.Monad.Transsize=500updateFrequency=0.2rotationStep=pi/10dataColor=Red|Green|Blue|Yellow|Orange|Purple|Blackderiving(Show,Eq,Ord,Enum)zRot::Float->MatrixFloatzRotrotation=letc=cosrotations=sinrotationinfromLists[[c,s,0,0],[-s,c,0,0],[0,0,1,0],[0,0,0,1]]xRot::Float->MatrixFloatxRotrotation=letc=cosrotations=sinrotationinfromLists[[1,0,0,0],[0,c,s,0],[0,-s,c,0],[0,0,0,1]]yRot::Float->MatrixFloatyRotrotation=letc=cosrotations=sinrotationinfromLists[[c,0,-s,0],[0,1,0,0],[s,0,c,0],[0,0,0,1]]translation::(Float,Float,Float)->MatrixFloattranslation(x,y,z)=fromLists[[1,0,0,0],[0,1,0,0],[0,0,1,0],[x,y,z,1]]scale::Float->MatrixFloatscales=fromLists[[s,0,0,0],[0,s,0,0],[0,0,s,0],[0,0,0,1]]-- perspective transformation;perspective::MatrixFloatperspective=fromLists[[1,0,0,0],[0,1,0,0],[0,0,1,1],[0,0,1,1]]transformPoints::MatrixFloat->MatrixFloat->[(Float,Float)]transformPointstransformpoints=letresult4d=points`multStd2`transformresult2d=(\[x,y,z,w]->(x/w,y/w))<$>toListsresult4dinresult2dshowRectangle::MonadWidgettm=>Float->Float->Float->Float->Color->Dynamict(MatrixFloat)->m()showRectanglex0y0x1y1faceColordFaceView=doletpoints=fromLists[[x0,y0,0,1],[x0,y1,0,1],[x1,y1,0,1],[x1,y0,0,1]]pointsToString=concatMap(\(x,y)->showx++", "++showy++" ")dAttrs<-mapDyn(\fvk->DM.fromList[("fill",showfaceColor),("points",pointsToString(transformPointsfvkpoints))])dFaceViewelDynAttrSVG"polygon"dAttrs$return()showUnitSquare::MonadWidgettm=>Color->Float->Dynamict(MatrixFloat)->m()showUnitSquarefaceColormargindFaceView=showRectanglemarginmargin(1.0-margin)(1.0-margin)faceColordFaceView-- show colored square on top of black square for outline effectshowFace::MonadWidgettm=>Color->Dynamict(MatrixFloat)->m()showFacefaceColordFaceView=doshowUnitSquareBlack0dFaceViewshowUnitSquarefaceColor0.03dFaceViewfacingCamera::[Float]->MatrixFloat->BoolfacingCameraviewPointmodelTransform=letcross[x0,y0,z0][x1,y1,z1]=[y0*z1-z0*y1,z0*x1-x0*z1,x0*y1-y0*x1]dotv0v1=sum$zipWith(*)v0v1vMinus=zipWith(-)untransformedPoints=fromLists[[0,0,0,1]-- lower left,[1,0,0,1]-- lower right,[0,1,0,1]]-- upper lefttransformedPoints=toLists$untransformedPoints`multStd2`modelTransformpt00=take3$headtransformedPoints-- transformed lower leftpt10=take3$transformedPoints!!1-- transformed upper rightpt01=take3$transformedPoints!!2-- transformed upper lefttVec_10_00=pt10`vMinus`pt00-- lower right to lower lefttVec_01_00=pt01`vMinus`pt00-- upper left to lower leftperpendicular=tVec_10_00`cross`tVec_01_00-- perpendicular to facecameraToPlane=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.incameraToPlane`dot`perpendicular<0faceView::MatrixFloat->MatrixFloat->(Bool,MatrixFloat)faceViewmodelOrientationfaceOrientation=letmodelTransform=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 cubeisFacingCamera=facingCamera[0,0,-1]modelTransform-- backface elimination-- combine to get single transform from 2d face to 2d displayviewTransform=modelTransform`multStd2`perspective`multStd2`scalesize-- scale up to svg box scale`multStd2`translation(size/2,size/2,0)-- move to center of svg boxin(isFacingCamera,viewTransform)updateFaceViews::MatrixFloat->MapColor(MatrixFloat)->(Color,MatrixFloat)->MapColor(MatrixFloat)updateFaceViewsmodelOrientationprevCollection(faceColor,faceOrientation)=let(isVisible,newFaceView)=faceViewmodelOrientationfaceOrientationinifisVisibletheninsertfaceColornewFaceViewprevCollectionelseprevCollectionfaceViews::MatrixFloat->MapColor(MatrixFloat)faceViewsmodelOrientation=foldl(updateFaceViewsmodelOrientation)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::MonadWidgettm=>Dynamict(MatrixFloat)->m()viewModelmodelOrientation=dofaceMap<-mapDynfaceViewsmodelOrientationlistWithKeyfaceMapshowFacereturn()view::MonadWidgettm=>Dynamict(MatrixFloat)->m()viewmodelOrientation=doel"h1"$text"Rotating Cube"elDynAttrSVG"svg"(constDyn$DM.fromList[("width",showsize),("height",showsize)])$viewModelmodelOrientationmain=mainWidget$doletinitialOrientation=xRot(pi/4)`multStd2`zRot(atan(1/sqrt(2)))update_modelOrientation=modelOrientation`multStd2`(yRot(rotationStep))tick<-tickLossyupdateFrequency=<<liftIOgetCurrentTimerecviewmodelOrientationmodelOrientation<-foldDynupdateinitialOrientationtickreturn()-- At end because of Rosetta Code handling of unmatched quotes.elDynAttrSVGa2a3a4=doelDynAttrNS'(Just"http://www.w3.org/2000/svg")a2a3a4return()
Link to live demo:https://dc25.github.io/drawRotatingCubeHaskell/
Derived from J'sqt 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'rplcfixosxHD=:".wd'qhwndc cube'wd'ptimer 17; pshow'}}rot_close=:{{wd'ptimer 0'glDeleteBuffers::0:2;vboglDeleteProgram::0:sprogerase'sprog'wd'pclose'}}cstr=:{{if.ydo.memry,0_12else.EMPTYend.}}gstr=:{{cstr>{.glGetStringy}}diag=:{{p[echoy,': ',p=.gstr".y}}blitf=:{{dat=.1fc,yNB. short floatsglBindBufferGL_ARRAY_BUFFER;x{vboglBufferDataGL_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.diageach;:'GL_VENDOR GL_RENDERER GL_SHADING_LANGUAGE_VERSION'GLSL=:wglGLSL''wglPROC'''err program'=.gl_makeprogramVSRC;&fixversionFSRCif.#errdo.echo'err: ',errreturn.end.if.GLSL>120do.vao=:>{:glGenVertexArrays1;,_1end.assert_1~:vertexAttr=:>{.glGetAttribLocationprogram;'vertex'assert_1~:colorAttr=:>{.glGetAttribLocationprogram;'color'assert_1~:mvpUni=:>{.glGetUniformLocationprogram;'mvp'vbo=:>{:glGenBuffers2;2#_10blitfvertexData1blitfcolorDatasprog=:program}}VSRC=:{{)n#version$version$v_in$highpvec3vertex;$v_in$lowpvec3color;$v_out$lowpvec4v_color;uniformmat4mvp;voidmain(void){gl_Position=mvp*vec4(vertex,1.0);v_color=vec4(color,1.0);}}}FSRC=:{{)n#version$version$f_in$lowpvec4v_color;$fragColorvoidmain(void){$gl_fragColor=v_color;}}}fixversion=:{{NB. cope with host shader language versionr=.'$version';GLSL,&":;(GLSL>:300)#(*GLES_VERSION){' core';' es'f1=.GLSL<:120r=.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_VERSIONr=.r,'$gl_fragColor';f2{'gl_FragColor';'fragColor'r=.r,'$fragColor';f2#'out vec4 fragColor;'yrplcr}}rot_timer=:{{try.gl_selHDgl_paint''catch.echo'error in rot_timer',LF,13!:12''wd'ptimer 0'end.}}zeroVAttr=:{{glEnableVertexAttribArrayyglBindBufferGL_ARRAY_BUFFER;x{vboglVertexAttribPointery;3;GL_FLOAT;0;0;0}}mp=:+/.*ref=:(gl_Translate00_10)mpglu_LookAt001,000,100rot_cube_paint=:{{try.if.nc<'sprog'do.return.end.wh=.gl_qwh''glClearGL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT[glClearColor0000+%3glUseProgramsprogglEnableeachGL_DEPTH_TEST,GL_CULL_FACE,GL_BLENDglBlendFuncGL_SRC_ALPHA;GL_ONE_MINUS_SRC_ALPHAmvp=.(gl_Rotate(360|60*6!:1''),100)mprefmpgl_Perspective30,(%/wh),120glUniformMatrix4fvmvpUni;1;GL_FALSE;mvpif.GLSL>120do.glBindVertexArray{.vaoend.0zeroVAttrvertexAttr1zeroVAttrcolorAttrglDrawArraysGL_TRIANGLES;0;36glUseProgram0catch.echo'error in rot_cube_paint',LF,13!:12''wd'ptimer 0'end.}}NB. oriented triangle representation of unit cubeunitCube=:#:(012,213)&{@".;._2{{)n2301NB. unit cube corner indices3715NB. 0: origin4051NB. 1, 2, 4: unit distance along each axis6240NB. 3, 5, 6, 7: combinations of axes76547362}}NB. orient cube so diagonal is along first axisdaxis=:(_1^56e.~i.33)*%:6%~204,231,:231vertexData=:(_1^unitCube)mpdaxisNB. cube with center at origincolorData=:unitCubeNB. corresponding colorsrotcube''
A variation which did not use opengl would probably be much more concise.

importjava.awt.*;importjava.awt.event.ActionEvent;import staticjava.lang.Math.*;importjavax.swing.*;publicclassRotatingCubeextendsJPanel{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}};publicRotatingCube(){setPreferredSize(newDimension(640,640));setBackground(Color.white);scale(100);rotateCube(PI/4,atan(sqrt(2)));newTimer(17,(ActionEvente)->{rotateCube(PI/180,0);repaint();}).start();}finalvoidscale(doubles){for(double[]node:nodes){node[0]*=s;node[1]*=s;node[2]*=s;}}finalvoidrotateCube(doubleangleX,doubleangleY){doublesinX=sin(angleX);doublecosX=cos(angleX);doublesinY=sin(angleY);doublecosY=cos(angleY);for(double[]node:nodes){doublex=node[0];doubley=node[1];doublez=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;}}voiddrawCube(Graphics2Dg){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);}@OverridepublicvoidpaintComponent(Graphicsgg){super.paintComponent(gg);Graphics2Dg=(Graphics2D)gg;g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);drawCube(g);}publicstaticvoidmain(String[]args){SwingUtilities.invokeLater(()->{JFramef=newJFrame();f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);f.setTitle("Rotating Cube");f.setResizable(false);f.add(newRotatingCube(),BorderLayout.CENTER);f.pack();f.setLocationRelativeTo(null);f.setVisible(true);});}}
<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><style>canvas{background-color:black;}</style></head><body><canvas></canvas><script>varcanvas=document.querySelector("canvas");canvas.width=window.innerWidth;canvas.height=window.innerHeight;varg=canvas.getContext("2d");varnodes=[[-1,-1,-1],[-1,-1,1],[-1,1,-1],[-1,1,1],[1,-1,-1],[1,-1,1],[1,1,-1],[1,1,1]];varedges=[[0,1],[1,3],[3,2],[2,0],[4,5],[5,7],[7,6],[6,4],[0,4],[1,5],[2,6],[3,7]];functionscale(factor0,factor1,factor2){nodes.forEach(function(node){node[0]*=factor0;node[1]*=factor1;node[2]*=factor2;});}functionrotateCuboid(angleX,angleY){varsinX=Math.sin(angleX);varcosX=Math.cos(angleX);varsinY=Math.sin(angleY);varcosY=Math.cos(angleY);nodes.forEach(function(node){varx=node[0];vary=node[1];varz=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;});}functiondrawCuboid(){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){varp1=nodes[edge[0]];varp2=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>
Run at the Julia REPL command line.
usingMakie,LinearAlgebraN=40interval=0.10scene=mesh(FRect3D(Vec3f0(-0.5),Vec3f0(1)),color=:skyblue2)rect=scene[end]forradin0.5:1/N:8.5arr=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
// version 1.1importjava.awt.*importjavax.swing.*classRotatingCube:JPanel(){privatevalnodes=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))privatevaledges=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.whitescale(100.0)rotateCube(Math.PI/4.0,Math.atan(Math.sqrt(2.0)))Timer(17){rotateCube(Math.PI/180.0,0.0)repaint()}.start()}privatefunscale(s:Double){for(nodeinnodes){node[0]*=snode[1]*=snode[2]*=s}}privatefunrotateCube(angleX:Double,angleY:Double){valsinX=Math.sin(angleX)valcosX=Math.cos(angleX)valsinY=Math.sin(angleY)valcosY=Math.cos(angleY)for(nodeinnodes){valx=node[0]valy=node[1]varz=node[2]node[0]=x*cosX-z*sinXnode[2]=z*cosX+x*sinXz=node[2]node[1]=y*cosY-z*sinYnode[2]=z*cosY+y*sinY}}privatefundrawCube(g:Graphics2D){g.translate(width/2,height/2)for(edgeinedges){valxy1=nodes[edge[0]]valxy2=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(nodeinnodes){g.fillOval(Math.round(node[0]).toInt()-4,Math.round(node[1]).toInt()-4,8,8)}}overridepublicfunpaintComponent(gg:Graphics){super.paintComponent(gg)valg=ggasGraphics2Dg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON)g.color=Color.bluedrawCube(g)}}funmain(args:Array<String>){SwingUtilities.invokeLater{valf=JFrame()f.defaultCloseOperation=JFrame.EXIT_ON_CLOSEf.title="Rotating cube"f.isResizable=falsef.add(RotatingCube(),BorderLayout.CENTER)f.pack()f.setLocationRelativeTo(null)f.isVisible=true}}
localabs,atan,cos,floor,pi,sin,sqrt=math.abs,math.atan,math.cos,math.floor,math.pi,math.sin,math.sqrtlocalbitmap={init=function(self,w,h,value)self.w,self.h,self.pixels=w,h,{}fory=1,hdoself.pixels[y]={}endself:clear(value)end,clear=function(self,value)fory=1,self.hdoforx=1,self.wdoself.pixels[y][x]=valueor" "endendend,set=function(self,x,y,value)x,y=floor(x),floor(y)ifx>0andy>0andx<=self.wandy<=self.hthenself.pixels[y][x]=valueor"#"endend,line=function(self,x1,y1,x2,y2,c)x1,y1,x2,y2=floor(x1),floor(y1),floor(x2),floor(y2)localdx,sx=abs(x2-x1),x1<x2and1or-1localdy,sy=abs(y2-y1),y1<y2and1or-1localerr=floor((dx>dyanddxor-dy)/2)while(true)doself:set(x1,y1,c)if(x1==x2andy1==y2)thenbreakendif(err>-dx)thenerr,x1=err-dy,x1+sxif(x1==x2andy1==y2)thenself:set(x1,y1,c)breakendendif(err<dy)thenerr,y1=err+dx,y1+syendendend,render=function(self)fory=1,self.hdoprint(table.concat(self.pixels[y]))endend,}screen={clear=function()os.execute("cls")-- or? os.execute("clear"), or? io.write("\027[2J\027[H"), or etc?end,}localcamera={fl=2.5}localL=0.5localcube={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)localcx,sx=cos(rx),sin(rx)localcy,sy=cos(ry),sin(ry)fori,vinipairs(self.verts)dolocalx,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*cyendend,}localrenderer={render=function(self,shape,camera,bitmap)localfl=camera.fllocalox,oy=bitmap.w/2,bitmap.h/2localmx,my=bitmap.w/2,bitmap.h/2localrpverts={}fori,vinipairs(shape.verts)dolocalx,y,z=v[1],v[2],v[3]localpx=ox+mx*(fl*x)/(fl-z)localpy=oy+my*(fl*y)/(fl-z)rpverts[i]={px,py}endfori,einipairs(shape.edges)dolocalv1,v2=rpverts[e[1]],rpverts[e[2]]bitmap:line(v1[1],v1[2],v2[1],v2[2],"██")endend}--bitmap:init(40,40)cube:rotate(pi/4,atan(sqrt(2)))fori=1,60docube:rotate(pi/60,0)bitmap:clear("··")renderer:render(cube,camera,bitmap)screen:clear()bitmap:render()end
Frame 1:······················································································································██············································································██████········································································████····██····································································██··██······██································································██····██········██····························································██······██··········██··························································██······██············██······················································██······██················██··················································██········██··················██··············································██········████····················██··········································██········██····██····················██······································██········██········██····················██··································██········██············██····················██······························██········██················██················████······························████····██····················██············██····██··························██····████························██········██······██························██······████··························██····██········██························██····██····████························████············██····················██····██··········██······················████············██····················██··██··············██················████····██··········██··················██··██··················████··········██··········██··········██················████························██······██··············████······██··············████····························██████····················██····██··············██································██························██··██············██··································██··························██··██············██································██····························████··············████····························██························████······················██··························██······················██····························████······················██··················████··································████··················██··············████··········································██················██············██················································████············██········████······················································██··········██······██····························································████······██··████··································································████··████··········································································████························································································································································································································································································Frame 60:······················································································································██············································································██████········································································██··██··██··································································████····██····████····························································██········██········██······················································████··········██··········████··············································████··············██··············██··········································██··················██················██····································████····················██··················████······························██························██······················██························████··························██························████················████······························██····························████············████······························██····························████··············████····························████························████················██··██························██····██····················██··██··················██··██····················██········████··············██····██··················██····██··············████··············██··········██····██····················██······██··········██····················██······██······██······················██······██······██························██████········██······················██········██████····························████······██························██········████····························██····██····██··························██··████····██························██········████····························████··········████··················██············██······························██··············██··············██············██··································██··············██··········██············██······································██··············██······██············██··········································██··············██████············██··············································██··············██············██··················································██············██············██····················································██··········██··········██························································██········██········██····························································██······██······██································································██····██····██····································································██··██··██········································································██████············································································██························································································································································································································································································

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, 32smooth on // enable GDI+ smooth lineszoff=0.5773502691896257645091487805019574556@cylr=1.6329931618554520654648560498039275946@oX=scale.x div 2 : oY=scale.y div 2SCALE=min.data(oX, oY)/2*.6gradient 0theta = 0.0 : dtheta = 1.5 : dt = 1000/60ScZof=SCALE/zoffScZofM=SCALE*zoffdim 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 Degreeevery DT {if mouse then (oX, oY)=(mouse.x,mouse.y) : dtheta*=1.05 else dtheta = 1.5dim x(6)=oX : for i=0 to 5: x(i) += SCALE*cylr*cos(cylphi(i)+theta):nextdrawcube() : refresh 100 : IF keypress(32) then exittheta += dtheta : gradient 0, 5: cursor 0,0Print "Press space to exit",,"Press any mouse button to move cube",,Time$(Now)}sub drawcube()for i= 0 to 2move x(i), oY-ScZofM:draw to oX,oY-ScZof, 11move oX,ScZof+oY:draw to x(i),oY-ScZofM, 9move oX,oY+ ScZof:draw to x(5-i),ScZofM+oYmove x(i),oY-ScZofM:draw to x(i mod 3 + 3),oY+ScZofM, 15move oX,oY-ScZof:draw to x(i mod 3 + 3), oY+ScZofM, 7move x(i),oY-ScZofM:draw to x((i+1) mod 3 + 3),oY+ScZofM, 13nextend sub}Cube3Dplots:-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);
Dynamic[Graphics3D[GeometricTransformation[GeometricTransformation[Cuboid[],RotationTransform[Pi/4,{1,1,0}]],RotationTransform[Clock[2Pi],{0,0,1}]],Boxed->False]]
import"mathUtil"scale=250radius=sqrt(scale^2)Face=newSpriteFace.image=file.loadImage("/sys/pics/shapes/SquareThin.png")clear;gfx.clearcolor.graysprites=display(4).sprites// build a sprite for each sideforiinrange(0,3)sp=newFacesp.x=480;sp.y=320yBot=-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.pushspendfor// ...and one for the toptop=newFacetop.x=480;top.y=320top.corners3d=[]foriinrange(0,3)top.corners3d.push[cos(i*pi/2),sin(pi/4),sin(i*pi/2)]endforsprites.pushtop// 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/180cosAng=cos(radians);sinAng=sin(radians)// First, rotate around the Y axis in 3D spacex=point3d[0]*cosAng-point3d[2]*sinAngy=point3d[1]z=point3d[0]*sinAng+point3d[2]*cosAng// Then, project this to the screenresult=[480+x*scale,320+y*scale+z*0]p=(8-z)/8// (perspective factor)returnmathUtil.lerp2d(result,[480,800],1-p)endfunction// Position all the sprites where they should be on screen for the given rotation.positionSprites=function(rotDegrees)forspinspritescorners=[]foriinrange(0,3)corners.pushrotateAndProject(sp.corners3d[i],rotDegrees)endforsp.setCornerscornersifsp==topthencontinueifcorners[1][0]>corners[0][0]thensp.tint=sp.colorelsesp.tint=color.clearendifendforendfunction// Main programrot=0whilenotkey.pressed("escape")andnotkey.pressed("q")yieldpositionSpritesrotrot=rot+1endwhilekey.clear
importmathimportsdl2constWidth=500Height=500Offset=500/2varnodes=[(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)]constEdges=[(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)]varwindow:WindowPtrrenderer:RendererPtrevent:EventendSimulation=false#---------------------------------------------------------------------------------------------------procrotateCube(angleX,angleY:float)=letsinX=sin(angleX)cosX=cos(angleX)sinY=sin(angleY)cosY=cos(angleY)fornodeinnodes.mitems:var(x,y,z)=nodenode.x=x*cosX-z*sinXnode.z=z*cosX+x*sinXz=node.znode.y=y*cosY-z*sinYnode.z=z*cosY+y*sinY#---------------------------------------------------------------------------------------------------procpollQuit():bool=whilepollEvent(event):ifevent.kind==QuitEvent:returntrue#---------------------------------------------------------------------------------------------------procdrawCube():bool=varrect:Rect=(cint(0),cint(0),cint(Width),cint(Height))rotateCube(PI/4,arctan(sqrt(2.0)))forframein0..359:renderer.setDrawColor((0u8, 0u8, 0u8, 255u8))renderer.fillRect(addr(rect))renderer.setDrawColor((0u8, 220u8, 0u8, 255u8))foredgeinEdges:letxy1=nodes[edge.a]letxy2=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()ifpollQuit():returntruedelay10#———————————————————————————————————————————————————————————————————————————————————————————————————ifsdl2.init(INIT_EVERYTHING)==SdlError:quit(QuitFailure)window=createWindow("Rotating cube",10,10,500,500,0)renderer=createRenderer(window,-1,Renderer_Accelerated)whilenotendSimulation:endSimulation=drawCube()window.destroy()
#~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}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
usesGraph3D;beginvarCube:=Box(Origin,Sz3D(3,3,3),Colors.Green);Cube.AnimRotate(OrtZ,180).Forever.Beginend.
#!/usr/bin/perlusestrict;# http://www.rosettacode.org/wiki/Draw_a_rotating_cubeusewarnings;useTk;useTime::HiResqw( time );my$size=600;my$wait=int1000/30;my($height,$width)=($size,$size*sqrt8/9);my$mid=$width/2;my$rot=atan2(0,-1)/3;# middle corners every 60 degreesmy$mw=MainWindow->new;my$c=$mw->Canvas(-width=>$width,-height=>$height)->pack;$c->Tk::bind('<ButtonRelease>'=>sub{$mw->destroy});# click to exitdraw();MainLoop;subdraw{my$angle=time-$^T;# full rotation every 2*PI secondsmy@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);}
You can run this onlinehere.
---- 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).--withjavascript_semanticsincludepGUI.econstanttitle="Draw a Rotating Cube"Ihandledlg,canvascdCanvascd_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.)--enumX,Y,Zconstantl=100constantcorners={{+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.constantfaces={{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 timeratomrx=45,-- initially makes cube like a Hry=35,-- " " "italic Hrz=0constantnaxes={{Y,Z},-- (rotate about the X-axis){X,Z},-- (rotate about the Y-axis){X,Y}}-- (rotate about the Z-axis)functionrotate(sequencepoints,atomangle,integeraxis)---- rotate points by the specified angle about the given axis--atomradians=angle*CD_DEG2RAD,sin_t=sin(radians),cos_t=cos(radians)integer{nx,ny}=naxes[axis]fori=1tolength(points)doatomx=points[i][nx],y=points[i][ny]points[i][nx]=x*cos_t-y*sin_tpoints[i][ny]=y*cos_t+x*sin_tendforreturnpointsendfunctionfunctionprojection(sequencepoints,atomd)---- project points from {0,0,d} onto the perpendicular plane through {0,0,0}--fori=1tolength(points)doatom{x,y,z}=points[i],denom=(1-z/d)points[i][X]=x/denompoints[i][Y]=y/denomendforreturnpointsendfunctionfunctionnearest(sequencepoints)---- return the index of the nearest point (highest z value)--returnlargest(vslice(points,Z),true)endfunctionproceduredraw_cube(integercx,cy)-- {cx,cy} is the centre point of the canvassequencepoints=deep_copy(corners)points=rotate(points,rx,X)points=rotate(points,ry,Y)points=rotate(points,rz,Z)points=projection(points,1000)integernp=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.) --sequencefaceset={}fori=1tolength(faces)dosequencefi=faces[i]integerk=find(np,fi)-- k:=2..5, or 0ifkthenintegerdiag=mod(k,4)+2-- {2,3,4,5} --> {4,5,2,3} -- aka swap 2<=>4 & 3<=>5diag=fi[diag]-- 1..8, diagonally opp. npfaceset=append(faceset,{points[diag][Z],i})-- else-- faceset = append(faceset,{-9999,i})endifendforfaceset=sort(faceset)fori=1tolength(faceset)dosequenceface=faces[faceset[i][2]]cdCanvasSetForeground(cd_canvas,face[1])-- first fill sides (with bresenham edges), then -- redraw edges, but anti-aliased aka smoothersequencemodes={CD_FILL,CD_CLOSED_LINES}form=1tolength(modes)docdCanvasBegin(cd_canvas,modes[m])forfdx=2to5dosequencept=points[face[fdx]]cdCanvasVertex(cd_canvas,cx+pt[X],cy-pt[Y])endforcdCanvasEnd(cd_canvas)endforendforendprocedurefunctioncanvas_action_cb(Ihandlecanvas)cdCanvasActivate(cd_canvas)cdCanvasClear(cd_canvas)integer{w,h}=IupGetIntInt(canvas,"DRAWSIZE")draw_cube(floor(w/2),floor(h/2))cdCanvasFlush(cd_canvas)returnIUP_DEFAULTendfunctionfunctioncanvas_map_cb(Ihandlecanvas)IupGLMakeCurrent(canvas)ifplatform()=JSthencd_canvas=cdCreateCanvas(CD_IUP,canvas)elseatomres=IupGetDouble(NULL,"SCREENDPI")/25.4cd_canvas=cdCreateCanvas(CD_GL,"10x10 %g",{res})endifcdCanvasSetBackground(cd_canvas,CD_PARCHMENT)returnIUP_DEFAULTendfunctionfunctioncanvas_resize_cb(Ihandle/*canvas*/)integer{canvas_width,canvas_height}=IupGetIntInt(canvas,"DRAWSIZE")atomres=IupGetDouble(NULL,"SCREENDPI")/25.4cdCanvasSetAttribute(cd_canvas,"SIZE","%dx%d %g",{canvas_width,canvas_height,res})returnIUP_DEFAULTendfunctionfunctiontimer_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)returnIUP_IGNOREendfunctionproceduremain()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)IhandlehTimer=IupTimer(Icallback("timer_cb"),30)ifplatform()!=JSthenIupMainLoop()IupClose()endifendproceduremain()
Don't send this to your printer!
%!PS-Adobe-3.0%%BoundingBox: 0 0 400 400/ed{exchdef}def/roty{dupsin/sedcos/ced[[c0sneg][010][s0c]]}def/rotz{dupsin/sedcos/ced[[csneg0][sc0][001]]}def/dot{/aed/beda0getb0getmula1getb1getmula2getb2getmuladdadd}def/mmul{/ved[exch{vdot}forall]}def/transall{/med[exch{mexchmmul}forall]}def/vt[[111][-111][1-11][-1-11][11-1][-11-1][1-1-1][-1-1-1]]-45rotytransall2sqrt1atanrotztransalldef/xy{exchget{}forallpop}def/page{/aed/vvtarotytransalldef0setlinewidth100100scale22translate/edge{vxymovetovxylinetostroke}def0123456702134657041526371112{popedge}forshowpage}def0{3.2addduppage}loop%%EOF
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);}See also:Draw_a_cuboid
fromvisualimport*scene.title="VPython: Draw a rotating cube"scene.range=2scene.autocenter=Trueprint"Drag with right mousebutton to rotate view."print"Drag up+down with middle mousebutton to zoom."deg45=math.radians(45.0)# 0.785398163397cube=box()# using defaults, see http://www.vpython.org/contents/docs/defaults.htmlcube.rotate(angle=deg45,axis=(1,0,0))cube.rotate(angle=deg45,axis=(0,0,1))whileTrue:# Animation-looprate(50)cube.rotate(angle=0.005,axis=(0,1,0))
#langracket/gui(requiremath/matrixmath/array)(define(Rxθ)(matrix[[1.00.00.0][0.0(cosθ)(-(sinθ))][0.0(sinθ)(cosθ)]]))(define(Ryθ)(matrix[[(cosθ)0.0(sinθ)][0.01.00.0][(-(sinθ))0.0(cosθ)]]))(define(Rzθ)(matrix[[(cosθ)(-(sinθ))0.0][(sinθ)(cosθ)0.0][0.00.01.0]]))(definebase-matrix(matrix*(identity-matrix3100.0)(Rx(-(/pi2)(atan(sqrt2))))(Rz(/pi4.0))))(define(current-matrix)(matrix*(Ry(/(current-inexact-milliseconds)1000.))base-matrix))(definecorners(for*/list([x'(-1.01.0)][y'(-1.01.0)][z'(-1.01.0)])(matrix[[x][y][z]])))(definelines'((01)(02)(04)(13)(15)(23)(26)(37)(45)(46)(57)(67)))(defineox200.)(defineoy200.)(define(draw-linedcab)(senddcdraw-line(+ox(array-refa#(00)))(+oy(array-refa#(10)))(+ox(array-refb#(00)))(+oy(array-refb#(10)))))(define(draw-cubecdc)(define-values(wh)(senddcget-size))(set!ox(/w2))(set!oy(/h2))(definecs(for/vector([c(in-listcorners)])(matrix*(current-matrix)c)))(for([l(in-listlines)])(match-define(listij)l)(draw-linedc(vector-refcsi)(vector-refcsj))))(definef(newframe%[label"cube"]))(definec(newcanvas%[parentf][min-width400][min-height400][paint-callbackdraw-cube]))(sendfshow#t)(send*(sendcget-dc)(set-pen"black"1'solid)(set-smoothing'smoothed))(define(refresh)(sendcrefresh))(definet(newtimer%[notify-callbackrefresh][interval35][just-once?#f]))
(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 toLibcaca, theColorASCIIArt library to generate a rotating cube in an ASCII terminal.
useTerminal::Caca;givenmy$canvas =Terminal::Caca.new { .title('Rosetta Code - Rotating cube - Press any key to exit');subscale-and-translate($x,$y,$z) {$x *5 / (5 +$z ) *15 +40,$y *5 / (5 +$z ) *7 +15,$z; }subrotate3d-x($x,$y,$z,$angle ) {my ($cosθ,$sinθ) =cis($angle *π /180.0 ).reals;$x,$y *$cosθ -$z *$sinθ,$y *$sinθ +$z *$cosθ; }subrotate3d-y($x,$y,$z,$angle ) {my ($cosθ,$sinθ) =cis($angle *π /180.0 ).reals;$x *$cosθ -$z *$sinθ,$y,$x *$sinθ +$z *$cosθ; }subrotate3d-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 axesmy@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 taskfor ^@meshX ^@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 facesmy@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++div2],points =>@points,avg-z =>$sum-z / +@points; ); }# Draw all faces# Sort by z to draw farthest firstfor@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;exitif .wait-for-event(key-press); } }# Cleanup on scope exitLEAVE { .cleanup; }}
#===================================================================## Based on Original Sample from RayLib (https://www.raylib.com/)# Ported to RingRayLib by Ring Team#===================================================================#load "raylib.ring"screenWidth = 800screenHeight = 450InitWindow(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 = falseSetCameraMode(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 okok 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()endCloseWindow()importjava.awt.event.ActionEventimportjava.awt._importjavax.swing.{JFrame,JPanel,Timer}importscala.math.{Pi,atan,cos,sin,sqrt}objectRotatingCubeextendsApp{classRotatingCubeextendsJPanel{privatevalvertices: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))privatevaledges: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(newDimension(640,640))setBackground(Color.white)scale(100)rotateCube(Pi/4,atan(sqrt(2)))newTimer(17,(_:ActionEvent)=>{rotateCube(Pi/180,0)repaint()}).start()overridedefpaintComponent(gg:Graphics):Unit={defdrawCube(g:Graphics2D):Unit={g.translate(getWidth/2,getHeight/2)for{edge<-edgesxy1: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)valg:Graphics2D=gg.asInstanceOf[Graphics2D]g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON)drawCube(g)}privatedefscale(s:Double):Unit={for{node<-verticesi<-node.indices}node(i)*=s}privatedefrotateCube(angleX:Double,angleY:Double):Unit={defsinCos(x:Double)=(sin(x),cos(x))val((sinX,cosX),(sinY,cosY))=(sinCos(angleX),sinCos(angleY))for{node<-verticesx:Double=node(0)y:Double=node(1)}{deff(p:Double,q:Double)(a:Double,b:Double)=a*p+b*qdeffx(a:Double,b:Double)=f(cosX,sinX)(a,b)deffy(a:Double,b:Double)=f(cosY,sinY)(a,b)node(0)=fx(x,-node(2))valz=fx(node(2),x)node(1)=fy(y,-z)node(2)=fy(z,y)}}}newJFrame("Rotating Cube"){add(newRotatingCube(),BorderLayout.CENTER)pack()setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE)setLocationRelativeTo(null)setResizable(false)setVisible(true)}}
See alsoDraw a cuboid. This implementation uses tcllib'sLinear 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".
Seethis wiki page (and others linked from it) for many similar examples.
# matrix operation support:packagerequiremath::linearalgebranamespaceimport::math::linearalgebra::matmulnamespaceimport::math::linearalgebra::crossproductnamespaceimport::math::linearalgebra::dotproductnamespaceimport::math::linearalgebra::sub# returns a cube as a list of faces,# where each face is a list of (3space) pointsprocmake_cube{{radius1}}{setdirs{A{111}B{11-1}C{1-1-1}D{1-11}E{-111}F{-11-1}G{-1-1-1}H{-1-11}}setfaces{{ABCD}{DCGH}{HGFE}{EFBA}{ADHE}{CBFG}}lmapfa$faces{lmapdir$fa{lmapx[dictget$dirs$dir]{expr{1.0*$x*$radius}}}}}# a matrix constructorprocMatrix{m}{tailcalllmaprow$m{lmape$row{expr1.0*($e)}}}procidentity{}{Matrix{{100}{010}{001}}}# some matrices useful for animation:procrotateZ{theta}{Matrix{{cos($theta)-sin($theta)0}{sin($theta)cos($theta)0}{001}}}procrotateY{theta}{Matrix{{sin($theta)0cos($theta)}{010}{cos($theta)0-sin($theta)}}}procrotateX{theta}{Matrix{{100}{0cos($theta)-sin($theta)}{0sin($theta)cos($theta)}}}proccamera{flen}{Matrix{{$flen00}{0$flen0}{000}}}procrender{canvasobject}{setW[winfowidth$canvas]setH[winfoheight$canvas]setfl1.0sett[expr{[clockmicroseconds]/1000000.0}]settransform[identity]settransform[matmul$transform[rotateX[expr{atan(1)}]]]settransform[matmul$transform[rotateZ[expr{atan(1)}]]]settransform[matmul$transform[rotateY$t]]settransform[matmul$transform[camera$fl]]foreachface$object{# do transformations into screen space:setpoints[lmapp$face{matmul$p$transform}]# calculate a normalseto[lindex$points0]setv1[sub[lindex$points1]$o]setv2[sub[lindex$points2]$o]setnormal[crossproduct$v1$v2]setcosi[dotproduct$normal{00-1.0}]if{$cosi<=0}{;# rear-facing!continue}setpoints[lmapp$points{lassign$pxylist[expr{$x+$W/2}][expr{$y+$H/2}]}]setpoints[concat{*}$points]$canvascreatepoly$points-outlineblack-fillred}}packagerequireTkpack[canvas.c]-expandyes-fillbothproctick{}{.cdeleteallrender.c$::worldafter50tick}set::world[make_cube100]tick
:-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.
import"graphics"forCanvas,Colorimport"dome"forWindowimport"math"forMathvarNodes=[[-1,-1,-1],[-1,-1,1],[-1,1,-1],[-1,1,1],[1,-1,-1],[1,-1,1],[1,1,-1],[1,1,1]]varEdges=[[0,1],[1,3],[3,2],[2,0],[4,5],[5,7],[7,6],[6,4],[0,4],[1,5],[2,6],[3,7]]classRotatingCube{constructnew(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(nodeinNodes){node[0]=node[0]*snode[1]=node[1]*snode[2]=node[2]*s}}drawCube(){Canvas.cls(Color.white)Canvas.offset(_width/2,_height/2)for(edgeinEdges){varxy1=Nodes[edge[0]]varxy2=Nodes[edge[1]]Canvas.line(Math.round(xy1[0]),Math.round(xy1[1]),Math.round(xy2[0]),Math.round(xy2[1]),_fore)}for(nodeinNodes){Canvas.rectfill(Math.round(node[0])-4,Math.round(node[1])-4,8,8,_fore)}}rotateCube(angleX,angleY){varsinX=Math.sin(angleX)varcosX=Math.cos(angleX)varsinY=Math.sin(angleY)varcosY=Math.cos(angleY)for(nodeinNodes){varx=node[0]vary=node[1]varz=node[2]node[0]=x*cosX-z*sinXnode[2]=z*cosX+x*sinXz=node[2]node[1]=y*cosY-z*sinYnode[2]=z*cosY+y*sinY}}}varGame=RotatingCube.new(640,640)
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 speedreal X, Y, Z, Farthest; \arrays: 3D coordinates of verticesint 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 graphicsrepeat 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 struckSetVid(3); \restore normal text mode]
http://www.xpl0.org/rotcube2.gif
// 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 rotationopen window 50, 70backcolor 0,0,0clear windowcolor 255,255,255do 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.15loop
conststd=@import("std");constc=@cImport({@cInclude("raylib.h");@cInclude("rlgl.h");});constdark_mode=true;constshow_grid=false;pubfnmain()!void{constscreen_width=640;constscreen_height=360;constcube_side=1;constsize=c.Vector3{.x=cube_side,.y=cube_side,.z=cube_side};constposition=c.Vector3{.x=0,.y=0,.z=0};constx_rot=45;consty_center:f32=std.math.sqrt(3.0)*cube_side/2.0;constz_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");deferc.CloseWindow();varcamera=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();deferc.EndDrawing();c.ClearBackground(if(dark_mode)c.BLACKelsec.RAYWHITE);{c.BeginMode3D(camera);deferc.EndMode3D();{c.rlPushMatrix();deferc.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.LIMEelsec.BLACK);}if(show_grid)c.DrawGrid(12,0.75);}}}