VOXEDIT: added palette import and load to ui

master
Martin Gerhardy 2019-07-03 22:17:57 +02:00
parent 7d61cbedc4
commit 14a4850a8f
22 changed files with 192 additions and 35 deletions

View File

@ -1,5 +1,5 @@
# import the palette
createpalette images/01.png
importpalette images/01.png
# import the frames front and back side
importplane images/01.png
@ -52,4 +52,3 @@ layermerge 13 14
# let's play
animate 150

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -9,6 +9,8 @@ elements
bitmap voxedit-flip-vertical.png
voxedit-load
bitmap voxedit-load.png
voxedit-import-palette
bitmap voxedit-import-palette.png
voxedit-down
bitmap voxedit-up.png
flip-y 1

View File

@ -58,6 +58,12 @@ TBLayout: distribution: gravity, axis: y
TBLayout: position: left top, axis: y
lp: padding: 0
PaletteWidget: id: palettecontainer, width: 20, height: 20, amount-x: 9, connection: current-voxel-color
TBLayout: position: right top, axis: x
lp: padding: 0
TBButton: @include: definitions>menubutton, text: Import, command: "importpalette"
TBSkinImage: skin: voxedit-import-palette
TBButton: @include: definitions>menubutton, text: Load, id: loadpalette
TBSkinImage: skin: voxedit-load
TBSection: value: 1, text: "Tools", is-group-root: 1
TBLayout: position: left top, axis: y

View File

@ -0,0 +1,13 @@
WindowInfo
title Select existing palette
position 500 0
TBLayout: distribution: gravity, axis: y
TBSelectList
id palettes
gravity all
TBSeparator: gravity: left right, skin: separator
TBLayout: distribution: gravity, axis: x
TBButton: text: Ok, id: ok, autofocus: 1, gravity: left right, size: gravity
TBButton: text: Cancel, id: cancel, gravity: left right, size: gravity

View File

@ -255,7 +255,7 @@ bool Filesystem::isRelativePath(const std::string& name) {
return name[1] != ':';
#else
if (size == 0) {
return false;
return true;
}
return name[0] != '/';
#endif

View File

@ -211,7 +211,7 @@ void TBSelectList::setValue(int value) {
invokeEvent(ev);
}
TBID TBSelectList::getSelectedItemID() {
TBID TBSelectList::getSelectedItemID() const {
if ((m_source != nullptr) && m_value >= 0 && m_value < m_source->getNumItems()) {
return m_source->getItemID(m_value);
}

View File

@ -60,7 +60,7 @@ public:
}
/** Get the ID of the selected item, or 0 if there is no item selected. */
TBID getSelectedItemID();
TBID getSelectedItemID() const;
/** Change the value to a non disabled item that is visible with the current
filter. Returns true if it successfully found another item.

View File

@ -105,16 +105,16 @@ public:
* @brief Wrapper method for @c fileDialog()
* @param[in] filter png,jpg;psd The default filter is for png and jpg files. A second filter is available for psd files. There is a wildcard option in a dropdown.
*/
void saveDialog(const std::function<void(const std::string&)>& callback, const std::string& filter = "");
void saveDialog(const std::function<void(const std::string)>& callback, const std::string& filter = "");
/**
* @brief Wrapper method for @c fileDialog()
* @param[in] filter png,jpg;psd The default filter is for png and jpg files. A second filter is available for psd files. There is a wildcard option in a dropdown.
*/
void openDialog(const std::function<void(const std::string&)>& callback, const std::string& filter = "");
void openDialog(const std::function<void(const std::string)>& callback, const std::string& filter = "");
/**
* @brief Wrapper method for @c fileDialog()
*/
void directoryDialog(const std::function<void(const std::string&)>& callback);
void directoryDialog(const std::function<void(const std::string)>& callback);
virtual core::AppState onRunning() override;
virtual void onAfterRunning() override;
@ -143,15 +143,15 @@ inline int WindowedApp::frameBufferHeight() const {
return _frameBufferDimension.y;
}
inline void WindowedApp::saveDialog(const std::function<void(const std::string&)>& callback, const std::string& filter) {
inline void WindowedApp::saveDialog(const std::function<void(const std::string)>& callback, const std::string& filter) {
fileDialog(callback, OpenFileMode::Save, filter);
}
inline void WindowedApp::openDialog(const std::function<void(const std::string&)>& callback, const std::string& filter) {
inline void WindowedApp::openDialog(const std::function<void(const std::string)>& callback, const std::string& filter) {
fileDialog(callback, OpenFileMode::Open, filter);
}
inline void WindowedApp::directoryDialog(const std::function<void(const std::string&)>& callback) {
inline void WindowedApp::directoryDialog(const std::function<void(const std::string)>& callback) {
fileDialog(callback, OpenFileMode::Directory);
}

View File

@ -260,10 +260,26 @@ bool overrideMaterialColors(const io::FilePtr& paletteFile, const io::FilePtr& l
return overrideMaterialColors(img->data(), img->width() * img->height() * img->depth(), luaFile->load());
}
const char* getDefaultPaletteName() {
return "nippon";
}
std::string extractPaletteName(const std::string& file) {
if (!core::string::startsWith(file, "palette-")) {
return "";
}
const std::string& nameWithExtension = file.substr(8);
const size_t extPos = nameWithExtension.rfind('.');
if (extPos != std::string::npos) {
return nameWithExtension.substr(0, extPos);
}
return nameWithExtension;
}
bool initDefaultMaterialColors() {
const io::FilesystemPtr& filesystem = core::App::getInstance()->filesystem();
const io::FilePtr& paletteFile = filesystem->open("palette-nippon.png");
const io::FilePtr& luaFile = filesystem->open("palette-nippon.lua");
const io::FilePtr& paletteFile = filesystem->open(core::string::format("palette-%s.png", getDefaultPaletteName()));
const io::FilePtr& luaFile = filesystem->open(core::string::format("palette-%s.lua", getDefaultPaletteName()));
return initMaterialColors(paletteFile, luaFile);
}

View File

@ -22,6 +22,9 @@ namespace voxel {
typedef std::vector<glm::vec4> MaterialColorArray;
typedef std::vector<uint8_t> MaterialColorIndices;
extern const char* getDefaultPaletteName();
extern std::string extractPaletteName(const std::string& file);
extern bool initDefaultMaterialColors();
extern bool initMaterialColors(const io::FilePtr& paletteFile, const io::FilePtr& luaFile);
extern bool initMaterialColors(const uint8_t* paletteBuffer, size_t paletteBufferSize, const std::string& luaBuffer);

View File

@ -6,6 +6,7 @@ set(SRCS
ui/editorscene/Controller.h ui/editorscene/Controller.cpp
ui/palette/PaletteWidget.h ui/palette/PaletteWidget.cpp
ui/palette/PaletteSelector.h ui/palette/PaletteSelector.cpp
ui/settings/SceneSettingsWindow.h ui/settings/SceneSettingsWindow.cpp
@ -28,6 +29,7 @@ set(UI_WINDOWS
voxedit/ui/window/voxedit-layer.tb.txt
voxedit/ui/window/voxedit-main.tb.txt
voxedit/ui/window/voxedit-noise.tb.txt
voxedit/ui/window/voxedit-palette-selector.tb.txt
voxedit/ui/window/voxedit-scene-settings.tb.txt
voxedit/ui/window/voxedit-tree.tb.txt
)
@ -47,6 +49,7 @@ set(IMAGES
voxedit/ui/skin/voxedit-extend
voxedit/ui/skin/voxedit-flip-horizontal
voxedit/ui/skin/voxedit-flip-vertical
voxedit/ui/skin/voxedit-import-palette
voxedit/ui/skin/voxedit-load
voxedit/ui/skin/voxedit-lock-layer
voxedit/ui/skin/voxedit-lock-layer-selected

View File

@ -77,4 +77,3 @@ my own engine and evolved into something that others might find useful, too.
* Fix memento states for merge of layers
* Fix memento states for layer group modifications
* Add createpalette and loadpalette ui options to palette panel

View File

@ -25,6 +25,10 @@ bool VoxEdit::importplaneFile(const std::string& file) {
return _mainWindow->importAsPlane(file);
}
bool VoxEdit::importpaletteFile(const std::string& file) {
return _mainWindow->importPalette(file);
}
bool VoxEdit::saveFile(const std::string& file) {
return _mainWindow->save(file);
}
@ -87,6 +91,7 @@ core::AppState VoxEdit::onConstruct() {
COMMAND_FILE(import, "Import a mesh from the given file and tries to voxelize it");
COMMAND_FILE(importheightmap, "Import a heightmap into the volume");
COMMAND_FILE(importplane, "Import an image as a plane");
COMMAND_FILE(importpalette, "Import an image as a palette");
#undef COMMAND_FILE
core::Command::registerCommand("new",

View File

@ -27,6 +27,7 @@ public:
bool importheightmapFile(const std::string& file);
bool importplaneFile(const std::string& file);
bool importpaletteFile(const std::string& file);
bool saveFile(const std::string& file);
bool loadFile(const std::string& file);
bool screenshotFile(const std::string& file);

View File

@ -6,6 +6,7 @@
#include "NoiseWindow.h"
#include "TreeWindow.h"
#include "palette/PaletteWidget.h"
#include "palette/PaletteSelector.h"
#include "io/Filesystem.h"
#include "video/WindowedApp.h"
#include "core/Var.h"
@ -405,6 +406,8 @@ bool VoxEditWindow::handleClickEvent(const tb::TBWidgetEvent &ev) {
if (!settings->show()) {
delete settings;
}
} else if (id == TBIDC("loadpalette")) {
new PaletteSelector(this);
} else if (id == TBIDC("scene_settings") && ev.ref_id == TBIDC("ok")) {
auto &renderer = sceneMgr().renderer();
if (_settings.ambientDirty) {
@ -767,16 +770,25 @@ void VoxEditWindow::quit() {
bool VoxEditWindow::importAsPlane(const std::string& file) {
if (file.empty()) {
getApp()->openDialog([this] (const std::string& file) { importAsPlane(file); }, "png");
getApp()->openDialog([this] (const std::string file) { importAsPlane(file); }, "png");
return true;
}
return sceneMgr().importAsPlane(file);
}
bool VoxEditWindow::importPalette(const std::string& file) {
if (file.empty()) {
getApp()->openDialog([this] (const std::string file) { importPalette(file); }, "png");
return true;
}
return sceneMgr().importPalette(file);
}
bool VoxEditWindow::importHeightmap(const std::string& file) {
if (file.empty()) {
getApp()->openDialog([this] (const std::string& file) { importHeightmap(file); }, "png");
getApp()->openDialog([this] (const std::string file) { importHeightmap(file); }, "png");
return true;
}
@ -785,7 +797,7 @@ bool VoxEditWindow::importHeightmap(const std::string& file) {
bool VoxEditWindow::save(const std::string& file) {
if (file.empty()) {
getApp()->saveDialog([this] (const std::string& file) {save(file); }, SUPPORTED_VOXEL_FORMATS_SAVE);
getApp()->saveDialog([this] (const std::string file) {save(file); }, SUPPORTED_VOXEL_FORMATS_SAVE);
return true;
}
if (!sceneMgr().save(file)) {
@ -800,7 +812,7 @@ bool VoxEditWindow::save(const std::string& file) {
bool VoxEditWindow::saveScreenshot(const std::string& file) {
if (file.empty()) {
getApp()->saveDialog([this] (const std::string& file) {saveScreenshot(file); }, "png");
getApp()->saveDialog([this] (const std::string file) {saveScreenshot(file); }, "png");
return true;
}
if (!_scene->saveImage(file.c_str())) {
@ -813,7 +825,7 @@ bool VoxEditWindow::saveScreenshot(const std::string& file) {
bool VoxEditWindow::importMesh(const std::string& file) {
if (file.empty()) {
getApp()->openDialog([this] (const std::string& file) {importMesh(file);}, _importFilter);
getApp()->openDialog([this] (const std::string file) {importMesh(file);}, _importFilter);
return true;
}
if (!sceneMgr().dirty()) {
@ -838,7 +850,7 @@ bool VoxEditWindow::exportFile(const std::string& file) {
if (_exportFilter.empty()) {
return false;
}
getApp()->saveDialog([this] (const std::string& file) { exportFile(file); }, _exportFilter);
getApp()->saveDialog([this] (const std::string file) { exportFile(file); }, _exportFilter);
return true;
}
return sceneMgr().exportModel(file);
@ -859,7 +871,7 @@ void VoxEditWindow::resetCamera() {
bool VoxEditWindow::prefab(const std::string& file) {
if (file.empty()) {
getApp()->openDialog([this] (const std::string& file) { prefab(file); }, SUPPORTED_VOXEL_FORMATS_LOAD);
getApp()->openDialog([this] (const std::string file) { prefab(file); }, SUPPORTED_VOXEL_FORMATS_LOAD);
return true;
}
@ -873,7 +885,7 @@ void VoxEditWindow::afterLoad(const std::string& file) {
bool VoxEditWindow::load(const std::string& file) {
if (file.empty()) {
getApp()->openDialog([this] (const std::string& file) { std::string copy(file); load(copy); }, SUPPORTED_VOXEL_FORMATS_LOAD);
getApp()->openDialog([this] (const std::string file) { std::string copy(file); load(copy); }, SUPPORTED_VOXEL_FORMATS_LOAD);
return true;
}

View File

@ -102,6 +102,7 @@ private:
bool importMesh(const std::string& file);
bool importHeightmap(const std::string& file);
bool importAsPlane(const std::string& file);
bool importPalette(const std::string& file);
bool save(const std::string& file);
bool load(const std::string& file);
bool saveScreenshot(const std::string& file);

View File

@ -0,0 +1,77 @@
/**
* @file
*/
#include "PaletteSelector.h"
#include "voxedit-util/SceneManager.h"
namespace voxedit {
static const char *PALETTELIST = "palettes";
PaletteSelector::PaletteSelector(ui::turbobadger::Window* window) :
Super(window) {
core_assert_always(loadResourceFile("ui/window/voxedit-palette-selector.tb.txt"));
_currentSelectedPalette = voxel::getDefaultPaletteName();
std::vector<io::Filesystem::DirEntry> entities;
core::App::getInstance()->filesystem()->list("", entities, "palette-*.png");
if (entities.empty()) {
Log::error("Could not find any palettes");
}
for (const io::Filesystem::DirEntry& file : entities) {
if (file.type != io::Filesystem::DirEntry::Type::file) {
continue;
}
const std::string& name = voxel::extractPaletteName(file.name);
_paletteList.addItem(new tb::TBGenericStringItem(name.c_str()));
}
if (tb::TBSelectList *select = getWidgetByType<tb::TBSelectList>(PALETTELIST)) {
select->setSource(&_paletteList);
const int n = _paletteList.getNumItems();
for (int i = 0; i < n; ++i) {
if (!strcmp(_paletteList.getItemString(i), _currentSelectedPalette.c_str())) {
select->setValue(i);
break;
}
}
}
}
PaletteSelector::~PaletteSelector() {
if (tb::TBSelectList *select = getWidgetByType<tb::TBSelectList>(PALETTELIST)) {
select->setSource(nullptr);
}
}
bool PaletteSelector::onEvent(const tb::TBWidgetEvent &ev) {
if (ev.type == tb::EVENT_TYPE_CLICK) {
if (ev.target->getID() == TBIDC("ok")) {
sceneMgr().loadPalette(_currentSelectedPalette);
close();
return true;
} else if (ev.target->getID() == TBIDC("cancel")) {
close();
return true;
}
} else if (ev.type == tb::EVENT_TYPE_KEY_DOWN) {
if (ev.special_key == tb::TB_KEY_ESC) {
close();
return true;
}
} else if (ev.type == tb::EVENT_TYPE_CHANGED) {
if (ev.target->getID() == TBIDC(PALETTELIST)) {
const tb::TBSelectList *select = (const tb::TBSelectList *)ev.target;
const int n = select->getValue();
const char *name = _paletteList.getItemString(n);
_currentSelectedPalette = name;
Log::info("%i: %s", n, name);
return true;
}
}
return Super::onEvent(ev);
}
}

View File

@ -0,0 +1,23 @@
/**
* @file
*/
#pragma once
#include "ui/turbobadger/Window.h"
namespace voxedit {
class PaletteSelector: public ui::turbobadger::Window {
private:
using Super = ui::turbobadger::Window;
tb::TBGenericStringItemSource _paletteList;
std::string _currentSelectedPalette;
public:
PaletteSelector(ui::turbobadger::Window* window);
~PaletteSelector();
bool onEvent(const tb::TBWidgetEvent &ev) override;
};
}

View File

@ -140,6 +140,13 @@ bool SceneManager::voxelizeModel(const video::MeshPtr& meshPtr) {
return true;
}
bool SceneManager::loadPalette(const std::string& paletteName) {
const io::FilesystemPtr& filesystem = core::App::getInstance()->filesystem();
const io::FilePtr& paletteFile = filesystem->open(core::string::format("palette-%s.png", paletteName.c_str()));
const io::FilePtr& luaFile = filesystem->open(core::string::format("palette-%s.lua", paletteName.c_str()));
return voxel::overrideMaterialColors(paletteFile, luaFile);
}
bool SceneManager::importPalette(const std::string& file) {
const image::ImagePtr& img = image::loadImage(file, false);
if (!img->isLoaded()) {
@ -725,23 +732,12 @@ void SceneManager::construct() {
moveCursor(x, y, z);
}).setHelp("Move the cursor by the specified offsets");
core::Command::registerCommand("createpalette", [this] (const core::CmdArgs& args) {
if (args.size() != 1) {
Log::info("Expected to get an image file name as parameter");
return;
}
importPalette(args[0]);
}).setArgumentCompleter(core::fileCompleter("", "*.png")).setHelp("Import a palette from the given image");
core::Command::registerCommand("loadpalette", [] (const core::CmdArgs& args) {
core::Command::registerCommand("loadpalette", [this] (const core::CmdArgs& args) {
if (args.size() != 1) {
Log::info("Expected to get the palette NAME as part of palette-NAME.[png|lua]");
return;
}
const io::FilesystemPtr& filesystem = core::App::getInstance()->filesystem();
const io::FilePtr& paletteFile = filesystem->open(core::string::format("palette-%s.png", args[0].c_str()));
const io::FilePtr& luaFile = filesystem->open(core::string::format("palette-%s.lua", args[0].c_str()));
voxel::overrideMaterialColors(paletteFile, luaFile);
loadPalette(args[0]);
}).setHelp("Load an existing palette by name. E.g. 'nippon'");
core::Command::registerCommand("cursor", [this] (const core::CmdArgs& args) {

View File

@ -190,6 +190,7 @@ public:
bool importHeightmap(const std::string& file);
bool importAsPlane(const std::string& file);
bool importPalette(const std::string& file);
bool loadPalette(const std::string& paletteName);
bool exportModel(const std::string& file);
bool save(const std::string& file, bool autosave = false);
bool load(const std::string& file);