mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-25 06:35:30 +00:00
Merge remote-tracking branch 'zini/master' into animations
Conflicts: apps/openmw/mwmechanics/character.cpp
This commit is contained in:
commit
90e29c83c0
@ -25,13 +25,14 @@ add_openmw_dir (mwinput
|
||||
|
||||
add_openmw_dir (mwgui
|
||||
textinput widgets race class birth review windowmanagerimp console dialogue
|
||||
dialoguehistory windowbase statswindow messagebox journalwindow charactercreation
|
||||
windowbase statswindow messagebox journalwindow charactercreation
|
||||
mapwindow windowpinnablebase tooltips scrollwindow bookwindow list
|
||||
formatting inventorywindow container hud countdialog tradewindow settingswindow
|
||||
confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu
|
||||
itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog
|
||||
enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons
|
||||
merchantrepair repair soulgemdialog companionwindow
|
||||
merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks
|
||||
keywordsearch
|
||||
)
|
||||
|
||||
add_openmw_dir (mwdialogue
|
||||
|
@ -41,7 +41,7 @@ namespace MWBase
|
||||
//calbacks for the GUI
|
||||
virtual void keywordSelected (const std::string& keyword) = 0;
|
||||
virtual void goodbyeSelected() = 0;
|
||||
virtual void questionAnswered (const std::string& answer) = 0;
|
||||
virtual void questionAnswered (int answer) = 0;
|
||||
|
||||
virtual bool checkServiceRefused () = 0;
|
||||
|
||||
|
@ -201,6 +201,8 @@ namespace MWBase
|
||||
///< Hides dialog and schedules dialog to be deleted.
|
||||
|
||||
virtual void messageBox (const std::string& message, const std::vector<std::string>& buttons = std::vector<std::string>()) = 0;
|
||||
virtual void staticMessageBox(const std::string& message) = 0;
|
||||
virtual void removeStaticMessageBox() = 0;
|
||||
|
||||
virtual void enterPressed () = 0;
|
||||
virtual int readPressedButton() = 0;
|
||||
|
@ -161,7 +161,7 @@ namespace MWDialogue
|
||||
parseText (info->mResponse);
|
||||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
||||
win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
||||
executeScript (info->mResultScript);
|
||||
mLastTopic = Misc::StringUtils::lowerCase(it->mId);
|
||||
mLastDialogue = *info;
|
||||
@ -263,6 +263,7 @@ namespace MWDialogue
|
||||
|
||||
parseText (info->mResponse);
|
||||
|
||||
std::string title;
|
||||
if (dialogue.mType==ESM::Dialogue::Persuasion)
|
||||
{
|
||||
std::string modifiedTopic = "s" + topic;
|
||||
@ -272,13 +273,13 @@ namespace MWDialogue
|
||||
const MWWorld::Store<ESM::GameSetting>& gmsts =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
win->addTitle (gmsts.find (modifiedTopic)->getString());
|
||||
title = gmsts.find (modifiedTopic)->getString();
|
||||
}
|
||||
else
|
||||
win->addTitle (topic);
|
||||
title = topic;
|
||||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
||||
win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), title);
|
||||
MWBase::Environment::get().getJournal()->addTopic (topic, info->mId);
|
||||
|
||||
executeScript (info->mResultScript);
|
||||
@ -289,9 +290,7 @@ namespace MWDialogue
|
||||
else
|
||||
{
|
||||
// no response found, print a fallback text
|
||||
win->addTitle (topic);
|
||||
win->addText ("…");
|
||||
|
||||
win->addResponse ("…", topic);
|
||||
}
|
||||
}
|
||||
|
||||
@ -424,53 +423,42 @@ namespace MWDialogue
|
||||
mTemporaryDispositionChange = 0;
|
||||
}
|
||||
|
||||
void DialogueManager::questionAnswered (const std::string& answer)
|
||||
void DialogueManager::questionAnswered (int answer)
|
||||
{
|
||||
mChoice = answer;
|
||||
|
||||
if (mChoiceMap.find(answer) != mChoiceMap.end())
|
||||
if (mDialogueMap.find(mLastTopic) != mDialogueMap.end())
|
||||
{
|
||||
mChoice = mChoiceMap[answer];
|
||||
Filter filter (mActor, mChoice, mTalkedTo);
|
||||
|
||||
if (mDialogueMap.find(mLastTopic) != mDialogueMap.end())
|
||||
if (mDialogueMap[mLastTopic].mType == ESM::Dialogue::Topic
|
||||
|| mDialogueMap[mLastTopic].mType == ESM::Dialogue::Greeting)
|
||||
{
|
||||
Filter filter (mActor, mChoice, mTalkedTo);
|
||||
|
||||
if (mDialogueMap[mLastTopic].mType == ESM::Dialogue::Topic
|
||||
|| mDialogueMap[mLastTopic].mType == ESM::Dialogue::Greeting)
|
||||
if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic], true))
|
||||
{
|
||||
if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic], true))
|
||||
{
|
||||
std::string text = info->mResponse;
|
||||
parseText (text);
|
||||
std::string text = info->mResponse;
|
||||
parseText (text);
|
||||
|
||||
mChoiceMap.clear();
|
||||
mChoice = -1;
|
||||
mIsInChoice = false;
|
||||
mChoice = -1;
|
||||
mIsInChoice = false;
|
||||
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->clearChoices();
|
||||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext));
|
||||
MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId);
|
||||
executeScript (info->mResultScript);
|
||||
mLastDialogue = *info;
|
||||
}
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse (Interpreter::fixDefinesDialog(text, interpreterContext));
|
||||
MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId);
|
||||
executeScript (info->mResultScript);
|
||||
mLastDialogue = *info;
|
||||
}
|
||||
}
|
||||
|
||||
updateTopics();
|
||||
}
|
||||
}
|
||||
|
||||
void DialogueManager::printError (const std::string& error)
|
||||
{
|
||||
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
|
||||
win->addText(error);
|
||||
updateTopics();
|
||||
}
|
||||
|
||||
void DialogueManager::askQuestion (const std::string& question, int choice)
|
||||
{
|
||||
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
|
||||
win->askQuestion(question);
|
||||
mChoiceMap[Misc::StringUtils::lowerCase(question)] = choice;
|
||||
win->addChoice(question, choice);
|
||||
mIsInChoice = true;
|
||||
}
|
||||
|
||||
@ -551,10 +539,10 @@ namespace MWDialogue
|
||||
const MWWorld::Store<ESM::GameSetting>& gmsts =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
win->addTitle (gmsts.find ("sServiceRefusal")->getString());
|
||||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
||||
|
||||
win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext),
|
||||
gmsts.find ("sServiceRefusal")->getString());
|
||||
|
||||
executeScript (info->mResultScript);
|
||||
return true;
|
||||
@ -565,9 +553,7 @@ namespace MWDialogue
|
||||
std::vector<HyperTextToken> ParseHyperText(const std::string& text)
|
||||
{
|
||||
std::vector<HyperTextToken> result;
|
||||
|
||||
MyGUI::UString utext(text);
|
||||
|
||||
size_t pos_begin, pos_end, iteration_pos = 0;
|
||||
for(;;)
|
||||
{
|
||||
|
@ -30,7 +30,6 @@ namespace MWDialogue
|
||||
bool mTalkedTo;
|
||||
|
||||
int mChoice;
|
||||
std::map<std::string, int> mChoiceMap;
|
||||
std::string mLastTopic;
|
||||
ESM::DialInfo mLastDialogue;
|
||||
bool mIsInChoice;
|
||||
@ -46,8 +45,6 @@ namespace MWDialogue
|
||||
bool compile (const std::string& cmd,std::vector<Interpreter::Type_Code>& code);
|
||||
void executeScript (const std::string& script);
|
||||
|
||||
void printError (const std::string& error);
|
||||
|
||||
void executeTopic (const std::string& topic, bool randomResponse=false);
|
||||
|
||||
public:
|
||||
@ -72,7 +69,7 @@ namespace MWDialogue
|
||||
//calbacks for the GUI
|
||||
virtual void keywordSelected (const std::string& keyword);
|
||||
virtual void goodbyeSelected();
|
||||
virtual void questionAnswered (const std::string& answer);
|
||||
virtual void questionAnswered (int answer);
|
||||
|
||||
virtual void persuade (int type);
|
||||
virtual int getTemporaryDispositionChange () const;
|
||||
|
1227
apps/openmw/mwgui/bookpage.cpp
Normal file
1227
apps/openmw/mwgui/bookpage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
122
apps/openmw/mwgui/bookpage.hpp
Normal file
122
apps/openmw/mwgui/bookpage.hpp
Normal file
@ -0,0 +1,122 @@
|
||||
#ifndef MWGUI_BOOKPAGE_HPP
|
||||
#define MWGUI_BOOKPAGE_HPP
|
||||
|
||||
#include "MyGUI_Colour.h"
|
||||
#include "MyGUI_Widget.h"
|
||||
|
||||
#include <functional>
|
||||
#include <platform/stdint.h>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
/// A formatted and paginated document to be used with
|
||||
/// the book page widget.
|
||||
struct TypesetBook
|
||||
{
|
||||
typedef boost::shared_ptr <TypesetBook> Ptr;
|
||||
typedef intptr_t InteractiveId;
|
||||
|
||||
/// Returns the number of pages in the document.
|
||||
virtual size_t pageCount () const = 0;
|
||||
|
||||
/// Return the area covered by the document. The first
|
||||
/// integer is the maximum with of any line. This is not
|
||||
/// the largest coordinate of the right edge of any line,
|
||||
/// it is the largest distance from the left edge to the
|
||||
/// right edge. The second integer is the height of all
|
||||
/// text combined prior to pagination.
|
||||
virtual std::pair <unsigned int, unsigned int> getSize () const = 0;
|
||||
};
|
||||
|
||||
/// A factory class for creating a typeset book instance.
|
||||
struct BookTypesetter
|
||||
{
|
||||
typedef boost::shared_ptr <BookTypesetter> Ptr;
|
||||
typedef TypesetBook::InteractiveId InteractiveId;
|
||||
typedef MyGUI::Colour Colour;
|
||||
typedef uint8_t const * Utf8Point;
|
||||
typedef std::pair <Utf8Point, Utf8Point> Utf8Span;
|
||||
|
||||
enum Alignment {
|
||||
AlignLeft = -1,
|
||||
AlignCenter = 0,
|
||||
AlignRight = +1
|
||||
};
|
||||
|
||||
/// Styles are used to control the character level formatting
|
||||
/// of text added to a typeset book. Their lifetime is equal
|
||||
/// to the lifetime of the book-typesetter instance that created
|
||||
/// them.
|
||||
struct Style;
|
||||
|
||||
/// A factory function for creating the default implementation of a book typesetter
|
||||
static Ptr create (int pageWidth, int pageHeight);
|
||||
|
||||
/// Create a simple text style consisting of a font and a text color.
|
||||
virtual Style* createStyle (char const * Font, Colour Colour) = 0;
|
||||
|
||||
/// Create a hyper-link style with a user-defined identifier based on an
|
||||
/// existing style. The unique flag forces a new instance of this style
|
||||
/// to be created even if an existing instance is present.
|
||||
virtual Style* createHotStyle (Style * BaseStyle, Colour NormalColour, Colour HoverColour, Colour ActiveColour, InteractiveId Id, bool Unique = true) = 0;
|
||||
|
||||
/// Insert a line break into the document. Newline characters in the input
|
||||
/// text have the same affect. The margin parameter adds additional space
|
||||
/// before the next line of text.
|
||||
virtual void lineBreak (float margin = 0) = 0;
|
||||
|
||||
/// Insert a section break into the document. This causes a new section
|
||||
/// to begin when additional text is inserted. Pagination attempts to keep
|
||||
/// sections together on a single page. The margin parameter adds additional space
|
||||
/// before the next line of text.
|
||||
virtual void sectionBreak (float margin = 0) = 0;
|
||||
|
||||
/// Changes the alignment for the current section of text.
|
||||
virtual void setSectionAlignment (Alignment sectionAlignment) = 0;
|
||||
|
||||
// Layout a block of text with the specified style into the document.
|
||||
virtual void write (Style * Style, Utf8Span Text) = 0;
|
||||
|
||||
/// Adds a content block to the document without laying it out. An
|
||||
/// identifier is returned that can be used to refer to it. If select
|
||||
/// is true, the block is activated to be references by future writes.
|
||||
virtual intptr_t addContent (Utf8Span Text, bool Select = true) = 0;
|
||||
|
||||
/// Select a previously created content block for future writes.
|
||||
virtual void selectContent (intptr_t contentHandle) = 0;
|
||||
|
||||
/// Layout a span of the selected content block into the document
|
||||
/// using the specified style.
|
||||
virtual void write (Style * Style, size_t Begin, size_t End) = 0;
|
||||
|
||||
/// Finalize the document layout, and return a pointer to it.
|
||||
virtual TypesetBook::Ptr complete () = 0;
|
||||
};
|
||||
|
||||
/// An interface to the BookPage widget.
|
||||
class BookPage : public MyGUI::Widget
|
||||
{
|
||||
MYGUI_RTTI_DERIVED(BookPage)
|
||||
public:
|
||||
|
||||
typedef TypesetBook::InteractiveId InteractiveId;
|
||||
typedef boost::function <void (InteractiveId)> ClickCallback;
|
||||
|
||||
/// Make the widget display the specified page from the specified book.
|
||||
virtual void showPage (TypesetBook::Ptr Book, size_t Page) = 0;
|
||||
|
||||
/// Set the callback for a clicking a hyper-link in the document.
|
||||
virtual void adviseLinkClicked (ClickCallback callback) = 0;
|
||||
|
||||
/// Clear the hyper-link click callback.
|
||||
virtual void unadviseLinkClicked () = 0;
|
||||
|
||||
/// Register the widget and associated sub-widget with MyGUI. Should be
|
||||
/// called once near the beginning of the program.
|
||||
static void registerMyGUIComponents ();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MWGUI_BOOKPAGE_HPP
|
@ -76,7 +76,7 @@ namespace MWGui
|
||||
parent = mRightPage;
|
||||
|
||||
MyGUI::Widget* pageWidget = parent->createWidgetReal<MyGUI::Widget>("", MyGUI::FloatCoord(0.0,0.0,1.0,1.0), MyGUI::Align::Default, "BookPage" + boost::lexical_cast<std::string>(i));
|
||||
parser.parse(*it, pageWidget, mLeftPage->getSize().width);
|
||||
parser.parsePage(*it, pageWidget, mLeftPage->getSize().width);
|
||||
mPages.push_back(pageWidget);
|
||||
++i;
|
||||
}
|
||||
@ -157,6 +157,21 @@ namespace MWGui
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
//If it is the last page, hide the button "Next Page"
|
||||
if ( (mCurrentPage+1)*2 == mPages.size()
|
||||
|| (mCurrentPage+1)*2 == mPages.size() + 1)
|
||||
{
|
||||
mNextPageButton->setVisible(false);
|
||||
} else {
|
||||
mNextPageButton->setVisible(true);
|
||||
}
|
||||
//If it is the fist page, hide the button "Prev Page"
|
||||
if (mCurrentPage == 0) {
|
||||
mPrevPageButton->setVisible(false);
|
||||
} else {
|
||||
mPrevPageButton->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,36 +11,24 @@
|
||||
|
||||
#include "../mwdialogue/dialoguemanagerimp.hpp"
|
||||
|
||||
#include "dialoguehistory.hpp"
|
||||
#include "widgets.hpp"
|
||||
#include "list.hpp"
|
||||
#include "tradewindow.hpp"
|
||||
#include "spellbuyingwindow.hpp"
|
||||
#include "inventorywindow.hpp"
|
||||
#include "travelwindow.hpp"
|
||||
#include "bookpage.hpp"
|
||||
|
||||
/**
|
||||
*Copied from the internet.
|
||||
*/
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::string lower_string(const std::string& str)
|
||||
MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text)
|
||||
{
|
||||
std::string lowerCase = Misc::StringUtils::lowerCase (str);
|
||||
typedef MWGui::BookTypesetter::Utf8Point point;
|
||||
|
||||
return lowerCase;
|
||||
}
|
||||
point begin = reinterpret_cast <point> (text);
|
||||
|
||||
std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos)
|
||||
{
|
||||
return lower_string(str).find(lower_string(substr),pos);
|
||||
}
|
||||
|
||||
bool sortByLength (const std::string& left, const std::string& right)
|
||||
{
|
||||
return left.size() > right.size();
|
||||
return MWGui::BookTypesetter::Utf8Span (begin, begin + strlen (text));
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,11 +104,144 @@ namespace MWGui
|
||||
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
|
||||
Response::Response(const std::string &text, const std::string &title)
|
||||
: mTitle(title)
|
||||
{
|
||||
mText = text;
|
||||
}
|
||||
|
||||
void Response::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map<std::string, Link*>& topicLinks) const
|
||||
{
|
||||
BookTypesetter::Style* title = typesetter->createStyle("EB Garamond", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f));
|
||||
typesetter->sectionBreak(9);
|
||||
if (mTitle != "")
|
||||
typesetter->write(title, to_utf8_span(mTitle.c_str()));
|
||||
typesetter->sectionBreak(9);
|
||||
|
||||
typedef std::pair<size_t, size_t> Range;
|
||||
std::map<Range, intptr_t> hyperLinks;
|
||||
|
||||
// We need this copy for when @# hyperlinks are replaced
|
||||
std::string text = mText;
|
||||
|
||||
size_t pos_begin, pos_end;
|
||||
for(;;)
|
||||
{
|
||||
pos_begin = text.find('@');
|
||||
if (pos_begin != std::string::npos)
|
||||
pos_end = text.find('#', pos_begin);
|
||||
|
||||
if (pos_begin != std::string::npos && pos_end != std::string::npos)
|
||||
{
|
||||
std::string link = text.substr(pos_begin + 1, pos_end - pos_begin - 1);
|
||||
const char specialPseudoAsteriskCharacter = 127;
|
||||
std::replace(link.begin(), link.end(), specialPseudoAsteriskCharacter, '*');
|
||||
std::string topicName = MWBase::Environment::get().getWindowManager()->
|
||||
getTranslationDataStorage().topicStandardForm(link);
|
||||
|
||||
std::string displayName = link;
|
||||
while (displayName[displayName.size()-1] == '*')
|
||||
displayName.erase(displayName.size()-1, 1);
|
||||
|
||||
text.replace(pos_begin, pos_end+1-pos_begin, displayName);
|
||||
|
||||
if (topicLinks.find(Misc::StringUtils::lowerCase(topicName)) != topicLinks.end())
|
||||
hyperLinks[std::make_pair(pos_begin, pos_begin+displayName.size())] = intptr_t(topicLinks[Misc::StringUtils::lowerCase(topicName)]);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
typesetter->addContent(to_utf8_span(text.c_str()));
|
||||
|
||||
if (hyperLinks.size() && MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation())
|
||||
{
|
||||
BookTypesetter::Style* style = typesetter->createStyle("EB Garamond", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f));
|
||||
size_t formatted = 0; // points to the first character that is not laid out yet
|
||||
for (std::map<Range, intptr_t>::iterator it = hyperLinks.begin(); it != hyperLinks.end(); ++it)
|
||||
{
|
||||
intptr_t topicId = it->second;
|
||||
const MyGUI::Colour linkHot (143/255.f, 155/255.f, 218/255.f);
|
||||
const MyGUI::Colour linkNormal (112/255.f, 126/255.f, 207/255.f);
|
||||
const MyGUI::Colour linkActive (175/255.f, 184/255.f, 228/255.f);
|
||||
BookTypesetter::Style* hotStyle = typesetter->createHotStyle (style, linkNormal, linkHot, linkActive, topicId);
|
||||
if (formatted < it->first.first)
|
||||
typesetter->write(style, formatted, it->first.first);
|
||||
typesetter->write(hotStyle, it->first.first, it->first.second);
|
||||
formatted = it->first.second;
|
||||
}
|
||||
if (formatted < text.size())
|
||||
typesetter->write(style, formatted, text.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string::const_iterator i = text.begin ();
|
||||
KeywordSearchT::Match match;
|
||||
while (i != text.end () && keywordSearch->search (i, text.end (), match))
|
||||
{
|
||||
if (i != match.mBeg)
|
||||
addTopicLink (typesetter, 0, i - text.begin (), match.mBeg - text.begin ());
|
||||
|
||||
addTopicLink (typesetter, match.mValue, match.mBeg - text.begin (), match.mEnd - text.begin ());
|
||||
|
||||
i = match.mEnd;
|
||||
}
|
||||
|
||||
if (i != text.end ())
|
||||
addTopicLink (typesetter, 0, i - text.begin (), text.size ());
|
||||
}
|
||||
}
|
||||
|
||||
void Response::addTopicLink(BookTypesetter::Ptr typesetter, intptr_t topicId, size_t begin, size_t end) const
|
||||
{
|
||||
BookTypesetter::Style* style = typesetter->createStyle("EB Garamond", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f));
|
||||
|
||||
const MyGUI::Colour linkHot (143/255.f, 155/255.f, 218/255.f);
|
||||
const MyGUI::Colour linkNormal (112/255.f, 126/255.f, 207/255.f);
|
||||
const MyGUI::Colour linkActive (175/255.f, 184/255.f, 228/255.f);
|
||||
|
||||
if (topicId)
|
||||
style = typesetter->createHotStyle (style, linkNormal, linkHot, linkActive, topicId);
|
||||
typesetter->write (style, begin, end);
|
||||
}
|
||||
|
||||
Message::Message(const std::string& text)
|
||||
{
|
||||
mText = text;
|
||||
}
|
||||
|
||||
void Message::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map<std::string, Link*>& topicLinks) const
|
||||
{
|
||||
BookTypesetter::Style* title = typesetter->createStyle("EB Garamond", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f));
|
||||
typesetter->sectionBreak(9);
|
||||
typesetter->write(title, to_utf8_span(mText.c_str()));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
|
||||
void Choice::activated()
|
||||
{
|
||||
MWBase::Environment::get().getDialogueManager()->questionAnswered(mChoiceId);
|
||||
}
|
||||
|
||||
void Topic::activated()
|
||||
{
|
||||
MWBase::Environment::get().getDialogueManager()->keywordSelected(Misc::StringUtils::lowerCase(mTopicId));
|
||||
}
|
||||
|
||||
void Goodbye::activated()
|
||||
{
|
||||
MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
|
||||
DialogueWindow::DialogueWindow()
|
||||
: WindowBase("openmw_dialogue_window.layout")
|
||||
, mPersuasionDialog()
|
||||
, mEnabled(false)
|
||||
, mServices(0)
|
||||
, mGoodbye(false)
|
||||
{
|
||||
// Centre dialog
|
||||
center();
|
||||
@ -129,15 +250,6 @@ namespace MWGui
|
||||
|
||||
//History view
|
||||
getWidget(mHistory, "History");
|
||||
mHistory->setOverflowToTheLeft(true);
|
||||
mHistory->setMaxTextLength(1000000);
|
||||
MyGUI::Widget* eventbox;
|
||||
|
||||
//An EditBox cannot receive mouse click events, so we use an
|
||||
//invisible widget on top of the editbox to receive them
|
||||
getWidget(eventbox, "EventBox");
|
||||
eventbox->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onHistoryClicked);
|
||||
eventbox->eventMouseWheel += MyGUI::newDelegate(this, &DialogueWindow::onMouseWheel);
|
||||
|
||||
//Topics list
|
||||
getWidget(mTopicsList, "TopicsList");
|
||||
@ -149,68 +261,30 @@ namespace MWGui
|
||||
|
||||
getWidget(mDispositionBar, "Disposition");
|
||||
getWidget(mDispositionText,"DispositionText");
|
||||
getWidget(mScrollBar, "VScroll");
|
||||
|
||||
mScrollBar->eventScrollChangePosition += MyGUI::newDelegate(this, &DialogueWindow::onScrollbarMoved);
|
||||
mHistory->eventMouseWheel += MyGUI::newDelegate(this, &DialogueWindow::onMouseWheel);
|
||||
|
||||
BookPage::ClickCallback callback = boost::bind (&DialogueWindow::notifyLinkClicked, this, _1);
|
||||
mHistory->adviseLinkClicked(callback);
|
||||
|
||||
static_cast<MyGUI::Window*>(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize);
|
||||
}
|
||||
|
||||
void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
MyGUI::ISubWidgetText* t = mHistory->getClient()->getSubWidgetText();
|
||||
if(t == NULL)
|
||||
return;
|
||||
|
||||
const MyGUI::IntPoint& lastPressed = MyGUI::InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left);
|
||||
|
||||
size_t cursorPosition = t->getCursorPosition(lastPressed);
|
||||
MyGUI::UString color = mHistory->getColorAtPos(cursorPosition);
|
||||
|
||||
if (!mEnabled && color == "#572D21")
|
||||
MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
|
||||
|
||||
if (!mEnabled)
|
||||
return;
|
||||
|
||||
if(color != "#B29154")
|
||||
{
|
||||
MyGUI::UString key = mHistory->getColorTextAt(cursorPosition);
|
||||
|
||||
if(color == "#686EBA")
|
||||
{
|
||||
std::map<size_t, HyperLink>::iterator i = mHyperLinks.upper_bound(cursorPosition);
|
||||
if( !mHyperLinks.empty() )
|
||||
{
|
||||
--i;
|
||||
|
||||
if( i->first + i->second.mLength > cursorPosition)
|
||||
{
|
||||
MWBase::Environment::get().getDialogueManager()->keywordSelected(i->second.mTrueValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// the link was colored, but it is not in mHyperLinks.
|
||||
// It means that those liunks are not marked with @# and found
|
||||
// by topic name search
|
||||
MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(key));
|
||||
}
|
||||
}
|
||||
|
||||
if(color == "#572D21")
|
||||
MWBase::Environment::get().getDialogueManager()->questionAnswered(lower_string(key));
|
||||
}
|
||||
}
|
||||
|
||||
void DialogueWindow::onWindowResize(MyGUI::Window* _sender)
|
||||
{
|
||||
mTopicsList->adjustSize();
|
||||
updateHistory();
|
||||
}
|
||||
|
||||
void DialogueWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel)
|
||||
{
|
||||
if (mHistory->getVScrollPosition() - _rel*0.3 < 0)
|
||||
mHistory->setVScrollPosition(0);
|
||||
else
|
||||
mHistory->setVScrollPosition(mHistory->getVScrollPosition() - _rel*0.3);
|
||||
if (!mScrollBar->getVisible())
|
||||
return;
|
||||
mScrollBar->setScrollPosition(std::min(static_cast<int>(mScrollBar->getScrollRange()-1),
|
||||
std::max(0, static_cast<int>(mScrollBar->getScrollPosition() - _rel*0.3))));
|
||||
onScrollbarMoved(mScrollBar, mScrollBar->getScrollPosition());
|
||||
}
|
||||
|
||||
void DialogueWindow::onByeClicked(MyGUI::Widget* _sender)
|
||||
@ -231,7 +305,7 @@ namespace MWGui
|
||||
}
|
||||
|
||||
if (id >= separatorPos)
|
||||
MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic));
|
||||
MWBase::Environment::get().getDialogueManager()->keywordSelected(Misc::StringUtils::lowerCase(topic));
|
||||
else
|
||||
{
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||
@ -289,20 +363,32 @@ namespace MWGui
|
||||
|
||||
void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName)
|
||||
{
|
||||
mGoodbye = false;
|
||||
mEnabled = true;
|
||||
mPtr = actor;
|
||||
mTopicsList->setEnabled(true);
|
||||
setTitle(npcName);
|
||||
|
||||
mTopicsList->clear();
|
||||
mHyperLinks.clear();
|
||||
mHistory->setCaption("");
|
||||
|
||||
for (std::vector<DialogueText*>::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it)
|
||||
delete (*it);
|
||||
mHistoryContents.clear();
|
||||
|
||||
for (std::vector<Link*>::iterator it = mLinks.begin(); it != mLinks.end(); ++it)
|
||||
delete (*it);
|
||||
mLinks.clear();
|
||||
|
||||
updateOptions();
|
||||
}
|
||||
|
||||
void DialogueWindow::setKeywords(std::list<std::string> keyWords)
|
||||
{
|
||||
mTopicsList->clear();
|
||||
for (std::map<std::string, Link*>::iterator it = mTopicLinks.begin(); it != mTopicLinks.end(); ++it)
|
||||
delete it->second;
|
||||
mTopicLinks.clear();
|
||||
mKeywordSearch.clear();
|
||||
|
||||
bool isCompanion = !MWWorld::Class::get(mPtr).getScript(mPtr).empty()
|
||||
&& mPtr.getRefData().getLocals().getIntVar(MWWorld::Class::get(mPtr).getScript(mPtr), "companion");
|
||||
@ -346,161 +432,138 @@ namespace MWGui
|
||||
for(std::list<std::string>::iterator it = keyWords.begin(); it != keyWords.end(); ++it)
|
||||
{
|
||||
mTopicsList->addItem(*it);
|
||||
|
||||
Topic* t = new Topic(*it);
|
||||
mTopicLinks[Misc::StringUtils::lowerCase(*it)] = t;
|
||||
|
||||
mKeywordSearch.seed(Misc::StringUtils::lowerCase(*it), intptr_t(t));
|
||||
}
|
||||
mTopicsList->adjustSize();
|
||||
|
||||
updateHistory();
|
||||
}
|
||||
|
||||
void DialogueWindow::removeKeyword(std::string keyWord)
|
||||
void DialogueWindow::updateHistory(bool scrollbar)
|
||||
{
|
||||
if(mTopicsList->hasItem(keyWord))
|
||||
if (!scrollbar && mScrollBar->getVisible())
|
||||
{
|
||||
mTopicsList->removeItem(keyWord);
|
||||
mHistory->setSize(mHistory->getSize()+MyGUI::IntSize(mScrollBar->getWidth(),0));
|
||||
mScrollBar->setVisible(false);
|
||||
}
|
||||
if (scrollbar && !mScrollBar->getVisible())
|
||||
{
|
||||
mHistory->setSize(mHistory->getSize()-MyGUI::IntSize(mScrollBar->getWidth(),0));
|
||||
mScrollBar->setVisible(true);
|
||||
}
|
||||
|
||||
BookTypesetter::Ptr typesetter = BookTypesetter::create (mHistory->getWidth(), std::numeric_limits<int>().max());
|
||||
|
||||
for (std::vector<DialogueText*>::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it)
|
||||
(*it)->write(typesetter, &mKeywordSearch, mTopicLinks);
|
||||
|
||||
|
||||
BookTypesetter::Style* body = typesetter->createStyle("EB Garamond", MyGUI::Colour::White);
|
||||
|
||||
// choices
|
||||
const MyGUI::Colour linkHot (223/255.f, 201/255.f, 159/255.f);
|
||||
const MyGUI::Colour linkNormal (150/255.f, 50/255.f, 30/255.f);
|
||||
const MyGUI::Colour linkActive (243/255.f, 237/255.f, 221/255.f);
|
||||
for (std::map<std::string, int>::iterator it = mChoices.begin(); it != mChoices.end(); ++it)
|
||||
{
|
||||
Choice* link = new Choice(it->second);
|
||||
mLinks.push_back(link);
|
||||
|
||||
typesetter->lineBreak();
|
||||
BookTypesetter::Style* questionStyle = typesetter->createHotStyle(body, linkNormal, linkHot, linkActive,
|
||||
TypesetBook::InteractiveId(link));
|
||||
typesetter->write(questionStyle, to_utf8_span(it->first.c_str()));
|
||||
}
|
||||
|
||||
if (mGoodbye)
|
||||
{
|
||||
std::string goodbye = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sGoodbye")->getString();
|
||||
BookTypesetter::Style* questionStyle = typesetter->createHotStyle(body, linkNormal, linkHot, linkActive,
|
||||
TypesetBook::InteractiveId(mLinks.back()));
|
||||
typesetter->lineBreak();
|
||||
typesetter->write(questionStyle, to_utf8_span(goodbye.c_str()));
|
||||
}
|
||||
|
||||
TypesetBook::Ptr book = typesetter->complete();
|
||||
mHistory->showPage(book, 0);
|
||||
size_t viewHeight = mHistory->getParent()->getHeight();
|
||||
if (!scrollbar && book->getSize().second > viewHeight)
|
||||
updateHistory(true);
|
||||
else if (scrollbar)
|
||||
{
|
||||
mHistory->setSize(MyGUI::IntSize(mHistory->getWidth(), book->getSize().second));
|
||||
size_t range = book->getSize().second - viewHeight;
|
||||
mScrollBar->setScrollRange(range);
|
||||
mScrollBar->setScrollPosition(range-1);
|
||||
mScrollBar->setTrackSize(viewHeight / static_cast<float>(book->getSize().second) * mScrollBar->getLineSize());
|
||||
onScrollbarMoved(mScrollBar, range-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no scrollbar
|
||||
onScrollbarMoved(mScrollBar, 0);
|
||||
}
|
||||
mTopicsList->adjustSize();
|
||||
}
|
||||
|
||||
void addColorInString(std::string& str, const std::string& keyword,std::string color1, std::string color2)
|
||||
void DialogueWindow::notifyLinkClicked (TypesetBook::InteractiveId link)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while((pos = find_str_ci(str,keyword, pos)) != std::string::npos)
|
||||
reinterpret_cast<Link*>(link)->activated();
|
||||
}
|
||||
|
||||
void DialogueWindow::onScrollbarMoved(MyGUI::ScrollBar *sender, size_t pos)
|
||||
{
|
||||
mHistory->setPosition(0,-pos);
|
||||
}
|
||||
|
||||
void DialogueWindow::addResponse(const std::string &text, const std::string &title)
|
||||
{
|
||||
// This is called from the dialogue manager, so text is
|
||||
// case-smashed - thus we have to retrieve the correct case
|
||||
// of the title through the topic list.
|
||||
std::string realTitle = title;
|
||||
if (realTitle != "")
|
||||
{
|
||||
// do not add color if this portion of text is already colored.
|
||||
for (size_t i=0; i<mTopicsList->getItemCount(); ++i)
|
||||
{
|
||||
MyGUI::TextIterator iterator (str);
|
||||
MyGUI::UString colour;
|
||||
while(iterator.moveNext())
|
||||
std::string item = mTopicsList->getItemNameAt(i);
|
||||
if (Misc::StringUtils::lowerCase(item) == title)
|
||||
{
|
||||
size_t iteratorPos = iterator.getPosition();
|
||||
iterator.getTagColour(colour);
|
||||
if (iteratorPos == pos)
|
||||
break;
|
||||
realTitle = item;
|
||||
break;
|
||||
}
|
||||
|
||||
if (colour == color1)
|
||||
return;
|
||||
}
|
||||
|
||||
str.insert(pos,color1);
|
||||
pos += color1.length();
|
||||
pos += keyword.length();
|
||||
str.insert(pos,color2);
|
||||
pos+= color2.length();
|
||||
}
|
||||
}
|
||||
|
||||
std::string DialogueWindow::parseText(const std::string& text)
|
||||
{
|
||||
bool separatorReached = false; // only parse topics that are below the separator (this prevents actions like "Barter" that are not topics from getting blue-colored)
|
||||
|
||||
std::vector<std::string> topics;
|
||||
|
||||
bool hasSeparator = false;
|
||||
for (unsigned int i=0; i<mTopicsList->getItemCount(); ++i)
|
||||
{
|
||||
if (mTopicsList->getItemNameAt(i) == "")
|
||||
hasSeparator = true;
|
||||
}
|
||||
|
||||
for(unsigned int i = 0;i<mTopicsList->getItemCount();i++)
|
||||
{
|
||||
std::string keyWord = mTopicsList->getItemNameAt(i);
|
||||
if (separatorReached || !hasSeparator)
|
||||
topics.push_back(keyWord);
|
||||
else if (keyWord == "")
|
||||
separatorReached = true;
|
||||
}
|
||||
|
||||
// sort by length to make sure longer topics are replaced first
|
||||
std::sort(topics.begin(), topics.end(), sortByLength);
|
||||
|
||||
std::vector<MWDialogue::HyperTextToken> hypertext = MWDialogue::ParseHyperText(text);
|
||||
|
||||
size_t historySize = 0;
|
||||
if(mHistory->getClient()->getSubWidgetText() != NULL)
|
||||
{
|
||||
historySize = mHistory->getOnlyText().size();
|
||||
}
|
||||
|
||||
std::string result;
|
||||
size_t hypertextPos = 0;
|
||||
for (size_t i = 0; i < hypertext.size(); ++i)
|
||||
{
|
||||
if (hypertext[i].mLink)
|
||||
{
|
||||
size_t asterisk_count = MWDialogue::RemovePseudoAsterisks(hypertext[i].mText);
|
||||
std::string standardForm = hypertext[i].mText;
|
||||
for(; asterisk_count > 0; --asterisk_count)
|
||||
standardForm.append("*");
|
||||
|
||||
standardForm =
|
||||
MWBase::Environment::get().getWindowManager()->
|
||||
getTranslationDataStorage().topicStandardForm(standardForm);
|
||||
|
||||
if( std::find(topics.begin(), topics.end(), std::string(standardForm) ) != topics.end() )
|
||||
{
|
||||
result.append("#686EBA").append(hypertext[i].mText).append("#B29154");
|
||||
|
||||
mHyperLinks[historySize+hypertextPos].mLength = MyGUI::UString(hypertext[i].mText).length();
|
||||
mHyperLinks[historySize+hypertextPos].mTrueValue = lower_string(standardForm);
|
||||
}
|
||||
else
|
||||
result += hypertext[i].mText;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation() )
|
||||
{
|
||||
for(std::vector<std::string>::const_iterator it = topics.begin(); it != topics.end(); ++it)
|
||||
{
|
||||
addColorInString(hypertext[i].mText, *it, "#686EBA", "#B29154");
|
||||
}
|
||||
}
|
||||
|
||||
result += hypertext[i].mText;
|
||||
}
|
||||
|
||||
hypertextPos += MyGUI::UString(hypertext[i].mText).length();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void DialogueWindow::addText(std::string text)
|
||||
{
|
||||
mHistory->addDialogText("#B29154"+parseText(text)+"#B29154");
|
||||
mHistoryContents.push_back(new Response(text, realTitle));
|
||||
updateHistory();
|
||||
}
|
||||
|
||||
void DialogueWindow::addMessageBox(const std::string& text)
|
||||
{
|
||||
mHistory->addDialogText("\n#FFFFFF"+text+"#B29154");
|
||||
mHistoryContents.push_back(new Message(text));
|
||||
updateHistory();
|
||||
}
|
||||
|
||||
void DialogueWindow::addTitle(std::string text)
|
||||
void DialogueWindow::addChoice(const std::string& choice, int id)
|
||||
{
|
||||
// This is called from the dialogue manager, so text is
|
||||
// case-smashed - thus we have to retrieve the correct case
|
||||
// of the text through the topic list.
|
||||
for (size_t i=0; i<mTopicsList->getItemCount(); ++i)
|
||||
{
|
||||
std::string item = mTopicsList->getItemNameAt(i);
|
||||
if (lower_string(item) == text)
|
||||
text = item;
|
||||
}
|
||||
|
||||
mHistory->addDialogHeading(text);
|
||||
mChoices[choice] = id;
|
||||
updateHistory();
|
||||
}
|
||||
|
||||
void DialogueWindow::askQuestion(std::string question)
|
||||
void DialogueWindow::clearChoices()
|
||||
{
|
||||
mHistory->addDialogText("#572D21"+question+"#B29154"+" ");
|
||||
mChoices.clear();
|
||||
updateHistory();
|
||||
}
|
||||
|
||||
void DialogueWindow::updateOptions()
|
||||
{
|
||||
//Clear the list of topics
|
||||
mTopicsList->clear();
|
||||
mHyperLinks.clear();
|
||||
mHistory->eraseText(0, mHistory->getTextLength());
|
||||
|
||||
if (mPtr.getTypeName() == typeid(ESM::NPC).name())
|
||||
{
|
||||
@ -513,9 +576,11 @@ namespace MWGui
|
||||
|
||||
void DialogueWindow::goodbye()
|
||||
{
|
||||
mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sGoodbye")->getString());
|
||||
mLinks.push_back(new Goodbye());
|
||||
mGoodbye = true;
|
||||
mTopicsList->setEnabled(false);
|
||||
mEnabled = false;
|
||||
updateHistory();
|
||||
}
|
||||
|
||||
void DialogueWindow::onReferenceUnavailable()
|
||||
|
@ -4,6 +4,10 @@
|
||||
#include "windowbase.hpp"
|
||||
#include "referenceinterface.hpp"
|
||||
|
||||
#include "bookpage.hpp"
|
||||
|
||||
#include "keywordsearch.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class WindowManager;
|
||||
@ -21,7 +25,8 @@ namespace MWGui
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class DialogueHistory;
|
||||
class DialogueHistoryViewModel;
|
||||
class BookPage;
|
||||
|
||||
class PersuasionDialog : public WindowModal
|
||||
{
|
||||
@ -44,6 +49,55 @@ namespace MWGui
|
||||
void onPersuade (MyGUI::Widget* sender);
|
||||
};
|
||||
|
||||
|
||||
struct Link
|
||||
{
|
||||
virtual ~Link() {}
|
||||
virtual void activated () = 0;
|
||||
};
|
||||
|
||||
struct Topic : Link
|
||||
{
|
||||
Topic(const std::string& id) : mTopicId(id) {}
|
||||
std::string mTopicId;
|
||||
virtual void activated ();
|
||||
};
|
||||
|
||||
struct Choice : Link
|
||||
{
|
||||
Choice(int id) : mChoiceId(id) {}
|
||||
int mChoiceId;
|
||||
virtual void activated ();
|
||||
};
|
||||
|
||||
struct Goodbye : Link
|
||||
{
|
||||
virtual void activated ();
|
||||
};
|
||||
|
||||
typedef KeywordSearch <std::string, intptr_t> KeywordSearchT;
|
||||
|
||||
struct DialogueText
|
||||
{
|
||||
virtual ~DialogueText() {}
|
||||
virtual void write (BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map<std::string, Link*>& topicLinks) const = 0;
|
||||
std::string mText;
|
||||
};
|
||||
|
||||
struct Response : DialogueText
|
||||
{
|
||||
Response(const std::string& text, const std::string& title = "");
|
||||
virtual void write (BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map<std::string, Link*>& topicLinks) const;
|
||||
void addTopicLink (BookTypesetter::Ptr typesetter, intptr_t topicId, size_t begin, size_t end) const;
|
||||
std::string mTitle;
|
||||
};
|
||||
|
||||
struct Message : DialogueText
|
||||
{
|
||||
Message(const std::string& text);
|
||||
virtual void write (BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map<std::string, Link*>& topicLinks) const;
|
||||
};
|
||||
|
||||
class DialogueWindow: public WindowBase, public ReferenceInterface
|
||||
{
|
||||
public:
|
||||
@ -52,19 +106,18 @@ namespace MWGui
|
||||
// Events
|
||||
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
|
||||
|
||||
/** Event : Dialog finished, OK button clicked.\n
|
||||
signature : void method()\n
|
||||
*/
|
||||
EventHandle_Void eventBye;
|
||||
void notifyLinkClicked (TypesetBook::InteractiveId link);
|
||||
|
||||
void startDialogue(MWWorld::Ptr actor, std::string npcName);
|
||||
void stopDialogue();
|
||||
void setKeywords(std::list<std::string> keyWord);
|
||||
void removeKeyword(std::string keyWord);
|
||||
void addText(std::string text);
|
||||
|
||||
void addResponse (const std::string& text, const std::string& title="");
|
||||
|
||||
void addMessageBox(const std::string& text);
|
||||
void addTitle(std::string text);
|
||||
void askQuestion(std::string question);
|
||||
|
||||
void addChoice(const std::string& choice, int id);
|
||||
void clearChoices();
|
||||
|
||||
void goodbye();
|
||||
void onFrame();
|
||||
|
||||
@ -85,37 +138,39 @@ namespace MWGui
|
||||
protected:
|
||||
void onSelectTopic(const std::string& topic, int id);
|
||||
void onByeClicked(MyGUI::Widget* _sender);
|
||||
void onHistoryClicked(MyGUI::Widget* _sender);
|
||||
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
|
||||
void onWindowResize(MyGUI::Window* _sender);
|
||||
|
||||
virtual void onReferenceUnavailable();
|
||||
void onScrollbarMoved (MyGUI::ScrollBar* sender, size_t pos);
|
||||
|
||||
struct HyperLink
|
||||
{
|
||||
size_t mLength;
|
||||
std::string mTrueValue;
|
||||
};
|
||||
void updateHistory(bool scrollbar=false);
|
||||
|
||||
virtual void onReferenceUnavailable();
|
||||
|
||||
private:
|
||||
void updateOptions();
|
||||
/**
|
||||
*Helper function that add topic keyword in blue in a text.
|
||||
*/
|
||||
std::string parseText(const std::string& text);
|
||||
|
||||
int mServices;
|
||||
|
||||
bool mEnabled;
|
||||
|
||||
DialogueHistory* mHistory;
|
||||
bool mGoodbye;
|
||||
|
||||
std::vector<DialogueText*> mHistoryContents;
|
||||
std::map<std::string, int> mChoices;
|
||||
|
||||
std::vector<Link*> mLinks;
|
||||
std::map<std::string, Link*> mTopicLinks;
|
||||
|
||||
KeywordSearchT mKeywordSearch;
|
||||
|
||||
BookPage* mHistory;
|
||||
Widgets::MWList* mTopicsList;
|
||||
MyGUI::ScrollBar* mScrollBar;
|
||||
MyGUI::ProgressPtr mDispositionBar;
|
||||
MyGUI::EditBox* mDispositionText;
|
||||
|
||||
PersuasionDialog mPersuasionDialog;
|
||||
|
||||
std::map<size_t, HyperLink> mHyperLinks;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -1,78 +0,0 @@
|
||||
#include "dialoguehistory.hpp"
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "widgets.hpp"
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
MyGUI::UString DialogueHistory::getColorAtPos(size_t _pos)
|
||||
{
|
||||
MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour());
|
||||
MyGUI::TextIterator iterator(getCaption());
|
||||
while(iterator.moveNext())
|
||||
{
|
||||
size_t pos = iterator.getPosition();
|
||||
iterator.getTagColour(colour);
|
||||
if (pos < _pos)
|
||||
continue;
|
||||
else if (pos == _pos)
|
||||
break;
|
||||
}
|
||||
return colour;
|
||||
}
|
||||
|
||||
MyGUI::UString DialogueHistory::getColorTextAt(size_t _pos)
|
||||
{
|
||||
bool breakOnNext = false;
|
||||
MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour());
|
||||
MyGUI::UString colour2 = colour;
|
||||
MyGUI::TextIterator iterator(getCaption());
|
||||
MyGUI::TextIterator col_start = iterator;
|
||||
while(iterator.moveNext())
|
||||
{
|
||||
size_t pos = iterator.getPosition();
|
||||
iterator.getTagColour(colour);
|
||||
if(colour != colour2)
|
||||
{
|
||||
if(breakOnNext)
|
||||
{
|
||||
return getOnlyText().substr(col_start.getPosition(), iterator.getPosition()-col_start.getPosition());
|
||||
}
|
||||
col_start = iterator;
|
||||
colour2 = colour;
|
||||
}
|
||||
if (pos < _pos)
|
||||
continue;
|
||||
else if (pos == _pos)
|
||||
{
|
||||
breakOnNext = true;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void DialogueHistory::addDialogHeading(const MyGUI::UString& parText)
|
||||
{
|
||||
MyGUI::UString head("\n#D8C09A");
|
||||
head.append(parText);
|
||||
head.append("#B29154\n");
|
||||
addText(head);
|
||||
}
|
||||
|
||||
void DialogueHistory::addDialogText(const MyGUI::UString& parText)
|
||||
{
|
||||
addText(parText);
|
||||
addText("\n");
|
||||
}
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#ifndef MWGUI_DIALOGE_HISTORY_H
|
||||
#define MWGUI_DIALOGE_HISTORY_H
|
||||
|
||||
#include <openengine/gui/layout.hpp>
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class DialogueHistory : public MyGUI::EditBox
|
||||
{
|
||||
MYGUI_RTTI_DERIVED( DialogueHistory )
|
||||
public:
|
||||
Widget* getClient() { return mClient; }
|
||||
MyGUI::UString getColorAtPos(size_t _pos);
|
||||
MyGUI::UString getColorTextAt(size_t _pos);
|
||||
void addDialogHeading(const MyGUI::UString& parText);
|
||||
void addDialogText(const MyGUI::UString& parText);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -6,7 +6,10 @@
|
||||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/range/adaptor/filtered.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
#include <OgreUTFString.h>
|
||||
|
||||
namespace
|
||||
@ -74,6 +77,12 @@ namespace
|
||||
Ogre::UTFString string(s);
|
||||
return string.getChar(0);
|
||||
}
|
||||
|
||||
bool is_not_empty(const std::string s) {
|
||||
std::string temp = s;
|
||||
boost::algorithm::trim(temp);
|
||||
return !temp.empty();
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
@ -88,6 +97,7 @@ namespace MWGui
|
||||
utf8Text = Interpreter::fixDefinesBook(utf8Text, interpreterContext);
|
||||
|
||||
boost::algorithm::replace_all(utf8Text, "\n", "");
|
||||
boost::algorithm::replace_all(utf8Text, "\r", "");
|
||||
boost::algorithm::replace_all(utf8Text, "<BR>", "\n");
|
||||
boost::algorithm::replace_all(utf8Text, "<P>", "\n\n");
|
||||
|
||||
@ -106,6 +116,14 @@ namespace MWGui
|
||||
|
||||
size_t currentWordStart = 0;
|
||||
size_t index = 0;
|
||||
|
||||
{
|
||||
std::string texToTrim = text.asUTF8();
|
||||
boost::algorithm::trim( texToTrim );
|
||||
text = UTFString(texToTrim);
|
||||
}
|
||||
|
||||
|
||||
while (currentHeight <= height - spacing && index < text.size())
|
||||
{
|
||||
const UTFString::unicode_char ch = text.getChar(index);
|
||||
@ -176,8 +194,10 @@ namespace MWGui
|
||||
result.push_back(text.substr(0, pageEnd).asUTF8());
|
||||
text.erase(0, pageEnd);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
std::vector<std::string> nonEmptyPages;
|
||||
boost::copy(result | boost::adaptors::filtered(is_not_empty), std::back_inserter(nonEmptyPages));
|
||||
return nonEmptyPages;
|
||||
}
|
||||
|
||||
float BookTextParser::widthForCharGlyph(unsigned unicodeChar) const
|
||||
@ -193,7 +213,30 @@ namespace MWGui
|
||||
return MyGUI::FontManager::getInstance().getByName(fontName)->getDefaultHeight();
|
||||
}
|
||||
|
||||
MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width)
|
||||
MyGUI::IntSize BookTextParser::parsePage(std::string text, MyGUI::Widget* parent, const int width)
|
||||
{
|
||||
MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor
|
||||
text = Interpreter::fixDefinesBook(text, interpreterContext);
|
||||
|
||||
mParent = parent;
|
||||
mWidth = width;
|
||||
mHeight = 0;
|
||||
|
||||
assert(mParent);
|
||||
while (mParent->getChildCount())
|
||||
{
|
||||
MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0));
|
||||
}
|
||||
|
||||
// remove trailing "
|
||||
if (text[text.size()-1] == '\"')
|
||||
text.erase(text.size()-1);
|
||||
|
||||
parseSubText(text);
|
||||
return MyGUI::IntSize(mWidth, mHeight);
|
||||
}
|
||||
|
||||
MyGUI::IntSize BookTextParser::parseScroll(std::string text, MyGUI::Widget* parent, const int width)
|
||||
{
|
||||
MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor
|
||||
text = Interpreter::fixDefinesBook(text, interpreterContext);
|
||||
@ -209,12 +252,10 @@ namespace MWGui
|
||||
}
|
||||
|
||||
boost::algorithm::replace_all(text, "\n", "");
|
||||
boost::algorithm::replace_all(text, "\r", "");
|
||||
boost::algorithm::replace_all(text, "<BR>", "\n");
|
||||
boost::algorithm::replace_all(text, "<P>", "\n\n");
|
||||
|
||||
// remove leading newlines
|
||||
// while (text[0] == '\n')
|
||||
// text.erase(0);
|
||||
boost::algorithm::trim_left(text);
|
||||
|
||||
// remove trailing "
|
||||
if (text[text.size()-1] == '\"')
|
||||
@ -223,6 +264,7 @@ namespace MWGui
|
||||
parseSubText(text);
|
||||
return MyGUI::IntSize(mWidth, mHeight);
|
||||
}
|
||||
|
||||
|
||||
void BookTextParser::parseImage(std::string tag, bool createWidget)
|
||||
{
|
||||
@ -309,7 +351,7 @@ namespace MWGui
|
||||
parseImage(tag);
|
||||
if (boost::algorithm::starts_with(tag, "FONT"))
|
||||
parseFont(tag);
|
||||
if (boost::algorithm::starts_with(tag, "DOV"))
|
||||
if (boost::algorithm::starts_with(tag, "DIV"))
|
||||
parseDiv(tag);
|
||||
|
||||
text.erase(0, tagEnd + 1);
|
||||
|
@ -32,7 +32,16 @@ namespace MWGui
|
||||
* @param maximum width
|
||||
* @return size of the created widgets
|
||||
*/
|
||||
MyGUI::IntSize parse(std::string text, MyGUI::Widget* parent, const int width);
|
||||
MyGUI::IntSize parsePage(std::string text, MyGUI::Widget* parent, const int width);
|
||||
|
||||
/**
|
||||
* Parse markup as MyGUI widgets
|
||||
* @param markup to parse
|
||||
* @param parent for the created widgets
|
||||
* @param maximum width
|
||||
* @return size of the created widgets
|
||||
*/
|
||||
MyGUI::IntSize parseScroll(std::string text, MyGUI::Widget* parent, const int width);
|
||||
|
||||
/**
|
||||
* Split the specified text into pieces that fit in the area specified by width and height parameters
|
||||
|
326
apps/openmw/mwgui/journalbooks.cpp
Normal file
326
apps/openmw/mwgui/journalbooks.cpp
Normal file
@ -0,0 +1,326 @@
|
||||
#include "journalbooks.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text)
|
||||
{
|
||||
typedef MWGui::BookTypesetter::Utf8Point point;
|
||||
|
||||
point begin = reinterpret_cast <point> (text);
|
||||
|
||||
return MWGui::BookTypesetter::Utf8Span (begin, begin + strlen (text));
|
||||
}
|
||||
|
||||
const MyGUI::Colour linkHot (0.40f, 0.40f, 0.80f);
|
||||
const MyGUI::Colour linkNormal (0.20f, 0.20f, 0.60f);
|
||||
const MyGUI::Colour linkActive (0.50f, 0.50f, 1.00f);
|
||||
|
||||
struct AddContent
|
||||
{
|
||||
MWGui::BookTypesetter::Ptr mTypesetter;
|
||||
MWGui::BookTypesetter::Style* mBodyStyle;
|
||||
|
||||
AddContent (MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* body_style) :
|
||||
mTypesetter (typesetter), mBodyStyle (body_style)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct AddSpan : AddContent
|
||||
{
|
||||
AddSpan (MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* body_style) :
|
||||
AddContent (typesetter, body_style)
|
||||
{
|
||||
}
|
||||
|
||||
void operator () (intptr_t topicId, size_t begin, size_t end)
|
||||
{
|
||||
MWGui::BookTypesetter::Style* style = mBodyStyle;
|
||||
|
||||
if (topicId)
|
||||
style = mTypesetter->createHotStyle (mBodyStyle, linkNormal, linkHot, linkActive, topicId);
|
||||
|
||||
mTypesetter->write (style, begin, end);
|
||||
}
|
||||
};
|
||||
|
||||
struct AddEntry
|
||||
{
|
||||
MWGui::BookTypesetter::Ptr mTypesetter;
|
||||
MWGui::BookTypesetter::Style* mBodyStyle;
|
||||
|
||||
AddEntry (MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* body_style) :
|
||||
mTypesetter (typesetter), mBodyStyle (body_style)
|
||||
{
|
||||
}
|
||||
|
||||
void operator () (MWGui::JournalViewModel::Entry const & entry)
|
||||
{
|
||||
mTypesetter->addContent (entry.body ());
|
||||
|
||||
entry.visitSpans (AddSpan (mTypesetter, mBodyStyle));
|
||||
}
|
||||
};
|
||||
|
||||
struct AddJournalEntry : AddEntry
|
||||
{
|
||||
bool mAddHeader;
|
||||
MWGui::BookTypesetter::Style* mHeaderStyle;
|
||||
|
||||
AddJournalEntry (MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* body_style,
|
||||
MWGui::BookTypesetter::Style* header_style, bool add_header) :
|
||||
AddEntry (typesetter, body_style),
|
||||
mHeaderStyle (header_style),
|
||||
mAddHeader (add_header)
|
||||
{
|
||||
}
|
||||
|
||||
void operator () (MWGui::JournalViewModel::JournalEntry const & entry)
|
||||
{
|
||||
if (mAddHeader)
|
||||
{
|
||||
mTypesetter->write (mHeaderStyle, entry.timestamp ());
|
||||
mTypesetter->lineBreak ();
|
||||
}
|
||||
|
||||
AddEntry::operator () (entry);
|
||||
|
||||
mTypesetter->sectionBreak (10);
|
||||
}
|
||||
};
|
||||
|
||||
struct AddTopicEntry : AddEntry
|
||||
{
|
||||
intptr_t mContentId;
|
||||
MWGui::BookTypesetter::Style* mHeaderStyle;
|
||||
|
||||
AddTopicEntry (MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* body_style,
|
||||
MWGui::BookTypesetter::Style* header_style, intptr_t contentId) :
|
||||
AddEntry (typesetter, body_style), mHeaderStyle (header_style), mContentId (contentId)
|
||||
{
|
||||
}
|
||||
|
||||
void operator () (MWGui::JournalViewModel::TopicEntry const & entry)
|
||||
{
|
||||
mTypesetter->write (mBodyStyle, entry.source ());
|
||||
mTypesetter->write (mBodyStyle, 0, 3);// begin
|
||||
|
||||
AddEntry::operator() (entry);
|
||||
|
||||
mTypesetter->selectContent (mContentId);
|
||||
mTypesetter->write (mBodyStyle, 2, 3);// end quote
|
||||
|
||||
mTypesetter->sectionBreak (10);
|
||||
}
|
||||
};
|
||||
|
||||
struct AddTopicName : AddContent
|
||||
{
|
||||
AddTopicName (MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* style) :
|
||||
AddContent (typesetter, style)
|
||||
{
|
||||
}
|
||||
|
||||
void operator () (MWGui::JournalViewModel::Utf8Span topicName)
|
||||
{
|
||||
mTypesetter->write (mBodyStyle, topicName);
|
||||
mTypesetter->sectionBreak (10);
|
||||
}
|
||||
};
|
||||
|
||||
struct AddQuestName : AddContent
|
||||
{
|
||||
AddQuestName (MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* style) :
|
||||
AddContent (typesetter, style)
|
||||
{
|
||||
}
|
||||
|
||||
void operator () (MWGui::JournalViewModel::Utf8Span topicName)
|
||||
{
|
||||
mTypesetter->write (mBodyStyle, topicName);
|
||||
mTypesetter->sectionBreak (10);
|
||||
}
|
||||
};
|
||||
|
||||
struct AddTopicLink : AddContent
|
||||
{
|
||||
AddTopicLink (MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* style) :
|
||||
AddContent (typesetter, style)
|
||||
{
|
||||
}
|
||||
|
||||
void operator () (MWGui::JournalViewModel::TopicId topicId, MWGui::JournalViewModel::Utf8Span name)
|
||||
{
|
||||
MWGui::BookTypesetter::Style* link = mTypesetter->createHotStyle (mBodyStyle, MyGUI::Colour::Black, linkHot, linkActive, topicId);
|
||||
|
||||
mTypesetter->write (link, name);
|
||||
mTypesetter->lineBreak ();
|
||||
}
|
||||
};
|
||||
|
||||
struct AddQuestLink : AddContent
|
||||
{
|
||||
AddQuestLink (MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* style) :
|
||||
AddContent (typesetter, style)
|
||||
{
|
||||
}
|
||||
|
||||
void operator () (MWGui::JournalViewModel::QuestId id, MWGui::JournalViewModel::Utf8Span name)
|
||||
{
|
||||
MWGui::BookTypesetter::Style* style = mTypesetter->createHotStyle (mBodyStyle, MyGUI::Colour::Black, linkHot, linkActive, id);
|
||||
|
||||
mTypesetter->write (style, name);
|
||||
mTypesetter->lineBreak ();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
typedef TypesetBook::Ptr book;
|
||||
|
||||
JournalBooks::JournalBooks (JournalViewModel::Ptr model) :
|
||||
mModel (model)
|
||||
{
|
||||
}
|
||||
|
||||
book JournalBooks::createEmptyJournalBook ()
|
||||
{
|
||||
BookTypesetter::Ptr typesetter = createTypesetter ();
|
||||
|
||||
BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f));
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
|
||||
|
||||
typesetter->write (header, to_utf8_span ("You have no journal entries!"));
|
||||
typesetter->lineBreak ();
|
||||
typesetter->write (body, to_utf8_span ("You should have gone though the starting quest and got an initial quest."));
|
||||
|
||||
BookTypesetter::Style* big = typesetter->createStyle ("EB Garamond 24", MyGUI::Colour::Black);
|
||||
BookTypesetter::Style* test = typesetter->createStyle ("MonoFont", MyGUI::Colour::Blue);
|
||||
|
||||
typesetter->sectionBreak (20);
|
||||
typesetter->write (body, to_utf8_span (
|
||||
"The layout engine doesn't currently support aligning fonts to "
|
||||
"their baseline within a single line so the following text looks "
|
||||
"funny. In order to properly implement it, a stupidly simple "
|
||||
"change is needed in MyGUI to report the where the baseline is for "
|
||||
"a particular font"
|
||||
));
|
||||
|
||||
typesetter->sectionBreak (20);
|
||||
typesetter->write (big, to_utf8_span ("big text g"));
|
||||
typesetter->write (body, to_utf8_span (" проверяем только в дебаге"));
|
||||
typesetter->write (body, to_utf8_span (" normal g"));
|
||||
typesetter->write (big, to_utf8_span (" done g"));
|
||||
|
||||
typesetter->sectionBreak (20);
|
||||
typesetter->write (test, to_utf8_span (
|
||||
"int main (int argc,\n"
|
||||
" char ** argv)\n"
|
||||
"{\n"
|
||||
" print (\"hello world!\\n\");\n"
|
||||
" return 0;\n"
|
||||
"}\n"
|
||||
));
|
||||
|
||||
return typesetter->complete ();
|
||||
}
|
||||
|
||||
book JournalBooks::createJournalBook ()
|
||||
{
|
||||
BookTypesetter::Ptr typesetter = createTypesetter ();
|
||||
|
||||
BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f));
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
|
||||
|
||||
mModel->visitJournalEntries (0, AddJournalEntry (typesetter, body, header, true));
|
||||
|
||||
return typesetter->complete ();
|
||||
}
|
||||
|
||||
book JournalBooks::createTopicBook (uintptr_t topicId)
|
||||
{
|
||||
BookTypesetter::Ptr typesetter = createTypesetter ();
|
||||
|
||||
BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f));
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
|
||||
|
||||
mModel->visitTopicName (topicId, AddTopicName (typesetter, header));
|
||||
|
||||
intptr_t contentId = typesetter->addContent (to_utf8_span (", \""));
|
||||
|
||||
mModel->visitTopicEntries (topicId, AddTopicEntry (typesetter, body, header, contentId));
|
||||
|
||||
return typesetter->complete ();
|
||||
}
|
||||
|
||||
book JournalBooks::createQuestBook (uintptr_t questId)
|
||||
{
|
||||
BookTypesetter::Ptr typesetter = createTypesetter ();
|
||||
|
||||
BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f));
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
|
||||
|
||||
mModel->visitQuestName (questId, AddQuestName (typesetter, header));
|
||||
|
||||
mModel->visitJournalEntries (questId, AddJournalEntry (typesetter, body, header, false));
|
||||
|
||||
return typesetter->complete ();
|
||||
}
|
||||
|
||||
book JournalBooks::createTopicIndexBook ()
|
||||
{
|
||||
BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 250);
|
||||
|
||||
typesetter->setSectionAlignment (BookTypesetter::AlignCenter);
|
||||
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
|
||||
|
||||
for (int i = 0; i < 26; ++i)
|
||||
{
|
||||
char ch = 'A' + i;
|
||||
|
||||
char buffer [32];
|
||||
|
||||
sprintf (buffer, "( %c )", ch);
|
||||
|
||||
BookTypesetter::Style* style = typesetter->createHotStyle (body, MyGUI::Colour::Black, linkHot, linkActive, ch);
|
||||
|
||||
if (i == 13)
|
||||
typesetter->sectionBreak ();
|
||||
|
||||
typesetter->write (style, to_utf8_span (buffer));
|
||||
typesetter->lineBreak ();
|
||||
}
|
||||
|
||||
return typesetter->complete ();
|
||||
}
|
||||
|
||||
book JournalBooks::createTopicIndexBook (char character)
|
||||
{
|
||||
BookTypesetter::Ptr typesetter = BookTypesetter::create (0x7FFFFFFF, 0x7FFFFFFF);
|
||||
BookTypesetter::Style* style = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
|
||||
|
||||
mModel->visitTopicNamesStartingWith (character, AddTopicLink (typesetter, style));
|
||||
|
||||
return typesetter->complete ();
|
||||
}
|
||||
|
||||
book JournalBooks::createQuestIndexBook (bool activeOnly)
|
||||
{
|
||||
BookTypesetter::Ptr typesetter = BookTypesetter::create (0x7FFFFFFF, 0x7FFFFFFF);
|
||||
BookTypesetter::Style* base = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
|
||||
|
||||
mModel->visitQuestNames (activeOnly, AddQuestLink (typesetter, base));
|
||||
|
||||
return typesetter->complete ();
|
||||
}
|
||||
|
||||
BookTypesetter::Ptr JournalBooks::createTypesetter ()
|
||||
{
|
||||
//TODO: determine page size from layout...
|
||||
return BookTypesetter::create (240, 300);
|
||||
}
|
||||
|
||||
}
|
29
apps/openmw/mwgui/journalbooks.hpp
Normal file
29
apps/openmw/mwgui/journalbooks.hpp
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef MWGUI_JOURNALBOOKS_HPP
|
||||
#define MWGUI_JOURNALBOOKS_HPP
|
||||
|
||||
#include "bookpage.hpp"
|
||||
#include "journalviewmodel.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
struct JournalBooks
|
||||
{
|
||||
typedef TypesetBook::Ptr Book;
|
||||
JournalViewModel::Ptr mModel;
|
||||
|
||||
JournalBooks (JournalViewModel::Ptr model);
|
||||
|
||||
Book createEmptyJournalBook ();
|
||||
Book createJournalBook ();
|
||||
Book createTopicBook (uintptr_t topicId);
|
||||
Book createQuestBook (uintptr_t questId);
|
||||
Book createTopicIndexBook ();
|
||||
Book createTopicIndexBook (char character);
|
||||
Book createQuestIndexBook (bool showAll);
|
||||
|
||||
private:
|
||||
BookTypesetter::Ptr createTypesetter ();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MWGUI_JOURNALBOOKS_HPP
|
389
apps/openmw/mwgui/journalviewmodel.cpp
Normal file
389
apps/openmw/mwgui/journalviewmodel.cpp
Normal file
@ -0,0 +1,389 @@
|
||||
#include "journalviewmodel.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <boost/make_shared.hpp>
|
||||
|
||||
#include <MyGUI_LanguageManager.h>
|
||||
|
||||
#include <components/misc/utf8stream.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/journal.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwdialogue/journalentry.hpp"
|
||||
|
||||
#include "keywordsearch.hpp"
|
||||
|
||||
namespace MWGui {
|
||||
|
||||
struct JournalViewModelImpl;
|
||||
|
||||
static void injectMonthName (std::ostream & os, int month);
|
||||
|
||||
struct JournalViewModelImpl : JournalViewModel
|
||||
{
|
||||
typedef KeywordSearch <std::string, intptr_t> KeywordSearchT;
|
||||
|
||||
mutable bool mKeywordSearchLoaded;
|
||||
mutable KeywordSearchT mKeywordSearch;
|
||||
|
||||
std::locale mLocale;
|
||||
|
||||
JournalViewModelImpl ()
|
||||
{
|
||||
mKeywordSearchLoaded = false;
|
||||
}
|
||||
|
||||
virtual ~JournalViewModelImpl ()
|
||||
{
|
||||
}
|
||||
|
||||
/// \todo replace this nasty BS
|
||||
static Utf8Span toUtf8Span (std::string const & str)
|
||||
{
|
||||
if (str.size () == 0)
|
||||
return Utf8Span (Utf8Point (NULL), Utf8Point (NULL));
|
||||
|
||||
Utf8Point point = reinterpret_cast <Utf8Point> (str.c_str ());
|
||||
|
||||
return Utf8Span (point, point + str.size ());
|
||||
}
|
||||
|
||||
void load ()
|
||||
{
|
||||
}
|
||||
|
||||
void unload ()
|
||||
{
|
||||
mKeywordSearch.clear ();
|
||||
mKeywordSearchLoaded = false;
|
||||
}
|
||||
|
||||
void ensureKeyWordSearchLoaded () const
|
||||
{
|
||||
if (!mKeywordSearchLoaded)
|
||||
{
|
||||
MWBase::Journal * journal = MWBase::Environment::get().getJournal();
|
||||
|
||||
for(MWBase::Journal::TTopicIter i = journal->topicBegin(); i != journal->topicEnd (); ++i)
|
||||
mKeywordSearch.seed (i->first, intptr_t (&i->second));
|
||||
|
||||
mKeywordSearchLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t tolower (wchar_t ch) const { return std::tolower (ch, mLocale); }
|
||||
|
||||
bool isEmpty () const
|
||||
{
|
||||
MWBase::Journal * journal = MWBase::Environment::get().getJournal();
|
||||
|
||||
return journal->begin () == journal->end ();
|
||||
}
|
||||
|
||||
template <typename t_iterator, typename Interface>
|
||||
struct BaseEntry : Interface
|
||||
{
|
||||
typedef t_iterator iterator_t;
|
||||
|
||||
iterator_t itr;
|
||||
JournalViewModelImpl const * mModel;
|
||||
|
||||
BaseEntry (JournalViewModelImpl const * model, iterator_t itr) :
|
||||
mModel (model), itr (itr), loaded (false)
|
||||
{}
|
||||
|
||||
virtual ~BaseEntry () {}
|
||||
|
||||
mutable bool loaded;
|
||||
mutable std::string utf8text;
|
||||
|
||||
typedef std::pair<size_t, size_t> Range;
|
||||
|
||||
// hyperlinks in @link# notation
|
||||
mutable std::map<Range, intptr_t> mHyperLinks;
|
||||
|
||||
virtual std::string getText () const = 0;
|
||||
|
||||
void ensureLoaded () const
|
||||
{
|
||||
if (!loaded)
|
||||
{
|
||||
mModel->ensureKeyWordSearchLoaded ();
|
||||
|
||||
utf8text = getText ();
|
||||
|
||||
size_t pos_begin, pos_end;
|
||||
for(;;)
|
||||
{
|
||||
pos_begin = utf8text.find('@');
|
||||
if (pos_begin != std::string::npos)
|
||||
pos_end = utf8text.find('#', pos_begin);
|
||||
|
||||
if (pos_begin != std::string::npos && pos_end != std::string::npos)
|
||||
{
|
||||
std::string link = utf8text.substr(pos_begin + 1, pos_end - pos_begin - 1);
|
||||
const char specialPseudoAsteriskCharacter = 127;
|
||||
std::replace(link.begin(), link.end(), specialPseudoAsteriskCharacter, '*');
|
||||
std::string topicName = MWBase::Environment::get().getWindowManager()->
|
||||
getTranslationDataStorage().topicStandardForm(link);
|
||||
|
||||
std::string displayName = link;
|
||||
while (displayName[displayName.size()-1] == '*')
|
||||
displayName.erase(displayName.size()-1, 1);
|
||||
|
||||
utf8text.replace(pos_begin, pos_end+1-pos_begin, displayName);
|
||||
|
||||
intptr_t value;
|
||||
if (mModel->mKeywordSearch.containsKeyword(topicName, value))
|
||||
mHyperLinks[std::make_pair(pos_begin, pos_begin+displayName.size())] = value;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
Utf8Span body () const
|
||||
{
|
||||
ensureLoaded ();
|
||||
|
||||
return toUtf8Span (utf8text);
|
||||
}
|
||||
|
||||
void visitSpans (boost::function < void (TopicId, size_t, size_t)> visitor) const
|
||||
{
|
||||
ensureLoaded ();
|
||||
mModel->ensureKeyWordSearchLoaded ();
|
||||
|
||||
if (mHyperLinks.size() && MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation())
|
||||
{
|
||||
size_t formatted = 0; // points to the first character that is not laid out yet
|
||||
for (std::map<Range, intptr_t>::const_iterator it = mHyperLinks.begin(); it != mHyperLinks.end(); ++it)
|
||||
{
|
||||
intptr_t topicId = it->second;
|
||||
if (formatted < it->first.first)
|
||||
visitor (0, formatted, it->first.first);
|
||||
visitor (topicId, it->first.first, it->first.second);
|
||||
formatted = it->first.second;
|
||||
}
|
||||
if (formatted < utf8text.size())
|
||||
visitor (0, formatted, utf8text.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string::const_iterator i = utf8text.begin ();
|
||||
|
||||
KeywordSearchT::Match match;
|
||||
|
||||
while (i != utf8text.end () && mModel->mKeywordSearch.search (i, utf8text.end (), match))
|
||||
{
|
||||
if (i != match.mBeg)
|
||||
visitor (0, i - utf8text.begin (), match.mBeg - utf8text.begin ());
|
||||
|
||||
visitor (match.mValue, match.mBeg - utf8text.begin (), match.mEnd - utf8text.begin ());
|
||||
|
||||
i = match.mEnd;
|
||||
}
|
||||
|
||||
if (i != utf8text.end ())
|
||||
visitor (0, i - utf8text.begin (), utf8text.size ());
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void visitQuestNames (bool active_only, boost::function <void (QuestId, Utf8Span)> visitor) const
|
||||
{
|
||||
MWBase::Journal * journal = MWBase::Environment::get ().getJournal ();
|
||||
|
||||
for (MWBase::Journal::TQuestIter i = journal->questBegin (); i != journal->questEnd (); ++i)
|
||||
{
|
||||
if (active_only && i->second.isFinished ())
|
||||
continue;
|
||||
|
||||
/// \todo quest.getName() is broken? returns empty string
|
||||
//const MWDialogue::Quest& quest = i->second;
|
||||
|
||||
visitor (reinterpret_cast <QuestId> (&i->second), toUtf8Span (i->first));
|
||||
}
|
||||
}
|
||||
|
||||
void visitQuestName (QuestId questId, boost::function <void (Utf8Span)> visitor) const
|
||||
{
|
||||
MWDialogue::Quest const * quest = reinterpret_cast <MWDialogue::Quest const *> (questId);
|
||||
|
||||
std::string name = quest->getName ();
|
||||
|
||||
visitor (toUtf8Span (name));
|
||||
}
|
||||
|
||||
template <typename iterator_t>
|
||||
struct JournalEntryImpl : BaseEntry <iterator_t, JournalEntry>
|
||||
{
|
||||
using BaseEntry <iterator_t, JournalEntry>::itr;
|
||||
|
||||
mutable std::string timestamp_buffer;
|
||||
|
||||
JournalEntryImpl (JournalViewModelImpl const * model, iterator_t itr) :
|
||||
BaseEntry <iterator_t, JournalEntry> (model, itr)
|
||||
{}
|
||||
|
||||
std::string getText () const
|
||||
{
|
||||
return itr->getText(MWBase::Environment::get().getWorld()->getStore());
|
||||
}
|
||||
|
||||
Utf8Span timestamp () const
|
||||
{
|
||||
if (timestamp_buffer.empty ())
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
os << itr->mDayOfMonth << ' ';
|
||||
|
||||
injectMonthName (os, itr->mMonth);
|
||||
|
||||
const std::string& dayStr = MyGUI::LanguageManager::getInstance().replaceTags("#{sDay}");
|
||||
os << " (" << dayStr << " " << (itr->mDay + 1) << ')';
|
||||
|
||||
timestamp_buffer = os.str ();
|
||||
}
|
||||
|
||||
return toUtf8Span (timestamp_buffer);
|
||||
}
|
||||
};
|
||||
|
||||
void visitJournalEntries (QuestId questId, boost::function <void (JournalEntry const &)> visitor) const
|
||||
{
|
||||
MWBase::Journal * journal = MWBase::Environment::get().getJournal();
|
||||
|
||||
if (questId != 0)
|
||||
{
|
||||
MWDialogue::Quest const * quest = reinterpret_cast <MWDialogue::Quest const *> (questId);
|
||||
|
||||
for(MWBase::Journal::TEntryIter i = journal->begin(); i != journal->end (); ++i)
|
||||
{
|
||||
for (MWDialogue::Topic::TEntryIter j = quest->begin (); j != quest->end (); ++j)
|
||||
{
|
||||
if (i->mInfoId == *j)
|
||||
visitor (JournalEntryImpl <MWBase::Journal::TEntryIter> (this, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(MWBase::Journal::TEntryIter i = journal->begin(); i != journal->end (); ++i)
|
||||
visitor (JournalEntryImpl <MWBase::Journal::TEntryIter> (this, i));
|
||||
}
|
||||
}
|
||||
|
||||
void visitTopics (boost::function <void (TopicId, Utf8Span)> visitor) const
|
||||
{
|
||||
throw std::runtime_error ("not implemented");
|
||||
}
|
||||
|
||||
void visitTopicName (TopicId topicId, boost::function <void (Utf8Span)> visitor) const
|
||||
{
|
||||
MWDialogue::Topic const & topic = * reinterpret_cast <MWDialogue::Topic const *> (topicId);
|
||||
// This is to get the correct case for the topic
|
||||
const std::string& name = MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find(topic.getName())->mId;
|
||||
visitor (toUtf8Span (name));
|
||||
}
|
||||
|
||||
void visitTopicNamesStartingWith (char character, boost::function < void (TopicId , Utf8Span) > visitor) const
|
||||
{
|
||||
MWBase::Journal * journal = MWBase::Environment::get().getJournal();
|
||||
|
||||
for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i)
|
||||
{
|
||||
if (i->first [0] != std::tolower (character, mLocale))
|
||||
continue;
|
||||
|
||||
// This is to get the correct case for the topic
|
||||
const std::string& name = MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find(i->first)->mId;
|
||||
|
||||
visitor (TopicId (&i->second), toUtf8Span (name));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct TopicEntryImpl : BaseEntry <MWDialogue::Topic::TEntryIter, TopicEntry>
|
||||
{
|
||||
MWDialogue::Topic const & mTopic;
|
||||
|
||||
mutable std::string source_buffer;
|
||||
|
||||
TopicEntryImpl (JournalViewModelImpl const * model, MWDialogue::Topic const & topic, iterator_t itr) :
|
||||
BaseEntry (model, itr), mTopic (topic)
|
||||
{}
|
||||
|
||||
std::string getText () const
|
||||
{
|
||||
/// \todo defines are not replaced (%PCName etc). should probably be done elsewhere though since we need the actor
|
||||
return mTopic.getEntry (*itr).getText(MWBase::Environment::get().getWorld()->getStore());
|
||||
|
||||
}
|
||||
|
||||
Utf8Span source () const
|
||||
{
|
||||
if (source_buffer.empty ())
|
||||
source_buffer = "someone";
|
||||
return toUtf8Span (source_buffer);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void visitTopicEntries (TopicId topicId, boost::function <void (TopicEntry const &)> visitor) const
|
||||
{
|
||||
typedef MWDialogue::Topic::TEntryIter iterator_t;
|
||||
|
||||
MWDialogue::Topic const & topic = * reinterpret_cast <MWDialogue::Topic const *> (topicId);
|
||||
|
||||
for (iterator_t i = topic.begin (); i != topic.end (); ++i)
|
||||
visitor (TopicEntryImpl (this, topic, i));
|
||||
}
|
||||
};
|
||||
|
||||
static void injectMonthName (std::ostream & os, int month)
|
||||
{
|
||||
MyGUI::LanguageManager& lm = MyGUI::LanguageManager::getInstance();
|
||||
|
||||
if (month == 0)
|
||||
os << lm.replaceTags ("#{sMonthMorningstar}");
|
||||
else if (month == 1)
|
||||
os << lm.replaceTags ("#{sMonthSunsdawn}");
|
||||
else if (month == 2)
|
||||
os << lm.replaceTags ("#{sMonthFirstseed}");
|
||||
else if (month == 3)
|
||||
os << lm.replaceTags ("#{sMonthRainshand}");
|
||||
else if (month == 4)
|
||||
os << lm.replaceTags ("#{sMonthSecondseed}");
|
||||
else if (month == 5)
|
||||
os << lm.replaceTags ("#{sMonthMidyear}");
|
||||
else if (month == 6)
|
||||
os << lm.replaceTags ("#{sMonthSunsheight}");
|
||||
else if (month == 7)
|
||||
os << lm.replaceTags ("#{sMonthLastseed}");
|
||||
else if (month == 8)
|
||||
os << lm.replaceTags ("#{sMonthHeartfire}");
|
||||
else if (month == 9)
|
||||
os << lm.replaceTags ("#{sMonthFrostfall}");
|
||||
else if (month == 10)
|
||||
os << lm.replaceTags ("#{sMonthSunsdusk}");
|
||||
else if (month == 11)
|
||||
os << lm.replaceTags ("#{sMonthEveningstar}");
|
||||
else
|
||||
os << month;
|
||||
}
|
||||
|
||||
JournalViewModel::Ptr JournalViewModel::create ()
|
||||
{
|
||||
return boost::make_shared <JournalViewModelImpl> ();
|
||||
}
|
||||
|
||||
}
|
93
apps/openmw/mwgui/journalviewmodel.hpp
Normal file
93
apps/openmw/mwgui/journalviewmodel.hpp
Normal file
@ -0,0 +1,93 @@
|
||||
#ifndef MWGUI_JOURNALVIEWMODEL_HPP
|
||||
#define MWGUI_JOURNALVIEWMODEL_HPP
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <platform/stdint.h>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
/// View-Model for the journal GUI
|
||||
///
|
||||
/// This interface defines an abstract data model suited
|
||||
/// specifically to the needs of the journal GUI. It isolates
|
||||
/// the journal GUI from the implementation details of the
|
||||
/// game data store.
|
||||
struct JournalViewModel
|
||||
{
|
||||
typedef boost::shared_ptr <JournalViewModel> Ptr;
|
||||
|
||||
typedef intptr_t QuestId;
|
||||
typedef intptr_t TopicId;
|
||||
typedef uint8_t const * Utf8Point;
|
||||
typedef std::pair <Utf8Point, Utf8Point> Utf8Span;
|
||||
|
||||
/// The base interface for both journal entries and topics.
|
||||
struct Entry
|
||||
{
|
||||
/// returns the body text for the journal entry
|
||||
///
|
||||
/// This function returns a borrowed reference to the body of the
|
||||
/// journal entry. The returned reference becomes invalid when the
|
||||
/// entry is destroyed.
|
||||
virtual Utf8Span body () const = 0;
|
||||
|
||||
/// Visits each subset of text in the body, delivering the beginning
|
||||
/// and end of the span relative to the body, and a valid topic ID if
|
||||
/// the span represents a keyword, or zero if not.
|
||||
virtual void visitSpans (boost::function <void (TopicId, size_t, size_t)> visitor) const = 0;
|
||||
};
|
||||
|
||||
/// An interface to topic data.
|
||||
struct TopicEntry : Entry
|
||||
{
|
||||
/// Returns a pre-formatted span of UTF8 encoded text representing
|
||||
/// the name of the NPC this portion of dialog was heard from.
|
||||
virtual Utf8Span source () const = 0;
|
||||
};
|
||||
|
||||
/// An interface to journal data.
|
||||
struct JournalEntry : Entry
|
||||
{
|
||||
/// Returns a pre-formatted span of UTF8 encoded text representing
|
||||
/// the in-game date this entry was added to the journal.
|
||||
virtual Utf8Span timestamp () const = 0;
|
||||
};
|
||||
|
||||
|
||||
/// called prior to journal opening
|
||||
virtual void load () = 0;
|
||||
|
||||
/// called prior to journal closing
|
||||
virtual void unload () = 0;
|
||||
|
||||
/// returns true if their are no journal entries to display
|
||||
virtual bool isEmpty () const = 0;
|
||||
|
||||
/// provides access to the name of the quest with the specified identifier
|
||||
virtual void visitQuestName (TopicId topicId, boost::function <void (Utf8Span)> visitor) const = 0;
|
||||
|
||||
/// walks the active and optionally completed, quests providing the quest id and name
|
||||
virtual void visitQuestNames (bool active_only, boost::function <void (QuestId, Utf8Span)> visitor) const = 0;
|
||||
|
||||
/// walks over the journal entries related to the specified quest identified by its id
|
||||
virtual void visitJournalEntries (QuestId questId, boost::function <void (JournalEntry const &)> visitor) const = 0;
|
||||
|
||||
/// provides the name of the topic specified by its id
|
||||
virtual void visitTopicName (TopicId topicId, boost::function <void (Utf8Span)> visitor) const = 0;
|
||||
|
||||
/// walks over the topics whose names start with the specified character providing the topics id and name
|
||||
virtual void visitTopicNamesStartingWith (char character, boost::function < void (TopicId , Utf8Span) > visitor) const = 0;
|
||||
|
||||
/// walks over the topic entries for the topic specified by its identifier
|
||||
virtual void visitTopicEntries (TopicId topicId, boost::function <void (TopicEntry const &)> visitor) const = 0;
|
||||
|
||||
// create an instance of the default journal view model implementation
|
||||
static Ptr create ();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MWGUI_JOURNALVIEWMODEL_HPP
|
@ -1,192 +1,433 @@
|
||||
#include "journalwindow.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/journal.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "list.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include "boost/lexical_cast.hpp"
|
||||
|
||||
#include "bookpage.hpp"
|
||||
#include "windowbase.hpp"
|
||||
#include "imagebutton.hpp"
|
||||
#include "journalviewmodel.hpp"
|
||||
#include "journalbooks.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct book
|
||||
static char const OptionsOverlay [] = "OptionsOverlay";
|
||||
static char const OptionsBTN [] = "OptionsBTN";
|
||||
static char const PrevPageBTN [] = "PrevPageBTN";
|
||||
static char const NextPageBTN [] = "NextPageBTN";
|
||||
static char const CloseBTN [] = "CloseBTN";
|
||||
static char const JournalBTN [] = "JournalBTN";
|
||||
static char const TopicsBTN [] = "TopicsBTN";
|
||||
static char const QuestsBTN [] = "QuestsBTN";
|
||||
static char const CancelBTN [] = "CancelBTN";
|
||||
static char const ShowAllBTN [] = "ShowAllBTN";
|
||||
static char const ShowActiveBTN [] = "ShowActiveBTN";
|
||||
static char const PageOneNum [] = "PageOneNum";
|
||||
static char const PageTwoNum [] = "PageTwoNum";
|
||||
static char const TopicsList [] = "TopicsList";
|
||||
static char const TopicsPage [] = "TopicsPage";
|
||||
static char const QuestsList [] = "QuestsList";
|
||||
static char const QuestsPage [] = "QuestsPage";
|
||||
static char const LeftBookPage [] = "LeftBookPage";
|
||||
static char const RightBookPage [] = "RightBookPage";
|
||||
static char const LeftTopicIndex [] = "LeftTopicIndex";
|
||||
static char const RightTopicIndex [] = "RightTopicIndex";
|
||||
|
||||
struct JournalWindowImpl : MWGui::WindowBase, MWGui::JournalBooks, MWGui::JournalWindow
|
||||
{
|
||||
int endLine;
|
||||
std::list<std::string> pages;
|
||||
struct DisplayState
|
||||
{
|
||||
unsigned int mPage;
|
||||
Book mBook;
|
||||
};
|
||||
|
||||
typedef std::stack <DisplayState> DisplayStateStack;
|
||||
|
||||
DisplayStateStack mStates;
|
||||
Book mTopicIndexBook;
|
||||
bool mQuestMode;
|
||||
bool mAllQuests;
|
||||
|
||||
template <typename T>
|
||||
T * getWidget (char const * name)
|
||||
{
|
||||
T * widget;
|
||||
WindowBase::getWidget (widget, name);
|
||||
return widget;
|
||||
}
|
||||
|
||||
template <typename value_type>
|
||||
void setText (char const * name, value_type const & value)
|
||||
{
|
||||
getWidget <MyGUI::TextBox> (name) ->
|
||||
setCaption (boost::lexical_cast <std::string> (value));
|
||||
}
|
||||
|
||||
void setVisible (char const * name, bool visible)
|
||||
{
|
||||
getWidget <MyGUI::Widget> (name) ->
|
||||
setVisible (visible);
|
||||
}
|
||||
|
||||
void adviseButtonClick (char const * name, void (JournalWindowImpl::*Handler) (MyGUI::Widget* _sender))
|
||||
{
|
||||
getWidget <MWGui::ImageButton> (name) ->
|
||||
eventMouseButtonClick += newDelegate(this, Handler);
|
||||
}
|
||||
|
||||
MWGui::BookPage* getPage (char const * name)
|
||||
{
|
||||
return getWidget <MWGui::BookPage> (name);
|
||||
}
|
||||
|
||||
JournalWindowImpl (MWGui::JournalViewModel::Ptr Model)
|
||||
: WindowBase("openmw_journal.layout"), JournalBooks (Model)
|
||||
{
|
||||
mMainWidget->setVisible(false);
|
||||
center();
|
||||
|
||||
adviseButtonClick (OptionsBTN, &JournalWindowImpl::notifyOptions );
|
||||
adviseButtonClick (PrevPageBTN, &JournalWindowImpl::notifyPrevPage );
|
||||
adviseButtonClick (NextPageBTN, &JournalWindowImpl::notifyNextPage );
|
||||
adviseButtonClick (CloseBTN, &JournalWindowImpl::notifyClose );
|
||||
adviseButtonClick (JournalBTN, &JournalWindowImpl::notifyJournal );
|
||||
|
||||
adviseButtonClick (TopicsBTN, &JournalWindowImpl::notifyTopics );
|
||||
adviseButtonClick (QuestsBTN, &JournalWindowImpl::notifyQuests );
|
||||
adviseButtonClick (CancelBTN, &JournalWindowImpl::notifyCancel );
|
||||
|
||||
adviseButtonClick (ShowAllBTN, &JournalWindowImpl::notifyShowAll );
|
||||
adviseButtonClick (ShowActiveBTN, &JournalWindowImpl::notifyShowActive);
|
||||
|
||||
{
|
||||
MWGui::BookPage::ClickCallback callback;
|
||||
|
||||
callback = boost::bind (&JournalWindowImpl::notifyTopicClicked, this, _1);
|
||||
|
||||
getPage (TopicsPage)->adviseLinkClicked (callback);
|
||||
getPage (LeftBookPage)->adviseLinkClicked (callback);
|
||||
getPage (RightBookPage)->adviseLinkClicked (callback);
|
||||
}
|
||||
|
||||
{
|
||||
MWGui::BookPage::ClickCallback callback;
|
||||
|
||||
callback = boost::bind (&JournalWindowImpl::notifyIndexLinkClicked, this, _1);
|
||||
|
||||
getPage (LeftTopicIndex)->adviseLinkClicked (callback);
|
||||
getPage (RightTopicIndex)->adviseLinkClicked (callback);
|
||||
}
|
||||
|
||||
{
|
||||
MWGui::BookPage::ClickCallback callback;
|
||||
|
||||
callback = boost::bind (&JournalWindowImpl::notifyQuestClicked, this, _1);
|
||||
|
||||
getPage (QuestsPage)->adviseLinkClicked (callback);
|
||||
}
|
||||
|
||||
mQuestMode = false;
|
||||
mAllQuests = false;
|
||||
}
|
||||
|
||||
void open()
|
||||
{
|
||||
mModel->load ();
|
||||
|
||||
setBookMode ();
|
||||
|
||||
/// \todo Wiping the whole book layout each time the journal is opened is probably too costly for a large journal (eg 300+ pages).
|
||||
/// There should be a way to keep the existing layout and append new entries to the end of it.
|
||||
/// However, that still leaves the problem of having to add links to previously unknown, but now known topics, so
|
||||
/// we maybe need to find another way to speed things up.
|
||||
Book journalBook;
|
||||
if (mModel->isEmpty ())
|
||||
journalBook = createEmptyJournalBook ();
|
||||
else
|
||||
journalBook = createJournalBook ();
|
||||
|
||||
pushBook (journalBook, 0);
|
||||
|
||||
// fast forward to the last page
|
||||
if (!mStates.empty ())
|
||||
{
|
||||
unsigned int & page = mStates.top ().mPage;
|
||||
page = mStates.top().mBook->pageCount()-1;
|
||||
if (page%2)
|
||||
--page;
|
||||
}
|
||||
updateShowingPages();
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
mModel->unload ();
|
||||
|
||||
getPage (LeftBookPage)->showPage (Book (), 0);
|
||||
getPage (RightBookPage)->showPage (Book (), 0);
|
||||
|
||||
while (!mStates.empty ())
|
||||
mStates.pop ();
|
||||
|
||||
mTopicIndexBook.reset ();
|
||||
}
|
||||
|
||||
void setVisible (bool newValue)
|
||||
{
|
||||
WindowBase::setVisible (newValue);
|
||||
}
|
||||
|
||||
void setBookMode ()
|
||||
{
|
||||
setVisible (OptionsBTN, true);
|
||||
setVisible (OptionsOverlay, false);
|
||||
|
||||
updateShowingPages ();
|
||||
updateCloseJournalButton ();
|
||||
}
|
||||
|
||||
void setOptionsMode ()
|
||||
{
|
||||
setVisible (OptionsBTN, false);
|
||||
setVisible (OptionsOverlay, true);
|
||||
|
||||
setVisible (PrevPageBTN, false);
|
||||
setVisible (NextPageBTN, false);
|
||||
setVisible (CloseBTN, false);
|
||||
setVisible (JournalBTN, false);
|
||||
|
||||
setVisible (TopicsList, false);
|
||||
setVisible (QuestsList, mQuestMode);
|
||||
setVisible (LeftTopicIndex, !mQuestMode);
|
||||
setVisible (RightTopicIndex, !mQuestMode);
|
||||
setVisible (ShowAllBTN, mQuestMode && !mAllQuests);
|
||||
setVisible (ShowActiveBTN, mQuestMode && mAllQuests);
|
||||
|
||||
//TODO: figure out how to make "options" page overlay book page
|
||||
// correctly, so that text may show underneath
|
||||
getPage (RightBookPage)->showPage (Book (), 0);
|
||||
}
|
||||
|
||||
void pushBook (Book book, unsigned int page)
|
||||
{
|
||||
DisplayState bs;
|
||||
bs.mPage = page;
|
||||
bs.mBook = book;
|
||||
mStates.push (bs);
|
||||
updateShowingPages ();
|
||||
updateCloseJournalButton ();
|
||||
}
|
||||
|
||||
void replaceBook (Book book, unsigned int page)
|
||||
{
|
||||
assert (!mStates.empty ());
|
||||
mStates.top ().mBook = book;
|
||||
mStates.top ().mPage = page;
|
||||
updateShowingPages ();
|
||||
}
|
||||
|
||||
void popBook ()
|
||||
{
|
||||
mStates.pop ();
|
||||
updateShowingPages ();
|
||||
updateCloseJournalButton ();
|
||||
}
|
||||
|
||||
void updateCloseJournalButton ()
|
||||
{
|
||||
setVisible (CloseBTN, mStates.size () < 2);
|
||||
setVisible (JournalBTN, mStates.size () >= 2);
|
||||
}
|
||||
|
||||
void updateShowingPages ()
|
||||
{
|
||||
Book book;
|
||||
unsigned int page;
|
||||
unsigned int relPages;
|
||||
|
||||
if (!mStates.empty ())
|
||||
{
|
||||
book = mStates.top ().mBook;
|
||||
page = mStates.top ().mPage;
|
||||
relPages = book->pageCount () - page;
|
||||
}
|
||||
else
|
||||
{
|
||||
page = 0;
|
||||
relPages = 0;
|
||||
}
|
||||
|
||||
setVisible (PrevPageBTN, page > 0);
|
||||
setVisible (NextPageBTN, relPages > 2);
|
||||
|
||||
setVisible (PageOneNum, relPages > 0);
|
||||
setVisible (PageTwoNum, relPages > 1);
|
||||
|
||||
getPage (LeftBookPage)->showPage ((relPages > 0) ? book : Book (), page+0);
|
||||
getPage (RightBookPage)->showPage ((relPages > 0) ? book : Book (), page+1);
|
||||
|
||||
setText (PageOneNum, page + 1);
|
||||
setText (PageTwoNum, page + 2);
|
||||
}
|
||||
|
||||
void notifyTopicClicked (intptr_t linkId)
|
||||
{
|
||||
Book topicBook = createTopicBook (linkId);
|
||||
|
||||
if (mStates.size () > 1)
|
||||
replaceBook (topicBook, 0);
|
||||
else
|
||||
pushBook (topicBook, 0);
|
||||
|
||||
setVisible (OptionsOverlay, false);
|
||||
setVisible (OptionsBTN, true);
|
||||
setVisible (JournalBTN, true);
|
||||
}
|
||||
|
||||
void notifyQuestClicked (intptr_t questId)
|
||||
{
|
||||
Book book = createQuestBook (questId);
|
||||
|
||||
if (mStates.size () > 1)
|
||||
replaceBook (book, 0);
|
||||
else
|
||||
pushBook (book, 0);
|
||||
|
||||
setVisible (OptionsOverlay, false);
|
||||
setVisible (OptionsBTN, true);
|
||||
setVisible (JournalBTN, true);
|
||||
}
|
||||
|
||||
void notifyOptions(MyGUI::Widget* _sender)
|
||||
{
|
||||
setOptionsMode ();
|
||||
|
||||
if (!mTopicIndexBook)
|
||||
mTopicIndexBook = createTopicIndexBook ();
|
||||
|
||||
getPage (LeftTopicIndex)->showPage (mTopicIndexBook, 0);
|
||||
getPage (RightTopicIndex)->showPage (mTopicIndexBook, 1);
|
||||
}
|
||||
|
||||
void notifyJournal(MyGUI::Widget* _sender)
|
||||
{
|
||||
assert (mStates.size () > 1);
|
||||
popBook ();
|
||||
}
|
||||
|
||||
void showList (char const * listId, char const * pageId, Book book)
|
||||
{
|
||||
std::pair <int, int> size = book->getSize ();
|
||||
|
||||
getPage (pageId)->showPage (book, 0);
|
||||
|
||||
getWidget <MyGUI::ScrollView> (listId)->setCanvasSize (size.first, size.second);
|
||||
}
|
||||
|
||||
void notifyIndexLinkClicked (MWGui::TypesetBook::InteractiveId character)
|
||||
{
|
||||
setVisible (LeftTopicIndex, false);
|
||||
setVisible (RightTopicIndex, false);
|
||||
setVisible (TopicsList, true);
|
||||
|
||||
showList (TopicsList, TopicsPage, createTopicIndexBook ((char)character));
|
||||
}
|
||||
|
||||
void notifyTopics(MyGUI::Widget* _sender)
|
||||
{
|
||||
mQuestMode = false;
|
||||
setVisible (LeftTopicIndex, true);
|
||||
setVisible (RightTopicIndex, true);
|
||||
setVisible (TopicsList, false);
|
||||
setVisible (QuestsList, false);
|
||||
setVisible (ShowAllBTN, false);
|
||||
setVisible (ShowActiveBTN, false);
|
||||
}
|
||||
|
||||
void notifyQuests(MyGUI::Widget* _sender)
|
||||
{
|
||||
mQuestMode = true;
|
||||
setVisible (LeftTopicIndex, false);
|
||||
setVisible (RightTopicIndex, false);
|
||||
setVisible (TopicsList, false);
|
||||
setVisible (QuestsList, true);
|
||||
setVisible (ShowAllBTN, !mAllQuests);
|
||||
setVisible (ShowActiveBTN, mAllQuests);
|
||||
|
||||
showList (QuestsList, QuestsPage, createQuestIndexBook (!mAllQuests));
|
||||
}
|
||||
|
||||
void notifyShowAll(MyGUI::Widget* _sender)
|
||||
{
|
||||
mAllQuests = true;
|
||||
setVisible (ShowAllBTN, !mAllQuests);
|
||||
setVisible (ShowActiveBTN, mAllQuests);
|
||||
showList (QuestsList, QuestsPage, createQuestIndexBook (!mAllQuests));
|
||||
}
|
||||
|
||||
void notifyShowActive(MyGUI::Widget* _sender)
|
||||
{
|
||||
mAllQuests = false;
|
||||
setVisible (ShowAllBTN, !mAllQuests);
|
||||
setVisible (ShowActiveBTN, mAllQuests);
|
||||
showList (QuestsList, QuestsPage, createQuestIndexBook (!mAllQuests));
|
||||
}
|
||||
|
||||
void notifyCancel(MyGUI::Widget* _sender)
|
||||
{
|
||||
setBookMode ();
|
||||
}
|
||||
|
||||
void notifyClose(MyGUI::Widget* _sender)
|
||||
{
|
||||
|
||||
MWBase::Environment::get().getWindowManager ()->popGuiMode ();
|
||||
}
|
||||
|
||||
void notifyNextPage(MyGUI::Widget* _sender)
|
||||
{
|
||||
if (!mStates.empty ())
|
||||
{
|
||||
unsigned int & page = mStates.top ().mPage;
|
||||
Book book = mStates.top ().mBook;
|
||||
|
||||
if (page < book->pageCount () - 2)
|
||||
{
|
||||
page += 2;
|
||||
updateShowingPages ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void notifyPrevPage(MyGUI::Widget* _sender)
|
||||
{
|
||||
if (!mStates.empty ())
|
||||
{
|
||||
unsigned int & page = mStates.top ().mPage;
|
||||
|
||||
if(page > 0)
|
||||
{
|
||||
page -= 2;
|
||||
updateShowingPages ();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
book formatText(std::string text,book mBook,int maxLine, int lineSize)
|
||||
// glue the implementation to the interface
|
||||
MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model)
|
||||
{
|
||||
//stringList.push_back("");
|
||||
|
||||
int cLineSize = 0;
|
||||
int cLine = mBook.endLine +1;
|
||||
std::string cString;
|
||||
|
||||
if(mBook.pages.empty())
|
||||
{
|
||||
cString = "";
|
||||
cLine = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cString = mBook.pages.back() + std::string("\n");
|
||||
mBook.pages.pop_back();
|
||||
}
|
||||
|
||||
//std::string::iterator wordBegin = text.begin();
|
||||
//std::string::iterator wordEnd;
|
||||
|
||||
std::string cText = text;
|
||||
|
||||
while(cText.length() != 0)
|
||||
{
|
||||
size_t firstSpace = cText.find_first_of(' ');
|
||||
if(firstSpace == std::string::npos)
|
||||
{
|
||||
cString = cString + cText;
|
||||
mBook.pages.push_back(cString);
|
||||
//TODO:finnish this
|
||||
break;
|
||||
}
|
||||
if(static_cast<int> (firstSpace) + cLineSize <= lineSize)
|
||||
{
|
||||
cLineSize = firstSpace + cLineSize;
|
||||
cString = cString + cText.substr(0,firstSpace +1);
|
||||
}
|
||||
else
|
||||
{
|
||||
cLineSize = firstSpace;
|
||||
if(cLine +1 <= maxLine)
|
||||
{
|
||||
cLine = cLine + 1;
|
||||
cString = cString + std::string("\n") + cText.substr(0,firstSpace +1);
|
||||
}
|
||||
else
|
||||
{
|
||||
cLine = 0;
|
||||
mBook.pages.push_back(cString);
|
||||
cString = cText.substr(0,firstSpace +1);
|
||||
}
|
||||
}
|
||||
//std::cout << cText << "\n";
|
||||
//std::cout << cText.length();
|
||||
cText = cText.substr(firstSpace +1,cText.length() - firstSpace -1);
|
||||
}
|
||||
mBook.endLine = cLine;
|
||||
return mBook;
|
||||
//std::string
|
||||
}
|
||||
|
||||
|
||||
MWGui::JournalWindow::JournalWindow ()
|
||||
: WindowBase("openmw_journal.layout")
|
||||
, mPageNumber(0)
|
||||
{
|
||||
mMainWidget->setVisible(false);
|
||||
//setCoord(0,0,498, 342);
|
||||
center();
|
||||
|
||||
getWidget(mLeftTextWidget, "LeftText");
|
||||
getWidget(mRightTextWidget, "RightText");
|
||||
getWidget(mPrevBtn, "PrevPageBTN");
|
||||
mPrevBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyPrevPage);
|
||||
getWidget(mNextBtn, "NextPageBTN");
|
||||
mNextBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyNextPage);
|
||||
//MyGUI::ItemBox* list = new MyGUI::ItemBox();
|
||||
//list->addItem("qaq","aqzazaz");
|
||||
//mScrollerWidget->addChildItem(list);
|
||||
//mScrollerWidget->addItem("dserzt",MyGUI::UString("fedgdfg"));
|
||||
//mEditWidget->addText("ljblsxdvdsfvgedfvdfvdkjfghldfjgn sdv,nhsxl;vvn lklksbvlksb lbsdflkbdSLKJGBLskdhbvl<kbvlqksbgkqsjhdvb");
|
||||
//mEditWidget->show();
|
||||
//mEditWidget->setEditStatic(true);
|
||||
mLeftTextWidget->addText("left texxxt ");
|
||||
mLeftTextWidget->setEditReadOnly(true);
|
||||
mRightTextWidget->setEditReadOnly(true);
|
||||
mRightTextWidget->setEditStatic(true);
|
||||
mLeftTextWidget->setEditStatic(true);
|
||||
mRightTextWidget->addText("Right texxt ");
|
||||
|
||||
//std::list<std::string> list = formatText("OpenMW rgh dsfg sqef srg ZT uzql n ZLIEHRF LQSJH GLOIjf qjfmj hslkdgn jlkdjhg qlr isgli shli uhs fiuh qksf cg ksjnf lkqsnbf ksbf sbfkl zbf kuyzflkj sbgdfkj zlfh ozhjfmo hzmfh lizuf rty qzt ezy tkyEZT RYYJ DG fgh is an open-source implementation of the game engine found in the game Morrowind. This is a dumb test text msodjbg smojg smoig fiiinnn");
|
||||
//std::list<std::string> list = formatText();
|
||||
//displayLeftText(list.front());
|
||||
}
|
||||
|
||||
void MWGui::JournalWindow::open()
|
||||
{
|
||||
mPageNumber = 0;
|
||||
if(MWBase::Environment::get().getJournal()->begin()!=MWBase::Environment::get().getJournal()->end())
|
||||
{
|
||||
book journal;
|
||||
journal.endLine = 0;
|
||||
|
||||
for(std::deque<MWDialogue::StampedJournalEntry>::const_iterator it = MWBase::Environment::get().getJournal()->begin();it!=MWBase::Environment::get().getJournal()->end();++it)
|
||||
{
|
||||
std::string a = it->getText(MWBase::Environment::get().getWorld()->getStore());
|
||||
journal = formatText(a,journal,10,17);
|
||||
journal.endLine = journal.endLine +1;
|
||||
journal.pages.back() = journal.pages.back() + std::string("\n");
|
||||
}
|
||||
//std::string a = MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore());
|
||||
//std::list<std::string> journal = formatText(a,10,20,1);
|
||||
bool left = true;
|
||||
for(std::list<std::string>::iterator it = journal.pages.begin(); it != journal.pages.end();++it)
|
||||
{
|
||||
if(left)
|
||||
{
|
||||
mLeftPages.push_back(*it);
|
||||
}
|
||||
else
|
||||
{
|
||||
mRightPages.push_back(*it);
|
||||
}
|
||||
left = !left;
|
||||
}
|
||||
if(!left) mRightPages.push_back("");
|
||||
|
||||
mPageNumber = mLeftPages.size()-1;
|
||||
displayLeftText(mLeftPages[mPageNumber]);
|
||||
displayRightText(mRightPages[mPageNumber]);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//std::cout << MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore());
|
||||
}
|
||||
}
|
||||
|
||||
void MWGui::JournalWindow::displayLeftText(std::string text)
|
||||
{
|
||||
mLeftTextWidget->eraseText(0,mLeftTextWidget->getTextLength());
|
||||
mLeftTextWidget->addText(text);
|
||||
}
|
||||
|
||||
void MWGui::JournalWindow::displayRightText(std::string text)
|
||||
{
|
||||
mRightTextWidget->eraseText(0,mRightTextWidget->getTextLength());
|
||||
mRightTextWidget->addText(text);
|
||||
}
|
||||
|
||||
|
||||
void MWGui::JournalWindow::notifyNextPage(MyGUI::Widget* _sender)
|
||||
{
|
||||
if(mPageNumber < int(mLeftPages.size())-1)
|
||||
{
|
||||
std::string nextSound = "book page2";
|
||||
MWBase::Environment::get().getSoundManager()->playSound (nextSound, 1.0, 1.0);
|
||||
mPageNumber = mPageNumber + 1;
|
||||
displayLeftText(mLeftPages[mPageNumber]);
|
||||
displayRightText(mRightPages[mPageNumber]);
|
||||
}
|
||||
}
|
||||
|
||||
void MWGui::JournalWindow::notifyPrevPage(MyGUI::Widget* _sender)
|
||||
{
|
||||
if(mPageNumber > 0)
|
||||
{
|
||||
std::string prevSound = "book page";
|
||||
MWBase::Environment::get().getSoundManager()->playSound (prevSound, 1.0, 1.0);
|
||||
mPageNumber = mPageNumber - 1;
|
||||
displayLeftText(mLeftPages[mPageNumber]);
|
||||
displayRightText(mRightPages[mPageNumber]);
|
||||
}
|
||||
return new JournalWindowImpl (Model);
|
||||
}
|
||||
|
@ -1,39 +1,26 @@
|
||||
#ifndef MWGUI_JOURNAL_H
|
||||
#define MWGUI_JOURNAL_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "windowbase.hpp"
|
||||
#include "imagebutton.hpp"
|
||||
namespace MWBase { class WindowManager; }
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class JournalWindow : public WindowBase
|
||||
struct JournalViewModel;
|
||||
|
||||
struct JournalWindow
|
||||
{
|
||||
public:
|
||||
JournalWindow();
|
||||
virtual void open();
|
||||
/// construct a new instance of the one JournalWindow implementation
|
||||
static JournalWindow * create (boost::shared_ptr <JournalViewModel> Model);
|
||||
|
||||
private:
|
||||
void displayLeftText(std::string text);
|
||||
void displayRightText(std::string text);
|
||||
/// destroy this instance of the JournalWindow implementation
|
||||
virtual ~JournalWindow () {};
|
||||
|
||||
|
||||
/**
|
||||
*Called when next/prev button is used.
|
||||
*/
|
||||
void notifyNextPage(MyGUI::Widget* _sender);
|
||||
void notifyPrevPage(MyGUI::Widget* _sender);
|
||||
|
||||
MyGUI::EditBox* mLeftTextWidget;
|
||||
MyGUI::EditBox* mRightTextWidget;
|
||||
MWGui::ImageButton* mPrevBtn;
|
||||
MWGui::ImageButton* mNextBtn;
|
||||
std::vector<std::string> mLeftPages;
|
||||
std::vector<std::string> mRightPages;
|
||||
int mPageNumber; //store the number of the current left page
|
||||
/// show/hide the journal window
|
||||
virtual void setVisible (bool newValue) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
0
apps/openmw/mwgui/keywordsearch.cpp
Normal file
0
apps/openmw/mwgui/keywordsearch.cpp
Normal file
199
apps/openmw/mwgui/keywordsearch.hpp
Normal file
199
apps/openmw/mwgui/keywordsearch.hpp
Normal file
@ -0,0 +1,199 @@
|
||||
#ifndef MWGUI_KEYWORDSEARCH_H
|
||||
#define MWGUI_KEYWORDSEARCH_H
|
||||
|
||||
#include <map>
|
||||
#include <locale>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <algorithm> // std::reverse
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
template <typename string_t, typename value_t>
|
||||
class KeywordSearch
|
||||
{
|
||||
public:
|
||||
|
||||
typedef typename string_t::const_iterator Point;
|
||||
|
||||
struct Match
|
||||
{
|
||||
Point mBeg;
|
||||
Point mEnd;
|
||||
value_t mValue;
|
||||
};
|
||||
|
||||
void seed (string_t keyword, value_t value)
|
||||
{
|
||||
seed_impl (/*std::move*/ (keyword), /*std::move*/ (value), 0, mRoot);
|
||||
}
|
||||
|
||||
void clear ()
|
||||
{
|
||||
mRoot.mChildren.clear ();
|
||||
mRoot.mKeyword.clear ();
|
||||
}
|
||||
|
||||
bool containsKeyword (string_t keyword, value_t& value)
|
||||
{
|
||||
typename Entry::childen_t::iterator current;
|
||||
typename Entry::childen_t::iterator next;
|
||||
|
||||
current = mRoot.mChildren.find (std::tolower (*keyword.begin(), mLocale));
|
||||
if (current == mRoot.mChildren.end())
|
||||
return false;
|
||||
else if (current->second.mKeyword.size() && Misc::StringUtils::ciEqual(current->second.mKeyword, keyword))
|
||||
{
|
||||
value = current->second.mValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (Point i = ++keyword.begin(); i != keyword.end(); ++i)
|
||||
{
|
||||
next = current->second.mChildren.find(std::tolower (*i, mLocale));
|
||||
if (next == current->second.mChildren.end())
|
||||
return false;
|
||||
if (Misc::StringUtils::ciEqual(next->second.mKeyword, keyword))
|
||||
{
|
||||
value = next->second.mValue;
|
||||
return true;
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool search (Point beg, Point end, Match & match)
|
||||
{
|
||||
for (Point i = beg; i != end; ++i)
|
||||
{
|
||||
// check first character
|
||||
typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (std::tolower (*i, mLocale));
|
||||
|
||||
// no match, on to next character
|
||||
if (candidate == mRoot.mChildren.end ())
|
||||
continue;
|
||||
|
||||
// see how far the match goes
|
||||
Point j = i;
|
||||
|
||||
// some keywords might be longer variations of other keywords, so we definitely need a list of candidates
|
||||
// the first element in the pair is length of the match, i.e. depth from the first character on
|
||||
std::vector< typename std::pair<int, typename Entry::childen_t::iterator> > candidates;
|
||||
|
||||
while ((j + 1) != end)
|
||||
{
|
||||
typename Entry::childen_t::iterator next = candidate->second.mChildren.find (std::tolower (*++j, mLocale));
|
||||
|
||||
if (next == candidate->second.mChildren.end ())
|
||||
{
|
||||
if (candidate->second.mKeyword.size() > 0)
|
||||
candidates.push_back(std::make_pair((j-i), candidate));
|
||||
break;
|
||||
}
|
||||
|
||||
candidate = next;
|
||||
|
||||
if (candidate->second.mKeyword.size() > 0)
|
||||
candidates.push_back(std::make_pair((j-i), candidate));
|
||||
}
|
||||
|
||||
if (!candidates.size())
|
||||
continue; // didn't match enough to disambiguate, on to next character
|
||||
|
||||
// shorter candidates will be added to the vector first. however, we want to check against longer candidates first
|
||||
std::reverse(candidates.begin(), candidates.end());
|
||||
|
||||
for (typename std::vector< std::pair<int, typename Entry::childen_t::iterator> >::iterator it = candidates.begin();
|
||||
it != candidates.end(); ++it)
|
||||
{
|
||||
candidate = it->second;
|
||||
// try to match the rest of the keyword
|
||||
Point k = i + it->first;
|
||||
typename string_t::const_iterator t = candidate->second.mKeyword.begin () + (k - i);
|
||||
|
||||
|
||||
while (k != end && t != candidate->second.mKeyword.end ())
|
||||
{
|
||||
if (std::tolower (*k, mLocale) != std::tolower (*t, mLocale))
|
||||
break;
|
||||
|
||||
++k, ++t;
|
||||
}
|
||||
|
||||
// didn't match full keyword, try the next candidate
|
||||
if (t != candidate->second.mKeyword.end ())
|
||||
continue;
|
||||
|
||||
// we did it, report the good news
|
||||
match.mValue = candidate->second.mValue;
|
||||
match.mBeg = i;
|
||||
match.mEnd = k;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// no match in range, report the bad news
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct Entry
|
||||
{
|
||||
typedef std::map <wchar_t, Entry> childen_t;
|
||||
|
||||
string_t mKeyword;
|
||||
value_t mValue;
|
||||
childen_t mChildren;
|
||||
};
|
||||
|
||||
void seed_impl (string_t keyword, value_t value, size_t depth, Entry & entry)
|
||||
{
|
||||
int ch = tolower (keyword.at (depth), mLocale);
|
||||
|
||||
typename Entry::childen_t::iterator j = entry.mChildren.find (ch);
|
||||
|
||||
if (j == entry.mChildren.end ())
|
||||
{
|
||||
entry.mChildren [ch].mValue = /*std::move*/ (value);
|
||||
entry.mChildren [ch].mKeyword = /*std::move*/ (keyword);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (j->second.mKeyword.size () > 0)
|
||||
{
|
||||
if (keyword == j->second.mKeyword)
|
||||
throw std::runtime_error ("duplicate keyword inserted");
|
||||
|
||||
value_t pushValue = /*std::move*/ (j->second.mValue);
|
||||
string_t pushKeyword = /*std::move*/ (j->second.mKeyword);
|
||||
|
||||
if (depth >= pushKeyword.size ())
|
||||
throw std::runtime_error ("unexpected");
|
||||
|
||||
if (depth+1 < pushKeyword.size())
|
||||
{
|
||||
seed_impl (/*std::move*/ (pushKeyword), /*std::move*/ (pushValue), depth+1, j->second);
|
||||
j->second.mKeyword.clear ();
|
||||
}
|
||||
}
|
||||
if (depth+1 == keyword.size())
|
||||
j->second.mKeyword = value;
|
||||
else // depth+1 < keyword.size()
|
||||
seed_impl (/*std::move*/ (keyword), /*std::move*/ (value), depth+1, j->second);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Entry mRoot;
|
||||
std::locale mLocale;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -22,6 +22,7 @@ namespace MWGui
|
||||
, mLastRenderTime(0.f)
|
||||
, mLastWallpaperChangeTime(0.f)
|
||||
, mFirstLoad(true)
|
||||
, mTotalRefsLoading(0)
|
||||
{
|
||||
getWidget(mLoadingText, "LoadingText");
|
||||
getWidget(mProgressBar, "ProgressBar");
|
||||
|
@ -13,6 +13,7 @@ namespace MWGui
|
||||
// defines
|
||||
mMessageBoxSpeed = 0.1;
|
||||
mInterMessageBoxe = NULL;
|
||||
mStaticMessageBox = NULL;
|
||||
}
|
||||
|
||||
void MessageBoxManager::onFrame (float frameDuration)
|
||||
@ -68,11 +69,14 @@ namespace MWGui
|
||||
}
|
||||
}
|
||||
|
||||
void MessageBoxManager::createMessageBox (const std::string& message)
|
||||
void MessageBoxManager::createMessageBox (const std::string& message, bool stat)
|
||||
{
|
||||
MessageBox *box = new MessageBox(*this, message);
|
||||
|
||||
removeMessageBox(message.length()*mMessageBoxSpeed, box);
|
||||
if(stat)
|
||||
mStaticMessageBox = box;
|
||||
else
|
||||
removeMessageBox(message.length()*mMessageBoxSpeed, box);
|
||||
|
||||
mMessageBoxes.push_back(box);
|
||||
std::vector<MessageBox*>::iterator it;
|
||||
@ -90,6 +94,12 @@ namespace MWGui
|
||||
}
|
||||
}
|
||||
|
||||
void MessageBoxManager::removeStaticMessageBox ()
|
||||
{
|
||||
removeMessageBox(mStaticMessageBox);
|
||||
mStaticMessageBox = NULL;
|
||||
}
|
||||
|
||||
bool MessageBoxManager::createInteractiveMessageBox (const std::string& message, const std::vector<std::string>& buttons)
|
||||
{
|
||||
if(mInterMessageBoxe != NULL) {
|
||||
|
@ -31,7 +31,8 @@ namespace MWGui
|
||||
public:
|
||||
MessageBoxManager ();
|
||||
void onFrame (float frameDuration);
|
||||
void createMessageBox (const std::string& message);
|
||||
void createMessageBox (const std::string& message, bool stat = false);
|
||||
void removeStaticMessageBox ();
|
||||
bool createInteractiveMessageBox (const std::string& message, const std::vector<std::string>& buttons);
|
||||
bool isInteractiveMessageBox ();
|
||||
|
||||
@ -52,6 +53,7 @@ namespace MWGui
|
||||
private:
|
||||
std::vector<MessageBox*> mMessageBoxes;
|
||||
InteractiveMessageBox* mInterMessageBoxe;
|
||||
MessageBox* mStaticMessageBox;
|
||||
std::vector<MessageBoxManagerTimer> mTimers;
|
||||
float mMessageBoxSpeed;
|
||||
};
|
||||
|
@ -39,7 +39,7 @@ namespace MWGui
|
||||
MWWorld::LiveCellRef<ESM::Book> *ref = mScroll.get<ESM::Book>();
|
||||
|
||||
BookTextParser parser;
|
||||
MyGUI::IntSize size = parser.parse(ref->mBase->mText, mTextView, 390);
|
||||
MyGUI::IntSize size = parser.parseScroll(ref->mBase->mText, mTextView, 390);
|
||||
|
||||
if (size.height > mTextView->getSize().height)
|
||||
mTextView->setCanvasSize(MyGUI::IntSize(410, size.height));
|
||||
|
@ -551,6 +551,8 @@ namespace MWGui
|
||||
while (mControlsBox->getChildCount())
|
||||
MyGUI::Gui::getInstance().destroyWidget(mControlsBox->getChildAt(0));
|
||||
|
||||
MWBase::Environment::get().getWindowManager ()->removeStaticMessageBox();
|
||||
|
||||
std::vector<int> actions = MWBase::Environment::get().getInputManager()->getActionSorting ();
|
||||
|
||||
const int h = 18;
|
||||
@ -585,7 +587,7 @@ namespace MWGui
|
||||
|
||||
static_cast<MyGUI::Button*>(_sender)->setCaptionWithReplacing("#{sNone}");
|
||||
|
||||
MWBase::Environment::get().getWindowManager ()->messageBox ("#{sControlsMenu3}");
|
||||
MWBase::Environment::get().getWindowManager ()->staticMessageBox ("#{sControlsMenu3}");
|
||||
MWBase::Environment::get().getWindowManager ()->disallowMouse();
|
||||
|
||||
MWBase::Environment::get().getInputManager ()->enableDetectingBindingMode (actionId);
|
||||
|
@ -7,9 +7,9 @@
|
||||
|
||||
#include "console.hpp"
|
||||
#include "journalwindow.hpp"
|
||||
#include "journalviewmodel.hpp"
|
||||
#include "charactercreation.hpp"
|
||||
#include "dialogue.hpp"
|
||||
#include "dialoguehistory.hpp"
|
||||
#include "statswindow.hpp"
|
||||
#include "messagebox.hpp"
|
||||
#include "tooltips.hpp"
|
||||
@ -38,6 +38,7 @@
|
||||
#include "soulgemdialog.hpp"
|
||||
#include "companionwindow.hpp"
|
||||
#include "inventorywindow.hpp"
|
||||
#include "bookpage.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
@ -106,7 +107,6 @@ namespace MWGui
|
||||
mGui = mGuiManager->getGui();
|
||||
|
||||
//Register own widgets with MyGUI
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<DialogueHistory>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWSkill>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWAttribute>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWSpell>("Widget");
|
||||
@ -122,6 +122,7 @@ namespace MWGui
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::ImageButton>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::ExposedWindow>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWScrollView>("Widget");
|
||||
BookPage::registerMyGUIComponents ();
|
||||
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<ResourceImageSetPointerFix>("Resource", "ResourceImageSetPointer");
|
||||
MyGUI::ResourceManager::getInstance().load("core.xml");
|
||||
@ -145,7 +146,7 @@ namespace MWGui
|
||||
mMap = new MapWindow(cacheDir);
|
||||
mStatsWindow = new StatsWindow();
|
||||
mConsole = new Console(w,h, consoleOnlyScripts);
|
||||
mJournal = new JournalWindow();
|
||||
mJournal = JournalWindow::create(JournalViewModel::create ());
|
||||
mMessageBoxManager = new MessageBoxManager();
|
||||
mInventoryWindow = new InventoryWindow(mDragAndDrop);
|
||||
mTradeWindow = new TradeWindow();
|
||||
@ -600,6 +601,16 @@ namespace MWGui
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::staticMessageBox(const std::string& message)
|
||||
{
|
||||
mMessageBoxManager->createMessageBox(message, true);
|
||||
}
|
||||
|
||||
void WindowManager::removeStaticMessageBox()
|
||||
{
|
||||
mMessageBoxManager->removeStaticMessageBox();
|
||||
}
|
||||
|
||||
void WindowManager::enterPressed ()
|
||||
{
|
||||
mMessageBoxManager->enterPressed();
|
||||
|
@ -192,6 +192,8 @@ namespace MWGui
|
||||
virtual void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted.
|
||||
|
||||
virtual void messageBox (const std::string& message, const std::vector<std::string>& buttons = std::vector<std::string>());
|
||||
virtual void staticMessageBox(const std::string& message);
|
||||
virtual void removeStaticMessageBox();
|
||||
virtual void enterPressed ();
|
||||
virtual int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)
|
||||
|
||||
|
@ -905,6 +905,10 @@ namespace MWInput
|
||||
void InputManager::keyBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
|
||||
, OIS::KeyCode key, ICS::Control::ControlChangingDirection direction)
|
||||
{
|
||||
//Disallow binding escape key, and unassigned keys
|
||||
if(key==OIS::KC_ESCAPE || key==OIS::KC_UNASSIGNED)
|
||||
return
|
||||
|
||||
clearAllBindings(control);
|
||||
ICS::DetectingBindingListener::keyBindingDetected (ICS, control, key, direction);
|
||||
MWBase::Environment::get().getWindowManager ()->notifyInputActionBound ();
|
||||
|
@ -48,7 +48,7 @@ namespace MWMechanics
|
||||
{
|
||||
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||
//check if actor is near the border of an inactive cell. If so, disable aitravel.
|
||||
if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000))
|
||||
if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
@ -58,7 +58,7 @@ namespace MWMechanics
|
||||
{
|
||||
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||
//check if actor is near the border of an inactive cell. If so, disable aitravel.
|
||||
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000))
|
||||
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
|
@ -152,6 +152,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||
, mMovingAnim(false)
|
||||
, mSecondsOfRunning(0)
|
||||
, mSecondsOfSwimming(0)
|
||||
, mLooping(false)
|
||||
{
|
||||
if(!mAnimation)
|
||||
return;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <OgreCompositionPass.h>
|
||||
#include <OgreHardwarePixelBuffer.h>
|
||||
#include <OgreControllerManager.h>
|
||||
#include <OgreMeshManager.h>
|
||||
|
||||
#include <extern/shiny/Main/Factory.hpp>
|
||||
#include <extern/shiny/Platforms/Ogre/OgrePlatform.hpp>
|
||||
@ -120,13 +121,11 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b
|
||||
MaterialManager::getSingleton().setDefaultTextureFiltering(tfo);
|
||||
MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 );
|
||||
|
||||
//ResourceGroupManager::getSingleton ().declareResource ("GlobalMap.png", "Texture", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||
Ogre::TextureManager::getSingleton().setMemoryBudget(126*1024*1024);
|
||||
Ogre::MeshManager::getSingleton().setMemoryBudget(64*1024*1024);
|
||||
|
||||
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
|
||||
|
||||
// causes light flicker in opengl when moving..
|
||||
//mRendering.getScene()->setCameraRelativeRendering(true);
|
||||
|
||||
// disable unsupported effects
|
||||
if (!Settings::Manager::getBool("shaders", "Objects"))
|
||||
Settings::Manager::setBool("enabled", "Shadows", false);
|
||||
@ -236,6 +235,7 @@ void RenderingManager::toggleWater()
|
||||
|
||||
void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store)
|
||||
{
|
||||
sh::Factory::getInstance().unloadUnreferencedMaterials();
|
||||
mObjects.buildStaticGeometry (*store);
|
||||
mDebugging->cellAdded(store);
|
||||
if (store->mCell->isExterior())
|
||||
@ -306,7 +306,6 @@ void RenderingManager::update (float duration, bool paused)
|
||||
|
||||
int blind = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Blind)).mMagnitude;
|
||||
mRendering.getFader()->setFactor(1.f-(blind / 100.f));
|
||||
|
||||
setAmbientMode();
|
||||
|
||||
// player position
|
||||
|
@ -49,6 +49,7 @@ namespace MWRender
|
||||
TerrainMaterial::Profile::Profile(Ogre::TerrainMaterialGenerator* parent, const Ogre::String& name, const Ogre::String& desc)
|
||||
: Ogre::TerrainMaterialGenerator::Profile(parent, name, desc)
|
||||
, mGlobalColourMap(false)
|
||||
, mMaterial(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,9 @@ namespace MWRender {
|
||||
{
|
||||
public:
|
||||
Reflection(Ogre::SceneManager* sceneManager)
|
||||
: mSceneMgr(sceneManager) {}
|
||||
: mSceneMgr(sceneManager)
|
||||
, mIsUnderwater(false)
|
||||
{}
|
||||
virtual ~Reflection() {}
|
||||
|
||||
virtual void setHeight (float height) {}
|
||||
|
@ -292,19 +292,25 @@ namespace MWScript
|
||||
|
||||
std::string factionId = MWWorld::Class::get (mReference).getNpcStats (mReference).getFactionRanks().begin()->first;
|
||||
|
||||
std::map<std::string, int> ranks = MWWorld::Class::get (player).getNpcStats (player).getFactionRanks();
|
||||
std::map<std::string, int>::const_iterator it = ranks.begin();
|
||||
|
||||
const MWWorld::ESMStore &store = world->getStore();
|
||||
const ESM::Faction *faction = store.get<ESM::Faction>().find(factionId);
|
||||
|
||||
if(it->second < 0 || it->second > 9)
|
||||
return "";
|
||||
std::map<std::string, int> ranks = MWWorld::Class::get (player).getNpcStats (player).getFactionRanks();
|
||||
|
||||
if(it->second <= 8) // If player is at max rank, there is no next rank
|
||||
return faction->mRanks[it->second + 1];
|
||||
if (ranks.size())
|
||||
{
|
||||
std::map<std::string, int>::const_iterator it = ranks.begin();
|
||||
|
||||
if(it->second < -1 || it->second > 9)
|
||||
return "";
|
||||
|
||||
if(it->second <= 8) // If player is at max rank, there is no next rank
|
||||
return faction->mRanks[it->second + 1];
|
||||
else
|
||||
return faction->mRanks[it->second];
|
||||
}
|
||||
else
|
||||
return faction->mRanks[it->second];
|
||||
return faction->mRanks[0];
|
||||
}
|
||||
|
||||
int InterpreterContext::getPCBounty() const
|
||||
|
@ -141,7 +141,7 @@ namespace Compiler
|
||||
|
||||
if (mState==SetMemberVarState)
|
||||
{
|
||||
mMemberName = Misc::StringUtils::lowerCase (name);
|
||||
mMemberName = name;
|
||||
char type = getContext().getMemberType (mMemberName, mName);
|
||||
|
||||
if (type!=' ')
|
||||
|
@ -23,7 +23,6 @@ namespace Interpreter{
|
||||
}
|
||||
|
||||
std::string fixDefinesReal(std::string text, char eschar, bool isBook, Context& context){
|
||||
|
||||
unsigned int start = 0;
|
||||
std::ostringstream retval;
|
||||
for(unsigned int i = 0; i < text.length(); i++){
|
||||
|
116
components/misc/utf8stream.hpp
Normal file
116
components/misc/utf8stream.hpp
Normal file
@ -0,0 +1,116 @@
|
||||
#ifndef MISC_UTF8ITER_HPP
|
||||
#define MISC_UTF8ITER_HPP
|
||||
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
class Utf8Stream
|
||||
{
|
||||
public:
|
||||
|
||||
typedef uint32_t UnicodeChar;
|
||||
typedef unsigned char const * Point;
|
||||
|
||||
//static const unicode_char sBadChar = 0xFFFFFFFF; gcc can't handle this
|
||||
static UnicodeChar sBadChar () { return UnicodeChar (0xFFFFFFFF); }
|
||||
|
||||
Utf8Stream (Point begin, Point end) :
|
||||
cur (begin), nxt (begin), end (end)
|
||||
{
|
||||
}
|
||||
|
||||
Utf8Stream (std::pair <Point, Point> range) :
|
||||
cur (range.first), nxt (range.first), end (range.second)
|
||||
{
|
||||
}
|
||||
|
||||
bool eof () const
|
||||
{
|
||||
return cur == end;
|
||||
}
|
||||
|
||||
Point current () const
|
||||
{
|
||||
return cur;
|
||||
}
|
||||
|
||||
UnicodeChar peek ()
|
||||
{
|
||||
if (cur == nxt)
|
||||
next ();
|
||||
return val;
|
||||
}
|
||||
|
||||
UnicodeChar consume ()
|
||||
{
|
||||
if (cur == nxt)
|
||||
next ();
|
||||
cur = nxt;
|
||||
return val;
|
||||
}
|
||||
|
||||
static std::pair <UnicodeChar, Point> decode (Point cur, Point end)
|
||||
{
|
||||
if ((*cur & 0x80) == 0)
|
||||
{
|
||||
UnicodeChar chr = *cur++;
|
||||
|
||||
return std::make_pair (chr, cur);
|
||||
}
|
||||
|
||||
int octets;
|
||||
UnicodeChar chr;
|
||||
|
||||
boost::tie (octets, chr) = octet_count (*cur++);
|
||||
|
||||
if (octets > 5)
|
||||
return std::make_pair (sBadChar(), cur);
|
||||
|
||||
Point eoc = cur + octets;
|
||||
|
||||
if (eoc > end)
|
||||
return std::make_pair (sBadChar(), cur);
|
||||
|
||||
while (cur != eoc)
|
||||
{
|
||||
if ((*cur & 0xC0) != 0x80) // check continuation mark
|
||||
return std::make_pair (sBadChar(), cur);;
|
||||
|
||||
chr = (chr << 6) | UnicodeChar ((*cur++) & 0x3F);
|
||||
}
|
||||
|
||||
return std::make_pair (chr, cur);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static std::pair <int, UnicodeChar> octet_count (unsigned char octet)
|
||||
{
|
||||
int octets;
|
||||
|
||||
unsigned char mark = 0xC0;
|
||||
unsigned char mask = 0xE0;
|
||||
|
||||
for (octets = 1; octets <= 5; ++octets)
|
||||
{
|
||||
if ((octet & mask) == mark)
|
||||
break;
|
||||
|
||||
mark = (mark >> 1) | 0x80;
|
||||
mask = (mask >> 1) | 0x80;
|
||||
}
|
||||
|
||||
return std::make_pair (octets, octet & ~mask);
|
||||
}
|
||||
|
||||
void next ()
|
||||
{
|
||||
boost::tie (val, nxt) = decode (nxt, end);
|
||||
}
|
||||
|
||||
Point cur;
|
||||
Point nxt;
|
||||
Point end;
|
||||
UnicodeChar val;
|
||||
};
|
||||
|
||||
#endif
|
@ -52,6 +52,7 @@ Paul McElroy (Greendogo)
|
||||
Pieter van der Kloet (pvdk)
|
||||
Radu-Marius Popovici (rpopovici)
|
||||
Roman Melnik (Kromgart)
|
||||
Roman Proskuryakov (humbug)
|
||||
Sandy Carter (bwrsandman)
|
||||
Sebastian Wick (swick)
|
||||
Sergey Shambir
|
||||
|
8
extern/oics/tinyxml.cpp
vendored
8
extern/oics/tinyxml.cpp
vendored
@ -706,9 +706,9 @@ void TiXmlElement::SetDoubleAttribute( const char * name, double val )
|
||||
{
|
||||
char buf[256];
|
||||
#if defined(TIXML_SNPRINTF)
|
||||
TIXML_SNPRINTF( buf, sizeof(buf), "%f", val );
|
||||
TIXML_SNPRINTF( buf, sizeof(buf), "%f", val );
|
||||
#else
|
||||
sprintf( buf, "%f", val );
|
||||
sprintf( buf, "%f", val );
|
||||
#endif
|
||||
SetAttribute( name, buf );
|
||||
}
|
||||
@ -1266,9 +1266,9 @@ void TiXmlAttribute::SetDoubleValue( double _value )
|
||||
{
|
||||
char buf [256];
|
||||
#if defined(TIXML_SNPRINTF)
|
||||
TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value);
|
||||
TIXML_SNPRINTF( buf, sizeof(buf), "%f", _value);
|
||||
#else
|
||||
sprintf (buf, "%lf", _value);
|
||||
sprintf (buf, "%f", _value);
|
||||
#endif
|
||||
SetValue (buf);
|
||||
}
|
||||
|
16
extern/shiny/CMakeLists.txt
vendored
16
extern/shiny/CMakeLists.txt
vendored
@ -9,8 +9,6 @@ set(SHINY_LIBRARY "shiny")
|
||||
set(SHINY_OGREPLATFORM_LIBRARY "shiny.OgrePlatform")
|
||||
|
||||
# Sources
|
||||
file(GLOB SOURCE_FILES Main/*.cpp )
|
||||
|
||||
set(SOURCE_FILES
|
||||
Main/Factory.cpp
|
||||
Main/MaterialInstance.cpp
|
||||
@ -57,12 +55,20 @@ file(GLOB OGRE_PLATFORM_SOURCE_FILES Platforms/Ogre/*.cpp)
|
||||
|
||||
add_library(${SHINY_LIBRARY} STATIC ${SOURCE_FILES})
|
||||
|
||||
set(SHINY_LIBRARIES ${SHINY_LIBRARY})
|
||||
|
||||
if (SHINY_BUILD_OGRE_PLATFORM)
|
||||
add_library(${SHINY_OGREPLATFORM_LIBRARY} STATIC ${OGRE_PLATFORM_SOURCE_FILES})
|
||||
set(SHINY_LIBRARIES ${SHINY_LIBRARIES} ${SHINY_OGREPLATFORM_LIBRARY})
|
||||
endif()
|
||||
|
||||
set(SHINY_LIBRARY ${SHINY_LIBRARY} PARENT_SCOPE)
|
||||
|
||||
if (DEFINED SHINY_BUILD_MATERIAL_EDITOR)
|
||||
add_subdirectory(Editor)
|
||||
|
||||
set(SHINY_BUILD_EDITOR_FLAG ${SHINY_BUILD_EDITOR_FLAG} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
link_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(SHINY_LIBRARY ${SHINY_LIBRARY} PARENT_SCOPE)
|
||||
set(SHINY_OGREPLATFORM_LIBRARY ${SHINY_OGREPLATFORM_LIBRARY} PARENT_SCOPE)
|
||||
set(SHINY_LIBRARIES ${SHINY_LIBRARIES} PARENT_SCOPE)
|
||||
|
2
extern/shiny/Docs/Configurations.dox
vendored
2
extern/shiny/Docs/Configurations.dox
vendored
@ -21,7 +21,7 @@
|
||||
}
|
||||
\endcode
|
||||
|
||||
\note You may also create configurations using sh::Factory::registerConfiguration.
|
||||
\note You may also create configurations using sh::Factory::createConfiguration.
|
||||
|
||||
The active Configuration is controlled by the active material scheme in Ogre. So, in order to use the configuration "reflection_targets" for your reflection renders, simply call
|
||||
\code
|
||||
|
195
extern/shiny/Editor/Actions.cpp
vendored
Normal file
195
extern/shiny/Editor/Actions.cpp
vendored
Normal file
@ -0,0 +1,195 @@
|
||||
#include "Actions.hpp"
|
||||
|
||||
#include "../Main/Factory.hpp"
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
void ActionDeleteMaterial::execute()
|
||||
{
|
||||
sh::Factory::getInstance().destroyMaterialInstance(mName);
|
||||
}
|
||||
|
||||
void ActionCloneMaterial::execute()
|
||||
{
|
||||
sh::MaterialInstance* sourceMaterial = sh::Factory::getInstance().getMaterialInstance(mSourceName);
|
||||
std::string sourceMaterialParent = static_cast<sh::MaterialInstance*>(sourceMaterial->getParent())->getName();
|
||||
sh::MaterialInstance* material = sh::Factory::getInstance().createMaterialInstance(
|
||||
mDestName, sourceMaterialParent);
|
||||
sourceMaterial->copyAll(material, sourceMaterial, false);
|
||||
|
||||
material->setSourceFile(sourceMaterial->getSourceFile());
|
||||
}
|
||||
|
||||
void ActionSaveAll::execute()
|
||||
{
|
||||
sh::Factory::getInstance().saveAll();
|
||||
}
|
||||
|
||||
void ActionChangeGlobalSetting::execute()
|
||||
{
|
||||
sh::Factory::getInstance().setGlobalSetting(mName, mNewValue);
|
||||
}
|
||||
|
||||
void ActionCreateConfiguration::execute()
|
||||
{
|
||||
sh::Configuration newConfiguration;
|
||||
sh::Factory::getInstance().createConfiguration(mName);
|
||||
}
|
||||
|
||||
void ActionDeleteConfiguration::execute()
|
||||
{
|
||||
sh::Factory::getInstance().destroyConfiguration(mName);
|
||||
}
|
||||
|
||||
void ActionChangeConfiguration::execute()
|
||||
{
|
||||
sh::Configuration* c = sh::Factory::getInstance().getConfiguration(mName);
|
||||
c->setProperty(mKey, sh::makeProperty(new sh::StringValue(mValue)));
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
void ActionDeleteConfigurationProperty::execute()
|
||||
{
|
||||
sh::Configuration* c = sh::Factory::getInstance().getConfiguration(mName);
|
||||
c->deleteProperty(mKey);
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
void ActionSetMaterialProperty::execute()
|
||||
{
|
||||
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
m->setProperty(mKey, sh::makeProperty(mValue));
|
||||
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
void ActionDeleteMaterialProperty::execute()
|
||||
{
|
||||
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
m->deleteProperty(mKey);
|
||||
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
void ActionCreatePass::execute()
|
||||
{
|
||||
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
m->createPass();
|
||||
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
void ActionDeletePass::execute()
|
||||
{
|
||||
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
m->deletePass(mPassIndex);
|
||||
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
void ActionSetPassProperty::execute()
|
||||
{
|
||||
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
assert (m->getPasses()->size() > mPassIndex);
|
||||
m->getPasses()->at(mPassIndex).setProperty (mKey, sh::makeProperty(mValue));
|
||||
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
void ActionDeletePassProperty::execute()
|
||||
{
|
||||
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
assert (m->getPasses()->size() > mPassIndex);
|
||||
m->getPasses()->at(mPassIndex).deleteProperty(mKey);
|
||||
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
void ActionSetShaderProperty::execute()
|
||||
{
|
||||
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
assert (m->getPasses()->size() > mPassIndex);
|
||||
m->getPasses()->at(mPassIndex).mShaderProperties.setProperty (mKey, sh::makeProperty(mValue));
|
||||
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
void ActionDeleteShaderProperty::execute()
|
||||
{
|
||||
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
assert (m->getPasses()->size() > mPassIndex);
|
||||
m->getPasses()->at(mPassIndex).mShaderProperties.deleteProperty (mKey);
|
||||
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
void ActionSetTextureProperty::execute()
|
||||
{
|
||||
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
assert (m->getPasses()->size() > mPassIndex);
|
||||
assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex);
|
||||
m->getPasses()->at(mPassIndex).mTexUnits.at(mTextureIndex).setProperty(mKey, sh::makeProperty(mValue));
|
||||
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
void ActionDeleteTextureProperty::execute()
|
||||
{
|
||||
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
assert (m->getPasses()->size() > mPassIndex);
|
||||
assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex);
|
||||
m->getPasses()->at(mPassIndex).mTexUnits.at(mTextureIndex).deleteProperty(mKey);
|
||||
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
void ActionCreateTextureUnit::execute()
|
||||
{
|
||||
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
assert (m->getPasses()->size() > mPassIndex);
|
||||
m->getPasses()->at(mPassIndex).createTextureUnit(mTexUnitName);
|
||||
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
void ActionDeleteTextureUnit::execute()
|
||||
{
|
||||
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
assert (m->getPasses()->size() > mPassIndex);
|
||||
assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex);
|
||||
|
||||
m->getPasses()->at(mPassIndex).mTexUnits.erase(m->getPasses()->at(mPassIndex).mTexUnits.begin() + mTextureIndex);
|
||||
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
void ActionMoveTextureUnit::execute()
|
||||
{
|
||||
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
assert (m->getPasses()->size() > mPassIndex);
|
||||
assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex);
|
||||
if (!mMoveUp)
|
||||
assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex+1);
|
||||
|
||||
std::vector<MaterialInstanceTextureUnit> textures = m->getPasses()->at(mPassIndex).mTexUnits;
|
||||
if (mMoveUp)
|
||||
std::swap(textures[mTextureIndex-1], textures[mTextureIndex]);
|
||||
else
|
||||
std::swap(textures[mTextureIndex+1], textures[mTextureIndex]);
|
||||
m->getPasses()->at(mPassIndex).mTexUnits = textures;
|
||||
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
void ActionChangeTextureUnitName::execute()
|
||||
{
|
||||
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
assert (m->getPasses()->size() > mPassIndex);
|
||||
assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex);
|
||||
|
||||
m->getPasses()->at(mPassIndex).mTexUnits[mTextureIndex].setName(mTexUnitName);
|
||||
|
||||
sh::Factory::getInstance().notifyConfigurationChanged();
|
||||
}
|
||||
}
|
307
extern/shiny/Editor/Actions.hpp
vendored
Normal file
307
extern/shiny/Editor/Actions.hpp
vendored
Normal file
@ -0,0 +1,307 @@
|
||||
#ifndef SH_ACTIONS_H
|
||||
#define SH_ACTIONS_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
class Action
|
||||
{
|
||||
public:
|
||||
virtual void execute() = 0;
|
||||
virtual ~Action();
|
||||
};
|
||||
|
||||
class ActionDeleteMaterial : public Action
|
||||
{
|
||||
public:
|
||||
ActionDeleteMaterial(const std::string& name)
|
||||
: mName(name) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
};
|
||||
|
||||
class ActionCloneMaterial : public Action
|
||||
{
|
||||
public:
|
||||
ActionCloneMaterial(const std::string& sourceName, const std::string& destName)
|
||||
: mSourceName(sourceName), mDestName(destName) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mSourceName;
|
||||
std::string mDestName;
|
||||
};
|
||||
|
||||
class ActionSaveAll : public Action
|
||||
{
|
||||
public:
|
||||
virtual void execute();
|
||||
};
|
||||
|
||||
class ActionChangeGlobalSetting : public Action
|
||||
{
|
||||
public:
|
||||
ActionChangeGlobalSetting(const std::string& name, const std::string& newValue)
|
||||
: mName(name), mNewValue(newValue) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
std::string mNewValue;
|
||||
};
|
||||
|
||||
// configuration
|
||||
|
||||
class ActionCreateConfiguration : public Action
|
||||
{
|
||||
public:
|
||||
ActionCreateConfiguration(const std::string& name)
|
||||
: mName(name) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
|
||||
};
|
||||
|
||||
class ActionDeleteConfiguration : public Action
|
||||
{
|
||||
public:
|
||||
ActionDeleteConfiguration(const std::string& name)
|
||||
: mName(name) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
|
||||
};
|
||||
|
||||
class ActionChangeConfiguration : public Action
|
||||
{
|
||||
public:
|
||||
ActionChangeConfiguration (const std::string& name, const std::string& key, const std::string& value)
|
||||
: mName(name), mKey(key), mValue(value) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
std::string mKey;
|
||||
std::string mValue;
|
||||
};
|
||||
|
||||
class ActionDeleteConfigurationProperty : public Action
|
||||
{
|
||||
public:
|
||||
ActionDeleteConfigurationProperty (const std::string& name, const std::string& key)
|
||||
: mName(name), mKey(key) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
std::string mKey;
|
||||
};
|
||||
|
||||
// material
|
||||
|
||||
class ActionSetMaterialProperty : public Action
|
||||
{
|
||||
public:
|
||||
ActionSetMaterialProperty (const std::string& name, const std::string& key, const std::string& value)
|
||||
: mName(name), mKey(key), mValue(value) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
std::string mKey;
|
||||
std::string mValue;
|
||||
};
|
||||
|
||||
class ActionDeleteMaterialProperty : public Action
|
||||
{
|
||||
public:
|
||||
ActionDeleteMaterialProperty (const std::string& name, const std::string& key)
|
||||
: mName(name), mKey(key) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
std::string mKey;
|
||||
};
|
||||
|
||||
// pass
|
||||
|
||||
class ActionCreatePass : public Action
|
||||
{
|
||||
public:
|
||||
ActionCreatePass (const std::string& name)
|
||||
: mName(name) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
};
|
||||
|
||||
class ActionDeletePass : public Action
|
||||
{
|
||||
public:
|
||||
ActionDeletePass (const std::string& name, int passIndex)
|
||||
: mName(name), mPassIndex(passIndex) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
int mPassIndex;
|
||||
};
|
||||
|
||||
class ActionSetPassProperty : public Action
|
||||
{
|
||||
public:
|
||||
ActionSetPassProperty (const std::string& name, int passIndex, const std::string& key, const std::string& value)
|
||||
: mName(name), mPassIndex(passIndex), mKey(key), mValue(value) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
int mPassIndex;
|
||||
std::string mKey;
|
||||
std::string mValue;
|
||||
};
|
||||
|
||||
class ActionDeletePassProperty : public Action
|
||||
{
|
||||
public:
|
||||
ActionDeletePassProperty (const std::string& name, int passIndex, const std::string& key)
|
||||
: mName(name), mPassIndex(passIndex), mKey(key) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
int mPassIndex;
|
||||
std::string mKey;
|
||||
};
|
||||
|
||||
// shader
|
||||
|
||||
class ActionSetShaderProperty : public Action
|
||||
{
|
||||
public:
|
||||
ActionSetShaderProperty (const std::string& name, int passIndex, const std::string& key, const std::string& value)
|
||||
: mName(name), mPassIndex(passIndex), mKey(key), mValue(value) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
int mPassIndex;
|
||||
std::string mKey;
|
||||
std::string mValue;
|
||||
};
|
||||
|
||||
class ActionDeleteShaderProperty : public Action
|
||||
{
|
||||
public:
|
||||
ActionDeleteShaderProperty (const std::string& name, int passIndex, const std::string& key)
|
||||
: mName(name), mPassIndex(passIndex), mKey(key) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
int mPassIndex;
|
||||
std::string mKey;
|
||||
};
|
||||
|
||||
// texture unit
|
||||
|
||||
class ActionChangeTextureUnitName : public Action
|
||||
{
|
||||
public:
|
||||
ActionChangeTextureUnitName (const std::string& name, int passIndex, int textureIndex, const std::string& texUnitName)
|
||||
: mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mTexUnitName(texUnitName) {}
|
||||
|
||||
virtual void execute();
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
int mPassIndex;
|
||||
int mTextureIndex;
|
||||
std::string mTexUnitName;
|
||||
};
|
||||
|
||||
class ActionCreateTextureUnit : public Action
|
||||
{
|
||||
public:
|
||||
ActionCreateTextureUnit (const std::string& name, int passIndex, const std::string& texUnitName)
|
||||
: mName(name), mPassIndex(passIndex), mTexUnitName(texUnitName) {}
|
||||
|
||||
virtual void execute();
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
int mPassIndex;
|
||||
std::string mTexUnitName;
|
||||
};
|
||||
|
||||
class ActionDeleteTextureUnit : public Action
|
||||
{
|
||||
public:
|
||||
ActionDeleteTextureUnit (const std::string& name, int passIndex, int textureIndex)
|
||||
: mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex) {}
|
||||
|
||||
virtual void execute();
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
int mPassIndex;
|
||||
int mTextureIndex;
|
||||
};
|
||||
|
||||
class ActionMoveTextureUnit : public Action
|
||||
{
|
||||
public:
|
||||
ActionMoveTextureUnit (const std::string& name, int passIndex, int textureIndex, bool moveUp)
|
||||
: mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mMoveUp(moveUp) {}
|
||||
|
||||
virtual void execute();
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
int mPassIndex;
|
||||
int mTextureIndex;
|
||||
bool mMoveUp;
|
||||
};
|
||||
|
||||
class ActionSetTextureProperty : public Action
|
||||
{
|
||||
public:
|
||||
ActionSetTextureProperty (const std::string& name, int passIndex, int textureIndex, const std::string& key, const std::string& value)
|
||||
: mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mKey(key), mValue(value) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
int mPassIndex;
|
||||
int mTextureIndex;
|
||||
std::string mKey;
|
||||
std::string mValue;
|
||||
};
|
||||
|
||||
class ActionDeleteTextureProperty : public Action
|
||||
{
|
||||
public:
|
||||
ActionDeleteTextureProperty (const std::string& name, int passIndex, int textureIndex, const std::string& key)
|
||||
: mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mKey(key) {}
|
||||
|
||||
virtual void execute();
|
||||
private:
|
||||
std::string mName;
|
||||
int mPassIndex;
|
||||
int mTextureIndex;
|
||||
std::string mKey;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
31
extern/shiny/Editor/AddPropertyDialog.cpp
vendored
Normal file
31
extern/shiny/Editor/AddPropertyDialog.cpp
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
#include "AddPropertyDialog.hpp"
|
||||
#include "ui_addpropertydialog.h"
|
||||
|
||||
AddPropertyDialog::AddPropertyDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::AddPropertyDialog)
|
||||
, mType(0)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
connect(ui->buttonBox, SIGNAL(accepted()),
|
||||
this, SLOT(accepted()));
|
||||
connect(ui->buttonBox, SIGNAL(rejected()),
|
||||
this, SLOT(rejected()));
|
||||
}
|
||||
|
||||
void AddPropertyDialog::accepted()
|
||||
{
|
||||
mName = ui->lineEdit->text();
|
||||
mType = ui->comboBox->currentIndex();
|
||||
}
|
||||
|
||||
void AddPropertyDialog::rejected()
|
||||
{
|
||||
mName = "";
|
||||
}
|
||||
|
||||
AddPropertyDialog::~AddPropertyDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
22
extern/shiny/Editor/AddPropertyDialog.h
vendored
Normal file
22
extern/shiny/Editor/AddPropertyDialog.h
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef ADDPROPERTYDIALOG_H
|
||||
#define ADDPROPERTYDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class AddPropertyDialog;
|
||||
}
|
||||
|
||||
class AddPropertyDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AddPropertyDialog(QWidget *parent = 0);
|
||||
~AddPropertyDialog();
|
||||
|
||||
private:
|
||||
Ui::AddPropertyDialog *ui;
|
||||
};
|
||||
|
||||
#endif // ADDPROPERTYDIALOG_H
|
29
extern/shiny/Editor/AddPropertyDialog.hpp
vendored
Normal file
29
extern/shiny/Editor/AddPropertyDialog.hpp
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef ADDPROPERTYDIALOG_H
|
||||
#define ADDPROPERTYDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class AddPropertyDialog;
|
||||
}
|
||||
|
||||
class AddPropertyDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AddPropertyDialog(QWidget *parent = 0);
|
||||
~AddPropertyDialog();
|
||||
|
||||
int mType;
|
||||
QString mName;
|
||||
|
||||
public slots:
|
||||
void accepted();
|
||||
void rejected();
|
||||
|
||||
private:
|
||||
Ui::AddPropertyDialog *ui;
|
||||
};
|
||||
|
||||
#endif // ADDPROPERTYDIALOG_H
|
61
extern/shiny/Editor/CMakeLists.txt
vendored
Normal file
61
extern/shiny/Editor/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
set(SHINY_EDITOR_LIBRARY "shiny.Editor")
|
||||
|
||||
find_package(Qt4)
|
||||
|
||||
if (QT_FOUND)
|
||||
|
||||
add_definitions(-DSHINY_BUILD_MATERIAL_EDITOR=1)
|
||||
set (SHINY_BUILD_EDITOR_FLAG -DSHINY_BUILD_MATERIAL_EDITOR=1 PARENT_SCOPE)
|
||||
|
||||
set(QT_USE_QTGUI 1)
|
||||
|
||||
# Headers that must be preprocessed
|
||||
set(SHINY_EDITOR_HEADER_MOC
|
||||
MainWindow.hpp
|
||||
NewMaterialDialog.hpp
|
||||
AddPropertyDialog.hpp
|
||||
PropertySortModel.hpp
|
||||
)
|
||||
|
||||
set(SHINY_EDITOR_UI
|
||||
mainwindow.ui
|
||||
newmaterialdialog.ui
|
||||
addpropertydialog.ui
|
||||
)
|
||||
|
||||
QT4_WRAP_CPP(MOC_SRCS ${SHINY_EDITOR_HEADER_MOC})
|
||||
QT4_WRAP_UI(UI_HDRS ${SHINY_EDITOR_UI})
|
||||
|
||||
set(SOURCE_FILES
|
||||
NewMaterialDialog.cpp
|
||||
AddPropertyDialog.cpp
|
||||
ColoredTabWidget.hpp
|
||||
MainWindow.cpp
|
||||
Editor.cpp
|
||||
Actions.cpp
|
||||
Query.cpp
|
||||
PropertySortModel.cpp
|
||||
${SHINY_EDITOR_UI} # Just to have them in the IDE's file explorer
|
||||
)
|
||||
|
||||
include(${QT_USE_FILE})
|
||||
|
||||
set (CMAKE_INCLUDE_CURRENT_DIR "true")
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_library(${SHINY_EDITOR_LIBRARY} STATIC ${SOURCE_FILES} ${MOC_SRCS} ${UI_HDRS})
|
||||
|
||||
set(SHINY_LIBRARIES ${SHINY_LIBRARIES}
|
||||
${SHINY_EDITOR_LIBRARY}
|
||||
${QT_LIBRARIES}
|
||||
)
|
||||
set(SHINY_LIBRARIES ${SHINY_LIBRARIES} PARENT_SCOPE)
|
||||
|
||||
else (QT_FOUND)
|
||||
|
||||
add_definitions(-DSHINY_BUILD_MATERIAL_EDITOR=0)
|
||||
set (SHINY_BUILD_EDITOR_FLAG -DSHINY_BUILD_MATERIAL_EDITOR=0 PARENT_SCOPE)
|
||||
message(STATUS "QT4 was not found. You will not be able to use the material editor.")
|
||||
|
||||
endif(QT_FOUND)
|
24
extern/shiny/Editor/ColoredTabWidget.hpp
vendored
Normal file
24
extern/shiny/Editor/ColoredTabWidget.hpp
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef SHINY_EDITOR_COLOREDTABWIDGET_H
|
||||
#define SHINY_EDITOR_COLOREDTABWIDGET_H
|
||||
|
||||
#include <QTabWidget>
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
/// Makes tabBar() public to allow changing tab title colors.
|
||||
class ColoredTabWidget : public QTabWidget
|
||||
{
|
||||
public:
|
||||
ColoredTabWidget(QWidget* parent = 0)
|
||||
: QTabWidget(parent) {}
|
||||
|
||||
QTabBar* tabBar()
|
||||
{
|
||||
return QTabWidget::tabBar();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
117
extern/shiny/Editor/Editor.cpp
vendored
Normal file
117
extern/shiny/Editor/Editor.cpp
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
#include "Editor.hpp"
|
||||
|
||||
|
||||
#include <QApplication>
|
||||
#include <QTimer>
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include "../Main/Factory.hpp"
|
||||
|
||||
#include "MainWindow.hpp"
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
Editor::Editor()
|
||||
: mMainWindow(NULL)
|
||||
, mApplication(NULL)
|
||||
, mInitialized(false)
|
||||
, mThread(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Editor::~Editor()
|
||||
{
|
||||
if (mMainWindow)
|
||||
mMainWindow->mRequestExit = true;
|
||||
|
||||
if (mThread)
|
||||
mThread->join();
|
||||
delete mThread;
|
||||
}
|
||||
|
||||
void Editor::show()
|
||||
{
|
||||
if (!mInitialized)
|
||||
{
|
||||
mInitialized = true;
|
||||
|
||||
mThread = new boost::thread(boost::bind(&Editor::runThread, this));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mMainWindow)
|
||||
mMainWindow->mRequestShowWindow = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::runThread()
|
||||
{
|
||||
int argc = 0;
|
||||
char** argv = NULL;
|
||||
mApplication = new QApplication(argc, argv);
|
||||
mApplication->setQuitOnLastWindowClosed(false);
|
||||
mMainWindow = new MainWindow();
|
||||
mMainWindow->mSync = &mSync;
|
||||
mMainWindow->show();
|
||||
|
||||
mApplication->exec();
|
||||
|
||||
delete mApplication;
|
||||
}
|
||||
|
||||
void Editor::update()
|
||||
{
|
||||
sh::Factory::getInstance().doMonitorShaderFiles();
|
||||
|
||||
if (!mMainWindow)
|
||||
return;
|
||||
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mSync.mActionMutex);
|
||||
|
||||
// execute pending actions
|
||||
while (mMainWindow->mActionQueue.size())
|
||||
{
|
||||
Action* action = mMainWindow->mActionQueue.front();
|
||||
action->execute();
|
||||
delete action;
|
||||
mMainWindow->mActionQueue.pop();
|
||||
}
|
||||
}
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mSync.mQueryMutex);
|
||||
|
||||
// execute pending queries
|
||||
for (std::vector<Query*>::iterator it = mMainWindow->mQueries.begin(); it != mMainWindow->mQueries.end(); ++it)
|
||||
{
|
||||
Query* query = *it;
|
||||
if (!query->mDone)
|
||||
query->execute();
|
||||
}
|
||||
}
|
||||
|
||||
boost::mutex::scoped_lock lock2(mSync.mUpdateMutex);
|
||||
|
||||
// update the list of materials
|
||||
mMainWindow->mState.mMaterialList.clear();
|
||||
sh::Factory::getInstance().listMaterials(mMainWindow->mState.mMaterialList);
|
||||
|
||||
// update global settings
|
||||
mMainWindow->mState.mGlobalSettingsMap.clear();
|
||||
sh::Factory::getInstance().listGlobalSettings(mMainWindow->mState.mGlobalSettingsMap);
|
||||
|
||||
// update configuration list
|
||||
mMainWindow->mState.mConfigurationList.clear();
|
||||
sh::Factory::getInstance().listConfigurationNames(mMainWindow->mState.mConfigurationList);
|
||||
|
||||
// update shader list
|
||||
mMainWindow->mState.mShaderSets.clear();
|
||||
sh::Factory::getInstance().listShaderSets(mMainWindow->mState.mShaderSets);
|
||||
|
||||
mMainWindow->mState.mErrors += sh::Factory::getInstance().getErrorLog();
|
||||
}
|
||||
|
||||
}
|
73
extern/shiny/Editor/Editor.hpp
vendored
Normal file
73
extern/shiny/Editor/Editor.hpp
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
#ifndef SH_EDITOR_H
|
||||
#define SH_EDITOR_H
|
||||
|
||||
#if SHINY_BUILD_MATERIAL_EDITOR
|
||||
class QApplication;
|
||||
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class thread;
|
||||
}
|
||||
|
||||
namespace sh
|
||||
{
|
||||
class MainWindow;
|
||||
|
||||
struct SynchronizationState
|
||||
{
|
||||
boost::mutex mUpdateMutex;
|
||||
boost::mutex mActionMutex;
|
||||
boost::mutex mQueryMutex;
|
||||
};
|
||||
|
||||
class Editor
|
||||
{
|
||||
public:
|
||||
|
||||
Editor();
|
||||
~Editor();
|
||||
|
||||
void show();
|
||||
void update();
|
||||
|
||||
|
||||
private:
|
||||
bool mInitialized;
|
||||
|
||||
MainWindow* mMainWindow;
|
||||
QApplication* mApplication;
|
||||
|
||||
SynchronizationState mSync;
|
||||
|
||||
boost::thread* mThread;
|
||||
|
||||
void runThread();
|
||||
|
||||
void processShowWindow();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Dummy implementation, so that the user's code does not have to be polluted with #ifdefs
|
||||
namespace sh
|
||||
{
|
||||
|
||||
class Editor
|
||||
{
|
||||
public:
|
||||
Editor() {}
|
||||
~Editor() {}
|
||||
void show() {}
|
||||
void update() {}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
950
extern/shiny/Editor/MainWindow.cpp
vendored
Normal file
950
extern/shiny/Editor/MainWindow.cpp
vendored
Normal file
@ -0,0 +1,950 @@
|
||||
#include "MainWindow.hpp"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QTimer>
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "Editor.hpp"
|
||||
#include "ColoredTabWidget.hpp"
|
||||
#include "AddPropertyDialog.hpp"
|
||||
|
||||
sh::MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
, mRequestShowWindow(false)
|
||||
, mRequestExit(false)
|
||||
, mIgnoreGlobalSettingChange(false)
|
||||
, mIgnoreConfigurationChange(false)
|
||||
, mIgnoreMaterialChange(false)
|
||||
, mIgnoreMaterialPropertyChange(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
QTimer *timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(onIdle()));
|
||||
timer->start(50);
|
||||
|
||||
QList<int> sizes;
|
||||
sizes << 250;
|
||||
sizes << 550;
|
||||
ui->splitter->setSizes(sizes);
|
||||
|
||||
mMaterialModel = new QStringListModel(this);
|
||||
|
||||
mMaterialProxyModel = new QSortFilterProxyModel(this);
|
||||
mMaterialProxyModel->setSourceModel(mMaterialModel);
|
||||
mMaterialProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
mMaterialProxyModel->setDynamicSortFilter(true);
|
||||
mMaterialProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
|
||||
ui->materialList->setModel(mMaterialProxyModel);
|
||||
ui->materialList->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
ui->materialList->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
ui->materialList->setAlternatingRowColors(true);
|
||||
|
||||
connect(ui->materialList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
|
||||
this, SLOT(onMaterialSelectionChanged(QModelIndex,QModelIndex)));
|
||||
|
||||
mMaterialPropertyModel = new QStandardItemModel(0, 2, this);
|
||||
mMaterialPropertyModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name")));
|
||||
mMaterialPropertyModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value")));
|
||||
connect(mMaterialPropertyModel, SIGNAL(itemChanged(QStandardItem*)),
|
||||
this, SLOT(onMaterialPropertyChanged(QStandardItem*)));
|
||||
|
||||
mMaterialSortModel = new PropertySortModel(this);
|
||||
mMaterialSortModel->setSourceModel(mMaterialPropertyModel);
|
||||
mMaterialSortModel->setDynamicSortFilter(true);
|
||||
mMaterialSortModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
|
||||
ui->materialView->setModel(mMaterialSortModel);
|
||||
ui->materialView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
ui->materialView->setAlternatingRowColors(true);
|
||||
ui->materialView->setSortingEnabled(true);
|
||||
connect(ui->materialView, SIGNAL(customContextMenuRequested(QPoint)),
|
||||
this, SLOT(onContextMenuRequested(QPoint)));
|
||||
|
||||
mGlobalSettingsModel = new QStandardItemModel(0, 2, this);
|
||||
mGlobalSettingsModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name")));
|
||||
mGlobalSettingsModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value")));
|
||||
connect(mGlobalSettingsModel, SIGNAL(itemChanged(QStandardItem*)),
|
||||
this, SLOT(onGlobalSettingChanged(QStandardItem*)));
|
||||
|
||||
ui->globalSettingsView->setModel(mGlobalSettingsModel);
|
||||
ui->globalSettingsView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
|
||||
ui->globalSettingsView->verticalHeader()->hide();
|
||||
ui->globalSettingsView->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
|
||||
ui->globalSettingsView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
|
||||
ui->configurationList->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
ui->configurationList->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
connect(ui->configurationList, SIGNAL(currentTextChanged(QString)),
|
||||
this, SLOT(onConfigurationSelectionChanged(QString)));
|
||||
|
||||
mConfigurationModel = new QStandardItemModel(0, 2, this);
|
||||
mConfigurationModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name")));
|
||||
mConfigurationModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value")));
|
||||
connect(mConfigurationModel, SIGNAL(itemChanged(QStandardItem*)),
|
||||
this, SLOT(onConfigurationChanged(QStandardItem*)));
|
||||
|
||||
ui->configurationView->setModel(mConfigurationModel);
|
||||
ui->configurationView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
|
||||
ui->configurationView->verticalHeader()->hide();
|
||||
ui->configurationView->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
|
||||
ui->configurationView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
}
|
||||
|
||||
sh::MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void sh::MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
this->hide();
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void sh::MainWindow::onIdle()
|
||||
{
|
||||
if (mRequestShowWindow)
|
||||
{
|
||||
mRequestShowWindow = false;
|
||||
show();
|
||||
}
|
||||
|
||||
if (mRequestExit)
|
||||
{
|
||||
QApplication::exit();
|
||||
return;
|
||||
}
|
||||
|
||||
boost::mutex::scoped_lock lock(mSync->mUpdateMutex);
|
||||
|
||||
|
||||
mIgnoreMaterialChange = true;
|
||||
QString selected;
|
||||
|
||||
QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex();
|
||||
if (selectedIndex.isValid())
|
||||
selected = mMaterialModel->data(selectedIndex, Qt::DisplayRole).toString();
|
||||
|
||||
QStringList list;
|
||||
|
||||
for (std::vector<std::string>::const_iterator it = mState.mMaterialList.begin(); it != mState.mMaterialList.end(); ++it)
|
||||
{
|
||||
list.push_back(QString::fromStdString(*it));
|
||||
}
|
||||
|
||||
if (mMaterialModel->stringList() != list)
|
||||
{
|
||||
mMaterialModel->setStringList(list);
|
||||
|
||||
// quick hack to keep our selection when the model has changed
|
||||
if (!selected.isEmpty())
|
||||
for (int i=0; i<mMaterialModel->rowCount(); ++i)
|
||||
{
|
||||
const QModelIndex& index = mMaterialModel->index(i,0);
|
||||
if (mMaterialModel->data(index, Qt::DisplayRole).toString() == selected)
|
||||
{
|
||||
ui->materialList->setCurrentIndex(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mIgnoreMaterialChange = false;
|
||||
|
||||
mIgnoreGlobalSettingChange = true;
|
||||
for (std::map<std::string, std::string>::const_iterator it = mState.mGlobalSettingsMap.begin();
|
||||
it != mState.mGlobalSettingsMap.end(); ++it)
|
||||
{
|
||||
QList<QStandardItem *> list = mGlobalSettingsModel->findItems(QString::fromStdString(it->first));
|
||||
if (!list.empty()) // item was already there
|
||||
{
|
||||
// if it changed, set the value column
|
||||
if (mGlobalSettingsModel->data(mGlobalSettingsModel->index(list.front()->row(), 1)).toString()
|
||||
!= QString::fromStdString(it->second))
|
||||
{
|
||||
mGlobalSettingsModel->setItem(list.front()->row(), 1, new QStandardItem(QString::fromStdString(it->second)));
|
||||
}
|
||||
}
|
||||
else // item wasn't there; insert new row
|
||||
{
|
||||
QList<QStandardItem*> toAdd;
|
||||
QStandardItem* name = new QStandardItem(QString::fromStdString(it->first));
|
||||
name->setFlags(name->flags() &= ~Qt::ItemIsEditable);
|
||||
QStandardItem* value = new QStandardItem(QString::fromStdString(it->second));
|
||||
toAdd.push_back(name);
|
||||
toAdd.push_back(value);
|
||||
mGlobalSettingsModel->appendRow(toAdd);
|
||||
}
|
||||
}
|
||||
mIgnoreGlobalSettingChange = false;
|
||||
|
||||
|
||||
mIgnoreConfigurationChange = true;
|
||||
QList<QListWidgetItem*> selected_ = ui->configurationList->selectedItems();
|
||||
QString selectedStr;
|
||||
if (selected_.size())
|
||||
selectedStr = selected_.front()->text();
|
||||
|
||||
ui->configurationList->clear();
|
||||
|
||||
for (std::vector<std::string>::const_iterator it = mState.mConfigurationList.begin(); it != mState.mConfigurationList.end(); ++it)
|
||||
ui->configurationList->addItem(QString::fromStdString(*it));
|
||||
|
||||
if (!selectedStr.isEmpty())
|
||||
for (int i=0; i<ui->configurationList->count(); ++i)
|
||||
{
|
||||
if (ui->configurationList->item(i)->text() == selectedStr)
|
||||
{
|
||||
ui->configurationList->setCurrentItem(ui->configurationList->item(i), QItemSelectionModel::ClearAndSelect);
|
||||
}
|
||||
}
|
||||
|
||||
mIgnoreConfigurationChange = false;
|
||||
|
||||
if (!mState.mErrors.empty())
|
||||
{
|
||||
ui->errorLog->append(QString::fromStdString(mState.mErrors));
|
||||
mState.mErrors = "";
|
||||
QColor color = ui->tabWidget->palette().color(QPalette::Normal, QPalette::Link);
|
||||
ui->tabWidget->tabBar()->setTabTextColor(3, color);
|
||||
}
|
||||
|
||||
|
||||
// process query results
|
||||
boost::mutex::scoped_lock lock2(mSync->mQueryMutex);
|
||||
for (std::vector<Query*>::iterator it = mQueries.begin(); it != mQueries.end();)
|
||||
{
|
||||
if ((*it)->mDone)
|
||||
{
|
||||
if (typeid(**it) == typeid(ConfigurationQuery))
|
||||
buildConfigurationModel(static_cast<ConfigurationQuery*>(*it));
|
||||
else if (typeid(**it) == typeid(MaterialQuery))
|
||||
buildMaterialModel(static_cast<MaterialQuery*>(*it));
|
||||
else if (typeid(**it) == typeid(MaterialPropertyQuery))
|
||||
{
|
||||
MaterialPropertyQuery* q = static_cast<MaterialPropertyQuery*>(*it);
|
||||
mIgnoreMaterialPropertyChange = true;
|
||||
if (getSelectedMaterial().toStdString() == q->mName)
|
||||
{
|
||||
for (int i=0; i<mMaterialPropertyModel->rowCount(); ++i)
|
||||
{
|
||||
if (mMaterialPropertyModel->item(i,0)->text() == QString::fromStdString(q->mPropertyName))
|
||||
{
|
||||
mMaterialPropertyModel->item(i,1)->setText(QString::fromStdString(q->mValue));
|
||||
if (mMaterialPropertyModel->item(i,1)->isCheckable())
|
||||
mMaterialPropertyModel->item(i,1)->setCheckState ((q->mValue == "true")
|
||||
? Qt::Checked : Qt::Unchecked);
|
||||
}
|
||||
}
|
||||
}
|
||||
mIgnoreMaterialPropertyChange = false;
|
||||
}
|
||||
|
||||
delete *it;
|
||||
it = mQueries.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void sh::MainWindow::onMaterialSelectionChanged (const QModelIndex & current, const QModelIndex & previous)
|
||||
{
|
||||
if (mIgnoreMaterialChange)
|
||||
return;
|
||||
|
||||
QString name = getSelectedMaterial();
|
||||
if (!name.isEmpty())
|
||||
requestQuery(new sh::MaterialQuery(name.toStdString()));
|
||||
}
|
||||
|
||||
QString sh::MainWindow::getSelectedMaterial()
|
||||
{
|
||||
QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex();
|
||||
if (!selectedIndex.isValid())
|
||||
return QString("");
|
||||
|
||||
return mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString();
|
||||
}
|
||||
|
||||
void sh::MainWindow::onConfigurationSelectionChanged (const QString& current)
|
||||
{
|
||||
if (mIgnoreConfigurationChange)
|
||||
return;
|
||||
requestQuery(new sh::ConfigurationQuery(current.toStdString()));
|
||||
}
|
||||
|
||||
void sh::MainWindow::onGlobalSettingChanged(QStandardItem *item)
|
||||
{
|
||||
if (mIgnoreGlobalSettingChange)
|
||||
return; // we are only interested in changes by the user, not by the backend.
|
||||
|
||||
std::string name = mGlobalSettingsModel->data(mGlobalSettingsModel->index(item->row(), 0)).toString().toStdString();
|
||||
std::string value = mGlobalSettingsModel->data(mGlobalSettingsModel->index(item->row(), 1)).toString().toStdString();
|
||||
|
||||
queueAction(new sh::ActionChangeGlobalSetting(name, value));
|
||||
}
|
||||
|
||||
void sh::MainWindow::onConfigurationChanged (QStandardItem* item)
|
||||
{
|
||||
QList<QListWidgetItem*> items = ui->configurationList->selectedItems();
|
||||
if (items.size())
|
||||
{
|
||||
std::string name = items.front()->text().toStdString();
|
||||
std::string key = mConfigurationModel->data(mConfigurationModel->index(item->row(), 0)).toString().toStdString();
|
||||
std::string value = mConfigurationModel->data(mConfigurationModel->index(item->row(), 1)).toString().toStdString();
|
||||
|
||||
queueAction(new sh::ActionChangeConfiguration(name, key, value));
|
||||
|
||||
requestQuery(new sh::ConfigurationQuery(name));
|
||||
}
|
||||
}
|
||||
|
||||
void sh::MainWindow::on_lineEdit_textEdited(const QString &arg1)
|
||||
{
|
||||
mMaterialProxyModel->setFilterFixedString(arg1);
|
||||
}
|
||||
|
||||
void sh::MainWindow::on_actionSave_triggered()
|
||||
{
|
||||
queueAction (new sh::ActionSaveAll());
|
||||
}
|
||||
|
||||
void sh::MainWindow::on_actionNewMaterial_triggered()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void sh::MainWindow::on_actionDeleteMaterial_triggered()
|
||||
{
|
||||
QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex();
|
||||
QString name = mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString();
|
||||
|
||||
queueAction (new sh::ActionDeleteMaterial(name.toStdString()));
|
||||
}
|
||||
|
||||
void sh::MainWindow::queueAction(Action* action)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mSync->mActionMutex);
|
||||
mActionQueue.push(action);
|
||||
}
|
||||
|
||||
void sh::MainWindow::requestQuery(Query *query)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mSync->mActionMutex);
|
||||
mQueries.push_back(query);
|
||||
}
|
||||
|
||||
void sh::MainWindow::on_actionQuit_triggered()
|
||||
{
|
||||
hide();
|
||||
}
|
||||
|
||||
void sh::MainWindow::on_actionNewConfiguration_triggered()
|
||||
{
|
||||
QInputDialog dialog(this);
|
||||
|
||||
QString text = QInputDialog::getText(this, tr("New Configuration"),
|
||||
tr("Configuration name:"));
|
||||
|
||||
if (!text.isEmpty())
|
||||
{
|
||||
queueAction(new ActionCreateConfiguration(text.toStdString()));
|
||||
}
|
||||
}
|
||||
|
||||
void sh::MainWindow::on_actionDeleteConfiguration_triggered()
|
||||
{
|
||||
QList<QListWidgetItem*> items = ui->configurationList->selectedItems();
|
||||
if (items.size())
|
||||
queueAction(new ActionDeleteConfiguration(items.front()->text().toStdString()));
|
||||
}
|
||||
|
||||
void sh::MainWindow::on_actionDeleteConfigurationProperty_triggered()
|
||||
{
|
||||
QList<QListWidgetItem*> items = ui->configurationList->selectedItems();
|
||||
if (items.empty())
|
||||
return;
|
||||
std::string configurationName = items.front()->text().toStdString();
|
||||
|
||||
QModelIndex current = ui->configurationView->currentIndex();
|
||||
if (!current.isValid())
|
||||
return;
|
||||
|
||||
std::string propertyName = mConfigurationModel->data(mConfigurationModel->index(current.row(), 0)).toString().toStdString();
|
||||
|
||||
queueAction(new sh::ActionDeleteConfigurationProperty(configurationName, propertyName));
|
||||
requestQuery(new sh::ConfigurationQuery(configurationName));
|
||||
}
|
||||
|
||||
void sh::MainWindow::on_actionCloneMaterial_triggered()
|
||||
{
|
||||
QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex();
|
||||
QString name = mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString();
|
||||
if (name.isEmpty())
|
||||
return;
|
||||
|
||||
QInputDialog dialog(this);
|
||||
|
||||
QString text = QInputDialog::getText(this, tr("Clone material"),
|
||||
tr("Name:"));
|
||||
|
||||
if (!text.isEmpty())
|
||||
{
|
||||
queueAction(new ActionCloneMaterial(name.toStdString(), text.toStdString()));
|
||||
}
|
||||
}
|
||||
|
||||
void sh::MainWindow::onContextMenuRequested(const QPoint &point)
|
||||
{
|
||||
QPoint globalPos = ui->materialView->viewport()->mapToGlobal(point);
|
||||
|
||||
QMenu menu;
|
||||
|
||||
QList <QAction*> actions;
|
||||
actions.push_back(ui->actionNewProperty);
|
||||
actions.push_back(ui->actionDeleteProperty);
|
||||
actions.push_back(ui->actionCreatePass);
|
||||
actions.push_back(ui->actionCreateTextureUnit);
|
||||
menu.addActions(actions);
|
||||
|
||||
menu.exec(globalPos);
|
||||
}
|
||||
|
||||
void sh::MainWindow::getContext(QModelIndex index, int* passIndex, int* textureIndex, bool* isInPass, bool* isInTextureUnit)
|
||||
{
|
||||
if (passIndex)
|
||||
{
|
||||
*passIndex = 0;
|
||||
if (isInPass)
|
||||
*isInPass = false;
|
||||
QModelIndex passModelIndex = index;
|
||||
// go up until we find the pass item.
|
||||
while (getPropertyKey(passModelIndex) != "pass" && passModelIndex.isValid())
|
||||
passModelIndex = passModelIndex.parent();
|
||||
|
||||
if (passModelIndex.isValid())
|
||||
{
|
||||
if (passModelIndex.column() != 0)
|
||||
passModelIndex = passModelIndex.parent().child(passModelIndex.row(), 0);
|
||||
for (int i=0; i<mMaterialPropertyModel->rowCount(); ++i)
|
||||
{
|
||||
if (mMaterialPropertyModel->data(mMaterialPropertyModel->index(i, 0)).toString() == QString("pass"))
|
||||
{
|
||||
if (mMaterialPropertyModel->index(i, 0) == passModelIndex)
|
||||
{
|
||||
if (isInPass)
|
||||
*isInPass = true;
|
||||
break;
|
||||
}
|
||||
++(*passIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (textureIndex)
|
||||
{
|
||||
*textureIndex = 0;
|
||||
if (isInTextureUnit)
|
||||
*isInTextureUnit = false;
|
||||
QModelIndex texModelIndex = index;
|
||||
// go up until we find the texture_unit item.
|
||||
while (getPropertyKey(texModelIndex) != "texture_unit" && texModelIndex.isValid())
|
||||
texModelIndex = texModelIndex.parent();
|
||||
if (texModelIndex.isValid())
|
||||
{
|
||||
if (texModelIndex.column() != 0)
|
||||
texModelIndex = texModelIndex.parent().child(texModelIndex.row(), 0);
|
||||
for (int i=0; i<mMaterialPropertyModel->rowCount(texModelIndex.parent()); ++i)
|
||||
{
|
||||
if (texModelIndex.parent().child(i, 0).data().toString() == QString("texture_unit"))
|
||||
{
|
||||
if (texModelIndex.parent().child(i, 0) == texModelIndex)
|
||||
{
|
||||
if (isInTextureUnit)
|
||||
*isInTextureUnit = true;
|
||||
break;
|
||||
}
|
||||
++(*textureIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string sh::MainWindow::getPropertyKey(QModelIndex index)
|
||||
{
|
||||
if (!index.parent().isValid())
|
||||
return mMaterialPropertyModel->data(mMaterialPropertyModel->index(index.row(), 0)).toString().toStdString();
|
||||
else
|
||||
return index.parent().child(index.row(), 0).data().toString().toStdString();
|
||||
}
|
||||
|
||||
std::string sh::MainWindow::getPropertyValue(QModelIndex index)
|
||||
{
|
||||
if (!index.parent().isValid())
|
||||
return mMaterialPropertyModel->data(mMaterialPropertyModel->index(index.row(), 1)).toString().toStdString();
|
||||
else
|
||||
return index.parent().child(index.row(), 1).data().toString().toStdString();
|
||||
}
|
||||
|
||||
void sh::MainWindow::onMaterialPropertyChanged(QStandardItem *item)
|
||||
{
|
||||
if (mIgnoreMaterialPropertyChange)
|
||||
return;
|
||||
|
||||
QString material = getSelectedMaterial();
|
||||
if (material.isEmpty())
|
||||
return;
|
||||
|
||||
// handle checkboxes being checked/unchecked
|
||||
std::string value = getPropertyValue(item->index());
|
||||
if (item->data(Qt::UserRole).toInt() == MaterialProperty::Boolean)
|
||||
{
|
||||
if (item->checkState() == Qt::Checked && value != "true")
|
||||
value = "true";
|
||||
else if (item->checkState() == Qt::Unchecked && value == "true")
|
||||
value = "false";
|
||||
item->setText(QString::fromStdString(value));
|
||||
}
|
||||
|
||||
// handle inherited properties being changed, i.e. overridden by the current (derived) material
|
||||
if (item->data(Qt::UserRole+1).toInt() == MaterialProperty::Inherited_Unchanged)
|
||||
{
|
||||
QColor normalColor = ui->materialView->palette().color(QPalette::Normal, QPalette::WindowText);
|
||||
mIgnoreMaterialPropertyChange = true;
|
||||
mMaterialPropertyModel->item(item->index().row(), 0)
|
||||
->setData(QVariant(MaterialProperty::Inherited_Changed), Qt::UserRole+1);
|
||||
mMaterialPropertyModel->item(item->index().row(), 0)
|
||||
->setData(normalColor, Qt::ForegroundRole);
|
||||
mMaterialPropertyModel->item(item->index().row(), 1)
|
||||
->setData(QVariant(MaterialProperty::Inherited_Changed), Qt::UserRole+1);
|
||||
mMaterialPropertyModel->item(item->index().row(), 1)
|
||||
->setData(normalColor, Qt::ForegroundRole);
|
||||
mIgnoreMaterialPropertyChange = false;
|
||||
|
||||
ui->materialView->scrollTo(mMaterialSortModel->mapFromSource(item->index()));
|
||||
}
|
||||
|
||||
if (!item->index().parent().isValid())
|
||||
{
|
||||
// top level material property
|
||||
queueAction(new ActionSetMaterialProperty(
|
||||
material.toStdString(), getPropertyKey(item->index()), value));
|
||||
}
|
||||
else if (getPropertyKey(item->index()) == "texture_unit")
|
||||
{
|
||||
// texture unit name changed
|
||||
int passIndex, textureIndex;
|
||||
getContext(item->index(), &passIndex, &textureIndex);
|
||||
std::cout << "passIndex " << passIndex << " " << textureIndex << std::endl;
|
||||
|
||||
queueAction(new ActionChangeTextureUnitName(
|
||||
material.toStdString(), passIndex, textureIndex, value));
|
||||
|
||||
}
|
||||
else if (item->index().parent().data().toString() == "pass")
|
||||
{
|
||||
// pass property
|
||||
int passIndex;
|
||||
getContext(item->index(), &passIndex, NULL);
|
||||
/// \todo if shaders are changed, check that the material provides all properties needed by the shader
|
||||
queueAction(new ActionSetPassProperty(
|
||||
material.toStdString(), passIndex, getPropertyKey(item->index()), value));
|
||||
}
|
||||
else if (item->index().parent().data().toString() == "shader_properties")
|
||||
{
|
||||
// shader property
|
||||
int passIndex;
|
||||
getContext(item->index(), &passIndex, NULL);
|
||||
queueAction(new ActionSetShaderProperty(
|
||||
material.toStdString(), passIndex, getPropertyKey(item->index()), value));
|
||||
}
|
||||
else if (item->index().parent().data().toString() == "texture_unit")
|
||||
{
|
||||
// texture property
|
||||
int passIndex, textureIndex;
|
||||
getContext(item->index(), &passIndex, &textureIndex);
|
||||
queueAction(new ActionSetTextureProperty(
|
||||
material.toStdString(), passIndex, textureIndex, getPropertyKey(item->index()), value));
|
||||
}
|
||||
}
|
||||
|
||||
void sh::MainWindow::buildMaterialModel(MaterialQuery *data)
|
||||
{
|
||||
mMaterialPropertyModel->clear();
|
||||
|
||||
mMaterialPropertyModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name")));
|
||||
mMaterialPropertyModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value")));
|
||||
|
||||
for (std::map<std::string, MaterialProperty>::const_iterator it = data->mProperties.begin();
|
||||
it != data->mProperties.end(); ++it)
|
||||
{
|
||||
addProperty(mMaterialPropertyModel->invisibleRootItem(), it->first, it->second);
|
||||
}
|
||||
|
||||
for (std::vector<PassInfo>::iterator it = data->mPasses.begin();
|
||||
it != data->mPasses.end(); ++it)
|
||||
{
|
||||
QStandardItem* passItem = new QStandardItem (QString("pass"));
|
||||
passItem->setFlags(passItem->flags() &= ~Qt::ItemIsEditable);
|
||||
passItem->setData(QVariant(static_cast<int>(MaterialProperty::Object)), Qt::UserRole);
|
||||
|
||||
if (it->mShaderProperties.size())
|
||||
{
|
||||
QStandardItem* shaderPropertiesItem = new QStandardItem (QString("shader_properties"));
|
||||
shaderPropertiesItem->setFlags(shaderPropertiesItem->flags() &= ~Qt::ItemIsEditable);
|
||||
shaderPropertiesItem->setData(QVariant(static_cast<int>(MaterialProperty::Object)), Qt::UserRole);
|
||||
|
||||
for (std::map<std::string, MaterialProperty>::iterator pit = it->mShaderProperties.begin();
|
||||
pit != it->mShaderProperties.end(); ++pit)
|
||||
{
|
||||
addProperty(shaderPropertiesItem, pit->first, pit->second);
|
||||
}
|
||||
passItem->appendRow(shaderPropertiesItem);
|
||||
}
|
||||
|
||||
for (std::map<std::string, MaterialProperty>::iterator pit = it->mProperties.begin();
|
||||
pit != it->mProperties.end(); ++pit)
|
||||
{
|
||||
addProperty(passItem, pit->first, pit->second);
|
||||
}
|
||||
|
||||
for (std::vector<TextureUnitInfo>::iterator tIt = it->mTextureUnits.begin();
|
||||
tIt != it->mTextureUnits.end(); ++tIt)
|
||||
{
|
||||
QStandardItem* unitItem = new QStandardItem (QString("texture_unit"));
|
||||
unitItem->setFlags(unitItem->flags() &= ~Qt::ItemIsEditable);
|
||||
unitItem->setData(QVariant(static_cast<int>(MaterialProperty::Object)), Qt::UserRole);
|
||||
QStandardItem* nameItem = new QStandardItem (QString::fromStdString(tIt->mName));
|
||||
nameItem->setData(QVariant(static_cast<int>(MaterialProperty::Object)), Qt::UserRole);
|
||||
|
||||
QList<QStandardItem*> texUnit;
|
||||
texUnit << unitItem << nameItem;
|
||||
|
||||
for (std::map<std::string, MaterialProperty>::iterator pit = tIt->mProperties.begin();
|
||||
pit != tIt->mProperties.end(); ++pit)
|
||||
{
|
||||
addProperty(unitItem, pit->first, pit->second);
|
||||
}
|
||||
|
||||
passItem->appendRow(texUnit);
|
||||
}
|
||||
|
||||
QList<QStandardItem*> toAdd;
|
||||
toAdd << passItem;
|
||||
toAdd << new QStandardItem(QString(""));
|
||||
mMaterialPropertyModel->appendRow(toAdd);
|
||||
}
|
||||
|
||||
ui->materialView->expandAll();
|
||||
ui->materialView->resizeColumnToContents(0);
|
||||
ui->materialView->resizeColumnToContents(1);
|
||||
}
|
||||
|
||||
void sh::MainWindow::addProperty(QStandardItem *parent, const std::string &key, MaterialProperty value, bool scrollTo)
|
||||
{
|
||||
QList<QStandardItem*> toAdd;
|
||||
QStandardItem* keyItem = new QStandardItem(QString::fromStdString(key));
|
||||
keyItem->setFlags(keyItem->flags() &= ~Qt::ItemIsEditable);
|
||||
keyItem->setData(QVariant(value.mType), Qt::UserRole);
|
||||
keyItem->setData(QVariant(value.mSource), Qt::UserRole+1);
|
||||
toAdd.push_back(keyItem);
|
||||
|
||||
QStandardItem* valueItem = NULL;
|
||||
if (value.mSource != MaterialProperty::None)
|
||||
{
|
||||
valueItem = new QStandardItem(QString::fromStdString(value.mValue));
|
||||
valueItem->setData(QVariant(value.mType), Qt::UserRole);
|
||||
valueItem->setData(QVariant(value.mSource), Qt::UserRole+1);
|
||||
toAdd.push_back(valueItem);
|
||||
}
|
||||
|
||||
|
||||
if (value.mSource == MaterialProperty::Inherited_Unchanged)
|
||||
{
|
||||
QColor color = ui->configurationView->palette().color(QPalette::Disabled, QPalette::WindowText);
|
||||
keyItem->setData(color, Qt::ForegroundRole);
|
||||
if (valueItem)
|
||||
valueItem->setData(color, Qt::ForegroundRole);
|
||||
}
|
||||
if (value.mType == MaterialProperty::Boolean && valueItem)
|
||||
{
|
||||
valueItem->setCheckable(true);
|
||||
valueItem->setCheckState((value.mValue == "true") ? Qt::Checked : Qt::Unchecked);
|
||||
}
|
||||
|
||||
parent->appendRow(toAdd);
|
||||
|
||||
if (scrollTo)
|
||||
ui->materialView->scrollTo(mMaterialSortModel->mapFromSource(keyItem->index()));
|
||||
}
|
||||
|
||||
void sh::MainWindow::buildConfigurationModel(ConfigurationQuery *data)
|
||||
{
|
||||
while (mConfigurationModel->rowCount())
|
||||
mConfigurationModel->removeRow(0);
|
||||
for (std::map<std::string, std::string>::iterator it = data->mProperties.begin();
|
||||
it != data->mProperties.end(); ++it)
|
||||
{
|
||||
QList<QStandardItem*> toAdd;
|
||||
QStandardItem* name = new QStandardItem(QString::fromStdString(it->first));
|
||||
name->setFlags(name->flags() &= ~Qt::ItemIsEditable);
|
||||
QStandardItem* value = new QStandardItem(QString::fromStdString(it->second));
|
||||
toAdd.push_back(name);
|
||||
toAdd.push_back(value);
|
||||
mConfigurationModel->appendRow(toAdd);
|
||||
}
|
||||
|
||||
// add items that are in global settings, but not in this configuration (with a "inactive" color)
|
||||
for (std::map<std::string, std::string>::const_iterator it = mState.mGlobalSettingsMap.begin();
|
||||
it != mState.mGlobalSettingsMap.end(); ++it)
|
||||
{
|
||||
if (data->mProperties.find(it->first) == data->mProperties.end())
|
||||
{
|
||||
QColor color = ui->configurationView->palette().color(QPalette::Disabled, QPalette::WindowText);
|
||||
QList<QStandardItem*> toAdd;
|
||||
QStandardItem* name = new QStandardItem(QString::fromStdString(it->first));
|
||||
name->setFlags(name->flags() &= ~Qt::ItemIsEditable);
|
||||
name->setData(color, Qt::ForegroundRole);
|
||||
QStandardItem* value = new QStandardItem(QString::fromStdString(it->second));
|
||||
value->setData(color, Qt::ForegroundRole);
|
||||
toAdd.push_back(name);
|
||||
toAdd.push_back(value);
|
||||
mConfigurationModel->appendRow(toAdd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sh::MainWindow::on_actionCreatePass_triggered()
|
||||
{
|
||||
QString material = getSelectedMaterial();
|
||||
if (!material.isEmpty())
|
||||
{
|
||||
addProperty(mMaterialPropertyModel->invisibleRootItem(),
|
||||
"pass", MaterialProperty("", MaterialProperty::Object, MaterialProperty::None), true);
|
||||
|
||||
queueAction (new ActionCreatePass(material.toStdString()));
|
||||
}
|
||||
}
|
||||
|
||||
void sh::MainWindow::on_actionDeleteProperty_triggered()
|
||||
{
|
||||
QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex());
|
||||
QString material = getSelectedMaterial();
|
||||
if (material.isEmpty())
|
||||
return;
|
||||
|
||||
mIgnoreMaterialPropertyChange = true;
|
||||
|
||||
if (getPropertyKey(selectedIndex) == "pass")
|
||||
{
|
||||
// delete whole pass
|
||||
int passIndex;
|
||||
getContext(selectedIndex, &passIndex, NULL);
|
||||
if (passIndex == 0)
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText("The first pass can not be deleted.");
|
||||
msgBox.exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
queueAction(new ActionDeletePass(material.toStdString(), passIndex));
|
||||
mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent());
|
||||
}
|
||||
}
|
||||
else if (getPropertyKey(selectedIndex) == "texture_unit")
|
||||
{
|
||||
// delete whole texture unit
|
||||
int passIndex, textureIndex;
|
||||
getContext(selectedIndex, &passIndex, &textureIndex);
|
||||
queueAction(new ActionDeleteTextureUnit(material.toStdString(), passIndex, textureIndex));
|
||||
mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent());
|
||||
}
|
||||
else if (!selectedIndex.parent().isValid())
|
||||
{
|
||||
// top level material property
|
||||
MaterialProperty::Source source = static_cast<MaterialProperty::Source>(
|
||||
mMaterialPropertyModel->itemFromIndex(selectedIndex)->data(Qt::UserRole+1).toInt());
|
||||
if (source == MaterialProperty::Inherited_Unchanged)
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText("Inherited properties can not be deleted.");
|
||||
msgBox.exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
queueAction(new ActionDeleteMaterialProperty(
|
||||
material.toStdString(), getPropertyKey(selectedIndex)));
|
||||
std::cout << "source is " << source << std::endl;
|
||||
if (source == MaterialProperty::Inherited_Changed)
|
||||
{
|
||||
QColor inactiveColor = ui->materialView->palette().color(QPalette::Disabled, QPalette::WindowText);
|
||||
mMaterialPropertyModel->item(selectedIndex.row(), 0)
|
||||
->setData(QVariant(MaterialProperty::Inherited_Unchanged), Qt::UserRole+1);
|
||||
mMaterialPropertyModel->item(selectedIndex.row(), 0)
|
||||
->setData(inactiveColor, Qt::ForegroundRole);
|
||||
mMaterialPropertyModel->item(selectedIndex.row(), 1)
|
||||
->setData(QVariant(MaterialProperty::Inherited_Unchanged), Qt::UserRole+1);
|
||||
mMaterialPropertyModel->item(selectedIndex.row(), 1)
|
||||
->setData(inactiveColor, Qt::ForegroundRole);
|
||||
|
||||
// make sure to update the property's value
|
||||
requestQuery(new sh::MaterialPropertyQuery(material.toStdString(), getPropertyKey(selectedIndex)));
|
||||
}
|
||||
else
|
||||
mMaterialPropertyModel->removeRow(selectedIndex.row());
|
||||
}
|
||||
}
|
||||
else if (selectedIndex.parent().data().toString() == "pass")
|
||||
{
|
||||
// pass property
|
||||
int passIndex;
|
||||
getContext(selectedIndex, &passIndex, NULL);
|
||||
queueAction(new ActionDeletePassProperty(
|
||||
material.toStdString(), passIndex, getPropertyKey(selectedIndex)));
|
||||
mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent());
|
||||
}
|
||||
else if (selectedIndex.parent().data().toString() == "shader_properties")
|
||||
{
|
||||
// shader property
|
||||
int passIndex;
|
||||
getContext(selectedIndex, &passIndex, NULL);
|
||||
queueAction(new ActionDeleteShaderProperty(
|
||||
material.toStdString(), passIndex, getPropertyKey(selectedIndex)));
|
||||
mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent());
|
||||
}
|
||||
else if (selectedIndex.parent().data().toString() == "texture_unit")
|
||||
{
|
||||
// texture property
|
||||
int passIndex, textureIndex;
|
||||
getContext(selectedIndex, &passIndex, &textureIndex);
|
||||
queueAction(new ActionDeleteTextureProperty(
|
||||
material.toStdString(), passIndex, textureIndex, getPropertyKey(selectedIndex)));
|
||||
mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent());
|
||||
}
|
||||
mIgnoreMaterialPropertyChange = false;
|
||||
}
|
||||
|
||||
void sh::MainWindow::on_actionNewProperty_triggered()
|
||||
{
|
||||
QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex());
|
||||
QString material = getSelectedMaterial();
|
||||
if (material.isEmpty())
|
||||
return;
|
||||
|
||||
AddPropertyDialog* dialog = new AddPropertyDialog(this);
|
||||
dialog->exec();
|
||||
QString propertyName = dialog->mName;
|
||||
QString defaultValue = "";
|
||||
|
||||
/// \todo check if this property name exists already
|
||||
|
||||
if (!propertyName.isEmpty())
|
||||
{
|
||||
int passIndex, textureIndex;
|
||||
bool isInPass, isInTextureUnit;
|
||||
getContext(selectedIndex, &passIndex, &textureIndex, &isInPass, &isInTextureUnit);
|
||||
|
||||
QList<QStandardItem*> items;
|
||||
QStandardItem* keyItem = new QStandardItem(propertyName);
|
||||
keyItem->setFlags(keyItem->flags() &= ~Qt::ItemIsEditable);
|
||||
items << keyItem;
|
||||
items << new QStandardItem(defaultValue);
|
||||
|
||||
// figure out which item the new property should be a child of
|
||||
QModelIndex parentIndex = selectedIndex;
|
||||
if (selectedIndex.data(Qt::UserRole) != MaterialProperty::Object)
|
||||
parentIndex = selectedIndex.parent();
|
||||
QStandardItem* parentItem;
|
||||
if (!parentIndex.isValid())
|
||||
parentItem = mMaterialPropertyModel->invisibleRootItem();
|
||||
else
|
||||
parentItem = mMaterialPropertyModel->itemFromIndex(parentIndex);
|
||||
|
||||
if (isInTextureUnit)
|
||||
{
|
||||
queueAction(new ActionSetTextureProperty(
|
||||
material.toStdString(), passIndex, textureIndex, propertyName.toStdString(), defaultValue.toStdString()));
|
||||
}
|
||||
else if (isInPass)
|
||||
{
|
||||
if (selectedIndex.parent().child(selectedIndex.row(),0).data().toString() == "shader_properties"
|
||||
|| selectedIndex.parent().data().toString() == "shader_properties")
|
||||
{
|
||||
queueAction(new ActionSetShaderProperty(
|
||||
material.toStdString(), passIndex, propertyName.toStdString(), defaultValue.toStdString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
queueAction(new ActionSetPassProperty(
|
||||
material.toStdString(), passIndex, propertyName.toStdString(), defaultValue.toStdString()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
queueAction(new ActionSetMaterialProperty(
|
||||
material.toStdString(), propertyName.toStdString(), defaultValue.toStdString()));
|
||||
}
|
||||
|
||||
addProperty(parentItem, propertyName.toStdString(),
|
||||
MaterialProperty (defaultValue.toStdString(), MaterialProperty::Misc, MaterialProperty::Normal), true);
|
||||
|
||||
/// \todo scroll to newly added property
|
||||
}
|
||||
}
|
||||
|
||||
void sh::MainWindow::on_actionCreateTextureUnit_triggered()
|
||||
{
|
||||
QString material = getSelectedMaterial();
|
||||
if (material.isEmpty())
|
||||
return;
|
||||
|
||||
QInputDialog dialog(this);
|
||||
|
||||
QString text = QInputDialog::getText(this, tr("New texture unit"),
|
||||
tr("Texture unit name (for referencing in shaders):"));
|
||||
if (!text.isEmpty())
|
||||
{
|
||||
QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex());
|
||||
int passIndex;
|
||||
getContext(selectedIndex, &passIndex, NULL);
|
||||
queueAction(new ActionCreateTextureUnit(material.toStdString(), passIndex, text.toStdString()));
|
||||
|
||||
// add to model
|
||||
int index = 0;
|
||||
for (int i=0; i<mMaterialPropertyModel->rowCount(); ++i)
|
||||
{
|
||||
if (mMaterialPropertyModel->data(mMaterialPropertyModel->index(i, 0)).toString() == QString("pass"))
|
||||
{
|
||||
if (index == passIndex)
|
||||
{
|
||||
addProperty(mMaterialPropertyModel->itemFromIndex(mMaterialPropertyModel->index(i, 0)),
|
||||
"texture_unit", MaterialProperty(text.toStdString(), MaterialProperty::Object), true);
|
||||
break;
|
||||
}
|
||||
|
||||
++index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sh::MainWindow::on_clearButton_clicked()
|
||||
{
|
||||
ui->errorLog->clear();
|
||||
}
|
||||
|
||||
void sh::MainWindow::on_tabWidget_currentChanged(int index)
|
||||
{
|
||||
QColor color = ui->tabWidget->palette().color(QPalette::Normal, QPalette::WindowText);
|
||||
|
||||
if (index == 3)
|
||||
ui->tabWidget->tabBar()->setTabTextColor(3, color);
|
||||
}
|
139
extern/shiny/Editor/MainWindow.hpp
vendored
Normal file
139
extern/shiny/Editor/MainWindow.hpp
vendored
Normal file
@ -0,0 +1,139 @@
|
||||
#ifndef SHINY_EDITOR_MAINWINDOW_HPP
|
||||
#define SHINY_EDITOR_MAINWINDOW_HPP
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStandardItemModel>
|
||||
#include <QStringListModel>
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "Actions.hpp"
|
||||
#include "Query.hpp"
|
||||
|
||||
#include "PropertySortModel.hpp"
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
struct SynchronizationState;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A snapshot of the material system's state. Lock the mUpdateMutex before accessing.
|
||||
*/
|
||||
struct MaterialSystemState
|
||||
{
|
||||
std::vector<std::string> mMaterialList;
|
||||
|
||||
std::map<std::string, std::string> mGlobalSettingsMap;
|
||||
|
||||
std::vector<std::string> mConfigurationList;
|
||||
|
||||
std::vector<std::string> mMaterialFiles;
|
||||
std::vector<std::string> mConfigurationFiles;
|
||||
|
||||
std::vector<std::string> mShaderSets;
|
||||
|
||||
std::string mErrors;
|
||||
};
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
|
||||
// really should be an std::atomic
|
||||
volatile bool mRequestShowWindow;
|
||||
// dito
|
||||
volatile bool mRequestExit;
|
||||
|
||||
SynchronizationState* mSync;
|
||||
|
||||
/// \todo Is there a better way to ignore manual model changes?
|
||||
bool mIgnoreGlobalSettingChange;
|
||||
bool mIgnoreConfigurationChange;
|
||||
bool mIgnoreMaterialChange;
|
||||
bool mIgnoreMaterialPropertyChange;
|
||||
|
||||
std::queue<Action*> mActionQueue;
|
||||
std::vector<Query*> mQueries;
|
||||
|
||||
MaterialSystemState mState;
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
|
||||
// material tab
|
||||
QStringListModel* mMaterialModel;
|
||||
QSortFilterProxyModel* mMaterialProxyModel;
|
||||
|
||||
QStandardItemModel* mMaterialPropertyModel;
|
||||
PropertySortModel* mMaterialSortModel;
|
||||
|
||||
// global settings tab
|
||||
QStandardItemModel* mGlobalSettingsModel;
|
||||
|
||||
// configuration tab
|
||||
QStandardItemModel* mConfigurationModel;
|
||||
|
||||
void queueAction(Action* action);
|
||||
void requestQuery(Query* query);
|
||||
|
||||
void buildMaterialModel (MaterialQuery* data);
|
||||
void buildConfigurationModel (ConfigurationQuery* data);
|
||||
|
||||
QString getSelectedMaterial();
|
||||
|
||||
/// get the context of an index in the material property model
|
||||
void getContext(QModelIndex index, int* passIndex, int* textureIndex, bool* isInPass=NULL, bool* isInTextureUnit=NULL);
|
||||
|
||||
std::string getPropertyKey(QModelIndex index);
|
||||
std::string getPropertyValue(QModelIndex index);
|
||||
|
||||
void addProperty (QStandardItem* parent, const std::string& key, MaterialProperty value, bool scrollTo=false);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
||||
public slots:
|
||||
void onIdle();
|
||||
|
||||
void onMaterialSelectionChanged (const QModelIndex & current, const QModelIndex & previous);
|
||||
void onConfigurationSelectionChanged (const QString& current);
|
||||
|
||||
void onGlobalSettingChanged (QStandardItem* item);
|
||||
void onConfigurationChanged (QStandardItem* item);
|
||||
void onMaterialPropertyChanged (QStandardItem* item);
|
||||
|
||||
void onContextMenuRequested(const QPoint& point);
|
||||
|
||||
private slots:
|
||||
void on_lineEdit_textEdited(const QString &arg1);
|
||||
void on_actionSave_triggered();
|
||||
void on_actionNewMaterial_triggered();
|
||||
void on_actionDeleteMaterial_triggered();
|
||||
void on_actionQuit_triggered();
|
||||
void on_actionNewConfiguration_triggered();
|
||||
void on_actionDeleteConfiguration_triggered();
|
||||
void on_actionDeleteConfigurationProperty_triggered();
|
||||
void on_actionCloneMaterial_triggered();
|
||||
void on_actionCreatePass_triggered();
|
||||
void on_actionDeleteProperty_triggered();
|
||||
void on_actionNewProperty_triggered();
|
||||
void on_actionCreateTextureUnit_triggered();
|
||||
void on_clearButton_clicked();
|
||||
void on_tabWidget_currentChanged(int index);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MAINWINDOW_HPP
|
14
extern/shiny/Editor/NewMaterialDialog.cpp
vendored
Normal file
14
extern/shiny/Editor/NewMaterialDialog.cpp
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
#include "NewMaterialDialog.hpp"
|
||||
#include "ui_newmaterialdialog.h"
|
||||
|
||||
NewMaterialDialog::NewMaterialDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::NewMaterialDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
NewMaterialDialog::~NewMaterialDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
22
extern/shiny/Editor/NewMaterialDialog.hpp
vendored
Normal file
22
extern/shiny/Editor/NewMaterialDialog.hpp
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef NEWMATERIALDIALOG_HPP
|
||||
#define NEWMATERIALDIALOG_HPP
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class NewMaterialDialog;
|
||||
}
|
||||
|
||||
class NewMaterialDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NewMaterialDialog(QWidget *parent = 0);
|
||||
~NewMaterialDialog();
|
||||
|
||||
private:
|
||||
Ui::NewMaterialDialog *ui;
|
||||
};
|
||||
|
||||
#endif // NEWMATERIALDIALOG_HPP
|
35
extern/shiny/Editor/PropertySortModel.cpp
vendored
Normal file
35
extern/shiny/Editor/PropertySortModel.cpp
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
#include "PropertySortModel.hpp"
|
||||
|
||||
#include "Query.hpp"
|
||||
|
||||
#include <iostream>
|
||||
sh::PropertySortModel::PropertySortModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool sh::PropertySortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||
{
|
||||
if (left.data(Qt::UserRole+1).toInt() != 0 && right.data(Qt::UserRole+1).toInt() != 0)
|
||||
{
|
||||
int sourceL = left.data(Qt::UserRole+1).toInt();
|
||||
int sourceR = right.data(Qt::UserRole+1).toInt();
|
||||
|
||||
if (sourceL > sourceR)
|
||||
return true;
|
||||
else if (sourceR > sourceL)
|
||||
return false;
|
||||
}
|
||||
|
||||
int typeL = left.data(Qt::UserRole).toInt();
|
||||
int typeR = right.data(Qt::UserRole).toInt();
|
||||
|
||||
if (typeL > typeR)
|
||||
return true;
|
||||
else if (typeR > typeL)
|
||||
return false;
|
||||
|
||||
QString nameL = left.data().toString();
|
||||
QString nameR = right.data().toString();
|
||||
return nameL > nameR;
|
||||
}
|
21
extern/shiny/Editor/PropertySortModel.hpp
vendored
Normal file
21
extern/shiny/Editor/PropertySortModel.hpp
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef SHINY_EDITOR_PROPERTYSORTMODEL_H
|
||||
#define SHINY_EDITOR_PROPERTYSORTMODEL_H
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
class PropertySortModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PropertySortModel(QObject* parent);
|
||||
protected:
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
134
extern/shiny/Editor/Query.cpp
vendored
Normal file
134
extern/shiny/Editor/Query.cpp
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
#include "Query.hpp"
|
||||
|
||||
#include "../Main/Factory.hpp"
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
void Query::execute()
|
||||
{
|
||||
executeImpl();
|
||||
mDone = true;
|
||||
}
|
||||
|
||||
ConfigurationQuery::ConfigurationQuery(const std::string &name)
|
||||
: mName(name)
|
||||
{
|
||||
}
|
||||
|
||||
void ConfigurationQuery::executeImpl()
|
||||
{
|
||||
sh::Factory::getInstance().listConfigurationSettings(mName, mProperties);
|
||||
}
|
||||
|
||||
void MaterialQuery::executeImpl()
|
||||
{
|
||||
sh::MaterialInstance* instance = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
|
||||
if (instance->getParent())
|
||||
mParent = static_cast<sh::MaterialInstance*>(instance->getParent())->getName();
|
||||
|
||||
// add the inherited properties
|
||||
sh::PropertySetGet* parent = instance;
|
||||
std::vector<std::string> inheritedPropertiesVector;
|
||||
while (parent->getParent())
|
||||
{
|
||||
parent = parent->getParent();
|
||||
const sh::PropertyMap& parentProperties = parent->listProperties();
|
||||
|
||||
for (PropertyMap::const_iterator it = parentProperties.begin(); it != parentProperties.end(); ++it)
|
||||
{
|
||||
MaterialProperty::Source source = MaterialProperty::Inherited_Unchanged;
|
||||
MaterialProperty::Type type = getType(it->first, parent->getProperty(it->first));
|
||||
mProperties[it->first] = MaterialProperty (
|
||||
retrieveValue<sh::StringValue>(parent->getProperty(it->first), NULL).get(),
|
||||
type, source);
|
||||
inheritedPropertiesVector.push_back(it->first);
|
||||
}
|
||||
}
|
||||
|
||||
// add our properties
|
||||
const sh::PropertyMap& ourProperties = instance->listProperties();
|
||||
for (PropertyMap::const_iterator it = ourProperties.begin(); it != ourProperties.end(); ++it)
|
||||
{
|
||||
MaterialProperty::Source source =
|
||||
(std::find(inheritedPropertiesVector.begin(), inheritedPropertiesVector.end(), it->first)
|
||||
!= inheritedPropertiesVector.end()) ?
|
||||
MaterialProperty::Inherited_Changed : MaterialProperty::Normal;
|
||||
MaterialProperty::Type type = getType(it->first, instance->getProperty(it->first));
|
||||
mProperties[it->first] = MaterialProperty (
|
||||
retrieveValue<sh::StringValue>(instance->getProperty(it->first), NULL).get(),
|
||||
type, source);
|
||||
}
|
||||
|
||||
std::vector<MaterialInstancePass>* passes = instance->getPasses();
|
||||
for (std::vector<MaterialInstancePass>::iterator it = passes->begin(); it != passes->end(); ++it)
|
||||
{
|
||||
mPasses.push_back(PassInfo());
|
||||
|
||||
const sh::PropertyMap& passProperties = it->listProperties();
|
||||
for (PropertyMap::const_iterator pit = passProperties.begin(); pit != passProperties.end(); ++pit)
|
||||
{
|
||||
PropertyValuePtr property = it->getProperty(pit->first);
|
||||
MaterialProperty::Type type = getType(pit->first, property);
|
||||
if (typeid(*property).name() == typeid(sh::LinkedValue).name())
|
||||
mPasses.back().mProperties[pit->first] = MaterialProperty("$" + property->_getStringValue(), type);
|
||||
else
|
||||
mPasses.back().mProperties[pit->first] = MaterialProperty(
|
||||
retrieveValue<sh::StringValue>(property, NULL).get(), type);
|
||||
}
|
||||
|
||||
const sh::PropertyMap& shaderProperties = it->mShaderProperties.listProperties();
|
||||
for (PropertyMap::const_iterator pit = shaderProperties.begin(); pit != shaderProperties.end(); ++pit)
|
||||
{
|
||||
PropertyValuePtr property = it->mShaderProperties.getProperty(pit->first);
|
||||
MaterialProperty::Type type = getType(pit->first, property);
|
||||
if (typeid(*property).name() == typeid(sh::LinkedValue).name())
|
||||
mPasses.back().mShaderProperties[pit->first] = MaterialProperty("$" + property->_getStringValue(), type);
|
||||
else
|
||||
mPasses.back().mShaderProperties[pit->first] = MaterialProperty(
|
||||
retrieveValue<sh::StringValue>(property, NULL).get(), type);
|
||||
}
|
||||
|
||||
std::vector<MaterialInstanceTextureUnit>* texUnits = &it->mTexUnits;
|
||||
for (std::vector<MaterialInstanceTextureUnit>::iterator tIt = texUnits->begin(); tIt != texUnits->end(); ++tIt)
|
||||
{
|
||||
mPasses.back().mTextureUnits.push_back(TextureUnitInfo());
|
||||
mPasses.back().mTextureUnits.back().mName = tIt->getName();
|
||||
const sh::PropertyMap& unitProperties = tIt->listProperties();
|
||||
for (PropertyMap::const_iterator pit = unitProperties.begin(); pit != unitProperties.end(); ++pit)
|
||||
{
|
||||
PropertyValuePtr property = tIt->getProperty(pit->first);
|
||||
MaterialProperty::Type type = getType(pit->first, property);
|
||||
if (typeid(*property).name() == typeid(sh::LinkedValue).name())
|
||||
mPasses.back().mTextureUnits.back().mProperties[pit->first] = MaterialProperty(
|
||||
"$" + property->_getStringValue(), MaterialProperty::Linked);
|
||||
else
|
||||
mPasses.back().mTextureUnits.back().mProperties[pit->first] = MaterialProperty(
|
||||
retrieveValue<sh::StringValue>(property, NULL).get(), type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MaterialProperty::Type MaterialQuery::getType(const std::string &key, PropertyValuePtr value)
|
||||
{
|
||||
if (typeid(*value).name() == typeid(sh::LinkedValue).name())
|
||||
return MaterialProperty::Linked;
|
||||
|
||||
if (key == "vertex_program" || key == "fragment_program")
|
||||
return MaterialProperty::Shader;
|
||||
|
||||
std::string valueStr = retrieveValue<sh::StringValue>(value, NULL).get();
|
||||
|
||||
if (valueStr == "false" || valueStr == "true")
|
||||
return MaterialProperty::Boolean;
|
||||
}
|
||||
|
||||
void MaterialPropertyQuery::executeImpl()
|
||||
{
|
||||
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
|
||||
mValue = retrieveValue<sh::StringValue>(m->getProperty(mPropertyName), m).get();
|
||||
}
|
||||
|
||||
}
|
121
extern/shiny/Editor/Query.hpp
vendored
Normal file
121
extern/shiny/Editor/Query.hpp
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
#ifndef SH_QUERY_H
|
||||
#define SH_QUERY_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "../Main/PropertyBase.hpp"
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
class Query
|
||||
{
|
||||
public:
|
||||
Query()
|
||||
: mDone(false) {}
|
||||
virtual ~Query();
|
||||
|
||||
void execute();
|
||||
|
||||
bool mDone;
|
||||
|
||||
protected:
|
||||
virtual void executeImpl() = 0;
|
||||
};
|
||||
|
||||
class ConfigurationQuery : public Query
|
||||
{
|
||||
public:
|
||||
ConfigurationQuery(const std::string& name);
|
||||
|
||||
std::map<std::string, std::string> mProperties;
|
||||
protected:
|
||||
std::string mName;
|
||||
virtual void executeImpl();
|
||||
};
|
||||
|
||||
|
||||
struct MaterialProperty
|
||||
{
|
||||
|
||||
enum Type
|
||||
{
|
||||
Texture,
|
||||
Color,
|
||||
Boolean,
|
||||
Shader,
|
||||
Misc,
|
||||
Linked,
|
||||
Object // child object, i.e. pass, texture unit, shader properties
|
||||
};
|
||||
|
||||
enum Source
|
||||
{
|
||||
Normal,
|
||||
Inherited_Changed,
|
||||
Inherited_Unchanged,
|
||||
None // there is no property source (e.g. a pass, which does not have a name)
|
||||
};
|
||||
|
||||
MaterialProperty() {}
|
||||
MaterialProperty (const std::string& value, Type type, Source source=Normal)
|
||||
: mValue(value), mType(type), mSource(source) {}
|
||||
|
||||
std::string mValue;
|
||||
Type mType;
|
||||
Source mSource;
|
||||
};
|
||||
|
||||
|
||||
struct TextureUnitInfo
|
||||
{
|
||||
std::string mName;
|
||||
std::map<std::string, MaterialProperty> mProperties;
|
||||
};
|
||||
|
||||
struct PassInfo
|
||||
{
|
||||
std::map<std::string, MaterialProperty> mShaderProperties;
|
||||
|
||||
std::map<std::string, MaterialProperty> mProperties;
|
||||
std::vector<TextureUnitInfo> mTextureUnits;
|
||||
};
|
||||
|
||||
class MaterialQuery : public Query
|
||||
{
|
||||
public:
|
||||
MaterialQuery(const std::string& name)
|
||||
: mName(name) {}
|
||||
|
||||
std::string mParent;
|
||||
std::vector<PassInfo> mPasses;
|
||||
std::map<std::string, MaterialProperty> mProperties;
|
||||
|
||||
protected:
|
||||
std::string mName;
|
||||
virtual void executeImpl();
|
||||
|
||||
MaterialProperty::Type getType (const std::string& key, PropertyValuePtr value);
|
||||
};
|
||||
|
||||
class MaterialPropertyQuery : public Query
|
||||
{
|
||||
public:
|
||||
MaterialPropertyQuery(const std::string& name, const std::string& propertyName)
|
||||
: mName(name), mPropertyName(propertyName)
|
||||
{
|
||||
}
|
||||
|
||||
std::string mValue;
|
||||
|
||||
std::string mName;
|
||||
std::string mPropertyName;
|
||||
protected:
|
||||
virtual void executeImpl();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
118
extern/shiny/Editor/addpropertydialog.ui
vendored
Normal file
118
extern/shiny/Editor/addpropertydialog.ui
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AddPropertyDialog</class>
|
||||
<widget class="QDialog" name="AddPropertyDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>257</width>
|
||||
<height>133</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Property name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Editing widget</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="comboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Checkbox</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Shader</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Color</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Texture</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Other</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>AddPropertyDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>AddPropertyDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
420
extern/shiny/Editor/mainwindow.ui
vendored
Normal file
420
extern/shiny/Editor/mainwindow.ui
vendored
Normal file
@ -0,0 +1,420 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>647</width>
|
||||
<height>512</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QHBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="sh::ColoredTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<property name="accessibleName">
|
||||
<string/>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Materials</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="verticalLayoutWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListView" name="materialList">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolBar" name="toolBar1">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<addaction name="actionNewMaterial"/>
|
||||
<addaction name="actionCloneMaterial"/>
|
||||
<addaction name="actionDeleteMaterial"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="verticalLayoutWidget2">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QTreeView" name="materialView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolBar" name="toolBar4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonIconOnly</enum>
|
||||
</property>
|
||||
<addaction name="actionNewProperty"/>
|
||||
<addaction name="actionDeleteProperty"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab2">
|
||||
<attribute name="title">
|
||||
<string>Global settings</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QTableView" name="globalSettingsView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>Configurations</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QListWidget" name="configurationList"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolBar" name="toolBar2">
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<addaction name="actionNewConfiguration"/>
|
||||
<addaction name="actionDeleteConfiguration"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="layoutWidget2">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QTableView" name="configurationView"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolBar" name="toolBar2_2">
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<addaction name="actionDeleteConfigurationProperty"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_3">
|
||||
<attribute name="title">
|
||||
<string>Errors</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QTextEdit" name="errorLog">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="clearButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="edit-clear"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>647</width>
|
||||
<height>25</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="defaultUp">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionSave"/>
|
||||
<addaction name="actionQuit"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuMaterial">
|
||||
<property name="title">
|
||||
<string>Material</string>
|
||||
</property>
|
||||
<addaction name="actionNewMaterial"/>
|
||||
<addaction name="actionCloneMaterial"/>
|
||||
<addaction name="actionDeleteMaterial"/>
|
||||
<addaction name="actionChange_parent"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHistory">
|
||||
<property name="title">
|
||||
<string>History</string>
|
||||
</property>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuMaterial"/>
|
||||
<addaction name="menuHistory"/>
|
||||
</widget>
|
||||
<action name="actionQuit">
|
||||
<property name="icon">
|
||||
<iconset theme="application-exit">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Quit</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave">
|
||||
<property name="icon">
|
||||
<iconset theme="document-save">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Save all</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDeleteMaterial">
|
||||
<property name="icon">
|
||||
<iconset theme="edit-delete">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Delete selected material</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionChange_parent">
|
||||
<property name="text">
|
||||
<string>Change parent...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNewMaterial">
|
||||
<property name="icon">
|
||||
<iconset theme="document-new">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>New</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Create a new material</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCloneMaterial">
|
||||
<property name="icon">
|
||||
<iconset theme="edit-copy">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clone</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Clone selected material</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDeleteConfiguration">
|
||||
<property name="icon">
|
||||
<iconset theme="edit-delete">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Delete selected configuration</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Del</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNewConfiguration">
|
||||
<property name="icon">
|
||||
<iconset theme="document-new">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>New</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Create a new configuration</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDeleteConfigurationProperty">
|
||||
<property name="icon">
|
||||
<iconset theme="edit-delete">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Delete property</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDeleteProperty">
|
||||
<property name="icon">
|
||||
<iconset theme="remove">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Delete item</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNewProperty">
|
||||
<property name="icon">
|
||||
<iconset theme="add">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>New property</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCreatePass">
|
||||
<property name="icon">
|
||||
<iconset theme="edit-add">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Create pass</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCreateTextureUnit">
|
||||
<property name="icon">
|
||||
<iconset theme="edit-add">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Create texture unit</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>sh::ColoredTabWidget</class>
|
||||
<extends>QTabWidget</extends>
|
||||
<header>ColoredTabWidget.hpp</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
98
extern/shiny/Editor/newmaterialdialog.ui
vendored
Normal file
98
extern/shiny/Editor/newmaterialdialog.ui
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>NewMaterialDialog</class>
|
||||
<widget class="QDialog" name="NewMaterialDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>385</width>
|
||||
<height>198</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Parent material</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_2"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>File</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="comboBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>NewMaterialDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>NewMaterialDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
349
extern/shiny/Main/Factory.cpp
vendored
349
extern/shiny/Main/Factory.cpp
vendored
@ -51,8 +51,6 @@ namespace sh
|
||||
{
|
||||
assert(mCurrentLanguage != Language_None);
|
||||
|
||||
bool removeBinaryCache = false;
|
||||
|
||||
if (boost::filesystem::exists (mPlatform->getCacheFolder () + "/lastModified.txt"))
|
||||
{
|
||||
std::ifstream file;
|
||||
@ -86,8 +84,9 @@ namespace sh
|
||||
break;
|
||||
}
|
||||
|
||||
PropertySetGet newConfiguration;
|
||||
Configuration newConfiguration;
|
||||
newConfiguration.setParent(&mGlobalSettings);
|
||||
newConfiguration.setSourceFile (it->second->mFileName);
|
||||
|
||||
std::vector<ScriptNode*> props = it->second->getChildren();
|
||||
for (std::vector<ScriptNode*>::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt)
|
||||
@ -137,82 +136,7 @@ namespace sh
|
||||
}
|
||||
|
||||
// load shader sets
|
||||
{
|
||||
ScriptLoader shaderSetLoader(".shaderset");
|
||||
ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath());
|
||||
std::map <std::string, ScriptNode*> nodes = shaderSetLoader.getAllConfigScripts();
|
||||
for (std::map <std::string, ScriptNode*>::const_iterator it = nodes.begin();
|
||||
it != nodes.end(); ++it)
|
||||
{
|
||||
if (!(it->second->getName() == "shader_set"))
|
||||
{
|
||||
std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .shaderset" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!it->second->findChild("profiles_cg"))
|
||||
throw std::runtime_error ("missing \"profiles_cg\" field for \"" + it->first + "\"");
|
||||
if (!it->second->findChild("profiles_hlsl"))
|
||||
throw std::runtime_error ("missing \"profiles_hlsl\" field for \"" + it->first + "\"");
|
||||
if (!it->second->findChild("source"))
|
||||
throw std::runtime_error ("missing \"source\" field for \"" + it->first + "\"");
|
||||
if (!it->second->findChild("type"))
|
||||
throw std::runtime_error ("missing \"type\" field for \"" + it->first + "\"");
|
||||
|
||||
std::vector<std::string> profiles_cg;
|
||||
boost::split (profiles_cg, it->second->findChild("profiles_cg")->getValue(), boost::is_any_of(" "));
|
||||
std::string cg_profile;
|
||||
for (std::vector<std::string>::iterator it2 = profiles_cg.begin(); it2 != profiles_cg.end(); ++it2)
|
||||
{
|
||||
if (mPlatform->isProfileSupported(*it2))
|
||||
{
|
||||
cg_profile = *it2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> profiles_hlsl;
|
||||
boost::split (profiles_hlsl, it->second->findChild("profiles_hlsl")->getValue(), boost::is_any_of(" "));
|
||||
std::string hlsl_profile;
|
||||
for (std::vector<std::string>::iterator it2 = profiles_hlsl.begin(); it2 != profiles_hlsl.end(); ++it2)
|
||||
{
|
||||
if (mPlatform->isProfileSupported(*it2))
|
||||
{
|
||||
hlsl_profile = *it2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue();
|
||||
std::string sourceRelative = it->second->findChild("source")->getValue();
|
||||
|
||||
ShaderSet newSet (it->second->findChild("type")->getValue(), cg_profile, hlsl_profile,
|
||||
sourceAbsolute,
|
||||
mPlatform->getBasePath(),
|
||||
it->first,
|
||||
&mGlobalSettings);
|
||||
|
||||
int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute));
|
||||
mShadersLastModifiedNew[sourceRelative] = lastModified;
|
||||
if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end())
|
||||
{
|
||||
if (mShadersLastModified[sourceRelative] != lastModified)
|
||||
{
|
||||
// delete any outdated shaders based on this shader set
|
||||
if (removeCache (it->first))
|
||||
removeBinaryCache = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we get here, this is either the first run or a new shader file was added
|
||||
// in both cases we can safely delete
|
||||
if (removeCache (it->first))
|
||||
removeBinaryCache = true;
|
||||
}
|
||||
mShaderSets.insert(std::make_pair(it->first, newSet));
|
||||
}
|
||||
}
|
||||
bool removeBinaryCache = reloadShaders();
|
||||
|
||||
// load materials
|
||||
{
|
||||
@ -315,6 +239,8 @@ namespace sh
|
||||
|
||||
Factory::~Factory ()
|
||||
{
|
||||
mShaderSets.clear();
|
||||
|
||||
if (mPlatform->supportsShaderSerialization () && mWriteMicrocodeCache)
|
||||
{
|
||||
std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName;
|
||||
@ -367,15 +293,16 @@ namespace sh
|
||||
while (i>0)
|
||||
{
|
||||
--i;
|
||||
m->createForConfiguration (configuration, i);
|
||||
|
||||
if (mListener)
|
||||
if (m->createForConfiguration (configuration, i) && mListener)
|
||||
mListener->materialCreated (m, configuration, i);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m->createForConfiguration (configuration, lodIndex);
|
||||
if (mListener)
|
||||
if (m->createForConfiguration (configuration, lodIndex) && mListener)
|
||||
mListener->materialCreated (m, configuration, lodIndex);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
@ -439,6 +366,12 @@ namespace sh
|
||||
|
||||
ShaderSet* Factory::getShaderSet (const std::string& name)
|
||||
{
|
||||
if (mShaderSets.find(name) == mShaderSets.end())
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << "Shader '" << name << "' not found";
|
||||
throw std::runtime_error(msg.str());
|
||||
}
|
||||
return &mShaderSets.find(name)->second;
|
||||
}
|
||||
|
||||
@ -466,6 +399,14 @@ namespace sh
|
||||
}
|
||||
}
|
||||
|
||||
void Factory::notifyConfigurationChanged()
|
||||
{
|
||||
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
|
||||
{
|
||||
it->second.destroyAll();
|
||||
}
|
||||
}
|
||||
|
||||
MaterialInstance* Factory::getMaterialInstance (const std::string& name)
|
||||
{
|
||||
return findInstance(name);
|
||||
@ -493,17 +434,21 @@ namespace sh
|
||||
return "";
|
||||
}
|
||||
|
||||
PropertySetGet* Factory::getConfiguration (const std::string& name)
|
||||
Configuration* Factory::getConfiguration (const std::string& name)
|
||||
{
|
||||
return &mConfigurations[name];
|
||||
}
|
||||
|
||||
void Factory::registerConfiguration (const std::string& name, PropertySetGet configuration)
|
||||
void Factory::createConfiguration (const std::string& name)
|
||||
{
|
||||
mConfigurations[name] = configuration;
|
||||
mConfigurations[name].setParent (&mGlobalSettings);
|
||||
}
|
||||
|
||||
void Factory::destroyConfiguration(const std::string &name)
|
||||
{
|
||||
mConfigurations.erase(name);
|
||||
}
|
||||
|
||||
void Factory::registerLodConfiguration (int index, PropertySetGet configuration)
|
||||
{
|
||||
mLodConfigurations[index] = configuration;
|
||||
@ -571,17 +516,93 @@ namespace sh
|
||||
return p;
|
||||
}
|
||||
|
||||
void Factory::saveMaterials (const std::string& filename)
|
||||
void Factory::saveAll ()
|
||||
{
|
||||
std::ofstream file;
|
||||
file.open (filename.c_str ());
|
||||
|
||||
std::map<std::string, std::ofstream*> files;
|
||||
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
|
||||
{
|
||||
it->second.save(file);
|
||||
if (it->second.getSourceFile().empty())
|
||||
continue;
|
||||
if (files.find(it->second.getSourceFile()) == files.end())
|
||||
{
|
||||
/// \todo check if this is actually the same file, since there can be different paths to the same file
|
||||
std::ofstream* stream = new std::ofstream();
|
||||
stream->open (it->second.getSourceFile().c_str());
|
||||
|
||||
files[it->second.getSourceFile()] = stream;
|
||||
}
|
||||
it->second.save (*files[it->second.getSourceFile()]);
|
||||
}
|
||||
|
||||
file.close();
|
||||
for (std::map<std::string, std::ofstream*>::iterator it = files.begin(); it != files.end(); ++it)
|
||||
{
|
||||
delete it->second;
|
||||
}
|
||||
files.clear();
|
||||
|
||||
for (ConfigurationMap::iterator it = mConfigurations.begin(); it != mConfigurations.end(); ++it)
|
||||
{
|
||||
if (it->second.getSourceFile().empty())
|
||||
continue;
|
||||
if (files.find(it->second.getSourceFile()) == files.end())
|
||||
{
|
||||
/// \todo check if this is actually the same file, since there can be different paths to the same file
|
||||
std::ofstream* stream = new std::ofstream();
|
||||
stream->open (it->second.getSourceFile().c_str());
|
||||
|
||||
files[it->second.getSourceFile()] = stream;
|
||||
}
|
||||
it->second.save (it->first, *files[it->second.getSourceFile()]);
|
||||
}
|
||||
|
||||
for (std::map<std::string, std::ofstream*>::iterator it = files.begin(); it != files.end(); ++it)
|
||||
{
|
||||
delete it->second;
|
||||
}
|
||||
}
|
||||
|
||||
void Factory::listMaterials(std::vector<std::string> &out)
|
||||
{
|
||||
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
|
||||
{
|
||||
out.push_back(it->first);
|
||||
}
|
||||
}
|
||||
|
||||
void Factory::listGlobalSettings(std::map<std::string, std::string> &out)
|
||||
{
|
||||
const PropertyMap& properties = mGlobalSettings.listProperties();
|
||||
|
||||
for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it)
|
||||
{
|
||||
out[it->first] = retrieveValue<StringValue>(mGlobalSettings.getProperty(it->first), NULL).get();
|
||||
}
|
||||
}
|
||||
|
||||
void Factory::listConfigurationSettings(const std::string& name, std::map<std::string, std::string> &out)
|
||||
{
|
||||
const PropertyMap& properties = mConfigurations[name].listProperties();
|
||||
|
||||
for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it)
|
||||
{
|
||||
out[it->first] = retrieveValue<StringValue>(mConfigurations[name].getProperty(it->first), NULL).get();
|
||||
}
|
||||
}
|
||||
|
||||
void Factory::listConfigurationNames(std::vector<std::string> &out)
|
||||
{
|
||||
for (ConfigurationMap::const_iterator it = mConfigurations.begin(); it != mConfigurations.end(); ++it)
|
||||
{
|
||||
out.push_back(it->first);
|
||||
}
|
||||
}
|
||||
|
||||
void Factory::listShaderSets(std::vector<std::string> &out)
|
||||
{
|
||||
for (ShaderSetMap::const_iterator it = mShaderSets.begin(); it != mShaderSets.end(); ++it)
|
||||
{
|
||||
out.push_back(it->first);
|
||||
}
|
||||
}
|
||||
|
||||
void Factory::_ensureMaterial(const std::string& name, const std::string& configuration)
|
||||
@ -630,4 +651,146 @@ namespace sh
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Factory::reloadShaders()
|
||||
{
|
||||
mShaderSets.clear();
|
||||
notifyConfigurationChanged();
|
||||
|
||||
bool removeBinaryCache = false;
|
||||
ScriptLoader shaderSetLoader(".shaderset");
|
||||
ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath());
|
||||
std::map <std::string, ScriptNode*> nodes = shaderSetLoader.getAllConfigScripts();
|
||||
for (std::map <std::string, ScriptNode*>::const_iterator it = nodes.begin();
|
||||
it != nodes.end(); ++it)
|
||||
{
|
||||
if (!(it->second->getName() == "shader_set"))
|
||||
{
|
||||
std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .shaderset" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!it->second->findChild("profiles_cg"))
|
||||
throw std::runtime_error ("missing \"profiles_cg\" field for \"" + it->first + "\"");
|
||||
if (!it->second->findChild("profiles_hlsl"))
|
||||
throw std::runtime_error ("missing \"profiles_hlsl\" field for \"" + it->first + "\"");
|
||||
if (!it->second->findChild("source"))
|
||||
throw std::runtime_error ("missing \"source\" field for \"" + it->first + "\"");
|
||||
if (!it->second->findChild("type"))
|
||||
throw std::runtime_error ("missing \"type\" field for \"" + it->first + "\"");
|
||||
|
||||
std::vector<std::string> profiles_cg;
|
||||
boost::split (profiles_cg, it->second->findChild("profiles_cg")->getValue(), boost::is_any_of(" "));
|
||||
std::string cg_profile;
|
||||
for (std::vector<std::string>::iterator it2 = profiles_cg.begin(); it2 != profiles_cg.end(); ++it2)
|
||||
{
|
||||
if (mPlatform->isProfileSupported(*it2))
|
||||
{
|
||||
cg_profile = *it2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> profiles_hlsl;
|
||||
boost::split (profiles_hlsl, it->second->findChild("profiles_hlsl")->getValue(), boost::is_any_of(" "));
|
||||
std::string hlsl_profile;
|
||||
for (std::vector<std::string>::iterator it2 = profiles_hlsl.begin(); it2 != profiles_hlsl.end(); ++it2)
|
||||
{
|
||||
if (mPlatform->isProfileSupported(*it2))
|
||||
{
|
||||
hlsl_profile = *it2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue();
|
||||
std::string sourceRelative = it->second->findChild("source")->getValue();
|
||||
|
||||
ShaderSet newSet (it->second->findChild("type")->getValue(), cg_profile, hlsl_profile,
|
||||
sourceAbsolute,
|
||||
mPlatform->getBasePath(),
|
||||
it->first,
|
||||
&mGlobalSettings);
|
||||
|
||||
int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute));
|
||||
mShadersLastModifiedNew[sourceRelative] = lastModified;
|
||||
if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end())
|
||||
{
|
||||
if (mShadersLastModified[sourceRelative] != lastModified)
|
||||
{
|
||||
// delete any outdated shaders based on this shader set
|
||||
if (removeCache (it->first))
|
||||
removeBinaryCache = true;
|
||||
mShadersLastModified[sourceRelative] = lastModified;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we get here, this is either the first run or a new shader file was added
|
||||
// in both cases we can safely delete
|
||||
if (removeCache (it->first))
|
||||
removeBinaryCache = true;
|
||||
mShadersLastModified[sourceRelative] = lastModified;
|
||||
}
|
||||
mShaderSets.insert(std::make_pair(it->first, newSet));
|
||||
}
|
||||
|
||||
return removeBinaryCache;
|
||||
}
|
||||
|
||||
void Factory::doMonitorShaderFiles()
|
||||
{
|
||||
bool reload=false;
|
||||
ScriptLoader shaderSetLoader(".shaderset");
|
||||
ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath());
|
||||
std::map <std::string, ScriptNode*> nodes = shaderSetLoader.getAllConfigScripts();
|
||||
for (std::map <std::string, ScriptNode*>::const_iterator it = nodes.begin();
|
||||
it != nodes.end(); ++it)
|
||||
{
|
||||
|
||||
std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue();
|
||||
std::string sourceRelative = it->second->findChild("source")->getValue();
|
||||
|
||||
int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute));
|
||||
if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end())
|
||||
{
|
||||
if (mShadersLastModified[sourceRelative] != lastModified)
|
||||
{
|
||||
reload=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (reload)
|
||||
reloadShaders();
|
||||
}
|
||||
|
||||
void Factory::logError(const std::string &msg)
|
||||
{
|
||||
mErrorLog << msg << '\n';
|
||||
}
|
||||
|
||||
std::string Factory::getErrorLog()
|
||||
{
|
||||
std::string errors = mErrorLog.str();
|
||||
mErrorLog.str("");
|
||||
return errors;
|
||||
}
|
||||
|
||||
void Factory::unloadUnreferencedMaterials()
|
||||
{
|
||||
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
|
||||
{
|
||||
if (it->second.getMaterial()->isUnreferenced())
|
||||
it->second.destroyAll();
|
||||
}
|
||||
}
|
||||
|
||||
void Configuration::save(const std::string& name, std::ofstream &stream)
|
||||
{
|
||||
stream << "configuration " << name << '\n';
|
||||
stream << "{\n";
|
||||
PropertySetGet::save(stream, "\t");
|
||||
stream << "}\n";
|
||||
}
|
||||
}
|
||||
|
70
extern/shiny/Main/Factory.hpp
vendored
70
extern/shiny/Main/Factory.hpp
vendored
@ -3,6 +3,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "MaterialInstance.hpp"
|
||||
#include "ShaderSet.hpp"
|
||||
@ -12,9 +13,21 @@ namespace sh
|
||||
{
|
||||
class Platform;
|
||||
|
||||
class Configuration : public PropertySetGet
|
||||
{
|
||||
public:
|
||||
void setSourceFile (const std::string& file) { mSourceFile = file ; }
|
||||
std::string getSourceFile () { return mSourceFile; }
|
||||
|
||||
void save(const std::string& name, std::ofstream &stream);
|
||||
|
||||
private:
|
||||
std::string mSourceFile;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, MaterialInstance> MaterialMap;
|
||||
typedef std::map<std::string, ShaderSet> ShaderSetMap;
|
||||
typedef std::map<std::string, PropertySetGet> ConfigurationMap;
|
||||
typedef std::map<std::string, Configuration> ConfigurationMap;
|
||||
typedef std::map<int, PropertySetGet> LodConfigurationMap;
|
||||
typedef std::map<std::string, int> LastModifiedMap;
|
||||
|
||||
@ -81,8 +94,8 @@ namespace sh
|
||||
/// Get a MaterialInstance by name
|
||||
MaterialInstance* getMaterialInstance (const std::string& name);
|
||||
|
||||
/// Register a configuration, which can then be used by switching the active material scheme
|
||||
void registerConfiguration (const std::string& name, PropertySetGet configuration);
|
||||
/// Create a configuration, which can then be altered by using Factory::getConfiguration
|
||||
void createConfiguration (const std::string& name);
|
||||
|
||||
/// Register a lod configuration, which can then be used by setting up lod distance values for the material \n
|
||||
/// 0 refers to highest lod, so use 1 or higher as index parameter
|
||||
@ -125,8 +138,48 @@ namespace sh
|
||||
/// \note The default is off (no cache reading)
|
||||
void setReadMicrocodeCache(bool read) { mReadMicrocodeCache = read; }
|
||||
|
||||
/// Saves all the materials that were initially loaded from the file with this name
|
||||
void saveMaterials (const std::string& filename);
|
||||
/// Lists all materials currently registered with the factory. Whether they are
|
||||
/// loaded or not does not matter.
|
||||
void listMaterials (std::vector<std::string>& out);
|
||||
|
||||
/// Lists current name & value of all global settings.
|
||||
void listGlobalSettings (std::map<std::string, std::string>& out);
|
||||
|
||||
/// Lists configuration names.
|
||||
void listConfigurationNames (std::vector<std::string>& out);
|
||||
|
||||
/// Lists current name & value of settings for a given configuration.
|
||||
void listConfigurationSettings (const std::string& name, std::map<std::string, std::string>& out);
|
||||
|
||||
/// Lists shader sets.
|
||||
void listShaderSets (std::vector<std::string>& out);
|
||||
|
||||
/// \note This only works if microcode caching is disabled, as there is currently no way to remove the cache
|
||||
/// through the Ogre API. Luckily, this is already fixed in Ogre 1.9.
|
||||
bool reloadShaders();
|
||||
|
||||
/// Calls reloadShaders() if shader files have been modified since the last reload.
|
||||
/// \note This only works if microcode caching is disabled, as there is currently no way to remove the cache
|
||||
/// through the Ogre API. Luckily, this is already fixed in Ogre 1.9.
|
||||
void doMonitorShaderFiles();
|
||||
|
||||
/// Unloads all materials that are currently not referenced. This will not unload the textures themselves,
|
||||
/// but it will let go of the SharedPtr's to the textures, so that you may unload them if you so desire. \n
|
||||
/// A good time to call this would be after a new level has been loaded, but just calling it occasionally after a period
|
||||
/// of time should work just fine too.
|
||||
void unloadUnreferencedMaterials();
|
||||
|
||||
void destroyConfiguration (const std::string& name);
|
||||
|
||||
void notifyConfigurationChanged();
|
||||
|
||||
/// Saves all materials and configurations, by default to the file they were loaded from.
|
||||
/// If you wish to save them elsewhere, use setSourceFile first.
|
||||
void saveAll ();
|
||||
|
||||
/// Returns the error log as a string, then clears it.
|
||||
/// Note: Errors are also written to the standard error output, or thrown if they are fatal.
|
||||
std::string getErrorLog ();
|
||||
|
||||
static Factory& getInstance();
|
||||
///< Return instance of this class.
|
||||
@ -137,11 +190,13 @@ namespace sh
|
||||
/// You will probably never have to use this.
|
||||
void _ensureMaterial(const std::string& name, const std::string& configuration);
|
||||
|
||||
|
||||
Configuration* getConfiguration (const std::string& name);
|
||||
|
||||
private:
|
||||
|
||||
MaterialInstance* requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex);
|
||||
ShaderSet* getShaderSet (const std::string& name);
|
||||
PropertySetGet* getConfiguration (const std::string& name);
|
||||
Platform* getPlatform ();
|
||||
|
||||
PropertySetGet* getCurrentGlobalSettings();
|
||||
@ -163,6 +218,8 @@ namespace sh
|
||||
|
||||
std::map<TextureUnitState*, std::string> mTextureAliasInstances;
|
||||
|
||||
void logError (const std::string& msg);
|
||||
|
||||
friend class Platform;
|
||||
friend class MaterialInstance;
|
||||
friend class ShaderInstance;
|
||||
@ -179,6 +236,7 @@ namespace sh
|
||||
bool mWriteMicrocodeCache;
|
||||
bool mReadSourceCache;
|
||||
bool mWriteSourceCache;
|
||||
std::stringstream mErrorLog;
|
||||
|
||||
MaterialMap mMaterials;
|
||||
ShaderSetMap mShaderSets;
|
||||
|
228
extern/shiny/Main/MaterialInstance.cpp
vendored
228
extern/shiny/Main/MaterialInstance.cpp
vendored
@ -1,6 +1,7 @@
|
||||
#include "MaterialInstance.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
|
||||
#include "Factory.hpp"
|
||||
#include "ShaderSet.hpp"
|
||||
@ -12,6 +13,7 @@ namespace sh
|
||||
, mShadersEnabled(true)
|
||||
, mFactory(f)
|
||||
, mListener(NULL)
|
||||
, mFailedToCreate(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -46,6 +48,7 @@ namespace sh
|
||||
return;
|
||||
mMaterial->removeAll();
|
||||
mTexUnits.clear();
|
||||
mFailedToCreate = false;
|
||||
}
|
||||
|
||||
void MaterialInstance::setProperty (const std::string& name, PropertyValuePtr value)
|
||||
@ -54,118 +57,136 @@ namespace sh
|
||||
destroyAll(); // trigger updates
|
||||
}
|
||||
|
||||
void MaterialInstance::createForConfiguration (const std::string& configuration, unsigned short lodIndex)
|
||||
bool MaterialInstance::createForConfiguration (const std::string& configuration, unsigned short lodIndex)
|
||||
{
|
||||
bool res = mMaterial->createConfiguration(configuration, lodIndex);
|
||||
if (!res)
|
||||
return; // listener was false positive
|
||||
if (mFailedToCreate)
|
||||
return false;
|
||||
try{
|
||||
mMaterial->ensureLoaded();
|
||||
bool res = mMaterial->createConfiguration(configuration, lodIndex);
|
||||
if (!res)
|
||||
return false; // listener was false positive
|
||||
|
||||
if (mListener)
|
||||
mListener->requestedConfiguration (this, configuration);
|
||||
if (mListener)
|
||||
mListener->requestedConfiguration (this, configuration);
|
||||
|
||||
mFactory->setActiveConfiguration (configuration);
|
||||
mFactory->setActiveLodLevel (lodIndex);
|
||||
mFactory->setActiveConfiguration (configuration);
|
||||
mFactory->setActiveLodLevel (lodIndex);
|
||||
|
||||
bool allowFixedFunction = true;
|
||||
if (!mShadersEnabled && hasProperty("allow_fixed_function"))
|
||||
{
|
||||
allowFixedFunction = retrieveValue<BooleanValue>(getProperty("allow_fixed_function"), NULL).get();
|
||||
}
|
||||
|
||||
bool useShaders = mShadersEnabled || !allowFixedFunction;
|
||||
|
||||
// get passes of the top-most parent
|
||||
PassVector passes = getPasses();
|
||||
if (passes.size() == 0)
|
||||
throw std::runtime_error ("material \"" + mName + "\" does not have any passes");
|
||||
|
||||
for (PassVector::iterator it = passes.begin(); it != passes.end(); ++it)
|
||||
{
|
||||
boost::shared_ptr<Pass> pass = mMaterial->createPass (configuration, lodIndex);
|
||||
it->copyAll (pass.get(), this);
|
||||
|
||||
// texture samplers used in the shaders
|
||||
std::vector<std::string> usedTextureSamplersVertex;
|
||||
std::vector<std::string> usedTextureSamplersFragment;
|
||||
|
||||
PropertySetGet* context = this;
|
||||
|
||||
// create or retrieve shaders
|
||||
bool hasVertex = it->hasProperty("vertex_program");
|
||||
bool hasFragment = it->hasProperty("fragment_program");
|
||||
if (useShaders)
|
||||
bool allowFixedFunction = true;
|
||||
if (!mShadersEnabled && hasProperty("allow_fixed_function"))
|
||||
{
|
||||
it->setContext(context);
|
||||
it->mShaderProperties.setContext(context);
|
||||
if (hasVertex)
|
||||
allowFixedFunction = retrieveValue<BooleanValue>(getProperty("allow_fixed_function"), NULL).get();
|
||||
}
|
||||
|
||||
bool useShaders = mShadersEnabled || !allowFixedFunction;
|
||||
|
||||
// get passes of the top-most parent
|
||||
PassVector* passes = getParentPasses();
|
||||
if (passes->empty())
|
||||
throw std::runtime_error ("material \"" + mName + "\" does not have any passes");
|
||||
|
||||
for (PassVector::iterator it = passes->begin(); it != passes->end(); ++it)
|
||||
{
|
||||
boost::shared_ptr<Pass> pass = mMaterial->createPass (configuration, lodIndex);
|
||||
it->copyAll (pass.get(), this);
|
||||
|
||||
// texture samplers used in the shaders
|
||||
std::vector<std::string> usedTextureSamplersVertex;
|
||||
std::vector<std::string> usedTextureSamplersFragment;
|
||||
|
||||
PropertySetGet* context = this;
|
||||
|
||||
// create or retrieve shaders
|
||||
bool hasVertex = it->hasProperty("vertex_program")
|
||||
&& !retrieveValue<StringValue>(it->getProperty("vertex_program"), context).get().empty();
|
||||
bool hasFragment = it->hasProperty("fragment_program")
|
||||
&& !retrieveValue<StringValue>(it->getProperty("fragment_program"), context).get().empty();
|
||||
if (useShaders)
|
||||
{
|
||||
ShaderSet* vertex = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("vertex_program"), context).get());
|
||||
ShaderInstance* v = vertex->getInstance(&it->mShaderProperties);
|
||||
if (v)
|
||||
it->setContext(context);
|
||||
it->mShaderProperties.setContext(context);
|
||||
if (hasVertex)
|
||||
{
|
||||
pass->assignProgram (GPT_Vertex, v->getName());
|
||||
v->setUniformParameters (pass, &it->mShaderProperties);
|
||||
|
||||
std::vector<std::string> sharedParams = v->getSharedParameters ();
|
||||
for (std::vector<std::string>::iterator it = sharedParams.begin(); it != sharedParams.end(); ++it)
|
||||
ShaderSet* vertex = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("vertex_program"), context).get());
|
||||
ShaderInstance* v = vertex->getInstance(&it->mShaderProperties);
|
||||
if (v)
|
||||
{
|
||||
pass->addSharedParameter (GPT_Vertex, *it);
|
||||
}
|
||||
pass->assignProgram (GPT_Vertex, v->getName());
|
||||
v->setUniformParameters (pass, &it->mShaderProperties);
|
||||
|
||||
std::vector<std::string> vector = v->getUsedSamplers ();
|
||||
usedTextureSamplersVertex.insert(usedTextureSamplersVertex.end(), vector.begin(), vector.end());
|
||||
std::vector<std::string> sharedParams = v->getSharedParameters ();
|
||||
for (std::vector<std::string>::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2)
|
||||
{
|
||||
pass->addSharedParameter (GPT_Vertex, *it2);
|
||||
}
|
||||
|
||||
std::vector<std::string> vector = v->getUsedSamplers ();
|
||||
usedTextureSamplersVertex.insert(usedTextureSamplersVertex.end(), vector.begin(), vector.end());
|
||||
}
|
||||
}
|
||||
if (hasFragment)
|
||||
{
|
||||
ShaderSet* fragment = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("fragment_program"), context).get());
|
||||
ShaderInstance* f = fragment->getInstance(&it->mShaderProperties);
|
||||
if (f)
|
||||
{
|
||||
pass->assignProgram (GPT_Fragment, f->getName());
|
||||
f->setUniformParameters (pass, &it->mShaderProperties);
|
||||
|
||||
std::vector<std::string> sharedParams = f->getSharedParameters ();
|
||||
for (std::vector<std::string>::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2)
|
||||
{
|
||||
pass->addSharedParameter (GPT_Fragment, *it2);
|
||||
}
|
||||
|
||||
std::vector<std::string> vector = f->getUsedSamplers ();
|
||||
usedTextureSamplersFragment.insert(usedTextureSamplersFragment.end(), vector.begin(), vector.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasFragment)
|
||||
|
||||
// create texture units
|
||||
std::vector<MaterialInstanceTextureUnit>* texUnits = &it->mTexUnits;
|
||||
int i=0;
|
||||
for (std::vector<MaterialInstanceTextureUnit>::iterator texIt = texUnits->begin(); texIt != texUnits->end(); ++texIt )
|
||||
{
|
||||
ShaderSet* fragment = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("fragment_program"), context).get());
|
||||
ShaderInstance* f = fragment->getInstance(&it->mShaderProperties);
|
||||
if (f)
|
||||
// only create those that are needed by the shader, OR those marked to be created in fixed function pipeline if shaders are disabled
|
||||
bool foundVertex = std::find(usedTextureSamplersVertex.begin(), usedTextureSamplersVertex.end(), texIt->getName()) != usedTextureSamplersVertex.end();
|
||||
bool foundFragment = std::find(usedTextureSamplersFragment.begin(), usedTextureSamplersFragment.end(), texIt->getName()) != usedTextureSamplersFragment.end();
|
||||
if ( (foundVertex || foundFragment)
|
||||
|| (((!useShaders || (!hasVertex || !hasFragment)) && allowFixedFunction) && texIt->hasProperty("create_in_ffp") && retrieveValue<BooleanValue>(texIt->getProperty("create_in_ffp"), this).get()))
|
||||
{
|
||||
pass->assignProgram (GPT_Fragment, f->getName());
|
||||
f->setUniformParameters (pass, &it->mShaderProperties);
|
||||
boost::shared_ptr<TextureUnitState> texUnit = pass->createTextureUnitState (texIt->getName());
|
||||
texIt->copyAll (texUnit.get(), context);
|
||||
|
||||
std::vector<std::string> sharedParams = f->getSharedParameters ();
|
||||
for (std::vector<std::string>::iterator it = sharedParams.begin(); it != sharedParams.end(); ++it)
|
||||
mTexUnits.push_back(texUnit);
|
||||
|
||||
// set texture unit indices (required by GLSL)
|
||||
if (useShaders && ((hasVertex && foundVertex) || (hasFragment && foundFragment)) && mFactory->getCurrentLanguage () == Language_GLSL)
|
||||
{
|
||||
pass->addSharedParameter (GPT_Fragment, *it);
|
||||
}
|
||||
pass->setTextureUnitIndex (foundVertex ? GPT_Vertex : GPT_Fragment, texIt->getName(), i);
|
||||
|
||||
std::vector<std::string> vector = f->getUsedSamplers ();
|
||||
usedTextureSamplersFragment.insert(usedTextureSamplersFragment.end(), vector.begin(), vector.end());
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create texture units
|
||||
std::vector<MaterialInstanceTextureUnit> texUnits = it->getTexUnits();
|
||||
int i=0;
|
||||
for (std::vector<MaterialInstanceTextureUnit>::iterator texIt = texUnits.begin(); texIt != texUnits.end(); ++texIt )
|
||||
{
|
||||
// only create those that are needed by the shader, OR those marked to be created in fixed function pipeline if shaders are disabled
|
||||
bool foundVertex = std::find(usedTextureSamplersVertex.begin(), usedTextureSamplersVertex.end(), texIt->getName()) != usedTextureSamplersVertex.end();
|
||||
bool foundFragment = std::find(usedTextureSamplersFragment.begin(), usedTextureSamplersFragment.end(), texIt->getName()) != usedTextureSamplersFragment.end();
|
||||
if ( (foundVertex || foundFragment)
|
||||
|| (((!useShaders || (!hasVertex || !hasFragment)) && allowFixedFunction) && texIt->hasProperty("create_in_ffp") && retrieveValue<BooleanValue>(texIt->getProperty("create_in_ffp"), this).get()))
|
||||
{
|
||||
boost::shared_ptr<TextureUnitState> texUnit = pass->createTextureUnitState ();
|
||||
texIt->copyAll (texUnit.get(), context);
|
||||
if (mListener)
|
||||
mListener->createdConfiguration (this, configuration);
|
||||
return true;
|
||||
|
||||
mTexUnits.push_back(texUnit);
|
||||
|
||||
// set texture unit indices (required by GLSL)
|
||||
if (useShaders && ((hasVertex && foundVertex) || (hasFragment && foundFragment)) && mFactory->getCurrentLanguage () == Language_GLSL)
|
||||
{
|
||||
pass->setTextureUnitIndex (foundVertex ? GPT_Vertex : GPT_Fragment, texIt->getName(), i);
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (std::runtime_error& e)
|
||||
{
|
||||
destroyAll();
|
||||
mFailedToCreate = true;
|
||||
std::stringstream msg;
|
||||
msg << "Error while creating material " << mName << ": " << e.what();
|
||||
std::cerr << msg.str() << std::endl;
|
||||
mFactory->logError(msg.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mListener)
|
||||
mListener->createdConfiguration (this, configuration);
|
||||
}
|
||||
|
||||
Material* MaterialInstance::getMaterial ()
|
||||
@ -180,12 +201,23 @@ namespace sh
|
||||
return &mPasses.back();
|
||||
}
|
||||
|
||||
PassVector MaterialInstance::getPasses()
|
||||
void MaterialInstance::deletePass(unsigned int index)
|
||||
{
|
||||
assert(mPasses.size() > index);
|
||||
mPasses.erase(mPasses.begin()+index);
|
||||
}
|
||||
|
||||
PassVector* MaterialInstance::getParentPasses()
|
||||
{
|
||||
if (mParent)
|
||||
return static_cast<MaterialInstance*>(mParent)->getPasses();
|
||||
return static_cast<MaterialInstance*>(mParent)->getParentPasses();
|
||||
else
|
||||
return mPasses;
|
||||
return &mPasses;
|
||||
}
|
||||
|
||||
PassVector* MaterialInstance::getPasses()
|
||||
{
|
||||
return &mPasses;
|
||||
}
|
||||
|
||||
void MaterialInstance::setShadersEnabled (bool enabled)
|
||||
@ -206,7 +238,7 @@ namespace sh
|
||||
|
||||
if (mParent)
|
||||
{
|
||||
stream << "\t" << static_cast<MaterialInstance*>(mParent)->getName() << "\n";
|
||||
stream << "\t" << "parent " << static_cast<MaterialInstance*>(mParent)->getName() << "\n";
|
||||
}
|
||||
|
||||
const PropertyMap& properties = listProperties ();
|
||||
@ -215,6 +247,14 @@ namespace sh
|
||||
stream << "\t" << it->first << " " << retrieveValue<StringValue>(getProperty(it->first), NULL).get() << "\n";
|
||||
}
|
||||
|
||||
for (PassVector::iterator it = mPasses.begin(); it != mPasses.end(); ++it)
|
||||
{
|
||||
stream << "\tpass" << '\n';
|
||||
stream << "\t{" << '\n';
|
||||
it->save(stream);
|
||||
stream << "\t}" << '\n';
|
||||
}
|
||||
|
||||
stream << "}\n";
|
||||
}
|
||||
}
|
||||
|
32
extern/shiny/Main/MaterialInstance.hpp
vendored
32
extern/shiny/Main/MaterialInstance.hpp
vendored
@ -41,8 +41,12 @@ namespace sh
|
||||
MaterialInstance (const std::string& name, Factory* f);
|
||||
virtual ~MaterialInstance ();
|
||||
|
||||
PassVector* getParentPasses(); ///< gets the passes of the top-most parent
|
||||
|
||||
PassVector* getPasses(); ///< get our passes (for derived materials, none)
|
||||
|
||||
MaterialInstancePass* createPass ();
|
||||
PassVector getPasses(); ///< gets the passes of the top-most parent
|
||||
void deletePass (unsigned int index);
|
||||
|
||||
/// @attention Because the backend material passes are created on demand, the returned material here might not contain anything yet!
|
||||
/// The only place where you should use this method, is for the MaterialInstance given by the MaterialListener::materialCreated event!
|
||||
@ -55,25 +59,25 @@ namespace sh
|
||||
|
||||
virtual void setProperty (const std::string& name, PropertyValuePtr value);
|
||||
|
||||
private:
|
||||
void setParentInstance (const std::string& name);
|
||||
std::string getParentInstance ();
|
||||
|
||||
void create (Platform* platform);
|
||||
void createForConfiguration (const std::string& configuration, unsigned short lodIndex);
|
||||
|
||||
void destroyAll ();
|
||||
|
||||
void setShadersEnabled (bool enabled);
|
||||
|
||||
void setSourceFile(const std::string& sourceFile) { mSourceFile = sourceFile; }
|
||||
|
||||
std::string getSourceFile() { return mSourceFile; }
|
||||
///< get the name of the file this material was read from, or empty if it was created dynamically by code
|
||||
|
||||
private:
|
||||
void setParentInstance (const std::string& name);
|
||||
std::string getParentInstance ();
|
||||
|
||||
void create (Platform* platform);
|
||||
bool createForConfiguration (const std::string& configuration, unsigned short lodIndex);
|
||||
|
||||
void destroyAll ();
|
||||
|
||||
void setShadersEnabled (bool enabled);
|
||||
|
||||
void save (std::ofstream& stream);
|
||||
///< this will only save the properties, not the passes and texture units, and as such
|
||||
/// is only intended to be used for derived materials
|
||||
|
||||
bool mFailedToCreate;
|
||||
|
||||
friend class Factory;
|
||||
|
||||
|
23
extern/shiny/Main/MaterialInstancePass.cpp
vendored
23
extern/shiny/Main/MaterialInstancePass.cpp
vendored
@ -1,5 +1,7 @@
|
||||
#include "MaterialInstancePass.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
@ -9,8 +11,25 @@ namespace sh
|
||||
return &mTexUnits.back();
|
||||
}
|
||||
|
||||
std::vector <MaterialInstanceTextureUnit> MaterialInstancePass::getTexUnits ()
|
||||
void MaterialInstancePass::save(std::ofstream &stream)
|
||||
{
|
||||
return mTexUnits;
|
||||
if (mShaderProperties.listProperties().size())
|
||||
{
|
||||
stream << "\t\t" << "shader_properties" << '\n';
|
||||
stream << "\t\t{\n";
|
||||
mShaderProperties.save(stream, "\t\t\t");
|
||||
stream << "\t\t}\n";
|
||||
}
|
||||
|
||||
PropertySetGet::save(stream, "\t\t");
|
||||
|
||||
for (std::vector <MaterialInstanceTextureUnit>::iterator it = mTexUnits.begin();
|
||||
it != mTexUnits.end(); ++it)
|
||||
{
|
||||
stream << "\t\ttexture_unit " << it->getName() << '\n';
|
||||
stream << "\t\t{\n";
|
||||
it->save(stream, "\t\t\t");
|
||||
stream << "\t\t}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
4
extern/shiny/Main/MaterialInstancePass.hpp
vendored
4
extern/shiny/Main/MaterialInstancePass.hpp
vendored
@ -18,10 +18,10 @@ namespace sh
|
||||
public:
|
||||
MaterialInstanceTextureUnit* createTextureUnit (const std::string& name);
|
||||
|
||||
void save (std::ofstream& stream);
|
||||
|
||||
PropertySetGet mShaderProperties;
|
||||
|
||||
std::vector <MaterialInstanceTextureUnit> getTexUnits ();
|
||||
private:
|
||||
std::vector <MaterialInstanceTextureUnit> mTexUnits;
|
||||
};
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ namespace sh
|
||||
public:
|
||||
MaterialInstanceTextureUnit (const std::string& name);
|
||||
std::string getName() const;
|
||||
void setName (const std::string& name) { mName = name; }
|
||||
private:
|
||||
std::string mName;
|
||||
};
|
||||
|
7
extern/shiny/Main/Platform.cpp
vendored
7
extern/shiny/Main/Platform.cpp
vendored
@ -9,7 +9,7 @@ namespace sh
|
||||
Platform::Platform (const std::string& basePath)
|
||||
: mBasePath(basePath)
|
||||
, mCacheFolder("./")
|
||||
, mShaderCachingEnabled(false)
|
||||
, mFactory(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@ -57,11 +57,6 @@ namespace sh
|
||||
mCacheFolder = folder;
|
||||
}
|
||||
|
||||
void Platform::setShaderCachingEnabled (bool enabled)
|
||||
{
|
||||
mShaderCachingEnabled = enabled;
|
||||
}
|
||||
|
||||
std::string Platform::getCacheFolder() const
|
||||
{
|
||||
return mCacheFolder;
|
||||
|
17
extern/shiny/Main/Platform.hpp
vendored
17
extern/shiny/Main/Platform.hpp
vendored
@ -24,6 +24,7 @@ namespace sh
|
||||
class GpuProgram
|
||||
{
|
||||
public:
|
||||
virtual ~GpuProgram() {}
|
||||
virtual bool getSupported () = 0; ///< @return true if the compilation was successful
|
||||
|
||||
/// @param name name of the uniform in the shader
|
||||
@ -35,8 +36,7 @@ namespace sh
|
||||
class TextureUnitState : public PropertySet
|
||||
{
|
||||
public:
|
||||
virtual ~TextureUnitState();
|
||||
|
||||
virtual ~TextureUnitState();
|
||||
virtual void setTextureName (const std::string& textureName) = 0;
|
||||
|
||||
protected:
|
||||
@ -46,7 +46,7 @@ namespace sh
|
||||
class Pass : public PropertySet
|
||||
{
|
||||
public:
|
||||
virtual boost::shared_ptr<TextureUnitState> createTextureUnitState () = 0;
|
||||
virtual boost::shared_ptr<TextureUnitState> createTextureUnitState (const std::string& name) = 0;
|
||||
virtual void assignProgram (GpuProgramType type, const std::string& name) = 0;
|
||||
|
||||
/// @param type gpu program type
|
||||
@ -68,6 +68,9 @@ namespace sh
|
||||
virtual bool createConfiguration (const std::string& name, unsigned short lodIndex) = 0; ///< @return false if already exists
|
||||
virtual void removeAll () = 0; ///< remove all configurations
|
||||
|
||||
virtual bool isUnreferenced() = 0;
|
||||
virtual void ensureLoaded() = 0;
|
||||
|
||||
virtual void setLodLevels (const std::string& lodLevels) = 0;
|
||||
|
||||
virtual void setShadowCasterMaterial (const std::string& name) = 0;
|
||||
@ -79,8 +82,6 @@ namespace sh
|
||||
Platform (const std::string& basePath);
|
||||
virtual ~Platform ();
|
||||
|
||||
void setShaderCachingEnabled (bool enabled);
|
||||
|
||||
/// set the folder to use for shader caching
|
||||
void setCacheFolder (const std::string& folder);
|
||||
|
||||
@ -93,6 +94,8 @@ namespace sh
|
||||
const std::string& name, const std::string& profile,
|
||||
const std::string& source, Language lang) = 0;
|
||||
|
||||
virtual void destroyGpuProgram (const std::string& name) = 0;
|
||||
|
||||
virtual void setSharedParameter (const std::string& name, PropertyValuePtr value) = 0;
|
||||
|
||||
virtual bool isProfileSupported (const std::string& profile) = 0;
|
||||
@ -105,6 +108,7 @@ namespace sh
|
||||
friend class Factory;
|
||||
friend class MaterialInstance;
|
||||
friend class ShaderInstance;
|
||||
friend class ShaderSet;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@ -131,9 +135,6 @@ namespace sh
|
||||
std::string mCacheFolder;
|
||||
Factory* mFactory;
|
||||
|
||||
protected:
|
||||
bool mShaderCachingEnabled;
|
||||
|
||||
private:
|
||||
void setFactory (Factory* factory);
|
||||
|
||||
|
48
extern/shiny/Main/PropertyBase.cpp
vendored
48
extern/shiny/Main/PropertyBase.cpp
vendored
@ -6,6 +6,8 @@
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
@ -39,8 +41,9 @@ namespace sh
|
||||
mValue = false;
|
||||
else
|
||||
{
|
||||
std::cerr << "sh::BooleanValue: Warning: Unrecognized value \"" << in << "\" for property value of type BooleanValue" << std::endl;
|
||||
mValue = false;
|
||||
std::stringstream msg;
|
||||
msg << "sh::BooleanValue: Warning: Unrecognized value \"" << in << "\" for property value of type BooleanValue";
|
||||
throw std::runtime_error(msg.str());
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,12 +186,16 @@ namespace sh
|
||||
void PropertySet::setProperty (const std::string& name, PropertyValuePtr &value, PropertySetGet* context)
|
||||
{
|
||||
if (!setPropertyOverride (name, value, context))
|
||||
std::cerr << "sh::PropertySet: Warning: No match for property with name '" << name << "'" << std::endl;
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << "sh::PropertySet: Warning: No match for property with name '" << name << "'";
|
||||
throw std::runtime_error(msg.str());
|
||||
}
|
||||
}
|
||||
|
||||
bool PropertySet::setPropertyOverride (const std::string& name, PropertyValuePtr &value, PropertySetGet* context)
|
||||
{
|
||||
// if we got here, none of the sub-classes was able to make use of the property
|
||||
// if we got here, none of the sub-classes were able to make use of the property
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -226,6 +233,11 @@ namespace sh
|
||||
mProperties [name] = value;
|
||||
}
|
||||
|
||||
void PropertySetGet::deleteProperty(const std::string &name)
|
||||
{
|
||||
mProperties.erase(name);
|
||||
}
|
||||
|
||||
PropertyValuePtr& PropertySetGet::getProperty (const std::string& name)
|
||||
{
|
||||
bool found = (mProperties.find(name) != mProperties.end());
|
||||
@ -241,7 +253,7 @@ namespace sh
|
||||
return mProperties[name];
|
||||
}
|
||||
|
||||
bool PropertySetGet::hasProperty (const std::string& name)
|
||||
bool PropertySetGet::hasProperty (const std::string& name) const
|
||||
{
|
||||
bool found = (mProperties.find(name) != mProperties.end());
|
||||
|
||||
@ -256,13 +268,35 @@ namespace sh
|
||||
return true;
|
||||
}
|
||||
|
||||
void PropertySetGet::copyAll (PropertySet* target, PropertySetGet* context)
|
||||
void PropertySetGet::copyAll (PropertySet* target, PropertySetGet* context, bool copyParent)
|
||||
{
|
||||
if (mParent)
|
||||
if (mParent && copyParent)
|
||||
mParent->copyAll (target, context);
|
||||
for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it)
|
||||
{
|
||||
target->setProperty(it->first, it->second, context);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertySetGet::copyAll (PropertySetGet* target, PropertySetGet* context, bool copyParent)
|
||||
{
|
||||
if (mParent && copyParent)
|
||||
mParent->copyAll (target, context);
|
||||
for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it)
|
||||
{
|
||||
std::string val = retrieveValue<StringValue>(it->second, this).get();
|
||||
target->setProperty(it->first, sh::makeProperty(new sh::StringValue(val)));
|
||||
}
|
||||
}
|
||||
|
||||
void PropertySetGet::save(std::ofstream &stream, const std::string& indentation)
|
||||
{
|
||||
for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it)
|
||||
{
|
||||
if (typeid( *(it->second) ) == typeid(LinkedValue))
|
||||
stream << indentation << it->first << " " << "$" + static_cast<LinkedValue*>(&*(it->second))->_getStringValue() << '\n';
|
||||
else
|
||||
stream << indentation << it->first << " " << retrieveValue<StringValue>(it->second, this).get() << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
extern/shiny/Main/PropertyBase.hpp
vendored
15
extern/shiny/Main/PropertyBase.hpp
vendored
@ -133,6 +133,7 @@ namespace sh
|
||||
class PropertySet
|
||||
{
|
||||
public:
|
||||
virtual ~PropertySet() {}
|
||||
void setProperty (const std::string& name, PropertyValuePtr& value, PropertySetGet* context);
|
||||
|
||||
protected:
|
||||
@ -151,18 +152,26 @@ namespace sh
|
||||
|
||||
virtual ~PropertySetGet() {}
|
||||
|
||||
void copyAll (PropertySet* target, PropertySetGet* context); ///< call setProperty for each property/value pair stored in \a this
|
||||
void save (std::ofstream& stream, const std::string& indentation);
|
||||
|
||||
void copyAll (PropertySet* target, PropertySetGet* context, bool copyParent=true);
|
||||
///< call setProperty for each property/value pair stored in \a this
|
||||
void copyAll (PropertySetGet* target, PropertySetGet* context, bool copyParent=true);
|
||||
///< call setProperty for each property/value pair stored in \a this
|
||||
|
||||
void setParent (PropertySetGet* parent);
|
||||
PropertySetGet* getParent () { return mParent; }
|
||||
void setContext (PropertySetGet* context);
|
||||
PropertySetGet* getContext();
|
||||
|
||||
virtual void setProperty (const std::string& name, PropertyValuePtr value);
|
||||
PropertyValuePtr& getProperty (const std::string& name);
|
||||
|
||||
void deleteProperty (const std::string& name);
|
||||
|
||||
const PropertyMap& listProperties() { return mProperties; }
|
||||
|
||||
bool hasProperty (const std::string& name);
|
||||
bool hasProperty (const std::string& name) const;
|
||||
|
||||
private:
|
||||
PropertyMap mProperties;
|
||||
@ -225,7 +234,7 @@ namespace sh
|
||||
|
||||
template <typename T>
|
||||
/// Create a property of any type
|
||||
/// Example: sh::makeProperty\<sh::Vector4\> (new sh::Vector4(1, 1, 1, 1))
|
||||
/// Example: sh::makeProperty (new sh::Vector4(1, 1, 1, 1))
|
||||
inline PropertyValuePtr makeProperty (T* p)
|
||||
{
|
||||
return PropertyValuePtr ( static_cast<PropertyValue*>(p) );
|
||||
|
23
extern/shiny/Main/ScriptLoader.cpp
vendored
23
extern/shiny/Main/ScriptLoader.cpp
vendored
@ -24,6 +24,10 @@ namespace sh
|
||||
}
|
||||
|
||||
ScriptLoader::ScriptLoader(const std::string& fileEnding)
|
||||
: mLoadOrder(0)
|
||||
, mToken(TOKEN_NewLine)
|
||||
, mLastToken(TOKEN_NewLine)
|
||||
|
||||
{
|
||||
mFileEnding = fileEnding;
|
||||
}
|
||||
@ -36,7 +40,7 @@ namespace sh
|
||||
void ScriptLoader::clearScriptList()
|
||||
{
|
||||
std::map <std::string, ScriptNode *>::iterator i;
|
||||
for (i = m_scriptList.begin(); i != m_scriptList.end(); i++)
|
||||
for (i = m_scriptList.begin(); i != m_scriptList.end(); ++i)
|
||||
{
|
||||
delete i->second;
|
||||
}
|
||||
@ -293,7 +297,7 @@ namespace sh
|
||||
{
|
||||
//Delete all children
|
||||
std::vector<ScriptNode*>::iterator i;
|
||||
for (i = mChildren.begin(); i != mChildren.end(); i++)
|
||||
for (i = mChildren.begin(); i != mChildren.end(); ++i)
|
||||
{
|
||||
ScriptNode *node = *i;
|
||||
node->mRemoveSelf = false;
|
||||
@ -323,15 +327,24 @@ namespace sh
|
||||
|
||||
ScriptNode *ScriptNode::findChild(const std::string &name, bool recursive)
|
||||
{
|
||||
int indx, prevC, nextC;
|
||||
int indx;
|
||||
int childCount = (int)mChildren.size();
|
||||
|
||||
if (mLastChildFound != -1)
|
||||
{
|
||||
//If possible, try checking the nodes neighboring the last successful search
|
||||
//(often nodes searched for in sequence, so this will boost search speeds).
|
||||
prevC = mLastChildFound-1; if (prevC < 0) prevC = 0; else if (prevC >= childCount) prevC = childCount-1;
|
||||
nextC = mLastChildFound+1; if (nextC < 0) nextC = 0; else if (nextC >= childCount) nextC = childCount-1;
|
||||
int prevC = mLastChildFound-1;
|
||||
if (prevC < 0)
|
||||
prevC = 0;
|
||||
else if (prevC >= childCount)
|
||||
prevC = childCount-1;
|
||||
int nextC = mLastChildFound+1;
|
||||
if (nextC < 0)
|
||||
nextC = 0;
|
||||
else if (nextC >= childCount)
|
||||
nextC = childCount-1;
|
||||
|
||||
for (indx = prevC; indx <= nextC; ++indx)
|
||||
{
|
||||
ScriptNode *node = mChildren[indx];
|
||||
|
8
extern/shiny/Main/ShaderSet.cpp
vendored
8
extern/shiny/Main/ShaderSet.cpp
vendored
@ -37,6 +37,14 @@ namespace sh
|
||||
parse();
|
||||
}
|
||||
|
||||
ShaderSet::~ShaderSet()
|
||||
{
|
||||
for (ShaderInstanceMap::iterator it = mInstances.begin(); it != mInstances.end(); ++it)
|
||||
{
|
||||
sh::Factory::getInstance().getPlatform()->destroyGpuProgram(it->second.getName());
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderSet::parse()
|
||||
{
|
||||
std::string currentToken;
|
||||
|
1
extern/shiny/Main/ShaderSet.hpp
vendored
1
extern/shiny/Main/ShaderSet.hpp
vendored
@ -21,6 +21,7 @@ namespace sh
|
||||
public:
|
||||
ShaderSet (const std::string& type, const std::string& cgProfile, const std::string& hlslProfile, const std::string& sourceFile, const std::string& basePath,
|
||||
const std::string& name, PropertySetGet* globalSettingsPtr);
|
||||
~ShaderSet();
|
||||
|
||||
/// Retrieve a shader instance for the given properties. \n
|
||||
/// If a \a ShaderInstance with the same properties exists already, simply returns this instance. \n
|
||||
|
18
extern/shiny/Platforms/Ogre/OgreMaterial.cpp
vendored
18
extern/shiny/Platforms/Ogre/OgreMaterial.cpp
vendored
@ -15,6 +15,7 @@ namespace sh
|
||||
OgreMaterial::OgreMaterial (const std::string& name, const std::string& resourceGroup)
|
||||
: Material()
|
||||
{
|
||||
mName = name;
|
||||
assert (Ogre::MaterialManager::getSingleton().getByName(name).isNull() && "Material already exists");
|
||||
mMaterial = Ogre::MaterialManager::getSingleton().create (name, resourceGroup);
|
||||
mMaterial->removeAllTechniques();
|
||||
@ -22,9 +23,22 @@ namespace sh
|
||||
mMaterial->compile();
|
||||
}
|
||||
|
||||
void OgreMaterial::ensureLoaded()
|
||||
{
|
||||
if (mMaterial.isNull())
|
||||
mMaterial = Ogre::MaterialManager::getSingleton().getByName(mName);
|
||||
}
|
||||
|
||||
bool OgreMaterial::isUnreferenced()
|
||||
{
|
||||
// Resource system internals hold 3 shared pointers, we hold one, so usecount of 4 means unused
|
||||
return (!mMaterial.isNull() && mMaterial.useCount() <= Ogre::ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS+1);
|
||||
}
|
||||
|
||||
OgreMaterial::~OgreMaterial()
|
||||
{
|
||||
Ogre::MaterialManager::getSingleton().remove(mMaterial->getName());
|
||||
if (!mMaterial.isNull())
|
||||
Ogre::MaterialManager::getSingleton().remove(mMaterial->getName());
|
||||
}
|
||||
|
||||
boost::shared_ptr<Pass> OgreMaterial::createPass (const std::string& configuration, unsigned short lodIndex)
|
||||
@ -34,6 +48,8 @@ namespace sh
|
||||
|
||||
void OgreMaterial::removeAll ()
|
||||
{
|
||||
if (mMaterial.isNull())
|
||||
return;
|
||||
mMaterial->removeAllTechniques();
|
||||
mMaterial->createTechnique()->setSchemeName (sDefaultTechniqueName);
|
||||
mMaterial->compile();
|
||||
|
4
extern/shiny/Platforms/Ogre/OgreMaterial.hpp
vendored
4
extern/shiny/Platforms/Ogre/OgreMaterial.hpp
vendored
@ -18,6 +18,9 @@ namespace sh
|
||||
virtual boost::shared_ptr<Pass> createPass (const std::string& configuration, unsigned short lodIndex);
|
||||
virtual bool createConfiguration (const std::string& name, unsigned short lodIndex);
|
||||
|
||||
virtual bool isUnreferenced();
|
||||
virtual void ensureLoaded();
|
||||
|
||||
virtual void removeAll ();
|
||||
|
||||
Ogre::MaterialPtr getOgreMaterial();
|
||||
@ -30,6 +33,7 @@ namespace sh
|
||||
|
||||
private:
|
||||
Ogre::MaterialPtr mMaterial;
|
||||
std::string mName;
|
||||
|
||||
std::string mShadowCasterMaterial;
|
||||
};
|
||||
|
16
extern/shiny/Platforms/Ogre/OgrePass.cpp
vendored
16
extern/shiny/Platforms/Ogre/OgrePass.cpp
vendored
@ -20,9 +20,9 @@ namespace sh
|
||||
mPass = t->createPass();
|
||||
}
|
||||
|
||||
boost::shared_ptr<TextureUnitState> OgrePass::createTextureUnitState ()
|
||||
boost::shared_ptr<TextureUnitState> OgrePass::createTextureUnitState (const std::string& name)
|
||||
{
|
||||
return boost::shared_ptr<TextureUnitState> (new OgreTextureUnitState (this));
|
||||
return boost::shared_ptr<TextureUnitState> (new OgreTextureUnitState (this, name));
|
||||
}
|
||||
|
||||
void OgrePass::assignProgram (GpuProgramType type, const std::string& name)
|
||||
@ -105,7 +105,17 @@ namespace sh
|
||||
else if (type == GPT_Fragment)
|
||||
params = mPass->getFragmentProgramParameters();
|
||||
|
||||
params->addSharedParameters (name);
|
||||
try
|
||||
{
|
||||
params->addSharedParameters (name);
|
||||
}
|
||||
catch (Ogre::Exception& e)
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << "Could not create a shared parameter instance for '"
|
||||
<< name << "'. Make sure this shared parameter has a value set (via Factory::setSharedParameter)!";
|
||||
throw std::runtime_error(msg.str());
|
||||
}
|
||||
}
|
||||
|
||||
void OgrePass::setTextureUnitIndex (int programType, const std::string& name, int index)
|
||||
|
2
extern/shiny/Platforms/Ogre/OgrePass.hpp
vendored
2
extern/shiny/Platforms/Ogre/OgrePass.hpp
vendored
@ -14,7 +14,7 @@ namespace sh
|
||||
public:
|
||||
OgrePass (OgreMaterial* parent, const std::string& configuration, unsigned short lodIndex);
|
||||
|
||||
virtual boost::shared_ptr<TextureUnitState> createTextureUnitState ();
|
||||
virtual boost::shared_ptr<TextureUnitState> createTextureUnitState (const std::string& name);
|
||||
virtual void assignProgram (GpuProgramType type, const std::string& name);
|
||||
|
||||
Ogre::Pass* getOgrePass();
|
||||
|
7
extern/shiny/Platforms/Ogre/OgrePlatform.cpp
vendored
7
extern/shiny/Platforms/Ogre/OgrePlatform.cpp
vendored
@ -4,6 +4,7 @@
|
||||
|
||||
#include <OgreDataStream.h>
|
||||
#include <OgreGpuProgramManager.h>
|
||||
#include <OgreHighLevelGpuProgramManager.h>
|
||||
#include <OgreRoot.h>
|
||||
|
||||
#include "OgreMaterial.hpp"
|
||||
@ -76,6 +77,11 @@ namespace sh
|
||||
return boost::shared_ptr<Material> (material);
|
||||
}
|
||||
|
||||
void OgrePlatform::destroyGpuProgram(const std::string &name)
|
||||
{
|
||||
Ogre::HighLevelGpuProgramManager::getSingleton().remove(name);
|
||||
}
|
||||
|
||||
boost::shared_ptr<GpuProgram> OgrePlatform::createGpuProgram (
|
||||
GpuProgramType type,
|
||||
const std::string& compileArguments,
|
||||
@ -122,6 +128,7 @@ namespace sh
|
||||
if (mSharedParameters.find(name) == mSharedParameters.end())
|
||||
{
|
||||
params = Ogre::GpuProgramManager::getSingleton().createSharedParameters(name);
|
||||
|
||||
Ogre::GpuConstantType type;
|
||||
if (typeid(*value) == typeid(Vector4))
|
||||
type = Ogre::GCT_FLOAT4;
|
||||
|
2
extern/shiny/Platforms/Ogre/OgrePlatform.hpp
vendored
2
extern/shiny/Platforms/Ogre/OgrePlatform.hpp
vendored
@ -47,6 +47,8 @@ namespace sh
|
||||
const std::string& name, const std::string& profile,
|
||||
const std::string& source, Language lang);
|
||||
|
||||
virtual void destroyGpuProgram (const std::string& name);
|
||||
|
||||
virtual void setSharedParameter (const std::string& name, PropertyValuePtr value);
|
||||
|
||||
friend class ShaderInstance;
|
||||
|
@ -6,10 +6,11 @@
|
||||
|
||||
namespace sh
|
||||
{
|
||||
OgreTextureUnitState::OgreTextureUnitState (OgrePass* parent)
|
||||
OgreTextureUnitState::OgreTextureUnitState (OgrePass* parent, const std::string& name)
|
||||
: TextureUnitState()
|
||||
{
|
||||
mTextureUnitState = parent->getOgrePass()->createTextureUnitState("");
|
||||
mTextureUnitState->setName(name);
|
||||
}
|
||||
|
||||
bool OgreTextureUnitState::setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context)
|
||||
|
@ -12,7 +12,7 @@ namespace sh
|
||||
class OgreTextureUnitState : public TextureUnitState
|
||||
{
|
||||
public:
|
||||
OgreTextureUnitState (OgrePass* parent);
|
||||
OgreTextureUnitState (OgrePass* parent, const std::string& name);
|
||||
|
||||
virtual void setTextureName (const std::string& textureName);
|
||||
|
||||
|
@ -415,7 +415,7 @@
|
||||
float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel);
|
||||
#endif
|
||||
|
||||
#if SHADOWS
|
||||
#if SHADOWS || SHADOWS_PSSM
|
||||
shOutputColour(0) *= (lightResult - float4(directionalResult * (1.0-shadow),0));
|
||||
#else
|
||||
shOutputColour(0) *= lightResult;
|
||||
|
@ -5,14 +5,13 @@
|
||||
|
||||
<Widget type="Widget" skin="MW_Box" position="8 8 415 381" align="Stretch" name = "Client"/>
|
||||
|
||||
<!-- The Dialogue history -->
|
||||
<Widget type="DialogueHistory" skin="MW_TextBoxEdit" position="13 13 405 371" name="History" align="ALIGN_LEFT ALIGN_TOP ALIGN_STRETCH">
|
||||
<Property key="Static" value="true"/>
|
||||
<Property key="WordWrap" value="true"/>
|
||||
<Property key="MultiLine" value="1" />
|
||||
<Property key="VisibleVScroll" value="1" />
|
||||
<!-- box for receiving mouse events -->
|
||||
<Widget type="Widget" skin="" position="0 0 400 375" name="EventBox" align="ALIGN_LEFT ALIGN_TOP ALIGN_STRETCH"/>
|
||||
<Widget type="Widget" position="13 13 391 371" align="ALIGN_LEFT ALIGN_TOP ALIGN_STRETCH">
|
||||
<Widget type="BookPage" skin="MW_BookPage" position="0 0 391 371" name="History" align="ALIGN_LEFT ALIGN_TOP ALIGN_STRETCH">
|
||||
</Widget>
|
||||
</Widget>
|
||||
|
||||
<Widget type="ScrollBar" skin="MW_VScroll" position="404 13 14 371" align="ALIGN_RIGHT ALIGN_VSTRETCH" name="VScroll">
|
||||
<Property key="Visible" value="false"/>
|
||||
</Widget>
|
||||
|
||||
<!-- The disposition bar-->
|
||||
|
@ -23,6 +23,28 @@
|
||||
</Codes>
|
||||
</Resource>
|
||||
|
||||
<Resource type="ResourceTrueTypeFont" name="EB Garamond 24">
|
||||
<Property key="Source" value="EBGaramond-Regular.ttf"/>
|
||||
<Property key="Size" value="24"/>
|
||||
<Property key="Resolution" value="72"/>
|
||||
<Property key="Antialias" value="false"/>
|
||||
<Property key="TabWidth" value="8"/>
|
||||
<Property key="OffsetHeight" value="0"/>
|
||||
<Codes>
|
||||
<Code range="33 126"/>
|
||||
<Code range="160"/> <!-- Non-breaking space -->
|
||||
<Code range="192 382"/> <!-- Central and Eastern European languages glyphs -->
|
||||
<Code range="1025 1105"/>
|
||||
<Code range="2026"/> <!-- Ellipsis -->
|
||||
<Code range="8470"/>
|
||||
<Code range="8211"/> <!-- Minus -->
|
||||
<Code range="8216 8217"/> <!-- Single quotes -->
|
||||
<Code range="8220 8221"/> <!-- Right and Left Double Quotation mark -->
|
||||
<Code hide="128"/>
|
||||
<Code hide="1026 1039"/>
|
||||
<Code hide="1104"/>
|
||||
</Codes>
|
||||
</Resource>
|
||||
<Resource type="ResourceTrueTypeFont" name="Daedric">
|
||||
<!--<Property key="Source" value="Oblivion/Oblivion Worn.ttf"/>-->
|
||||
<Property key="Source" value="Oblivion/Oblivion.ttf"/>
|
||||
|
@ -2,24 +2,111 @@
|
||||
|
||||
<MyGUI type="Layout">
|
||||
|
||||
<Widget type="Window" skin="" layer="Windows" align="Left|Top" position="00 200 512 256" name="_Main">
|
||||
<Widget type="Window" skin="" layer="Windows" align="Left|Top" position="0 0 565 390" name="_Main">
|
||||
<!-- pages -->
|
||||
<Widget type="ImageBox" skin="ImageBox" position="0 0 565 390" align="Top|Right" name="JImage">
|
||||
<Property key="ImageTexture" value="textures\tx_menubook.dds"/>
|
||||
<Property key="ImageCoord" value="50 0 412 256"/>
|
||||
|
||||
<Widget type="ImageBox" skin="ImageBox" position_real="0 0 1 1" align="Top|Right" name="JImage">
|
||||
<Property key="ImageTexture" value="textures\tx_menubook.dds"/>
|
||||
<!-- buttons -->
|
||||
<Widget type="ImageButton" skin="ImageBox" position="40 350 64 32" name="OptionsBTN">
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_options_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_options_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_options_pressed.dds"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="NormalText" position="150 350 32 16" name="PageOneNum">
|
||||
<Property key="TextColour" value="0 0 0"/>
|
||||
</Widget>
|
||||
<Widget type="ImageButton" skin="ImageBox" position="220 350 48 32" name="PrevPageBTN">
|
||||
<Property key="ImageCoord" value="0 0 48 32"/>
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_prev_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_prev_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_prev_pressed.dds"/>
|
||||
</Widget>
|
||||
<Widget type="ImageButton" skin="ImageBox" position="300 350 48 32" name="NextPageBTN">
|
||||
<Property key="ImageCoord" value="0 0 48 32"/>
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_next_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_next_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_next_pressed.dds"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="NormalText" position="410 350 32 16" name="PageTwoNum">
|
||||
<Property key="TextColour" value="0 0 0"/>
|
||||
</Widget>
|
||||
<Widget type="ImageButton" skin="ImageBox" position="475 350 48 32" name="CloseBTN">
|
||||
<Property key="ImageCoord" value="0 0 48 32"/>
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_close_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_close_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_close_pressed.dds"/>
|
||||
</Widget>
|
||||
<Widget type="ImageButton" skin="ImageBox" position="460 350 64 32" name="JournalBTN">
|
||||
<Property key="ImageCoord" value="0 0 64 32"/>
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_journal_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_journal_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_journal_pressed.dds"/>
|
||||
</Widget>
|
||||
|
||||
|
||||
<!-- text pages -->
|
||||
<Widget type="BookPage" skin="MW_BookPage" position="30 22 240 300" name="LeftBookPage"/>
|
||||
<Widget type="BookPage" skin="MW_BookPage" position="300 22 240 300" name="RightBookPage"/>
|
||||
|
||||
<!-- options overlay -->
|
||||
|
||||
<Widget type="ImageButton" skin="ImageBox" position="370 220 128 32" name="NextPageBTN">
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_next_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_next_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_next_pressed.dds"/>
|
||||
</Widget>
|
||||
<Widget type="ImageButton" skin="ImageBox" position="80 220 128 32" name="PrevPageBTN">
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_prev_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_prev_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_prev_pressed.dds"/>
|
||||
</Widget>
|
||||
<Widget type="EditBox" skin="MW_BookPage" position_real="0.15 0.1 0.3 0.75" name = "LeftText"/>
|
||||
<Widget type="EditBox" skin="MW_BookPage" position_real="0.55 0.1 0.3 0.75" name = "RightText"/>
|
||||
</Widget>
|
||||
</Widget>
|
||||
|
||||
<!-- "options" -->
|
||||
<Widget type="ImageBox" skin="ImageBox" position="300 0 224 350" name="OptionsOverlay">
|
||||
<Property key="ImageTexture" value="textures\tx_menubook_bookmark.dds"/>
|
||||
<Property key="ImageCoord" value="0 0 164 256"/>
|
||||
|
||||
<Widget type="BookPage" skin="MW_BookPage" position="20 15 92 250" name="LeftTopicIndex"/>
|
||||
<Widget type="BookPage" skin="MW_BookPage" position="112 15 92 250" name="RightTopicIndex"/>
|
||||
|
||||
<Widget type="ScrollView" skin="MW_ScrollView" position="20 15 184 245" name="TopicsList" align="Right VStretch">
|
||||
<Property key="CanvasAlign" value="Left Top"/>
|
||||
<Widget type="BookPage" skin="MW_BookPage" position="0 0 30000 30000" name="TopicsPage"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="ScrollView" skin="MW_ScrollView" position="20 35 184 225" name="QuestsList" align="Right VStretch">
|
||||
<Property key="CanvasAlign" value="Left Top"/>
|
||||
<Widget type="BookPage" skin="MW_BookPage" position="0 0 30000 30000" name="QuestsPage"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="ImageButton" skin="ImageBox" position="62 15 100 20" Align="Top|Left" name="ShowActiveBTN">
|
||||
<Property key="ImageCoord" value="0 0 100 20"/>
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_quests_active_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_quests_active_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_quests_active_pressed.dds"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="ImageButton" skin="ImageBox" position="76 15 72 20" Align="Top|Left" name="ShowAllBTN">
|
||||
<Property key="ImageCoord" value="0 0 72 20"/>
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_quests_all_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_quests_all_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_quests_all_pressed.dds"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="ImageButton" skin="ImageBox" position="40 265 56 32" Align="Top|Left" name="TopicsBTN">
|
||||
<Property key="ImageCoord" value="0 0 56 32"/>
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_topics_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_topics_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_topics_pressed.dds"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="ImageButton" skin="ImageBox" position="130 265 56 32" Align="Top|Left" name="QuestsBTN">
|
||||
<Property key="ImageCoord" value="0 0 56 32"/>
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_quests_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_quests_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_quests_pressed.dds"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="ImageButton" skin="ImageBox" position="85 290 56 32" Align="Top|Left" name="CancelBTN">
|
||||
<Property key="ImageCoord" value="0 0 56 32"/>
|
||||
<Property key="ImageHighlighted" value="textures\tx_menubook_cancel_over.dds"/>
|
||||
<Property key="ImageNormal" value="textures\tx_menubook_cancel_idle.dds"/>
|
||||
<Property key="ImagePushed" value="textures\tx_menubook_cancel_pressed.dds"/>
|
||||
</Widget>
|
||||
|
||||
</Widget>
|
||||
</Widget>
|
||||
</MyGUI>
|
||||
|
@ -10,8 +10,6 @@
|
||||
</Skin>
|
||||
|
||||
<Skin name="MW_BookPage" size="0 0 50 50">
|
||||
<Property key="WordWrap" value = "true" />
|
||||
<Child type="TextBox" skin="MW_BookClient" offset="0 0 35 10" align = "ALIGN_STRETCH" name = "Client"/>
|
||||
<!--Child type="ScrollBar" skin="VScroll" offset = "35 0 15 50" align = "Right VStretch" name = "VScroll"/-->
|
||||
<BasisSkin type="PageDisplay"/>
|
||||
</Skin>
|
||||
</MyGUI>
|
||||
|
@ -16,7 +16,7 @@
|
||||
<Property key="Caption" value="#{sTransparency_Menu}"/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="4 28 352 18" align="Left Top" name="MenuTransparencySlider">
|
||||
<Property key="Range" value="1000000"/>
|
||||
<Property key="Range" value="100"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="SandText" position="4 52 352 18" align="Left Top">
|
||||
<Property key="Caption" value="#{sFull}"/>
|
||||
@ -31,7 +31,7 @@
|
||||
<Property key="Caption" value="#{sMenu_Help_Delay}"/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="4 102 352 18" align="Left Top" name="ToolTipDelaySlider">
|
||||
<Property key="Range" value="1000000"/>
|
||||
<Property key="Range" value="100"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="SandText" position="4 126 352 18" align="Left Top">
|
||||
<Property key="Caption" value="#{sFast}"/>
|
||||
@ -65,35 +65,35 @@
|
||||
<Property key="Caption" value="#{sMaster}"/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="4 28 352 18" align="Left Top" name="MasterVolume">
|
||||
<Property key="Range" value="1000000"/>
|
||||
<Property key="Range" value="100"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="TextBox" skin="NormalText" position="4 54 352 18" align="Left Top">
|
||||
<Property key="Caption" value="#{sVoice}"/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="4 78 352 18" align="Left Top" name="VoiceVolume">
|
||||
<Property key="Range" value="1000000"/>
|
||||
<Property key="Range" value="100"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="TextBox" skin="NormalText" position="4 104 352 18" align="Left Top">
|
||||
<Property key="Caption" value="#{sEffects}"/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="4 128 352 18" align="Left Top" name="EffectsVolume">
|
||||
<Property key="Range" value="1000000"/>
|
||||
<Property key="Range" value="100"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="TextBox" skin="NormalText" position="4 154 352 18" align="Left Top">
|
||||
<Property key="Caption" value="#{sFootsteps}"/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="4 178 352 18" align="Left Top" name="FootstepsVolume">
|
||||
<Property key="Range" value="1000000"/>
|
||||
<Property key="Range" value="100"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="TextBox" skin="NormalText" position="4 204 352 18" align="Left Top">
|
||||
<Property key="Caption" value="#{sMusic}"/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="4 228 352 18" align="Left Top" name="MusicVolume">
|
||||
<Property key="Range" value="1000000"/>
|
||||
<Property key="Range" value="100"/>
|
||||
</Widget>
|
||||
</Widget>
|
||||
<Widget type="TabItem" skin="" position="4 28 360 312">
|
||||
@ -118,7 +118,7 @@
|
||||
<Property key="Caption" value="UI cursor sensitivity"/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="4 252 160 18" align="Left Top" name="UISensitivitySlider">
|
||||
<Property key="Range" value="1000000"/>
|
||||
<Property key="Range" value="100"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="SandText" position="4 276 160 18" align="Left Top">
|
||||
<Property key="Caption" value="#{sLow}"/>
|
||||
@ -134,7 +134,7 @@
|
||||
<Property key="Caption" value="Camera sensitivity"/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="180 252 160 18" align="Left Top" name="CameraSensitivitySlider">
|
||||
<Property key="Range" value="1000000"/>
|
||||
<Property key="Range" value="100"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="SandText" position="180 276 160 18" align="Left Top">
|
||||
<Property key="Caption" value="#{sLow}"/>
|
||||
@ -199,7 +199,7 @@
|
||||
<Property key="Caption" value="Field of View"/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="4 222 329 18" align="Left Top" name="FOVSlider">
|
||||
<Property key="Range" value="1000000"/>
|
||||
<Property key="Range" value="100"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="SandText" position="4 246 329 18" align="Left Top">
|
||||
<Property key="Caption" value="#{sLow}"/>
|
||||
@ -224,7 +224,7 @@
|
||||
<Property key="Caption" value="Anisotropy"/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="0 28 150 18" align="Left Top" name="AnisotropySlider">
|
||||
<Property key="Range" value="1000000"/>
|
||||
<Property key="Range" value="100"/>
|
||||
</Widget>
|
||||
</Widget>
|
||||
|
||||
@ -232,7 +232,7 @@
|
||||
<Property key="Caption" value="#{sRender_Distance}"/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="4 154 322 18" align="Left Top" name="ViewDistanceSlider">
|
||||
<Property key="Range" value="1000000"/>
|
||||
<Property key="Range" value="100"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="SandText" position="4 178 332 18" align="Left Top">
|
||||
<Property key="Caption" value="#{sNear}"/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user