253 lines
7.2 KiB
C++
253 lines
7.2 KiB
C++
/*
|
|
Borealis, a Nintendo Switch UI Library
|
|
Copyright (C) 2019 WerWolv
|
|
Copyright (C) 2019 p-sam
|
|
|
|
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 3 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, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <borealis/application.hpp>
|
|
#include <borealis/image.hpp>
|
|
#include <cstring>
|
|
|
|
namespace brls
|
|
{
|
|
|
|
Image::Image(std::string imagePath)
|
|
{
|
|
this->setImage(imagePath);
|
|
this->setOpacity(1.0F);
|
|
}
|
|
|
|
Image::Image(unsigned char* buffer, size_t bufferSize)
|
|
{
|
|
this->setImage(buffer, bufferSize);
|
|
this->setOpacity(1.0F);
|
|
}
|
|
|
|
Image::Image(Image&& move) noexcept
|
|
: Image()
|
|
{
|
|
std::swap(*this, move);
|
|
move.texture = -1;
|
|
move.imageBuffer = nullptr;
|
|
}
|
|
|
|
Image::Image(const Image& copy)
|
|
: imagePath { copy.imagePath }
|
|
, imageBuffer { copy.copyImgBuf() }
|
|
, imageBufferSize { copy.imageBufferSize }
|
|
, texture { -1 } // We set as -1 so that reloadTexture() does not try to delete a texture.
|
|
, imgPaint { copy.imgPaint }
|
|
, imageScaleType { copy.imageScaleType }
|
|
, cornerRadius { copy.cornerRadius }
|
|
, imageX { copy.imageX }
|
|
, imageY { copy.imageY }
|
|
, imageWidth { copy.imageWidth }
|
|
, imageHeight { copy.imageHeight }
|
|
, origViewWidth { copy.origViewWidth }
|
|
, origViewHeight { copy.origViewHeight }
|
|
{
|
|
// Recreate the texture on copy.
|
|
reloadTexture();
|
|
}
|
|
|
|
unsigned char* Image::copyImgBuf() const
|
|
{
|
|
if (imageBuffer && imageBufferSize)
|
|
{
|
|
unsigned char* imageBuffer = new unsigned char[imageBufferSize];
|
|
memcpy(imageBuffer, this->imageBuffer, imageBufferSize);
|
|
return imageBuffer;
|
|
}
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
Image& Image::operator=(const Image& cp_assign)
|
|
{
|
|
return *this = cp_assign;
|
|
}
|
|
|
|
Image& Image::operator=(Image&& mv_assign)
|
|
{
|
|
std::swap(*this, mv_assign);
|
|
return *this;
|
|
}
|
|
|
|
Image::~Image()
|
|
{
|
|
if (this->imageBuffer != nullptr)
|
|
delete[] this->imageBuffer;
|
|
|
|
if (this->texture != -1)
|
|
nvgDeleteImage(Application::getNVGContext(), this->texture);
|
|
}
|
|
|
|
void Image::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
|
{
|
|
nvgSave(vg);
|
|
|
|
if (this->texture != -1)
|
|
{
|
|
nvgBeginPath(vg);
|
|
nvgRoundedRect(vg, x + this->imageX, y + this->imageY, this->imageWidth, this->imageHeight, this->cornerRadius);
|
|
nvgFillPaint(vg, a(this->imgPaint));
|
|
nvgFill(vg);
|
|
}
|
|
|
|
nvgRestore(vg);
|
|
}
|
|
|
|
void Image::reloadTexture()
|
|
{
|
|
NVGcontext* vg = Application::getNVGContext();
|
|
|
|
if (this->texture != -1)
|
|
nvgDeleteImage(vg, this->texture);
|
|
|
|
if (!this->imagePath.empty())
|
|
this->texture = nvgCreateImage(vg, this->imagePath.c_str(), 0);
|
|
else if (this->imageBuffer != nullptr)
|
|
this->texture = nvgCreateImageMem(vg, 0, this->imageBuffer, this->imageBufferSize);
|
|
}
|
|
|
|
void Image::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
|
{
|
|
if (this->origViewWidth == 0 || this->origViewHeight == 0)
|
|
{
|
|
this->origViewWidth = this->getWidth();
|
|
this->origViewHeight = this->getHeight();
|
|
}
|
|
|
|
nvgImageSize(vg, this->texture, &this->imageWidth, &this->imageHeight);
|
|
|
|
this->setWidth(this->origViewWidth);
|
|
this->setHeight(this->origViewHeight);
|
|
|
|
this->imageX = 0;
|
|
this->imageY = 0;
|
|
|
|
float viewAspectRatio = static_cast<float>(this->getWidth()) / static_cast<float>(this->getHeight());
|
|
float imageAspectRatio = static_cast<float>(this->imageWidth) / static_cast<float>(this->imageHeight);
|
|
|
|
switch (imageScaleType)
|
|
{
|
|
case ImageScaleType::NO_RESIZE:
|
|
this->imageX = (this->origViewWidth - this->imageWidth) / 2.0F;
|
|
this->imageY = (this->origViewHeight - this->imageHeight) / 2.0F;
|
|
break;
|
|
case ImageScaleType::FIT:
|
|
if (viewAspectRatio >= imageAspectRatio)
|
|
{
|
|
this->imageHeight = this->getHeight();
|
|
this->imageWidth = this->imageHeight * imageAspectRatio;
|
|
this->imageX = (this->origViewWidth - this->imageWidth) / 2.0F;
|
|
}
|
|
else
|
|
{
|
|
this->imageWidth = this->getWidth();
|
|
this->imageHeight = this->imageWidth * imageAspectRatio;
|
|
this->imageY = (this->origViewHeight - this->imageHeight) / 2.0F;
|
|
}
|
|
break;
|
|
case ImageScaleType::CROP:
|
|
if (viewAspectRatio < imageAspectRatio)
|
|
{
|
|
this->imageHeight = this->getHeight();
|
|
this->imageWidth = this->imageHeight * imageAspectRatio;
|
|
this->imageX = (this->origViewWidth - this->imageWidth) / 2.0F;
|
|
}
|
|
else
|
|
{
|
|
this->imageWidth = this->getWidth();
|
|
this->imageHeight = this->imageWidth * imageAspectRatio;
|
|
this->imageY = (this->origViewHeight - this->imageHeight) / 2.0F;
|
|
}
|
|
break;
|
|
case ImageScaleType::SCALE:
|
|
this->imageWidth = this->getWidth();
|
|
this->imageHeight = this->getHeight();
|
|
break;
|
|
case ImageScaleType::VIEW_RESIZE:
|
|
this->setWidth(this->imageWidth);
|
|
this->setHeight(this->imageHeight);
|
|
break;
|
|
}
|
|
|
|
this->imgPaint = nvgImagePattern(vg, getX() + this->imageX, getY() + this->imageY, this->imageWidth, this->imageHeight, 0, this->texture, this->alpha);
|
|
}
|
|
|
|
void Image::setImage(unsigned char* buffer, size_t bufferSize)
|
|
{
|
|
if (this->imageBuffer != nullptr)
|
|
delete[] this->imageBuffer;
|
|
|
|
this->imagePath = "";
|
|
|
|
this->imageBuffer = new unsigned char[bufferSize];
|
|
std::memcpy(this->imageBuffer, buffer, bufferSize);
|
|
this->imageBufferSize = bufferSize;
|
|
|
|
this->reloadTexture();
|
|
this->invalidate();
|
|
}
|
|
|
|
void Image::setImage(std::string imagePath)
|
|
{
|
|
this->imagePath = imagePath;
|
|
|
|
if (this->imageBuffer != nullptr)
|
|
delete[] this->imageBuffer;
|
|
|
|
this->imageBuffer = nullptr;
|
|
|
|
this->reloadTexture();
|
|
|
|
this->invalidate();
|
|
}
|
|
|
|
void Image::setOpacity(float opacity)
|
|
{
|
|
this->alpha = opacity;
|
|
this->invalidate();
|
|
}
|
|
|
|
void Image::setScaleType(ImageScaleType imageScaleType)
|
|
{
|
|
this->imageScaleType = imageScaleType;
|
|
this->invalidate();
|
|
}
|
|
|
|
} // namespace brls
|
|
|
|
namespace std
|
|
{
|
|
void swap(brls::Image& a, brls::Image& b)
|
|
{
|
|
swap(a.imagePath, b.imagePath);
|
|
swap(a.imageBuffer, b.imageBuffer);
|
|
swap(a.imageBufferSize, b.imageBufferSize);
|
|
swap(a.texture, b.texture);
|
|
swap(a.imgPaint, b.imgPaint);
|
|
swap(a.imageScaleType, b.imageScaleType);
|
|
swap(a.imageX, b.imageX);
|
|
swap(a.imageY, b.imageY);
|
|
swap(a.imageWidth, b.imageWidth);
|
|
swap(a.imageHeight, b.imageHeight);
|
|
swap(a.origViewWidth, b.origViewWidth);
|
|
swap(a.origViewHeight, b.origViewHeight);
|
|
}
|
|
}
|