Copy Link
Add to Bookmark
Report

Sprite editor for the GP32

sang's profile picture
Published in 
GP32
 · 16 Aug 2021
sprite editor for GP32
Pin it
sprite editor for GP32
sprite editor for GP32 with an image loaded
Pin it
sprite editor for GP32 with an image loaded

source code

  
//////////////////////////////////////////////////////////////////////////////
//
// GPMain.c
//
// Author: Jung-Man Park ( sysop@doyongid.com )
//
// - Example code about sprite reading and drawing
//
// - Any modifications for optimize or bug-fix are welcomed.
//
// - When you modified this code, please notify to the author
// about the modification by the e-mail.
//
//////////////////////////////////////////////////////////////////////////////

#include "gpdef.h"
#include "gpstdlib.h"
#include "gpgraphic.h"
#include "gpstdio.h"
#include "gpmem.h"
#include "gpmain.h"
//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
GPDRAWSURFACE gpDraw[2]; // Primary / Back Surface
int nflip; // Flip

#define MAX_ALPHA 8 // Alpha Level (1 - 8)
unsigned char AlphaTable[256][256][8]; // Alpha Table
//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
// Minimum image area of one sprite
//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
typedef struct
{
unsigned short Left;
unsigned short Top;
unsigned short Width;
unsigned short Height;
} _MINAREA;

//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
// GPF Header
//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
typedef struct
{
int FileKind; // Identifier
int ColorMode; // Color Mode (Always 1 = 8 Bit)
int Size; // Size of sprite (seldom used)
int Col, Row; // Column and row blocks of sprite
int Width, Height; // Width and height of sprite
int TileNumber; // Number of sprites
int ColorKey; // Color key
} GPFHEADER;

//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
// Information of one sprite
//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
typedef struct
{
_MINAREA *Area; // Minimum image area of one sprite
int *SaveSize; // the compressed size of sprite when saved
} GPFDATA;

//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
// GPF Structure
//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
typedef struct
{
// CompressMode = 1 : Load compressed image to memory (with color-key-compression)
// CompressMode = 0 : Load decompressed image to memory (expand color-key-compression)
int CompressMode;

GPFHEADER stHeader;
GPFDATA stData;

// 'Bitmap' is used when CompressMode == 1, (compressed)
// otherwise 'Surface' is used. (decompressed)
unsigned char **Bitmap;
GPDRAWSURFACE *Surface;
} _GPF;

//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
// Load GPF
//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
int GPF_Load(_GPF *pGpf, char *pFileName, int pCompressMode)
{
int i, j, l;
ulong ReadCount, TotalCount;
unsigned char *ReadBuffer, *PutPtr, *TempBuffer;
int ReadBufferSize = 0;

F_HANDLE fp;

// Open file
if(GpFileOpen(pFileName, OPEN_R, &fp) != SM_OK)
return 0;

// Read header info
GpFileRead(fp, &pGpf->stHeader, sizeof(GPFHEADER), &ReadCount);

// Is it a valid GPF file? (Identifier is always 0x7839)
if(pGpf->stHeader.FileKind != 0x7839)
return 0;

// Is it an 8-Bit image?
if(pGpf->stHeader.ColorMode != 1)
return 0;

// 4-byte width arrangement
while(pGpf->stHeader.Width % 4)
pGpf->stHeader.Width++;

// Set compression mode
pGpf->CompressMode = pCompressMode;

// Allocate memory for a minimum-image-area-structure (_MINAREA)
pGpf->stData.Area = (_MINAREA *)gp_mem_func.malloc(pGpf->stHeader.TileNumber * sizeof(_MINAREA));

// Allocate memory using the compressed size in the GPF file
pGpf->stData.SaveSize = (int *)gp_mem_func.malloc(pGpf->stHeader.TileNumber * sizeof(int));

// Read the minimum image area for every sprite
GpFileRead(fp, pGpf->stData.Area, sizeof(_MINAREA) * pGpf->stHeader.TileNumber, &ReadCount);

// Read the compressed size for every sprite
GpFileRead(fp, pGpf->stData.SaveSize, sizeof(int) * pGpf->stHeader.TileNumber, &ReadCount);

// If there is any key-color(transparent color), load sprite data, leave it compressed
if(pGpf->CompressMode)
{
// Create image containers (Bitmap) as the amount of sprites
pGpf->Bitmap = (unsigned char **)gp_mem_func.malloc(pGpf->stHeader.TileNumber * sizeof(int));

// Load compressed sprite data
for(l = 0; l < pGpf->stHeader.TileNumber; l++)
{
pGpf->Bitmap[l] = (unsigned char *)gp_mem_func.malloc(pGpf->stData.SaveSize[l]);

// Load compressed tile data
GpFileRead(fp, pGpf->Bitmap[l], pGpf->stData.SaveSize[l], &ReadCount);
}
}
// Else if there is no key-color, load sprite data, and decompress it
else
{
// Create Surfaces as the amount of sprites
pGpf->Surface = (GPDRAWSURFACE *)gp_mem_func.malloc(pGpf->stHeader.TileNumber * sizeof(GPDRAWSURFACE));

// Check compressed size, and calculate the decompressed size
for(l = 0; l < pGpf->stHeader.TileNumber; l++)
{
if(ReadBufferSize < pGpf->stData.SaveSize[l])
ReadBufferSize = pGpf->stData.SaveSize[l];
}

// Allocate memory for a temporary read buffer
ReadBuffer = (unsigned char *)gp_mem_func.malloc(ReadBufferSize);

// Load sprite data to Surface, and decompress it
for(l = 0; l < pGpf->stHeader.TileNumber; l++)
{
// Skip empty sprite
if(pGpf->stData.Area[l].Width == 0) continue;

// Create Surface
pGpf->Surface[l].bpp = 8;
pGpf->Surface[l].buf_w = pGpf->stData.Area[l].Width;
pGpf->Surface[l].buf_h = pGpf->stData.Area[l].Height;

GpMemSurfaceGet(&pGpf->Surface[l]);

// Load an image data of every sprite to Surface
GpFileRead(fp, ReadBuffer, pGpf->stData.SaveSize[l], &ReadCount);

i = 0;
j = 0;

// Decompress it
while(i < pGpf->stData.SaveSize[l])
{
// Fill key-color by the amount of key-color
if(ReadBuffer[i + 1] == pGpf->stHeader.ColorKey)
{
gm_memset(&pGpf->Surface[l].o_buffer[j], pGpf->stHeader.ColorKey, ReadBuffer[i]);

j += ReadBuffer[i];
i += 2;
}
// Otherwise, just copy it
else
{
gm_memcpy(&pGpf->Surface[l].o_buffer[j], &ReadBuffer[i + 1], ReadBuffer[i]);

j += ReadBuffer[i];
i += (ReadBuffer[i] + 1);
}
}
}

gp_mem_func.free(ReadBuffer);
}

GpFileClose(fp);

return 1;
}
//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
// Delete GPF
//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
void GPF_Delete(_GPF *pGpf)
{
int i;

if(pGpf->CompressMode)
{
for(i = 0; i < pGpf->stHeader.TileNumber; i++)
{
if(pGpf->Bitmap[i]) gp_mem_func.free(pGpf->Bitmap[i]);
}
}
else
{
for(i = 0; i < pGpf->stHeader.TileNumber; i++)
{
// Release Surface, if exists (Width > 0)
if(pGpf->stData.Area[i].Width)
{
gp_mem_func.free(pGpf->Surface[i].o_buffer);
}
}
}

gp_mem_func.free(pGpf->stData.Area);
gp_mem_func.free(pGpf->stData.SaveSize);

gm_memset(pGpf, 0, sizeof(_GPF));
}

//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
// Load Palette
//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
int Palette_Load(char *pFileName)
{
int i;
unsigned char PalOk;
unsigned char PalEntry[768];
ulong ReadCount;
GP_HPALETTE GpPalette;
GP_LOGPALENTRY GpPalEntry[256];
F_HANDLE fp;

if(GpFileOpen(pFileName, OPEN_R, &fp) != SM_OK)
return 0;

// Read header info
GpFileRead(fp, &PalOk, 1, &ReadCount);

// Check Identifier
if(PalOk != 1)
{
GpFileClose(fp);

return 0;
}

// Read palette data
GpFileRead(fp, PalEntry, 768, &ReadCount);

// Read alpha table
GpFileRead(fp, AlphaTable, sizeof(AlphaTable), &ReadCount);

GpFileClose(fp);

// Set palette data to GP32 palette
for(i = 0; i < 256; i++)
{
GpPalEntry[i].peRed = PalEntry[i * 3];
GpPalEntry[i].peGreen = PalEntry[i * 3 + 1];
GpPalEntry[i].peBlue = PalEntry[i * 3 + 2];
GpPalEntry[i].peFlags = 0;
}

// Apply palette
GpPalette = GpPaletteCreateEx(256, GpPalEntry);
GpPaletteSelect(GpPalette);
GpPaletteRealize();

return 1;
}
//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
// Copy memory. (pPutBuffer = output surface buffer, pLineBuffer = source image)
//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
void SprCopyMemory(unsigned char *pPutBuffer, unsigned char *pLineBuffer, int pSize, unsigned short pAlphaDepth)
{
int i, j = 0;

// If there is no alpha depth, just copy them
if(pAlphaDepth == 0)
{
gm_memcpy(pPutBuffer, pLineBuffer, pSize);
}
// Else, apply alpha blend
else if(pAlphaDepth <= MAX_ALPHA)
{
for(i = 0; i < pSize; i++)
{
// Set the alpha-blended color using alpha table
pPutBuffer[i] = AlphaTable[pPutBuffer[i]][pLineBuffer[j++]][pAlphaDepth - 1];
}
}
}
//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
// Draw specified frame. (pFrame = frame number, pRotateMode = horizontal flip, pAlphaDepth = alpha depth)
//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
void GPF_ShowFrame(GPDRAWSURFACE *pSurface, int pLeft, int pTop, _GPF *pGpf, int pFrame, int pRotateMode, int pAlphaDepth)
{
int i, j, w, h;

int PutLoc, LineCount, LineStart, LineWidth, BlockStart;
int PutSurfaceWidth, PutSurfaceHeight;
int RealLeft, RealTop;
int SprWidth, SprHeight;

unsigned char *SprPtr;
unsigned char *PutPtr;

GPRECT stMinRect, stGpRect;
GPFHEADER *GpfHeader;
GPFDATA *GpfData;

// Get sprite info
GpfHeader = &pGpf->stHeader;
GpfData = &pGpf->stData;

// If sprite was decompressed (No alpha blend)
if(pGpf->CompressMode == 0)
{
GpBitBlt(NULL,
pSurface,
pLeft, pTop,
pGpf->Surface[pFrame].buf_w, pGpf->Surface[pFrame].buf_h,
pGpf->Surface[pFrame].o_buffer,
0, 0,
pGpf->Surface[pFrame].buf_w, pGpf->Surface[pFrame].buf_h);
}
else
{
// Set the sprite's start address
SprPtr = pGpf->Bitmap[pFrame];

// Convert to the GP32 coordinates (Note that X-Editor does not convert the sprite coordinates to GP32's)
stGpRect.left = GpfHeader->Height - (GpfData->Area[pFrame].Top + GpfData->Area[pFrame].Height);
stGpRect.top = GpfData->Area[pFrame].Left;
stGpRect.right = GpfHeader->Height - GpfData->Area[pFrame].Top;
stGpRect.bottom = GpfData->Area[pFrame].Left + GpfData->Area[pFrame].Width;

// Get minimum-image-area-info. (Exchange width and height, according to the GP32 coordinates)
SprWidth = GpfData->Area[pFrame].Height;
SprHeight = GpfData->Area[pFrame].Width;

// Reset the minimum-image-area (This value will be changed when clipped)
stMinRect.left = 0;
stMinRect.top = 0;
stMinRect.right = SprWidth;
stMinRect.bottom = SprHeight;

// Set output surface size (Exchange, as the GP32 coord.)
PutSurfaceWidth = pSurface->buf_h;
PutSurfaceHeight = pSurface->buf_w;

// Calculate the output position (as the GP32 coord.)
RealLeft = PutSurfaceWidth - pTop - GpfHeader->Height + stGpRect.left;
if(pRotateMode)
{
RealTop = pLeft + GpfHeader->Width - stGpRect.top - SprHeight;
LineCount = SprHeight;
}
else
{
RealTop = pLeft + stGpRect.top;
LineCount = 0;
}

// Skip the out-of-screen drawing
if(RealLeft <= -SprWidth || RealLeft >= PutSurfaceWidth || RealTop <= -SprHeight || RealTop >= PutSurfaceHeight)
return;

// Apply clipping to the output area
if(RealLeft < 0 && RealLeft > -SprWidth)
stMinRect.left = -RealLeft;

if(RealLeft + SprWidth >= PutSurfaceWidth)
stMinRect.right = stMinRect.left + PutSurfaceWidth - RealLeft;

if(RealTop < 0 && RealTop > -SprHeight)
stMinRect.top = -RealTop;

if(RealTop + SprHeight >= PutSurfaceHeight)
stMinRect.bottom = PutSurfaceHeight - RealTop;

// Get the address of output surface
PutPtr = pSurface->ptbuffer;

// Calculate the output position
PutLoc = RealTop * PutSurfaceWidth + RealLeft;

i = 0;
j = 0;
// Loop around the sprite
while(i < GpfData->SaveSize[pFrame])
{
// Color Key check
if(SprPtr[i + 1] == GpfHeader->ColorKey)
{
j += SprPtr[i];
i += 2;
}
// Else it's not a key-color
else
{
// Y-axis clipping
if((RealTop + LineCount) >= 0 && (RealTop + LineCount) < PutSurfaceHeight)
{
BlockStart = j;

// Left-side clipping
if(stMinRect.left > 0)
{
// If across the border
if(stMinRect.left > BlockStart && stMinRect.left < BlockStart + SprPtr[i])
{
LineWidth = (BlockStart + SprPtr[i]) - stMinRect.left;
LineStart = stMinRect.left;

if(PutLoc + LineStart >= 0)
{
SprCopyMemory(&PutPtr[PutLoc + LineStart], &SprPtr[i + stMinRect.left - j + 1], LineWidth, pAlphaDepth);
}
}
// else, lay inside of the output area
else if(stMinRect.left <= BlockStart)
{
LineWidth = SprPtr[i];
LineStart = BlockStart;

if(PutLoc + LineStart >= 0)
SprCopyMemory(&PutPtr[PutLoc + LineStart], &SprPtr[i + 1], LineWidth, pAlphaDepth);
}
}
// Right-side clipping
else if(stMinRect.right < SprWidth)
{
// If across the border
if(stMinRect.right > BlockStart && stMinRect.right < BlockStart + SprPtr[i])
{
LineWidth = stMinRect.right - BlockStart;
LineStart = BlockStart;

if(PutLoc + LineStart >= 0)
SprCopyMemory(&PutPtr[PutLoc + LineStart], &SprPtr[i + 1], LineWidth, pAlphaDepth);
}
// else, lay inside of the output area
else if(stMinRect.right >= BlockStart + SprPtr[i])
{
LineWidth = SprPtr[i];
LineStart = BlockStart;

if(PutLoc + LineStart >= 0)
SprCopyMemory(&PutPtr[PutLoc + LineStart], &SprPtr[i + 1], LineWidth, pAlphaDepth);
}
}
// inside of the output area
else
{
if(PutLoc + BlockStart >= 0)
SprCopyMemory(&PutPtr[PutLoc + BlockStart], &SprPtr[i + 1], SprPtr[i], pAlphaDepth);
}
}


j += SprPtr[i];
i += (SprPtr[i] + 1);
}

// When finished decompressing one line
if(j == SprWidth)
{
if(pRotateMode)
{
// Decrease amount of lines to draw
LineCount--;
// Recalculate the next line position
PutLoc -= PutSurfaceWidth;
}
else
{
// Increase amount of lines to draw
LineCount++;
// Recalculate the next line position
PutLoc += PutSurfaceWidth;
}

j = 0;
}
}
}
}

//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
// Main Program
//¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨¶¨
int Frame = 0;
int GpMain(void *arg)
{
int n_tick, i, j;

_GPF stGpf;

GpFatInit();
GpRelativePathSet("gp:\\gpmm\\XEditor");

GpLcdSurfaceGet(&gpDraw[0], 0);
GpLcdSurfaceGet(&gpDraw[1], 1);
GpRectFill(NULL, &gpDraw[0], 0, 0, 320, 240, 0);
GpRectFill(NULL, &gpDraw[1], 0, 0, 320, 240, 0);
GpSurfaceSet(&gpDraw[0]);
nflip = 1;

// Load palette
if(Palette_Load("Palette.Pal") == 0) return 0;

// Initialize GPF structure
gm_memset(&stGpf, 0, sizeof(_GPF));

// Load GPF to memory, with color key (set 1 at the third parameter)
if(GPF_Load(&stGpf, "Sample.Gpf", 1) == 0) return 0;

// Load GPF to memory, without color key (set 0 at the third parameter)
//if(GPF_Load(&stGpf, "Sample2.Gpf", 0) == 0) return 0;

while(1)
{
GpKeyInit();

// Finish program
if(GpKeyGet() == GPC_VK_FA)
{
// Delete GPF
GPF_Delete(&stGpf);

GpAppExit();
return 0;
}

// Set to 25 frame-per-second
if(GpTickCountGet() - n_tick > 1000 / 25)
{
n_tick = GpTickCountGet();

// Fill the screen with black
GpRectFill(NULL, &gpDraw[nflip], 0, 0, 320, 240, 0);

// Draw sprite
GPF_ShowFrame( &gpDraw[nflip], // Target surface
0, 0, // Target Coordinate (x, y)
&stGpf, // GPF structure
Frame++, // Frame number to draw
0, // Apply horizontal flip?
0 // Alpha depth(1 - 8)
);
// Note: To use alpha depth,
// you must set the third parameter as integer '1' when you call GPF_Load()

// If passed last frame, return to first frame
if(Frame == stGpf.stHeader.TileNumber)
Frame = 0;

// Flip Surface.
GpSurfaceFlip(&gpDraw[nflip++]);
nflip %= 2;
}
}

return 0;
}

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT