Everyone who has used the Win32 API knows that its not exactly the friendliest thing to work with. It has a lot of defines and macros that can make life difficult, and every time I need to use it, I find myself relearning everything from scratch.
Because of this repeated tedium, I decided to post a complete code file, showing how to use the Win32 API with OpenGL and Vertex Buffers in a nice, class-oriented way. You can find it in the code section of the site, or go straight to it:
Win32, OpenGL, and Drawing Vertex Buffers
Using the Win32 API with OpenGL and Vertex Buffers
Posted on March 28, 2012
Basic LibPNG usage with C++ and OpenGL
Posted on March 4, 2012
I am using LibPNG and Zlib in my game engine. After much frustration, I was finally able to get it to work. The following is my LoadImage function:
There are some premade things in this snippet. For one, the GenerateImage function just creates a blank, solid color image instead of a loaded PNG, in the case of an error. Engine::console is just a singleton that outputs to some error stream, usually a file. Finally, image_data is an unsigned char array. I allocated 4 bytes per pixel so that the buffer is always RGB.
If you're getting crashes with LibPNG, make sure you are linking the right library: compile LibPNG with the same compiler options as your project. This is due to the fact that LibPNG uses some internal functions to read from a file pointer.
Next time I might just use stb_image.
void Image::LoadImage( const char *filename ) { // Open up the file as a binary FILE *file_pointer = fopen( filename, "rb"); if( file_pointer == 0 ) { Engine::console << "LoadImage failed: file '" << filename << "'does not exist." << std::endl; // The file does not exist. Create a false image that is just red. GenerateImage( 64, 64, 255, 128, 128, 255 ); return; } // First we check the header, stored in the first 8 bytes of the file char header[8]; fread(header, 1, 8, file_pointer ); // png_sig_cmp will return 0 if the file read is not a PNG if (png_sig_cmp( (png_const_bytep) header, 0, 8) != 0 ) { Engine::console << "LoadImage failed: file '" << filename << "' is not a PNG." << std::endl; GenerateImage( 64, 64, 255, 128, 128, 255 ); fclose( file_pointer ); return; } // Initialize the two structures that will represent the PNG file. png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); png_infop info_ptr = png_create_info_struct( png_ptr ); // This is an old C way to handle errors, and franky is not very good because it // can jump over class destructors if you're not careful. if ( setjmp( png_jmpbuf(png_ptr) ) ) { Engine::console << "LoadImage failed: file '" << filename << "' caused LibPNG to trigger an error response." << std::endl; GenerateImage( 64, 64, 255, 128, 128, 255 ); // This block is called if there was an error reading the file png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if ( file_pointer ) { fclose( file_pointer); } return; } // Initialize the reading of the file, skip the 8 signature bytes, and then read the file information png_init_io( png_ptr, file_pointer ); png_set_sig_bytes( png_ptr, 8 ); png_read_info( png_ptr, info_ptr ); // Get the information, including image width, height, bit depth and color type. // Bit depth is the number of bits per channel, a channel being red, green, blue, or alpha. // Typically bit depth will be 8, meaning each channel gets 1 byte. image_width = png_get_image_width ( png_ptr, info_ptr ); image_height = png_get_image_height( png_ptr, info_ptr ); int bit_depth = png_get_bit_depth( png_ptr, info_ptr ); int color_type = png_get_color_type( png_ptr, info_ptr ); int channels = png_get_channels(png_ptr, info_ptr); // Allocate the data for the texture using its width and height. Reserve 4 bytes for RGBA pixels. image_data = new unsigned char[ image_width * image_height * 4 ]; // Read the pixel data from the PNG into an array of rows. // First allocate memory for row structure. png_bytepp row_pointers = new png_bytep[image_height]; // Then go through each row, and allocate space for that row. for ( int i = 0; i < image_height; i++) { row_pointers[i] = new png_byte[ image_width * channels ]; } // Finally, read the image into the row structure we just made. png_read_image(png_ptr, row_pointers); // Copy the image data into the image class's image_data, which // must be an array of RGBA pixels. for( int y = 0; y < image_height; y++ ) { // Get one row of pixels for the row structure png_bytep row = row_pointers[y]; for( int x = 0; x < image_width; x++ ) { // Our data is stored in image_data, and the PNG pixels are stored in row image_data[ y * image_width * 4 + x*4 + 0 ] = row[ x * channels + 0 ]; image_data[ y * image_width * 4 + x*4 + 1 ] = row[ x * channels + 1 ]; image_data[ y * image_width * 4 + x*4 + 2 ] = row[ x * channels + 2 ]; // If there is an alpha channel, be sure to copy it if( channels == 4 ) { image_data[ y * image_width + x*4 + 3 ] = row[ x * channels + 3 ]; } else { image_data[ y * image_width + x*4 + 3 ] = 255; } } } // Free all memory that we used to avoid leaks, starting with each individual row for ( int i = 0; i < image_height; i++) { delete [] row_pointers[i]; } // And finally, delete the row structure delete [] row_pointers; // Final PNG closing things png_destroy_read_struct( &png_ptr, &info_ptr, NULL ); // Close our file pointer fclose( file_pointer ); }
There are some premade things in this snippet. For one, the GenerateImage function just creates a blank, solid color image instead of a loaded PNG, in the case of an error. Engine::console is just a singleton that outputs to some error stream, usually a file. Finally, image_data is an unsigned char array. I allocated 4 bytes per pixel so that the buffer is always RGB.
If you're getting crashes with LibPNG, make sure you are linking the right library: compile LibPNG with the same compiler options as your project. This is due to the fact that LibPNG uses some internal functions to read from a file pointer.
Next time I might just use stb_image.
Python Decorators are Functions that Return Functions
Posted on September 13, 2011
If you've ever seen this kind of syntax and been bewildered:
Then you are not alone. This is an example of using decorators in python. The @ indicates that the function will be "decorated" with "decorator." What is decorator exactly?
It's a function that takes a function as an argument and returns a function.
You have just made a decorator. The function "function" is now whatever "decorator" returns, which is in this case math.sin. Now when you run:
You will really be calling math.sin( 5 ), because that's what your decorator returned. Of course, this is a silly example because it does not make use of your function. Let's make one that does.
Don't be thrown off by the fact that I defined a function within a function. This is just fine by the Python compiler.
What's happening here is that I defined a function called new_function that takes a single argument. It calls your function, giving it the value x, and then adds 5 to it and returns it. At the end of the decorator function, new_function is returned. Now when you call
You will see 15. What you really called was the function new_function, with an argument 10. That's because the function decorator returned new_function, which runs your old function and adds 5 to it. So the entire code would be this:
I hope that was a good explanation for some tricky Python stuff.
@decorator def function( x ): return x
Then you are not alone. This is an example of using decorators in python. The @ indicates that the function will be "decorated" with "decorator." What is decorator exactly?
It's a function that takes a function as an argument and returns a function.
def decorator( your_function ): return math.sin @decorator def function( x ): return x
You have just made a decorator. The function "function" is now whatever "decorator" returns, which is in this case math.sin. Now when you run:
print function( 5 )
You will really be calling math.sin( 5 ), because that's what your decorator returned. Of course, this is a silly example because it does not make use of your function. Let's make one that does.
def decorator( your_function ): def new_function( x ): return 5 + your_function( x ) return new_function @decorator def function( x ): return x
Don't be thrown off by the fact that I defined a function within a function. This is just fine by the Python compiler.
What's happening here is that I defined a function called new_function that takes a single argument. It calls your function, giving it the value x, and then adds 5 to it and returns it. At the end of the decorator function, new_function is returned. Now when you call
print function( 10 )
You will see 15. What you really called was the function new_function, with an argument 10. That's because the function decorator returned new_function, which runs your old function and adds 5 to it. So the entire code would be this:
def decorator( your_function ): def new_function( x ): return 5 + your_function( x ) return new_function @decorator def function( x ): return x print function(5)
I hope that was a good explanation for some tricky Python stuff.
