/*
  Maze editor: draft editor class
  Copyright (C) 1998 by Jorrit Tyberghein
  Written by Andrew Zabolotny <bit@eltech.ru>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef __ME_DRAFT_H__
#define __ME_DRAFT_H__

#if defined(COMP_VC) || defined(COMP_WCC)
#define rint(x) floor ((x)+.5)
#elif defined(OS_NEXT)
extern "C" double rint(double x);
#endif

#include "mazed.h"

/// Indicices into mzDraftEditor's palette
#define CSPAL_DRAFT_BACKGROUND	0
#define CSPAL_DRAFT_VERTEX	1
#define CSPAL_DRAFT_INACTVERTEX	2
#define CSPAL_DRAFT_SELVERTEX	3
#define CSPAL_DRAFT_POLY	4
#define CSPAL_DRAFT_ACTPOLY	5
#define CSPAL_DRAFT_SELPOLY	6
#define CSPAL_DRAFT_AXIS	7
#define CSPAL_DRAFT_AXISNAME	8
#define CSPAL_DRAFT_GRID	9
#define CSPAL_DRAFT_SELRECT	10
#define CSPAL_DRAFT_MODIFYAXIS	11
#define CSPAL_DRAFT_MODIFIED	12
#define CSPAL_DRAFT_SCRATCHPAD	13

///
class mzDraftWindow : public csWindow
{
  /// Additional titlebar buttons
  csButton *tbTop, *tbBottom,
           *tbLeft, *tbRight,
           *tbFront, *tbBack,
           *tbFit, *tbOrg;
public:
  /// Create the Draft Editor window (frame etc)
  mzDraftWindow (csComponent *iParent, char *iTitle);

  /// Position our additional window controls when window changes
  virtual bool SetRect (int xmin, int ymin, int xmax, int ymax);

  /// Handle titlebar buttons events
  virtual bool HandleEvent (csEvent &Event);

  /// Don't allow buttons to overlap titlebar buttons
  virtual void FixSize (int &newW, int &newH);
};

/**
 * This is the draft editor class
 */
class mzDraftEditor : public csComponent
{
public:
  /// Create the Draft Editor view
  mzDraftEditor (csComponent *iParent);

  /// Draw the component (only dirty rectangle should be redrawn)
  virtual void Draw ();

  /// Handle draft editor events
  virtual bool HandleEvent (csEvent &Event);

  /// Call UpdateMatrix () when window size changes
  virtual bool SetRect (int xmin, int ymin, int xmax, int ymax);

  /// Set viewing angles
  void SetViewAngles (float iPhi, float iTheta);

protected:
  friend class mz3DModel;
  /**
   * We keep view vector as two angles: phi and theta. They are the
   * dirtection of vector in polar coordinates, phi being the angle of
   * rotation around vertical (Y) axis and theta being the angle of rotation
   * around horizontal axis that is perpendicular to Y.
   */
  float phi, theta;
  /**
   * We also keep the scale of ortogonal projection<p>
   * The scale is expressed as the medium distance between
   * horizontal and vertical window bounds. For example, if scale is 1
   * and we have a square window, and the center point of window (pos)
   * is at (0,0,0), and we have a XOY plane projection matrix this means
   * that we'll see in window the square (-0.5, -0.5, 0)...(+0.5, +0.5, 0)
   */
  float scale;
  /// Current 3D transform matrix resulting from above, and its inverse
  csMatrix3 w2c, c2w;
  /// ... and the position of camera
  csVector3 pos;
  /// The menu that is used to pick vertices
  csMenu *menu;
  /// Mouse coordinates in previous frame when dragging etc
  int oldMouseX, oldMouseY;
  /// Used when dragging a rectangle
  int dragMouseX, dragMouseY;
  /// true if dragging a rectangle
  bool dragRect;
  /// Equations of four planes that cuts visible space
  struct { double A, B, C, D; } clip_eq [4];
  /// Minimal and maximal coordinates within view frustum
  float xmin, ymin, zmin, xmax, ymax, zmax;
  /// Coordinates of four viewport corners in world space
  mz3DVertex clip_corner [4];
  /// Ordinal of current vertex that user clicks during "create poly" ops
  static int ConnVerticeOrd;
  /// Current modification mode (move, rotate, scale etc or 0). Used in ::Draw.
  int ModifyMode;
  /// Deformation matrix for Modify ()
  csMatrix3 ModifyDeform;
  /// Translation matrix for Modify ();
  csVector3 ModifyMotion;
  /// Modification axis/center for Modify ();
  csVector3 ModifyCenter;
  /// Are we creating a polygon?
  static bool doCreatePolygon;
  /// Number of vertices in polygon
  static int PolygonVertices;
  /// Are we creating a 3D body?
  static bool doCreateBody;
  /// 3D body creation phase
  static int BodyCreationPhase;

  /// Call this routine after changing phi, theta, scale or pos
  void UpdateMatrix ();
  /// Convert a point from world space to window space
  void world2win (csVector3 &v, int &x, int &y);
  /// Same but without translation
  void world2win (csVector3 &v, csVector3 &dest);
  /**
   * Convert a point from world space to window space
   * with current modification applied
   */
  void world2winM (csVector3 &v, int &x, int &y);
  /// Convert a point from window space to world space
  void win2world (int x, int y, float z, csVector3 &v);
  /// Same but given floating-point coordinates
  void win2world (float x, float y, float z, csVector3 &v);
  /// Prepare a csMatrix3 and a csVector3 used for dynamic object modification
  void PrepareModificationMatrix ();
  /// Modify a vertex using current modification matrices
  void Modify (csVector3 &v);
  /// Zoom view in or out given mouse click position
  void ZoomInOut (int x, int y, float delta);
  /// Pick the vertex that lies at or near the given window position
  int PickVertex (int x, int y);
  /// Draw support gadgets: grid and coordinate axes
  void DrawGadgets ();
  /// Clip a 3D line by view frustum; return false if line is invisible
  bool clip3Dline (csVector3 &v1, csVector3 &v2);
  /// Insert a 3D vertex into model given its window x,y coordinates
  int InsertVertexAt (int x, int y);
  /// Zoom view so that given rectangle will maximally fit in window
  void ZoomToRect (csVector3 &o, csVector3 &ha, csVector3 &va, bool iUpdateAngles = false);
  /// Snap a vertex to grid
  void SnapToGrid (csVector3 &v);
  /// Add a vertex at given window position to polygon that is currently created
  void ConnectPolyVertex (int x, int y);
  /// Exit from "connect poly vertices" mode
  void FinishConnectPoly ();
  /// Select/deselect/invert vertices/polygons within a given window rectangle
  void SelectRect (csRect &r);
  /// Set view parameters so that current model maximally fits in window
  void FitModelInWindow ();
  /// Center model in window
  void CenterModelInWindow ();
  /// Calculate interpolation step for moving through the grid points from v1 to v2
  void GridInterpolationSteps (mz3DVertex &v1, mz3DVertex &v2,
    mz3DVertex &step, int &steps);
  /// Display an unexisting polygon that user is creating
  void ShowPolygon (int xc, int yc, int xr, int yr);
  /// Interactively create a 3D body
  void ShowBody (int xc, int yc, int xr, int yr);
  /// Create a polygon
  void CreatePolygon (int icx, int icy, int irx, int iry, float iz,
    bool iReverse, int *oVertIdx);
  /// Create a box
  void CreateBox (int xl, int yt, int xr, int yb, float depth);
  /// Create a prism
  void CreatePrism (int xc, int yc, int xr, int yr, float depth);
  /// Create a pyramid
  void CreatePyramid (int xc, int yc, int xr, int yr, float depth);
  /// Guess what?
  void CreateTorus (int xc, int yc, int xr, int yr, float iInnerRadius,
    float iOuterRadius);
  /// Hmm... its a complex question
  void CreateSphere (int xc, int yc, int xr, int yr);
};

#endif // __ME_DRAFT_H__
