Logo Search packages:      
Sourcecode: vertex version File versions

editorhf.c

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

#include <gtk/gtk.h>

#include <GL/gl.h>

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

#include "guiutils.h"
#include "cdialog.h"

#include "v3dmp.h"
#include "v3dhf.h"
#include "v3dmodel.h"
#include "editor.h"
#include "editorlist.h"
#include "editoridialog.h"
#include "editorhf.h"
#include "editorviewcb.h"

#include "vma.h"

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


void EditorHFPrimitiveRealize(
        ma_editor_struct *editor,
        mp_heightfield_load_struct *mp_heightfield_load,
        gbool rerealize
);
void EditorHFPrimitiveUnrealize(
        ma_editor_struct *editor,
        mp_heightfield_load_struct *mp_heightfield_load 
);

void EditorHFDialogMap(
        ma_editor_struct *editor,
        void *p         /* If NULL, then implies create. */
);
void EditorHFDialogBrowseCB(void *widget, void *data);
void EditorHFDialogOKCB(void *idialog, void *data);
void EditorHFDialogApplyCB(void *idialog, void *data);
void EditorHFDialogCancelCB(void *idialog, void *data);


/*
 *    (Re)loads the given V3DMP_TYPE_HEIGHTFIELD_LOAD primitive with
 *    respect to the specified editor.
 *
 *    If data is already loaded (realized) then it will only be reloaded
 *    if rerealize is TRUE.
 *
 *    The first 3D view on the editor may be placed into context by
 *    this function.
 */
void EditorHFPrimitiveRealize(
        ma_editor_struct *editor,
      mp_heightfield_load_struct *mp_heightfield_load,
      gbool rerealize
)
{
        gbool cull_direction = FALSE;     /* FALSE is clockwise. */
        int status;
      GLuint list;
      const char *cstrptr, *cstrptr2;
      char tmp_path[PATH_MAX + NAME_MAX];


        if((editor == NULL) || (mp_heightfield_load == NULL))
            return;

        /* Need to put the first 3d view into context so that the
       * gl operations done in this function are in context with that
       * view.
         */
        if(VMA_MAX_3D_VIEWS_PER_EDITOR > 0)
      {
          vma_view3d_struct *view3d = editor->view3d[0];

          if(view3d != NULL)
          {
            View3DGLEnableContext(view3d);

            /* Get cull direction from 3d view. */
            cull_direction = view3d->cull_direction;
          }
      }

      /* Check heightfield is currently not realized or if
       * we are requested to re-realize it.
       */
      if((mp_heightfield_load->gl_list == NULL) ||
           rerealize
      )
      {
          /* Unrealize as needed. */
          EditorHFPrimitiveUnrealize(
            editor, mp_heightfield_load
          );

          /* Begin realizing by reloading data. */

          /* Complete path as needed. */
          (*tmp_path) = '\0';
          cstrptr = (const char *)mp_heightfield_load->path;
          if(cstrptr != NULL)
          {
            if(ISPATHABSOLUTE(cstrptr))
            {
                strncpy(tmp_path, cstrptr, PATH_MAX + NAME_MAX);
            }
            else
            {
                const char *parent = (const char *)EditorListHeaderGetHeightFieldBaseDir(editor);
                if(parent == NULL)
                {
                  strncpy(tmp_path, cstrptr, PATH_MAX + NAME_MAX);
                }
                else
                {
                  cstrptr2 = (const char *)PrefixPaths(parent, cstrptr);
                  strncpy(
                      tmp_path,
                      (cstrptr2 == NULL) ? cstrptr : cstrptr2,
                      PATH_MAX + NAME_MAX
                  );
                }
            }
          }
          tmp_path[PATH_MAX + NAME_MAX - 1] = '\0';

          /* Create new gl list and load heightfield. */
          list = glGenLists(1);
          if(list != 0)
          {
            v3d_hf_options_struct hfopt;

            glNewList(list, GL_COMPILE);

            /* Set shading type. */
/*          glShadeModel(GL_FLAT); */

            /* Set heightfield loading options. */
            hfopt.flags = (V3D_HF_OPT_FLAG_WINDING |
                V3D_HF_OPT_FLAG_SET_NORMAL | V3D_HF_OPT_FLAG_SET_TEXCOORD
            );
            hfopt.winding = ((cull_direction) ?
                V3D_HF_WIND_CCW : V3D_HF_WIND_CW
            );
            hfopt.set_normal = V3D_HF_SET_NORMAL_STREATCHED;
            hfopt.set_texcoord = V3D_HF_SET_TEXCOORD_ALWAYS;

            /* Load heightfield. */
            status = V3DHFLoadFromFile(
                tmp_path,
                mp_heightfield_load->x_length,  /* Lengths. */
                mp_heightfield_load->y_length,
                mp_heightfield_load->z_length,
                &mp_heightfield_load->x_points, /* Points. */
                &mp_heightfield_load->y_points,
                NULL, NULL,   /* Each grid (pixel) is this many meters. */
                NULL,   /* Dynamically allocated z points
                         * can be NULL.
                         */
                (void *)list,
                &hfopt
            );

            /* Calculate total points. */
            mp_heightfield_load->total_points =
                mp_heightfield_load->x_points *
                mp_heightfield_load->y_points;

            glEndList();

            /* Record newly loaded gl list of the heightfield. */
            mp_heightfield_load->gl_list = (void *)list;
          }
      }

        return;
}

/*
 *      Unrealizes the given V3DMP_TYPE_HEIGHTFIELD_LOAD primitive with
 *      respect to the specified editor.
 *
 *      The first 3D view on the editor may be placed into context by
 *      this function.
 */
void EditorHFPrimitiveUnrealize(
        ma_editor_struct *editor,
        mp_heightfield_load_struct *mp_heightfield_load
)
{
        if((editor == NULL) || (mp_heightfield_load == NULL))
            return;

        /* Need to put the first 3D view glarea into context
         * so the heightfield gl list gets deleted for that view.
         */
        if(VMA_MAX_3D_VIEWS_PER_EDITOR > 0)
        {
            vma_view3d_struct *view3d = editor->view3d[0];

            if(view3d != NULL)
                View3DGLEnableContext(view3d);
        }

      /* Delete the GL list for the heightfield. */
      if(mp_heightfield_load->gl_list != NULL)
      {
          glDeleteLists((GLint)mp_heightfield_load->gl_list, 1);
          mp_heightfield_load->gl_list = NULL;
      }

      /* Free loaded z points. */
      if(mp_heightfield_load->data != NULL)
      {
          free(mp_heightfield_load->data);
          mp_heightfield_load->data = NULL;
      }

      return;
}


/*
 *      Set up and map heightfield dialog using the editor's
 *    input dialog.
 */
void EditorHFDialogMap(
        ma_editor_struct *editor,
        void *p         /* If NULL, then implies create. */
)
{
      GtkWidget *parent, *parent2;
      void *client_data;
      mp_heightfield_load_struct *mp_heightfield;
        ma_editor_idialog_struct *d;
      char num_str[256];
      char fmt_str[80];


        if(editor == NULL)
            return;

        d = &editor->idialog;       /* Editor's input dialog. */

      /* Get mp_heightfield pointer if possible. */
      if((p == NULL) ? 0 : ((*(int *)p) == V3DMP_TYPE_HEIGHTFIELD_LOAD))
          mp_heightfield = (mp_heightfield_load_struct *)p;
      else
          mp_heightfield = NULL;

      /* Reset input dialog. */
        EditorIDialogReset(editor, d, FALSE);

      /* Get input dialog's client vbox. */
        parent = EditorIDialogClientParent(d);
      if(parent != NULL)
      {
          void *label, *entry, *browse;

          /* Path to heightfield image. */
          parent2 = (GtkWidget *)GUIPromptBarWithBrowse(
            NULL, "Path:",
            &label, &entry, &browse,
            (void *)editor,
            EditorHFDialogBrowseCB
          );
          if((entry != NULL) && (mp_heightfield != NULL))
          {
            gtk_entry_set_text(
                (GtkEntry *)entry,
                (mp_heightfield->path == NULL) ?
                  "" : mp_heightfield->path
            );
          }
          gtk_box_pack_start(GTK_BOX(parent), parent2, FALSE, FALSE, 2);
            gtk_widget_show(parent2);
          /* Record as widget 0. */
          EditorIDialogRecordWidget(d, entry);

          /* Length along X axis. */
            parent2 = (GtkWidget *)GUIPromptBar(
                NULL, "X Axis Length:",
                NULL, &entry
            );
            if((entry != NULL) && (mp_heightfield != NULL))
            {
            double l = mp_heightfield->x_length;
                sprintf(fmt_str, "%%.%if", editor->vertex_decimals);
                sprintf(num_str, fmt_str,
                (l <= 0.0) ? 1.0 : l
            );
                gtk_entry_set_text((GtkEntry *)entry, num_str);
            }
            gtk_box_pack_start(GTK_BOX(parent), parent2, FALSE, FALSE, 2);
            gtk_widget_show(parent2);
            /* Record as widget 1. */
            EditorIDialogRecordWidget(d, entry);

            /* Length along Y axis. */
            parent2 = (GtkWidget *)GUIPromptBar(
                NULL, "Y Axis Length:",
                NULL, &entry
            );
            if((entry != NULL) && (mp_heightfield != NULL))
            {
            double l = mp_heightfield->y_length;
                sprintf(fmt_str, "%%.%if", editor->vertex_decimals);
                sprintf(num_str, fmt_str,
                    (l <= 0.0) ? 1.0 : l
                );
                gtk_entry_set_text((GtkEntry *)entry, num_str);
            }
            gtk_box_pack_start(GTK_BOX(parent), parent2, FALSE, FALSE, 2);
            gtk_widget_show(parent2);
            /* Record as widget 2. */
            EditorIDialogRecordWidget(d, entry);

            /* Length along Z axis. */
            parent2 = (GtkWidget *)GUIPromptBar(   
                NULL, "Z Axis Length:",
                NULL, &entry
            );
            if((entry != NULL) && (mp_heightfield != NULL))
            {
            double l = mp_heightfield->z_length;
                sprintf(fmt_str, "%%.%if", editor->vertex_decimals);
                sprintf(num_str, fmt_str,
                    (l <= 0.0) ? 1.0 : l
                );
                gtk_entry_set_text((GtkEntry *)entry, num_str);
            }
            gtk_box_pack_start(GTK_BOX(parent), parent2, FALSE, FALSE, 2);
            gtk_widget_show(parent2);
            /* Record as widget 3. */
            EditorIDialogRecordWidget(d, entry);
      }

      /* Use pointer to editor as client data. */
      client_data = (void *)editor;

        EditorIDialogMap(
            editor, d,
            "Heightfield Properties",
            "Set", "Apply", "Close",
            client_data,
            EditorHFDialogOKCB,
            EditorHFDialogApplyCB,
            EditorHFDialogCancelCB
        );


      return;
}

/*
 *    Browse heightfield path button callback.
 */
void EditorHFDialogBrowseCB(void *widget, void *data)
{
      gbool status;
      GtkWidget *w;
      const gchar *base_dir;
        gchar **fb_path_rtn;
        gint fb_path_total_rtns;
        fb_type_struct *fb_type_rtn;  
        static gchar tmp_path[PATH_MAX + NAME_MAX];
      ma_editor_idialog_struct *d;
        ma_editor_struct *editor = (ma_editor_struct *)data;
        if(editor == NULL)
            return;

      d = &editor->idialog;

        /* Get base directory (if available). */
      base_dir = (const char *)EditorListHeaderGetHeightFieldBaseDir(
          editor
      );

      /* Get pointer to recorded widget 0 on the input dialog which
       * should be a entry widget for the heightfield image path.
       */
      w = EditorIDialogGetWidget(d, 0);
      if(w == NULL)
          return;


      /* Get user response for heightfield image using file browser,
       * use textures directory as the last directory.
       */
      FileBrowserSetTransientFor(d->toplevel);
      status = FileBrowserGetResponse(
          "Select Heightfield Image",
          "Select", "Cancel",
          dname.fb_last_textures,         /* Last path. */
          ftype.load_texture, ftype.load_texture_total,
          &fb_path_rtn, &fb_path_total_rtns,
          &fb_type_rtn
      );
      FileBrowserSetTransientFor(NULL);

      if(status)
      {
          if(fb_path_rtn != NULL)
          {
            int len = ((base_dir != NULL) ? strlen(base_dir) : 0);
            char *new_path, *strptr, *selected_path;

            /* Get pointer to last path return. */
            selected_path = ((fb_path_total_rtns > 0) ?
                fb_path_rtn[fb_path_total_rtns - 1] : NULL
            );
            if(selected_path != NULL)
            {
                /* Record last path, use textures directory list. */
                VMARecordFBPath(
                  selected_path,
                  dname.fb_last_textures,
                  1
                );

                /* Is base directory available? If so compare it with
                 * the path selected by user.
                 */
                if((base_dir != NULL) ?
#ifdef __MSW__
                  strcasepfx(selected_path, base_dir) : 0
#else
                  strpfx(selected_path, base_dir) : 0
#endif
                )
                {
                  /* Parse as relative path. */
                  strncpy(
                      tmp_path,
                      selected_path + len,
                      PATH_MAX + NAME_MAX
                  );
                  tmp_path[PATH_MAX + NAME_MAX - 1] = '\0';

                  /* Seek strptr past last dir deliminator. */
                  strptr = tmp_path;
                  while((*strptr) == DIR_DELIMINATOR)
                      strptr++;
                }
                else
                {
                  /* Use absolute path. */
                  strncpy(
                      tmp_path,
                      selected_path,
                      PATH_MAX + NAME_MAX
                  );
                  tmp_path[PATH_MAX + NAME_MAX - 1] = '\0';

                  /* Seek strptr to initial position of tmp_path. */
                  strptr = tmp_path;
                }

                /* Get pointer to new path. */
                new_path = strptr;
                if(new_path != NULL)
                {
                  gtk_entry_set_text(GTK_ENTRY(w), new_path);
                }

            }
          }
      }
      else
      {
          /* User canceled. */
      }

      return;
}

/*
 *    Heightfield dialog OK callback.
 */
void EditorHFDialogOKCB(void *idialog, void *data)
{
      ma_editor_struct *editor;
        ma_editor_idialog_struct *d = (ma_editor_idialog_struct *)idialog;
      if(d == NULL)
          return;

        editor = d->editor_ptr;
        if(editor == NULL)
            return;

      EditorHFDialogApplyCB(idialog, data);

        /* Reset input dialog. */
        EditorIDialogReset(editor, d, TRUE);

      return;
}


/*
 *    Heightfield dialog apply callback.
 */
void EditorHFDialogApplyCB(void *idialog, void *data)
{
      GtkWidget *w;
      gint model_num, pn;
      v3d_model_struct *model_ptr;
      gpointer p;
      mp_heightfield_load_struct *mp_heightfield;
        ma_editor_struct *editor = (ma_editor_struct *)data;
        ma_editor_idialog_struct *d = (ma_editor_idialog_struct *)idialog;
        if((editor == NULL) || (d == NULL))
            return;

      if(!editor->initialized || editor->processing)
          return;

      /* Note that we use the editor pointer passed from the data, not
       * the one pointed to by the input dialog (though they are the
       * same).
       */

      /* Get selected primitive on editor. */
      model_num = EditorSelectedModelIndex(editor);
      model_ptr = V3DModelListGetPtr(
          editor->model, editor->total_models, model_num
      );
      if((model_ptr == NULL) ?
          1 : (model_ptr->type != V3D_MODEL_TYPE_STANDARD)
      )
          return;

      /* Get selected primitive. */
      pn = ((editor->total_selected_primitives == 1) ?
          editor->selected_primitive[0] : -1
      );
      p = V3DMPListGetPtr(
          model_ptr->primitive, model_ptr->total_primitives, pn
      );
      if((p == NULL) ?
          1 : ((*(gint *)p) != V3DMP_TYPE_HEIGHTFIELD_LOAD)
      )
          return;

      mp_heightfield = (mp_heightfield_load_struct *)p;


      /* Get widget 0 from input dialog, which should be the path
       * to the heightfield image path.
       */
        w = EditorIDialogGetWidget(d, 0);
        if(w != NULL)
      {
          const gchar *path = (const gchar *)gtk_entry_get_text(GTK_ENTRY(w));
          if(path != NULL)
          {
            /* Update path on primitive. */
            free(mp_heightfield->path);
            mp_heightfield->path = strdup(path);
          }
      }

        /* Get widget 1 from input dialog, which should be the x axis
       * length.
         */
        w = EditorIDialogGetWidget(d, 1);
        if(w != NULL)
        {
            const char *value = (const char *)gtk_entry_get_text(GTK_ENTRY(w));
            if(value != NULL)
          {
            while(ISBLANK(*value))
                value++;

            mp_heightfield->x_length = atof(value);
          }
        }

        /* Get widget 2 from input dialog, which should be the y axis
         * length.  
         */
        w = EditorIDialogGetWidget(d, 2);
        if(w != NULL)
        {
            const char *value = (const char *)gtk_entry_get_text(GTK_ENTRY(w));
            if(value != NULL)
            {   
                while(ISBLANK(*value))
                    value++;

                mp_heightfield->y_length = atof(value);
          }
        }

        /* Get widget 3 from input dialog, which should be the z axis
         * length.  
         */
        w = EditorIDialogGetWidget(d, 3);
        if(w != NULL)
        {
            const char *value = (const char *)gtk_entry_get_text(GTK_ENTRY(w));
            if(value != NULL)
            {   
                while(ISBLANK(*value))
                    value++;

                mp_heightfield->z_length = atof(value);
          }
        }


      /* Mark editor as having changes. */
      if(!editor->has_changes)
          editor->has_changes = TRUE;

      /* Update primitives list. */
      EditorListPrimitivesSetHeightField(
          editor->primitives_list, pn,
          p, TRUE
      );

      /* Update the editor's values list. */
      EditorListDeleteValuesG(editor);
      EditorListAddValuesRG(editor, p);

      /* Re-realize heightfield load primitive. */
      EditorHFPrimitiveRealize(editor, mp_heightfield, TRUE);

      /* Update menus on editor. */
      EditorUpdateMenus(editor);
      EditorRedrawAllViews(editor);
      EditorUpdateAllViewMenus(editor);

      return;
}

/*
 *    Heightfield dialog cancel callback.
 */
void EditorHFDialogCancelCB(void *idialog, void *data)
{
        ma_editor_struct *editor;
        ma_editor_idialog_struct *d = (ma_editor_idialog_struct *)idialog;
        if(d == NULL)
            return;

        editor = d->editor_ptr;
        if(editor == NULL)
            return;

      /* Reset input dialog. */
        EditorIDialogReset(editor, d, TRUE);

      return;
}

Generated by  Doxygen 1.6.0   Back to index