diff --git a/src/Format.cpp b/src/Format.cpp index 4dc40dd08..e19ce5314 100644 --- a/src/Format.cpp +++ b/src/Format.cpp @@ -94,26 +94,22 @@ String format::CleanString(String dirtyString, bool ascii, bool color, bool newl return dirtyString; } -std::vector format::VideoBufferToPPM(const VideoBuffer & vidBuf) +std::vector format::VideoBufferToPPM(VideoBuffer const &vidBuf) { std::vector data; char buffer[256]; - sprintf(buffer, "P6\n%d %d\n255\n", vidBuf.Width, vidBuf.Height); - data.insert(data.end(), buffer, buffer+strlen(buffer)); + sprintf(buffer, "P6\n%d %d\n255\n", vidBuf.Size().X, vidBuf.Size().Y); + data.insert(data.end(), buffer, buffer + strlen(buffer)); - unsigned char * currentRow = new unsigned char[vidBuf.Width*3]; - for(int y = 0; y < vidBuf.Height; y++) + data.reserve(data.size() + vidBuf.Size().X * vidBuf.Size().Y * 3); + + for (int i = 0; i < vidBuf.Size().X * vidBuf.Size().Y; i++) { - int rowPos = 0; - for(int x = 0; x < vidBuf.Width; x++) - { - currentRow[rowPos++] = PIXR(vidBuf.Buffer[(y*vidBuf.Width)+x]); - currentRow[rowPos++] = PIXG(vidBuf.Buffer[(y*vidBuf.Width)+x]); - currentRow[rowPos++] = PIXB(vidBuf.Buffer[(y*vidBuf.Width)+x]); - } - data.insert(data.end(), currentRow, currentRow+(vidBuf.Width*3)); + auto colour = RGB::Unpack(vidBuf.Data()[i]); + data.push_back(colour.Red); + data.push_back(colour.Green); + data.push_back(colour.Blue); } - delete [] currentRow; return data; } diff --git a/src/client/ThumbnailRendererTask.cpp b/src/client/ThumbnailRendererTask.cpp index f5a42356f..6b6f22a30 100644 --- a/src/client/ThumbnailRendererTask.cpp +++ b/src/client/ThumbnailRendererTask.cpp @@ -13,20 +13,15 @@ int ThumbnailRendererTask::QueueSize() return queueSize; } -ThumbnailRendererTask::ThumbnailRendererTask(GameSave const &save, Vec2 size, bool autoRescale, bool decorations, bool fire): +ThumbnailRendererTask::ThumbnailRendererTask(GameSave const &save, Vec2 size, bool decorations, bool fire): save(std::make_unique(save)), size(size), decorations(decorations), - fire(fire), - autoRescale(autoRescale) + fire(fire) { queueSize += 1; } -ThumbnailRendererTask::ThumbnailRendererTask(GameSave *save, int width, int height, bool autoRescale, bool decorations, bool fire): - ThumbnailRendererTask(*save, Vec2(width, height), autoRescale, decorations, fire) -{} - ThumbnailRendererTask::~ThumbnailRendererTask() { queueSize -= 1; @@ -37,15 +32,8 @@ bool ThumbnailRendererTask::doWork() thumbnail = std::unique_ptr(SaveRenderer::Ref().Render(save.get(), decorations, fire)); if (thumbnail) { - if (autoRescale) - { - thumbnail->ResizeToFit(size, true); - size = thumbnail->Size(); - } - else - { - thumbnail->Resize(size); - } + thumbnail->ResizeToFit(size, true); + size = thumbnail->Size(); return true; } else diff --git a/src/client/ThumbnailRendererTask.h b/src/client/ThumbnailRendererTask.h index 2518def20..8a57ef2f6 100644 --- a/src/client/ThumbnailRendererTask.h +++ b/src/client/ThumbnailRendererTask.h @@ -12,15 +12,12 @@ class ThumbnailRendererTask : public AbandonableTask Vec2 size; bool decorations; bool fire; - bool autoRescale; std::unique_ptr thumbnail; static int queueSize; public: - ThumbnailRendererTask(GameSave const &, Vec2 size, bool autoRescale, bool decorations, bool fire); - [[deprecated("Use ThumbnailRendererTask(GameSave const &, Vec2, bool, bool, bool)")]] - ThumbnailRendererTask(GameSave *save, int width, int height, bool autoRescale = false, bool decorations = true, bool fire = true); + ThumbnailRendererTask(GameSave const &, Vec2 size, bool decorations, bool fire); virtual ~ThumbnailRendererTask(); virtual bool doWork() override; diff --git a/src/common/Plane.h b/src/common/Plane.h index a40f66a28..c79ff701b 100644 --- a/src/common/Plane.h +++ b/src/common/Plane.h @@ -59,8 +59,6 @@ struct yExtent: extentStorage template class PlaneAdapter: xExtent, yExtent { - friend class VideoBuffer; // TODO: remove - using value_type = std::remove_reference_t()[0])>; using iterator = decltype(std::begin(std::declval())); using const_iterator = decltype(std::begin(std::declval())); diff --git a/src/common/Vec2.h b/src/common/Vec2.h index 6fd6c0198..b98a638e0 100644 --- a/src/common/Vec2.h +++ b/src/common/Vec2.h @@ -118,6 +118,14 @@ struct Vec2 return (*this + Vec2(0.5, 0.5)).Floor(); } + Vec2 Clamp(Rect rect) const + { + return Vec2( + std::clamp(X, rect.TopLeft.X, rect.BottomRight.X), + std::clamp(Y, rect.TopLeft.Y, rect.BottomRight.Y) + ); + } + // Return a rectangle starting at origin, whose dimensions match this vector template>> constexpr inline Rect OriginRect() const @@ -382,6 +390,12 @@ public: return BottomRight - TopLeft + Vec2(1, 1); } + template + Rect() + std::declval())> Inset(S delta) const + { + return Rect() + std::declval())>(TopLeft + Vec2(delta, delta), BottomRight - Vec2(delta, delta)); + } + template>> constexpr auto Range() const { diff --git a/src/graphics/Graphics.cpp b/src/graphics/Graphics.cpp index 4f29f908f..4181c2736 100644 --- a/src/graphics/Graphics.cpp +++ b/src/graphics/Graphics.cpp @@ -555,8 +555,8 @@ void Graphics::draw_rgba_image(const pixel *data, int w, int h, int x, int y, fl VideoBuffer Graphics::DumpFrame() { - VideoBuffer newBuffer(WINDOW); - std::copy_n(video.data(), WINDOW.X * WINDOW.Y, newBuffer.Data()); + VideoBuffer newBuffer(video.Size()); + std::copy_n(video.data(), video.Size().X * video.Size().Y, newBuffer.Data()); return newBuffer; } @@ -578,10 +578,10 @@ void Graphics::SetClipRect(int &x, int &y, int &w, int &h) bool VideoBuffer::WritePNG(const ByteString &path) const { - std::vector rowPointers(Height); - for (auto y = 0; y < Height; ++y) + std::vector rowPointers(Size().Y); + for (auto y = 0; y < Size().Y; ++y) { - rowPointers[y] = (png_const_bytep)&Buffer[y * Width]; + rowPointers[y] = (png_const_bytep)&*video.RowIterator(Vec2(0, y)); } png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) @@ -612,7 +612,7 @@ bool VideoBuffer::WritePNG(const ByteString &path) const auto &imf = *(InMemoryFile *)ud; imf.data.insert(imf.data.end(), data, data + length); }, NULL); - png_set_IHDR(png, info, Width, Height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + png_set_IHDR(png, info, Size().X, Size().Y, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png, info); png_set_filler(png, 0, PNG_FILLER_AFTER); png_set_bgr(png); diff --git a/src/graphics/Graphics.h b/src/graphics/Graphics.h index cfe372b09..f71a88cdf 100644 --- a/src/graphics/Graphics.h +++ b/src/graphics/Graphics.h @@ -21,13 +21,6 @@ class VideoBuffer: public RasterDrawMethods friend struct RasterDrawMethods; public: - [[deprecated("Use video")]] - std::vector &Buffer = video.Base; - [[deprecated("Use Size()")]] - size_t &Width = video.xExtent::extent; // See TODO in common/Plane.h - [[deprecated("Use Size()")]] - size_t &Height = video.yExtent::extent; - VideoBuffer(VideoBuffer const &) = default; VideoBuffer(pixel const *data, Vec2 size); VideoBuffer(pixel const *data, Vec2 size, size_t rowStride); diff --git a/src/graphics/RasterDrawMethodsImpl.h b/src/graphics/RasterDrawMethodsImpl.h index 774214b5d..a228546a5 100644 --- a/src/graphics/RasterDrawMethodsImpl.h +++ b/src/graphics/RasterDrawMethodsImpl.h @@ -427,7 +427,7 @@ void RasterDrawMethods::draw_image(const pixel *img, int x, int y, int template void RasterDrawMethods::draw_image(const VideoBuffer * vidBuf, int x, int y, int a) { - draw_image(vidBuf->Buffer.data(), x, y, vidBuf->Width, vidBuf->Height, a); + BlendImage(vidBuf->Data(), a, RectSized(Vec2(x, y), vidBuf->Size())); } #undef video diff --git a/src/graphics/RendererBasic.cpp b/src/graphics/RendererBasic.cpp index b4332b464..fe3d412c3 100644 --- a/src/graphics/RendererBasic.cpp +++ b/src/graphics/RendererBasic.cpp @@ -502,7 +502,7 @@ VideoBuffer Renderer::DumpFrame() VideoBuffer newBuffer(XRES, YRES); for(int y = 0; y < YRES; y++) { - std::copy(vid+(y*WINDOWW), vid+(y*WINDOWW)+XRES, newBuffer.Buffer.data()+(y*XRES)); + std::copy(vid+(y*WINDOWW), vid+(y*WINDOWW)+XRES, newBuffer.Data()+(y*XRES)); } return newBuffer; } diff --git a/src/gui/game/GameView.cpp b/src/gui/game/GameView.cpp index ac84e6451..ac7f8c71f 100644 --- a/src/gui/game/GameView.cpp +++ b/src/gui/game/GameView.cpp @@ -958,7 +958,7 @@ ByteString GameView::TakeScreenshot(int captureUI, int fileType) // We should be able to simply use SDL_PIXELFORMAT_XRGB8888 here with a bit depth of 32 to convert RGBA data to RGB data, // and save the resulting surface directly. However, ubuntu-18.04 ships SDL2 so old that it doesn't have // SDL_PIXELFORMAT_XRGB8888, so we first create an RGBA surface and then convert it. - auto *rgbaSurface = SDL_CreateRGBSurfaceWithFormatFrom(screenshot->Buffer.data(), screenshot->Width, screenshot->Height, 32, screenshot->Width * sizeof(pixel), SDL_PIXELFORMAT_ARGB8888); + auto *rgbaSurface = SDL_CreateRGBSurfaceWithFormatFrom(screenshot->Data(), screenshot->Size().X, screenshot->Size().Y, 32, screenshot->Size().X * sizeof(pixel), SDL_PIXELFORMAT_ARGB8888); auto *rgbSurface = SDL_ConvertSurfaceFormat(rgbaSurface, SDL_PIXELFORMAT_RGB888, 0); if (!rgbSurface || SDL_SaveBMP(rgbSurface, filename.c_str())) { @@ -1200,20 +1200,9 @@ void GameView::OnMouseUp(int x, int y, unsigned button) { if (placeSaveThumb && y <= WINDOWH-BARSIZE) { - int thumbX = selectPoint2.X - ((placeSaveThumb->Width-placeSaveOffset.X)/2); - int thumbY = selectPoint2.Y - ((placeSaveThumb->Height-placeSaveOffset.Y)/2); - - if (thumbX < 0) - thumbX = 0; - if (thumbX+(placeSaveThumb->Width) >= XRES) - thumbX = XRES-placeSaveThumb->Width; - - if (thumbY < 0) - thumbY = 0; - if (thumbY+(placeSaveThumb->Height) >= YRES) - thumbY = YRES-placeSaveThumb->Height; - - c->PlaceSave(ui::Point(thumbX, thumbY)); + auto thumb = selectPoint2 - (placeSaveThumb->Size() - placeSaveOffset) / 2; + thumb = thumb.Clamp(RectBetween(Vec2::Zero, RES - placeSaveThumb->Size())); + c->PlaceSave(thumb); } } else @@ -2145,24 +2134,11 @@ void GameView::OnDraw() { if(placeSaveThumb && selectPoint2.X!=-1) { - int thumbX = selectPoint2.X - ((placeSaveThumb->Width-placeSaveOffset.X)/2) + CELL/2; - int thumbY = selectPoint2.Y - ((placeSaveThumb->Height-placeSaveOffset.Y)/2) + CELL/2; - - ui::Point thumbPos = c->NormaliseBlockCoord(ui::Point(thumbX, thumbY)); - - if(thumbPos.X<0) - thumbPos.X = 0; - if(thumbPos.X+(placeSaveThumb->Width)>=XRES) - thumbPos.X = XRES-placeSaveThumb->Width; - - if(thumbPos.Y<0) - thumbPos.Y = 0; - if(thumbPos.Y+(placeSaveThumb->Height)>=YRES) - thumbPos.Y = YRES-placeSaveThumb->Height; - - ren->draw_image(placeSaveThumb, thumbPos.X, thumbPos.Y, 128); - - ren->xor_rect(thumbPos.X, thumbPos.Y, placeSaveThumb->Width, placeSaveThumb->Height); + auto thumb = selectPoint2 - (placeSaveThumb->Size() - placeSaveOffset) / 2 + Vec2(1, 1) * CELL / 2; + thumb = c->NormaliseBlockCoord(thumb).Clamp(RectBetween(Vec2::Zero, RES - placeSaveThumb->Size())); + auto rect = RectSized(thumb, placeSaveThumb->Size()); + ren->BlendImage(placeSaveThumb->Data(), 0x80, rect); + ren->XorDottedRect(rect); } } else diff --git a/src/gui/interface/SaveButton.cpp b/src/gui/interface/SaveButton.cpp index 4ef69a4ad..1f7bbee54 100644 --- a/src/gui/interface/SaveButton.cpp +++ b/src/gui/interface/SaveButton.cpp @@ -131,7 +131,7 @@ void SaveButton::Tick(float dt) { if(save->GetGameSave()) { - thumbnailRenderer = new ThumbnailRendererTask(save->GetGameSave(), thumbBoxSize.X, thumbBoxSize.Y); + thumbnailRenderer = new ThumbnailRendererTask(*save->GetGameSave(), thumbBoxSize, true, true); thumbnailRenderer->Start(); triedThumbnail = true; } @@ -144,7 +144,7 @@ void SaveButton::Tick(float dt) } else if (file && file->GetGameSave()) { - thumbnailRenderer = new ThumbnailRendererTask(file->GetGameSave(), thumbBoxSize.X, thumbBoxSize.Y, true, true, false); + thumbnailRenderer = new ThumbnailRendererTask(*file->GetGameSave(), thumbBoxSize, true, false); thumbnailRenderer->Start(); triedThumbnail = true; } @@ -168,7 +168,7 @@ void SaveButton::Tick(float dt) if (thumbnail && file) { - thumbSize = ui::Point(thumbnail->Width, thumbnail->Height); + thumbSize = thumbnail->Size(); } } if (file && !wantsDraw && !thumbnailRenderer) diff --git a/src/gui/preview/PreviewView.cpp b/src/gui/preview/PreviewView.cpp index e8c8e2a59..a6391f6c3 100644 --- a/src/gui/preview/PreviewView.cpp +++ b/src/gui/preview/PreviewView.cpp @@ -285,9 +285,9 @@ void PreviewView::OnDraw() g->clearrect(Position.X-2, Position.Y-2, Size.X+4, Size.Y+4); //Save preview (top-left) - if(savePreview) + if (savePreview) { - g->draw_image(savePreview, (Position.X+1)+(((XRES/2)-savePreview->Width)/2), (Position.Y+1)+(((YRES/2)-savePreview->Height)/2), 255); + g->BlendImage(savePreview->Data(), 0xFF, RectSized(Position + Vec2(1, 1) + (RES / 2 - savePreview->Size()) / 2, savePreview->Size())); } g->drawrect(Position.X, Position.Y, (XRES/2)+1, (YRES/2)+1, 255, 255, 255, 100); g->draw_line(Position.X+XRES/2, Position.Y+1, Position.X+XRES/2, Position.Y+Size.Y-2, 200, 200, 200, 255); diff --git a/src/gui/save/LocalSaveActivity.cpp b/src/gui/save/LocalSaveActivity.cpp index 56b42dc6e..241d0b188 100644 --- a/src/gui/save/LocalSaveActivity.cpp +++ b/src/gui/save/LocalSaveActivity.cpp @@ -58,7 +58,7 @@ LocalSaveActivity::LocalSaveActivity(SaveFile save, OnSaved onSaved_) : if(save.GetGameSave()) { - thumbnailRenderer = new ThumbnailRendererTask(save.GetGameSave(), Size.X-16, -1, false, true, false); + thumbnailRenderer = new ThumbnailRendererTask(*save.GetGameSave(), Size - Vec2(16, 16), true, false); thumbnailRenderer->Start(); } } @@ -135,13 +135,14 @@ void LocalSaveActivity::OnDraw() { Graphics * g = GetGraphics(); g->draw_rgba_image(&save_to_disk_image[0], save_to_disk_imageW, save_to_disk_imageH, 0, 0, 0.7f); - g->clearrect(Position.X-2, Position.Y-2, Size.X+3, Size.Y+3); - g->drawrect(Position.X, Position.Y, Size.X, Size.Y, 255, 255, 255, 255); + g->DrawFilledRect(RectSized(Position, Size).Inset(-1), 0x000000_rgb); + g->DrawRect(RectSized(Position, Size), 0xFFFFFF_rgb); - if(thumbnail) + if (thumbnail) { - g->draw_image(thumbnail.get(), Position.X+(Size.X-thumbnail->Width)/2, Position.Y+45, 255); - g->drawrect(Position.X+(Size.X-thumbnail->Width)/2, Position.Y+45, thumbnail->Width, thumbnail->Height, 180, 180, 180, 255); + auto rect = RectSized(Position + Vec2((Size.X - thumbnail->Size().X) / 2, 45), thumbnail->Size()); + g->BlendImage(thumbnail->Data(), 0xFF, rect); + g->DrawRect(rect, 0xB4B4B4_rgb); } } diff --git a/src/gui/save/ServerSaveActivity.cpp b/src/gui/save/ServerSaveActivity.cpp index d5f3d7856..a63dd47e4 100644 --- a/src/gui/save/ServerSaveActivity.cpp +++ b/src/gui/save/ServerSaveActivity.cpp @@ -147,7 +147,7 @@ ServerSaveActivity::ServerSaveActivity(SaveInfo save, OnUploaded onUploaded_) : if (save.GetGameSave()) { - thumbnailRenderer = new ThumbnailRendererTask(save.GetGameSave(), (Size.X/2)-16, -1, false, false, true); + thumbnailRenderer = new ThumbnailRendererTask(*save.GetGameSave(), Size / 2 - Vec2(16, 16), false, true); thumbnailRenderer->Start(); } } @@ -375,16 +375,17 @@ void ServerSaveActivity::OnDraw() { Graphics * g = GetGraphics(); g->draw_rgba_image(&save_to_server_image[0], save_to_server_imageW, save_to_server_imageH, -10, 0, 0.7f); - g->clearrect(Position.X-2, Position.Y-2, Size.X+3, Size.Y+3); - g->drawrect(Position.X, Position.Y, Size.X, Size.Y, 255, 255, 255, 255); + g->DrawFilledRect(RectSized(Position, Size).Inset(-1), 0x000000_rgb); + g->DrawRect(RectSized(Position, Size), 0xFFFFFF_rgb); - if(Size.X>220) - g->draw_line(Position.X+(Size.X/2)-1, Position.Y, Position.X+(Size.X/2)-1, Position.Y+Size.Y-1, 255, 255, 255, 255); + if (Size.X > 220) + g->DrawLine(Position + Vec2(Size.X / 2 - 1, 0), Position + Vec2(Size.X / 2 - 1, Size.Y - 1), 0xFFFFFF_rgb); - if(thumbnail) + if (thumbnail) { - g->draw_image(thumbnail.get(), Position.X+(Size.X/2)+((Size.X/2)-thumbnail->Width)/2, Position.Y+25, 255); - g->drawrect(Position.X+(Size.X/2)+((Size.X/2)-thumbnail->Width)/2, Position.Y+25, thumbnail->Width, thumbnail->Height, 180, 180, 180, 255); + auto rect = RectSized(Position + Vec2(Size.X / 2 + (Size.X / 2 - thumbnail->Size().X) / 2, 25), thumbnail->Size()); + g->BlendImage(thumbnail->Data(), 0xFF, rect); + g->DrawRect(rect, 0xB4B4B4_rgb); } }