Files
nethack/win/Qt/qt_glyph.cpp
PatR 37ce6f72b3 Qt without tiles
When tiles fail to load, the Qt interface switches to the text map.
But it wasn't inhibiting the player from trying to switch to tiles
map.  Also, when the text map was in use it was forcing the paper
doll inventory subset to be disabled regardless of whether the map
was by choice or because tiles wouldn't load.  Allow the paper doll
in combination with the text map if tiles got loaded successfully.
2022-01-02 01:48:07 -08:00

269 lines
8.6 KiB
C++

// Copyright (c) Warwick Allison, 1999.
// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
// qt_glyph.cpp -- class to manage the glyphs in a tile set
extern "C" {
#include "hack.h"
#include "tile2x11.h" /* x11tiles is potential fallback for nhtiles.bmp */
}
#include "qt_pre.h"
#include <QtGui/QtGui>
#if QT_VERSION >= 0x050000
#include <QtWidgets/QtWidgets>
#endif
#include "qt_post.h"
#include "qt_glyph.h"
#include "qt_bind.h"
#include "qt_set.h"
#include "qt_inv.h"
#include "qt_map.h"
#include "qt_str.h"
extern short glyph2tile[]; // from tile.c
namespace nethack_qt_ {
static int tilefile_tile_W=16;
static int tilefile_tile_H=16;
// Debian uses a separate PIXMAPDIR
#ifndef PIXMAPDIR
# ifdef HACKDIR
# define PIXMAPDIR HACKDIR
# else
# define PIXMAPDIR "."
# endif
#endif
NetHackQtGlyphs::NetHackQtGlyphs()
{
boolean tilesok = TRUE, user_tiles = (::iflags.wc_tile_file != NULL);
char cbuf[BUFSZ];
const char *tile_file = NULL, *tile_list[2];
this->no_tiles = false;
tiles_per_row = TILES_PER_ROW;
if (user_tiles) {
tile_list[0] = ::iflags.wc_tile_file;
Snprintf(cbuf, sizeof cbuf, "%s/%s", PIXMAPDIR, tile_list[0]);
tile_list[1] = cbuf;
} else {
tile_list[0] = PIXMAPDIR "/nhtiles.bmp";
tile_list[1] = PIXMAPDIR "/x11tiles";
}
if (img.load(tile_list[0]))
tile_file = tile_list[0];
else if (img.load(tile_list[1]))
tile_file = tile_list[1];
if (!tile_file) {
tilesok = FALSE;
QString msg = QString::asprintf("Cannot load '%s'.",
user_tiles ? tile_list[0]
// mismatched quotes match format
: "nhtiles.bmp' or 'x11tiles");
QMessageBox::warning(0, "IO Error", msg);
} else {
if (img.width() % tiles_per_row) {
tilesok = FALSE;
impossible(
"Tile file \"%s\" has %d columns, not multiple of row count (%d)",
tile_file, img.width(), tiles_per_row);
}
}
if (!tilesok) {
this->no_tiles = true;
/* tiles wouldn't load so force ascii map */
::iflags.wc_ascii_map = 1;
::iflags.wc_tiled_map = 0;
/* tiles wouldn't load so don't allow toggling to tiled map */
::set_wc_option_mod_status(WC_ASCII_MAP | WC_TILED_MAP,
::set_in_config);
tiles_per_row = 40; // arbitrary to avoid potential divide-by-0
}
if (iflags.wc_tile_width)
tilefile_tile_W = iflags.wc_tile_width;
else if (iflags.wc_ascii_map)
tilefile_tile_W = 16;
else
tilefile_tile_W = img.width() / tiles_per_row;
if (iflags.wc_tile_height)
tilefile_tile_H = iflags.wc_tile_height;
else
tilefile_tile_H = tilefile_tile_W;
setSize(tilefile_tile_W, tilefile_tile_H);
}
void NetHackQtGlyphs::drawGlyph(QPainter& painter, int glyph, int tileidx,
int x, int y, bool fem, bool reversed)
{
if (!reversed) {
#if 0
int tile = glyph2tile[glyph];
/* this is not required with the new glyph representation */
if (fem)
++tile;
#else
int tile = tileidx;
#endif
int px = (tile % tiles_per_row) * width();
int py = tile / tiles_per_row * height();
painter.drawPixmap(x, y, pm, px, py, width(), height());
} else {
// for paper doll; mirrored image for left side of two-handed weapon
painter.drawPixmap(x, y, reversed_pixmap(glyph, tileidx, fem),
0, 0, width(), height());
}
}
void NetHackQtGlyphs::drawCell(QPainter& painter, int glyph, int tileidx,
int cellx, int celly, bool fem)
{
drawGlyph(painter, glyph, tileidx, cellx * width(), celly * height(),
fem, false);
}
void NetHackQtGlyphs::drawBorderedCell(QPainter& painter, int glyph,
int tileidx, int cellx, int celly,
int border, bool reversed, bool fem)
{
int wd = width(),
ht = height(),
yoffset = 1, // tiny extra margin at top
lox = cellx * (wd + 2),
loy = celly * (ht + 2) + yoffset;
drawGlyph(painter, glyph, tileidx, lox + 1, loy + 1, fem, reversed);
#ifdef TEXTCOLOR
if (border != NO_BORDER) {
// gray would be a better mid-point between red and cyan but it
// doesn't show up well enough against the wall tile background
painter.setPen((border == BORDER_CURSED) ? Qt::red
: (border == BORDER_UNCURSED) ? Qt::yellow
: (border == BORDER_BLESSED) ? Qt::cyan
: Qt::white); // BORDER_DEFAULT
// assuming 32x32, draw 34x34 rectangle from 0..33x0..33, outside glyph
#if 0 /* Qt 5.11 drawRect(x,y,width,height) seems to have an off by 1 bug;
* drawRect(0,0,34,34) is drawing at 0..34x0..34 which is 35x35;
* should subtract 1 when adding width and/or height to base coord;
* the relevant code in QtCore/QRect.h is correct so this observable
* misbehavior is a mystery... */
painter.drawRect(lox, loy, wd + 2, ht + 2);
#else
painter.drawLine(lox, loy, lox + wd + 1, loy); // 0,0->33,0
painter.drawLine(lox, loy + ht + 1, lox + wd + 1, loy + ht + 1);
painter.drawLine(lox, loy, lox, loy + ht + 1); // 0,0->0,33
painter.drawLine(lox + wd + 1, loy, lox + wd + 1, loy + ht + 1);
#endif
if (border != BORDER_DEFAULT) {
// assuming 32x32, draw rectangle from 1..32x1..32, inside glyph
#if 0 /* (see above) */
painter.drawRect(lox + 1, loy + 1, wd, ht);
#else
painter.drawLine(lox + 1, loy + 1, lox + wd, loy + 1); // 1,1->32,1
painter.drawLine(lox + 1, loy + ht, lox + wd, loy + ht);
painter.drawLine(lox + 1, loy + 1, lox + 1, loy + ht); // 1,1->1,32
painter.drawLine(lox + wd, loy + 1, lox + wd, loy + ht);
#endif
for (int i = lox + 2; i < lox + wd - 1; i += 2) {
// assuming 32x32, draw points along <2..31,2> and <2..31,31>
painter.drawPoint(i, loy + 2);
painter.drawPoint(i + 1, loy + ht - 1);
}
for (int j = loy + 2; j < loy + ht - 1; j += 2) {
// assuming 32x32, draw points along <2,2..31> and <31,2..31>
painter.drawPoint(lox + 2, j);
painter.drawPoint(lox + wd - 1, j + 1);
}
}
}
#else
nhUse(border);
#endif
}
// mis-named routine to get the pixmap for a particular glyph
QPixmap NetHackQtGlyphs::glyph(int glyphindx UNUSED, int tileidx, bool fem UNUSED)
{
#if 0
int tile = glyph2tile[glyphindx];
if (fem)
++tile;
#else
int tile = tileidx;
#endif
int px = (tile % tiles_per_row) * tilefile_tile_W;
int py = tile / tiles_per_row * tilefile_tile_H;
return QPixmap::fromImage(img.copy(px, py,
tilefile_tile_W, tilefile_tile_H));
}
// transpose a glyph's tile horizontally, scaled for use in paper doll
QPixmap NetHackQtGlyphs::reversed_pixmap(int glyphindx, int tileidx, bool fem)
{
QPixmap pxmp = glyph(glyphindx, tileidx, fem);
#ifdef ENHANCED_PAPERDOLL
qreal wid = (qreal) pxmp.width(),
//hgt = (qreal) pxmp.height(),
xscale = (qreal) qt_settings->dollWidth / (qreal) tilefile_tile_W,
yscale = (qreal) qt_settings->dollHeight / (qreal) tilefile_tile_H;
QTransform *mirrormatrix = new QTransform(
// negate x coordinates to flip the image across the y-axis
-1.0 * xscale, 0.0, 0.0, yscale,
// slide flipped image to the right to make things positive again
wid * xscale, 0.0
);
return pxmp.transformed(*mirrormatrix);
#else
return pxmp;
#endif
}
void NetHackQtGlyphs::setSize(int w, int h)
{
if (size == QSize(w, h))
return;
size = QSize(w, h);
if (!w || !h)
return; // Still not decided
if (size == pm1.size()) { // not zoomed
pm = pm1;
return;
}
if (size == pm2.size()) { // zoomed
pm = pm2;
return;
}
bool was1 = (size == pm1.size());
if (w == tilefile_tile_W && h == tilefile_tile_H) {
pm.convertFromImage(img);
} else {
QApplication::setOverrideCursor(Qt::WaitCursor);
QImage scaled = img.scaled(
w * img.width() / tilefile_tile_W,
h * img.height() / tilefile_tile_H,
Qt::IgnoreAspectRatio,
Qt::FastTransformation
);
pm.convertFromImage(scaled, Qt::ThresholdDither | Qt::PreferDither);
QApplication::restoreOverrideCursor();
}
(was1 ? pm2 : pm1) = pm;
}
} // namespace nethack_qt_