VOXEDIT: added palette import and load to ui
parent
7d61cbedc4
commit
14a4850a8f
|
@ -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 |
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue