#include #include #include #ifdef USE_CMAKE_CONFIG_H #include "cmake_config.h" #else #define D_ABOUT_LINK_URL "https://github.com/stujones11/SAM-Viewer" #define D_ABOUT_LINK_TEXT "github.com/stujones11/SAM-Viewer" #define D_VERSION "0.0.0" #endif #include "config.h" #include "scene.h" #include "dialog.h" static inline void open_url(std::string url) { system((std::string("xdg-open \"") + url + std::string("\"")).c_str()); } HyperlinkCtrl::HyperlinkCtrl(IGUIEnvironment *env, IGUIElement *parent, s32 id, const rect &rectangle, const wchar_t *title, std::string url) : IGUIElement(EGUIET_ELEMENT, env, parent, id, rectangle), url(url), is_active(false) { IGUIStaticText *text = env->addStaticText(title, rect(0,0,rectangle.getWidth(),20), false, false, this); text->setOverrideColor(SColor(255,0,0,255)); text->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER); } void HyperlinkCtrl::draw() { if (is_active) { IVideoDriver *driver = Environment->getVideoDriver(); rect pos = getAbsolutePosition(); vector2di end = pos.LowerRightCorner; vector2di start = end - vector2di(pos.getWidth(), 0); driver->draw2DLine(start, end, SColor(255,0,0,255)); } IGUIElement::draw(); } bool HyperlinkCtrl::OnEvent(const SEvent &event) { if (event.EventType == EET_GUI_EVENT) { if (event.GUIEvent.EventType == EGET_ELEMENT_HOVERED) is_active = true; else if (event.GUIEvent.EventType == EGET_ELEMENT_LEFT) is_active = false; } else if (is_active && event.EventType == EET_MOUSE_INPUT_EVENT && event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) { open_url(url); } return IGUIElement::OnEvent(event); } static inline bool isValidHexString(std::string hex) { return (hex.length() == 6 && hex.find_first_not_of("0123456789abcdefABCDEF") == std::string::npos); } ColorCtrl::ColorCtrl(IGUIEnvironment *env, IGUIElement *parent, s32 id, const rect &rectangle, const wchar_t *label) : IGUIElement(EGUIET_ELEMENT, env, parent, id, rectangle) { IVideoDriver *driver = env->getVideoDriver(); IGUIStaticText *text = env->addStaticText(label, rect(0,0,160,20), false, false, this); IGUIEditBox *edit = env->addEditBox(L"", rect(180,0,250,20), true, this, E_DIALOG_ID_COLOR_EDIT); edit->setMax(6); edit->setToolTipText(L"Hex color string RRGGBB"); ITexture *texture = driver->findTexture("color_preview"); if (!texture) { IImage *image = driver->createImage(ECF_A8R8G8B8, dimension2du(30,20)); image->fill(SColor(255,255,255,255)); texture = driver->addTexture("color_preview", image); image->drop(); } IGUIImage *preview = env->addImage(rect(270,0,300,20), this, E_DIALOG_ID_COLOR_PREVIEW); preview->setImage(texture); } void ColorCtrl::setColor(const std::string &hex) { if (!isValidHexString(hex)) return; stringw text = hex.c_str(); IGUIEditBox *edit = (IGUIEditBox*) getElementFromId(E_DIALOG_ID_COLOR_EDIT); if (edit) edit->setText(text.c_str()); IGUIImage *preview = (IGUIImage*) getElementFromId(E_DIALOG_ID_COLOR_PREVIEW); if (preview) { SColor color; color.color = std::stoul(hex, nullptr, 16); color.setAlpha(255); preview->setColor(color); } } std::string ColorCtrl::getColor() const { std::string hex = ""; IGUIEditBox *edit = (IGUIEditBox*) getElementFromId(E_DIALOG_ID_COLOR_EDIT); if (edit) hex = stringc(edit->getText()).c_str(); return hex; } bool ColorCtrl::OnEvent(const SEvent &event) { if (event.EventType == EET_GUI_EVENT && event.GUIEvent.EventType == EGET_EDITBOX_CHANGED && event.GUIEvent.Caller->getID() == E_DIALOG_ID_COLOR_EDIT) { IGUIEditBox *edit = (IGUIEditBox*)event.GUIEvent.Caller; std::string hex = stringc(edit->getText()).c_str(); setColor(hex); } return IGUIElement::OnEvent(event); } AboutDialog::AboutDialog(IGUIEnvironment *env, IGUIElement *parent, s32 id, const rect &rectangle) : IGUIElement(EGUIET_ELEMENT, env, parent, id, rectangle) { IVideoDriver *driver = env->getVideoDriver(); ITexture *icon = driver->findTexture("sam_icon_128.png"); if (!icon) icon = driver->getTexture("sam_icon_128.png"); if (icon) { IGUIImage *image = env->addImage(rect(86,10,214,138), this); image->setImage(icon); } ITexture *title = driver->findTexture("title.png"); if (!title) title = driver->getTexture("title.png"); if (title) { IGUIImage *image = env->addImage(rect(50,140,250,170), this); image->setImage(title); } stringw desc = stringw("Skin & Model Viewer - Version ") + D_VERSION; IGUIStaticText *text; text = env->addStaticText(desc.c_str(), rect(20,175,280,195), false, false, this); text->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER); HyperlinkCtrl *link = new HyperlinkCtrl(env, this, E_DIALOG_ID_ABOUT_LINK, rect(32,200,268,216), stringw(D_ABOUT_LINK_TEXT).c_str(), D_ABOUT_LINK_URL); link->drop(); IGUIButton *button = env->addButton(rect(110,235,190,265), this, E_DIALOG_ID_ABOUT_OK, L"OK"); } SettingsDialog::SettingsDialog(IGUIEnvironment *env, IGUIElement *parent, s32 id, const rect &rectangle, Config *conf) : IGUIElement(EGUIET_ELEMENT, env, parent, id, rectangle), conf(conf) { IGUITabControl *tabs = env->addTabControl(rect(2,2,398,250), this, true, true); IGUITab *tab_general = tabs->addTab(L"General"); IGUITab *tab_debug = tabs->addTab(L"Debug"); IGUIStaticText *text; IGUIEditBox *edit; IGUISpinBox *spin; IGUICheckBox *check; IGUIButton *button; ColorCtrl *color; color = new ColorCtrl(env, tab_general, E_DIALOG_ID_BG_COLOR, rect(20,20,320,40), L"Background Color:"); color->setColor(conf->get("bg_color")); color->drop(); color = new ColorCtrl(env, tab_general, E_DIALOG_ID_GRID_COLOR, rect(20,50,320,70), L"Grid Color:"); color->setColor(conf->get("grid_color")); color->drop(); text = env->addStaticText(L"Wield Attachment Bone:", rect(20,80,180,100), false, false, tab_general, -1); stringw bone_name = conf->getCStr("wield_bone"); edit = env->addEditBox(bone_name.c_str(), rect(200,80,320,100), true, tab_general, E_DIALOG_ID_WIELD_BONE); text = env->addStaticText(L"Default Screen Width:", rect(20,110,180,130), false, false, tab_general, -1); spin = env->addSpinBox(L"", rect(200,110,270,130), true, tab_general, E_DIALOG_ID_SCREEN_WIDTH); spin->setValue(conf->getInt("screen_width")); spin->setDecimalPlaces(0); text = env->addStaticText(L"Default Screen Height:", rect(20,140,180,160), false, false, tab_general, -1); spin = env->addSpinBox(L"", rect(200,140,270,160), true, tab_general, E_DIALOG_ID_SCREEN_HEIGHT); spin->setValue(conf->getInt("screen_height")); spin->setDecimalPlaces(0); check = env->addCheckBox(false, rect(20,20,380,40), tab_debug, E_DIALOG_ID_DEBUG_BBOX, L"Show bounding boxes"); check->setChecked(conf->getInt("debug_flags") & EDS_BBOX); check = env->addCheckBox(false, rect(20,50,380,70), tab_debug, E_DIALOG_ID_DEBUG_NORMALS, L"Show vertex normals"); check->setChecked(conf->getInt("debug_flags") & EDS_NORMALS); check = env->addCheckBox(false, rect(20,80,380,100), tab_debug, E_DIALOG_ID_DEBUG_SKELETON, L"Show skeleton"); check->setChecked(conf->getInt("debug_flags") & EDS_SKELETON); check = env->addCheckBox(false, rect(20,110,380,130), tab_debug, E_DIALOG_ID_DEBUG_WIREFRANE, L"Wireframe overaly"); check->setChecked(conf->getInt("debug_flags") & EDS_MESH_WIRE_OVERLAY); check = env->addCheckBox(false, rect(20,140,380,160), tab_debug, E_DIALOG_ID_DEBUG_ALPHA, L"Use transparent material"); check->setChecked(conf->getInt("debug_flags") & EDS_HALF_TRANSPARENCY); check = env->addCheckBox(false, rect(20,170,380,190), tab_debug, E_DIALOG_ID_DEBUG_BUFFERS, L"Show all mesh buffers"); check->setChecked(conf->getInt("debug_flags") & EDS_BBOX_BUFFERS); button = env->addButton(rect(315,255,395,285), this, E_DIALOG_ID_SETTINGS_OK, L"OK"); button = env->addButton(rect(230,255,310,285), this, E_DIALOG_ID_SETTINGS_CANCEL, L"Cancel"); } bool SettingsDialog::isBoxChecked(s32 id) const { IGUICheckBox *check = (IGUICheckBox*)getElementFromId(id, true); if (check) return check->isChecked(); return false; } bool SettingsDialog::OnEvent(const SEvent &event) { if (event.EventType == EET_GUI_EVENT && event.GUIEvent.EventType == EGET_BUTTON_CLICKED && event.GUIEvent.Caller->getID() == E_DIALOG_ID_SETTINGS_OK) { IGUIEditBox *edit; IGUISpinBox *spin; ColorCtrl *color; color = (ColorCtrl*)getElementFromId(E_DIALOG_ID_BG_COLOR, true); if (color) { const std::string hex = color->getColor(); if (isValidHexString(hex)) conf->set("bg_color", hex); } color = (ColorCtrl*)getElementFromId(E_DIALOG_ID_GRID_COLOR, true); if (color) { const std::string hex = color->getColor(); if (isValidHexString(hex)) conf->set("grid_color", hex); } edit = (IGUIEditBox*) getElementFromId(E_DIALOG_ID_WIELD_BONE, true); std::string bone = stringc(edit->getText()).c_str(); conf->set("wield_bone", bone); spin = (IGUISpinBox*) getElementFromId(E_DIALOG_ID_SCREEN_WIDTH, true); u32 width = spin->getValue(); conf->set("screen_width", std::to_string(width)); spin = (IGUISpinBox*) getElementFromId(E_DIALOG_ID_SCREEN_HEIGHT, true); u32 height = spin->getValue(); conf->set("screen_height", std::to_string(height)); u32 flags = 0; if (isBoxChecked(E_DIALOG_ID_DEBUG_BBOX)) flags |= EDS_BBOX; if (isBoxChecked(E_DIALOG_ID_DEBUG_NORMALS)) flags |= EDS_NORMALS; if (isBoxChecked(E_DIALOG_ID_DEBUG_SKELETON)) flags |= EDS_SKELETON; if (isBoxChecked(E_DIALOG_ID_DEBUG_WIREFRANE)) flags |= EDS_MESH_WIRE_OVERLAY; if (isBoxChecked(E_DIALOG_ID_DEBUG_ALPHA)) flags |= EDS_HALF_TRANSPARENCY; if (isBoxChecked(E_DIALOG_ID_DEBUG_BUFFERS)) flags |= EDS_BBOX_BUFFERS; conf->set("debug_flags", std::to_string(flags)); } return IGUIElement::OnEvent(event); } TexturesDialog::TexturesDialog(IGUIEnvironment *env, IGUIElement *parent, s32 id, const rect &rectangle, Config *conf, ISceneManager *smgr) : IGUIElement(EGUIET_ELEMENT, env, parent, id, rectangle), conf(conf), smgr(smgr) { IGUITabControl *tabs = env->addTabControl(rect(2,2,398,250), this, true, true); IGUITab *tab_model = tabs->addTab(L"Model"); IGUITab *tab_wield = tabs->addTab(L"Wield"); IGUIStaticText *text; IGUIEditBox *edit; IGUIButton *button; stringw fn; std::string key; ITexture *image = getTexture("browse.png"); ISceneNode *model = smgr->getSceneNodeFromId(E_SCENE_ID_MODEL); ISceneNode *wield = smgr->getSceneNodeFromId(E_SCENE_ID_WIELD); u32 mc_model = (model) ? model->getMaterialCount() : 0; u32 mc_wield = (wield) ? wield->getMaterialCount() : 0; for (s32 i = 0; i < 6; ++i) { s32 top = i * 30 + 20; stringw num = stringw(i + 1); key = "model_texture_" + std::to_string(i + 1); fn = conf->getCStr(key); text = env->addStaticText(num.c_str(), rect(15,top,25,top+20), false, false, tab_model, -1); edit = env->addEditBox(fn.c_str(), rect(35,top,350,top+20), true, tab_model, E_TEXTURE_ID_MODEL + i); edit->setEnabled(i < mc_model); edit->setOverrideColor(SColor(255,255,0,0)); edit->enableOverrideColor(false); button = env->addButton(rect(360,top,380,top+20), tab_model, E_BUTTON_ID_MODEL + i); button->setToolTipText(L"Browse"); if (image) { button->setImage(image); button->setUseAlphaChannel(true); button->setDrawBorder(false); } button->setEnabled(i < mc_model); key = "wield_texture_" + std::to_string(i + 1); fn = conf->getCStr(key); text = env->addStaticText(num.c_str(), rect(15,top,25,top+20), false, false, tab_wield, -1); edit = env->addEditBox(fn.c_str(), rect(35,top,350,top+20), true, tab_wield, E_TEXTURE_ID_WIELD + i); edit->setEnabled(i < mc_wield); edit->setOverrideColor(SColor(255,255,0,0)); edit->enableOverrideColor(false); button = env->addButton(rect(360,top,380,top+20), tab_wield, E_BUTTON_ID_WIELD + i); if (image) { button->setImage(image); button->setUseAlphaChannel(true); button->setDrawBorder(false); } button->setEnabled(i < mc_wield); } button = env->addButton(rect(315,255,395,285), this, E_DIALOG_ID_TEXTURES_OK, L"OK"); button = env->addButton(rect(230,255,310,285), this, E_DIALOG_ID_TEXTURES_CANCEL, L"Cancel"); } ITexture *TexturesDialog::getTexture(const io::path &filename) { IVideoDriver *driver = Environment->getVideoDriver(); ITexture *texture = driver->findTexture(filename); if (!texture) texture = driver->getTexture(filename); return texture; } bool TexturesDialog::OnEvent(const SEvent &event) { if (event.EventType == EET_GUI_EVENT) { s32 id = event.GUIEvent.Caller->getID(); if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) { if (event.GUIEvent.Caller->getType() == EGUIET_EDIT_BOX) { IGUIEditBox *edit = (IGUIEditBox*)event.GUIEvent.Caller; if (edit) { stringc fn = stringc(edit->getText()).c_str(); edit->enableOverrideColor(!(getTexture(fn))); } } } else if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED) { if (id == E_DIALOG_ID_TEXTURES_OK) { ISceneNode *model = smgr->getSceneNodeFromId(E_SCENE_ID_MODEL); ISceneNode *wield = smgr->getSceneNodeFromId(E_SCENE_ID_WIELD); IGUIEditBox *edit; for (s32 i = 0; i < 6; ++i) { std::string idx = std::to_string(i + 1); edit = (IGUIEditBox*) getElementFromId(E_TEXTURE_ID_MODEL + i, true); if (edit && model && i < model->getMaterialCount()) { stringc fn = stringc(edit->getText()).c_str(); ITexture *texture = getTexture(fn); if (texture) { std::string key = "model_texture_" + idx; conf->set(key, fn.c_str()); SMaterial &material = model->getMaterial(i); material.TextureLayer[0].Texture = texture; } } edit = (IGUIEditBox*) getElementFromId(E_TEXTURE_ID_WIELD + i, true); if (edit && wield && i < wield->getMaterialCount()) { stringc fn = stringc(edit->getText()).c_str(); ITexture *texture = getTexture(fn); if (texture) { std::string key = "wield_texture_" + idx; conf->set(key, fn.c_str()); SMaterial &material = wield->getMaterial(i); material.TextureLayer[0].Texture = texture; } } } } else { for (s32 i = 0; i < 6; ++i) { if (id == E_BUTTON_ID_MODEL + i) { Environment->addFileOpenDialog(L"Open Image File", true, this, E_TEXTURE_ID_MODEL + i); break; } else if (id == E_BUTTON_ID_WIELD + i) { Environment->addFileOpenDialog(L"Open Image File", true, this, E_TEXTURE_ID_WIELD + i); break; } } } } else if (event.GUIEvent.EventType == EGET_FILE_SELECTED) { IGUIFileOpenDialog *dialog = (IGUIFileOpenDialog*)event.GUIEvent.Caller; stringw fn = stringw(dialog->getFileName()); if (!fn.empty()) { s32 id = dialog->getID(); IGUIEditBox *edit = (IGUIEditBox*)getElementFromId(id, true); if (edit) { edit->setText(fn.c_str()); edit->enableOverrideColor(!(getTexture(fn))); } } } } return IGUIElement::OnEvent(event); }