Skip to content

Commit

Permalink
support zooming "out" - below zoom factor 1.0.
Browse files Browse the repository at this point in the history
Works using QPainter::drawImage functionallity instead of manual memcpy for displaying pre-rendered chunk images
  • Loading branch information
cre4ture committed Sep 15, 2019
1 parent fea8541 commit e468324
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 72 deletions.
123 changes: 52 additions & 71 deletions mapview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
MapView::MapView(QWidget *parent)
: QWidget(parent)
, cache(ChunkCache::Instance())
, zoom_internal(1.0)
{
depth = 255;
scale = 1;
zoom = 1.0;
connect(&cache, SIGNAL(chunkLoaded(int, int)),
this, SLOT (chunkUpdated(int, int)));
connect(&cache, SIGNAL(structureFound(QSharedPointer<GeneratedStructure>)),
Expand Down Expand Up @@ -131,6 +131,21 @@ void MapView::clearCache() {
redraw();
}

double MapView::getZoom() const
{
return zoom_internal*zoom_internal; // get a more "natural" zoom behaviour
}

void MapView::adjustZoom(double rate)
{
static const double zoomMin = sqrt(0.17);
static const double zoomMax = sqrt(20.0);

zoom_internal *= (1.0 + (rate / 100.0));
if (zoom_internal < zoomMin) zoom_internal = zoomMin;
if (zoom_internal > zoomMax) zoom_internal = zoomMax;
}

static int lastMouseX = -1, lastMouseY = -1;
static bool dragging = false;
void MapView::mousePressEvent(QMouseEvent *event) {
Expand All @@ -147,17 +162,17 @@ void MapView::mouseMoveEvent(QMouseEvent *event) {
int centerx = imageChunks.width() / 2;
int centery = imageChunks.height() / 2;

centerx -= (this->x - centerblockx) * zoom;
centery -= (this->z - centerblockz) * zoom;
centerx -= (this->x - centerblockx) * getZoom();
centery -= (this->z - centerblockz) * getZoom();

int mx = floor(centerblockx - (centerx - event->x()) / zoom);
int mz = floor(centerblockz - (centery - event->y()) / zoom);
int mx = floor(centerblockx - (centerx - event->x()) / getZoom());
int mz = floor(centerblockz - (centery - event->y()) / getZoom());

getToolTip(mx, mz);
return;
}
x += (lastMouseX-event->x()) / zoom;
z += (lastMouseY-event->y()) / zoom;
x += (lastMouseX-event->x()) / getZoom();
z += (lastMouseY-event->y()) / getZoom();
lastMouseX = event->x();
lastMouseY = event->y();

Expand All @@ -175,11 +190,11 @@ void MapView::mouseDoubleClickEvent(QMouseEvent *event) {
int centerx = imageChunks.width() / 2;
int centery = imageChunks.height() / 2;

centerx -= (this->x - centerblockx) * zoom;
centery -= (this->z - centerblockz) * zoom;
centerx -= (this->x - centerblockx) * getZoom();
centery -= (this->z - centerblockz) * getZoom();

int mx = floor(centerblockx - (centerx - event->x()) / zoom);
int mz = floor(centerblockz - (centery - event->y()) / zoom);
int mx = floor(centerblockx - (centerx - event->x()) / getZoom());
int mz = floor(centerblockz - (centery - event->y()) / getZoom());

// get the y coordinate
int my = getY(mx, mz);
Expand All @@ -199,9 +214,7 @@ void MapView::wheelEvent(QWheelEvent *event) {
// change depth
emit demandDepthChange(event->delta() / 120);
} else { // change zoom
zoom += floor(event->delta() / 90.0);
if (zoom < 1.0) zoom = 1.0;
if (zoom > 20.0) zoom = 20.0;
adjustZoom( event->delta() / 90.0 );
redraw();
}
}
Expand All @@ -226,34 +239,32 @@ void MapView::keyPressEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_Up:
case Qt::Key_W:
z -= stepSize / zoom;
z -= stepSize / getZoom();
redraw();
break;
case Qt::Key_Down:
case Qt::Key_S:
z += stepSize / zoom;
z += stepSize / getZoom();
redraw();
break;
case Qt::Key_Left:
case Qt::Key_A:
x -= stepSize / zoom;
x -= stepSize / getZoom();
redraw();
break;
case Qt::Key_Right:
case Qt::Key_D:
x += stepSize / zoom;
x += stepSize / getZoom();
redraw();
break;
case Qt::Key_PageUp:
case Qt::Key_Q:
zoom++;
if (zoom > 20.0) zoom = 20.0;
adjustZoom(1);
redraw();
break;
case Qt::Key_PageDown:
case Qt::Key_E:
zoom--;
if (zoom < 1.0) zoom = 1.0;
adjustZoom(-1);
redraw();
break;
case Qt::Key_Home:
Expand Down Expand Up @@ -290,7 +301,7 @@ void MapView::redraw() {
return;
}

double chunksize = 16 * zoom;
double chunksize = 16 * getZoom();

// first find the center block position
int centerchunkx = floor(x / 16);
Expand All @@ -299,8 +310,8 @@ void MapView::redraw() {
int centerx = imageChunks.width() / 2;
int centery = imageChunks.height() / 2;
// and align for panning
centerx -= (x - centerchunkx * 16) * zoom;
centery -= (z - centerchunkz * 16) * zoom;
centerx -= (x - centerchunkx * 16) * getZoom();
centery -= (z - centerchunkz * 16) * getZoom();
// now calculate the topleft block on the screen
int startx = centerchunkx - floor(centerx / chunksize) - 1;
int startz = centerchunkz - floor(centery / chunksize) - 1;
Expand All @@ -317,8 +328,8 @@ void MapView::redraw() {

// add on the entity layer
QPainter canvas(&imageOverlays);
double halfviewwidth = imageOverlays.width() / 2 / zoom;
double halvviewheight = imageOverlays.height() / 2 / zoom;
double halfviewwidth = imageOverlays.width() / 2 / getZoom();
double halvviewheight = imageOverlays.height() / 2 / getZoom();
double x1 = x - halfviewwidth;
double z1 = z - halvviewheight;
double x2 = x + halfviewwidth;
Expand All @@ -344,7 +355,7 @@ void MapView::redraw() {
int highY = chunk->depth[index];
if ( (entityY+10 >= highY) ||
(entityY+10 >= depth) )
(*it)->draw(x1, z1, zoom, &canvas);
(*it)->draw(x1, z1, getZoom(), &canvas);
}
}
}
Expand All @@ -358,7 +369,7 @@ void MapView::redraw() {
for (auto &item : overlayItems[type]) {
if (item->intersects(OverlayItem::Point(x1 - 1, 0, z1 - 1),
OverlayItem::Point(x2 + 1, depth, z2 + 1))) {
item->draw(x1, z1, zoom, &canvas);
item->draw(x1, z1, getZoom(), &canvas);
}
}
}
Expand Down Expand Up @@ -393,54 +404,24 @@ void MapView::drawChunk(int x, int z) {
int centerchunkx = floor(this->x / 16);
int centerchunkz = floor(this->z / 16);
// and the center chunk screen coordinates
int centerx = imageChunks.width() / 2;
int centery = imageChunks.height() / 2;
double centerx = imageChunks.width() / 2;
double centery = imageChunks.height() / 2;
// which need to be shifted to account for panning inside that chunk
centerx -= (this->x - centerchunkx * 16) * zoom;
centery -= (this->z - centerchunkz * 16) * zoom;
centerx -= (this->x - centerchunkx * 16) * getZoom();
centery -= (this->z - centerchunkz * 16) * getZoom();
// centerx,y now points to the top left corner of the center chunk
// so now calculate our x,y in relation
double chunksize = 16 * zoom;
double chunksize = 16 * getZoom();
centerx += (x - centerchunkx) * chunksize;
centery += (z - centerchunkz) * chunksize;

int srcoffset = 0;
uchar *bits = imageChunks.bits();
int imgstride = imageChunks.bytesPerLine();
const uchar* srcImageData = chunk ? chunk->image : placeholder;
QImage srcImage(srcImageData, 16, 16, QImage::Format_RGB32);

int skipx = 0, skipy = 0;
int blockwidth = chunksize, blockheight = chunksize;
// now if we're off the screen we need to crop
if (centerx < 0) {
skipx = -centerx;
centerx = 0;
}
if (centery < 0) {
skipy = -centery;
centery = 0;
}
// or the other side, we need to trim
if (centerx + blockwidth > imageChunks.width())
blockwidth = imageChunks.width() - centerx;
if (centery + blockheight > imageChunks.height())
blockheight = imageChunks.height() - centery;
if (blockwidth <= 0 || skipx >= blockwidth) return;
int imgoffset = centerx * 4 + centery * imgstride;
if (chunk)
src = chunk->image;
// blit (or scale blit)
for (int z = skipy; z < blockheight; z++, imgoffset += imgstride) {
srcoffset = floor(z / zoom) * 16 * 4;
if (zoom == 1.0) {
memcpy(bits + imgoffset, src + srcoffset + skipx * 4,
(blockwidth - skipx) * 4);
} else {
int xofs = 0;
for (int x = skipx; x < blockwidth; x++, xofs += 4)
memcpy(bits + imgoffset + xofs, src + srcoffset +
static_cast<int>(floor(x / zoom) * 4), 4);
}
}
QRectF targetRect(centerx, centery, chunksize, chunksize);

QPainter canvas(&imageChunks);
canvas.drawImage(targetRect, srcImage);
}

void MapView::getToolTip(int x, int z) {
Expand Down Expand Up @@ -563,7 +544,7 @@ QList<QSharedPointer<OverlayItem>> MapView::getItems(int x, int y, int z) {
QSharedPointer<Chunk> chunk(cache.fetch(cx, cz));

if (chunk) {
double invzoom = 10.0 / zoom;
double invzoom = 10.0 / getZoom();
for (auto &type : overlayItemTypes) {
// generated structures
for (auto &item : overlayItems[type]) {
Expand Down
4 changes: 3 additions & 1 deletion mapview.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,16 @@ class MapView : public QWidget {
void getToolTip(int x, int z);
int getY(int x, int z);
QList<QSharedPointer<OverlayItem>> getItems(int x, int y, int z);
double getZoom() const;
void adjustZoom(double rate);

static const int CAVE_DEPTH = 16; // maximum depth caves are searched in cave mode
float caveshade[CAVE_DEPTH];

int depth;
double x, z;
int scale;
double zoom;
double zoom_internal;
int flags;
ChunkCache &cache;
QImage imageChunks;
Expand Down

0 comments on commit e468324

Please sign in to comment.