Logo Search packages:      
Sourcecode: vertex version File versions

viewbg.c

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

#ifdef HAVE_IMLIB
# include <Imlib.h>
#endif  /* HAVE_IMLIB */

#include <GL/gl.h>

#include <gtk/gtk.h>

#include "../include/tga.h"
#include "v3dtex.h"
#include "guiutils.h"

#include "view.h"
#include "viewbg.h"
#include "viewdraw.h"

#include "vma.h"

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


view_bgimage_struct *ViewBGImageLoad(
        guint flags,
        gpointer view_ptr,
        const gchar *path,
        gdouble v_offset_i, gdouble v_offset_j, /* In meters. */
      gdouble v_scale_i, gdouble v_scale_j      /* Pielx to meters coeff. */
);
void ViewBGImageUnload(view_bgimage_struct *bgimg);

static void ViewBGImageDraw2D(
        view_bgimage_struct *bgimg,
        vma_view2d_struct *v
);
static void ViewBGImageDraw3D(
        view_bgimage_struct *bgimg,
        vma_view3d_struct *v
);
void ViewBGImageDraw(view_bgimage_struct *bgimg);


#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)


/*
 *    Loads the specified background image from the texture image
 *    file referanced by the given path. Returns a newly allocated
 *    view_bgimage_struct or NULL on error.
 *
 *    Returned view_bgimage_struct must be deallocated by a call to
 *    ViewBGImageUnload().
 *
 *    This function may place the given view into context before loading
 *    of the texture.
 *
 *    If w_length_i and w_length_h are both 0 then it imples to use
 *    current size.
 */
view_bgimage_struct *ViewBGImageLoad(
        guint flags,
        gpointer view_ptr,
        const gchar *path,
        gdouble v_offset_i, gdouble v_offset_j, /* In meters. */
        gdouble v_scale_i, gdouble v_scale_j    /* Pielx to meters coeff. */
)
{
      view_bgimage_struct *bgimg;
      u_int8_t *tex_data = NULL;
      gint tex_width = 0, tex_height = 0;
      v3d_texture_ref_struct *texture;
      struct stat stat_buf;


      if(path == NULL)
          return(NULL);

      /* No such file? */
      if(stat(path, &stat_buf))
          return(NULL);

      /* Set given view into GL context before loading texture. */

      /* Using 2d view? */
      if(flags & VIEW_BGIMAGE_FLAG_VIEW_2D)
      {
          vma_view2d_struct *v = (vma_view2d_struct *)view_ptr;
            if((v == NULL) ? 0 : v->initialized)
                View2DGLEnableContext(v);
      }
      /* Using 3d view? */
      else if(flags & VIEW_BGIMAGE_FLAG_VIEW_3D)
      {
            vma_view3d_struct *v = (vma_view3d_struct *)view_ptr;
          if((v == NULL) ? 0 : v->initialized)
                View3DGLEnableContext(v);
      }

      /* Begin attempting to load image data. */
#ifdef HAVE_IMLIB
      /* First try to load texture data using Imlib. */
        while((imlib_handle != NULL) && (tex_data == NULL))
        {
            gint len;
          gchar *dpath;
          ImlibImage *imlib_image;


          /* Copy path and load image. */
          dpath = g_strdup(path);
            imlib_image = Imlib_load_image(imlib_handle, dpath);
          g_free(dpath); dpath = NULL;

          /* Failed to load Imlib image? */
            if(imlib_image == NULL)
                break;

          /* Need to re-realize Imlib image incase the image changed on
           * disk.
           */
          Imlib_changed_image(imlib_handle, imlib_image);

          /* Get texture size. */
            tex_width = imlib_image->rgb_width;
            tex_height = imlib_image->rgb_height;

            /* Calculate length of image data in bytes, since in RGB
             * format that would be w * h * 3 bytes.
             */
            len = tex_width * tex_height * 3;

            /* Allocate and copy image data. */
            if(len > 0)
                tex_data = (u_int8_t *)g_malloc(len);
            if(tex_data != NULL)
                memcpy(
                    tex_data, 
                    imlib_image->rgb_data,
                    len
                ); 

            /* Unref and cache loaded Imlib image. */
            Imlib_destroy_image(imlib_handle, imlib_image);
          imlib_image = NULL;

            break;
        }
#endif  /* HAVE_IMLIB */

        /* If still unable to load texture data then try the built in
       * Targa library.
       */
        while(tex_data == NULL)
        {
            /* Attempt to load as tga image using internal tga
             * loading functions.
             */
            u_int32_t   *ptr32_src, *ptr32_src_end;
            u_int8_t    *ptr8_tar, *ptr8_tar_end;
            u_int8_t a, r, g, b;
          gint status, len;
            tga_data_struct td;


            memset(&td, 0x00, sizeof(tga_data_struct));

            status = TgaReadFromFile(
                path,
                &td,
                32
            );
            if(status != TgaSuccess)
            {
                TgaDestroyData(&td);
                break;
            }

            tex_width = td.width;
            tex_height = td.height;

            /* Allocate target buffer for RGB, that's (w * h * 3). */
            len = tex_width * tex_height * 3;
            if(len > 0)
                ptr8_tar = (u_int8_t *)g_malloc(len);
            else
                ptr8_tar = NULL;

            /* Set texture data pointer to target buffer. */
            tex_data = ptr8_tar;
            ptr8_tar_end = ptr8_tar + len;

            /* Get pointer to source buffer. */
            ptr32_src = (u_int32_t *)td.data;
            ptr32_src_end = ptr32_src + (tex_width * tex_height);

            if((ptr32_src != NULL) && (ptr8_tar != NULL))
            {
                while(ptr32_src < ptr32_src_end)
                {
                    a = (u_int8_t)(((*ptr32_src) & 0xff000000) >> 24);
                    r = (u_int8_t)(((*ptr32_src) & 0x00ff0000) >> 16);
                    g = (u_int8_t)(((*ptr32_src) & 0x0000ff00) >> 8);
                    b = (u_int8_t)(((*ptr32_src) & 0x000000ff) >> 0);

                    *ptr8_tar++ = r;
                    *ptr8_tar++ = g;
                    *ptr8_tar++ = b;

                    ptr32_src++;
                }  
            }

            TgaDestroyData(&td);

            break;
        }

      /* If all fallbacks failed to load texture data then give up. */
      if(tex_data == NULL)
          return(NULL);


        /* Create texture from image data, note the size of the 
       * texture may be re-adjusted after loading to make it conform
       * to GL standards.
       */
      texture = V3DTextureLoadFromData2D(
          tex_data,
          "background", /* Not used, but just it something. */
          tex_width, tex_height,
          24,                 /* Bits per pixel. */
          V3D_TEX_FORMAT_RGB, /* Destination format. */
          NULL, NULL
      );
      if(texture == NULL)
      {
          g_free(tex_data);
          return(NULL);
      }

      /* At this point tex_width and tex_height reflect the original
       * size of the image, they are garbage for current values but
       * that is okay. We only want to know the original size.
       */

      /* Free texture data, it is no longer needed. */
      g_free(tex_data);
      tex_data = NULL;


      /* Allocate background image structure. */
      bgimg = (view_bgimage_struct *)g_malloc0(
            sizeof(view_bgimage_struct)
        );
        if(bgimg == NULL)
      {
          V3DTextureDestroy(texture);
            return(bgimg);
      }

if(v_scale_i <= 0.0)
 v_scale_i = 0.01;
if(v_scale_j <= 0.0)
 v_scale_j = 0.01;


        /* Set input values to newly allocated structure. */
        bgimg->flags = flags;
        bgimg->view_ptr = view_ptr;
        bgimg->path = ((path != NULL) ? g_strdup(path) : NULL);
        bgimg->v_offset_i = v_offset_i;
        bgimg->v_offset_j = v_offset_j;
        bgimg->v_length_i = v_scale_i * tex_width;
        bgimg->v_length_j = v_scale_j * tex_height;
      bgimg->texture = texture;
      bgimg->tex_width = tex_width;
      bgimg->tex_height = tex_height;
      bgimg->tex_aspect = (tex_height <= 0) ?
          1.0 : (gdouble)tex_width / (gdouble)tex_height;
      

      return(bgimg);
}

/*
 *    Deallocates all resources on the given view_bgimage_struct and
 *    deallocates the structure itself. The view_bgimage_struct's
 *    view structure may be placed into GL context before deallocating
 *    of the texture by this function.
 */
void ViewBGImageUnload(view_bgimage_struct *bgimg)
{
      if(bgimg == NULL)
          return;

        /* Using 2d view? */
        if(bgimg->flags & VIEW_BGIMAGE_FLAG_VIEW_2D)
        {
            vma_view2d_struct *v = (vma_view2d_struct *)bgimg->view_ptr;
            if((v == NULL) ? 0 : v->initialized)
            {
                View2DGLEnableContext(v);
                V3DTextureDestroy(bgimg->texture);
                bgimg->texture = NULL;
            }
        }
        /* Using 3d view? */
        else if(bgimg->flags & VIEW_BGIMAGE_FLAG_VIEW_3D)
        {
            vma_view3d_struct *v = (vma_view3d_struct *)bgimg->view_ptr;
            if((v == NULL) ? 0 : v->initialized)
            {
            View3DGLEnableContext(v);
            V3DTextureDestroy(bgimg->texture);
            bgimg->texture = NULL;
            }
        }

      if(bgimg->texture != NULL)
      {
          fprintf(
            stderr,
"ViewBGImageUnload(): Unable to destroy background image texture.\n"
          );
      }

      /* Deallocate other resources. */
      g_free(bgimg->path);
      bgimg->path = NULL;

      /* Deallocate structure itself. */
      g_free(bgimg);
      bgimg = NULL;
}


/*
 *    Draw background for 2d view.
 */
static void ViewBGImageDraw2D(
      view_bgimage_struct *bgimg,
      vma_view2d_struct *v
)
{
      GtkWidget *w;
      gint w_hw, w_hh;
      gdouble i[2], j[2], bi[2], bj[2];
      gdouble vtow_coeff;
      gdouble i_flip_coeff = 1.0, j_flip_coeff = -1.0;


      if((v != NULL) ? !v->initialized : 1)
          return;

        /* Get GtkGLArea widget from view. */
      w = v->view;
        if(w == NULL)
            return;

      /* Calculate half sizes of glarea widget. */
      w_hw = w->allocation.width / 2;
      w_hh = w->allocation.height / 2;

      /* View to window coeff. */
      vtow_coeff = View2DGetVToWCoeff(v);
      if(vtow_coeff <= 0.0)
          return;

      /* Get flip coefficient values. */
      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);

      /* Calculate geometry of background image in meters. */
      bi[0] = bgimg->v_offset_i - (bgimg->v_length_i / 2);
      bj[0] = bgimg->v_offset_j - (bgimg->v_length_j / 2);
      bi[1] = bi[0] + bgimg->v_length_i;
      bj[1] = bj[0] + bgimg->v_length_j;

      /* Calculate background image in window coordinates. */
      i[0] = (((bi[0] * i_flip_coeff) - v->v_ti) * vtow_coeff) + w_hw;
      j[0] = (((bj[0] * j_flip_coeff) - v->v_tj) * vtow_coeff) + w_hh;
        i[1] = (((bi[1] * i_flip_coeff) - v->v_ti) * vtow_coeff) + w_hw;
        j[1] = (((bj[1] * j_flip_coeff) - v->v_tj) * vtow_coeff) + w_hh;

      /* Need to flip results of calculated window coordinates? */
      if(i_flip_coeff < 0.0)
      {
          gdouble t = i[0];
          i[0] = i[1];
          i[1] = t;
      }
        if(j_flip_coeff < 0.0)
        {
            gdouble t = j[0];
            j[0] = j[1];
            j[1] = t;
        }


        /* Enable 2d texture. */
        glEnable(GL_TEXTURE_2D);

        /* Select texture. */
        V3DTextureSelect(bgimg->texture);

        glColor4f(1.0, 1.0, 1.0, 1.0);
        glBegin(GL_QUADS);
        {
            glTexCoord2d(0.0, 1.0);
            glVertex2d(i[0], j[0]);

            glTexCoord2d(0.0, 0.0);
            glVertex2d(i[0], j[1]);

            glTexCoord2d(1.0, 0.0);
            glVertex2d(i[1], j[1]);

            glTexCoord2d(1.0, 1.0);
            glVertex2d(i[1], j[0]);
        }
        glEnd();

        /* Unselect texture. */
        V3DTextureSelect(NULL);
}

/*
 *      Draw background for 3d view.
 */
static void ViewBGImageDraw3D(
        view_bgimage_struct *bgimg,
        vma_view3d_struct *v
)
{
        GtkWidget *w;
        gint w_hw, w_hh, ww, wh, bwidth, bheight;
        gdouble bi[2], bj[2];
        gdouble aspect;


        if((v != NULL) ? !v->initialized : 1)
            return;

        /* Get GtkGLArea widget from view. */
        w = v->view;
        if(w == NULL)
            return;

        /* Calculate half sizes of glarea widget. */
      ww = w->allocation.width;
      wh = w->allocation.height;
        w_hw = ww / 2;
        w_hh = wh / 2;
      aspect = bgimg->tex_aspect;
      if(aspect <= 0.0)
          return;

      /* Calculate bg image size. */
      bwidth = ww;
      bheight = ww / aspect;
      if(bheight > wh)
      {
          bheight = wh;
          bwidth = wh * aspect;
      }

      /* Calculate bg image position. */
      bi[0] = w_hw - (bwidth / 2);
        bj[0] = w_hh - (bheight / 2);
      bi[1] = bi[0] + bwidth;
      bj[1] = bj[0] + bheight;

        /* Enable 2d texture. */
        glEnable(GL_TEXTURE_2D);

        /* Select texture. */
        V3DTextureSelect(bgimg->texture);

        glColor4f(1.0, 1.0, 1.0, 1.0);
        glBegin(GL_QUADS);
        {
            glTexCoord2d(0.0, 1.0);
            glVertex2d(bi[0], bj[0]);

            glTexCoord2d(0.0, 0.0);
            glVertex2d(bi[0], bj[1]);

            glTexCoord2d(1.0, 0.0);
            glVertex2d(bi[1], bj[1]);

            glTexCoord2d(1.0, 1.0);
            glVertex2d(bi[1], bj[0]);
        }
        glEnd();

        /* Unselect texture. */
        V3DTextureSelect(NULL);
}

/*
 *    Redraws the background texture.
 *
 *    The view structure referanced by the given view_bgimage_struct
 *    will NOT be placed into context, it is up to the calling function
 *    to do that. The calling function must also set up an orthogonal
 *    viewport with coordinate bounds that match the size of the glarea
 *    widget on the view.
 *
 *    GL_TEXTURE_2D will be enabled in this function, so the calling
 *    function needs to note that.
 */
void ViewBGImageDraw(view_bgimage_struct *bgimg)
{
      if(bgimg == NULL)
          return;

      if(bgimg->view_ptr == NULL)
          return;

      if((bgimg->texture == NULL) || (bgimg->tex_width < 1) ||
         (bgimg->tex_height < 1) || (bgimg->tex_aspect <= 0.0)
      )
          return;

        /* Using 2d view? */
        if(bgimg->flags & VIEW_BGIMAGE_FLAG_VIEW_2D)
          ViewBGImageDraw2D(
            bgimg, (vma_view2d_struct *)bgimg->view_ptr
          );
        /* Using 3d view? */
        else if(bgimg->flags & VIEW_BGIMAGE_FLAG_VIEW_3D)
            ViewBGImageDraw3D(
                bgimg, (vma_view3d_struct *)bgimg->view_ptr
            );
}

Generated by  Doxygen 1.6.0   Back to index