<commit_before>/*
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    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 for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "QtBackend.h"
#include <QKeyEvent>
#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <boost/format.hpp>
#include <iostream>
#include "../exceptions.h"

#ifdef _WIN32
#include <windows.h>
#endif

#ifdef _WIN32
HBITMAP screen_bmp = 0;
void *oldPixels = 0;
#endif

QtBackend::QtBackend() {
	viewport = 0;
	needsrender = false;

	for (unsigned int i = 0; i < 256; i++) {
		downkeys[i] = false;
	}
}

void QtBackend::shutdown() {
#ifdef _WIN32
	if (screen_bmp) DeleteObject(screen_bmp);
	
	SDL_Surface *surf = getMainSDLSurface();
	surf->pixels = oldPixels;
#endif

	SDLBackend::shutdown();
}

void QtBackend::init() {
}

void QtBackend::setup(QWidget *vp) {
	viewport = vp;

#if defined(Q_WS_X11)
	// on X11, using SDL_WINDOWID works, thank goodness.
	((QApplication *)QApplication::instance())->syncX();

	std::string windowidstr = boost::str(boost::format("SDL_WINDOWID=0x%lx") % viewport->winId());
	putenv((char *)windowidstr.c_str());
#else
	// alas, it sucks on Windows and OS X, so we use an offscreen buffer instead
	putenv("SDL_VIDEODRIVER=dummy");
#endif
	
	SDLBackend::init();

	/*
	char videodrivername[200];
	std::cout << "SDL video driver: " << SDL_VideoDriverName(videodrivername, 200) << std::endl;
	*/

	viewport->setCursor(Qt::BlankCursor);
}

int QtBackend::idealBpp() {
#if defined(Q_WS_X11)
	return SDLBackend::idealBpp();
#endif

	// TODO: handle 8bpp for C1

#ifdef _WIN32
	// TODO: how to pick up real depth on windows?
	/*if (viewport->depth() == 16)*/ return 16;
	/*return 24;*/
#endif

	return 32;
}


void QtBackend::resized(int w, int h) {
#ifdef _WIN32
	// avoid hideous resizing bugs which we don't understand
	// TODO: try to understand
	if (w % 2 == 1) w += 1;
#endif

	resizeNotify(w, h);

#ifdef _WIN32
	// We need to construct a DIB for blitting, based on the surface data.
	
	// Delete the old one if needed.
	if (screen_bmp) DeleteObject(screen_bmp);

	// Setup a BITMAPINFO structure for this.
	BITMAPINFO *binfo = (BITMAPINFO *)malloc(sizeof(BITMAPINFO) + 12); // TODO: wrong wrong wrong
	binfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	binfo->bmiHeader.biPlanes = 1;
	binfo->bmiHeader.biClrUsed = 0;
	binfo->bmiHeader.biClrImportant = 0;

	binfo->bmiHeader.biXPelsPerMeter = 0;
	binfo->bmiHeader.biYPelsPerMeter = 0;	

	SDL_Surface *surf = getMainSDLSurface();
	assert(idealBpp() == surf->format->BitsPerPixel);
	assert(w == surf->w);
	assert(h == surf->h);

	// Set the relevant entries of the structure.
	binfo->bmiHeader.biWidth = w;
	binfo->bmiHeader.biHeight = -h;
	binfo->bmiHeader.biSizeImage = w * h * (idealBpp() / 8);
	assert(binfo->bmiHeader.biSizeImage == h * surf->pitch);
	binfo->bmiHeader.biBitCount = idealBpp();

	// Describe the format of the data and any additional information needed (eg masks/palette)
	if (idealBpp() == 16) {
		binfo->bmiHeader.biCompression = BI_BITFIELDS;
		unsigned int *masks = (unsigned int *)binfo->bmiColors;
		masks[0] = surf->format->Rmask;
		masks[1] = surf->format->Gmask;
		masks[2] = surf->format->Bmask;
	} else {
		binfo->bmiHeader.biCompression = BI_RGB;
		if (idealBpp() == 8) {
			// TODO: set binfo.bmiColors
		}
	}

	// Create the actual DIB.
	// TODO: Observe how this helpfully stomps over surf->pixels. :-/
	HDC hdc = GetDC(viewport->winId());
	oldPixels = surf->pixels; // store so we can restore before SDL shutdown
	screen_bmp = CreateDIBSection(hdc, binfo, DIB_RGB_COLORS, (void **)(&surf->pixels), NULL, 0);
	ReleaseDC(viewport->winId(), hdc);

	// Free the BITMAPINFO structure now we're done with it.
	free(binfo);

	// TODO: fall back to Qt?
	if (!screen_bmp) {
		// Windows helpfully provides no useful error information :(
		throw creaturesException("Internal error: failed to create DIB");
	}
#endif

	// add resize window event to backend queue<commit_msg>fix the DIB renderer to be a bit less broken, and choose whether to run in 16bpp or 24bpp using the current Windows colour depth<commit_after>/*
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    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 for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "QtBackend.h"
#include <QKeyEvent>
#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <boost/format.hpp>
#include <iostream>
#include "../exceptions.h"

#ifdef _WIN32
#include <windows.h>
#endif

#ifdef _WIN32
HBITMAP screen_bmp = 0;
void *oldPixels = 0;
#endif

QtBackend::QtBackend() {
	viewport = 0;
	needsrender = false;

	for (unsigned int i = 0; i < 256; i++) {
		downkeys[i] = false;
	}
}

void QtBackend::shutdown() {
#ifdef _WIN32
	if (screen_bmp) DeleteObject(screen_bmp);
	
	SDL_Surface *surf = getMainSDLSurface();
	surf->pixels = oldPixels;
#endif

	SDLBackend::shutdown();
}

void QtBackend::init() {
}

void QtBackend::setup(QWidget *vp) {
	viewport = vp;

#if defined(Q_WS_X11)
	// on X11, using SDL_WINDOWID works, thank goodness.
	((QApplication *)QApplication::instance())->syncX();

	std::string windowidstr = boost::str(boost::format("SDL_WINDOWID=0x%lx") % viewport->winId());
	putenv((char *)windowidstr.c_str());
#else
	// alas, it sucks on Windows and OS X, so we use an offscreen buffer instead
	putenv("SDL_VIDEODRIVER=dummy");
#endif
	
	SDLBackend::init();

	/*
	char videodrivername[200];
	std::cout << "SDL video driver: " << SDL_VideoDriverName(videodrivername, 200) << std::endl;
	std::cout << "SDL requested colour depth: " << idealBpp() << std::endl;
	*/

	viewport->setCursor(Qt::BlankCursor);
}

int QtBackend::idealBpp() {
#if defined(Q_WS_X11)
	return SDLBackend::idealBpp();
#endif

	// TODO: handle 8bpp for C1

#ifdef _WIN32
	// TODO: how to pick up real depth on windows?
	if (viewport->depth() == 16) return 16;
	return 24;
#endif

	return 32;
}


void QtBackend::resized(int w, int h) {
	resizeNotify(w, h);

#ifdef _WIN32
	// We need to construct a DIB for blitting, based on the surface data.
	
	// Delete the old one if needed.
	if (screen_bmp) DeleteObject(screen_bmp);

	// Setup a BITMAPINFO structure for this.
	BITMAPINFO *binfo = (BITMAPINFO *)malloc(sizeof(BITMAPINFO) + 12); // TODO: wrong wrong wrong
	binfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	binfo->bmiHeader.biPlanes = 1;
	binfo->bmiHeader.biClrUsed = 0;
	binfo->bmiHeader.biClrImportant = 0;

	binfo->bmiHeader.biXPelsPerMeter = 0;
	binfo->bmiHeader.biYPelsPerMeter = 0;	

	SDL_Surface *surf = getMainSDLSurface();
	assert(idealBpp() == surf->format->BitsPerPixel);

	// Set the relevant entries of the structure.
	binfo->bmiHeader.biWidth = w;
	binfo->bmiHeader.biHeight = -h;
	binfo->bmiHeader.biSizeImage = w * h * (idealBpp() / 8);
	binfo->bmiHeader.biBitCount = idealBpp();

	// Describe the format of the data and any additional information needed (eg masks/palette)
	if (idealBpp() == 16) {
		binfo->bmiHeader.biCompression = BI_BITFIELDS;
		unsigned int *masks = (unsigned int *)binfo->bmiColors;
		masks[0] = surf->format->Rmask;
		masks[1] = surf->format->Gmask;
		masks[2] = surf->format->Bmask;
	} else {
		binfo->bmiHeader.biCompression = BI_RGB;
		if (idealBpp() == 8) {
			// TODO: set binfo.bmiColors
		}
	}

	// Create the actual DIB.
	void *pixels = 0;
	HDC hdc = GetDC(viewport->winId());
	screen_bmp = CreateDIBSection(hdc, binfo, DIB_RGB_COLORS, (void **)(&pixels), NULL, 0);
	ReleaseDC(viewport->winId(), hdc);

	// Free the BITMAPINFO structure now we're done with it.
	free(binfo);

	// TODO: fall back to Qt?
	if (!screen_bmp || !pixels) {
		// Windows helpfully provides no useful error information :(
		throw creaturesException("Internal error: failed to create DIB");
	}
	
	// TODO: Observe how this helpfully stomps over surf->pixels. :-/
	oldPixels = surf->pixels; // store so we can restore before SDL shutdown
	surf->pixels = pixels;

	// So, CreateDIBSection doesn't pay a lot of attention to what we ask for.
	// Let's snaffle the information back from the DIB object.
	// TODO: Observe how this helpfully stomps over surf->w/h/pitch. :-/
	BITMAP dibsection;
	GetObject(screen_bmp, sizeof(BITMAP), &dibsection);
	surf->w = dibsection.bmWidth;
	surf->h = dibsection.bmHeight;
	surf->pitch = dibsection.bmWidthBytes;
	assert(dibsection.bmBitsPixel == surf->format->BitsPerPixel);

#endif

	// add resize window event to backend queue
{'fraction_non_alphanumeric': 0.12749003984063745, 'fraction_numerical': 0.015097504717970224, 'mean_word_length': 4.184239130434783, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 89, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6395155', 'n_tokens_mistral': 3514, 'n_tokens_neox': 3283, 'n_words': 1013}