{**************************************************************************** Author: DeveloCAD.com Web: http://www.DeveloCAD.com Email: info@develocad.com Contents: Tutorial for how to create an ActiveX component with CAD/graphics functionality control the rubic cube with: - left mouse button on a cube side --> rotate counterclockwise - left mouse button with Ctrl key on a cube side --> rotate clockwise - left mouse button while mousemove (outside the cube) --> rotate the scene - left mouse button while mousemove (outside the cube) with Ctrl key pressed --> transform the scene in x and y - left mouse button while mousemove (outside the cube) with Shift key pressed --> transform the scene in z - right mouse button --> highlights a popup menu ****************************************************************************} unit _axRubic; // check the Delphi version {$IFDEF VER150} {$WARN SYMBOL_PLATFORM OFF} {$ENDIF} interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ActiveX, AxCtrls, MNRubic_TLB, StdVcl, ExtCtrls, Menus, // not the MNCadBuilder units _MNmath, _MNform, _MNxyz, _mnoglcanvas, _MNxyArrays, _MNDevice ; // 90% of this is standard Delphi code (automatically produced) type TaxRubic = class(TActiveForm, IaxRubic) Timer1: TTimer; PopupMenu1: TPopupMenu; resetview1: TMenuItem; N1: TMenuItem; about1: TMenuItem; merge1: TMenuItem; resetcube1: TMenuItem; procedure Timer1Timer(Sender: TObject); procedure ActiveFormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure ActiveFormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure resetview1Click(Sender: TObject); procedure about1Click(Sender: TObject); procedure merge1Click(Sender: TObject); procedure resetcube1Click(Sender: TObject); private { Private declarations } FEvents: IaxRubicEvents; FMergeCount:SysInt; FcurrentSide: Integer; RubicDirection:integer; Tick : integer; ActCurrentSide:integer; Cubes:TMNgrob; OglDevice:TMNOglCanvas; Start:TPoint; procedure ActivateEvent(Sender: TObject); procedure ClickEvent(Sender: TObject); procedure CreateEvent(Sender: TObject); procedure DblClickEvent(Sender: TObject); procedure DeactivateEvent(Sender: TObject); procedure DestroyEvent(Sender: TObject); procedure KeyPressEvent(Sender: TObject; var Key: Char); procedure PaintEvent(Sender: TObject); procedure OnDrawCube(Sender: TObject); procedure SetCurrentside(const Value: Integer); procedure SetMergeCount(const Value: Integer); Property CurrentSide:Integer read FcurrentSide write SetCurrentside; property MergeCount: integer read FMergeCount write SetMergeCount; Function SlowRotate(axis:integer;count:integer):Tmatrix; Function Rotate(axis:integer;count:integer):Tmatrix; procedure InitCube; protected { Protected declarations } procedure DefinePropertyPages(DefinePropertyPage: TDefinePropertyPage); override; procedure EventSinkChanged(const EventSink: IUnknown); override; function Get_Active: WordBool; safecall; function Get_AlignDisabled: WordBool; safecall; function Get_AutoScroll: WordBool; safecall; function Get_AutoSize: WordBool; safecall; function Get_AxBorderStyle: TxActiveFormBorderStyle; safecall; function Get_Caption: WideString; safecall; function Get_Color: OLE_COLOR; safecall; function Get_DoubleBuffered: WordBool; safecall; function Get_DropTarget: WordBool; safecall; function Get_Enabled: WordBool; safecall; function Get_Font: IFontDisp; safecall; function Get_HelpFile: WideString; safecall; function Get_KeyPreview: WordBool; safecall; function Get_PixelsPerInch: Integer; safecall; function Get_PrintScale: TxPrintScale; safecall; function Get_Scaled: WordBool; safecall; function Get_ScreenSnap: WordBool; safecall; function Get_SnapBuffer: Integer; safecall; function Get_Visible: WordBool; safecall; function Get_VisibleDockClientCount: Integer; safecall; procedure _Set_Font(var Value: IFontDisp); safecall; procedure AboutBox; safecall; procedure Set_AutoScroll(Value: WordBool); safecall; procedure Set_AutoSize(Value: WordBool); safecall; procedure Set_AxBorderStyle(Value: TxActiveFormBorderStyle); safecall; procedure Set_Caption(const Value: WideString); safecall; procedure Set_Color(Value: OLE_COLOR); safecall; procedure Set_DoubleBuffered(Value: WordBool); safecall; procedure Set_DropTarget(Value: WordBool); safecall; procedure Set_Enabled(Value: WordBool); safecall; procedure Set_Font(const Value: IFontDisp); safecall; procedure Set_HelpFile(const Value: WideString); safecall; procedure Set_KeyPreview(Value: WordBool); safecall; procedure Set_PixelsPerInch(Value: Integer); safecall; procedure Set_PrintScale(Value: TxPrintScale); safecall; procedure Set_Scaled(Value: WordBool); safecall; procedure Set_ScreenSnap(Value: WordBool); safecall; procedure Set_SnapBuffer(Value: Integer); safecall; procedure Set_Visible(Value: WordBool); safecall; procedure AfterConstruction; override; procedure BeforeDestruction; override; procedure IaxRubic._Set_Font = IaxRubic__Set_Font; procedure IaxRubic.Set_Font = IaxRubic_Set_Font; procedure IaxRubic__Set_Font(var Value: IFontDisp); safecall; procedure IaxRubic_Set_Font(const Value: IFontDisp); safecall; function Get_MergeCount: SYSINT; safecall; procedure Set_MergeCount(Value: SYSINT); safecall; public { Public declarations } procedure Initialize; override; end; implementation uses ComObj, ComServ, _axRubic_About; {$R *.DFM} { TaxRubic } procedure TaxRubic.DefinePropertyPages(DefinePropertyPage: TDefinePropertyPage); begin { Define property pages here. Property pages are defined by calling DefinePropertyPage with the class id of the page. For example, DefinePropertyPage(Class_axRubicPage); } end; procedure TaxRubic.EventSinkChanged(const EventSink: IUnknown); begin FEvents := EventSink as IaxRubicEvents; inherited EventSinkChanged(EventSink); end; procedure TaxRubic.Initialize; begin inherited Initialize; Randomize; OnActivate := ActivateEvent; OnClick := ClickEvent; OnCreate := CreateEvent; OnDblClick := DblClickEvent; OnDeactivate := DeactivateEvent; OnDestroy := DestroyEvent; OnKeyPress := KeyPressEvent; OnPaint := PaintEvent; MergeCount := 3; end; function TaxRubic.Get_Active: WordBool; begin Result := Active; end; function TaxRubic.Get_AlignDisabled: WordBool; begin {$IFDEF VER150} Result := AlignDisabled; {$ELSE} Result := FALSE; {$ENDIF} end; function TaxRubic.Get_AutoScroll: WordBool; begin Result := AutoScroll; end; function TaxRubic.Get_AutoSize: WordBool; begin Result := AutoSize; end; function TaxRubic.Get_AxBorderStyle: TxActiveFormBorderStyle; begin Result := Ord(AxBorderStyle); end; function TaxRubic.Get_Caption: WideString; begin Result := WideString(Caption); end; function TaxRubic.Get_Color: OLE_COLOR; begin Result := OLE_COLOR(Color); end; function TaxRubic.Get_DoubleBuffered: WordBool; begin Result := DoubleBuffered; end; function TaxRubic.Get_DropTarget: WordBool; begin Result := DropTarget; end; function TaxRubic.Get_Enabled: WordBool; begin Result := Enabled; end; function TaxRubic.Get_Font: IFontDisp; begin GetOleFont(Font, Result); end; function TaxRubic.Get_HelpFile: WideString; begin Result := WideString(HelpFile); end; function TaxRubic.Get_KeyPreview: WordBool; begin Result := KeyPreview; end; function TaxRubic.Get_PixelsPerInch: Integer; begin Result := PixelsPerInch; end; function TaxRubic.Get_PrintScale: TxPrintScale; begin Result := Ord(PrintScale); end; function TaxRubic.Get_Scaled: WordBool; begin Result := Scaled; end; function TaxRubic.Get_ScreenSnap: WordBool; begin {$IFDEF VER150} Result := ScreenSnap; {$ELSE} Result := FALSE; {$ENDIF} end; function TaxRubic.Get_SnapBuffer: Integer; begin {$IFDEF VER150} Result := SnapBuffer; {$ELSE} Result := 0; {$ENDIF} end; function TaxRubic.Get_Visible: WordBool; begin Result := Visible; end; function TaxRubic.Get_VisibleDockClientCount: Integer; begin Result := VisibleDockClientCount; end; procedure TaxRubic._Set_Font(var Value: IFontDisp); begin SetOleFont(Font, Value); end; procedure TaxRubic.AboutBox; begin ShowaxRubicAbout; end; procedure TaxRubic.ActivateEvent(Sender: TObject); begin if FEvents <> nil then FEvents.OnActivate; end; procedure TaxRubic.ClickEvent(Sender: TObject); begin if FEvents <> nil then FEvents.OnClick; end; procedure TaxRubic.CreateEvent(Sender: TObject); begin if FEvents <> nil then FEvents.OnCreate; end; procedure TaxRubic.DblClickEvent(Sender: TObject); begin if FEvents <> nil then FEvents.OnDblClick; end; procedure TaxRubic.DeactivateEvent(Sender: TObject); begin if FEvents <> nil then FEvents.OnDeactivate; end; procedure TaxRubic.DestroyEvent(Sender: TObject); begin if FEvents <> nil then FEvents.OnDestroy; end; procedure TaxRubic.KeyPressEvent(Sender: TObject; var Key: Char); var TempKey: Smallint; begin TempKey := Smallint(Key); if FEvents <> nil then FEvents.OnKeyPress(TempKey); Key := Char(TempKey); end; procedure TaxRubic.PaintEvent(Sender: TObject); begin if FEvents <> nil then FEvents.OnPaint; end; procedure TaxRubic.Set_AutoScroll(Value: WordBool); begin AutoScroll := Value; end; procedure TaxRubic.Set_AutoSize(Value: WordBool); begin AutoSize := Value; end; procedure TaxRubic.Set_AxBorderStyle(Value: TxActiveFormBorderStyle); begin AxBorderStyle := TActiveFormBorderStyle(Value); end; procedure TaxRubic.Set_Caption(const Value: WideString); begin Caption := TCaption(Value); end; procedure TaxRubic.Set_Color(Value: OLE_COLOR); begin Color := TColor(Value); end; procedure TaxRubic.Set_DoubleBuffered(Value: WordBool); begin DoubleBuffered := Value; end; procedure TaxRubic.Set_DropTarget(Value: WordBool); begin DropTarget := Value; end; procedure TaxRubic.Set_Enabled(Value: WordBool); begin Enabled := Value; end; procedure TaxRubic.Set_Font(const Value: IFontDisp); begin SetOleFont(Font, Value); end; procedure TaxRubic.Set_HelpFile(const Value: WideString); begin HelpFile := String(Value); end; procedure TaxRubic.Set_KeyPreview(Value: WordBool); begin KeyPreview := Value; end; procedure TaxRubic.Set_PixelsPerInch(Value: Integer); begin PixelsPerInch := Value; end; procedure TaxRubic.Set_PrintScale(Value: TxPrintScale); begin PrintScale := TPrintScale(Value); end; procedure TaxRubic.Set_Scaled(Value: WordBool); begin Scaled := Value; end; procedure TaxRubic.Set_ScreenSnap(Value: WordBool); begin {$IFDEF VER150} ScreenSnap := Value; {$ENDIF} end; procedure TaxRubic.Set_SnapBuffer(Value: Integer); begin {$IFDEF VER150} SnapBuffer := Value; {$ENDIF} end; procedure TaxRubic.Set_Visible(Value: WordBool); begin Visible := Value; end; // // from now on, MNCadBuilder things will follow // // the colors of the cube const Colors: array[1..6] Of Integer= (Clwhite, // Down CLred, // left ClYellow, // back CLgreen, // right CLBlue, // front $00007Fff); // up // resolution of the animated rotation AnimSteps = 4; // let us define the rubic cube as a descendent of the TMNGrob Type TRCube = Class(TMNgrob) Protected Procedure Draw; Override; Public _Colors:array[1..3] of TColor; Function GetPlane(AtSide:integer):Integer; end; const xaxis=1; yaxis=2; zaxis=3; RCubeSize:Double= 2; // handle the standard rotation Function TaxRubic.Rotate(axis:integer;count:integer):Tmatrix; begin case axis of Xaxis: RotationToMAtrix3d(NewLineType(NewPT(0,3*Rcubesize/2,3*Rcubesize/2), NewPT(1.0,0,0)),Count*Pi/2,result); YAxis: RotationToMAtrix3d(NewLineType(NewPT(3*Rcubesize/2,0,3*Rcubesize/2), NewPT(0.0,1,0)),Count*Pi/2,result); ZAxis: RotationToMAtrix3d(NewLineType(NewPT(3*Rcubesize/2,3*Rcubesize/2,0), NewPT(0.0,0,1)),Count*Pi/2,result); end; // of case end; // handle the animated rotation Function TaxRubic.SlowRotate(axis:integer;count:integer):Tmatrix; begin case axis of Xaxis: RotationToMAtrix3d(NewLineType(NewPT(0,3*Rcubesize/2,3*Rcubesize/2), NewPT(1.0,0,0)),RubicDirection*(Count*Pi/2)/AnimSteps,result); YAxis: RotationToMAtrix3d(NewLineType(NewPT(3*Rcubesize/2,0,3*Rcubesize/2), NewPT(0.0,1,0)),RubicDirection*(Count*Pi/2)/AnimSteps,result); ZAxis: RotationToMAtrix3d(NewLineType(NewPT(3*Rcubesize/2,3*Rcubesize/2,0), NewPT(0.0,0,1)),RubicDirection*(Count*Pi/2)/AnimSteps,result); end; // of case end; { TRCube } // the draw procedure of the rubic cube procedure TRCube.Draw; var xyzarray :Txyzarray; begin ArrayInit(xyzarray,SizeOF(Txyz),5); With MNdevice do begin DrawBorder:=true; Pencolor:=clblack; Penwidth:=2; BrushColor:=_Colors[1]; GetBoxSide(Index_Box_West,NewPT(rcubeSize,rcubeSize,rcubeSize),xyzarray); PolyLine3d(xyzarray); BrushColor:=_Colors[2]; GetBoxSide(Index_Box_South,NewPT(rcubeSize,rcubeSize,rcubeSize),xyzarray); PolyLine3d(xyzarray); BrushColor:=_Colors[3]; GetBoxSide(Index_Box_Down,NewPT(rcubesize,rcubesize,rcubesize),xyzarray); PolyLine3d(xyzarray); Drawborder:=false; end; ArrayClear(xyzarray); end; // retrieve the current plane function TRCube.GetPlane(AtSide: integer): Integer; var xyzarray:TXyzarray; N:Txyz; begin result:=-1; ArrayInit(xyzarray,SizeOF(Txyz),5); GetBoxSide(AtSide,NewPT(3*rcubesize,3*rcubesize,3*rcubesize),xyzarray); n:=Normalize(Mul(vekt(xyzarray),-1)); If Dist(BAse.BAseO,NewPLane(xyzarray.items[0],N)) < rcubesize/2 then begin If Equals(Vekt(base.basex,n),Nullxyz) then result:=xaxis; If Equals(Vekt(base.basey,n),Nullxyz) then result:=yAxis; If Equals(Vekt(base.basez,n),Nullxyz) then result:=zAxis; end; ArrayClear(xyzarray); end; procedure TaxRubic.Timer1Timer(Sender: TObject); var i:integer; M:Tmatrix; begin Inc(Tick); If Tick > AnimSteps then BEGIN Timer1.Enabled:=false; Tick := 0; END; Case CurrentSide of Index_Box_Down:M:=SlowRotate(zaxis,3); Index_Box_UP: M:=SlowRotate(zaxis,1); Index_Box_East:M:=Slowrotate(xaxis,1); Index_Box_West:M:=Slowrotate(xaxis,3); Index_Box_North:M:=Slowrotate(yaxis,1); Index_Box_South:M:=Slowrotate(yaxis,3); end; // of case For i:= 0 to Cubes.MNComponentCount-1 do If (Cubes.MnGrob[i] as TRcube).GetPlane(CurrentSide) > 0 then begin Cubes.MnGrob[i].Base:=Mul(M,Cubes.MnGrob[i].Base); end; end; procedure TaxRubic.OnDrawCube(Sender: TObject); var xyzarray:TxyzArray; CE:Boolean; m:Tmatrix; B:Tbase; begin OglDevice.DrawEnabled:=false; OglDevice.DrawBox(NewPT(3*rcubesize,3*rcubesize,3*rcubesize)); OglDevice.DrawEnabled:=true; ArrayInit(xyzarray,SizeOF(Txyz),5); If CurrentSide >= 0 then BEGIN GetBoxSide(CurrentSide,NewPT(3*rcubesize+1,3*rcubesize+1,3*rcubesize+1),xyzarray); M:=TransLationToMAtrix3d(NewPT(-0.5,-0.5,-0.5)); MatMul(M,xyzarray); B:=NewBAse(xyzArray); B.BAseO:=Mul(add(xyzarray.items[0],xyzarray.items[2]),0.5); Ogldevice.Polygonmode:=gl_Line; OglDevice.Linestyle:=LSRound; OglDevice.Linestyle.CalculateMaxdist; TLSround(OglDevice.Linestyle).Radius:=0.1; OglDevice.Pencolor:=ClYellow; OglDevice.Culling:=false; Ogldevice.Circle3d(B.BAseO,B.Basez,rcubesize,20); CE:=OglDevice.CatchEnabled; OglDevice.CatchEnabled:=false; Ogldevice.Polygonmode:=gl_Fill; OglDevice.Linestyle:=NIL; OglDevice.CatchEnabled:=CE; END; ArrayClear(xyzarray); end; procedure TaxRubic.SetCurrentside(const Value: Integer); begin If Timer1.Enabled then Exit; Cubes.Changing:=true; FcurrentSide := Value; Cubes.Changing:=false; end; procedure TaxRubic.AfterConstruction; begin inherited; OglDevice := TMNOglCanvas.Create (NIL); // assign a WinControl (the form itsself) to the OglDevice OglDevice.WinControl := self; // set the background color OglDevice.BackgroundColor := Color; // set perspective view (angle to 22.5 degree) OglDevice.FieldOfView := 20; OglDevice.AutoCompile := False; // Enable a default lightning setting // OglDevice.Lights[0].Position:=newpt(-10.0, 0, 25); EnableDefaultLight (OglDevice); Fcurrentside:=-1; InitCube; end; procedure TaxRubic.InitCube; var b : Tbase; s, side, i:integer; begin Cubes:=TMNgrob.Create(OglDevice.StdGround); Cubes.OnDraw:=OnDrawCube; B:=UnitBase; B.BAseO:=newPT(-3*RcubeSize/2,-3*RcubeSize/2,-3*RcubeSize/2); Cubes.Base:=B; // 4 CornerCubes down For i:= 0 to 3 do TRCube.Create(Cubes).base:=MatrixTObase(Rotate(zaxis,i)); // 4 CornerCubes up For i:= 0 to 3 do TRCube.Create(Cubes).base:=MatrixTObase(MulMat(Rotate(xaxis,1),Rotate(zaxis,i))); // 4 EdgeCubes x For i:= 0 to 3 do TRCube.Create(Cubes).base:=MatrixTObase( MulMat(TranslationTomatrix3d(newPT(rcubesize,0,0)),Rotate(xaxis,i))); // 4 EdgeCubes y For i:= 0 to 3 do TRCube.Create(Cubes).base:=MatrixTObase( MulMat(TranslationTomatrix3d(newPT(0,rcubesize,0)),Rotate(yaxis,i))); // 4 EdgeCubes z For i:= 0 to 3 do TRCube.Create(Cubes).base:=MatrixTObase( MulMat(TranslationTomatrix3d(newPT(0,0,rcubesize)),Rotate(zaxis,i))); // 4 CenterCubes x For i:= 0 to 3 do TRCube.Create(Cubes).base:=MatrixTObase( MulMat(TranslationTomatrix3d(newPT(rcubesize,rcubesize,0)),Rotate(xaxis,i))); // 2 CenterCubes y,z For i:= 0 to 1 do TRCube.Create(Cubes).base:=MatrixTObase( MulMat(TranslationTomatrix3d(newPT(0,rcubesize,rcubesize)),Rotate(zaxis,2*i))); // SetColors For s:= 1 to 6 do For i:= 0 to Cubes.MNComponentCount-1 do begin Cubes.MnGrob[i].CatchEnabled:=False; Side:=(Cubes.MnGrob[i] as TRcube).GetPlane(s); If Side > 0 then (Cubes.MnGrob[i] as TRcube)._Colors[side]:=colors[s]; end; end; procedure TaxRubic.BeforeDestruction; begin If ActiveMarklist <> NIL then If ActiveMarkList.Count > 0 then ActiveMarkList.Clear; FreeAndNil (OglDevice); inherited; end; procedure TaxRubic.ActiveFormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); VAR Direction:integer; locAngle:double; M,M2:Tmatrix; G:TLineType; di:TPoint; Base, B:TBase; FTranslation, orgBaseO:TXYZ; MustUpdate:Boolean; begin inherited; MustUpdate:=FALSE; If (csDesigning in ComponentState) then Exit; Direction := 0; Base := OglDevice.ProjectionBase; If ssLeft in Shift then begin di.x := x - Start.x; di.y := y - Start.y; If GetKeyState(vk_Shift) AND $8000 <> 0 then begin FTranslation := NewPt (0.0, 0, 0); If di.x <> 0 then FTranslation := Add (FTranslation, Mul(Base.Basez, di.x/(120/2.54))); TranslationToMatrix3D (FTranslation, M2); BaseToMAtrix(OglDevice.ProjectionBase, M); M:=Mulmat(M, M2); OglDevice.ProjectionBase:=MatrixToBAse(M); MustUpdate := TRUE; end else If GetKeyState(vk_Control) AND $8000 <> 0 then begin FTranslation := NewPt (0.0, 0, 0); If di.x <> 0 then FTranslation := Mul(Base.Basex, di.x/(120/2.54)); If di.y <> 0 then FTranslation := Sub (FTranslation, Mul(Base.Basey, di.y/(120/2.54))); FTranslation := Mul (FTranslation, -1); TranslationToMatrix3D (FTranslation, M2); BaseToMAtrix(OglDevice.ProjectionBase, M); M:=Mulmat(M, M2); OglDevice.ProjectionBase:=MatrixToBAse(M); MustUpdate := TRUE; end else begin G.P:=Base.BaseO; G.Direction:=Base.BaseY; locAngle := ((di.x/(Width/2))*Pi); MustUpdate:=TRUE; RotationToMAtrix3d(G, locAngle, M2); BaseToMAtrix(OglDevice.ProjectionBase,M); M:=Mulmat(M, M2); OglDevice.ProjectionBase:=MatrixToBAse(M); G.P:=Base.BaseO; G.Direction:=Base.BaseX; locAngle := ((di.y/(Height/2))*Pi); MustUpdate:=TRUE; RotationToMAtrix3d(G, locAngle, M2); BaseToMAtrix(OglDevice.ProjectionBase,M); M:=Mulmat(M, M2); OglDevice.ProjectionBase:=MatrixToBAse(M); end; Start.x := x; Start.y := y; end; with activemarklist do If (CurrentList.Count > 0) then Currentside:=CurrentList[0].PrimData else Currentside:=-1; end; procedure TaxRubic.ActiveFormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ActCurrentSide:integer; M:Tmatrix; i:integer; begin If ssLeft in Shift then begin Start := Point (x, y); If CurrentSide < 0 then exit; If Timer1.Enabled then Exit; If Tick > 0 then Exit; Tick:=1; RubicDirection := 1; If GetKeyState(vk_Control) AND $8000 <> 0 then RubicDirection := -1; Timer1.Enabled:=true; end; end; procedure TaxRubic.IaxRubic__Set_Font(var Value: IFontDisp); begin SetOleFont(Font, Value); end; procedure TaxRubic.IaxRubic_Set_Font(const Value: IFontDisp); begin SetOleFont(Font, Value); end; procedure TaxRubic.resetview1Click(Sender: TObject); begin OglDevice.ProjectionBase := UnitBase; end; procedure TaxRubic.about1Click(Sender: TObject); begin ShowaxRubicAbout; end; procedure TaxRubic.merge1Click(Sender: TObject); VAR r : integer; M:TMatrix; mc, i:integer; begin for mc := 0 to MergeCount-1 do begin r := Random (5); r := r + 1; If r mod 2 = 0 then RubicDirection := 1 else RubicDirection := -1; CurrentSide := r; Case CurrentSide of Index_Box_Down:M:=Rotate(zaxis,3); Index_Box_UP: M:=Rotate(zaxis,1); Index_Box_East:M:=Rotate(xaxis,1); Index_Box_West:M:=Rotate(xaxis,3); Index_Box_North:M:=Rotate(yaxis,1); Index_Box_South:M:=Rotate(yaxis,3); end; // of case For i:= 0 to Cubes.MNComponentCount-1 do If (Cubes.MnGrob[i] as TRcube).GetPlane(CurrentSide) > 0 then begin Cubes.MnGrob[i].Base:=Mul(M,Cubes.MnGrob[i].Base); end; end; CurrentSide := -1; end; function TaxRubic.Get_MergeCount: SYSINT; begin result := FMergeCount; end; procedure TaxRubic.Set_MergeCount(Value: SYSINT); begin FMergeCount := Abs (Value); end; procedure TaxRubic.SetMergeCount(const Value: integer); begin FMergeCount := Abs (Value); end; procedure TaxRubic.resetcube1Click(Sender: TObject); begin FreeAndNIL (self.Cubes); InitCube; end; initialization TActiveFormFactory.Create( ComServer, TActiveFormControl, TaxRubic, Class_axRubic, 1, '', OLEMISC_SIMPLEFRAME or OLEMISC_ACTSLIKELABEL, tmApartment); end.