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 
38 extern "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 
RDebug_Print_b(char * error_str,void * param)69 void 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 
RDebug_Print(char * error_str,void * param)89 extern "C" void RDebug_Print(char* error_str, void* param)
90     {
91     RDebug_Print_b(error_str, param);
92     }
93 
94 /*
95 int 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 
104 extern "C" int Debug_AvailMem()
105     {
106     return(Debug_AvailMem2());
107     }
108 
109 */
110 
111 extern "C" {
112 
113 /* Initialization/Query functions */
114 
115 static int EPOC_VideoInit(_THIS, SDL_PixelFormat *vformat);
116 static SDL_Rect **EPOC_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
117 static SDL_Surface *EPOC_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
118 static int EPOC_SetColors(_THIS, int firstcolor, int ncolors,
119 			  SDL_Color *colors);
120 static void EPOC_VideoQuit(_THIS);
121 
122 /* Hardware surface functions */
123 
124 static int EPOC_AllocHWSurface(_THIS, SDL_Surface *surface);
125 static int EPOC_LockHWSurface(_THIS, SDL_Surface *surface);
126 static int EPOC_FlipHWSurface(_THIS, SDL_Surface *surface);
127 static void EPOC_UnlockHWSurface(_THIS, SDL_Surface *surface);
128 static void EPOC_FreeHWSurface(_THIS, SDL_Surface *surface);
129 static void EPOC_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
130 
131 static int EPOC_Available(void);
132 static SDL_VideoDevice *EPOC_CreateDevice(int devindex);
133 
134 void DrawBackground(_THIS);
135 void DirectDraw(_THIS, int numrects, SDL_Rect *rects, TUint16* screenBuffer);
136 void DirectDrawRotated(_THIS, int numrects, SDL_Rect *rects, TUint16* screenBuffer);
137 
138 /* Mouse functions */
139 
140 static WMcursor *EPOC_CreateWMCursor(_THIS, Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y);
141 static void EPOC_FreeWMCursor(_THIS, WMcursor *cursor);
142 static int EPOC_ShowWMCursor(_THIS, WMcursor *cursor);
143 }
144 
145 
146 extern "C"
147 	{
148 	struct WMcursor
149 		{
150 		};
151 	}
152 
153 /* Epoc video driver bootstrap functions */
154 
155 
EPOC_Available(void)156 static int EPOC_Available(void)
157     {
158     return 1; /* Always available */
159     }
160 
EPOC_DeleteDevice(SDL_VideoDevice * device)161 static void EPOC_DeleteDevice(SDL_VideoDevice *device)
162     {
163 	User::Free(device->hidden);
164 	User::Free(device);
165     }
166 
EPOC_CreateDevice(int)167 static 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 
222 VideoBootStrap EPOC_bootstrap = {
223 	"epoc\0\0\0", "EPOC system",
224     EPOC_Available, EPOC_CreateDevice
225 };
226 
227 
228 
DisableKeyBlocking(_THIS)229 void DisableKeyBlocking(_THIS)
230     {
231     EpocSdlEnv::Request(EpocSdlEnv::EDisableKeyBlocking);
232     }
233 
ConstructWindowL(_THIS)234 void ConstructWindowL(_THIS)
235 	{
236 	SDL_TRACE("SDL:ConstructWindowL");
237 	DisableKeyBlocking(_this); //disable key blocking
238 	}
239 
240 
EPOC_VideoInit(_THIS,SDL_PixelFormat * vformat)241 int 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 
EPOC_ListModes(_THIS,SDL_PixelFormat * format,Uint32 flags)275 SDL_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 
EPOC_SetColors(_THIS,int firstcolor,int ncolors,SDL_Color * colors)290 int 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 /*
344 void 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 
355 int 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 
GetDisplayMode(TInt aBitsPerPixel)385 TDisplayMode 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 
EPOC_SetVideoMode(_THIS,SDL_Surface * current,int width,int height,int bpp,Uint32 flags)406 SDL_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 
EPOC_AllocHWSurface(_THIS,SDL_Surface * surface)508 static int EPOC_AllocHWSurface(_THIS, SDL_Surface* surface)
509 	{
510 	return KErrNone == EpocSdlEnv::AllocHwSurface(TSize(surface->w, surface->h), GetDisplayMode(surface->format->BitsPerPixel));
511 	}
512 
EPOC_FreeHWSurface(_THIS,SDL_Surface *)513 static void EPOC_FreeHWSurface(_THIS, SDL_Surface* /*surface*/)
514 	{
515 	}
516 
EPOC_LockHWSurface(_THIS,SDL_Surface * surface)517 static 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 	}
EPOC_UnlockHWSurface(_THIS,SDL_Surface *)530 static void EPOC_UnlockHWSurface(_THIS, SDL_Surface* /*surface*/)
531 	{
532 	EpocSdlEnv::UnlockHwSurface();
533 	}
534 
EPOC_FlipHWSurface(_THIS,SDL_Surface *)535 static int EPOC_FlipHWSurface(_THIS, SDL_Surface* /*surface*/)
536 	{
537 	return(0);
538 	}
539 
EPOC_DirectUpdate(_THIS,int numrects,SDL_Rect * rects)540 static 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 */
EPOC_VideoQuit(_THIS)569 void 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 
EPOC_CreateWMCursor(_THIS,Uint8 *,Uint8 *,int,int,int,int)581 WMcursor *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 
EPOC_FreeWMCursor(_THIS,WMcursor *)586 void EPOC_FreeWMCursor(_THIS, WMcursor* /*cursor*/)
587     {
588     }
589 
EPOC_ShowWMCursor(_THIS,WMcursor * cursor)590 int EPOC_ShowWMCursor(_THIS, WMcursor *cursor)
591     {
592     return true;
593     }
594 
595