mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-11 22:54:34 +00:00
615 lines
18 KiB
C++
615 lines
18 KiB
C++
//---------------------------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------------------------
|
|
//
|
|
// MNGView Sample Application for VC6:
|
|
// Loads all MNG/JNG/PNG Files LibMNG can do
|
|
// Can save a single Frame to PNG Format.
|
|
//
|
|
// This code is public domain.
|
|
// Created by Nikolaus Brennig, November 14th, 2000.
|
|
// virtualnik@nol.at
|
|
// http://cust.nol.at/ppee
|
|
//
|
|
// Tab: 4
|
|
//
|
|
//---------------------------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------------------------
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include "Main.h"
|
|
#include <libmng.h>
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// VARS:
|
|
//---------------------------------------------------------------------------------------------
|
|
typedef struct
|
|
{
|
|
FILE *file;
|
|
LPSTR filename;
|
|
mng_uint32 delay;
|
|
} mngstuff;
|
|
|
|
int lineWidth;
|
|
BYTE *mngdestbuffer;
|
|
mngstuff *mymngstuff;
|
|
mng_handle Curmng;
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
//---------------------------------------------------------------------------------------------
|
|
// callbacks for the mng decoder:
|
|
//---------------------------------------------------------------------------------------------
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// memory allocation; data must be zeroed
|
|
//---------------------------------------------------------------------------------------------
|
|
mng_ptr mymngalloc( mng_uint32 size )
|
|
{
|
|
return (mng_ptr)calloc(1, size);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// memory deallocation
|
|
//---------------------------------------------------------------------------------------------
|
|
void mymngfree(mng_ptr p, mng_uint32 size)
|
|
{
|
|
free(p);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// Stream open:
|
|
//---------------------------------------------------------------------------------------------
|
|
mng_bool mymngopenstream(mng_handle mng)
|
|
{
|
|
mngstuff *mymng;
|
|
|
|
// look up our stream struct
|
|
mymng = (mngstuff*)mng_get_userdata(mng);
|
|
|
|
// open the file
|
|
mymng->file = fopen( mymng->filename, "rb" );
|
|
if( mymng->file == NULL )
|
|
{
|
|
char temp[100];
|
|
sprintf( temp, "Unable to open File: %s", mymng->filename );
|
|
Warning( temp );
|
|
return MNG_FALSE;
|
|
}
|
|
|
|
return MNG_TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// Stream open for Writing:
|
|
//---------------------------------------------------------------------------------------------
|
|
mng_bool mymngopenstreamwrite(mng_handle mng)
|
|
{
|
|
mngstuff *mymng;
|
|
|
|
// look up our stream struct
|
|
mymng = (mngstuff*)mng_get_userdata(mng);
|
|
|
|
// open the file
|
|
mymng->file = fopen( mymng->filename, "wb" );
|
|
if( mymng->file == NULL )
|
|
{
|
|
Warning( "unable to open file!" );
|
|
return MNG_FALSE;
|
|
}
|
|
|
|
return MNG_TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// Stream close:
|
|
//---------------------------------------------------------------------------------------------
|
|
mng_bool mymngclosestream(mng_handle mng)
|
|
{
|
|
return MNG_TRUE; // We close the file ourself, mng_cleanup doesnt seem to do it...
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// feed data to the decoder
|
|
//---------------------------------------------------------------------------------------------
|
|
mng_bool mymngreadstream( mng_handle mng, mng_ptr buffer, mng_uint32 size, mng_uint32 *bytesread )
|
|
{
|
|
mngstuff *mymng;
|
|
|
|
// look up our stream struct
|
|
mymng = (mngstuff*)mng_get_userdata(mng);
|
|
|
|
// read the requested amount of data from the file
|
|
*bytesread = fread( buffer, sizeof(BYTE), size, mymng->file );
|
|
|
|
return MNG_TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// the header's been read. set up the display stuff
|
|
//---------------------------------------------------------------------------------------------
|
|
mng_bool mymngprocessheader( mng_handle mng, mng_uint32 width, mng_uint32 height )
|
|
{
|
|
// Store values:
|
|
W = width; H = height;
|
|
Bits = 24;
|
|
lineWidth = ((((W * Bits) + 31) >> 5) << 2);
|
|
|
|
// Create decoderbuffer:
|
|
mngdestbuffer = new BYTE[lineWidth*H];
|
|
if( mngdestbuffer == 0 ) Warning( "Out of Memory!" );
|
|
|
|
// Create the MemoryBitmap now, we store there the image...
|
|
if( DefaultMemImage ) SelectObject( MemDC, DefaultMemImage );
|
|
if( MemDC ) DeleteDC( MemDC );
|
|
if( MemImage ) DeleteObject( MemImage );
|
|
hdc = GetDC( hPicWin );
|
|
MemDC = CreateCompatibleDC( 0 );
|
|
MemImage = CreateCompatibleBitmap( hdc, W, H );
|
|
DefaultMemImage = (HBITMAP)SelectObject( MemDC, MemImage );
|
|
ReleaseDC( hPicWin, hdc );
|
|
|
|
// Set output style:
|
|
mng_set_canvasstyle( mng, MNG_CANVAS_BGR8 );
|
|
|
|
return MNG_TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// return a row pointer for the decoder to fill
|
|
//---------------------------------------------------------------------------------------------
|
|
mng_ptr mymnggetcanvasline( mng_handle mng, mng_uint32 line )
|
|
{
|
|
return (mng_ptr)(mngdestbuffer + (lineWidth*(H-1-line)));
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// timer
|
|
//---------------------------------------------------------------------------------------------
|
|
mng_uint32 mymnggetticks(mng_handle mng)
|
|
{
|
|
return (mng_uint32)GetTickCount();
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// Refresh:
|
|
//---------------------------------------------------------------------------------------------
|
|
mng_bool mymngrefresh( mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h )
|
|
{
|
|
PBITMAPINFO bmpi = (PBITMAPINFO)LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));
|
|
bmpi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
bmpi->bmiHeader.biWidth = W;
|
|
bmpi->bmiHeader.biHeight = H;
|
|
bmpi->bmiHeader.biPlanes = 1;
|
|
bmpi->bmiHeader.biCompression = BI_RGB;
|
|
bmpi->bmiHeader.biBitCount = Bits;
|
|
bmpi->bmiHeader.biSizeImage = 0;
|
|
bmpi->bmiHeader.biClrUsed = 0;
|
|
bmpi->bmiHeader.biClrImportant = 0;
|
|
|
|
// Now blt the Image onto our MemDC...
|
|
StretchDIBits( MemDC, 0, 0, W, H, 0, 0, W, H, mngdestbuffer, bmpi, 0, SRCCOPY );
|
|
LocalFree((PBITMAPINFO)bmpi);
|
|
|
|
return MNG_TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// interframe delay callback
|
|
//---------------------------------------------------------------------------------------------
|
|
mng_bool mymngsettimer(mng_handle mng, mng_uint32 msecs)
|
|
{
|
|
mngstuff *mymng;
|
|
|
|
// look up our stream struct
|
|
mymng = (mngstuff*)mng_get_userdata(mng);
|
|
|
|
// set the timer for when the decoder wants to be woken
|
|
mymng->delay = msecs;
|
|
|
|
return MNG_TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// Error Callback;
|
|
//---------------------------------------------------------------------------------------------
|
|
mng_bool mymngerror(
|
|
mng_handle mng, mng_int32 code, mng_int8 severity,
|
|
mng_chunkid chunktype, mng_uint32 chunkseq,
|
|
mng_int32 extra1, mng_int32 extra2, mng_pchar text
|
|
)
|
|
{
|
|
char chunk[5];
|
|
|
|
// pull out the chuck type as a string
|
|
// FIXME: does this assume unsigned char?
|
|
chunk[0] = (char)((chunktype >> 24) & 0xFF);
|
|
chunk[1] = (char)((chunktype >> 16) & 0xFF);
|
|
chunk[2] = (char)((chunktype >> 8) & 0xFF);
|
|
chunk[3] = (char)((chunktype ) & 0xFF);
|
|
chunk[4] = '\0';
|
|
|
|
// output the error:
|
|
char temp[1000];
|
|
sprintf( temp, "error playing chunk %s (%d)", chunk, chunkseq );
|
|
Warning( temp );
|
|
|
|
// No need for anymore decoding:
|
|
KillTimer( hPicWin, 2 );
|
|
|
|
// error occured;
|
|
return MNG_FALSE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// Load a MNG/JNG/PNG file:
|
|
//---------------------------------------------------------------------------------------------
|
|
VOID LoadMNG( LPSTR Filename, HWND hwnd, HDC hdc )
|
|
{
|
|
// allocate our stream data structure
|
|
mymngstuff = (mngstuff*)calloc(1, sizeof(*mymngstuff));
|
|
if( mymngstuff == NULL )
|
|
{
|
|
Warning( "Unable to allocate MNG struct!" );
|
|
return;
|
|
}
|
|
|
|
// pass the name of the file we want to play
|
|
mymngstuff->filename = Filename;
|
|
|
|
// set up the mng decoder for our stream
|
|
Curmng = mng_initialize(mymngstuff, mymngalloc, mymngfree, MNG_NULL);
|
|
if(Curmng == MNG_NULL)
|
|
{
|
|
free(mymngstuff);
|
|
Warning( "MNG Init Error!" );
|
|
return;
|
|
}
|
|
|
|
// No need to store chunks:
|
|
mng_set_storechunks(Curmng, MNG_FALSE);
|
|
|
|
// Set the colorprofile, lcms uses this:
|
|
mng_set_srgb( Curmng, MNG_TRUE );
|
|
char DestDir[2048];
|
|
SearchPath( NULL, "MNGVIEW.EXE", NULL, sizeof(DestDir), DestDir, NULL );
|
|
lstrcpyn( DestDir, DestDir, lstrlen(DestDir)-lstrlen("MNGVIEW.EXE") );
|
|
catpath( DestDir, "sRGB.icm" );
|
|
FILE *RGBfile = fopen( DestDir, "rb" );
|
|
if( RGBfile == 0 )
|
|
{
|
|
mng_cleanup(&Curmng);
|
|
free(mymngstuff);
|
|
Warning( "Need file \"sRGB.icm\" !" );
|
|
return;
|
|
}
|
|
fclose(RGBfile);
|
|
mng_set_outputprofile(Curmng, DestDir);
|
|
|
|
// Set white as background color:
|
|
WORD Red = (255 << 8) + 255;
|
|
WORD Green = (255 << 8) + 255;
|
|
WORD Blue = (255 << 8) + 255;
|
|
mng_set_bgcolor( Curmng, Red, Green, Blue );
|
|
|
|
// If PNG Background is available, use it:
|
|
mng_set_usebkgd( Curmng, MNG_TRUE );
|
|
|
|
// set the callbacks
|
|
mng_setcb_errorproc(Curmng, mymngerror);
|
|
mng_setcb_openstream(Curmng, mymngopenstream);
|
|
mng_setcb_closestream(Curmng, mymngclosestream);
|
|
mng_setcb_readdata(Curmng, mymngreadstream);
|
|
mng_setcb_gettickcount(Curmng, mymnggetticks);
|
|
mng_setcb_settimer(Curmng, mymngsettimer);
|
|
mng_setcb_processheader(Curmng, mymngprocessheader);
|
|
mng_setcb_getcanvasline(Curmng, mymnggetcanvasline);
|
|
mng_setcb_refresh(Curmng, mymngrefresh);
|
|
|
|
// Read the stuff:
|
|
mng_readdisplay(Curmng);
|
|
|
|
AnimFile.CurFrame = mng_get_layercount( Curmng );
|
|
AnimFile.MaxFrame = mng_get_framecount( Curmng );
|
|
AnimFile.isAnimation = 1;
|
|
AnimFile.Delay = mymngstuff->delay;
|
|
|
|
// Start the whole thing:
|
|
SetTimer( hPicWin, 2, mymngstuff->delay, 0 );
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// Called when loading a new file or Appquit:
|
|
//---------------------------------------------------------------------------------------------
|
|
void CleanUpMNG()
|
|
{
|
|
KillTimer( hPicWin, 2 );
|
|
mng_cleanup(&Curmng);
|
|
fclose( mymngstuff->file );
|
|
free(mymngstuff);
|
|
delete [] mngdestbuffer;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// Called when timer says next frame/layer/update is needed:
|
|
//---------------------------------------------------------------------------------------------
|
|
void UpdateMNG()
|
|
{
|
|
mymngstuff->delay = 0;
|
|
if( MNG_NEEDTIMERWAIT == mng_display_resume(Curmng) )
|
|
{
|
|
KillTimer( hPicWin, 2 );
|
|
SetTimer( hPicWin, 2, mymngstuff->delay, 0 );
|
|
}
|
|
else
|
|
{
|
|
CleanUpMNG();
|
|
AnimFile.CurFrame = -1;
|
|
AnimFile.MaxFrame = -1;
|
|
AnimFile.isAnimation = -1;
|
|
AnimFile.Delay = -1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
//---------------------------------------------------------------------------------------------
|
|
// MNG WRITING STUFF:
|
|
//---------------------------------------------------------------------------------------------
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
int OffsetX=0,OffsetY=0,OffsetW=0,OffsetH=0;
|
|
BYTE *srcbuffer=0, *tmpbuffer;
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// Callback for writing data:
|
|
//---------------------------------------------------------------------------------------------
|
|
mng_bool mymngwritedata( mng_handle hMNG, mng_ptr pBuf, mng_uint32 iSize, mng_uint32 *iWritten )
|
|
{
|
|
mngstuff *pMydata = (mngstuff*)mng_get_userdata(hMNG);
|
|
|
|
*iWritten = fwrite( pBuf, sizeof(BYTE), iSize, pMydata->file );
|
|
|
|
if( *iWritten < iSize )
|
|
{
|
|
Warning( "write error" );
|
|
return MNG_FALSE;
|
|
}
|
|
|
|
return MNG_TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// swap Rs and Bs...
|
|
//---------------------------------------------------------------------------------------------
|
|
BOOL RGBFromBGR( BYTE *buf, UINT widthPix, UINT height )
|
|
{
|
|
UINT col, row;
|
|
LPBYTE pRed, pBlu;
|
|
BYTE tmp;
|
|
|
|
if (buf==NULL)return FALSE;
|
|
|
|
INT TmpRow = 0;
|
|
INT WidthBytes = widthPix*3;
|
|
if(WidthBytes & 0x003) WidthBytes = (WidthBytes | 3) + 1;
|
|
INT OurCol = 0;
|
|
for( row=0; row<height; row++ )
|
|
{
|
|
for( col=0; col<widthPix; col++ )
|
|
{
|
|
pRed = buf + TmpRow + OurCol;
|
|
pBlu = pRed + 2;
|
|
|
|
// swap red and blue
|
|
tmp = *pBlu;
|
|
*pBlu = *pRed;
|
|
*pRed = tmp;
|
|
|
|
OurCol += 3;
|
|
}
|
|
TmpRow += WidthBytes;
|
|
OurCol = 0;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// Creates the srcuffer filled with data for saving:
|
|
//---------------------------------------------------------------------------------------------
|
|
VOID CreateSrcBuffer( int Frame, int FrameCount, HBITMAP hBmp2 )
|
|
{
|
|
PBITMAPINFO pbmi;
|
|
BITMAP bmp;
|
|
|
|
srcbuffer=0;
|
|
|
|
// Get WidthBytes...
|
|
INT WidthBytes = W*3;
|
|
|
|
INT LineWidth = W*3;
|
|
if(LineWidth & 0x003) LineWidth = (LineWidth | 3) + 1;
|
|
|
|
// Bitmapstruct init...
|
|
GetObject( hBmp2, sizeof(BITMAP), (LPSTR)&bmp );
|
|
pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));
|
|
|
|
// Initialize the fields in the BITMAPINFO structure.
|
|
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
pbmi->bmiHeader.biWidth = bmp.bmWidth;
|
|
pbmi->bmiHeader.biHeight = -bmp.bmHeight;
|
|
pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
|
|
pbmi->bmiHeader.biBitCount = 24;
|
|
pbmi->bmiHeader.biCompression = BI_RGB;
|
|
pbmi->bmiHeader.biSizeImage = LineWidth * H * FrameCount;
|
|
pbmi->bmiHeader.biClrImportant = 0;
|
|
|
|
// Alloc Memory...
|
|
srcbuffer = 0;
|
|
srcbuffer = new BYTE[LineWidth*H*FrameCount];
|
|
if( srcbuffer == 0 )
|
|
Warning( "srcbuffer == 0!" );
|
|
|
|
// get the buffer and modify the format:
|
|
if( 0 == GetDIBits( MemDC, hBmp2, 0, (WORD) (H*FrameCount), srcbuffer, pbmi, 0 ) )
|
|
Warning( "no GetDIBits!!!" );
|
|
RGBFromBGR( srcbuffer, W, H*FrameCount );
|
|
if( srcbuffer == 0 )
|
|
Warning( "srcbuffer == 0!" );
|
|
|
|
// Freee.
|
|
LocalFree((PBITMAPINFO)pbmi);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// Writes a single PNG datastream
|
|
//---------------------------------------------------------------------------------------------
|
|
VOID WritePNG( mng_handle hMNG, int Frame, int FrameCount )
|
|
{
|
|
BYTE *dstbuffer;
|
|
INT LineWidth;
|
|
INT WidthBytes;
|
|
|
|
OffsetX=0; OffsetY=0; OffsetW=W; OffsetH=H;
|
|
|
|
// Get WidthBytes...
|
|
WidthBytes = W*3;
|
|
LineWidth = W*3;
|
|
if(LineWidth & 0x003) LineWidth = (LineWidth | 3) + 1;
|
|
|
|
tmpbuffer = new BYTE[(WidthBytes+1)*OffsetH];
|
|
if( tmpbuffer == 0 ) Warning( "Out of Memory!" );
|
|
|
|
// Write DEFI chunk.
|
|
mng_putchunk_defi( hMNG, 0, 0, 0, MNG_TRUE, OffsetX, OffsetY, MNG_FALSE, 0, 0, 0, 0 );
|
|
|
|
// Write Header:
|
|
mng_putchunk_ihdr(
|
|
hMNG,
|
|
OffsetW, OffsetH,
|
|
MNG_BITDEPTH_8/*iBitdepth*/,
|
|
MNG_COLORTYPE_RGB/*iColortype*/,
|
|
MNG_COMPRESSION_DEFLATE/*iCompression*/,
|
|
MNG_FILTER_ADAPTIVE/*iFilter*/,
|
|
MNG_INTERLACE_NONE /*iInterlace*/
|
|
);
|
|
|
|
// transfer data, add Filterbyte:
|
|
for( int Row=0; Row<OffsetH; Row++ )
|
|
{
|
|
// First Byte in each Scanline is Filterbyte: Currently 0 -> No Filter.
|
|
tmpbuffer[Row*(WidthBytes+1)]=0;
|
|
|
|
// Copy the scanline:
|
|
memcpy(
|
|
tmpbuffer+Row*(WidthBytes+1)+1,
|
|
srcbuffer+((OffsetY+Row)*(LineWidth))+OffsetX,
|
|
WidthBytes
|
|
);
|
|
}
|
|
|
|
// Free srcbuffer if not animated GIF:
|
|
delete [] srcbuffer;
|
|
|
|
// Compress data with ZLib (Deflate):
|
|
dstbuffer = new BYTE[(WidthBytes+1)*OffsetH];
|
|
if( dstbuffer == 0 ) Warning( "Out of Memory!" );
|
|
DWORD dstbufferSize=(WidthBytes+1)*OffsetH;
|
|
|
|
// Compress data:
|
|
if( Z_OK != compress2(
|
|
(Bytef *)dstbuffer, (ULONG *)&dstbufferSize,
|
|
(const Bytef*)tmpbuffer, (ULONG) (WidthBytes+1)*OffsetH,
|
|
9
|
|
)) Warning( "Unable to compress imagedata!" );
|
|
|
|
// Write Data into MNG File:
|
|
mng_putchunk_idat( hMNG, dstbufferSize, (mng_ptr*)dstbuffer);
|
|
mng_putchunk_iend(hMNG);
|
|
|
|
// Free the stuff:
|
|
delete [] tmpbuffer;
|
|
delete [] dstbuffer;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
// Writes a MNG (24bit)
|
|
//---------------------------------------------------------------------------------------------
|
|
VOID SaveMNG( LPSTR Filename, HDC hdc, HBITMAP hBmp )
|
|
{
|
|
mng_handle hMNG;
|
|
|
|
// check if currently a MNG file is loaded:
|
|
if( AnimFile.isAnimation == 1 )
|
|
CleanUpMNG();
|
|
|
|
// Creates the srcbuffer for imagedata:
|
|
CreateSrcBuffer( 0, 1, hBmp );
|
|
|
|
// allocate our stream data structure
|
|
mymngstuff = (mngstuff*)calloc(1, sizeof(*mymngstuff));
|
|
if( mymngstuff == NULL )
|
|
{
|
|
Warning( "Cannot allocate data buffer." );
|
|
return;
|
|
}
|
|
|
|
// pass the name of the file we want to play
|
|
mymngstuff->filename = Filename;
|
|
|
|
// init the lib:
|
|
hMNG = mng_initialize((mng_ptr)mymngstuff, mymngalloc, mymngfree, MNG_NULL);
|
|
if( !hMNG )
|
|
{
|
|
Warning( "Cannot initialize libmng." );
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
mng_setcb_openstream(hMNG, mymngopenstreamwrite );
|
|
mng_setcb_closestream(hMNG, mymngclosestream);
|
|
mng_setcb_writedata(hMNG, mymngwritedata);
|
|
|
|
// Write File:
|
|
mng_create(hMNG);
|
|
|
|
// Just a single Frame (save a normal PNG):
|
|
WritePNG( hMNG, 0, 1 );
|
|
|
|
// Now write file:
|
|
mng_write(hMNG);
|
|
|
|
// Free the stuff:
|
|
fclose( mymngstuff->file );
|
|
mng_cleanup(&hMNG);
|
|
}
|
|
|
|
free( mymngstuff );
|
|
}
|
|
|
|
|