OSDN Git Service

e9180c4313ad9fa1ac60dcc1a0f730e061fac6d2
[csp-qt/common_source_project-fm7.git] / source / src / qt / common / emu_thread.cpp
1 /*
2         Skelton for retropc emulator
3         Author : Takeda.Toshiya
4     Port to Qt : K.Ohta <whatisthis.sowhat _at_ gmail.com>
5         Date   : 2015.11.10
6         History: 2015.11.10 Split from qt_main.cpp
7
8         [ win32 main ] -> [ Qt main ] -> [Emu Thread]
9 */
10
11 #include <QString>
12 #include <QTextCodec>
13 #include <QWaitCondition>
14
15 #include <SDL.h>
16
17 #include "emu_thread.h"
18
19 #include "qt_gldraw.h"
20 #include "agar_logger.h"
21
22 // buttons
23 #ifdef MAX_BUTTONS
24 #define MAX_FONT_SIZE 32
25 #endif
26 #define MAX_SKIP_FRAMES 10
27
28 EmuThreadClass::EmuThreadClass(META_MainWindow *rootWindow, EMU *pp_emu, QObject *parent) : QThread(parent) {
29         MainWindow = rootWindow;
30         p_emu = pp_emu;
31         bRunThread = true;
32         prev_skip = false;
33         update_fps_time = SDL_GetTicks();
34         next_time = update_fps_time;
35         total_frames = 0;
36         draw_frames = 0;
37         skip_frames = 0;
38         calc_message = true;
39         mouse_flag = false;
40         //p_emu->set_parent_handler(this);
41         drawCond = new QWaitCondition();
42 #if defined(USE_TAPE) && !defined(TAPE_BINARY_ONLY)
43         tape_play_flag = false;
44         tape_rec_flag = false;
45         tape_pos = 0;
46 #endif  
47 };
48
49 EmuThreadClass::~EmuThreadClass() {
50         delete drawCond;
51 };
52
53
54 int EmuThreadClass::get_interval(void)
55 {
56         static int accum = 0;
57         accum += p_emu->frame_interval();
58         int interval = accum >> 10;
59         accum -= interval << 10;
60         return interval;
61 }
62
63 void EmuThreadClass::doExit(void)
64 {
65         int status;
66         bRunThread = false;
67 }
68
69 void EmuThreadClass::moved_mouse(int x, int y)
70 {
71         p_emu->set_mouse_pointer(x, y);
72 }
73
74 void EmuThreadClass::button_pressed_mouse(Qt::MouseButton button)
75 {
76         int stat = p_emu->get_mouse_button();
77         bool flag = p_emu->get_mouse_enabled();
78         switch(button) {
79         case Qt::LeftButton:
80                 stat |= 0x01;
81                 break;
82         case Qt::RightButton:
83                 stat |= 0x02;
84                 break;
85         case Qt::MiddleButton:
86                 flag = !flag;
87                 emit sig_mouse_enable(flag);
88                 break;
89         }
90         p_emu->set_mouse_button(stat);
91 }
92
93 void EmuThreadClass::button_released_mouse(Qt::MouseButton button)
94 {
95         int stat = p_emu->get_mouse_button();
96         switch(button) {
97         case Qt::LeftButton:
98                 stat &= 0x7ffffffe;
99                 break;
100         case Qt::RightButton:
101                 stat &= 0x7ffffffd;
102                 break;
103         case Qt::MiddleButton:
104           //emit sig_mouse_enable(false);
105                 break;
106         }
107         p_emu->set_mouse_button(stat);
108 }
109
110
111 void EmuThreadClass::set_tape_play(bool flag)
112 {
113 #ifdef USE_TAPE_BUTTON
114         tape_play_flag = flag;
115 #endif
116 }
117
118 EmuThreadClass *EmuThreadClass::currentHandler()
119 {
120         return this;
121 }
122
123 void EmuThreadClass::resize_screen(int screen_width, int screen_height, int stretched_width, int stretched_height)
124 {
125         //emit sig_resize_uibar(stretched_width, stretched_height);
126         emit sig_resize_screen(screen_width, screen_height);
127 }
128
129 void EmuThreadClass::do_start_auto_key(QString ctext)
130 {
131 #ifdef USE_AUTO_KEY
132         QTextCodec *codec = QTextCodec::codecForName("Shift-Jis");
133         QByteArray array;
134         clipBoardText = ctext;
135         if(clipBoardText.size() > 0) {
136                 array = codec->fromUnicode(clipBoardText.toUtf8());
137                 //p_emu->set_auto_key_string((const char *)array.constData());
138                 emit sig_auto_key_string(array);
139                 //AGAR_DebugLog(AGAR_LOG_DEBUG, "AutoKey: SET :%s\n", clipBoardText.toUtf8().constData());
140                 p_emu->start_auto_key();
141         }
142         //clipBoardText.clear();
143 #endif  
144 }
145
146 void EmuThreadClass::do_stop_auto_key(void)
147 {
148 #ifdef USE_AUTO_KEY
149         AGAR_DebugLog(AGAR_LOG_DEBUG, "AutoKey: stop\n");
150         p_emu->stop_auto_key();
151 #endif  
152 }
153
154 #if defined(USE_FD1) || defined(USE_FD2) || defined(USE_FD3) || defined(USE_FD4) || \
155     defined(USE_FD5) || defined(USE_FD6) || defined(USE_FD7) || defined(USE_FD8)
156 void EmuThreadClass::do_write_protect_disk(int drv, bool flag)
157 {
158         p_emu->set_disk_protected(drv, flag);
159 }
160
161 void EmuThreadClass::do_close_disk(int drv)
162 {
163         p_emu->close_disk(drv);
164         p_emu->d88_file[drv].bank_num = 0;
165         p_emu->d88_file[drv].cur_bank = -1;
166 }
167
168 void EmuThreadClass::do_open_disk(int drv, QString path, int bank)
169 {
170    
171         QByteArray localPath = path.toLocal8Bit();
172    
173         p_emu->d88_file[drv].bank_num = 0;
174         p_emu->d88_file[drv].cur_bank = -1;
175         
176         if(check_file_extension(localPath.constData(), ".d88") || check_file_extension(localPath.constData(), ".d77")) {
177                 
178                 FILEIO *fio = new FILEIO();
179                 if(fio->Fopen(localPath.constData(), FILEIO_READ_BINARY)) {
180                         try {
181                                 fio->Fseek(0, FILEIO_SEEK_END);
182                                 int file_size = fio->Ftell(), file_offset = 0;
183                                 while(file_offset + 0x2b0 <= file_size && p_emu->d88_file[drv].bank_num < MAX_D88_BANKS) {
184                                         fio->Fseek(file_offset, FILEIO_SEEK_SET);
185                                         char tmp[18];
186                                         memset(tmp, 0x00, sizeof(tmp));
187                                         fio->Fread(tmp, 17, 1);
188                                         memset(p_emu->d88_file[drv].disk_name[p_emu->d88_file[drv].bank_num], 0x00, 128);
189                                         if(strlen(tmp) > 0) Convert_CP932_to_UTF8(p_emu->d88_file[drv].disk_name[p_emu->d88_file[drv].bank_num], tmp, 127, 17);
190                                         
191                                         fio->Fseek(file_offset + 0x1c, FILEIO_SEEK_SET);
192                                         file_offset += fio->FgetUint32_LE();
193                                         p_emu->d88_file[drv].bank_num++;
194                                 }
195                                 strcpy(p_emu->d88_file[drv].path, path.toUtf8().constData());
196                                 if(bank >= p_emu->d88_file[drv].bank_num) bank = p_emu->d88_file[drv].bank_num - 1;
197                                 if(bank < 0) bank = 0;
198                                 p_emu->d88_file[drv].cur_bank = bank;
199                         }
200                         catch(...) {
201                                 bank = 0;
202                                 p_emu->d88_file[drv].bank_num = 0;
203                         }
204                         fio->Fclose();
205                 }
206                 delete fio;
207         } else {
208            bank = 0;
209         }
210         p_emu->open_disk(drv, localPath.constData(), bank);
211         emit sig_update_recent_disk(drv);
212 }
213
214 #endif
215
216 #ifdef USE_TAPE
217 void EmuThreadClass::do_play_tape(QString name)
218 {
219         p_emu->play_tape(name.toLocal8Bit().constData());
220 }
221
222 void EmuThreadClass::do_rec_tape(QString name)
223 {
224         p_emu->rec_tape(name.toLocal8Bit().constData());
225 }
226
227 void EmuThreadClass::do_close_tape(void)
228 {
229         p_emu->close_tape();
230 }
231
232 # ifdef USE_TAPE_BUTTON
233 void EmuThreadClass::do_cmt_push_play(void)
234 {
235         p_emu->push_play();
236 }
237
238 void EmuThreadClass::do_cmt_push_stop(void)
239 {
240         p_emu->push_stop();
241 }
242
243 void EmuThreadClass::do_cmt_push_fast_forward(void)
244 {
245         p_emu->push_fast_forward();
246 }
247
248 void EmuThreadClass::do_cmt_push_fast_rewind(void)
249 {
250         p_emu->push_fast_rewind();
251 }
252
253 void EmuThreadClass::do_cmt_push_apss_forward(void)
254 {
255         p_emu->push_apss_forward();
256 }
257
258 void EmuThreadClass::do_cmt_push_apss_rewind(void)
259 {
260         p_emu->push_apss_rewind();
261 }
262
263 # endif
264 #endif
265
266 #ifdef USE_QD1
267 void EmuThreadClass::do_write_protect_quickdisk(int drv, bool flag)
268 {
269         //p_emu->write_protect_Qd(drv, flag);
270 }
271
272 void EmuThreadClass::do_close_quickdisk(int drv)
273 {
274         p_emu->close_quickdisk(drv);
275 }
276
277 void EmuThreadClass::do_open_quickdisk(int drv, QString path)
278 {
279         p_emu->open_quickdisk(drv, path.toLocal8Bit().constData());
280 }
281 #endif
282
283 #ifdef USE_CART1
284 void EmuThreadClass::do_close_cart(int drv)
285 {
286         p_emu->close_cart(drv);
287 }
288
289 void EmuThreadClass::do_open_cart(int drv, QString path)
290 {
291         p_emu->open_cart(drv, path.toLocal8Bit().constData());
292 }
293 #endif
294
295 #ifdef USE_LASER_DISK
296 void EmuThreadClass::do_close_laser_disk(void)
297 {
298         p_emu->close_laser_disk();
299 }
300
301 void EmuThreadClass::do_open_laser_disk(QString path)
302 {
303         p_emu->open_laser_disk(path.toLocal8Bit().constData());
304 }
305 #endif
306 #ifdef USE_BINARY_FILE1
307 void EmuThreadClass::do_load_binary(int drv, QString path)
308 {
309         p_emu->load_binary(drv, path.toLocal8Bit().constData());
310 }
311
312 void EmuThreadClass::do_save_binary(int drv, QString path)
313 {
314         p_emu->save_binary(drv, path.toLocal8Bit().constData());
315 }
316 #endif
317
318 void EmuThreadClass::print_framerate(int frames)
319 {
320         if(frames >= 0) draw_frames += frames;
321         if(calc_message) {
322                 uint32_t current_time = SDL_GetTicks();
323                         if(update_fps_time <= current_time && update_fps_time != 0) {
324                                 _TCHAR buf[256];
325                                 QString message;
326                                 int ratio = (int)(100.0 * (double)draw_frames / (double)total_frames + 0.5);
327
328 #ifdef USE_POWER_OFF
329                                 if(MainWindow->GetPowerState() == false){        
330                                         snprintf(buf, 255, _T("*Power OFF*"));
331                                 } else {
332 #endif // USE_POWER_OFF         
333                                         if(p_emu->message_count > 0) {
334                                                 snprintf(buf, 255, _T("%s - %s"), DEVICE_NAME, p_emu->message);
335                                                 p_emu->message_count--;
336                                         } else {
337                                                 snprintf(buf, 255, _T("%s - %d fps (%d %%)"), DEVICE_NAME, draw_frames, ratio);
338                                         }
339 #ifdef USE_POWER_OFF
340                                 } 
341 #endif // USE_POWER_OFF  
342               
343                                 message = buf;
344                                 emit message_changed(message);
345                                 update_fps_time += 1000;
346                                 total_frames = draw_frames = 0;
347                                 
348                         }
349                         if(update_fps_time <= current_time) {
350                                 update_fps_time = current_time + 1000;
351                         }
352                         calc_message = false;  
353                 } else {
354                         calc_message = true;
355                 }
356 }
357
358 void EmuThreadClass::do_draw_timing(bool f)
359 {
360         draw_timing = f;
361 }
362
363 void EmuThreadClass::sample_access_drv(void)
364 {
365         uint32 access_drv;
366         QString alamp;
367         QString tmpstr;
368         QString iname;
369         int i;
370 #if defined(USE_QD1)
371 # if defined(USE_ACCESS_LAMP)      
372         access_drv = p_emu->get_vm()->access_lamp();
373 # endif
374         for(i = 0; i < MAX_QD ; i++) {
375                 if(p_emu->quickdisk_inserted(i)) {
376                 //           printf("%d\n", access_drv);
377 # if defined(USE_ACCESS_LAMP)      
378                         if(i == (access_drv - 1)) {
379                                 alamp = QString::fromUtf8("● ");
380                         } else {
381                                 alamp = QString::fromUtf8("○ ");
382                         }
383                         tmpstr = QString::fromUtf8("QD");
384                         tmpstr = alamp + tmpstr + QString::number(i) + QString::fromUtf8(":");
385 # else
386                         tmpstr = QString::fromUtf8("QD");
387                         tmpstr = tmpstr + QString::number(i) + QString::fromUtf8(":");
388 # endif
389                         iname = QString::fromUtf8("*Inserted*");
390                         tmpstr = tmpstr + iname;
391                 } else {
392                         tmpstr = QString::fromUtf8("× QD") + QString::number(i) + QString::fromUtf8(":");
393                         tmpstr = tmpstr + QString::fromUtf8(" ");
394                 }
395                 if(tmpstr != qd_text[i]) {
396                         emit sig_change_osd_qd(i, tmpstr);
397                         qd_text[i] = tmpstr;
398                 }
399         }
400 #endif
401
402 #if defined(USE_FD1)
403 # if defined(USE_ACCESS_LAMP)      
404         access_drv = p_emu->get_vm()->access_lamp();
405 # endif
406         for(i = 0; i < MAX_FD; i++) {
407                 if(p_emu->disk_inserted(i)) {
408 # if defined(USE_ACCESS_LAMP)      
409                         if(i == (access_drv - 1)) {
410                                 alamp = QString::fromUtf8("<FONT COLOR=RED>●</FONT> ");
411                         } else {
412                                 alamp = QString::fromUtf8("○ ");
413                         }
414                         tmpstr = QString::fromUtf8("FD");
415                         tmpstr = alamp + tmpstr + QString::number(i) + QString::fromUtf8(":");
416 # else
417                         tmpstr = QString::fromUtf8("FD");
418                         tmpstr = tmpstr + QString::number(i) + QString::fromUtf8(":");
419 # endif
420                         if(emu->d88_file[i].bank_num > 0) {
421                                 iname = QString::fromUtf8(emu->d88_file[i].disk_name[emu->d88_file[i].cur_bank]);
422                         } else {
423                                 iname = QString::fromUtf8("*Inserted*");
424                         }
425                         tmpstr = tmpstr + iname;
426                 } else {
427                         tmpstr = QString::fromUtf8("× FD") + QString::number(i) + QString::fromUtf8(":");
428                         tmpstr = tmpstr + QString::fromUtf8(" ");
429                 }
430
431                 if(tmpstr != fd_text[i]) {
432                         emit sig_change_osd_fd(i, tmpstr);
433                         fd_text[i] = tmpstr;
434                 }
435         }
436 #endif
437 #if defined(USE_TAPE) && !defined(TAPE_BINARY_ONLY)
438         if(p_emu->tape_inserted()) {
439                 int tape_counter = p_emu->tape_position();
440                 tmpstr = QString::fromUtf8("");
441                 if(p_emu->tape_playing()) {
442                         tmpstr = QString::fromUtf8("<FONT COLOR=BLUE>▶ </FONT>");
443                 } else if(p_emu->tape_recording()) {
444                         tmpstr = QString::fromUtf8("<FONT COLOR=RED>● </FONT>");
445                 } else {
446                         tmpstr = QString::fromUtf8("<FONT COLOR=BLACK>■ </FONT>");
447                 }
448                 if(tape_counter >= 100) {
449                         tmpstr = tmpstr + QString::fromUtf8("BOTTOM");
450                 } else if(tape_counter >= 0) {
451                         tmpstr = tmpstr + QString::number(tape_counter) + QString::fromUtf8("%");
452                 } else {
453                         tmpstr = tmpstr + QString::fromUtf8("TOP");
454                 }
455         } else {
456                 tmpstr = QString::fromUtf8("EMPTY");
457         }
458         if(tmpstr != cmt_text) {
459                 emit sig_change_osd_cmt(tmpstr);
460                 cmt_text = tmpstr;
461         }
462 #endif
463
464 }
465
466 void EmuThreadClass::doWork(const QString &params)
467 {
468         int interval = 0, sleep_period = 0;
469         int run_frames;
470         bool now_skip;
471         uint32 current_time;
472         bool first = true;
473 #ifdef SUPPORT_DUMMY_DEVICE_LED
474         uint32 led_data = 0x00000000;
475         uint32 led_data_old = 0x00000000;
476 #endif
477 #if defined(USE_TAPE) && !defined(TAPE_BINARY_ONLY)
478         bool tape_flag;
479         int tpos;
480 #endif
481 #ifdef USE_DIG_RESOLUTION
482         int width, height;
483 #endif
484         QString ctext;
485         bool req_draw = true;
486         bool vert_line_bak = config.opengl_scanline_vert;
487         bool horiz_line_bak = config.opengl_scanline_horiz;
488         bool gl_crt_filter_bak = config.use_opengl_filters;
489         int opengl_filter_num_bak = config.opengl_filter_num;
490         int no_draw_count = 0;
491         
492         ctext.clear();
493         draw_timing = false;
494         bResetReq = false;
495         bSpecialResetReq = false;
496         bLoadStateReq = false;
497         bSaveStateReq = false;
498         bUpdateConfigReq = false;
499         bStartRecordSoundReq = false;
500         bStopRecordSoundReq = false;
501         
502         next_time = 0;
503         mouse_flag = false;
504         //(this->idealThreadCount());
505         
506 #if defined(USE_QD1)
507         for(int i = 0; i < 2; i++) qd_text[i].clear();
508 #endif
509 #if defined(USE_QD1)
510         for(int i = 0; i < MAX_FD; i++) fd_text[i].clear();
511 #endif
512 #if defined(USE_TAPE)
513         cmt_text.clear();
514 #endif
515         do {
516                 //p_emu->SetHostCpus(this->idealThreadCount());
517                 if(MainWindow == NULL) {
518                         if(bRunThread == false){
519                                 goto _exit;
520                         }
521                         msleep(10);
522                         continue;
523                 }
524                 if(first) {
525 #ifdef SUPPORT_DUMMY_DEVICE_LED
526                         emit sig_send_data_led((quint32)led_data);
527 #endif
528                         first = false;
529                 }
530                 interval = 0;
531                 sleep_period = 0;
532                 if(p_emu) {
533                         // drive machine
534 #ifdef USE_STATE
535                         if(bLoadStateReq != false) {
536                                 p_emu->load_state();
537                                 bLoadStateReq = false;
538                                 req_draw = true;
539                         }
540 #endif                  
541                         if(bResetReq != false) {
542                                 p_emu->reset();
543                                 bResetReq = false;
544                                 req_draw = true;
545                         }
546 #ifdef USE_SPECIAL_RESET
547                         if(bSpecialResetReq != false) {
548                                 p_emu->special_reset();
549                                 bSpecialResetReq = false;
550                         }
551 #endif
552 #ifdef USE_STATE
553                         if(bSaveStateReq != false) {
554                                 p_emu->save_state();
555                                 bSaveStateReq = false;
556                         }
557 #endif
558 #if defined(USE_MINIMUM_RENDERING)
559                         if((vert_line_bak != config.opengl_scanline_vert) ||
560                            (horiz_line_bak != config.opengl_scanline_horiz) ||
561                            (gl_crt_filter_bak != config.use_opengl_filters) ||
562                            (opengl_filter_num_bak != config.opengl_filter_num)) req_draw = true;
563                         vert_line_bak = config.opengl_scanline_vert;
564                         horiz_line_bak = config.opengl_scanline_horiz;
565                         gl_crt_filter_bak = config.use_opengl_filters;
566                         opengl_filter_num_bak = config.opengl_filter_num;
567 #endif
568                         if(bStartRecordSoundReq != false) {
569                                 p_emu->start_rec_sound();
570                                 bStartRecordSoundReq = false;
571                                 req_draw = true;
572                         }
573                         if(bStopRecordSoundReq != false) {
574                                 p_emu->stop_rec_sound();
575                                 bStopRecordSoundReq = false;
576                                 req_draw = true;
577                         }
578                         if(bUpdateConfigReq != false) {
579                                 p_emu->update_config();
580                                 bUpdateConfigReq = false;
581                                 req_draw = true;
582                         }
583                         run_frames = p_emu->run();
584                         total_frames += run_frames;
585 #if defined(USE_MINIMUM_RENDERING)
586                         req_draw |= p_emu->screen_changed();
587 #else
588                         req_draw = true;
589 #endif                  
590 #ifdef SUPPORT_DUMMY_DEVICE_LED
591                         led_data = p_emu->get_led_status();
592                         if(led_data != led_data_old) {
593                                 emit sig_send_data_led((quint32)led_data);
594                                 led_data_old = led_data;
595                         }
596 #endif
597                         sample_access_drv();
598
599                         interval += get_interval();
600                         now_skip = p_emu->now_skip() && !p_emu->now_rec_video();
601
602                         if((prev_skip && !now_skip) || next_time == 0) {
603                                 next_time = SDL_GetTicks();
604                         }
605                         if(!now_skip) {
606                                 next_time += interval;
607                         }
608                         prev_skip = now_skip;
609                         //printf("p_emu::RUN Frames = %d SKIP=%d Interval = %d NextTime = %d\n", run_frames, now_skip, interval, next_time);
610       
611                         if(next_time > SDL_GetTicks()) {
612                                 //  update window if enough time
613                                 draw_timing = false;
614                                 if(!req_draw) {
615                                         no_draw_count++;
616                                         if(no_draw_count > (int)(FRAMES_PER_SEC / 4)) {
617                                                 req_draw = true;
618                                                 no_draw_count = 0;
619                                         }
620                                 } else {
621                                         no_draw_count = 0;
622                                 }
623                                 emit sig_draw_thread(req_draw);
624                                 skip_frames = 0;
625                         
626                                 // sleep 1 frame priod if need
627                                 current_time = SDL_GetTicks();
628                                 if((int)(next_time - current_time) >= 10) {
629                                         sleep_period = next_time - current_time;
630                                 }
631                         } else if(++skip_frames > MAX_SKIP_FRAMES) {
632                                 // update window at least once per 10 frames
633                                 draw_timing = false;
634                                 emit sig_draw_thread(true);
635                                 no_draw_count = 0;
636                                 skip_frames = 0;
637                                 uint32_t tt = SDL_GetTicks();
638                                 next_time = tt + get_interval();
639                                 sleep_period = next_time - tt;
640                         }
641                 }
642                 req_draw = false;
643                 if(bRunThread == false){
644                         goto _exit;
645                 }
646                 if(sleep_period <= 0) sleep_period = 1;
647                 msleep(sleep_period);
648         } while(1);
649 _exit:
650         //emit quit_draw_thread();
651         AGAR_DebugLog(AGAR_LOG_DEBUG, "EmuThread : EXIT");
652         emit sig_finished();
653         this->quit();
654 }
655
656 void EmuThreadClass::doSetDisplaySize(int w, int h, int ww, int wh)
657 {
658         p_emu->suspend();
659         //p_emu->set_vm_screen_size(w, h, -1, -1, ww, wh);
660         p_emu->set_window_size(w, h, true);
661 }
662
663 void EmuThreadClass::doUpdateConfig()
664 {
665         bUpdateConfigReq = true;
666 }
667
668 void EmuThreadClass::doStartRecordSound()
669 {
670         bStartRecordSoundReq = true;
671 }
672
673 void EmuThreadClass::doStopRecordSound()
674 {
675         bStopRecordSoundReq = true;
676 }
677
678 void EmuThreadClass::doReset()
679 {
680         bResetReq = true;
681 }
682
683 void EmuThreadClass::doSpecialReset()
684 {
685         bSpecialResetReq = true;
686 }
687
688 void EmuThreadClass::doLoadState()
689 {
690         bLoadStateReq = true;
691 }
692
693 void EmuThreadClass::doSaveState()
694 {
695         bSaveStateReq = true;
696 }
697