OSDN Git Service

[UI][Qt][OSD][LOG] CDROM: May works with new messaging framework.
[csp-qt/common_source_project-fm7.git] / source / src / qt / osd_wrapper.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : K.Ohta <whatisthis.sowhat _at_ gmail.com>
5         Date   : 2015.11.30-
6
7         [ VM/OSD Wrapper ]
8 */
9
10 #include <string>
11
12 #include <QObject>
13 #include <QWidget>
14
15 #include <chrono>
16 #include <QSemaphore>
17 #include <QPainter>
18 #include <QElapsedTimer>
19 #include <QQueue>
20
21 #include <QDateTime>
22 #include <QDate>
23 #include <QTime>
24 #include <QString>
25 #include <QObject>
26 #include <QThread>
27
28 #include <QOpenGLContext>
29
30 #include <QImage>
31 #include <QPainter>
32 #include <QColor>
33 #include <QPen>
34 #include <QPoint>
35 #include <QTextCodec>
36
37 #include "osd.h"
38 #include "../vm/vm.h"
39 #include "../vm/device.h"
40 #include "../common.h"
41
42 #include "emu.h"
43
44 #include "emu_thread.h"
45 #include "draw_thread.h"
46 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
47 #include "avio/movie_loader.h"
48 #endif
49 #include "qt_gldraw.h"
50 #include "csp_logger.h"
51
52 bool OSD::get_use_socket(void)
53 {
54 #ifdef USE_SOCKET
55         return true;
56 #else
57         return false;
58 #endif
59 }
60
61
62 bool OSD::get_use_auto_key(void)
63 {
64 #ifdef USE_AUTO_KEY
65         return true;
66 #else
67         return false;
68 #endif
69 }
70
71 bool OSD::get_dont_keeep_key_pressed(void)
72 {
73 #ifdef DONT_KEEEP_KEY_PRESSED
74         return true;
75 #else
76         return false;
77 #endif
78 }
79
80 bool OSD::get_one_board_micro_computer(void)
81 {
82 #ifdef ONE_BOARD_MICRO_COMPUTER
83         return true;
84 #else
85         return false;
86 #endif
87 }
88
89 bool OSD::get_use_screen_rotate(void)
90 {
91 #ifdef USE_SCREEN_ROTATE
92         return true;
93 #else
94         return false;
95 #endif
96 }
97
98 bool OSD::get_use_movie_player(void)
99 {
100 #ifdef USE_MOVIE_PLAYER
101         return true;
102 #else
103         return false;
104 #endif
105 }
106
107 bool OSD::get_use_video_capture(void)
108 {
109 #ifdef USE_VIDEO_CAPTURE
110         return true;
111 #else
112         return false;
113 #endif
114 }
115
116
117 int OSD::get_vm_buttons_code(int num)
118 {
119 #ifdef ONE_BOARD_MICRO_COMPUTER
120         if(num < 0) return 0;
121         return vm_buttons[num].code;
122 #else
123         return 0;
124 #endif
125 }
126
127
128 QString OSD::get_vm_config_name(void)
129 {
130 #if defined(CONFIG_NAME)
131         return QString::fromUtf8(CONFIG_NAME);
132 #else
133         return QString::fromUtf8(" ");
134 #endif
135 }
136
137 int OSD::get_screen_width(void)
138 {
139         return SCREEN_WIDTH;
140 }
141
142 int OSD::get_screen_height(void)
143 {
144         return SCREEN_HEIGHT;
145 }
146
147
148 void OSD::set_draw_thread(DrawThreadClass *handler)
149 {
150         //this->moveToThread(handler);
151         connect(this, SIGNAL(sig_update_screen(void *, bool)), handler, SLOT(do_update_screen(void *, bool)));
152         connect(this, SIGNAL(sig_save_screen(const char *)), p_glv, SLOT(do_save_frame_screen(const char *)));
153         connect(this, SIGNAL(sig_resize_vm_screen(QImage *, int, int)), p_glv, SLOT(do_set_texture_size(QImage *, int, int)));
154         connect(this, SIGNAL(sig_resize_vm_lines(int)), p_glv, SLOT(do_set_horiz_lines(int)));
155         connect(parent_thread, SIGNAL(sig_debugger_input(QString)), this, SLOT(do_set_input_string(QString)));
156         connect(parent_thread, SIGNAL(sig_quit_debugger()), this, SLOT(do_close_debugger_thread()));
157         connect(this, SIGNAL(sig_move_mouse_to_center()), p_glv, SLOT(do_move_mouse_to_center()));
158         connect(this, SIGNAL(sig_close_window()), parent_thread, SLOT(doExit()));
159 }
160
161 void OSD::initialize_screen()
162 {
163         host_window_width = base_window_width = WINDOW_WIDTH;
164         host_window_height = base_window_height = WINDOW_HEIGHT;
165         host_window_mode = true;
166
167         vm_screen_width = SCREEN_WIDTH;
168         vm_screen_height = SCREEN_HEIGHT;
169         vm_window_width = WINDOW_WIDTH;
170         vm_window_height = WINDOW_HEIGHT;
171         vm_window_width_aspect = WINDOW_WIDTH_ASPECT;
172         vm_window_height_aspect = WINDOW_HEIGHT_ASPECT;
173
174         QColor col(0, 0, 0, 255);
175
176         vm_screen_buffer.width = SCREEN_WIDTH;
177         vm_screen_buffer.height = SCREEN_HEIGHT;
178         vm_screen_buffer.pImage = QImage(SCREEN_WIDTH, SCREEN_HEIGHT, QImage::Format_ARGB32);
179         vm_screen_buffer.pImage.fill(col);
180         now_record_video = false;
181
182         first_draw_screen = false;
183         first_invalidate = true;
184         self_invalidate = false;
185 }
186
187 void OSD::release_screen()
188 {
189         stop_record_video();
190         release_screen_buffer(&vm_screen_buffer);
191 }
192
193 int OSD::get_window_mode_width(int mode)
194 {
195         if(get_use_screen_rotate()) {
196                 if(p_config->rotate_type == 1 || p_config->rotate_type == 3) {
197                         return (p_config->window_stretch_type == 0 ? vm_window_height : vm_window_height_aspect) * (mode + WINDOW_MODE_BASE);
198                 }
199         }
200         return (p_config->window_stretch_type == 0 ? vm_window_width : vm_window_width_aspect) * (mode + WINDOW_MODE_BASE);
201 }
202
203 int OSD::get_window_mode_height(int mode)
204 {
205         if(get_use_screen_rotate()) {
206                 if(p_config->rotate_type == 1 || p_config->rotate_type == 3) {
207                         return (p_config->window_stretch_type == 0 ? vm_window_width : vm_window_width_aspect) * (mode + WINDOW_MODE_BASE);
208                 }
209         }
210         return (p_config->window_stretch_type == 0 ? vm_window_height : vm_window_height_aspect) * (mode + WINDOW_MODE_BASE);
211 }
212
213 double OSD::get_window_mode_power(int mode)
214 {
215         if(mode + WINDOW_MODE_BASE == 2) {
216                 return 1.5;
217         } else if(mode + WINDOW_MODE_BASE > 2) {
218                 return mode + WINDOW_MODE_BASE - 1;
219         }
220         return mode + WINDOW_MODE_BASE;
221 }
222
223
224 void OSD::initialize_video()
225 {
226         movie_loader = NULL;
227 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
228         movie_loader = new MOVIE_LOADER(this, &config);
229         //connect(movie_loader, SIGNAL(sig_send_audio_frame(uint8_t *, long)), this, SLOT(do_run_movie_audio_callback2(uint8_t *, long)));
230         connect(movie_loader, SIGNAL(sig_movie_end(bool)), this, SLOT(do_video_movie_end(bool)));
231         connect(this, SIGNAL(sig_movie_play(void)), movie_loader, SLOT(do_play()));
232         connect(this, SIGNAL(sig_movie_stop(void)), movie_loader, SLOT(do_stop()));
233         connect(this, SIGNAL(sig_movie_pause(bool)), movie_loader, SLOT(do_pause(bool)));
234         connect(this, SIGNAL(sig_movie_seek_frame(bool, int)), movie_loader, SLOT(do_seek_frame(bool, int)));
235         //connect(this, SIGNAL(sig_movie_mute(bool, bool)), movie_loader, SLOT(do_mute(bool, bool)));
236         connect(movie_loader, SIGNAL(sig_decoding_error(int)), this, SLOT(do_video_decoding_error(int)));
237 #endif
238 }
239
240 void OSD::release_video()
241 {
242 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
243         delete movie_loader;
244 #endif
245         movie_loader = NULL;
246 }
247
248
249 bool OSD::open_movie_file(const _TCHAR* file_path)
250 {
251         bool ret = false;
252         if(file_path == NULL) return ret;
253 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
254         if(movie_loader != NULL) {
255                 ret = movie_loader->open(QString::fromUtf8(file_path));
256         }
257 #endif
258         return ret;
259 }
260
261 void OSD::close_movie_file()
262 {
263 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
264         if(movie_loader != NULL) {
265                 movie_loader->close();
266         }
267 #endif
268         now_movie_play = false;
269         now_movie_pause = false;
270 }
271
272 #include <limits.h>
273 uint32_t OSD::get_cur_movie_frame()
274 {
275 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
276         if(movie_loader != NULL) {
277                 uint64_t pos;
278                 pos = movie_loader->get_current_frame();
279                 if(pos > UINT_MAX) {
280                         return UINT_MAX;
281                 }
282                 return (uint32_t)pos;
283         }
284 #endif
285         return 0;
286 }
287
288 void OSD::do_run_movie_audio_callback(uint8_t *data, long len)
289 {
290         if(data == NULL) return;
291 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
292 #if defined(_PX7)
293         {
294                 lock_vm();
295                 this->vm->movie_sound_callback(data, len);
296                 unlock_vm();
297         }
298 #endif
299 #endif
300         free(data);
301 }
302
303 void OSD::do_decode_movie(int frames)
304 {
305 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
306         //movie_loader->do_decode_frames(frames, SCREEN_WIDTH, SCREEN_HEIGHT);
307         movie_loader->do_decode_frames(frames, vm_window_width_aspect, vm_window_height_aspect);
308 #endif
309 }
310
311 void OSD::get_video_buffer()
312 {
313 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
314         //movie_loader->do_decode_frames(1, this->get_vm_window_width(), this->get_vm_window_height());
315         movie_loader->get_video_frame();
316         //printf("**\n");
317 #endif
318 }
319
320 int OSD::get_movie_sound_rate()
321 {
322 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
323         return movie_loader->get_movie_sound_rate();
324 #endif
325         return 44100;
326 }
327
328 #if defined(USE_SOCKET)
329 #include <QHostAddress>
330 #include <QTcpSocket>
331 #include <QUdpSocket>
332
333 #include "osd_socket.h"
334 #endif
335 // Socket
336 void OSD::initialize_socket()
337 {
338         for(int i = 0; i < SOCKET_MAX; i++) {
339                 tcp_socket[i] = NULL;
340                 udp_socket[i] = NULL;
341                 is_tcp[i] = false;
342                 socket_delay[i] = 0;
343                 host_mode[i] = false;
344         }
345 }
346
347 void OSD::release_socket()
348 {
349         // release sockets
350 #ifdef USE_SOCKET
351         for(int i = 0; i < SOCKET_MAX; i++) {
352                 if(tcp_socket[i] != NULL) {
353                         if(tcp_socket[i]->isOpen()) tcp_socket[i]->close();
354                         delete tcp_socket[i];
355                         tcp_socket[i] = NULL;
356                 }
357                 if(udp_socket[i] != NULL) {
358                         if(udp_socket[i]->isOpen()) udp_socket[i]->close();
359                         delete udp_socket[i];
360                         udp_socket[i] = NULL;
361                 }
362         }
363 #endif
364 }
365
366
367 void OSD::notify_socket_connected(int ch)
368 {
369         do_notify_socket_connected(ch);
370 }
371
372 void OSD::do_notify_socket_connected(int ch)
373 {
374 #ifdef USE_SOCKET
375         // ToDo: Really need to lock? 20221011 K.O
376         std::lock_guard<std::recursive_timed_mutex> lv(vm_mutex);
377         vm->notify_socket_connected(ch);
378 #endif
379 }
380
381
382 void OSD::notify_socket_disconnected(int ch)
383 {
384         do_notify_socket_disconnected(ch);
385 }
386
387
388 void OSD::do_notify_socket_disconnected(int ch)
389 {
390         if(!socket_delay[ch]) {
391                 socket_delay[ch] = 1;//56;
392         }
393 }
394
395 // Called per 1 frame.
396 void OSD::update_socket()
397 {
398 #ifdef USE_SOCKET
399         // ToDo: Really need to lock? 20221011 K.O
400         std::lock_guard<std::recursive_timed_mutex> lv(vm_mutex);
401         qint64 bytes;
402         for(int i = 0; i < SOCKET_MAX; i++) {
403                 QIODevice *p = NULL;
404                 if(is_tcp[i]) {
405                         if(tcp_socket[i] != NULL) {
406                                 if(tcp_socket[i]->isOpen()) {
407                                         p = tcp_socket[i];
408                                 }
409                         }
410                 } else {
411                         if(udp_socket[i] != NULL) {
412                                 if(udp_socket[i]->isOpen()) {
413                                         p = udp_socket[i];
414                                 }
415                         }
416                 }
417                 if((p != nullptr) && (vm != nullptr)) {
418                         // recv
419                         bytes = p->bytesAvailable();
420                         if(bytes > 0) {
421                                 int size0, size1;
422                                 uint8_t* buf0 = vm->get_socket_recv_buffer0(i, &size0, &size1);
423                                 uint8_t* buf1 = vm->get_socket_recv_buffer1(i);
424                                 qint64 size;
425
426                                 if(bytes > (qint64)(size0 + size1)) {
427                                         bytes = (qint64)(size0 + size1);
428                                 }
429                                 QByteArray src = p->read(bytes);
430
431                                 size = src.size();
432                                 uint8_t *pp = (uint8_t *)(src.constData());
433                                 if(size <= (qint64)size0) {
434                                         memcpy(buf0, pp, size);
435                                 } else {
436                                         memcpy(buf0, pp, size0);
437                                         memcpy(buf1, pp + size0, (int)size - size0);
438                                 }
439                                 vm->inc_socket_recv_buffer_ptr(i, (int)size);
440                         } else if(socket_delay[i] != 0) {
441                                 if(--socket_delay[i] == 0) {
442                                         vm->notify_socket_disconnected(i);
443                                 }
444                         }
445                 }
446         }
447 #endif
448 }
449
450 bool OSD::initialize_socket_tcp(int ch)
451 {
452 #ifdef USE_SOCKET
453         if(udp_socket[ch] != NULL) {
454                 if(udp_socket[ch]->isOpen()) {
455                         udp_socket[ch]->close();
456                 }
457                 delete udp_socket[ch];
458                 udp_socket[ch] = NULL;
459         }
460         if(tcp_socket[ch] != NULL) {
461                 if(tcp_socket[ch]->isOpen()) tcp_socket[ch]->close();
462                 delete tcp_socket[ch];
463         }
464         is_tcp[ch] = true;
465         tcp_socket[ch] = new QTcpSocket2(ch);
466         if(tcp_socket[ch] == NULL) return false;
467         tcp_socket[ch]->setChannel(ch);
468         connect(tcp_socket[ch], SIGNAL(connected()), tcp_socket[ch], SLOT(do_connected()));
469         connect(tcp_socket[ch], SIGNAL(sig_connected(int)), this, SLOT(do_notify_socket_connected(int)));
470         connect(tcp_socket[ch], SIGNAL(disconnected()), tcp_socket[ch], SLOT(do_disconnected()));
471         connect(tcp_socket[ch], SIGNAL(sig_disconnected(int)), this, SLOT(do_notify_socket_disconnected(int)));
472 #endif
473         return true;
474 }
475
476 bool OSD::initialize_socket_udp(int ch)
477 {
478 #ifdef USE_SOCKET
479         if(tcp_socket[ch] != NULL) {
480                 if(tcp_socket[ch]->isOpen()) {
481                         tcp_socket[ch]->close();
482                 }
483                 delete tcp_socket[ch];
484                 tcp_socket[ch] = NULL;
485         }
486         if(udp_socket[ch] != NULL) {
487                 if(udp_socket[ch]->isOpen()) udp_socket[ch]->close();
488                 delete udp_socket[ch];
489         }
490         is_tcp[ch] = false;
491         udp_socket[ch] = new QUdpSocket2(ch);
492         if(udp_socket[ch] == NULL) return false;
493         connect(udp_socket[ch], SIGNAL(connected()), udp_socket[ch], SLOT(do_connected()));
494         connect(udp_socket[ch], SIGNAL(sig_connected(int)), this, SLOT(do_notify_socket_connected(int)));
495         connect(udp_socket[ch], SIGNAL(disconnected()), udp_socket[ch], SLOT(do_disconnected()));
496         connect(udp_socket[ch], SIGNAL(sig_disconnected(int)), this, SLOT(do_notify_socket_disconnected(int)));
497 #endif
498         return true;
499 }
500
501 bool OSD::connect_socket(int ch, uint32_t ipaddr, int port)
502 {
503 #ifdef USE_SOCKET
504         QHostAddress addr = QHostAddress((quint32)ipaddr);
505         if(is_tcp[ch]) {
506                 if(tcp_socket[ch] != NULL) {
507                         tcp_socket[ch]->connectToHost(addr, (quint16)port);
508                 } else {
509                         return false;
510                 }
511         } else {
512                 if(udp_socket[ch] != NULL) {
513                         udp_socket[ch]->connectToHost(addr, (quint16)port);
514                 } else {
515                         return false;
516                 }
517         }
518         host_mode[ch] = false;
519 #endif
520         return true;
521 }
522
523 void OSD::disconnect_socket(int ch)
524 {
525 //      soc[ch] = -1;
526 #ifdef USE_SOCKET
527         // ToDo: Really need to lock? 20221011 K.O
528         std::lock_guard<std::recursive_timed_mutex> lv(vm_mutex);
529
530         if(host_mode[ch]) {
531                 if(is_tcp[ch]) {
532                         if(tcp_socket[ch] != NULL) {
533                                 if(tcp_socket[ch]->isOpen()) tcp_socket[ch]->close();
534                         }
535                 } else {
536                         if(udp_socket[ch] != NULL) {
537                                 if(udp_socket[ch]->isOpen()) udp_socket[ch]->close();
538                         }
539                 }
540         } else {
541                 if(is_tcp[ch]) {
542                         if(tcp_socket[ch] != NULL) {
543                                 udp_socket[ch]->disconnectFromHost();
544                         }
545                 } else {
546                         if(udp_socket[ch] != NULL) {
547                                 udp_socket[ch]->disconnectFromHost();
548                         }
549                 }
550         }
551         if(vm == nullptr) return;
552         vm->notify_socket_disconnected(ch);
553 #endif
554 }
555
556 bool OSD::listen_socket(int ch)
557 {
558 #ifdef USE_SOCKET
559         // ToDo: Really need to lock? 20221011 K.O
560         std::lock_guard<std::recursive_timed_mutex> lv(vm_mutex);
561
562         //QHostAddress addr = QHostAddress(QHostAddress::AnyIPv4); // OK?
563         // This unit is dummy?
564         //connect(udp_socket[ch], SIGNAL(connected()), udp_socket[ch], SLOT(do_connected()));
565         //connect(udp_socket[ch], SIGNAL(sig_connected(int)), this, SLOT(do_notify_socket_connected(int)));
566         //connect(udp_socket[ch], SIGNAL(disconnected()), udp_socket[ch], SLOT(do_disconnected()));
567         //connect(udp_socket[ch], SIGNAL(sig_disconnected(int)), this, SLOT(do_notify_socket_disconnected(int)));
568 #endif
569         return false;
570 }
571
572 void OSD::send_socket_data_tcp(int ch)
573 {
574 #ifdef USE_SOCKET
575         // ToDo: Really need to lock? 20221011 K.O
576         std::lock_guard<std::recursive_timed_mutex> lv(vm_mutex);
577
578         if(vm == nullptr) return;
579         if(is_tcp[ch]) {
580                 while(1) {
581                         int size;
582                         uint8_t *buf = vm->get_socket_send_buffer(ch, &size);
583                         if(size <= 0) {
584                                 return;
585                         }
586                         qint64 size2 = 0;
587                         if(tcp_socket[ch] != NULL) {
588                                 if(tcp_socket[ch]->isWritable()) {
589                                         size2 = tcp_socket[ch]->write((const char *)buf, (qint64)size);
590                                         if(size2 < 0) {
591                                                 disconnect_socket(ch);
592                                                 notify_socket_disconnected(ch);
593                                                 return;
594                                         }
595                                 }
596                         } else {
597                                 return;
598                         }
599                         vm->inc_socket_send_buffer_ptr(ch, (int)size2);
600                 }
601         }
602 #endif
603 }
604
605 void OSD::send_socket_data_udp(int ch, uint32_t ipaddr, int port)
606 {
607 #ifdef USE_SOCKET
608         // ToDo: Really need to lock? 20221011 K.O
609         std::lock_guard<std::recursive_timed_mutex> lv(vm_mutex);
610
611         QHostAddress addr = QHostAddress((quint32)ipaddr);
612         if(vm == nullptr) return;
613         if(!(is_tcp[ch])) {
614                 while(1) {
615                         int size;
616                         uint8_t *buf = vm->get_socket_send_buffer(ch, &size);
617                         if(size <= 0) {
618                                 return;
619                         }
620                         qint64 size2 = 0;
621
622                         if(udp_socket[ch] != NULL) {
623                                 size2 = udp_socket[ch]->writeDatagram((const char *)buf, (qint64)size, addr, (quint16)port);
624                                 if(size2 < 0) {
625                                         disconnect_socket(ch);
626                                         notify_socket_disconnected(ch);
627                                         return;
628                                 }
629                         } else {
630                                 return;
631                         }
632                         vm->inc_socket_send_buffer_ptr(ch, (int)size2);
633                 }
634         }
635 #endif
636 }
637
638 void OSD::send_socket_data(int ch)
639 {
640         // This is dummy.
641 }
642
643 void OSD::recv_socket_data(int ch)
644 {
645         // This is dummy.
646 }
647
648 SOCKET OSD::get_socket(int ch)
649 {
650 #ifdef USE_SOCKET
651         if(is_tcp[ch]) {
652                 if(tcp_socket[ch] == NULL) return (SOCKET)0;
653                 return (SOCKET)tcp_socket[ch];
654         } else {
655                 if(udp_socket[ch] == NULL) return (SOCKET)0;
656                 return (SOCKET)udp_socket[ch];
657         }
658 #endif
659         return (SOCKET)0;
660 }
661
662 //
663
664 // Screen
665 scrntype_t DLL_PREFIX *bitmap_s::get_buffer(int y)
666 {
667         if((is_mapped) && (glv != NULL)) {
668                 scrntype_t *p = NULL;
669                         p = glv->get_screen_buffer(y);
670                         if(p != NULL) return p;
671                 }
672                 return (scrntype_t *)pImage.scanLine(y);
673 }
674
675 scrntype_t* OSD::get_buffer(bitmap_t *p, int y)
676 {
677         if(p_glv->is_ready_to_map_vram_texture()) {
678                 if(p == &vm_screen_buffer) {
679                         return (scrntype_t *)p->get_buffer(y);
680                 }
681         }
682         if((y >= p->pImage.height()) || (y < 0) || (y >= p->height)) {
683                 return NULL;
684         }
685         return (scrntype_t *)p->pImage.scanLine(y);
686 }
687
688
689 int OSD::draw_screen()
690 {
691         // draw screen
692         std::lock_guard<std::recursive_timed_mutex> Locker_S(screen_mutex);
693
694         bool mapped = false;
695         //QMutexLocker Locker_VM(&vm_mutex);
696         if(vm_screen_buffer.width != vm_screen_width || vm_screen_buffer.height != vm_screen_height) {
697                 //emit sig_movie_set_width(vm_screen_width);
698                 //emit sig_movie_set_height(vm_screen_height);
699                 initialize_screen_buffer(&vm_screen_buffer, vm_screen_width, vm_screen_height, 0);
700         }
701         #if 1
702         if(p_glv->is_ready_to_map_vram_texture()) {
703                 vm_screen_buffer.is_mapped = true;
704                 mapped = true;
705                 vm_screen_buffer.glv = p_glv;
706         } else {
707                 vm_screen_buffer.is_mapped = false;
708         }
709         #else
710                         vm_screen_buffer.is_mapped = false;
711         #endif
712         this->vm_draw_screen();
713         // screen size was changed in vm->draw_screen()
714         if(vm_screen_buffer.width != vm_screen_width || vm_screen_buffer.height != vm_screen_height) {
715                 return 0;
716         }
717         draw_screen_buffer = &vm_screen_buffer;
718
719         // calculate screen size
720         // invalidate window
721         // ToDo: Support MAX_DRAW_RANGES. 20221212 K.O
722         emit sig_update_screen((void *)draw_screen_buffer, mapped);
723
724         first_draw_screen = self_invalidate = true;
725
726         // record avi file
727         if(now_record_video) {
728                 add_video_frames();
729         }
730         return 1;
731 }
732
733 void OSD::initialize_screen_buffer(bitmap_t *buffer, int width, int height, int mode)
734 {
735         OSD_BASE::initialize_screen_buffer(buffer, width, height, mode);
736         buffer->glv = p_glv;
737         //emit sig_movie_set_width(width);
738         //emit sig_movie_set_height(height);
739         emit sig_resize_vm_screen(&(buffer->pImage), width, height);
740 }
741
742 bool OSD::set_glview(GLDrawClass *glv)
743 {
744         if(glv == NULL) return false;
745         if(glContext != NULL) {
746                 if(glContext->isValid()) return true;
747                 return false;
748         }
749         p_glv = glv;
750
751         glContext = new QOpenGLContext();
752         if(glContext != NULL) {
753                 glContext->setShareContext(glv->context());
754                 glContext->create();
755         }
756         if(glContext->isValid()) {
757                 is_glcontext_shared = true;
758                 return true;
759         }
760         return false;
761 }
762
763 int OSD::add_video_frames()
764 {
765         //static double frames = 0;
766         //static int prev_video_fps = -1;
767         int counter = 0;
768         //static double prev_vm_fps = -1;
769         double vm_fps = vm_frame_rate();
770         int delta_ns = (int)(1.0e9 / vm_fps);
771         //if(rec_video_fps_nsec >= delta_ns) {
772         if(delta_ns == rec_video_fps_nsec) {
773                 rec_video_nsec += delta_ns;
774                 if(rec_video_nsec > (rec_video_fps_nsec * 2)) {
775                         rec_video_nsec -= rec_video_fps_nsec;
776                 } else if(rec_video_nsec < (rec_video_fps_nsec * -2)) {
777                         rec_video_nsec += rec_video_fps_nsec;
778                 }
779                 while(rec_video_nsec > rec_video_fps_nsec) {
780                         rec_video_nsec -= rec_video_fps_nsec;
781                         counter++;
782                 }
783         } else { // Will branch whether rec_video_fps_nsec >= delta_ns ?
784                 rec_video_nsec += delta_ns;
785                 if(rec_video_nsec > (rec_video_fps_nsec * 2)) {
786                         rec_video_nsec -= rec_video_fps_nsec;
787                 } else if(rec_video_nsec < (rec_video_fps_nsec * -2)) {
788                         rec_video_nsec += rec_video_fps_nsec;
789                 }
790                 while(rec_video_nsec >= rec_video_fps_nsec) {
791                         rec_video_nsec -= rec_video_fps_nsec;
792                         counter++;
793                 }
794         }
795
796         if(using_flags->is_use_one_board_computer()) {
797                 //int size = vm_screen_buffer.pImage.byteCount();
798                 int i = counter;
799                 rec_image_buffer = background_image.rgbSwapped();
800                 if(p_glv->is_ready_to_map_vram_texture()) {
801                         vm_screen_buffer.is_mapped = true;
802                         vm_screen_buffer.glv = p_glv;
803                         for(int y = 0; y < vm_screen_buffer.pImage.height(); y++) {
804                                 scrntype_t *p = vm_screen_buffer.get_buffer(y);
805                                 if(p != NULL) {
806                                         if(p != (scrntype_t*)(vm_screen_buffer.pImage.scanLine(y))) {
807                                                 memcpy(vm_screen_buffer.pImage.scanLine(y), p, vm_screen_buffer.pImage.width() * sizeof(scrntype_t));
808                                         }
809                                 } else {
810                                         if(vm_screen_buffer.pImage.scanLine(y) != NULL) {
811                                                 memset(vm_screen_buffer.pImage.scanLine(y), 0x00, vm_screen_buffer.pImage.width() * sizeof(scrntype_t));
812                                         }
813                                 }
814                         }
815                 }
816                 QImage video_result = QImage(vm_screen_buffer.pImage);
817
818                 QRgb pixel;
819                 int ww = video_result.width();
820                 int hh = video_result.height();
821                 //printf("%d x %d\n", ww, hh);
822                 for(int yy = 0; yy < hh; yy++) {
823                         for(int xx = 0; xx < ww; xx++) {
824                                 pixel = video_result.pixel(xx, yy);
825 #if defined(__LITTLE_ENDIAN__)
826                                 pixel |= 0xff000000;
827                                 if(pixel != 0xff000000) {
828                                         rec_image_buffer.setPixel(xx, yy, pixel);
829                                 }
830 #else
831                                 pixel |= 0x000000ff;
832                                 if(pixel != 0x000000ff) {
833                                         rec_image_buffer.setPixel(xx, yy, pixel);
834                                 }
835 #endif
836                         }
837                 }
838                 if(i > 0) {
839                         // Enqueue to frame.
840                         emit sig_enqueue_video(i, background_image.width(), background_image.height(), &rec_image_buffer);
841                         //i--;
842                 }
843         } else {
844                 //int size = vm_screen_buffer.pImage.byteCount();
845                 int i = counter;
846                 QImage video_result;
847                 video_result = QImage(vm_screen_buffer.pImage);
848                 // Rescaling
849                 if(i > 0) {
850                         // Enqueue to frame.
851                         emit sig_enqueue_video(i, vm_screen_width, vm_screen_height, &video_result);
852                         //i--;
853                 }
854                 // _TCHAR __tmps1[128] = {0};
855                 // my_stprintf_s(__tmps1, sizeof(__tmps1) - 1, "Push Video %d frames\n", counter);
856                 //emit sig_debug_log(CSP_LOG_DEBUG2, CSP_LOG_TYPE_SCREEN, QString::fromUtf8(__tmps1) );
857         }
858         return counter;
859 }
860
861 double OSD::get_vm_current_usec()
862 {
863         if(log_mutex.try_lock_for(std::chrono::milliseconds(100))) {
864                 if(vm == nullptr) {
865                         log_mutex.unlock();
866                         return 0.0;
867                 }
868                 double _d = vm->get_current_usec();
869                 log_mutex.unlock();
870                 return _d;
871         }
872         return 0.0;
873 }
874
875 uint64_t OSD::get_vm_current_clock_uint64()
876 {
877         if(log_mutex.try_lock_for(std::chrono::milliseconds(100))) {
878                 if(vm == nullptr) {
879                         log_mutex.unlock();
880                         return 0;
881                 }
882                 uint64_t _n = vm->get_current_clock_uint64();
883                 log_mutex.unlock();
884                 return _n;
885         }
886         return 0;
887 }
888
889 const _TCHAR *OSD::get_lib_common_vm_version()
890 {
891         // ToDo: Really need to lock? 20221011 K.O
892 //      std::lock_guard<std::recursive_timed_mutex> lv(vm_mutex);
893
894         if(vm->first_device != NULL) {
895                 return vm->first_device->get_lib_common_vm_version();
896         } else {
897                 return (const _TCHAR *)"\0";
898         }
899 }
900
901 void OSD::reset_vm_node(void)
902 {
903         // ToDo: Really need to lock? 20221011 K.O
904         std::lock_guard<std::recursive_timed_mutex> lv(vm_mutex);
905
906         device_node_t sp;
907         device_node_list.clear();
908         emit sig_logger_reset();
909
910         max_vm_nodes = 0;
911         if(vm == NULL) return;
912         for(DEVICE *p = vm->first_device; p != NULL; p = p->next_device) {
913                 sp.id = p->this_device_id;
914                 sp.name = p->this_device_name;
915                 emit sig_logger_set_device_name(sp.id, QString::fromUtf8(sp.name));
916
917                 _TCHAR tmps2[512] = {0};
918                 my_stprintf_s(tmps2, sizeof(tmps2) - 1, "Device %d :%s", sp.id, sp.name);
919                 emit sig_debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_GENERAL, QString::fromUtf8(tmps2));
920
921                 device_node_list.append(sp);
922                 if(max_vm_nodes <= p->this_device_id) max_vm_nodes = p->this_device_id + 1;
923         }
924         for(DEVICE *p = vm->first_device; p != NULL; p = p->next_device) {
925                 emit sig_update_device_node_name(p->this_device_id, p->this_device_name);
926         }
927 }