Qt 5.3.1をいじってみた その3

若干ですがAndroid用に書き直すソースコードもあります。

f:id:tanam:20140817142352p:image:w360

これで武田さんの最新版ソースコードをベースに、Qt5.3.1でAndroid版をビルドすることが可能となります。なお個人的にAndroid端末を利用しなくなったため開発は継続されません。

http://takeda-toshiya.seesaa.net/article/397915031.html

emu.cpp

/*
	Skelton for retropc emulator

    QT Version : tanam
	Date   : 2013.05.18 -

	[ QT emulation i/f ]

*/

#include "emu.h"

// ----------------------------------------------------------------------------
// initialize
// ----------------------------------------------------------------------------
EMU::EMU(QWidget *)
{
    // timer event
    skip_frames=0;
    m_timer = new QTimer();
    connect(m_timer, SIGNAL(timeout()), this, SLOT(onTimer()));
    m_timer->start(1000/FPS);

    // load sound config
    static int freq_table[8] = {2000, 4000, 8000, 11025, 22050, 44100, 48000, 96000};
    static double late_table[5] = {0.05, 0.1, 0.2, 0.3, 0.4};

    if(!(0 <= config.sound_frequency && config.sound_frequency < 8)) {
        config.sound_frequency = 6;	// default: 48KHz
    }
    if(!(0 <= config.sound_latency && config.sound_latency < 5)) {
        config.sound_latency = 1;	// default: 100msec
    }
    sound_rate = freq_table[config.sound_frequency];
    sound_samples = (int)(sound_rate * late_table[config.sound_latency] + 0.5);

    // initialize
    vm = new VM(this);
    initialize_input();
    initialize_screen();
    initialize_sound();
    initialize_media();
    initialize_printer();
    vm->initialize_sound(sound_rate, sound_samples);
    vm->reset();

    config.window_mode = 1;
}

EMU::~EMU()
{
    release_screen();
    release_sound();
    release_printer();
    delete vm;
}

// ----------------------------------------------------------------------------
// drive machine
// ----------------------------------------------------------------------------
int EMU::run()
{
    update_media();
    update_printer();

    // virtual machine may be driven to fill sound buffer
    int extra_frames = 0;
    update_sound(&extra_frames);

    // drive virtual machine
    if(extra_frames == 0) {
        vm->run();
        extra_frames = 1;
    }
    return extra_frames;
}

void EMU::reset()
{
    // reset virtual machine
    vm->reset();
    // reset printer
    reset_printer();
}

// ----------------------------------------------------------------------------
// user interface
// ----------------------------------------------------------------------------

void EMU::initialize_media()
{
#ifdef USE_CART1
    memset(&cart_status, 0, sizeof(cart_status));
#endif
#ifdef USE_FD1
    memset(disk_status, 0, sizeof(disk_status));
#endif
#ifdef USE_TAPE
    memset(&tape_status, 0, sizeof(tape_status));
#endif
}

void EMU::update_media()
{
#ifdef USE_FD1
    for(int drv = 0; drv < 8; drv++) {
        if(disk_status[drv].wait_count != 0 && --disk_status[drv].wait_count == 0) {
            vm->open_disk(drv, disk_status[drv].path, disk_status[drv].offset);
        }
    }
#endif
#ifdef USE_TAPE
    if(tape_status.wait_count != 0 && --tape_status.wait_count == 0) {
        if(tape_status.play) {
            vm->play_tape(tape_status.path);
        } else {
            vm->rec_tape(tape_status.path);
        }
    }
#endif
}

void EMU::restore_media()
{
#ifdef USE_CART1
    if(cart_status.path[0] != _T('\0')) {
        vm->open_cart(0, cart_status.path);
    }
#endif
#ifdef USE_FD1
    for(int drv = 0; drv < 8; drv++) {
        if(disk_status[drv].path[0] != _T('\0')) {
            vm->open_disk(drv, disk_status[drv].path, disk_status[drv].offset);
        }
    }
#endif
#ifdef USE_TAPE
    if(tape_status.path[0] != _T('\0')) {
        if(tape_status.play) {
            vm->play_tape(tape_status.path);
        } else {
            tape_status.path[0] = _T('\0');
        }
    }
#endif
}

#ifdef USE_CART1
void EMU::open_cart(int drv, _TCHAR* file_path)
{
    vm->open_cart(drv, file_path);
    _tcscpy(cart_status.path, file_path);
}

void EMU::close_cart(int drv)
{
    vm->close_cart(drv);
    clear_media_status(&cart_status);
}

bool EMU::cart_inserted(int drv)
{
    return vm->cart_inserted(drv);
}
#endif

#ifdef USE_FD1
void EMU::open_disk(int drv, _TCHAR* file_path, int offset)
{
    if(vm->disk_inserted(drv)) {
        vm->close_disk(drv);
        // wait 0.5sec
        disk_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);
    } else if(disk_status[drv].wait_count == 0) {
        vm->open_disk(drv, file_path, offset);
    }
    _tcscpy(disk_status[drv].path, file_path);
    disk_status[drv].offset = offset;
}

void EMU::close_disk(int drv)
{
    vm->close_disk(drv);
    clear_media_status(&disk_status[drv]);
}

bool EMU::disk_inserted(int drv)
{
    return vm->disk_inserted(drv);
}
#endif

#ifdef USE_TAPE
void EMU::play_tape(_TCHAR* file_path)
{
    if(vm->tape_inserted()) {
        vm->close_tape();
        // wait 0.5sec
        tape_status.wait_count = (int)(FRAMES_PER_SEC / 2);
    } else if(tape_status.wait_count == 0) {
        vm->play_tape(file_path);
    }
    _tcscpy(tape_status.path, file_path);
    tape_status.play = true;
}

void EMU::rec_tape(_TCHAR* file_path)
{
    if(vm->tape_inserted()) {
        vm->close_tape();
        // wait 0.5sec
        tape_status.wait_count = (int)(FRAMES_PER_SEC / 2);
    } else if(tape_status.wait_count == 0) {
        vm->rec_tape(file_path);
    }
    _tcscpy(tape_status.path, file_path);
    tape_status.play = false;
}

void EMU::close_tape()
{
    vm->close_tape();
    clear_media_status(&tape_status);
}

bool EMU::tape_inserted()
{
    return vm->tape_inserted();
}
#endif

void EMU::onTimer()
{
    run();
    if (++skip_frames >MAX_SKIP_FRAMES) {
        draw_screen();
        skip_frames=0;
    }
    update();
    return;
}

_TCHAR* EMU::bios_path(_TCHAR* file_name)
{
	static _TCHAR file_path[_MAX_PATH];
    _stprintf(file_path, _T("/sdcard/rom/%s"), file_name);
	return file_path;
}


// ----------------------------------------------------------------------------
// printer
// ----------------------------------------------------------------------------

void EMU::initialize_printer()
{
    prn_fio = new FILEIO();
    prn_data = -1;
    prn_strobe = false;
}

void EMU::release_printer()
{
    delete prn_fio;
}

void EMU::reset_printer()
{
    prn_fio->Fclose();
    prn_data = -1;
    prn_strobe = false;
}

void EMU::update_printer()
{
    if(prn_fio->IsOpened() && --prn_wait_frames == 0) {
        prn_fio->Fclose();
    }
}

void EMU::printer_out(uint8 value)
{
    prn_data = value;
}

void EMU::printer_strobe(bool value)
{
    bool falling = (prn_strobe && !value);
    prn_strobe = value;

    if(falling) {
        if(!prn_fio->IsOpened()) {
            if(prn_data == -1) {
                return;
            }
            cur_time_t time;
            _TCHAR file_name[_MAX_PATH];
///            get_host_time(&time);
            _stprintf(file_name, _T("prn_%d-%0.2d-%0.2d_%0.2d-%0.2d-%0.2d.txt"), time.year, time.month, time.day, time.hour, time.minute, time.second);
            prn_fio->Fopen(bios_path(file_name), FILEIO_WRITE_BINARY);
        }
        prn_fio->Fputc(prn_data);
        // wait 10sec
#ifdef SUPPORT_VARIABLE_TIMING
        prn_wait_frames = (int)(vm->frame_rate() * 10.0 + 0.5);
#else
        prn_wait_frames = (int)(FRAMES_PER_SEC * 10.0 + 0.5);
#endif
    }
}

void EMU::out_debug(const _TCHAR* format, ...)
{
#ifdef _DEBUG_LOG
    va_list ap;
    _TCHAR buffer[1024];

    va_start(ap, format);
    _vstprintf(buffer, format, ap);
#ifdef _DEBUG_CONSOLE
    DWORD dwWritten;
    WriteConsole(hConsole, buffer, _tcslen(buffer), &dwWritten, NULL);
#endif
#ifdef _DEBUG_FILE
    if(debug) {
        _ftprintf(debug, _T("%s"), buffer);
    }
#endif
    va_end(ap);
#endif
}

void EMU::out_message(const _TCHAR* format)
{
    qDebug(format);
    return;
}

emu.h

/*
	Skelton for retropc emulator

    QT Version : tanam
	Date   : 2013.05.18 -

    [ QT emulation i/f ]

*/

#ifndef _EMU_H_
#define _EMU_H_

#include <QApplication>
#include <QtCore>
#include <QtWidgets>
#include <QKeyEvent>
#include <QPainter>
#include <QTimer>
#include <windows.h>
#include "common.h"
#include "vm/vm.h"
#include "res/resource.h"
#include "config.h"
#include "fileio.h"

#ifndef WINDOW_WIDTH
#define WINDOW_WIDTH SCREEN_WIDTH
#endif
#ifndef WINDOW_HEIGHT
#define WINDOW_HEIGHT SCREEN_HEIGHT
#endif

#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define __assume exit

class EMU : public QWidget
{
    Q_OBJECT
protected:
    VM* vm;
    void paintEvent(QPaintEvent *);
    void keyPressEvent(QKeyEvent *);
    void keyReleaseEvent(QKeyEvent *);
    void mousePressEvent(QMouseEvent *);
protected slots:
    void onTimer();
private:
    QTimer *m_timer;
    int skip_frames;
    void ShowPopup();

    // ----------------------------------------
    // input
    // ----------------------------------------
    void initialize_input();
    void release_input();
    void update_input();
    uint8 key_status[256];	// windows key code mapping
    uint32 joy_status[3];	// joystick #1, #2 (b0 = up, b1 = down, b2 = left, b3 = right, b4- = buttons
    int joy_num;
    uint32 joy_mask[3];
    int mouse_status[3];	// x, y, button (b0 = left, b1 = right)
    bool mouse_enabled;

    // ----------------------------------------
    // screen
    // ----------------------------------------
    void initialize_screen();
    void release_screen();

    // screen settings
    int screen_width, screen_height;
    int window_width, window_height;

    // screen buffer
    unsigned char *scrbuf;

    // ----------------------------------------
    // sound
    // ----------------------------------------
    void initialize_sound();
    void release_sound();
    void update_sound(int* extra_frames);
    int sound_rate, sound_samples;
    bool sound_ok, sound_started, now_mute;

    // ----------------------------------------
    // media
    // ----------------------------------------
    typedef struct {
        _TCHAR path[_MAX_PATH];
        bool play;
        int offset;
        int wait_count;
    } media_status_t;

#ifdef USE_CART1
    media_status_t cart_status;
#endif
#ifdef USE_FD1
    media_status_t disk_status[8];
#endif
#ifdef USE_TAPE
    media_status_t tape_status;
#endif

    void initialize_media();
    void update_media();
    void restore_media();
    void clear_media_status(media_status_t *status) {
        status->path[0] = _T('\0');
        status->wait_count = 0;
    }

    // ----------------------------------------
    // printer
    // ----------------------------------------
    void initialize_printer();
    void release_printer();
    void reset_printer();
    void update_printer();

    FILEIO *prn_fio;
    int prn_data, prn_wait_frames;
    bool prn_strobe;

public:
    // ----------------------------------------
    // initialize
    // ----------------------------------------
    EMU(QWidget *parent = 0);
    ~EMU();
    _TCHAR app_path[_MAX_PATH];
    _TCHAR* application_path() {
        return app_path;
    }
    _TCHAR* bios_path(_TCHAR* file_name);
    // drive virtual machine
    int x;
    int y;
    int run();
    void reset();

    // user interface
#ifdef USE_CART1
    void open_cart(int drv, _TCHAR* file_path);
    void close_cart(int drv);
    bool cart_inserted(int drv);
#endif
#ifdef USE_FD1
    void open_disk(int drv, _TCHAR* file_path, int offset);
    void close_disk(int drv);
    bool disk_inserted(int drv);
#endif
#ifdef USE_TAPE
    void play_tape(_TCHAR* file_path);
    void rec_tape(_TCHAR* file_path);
    void close_tape();
    bool tape_inserted();
#endif

    // screen
    int get_window_width(int mode);
    int get_window_height(int mode);
    void draw_screen();

    // sound
    void mute_sound();

    // ----------------------------------------
    // for virtual machine
    // ----------------------------------------

    // input device
    uint8* key_buffer() {
        return key_status;
    }
    uint32* joy_buffer() {
        return joy_status;
    }
    int* mouse_buffer() {
        return mouse_status;
    }

    // screen
    scrntype* screen_buffer(int y);

    // printer
    void printer_out(uint8 value);
    void printer_strobe(bool value);

    // debug log
    void out_debug(const _TCHAR* format, ...);
    void out_message(const _TCHAR* format);
    void out_message(const _TCHAR* format, int){out_message(format);};
};

#endif

config.cpp

/*
	Skelton for retropc emulator

	Author : Takeda.Toshiya
	Date   : 2006.08.18 -

	[ config ]
*/

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include "config.h"

config_t config;
#ifndef WIN32
BOOL WritePrivateProfileString(LPCTSTR lpAppName, LPCTSTR lpKeyName, _TCHAR* String, LPCTSTR lpFileName)
{
    return false;
}

LPCTSTR GetModuleFileName(LPCTSTR a, LPCTSTR b, int c)
{
    return 0;
}

LPCTSTR GetPrivateProfileString(LPCTSTR a, LPCTSTR b, LPCTSTR c, LPCTSTR d, int e, LPCTSTR f)
{
    return 0;
}

int GetPrivateProfileInt(LPCTSTR lpAppName, LPCTSTR lpKeyName, int Value, LPCTSTR lpFileName)
{
    return -1;
}

int GetFullPathName(_TCHAR *config_path, int max_path, _TCHAR *app_path, _TCHAR **ptr) {
	int pt = _tcslen(app_path);
	while(pt >= 0 && app_path[pt] != _T('\\')) {
		pt--;
	}
	*ptr = &app_path[pt + 1];
}
#endif

BOOL WritePrivateProfileInt(LPCTSTR lpAppName, LPCTSTR lpKeyName, int Value, LPCTSTR lpFileName)
{
	_TCHAR String[32];
	_stprintf(String, _T("%d"), Value);
	return WritePrivateProfileString(lpAppName, lpKeyName, String, lpFileName);
}

(省略)

fileio.cpp

/*
	Skelton for retropc emulator

	Author : Takeda.Toshiya
	Date   : 2006.08.18 -

	[ file i/o ]
*/

#include "fileio.h"

#ifndef WIN32
#define FILE_ATTRIBUTE_DIRECTORY -1
#define FILE_ATTRIBUTE_READONLY -1

DWORD GetFileAttributes(_TCHAR *filename) {
	return -1;
}

void DeleteFile(_TCHAR *filename) {
	return;
}
#endif

FILEIO::FILEIO()
{
	fp = NULL;
}

(省略)

vm/fmgen/file.cpp

//	$Id: file.cpp,v 1.6 1999/12/28 11:14:05 cisc Exp $

#include "headers.h"
#include "file.h"
#ifndef WIN32
#define ERROR_FILE_NOT_FOUND		0
#define ERROR_SHARING_VIOLATION		1

HANDLE CreateFile(const _TCHAR* filename, DWORD access, DWORD share, int a, DWORD creation, int b, int c) {
	return NULL;
}

void CloseHandle(HANDLE hfile) {
	return;
}

int GetLastError(void) {
	return 0;
}

int32 ReadFile(HANDLE hfile, const void *dest, int32 size, DWORD* readsize, int a) {
	return 0;
}

int32 WriteFile(HANDLE hfile, const void *dest, int32 size, DWORD* writtensize, int a) {
	return 0;
}

int32 SetFilePointer(HANDLE hfile, int32 pos, int a, DWORD wmethod) {
	return 0;
}

int32 SetEndOfFile(HANDLE hfile) {
	return 0;
}
#endif

// ---------------------------------------------------------------------------
//	構築/消滅
// ---------------------------------------------------------------------------

FileIO::FileIO()
{
	flags = 0;
}

(省略)