Logo Search packages:      
Sourcecode: vertex version File versions

editorundo.c

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

#include <gtk/gtk.h>

#include "../include/string.h"

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

#include "editor.h"
#include "editorselect.h"
#include "editorlist.h"
#include "editorhf.h"
#include "editorp.h"

#include "vmaundo.h"

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



static void EditorUndoOrRedoRecord(
        ma_editor_struct *editor,
        gpointer **list, gint *total, gint max,
      gpointer u
);
void EditorUndoRecord(ma_editor_struct *editor, void *u);
void EditorRedoRecord(ma_editor_struct *editor, void *u); 


static int EditorUndoOPSetNormal(
      ma_editor_struct *editor,
      vma_undo_set_normal_struct *u,
      void ***out_list, int *out_total, int out_max
);
static int EditorUndoOPSetTexCoord(
      ma_editor_struct *editor,
        vma_undo_set_texcoord_struct *u,
        void ***out_list, int *out_total, int out_max
);
static int EditorUndoOPSetVertex(
      ma_editor_struct *editor,
        vma_undo_set_vertex_struct *u,
        void ***out_list, int *out_total, int out_max
);
static int EditorUndoOPSetTexOrient(
        ma_editor_struct *editor,
        vma_undo_set_texorient_struct *u,
        void ***out_list, int *out_total, int out_max
);
static int EditorUndoOPSetHeightField(
        ma_editor_struct *editor,
        vma_undo_set_heightfield_struct *u,
        void ***out_list, int *out_total, int out_max
);
static int EditorUndoOPFlipWinding(
        ma_editor_struct *editor,
        vma_undo_flip_winding_struct *u,
        void ***out_list, int *out_total, int out_max
);
static int EditorUndoOPCreatePrimitive(
      ma_editor_struct *editor,
      vma_undo_create_primitive_struct *u,
      void ***out_list, int *out_total, int out_max
);
static int EditorUndoOPDeletePrimitive(
        ma_editor_struct *editor,
        vma_undo_delete_primitive_struct *u,
        void ***out_list, int *out_total, int out_max
);
static int EditorUndoOPTranslatePrimitive(
        ma_editor_struct *editor,
        vma_undo_translate_primitive_struct *u,
        void ***out_list, int *out_total, int out_max
);
static int EditorUndoOPAddVertex( 
        ma_editor_struct *editor,
        vma_undo_add_vertex_struct *u,
        void ***out_list, int *out_total, int out_max
);
static int EditorUndoOPRemoveVertex(
        ma_editor_struct *editor,
        vma_undo_remove_vertex_struct *u,
        void ***out_list, int *out_total, int out_max
);


static gint EditorUndoOrRedoProcess(
      ma_editor_struct *editor,
      gpointer **in_list, gint *in_total, gint in_max,
      gpointer **out_list, gint *out_total, gint out_max
);

int EditorUndoProcess(ma_editor_struct *editor);
int EditorRedoProcess(ma_editor_struct *editor);


/*
 *    Adds the given undo or redo structure u to the given list.
 *
 *      The given pointer to the undo structure will be taken by this
 *      function and set to the list on the editor, therefore the 
 *      given structure u should not be referanced again after this
 *      call.
 */
static void EditorUndoOrRedoRecord(
        ma_editor_struct *editor,
      gpointer **list, gint *total, gint max,
      gpointer u              /* Undo/redo structure. */
)
{
      gint i, n;


      if((editor == NULL) ||
           (list == NULL) ||
           (total == NULL) ||
           (u == NULL) ||
         (max <= 0)
      )
      {
          VMAUndoDelete(u);
            return;
        }

      /* Sanitize total. */
      if((*total) < 0)
          (*total) = 0;

      /* Total number of structures reached or exceeded? */
      if((*total) >= max)
      {
          /* Deallocate excess structures and reallocated number
           * of structures in list to match total.
           */
            int m = (*total) - max + 1;

          /* Deallocate old structures. */
          for(i = 0; i < m; i++)
          {
            VMAUndoDelete((*list)[i]);
            (*list)[i] = NULL;
          }

          /* Shift pointers. */
          for(i = 0; i < ((*total) - m); i++)
            (*list)[i] = (*list)[i + m];

          /* Update total. */
          (*total) = max;
          n = max - 1;
      }
      else
      {
          n = (*total);
          (*total) = (*total) + 1;
      }

      /* Reallocate pointers. */
      (*list) = (void **)realloc(
          *list,
          (*total) * sizeof(void *)
      );
      if((*list) == NULL)
      {
          (*total) = 0;
          VMAUndoDelete(u);
          return;
      }

      /* Variable n is already set to represent new structure index. */
      (*list)[n] = u;


      return;
}

/*
 *    Adds the given undo structure to the editor.
 *
 *    The given pointer to the undo structure will be taken by this
 *    function and set to the list on the editor, therefore the
 *    given structure u should not be referanced again after this
 *    call.
 */
void EditorUndoRecord(
      ma_editor_struct *editor,
      void *u                       /* Undo structure. */
)
{
      if(editor == NULL)
      {
          VMAUndoDelete(u);
          return;
      }

      EditorUndoOrRedoRecord(
          editor,
          &editor->undo, &editor->total_undos, editor->max_undos,
          u
      );

      return;
}

/*
 *    Adds the given redo structure to the editor.
 *
 *      The given pointer to the undo structure will be taken by this
 *      function and set to the list on the editor, therefore the
 *      given structure u should not be referanced again after this
 *      call.
 */
void EditorRedoRecord(
        ma_editor_struct *editor,
        void *u                         /* Redo structure. */
)
{
        if(editor == NULL)
        {   
            VMAUndoDelete(u);
            return;
        }

        EditorUndoOrRedoRecord(
            editor,
            &editor->redo, &editor->total_redos, editor->max_redos,
            u
        );

        return;
}


/* For: EditorUndoOPSetNormal(), EditorUndoOPSetTexCoord(),
 * EditorUndoOPSetHeightField(), EditorUndoOPSetVertex(),
 * EditorUndoOPFlipWinding(), EditorUndoOPTranslatePrimitive(), and
 * EditorUndoOPAddVertex(), and EditorUndoOPRemoveVertex().
 *
 * Macro to check if the editor has selected the model, primitive, and
 * is currently displaying the primitive's values in the values list
 * of the primitive being updated.
 *
 * If so it then reupdates the values list and reselects whatever value
 * item the editor has last selected.
 *
 * Uses variables; editor, v, i, u, p, w
 */
#define DO_UPDATE_EDITOR_VALUES_LIST      \
{ \
        if((editor->total_selected_primitives == 1) && \
           (EditorSelectedModelIndex(editor) == u->model_num) \
        ) \
        { \
            i = editor->selected_primitive[0]; \
            if(i == u->primitive_num) \
            { \
                /* Record previously selected value. */ \
                i = EditorGetSelected( \
                editor->selected_value, editor->total_selected_values, \
                0 \
            ); \
 \
                /* Refetch values for current primitive. */ \
                EditorListDeleteValuesG(editor); \
                EditorListAddValuesRG(editor, p); \
 \
                w = editor->values_list; \
                if(w != NULL) \
                    gtk_clist_select_row( \
                        GTK_CLIST(w), \
                        i, 0 \
                    ); \
            } \
        } \
}

/*
 *    Processes the undo set normal operation and transfers
 *    (or deallocates) the u structure to the out list.
 *
 *    Inputs assumed valid, editor lists will be updated as
 *    needed. Calling function will decide to whether to update
 *      editor menus and redraw all views or not.
 */
static int EditorUndoOPSetNormal(
      ma_editor_struct *editor,
      vma_undo_set_normal_struct *u,
      void ***out_list, int *out_total, int out_max
)
{
      gint i;
      GtkWidget *w;
      gpointer p;
      v3d_model_struct *model;
      mp_vertex_struct *n, n_old;


      model = V3DModelListGetPtr(
          editor->model, editor->total_models,
          u->model_num
      );
      if(model == NULL)
        {   
            VMAUndoDelete(u);
            return(-1);
        }

      p = V3DMPListGetPtr(
          model->primitive, model->total_primitives,
          u->primitive_num
      );
      n = V3DMPGetNormal(p, u->vertex_num);
      if(n == NULL)
        {   
            VMAUndoDelete(u);
            return(-1);
        }

      memcpy(&n_old, n, sizeof(mp_vertex_struct));
      memcpy(n, &u->n, sizeof(mp_vertex_struct));
      memcpy(&u->n, &n_old, sizeof(mp_vertex_struct));

      DO_UPDATE_EDITOR_VALUES_LIST

      /* Record u structure to out list. */
      EditorUndoOrRedoRecord(
          editor,
          out_list, out_total, out_max,
          u
      );

        /* Note: Calling function will decide to whether to
       * update editor menus and redraw all views or not.
       */

      return(0);
}

/*
 *      Processes the undo set texcoord operation and transfers
 *      (or deallocates) the u structure to the out list.
 *
 *      Inputs assumed valid, editor lists will be updated as
 *      needed. Calling function will decide to whether to update
 *      editor menus and redraw all views or not.
 */
static int EditorUndoOPSetTexCoord(
        ma_editor_struct *editor,
        vma_undo_set_texcoord_struct *u,
        void ***out_list, int *out_total, int out_max
)
{
      gint i;
        GtkWidget *w;
        gpointer p;
        v3d_model_struct *model;
        mp_vertex_struct *tc, tc_old;


        model = V3DModelListGetPtr(
            editor->model, editor->total_models,
            u->model_num
        );
        if(model == NULL)
        {   
            VMAUndoDelete(u);
            return(-1);
        }

        p = V3DMPListGetPtr(
            model->primitive, model->total_primitives,
            u->primitive_num
        );
        tc = V3DMPGetTexCoord(p, u->vertex_num);
        if(tc == NULL)
        {   
            VMAUndoDelete(u);
            return(-1);
        }

        memcpy(&tc_old, tc, sizeof(mp_vertex_struct));
        memcpy(tc, &u->tc, sizeof(mp_vertex_struct));
        memcpy(&u->tc, &tc_old, sizeof(mp_vertex_struct));
 
        DO_UPDATE_EDITOR_VALUES_LIST

        EditorUndoOrRedoRecord(
            editor,
            out_list, out_total, out_max,
            u
        );   

      return(0);
}

/*
 *      Processes the undo set vertex operation and transfers
 *      (or deallocates) the u structure to the out list.
 *
 *      Inputs assumed valid, editor lists will be updated as
 *      needed. Calling function will decide to whether to update
 *      editor menus and redraw all views or not.
 */
static int EditorUndoOPSetVertex(
        ma_editor_struct *editor,
        vma_undo_set_vertex_struct *u,
        void ***out_list, int *out_total, int out_max
)
{           
        gint i;
        GtkWidget *w; 
        gpointer p;
        v3d_model_struct *model;
        mp_vertex_struct *v, v_old;


        model = V3DModelListGetPtr(
            editor->model, editor->total_models,
            u->model_num
        );
        if(model == NULL)
        {   
            VMAUndoDelete(u);
            return(-1);
        }

        p = V3DMPListGetPtr(
            model->primitive, model->total_primitives,
            u->primitive_num
        );
        v = V3DMPGetVertex(p, u->vertex_num);
        if(v == NULL)
        {
            VMAUndoDelete(u);
            return(-1);
        }

        memcpy(&v_old, v, sizeof(mp_vertex_struct));
        memcpy(v, &u->v, sizeof(mp_vertex_struct));
        memcpy(&u->v, &v_old, sizeof(mp_vertex_struct));

        DO_UPDATE_EDITOR_VALUES_LIST
            
        EditorUndoOrRedoRecord(
            editor,
            out_list, out_total, out_max,
            u
        );

        return(0);
}

/*
 *      Processes the set texture orient (translate and/or resize)
 *    operation and transfers (or deallocates) the u structure to
 *    the out list.
 *
 *      Inputs assumed valid, editor lists will be updated as
 *      needed. Calling function will decide to whether to update
 *      editor menus and redraw all views or not.
 */
static int EditorUndoOPSetTexOrient(  
        ma_editor_struct *editor,
        vma_undo_set_texorient_struct *u,
        void ***out_list, int *out_total, int out_max
)
{
      gint i;
        GtkWidget *w;
        gpointer p;
        v3d_model_struct *model;
        mp_texture_orient_xy_struct *orient_xy;
      mp_texture_orient_yz_struct *orient_yz;
      mp_texture_orient_xz_struct *orient_xz;
      vma_undo_set_texorient_struct u_tmp;


        model = V3DModelListGetPtr(
            editor->model, editor->total_models,
            u->model_num
        );
        if(model == NULL)
        {   
            VMAUndoDelete(u);
            return(-1);
        }

        p = V3DMPListGetPtr(
            model->primitive, model->total_primitives,
            u->primitive_num
        );
      if(p == NULL)
        {   
            VMAUndoDelete(u);
            return(-1);
        }

      switch(*(int *)p)
      {
        case V3DMP_TYPE_TEXTURE_ORIENT_XY:
          orient_xy = p;

          u_tmp.i = orient_xy->x;
          u_tmp.j = orient_xy->y;
            u_tmp.di = orient_xy->dx;
            u_tmp.dj = orient_xy->dy;

          orient_xy->x = u->i;
            orient_xy->y = u->j;
            orient_xy->dx = u->di;
            orient_xy->dy = u->dj;

          u->i = u_tmp.i;
            u->j = u_tmp.j;
            u->di = u_tmp.di;
            u->dj = u_tmp.dj;

          break;

          case V3DMP_TYPE_TEXTURE_ORIENT_YZ:
            orient_yz = p;

            u_tmp.i = orient_yz->y;
            u_tmp.j = orient_yz->z;
            u_tmp.di = orient_yz->dy;
            u_tmp.dj = orient_yz->dz;

            orient_yz->y = u->i;
            orient_yz->z = u->j;
            orient_yz->dy = u->di;
            orient_yz->dz = u->dj;

            u->i = u_tmp.i;
            u->j = u_tmp.j;
            u->di = u_tmp.di;
            u->dj = u_tmp.dj;
 
            break;

          case V3DMP_TYPE_TEXTURE_ORIENT_XZ:
            orient_xz = p;

            u_tmp.i = orient_xz->x;
            u_tmp.j = orient_xz->z;
            u_tmp.di = orient_xz->dx;
            u_tmp.dj = orient_xz->dz;

            orient_xz->x = u->i;
            orient_xz->z = u->j;
            orient_xz->dx = u->di;
            orient_xz->dz = u->dj;

            u->i = u_tmp.i;  
            u->j = u_tmp.j;  
            u->di = u_tmp.di;
            u->dj = u_tmp.dj;

            break;



        default:
          VMAUndoDelete(u);
          return(-1);
          break;
      }

        DO_UPDATE_EDITOR_VALUES_LIST

        EditorUndoOrRedoRecord(
            editor,
            out_list, out_total, out_max,
            u
        );  

        return(0);
}

/*
 *      Processes the set heightfield value operation and transfers
 *    (or deallocates) the u structure to the out list.
 *
 *      Inputs assumed valid, editor lists will be updated as
 *      needed. Calling function will decide to whether to update
 *      editor menus and redraw all views or not.
 */
static int EditorUndoOPSetHeightField(
        ma_editor_struct *editor,
        vma_undo_set_heightfield_struct *u,
        void ***out_list, int *out_total, int out_max
)
{
        gint i;
        GtkWidget *w;
        gpointer p;
        v3d_model_struct *model;
      mp_heightfield_load_struct *mp_heightfield_load;

      gdouble x_length, y_length, z_length;
      gdouble x, y, z;
      gdouble heading, pitch, bank;


        model = V3DModelListGetPtr(
            editor->model, editor->total_models,
            u->model_num
        );
        if(model == NULL)
        {
            VMAUndoDelete(u);
            return(-1);
        }

        p = V3DMPListGetPtr(
            model->primitive, model->total_primitives,
            u->primitive_num
        );

      switch(*(int *)p)
      {
        case V3DMP_TYPE_HEIGHTFIELD_LOAD:
          mp_heightfield_load = p;

          x_length = mp_heightfield_load->x_length;
            y_length = mp_heightfield_load->y_length;
            z_length = mp_heightfield_load->z_length;
            x = mp_heightfield_load->x;
            y = mp_heightfield_load->y;
            z = mp_heightfield_load->z;
            heading = mp_heightfield_load->heading;
            pitch = mp_heightfield_load->pitch;
            bank = mp_heightfield_load->bank;

          mp_heightfield_load->x_length = u->x_length;
            mp_heightfield_load->y_length = u->y_length;
            mp_heightfield_load->z_length = u->z_length;
            mp_heightfield_load->x = u->x;
            mp_heightfield_load->y = u->y;
            mp_heightfield_load->z = u->z;
            mp_heightfield_load->heading = u->heading;
            mp_heightfield_load->pitch = u->pitch;
            mp_heightfield_load->bank = u->bank;

          u->x_length = x_length;
            u->y_length = y_length;
            u->z_length = z_length;
            u->x = x;
            u->y = y;
            u->z = z;
            u->heading = heading;
            u->pitch = pitch;
            u->bank = bank;

          /* Rerealize heightfield. */
          EditorHFPrimitiveRealize(editor, mp_heightfield_load, TRUE);
          break;

          default:
            VMAUndoDelete(u);
            return(-1);
            break;
        }

        DO_UPDATE_EDITOR_VALUES_LIST

        EditorUndoOrRedoRecord(  
            editor,
            out_list, out_total, out_max,
            u
        );

        return(0);
}

/*
 *      Processes the undo flip winding operation and transfers
 *      (or deallocates) the u structure to the out list.
 *
 *      Inputs assumed valid, editor lists will be updated as
 *      needed. Calling function will decide to whether to update
 *      editor menus and redraw all views or not.
 */
static int EditorUndoOPFlipWinding(
        ma_editor_struct *editor,
        vma_undo_flip_winding_struct *u,
        void ***out_list, int *out_total, int out_max
)
{
      gint i;
      GtkWidget *w;
      gpointer p;
      v3d_model_struct *model;


      model = V3DModelListGetPtr(
            editor->model, editor->total_models,
            u->model_num
        );
        if(model == NULL)
        {
            VMAUndoDelete(u);
            return(-1);
        }

        p = V3DMPListGetPtr(
            model->primitive, model->total_primitives,
            u->primitive_num
        );
      if(p == NULL)
        {
            VMAUndoDelete(u);
            return(-1);
        }

      V3DMPFlipWinding(p, TRUE, TRUE);
        
        DO_UPDATE_EDITOR_VALUES_LIST
            
        EditorUndoOrRedoRecord(
            editor,
            out_list, out_total, out_max,
            u
        );

        return(0);
}

/*
 *      Processes the undo create primitive (which was for a delete
 *    primitive) operation and deallocates the u structure. A delete
 *    primitive operation structure will be created and passed to
 *    the out list.
 *
 *      Inputs assumed valid, editor lists will be updated as
 *      needed. Calling function will decide to whether to update
 *      editor menus and redraw all views or not.
 */
static int EditorUndoOPCreatePrimitive(
        ma_editor_struct *editor,
        vma_undo_create_primitive_struct *u,
        void ***out_list, int *out_total, int out_max
)
{
        v3d_model_struct *model;
      vma_undo_delete_primitive_struct *ud;


        model = V3DModelListGetPtr(
            editor->model, editor->total_models,
            u->model_num
        );
        if(model == NULL)
      {
          VMAUndoDelete(u);
            return(-1);
      }

      /* Model type must be V3D_MODEL_TYPE_STANDARD. */
      if(model->type != V3D_MODEL_TYPE_STANDARD)
      {
            VMAUndoDelete(u);
            return(-1);
      }

      /* Create primitive on model if possable. */
      EditorPrimitiveDoCreate(
          editor, u->model_num,
          u->insert_at,
          0,            /* Insert at. */
          1,            /* Select it. */
          u->p,   /* Primitive structure. */
          FALSE   /* No record undo. */
      );

      /* Passing primitive structure to EditorPrimitiveDoCreate()
       * would have deallocated or transfered it, so do not
       * referance it again.
       */
      u->p = NULL;

      /* No need to update values list, EditorPrimitiveDoCreate()
       * would have already updated it.
       */

      /* Create undo delete structure and pass to out list. */
      ud = (vma_undo_delete_primitive_struct *)VMAUndoNew(
          VMA_UNDO_TYPE_DELETE_PRIMITIVE, u->name
      );
      if(ud != NULL)
      {
          ud->repeats = u->repeats;
          ud->editor = u->editor;
          ud->model_num = u->model_num;
          ud->delete_at = u->insert_at;
            EditorUndoOrRedoRecord(
                editor,
                out_list, out_total, out_max,
                ud
            );
      }

        /* Deallocate undo create structure. */
        VMAUndoDelete(u);
        u = NULL;

      return(0);
}

/*
 *      Processes the undo delete primitive (which was for a create
 *      primitive) operation and deallocates the u structure. A create
 *      primitive operation structure will be created and passed to
 *      the out list.
 *
 *      Inputs assumed valid, editor lists will be updated as
 *      needed. Calling function will decide to whether to update
 *      editor menus and redraw all views or not.
 */
static int EditorUndoOPDeletePrimitive(
        ma_editor_struct *editor,
        vma_undo_delete_primitive_struct *u,
        void ***out_list, int *out_total, int out_max
)
{
      gint pn;
        gpointer p;
        v3d_model_struct *model;
      vma_undo_create_primitive_struct *uc;


        model = V3DModelListGetPtr(
            editor->model, editor->total_models,
            u->model_num
        );
        if(model == NULL)
        {
            VMAUndoDelete(u);
            return(-1);
        }

      /* First back up the actual primitive on the editor to
       * the out list.
       */
      pn = u->delete_at;
      p = V3DMPListGetPtr(
            model->primitive, model->total_primitives, pn
        );
        if(p == NULL)
        {
            VMAUndoDelete(u);
            return(-1);
        }

      /* Create undo create primitive structure. */
      uc = (vma_undo_create_primitive_struct *)VMAUndoNew(
          VMA_UNDO_TYPE_CREATE_PRIMITIVE, u->name
      );
        if(uc != NULL)
        {
          uc->repeats = u->repeats;
            uc->editor = u->editor;
            uc->model_num = u->model_num;
            uc->insert_at = pn;
          uc->p = p;          /* Transfer primitive to undo structure. */
          /* Set primitive list pointer NULl, since we transfered
           * the primitive to the undo structure.
           */
          model->primitive[pn] = NULL;

            EditorUndoOrRedoRecord(
                editor,
                out_list, out_total, out_max,
                uc
            );
        }

      /* Call editor delete primitive function, don't worry if
       * model->primitive[pn] is NULL or not, it'll reallocate
       * the list and shift the entries if it is NULL or not NULL.
       */
      if(1)
      {
          int *list;
          int total = 1;

          list = (int *)malloc(total * sizeof(int));
          if(list != NULL)
          {
            list[0] = pn;
            EditorPrimitiveDoDelete(
                editor, u->model_num,
                list, total,
                FALSE   /* No record undo. */
            );

            free(list);
            list = NULL;
            total = 0;
            p = NULL;
            pn = -1;
          }
          else
          {
            V3DMPDestroy(p);
            p = NULL;
            pn = -1;
          }
      }

      /* Destroy undo delete structure. */
      VMAUndoDelete(u);

      return(0);
}


/*
 *      Processes the undo translate entire primitive operation and
 *    transfers (or deallocates) the u structure to the out list.
 *
 *      Inputs assumed valid, editor lists will be updated as
 *      needed. Calling function will decide to whether to update
 *      editor menus and redraw all views or not.
 */
static int EditorUndoOPTranslatePrimitive(
      ma_editor_struct *editor,
      vma_undo_translate_primitive_struct *u,
      void ***out_list, int *out_total, int out_max
)
{
      gint i;
        GtkWidget *w;
        gpointer p;
        v3d_model_struct *model;
      mp_vertex_struct *v;


        model = V3DModelListGetPtr(
            editor->model, editor->total_models, 
            u->model_num
        );
        if(model == NULL)
        {   
            VMAUndoDelete(u);
            return(-1);
        }

        p = V3DMPListGetPtr(
            model->primitive, model->total_primitives,
            u->primitive_num
        );
        if(p == NULL)
        {   
            VMAUndoDelete(u);
            return(-1);
        }

      /* Retranslate each vertex back to original position. */
        for(i = 0; 1; i++)
        {
            v = V3DMPGetVertex(p, i);
            if(v == NULL)
                break;

          v->x -= u->dx;
            v->y -= u->dy;
            v->z -= u->dz;
      }
      /* Reverse net translations. */
      u->dx *= -1;
        u->dy *= -1;
        u->dz *= -1;


        DO_UPDATE_EDITOR_VALUES_LIST

      /* Transfer given undo structure to outlist. */            
        EditorUndoOrRedoRecord(
            editor,
            out_list, out_total, out_max,
            u
        );

      return(0);
}

/*
 *    Processes the undo add vertex (which was for a remove vertex
 *    operation and deallocates the u structure. An add vertex
 *    operation structure will be created and passed to the out list.
 *
 *      Inputs assumed valid, editor lists will be updated as
 *      needed. Calling function will decide to whether to update
 *      editor menus and redraw all views or not.
 */
static int EditorUndoOPAddVertex(
        ma_editor_struct *editor,
        vma_undo_add_vertex_struct *u,
        void ***out_list, int *out_total, int out_max
)
{
        v3d_model_struct *model_ptr;
      gpointer p;
        vma_undo_remove_vertex_struct *ur;


        model_ptr = V3DModelListGetPtr(
            editor->model, editor->total_models, u->model_num
        );
        if(model_ptr == NULL)
        {
            VMAUndoDelete(u);
            return(-1);
        } 
        /* Model type must be V3D_MODEL_TYPE_STANDARD. */
        if(model_ptr->type != V3D_MODEL_TYPE_STANDARD)
        {
            VMAUndoDelete(u);
            return(-1);
        }

      /* Get pointer to primitive. */
        p = V3DMPListGetPtr(
            model_ptr->primitive, model_ptr->total_primitives,
            u->primitive_num
        );
        if(p == NULL)
        {
            VMAUndoDelete(u);
            return(-1);
        }

        /* Add vertex to primitive if possable. */
      EditorPrimitiveVertexAdd(
          editor, u->model_num, u->primitive_num,
          u->insert_at,
          u->v, u->n, u->tc,
          FALSE
      );

      /* The pointers v and tc passed to EditorPrimitiveVertexAdd()
       * should considered NULL now.
       */
      u->v = NULL;
      u->n = NULL;
      u->tc = NULL;

        /* No need to update values list, EditorPrimitiveVertexAdd()
         * would have already updated it.
         */

        /* Create undo remove vertex structure and pass to out list. */
        ur = (vma_undo_remove_vertex_struct *)VMAUndoNew(
          VMA_UNDO_TYPE_REMOVE_VERTEX, u->name
      );
        if(ur != NULL)
        {
          ur->repeats = u->repeats;
            ur->editor = u->editor;
            ur->model_num = u->model_num;
          ur->primitive_num = u->primitive_num;
            ur->delete_at = u->insert_at;
            EditorUndoOrRedoRecord(
                editor,
                out_list, out_total, out_max,
                ur
            );
        }

        /* Deallocate undo add vertex structure. */
        VMAUndoDelete(u);

      return(0);
}

/*
 *    Processes the undo remove vertex (which was for an add vertex
 *    operation and deallocates the u structure. A remove vertex
 *    operation structure will be created and passed to the out list.
 *
 *    Inputs assumed valid, editor lists will be updated as
 *      needed. Calling function will decide to whether to update
 *      editor menus and redraw all views or not.
 */
static int EditorUndoOPRemoveVertex(
        ma_editor_struct *editor,
        vma_undo_remove_vertex_struct *u,
        void ***out_list, int *out_total, int out_max
)
{
      gint vtx_num;
      gpointer p;
      mp_vertex_struct *tc, *n, *v;
        v3d_model_struct *model_ptr;
        vma_undo_add_vertex_struct *ua;


        model_ptr = V3DModelListGetPtr(
            editor->model, editor->total_models, u->model_num
        );
        if(model_ptr == NULL)
        {
            VMAUndoDelete(u);
            return(-1);
        }

        p = V3DMPListGetPtr(
            model_ptr->primitive, model_ptr->total_primitives,
          u->primitive_num
        );
      if(p == NULL)
        {
            VMAUndoDelete(u);
            return(-1);
        }

        /* First back up the actual vertex on the primitive to the out
       * list.
       */
      vtx_num = u->delete_at;
      v = V3DMPGetVertex(p, vtx_num);
      n = V3DMPGetNormal(p, vtx_num);
      tc = V3DMPGetTexCoord(p, vtx_num);

        /* Create undo add vertex structure. */
        ua = (vma_undo_add_vertex_struct *)VMAUndoNew(
          VMA_UNDO_TYPE_ADD_VERTEX, u->name
      );
        if(ua != NULL)
        {
          ua->repeats = u->repeats;
            ua->editor = u->editor;
            ua->model_num = u->model_num;
          ua->primitive_num = u->primitive_num;
          ua->insert_at = vtx_num;

          ua->v = (mp_vertex_struct *)calloc(1, sizeof(mp_vertex_struct));
          if((ua->v != NULL) && (v != NULL))
            memcpy(ua->v, v, sizeof(mp_vertex_struct));

            ua->n = (mp_vertex_struct *)calloc(1, sizeof(mp_vertex_struct));
            if((ua->n != NULL) && (n != NULL))
                memcpy(ua->n, n, sizeof(mp_vertex_struct));

            ua->tc = (mp_vertex_struct *)calloc(1, sizeof(mp_vertex_struct));
            if((ua->tc != NULL) && (tc != NULL))
                memcpy(ua->tc, tc, sizeof(mp_vertex_struct));

            EditorUndoOrRedoRecord(
                editor,
                out_list, out_total, out_max,
                ua
            );
        } 

      /* Variables v, n, and tc should be considered invalid now. */
      v = NULL;
      n = NULL;
      tc = NULL;

      /* Remove the vertexes on the primitive. */
      EditorPrimitiveVertexRemove(
          u->editor, u->model_num, u->primitive_num,
          vtx_num,
          FALSE,        /* Record undo. */
          FALSE         /* Report errors. */
      );

        /* Destroy undo remove vertex structure. */
        VMAUndoDelete(u);

      return(0);
}


#undef DO_UPDATE_EDITOR_VALUES_LIST




/*
 *      Performs the procedure to undo or redo the highest recorded
 *      structure on the given in_list. The opposite affect
 *    will be added to the out_list.
 *
 *    The highest recorded structure on the given in_list will be
 *    deleted.
 */
static gint EditorUndoOrRedoProcess(
      ma_editor_struct *editor,
      gpointer **in_list, gint *in_total, gint in_max,
      gpointer **out_list, gint *out_total, gint out_max
)
{
      vma_undo_common_struct *u_common;
      gint i;


      if((editor == NULL) ||
           (in_list == NULL) ||
           (in_total == NULL) ||
           (in_max <= 0) ||
           (out_list == NULL) ||
           (out_total == NULL) ||
           (out_max <= 0)
      )
          return(-1);

      /* Get last pointer index in the list. */
      i = (*in_total) - 1;
      if(i < 0)
          return(0);

      u_common = VMAUndoListGetPtr(
          *in_list, *in_total, i
      );

      /* Last pointer index is null? */
      if(u_common == NULL)
      {
          /* Reduce in list pointer array size by one. */
          (*in_total) = (*in_total) - 1;
          if((*in_total) > 0)
          {
            (*in_list) = (void **)realloc(
                *in_list,
                (*in_total) * sizeof(void *)
            );
            if((*in_list) == NULL)
            {
                (*in_total) = 0;
            }
          }
          else
          {
            free(*in_list);
            (*in_list) = NULL;
            (*in_total) = 0;
          }

          return(-1);
      }

      /* Handle by last in structure type. */
      switch(u_common->type)
      {
        case VMA_UNDO_TYPE_SET_NORMAL:
          EditorUndoOPSetNormal(
            editor, (vma_undo_set_normal_struct *)u_common,
            out_list, out_total, out_max
          );
          break;

        case VMA_UNDO_TYPE_SET_TEXCOORD:
          EditorUndoOPSetTexCoord(
                editor, (vma_undo_set_texcoord_struct *)u_common,
                out_list, out_total, out_max
            );
            break;

          case VMA_UNDO_TYPE_SET_VERTEX:
            EditorUndoOPSetVertex(
                editor, (vma_undo_set_vertex_struct *)u_common,
                out_list, out_total, out_max
            );
            break;

          case VMA_UNDO_TYPE_SET_TEXORIENT:
          EditorUndoOPSetTexOrient(
                editor, (vma_undo_set_texorient_struct *)u_common,
                out_list, out_total, out_max
            );
          break;

        case VMA_UNDO_TYPE_SET_HEIGHTFIELD:
          EditorUndoOPSetHeightField(
                editor, (vma_undo_set_heightfield_struct *)u_common,
                out_list, out_total, out_max
            );
            break;


        case VMA_UNDO_TYPE_FLIP_WINDING:
            EditorUndoOPFlipWinding(
                editor, (vma_undo_flip_winding_struct *)u_common,
                out_list, out_total, out_max
            );
            break;


        case VMA_UNDO_TYPE_CREATE_PRIMITIVE:
            EditorUndoOPCreatePrimitive(
                editor, (vma_undo_create_primitive_struct *)u_common,
                out_list, out_total, out_max
            );
            break;

        case VMA_UNDO_TYPE_DELETE_PRIMITIVE:
          EditorUndoOPDeletePrimitive(
                editor, (vma_undo_delete_primitive_struct *)u_common,
                out_list, out_total, out_max
            );
            break;


        case VMA_UNDO_TYPE_TRANSLATE_PRIMITIVE:
          EditorUndoOPTranslatePrimitive(
                editor, (vma_undo_translate_primitive_struct *)u_common,
                out_list, out_total, out_max
            );
            break;


          case VMA_UNDO_TYPE_ADD_VERTEX:
            EditorUndoOPAddVertex(
                editor, (vma_undo_add_vertex_struct *)u_common,
                out_list, out_total, out_max  
            );
            break;

          case VMA_UNDO_TYPE_REMOVE_VERTEX:
            EditorUndoOPRemoveVertex(
                editor, (vma_undo_remove_vertex_struct *)u_common,
                out_list, out_total, out_max
            );
            break;


        default:
          fprintf(stderr,
 "EditorUndoOrRedoProcess(): Unsupported procedure type %i\n",
            u_common->type
          );
          VMAUndoDelete(u_common);
          break;
      }

      /* Last in list structure would have been deallocated
       * or transfered to the out list, so reduce in list pointer
         * pointer array size by one.
       */
      u_common = NULL;
        (*in_total) = (*in_total) - 1;
        if((*in_total) > 0)
        {
            (*in_list) = (void **)realloc(
                *in_list,
                (*in_total) * sizeof(void *)
            );
            if((*in_list) == NULL) 
            {
                (*in_total) = 0;
            } 
        }
        else
        {
            free(*in_list);
            (*in_list) = NULL;
            (*in_total) = 0;
        }

      return(0);
}


/*
 *    Performs the procedure to undo the highest recorded undo
 *    item and then deletes that structure.
 *
 *    Returns non-zero on error.
 */
int EditorUndoProcess(ma_editor_struct *editor)
{
      if(editor == NULL)
          return(-1);

      return(EditorUndoOrRedoProcess(
          editor,
            &editor->undo, &editor->total_undos, editor->max_undos,
            &editor->redo, &editor->total_redos, editor->max_redos
      ));
}

/*
 *      Performs the procedure to redo the highest recorded redo
 *      item and then deletes that structure.
 */
int EditorRedoProcess(ma_editor_struct *editor)
{
        if(editor == NULL)
            return(-1);

        return(EditorUndoOrRedoProcess(
            editor,
            &editor->redo, &editor->total_redos, editor->max_redos,
          &editor->undo, &editor->total_undos, editor->max_undos
        ));
}

Generated by  Doxygen 1.6.0   Back to index