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