Colourblind

Welcome to Colourblind.

This is the personal web space of Tom Milsom. As much as possible everything is free (as in speach and as in beer).


Make text: Smaller Bigger

Creating OpenGL Textures from Embedded Win32 Resources

Posted by Tom on 10/06/2011 17:37:13

So I was faffing around with Those Magnificent Men - one of my after-hours just-simple-enough-to-work game projects. I'd been working quite a lot with Cinder and its slick resource handling and wondered if I could do something similar in my own non-Cinder projects. Rather than loading the game's resources (graphics, sounds and the like) from external files, it's neater as a single, all-encompassing monolithic beast of an executable. Besides, any simple game is going to find itself competing with Flash when it comes to ease of distribution, so anything you can do to smooth the process has got to be good.

Typically you'd embed the data inside the binary as a resource, but there's no mechanism for loading my image format of choice (PNG) from a resource. Only BMP images, which are made from orphans' tears and give kittens cancer. There must be a way to loaded PNGs out of an embedded resource and into an OpenGL texture, right?

Resource Loading . . .

I ended up using the resource type of RCDATA since any of the included image formats come with Visual Studio baggage. Oddly, even calling it PNG causes Visual Studio to try and barge you out of the way in that charming I-know-best-pal manner, despite PNG not being on the list of file types it purports to recognise.

   1:  HRSRC resourceBlock = ::FindResource(NULL, MAKEINTRESOURCE(resourceId), RT_RCDATA);
   2:  HGLOBAL resourceHandle = ::LoadResource(NULL, resourceBlock);
   3:  unsigned char *resourceData = (unsigned char *)::LockResource(resourceHandle);

That's our data, but it's in PNG format. It's time to break out the image loaders.

Image Loading . . .

In the past I've used stb_image for my image loading needs, but since it's all I've ever really used I decided to shop around a bit. In the end I plumped for the hairier libpng instead, but there are plenty of image loading options out there. If you're using another one then do your thing and we'll meet up again at part 3.

While libpng typically takes its input from a FILE pointer, it will allow you to supply your own function to do the data reading. In our case it's going to look like this:

   1:  struct PngBuffer
   2:  {
   3:      PngBuffer(unsigned char *data) : Data(data), Position(0) { }
   4:   
   5:      unsigned char *Data;
   6:      unsigned int Position;
   7:  };
   8:   
   9:  void ReadData(png_structp pngPtr, png_bytep data, png_size_t length)
  10:  {
  11:      PngBuffer *buffer = reinterpret_cast<PngBuffer *>(png_get_io_ptr(pngPtr));
  12:      memcpy(reinterpret_cast<unsigned char *>(data), buffer->Data + buffer->Position, length);
  13:      buffer->Position += length;
  14:  }

When setting up our libpng structures we then pass in the above function using png_set_read_fn.

   1:  png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
   2:  png_infop infoPtr = png_create_info_struct(pngPtr);
   3:  PngBuffer buffer(resourceData);
   4:  png_set_read_fn(pngPtr, rreinterpret_cast<voidp>(&buffer), ReadData);

And then it's business as usual.

   1:  png_read_info(pngPtr, infoPtr);
   2:   
   3:  unsigned int width = infoPtr->width;
   4:  unsigned int height = infoPtr->height;
   5:  short bitDepth = infoPtr->bit_depth;
   6:  short channels = infoPtr->channels;
   7:   
   8:  unsigned char *imageData = new unsigned char[width * height * bitDepth * channels / 8];
   9:  unsigned char **rowPointers = new unsigned char *[height];
  10:   
  11:  for (unsigned int i = 0; i < height; i ++)
  12:      rowPointers[i] = &(imageData[i * width * bitDepth * channels / 8]);
  13:   
  14:  png_read_image(pngPtr, (png_bytepp)rowPointers);
  15:   
  16:  // Insert OpenGL texture loading gubbins here
  17:   
  18:  delete [] imageData;
  19:  delete [] rowPointers;

Texture Loading . . .

That's the hard part out of the way. Now we have the raw pixel data we need to loading this into OpenGL as texture data. The following lines will look very familiar to anyone with OpenGL experience.

   1:  GLuint texture;
   2:   
   3:  glGenTextures(1, &texture);
   4:  glBindTexture(GL_TEXTURE_2D, texture);
   5:   
   6:  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   7:  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   8:  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, x, y, 0, GL_RGB, GL_UNSIGNED_BYTE, imageData);

Beer Loading . . .

Job done!

P.S. We're not checking any error codes, return values or doing anything, well, boring here. You're probably going to want to beef this out a little bit, but it illustrates the points. You know the rules.

Tags: OpenGL

Comments

Gravatar Test 30/11/2011 15:52

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent et urna dolor. Mauris sit amet mi vel felis feugiat egestas. Nunc et tortor in massa molestie condimentum vel sed nisl. Sed vitae mi est, sit amet pulvinar mi. Sed lacinia lectus eget odio consequat eget aliquet nunc consequat. Nam neque urna, ultricies eu posuere at, rhoncus id turpis. Donec pulvinar nulla eget justo fermentum vitae tempus felis dictum. Aliquam erat volutpat.

Sed at tellus non sem porttitor gravida in vel justo. Praesent sit amet purus odio. Duis lorem risus, bibendum quis dignissim quis, porttitor eu metus. Nulla rutrum mattis mi, quis bibendum ante commodo sit amet. Mauris sed massa ligula, congue pulvinar odio. Cras laoreet ultrices euismod. Donec congue convallis tincidunt. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec at enim in nisl malesuada commodo. Donec molestie malesuada est, blandit commodo elit dictum non. Cras est urna, dictum ac dignissim non, pretium nec sem. Nulla massa libero, tempor sit amet gravida at, blandit eget leo. Integer facilisis sagittis venenatis. Sed euismod elit vitae metus venenatis eget tincidunt dui convallis. In sed pretium sapien. Donec venenatis interdum nunc eget tempus.

Fusce imperdiet venenatis adipiscing. Sed rutrum tortor sit amet felis bibendum et porttitor ante sodales. Aliquam sed blandit metus. Vestibulum massa magna, vulputate sit amet dictum et, venenatis nec ipsum. Fusce quis nisi at tellus luctus euismod. Duis in lectus sapien, eget dictum dui. Integer ut turpis et purus elementum tincidunt. In lobortis, lorem ut mattis commodo, ante sem placerat odio, sit amet facilisis velit libero in felis. Aenean et lectus eget lorem tempor cursus. Integer tempor, arcu at semper congue, lectus justo pharetra tortor, quis imperdiet lorem lorem in mauris. Donec laoreet ullamcorper velit et tempor. Pellentesque ultricies suscipit ante, at fermentum lorem aliquam a. Donec condimentum, dui in consectetur fringilla, dui enim rutrum urna, vitae tincidunt nunc dolor a arcu. Nam commodo fringilla leo, et facilisis sapien convallis ut.

Gravatar asdasd 30/11/2011 15:55

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent et urna dolor. Mauris sit amet mi vel felis feugiat egestas. Nunc et tortor in massa molestie condimentum vel sed nisl. Sed vitae mi est, sit amet pulvinar mi. Sed lacinia lectus eget odio consequat eget aliquet nunc consequat. Nam neque urna, ultricies eu posuere at, rhoncus id turpis. Donec pulvinar nulla eget justo fermentum vitae tempus felis dictum. Aliquam erat volutpat.

Sed at tellus non sem porttitor gravida in vel justo. Praesent sit amet purus odio. Duis lorem risus, bibendum quis dignissim quis, porttitor eu metus. Nulla rutrum mattis mi, quis bibendum ante commodo sit amet. Mauris sed massa ligula, congue pulvinar odio. Cras laoreet ultrices euismod. Donec congue convallis tincidunt. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec at enim in nisl malesuada commodo. Donec molestie malesuada est, blandit commodo elit dictum non. Cras est urna, dictum ac dignissim non, pretium nec sem. Nulla massa libero, tempor sit amet gravida at, blandit eget leo. Integer facilisis sagittis venenatis. Sed euismod elit vitae metus venenatis eget tincidunt dui convallis. In sed pretium sapien. Donec venenatis interdum nunc eget tempus.

Fusce imperdiet venenatis adipiscing. Sed rutrum tortor sit amet felis bibendum et porttitor ante sodales. Aliquam sed blandit metus. Vestibulum massa magna, vulputate sit amet dictum et, venenatis nec ipsum. Fusce quis nisi at tellus luctus euismod. Duis in lectus sapien, eget dictum dui. Integer ut turpis et purus elementum tincidunt. In lobortis, lorem ut mattis commodo, ante sem placerat odio, sit amet facilisis velit libero in felis. Aenean et lectus eget lorem tempor cursus. Integer tempor, arcu at semper congue, lectus justo pharetra tortor, quis imperdiet lorem lorem in mauris. Donec laoreet ullamcorper velit et tempor. Pellentesque ultricies suscipit ante, at fermentum lorem aliquam a. Donec condimentum, dui in consectetur fringilla, dui enim rutrum urna, vitae tincidunt nunc dolor a arcu. Nam commodo fringilla leo, et facilisis sapien convallis ut.

Add Comment




Good luck with that

Please type the characters from the image above into the box below
or click here to get a new one


Submit