forked from teamnwah/openmw-tes3coop
Merge branch 'master' into appveyor
This commit is contained in:
commit
0d2bd31f8b
83 changed files with 1936 additions and 471 deletions
|
@ -19,6 +19,7 @@ Programmers
|
||||||
Alexander Nadeau (wareya)
|
Alexander Nadeau (wareya)
|
||||||
Alexander Olofsson (Ace)
|
Alexander Olofsson (Ace)
|
||||||
Artem Kotsynyak (greye)
|
Artem Kotsynyak (greye)
|
||||||
|
artemutin
|
||||||
Arthur Moore (EmperorArthur)
|
Arthur Moore (EmperorArthur)
|
||||||
athile
|
athile
|
||||||
Bret Curtis (psi29a)
|
Bret Curtis (psi29a)
|
||||||
|
|
|
@ -67,7 +67,7 @@ opencs_hdrs_noqt (view/doc
|
||||||
|
|
||||||
opencs_units (view/world
|
opencs_units (view/world
|
||||||
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
|
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
|
||||||
cellcreator referenceablecreator referencecreator scenesubview
|
cellcreator referenceablecreator startscriptcreator referencecreator scenesubview
|
||||||
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
|
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
|
||||||
dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator
|
dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator
|
||||||
)
|
)
|
||||||
|
@ -85,12 +85,12 @@ opencs_units (view/widget
|
||||||
|
|
||||||
opencs_units (view/render
|
opencs_units (view/render
|
||||||
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
|
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
|
||||||
previewwidget editmode
|
previewwidget editmode instancemode
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (view/render
|
opencs_units_noqt (view/render
|
||||||
lighting lightingday lightingnight
|
lighting lightingday lightingnight
|
||||||
lightingbright object cell terrainstorage
|
lightingbright object cell terrainstorage tagbase cellarrow
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_hdrs_noqt (view/render
|
opencs_hdrs_noqt (view/render
|
||||||
|
|
|
@ -371,6 +371,57 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
|
||||||
"list go to the first/last item");
|
"list go to the first/last item");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declareSection ("scene-input", "3D Scene Input");
|
||||||
|
{
|
||||||
|
QString left ("Left Mouse-Button");
|
||||||
|
QString cLeft ("Ctrl-Left Mouse-Button");
|
||||||
|
QString right ("Right Mouse-Button");
|
||||||
|
QString cRight ("Ctrl-Right Mouse-Button");
|
||||||
|
QString middle ("Middle Mouse-Button");
|
||||||
|
QString cMiddle ("Ctrl-Middle Mouse-Button");
|
||||||
|
|
||||||
|
QStringList values;
|
||||||
|
values << left << cLeft << right << cRight << middle << cMiddle;
|
||||||
|
|
||||||
|
Setting *primaryNavigation = createSetting (Type_ComboBox, "p-navi", "Primary Camera Navigation Button");
|
||||||
|
primaryNavigation->setDeclaredValues (values);
|
||||||
|
primaryNavigation->setDefaultValue (left);
|
||||||
|
|
||||||
|
Setting *secondaryNavigation = createSetting (Type_ComboBox, "s-navi", "Secondary Camera Navigation Button");
|
||||||
|
secondaryNavigation->setDeclaredValues (values);
|
||||||
|
secondaryNavigation->setDefaultValue (cLeft);
|
||||||
|
|
||||||
|
Setting *primaryEditing = createSetting (Type_ComboBox, "p-edit", "Primary Editing Button");
|
||||||
|
primaryEditing->setDeclaredValues (values);
|
||||||
|
primaryEditing->setDefaultValue (right);
|
||||||
|
|
||||||
|
Setting *secondaryEditing = createSetting (Type_ComboBox, "s-edit", "Secondary Editing Button");
|
||||||
|
secondaryEditing->setDeclaredValues (values);
|
||||||
|
secondaryEditing->setDefaultValue (cRight);
|
||||||
|
|
||||||
|
Setting *selection = createSetting (Type_ComboBox, "select", "Selection Button");
|
||||||
|
selection->setDeclaredValues (values);
|
||||||
|
selection->setDefaultValue (middle);
|
||||||
|
|
||||||
|
Setting *contextSensitive = createSetting (Type_CheckBox, "context-select", "Context Sensitive Selection");
|
||||||
|
contextSensitive->setDefaultValue ("false");
|
||||||
|
|
||||||
|
Setting *dragMouseSensitivity = createSetting (Type_DoubleSpinBox, "drag-factor",
|
||||||
|
"Mouse sensitivity during drag operations");
|
||||||
|
dragMouseSensitivity->setDefaultValue (1.0);
|
||||||
|
dragMouseSensitivity->setRange (0.001, 100.0);
|
||||||
|
|
||||||
|
Setting *dragWheelSensitivity = createSetting (Type_DoubleSpinBox, "drag-wheel-factor",
|
||||||
|
"Mouse wheel sensitivity during drag operations");
|
||||||
|
dragWheelSensitivity->setDefaultValue (1.0);
|
||||||
|
dragWheelSensitivity->setRange (0.001, 100.0);
|
||||||
|
|
||||||
|
Setting *dragShiftFactor = createSetting (Type_DoubleSpinBox, "drag-shift-factor",
|
||||||
|
"Acceleration factor during drag operations while holding down shift");
|
||||||
|
dragShiftFactor->setDefaultValue (4.0);
|
||||||
|
dragShiftFactor->setRange (0.001, 100.0);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* There are three types of values:
|
* There are three types of values:
|
||||||
|
|
|
@ -32,6 +32,23 @@ std::string CSMWorld::CellCoordinates::getId (const std::string& worldspace) con
|
||||||
return stream.str();
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<CSMWorld::CellCoordinates, bool> CSMWorld::CellCoordinates::fromId (
|
||||||
|
const std::string& id)
|
||||||
|
{
|
||||||
|
// no worldspace for now, needs to be changed for 1.1
|
||||||
|
if (!id.empty() && id[0]=='#')
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
char ignore;
|
||||||
|
|
||||||
|
std::istringstream stream (id);
|
||||||
|
if (stream >> ignore >> x >> y)
|
||||||
|
return std::make_pair (CellCoordinates (x, y), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair (CellCoordinates(), false);
|
||||||
|
}
|
||||||
|
|
||||||
bool CSMWorld::operator== (const CellCoordinates& left, const CellCoordinates& right)
|
bool CSMWorld::operator== (const CellCoordinates& left, const CellCoordinates& right)
|
||||||
{
|
{
|
||||||
return left.getX()==right.getX() && left.getY()==right.getY();
|
return left.getX()==right.getX() && left.getY()==right.getY();
|
||||||
|
|
|
@ -28,6 +28,12 @@ namespace CSMWorld
|
||||||
|
|
||||||
std::string getId (const std::string& worldspace) const;
|
std::string getId (const std::string& worldspace) const;
|
||||||
///< Return the ID for the cell at these coordinates.
|
///< Return the ID for the cell at these coordinates.
|
||||||
|
|
||||||
|
/// \return first: CellCoordinates (or 0, 0 if cell does not have coordinates),
|
||||||
|
/// second: is cell paged?
|
||||||
|
///
|
||||||
|
/// \note The worldspace part of \a id is ignored
|
||||||
|
static std::pair<CellCoordinates, bool> fromId (const std::string& id);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator== (const CellCoordinates& left, const CellCoordinates& right);
|
bool operator== (const CellCoordinates& left, const CellCoordinates& right);
|
||||||
|
|
|
@ -77,7 +77,7 @@ bool CSMWorld::ColumnBase::isId (Display display)
|
||||||
Display_Video,
|
Display_Video,
|
||||||
|
|
||||||
Display_Id,
|
Display_Id,
|
||||||
Display_SkillImpact,
|
Display_SkillId,
|
||||||
Display_EffectRange,
|
Display_EffectRange,
|
||||||
Display_EffectId,
|
Display_EffectId,
|
||||||
Display_PartRefType,
|
Display_PartRefType,
|
||||||
|
@ -85,7 +85,6 @@ bool CSMWorld::ColumnBase::isId (Display display)
|
||||||
Display_InfoCondFunc,
|
Display_InfoCondFunc,
|
||||||
Display_InfoCondVar,
|
Display_InfoCondVar,
|
||||||
Display_InfoCondComp,
|
Display_InfoCondComp,
|
||||||
Display_RaceSkill,
|
|
||||||
|
|
||||||
Display_None
|
Display_None
|
||||||
};
|
};
|
||||||
|
|
|
@ -113,7 +113,7 @@ namespace CSMWorld
|
||||||
Display_SoundGeneratorType,
|
Display_SoundGeneratorType,
|
||||||
Display_School,
|
Display_School,
|
||||||
Display_Id,
|
Display_Id,
|
||||||
Display_SkillImpact,
|
Display_SkillId,
|
||||||
Display_EffectRange,
|
Display_EffectRange,
|
||||||
Display_EffectId,
|
Display_EffectId,
|
||||||
Display_PartRefType,
|
Display_PartRefType,
|
||||||
|
@ -121,7 +121,6 @@ namespace CSMWorld
|
||||||
Display_InfoCondFunc,
|
Display_InfoCondFunc,
|
||||||
Display_InfoCondVar,
|
Display_InfoCondVar,
|
||||||
Display_InfoCondComp,
|
Display_InfoCondComp,
|
||||||
Display_RaceSkill,
|
|
||||||
Display_String32,
|
Display_String32,
|
||||||
Display_LongString256,
|
Display_LongString256,
|
||||||
|
|
||||||
|
|
|
@ -249,7 +249,7 @@ namespace CSMWorld
|
||||||
{ ColumnId_AiWanderDist, "Wander Dist" },
|
{ ColumnId_AiWanderDist, "Wander Dist" },
|
||||||
{ ColumnId_AiDuration, "Ai Duration" },
|
{ ColumnId_AiDuration, "Ai Duration" },
|
||||||
{ ColumnId_AiWanderToD, "Wander ToD" },
|
{ ColumnId_AiWanderToD, "Wander ToD" },
|
||||||
{ ColumnId_AiWanderIdle, "Wander Idle" },
|
//{ ColumnId_AiWanderIdle, "Wander Idle" },
|
||||||
{ ColumnId_AiWanderRepeat, "Wander Repeat" },
|
{ ColumnId_AiWanderRepeat, "Wander Repeat" },
|
||||||
{ ColumnId_AiActivateName, "Activate" },
|
{ ColumnId_AiActivateName, "Activate" },
|
||||||
{ ColumnId_AiTargetId, "Target ID" },
|
{ ColumnId_AiTargetId, "Target ID" },
|
||||||
|
@ -268,7 +268,7 @@ namespace CSMWorld
|
||||||
{ ColumnId_LevelledItemChanceNone, "Chance None" },
|
{ ColumnId_LevelledItemChanceNone, "Chance None" },
|
||||||
|
|
||||||
{ ColumnId_PowerList, "Powers" },
|
{ ColumnId_PowerList, "Powers" },
|
||||||
{ ColumnId_SkillImpact, "Skill" },
|
{ ColumnId_Skill, "Skill" },
|
||||||
|
|
||||||
{ ColumnId_InfoList, "Info List" },
|
{ ColumnId_InfoList, "Info List" },
|
||||||
{ ColumnId_InfoCondition, "Info Conditions" },
|
{ ColumnId_InfoCondition, "Info Conditions" },
|
||||||
|
@ -293,8 +293,7 @@ namespace CSMWorld
|
||||||
{ ColumnId_NpcPersistence, "Persistent" },
|
{ ColumnId_NpcPersistence, "Persistent" },
|
||||||
|
|
||||||
{ ColumnId_RaceAttributes, "Race Attributes" },
|
{ ColumnId_RaceAttributes, "Race Attributes" },
|
||||||
{ ColumnId_RaceMaleValue, "Male Attrib" },
|
{ ColumnId_Male, "Male" },
|
||||||
{ ColumnId_RaceFemaleValue, "Female Attrib" },
|
|
||||||
{ ColumnId_RaceSkillBonus, "Skill Bonus" },
|
{ ColumnId_RaceSkillBonus, "Skill Bonus" },
|
||||||
{ ColumnId_RaceBonus, "Bonus" },
|
{ ColumnId_RaceBonus, "Bonus" },
|
||||||
|
|
||||||
|
@ -317,6 +316,15 @@ namespace CSMWorld
|
||||||
{ ColumnId_MaxAttack, "Max Attack" },
|
{ ColumnId_MaxAttack, "Max Attack" },
|
||||||
{ ColumnId_CreatureMisc, "Creature Misc" },
|
{ ColumnId_CreatureMisc, "Creature Misc" },
|
||||||
|
|
||||||
|
{ ColumnId_Idle1, "Idle 1" },
|
||||||
|
{ ColumnId_Idle2, "Idle 2" },
|
||||||
|
{ ColumnId_Idle3, "Idle 3" },
|
||||||
|
{ ColumnId_Idle4, "Idle 4" },
|
||||||
|
{ ColumnId_Idle5, "Idle 5" },
|
||||||
|
{ ColumnId_Idle6, "Idle 6" },
|
||||||
|
{ ColumnId_Idle7, "Idle 7" },
|
||||||
|
{ ColumnId_Idle8, "Idle 8" },
|
||||||
|
|
||||||
{ ColumnId_UseValue1, "Use value 1" },
|
{ ColumnId_UseValue1, "Use value 1" },
|
||||||
{ ColumnId_UseValue2, "Use value 2" },
|
{ ColumnId_UseValue2, "Use value 2" },
|
||||||
{ ColumnId_UseValue3, "Use value 3" },
|
{ ColumnId_UseValue3, "Use value 3" },
|
||||||
|
@ -572,7 +580,7 @@ namespace
|
||||||
case CSMWorld::Columns::ColumnId_MeshType: return sMeshTypes;
|
case CSMWorld::Columns::ColumnId_MeshType: return sMeshTypes;
|
||||||
case CSMWorld::Columns::ColumnId_SoundGeneratorType: return sSoundGeneratorType;
|
case CSMWorld::Columns::ColumnId_SoundGeneratorType: return sSoundGeneratorType;
|
||||||
case CSMWorld::Columns::ColumnId_School: return sSchools;
|
case CSMWorld::Columns::ColumnId_School: return sSchools;
|
||||||
case CSMWorld::Columns::ColumnId_SkillImpact: return sSkills;
|
case CSMWorld::Columns::ColumnId_Skill: return sSkills;
|
||||||
case CSMWorld::Columns::ColumnId_EffectRange: return sEffectRange;
|
case CSMWorld::Columns::ColumnId_EffectRange: return sEffectRange;
|
||||||
case CSMWorld::Columns::ColumnId_EffectId: return sEffectId;
|
case CSMWorld::Columns::ColumnId_EffectId: return sEffectId;
|
||||||
case CSMWorld::Columns::ColumnId_PartRefType: return sPartRefType;
|
case CSMWorld::Columns::ColumnId_PartRefType: return sPartRefType;
|
||||||
|
|
|
@ -241,7 +241,7 @@ namespace CSMWorld
|
||||||
ColumnId_AiWanderDist = 221,
|
ColumnId_AiWanderDist = 221,
|
||||||
ColumnId_AiDuration = 222,
|
ColumnId_AiDuration = 222,
|
||||||
ColumnId_AiWanderToD = 223,
|
ColumnId_AiWanderToD = 223,
|
||||||
ColumnId_AiWanderIdle = 224,
|
// unused
|
||||||
ColumnId_AiWanderRepeat = 225,
|
ColumnId_AiWanderRepeat = 225,
|
||||||
ColumnId_AiActivateName = 226,
|
ColumnId_AiActivateName = 226,
|
||||||
// use ColumnId_PosX, etc for AI destinations
|
// use ColumnId_PosX, etc for AI destinations
|
||||||
|
@ -261,7 +261,7 @@ namespace CSMWorld
|
||||||
ColumnId_LevelledItemChanceNone = 238,
|
ColumnId_LevelledItemChanceNone = 238,
|
||||||
|
|
||||||
ColumnId_PowerList = 239,
|
ColumnId_PowerList = 239,
|
||||||
ColumnId_SkillImpact = 240, // impact from magic effects
|
ColumnId_Skill = 240,
|
||||||
|
|
||||||
ColumnId_InfoList = 241,
|
ColumnId_InfoList = 241,
|
||||||
ColumnId_InfoCondition = 242,
|
ColumnId_InfoCondition = 242,
|
||||||
|
@ -288,8 +288,8 @@ namespace CSMWorld
|
||||||
ColumnId_NpcPersistence = 261,
|
ColumnId_NpcPersistence = 261,
|
||||||
|
|
||||||
ColumnId_RaceAttributes = 262,
|
ColumnId_RaceAttributes = 262,
|
||||||
ColumnId_RaceMaleValue = 263,
|
ColumnId_Male = 263,
|
||||||
ColumnId_RaceFemaleValue = 264,
|
// unused
|
||||||
ColumnId_RaceSkillBonus = 265,
|
ColumnId_RaceSkillBonus = 265,
|
||||||
// unused
|
// unused
|
||||||
ColumnId_RaceBonus = 267,
|
ColumnId_RaceBonus = 267,
|
||||||
|
@ -316,6 +316,15 @@ namespace CSMWorld
|
||||||
ColumnId_MaxAttack = 284,
|
ColumnId_MaxAttack = 284,
|
||||||
ColumnId_CreatureMisc = 285,
|
ColumnId_CreatureMisc = 285,
|
||||||
|
|
||||||
|
ColumnId_Idle1 = 286,
|
||||||
|
ColumnId_Idle2 = 287,
|
||||||
|
ColumnId_Idle3 = 288,
|
||||||
|
ColumnId_Idle4 = 289,
|
||||||
|
ColumnId_Idle5 = 290,
|
||||||
|
ColumnId_Idle6 = 291,
|
||||||
|
ColumnId_Idle7 = 292,
|
||||||
|
ColumnId_Idle8 = 293,
|
||||||
|
|
||||||
// Allocated to a separate value range, so we don't get a collision should we ever need
|
// Allocated to a separate value range, so we don't get a collision should we ever need
|
||||||
// to extend the number of use values.
|
// to extend the number of use values.
|
||||||
ColumnId_UseValue1 = 0x10000,
|
ColumnId_UseValue1 = 0x10000,
|
||||||
|
|
|
@ -143,15 +143,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
|
||||||
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute,
|
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute,
|
||||||
ColumnBase::Flag_Dialogue, false));
|
ColumnBase::Flag_Dialogue, false));
|
||||||
mRaces.getNestableColumn(index)->addColumn(
|
mRaces.getNestableColumn(index)->addColumn(
|
||||||
new NestedChildColumn (Columns::ColumnId_RaceMaleValue, ColumnBase::Display_Integer));
|
new NestedChildColumn (Columns::ColumnId_Male, ColumnBase::Display_Integer));
|
||||||
mRaces.getNestableColumn(index)->addColumn(
|
mRaces.getNestableColumn(index)->addColumn(
|
||||||
new NestedChildColumn (Columns::ColumnId_RaceFemaleValue, ColumnBase::Display_Integer));
|
new NestedChildColumn (Columns::ColumnId_Female, ColumnBase::Display_Integer));
|
||||||
// Race skill bonus
|
// Race skill bonus
|
||||||
mRaces.addColumn (new NestedParentColumn<ESM::Race> (Columns::ColumnId_RaceSkillBonus));
|
mRaces.addColumn (new NestedParentColumn<ESM::Race> (Columns::ColumnId_RaceSkillBonus));
|
||||||
index = mRaces.getColumns()-1;
|
index = mRaces.getColumns()-1;
|
||||||
mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceSkillsBonusAdapter()));
|
mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceSkillsBonusAdapter()));
|
||||||
mRaces.getNestableColumn(index)->addColumn(
|
mRaces.getNestableColumn(index)->addColumn(
|
||||||
new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact));
|
new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId));
|
||||||
mRaces.getNestableColumn(index)->addColumn(
|
mRaces.getNestableColumn(index)->addColumn(
|
||||||
new NestedChildColumn (Columns::ColumnId_RaceBonus, ColumnBase::Display_Integer));
|
new NestedChildColumn (Columns::ColumnId_RaceBonus, ColumnBase::Display_Integer));
|
||||||
|
|
||||||
|
@ -213,7 +213,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
|
||||||
mSpells.getNestableColumn(index)->addColumn(
|
mSpells.getNestableColumn(index)->addColumn(
|
||||||
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId));
|
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId));
|
||||||
mSpells.getNestableColumn(index)->addColumn(
|
mSpells.getNestableColumn(index)->addColumn(
|
||||||
new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact));
|
new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId));
|
||||||
mSpells.getNestableColumn(index)->addColumn(
|
mSpells.getNestableColumn(index)->addColumn(
|
||||||
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute));
|
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute));
|
||||||
mSpells.getNestableColumn(index)->addColumn(
|
mSpells.getNestableColumn(index)->addColumn(
|
||||||
|
@ -329,7 +329,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
|
||||||
mEnchantments.getNestableColumn(index)->addColumn(
|
mEnchantments.getNestableColumn(index)->addColumn(
|
||||||
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId));
|
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId));
|
||||||
mEnchantments.getNestableColumn(index)->addColumn(
|
mEnchantments.getNestableColumn(index)->addColumn(
|
||||||
new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact));
|
new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId));
|
||||||
mEnchantments.getNestableColumn(index)->addColumn(
|
mEnchantments.getNestableColumn(index)->addColumn(
|
||||||
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute));
|
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute));
|
||||||
mEnchantments.getNestableColumn(index)->addColumn(
|
mEnchantments.getNestableColumn(index)->addColumn(
|
||||||
|
|
|
@ -1532,6 +1532,8 @@ namespace CSMWorld
|
||||||
|
|
||||||
virtual ~ActorAiRefIdAdapter() {}
|
virtual ~ActorAiRefIdAdapter() {}
|
||||||
|
|
||||||
|
// FIXME: should check if the AI package type is already in the list and use a default
|
||||||
|
// that wasn't used already (in extreme case do not add anything at all?
|
||||||
virtual void addNestedRow (const RefIdColumn *column,
|
virtual void addNestedRow (const RefIdColumn *column,
|
||||||
RefIdData& data, int index, int position) const
|
RefIdData& data, int index, int position) const
|
||||||
{
|
{
|
||||||
|
@ -1615,6 +1617,7 @@ namespace CSMWorld
|
||||||
switch (subColIndex)
|
switch (subColIndex)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
// FIXME: should more than one AI package type be allowed? Check vanilla
|
||||||
switch (content.mType)
|
switch (content.mType)
|
||||||
{
|
{
|
||||||
case ESM::AI_Wander: return 0;
|
case ESM::AI_Wander: return 0;
|
||||||
|
@ -1642,47 +1645,52 @@ namespace CSMWorld
|
||||||
else
|
else
|
||||||
return QVariant();
|
return QVariant();
|
||||||
case 4: // wander idle
|
case 4: // wander idle
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
case 9:
|
||||||
|
case 10:
|
||||||
|
case 11:
|
||||||
if (content.mType == ESM::AI_Wander)
|
if (content.mType == ESM::AI_Wander)
|
||||||
{
|
return static_cast<int>(content.mWander.mIdle[subColIndex-4]);
|
||||||
return static_cast<int>(content.mWander.mIdle[0]); // FIXME:
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
return QVariant();
|
return QVariant();
|
||||||
case 5: // wander repeat
|
case 12: // wander repeat
|
||||||
if (content.mType == ESM::AI_Wander)
|
if (content.mType == ESM::AI_Wander)
|
||||||
return content.mWander.mShouldRepeat != 0;
|
return content.mWander.mShouldRepeat != 0;
|
||||||
else
|
else
|
||||||
return QVariant();
|
return QVariant();
|
||||||
case 6: // activate name
|
case 13: // activate name
|
||||||
if (content.mType == ESM::AI_Activate)
|
if (content.mType == ESM::AI_Activate)
|
||||||
return QString(content.mActivate.mName.toString().c_str());
|
return QString(content.mActivate.mName.toString().c_str());
|
||||||
else
|
else
|
||||||
return QVariant();
|
return QVariant();
|
||||||
case 7: // target id
|
case 14: // target id
|
||||||
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||||
return QString(content.mTarget.mId.toString().c_str());
|
return QString(content.mTarget.mId.toString().c_str());
|
||||||
else
|
else
|
||||||
return QVariant();
|
return QVariant();
|
||||||
case 8: // target cell
|
case 15: // target cell
|
||||||
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||||
return QString::fromUtf8(content.mCellName.c_str());
|
return QString::fromUtf8(content.mCellName.c_str());
|
||||||
else
|
else
|
||||||
return QVariant();
|
return QVariant();
|
||||||
case 9:
|
case 16:
|
||||||
if (content.mType == ESM::AI_Travel)
|
if (content.mType == ESM::AI_Travel)
|
||||||
return content.mTravel.mX;
|
return content.mTravel.mX;
|
||||||
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||||
return content.mTarget.mX;
|
return content.mTarget.mX;
|
||||||
else
|
else
|
||||||
return QVariant();
|
return QVariant();
|
||||||
case 10:
|
case 17:
|
||||||
if (content.mType == ESM::AI_Travel)
|
if (content.mType == ESM::AI_Travel)
|
||||||
return content.mTravel.mY;
|
return content.mTravel.mY;
|
||||||
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||||
return content.mTarget.mY;
|
return content.mTarget.mY;
|
||||||
else
|
else
|
||||||
return QVariant();
|
return QVariant();
|
||||||
case 11:
|
case 18:
|
||||||
if (content.mType == ESM::AI_Travel)
|
if (content.mType == ESM::AI_Travel)
|
||||||
return content.mTravel.mZ;
|
return content.mTravel.mZ;
|
||||||
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||||
|
@ -1712,11 +1720,12 @@ namespace CSMWorld
|
||||||
case 0: // ai package type
|
case 0: // ai package type
|
||||||
switch (value.toInt())
|
switch (value.toInt())
|
||||||
{
|
{
|
||||||
case 0: content.mType = ESM::AI_Wander;
|
case 0: content.mType = ESM::AI_Wander; break;
|
||||||
case 1: content.mType = ESM::AI_Travel;
|
case 1: content.mType = ESM::AI_Travel; break;
|
||||||
case 2: content.mType = ESM::AI_Follow;
|
case 2: content.mType = ESM::AI_Follow; break;
|
||||||
case 3: content.mType = ESM::AI_Escort;
|
case 3: content.mType = ESM::AI_Escort; break;
|
||||||
case 4: content.mType = ESM::AI_Activate;
|
case 4: content.mType = ESM::AI_Activate; break;
|
||||||
|
default: return; // return without saving
|
||||||
}
|
}
|
||||||
break; // always save
|
break; // always save
|
||||||
|
|
||||||
|
@ -1725,6 +1734,8 @@ namespace CSMWorld
|
||||||
content.mWander.mDistance = static_cast<short>(value.toInt());
|
content.mWander.mDistance = static_cast<short>(value.toInt());
|
||||||
else
|
else
|
||||||
return; // return without saving
|
return; // return without saving
|
||||||
|
|
||||||
|
break; // always save
|
||||||
case 2:
|
case 2:
|
||||||
if (content.mType == ESM::AI_Wander ||
|
if (content.mType == ESM::AI_Wander ||
|
||||||
content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||||
|
@ -1736,62 +1747,77 @@ namespace CSMWorld
|
||||||
content.mWander.mTimeOfDay = static_cast<unsigned char>(value.toInt());
|
content.mWander.mTimeOfDay = static_cast<unsigned char>(value.toInt());
|
||||||
else
|
else
|
||||||
return; // return without saving
|
return; // return without saving
|
||||||
|
|
||||||
|
break; // always save
|
||||||
case 4:
|
case 4:
|
||||||
if (content.mType == ESM::AI_Wander)
|
|
||||||
break; // FIXME: idle
|
|
||||||
else
|
|
||||||
return; // return without saving
|
|
||||||
case 5:
|
case 5:
|
||||||
if (content.mType == ESM::AI_Wander)
|
case 6:
|
||||||
{
|
case 7:
|
||||||
content.mWander.mShouldRepeat = static_cast<unsigned char>(value.toInt());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 6: // NAME32
|
|
||||||
if (content.mType == ESM::AI_Activate)
|
|
||||||
{
|
|
||||||
content.mActivate.mName.assign(value.toString().toUtf8().constData());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return; // return without saving
|
|
||||||
case 7: // NAME32
|
|
||||||
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
||||||
{
|
|
||||||
content.mTarget.mId.assign(value.toString().toUtf8().constData());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return; // return without saving
|
|
||||||
case 8:
|
case 8:
|
||||||
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
||||||
{
|
|
||||||
content.mCellName = std::string(value.toString().toUtf8().constData());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return; // return without saving
|
|
||||||
case 9:
|
case 9:
|
||||||
if (content.mType == ESM::AI_Travel)
|
|
||||||
content.mTravel.mZ = value.toFloat();
|
|
||||||
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
||||||
content.mTarget.mZ = value.toFloat();
|
|
||||||
else
|
|
||||||
return; // return without saving
|
|
||||||
case 10:
|
case 10:
|
||||||
if (content.mType == ESM::AI_Travel)
|
|
||||||
content.mTravel.mZ = value.toFloat();
|
|
||||||
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
||||||
content.mTarget.mZ = value.toFloat();
|
|
||||||
else
|
|
||||||
return; // return without saving
|
|
||||||
case 11:
|
case 11:
|
||||||
|
if (content.mType == ESM::AI_Wander)
|
||||||
|
content.mWander.mIdle[subColIndex-4] = static_cast<unsigned char>(value.toInt());
|
||||||
|
else
|
||||||
|
return; // return without saving
|
||||||
|
|
||||||
|
break; // always save
|
||||||
|
case 12:
|
||||||
|
if (content.mType == ESM::AI_Wander)
|
||||||
|
content.mWander.mShouldRepeat = static_cast<unsigned char>(value.toInt());
|
||||||
|
else
|
||||||
|
return; // return without saving
|
||||||
|
|
||||||
|
break; // always save
|
||||||
|
case 13: // NAME32
|
||||||
|
if (content.mType == ESM::AI_Activate)
|
||||||
|
content.mActivate.mName.assign(value.toString().toUtf8().constData());
|
||||||
|
else
|
||||||
|
return; // return without saving
|
||||||
|
|
||||||
|
break; // always save
|
||||||
|
case 14: // NAME32
|
||||||
|
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||||
|
content.mTarget.mId.assign(value.toString().toUtf8().constData());
|
||||||
|
else
|
||||||
|
return; // return without saving
|
||||||
|
|
||||||
|
break; // always save
|
||||||
|
case 15:
|
||||||
|
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||||
|
content.mCellName = std::string(value.toString().toUtf8().constData());
|
||||||
|
else
|
||||||
|
return; // return without saving
|
||||||
|
|
||||||
|
break; // always save
|
||||||
|
case 16:
|
||||||
if (content.mType == ESM::AI_Travel)
|
if (content.mType == ESM::AI_Travel)
|
||||||
content.mTravel.mZ = value.toFloat();
|
content.mTravel.mZ = value.toFloat();
|
||||||
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||||
content.mTarget.mZ = value.toFloat();
|
content.mTarget.mZ = value.toFloat();
|
||||||
else
|
else
|
||||||
return; // return without saving
|
return; // return without saving
|
||||||
|
|
||||||
|
break; // always save
|
||||||
|
case 17:
|
||||||
|
if (content.mType == ESM::AI_Travel)
|
||||||
|
content.mTravel.mZ = value.toFloat();
|
||||||
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||||
|
content.mTarget.mZ = value.toFloat();
|
||||||
|
else
|
||||||
|
return; // return without saving
|
||||||
|
|
||||||
|
break; // always save
|
||||||
|
case 18:
|
||||||
|
if (content.mType == ESM::AI_Travel)
|
||||||
|
content.mTravel.mZ = value.toFloat();
|
||||||
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||||
|
content.mTarget.mZ = value.toFloat();
|
||||||
|
else
|
||||||
|
return; // return without saving
|
||||||
|
|
||||||
|
break; // always save
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
||||||
}
|
}
|
||||||
|
@ -1801,7 +1827,7 @@ namespace CSMWorld
|
||||||
|
|
||||||
virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const
|
virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const
|
||||||
{
|
{
|
||||||
return 12;
|
return 19;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const
|
virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const
|
||||||
|
|
|
@ -83,7 +83,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
||||||
mColumns.back().addColumn(
|
mColumns.back().addColumn(
|
||||||
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId));
|
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId));
|
||||||
mColumns.back().addColumn(
|
mColumns.back().addColumn(
|
||||||
new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact));
|
new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId));
|
||||||
mColumns.back().addColumn(
|
mColumns.back().addColumn(
|
||||||
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute));
|
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute));
|
||||||
mColumns.back().addColumn(
|
mColumns.back().addColumn(
|
||||||
|
@ -193,8 +193,24 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
||||||
new RefIdColumn (Columns::ColumnId_AiDuration, CSMWorld::ColumnBase::Display_Integer));
|
new RefIdColumn (Columns::ColumnId_AiDuration, CSMWorld::ColumnBase::Display_Integer));
|
||||||
mColumns.back().addColumn(
|
mColumns.back().addColumn(
|
||||||
new RefIdColumn (Columns::ColumnId_AiWanderToD, CSMWorld::ColumnBase::Display_Integer));
|
new RefIdColumn (Columns::ColumnId_AiWanderToD, CSMWorld::ColumnBase::Display_Integer));
|
||||||
|
|
||||||
mColumns.back().addColumn(
|
mColumns.back().addColumn(
|
||||||
new RefIdColumn (Columns::ColumnId_AiWanderIdle, CSMWorld::ColumnBase::Display_Integer));
|
new RefIdColumn (Columns::ColumnId_Idle1, CSMWorld::ColumnBase::Display_Integer));
|
||||||
|
mColumns.back().addColumn(
|
||||||
|
new RefIdColumn (Columns::ColumnId_Idle2, CSMWorld::ColumnBase::Display_Integer));
|
||||||
|
mColumns.back().addColumn(
|
||||||
|
new RefIdColumn (Columns::ColumnId_Idle3, CSMWorld::ColumnBase::Display_Integer));
|
||||||
|
mColumns.back().addColumn(
|
||||||
|
new RefIdColumn (Columns::ColumnId_Idle4, CSMWorld::ColumnBase::Display_Integer));
|
||||||
|
mColumns.back().addColumn(
|
||||||
|
new RefIdColumn (Columns::ColumnId_Idle5, CSMWorld::ColumnBase::Display_Integer));
|
||||||
|
mColumns.back().addColumn(
|
||||||
|
new RefIdColumn (Columns::ColumnId_Idle6, CSMWorld::ColumnBase::Display_Integer));
|
||||||
|
mColumns.back().addColumn(
|
||||||
|
new RefIdColumn (Columns::ColumnId_Idle7, CSMWorld::ColumnBase::Display_Integer));
|
||||||
|
mColumns.back().addColumn(
|
||||||
|
new RefIdColumn (Columns::ColumnId_Idle8, CSMWorld::ColumnBase::Display_Integer));
|
||||||
|
|
||||||
mColumns.back().addColumn(
|
mColumns.back().addColumn(
|
||||||
new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_Boolean));
|
new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_Boolean));
|
||||||
mColumns.back().addColumn(
|
mColumns.back().addColumn(
|
||||||
|
@ -491,7 +507,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
||||||
skillsMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcSkillsRefIdAdapter()));
|
skillsMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcSkillsRefIdAdapter()));
|
||||||
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), skillsMap));
|
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), skillsMap));
|
||||||
mColumns.back().addColumn(
|
mColumns.back().addColumn(
|
||||||
new RefIdColumn (Columns::ColumnId_SkillImpact, CSMWorld::ColumnBase::Display_SkillImpact, false, false));
|
new RefIdColumn (Columns::ColumnId_Skill, CSMWorld::ColumnBase::Display_SkillId, false, false));
|
||||||
mColumns.back().addColumn(
|
mColumns.back().addColumn(
|
||||||
new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer));
|
new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer));
|
||||||
|
|
||||||
|
|
|
@ -435,6 +435,8 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to
|
||||||
mOperations = new Operations;
|
mOperations = new Operations;
|
||||||
addDockWidget (Qt::BottomDockWidgetArea, mOperations);
|
addDockWidget (Qt::BottomDockWidgetArea, mOperations);
|
||||||
|
|
||||||
|
setContextMenuPolicy(Qt::NoContextMenu);
|
||||||
|
|
||||||
updateTitle();
|
updateTitle();
|
||||||
|
|
||||||
setupUi();
|
setupUi();
|
||||||
|
|
|
@ -97,7 +97,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
|
||||||
{ CSMWorld::ColumnBase::Display_Gender, CSMWorld::Columns::ColumnId_Gender, true },
|
{ CSMWorld::ColumnBase::Display_Gender, CSMWorld::Columns::ColumnId_Gender, true },
|
||||||
{ CSMWorld::ColumnBase::Display_SoundGeneratorType, CSMWorld::Columns::ColumnId_SoundGeneratorType, false },
|
{ CSMWorld::ColumnBase::Display_SoundGeneratorType, CSMWorld::Columns::ColumnId_SoundGeneratorType, false },
|
||||||
{ CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, false },
|
{ CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, false },
|
||||||
{ CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true },
|
{ CSMWorld::ColumnBase::Display_SkillId, CSMWorld::Columns::ColumnId_Skill, true },
|
||||||
{ CSMWorld::ColumnBase::Display_EffectRange, CSMWorld::Columns::ColumnId_EffectRange, false },
|
{ CSMWorld::ColumnBase::Display_EffectRange, CSMWorld::Columns::ColumnId_EffectRange, false },
|
||||||
{ CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false },
|
{ CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false },
|
||||||
{ CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false },
|
{ CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false },
|
||||||
|
|
|
@ -5,14 +5,17 @@
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
||||||
#include "../../model/world/data.hpp"
|
#include "../../model/world/data.hpp"
|
||||||
|
#include "../../model/world/idtablebase.hpp"
|
||||||
|
#include "../../model/world/columns.hpp"
|
||||||
|
|
||||||
CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent)
|
CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent)
|
||||||
: QLineEdit (parent), mParser (data)
|
: QLineEdit (parent), mParser (data), mIsEmpty(true)
|
||||||
{
|
{
|
||||||
mPalette = palette();
|
mPalette = palette();
|
||||||
connect (this, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&)));
|
connect (this, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&)));
|
||||||
|
|
||||||
QAbstractItemModel *model = data.getTableModel (CSMWorld::UniversalId::Type_Filters);
|
const CSMWorld::IdTableBase *model =
|
||||||
|
static_cast<const CSMWorld::IdTableBase *> (data.getTableModel (CSMWorld::UniversalId::Type_Filters));
|
||||||
|
|
||||||
connect (model, SIGNAL (dataChanged (const QModelIndex &, const QModelIndex&)),
|
connect (model, SIGNAL (dataChanged (const QModelIndex &, const QModelIndex&)),
|
||||||
this, SLOT (filterDataChanged (const QModelIndex &, const QModelIndex&)),
|
this, SLOT (filterDataChanged (const QModelIndex &, const QModelIndex&)),
|
||||||
|
@ -23,10 +26,23 @@ CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent)
|
||||||
connect (model, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
connect (model, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
||||||
this, SLOT (filterRowsInserted (const QModelIndex&, int, int)),
|
this, SLOT (filterRowsInserted (const QModelIndex&, int, int)),
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
|
mStateColumnIndex = model->findColumnIndex(CSMWorld::Columns::ColumnId_Modification);
|
||||||
|
mDescColumnIndex = model->findColumnIndex(CSMWorld::Columns::ColumnId_Description);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVFilter::EditWidget::textChanged (const QString& text)
|
void CSVFilter::EditWidget::textChanged (const QString& text)
|
||||||
{
|
{
|
||||||
|
//no need to parse and apply filter if it was empty and now is empty too.
|
||||||
|
//e.g. - we modifiing content of filter with already opened some other (big) tables.
|
||||||
|
if (text.length() == 0){
|
||||||
|
if (mIsEmpty)
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
mIsEmpty = true;
|
||||||
|
}else
|
||||||
|
mIsEmpty = false;
|
||||||
|
|
||||||
if (mParser.parse (text.toUtf8().constData()))
|
if (mParser.parse (text.toUtf8().constData()))
|
||||||
{
|
{
|
||||||
setPalette (mPalette);
|
setPalette (mPalette);
|
||||||
|
@ -45,6 +61,8 @@ void CSVFilter::EditWidget::textChanged (const QString& text)
|
||||||
void CSVFilter::EditWidget::filterDataChanged (const QModelIndex& topLeft,
|
void CSVFilter::EditWidget::filterDataChanged (const QModelIndex& topLeft,
|
||||||
const QModelIndex& bottomRight)
|
const QModelIndex& bottomRight)
|
||||||
{
|
{
|
||||||
|
for (int i = topLeft.column(); i <= bottomRight.column(); ++i)
|
||||||
|
if (i != mStateColumnIndex && i != mDescColumnIndex)
|
||||||
textChanged (text());
|
textChanged (text());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,9 @@ namespace CSVFilter
|
||||||
|
|
||||||
CSMFilter::Parser mParser;
|
CSMFilter::Parser mParser;
|
||||||
QPalette mPalette;
|
QPalette mPalette;
|
||||||
|
bool mIsEmpty;
|
||||||
|
int mStateColumnIndex;
|
||||||
|
int mDescColumnIndex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "../../model/world/columns.hpp"
|
#include "../../model/world/columns.hpp"
|
||||||
#include "../../model/world/data.hpp"
|
#include "../../model/world/data.hpp"
|
||||||
#include "../../model/world/refcollection.hpp"
|
#include "../../model/world/refcollection.hpp"
|
||||||
|
#include "../../model/world/cellcoordinates.hpp"
|
||||||
|
|
||||||
#include "elements.hpp"
|
#include "elements.hpp"
|
||||||
#include "terrainstorage.hpp"
|
#include "terrainstorage.hpp"
|
||||||
|
@ -50,12 +51,20 @@ bool CSVRender::Cell::addObjects (int start, int end)
|
||||||
return modified;
|
return modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id)
|
CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id,
|
||||||
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mX(0), mY(0)
|
bool deleted)
|
||||||
|
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted)
|
||||||
{
|
{
|
||||||
|
std::pair<CSMWorld::CellCoordinates, bool> result = CSMWorld::CellCoordinates::fromId (id);
|
||||||
|
|
||||||
|
if (result.second)
|
||||||
|
mCoordinates = result.first;
|
||||||
|
|
||||||
mCellNode = new osg::Group;
|
mCellNode = new osg::Group;
|
||||||
rootNode->addChild(mCellNode);
|
rootNode->addChild(mCellNode);
|
||||||
|
|
||||||
|
if (!mDeleted)
|
||||||
|
{
|
||||||
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
|
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
|
||||||
|
|
||||||
|
@ -74,9 +83,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st
|
||||||
mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1));
|
mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1));
|
||||||
mTerrain->loadCell(esmLand.mX,
|
mTerrain->loadCell(esmLand.mX,
|
||||||
esmLand.mY);
|
esmLand.mY);
|
||||||
|
}
|
||||||
mX = esmLand.mX;
|
|
||||||
mY = esmLand.mY;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,6 +129,9 @@ bool CSVRender::Cell::referenceableAboutToBeRemoved (const QModelIndex& parent,
|
||||||
bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft,
|
bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft,
|
||||||
const QModelIndex& bottomRight)
|
const QModelIndex& bottomRight)
|
||||||
{
|
{
|
||||||
|
if (mDeleted)
|
||||||
|
return false;
|
||||||
|
|
||||||
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
|
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
|
||||||
|
|
||||||
|
@ -189,6 +199,9 @@ bool CSVRender::Cell::referenceAboutToBeRemoved (const QModelIndex& parent, int
|
||||||
if (parent.isValid())
|
if (parent.isValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (mDeleted)
|
||||||
|
return false;
|
||||||
|
|
||||||
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
|
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
|
||||||
|
|
||||||
|
@ -209,5 +222,57 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int
|
||||||
if (parent.isValid())
|
if (parent.isValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (mDeleted)
|
||||||
|
return false;
|
||||||
|
|
||||||
return addObjects (start, end);
|
return addObjects (start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::Cell::setSelection (int elementMask, Selection mode)
|
||||||
|
{
|
||||||
|
if (elementMask & Element_Reference)
|
||||||
|
{
|
||||||
|
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
|
||||||
|
iter!=mObjects.end(); ++iter)
|
||||||
|
{
|
||||||
|
bool selected = false;
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case Selection_Clear: selected = false; break;
|
||||||
|
case Selection_All: selected = true; break;
|
||||||
|
case Selection_Invert: selected = !iter->second->getSelected(); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter->second->setSelected (selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::Cell::setCellArrows (int mask)
|
||||||
|
{
|
||||||
|
for (int i=0; i<4; ++i)
|
||||||
|
{
|
||||||
|
CellArrow::Direction direction = static_cast<CellArrow::Direction> (1<<i);
|
||||||
|
|
||||||
|
bool enable = mask & direction;
|
||||||
|
|
||||||
|
if (enable!=(mCellArrows[i].get()!=0))
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
mCellArrows[i].reset (new CellArrow (mCellNode, direction, mCoordinates));
|
||||||
|
else
|
||||||
|
mCellArrows[i].reset (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::CellCoordinates CSVRender::Cell::getCoordinates() const
|
||||||
|
{
|
||||||
|
return mCoordinates;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSVRender::Cell::isDeleted() const
|
||||||
|
{
|
||||||
|
return mDeleted;
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "object.hpp"
|
#include "object.hpp"
|
||||||
|
#include "cellarrow.hpp"
|
||||||
|
|
||||||
class QModelIndex;
|
class QModelIndex;
|
||||||
|
|
||||||
|
@ -25,6 +26,7 @@ namespace osg
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
class Data;
|
class Data;
|
||||||
|
class CellCoordinates;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace CSVRender
|
namespace CSVRender
|
||||||
|
@ -36,8 +38,9 @@ namespace CSVRender
|
||||||
osg::ref_ptr<osg::Group> mCellNode;
|
osg::ref_ptr<osg::Group> mCellNode;
|
||||||
std::map<std::string, Object *> mObjects;
|
std::map<std::string, Object *> mObjects;
|
||||||
std::auto_ptr<Terrain::TerrainGrid> mTerrain;
|
std::auto_ptr<Terrain::TerrainGrid> mTerrain;
|
||||||
int mX;
|
CSMWorld::CellCoordinates mCoordinates;
|
||||||
int mY;
|
std::auto_ptr<CellArrow> mCellArrows[4];
|
||||||
|
bool mDeleted;
|
||||||
|
|
||||||
/// Ignored if cell does not have an object with the given ID.
|
/// Ignored if cell does not have an object with the given ID.
|
||||||
///
|
///
|
||||||
|
@ -51,7 +54,19 @@ namespace CSVRender
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id);
|
enum Selection
|
||||||
|
{
|
||||||
|
Selection_Clear,
|
||||||
|
Selection_All,
|
||||||
|
Selection_Invert
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// \note Deleted covers both cells that are deleted and cells that don't exist in
|
||||||
|
/// the first place.
|
||||||
|
Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id,
|
||||||
|
bool deleted = false);
|
||||||
|
|
||||||
~Cell();
|
~Cell();
|
||||||
|
|
||||||
|
@ -75,6 +90,15 @@ namespace CSVRender
|
||||||
/// \return Did this call result in a modification of the visual representation of
|
/// \return Did this call result in a modification of the visual representation of
|
||||||
/// this cell?
|
/// this cell?
|
||||||
bool referenceAdded (const QModelIndex& parent, int start, int end);
|
bool referenceAdded (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
|
void setSelection (int elementMask, Selection mode);
|
||||||
|
|
||||||
|
void setCellArrows (int mask);
|
||||||
|
|
||||||
|
/// Returns 0, 0 in case of an unpaged cell.
|
||||||
|
CSMWorld::CellCoordinates getCoordinates() const;
|
||||||
|
|
||||||
|
bool isDeleted() const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
161
apps/opencs/view/render/cellarrow.cpp
Normal file
161
apps/opencs/view/render/cellarrow.cpp
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
|
||||||
|
#include "cellarrow.hpp"
|
||||||
|
|
||||||
|
#include <osg/Group>
|
||||||
|
#include <osg/PositionAttitudeTransform>
|
||||||
|
#include <osg/Geode>
|
||||||
|
#include <osg/Geometry>
|
||||||
|
#include <osg/PrimitiveSet>
|
||||||
|
|
||||||
|
#include "elements.hpp"
|
||||||
|
|
||||||
|
CSVRender::CellArrowTag::CellArrowTag (CellArrow *arrow)
|
||||||
|
: TagBase (Element_CellArrow), mArrow (arrow)
|
||||||
|
{}
|
||||||
|
|
||||||
|
CSVRender::CellArrow *CSVRender::CellArrowTag::getCellArrow() const
|
||||||
|
{
|
||||||
|
return mArrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CSVRender::CellArrow::adjustTransform()
|
||||||
|
{
|
||||||
|
// position
|
||||||
|
const int cellSize = 8192;
|
||||||
|
const int offset = cellSize / 2 + 800;
|
||||||
|
|
||||||
|
int x = mCoordinates.getX()*cellSize + cellSize/2;
|
||||||
|
int y = mCoordinates.getY()*cellSize + cellSize/2;
|
||||||
|
|
||||||
|
float xr = 0;
|
||||||
|
float yr = 0;
|
||||||
|
float zr = 0;
|
||||||
|
|
||||||
|
float angle = osg::DegreesToRadians (90.0f);
|
||||||
|
|
||||||
|
switch (mDirection)
|
||||||
|
{
|
||||||
|
case Direction_North: y += offset; xr = -angle; zr = angle; break;
|
||||||
|
case Direction_West: x -= offset; yr = -angle; break;
|
||||||
|
case Direction_South: y -= offset; xr = angle; zr = angle; break;
|
||||||
|
case Direction_East: x += offset; yr = angle; break;
|
||||||
|
};
|
||||||
|
|
||||||
|
mBaseNode->setPosition (osg::Vec3f (x, y, 0));
|
||||||
|
|
||||||
|
// orientation
|
||||||
|
osg::Quat xr2 (xr, osg::Vec3f (1,0,0));
|
||||||
|
osg::Quat yr2 (yr, osg::Vec3f (0,1,0));
|
||||||
|
osg::Quat zr2 (zr, osg::Vec3f (0,0,1));
|
||||||
|
mBaseNode->setAttitude (zr2*yr2*xr2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::CellArrow::buildShape()
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
|
||||||
|
|
||||||
|
const int arrowWidth = 4000;
|
||||||
|
const int arrowLength = 1500;
|
||||||
|
const int arrowHeight = 500;
|
||||||
|
|
||||||
|
osg::Vec3Array *vertices = new osg::Vec3Array;
|
||||||
|
for (int i2=0; i2<2; ++i2)
|
||||||
|
for (int i=0; i<2; ++i)
|
||||||
|
{
|
||||||
|
float height = i ? -arrowHeight/2 : arrowHeight/2;
|
||||||
|
vertices->push_back (osg::Vec3f (height, -arrowWidth/2, 0));
|
||||||
|
vertices->push_back (osg::Vec3f (height, arrowWidth/2, 0));
|
||||||
|
vertices->push_back (osg::Vec3f (height, 0, arrowLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
geometry->setVertexArray (vertices);
|
||||||
|
|
||||||
|
osg::DrawElementsUShort *primitives = new osg::DrawElementsUShort (osg::PrimitiveSet::TRIANGLES, 0);
|
||||||
|
|
||||||
|
// top
|
||||||
|
primitives->push_back (0);
|
||||||
|
primitives->push_back (1);
|
||||||
|
primitives->push_back (2);
|
||||||
|
|
||||||
|
// bottom
|
||||||
|
primitives->push_back (5);
|
||||||
|
primitives->push_back (4);
|
||||||
|
primitives->push_back (3);
|
||||||
|
|
||||||
|
// back
|
||||||
|
primitives->push_back (3+6);
|
||||||
|
primitives->push_back (4+6);
|
||||||
|
primitives->push_back (1+6);
|
||||||
|
|
||||||
|
primitives->push_back (3+6);
|
||||||
|
primitives->push_back (1+6);
|
||||||
|
primitives->push_back (0+6);
|
||||||
|
|
||||||
|
// sides
|
||||||
|
primitives->push_back (0+6);
|
||||||
|
primitives->push_back (2+6);
|
||||||
|
primitives->push_back (5+6);
|
||||||
|
|
||||||
|
primitives->push_back (0+6);
|
||||||
|
primitives->push_back (5+6);
|
||||||
|
primitives->push_back (3+6);
|
||||||
|
|
||||||
|
primitives->push_back (4+6);
|
||||||
|
primitives->push_back (5+6);
|
||||||
|
primitives->push_back (2+6);
|
||||||
|
|
||||||
|
primitives->push_back (4+6);
|
||||||
|
primitives->push_back (2+6);
|
||||||
|
primitives->push_back (1+6);
|
||||||
|
|
||||||
|
geometry->addPrimitiveSet (primitives);
|
||||||
|
|
||||||
|
osg::Vec4Array *colours = new osg::Vec4Array;
|
||||||
|
|
||||||
|
for (int i=0; i<6; ++i)
|
||||||
|
colours->push_back (osg::Vec4f (1.0f, 0.0f, 0.0f, 1.0f));
|
||||||
|
for (int i=0; i<6; ++i)
|
||||||
|
colours->push_back (osg::Vec4f (0.8f, (i==2 || i==5) ? 0.6f : 0.4f, 0.0f, 1.0f));
|
||||||
|
|
||||||
|
geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX);
|
||||||
|
|
||||||
|
geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF);
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
|
||||||
|
geode->addDrawable (geometry);
|
||||||
|
|
||||||
|
mBaseNode->addChild (geode);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVRender::CellArrow::CellArrow (osg::Group *cellNode, Direction direction,
|
||||||
|
const CSMWorld::CellCoordinates& coordinates)
|
||||||
|
: mDirection (direction), mParentNode (cellNode), mCoordinates (coordinates)
|
||||||
|
{
|
||||||
|
mBaseNode = new osg::PositionAttitudeTransform;
|
||||||
|
|
||||||
|
mBaseNode->setUserData (new CellArrowTag (this));
|
||||||
|
|
||||||
|
mParentNode->addChild (mBaseNode);
|
||||||
|
|
||||||
|
// 0x1 reserved for separating cull and update visitors
|
||||||
|
mBaseNode->setNodeMask (Element_CellArrow<<1);
|
||||||
|
|
||||||
|
adjustTransform();
|
||||||
|
buildShape();
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVRender::CellArrow::~CellArrow()
|
||||||
|
{
|
||||||
|
mParentNode->removeChild (mBaseNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::CellCoordinates CSVRender::CellArrow::getCoordinates() const
|
||||||
|
{
|
||||||
|
return mCoordinates;
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVRender::CellArrow::Direction CSVRender::CellArrow::getDirection() const
|
||||||
|
{
|
||||||
|
return mDirection;
|
||||||
|
}
|
72
apps/opencs/view/render/cellarrow.hpp
Normal file
72
apps/opencs/view/render/cellarrow.hpp
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#ifndef OPENCS_VIEW_CELLARROW_H
|
||||||
|
#define OPENCS_VIEW_CELLARROW_H
|
||||||
|
|
||||||
|
#include "tagbase.hpp"
|
||||||
|
|
||||||
|
#include <osg/ref_ptr>
|
||||||
|
|
||||||
|
#include "../../model/world/cellcoordinates.hpp"
|
||||||
|
|
||||||
|
namespace osg
|
||||||
|
{
|
||||||
|
class PositionAttitudeTransform;
|
||||||
|
class Group;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
class CellArrow;
|
||||||
|
|
||||||
|
class CellArrowTag : public TagBase
|
||||||
|
{
|
||||||
|
CellArrow *mArrow;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CellArrowTag (CellArrow *arrow);
|
||||||
|
|
||||||
|
CellArrow *getCellArrow() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CellArrow
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Direction
|
||||||
|
{
|
||||||
|
Direction_North = 1,
|
||||||
|
Direction_West = 2,
|
||||||
|
Direction_South = 4,
|
||||||
|
Direction_East = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// not implemented
|
||||||
|
CellArrow (const CellArrow&);
|
||||||
|
CellArrow& operator= (const CellArrow&);
|
||||||
|
|
||||||
|
Direction mDirection;
|
||||||
|
osg::Group* mParentNode;
|
||||||
|
osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode;
|
||||||
|
CSMWorld::CellCoordinates mCoordinates;
|
||||||
|
|
||||||
|
void adjustTransform();
|
||||||
|
|
||||||
|
void buildShape();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CellArrow (osg::Group *cellNode, Direction direction,
|
||||||
|
const CSMWorld::CellCoordinates& coordinates);
|
||||||
|
|
||||||
|
~CellArrow();
|
||||||
|
|
||||||
|
CSMWorld::CellCoordinates getCoordinates() const;
|
||||||
|
|
||||||
|
Direction getDirection() const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,7 +1,13 @@
|
||||||
#include "editmode.hpp"
|
#include "editmode.hpp"
|
||||||
|
|
||||||
|
#include "tagbase.hpp"
|
||||||
#include "worldspacewidget.hpp"
|
#include "worldspacewidget.hpp"
|
||||||
|
|
||||||
|
CSVRender::WorldspaceWidget& CSVRender::EditMode::getWorldspaceWidget()
|
||||||
|
{
|
||||||
|
return *mWorldspaceWidget;
|
||||||
|
}
|
||||||
|
|
||||||
CSVRender::EditMode::EditMode (WorldspaceWidget *worldspaceWidget, const QIcon& icon,
|
CSVRender::EditMode::EditMode (WorldspaceWidget *worldspaceWidget, const QIcon& icon,
|
||||||
unsigned int mask, const QString& tooltip, QWidget *parent)
|
unsigned int mask, const QString& tooltip, QWidget *parent)
|
||||||
: ModeButton (icon, tooltip, parent), mWorldspaceWidget (worldspaceWidget), mMask (mask)
|
: ModeButton (icon, tooltip, parent), mWorldspaceWidget (worldspaceWidget), mMask (mask)
|
||||||
|
@ -15,4 +21,44 @@ unsigned int CSVRender::EditMode::getInteractionMask() const
|
||||||
void CSVRender::EditMode::activate (CSVWidget::SceneToolbar *toolbar)
|
void CSVRender::EditMode::activate (CSVWidget::SceneToolbar *toolbar)
|
||||||
{
|
{
|
||||||
mWorldspaceWidget->setInteractionMask (mMask);
|
mWorldspaceWidget->setInteractionMask (mMask);
|
||||||
|
mWorldspaceWidget->clearSelection (~mMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::EditMode::updateUserSetting (const QString& name, const QStringList& value)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::EditMode::setEditLock (bool locked)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::EditMode::primaryEditPressed (osg::ref_ptr<TagBase> tag) {}
|
||||||
|
|
||||||
|
void CSVRender::EditMode::secondaryEditPressed (osg::ref_ptr<TagBase> tag) {}
|
||||||
|
|
||||||
|
void CSVRender::EditMode::selectPressed (osg::ref_ptr<TagBase> tag) {}
|
||||||
|
|
||||||
|
bool CSVRender::EditMode::primaryEditStartDrag (osg::ref_ptr<TagBase> tag)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSVRender::EditMode::secondaryEditStartDrag (osg::ref_ptr<TagBase> tag)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSVRender::EditMode::selectStartDrag (osg::ref_ptr<TagBase> tag)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::EditMode::drag (int diffX, int diffY, double speedFactor) {}
|
||||||
|
|
||||||
|
void CSVRender::EditMode::dragCompleted() {}
|
||||||
|
|
||||||
|
void CSVRender::EditMode::dragAborted() {}
|
||||||
|
|
||||||
|
void CSVRender::EditMode::dragWheel (int diff, double speedFactor) {}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
#ifndef CSV_RENDER_EDITMODE_H
|
#ifndef CSV_RENDER_EDITMODE_H
|
||||||
#define CSV_RENDER_EDITMODE_H
|
#define CSV_RENDER_EDITMODE_H
|
||||||
|
|
||||||
|
#include <osg/ref_ptr>
|
||||||
|
|
||||||
#include "../widget/modebutton.hpp"
|
#include "../widget/modebutton.hpp"
|
||||||
|
|
||||||
namespace CSVRender
|
namespace CSVRender
|
||||||
{
|
{
|
||||||
class WorldspaceWidget;
|
class WorldspaceWidget;
|
||||||
|
class TagBase;
|
||||||
|
|
||||||
class EditMode : public CSVWidget::ModeButton
|
class EditMode : public CSVWidget::ModeButton
|
||||||
{
|
{
|
||||||
|
@ -14,6 +17,10 @@ namespace CSVRender
|
||||||
WorldspaceWidget *mWorldspaceWidget;
|
WorldspaceWidget *mWorldspaceWidget;
|
||||||
unsigned int mMask;
|
unsigned int mMask;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
WorldspaceWidget& getWorldspaceWidget();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
EditMode (WorldspaceWidget *worldspaceWidget, const QIcon& icon, unsigned int mask,
|
EditMode (WorldspaceWidget *worldspaceWidget, const QIcon& icon, unsigned int mask,
|
||||||
|
@ -22,6 +29,51 @@ namespace CSVRender
|
||||||
unsigned int getInteractionMask() const;
|
unsigned int getInteractionMask() const;
|
||||||
|
|
||||||
virtual void activate (CSVWidget::SceneToolbar *toolbar);
|
virtual void activate (CSVWidget::SceneToolbar *toolbar);
|
||||||
|
|
||||||
|
/// Default-implementation: Do nothing.
|
||||||
|
virtual void updateUserSetting (const QString& name, const QStringList& value);
|
||||||
|
|
||||||
|
/// Default-implementation: Ignored.
|
||||||
|
virtual void setEditLock (bool locked);
|
||||||
|
|
||||||
|
/// Default-implementation: Ignored.
|
||||||
|
virtual void primaryEditPressed (osg::ref_ptr<TagBase> tag);
|
||||||
|
|
||||||
|
/// Default-implementation: Ignored.
|
||||||
|
virtual void secondaryEditPressed (osg::ref_ptr<TagBase> tag);
|
||||||
|
|
||||||
|
/// Default-implementation: Ignored.
|
||||||
|
virtual void selectPressed (osg::ref_ptr<TagBase> tag);
|
||||||
|
|
||||||
|
/// Default-implementation: ignore and return false
|
||||||
|
///
|
||||||
|
/// \return Drag accepted?
|
||||||
|
virtual bool primaryEditStartDrag (osg::ref_ptr<TagBase> tag);
|
||||||
|
|
||||||
|
/// Default-implementation: ignore and return false
|
||||||
|
///
|
||||||
|
/// \return Drag accepted?
|
||||||
|
virtual bool secondaryEditStartDrag (osg::ref_ptr<TagBase> tag);
|
||||||
|
|
||||||
|
/// Default-implementation: ignore and return false
|
||||||
|
///
|
||||||
|
/// \return Drag accepted?
|
||||||
|
virtual bool selectStartDrag (osg::ref_ptr<TagBase> tag);
|
||||||
|
|
||||||
|
/// Default-implementation: ignored
|
||||||
|
virtual void drag (int diffX, int diffY, double speedFactor);
|
||||||
|
|
||||||
|
/// Default-implementation: ignored
|
||||||
|
virtual void dragCompleted();
|
||||||
|
|
||||||
|
/// Default-implementation: ignored
|
||||||
|
///
|
||||||
|
/// \note dragAborted will not be called, if the drag is aborted via changing
|
||||||
|
/// editing mode
|
||||||
|
virtual void dragAborted();
|
||||||
|
|
||||||
|
/// Default-implementation: ignored
|
||||||
|
virtual void dragWheel (int diff, double speedFactor);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
56
apps/opencs/view/render/instancemode.cpp
Normal file
56
apps/opencs/view/render/instancemode.cpp
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
#include "instancemode.hpp"
|
||||||
|
|
||||||
|
#include "../../model/settings/usersettings.hpp"
|
||||||
|
|
||||||
|
#include "elements.hpp"
|
||||||
|
#include "object.hpp"
|
||||||
|
#include "worldspacewidget.hpp"
|
||||||
|
|
||||||
|
CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent)
|
||||||
|
: EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing",
|
||||||
|
parent), mContextSelect (false)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar)
|
||||||
|
{
|
||||||
|
EditMode::activate (toolbar);
|
||||||
|
|
||||||
|
mContextSelect = CSMSettings::UserSettings::instance().setting ("scene-input/context-select")=="true";
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::InstanceMode::updateUserSetting (const QString& name, const QStringList& value)
|
||||||
|
{
|
||||||
|
if (name=="scene-input/context-select")
|
||||||
|
mContextSelect = value.at (0)=="true";
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::InstanceMode::primaryEditPressed (osg::ref_ptr<TagBase> tag)
|
||||||
|
{
|
||||||
|
if (mContextSelect)
|
||||||
|
selectPressed (tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::InstanceMode::secondaryEditPressed (osg::ref_ptr<TagBase> tag)
|
||||||
|
{
|
||||||
|
if (mContextSelect)
|
||||||
|
selectPressed (tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::InstanceMode::selectPressed (osg::ref_ptr<TagBase> tag)
|
||||||
|
{
|
||||||
|
if (tag)
|
||||||
|
{
|
||||||
|
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (tag.get()))
|
||||||
|
{
|
||||||
|
// hit an Object, toggle its selection state
|
||||||
|
CSVRender::Object* object = objectTag->mObject;
|
||||||
|
object->setSelected (!object->getSelected());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getWorldspaceWidget().clearSelection (Element_Reference);
|
||||||
|
}
|
30
apps/opencs/view/render/instancemode.hpp
Normal file
30
apps/opencs/view/render/instancemode.hpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef CSV_RENDER_INSTANCEMODE_H
|
||||||
|
#define CSV_RENDER_INSTANCEMODE_H
|
||||||
|
|
||||||
|
#include "editmode.hpp"
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
class InstanceMode : public EditMode
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
bool mContextSelect;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent = 0);
|
||||||
|
|
||||||
|
virtual void activate (CSVWidget::SceneToolbar *toolbar);
|
||||||
|
|
||||||
|
virtual void updateUserSetting (const QString& name, const QStringList& value);
|
||||||
|
|
||||||
|
virtual void primaryEditPressed (osg::ref_ptr<TagBase> tag);
|
||||||
|
|
||||||
|
virtual void secondaryEditPressed (osg::ref_ptr<TagBase> tag);
|
||||||
|
|
||||||
|
virtual void selectPressed (osg::ref_ptr<TagBase> tag);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -38,6 +38,11 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CSVRender::ObjectTag::ObjectTag (Object* object)
|
||||||
|
: TagBase (Element_Reference), mObject (object)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
void CSVRender::Object::clear()
|
void CSVRender::Object::clear()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -124,7 +129,7 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode,
|
||||||
mOutline = new osgFX::Scribe;
|
mOutline = new osgFX::Scribe;
|
||||||
mOutline->addChild(mBaseNode);
|
mOutline->addChild(mBaseNode);
|
||||||
|
|
||||||
mBaseNode->setUserData(new ObjectHolder(this));
|
mBaseNode->setUserData(new ObjectTag(this));
|
||||||
|
|
||||||
parentNode->addChild(mBaseNode);
|
parentNode->addChild(mBaseNode);
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,9 @@
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
#include <osg/Referenced>
|
#include <osg/Referenced>
|
||||||
|
|
||||||
class QModelIndex;
|
#include "tagbase.hpp"
|
||||||
|
|
||||||
|
class QModelIndex;
|
||||||
|
|
||||||
namespace osg
|
namespace osg
|
||||||
{
|
{
|
||||||
|
@ -35,21 +36,19 @@ namespace CSMWorld
|
||||||
|
|
||||||
namespace CSVRender
|
namespace CSVRender
|
||||||
{
|
{
|
||||||
|
|
||||||
class Object;
|
class Object;
|
||||||
|
|
||||||
// An object to attach as user data to the osg::Node, allows us to get an Object back from a Node when we are doing a ray query
|
// An object to attach as user data to the osg::Node, allows us to get an Object back from a Node when we are doing a ray query
|
||||||
class ObjectHolder : public osg::Referenced
|
class ObjectTag : public TagBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ObjectHolder(Object* obj)
|
|
||||||
: mObject(obj)
|
ObjectTag (Object* object);
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Object* mObject;
|
Object* mObject;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Object
|
class Object
|
||||||
{
|
{
|
||||||
const CSMWorld::Data& mData;
|
const CSMWorld::Data& mData;
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
#include "pagedworldspacewidget.hpp"
|
#include "pagedworldspacewidget.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
#include <osgGA/TrackballManipulator>
|
#include <osgGA/TrackballManipulator>
|
||||||
|
|
||||||
|
@ -21,20 +23,19 @@
|
||||||
bool CSVRender::PagedWorldspaceWidget::adjustCells()
|
bool CSVRender::PagedWorldspaceWidget::adjustCells()
|
||||||
{
|
{
|
||||||
bool modified = false;
|
bool modified = false;
|
||||||
|
bool wasEmpty = mCells.empty();
|
||||||
|
|
||||||
const CSMWorld::IdCollection<CSMWorld::Cell>& cells = mDocument.getData().getCells();
|
const CSMWorld::IdCollection<CSMWorld::Cell>& cells = mDocument.getData().getCells();
|
||||||
|
|
||||||
{
|
{
|
||||||
// remove (or name/region modified)
|
// remove/update
|
||||||
std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
|
std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
|
||||||
|
|
||||||
while (iter!=mCells.end())
|
while (iter!=mCells.end())
|
||||||
{
|
{
|
||||||
int index = cells.searchId (iter->first.getId (mWorldspace));
|
if (!mSelection.has (iter->first))
|
||||||
|
|
||||||
if (!mSelection.has (iter->first) || index==-1 ||
|
|
||||||
cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted)
|
|
||||||
{
|
{
|
||||||
|
// remove
|
||||||
delete iter->second;
|
delete iter->second;
|
||||||
mCells.erase (iter++);
|
mCells.erase (iter++);
|
||||||
|
|
||||||
|
@ -42,12 +43,33 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// check if name or region field has changed
|
// update
|
||||||
|
int index = cells.searchId (iter->first.getId (mWorldspace));
|
||||||
|
|
||||||
|
bool deleted = index==-1 ||
|
||||||
|
cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted;
|
||||||
|
|
||||||
|
if (deleted!=iter->second->isDeleted())
|
||||||
|
{
|
||||||
|
modified = true;
|
||||||
|
|
||||||
|
std::auto_ptr<Cell> cell (new Cell (mDocument.getData(), mRootNode,
|
||||||
|
iter->first.getId (mWorldspace), deleted));
|
||||||
|
|
||||||
|
delete iter->second;
|
||||||
|
iter->second = cell.release();
|
||||||
|
}
|
||||||
|
else if (!deleted)
|
||||||
|
{
|
||||||
|
// delete state has not changed -> just update
|
||||||
|
|
||||||
|
// TODO check if name or region field has changed (cell marker)
|
||||||
// FIXME: config setting
|
// FIXME: config setting
|
||||||
//std::string name = cells.getRecord(index).get().mName;
|
//std::string name = cells.getRecord(index).get().mName;
|
||||||
//std::string region = cells.getRecord(index).get().mRegion;
|
//std::string region = cells.getRecord(index).get().mRegion;
|
||||||
|
|
||||||
// cell marker update goes here
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
|
@ -58,20 +80,43 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells()
|
||||||
for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end();
|
for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end();
|
||||||
++iter)
|
++iter)
|
||||||
{
|
{
|
||||||
int index = cells.searchId (iter->getId (mWorldspace));
|
if (mCells.find (*iter)==mCells.end())
|
||||||
|
|
||||||
if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted &&
|
|
||||||
mCells.find (*iter)==mCells.end())
|
|
||||||
{
|
{
|
||||||
Cell *cell = new Cell (mDocument.getData(), mRootNode,
|
addCellToScene (*iter);
|
||||||
iter->getId (mWorldspace));
|
|
||||||
mCells.insert (std::make_pair (*iter, cell));
|
|
||||||
|
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modified)
|
if (modified)
|
||||||
|
{
|
||||||
|
for (std::map<CSMWorld::CellCoordinates, Cell *>::const_iterator iter (mCells.begin());
|
||||||
|
iter!=mCells.end(); ++iter)
|
||||||
|
{
|
||||||
|
int mask = 0;
|
||||||
|
|
||||||
|
for (int i=CellArrow::Direction_North; i<=CellArrow::Direction_East; i *= 2)
|
||||||
|
{
|
||||||
|
CSMWorld::CellCoordinates coordinates (iter->second->getCoordinates());
|
||||||
|
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case CellArrow::Direction_North: coordinates = coordinates.move (0, 1); break;
|
||||||
|
case CellArrow::Direction_West: coordinates = coordinates.move (-1, 0); break;
|
||||||
|
case CellArrow::Direction_South: coordinates = coordinates.move (0, -1); break;
|
||||||
|
case CellArrow::Direction_East: coordinates = coordinates.move (1, 0); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mSelection.has (coordinates))
|
||||||
|
mask |= i;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter->second->setCellArrows (mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \todo do not overwrite manipulator object
|
||||||
|
/// \todo move code to useViewHint function
|
||||||
|
if (modified && wasEmpty)
|
||||||
mView->setCameraManipulator(new osgGA::TrackballManipulator);
|
mView->setCameraManipulator(new osgGA::TrackballManipulator);
|
||||||
|
|
||||||
return modified;
|
return modified;
|
||||||
|
@ -105,6 +150,76 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons (
|
||||||
"terrain-move");
|
"terrain-move");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::handleMouseClick (osg::ref_ptr<TagBase> tag, const std::string& button, bool shift)
|
||||||
|
{
|
||||||
|
if (tag && tag->getElement()==Element_CellArrow)
|
||||||
|
{
|
||||||
|
if (button=="p-edit" || button=="s-edit")
|
||||||
|
{
|
||||||
|
if (CellArrowTag *cellArrowTag =
|
||||||
|
dynamic_cast<CSVRender::CellArrowTag *> (tag.get()))
|
||||||
|
{
|
||||||
|
CellArrow *arrow = cellArrowTag->getCellArrow();
|
||||||
|
|
||||||
|
CSMWorld::CellCoordinates coordinates = arrow->getCoordinates();
|
||||||
|
|
||||||
|
CellArrow::Direction direction = arrow->getDirection();
|
||||||
|
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
|
||||||
|
switch (direction)
|
||||||
|
{
|
||||||
|
case CellArrow::Direction_North: y = 1; break;
|
||||||
|
case CellArrow::Direction_West: x = -1; break;
|
||||||
|
case CellArrow::Direction_South: y = -1; break;
|
||||||
|
case CellArrow::Direction_East: x = 1; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool modified = false;
|
||||||
|
|
||||||
|
if (shift)
|
||||||
|
{
|
||||||
|
if (button=="p-edit")
|
||||||
|
addCellSelection (x, y);
|
||||||
|
else
|
||||||
|
moveCellSelection (x, y);
|
||||||
|
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CSMWorld::CellCoordinates newCoordinates = coordinates.move (x, y);
|
||||||
|
|
||||||
|
if (mCells.find (newCoordinates)==mCells.end())
|
||||||
|
{
|
||||||
|
addCellToScene (newCoordinates);
|
||||||
|
mSelection.add (newCoordinates);
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button=="s-edit")
|
||||||
|
{
|
||||||
|
if (mCells.find (coordinates)!=mCells.end())
|
||||||
|
{
|
||||||
|
removeCellFromScene (coordinates);
|
||||||
|
mSelection.remove (coordinates);
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modified)
|
||||||
|
adjustCells();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WorldspaceWidget::handleMouseClick (tag, button, shift);
|
||||||
|
}
|
||||||
|
|
||||||
void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
|
void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
|
||||||
const QModelIndex& bottomRight)
|
const QModelIndex& bottomRight)
|
||||||
{
|
{
|
||||||
|
@ -184,6 +299,72 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction()
|
||||||
return stream.str();
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::addCellToScene (
|
||||||
|
const CSMWorld::CellCoordinates& coordinates)
|
||||||
|
{
|
||||||
|
const CSMWorld::IdCollection<CSMWorld::Cell>& cells = mDocument.getData().getCells();
|
||||||
|
|
||||||
|
int index = cells.searchId (coordinates.getId (mWorldspace));
|
||||||
|
|
||||||
|
bool deleted = index==-1 ||
|
||||||
|
cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted;
|
||||||
|
|
||||||
|
Cell *cell = new Cell (mDocument.getData(), mRootNode, coordinates.getId (mWorldspace),
|
||||||
|
deleted);
|
||||||
|
|
||||||
|
mCells.insert (std::make_pair (coordinates, cell));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::removeCellFromScene (
|
||||||
|
const CSMWorld::CellCoordinates& coordinates)
|
||||||
|
{
|
||||||
|
std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter = mCells.find (coordinates);
|
||||||
|
|
||||||
|
if (iter!=mCells.end())
|
||||||
|
{
|
||||||
|
delete iter->second;
|
||||||
|
mCells.erase (iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::addCellSelection (int x, int y)
|
||||||
|
{
|
||||||
|
CSMWorld::CellSelection newSelection = mSelection;
|
||||||
|
newSelection.move (x, y);
|
||||||
|
|
||||||
|
for (CSMWorld::CellSelection::Iterator iter (newSelection.begin()); iter!=newSelection.end();
|
||||||
|
++iter)
|
||||||
|
{
|
||||||
|
if (mCells.find (*iter)==mCells.end())
|
||||||
|
{
|
||||||
|
addCellToScene (*iter);
|
||||||
|
mSelection.add (*iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::moveCellSelection (int x, int y)
|
||||||
|
{
|
||||||
|
CSMWorld::CellSelection newSelection = mSelection;
|
||||||
|
newSelection.move (x, y);
|
||||||
|
|
||||||
|
for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end();
|
||||||
|
++iter)
|
||||||
|
{
|
||||||
|
if (!newSelection.has (*iter))
|
||||||
|
removeCellFromScene (*iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (CSMWorld::CellSelection::Iterator iter (newSelection.begin()); iter!=newSelection.end();
|
||||||
|
++iter)
|
||||||
|
{
|
||||||
|
if (!mSelection.has (*iter))
|
||||||
|
addCellToScene (*iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
mSelection = newSelection;
|
||||||
|
}
|
||||||
|
|
||||||
CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document)
|
CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document)
|
||||||
: WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"),
|
: WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"),
|
||||||
mControlElements(NULL), mDisplayCellCoord(true)
|
mControlElements(NULL), mDisplayCellCoord(true)
|
||||||
|
@ -314,6 +495,15 @@ unsigned int CSVRender::PagedWorldspaceWidget::getVisibilityMask() const
|
||||||
return WorldspaceWidget::getVisibilityMask() | mControlElements->getSelection();
|
return WorldspaceWidget::getVisibilityMask() | mControlElements->getSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::PagedWorldspaceWidget::clearSelection (int elementMask)
|
||||||
|
{
|
||||||
|
for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter = mCells.begin();
|
||||||
|
iter!=mCells.end(); ++iter)
|
||||||
|
iter->second->setSelection (elementMask, Cell::Selection_Clear);
|
||||||
|
|
||||||
|
flagAsModified();
|
||||||
|
}
|
||||||
|
|
||||||
CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector (
|
CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector (
|
||||||
CSVWidget::SceneToolbar *parent)
|
CSVWidget::SceneToolbar *parent)
|
||||||
{
|
{
|
||||||
|
|
|
@ -53,6 +53,20 @@ namespace CSVRender
|
||||||
|
|
||||||
virtual std::string getStartupInstruction();
|
virtual std::string getStartupInstruction();
|
||||||
|
|
||||||
|
/// \note Does not update the view or any cell marker
|
||||||
|
void addCellToScene (const CSMWorld::CellCoordinates& coordinates);
|
||||||
|
|
||||||
|
/// \note Does not update the view or any cell marker
|
||||||
|
///
|
||||||
|
/// \note Calling this function for a cell that is not in the selection is a no-op.
|
||||||
|
void removeCellFromScene (const CSMWorld::CellCoordinates& coordinates);
|
||||||
|
|
||||||
|
/// \note Does not update the view or any cell marker
|
||||||
|
void addCellSelection (int x, int y);
|
||||||
|
|
||||||
|
/// \note Does not update the view or any cell marker
|
||||||
|
void moveCellSelection (int x, int y);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document);
|
PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document);
|
||||||
|
@ -79,12 +93,17 @@ namespace CSVRender
|
||||||
|
|
||||||
virtual unsigned int getVisibilityMask() const;
|
virtual unsigned int getVisibilityMask() const;
|
||||||
|
|
||||||
|
/// \param elementMask Elements to be affected by the clear operation
|
||||||
|
virtual void clearSelection (int elementMask);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);
|
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);
|
||||||
|
|
||||||
virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool);
|
virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool);
|
||||||
|
|
||||||
|
virtual void handleMouseClick (osg::ref_ptr<TagBase> tag, const std::string& button, bool shift);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void cellSelectionChanged (const CSMWorld::CellSelection& selection);
|
void cellSelectionChanged (const CSMWorld::CellSelection& selection);
|
||||||
|
|
|
@ -110,6 +110,8 @@ bool RenderWidget::eventFilter(QObject* obj, QEvent* event)
|
||||||
keyPressEvent(static_cast<QKeyEvent*>(event));
|
keyPressEvent(static_cast<QKeyEvent*>(event));
|
||||||
if (event->type() == QEvent::KeyRelease)
|
if (event->type() == QEvent::KeyRelease)
|
||||||
keyReleaseEvent(static_cast<QKeyEvent*>(event));
|
keyReleaseEvent(static_cast<QKeyEvent*>(event));
|
||||||
|
if (event->type() == QEvent::Wheel)
|
||||||
|
wheelEvent(static_cast<QWheelEvent *>(event));
|
||||||
|
|
||||||
// Always pass the event on to GLWidget, i.e. to OSG event queue
|
// Always pass the event on to GLWidget, i.e. to OSG event queue
|
||||||
return QObject::eventFilter(obj, event);
|
return QObject::eventFilter(obj, event);
|
||||||
|
|
9
apps/opencs/view/render/tagbase.cpp
Normal file
9
apps/opencs/view/render/tagbase.cpp
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
#include "tagbase.hpp"
|
||||||
|
|
||||||
|
CSVRender::TagBase::TagBase (Elements element) : mElement (element) {}
|
||||||
|
|
||||||
|
CSVRender::Elements CSVRender::TagBase::getElement() const
|
||||||
|
{
|
||||||
|
return mElement;
|
||||||
|
}
|
22
apps/opencs/view/render/tagbase.hpp
Normal file
22
apps/opencs/view/render/tagbase.hpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef OPENCS_VIEW_TAGBASE_H
|
||||||
|
#define OPENCS_VIEW_TAGBASE_H
|
||||||
|
|
||||||
|
#include <osg/Referenced>
|
||||||
|
|
||||||
|
#include "elements.hpp"
|
||||||
|
|
||||||
|
namespace CSVRender
|
||||||
|
{
|
||||||
|
class TagBase : public osg::Referenced
|
||||||
|
{
|
||||||
|
Elements mElement;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
TagBase (Elements element);
|
||||||
|
|
||||||
|
Elements getElement() const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -102,6 +102,12 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector<CSMWorld:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::UnpagedWorldspaceWidget::clearSelection (int elementMask)
|
||||||
|
{
|
||||||
|
mCell->setSelection (elementMask, Cell::Selection_Clear);
|
||||||
|
flagAsModified();
|
||||||
|
}
|
||||||
|
|
||||||
void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
|
void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
|
||||||
const QModelIndex& bottomRight)
|
const QModelIndex& bottomRight)
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,6 +43,9 @@ namespace CSVRender
|
||||||
virtual bool handleDrop (const std::vector<CSMWorld::UniversalId>& data,
|
virtual bool handleDrop (const std::vector<CSMWorld::UniversalId>& data,
|
||||||
DropType type);
|
DropType type);
|
||||||
|
|
||||||
|
/// \param elementMask Elements to be affected by the clear operation
|
||||||
|
virtual void clearSelection (int elementMask);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
virtual void referenceableDataChanged (const QModelIndex& topLeft,
|
virtual void referenceableDataChanged (const QModelIndex& topLeft,
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <QDropEvent>
|
#include <QDropEvent>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
#include <osgGA/TrackballManipulator>
|
#include <osgGA/TrackballManipulator>
|
||||||
#include <osgGA/FirstPersonManipulator>
|
#include <osgGA/FirstPersonManipulator>
|
||||||
|
@ -18,6 +19,8 @@
|
||||||
#include "../../model/world/universalid.hpp"
|
#include "../../model/world/universalid.hpp"
|
||||||
#include "../../model/world/idtable.hpp"
|
#include "../../model/world/idtable.hpp"
|
||||||
|
|
||||||
|
#include "../../model/settings/usersettings.hpp"
|
||||||
|
|
||||||
#include "../widget/scenetoolmode.hpp"
|
#include "../widget/scenetoolmode.hpp"
|
||||||
#include "../widget/scenetooltoggle2.hpp"
|
#include "../widget/scenetooltoggle2.hpp"
|
||||||
#include "../widget/scenetoolrun.hpp"
|
#include "../widget/scenetoolrun.hpp"
|
||||||
|
@ -25,10 +28,22 @@
|
||||||
#include "object.hpp"
|
#include "object.hpp"
|
||||||
#include "elements.hpp"
|
#include "elements.hpp"
|
||||||
#include "editmode.hpp"
|
#include "editmode.hpp"
|
||||||
|
#include "instancemode.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
static const char * const sMappingSettings[] =
|
||||||
|
{
|
||||||
|
"p-navi", "s-navi",
|
||||||
|
"p-edit", "s-edit",
|
||||||
|
"select",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
|
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
|
||||||
: SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document),
|
: SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document),
|
||||||
mInteractionMask (0)
|
mInteractionMask (0), mEditMode (0), mLocked (false), mDragging (false)
|
||||||
{
|
{
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
|
|
||||||
|
@ -59,6 +74,17 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg
|
||||||
this, SLOT (debugProfileDataChanged (const QModelIndex&, const QModelIndex&)));
|
this, SLOT (debugProfileDataChanged (const QModelIndex&, const QModelIndex&)));
|
||||||
connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
||||||
this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int)));
|
this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int)));
|
||||||
|
|
||||||
|
for (int i=0; sMappingSettings[i]; ++i)
|
||||||
|
{
|
||||||
|
QString key ("scene-input/");
|
||||||
|
key += sMappingSettings[i];
|
||||||
|
storeMappingSetting (key, CSMSettings::UserSettings::instance().settingValue (key));
|
||||||
|
}
|
||||||
|
|
||||||
|
mDragFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-factor").toDouble();
|
||||||
|
mDragWheelFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-wheel-factor").toDouble();
|
||||||
|
mDragShiftFactor = CSMSettings::UserSettings::instance().settingValue ("scene-input/drag-shift-factor").toDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVRender::WorldspaceWidget::~WorldspaceWidget ()
|
CSVRender::WorldspaceWidget::~WorldspaceWidget ()
|
||||||
|
@ -178,11 +204,14 @@ CSVWidget::SceneToolRun *CSVRender::WorldspaceWidget::makeRunTool (
|
||||||
CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeEditModeSelector (
|
CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeEditModeSelector (
|
||||||
CSVWidget::SceneToolbar *parent)
|
CSVWidget::SceneToolbar *parent)
|
||||||
{
|
{
|
||||||
CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Edit Mode");
|
mEditMode = new CSVWidget::SceneToolMode (parent, "Edit Mode");
|
||||||
|
|
||||||
addEditModeSelectorButtons (tool);
|
addEditModeSelectorButtons (mEditMode);
|
||||||
|
|
||||||
return tool;
|
connect (mEditMode, SIGNAL (modeChanged (const std::string&)),
|
||||||
|
this, SLOT (editModeChanged (const std::string&)));
|
||||||
|
|
||||||
|
return mEditMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVRender::WorldspaceWidget::DropType CSVRender::WorldspaceWidget::getDropType (
|
CSVRender::WorldspaceWidget::DropType CSVRender::WorldspaceWidget::getDropType (
|
||||||
|
@ -254,6 +283,26 @@ unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const
|
||||||
return mInteractionMask & getVisibilityMask();
|
return mInteractionMask & getVisibilityMask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::WorldspaceWidget::updateUserSetting (const QString& name, const QStringList& value)
|
||||||
|
{
|
||||||
|
if (!value.isEmpty() && storeMappingSetting (name, value.first()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (name=="scene-input/drag-factor")
|
||||||
|
mDragFactor = value.at (0).toDouble();
|
||||||
|
else if (name=="scene-input/drag-wheel-factor")
|
||||||
|
mDragWheelFactor = value.at (0).toDouble();
|
||||||
|
else if (name=="scene-input/drag-shift-factor")
|
||||||
|
mDragShiftFactor = value.at (0).toDouble();
|
||||||
|
else
|
||||||
|
dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent()).updateUserSetting (name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::WorldspaceWidget::setEditLock (bool locked)
|
||||||
|
{
|
||||||
|
dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent()).setEditLock (locked);
|
||||||
|
}
|
||||||
|
|
||||||
void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons (
|
void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons (
|
||||||
CSVWidget::SceneToolToggle2 *tool)
|
CSVWidget::SceneToolToggle2 *tool)
|
||||||
{
|
{
|
||||||
|
@ -265,9 +314,7 @@ void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons (
|
||||||
void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool)
|
void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool)
|
||||||
{
|
{
|
||||||
/// \todo replace EditMode with suitable subclasses
|
/// \todo replace EditMode with suitable subclasses
|
||||||
tool->addButton (
|
tool->addButton (new InstanceMode (this, tool), "object");
|
||||||
new EditMode (this, QIcon (":placeholder"), Element_Reference, "Instance editing"),
|
|
||||||
"object");
|
|
||||||
tool->addButton (
|
tool->addButton (
|
||||||
new EditMode (this, QIcon (":placeholder"), Element_Pathgrid, "Pathgrid editing"),
|
new EditMode (this, QIcon (":placeholder"), Element_Pathgrid, "Pathgrid editing"),
|
||||||
"pathgrid");
|
"pathgrid");
|
||||||
|
@ -288,6 +335,95 @@ void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event)
|
||||||
event->accept();
|
event->accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool CSVRender::WorldspaceWidget::storeMappingSetting (const QString& key, const QString& value)
|
||||||
|
{
|
||||||
|
const QString prefix = "scene-input/";
|
||||||
|
|
||||||
|
if (key.startsWith (prefix))
|
||||||
|
{
|
||||||
|
QString key2 (key.mid (prefix.length()));
|
||||||
|
|
||||||
|
for (int i=0; sMappingSettings[i]; ++i)
|
||||||
|
if (key2==sMappingSettings[i])
|
||||||
|
{
|
||||||
|
Qt::MouseButton button = Qt::NoButton;
|
||||||
|
|
||||||
|
if (value.endsWith ("Left Mouse-Button"))
|
||||||
|
button = Qt::LeftButton;
|
||||||
|
else if (value.endsWith ("Right Mouse-Button"))
|
||||||
|
button = Qt::RightButton;
|
||||||
|
else if (value.endsWith ("Middle Mouse-Button"))
|
||||||
|
button = Qt::MiddleButton;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool ctrl = value.startsWith ("Ctrl-");
|
||||||
|
|
||||||
|
mButtonMapping[std::make_pair (button, ctrl)] = sMappingSettings[i];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<CSVRender::TagBase> CSVRender::WorldspaceWidget::mousePick (QMouseEvent *event)
|
||||||
|
{
|
||||||
|
// (0,0) is considered the lower left corner of an OpenGL window
|
||||||
|
int x = event->x();
|
||||||
|
int y = height() - event->y();
|
||||||
|
|
||||||
|
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y));
|
||||||
|
|
||||||
|
intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT);
|
||||||
|
osgUtil::IntersectionVisitor visitor(intersector);
|
||||||
|
|
||||||
|
visitor.setTraversalMask(getInteractionMask() << 1);
|
||||||
|
|
||||||
|
mView->getCamera()->accept(visitor);
|
||||||
|
|
||||||
|
for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin();
|
||||||
|
it != intersector->getIntersections().end(); ++it)
|
||||||
|
{
|
||||||
|
osgUtil::LineSegmentIntersector::Intersection intersection = *it;
|
||||||
|
|
||||||
|
// reject back-facing polygons
|
||||||
|
osg::Vec3f normal = intersection.getWorldIntersectNormal();
|
||||||
|
normal = osg::Matrix::transform3x3(normal, mView->getCamera()->getViewMatrix());
|
||||||
|
if (normal.z() < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (std::vector<osg::Node*>::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it)
|
||||||
|
{
|
||||||
|
osg::Node* node = *it;
|
||||||
|
if (osg::ref_ptr<CSVRender::TagBase> tag = dynamic_cast<CSVRender::TagBase *>(node->getUserData()))
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignoring terrain for now
|
||||||
|
// must be terrain, report coordinates
|
||||||
|
// std::cout << "Terrain hit at " << intersection.getWorldIntersectPoint().x() << " " << intersection.getWorldIntersectPoint().y() << std::endl;
|
||||||
|
// return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return osg::ref_ptr<CSVRender::TagBase>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CSVRender::WorldspaceWidget::mapButton (QMouseEvent *event)
|
||||||
|
{
|
||||||
|
std::pair<Qt::MouseButton, bool> phyiscal (
|
||||||
|
event->button(), event->modifiers() & Qt::ControlModifier);
|
||||||
|
|
||||||
|
std::map<std::pair<Qt::MouseButton, bool>, std::string>::const_iterator iter =
|
||||||
|
mButtonMapping.find (phyiscal);
|
||||||
|
|
||||||
|
if (iter!=mButtonMapping.end())
|
||||||
|
return iter->second;
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event)
|
void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event)
|
||||||
{
|
{
|
||||||
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
|
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
|
||||||
|
@ -352,6 +488,12 @@ void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelInde
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::WorldspaceWidget::editModeChanged (const std::string& id)
|
||||||
|
{
|
||||||
|
dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent()).setEditLock (mLocked);
|
||||||
|
mDragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
void CSVRender::WorldspaceWidget::elementSelectionChanged()
|
void CSVRender::WorldspaceWidget::elementSelectionChanged()
|
||||||
{
|
{
|
||||||
setVisibilityMask (getVisibilityMask());
|
setVisibilityMask (getVisibilityMask());
|
||||||
|
@ -365,74 +507,97 @@ void CSVRender::WorldspaceWidget::updateOverlay()
|
||||||
|
|
||||||
void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event)
|
void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event)
|
||||||
{
|
{
|
||||||
if(event->buttons() & Qt::RightButton)
|
if (!mDragging)
|
||||||
{
|
{
|
||||||
//mMouse->mouseMoveEvent(event);
|
if (mDragMode=="p-navi" || mDragMode=="s-navi")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="select")
|
||||||
|
{
|
||||||
|
osg::ref_ptr<TagBase> tag = mousePick (event);
|
||||||
|
|
||||||
|
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
||||||
|
|
||||||
|
if (mDragMode=="p-edit")
|
||||||
|
mDragging = editMode.primaryEditStartDrag (tag);
|
||||||
|
else if (mDragMode=="s-edit")
|
||||||
|
mDragging = editMode.secondaryEditStartDrag (tag);
|
||||||
|
else if (mDragMode=="select")
|
||||||
|
mDragging = editMode.selectStartDrag (tag);
|
||||||
|
|
||||||
|
if (mDragging)
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||||
|
mDragX = event->localPos().x();
|
||||||
|
mDragY = height() - event->localPos().y();
|
||||||
|
#else
|
||||||
|
mDragX = event->posF().x();
|
||||||
|
mDragY = height() - event->posF().y();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int diffX = event->x() - mDragX;
|
||||||
|
int diffY = (height() - event->y()) - mDragY;
|
||||||
|
|
||||||
|
mDragX = event->x();
|
||||||
|
mDragY = height() - event->y();
|
||||||
|
|
||||||
|
double factor = mDragFactor;
|
||||||
|
|
||||||
|
if (event->modifiers() & Qt::ShiftModifier)
|
||||||
|
factor *= mDragShiftFactor;
|
||||||
|
|
||||||
|
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
||||||
|
|
||||||
|
editMode.drag (diffX, diffY, factor);
|
||||||
}
|
}
|
||||||
RenderWidget::mouseMoveEvent(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event)
|
void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event)
|
||||||
{
|
{
|
||||||
if (event->button() != Qt::RightButton)
|
std::string button = mapButton (event);
|
||||||
return;
|
|
||||||
|
|
||||||
// (0,0) is considered the lower left corner of an OpenGL window
|
if (!mDragging)
|
||||||
int x = event->x();
|
mDragMode = button;
|
||||||
int y = height() - event->y();
|
|
||||||
|
|
||||||
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y));
|
|
||||||
|
|
||||||
intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT);
|
|
||||||
osgUtil::IntersectionVisitor visitor(intersector);
|
|
||||||
|
|
||||||
visitor.setTraversalMask(getInteractionMask() << 1);
|
|
||||||
|
|
||||||
mView->getCamera()->accept(visitor);
|
|
||||||
|
|
||||||
for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin();
|
|
||||||
it != intersector->getIntersections().end(); ++it)
|
|
||||||
{
|
|
||||||
osgUtil::LineSegmentIntersector::Intersection intersection = *it;
|
|
||||||
|
|
||||||
// reject back-facing polygons
|
|
||||||
osg::Vec3f normal = intersection.getWorldIntersectNormal();
|
|
||||||
normal = osg::Matrix::transform3x3(normal, mView->getCamera()->getViewMatrix());
|
|
||||||
if (normal.z() < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (std::vector<osg::Node*>::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it)
|
|
||||||
{
|
|
||||||
osg::Node* node = *it;
|
|
||||||
if (CSVRender::ObjectHolder* holder = dynamic_cast<CSVRender::ObjectHolder*>(node->getUserData()))
|
|
||||||
{
|
|
||||||
// hit an Object, toggle its selection state
|
|
||||||
CSVRender::Object* obj = holder->mObject;
|
|
||||||
obj->setSelected(!obj->getSelected());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// must be terrain, report coordinates
|
|
||||||
std::cout << "Terrain hit at " << intersection.getWorldIntersectPoint().x() << " " << intersection.getWorldIntersectPoint().y() << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event)
|
void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event)
|
||||||
{
|
{
|
||||||
if(event->button() == Qt::RightButton)
|
std::string button = mapButton (event);
|
||||||
|
|
||||||
|
if (mDragging)
|
||||||
{
|
{
|
||||||
/*
|
if (mDragMode=="p-navi" || mDragMode=="s-navi")
|
||||||
if(!getViewport())
|
|
||||||
{
|
{
|
||||||
SceneWidget::mouseReleaseEvent(event);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
*/
|
else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="select")
|
||||||
//mMouse->mouseReleaseEvent(event);
|
{
|
||||||
|
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
||||||
|
|
||||||
|
editMode.dragCompleted();
|
||||||
|
mDragging = false;
|
||||||
}
|
}
|
||||||
RenderWidget::mouseReleaseEvent(event);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (button=="p-navi" || button=="s-navi")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (button=="p-edit" || button=="s-edit" || button=="select")
|
||||||
|
{
|
||||||
|
osg::ref_ptr<TagBase> tag = mousePick (event);
|
||||||
|
|
||||||
|
handleMouseClick (tag, button, event->modifiers() & Qt::ShiftModifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mDragMode.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event)
|
void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event)
|
||||||
|
@ -441,21 +606,47 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event)
|
||||||
{
|
{
|
||||||
//mMouse->mouseDoubleClickEvent(event);
|
//mMouse->mouseDoubleClickEvent(event);
|
||||||
}
|
}
|
||||||
//SceneWidget::mouseDoubleClickEvent(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event)
|
void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event)
|
||||||
{
|
{
|
||||||
//if(!mMouse->wheelEvent(event))
|
if (mDragging)
|
||||||
RenderWidget::wheelEvent(event);
|
{
|
||||||
|
double factor = mDragWheelFactor;
|
||||||
|
|
||||||
|
if (event->modifiers() & Qt::ShiftModifier)
|
||||||
|
factor *= mDragShiftFactor;
|
||||||
|
|
||||||
|
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
||||||
|
|
||||||
|
editMode.dragWheel (event->delta(), factor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event)
|
void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event)
|
||||||
{
|
{
|
||||||
if(event->key() == Qt::Key_Escape)
|
if(event->key() == Qt::Key_Escape)
|
||||||
{
|
{
|
||||||
//mMouse->cancelDrag();
|
if (mDragging)
|
||||||
|
{
|
||||||
|
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
||||||
|
|
||||||
|
editMode.dragAborted();
|
||||||
|
mDragging = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
RenderWidget::keyPressEvent(event);
|
RenderWidget::keyPressEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::WorldspaceWidget::handleMouseClick (osg::ref_ptr<TagBase> tag, const std::string& button, bool shift)
|
||||||
|
{
|
||||||
|
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
||||||
|
|
||||||
|
if (button=="p-edit")
|
||||||
|
editMode.primaryEditPressed (tag);
|
||||||
|
else if (button=="s-edit")
|
||||||
|
editMode.secondaryEditPressed (tag);
|
||||||
|
else if (button=="select")
|
||||||
|
editMode.selectPressed (tag);
|
||||||
|
}
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
#ifndef OPENCS_VIEW_WORLDSPACEWIDGET_H
|
#ifndef OPENCS_VIEW_WORLDSPACEWIDGET_H
|
||||||
#define OPENCS_VIEW_WORLDSPACEWIDGET_H
|
#define OPENCS_VIEW_WORLDSPACEWIDGET_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
#include "scenewidget.hpp"
|
#include "../../model/doc/document.hpp"
|
||||||
|
#include "../../model/world/tablemimedata.hpp"
|
||||||
|
|
||||||
#include <apps/opencs/model/doc/document.hpp>
|
#include "scenewidget.hpp"
|
||||||
#include <apps/opencs/model/world/tablemimedata.hpp>
|
#include "elements.hpp"
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
|
@ -23,6 +26,9 @@ namespace CSVWidget
|
||||||
|
|
||||||
namespace CSVRender
|
namespace CSVRender
|
||||||
{
|
{
|
||||||
|
class TagBase;
|
||||||
|
class CellArrow;
|
||||||
|
|
||||||
class WorldspaceWidget : public SceneWidget
|
class WorldspaceWidget : public SceneWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -31,6 +37,16 @@ namespace CSVRender
|
||||||
CSVWidget::SceneToolRun *mRun;
|
CSVWidget::SceneToolRun *mRun;
|
||||||
CSMDoc::Document& mDocument;
|
CSMDoc::Document& mDocument;
|
||||||
unsigned int mInteractionMask;
|
unsigned int mInteractionMask;
|
||||||
|
std::map<std::pair<Qt::MouseButton, bool>, std::string> mButtonMapping;
|
||||||
|
CSVWidget::SceneToolMode *mEditMode;
|
||||||
|
bool mLocked;
|
||||||
|
std::string mDragMode;
|
||||||
|
bool mDragging;
|
||||||
|
int mDragX;
|
||||||
|
int mDragY;
|
||||||
|
double mDragFactor;
|
||||||
|
double mDragWheelFactor;
|
||||||
|
double mDragShiftFactor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -93,14 +109,21 @@ namespace CSVRender
|
||||||
/// marked for interaction.
|
/// marked for interaction.
|
||||||
unsigned int getInteractionMask() const;
|
unsigned int getInteractionMask() const;
|
||||||
|
|
||||||
|
virtual void updateUserSetting (const QString& name, const QStringList& value);
|
||||||
|
|
||||||
|
virtual void setEditLock (bool locked);
|
||||||
|
|
||||||
|
CSMDoc::Document& getDocument();
|
||||||
|
|
||||||
|
/// \param elementMask Elements to be affected by the clear operation
|
||||||
|
virtual void clearSelection (int elementMask) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);
|
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);
|
||||||
|
|
||||||
virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool);
|
virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool);
|
||||||
|
|
||||||
CSMDoc::Document& getDocument();
|
|
||||||
|
|
||||||
virtual void updateOverlay();
|
virtual void updateOverlay();
|
||||||
|
|
||||||
virtual void mouseMoveEvent (QMouseEvent *event);
|
virtual void mouseMoveEvent (QMouseEvent *event);
|
||||||
|
@ -110,6 +133,9 @@ namespace CSVRender
|
||||||
virtual void wheelEvent (QWheelEvent *event);
|
virtual void wheelEvent (QWheelEvent *event);
|
||||||
virtual void keyPressEvent (QKeyEvent *event);
|
virtual void keyPressEvent (QKeyEvent *event);
|
||||||
|
|
||||||
|
virtual void handleMouseClick (osg::ref_ptr<TagBase> tag, const std::string& button,
|
||||||
|
bool shift);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void dragEnterEvent(QDragEnterEvent *event);
|
void dragEnterEvent(QDragEnterEvent *event);
|
||||||
|
@ -118,6 +144,13 @@ namespace CSVRender
|
||||||
|
|
||||||
void dragMoveEvent(QDragMoveEvent *event);
|
void dragMoveEvent(QDragMoveEvent *event);
|
||||||
|
|
||||||
|
/// \return Is \a key a button mapping setting? (ignored otherwise)
|
||||||
|
bool storeMappingSetting (const QString& key, const QString& value);
|
||||||
|
|
||||||
|
osg::ref_ptr<TagBase> mousePick (QMouseEvent *event);
|
||||||
|
|
||||||
|
std::string mapButton (QMouseEvent *event);
|
||||||
|
|
||||||
virtual std::string getStartupInstruction() = 0;
|
virtual std::string getStartupInstruction() = 0;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -144,6 +177,7 @@ namespace CSVRender
|
||||||
|
|
||||||
void debugProfileAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
void debugProfileAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
|
void editModeChanged (const std::string& id);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,11 @@ void CSVWidget::SceneToolMode::addButton (ModeButton *button, const std::string&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSVWidget::ModeButton *CSVWidget::SceneToolMode::getCurrent()
|
||||||
|
{
|
||||||
|
return mCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
void CSVWidget::SceneToolMode::selected()
|
void CSVWidget::SceneToolMode::selected()
|
||||||
{
|
{
|
||||||
std::map<ModeButton *, std::string>::const_iterator iter =
|
std::map<ModeButton *, std::string>::const_iterator iter =
|
||||||
|
|
|
@ -41,6 +41,9 @@ namespace CSVWidget
|
||||||
/// The ownership of \a button is transferred to *this.
|
/// The ownership of \a button is transferred to *this.
|
||||||
void addButton (ModeButton *button, const std::string& id);
|
void addButton (ModeButton *button, const std::string& id);
|
||||||
|
|
||||||
|
/// Will return a 0-pointer only if the mode does not have any buttons yet.
|
||||||
|
ModeButton *getCurrent();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void modeChanged (const std::string& id);
|
void modeChanged (const std::string& id);
|
||||||
|
|
|
@ -47,6 +47,16 @@ std::string CSVWorld::GenericCreator::getId() const
|
||||||
return mId->text().toUtf8().constData();
|
return mId->text().toUtf8().constData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CSVWorld::GenericCreator::getIdValidatorResult() const
|
||||||
|
{
|
||||||
|
std::string errors;
|
||||||
|
|
||||||
|
if (!mId->hasAcceptableInput())
|
||||||
|
errors = mValidator->getError();
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
void CSVWorld::GenericCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const {}
|
void CSVWorld::GenericCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const {}
|
||||||
|
|
||||||
void CSVWorld::GenericCreator::pushCommand (std::auto_ptr<CSMWorld::CreateCommand> command,
|
void CSVWorld::GenericCreator::pushCommand (std::auto_ptr<CSMWorld::CreateCommand> command,
|
||||||
|
|
|
@ -60,6 +60,8 @@ namespace CSVWorld
|
||||||
|
|
||||||
virtual std::string getId() const;
|
virtual std::string getId() const;
|
||||||
|
|
||||||
|
virtual std::string getIdValidatorResult() const;
|
||||||
|
|
||||||
/// Allow subclasses to add additional data to \a command.
|
/// Allow subclasses to add additional data to \a command.
|
||||||
virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const;
|
virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const;
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "../render/pagedworldspacewidget.hpp"
|
#include "../render/pagedworldspacewidget.hpp"
|
||||||
#include "../render/unpagedworldspacewidget.hpp"
|
#include "../render/unpagedworldspacewidget.hpp"
|
||||||
|
#include "../render/editmode.hpp"
|
||||||
|
|
||||||
#include "../widget/scenetoolbar.hpp"
|
#include "../widget/scenetoolbar.hpp"
|
||||||
#include "../widget/scenetoolmode.hpp"
|
#include "../widget/scenetoolmode.hpp"
|
||||||
|
@ -121,15 +122,14 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp
|
||||||
CSVWidget::SceneToolRun *runTool = widget->makeRunTool (toolbar);
|
CSVWidget::SceneToolRun *runTool = widget->makeRunTool (toolbar);
|
||||||
toolbar->addTool (runTool);
|
toolbar->addTool (runTool);
|
||||||
|
|
||||||
CSVWidget::SceneToolMode *editModeTool = widget->makeEditModeSelector (toolbar);
|
toolbar->addTool (widget->makeEditModeSelector (toolbar));
|
||||||
toolbar->addTool (editModeTool);
|
|
||||||
|
|
||||||
return toolbar;
|
return toolbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::SceneSubView::setEditLock (bool locked)
|
void CSVWorld::SceneSubView::setEditLock (bool locked)
|
||||||
{
|
{
|
||||||
|
mScene->setEditLock (locked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::SceneSubView::setStatusBar (bool show)
|
void CSVWorld::SceneSubView::setStatusBar (bool show)
|
||||||
|
@ -147,6 +147,12 @@ std::string CSVWorld::SceneSubView::getTitle() const
|
||||||
return mTitle;
|
return mTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::SceneSubView::updateUserSetting (const QString& name, const QStringList& value)
|
||||||
|
{
|
||||||
|
mScene->updateUserSetting (name, value);
|
||||||
|
CSVDoc::SubView::updateUserSetting (name, value);
|
||||||
|
}
|
||||||
|
|
||||||
void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::UniversalId& id)
|
void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::UniversalId& id)
|
||||||
{
|
{
|
||||||
setUniversalId(id);
|
setUniversalId(id);
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace CSVRender
|
||||||
namespace CSVWidget
|
namespace CSVWidget
|
||||||
{
|
{
|
||||||
class SceneToolbar;
|
class SceneToolbar;
|
||||||
|
class SceneToolMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace CSVWorld
|
namespace CSVWorld
|
||||||
|
@ -58,6 +59,8 @@ namespace CSVWorld
|
||||||
|
|
||||||
virtual std::string getTitle() const;
|
virtual std::string getTitle() const;
|
||||||
|
|
||||||
|
virtual void updateUserSetting (const QString& name, const QStringList& value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void makeConnections(CSVRender::PagedWorldspaceWidget* widget);
|
void makeConnections(CSVRender::PagedWorldspaceWidget* widget);
|
||||||
|
|
|
@ -198,16 +198,33 @@ void CSVWorld::ScriptSubView::useHint (const std::string& hint)
|
||||||
if (hint.empty())
|
if (hint.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (hint[0]=='l')
|
unsigned line = 0, column = 0;
|
||||||
{
|
char c;
|
||||||
std::istringstream stream (hint.c_str()+1);
|
std::istringstream stream (hint.c_str()+1);
|
||||||
|
switch(hint[0]){
|
||||||
char ignore;
|
case 'R':
|
||||||
int line;
|
case 'r':
|
||||||
int column;
|
|
||||||
|
|
||||||
if (stream >> ignore >> line >> column)
|
|
||||||
{
|
{
|
||||||
|
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
|
||||||
|
QString source = mModel->data (index).toString();
|
||||||
|
unsigned pos, dummy;
|
||||||
|
if (!(stream >> c >> dummy >> pos) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i <= pos; ++i){
|
||||||
|
if (source[i] == '\n'){
|
||||||
|
++line;
|
||||||
|
column = i+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
column = pos - column;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'l':
|
||||||
|
if (!(stream >> c >> line >> column))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QTextCursor cursor = mEditor->textCursor();
|
QTextCursor cursor = mEditor->textCursor();
|
||||||
|
|
||||||
cursor.movePosition (QTextCursor::Start);
|
cursor.movePosition (QTextCursor::Start);
|
||||||
|
@ -216,8 +233,6 @@ void CSVWorld::ScriptSubView::useHint (const std::string& hint)
|
||||||
|
|
||||||
mEditor->setFocus();
|
mEditor->setFocus();
|
||||||
mEditor->setTextCursor (cursor);
|
mEditor->setTextCursor (cursor);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::ScriptSubView::textChanged()
|
void CSVWorld::ScriptSubView::textChanged()
|
||||||
|
|
20
apps/opencs/view/world/startscriptcreator.cpp
Normal file
20
apps/opencs/view/world/startscriptcreator.cpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#include "startscriptcreator.hpp"
|
||||||
|
|
||||||
|
CSVWorld::StartScriptCreator::StartScriptCreator(CSMWorld::Data &data, QUndoStack &undoStack, const CSMWorld::UniversalId &id, bool relaxedIdRules):
|
||||||
|
GenericCreator (data, undoStack, id, true)
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string CSVWorld::StartScriptCreator::getErrors() const
|
||||||
|
{
|
||||||
|
std::string errors;
|
||||||
|
|
||||||
|
errors = getIdValidatorResult();
|
||||||
|
if (errors.length() > 0)
|
||||||
|
return errors;
|
||||||
|
else if (getData().getScripts().searchId(getId()) == -1)
|
||||||
|
errors = "Script ID not found";
|
||||||
|
else if (getData().getStartScripts().searchId(getId()) > -1 )
|
||||||
|
errors = "Script with this ID already registered as Start Script";
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
25
apps/opencs/view/world/startscriptcreator.hpp
Normal file
25
apps/opencs/view/world/startscriptcreator.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef STARTSCRIPTCREATOR_HPP
|
||||||
|
#define STARTSCRIPTCREATOR_HPP
|
||||||
|
|
||||||
|
#include "genericcreator.hpp"
|
||||||
|
|
||||||
|
namespace CSVWorld {
|
||||||
|
|
||||||
|
class StartScriptCreator : public GenericCreator
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
StartScriptCreator(CSMWorld::Data& data, QUndoStack& undoStack,
|
||||||
|
const CSMWorld::UniversalId& id, bool relaxedIdRules = false);
|
||||||
|
|
||||||
|
virtual std::string getErrors() const;
|
||||||
|
///< Return formatted error descriptions for the current state of the creator. if an empty
|
||||||
|
/// string is returned, there is no error.
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // STARTSCRIPTCREATOR_HPP
|
|
@ -10,6 +10,7 @@
|
||||||
#include "cellcreator.hpp"
|
#include "cellcreator.hpp"
|
||||||
#include "referenceablecreator.hpp"
|
#include "referenceablecreator.hpp"
|
||||||
#include "referencecreator.hpp"
|
#include "referencecreator.hpp"
|
||||||
|
#include "startscriptcreator.hpp"
|
||||||
#include "scenesubview.hpp"
|
#include "scenesubview.hpp"
|
||||||
#include "dialoguecreator.hpp"
|
#include "dialoguecreator.hpp"
|
||||||
#include "infocreator.hpp"
|
#include "infocreator.hpp"
|
||||||
|
@ -42,7 +43,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
||||||
CSMWorld::UniversalId::Type_BodyParts,
|
CSMWorld::UniversalId::Type_BodyParts,
|
||||||
CSMWorld::UniversalId::Type_SoundGens,
|
CSMWorld::UniversalId::Type_SoundGens,
|
||||||
CSMWorld::UniversalId::Type_Pathgrids,
|
CSMWorld::UniversalId::Type_Pathgrids,
|
||||||
CSMWorld::UniversalId::Type_StartScripts,
|
|
||||||
|
|
||||||
CSMWorld::UniversalId::Type_None // end marker
|
CSMWorld::UniversalId::Type_None // end marker
|
||||||
};
|
};
|
||||||
|
@ -51,6 +51,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
||||||
manager.add (sTableTypes[i],
|
manager.add (sTableTypes[i],
|
||||||
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GenericCreator> >);
|
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GenericCreator> >);
|
||||||
|
|
||||||
|
manager.add (CSMWorld::UniversalId::Type_StartScripts,
|
||||||
|
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<StartScriptCreator> >);
|
||||||
|
|
||||||
manager.add (CSMWorld::UniversalId::Type_Cells,
|
manager.add (CSMWorld::UniversalId::Type_Cells,
|
||||||
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<CellCreator> >);
|
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<CellCreator> >);
|
||||||
|
|
||||||
|
@ -123,7 +126,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
||||||
CSMWorld::UniversalId::Type_BodyPart,
|
CSMWorld::UniversalId::Type_BodyPart,
|
||||||
CSMWorld::UniversalId::Type_SoundGen,
|
CSMWorld::UniversalId::Type_SoundGen,
|
||||||
CSMWorld::UniversalId::Type_Pathgrid,
|
CSMWorld::UniversalId::Type_Pathgrid,
|
||||||
CSMWorld::UniversalId::Type_StartScript,
|
|
||||||
|
|
||||||
CSMWorld::UniversalId::Type_None // end marker
|
CSMWorld::UniversalId::Type_None // end marker
|
||||||
};
|
};
|
||||||
|
@ -133,6 +135,10 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
||||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView,
|
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView,
|
||||||
CreatorFactory<GenericCreator> > (false));
|
CreatorFactory<GenericCreator> > (false));
|
||||||
|
|
||||||
|
manager.add (CSMWorld::UniversalId::Type_StartScript,
|
||||||
|
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView,
|
||||||
|
CreatorFactory<StartScriptCreator> > (false));
|
||||||
|
|
||||||
manager.add (CSMWorld::UniversalId::Type_Skill,
|
manager.add (CSMWorld::UniversalId::Type_Skill,
|
||||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, NullCreatorFactory > (false));
|
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, NullCreatorFactory > (false));
|
||||||
|
|
||||||
|
|
|
@ -234,6 +234,11 @@ namespace MWClass
|
||||||
|
|
||||||
std::pair<int, std::string> Light::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
|
std::pair<int, std::string> Light::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
|
||||||
{
|
{
|
||||||
|
MWWorld::LiveCellRef<ESM::Light> *ref =
|
||||||
|
ptr.get<ESM::Light>();
|
||||||
|
if (!(ref->mBase->mData.mFlags & ESM::Light::Carry))
|
||||||
|
return std::make_pair(0,"");
|
||||||
|
|
||||||
MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc);
|
MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc);
|
||||||
MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
|
|
||||||
|
|
|
@ -139,9 +139,6 @@ namespace MWDialogue
|
||||||
|
|
||||||
win->startDialogue(actor, actor.getClass().getName (actor), resetHistory);
|
win->startDialogue(actor, actor.getClass().getName (actor), resetHistory);
|
||||||
|
|
||||||
//setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI
|
|
||||||
updateTopics();
|
|
||||||
|
|
||||||
//greeting
|
//greeting
|
||||||
const MWWorld::Store<ESM::Dialogue> &dialogs =
|
const MWWorld::Store<ESM::Dialogue> &dialogs =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>();
|
||||||
|
@ -165,12 +162,19 @@ namespace MWDialogue
|
||||||
// TODO play sound
|
// TODO play sound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// first topics update so that parseText knows the keywords to highlight
|
||||||
|
updateTopics();
|
||||||
|
|
||||||
parseText (info->mResponse);
|
parseText (info->mResponse);
|
||||||
|
|
||||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||||
win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
||||||
executeScript (info->mResultScript);
|
executeScript (info->mResultScript);
|
||||||
mLastTopic = Misc::StringUtils::lowerCase(it->mId);
|
mLastTopic = Misc::StringUtils::lowerCase(it->mId);
|
||||||
|
|
||||||
|
// update topics again to accomodate changes resulting from executeScript
|
||||||
|
updateTopics();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -420,7 +424,6 @@ namespace MWDialogue
|
||||||
{
|
{
|
||||||
if(mDialogueMap.find(keyword) != mDialogueMap.end())
|
if(mDialogueMap.find(keyword) != mDialogueMap.end())
|
||||||
{
|
{
|
||||||
ESM::Dialogue ndialogue = mDialogueMap[keyword];
|
|
||||||
if (mDialogueMap[keyword].mType == ESM::Dialogue::Topic)
|
if (mDialogueMap[keyword].mType == ESM::Dialogue::Topic)
|
||||||
{
|
{
|
||||||
executeTopic (keyword);
|
executeTopic (keyword);
|
||||||
|
|
|
@ -170,25 +170,25 @@ namespace MWGui
|
||||||
mCommandLine->setFontName(fntName);
|
mCommandLine->setFontName(fntName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::print(const std::string &msg)
|
void Console::print(const std::string &msg, const std::string& color)
|
||||||
{
|
{
|
||||||
mHistory->addText(msg);
|
mHistory->addText(color + MyGUI::TextIterator::toTagsString(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::printOK(const std::string &msg)
|
void Console::printOK(const std::string &msg)
|
||||||
{
|
{
|
||||||
print("#FF00FF" + msg + "\n");
|
print(msg + "\n", "#FF00FF");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::printError(const std::string &msg)
|
void Console::printError(const std::string &msg)
|
||||||
{
|
{
|
||||||
print("#FF2222" + msg + "\n");
|
print(msg + "\n", "#FF2222");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::execute (const std::string& command)
|
void Console::execute (const std::string& command)
|
||||||
{
|
{
|
||||||
// Log the command
|
// Log the command
|
||||||
print("#FFFFFF> " + command + "\n");
|
print("> " + command + "\n");
|
||||||
|
|
||||||
Compiler::Locals locals;
|
Compiler::Locals locals;
|
||||||
Compiler::Output output (locals);
|
Compiler::Output output (locals);
|
||||||
|
|
|
@ -48,9 +48,8 @@ namespace MWGui
|
||||||
|
|
||||||
void onResChange(int width, int height);
|
void onResChange(int width, int height);
|
||||||
|
|
||||||
// Print a message to the console. Messages may contain color
|
// Print a message to the console, in specified color.
|
||||||
// code, eg. "#FFFFFF this is white".
|
void print(const std::string &msg, const std::string& color = "#FFFFFF");
|
||||||
void print(const std::string &msg);
|
|
||||||
|
|
||||||
// These are pre-colored versions that you should use.
|
// These are pre-colored versions that you should use.
|
||||||
|
|
||||||
|
|
|
@ -167,11 +167,12 @@ namespace MWGui
|
||||||
MyGUI::IntSize size(static_cast<int>(Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width),
|
MyGUI::IntSize size(static_cast<int>(Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width),
|
||||||
static_cast<int>(Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height));
|
static_cast<int>(Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height));
|
||||||
|
|
||||||
|
mMainWidget->setPosition(pos);
|
||||||
|
mMainWidget->setSize(size);
|
||||||
|
|
||||||
if (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight())
|
if (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight())
|
||||||
updatePreviewSize();
|
updatePreviewSize();
|
||||||
|
|
||||||
mMainWidget->setPosition(pos);
|
|
||||||
mMainWidget->setSize(size);
|
|
||||||
adjustPanes();
|
adjustPanes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -235,13 +235,38 @@ namespace MWGui
|
||||||
draw();
|
draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadingScreen::draw()
|
bool LoadingScreen::needToDrawLoadingScreen()
|
||||||
{
|
{
|
||||||
if (mTimer.time_m() > mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0)
|
if ( mTimer.time_m() <= mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// the minimal delay before a loading screen shows
|
||||||
|
const float initialDelay = 0.05;
|
||||||
|
|
||||||
|
bool alreadyShown = (mLastRenderTime > mLoadingOnTime);
|
||||||
|
float diff = (mTimer.time_m() - mLoadingOnTime);
|
||||||
|
|
||||||
|
if (!alreadyShown)
|
||||||
{
|
{
|
||||||
|
// bump the delay by the current progress - i.e. if during the initial delay the loading
|
||||||
|
// has almost finished, no point showing the loading screen now
|
||||||
|
diff -= mProgress / static_cast<float>(mProgressBar->getScrollRange()) * 100.f;
|
||||||
|
}
|
||||||
|
|
||||||
bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState()
|
bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState()
|
||||||
== MWBase::StateManager::State_NoGame);
|
== MWBase::StateManager::State_NoGame);
|
||||||
|
if (!showWallpaper && diff < initialDelay*1000)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadingScreen::draw()
|
||||||
|
{
|
||||||
|
if (!needToDrawLoadingScreen())
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState()
|
||||||
|
== MWBase::StateManager::State_NoGame);
|
||||||
if (showWallpaper && mTimer.time_m() > mLastWallpaperChangeTime + 5000*1)
|
if (showWallpaper && mTimer.time_m() > mLastWallpaperChangeTime + 5000*1)
|
||||||
{
|
{
|
||||||
mLastWallpaperChangeTime = mTimer.time_m();
|
mLastWallpaperChangeTime = mTimer.time_m();
|
||||||
|
@ -269,6 +294,5 @@ namespace MWGui
|
||||||
|
|
||||||
mLastRenderTime = mTimer.time_m();
|
mLastRenderTime = mTimer.time_m();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ namespace MWGui
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void findSplashScreens();
|
void findSplashScreens();
|
||||||
|
bool needToDrawLoadingScreen();
|
||||||
|
|
||||||
const VFS::Manager* mVFS;
|
const VFS::Manager* mVFS;
|
||||||
osg::ref_ptr<osgViewer::Viewer> mViewer;
|
osg::ref_ptr<osgViewer::Viewer> mViewer;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "spellmodel.hpp"
|
#include "spellmodel.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -79,8 +81,13 @@ namespace MWGui
|
||||||
const std::string enchantId = item.getClass().getEnchantment(item);
|
const std::string enchantId = item.getClass().getEnchantment(item);
|
||||||
if (enchantId.empty())
|
if (enchantId.empty())
|
||||||
continue;
|
continue;
|
||||||
const ESM::Enchantment* enchant =
|
const ESM::Enchantment* enchant = esmStore.get<ESM::Enchantment>().search(enchantId);
|
||||||
esmStore.get<ESM::Enchantment>().find(item.getClass().getEnchantment(item));
|
if (!enchant)
|
||||||
|
{
|
||||||
|
std::cerr << "Can't find enchantment '" << enchantId << "' on item " << item.getCellRef().getRefId() << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (enchant->mData.mType != ESM::Enchantment::WhenUsed && enchant->mData.mType != ESM::Enchantment::CastOnce)
|
if (enchant->mData.mType != ESM::Enchantment::WhenUsed && enchant->mData.mType != ESM::Enchantment::CastOnce)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,6 @@
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace Widgets
|
|
||||||
{
|
|
||||||
class MWScrollBar;
|
|
||||||
}
|
|
||||||
|
|
||||||
class WaitDialogProgressBar : public WindowBase
|
class WaitDialogProgressBar : public WindowBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -51,7 +46,7 @@ namespace MWGui
|
||||||
MyGUI::Button* mUntilHealedButton;
|
MyGUI::Button* mUntilHealedButton;
|
||||||
MyGUI::Button* mWaitButton;
|
MyGUI::Button* mWaitButton;
|
||||||
MyGUI::Button* mCancelButton;
|
MyGUI::Button* mCancelButton;
|
||||||
MWGui::Widgets::MWScrollBar* mHourSlider;
|
MyGUI::ScrollBar* mHourSlider;
|
||||||
|
|
||||||
TimeAdvancer mTimeAdvancer;
|
TimeAdvancer mTimeAdvancer;
|
||||||
bool mSleeping;
|
bool mSleeping;
|
||||||
|
|
|
@ -20,8 +20,9 @@ namespace MWMechanics
|
||||||
struct AiFollowStorage : AiTemporaryBase
|
struct AiFollowStorage : AiTemporaryBase
|
||||||
{
|
{
|
||||||
float mTimer;
|
float mTimer;
|
||||||
|
bool mMoving;
|
||||||
|
|
||||||
AiFollowStorage() : mTimer(0.f) {}
|
AiFollowStorage() : mTimer(0.f), mMoving(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
int AiFollow::mFollowIndexCounter = 0;
|
int AiFollow::mFollowIndexCounter = 0;
|
||||||
|
@ -64,10 +65,11 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
||||||
|
|
||||||
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
|
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
|
||||||
|
|
||||||
|
AiFollowStorage& storage = state.get<AiFollowStorage>();
|
||||||
|
|
||||||
// AiFollow requires the target to be in range and within sight for the initial activation
|
// AiFollow requires the target to be in range and within sight for the initial activation
|
||||||
if (!mActive)
|
if (!mActive)
|
||||||
{
|
{
|
||||||
AiFollowStorage& storage = state.get<AiFollowStorage>();
|
|
||||||
storage.mTimer -= duration;
|
storage.mTimer -= duration;
|
||||||
|
|
||||||
if (storage.mTimer < 0)
|
if (storage.mTimer < 0)
|
||||||
|
@ -126,7 +128,15 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
||||||
//Set the target destination from the actor
|
//Set the target destination from the actor
|
||||||
ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos;
|
ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos;
|
||||||
|
|
||||||
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < followDistance) //Stop when you get close
|
float dist = distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]);
|
||||||
|
const float threshold = 10;
|
||||||
|
|
||||||
|
if (storage.mMoving) //Stop when you get close
|
||||||
|
storage.mMoving = (dist > followDistance);
|
||||||
|
else
|
||||||
|
storage.mMoving = (dist > followDistance + threshold);
|
||||||
|
|
||||||
|
if(!storage.mMoving)
|
||||||
{
|
{
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
|
|
||||||
|
@ -141,9 +151,9 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check if you're far away
|
//Check if you're far away
|
||||||
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) > 450)
|
if(dist > 450)
|
||||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
|
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
|
||||||
else if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold
|
else if(dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold
|
||||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk
|
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -88,7 +88,8 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur
|
||||||
MWWorld::Ptr door = getNearbyDoor(actor);
|
MWWorld::Ptr door = getNearbyDoor(actor);
|
||||||
if (door != MWWorld::Ptr()) // NOTE: checks interior cells only
|
if (door != MWWorld::Ptr()) // NOTE: checks interior cells only
|
||||||
{
|
{
|
||||||
if (!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() && door.getClass().getDoorState(door) == 0) { //Open the door if untrapped
|
if (!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty()
|
||||||
|
&& door.getCellRef().getLockLevel() <= 0 && door.getClass().getDoorState(door) == 0) {
|
||||||
MWBase::Environment::get().getWorld()->activateDoor(door, 1);
|
MWBase::Environment::get().getWorld()->activateDoor(door, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -295,7 +295,7 @@ namespace MWMechanics
|
||||||
creatureStats.getSpells().add(*it);
|
creatureStats.getSpells().add(*it);
|
||||||
|
|
||||||
// forced update and current value adjustments
|
// forced update and current value adjustments
|
||||||
//mActors.updateActor (ptr, 0);
|
mActors.updateActor (ptr, 0);
|
||||||
|
|
||||||
for (int i=0; i<3; ++i)
|
for (int i=0; i<3; ++i)
|
||||||
{
|
{
|
||||||
|
|
|
@ -123,6 +123,9 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (spell->mData.mType == ESM::Spell::ST_Power)
|
||||||
|
return stats.getSpells().canUsePower(spell->mId) ? 100 : 0;
|
||||||
|
|
||||||
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
||||||
return 100;
|
return 100;
|
||||||
|
|
||||||
|
@ -817,6 +820,10 @@ namespace MWMechanics
|
||||||
sndMgr->playSound3D(mCaster, "Spell Failure " + schools[school], 1.0f, 1.0f);
|
sndMgr->playSound3D(mCaster, "Spell Failure " + schools[school], 1.0f, 1.0f);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A power can be used once per 24h
|
||||||
|
if (spell->mData.mType == ESM::Spell::ST_Power)
|
||||||
|
stats.getSpells().usePower(spell->mId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mCaster == getPlayer() && spellIncreasesSkill(spell))
|
if (mCaster == getPlayer() && spellIncreasesSkill(spell))
|
||||||
|
|
|
@ -312,7 +312,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool Spells::canUsePower(const std::string &power) const
|
bool Spells::canUsePower(const std::string &power) const
|
||||||
{
|
{
|
||||||
std::map<std::string, MWWorld::TimeStamp>::const_iterator it = mUsedPowers.find(power);
|
std::map<std::string, MWWorld::TimeStamp>::const_iterator it = mUsedPowers.find(Misc::StringUtils::lowerCase(power));
|
||||||
if (it == mUsedPowers.end() || it->second + 24 <= MWBase::Environment::get().getWorld()->getTimeStamp())
|
if (it == mUsedPowers.end() || it->second + 24 <= MWBase::Environment::get().getWorld()->getTimeStamp())
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
|
@ -321,7 +321,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
void Spells::usePower(const std::string &power)
|
void Spells::usePower(const std::string &power)
|
||||||
{
|
{
|
||||||
mUsedPowers[power] = MWBase::Environment::get().getWorld()->getTimeStamp();
|
mUsedPowers[Misc::StringUtils::lowerCase(power)] = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spells::readState(const ESM::SpellState &state)
|
void Spells::readState(const ESM::SpellState &state)
|
||||||
|
|
|
@ -1275,15 +1275,26 @@ namespace MWRender
|
||||||
material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1));
|
material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1));
|
||||||
stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
||||||
|
|
||||||
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
|
||||||
stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS);
|
|
||||||
stateset->setNestRenderBins(false);
|
|
||||||
mObjectRoot->setStateSet(stateset);
|
mObjectRoot->setStateSet(stateset);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mObjectRoot->setStateSet(NULL);
|
mObjectRoot->setStateSet(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setRenderBin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::setRenderBin()
|
||||||
|
{
|
||||||
|
if (mAlpha != 1.f)
|
||||||
|
{
|
||||||
|
osg::StateSet* stateset = mObjectRoot->getOrCreateStateSet();
|
||||||
|
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||||
|
stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS);
|
||||||
|
}
|
||||||
|
else if (osg::StateSet* stateset = mObjectRoot->getStateSet())
|
||||||
|
stateset->setRenderBinToInherit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::setLightEffect(float effect)
|
void Animation::setLightEffect(float effect)
|
||||||
|
@ -1320,6 +1331,8 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
mHeadController = NULL;
|
mHeadController = NULL;
|
||||||
|
|
||||||
|
if (mPtr.getClass().isBipedal(mPtr))
|
||||||
|
{
|
||||||
NodeMap::iterator found = mNodeMap.find("bip01 head");
|
NodeMap::iterator found = mNodeMap.find("bip01 head");
|
||||||
if (found != mNodeMap.end() && dynamic_cast<osg::MatrixTransform*>(found->second.get()))
|
if (found != mNodeMap.end() && dynamic_cast<osg::MatrixTransform*>(found->second.get()))
|
||||||
{
|
{
|
||||||
|
@ -1329,6 +1342,7 @@ namespace MWRender
|
||||||
mActiveControllers.insert(std::make_pair(node, mHeadController));
|
mActiveControllers.insert(std::make_pair(node, mHeadController));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Animation::setHeadPitch(float pitchRadians)
|
void Animation::setHeadPitch(float pitchRadians)
|
||||||
{
|
{
|
||||||
|
|
|
@ -307,6 +307,9 @@ protected:
|
||||||
|
|
||||||
void addGlow(osg::ref_ptr<osg::Node> node, osg::Vec4f glowColor);
|
void addGlow(osg::ref_ptr<osg::Node> node, osg::Vec4f glowColor);
|
||||||
|
|
||||||
|
/// Set the render bin for this animation's object root. May be customized by subclasses.
|
||||||
|
virtual void setRenderBin();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Animation(const MWWorld::Ptr &ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem);
|
Animation(const MWWorld::Ptr &ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem);
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
#include <osg/UserDataContainer>
|
#include <osg/UserDataContainer>
|
||||||
#include <osg/MatrixTransform>
|
#include <osg/MatrixTransform>
|
||||||
|
#include <osg/Depth>
|
||||||
|
|
||||||
|
#include <osgUtil/RenderBin>
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
|
@ -28,6 +31,7 @@
|
||||||
|
|
||||||
#include "camera.hpp"
|
#include "camera.hpp"
|
||||||
#include "rotatecontroller.hpp"
|
#include "rotatecontroller.hpp"
|
||||||
|
#include "renderbin.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -303,6 +307,50 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
|
||||||
|
|
||||||
mViewMode = viewMode;
|
mViewMode = viewMode;
|
||||||
rebuild();
|
rebuild();
|
||||||
|
|
||||||
|
setRenderBin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief A RenderBin callback to clear the depth buffer before rendering.
|
||||||
|
class DepthClearCallback : public osgUtil::RenderBin::DrawCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DepthClearCallback()
|
||||||
|
{
|
||||||
|
mDepth = new osg::Depth;
|
||||||
|
mDepth->setWriteMask(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void drawImplementation(osgUtil::RenderBin* bin, osg::RenderInfo& renderInfo, osgUtil::RenderLeaf*& previous)
|
||||||
|
{
|
||||||
|
renderInfo.getState()->applyAttribute(mDepth);
|
||||||
|
|
||||||
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
bin->drawImplementation(renderInfo, previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Depth> mDepth;
|
||||||
|
};
|
||||||
|
|
||||||
|
void NpcAnimation::setRenderBin()
|
||||||
|
{
|
||||||
|
if (mViewMode == VM_FirstPerson)
|
||||||
|
{
|
||||||
|
static bool prototypeAdded = false;
|
||||||
|
if (!prototypeAdded)
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osgUtil::RenderBin> depthClearBin (new osgUtil::RenderBin);
|
||||||
|
depthClearBin->setDrawCallback(new DepthClearCallback);
|
||||||
|
osgUtil::RenderBin::addRenderBinPrototype("DepthClear", depthClearBin);
|
||||||
|
prototypeAdded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::StateSet* stateset = mObjectRoot->getOrCreateStateSet();
|
||||||
|
stateset->setRenderBinDetails(RenderBin_FirstPerson, "DepthClear", osg::StateSet::OVERRIDE_RENDERBIN_DETAILS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Animation::setRenderBin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpcAnimation::rebuild()
|
void NpcAnimation::rebuild()
|
||||||
|
|
|
@ -81,6 +81,8 @@ private:
|
||||||
void addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts,
|
void addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts,
|
||||||
bool enchantedGlow=false, osg::Vec4f* glowColor=NULL);
|
bool enchantedGlow=false, osg::Vec4f* glowColor=NULL);
|
||||||
|
|
||||||
|
virtual void setRenderBin();
|
||||||
|
|
||||||
osg::ref_ptr<NeckController> mFirstPersonNeckController;
|
osg::ref_ptr<NeckController> mFirstPersonNeckController;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -5,14 +5,15 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
|
|
||||||
/// Defines the render bin numbers used in the OpenMW scene graph. The bin with the lowest number is rendered first.
|
/// Defines the render bin numbers used in the OpenMW scene graph. The bin with the lowest number is rendered first.
|
||||||
/// Beware of RenderBin nesting, in most cases you will want to use setNestRenderBins(false).
|
|
||||||
enum RenderBins
|
enum RenderBins
|
||||||
{
|
{
|
||||||
RenderBin_Sky = -1,
|
RenderBin_Sky = -1,
|
||||||
RenderBin_Default = 0,
|
RenderBin_Default = 0, // osg::StateSet::OPAQUE_BIN
|
||||||
RenderBin_Water = 9,
|
RenderBin_Water = 9,
|
||||||
RenderBin_OcclusionQuery = 10,
|
RenderBin_DepthSorted = 10, // osg::StateSet::TRANSPARENT_BIN
|
||||||
RenderBin_SunGlare = 11
|
RenderBin_OcclusionQuery = 11,
|
||||||
|
RenderBin_FirstPerson = 12,
|
||||||
|
RenderBin_SunGlare = 13
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -493,6 +493,8 @@ namespace MWRender
|
||||||
texture->setInternalFormat(GL_RGB);
|
texture->setInternalFormat(GL_RGB);
|
||||||
texture->setTextureSize(w, h);
|
texture->setTextureSize(w, h);
|
||||||
texture->setResizeNonPowerOfTwoHint(false);
|
texture->setResizeNonPowerOfTwoHint(false);
|
||||||
|
texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
|
||||||
|
texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
||||||
rttCamera->attach(osg::Camera::COLOR_BUFFER, texture);
|
rttCamera->attach(osg::Camera::COLOR_BUFFER, texture);
|
||||||
|
|
||||||
image->setDataType(GL_UNSIGNED_BYTE);
|
image->setDataType(GL_UNSIGNED_BYTE);
|
||||||
|
|
|
@ -724,22 +724,30 @@ private:
|
||||||
, mTimeOfDayFade(1.f)
|
, mTimeOfDayFade(1.f)
|
||||||
, mGlareView(1.f)
|
, mGlareView(1.f)
|
||||||
{
|
{
|
||||||
|
const MWWorld::Fallback* fallback = MWBase::Environment::get().getWorld()->getFallback();
|
||||||
|
mColor = fallback->getFallbackColour("Weather_Sun_Glare_Fader_Color");
|
||||||
|
mSunGlareFaderMax = fallback->getFallbackFloat("Weather_Sun_Glare_Fader_Max");
|
||||||
|
mSunGlareFaderAngleMax = fallback->getFallbackFloat("Weather_Sun_Glare_Fader_Angle_Max");
|
||||||
|
|
||||||
|
// Replicating a design flaw in MW. The color was being set on both ambient and emissive properties, which multiplies the result by two,
|
||||||
|
// then finally gets clamped by the fixed function pipeline. With the default INI settings, only the red component gets clamped,
|
||||||
|
// so the resulting color looks more orange than red.
|
||||||
|
mColor *= 2;
|
||||||
|
for (int i=0; i<3; ++i)
|
||||||
|
mColor[i] = std::min(1.f, mColor[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void operator ()(osg::Node* node, osg::NodeVisitor* nv)
|
virtual void operator ()(osg::Node* node, osg::NodeVisitor* nv)
|
||||||
{
|
{
|
||||||
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv);
|
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv);
|
||||||
|
|
||||||
float angleRadians = getAngleToSunInRadians(cv->getCurrentCamera());
|
float angleRadians = getAngleToSunInRadians(*cv->getCurrentRenderStage()->getInitialViewMatrix());
|
||||||
float visibleRatio = getVisibleRatio(cv->getCurrentCamera());
|
float visibleRatio = getVisibleRatio(cv->getCurrentCamera());
|
||||||
|
|
||||||
const float angleMaxRadians = osg::DegreesToRadians(30.f); // Sun Glare Fader Angle Max
|
const float angleMaxRadians = osg::DegreesToRadians(mSunGlareFaderAngleMax);
|
||||||
|
|
||||||
float value = 1.f - std::min(1.f, angleRadians / angleMaxRadians);
|
float value = 1.f - std::min(1.f, angleRadians / angleMaxRadians);
|
||||||
|
float fade = value * mSunGlareFaderMax;
|
||||||
const float sunGlareFaderMax = 0.5f;
|
|
||||||
float fade = value * sunGlareFaderMax;
|
|
||||||
|
|
||||||
fade *= mTimeOfDayFade * mGlareView * visibleRatio;
|
fade *= mTimeOfDayFade * mGlareView * visibleRatio;
|
||||||
|
|
||||||
|
@ -754,17 +762,8 @@ private:
|
||||||
|
|
||||||
osg::ref_ptr<osg::Material> mat (createUnlitMaterial());
|
osg::ref_ptr<osg::Material> mat (createUnlitMaterial());
|
||||||
|
|
||||||
osg::Vec4f sunGlareFaderColor (222/255.f, 95/255.f, 39/255.f, 1);
|
|
||||||
|
|
||||||
// Replicating a design flaw in MW. The color was being set on both ambient and emissive properties, which multiplies the result by two,
|
|
||||||
// then finally gets clamped by the fixed function pipeline. With the default INI settings, only the red component gets clamped,
|
|
||||||
// so the resulting color looks more orange than red.
|
|
||||||
sunGlareFaderColor *= 2;
|
|
||||||
for (int i=0; i<3; ++i)
|
|
||||||
sunGlareFaderColor[i] = std::min(1.f, sunGlareFaderColor[i]);
|
|
||||||
|
|
||||||
mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,fade));
|
mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,fade));
|
||||||
mat->setEmission(osg::Material::FRONT_AND_BACK, sunGlareFaderColor);
|
mat->setEmission(osg::Material::FRONT_AND_BACK, mColor);
|
||||||
|
|
||||||
stateset->setAttributeAndModes(mat, osg::StateAttribute::ON);
|
stateset->setAttributeAndModes(mat, osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
@ -785,10 +784,10 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float getAngleToSunInRadians(osg::Camera* camera) const
|
float getAngleToSunInRadians(const osg::Matrix& viewMatrix) const
|
||||||
{
|
{
|
||||||
osg::Vec3d eye, center, up;
|
osg::Vec3d eye, center, up;
|
||||||
camera->getViewMatrixAsLookAt(eye, center, up);
|
viewMatrix.getLookAt(eye, center, up);
|
||||||
|
|
||||||
osg::Vec3d forward = center - eye;
|
osg::Vec3d forward = center - eye;
|
||||||
osg::Vec3d sun = mSunTransform->getPosition();
|
osg::Vec3d sun = mSunTransform->getPosition();
|
||||||
|
@ -802,6 +801,9 @@ private:
|
||||||
osg::ref_ptr<osg::PositionAttitudeTransform> mSunTransform;
|
osg::ref_ptr<osg::PositionAttitudeTransform> mSunTransform;
|
||||||
float mTimeOfDayFade;
|
float mTimeOfDayFade;
|
||||||
float mGlareView;
|
float mGlareView;
|
||||||
|
osg::Vec4f mColor;
|
||||||
|
float mSunGlareFaderMax;
|
||||||
|
float mSunGlareFaderAngleMax;
|
||||||
};
|
};
|
||||||
|
|
||||||
osg::ref_ptr<Updater> mUpdater;
|
osg::ref_ptr<Updater> mUpdater;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/manualref.hpp"
|
||||||
|
|
||||||
namespace MWScript
|
namespace MWScript
|
||||||
{
|
{
|
||||||
|
@ -42,9 +43,9 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false);
|
MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id);
|
||||||
|
|
||||||
script = ptr.getClass().getScript (ptr);
|
script = ref.getPtr().getClass().getScript (ref.getPtr());
|
||||||
reference = true;
|
reference = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +83,8 @@ namespace MWScript
|
||||||
store.get<ESM::Probe>().search (name) ||
|
store.get<ESM::Probe>().search (name) ||
|
||||||
store.get<ESM::Repair>().search (name) ||
|
store.get<ESM::Repair>().search (name) ||
|
||||||
store.get<ESM::Static>().search (name) ||
|
store.get<ESM::Static>().search (name) ||
|
||||||
store.get<ESM::Weapon>().search (name);
|
store.get<ESM::Weapon>().search (name) ||
|
||||||
|
store.get<ESM::Script>().search (name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompilerContext::isJournalId (const std::string& name) const
|
bool CompilerContext::isJournalId (const std::string& name) const
|
||||||
|
|
|
@ -140,7 +140,11 @@ void MWWorld::ContainerStore::unstack(const Ptr &ptr, const Ptr& container)
|
||||||
{
|
{
|
||||||
if (ptr.getRefData().getCount() <= 1)
|
if (ptr.getRefData().getCount() <= 1)
|
||||||
return;
|
return;
|
||||||
addNewStack(ptr, ptr.getRefData().getCount()-1);
|
MWWorld::ContainerStoreIterator it = addNewStack(ptr, ptr.getRefData().getCount()-1);
|
||||||
|
const std::string script = it->getClass().getScript(*it);
|
||||||
|
if (!script.empty())
|
||||||
|
MWBase::Environment::get().getWorld()->getLocalScripts().add(script, *it);
|
||||||
|
|
||||||
remove(ptr, ptr.getRefData().getCount()-1, container);
|
remove(ptr, ptr.getRefData().getCount()-1, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,6 +415,7 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::
|
||||||
void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner,
|
void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner,
|
||||||
int count, bool topLevel, const std::string& levItem)
|
int count, bool topLevel, const std::string& levItem)
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count);
|
ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count);
|
||||||
|
|
||||||
if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name())
|
if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name())
|
||||||
|
@ -446,6 +451,12 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
|
||||||
ref.getPtr().getCellRef().setOwner(owner);
|
ref.getPtr().getCellRef().setOwner(owner);
|
||||||
addImp (ref.getPtr(), count);
|
addImp (ref.getPtr(), count);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "Error in MWWorld::ContainerStore::addInitialItem: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner)
|
void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner)
|
||||||
|
|
|
@ -645,8 +645,15 @@ void MWWorld::InventoryStore::updateRechargingItems()
|
||||||
{
|
{
|
||||||
if (it->getClass().getEnchantment(*it) != "")
|
if (it->getClass().getEnchantment(*it) != "")
|
||||||
{
|
{
|
||||||
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(
|
std::string enchantmentId = it->getClass().getEnchantment(*it);
|
||||||
it->getClass().getEnchantment(*it));
|
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(
|
||||||
|
enchantmentId);
|
||||||
|
if (!enchantment)
|
||||||
|
{
|
||||||
|
std::cerr << "Can't find enchantment '" << enchantmentId << "' on item " << it->getCellRef().getRefId() << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (enchantment->mData.mType == ESM::Enchantment::WhenUsed
|
if (enchantment->mData.mType == ESM::Enchantment::WhenUsed
|
||||||
|| enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
|| enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
||||||
mRechargingItems.push_back(std::make_pair(it, static_cast<float>(enchantment->mData.mCharge)));
|
mRechargingItems.push_back(std::make_pair(it, static_cast<float>(enchantment->mData.mCharge)));
|
||||||
|
|
|
@ -1029,7 +1029,8 @@ namespace MWWorld
|
||||||
// Script
|
// Script
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
||||||
inline void Store<ESM::Script>::load(ESM::ESMReader &esm, const std::string &id) {
|
template <>
|
||||||
|
void Store<ESM::Script>::load(ESM::ESMReader &esm, const std::string &id) {
|
||||||
ESM::Script scpt;
|
ESM::Script scpt;
|
||||||
scpt.load(esm);
|
scpt.load(esm);
|
||||||
Misc::StringUtils::toLower(scpt.mId);
|
Misc::StringUtils::toLower(scpt.mId);
|
||||||
|
@ -1045,7 +1046,8 @@ namespace MWWorld
|
||||||
// StartScript
|
// StartScript
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
||||||
inline void Store<ESM::StartScript>::load(ESM::ESMReader &esm, const std::string &id)
|
template <>
|
||||||
|
void Store<ESM::StartScript>::load(ESM::ESMReader &esm, const std::string &id)
|
||||||
{
|
{
|
||||||
ESM::StartScript s;
|
ESM::StartScript s;
|
||||||
s.load(esm);
|
s.load(esm);
|
||||||
|
|
|
@ -204,6 +204,10 @@ namespace MWWorld
|
||||||
mLevitationEnabled = true;
|
mLevitationEnabled = true;
|
||||||
mTeleportEnabled = true;
|
mTeleportEnabled = true;
|
||||||
|
|
||||||
|
mGodMode = false;
|
||||||
|
mScriptsEnabled = true;
|
||||||
|
mSky = true;
|
||||||
|
|
||||||
// Rebuild player
|
// Rebuild player
|
||||||
setupPlayer();
|
setupPlayer();
|
||||||
|
|
||||||
|
@ -297,9 +301,6 @@ namespace MWWorld
|
||||||
|
|
||||||
mDoorStates.clear();
|
mDoorStates.clear();
|
||||||
|
|
||||||
mGodMode = false;
|
|
||||||
mScriptsEnabled = true;
|
|
||||||
mSky = true;
|
|
||||||
mTeleportEnabled = true;
|
mTeleportEnabled = true;
|
||||||
mLevitationEnabled = true;
|
mLevitationEnabled = true;
|
||||||
|
|
||||||
|
@ -2659,10 +2660,6 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
const ESM::Spell* spell = getStore().get<ESM::Spell>().find(selectedSpell);
|
const ESM::Spell* spell = getStore().get<ESM::Spell>().find(selectedSpell);
|
||||||
|
|
||||||
// A power can be used once per 24h
|
|
||||||
if (spell->mData.mType == ESM::Spell::ST_Power)
|
|
||||||
stats.getSpells().usePower(spell->mId);
|
|
||||||
|
|
||||||
cast.cast(spell);
|
cast.cast(spell);
|
||||||
}
|
}
|
||||||
else if (actor.getClass().hasInventoryStore(actor))
|
else if (actor.getClass().hasInventoryStore(actor))
|
||||||
|
|
|
@ -652,6 +652,13 @@ namespace Compiler
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (code ==Scanner::S_plus && mNextOperand)
|
||||||
|
{
|
||||||
|
// Also unary, but +, just ignore it
|
||||||
|
mTokenLoc = loc;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (code==Scanner::S_open)
|
if (code==Scanner::S_open)
|
||||||
{
|
{
|
||||||
if (mNextOperand)
|
if (mNextOperand)
|
||||||
|
|
|
@ -179,7 +179,7 @@ namespace Compiler
|
||||||
extensions.registerInstruction ("setjournalindex", "cl", opcodeSetJournalIndex);
|
extensions.registerInstruction ("setjournalindex", "cl", opcodeSetJournalIndex);
|
||||||
extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex);
|
extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex);
|
||||||
extensions.registerInstruction ("addtopic", "S" , opcodeAddTopic);
|
extensions.registerInstruction ("addtopic", "S" , opcodeAddTopic);
|
||||||
extensions.registerInstruction ("choice", "j/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice);
|
extensions.registerInstruction ("choice", "j/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice);
|
||||||
extensions.registerInstruction("forcegreeting","",opcodeForceGreeting,
|
extensions.registerInstruction("forcegreeting","",opcodeForceGreeting,
|
||||||
opcodeForceGreetingExplicit);
|
opcodeForceGreetingExplicit);
|
||||||
extensions.registerInstruction("goodbye", "", opcodeGoodbye);
|
extensions.registerInstruction("goodbye", "", opcodeGoodbye);
|
||||||
|
|
|
@ -555,7 +555,7 @@ namespace Compiler
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mAllowExpression && mState==BeginState &&
|
if (mAllowExpression && mState==BeginState &&
|
||||||
(code==Scanner::S_open || code==Scanner::S_minus))
|
(code==Scanner::S_open || code==Scanner::S_minus || code==Scanner::S_plus))
|
||||||
{
|
{
|
||||||
scanner.putbackSpecial (code, loc);
|
scanner.putbackSpecial (code, loc);
|
||||||
parseExpression (scanner, loc);
|
parseExpression (scanner, loc);
|
||||||
|
|
|
@ -175,7 +175,7 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
value += c;
|
value += c;
|
||||||
}
|
}
|
||||||
else if (isStringCharacter (c))
|
else if (c!='-' && isStringCharacter (c))
|
||||||
{
|
{
|
||||||
error = true;
|
error = true;
|
||||||
value += c;
|
value += c;
|
||||||
|
|
|
@ -132,7 +132,34 @@ namespace Interpreter
|
||||||
throw std::runtime_error (error.str());
|
throw std::runtime_error (error.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
Interpreter::Interpreter()
|
void Interpreter::begin()
|
||||||
|
{
|
||||||
|
if (mRunning)
|
||||||
|
{
|
||||||
|
mCallstack.push (mRuntime);
|
||||||
|
mRuntime.clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mRunning = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::end()
|
||||||
|
{
|
||||||
|
if (mCallstack.empty())
|
||||||
|
{
|
||||||
|
mRuntime.clear();
|
||||||
|
mRunning = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mRuntime = mCallstack.top();
|
||||||
|
mCallstack.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Interpreter::Interpreter() : mRunning (false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Interpreter::~Interpreter()
|
Interpreter::~Interpreter()
|
||||||
|
@ -202,6 +229,10 @@ namespace Interpreter
|
||||||
{
|
{
|
||||||
assert (codeSize>=4);
|
assert (codeSize>=4);
|
||||||
|
|
||||||
|
begin();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
mRuntime.configure (code, codeSize, context);
|
mRuntime.configure (code, codeSize, context);
|
||||||
|
|
||||||
int opcodes = static_cast<int> (code[0]);
|
int opcodes = static_cast<int> (code[0]);
|
||||||
|
@ -214,7 +245,13 @@ namespace Interpreter
|
||||||
mRuntime.setPC (mRuntime.getPC()+1);
|
mRuntime.setPC (mRuntime.getPC()+1);
|
||||||
execute (code);
|
execute (code);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
end();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
mRuntime.clear();
|
end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define INTERPRETER_INTERPRETER_H_INCLUDED
|
#define INTERPRETER_INTERPRETER_H_INCLUDED
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
#include "runtime.hpp"
|
#include "runtime.hpp"
|
||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
|
@ -14,6 +15,8 @@ namespace Interpreter
|
||||||
|
|
||||||
class Interpreter
|
class Interpreter
|
||||||
{
|
{
|
||||||
|
std::stack<Runtime> mCallstack;
|
||||||
|
bool mRunning;
|
||||||
Runtime mRuntime;
|
Runtime mRuntime;
|
||||||
std::map<int, Opcode1 *> mSegment0;
|
std::map<int, Opcode1 *> mSegment0;
|
||||||
std::map<int, Opcode2 *> mSegment1;
|
std::map<int, Opcode2 *> mSegment1;
|
||||||
|
@ -32,6 +35,10 @@ namespace Interpreter
|
||||||
|
|
||||||
void abortUnknownSegment (Type_Code code);
|
void abortUnknownSegment (Type_Code code);
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
|
||||||
|
void end();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Interpreter();
|
Interpreter();
|
||||||
|
|
|
@ -57,8 +57,8 @@ namespace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect all properties affecting the given node that should be applied to an osg::Material.
|
// Collect all properties affecting the given drawable that should be handled on drawable basis rather than on the node hierarchy above it.
|
||||||
void collectMaterialProperties(const Nif::Node* nifNode, std::vector<const Nif::Property*>& out)
|
void collectDrawableProperties(const Nif::Node* nifNode, std::vector<const Nif::Property*>& out)
|
||||||
{
|
{
|
||||||
const Nif::PropertyList& props = nifNode->props;
|
const Nif::PropertyList& props = nifNode->props;
|
||||||
for (size_t i = 0; i <props.length();++i)
|
for (size_t i = 0; i <props.length();++i)
|
||||||
|
@ -70,6 +70,7 @@ namespace
|
||||||
case Nif::RC_NiMaterialProperty:
|
case Nif::RC_NiMaterialProperty:
|
||||||
case Nif::RC_NiVertexColorProperty:
|
case Nif::RC_NiVertexColorProperty:
|
||||||
case Nif::RC_NiSpecularProperty:
|
case Nif::RC_NiSpecularProperty:
|
||||||
|
case Nif::RC_NiAlphaProperty:
|
||||||
out.push_back(props[i].getPtr());
|
out.push_back(props[i].getPtr());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -78,7 +79,7 @@ namespace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nifNode->parent)
|
if (nifNode->parent)
|
||||||
collectMaterialProperties(nifNode->parent, out);
|
collectDrawableProperties(nifNode->parent, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
class FrameSwitch : public osg::Group
|
class FrameSwitch : public osg::Group
|
||||||
|
@ -113,6 +114,7 @@ namespace
|
||||||
|
|
||||||
// NodeCallback used to have a transform always oriented towards the camera. Can have translation and scale
|
// NodeCallback used to have a transform always oriented towards the camera. Can have translation and scale
|
||||||
// set just like a regular MatrixTransform, but the rotation set will be overridden in order to face the camera.
|
// set just like a regular MatrixTransform, but the rotation set will be overridden in order to face the camera.
|
||||||
|
// Must be set as a cull callback.
|
||||||
class BillboardCallback : public osg::NodeCallback
|
class BillboardCallback : public osg::NodeCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -160,24 +162,34 @@ namespace
|
||||||
struct UpdateMorphGeometry : public osg::Drawable::CullCallback
|
struct UpdateMorphGeometry : public osg::Drawable::CullCallback
|
||||||
{
|
{
|
||||||
UpdateMorphGeometry()
|
UpdateMorphGeometry()
|
||||||
|
: mLastFrameNumber(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateMorphGeometry(const UpdateMorphGeometry& copy, const osg::CopyOp& copyop)
|
UpdateMorphGeometry(const UpdateMorphGeometry& copy, const osg::CopyOp& copyop)
|
||||||
: osg::Drawable::CullCallback(copy, copyop)
|
: osg::Drawable::CullCallback(copy, copyop)
|
||||||
|
, mLastFrameNumber(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
META_Object(NifOsg, UpdateMorphGeometry)
|
META_Object(NifOsg, UpdateMorphGeometry)
|
||||||
|
|
||||||
virtual bool cull(osg::NodeVisitor *, osg::Drawable * drw, osg::State *) const
|
virtual bool cull(osg::NodeVisitor* nv, osg::Drawable * drw, osg::State *) const
|
||||||
{
|
{
|
||||||
osgAnimation::MorphGeometry* geom = static_cast<osgAnimation::MorphGeometry*>(drw);
|
osgAnimation::MorphGeometry* geom = static_cast<osgAnimation::MorphGeometry*>(drw);
|
||||||
if (!geom)
|
if (!geom)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (mLastFrameNumber == nv->getFrameStamp()->getFrameNumber())
|
||||||
|
return false;
|
||||||
|
mLastFrameNumber = nv->getFrameStamp()->getFrameNumber();
|
||||||
|
|
||||||
geom->transformSoftwareMethod();
|
geom->transformSoftwareMethod();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable unsigned int mLastFrameNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Callback to return a static bounding box for a MorphGeometry. The idea is to not recalculate the bounding box
|
// Callback to return a static bounding box for a MorphGeometry. The idea is to not recalculate the bounding box
|
||||||
|
@ -861,9 +873,9 @@ namespace NifOsg
|
||||||
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
|
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
|
||||||
geode->addDrawable(partsys);
|
geode->addDrawable(partsys);
|
||||||
|
|
||||||
std::vector<const Nif::Property*> materialProps;
|
std::vector<const Nif::Property*> drawableProps;
|
||||||
collectMaterialProperties(nifNode, materialProps);
|
collectDrawableProperties(nifNode, drawableProps);
|
||||||
applyMaterialProperties(parentNode, materialProps, composite, true, animflags);
|
applyDrawableProperties(parentNode, drawableProps, composite, true, animflags);
|
||||||
|
|
||||||
// Particles don't have normals, so can't be diffuse lit.
|
// Particles don't have normals, so can't be diffuse lit.
|
||||||
osg::Material* mat = static_cast<osg::Material*>(parentNode->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL));
|
osg::Material* mat = static_cast<osg::Material*>(parentNode->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL));
|
||||||
|
@ -923,9 +935,9 @@ namespace NifOsg
|
||||||
// - if there are no vertex colors, we need to disable colorMode.
|
// - if there are no vertex colors, we need to disable colorMode.
|
||||||
// - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them
|
// - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them
|
||||||
// above the actual renderable would be tedious.
|
// above the actual renderable would be tedious.
|
||||||
std::vector<const Nif::Property*> materialProps;
|
std::vector<const Nif::Property*> drawableProps;
|
||||||
collectMaterialProperties(triShape, materialProps);
|
collectDrawableProperties(triShape, drawableProps);
|
||||||
applyMaterialProperties(parentNode, materialProps, composite, !data->colors->empty(), animflags);
|
applyDrawableProperties(parentNode, drawableProps, composite, !data->colors->empty(), animflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
|
void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
|
||||||
|
@ -1212,42 +1224,12 @@ namespace NifOsg
|
||||||
case Nif::RC_NiVertexColorProperty:
|
case Nif::RC_NiVertexColorProperty:
|
||||||
case Nif::RC_NiSpecularProperty:
|
case Nif::RC_NiSpecularProperty:
|
||||||
{
|
{
|
||||||
// Handled in handleTriShape so we know whether vertex colors are available
|
// Handled on drawable level so we know whether vertex colors are available
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Nif::RC_NiAlphaProperty:
|
case Nif::RC_NiAlphaProperty:
|
||||||
{
|
{
|
||||||
const Nif::NiAlphaProperty* alphaprop = static_cast<const Nif::NiAlphaProperty*>(property);
|
// Handled on drawable level to prevent RenderBin nesting issues
|
||||||
osg::BlendFunc* blendfunc = new osg::BlendFunc;
|
|
||||||
osg::StateSet* stateset = node->getOrCreateStateSet();
|
|
||||||
if (alphaprop->flags&1)
|
|
||||||
{
|
|
||||||
blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf),
|
|
||||||
getBlendMode((alphaprop->flags>>5)&0xf));
|
|
||||||
stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON);
|
|
||||||
|
|
||||||
bool noSort = (alphaprop->flags>>13)&1;
|
|
||||||
if (!noSort)
|
|
||||||
{
|
|
||||||
stateset->setNestRenderBins(false);
|
|
||||||
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::OFF);
|
|
||||||
stateset->setNestRenderBins(false);
|
|
||||||
stateset->setRenderingHint(osg::StateSet::OPAQUE_BIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::AlphaFunc* alphafunc = new osg::AlphaFunc;
|
|
||||||
if((alphaprop->flags>>9)&1)
|
|
||||||
{
|
|
||||||
alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f);
|
|
||||||
stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::OFF);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Nif::RC_NiTexturingProperty:
|
case Nif::RC_NiTexturingProperty:
|
||||||
|
@ -1377,7 +1359,7 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyMaterialProperties(osg::Node* node, const std::vector<const Nif::Property*>& properties, SceneUtil::CompositeStateSetUpdater* composite,
|
void applyDrawableProperties(osg::Node* node, const std::vector<const Nif::Property*>& properties, SceneUtil::CompositeStateSetUpdater* composite,
|
||||||
bool hasVertexColors, int animflags)
|
bool hasVertexColors, int animflags)
|
||||||
{
|
{
|
||||||
osg::StateSet* stateset = node->getOrCreateStateSet();
|
osg::StateSet* stateset = node->getOrCreateStateSet();
|
||||||
|
@ -1433,6 +1415,43 @@ namespace NifOsg
|
||||||
mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Nif::RC_NiAlphaProperty:
|
||||||
|
{
|
||||||
|
const Nif::NiAlphaProperty* alphaprop = static_cast<const Nif::NiAlphaProperty*>(property);
|
||||||
|
osg::BlendFunc* blendfunc = new osg::BlendFunc;
|
||||||
|
if (alphaprop->flags&1)
|
||||||
|
{
|
||||||
|
blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf),
|
||||||
|
getBlendMode((alphaprop->flags>>5)&0xf));
|
||||||
|
stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
bool noSort = (alphaprop->flags>>13)&1;
|
||||||
|
if (!noSort)
|
||||||
|
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||||
|
else
|
||||||
|
stateset->setRenderBinToInherit();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stateset->removeAttribute(osg::StateAttribute::BLENDFUNC);
|
||||||
|
stateset->removeMode(GL_BLEND);
|
||||||
|
stateset->setRenderBinToInherit();
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::AlphaFunc* alphafunc = new osg::AlphaFunc;
|
||||||
|
if((alphaprop->flags>>9)&1)
|
||||||
|
{
|
||||||
|
alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f);
|
||||||
|
stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stateset->removeAttribute(osg::StateAttribute::ALPHAFUNC);
|
||||||
|
stateset->removeMode(GL_ALPHA_TEST);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,16 @@ namespace SceneUtil
|
||||||
std::vector<osg::ref_ptr<osg::Light> > mLights;
|
std::vector<osg::ref_ptr<osg::Light> > mLights;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LightManager* findLightManager(const osg::NodePath& path)
|
||||||
|
{
|
||||||
|
for (unsigned int i=0;i<path.size(); ++i)
|
||||||
|
{
|
||||||
|
if (LightManager* lightManager = dynamic_cast<LightManager*>(path[i]))
|
||||||
|
return lightManager;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Set on a LightSource. Adds the light source to its light manager for the current frame.
|
// Set on a LightSource. Adds the light source to its light manager for the current frame.
|
||||||
// This allows us to keep track of the current lights in the scene graph without tying creation & destruction to the manager.
|
// This allows us to keep track of the current lights in the scene graph without tying creation & destruction to the manager.
|
||||||
class CollectLightCallback : public osg::NodeCallback
|
class CollectLightCallback : public osg::NodeCallback
|
||||||
|
@ -82,14 +92,8 @@ namespace SceneUtil
|
||||||
{
|
{
|
||||||
if (!mLightManager)
|
if (!mLightManager)
|
||||||
{
|
{
|
||||||
for (unsigned int i=0;i<nv->getNodePath().size(); ++i)
|
mLightManager = findLightManager(nv->getNodePath());
|
||||||
{
|
|
||||||
if (LightManager* lightManager = dynamic_cast<LightManager*>(nv->getNodePath()[i]))
|
|
||||||
{
|
|
||||||
mLightManager = lightManager;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!mLightManager)
|
if (!mLightManager)
|
||||||
throw std::runtime_error("can't find parent LightManager");
|
throw std::runtime_error("can't find parent LightManager");
|
||||||
}
|
}
|
||||||
|
@ -126,15 +130,13 @@ namespace SceneUtil
|
||||||
};
|
};
|
||||||
|
|
||||||
LightManager::LightManager()
|
LightManager::LightManager()
|
||||||
: mLightsInViewSpace(false)
|
: mStartLight(0)
|
||||||
, mStartLight(0)
|
|
||||||
{
|
{
|
||||||
setUpdateCallback(new LightManagerUpdateCallback);
|
setUpdateCallback(new LightManagerUpdateCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op)
|
LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op)
|
||||||
: osg::Group(copy, copyop)
|
: osg::Group(copy, copyop)
|
||||||
, mLightsInViewSpace(false)
|
|
||||||
, mStartLight(copy.mStartLight)
|
, mStartLight(copy.mStartLight)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -142,8 +144,8 @@ namespace SceneUtil
|
||||||
|
|
||||||
void LightManager::update()
|
void LightManager::update()
|
||||||
{
|
{
|
||||||
mLightsInViewSpace = false;
|
|
||||||
mLights.clear();
|
mLights.clear();
|
||||||
|
mLightsInViewSpace.clear();
|
||||||
|
|
||||||
// do an occasional cleanup for orphaned lights
|
// do an occasional cleanup for orphaned lights
|
||||||
if (mStateSetCache.size() > 5000)
|
if (mStateSetCache.size() > 5000)
|
||||||
|
@ -161,22 +163,6 @@ namespace SceneUtil
|
||||||
mLights.push_back(l);
|
mLights.push_back(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightManager::prepareForCamera(osg::Camera *cam)
|
|
||||||
{
|
|
||||||
// later on we need to store this per camera
|
|
||||||
if (!mLightsInViewSpace)
|
|
||||||
{
|
|
||||||
for (std::vector<LightSourceTransform>::iterator it = mLights.begin(); it != mLights.end(); ++it)
|
|
||||||
{
|
|
||||||
LightSourceTransform& l = *it;
|
|
||||||
osg::Matrix worldViewMat = l.mWorldMatrix * cam->getViewMatrix();
|
|
||||||
l.mViewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), l.mLightSource->getRadius());
|
|
||||||
transformBoundingSphere(worldViewMat, l.mViewBound);
|
|
||||||
}
|
|
||||||
mLightsInViewSpace = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::StateSet> LightManager::getLightListStateSet(const LightList &lightList)
|
osg::ref_ptr<osg::StateSet> LightManager::getLightListStateSet(const LightList &lightList)
|
||||||
{
|
{
|
||||||
// possible optimization: return a StateSet containing all requested lights plus some extra lights (if a suitable one exists)
|
// possible optimization: return a StateSet containing all requested lights plus some extra lights (if a suitable one exists)
|
||||||
|
@ -212,6 +198,30 @@ namespace SceneUtil
|
||||||
return mLights;
|
return mLights;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<LightManager::LightSourceViewBound>& LightManager::getLightsInViewSpace(osg::Camera *camera, const osg::RefMatrix* viewMatrix)
|
||||||
|
{
|
||||||
|
osg::observer_ptr<osg::Camera> camPtr (camera);
|
||||||
|
std::map<osg::observer_ptr<osg::Camera>, LightSourceViewBoundCollection>::iterator it = mLightsInViewSpace.find(camPtr);
|
||||||
|
|
||||||
|
if (it == mLightsInViewSpace.end())
|
||||||
|
{
|
||||||
|
it = mLightsInViewSpace.insert(std::make_pair(camPtr, LightSourceViewBoundCollection())).first;
|
||||||
|
|
||||||
|
for (std::vector<LightSourceTransform>::iterator lightIt = mLights.begin(); lightIt != mLights.end(); ++lightIt)
|
||||||
|
{
|
||||||
|
osg::Matrix worldViewMat = lightIt->mWorldMatrix * (*viewMatrix);
|
||||||
|
osg::BoundingSphere viewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), lightIt->mLightSource->getRadius());
|
||||||
|
transformBoundingSphere(worldViewMat, viewBound);
|
||||||
|
|
||||||
|
LightSourceViewBound l;
|
||||||
|
l.mLightSource = lightIt->mLightSource;
|
||||||
|
l.mViewBound = viewBound;
|
||||||
|
it->second.push_back(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
void LightManager::setStartLight(int start)
|
void LightManager::setStartLight(int start)
|
||||||
{
|
{
|
||||||
mStartLight = start;
|
mStartLight = start;
|
||||||
|
@ -241,7 +251,7 @@ namespace SceneUtil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool sortLights (const LightManager::LightSourceTransform* left, const LightManager::LightSourceTransform* right)
|
bool sortLights (const LightManager::LightSourceViewBound* left, const LightManager::LightSourceViewBound* right)
|
||||||
{
|
{
|
||||||
return left->mViewBound.center().length2() - left->mViewBound.radius2()/4.f < right->mViewBound.center().length2() - right->mViewBound.radius2()/4.f;
|
return left->mViewBound.center().length2() - left->mViewBound.radius2()/4.f < right->mViewBound.center().length2() - right->mViewBound.radius2()/4.f;
|
||||||
}
|
}
|
||||||
|
@ -258,14 +268,7 @@ namespace SceneUtil
|
||||||
|
|
||||||
if (!mLightManager)
|
if (!mLightManager)
|
||||||
{
|
{
|
||||||
for (unsigned int i=0;i<nv->getNodePath().size(); ++i)
|
mLightManager = findLightManager(nv->getNodePath());
|
||||||
{
|
|
||||||
if (LightManager* lightManager = dynamic_cast<LightManager*>(nv->getNodePath()[i]))
|
|
||||||
{
|
|
||||||
mLightManager = lightManager;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!mLightManager)
|
if (!mLightManager)
|
||||||
{
|
{
|
||||||
traverse(node, nv);
|
traverse(node, nv);
|
||||||
|
@ -273,13 +276,14 @@ namespace SceneUtil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mLightManager->prepareForCamera(cv->getCurrentCamera());
|
|
||||||
|
|
||||||
// Possible optimizations:
|
// Possible optimizations:
|
||||||
// - cull list of lights by the camera frustum
|
// - cull list of lights by the camera frustum
|
||||||
// - organize lights in a quad tree
|
// - organize lights in a quad tree
|
||||||
|
|
||||||
const std::vector<LightManager::LightSourceTransform>& lights = mLightManager->getLights();
|
// Don't use Camera::getViewMatrix, that one might be relative to another camera!
|
||||||
|
const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix();
|
||||||
|
|
||||||
|
const std::vector<LightManager::LightSourceViewBound>& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix);
|
||||||
|
|
||||||
if (lights.size())
|
if (lights.size())
|
||||||
{
|
{
|
||||||
|
@ -288,10 +292,10 @@ namespace SceneUtil
|
||||||
osg::Matrixf mat = *cv->getModelViewMatrix();
|
osg::Matrixf mat = *cv->getModelViewMatrix();
|
||||||
transformBoundingSphere(mat, nodeBound);
|
transformBoundingSphere(mat, nodeBound);
|
||||||
|
|
||||||
std::vector<const LightManager::LightSourceTransform*> lightList;
|
LightManager::LightList lightList;
|
||||||
for (unsigned int i=0; i<lights.size(); ++i)
|
for (unsigned int i=0; i<lights.size(); ++i)
|
||||||
{
|
{
|
||||||
const LightManager::LightSourceTransform& l = lights[i];
|
const LightManager::LightSourceViewBound& l = lights[i];
|
||||||
if (l.mViewBound.intersects(nodeBound))
|
if (l.mViewBound.intersects(nodeBound))
|
||||||
lightList.push_back(&l);
|
lightList.push_back(&l);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,18 +74,23 @@ namespace SceneUtil
|
||||||
// Called automatically by the LightSource's UpdateCallback
|
// Called automatically by the LightSource's UpdateCallback
|
||||||
void addLight(LightSource* lightSource, osg::Matrix worldMat);
|
void addLight(LightSource* lightSource, osg::Matrix worldMat);
|
||||||
|
|
||||||
void prepareForCamera(osg::Camera* cam);
|
|
||||||
|
|
||||||
struct LightSourceTransform
|
struct LightSourceTransform
|
||||||
{
|
{
|
||||||
LightSource* mLightSource;
|
LightSource* mLightSource;
|
||||||
osg::Matrix mWorldMatrix;
|
osg::Matrix mWorldMatrix;
|
||||||
osg::BoundingSphere mViewBound;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::vector<LightSourceTransform>& getLights() const;
|
const std::vector<LightSourceTransform>& getLights() const;
|
||||||
|
|
||||||
typedef std::vector<const LightSourceTransform*> LightList;
|
struct LightSourceViewBound
|
||||||
|
{
|
||||||
|
LightSource* mLightSource;
|
||||||
|
osg::BoundingSphere mViewBound;
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::vector<LightSourceViewBound>& getLightsInViewSpace(osg::Camera* camera, const osg::RefMatrix* viewMatrix);
|
||||||
|
|
||||||
|
typedef std::vector<const LightSourceViewBound*> LightList;
|
||||||
|
|
||||||
osg::ref_ptr<osg::StateSet> getLightListStateSet(const LightList& lightList);
|
osg::ref_ptr<osg::StateSet> getLightListStateSet(const LightList& lightList);
|
||||||
|
|
||||||
|
@ -98,7 +103,8 @@ namespace SceneUtil
|
||||||
// Lights collected from the scene graph. Only valid during the cull traversal.
|
// Lights collected from the scene graph. Only valid during the cull traversal.
|
||||||
std::vector<LightSourceTransform> mLights;
|
std::vector<LightSourceTransform> mLights;
|
||||||
|
|
||||||
bool mLightsInViewSpace;
|
typedef std::vector<LightSourceViewBound> LightSourceViewBoundCollection;
|
||||||
|
std::map<osg::observer_ptr<osg::Camera>, LightSourceViewBoundCollection> mLightsInViewSpace;
|
||||||
|
|
||||||
// < Light list hash , StateSet >
|
// < Light list hash , StateSet >
|
||||||
typedef std::map<size_t, osg::ref_ptr<osg::StateSet> > LightStateSetMap;
|
typedef std::map<size_t, osg::ref_ptr<osg::StateSet> > LightStateSetMap;
|
||||||
|
|
|
@ -60,7 +60,7 @@ public:
|
||||||
|
|
||||||
RigGeometry::RigGeometry()
|
RigGeometry::RigGeometry()
|
||||||
: mSkeleton(NULL)
|
: mSkeleton(NULL)
|
||||||
, mFirstFrame(true)
|
, mLastFrameNumber(0)
|
||||||
, mBoundsFirstFrame(true)
|
, mBoundsFirstFrame(true)
|
||||||
{
|
{
|
||||||
setCullCallback(new UpdateRigGeometry);
|
setCullCallback(new UpdateRigGeometry);
|
||||||
|
@ -72,7 +72,7 @@ RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op)
|
||||||
: osg::Geometry(copy, copyop)
|
: osg::Geometry(copy, copyop)
|
||||||
, mSkeleton(NULL)
|
, mSkeleton(NULL)
|
||||||
, mInfluenceMap(copy.mInfluenceMap)
|
, mInfluenceMap(copy.mInfluenceMap)
|
||||||
, mFirstFrame(copy.mFirstFrame)
|
, mLastFrameNumber(0)
|
||||||
, mBoundsFirstFrame(copy.mBoundsFirstFrame)
|
, mBoundsFirstFrame(copy.mBoundsFirstFrame)
|
||||||
{
|
{
|
||||||
setSourceGeometry(copy.mSourceGeometry);
|
setSourceGeometry(copy.mSourceGeometry);
|
||||||
|
@ -206,9 +206,12 @@ void RigGeometry::update(osg::NodeVisitor* nv)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mSkeleton->getActive() && !mFirstFrame)
|
if (!mSkeleton->getActive() && mLastFrameNumber != 0)
|
||||||
return;
|
return;
|
||||||
mFirstFrame = false;
|
|
||||||
|
if (mLastFrameNumber == nv->getFrameStamp()->getFrameNumber())
|
||||||
|
return;
|
||||||
|
mLastFrameNumber = nv->getFrameStamp()->getFrameNumber();
|
||||||
|
|
||||||
mSkeleton->updateBoneMatrices(nv);
|
mSkeleton->updateBoneMatrices(nv);
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ namespace SceneUtil
|
||||||
|
|
||||||
BoneSphereMap mBoneSphereMap;
|
BoneSphereMap mBoneSphereMap;
|
||||||
|
|
||||||
bool mFirstFrame;
|
unsigned int mLastFrameNumber;
|
||||||
bool mBoundsFirstFrame;
|
bool mBoundsFirstFrame;
|
||||||
|
|
||||||
bool initFromParentSkeleton(osg::NodeVisitor* nv);
|
bool initFromParentSkeleton(osg::NodeVisitor* nv);
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="MWScrollBar" skin="MW_HScroll" position="7 61 578 18" align="Left Top HStretch" name="CountSlider">
|
<Widget type="MWScrollBar" skin="MW_HScroll" position="7 61 578 18" align="Left Top HStretch" name="CountSlider">
|
||||||
<Property key="MoveToClick" value="true"/>
|
<Property key="MoveToClick" value="true"/>
|
||||||
|
<Property key="Page" value="1"/>
|
||||||
|
<Property key="WheelPage" value="1"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="HBox" skin="" position="0 88 585 24" align="Right Bottom">
|
<Widget type="HBox" skin="" position="0 88 585 24" align="Right Bottom">
|
||||||
<Widget type="Widget" skin="" position="0 12 0 0">
|
<Widget type="Widget" skin="" position="0 12 0 0">
|
||||||
|
|
Loading…
Reference in a new issue