Restore support for the Nokia N-Gage (#12148)

This commit is contained in:
Michael Fitzmayer
2025-05-22 20:07:22 +02:00
committed by GitHub
parent 26f9940f82
commit 7ae64592c9
51 changed files with 4184 additions and 44 deletions

View File

@@ -728,6 +728,8 @@ const char *SDL_GetPlatform(void)
return "macOS";
#elif defined(SDL_PLATFORM_NETBSD)
return "NetBSD";
#elif defined(SDL_PLATFORM_NGAGE)
return "Nokia N-Gage";
#elif defined(SDL_PLATFORM_OPENBSD)
return "OpenBSD";
#elif defined(SDL_PLATFORM_OS2)

View File

@@ -20,6 +20,8 @@
*/
#include "SDL_internal.h"
#include "stdlib/SDL_vacopy.h"
// Simple error handling in SDL
#include "SDL_error_c.h"

View File

@@ -587,6 +587,25 @@ void SDL_LogMessageV(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_S
return;
}
#if defined(SDL_PLATFORM_NGAGE)
extern void NGAGE_vnprintf(char *buf, size_t size, const char *fmt, va_list ap);
char buf[1024];
NGAGE_vnprintf(buf, sizeof(buf), fmt, ap);
#ifdef ENABLE_FILE_LOG
FILE* file;
file = fopen("E:/SDL_Log.txt", "a");
if (file)
{
vfprintf(file, fmt, ap);
fprintf(file, "\n");
(void)fclose(file);
}
#endif
return;
#endif
// Render into stack buffer
va_copy(aq, ap);
len = SDL_vsnprintf(stack_buf, sizeof(stack_buf), fmt, aq);
@@ -767,9 +786,14 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority
(void)fclose(pFile);
}
}
#elif defined(SDL_PLATFORM_NGAGE)
{
/* Nothing to do here. */
}
#endif
#if defined(HAVE_STDIO_H) && \
!(defined(SDL_PLATFORM_APPLE) && (defined(SDL_VIDEO_DRIVER_COCOA) || defined(SDL_VIDEO_DRIVER_UIKIT))) && \
!(defined(SDL_PLATFORM_NGAGE)) && \
!(defined(SDL_PLATFORM_WIN32))
(void)fprintf(stderr, "%s%s\n", GetLogPriorityPrefix(priority), message);
#endif

View File

@@ -77,6 +77,9 @@ static const AudioBootStrap *const bootstrap[] = {
#ifdef SDL_AUDIO_DRIVER_N3DS
&N3DSAUDIO_bootstrap,
#endif
#ifdef SDL_AUDIO_DRIVER_NGAGE
&NGAGEAUDIO_bootstrap,
#endif
#ifdef SDL_AUDIO_DRIVER_EMSCRIPTEN
&EMSCRIPTENAUDIO_bootstrap,
#endif

View File

@@ -393,6 +393,7 @@ extern AudioBootStrap PS2AUDIO_bootstrap;
extern AudioBootStrap PSPAUDIO_bootstrap;
extern AudioBootStrap VITAAUD_bootstrap;
extern AudioBootStrap N3DSAUDIO_bootstrap;
extern AudioBootStrap NGAGEAUDIO_bootstrap;
extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
extern AudioBootStrap QSAAUDIO_bootstrap;

View File

@@ -0,0 +1,103 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_AUDIO_DRIVER_NGAGE
#include "../SDL_sysaudio.h"
#include "SDL_ngageaudio.h"
static SDL_AudioDevice *devptr = NULL;
SDL_AudioDevice *NGAGE_GetAudioDeviceAddr()
{
return devptr;
}
static bool NGAGEAUDIO_OpenDevice(SDL_AudioDevice *device)
{
SDL_PrivateAudioData *phdata = SDL_calloc(1, sizeof(SDL_PrivateAudioData));
if (!phdata) {
SDL_OutOfMemory();
return false;
}
device->hidden = phdata;
phdata->buffer = SDL_calloc(1, device->buffer_size);
if (!phdata->buffer) {
SDL_OutOfMemory();
SDL_free(phdata);
return false;
}
devptr = device;
// Since the phone can change the sample rate during a phone call,
// we set the sample rate to 8KHz to be safe. Even though it
// might be possible to adjust the sample rate dynamically, it's
// not supported by the current implementation.
device->spec.format = SDL_AUDIO_S16LE;
device->spec.channels = 1;
device->spec.freq = 8000;
SDL_UpdatedAudioDeviceFormat(device);
return true;
}
static Uint8 *NGAGEAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
SDL_PrivateAudioData *phdata = (SDL_PrivateAudioData *)device->hidden;
if (!phdata) {
*buffer_size = 0;
return 0;
}
*buffer_size = device->buffer_size;
return phdata->buffer;
}
static void NGAGEAUDIO_CloseDevice(SDL_AudioDevice *device)
{
if (device->hidden) {
SDL_free(device->hidden->buffer);
SDL_free(device->hidden);
}
return;
}
static bool NGAGEAUDIO_Init(SDL_AudioDriverImpl *impl)
{
impl->OpenDevice = NGAGEAUDIO_OpenDevice;
impl->GetDeviceBuf = NGAGEAUDIO_GetDeviceBuf;
impl->CloseDevice = NGAGEAUDIO_CloseDevice;
impl->ProvidesOwnCallbackThread = true;
impl->OnlyHasDefaultPlaybackDevice = true;
return true;
}
AudioBootStrap NGAGEAUDIO_bootstrap = { "N-Gage", "N-Gage audio driver", NGAGEAUDIO_Init, false };
#endif // SDL_AUDIO_DRIVER_NGAGE

View File

@@ -0,0 +1,368 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "SDL_ngageaudio.h"
#include "../SDL_sysaudio.h"
#include "SDL_internal.h"
#ifdef __cplusplus
}
#endif
#ifdef SDL_AUDIO_DRIVER_NGAGE
#include "SDL_ngageaudio.hpp"
CAudio::CAudio() : CActive(EPriorityStandard), iBufDes(NULL, 0) {}
CAudio *CAudio::NewL(TInt aLatency)
{
CAudio *self = new (ELeave) CAudio();
CleanupStack::PushL(self);
self->ConstructL(aLatency);
CleanupStack::Pop(self);
return self;
}
void CAudio::ConstructL(TInt aLatency)
{
CActiveScheduler::Add(this);
User::LeaveIfError(iTimer.CreateLocal());
iTimerCreated = ETrue;
iStream = CMdaAudioOutputStream::NewL(*this);
if (!iStream) {
SDL_Log("Error: Failed to create audio stream");
User::Leave(KErrNoMemory);
}
iLatency = aLatency;
iLatencySamples = aLatency * 8; // 8kHz.
// Determine minimum and maximum number of samples to write with one
// WriteL request.
iMinWrite = iLatencySamples / 8;
iMaxWrite = iLatencySamples / 2;
// Set defaults.
iState = EStateNone;
iTimerCreated = EFalse;
iTimerActive = EFalse;
}
CAudio::~CAudio()
{
if (iStream) {
iStream->Stop();
while (iState != EStateDone) {
User::After(100000); // 100ms.
}
delete iStream;
}
}
void CAudio::Start()
{
if (iStream) {
// Set to 8kHz mono audio.
iStreamSettings.iChannels = TMdaAudioDataSettings::EChannelsMono;
iStreamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate8000Hz;
iStream->Open(&iStreamSettings);
iState = EStateOpening;
} else {
SDL_Log("Error: Failed to open audio stream");
}
}
// Feeds more processed data to the audio stream.
void CAudio::Feed()
{
// If a WriteL is already in progress, or we aren't even playing;
// do nothing!
if ((iState != EStateWriting) && (iState != EStatePlaying)) {
return;
}
// Figure out the number of samples that really have been played
// through the output.
TTimeIntervalMicroSeconds pos = iStream->Position();
TInt played = 8 * (pos.Int64() / TInt64(1000)).GetTInt(); // 8kHz.
played += iBaseSamplesPlayed;
// Determine the difference between the number of samples written to
// CMdaAudioOutputStream and the number of samples it has played.
// The difference is the amount of data in the buffers.
if (played < 0) {
played = 0;
}
TInt buffered = iSamplesWritten - played;
if (buffered < 0) {
buffered = 0;
}
if (iState == EStateWriting) {
return;
}
// The trick for low latency: Do not let the buffers fill up beyond the
// latency desired! We write as many samples as the difference between
// the latency target (in samples) and the amount of data buffered.
TInt samplesToWrite = iLatencySamples - buffered;
// Do not write very small blocks. This should improve efficiency, since
// writes to the streaming API are likely to be expensive.
if (samplesToWrite < iMinWrite) {
// Not enough data to write, set up a timer to fire after a while.
// Try againwhen it expired.
if (iTimerActive) {
return;
}
iTimerActive = ETrue;
SetActive();
iTimer.After(iStatus, (1000 * iLatency) / 8);
return;
}
// Do not write more than the set number of samples at once.
int numSamples = samplesToWrite;
if (numSamples > iMaxWrite) {
numSamples = iMaxWrite;
}
SDL_AudioDevice *device = NGAGE_GetAudioDeviceAddr();
if (device) {
SDL_PrivateAudioData *phdata = (SDL_PrivateAudioData *)device->hidden;
iBufDes.Set(phdata->buffer, 2 * numSamples, 2 * numSamples);
iStream->WriteL(iBufDes);
iState = EStateWriting;
// Keep track of the number of samples written (for latency calculations).
iSamplesWritten += numSamples;
} else {
// Output device not ready yet. Let's go for another round.
if (iTimerActive) {
return;
}
iTimerActive = ETrue;
SetActive();
iTimer.After(iStatus, (1000 * iLatency) / 8);
}
}
void CAudio::RunL()
{
iTimerActive = EFalse;
Feed();
}
void CAudio::DoCancel()
{
iTimerActive = EFalse;
iTimer.Cancel();
}
void CAudio::StartThread()
{
TInt heapMinSize = 8192; // 8 KB initial heap size.
TInt heapMaxSize = 1024 * 1024; // 1 MB maximum heap size.
TInt err = iProcess.Create(_L("ProcessThread"), ProcessThreadCB, KDefaultStackSize * 2, heapMinSize, heapMaxSize, this);
if (err == KErrNone) {
iProcess.SetPriority(EPriorityLess);
iProcess.Resume();
} else {
SDL_Log("Error: Failed to create audio processing thread: %d", err);
}
}
void CAudio::StopThread()
{
if (iStreamStarted) {
iProcess.Kill(KErrNone);
iProcess.Close();
iStreamStarted = EFalse;
}
}
TInt CAudio::ProcessThreadCB(TAny *aPtr)
{
CAudio *self = static_cast<CAudio *>(aPtr);
SDL_AudioDevice *device = NGAGE_GetAudioDeviceAddr();
while (self->iStreamStarted) {
if (device) {
SDL_PlaybackAudioThreadIterate(device);
} else {
device = NGAGE_GetAudioDeviceAddr();
}
User::After(100000); // 100ms.
}
return KErrNone;
}
void CAudio::MaoscOpenComplete(TInt aError)
{
if (aError == KErrNone) {
iStream->SetVolume(1);
iStreamStarted = ETrue;
StartThread();
} else {
SDL_Log("Error: Failed to open audio stream: %d", aError);
}
}
void CAudio::MaoscBufferCopied(TInt aError, const TDesC8 & /*aBuffer*/)
{
if (aError == KErrNone) {
iState = EStatePlaying;
Feed();
} else if (aError == KErrAbort) {
// The stream has been stopped.
iState = EStateDone;
} else {
SDL_Log("Error: Failed to copy audio buffer: %d", aError);
}
}
void CAudio::MaoscPlayComplete(TInt aError)
{
// If we finish due to an underflow, we'll need to restart playback.
// Normally KErrUnderlow is raised at stream end, but in our case the API
// should never see the stream end -- we are continuously feeding it more
// data! Many underflow errors mean that the latency target is too low.
if (aError == KErrUnderflow) {
// The number of samples played gets resetted to zero when we restart
// playback after underflow.
iBaseSamplesPlayed = iSamplesWritten;
iStream->Stop();
Cancel();
iStream->SetAudioPropertiesL(TMdaAudioDataSettings::ESampleRate8000Hz, TMdaAudioDataSettings::EChannelsMono);
iState = EStatePlaying;
Feed();
return;
} else if (aError != KErrNone) {
// Handle error.
}
// We shouldn't get here.
SDL_Log("%s: %d", __FUNCTION__, aError);
}
static TBool gAudioRunning;
TBool AudioIsReady()
{
return gAudioRunning;
}
TInt AudioThreadCB(TAny *aParams)
{
CTrapCleanup *cleanup = CTrapCleanup::New();
if (!cleanup) {
return KErrNoMemory;
}
CActiveScheduler *scheduler = new CActiveScheduler();
if (!scheduler) {
delete cleanup;
return KErrNoMemory;
}
CActiveScheduler::Install(scheduler);
TRAPD(err,
{
TInt latency = *(TInt *)aParams;
CAudio *audio = CAudio::NewL(latency);
CleanupStack::PushL(audio);
gAudioRunning = ETrue;
audio->Start();
TBool once = EFalse;
while (gAudioRunning) {
// Allow active scheduler to process any events.
TInt error;
CActiveScheduler::RunIfReady(error, CActive::EPriorityIdle);
if (!once) {
SDL_AudioDevice *device = NGAGE_GetAudioDeviceAddr();
if (device) {
// Stream ready; start feeding audio data.
// After feeding it once, the callbacks will take over.
audio->iState = CAudio::EStatePlaying;
audio->Feed();
once = ETrue;
}
}
User::After(100000); // 100ms.
}
CleanupStack::PopAndDestroy(audio);
});
delete scheduler;
delete cleanup;
return err;
}
RThread audioThread;
void InitAudio(TInt *aLatency)
{
_LIT(KAudioThreadName, "AudioThread");
TInt err = audioThread.Create(KAudioThreadName, AudioThreadCB, KDefaultStackSize, 0, aLatency);
if (err != KErrNone) {
User::Leave(err);
}
audioThread.Resume();
}
void DeinitAudio()
{
gAudioRunning = EFalse;
TRequestStatus status;
audioThread.Logon(status);
User::WaitForRequest(status);
audioThread.Close();
}
#endif // SDL_AUDIO_DRIVER_NGAGE

View File

@@ -0,0 +1,44 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_ngageaudio_h
#define SDL_ngageaudio_h
typedef struct SDL_PrivateAudioData
{
Uint8 *buffer;
} SDL_PrivateAudioData;
#ifdef __cplusplus
extern "C" {
#endif
#include "../SDL_sysaudio.h"
SDL_AudioDevice *NGAGE_GetAudioDeviceAddr();
#ifdef __cplusplus
}
#endif
#endif // SDL_ngageaudio_h

View File

@@ -0,0 +1,98 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_ngageaudio_hpp
#define SDL_ngageaudio_hpp
#include <e32base.h>
#include <e32std.h>
#include <mda/common/audio.h>
#include <mdaaudiooutputstream.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "../SDL_sysaudio.h"
#include "SDL_ngageaudio.h"
#ifdef __cplusplus
}
#endif
TBool AudioIsReady();
void InitAudio(TInt *aLatency);
void DeinitAudio();
class CAudio : public CActive, public MMdaAudioOutputStreamCallback
{
public:
static CAudio *NewL(TInt aLatency);
~CAudio();
void ConstructL(TInt aLatency);
void Start();
void Feed();
void RunL();
void DoCancel();
static TInt ProcessThreadCB(TAny * /*aPtr*/);
// From MMdaAudioOutputStreamCallback
void MaoscOpenComplete(TInt aError);
void MaoscBufferCopied(TInt aError, const TDesC8 &aBuffer);
void MaoscPlayComplete(TInt aError);
enum
{
EStateNone = 0,
EStateOpening,
EStatePlaying,
EStateWriting,
EStateDone
} iState;
private:
CAudio();
void StartThread();
void StopThread();
CMdaAudioOutputStream *iStream;
TMdaAudioDataSettings iStreamSettings;
TBool iStreamStarted;
TPtr8 iBufDes; // Descriptor for the buffer.
TInt iLatency; // Latency target in ms
TInt iLatencySamples; // Latency target in samples.
TInt iMinWrite; // Min number of samples to write per turn.
TInt iMaxWrite; // Max number of samples to write per turn.
TInt iBaseSamplesPlayed; // amples played before last restart.
TInt iSamplesWritten; // Number of samples written so far.
RTimer iTimer;
TBool iTimerCreated;
TBool iTimerActive;
RThread iProcess;
};
#endif // SDL_ngageaudio_hpp

View File

@@ -0,0 +1,77 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include <e32std.h>
#include <e32svr.h>
#include <hal.h>
#ifdef __cplusplus
extern "C" {
#endif
bool NGAGE_IsClassicModel()
{
int phone_id;
HAL::Get(HALData::EMachineUid, phone_id);
return (0x101f8c19 == phone_id);
}
void NGAGE_printf(const char *fmt, ...)
{
char buffer[512] = { 0 };
va_list ap;
va_start(ap, fmt);
vsprintf(buffer, fmt, ap);
va_end(ap);
TBuf<512> buf;
buf.Copy(TPtrC8((TText8 *)buffer));
RDebug::Print(_L("%S"), &buf);
}
void NGAGE_vnprintf(char *buf, size_t size, const char *fmt, va_list ap)
{
char buffer[512] = { 0 };
vsprintf(buffer, fmt, ap);
TBuf<512> tbuf;
tbuf.Copy(TPtrC8((TText8 *)buffer));
RDebug::Print(_L("%S"), &tbuf);
strncpy(buf, buffer, size - 1);
buf[size - 1] = '\0';
}
TInt NGAGE_GetFreeHeapMemory()
{
TInt free = 0;
return User::Available(free);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,36 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_ngage_h
#define SDL_ngage_h
#ifdef __cplusplus
extern "C" {
#endif
bool NGAGE_IsClassicModel();
#ifdef __cplusplus
}
#endif
#endif /* SDL_ngage_h */

View File

@@ -421,6 +421,12 @@ static int CPU_haveARMSIMD(void)
return regs.r[0];
}
#elif defined(SDL_PLATFORM_NGAGE)
static int CPU_haveARMSIMD(void)
{
// The RM920T is based on the ARMv4T architecture and doesn't have SIMD.
return 0;
}
#else
static int CPU_haveARMSIMD(void)
{
@@ -468,6 +474,8 @@ static int CPU_haveNEON(void)
return 1;
#elif defined(SDL_PLATFORM_3DS)
return 0;
#elif defined(SDL_PLATFORM_NGAGE)
return 0; // The ARM920T is based on the ARMv4T architecture and doesn't have NEON.
#elif defined(SDL_PLATFORM_APPLE) && defined(__ARM_ARCH) && (__ARM_ARCH >= 7)
// (note that sysctlbyname("hw.optional.neon") doesn't work!)
return 1; // all Apple ARMv7 chips and later have NEON.

View File

@@ -63,6 +63,8 @@
#define SDL_DYNAMIC_API 0 // vitasdk doesn't support dynamic linking
#elif defined(SDL_PLATFORM_3DS)
#define SDL_DYNAMIC_API 0 // devkitARM doesn't support dynamic linking
#elif defined(SDL_PLATFORM_NGAGE)
#define SDL_DYNAMIC_API 0
#elif defined(DYNAPI_NEEDS_DLOPEN) && !defined(HAVE_DLOPEN)
#define SDL_DYNAMIC_API 0 // we need dlopen(), but don't have it....
#endif

View File

@@ -0,0 +1,67 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
extern void NGAGE_GetAppPath(char* path);
char *SDL_SYS_GetBasePath(void)
{
char app_path[512];
NGAGE_GetAppPath(app_path);
char *base_path = SDL_strdup(app_path);
return base_path;
}
char *SDL_SYS_GetPrefPath(const char *org, const char *app)
{
char *pref_path;
if (SDL_asprintf(&pref_path, "C:/System/Apps/%s/%s/", org, app) < 0)
return NULL;
else
return pref_path;
}
char *SDL_SYS_GetUserFolder(SDL_Folder folder)
{
const char *folder_path = NULL;
switch (folder)
{
case SDL_FOLDER_HOME:
folder_path = "C:/";
break;
case SDL_FOLDER_PICTURES:
folder_path = "C:/Nokia/Pictures/";
break;
case SDL_FOLDER_SAVEDGAMES:
folder_path = "C:/";
break;
case SDL_FOLDER_SCREENSHOTS:
folder_path = "C:/Nokia/Pictures/";
break;
case SDL_FOLDER_VIDEOS:
folder_path = "C:/Nokia/Videos/";
break;
default:
folder_path = "C:/Nokia/Others/";
break;
}
return SDL_strdup(folder_path);
}

View File

@@ -0,0 +1,68 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "SDL_internal.h"
#ifdef __cplusplus
}
#endif
#include <e32base.h>
#include <e32std.h>
#include <f32file.h>
#include <utf.h>
#ifdef __cplusplus
extern "C" {
#endif
void NGAGE_GetAppPath(char* path)
{
TBuf<512> aPath;
TFileName fullExePath = RProcess().FileName();
TParsePtrC parser(fullExePath);
aPath.Copy(parser.DriveAndPath());
TBuf8<512> utf8Path; // Temporary buffer for UTF-8 data.
CnvUtfConverter::ConvertFromUnicodeToUtf8(utf8Path, aPath);
// Copy UTF-8 data to the provided char* buffer.
strncpy(path, (const char*)utf8Path.Ptr(), utf8Path.Length());
path[utf8Path.Length()] = '\0';
// Replace backslashes with forward slashes.
for (int i = 0; i < utf8Path.Length(); i++)
{
if (path[i] == '\\')
{
path[i] = '/';
}
}
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,307 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../SDL_syslocale.h"
#include "SDL_internal.h"
#include <bautils.h>
#include <e32base.h>
#include <e32cons.h>
#include <e32std.h>
bool SDL_SYS_GetPreferredLocales(char *buf, size_t buflen)
{
TLanguage language = User::Language();
const char *locale;
switch (language) {
case ELangFrench:
case ELangSwissFrench:
locale = "fr_CH";
break;
case ELangBelgianFrench:
locale = "fr_BE";
break;
case ELangInternationalFrench:
locale = "fr_FR";
break;
case ELangGerman:
case ELangSwissGerman:
case ELangAustrian:
locale = "de_DE";
break;
case ELangSpanish:
case ELangInternationalSpanish:
case ELangLatinAmericanSpanish:
locale = "es_ES";
break;
case ELangItalian:
case ELangSwissItalian:
locale = "it_IT";
break;
case ELangSwedish:
case ELangFinlandSwedish:
locale = "sv_SE";
break;
case ELangDanish:
locale = "da_DK";
break;
case ELangNorwegian:
case ELangNorwegianNynorsk:
locale = "no_NO";
break;
case ELangFinnish:
locale = "fi_FI";
break;
case ELangPortuguese:
locale = "pt_PT";
break;
case ELangBrazilianPortuguese:
locale = "pt_BR";
break;
case ELangTurkish:
case ELangCyprusTurkish:
locale = "tr_TR";
break;
case ELangIcelandic:
locale = "is_IS";
break;
case ELangRussian:
locale = "ru_RU";
break;
case ELangHungarian:
locale = "hu_HU";
break;
case ELangDutch:
locale = "nl_NL";
break;
case ELangBelgianFlemish:
locale = "nl_BE";
break;
case ELangAustralian:
case ELangNewZealand:
locale = "en_AU";
break;
case ELangCzech:
locale = "cs_CZ";
break;
case ELangSlovak:
locale = "sk_SK";
break;
case ELangPolish:
locale = "pl_PL";
break;
case ELangSlovenian:
locale = "sl_SI";
break;
case ELangTaiwanChinese:
locale = "zh_TW";
break;
case ELangHongKongChinese:
locale = "zh_HK";
break;
case ELangPrcChinese:
locale = "zh_CN";
break;
case ELangJapanese:
locale = "ja_JP";
break;
case ELangThai:
locale = "th_TH";
break;
case ELangAfrikaans:
locale = "af_ZA";
break;
case ELangAlbanian:
locale = "sq_AL";
break;
case ELangAmharic:
locale = "am_ET";
break;
case ELangArabic:
locale = "ar_SA";
break;
case ELangArmenian:
locale = "hy_AM";
break;
case ELangAzerbaijani:
locale = "az_AZ";
break;
case ELangBelarussian:
locale = "be_BY";
break;
case ELangBengali:
locale = "bn_IN";
break;
case ELangBulgarian:
locale = "bg_BG";
break;
case ELangBurmese:
locale = "my_MM";
break;
case ELangCatalan:
locale = "ca_ES";
break;
case ELangCroatian:
locale = "hr_HR";
break;
case ELangEstonian:
locale = "et_EE";
break;
case ELangFarsi:
locale = "fa_IR";
break;
case ELangCanadianFrench:
locale = "fr_CA";
break;
case ELangScotsGaelic:
locale = "gd_GB";
break;
case ELangGeorgian:
locale = "ka_GE";
break;
case ELangGreek:
case ELangCyprusGreek:
locale = "el_GR";
break;
case ELangGujarati:
locale = "gu_IN";
break;
case ELangHebrew:
locale = "he_IL";
break;
case ELangHindi:
locale = "hi_IN";
break;
case ELangIndonesian:
locale = "id_ID";
break;
case ELangIrish:
locale = "ga_IE";
break;
case ELangKannada:
locale = "kn_IN";
break;
case ELangKazakh:
locale = "kk_KZ";
break;
case ELangKhmer:
locale = "km_KH";
break;
case ELangKorean:
locale = "ko_KR";
break;
case ELangLao:
locale = "lo_LA";
break;
case ELangLatvian:
locale = "lv_LV";
break;
case ELangLithuanian:
locale = "lt_LT";
break;
case ELangMacedonian:
locale = "mk_MK";
break;
case ELangMalay:
locale = "ms_MY";
break;
case ELangMalayalam:
locale = "ml_IN";
break;
case ELangMarathi:
locale = "mr_IN";
break;
case ELangMoldavian:
locale = "ro_MD";
break;
case ELangMongolian:
locale = "mn_MN";
break;
case ELangPunjabi:
locale = "pa_IN";
break;
case ELangRomanian:
locale = "ro_RO";
break;
case ELangSerbian:
locale = "sr_RS";
break;
case ELangSinhalese:
locale = "si_LK";
break;
case ELangSomali:
locale = "so_SO";
break;
case ELangSwahili:
locale = "sw_KE";
break;
case ELangTajik:
locale = "tg_TJ";
break;
case ELangTamil:
locale = "ta_IN";
break;
case ELangTelugu:
locale = "te_IN";
break;
case ELangTibetan:
locale = "bo_CN";
break;
case ELangTigrinya:
locale = "ti_ET";
break;
case ELangTurkmen:
locale = "tk_TM";
break;
case ELangUkrainian:
locale = "uk_UA";
break;
case ELangUrdu:
locale = "ur_PK";
break;
case ELangUzbek:
locale = "uz_UZ";
break;
case ELangVietnamese:
locale = "vi_VN";
break;
case ELangWelsh:
locale = "cy_GB";
break;
case ELangZulu:
locale = "zu_ZA";
break;
case ELangEnglish:
locale = "en_GB";
break;
case ELangAmerican:
case ELangCanadianEnglish:
case ELangInternationalEnglish:
case ELangSouthAfricanEnglish:
default:
locale = "en_US";
break;
}
SDL_strlcpy(buf, locale, buflen);
return true;
}

View File

@@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_PLATFORM_NGAGE
int SDL_EnterAppMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)
{
// Intentionally does nothing; Callbacks are called using the RunL() method.
return 0;
}
#endif // SDL_PLATFORM_NGAGE

View File

@@ -0,0 +1,199 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "SDL_internal.h"
extern SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]);
extern SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event);
extern SDL_AppResult SDL_AppIterate(void* appstate);
extern void SDL_AppQuit(void* appstate, SDL_AppResult result);
#ifdef __cplusplus
}
#endif
#include <e32std.h>
#include <estlib.h>
#include <stdlib.h>
#include <stdio.h>
#include "SDL_sysmain_main.hpp"
#include "../../audio/ngage/SDL_ngageaudio.hpp"
#include "../../render/ngage/SDL_render_ngage_c.hpp"
CRenderer *gRenderer = 0;
GLDEF_C TInt E32Main()
{
// Get args and environment.
int argc = 1;
char* argv[] = { "game", NULL };
char** envp = NULL;
// Create lvalue variables for __crt0 arguments.
char** argv_lvalue = argv;
char** envp_lvalue = envp;
CTrapCleanup* cleanup = CTrapCleanup::New();
if (!cleanup)
{
return KErrNoMemory;
}
TRAPD(err,
{
CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
CleanupStack::PushL(scheduler);
CActiveScheduler::Install(scheduler);
TInt posixErr = SpawnPosixServerThread();
if (posixErr != KErrNone)
{
SDL_Log("Error: Failed to spawn POSIX server thread: %d", posixErr);
User::Leave(posixErr);
}
__crt0(argc, argv_lvalue, envp_lvalue);
// Increase heap size.
RHeap* newHeap = User::ChunkHeap(NULL, 7500000, 7500000, KMinHeapGrowBy);
if (!newHeap)
{
SDL_Log("Error: Failed to create new heap");
User::Leave(KErrNoMemory);
}
CleanupStack::PushL(newHeap);
RHeap* oldHeap = User::SwitchHeap(newHeap);
TInt targetLatency = 225;
InitAudio(&targetLatency);
// Wait until audio is ready.
while (!AudioIsReady())
{
User::After(100000); // 100ms.
}
// Create and start the rendering backend.
gRenderer = CRenderer::NewL();
CleanupStack::PushL(gRenderer);
// Create and start the SDL main runner.
CSDLmain* mainApp = CSDLmain::NewL();
CleanupStack::PushL(mainApp);
mainApp->Start();
// Start the active scheduler to handle events.
CActiveScheduler::Start();
CleanupStack::PopAndDestroy(gRenderer);
CleanupStack::PopAndDestroy(mainApp);
User::SwitchHeap(oldHeap);
CleanupStack::PopAndDestroy(newHeap);
CleanupStack::PopAndDestroy(scheduler);
});
if (err != KErrNone)
{
SDL_Log("Error: %d", err);
}
return err;
}
CSDLmain* CSDLmain::NewL()
{
CSDLmain* self = new (ELeave) CSDLmain();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CSDLmain::CSDLmain() : CActive(EPriorityLow) {}
void CSDLmain::ConstructL()
{
CActiveScheduler::Add(this);
}
CSDLmain::~CSDLmain()
{
Cancel();
}
void CSDLmain::Start()
{
SetActive();
TRequestStatus* status = &iStatus;
User::RequestComplete(status, KErrNone);
}
void CSDLmain::DoCancel() {}
static bool callbacks_initialized = false;
void CSDLmain::RunL()
{
if (callbacks_initialized)
{
SDL_Event event;
iResult = SDL_AppIterate(NULL);
if (iResult != SDL_APP_CONTINUE)
{
DeinitAudio();
SDL_AppQuit(NULL, iResult);
SDL_Quit();
CActiveScheduler::Stop();
return;
}
SDL_PumpEvents();
if (SDL_PollEvent(&event))
{
iResult = SDL_AppEvent(NULL, &event);
if (iResult != SDL_APP_CONTINUE)
{
DeinitAudio();
SDL_AppQuit(NULL, iResult);
SDL_Quit();
CActiveScheduler::Stop();
return;
}
}
Start();
}
else
{
SDL_SetMainReady();
SDL_AppInit(NULL, 0, NULL);
callbacks_initialized = true;
Start();
}
}

View File

@@ -0,0 +1,46 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_sysmain_main_hpp_
#define SDL_sysmain_main_hpp_
#include <e32std.h>
class CSDLmain : public CActive
{
public:
static CSDLmain* NewL();
~CSDLmain();
void Start();
protected:
void DoCancel() ;
void RunL();
private:
CSDLmain();
void ConstructL();
SDL_AppResult iResult;
};
#endif // SDL_sysmain_main_hpp_

View File

@@ -120,6 +120,9 @@ static const SDL_RenderDriver *render_drivers[] = {
#ifdef SDL_VIDEO_RENDER_METAL
&METAL_RenderDriver,
#endif
#ifdef SDL_VIDEO_RENDER_NGAGE
&NGAGE_RenderDriver,
#endif
#ifdef SDL_VIDEO_RENDER_OGL
&GL_RenderDriver,
#endif

View File

@@ -357,6 +357,7 @@ extern SDL_RenderDriver D3D12_RenderDriver;
extern SDL_RenderDriver GL_RenderDriver;
extern SDL_RenderDriver GLES2_RenderDriver;
extern SDL_RenderDriver METAL_RenderDriver;
extern SDL_RenderDriver NGAGE_RenderDriver;
extern SDL_RenderDriver VULKAN_RenderDriver;
extern SDL_RenderDriver PS2_RenderDriver;
extern SDL_RenderDriver PSP_RenderDriver;

View File

@@ -0,0 +1,544 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_RENDER_NGAGE
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifndef Int2Fix
#define Int2Fix(i) ((i) << 16)
#endif
#ifndef Fix2Int
#define Fix2Int(i) ((((unsigned int)(i) > 0xFFFF0000) ? 0 : ((i) >> 16)))
#endif
#ifndef Fix2Real
#define Fix2Real(i) ((i) / 65536.0)
#endif
#ifndef Real2Fix
#define Real2Fix(i) ((int)((i) * 65536.0))
#endif
#include "../SDL_sysrender.h"
#include "SDL_render_ngage_c.h"
static void NGAGE_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event);
static bool NGAGE_GetOutputSize(SDL_Renderer *renderer, int *w, int *h);
static bool NGAGE_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode);
static bool NGAGE_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props);
static bool NGAGE_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd);
static bool NGAGE_QueueSetDrawColor(SDL_Renderer *renderer, SDL_RenderCommand *cmd);
static bool NGAGE_QueueDrawVertices(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count);
static bool NGAGE_QueueFillRects(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, int count);
static bool NGAGE_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const SDL_FRect *srcrect, const SDL_FRect *dstrect);
static bool NGAGE_QueueCopyEx(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const SDL_FRect *srcquad, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y);
static bool NGAGE_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, int num_vertices, const void *indices, int num_indices, int size_indices, float scale_x, float scale_y);
static void NGAGE_InvalidateCachedState(SDL_Renderer *renderer);
static bool NGAGE_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize);
static bool NGAGE_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch);
static bool NGAGE_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch);
static void NGAGE_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture);
static void NGAGE_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode);
static bool NGAGE_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture);
static SDL_Surface *NGAGE_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect);
static bool NGAGE_RenderPresent(SDL_Renderer *renderer);
static void NGAGE_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture);
static void NGAGE_DestroyRenderer(SDL_Renderer *renderer);
static bool NGAGE_SetVSync(SDL_Renderer *renderer, int vsync);
static bool NGAGE_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
{
SDL_SetupRendererColorspace(renderer, create_props);
if (renderer->output_colorspace != SDL_COLORSPACE_RGB_DEFAULT) {
return SDL_SetError("Unsupported output colorspace");
}
NGAGE_RendererData *phdata = SDL_calloc(1, sizeof(NGAGE_RendererData));
if (!phdata) {
SDL_OutOfMemory();
return false;
}
renderer->WindowEvent = NGAGE_WindowEvent;
renderer->GetOutputSize = NGAGE_GetOutputSize;
renderer->SupportsBlendMode = NGAGE_SupportsBlendMode;
renderer->CreateTexture = NGAGE_CreateTexture;
renderer->QueueSetViewport = NGAGE_QueueSetViewport;
renderer->QueueSetDrawColor = NGAGE_QueueSetDrawColor;
renderer->QueueDrawPoints = NGAGE_QueueDrawVertices;
renderer->QueueDrawLines = NGAGE_QueueDrawVertices;
renderer->QueueFillRects = NGAGE_QueueFillRects;
renderer->QueueCopy = NGAGE_QueueCopy;
renderer->QueueCopyEx = NGAGE_QueueCopyEx;
renderer->QueueGeometry = NGAGE_QueueGeometry;
renderer->InvalidateCachedState = NGAGE_InvalidateCachedState;
renderer->RunCommandQueue = NGAGE_RunCommandQueue;
renderer->UpdateTexture = NGAGE_UpdateTexture;
renderer->LockTexture = NGAGE_LockTexture;
renderer->UnlockTexture = NGAGE_UnlockTexture;
// renderer->SetTextureScaleMode = NGAGE_SetTextureScaleMode;
renderer->SetRenderTarget = NGAGE_SetRenderTarget;
renderer->RenderReadPixels = NGAGE_RenderReadPixels;
renderer->RenderPresent = NGAGE_RenderPresent;
renderer->DestroyTexture = NGAGE_DestroyTexture;
renderer->DestroyRenderer = NGAGE_DestroyRenderer;
renderer->SetVSync = NGAGE_SetVSync;
renderer->name = NGAGE_RenderDriver.name;
renderer->window = window;
renderer->internal = phdata;
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB4444);
SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 256);
SDL_SetHintWithPriority(SDL_HINT_RENDER_LINE_METHOD, "2", SDL_HINT_OVERRIDE);
return true;
}
SDL_RenderDriver NGAGE_RenderDriver = {
NGAGE_CreateRenderer,
"N-Gage"
};
static void NGAGE_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event)
{
return;
}
static bool NGAGE_GetOutputSize(SDL_Renderer *renderer, int *w, int *h)
{
return true;
}
static bool NGAGE_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode)
{
switch (blendMode) {
case SDL_BLENDMODE_NONE:
case SDL_BLENDMODE_MOD:
return true;
default:
return false;
}
}
static bool NGAGE_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
{
NGAGE_TextureData *data = (NGAGE_TextureData *)SDL_calloc(1, sizeof(*data));
if (!data) {
return false;
}
if (!NGAGE_CreateTextureData(data, texture->w, texture->h)) {
SDL_free(data);
return false;
}
SDL_Surface *surface = SDL_CreateSurface(texture->w, texture->h, texture->format);
if (!surface) {
SDL_free(data);
return false;
}
data->surface = surface;
texture->internal = data;
return true;
}
static bool NGAGE_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
{
if (!cmd->data.viewport.rect.w && !cmd->data.viewport.rect.h) {
SDL_Rect viewport = { 0, 0, NGAGE_SCREEN_WIDTH, NGAGE_SCREEN_HEIGHT };
SDL_SetRenderViewport(renderer, &viewport);
}
return true;
}
static bool NGAGE_QueueSetDrawColor(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
{
return true;
}
static bool NGAGE_QueueDrawVertices(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
{
NGAGE_Vertex *verts = (NGAGE_Vertex *)SDL_AllocateRenderVertices(renderer, count * sizeof(NGAGE_Vertex), 0, &cmd->data.draw.first);
if (!verts) {
return false;
}
cmd->data.draw.count = count;
for (int i = 0; i < count; i++, points++) {
int fixed_x = Real2Fix(points->x);
int fixed_y = Real2Fix(points->y);
verts[i].x = Fix2Int(fixed_x);
verts[i].y = Fix2Int(fixed_y);
Uint32 color = NGAGE_ConvertColor(cmd->data.draw.color.r, cmd->data.draw.color.g, cmd->data.draw.color.b, cmd->data.draw.color.a, cmd->data.draw.color_scale);
verts[i].color.a = (Uint8)(color >> 24);
verts[i].color.b = (Uint8)(color >> 16);
verts[i].color.g = (Uint8)(color >> 8);
verts[i].color.r = (Uint8)color;
}
return true;
}
static bool NGAGE_QueueFillRects(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, int count)
{
NGAGE_Vertex *verts = (NGAGE_Vertex *)SDL_AllocateRenderVertices(renderer, count * 2 * sizeof(NGAGE_Vertex), 0, &cmd->data.draw.first);
if (!verts) {
return false;
}
cmd->data.draw.count = count;
for (int i = 0; i < count; i++, rects++) {
verts[i * 2].x = Real2Fix(rects->x);
verts[i * 2].y = Real2Fix(rects->y);
verts[i * 2 + 1].x = Real2Fix(rects->w);
verts[i * 2 + 1].y = Real2Fix(rects->h);
verts[i * 2].x = Fix2Int(verts[i * 2].x);
verts[i * 2].y = Fix2Int(verts[i * 2].y);
verts[i * 2 + 1].x = Fix2Int(verts[i * 2 + 1].x);
verts[i * 2 + 1].y = Fix2Int(verts[i * 2 + 1].y);
Uint32 color = NGAGE_ConvertColor(cmd->data.draw.color.r, cmd->data.draw.color.g, cmd->data.draw.color.b, cmd->data.draw.color.a, cmd->data.draw.color_scale);
verts[i * 2].color.a = (Uint8)(color >> 24);
verts[i * 2].color.b = (Uint8)(color >> 16);
verts[i * 2].color.g = (Uint8)(color >> 8);
verts[i * 2].color.r = (Uint8)color;
}
return true;
}
static bool NGAGE_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const SDL_FRect *srcrect, const SDL_FRect *dstrect)
{
SDL_Rect *verts = (SDL_Rect *)SDL_AllocateRenderVertices(renderer, 2 * sizeof(SDL_Rect), 0, &cmd->data.draw.first);
if (!verts) {
return false;
}
cmd->data.draw.count = 1;
verts->x = (int)srcrect->x;
verts->y = (int)srcrect->y;
verts->w = (int)srcrect->w;
verts->h = (int)srcrect->h;
verts++;
verts->x = (int)dstrect->x;
verts->y = (int)dstrect->y;
verts->w = (int)dstrect->w;
verts->h = (int)dstrect->h;
return true;
}
static bool NGAGE_QueueCopyEx(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const SDL_FRect *srcquad, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y)
{
NGAGE_CopyExData *verts = (NGAGE_CopyExData *)SDL_AllocateRenderVertices(renderer, sizeof(NGAGE_CopyExData), 0, &cmd->data.draw.first);
if (!verts) {
return false;
}
cmd->data.draw.count = 1;
verts->srcrect.x = (int)srcquad->x;
verts->srcrect.y = (int)srcquad->y;
verts->srcrect.w = (int)srcquad->w;
verts->srcrect.h = (int)srcquad->h;
verts->dstrect.x = (int)dstrect->x;
verts->dstrect.y = (int)dstrect->y;
verts->dstrect.w = (int)dstrect->w;
verts->dstrect.h = (int)dstrect->h;
verts->angle = Real2Fix(angle);
verts->center.x = Real2Fix(center->x);
verts->center.y = Real2Fix(center->y);
verts->scale_x = Real2Fix(scale_x);
verts->scale_y = Real2Fix(scale_y);
verts->flip = flip;
return true;
}
static bool NGAGE_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, int num_vertices, const void *indices, int num_indices, int size_indices, float scale_x, float scale_y)
{
return true;
}
static void NGAGE_InvalidateCachedState(SDL_Renderer *renderer)
{
return;
}
static bool NGAGE_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
{
NGAGE_RendererData *phdata = (NGAGE_RendererData *)renderer->internal;
if (!phdata) {
return false;
}
phdata->viewport = 0;
while (cmd) {
switch (cmd->command) {
case SDL_RENDERCMD_NO_OP:
break;
case SDL_RENDERCMD_SETVIEWPORT:
phdata->viewport = &cmd->data.viewport.rect;
break;
case SDL_RENDERCMD_SETCLIPRECT:
{
const SDL_Rect *rect = &cmd->data.cliprect.rect;
if (cmd->data.cliprect.enabled) {
NGAGE_SetClipRect(rect);
}
break;
}
case SDL_RENDERCMD_SETDRAWCOLOR:
{
break;
}
case SDL_RENDERCMD_CLEAR:
{
Uint32 color = NGAGE_ConvertColor(cmd->data.color.color.r, cmd->data.color.color.g, cmd->data.color.color.b, cmd->data.color.color.a, cmd->data.color.color_scale);
NGAGE_Clear(color);
break;
}
case SDL_RENDERCMD_DRAW_POINTS:
{
NGAGE_Vertex *verts = (NGAGE_Vertex *)(((Uint8 *)vertices) + cmd->data.draw.first);
const int count = cmd->data.draw.count;
// Apply viewport.
if (phdata->viewport && (phdata->viewport->x || phdata->viewport->y)) {
for (int i = 0; i < count; i++) {
verts[i].x += phdata->viewport->x;
verts[i].y += phdata->viewport->y;
}
}
NGAGE_DrawPoints(verts, count);
break;
}
case SDL_RENDERCMD_DRAW_LINES:
{
NGAGE_Vertex *verts = (NGAGE_Vertex *)(((Uint8 *)vertices) + cmd->data.draw.first);
const int count = cmd->data.draw.count;
// Apply viewport.
if (phdata->viewport && (phdata->viewport->x || phdata->viewport->y)) {
for (int i = 0; i < count; i++) {
verts[i].x += phdata->viewport->x;
verts[i].y += phdata->viewport->y;
}
}
NGAGE_DrawLines(verts, count);
break;
}
case SDL_RENDERCMD_FILL_RECTS:
{
NGAGE_Vertex *verts = (NGAGE_Vertex *)(((Uint8 *)vertices) + cmd->data.draw.first);
const int count = cmd->data.draw.count;
// Apply viewport.
if (phdata->viewport && (phdata->viewport->x || phdata->viewport->y)) {
for (int i = 0; i < count; i++) {
verts[i].x += phdata->viewport->x;
verts[i].y += phdata->viewport->y;
}
}
NGAGE_FillRects(verts, count);
break;
}
case SDL_RENDERCMD_COPY:
{
SDL_Rect *verts = (SDL_Rect *)(((Uint8 *)vertices) + cmd->data.draw.first);
SDL_Rect *srcrect = verts;
SDL_Rect *dstrect = verts + 1;
SDL_Texture *texture = cmd->data.draw.texture;
// Apply viewport.
if (phdata->viewport && (phdata->viewport->x || phdata->viewport->y)) {
dstrect->x += phdata->viewport->x;
dstrect->y += phdata->viewport->y;
}
NGAGE_Copy(renderer, texture, srcrect, dstrect);
break;
}
case SDL_RENDERCMD_COPY_EX:
{
NGAGE_CopyExData *copydata = (NGAGE_CopyExData *)(((Uint8 *)vertices) + cmd->data.draw.first);
SDL_Texture *texture = cmd->data.draw.texture;
// Apply viewport.
if (phdata->viewport && (phdata->viewport->x || phdata->viewport->y)) {
copydata->dstrect.x += phdata->viewport->x;
copydata->dstrect.y += phdata->viewport->y;
}
NGAGE_CopyEx(renderer, texture, copydata);
break;
}
case SDL_RENDERCMD_GEOMETRY:
{
break;
}
}
cmd = cmd->next;
}
return true;
}
static bool NGAGE_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch)
{
NGAGE_TextureData *phdata = (NGAGE_TextureData *)texture->internal;
SDL_Surface *surface = phdata->surface;
Uint8 *src, *dst;
int row;
size_t length;
if (SDL_MUSTLOCK(surface)) {
if (!SDL_LockSurface(surface)) {
return false;
}
}
src = (Uint8 *)pixels;
dst = (Uint8 *)surface->pixels +
rect->y * surface->pitch +
rect->x * surface->fmt->bytes_per_pixel;
length = (size_t)rect->w * surface->fmt->bytes_per_pixel;
for (row = 0; row < rect->h; ++row) {
SDL_memcpy(dst, src, length);
src += pitch;
dst += surface->pitch;
}
if (SDL_MUSTLOCK(surface)) {
SDL_UnlockSurface(surface);
}
return true;
}
static bool NGAGE_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch)
{
NGAGE_TextureData *phdata = (NGAGE_TextureData *)texture->internal;
SDL_Surface *surface = phdata->surface;
*pixels =
(void *)((Uint8 *)surface->pixels + rect->y * surface->pitch +
rect->x * surface->fmt->bytes_per_pixel);
*pitch = surface->pitch;
return true;
}
static void NGAGE_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
{
}
static void NGAGE_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
{
}
static bool NGAGE_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
{
return true;
}
static SDL_Surface *NGAGE_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect)
{
return (SDL_Surface *)0;
}
static bool NGAGE_RenderPresent(SDL_Renderer *renderer)
{
NGAGE_Flip();
return true;
}
static void NGAGE_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
{
NGAGE_TextureData *data = (NGAGE_TextureData *)texture->internal;
if (data) {
SDL_DestroySurface(data->surface);
NGAGE_DestroyTextureData(data);
SDL_free(data);
texture->internal = 0;
}
}
static void NGAGE_DestroyRenderer(SDL_Renderer *renderer)
{
NGAGE_RendererData *phdata = (NGAGE_RendererData *)renderer->internal;
if (phdata) {
SDL_free(phdata);
renderer->internal = 0;
}
}
static bool NGAGE_SetVSync(SDL_Renderer *renderer, int vsync)
{
return true;
}
#endif // SDL_VIDEO_RENDER_NGAGE

View File

@@ -0,0 +1,744 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "../../events/SDL_keyboard_c.h"
#include "../SDL_sysrender.h"
#include "SDL_internal.h"
#include "SDL_render_ngage_c.h"
#ifdef __cplusplus
}
#endif
#ifdef SDL_VIDEO_RENDER_NGAGE
#include "SDL_render_ngage_c.hpp"
#include "SDL_render_ops.hpp"
const TUint32 WindowClientHandle = 0x571D0A;
extern CRenderer *gRenderer;
#ifdef __cplusplus
extern "C" {
#endif
void NGAGE_Clear(const Uint32 color)
{
gRenderer->Clear(color);
}
bool NGAGE_Copy(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Rect *srcrect, SDL_Rect *dstrect)
{
return gRenderer->Copy(renderer, texture, srcrect, dstrect);
}
bool NGAGE_CopyEx(SDL_Renderer *renderer, SDL_Texture *texture, NGAGE_CopyExData *copydata)
{
return gRenderer->CopyEx(renderer, texture, copydata);
}
bool NGAGE_CreateTextureData(NGAGE_TextureData *data, const int width, const int height)
{
return gRenderer->CreateTextureData(data, width, height);
}
void NGAGE_DestroyTextureData(NGAGE_TextureData *data)
{
if (data) {
delete data->bitmap;
data->bitmap = NULL;
}
}
void NGAGE_DrawLines(NGAGE_Vertex *verts, const int count)
{
gRenderer->DrawLines(verts, count);
}
void NGAGE_DrawPoints(NGAGE_Vertex *verts, const int count)
{
gRenderer->DrawPoints(verts, count);
}
void NGAGE_FillRects(NGAGE_Vertex *verts, const int count)
{
gRenderer->FillRects(verts, count);
}
void NGAGE_Flip()
{
gRenderer->Flip();
}
void NGAGE_SetClipRect(const SDL_Rect *rect)
{
gRenderer->SetClipRect(rect->x, rect->y, rect->w, rect->h);
}
void NGAGE_SetDrawColor(const Uint32 color)
{
if (gRenderer) {
gRenderer->SetDrawColor(color);
}
}
void NGAGE_PumpEventsInternal()
{
gRenderer->PumpEvents();
}
void NGAGE_SuspendScreenSaverInternal(bool suspend)
{
gRenderer->SuspendScreenSaver(suspend);
}
#ifdef __cplusplus
}
#endif
CRenderer *CRenderer::NewL()
{
CRenderer *self = new (ELeave) CRenderer();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CRenderer::CRenderer() : iRenderer(0), iDirectScreen(0), iScreenGc(0), iWsSession(), iWsWindowGroup(), iWsWindowGroupID(0), iWsWindow(), iWsScreen(0), iWsEventStatus(), iWsEvent(), iShowFPS(EFalse), iFPS(0), iFont(0) {}
CRenderer::~CRenderer()
{
delete iRenderer;
iRenderer = 0;
}
void CRenderer::ConstructL()
{
TInt error = KErrNone;
error = iWsSession.Connect();
if (error != KErrNone) {
SDL_Log("Failed to connect to window server: %d", error);
User::Leave(error);
}
iWsScreen = new (ELeave) CWsScreenDevice(iWsSession);
error = iWsScreen->Construct();
if (error != KErrNone) {
SDL_Log("Failed to construct screen device: %d", error);
User::Leave(error);
}
iWsWindowGroup = RWindowGroup(iWsSession);
error = iWsWindowGroup.Construct(WindowClientHandle);
if (error != KErrNone) {
SDL_Log("Failed to construct window group: %d", error);
User::Leave(error);
}
iWsWindowGroup.SetOrdinalPosition(0);
RProcess thisProcess;
TParse exeName;
exeName.Set(thisProcess.FileName(), NULL, NULL);
TBuf<32> winGroupName;
winGroupName.Append(0);
winGroupName.Append(0);
winGroupName.Append(0); // UID
winGroupName.Append(0);
winGroupName.Append(exeName.Name()); // Caption
winGroupName.Append(0);
winGroupName.Append(0); // DOC name
iWsWindowGroup.SetName(winGroupName);
iWsWindow = RWindow(iWsSession);
error = iWsWindow.Construct(iWsWindowGroup, WindowClientHandle - 1);
if (error != KErrNone) {
SDL_Log("Failed to construct window: %d", error);
User::Leave(error);
}
iWsWindow.SetBackgroundColor(KRgbWhite);
iWsWindow.SetRequiredDisplayMode(EColor4K);
iWsWindow.Activate();
iWsWindow.SetSize(iWsScreen->SizeInPixels());
iWsWindow.SetVisible(ETrue);
iWsWindowGroupID = iWsWindowGroup.Identifier();
TRAPD(errc, iRenderer = iRenderer->NewL());
if (errc != KErrNone) {
SDL_Log("Failed to create renderer: %d", errc);
return;
}
iDirectScreen = CDirectScreenAccess::NewL(
iWsSession,
*(iWsScreen),
iWsWindow, *this);
// Select font.
TFontSpec fontSpec(_L("LatinBold12"), 12);
TInt errd = iWsScreen->GetNearestFontInTwips((CFont *&)iFont, fontSpec);
if (errd != KErrNone) {
SDL_Log("Failed to get font: %d", errd);
return;
}
// Activate events.
iWsEventStatus = KRequestPending;
iWsSession.EventReady(&iWsEventStatus);
DisableKeyBlocking();
iIsFocused = ETrue;
iShowFPS = EFalse;
iSuspendScreenSaver = EFalse;
if (!iDirectScreen->IsActive()) {
TRAPD(err, iDirectScreen->StartL());
if (KErrNone != err) {
return;
}
iDirectScreen->ScreenDevice()->SetAutoUpdate(ETrue);
}
}
void CRenderer::Restart(RDirectScreenAccess::TTerminationReasons aReason)
{
if (!iDirectScreen->IsActive()) {
TRAPD(err, iDirectScreen->StartL());
if (KErrNone != err) {
return;
}
iDirectScreen->ScreenDevice()->SetAutoUpdate(ETrue);
}
}
void CRenderer::AbortNow(RDirectScreenAccess::TTerminationReasons aReason)
{
if (iDirectScreen->IsActive()) {
iDirectScreen->Cancel();
}
}
void CRenderer::Clear(TUint32 iColor)
{
if (iRenderer && iRenderer->Gc()) {
iRenderer->Gc()->SetBrushColor(iColor);
iRenderer->Gc()->Clear();
}
}
#ifdef __cplusplus
extern "C" {
#endif
Uint32 NGAGE_ConvertColor(float r, float g, float b, float a, float color_scale)
{
TFixed ff = 255 << 16; // 255.f
TFixed scalef = Real2Fix(color_scale);
TFixed rf = Real2Fix(r);
TFixed gf = Real2Fix(g);
TFixed bf = Real2Fix(b);
TFixed af = Real2Fix(a);
rf = FixMul(rf, scalef);
gf = FixMul(gf, scalef);
bf = FixMul(bf, scalef);
rf = SDL_clamp(rf, 0, ff);
gf = SDL_clamp(gf, 0, ff);
bf = SDL_clamp(bf, 0, ff);
af = SDL_clamp(af, 0, ff);
rf = FixMul(rf, ff) >> 16;
gf = FixMul(gf, ff) >> 16;
bf = FixMul(bf, ff) >> 16;
af = FixMul(af, ff) >> 16;
return (af << 24) | (bf << 16) | (gf << 8) | rf;
}
#ifdef __cplusplus
}
#endif
bool CRenderer::Copy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, const SDL_Rect *dstrect)
{
if (!texture) {
return false;
}
NGAGE_TextureData *phdata = (NGAGE_TextureData *)texture->internal;
if (!phdata) {
return false;
}
SDL_FColor *c = &texture->color;
int w = phdata->surface->w;
int h = phdata->surface->h;
int pitch = phdata->surface->pitch;
void *source = phdata->surface->pixels;
void *dest;
if (!source) {
return false;
}
void *pixel_buffer_a = SDL_calloc(1, pitch * h);
if (!pixel_buffer_a) {
return false;
}
dest = pixel_buffer_a;
void *pixel_buffer_b = SDL_calloc(1, pitch * h);
if (!pixel_buffer_b) {
SDL_free(pixel_buffer_a);
return false;
}
if (c->a != 1.f || c->r != 1.f || c->g != 1.f || c->b != 1.f) {
ApplyColorMod(dest, source, pitch, w, h, texture->color);
source = dest;
}
float sx;
float sy;
SDL_GetRenderScale(renderer, &sx, &sy);
if (sx != 1.f || sy != 1.f) {
TFixed scale_x = Real2Fix(sx);
TFixed scale_y = Real2Fix(sy);
TFixed center_x = Int2Fix(w / 2);
TFixed center_y = Int2Fix(h / 2);
dest == pixel_buffer_a ? dest = pixel_buffer_b : dest = pixel_buffer_a;
ApplyScale(dest, source, pitch, w, h, center_x, center_y, scale_x, scale_y);
source = dest;
}
Mem::Copy(phdata->bitmap->DataAddress(), source, pitch * h);
SDL_free(pixel_buffer_a);
SDL_free(pixel_buffer_b);
if (phdata->bitmap) {
TRect aSource(TPoint(srcrect->x, srcrect->y), TSize(srcrect->w, srcrect->h));
TPoint aDest(dstrect->x, dstrect->y);
iRenderer->Gc()->BitBlt(aDest, phdata->bitmap, aSource);
}
return true;
}
bool CRenderer::CopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const NGAGE_CopyExData *copydata)
{
NGAGE_TextureData *phdata = (NGAGE_TextureData *)texture->internal;
if (!phdata) {
return false;
}
SDL_FColor *c = &texture->color;
int w = phdata->surface->w;
int h = phdata->surface->h;
int pitch = phdata->surface->pitch;
void *source = phdata->surface->pixels;
void *dest;
if (!source) {
return false;
}
void *pixel_buffer_a = SDL_calloc(1, pitch * h);
if (!pixel_buffer_a) {
return false;
}
dest = pixel_buffer_a;
void *pixel_buffer_b = SDL_calloc(1, pitch * h);
if (!pixel_buffer_a) {
SDL_free(pixel_buffer_a);
return false;
}
if (copydata->flip) {
ApplyFlip(dest, source, pitch, w, h, copydata->flip);
source = dest;
}
if (copydata->scale_x != 1.f || copydata->scale_y != 1.f) {
dest == pixel_buffer_a ? dest = pixel_buffer_b : dest = pixel_buffer_a;
ApplyScale(dest, source, pitch, w, h, copydata->center.x, copydata->center.y, copydata->scale_x, copydata->scale_y);
source = dest;
}
if (copydata->angle) {
dest == pixel_buffer_a ? dest = pixel_buffer_b : dest = pixel_buffer_a;
ApplyRotation(dest, source, pitch, w, h, copydata->center.x, copydata->center.y, copydata->angle);
source = dest;
}
if (c->a != 1.f || c->r != 1.f || c->g != 1.f || c->b != 1.f) {
dest == pixel_buffer_a ? dest = pixel_buffer_b : dest = pixel_buffer_a;
ApplyColorMod(dest, source, pitch, w, h, texture->color);
source = dest;
}
Mem::Copy(phdata->bitmap->DataAddress(), source, pitch * h);
SDL_free(pixel_buffer_a);
SDL_free(pixel_buffer_b);
if (phdata->bitmap) {
TRect aSource(TPoint(copydata->srcrect.x, copydata->srcrect.y), TSize(copydata->srcrect.w, copydata->srcrect.h));
TPoint aDest(copydata->dstrect.x, copydata->dstrect.y);
iRenderer->Gc()->BitBlt(aDest, phdata->bitmap, aSource);
}
return true;
}
bool CRenderer::CreateTextureData(NGAGE_TextureData *aTextureData, const TInt aWidth, const TInt aHeight)
{
if (!aTextureData) {
return false;
}
aTextureData->bitmap = new CFbsBitmap();
if (!aTextureData->bitmap) {
return false;
}
TInt error = aTextureData->bitmap->Create(TSize(aWidth, aHeight), EColor4K);
if (error != KErrNone) {
delete aTextureData->bitmap;
aTextureData->bitmap = NULL;
return false;
}
return true;
}
void CRenderer::DrawLines(NGAGE_Vertex *aVerts, const TInt aCount)
{
if (iRenderer && iRenderer->Gc()) {
TPoint *aPoints = new TPoint[aCount];
for (TInt i = 0; i < aCount; i++) {
aPoints[i] = TPoint(aVerts[i].x, aVerts[i].y);
}
TUint32 aColor = (((TUint8)aVerts->color.a << 24) |
((TUint8)aVerts->color.b << 16) |
((TUint8)aVerts->color.g << 8) |
(TUint8)aVerts->color.r);
iRenderer->Gc()->SetPenColor(aColor);
iRenderer->Gc()->DrawPolyLineNoEndPoint(aPoints, aCount);
delete[] aPoints;
}
}
void CRenderer::DrawPoints(NGAGE_Vertex *aVerts, const TInt aCount)
{
if (iRenderer && iRenderer->Gc()) {
for (TInt i = 0; i < aCount; i++, aVerts++) {
TUint32 aColor = (((TUint8)aVerts->color.a << 24) |
((TUint8)aVerts->color.b << 16) |
((TUint8)aVerts->color.g << 8) |
(TUint8)aVerts->color.r);
iRenderer->Gc()->SetPenColor(aColor);
iRenderer->Gc()->Plot(TPoint(aVerts->x, aVerts->y));
}
}
}
void CRenderer::FillRects(NGAGE_Vertex *aVerts, const TInt aCount)
{
if (iRenderer && iRenderer->Gc()) {
for (TInt i = 0; i < aCount; i++, aVerts++) {
TPoint pos(aVerts[i].x, aVerts[i].y);
TSize size(
aVerts[i + 1].x,
aVerts[i + 1].y);
TRect rect(pos, size);
TUint32 aColor = (((TUint8)aVerts->color.a << 24) |
((TUint8)aVerts->color.b << 16) |
((TUint8)aVerts->color.g << 8) |
(TUint8)aVerts->color.r);
iRenderer->Gc()->SetPenColor(aColor);
iRenderer->Gc()->SetBrushColor(aColor);
iRenderer->Gc()->DrawRect(rect);
}
}
}
void CRenderer::Flip()
{
if (!iRenderer) {
SDL_Log("iRenderer is NULL.");
return;
}
if (!iIsFocused) {
return;
}
iRenderer->Gc()->UseFont(iFont);
if (iShowFPS && iRenderer->Gc()) {
UpdateFPS();
TBuf<64> info;
iRenderer->Gc()->SetPenStyle(CGraphicsContext::ESolidPen);
iRenderer->Gc()->SetBrushStyle(CGraphicsContext::ENullBrush);
iRenderer->Gc()->SetPenColor(KRgbCyan);
TRect aTextRect(TPoint(3, 203 - iFont->HeightInPixels()), TSize(45, iFont->HeightInPixels() + 2));
iRenderer->Gc()->SetBrushStyle(CGraphicsContext::ESolidBrush);
iRenderer->Gc()->SetBrushColor(KRgbBlack);
iRenderer->Gc()->DrawRect(aTextRect);
// Draw messages.
info.Format(_L("FPS: %d"), iFPS);
iRenderer->Gc()->DrawText(info, TPoint(5, 203));
} else {
// This is a workaround that helps regulating the FPS.
iRenderer->Gc()->DrawText(_L(""), TPoint(0, 0));
}
iRenderer->Gc()->DiscardFont();
iRenderer->Flip(iDirectScreen);
// Keep the backlight on.
if (iSuspendScreenSaver) {
User::ResetInactivityTime();
}
// Suspend the current thread for a short while.
// Give some time to other threads and active objects.
User::After(0);
}
void CRenderer::SetDrawColor(TUint32 iColor)
{
if (iRenderer && iRenderer->Gc()) {
iRenderer->Gc()->SetPenColor(iColor);
iRenderer->Gc()->SetBrushColor(iColor);
iRenderer->Gc()->SetBrushStyle(CGraphicsContext::ESolidBrush);
TRAPD(err, iRenderer->SetCurrentColor(iColor));
if (err != KErrNone) {
return;
}
}
}
void CRenderer::SetClipRect(TInt aX, TInt aY, TInt aWidth, TInt aHeight)
{
if (iRenderer && iRenderer->Gc()) {
TRect viewportRect(aX, aY, aX + aWidth, aY + aHeight);
iRenderer->Gc()->SetClippingRect(viewportRect);
}
}
void CRenderer::UpdateFPS()
{
static TTime lastTime;
static TInt frameCount = 0;
TTime currentTime;
const TUint KOneSecond = 1000000; // 1s in ms.
currentTime.HomeTime();
++frameCount;
TTimeIntervalMicroSeconds timeDiff = currentTime.MicroSecondsFrom(lastTime);
if (timeDiff.Int64() >= KOneSecond) {
// Calculate FPS.
iFPS = frameCount;
// Reset frame count and last time.
frameCount = 0;
lastTime = currentTime;
}
}
void CRenderer::SuspendScreenSaver(TBool aSuspend)
{
iSuspendScreenSaver = aSuspend;
}
static SDL_Scancode ConvertScancode(int key)
{
SDL_Keycode keycode;
switch (key) {
case EStdKeyBackspace: // Clear key
keycode = SDLK_BACKSPACE;
break;
case 0x31: // 1
keycode = SDLK_1;
break;
case 0x32: // 2
keycode = SDLK_2;
break;
case 0x33: // 3
keycode = SDLK_3;
break;
case 0x34: // 4
keycode = SDLK_4;
break;
case 0x35: // 5
keycode = SDLK_5;
break;
case 0x36: // 6
keycode = SDLK_6;
break;
case 0x37: // 7
keycode = SDLK_7;
break;
case 0x38: // 8
keycode = SDLK_8;
break;
case 0x39: // 9
keycode = SDLK_9;
break;
case 0x30: // 0
keycode = SDLK_0;
break;
case 0x2a: // Asterisk
keycode = SDLK_ASTERISK;
break;
case EStdKeyHash: // Hash
keycode = SDLK_HASH;
break;
case EStdKeyDevice0: // Left softkey
keycode = SDLK_SOFTLEFT;
break;
case EStdKeyDevice1: // Right softkey
keycode = SDLK_SOFTRIGHT;
break;
case EStdKeyApplication0: // Call softkey
keycode = SDLK_CALL;
break;
case EStdKeyApplication1: // End call softkey
keycode = SDLK_ENDCALL;
break;
case EStdKeyDevice3: // Middle softkey
keycode = SDLK_SELECT;
break;
case EStdKeyUpArrow: // Up arrow
keycode = SDLK_UP;
break;
case EStdKeyDownArrow: // Down arrow
keycode = SDLK_DOWN;
break;
case EStdKeyLeftArrow: // Left arrow
keycode = SDLK_LEFT;
break;
case EStdKeyRightArrow: // Right arrow
keycode = SDLK_RIGHT;
break;
default:
keycode = SDLK_UNKNOWN;
break;
}
return SDL_GetScancodeFromKey(keycode, NULL);
}
void CRenderer::HandleEvent(const TWsEvent &aWsEvent)
{
Uint64 timestamp;
switch (aWsEvent.Type()) {
case EEventKeyDown: /* Key events */
timestamp = SDL_GetPerformanceCounter();
SDL_SendKeyboardKey(timestamp, 1, aWsEvent.Key()->iCode, ConvertScancode(aWsEvent.Key()->iScanCode), true);
if (aWsEvent.Key()->iScanCode == EStdKeyHash) {
if (iShowFPS) {
iShowFPS = EFalse;
} else {
iShowFPS = ETrue;
}
}
break;
case EEventKeyUp: /* Key events */
timestamp = SDL_GetPerformanceCounter();
SDL_SendKeyboardKey(timestamp, 1, aWsEvent.Key()->iCode, ConvertScancode(aWsEvent.Key()->iScanCode), false);
case EEventFocusGained:
DisableKeyBlocking();
if (!iDirectScreen->IsActive()) {
TRAPD(err, iDirectScreen->StartL());
if (KErrNone != err) {
return;
}
iDirectScreen->ScreenDevice()->SetAutoUpdate(ETrue);
iIsFocused = ETrue;
}
Flip();
break;
case EEventFocusLost:
{
if (iDirectScreen->IsActive()) {
iDirectScreen->Cancel();
}
iIsFocused = EFalse;
break;
}
default:
break;
}
}
void CRenderer::DisableKeyBlocking()
{
TRawEvent aEvent;
aEvent.Set((TRawEvent::TType) /*EDisableKeyBlock*/ 51);
iWsSession.SimulateRawEvent(aEvent);
}
void CRenderer::PumpEvents()
{
while (iWsEventStatus != KRequestPending) {
iWsSession.GetEvent(iWsEvent);
HandleEvent(iWsEvent);
iWsEventStatus = KRequestPending;
iWsSession.EventReady(&iWsEventStatus);
}
}
#endif // SDL_VIDEO_RENDER_NGAGE

View File

@@ -0,0 +1,105 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef ngage_video_render_ngage_c_h
#define ngage_video_render_ngage_c_h
#define NGAGE_SCREEN_WIDTH 176
#define NGAGE_SCREEN_HEIGHT 208
#ifdef __cplusplus
extern "C" {
#endif
#include "../SDL_sysrender.h"
typedef struct NGAGE_RendererData
{
SDL_Rect *viewport;
} NGAGE_RendererData;
typedef struct NGAGE_Vertex
{
int x;
int y;
struct
{
Uint8 a;
Uint8 r;
Uint8 g;
Uint8 b;
} color;
} NGAGE_Vertex;
typedef struct CFbsBitmap CFbsBitmap;
typedef struct NGAGE_TextureData
{
CFbsBitmap *bitmap;
SDL_Surface *surface;
} NGAGE_TextureData;
typedef struct NGAGE_CopyExData
{
SDL_Rect srcrect;
SDL_Rect dstrect;
int angle;
struct
{
int x;
int y;
} center;
SDL_FlipMode flip;
int scale_x;
int scale_y;
} NGAGE_CopyExData;
void NGAGE_Clear(const Uint32 color);
Uint32 NGAGE_ConvertColor(float r, float g, float b, float a, float color_scale);
bool NGAGE_Copy(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Rect *srcrect, SDL_Rect *dstrect);
bool NGAGE_CopyEx(SDL_Renderer *renderer, SDL_Texture *texture, NGAGE_CopyExData *copydata);
bool NGAGE_CreateTextureData(NGAGE_TextureData *data, const int width, const int height);
void NGAGE_DestroyTextureData(NGAGE_TextureData *data);
void NGAGE_DrawLines(NGAGE_Vertex *verts, const int count);
void NGAGE_DrawPoints(NGAGE_Vertex *verts, const int count);
void NGAGE_FillRects(NGAGE_Vertex *verts, const int count);
void NGAGE_Flip(void);
void NGAGE_SetClipRect(const SDL_Rect *rect);
void NGAGE_SetDrawColor(const Uint32 color);
void NGAGE_PumpEventsInternal(void);
void NGAGE_SuspendScreenSaverInternal(bool suspend);
#ifdef __cplusplus
}
#endif
#endif // ngage_video_render_ngage_c_h

View File

@@ -0,0 +1,91 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef ngage_video_render_ngage_c_hpp
#define ngage_video_render_ngage_c_hpp
#include "SDL_render_ngage_c.h"
#include <NRenderer.h>
#include <e32std.h>
#include <w32std.h>
class CRenderer : public MDirectScreenAccess
{
public:
static CRenderer *NewL();
virtual ~CRenderer();
// Rendering functions.
void Clear(TUint32 iColor);
bool Copy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, const SDL_Rect *dstrect);
bool CopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const NGAGE_CopyExData *copydata);
bool CreateTextureData(NGAGE_TextureData *aTextureData, const TInt aWidth, const TInt aHeight);
void DrawLines(NGAGE_Vertex *aVerts, const TInt aCount);
void DrawPoints(NGAGE_Vertex *aVerts, const TInt aCount);
void FillRects(NGAGE_Vertex *aVerts, const TInt aCount);
void Flip();
void SetDrawColor(TUint32 iColor);
void SetClipRect(TInt aX, TInt aY, TInt aWidth, TInt aHeight);
void UpdateFPS();
void SuspendScreenSaver(TBool aSuspend);
// Event handling.
void DisableKeyBlocking();
void HandleEvent(const TWsEvent &aWsEvent);
void PumpEvents();
private:
CRenderer();
void ConstructL(void);
// BackBuffer.
CNRenderer *iRenderer;
// Direct screen access.
CDirectScreenAccess *iDirectScreen;
CFbsBitGc *iScreenGc;
TBool iIsFocused;
// Window server session.
RWsSession iWsSession;
RWindowGroup iWsWindowGroup;
TInt iWsWindowGroupID;
RWindow iWsWindow;
CWsScreenDevice *iWsScreen;
// Event handling.
TRequestStatus iWsEventStatus;
TWsEvent iWsEvent;
// MDirectScreenAccess functions.
void Restart(RDirectScreenAccess::TTerminationReasons aReason);
void AbortNow(RDirectScreenAccess::TTerminationReasons aReason);
// Frame per second.
TBool iShowFPS;
TUint iFPS;
const CFont *iFont;
// Screen saver.
TBool iSuspendScreenSaver;
};
#endif // ngage_video_render_ngage_c_hpp

View File

@@ -0,0 +1,152 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include <3dtypes.h>
#include "SDL_render_ops.hpp"
void ApplyColorMod(void *dest, void *source, int pitch, int width, int height, SDL_FColor color)
{
TUint16 *src_pixels = static_cast<TUint16 *>(source);
TUint16 *dst_pixels = static_cast<TUint16 *>(dest);
TFixed rf = Real2Fix(color.r);
TFixed gf = Real2Fix(color.g);
TFixed bf = Real2Fix(color.b);
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
TUint16 pixel = src_pixels[y * pitch / 2 + x];
TUint8 r = (pixel & 0xF800) >> 8;
TUint8 g = (pixel & 0x07E0) >> 3;
TUint8 b = (pixel & 0x001F) << 3;
r = FixMul(r, rf);
g = FixMul(g, gf);
b = FixMul(b, bf);
dst_pixels[y * pitch / 2 + x] = (r << 8) | (g << 3) | (b >> 3);
}
}
}
void ApplyFlip(void* dest, void* source, int pitch, int width, int height, SDL_FlipMode flip)
{
TUint16* src_pixels = static_cast<TUint16*>(source);
TUint16* dst_pixels = static_cast<TUint16*>(dest);
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
int src_x = x;
int src_y = y;
if (flip & SDL_FLIP_HORIZONTAL)
{
src_x = width - 1 - x;
}
if (flip & SDL_FLIP_VERTICAL)
{
src_y = height - 1 - y;
}
dst_pixels[y * pitch / 2 + x] = src_pixels[src_y * pitch / 2 + src_x];
}
}
}
void ApplyRotation(void* dest, void* source, int pitch, int width, int height, TFixed center_x, TFixed center_y, TFixed angle)
{
TUint16* src_pixels = static_cast<TUint16*>(source);
TUint16* dst_pixels = static_cast<TUint16*>(dest);
TFixed cos_angle = 0;
TFixed sin_angle = 0;
if (angle != 0)
{
FixSinCos(angle, sin_angle, cos_angle);
}
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
// Translate point to origin.
TFixed translated_x = Int2Fix(x) - center_x;
TFixed translated_y = Int2Fix(y) - center_y;
// Rotate point (clockwise).
TFixed rotated_x = FixMul(translated_x, cos_angle) + FixMul(translated_y, sin_angle);
TFixed rotated_y = FixMul(translated_y, cos_angle) - FixMul(translated_x, sin_angle);
// Translate point back.
int final_x = Fix2Int(rotated_x + center_x);
int final_y = Fix2Int(rotated_y + center_y);
// Check bounds.
if (final_x >= 0 && final_x < width && final_y >= 0 && final_y < height)
{
dst_pixels[y * pitch / 2 + x] = src_pixels[final_y * pitch / 2 + final_x];
}
else
{
dst_pixels[y * pitch / 2 + x] = 0;
}
}
}
}
void ApplyScale(void* dest, void* source, int pitch, int width, int height, TFixed center_x, TFixed center_y, TFixed scale_x, TFixed scale_y)
{
TUint16* src_pixels = static_cast<TUint16*>(source);
TUint16* dst_pixels = static_cast<TUint16*>(dest);
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
// Translate point to origin.
TFixed translated_x = Int2Fix(x) - center_x;
TFixed translated_y = Int2Fix(y) - center_y;
// Scale point.
TFixed scaled_x = FixDiv(translated_x, scale_x);
TFixed scaled_y = FixDiv(translated_y, scale_y);
// Translate point back.
int final_x = Fix2Int(scaled_x + center_x);
int final_y = Fix2Int(scaled_y + center_y);
// Check bounds.
if (final_x >= 0 && final_x < width && final_y >= 0 && final_y < height)
{
dst_pixels[y * pitch / 2 + x] = src_pixels[final_y * pitch / 2 + final_x];
}
else
{
dst_pixels[y * pitch / 2 + x] = 0;
}
}
}
}

View File

@@ -0,0 +1,32 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef ngage_video_render_ops_hpp
#define ngage_video_render_ops_hpp
#include <3dtypes.h>
void ApplyColorMod(void* dest, void* source, int pitch, int width, int height, SDL_FColor color);
void ApplyFlip(void* dest, void* source, int pitch, int width, int height, SDL_FlipMode flip);
void ApplyRotation(void* dest, void* source, int pitch, int width, int height, TFixed center_x, TFixed center_y, TFixed angle);
void ApplyScale(void* dest, void* source, int pitch, int width, int height, TFixed center_x, TFixed center_y, TFixed scale_x, TFixed scale_y);
#endif // ngage_video_render_ops_hpp

View File

@@ -34,6 +34,8 @@
#if defined(__SIZEOF_WCHAR_T__)
#define SDL_SIZEOF_WCHAR_T __SIZEOF_WCHAR_T__
#elif defined(SDL_PLATFORM_NGAGE)
#define SDL_SIZEOF_WCHAR_T 2
#elif defined(SDL_PLATFORM_WINDOWS)
#define SDL_SIZEOF_WCHAR_T 2
#else // assume everything else is UTF-32 (add more tests if compiler-assert fails below!)

View File

@@ -20,11 +20,12 @@
*/
// Do our best to make sure va_copy is working
#if defined(_MSC_VER) && _MSC_VER <= 1800
#if (defined(_MSC_VER) && _MSC_VER <= 1800) || defined(__SYMBIAN32__)
// Visual Studio 2013 tries to link with _vacopy in the C runtime. Newer versions do an inline assignment
#undef va_copy
#define va_copy(dst, src) dst = src
#elif defined(__GNUC__) && (__GNUC__ < 3)
#define va_copy(dst, src) __va_copy(dst, src)
#endif

View File

@@ -0,0 +1,184 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_TIME_NGAGE
#include <bautils.h>
#include <e32base.h>
#include <e32cons.h>
#include <e32std.h>
#ifdef __cplusplus
extern "C" {
#endif
static TTime UnixEpoch();
void SDL_GetSystemTimeLocalePreferences(SDL_DateFormat *df, SDL_TimeFormat *tf)
{
TLanguage language = User::Language();
switch (language) {
case ELangFrench:
case ELangSwissFrench:
case ELangBelgianFrench:
case ELangInternationalFrench:
case ELangGerman:
case ELangSwissGerman:
case ELangAustrian:
case ELangSpanish:
case ELangInternationalSpanish:
case ELangLatinAmericanSpanish:
case ELangItalian:
case ELangSwissItalian:
case ELangSwedish:
case ELangFinlandSwedish:
case ELangDanish:
case ELangNorwegian:
case ELangNorwegianNynorsk:
case ELangFinnish:
case ELangPortuguese:
case ELangBrazilianPortuguese:
case ELangTurkish:
case ELangCyprusTurkish:
case ELangIcelandic:
case ELangRussian:
case ELangHungarian:
case ELangDutch:
case ELangBelgianFlemish:
case ELangCzech:
case ELangSlovak:
case ELangPolish:
case ELangSlovenian:
case ELangTaiwanChinese:
case ELangHongKongChinese:
case ELangPrcChinese:
case ELangJapanese:
case ELangThai:
case ELangAfrikaans:
case ELangAlbanian:
case ELangAmharic:
case ELangArabic:
case ELangArmenian:
case ELangAzerbaijani:
case ELangBelarussian:
case ELangBengali:
case ELangBulgarian:
case ELangBurmese:
case ELangCatalan:
case ELangCroatian:
case ELangEstonian:
case ELangFarsi:
case ELangScotsGaelic:
case ELangGeorgian:
case ELangGreek:
case ELangCyprusGreek:
case ELangGujarati:
case ELangHebrew:
case ELangHindi:
case ELangIndonesian:
case ELangIrish:
case ELangKannada:
case ELangKazakh:
case ELangKhmer:
case ELangKorean:
case ELangLao:
case ELangLatvian:
case ELangLithuanian:
case ELangMacedonian:
case ELangMalay:
case ELangMalayalam:
case ELangMarathi:
case ELangMoldavian:
case ELangMongolian:
case ELangPunjabi:
case ELangRomanian:
case ELangSerbian:
case ELangSinhalese:
case ELangSomali:
case ELangSwahili:
case ELangTajik:
case ELangTamil:
case ELangTelugu:
case ELangTibetan:
case ELangTigrinya:
case ELangTurkmen:
case ELangUkrainian:
case ELangUrdu:
case ELangUzbek:
case ELangVietnamese:
case ELangWelsh:
case ELangZulu:
*df = SDL_DATE_FORMAT_DDMMYYYY;
*tf = SDL_TIME_FORMAT_24HR;
break;
case ELangAmerican:
case ELangCanadianEnglish:
case ELangInternationalEnglish:
case ELangSouthAfricanEnglish:
case ELangAustralian:
case ELangNewZealand:
case ELangCanadianFrench:
*df = SDL_DATE_FORMAT_MMDDYYYY;
*tf = SDL_TIME_FORMAT_12HR;
break;
case ELangEnglish:
case ELangOther:
default:
*df = SDL_DATE_FORMAT_DDMMYYYY;
*tf = SDL_TIME_FORMAT_24HR;
break;
}
}
bool SDL_GetCurrentTime(SDL_Time *ticks)
{
if (!ticks) {
return SDL_InvalidParamError("ticks");
}
TTime now;
now.UniversalTime();
TTimeIntervalMicroSeconds interval = now.MicroSecondsFrom(UnixEpoch());
TInt64 interval_ns = interval.Int64() * 1000;
Uint32 ns_low = interval_ns.Low();
Uint32 ns_high = interval_ns.High();
*ticks = ((Uint64)ns_high << 32) | ns_low;
return true;
}
static TTime UnixEpoch()
{
_LIT(KUnixEpoch, "19700101:000000.000000");
TTime epochTime;
epochTime.Set(KUnixEpoch);
return epochTime;
}
#ifdef __cplusplus
}
#endif
#endif // SDL_TIME_NGAGE

View File

@@ -0,0 +1,47 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include <e32hal.h>
#include <e32std.h>
#ifdef __cplusplus
extern "C" {
#endif
Uint64 SDL_GetPerformanceCounter(void)
{
return (Uint64)User::TickCount();
}
Uint64 SDL_GetPerformanceFrequency(void)
{
return (Uint64)1000000u;
}
void SDL_SYS_DelayNS(Uint64 ns)
{
User::After(SDL_NS_TO_US(ns));
}
#ifdef __cplusplus
}
#endif

View File

@@ -530,6 +530,7 @@ extern VideoBootStrap PSP_bootstrap;
extern VideoBootStrap VITA_bootstrap;
extern VideoBootStrap RISCOS_bootstrap;
extern VideoBootStrap N3DS_bootstrap;
extern VideoBootStrap NGAGE_bootstrap;
extern VideoBootStrap RPI_bootstrap;
extern VideoBootStrap KMSDRM_bootstrap;
extern VideoBootStrap DUMMY_bootstrap;

View File

@@ -119,6 +119,9 @@ static VideoBootStrap *bootstrap[] = {
#ifdef SDL_VIDEO_DRIVER_N3DS
&N3DS_bootstrap,
#endif
#ifdef SDL_VIDEO_DRIVER_NGAGE
&NGAGE_bootstrap,
#endif
#ifdef SDL_VIDEO_DRIVER_KMSDRM
&KMSDRM_bootstrap,
#endif

View File

@@ -0,0 +1,175 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../SDL_sysvideo.h"
#ifdef SDL_VIDEO_DRIVER_NGAGE
#include "SDL_ngagevideo.h"
#define NGAGE_VIDEO_DRIVER_NAME "N-Gage"
static void NGAGE_DeleteDevice(SDL_VideoDevice *device);
static bool NGAGE_VideoInit(SDL_VideoDevice *device);
static void NGAGE_VideoQuit(SDL_VideoDevice *device);
static bool NGAGE_GetDisplayBounds(SDL_VideoDevice *device, SDL_VideoDisplay *display, SDL_Rect *rect);
static bool NGAGE_GetDisplayModes(SDL_VideoDevice *device, SDL_VideoDisplay *display);
static void NGAGE_PumpEvents(SDL_VideoDevice *device);
static bool NGAGE_SuspendScreenSaver(SDL_VideoDevice *device);
static SDL_VideoDevice *NGAGE_CreateDevice(void)
{
SDL_VideoDevice *device;
SDL_VideoData *phdata;
// Initialize all variables that we clean on shutdown.
device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
if (!device) {
SDL_OutOfMemory();
return (SDL_VideoDevice *)0;
}
// Initialize internal N-Gage specific data.
phdata = (SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData));
if (!phdata) {
SDL_OutOfMemory();
SDL_free(device);
return (SDL_VideoDevice *)0;
}
device->internal = phdata;
device->name = "Nokia N-Gage";
device->VideoInit = NGAGE_VideoInit;
device->VideoQuit = NGAGE_VideoQuit;
device->GetDisplayBounds = NGAGE_GetDisplayBounds;
device->GetDisplayModes = NGAGE_GetDisplayModes;
device->PumpEvents = NGAGE_PumpEvents;
device->SuspendScreenSaver = NGAGE_SuspendScreenSaver;
device->free = NGAGE_DeleteDevice;
device->device_caps = VIDEO_DEVICE_CAPS_FULLSCREEN_ONLY;
return device;
}
VideoBootStrap NGAGE_bootstrap = {
NGAGE_VIDEO_DRIVER_NAME,
"N-Gage Video Driver",
NGAGE_CreateDevice,
0
};
static void NGAGE_DeleteDevice(SDL_VideoDevice *device)
{
SDL_free(device->internal);
SDL_free(device);
}
static bool NGAGE_VideoInit(SDL_VideoDevice *device)
{
SDL_VideoData *phdata = (SDL_VideoData *)device->internal;
if (!phdata) {
return false;
}
SDL_zero(phdata->mode);
SDL_zero(phdata->display);
phdata->mode.w = 176;
phdata->mode.h = 208;
phdata->mode.refresh_rate = 60.0f;
phdata->mode.format = SDL_PIXELFORMAT_ARGB4444;
phdata->display.name = "N-Gage";
phdata->display.desktop_mode = phdata->mode;
if (SDL_AddVideoDisplay(&phdata->display, false) == 0) {
return false;
}
return true;
}
static void NGAGE_VideoQuit(SDL_VideoDevice *device)
{
SDL_VideoData *phdata = (SDL_VideoData *)device->internal;
if (phdata) {
SDL_zero(phdata->mode);
SDL_zero(phdata->display);
}
}
static bool NGAGE_GetDisplayBounds(SDL_VideoDevice *device, SDL_VideoDisplay *display, SDL_Rect *rect)
{
if (!display) {
return false;
}
rect->x = 0;
rect->y = 0;
rect->w = display->current_mode->w;
rect->h = display->current_mode->h;
return true;
}
static bool NGAGE_GetDisplayModes(SDL_VideoDevice *device, SDL_VideoDisplay *display)
{
SDL_VideoData *phdata = (SDL_VideoData *)device->internal;
SDL_DisplayMode mode;
SDL_zero(mode);
mode.w = phdata->mode.w;
mode.h = phdata->mode.h;
mode.refresh_rate = phdata->mode.refresh_rate;
mode.format = phdata->mode.format;
if (!SDL_AddFullscreenDisplayMode(display, &mode)) {
return false;
}
return true;
}
#include "../../render/ngage/SDL_render_ngage_c.h"
static void NGAGE_PumpEvents(SDL_VideoDevice *device)
{
NGAGE_PumpEventsInternal();
}
static bool NGAGE_SuspendScreenSaver(SDL_VideoDevice *device)
{
NGAGE_SuspendScreenSaverInternal(device->suspend_screensaver);
return true;
}
#endif // SDL_VIDEO_DRIVER_NGAGE

View File

@@ -0,0 +1,39 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_NGAGE
#include "../SDL_sysvideo.h"
#ifndef _SDL_ngagevideo_h
#define _SDL_ngagevideo_h
typedef struct SDL_VideoData
{
SDL_DisplayMode mode;
SDL_VideoDisplay display;
} SDL_VideoData;
#endif // _SDL_ngagevideo_h
#endif // SDL_VIDEO_DRIVER_NGAGE