MultiSpaccSDK/LibMultiSpacc/LibMultiSpacc/MultiSpacc.c

250 lines
6.8 KiB
C

#include "./MultiSpacc.h"
bool MultiSpacc_InitSystem(void)
{
#if defined(MultiSpacc_Target_SDLCommon)
SDL_Init(SDL_INIT_EVERYTHING);
#endif
return true;
}
MultiSpacc_Surface *MultiSpacc_GetWindowSurface( MultiSpacc_Window *Window )
{
#if defined(MultiSpacc_Target_SDL12)
return Window;
#elif defined(MultiSpacc_Target_SDL20)
return SDL_GetWindowSurface(Window);
#elif defined(MultiSpacc_Target_NDS)
return Window;
#endif
}
MultiSpacc_Surface *MultiSpacc_LoadImage( char FilePath[], MultiSpacc_Surface *Screen, Uint32 *ColorKey )
{
#ifdef MultiSpacc_Target_SDLCom
MultiSpacc_Surface *Final = NULL;
MultiSpacc_Surface *Raw = IMG_Load(FilePath);
if( Raw == NULL ) {
MultiSpacc_PrintDebug( "[E] Error Reading Image %s.\n", FilePath );
} else {
Final = SDL_ConvertSurface( Raw, Screen->format, 0 );
SDL_FreeSurface(Raw);
if( Final == NULL ) {
MultiSpacc_PrintDebug( "[E] Error Adapting Image %s.\n", FilePath );
} else {
Uint32 FinalColorKey = SDL_MapRGB( Final->format, 0xFF, 0x00, 0xFF ); // Magenta
if( ColorKey != NULL ){
FinalColorKey = *ColorKey;
}
MultiSpacc_SetColorKey( Final, true, FinalColorKey );
};
};
return Final;
#else
return true;
#endif
}
int MultiSpacc_SetColorKey( MultiSpacc_Surface *Surface, bool Flag, Uint32 Key )
{
#ifdef MultiSpacc_Target_SDLCom
Uint32 useKey;
if(Flag)
{
#if defined(MultiSpacc_Target_SDL12)
useKey = SDL_SRCCOLORKEY;
#elif defined(MultiSpacc_Target_SDL20)
useKey = SDL_TRUE;
#endif
}
else
{
#if defined(MultiSpacc_Target_SDL12)
useKey = 0;
#elif defined(MultiSpacc_Target_SDL20)
useKey = SDL_FALSE;
#endif
}
return SDL_SetColorKey( Surface, useKey, Key );
#endif
}
#ifndef MultiSpacc_Target_SDLCom
void MultiSpacc_Sleep( int milliseconds )
{
#if defined(MultiSpacc_Target_NDS)
#define NativeFps 60
#elif defined(MultiSpacc_Target_NES)
#define NativeFps 50
#endif
int frames = (NativeFps * milliseconds / 1000);
while( --frames )
{
#if defined(MultiSpacc_Target_NDS)
swiWaitForVBlank();
#elif defined(MultiSpacc_Target_NES)
ppu_wait_frame();
#endif
};
}
#endif
#ifdef MultiSpacc_Target_SDLCom
int MultiSpacc_PollEvent( MultiSpacc_Event *Event )
{
SDL_Event FromEvent;
int Result = SDL_PollEvent( &FromEvent );
*Event = (MultiSpacc_Event){
.Type = FromEvent.type,
.Key = FromEvent.key.keysym.sym,
};
return Result;
}
#endif
void MultiSpacc_SetSprite( int id, int x, int y, int sprite, MultiSpacc_SpriteFlags *flags, MultiSpacc_Surface *tiles, MultiSpacc_Surface *screen )
{
#if defined(MultiSpacc_Target_SDLCommon)
MultiSpacc_Rect offset = { .x = x, .y = y, };
MultiSpacc_Rect clip = {
.x = (8 * (sprite % 16)),
.y = (8 * (sprite / 16)),
.w = 8,
.h = 8,
};
SDL_BlitSurface( tiles, &clip, screen, &offset );
#elif defined(MultiSpacc_Target_NES)
oam_spr( x, y, sprite, (flags == NULL ? 0 : 0|(flags->flipHorizontal ? OAM_FLIP_H : 0)|(flags->flipVertical ? OAM_FLIP_V : 0)), id*4 );
#endif
}
void MultiSpacc_SetMetaSprite( int id, int x, int y, MultiSpacc_SpritesMap *map, int mapSize, MultiSpacc_Surface *tiles, MultiSpacc_Surface *screen )
{
int i;
for(i=0; i<mapSize; i++)
{
MultiSpacc_SetSprite( (id + i), (x + map->x[i]), (y + map->y[i]), map->chr[i], &map->flags[i], tiles, screen );
}
}
void MultiSpacc_SetTile( int x, int y, int tile, MultiSpacc_Surface *tiles, MultiSpacc_Surface *screen )
{
#if defined(MultiSpacc_Target_SDLCommon)
MultiSpacc_Rect offset = {
.x = 8*x,
.y = 8*y,
};
MultiSpacc_Rect clip = {
.x = (8 * (tile % 16)),
.y = (8 * (tile / 16)),
.w = 8,
.h = 8,
};
SDL_BlitSurface( tiles, &clip, screen, &offset );
#elif defined(MultiSpacc_Target_NES)
ppu_off();
vram_adr(NTADR_A( x, y ));
vram_put(tile);
ppu_on_all();
#endif
}
void MultiSpacc_SetMetaTile( int x, int y, MultiSpacc_TilesMap *map, int mapSize, MultiSpacc_Surface *tiles, MultiSpacc_Surface *screen )
{
int i;
#if defined(MultiSpacc_Target_NES)
ppu_off();
#endif
for(i=0; i<mapSize; i++)
{
#if defined(MultiSpacc_Target_NES)
vram_adr(NTADR_A( (x + map->x[i]), (y + map->y[i]) ));
vram_put( map->chr[i] );
#else
MultiSpacc_SetTile( (x + map->x[i]), (y + map->y[i]), map->chr[i], tiles, screen );
#endif
}
#if defined(MultiSpacc_Target_NES)
ppu_on_all();
#endif
}
void MultiSpacc_BlitLayer( MultiSpacc_Surface *source, MultiSpacc_Surface *destination )
{
#if defined(MultiSpacc_Target_SDLCommon)
SDL_BlitSurface( source, NULL, destination, NULL );
#endif
}
MultiSpacc_Surface *MultiSpacc_CreateSurface( MultiSpacc_SurfaceConfig *surfaceConfig )
{
#if defined(MultiSpacc_Target_SDLCommon)
return SDL_CreateRGBSurface( 0, surfaceConfig->width, surfaceConfig->height, surfaceConfig->bits, 0, 0, 0, 0 );
#endif
}
// partially copied from Unity's implementation, see <https://docs.unity3d.com/Manual/TimeFrameManagement.html>
bool MultiSpacc_MainLoopHandler( MultiSpacc_MainLoopHandlerArgs *handlerArgs )
{
#define AssertDirectCallUpdates ( ( handlerArgs->functionFixedUpdate != NULL && !handlerArgs->functionFixedUpdate(handlerArgs->args) ) || ( handlerArgs->functionRealUpdate != NULL && !handlerArgs->functionRealUpdate( handlerArgs->args, 1 ) ) )
#if defined(MultiSpacc_Target_SDLCommon)
Uint32 ticksNow;
Uint32 realDeltaTime;
double fixedDeltaTime;
ticksNow = SDL_GetTicks();
realDeltaTime = (ticksNow - handlerArgs->elapsedRealTime);
handlerArgs->elapsedRealTime += realDeltaTime;
fixedDeltaTime = (double)(handlerArgs->elapsedRealTime - handlerArgs->elapsedFixedTime) / (double)(1000 / MultiSpacc_GameTick);
while ( (handlerArgs->elapsedRealTime - handlerArgs->elapsedFixedTime) > (1000 / MultiSpacc_GameTick) ) {
if( handlerArgs->functionFixedUpdate != NULL && !handlerArgs->functionFixedUpdate(handlerArgs->args) ){
return false;
}
handlerArgs->elapsedFixedTime += (1000 / MultiSpacc_GameTick);
}
// TODO: limit real updates on native platforms, otherwise we waste infinite CPU cycles
if( handlerArgs->functionRealUpdate != NULL && !handlerArgs->functionRealUpdate( handlerArgs->args, fixedDeltaTime ) ){
return false;
}
#elif defined(MultiSpacc_Target_NDS)
// TODO: limit FixedUpdate to 50 FPS, since NDS vblank is 60 Hz
swiWaitForVBlank();
if( AssertDirectCallUpdates ){
return false;
}
#elif defined(MultiSpacc_Target_NES)
ppu_wait_frame();
if( AssertDirectCallUpdates ){
return false;
}
#endif
return true;
}
bool MultiSpacc_UpdateDisplay( MultiSpacc_Window *window )
{
#if defined(MultiSpacc_Target_SDL12)
return !SDL_Flip(window);
#elif defined(MultiSpacc_Target_SDL20)
return !SDL_UpdateWindowSurface(window);
#else
return true;
#endif
}