2 Skelton for retropc emulator
3 Author : Takeda.Toshiya
4 Port to Qt : K.Ohta <whatisthis.sowhat _at_ gmail.com>
6 History: 2015.11.10 Split from qt_main.cpp
8 [ win32 main ] -> [ Qt main ] -> [Emu Thread]
13 #include <QWaitCondition>
17 #include "emu_thread.h"
19 #include "qt_gldraw.h"
20 #include "agar_logger.h"
24 #define MAX_FONT_SIZE 32
26 #define MAX_SKIP_FRAMES 10
28 EmuThreadClass::EmuThreadClass(META_MainWindow *rootWindow, EMU *pp_emu, QObject *parent) : QThread(parent) {
29 MainWindow = rootWindow;
33 update_fps_time = SDL_GetTicks();
34 next_time = update_fps_time;
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;
49 EmuThreadClass::~EmuThreadClass() {
54 int EmuThreadClass::get_interval(void)
57 accum += p_emu->frame_interval();
58 int interval = accum >> 10;
59 accum -= interval << 10;
63 void EmuThreadClass::doExit(void)
69 void EmuThreadClass::moved_mouse(int x, int y)
71 p_emu->set_mouse_pointer(x, y);
74 void EmuThreadClass::button_pressed_mouse(Qt::MouseButton button)
76 int stat = p_emu->get_mouse_button();
77 bool flag = p_emu->get_mouse_enabled();
85 case Qt::MiddleButton:
87 emit sig_mouse_enable(flag);
90 p_emu->set_mouse_button(stat);
93 void EmuThreadClass::button_released_mouse(Qt::MouseButton button)
95 int stat = p_emu->get_mouse_button();
100 case Qt::RightButton:
103 case Qt::MiddleButton:
104 //emit sig_mouse_enable(false);
107 p_emu->set_mouse_button(stat);
111 void EmuThreadClass::set_tape_play(bool flag)
113 #ifdef USE_TAPE_BUTTON
114 tape_play_flag = flag;
118 EmuThreadClass *EmuThreadClass::currentHandler()
123 void EmuThreadClass::resize_screen(int screen_width, int screen_height, int stretched_width, int stretched_height)
125 //emit sig_resize_uibar(stretched_width, stretched_height);
126 emit sig_resize_screen(screen_width, screen_height);
129 void EmuThreadClass::do_start_auto_key(QString ctext)
132 QTextCodec *codec = QTextCodec::codecForName("Shift-Jis");
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();
142 //clipBoardText.clear();
146 void EmuThreadClass::do_stop_auto_key(void)
149 AGAR_DebugLog(AGAR_LOG_DEBUG, "AutoKey: stop\n");
150 p_emu->stop_auto_key();
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)
158 p_emu->set_disk_protected(drv, flag);
161 void EmuThreadClass::do_close_disk(int drv)
163 p_emu->close_disk(drv);
164 p_emu->d88_file[drv].bank_num = 0;
165 p_emu->d88_file[drv].cur_bank = -1;
168 void EmuThreadClass::do_open_disk(int drv, QString path, int bank)
171 QByteArray localPath = path.toLocal8Bit();
173 p_emu->d88_file[drv].bank_num = 0;
174 p_emu->d88_file[drv].cur_bank = -1;
176 if(check_file_extension(localPath.constData(), ".d88") || check_file_extension(localPath.constData(), ".d77")) {
178 FILEIO *fio = new FILEIO();
179 if(fio->Fopen(localPath.constData(), FILEIO_READ_BINARY)) {
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);
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);
191 fio->Fseek(file_offset + 0x1c, FILEIO_SEEK_SET);
192 file_offset += fio->FgetUint32_LE();
193 p_emu->d88_file[drv].bank_num++;
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;
202 p_emu->d88_file[drv].bank_num = 0;
210 p_emu->open_disk(drv, localPath.constData(), bank);
211 emit sig_update_recent_disk(drv);
217 void EmuThreadClass::do_play_tape(QString name)
219 p_emu->play_tape(name.toLocal8Bit().constData());
222 void EmuThreadClass::do_rec_tape(QString name)
224 p_emu->rec_tape(name.toLocal8Bit().constData());
227 void EmuThreadClass::do_close_tape(void)
232 # ifdef USE_TAPE_BUTTON
233 void EmuThreadClass::do_cmt_push_play(void)
238 void EmuThreadClass::do_cmt_push_stop(void)
243 void EmuThreadClass::do_cmt_push_fast_forward(void)
245 p_emu->push_fast_forward();
248 void EmuThreadClass::do_cmt_push_fast_rewind(void)
250 p_emu->push_fast_rewind();
253 void EmuThreadClass::do_cmt_push_apss_forward(void)
255 p_emu->push_apss_forward();
258 void EmuThreadClass::do_cmt_push_apss_rewind(void)
260 p_emu->push_apss_rewind();
267 void EmuThreadClass::do_write_protect_quickdisk(int drv, bool flag)
269 //p_emu->write_protect_Qd(drv, flag);
272 void EmuThreadClass::do_close_quickdisk(int drv)
274 p_emu->close_quickdisk(drv);
277 void EmuThreadClass::do_open_quickdisk(int drv, QString path)
279 p_emu->open_quickdisk(drv, path.toLocal8Bit().constData());
284 void EmuThreadClass::do_close_cart(int drv)
286 p_emu->close_cart(drv);
289 void EmuThreadClass::do_open_cart(int drv, QString path)
291 p_emu->open_cart(drv, path.toLocal8Bit().constData());
295 #ifdef USE_LASER_DISK
296 void EmuThreadClass::do_close_laser_disk(void)
298 p_emu->close_laser_disk();
301 void EmuThreadClass::do_open_laser_disk(QString path)
303 p_emu->open_laser_disk(path.toLocal8Bit().constData());
306 #ifdef USE_BINARY_FILE1
307 void EmuThreadClass::do_load_binary(int drv, QString path)
309 p_emu->load_binary(drv, path.toLocal8Bit().constData());
312 void EmuThreadClass::do_save_binary(int drv, QString path)
314 p_emu->save_binary(drv, path.toLocal8Bit().constData());
318 void EmuThreadClass::print_framerate(int frames)
320 if(frames >= 0) draw_frames += frames;
322 uint32_t current_time = SDL_GetTicks();
323 if(update_fps_time <= current_time && update_fps_time != 0) {
326 int ratio = (int)(100.0 * (double)draw_frames / (double)total_frames + 0.5);
329 if(MainWindow->GetPowerState() == false){
330 snprintf(buf, 255, _T("*Power OFF*"));
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--;
337 snprintf(buf, 255, _T("%s - %d fps (%d %%)"), DEVICE_NAME, draw_frames, ratio);
341 #endif // USE_POWER_OFF
344 emit message_changed(message);
345 update_fps_time += 1000;
346 total_frames = draw_frames = 0;
349 if(update_fps_time <= current_time) {
350 update_fps_time = current_time + 1000;
352 calc_message = false;
358 void EmuThreadClass::do_draw_timing(bool f)
363 void EmuThreadClass::sample_access_drv(void)
371 # if defined(USE_ACCESS_LAMP)
372 access_drv = p_emu->get_vm()->access_lamp();
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("● ");
381 alamp = QString::fromUtf8("○ ");
383 tmpstr = QString::fromUtf8("QD");
384 tmpstr = alamp + tmpstr + QString::number(i) + QString::fromUtf8(":");
386 tmpstr = QString::fromUtf8("QD");
387 tmpstr = tmpstr + QString::number(i) + QString::fromUtf8(":");
389 iname = QString::fromUtf8("*Inserted*");
390 tmpstr = tmpstr + iname;
392 tmpstr = QString::fromUtf8("× QD") + QString::number(i) + QString::fromUtf8(":");
393 tmpstr = tmpstr + QString::fromUtf8(" ");
395 if(tmpstr != qd_text[i]) {
396 emit sig_change_osd_qd(i, tmpstr);
403 # if defined(USE_ACCESS_LAMP)
404 access_drv = p_emu->get_vm()->access_lamp();
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> ");
412 alamp = QString::fromUtf8("○ ");
414 tmpstr = QString::fromUtf8("FD");
415 tmpstr = alamp + tmpstr + QString::number(i) + QString::fromUtf8(":");
417 tmpstr = QString::fromUtf8("FD");
418 tmpstr = tmpstr + QString::number(i) + QString::fromUtf8(":");
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]);
423 iname = QString::fromUtf8("*Inserted*");
425 tmpstr = tmpstr + iname;
427 tmpstr = QString::fromUtf8("× FD") + QString::number(i) + QString::fromUtf8(":");
428 tmpstr = tmpstr + QString::fromUtf8(" ");
431 if(tmpstr != fd_text[i]) {
432 emit sig_change_osd_fd(i, tmpstr);
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>");
446 tmpstr = QString::fromUtf8("<FONT COLOR=BLACK>■ </FONT>");
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("%");
453 tmpstr = tmpstr + QString::fromUtf8("TOP");
456 tmpstr = QString::fromUtf8("EMPTY");
458 if(tmpstr != cmt_text) {
459 emit sig_change_osd_cmt(tmpstr);
466 void EmuThreadClass::doWork(const QString ¶ms)
468 int interval = 0, sleep_period = 0;
473 #ifdef SUPPORT_DUMMY_DEVICE_LED
474 uint32 led_data = 0x00000000;
475 uint32 led_data_old = 0x00000000;
477 #if defined(USE_TAPE) && !defined(TAPE_BINARY_ONLY)
481 #ifdef USE_DIG_RESOLUTION
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 doing_debug_command = false;
496 bSpecialResetReq = false;
497 bLoadStateReq = false;
498 bSaveStateReq = false;
499 bUpdateConfigReq = false;
500 bStartRecordSoundReq = false;
501 bStopRecordSoundReq = false;
505 //(this->idealThreadCount());
508 for(int i = 0; i < 2; i++) qd_text[i].clear();
511 for(int i = 0; i < MAX_FD; i++) fd_text[i].clear();
513 #if defined(USE_TAPE)
517 //p_emu->SetHostCpus(this->idealThreadCount());
518 if(MainWindow == NULL) {
519 if(bRunThread == false){
526 #ifdef SUPPORT_DUMMY_DEVICE_LED
527 emit sig_send_data_led((quint32)led_data);
536 if(bLoadStateReq != false) {
538 bLoadStateReq = false;
542 if(bResetReq != false) {
547 #ifdef USE_SPECIAL_RESET
548 if(bSpecialResetReq != false) {
549 p_emu->special_reset();
550 bSpecialResetReq = false;
554 if(bSaveStateReq != false) {
556 bSaveStateReq = false;
559 #if defined(USE_MINIMUM_RENDERING)
560 if((vert_line_bak != config.opengl_scanline_vert) ||
561 (horiz_line_bak != config.opengl_scanline_horiz) ||
562 (gl_crt_filter_bak != config.use_opengl_filters) ||
563 (opengl_filter_num_bak != config.opengl_filter_num)) req_draw = true;
564 vert_line_bak = config.opengl_scanline_vert;
565 horiz_line_bak = config.opengl_scanline_horiz;
566 gl_crt_filter_bak = config.use_opengl_filters;
567 opengl_filter_num_bak = config.opengl_filter_num;
569 if(bStartRecordSoundReq != false) {
570 p_emu->start_rec_sound();
571 bStartRecordSoundReq = false;
574 if(bStopRecordSoundReq != false) {
575 p_emu->stop_rec_sound();
576 bStopRecordSoundReq = false;
579 if(bUpdateConfigReq != false) {
580 p_emu->update_config();
581 bUpdateConfigReq = false;
584 run_frames = p_emu->run();
585 total_frames += run_frames;
586 #if defined(USE_MINIMUM_RENDERING)
587 req_draw |= p_emu->screen_changed();
591 #ifdef SUPPORT_DUMMY_DEVICE_LED
592 led_data = p_emu->get_led_status();
593 if(led_data != led_data_old) {
594 emit sig_send_data_led((quint32)led_data);
595 led_data_old = led_data;
600 interval += get_interval();
601 now_skip = p_emu->now_skip() && !p_emu->now_rec_video();
603 if((prev_skip && !now_skip) || next_time == 0) {
604 next_time = SDL_GetTicks();
607 next_time += interval;
609 prev_skip = now_skip;
610 //printf("p_emu::RUN Frames = %d SKIP=%d Interval = %d NextTime = %d\n", run_frames, now_skip, interval, next_time);
612 if(next_time > SDL_GetTicks()) {
613 // update window if enough time
617 if(no_draw_count > (int)(FRAMES_PER_SEC / 4)) {
624 emit sig_draw_thread(req_draw);
627 // sleep 1 frame priod if need
628 current_time = SDL_GetTicks();
629 if((int)(next_time - current_time) >= 10) {
630 sleep_period = next_time - current_time;
632 } else if(++skip_frames > MAX_SKIP_FRAMES) {
633 // update window at least once per 10 frames
635 emit sig_draw_thread(true);
638 uint32_t tt = SDL_GetTicks();
639 next_time = tt + get_interval();
640 sleep_period = next_time - tt;
644 if(bRunThread == false){
647 if(sleep_period <= 0) sleep_period = 1;
648 msleep(sleep_period);
651 //emit quit_draw_thread();
652 AGAR_DebugLog(AGAR_LOG_DEBUG, "EmuThread : EXIT");
657 void EmuThreadClass::doSetDisplaySize(int w, int h, int ww, int wh)
660 //p_emu->set_vm_screen_size(w, h, -1, -1, ww, wh);
661 p_emu->set_window_size(w, h, true);
664 void EmuThreadClass::doUpdateConfig()
666 bUpdateConfigReq = true;
669 void EmuThreadClass::doStartRecordSound()
671 bStartRecordSoundReq = true;
674 void EmuThreadClass::doStopRecordSound()
676 bStopRecordSoundReq = true;
679 void EmuThreadClass::doReset()
684 void EmuThreadClass::doSpecialReset()
686 bSpecialResetReq = true;
689 void EmuThreadClass::doLoadState()
691 bLoadStateReq = true;
694 void EmuThreadClass::doSaveState()
696 bSaveStateReq = true;
699 #if defined(USE_DEBUGGER)
700 extern int debugger_command(debugger_thread_t *p, _TCHAR *command, _TCHAR *prev_command, bool cp932);
702 void EmuThreadClass::do_call_debugger_command(QString s)
705 #if defined(USE_DEBUGGER)
706 _TCHAR command[MAX_COMMAND_LEN + 1];
708 if(doing_debug_command) {
709 emit sig_debugger_input(s);
712 memset(command, 0x00, MAX_COMMAND_LEN + 1);
714 strncpy(command, dbg_prev_command, MAX_COMMAND_LEN);
716 strncpy(command, s.toUtf8().constData(), MAX_COMMAND_LEN);
718 doing_debug_command = true;
719 if(debugger_command(&(p_emu->debugger_thread_param), command, dbg_prev_command, false) < 0) {
722 doing_debug_command = false;
727 void EmuThreadClass::do_close_debugger(void)
730 #if defined(USE_DEBUGGER)
731 emit sig_quit_debugger();
736 bool EmuThreadClass::now_debugging() {
737 #if defined(USE_DEBUGGER)
738 return p_emu->now_debugging;