2 This program is free software; you can redistribute it and/or modify
3 it under the terms of the GNU General Public License as published by
4 the Free Software Foundation; either version 2 of the License, or
5 (at your option) any later version.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License along
13 with this program; if not, write to the Free Software Foundation, Inc.,
14 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 #include "QtBackend.h"
18 #include "qtopenc2e.h"
21 #include <QApplication>
24 #include <boost/format.hpp>
26 #include "exceptions.h"
33 HBITMAP screen_bmp
= 0;
37 QtBackend::QtBackend() {
41 for (unsigned int i
= 0; i
< 256; i
++) {
46 void QtBackend::shutdown() {
47 if (!viewport
) return;
50 if (screen_bmp
) DeleteObject(screen_bmp
);
52 SDL_Surface
*surf
= getMainSDLSurface();
53 if (surf
) surf
->pixels
= oldPixels
;
56 SDLBackend::shutdown();
59 void QtBackend::init() {
62 void QtBackend::setup(QWidget
*vp
) {
66 // on X11, using SDL_WINDOWID works, thank goodness.
67 static char windowid_str
[64]; // possibly big, but who cares
68 ((QApplication
*)QApplication::instance())->syncX();
70 if (sizeof windowid_str
<=
71 (size_t)snprintf(windowid_str
, sizeof windowid_str
, "SDL_WINDOWID=0x%lx", viewport
->winId())) {
72 std::cerr
<< "windowid_str buffer was too small - how big are your longs, anyway? Panicing..." << std::endl
;
75 // ->winId() may have created the window for us
76 ((QApplication
*)QApplication::instance())->syncX();
79 // alas, it sucks on Windows and OS X, so we use an offscreen buffer instead
80 putenv("SDL_VIDEODRIVER=dummy");
86 char videodrivername[200];
87 std::cout << "SDL video driver: " << SDL_VideoDriverName(videodrivername, 200) << std::endl;
88 std::cout << "SDL requested colour depth: " << idealBpp() << std::endl;
91 viewport
->setCursor(Qt::BlankCursor
);
94 int QtBackend::idealBpp() {
96 return SDLBackend::idealBpp();
99 // TODO: handle 8bpp for C1
102 // TODO: how to pick up real depth on windows?
103 if (viewport
->depth() == 16) return 16;
111 void QtBackend::resized(int w
, int h
) {
115 // We need to construct a DIB for blitting, based on the surface data.
117 // Delete the old one if needed.
118 if (screen_bmp
) DeleteObject(screen_bmp
);
120 // Setup a BITMAPINFO structure for this.
121 BITMAPINFO
*binfo
= (BITMAPINFO
*)malloc(sizeof(BITMAPINFO
) + 12); // TODO: wrong wrong wrong
122 binfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
123 binfo
->bmiHeader
.biPlanes
= 1;
124 binfo
->bmiHeader
.biClrUsed
= 0;
125 binfo
->bmiHeader
.biClrImportant
= 0;
127 binfo
->bmiHeader
.biXPelsPerMeter
= 0;
128 binfo
->bmiHeader
.biYPelsPerMeter
= 0;
130 SDL_Surface
*surf
= getMainSDLSurface();
131 assert(idealBpp() == surf
->format
->BitsPerPixel
);
133 // Set the relevant entries of the structure.
134 binfo
->bmiHeader
.biWidth
= w
;
135 binfo
->bmiHeader
.biHeight
= -h
;
136 binfo
->bmiHeader
.biSizeImage
= w
* h
* (idealBpp() / 8);
137 binfo
->bmiHeader
.biBitCount
= idealBpp();
139 // Describe the format of the data and any additional information needed (eg masks/palette)
140 if (idealBpp() == 16) {
141 binfo
->bmiHeader
.biCompression
= BI_BITFIELDS
;
142 unsigned int *masks
= (unsigned int *)binfo
->bmiColors
;
143 masks
[0] = surf
->format
->Rmask
;
144 masks
[1] = surf
->format
->Gmask
;
145 masks
[2] = surf
->format
->Bmask
;
147 binfo
->bmiHeader
.biCompression
= BI_RGB
;
148 if (idealBpp() == 8) {
149 // TODO: set binfo.bmiColors
153 // Create the actual DIB.
155 HDC hdc
= GetDC(viewport
->winId());
156 screen_bmp
= CreateDIBSection(hdc
, binfo
, DIB_RGB_COLORS
, (void **)(&pixels
), NULL
, 0);
157 ReleaseDC(viewport
->winId(), hdc
);
159 // Free the BITMAPINFO structure now we're done with it.
162 // TODO: fall back to Qt?
163 if (!screen_bmp
|| !pixels
) {
164 // Windows helpfully provides no useful error information :(
165 throw creaturesException("Internal error: failed to create DIB");
168 // TODO: Observe how this helpfully stomps over surf->pixels. :-/
169 oldPixels
= surf
->pixels
; // store so we can restore before SDL shutdown
170 surf
->pixels
= pixels
;
172 // So, CreateDIBSection doesn't pay a lot of attention to what we ask for.
173 // Let's snaffle the information back from the DIB object.
174 // TODO: Observe how this helpfully stomps over surf->w/h/pitch. :-/
176 GetObject(screen_bmp
, sizeof(BITMAP
), &dibsection
);
177 surf
->w
= dibsection
.bmWidth
;
178 surf
->h
= dibsection
.bmHeight
;
179 surf
->pitch
= dibsection
.bmWidthBytes
;
180 assert(dibsection
.bmBitsPixel
== surf
->format
->BitsPerPixel
);
184 // add resize window event to backend queue
186 e
.type
= eventresizewindow
;
192 void QtBackend::renderDone() {
195 // If we're not on X11, we need to copy the contents of the offscreen buffer into the window.
198 // We need to blit from the DIB we made earlier. Easy!
200 SDL_Surface
*surf
= getMainSDLSurface(); // for width/height
202 // Obtain the DC for our viewport and create a compatible one, then select the DIB into it.
203 hdc
= GetDC(viewport
->winId());
204 mdc
= CreateCompatibleDC(hdc
);
205 SelectObject(mdc
, screen_bmp
);
208 BitBlt(hdc
, 0, 0, surf
->w
, surf
->h
, mdc
, 0, 0, SRCCOPY
);
210 // Tidy up by deleting our temporary one and releasing the viewport DC.
212 ReleaseDC(viewport
->winId(), hdc
);
214 // TODO: call GdiFlush? SDL doesn't seem to bother.
216 #elif !defined(Q_WS_X11)
217 // As a generic method, we use Qt's code.
218 // Note that we don't bother to lock because we know the dummy driver doesn't bother with locking.
220 SDL_Surface
*surf
= getMainSDLSurface();
221 QImage
img((uchar
*)surf
->pixels
, surf
->w
, surf
->h
, QImage::Format_RGB32
);
222 QPainter
painter(viewport
);
223 painter
.drawImage(0, 0, img
);
227 bool QtBackend::pollEvent(SomeEvent
&e
) {
228 // obtain events from backend
229 if (SDLBackend::pollEvent(e
)) return true;
231 if (events
.size() == 0)
239 void QtBackend::pushEvent(SomeEvent e
) {
243 int translateQtKey(int qtkey
) {
244 if (qtkey
>= Qt::Key_F1
&& qtkey
<= Qt::Key_F12
) {
245 return 112 + (qtkey
- Qt::Key_F1
);
249 case Qt::Key_Backspace
: return 8;
250 case Qt::Key_Tab
: return 9;
251 case Qt::Key_Clear
: return 12;
252 case Qt::Key_Return
: return 13;
253 case Qt::Key_Enter
: return 13;
254 case Qt::Key_Shift
: return 16;
255 case Qt::Key_Control
: return 17;
256 case Qt::Key_Pause
: return 19;
257 case Qt::Key_CapsLock
: return 20;
258 case Qt::Key_Escape
: return 27;
259 case Qt::Key_PageUp
: return 33;
260 case Qt::Key_PageDown
: return 34;
261 case Qt::Key_End
: return 35;
262 case Qt::Key_Home
: return 36;
263 case Qt::Key_Left
: return 37;
264 case Qt::Key_Up
: return 38;
265 case Qt::Key_Right
: return 39;
266 case Qt::Key_Down
: return 40;
267 case Qt::Key_Print
: return 42;
268 case Qt::Key_Insert
: return 45;
269 case Qt::Key_Delete
: return 46;
270 case Qt::Key_NumLock
: return 144;
275 void QtBackend::keyEvent(QKeyEvent
*k
, bool pressed
) {
276 int translatedkey
= translateQtKey(k
->key());
277 int key
= translatedkey
;
279 if (k
->key() >= Qt::Key_0
&& k
->key() <= Qt::Key_9
) {
281 } else if (k
->key() >= Qt::Key_A
&& k
->key() <= Qt::Key_Z
) {
288 e
.type
= eventspecialkeydown
;
290 e
.type
= eventspecialkeyup
;
293 downkeys
[key
] = pressed
;
294 if (translatedkey
!= -1) return;
297 for (int i
= 0; i
< k
->text().size(); i
++) {
298 // TODO: openc2e probably doesn't like latin1
299 unsigned char x
= k
->text().at(i
).toLatin1();
300 if (x
> 31) { // Qt helpfully hands us non-text chars for some crazy reason
301 // We have a Latin-1 key which we can process.
304 // the engine only handles eventkeydown at present
306 e
.type
= eventkeydown
;
314 bool QtBackend::keyDown(int key
) {
315 return downkeys
[key
];
318 int QtBackend::run(int argc
, char **argv
) {
319 QApplication
app(argc
, argv
);
320 boost::shared_ptr
<QtBackend
> qtbackend
= boost::dynamic_pointer_cast
<class QtBackend
, class Backend
>(engine
.backend
);
321 assert(qtbackend
.get() == this);
323 QtOpenc2e
myvat(qtbackend
);