• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.

Archived

This topic is now archived and is closed to further replies.

drago

How To Load PNG files on a ddraw surface

1 post in this topic

Greets,

Can anyone tell me how to load PNG files onto a ddraw surface, i use MSVC6. Any help would be appreciated

0

Share this post


Link to post
Share on other sites
If you have any need to preserve the alpha component
of the pixel, you're best off skipping this and doing
it right the first time.

"This," being a test I did some time ago. I quickly
documented it and made sure it compiled, but other
than for loading a test PNG, I haven't tested it
further.

The code's pretty ugly in parts. Basically what
it does is load a PNG and make a DIB out of it with
MakeDIB(). Then, with MakeCompatibleSurface(), it
creates a DirectDraw surface and BitBlt()s that
DIB onto it.

A quick example of using it:

code:

MyPNG png;

// I'll just pretend my code is
// perfect and there's no need
// for error processing.

png.MakeDIB( "paddle.png" );
// Oh no! Global variables!
png.MakeCompatibleSurface( g_lpDD, &g_lpPaddleSprite );

png.DoCleanUp();

png.MakeDIB( "ball.png" );
png.MakeCompatibleSurface( g_lpDD,
&g_lpBallSprite );

PlayPong();



Using this, you don't have to worry about pixel format
conversion but, as I said, it might be better to
do that anyway. Try searching for information
on plotting 16bpp pixels in DirectDraw.

Note: this assumes you have libpng and zlib
already, so make sure you link to them.

code:

#ifndef __MY_PNG_INCLUDED__

#define __MY_PNG_INCLUDED__

#define WIN32_LEAN_AND_MEAN

#include
#include
#include LIBPNG_HEADER_LOCATION

// Number of bytes read by IsPNG() to
// check for the file's signature.

#define MYPNG_BYTES_TO_CHECK 4


// The following specifies the RGB colours of the default
// background. The class doesn't preserve alpha
// values. Instead it tries to combine them with
// the image's background or, if none is provided,
// creates a default background from these
// #defines. If you define MYPNG_STRIP_ALPHA,
// the alpha values are stripped instead of
// combined.

#undef MYPNG_STRIP_ALPHA

/* Specifies a black background. */
#define MYPNG_DEFAULT_BACKGROUND_RED 0
#define MYPNG_DEFAULT_BACKGROUND_GREEN 0
#define MYPNG_DEFAULT_BACKGROUND_BLUE 0

enum MYPNG_STATUS
{
MYPNG_OK,
MYPNGERR_FILECOULDNTBEACCESSED,
MYPNGERR_NOTAPNG,
MYPNGERR_NOTENOUGHMEMORY,
MYPNGERR_DIBNOTCREATED,
MYPNGERR_COULDNTCREATESURFACE,
MYPNGERR_COULDNTGETSRCCONTEXT,
MYPNGERR_COULDNTGETDESTCONTEXT,
MYPNGERR_COULDNTBLIT
};

class MyPNG
{
public:
MyPNG();
~MyPNG();

// Clears and resets all variables.

void DoCleanUp();

// Open a PNG file specified by 'filename', extract data
// from it and convert it into a device-independent
// bitmap. Returns: MYPNG_OK on success, or a
// MYPNGERR_something.

MYPNG_STATUS MakeDIB( LPCSTR filename );

// Create an off-screen DirectDraw surface and BitBlt()
// the DIB onto it. It takes as arguments a pointer
// to a DirectDraw object and a pointer to a DirectDraw
// surface pointer. Returns: MYPNG_OK on success,
// else a MYPNGERR_something.

MYPNG_STATUS MakeCompatibleSurface( LPDIRECTDRAW4 lpdd, LPDIRECTDRAWSURFACE4
*surface );

private:

/* Private function declarations. */

BOOL IsPNG(); // Determines if the open
// file is a PNG.

void Initialize(); // Resets all variables.

MYPNG_STATUS OpenFile( LPCSTR file ); // Opens a file and
// extracts information
// to the PNG structs.

BOOL ConvertToDIB(); // Sets up a DIB and writes
// image data into it.

BOOL CloseFile(); // Closes an open file and destroys
// created PNG structs.

/* Private variable declarations. */

FILE *m_pFile; // Currently open file.
HBITMAP m_hbm; // Handle to a generated DIB.
png_structp m_pStruct; // Currently open PNG file struct.
png_infop m_pInfo; // Currently open PNG info struct.
png_uint_32 m_Width; // Width of image.
png_uint_32 m_Height; // Height of image.

};

#endif


#include "mypng.h"

MyPNG::MyPNG()
{
Initialize();
} /* MyPNG() */


MyPNG::~MyPNG()
{
DoCleanUp();
} /* MyPNG() */


void MyPNG::Initialize()
{

m_Width = 0;
m_Height = 0;
m_hbm = NULL;
m_pFile = NULL;
m_pInfo = NULL;
m_pStruct = NULL;

} /* Initialize() */


BOOL MyPNG::CloseFile()
{

if( m_pStruct != NULL | | m_pInfo != NULL )
{
// Destroy created PNG structs.
png_destroy_read_struct( &m_pStruct, &m_pInfo, NULL );
m_pStruct = NULL;
m_pInfo = NULL;
}

if( m_pFile != NULL )
{
// Close open file.
fclose( m_pFile );
m_pFile = NULL;
}
else
{
return FALSE;
}

return TRUE;

} /* CloseFile() */


void MyPNG: oCleanUp()
{
CloseFile();

if( m_hbm )
{
// Does deleting an object also free the memory
// allocated to the bitmap pointer? If not, this
// causes a serious memory leak because I'm too
// lazy to check it out and free it myself. :P
DeleteObject( m_hbm );
m_hbm = NULL;
}

Initialize();

} /* DoCleanUp() */


BOOL MyPNG::IsPNG()
{
unsigned char buf[ MYPNG_BYTES_TO_CHECK ];

if( m_pFile == NULL )
{
// No file currently open.
return FALSE;
}

if( fread( buf, sizeof( unsigned char ), MYPNG_BYTES_TO_CHECK,
m_pFile ) != MYPNG_BYTES_TO_CHECK )
{
return FALSE;
}

if( png_sig_cmp( buf, ( png_size_t )0, MYPNG_BYTES_TO_CHECK ) == 1 )
{
// File signature match failed. Not a PNG file.
return FALSE;
}

return TRUE;

} /* IsPNG */


MYPNG_STATUS MyPNG::MakeDIB( LPCSTR filename )
{
MYPNG_STATUS retval;

// First open the file and extract header data.
retval = OpenFile( filename );

if( retval != MYPNG_OK )
{
DoCleanUp();
return retval;
}

if( !ConvertToDIB() )
{
DoCleanUp();
return MYPNGERR_NOTENOUGHMEMORY;
}

// The DIB can now be blitted onto a compatible
// surface.

return MYPNG_OK;
} /* MakeDIB() */


MYPNG_STATUS MyPNG::OpenFile( LPCSTR filename )
{

/* Note that this is largely a copy of the
example file included in libpng. */

#ifndef MYPNG_STRIP_ALPHA
png_color_16 my_background, *image_background;
#endif

if( m_pFile != NULL | | m_hbm != NULL )
{
// File's already loaded.
DoCleanUp();
Initialize();
}

// Open the proposed file for reading.
m_pFile = fopen( filename, "rb" );

if( m_pFile == NULL )
{
// Couldn't access the file.
return MYPNGERR_FILECOULDNTBEACCESSED;
}

// Check if the file's a PNG file.
if( !this->IsPNG() )
{
return MYPNGERR_NOTAPNG;
}

// Create the PNG stuctures.
m_pStruct = png_create_read_struct( PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL );

if ( m_pStruct == NULL )
{
// Oh dear.
return MYPNGERR_NOTENOUGHMEMORY;
}

m_pInfo = png_create_info_struct( m_pStruct );

if( m_pInfo == NULL )
{
// Oh dear oh dear.
return MYPNGERR_NOTENOUGHMEMORY;
}

// Used for default error handling. Er, I think. :-/
if( setjmp( m_pStruct->jmpbuf ) )
{
return MYPNGERR_NOTENOUGHMEMORY;
}

// We've read some of the signature bytes, so let's let them
// know.
png_set_sig_bytes( m_pStruct, MYPNG_BYTES_TO_CHECK );

// Initialize default I/O routines.
png_init_io( m_pStruct, m_pFile );

// Read information into the info structure.
png_read_info( m_pStruct, m_pInfo );

// Strip 16 bit/channel files down to 8 bits/channel.
png_set_strip_16( m_pStruct );

// Expand palette and grayscale information to RGB triplets.
switch( m_pInfo->color_type )
{
case PNG_COLOR_TYPE_PALETTE:
case PNG_COLOR_TYPE_GRAY:
png_set_expand( m_pStruct );
break;
}

// Expand packed colour information to their own
// bytes.
switch( m_pInfo->bit_depth )
{
case 1:
case 2:
case 4:
png_set_packing( m_pStruct );
break;
}

// Swap the R and B bits. This is required for Windows DIBs.
png_set_bgr( m_pStruct );

if( png_get_valid( m_pStruct, m_pInfo, PNG_INFO_tRNS ) )
{
png_set_expand( m_pStruct );
}

#ifdef MYPNG_STRIP_ALPHA
// Strip alpha values (not recommended).
png_set_strip_alpha( png_ptr );
#else
// Combine alpha values with the background.
if( png_get_bKGD( m_pStruct, m_pInfo, &image_background ) )
{
// Image had its own background.
png_set_background( m_pStruct, image_background,
PNG_BACKGROUND_GAMMA_FILE, 1, 1.0 );
}
else
{
// No background provided. We'll make one.
my_background.red = MYPNG_DEFAULT_BACKGROUND_RED;
my_background.blue = MYPNG_DEFAULT_BACKGROUND_BLUE;
my_background.green = MYPNG_DEFAULT_BACKGROUND_GREEN;
png_set_background( m_pStruct, &my_background,
PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0 );
}
#endif

// Finally update the info struct.
png_read_update_info( m_pStruct, m_pInfo );

return MYPNG_OK;

} /* OpenFile() */


BOOL MyPNG::ConvertToDIB()
{
// PNG image's scanline length in bytes.
png_uint_32 rowsize;
// The future DIB's scanline length. DIBs are
// LONG-aligned with the unused bytes set to 0.
png_uint_32 realrowsize;
// Counter.
png_uint_32 row;
BITMAPINFOHEADER bmih;
// Pointer returned by CreateDIBSection() where
// we can write our data.
png_bytep OurDIB;

if( m_pStruct == NULL | | m_pInfo == NULL | | m_pFile == NULL )
{
// No file open. :-/
return FALSE;
}

// Get the scanline length.
rowsize = png_get_rowbytes( m_pStruct, m_pInfo );
realrowsize = rowsize + ( rowsize % sizeof( LONG ) );

// Fill in the BITMAPINFOHEADER
ZeroMemory( &bmih, sizeof( bmih ) );
bmih.biSize = sizeof( bmih );
bmih.biWidth = m_pInfo->width;
// DIB only displays top->down if the height is negative.
bmih.biHeight = -( int )m_pInfo->height;
bmih.biPlanes = 1;
bmih.biBitCount = m_pInfo->bit_depth * m_pInfo->channels;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 0;
bmih.biYPelsPerMeter = 0;
bmih.biClrUsed = 0;
bmih.biClrImportant = 0;

// Create a DIB we can write to from the info in the header.
m_hbm = CreateDIBSection( NULL, ( BITMAPINFO * )&bmih, DIB_RGB_COLORS,
( void ** )&OurDIB, NULL, 0 );

if ( m_hbm == NULL )
{
// Well we screwed up somewhere.
return FALSE;
}

// Initialize the bitmap with zeros. Yeah, I did this
// just because unused bytes are set to zero,
// and this is a HIDEOUS way to do it. I just don't
// feel like rewriting it for the sake of this post.
ZeroMemory( OurDIB, m_pInfo->height * realrowsize );

m_Width = m_pInfo->width;
m_Height = m_pInfo->height;

// Read (write) one row at a time.
for( row = 0; row < m_pInfo->height; row ++ )
{
png_read_rows( m_pStruct, &OurDIB, NULL, 1 );
OurDIB += realrowsize;
}

// Finish reading.
png_read_end( m_pStruct, m_pInfo );

return TRUE;

} /* MakeDIB() */


MYPNG_STATUS MyPNG::MakeCompatibleSurface( LPDIRECTDRAW4 lp_dd, LPDIRECTDRAWSURFACE4 *lp_surface )
{
HRESULT retval;
HDC hdc_src, hdc_dest;
DDSURFACEDESC2 ddsd;
LPDIRECTDRAWSURFACE4 surf;


if( m_hbm == NULL )
{
// Oops! No DIB to create from.
return MYPNGERR_DIBNOTCREATED;
}

// Set up the surface parameters.
ZeroMemory( &ddsd, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
ddsd.dwWidth = m_Width;
ddsd.dwHeight = m_Height;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;

retval = lp_dd->CreateSurface( &ddsd, &surf, NULL );

if( FAILED( retval ) )
{
return MYPNGERR_COULDNTCREATESURFACE;
}

// Create a device context to blit from.

hdc_src = CreateCompatibleDC( NULL );

if( !hdc_src )
{
surf->Release();
surf = NULL;
return MYPNGERR_COULDNTGETSRCCONTEXT;
}

SelectObject( hdc_src, m_hbm );

// Get the context to blit onto.

surf->GetDC( &hdc_dest );

if( !hdc_dest )
{
DeleteDC( hdc_src );
surf->Release();
surf = NULL;
return MYPNGERR_COULDNTGETDESTCONTEXT;
}

if( !BitBlt( hdc_dest, 0, 0, m_Width, m_Height,
hdc_src, 0, 0, SRCCOPY ) )
{
DeleteDC( hdc_src );
surf->ReleaseDC( hdc_dest );
surf->Release();
surf = NULL;
return MYPNGERR_COULDNTBLIT;
}

DeleteDC( hdc_src );
surf->ReleaseDC( hdc_dest );

*lp_surface = surf;

return MYPNG_OK;

} /* MakeCompatibleSurface() */



[This message has been edited by foo (edited August 08, 1999).]

[This message has been edited by foo (edited August 08, 1999).]

[This message has been edited by foo (edited August 08, 1999).]

0

Share this post


Link to post
Share on other sites