Выбрать главу

bool keys[256]; // Array Used For The Keyboard Routine

bool active=TRUE; // Window Active Flag Set To TRUE By Default

bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default

DEVMODE DMsaved; // Saves The Previous Screen Settings (NEW)

GLfloat xrot; // X Rotation

GLfloat yrot; // Y Rotation

GLfloat zrot; // Z Rotation

GLuint texture[1]; // Storage For 1 Texture

Now for the fun stuff. We create a structure called TEXTURE_IMAGE. The structure contains information about our images width, height, and format (bytes per pixel). data is a pointer to unsigned char. Later on data will point to our image data.

typedef struct Texture_Image {

 int width; // Width Of Image In Pixels

 int height; // Height Of Image In Pixels

 int format; // Number Of Bytes Per Pixel

 unsigned char *data; // Texture Data

} TEXTURE_IMAGE;

We then create a pointer called P_TEXTURE_IMAGE to the TEXTURE_IMAGE data type. The variables t1 and t2 are of type P_TEXTURE_IMAGE where P_TEXTURE_IMAGE is a redefined type of pointer to TEXTURE_IMAGE.

typedef TEXTURE_IMAGE* P_TEXTURE_IMAGE; // A Pointer To The Texture Image Data Type

P_TEXTURE_IMAGE t1; // Pointer To The Texture Image Data Type

P_TEXTURE_IMAGE t2; // Pointer To The Texture Image Data Type

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc

Below is the code to allocate memory for a texture. When we call this code, we pass it the width, height and bytes per pixel information of the image we plan to load. ti is a pointer to our TEXTURE_IMAGE data type. It's given a NULL value. c is a pointer to unsigned char, it is also set to NULL.

// Allocate An Image Structure And Inside Allocate Its Memory Requirements

P_TEXTURE_IMAGE AllocateTextureBuffer(GLint w, GLint h, GLint f) {

 P_TEXTURE_IMAGE ti=NULL; // Pointer To Image Struct

 unsigned char *c=NULL; // Pointer To Block Memory For Image

Here is where we allocate the memory for our image structure. If everything goes well, ti will point to the allocated memory.

After allocating the memory, and checking to make sure ti is not equal to NULL, we can fill the structure with the image attributes. First we set the width (w), then the height (h) and lastly the format (f). Keep in mind format is bytes per pixel.

 ti = (P_TEXTURE_IMAGE)malloc(sizeof(TEXTURE_IMAGE)); // One Image Struct Please

 if (ti != NULL) {

  ti->width = w; // Set Width

  ti->height = h; // Set Height

  ti->format = f; // Set Format

Now we need to allocate memory for the actual image data. The calculation is easy! We multiply the width of the image (w) by the height of the image (h) then multiply by the format (f – bytes per pixel).

  c = (unsigned char *)malloc(w * h * f);

We check to see if everything went ok. If the value in c is not equal to NULL we set the data variable in our structure to point to the newly allocated memory.

If there was a problem, we pop up an error message on the screen letting the user know that the program was unable to allocate memory for the texture buffer. NULL is returned.

  if (c != NULL) {

   ti->data = c;

  } else {

   MessageBox(NULL, "Could Not Allocate Memory For A Texture Buffer", "BUFFER ERROR", MB_OK | MB_ICONINFORMATION);

   return NULL;

  }

 }

If anything went wrong when we were trying to allocate memory for our image structure, the code below would pop up an error message and return NULL.

If there were no problems, we return ti which is a pointer to our newly allocated image structure. Whew… Hope that all made sense.

 else {

  MessageBox(NULL, "Could Not Allocate An Image Structure", "IMAGE STRUCTURE ERROR", MB_OK | MB_ICONINFORMATION);

  return NULL;

 }

 return ti; // Return Pointer To Image Struct

}

When it comes time to release the memory, the code below will deallocate the texture buffer and then free the image structure. t is a pointer to the TEXTURE_IMAGE data structure we want to deallocate.

// Free Up The Image Data

void DeallocateTexture( P_TEXTURE_IMAGE t ) {

 if(t) {

  if(t->data) {

   free(t->data); // Free Its Image Buffer

  }

  free(t); // Free Itself

 }

}

Now we read in our .RAW image. We pass the filename and a pointer to the image structure we want to load the image into. We set up our misc variables, and then calculate the size of a row. We figure out the size of a row by multiplying the width of our image by the format (bytes per pixel). So if the image was 256 pixels wide and there were 4 bytes per pixel, the width of a row would be 1024 bytes. We store the width of a row in stride.

We set up a pointer (p), and then attempt to open the file.

// Read A .RAW File In To The Allocated Image Buffer Using data In The Image Structure Header.

// Flip The Image Top To Bottom. Returns 0 For Failure Of Read, Or Number Of Bytes Read.

int ReadTextureData(char *filename, P_TEXTURE_IMAGE buffer) {

 FILE *f;

 int i,j,k,done=0;

 int stride = buffer->width * buffer->format; // Size Of A Row (Width * Bytes Per Pixel)

 unsigned char *p = NULL;

 f = fopen(filename, "rb"); // Open "filename" For Reading Bytes

 if (f != NULL ) // If File Exists

 {

If the file exists, we set up the loops to read in our texture. i starts at the bottom of the image and moves up a line at a time. We start at the bottom so that the image is flipped the right way. .RAW images are stored upside down. We have to set our pointer now so that the data is loaded into the proper spot in the image buffer. Each time we move up a line (i is decreased) we set the pointer to the start of the new line. data is where our image buffer starts, and to move an entire line at a time in the buffer, multiply i by stride. Remember that stride is the length of a line in bytes, and i is the current line. So by multiplying the two, we move an entire line at a time.

The j loop moves from left (0) to right (width of line in pixels, not bytes).

  for(i = buffer->height-1; i>= 0 ; i--) // Loop Through Height (Bottoms Up – Flip Image)

  {

   p = buffer->data + (i * stride );

   for (j = 0; j < buffer->width ; j++ ) // Loop Through Width

   {

The k loop reads in our bytes per pixel. So if format (bytes per pixel) is 4, k loops from 0 to 2 which is bytes per pixel minus one (format-1). The reason we subtract one is because most raw images don't have an alpha value. We want to make the 4th byte our alpha value, and we want to set the alpha value manually.

Notice in the loop we also increase the pointer (p) and a variable called done. More about done later.