unit fDemoMain;
{$INCLUDE CADSoftTools.INC}
// If you see error "File not found: 'CADSoftTools.INC'",
// then please contact info@cadsofttools.com to get a compilable version.
// If you have a compilable version, you need to copy the contents of
// Lib7/LibXE5win32/LibXE5win64... to Lib directory according to your
// Delphi version and target CPU platform.

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, ExtCtrls, Menus, DXFConv, CADImage, sg3DNavigator,
  sgDrawingNavigator, DXF, DWG, sgSTLImage, sgSatImage, sgConsts, sgFunction,
{$IFDEF DEMO}
  fInfo,
{$ENDIF}
  ComCtrls;

type
  Tfm3DGLS = class(TForm)
    pnlClient: TPanel;
    pnlTop: TPanel;
    btbtnOpen: TBitBtn;
    btbtnClose: TBitBtn;
    btbtn3DOrbit: TBitBtn;
    btbtnDisplayMode: TBitBtn;
    pmViewMode: TPopupMenu;
    pmi2DWireframe: TMenuItem;
    N1: TMenuItem;
    pmi3DWireframe: TMenuItem;
    pmi3DHiddenLines: TMenuItem;
    pmi3DSmoothShading: TMenuItem;
    pmi3DFlatShading: TMenuItem;
    pmiDisplayMode: TMenuItem;
    N2: TMenuItem;
    pmiInitialView: TMenuItem;
    N3: TMenuItem;
    pmiSWIsometric: TMenuItem;
    pmiSEIsometric: TMenuItem;
    pmiNWIsometric: TMenuItem;
    pmiNEIsometric: TMenuItem;
    OpenDialog: TOpenDialog;
    srInfo: TStatusBar;
    procedure btbtnDisplayModeClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btbtnOpenClick(Sender: TObject);
    procedure btbtnCloseClick(Sender: TObject);
    procedure btbtn3DOrbitClick(Sender: TObject);
    procedure pmi2DWireframeClick(Sender: TObject);
    procedure pmi3DSmoothShadingClick(Sender: TObject);
    procedure pmi3DWireframeClick(Sender: TObject);
    procedure pmi3DHiddenLinesClick(Sender: TObject);
    procedure pmi3DFlatShadingClick(Sender: TObject);
    procedure pmiInitialViewClick(Sender: TObject);
    procedure pmiNEIsometricClick(Sender: TObject);
    procedure pmiNWIsometricClick(Sender: TObject);
    procedure pmiSEIsometricClick(Sender: TObject);
    procedure pmiSWIsometricClick(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  private
    F3DN: Tsg3DDrawingNavigator;
    FDN: TsgDrawingNavigator;
    procedure SetShowingStyle(Sender: TObject; const AStyle: Tsg3DShowingStyle);
    function GetLoadedCADImage: TsgCADImage;
    procedure ClearChecked;
    procedure RotateByView(const A3DView: CADImage.TsgDXFViewDirection);
    procedure NavigatorMouseMove(Sender: TObject; Shift: TShiftState;
      X, Y: Integer);
    procedure PickObjectEvent(Sender: TObject);
  protected
    property LoadedCADImage: TsgCADImage read GetLoadedCADImage;
  public
    { Public declarations }
  end;

var
  fm3DGLS: Tfm3DGLS;

implementation

{$R *.dfm}

type
  Tsg3DDrawingNavigatorAccess = class(Tsg3DDrawingNavigator);

procedure Tfm3DGLS.btbtn3DOrbitClick(Sender: TObject);
begin
  if F3DN.Visible then
    F3DN.Orbit3D.Visible := not F3DN.Orbit3D.Visible;
  if FDN.Visible then
    FDN.Orbit3D.Visible := not FDN.Orbit3D.Visible;
end;

procedure Tfm3DGLS.btbtnCloseClick(Sender: TObject);
begin
  if FDN.Picture <> nil then
    FDN.Picture.Graphic := nil;
  FDN.Orbit3D.Visible := False;
  F3DN.Visible := False;
  F3DN.Clear;
  FDN.Visible := True;
  ClearChecked;
  srInfo.Panels[0].Text := '';
end;

procedure Tfm3DGLS.btbtnDisplayModeClick(Sender: TObject);
var
  vPoint: TPoint;
begin
  vPoint.X := 0;
  vPoint.Y := btbtnDisplayMode.Height;
  vPoint := btbtnDisplayMode.ClientToScreen(vPoint);
  pmViewMode.Popup(vPoint.X, vPoint.Y);
end;

procedure Tfm3DGLS.btbtnOpenClick(Sender: TObject);
begin
  if OpenDialog.Execute then
  begin
    btbtnClose.Click;
    Screen.Cursor := crHourGlass;
    try
      FDN.Visible := False;
      FDN.Picture.LoadFromFile(OpenDialog.FileName);
      FDN.BeginUpdate;
      try
        (FDN.Picture.Graphic as TsgCADImage).CustomDraw := False;
        FDN.FitToSize;
      finally
        FDN.EndUpdate;
      end;
      FDN.Visible := True;
      FDN.Orbit3D.Visible := True;
      pmi2DWireframe.Checked := True;
      srInfo.Panels[0].Text := OpenDialog.FileName;
    finally
      Screen.Cursor := crDefault;
    end;
    pmi3DSmoothShading.Click;
    if F3DN.Empty then
      pmi2DWireframe.Click;
  end;
end;

procedure Tfm3DGLS.ClearChecked;
var
  I: Integer;

  procedure CheckedFalse(const Item: TMenuItem);
  var
    I: Integer;
  begin
    if Item.Count > 0 then
    begin
      for I := 0 to Item.Count - 1 do
        CheckedFalse(Item[I])
    end
    else
      Item.Checked := False;
  end;

begin
  for I := 0 to pmViewMode.Items.Count - 1 do
    CheckedFalse(pmViewMode.Items[I]);
end;

procedure Tfm3DGLS.FormCreate(Sender: TObject);
  procedure CreateNavigator(var ANavigator: TsgDrawingNavigator;
    const ANavigatorClass: TsgDrawingNavigatorClass;
    const AParent: TWinControl);
  begin
    ANavigator := ANavigatorClass.Create(Self);
    ANavigator.Parent := AParent;
    ANavigator.Visible := False;
    ANavigator.Align := alClient;
    ANavigator.SysMenuIconsVisible := False;
    ANavigator.AutoFocus := True;
    ANavigator.RectZooming := True;
    ANavigator.DoubleBuffered := True;
    ANavigator.Color := clWhite;
    ANavigator.OnMouseMove := NavigatorMouseMove;
  end;

begin
  sSHXSearchPaths := ExpandFileName('../../../SHX');
  InitDefMeshBuilderDllPath(ExtractFilePath(Application.ExeName),
    'Demos\3D\Bin'); // only for default MeshBuilder.dll path initaization
  CreateNavigator(TsgDrawingNavigator(F3DN), Tsg3DDrawingNavigator, pnlClient);
  F3DN.ShowHighlight := True;
  F3DN.OnPickObject := PickObjectEvent;
  CreateNavigator(FDN, TsgDrawingNavigator, pnlClient);
  FDN.Visible := True;
{$IFDEF DEMO}
  fInfo.CreateInfoFrame(FDN.Handle, Point(10, 10));
{$ENDIF}
end;

procedure Tfm3DGLS.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Key = VK_ESCAPE then
  begin
    if F3DN.Visible then
      F3DN.Orbit3D.Visible := False;
    if FDN.Visible then
      FDN.Orbit3D.Visible := False;
  end;
end;

procedure Tfm3DGLS.NavigatorMouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
var
  Navigator: TsgDrawingNavigator;
  vUnits: string;
  P: TFPoint;
  S: string;
  DS: Char;
begin
  if Assigned(LoadedCADImage) then
  begin
    Navigator := TsgDrawingNavigator(Sender);
    P := Navigator.GetDrawingCoords(X, Y, vUnits);
    DS := GetDecimalSeparator;
    S := Format('X:%s; Y:%s; Z:%s', [DoubleToStr(P.X, DS), DoubleToStr(P.Y, DS),
      DoubleToStr(P.Z, DS)]);
  end
  else
    S := Format('X:%d; Y:%d', [X, Y]);
  srInfo.Panels[1].Text := S;
end;

procedure Tfm3DGLS.PickObjectEvent(Sender: TObject);
const
  cnstEOLN = #13#10;
var
  vMesh: TsgMeshObject;

  S: string;
  vRootInsert, vInsert: TsgDXFInsert;

  function GetAttribsList(AInsert: TsgDXFInsert): string;
  var
    I: Integer;
  begin
    Result := '';
    for I := 0 to AInsert.Attribs.Count - 1 do
      Result := Result + TsgDXFAttrib(AInsert.Attribs[I]).Name + cnstEOLN;
  end;

begin
  if F3DN.PickObject is TsgMeshObject then
  begin
    vMesh := TsgMeshObject(F3DN.PickObject);
    vInsert := TsgDXFInsert(vMesh.Insert);
    if vInsert <> nil then
    begin
      S := 'Block Reference "' + vInsert.Name + '":' + cnstEOLN;
      S := S + GetAttribsList(vInsert) + cnstEOLN;
      if vMesh.RootInsert <> nil then
      begin
        vRootInsert := TsgDXFInsert(vMesh.RootInsert);
        S := S + 'Top Block Reference "' + vRootInsert.Name + '":' + cnstEOLN;
        S := S + GetAttribsList(vRootInsert) + cnstEOLN;
      end;
    end
    else
      S := TsgDXFEntity(vMesh.Entity).Name;
    if S <> '' then
      Application.MessageBox(PChar(S), 'Object picked', MB_ICONINFORMATION);
  end;
end;

function Tfm3DGLS.GetLoadedCADImage: TsgCADImage;
begin
  Result := FDN.Picture.Graphic as TsgCADImage;
end;

procedure Tfm3DGLS.pmi2DWireframeClick(Sender: TObject);
var
  vImg: TsgCADImage;
begin
  if F3DN.Visible then
  begin
    F3DN.Visible := False;
    if not F3DN.Empty then
    begin
      vImg := FDN.Picture.Graphic as TsgCADImage;
      LoadViewFrom3DNavigator(vImg, F3DN);
    end;
    FDN.Visible := True;
    ClearChecked;
    (Sender as TMenuItem).Checked := True;
  end;
end;

procedure Tfm3DGLS.pmi3DFlatShadingClick(Sender: TObject);
begin
  SetShowingStyle(Sender, ssFlatShading);
end;

procedure Tfm3DGLS.pmi3DHiddenLinesClick(Sender: TObject);
begin
  SetShowingStyle(Sender, ssHiddenLines);
end;

procedure Tfm3DGLS.pmi3DSmoothShadingClick(Sender: TObject);
begin
  SetShowingStyle(Sender, ssSmoothShading);
end;

procedure Tfm3DGLS.pmi3DWireframeClick(Sender: TObject);
begin
  SetShowingStyle(Sender, ssWireframe);
end;

procedure Tfm3DGLS.pmiInitialViewClick(Sender: TObject);
begin
  RotateByView(vdDefault);
end;

procedure Tfm3DGLS.pmiNEIsometricClick(Sender: TObject);
begin
  RotateByView(vdNEIsometric);
end;

procedure Tfm3DGLS.pmiNWIsometricClick(Sender: TObject);
begin
  RotateByView(vdNWIsometric);
end;

procedure Tfm3DGLS.pmiSEIsometricClick(Sender: TObject);
begin
  RotateByView(vdSEIsometric);
end;

procedure Tfm3DGLS.pmiSWIsometricClick(Sender: TObject);
begin
  RotateByView(vdSWIsometric);
end;

procedure Tfm3DGLS.RotateByView(const A3DView: CADImage.TsgDXFViewDirection);
var
  vPaintBox: TsgDrawingNavigator;
begin
  if FDN.Visible then
    vPaintBox := FDN
  else
    vPaintBox := F3DN;
  if LoadedCADImage <> nil then
  begin
    vPaintBox.BeginUpdate;
    try
      vPaintBox.RotToView(A3DView);
    finally
      vPaintBox.EndUpdate;
    end;
  end;
end;

procedure Tfm3DGLS.SetShowingStyle(Sender: TObject;
  const AStyle: Tsg3DShowingStyle);
begin
  if LoadedCADImage = nil then
    Exit;
  if not F3DN.Visible then
  begin
    F3DN.Visible := True;
    FDN.Visible := False;
    if F3DN.Empty then
    begin
      try
        Screen.Cursor := crHourGlass;
        F3DN.LoadFromConverter(LoadedCADImage.Converter, LoadedCADImage);
      finally
        Screen.Cursor := crDefault;
      end;
    end
    else
      LoadViewFromCADImage(LoadedCADImage, F3DN);
  end;
  if F3DN.ShowingStyle <> AStyle then
    F3DN.ShowingStyle := AStyle;
  ClearChecked;
  (Sender as TMenuItem).Checked := True;
  F3DN.Orbit3D.Visible := True;
end;

initialization

cnstVisualRound := True;

end.
