1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 Sam Lantinga
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with this library; if not, write to the Free
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19    Sam Lantinga
20    slouken@devolution.com
21*/
22
23/*
24    SDL_epocvideo.cpp
25    Epoc based SDL video driver implementation
26
27    Markus Mertama
28*/
29
30
31
32#include "epoc_sdl.h"
33
34#include <stdlib.h>
35#include <stdio.h>
36#include <string.h>
37
38extern "C" {
39#include "SDL_error.h"
40#include "SDL_timer.h"
41#include "SDL_video.h"
42#undef NULL
43#include "SDL_pixels_c.h"
44#include "SDL.h"
45#include "SDL_mouse.h"
46}
47
48#include "SDL_epocvideo.h"
49#include "SDL_epocevents_c.h"
50
51
52
53#include <coedef.h>
54#include <flogger.h>
55
56#include <eikenv.h>
57#include <eikappui.h>
58#include <eikapp.h>
59#include "sdlepocapi.h"
60
61
62////////////////////////////////////////////////////////////////
63
64
65
66
67_LIT(KLibName, "SDL");
68
69void RDebug_Print_b(char* error_str, void* param)
70    {
71    TBuf8<128> error8((TUint8*)error_str);
72    TBuf<128> error;
73    error.Copy(error8);
74
75#ifndef TRACE_TO_FILE
76    if (param) //!! Do not work if the parameter is really 0!!
77        RDebug::Print(error, param);
78    else
79        RDebug::Print(error);
80#else
81    if (param) //!! Do not work if the parameter is really 0!!
82        RFileLogger::WriteFormat(KLibName, _L("SDL.txt"), EFileLoggingModeAppend, error, param);
83    else
84        RFileLogger::Write(KLibName, _L("SDL.txt"), EFileLoggingModeAppend, error);
85#endif
86
87    }
88
89extern "C" void RDebug_Print(char* error_str, void* param)
90    {
91    RDebug_Print_b(error_str, param);
92    }
93
94/*
95int Debug_AvailMem2()
96    {
97    //User::CompressAllHeaps();
98    TMemoryInfoV1Buf membuf;
99    User::LeaveIfError(UserHal::MemoryInfo(membuf));
100    TMemoryInfoV1 minfo = membuf();
101	return(minfo.iFreeRamInBytes);
102    }
103
104extern "C" int Debug_AvailMem()
105    {
106    return(Debug_AvailMem2());
107    }
108
109*/
110
111extern "C" {
112
113/* Initialization/Query functions */
114
115static int EPOC_VideoInit(_THIS, SDL_PixelFormat *vformat);
116static SDL_Rect **EPOC_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
117static SDL_Surface *EPOC_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
118static int EPOC_SetColors(_THIS, int firstcolor, int ncolors,
119			  SDL_Color *colors);
120static void EPOC_VideoQuit(_THIS);
121
122/* Hardware surface functions */
123
124static int EPOC_AllocHWSurface(_THIS, SDL_Surface *surface);
125static int EPOC_LockHWSurface(_THIS, SDL_Surface *surface);
126static int EPOC_FlipHWSurface(_THIS, SDL_Surface *surface);
127static void EPOC_UnlockHWSurface(_THIS, SDL_Surface *surface);
128static void EPOC_FreeHWSurface(_THIS, SDL_Surface *surface);
129static void EPOC_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
130
131static int EPOC_Available(void);
132static SDL_VideoDevice *EPOC_CreateDevice(int devindex);
133
134void DrawBackground(_THIS);
135void DirectDraw(_THIS, int numrects, SDL_Rect *rects, TUint16* screenBuffer);
136void DirectDrawRotated(_THIS, int numrects, SDL_Rect *rects, TUint16* screenBuffer);
137
138/* Mouse functions */
139
140static WMcursor *EPOC_CreateWMCursor(_THIS, Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y);
141static void EPOC_FreeWMCursor(_THIS, WMcursor *cursor);
142static int EPOC_ShowWMCursor(_THIS, WMcursor *cursor);
143}
144
145
146extern "C"
147	{
148	struct WMcursor
149		{
150		};
151	}
152
153/* Epoc video driver bootstrap functions */
154
155
156static int EPOC_Available(void)
157    {
158    return 1; /* Always available */
159    }
160
161static void EPOC_DeleteDevice(SDL_VideoDevice *device)
162    {
163	User::Free(device->hidden);
164	User::Free(device);
165    }
166
167static SDL_VideoDevice *EPOC_CreateDevice(int /*devindex*/)
168    {
169	SDL_VideoDevice *device;
170
171	SDL_TRACE("SDL:EPOC_CreateDevice");
172
173	/* Allocate all variables that we free on delete */
174	device = static_cast<SDL_VideoDevice*>(User::Alloc(sizeof(SDL_VideoDevice)));
175	if ( device )
176	    {
177		Mem::FillZ(device, (sizeof *device));
178		device->hidden = static_cast<struct SDL_PrivateVideoData*>
179				(User::Alloc((sizeof *device->hidden)));
180	    }
181	if ( (device == NULL) || (device->hidden == NULL) )
182	    {
183		SDL_OutOfMemory();
184		if ( device ) {
185		User::Free(device);
186		}
187		return(0);
188	}
189	Mem::FillZ(device->hidden, (sizeof *device->hidden));
190
191	/* Set the function pointers */
192	device->VideoInit = EPOC_VideoInit;
193	device->ListModes = EPOC_ListModes;
194	device->SetVideoMode = EPOC_SetVideoMode;
195	device->SetColors = EPOC_SetColors;
196	device->UpdateRects = NULL;
197	device->VideoQuit = EPOC_VideoQuit;
198	device->AllocHWSurface = EPOC_AllocHWSurface;
199	device->CheckHWBlit = NULL;
200	device->FillHWRect = NULL;
201	device->SetHWColorKey = NULL;
202	device->SetHWAlpha = NULL;
203	device->LockHWSurface = EPOC_LockHWSurface;
204	device->UnlockHWSurface = EPOC_UnlockHWSurface;
205	device->FlipHWSurface = EPOC_FlipHWSurface;
206	device->FreeHWSurface = EPOC_FreeHWSurface;
207	device->SetIcon = NULL;
208	device->SetCaption = NULL;
209	device->GetWMInfo = NULL;
210	device->FreeWMCursor = EPOC_FreeWMCursor;
211	device->CreateWMCursor = EPOC_CreateWMCursor;
212	device->ShowWMCursor = EPOC_ShowWMCursor;
213	device->WarpWMCursor = NULL;
214	device->InitOSKeymap = EPOC_InitOSKeymap;
215	device->PumpEvents = EPOC_PumpEvents;
216	device->free = EPOC_DeleteDevice;
217
218	return device;
219}
220
221
222VideoBootStrap EPOC_bootstrap = {
223	"epoc\0\0\0", "EPOC system",
224    EPOC_Available, EPOC_CreateDevice
225};
226
227
228
229void DisableKeyBlocking(_THIS)
230    {
231    EpocSdlEnv::Request(EpocSdlEnv::EDisableKeyBlocking);
232    }
233
234void ConstructWindowL(_THIS)
235	{
236	SDL_TRACE("SDL:ConstructWindowL");
237	DisableKeyBlocking(_this); //disable key blocking
238	}
239
240
241int EPOC_VideoInit(_THIS, SDL_PixelFormat *vformat)
242	{
243    /* Construct Epoc window */
244
245    ConstructWindowL(_this);
246
247    /* Initialise Epoc frame buffer */
248
249
250    const TDisplayMode displayMode = EpocSdlEnv::DisplayMode();
251
252    /* The "best" video format should be returned to caller. */
253
254    vformat->BitsPerPixel 	= TDisplayModeUtils::NumDisplayModeBitsPerPixel(displayMode);
255    vformat->BytesPerPixel  = TDisplayModeUtils::NumDisplayModeBitsPerPixel(displayMode) / 8;
256
257
258 //??   Private->iWindow->PointerFilter(EPointerFilterDrag, 0);
259
260    Private->iScreenPos = TPoint(0, 0);
261
262    Private->iRect.x = Private->iScreenPos.iX;
263    Private->iRect.y = Private->iScreenPos.iY;
264
265    const TSize sz = EpocSdlEnv::WindowSize();
266
267    Private->iRect.w = sz.iWidth;
268    Private->iRect.h = sz.iHeight;
269	Private->iRectPtr = &Private->iRect;
270
271	return(0);
272	}
273
274
275SDL_Rect **EPOC_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
276	{
277	if(flags & SDL_HWSURFACE)
278		{
279		if(format->BytesPerPixel != 4) //in HW only full color is supported
280			return NULL;
281		}
282	if(flags & SDL_FULLSCREEN)
283		{
284		return &Private->iRectPtr;
285		}
286    return (SDL_Rect **)(-1); //everythingisok, unless too small shoes
287	}
288
289
290int EPOC_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
291	{
292	if ((firstcolor+ncolors) > 256)
293		return -1;
294	TUint32 palette[256];
295	const TDisplayMode mode = EpocSdlEnv::DisplayMode();
296    if(TDisplayModeUtils::NumDisplayModeColors(mode) == 4096)
297        {
298	// Set 12 bit palette
299        for(int i = firstcolor; i < ncolors; i++)
300            {
301	        // 4k value: 0000 rrrr gggg bbbb
302	        TUint32 color4K	 = (colors[i].r & 0x0000f0) << 4;
303	        color4K			|= (colors[i].g & 0x0000f0);
304	        color4K			|= (colors[i].b & 0x0000f0) >> 4;
305            palette[i] = color4K;
306            }
307        }
308    else if(TDisplayModeUtils::NumDisplayModeColors(mode) == 65536)
309        {
310        for(int i = firstcolor; i < ncolors; i++)
311            {
312			// 64k-colour displays effectively support RGB values
313			// with 5 bits allocated to red, 6 to green and 5 to blue
314			// 64k value: rrrr rggg gggb bbbb
315	        TUint32 color64K = (colors[i].r & 0x0000f8) << 8;
316	        color64K		|= (colors[i].g & 0x0000fc) << 3;
317	        color64K		|= (colors[i].b & 0x0000f8) >> 3;
318            palette[i] = color64K;
319            }
320        }
321    else if(TDisplayModeUtils::NumDisplayModeColors(mode) == 16777216)
322        {
323        for(int i = firstcolor; i < ncolors; i++)
324            {
325			// 16M-colour
326            //0000 0000 rrrr rrrr gggg gggg bbbb bbbb
327	        TUint32 color16M = colors[i].r << 16;
328	        color16M		|= colors[i].g << 8;
329	        color16M		|= colors[i].b;
330            palette[i] = color16M;
331            }
332        }
333    else
334        {
335        return -2;
336        }
337    if(EpocSdlEnv::SetPalette(firstcolor, ncolors, palette) == KErrNone)
338    	return 0;
339	return -1;
340	}
341
342
343/*
344void AllocHWSurfaceL(CFbsBitmap*& aBitmap, const TDisplayMode& aMode, const TSize& aSize)
345	{
346	aBitmap = new (ELeave) CFbsBitmap();
347	if(KErrNone != aBitmap->CreateHardwareBitmap(aSize, aMode,
348		EpocSdlEnv::EikonEnv().EikAppUi()->Application()->AppDllUid()))
349	//...if it fails - should we use wsbitmaps???
350		{//the good reason to use hw bitmaps is that they wont need lock heap
351		PANIC_IF_ERROR(aBitmap->Create(aSize, aMode));
352		}
353	}
354
355int CreateSurfaceL(_THIS, SDL_Surface* surface)
356    {
357    __ASSERT_ALWAYS(Private->iFrame == NULL, PANIC(KErrAlreadyExists));
358;
359	TInt dmode = EColorLast;
360
361	TDisplayMode displayMode;
362	EpocSdlEnv::GetDiplayMode(displayMode);
363
364	if(
365	TDisplayModeUtils::NumDisplayModeBitsPerPixel(displayMode)
366	== surface->format->BitsPerPixel)
367		{
368		dmode = displayMode;
369		}
370	else
371		{
372		--dmode;
373		while(TDisplayModeUtils::IsDisplayModeColor(TDisplayMode(dmode)) &&
374			TDisplayModeUtils::NumDisplayModeBitsPerPixel(TDisplayMode(dmode)) !=
375			surface->format->BitsPerPixel)
376			--dmode;
377		}
378
379	__ASSERT_ALWAYS(TDisplayModeUtils::IsDisplayModeColor(TDisplayMode(dmode)), PANIC(KErrNotSupported));
380	TRAPD(err, AllocHWSurfaceL(Private->iFrame, TDisplayMode(dmode), TSize(surface->w, surface->h)));
381	return err == KErrNone ? 0 : -1;
382    }
383*/
384
385TDisplayMode GetDisplayMode(TInt aBitsPerPixel)
386	{
387	const TDisplayMode displayMode = EpocSdlEnv::DisplayMode();
388	TInt dmode = EColorLast;
389	if(
390	TDisplayModeUtils::NumDisplayModeBitsPerPixel(displayMode)
391	== aBitsPerPixel)
392		{
393		dmode = displayMode;
394		}
395	else
396		{
397		--dmode;
398		while(TDisplayModeUtils::IsDisplayModeColor(TDisplayMode(dmode)) &&
399			TDisplayModeUtils::NumDisplayModeBitsPerPixel(TDisplayMode(dmode)) !=
400			aBitsPerPixel)
401			--dmode;
402		}
403	return TDisplayMode(dmode);
404	}
405
406SDL_Surface *EPOC_SetVideoMode(_THIS, SDL_Surface *current,
407				int width, int height, int bpp, Uint32 flags)
408	{
409	const TSize screenSize = EpocSdlEnv::WindowSize(TSize(width, height));
410	if(width > screenSize.iWidth || height > screenSize.iHeight)
411	    {
412	    if(flags & SDL_FULLSCREEN)
413	        {
414	        width = screenSize.iWidth;
415	        height = screenSize.iHeight;
416	        }
417	    else
418		    return NULL;
419	    }
420
421    if(current && current->pixels)
422    	{
423      //  free(current->pixels);
424        current->pixels = NULL;
425    	}
426
427	if(!SDL_ReallocFormat(current, bpp, 0, 0, 0, 0))
428	 	{
429		return(NULL);
430	 	}
431
432	current->flags = 0;
433	if(width == screenSize.iWidth && height == screenSize.iHeight)
434		current->flags |= SDL_FULLSCREEN;
435
436	const int numBytesPerPixel = ((bpp-1)>>3) + 1;
437	current->pitch = numBytesPerPixel * width; // Number of bytes in scanline
438
439    /* Set up the new mode framebuffer */
440   	current->flags |= SDL_PREALLOC;
441
442   	if(bpp <= 8)
443   		current->flags |= SDL_HWPALETTE;
444
445   	User::Free(Private->iSwSurface);
446   	current->pixels = NULL;
447   	Private->iSwSurface = NULL;
448
449   	if(flags & SDL_HWSURFACE)
450   	    {
451   	    current->flags |= SDL_HWSURFACE;
452   	   //	current->pixels = NULL;
453   	   // 	Private->iSwSurface = NULL;
454   	    }
455   	else
456   	    {
457   	    current->flags |= SDL_SWSURFACE;
458   	    const TInt surfacesize = width * height * numBytesPerPixel;
459   	   	Private->iSwSurfaceSize = TSize(width, height);
460   	   	delete Private->iSwSurface;
461   	   	Private->iSwSurface = NULL;
462   	  	current->pixels = (TUint8*) User::AllocL(surfacesize);
463   	  	Private->iSwSurface = (TUint8*) current->pixels;
464   	  	const TInt err = EpocSdlEnv::AllocSwSurface
465   	  		(TSize(width, height), GetDisplayMode(current->format->BitsPerPixel));
466	    if(err != KErrNone)
467	    	return NULL;
468	    }
469
470	current->w = width;
471	current->h = height;
472
473
474
475	/* Set the blit function */
476	_this->UpdateRects = EPOC_DirectUpdate;
477
478    /*
479     *  Logic for getting suitable screen dimensions, offset, scaling and orientation
480     */
481
482
483    /* Centralize game window on device screen  */
484
485
486    Private->iScreenPos.iX = Max(0, (screenSize.iWidth  - width)  / 2);
487    Private->iScreenPos.iY = Max(0, (screenSize.iHeight - height) / 2);
488
489 //   delete (Private->iFrame);
490//	Private->iFrame = NULL;
491
492  //  TRAPD(err, CreateSurfaceL(_this, current));
493  //  PANIC_IF_ERROR(err);
494
495    SDL_TRACE1("View width %d", width);
496    SDL_TRACE1("View height %d", height);
497    SDL_TRACE1("View bmode %d", bpp);
498    SDL_TRACE1("View x %d", Private->iScreenPos.iX);
499    SDL_TRACE1("View y %d", Private->iScreenPos.iY);
500
501	EpocSdlEnv::LockPalette(EFalse);
502	/* We're done */
503	return(current);
504}
505
506
507
508static int EPOC_AllocHWSurface(_THIS, SDL_Surface* surface)
509	{
510	return KErrNone == EpocSdlEnv::AllocHwSurface(TSize(surface->w, surface->h), GetDisplayMode(surface->format->BitsPerPixel));
511	}
512
513static void EPOC_FreeHWSurface(_THIS, SDL_Surface* /*surface*/)
514	{
515	}
516
517static int EPOC_LockHWSurface(_THIS, SDL_Surface* surface)
518	{
519	if(EpocSdlEnv::IsDsaAvailable())
520		{
521		TUint8* address = EpocSdlEnv::LockHwSurface();
522		if(address != NULL)
523			{
524			surface->pixels = address;
525			return 1;
526			}
527		}
528	return 0;
529	}
530static void EPOC_UnlockHWSurface(_THIS, SDL_Surface* /*surface*/)
531	{
532	EpocSdlEnv::UnlockHwSurface();
533	}
534
535static int EPOC_FlipHWSurface(_THIS, SDL_Surface* /*surface*/)
536	{
537	return(0);
538	}
539
540static void EPOC_DirectUpdate(_THIS, int numrects, SDL_Rect *rects)
541	{
542	if(EpocSdlEnv::IsDsaAvailable())
543		{
544		if(Private->iSwSurface)
545		    {
546		    const TRect target(Private->iScreenPos, Private->iSwSurfaceSize);
547		    for(TInt i = 0; i < numrects ;i++)
548		    	{
549		    	const TRect rect(TPoint(rects[i].x, rects[i].y),
550		    		TSize(rects[i].w, rects[i].h));
551		    	if(!EpocSdlEnv::AddUpdateRect(Private->iSwSurface, rect, target))
552		    		return; //not succesful
553		    	}
554		    EpocSdlEnv::UpdateSwSurface();
555		    }
556		SDL_PauseAudio(0);
557		}
558    else
559    	{
560     	SDL_PauseAudio(1);
561    	EpocSdlEnv::WaitDsaAvailable();
562		}
563	}
564
565
566/* Note:  If we are terminated, this could be called in the middle of
567   another SDL video routine -- notably UpdateRects.
568*/
569void EPOC_VideoQuit(_THIS)
570	{
571//	delete Private->iFrame;
572//	Private->iFrame = NULL;
573	User::Free(Private->iSwSurface);
574	Private->iSwSurface = NULL;
575	EpocSdlEnv::FreeSurface();
576	}
577
578
579
580
581WMcursor *EPOC_CreateWMCursor(_THIS, Uint8* /*data*/, Uint8* /*mask*/, int /*w*/, int /*h*/, int /*hot_x*/, int /*hot_y*/)
582    {
583    return (WMcursor*) 1; //hii! prevents SDL to view a std cursor
584    }
585
586void EPOC_FreeWMCursor(_THIS, WMcursor* /*cursor*/)
587    {
588    }
589
590int EPOC_ShowWMCursor(_THIS, WMcursor *cursor)
591    {
592    return true;
593    }
594
595