#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); winGroupName.Append(0);
winGroupName.Append(exeName.Name()); winGroupName.Append(0);
winGroupName.Append(0); 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);
TFontSpec fontSpec(_L("LatinBold12"), 12);
TInt errd = iWsScreen->GetNearestFontInTwips((CFont *&)iFont, fontSpec);
if (errd != KErrNone) {
SDL_Log("Failed to get font: %d", errd);
return;
}
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;
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);
info.Format(_L("FPS: %d"), iFPS);
iRenderer->Gc()->DrawText(info, TPoint(5, 203));
} else {
iRenderer->Gc()->DrawText(_L(""), TPoint(0, 0));
}
iRenderer->Gc()->DiscardFont();
iRenderer->Flip(iDirectScreen);
if (iSuspendScreenSaver) {
User::ResetInactivityTime();
}
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;
currentTime.HomeTime();
++frameCount;
TTimeIntervalMicroSeconds timeDiff = currentTime.MicroSecondsFrom(lastTime);
if (timeDiff.Int64() >= KOneSecond) {
iFPS = frameCount;
frameCount = 0;
lastTime = currentTime;
}
}
void CRenderer::SuspendScreenSaver(TBool aSuspend)
{
iSuspendScreenSaver = aSuspend;
}
static SDL_Scancode ConvertScancode(int key)
{
SDL_Keycode keycode;
switch (key) {
case EStdKeyBackspace: keycode = SDLK_BACKSPACE;
break;
case 0x31: keycode = SDLK_1;
break;
case 0x32: keycode = SDLK_2;
break;
case 0x33: keycode = SDLK_3;
break;
case 0x34: keycode = SDLK_4;
break;
case 0x35: keycode = SDLK_5;
break;
case 0x36: keycode = SDLK_6;
break;
case 0x37: keycode = SDLK_7;
break;
case 0x38: keycode = SDLK_8;
break;
case 0x39: keycode = SDLK_9;
break;
case 0x30: keycode = SDLK_0;
break;
case 0x2a: keycode = SDLK_ASTERISK;
break;
case EStdKeyHash: keycode = SDLK_HASH;
break;
case EStdKeyDevice0: keycode = SDLK_SOFTLEFT;
break;
case EStdKeyDevice1: keycode = SDLK_SOFTRIGHT;
break;
case EStdKeyApplication0: keycode = SDLK_CALL;
break;
case EStdKeyApplication1: keycode = SDLK_ENDCALL;
break;
case EStdKeyDevice3: keycode = SDLK_SELECT;
break;
case EStdKeyUpArrow: keycode = SDLK_UP;
break;
case EStdKeyDownArrow: keycode = SDLK_DOWN;
break;
case EStdKeyLeftArrow: keycode = SDLK_LEFT;
break;
case EStdKeyRightArrow: 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:
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:
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) 51);
iWsSession.SimulateRawEvent(aEvent);
}
void CRenderer::PumpEvents()
{
while (iWsEventStatus != KRequestPending) {
iWsSession.GetEvent(iWsEvent);
HandleEvent(iWsEvent);
iWsEventStatus = KRequestPending;
iWsSession.EventReady(&iWsEventStatus);
}
}
#endif