Logo Search packages:      
Sourcecode: vertex version File versions

vmadde.c

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <ctype.h>

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

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

#include "v3dfio.h"

#include "vmadde.h"

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


static char *cat_line_array(char **line, int total_lines);
static char **explode_line(const char *line, int *n_lines);

char *VMADDEPrimitivesToText(void **primitive, int total_primitives);
int VMADDETextToPrimitives(
      const char *text,
      void ***primitive, int *total_primitives
);

char *VMADDEModelsToText(v3d_model_struct **model, int total_models);
int VMADDETextToModels(
      const char *text,
      v3d_model_struct ***model, int *total_models
);


#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 DEGTORAD(d)     ((d) * PI / 180)
#define RADTODEG(r)     ((r) * 180 / PI)

#define ISCR(c)         (((c) == '\n') || ((c) == '\n'))


/*
 *    Returns a dynamically allocated string containing all
 *    the given lines concatinated togeather with '\n' delimiators.
 */
static char *cat_line_array(char **line, int total_lines)
{
      int line_i_num, line_i_len;
      int line_o_len = 0;
      const char *line_i;
      char *line_o = NULL;


      /* Allocate first null byte into line_o. */
      line_o = (char *)malloc((line_o_len + 1) * sizeof(char));
      if(line_o == NULL)
          return(line_o);
      else
          line_o[line_o_len] = '\0';

      /* Check if given line arrays are non-empty. */
      if((line == NULL) || (total_lines <= 0))
          return(line_o);

      /* Go through each line. */
      for(line_i_num = 0; line_i_num < total_lines; line_i_num++)
      {
          line_i = line[line_i_num];
          if(line_i == NULL)
            continue;


          /* Get length of input line. */
            line_i_len = strlen(line_i);

          /* Increase out line by the length of the in line plus one
           * extra byte for the new line character.
           */
          line_o_len += (line_i_len + 1);
          /* Allocate more of the out line and add one more byte for
           * the null character.
           */
          line_o = (char *)realloc(
            line_o,
            (line_o_len + 1) * sizeof(char *)
          );
          if(line_o == NULL)
          {
            return(line_o);
          }

          strcat(line_o, line_i);
          line_o[line_o_len - 1] = '\n';
          line_o[line_o_len] = '\0';
      }

      return(line_o);
}


/*
 *    Explodes the given line, deliminating at all '\n' characters.
 *
 *    Any '\n' character starting with a '\\' will be escaped and not
 *    exploded.
 *
 *    Returned array of strings and the array itself need to be free'ed
 *    by the calling function.
 */
static char **explode_line(const char *line, int *n_lines)
{
      const int chunk_size = 80;
        const char *line_i = line;
        int line_i_pos = 0;

        char **line_o = NULL;
        int total_lines_o = 0;

        char *cur_line_o;
        int cur_line_o_pos, cur_line_o_len;


        /* Check if given line arrays are non-empty. */
        if((line == NULL) || (n_lines <= 0))
        {
            if(n_lines != NULL)
                (*n_lines) = total_lines_o;
            return(line_o);
        }

        /* Allocate first line. */
        total_lines_o = 1;
        line_o = (char **)realloc(
            line_o,
            total_lines_o * sizeof(char *)
        );
        if(line_o == NULL)
        {
            total_lines_o = 0;
            if(n_lines != NULL)
                (*n_lines) = total_lines_o;
            return(line_o);
        }
        cur_line_o_pos = 0;
        cur_line_o_len = 0;
        cur_line_o = NULL;

        line_o[total_lines_o - 1] = cur_line_o;


        /* Itterate through input line. */
        while(line_i[line_i_pos] != '\0')
        {
            int ci = line_i[line_i_pos];

          /* Increase allocation to output line as needed. */
            if(cur_line_o_pos <= cur_line_o_len)
            {
                cur_line_o_len = (cur_line_o_pos + chunk_size);
                cur_line_o = (char *)realloc(
                    cur_line_o,
                    (cur_line_o_len + 2) * sizeof(char)
                );
                if(cur_line_o == NULL)
                {
                    cur_line_o_pos = 0;
                    cur_line_o_len = 0;
                    line_o[total_lines_o - 1] = cur_line_o;
                    total_lines_o--;
                    break;
                }
            }


            if(ci == '\\')
            {
            /* Store backslash character. */
                cur_line_o[cur_line_o_pos] = ci;
                cur_line_o_pos++;
                line_i_pos++;

                /* Next character should be preserved literally, but
             * check for the exception that it is null.
             */
                ci = line_i[line_i_pos];
                if(ci == '\0')
                    break;

            cur_line_o[cur_line_o_pos] = ci;
                cur_line_o_pos++;
                line_i_pos++;
            }
            else if(ISCR(ci))
            {
                /* End and record current output line. */
                cur_line_o[cur_line_o_pos] = '\0';
                line_o[total_lines_o - 1] = cur_line_o;

                /* Reset output line. */
                cur_line_o_pos = 0;
            cur_line_o_len = 0;
                cur_line_o = NULL;

                /* Allocate a new output line in array. */
                total_lines_o++;
                line_o = (char **)realloc(
                    line_o,
                    total_lines_o * sizeof(char *)
                );
                if(line_o == NULL)
                {
                    total_lines_o = 0;
                    break;
                }
                else
                {
                    line_o[total_lines_o - 1] = NULL;
                }

                line_i_pos++;
            }
            else
            {
                cur_line_o[cur_line_o_pos] = ci;
                cur_line_o_pos++;
                line_i_pos++;
            }
        }

        /* End current line if any. */
      if(total_lines_o > 0)
      {
          line_o[total_lines_o - 1] = cur_line_o;
          if(cur_line_o == NULL)
            total_lines_o--;
          else
            cur_line_o[cur_line_o_pos] = '\0';
      }
      else
      {
          free(line_o);
          line_o = NULL;
          total_lines_o = 0;
      }

      /* Update total lines return value. */
        if(n_lines != NULL)
            (*n_lines) = total_lines_o;   

        return(line_o);
}


/*
 *    Returns a dynamically allocated string containing a V3D format
 *    specification for the given primitives and will place them
 *    in to a model of type V3D_MODEL_TYPE_STANDARD named "standard".
 *
 *    The given primitives list and the primitives themselves will not
 *    be destroyed or modified.
 */
char *VMADDEPrimitivesToText(void **primitive, int total_primitives)
{
      int status;
      char **buf, **buf_ptr;
      char *line_rtn;
      int buf_lines;
      v3d_model_struct **model, *model_ptr;
      int total_models = 1;


      if((primitive == NULL) || (total_primitives <= 0))
          return(NULL);

      /* Allocate one model and create the model list. */
      model_ptr = V3DModelCreate(V3D_MODEL_TYPE_STANDARD, "standard");
      if(model_ptr == NULL)
          return(NULL);

      model = (v3d_model_struct **)calloc(
          total_models, sizeof(v3d_model_struct *)
      );
      if(model == NULL)
      {
          V3DModelDestroy(model_ptr);
          return(NULL);
      }

      model[0] = model_ptr;

      /* Set primitives pointer to model's primitives list. */
        model_ptr->primitive = primitive;
      model_ptr->total_primitives = total_primitives;

      /* Save model to buffer, so we should get back an array of
       * V3D format lines.
       */
      buf = NULL;
        status = V3DSaveModel(
            &buf, NULL,
            NULL, 0,          /* No model header items. */
            model, total_models,
            0,                /* No optimization. */
          0,                  /* Do not strip extranous data. */
            NULL, NULL
        );

      /* Count number of buf_lines we got. */
      buf_ptr = buf;
      buf_lines = 0;
      while((*buf_ptr) != NULL)
      {
          buf_lines++;
          buf_ptr++;
      }

        /* Concatinate all loaded lines into one dynamically
         * allocated line.
         */
      line_rtn = cat_line_array(buf, buf_lines);

      /* Reset primitives list to NULL on model but do not destroy
       * the given primitives.
       */
      model_ptr->primitive = NULL;
      model_ptr->total_primitives = 0;
      V3DModelDestroy(model_ptr);
      model_ptr = NULL;

      /* Free models list. */
      free(model);
      model = NULL;
      total_models = 0;

      /* Free loaded lines. */
      StringFreeArray(buf, buf_lines);

      return(line_rtn);
}

/*
 *    Returns a list of dynamically allocated V3D model primitives
 *    from the given V3D format string text. The string may contain
 *    more than one model in which case multiple model's primitives
 *    will be concatinated into a single primitives list on return.
 *
 *    Calling function needs to destroy the returned primitives and
 *    pointer array.
 *
 *    Returns non-zero on error.
 */
int VMADDETextToPrimitives(
        const char *text,
        void ***primitive, int *total_primitives
)
{
      int status;
      char **buf;
      int buf_lines;
      void **mh_item; int total_mh_items;
      v3d_model_struct **model, *model_ptr; int total_models;
      int i, n, pcur, ptotal;
      void **plist;


      if(primitive != NULL)
          (*primitive) = NULL;
      if(total_primitives != NULL)
          (*total_primitives) = 0;

      if(text == NULL)
          return(-1);

      /* Explode input V3D format line into multiple lines. */
      buf = explode_line(text, &buf_lines);
      if((buf == NULL) || (buf_lines <= 0))
      {
          free(buf);
          return(-1);
      }

      /* Add last buf line to be NULL. */
      buf = (char **)realloc(
          buf,
          (buf_lines + 1) * sizeof(char *)
      );
      if(buf == NULL)
          return(-1);
      else
          buf[buf_lines] = NULL;

      /* Load V3D format lines. */
      mh_item = NULL; total_mh_items = 0;
      model = NULL; total_models = 0;
      status = V3DLoadModel(
          (const char **)buf, NULL,
          &mh_item, &total_mh_items,
          &model, &total_models,
          NULL, NULL
      );

      /* Destroy the exploded lines, they are no longer needed. */
      StringFreeArray(buf, buf_lines);
      buf = NULL; buf_lines = 0;

      /* Destroy the loaded model header items, they are not needed. */
      V3DMHListDeleteAll(&mh_item, &total_mh_items);


      /* Go through each loaded model and calculate the total number
       * of primitives ptotal.
       */
      for(i = 0, ptotal = 0; i < total_models; i++)
      {
          model_ptr = model[i];
          if(model_ptr == NULL)
            continue;

          ptotal += model_ptr->total_primitives;
      }

      /* Allocate local primitives list plist. */
      if(ptotal > 0)
          plist = (void **)malloc(ptotal * sizeof(void *));
      else
          plist = NULL;
      if(plist == NULL)
      {
          V3DModelListDeleteAll(&model, &total_models);
          return(-1);
      }

      /* Concatinate all primitives loaded from each model into
       * one primitives list plist.
       */
      for(i = 0, pcur = 0; i < total_models; i++)
        {
            model_ptr = model[i];
            if(model_ptr == NULL) 
                continue;

          for(n = 0; n < model_ptr->total_primitives; n++)
          {
                if(pcur >= ptotal)
                    break;

            plist[pcur] = model_ptr->primitive[n];
            pcur++;
          }

          /* Reset model's primitives list pointer array since we
           * transfered all the primitives to our local primitives list.
           */
          model_ptr->total_primitives = 0;
          free(model_ptr->primitive);
          model_ptr->primitive = NULL;

          /* Destroy the model too, it will not be needed again. */
          V3DModelDestroy(model_ptr);
      }
      /* Free model list. */
      free(model);
      model = NULL;
      total_models = 0;

      /* Update returns. */
        if(primitive != NULL)
            (*primitive) = plist;
        if(total_primitives != NULL)
            (*total_primitives) = ptotal;

      return(0);
}


/*
 *      Returns a dynamically allocated string containing a V3D format
 *      specification for the given models.
 *
 *      The given modelslist and the models themselves will not
 *      be destroyed or modified.
 */
char *VMADDEModelsToText(v3d_model_struct **model, int total_models)
{
      char **buf, **buf_ptr;
      int status, buf_lines;
      char *line_rtn;


        if((model == NULL) || (total_models <= 0))
            return(NULL);

        /* Save model to buffer, so we should get back an array of  
         * V3D format lines.
         */
        buf = NULL;
        status = V3DSaveModel(
            &buf, NULL,
            NULL, 0,            /* No model header items. */
            model, total_models,
            0,                /* No optimization. */
          0,                  /* Do not strip extranous data. */
            NULL, NULL
        );

        /* Count number of buf_lines we got. */
        buf_ptr = buf;
        buf_lines = 0;
        while((*buf_ptr) != NULL)
        {
            buf_lines++;
            buf_ptr++;
        }

        /* Concatinate all loaded lines into one dynamically
       * allocated line.
       */
        line_rtn = cat_line_array(buf, buf_lines);

        /* Free loaded lines. */
        StringFreeArray(buf, buf_lines);

      return(line_rtn);
}

/*
 *    Returns a list of dynamically allocated V3D models from the given
 *    V3D format string text, which may contain more than one model.
 *
 *      Calling function needs to destroy the returned models and pointer
 *    array.
 *
 *      Returns non-zero on error.
 */
int VMADDETextToModels(
        const char *text,
        v3d_model_struct ***model, int *total_models
)
{
        int status;
        char **buf;
        int buf_lines;
        void **mh_item; int total_mh_items;


        if(model != NULL)
            (*model) = NULL;
        if(total_models != NULL)
            (*total_models) = 0;

        if(text == NULL)
            return(-1);

        /* Explode input V3D format line into multiple lines. */
        buf = explode_line(text, &buf_lines);
        if((buf == NULL) || (buf_lines <= 0))
        {
            free(buf);
            return(-1);
        }

        /* Add last buf line to be NULL. */
        buf = (char **)realloc(
            buf,
            (buf_lines + 1) * sizeof(char *)
        );
        if(buf == NULL)  
        {
            return(-1);
        }
        buf[buf_lines] = NULL;

        /* Load V3D format lines. */
        mh_item = NULL; total_mh_items = 0;
        status = V3DLoadModel(
            (const char **)buf, NULL,
            &mh_item, &total_mh_items,
            model, total_models,
            NULL, NULL
        );

        /* Destroy the exploded lines, they are no longer needed. */
        StringFreeArray(buf, buf_lines);
        buf = NULL; buf_lines = 0;

        /* Destroy the loaded model header items, they are not needed. */
        V3DMHListDeleteAll(&mh_item, &total_mh_items);


        /* Model returns already updated when calling V3DLoadModel(). */

      return(0);
}

Generated by  Doxygen 1.6.0   Back to index