Implement screenshots in SaveLoad menu
Also refactor item selection in ListBox.
This commit is contained in:
parent
bdedd88d9d
commit
61ac0f320d
9 changed files with 95 additions and 30 deletions
|
@ -565,6 +565,11 @@ void Game::openInGame() {
|
|||
}
|
||||
|
||||
void Game::openInGameMenu(InGameMenu::Tab tab) {
|
||||
// Take a screenshot to be used in SaveLoad menu
|
||||
_graphics.window().clear();
|
||||
_scene.worldRenderPipeline().setTakeScreenshot(true);
|
||||
_scene.worldRenderPipeline().render();
|
||||
|
||||
setCursorType(CursorType::Default);
|
||||
switch (tab) {
|
||||
case InGameMenu::Tab::Equipment:
|
||||
|
@ -805,10 +810,6 @@ bool Game::handleKeyDown(const SDL_KeyboardEvent &event) {
|
|||
}
|
||||
break;
|
||||
|
||||
case SDLK_p:
|
||||
_scene.worldRenderPipeline().setTakeScreenshot(true);
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <boost/iostreams/stream.hpp>
|
||||
|
||||
#include "../common/streamutil.h"
|
||||
#include "../graphics/texture/tgawriter.h"
|
||||
#include "../resource/format/erfreader.h"
|
||||
#include "../resource/format/erfwriter.h"
|
||||
#include "../resource/format/gffwriter.h"
|
||||
|
@ -33,6 +34,7 @@ namespace io = boost::iostreams;
|
|||
|
||||
using namespace std;
|
||||
|
||||
using namespace reone::graphics;
|
||||
using namespace reone::resource;
|
||||
|
||||
namespace reone {
|
||||
|
@ -40,8 +42,11 @@ namespace reone {
|
|||
namespace game {
|
||||
|
||||
static constexpr int kNfoBufferSize = 1024;
|
||||
static constexpr int kScreenBufferSize = 262144;
|
||||
|
||||
void Game::saveToFile(const fs::path &path) {
|
||||
// Prepare savenfo RES
|
||||
|
||||
GffStruct::Field nfoLastModuleFld(GffStruct::FieldType::CExoString, "LastModule");
|
||||
nfoLastModuleFld.strValue = _module->name();
|
||||
|
||||
|
@ -65,8 +70,28 @@ void Game::saveToFile(const fs::path &path) {
|
|||
nfoRes.resType = ResourceType::Res;
|
||||
nfoRes.data = move(nfoResData);
|
||||
|
||||
// Prepare screen TGA
|
||||
|
||||
ByteArray screenBuffer;
|
||||
screenBuffer.resize(kScreenBufferSize);
|
||||
io::array_sink screenSink(&screenBuffer[0], kScreenBufferSize);
|
||||
auto screenStream = make_shared<io::stream<io::array_sink>>(screenSink);
|
||||
|
||||
shared_ptr<Texture> screenshot(_scene.worldRenderPipeline().screenshot());
|
||||
TgaWriter tga(screenshot);
|
||||
tga.save(*screenStream);
|
||||
screenBuffer.resize(screenStream->tellp());
|
||||
|
||||
ErfWriter::Resource screenRes;
|
||||
screenRes.resRef = "screen";
|
||||
screenRes.resType = ResourceType::Tga;
|
||||
screenRes.data = move(screenBuffer);
|
||||
|
||||
// Save ERF
|
||||
|
||||
ErfWriter erf;
|
||||
erf.add(move(nfoRes));
|
||||
erf.add(move(screenRes));
|
||||
erf.save(ErfWriter::FileType::ERF, path);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "../../common/log.h"
|
||||
#include "../../common/streamutil.h"
|
||||
#include "../../graphics/texture/tgareader.h"
|
||||
#include "../../gui/control/listbox.h"
|
||||
#include "../../resource/format/erfreader.h"
|
||||
#include "../../resource/format/gffreader.h"
|
||||
|
@ -37,6 +38,7 @@ namespace fs = boost::filesystem;
|
|||
|
||||
using namespace std;
|
||||
|
||||
using namespace reone::graphics;
|
||||
using namespace reone::gui;
|
||||
using namespace reone::resource;
|
||||
|
||||
|
@ -68,7 +70,7 @@ void SaveLoad::load() {
|
|||
hideControl("LBL_AREANAME");
|
||||
|
||||
ListBox &lbGames = getControl<ListBox>("LB_GAMES");
|
||||
lbGames.setSelectionMode(ListBox::SelectionMode::Hilight);
|
||||
lbGames.setSelectionMode(ListBox::SelectionMode::OnClick);
|
||||
lbGames.setPadding(3);
|
||||
|
||||
Control &protoItem = lbGames.protoItem();
|
||||
|
@ -124,11 +126,19 @@ static SavedGame peekSavedGame(const fs::path &path) {
|
|||
erf.load(path);
|
||||
|
||||
shared_ptr<ByteArray> nfoData(erf.find("savenfo", ResourceType::Res));
|
||||
|
||||
GffReader nfo;
|
||||
nfo.load(wrap(nfoData));
|
||||
|
||||
shared_ptr<Texture> screen;
|
||||
shared_ptr<ByteArray> screenData(erf.find("screen", ResourceType::Tga));
|
||||
if (screenData) {
|
||||
TgaReader tga("screen", TextureUsage::GUI);
|
||||
tga.load(wrap(screenData));
|
||||
screen = tga.texture();
|
||||
}
|
||||
|
||||
SavedGame result;
|
||||
result.screen = move(screen);
|
||||
result.lastModule = nfo.root()->getString("LastModule");
|
||||
|
||||
return move(result);
|
||||
|
@ -199,7 +209,7 @@ void SaveLoad::onClick(const string &control) {
|
|||
int SaveLoad::getSelectedSaveNumber() const {
|
||||
ListBox &lbGames = getControl<ListBox>("LB_GAMES");
|
||||
|
||||
int hilightedIdx = lbGames.hilightedIndex();
|
||||
int hilightedIdx = lbGames.selectedItemIndex();
|
||||
if (hilightedIdx == -1) return -1;
|
||||
|
||||
string tag(lbGames.getItemAt(hilightedIdx).tag);
|
||||
|
@ -242,6 +252,36 @@ void SaveLoad::deleteGame(int number) {
|
|||
}
|
||||
}
|
||||
|
||||
void SaveLoad::onListBoxItemClick(const string &control, const string &item) {
|
||||
if (control != "LB_GAMES") return;
|
||||
|
||||
// Get save number by item tag
|
||||
int selectedSaveNumber = -1;
|
||||
auto &lbGames = getControl<ListBox>("LB_GAMES");
|
||||
for (int i = 0; i < lbGames.getItemCount(); ++i) {
|
||||
auto &lbItem = lbGames.getItemAt(i);
|
||||
if (lbItem.tag == item) {
|
||||
selectedSaveNumber = stoi(lbItem.tag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get save screenshot by save number
|
||||
shared_ptr<Texture> screenshot;
|
||||
if (selectedSaveNumber != -1) {
|
||||
for (auto &save : _saves) {
|
||||
if (save.number == selectedSaveNumber) {
|
||||
screenshot = save.save.screen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set screenshot
|
||||
Label &lblScreenshot = getControl<Label>("LBL_SCREENSHOT");
|
||||
lblScreenshot.setBorderFill(move(screenshot));
|
||||
}
|
||||
|
||||
} // namespace game
|
||||
|
||||
} // namespace reone
|
||||
|
|
|
@ -57,6 +57,7 @@ private:
|
|||
void indexSavedGame(boost::filesystem::path path);
|
||||
|
||||
void onClick(const std::string &control) override;
|
||||
void onListBoxItemClick(const std::string &control, const std::string &item) override;
|
||||
|
||||
void saveGame(int number);
|
||||
void loadGame(int number);
|
||||
|
|
|
@ -19,11 +19,14 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "../graphics/texture/texture.h"
|
||||
|
||||
namespace reone {
|
||||
|
||||
namespace game {
|
||||
|
||||
struct SavedGame {
|
||||
std::shared_ptr<graphics::Texture> screen;
|
||||
std::string lastModule;
|
||||
};
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ ListBox::ListBox(GUI *gui) : Control(gui, ControlType::ListBox) {
|
|||
void ListBox::clearItems() {
|
||||
_items.clear();
|
||||
_itemOffset = 0;
|
||||
_hilightedIndex = -1;
|
||||
_selectedItemIndex = -1;
|
||||
}
|
||||
|
||||
void ListBox::addItem(Item &&item) {
|
||||
|
@ -74,7 +74,7 @@ void ListBox::addTextLinesAsItems(const string &text) {
|
|||
}
|
||||
|
||||
void ListBox::clearSelection() {
|
||||
_hilightedIndex = -1;
|
||||
_selectedItemIndex = -1;
|
||||
}
|
||||
|
||||
void ListBox::load(const GffStruct &gffs) {
|
||||
|
@ -94,8 +94,8 @@ void ListBox::load(const GffStruct &gffs) {
|
|||
}
|
||||
|
||||
bool ListBox::handleMouseMotion(int x, int y) {
|
||||
if (_mode == SelectionMode::Propagate) {
|
||||
_hilightedIndex = getItemIndex(y);
|
||||
if (_selectionMode == SelectionMode::OnHover) {
|
||||
_selectedItemIndex = getItemIndex(y);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -168,14 +168,10 @@ bool ListBox::handleClick(int x, int y) {
|
|||
int itemIdx = getItemIndex(y);
|
||||
if (itemIdx == -1) return false;
|
||||
|
||||
switch (_mode) {
|
||||
case SelectionMode::Hilight:
|
||||
_hilightedIndex = itemIdx;
|
||||
break;
|
||||
case SelectionMode::Propagate:
|
||||
_gui->onListBoxItemClick(_tag, _items[itemIdx].tag);
|
||||
break;
|
||||
if (_selectionMode == SelectionMode::OnClick) {
|
||||
_selectedItemIndex = itemIdx;
|
||||
}
|
||||
_gui->onListBoxItemClick(_tag, _items[itemIdx].tag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -197,7 +193,7 @@ void ListBox::draw(const glm::ivec2 &offset, const vector<string> &text) {
|
|||
if (_protoMatchContent) {
|
||||
_protoItem->setHeight(static_cast<int>(item._textLines.size() * (_protoItem->text().font->height() + _padding)));
|
||||
}
|
||||
_protoItem->setFocus(_hilightedIndex == itemIdx);
|
||||
_protoItem->setFocus(_selectedItemIndex == itemIdx);
|
||||
|
||||
auto imageButton = dynamic_pointer_cast<ImageButton>(_protoItem);
|
||||
if (imageButton) {
|
||||
|
@ -239,8 +235,8 @@ void ListBox::stretch(float x, float y, int mask) {
|
|||
|
||||
void ListBox::setFocus(bool focus) {
|
||||
Control::setFocus(focus);
|
||||
if (!focus && _mode == SelectionMode::Propagate) {
|
||||
_hilightedIndex = -1;
|
||||
if (!focus && _selectionMode == SelectionMode::OnHover) {
|
||||
_selectedItemIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,7 +255,7 @@ void ListBox::setProtoItemType(ControlType type) {
|
|||
}
|
||||
|
||||
void ListBox::setSelectionMode(SelectionMode mode) {
|
||||
_mode = mode;
|
||||
_selectionMode = mode;
|
||||
}
|
||||
|
||||
void ListBox::setProtoMatchContent(bool match) {
|
||||
|
|
|
@ -30,8 +30,8 @@ constexpr int kDefaultSlotCount = 6;
|
|||
class ListBox : public Control {
|
||||
public:
|
||||
enum class SelectionMode {
|
||||
Hilight,
|
||||
Propagate
|
||||
OnHover,
|
||||
OnClick
|
||||
};
|
||||
|
||||
struct Item {
|
||||
|
@ -71,17 +71,17 @@ public:
|
|||
|
||||
Control &protoItem() const { return *_protoItem; }
|
||||
Control &scrollBar() const { return *_scrollBar; }
|
||||
int hilightedIndex() const { return _hilightedIndex; }
|
||||
int selectedItemIndex() const { return _selectedItemIndex; }
|
||||
|
||||
private:
|
||||
SelectionMode _mode { SelectionMode::Propagate };
|
||||
SelectionMode _selectionMode { SelectionMode::OnHover };
|
||||
ControlType _protoItemType { ControlType::Invalid };
|
||||
std::shared_ptr<Control> _protoItem;
|
||||
std::shared_ptr<Control> _scrollBar;
|
||||
std::vector<Item> _items;
|
||||
int _slotCount { 0 };
|
||||
int _itemOffset { 0 };
|
||||
int _hilightedIndex { -1 };
|
||||
int _selectedItemIndex { -1 };
|
||||
int _itemMargin { 0 };
|
||||
bool _protoMatchContent { false }; /**< proto item height must match its content */
|
||||
|
||||
|
|
|
@ -439,9 +439,6 @@ void WorldRenderPipeline::drawResult() {
|
|||
void WorldRenderPipeline::saveScreenshot() {
|
||||
_screenshotColor->bind();
|
||||
_screenshotColor->flushGPUToCPU();
|
||||
|
||||
TgaWriter tga(_screenshotColor);
|
||||
tga.save("screen.tga");
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
|
|
|
@ -40,6 +40,8 @@ public:
|
|||
void init();
|
||||
void render();
|
||||
|
||||
std::shared_ptr<graphics::Texture> screenshot() { return _screenshotColor; }
|
||||
|
||||
void setTakeScreenshot(bool take) { _takeScreenshot = take; }
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in a new issue