Added zoom support to the PDF viewer

Also increased page rasterization resolution when running at lower screen resolutions
This commit is contained in:
Leon Styhre 2023-07-04 17:47:00 +02:00
parent ba05679cde
commit b60f86ae04
4 changed files with 188 additions and 46 deletions

View file

@ -29,7 +29,6 @@ PDFViewer::PDFViewer()
, mHelpInfoPosition {HelpInfoPosition::TOP} , mHelpInfoPosition {HelpInfoPosition::TOP}
{ {
Window::getInstance()->setPDFViewer(this); Window::getInstance()->setPDFViewer(this);
mTexture = TextureResource::get("");
} }
bool PDFViewer::startPDFViewer(FileData* game) bool PDFViewer::startPDFViewer(FileData* game)
@ -74,6 +73,19 @@ bool PDFViewer::startPDFViewer(FileData* game)
mPageCount = 0; mPageCount = 0;
mCurrentPage = 0; mCurrentPage = 0;
mScaleFactor = 1.0f; mScaleFactor = 1.0f;
mZoom = 1.0f;
mPanAmount = 0.0f;
mPanOffset = {0.0f, 0.0f, 0.0f};
// Increase the rasterization resolution when running at lower screen resolutions to make
// the texture look ok when zoomed in.
const float resolutionModifier {mRenderer->getScreenResolutionModifier()};
if (resolutionModifier < 1.0f)
mScaleFactor = 1.8f;
else if (resolutionModifier < 1.2f)
mScaleFactor = 1.3f;
else if (resolutionModifier < 1.4f)
mScaleFactor = 1.15f;
if (!getDocumentInfo()) { if (!getDocumentInfo()) {
LOG(LogError) << "PDFViewer: Couldn't load file \"" << mManualPath << "\""; LOG(LogError) << "PDFViewer: Couldn't load file \"" << mManualPath << "\"";
@ -303,11 +315,13 @@ void PDFViewer::convertPage(int pageNum)
{ {
assert(pageNum <= static_cast<int>(mPages.size())); assert(pageNum <= static_cast<int>(mPages.size()));
if (mPages[pageNum].imageData.empty()) {
#if defined(_WIN64) #if defined(_WIN64)
std::wstring command { std::wstring command {
Utils::String::stringToWideString(Utils::FileSystem::getEscapedPath(mESConvertPath))}; Utils::String::stringToWideString(Utils::FileSystem::getEscapedPath(mESConvertPath))};
command.append(L" -convert ") command.append(L" -convert ")
.append(Utils::String::stringToWideString(Utils::FileSystem::getEscapedPath(mManualPath))) .append(
Utils::String::stringToWideString(Utils::FileSystem::getEscapedPath(mManualPath)))
.append(L" ") .append(L" ")
.append(std::to_wstring(pageNum)) .append(std::to_wstring(pageNum))
.append(L" ") .append(L" ")
@ -326,7 +340,6 @@ void PDFViewer::convertPage(int pageNum)
.append(std::to_string(static_cast<int>(mPages[pageNum].height))); .append(std::to_string(static_cast<int>(mPages[pageNum].height)));
#endif #endif
if (mPages[pageNum].imageData.empty()) {
#if (DEBUG_PDF_CONVERSION) #if (DEBUG_PDF_CONVERSION)
LOG(LogDebug) << "Converting page: " << mCurrentPage; LOG(LogDebug) << "Converting page: " << mCurrentPage;
#if defined(_WIN64) #if defined(_WIN64)
@ -436,6 +449,7 @@ void PDFViewer::convertPage(int pageNum)
mPageImage.reset(); mPageImage.reset();
mPageImage = std::make_unique<ImageComponent>(false, false); mPageImage = std::make_unique<ImageComponent>(false, false);
mPageImage->setFlipY(true); mPageImage->setFlipY(true);
mPageImage->setLinearInterpolation(true);
mPageImage->setOrigin(0.5f, 0.5f); mPageImage->setOrigin(0.5f, 0.5f);
if (mHelpInfoPosition == HelpInfoPosition::TOP) { if (mHelpInfoPosition == HelpInfoPosition::TOP) {
mPageImage->setPosition(mRenderer->getScreenWidth() / 2.0f, mPageImage->setPosition(mRenderer->getScreenWidth() / 2.0f,
@ -451,16 +465,20 @@ void PDFViewer::convertPage(int pageNum)
} }
float sizeReduction {0.0f}; float sizeReduction {0.0f};
if (mPages[pageNum].height > mRenderer->getScreenHeight() - mFrameHeight) if (mPages[pageNum].height / mScaleFactor > mRenderer->getScreenHeight() - mFrameHeight)
sizeReduction = mPages[pageNum].height - (mRenderer->getScreenHeight() - mFrameHeight); sizeReduction =
(mPages[pageNum].height / mScaleFactor) - (mRenderer->getScreenHeight() - mFrameHeight);
mPageImage->setMaxSize(glm::vec2 {mPages[pageNum].width / mScaleFactor, mPageImage->setMaxSize(
(mPages[pageNum].height / mScaleFactor) - sizeReduction}); glm::vec2 {(mPages[pageNum].width / mScaleFactor) * mZoom,
((mPages[pageNum].height / mScaleFactor) * mZoom) - sizeReduction});
mPageImage->setRawImage(reinterpret_cast<const unsigned char*>(&mPages[pageNum].imageData[0]), mPageImage->setRawImage(reinterpret_cast<const unsigned char*>(&mPages[pageNum].imageData[0]),
static_cast<size_t>(mPages[pageNum].width), static_cast<size_t>(mPages[pageNum].width),
static_cast<size_t>(mPages[pageNum].height)); static_cast<size_t>(mPages[pageNum].height));
mPanAmount = std::min(mRenderer->getScreenWidth(), mRenderer->getScreenHeight()) * 0.1f;
#if (DEBUG_PDF_CONVERSION) #if (DEBUG_PDF_CONVERSION)
LOG(LogDebug) << "ABGR32 data stream size: " << mPages[pageNum].imageData.size(); LOG(LogDebug) << "ABGR32 data stream size: " << mPages[pageNum].imageData.size();
#endif #endif
@ -475,9 +493,15 @@ void PDFViewer::render(const glm::mat4& /*parentTrans*/)
mRenderer->drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), mRenderer->drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(),
0x000000FF, 0x000000FF); 0x000000FF, 0x000000FF);
if (mZoom != 1.0f)
mPageImage->setPosition(mPageImage->getPosition() + (mPanOffset * mZoom));
if (mPageImage != nullptr) if (mPageImage != nullptr)
mPageImage->render(trans); mPageImage->render(trans);
if (mZoom != 1.0f)
mPageImage->setPosition(mPageImage->getPosition() - (mPanOffset * mZoom));
if (mHelpInfoPosition != HelpInfoPosition::DISABLED) { if (mHelpInfoPosition != HelpInfoPosition::DISABLED) {
// Render a dark gray frame behind the help info. // Render a dark gray frame behind the help info.
mRenderer->setMatrix(mRenderer->getIdentity()); mRenderer->setMatrix(mRenderer->getIdentity());
@ -494,10 +518,18 @@ void PDFViewer::render(const glm::mat4& /*parentTrans*/)
std::vector<HelpPrompt> PDFViewer::getHelpPrompts() std::vector<HelpPrompt> PDFViewer::getHelpPrompts()
{ {
std::vector<HelpPrompt> prompts; std::vector<HelpPrompt> prompts;
if (mZoom > 1.0f) {
prompts.push_back(HelpPrompt("up/down/left/right", "pan"));
prompts.push_back(HelpPrompt("ltrt", "reset"));
}
else {
prompts.push_back(HelpPrompt("left/right", "browse")); prompts.push_back(HelpPrompt("left/right", "browse"));
prompts.push_back(HelpPrompt("down", "game media")); prompts.push_back(HelpPrompt("down", "game media"));
prompts.push_back(HelpPrompt("lt", "first")); prompts.push_back(HelpPrompt("lt", "first"));
prompts.push_back(HelpPrompt("rt", "last")); prompts.push_back(HelpPrompt("rt", "last"));
}
prompts.push_back(HelpPrompt("lr", "zoom"));
return prompts; return prompts;
} }
@ -524,22 +556,110 @@ void PDFViewer::showPreviousPage()
convertPage(mCurrentPage); convertPage(mCurrentPage);
} }
void PDFViewer::showFirstPage() void PDFViewer::navigateUp()
{ {
if (mZoom != 1.0f) {
if (mPanOffset.y * mZoom <= mPageImage->getSize().y / 2.0f)
mPanOffset.y += mPanAmount;
}
}
void PDFViewer::navigateDown()
{
if (mZoom != 1.0f) {
if (mPanOffset.y * mZoom >= -(mPageImage->getSize().y / 2.0f))
mPanOffset.y -= mPanAmount;
}
else {
launchMediaViewer();
}
}
void PDFViewer::navigateLeft()
{
if (mZoom != 1.0f) {
if (mPanOffset.x * mZoom <= mPageImage->getSize().x / 2.0f)
mPanOffset.x += mPanAmount;
}
else {
mPanOffset = {0.0f, 0.0f, 0.0f};
showPreviousPage();
}
}
void PDFViewer::navigateRight()
{
if (mZoom != 1.0f) {
if (mPanOffset.x * mZoom > -(mPageImage->getSize().x / 2.0f))
mPanOffset.x -= mPanAmount;
}
else {
mPanOffset = {0.0f, 0.0f, 0.0f};
showNextPage();
}
}
void PDFViewer::navigateRightShoulder()
{
if (mZoom <= 2.5f)
mZoom += 0.5f;
if (mZoom == 1.5f)
mHelp->setPrompts(getHelpPrompts());
convertPage(mCurrentPage);
}
void PDFViewer::navigateLeftShoulder()
{
if (mZoom == 1.0f)
mPanOffset = {0.0f, 0.0f, 0.0f};
if (mZoom >= 1.5f)
mZoom -= 0.5f;
if (mZoom == 1.0f)
mHelp->setPrompts(getHelpPrompts());
convertPage(mCurrentPage);
}
void PDFViewer::navigateLeftTrigger()
{
if (mZoom != 1.0f) {
mZoom = 1.0f;
mPanOffset = {0.0f, 0.0f, 0.0f};
mHelp->setPrompts(getHelpPrompts());
convertPage(mCurrentPage);
return;
}
if (mCurrentPage == 1) if (mCurrentPage == 1)
return; return;
mPanOffset = {0.0f, 0.0f, 0.0f};
NavigationSounds::getInstance().playThemeNavigationSound(SCROLLSOUND); NavigationSounds::getInstance().playThemeNavigationSound(SCROLLSOUND);
mCurrentPage = 1; mCurrentPage = 1;
mEntryNumText->setText(std::to_string(mCurrentPage) + "/" + mEntryCount); mEntryNumText->setText(std::to_string(mCurrentPage) + "/" + mEntryCount);
convertPage(mCurrentPage); convertPage(mCurrentPage);
} }
void PDFViewer::showLastPage() void PDFViewer::navigateRightTrigger()
{ {
if (mZoom != 1.0f) {
mZoom = 1.0f;
mPanOffset = {0.0f, 0.0f, 0.0f};
mHelp->setPrompts(getHelpPrompts());
convertPage(mCurrentPage);
return;
}
if (mCurrentPage == mPageCount) if (mCurrentPage == mPageCount)
return; return;
mPanOffset = {0.0f, 0.0f, 0.0f};
NavigationSounds::getInstance().playThemeNavigationSound(SCROLLSOUND); NavigationSounds::getInstance().playThemeNavigationSound(SCROLLSOUND);
mCurrentPage = mPageCount; mCurrentPage = mPageCount;
mEntryNumText->setText(std::to_string(mCurrentPage) + "/" + mEntryCount); mEntryNumText->setText(std::to_string(mCurrentPage) + "/" + mEntryCount);

View file

@ -37,10 +37,19 @@ public:
}; };
private: private:
void showNextPage() override; void showNextPage();
void showPreviousPage() override; void showPreviousPage();
void showFirstPage() override;
void showLastPage() override; void navigateUp() override;
void navigateDown() override;
void navigateLeft() override;
void navigateRight() override;
void navigateLeftShoulder() override;
void navigateRightShoulder() override;
void navigateLeftTrigger() override;
void navigateRightTrigger() override;
struct PageEntry { struct PageEntry {
float width; float width;
@ -56,11 +65,13 @@ private:
float mScaleFactor; float mScaleFactor;
int mCurrentPage; int mCurrentPage;
int mPageCount; int mPageCount;
float mZoom;
float mPanAmount;
glm::vec3 mPanOffset;
std::string mESConvertPath; std::string mESConvertPath;
std::string mManualPath; std::string mManualPath;
std::shared_ptr<TextureResource> mTexture;
std::unique_ptr<ImageComponent> mPageImage; std::unique_ptr<ImageComponent> mPageImage;
std::map<int, PageEntry> mPages; std::map<int, PageEntry> mPages;

View file

@ -249,23 +249,29 @@ void Window::input(InputConfig* config, Input input)
if (mPDFViewer && mRenderPDFViewer) { if (mPDFViewer && mRenderPDFViewer) {
if (config->isMappedLike("up", input) && input.value != 0) { if (config->isMappedLike("up", input) && input.value != 0) {
return; mPDFViewer->navigateUp();
} }
else if (config->isMappedLike("down", input) && input.value != 0) { else if (config->isMappedLike("down", input) && input.value != 0) {
mPDFViewer->launchMediaViewer(); mPDFViewer->navigateDown();
return; return;
} }
else if (config->isMappedLike("left", input) && input.value != 0) { else if (config->isMappedLike("left", input) && input.value != 0) {
mPDFViewer->showPreviousPage(); mPDFViewer->navigateLeft();
} }
else if (config->isMappedLike("right", input) && input.value != 0) { else if (config->isMappedLike("right", input) && input.value != 0) {
mPDFViewer->showNextPage(); mPDFViewer->navigateRight();
}
else if (config->isMappedLike("leftshoulder", input) && input.value != 0) {
mPDFViewer->navigateLeftShoulder();
}
else if (config->isMappedLike("rightshoulder", input) && input.value != 0) {
mPDFViewer->navigateRightShoulder();
} }
else if (config->isMappedLike("lefttrigger", input) && input.value != 0) { else if (config->isMappedLike("lefttrigger", input) && input.value != 0) {
mPDFViewer->showFirstPage(); mPDFViewer->navigateLeftTrigger();
} }
else if (config->isMappedLike("righttrigger", input) && input.value != 0) { else if (config->isMappedLike("righttrigger", input) && input.value != 0) {
mPDFViewer->showLastPage(); mPDFViewer->navigateRightTrigger();
} }
else if (input.value != 0) { else if (input.value != 0) {
// Any other input stops the PDF viewer. // Any other input stops the PDF viewer.

View file

@ -75,10 +75,15 @@ public:
virtual void stopPDFViewer() = 0; virtual void stopPDFViewer() = 0;
virtual void launchMediaViewer() = 0; virtual void launchMediaViewer() = 0;
virtual void showNextPage() = 0; virtual void navigateUp() = 0;
virtual void showPreviousPage() = 0; virtual void navigateDown() = 0;
virtual void showFirstPage() = 0; virtual void navigateLeft() = 0;
virtual void showLastPage() = 0; virtual void navigateRight() = 0;
virtual void navigateLeftShoulder() = 0;
virtual void navigateRightShoulder() = 0;
virtual void navigateLeftTrigger() = 0;
virtual void navigateRightTrigger() = 0;
virtual void render(const glm::mat4& parentTrans) = 0; virtual void render(const glm::mat4& parentTrans) = 0;
virtual std::vector<HelpPrompt> getHelpPrompts() = 0; virtual std::vector<HelpPrompt> getHelpPrompts() = 0;