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 Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 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    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19    Sam Lantinga
20    slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24#include <nds.h>
25#include <nds/registers_alt.h>
26#include "SDL.h"
27#include "SDL_error.h"
28#include "SDL_video.h"
29#include "SDL_mouse.h"
30#include "../SDL_sysvideo.h"
31#include "../SDL_pixels_c.h"
32#include "../../events/SDL_events_c.h"
33
34#include "SDL_ndsvideo.h"
35#include "SDL_ndsevents_c.h"
36#include "SDL_ndsmouse_c.h"
37
38#define NDSVID_DRIVER_NAME "nds"
39
40/* Initialization/Query functions */
41static int NDS_VideoInit(_THIS, SDL_PixelFormat *vformat);
42static SDL_Rect **NDS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
43static SDL_Surface *NDS_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
44static int NDS_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
45static void NDS_VideoQuit(_THIS);
46
47/* Hardware surface functions */
48static int NDS_AllocHWSurface(_THIS, SDL_Surface *surface);
49static int NDS_LockHWSurface(_THIS, SDL_Surface *surface);
50static int NDS_FlipHWSurface(_THIS, SDL_Surface *surface);
51static void NDS_UnlockHWSurface(_THIS, SDL_Surface *surface);
52static void NDS_FreeHWSurface(_THIS, SDL_Surface *surface);
53
54/* etc. */
55static void NDS_UpdateRects(_THIS, int numrects, SDL_Rect *rects);
56
57/* NDS driver bootstrap functions */
58
59static int NDS_Available(void)
60{
61	return(1);
62}
63
64static void NDS_DeleteDevice(SDL_VideoDevice *device)
65{
66	SDL_free(device->hidden);
67	SDL_free(device);
68}
69
70void on_irq_vblank()
71{
72  // Disable interrupts
73  //REG_IME = 0;
74  scanKeys();
75
76  //  VBLANK_INTR_WAIT_FLAGS |= IRQ_VBLANK;
77  //  REG_IF |= IRQ_VBLANK;
78  //REG_IF = REG_IF;
79
80  // Enable interrupts
81  //REG_IME = 1;
82}
83
84static int HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
85                        SDL_Surface *dst, SDL_Rect *dstrect)
86 {
87	return 0;
88 }
89
90static int CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dst)
91{
92 	if (src->flags & SDL_SRCALPHA) return false;
93 	if (src->flags & SDL_SRCCOLORKEY) return false;
94 	if (src->flags & SDL_HWPALETTE ) return false;
95 	if (dst->flags & SDL_SRCALPHA) return false;
96 	if (dst->flags & SDL_SRCCOLORKEY) return false;
97 	if (dst->flags & SDL_HWPALETTE ) return false;
98
99 	if (src->format->BitsPerPixel != dst->format->BitsPerPixel) return false;
100 	if (src->format->BytesPerPixel != dst->format->BytesPerPixel) return false;
101
102        src->map->hw_blit = HWAccelBlit;
103        return true;
104}
105
106static SDL_VideoDevice *NDS_CreateDevice(int devindex)
107{
108	SDL_VideoDevice *device=0;
109
110
111	/* Initialize all variables that we clean on shutdown */
112	device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
113	if ( device ) {
114		SDL_memset(device, 0, (sizeof *device));
115		device->hidden = (struct SDL_PrivateVideoData *)
116				SDL_malloc((sizeof *device->hidden));
117	}
118	if ( (device == NULL) || (device->hidden == NULL) ) {
119		SDL_OutOfMemory();
120		if ( device ) {
121			SDL_free(device);
122		}
123		return(0);
124	}
125	SDL_memset(device->hidden, 0, (sizeof *device->hidden));
126
127	/* Set the function pointers */
128	device->VideoInit = NDS_VideoInit;
129	device->ListModes = NDS_ListModes;
130	device->SetVideoMode = NDS_SetVideoMode;
131	device->CreateYUVOverlay = NULL;
132	device->SetColors = NDS_SetColors;
133	device->UpdateRects = NDS_UpdateRects;
134	device->VideoQuit = NDS_VideoQuit;
135	device->AllocHWSurface = NDS_AllocHWSurface;
136	device->CheckHWBlit = CheckHWBlit;
137	device->FillHWRect = NULL;
138	device->SetHWColorKey = NULL;
139	device->SetHWAlpha = NULL;
140	device->LockHWSurface = NDS_LockHWSurface;
141	device->UnlockHWSurface = NDS_UnlockHWSurface;
142	device->FlipHWSurface = NDS_FlipHWSurface;
143	device->FreeHWSurface = NDS_FreeHWSurface;
144	device->SetCaption = NULL;
145	device->SetIcon = NULL;
146	device->IconifyWindow = NULL;
147	device->GrabInput = NULL;
148	device->GetWMInfo = NULL;
149	device->InitOSKeymap = NDS_InitOSKeymap;
150	device->PumpEvents = NDS_PumpEvents;
151	device->info.blit_hw=1;
152
153	device->free = NDS_DeleteDevice;
154	return device;
155}
156
157VideoBootStrap NDS_bootstrap = {
158	NDSVID_DRIVER_NAME, "SDL NDS video driver",
159	NDS_Available, NDS_CreateDevice
160};
161
162	u16* frontBuffer;// = (u16*)(0x06000000);
163	u16* backBuffer;// =  (u16*)(0x06000000 + 256 * 256 * 2);
164int NDS_VideoInit(_THIS, SDL_PixelFormat *vformat)
165{
166	//printf("WARNING: You are using the SDL NDS video driver!\n");
167
168	/* Determine the screen depth (use default 8-bit depth) */
169	/* we change this during the SDL_SetVideoMode implementation... */
170	vformat->BitsPerPixel = 16;	// mode 3
171	vformat->BytesPerPixel = 2;
172	vformat->Rmask = 0x0000f800;
173	vformat->Gmask = 0x000007e0;
174	vformat->Bmask = 0x0000001f;
175    powerON(POWER_ALL);
176	irqInit();
177	irqSet(IRQ_VBLANK, on_irq_vblank);
178	irqEnable(IRQ_VBLANK);
179
180    //set the mode for 2 text layers and two extended background layers
181	//videoSetMode(MODE_5_2D | DISPLAY_BG3_ACTIVE);
182	videoSetMode(MODE_6_2D| DISPLAY_BG2_ACTIVE);
183
184	//set the sub background up for text display (we could just print to one
185	//of the main display text backgrounds just as easily
186	videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE); //sub bg 0 will be used to print text
187
188    //set the first two banks as background memory and the third as sub background memory
189    //D is not used..if you need a bigger background then you will need to map
190    //more vram banks consecutivly (VRAM A-D are all 0x20000 bytes in size)
191    //vramSetMainBanks(VRAM_A_MAIN_BG_0x6000000, VRAM_B_MAIN_BG_0x6020000,VRAM_C_SUB_BG , VRAM_D_LCD);
192	vramSetMainBanks(VRAM_A_MAIN_BG,VRAM_B_MAIN_BG,VRAM_C_MAIN_BG,VRAM_D_MAIN_BG);
193	//vramSetBankA(VRAM_A_MAIN_BG);
194	//vramSetBankB(VRAM_B_MAIN_BG);
195	//vramSetBankC(VRAM_C_MAIN_BG);
196	//vramSetBankD(VRAM_D_MAIN_BG);
197	//vramSetBankE(VRAM_E_MAIN_BG);
198	//vramSetBankF(VRAM_F_MAIN_BG);
199	//vramSetBankG(VRAM_G_MAIN_BG);
200	vramSetBankH(VRAM_H_SUB_BG);
201	vramSetBankI(VRAM_I_LCD);
202
203	////////////////set up text background for text/////////////////////
204    SUB_BG0_CR = BG_MAP_BASE(8);
205
206	BG_PALETTE_SUB[255] = RGB15(31,31,31);//by default font will be rendered with color 255
207	///////////////set up our bitmap background///////////////////////
208
209	//BG3_CR = BG_BMP16_512x512;
210
211	//these are rotation backgrounds so you must set the rotation attributes:
212    //these are fixed point numbers with the low 8 bits the fractional part
213    //this basicaly gives it a 1:1 translation in x and y so you get a nice flat bitmap
214      /*  BG3_XDX = 1<<8;
215        BG3_XDY = 0;
216        BG3_YDX = 0;
217        BG3_YDY = 1<<8;
218    //our bitmap looks a bit better if we center it so scroll down (256 - 192) / 2
219        BG3_CX = 0;
220        BG3_CY = 0;
221		*/
222	//consoleInit() is a lot more flexible but this gets you up and running quick
223	consoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(8), (u16*)CHAR_BASE_BLOCK_SUB(0), 16);
224
225
226	frontBuffer =(u16*)(0x06000000);
227	//backBuffer  =(u16*)(0x06000000 + 1024 * 512*2);
228
229	//lcdSwap();
230	/* We're done! */
231	return(0);
232}
233
234SDL_Rect **NDS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
235{
236	return (SDL_Rect **) -1;
237}
238
239SDL_Surface *NDS_SetVideoMode(_THIS, SDL_Surface *current,
240				int width, int height, int bpp, Uint32 flags)
241{
242	Uint32 Rmask, Gmask, Bmask, Amask;
243
244	//if(width > 1024 || height > 512 || bpp > 16)
245	//	return(NULL);
246
247	if(bpp >8) {
248		bpp=16;
249 		Rmask = 0x0000001F;
250		Gmask = 0x000003E0;
251		Bmask = 0x00007C00;
252		Amask = 0x00008000;
253
254		videoSetMode(MODE_5_2D| DISPLAY_BG2_ACTIVE);
255
256		vramSetMainBanks(VRAM_A_MAIN_BG,VRAM_B_MAIN_BG,VRAM_C_MAIN_BG,VRAM_D_MAIN_BG);
257
258		BG2_CR = BG_BMP16_512x512;
259	    BG2_XDX = ((width / 256) << 8) | (width % 256) ;
260        BG2_XDY = 0;
261        BG2_YDX = 0;
262        BG2_YDY = ((height / 192) << 8) | ((height % 192) + (height % 192) / 3) ;
263        BG2_CX = 0;
264        BG2_CY = 0;
265//        for (i=0;i<256*192;i++)
266//	        frontBuffer[i] = RGB15(31,0,0)|BIT(15);
267	}
268	else
269	if(bpp <= 8) {
270		bpp=8;
271		Rmask = 0x00000000;
272		Gmask = 0x00000000;
273		Bmask = 0x00000000;
274		BG2_CR = BG_BMP8_1024x512;
275        BG2_XDX = ((width / 256) << 8) | (width % 256) ;
276        BG2_XDY = 0;
277        BG2_YDX = 0;
278        BG2_YDY = ((height / 192) << 8) | ((height % 192) + (height % 192) / 3) ;
279
280	}
281	else
282		if(bpp < 15) bpp=15;
283	if(width<=256) width=256;
284	else
285		if(width<256) width=256;
286	if(height<=192) height=192;
287	else
288		if(height<192) height=192;
289
290	if(bpp==8)
291	{
292		if(width<256) width=256;
293		if(height<192) height=192;
294		this->hidden->ndsmode=4;
295	}
296
297	if(bpp==15)
298	{
299		if(width<256) this->hidden->ndsmode=5;
300		else this->hidden->ndsmode=3;
301	}
302
303	this->hidden->buffer= frontBuffer;//NDS_VRAM_BASE;
304
305	//NDS_DISPCNT = NDS_DISP_MODE(this->hidden->ndsmode)|NDS_DISP_BG2;
306
307 	//fprintf(stderr,"Setting mode %dx%d (ndsmode %d)\n", width, height,this->hidden->ndsmode);
308
309	// FIXME: How do I tell that 15 bits mode is 555?
310
311	SDL_memset(this->hidden->buffer, 0, 1024 * 512* ((this->hidden->ndsmode==4 || this->hidden->ndsmode==5) ? 2 : 1 ) * ((bpp+7) / 8));
312
313	/* Allocate the new pixel format for the screen */
314	if ( ! SDL_ReallocFormat(current, bpp, Rmask, Gmask, Bmask, Amask) ) {
315		this->hidden->buffer = NULL;
316		SDL_SetError("Couldn't allocate new pixel format for requested mode");
317		return(NULL);
318	}
319
320	/* Set up the new mode framebuffer */
321	current->flags = flags | SDL_FULLSCREEN | SDL_HWSURFACE | (this->hidden->ndsmode > 0 ? SDL_DOUBLEBUF : 0);
322	this->hidden->w = current->w = width;
323	this->hidden->h = current->h = height;
324	current->pixels = frontBuffer;
325
326	if (flags & SDL_DOUBLEBUF) {
327		this->hidden->secondbufferallocd=1;
328		backBuffer=(u16*)SDL_malloc(1024*512*2);
329		current->pixels = backBuffer;
330	}
331	if(bpp==8)
332		current->pitch =1024;
333	else
334		current->pitch =512*2;
335
336	/* We're done */
337	return(current);
338}
339
340static int NDS_AllocHWSurface(_THIS, SDL_Surface *surface)
341{
342	if(this->hidden->secondbufferallocd) {
343		//printf("double double buffer alloc\n");
344		return -1;
345	}
346	//if(this->hidden->ndsmode==3)
347	//{
348	//	printf("no 2nd buffer in mode3\n");
349	//	return -1;
350	//}
351	//printf("second buffer\n");
352	//this->hidden->secondbufferallocd=1;
353	//backBuffer=(u16*)malloc(1024*512*2);
354	//surface->pixels = backBuffer;
355
356	return(0);
357}
358static void NDS_FreeHWSurface(_THIS, SDL_Surface *surface)
359{
360	//free(backBuffer);
361	this->hidden->secondbufferallocd=0;
362}
363int z=0;
364/* We need to wait for vertical retrace on page flipped displays */
365static int NDS_LockHWSurface(_THIS, SDL_Surface *surface)
366{
367/*
368	uint8* a = surface->pixels;
369  int i,j;
370  a += 5 * SCREEN_WIDTH + 5;
371  for( i = 0; i < 195; ++i) {
372    uint16* line = a + (SCREEN_WIDTH * i);
373    for( j = 0; j < 158; ++j) {
374      *line++ = RGB15(155,155,25);
375    }
376  }
377*/
378	//if (z <256)
379	// BG_PALETTE[z++]=RGB15(255-z,z,255-z);
380
381
382	return(0);
383}
384
385static void NDS_UnlockHWSurface(_THIS, SDL_Surface *surface)
386{
387	return;
388}
389
390static int NDS_FlipHWSurface(_THIS, SDL_Surface *surface)
391{
392	if(this->hidden->secondbufferallocd){
393		while(DISP_Y!=192);
394	    while(DISP_Y==192);
395		//printf("flip");
396
397		dmaCopyAsynch(backBuffer,frontBuffer,1024*512);
398	}
399		//printf("flip\n");
400        //u16* temp = surface->pixels;
401        //surface->pixels = frontBuffer;
402        //frontBuffer = temp;
403	/*	u8* vram=BG_GFX;
404	int x,y;
405	for(y = 0; y < 512; y++)
406		dmaCopy(&frontBuffer[y*rects->w], &vram[y*512],512);
407	//unsigned char buf;
408
409	//printf("NDS_FlipHWSurface\n");
410	//printf("ptr now: 0x%x\n",surface->pixels);
411
412	    while(DISP_Y!=192);
413	    while(DISP_Y==192);
414        //swap
415        u16* temp = frontBuffer;
416        frontBuffer = backBuffer;
417        backBuffer = temp;
418
419        //flip
420        //base is 16KB and screen size is 256x256x2 (128KB)
421        BG2_CR ^= BG_BMP_BASE( 512 / 16 ); */
422/*
423	if(surface->pixels == frontBuffer)//NDS_VRAM_BASE)
424	{
425			while(DISP_Y!=192);
426	while(DISP_Y==192);
427        //swap
428        u16* temp = backBuffer;
429        backBuffer = frontBuffer;
430        frontBuffer = temp;
431
432        //flip
433        //base is 16KB and screen size is 256x256x2 (128KB)
434        BG3_CR ^= BG_BMP_BASE( 128 / 16 );
435	}
436	else
437	{
438
439		while(DISP_Y!=192);
440	while(DISP_Y==192);
441        //swap
442        u16* temp = frontBuffer;
443        frontBuffer = backBuffer;
444        backBuffer = temp;
445
446        //flip
447        //base is 16KB and screen size is 256x256x2 (128KB)
448        BG3_CR ^= BG_BMP_BASE( 128 / 16 );
449
450	}
451	*/
452	//printf("ptr then: 0x%x\n",surface->pixels);
453
454	//printf("setting dispcnt to 0x%x\n",NDS_DISPCNT = NDS_DISP_MODE(this->hidden->ndsmode)|NDS_DISP_BG2| buf);
455	return(0);
456}
457
458static void NDS_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
459{
460	//fprintf(stderr,"update\n");
461	/* do nothing. */
462	//dmaCopy(frontBuffer,BG_GFX,512*512);
463	 /*
464	u8* vram=(u8*)BG_GFX;
465	int x,y;
466	for(y = 0; y < 512; y++)
467		dmaCopy(&frontBuffer[y*rects->w], &vram[y*512],512);
468	 */
469
470}
471
472int NDS_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
473{
474	//printf("SetColors\n");
475	short r,g,b;
476
477	if(this->hidden->ndsmode != 4)
478	{
479		printf("This is not a palettized mode\n");
480		return -1;
481	}
482
483	int i,j=firstcolor+ncolors;
484	for(i=firstcolor;i<j;i++)
485	{
486		r=colors[i].r>>3;
487		g=colors[i].g>>3;
488		b=colors[i].b>>3;
489		BG_PALETTE[i]=RGB15(r, g, b);
490	}
491
492	return(0);
493}
494
495/* Note:  If we are terminated, this could be called in the middle of
496   another SDL video routine -- notably UpdateRects.
497*/
498void NDS_VideoQuit(_THIS)
499{
500}
501