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

@@ -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