1 #include <stdarg.h>
2 #include <libretro.h>
3 
4 #if defined(VITA)
5   int _newlib_heap_size_user = 128 * 1024 * 1024;
6 #endif
7 
8 #include "cheatSystem.h"
9 #include "MMU.h"
10 #include "NDSSystem.h"
11 #include "debug.h"
12 #include "render3D.h"
13 #include "rasterize.h"
14 #include "saves.h"
15 #include "firmware.h"
16 #include "GPU.h"
17 #include "SPU.h"
18 #include "emufile.h"
19 #include "common.h"
20 
21 #define LAYOUTS_MAX 9
22 
23 retro_log_printf_t log_cb = NULL;
24 static retro_video_refresh_t video_cb = NULL;
25 static retro_input_poll_t poll_cb = NULL;
26 static retro_input_state_t input_cb = NULL;
27 retro_audio_sample_batch_t audio_batch_cb = NULL;
28 retro_environment_t environ_cb = NULL;
29 
30 volatile int execute = 0;
31 
32 static int delay_timer = 0;
33 static bool quick_switch_enable = false;
34 static bool mouse_enable = false;
35 static double mouse_speed= 1.0;
36 static double mouse_x_delta = 0.0;
37 static double mouse_y_delta = 0.0;
38 static int pointer_device_l = 0;
39 static int pointer_device_r = 0;
40 static int analog_stick_deadzone;
41 static int analog_stick_acceleration = 2048;
42 static int analog_stick_acceleration_modifier = 0;
43 static int microphone_force_enable = 0;
44 static int nds_screen_gap = 0;
45 static int hybrid_layout_scale = 1;
46 static bool hybrid_layout_showbothscreens = true;
47 static bool hybrid_cursor_always_smallscreen = true;
48 static uint16_t pointer_colour = 0xFFFF;
49 
50 static uint16_t *screen_buf;
51 
52 extern GPUSubsystem *GPU;
53 
54 int currFrameCounter;
55 
56 unsigned GPU_LR_FRAMEBUFFER_NATIVE_WIDTH  = 256;
57 unsigned GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT = 192;
58 unsigned scale = 1;
59 
60 #define NDS_MAX_SCREEN_GAP               100
61 
62 int current_layout = LAYOUT_TOP_BOTTOM;
63 
64 struct LayoutData
65 {
66    uint16_t *dst;
67    uint16_t *dst2;
68    uint32_t touch_x;
69    uint32_t touch_y;
70    uint32_t width;
71    uint32_t height;
72    uint32_t pitch;
73    bool draw_screen1;
74    bool draw_screen2;
75 };
76 
77 static bool touchEnabled;
78 
host_get_language(void)79 static unsigned host_get_language(void)
80 {
81    static const u8 langconv[]={ // libretro to NDS
82       NDS_FW_LANG_ENG,
83       NDS_FW_LANG_JAP,
84       NDS_FW_LANG_FRE,
85       NDS_FW_LANG_SPA,
86       NDS_FW_LANG_GER,
87       NDS_FW_LANG_ITA
88    };
89 
90    unsigned lang = RETRO_LANGUAGE_ENGLISH;
91    environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &lang);
92    if (lang >= 6) lang = RETRO_LANGUAGE_ENGLISH;
93    return langconv[lang];
94 }
95 
Saturate(int32_t min,int32_t max,int32_t aValue)96 static inline int32_t Saturate(int32_t min, int32_t max, int32_t aValue)
97 {
98    return std::max(min, std::min(max, aValue));
99 }
100 
101 static int32_t TouchX;
102 static int32_t TouchY;
103 
104 static const uint32_t FramesWithPointerBase = 60 * 10;
105 static int32_t FramesWithPointer;
106 
DrawPointerLine(uint16_t * aOut,uint32_t aPitchInPix)107 static void DrawPointerLine(uint16_t* aOut, uint32_t aPitchInPix)
108 {
109    for(int i = 0; i < (5 * scale) ; i ++)
110       aOut[aPitchInPix * i] = pointer_colour;
111 }
112 
DrawPointerLineSmall(uint16_t * aOut,uint32_t aPitchInPix,int factor)113 static void DrawPointerLineSmall(uint16_t* aOut, uint32_t aPitchInPix, int factor)
114 {
115    for(int i = 0; i < (factor * scale) ; i ++)
116       aOut[aPitchInPix * i] = pointer_colour;
117 }
118 
DrawPointer(uint16_t * aOut,uint32_t aPitchInPix)119 static void DrawPointer(uint16_t* aOut, uint32_t aPitchInPix)
120 {
121    if(FramesWithPointer-- < 0)
122       return;
123 
124    TouchX = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1), TouchX);
125    TouchY = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT-1), TouchY);
126 
127    if(TouchX >   (5 * scale)) DrawPointerLine(&aOut[TouchY * aPitchInPix + TouchX - (5 * scale) ], 1);
128    if(TouchX < (GPU_LR_FRAMEBUFFER_NATIVE_WIDTH - (5 * scale) )) DrawPointerLine(&aOut[TouchY * aPitchInPix + TouchX + 1], 1);
129    if(TouchY >   (5 * scale)) DrawPointerLine(&aOut[(TouchY - (5 * scale) ) * aPitchInPix + TouchX], aPitchInPix);
130    if(TouchY < (GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT-(5 * scale) )) DrawPointerLine(&aOut[(TouchY + 1) * aPitchInPix + TouchX], aPitchInPix);
131 }
132 
DrawPointerHybrid(uint16_t * aOut,uint32_t aPitchInPix,bool large)133 static void DrawPointerHybrid(uint16_t* aOut, uint32_t aPitchInPix, bool large)
134 {
135    if(FramesWithPointer-- < 0)
136       return;
137 
138 	unsigned height,width;
139 	unsigned DrawX, DrawY;
140    if(!large)
141    {
142 	int addgap;
143 	if(nds_screen_gap >= hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/3)
144 	   addgap = hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/3-1;
145    	else
146 		addgap = nds_screen_gap;
147 	aOut += hybrid_layout_scale*(GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/3 + addgap)*hybrid_layout_scale*(GPU_LR_FRAMEBUFFER_NATIVE_WIDTH + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3);
148 	height = hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/3;
149 	int awidth = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3;
150 		width = hybrid_layout_scale*awidth;
151 		DrawX = Saturate(0, (width-1), TouchX);
152 		DrawY = Saturate(0, (height-1), TouchY);
153    }
154    else{
155 	   height = hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT;
156 		width = hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
157 		DrawX = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1), TouchX);
158 		DrawY = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT-1), TouchY);
159    }
160    int factor;
161    if(large)
162    {
163 	   factor = 5*hybrid_layout_scale;
164 	   if(hybrid_layout_scale == 3)
165 	   {
166 		   DrawX = 3*DrawX;
167 		   DrawY = 3*DrawY;
168 	   }
169    }
170    else if(hybrid_layout_scale == 3)
171 	   factor = 6;
172    else
173 	   factor = 3;
174    if(DrawX >   (factor * scale)) DrawPointerLineSmall(&aOut[DrawY * aPitchInPix + DrawX - (factor * scale) ], 1, factor);
175    if(DrawX < (width - (factor * scale) )) DrawPointerLineSmall(&aOut[DrawY * aPitchInPix + DrawX + 1], 1, factor);
176    if(DrawY >   (factor * scale)) DrawPointerLineSmall(&aOut[(DrawY - (factor * scale) ) * aPitchInPix + DrawX], aPitchInPix, factor);
177    if(DrawY < (height-(factor * scale) )) DrawPointerLineSmall(&aOut[(DrawY + 1) * aPitchInPix + DrawX], aPitchInPix, factor);
178 }
179 
180 
181 
182 static retro_pixel_format colorMode;
183 static uint32_t frameSkip;
184 static uint32_t frameIndex;
185 
186 #define CONVERT_COLOR(color) (((color & 0x001f) << 11) | ((color & 0x03e0) << 1) | ((color & 0x0200) >> 4) | ((color & 0x7c00) >> 10))
187 
Resample_Screen(int w1,int h1,bool shrink,const uint16_t * old,uint16_t * ret)188 bool Resample_Screen(int w1, int h1, bool shrink, const uint16_t *old, uint16_t *ret)
189     {
190 		int w2, h2, x2, y2 ;
191 		if(shrink)
192 		{
193 			w2 = w1/3;
194 			h2 = h1/3;
195 		}
196 		else
197 		{
198 			w2 = w1*3;
199 			h2 = h1*3;
200 		}
201 
202 		for (int i=0;i<h2;i++)
203 		{
204 			for (int j=0;j<w2;j++)
205 			{
206 				if(shrink){
207 					x2 = j*3;
208 					y2 = i*3;
209 				}
210 				else{
211 					x2 = j/3;
212 					y2 = i/3;
213 				}
214 				ret[(i*w2)+j] = old[(y2*w1)+x2] ;
215 			}
216 		}
217         return true;
218     }
219 
BlankScreenSmallSection(uint16_t * pt1,const uint16_t * pt2)220 static void BlankScreenSmallSection(uint16_t *pt1, const uint16_t *pt2){
221 	//Ensures above the hybrid screens is blank - If someone changes screen layout, stuff will be leftover otherwise
222 	unsigned i;
223 	pt1 += hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
224 	while( pt1 < pt2)
225 	{
226 		int awidth = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3;
227 		memset(pt1, 0, hybrid_layout_scale*awidth*sizeof(uint16_t));
228 		pt1 += hybrid_layout_scale*(GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3 + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH);
229 	}
230 }
231 
BlankScreenGap(uint16_t * screen1,uint16_t * screen2,uint32_t pitch)232 static void BlankScreenGap(uint16_t *screen1, uint16_t *screen2, uint32_t pitch) {
233 	if (nds_screen_gap == 0)
234 		return;
235 
236 	bool vertical;
237 	uint16_t *screen;
238 
239 	switch (current_layout) {
240 		case LAYOUT_TOP_BOTTOM:
241 			vertical = true;
242 			screen = screen1;
243 			break;
244 
245 		case LAYOUT_BOTTOM_TOP:
246 			vertical = true;
247 			screen = screen2;
248 			break;
249 
250 		case LAYOUT_LEFT_RIGHT:
251 			vertical = false;
252 			screen = screen1;
253 			break;
254 
255 		case LAYOUT_RIGHT_LEFT:
256 			vertical = false;
257 			screen = screen2;
258 			break;
259 
260 		default:
261 			return;
262 	}
263 
264 	if (vertical) {
265 		memset(screen + GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT * pitch, 0, nds_screen_gap * pitch * sizeof(uint16_t));
266 	}
267 	else {
268 		unsigned i;
269 		for (i = 0; i < GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT; i++) {
270 			memset (screen + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH, 0, nds_screen_gap * sizeof(uint16_t));
271 			screen += pitch;
272 		}
273 	}
274 }
275 
SwapScreen(uint16_t * dst,const uint16_t * src,uint32_t pitch)276 static void SwapScreen(uint16_t *dst, const uint16_t *src, uint32_t pitch)
277 {
278    unsigned i, j;
279    uint32_t skip = pitch - GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
280 
281    for(i = 0; i < GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT; i ++)
282    {
283       for(j = 0; j < GPU_LR_FRAMEBUFFER_NATIVE_WIDTH; j ++)
284       {
285          uint16_t col = *src++;
286          *dst++ = CONVERT_COLOR(col);
287       }
288       dst += skip;
289    }
290 }
291 
SwapScreenLarge(uint16_t * dst,const uint16_t * src,uint32_t pitch)292 static void SwapScreenLarge(uint16_t *dst, const uint16_t *src, uint32_t pitch)
293 {
294 	/*
295 	This method uses Nearest Neighbour to resize the primary screen to 3 times its original width and 3 times its original height.
296 	It is a lot faster than the previous method. If we want to apply some different method of scaling this needs to change.
297 	*/
298 	unsigned i, j, k;
299 	uint32_t skip = pitch - hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
300 
301 	unsigned heightlimit = hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT;
302 	for(i = 0; i < heightlimit; i ++)
303    {
304 	  if( i%hybrid_layout_scale != 0)
305 		  src -= GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
306       for(j = 0; j < GPU_LR_FRAMEBUFFER_NATIVE_WIDTH; j ++)
307       {
308 		 uint16_t col = *src++;
309 		 for(k = 0; k < hybrid_layout_scale; ++k)
310 			*dst++ = CONVERT_COLOR(col);
311       }
312       dst += skip;
313    }
314 }
315 
SwapScreenSmall(uint16_t * dst,const uint16_t * src,uint32_t pitch,bool first,bool draw)316 static void SwapScreenSmall(uint16_t *dst, const uint16_t *src, uint32_t pitch, bool first, bool draw)
317 {
318    unsigned i, j;
319 	int addgap;
320 	if(nds_screen_gap >= hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/3)
321 		addgap = hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/3 - 1;
322 	else
323 		addgap = nds_screen_gap;
324 	//If it is the bottom screen, start drawing lower down.
325 	if(!first)
326 	{
327 		dst += hybrid_layout_scale*(GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/3)*hybrid_layout_scale*(GPU_LR_FRAMEBUFFER_NATIVE_WIDTH + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3);
328 		//Make Sure The Screen Gap is Empty
329 		for(i=0; i< addgap; ++i)
330 		{
331 			memset(dst, 0, hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3*sizeof(uint16_t));
332 			dst += hybrid_layout_scale*(GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3 + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH);
333 		}
334 	}
335 
336 	if(hybrid_layout_scale != 3)
337 	{
338 		//Shrink to 1/3 the width and 1/3 the height
339 		uint16_t *resampl;
340 		resampl = (uint16_t*)malloc(GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/9*sizeof(uint16_t));
341 		Resample_Screen(GPU_LR_FRAMEBUFFER_NATIVE_WIDTH, GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT, true, src, resampl);
342 
343 		for(i=0; i<GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/3; ++i)
344 		{
345 			if(draw)
346 			{
347 				for(j=0; j<GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3; ++j)
348 					*dst++ = CONVERT_COLOR(resampl[i*(GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3)+j]);
349 			}
350 			else
351 			{
352 				memset(dst, 0, GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3*sizeof(uint16_t));
353 				dst += GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3;
354 			}
355 			dst += GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
356 		}
357 		free(resampl);
358 	}
359 	else
360 	{
361 		uint32_t skip = pitch - GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
362 		for(i=0; i<GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT; ++i)
363 		{
364 			if(draw)
365 			{
366 				for(j=0; j<GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1; ++j)
367 				{
368 					uint16_t col = *src++;
369 					*dst++ = CONVERT_COLOR(col);
370 				}
371 			}
372 			else
373 			{
374 				memset(dst, 0, (GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1)*sizeof(uint16_t));
375 				dst += GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1;
376 			}
377 			//Cuts off last pixel in width, because 3 does not divide native_width evenly. This prevents overwriting some of the main screen
378 			*src++; *dst++;
379 			dst += skip;
380 		}
381 	}
382 	//Make Sure underneath the Screens is Empty. Fixes leftovers when changing screen layout
383 	if(!first){
384 		int endheight = hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/3 - addgap;
385 		for(i=0; i<endheight; ++i){
386 			memset(dst, 0, hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3*sizeof(uint16_t));
387 			dst += hybrid_layout_scale*(GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3 + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH);
388 		}
389 	}
390 }
391 
392 namespace
393 {
394     uint32_t firmwareLanguage;
395 }
396 
retro_get_system_info(struct retro_system_info * info)397 void retro_get_system_info(struct retro_system_info *info)
398 {
399    info->library_name = "DeSmuME 2015";
400 #ifdef GIT_VERSION
401    info->library_version = "git" GIT_VERSION;
402 #else
403    info->library_version = "SVN";
404 #endif
405    info->valid_extensions = "nds|bin";
406    info->need_fullpath = true;
407    info->block_extract = false;
408 }
409 
get_layout_params(unsigned id,uint16_t * src,LayoutData * layout)410 static void get_layout_params(unsigned id, uint16_t *src, LayoutData *layout)
411 {
412    if (!layout)
413       return;
414 
415    switch (id)
416    {
417       case LAYOUT_TOP_BOTTOM:
418          if (src)
419          {
420             layout->dst    = src;
421             layout->dst2   = (uint16_t*)(src + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH * (GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT + nds_screen_gap));
422          }
423          layout->width  = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
424          layout->height = GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT * 2 + nds_screen_gap;
425          layout->pitch  = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
426          layout->touch_x= 0;
427          layout->touch_y= GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT + nds_screen_gap;
428 
429          layout->draw_screen1  = true;
430          layout->draw_screen2  = true;
431          break;
432       case LAYOUT_BOTTOM_TOP:
433          if (src)
434          {
435             layout->dst   = (uint16_t*)(src + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH * (GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT + nds_screen_gap));
436             layout->dst2  = src;
437          }
438          layout->width  = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
439          layout->height = GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT * 2 + nds_screen_gap;
440          layout->pitch  = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
441          layout->touch_x= 0;
442          layout->touch_y= 0;
443 
444          layout->draw_screen1  = true;
445          layout->draw_screen2  = true;
446          break;
447       case LAYOUT_LEFT_RIGHT:
448          if (src)
449          {
450             layout->dst    = src;
451             layout->dst2   = (uint16_t*)(src + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH + nds_screen_gap);
452          }
453          layout->width  = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH * 2 + nds_screen_gap;
454          layout->height = GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT;
455          layout->pitch  = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH * 2 + nds_screen_gap;
456          layout->touch_x= GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
457          layout->touch_y= 0;
458 
459          layout->draw_screen1  = true;
460          layout->draw_screen2  = true;
461          break;
462       case LAYOUT_RIGHT_LEFT:
463          if (src)
464          {
465             layout->dst   = (uint16_t*)(src + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH + nds_screen_gap);
466             layout->dst2  = src;
467          }
468          layout->width  = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH * 2 + nds_screen_gap;
469          layout->height = GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT;
470          layout->pitch  = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH * 2 + nds_screen_gap;
471          layout->touch_x= 0;
472          layout->touch_y= 0;
473 
474          layout->draw_screen1  = true;
475          layout->draw_screen2  = true;
476 		 break;
477       case LAYOUT_HYBRID_TOP_ONLY:
478 	  {
479 		  int awidth = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3;
480          if (src)
481          {
482             layout->dst    = src;
483 			int addgap;
484 			if(nds_screen_gap >= hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/3)
485 				addgap = hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/3-1;
486 			else
487 				addgap = nds_screen_gap;
488 			layout->dst2   = (uint16_t*)(src + hybrid_layout_scale*(GPU_LR_FRAMEBUFFER_NATIVE_WIDTH + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3)*( hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/6 - addgap/2) - hybrid_layout_scale*awidth);
489          }
490          layout->width  = hybrid_layout_scale*(GPU_LR_FRAMEBUFFER_NATIVE_WIDTH + awidth);
491          layout->height = hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT;
492          layout->pitch  = hybrid_layout_scale*(GPU_LR_FRAMEBUFFER_NATIVE_WIDTH + awidth);
493 		 //What should these touch values be?
494          layout->touch_x= GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
495          layout->touch_y= 0;
496 
497          layout->draw_screen1  = true;
498          layout->draw_screen2  = false;
499 	  }
500          break;
501       case LAYOUT_HYBRID_BOTTOM_ONLY:
502 		{
503 			int awidth = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3;
504          if (src)
505          {
506 			int addgap;
507 			if(nds_screen_gap >= GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/3)
508 				addgap = GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/3-1;
509 			else
510 				addgap = nds_screen_gap;
511             layout->dst   = (uint16_t*)(src + hybrid_layout_scale*(GPU_LR_FRAMEBUFFER_NATIVE_WIDTH + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/3)*( hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/6 - addgap/2) - hybrid_layout_scale*awidth);
512 			layout->dst2  = src;
513          }
514          layout->width  = hybrid_layout_scale*(GPU_LR_FRAMEBUFFER_NATIVE_WIDTH + awidth);
515          layout->height = hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT;
516          layout->pitch  = hybrid_layout_scale*(GPU_LR_FRAMEBUFFER_NATIVE_WIDTH + awidth);
517 		 //What should these touch values be?
518          layout->touch_x= 0;
519          layout->touch_y= hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT;
520 		}
521 
522          layout->draw_screen1  = false;
523          layout->draw_screen2  = true;
524          break;
525       case LAYOUT_TOP_ONLY:
526          if (src)
527          {
528             layout->dst    = src;
529             layout->dst2   = (uint16_t*)(src + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH * GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT);
530          }
531          layout->width  = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
532          layout->height = GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT;
533          layout->pitch  = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
534          layout->touch_x= 0;
535          layout->touch_y= GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT;
536 
537          layout->draw_screen1 = true;
538          break;
539       case LAYOUT_BOTTOM_ONLY:
540          if (src)
541          {
542             layout->dst    = (uint16_t*)(src + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH * GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT);
543             layout->dst2   = src;
544          }
545          layout->width  = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
546          layout->height = GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT;
547          layout->pitch  = GPU_LR_FRAMEBUFFER_NATIVE_WIDTH;
548          layout->touch_x= 0;
549          layout->touch_y= 0;
550 
551          layout->draw_screen2 = true;
552          break;
553    }
554 }
555 
retro_get_system_av_info(struct retro_system_av_info * info)556 void retro_get_system_av_info(struct retro_system_av_info *info)
557 {
558    struct LayoutData layout;
559    get_layout_params(current_layout, NULL, &layout);
560 
561    info->geometry.base_width   = layout.width;
562    info->geometry.base_height  = layout.height;
563    info->geometry.max_width    = layout.width * 2;
564    info->geometry.max_height   = layout.height;
565    info->geometry.aspect_ratio = 0.0;
566    info->timing.fps = 60.0;
567    info->timing.sample_rate = 44100.0;
568 }
569 
570 
MicrophoneToggle(void)571 static void MicrophoneToggle(void)
572 {
573    if (NDS_getFinalUserInput().mic.micButtonPressed)
574       NDS_setMic(false);
575    else
576       NDS_setMic(true);
577 }
578 
check_variables(bool first_boot)579 static void check_variables(bool first_boot)
580 {
581     struct retro_variable var = {0};
582 
583    if (first_boot)
584    {
585       var.key = "desmume_internal_resolution";
586 
587       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
588       {
589          char *pch;
590          char str[100];
591          snprintf(str, sizeof(str), "%s", var.value);
592 
593          pch = strtok(str, "x");
594          if (pch)
595             GPU_LR_FRAMEBUFFER_NATIVE_WIDTH = strtoul(pch, NULL, 0);
596          pch = strtok(NULL, "x");
597          if (pch)
598             GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT = strtoul(pch, NULL, 0);
599 
600          switch (GPU_LR_FRAMEBUFFER_NATIVE_WIDTH)
601          {
602             case 256:
603                scale = 1;
604                break;
605             case 512:
606                scale = 2;
607                break;
608             case 768:
609                scale = 3;
610                break;
611             case 1024:
612                scale = 4;
613                break;
614             case 1280:
615                scale = 5;
616                break;
617             case 1536:
618                scale = 6;
619                break;
620             case 1792:
621                scale = 7;
622                break;
623             case 2048:
624                scale = 8;
625                break;
626             case 2304:
627                scale = 9;
628                break;
629             case 2560:
630                scale = 10;
631                break;
632          }
633       }
634 
635       //This needs to be on first boot only as it affects the screen_buf size, unless want to realloc
636       var.key = "desmume_hybrid_layout_scale";
637 
638       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
639       {
640          if ((atoi(var.value)) != hybrid_layout_scale)
641          {
642             hybrid_layout_scale = atoi(var.value);
643             if (hybrid_layout_scale != 1 && hybrid_layout_scale != 3)
644                hybrid_layout_scale = 1;
645          }
646       }
647    }
648 
649    var.key = "desmume_num_cores";
650 
651    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
652       CommonSettings.num_cores = var.value ? strtol(var.value, 0, 10) : 1;
653    else
654       CommonSettings.num_cores = 1;
655 
656    var.key = "desmume_cpu_mode";
657    var.value = 0;
658 
659    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
660    {
661       if (!strcmp(var.value, "jit"))
662          CommonSettings.use_jit = true;
663       else if (!strcmp(var.value, "interpreter"))
664          CommonSettings.use_jit = false;
665    }
666    else
667    {
668 #ifdef HAVE_JIT
669       CommonSettings.use_jit = true;
670 #else
671       CommonSettings.use_jit = false;
672 #endif
673    }
674 
675 #ifdef HAVE_JIT
676    var.key = "desmume_jit_block_size";
677 
678    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
679       CommonSettings.jit_max_block_size = var.value ? strtol(var.value, 0, 10) : 100;
680    else
681    CommonSettings.jit_max_block_size = 100;
682 #endif
683 
684    var.key = "desmume_screens_layout";
685 
686    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
687    {
688       static int old_layout_id = -1;
689       unsigned new_layout_id   = 0;
690       quick_switch_enable      = false;
691 
692       if (!strcmp(var.value, "top/bottom"))
693          new_layout_id = LAYOUT_TOP_BOTTOM;
694       else if (!strcmp(var.value, "bottom/top"))
695          new_layout_id = LAYOUT_BOTTOM_TOP;
696       else if (!strcmp(var.value, "left/right"))
697          new_layout_id = LAYOUT_LEFT_RIGHT;
698       else if (!strcmp(var.value, "right/left"))
699          new_layout_id = LAYOUT_RIGHT_LEFT;
700       else if (!strcmp(var.value, "top only"))
701          new_layout_id = LAYOUT_TOP_ONLY;
702       else if (!strcmp(var.value, "bottom only"))
703          new_layout_id = LAYOUT_BOTTOM_ONLY;
704       else if(!strcmp(var.value, "hybrid/top"))
705       {
706          new_layout_id = LAYOUT_HYBRID_TOP_ONLY;
707          quick_switch_enable = true;
708       }
709       else if(!strcmp(var.value, "hybrid/bottom"))
710       {
711          new_layout_id = LAYOUT_HYBRID_BOTTOM_ONLY;
712          quick_switch_enable = true;
713       }
714       else if (!strcmp(var.value, "quick switch"))
715       {
716          new_layout_id = LAYOUT_TOP_ONLY;
717          quick_switch_enable = true;
718       }
719 
720       if (old_layout_id != new_layout_id)
721       {
722          old_layout_id = new_layout_id;
723          current_layout = new_layout_id;
724       }
725    }
726    else
727       quick_switch_enable = false;
728 
729     var.key = "desmume_pointer_mouse";
730 
731    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
732    {
733       if (!strcmp(var.value, "enabled"))
734          mouse_enable = true;
735       else if (!strcmp(var.value, "disabled"))
736          mouse_enable = false;
737    }
738    else
739       mouse_enable = false;
740 
741    var.key = "desmume_mouse_speed";
742 
743    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
744       mouse_speed = (float) atof(var.value);
745    else
746       mouse_speed = 1.0f;
747 
748    var.key = "desmume_pointer_device_l";
749 
750    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
751    {
752       if (!strcmp(var.value, "emulated"))
753          pointer_device_l = 1;
754       else if(!strcmp(var.value, "absolute"))
755          pointer_device_l = 2;
756       else if (!strcmp(var.value, "pressed"))
757          pointer_device_l = 3;
758       else
759          pointer_device_l=0;
760    }
761    else
762       pointer_device_l=0;
763 
764    var.key = "desmume_pointer_device_r";
765 
766    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
767    {
768       if (!strcmp(var.value, "emulated"))
769          pointer_device_r = 1;
770       else if(!strcmp(var.value, "absolute"))
771          pointer_device_r = 2;
772       else if (!strcmp(var.value, "pressed"))
773          pointer_device_r = 3;
774       else
775          pointer_device_r=0;
776    }
777    else
778       pointer_device_r=0;
779 
780    var.key = "desmume_pointer_device_deadzone";
781 
782    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
783       analog_stick_deadzone = (int)(atoi(var.value));
784 
785    var.key = "desmume_pointer_type";
786 
787    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
788       touchEnabled = var.value && (!strcmp(var.value, "touch"));
789 
790    var.key = "desmume_frameskip";
791 
792    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
793       frameSkip = var.value ? strtol(var.value, 0, 10) : 0;
794    else
795       frameSkip = 0;
796 
797    var.key = "desmume_firmware_language";
798 
799    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
800    {
801       static const struct { const char* name; int id; } languages[] =
802       {
803          { "Auto", -1 },
804          { "Japanese", 0 },
805          { "English", 1 },
806          { "French", 2 },
807          { "German", 3 },
808          { "Italian", 4 },
809          { "Spanish", 5 }
810       };
811 
812       for (int i = 0; i < 7; i ++)
813       {
814          if (!strcmp(languages[i].name, var.value))
815          {
816             firmwareLanguage = languages[i].id;
817             if (firmwareLanguage == -1) firmwareLanguage = host_get_language();
818                break;
819          }
820       }
821    }
822    else
823       firmwareLanguage = 1;
824 
825 
826    var.key = "desmume_gfx_edgemark";
827 
828    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
829    {
830       if (!strcmp(var.value, "enabled"))
831          CommonSettings.GFX3D_EdgeMark = true;
832       else if (!strcmp(var.value, "disabled"))
833          CommonSettings.GFX3D_EdgeMark = false;
834    }
835    else
836       CommonSettings.GFX3D_EdgeMark = true;
837 
838    var.key = "desmume_gfx_linehack";
839 
840    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
841    {
842       if (!strcmp(var.value, "enabled"))
843          CommonSettings.GFX3D_LineHack = true;
844       else if (!strcmp(var.value, "disabled"))
845          CommonSettings.GFX3D_LineHack = false;
846    }
847    else
848       CommonSettings.GFX3D_LineHack = true;
849 
850    var.key = "desmume_gfx_txthack";
851 
852    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
853    {
854       if (!strcmp(var.value, "enabled"))
855          CommonSettings.GFX3D_TXTHack = true;
856       else if (!strcmp(var.value, "disabled"))
857          CommonSettings.GFX3D_TXTHack = false;
858    }
859    else
860       CommonSettings.GFX3D_TXTHack = false;
861 
862    var.key = "desmume_mic_force_enable";
863 
864    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
865    {
866       if (!strcmp(var.value, "enabled"))
867          microphone_force_enable = 1;
868       else if(!strcmp(var.value, "disabled"))
869          microphone_force_enable = 0;
870    }
871    else
872       NDS_setMic(false);
873 
874    var.key = "desmume_mic_mode";
875 
876     if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
877    {
878       if (!strcmp(var.value, "internal"))
879          CommonSettings.micMode = TCommonSettings::InternalNoise;
880       else if(!strcmp(var.value, "sample"))
881          CommonSettings.micMode = TCommonSettings::Sample;
882       else if(!strcmp(var.value, "random"))
883          CommonSettings.micMode = TCommonSettings::Random;
884       else if(!strcmp(var.value, "physical"))
885          CommonSettings.micMode = TCommonSettings::Physical;
886    }
887    else
888       CommonSettings.micMode = TCommonSettings::InternalNoise;
889 
890    var.key = "desmume_pointer_device_acceleration_mod";
891 
892    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
893       analog_stick_acceleration_modifier = atoi(var.value);
894    else
895       analog_stick_acceleration_modifier = 0;
896 
897    var.key = "desmume_pointer_stylus_pressure";
898 
899    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
900       CommonSettings.StylusPressure = atoi(var.value);
901    else
902       CommonSettings.StylusPressure = 50;
903 
904    var.key = "desmume_pointer_stylus_jitter";
905 
906    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
907    {
908       if (!strcmp(var.value, "enabled"))
909          CommonSettings.StylusJitter = true;
910       else if (!strcmp(var.value, "disabled"))
911          CommonSettings.StylusJitter = false;
912    }
913    else
914       CommonSettings.StylusJitter = false;
915 
916    var.key = "desmume_load_to_memory";
917 
918    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
919    {
920       if (!strcmp(var.value, "enabled"))
921          CommonSettings.loadToMemory = true;
922       else if (!strcmp(var.value, "disabled"))
923          CommonSettings.loadToMemory = false;
924    }
925    else
926       CommonSettings.loadToMemory = false;
927 
928    var.key = "desmume_advanced_timing";
929 
930    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
931    {
932       if (!strcmp(var.value, "enabled"))
933          CommonSettings.advanced_timing = true;
934       else if (!strcmp(var.value, "disabled"))
935          CommonSettings.advanced_timing = false;
936    }
937    else
938       CommonSettings.advanced_timing = true;
939 
940    var.key = "desmume_screens_gap";
941 
942    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
943    {
944       if ((atoi(var.value)) != nds_screen_gap)
945       {
946          nds_screen_gap = atoi(var.value);
947          if (nds_screen_gap > 100)
948             nds_screen_gap = 100;
949       }
950    }
951 
952    var.key = "desmume_hybrid_showboth_screens";
953 
954    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
955    {
956       if (!strcmp(var.value, "enabled"))
957          hybrid_layout_showbothscreens = true;
958       else if(!strcmp(var.value, "disabled"))
959          hybrid_layout_showbothscreens = false;
960    }
961    else
962       hybrid_layout_showbothscreens = true;
963 
964    var.key = "desmume_hybrid_cursor_always_smallscreen";
965 
966    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
967    {
968       if (!strcmp(var.value, "enabled"))
969          hybrid_cursor_always_smallscreen = true;
970       else if(!strcmp(var.value, "disabled"))
971          hybrid_cursor_always_smallscreen = false;
972    }
973    else
974       hybrid_cursor_always_smallscreen = true;
975 
976    var.key = "desmume_pointer_colour";
977 
978    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
979    {
980       if(!strcmp(var.value, "white"))
981          pointer_colour = 0xFFFF;
982       else if (!strcmp(var.value, "black"))
983          pointer_colour = 0x0000;
984       else if(!strcmp(var.value, "red"))
985          pointer_colour = 0xF800;
986       else if(!strcmp(var.value, "yellow"))
987          pointer_colour = 0xFFE0;
988       else if(!strcmp(var.value, "blue"))
989          pointer_colour = 0x001F;
990       else
991          pointer_colour = 0xFFFF;
992    }
993    else
994       pointer_colour = 0xFFFF;
995 }
996 
997 #ifndef GPU3D_NULL
998 #define GPU3D_NULL 0
999 #endif
1000 
1001 #ifdef HAVE_OPENGL
1002 #define GPU3D_OPENGL_3_2 1
1003 #define GPU3D_SWRAST     2
1004 #define GPU3D_OPENGL_OLD 3
1005 #else
1006 #define GPU3D_SWRAST     1
1007 #endif
1008 
1009 GPU3DInterface* core3DList[] =
1010 {
1011    &gpu3DNull,
1012 #ifdef HAVE_OPENGL
1013    &gpu3Dgl_3_2,
1014 #endif
1015     &gpu3DRasterize,
1016 #ifdef HAVE_OPENGL
1017     &gpu3DglOld,
1018 #endif
1019     NULL
1020 };
1021 
retro_set_video_refresh(retro_video_refresh_t cb)1022 void retro_set_video_refresh(retro_video_refresh_t cb) { video_cb = cb; }
retro_set_audio_sample(retro_audio_sample_t cb)1023 void retro_set_audio_sample(retro_audio_sample_t cb)   { }
retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)1024 void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) { audio_batch_cb = cb; }
retro_set_input_poll(retro_input_poll_t cb)1025 void retro_set_input_poll(retro_input_poll_t cb) { poll_cb = cb; }
retro_set_input_state(retro_input_state_t cb)1026 void retro_set_input_state(retro_input_state_t cb) { input_cb = cb; }
1027 
retro_set_environment(retro_environment_t cb)1028 void retro_set_environment(retro_environment_t cb)
1029 {
1030    environ_cb = cb;
1031 
1032    static const retro_variable values[] =
1033    {
1034       { "desmume_internal_resolution", "Internal resolution (restart); 256x192|512x384|768x576|1024x768|1280x960|1536x1152|1792x1344|2048x1536|2304x1728|2560x1920" },
1035       { "desmume_num_cores", "CPU cores; 1|2|3|4" },
1036 #ifdef HAVE_JIT
1037 #if defined(IOS) || defined(ANDROID)
1038       { "desmume_cpu_mode", "CPU mode; interpreter|jit" },
1039 #else
1040       { "desmume_cpu_mode", "CPU mode; jit|interpreter" },
1041 #endif
1042       { "desmume_jit_block_size", "JIT block size; 12|11|10|9|8|7|6|5|4|3|2|1|0|100|99|98|97|96|95|94|93|92|91|90|89|88|87|86|85|84|83|82|81|80|79|78|77|76|75|74|73|72|71|70|69|68|67|66|65|64|63|62|61|60|59|58|57|56|55|54|53|52|51|50|49|48|47|46|45|44|43|42|41|40|39|38|37|36|35|34|33|32|31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13" },
1043 #else
1044       { "desmume_cpu_mode", "CPU mode; interpreter" },
1045 #endif
1046       { "desmume_screens_layout", "Screen layout; top/bottom|bottom/top|left/right|right/left|top only|bottom only|quick switch|hybrid/top|hybrid/bottom" },
1047       { "desmume_hybrid_layout_scale", "Hybrid layout scale (restart); 1|3"},
1048       { "desmume_hybrid_showboth_screens", "Hybrid layout show both screens; enabled|disabled"},
1049       { "desmume_hybrid_cursor_always_smallscreen", "Hybrid layout cursor always on small screen; enabled|disabled"},
1050       { "desmume_pointer_mouse", "Enable mouse/pointer; enabled|disabled" },
1051       { "desmume_pointer_type", "Pointer type; mouse|touch" },
1052       { "desmume_mouse_speed", "Mouse Speed; 1.0|1.5|2.0|0.125|0.25|0.5"},
1053       { "desmume_pointer_colour", "Pointer Colour; white|black|red|blue|yellow"},
1054       { "desmume_pointer_device_l", "Pointer mode l-analog; none|emulated|absolute|pressed" },
1055       { "desmume_pointer_device_r", "Pointer mode r-analog; none|emulated|absolute|pressed" },
1056       { "desmume_pointer_device_deadzone", "Emulated pointer deadzone percent; 15|20|25|30|35|0|5|10" },
1057       { "desmume_pointer_device_acceleration_mod", "Emulated pointer acceleration modifier percent; 0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100" },
1058       { "desmume_pointer_stylus_pressure", "Emulated stylus pressure modifier percent; 50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|" },
1059       { "desmume_pointer_stylus_jitter", "Enable emulated stylus jitter; disabled|enabled"},
1060       { "desmume_load_to_memory", "Load Game into Memory (restart); disabled|enabled" },
1061       { "desmume_advanced_timing", "Enable Advanced Bus-Level Timing; enabled|disabled" },
1062       { "desmume_firmware_language", "Firmware language; Auto|English|Japanese|French|German|Italian|Spanish" },
1063       { "desmume_frameskip", "Frameskip; 0|1|2|3|4|5|6|7|8|9" },
1064       { "desmume_screens_gap", "Screen Gap; 0|5|64|90|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100" },
1065       { "desmume_gfx_edgemark", "Enable Edgemark; enabled|disabled" },
1066       { "desmume_gfx_linehack", "Enable Line Hack; enabled|disabled" },
1067       { "desmume_gfx_txthack", "Enable TXT Hack; disabled|enabled"},
1068       { "desmume_mic_force_enable", "Force Microphone Enable; disabled|enabled" },
1069       { "desmume_mic_mode", "Microphone Simulation Settings; internal|sample|random|physical" },
1070       { 0, 0 }
1071    };
1072 
1073    environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)values);
1074 }
1075 
1076 
1077 //====================== Message box
1078 #define MSG_ARG \
1079     char msg_buf[1024] = {0}; \
1080     { \
1081         va_list args; \
1082         va_start (args, fmt); \
1083         vsprintf (msg_buf, fmt, args); \
1084         va_end (args); \
1085     }
1086 
msgWndInfo(const char * fmt,...)1087 void msgWndInfo(const char *fmt, ...)
1088 {
1089     MSG_ARG;
1090    if (log_cb)
1091       log_cb(RETRO_LOG_INFO, "%s.\n", msg_buf);
1092 }
1093 
msgWndConfirm(const char * fmt,...)1094 bool msgWndConfirm(const char *fmt, ...)
1095 {
1096     MSG_ARG;
1097    if (log_cb)
1098       log_cb(RETRO_LOG_INFO, "%s.\n", msg_buf);
1099    return true;
1100 }
1101 
msgWndError(const char * fmt,...)1102 void msgWndError(const char *fmt, ...)
1103 {
1104     MSG_ARG;
1105    if (log_cb)
1106       log_cb(RETRO_LOG_ERROR, "%s.\n", msg_buf);
1107 }
1108 
msgWndWarn(const char * fmt,...)1109 void msgWndWarn(const char *fmt, ...)
1110 {
1111     MSG_ARG;
1112    if (log_cb)
1113       log_cb(RETRO_LOG_WARN, "%s.\n", msg_buf);
1114 }
1115 
1116 msgBoxInterface msgBoxWnd = {
1117     msgWndInfo,
1118     msgWndConfirm,
1119     msgWndError,
1120     msgWndWarn,
1121 };
1122 //====================== Dialogs end
1123 
check_system_specs(void)1124 static void check_system_specs(void)
1125 {
1126    unsigned level = 15;
1127    environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level);
1128 }
1129 
Change3DCoreWithFallback(int newCore)1130 static void Change3DCoreWithFallback(int newCore)
1131 {
1132    if( (newCore < 0)
1133 #ifdef HAVE_OPENGL
1134          || (newCore > GPU3D_OPENGL_OLD)
1135 #endif
1136          )
1137       newCore = GPU3D_SWRAST;
1138 
1139    printf("Attempting change to 3d core to: %s\n",core3DList[newCore]->name);
1140 
1141 #ifdef HAVE_OPENGL
1142    if(newCore == GPU3D_OPENGL_OLD)
1143       goto TRY_OGL_OLD;
1144 #endif
1145 
1146    if(newCore == GPU3D_SWRAST)
1147       goto TRY_SWRAST;
1148 
1149    if(newCore == GPU3D_NULL)
1150    {
1151       NDS_3D_ChangeCore(GPU3D_NULL);
1152       cur3DCore = GPU3D_NULL;
1153       goto DONE;
1154    }
1155 
1156 #ifdef HAVE_OPENGL
1157    if(!NDS_3D_ChangeCore(GPU3D_OPENGL_3_2))
1158    {
1159       printf("falling back to 3d core: %s\n",core3DList[GPU3D_OPENGL_OLD]->name);
1160       cur3DCore = GPU3D_OPENGL_3_2;
1161       goto TRY_OGL_OLD;
1162    }
1163 #endif
1164    goto DONE;
1165 
1166 #ifdef HAVE_OPENGL
1167 TRY_OGL_OLD:
1168    if(!NDS_3D_ChangeCore(GPU3D_OPENGL_OLD))
1169    {
1170       printf("falling back to 3d core: %s\n",core3DList[GPU3D_SWRAST]->name);
1171       cur3DCore = GPU3D_OPENGL_OLD;
1172       goto TRY_SWRAST;
1173    }
1174    goto DONE;
1175 
1176 #endif
1177 TRY_SWRAST:
1178    cur3DCore = GPU3D_SWRAST;
1179    NDS_3D_ChangeCore(GPU3D_SWRAST);
1180 
1181 DONE:
1182    (void)0;
1183 }
1184 
retro_init(void)1185 void retro_init (void)
1186 {
1187    struct retro_log_callback log;
1188    if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
1189       log_cb = log.log;
1190    else
1191       log_cb = NULL;
1192 
1193     colorMode = RETRO_PIXEL_FORMAT_RGB565;
1194     if(!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &colorMode))
1195        return;
1196 
1197     check_variables(true);
1198 
1199     // Init DeSmuME
1200     struct NDS_fw_config_data fw_config;
1201     NDS_FillDefaultFirmwareConfigData(&fw_config);
1202     fw_config.language = firmwareLanguage;
1203 
1204 
1205     //addonsChangePak(NDS_ADDON_NONE);
1206     NDS_Init();
1207     SPU_ChangeSoundCore(0, 735 * 2);
1208     NDS_CreateDummyFirmware(&fw_config);
1209 
1210     Change3DCoreWithFallback(GPU3D_SWRAST);
1211 
1212     backup_setManualBackupType(MC_TYPE_AUTODETECT);
1213 
1214     msgbox = &msgBoxWnd;
1215    check_system_specs();
1216 }
1217 
retro_deinit(void)1218 void retro_deinit(void)
1219 {
1220     NDS_DeInit();
1221 
1222 #ifdef PERF_TEST
1223    rarch_perf_log();
1224 #endif
1225 }
1226 
retro_reset(void)1227 void retro_reset (void)
1228 {
1229     NDS_Reset();
1230 }
1231 
retro_run(void)1232 void retro_run (void)
1233 {
1234    struct LayoutData layout;
1235    bool updated                  = false;
1236    bool have_touch               = false;
1237 
1238    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
1239    {
1240       check_variables(false);
1241       struct retro_system_av_info new_av_info;
1242       retro_get_system_av_info(&new_av_info);
1243 
1244       environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &new_av_info);
1245    }
1246 
1247    poll_cb();
1248    get_layout_params(current_layout, screen_buf, &layout);
1249 
1250    if(pointer_device_l != 0 || pointer_device_r != 0)  // 1=emulated pointer, 2=absolute pointer, 3=absolute pointer constantly pressed
1251    {
1252         int16_t analogX_l = 0;
1253         int16_t analogY_l = 0;
1254         int16_t analogX_r = 0;
1255         int16_t analogY_r = 0;
1256         int16_t analogX = 0;
1257         int16_t analogY = 0;
1258         int16_t analogXpointer = 0;
1259         int16_t analogYpointer = 0;
1260 
1261         //emulated pointer on one or both sticks
1262         //just prioritize the stick that has a higher radius
1263         if((pointer_device_l == 1) || (pointer_device_r == 1))
1264         {
1265             double radius = 0;
1266             double angle = 0;
1267             float final_acceleration = analog_stick_acceleration * (1.0 + (float)analog_stick_acceleration_modifier / 100.0);
1268 
1269             if((pointer_device_l == 1) && (pointer_device_r == 1))
1270             {
1271                 analogX_l = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X) /  final_acceleration;
1272                 analogY_l = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y) / final_acceleration;
1273                 analogX_r = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X) /  final_acceleration;
1274                 analogY_r = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y) / final_acceleration;
1275 
1276                 double radius_l = sqrt(analogX_l * analogX_l + analogY_l * analogY_l);
1277                 double radius_r = sqrt(analogX_r * analogX_r + analogY_r * analogY_r);
1278 
1279                 if(radius_l > radius_r)
1280                 {
1281                     radius = radius_l;
1282                     angle = atan2(analogY_l, analogX_l);
1283                     analogX = analogX_l;
1284                     analogY = analogY_l;
1285                 }
1286                 else
1287                 {
1288                     radius = radius_r;
1289                     angle = atan2(analogY_r, analogX_r);
1290                     analogX = analogX_r;
1291                     analogY = analogY_r;
1292                 }
1293             }
1294 
1295             else if(pointer_device_l == 1)
1296             {
1297                 analogX = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X) / final_acceleration;
1298                 analogY = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y) / final_acceleration;
1299                 radius = sqrt(analogX * analogX + analogY * analogY);
1300                 angle = atan2(analogY, analogX);
1301             }
1302             else
1303             {
1304                 analogX = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X) / final_acceleration;
1305                 analogY = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y) / final_acceleration;
1306                 radius = sqrt(analogX * analogX + analogY * analogY);
1307                 angle = atan2(analogY, analogX);
1308             }
1309 
1310             // Convert cartesian coordinate analog stick to polar coordinates
1311             double max = (float)0x8000/analog_stick_acceleration;
1312 
1313             //log_cb(RETRO_LOG_DEBUG, "%d %d.\n", analogX,analogY);
1314             //log_cb(RETRO_LOG_DEBUG, "%d %d.\n", radius,analog_stick_deadzone);
1315             if(radius > (float)analog_stick_deadzone*max/100)
1316             {
1317                 // Re-scale analog stick range to negate deadzone (makes slow movements possible)
1318                 radius = (radius - (float)analog_stick_deadzone*max/100)*((float)max/(max - (float)analog_stick_deadzone*max/100));
1319 
1320                 // Convert back to cartesian coordinates
1321                 analogXpointer = (int32_t)round(radius * cos(angle));
1322                 analogYpointer = (int32_t)round(radius * sin(angle));
1323 
1324                 TouchX = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1), TouchX + analogXpointer);
1325                 TouchY = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT-1), TouchY + analogYpointer);
1326 
1327 
1328             }
1329 
1330         }
1331 
1332         //absolute pointer -- doesn't run if emulated pointer > deadzone
1333         if(((pointer_device_l == 2) || (pointer_device_l == 3) || (pointer_device_r == 2) || (pointer_device_r == 3)) && !(analogXpointer || analogYpointer))
1334         {
1335             if(((pointer_device_l == 2) || (pointer_device_l == 3)) && ((pointer_device_r == 2) || (pointer_device_r == 3))) //both sticks set to absolute or pressed
1336             {
1337 
1338                 if(pointer_device_l == 3) //left analog is always pressed
1339                 {
1340                     int16_t analogXpress = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X);
1341                     int16_t analogYpress = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y);
1342 
1343                     double radius = sqrt(analogXpress * analogXpress + analogYpress * analogYpress);
1344 
1345                     //check if analog exceeds deadzone
1346                     if (radius > (float)analog_stick_deadzone*0x8000/100)
1347                     {
1348                         have_touch = 1;
1349 
1350                         //scale analog position to ellipse enclosing framebuffer rectangle
1351                         analogX = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/2*analogXpress / (float)0x8000;
1352                         analogY = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/2*analogYpress / (float)0x8000;
1353 
1354                     }
1355                     else if (pointer_device_r == 2) //use the other stick as absolute
1356                     {
1357                         analogX = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/2*input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X) / (float)0x8000;
1358                         analogY = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/2*input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y) / (float)0x8000;
1359                     }
1360                 }
1361 
1362                 else if(pointer_device_r == 3) // right analog is always pressed
1363                 {
1364                     int16_t analogXpress = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X);
1365                     int16_t analogYpress = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y);
1366 
1367                     double radius = sqrt(analogXpress * analogXpress + analogYpress * analogYpress);
1368 
1369                     if (radius > (float)analog_stick_deadzone*0x8000/100)
1370                     {
1371                         have_touch = 1;
1372                         analogX = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/2*analogXpress / (float)0x8000;
1373                         analogY = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/2*analogYpress / (float)0x8000;
1374 
1375                     }
1376                     else if (pointer_device_l == 2)
1377                     {
1378                         analogX = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/2*input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X) / (float)0x8000;
1379                         analogY = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/2*input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y) / (float)0x8000;
1380                     }
1381 
1382                 }
1383                 else //right analog takes priority when both set to absolute
1384                 {
1385                     analogX = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/2*input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X) / (float)0x8000;
1386                     analogY = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/2*input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y) / (float)0x8000;
1387                 }
1388 
1389                 //set absolute analog position offset to center of screen
1390                 TouchX = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1), analogX + ((GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1) / 2));
1391                 TouchY = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT-1), analogY + ((GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT-1) / 2));
1392             }
1393 
1394             else if((pointer_device_l == 2) || (pointer_device_l == 3))
1395             {
1396                 if(pointer_device_l == 2)
1397                 {
1398                     analogX = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X);
1399                     analogY = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y);
1400                     analogX = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/2*analogX / (float)0x8000;
1401                     analogY = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/2*analogY / (float)0x8000;
1402 
1403                     TouchX = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1), analogX + ((GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1) / 2));
1404                     TouchY = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT-1), analogY + ((GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT-1) / 2));
1405 
1406 
1407                 }
1408                 if(pointer_device_l == 3)
1409                 {
1410                     int16_t analogXpress = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X);
1411                     int16_t analogYpress = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y);
1412                     double radius = sqrt(analogXpress * analogXpress + analogYpress * analogYpress);
1413                     if (radius > (float)analog_stick_deadzone*(float)0x8000/100)
1414                     {
1415                         have_touch = 1;
1416                         analogX = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/2*analogXpress / (float)0x8000;
1417                         analogY = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/2*analogYpress / (float)0x8000;
1418 
1419                         TouchX = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1), analogX + ((GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1) / 2));
1420                         TouchY = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT-1), analogY + ((GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT-1) / 2));
1421                     }
1422                 }
1423             }
1424 
1425             else
1426             {
1427                 if(pointer_device_r == 2)
1428                 {
1429                     analogX = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X);
1430                     analogY = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y);
1431                     analogX = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/2*analogX / (float)0x8000;
1432                     analogY = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/2*analogY / (float)0x8000;
1433 
1434                     TouchX = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1), analogX + ((GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1) / 2));
1435                     TouchY = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT-1), analogY + ((GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT-1) / 2));
1436                 }
1437 
1438                 if(pointer_device_r == 3)
1439                 {
1440                     int16_t analogXpress = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X);
1441                     int16_t analogYpress = input_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y);
1442                     double radius = sqrt(analogXpress * analogXpress + analogYpress * analogYpress);
1443                     if (radius > (float)analog_stick_deadzone*(float)0x8000/100)
1444                     {
1445                         have_touch = 1;
1446                         analogX = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH/2*analogXpress / (float)0x8000;
1447                         analogY = sqrt(2)*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT/2*analogYpress / (float)0x8000;
1448 
1449                         TouchX = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1), analogX + ((GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1) / 2));
1450                         TouchY = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT-1), analogY + ((GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT-1) / 2));
1451 
1452                     }
1453                 }
1454             }
1455         }
1456 
1457         //log_cb(RETRO_LOG_DEBUG, "%d %d.\n", GPU_LR_FRAMEBUFFER_NATIVE_WIDTH,GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT);
1458         //log_cb(RETRO_LOG_DEBUG, "%d %d.\n", analogX,analogY);
1459 
1460         have_touch = have_touch || input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2);
1461 
1462         FramesWithPointer = (analogX || analogY) ? FramesWithPointerBase : FramesWithPointer;
1463 
1464    }
1465 
1466    if(mouse_enable)
1467    {
1468       // TOUCH: Mouse
1469       if(!touchEnabled)
1470       {
1471          int16_t mouseX = input_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X);
1472          int16_t mouseY = input_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y);
1473          have_touch           = have_touch || input_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT);
1474 
1475          mouse_x_delta += mouseX * mouse_speed;
1476          mouse_y_delta += mouseY * mouse_speed;
1477 
1478          mouseX = (int16_t) trunc(mouse_x_delta);
1479          mouse_x_delta -= mouseX;
1480          mouseY = (int16_t) trunc(mouse_y_delta);
1481          mouse_y_delta -= mouseY;
1482 
1483          TouchX = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_WIDTH-1), TouchX + mouseX);
1484          TouchY = Saturate(0, (GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT-1), TouchY + mouseY);
1485          FramesWithPointer = (mouseX || mouseY) ? FramesWithPointerBase : FramesWithPointer;
1486       }
1487       // TOUCH: Pointer
1488       else if(input_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED))
1489       {
1490          const float X_FACTOR = ((float)layout.width / 65536.0f);
1491          const float Y_FACTOR = ((float)layout.height / 65536.0f);
1492 
1493          float x = (input_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X) + 32768.0f) * X_FACTOR;
1494          float y = (input_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y) + 32768.0f) * Y_FACTOR;
1495 
1496          if ((x >= layout.touch_x) && (x < layout.touch_x + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH) &&
1497                (y >= layout.touch_y) && (y < layout.touch_y + GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT))
1498          {
1499             have_touch = true;
1500 
1501             TouchX = x - layout.touch_x;
1502             TouchY = y - layout.touch_y;
1503          }
1504       }
1505    }
1506 
1507    if(have_touch)
1508    {
1509 	   //Hybrid layout requires "rescaling" of coordinates. No idea how this works on actual touch screen - tested on PC with mousepad and emulated gamepad
1510 	if(current_layout == LAYOUT_HYBRID_TOP_ONLY || (current_layout == LAYOUT_HYBRID_BOTTOM_ONLY))
1511 	{
1512 		if( (current_layout == LAYOUT_HYBRID_BOTTOM_ONLY) && hybrid_layout_scale == 1 && ( !hybrid_cursor_always_smallscreen || !hybrid_layout_showbothscreens))
1513 			NDS_setTouchPos(TouchX, TouchY, scale);
1514 		else
1515 			NDS_setTouchPos(TouchX*3/hybrid_layout_scale, TouchY*3/hybrid_layout_scale, scale);
1516 	}
1517 	else
1518 		NDS_setTouchPos(TouchX, TouchY, scale);
1519    }
1520    else
1521       NDS_releaseTouch();
1522 
1523 
1524    // BUTTONS
1525    //NDS_beginProcessingInput();
1526 
1527    NDS_setPad(
1528          input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT),
1529          input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT),
1530          input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN),
1531          input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP),
1532          input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT),
1533          input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START),
1534          input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B),
1535          input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A),
1536          input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y),
1537          input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X),
1538          input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L),
1539          input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R),
1540          0, // debug
1541          input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2) //Lid
1542          );
1543 
1544    if (!microphone_force_enable)
1545    {
1546       if(input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3))
1547          NDS_setMic(true);
1548       else if(!input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3))
1549          NDS_setMic(false);
1550    }
1551    else
1552       NDS_setMic(true);
1553 
1554 
1555    if(input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3) && quick_switch_enable && delay_timer == 0)
1556    {
1557       switch (current_layout)
1558       {
1559          case LAYOUT_TOP_ONLY:
1560             current_layout = LAYOUT_BOTTOM_ONLY;
1561             break;
1562          case LAYOUT_BOTTOM_ONLY:
1563             current_layout = LAYOUT_TOP_ONLY;
1564             break;
1565 		case LAYOUT_HYBRID_TOP_ONLY:
1566 			current_layout = LAYOUT_HYBRID_BOTTOM_ONLY;
1567 			{
1568 				//Need to swap around DST variables
1569 				uint16_t*swap = layout.dst;
1570 				layout.dst = layout.dst2;
1571 				layout.dst2 = swap;
1572 				//Need to reset Touch position to 0 with these conditions or it causes problems with mouse
1573 				if(hybrid_layout_scale == 1 && (!hybrid_layout_showbothscreens || !hybrid_cursor_always_smallscreen))
1574 				{
1575 					TouchX = 0;
1576 					TouchY = 0;
1577 				}
1578 			}
1579 			break;
1580 		case LAYOUT_HYBRID_BOTTOM_ONLY:
1581 			current_layout = LAYOUT_HYBRID_TOP_ONLY;
1582 			{
1583 				uint16_t*swap = layout.dst;
1584 				layout.dst = layout.dst2;
1585 				layout.dst2 = swap;
1586 				//Need to reset Touch position to 0 with these conditions are it causes problems with mouse
1587 				if(hybrid_layout_scale == 1 && (!hybrid_layout_showbothscreens || !hybrid_cursor_always_smallscreen))
1588 				{
1589 					TouchX = 0;
1590 					TouchY = 0;
1591 				}
1592 
1593 			}
1594 			break;
1595       }
1596       delay_timer++;
1597    }
1598 
1599    if(delay_timer != 0)
1600    {
1601       delay_timer++;
1602       if(delay_timer == 30)
1603          delay_timer = 0;
1604    }
1605 
1606    NDS_endProcessingInput();
1607 
1608    // RUN
1609    frameIndex ++;
1610    bool skipped = frameIndex <= frameSkip;
1611 
1612    if (skipped)
1613       NDS_SkipNextFrame();
1614 
1615    NDS_exec();
1616    SPU_Emulate_user();
1617 
1618    if (!skipped)
1619    {
1620 	  if (current_layout == LAYOUT_HYBRID_TOP_ONLY || current_layout == LAYOUT_HYBRID_BOTTOM_ONLY)
1621 	  {
1622 		u16 *screen = GPU->GetCustomFramebuffer();
1623 		if (current_layout == LAYOUT_HYBRID_TOP_ONLY)
1624 		{
1625 			if(hybrid_layout_scale == 3)
1626 				SwapScreenLarge(layout.dst,  screen, layout.pitch);
1627 			else
1628 				SwapScreen (layout.dst,  screen, layout.pitch);
1629 			BlankScreenSmallSection(layout.dst, layout.dst2);
1630 			SwapScreenSmall(layout.dst2, screen, layout.pitch, true, hybrid_layout_showbothscreens);
1631 		}
1632 		else if (current_layout == LAYOUT_HYBRID_BOTTOM_ONLY)
1633 			SwapScreenSmall(layout.dst, screen, layout.pitch, true, true);
1634 
1635 		screen = GPU->GetCustomFramebuffer() + (GPU_LR_FRAMEBUFFER_NATIVE_WIDTH * GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT);
1636 		if (current_layout == LAYOUT_HYBRID_BOTTOM_ONLY)
1637 		{
1638 			if(hybrid_layout_scale == 3)
1639 				SwapScreenLarge(layout.dst2,  screen, layout.pitch);
1640 			else
1641 				SwapScreen (layout.dst2,  screen, layout.pitch);
1642 			BlankScreenSmallSection(layout.dst2, layout.dst);
1643 			SwapScreenSmall (layout.dst, screen, layout.pitch, false , hybrid_layout_showbothscreens);
1644 			//Keep the Touch Cursor on the Small Screen, even if the bottom is the primary screen? Make this configurable by user? (Needs work to get working with hybrid_layout_scale==3 and layout_hybrid_bottom_only)
1645 			if(hybrid_cursor_always_smallscreen && hybrid_layout_showbothscreens)
1646 				DrawPointerHybrid (layout.dst, layout.pitch, false);
1647 			else
1648 				DrawPointerHybrid (layout.dst2, layout.pitch, true);
1649 		}
1650 		else
1651 		{
1652 			SwapScreenSmall (layout.dst2, screen, layout.pitch, false, true);
1653 			DrawPointerHybrid (layout.dst2, layout.pitch, false);
1654 		}
1655 	  }
1656 	  //This is for every layout except Hybrid - same as before
1657 	  else
1658 	  {
1659 		u16 *screen = GPU->GetCustomFramebuffer();
1660 		if (layout.draw_screen1)
1661 			SwapScreen (layout.dst,  screen, layout.pitch);
1662 		if (layout.draw_screen2)
1663 		{
1664 			screen = GPU->GetCustomFramebuffer() + GPU_LR_FRAMEBUFFER_NATIVE_WIDTH * GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT;
1665 			SwapScreen (layout.dst2, screen, layout.pitch);
1666 			DrawPointer(layout.dst2, layout.pitch);
1667 		}
1668 
1669 		BlankScreenGap(layout.dst, layout.dst2, layout.pitch);
1670 	  }
1671    }
1672    video_cb(skipped ? 0 : screen_buf, layout.width, layout.height, layout.pitch * 2);
1673    frameIndex = skipped ? frameIndex : 0;
1674 }
1675 
retro_serialize_size(void)1676 size_t retro_serialize_size (void)
1677 {
1678     // HACK: Usually around 10 MB but can vary frame to frame!
1679     return 1024 * 1024 * 12;
1680 }
1681 
retro_serialize(void * data,size_t size)1682 bool retro_serialize(void *data, size_t size)
1683 {
1684     EMUFILE_MEMORY state;
1685     savestate_save(&state);
1686 
1687     if(state.size() <= size)
1688     {
1689         memcpy(data, state.buf(), state.size());
1690         return true;
1691     }
1692 
1693     return false;
1694 }
1695 
retro_unserialize(const void * data,size_t size)1696 bool retro_unserialize(const void * data, size_t size)
1697 {
1698     EMUFILE_MEMORY state(const_cast<void*>(data), size);
1699     return savestate_load(&state);
1700 }
1701 
retro_load_game(const struct retro_game_info * game)1702 bool retro_load_game(const struct retro_game_info *game)
1703 {
1704    if (!game || colorMode != RETRO_PIXEL_FORMAT_RGB565)
1705       return false;
1706 
1707    struct retro_input_descriptor desc[] = {
1708       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,   "Left" },
1709       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,     "Up" },
1710       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,   "Down" },
1711       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT,  "Right" },
1712       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,      "X" },
1713       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,      "Y" },
1714       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,      "B" },
1715       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,      "A" },
1716       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,      "L" },
1717       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2,     "Lid Close/Open" },
1718       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3,     "Toggle Microphone" },
1719       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,      "R" },
1720       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2,     "Tap Stylus" },
1721       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3,     "Quick Screen Switch" },
1722       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,  "Start" },
1723       { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,  "Select" },
1724 
1725       { 0 },
1726    };
1727 
1728    environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc);
1729 
1730    execute = NDS_LoadROM(game->path);
1731 
1732    if (execute == -1)
1733       return false;
1734 
1735    screen_buf = (uint16_t*)malloc(hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_WIDTH * (hybrid_layout_scale*GPU_LR_FRAMEBUFFER_NATIVE_HEIGHT + NDS_MAX_SCREEN_GAP) * 2 * sizeof(uint16_t));
1736 
1737    return true;
1738 }
1739 
retro_load_game_special(unsigned game_type,const struct retro_game_info * info,size_t num_info)1740 bool retro_load_game_special(unsigned game_type, const struct retro_game_info *info, size_t num_info)
1741 {
1742 #if 0
1743     if(game_type == RETRO_GAME_TYPE_SUPER_GAME_BOY && num_info == 2)
1744     {
1745         strncpy(GBAgameName, info[1].path, sizeof(GBAgameName));
1746         addonsChangePak(NDS_ADDON_GBAGAME);
1747 
1748         return retro_load_game(&info[0]);
1749     }
1750 #endif
1751     return false;
1752 }
1753 
retro_unload_game(void)1754 void retro_unload_game (void)
1755 {
1756     NDS_FreeROM();
1757     if (screen_buf)
1758        free(screen_buf);
1759     screen_buf = NULL;
1760     execute    = 0;
1761 }
1762 
retro_get_memory_data(unsigned type)1763 void *retro_get_memory_data(unsigned type)
1764 {
1765    if (type == RETRO_MEMORY_SYSTEM_RAM)
1766       return MMU.MAIN_MEM;
1767    else
1768       return NULL;
1769 }
1770 
retro_get_memory_size(unsigned type)1771 size_t retro_get_memory_size(unsigned type)
1772 {
1773    if (type == RETRO_MEMORY_SYSTEM_RAM)
1774       return CommonSettings.ConsoleType == NDS_CONSOLE_TYPE_DSI ?
1775          0x1000000 : 0x0400000;
1776    else
1777       return 0;
1778 }
1779 
1780 // Stubs
retro_set_controller_port_device(unsigned in_port,unsigned device)1781 void retro_set_controller_port_device(unsigned in_port, unsigned device) { }
retro_api_version(void)1782 unsigned retro_api_version(void) { return RETRO_API_VERSION; }
1783 
1784 extern CHEATS *cheats;
1785 
retro_cheat_reset(void)1786 void retro_cheat_reset(void)
1787 {
1788    if (cheats)
1789       cheats->clear();
1790 }
1791 
retro_cheat_set(unsigned index,bool enabled,const char * code)1792 void retro_cheat_set(unsigned index, bool enabled, const char *code)
1793 {
1794    char ds_code[1024];
1795    char desc[1024];
1796    strcpy(ds_code, code);
1797    strcpy(desc, "N/A");
1798 
1799    if (!cheats)
1800       return;
1801 
1802    if (cheats->add_AR(ds_code, desc, 1) != TRUE)
1803    {
1804       /* Couldn't add Action Replay code */
1805    }
1806 }
1807 
retro_get_region(void)1808 unsigned retro_get_region (void) { return RETRO_REGION_NTSC; }
1809 
1810 #if defined(PSP)
ftruncate(int fd,off_t length)1811 int ftruncate(int fd, off_t length)
1812 {
1813    int ret;
1814    SceOff oldpos;
1815    if (!__PSP_IS_FD_VALID(fd)) {
1816       errno = EBADF;
1817       return -1;
1818    }
1819 
1820    switch(__psp_descriptormap[fd]->type)
1821    {
1822       case __PSP_DESCRIPTOR_TYPE_FILE:
1823          if (__psp_descriptormap[fd]->filename != NULL) {
1824             if (!(__psp_descriptormap[fd]->flags & (O_WRONLY | O_RDWR)))
1825                break;
1826             return truncate(__psp_descriptormap[fd]->filename, length);
1827             /* ANSI sez ftruncate doesn't move the file pointer */
1828          }
1829          break;
1830       case __PSP_DESCRIPTOR_TYPE_TTY:
1831       case __PSP_DESCRIPTOR_TYPE_PIPE:
1832       case __PSP_DESCRIPTOR_TYPE_SOCKET:
1833       default:
1834          break;
1835    }
1836 
1837    errno = EINVAL;
1838    return -1;
1839 }
1840 #endif
1841