Skip to content
Snippets Groups Projects
FXGLViewer.i 19.2 KiB
Newer Older
/***********************************************************************
 * FXRuby -- the Ruby language bindings for the FOX GUI toolkit.
 * Copyright (c) 2001-2009 by Lyle Johnson. All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * For further information please contact the author by e-mail
 * at "lyle@lylejohnson.name".
 ***********************************************************************/

class FXDCPrint;
class FXGLObject;


// GL Viewer options
enum {
  VIEWER_LIGHTING    = 0x00008000,    /// Lighting is on
  VIEWER_FOG         = 0x00010000,    /// Fog mode on
  VIEWER_DITHER      = 0x00020000     /// Dithering
  };

/*******************************  Viewer  Structs  *****************************/

/// OpenGL Viewer Viewport
struct FXViewport {
  FXViewport();
  FXint      w,h;               // Viewport dimensions
  FXdouble   left,right;        // World box
  FXdouble   bottom,top;
  FXdouble   hither,yon;
  ~FXViewport();
  };


// OpenGL Light Source
struct FXLight {
  FXLight();
  FXVec4f    ambient;           // Ambient light color
  FXVec4f    diffuse;           // Diffuse light color
  FXVec4f    specular;          // Specular light color
  FXVec4f    position;          // Light position
  FXVec3f    direction;         // Spot direction
  FXfloat    exponent;          // Spotlight exponent
  FXfloat    cutoff;            // Spotlight cutoff angle
  FXfloat    c_attn;            // Constant attenuation factor
  FXfloat    l_attn;            // Linear attenuation factor
  FXfloat    q_attn;            // Quadratic attenuation factor
  ~FXLight();
  };


// OpenGL Material Description
struct FXMaterial {
  FXMaterial();
  FXVec4f    ambient;           // Ambient material color
  FXVec4f    diffuse;           // Diffuse material color
  FXVec4f    specular;          // Specular material color
  FXVec4f    emission;          // Emissive material color
  FXfloat    shininess;         // Specular shininess
  ~FXMaterial();
  };

// Feedback buffer sort routine
// typedef FXbool (*FXZSortFunc)(FXfloat*& buffer,FXint& used,FXint& size); FIXME

/********************************  Viewer  Class  ******************************/


/// Canvas, an area drawn by another object
class FXGLViewer : public FXGLCanvas {
public:

  // Common DND types
  static FXDragType objectType;     // GL Object type

public:

  // Events
  long onPaint(FXObject*,FXSelector,void* PTR_IGNORE);
  long onEnter(FXObject*,FXSelector,void* PTR_EVENT);
  long onLeave(FXObject*,FXSelector,void* PTR_EVENT);
  long onMotion(FXObject*,FXSelector,void* PTR_EVENT);
  long onMouseWheel(FXObject*,FXSelector,void* PTR_EVENT);
  long onChanged(FXObject*,FXSelector,void* PTR_GLOBJECT);
  long onPick(FXObject*,FXSelector,void* PTR_GLOBJECT); // FIXME
  long onClicked(FXObject*,FXSelector,void* PTR_GLOBJECT);
  long onDoubleClicked(FXObject*,FXSelector,void* PTR_GLOBJECT);
  long onTripleClicked(FXObject*,FXSelector,void* PTR_GLOBJECT);
  long onLassoed(FXObject*,FXSelector,void* PTR_EVENT);
  long onSelected(FXObject*,FXSelector,void* PTR_IGNORE); // FIXME
  long onDeselected(FXObject*,FXSelector,void* PTR_IGNORE); // FIXME
  long onInserted(FXObject*,FXSelector,void* PTR_IGNORE); // FIXME
  long onDeleted(FXObject*,FXSelector,void* PTR_IGNORE); // FIXME
  long onLeftBtnPress(FXObject*,FXSelector,void* PTR_EVENT);
  long onLeftBtnRelease(FXObject*,FXSelector,void* PTR_EVENT);
  long onMiddleBtnPress(FXObject*,FXSelector,void* PTR_EVENT);
  long onMiddleBtnRelease(FXObject*,FXSelector,void* PTR_EVENT);
  long onRightBtnPress(FXObject*,FXSelector,void* PTR_EVENT);
  long onRightBtnRelease(FXObject*,FXSelector,void* PTR_EVENT);
  long onUngrabbed(FXObject*,FXSelector,void* PTR_EVENT);
  long onKeyPress(FXObject*,FXSelector,void* PTR_EVENT);
  long onKeyRelease(FXObject*,FXSelector,void* PTR_EVENT);
  long onFocusIn(FXObject*,FXSelector,void* PTR_EVENT);
  long onFocusOut(FXObject*,FXSelector,void* PTR_EVENT);
  long onClipboardLost(FXObject*,FXSelector,void* PTR_EVENT);
  long onClipboardGained(FXObject*,FXSelector,void* PTR_EVENT);
  long onClipboardRequest(FXObject*,FXSelector,void* PTR_EVENT);

  // Commands
  long onCmdPerspective(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdPerspective(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdParallel(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdParallel(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdFront(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdFront(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdBack(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdBack(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdLeft(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdLeft(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdRight(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdRight(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdTop(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdTop(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdBottom(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdBottom(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdResetView(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdFitView(FXObject*,FXSelector,void* PTR_IGNORE);
  long onDNDEnter(FXObject*,FXSelector,void* PTR_EVENT);
  long onDNDLeave(FXObject*,FXSelector,void* PTR_EVENT);
  long onDNDMotion(FXObject*,FXSelector,void* PTR_EVENT);
  long onDNDDrop(FXObject*,FXSelector,void* PTR_EVENT);
  long onTipTimer(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdXYZDial(FXObject*,FXSelector,void* PTR_INT);
  long onUpdXYZDial(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdRollPitchYaw(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdRollPitchYaw(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdXYZScale(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdXYZScale(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdCurrent(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdCutSel(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdCopySel(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdPasteSel(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdDeleteSel(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdDeleteSel(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdBackColor(FXObject*,FXSelector,void* PTR_COLOR);
  long onUpdBackColor(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdGradientBackColor(FXObject*,FXSelector,void* PTR_COLOR);
  long onUpdGradientBackColor(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdAmbientColor(FXObject*,FXSelector,void* PTR_COLOR);
  long onUpdAmbientColor(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdLighting(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdLighting(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdFog(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdFog(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdDither(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdDither(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdFov(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdFov(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdZoom(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdZoom(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdLightAmbient(FXObject*,FXSelector,void* PTR_COLOR);
  long onUpdLightAmbient(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdLightDiffuse(FXObject*,FXSelector,void* PTR_COLOR);
  long onUpdLightDiffuse(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdLightSpecular(FXObject*,FXSelector,void* PTR_COLOR);
  long onUpdLightSpecular(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdTurbo(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdTurbo(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdPrintImage(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdPrintVector(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdLassoZoom(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdLassoSelect(FXObject*,FXSelector,void* PTR_IGNORE);
  long onQueryHelp(FXObject*,FXSelector,void* PTR_IGNORE);
  long onQueryTip(FXObject*,FXSelector,void* PTR_IGNORE); // FIXME

public:
  // Projection modes
  enum {
    PARALLEL,		  // Parallel projection
    PERSPECTIVE		  // Perspective projection
    };

  // Messages
  enum {
    ID_PERSPECTIVE=FXGLCanvas::ID_LAST,
    ID_PARALLEL,
    ID_FRONT,
    ID_BACK,
    ID_LEFT,
    ID_RIGHT,
    ID_TOP,
    ID_BOTTOM,
    ID_RESETVIEW,
    ID_FITVIEW,
    ID_TOP_COLOR,
    ID_BOTTOM_COLOR,
    ID_BACK_COLOR,
    ID_AMBIENT_COLOR,
    ID_LIGHT_AMBIENT,
    ID_LIGHT_DIFFUSE,
    ID_LIGHT_SPECULAR,
    ID_LIGHTING,
    ID_TURBO,
    ID_FOG,
    ID_DITHER,
    ID_SCALE_X,
    ID_SCALE_Y,
    ID_SCALE_Z,
    ID_DIAL_X,
    ID_DIAL_Y,
    ID_DIAL_Z,
    ID_ROLL,
    ID_PITCH,
    ID_YAW,
    ID_FOV,
    ID_ZOOM,
    ID_CUT_SEL,
    ID_COPY_SEL,
    ID_PASTE_SEL,
    ID_DELETE_SEL,
    ID_PRINT_IMAGE,
    ID_PRINT_VECTOR,
    ID_LASSO_ZOOM,
    ID_LASSO_SELECT,
    ID_LAST
    };

public:

  // Common DND type names
  %extend {
    static VALUE objectTypeName(){
      return to_ruby(FXGLViewer::objectTypeName);
      }
  }

public:
  %extend {
    /// Construct GL viewer widget
    FXGLViewer(FXComposite* p,FXGLVisual *vis,FXObject* tgt=NULL,FXSelector sel=0,FXuint opts=0,FXint x=0,FXint y=0,FXint w=0,FXint h=0){
      return new FXRbGLViewer(p,vis,tgt,sel,opts,x,y,w,h);
      }
    /// Construct GL viewer widget sharing display list with another GL viewer
    FXGLViewer(FXComposite* p,FXGLVisual *vis,FXGLViewer* sharegroup,FXObject* tgt=NULL,FXSelector sel=0,FXuint opts=0,FXint x=0,FXint y=0,FXint w=0,FXint h=0){
      return new FXRbGLViewer(p,vis,sharegroup,tgt,sel,opts,x,y,w,h);
      }
    }

  /// Return size of pixel in world coordinates
  FXdouble worldPix() const;

  /// Return size of pixel in model coordinates
  FXdouble modelPix() const;

  %extend {
    // Return a list of all objects in the given rectangle
    VALUE lasso(FXint x1,FXint y1,FXint x2,FXint y2) {
      VALUE objects = rb_ary_new();
      FXGLObject** items = self->lasso(x1, y1, x2, y2);
      if (items) {
        register FXGLObject** p = items;
        while (*p) {
          rb_ary_push(objects, to_ruby(*p));
          p++;
        }
        FXFREE(&items);
      }
      return objects;
    }
  }

  /// Fit viewer to the given bounding box
  FXbool fitToBounds(const FXRangef& box);
  %extend {
    /// Return the viewer's viewport
    FXViewport getViewport() const {
      FXViewport v;
      self->getViewport(v);
      return v;
    }
  }
  %extend {
    /// Translate eye-coordinate to screen coordinate
    VALUE eyeToScreen(FXVec3f e) {
      FXint sx, sy;
      self->eyeToScreen(sx, sy, e);
      VALUE point = rb_ary_new();
      rb_ary_push(point, INT2NUM(sx));
      rb_ary_push(point, INT2NUM(sy));
      return point;
    }
  }

  /// Translate screen coordinate to eye coordinate at the given depth
  FXVec3f screenToEye(FXint sx,FXint sy,FXfloat eyez=0.0);
  /// Translate screen coordinate to eye coordinate at the target point depth
  FXVec3f screenToTarget(FXint sx,FXint sy);
  /// Translate world coordinate to eye coordinate
  FXVec3f worldToEye(FXVec3f w);
  /// Translate world coordinate to eye coordinate depth
  FXfloat worldToEyeZ(FXVec3f w);
  /// Translate eye coordinate to eye coordinate
  FXVec3f eyeToWorld(FXVec3f e);

  /// Calculate world coordinate vector from screen movement
  FXVec3f worldVector(FXint fx,FXint fy,FXint tx,FXint ty);
  ///  Change default object material setting
  void setMaterial(const FXMaterial &mtl);
  %extend {
    /// Return default object material setting
    FXMaterial getMaterial() const {
      FXMaterial mtl;
      self->getMaterial(mtl);
      return mtl;
    }
  }
  /// Change camera field of view angle (in degrees)
  void setFieldOfView(FXdouble fv);
  /// Return camera field of view angle
  FXdouble getFieldOfView() const { return fov; }

  /// Change camera zoom factor
  void setZoom(FXdouble zm);
  /// Return camera zoom factor
  FXdouble getZoom() const;

  /// Change target point distance
  void setDistance(FXdouble ed);
  /// Return target point distance
  FXdouble getDistance() const;

  /// Change unequal model scaling factors
  void setScale(FXVec3f s);
  /// Return current scaling factors
  const FXVec3f& getScale() const;

  /// Change camera orientation from quaternion
  void setOrientation(FXQuatf rot);
  /// Return current camera orientation quaternion
  const FXQuatf& getOrientation() const;

  /// Change object center (tranlation)
  void setCenter(FXVec3f cntr);
  /// Return object center
  const FXVec3f& getCenter() const;

  /// Translate object center
  void translate(FXVec3f vec);
  %extend {
    /// Return boresight vector (an array of two arrays)
    VALUE getBoreVector(FXint sx,FXint sy) {
      FXVec3f point, dir;
      self->getBoreVector(sx, sy, point, dir);

      VALUE pointArray = rb_ary_new();
      rb_ary_push(pointArray, rb_float_new(point[0]));
      rb_ary_push(pointArray, rb_float_new(point[1]));
      rb_ary_push(pointArray, rb_float_new(point[2]));

      VALUE dirArray = rb_ary_new();
      rb_ary_push(dirArray, rb_float_new(dir[0]));
      rb_ary_push(dirArray, rb_float_new(dir[1]));
      rb_ary_push(dirArray, rb_float_new(dir[2]));

      VALUE results = rb_ary_new();
      rb_ary_push(results, pointArray);
      rb_ary_push(results, dirArray);

      return results;
    }
  }

  /// Return eyesight vector
  FXVec3f getEyeVector() const;

  /// Return eye position
  FXVec3f getEyePosition() const;
  /// Change help text
  void setHelpText(const FXString& text);
  /// Return help text
  const FXString& getHelpText() const;

  /// Change tip text
  void setTipText(const FXString& text);
  /// Return tip text
  const FXString& getTipText() const;

  /// Return the current transformation matrix
  const FXMat4f& getTransform() const;

  /// Return the inverse of the current transformation matrix
  const FXMat4f& getInvTransform() const;

  /// Change the scene, i.e. the object being displayed.
  void setScene(FXGLObject* sc);
  /// Return the current scene object
  FXGLObject* getScene() const;

  /// Change selection
  void setSelection(FXGLObject* sel);

  /// Returns the selection
  FXGLObject* getSelection() const;

  /// Change the projection mode, PERSPECTIVE or PARALLEL
  void setProjection(FXuint proj);
  /// Return the projection mode
  FXuint getProjection() const;

  /// Change top or bottom or both background colors
  void setBackgroundColor(const FXVec4f& clr,FXbool bottom=MAYBE);
  /// Return top or bottom window background color.
  const FXVec4f& getBackgroundColor(FXbool bottom=FALSE) const;

  /// Change global ambient light color
  void setAmbientColor(const FXVec4f& clr);
  /// Return global ambient light color
  const FXVec4f& getAmbientColor() const;

#ifdef SWIGRUBY
  %extend {
    /**
     * Read the pixels off the screen as array of FXColor;
     * this array can be directly passed to fxsaveBMP and other image
     * output routines.
     */
    VALUE readPixels(FXint x,FXint y,FXint w,FXint h){
      FXColor *buffer;
      VALUE pixels=Qnil;
      if(self->readPixels(buffer,x,y,w,h)){
	pixels=FXRbMakeColorArray(buffer,w,h);
	FXFREE(&buffer);
	}
      return pixels;
      }
     * Read the feedback buffer containing the current scene, returning used
     * and allocated size.
     */
    VALUE readFeedback(FXint x,FXint y,FXint w,FXint h){
      FXfloat *buffer;
      FXint used, size;
      if (self->readFeedback(buffer,used,size,x,y,w,h)){
	VALUE results=rb_ary_new();
	for(FXint i=0;i<used;i++) rb_ary_push(results,rb_float_new(buffer[i]));
	FXFREE(&buffer);
	return results;
        }
      else{
	return Qnil;
        }
      }
  }
#else
  %extend {
    PyObject *readPixels(FXint x,FXint y,FXint w,FXint h) {
      FXuchar *buffer;
      if(self->readPixels(buffer,x,y,w,h)){
	char *charBuffer;
	FXint nbytes=3*w*h;
	if(FXMALLOC(&charBuffer,char,nbytes)){
	  memcpy((void*)charBuffer,(void*)buffer,nbytes);
	  FXFREE(&buffer);
          FXbool doSave=FXPyRestoreThread();
	  PyObject *result=PyString_FromString(charBuffer);
          FXPySaveThread(doSave);
	  FXFREE(&charBuffer);
	  return result;
          }
	else{
	  FXFREE(&buffer);
          FXbool doSave=FXPyRestoreThread();
          PyErr_SetString(PyExc_MemoryError,"out of memory");
          FXPySaveThread(doSave);
	  return NULL;
	  }
        }
      else{
        FXbool doSave=FXPyRestoreThread();
        PyErr_SetString(PyExc_MemoryError,"out of memory");
        FXPySaveThread(doSave);
	return NULL;
        }
      }

    PyObject *readFeedback(FXint x,FXint y,FXint w,FXint h) {
      FXfloat *buffer;
      FXint used,size;
      if(self->readFeedback(buffer,used,size,x,y,w,h)){
        FXbool doSave=FXPyRestoreThread();
	PyObject *list=PyList_New(used);
	if(!list){
	  FXFREE(&buffer);
          FXPySaveThread(doSave);
	  return NULL;
	  }
	for(FXint i=0;i<used;i++){
	  PyObject *flt=PyFloat_FromDouble(buffer[i]);
	  if(!flt){
	    FXFREE(&buffer);
	    Py_DECREF(list);
            FXPySaveThread(doSave);
	    return NULL;
	    }
	  PyList_SetItem(list,i,flt);
	  }
        FXPySaveThread(doSave);
	FXFREE(&buffer);
	return list;
	}
      else{
        PyErr_SetString(PyExc_MemoryError,"out of memory");
	return NULL;
	}
      }
  }
#endif
#ifdef SWIGRUBY
  /**
  * Change hidden-surface feedback buffer sorting algorithm.
  * This can be used for move/draw printed output depth sorting.
  %extend {
    void setZSortFunc(VALUE proc){
      }
  }
#endif

#ifdef SWIGRUBY
  /// Return hidden surface sorting function.
  %extend {
    VALUE getZSortFunc() const {
      return Qnil;
      }
  }
#endif

  * Change the maximum hits, i.e. the maximum size of the pick buffer.
  * When set to less than or equal to zero, picking is essentially turned off.
  */
  void setMaxHits(FXint maxh);

  /// Return maximum pickbuffer size
  FXint getMaxHits() const;

  /**
  * When drawing a GL object, if doesTurbo() is true, the object
  * may choose to perform a reduced complexity drawing as the user is
  * interactively manipulating; another update will be done later when
  * the full complexity drawing can be performed again.
  */
  FXbool doesTurbo() const;

  /// Return turbo mode setting
  FXbool getTurboMode() const;

  /// Set turbo mode
  void setTurboMode(FXbool turbo=TRUE);
  %extend {
    // Return light source settings
    FXLight getLight() const {
      FXLight lite;
      self->getLight(lite);
      return lite;
    }
  }
  /// Change light source settings
  void setLight(const FXLight& lite);

  /// Destructor
  virtual ~FXGLViewer();
  };


DECLARE_FXOBJECT_VIRTUALS(FXGLViewer)
DECLARE_FXID_VIRTUALS(FXGLViewer)
DECLARE_FXDRAWABLE_VIRTUALS(FXGLViewer)
DECLARE_FXWINDOW_VIRTUALS(FXGLViewer)
DECLARE_FXGLCANVAS_VIRTUALS(FXGLViewer)
DECLARE_FXGLVIEWER_VIRTUALS(FXGLViewer)