Logo Search packages:      
Sourcecode: vertex version File versions

viewdraw.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <math.h>

#include <GL/gl.h>
#include <GL/glu.h>

#include <gtk/gtk.h>
#include <gtkgl/gtkglarea.h>

#include "matrixmath.h"
#include "v3dmp.h"
#include "v3dmodel.h"

#include "view.h"
#include "viewbg.h"
#include "viewdraw.h"
#include "editor.h"
#include "editorselect.h"
#include "vmautils.h"
#include "font6x10.h"

#ifdef MEMWATCH
# include "memwatch.h"
#endif


static gdouble ViewRoundDoubleWhole(gdouble x);
static void ViewDrawString(
      u_int8_t *font,
      gint x, gint y,
        const gchar *string
);

static void View2DDrawNormalVector(
      vma_view2d_struct *view2d,
      mp_vertex_struct *vn,         /* Vertex the normal originates at. */
      mp_vertex_struct *n,          /* Normal vector. */
      gint vtype, gdouble vtow_coeff,
      gdouble v_ti, gdouble v_tj,
        gint w_hw, gint w_hh
);
static void View2DSetVertex(
      vma_view2d_struct *view2d,
      mp_vertex_struct *v,
      gint vtype, gdouble vtow_coeff,
      gdouble v_ti, gdouble v_tj,
      gint w_hw, gint w_hh
);
static void View3DSetNormal(
      vma_view3d_struct *view3d,
      mp_vertex_struct *n
);
static void View3DSetVertex(
      vma_view3d_struct *view3d,
      mp_vertex_struct *v,
        mp_vertex_struct *tc
);

static void View2DDoDrawPrimitive(
      vma_view2d_struct *v, ma_editor_struct *editor,
      v3d_model_struct *model, void *p, gint pn,
        gint ww, gint wh,
        vma_view_palette_struct *palette
);
static void View3DDoDrawPrimitive(
      vma_view3d_struct *v, ma_editor_struct *editor,
      v3d_model_struct *model, int model_num,
      void *p, gint pn,
        vma_view_palette_struct *palette
);

static void View2DDrawGrid(
      vma_view2d_struct *v, gint ww, gint wh,
        vma_view_palette_struct *palette
);
static void View3DDrawGrid(
      vma_view3d_struct *v, vma_view_palette_struct *palette
);

static void View2DDrawSelectRectangle(
      vma_view2d_struct *v, gint ww, gint wh,
        vma_view_palette_struct *palette
);
static void View2DDrawCursor(
        vma_view2d_struct *v, gint ww, gint wh,
        vma_view_palette_struct *palette
);
static void View2DDrawLight(
        vma_view2d_struct *v, gint ww, gint wh,
        vma_view_palette_struct *palette,
      vma_light_struct *light_ptr, gint light_num
);

static void View2DDrawDisabled(
      vma_view2d_struct *v, gint ww, gint wh
);
static void View3DDrawDisabled(
      vma_view3d_struct *v, gint ww, gint wh
);

static void View3DSetCameraPosition(vma_view3d_struct *v);

void View2DDraw(
      vma_view2d_struct *v, vma_view_palette_struct *palette,
        gint vp_width, gint vp_height,
        gbool swap_buffers
);
void View3DDraw(
      vma_view3d_struct *v, vma_view_palette_struct *palette,
        gint vp_width, gint vp_height,
        gbool swap_buffers
);


#define MAX(a,b)  (((a) > (b)) ? (a) : (b))
#define MIN(a,b)  (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))

#define RADTODEG(r)     ((r) * 180 / PI)


#define VMA_VIEW_TEXTURE_STATE_OFF  0
#define VMA_VIEW_TEXTURE_STATE_ON   1
#define VMA_VIEW_TEXTURE_STATE_XY   2
#define VMA_VIEW_TEXTURE_STATE_YZ   3
#define VMA_VIEW_TEXTURE_STATE_XZ   4


static gint view3d_matrix_level;

static gint texture_state;
static gdouble texture_orient_i0, texture_orient_j0;
static gdouble texture_orient_id, texture_orient_jd;


/*
 *    Rounds x to the nearest whole number.
 */
static gdouble ViewRoundDoubleWhole(gdouble x)
{
      return(rint(x));
}

/*
 *    Draws string to the current OpenGL context.
 */
static void ViewDrawString(
      u_int8_t *font,
        gint x, gint y,
        const gchar *string
)
{
        u_int8_t *font_header, *font_data;

        gint font_width, font_height;           /* In pixels. */
        gint width_spacing, line_spacing; /* In pixels. */
        gint bytes_per_line;  /* Bytes per line (per width). */
        gint bytes_per_char;  /* Bytes per character. */
        gint char_offset;     /* Current char's offset in the font data. */

        gint chars_hidden = 0;      /* # of chars entirely outside viewport */
        gdouble xorig = 0.0;
        gdouble yorig = 0.0;


        if((font == NULL) ||
           (string == NULL)
        )
            return;

        /* Get pointer to font header data. */
        font_header = font;

        /* Seek past header and get pointer to start of font data. */
        font_data = font_header + 32;
 
        /* Format, header is first 32 bytes:
         *
         * Address       Desc
         * 0             Width of each font
         * 1             Height of each font
         * 2             Character width spacing
         * 3             Line spacing
         * 4             Bytes per line   
         */

        font_width = font_header[0];
        font_height = font_header[1];
        width_spacing = font_header[2];
        line_spacing = font_header[3];
        bytes_per_line = font_header[4];

        /* Calculate bytes per character. */
        bytes_per_char = bytes_per_line * font_height;
           
        /* Adjust string index in case x < 0. */
        if(x < 0)  
        {        
            chars_hidden = (-x) / width_spacing;
            xorig = (-x) - (chars_hidden * width_spacing);
        
            if(chars_hidden >= (gint)strlen(string))
                return;

            x = 0;
            string += chars_hidden;
        }
        if(y < 0)
        {
            if(y < -line_spacing)
                return;
         
            yorig = -y;
            y = 0;
        }  

        glRasterPos2i(x, y);
        for(; *string; string++)
        {
            char_offset = bytes_per_char * (*string);

            glBitmap(
                font_width, font_height,
                (GLfloat)xorig, (GLfloat)yorig,
                (GLfloat)width_spacing, 0.0,
                font_data + char_offset
            );
        }  

        return;    
}


/*
 *      Sets a 2d OpenGL normal based on the dimensional plane
 *      orientation type vtype. Any flip options will be added
 *      by this function.
 *
 *    The normal vector will be drawn as a GL_LINES, the calling
 *    function must set the color.
 */
static void View2DDrawNormalVector(
        vma_view2d_struct *view2d,
        mp_vertex_struct *vn,           /* Vertex the normal originates at. */
        mp_vertex_struct *n,            /* Normal vector. */
        gint vtype, gdouble vtow_coeff,
        gdouble v_ti, gdouble v_tj,
        gint w_hw, gint w_hh
)
{
      mp_vertex_struct v;
      double len, nlen;

      if((view2d == NULL) || (vn == NULL) || (n == NULL))
          return;

      if(vtow_coeff <= 0.0)
          return;

      /* Undefined normal vector? */
      if((n->x == 0.0) && (n->y == 0.0) && (n->z == 0.0))
          return;

      len = sqrt((n->x * n->x) + (n->y * n->y) + (n->z * n->z));
      if(len <= 0.0)
          return;

      /* Calculate the length for the displayed normal, should be
       * the length about half the view.
       */
      nlen = MAX(w_hw, w_hh) / vtow_coeff;

      glBegin(GL_LINES);
      {
          memcpy(&v, vn, sizeof(mp_vertex_struct));
          View2DSetVertex(
            view2d, &v,
            vtype, vtow_coeff,
            v_ti, v_tj, w_hw, w_hh
          );

          v.x = (nlen * n->x / len) + vn->x;
            v.y = (nlen * n->y / len) + vn->y;
            v.z = (nlen * n->z / len) + vn->z;
            View2DSetVertex(
                view2d, &v,
                vtype, vtow_coeff,
                v_ti, v_tj, w_hw, w_hh
            );
      }
      glEnd();

      glBegin(GL_POINTS);
      {
            View2DSetVertex(
                view2d, &v,
                vtype, vtow_coeff,
                v_ti, v_tj, w_hw, w_hh
            );
      }
      glEnd();

      return;
}


/*
 *    Sets a 2d OpenGL vertex based on the dimensional plane
 *    orientation type vtype. Any flip options will be added
 *    by this function.
 */
static void View2DSetVertex(
      vma_view2d_struct *view2d,
      mp_vertex_struct *v,
      gint vtype, gdouble vtow_coeff,     /* View to window conversion. */
      gdouble v_ti, gdouble v_tj,   /* View offset. */
      gint w_hw, gint w_hh    /* Offset to window center. */
)
{
      double i, j;
      double i_flip_coeff = 1.0, j_flip_coeff = -1.0;

      if(v == NULL)
          return;

      if(view2d != NULL)
      {
          i_flip_coeff = ((view2d->flags & VMA_VIEW_FLAG_FLIP_I) ? -1 : 1);
          j_flip_coeff = ((view2d->flags & VMA_VIEW_FLAG_FLIP_J) ? -1 : 1);
      }

      switch(vtype)
      {
        case VMA_VIEW2D_TYPE_XY:
          i = (((v->x * i_flip_coeff) - v_ti) * vtow_coeff) + w_hw;
          j = (((v->y * j_flip_coeff) - v_tj) * vtow_coeff) + w_hh;
          glVertex2d(
            ViewRoundDoubleWhole(i),
            ViewRoundDoubleWhole(j)
          );
          break;

          case VMA_VIEW2D_TYPE_YZ:
            i = (((v->y * i_flip_coeff) - v_ti) * vtow_coeff) + w_hw;
            j = (((v->z * j_flip_coeff) - v_tj) * vtow_coeff) + w_hh;
            glVertex2d(
                ViewRoundDoubleWhole(i),
                ViewRoundDoubleWhole(j)
            );
            break;

          case VMA_VIEW2D_TYPE_XZ:
            i = (((v->x * i_flip_coeff) - v_ti) * vtow_coeff) + w_hw;
            j = (((v->z * j_flip_coeff) - v_tj) * vtow_coeff) + w_hh;
            glVertex2d(
                ViewRoundDoubleWhole(i),
                ViewRoundDoubleWhole(j)
            );
            break;
      }


      return;
}

/*
 *    Sets a 3d normal vector.
 *
 *    Inputs assumed valid except for n.
 */
static void View3DSetNormal(
        vma_view3d_struct *view3d,
        mp_vertex_struct *n
)
{       
        if(n != NULL)
      {
          gdouble mag = sqrt(
            (n->x * n->x) + (n->y * n->y) + (n->z * n->z)
          );
          if(mag > 0.0)
          {
            glNormal3d(
                (n->x / mag),
                (n->z / mag),
                -(n->y / mag)
            );
          }
      }

      return;
}

/*
 *    Sets a 3d view vertex.
 *
 *    Inputs assumed valid except for v.
 */
static void View3DSetVertex(
        vma_view3d_struct *view3d,
        mp_vertex_struct *v,
      mp_vertex_struct *tc
)
{
      double ti, tj;


      if(v == NULL)
          return;

      switch(texture_state)
      {
        case VMA_VIEW_TEXTURE_STATE_ON:
          if(tc != NULL)
          {
              glTexCoord2d(
                tc->x,
                1.0 - tc->y
              );
          }
          break;

          case VMA_VIEW_TEXTURE_STATE_XY:
          if((texture_orient_id > 0.0) &&
               (texture_orient_jd > 0.0)
          )
          {
            ti = (v->x - texture_orient_i0) / texture_orient_id;
                tj = (v->y - texture_orient_j0) / texture_orient_jd;
            glTexCoord2d(
                    ti,
                    1.0 - tj
                );
          }
          break;

          case VMA_VIEW_TEXTURE_STATE_YZ:
            if((texture_orient_id > 0.0) &&
               (texture_orient_jd > 0.0)
            )
            {
            /* i is fliped. */
                ti = -(v->y - texture_orient_i0) / texture_orient_id;
                tj = (v->z - texture_orient_j0) / texture_orient_jd;
                glTexCoord2d(
                    ti,
                    1.0 - tj
                );
            }
          break;

          case VMA_VIEW_TEXTURE_STATE_XZ:
            if((texture_orient_id > 0.0) &&
               (texture_orient_jd > 0.0)
            )
            {
                ti = (v->x - texture_orient_i0) / texture_orient_id;
                tj = (v->z - texture_orient_j0) / texture_orient_jd;
                glTexCoord2d(
                    ti,
                    1.0 - tj
                );
            }
          break;

        default:
          break;
      }

        glVertex3d(v->x, v->z, -v->y);

      return;
}

/*
 *    Draws the primitive to the current context based on the given
 *    2d view.
 *
 *    All inputs except p assumed valid.
 */
static void View2DDoDrawPrimitive(
      vma_view2d_struct *v, ma_editor_struct *editor,
      v3d_model_struct *model, void *p, gint pn,
      gint ww, gint wh,
      vma_view_palette_struct *palette
)
{
      gbool is_selected = FALSE;
      gint i, spn, sel_vtx;
      gint vtype = v->type;
      gdouble     w_hw = ww / 2,    /* Window half dimensions. */
            w_hh = wh / 2;
      gdouble     v_ti = v->v_ti,   /* View translations. */
            v_tj = v->v_tj;
      gdouble vtow_coeff;
      mp_point_struct *mp_point;
      mp_line_struct *mp_line;
      mp_line_strip_struct *mp_line_strip;
      mp_line_loop_struct *mp_line_loop;
      mp_triangle_struct *mp_triangle;
      mp_triangle_strip_struct *mp_triangle_strip;
      mp_triangle_fan_struct *mp_triangle_fan;
      mp_quad_struct *mp_quad;
      mp_quad_strip_struct *mp_quad_strip;
        mp_polygon_struct *mp_polygon;
        mp_texture_orient_xy_struct *mp_texture_xy;
        mp_texture_orient_yz_struct *mp_texture_yz;
        mp_texture_orient_xz_struct *mp_texture_xz;
      mp_heightfield_load_struct *mp_heightfield_load;

        mp_vertex_struct tv[4];     /* Texture rectangular vertexes. */
      vma_color_struct *c, *c_normal, *c_sel, *c_sel_solid;


      if(p == NULL)
          return;

      /* Reset selected primitive select index, this will be used
       * to correspond to any selected vertices.
       */
      spn = -1;

      /* Check if this primitive is selected on the editor. */
      for(i = 0; i < editor->total_selected_primitives; i++)
      {
          if(editor->selected_primitive[i] == pn)
          {
            is_selected = TRUE;
            spn = i;
            break;
          }
      }

      /* Get selected vertex from the value list index. */
      sel_vtx = EditorGetSelected(
          editor->selected_value, editor->total_selected_values,
          spn
      );

      /* Calculate view to window coefficient. */
      vtow_coeff = View2DGetVToWCoeff(v);

      /* Get pointers to color structures. */
        c = palette->point;
      c_normal = palette->normal_vector;
        c_sel = palette->selected_vertex;
        c_sel_solid = palette->selected;


#define DO_SET_COLOR    \
{ \
 if(is_selected) \
 { \
  if(c_sel_solid == NULL) \
   glColor4d(1.0, 1.0, 0.0, 1.0); \
  else \
   glColor4d(c_sel_solid->r, c_sel_solid->g, c_sel_solid->b, c_sel_solid->a); \
 } \
 else \
 { \
  if(c == NULL) \
   glColor4d(0.8, 0.8, 0.8, 1.0); \
  else \
   glColor4d(c->r, c->g, c->b, c->a); \
 } \
}

#define DO_SET_COLOR_NORMAL         \
{ \
 if(c_normal == NULL) \
  glColor4d(1.0, 1.0, 1.0, 1.0); \
 else \
  glColor4d(c_normal->r, c_normal->g, c_normal->b, c_normal->a); \
}

#define DO_SET_COLOR_SEL_VERTEX           \
{ \
 if(c_sel == NULL) \
  glColor4d(1.0, 1.0, 1.0, 1.0); \
 else \
  glColor4d(c_sel->r, c_sel->g, c_sel->b, c_sel->a); \
}
#define DO_SET_COLOR_UNSEL_VERTEX   \
{ \
 if(c_sel == NULL) \
  glColor4d(0.5, 0.5, 0.5, 1.0); \
 else \
  glColor4d(c_sel->r * 0.5, c_sel->g * 0.5, c_sel->b * 0.5, c_sel->a); \
}

      switch(*(gint *)p)
      {
          case V3DMP_TYPE_POINT:
            mp_point = p;
          c = palette->point;
          DO_SET_COLOR
            glEnable(GL_POINT_SMOOTH);
            glPointSize(MAX(mp_point->r, 1.0));
            glBegin(GL_POINTS);
            {
                for(i = 0; i < V3DMP_POINT_NVERTEX; i++)
                    View2DSetVertex(
                        v, &mp_point->v[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
            }
            glEnd();
          break;

        case V3DMP_TYPE_LINE:
          mp_line = p;
            c = palette->line;
          DO_SET_COLOR
          glBegin(GL_LINES);
          {
              for(i = 0; i < V3DMP_LINE_NVERTEX; i++)
                View2DSetVertex(
                  v, &mp_line->v[i],
                    vtype, vtow_coeff,
                  v_ti, v_tj, w_hw, w_hh
                );
          }
          glEnd();
          if(is_selected)
          {
            mp_vertex_struct *n = NULL, *vn = NULL;

            glEnable(GL_POINT_SMOOTH);
            glPointSize(3.0);
            glBegin(GL_POINTS);
            {
                for(i = 0; i < V3DMP_LINE_NVERTEX; i++)
                {
                  if(i == sel_vtx)
                  {
                      n = &mp_line->n[i];
                      vn = &mp_line->v[i];
                      DO_SET_COLOR_SEL_VERTEX
                  }
                  else
                      DO_SET_COLOR_UNSEL_VERTEX
                  View2DSetVertex(
                      v, &mp_line->v[i],
                      vtype, vtow_coeff,
                      v_ti, v_tj, w_hw, w_hh
                  );
                }
            }
            glEnd();

            DO_SET_COLOR_NORMAL
            View2DDrawNormalVector(
                v, vn, n,
                vtype, vtow_coeff,
                v_ti, v_tj, w_hw, w_hh
            );
          }
          break;

          case V3DMP_TYPE_LINE_STRIP:
            mp_line_strip = p;
            c = palette->line_strip;
          DO_SET_COLOR
            glBegin(GL_LINE_STRIP);
            {
                for(i = 0; i < mp_line_strip->total; i++)
                    View2DSetVertex(
                        v, mp_line_strip->v[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
            }
            glEnd();
            if(is_selected)
            {
                mp_vertex_struct *n = NULL, *vn = NULL;

                glEnable(GL_POINT_SMOOTH);
                glPointSize(3.0);
                glBegin(GL_POINTS);
                {
                    for(i = 0; i < mp_line_strip->total; i++)
                {
                        if(i == sel_vtx)
                        {
                            n = mp_line_strip->n[i];
                            vn = mp_line_strip->v[i];
                            DO_SET_COLOR_SEL_VERTEX
                        }
                        else
                            DO_SET_COLOR_UNSEL_VERTEX
                        View2DSetVertex(
                            v, mp_line_strip->v[i],
                            vtype, vtow_coeff,
                            v_ti, v_tj, w_hw, w_hh
                        );
                    }
                }
                glEnd();

            DO_SET_COLOR_NORMAL
                View2DDrawNormalVector(
                    v, vn, n,
                    vtype, vtow_coeff,
                    v_ti, v_tj, w_hw, w_hh
                ); 
          }
            break;

          case V3DMP_TYPE_LINE_LOOP:
            mp_line_loop = p;
            c = palette->line_loop;
          DO_SET_COLOR
            glBegin(GL_LINE_LOOP);
            {       
                for(i = 0; i < mp_line_loop->total; i++)
                    View2DSetVertex(
                        v, mp_line_loop->v[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
            }
            glEnd();
            if(is_selected)
            {
                mp_vertex_struct *n = NULL, *vn = NULL;

                glEnable(GL_POINT_SMOOTH);
                glPointSize(3.0);
                glBegin(GL_POINTS);
                {
                    for(i = 0; i < mp_line_loop->total; i++)
                    {
                        if(i == sel_vtx)
                        {
                            n = mp_line_loop->n[i];
                            vn = mp_line_loop->v[i];
                            DO_SET_COLOR_SEL_VERTEX
                        }
                        else
                            DO_SET_COLOR_UNSEL_VERTEX   
                        View2DSetVertex(
                            v, mp_line_loop->v[i],
                            vtype, vtow_coeff,
                            v_ti, v_tj, w_hw, w_hh
                        );
                    }
                    glEnd();
                }

            DO_SET_COLOR_NORMAL
                View2DDrawNormalVector(
                    v, vn, n,
                    vtype, vtow_coeff,
                    v_ti, v_tj, w_hw, w_hh
                );
          }
          break;

          case V3DMP_TYPE_TRIANGLE:
            mp_triangle = p;
            c = palette->triangle;
          DO_SET_COLOR
          glBegin((is_selected) ? GL_TRIANGLES : GL_LINE_LOOP);
            {
                for(i = 0; i < V3DMP_TRIANGLE_NVERTEX; i++)
                    View2DSetVertex(
                        v, &mp_triangle->v[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
            }
            glEnd();
            if(is_selected)
            {
            mp_vertex_struct *n = NULL, *vn = NULL;

                glEnable(GL_POINT_SMOOTH);
                glPointSize(3.0);
                glBegin(GL_POINTS);
                {
                    for(i = 0; i < V3DMP_TRIANGLE_NVERTEX; i++)
                    {
                        if(i == sel_vtx)
                        {
                            n = &mp_triangle->n[i];
                            vn = &mp_triangle->v[i];
                            DO_SET_COLOR_SEL_VERTEX
                        }
                        else
                            DO_SET_COLOR_UNSEL_VERTEX
                        View2DSetVertex(
                            v, &mp_triangle->v[i],
                            vtype, vtow_coeff,
                            v_ti, v_tj, w_hw, w_hh
                        );
                    }
                }
                glEnd();

            DO_SET_COLOR_NORMAL
                View2DDrawNormalVector(
                    v, vn, n,
                    vtype, vtow_coeff,
                    v_ti, v_tj, w_hw, w_hh
                );
            }
            break;

          case V3DMP_TYPE_TRIANGLE_STRIP:
            mp_triangle_strip = p;
            c = palette->triangle_strip;
          DO_SET_COLOR
            glBegin((is_selected) ? GL_TRIANGLE_STRIP : GL_LINE_STRIP);
            {
                for(i = 0; i < mp_triangle_strip->total; i++)
                    View2DSetVertex(
                        v, mp_triangle_strip->v[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
            }
            glEnd();
            if(is_selected)
            {
                mp_vertex_struct *n = NULL, *vn = NULL;

                glEnable(GL_POINT_SMOOTH);
                glPointSize(3.0);
                glBegin(GL_POINTS);
                {
                    for(i = 0; i < mp_triangle_strip->total; i++)
                    {
                        if(i == sel_vtx)
                        {
                            n = mp_triangle_strip->n[i];
                            vn = mp_triangle_strip->v[i];
                            DO_SET_COLOR_SEL_VERTEX
                        }
                        else
                            DO_SET_COLOR_UNSEL_VERTEX
                        View2DSetVertex(
                            v, mp_triangle_strip->v[i],
                            vtype, vtow_coeff,
                            v_ti, v_tj, w_hw, w_hh
                        );
                }
                }
                glEnd();

            DO_SET_COLOR_NORMAL
                View2DDrawNormalVector(
                    v, vn, n,
                    vtype, vtow_coeff,
                    v_ti, v_tj, w_hw, w_hh
                );
            }
          break;

          case V3DMP_TYPE_TRIANGLE_FAN:
            mp_triangle_fan = p;
            c = palette->triangle_fan;
          DO_SET_COLOR
            glBegin((is_selected) ? GL_TRIANGLE_FAN : GL_LINE_LOOP);
            {
                for(i = 0; i < mp_triangle_fan->total; i++)
                    View2DSetVertex(
                        v, mp_triangle_fan->v[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
            }
            glEnd();
            if(is_selected)
            {
                mp_vertex_struct *n = NULL, *vn = NULL;

                glEnable(GL_POINT_SMOOTH);
                glPointSize(3.0);
                glBegin(GL_POINTS);
                {
                    for(i = 0; i < mp_triangle_fan->total; i++)
                    {
                        if(i == sel_vtx)
                        {   
                            n = mp_triangle_fan->n[i];
                            vn = mp_triangle_fan->v[i];
                            DO_SET_COLOR_SEL_VERTEX
                        }
                        else
                            DO_SET_COLOR_UNSEL_VERTEX
                        View2DSetVertex(
                            v, mp_triangle_fan->v[i],
                            vtype, vtow_coeff,
                            v_ti, v_tj, w_hw, w_hh
                        );
                    }
                }
                glEnd();

            DO_SET_COLOR_NORMAL
                View2DDrawNormalVector(
                    v, vn, n,
                    vtype, vtow_coeff,
                    v_ti, v_tj, w_hw, w_hh
                );
            }
            break;

        case V3DMP_TYPE_QUAD:
            mp_quad = p;
            c = palette->quad;
          DO_SET_COLOR
            glBegin((is_selected) ? GL_QUADS : GL_LINE_LOOP);
            {
                for(i = 0; i < V3DMP_QUAD_NVERTEX; i++)
                    View2DSetVertex(
                        v, &mp_quad->v[i],
                        vtype, vtow_coeff, 
                        v_ti, v_tj, w_hw, w_hh
                    );
            }
            glEnd();
            if(is_selected)
            {
                mp_vertex_struct *n = NULL, *vn = NULL;

                glEnable(GL_POINT_SMOOTH);
                glPointSize(3.0);
                glBegin(GL_POINTS);
                {
                    for(i = 0; i < V3DMP_QUAD_NVERTEX; i++)
                    {
                        if(i == sel_vtx)
                        {   
                            n = &mp_quad->n[i];
                            vn = &mp_quad->v[i];
                            DO_SET_COLOR_SEL_VERTEX
                        }
                        else
                            DO_SET_COLOR_UNSEL_VERTEX
                        View2DSetVertex(
                            v, &mp_quad->v[i],
                            vtype, vtow_coeff,
                            v_ti, v_tj, w_hw, w_hh
                        );
                    }
                }
                glEnd();

            DO_SET_COLOR_NORMAL
                View2DDrawNormalVector(
                    v, vn, n,
                    vtype, vtow_coeff,
                    v_ti, v_tj, w_hw, w_hh
                );
            }
            break;

         case V3DMP_TYPE_QUAD_STRIP:
            mp_quad_strip = p;
            c = palette->quad_strip;
          DO_SET_COLOR
          glBegin((is_selected) ? GL_QUAD_STRIP : GL_LINE_STRIP); 
            {
                for(i = 0; i < mp_quad_strip->total; i++)
                    View2DSetVertex(
                        v, mp_quad_strip->v[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
            }
            glEnd();
            if(is_selected)
            {
                mp_vertex_struct *n = NULL, *vn = NULL;

                glEnable(GL_POINT_SMOOTH);
                glPointSize(3.0);
                glBegin(GL_POINTS);
                {
                    for(i = 0; i < mp_quad_strip->total; i++)
                {
                        if(i == sel_vtx)
                        {
                            n = mp_quad_strip->n[i];
                            vn = mp_quad_strip->v[i];
                            DO_SET_COLOR_SEL_VERTEX
                        }
                        else
                            DO_SET_COLOR_UNSEL_VERTEX
                        View2DSetVertex(
                            v, mp_quad_strip->v[i],
                            vtype, vtow_coeff,
                            v_ti, v_tj, w_hw, w_hh
                        );
                }
                }
                glEnd();

            DO_SET_COLOR_NORMAL
                View2DDrawNormalVector(
                    v, vn, n,
                    vtype, vtow_coeff,
                    v_ti, v_tj, w_hw, w_hh
                );
            }
            break;

          case V3DMP_TYPE_POLYGON:
            mp_polygon = p;
            c = palette->polygon;
          DO_SET_COLOR
            glBegin((is_selected) ? GL_POLYGON : GL_LINE_LOOP);
            {
                for(i = 0; i < mp_polygon->total; i++)
                    View2DSetVertex(
                        v, mp_polygon->v[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
            }
            glEnd();
            if(is_selected)
            {
                mp_vertex_struct *n = NULL, *vn = NULL;

                glEnable(GL_POINT_SMOOTH);
                glPointSize(3.0);
                glBegin(GL_POINTS);
                {
                    for(i = 0; i < mp_polygon->total; i++)
                    {
                        if(i == sel_vtx)
                        {   
                            n = mp_polygon->n[i];
                            vn = mp_polygon->v[i];
                            DO_SET_COLOR_SEL_VERTEX
                        }
                        else
                            DO_SET_COLOR_UNSEL_VERTEX
                        View2DSetVertex(
                            v, mp_polygon->v[i],
                            vtype, vtow_coeff,
                            v_ti, v_tj, w_hw, w_hh
                        );
                }
                }
                glEnd();

            DO_SET_COLOR_NORMAL
                View2DDrawNormalVector(
                    v, vn, n,
                    vtype, vtow_coeff,
                    v_ti, v_tj, w_hw, w_hh
                );
            }
            break;

        case V3DMP_TYPE_TEXTURE_ORIENT_XY:
          if(v->type != VMA_VIEW2D_TYPE_XY)
            break;
          mp_texture_xy = p;
          c = palette->texture_outline;
          c_sel_solid = palette->texture_outline_selected;
          DO_SET_COLOR
            glBegin(GL_LINE_STRIP);
            {
            tv[0].x = mp_texture_xy->x;
                tv[0].y = mp_texture_xy->y;
                tv[0].z = 0.0;
                tv[1].x = mp_texture_xy->x + mp_texture_xy->dx;
                tv[1].y = mp_texture_xy->y;
                tv[1].z = 0.0;
                tv[2].x = mp_texture_xy->x + mp_texture_xy->dx;
                tv[2].y = mp_texture_xy->y + mp_texture_xy->dy;
                tv[2].z = 0.0;
                tv[3].x = mp_texture_xy->x;
                tv[3].y = mp_texture_xy->y + mp_texture_xy->dy;
                tv[3].z = 0.0;
            for(i = 0; i < 4; i++)
                    View2DSetVertex(
                        v, &tv[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
                /* Last to first. */ 
                View2DSetVertex(
                    v, &tv[0],
                    vtype, vtow_coeff,
                    v_ti, v_tj, w_hw, w_hh
                );
            }
            glEnd();
          /* X direction arrow. */
            glBegin(GL_LINE_STRIP);
            {
            double dx = mp_texture_xy->dx * 0.15;

                tv[0].x = mp_texture_xy->x + mp_texture_xy->dx - dx;
                tv[0].y = mp_texture_xy->y + dx;
                tv[0].z = 0.0;
                tv[1].x = mp_texture_xy->x + mp_texture_xy->dx;
                tv[1].y = mp_texture_xy->y;
                tv[1].z = 0.0;
                tv[2].x = mp_texture_xy->x + mp_texture_xy->dx - dx;
                tv[2].y = mp_texture_xy->y - dx;
                tv[2].z = 0.0;

                for(i = 0; i < 3; i++)
                    View2DSetVertex(
                        v, &tv[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
          }
          glEnd();
            /* Y direction arrow. */
            glBegin(GL_LINE_STRIP);
            {
                gdouble dy = mp_texture_xy->dy * 0.15;
                
                tv[0].x = mp_texture_xy->x - dy;
                tv[0].y = mp_texture_xy->y + mp_texture_xy->dy - dy;
                tv[0].z = 0.0;
                tv[1].x = mp_texture_xy->x;
                tv[1].y = mp_texture_xy->y + mp_texture_xy->dy;
                tv[1].z = 0.0;
                tv[2].x = mp_texture_xy->x + dy;
                tv[2].y = mp_texture_xy->y + mp_texture_xy->dy - dy;
                tv[2].z = 0.0;

                for(i = 0; i < 3; i++)
                    View2DSetVertex(
                        v, &tv[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
            }
            glEnd();
          break;

          case V3DMP_TYPE_TEXTURE_ORIENT_YZ:
            if(v->type != VMA_VIEW2D_TYPE_YZ)
                break;
            mp_texture_yz = p;
            c = palette->texture_outline;
            c_sel_solid = palette->texture_outline_selected;
          DO_SET_COLOR
            glBegin(GL_LINE_STRIP); 
            {
            tv[0].x = 0.0;
                tv[0].y = mp_texture_yz->y;
                tv[0].z = mp_texture_yz->z;
                tv[1].x = 0.0;
                tv[1].y = mp_texture_yz->y - mp_texture_yz->dy;
                tv[1].z = mp_texture_yz->z;
                tv[2].x = 0.0;
                tv[2].y = mp_texture_yz->y - mp_texture_yz->dy;
                tv[2].z = mp_texture_yz->z + mp_texture_yz->dz;
                tv[3].x = 0.0;
                tv[3].y = mp_texture_yz->y;
                tv[3].z = mp_texture_yz->z + mp_texture_yz->dz;
                for(i = 0; i < 4; i++)
                    View2DSetVertex(
                        v, &tv[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
                /* Last to first. */
                View2DSetVertex(
                    v, &tv[0],
                    vtype, vtow_coeff,
                    v_ti, v_tj, w_hw, w_hh
                );
            }
            glEnd();
            /* Y direction arrow. */
            glBegin(GL_LINE_STRIP);
            {
                gdouble dy = mp_texture_yz->dy * 0.15;

            tv[0].x = 0.0;
                tv[0].y = mp_texture_yz->y - mp_texture_yz->dy + dy;
                tv[0].z = mp_texture_yz->z + dy;
                tv[1].x = 0.0;
                tv[1].y = mp_texture_yz->y - mp_texture_yz->dy;
                tv[1].z = mp_texture_yz->z;
                tv[2].x = 0.0;
                tv[2].y = mp_texture_yz->y - mp_texture_yz->dy + dy;
                tv[2].z = mp_texture_yz->z - dy;

                for(i = 0; i < 3; i++)
                    View2DSetVertex(
                        v, &tv[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
            }
            glEnd();
            /* Z direction arrow. */
            glBegin(GL_LINE_STRIP);
            {
                gdouble dz = mp_texture_yz->dz * 0.15;

                tv[0].x = 0.0;
                tv[0].y = mp_texture_yz->y - dz;
                tv[0].z = mp_texture_yz->z + mp_texture_yz->dz - dz;
                tv[1].x = 0.0;
                tv[1].y = mp_texture_yz->y;
                tv[1].z = mp_texture_yz->z + mp_texture_yz->dz;
                tv[2].x = 0.0;
                tv[2].y = mp_texture_yz->y + dz;
                tv[2].z = mp_texture_yz->z + mp_texture_yz->dz - dz;
                
                for(i = 0; i < 3; i++)
                    View2DSetVertex(
                        v, &tv[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
            }
            glEnd();
            break;

          case V3DMP_TYPE_TEXTURE_ORIENT_XZ:
            if(v->type != VMA_VIEW2D_TYPE_XZ)
                break;
            mp_texture_xz = p;
            c = palette->texture_outline;
            c_sel_solid = palette->texture_outline_selected;
          DO_SET_COLOR
            glBegin(GL_LINE_STRIP);
            {
                tv[0].x = mp_texture_xz->x;
            tv[0].y = 0.0;
                tv[0].z = mp_texture_xz->z;
                tv[1].x = mp_texture_xz->x + mp_texture_xz->dx;
            tv[1].y = 0.0;
                tv[1].z = mp_texture_xz->z;
                tv[2].x = mp_texture_xz->x + mp_texture_xz->dx;
            tv[2].y = 0.0;
                tv[2].z = mp_texture_xz->z + mp_texture_xz->dz;
                tv[3].x = mp_texture_xz->x;
                tv[3].y = 0.0;
                tv[3].z = mp_texture_xz->z + mp_texture_xz->dz;
                for(i = 0; i < 4; i++)
                    View2DSetVertex(
                        v, &tv[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
                /* Last to first. */
                View2DSetVertex(
                    v, &tv[0],
                    vtype, vtow_coeff,
                    v_ti, v_tj, w_hw, w_hh
                );
            }
            glEnd();
            /* X direction arrow. */
            glBegin(GL_LINE_STRIP);
            {
                gdouble dx = mp_texture_xz->dx * 0.15;

                tv[0].x = mp_texture_xz->x + mp_texture_xz->dx - dx;
                tv[0].y = 0.0;
                tv[0].z = mp_texture_xz->z + dx;
                tv[1].x = mp_texture_xz->x + mp_texture_xz->dx;
                tv[1].y = 0.0;
                tv[1].z = mp_texture_xz->z;
                tv[2].x = mp_texture_xz->x + mp_texture_xz->dx - dx;
                tv[2].y = 0.0;
                tv[2].z = mp_texture_xz->z - dx;

                for(i = 0; i < 3; i++)
                    View2DSetVertex(
                        v, &tv[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
            }
            glEnd();
            /* Z direction arrow. */
            glBegin(GL_LINE_STRIP);
            {
                gdouble dz = mp_texture_xz->dz * 0.15;

                tv[0].x = mp_texture_xz->x - dz;
                tv[0].y = 0.0;
                tv[0].z = mp_texture_xz->z + mp_texture_xz->dz - dz;
                tv[1].x = mp_texture_xz->x;
                tv[1].y = 0.0;
                tv[1].z = mp_texture_xz->z + mp_texture_xz->dz;
                tv[2].x = mp_texture_xz->x + dz;
                tv[2].y = 0.0;
                tv[2].z = mp_texture_xz->z + mp_texture_xz->dz - dz;

                for(i = 0; i < 3; i++)
                    View2DSetVertex(
                        v, &tv[i],
                        vtype, vtow_coeff,
                        v_ti, v_tj, w_hw, w_hh
                    );
            }
          glEnd();
            break;

        case V3DMP_TYPE_HEIGHTFIELD_LOAD:
            mp_heightfield_load = p;
            c = palette->heightfield;
            DO_SET_COLOR

          if(1)
          {
            mp_vertex_struct tmp_v;
            double a[3], r[3];
            double      x_h = (mp_heightfield_load->x_length / 2),
                  y_h = (mp_heightfield_load->y_length / 2),
                  z_h_min = 0.0,
                  z_h_max = mp_heightfield_load->z_length;

            /* Begin setting vertexes of heightfield's `base',
             * relative to world coordinates.
             */
/* Takes object origin relative coordinates in 3 * 1 matrix a and
 * rotations and translations from mp_heightfield_load to set vertexes.
 */
#define DO_SET_HF_VTX   \
{ \
 MatrixRotateBank3(a, mp_heightfield_load->bank, r); \
 MatrixRotatePitch3(r, mp_heightfield_load->pitch, a); \
 MatrixRotateHeading3(a, mp_heightfield_load->heading, r); \
 tmp_v.x = r[0] + mp_heightfield_load->x; \
 tmp_v.y = r[1] + mp_heightfield_load->y; \
 tmp_v.z = r[2] + mp_heightfield_load->z; \
 View2DSetVertex( \
  v, &tmp_v, \
  vtype, vtow_coeff, \
  v_ti, v_tj, w_hw, w_hh \
 ); \
} 
            glBegin((is_selected) ? GL_POLYGON : GL_LINE_LOOP);
            {
                a[0] = -x_h;
                a[1] = y_h;
                a[2] = z_h_min;
                DO_SET_HF_VTX

                    a[0] = x_h;
                    a[1] = y_h;
                    a[2] = z_h_min;
                    DO_SET_HF_VTX

                    a[0] = x_h;
                    a[1] = -y_h;
                    a[2] = z_h_min;
                    DO_SET_HF_VTX

                    a[0] = -x_h;
                    a[1] = -y_h;
                    a[2] = z_h_min;
                    DO_SET_HF_VTX
            }
            glEnd();
            glBegin((is_selected) ? GL_POLYGON : GL_LINE_LOOP);
            {
                /* Begin setting vertexes of heightfield's upper
                 * maximum relative to world coordinates.
                 */
                a[0] = -x_h;
                a[1] = y_h;
                a[2] = z_h_max;
                DO_SET_HF_VTX

                a[0] = x_h;
                a[1] = y_h;
                a[2] = z_h_max;
                DO_SET_HF_VTX

                    a[0] = x_h;
                    a[1] = -y_h;
                    a[2] = z_h_max;
                    DO_SET_HF_VTX

                    a[0] = -x_h;
                    a[1] = -y_h;
                    a[2] = z_h_max;
                    DO_SET_HF_VTX
            }
            glEnd();

              if(is_selected)
            {

            }
            else
            {
                /* Is selected, draw vertical lines. */
                glBegin(GL_LINES);
                {
                  a[0] = -x_h;
                  a[1] = y_h;
                  a[2] = z_h_min;
                  DO_SET_HF_VTX

                        a[0] = -x_h;
                        a[1] = y_h;
                        a[2] = z_h_max;
                        DO_SET_HF_VTX


                        a[0] = x_h;
                        a[1] = y_h;
                        a[2] = z_h_min;
                        DO_SET_HF_VTX

                        a[0] = x_h;
                        a[1] = y_h;
                        a[2] = z_h_max;
                        DO_SET_HF_VTX


                        a[0] = x_h;
                        a[1] = -y_h;
                        a[2] = z_h_min;
                        DO_SET_HF_VTX

                        a[0] = x_h;
                        a[1] = -y_h;
                        a[2] = z_h_max;
                        DO_SET_HF_VTX


                        a[0] = -x_h;
                        a[1] = -y_h;
                        a[2] = z_h_min;
                        DO_SET_HF_VTX

                        a[0] = -x_h;
                        a[1] = -y_h;
                        a[2] = z_h_max;
                        DO_SET_HF_VTX
                }
                glEnd();
            }

#undef DO_SET_HF_VTX
          }

          break;

      }

#undef DO_SET_COLOR
#undef DO_SET_COLOR_NORMAL
#undef DO_SET_COLOR_SEL_VERTEX
#undef DO_SET_COLOR_UNSEL_VERTEX

      return;
}

/*
 *      Draws the primitive to the current context based on the given
 *      3d view.
 *
 *      All inputs except p assumed valid.
 */ 
static void View3DDoDrawPrimitive(
        vma_view3d_struct *v, ma_editor_struct *editor,
        v3d_model_struct *model, int model_num,
      void *p, gint pn,
        vma_view_palette_struct *palette
)
{
        gbool     is_selected = FALSE,
            render_state = v->render_state,
            translations_state = v->translations_state;
        gint i, spn, tex_num;
      GLint list;
      mp_translate_struct *mp_translate;
      mp_rotate_struct *mp_rotate;
        mp_point_struct *mp_point;
        mp_line_struct *mp_line;
        mp_line_strip_struct *mp_line_strip;
        mp_line_loop_struct *mp_line_loop;
        mp_triangle_struct *mp_triangle;
        mp_triangle_strip_struct *mp_triangle_strip;
        mp_triangle_fan_struct *mp_triangle_fan;   
        mp_quad_struct *mp_quad;
        mp_quad_strip_struct *mp_quad_strip;
        mp_polygon_struct *mp_polygon;
        mp_color_struct *mp_color;
      mp_texture_select_struct *mp_texture_select;
        mp_texture_orient_xy_struct *mp_texture_xy;
        mp_texture_orient_yz_struct *mp_texture_yz;
        mp_texture_orient_xz_struct *mp_texture_xz;
      mp_heightfield_load_struct *mp_heightfield_load;

        vma_color_struct *c, *c_sel, *c_sel_solid;


       if(p == NULL)
            return;

        /* Reset selected primitive select index, this will be used
         * to correspond to any selected vertices.
         */
        spn = -1;

        /* Check if this primitive is selected on the editor. */
      if(model_num == EditorSelectedModelIndex(editor))
      {
          for(i = 0; i < editor->total_selected_primitives; i++)
          {
            if(editor->selected_primitive[i] == pn)
            {
                is_selected = TRUE;
                spn = i;
                break;
            }
          }
      }

#define DO_SET_COLOR    \
{ \
 if(!render_state) \
 { \
  if(is_selected) \
  { \
   if(c_sel_solid == NULL) \
    glColor4d(1.0, 1.0, 0.0, 1.0); \
   else \
    glColor4d(c_sel_solid->r, c_sel_solid->g, c_sel_solid->b, c_sel_solid->a); \
  } \
  else \
  { \
   if(c == NULL) \
    glColor4d(0.8, 0.8, 0.8, 1.0); \
   else \
    glColor4d(c->r, c->g, c->b, c->a); \
  } \
 } \
}

#define DO_SET_COLOR_SEL_VERTEX     \
{ \
 if(!render_state) \
 { \
  if(c_sel == NULL) \
   glColor4d(1.0, 1.0, 1.0, 1.0); \
  else \
   glColor4d(c_sel->r, c_sel->g, c_sel->b, c_sel->a); \
 } \
}
      c = NULL;
      c_sel_solid = palette->selected;
      c_sel = palette->selected_vertex;

        switch(*(gint *)p)
        {
        case V3DMP_TYPE_TRANSLATE:
          if(translations_state)
          {
            mp_translate = p;

            view3d_matrix_level++;
            glPushMatrix();

            glTranslatef(
                (GLfloat)mp_translate->x,
                (GLfloat)mp_translate->z,
                (GLfloat)-mp_translate->y
            );
          }
          break;

          case V3DMP_TYPE_UNTRANSLATE:
            if(translations_state)
            {
            /* Can we pop a matrix? */
                if(view3d_matrix_level > 0)
                {
                    view3d_matrix_level--;
                    glPopMatrix();
                }
            }
            break;

          case V3DMP_TYPE_ROTATE:
            if(translations_state)
            {
                mp_rotate = p;

                view3d_matrix_level++;
                glPushMatrix();

                glRotatef(
                (GLfloat)-RADTODEG(mp_rotate->heading),
                    0.0, 1.0, 0.0
                );
                glRotatef(
                    (GLfloat)-RADTODEG(mp_rotate->pitch),
                    1.0, 0.0, 0.0
                );
            glRotatef(
                (GLfloat)-RADTODEG(mp_rotate->bank),
                    0.0, 0.0, 1.0
                );
            }
            break;

          case V3DMP_TYPE_UNROTATE:
            if(translations_state)
            {
                /* Can we pop a matrix? */
            if(view3d_matrix_level > 0)
            {
                    view3d_matrix_level--;
                    glPopMatrix();
            }
          }
          break;

          case V3DMP_TYPE_POINT:
            mp_point = (mp_point_struct *)p;
            c = palette->point;
            DO_SET_COLOR
            glEnable(GL_POINT_SMOOTH);
            glPointSize(MAX(mp_point->r, 1.0));
            glBegin(GL_POINTS);
            {
                for(i = 0; i < V3DMP_POINT_NVERTEX; i++)
            {
                View3DSetNormal(v, &mp_point->n[i]);
                    View3DSetVertex(
                        v, &mp_point->v[i], &mp_point->tc[i]
                    );
            }
            }
            glEnd();
            break;

          case V3DMP_TYPE_LINE:
            mp_line = (mp_line_struct *)p;
            c = palette->line;
            DO_SET_COLOR
            glBegin(GL_LINES);
            {
                for(i = 0; i < V3DMP_LINE_NVERTEX; i++)
            {
                View3DSetNormal(v, &mp_line->n[i]);
                    View3DSetVertex(
                        v, &mp_line->v[i], &mp_line->tc[i]
                    );
            }
            }
            glEnd();
            if(is_selected && !render_state)
            {
                i = EditorGetSelected(
                    editor->selected_value, editor->total_selected_values,
                    spn
                );
                if((i >= 0) && (i < V3DMP_LINE_NVERTEX))
                {
                    DO_SET_COLOR_SEL_VERTEX
                    glEnable(GL_POINT_SMOOTH);
                    glPointSize(3.0);

                    glBegin(GL_POINTS);
                    {
                        View3DSetVertex(
                            v, &mp_line->v[i], NULL
                  );
                    }
                    glEnd();
                }
            }
            break;

          case V3DMP_TYPE_LINE_STRIP:
            mp_line_strip = (mp_line_strip_struct *)p;
            c = palette->line_strip;
            DO_SET_COLOR
            glBegin(GL_LINE_STRIP);
            {
                for(i = 0; i < mp_line_strip->total; i++)
            {
                View3DSetNormal(v, mp_line_strip->n[i]);
                    View3DSetVertex(
                        v, mp_line_strip->v[i], mp_line_strip->tc[i]
                    );
            }
            }
            glEnd();
            if(is_selected && !render_state)
            {
                i = EditorGetSelected(
                editor->selected_value, editor->total_selected_values,
                spn
            );
                if((i >= 0) && (i < mp_line_strip->total))
                {
                    DO_SET_COLOR_SEL_VERTEX
                    glEnable(GL_POINT_SMOOTH);
                    glPointSize(3.0);
             
                    glBegin(GL_POINTS);   
                    {
                        View3DSetVertex(
                            v, mp_line_strip->v[i], NULL  
                        );
                    }
                    glEnd();
                }
            }
            break;

          case V3DMP_TYPE_LINE_LOOP:
            mp_line_loop = (mp_line_loop_struct *)p;
            c = palette->line_loop;
            DO_SET_COLOR
            glBegin(GL_LINE_LOOP);
            {
                for(i = 0; i < mp_line_loop->total; i++)
            {
                View3DSetNormal(v, mp_line_loop->n[i]);
                    View3DSetVertex(
                        v, mp_line_loop->v[i], mp_line_loop->tc[i]
                    );
            }
            }
            glEnd();
            if(is_selected && !render_state)
            {
                i = EditorGetSelected(
                    editor->selected_value, editor->total_selected_values, 
                    spn
                );
                if((i >= 0) && (i < mp_line_loop->total))
                {
                    DO_SET_COLOR_SEL_VERTEX
                    glEnable(GL_POINT_SMOOTH);
                    glPointSize(3.0);
            
                    glBegin(GL_POINTS);
                    {
                        View3DSetVertex(
                            v, mp_line_loop->v[i], NULL
                        );
                    }
                    glEnd();
                }
            }
            break;

          case V3DMP_TYPE_TRIANGLE:
            mp_triangle = (mp_triangle_struct *)p;
            c = palette->triangle;
            DO_SET_COLOR
            glBegin(render_state ? GL_TRIANGLES : GL_LINE_LOOP);
            {
                for(i = 0; i < V3DMP_TRIANGLE_NVERTEX; i++)
            {
                View3DSetNormal(v, &mp_triangle->n[i]);
                    View3DSetVertex(
                        v, &mp_triangle->v[i], &mp_triangle->tc[i]
                    );
            }
            }
            glEnd();
            if(is_selected && !render_state)
            {
                i = EditorGetSelected(
                    editor->selected_value, editor->total_selected_values, 
                    spn
                );
                if((i >= 0) && (i < V3DMP_TRIANGLE_NVERTEX))
                {
                    DO_SET_COLOR_SEL_VERTEX
                    glEnable(GL_POINT_SMOOTH);    
                    glPointSize(3.0);
             
                    glBegin(GL_POINTS);
                    {
                        View3DSetVertex(
                            v, &mp_triangle->v[i], NULL
                        );
                    }
                    glEnd();
                }
            }
            break;

          case V3DMP_TYPE_TRIANGLE_STRIP:
            mp_triangle_strip = (mp_triangle_strip_struct *)p;
            c = palette->triangle_strip;
            DO_SET_COLOR
            glBegin(render_state ? GL_TRIANGLE_STRIP : GL_LINE_LOOP);
            {
                for(i = 0; i < mp_triangle_strip->total; i++)
            {
                View3DSetNormal(v, mp_triangle_strip->n[i]);
                    View3DSetVertex(
                        v, mp_triangle_strip->v[i], mp_triangle_strip->tc[i]
                    );
            }
            }
            glEnd();
            if(is_selected && !render_state)
            {
                i = EditorGetSelected(
                    editor->selected_value, editor->total_selected_values, 
                    spn
                );
                if((i >= 0) && (i < mp_triangle_strip->total))
                {
                    DO_SET_COLOR_SEL_VERTEX
                    glEnable(GL_POINT_SMOOTH);
                    glPointSize(3.0);
          
                    glBegin(GL_POINTS);
                    {
                        View3DSetVertex(
                            v, mp_triangle_strip->v[i], NULL
                        );
                    }
                    glEnd();
                }
            }
            break;

          case V3DMP_TYPE_TRIANGLE_FAN:
            mp_triangle_fan = (mp_triangle_fan_struct *)p;
            c = palette->triangle_fan;
            DO_SET_COLOR
            glBegin(render_state ? GL_TRIANGLE_FAN : GL_LINE_LOOP);
            {
                for(i = 0; i < mp_triangle_fan->total; i++)
            {
                View3DSetNormal(v, mp_triangle_fan->n[i]);
                    View3DSetVertex(
                        v, mp_triangle_fan->v[i], mp_triangle_fan->tc[i]
                    );
            }
            }
            glEnd();
            if(is_selected && !render_state)
            {
                i = EditorGetSelected(
                    editor->selected_value, editor->total_selected_values,
                    spn
                );
                if((i >= 0) && (i < mp_triangle_fan->total)) 
                {
                    DO_SET_COLOR_SEL_VERTEX
                    glEnable(GL_POINT_SMOOTH);
                    glPointSize(3.0);
          
                    glBegin(GL_POINTS);
                    {
                        View3DSetVertex(
                            v, mp_triangle_fan->v[i], NULL
                        );
                    }
                    glEnd();
                }
            }
            break;

          case V3DMP_TYPE_QUAD:
            mp_quad = (mp_quad_struct *)p;
            c = palette->quad;
            DO_SET_COLOR
            glBegin(render_state ? GL_QUADS : GL_LINE_LOOP);
            {
                for(i = 0; i < V3DMP_QUAD_NVERTEX; i++)
            {
                View3DSetNormal(v, &mp_quad->n[i]);
                    View3DSetVertex(
                        v, &mp_quad->v[i], &mp_quad->tc[i]
                    );
            }
            }
            glEnd();
            if(is_selected && !render_state)
            {
                i = EditorGetSelected(
                    editor->selected_value, editor->total_selected_values,
                    spn
                );
                if((i >= 0) && (i < V3DMP_QUAD_NVERTEX))
                {
                    DO_SET_COLOR_SEL_VERTEX
                    glEnable(GL_POINT_SMOOTH);
                    glPointSize(3.0); 
          
                    glBegin(GL_POINTS);
                    {
                        View3DSetVertex(
                            v, &mp_quad->v[i], NULL
                        );
                    }
                    glEnd();
                }
            }
            break;

          case V3DMP_TYPE_QUAD_STRIP:
            mp_quad_strip = (mp_quad_strip_struct *)p;
            c = palette->quad_strip;
            DO_SET_COLOR
            glBegin(render_state ? GL_QUAD_STRIP : GL_LINE_STRIP);
            {
                for(i = 0; i < mp_quad_strip->total; i++)
            {
                View3DSetNormal(v, mp_quad_strip->n[i]);
                    View3DSetVertex(
                        v, mp_quad_strip->v[i], mp_quad_strip->tc[i]
                    );
            }
            }
            glEnd();
            if(is_selected && !render_state)
            {
                i = EditorGetSelected(
                    editor->selected_value, editor->total_selected_values,
                    spn
                );
                if((i >= 0) && (i < mp_quad_strip->total))
                {
                    DO_SET_COLOR_SEL_VERTEX
                    glEnable(GL_POINT_SMOOTH);
                    glPointSize(3.0);
          
                    glBegin(GL_POINTS);
                    {
                        View3DSetVertex(
                            v, mp_quad_strip->v[i], NULL
                        );
                    }
                    glEnd();
                }
            }
            break;

          case V3DMP_TYPE_POLYGON:
            mp_polygon = (mp_polygon_struct *)p;
            c = palette->polygon;
            DO_SET_COLOR
            glBegin(render_state ? GL_POLYGON : GL_LINE_LOOP);
            {
                for(i = 0; i < mp_polygon->total; i++)
            {
                View3DSetNormal(v, mp_polygon->n[i]);
                    View3DSetVertex(
                        v, mp_polygon->v[i], mp_polygon->tc[i]
                    );
            }
            }
            glEnd();
            if(is_selected && !render_state)
            {
                i = EditorGetSelected(
                    editor->selected_value, editor->total_selected_values,
                    spn
                );
                if((i >= 0) && (i < mp_polygon->total))
                {
                    DO_SET_COLOR_SEL_VERTEX
                    glEnable(GL_POINT_SMOOTH);
                    glPointSize(3.0);
          
                    glBegin(GL_POINTS);
                    {
                        View3DSetVertex(
                            v, mp_polygon->v[i], NULL
                        );
                    }
                    glEnd();
                }
            }
            break;


        case V3DMP_TYPE_COLOR:
          mp_color = (mp_color_struct *)p;
          if(render_state)
          {
            GLenum face = (v->cull_state) ?
                GL_FRONT : GL_FRONT_AND_BACK;
            GLfloat cv[4];

            glColor4d(
                (GLfloat)mp_color->r,
                (GLfloat)mp_color->g,
                (GLfloat)mp_color->b,
                (GLfloat)mp_color->a
            );

            cv[0] = (GLfloat)(mp_color->r * mp_color->ambient);
                cv[1] = (GLfloat)(mp_color->g * mp_color->ambient);
                cv[2] = (GLfloat)(mp_color->b * mp_color->ambient);
                cv[3] = (GLfloat)(mp_color->a);
            glMaterialfv(face, GL_AMBIENT, cv);

                cv[0] = (GLfloat)(mp_color->r * mp_color->diffuse);
                cv[1] = (GLfloat)(mp_color->g * mp_color->diffuse);
                cv[2] = (GLfloat)(mp_color->b * mp_color->diffuse);
                cv[3] = (GLfloat)(mp_color->a);
                glMaterialfv(face, GL_DIFFUSE, cv);

                cv[0] = (GLfloat)(mp_color->r * mp_color->specular);
                cv[1] = (GLfloat)(mp_color->g * mp_color->specular);
                cv[2] = (GLfloat)(mp_color->b * mp_color->specular);
                cv[3] = (GLfloat)(mp_color->a);
                glMaterialfv(face, GL_SPECULAR, cv);

                cv[0] = (GLfloat)(mp_color->shininess * 128.0);
                glMaterialfv(face, GL_SHININESS, cv);

                cv[0] = (GLfloat)(mp_color->r * mp_color->emission);
                cv[1] = (GLfloat)(mp_color->g * mp_color->emission);
                cv[2] = (GLfloat)(mp_color->b * mp_color->emission);
                cv[3] = (GLfloat)(mp_color->a);
                glMaterialfv(face, GL_EMISSION, cv);
          }
          break;

        case V3DMP_TYPE_TEXTURE_SELECT:
          mp_texture_select = (mp_texture_select_struct *)p;
          if(!render_state)
            break;
          tex_num = (gint)mp_texture_select->client_data;
          if((tex_num < 0) || (tex_num >= editor->total_textures))
            break;
          if(editor->texture[tex_num] == NULL)
            break;
          V3DTextureSelect(editor->texture[tex_num]);
/*            glEnable(GL_TEXTURE_1D); */
            glEnable(GL_TEXTURE_2D);
          glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
            texture_state = VMA_VIEW_TEXTURE_STATE_ON;
          break;

        case V3DMP_TYPE_TEXTURE_ORIENT_XY:
          mp_texture_xy = p;
            if(!render_state)
                break;
          texture_state = VMA_VIEW_TEXTURE_STATE_XY;
          texture_orient_i0 = mp_texture_xy->x;
          texture_orient_j0 = mp_texture_xy->y;
          texture_orient_id = mp_texture_xy->dx;
          texture_orient_jd = mp_texture_xy->dy;
          break;

          case V3DMP_TYPE_TEXTURE_ORIENT_YZ:
            mp_texture_yz = p;
            if(!render_state)
                break;
            texture_state = VMA_VIEW_TEXTURE_STATE_YZ;
            texture_orient_i0 = mp_texture_yz->y;
            texture_orient_j0 = mp_texture_yz->z;
            texture_orient_id = mp_texture_yz->dy;
            texture_orient_jd = mp_texture_yz->dz;
            break;

          case V3DMP_TYPE_TEXTURE_ORIENT_XZ:
            mp_texture_xz = p;
            if(!render_state)
                break;
            texture_state = VMA_VIEW_TEXTURE_STATE_XZ;
            texture_orient_i0 = mp_texture_xz->x;
            texture_orient_j0 = mp_texture_xz->z;
            texture_orient_id = mp_texture_xz->dx;
            texture_orient_jd = mp_texture_xz->dz;
            break;

        case V3DMP_TYPE_TEXTURE_OFF:
            if(!render_state)
                break;
/*
          V3DTextureSelect(NULL);
 */
          texture_state = VMA_VIEW_TEXTURE_STATE_OFF;
            glDisable(GL_TEXTURE_1D);
            glDisable(GL_TEXTURE_2D);
          break;

        case V3DMP_TYPE_HEIGHTFIELD_LOAD:
          mp_heightfield_load = p;
          list = (GLint)mp_heightfield_load->gl_list;
          if(list <= 0)
            break;

          glPushMatrix();
          {
                glTranslatef(
                    (GLfloat)mp_heightfield_load->x,
                    (GLfloat)mp_heightfield_load->z,
                    (GLfloat)-mp_heightfield_load->y
                );
                glRotatef(
                (GLfloat)-RADTODEG(mp_heightfield_load->heading),
                    0.0, 1.0, 0.0
                );
                glRotatef(
                    (GLfloat)-RADTODEG(mp_heightfield_load->pitch),
                    1.0, 0.0, 0.0
                );
                glRotatef(
                    (GLfloat)-RADTODEG(mp_heightfield_load->bank),
                    0.0, 0.0, 1.0
                );
            /* Now translated and rotated to the proper location. */
            if(render_state)
            {
                if(mp_heightfield_load->gl_list != NULL)
                  glCallList((GLint)mp_heightfield_load->gl_list);
            }
            else
            {
                gdouble xh = (mp_heightfield_load->x_length / 2),
                     yh = (mp_heightfield_load->y_length / 2),
                     z = mp_heightfield_load->z_length;

                    c = palette->heightfield;
                    DO_SET_COLOR

                glBegin(GL_LINE_LOOP);
                {
                  glVertex3d(
                      (0.0 - xh),
                      (0.0 - 0.0),
                      -(0.0 + yh)
                  );
                        glVertex3d(
                            (0.0 + xh),
                            (0.0 - 0.0),
                            -(0.0 + yh)
                        );
                        glVertex3d(
                            (0.0 + xh),
                            (0.0 - 0.0),
                            -(0.0 - yh)
                        );
                        glVertex3d(
                            (0.0 - xh),
                            (0.0 - 0.0),
                            -(0.0 - yh)
                        );
                }
                glEnd();
                    glBegin(GL_LINE_LOOP);
                    {
                        glVertex3d(
                            (0.0 - xh),
                            (0.0 + z),
                            -(0.0 + yh)
                        );
                        glVertex3d(
                            (0.0 + xh),
                            (0.0 + z),
                            -(0.0 + yh)
                        );
                        glVertex3d(
                            (0.0 + xh),
                            (0.0 + z),
                            -(0.0 - yh)
                        );
                        glVertex3d(
                            (0.0 - xh),
                            (0.0 + z),
                            -(0.0 - yh)
                        );
                    }
                    glEnd();
                    glBegin(GL_LINES);
                {
                        glVertex3d(
                            (0.0 - xh),
                            (0.0 - 0.0),
                            -(0.0 + yh)
                        );
                        glVertex3d(
                            (0.0 - xh),
                            (0.0 + z),
                            -(0.0 + yh)
                        );

                        glVertex3d(
                            (0.0 + xh),
                            (0.0 - 0.0),
                            -(0.0 + yh)
                        );
                        glVertex3d(
                            (0.0 + xh),
                            (0.0 + z),
                            -(0.0 + yh)
                        );

                        glVertex3d(
                            (0.0 + xh),
                            (0.0 - 0.0),
                            -(0.0 - yh)
                        );
                        glVertex3d(
                            (0.0 + xh),
                            (0.0 + z),
                            -(0.0 - yh)
                        );

                        glVertex3d(
                            (0.0 - xh),
                            (0.0 + z),
                            -(0.0 - yh)
                        );
                        glVertex3d(
                            (0.0 - xh),
                            (0.0 + z),
                            -(0.0 - yh)
                        );
                }
                glEnd();

            }
          }
          glPopMatrix();
          break;

      }

#undef DO_SET_COLOR
#undef DO_SET_COLOR_SEL_VERTEX

      return;
}


/*
 *    Draws grid to the current OpenGL context.
 *
 *    Inputs assumed valid.
 */
static void View2DDrawGrid(
      vma_view2d_struct *v, gint ww, gint wh,
      vma_view_palette_struct *palette
)
{
      gdouble wi, wj, vi, vj, w_i_start, w_j_start;
      gdouble v_grid_spacing = v->grid_spacing;
      gdouble w_grid_spacing;
      gdouble vtow_coeff = View2DGetVToWCoeff(v);
        gdouble  w_hw = ww / 2,  /* Window half dimensions. */
                w_hh = wh / 2;
        gdouble  v_ti = v->v_ti, /* View translations. */
                v_tj = v->v_tj;
      gdouble i_flip_coeff = 1.0, j_flip_coeff = 1.0;
      vma_color_struct *c;
      gchar text[80];


      w_grid_spacing = v_grid_spacing * vtow_coeff;
        /* Grid spacing too small, thus cause too many grids? */ 
        if((gint)w_grid_spacing < 10)
            return;

      w_i_start = -(gdouble)(
          (gint)(v_ti * vtow_coeff) % (gint)w_grid_spacing
      );
      w_j_start = -(gdouble)(
            (gint)(v_tj * vtow_coeff) % (gint)w_grid_spacing
        );

      i_flip_coeff = ((v->flags & VMA_VIEW_FLAG_FLIP_I) ? -1 : 1);
        j_flip_coeff = ((v->flags & VMA_VIEW_FLAG_FLIP_J) ? -1 : 1);


      /* Set grid color. */
      c = palette->grid;
      if(c != NULL)
          glColor4d(c->r, c->g, c->b, c->a);
      else
          glColor4d(0.4, 0.4, 0.4, 1.0);

      /* Begin drawing grids. */
      if(1)
      {
          /* Vertical grid lines. */
          for(wi = w_i_start + w_hw - w_grid_spacing,
            vi = (w_i_start / vtow_coeff) + v->v_ti - v_grid_spacing;
                wi > 0;
                wi -= w_grid_spacing,
            vi -= v_grid_spacing
          )
          {
            glBegin(GL_LINES);
            {
                   glVertex2d(wi, 0.0);
                 glVertex2d(wi, wh);
            }
            glEnd();
            sprintf(text, "%.0f", vi * i_flip_coeff);
                ViewDrawString(font_6x10, wi + 2, wh - 14, text);
          }
            for(wi = w_i_start + w_hw,
                vi = (w_i_start / vtow_coeff) + v->v_ti;
                wi < ww;
                wi += w_grid_spacing,
                vi += v_grid_spacing
            )
            {
                glBegin(GL_LINES);
                {
                     glVertex2d(wi, 0.0);
                     glVertex2d(wi, wh);
                }
                glEnd();
                sprintf(text, "%.0f", vi * i_flip_coeff);
                ViewDrawString(font_6x10, wi + 2, wh - 14, text);
          }

            /* Horizontal grid lines. */
            for(wj = w_j_start + w_hh - w_grid_spacing,
                vj = (w_j_start / vtow_coeff) + v->v_tj - v_grid_spacing;
                wj > 0;
                wj -= w_grid_spacing,
                vj -= v_grid_spacing
            )
            {
                glBegin(GL_LINES);
                {
                     glVertex2d(0.0, wj);
                     glVertex2d(ww, wj);
                }
                glEnd();
                sprintf(text, "%.0f", vj * j_flip_coeff);
                ViewDrawString(font_6x10, 2, wj - 14, text);
            }
            for(wj = w_j_start + w_hh,
                vj = (w_j_start / vtow_coeff) + v->v_tj;
                wj < wh;
                wj += w_grid_spacing,
                vj += v_grid_spacing
            )
            {
                glBegin(GL_LINES);
                {
                     glVertex2d(0.0, wj); 
                     glVertex2d(ww, wj); 
                }
                glEnd();
                sprintf(text, "%.0f", vj * j_flip_coeff);
                ViewDrawString(font_6x10, 2, wj - 14, text);
            }
        }

      return;
}

/*
 *      Draws a 3d grid to the current OpenGL context.
 *
 *      Inputs assumed valid.
 */
static void View3DDrawGrid(
        vma_view3d_struct *v, vma_view_palette_struct *palette
)
{
      int i, max_grids_half = 10;
      double x, y;
      double      grid_spacing_x = v->grid_spacing,
            grid_spacing_y = v->grid_spacing;
      double grid_start_dx, grid_start_dy;
      double grid_start_x, grid_start_y;
      vma_color_struct *c;


      /* Grid spacing too small? */
      if(((gint)grid_spacing_x < 1) ||
           ((gint)grid_spacing_y < 1)
      )
          return;
         
        c = palette->grid;
        if(c != NULL)
            glColor4d(c->r, c->g, c->b, c->a);
        else
            glColor4d(0.4, 0.4, 0.4, 1.0);

      grid_start_dx = (gint)v->cam_x % (gint)grid_spacing_x;
      grid_start_dy = (gint)v->cam_y % (gint)grid_spacing_y;

      grid_start_x = (gint)v->cam_x - (gint)grid_start_dx;
      grid_start_y = (gint)v->cam_y - (gint)grid_start_dy;


      /* Draw grids along x axis. */
      glBegin(GL_LINES);
      {
          for(i = 0,
                x = grid_start_x;
                i < max_grids_half;
                i++,
                x += grid_spacing_x
          )
          {
            glVertex3d(
                x,
                0.0,
                -((-max_grids_half * grid_spacing_y) +
                  v->cam_y)
            );
                glVertex3d(
                    x,
                    0.0,
                    -((max_grids_half * grid_spacing_y) +
                  v->cam_y)
                );
          }

            for(i = 1,
                x = grid_start_x - grid_spacing_x;
                i < max_grids_half;
                i++,
                x -= grid_spacing_x
            )
            {
                glVertex3d(
                    x,
                    0.0,
                    -((-max_grids_half * grid_spacing_y) +
                  v->cam_y)
                );
                glVertex3d(
                    x,
                    0.0,
                    -((max_grids_half * grid_spacing_y) +
                  v->cam_y)
                );
            }
      }
      glEnd();

        /* Draw grids along y axis. */
        glBegin(GL_LINES);
        {
            for(i = 0,
                y = grid_start_y;
                i < max_grids_half;
                i++,
                y += grid_spacing_y
            )
            {
                glVertex3d(
                    ((-max_grids_half * grid_spacing_x) +
                  v->cam_x),
                    0.0,
                    -y
                );
                glVertex3d(
                    ((max_grids_half * grid_spacing_x) + 
                  v->cam_x),
                    0.0,
                    -y
                );
            }

            for(i = 1,
                y = grid_start_y - grid_spacing_y;
                i < max_grids_half;
                i++,
                y -= grid_spacing_y
            )
            {
                glVertex3d(
                    ((-max_grids_half * grid_spacing_x) +
                  v->cam_x),
                    0.0,
                    -y                                
                );
                glVertex3d(
                    ((max_grids_half * grid_spacing_x) +
                  v->cam_x),
                    0.0,
                    -y
                );
            }
        }
        glEnd();

      return;
}

/*
 *    Draws rectangle displaying rectangular select.
 *
 *    Inputs assumed valid.
 */
static void View2DDrawSelectRectangle(
      vma_view2d_struct *v, gint ww, gint wh,
      vma_view_palette_struct *palette
)
{

      double      wi0 = v->w_sel_rect_i0,
            wj0 = wh - v->w_sel_rect_j0,
            wi1 = v->w_sel_rect_i1,
            wj1 = wh - v->w_sel_rect_j1;
      vma_color_struct *c;

      c = palette->cursory;
      if(c == NULL)
          glColor4d(1.0, 1.0, 1.0, 1.0);
      else
          glColor4d(c->r, c->g, c->b, c->a);

      /* Flip if higher is less. */
      if(wi0 > wi1)
      {
          gdouble d_tmp = wi1;
          wi1 = wi0;
          wi0 = d_tmp;
      }
        if(wj0 > wj1)
        {
            gdouble d_tmp = wj1;
            wj1 = wj0;
            wj0 = d_tmp;
        }

      glBegin(GL_LINE_LOOP);
      {
          glVertex2d(wi0, wj0);
            glVertex2d(wi1, wj0);
            glVertex2d(wi1, wj1);
            glVertex2d(wi0, wj1);
      }
      glEnd();

      return;
}

/*
 *    Draws view's cursor.
 */
static void View2DDrawCursor(
        vma_view2d_struct *v, gint ww, gint wh,
        vma_view_palette_struct *palette
)
{
        gdouble   w_hw = (gdouble)ww / 2, /* Window half dimensions. */
            w_hh = (gdouble)wh / 2;
        gdouble   v_ti = v->v_ti,         /* View translations. */
            v_tj = v->v_tj;
      gdouble wcenter_i, wcenter_j;
      gdouble i_flip_coeff, j_flip_coeff;
      gdouble vtow_coeff;
      gint vtype;
        vma_color_struct *c;

        GLsizei icon_width = 16, icon_height = 16;
      const GLubyte cursor_fg[] = {
0x00, 0x00,
0x01, 0x00,
0x01, 0x00,
0x01, 0x00,
0x01, 0x00,
0x01, 0x00,
0x00, 0x00,
0x7c, 0x7c,
0x00, 0x00,
0x01, 0x00,
0x01, 0x00,
0x01, 0x00,
0x01, 0x00,
0x01, 0x00,
0x00, 0x00,
0x00, 0x00
      };
        const GLubyte cursor_bg[] = {
0x01, 0x00,
0x02, 0x80,
0x02, 0x80,
0x02, 0x80,
0x02, 0x80,
0x02, 0x80,
0x7f, 0xfc,
0x82, 0x82,
0x7f, 0xfc,
0x02, 0x80,
0x02, 0x80,
0x02, 0x80,
0x02, 0x80,
0x02, 0x80,
0x01, 0x00,
0x00, 0x00
      };


      /* Get type of view. */
      vtype = v->type;

      /* Set color. */
        c = palette->cursory;
        if(c == NULL)
            glColor4d(1.0, 1.0, 1.0, 1.0);
        else
            glColor4d(c->r, c->g, c->b, c->a);

        /* Calculate view to window coefficient. */
        vtow_coeff = View2DGetVToWCoeff(v);

      /* Calculate flip coeff. */
        i_flip_coeff = ((v->flags & VMA_VIEW_FLAG_FLIP_I) ? -1.0 : 1.0);
        j_flip_coeff = ((v->flags & VMA_VIEW_FLAG_FLIP_J) ? -1.0 : 1.0);


      /* Draw using the view's cursor view coordinates since they
       * are gauranteed to be correct instead of the cursor window
       * coordinates.
       */
      wcenter_i = (((v->v_cur_i * i_flip_coeff) - v_ti) * vtow_coeff) + w_hw;
      wcenter_j = (((v->v_cur_j * j_flip_coeff) - v_tj) * vtow_coeff) + w_hh;

        /* Draw cursor foreground. */
        /* Set color. */
        c = palette->cursory;
        if(c == NULL)
            glColor4d(1.0, 1.0, 1.0, 1.0);
        else
            glColor4d(1.0 - c->r, 1.0 - c->g, 1.0 - c->b, c->a);
        glRasterPos2d(
            (GLdouble)(wcenter_i - (icon_width / 2) + 1),
            (GLdouble)(wcenter_j - (icon_height / 2) + 1)
        );
        glBitmap(
            icon_width, icon_height,
            0.0, 0.0,
            0.0, 0.0,
          cursor_bg
        );

      /* Draw cursor foreground. */
        /* Set color. */
        c = palette->cursory;
        if(c == NULL)
            glColor4d(1.0, 1.0, 1.0, 1.0);
        else
            glColor4d(c->r, c->g, c->b, c->a);
        glRasterPos2d(
            (GLdouble)(wcenter_i - (icon_width / 2) + 1),
            (GLdouble)(wcenter_j - (icon_height / 2) + 1)
        );
        glBitmap(
            icon_width, icon_height,
            0.0, 0.0,
            0.0, 0.0,
            cursor_fg
        );


      return;
}

/*
 *      Draws the given light on the 2d view as an icon.
 */
static void View2DDrawLight( 
        vma_view2d_struct *v, gint ww, gint wh,
        vma_view_palette_struct *palette,
      vma_light_struct *light_ptr, gint light_num
)
{
        gdouble  w_hw = (gdouble)ww / 2,  /* Window half dimensions. */
                w_hh = (gdouble)wh / 2;
        gdouble  v_ti = v->v_ti,         /* View translations. */
                v_tj = v->v_tj;
        gdouble wiw, wih, wcenter_i = 0.0, wcenter_j = 0.0;
        gdouble i_flip_coeff, j_flip_coeff;
        gdouble vtow_coeff;
        gint vtype;
        vma_color_struct *c;

      GLsizei icon_width = 16, icon_height = 16;
      const GLubyte icon_omnidirectional[] = {
0x01, 0x00, 
0x01, 0x00, 
0x20, 0x08, 
0x13, 0x90, 
0x04, 0x40, 
0x09, 0x20, 
0x11, 0x10, 
0xd7, 0xd6, 
0x11, 0x10, 
0x09, 0x20, 
0x04, 0x40, 
0x13, 0x90, 
0x20, 0x08, 
0x01, 0x00, 
0x01, 0x00, 
      };
      const GLubyte icon_directional[] = {
0x00, 0x00, 
0x00, 0x00, 
0x00, 0x80, 
0x00, 0x88, 
0x0c, 0x10, 
0x0a, 0xc0, 
0x09, 0x20, 
0x08, 0xa6, 
0x08, 0x40, 
0x18, 0x20, 
0x28, 0x10, 
0x4f, 0xf0, 
0x42, 0x00, 
0x24, 0x00, 
0x18, 0x00, 
0x00, 0x00
      };


      /* Skip if this light is not enabled. */
      if(!(light_ptr->flags & VMA_LIGHT_FLAG_ENABLED))
          return;

        /* Get type of view. */
        vtype = v->type;

        /* Set color. */
        c = palette->cursory;
        if(c == NULL)
            glColor4d(1.0, 1.0, 1.0, 1.0);
        else
            glColor4d(c->r, c->g, c->b, c->a);

        /* Calculate view to window coefficient. */
        vtow_coeff = View2DGetVToWCoeff(v);

        /* Calculate icon size in window units. */
        wiw = 8.0;
      wih = 8.0;

        /* Calculate flip coeff. */
        i_flip_coeff = ((v->flags & VMA_VIEW_FLAG_FLIP_I) ? -1.0 : 1.0);
        j_flip_coeff = ((v->flags & VMA_VIEW_FLAG_FLIP_J) ? -1.0 : 1.0);


        /* Draw using the view's cursor view coordinates since they
         * are gauranteed to be correct instead of the cursor window
         * coordinates.
         */ 
        switch(vtype)
        {
          case VMA_VIEW2D_TYPE_XY:
            wcenter_i = (
            ((light_ptr->x * i_flip_coeff) - v_ti) * vtow_coeff
          ) + w_hw;
          wcenter_j = (
            ((light_ptr->y * j_flip_coeff) - v_tj) * vtow_coeff
          ) + w_hh;
            break;

          case VMA_VIEW2D_TYPE_YZ:
            wcenter_i = (
                ((light_ptr->y * i_flip_coeff) - v_ti) * vtow_coeff
            ) + w_hw;
            wcenter_j = (
                ((light_ptr->z * j_flip_coeff) - v_tj) * vtow_coeff   
            ) + w_hh;
            break;

          case VMA_VIEW2D_TYPE_XZ:
            wcenter_i = (
                ((light_ptr->x * i_flip_coeff) - v_ti) * vtow_coeff
            ) + w_hw;
            wcenter_j = (
                ((light_ptr->z * j_flip_coeff) - v_tj) * vtow_coeff   
            ) + w_hh;
            break;
        }

      /* Draw light icon. */
        glRasterPos2d(
          (GLdouble)(wcenter_i - (icon_width / 2) + 1),
          (GLdouble)(wcenter_j - (icon_height / 2) + 1)
      );
      glBitmap(
          icon_width, icon_height,
          0.0, 0.0,
          (GLfloat)icon_width, 0.0,
          (light_ptr->spot_cutoff > (0.5 * PI)) ?
            icon_omnidirectional : icon_directional
      );

      /* Draw normal line (if omni-directional). */
      if(light_ptr->spot_cutoff <= (0.5 * PI))
      {
          gdouble wnl_i[2], wnl_j[2];     /* Normal line coordinates. */
          gdouble wnl_m = 16.0;     /* Normal line magnitude. */
          gdouble wcol_i, wcol_j;   /* Cutoff bound points. */
            gdouble wcoh_i, wcoh_j;
          gdouble a[3 * 1], r[3 * 1];


          /* Begin calculating normal line in window coordinates. */

          /* We get the initial point free. */
          wnl_i[0] = wcenter_i;
          wnl_j[0] = wcenter_j;
          wnl_i[1] = wcenter_i;
            wnl_j[1] = wcenter_j;
          wcol_i = wcol_j = 0.0;
          wcoh_i = wcoh_j = 0.0;

          /* Calculate normal line and cutoff line based on view
           * orientation type.
           */
            switch(vtype)
            {
              case VMA_VIEW2D_TYPE_XY:
            a[0] = 0.0;
            a[1] = wnl_m;
            a[2] = 0.0;
            MatrixRotateBank3(a, light_ptr->bank, r);
            MatrixRotatePitch3(r, light_ptr->pitch, a);
            MatrixRotateHeading3(a, light_ptr->heading, r);
            wnl_i[1] = wnl_i[0] + (r[0] * i_flip_coeff);
                wnl_j[1] = wnl_j[0] + (r[1] * j_flip_coeff);

                a[0] = wnl_m * sin(light_ptr->spot_cutoff);
                a[1] = wnl_m * cos(light_ptr->spot_cutoff);
                a[2] = wnl_m * -sin(light_ptr->spot_cutoff);
                MatrixRotateBank3(a, light_ptr->bank, r);  
                MatrixRotatePitch3(r, light_ptr->pitch, a);  
                MatrixRotateHeading3(a, light_ptr->heading, r);  
                wcoh_i = wnl_i[0] + (r[0] * i_flip_coeff);
                wcoh_j = wnl_j[0] + (r[1] * j_flip_coeff);

                a[0] = wnl_m * sin(-light_ptr->spot_cutoff);
                a[1] = wnl_m * cos(-light_ptr->spot_cutoff);
                a[2] = wnl_m * -sin(-light_ptr->spot_cutoff);
                MatrixRotateBank3(a, light_ptr->bank, r);
                MatrixRotatePitch3(r, light_ptr->pitch, a);
                MatrixRotateHeading3(a, light_ptr->heading, r);
                wcol_i = wnl_i[0] + (r[0] * i_flip_coeff);
                wcol_j = wnl_j[0] + (r[1] * j_flip_coeff);
            break;

              case VMA_VIEW2D_TYPE_YZ:
                a[0] = 0.0;
                a[1] = wnl_m;
                a[2] = 0.0;
                MatrixRotateBank3(a, light_ptr->bank, r);
                MatrixRotatePitch3(r, light_ptr->pitch, a);
                MatrixRotateHeading3(a, light_ptr->heading, r);
                wnl_i[1] = wnl_i[0] + (r[1] * i_flip_coeff);
                wnl_j[1] = wnl_j[0] + (r[2] * j_flip_coeff);

                a[0] = wnl_m * sin(light_ptr->spot_cutoff);
                a[1] = wnl_m * cos(light_ptr->spot_cutoff);
                a[2] = wnl_m * -sin(light_ptr->spot_cutoff);
                MatrixRotateBank3(a, light_ptr->bank, r);
                MatrixRotatePitch3(r, light_ptr->pitch, a);
                MatrixRotateHeading3(a, light_ptr->heading, r);
                wcoh_i = wnl_i[0] + (r[1] * i_flip_coeff);
                wcoh_j = wnl_j[0] + (r[2] * j_flip_coeff);

                a[0] = wnl_m * sin(-light_ptr->spot_cutoff);
                a[1] = wnl_m * cos(-light_ptr->spot_cutoff);
                a[2] = wnl_m * -sin(-light_ptr->spot_cutoff);
                MatrixRotateBank3(a, light_ptr->bank, r);
                MatrixRotatePitch3(r, light_ptr->pitch, a);
                MatrixRotateHeading3(a, light_ptr->heading, r);
                wcol_i = wnl_i[0] + (r[1] * i_flip_coeff);
                wcol_j = wnl_j[0] + (r[2] * j_flip_coeff);
                break;

              case VMA_VIEW2D_TYPE_XZ:
                a[0] = 0.0;
                a[1] = wnl_m;
                a[2] = 0.0;
                MatrixRotateBank3(a, light_ptr->bank, r);
                MatrixRotatePitch3(r, light_ptr->pitch, a); 
                MatrixRotateHeading3(a, light_ptr->heading, r);
                wnl_i[1] = wnl_i[0] + (r[0] * i_flip_coeff);
                wnl_j[1] = wnl_j[0] + (r[2] * j_flip_coeff);

                a[0] = wnl_m * sin(light_ptr->spot_cutoff);
                a[1] = wnl_m * cos(light_ptr->spot_cutoff);
                a[2] = wnl_m * -sin(light_ptr->spot_cutoff);
                MatrixRotateBank3(a, light_ptr->bank, r);
                MatrixRotatePitch3(r, light_ptr->pitch, a);
                MatrixRotateHeading3(a, light_ptr->heading, r);
                wcoh_i = wnl_i[0] + (r[0] * i_flip_coeff);
                wcoh_j = wnl_j[0] + (r[2] * j_flip_coeff);

                a[0] = wnl_m * sin(-light_ptr->spot_cutoff);
                a[1] = wnl_m * cos(-light_ptr->spot_cutoff);
                a[2] = wnl_m * -sin(-light_ptr->spot_cutoff);
                MatrixRotateBank3(a, light_ptr->bank, r);
                MatrixRotatePitch3(r, light_ptr->pitch, a); 
                MatrixRotateHeading3(a, light_ptr->heading, r);
                wcol_i = wnl_i[0] + (r[0] * i_flip_coeff);
                wcol_j = wnl_j[0] + (r[2] * j_flip_coeff);
                break;
          }

          /* Draw lines. */
          glBegin(GL_LINES);
          {
            /* Normal line. */
            glVertex2d(wnl_i[0], wnl_j[0]);
                glVertex2d(wnl_i[1], wnl_j[1]);

            /* Cutoff bounds lines. */
                glVertex2d(wnl_i[0], wnl_j[0]);
                glVertex2d(wcol_i, wcol_j);

                glVertex2d(wnl_i[0], wnl_j[0]);
                glVertex2d(wcoh_i, wcoh_j);
          }
          glEnd();

          glDisable(GL_ALPHA_TEST);
          glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
          glEnable(GL_BLEND);

            if(c == NULL)
                glColor4d(1.0, 1.0, 1.0, 0.5);
            else
                glColor4d(c->r, c->g, c->b, c->a * 0.5);

          glBegin(GL_TRIANGLES);
          {
                glVertex2d(wnl_i[0], wnl_j[0]);
                glVertex2d(wcol_i, wcol_j);
                glVertex2d(wcoh_i, wcoh_j);
          }
          glEnd();

          glDisable(GL_BLEND);
        }

      return;
}


/*
 *    Draws the `disabled background' on the given 2d view.
 */
static void View2DDrawDisabled(vma_view2d_struct *v, gint ww, gint wh)
{
      GLsizei width = 4, height = 4;
      const GLubyte pixels[4 * 4 * 4];
      u_int32_t *ptr32;


      if(v == NULL)
          return;

      ptr32 = (u_int32_t *)pixels;

      ptr32[(0 * width) + 0] =
          ptr32[(1 * width) + 0] =
          ptr32[(2 * width) + 0] = 0xff0000ff;
        ptr32[(0 * width) + 1] =  
            ptr32[(1 * width) + 1] =
            ptr32[(2 * width) + 1] = 0xff00ff00;
        ptr32[(0 * width) + 2] =  
            ptr32[(1 * width) + 2] =
            ptr32[(2 * width) + 2] = 0xffff0000;
        ptr32[(0 * width) + 3] =  
            ptr32[(1 * width) + 3] =
            ptr32[(2 * width) + 3] = 0xff00ffff;

        ptr32[(3 * width) + 0] =  
            ptr32[(3 * width) + 1] = 0xffffffff;
        ptr32[(3 * width) + 2] =
            ptr32[(3 * width) + 3] = 0xff000000;

      glRasterPos2i(0, wh - 1);
      glPixelZoom(
          (GLfloat)ww / (GLfloat)width,
          -(GLfloat)wh / (GLfloat)height
      );
      glDrawPixels(
          width, height,
          GL_RGBA,
          GL_UNSIGNED_BYTE,
          pixels
      );

      return;
}

/*
 *      Draws the `disabled background' on the given 2d view.
 */
static void View3DDrawDisabled(vma_view3d_struct *v, gint ww, gint wh)
{
        GLsizei width = 4, height = 4;
        const GLubyte pixels[4 * 4 * 4];
        u_int32_t *ptr32;


        if(v == NULL)
            return;

        ptr32 = (u_int32_t *)pixels;

        ptr32[(0 * width) + 0] =
            ptr32[(1 * width) + 0] =
            ptr32[(2 * width) + 0] = 0xff0000ff;
        ptr32[(0 * width) + 1] =
            ptr32[(1 * width) + 1] =
            ptr32[(2 * width) + 1] = 0xff00ff00;
        ptr32[(0 * width) + 2] =
            ptr32[(1 * width) + 2] =
            ptr32[(2 * width) + 2] = 0xffff0000;
        ptr32[(0 * width) + 3] =
            ptr32[(1 * width) + 3] =
            ptr32[(2 * width) + 3] = 0xff00ffff;

        ptr32[(3 * width) + 0] =
            ptr32[(3 * width) + 1] = 0xffffffff;
        ptr32[(3 * width) + 2] =
            ptr32[(3 * width) + 3] = 0xff000000;

        glRasterPos2i(0, wh - 1);
        glPixelZoom(
            (GLfloat)ww / (GLfloat)width,
            -(GLfloat)wh / (GLfloat)height
        );
        glDrawPixels(
            width, height,
            GL_RGBA,
            GL_UNSIGNED_BYTE,
            pixels
        );

        return;
}


/*
 *    Sets up the camera for the 3d view using gluLookAt().
 *
 *    Inputs assumed valid.
 */
static void View3DSetCameraPosition(vma_view3d_struct *v)
{
      double cx, cy, cz;
      double ux, uy, uz;
      double cos_p;


      cos_p = cos(v->cam_p);
      cx = sin(v->cam_h) * cos_p;
        cy = cos(v->cam_h) * cos_p;
      cz = -sin(v->cam_p);
/*
 i  j  k
 cx cy cz
 cy -cx 0

 i(0 - (cz * -cx)) - j(0 - (cz * cy)) + k((cx * -cx) - (cy * cy))
 */
/*
      ux = -(cz * -cx);
      uy = (cz * cy);
      uz = ((cx * -cx) - (cy * cy));
 */
      ux = 0;
      uy = 0;
      uz = 1;

      gluLookAt(
          (GLdouble)v->cam_x,
          (GLdouble)v->cam_z,
          (GLdouble)-v->cam_y,
          (GLdouble)(cx + v->cam_x),
          (GLdouble)(cz + v->cam_z),
          (GLdouble)-(cy + v->cam_y),
          (GLdouble)ux,
          (GLdouble)uz,
          (GLdouble)-uy
      );


      return;
}

/*
 *    Redraws the 2d view.
 *
 *    The given viewport size vp_width and vp_height can be
 *    both 0 to indicate to use the current viewport size.
 *
 *    Buffers will only be swapped if swap_buffers is TRUE.
 */
void View2DDraw(
      vma_view2d_struct *v, vma_view_palette_struct *palette,
        gint vp_width, gint vp_height,
        gbool swap_buffers
)
{
      GtkWidget *w;
      gint ww, wh;
      vma_color_struct *c;
      vma_view_palette_struct def_palette;


      if(v == NULL)
          return;

      w = v->view;
      if((w == NULL) ||
           (!v->view_realized)
      )
          return;

      /* Use default palette if given palette is NULL, since
       * subsequent calls need palette to be valid.
       */
      if(palette == NULL)
      {
          palette = &def_palette;
          memset(palette, 0x00, sizeof(vma_view_palette_struct));
      }

      /* Make the glarea widget as the current OpenGL rendering
       * context.
       */
      if(View2DGLEnableContext(v))
          return;

      /* Get size of view in pixels. */
        if(vp_width > 0)
            ww = vp_width;
        else
            ww = w->allocation.width;

        if(vp_height > 0)
            wh = vp_height;
        else
            wh = w->allocation.height;

      /* No visable dimension? */
      if((ww <= 0) || (wh <= 0) ||
           (v->viewable_dim <= 0.0)
      )
          return;


      /* Set up camera viewport. */
      glViewport(0, 0, ww, wh);
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();

      /* Go to 2D and make units the same as the size of the window. */
      gluOrtho2D(0, ww, 0, wh);
      glMatrixMode(GL_MODELVIEW);

        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
      glPixelStorei(GL_PACK_ALIGNMENT, 1);

      /* Update states. */
      glDisable(GL_DEPTH_TEST);
      glDisable(GL_LIGHTING);
      glDisable(GL_LIGHT0);
      glDisable(GL_TEXTURE_1D);
        glDisable(GL_TEXTURE_2D);
        glDisable(GL_TEXTURE_3D);

      /* Reset local global texture state and orientations. */
      texture_state = VMA_VIEW_TEXTURE_STATE_OFF;
        texture_orient_i0 = 0.0;
        texture_orient_j0 = 0.0;
        texture_orient_id = 0.0;
        texture_orient_jd = 0.0;


      /* Draw disabled, clear buffer, or redraw background image. */
      if(v->flags & VMA_VIEW_FLAG_ENABLED)
      {
          c = palette->background;
          if(c != NULL)
            glClearColor(
                (GLclampf)c->r,
                    (GLclampf)c->g,
                    (GLclampf)c->b,
                    (GLclampf)c->a
            );
          else
            glClearColor(0.0, 0.0, 0.0, 0.0);
          glClearDepth(1.0);
          glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


          /* Draw background image if any. */
          ViewBGImageDraw(v->bg_image);

          /* Need to disable GL_TEXTURE_2D since ViewBGImageDraw()
           * turns it on.
           */
          glDisable(GL_TEXTURE_2D);
      }
        else
        {
            /* Draw disabled background and exit. */

            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            gluOrtho2D(0, ww, 0, wh);  
            glMatrixMode(GL_MODELVIEW);

            View2DDrawDisabled(v, ww, wh);
            if(swap_buffers)
                gtk_gl_area_swapbuffers(GTK_GL_AREA(w));
            return;
        }


      /* Draw grid. */
      View2DDrawGrid(v, ww, wh, palette);


      if(v->editor_ptr != NULL)
      {
          gint i;
          ma_editor_struct *editor = (ma_editor_struct *)v->editor_ptr;

            /* Draw icons representing each enabled light. */
            for(i = 0; i < VMA_LIGHTS_MAX; i++)
            {
                View2DDrawLight(
                v, ww, wh, palette,
                &(editor->light[i]), i
            );
          }
      }

      /* Begin drawing each primitives. */
      if(v->editor_ptr != NULL)
      {
          gint i, model_num;
          v3d_model_struct *model_ptr;
          ma_editor_struct *editor = (ma_editor_struct *)v->editor_ptr;

          model_num = EditorSelectedModelIndex(editor);
          model_ptr = V3DModelListGetPtr(
            editor->model, editor->total_models, model_num
          );
          if(model_ptr != NULL)
          {
            for(i = 0; i < model_ptr->total_primitives; i++)
                View2DDoDrawPrimitive(
                  v, editor, model_ptr,
                  model_ptr->primitive[i], i,   /* Primitive. */
                  ww, wh,                       /* Window size. */
                  palette
                );
          }
      }

      /* Draw cursor. */
      View2DDrawCursor(v, ww, wh, palette);

      /* Draw rectangular select if buttons are pressed and
       * drag mode is in rectangular select.
       */
      if((v->drag_state == VMA_VIEW2D_DRAG_SELECT_RECTANGLE) &&
           (v->flags & (VMA_VIEW_FLAG_BUTTON1 | VMA_VIEW_FLAG_BUTTON2))
      )
      {
          View2DDrawSelectRectangle(v, ww, wh, palette);
      }



      /* Make glarea rendered buffer active. */
      if(swap_buffers)
          gtk_gl_area_swapbuffers(GTK_GL_AREA(w));

      /* Check for GL errors. */
      if(1)
      {
            GLenum error_code = glGetError();
            if(error_code != GL_NO_ERROR)
                VMAReportGLError(NULL, (gint)error_code);
      }

      return;
}

/*
 *    Redraws the 3d view.
 *
 *      The given viewport size vp_width and vp_height can be
 *      both 0 to indicate to use the current viewport size.
 *
 *      Buffers will only be swapped if swap_buffers is TRUE.
 */
void View3DDraw(
      vma_view3d_struct *v, vma_view_palette_struct *palette,
        gint vp_width, gint vp_height,
        gbool swap_buffers
)
{
        GtkWidget *w;
        gint ww, wh;
      double field_of_view_deg = 40;
      double view_aspect;
        vma_color_struct *c;
        vma_view_palette_struct def_palette;

        
        if(v == NULL)  
            return; 
         
        w = v->view;
        if((w == NULL) ||
           (!v->view_realized)
        ) 
            return;

        /* Use default palette if given palette is NULL, since
         * subsequent calls need palette to be valid.
         */
        if(palette == NULL)
        {
            palette = &def_palette;
            memset(palette, 0x00, sizeof(vma_view_palette_struct));
        } 

        /* Make the glarea widget as the current OpenGL rendering
         * context.
         */
      if(View3DGLEnableContext(v))
            return;

        /* Get size of view in pixels. */
      if(vp_width > 0)
          ww = vp_width;
      else
          ww = w->allocation.width;

      if(vp_height > 0)
          wh = vp_height;
      else
          wh = w->allocation.height;

        /* No visable dimension? */
        if((ww <= 0) || (wh <= 0))
            return;

      view_aspect = (gdouble)ww / (gdouble)wh;
      field_of_view_deg = RADTODEG(v->cam_fov);
        if(field_of_view_deg >= 90.0)
            field_of_view_deg = 40.0;
      if(field_of_view_deg <= 0.0)
          field_of_view_deg = 40.0;

        /* Set up camera viewport. */
        glViewport(0, 0, ww, wh);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
      glPixelStorei(GL_PACK_ALIGNMENT, 1);

        /* Update states. */
        glDisable(GL_DEPTH_TEST);
        glDisable(GL_LIGHTING);
        glDisable(GL_LIGHT0);
        glDisable(GL_TEXTURE_1D);
        glDisable(GL_TEXTURE_2D);
        glDisable(GL_TEXTURE_3D);

        /* Reset local global texture state and orientations. */
        texture_state = VMA_VIEW_TEXTURE_STATE_OFF;
        texture_orient_i0 = 0.0;
        texture_orient_j0 = 0.0;
        texture_orient_id = 0.0;
        texture_orient_jd = 0.0;

        /* Draw disabled, clear buffer, or redraw background image. */
        if(v->flags & VMA_VIEW_FLAG_ENABLED)
        {
          /* Clear background. */
            c = palette->background;
            if(c != NULL)
                glClearColor(
                    (GLclampf)c->r,
                    (GLclampf)c->g,
                    (GLclampf)c->b,
                    (GLclampf)c->a
                );
            else
                glClearColor(0.0, 0.0, 0.0, 0.0);
            glClear(GL_COLOR_BUFFER_BIT);

          /* Have background image to draw? */
          if(v->bg_image != NULL)
          {
            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            gluOrtho2D(0, ww, 0, wh);
            glMatrixMode(GL_MODELVIEW);

            /* Disable cull face for background image drawing. */
            glDisable(GL_CULL_FACE);

            /* Draw background image if any. */
            ViewBGImageDraw(v->bg_image);

            /* Need to disable GL_TEXTURE_2D since ViewBGImageDraw()
             * turns it on.
             */
            glDisable(GL_TEXTURE_2D);
          }

          /* Clear depth (after drawing background image if any). */
          glClearDepth(1.0);
          glClear(GL_DEPTH_BUFFER_BIT);
        }
      else
      {
          /* Draw disabled background and exit. */

            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            gluOrtho2D(0, ww, 0, wh);
            glMatrixMode(GL_MODELVIEW);

          View3DDrawDisabled(v, ww, wh);
            if(swap_buffers)
                gtk_gl_area_swapbuffers(GTK_GL_AREA(w));
          return;
      }

      /* Update cull faces state and direction. */
      glFrontFace((v->cull_direction) ? GL_CCW : GL_CW);
        if(v->cull_state)
            glEnable(GL_CULL_FACE); 
        else
            glDisable(GL_CULL_FACE);

      /* Update alpha channel. */
        if(v->enable_alpha_channel)
        {
            glEnable(GL_ALPHA_TEST);
            glAlphaFunc(GL_GREATER, 0.5);
        }
        else
        {
            glDisable(GL_ALPHA_TEST);
        }

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(
            (GLfloat)field_of_view_deg, /* Field of view in degrees. */
            (GLfloat)view_aspect,       /* Aspect. */
            MAX(v->cam_clip_near, 0.000001),                    /* Clip near. */
            MAX(v->cam_clip_far, v->cam_clip_near + 1.00)       /* Clip far. */
        );
        glMatrixMode(GL_MODELVIEW);

        /* Set up 3d camera position. */
        View3DSetCameraPosition(v);


/* Enable some states. */

/* Enable depth testing. */
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);

/* Track glColor*() calls to affect ambient and diffuse material. */
/* Skip this, we're using glMaterial4f() through out drawing 3d views.
glColorMaterial(
 (v->cull_state) ? GL_FRONT : GL_FRONT_AND_BACK,
 GL_AMBIENT_AND_DIFFUSE
);
glEnable(GL_COLOR_MATERIAL);
*/
glDisable(GL_COLOR_MATERIAL);


/* No dithering. */
glDisable(GL_DITHER);


      /* Draw grid. */
      View3DDrawGrid(v, palette);

      /* Enable lighting if editor is valid and rendering state is
       * enabled.
       */
        if((v->editor_ptr != NULL) && v->render_state)
        {
          gint i, gl_light_num;
          GLenum face;
          GLfloat value[4];
          gbool need_enable_lighting = TRUE;
          vma_light_struct *light_ptr;
          ma_editor_struct *editor = (ma_editor_struct *)v->editor_ptr;


            /* Set initial normal and material colors. */
            glNormal3d(0.0, 1.0, 0.0);
          face = GL_FRONT_AND_BACK;
          value[0] = 0.2;
            value[1] = 0.2;
            value[2] = 0.2;
            value[3] = 1.0;
          glMaterialfv(face, GL_AMBIENT, value);
            value[0] = 0.8;
            value[1] = 0.8;
            value[2] = 0.8;
            value[3] = 1.0;
            glMaterialfv(face, GL_DIFFUSE, value);
            value[0] = 0.0;
            value[1] = 0.0;
            value[2] = 0.0;
            value[3] = 1.0;
            glMaterialfv(face, GL_SPECULAR, value);
            value[0] = 0.0 * 128.0;
            glMaterialfv(face, GL_SHININESS, value);
            value[0] = 0.0;
            value[1] = 0.0;
            value[2] = 0.0;
            value[3] = 1.0;
            glMaterialfv(face, GL_EMISSION, value);


          /* Adjust light globals (even though GL_LIGHTING is not
           * definatly going to be enabled).
           */
            value[0] = 0.0;
            value[1] = 0.0;
            value[2] = 0.0;
            value[3] = 1.0;
          glLightModelfv(GL_LIGHT_MODEL_AMBIENT, value);
/* Uncomment for more realistic specular lighting. */
/*        glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); */
          glLightModeli(
            GL_LIGHT_MODEL_TWO_SIDE,
            (v->cull_state) ? GL_FALSE : GL_TRUE
          );
          glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);


          /* Update each light's GL state, note that GL_LIGHTING is
           * disabled at the beginning of this call but will be turned
           * on when the first light (if any) is enabled.
           */
          for(i = 0; i < VMA_LIGHTS_MAX; i++)
          {
            light_ptr = &(editor->light[i]);
            gl_light_num = GL_LIGHT0 + i;

            if(light_ptr->flags & VMA_LIGHT_FLAG_ENABLED)
            {
                if(need_enable_lighting)
                  glEnable(GL_LIGHTING);
                glEnable(gl_light_num);

                value[0] = light_ptr->ambient.r;
                    value[1] = light_ptr->ambient.g;
                    value[2] = light_ptr->ambient.b;
                    value[3] = light_ptr->ambient.a;
                glLightfv(gl_light_num, GL_AMBIENT, value);

                    value[0] = light_ptr->diffuse.r;
                    value[1] = light_ptr->diffuse.g;
                    value[2] = light_ptr->diffuse.b;
                    value[3] = light_ptr->diffuse.a;
                    glLightfv(gl_light_num, GL_DIFFUSE, value);

                    value[0] = light_ptr->specular.r;
                    value[1] = light_ptr->specular.g;
                    value[2] = light_ptr->specular.b;
                    value[3] = light_ptr->specular.a;
                    glLightfv(gl_light_num, GL_SPECULAR, value);

                    value[0] = light_ptr->x;
                    value[1] = light_ptr->z;
                    value[2] = -light_ptr->y;
                    value[3] = 0.0;
                    glLightfv(gl_light_num, GL_POSITION, value);

                    value[0] = sin(light_ptr->heading);
                    value[1] = -sin(light_ptr->pitch);
                    value[2] = -cos(light_ptr->heading);
                    value[3] = 0.0;
                    glLightfv(gl_light_num, GL_SPOT_DIRECTION, value);

                    value[0] = light_ptr->spot_exponent;
                    glLightfv(gl_light_num, GL_SPOT_EXPONENT, value);

                if(light_ptr->spot_cutoff > (0.5 * PI))
                  value[0] = 180.0;
                else
                        value[0] = RADTODEG(light_ptr->spot_cutoff);
                    glLightfv(gl_light_num, GL_SPOT_CUTOFF, value);

                    value[0] = light_ptr->attenuation_constant;
                    glLightfv(gl_light_num, GL_CONSTANT_ATTENUATION, value);
                    value[0] = light_ptr->attenuation_linear;
                    glLightfv(gl_light_num, GL_LINEAR_ATTENUATION, value);
                    value[0] = light_ptr->attenuation_quadratic;
                    glLightfv(gl_light_num, GL_QUADRATIC_ATTENUATION, value);
            }
            else
            {
                glDisable(gl_light_num);
            }
          }
      }

        /* Begin drawing primitives from each model on the editor. */
        if(v->editor_ptr != NULL)
        {
            gint i, n;
            ma_editor_struct *editor = (ma_editor_struct *)v->editor_ptr;
            v3d_model_struct *model;

          for(i = 0; i < editor->total_models; i++)
          {
            model = editor->model[i];
            if(model == NULL)
                continue;

            /* Reset view3d matrix level. */
            view3d_matrix_level = 0;

            /* Skip models that are not contain model data or
             * are marked as hidden.
             */
            if((model->type == V3D_MODEL_TYPE_STANDARD) &&
               !(model->flags & V3D_MODEL_FLAG_HIDE)
            )
            {
                    for(n = 0; n < model->total_primitives; n++)
                        View3DDoDrawPrimitive(
                            v, editor,
                      model, i,                 /* Model. */
                            model->primitive[n], n,   /* Primitive. */
                            palette
                        );
            }

            /* Pop off any excess matrixes incurred from above. */
            for(n = 0; n < view3d_matrix_level; n++)
                glPopMatrix();
            view3d_matrix_level = 0;
            }
        }
      


        /* Make glarea rendered buffer active. */
      if(swap_buffers)
          gtk_gl_area_swapbuffers(GTK_GL_AREA(w));

        /* Check for GL errors. */
        if(1)
        {
            GLenum error_code = glGetError();
            if(error_code != GL_NO_ERROR)
                VMAReportGLError(NULL, (gint)error_code);
        }

      return;
}

Generated by  Doxygen 1.6.0   Back to index