mirror of
https://github.com/libretro/gambatte-libretro.git
synced 2024-11-23 07:49:48 +00:00
Initial commit.
git-svn-id: https://gambatte.svn.sourceforge.net/svnroot/gambatte@3 9dfb2916-2d38-0410-aef4-c5fe6c9ffc24
This commit is contained in:
parent
8700ab170f
commit
f30f14130d
5
gambatte_qt/gambatte_qt.pro
Normal file
5
gambatte_qt/gambatte_qt.pro
Normal file
@ -0,0 +1,5 @@
|
||||
SUBDIRS += src
|
||||
TEMPLATE = subdirs
|
||||
CONFIG += warn_on \
|
||||
qt \
|
||||
thread
|
25
gambatte_qt/src/addaudioengines.cpp
Normal file
25
gambatte_qt/src/addaudioengines.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "addaudioengines.h"
|
||||
|
||||
#include "audioengines/aoengine.h"
|
||||
|
||||
void addAudioEngines(std::vector<AudioEngine*> &audioEngines, const unsigned long /*winId*/) {
|
||||
audioEngines.push_back(new AoEngine);
|
||||
}
|
28
gambatte_qt/src/addaudioengines.h
Normal file
28
gambatte_qt/src/addaudioengines.h
Normal file
@ -0,0 +1,28 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef ADD_AUDIO_ENGINES_H
|
||||
#define ADD_AUDIO_ENGINES_H
|
||||
|
||||
class AudioEngine;
|
||||
|
||||
#include <vector>
|
||||
|
||||
void addAudioEngines(std::vector<AudioEngine*> &audioEngines, unsigned long winId);
|
||||
|
||||
#endif
|
27
gambatte_qt/src/addaudioengines_linux.cpp
Normal file
27
gambatte_qt/src/addaudioengines_linux.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "addaudioengines.h"
|
||||
|
||||
#include "audioengines/alsaengine.h"
|
||||
#include "audioengines/ossengine.h"
|
||||
|
||||
void addAudioEngines(std::vector<AudioEngine*> &audioEngines, const unsigned long /*winId*/) {
|
||||
audioEngines.push_back(new OssEngine);
|
||||
audioEngines.push_back(new AlsaEngine);
|
||||
}
|
25
gambatte_qt/src/addaudioengines_unix.cpp
Normal file
25
gambatte_qt/src/addaudioengines_unix.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "addaudioengines.h"
|
||||
|
||||
#include "audioengines/ossengine.h"
|
||||
|
||||
void addAudioEngines(std::vector<AudioEngine*> &audioEngines, const unsigned long /*winId*/) {
|
||||
audioEngines.push_back(new OssEngine);
|
||||
}
|
25
gambatte_qt/src/addaudioengines_win32.cpp
Normal file
25
gambatte_qt/src/addaudioengines_win32.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "addaudioengines.h"
|
||||
|
||||
#include "audioengines/directsoundengine.h"
|
||||
|
||||
void addAudioEngines(std::vector<AudioEngine*> &audioEngines, const unsigned long winId) {
|
||||
audioEngines.push_back(new DirectSoundEngine(winId));
|
||||
}
|
21
gambatte_qt/src/addblitterwidgets.cpp
Normal file
21
gambatte_qt/src/addblitterwidgets.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "addblitterwidgets.h"
|
||||
|
||||
void addBlitterWidgets(std::vector<BlitterWidget*> &/*blitters*/, VideoBufferReseter &/*resetVideoBuffer*/) {}
|
29
gambatte_qt/src/addblitterwidgets.h
Normal file
29
gambatte_qt/src/addblitterwidgets.h
Normal file
@ -0,0 +1,29 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef ADD_BLITTER_WIDGETS_H
|
||||
#define ADD_BLITTER_WIDGETS_H
|
||||
|
||||
class BlitterWidget;
|
||||
class VideoBufferReseter;
|
||||
|
||||
#include <vector>
|
||||
|
||||
void addBlitterWidgets(std::vector<BlitterWidget*> &blitters, VideoBufferReseter &resetVideoBuffer);
|
||||
|
||||
#endif
|
27
gambatte_qt/src/addblitterwidgets_unix.cpp
Normal file
27
gambatte_qt/src/addblitterwidgets_unix.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "addblitterwidgets.h"
|
||||
|
||||
#include "blitterwidgets/x11blitter.h"
|
||||
#include "blitterwidgets/xvblitter.h"
|
||||
|
||||
void addBlitterWidgets(std::vector<BlitterWidget*> &blitters, VideoBufferReseter &resetVideoBuffer) {
|
||||
blitters.push_back(new X11Blitter(resetVideoBuffer));
|
||||
blitters.push_back(new XvBlitter);
|
||||
}
|
25
gambatte_qt/src/addblitterwidgets_win32.cpp
Normal file
25
gambatte_qt/src/addblitterwidgets_win32.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "addblitterwidgets.h"
|
||||
|
||||
#include "blitterwidgets/directdrawblitter.h"
|
||||
|
||||
void addBlitterWidgets(std::vector<BlitterWidget*> &blitters, VideoBufferReseter &resetVideoBuffer) {
|
||||
blitters.push_back(new DirectDrawBlitter(resetVideoBuffer));
|
||||
}
|
37
gambatte_qt/src/audioengine.h
Normal file
37
gambatte_qt/src/audioengine.h
Normal file
@ -0,0 +1,37 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef AUDIOENGINE_H
|
||||
#define AUDIOENGINE_H
|
||||
|
||||
class AudioEngine {
|
||||
public:
|
||||
struct BufferState {
|
||||
unsigned fromUnderrun;
|
||||
unsigned fromOverflow;
|
||||
};
|
||||
|
||||
virtual ~AudioEngine() {}
|
||||
virtual int init() = 0;
|
||||
virtual void uninit() {}
|
||||
virtual int write(void *buffer, unsigned samples) = 0;
|
||||
virtual const BufferState bufferState() const { static const BufferState s = { 0xFFFFFFFF, 0xFFFFFFFF }; return s; }
|
||||
virtual void pause() {}
|
||||
};
|
||||
|
||||
#endif
|
142
gambatte_qt/src/audioengines/alsaengine.cpp
Normal file
142
gambatte_qt/src/audioengines/alsaengine.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "alsaengine.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
AlsaEngine::AlsaEngine() : pcm_handle(NULL) {}
|
||||
|
||||
AlsaEngine::~AlsaEngine() {
|
||||
uninit();
|
||||
}
|
||||
|
||||
int AlsaEngine::init() {
|
||||
unsigned rate = 48000;
|
||||
|
||||
if (snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, 0) < 0) {
|
||||
fprintf(stderr, "Error opening PCM device %s\n", "default");
|
||||
pcm_handle = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
{
|
||||
snd_pcm_hw_params_t *hwparams;
|
||||
snd_pcm_hw_params_alloca(&hwparams);
|
||||
|
||||
if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
|
||||
fprintf(stderr, "Can not configure this PCM device.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
|
||||
fprintf(stderr, "Error setting access.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
{
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
const snd_pcm_format_t format = SND_PCM_FORMAT_S16_BE;
|
||||
#else
|
||||
const snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
|
||||
#endif
|
||||
if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) < 0) {
|
||||
fprintf(stderr, "Error setting format.\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &rate, 0) < 0) {
|
||||
fprintf(stderr, "Error setting rate.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2) < 0) {
|
||||
fprintf(stderr, "Error setting channels.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*if (snd_pcm_hw_params_set_periods(pcm_handle, hwparams, 2, 0) < 0) {
|
||||
fprintf(stderr, "Error setting periods.\n");
|
||||
goto fail;
|
||||
}*/
|
||||
|
||||
{
|
||||
snd_pcm_uframes_t periodSize = ((rate * 4389) / 262144) + 1 << 1;
|
||||
|
||||
periodSize |= periodSize >> 1;
|
||||
periodSize |= periodSize >> 2;
|
||||
periodSize |= periodSize >> 4;
|
||||
periodSize |= periodSize >> 8;
|
||||
periodSize |= periodSize >> 16;
|
||||
++periodSize;
|
||||
|
||||
snd_pcm_uframes_t bSize = periodSize * 2;
|
||||
|
||||
if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &periodSize, 0) < 0) {
|
||||
fprintf(stderr, "Error setting period size %lu.\n", static_cast<unsigned long>(periodSize));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &bSize) < 0) {
|
||||
fprintf(stderr, "Error setting buffer size %u.\n", bufSize);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bufSize = bSize;
|
||||
}
|
||||
|
||||
if (snd_pcm_hw_params(pcm_handle, hwparams) < 0) {
|
||||
fprintf(stderr, "Error setting HW params.\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return rate;
|
||||
|
||||
fail:
|
||||
uninit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
void AlsaEngine::uninit() {
|
||||
if (pcm_handle)
|
||||
snd_pcm_close(pcm_handle);
|
||||
|
||||
pcm_handle = NULL;
|
||||
}
|
||||
|
||||
int AlsaEngine::write(void *const buffer, const unsigned samples) {
|
||||
while (snd_pcm_writei(pcm_handle, buffer, samples) < 0) {
|
||||
snd_pcm_prepare(pcm_handle);
|
||||
// fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const AudioEngine::BufferState AlsaEngine::bufferState() const {
|
||||
const snd_pcm_sframes_t avail = snd_pcm_avail_update(pcm_handle);
|
||||
|
||||
BufferState s = { bufSize - avail, avail };
|
||||
|
||||
if (avail < 0)
|
||||
s.fromOverflow = s.fromUnderrun = bufSize;
|
||||
|
||||
return s;
|
||||
}
|
38
gambatte_qt/src/audioengines/alsaengine.h
Normal file
38
gambatte_qt/src/audioengines/alsaengine.h
Normal file
@ -0,0 +1,38 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef ALSAENGINE_H
|
||||
#define ALSAENGINE_H
|
||||
|
||||
#include "../audioengine.h"
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
class AlsaEngine : public AudioEngine {
|
||||
snd_pcm_t *pcm_handle;
|
||||
unsigned bufSize;
|
||||
|
||||
public:
|
||||
AlsaEngine();
|
||||
~AlsaEngine();
|
||||
int init();
|
||||
void uninit();
|
||||
int write(void *buffer, unsigned samples);
|
||||
const BufferState bufferState() const;
|
||||
};
|
||||
|
||||
#endif
|
65
gambatte_qt/src/audioengines/aoengine.cpp
Normal file
65
gambatte_qt/src/audioengines/aoengine.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "aoengine.h"
|
||||
|
||||
AoEngine::AoEngine() : aoDevice(NULL) {}
|
||||
|
||||
AoEngine::~AoEngine() {
|
||||
uninit();
|
||||
}
|
||||
|
||||
int AoEngine::init() {
|
||||
ao_initialize();
|
||||
|
||||
aoDevice = NULL;
|
||||
|
||||
ao_sample_format sampleFormat = { 16, 48000, 2, AO_FMT_NATIVE };
|
||||
|
||||
int aoDriverId = ao_default_driver_id();
|
||||
|
||||
if (aoDriverId != -1) {
|
||||
if ((aoDevice = ao_open_live(aoDriverId, &sampleFormat, NULL)) == NULL) {
|
||||
sampleFormat.rate = 44100;
|
||||
aoDevice = ao_open_live(aoDriverId, &sampleFormat, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (aoDevice == NULL) {
|
||||
ao_shutdown();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sampleFormat.rate;
|
||||
}
|
||||
|
||||
void AoEngine::uninit() {
|
||||
if (aoDevice) {
|
||||
ao_close(aoDevice);
|
||||
aoDevice = NULL;
|
||||
|
||||
ao_shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
int AoEngine::write(void *const buffer, const unsigned samples) {
|
||||
if (ao_play(aoDevice, reinterpret_cast<char*>(buffer), samples * 4) == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
37
gambatte_qt/src/audioengines/aoengine.h
Normal file
37
gambatte_qt/src/audioengines/aoengine.h
Normal file
@ -0,0 +1,37 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef AOENGINE_H
|
||||
#define AOENGINE_H
|
||||
|
||||
#include "../audioengine.h"
|
||||
|
||||
#include <ao/ao.h>
|
||||
|
||||
class AoEngine : public AudioEngine {
|
||||
ao_device *aoDevice;
|
||||
|
||||
public:
|
||||
AoEngine();
|
||||
~AoEngine();
|
||||
int init();
|
||||
void uninit();
|
||||
int write(void *buffer, unsigned samples);
|
||||
};
|
||||
|
||||
#endif
|
193
gambatte_qt/src/audioengines/directsoundengine.cpp
Normal file
193
gambatte_qt/src/audioengines/directsoundengine.cpp
Normal file
@ -0,0 +1,193 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "directsoundengine.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
DirectSoundEngine::DirectSoundEngine(HWND hwnd_in) : lpDS(NULL), lpDSB(NULL), hwnd(hwnd_in) {}
|
||||
|
||||
DirectSoundEngine::~DirectSoundEngine() {
|
||||
uninit();
|
||||
}
|
||||
|
||||
int DirectSoundEngine::init() {
|
||||
unsigned rate = 48000;
|
||||
|
||||
if (DirectSoundCreate(NULL, &lpDS, NULL) != DS_OK) {
|
||||
lpDS = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (lpDS->SetCooperativeLevel(hwnd, DSSCL_PRIORITY) != DS_OK)
|
||||
goto fail;
|
||||
|
||||
{
|
||||
DSBUFFERDESC dsbd;
|
||||
memset(&dsbd, 0, sizeof(dsbd));
|
||||
dsbd.dwSize = sizeof(dsbd);
|
||||
|
||||
{
|
||||
int bufferSize = (((rate * 4389) / 262144) + 1) * 8 * 4;
|
||||
|
||||
bufferSize |= bufferSize >> 1;
|
||||
bufferSize |= bufferSize >> 2;
|
||||
bufferSize |= bufferSize >> 4;
|
||||
bufferSize |= bufferSize >> 8;
|
||||
bufferSize |= bufferSize >> 16;
|
||||
++bufferSize;
|
||||
|
||||
if (bufferSize < DSBSIZE_MIN)
|
||||
bufferSize = DSBSIZE_MIN;
|
||||
|
||||
if (bufferSize > DSBSIZE_MAX)
|
||||
bufferSize = DSBSIZE_MAX;
|
||||
|
||||
dsbd.dwBufferBytes = bufSize = bufferSize;
|
||||
}
|
||||
|
||||
WAVEFORMATEX wfe;
|
||||
memset(&wfe, 0, sizeof(wfe));
|
||||
wfe.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfe.nChannels = 2;
|
||||
wfe.nSamplesPerSec = rate;
|
||||
wfe.wBitsPerSample = 16;
|
||||
wfe.nBlockAlign = wfe.nChannels * wfe.wBitsPerSample >> 3;
|
||||
wfe.nAvgBytesPerSec = rate * wfe.nBlockAlign;
|
||||
|
||||
dsbd.lpwfxFormat = &wfe;
|
||||
|
||||
{
|
||||
GUID guidNULL;
|
||||
memset(&guidNULL,0,sizeof(GUID));
|
||||
dsbd.guid3DAlgorithm = guidNULL;
|
||||
}
|
||||
|
||||
if (lpDS->CreateSoundBuffer(&dsbd, &lpDSB, NULL) != DS_OK) {
|
||||
rate = 44100;
|
||||
wfe.nSamplesPerSec = rate;
|
||||
wfe.nAvgBytesPerSec = rate * wfe.nBlockAlign;
|
||||
|
||||
if (lpDS->CreateSoundBuffer(&dsbd, &lpDSB, NULL) != DS_OK) {
|
||||
lpDSB = NULL;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rate;
|
||||
|
||||
fail:
|
||||
uninit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
void DirectSoundEngine::uninit() {
|
||||
if (lpDSB) {
|
||||
lpDSB->Stop();
|
||||
lpDSB->Release();
|
||||
}
|
||||
|
||||
lpDSB = NULL;
|
||||
|
||||
if (lpDS)
|
||||
lpDS->Release();
|
||||
|
||||
lpDS = NULL;
|
||||
}
|
||||
|
||||
int DirectSoundEngine::write(void *const buffer, const unsigned frames) {
|
||||
DWORD status;
|
||||
lpDSB->GetStatus(&status);
|
||||
|
||||
if (status & DSBSTATUS_BUFFERLOST) {
|
||||
lpDSB->Restore();
|
||||
status &= ~DSBSTATUS_PLAYING;
|
||||
}
|
||||
|
||||
if (!(status & DSBSTATUS_PLAYING)) {
|
||||
std:: cout << "notplaying" << std::endl;
|
||||
offset = bufSize >> 1;
|
||||
lpDSB->SetCurrentPosition(0);
|
||||
} else for (DWORD pc, wc;;) {
|
||||
if (lpDSB->GetCurrentPosition(&pc, &wc) != DS_OK)
|
||||
return -1;
|
||||
|
||||
//std::cout << "wc-pc: " << ((wc < pc ? bufSize : 0) + wc - pc) << std::endl;
|
||||
if (offset > pc && offset < wc) {
|
||||
std::cout << "underrun" << std::endl;
|
||||
offset = wc;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((pc < offset ? bufSize : 0) + pc - offset >= frames * 4)
|
||||
break;
|
||||
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
{
|
||||
LPVOID ptr1;
|
||||
LPVOID ptr2;
|
||||
DWORD bytes1;
|
||||
DWORD bytes2;
|
||||
|
||||
if (lpDSB->Lock(offset, frames * 4, &ptr1, &bytes1, &ptr2, &bytes2, 0) != DS_OK)
|
||||
return 0;
|
||||
|
||||
memcpy(ptr1, buffer, bytes1);
|
||||
|
||||
if (ptr2) {
|
||||
memcpy(ptr2, static_cast<char*>(buffer) + bytes1, bytes2);
|
||||
}
|
||||
|
||||
lpDSB->Unlock(ptr1, bytes1, ptr2, bytes2);
|
||||
}
|
||||
|
||||
if ((offset += frames * 4) >= bufSize)
|
||||
offset -= bufSize;
|
||||
|
||||
if (!(status & DSBSTATUS_PLAYING)) {
|
||||
lpDSB->Play(0, 0, DSBPLAY_LOOPING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const AudioEngine::BufferState DirectSoundEngine::bufferState() const {
|
||||
BufferState s;
|
||||
DWORD pc, wc;
|
||||
|
||||
if (lpDSB->GetCurrentPosition(&pc, &wc) != DS_OK) {
|
||||
s.fromOverflow = s.fromUnderrun = bufSize >> 2;
|
||||
} else if (offset > pc && offset < wc) {
|
||||
s.fromUnderrun = 0;
|
||||
s.fromOverflow = bufSize >> 2;
|
||||
} else {
|
||||
s.fromUnderrun = (offset < wc ? bufSize : 0) + offset - wc >> 2;
|
||||
s.fromOverflow = (pc < offset ? bufSize : 0) + pc - offset >> 2;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void DirectSoundEngine::pause() {
|
||||
if (lpDSB) {
|
||||
lpDSB->Stop();
|
||||
}
|
||||
}
|
43
gambatte_qt/src/audioengines/directsoundengine.h
Normal file
43
gambatte_qt/src/audioengines/directsoundengine.h
Normal file
@ -0,0 +1,43 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef DIRECTSOUNDENGINE_H
|
||||
#define DIRECTSOUNDENGINE_H
|
||||
|
||||
#include "../audioengine.h"
|
||||
|
||||
#include <dsound.h>
|
||||
|
||||
class DirectSoundEngine : public AudioEngine {
|
||||
LPDIRECTSOUND lpDS;
|
||||
LPDIRECTSOUNDBUFFER lpDSB;
|
||||
unsigned bufSize;
|
||||
DWORD offset;
|
||||
HWND hwnd;
|
||||
|
||||
public:
|
||||
DirectSoundEngine(HWND hwnd);
|
||||
~DirectSoundEngine();
|
||||
int init();
|
||||
void uninit();
|
||||
int write(void *buffer, unsigned frames);
|
||||
const BufferState bufferState() const;
|
||||
void pause();
|
||||
};
|
||||
|
||||
#endif
|
130
gambatte_qt/src/audioengines/ossengine.cpp
Normal file
130
gambatte_qt/src/audioengines/ossengine.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "ossengine.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/soundcard.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
OssEngine::OssEngine() : audio_fd(-1) {}
|
||||
|
||||
OssEngine::~OssEngine() {
|
||||
uninit();
|
||||
}
|
||||
|
||||
int OssEngine::init() {
|
||||
int speed = 48000;
|
||||
|
||||
if ((audio_fd = open("/dev/dsp", O_WRONLY, 0)) == -1) {
|
||||
perror("/dev/dsp");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
{
|
||||
int format = AFMT_S16_NE;
|
||||
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format) == -1) {
|
||||
perror("SNDCTL_DSP_SETFMT");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (format != AFMT_S16_NE) {
|
||||
printf("oss-sound: unsupported format\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int channels = 2;
|
||||
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
|
||||
perror("SNDCTL_DSP_CHANNELS");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (channels != 2) {
|
||||
printf("oss-sound: unsupported number of channels\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed) == -1) {
|
||||
perror("SNDCTL_DSP_SPEED");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
{
|
||||
const int bytes = (((speed * 4389) / 262144) + 1) * 4;
|
||||
int arg = 0x00040000 | std::min(static_cast<int>(log2(static_cast<float>(bytes))) + 1, 0xFFFF);
|
||||
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &arg) == -1) {
|
||||
perror("SNDCTL_DSP_SETFRAGMENT");
|
||||
// goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
audio_buf_info info;
|
||||
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) == -1) {
|
||||
perror("SNDCTL_DSP_GETOSPACE");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bufSize = (info.fragstotal * info.fragsize) >> 2;
|
||||
}
|
||||
|
||||
return speed;
|
||||
|
||||
fail:
|
||||
uninit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
void OssEngine::uninit() {
|
||||
if (audio_fd != -1)
|
||||
close(audio_fd);
|
||||
|
||||
audio_fd = -1;
|
||||
}
|
||||
|
||||
int OssEngine::write(void *const buffer, const unsigned samples) {
|
||||
if (::write(audio_fd, buffer, samples * 4) != static_cast<int>(samples * 4))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const AudioEngine::BufferState OssEngine::bufferState() const {
|
||||
BufferState s;
|
||||
audio_buf_info info;
|
||||
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) == -1 || info.bytes < 0) {
|
||||
s.fromOverflow = s.fromUnderrun = bufSize;
|
||||
} else {
|
||||
s.fromUnderrun = bufSize - (info.bytes >> 2);
|
||||
s.fromOverflow = info.bytes >> 2;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
37
gambatte_qt/src/audioengines/ossengine.h
Normal file
37
gambatte_qt/src/audioengines/ossengine.h
Normal file
@ -0,0 +1,37 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef OSSENGINE_H
|
||||
#define OSSENGINE_H
|
||||
|
||||
#include "../audioengine.h"
|
||||
|
||||
class OssEngine : public AudioEngine {
|
||||
int audio_fd;
|
||||
unsigned bufSize;
|
||||
|
||||
public:
|
||||
OssEngine();
|
||||
~OssEngine();
|
||||
int init();
|
||||
void uninit();
|
||||
int write(void *buffer, unsigned samples);
|
||||
const BufferState bufferState() const;
|
||||
};
|
||||
|
||||
#endif
|
90
gambatte_qt/src/blittercontainer.cpp
Normal file
90
gambatte_qt/src/blittercontainer.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "blittercontainer.h"
|
||||
|
||||
#include "blitterwidget.h"
|
||||
#include "fullrestoggler.h"
|
||||
#include <QResizeEvent>
|
||||
|
||||
BlitterContainer::BlitterContainer(const FullResToggler &resToggler_in, QWidget *parent) :
|
||||
QWidget(parent),
|
||||
resToggler(resToggler_in),
|
||||
blitter(NULL)
|
||||
{
|
||||
QPalette pal = palette();
|
||||
pal.setColor(QPalette::Window, QColor(0, 0, 0));
|
||||
setPalette(pal);
|
||||
// setBackgroundRole(QPalette::Window);
|
||||
setAutoFillBackground(true);
|
||||
}
|
||||
|
||||
BlitterContainer::~BlitterContainer()
|
||||
{}
|
||||
|
||||
void BlitterContainer::doLayout(const int w, const int h) {
|
||||
if (!blitter)
|
||||
return;
|
||||
|
||||
if (blitter->keepsAspectRatio() && !blitter->selfScaling) {
|
||||
if (blitter->scalesByInteger()) {
|
||||
const int scale = std::min(w / minimumWidth(), h / minimumHeight());
|
||||
const int new_w = minimumWidth() * scale;
|
||||
const int new_h = minimumHeight() * scale;
|
||||
blitter->setGeometry(w - new_w >> 1, h - new_h >> 1, new_w, new_h);
|
||||
} else {
|
||||
if (w * 9 > h * 10) {
|
||||
const int new_w = (h * 20 + 9) / 18;
|
||||
blitter->setGeometry(w - new_w >> 1, 0, new_w, h);
|
||||
} else {
|
||||
const int new_h = (w * 9 + 5) / 10;
|
||||
blitter->setGeometry(0, h - new_h >> 1, w, new_h);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
blitter->setGeometry(0, 0, w, h);
|
||||
}
|
||||
|
||||
if (!resToggler.resVector().empty()) {
|
||||
const ResInfo &res = resToggler.resVector()[resToggler.currentResIndex()];
|
||||
blitter->setExclusive(res.w == static_cast<unsigned>(w) && res.h == static_cast<unsigned>(h));
|
||||
}
|
||||
}
|
||||
|
||||
void BlitterContainer::setBlitter(BlitterWidget *const blitter_in) {
|
||||
if (blitter)
|
||||
blitter->setParent(0);
|
||||
|
||||
blitter = blitter_in;
|
||||
|
||||
if (blitter) {
|
||||
blitter->setParent(this);
|
||||
updateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
void BlitterContainer::resizeEvent(QResizeEvent *const event) {
|
||||
doLayout(event->size().width(), event->size().height());
|
||||
}
|
||||
|
||||
void BlitterContainer::hideEvent(QHideEvent *const event) {
|
||||
if (blitter)
|
||||
blitter->setExclusive(false);
|
||||
|
||||
QWidget::hideEvent(event);
|
||||
}
|
44
gambatte_qt/src/blittercontainer.h
Normal file
44
gambatte_qt/src/blittercontainer.h
Normal file
@ -0,0 +1,44 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef BLITTERCONTAINER_H
|
||||
#define BLITTERCONTAINER_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class BlitterWidget;
|
||||
class FullResToggler;
|
||||
|
||||
class BlitterContainer : public QWidget {
|
||||
const FullResToggler &resToggler;
|
||||
BlitterWidget *blitter;
|
||||
|
||||
void doLayout(int w, int h);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
void hideEvent(QHideEvent *event);
|
||||
|
||||
public:
|
||||
BlitterContainer(const FullResToggler &fullResToggler, QWidget *parent = 0);
|
||||
~BlitterContainer();
|
||||
void setBlitter(BlitterWidget *blitter);
|
||||
void updateLayout() { doLayout(width(), height()); }
|
||||
};
|
||||
|
||||
#endif
|
85
gambatte_qt/src/blitterwidget.cpp
Normal file
85
gambatte_qt/src/blitterwidget.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "blitterwidget.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
// #include <time.h>
|
||||
|
||||
const BlitterWidget::Rational BlitterWidget::frameTime() const {
|
||||
Rational r = { 16743, 1000000 };
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int BlitterWidget::sync(const bool turbo) {
|
||||
if (turbo)
|
||||
return 0;
|
||||
|
||||
timeval t;
|
||||
gettimeofday(&t, NULL);
|
||||
static timeval time = t;
|
||||
static long late = 0;
|
||||
static unsigned noSleep = 60;
|
||||
|
||||
if (time.tv_sec > t.tv_sec || (time.tv_sec == t.tv_sec && time.tv_usec > t.tv_usec)) {
|
||||
timeval tmp;
|
||||
tmp.tv_sec = 0;
|
||||
tmp.tv_usec = time.tv_usec - t.tv_usec;
|
||||
if (time.tv_sec != t.tv_sec)
|
||||
tmp.tv_usec += 1000000;
|
||||
|
||||
if (tmp.tv_usec > late) {
|
||||
tmp.tv_usec -= late;
|
||||
|
||||
if (tmp.tv_usec >= 1000000) {
|
||||
tmp.tv_usec -= 1000000;
|
||||
++tmp.tv_sec;
|
||||
}
|
||||
|
||||
timespec tspec = { tmp.tv_sec, tmp.tv_usec * 1000 };
|
||||
nanosleep(&tspec, NULL);
|
||||
|
||||
gettimeofday(&t, NULL);
|
||||
late -= (time.tv_sec - t.tv_sec) * 1000000 + time.tv_usec - t.tv_usec >> 1;
|
||||
// printf("late: %d\n", late);
|
||||
|
||||
if (late < 0)
|
||||
late = 0;
|
||||
|
||||
noSleep = 60;
|
||||
} else if (noSleep-- == 0) {
|
||||
noSleep = 60;
|
||||
late = 0;
|
||||
}
|
||||
|
||||
while (time.tv_sec > t.tv_sec || (time.tv_sec == t.tv_sec && time.tv_usec > t.tv_usec)) {
|
||||
gettimeofday(&t, NULL);
|
||||
}
|
||||
} else
|
||||
time = t; //quickfix:catches up to current time (The GUI tends to pause the run loop, so this function doesn't get called)
|
||||
|
||||
time.tv_usec += 16743;
|
||||
|
||||
if (time.tv_usec >= 1000000) {
|
||||
time.tv_usec -= 1000000;
|
||||
++time.tv_sec;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
69
gambatte_qt/src/blitterwidget.h
Normal file
69
gambatte_qt/src/blitterwidget.h
Normal file
@ -0,0 +1,69 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef BLITTERWIDGET_H
|
||||
#define BLITTERWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <videoblitter.h>
|
||||
#include <QString>
|
||||
|
||||
class QHBoxLayout;
|
||||
|
||||
class BlitterWidget : public QWidget, public VideoBlitter {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
struct Rational {
|
||||
unsigned numerator;
|
||||
unsigned denominator;
|
||||
};
|
||||
|
||||
const QString nameString;
|
||||
const bool integerOnlyScaler;
|
||||
const bool selfScaling;
|
||||
|
||||
BlitterWidget(const QString &name, bool integerOnlyScaler_in = false, bool selfScaling_in = false, QWidget *parent = 0) :
|
||||
QWidget(parent),
|
||||
nameString(name),
|
||||
integerOnlyScaler(integerOnlyScaler_in),
|
||||
selfScaling(selfScaling_in)
|
||||
{}
|
||||
|
||||
virtual void init() {}
|
||||
virtual void uninit() {}
|
||||
virtual bool isUnusable() { return false; }
|
||||
virtual void keepAspectRatio(const bool enable) = 0;
|
||||
virtual bool keepsAspectRatio() = 0;
|
||||
virtual void scaleByInteger(const bool enable) = 0;
|
||||
virtual bool scalesByInteger() = 0;
|
||||
virtual const Rational frameTime() const;
|
||||
virtual int sync(bool turbo);
|
||||
virtual QWidget* settingsWidget() { return NULL; }
|
||||
virtual void setExclusive(bool) {}
|
||||
|
||||
// public slots:
|
||||
virtual void acceptSettings() {}
|
||||
virtual void rejectSettings() {}
|
||||
|
||||
public slots:
|
||||
virtual void rateChange(int /*newHz*/) {}
|
||||
// virtual void modeChange() {}
|
||||
};
|
||||
|
||||
#endif
|
71
gambatte_qt/src/blitterwidget_win32.cpp
Normal file
71
gambatte_qt/src/blitterwidget_win32.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "blitterwidget.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
class Freq {
|
||||
LONGLONG value;
|
||||
|
||||
public:
|
||||
Freq() {
|
||||
LARGE_INTEGER li;
|
||||
QueryPerformanceFrequency(&li);
|
||||
value = li.QuadPart;
|
||||
}
|
||||
|
||||
LONGLONG get() const { return value; }
|
||||
};
|
||||
|
||||
const BlitterWidget::Rational BlitterWidget::frameTime() const {
|
||||
Rational r = { 16743, 1000000 };
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int BlitterWidget::sync(const bool turbo) {
|
||||
if (turbo)
|
||||
return 0;
|
||||
|
||||
static Freq freq;
|
||||
static const LONGLONG inc = (freq.get() * 16743) / 1000000;
|
||||
|
||||
LARGE_INTEGER t;
|
||||
QueryPerformanceCounter(&t);
|
||||
static LONGLONG time = t.QuadPart;
|
||||
|
||||
if (time > t.QuadPart) {
|
||||
{
|
||||
const DWORD tmp = ((time - t.QuadPart) * 1000) / freq.get();
|
||||
|
||||
if (tmp > 1) {
|
||||
Sleep(tmp - 1);
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
QueryPerformanceCounter(&t);
|
||||
} while (time > t.QuadPart);
|
||||
} else
|
||||
time = t.QuadPart; //quickfix:catches up to current time (The GUI tends to pause the run loop, so this function doesn't get called)
|
||||
|
||||
time += inc;
|
||||
|
||||
return 0;
|
||||
}
|
511
gambatte_qt/src/blitterwidgets/directdrawblitter.cpp
Normal file
511
gambatte_qt/src/blitterwidgets/directdrawblitter.cpp
Normal file
@ -0,0 +1,511 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "directdrawblitter.h"
|
||||
|
||||
#include "../videobufferreseter.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QSettings>
|
||||
#include <QVBoxLayout>
|
||||
#include <iostream>
|
||||
|
||||
DirectDrawBlitter::DirectDrawBlitter(VideoBufferReseter &resetVideoBuffer_in, QWidget *parent) :
|
||||
BlitterWidget("DirectDraw", parent),
|
||||
resetVideoBuffer(resetVideoBuffer_in),
|
||||
confWidget(new QWidget),
|
||||
vblankBox(new QCheckBox(QString("Sync to vertical blank in 60 Hz modes"))),
|
||||
flippingBox(new QCheckBox(QString("Page flipping"))),
|
||||
videoSurfaceBox(new QCheckBox(QString("Use video memory surface"))),
|
||||
lpDD(NULL),
|
||||
lpDDSPrimary(NULL),
|
||||
lpDDSSystem(NULL),
|
||||
lpDDSVideo(NULL),
|
||||
lpClipper(NULL),
|
||||
keepRatio(true),
|
||||
integerScaling(false),
|
||||
exclusive(false)
|
||||
{
|
||||
pixb.pixels = NULL;
|
||||
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||
setAttribute(Qt::WA_PaintOnScreen, true);
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("directdrawblitter");
|
||||
vblank = settings.value("vblank", false).toBool();
|
||||
flipping = settings.value("flipping", false).toBool();
|
||||
videoSurface = settings.value("videoSurface", true).toBool();
|
||||
settings.endGroup();
|
||||
|
||||
confWidget->setLayout(new QVBoxLayout);
|
||||
confWidget->layout()->setMargin(0);
|
||||
confWidget->layout()->addWidget(vblankBox);
|
||||
confWidget->layout()->addWidget(flippingBox);
|
||||
confWidget->layout()->addWidget(videoSurfaceBox);
|
||||
vblankBox->setChecked(vblank);
|
||||
flippingBox->setChecked(flipping);
|
||||
videoSurfaceBox->setChecked(videoSurface);
|
||||
}
|
||||
|
||||
DirectDrawBlitter::~DirectDrawBlitter() {
|
||||
uninit();
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("directdrawblitter");
|
||||
settings.setValue("vblank", vblank);
|
||||
settings.setValue("flipping", flipping);
|
||||
settings.setValue("videoSurface", videoSurface);
|
||||
settings.endGroup();
|
||||
|
||||
delete confWidget;
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::videoSurfaceBlit() {
|
||||
lpDDSSystem->PageLock(0);
|
||||
lpDDSVideo->PageLock(0);
|
||||
|
||||
HRESULT ddrval;
|
||||
ddrval = lpDDSVideo->BltFast(0, 0, lpDDSSystem, NULL, DDBLTFAST_WAIT);
|
||||
|
||||
if (ddrval == DDERR_SURFACELOST) {
|
||||
if (!restoreSurfaces())
|
||||
ddrval = lpDDSVideo->BltFast(0, 0, lpDDSSystem, NULL, DDBLTFAST_WAIT);
|
||||
}
|
||||
|
||||
if (ddrval != DD_OK) {
|
||||
std::cout << "lpDDSVideo->BltFast(0, 0, lpDDSSystem, NULL, DDBLTFAST_WAIT) failed" << std::endl;
|
||||
|
||||
if (lpDDSPrimary) {
|
||||
lpDDSPrimary->Release();
|
||||
lpDDSPrimary = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
lpDDSVideo->PageUnlock(0);
|
||||
lpDDSSystem->PageUnlock(0);
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::systemSurfaceBlit() {
|
||||
LPDIRECTDRAWSURFACE7 lpDDSTmp = lpDDSSystem;
|
||||
lpDDSSystem = lpDDSVideo;
|
||||
lpDDSVideo = lpDDSTmp;
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::blit() {
|
||||
if (!lpDDSPrimary)
|
||||
return;
|
||||
|
||||
lpDDSSystem->Unlock(NULL);
|
||||
|
||||
if (videoSurface)
|
||||
videoSurfaceBlit();
|
||||
else
|
||||
systemSurfaceBlit();
|
||||
|
||||
DDSURFACEDESC2 ddsd;
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
|
||||
if (lpDDSSystem->Lock(NULL, &ddsd, DDLOCK_NOSYSLOCK, NULL) != DD_OK)
|
||||
std::cout << "lpDDSSystem->Lock(NULL, &ddsd, DDLOCK_NOSYSLOCK, NULL) failed" << std::endl;
|
||||
|
||||
pixb.pixels = ddsd.lpSurface;
|
||||
pixb.pitch = pixb.format == PixelBuffer::RGB16 ? ddsd.lPitch >> 1 : (ddsd.lPitch >> 2);
|
||||
resetVideoBuffer();
|
||||
}
|
||||
|
||||
const PixelBuffer DirectDrawBlitter::inBuffer() {
|
||||
return pixb;
|
||||
}
|
||||
|
||||
bool DirectDrawBlitter::initPrimarySurface() {
|
||||
{
|
||||
DDSURFACEDESC2 ddsd;
|
||||
memset(&ddsd, 0, sizeof(ddsd));
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
ddsd.dwFlags = DDSD_CAPS;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
||||
|
||||
if (exclusive && flipping) {
|
||||
ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT;
|
||||
ddsd.dwBackBufferCount = 1;
|
||||
ddsd.ddsCaps.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_FLIP;
|
||||
}
|
||||
|
||||
HRESULT ddrval = lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL);
|
||||
lpDDSBack = lpDDSPrimary;
|
||||
|
||||
if (exclusive && flipping && ddrval == DD_OK) {
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
|
||||
ddrval = lpDDSPrimary->GetAttachedSurface(&ddsd.ddsCaps, &lpDDSBack);
|
||||
}
|
||||
|
||||
if (ddrval != DD_OK) {
|
||||
std::cout << "CreateSurface failed" << std::endl;
|
||||
lpDDSPrimary = NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (lpDDSPrimary->SetClipper(lpClipper) != DD_OK) {
|
||||
std::cout << "SetClipper failed" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DirectDrawBlitter::initVideoSurface() {
|
||||
DDSURFACEDESC2 ddsd;
|
||||
memset(&ddsd, 0, sizeof(ddsd));
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
lpDDSSystem->GetSurfaceDesc(&ddsd);
|
||||
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
||||
|
||||
if (!videoSurface)
|
||||
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
|
||||
|
||||
if (lpDD->CreateSurface(&ddsd, &lpDDSVideo, NULL) != DD_OK) {
|
||||
lpDDSVideo = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::init() {
|
||||
if (DirectDrawCreateEx(NULL, reinterpret_cast<void**>(&lpDD), IID_IDirectDraw7, NULL) != DD_OK) {
|
||||
std::cout << "DirectDrawCreateEx failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (lpDD->SetCooperativeLevel(GetParent(GetParent(winId())), (exclusive && flipping) ? DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN : DDSCL_NORMAL) != DD_OK) {
|
||||
std::cout << "SetCooperativeLevel failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (lpDD->CreateClipper(0, &lpClipper, NULL) != DD_OK) {
|
||||
std::cout << "CreateClipper failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (lpClipper->SetHWnd(0, winId()) != DD_OK) {
|
||||
std::cout << "SetHWnd failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (initPrimarySurface())
|
||||
goto fail;
|
||||
|
||||
DDPIXELFORMAT ddpf;
|
||||
ddpf.dwSize = sizeof(ddpf);
|
||||
|
||||
if (lpDDSPrimary->GetPixelFormat(&ddpf) == DD_OK && (ddpf.dwFlags & DDPF_RGB) && ddpf.dwRGBBitCount == 16) {
|
||||
pixb.format = PixelBuffer::RGB16;
|
||||
} else {
|
||||
pixb.format = PixelBuffer::RGB32;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
uninit();
|
||||
}
|
||||
|
||||
bool DirectDrawBlitter::restoreSurfaces() {
|
||||
lpDDSPrimary->Restore();
|
||||
lpDDSVideo->Restore();
|
||||
|
||||
if (lpDDSPrimary->IsLost() != DDERR_SURFACELOST && lpDDSVideo->IsLost() != DDERR_SURFACELOST)
|
||||
return false;
|
||||
|
||||
lpDDSPrimary->Release();
|
||||
|
||||
if (initPrimarySurface()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (videoSurface) {
|
||||
lpDDSVideo->Release();
|
||||
|
||||
if (initVideoSurface())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void setDdPf(DDPIXELFORMAT *const ddpf, const PixelBuffer::Format format) {
|
||||
memset(ddpf, 0, sizeof(DDPIXELFORMAT));
|
||||
ddpf->dwSize = sizeof(DDPIXELFORMAT);
|
||||
|
||||
if (format == PixelBuffer::RGB16) {
|
||||
ddpf->dwFlags = DDPF_RGB;
|
||||
ddpf->dwRGBBitCount = 16;
|
||||
ddpf->dwRGBAlphaBitMask = 0x0000;
|
||||
ddpf->dwRBitMask = 0xF800;
|
||||
ddpf->dwGBitMask = 0x07E0;
|
||||
ddpf->dwBBitMask = 0x001F;
|
||||
} else {
|
||||
ddpf->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
|
||||
ddpf->dwRGBBitCount = 32;
|
||||
ddpf->dwRGBAlphaBitMask = 0xFF000000;
|
||||
ddpf->dwRBitMask = 0x00FF0000;
|
||||
ddpf->dwGBitMask = 0x0000FF00;
|
||||
ddpf->dwBBitMask = 0x000000FF;
|
||||
}
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::setBufferDimensions(const unsigned int w, const unsigned int h) {
|
||||
if (lpDDSPrimary == NULL)
|
||||
return;
|
||||
|
||||
if (lpDDSSystem) {
|
||||
lpDDSSystem->Release();
|
||||
lpDDSSystem = NULL;
|
||||
}
|
||||
|
||||
if (lpDDSVideo) {
|
||||
lpDDSVideo->Release();
|
||||
lpDDSVideo = NULL;
|
||||
}
|
||||
|
||||
DDPIXELFORMAT ddpf;
|
||||
setDdPf(&ddpf, pixb.format);
|
||||
|
||||
DDSURFACEDESC2 ddsd;
|
||||
memset(&ddsd, 0, sizeof(ddsd));
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
||||
ddsd.dwWidth = w;
|
||||
ddsd.dwHeight = h;
|
||||
ddsd.ddpfPixelFormat = ddpf;
|
||||
|
||||
if (lpDD->CreateSurface(&ddsd, &lpDDSSystem, NULL) != DD_OK) {
|
||||
std::cout << "lpDD->CreateSurface(&ddsd, &lpDDSSystem, NULL) failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (videoSurface)
|
||||
ddsd.ddsCaps.dwCaps &= ~DDSCAPS_SYSTEMMEMORY;
|
||||
|
||||
if (lpDD->CreateSurface(&ddsd, &lpDDSVideo, NULL) != DD_OK) {
|
||||
std::cout << "lpDD->CreateSurface(&ddsd, &lpDDSVideo, NULL) failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (lpDDSSystem->Lock(NULL, &ddsd, DDLOCK_NOSYSLOCK, NULL) != DD_OK) {
|
||||
std::cout << "lpDDSSystem->Lock(NULL, &ddsd, DDLOCK_NOSYSLOCK, NULL) failed" << std::endl;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pixb.pixels = ddsd.lpSurface;
|
||||
pixb.pitch = pixb.format == PixelBuffer::RGB16 ? ddsd.lPitch >> 1 : (ddsd.lPitch >> 2);
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
uninit();
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::uninit() {
|
||||
if (lpClipper) {
|
||||
lpClipper->Release();
|
||||
lpClipper = NULL;
|
||||
}
|
||||
|
||||
if (lpDDSPrimary) {
|
||||
lpDDSPrimary->Release();
|
||||
lpDDSPrimary = NULL;
|
||||
}
|
||||
|
||||
if (lpDDSSystem) {
|
||||
lpDDSSystem->Release();
|
||||
lpDDSSystem = NULL;
|
||||
}
|
||||
|
||||
if (lpDDSVideo) {
|
||||
lpDDSVideo->Release();
|
||||
lpDDSVideo = NULL;
|
||||
}
|
||||
|
||||
if (lpDD) {
|
||||
lpDD->Release();
|
||||
lpDD = NULL;
|
||||
}
|
||||
|
||||
pixb.pixels = NULL;
|
||||
}
|
||||
|
||||
const BlitterWidget::Rational DirectDrawBlitter::frameTime() const {
|
||||
if (vblank && hz60) {
|
||||
Rational r = { 1, 60 };
|
||||
return r;
|
||||
}
|
||||
|
||||
return BlitterWidget::frameTime();
|
||||
}
|
||||
|
||||
int DirectDrawBlitter::sync(const bool turbo) {
|
||||
if (lpDDSPrimary == NULL)
|
||||
return -1;
|
||||
|
||||
lpDDSVideo->PageLock(0);
|
||||
|
||||
RECT rcRectDest;
|
||||
GetWindowRect(winId(), &rcRectDest);
|
||||
|
||||
if (!turbo) {
|
||||
if (vblank && hz60) {
|
||||
if (!(exclusive && flipping))
|
||||
lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0);
|
||||
} else
|
||||
BlitterWidget::sync(turbo);
|
||||
}
|
||||
|
||||
const bool dontwait = exclusive && flipping && !(vblank && hz60 && !turbo);
|
||||
|
||||
HRESULT ddrval = lpDDSBack->Blt(&rcRectDest, lpDDSVideo, NULL, dontwait ? DDBLT_DONOTWAIT : DDBLT_WAIT, NULL);
|
||||
|
||||
if (ddrval == DDERR_SURFACELOST) {
|
||||
if (!restoreSurfaces())
|
||||
ddrval = lpDDSBack->Blt(&rcRectDest, lpDDSVideo, NULL, dontwait ? DDBLT_DONOTWAIT : DDBLT_WAIT, NULL);
|
||||
}
|
||||
|
||||
lpDDSVideo->PageUnlock(0);
|
||||
|
||||
if (ddrval == DD_OK && exclusive && flipping) {
|
||||
ddrval = lpDDSPrimary->Flip(NULL, dontwait ? DDFLIP_DONOTWAIT : DDFLIP_WAIT);
|
||||
}
|
||||
|
||||
if (ddrval != DD_OK && ddrval != DDERR_WASSTILLDRAWING) {
|
||||
//std::cout << "lpDDSPrimary->Blt(&rcRectDest, lpDDSVideo, NULL, DDBLT_WAIT, NULL) failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::keepAspectRatio(const bool enable) {
|
||||
keepRatio = enable;
|
||||
}
|
||||
|
||||
bool DirectDrawBlitter::keepsAspectRatio() {
|
||||
return keepRatio;
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::scaleByInteger(const bool enable) {
|
||||
integerScaling = enable;
|
||||
}
|
||||
|
||||
bool DirectDrawBlitter::scalesByInteger() {
|
||||
return integerScaling;
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::acceptSettings() {
|
||||
vblank = vblankBox->isChecked();
|
||||
|
||||
if (flipping != flippingBox->isChecked()) {
|
||||
flipping = flippingBox->isChecked();
|
||||
|
||||
if (exclusive)
|
||||
reinit();
|
||||
}
|
||||
|
||||
if (videoSurface != videoSurfaceBox->isChecked()) {
|
||||
videoSurface = videoSurfaceBox->isChecked();
|
||||
|
||||
if (lpDDSVideo) {
|
||||
lpDDSVideo->Release();
|
||||
|
||||
if (initVideoSurface()) {
|
||||
lpDDSPrimary->Release();
|
||||
lpDDSPrimary = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::rejectSettings() {
|
||||
vblankBox->setChecked(vblank);
|
||||
flippingBox->setChecked(flipping);
|
||||
videoSurfaceBox->setChecked(videoSurface);
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::rateChange(int hz) {
|
||||
hz60 = hz == 60;
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::paintEvent(QPaintEvent */*event*/) {
|
||||
sync(true);
|
||||
}
|
||||
|
||||
/*void DirectDrawBlitter::detectExclusive() {
|
||||
if (!lpDD || !parentWidget())
|
||||
return;
|
||||
|
||||
DDSURFACEDESC2 ddsd;
|
||||
memset(&ddsd, 0, sizeof(ddsd));
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
lpDD->GetDisplayMode(&ddsd);
|
||||
|
||||
setExclusive(parentWidget()->width() == ddsd.dwWidth && parentWidget()->height() == ddsd.dwHeight);
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::resizeEvent(QResizeEvent *event) {
|
||||
BlitterWidget::resizeEvent(event);
|
||||
detectExclusive();
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::moveEvent(QMoveEvent *event) {
|
||||
BlitterWidget::moveEvent(event);
|
||||
detectExclusive();
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::hideEvent(QHideEvent *event) {
|
||||
BlitterWidget::hideEvent(event);
|
||||
setExclusive(false);
|
||||
}*/
|
||||
|
||||
void DirectDrawBlitter::setExclusive(const bool exclusive) {
|
||||
if (this->exclusive == exclusive)
|
||||
return;
|
||||
|
||||
this->exclusive = exclusive;
|
||||
|
||||
std::cout << "exclusive: " << exclusive << std::endl;
|
||||
|
||||
if (flipping)
|
||||
reinit();
|
||||
}
|
||||
|
||||
void DirectDrawBlitter::reinit() {
|
||||
if (lpDDSSystem) {
|
||||
DDSURFACEDESC2 ddsd;
|
||||
memset(&ddsd, 0, sizeof(ddsd));
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
lpDDSSystem->GetSurfaceDesc(&ddsd);
|
||||
|
||||
uninit();
|
||||
init();
|
||||
setBufferDimensions(ddsd.dwWidth, ddsd.dwHeight);
|
||||
resetVideoBuffer();
|
||||
}
|
||||
}
|
89
gambatte_qt/src/blitterwidgets/directdrawblitter.h
Normal file
89
gambatte_qt/src/blitterwidgets/directdrawblitter.h
Normal file
@ -0,0 +1,89 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef DIRECTDRAWBLITTER_H_
|
||||
#define DIRECTDRAWBLITTER_H_
|
||||
|
||||
#include "../blitterwidget.h"
|
||||
|
||||
#include <ddraw.h>
|
||||
|
||||
class QCheckBox;
|
||||
class VideoBufferReseter;
|
||||
|
||||
class DirectDrawBlitter : public BlitterWidget {
|
||||
VideoBufferReseter &resetVideoBuffer;
|
||||
QWidget *const confWidget;
|
||||
QCheckBox *const vblankBox;
|
||||
QCheckBox *const flippingBox;
|
||||
QCheckBox *const videoSurfaceBox;
|
||||
LPDIRECTDRAW7 lpDD;
|
||||
LPDIRECTDRAWSURFACE7 lpDDSPrimary;
|
||||
LPDIRECTDRAWSURFACE7 lpDDSBack;
|
||||
LPDIRECTDRAWSURFACE7 lpDDSSystem;
|
||||
LPDIRECTDRAWSURFACE7 lpDDSVideo;
|
||||
LPDIRECTDRAWCLIPPER lpClipper;
|
||||
PixelBuffer pixb;
|
||||
bool keepRatio;
|
||||
bool integerScaling;
|
||||
bool vblank;
|
||||
bool hz60;
|
||||
bool videoSurface;
|
||||
bool exclusive;
|
||||
bool flipping;
|
||||
|
||||
bool initPrimarySurface();
|
||||
bool initVideoSurface();
|
||||
bool restoreSurfaces();
|
||||
void systemSurfaceBlit();
|
||||
void videoSurfaceBlit();
|
||||
//void detectExclusive();
|
||||
void reinit();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
/*void resizeEvent(QResizeEvent *event);
|
||||
void moveEvent(QMoveEvent *event);
|
||||
void hideEvent(QHideEvent *event);*/
|
||||
|
||||
public:
|
||||
DirectDrawBlitter(VideoBufferReseter &resetVideoBuffer_in, QWidget *parent = 0);
|
||||
~DirectDrawBlitter();
|
||||
void blit();
|
||||
const PixelBuffer inBuffer();
|
||||
void init();
|
||||
void keepAspectRatio(bool enable);
|
||||
bool keepsAspectRatio();
|
||||
void scaleByInteger(bool enable);
|
||||
bool scalesByInteger();
|
||||
void setBufferDimensions(unsigned int w, unsigned int h);
|
||||
const Rational frameTime() const;
|
||||
int sync(bool turbo);
|
||||
void uninit();
|
||||
void setExclusive(bool exclusive);
|
||||
|
||||
QWidget* settingsWidget() { return confWidget; }
|
||||
void acceptSettings();
|
||||
void rejectSettings();
|
||||
|
||||
public slots:
|
||||
// void modeChange();
|
||||
void rateChange(int hz);
|
||||
};
|
||||
|
||||
#endif /*DIRECTDRAWBLITTER_H_*/
|
447
gambatte_qt/src/blitterwidgets/qglblitter.cpp
Normal file
447
gambatte_qt/src/blitterwidgets/qglblitter.cpp
Normal file
@ -0,0 +1,447 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "qglblitter.h"
|
||||
|
||||
#include <QSizePolicy>
|
||||
#include <QVBoxLayout>
|
||||
#include <QCheckBox>
|
||||
#include <QResizeEvent>
|
||||
#include <QSettings>
|
||||
|
||||
#include <QGLWidget>
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
#include <GL/glext.h>
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_UNIX
|
||||
#include "../x11getprocaddress.h"
|
||||
#endif
|
||||
|
||||
class QGLSubWidget : public QGLWidget {
|
||||
unsigned textureRes;
|
||||
unsigned inWidth;
|
||||
unsigned inHeight;
|
||||
unsigned swapInterval;
|
||||
bool initialized;
|
||||
bool keepRatio;
|
||||
bool integerScaling;
|
||||
bool bf;
|
||||
|
||||
protected:
|
||||
void initializeGL();
|
||||
void paintGL();
|
||||
void resizeGL(int w, int h);
|
||||
|
||||
public:
|
||||
QGLSubWidget(unsigned swapInterval, bool bf, QWidget *parent = 0);
|
||||
~QGLSubWidget();
|
||||
|
||||
void blit();
|
||||
void blitFront();
|
||||
|
||||
unsigned getInWidth() const {
|
||||
return inWidth;
|
||||
}
|
||||
|
||||
unsigned getInHeight() const {
|
||||
return inHeight;
|
||||
}
|
||||
|
||||
unsigned getSwapInterval() const {
|
||||
return swapInterval;
|
||||
}
|
||||
|
||||
bool keepsRatio() {
|
||||
return keepRatio;
|
||||
}
|
||||
|
||||
bool scalesByInteger() {
|
||||
return integerScaling;
|
||||
}
|
||||
|
||||
void setBilinearFiltering(bool on);
|
||||
void setBufferDimensions(unsigned w, unsigned h);
|
||||
|
||||
void setIntegerScaling(const bool on) {
|
||||
integerScaling = on;
|
||||
|
||||
if (initialized) {
|
||||
makeCurrent();
|
||||
resizeGL(width(), height());
|
||||
}
|
||||
}
|
||||
|
||||
void setKeepRatio(const bool on) {
|
||||
keepRatio = on;
|
||||
|
||||
if (initialized) {
|
||||
makeCurrent();
|
||||
resizeGL(width(), height());
|
||||
}
|
||||
}
|
||||
|
||||
void updateTexture(uint32_t *buffer);
|
||||
|
||||
void uninit();
|
||||
};
|
||||
|
||||
static const QGLFormat getQGLFormat(const unsigned swapInterval) {
|
||||
QGLFormat f;
|
||||
|
||||
#ifndef PLATFORM_UNIX
|
||||
f.setSwapInterval(swapInterval);
|
||||
#endif
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
QGLSubWidget::QGLSubWidget(const unsigned swapInterval_in, const bool bf_in, QWidget *parent) :
|
||||
QGLWidget(getQGLFormat(swapInterval_in), parent),
|
||||
inWidth(160),
|
||||
inHeight(144),
|
||||
swapInterval(swapInterval_in),
|
||||
initialized(false),
|
||||
keepRatio(true),
|
||||
integerScaling(false),
|
||||
bf(bf_in)
|
||||
{
|
||||
setAutoBufferSwap(false);
|
||||
// setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
||||
|
||||
// QSettings settings;
|
||||
// settings.beginGroup("qglsubwidget");
|
||||
// bf = settings.value("bf", true).toBool();
|
||||
// settings.endGroup();
|
||||
}
|
||||
|
||||
QGLSubWidget::~QGLSubWidget() {
|
||||
uninit();
|
||||
|
||||
// QSettings settings;
|
||||
// settings.beginGroup("qglsubwidget");
|
||||
// settings.setValue("bf", bf);
|
||||
// settings.endGroup();
|
||||
}
|
||||
|
||||
void QGLSubWidget::blit() {
|
||||
glCallList(1);
|
||||
glFlush();
|
||||
}
|
||||
|
||||
void QGLSubWidget::initializeGL() {
|
||||
// void *libHandle = dlopen("libgl.so", RTLD_LAZY);
|
||||
|
||||
// glXGetVideoSyncSGI_ptr = (glXGetVideoSyncSGI_Func) dlsym(libHandle, "glXGetVideoSyncSGI");
|
||||
// glXWaitVideoSyncSGI_ptr = (glXWaitVideoSyncSGI_Func) dlsym(libHandle, "glXWaitVideoSyncSGI");
|
||||
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, bf ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, bf ? GL_LINEAR : GL_NEAREST);
|
||||
glShadeModel(GL_FLAT);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_DITHER);
|
||||
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
glNewList(1, GL_COMPILE);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, -0.2); glVertex2f(0.0, -0.2);
|
||||
glTexCoord2f(0.0, 1.0); glVertex2f(0.0, 1.0);
|
||||
glTexCoord2f(1.2, 1.0); glVertex2f(1.2, 1.0);
|
||||
glTexCoord2f(1.2, -0.2); glVertex2f(1.2, -0.2);
|
||||
glEnd();
|
||||
glEndList();
|
||||
|
||||
#ifdef PLATFORM_UNIX
|
||||
if (swapInterval) {
|
||||
static void (*const glXSwapIntervalSGI)(int) = reinterpret_cast<void (*)(int)>(x11GetProcAddress("glXSwapIntervalSGI"));
|
||||
|
||||
if (glXSwapIntervalSGI) {
|
||||
glXSwapIntervalSGI(swapInterval);
|
||||
} else
|
||||
swapInterval = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void QGLSubWidget::blitFront() {
|
||||
GLint drawBuffer;
|
||||
glGetIntegerv(GL_DRAW_BUFFER, &drawBuffer);
|
||||
glDrawBuffer(GL_FRONT);
|
||||
blit();
|
||||
glDrawBuffer(drawBuffer);
|
||||
}
|
||||
|
||||
void QGLSubWidget::paintGL() {
|
||||
if (swapInterval)
|
||||
blitFront();
|
||||
else {
|
||||
blit();
|
||||
swapBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
void QGLSubWidget::resizeGL(const int w, const int h) {
|
||||
if (keepRatio) {
|
||||
{
|
||||
GLint drawBuffer;
|
||||
glGetIntegerv(GL_DRAW_BUFFER, &drawBuffer);
|
||||
glDrawBuffer(GL_FRONT_AND_BACK);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glDrawBuffer(drawBuffer);
|
||||
}
|
||||
|
||||
if (integerScaling) {
|
||||
const unsigned int scale_factor = std::min(w / inWidth, h / inHeight);
|
||||
|
||||
const int new_w = inWidth * scale_factor;
|
||||
const int new_h = inHeight * scale_factor;
|
||||
|
||||
glViewport(w - new_w >> 1, h - new_h >> 1, new_w, new_h);
|
||||
} else {
|
||||
if (w * 9 > h * 10) {
|
||||
const int new_w = (h * 20 + 9) / 18;
|
||||
glViewport(w - new_w >> 1, 0, new_w, h);
|
||||
} else {
|
||||
const int new_h = (w * 9 + 5) / 10;
|
||||
glViewport(0, h - new_h >> 1, w, new_h);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
glViewport(0, 0, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
void QGLSubWidget::setBilinearFiltering(const bool on) {
|
||||
const bool oldbf = bf;
|
||||
bf = on;
|
||||
|
||||
if (bf != oldbf && initialized) {
|
||||
makeCurrent();
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, bf ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, bf ? GL_LINEAR : GL_NEAREST);
|
||||
}
|
||||
}
|
||||
|
||||
void QGLSubWidget::setBufferDimensions(const unsigned int width, const unsigned int height) {
|
||||
inWidth = width;
|
||||
inHeight = height;
|
||||
|
||||
textureRes = std::max(width, height);
|
||||
|
||||
//Next power of 2
|
||||
--textureRes;
|
||||
textureRes |= textureRes >> 1;
|
||||
textureRes |= textureRes >> 2;
|
||||
textureRes |= textureRes >> 4;
|
||||
textureRes |= textureRes >> 8;
|
||||
textureRes |= textureRes >> 16;
|
||||
++textureRes;
|
||||
|
||||
if (!initialized)
|
||||
glInit();
|
||||
else
|
||||
makeCurrent();
|
||||
|
||||
glLoadIdentity();
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textureRes, textureRes, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
|
||||
double dres = textureRes;
|
||||
glOrtho(0, width / dres, 1, 1.0 - height / dres, -1, 1);
|
||||
}
|
||||
|
||||
void QGLSubWidget::uninit() {
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
void QGLSubWidget::updateTexture(uint32_t *const buffer) {
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, textureRes - inHeight, inWidth, inHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
|
||||
}
|
||||
|
||||
QGLBlitter::QGLBlitter(QWidget *parent) :
|
||||
BlitterWidget(QString("OpenGL"), false, true, parent),
|
||||
confWidget(new QWidget),
|
||||
vsyncBox(new QCheckBox(QString("Sync to vertical blank in 60, 119 and 120 Hz modes"))),
|
||||
bfBox(new QCheckBox(QString("Bilinear filtering"))),
|
||||
buffer(NULL),
|
||||
hz(0)
|
||||
{
|
||||
// setLayout(new QVBoxLayout);
|
||||
// layout()->setMargin(0);
|
||||
// layout()->setSpacing(0);
|
||||
// layout()->addWidget(subWidget);
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("qglblitter");
|
||||
vsync = settings.value("vsync", false).toBool();
|
||||
bf = settings.value("bf", true).toBool();
|
||||
settings.endGroup();
|
||||
|
||||
confWidget->setLayout(new QVBoxLayout);
|
||||
confWidget->layout()->setMargin(0);
|
||||
confWidget->layout()->addWidget(vsyncBox);
|
||||
confWidget->layout()->addWidget(bfBox);
|
||||
vsyncBox->setChecked(vsync);
|
||||
bfBox->setChecked(bf);
|
||||
|
||||
subWidget = new QGLSubWidget(0, bf, this);
|
||||
}
|
||||
|
||||
QGLBlitter::~QGLBlitter() {
|
||||
uninit();
|
||||
|
||||
// delete subWidget;
|
||||
delete confWidget;
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("qglblitter");
|
||||
settings.setValue("vsync", vsync);
|
||||
settings.setValue("bf", bf);
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void QGLBlitter::resizeEvent(QResizeEvent *const event) {
|
||||
subWidget->setGeometry(0, 0, event->size().width(), event->size().height());
|
||||
}
|
||||
|
||||
void QGLBlitter::uninit() {
|
||||
subWidget->uninit();
|
||||
|
||||
delete[] buffer;
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
bool QGLBlitter::isUnusable() {
|
||||
return !subWidget->isValid();
|
||||
}
|
||||
|
||||
void QGLBlitter::keepAspectRatio(const bool enable) {
|
||||
subWidget->setKeepRatio(enable);
|
||||
}
|
||||
|
||||
bool QGLBlitter::keepsAspectRatio() {
|
||||
return subWidget->keepsRatio();
|
||||
}
|
||||
|
||||
void QGLBlitter::scaleByInteger(const bool enable) {
|
||||
subWidget->setIntegerScaling(enable);
|
||||
}
|
||||
|
||||
bool QGLBlitter::scalesByInteger() {
|
||||
return subWidget->scalesByInteger();
|
||||
}
|
||||
|
||||
void QGLBlitter::setBufferDimensions(const unsigned int width, const unsigned int height) {
|
||||
delete []buffer;
|
||||
buffer = new uint32_t[width * height];
|
||||
|
||||
subWidget->setBufferDimensions(width, height);
|
||||
}
|
||||
|
||||
const PixelBuffer QGLBlitter::inBuffer() {
|
||||
PixelBuffer pixb;
|
||||
pixb.format = PixelBuffer::RGB32;
|
||||
pixb.pixels = buffer;
|
||||
pixb.pitch = subWidget->getInWidth();
|
||||
|
||||
return pixb;
|
||||
}
|
||||
|
||||
void QGLBlitter::blit() {
|
||||
if (buffer) {
|
||||
subWidget->makeCurrent();
|
||||
subWidget->updateTexture(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
const BlitterWidget::Rational QGLBlitter::frameTime() const {
|
||||
if (subWidget->getSwapInterval()) {
|
||||
Rational r = { subWidget->getSwapInterval(), hz };
|
||||
return r;
|
||||
}
|
||||
|
||||
return BlitterWidget::frameTime();
|
||||
}
|
||||
|
||||
int QGLBlitter::sync(const bool turbo) {
|
||||
subWidget->makeCurrent();
|
||||
|
||||
if (subWidget->getSwapInterval() && turbo)
|
||||
subWidget->blitFront();
|
||||
else {
|
||||
subWidget->blit();
|
||||
subWidget->swapBuffers();
|
||||
}
|
||||
|
||||
if (subWidget->getSwapInterval())
|
||||
return 0;
|
||||
|
||||
return BlitterWidget::sync(turbo);
|
||||
}
|
||||
|
||||
void QGLBlitter::resetSubWidget() {
|
||||
unsigned swapInterval = 0;
|
||||
|
||||
if (vsync) {
|
||||
if (hz == 60)
|
||||
swapInterval = 1;
|
||||
else if (hz == 119 || hz == 120)
|
||||
swapInterval = 2;
|
||||
}
|
||||
|
||||
if (swapInterval == subWidget->getSwapInterval())
|
||||
return;
|
||||
|
||||
const bool keepRatio = subWidget->keepsRatio();
|
||||
const bool integerScaling = subWidget->scalesByInteger();
|
||||
const unsigned w = subWidget->getInWidth();
|
||||
const unsigned h = subWidget->getInHeight();
|
||||
|
||||
// subWidget->hide();
|
||||
delete subWidget;
|
||||
subWidget = new QGLSubWidget(swapInterval, bf, this);
|
||||
subWidget->setKeepRatio(keepRatio);
|
||||
subWidget->setIntegerScaling(integerScaling);
|
||||
subWidget->setGeometry(0, 0, width(), height());
|
||||
subWidget->show();
|
||||
|
||||
if (buffer)
|
||||
subWidget->setBufferDimensions(w, h);
|
||||
}
|
||||
|
||||
void QGLBlitter::acceptSettings() {
|
||||
bf = bfBox->isChecked();
|
||||
subWidget->setBilinearFiltering(bf);
|
||||
|
||||
vsync = vsyncBox->isChecked();
|
||||
resetSubWidget();
|
||||
}
|
||||
|
||||
void QGLBlitter::rejectSettings() {
|
||||
vsyncBox->setChecked(vsync);
|
||||
bfBox->setChecked(bf);
|
||||
}
|
||||
|
||||
void QGLBlitter::rateChange(const int hz) {
|
||||
this->hz = hz;
|
||||
resetSubWidget();
|
||||
}
|
68
gambatte_qt/src/blitterwidgets/qglblitter.h
Normal file
68
gambatte_qt/src/blitterwidgets/qglblitter.h
Normal file
@ -0,0 +1,68 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef QGLBLITTER_H
|
||||
#define QGLBLITTER_H
|
||||
|
||||
#include "../blitterwidget.h"
|
||||
|
||||
class QGLSubWidget;
|
||||
class QCheckBox;
|
||||
|
||||
class QGLBlitter : public BlitterWidget {
|
||||
QGLSubWidget *subWidget;
|
||||
QWidget *const confWidget;
|
||||
QCheckBox *const vsyncBox;
|
||||
QCheckBox *const bfBox;
|
||||
uint32_t *buffer;
|
||||
unsigned hz;
|
||||
bool vsync;
|
||||
bool bf;
|
||||
|
||||
void resetSubWidget();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
|
||||
public:
|
||||
QGLBlitter(QWidget *parent = 0);
|
||||
~QGLBlitter();
|
||||
// void init();
|
||||
void uninit();
|
||||
bool isUnusable();
|
||||
void keepAspectRatio(bool enable);
|
||||
bool keepsAspectRatio();
|
||||
void scaleByInteger(bool enable);
|
||||
bool scalesByInteger();
|
||||
void setBufferDimensions(unsigned int width, unsigned int height);
|
||||
const PixelBuffer inBuffer();
|
||||
void blit();
|
||||
const Rational frameTime() const;
|
||||
int sync(bool turbo);
|
||||
QWidget* settingsWidget() { return confWidget; }
|
||||
|
||||
// // public slots:
|
||||
void acceptSettings();
|
||||
void rejectSettings();
|
||||
|
||||
public slots:
|
||||
void rateChange(int hz);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
117
gambatte_qt/src/blitterwidgets/qpainterblitter.cpp
Normal file
117
gambatte_qt/src/blitterwidgets/qpainterblitter.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "qpainterblitter.h"
|
||||
|
||||
#include "../scalebuffer.h"
|
||||
#include "../videobufferreseter.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QImage>
|
||||
#include <QPaintEvent>
|
||||
|
||||
QPainterBlitter::QPainterBlitter(VideoBufferReseter &resetVideoBuffer_in, QWidget *parent) :
|
||||
BlitterWidget("QPainter", true, parent),
|
||||
resetVideoBuffer(resetVideoBuffer_in),
|
||||
image(NULL),
|
||||
buffer(NULL),
|
||||
inWidth(160),
|
||||
inHeight(144),
|
||||
scale(0)
|
||||
{
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||
}
|
||||
|
||||
QPainterBlitter::~QPainterBlitter() {
|
||||
uninit();
|
||||
}
|
||||
|
||||
void QPainterBlitter::blit() {
|
||||
repaint();
|
||||
}
|
||||
|
||||
const PixelBuffer QPainterBlitter::inBuffer() {
|
||||
PixelBuffer pixb;
|
||||
pixb.format = PixelBuffer::RGB32;
|
||||
pixb.pixels = image->bits();
|
||||
pixb.pitch = image->bytesPerLine() >> 2;
|
||||
|
||||
if (buffer) {
|
||||
pixb.pixels = buffer;
|
||||
pixb.pitch = inWidth;
|
||||
}
|
||||
|
||||
return pixb;
|
||||
}
|
||||
|
||||
void QPainterBlitter::paintEvent(QPaintEvent *const event) {
|
||||
if (buffer) {
|
||||
scaleBuffer(buffer, reinterpret_cast<uint32_t*>(image->bits()), inWidth, inHeight, scale);
|
||||
}
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setClipRegion(event->region());
|
||||
painter.drawImage(rect(), *image);
|
||||
}
|
||||
|
||||
void QPainterBlitter::resizeEvent(QResizeEvent */*event*/) {
|
||||
const unsigned newScale = std::min(width() / inWidth, height() / inHeight);
|
||||
|
||||
if (newScale != scale) {
|
||||
scale = newScale;
|
||||
|
||||
if (image) {
|
||||
setBufferDimensions(inWidth, inHeight);
|
||||
resetVideoBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QPainterBlitter::setBufferDimensions(const unsigned int w, const unsigned int h) {
|
||||
inWidth = w;
|
||||
inHeight = h;
|
||||
|
||||
scale = std::min(width() / w, height() / h);
|
||||
|
||||
uninit();
|
||||
|
||||
if (scale > 1)
|
||||
buffer = new uint32_t[w * h];
|
||||
|
||||
image = new QImage(w * scale, h * scale, QImage::Format_RGB32);
|
||||
}
|
||||
|
||||
void QPainterBlitter::uninit() {
|
||||
delete image;
|
||||
image = NULL;
|
||||
|
||||
delete[] buffer;
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
void QPainterBlitter::keepAspectRatio(const bool /*enable*/) {}
|
||||
|
||||
bool QPainterBlitter::keepsAspectRatio() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void QPainterBlitter::scaleByInteger(const bool /*enable*/) {}
|
||||
|
||||
bool QPainterBlitter::scalesByInteger() {
|
||||
return true;
|
||||
}
|
52
gambatte_qt/src/blitterwidgets/qpainterblitter.h
Normal file
52
gambatte_qt/src/blitterwidgets/qpainterblitter.h
Normal file
@ -0,0 +1,52 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef QPAINTERBLITTER_H
|
||||
#define QPAINTERBLITTER_H
|
||||
|
||||
#include "../blitterwidget.h"
|
||||
|
||||
class QPainter;
|
||||
class QImage;
|
||||
class VideoBufferReseter;
|
||||
|
||||
class QPainterBlitter : public BlitterWidget {
|
||||
VideoBufferReseter &resetVideoBuffer;
|
||||
QImage *image;
|
||||
uint32_t *buffer;
|
||||
unsigned int inWidth, inHeight;
|
||||
unsigned int scale;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
|
||||
public:
|
||||
QPainterBlitter(VideoBufferReseter &resetVideoBuffer_in, QWidget *parent = 0);
|
||||
~QPainterBlitter();
|
||||
void blit();
|
||||
const PixelBuffer inBuffer();
|
||||
void keepAspectRatio(bool enable);
|
||||
bool keepsAspectRatio();
|
||||
void scaleByInteger(bool enable);
|
||||
bool scalesByInteger();
|
||||
void setBufferDimensions(unsigned int w, unsigned int h);
|
||||
void uninit();
|
||||
};
|
||||
|
||||
#endif
|
301
gambatte_qt/src/blitterwidgets/x11blitter.cpp
Normal file
301
gambatte_qt/src/blitterwidgets/x11blitter.cpp
Normal file
@ -0,0 +1,301 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include <QPaintEvent>
|
||||
|
||||
#include "x11blitter.h"
|
||||
|
||||
#include "../scalebuffer.h"
|
||||
#include "../videobufferreseter.h"
|
||||
|
||||
#include <QX11Info>
|
||||
#include <X11/Xlib.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <X11/extensions/XShm.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <videoblitter.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class X11SubBlitter {
|
||||
public:
|
||||
virtual void blit(Drawable drawable, unsigned x, unsigned y, unsigned w, unsigned h) = 0;
|
||||
virtual bool failed() = 0;
|
||||
virtual const PixelBuffer inBuffer() = 0;
|
||||
virtual ~X11SubBlitter() {};
|
||||
};
|
||||
|
||||
class X11ShmBlitter : public X11SubBlitter {
|
||||
XShmSegmentInfo shminfo;
|
||||
XImage *ximage;
|
||||
|
||||
public:
|
||||
X11ShmBlitter(unsigned int width, unsigned int height);
|
||||
void blit(Drawable drawable, unsigned x, unsigned y, unsigned w, unsigned h);
|
||||
bool failed();
|
||||
const PixelBuffer inBuffer();
|
||||
~X11ShmBlitter();
|
||||
};
|
||||
|
||||
X11ShmBlitter::X11ShmBlitter(const unsigned int width, const unsigned int height) {
|
||||
shminfo.shmaddr = NULL;
|
||||
std::cout << "creating shm ximage...\n";
|
||||
ximage = XShmCreateImage(QX11Info::display(), reinterpret_cast<Visual*>(QX11Info::appVisual()), QX11Info::appDepth(), ZPixmap, NULL, &shminfo, width, height);
|
||||
|
||||
if (ximage == NULL) {
|
||||
std::cout << "failed to create shm ximage\n";
|
||||
} else {
|
||||
shminfo.shmid = shmget(IPC_PRIVATE, ximage->bytes_per_line * ximage->height, IPC_CREAT | 0777);
|
||||
shminfo.shmaddr = ximage->data = static_cast<char*>(shmat(shminfo.shmid, 0, 0));
|
||||
shminfo.readOnly = True;
|
||||
XShmAttach(QX11Info::display(), &shminfo);
|
||||
XSync(QX11Info::display(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
X11ShmBlitter::~X11ShmBlitter() {
|
||||
if (shminfo.shmaddr != NULL) {
|
||||
XShmDetach(QX11Info::display(), &shminfo);
|
||||
XSync(QX11Info::display(), 0);
|
||||
shmdt(shminfo.shmaddr);
|
||||
shmctl(shminfo.shmid, IPC_RMID, 0);
|
||||
}
|
||||
|
||||
if (ximage != NULL)
|
||||
XFree(ximage);
|
||||
}
|
||||
|
||||
void X11ShmBlitter::blit(const Drawable drawable, const unsigned x, const unsigned y, const unsigned w, const unsigned h) {
|
||||
if (ximage && shminfo.shmaddr) {
|
||||
XShmPutImage(QX11Info::display(), drawable, DefaultGC(QX11Info::display(), QX11Info::appScreen()), ximage, x, y, x, y, w, h, False);
|
||||
}
|
||||
}
|
||||
|
||||
bool X11ShmBlitter::failed() {
|
||||
return ximage == NULL || shminfo.shmaddr == NULL;
|
||||
}
|
||||
|
||||
const PixelBuffer X11ShmBlitter::inBuffer() {
|
||||
PixelBuffer pixb;
|
||||
pixb.format = QX11Info::appDepth() == 16 ? PixelBuffer::RGB16 : PixelBuffer::RGB32;
|
||||
pixb.pixels = ximage ? ximage->data : NULL;
|
||||
pixb.pitch = ximage ? ximage->width : 0;
|
||||
|
||||
return pixb;
|
||||
}
|
||||
|
||||
class X11PlainBlitter : public X11SubBlitter {
|
||||
XImage *ximage;
|
||||
|
||||
public:
|
||||
X11PlainBlitter (unsigned int width, unsigned int height);
|
||||
void blit(Drawable drawable, unsigned x, unsigned y, unsigned w, unsigned h);
|
||||
bool failed();
|
||||
const PixelBuffer inBuffer();
|
||||
~X11PlainBlitter ();
|
||||
};
|
||||
|
||||
X11PlainBlitter::X11PlainBlitter(const unsigned int width, const unsigned int height) {
|
||||
std::cout << "creating ximage...\n";
|
||||
ximage = XCreateImage(QX11Info::display(), reinterpret_cast<Visual*>(QX11Info::appVisual()), QX11Info::appDepth(), ZPixmap, 0, NULL, width, height, QX11Info::appDepth(), 0);
|
||||
|
||||
if (ximage == NULL) {
|
||||
std::cout << "failed to create ximage\n";
|
||||
} else {
|
||||
ximage->data = new char[ximage->bytes_per_line * ximage->height];
|
||||
}
|
||||
}
|
||||
|
||||
X11PlainBlitter::~X11PlainBlitter () {
|
||||
if (ximage) {
|
||||
delete[] ximage->data;
|
||||
XFree(ximage);
|
||||
}
|
||||
}
|
||||
|
||||
void X11PlainBlitter::blit(const Drawable drawable, const unsigned x, const unsigned y, const unsigned w, const unsigned h) {
|
||||
if (ximage) {
|
||||
XPutImage(QX11Info::display(), drawable, DefaultGC(QX11Info::display(), QX11Info::appScreen()), ximage, x, y, x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
bool X11PlainBlitter::failed() {
|
||||
return ximage == NULL;
|
||||
}
|
||||
|
||||
const PixelBuffer X11PlainBlitter::inBuffer() {
|
||||
PixelBuffer pixb;
|
||||
pixb.format = QX11Info::appDepth() == 16 ? PixelBuffer::RGB16 : PixelBuffer::RGB32;
|
||||
pixb.pixels = ximage ? ximage->data : NULL;
|
||||
pixb.pitch = ximage ? ximage->width : 0;
|
||||
|
||||
return pixb;
|
||||
}
|
||||
|
||||
X11Blitter::X11Blitter(VideoBufferReseter &resetVideoBuffer_in, QWidget *parent) :
|
||||
BlitterWidget(QString("X11"), true, parent),
|
||||
resetVideoBuffer(resetVideoBuffer_in),
|
||||
subBlitter(NULL),
|
||||
buffer(NULL),
|
||||
inWidth(160),
|
||||
inHeight(144),
|
||||
scale(0)
|
||||
{
|
||||
/*QPalette pal = palette();
|
||||
pal.setColor(QPalette::Window, QColor(0,0,0));
|
||||
setPalette(pal);
|
||||
setBackgroundRole(QPalette::Window);
|
||||
setAutoFillBackground(true);*/
|
||||
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||
setAttribute(Qt::WA_PaintOnScreen, true);
|
||||
}
|
||||
|
||||
bool X11Blitter::isUnusable() {
|
||||
return !(QX11Info::appDepth() == 16 || QX11Info::appDepth() == 24 || QX11Info::appDepth() == 32);
|
||||
}
|
||||
|
||||
void X11Blitter::init() {
|
||||
XSync(QX11Info::display(), 0);
|
||||
|
||||
shm = XShmQueryExtension(QX11Info::display());
|
||||
// shm = false;
|
||||
std::cout << "shm: " << shm << std::endl;
|
||||
}
|
||||
|
||||
void X11Blitter::uninit() {
|
||||
delete subBlitter;
|
||||
subBlitter = NULL;
|
||||
|
||||
delete[] buffer;
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
X11Blitter::~X11Blitter() {
|
||||
uninit();
|
||||
}
|
||||
|
||||
int X11Blitter::sync(const bool turbo) {
|
||||
if (subBlitter->failed())
|
||||
return -1;
|
||||
|
||||
return BlitterWidget::sync(turbo);
|
||||
}
|
||||
|
||||
void X11Blitter::keepAspectRatio(const bool /*enable*/) {
|
||||
// keepRatio = enable;
|
||||
}
|
||||
|
||||
bool X11Blitter::keepsAspectRatio() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void X11Blitter::scaleByInteger(const bool /*enable*/) {
|
||||
// integerScaling = enable;
|
||||
}
|
||||
|
||||
bool X11Blitter::scalesByInteger() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
void X11Blitter::paintEvent(QPaintEvent *event) {
|
||||
if(event)
|
||||
event->accept();
|
||||
|
||||
if(xvimage) {
|
||||
XvShmPutImage(QX11Info::display(), xvport, winId(), DefaultGC(QX11Info::display(), QX11Info::appScreen()), xvimage, 0, 0, inWidth*2, inHeight, 0, 0, width(), height(), False);
|
||||
XSync(QX11Info::display(),0);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void X11Blitter::paintEvent(QPaintEvent *event) {
|
||||
if (subBlitter) {
|
||||
event->accept();
|
||||
const QRect &rect = event->rect();
|
||||
subBlitter->blit(winId(), rect.x(), rect.y(), rect.width(), rect.height());
|
||||
}
|
||||
}
|
||||
|
||||
void X11Blitter::setBufferDimensions(const unsigned int w, const unsigned int h) {
|
||||
inWidth = w;
|
||||
inHeight = h;
|
||||
|
||||
scale = std::min(width() / w, height() / h);
|
||||
|
||||
uninit();
|
||||
|
||||
if (scale > 1)
|
||||
buffer = new char[w * h * (QX11Info::appDepth() == 16 ? 2 : 4)];
|
||||
|
||||
if (shm) {
|
||||
subBlitter = new X11ShmBlitter(w * scale, h * scale);
|
||||
|
||||
if (subBlitter->failed()) {
|
||||
shm = false;
|
||||
delete subBlitter;
|
||||
}
|
||||
}
|
||||
|
||||
if (!shm)
|
||||
subBlitter = new X11PlainBlitter (w * scale, h * scale);
|
||||
}
|
||||
|
||||
const PixelBuffer X11Blitter::inBuffer() {
|
||||
if (buffer) {
|
||||
PixelBuffer pixb;
|
||||
pixb.format = QX11Info::appDepth() == 16 ? PixelBuffer::RGB16 : PixelBuffer::RGB32;
|
||||
pixb.pixels = buffer;
|
||||
pixb.pitch = inWidth;
|
||||
|
||||
return pixb;
|
||||
}
|
||||
|
||||
return subBlitter->inBuffer();
|
||||
}
|
||||
|
||||
void X11Blitter::blit() {
|
||||
if (buffer) {
|
||||
const PixelBuffer &pb = subBlitter->inBuffer();
|
||||
|
||||
if (QX11Info::appDepth() == 16) {
|
||||
scaleBuffer(reinterpret_cast<uint16_t*>(buffer), reinterpret_cast<uint16_t*>(pb.pixels), inWidth, inHeight, scale);
|
||||
} else {
|
||||
scaleBuffer(reinterpret_cast<uint32_t*>(buffer), reinterpret_cast<uint32_t*>(pb.pixels), inWidth, inHeight, scale);
|
||||
}
|
||||
}
|
||||
|
||||
subBlitter->blit(winId(), 0, 0, width(), height());
|
||||
XSync(QX11Info::display(), 0);
|
||||
}
|
||||
|
||||
void X11Blitter::resizeEvent(QResizeEvent */*event*/) {
|
||||
const unsigned newScale = std::min(width() / inWidth, height() / inHeight);
|
||||
|
||||
if (newScale != scale) {
|
||||
scale = newScale;
|
||||
|
||||
if (subBlitter) {
|
||||
setBufferDimensions(inWidth, inHeight);
|
||||
resetVideoBuffer();
|
||||
}
|
||||
}
|
||||
}
|
62
gambatte_qt/src/blitterwidgets/x11blitter.h
Normal file
62
gambatte_qt/src/blitterwidgets/x11blitter.h
Normal file
@ -0,0 +1,62 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef X11BLITTER_H
|
||||
#define X11BLITTER_H
|
||||
|
||||
#include "../blitterwidget.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
class X11SubBlitter;
|
||||
class VideoBufferReseter;
|
||||
|
||||
class X11Blitter : public BlitterWidget {
|
||||
VideoBufferReseter &resetVideoBuffer;
|
||||
X11SubBlitter *subBlitter;
|
||||
char *buffer;
|
||||
unsigned int inWidth, inHeight;
|
||||
unsigned int scale;
|
||||
// bool init;
|
||||
// bool keepRatio;
|
||||
// bool integerScaling;
|
||||
bool shm;
|
||||
// bool failed;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
|
||||
public:
|
||||
X11Blitter(VideoBufferReseter &resetVideoBuffer_in, QWidget *parent = 0);
|
||||
~X11Blitter();
|
||||
void init();
|
||||
void uninit();
|
||||
// void init(const unsigned int srcW, const unsigned int srcH);
|
||||
bool isUnusable();
|
||||
void keepAspectRatio(const bool enable);
|
||||
bool keepsAspectRatio();
|
||||
void scaleByInteger(const bool enable);
|
||||
bool scalesByInteger();
|
||||
int sync(bool turbo);
|
||||
void setBufferDimensions(const unsigned int width, const unsigned int height);
|
||||
const PixelBuffer inBuffer();
|
||||
void blit();
|
||||
};
|
||||
|
||||
#endif
|
469
gambatte_qt/src/blitterwidgets/xvblitter.cpp
Normal file
469
gambatte_qt/src/blitterwidgets/xvblitter.cpp
Normal file
@ -0,0 +1,469 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QSettings>
|
||||
#include <QPaintEvent>
|
||||
|
||||
#include "xvblitter.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <QX11Info>
|
||||
#include <X11/Xlib.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <X11/extensions/XShm.h>
|
||||
#include <X11/extensions/Xvlib.h>
|
||||
|
||||
class XvSubBlitter {
|
||||
public:
|
||||
virtual void blit(Drawable drawable, XvPortID xvport, unsigned width, unsigned height) = 0;
|
||||
virtual bool failed() = 0;
|
||||
virtual const PixelBuffer inBuffer() = 0;
|
||||
virtual ~XvSubBlitter() {};
|
||||
};
|
||||
|
||||
class XvShmBlitter : public XvSubBlitter {
|
||||
XShmSegmentInfo shminfo;
|
||||
XvImage *xvimage;
|
||||
|
||||
public:
|
||||
XvShmBlitter(XvPortID xvport, unsigned int width, unsigned int height);
|
||||
void blit(Drawable drawable, XvPortID xvport, unsigned width, unsigned height);
|
||||
bool failed();
|
||||
const PixelBuffer inBuffer();
|
||||
~XvShmBlitter();
|
||||
};
|
||||
|
||||
XvShmBlitter::XvShmBlitter(const XvPortID xvport, const unsigned int width, const unsigned int height) {
|
||||
std::cout << "creating xvimage...\n";
|
||||
xvimage = XvShmCreateImage(QX11Info::display(), xvport, 0x59565955, NULL, width * 2, height, &shminfo);
|
||||
|
||||
if (xvimage == NULL) {
|
||||
std::cout << "failed to create xvimage\n";
|
||||
} else {
|
||||
shminfo.shmid = shmget(IPC_PRIVATE, xvimage->data_size, IPC_CREAT | 0777);
|
||||
shminfo.shmaddr = xvimage->data = static_cast<char*>(shmat(shminfo.shmid, 0, 0));
|
||||
shminfo.readOnly = True;
|
||||
XShmAttach(QX11Info::display(), &shminfo);
|
||||
XSync(QX11Info::display(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
XvShmBlitter::~XvShmBlitter() {
|
||||
if (shminfo.shmaddr != NULL) {
|
||||
XShmDetach(QX11Info::display(), &shminfo);
|
||||
XSync(QX11Info::display(), 0);
|
||||
shmdt(shminfo.shmaddr);
|
||||
shmctl(shminfo.shmid, IPC_RMID, 0);
|
||||
}
|
||||
|
||||
if (xvimage != NULL)
|
||||
XFree(xvimage);
|
||||
}
|
||||
|
||||
void XvShmBlitter::blit(const Drawable drawable, const XvPortID xvport, const unsigned width, const unsigned height) {
|
||||
if (xvimage && shminfo.shmaddr) {
|
||||
if (XvShmPutImage(QX11Info::display(), xvport, drawable, DefaultGC(QX11Info::display(), QX11Info::appScreen()), xvimage, 0, 0, xvimage->width, xvimage->height, 0, 0, width, height, False) != Success) {
|
||||
std::cout << "failed to put xvimage\n";
|
||||
// failed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool XvShmBlitter::failed() {
|
||||
return xvimage == NULL || shminfo.shmaddr == NULL;
|
||||
}
|
||||
|
||||
const PixelBuffer XvShmBlitter::inBuffer() {
|
||||
PixelBuffer pixb;
|
||||
pixb.format = PixelBuffer::UYVY;
|
||||
pixb.pixels = xvimage ? xvimage->data + xvimage->offsets[0] : NULL;
|
||||
pixb.pitch = xvimage ? xvimage->pitches[0] >> 2 : 0;
|
||||
|
||||
return pixb;
|
||||
}
|
||||
|
||||
class XvPlainBlitter : public XvSubBlitter {
|
||||
XvImage *xvimage;
|
||||
|
||||
public:
|
||||
XvPlainBlitter(XvPortID xvport, unsigned int width, unsigned int height);
|
||||
void blit(Drawable drawable, XvPortID xvport, unsigned width, unsigned height);
|
||||
bool failed();
|
||||
const PixelBuffer inBuffer();
|
||||
~XvPlainBlitter();
|
||||
};
|
||||
|
||||
XvPlainBlitter::XvPlainBlitter(const XvPortID xvport, const unsigned int width, const unsigned int height) {
|
||||
std::cout << "creating xvimage...\n";
|
||||
xvimage = XvCreateImage(QX11Info::display(), xvport, 0x59565955, NULL, width * 2, height);
|
||||
|
||||
if (xvimage == NULL) {
|
||||
std::cout << "failed to create xvimage\n";
|
||||
} else {
|
||||
xvimage->data = new char[xvimage->data_size];
|
||||
}
|
||||
}
|
||||
|
||||
XvPlainBlitter::~XvPlainBlitter() {
|
||||
if (xvimage) {
|
||||
if (xvimage->data)
|
||||
delete[] xvimage->data;
|
||||
|
||||
XFree(xvimage);
|
||||
}
|
||||
}
|
||||
|
||||
void XvPlainBlitter::blit(const Drawable drawable, const XvPortID xvport, const unsigned width, const unsigned height) {
|
||||
if (xvimage) {
|
||||
if (XvPutImage(QX11Info::display(), xvport, drawable, DefaultGC(QX11Info::display(), QX11Info::appScreen()), xvimage, 0, 0, xvimage->width, xvimage->height, 0, 0, width, height) != Success) {
|
||||
std::cout << "failed to put xvimage\n";
|
||||
// failed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool XvPlainBlitter::failed() {
|
||||
return xvimage == NULL;
|
||||
}
|
||||
|
||||
const PixelBuffer XvPlainBlitter::inBuffer() {
|
||||
PixelBuffer pixb;
|
||||
pixb.format = PixelBuffer::UYVY;
|
||||
pixb.pixels = xvimage ? xvimage->data + xvimage->offsets[0] : NULL;
|
||||
pixb.pitch = xvimage ? xvimage->pitches[0] >> 2 : 0;
|
||||
|
||||
return pixb;
|
||||
}
|
||||
|
||||
static void addPorts(QComboBox *portSelector) {
|
||||
unsigned int num_adaptors;
|
||||
XvAdaptorInfo *adaptor_info;
|
||||
|
||||
if (XvQueryAdaptors(QX11Info::display(), QX11Info::appRootWindow(), &num_adaptors, &adaptor_info) == Success) {
|
||||
for (unsigned int i = 0; i < num_adaptors; ++i) {
|
||||
if (!(adaptor_info[i].type & XvImageMask))
|
||||
continue;
|
||||
|
||||
int numImages;
|
||||
XvImageFormatValues *const formats = XvListImageFormats(QX11Info::display(), adaptor_info[i].base_id, &numImages);
|
||||
|
||||
for (int j = 0; j < numImages; ++j) {
|
||||
if (formats[j].id == 0x59565955) {
|
||||
portSelector->addItem(adaptor_info[i].name, static_cast<qulonglong>(adaptor_info[i].base_id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XFree(formats);
|
||||
}
|
||||
|
||||
XvFreeAdaptorInfo(adaptor_info);
|
||||
} else {
|
||||
std::cout << "failed to query xv adaptors\n";
|
||||
}
|
||||
}
|
||||
|
||||
XvBlitter::XvBlitter(QWidget *parent) :
|
||||
BlitterWidget(QString("Xv"), parent),
|
||||
subBlitter(NULL),
|
||||
// xvbuffer(NULL),
|
||||
// yuv_table(NULL),
|
||||
// xvimage(NULL),
|
||||
inWidth(160),
|
||||
inHeight(144),
|
||||
old_w(0),
|
||||
old_h(0),
|
||||
keepRatio(true),
|
||||
integerScaling(false),
|
||||
portGrabbed(false),
|
||||
failed(true),
|
||||
initialized(false)
|
||||
{
|
||||
|
||||
/*QPalette pal = palette();
|
||||
pal.setColor(QPalette::Window, QColor(2110));
|
||||
setPalette(pal);
|
||||
setBackgroundRole(QPalette::Window);
|
||||
setAutoFillBackground(true);*/
|
||||
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||
setAttribute(Qt::WA_PaintOnScreen, true);
|
||||
|
||||
{
|
||||
XGCValues gcValues;
|
||||
gcValues.foreground = gcValues.background = 2110;
|
||||
gc = XCreateGC(QX11Info::display(), QX11Info::appRootWindow(), GCForeground | GCBackground, &gcValues);
|
||||
}
|
||||
|
||||
confWidget = new QWidget();
|
||||
QHBoxLayout *layout = new QHBoxLayout;
|
||||
layout->setMargin(0);
|
||||
layout->addWidget(new QLabel(QString(tr("Xv Port:"))));
|
||||
portSelector = new QComboBox;
|
||||
addPorts(portSelector);
|
||||
layout->addWidget(portSelector);
|
||||
confWidget->setLayout(layout);
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("xvblitter");
|
||||
|
||||
if ((portIndex = settings.value("portIndex", 0).toUInt()) >= static_cast<unsigned>(portSelector->count()))
|
||||
portIndex = 0;
|
||||
|
||||
settings.endGroup();
|
||||
rejectSettings();
|
||||
}
|
||||
|
||||
bool XvBlitter::isUnusable() {
|
||||
return portSelector->count() == 0;
|
||||
}
|
||||
|
||||
/*static bool getBestPort(const unsigned int num_adaptors, const XvAdaptorInfo *const adaptor_info, XvPortID *const port_out) {
|
||||
for (unsigned int i = 0; i < num_adaptors; ++i) {
|
||||
if (!(adaptor_info[i].type & XvImageMask))
|
||||
continue;
|
||||
|
||||
int numImages;
|
||||
XvImageFormatValues *const formats = XvListImageFormats(QX11Info::display(), adaptor_info[i].base_id, &numImages);
|
||||
|
||||
for (int j = 0; j < numImages; ++j) {
|
||||
if (formats[j].id == 0x59565955 &&
|
||||
XvGrabPort(QX11Info::display(), adaptor_info[i].base_id, CurrentTime) == Success) {
|
||||
*port_out = adaptor_info[i].base_id;
|
||||
XFree(formats);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
XFree(formats);
|
||||
}
|
||||
|
||||
return true;
|
||||
}*/
|
||||
|
||||
void XvBlitter::init() {
|
||||
/*if (yuv_table == NULL) {
|
||||
yuv_table = new u_int32_t[0x10000];
|
||||
u_int32_t r, g, b, y, u, v;
|
||||
for (u_int32_t i = 0;i < 0x10000;++i) {
|
||||
r = (i & 0xF800) >> 8;
|
||||
g = (i & 0x07E0) >> 3;
|
||||
b = (i & 0x001F) << 3;
|
||||
|
||||
y = (r * 299 * 219 + g * 587 * 219 + b * 114 * 219 + (255 * 1000) / 2) / (255 * 1000) + 16;
|
||||
u = (b * 886 * 112 - r * 299 * 112 - g * 587 * 112 + (886 * 255) / 2 + 128 * 886 * 255) / (886 * 255);
|
||||
v = (r * 701 * 112 - b * 114 * 112 - g * 587 * 112 + (701 * 255) / 2 + 128 * 701 * 255) / (701 * 255);
|
||||
|
||||
yuv_table[i] = (y << 24) | (v << 16) | (y << 8) | u;
|
||||
}
|
||||
}*/
|
||||
|
||||
XSync(QX11Info::display(), 0);
|
||||
|
||||
shm = XShmQueryExtension(QX11Info::display());
|
||||
std::cout << "shm: " << shm << std::endl;
|
||||
|
||||
initPort();
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void XvBlitter::uninit() {
|
||||
// delete []xvbuffer;
|
||||
// xvbuffer = NULL;
|
||||
// delete []yuv_table;
|
||||
// yuv_table = NULL;
|
||||
|
||||
if (subBlitter) {
|
||||
delete subBlitter;
|
||||
subBlitter = NULL;
|
||||
}
|
||||
|
||||
if (portGrabbed) {
|
||||
XvUngrabPort(QX11Info::display(), xvport, CurrentTime);
|
||||
portGrabbed = false;
|
||||
}
|
||||
|
||||
failed = true;
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
XvBlitter::~XvBlitter() {
|
||||
uninit();
|
||||
XFreeGC(QX11Info::display(), gc);
|
||||
delete confWidget;
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("xvblitter");
|
||||
settings.setValue("portIndex", portIndex);
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
int XvBlitter::sync(const bool turbo) {
|
||||
if (failed || subBlitter->failed())
|
||||
return -1;
|
||||
|
||||
return BlitterWidget::sync(turbo);
|
||||
}
|
||||
|
||||
void XvBlitter::keepAspectRatio(const bool enable) {
|
||||
keepRatio = enable;
|
||||
}
|
||||
|
||||
bool XvBlitter::keepsAspectRatio() {
|
||||
return keepRatio;
|
||||
}
|
||||
|
||||
void XvBlitter::scaleByInteger(const bool enable) {
|
||||
integerScaling = enable;
|
||||
}
|
||||
|
||||
bool XvBlitter::scalesByInteger() {
|
||||
return integerScaling;
|
||||
}
|
||||
|
||||
void XvBlitter::paintEvent(QPaintEvent *event) {
|
||||
event->accept();
|
||||
const QRect &rect = event->rect();
|
||||
XFillRectangle(QX11Info::display(), winId(), gc, rect.x(), rect.y(), rect.width(), rect.height());
|
||||
|
||||
if (!failed)
|
||||
subBlitter->blit(winId(), xvport, width(), height());
|
||||
}
|
||||
|
||||
void XvBlitter::setBufferDimensions(const unsigned int width, const unsigned int height) {
|
||||
inWidth = width;
|
||||
inHeight = height;
|
||||
|
||||
if (subBlitter) {
|
||||
delete subBlitter;
|
||||
subBlitter = NULL;
|
||||
}
|
||||
|
||||
if (shm) {
|
||||
subBlitter = new XvShmBlitter(xvport, width, height);
|
||||
|
||||
if (subBlitter->failed()) {
|
||||
shm = false;
|
||||
delete subBlitter;
|
||||
}
|
||||
}
|
||||
|
||||
if (!shm)
|
||||
subBlitter = new XvPlainBlitter(xvport, width, height);
|
||||
|
||||
// delete []xvbuffer;
|
||||
// xvbuffer = new u_int16_t[width*height];
|
||||
|
||||
old_w = old_h = 0;
|
||||
}
|
||||
|
||||
const PixelBuffer XvBlitter::inBuffer() {
|
||||
/*PixelBuffer pixb;
|
||||
pixb.format = PixelBuffer::RGB16;
|
||||
pixb.pixels = xvbuffer;
|
||||
pixb.pitch = inWidth;
|
||||
return pixb;*/
|
||||
|
||||
return subBlitter->inBuffer();
|
||||
}
|
||||
|
||||
void XvBlitter::blit() {
|
||||
if (!failed) {
|
||||
/*{
|
||||
u_int32_t *yuv_pixel = (u_int32_t*)(subBlitter->inBuffer().pixels);
|
||||
const u_int16_t *s = xvbuffer;
|
||||
unsigned n = inWidth * inHeight;
|
||||
|
||||
while (n--) {
|
||||
*yuv_pixel++ = yuv_table[*s++];
|
||||
}
|
||||
}*/
|
||||
|
||||
subBlitter->blit(winId(), xvport, width(), height());
|
||||
XSync(QX11Info::display(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*void XvBlitter::resizeEvent(QResizeEvent *event) {
|
||||
// std::cout << "resizeEvent\n";
|
||||
if (keepRatio) {
|
||||
// static int old_w=0;
|
||||
// static int old_h=0;
|
||||
if (width() != old_w || height() != old_h) {
|
||||
if (integerScaling) {
|
||||
unsigned int scale = std::min((width() / inWidth), (height() / inHeight));
|
||||
old_w = inWidth * scale;
|
||||
old_h = inHeight * scale;
|
||||
setGeometry(x() + (width() - old_w) / 2, y() + (height() - old_h) / 2, old_w, old_h);
|
||||
} else {
|
||||
if ((static_cast<double>(width()) / static_cast<double>(height())) > (10.0 / 9.0)) {
|
||||
old_w = height() * 10.0 / 9.0 + 0.5;
|
||||
old_h = height();
|
||||
if (old_w < width())
|
||||
setGeometry(x() + (width() - old_w) / 2, y(), old_w, old_h);
|
||||
} else {
|
||||
old_w = width();
|
||||
old_h = old_w * 0.9 + 0.5;
|
||||
if (old_h < height())
|
||||
setGeometry(x(), y() + (height() - old_h) / 2, old_w, old_h);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
void XvBlitter::initPort() {
|
||||
xvport = portSelector->itemData(portIndex).toULongLong();
|
||||
failed = !(portGrabbed = (XvGrabPort(QX11Info::display(), xvport, CurrentTime) == Success));
|
||||
|
||||
if (!failed) {
|
||||
Atom atom = XInternAtom(QX11Info::display(), "XV_AUTOPAINT_COLORKEY", True);
|
||||
|
||||
if (atom != None)
|
||||
XvSetPortAttribute(QX11Info::display(), xvport, atom, 0);
|
||||
|
||||
atom = XInternAtom(QX11Info::display(), "XV_COLORKEY", True);
|
||||
|
||||
if (atom != None)
|
||||
XvSetPortAttribute(QX11Info::display(), xvport, atom, 2110);
|
||||
}
|
||||
}
|
||||
|
||||
void XvBlitter::acceptSettings() {
|
||||
portIndex = portSelector->currentIndex();
|
||||
|
||||
if (initialized) {
|
||||
if (portGrabbed) {
|
||||
XvUngrabPort(QX11Info::display(), xvport, CurrentTime);
|
||||
portGrabbed = false;
|
||||
}
|
||||
|
||||
initPort();
|
||||
setBufferDimensions(inWidth, inHeight);
|
||||
}
|
||||
}
|
||||
|
||||
void XvBlitter::rejectSettings() {
|
||||
portSelector->setCurrentIndex(portIndex);
|
||||
}
|
82
gambatte_qt/src/blitterwidgets/xvblitter.h
Normal file
82
gambatte_qt/src/blitterwidgets/xvblitter.h
Normal file
@ -0,0 +1,82 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef XVBLITTER_H
|
||||
#define XVBLITTER_H
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
#include "../blitterwidget.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/XShm.h>
|
||||
#include <X11/extensions/Xvlib.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
class XvSubBlitter;
|
||||
|
||||
class XvBlitter : public BlitterWidget {
|
||||
// XShmSegmentInfo shminfo;
|
||||
XvSubBlitter *subBlitter;
|
||||
XvPortID xvport;
|
||||
// u_int16_t *xvbuffer;
|
||||
// u_int32_t *yuv_table;
|
||||
// XvImage *xvimage;
|
||||
QWidget *confWidget;
|
||||
QComboBox *portSelector;
|
||||
unsigned int inWidth, inHeight;
|
||||
int old_w, old_h;
|
||||
unsigned portIndex;
|
||||
GC gc;
|
||||
// bool init;
|
||||
bool keepRatio;
|
||||
bool integerScaling;
|
||||
bool shm;
|
||||
bool portGrabbed;
|
||||
bool failed;
|
||||
bool initialized;
|
||||
|
||||
void initPort();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
// void resizeEvent(QResizeEvent *event);
|
||||
|
||||
public:
|
||||
XvBlitter(QWidget *parent = 0);
|
||||
~XvBlitter();
|
||||
void init();
|
||||
void uninit();
|
||||
// void init(const unsigned int srcW, const unsigned int srcH);
|
||||
bool isUnusable();
|
||||
void keepAspectRatio(const bool enable);
|
||||
bool keepsAspectRatio();
|
||||
void scaleByInteger(const bool enable);
|
||||
bool scalesByInteger();
|
||||
int sync(bool turbo);
|
||||
void setBufferDimensions(const unsigned int width, const unsigned int height);
|
||||
const PixelBuffer inBuffer();
|
||||
void blit();
|
||||
|
||||
QWidget* settingsWidget() { return confWidget; }
|
||||
void acceptSettings();
|
||||
void rejectSettings();
|
||||
};
|
||||
|
||||
#endif
|
45
gambatte_qt/src/fullrestoggler.h
Normal file
45
gambatte_qt/src/fullrestoggler.h
Normal file
@ -0,0 +1,45 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef FULLRESTOGGLER_H
|
||||
#define FULLRESTOGGLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <vector>
|
||||
|
||||
#include "resinfo.h"
|
||||
|
||||
class FullResToggler : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
virtual ~FullResToggler() {};
|
||||
virtual unsigned currentResIndex() const = 0;
|
||||
virtual unsigned currentRateIndex() const = 0;
|
||||
virtual bool isFullRes() const = 0;
|
||||
virtual void setMode(unsigned newID, unsigned rate) = 0;
|
||||
virtual void setFullRes(bool enable) = 0;
|
||||
virtual void emitRate() = 0;
|
||||
virtual const std::vector<ResInfo>& resVector() const = 0;
|
||||
|
||||
signals:
|
||||
void rateChange(int newHz);
|
||||
// void modeChange();
|
||||
};
|
||||
|
||||
#endif
|
124
gambatte_qt/src/fullrestogglers/gditoggler.cpp
Normal file
124
gambatte_qt/src/fullrestogglers/gditoggler.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "gditoggler.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
GdiToggler::GdiToggler() :
|
||||
isFull(false)
|
||||
{
|
||||
DEVMODE devmode;
|
||||
devmode.dmSize = sizeof(DEVMODE);
|
||||
devmode.dmDriverExtra = 0;
|
||||
|
||||
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devmode);
|
||||
const unsigned originalWidth = devmode.dmPelsWidth;
|
||||
const unsigned originalHeight = devmode.dmPelsHeight;
|
||||
const short originalRate = devmode.dmDisplayFrequency;
|
||||
const unsigned bpp = devmode.dmBitsPerPel;
|
||||
|
||||
int n = 0;
|
||||
|
||||
while (EnumDisplaySettings(NULL, n++, &devmode)) {
|
||||
if (devmode.dmBitsPerPel != bpp)
|
||||
continue;
|
||||
|
||||
ResInfo info;
|
||||
info.w = devmode.dmPelsWidth;
|
||||
info.h = devmode.dmPelsHeight;
|
||||
|
||||
if (infoVector.empty() || infoVector.back().w != info.w || infoVector.back().h != info.h) {
|
||||
infoVector.push_back(info);
|
||||
}
|
||||
|
||||
infoVector.back().rates.push_back(devmode.dmDisplayFrequency);
|
||||
}
|
||||
|
||||
{
|
||||
unsigned i = 0;
|
||||
|
||||
while (infoVector[i].w != originalWidth || infoVector[i].h != originalHeight)
|
||||
++i;
|
||||
|
||||
fullResIndex = originalResIndex = i;
|
||||
}
|
||||
|
||||
{
|
||||
unsigned i = 0;
|
||||
|
||||
while (infoVector[fullResIndex].rates[i] != originalRate)
|
||||
++i;
|
||||
|
||||
fullRateIndex = originalRateIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
GdiToggler::~GdiToggler() {
|
||||
setFullRes(false);
|
||||
}
|
||||
|
||||
bool GdiToggler::isFullRes() const {
|
||||
return isFull;
|
||||
}
|
||||
|
||||
void GdiToggler::setMode(const unsigned resIndex, const unsigned rateIndex) {
|
||||
fullResIndex = resIndex;
|
||||
fullRateIndex = rateIndex;
|
||||
|
||||
if (isFullRes())
|
||||
setFullRes(true);
|
||||
}
|
||||
|
||||
void GdiToggler::setFullRes(const bool enable) {
|
||||
DEVMODE devmode;
|
||||
devmode.dmSize = sizeof(DEVMODE);
|
||||
devmode.dmDriverExtra = 0;
|
||||
|
||||
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devmode);
|
||||
const unsigned currentWidth = devmode.dmPelsWidth;
|
||||
const unsigned currentHeight = devmode.dmPelsHeight;
|
||||
const unsigned currentRate = devmode.dmDisplayFrequency;
|
||||
|
||||
{
|
||||
const ResInfo &info = infoVector[enable ? fullResIndex : originalResIndex];
|
||||
devmode.dmPelsWidth = info.w;
|
||||
devmode.dmPelsHeight = info.h;
|
||||
devmode.dmDisplayFrequency = info.rates[enable ? fullRateIndex : originalRateIndex];
|
||||
}
|
||||
|
||||
if (devmode.dmPelsWidth != currentWidth || devmode.dmPelsHeight != currentHeight || devmode.dmDisplayFrequency != currentRate) {
|
||||
devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
|
||||
ChangeDisplaySettings(&devmode, CDS_FULLSCREEN);
|
||||
|
||||
//emit modeChange();
|
||||
|
||||
if (devmode.dmDisplayFrequency != currentRate)
|
||||
emit rateChange(devmode.dmDisplayFrequency);
|
||||
}
|
||||
|
||||
isFull = enable;
|
||||
}
|
||||
|
||||
void GdiToggler::emitRate() {
|
||||
DEVMODE devmode;
|
||||
devmode.dmSize = sizeof(DEVMODE);
|
||||
devmode.dmDriverExtra = 0;
|
||||
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devmode);
|
||||
emit rateChange(devmode.dmDisplayFrequency);
|
||||
}
|
56
gambatte_qt/src/fullrestogglers/gditoggler.h
Normal file
56
gambatte_qt/src/fullrestogglers/gditoggler.h
Normal file
@ -0,0 +1,56 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef GDITOGGLER_H_
|
||||
#define GDITOGGLER_H_
|
||||
|
||||
#include "../fullrestoggler.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <vector>
|
||||
|
||||
#include "../resinfo.h"
|
||||
|
||||
class GdiToggler : public FullResToggler {
|
||||
Q_OBJECT
|
||||
|
||||
std::vector<ResInfo> infoVector;
|
||||
unsigned originalResIndex;
|
||||
unsigned originalRateIndex;
|
||||
unsigned fullResIndex;
|
||||
unsigned fullRateIndex;
|
||||
bool isFull;
|
||||
|
||||
public:
|
||||
GdiToggler();
|
||||
~GdiToggler();
|
||||
unsigned currentResIndex() const { return fullResIndex; }
|
||||
unsigned currentRateIndex() const { return fullRateIndex; }
|
||||
bool isFullRes() const;
|
||||
void setMode(unsigned resIndex, unsigned rateIndex);
|
||||
void setFullRes(bool enable);
|
||||
void emitRate();
|
||||
const std::vector<ResInfo>& resVector() const { return infoVector; }
|
||||
|
||||
signals:
|
||||
void rateChange(int newHz);
|
||||
// void modeChange();
|
||||
};
|
||||
|
||||
#endif /*GDITOGGLER_H_*/
|
40
gambatte_qt/src/fullrestogglers/nulltoggler.h
Normal file
40
gambatte_qt/src/fullrestogglers/nulltoggler.h
Normal file
@ -0,0 +1,40 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef NULLTOGGLER_H
|
||||
#define NULLTOGGLER_H
|
||||
|
||||
#include "../fullrestoggler.h"
|
||||
|
||||
class NullToggler : public FullResToggler {
|
||||
const std::vector<ResInfo> nullVector;
|
||||
bool fullRes;
|
||||
|
||||
public:
|
||||
NullToggler() : fullRes(false) {}
|
||||
|
||||
unsigned currentResIndex() const { return 0; }
|
||||
unsigned currentRateIndex() const { return 0; }
|
||||
bool isFullRes() const { return fullRes; }
|
||||
void setMode(unsigned /*newID*/, unsigned /*rate*/) {}
|
||||
void setFullRes(const bool enable) { fullRes = enable; }
|
||||
void emitRate() {}
|
||||
const std::vector<ResInfo>& resVector() const { return nullVector; }
|
||||
};
|
||||
|
||||
#endif
|
120
gambatte_qt/src/fullrestogglers/xrandrtoggler.cpp
Normal file
120
gambatte_qt/src/fullrestogglers/xrandrtoggler.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "xrandrtoggler.h"
|
||||
|
||||
#include <QX11Info>
|
||||
|
||||
bool XRandRToggler::isUsable() {
|
||||
int unused;
|
||||
return XQueryExtension(QX11Info::display(), "RANDR", &unused, &unused, &unused);
|
||||
}
|
||||
|
||||
XRandRToggler::XRandRToggler() :
|
||||
isFull(false)
|
||||
{
|
||||
XRRScreenConfiguration *config = XRRGetScreenInfo(QX11Info::display(), QX11Info::appRootWindow());
|
||||
/*Rotation */rotation = 0;
|
||||
fullResIndex = originalResIndex = XRRConfigCurrentConfiguration(config, &rotation);
|
||||
const short rate = XRRConfigCurrentRate(config);
|
||||
|
||||
int nSizes;
|
||||
XRRScreenSize *randrSizes = XRRConfigSizes(config, &nSizes);
|
||||
|
||||
for (int i = 0; i < nSizes; ++i) {
|
||||
ResInfo info;
|
||||
info.w = randrSizes[i].width;
|
||||
info.h = randrSizes[i].height;
|
||||
|
||||
int nHz;
|
||||
short *rates = XRRConfigRates(config, i, &nHz);
|
||||
|
||||
for (int j = 0; j < nHz; ++j)
|
||||
info.rates.push_back(rates[j]);
|
||||
|
||||
infoVector.push_back(info);
|
||||
}
|
||||
|
||||
{
|
||||
unsigned i = 0;
|
||||
|
||||
while (infoVector[fullResIndex].rates[i] != rate)
|
||||
++i;
|
||||
|
||||
fullRateIndex = originalRateIndex = i;
|
||||
}
|
||||
|
||||
XRRFreeScreenConfigInfo(config);
|
||||
}
|
||||
|
||||
XRandRToggler::~XRandRToggler() {
|
||||
setFullRes(false);
|
||||
// XRRFreeScreenConfigInfo(config);
|
||||
}
|
||||
|
||||
bool XRandRToggler::isFullRes() const {
|
||||
return isFull;
|
||||
}
|
||||
|
||||
void XRandRToggler::setMode(const unsigned resIndex, const unsigned rateIndex) {
|
||||
fullResIndex = resIndex;
|
||||
fullRateIndex = rateIndex;
|
||||
|
||||
if (isFullRes())
|
||||
setFullRes(true);
|
||||
}
|
||||
|
||||
void XRandRToggler::setFullRes(const bool enable) {
|
||||
XRRScreenConfiguration *config = XRRGetScreenInfo(QX11Info::display(), QX11Info::appRootWindow());
|
||||
// Rotation rotation=0;
|
||||
SizeID currentID = XRRConfigCurrentConfiguration(config, &rotation);
|
||||
int currentRate = XRRConfigCurrentRate(config);
|
||||
// std::cout << "current rate: " << currentRate << "\n";
|
||||
|
||||
SizeID newID;
|
||||
int newRate;
|
||||
|
||||
if (enable) {
|
||||
newID = fullResIndex;
|
||||
newRate = infoVector[fullResIndex].rates[fullRateIndex];
|
||||
} else {
|
||||
newID = originalResIndex;
|
||||
newRate = infoVector[originalResIndex].rates[originalRateIndex];
|
||||
}
|
||||
|
||||
// std::cout << "new rate: " << newRate << "\n";
|
||||
|
||||
if (newID != currentID || newRate != currentRate) {
|
||||
XRRSetScreenConfigAndRate(QX11Info::display(), config, QX11Info::appRootWindow(), newID, rotation, newRate, CurrentTime);
|
||||
|
||||
//emit modeChange();
|
||||
|
||||
if (newRate != currentRate)
|
||||
emit rateChange(newRate);
|
||||
}
|
||||
|
||||
XRRFreeScreenConfigInfo(config);
|
||||
|
||||
isFull = enable;
|
||||
}
|
||||
|
||||
void XRandRToggler::emitRate() {
|
||||
XRRScreenConfiguration *config = XRRGetScreenInfo(QX11Info::display(), QX11Info::appRootWindow());
|
||||
emit rateChange(XRRConfigCurrentRate(config));
|
||||
XRRFreeScreenConfigInfo(config);
|
||||
}
|
61
gambatte_qt/src/fullrestogglers/xrandrtoggler.h
Normal file
61
gambatte_qt/src/fullrestogglers/xrandrtoggler.h
Normal file
@ -0,0 +1,61 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef XRANDRTOGGLER_H
|
||||
#define XRANDRTOGGLER_H
|
||||
|
||||
#include "../fullrestoggler.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <vector>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
|
||||
#include "../resinfo.h"
|
||||
|
||||
class XRandRToggler : public FullResToggler {
|
||||
Q_OBJECT
|
||||
|
||||
std::vector<ResInfo> infoVector;
|
||||
// XRRScreenConfiguration *config;
|
||||
unsigned originalResIndex;
|
||||
unsigned fullResIndex;
|
||||
Rotation rotation;
|
||||
unsigned originalRateIndex;
|
||||
unsigned fullRateIndex;
|
||||
bool isFull;
|
||||
|
||||
public:
|
||||
static bool isUsable();
|
||||
XRandRToggler();
|
||||
~XRandRToggler();
|
||||
unsigned currentResIndex() const { return fullResIndex; }
|
||||
unsigned currentRateIndex() const { return fullRateIndex; }
|
||||
bool isFullRes() const;
|
||||
void setMode(unsigned resIndex, unsigned rateIndex);
|
||||
void setFullRes(bool enable);
|
||||
void emitRate();
|
||||
const std::vector<ResInfo>& resVector() const { return infoVector; }
|
||||
|
||||
signals:
|
||||
void rateChange(int newHz);
|
||||
// void modeChange();
|
||||
};
|
||||
|
||||
#endif
|
625
gambatte_qt/src/gambatte_qt.cpp
Normal file
625
gambatte_qt/src/gambatte_qt.cpp
Normal file
@ -0,0 +1,625 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <QtGui>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "gambatte_qt.h"
|
||||
#include "blitterwidgets/qpainterblitter.h"
|
||||
#include "blitterwidgets/qglblitter.h"
|
||||
#include "videodialog.h"
|
||||
#include "inputdialog.h"
|
||||
#include "blittercontainer.h"
|
||||
|
||||
#include "addaudioengines.h"
|
||||
#include "addblitterwidgets.h"
|
||||
#include "getfullrestoggler.h"
|
||||
#include "audioengine.h"
|
||||
#include "fullrestoggler.h"
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "resizesignalingmenubar.h"
|
||||
|
||||
GambatteQt::GambatteQt() : resetVideoBuffer(gambatte) {
|
||||
blitter = NULL;
|
||||
ae = NULL;
|
||||
timerId = 0;
|
||||
running = false;
|
||||
turbo = false;
|
||||
//samplesPrFrame = ((sampleFormat.rate * 4389) / 262144) + 1;
|
||||
samplesPrFrame = 0;
|
||||
sndBuffer = NULL;
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
{
|
||||
ResizeSignalingMenuBar *m = new ResizeSignalingMenuBar;
|
||||
connect(m, SIGNAL(resized()), this, SLOT(resetWindowSize()));
|
||||
setMenuBar(m);
|
||||
}
|
||||
|
||||
{
|
||||
QSettings settings;
|
||||
settings.beginGroup("mainwindow");
|
||||
resize(settings.value("size", QSize(160, 144)).toSize());
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
addAudioEngines(audioEngines, winId());
|
||||
|
||||
inputDialog = new InputDialog(this);
|
||||
|
||||
fullResToggler = getFullResToggler();
|
||||
|
||||
addBlitterWidgets(blitters, resetVideoBuffer);
|
||||
blitters.push_back(new QGLBlitter);
|
||||
blitters.push_back(new QPainterBlitter(resetVideoBuffer));
|
||||
|
||||
for (std::vector<BlitterWidget*>::iterator it = blitters.begin(); it != blitters.end();) {
|
||||
if ((*it)->isUnusable()) {
|
||||
delete *it;
|
||||
it = blitters.erase(it);
|
||||
} else
|
||||
++it;
|
||||
}
|
||||
|
||||
videoDialog = new VideoDialog(blitters, gambatte.filterInfo(), *fullResToggler, this);
|
||||
connect(videoDialog, SIGNAL(accepted()), this, SLOT(videoSettingsChange()));
|
||||
|
||||
/*QPalette pal = palette();
|
||||
pal.setColor(QPalette::AlternateBase, QColor(0, 0, 0));
|
||||
setPalette(pal);
|
||||
setBackgroundRole(QPalette::AlternateBase);
|
||||
setAutoFillBackground(true);*/
|
||||
|
||||
blitterContainer = new BlitterContainer(*fullResToggler);
|
||||
blitterContainer->setMinimumSize(160, 144);
|
||||
setCentralWidget(blitterContainer);
|
||||
|
||||
createActions();
|
||||
createMenus();
|
||||
|
||||
setWindowTitle("gambatte");
|
||||
|
||||
gambatte.setInputStateGetter(&inputGetter);
|
||||
|
||||
{
|
||||
QSettings iniSettings(QSettings::IniFormat, QSettings::UserScope, "gambatte", "gambatte_qt");
|
||||
QString savepath = iniSettings.fileName();
|
||||
savepath.truncate(iniSettings.fileName().lastIndexOf("/") + 1);
|
||||
savepath += "saves";
|
||||
QDir::root().mkpath(savepath);
|
||||
gambatte.set_savedir(savepath.toAscii().data());
|
||||
}
|
||||
|
||||
videoSettingsChange();
|
||||
|
||||
setFocus();
|
||||
}
|
||||
|
||||
GambatteQt::~GambatteQt() {
|
||||
delete fullResToggler;
|
||||
|
||||
for (uint i = 0; i < blitters.size(); ++i)
|
||||
delete blitters[i];
|
||||
|
||||
for (uint i = 0; i < audioEngines.size(); ++i)
|
||||
delete audioEngines[i];
|
||||
|
||||
delete []sndBuffer;
|
||||
}
|
||||
|
||||
void GambatteQt::open() {
|
||||
pause();
|
||||
|
||||
QString fileName = QFileDialog::getOpenFileName(this, "Open", recentFileActs[0]->data().toString(), "Game Boy ROM Images (*.gb *.gbc *.sgb)");
|
||||
if (!fileName.isEmpty())
|
||||
loadFile(fileName);
|
||||
|
||||
unpause();
|
||||
}
|
||||
|
||||
void GambatteQt::openRecentFile() {
|
||||
QAction *action = qobject_cast<QAction *>(sender());
|
||||
if (action)
|
||||
loadFile(action->data().toString());
|
||||
}
|
||||
|
||||
void GambatteQt::about() {
|
||||
pause();
|
||||
|
||||
QMessageBox::about(
|
||||
this,
|
||||
tr("About gambatte"),
|
||||
tr("gambatte is a Game Boy / Game Boy Color emulator.")
|
||||
);
|
||||
|
||||
unpause();
|
||||
}
|
||||
|
||||
void GambatteQt::resetWindowSize() {
|
||||
if (isFullScreen())
|
||||
return;
|
||||
|
||||
const QSize s(videoDialog->winRes());
|
||||
|
||||
if (s == QSize(-1, -1)) {
|
||||
setMinimumSize(0, 0);
|
||||
setMaximumSize(0xFFFFFF, 0xFFFFFF);
|
||||
} else {
|
||||
setFixedSize(s.width(), s.height() + (menuBar()->isVisible() ? menuBar()->height() : 0));
|
||||
}
|
||||
}
|
||||
|
||||
void GambatteQt::toggleFullScreen() {
|
||||
if (fullResToggler->isFullRes()) {
|
||||
fullResToggler->setFullRes(false);
|
||||
showNormal();
|
||||
resetWindowSize();
|
||||
} else {
|
||||
fullResToggler->setFullRes(true);
|
||||
showFullScreen();
|
||||
}
|
||||
}
|
||||
|
||||
void GambatteQt::toggleMenuHidden() {
|
||||
menuBar()->setVisible(!menuBar()->isVisible());
|
||||
|
||||
if (menuBar()->isVisible())
|
||||
centralWidget()->unsetCursor();
|
||||
else
|
||||
centralWidget()->setCursor(Qt::BlankCursor);
|
||||
|
||||
resetWindowSize();
|
||||
}
|
||||
|
||||
void GambatteQt::videoSettingsChange() {
|
||||
{
|
||||
const int engineIndex = videoDialog->engine();
|
||||
|
||||
if (blitter != blitters[engineIndex]) {
|
||||
bool updatesEnabled = true;
|
||||
bool visible = false;
|
||||
|
||||
if (blitter) {
|
||||
updatesEnabled = blitter->updatesEnabled();
|
||||
visible = blitter->isVisible();
|
||||
disconnect(fullResToggler, SIGNAL(rateChange(int)), blitter, SLOT(rateChange(int)));
|
||||
|
||||
if (running)
|
||||
blitter->uninit();
|
||||
|
||||
blitter->setVisible(false);
|
||||
}
|
||||
|
||||
blitter = blitters[engineIndex];
|
||||
blitter->setVisible(false);
|
||||
blitter->setUpdatesEnabled(updatesEnabled);
|
||||
//connect(fullResToggler, SIGNAL(modeChange()), blitter, SLOT(modeChange()));
|
||||
connect(fullResToggler, SIGNAL(rateChange(int)), blitter, SLOT(rateChange(int)));
|
||||
fullResToggler->emitRate();
|
||||
blitterContainer->setBlitter(blitter);
|
||||
blitter->setVisible(visible);
|
||||
|
||||
if (running) {
|
||||
// XSync(QX11Info::display(), 0);
|
||||
blitter->init();
|
||||
gambatte.setVideoBlitter(blitter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gambatte.setVideoFilter(videoDialog->filterIndex());
|
||||
centralWidget()->setMinimumSize(gambatte.videoWidth(), gambatte.videoHeight());
|
||||
|
||||
resetWindowSize();
|
||||
|
||||
if (fullResToggler->currentResIndex() != videoDialog->fullMode() ||
|
||||
fullResToggler->currentRateIndex() != videoDialog->fullRate()) {
|
||||
fullResToggler->setMode(videoDialog->fullMode(), videoDialog->fullRate());
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
if (fullResToggler->isFullRes()) {
|
||||
showNormal();
|
||||
showFullScreen();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
setSamplesPrFrame();
|
||||
|
||||
blitter->keepAspectRatio(videoDialog->keepsRatio());
|
||||
blitter->scaleByInteger(videoDialog->scalesByInteger());
|
||||
|
||||
blitterContainer->updateLayout();
|
||||
}
|
||||
|
||||
void GambatteQt::createActions() {
|
||||
exitAct = new QAction(tr("E&xit"), this);
|
||||
exitAct->setShortcut(tr("Ctrl+Q"));
|
||||
exitAct->setStatusTip(tr("Exit the application"));
|
||||
connect(exitAct, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
|
||||
|
||||
hideMenuAct = new QAction(this);
|
||||
hideMenuAct->setVisible(false);
|
||||
hideMenuAct->setShortcut(tr("Esc"));
|
||||
connect(hideMenuAct, SIGNAL(triggered()), this, SLOT(toggleMenuHidden()));
|
||||
|
||||
fsAct = new QAction(tr("&Full screen"), this);
|
||||
fsAct->setShortcut(tr("Ctrl+F"));
|
||||
fsAct->setCheckable(true);
|
||||
connect(fsAct, SIGNAL(triggered()), this, SLOT(toggleFullScreen()));
|
||||
}
|
||||
|
||||
void GambatteQt::createMenus() {
|
||||
QAction *openAct = new QAction(tr("&Open..."), this);
|
||||
openAct->setShortcut(tr("Ctrl+O"));
|
||||
openAct->setStatusTip(tr("Open an existing file"));
|
||||
connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
|
||||
|
||||
for (int i = 0; i < MaxRecentFiles; ++i) {
|
||||
recentFileActs[i] = new QAction(this);
|
||||
recentFileActs[i]->setVisible(false);
|
||||
connect(recentFileActs[i], SIGNAL(triggered()), this, SLOT(openRecentFile()));
|
||||
}
|
||||
|
||||
QAction *aboutAct = new QAction(tr("&About"), this);
|
||||
aboutAct->setStatusTip(tr("Show the application's About box"));
|
||||
connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
|
||||
|
||||
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
|
||||
fileMenu->addAction(openAct);
|
||||
separatorAct = fileMenu->addSeparator();
|
||||
for (int i = 0; i < MaxRecentFiles; ++i)
|
||||
fileMenu->addAction(recentFileActs[i]);
|
||||
fileMenu->addSeparator();
|
||||
fileMenu->addAction(exitAct);
|
||||
updateRecentFileActions();
|
||||
|
||||
QMenu *videom = menuBar()->addMenu(tr("&Settings"));
|
||||
|
||||
{
|
||||
QAction *inputDialogAct = new QAction(tr("&Input..."), this);
|
||||
connect(inputDialogAct, SIGNAL(triggered()), this, SLOT(execInputDialog()));
|
||||
videom->addAction(inputDialogAct);
|
||||
}
|
||||
|
||||
{
|
||||
QAction *videoDialogAct = new QAction(tr("&Video..."), this);
|
||||
connect(videoDialogAct, SIGNAL(triggered()), this, SLOT(execVideoDialog()));
|
||||
videom->addAction(videoDialogAct);
|
||||
}
|
||||
|
||||
videom->addAction(fsAct);
|
||||
videom->addAction(hideMenuAct);
|
||||
|
||||
menuBar()->addSeparator();
|
||||
|
||||
QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
|
||||
helpMenu->addAction(aboutAct);
|
||||
}
|
||||
|
||||
void GambatteQt::loadFile(const QString &fileName) {
|
||||
if (gambatte.load((fileName.toAscii()).data())) {
|
||||
stop();
|
||||
QMessageBox::critical(
|
||||
this,
|
||||
tr("Error"),
|
||||
tr("Failed to load file ") + fileName + "."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
setCurrentFile(fileName);
|
||||
|
||||
run();
|
||||
}
|
||||
|
||||
void GambatteQt::execDialog(QDialog *const dialog) {
|
||||
pause();
|
||||
dialog->exec();
|
||||
unpause();
|
||||
}
|
||||
|
||||
void GambatteQt::execVideoDialog() {
|
||||
execDialog(videoDialog);
|
||||
}
|
||||
|
||||
void GambatteQt::execInputDialog() {
|
||||
execDialog(inputDialog);
|
||||
}
|
||||
|
||||
void GambatteQt::setSamplesPrFrame() {
|
||||
const BlitterWidget::Rational r = blitter->frameTime();
|
||||
const unsigned old = samplesPrFrame;
|
||||
samplesPrFrame = ((sampleRate * r.numerator) / r.denominator) + 1;
|
||||
|
||||
if (old != samplesPrFrame) {
|
||||
delete []sndBuffer;
|
||||
sndBuffer = new int16_t[(samplesPrFrame + 4) * 2];
|
||||
|
||||
samplesCalc.setBaseSamples(samplesPrFrame);
|
||||
}
|
||||
}
|
||||
|
||||
AudioEngine* GambatteQt::initAudio() {
|
||||
AudioEngine *ae;
|
||||
int rate = -1;
|
||||
|
||||
while (!audioEngines.empty()) {
|
||||
ae = audioEngines.back();
|
||||
rate = ae->init();
|
||||
|
||||
if (rate >= 0)
|
||||
break;
|
||||
|
||||
delete ae;
|
||||
audioEngines.pop_back();
|
||||
}
|
||||
|
||||
if (rate < 0) {
|
||||
ae = NULL;
|
||||
rate = 0;
|
||||
}
|
||||
|
||||
sampleRate = rate;
|
||||
|
||||
setSamplesPrFrame();
|
||||
|
||||
return ae;
|
||||
}
|
||||
|
||||
void GambatteQt::timerEvent(QTimerEvent */*event*/) {
|
||||
gambatte.runFor(70224);
|
||||
|
||||
if (!turbo)
|
||||
gambatte.fill_buffer(reinterpret_cast<uint16_t*>(sndBuffer), samplesCalc.getSamples());
|
||||
|
||||
if (blitter->sync(turbo)) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Video engine failure."));
|
||||
blitter->uninit();
|
||||
blitter->init();
|
||||
gambatte.setVideoBlitter(blitter);
|
||||
|
||||
if (ae)
|
||||
ae->pause();
|
||||
|
||||
videoDialog->exec();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!turbo) {
|
||||
if (ae) {
|
||||
unsigned lastSamples = samplesCalc.getSamples();
|
||||
|
||||
const AudioEngine::BufferState bufState = ae->bufferState();
|
||||
|
||||
if (bufState.fromUnderrun != 0xFFFFFFFF)
|
||||
samplesCalc.update(bufState.fromUnderrun, bufState.fromOverflow);
|
||||
|
||||
if (ae->write(sndBuffer, lastSamples) < 0) {
|
||||
delete ae;
|
||||
audioEngines.pop_back();
|
||||
ae = initAudio();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GambatteQt::run() {
|
||||
if (running)
|
||||
return;
|
||||
|
||||
running = true;
|
||||
|
||||
memset(&inputGetter.is, 0, sizeof(inputGetter.is));
|
||||
|
||||
ae = initAudio();
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
timeBeginPeriod(1);
|
||||
#endif
|
||||
|
||||
blitter->setVisible(true);
|
||||
blitter->init();
|
||||
gambatte.setVideoBlitter(blitter);
|
||||
|
||||
timerId = startTimer(0);
|
||||
}
|
||||
|
||||
void GambatteQt::stop() {
|
||||
if (!running)
|
||||
return;
|
||||
|
||||
running = false;
|
||||
|
||||
killTimer(timerId);
|
||||
|
||||
blitter->uninit();
|
||||
blitter->setVisible(false);
|
||||
|
||||
ae->uninit();
|
||||
ae = NULL;
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
timeEndPeriod(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GambatteQt::pause() {
|
||||
if (!running || !timerId)
|
||||
return;
|
||||
|
||||
if (ae)
|
||||
ae->pause();
|
||||
|
||||
killTimer(timerId);
|
||||
timerId = 0;
|
||||
}
|
||||
|
||||
void GambatteQt::unpause() {
|
||||
if (!running || timerId)
|
||||
return;
|
||||
|
||||
timerId = startTimer(0);
|
||||
}
|
||||
|
||||
void GambatteQt::setCurrentFile(const QString &fileName) {
|
||||
QString curFile = fileName;
|
||||
if (curFile.isEmpty())
|
||||
setWindowTitle(tr("gambatte"));
|
||||
else
|
||||
setWindowTitle(tr("%1 - %2").arg(strippedName(curFile)) .arg(tr("gambatte")));
|
||||
|
||||
QSettings settings;
|
||||
QStringList files = settings.value("recentFileList").toStringList();
|
||||
files.removeAll(fileName);
|
||||
files.prepend(fileName);
|
||||
while (files.size() > MaxRecentFiles)
|
||||
files.removeLast();
|
||||
|
||||
settings.setValue("recentFileList", files);
|
||||
|
||||
foreach(QWidget *widget, QApplication::topLevelWidgets()) {
|
||||
GambatteQt *mainWin = qobject_cast<GambatteQt *>(widget);
|
||||
if (mainWin)
|
||||
mainWin->updateRecentFileActions();
|
||||
}
|
||||
}
|
||||
|
||||
void GambatteQt::updateRecentFileActions() {
|
||||
QSettings settings;
|
||||
QStringList files = settings.value("recentFileList").toStringList();
|
||||
|
||||
int numRecentFiles = qMin(files.size(), (int)MaxRecentFiles);
|
||||
|
||||
for (int i = 0; i < numRecentFiles; ++i) {
|
||||
QString text = tr("&%1 %2").arg(i + 1).arg(strippedName(files[i]));
|
||||
recentFileActs[i]->setText(text);
|
||||
recentFileActs[i]->setData(files[i]);
|
||||
recentFileActs[i]->setVisible(true);
|
||||
}
|
||||
for (int j = numRecentFiles; j < MaxRecentFiles; ++j)
|
||||
recentFileActs[j]->setVisible(false);
|
||||
|
||||
separatorAct->setVisible(numRecentFiles > 0);
|
||||
}
|
||||
|
||||
QString GambatteQt::strippedName(const QString &fullFileName) {
|
||||
return QFileInfo(fullFileName).fileName();
|
||||
}
|
||||
|
||||
void GambatteQt::keyPressEvent(QKeyEvent *e) {
|
||||
// memset(&is, 0, sizeof(is));
|
||||
|
||||
e->accept();
|
||||
|
||||
if (e->key() == inputDialog->getStartKey())
|
||||
inputGetter.is.startButton = 1;
|
||||
else if (e->key() == inputDialog->getSelectKey())
|
||||
inputGetter.is.selectButton = 1;
|
||||
else if (e->key() == inputDialog->getBKey())
|
||||
inputGetter.is.bButton = 1;
|
||||
else if (e->key() == inputDialog->getAKey())
|
||||
inputGetter.is.aButton = 1;
|
||||
else if (e->key() == inputDialog->getDownKey()) {
|
||||
inputGetter.is.dpadDown = 1;
|
||||
inputGetter.is.dpadUp = 0;
|
||||
} else if (e->key() == inputDialog->getUpKey()) {
|
||||
inputGetter.is.dpadUp = 1;
|
||||
inputGetter.is.dpadDown = 0;
|
||||
} else if (e->key() == inputDialog->getLeftKey()) {
|
||||
inputGetter.is.dpadLeft = 1;
|
||||
inputGetter.is.dpadRight = 0;
|
||||
} else if (e->key() == inputDialog->getRightKey()) {
|
||||
inputGetter.is.dpadRight = 1;
|
||||
inputGetter.is.dpadLeft = 0;
|
||||
}
|
||||
|
||||
switch (e->key()) {
|
||||
case Qt::Key_Tab: turbo = true; break;
|
||||
case Qt::Key_Escape:
|
||||
hideMenuAct->trigger();
|
||||
break;
|
||||
case Qt::Key_F:
|
||||
if (e->modifiers()&Qt::ControlModifier) {
|
||||
fsAct->trigger();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Q:
|
||||
if (e->modifiers()&Qt::ControlModifier) {
|
||||
exitAct->trigger();
|
||||
}
|
||||
break;
|
||||
default: e->ignore(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void GambatteQt::keyReleaseEvent(QKeyEvent *e) {
|
||||
// memset(&is, 0, sizeof(is));
|
||||
|
||||
if (e->key() == inputDialog->getStartKey())
|
||||
inputGetter.is.startButton = 0;
|
||||
else if (e->key() == inputDialog->getSelectKey())
|
||||
inputGetter.is.selectButton = 0;
|
||||
else if (e->key() == inputDialog->getBKey())
|
||||
inputGetter.is.bButton = 0;
|
||||
else if (e->key() == inputDialog->getAKey())
|
||||
inputGetter.is.aButton = 0;
|
||||
else if (e->key() == inputDialog->getDownKey())
|
||||
inputGetter.is.dpadDown = 0;
|
||||
else if (e->key() == inputDialog->getUpKey())
|
||||
inputGetter.is.dpadUp = 0;
|
||||
else if (e->key() == inputDialog->getLeftKey())
|
||||
inputGetter.is.dpadLeft = 0;
|
||||
else if (e->key() == inputDialog->getRightKey())
|
||||
inputGetter.is.dpadRight = 0;
|
||||
|
||||
switch (e->key()) {
|
||||
case Qt::Key_Tab: turbo = false; break;
|
||||
default: e->ignore(); return;
|
||||
}
|
||||
|
||||
// e->accept();
|
||||
}
|
||||
|
||||
void GambatteQt::closeEvent(QCloseEvent *e) {
|
||||
stop();
|
||||
|
||||
if (!isFullScreen()) {
|
||||
QSettings settings;
|
||||
settings.beginGroup("mainwindow");
|
||||
settings.setValue("size", size());
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
QMainWindow::closeEvent(e);
|
||||
}
|
||||
|
||||
/*void GambatteQt::showEvent(QShowEvent *event) {
|
||||
QMainWindow::showEvent(event);
|
||||
resetWindowSize();
|
||||
}*/
|
132
gambatte_qt/src/gambatte_qt.h
Normal file
132
gambatte_qt/src/gambatte_qt.h
Normal file
@ -0,0 +1,132 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef GAMBATTE_QT_H
|
||||
#define GAMBATTE_QT_H
|
||||
|
||||
#include <QList>
|
||||
#include <QMainWindow>
|
||||
#include <QSize>
|
||||
#include <vector>
|
||||
#include <gambatte.h>
|
||||
#include "videobufferreseter.h"
|
||||
#include "samplescalculator.h"
|
||||
|
||||
class QAction;
|
||||
class QMenu;
|
||||
// class QTextEdit;
|
||||
class AudioEngine;
|
||||
class BlitterWidget;
|
||||
class VideoDialog;
|
||||
class InputDialog;
|
||||
class FullResToggler;
|
||||
class BlitterContainer;
|
||||
|
||||
class InputGetter : public InputStateGetter {
|
||||
public:
|
||||
InputState is;
|
||||
const InputState& operator()() { return is; }
|
||||
};
|
||||
|
||||
class GambatteQt : public QMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GambatteQt();
|
||||
~GambatteQt();
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *event);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void keyReleaseEvent(QKeyEvent *e);
|
||||
void closeEvent(QCloseEvent *e);
|
||||
// void showEvent(QShowEvent *event);
|
||||
|
||||
private slots:
|
||||
void open();
|
||||
void openRecentFile();
|
||||
void about();
|
||||
void resetWindowSize();
|
||||
void toggleFullScreen();
|
||||
void toggleMenuHidden();
|
||||
// void gl();
|
||||
// void xv();
|
||||
void videoSettingsChange();
|
||||
void execVideoDialog();
|
||||
void execInputDialog();
|
||||
|
||||
private:
|
||||
void createActions();
|
||||
void createMenus();
|
||||
void loadFile(const QString &fileName);
|
||||
AudioEngine* initAudio();
|
||||
void run();
|
||||
void stop();
|
||||
void pause();
|
||||
void unpause();
|
||||
void setSamplesPrFrame();
|
||||
// void calculateSamples(unsigned bufPos, unsigned bufSize);
|
||||
void setCurrentFile(const QString &fileName);
|
||||
void updateRecentFileActions();
|
||||
QString strippedName(const QString &fullFileName);
|
||||
// void toggleFullScreen();
|
||||
// void pauseAudio();
|
||||
void execDialog(QDialog *dialog);
|
||||
|
||||
Gambatte gambatte;
|
||||
// QString curFile;
|
||||
// QSize fixedSize;
|
||||
|
||||
std::vector<AudioEngine*> audioEngines;
|
||||
std::vector<BlitterWidget*> blitters;
|
||||
|
||||
InputGetter inputGetter;
|
||||
VideoBufferReseter resetVideoBuffer;
|
||||
|
||||
int16_t *sndBuffer;
|
||||
|
||||
BlitterContainer *blitterContainer;
|
||||
QAction *exitAct;
|
||||
QAction *separatorAct;
|
||||
QAction *fsAct;
|
||||
QAction *hideMenuAct;
|
||||
InputDialog *inputDialog;
|
||||
VideoDialog* videoDialog;
|
||||
BlitterWidget *blitter;
|
||||
FullResToggler *fullResToggler;
|
||||
|
||||
enum { MaxRecentFiles = 8 };
|
||||
QAction *recentFileActs[MaxRecentFiles];
|
||||
|
||||
AudioEngine *ae;
|
||||
|
||||
unsigned sampleRate;
|
||||
unsigned samplesPrFrame;
|
||||
|
||||
int timerId;
|
||||
|
||||
SamplesCalculator samplesCalc;
|
||||
|
||||
bool running;
|
||||
bool turbo;
|
||||
//bool esc;
|
||||
};
|
||||
|
||||
#endif
|
25
gambatte_qt/src/getfullrestoggler.cpp
Normal file
25
gambatte_qt/src/getfullrestoggler.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "getfullrestoggler.h"
|
||||
|
||||
#include "fullrestogglers/nulltoggler.h"
|
||||
|
||||
FullResToggler* getFullResToggler() {
|
||||
return new NullToggler;
|
||||
}
|
26
gambatte_qt/src/getfullrestoggler.h
Normal file
26
gambatte_qt/src/getfullrestoggler.h
Normal file
@ -0,0 +1,26 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef GET_FULL_RES_TOGGLER_H
|
||||
#define GET_FULL_RES_TOGGLER_H
|
||||
|
||||
class FullResToggler;
|
||||
|
||||
FullResToggler* getFullResToggler();
|
||||
|
||||
#endif
|
29
gambatte_qt/src/getfullrestoggler_unix.cpp
Normal file
29
gambatte_qt/src/getfullrestoggler_unix.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "getfullrestoggler.h"
|
||||
|
||||
#include "fullrestogglers/nulltoggler.h"
|
||||
#include "fullrestogglers/xrandrtoggler.h"
|
||||
|
||||
FullResToggler* getFullResToggler() {
|
||||
if (XRandRToggler::isUsable())
|
||||
return new XRandRToggler;
|
||||
|
||||
return new NullToggler;
|
||||
}
|
25
gambatte_qt/src/getfullrestoggler_win32.cpp
Normal file
25
gambatte_qt/src/getfullrestoggler_win32.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "getfullrestoggler.h"
|
||||
|
||||
#include "fullrestogglers/gditoggler.h"
|
||||
|
||||
FullResToggler* getFullResToggler() {
|
||||
return new GdiToggler;
|
||||
}
|
503
gambatte_qt/src/inputdialog.cpp
Normal file
503
gambatte_qt/src/inputdialog.cpp
Normal file
@ -0,0 +1,503 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "inputdialog.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QKeyEvent>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QSettings>
|
||||
|
||||
static QString keyToString(int key) {
|
||||
switch (key) {
|
||||
case Qt::Key_Escape: return QString("Escape");
|
||||
case Qt::Key_Tab: return QString("Tab");
|
||||
case Qt::Key_Backtab: return QString("Backtab");
|
||||
case Qt::Key_Backspace: return QString("Backspace");
|
||||
case Qt::Key_Return: return QString("Return");
|
||||
case Qt::Key_Enter: return QString("Enter");
|
||||
case Qt::Key_Insert: return QString("Insert");
|
||||
case Qt::Key_Delete: return QString("Delete");
|
||||
case Qt::Key_Pause: return QString("Pause");
|
||||
case Qt::Key_Print: return QString("Print");
|
||||
case Qt::Key_SysReq: return QString("SysReq");
|
||||
case Qt::Key_Clear: return QString("Clear");
|
||||
case Qt::Key_Home: return QString("Home");
|
||||
case Qt::Key_End: return QString("End");
|
||||
case Qt::Key_Left: return QString("Left");
|
||||
case Qt::Key_Up: return QString("Up");
|
||||
case Qt::Key_Right: return QString("Right");
|
||||
case Qt::Key_Down: return QString("Down");
|
||||
case Qt::Key_PageUp: return QString("PageUp");
|
||||
case Qt::Key_PageDown: return QString("PageDown");
|
||||
case Qt::Key_Shift: return QString("Shift");
|
||||
case Qt::Key_Control: return QString("Control");
|
||||
case Qt::Key_Meta: return QString("Meta");
|
||||
case Qt::Key_Alt: return QString("Alt");
|
||||
case Qt::Key_AltGr: return QString("AltGr");
|
||||
case Qt::Key_CapsLock: return QString("CapsLock");
|
||||
case Qt::Key_NumLock: return QString("NumLock");
|
||||
case Qt::Key_ScrollLock: return QString("ScrollLock");
|
||||
case Qt::Key_F1: return QString("F1");
|
||||
case Qt::Key_F2: return QString("F2");
|
||||
case Qt::Key_F3: return QString("F3");
|
||||
case Qt::Key_F4: return QString("F4");
|
||||
case Qt::Key_F5: return QString("F5");
|
||||
case Qt::Key_F6: return QString("F6");
|
||||
case Qt::Key_F7: return QString("F7");
|
||||
case Qt::Key_F8: return QString("F8");
|
||||
case Qt::Key_F9: return QString("F9");
|
||||
case Qt::Key_F10: return QString("F10");
|
||||
case Qt::Key_F11: return QString("F11");
|
||||
case Qt::Key_F12: return QString("F12");
|
||||
case Qt::Key_F13: return QString("F13");
|
||||
case Qt::Key_F14: return QString("F14");
|
||||
case Qt::Key_F15: return QString("F15");
|
||||
case Qt::Key_F16: return QString("F16");
|
||||
case Qt::Key_F17: return QString("F17");
|
||||
case Qt::Key_F18: return QString("F18");
|
||||
case Qt::Key_F19: return QString("F19");
|
||||
case Qt::Key_F20: return QString("F20");
|
||||
case Qt::Key_F21: return QString("F21");
|
||||
case Qt::Key_F22: return QString("F22");
|
||||
case Qt::Key_F23: return QString("F23");
|
||||
case Qt::Key_F24: return QString("F24");
|
||||
case Qt::Key_F25: return QString("F25");
|
||||
case Qt::Key_F26: return QString("F26");
|
||||
case Qt::Key_F27: return QString("F27");
|
||||
case Qt::Key_F28: return QString("F28");
|
||||
case Qt::Key_F29: return QString("F29");
|
||||
case Qt::Key_F30: return QString("F30");
|
||||
case Qt::Key_F31: return QString("F31");
|
||||
case Qt::Key_F32: return QString("F32");
|
||||
case Qt::Key_F33: return QString("F33");
|
||||
case Qt::Key_F34: return QString("F34");
|
||||
case Qt::Key_F35: return QString("F35");
|
||||
case Qt::Key_Super_L: return QString("Super_L");
|
||||
case Qt::Key_Super_R: return QString("Super_R");
|
||||
case Qt::Key_Menu: return QString("Menu");
|
||||
case Qt::Key_Hyper_L: return QString("Hyper_L");
|
||||
case Qt::Key_Hyper_R: return QString("Hyper_R");
|
||||
case Qt::Key_Help: return QString("Help");
|
||||
case Qt::Key_Direction_L: return QString("Direction_L");
|
||||
case Qt::Key_Direction_R: return QString("Direction_R");
|
||||
case Qt::Key_Space: return QString("Space");
|
||||
case Qt::Key_Exclam: return QString("Exclam");
|
||||
case Qt::Key_QuoteDbl: return QString("QuoteDbl");
|
||||
case Qt::Key_NumberSign: return QString("NumberSign");
|
||||
case Qt::Key_Dollar: return QString("Dollar");
|
||||
case Qt::Key_Percent: return QString("Percent");
|
||||
case Qt::Key_Ampersand: return QString("Ampersand");
|
||||
case Qt::Key_Apostrophe: return QString("Apostrophe");
|
||||
case Qt::Key_ParenLeft: return QString("ParenLeft");
|
||||
case Qt::Key_ParenRight: return QString("ParenRight");
|
||||
case Qt::Key_Asterisk: return QString("Asterisk");
|
||||
case Qt::Key_Plus: return QString("Plus");
|
||||
case Qt::Key_Comma: return QString("Comma");
|
||||
case Qt::Key_Minus: return QString("Minus");
|
||||
case Qt::Key_Period: return QString("Period");
|
||||
case Qt::Key_Slash: return QString("Slash");
|
||||
case Qt::Key_0: return QString("0");
|
||||
case Qt::Key_1: return QString("1");
|
||||
case Qt::Key_2: return QString("2");
|
||||
case Qt::Key_3: return QString("3");
|
||||
case Qt::Key_4: return QString("4");
|
||||
case Qt::Key_5: return QString("5");
|
||||
case Qt::Key_6: return QString("6");
|
||||
case Qt::Key_7: return QString("7");
|
||||
case Qt::Key_8: return QString("8");
|
||||
case Qt::Key_9: return QString("9");
|
||||
case Qt::Key_Colon: return QString("Colon");
|
||||
case Qt::Key_Semicolon: return QString("Semicolon");
|
||||
case Qt::Key_Less: return QString("Less");
|
||||
case Qt::Key_Equal: return QString("Equal");
|
||||
case Qt::Key_Greater: return QString("Greater");
|
||||
case Qt::Key_Question: return QString("Question");
|
||||
case Qt::Key_At: return QString("At");
|
||||
case Qt::Key_A: return QString("A");
|
||||
case Qt::Key_B: return QString("B");
|
||||
case Qt::Key_C: return QString("C");
|
||||
case Qt::Key_D: return QString("D");
|
||||
case Qt::Key_E: return QString("E");
|
||||
case Qt::Key_F: return QString("F");
|
||||
case Qt::Key_G: return QString("G");
|
||||
case Qt::Key_H: return QString("H");
|
||||
case Qt::Key_I: return QString("I");
|
||||
case Qt::Key_J: return QString("J");
|
||||
case Qt::Key_K: return QString("K");
|
||||
case Qt::Key_L: return QString("L");
|
||||
case Qt::Key_M: return QString("M");
|
||||
case Qt::Key_N: return QString("N");
|
||||
case Qt::Key_O: return QString("O");
|
||||
case Qt::Key_P: return QString("P");
|
||||
case Qt::Key_Q: return QString("Q");
|
||||
case Qt::Key_R: return QString("R");
|
||||
case Qt::Key_S: return QString("S");
|
||||
case Qt::Key_T: return QString("T");
|
||||
case Qt::Key_U: return QString("U");
|
||||
case Qt::Key_V: return QString("V");
|
||||
case Qt::Key_W: return QString("W");
|
||||
case Qt::Key_X: return QString("X");
|
||||
case Qt::Key_Y: return QString("Y");
|
||||
case Qt::Key_Z: return QString("Z");
|
||||
case Qt::Key_BracketLeft: return QString("BracketLeft");
|
||||
case Qt::Key_Backslash: return QString("Backslash");
|
||||
case Qt::Key_BracketRight: return QString("BracketRight");
|
||||
case Qt::Key_AsciiCircum: return QString("AsciiCircum");
|
||||
case Qt::Key_Underscore: return QString("Underscore");
|
||||
case Qt::Key_QuoteLeft: return QString("QuoteLeft");
|
||||
case Qt::Key_BraceLeft: return QString("BraceLeft");
|
||||
case Qt::Key_Bar: return QString("Bar");
|
||||
case Qt::Key_BraceRight: return QString("BraceRight");
|
||||
case Qt::Key_AsciiTilde: return QString("AsciiTilde");
|
||||
case Qt::Key_nobreakspace: return QString("nobreakspace");
|
||||
case Qt::Key_exclamdown: return QString("exclamdown");
|
||||
case Qt::Key_cent: return QString("cent");
|
||||
case Qt::Key_sterling: return QString("sterling");
|
||||
case Qt::Key_currency: return QString("currency");
|
||||
case Qt::Key_yen: return QString("yen");
|
||||
case Qt::Key_brokenbar: return QString("brokenbar");
|
||||
case Qt::Key_section: return QString("section");
|
||||
case Qt::Key_diaeresis: return QString("diaeresis");
|
||||
case Qt::Key_copyright: return QString("copyright");
|
||||
case Qt::Key_ordfeminine: return QString("ordfeminine");
|
||||
case Qt::Key_guillemotleft: return QString("guillemotleft");
|
||||
case Qt::Key_notsign: return QString("notsign");
|
||||
case Qt::Key_hyphen: return QString("hyphen");
|
||||
case Qt::Key_registered: return QString("registered");
|
||||
case Qt::Key_macron: return QString("macron");
|
||||
case Qt::Key_degree: return QString("degree");
|
||||
case Qt::Key_plusminus: return QString("plusminus");
|
||||
case Qt::Key_twosuperior: return QString("twosuperior");
|
||||
case Qt::Key_threesuperior: return QString("threesuperior");
|
||||
case Qt::Key_acute: return QString("acute");
|
||||
case Qt::Key_mu: return QString("mu");
|
||||
case Qt::Key_paragraph: return QString("paragraph");
|
||||
case Qt::Key_periodcentered: return QString("periodcentered");
|
||||
case Qt::Key_cedilla: return QString("cedilla");
|
||||
case Qt::Key_onesuperior: return QString("onesuperior");
|
||||
case Qt::Key_masculine: return QString("masculine");
|
||||
case Qt::Key_guillemotright: return QString("guillemotright");
|
||||
case Qt::Key_onequarter: return QString("onequarter");
|
||||
case Qt::Key_onehalf: return QString("onehalf");
|
||||
case Qt::Key_threequarters: return QString("threequarters");
|
||||
case Qt::Key_questiondown: return QString("questiondown");
|
||||
case Qt::Key_Agrave: return QString("Agrave");
|
||||
case Qt::Key_Aacute: return QString("Aacute");
|
||||
case Qt::Key_Acircumflex: return QString("Acircumflex");
|
||||
case Qt::Key_Atilde: return QString("Atilde");
|
||||
case Qt::Key_Adiaeresis: return QString("Adiaeresis");
|
||||
case Qt::Key_Aring: return QString("Aring");
|
||||
case Qt::Key_AE: return QString("AE");
|
||||
case Qt::Key_Ccedilla: return QString("Ccedilla");
|
||||
case Qt::Key_Egrave: return QString("Egrave");
|
||||
case Qt::Key_Eacute: return QString("Eacute");
|
||||
case Qt::Key_Ecircumflex: return QString("Ecircumflex");
|
||||
case Qt::Key_Ediaeresis: return QString("Ediaeresis");
|
||||
case Qt::Key_Igrave: return QString("Igrave");
|
||||
case Qt::Key_Iacute: return QString("Iacute");
|
||||
case Qt::Key_Icircumflex: return QString("Icircumflex");
|
||||
case Qt::Key_Idiaeresis: return QString("Idiaeresis");
|
||||
case Qt::Key_ETH: return QString("ETH");
|
||||
case Qt::Key_Ntilde: return QString("Ntilde");
|
||||
case Qt::Key_Ograve: return QString("Ograve");
|
||||
case Qt::Key_Oacute: return QString("Oacute");
|
||||
case Qt::Key_Ocircumflex: return QString("Ocircumflex");
|
||||
case Qt::Key_Otilde: return QString("Otilde");
|
||||
case Qt::Key_Odiaeresis: return QString("Odiaeresis");
|
||||
case Qt::Key_multiply: return QString("multiply");
|
||||
case Qt::Key_Ooblique: return QString("Ooblique");
|
||||
case Qt::Key_Ugrave: return QString("Ugrave");
|
||||
case Qt::Key_Uacute: return QString("Uacute");
|
||||
case Qt::Key_Ucircumflex: return QString("Ucircumflex");
|
||||
case Qt::Key_Udiaeresis: return QString("Udiaeresis");
|
||||
case Qt::Key_Yacute: return QString("Yacute");
|
||||
case Qt::Key_THORN: return QString("THORN");
|
||||
case Qt::Key_ssharp: return QString("ssharp");
|
||||
case Qt::Key_division: return QString("division");
|
||||
case Qt::Key_ydiaeresis: return QString("ydiaeresis");
|
||||
case Qt::Key_Multi_key: return QString("Multi_key");
|
||||
case Qt::Key_Codeinput: return QString("Codeinput");
|
||||
case Qt::Key_SingleCandidate: return QString("SingleCandidate");
|
||||
case Qt::Key_MultipleCandidate: return QString("MultipleCandidate");
|
||||
case Qt::Key_PreviousCandidate: return QString("PreviousCandidate");
|
||||
case Qt::Key_Mode_switch: return QString("Mode_switch");
|
||||
case Qt::Key_Kanji: return QString("Kanji");
|
||||
case Qt::Key_Muhenkan: return QString("Muhenkan");
|
||||
case Qt::Key_Henkan: return QString("Henkan");
|
||||
case Qt::Key_Romaji: return QString("Romaji");
|
||||
case Qt::Key_Hiragana: return QString("Hiragana");
|
||||
case Qt::Key_Katakana: return QString("Katakana");
|
||||
case Qt::Key_Hiragana_Katakana: return QString("Hiragana_Katakana");
|
||||
case Qt::Key_Zenkaku: return QString("Zenkaku");
|
||||
case Qt::Key_Hankaku: return QString("Hankaku");
|
||||
case Qt::Key_Zenkaku_Hankaku: return QString("Zenkaku_Hankaku");
|
||||
case Qt::Key_Touroku: return QString("Touroku");
|
||||
case Qt::Key_Massyo: return QString("Massyo");
|
||||
case Qt::Key_Kana_Lock: return QString("Kana_Lock");
|
||||
case Qt::Key_Kana_Shift: return QString("Kana_Shift");
|
||||
case Qt::Key_Eisu_Shift: return QString("Eisu_Shift");
|
||||
case Qt::Key_Eisu_toggle: return QString("Eisu_toggle");
|
||||
case Qt::Key_Hangul: return QString("Hangul");
|
||||
case Qt::Key_Hangul_Start: return QString("Hangul_Start");
|
||||
case Qt::Key_Hangul_End: return QString("Hangul_End");
|
||||
case Qt::Key_Hangul_Hanja: return QString("Hangul_Hanja");
|
||||
case Qt::Key_Hangul_Jamo: return QString("Hangul_Jamo");
|
||||
case Qt::Key_Hangul_Romaja: return QString("Hangul_Romaja");
|
||||
case Qt::Key_Hangul_Jeonja: return QString("Hangul_Jeonja");
|
||||
case Qt::Key_Hangul_Banja: return QString("Hangul_Banja");
|
||||
case Qt::Key_Hangul_PreHanja: return QString("Hangul_PreHanja");
|
||||
case Qt::Key_Hangul_PostHanja: return QString("Hangul_PostHanja");
|
||||
case Qt::Key_Hangul_Special: return QString("Hangul_Special");
|
||||
case Qt::Key_Dead_Grave: return QString("Dead_Grave");
|
||||
case Qt::Key_Dead_Acute: return QString("Dead_Acute");
|
||||
case Qt::Key_Dead_Circumflex: return QString("Dead_Circumflex");
|
||||
case Qt::Key_Dead_Tilde: return QString("Dead_Tilde");
|
||||
case Qt::Key_Dead_Macron: return QString("Dead_Macron");
|
||||
case Qt::Key_Dead_Breve: return QString("Dead_Breve");
|
||||
case Qt::Key_Dead_Abovedot: return QString("Dead_Abovedot");
|
||||
case Qt::Key_Dead_Diaeresis: return QString("Dead_Diaeresis");
|
||||
case Qt::Key_Dead_Abovering: return QString("Dead_Abovering");
|
||||
case Qt::Key_Dead_Doubleacute: return QString("Dead_Doubleacute");
|
||||
case Qt::Key_Dead_Caron: return QString("Dead_Caron");
|
||||
case Qt::Key_Dead_Cedilla: return QString("Dead_Cedilla");
|
||||
case Qt::Key_Dead_Ogonek: return QString("Dead_Ogonek");
|
||||
case Qt::Key_Dead_Iota: return QString("Dead_Iota");
|
||||
case Qt::Key_Dead_Voiced_Sound: return QString("Dead_Voiced_Sound");
|
||||
case Qt::Key_Dead_Semivoiced_Sound: return QString("Dead_Semivoiced_Sound");
|
||||
case Qt::Key_Dead_Belowdot: return QString("Dead_Belowdot");
|
||||
case Qt::Key_Dead_Hook: return QString("Dead_Hook");
|
||||
case Qt::Key_Dead_Horn: return QString("Dead_Horn");
|
||||
case Qt::Key_Back: return QString("Back");
|
||||
case Qt::Key_Forward: return QString("Forward");
|
||||
case Qt::Key_Stop: return QString("Stop");
|
||||
case Qt::Key_Refresh: return QString("Refresh");
|
||||
case Qt::Key_VolumeDown: return QString("VolumeDown");
|
||||
case Qt::Key_VolumeMute: return QString("VolumeMute");
|
||||
case Qt::Key_VolumeUp: return QString("VolumeUp");
|
||||
case Qt::Key_BassBoost: return QString("BassBoost");
|
||||
case Qt::Key_BassUp: return QString("BassUp");
|
||||
case Qt::Key_BassDown: return QString("BassDown");
|
||||
case Qt::Key_TrebleUp: return QString("TrebleUp");
|
||||
case Qt::Key_TrebleDown: return QString("TrebleDown");
|
||||
case Qt::Key_MediaPlay: return QString("MediaPlay");
|
||||
case Qt::Key_MediaStop: return QString("MediaStop");
|
||||
case Qt::Key_MediaPrevious: return QString("MediaPrevious");
|
||||
case Qt::Key_MediaNext: return QString("MediaNext");
|
||||
case Qt::Key_MediaRecord: return QString("MediaRecord");
|
||||
case Qt::Key_HomePage: return QString("HomePage");
|
||||
case Qt::Key_Favorites: return QString("Favorites");
|
||||
case Qt::Key_Search: return QString("Search");
|
||||
case Qt::Key_Standby: return QString("Standby");
|
||||
case Qt::Key_OpenUrl: return QString("OpenUrl");
|
||||
case Qt::Key_LaunchMail: return QString("LaunchMail");
|
||||
case Qt::Key_LaunchMedia: return QString("LaunchMedia");
|
||||
case Qt::Key_Launch0: return QString("Launch0");
|
||||
case Qt::Key_Launch1: return QString("Launch1");
|
||||
case Qt::Key_Launch2: return QString("Launch2");
|
||||
case Qt::Key_Launch3: return QString("Launch3");
|
||||
case Qt::Key_Launch4: return QString("Launch4");
|
||||
case Qt::Key_Launch5: return QString("Launch5");
|
||||
case Qt::Key_Launch6: return QString("Launch6");
|
||||
case Qt::Key_Launch7: return QString("Launch7");
|
||||
case Qt::Key_Launch8: return QString("Launch8");
|
||||
case Qt::Key_Launch9: return QString("Launch9");
|
||||
case Qt::Key_LaunchA: return QString("LaunchA");
|
||||
case Qt::Key_LaunchB: return QString("LaunchB");
|
||||
case Qt::Key_LaunchC: return QString("LaunchC");
|
||||
case Qt::Key_LaunchD: return QString("LaunchD");
|
||||
case Qt::Key_LaunchE: return QString("LaunchE");
|
||||
case Qt::Key_LaunchF: return QString("LaunchF");
|
||||
case Qt::Key_MediaLast: return QString("MediaLast");
|
||||
case Qt::Key_unknown: return QString("unknown");
|
||||
case Qt::Key_Call: return QString("Call");
|
||||
case Qt::Key_Context1: return QString("Context1");
|
||||
case Qt::Key_Context2: return QString("Context2");
|
||||
case Qt::Key_Context3: return QString("Context3");
|
||||
case Qt::Key_Context4: return QString("Context4");
|
||||
case Qt::Key_Flip: return QString("Flip");
|
||||
case Qt::Key_Hangup: return QString("Hangup");
|
||||
case Qt::Key_No: return QString("No");
|
||||
case Qt::Key_Select: return QString("Select");
|
||||
case Qt::Key_Yes: return QString("Yes");
|
||||
case Qt::Key_Execute: return QString("Execute");
|
||||
case Qt::Key_Printer: return QString("Printer");
|
||||
case Qt::Key_Play: return QString("Play");
|
||||
case Qt::Key_Sleep: return QString("Sleep");
|
||||
case Qt::Key_Zoom: return QString("Zoom");
|
||||
case Qt::Key_Cancel: return QString("Cancel");
|
||||
default: return QString("");
|
||||
}
|
||||
}
|
||||
|
||||
class InputBox : public QLineEdit {
|
||||
int key;
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *e) {
|
||||
setKey(e->key());;
|
||||
}
|
||||
|
||||
public:
|
||||
InputBox(int key = 0) {
|
||||
setKey(key);;
|
||||
setReadOnly(true);
|
||||
}
|
||||
|
||||
int getKey() const {
|
||||
return key;
|
||||
}
|
||||
|
||||
void setKey(int key) {
|
||||
this->key = key;
|
||||
setText(keyToString(key));
|
||||
}
|
||||
};
|
||||
|
||||
InputDialog::InputDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setWindowTitle(tr("Input settings"));
|
||||
|
||||
upBox = new InputBox;
|
||||
downBox = new InputBox;
|
||||
leftBox = new InputBox;
|
||||
rightBox = new InputBox;
|
||||
aBox = new InputBox;
|
||||
bBox = new InputBox;
|
||||
startBox = new InputBox;
|
||||
selectBox = new InputBox;
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
QHBoxLayout *topLayout = new QHBoxLayout;
|
||||
QVBoxLayout *vLayout;
|
||||
QHBoxLayout *hLayout;
|
||||
|
||||
hLayout = new QHBoxLayout;
|
||||
|
||||
vLayout = new QVBoxLayout;
|
||||
vLayout->addWidget(new QLabel(tr("Up:")));
|
||||
vLayout->addWidget(new QLabel(tr("Down:")));
|
||||
vLayout->addWidget(new QLabel(tr("Left:")));
|
||||
vLayout->addWidget(new QLabel(tr("Right:")));
|
||||
hLayout->addLayout(vLayout);
|
||||
|
||||
vLayout = new QVBoxLayout;
|
||||
vLayout->addWidget(upBox);
|
||||
vLayout->addWidget(downBox);
|
||||
vLayout->addWidget(leftBox);
|
||||
vLayout->addWidget(rightBox);
|
||||
hLayout->addLayout(vLayout);
|
||||
|
||||
topLayout->addLayout(hLayout);
|
||||
hLayout = new QHBoxLayout;
|
||||
|
||||
vLayout = new QVBoxLayout;
|
||||
vLayout->addWidget(new QLabel(tr("A:")));
|
||||
vLayout->addWidget(new QLabel(tr("B:")));
|
||||
vLayout->addWidget(new QLabel(tr("Start:")));
|
||||
vLayout->addWidget(new QLabel(tr("Select:")));
|
||||
hLayout->addLayout(vLayout);
|
||||
|
||||
vLayout = new QVBoxLayout;
|
||||
vLayout->addWidget(aBox);
|
||||
vLayout->addWidget(bBox);
|
||||
vLayout->addWidget(startBox);
|
||||
vLayout->addWidget(selectBox);
|
||||
hLayout->addLayout(vLayout);
|
||||
|
||||
topLayout->addLayout(hLayout);
|
||||
mainLayout->addLayout(topLayout);
|
||||
|
||||
QPushButton *okButton = new QPushButton(tr("OK"));
|
||||
QPushButton *cancelButton = new QPushButton(tr("Cancel"));
|
||||
hLayout = new QHBoxLayout;
|
||||
hLayout->addWidget(okButton);
|
||||
hLayout->addWidget(cancelButton);
|
||||
mainLayout->addLayout(hLayout);
|
||||
mainLayout->setAlignment(hLayout, Qt::AlignBottom | Qt::AlignRight);
|
||||
okButton->setDefault(true);
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
|
||||
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("input");
|
||||
upKey = settings.value("upKey", Qt::Key_Up).toInt();
|
||||
downKey = settings.value("downKey", Qt::Key_Down).toInt();
|
||||
leftKey = settings.value("leftKey", Qt::Key_Left).toInt();
|
||||
rightKey = settings.value("rightKey", Qt::Key_Right).toInt();
|
||||
aKey = settings.value("aKey", Qt::Key_D).toInt();
|
||||
bKey = settings.value("bKey", Qt::Key_C).toInt();
|
||||
startKey = settings.value("startKey", Qt::Key_Return).toInt();
|
||||
selectKey = settings.value("selectKey", Qt::Key_Shift).toInt();
|
||||
settings.endGroup();
|
||||
|
||||
restore();
|
||||
}
|
||||
|
||||
InputDialog::~InputDialog() {
|
||||
QSettings settings;
|
||||
settings.beginGroup("input");
|
||||
settings.setValue("upKey", upKey);
|
||||
settings.setValue("downKey", downKey);
|
||||
settings.setValue("leftKey", leftKey);
|
||||
settings.setValue("rightKey", rightKey);
|
||||
settings.setValue("aKey", aKey);
|
||||
settings.setValue("bKey", bKey);
|
||||
settings.setValue("startKey", startKey);
|
||||
settings.setValue("selectKey", selectKey);
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void InputDialog::store() {
|
||||
upKey = upBox->getKey();
|
||||
downKey = downBox->getKey();
|
||||
leftKey = leftBox->getKey();
|
||||
rightKey = rightBox->getKey();
|
||||
aKey = aBox->getKey();
|
||||
bKey = bBox->getKey();
|
||||
startKey = startBox->getKey();
|
||||
selectKey = selectBox->getKey();
|
||||
}
|
||||
|
||||
void InputDialog::restore() {
|
||||
upBox->setKey(upKey);
|
||||
downBox->setKey(downKey);
|
||||
leftBox->setKey(leftKey);
|
||||
rightBox->setKey(rightKey);
|
||||
aBox->setKey(aKey);
|
||||
bBox->setKey(bKey);
|
||||
startBox->setKey(startKey);
|
||||
selectBox->setKey(selectKey);
|
||||
}
|
||||
|
||||
void InputDialog::accept() {
|
||||
store();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void InputDialog::reject() {
|
||||
restore();
|
||||
QDialog::reject();
|
||||
}
|
68
gambatte_qt/src/inputdialog.h
Normal file
68
gambatte_qt/src/inputdialog.h
Normal file
@ -0,0 +1,68 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef INPUTDIALOG_H
|
||||
#define INPUTDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class InputBox;
|
||||
|
||||
class InputDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
InputBox *upBox;
|
||||
InputBox *downBox;
|
||||
InputBox *leftBox;
|
||||
InputBox *rightBox;
|
||||
InputBox *aBox;
|
||||
InputBox *bBox;
|
||||
InputBox *startBox;
|
||||
InputBox *selectBox;
|
||||
|
||||
int upKey;
|
||||
int downKey;
|
||||
int leftKey;
|
||||
int rightKey;
|
||||
int aKey;
|
||||
int bKey;
|
||||
int startKey;
|
||||
int selectKey;
|
||||
|
||||
void store();
|
||||
void restore();
|
||||
|
||||
public:
|
||||
InputDialog(QWidget *parent = 0);
|
||||
~InputDialog();
|
||||
|
||||
int getUpKey() const { return upKey; }
|
||||
int getDownKey() const { return downKey; }
|
||||
int getLeftKey() const { return leftKey; }
|
||||
int getRightKey() const { return rightKey; }
|
||||
int getAKey() const { return aKey; }
|
||||
int getBKey() const { return bKey; }
|
||||
int getStartKey() const { return startKey; }
|
||||
int getSelectKey() const { return selectKey; }
|
||||
|
||||
public slots:
|
||||
void accept();
|
||||
void reject();
|
||||
};
|
||||
|
||||
#endif
|
32
gambatte_qt/src/main.cpp
Normal file
32
gambatte_qt/src/main.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <QApplication>
|
||||
#include "gambatte_qt.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// Q_INIT_RESOURCE(application);
|
||||
QApplication app(argc, argv);
|
||||
QCoreApplication::setOrganizationName("gambatte");
|
||||
QCoreApplication::setApplicationName("gambatte_qt");
|
||||
GambatteQt * mw = new GambatteQt();
|
||||
mw->show();
|
||||
return app.exec();
|
||||
}
|
30
gambatte_qt/src/resinfo.h
Normal file
30
gambatte_qt/src/resinfo.h
Normal file
@ -0,0 +1,30 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef RESINFO_H
|
||||
#define RESINFO_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct ResInfo {
|
||||
unsigned w;
|
||||
unsigned h;
|
||||
std::vector<short> rates;
|
||||
};
|
||||
|
||||
#endif
|
29
gambatte_qt/src/resizesignalingmenubar.cpp
Normal file
29
gambatte_qt/src/resizesignalingmenubar.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "resizesignalingmenubar.h"
|
||||
|
||||
ResizeSignalingMenuBar::ResizeSignalingMenuBar(QWidget *parent)
|
||||
: QMenuBar(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void ResizeSignalingMenuBar::resizeEvent(QResizeEvent *event) {
|
||||
QMenuBar::resizeEvent(event);
|
||||
emit resized();
|
||||
}
|
37
gambatte_qt/src/resizesignalingmenubar.h
Normal file
37
gambatte_qt/src/resizesignalingmenubar.h
Normal file
@ -0,0 +1,37 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef RESIZESIGNALINGMENUBAR_H
|
||||
#define RESIZESIGNALINGMENUBAR_H
|
||||
|
||||
#include <QMenuBar>
|
||||
|
||||
class ResizeSignalingMenuBar : public QMenuBar {
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
|
||||
public:
|
||||
ResizeSignalingMenuBar(QWidget *parent = 0);
|
||||
|
||||
signals:
|
||||
void resized();
|
||||
};
|
||||
|
||||
#endif
|
66
gambatte_qt/src/samplescalculator.cpp
Normal file
66
gambatte_qt/src/samplescalculator.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "samplescalculator.h"
|
||||
|
||||
SamplesCalculator::SamplesCalculator(const unsigned baseSamples, const unsigned maxDiff)
|
||||
: maxDiff(maxDiff)
|
||||
{
|
||||
setBaseSamples(baseSamples);
|
||||
}
|
||||
|
||||
void SamplesCalculator::setBaseSamples(const unsigned baseSamples) {
|
||||
this->baseSamples = baseSamples;
|
||||
samples = baseSamples;
|
||||
lastFromUnderrun = baseSamples >> 2;
|
||||
lastOverflowTime = lastUnderrunTime = updates = samplesOverflowed = 0;
|
||||
}
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
void SamplesCalculator::update(const unsigned fromUnderrun, const unsigned fromOverflow) {
|
||||
++updates;
|
||||
|
||||
if (fromUnderrun < samples * 2) {
|
||||
if (fromUnderrun <= lastFromUnderrun && samples < baseSamples + maxDiff && updates - lastUnderrunTime >= 60) {
|
||||
++samples;
|
||||
lastFromUnderrun = fromUnderrun;
|
||||
lastUnderrunTime = updates;
|
||||
printf("samples: %u\n", samples);
|
||||
lastOverflowTime = samplesOverflowed = 0;
|
||||
}
|
||||
} else {
|
||||
const unsigned of = samples - fromOverflow;
|
||||
|
||||
if (!(of & 0x80000000)) {
|
||||
if (!lastOverflowTime)
|
||||
lastOverflowTime = updates;
|
||||
else {
|
||||
samplesOverflowed += of;
|
||||
|
||||
if (samples > baseSamples - maxDiff && samplesOverflowed >= (updates - lastOverflowTime) * 2 + samples && updates - lastOverflowTime >= 300) {
|
||||
--samples;
|
||||
lastFromUnderrun = 0xFFFFFFFF;
|
||||
printf("samples: %u\n", samples);
|
||||
samplesOverflowed = 0;
|
||||
lastOverflowTime = updates;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
gambatte_qt/src/samplescalculator.h
Normal file
44
gambatte_qt/src/samplescalculator.h
Normal file
@ -0,0 +1,44 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SAMPLESCALCULATOR_H
|
||||
#define SAMPLESCALCULATOR_H
|
||||
|
||||
class SamplesCalculator {
|
||||
unsigned samples;
|
||||
unsigned baseSamples;
|
||||
unsigned updates;
|
||||
unsigned lastFromUnderrun;
|
||||
unsigned lastUnderrunTime;
|
||||
unsigned lastOverflowTime;
|
||||
unsigned samplesOverflowed;
|
||||
|
||||
const unsigned maxDiff;
|
||||
|
||||
public:
|
||||
SamplesCalculator(unsigned baseSamples = 804, unsigned maxDiff = 4);
|
||||
|
||||
void setBaseSamples(unsigned samples);
|
||||
void update(unsigned fromUnderrun, unsigned fromOverflow);
|
||||
|
||||
unsigned getSamples() const {
|
||||
return samples;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
66
gambatte_qt/src/scalebuffer.h
Normal file
66
gambatte_qt/src/scalebuffer.h
Normal file
@ -0,0 +1,66 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SCALEBUFFER_H_
|
||||
#define SCALEBUFFER_H_
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#define SCALE_BUFFER \
|
||||
const unsigned dstW = srcW * scale; \
|
||||
\
|
||||
for (unsigned h = srcH; h--;) { \
|
||||
for (unsigned w = srcW; w--;) { \
|
||||
for (unsigned n = scale; n--;) \
|
||||
*d++ = *s; \
|
||||
\
|
||||
++s; \
|
||||
} \
|
||||
\
|
||||
std::memcpy(d, d - dstW, dstW * (scale - 1) * sizeof(T)); \
|
||||
d += dstW * (scale - 1); \
|
||||
}
|
||||
|
||||
|
||||
template<typename T, const unsigned scale>
|
||||
static void do_scaleBuffer(const T *s, T *d, const unsigned srcW, const unsigned srcH) {
|
||||
SCALE_BUFFER
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void do_scaleBuffer(const T *s, T *d, const unsigned srcW, const unsigned srcH, const unsigned scale) {
|
||||
SCALE_BUFFER
|
||||
}
|
||||
|
||||
#undef SCALE_BUFFER
|
||||
|
||||
template<typename T>
|
||||
void scaleBuffer(const T *s, T *d, const unsigned srcW, const unsigned srcH, const unsigned scale) {
|
||||
switch (scale) {
|
||||
case 2: do_scaleBuffer<T, 2>(s, d, srcW, srcH); break;
|
||||
case 3: do_scaleBuffer<T, 3>(s, d, srcW, srcH); break;
|
||||
case 4: do_scaleBuffer<T, 4>(s, d, srcW, srcH); break;
|
||||
case 5: do_scaleBuffer<T, 5>(s, d, srcW, srcH); break;
|
||||
case 6: do_scaleBuffer<T, 6>(s, d, srcW, srcH); break;
|
||||
case 7: do_scaleBuffer<T, 7>(s, d, srcW, srcH); break;
|
||||
case 8: do_scaleBuffer<T, 8>(s, d, srcW, srcH); break;
|
||||
default: do_scaleBuffer(s, d, srcW, srcH, scale); break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /*SCALEBUFFER_H_*/
|
91
gambatte_qt/src/src.pro
Normal file
91
gambatte_qt/src/src.pro
Normal file
@ -0,0 +1,91 @@
|
||||
SOURCES += gambatte_qt.cpp \
|
||||
main.cpp \
|
||||
videodialog.cpp \
|
||||
videobufferreseter.cpp \
|
||||
blittercontainer.cpp \
|
||||
inputdialog.cpp \
|
||||
resizesignalingmenubar.cpp \
|
||||
samplescalculator.cpp \
|
||||
blitterwidgets/qglblitter.cpp \
|
||||
blitterwidgets/qpainterblitter.cpp
|
||||
|
||||
HEADERS += gambatte_qt.h \
|
||||
blitterwidget.h \
|
||||
fullrestoggler.h \
|
||||
videodialog.h \
|
||||
videobufferreseter.h \
|
||||
blittercontainer.h \
|
||||
resinfo.h \
|
||||
inputdialog.h \
|
||||
resizesignalingmenubar.h \
|
||||
audioengine.h \
|
||||
samplescalculator.h \
|
||||
addaudioengines.h \
|
||||
addblitterwidgets.h \
|
||||
getfullrestoggler.h \
|
||||
blitterwidgets/qglblitter.h \
|
||||
blitterwidgets/qpainterblitter.h \
|
||||
fullrestogglers/nulltoggler.h
|
||||
|
||||
TEMPLATE = app
|
||||
CONFIG += warn_on \
|
||||
thread \
|
||||
qt \
|
||||
release
|
||||
QT += opengl
|
||||
TARGET = ../bin/gambatte_qt
|
||||
INCLUDEPATH += ../../libgambatte/include
|
||||
LIBS += -L../../libgambatte -lgambatte
|
||||
|
||||
unix {
|
||||
DEFINES += PLATFORM_UNIX
|
||||
|
||||
SOURCES += blitterwidget.cpp \
|
||||
x11getprocaddress.cpp \
|
||||
addblitterwidgets_unix.cpp \
|
||||
getfullrestoggler_unix.cpp \
|
||||
audioengines/ossengine.cpp \
|
||||
blitterwidgets/xvblitter.cpp \
|
||||
blitterwidgets/x11blitter.cpp \
|
||||
fullrestogglers/xrandrtoggler.cpp
|
||||
|
||||
HEADERS += x11getprocaddress.h \
|
||||
audioengines/ossengine.h \
|
||||
blitterwidgets/xvblitter.h \
|
||||
blitterwidgets/x11blitter.h \
|
||||
fullrestogglers/xrandrtoggler.h
|
||||
|
||||
LIBS += -L/usr/X11R6/lib -lXv -lXrandr
|
||||
|
||||
linux-g++ {
|
||||
SOURCES += addaudioengines_linux.cpp audioengines/alsaengine.cpp
|
||||
HEADERS += audioengines/alsaengine.h
|
||||
LIBS += -lasound
|
||||
} else {
|
||||
SOURCES += addaudioengines_unix.cpp
|
||||
}
|
||||
}
|
||||
|
||||
win32 {
|
||||
DEFINES += PLATFORM_WIN32
|
||||
|
||||
SOURCES += getfullrestoggler_win32.cpp \
|
||||
blitterwidget_win32.cpp \
|
||||
addaudioengines_win32.cpp \
|
||||
addblitterwidgets_win32.cpp \
|
||||
audioengines/directsoundengine.cpp \
|
||||
blitterwidgets/directdrawblitter.cpp \
|
||||
fullrestogglers/gditoggler.cpp
|
||||
|
||||
HEADERS += audioengines/directsoundengine.h \
|
||||
blitterwidgets/directdrawblitter.h \
|
||||
fullrestogglers/gditoggler.h
|
||||
|
||||
LIBS += -lwinmm -lddraw -ldxguid -ldsound
|
||||
}
|
||||
|
||||
!win32 : !unix {
|
||||
SOURCES += addaudioengines.cpp addblitterwidgets.cpp getfullrestoggler.cpp audioengines/aoengine.cpp
|
||||
HEADERS += audioengines/aoengine.h
|
||||
LIBS += -lao
|
||||
}
|
29
gambatte_qt/src/videobufferreseter.cpp
Normal file
29
gambatte_qt/src/videobufferreseter.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "videobufferreseter.h"
|
||||
#include <gambatte.h>
|
||||
|
||||
VideoBufferReseter::VideoBufferReseter(Gambatte &gambatte_in) :
|
||||
gambatte(gambatte_in)
|
||||
{}
|
||||
|
||||
void VideoBufferReseter::operator()() {
|
||||
gambatte.videoBufferChange();
|
||||
}
|
32
gambatte_qt/src/videobufferreseter.h
Normal file
32
gambatte_qt/src/videobufferreseter.h
Normal file
@ -0,0 +1,32 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef VIDEOBUFFERRESETER_H
|
||||
#define VIDEOBUFFERRESETER_H
|
||||
|
||||
class Gambatte;
|
||||
|
||||
class VideoBufferReseter {
|
||||
Gambatte &gambatte;
|
||||
|
||||
public:
|
||||
VideoBufferReseter(Gambatte &gambatte_in);
|
||||
void operator()();
|
||||
};
|
||||
|
||||
#endif
|
399
gambatte_qt/src/videodialog.cpp
Normal file
399
gambatte_qt/src/videodialog.cpp
Normal file
@ -0,0 +1,399 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "videodialog.h"
|
||||
|
||||
#include <filterinfo.h>
|
||||
#include "blitterwidget.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QComboBox>
|
||||
#include <QCheckBox>
|
||||
#include <QString>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QSettings>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "fullrestoggler.h"
|
||||
|
||||
VideoDialog::VideoDialog(const std::vector<BlitterWidget*> &blitters, std::vector<const FilterInfo*> filterInfo, const FullResToggler& resHandler, QWidget *parent) : QDialog(parent), engines(blitters), resVector(resHandler.resVector()) {
|
||||
ResInfo currentRes;
|
||||
if (resVector.empty()) {
|
||||
currentRes.w = 1600;
|
||||
currentRes.h = 1200;
|
||||
} else
|
||||
currentRes = resVector.at(resHandler.currentResIndex());
|
||||
|
||||
|
||||
std::cout << currentRes.w << "x" << currentRes.h << std::endl;
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
setLayout(mainLayout);
|
||||
|
||||
QLabel *winResLabel = new QLabel(QString(tr("Windowed resolution:")));
|
||||
|
||||
winResSelector = new QComboBox;
|
||||
winResSelectorBackup = new QComboBox;
|
||||
|
||||
{
|
||||
unsigned hres = 160;
|
||||
unsigned vres = 144;
|
||||
|
||||
while (hres <= currentRes.w && vres <= currentRes.h) {
|
||||
winResSelector->addItem(QString::number(hres) + QString("x") + QString::number(vres), QVariant(QSize(hres, vres)));
|
||||
winResSelectorBackup->addItem(QString::number(hres) + QString("x") + QString::number(vres), QVariant(QSize(hres, vres)));
|
||||
hres += 160;
|
||||
vres += 144;
|
||||
}
|
||||
}
|
||||
|
||||
winResSelector->addItem(QString(tr("Variable")), QVariant(QSize(-1, -1)));
|
||||
// winResSelectorBackup->addItem(QString(tr("Variable")), QVariant(QSize(-1, -1)));
|
||||
|
||||
QLabel *fullResLabel = new QLabel(QString(tr("Full screen resolution:")));
|
||||
fullResSelector = new QComboBox;
|
||||
// fullResSelectorBackup = new QComboBox;
|
||||
hzSelector = new QComboBox;
|
||||
|
||||
fillFullResSelector(QSize(160, 144));
|
||||
|
||||
// fullResSelector->setCurrentIndex(fullIndex);
|
||||
|
||||
for (unsigned int i = 0; i < currentRes.rates.size(); ++i)
|
||||
hzSelector->addItem(QString::number(currentRes.rates[i]) + QString(" Hz"), i);
|
||||
|
||||
QPushButton *okButton = new QPushButton(tr("OK"));
|
||||
QPushButton *cancelButton = new QPushButton(tr("Cancel"));
|
||||
|
||||
topLayout = new QVBoxLayout;
|
||||
|
||||
QHBoxLayout *hLayout = new QHBoxLayout;
|
||||
hLayout->addWidget(new QLabel(tr("Video engine:")));
|
||||
engineSelector = new QComboBox;
|
||||
|
||||
for (unsigned int i = 0; i < engines.size(); ++i) {
|
||||
engineSelector->addItem(engines[i]->nameString);
|
||||
}
|
||||
|
||||
hLayout->addWidget(engineSelector);
|
||||
topLayout->addLayout(hLayout);
|
||||
engineWidget = engines[0]->settingsWidget();
|
||||
|
||||
if (engineWidget)
|
||||
topLayout->addWidget(engineWidget);
|
||||
|
||||
hLayout = new QHBoxLayout;
|
||||
hLayout->addWidget(winResLabel);
|
||||
hLayout->addWidget(winResSelector);
|
||||
topLayout->addLayout(hLayout);
|
||||
|
||||
hLayout = new QHBoxLayout;
|
||||
hLayout->addWidget(fullResLabel);
|
||||
QHBoxLayout *hhLayout = new QHBoxLayout;
|
||||
hhLayout->addWidget(fullResSelector);
|
||||
hhLayout->addWidget(hzSelector);
|
||||
hLayout->addLayout(hhLayout);
|
||||
topLayout->addLayout(hLayout);
|
||||
|
||||
keepRatioBox = new QCheckBox(QString("Keep aspect ratio"));
|
||||
topLayout->addWidget(keepRatioBox);
|
||||
|
||||
integerScalingBox = new QCheckBox(QString("Only scale by integer factors"));
|
||||
topLayout->addWidget(integerScalingBox);
|
||||
|
||||
hLayout = new QHBoxLayout;
|
||||
hLayout->addWidget(new QLabel(tr("Video filter:")));
|
||||
filterSelector = new QComboBox;
|
||||
|
||||
{
|
||||
unsigned maxW = 0;
|
||||
unsigned maxH = 0;
|
||||
|
||||
for (unsigned i = 0, max = 0; i < resVector.size(); ++i) {
|
||||
const unsigned cur = std::min(resVector[i].w * 9, resVector[i].h * 10);
|
||||
|
||||
if (cur > max) {
|
||||
max = cur;
|
||||
maxW = resVector[i].w;
|
||||
maxH = resVector[i].h;
|
||||
}
|
||||
}
|
||||
|
||||
if (!maxW) {
|
||||
maxW = 1600;
|
||||
maxH = 1200;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < filterInfo.size(); ++i) {
|
||||
if (filterInfo[i]->outWidth <= maxW && filterInfo[i]->outHeight <= maxH)
|
||||
filterSelector->addItem(filterInfo[i]->handle.c_str(), QSize(filterInfo[i]->outWidth, filterInfo[i]->outHeight));
|
||||
}
|
||||
}
|
||||
|
||||
hLayout->addWidget(filterSelector);
|
||||
topLayout->addLayout(hLayout);
|
||||
|
||||
mainLayout->addLayout(topLayout);
|
||||
mainLayout->setAlignment(topLayout, Qt::AlignTop);
|
||||
|
||||
hLayout = new QHBoxLayout;
|
||||
hLayout->addWidget(okButton);
|
||||
hLayout->addWidget(cancelButton);
|
||||
mainLayout->addLayout(hLayout);
|
||||
mainLayout->setAlignment(hLayout, Qt::AlignBottom | Qt::AlignRight);
|
||||
okButton->setDefault(true);
|
||||
|
||||
connect(engineSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(engineChange(int)));
|
||||
connect(fullResSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(fullresChange(int)));
|
||||
connect(keepRatioBox, SIGNAL(toggled(bool)), this, SLOT(keepRatioChange(bool)));
|
||||
connect(integerScalingBox, SIGNAL(toggled(bool)), this, SLOT(integerScalingChange(bool)));
|
||||
connect(filterSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChange(int)));
|
||||
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
|
||||
// connect(this, SIGNAL(accepted()), this, SLOT(store()));
|
||||
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
|
||||
// connect(this, SIGNAL(rejected()), this, SLOT(restore()));
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("video");
|
||||
|
||||
if (static_cast<unsigned>(fullIndex = settings.value("fullIndex", resHandler.currentResIndex()).toInt()) >= static_cast<unsigned>(fullResSelector->count()))
|
||||
fullIndex = resHandler.currentResIndex();
|
||||
|
||||
if (static_cast<unsigned>(filterIndexStore = settings.value("filterIndexStore", 0).toInt()) >= static_cast<unsigned>(filterSelector->count()))
|
||||
filterIndexStore = 0;
|
||||
|
||||
if (static_cast<unsigned>(engineIndex = settings.value("engineIndex", 0).toInt()) >= static_cast<unsigned>(engineSelector->count()))
|
||||
engineIndex = 0;
|
||||
|
||||
restore();
|
||||
store();
|
||||
|
||||
if (static_cast<unsigned>(winIndex = settings.value("winIndex", winResSelector->count() - 1).toInt()) >= static_cast<unsigned>(winResSelector->count()))
|
||||
winIndex = winResSelector->count() - 1;
|
||||
|
||||
if (static_cast<unsigned>(hzIndex = settings.value("hzIndex", resHandler.currentRateIndex()).toInt()) >= static_cast<unsigned>(hzSelector->count()))
|
||||
hzIndex = resHandler.currentRateIndex();
|
||||
|
||||
keepRatio = settings.value("keepRatio", true).toBool();
|
||||
integerScaling = settings.value("integerScaling", false).toBool();
|
||||
|
||||
restore();
|
||||
engineChange(engineIndex);
|
||||
store();
|
||||
|
||||
settings.endGroup();
|
||||
|
||||
setWindowTitle(tr("Video settings"));
|
||||
}
|
||||
|
||||
VideoDialog::~VideoDialog() {
|
||||
delete winResSelectorBackup;
|
||||
// delete fullResSelectorBackup;
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("video");
|
||||
settings.setValue("fullIndex", fullIndex);
|
||||
settings.setValue("winIndex", winIndex);
|
||||
settings.setValue("hzIndex", hzIndex);
|
||||
settings.setValue("keepRatio", keepRatio);
|
||||
settings.setValue("integerScaling", integerScaling);
|
||||
settings.setValue("filterIndexStore", filterIndexStore);
|
||||
settings.setValue("engineIndex", engineIndex);
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void VideoDialog::fillFullResSelector(const QSize &minimumRes) {
|
||||
while (fullResSelector->count())
|
||||
fullResSelector->removeItem(0);
|
||||
|
||||
for (std::size_t i = 0; i < resVector.size(); ++i) {
|
||||
const int hres = resVector[i].w;
|
||||
const int vres = resVector[i].h;
|
||||
|
||||
if (hres >= minimumRes.width() && vres >= minimumRes.height())
|
||||
fullResSelector->addItem(QString::number(hres) + QString("x") + QString::number(vres), i);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDialog::store() {
|
||||
engineIndex = engineSelector->currentIndex();
|
||||
|
||||
for (unsigned int i = 0; i < engines.size(); ++i)
|
||||
engines[i]->acceptSettings();
|
||||
|
||||
hzIndex = hzSelector->currentIndex();
|
||||
winIndex = winResSelector->currentIndex();
|
||||
fullIndex = fullResSelector->currentIndex();
|
||||
keepRatio = keepRatioBox->checkState() != Qt::Unchecked;
|
||||
integerScaling = integerScalingBox->checkState() != Qt::Unchecked;
|
||||
filterIndexStore = filterSelector->currentIndex();
|
||||
}
|
||||
|
||||
void VideoDialog::restore() {
|
||||
keepRatioBox->setChecked(keepRatio);
|
||||
integerScalingBox->setChecked(integerScaling);
|
||||
filterSelector->setCurrentIndex(filterIndexStore);
|
||||
winResSelector->setCurrentIndex(winIndex);
|
||||
fullResSelector->setCurrentIndex(fullIndex);
|
||||
hzSelector->setCurrentIndex(hzIndex);
|
||||
|
||||
for (unsigned int i = 0;i < engines.size();++i)
|
||||
engines[i]->rejectSettings();
|
||||
|
||||
engineSelector->setCurrentIndex(engineIndex);
|
||||
}
|
||||
|
||||
void VideoDialog::engineChange(int index) {
|
||||
if (engineWidget) {
|
||||
topLayout->removeWidget(engineWidget);
|
||||
engineWidget->setParent(NULL);
|
||||
}
|
||||
|
||||
engineWidget = engines[index]->settingsWidget();
|
||||
|
||||
if (engineWidget)
|
||||
topLayout->insertWidget(1, engineWidget);
|
||||
|
||||
if (engines[index]->integerOnlyScaler) {
|
||||
keepRatioBox->setChecked(true);
|
||||
integerScalingBox->setChecked(true);
|
||||
keepRatioBox->setEnabled(false);
|
||||
integerScalingBox->setEnabled(false);
|
||||
} else {
|
||||
keepRatioBox->setEnabled(true);
|
||||
|
||||
if (keepRatioBox->checkState() != Qt::Unchecked)
|
||||
integerScalingBox->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDialog::fullresChange(int index) {
|
||||
while (hzSelector->count())
|
||||
hzSelector->removeItem(0);
|
||||
|
||||
if (index >= 0) {
|
||||
const std::vector<short> &v = resVector[index].rates;
|
||||
|
||||
for (unsigned int i = 0; i < v.size(); ++i)
|
||||
hzSelector->addItem(QString::number(v[i]) + QString(" Hz"), i);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDialog::filterChange(int index) {
|
||||
const QSize filterSize = filterSelector->itemData(index).toSize();
|
||||
|
||||
{
|
||||
QString oldtext = winResSelector->itemText(winResSelector->currentIndex());
|
||||
|
||||
while (winResSelector->count())
|
||||
winResSelector->removeItem(0);
|
||||
|
||||
if (integerScalingBox->checkState() != Qt::Unchecked) {
|
||||
QSize fSize = filterSize;
|
||||
|
||||
for (int i = 0;i < winResSelectorBackup->count();++i) {
|
||||
QSize s = winResSelectorBackup->itemData(i).toSize();
|
||||
|
||||
if (s == fSize) {
|
||||
winResSelector->addItem(winResSelectorBackup->itemText(i), s);
|
||||
fSize += filterSize;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0;i < winResSelectorBackup->count();++i) {
|
||||
QSize s = winResSelectorBackup->itemData(i).toSize();
|
||||
|
||||
if (s.width() >= filterSize.width() && s.height() >= filterSize.height())
|
||||
winResSelector->addItem(winResSelectorBackup->itemText(i), s);
|
||||
}
|
||||
}
|
||||
winResSelector->addItem(QString(tr("Variable")), QVariant(QSize(-1, -1)));
|
||||
int newIndex = winResSelector->findText(oldtext);
|
||||
|
||||
if (newIndex >= 0)
|
||||
winResSelector->setCurrentIndex(newIndex);
|
||||
}
|
||||
|
||||
{
|
||||
QString oldtext = fullResSelector->itemText(fullResSelector->currentIndex());
|
||||
int oldHzIndex = hzSelector->currentIndex();
|
||||
|
||||
fillFullResSelector(filterSize);
|
||||
|
||||
int newIndex = fullResSelector->findText(oldtext);
|
||||
|
||||
if (newIndex >= 0) {
|
||||
fullResSelector->setCurrentIndex(newIndex);
|
||||
hzSelector->setCurrentIndex(oldHzIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDialog::keepRatioChange(bool checked) {
|
||||
if (integerScalingBox->checkState() != Qt::Unchecked)
|
||||
integerScalingBox->setChecked(checked);
|
||||
|
||||
integerScalingBox->setEnabled(checked);
|
||||
}
|
||||
|
||||
void VideoDialog::integerScalingChange(bool /*checked*/) {
|
||||
filterChange(filterSelector->currentIndex());
|
||||
}
|
||||
|
||||
const int VideoDialog::engine() const {
|
||||
return engineSelector->currentIndex();
|
||||
}
|
||||
|
||||
const QSize VideoDialog::winRes() const {
|
||||
return winResSelector->itemData(winResSelector->currentIndex()).toSize();
|
||||
}
|
||||
|
||||
const unsigned VideoDialog::fullMode() const {
|
||||
//return fullResSelector->currentIndex();
|
||||
// return fullResSelectorBackup->findText(fullResSelector->itemText(fullResSelector->currentIndex()));
|
||||
return fullResSelector->itemData(fullResSelector->currentIndex()).toUInt();
|
||||
}
|
||||
|
||||
const unsigned VideoDialog::fullRate() const {
|
||||
return hzSelector->itemData(hzSelector->currentIndex()).toUInt();
|
||||
}
|
||||
|
||||
bool VideoDialog::keepsRatio() const {
|
||||
return keepRatio;
|
||||
}
|
||||
|
||||
bool VideoDialog::scalesByInteger() const {
|
||||
return integerScaling;
|
||||
}
|
||||
|
||||
const unsigned int VideoDialog::filterIndex() const {
|
||||
return filterSelector->currentIndex();
|
||||
}
|
||||
|
||||
void VideoDialog::accept() {
|
||||
store();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void VideoDialog::reject() {
|
||||
restore();
|
||||
QDialog::reject();
|
||||
}
|
86
gambatte_qt/src/videodialog.h
Normal file
86
gambatte_qt/src/videodialog.h
Normal file
@ -0,0 +1,86 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef VIDEODIALOG_H
|
||||
#define VIDEODIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <vector>
|
||||
|
||||
class QVBoxLayout;
|
||||
class QHBoxLayout;
|
||||
class QComboBox;
|
||||
class QCheckBox;
|
||||
class FilterInfo;
|
||||
class BlitterWidget;
|
||||
class FullResToggler;
|
||||
|
||||
#include "resinfo.h"
|
||||
|
||||
class VideoDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
const std::vector<BlitterWidget*> &engines;
|
||||
const std::vector<ResInfo>& resVector;
|
||||
QVBoxLayout *topLayout;
|
||||
QWidget *engineWidget;
|
||||
QComboBox *engineSelector;
|
||||
QComboBox *winResSelector;
|
||||
QComboBox *winResSelectorBackup;
|
||||
QComboBox *fullResSelector;
|
||||
// QComboBox *fullResSelectorBackup;
|
||||
QComboBox *hzSelector;
|
||||
QCheckBox *keepRatioBox;
|
||||
QCheckBox *integerScalingBox;
|
||||
QComboBox *filterSelector;
|
||||
int engineIndex;
|
||||
int winIndex;
|
||||
int fullIndex;
|
||||
int hzIndex;
|
||||
int filterIndexStore;
|
||||
bool keepRatio;
|
||||
bool integerScaling;
|
||||
|
||||
void fillFullResSelector(const QSize &minimum);
|
||||
void store();
|
||||
void restore();
|
||||
|
||||
private slots:
|
||||
void engineChange(int index);
|
||||
void fullresChange(int index);
|
||||
void filterChange(int index);
|
||||
void keepRatioChange(bool checked);
|
||||
void integerScalingChange(bool checked);
|
||||
|
||||
public:
|
||||
VideoDialog(const std::vector<BlitterWidget*> &engines, std::vector<const FilterInfo*> filterInfo, const FullResToggler &resHandler, QWidget *parent = 0);
|
||||
~VideoDialog();
|
||||
const int engine() const;
|
||||
const QSize winRes() const;
|
||||
const unsigned fullMode() const;
|
||||
const unsigned fullRate() const;
|
||||
bool keepsRatio() const;
|
||||
bool scalesByInteger() const;
|
||||
const unsigned int filterIndex() const;
|
||||
|
||||
public slots:
|
||||
void accept();
|
||||
void reject();
|
||||
};
|
||||
|
||||
#endif
|
45
gambatte_qt/src/x11getprocaddress.cpp
Normal file
45
gambatte_qt/src/x11getprocaddress.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* Based on source code from The OpenGL Extension Wrangler Library. *
|
||||
* Copyright (C) 2002-2007, Milan Ikits <milan ikits[]ieee org> *
|
||||
* Copyright (C) 2002-2007, Marcelo E. Magallon <mmagallo[]debian org> *
|
||||
* Copyright (C) 2002, Lev Povalahev *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "x11getprocaddress.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
void* x11GetProcAddress(const char* name) {
|
||||
static void* h = NULL;
|
||||
static void* gpa;
|
||||
|
||||
if (h == NULL) {
|
||||
if ((h = dlopen(NULL, RTLD_LAZY | RTLD_LOCAL)) == NULL)
|
||||
return NULL;
|
||||
|
||||
if ((gpa = dlsym(h, "glXGetProcAddress")) == NULL)
|
||||
gpa = dlsym(h, "glXGetProcAddressARB");
|
||||
}
|
||||
|
||||
if (gpa != NULL)
|
||||
return (reinterpret_cast<void*(*)(const GLubyte*)>(gpa))((const GLubyte*)name);
|
||||
else
|
||||
return dlsym(h, name);
|
||||
}
|
25
gambatte_qt/src/x11getprocaddress.h
Normal file
25
gambatte_qt/src/x11getprocaddress.h
Normal file
@ -0,0 +1,25 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef X11GETPROCADDRESS_H
|
||||
#define X11GETPROCADDRESS_H
|
||||
|
||||
void* x11GetProcAddress(const char* name);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user