FAQ  •  Register  •  Login

Crazy pointer arithmetic issues

Moderator: Inside3D Admins

<<

mankrip

User avatar

Posts: 500

Joined: Fri Jul 04, 2008 3:02 am

Post Thu Feb 24, 2011 2:29 am

Crazy pointer arithmetic issues

I'm trying to get TGAs to load in Makaqu, but the code I've ported from GLQuake refuses to work.

More specifically, this:
  Code:
typedef struct //_TargaHeader
{
   byte
      id_length
   ,   colormap_type
   ,   image_type
      ;
   unsigned short
      colormap_index
   ,   colormap_length
      ;
   byte
      colormap_size
      ;
   unsigned short
      x_origin
   ,   y_origin
   ,   width
   ,   height
      ;
   byte
      pixel_size
   ,   attributes
      ;
} TargaHeader;

void LoadTGA_as8bit (char *filename, byte **pic, int *width, int *height)
{
   TargaHeader      *filedata;               //pcx_t   *pcx;
   byte         *input, *output;         //*out,

   int            row, column;            //int      x, y;
   int            columns, rows, numPixels;   //int      dataByte, runLength;
   byte         *pixbuf;               //byte   *pix;
   loadedfile_t   *fileinfo;

   *pic = NULL;

   fileinfo = COM_LoadTempFile (filename);
   if (!fileinfo)
      return;

   // parse the file
   filedata = (TargaHeader *) fileinfo->data;

   if (filedata->image_type != 2 && filedata->image_type != 10)
      Sys_Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");

   if (filedata->colormap_type != 0)
      Sys_Error ("LoadTGA: No colormaps supported\non \"%s\"\n", filename);

   if (filedata->pixel_size != 32)
   if (filedata->pixel_size != 24)
      Sys_Error ("LoadTGA: Only 32 or 24 bit images supported\non \"%s\",\n%i not supported", filename, (int) (filedata->pixel_size));

   columns   = LittleShort (filedata->width         );
   rows   = LittleShort (filedata->height         );
   numPixels = columns * rows;

   *pic = output = malloc (numPixels);
   input = (byte *) filedata + sizeof (TargaHeader) + filedata->id_length; // skip TARGA image comment

   if (filedata->image_type == 2) // Uncompressed, RGB images
   {
      for(row = rows - 1 ; row >= 0 ; row--)
      {
         pixbuf = output + row * columns;
         for (column = 0 ; column < columns ; column++)
         {
            byte
               red
            ,   green
            ,   blue
            ,   alphabyte
               ;
            switch (filedata->pixel_size)
            {
               case 24:
                     blue      = input[ (rows - row) * columns + 0];
                     green      = input[ (rows - row) * columns + 1];
                     red         = input[ (rows - row) * columns + 2];
                     *pixbuf++ = BestColor (red, green, blue, 0, 254);
                     break;
               case 32:
                     blue      = input[ (rows - row) * columns + 0];
                     green      = input[ (rows - row) * columns + 1];
                     red         = input[ (rows - row) * columns + 2];
                     alphabyte   = input[ (rows - row) * columns + 3];
                     *pixbuf++ = (alphabyte == 255) ? 255 : BestColor (red, green, blue, 0, 254);
                     break;
            }
            input += (filedata->pixel_size / 8);
         }
      }
   }
}

I've just checked the TargaHeader struct and it's fine, it passes the image_type test with no problems, but when checking for the pixel_size it goes nuts, apparently reading two, five or eight bytes ahead, and returning 49 instead of 24.

These are the first 32 bytes of the TGA file:
  Code:
00 00 02 00   00 00 00 00   00 00 00 00   00 01 00 01
18 00 31 47   65 31 46 61   31 44 5B 33   4C 73 33 4E


This makes no sense for me, specially since the algorithm for loading PCX images is quite similar, and works just fine.
Thinking with slipgates.
=-=-=-=-=-=-=-=-=-=
Makaqu engine blog / website.
<<

leileilol

User avatar

Posts: 2399

Joined: Fri Oct 15, 2004 3:23 am

Post Thu Feb 24, 2011 2:32 am

Try ripping up Quake2's TGA loader rather than the questionably functional GLQuake one (what did glquake ever use tgas for lol)

Quake3's image loader is slicker and more streamlined by the way. I'd actually recommend using that so you also get JPEGs and BMPs in software (jpeg lib overhead, though...)
<<

Sajt

Posts: 1216

Joined: Sat Oct 16, 2004 3:39 am

Post Thu Feb 24, 2011 2:38 am

The fields in the TGA file are packed tightly, not padded for data alignment (like C structs are). You'll have to load it byte by byte.
F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe.
<<

Spike

Posts: 2070

Joined: Fri Nov 05, 2004 3:12 am

Location: UK

Post Thu Feb 24, 2011 4:54 am

  Code:
#pragma pack(push,1)
struct my struct
{
char sillydef;
int mybadlylayedoutfield;
} foo;
#pragma pack(pop)


will work as expected. without the pragmas, the struct is larger than you might expect due to padding for alignment.
gcc+mvsc should both understand the pragma.
<<

mankrip

User avatar

Posts: 500

Joined: Fri Jul 04, 2008 3:02 am

Post Mon Feb 28, 2011 7:42 pm

Thanks! It worked perfectly.
Thinking with slipgates.
=-=-=-=-=-=-=-=-=-=
Makaqu engine blog / website.
<<

Sajt

Posts: 1216

Joined: Sat Oct 16, 2004 3:39 am

Post Tue Mar 01, 2011 2:02 am

If you're going for crossplatform stability you probably shouldn't do that. I think some processors don't allow access of unaligned memory at all... (they crash). Someone else might be able to tell you more about this. The safest thing is not to do that pragma thing, but to load the header byte by byte.
F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe.
<<

Spike

Posts: 2070

Joined: Fri Nov 05, 2004 3:12 am

Location: UK

Post Tue Mar 01, 2011 2:21 am

if you're using gcc on a packed structure, it'll do special accesses to ensure its all aligned and fine and dandy.
but yeah, its slower on such machines (slower on x86 too, just not so noticably).
<<

qbism

User avatar

Posts: 790

Joined: Thu Nov 04, 2004 5:51 am

Post Mon Apr 04, 2011 5:10 pm

Thanks, this is great, now loading tga skies directly into 8-bit engine! Got type 10 (compressed) tga working also, need some clean-up and will post.
<<

qbism

User avatar

Posts: 790

Joined: Thu Nov 04, 2004 5:51 am

Post Tue Apr 05, 2011 3:33 am

Modified from Makaqu 1.4alpha
  Code:
void LoadTGA_as8bit (char *filename, byte **pic, int *width, int *height)
{
   TargaHeader      *filedata;               //pcx_t   *pcx;
   byte         *input, *output;         //*out,

   int            row, column;            //int      x, y;
   int            columns, rows, numPixels;   //int      dataByte, runLength;
   byte         *pixbuf;               //byte   *pix;
   loadedfile_t   *fileinfo;

   *pic = NULL;

   fileinfo = COM_LoadTempFile (filename);
   if (!fileinfo)
      return;

   // parse the file
   filedata = (TargaHeader *) (fileinfo->data);

   if (filedata->image_type != 2 && filedata->image_type != 10)
      Sys_Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");

   if (filedata->colormap_type != 0 || (filedata->pixel_size != 32 && filedata->pixel_size != 24))
      Sys_Error ("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\non \"%s\"\n", filename);

   columns   = LittleShort (filedata->width);
   rows   = LittleShort (filedata->height);
   Con_Printf ("%i columns x %i rows\n", columns, rows);
   numPixels = columns * rows;
    *width = filedata->width;
   *height = filedata->height;

   *pic = output = Q_malloc (numPixels);
   input = (byte *) filedata + sizeof (TargaHeader) + filedata->id_length; // skip TARGA image comment

   if (filedata->image_type == 2) // Uncompressed, RGB images
   {
        byte red, green, blue,alphabyte;
        int k = 0;
      for(row = rows - 1 ; row >= 0 ; row--)
      {
         pixbuf = output + row * columns;
         for (column = 0 ; column < columns ; column++)
         {
            switch (filedata->pixel_size)
            {
               case 24:
                     blue      = input[k++];
                     green      = input[k++];
                     red         = input[k++];
                     *pixbuf++ = BestColor (red, green, blue, 0, 254);
                     break;
               case 32:
                     blue      = input[k++];
                     green      = input[k++];
                     red         = input[k++];
                     alphabyte   = input[k++];
                     *pixbuf++ =  BestColor (red, green, blue, 0, 254);
                     break;
            }
         }
      }
   }

   else if (filedata->image_type == 10) // Runlength encoded RGB images
   {
        byte red, green, blue, alphabyte, packetHeader, packetSize, bestcol;
        int j, k=0;

      for (row = rows - 1 ; row >= 0 ; row--)
      {
         pixbuf = output + row * columns;
         for (column = 0 ; column < columns ; )
         {
            packetHeader = input[k++];
            packetSize = 1 + (packetHeader & 0x7f);
            if (packetHeader & 0x80) // run-length packet
            {
               switch (filedata->pixel_size)
               {
                  case 24:
                        blue      = input[k++];
                        green      = input[k++];
                        red         = input[k++];
                        bestcol = BestColor (red, green, blue, 0, 254);
                        break;
                  case 32:
                        blue      = input[k++];
                        green      = input[k++];
                        red         = input[k++];
                        alphabyte   = input[k++];
                        bestcol =  BestColor (red, green, blue, 0, 254);
                        break;
               }
                    for(j = 0 ; j < packetSize ; j++)
               {
                        *pixbuf++ = bestcol;
                  column++;
                  if (column == columns) // run spans across rows
                  {
                     column = 0;
                     if (row > 0)
                        row--;
                     else
                        goto breakOut;
                     pixbuf = output + row * columns;
                  }
               }
            }
            else // non run-length packet
            {
               for(j = 0 ; j < packetSize ; j++)
               {
                  switch (filedata->pixel_size)
                  {
                     case 24:
                           blue      = input[k++];
                           green      = input[k++];
                           red         = input[k++];
                           *pixbuf++   = BestColor (red, green, blue, 0, 254);
                           break;
                     case 32:
                           blue      = input[k++];
                           green      = input[k++];
                           red         = input[k++];
                           alphabyte   = input[k++];
                           *pixbuf++   = BestColor (red, green, blue, 0, 254);
                           break;
                  }
                  column++;
                  if (column == columns) // pixel packet run spans across rows
                  {
                     column = 0;
                     if (row > 0)
                        row--;
                     else
                        goto breakOut;
                     pixbuf = output + row * columns;
                  }
               }
            }
         }
         breakOut:;
      }
   }

}

<<

frag.machine

User avatar

Posts: 1475

Joined: Sat Nov 25, 2006 1:49 pm

Post Wed Apr 06, 2011 12:11 am

Where's the BestColor function ? I'm a bit curious about how you did it.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
<<

leileilol

User avatar

Posts: 2399

Joined: Fri Oct 15, 2004 3:23 am

Post Wed Apr 06, 2011 12:19 am

You can steal BestColor from the qlumpy source. That's what I did.
<<

qbism

User avatar

Posts: 790

Joined: Thu Nov 04, 2004 5:51 am

Post Wed Apr 06, 2011 5:01 pm

BestColor is in the revised load palette tute:
viewtopic.php?p=32285
<<

mankrip

User avatar

Posts: 500

Joined: Fri Jul 04, 2008 3:02 am

Post Mon Dec 10, 2012 2:31 am

Re: Crazy pointer arithmetic issues

That #pragma isn't recognized when compiling the Dreamcast version of the engine, so I did this:
  Code:
void LoadTGA_as8bit (char *filename, byte **pic, int *width, int *height)
{
   TargaHeader      filedata;               //pcx_t   *pcx;
[...]
   loadedfile_t   *fileinfo;

[...]

   fileinfo = COM_LoadTempFile (filename);
   if (!fileinfo)
      return;

   // parse the file
   filedata.id_length         = fileinfo->data[0];
   filedata.colormap_type      = fileinfo->data[1];
   filedata.image_type         = fileinfo->data[2];
   filedata.colormap_index      = * (unsigned short *) (fileinfo->data + 3);
   filedata.colormap_length   = * (unsigned short *) (fileinfo->data + 5);
   filedata.colormap_size      = fileinfo->data[7];
   filedata.x_origin         = * (unsigned short *) (fileinfo->data + 8);
   filedata.y_origin         = * (unsigned short *) (fileinfo->data + 10);
   filedata.width            = * (unsigned short *) (fileinfo->data + 12);
   filedata.height            = * (unsigned short *) (fileinfo->data + 14);
   filedata.pixel_size         = fileinfo->data[16];
   filedata.attributes         = fileinfo->data[17];

[...]
}

This have worked for me (on Windows at least, I'm going to test it on the Dreamcast in some minutes), but I guess it may not work on machines using a different endianess. How do I take care of the endianess?
Thinking with slipgates.
=-=-=-=-=-=-=-=-=-=
Makaqu engine blog / website.
<<

mankrip

User avatar

Posts: 500

Joined: Fri Jul 04, 2008 3:02 am

Post Sat Dec 22, 2012 5:25 am

Re: Crazy pointer arithmetic issues

mankrip wrote:How do I take care of the endianess?

Some googling gave me the answer.
Thinking with slipgates.
=-=-=-=-=-=-=-=-=-=
Makaqu engine blog / website.

Return to General Programming

Who is online

Users browsing this forum: Google [Bot] and 0 guests

cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.
Icons provided by Aha Soft