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 Olofsson (Ace)
|
||||
Artem Kotsynyak (greye)
|
||||
artemutin
|
||||
Arthur Moore (EmperorArthur)
|
||||
athile
|
||||
Bret Curtis (psi29a)
|
||||
|
|
|
@ -67,7 +67,7 @@ opencs_hdrs_noqt (view/doc
|
|||
|
||||
opencs_units (view/world
|
||||
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
|
||||
cellcreator referenceablecreator referencecreator scenesubview
|
||||
cellcreator referenceablecreator startscriptcreator referencecreator scenesubview
|
||||
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
|
||||
dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator
|
||||
)
|
||||
|
@ -85,12 +85,12 @@ opencs_units (view/widget
|
|||
|
||||
opencs_units (view/render
|
||||
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
|
||||
previewwidget editmode
|
||||
previewwidget editmode instancemode
|
||||
)
|
||||
|
||||
opencs_units_noqt (view/render
|
||||
lighting lightingday lightingnight
|
||||
lightingbright object cell terrainstorage
|
||||
lightingbright object cell terrainstorage tagbase cellarrow
|
||||
)
|
||||
|
||||
opencs_hdrs_noqt (view/render
|
||||
|
|
|
@ -371,6 +371,57 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
|
|||
"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:
|
||||
|
|
|
@ -32,6 +32,23 @@ std::string CSMWorld::CellCoordinates::getId (const std::string& worldspace) con
|
|||
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)
|
||||
{
|
||||
return left.getX()==right.getX() && left.getY()==right.getY();
|
||||
|
|
|
@ -28,6 +28,12 @@ namespace CSMWorld
|
|||
|
||||
std::string getId (const std::string& worldspace) const;
|
||||
///< 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);
|
||||
|
|
|
@ -77,7 +77,7 @@ bool CSMWorld::ColumnBase::isId (Display display)
|
|||
Display_Video,
|
||||
|
||||
Display_Id,
|
||||
Display_SkillImpact,
|
||||
Display_SkillId,
|
||||
Display_EffectRange,
|
||||
Display_EffectId,
|
||||
Display_PartRefType,
|
||||
|
@ -85,7 +85,6 @@ bool CSMWorld::ColumnBase::isId (Display display)
|
|||
Display_InfoCondFunc,
|
||||
Display_InfoCondVar,
|
||||
Display_InfoCondComp,
|
||||
Display_RaceSkill,
|
||||
|
||||
Display_None
|
||||
};
|
||||
|
|
|
@ -113,7 +113,7 @@ namespace CSMWorld
|
|||
Display_SoundGeneratorType,
|
||||
Display_School,
|
||||
Display_Id,
|
||||
Display_SkillImpact,
|
||||
Display_SkillId,
|
||||
Display_EffectRange,
|
||||
Display_EffectId,
|
||||
Display_PartRefType,
|
||||
|
@ -121,7 +121,6 @@ namespace CSMWorld
|
|||
Display_InfoCondFunc,
|
||||
Display_InfoCondVar,
|
||||
Display_InfoCondComp,
|
||||
Display_RaceSkill,
|
||||
Display_String32,
|
||||
Display_LongString256,
|
||||
|
||||
|
|
|
@ -249,7 +249,7 @@ namespace CSMWorld
|
|||
{ ColumnId_AiWanderDist, "Wander Dist" },
|
||||
{ ColumnId_AiDuration, "Ai Duration" },
|
||||
{ ColumnId_AiWanderToD, "Wander ToD" },
|
||||
{ ColumnId_AiWanderIdle, "Wander Idle" },
|
||||
//{ ColumnId_AiWanderIdle, "Wander Idle" },
|
||||
{ ColumnId_AiWanderRepeat, "Wander Repeat" },
|
||||
{ ColumnId_AiActivateName, "Activate" },
|
||||
{ ColumnId_AiTargetId, "Target ID" },
|
||||
|
@ -268,7 +268,7 @@ namespace CSMWorld
|
|||
{ ColumnId_LevelledItemChanceNone, "Chance None" },
|
||||
|
||||
{ ColumnId_PowerList, "Powers" },
|
||||
{ ColumnId_SkillImpact, "Skill" },
|
||||
{ ColumnId_Skill, "Skill" },
|
||||
|
||||
{ ColumnId_InfoList, "Info List" },
|
||||
{ ColumnId_InfoCondition, "Info Conditions" },
|
||||
|
@ -293,8 +293,7 @@ namespace CSMWorld
|
|||
{ ColumnId_NpcPersistence, "Persistent" },
|
||||
|
||||
{ ColumnId_RaceAttributes, "Race Attributes" },
|
||||
{ ColumnId_RaceMaleValue, "Male Attrib" },
|
||||
{ ColumnId_RaceFemaleValue, "Female Attrib" },
|
||||
{ ColumnId_Male, "Male" },
|
||||
{ ColumnId_RaceSkillBonus, "Skill Bonus" },
|
||||
{ ColumnId_RaceBonus, "Bonus" },
|
||||
|
||||
|
@ -317,6 +316,15 @@ namespace CSMWorld
|
|||
{ ColumnId_MaxAttack, "Max Attack" },
|
||||
{ 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_UseValue2, "Use value 2" },
|
||||
{ ColumnId_UseValue3, "Use value 3" },
|
||||
|
@ -572,7 +580,7 @@ namespace
|
|||
case CSMWorld::Columns::ColumnId_MeshType: return sMeshTypes;
|
||||
case CSMWorld::Columns::ColumnId_SoundGeneratorType: return sSoundGeneratorType;
|
||||
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_EffectId: return sEffectId;
|
||||
case CSMWorld::Columns::ColumnId_PartRefType: return sPartRefType;
|
||||
|
|
|
@ -241,7 +241,7 @@ namespace CSMWorld
|
|||
ColumnId_AiWanderDist = 221,
|
||||
ColumnId_AiDuration = 222,
|
||||
ColumnId_AiWanderToD = 223,
|
||||
ColumnId_AiWanderIdle = 224,
|
||||
// unused
|
||||
ColumnId_AiWanderRepeat = 225,
|
||||
ColumnId_AiActivateName = 226,
|
||||
// use ColumnId_PosX, etc for AI destinations
|
||||
|
@ -261,7 +261,7 @@ namespace CSMWorld
|
|||
ColumnId_LevelledItemChanceNone = 238,
|
||||
|
||||
ColumnId_PowerList = 239,
|
||||
ColumnId_SkillImpact = 240, // impact from magic effects
|
||||
ColumnId_Skill = 240,
|
||||
|
||||
ColumnId_InfoList = 241,
|
||||
ColumnId_InfoCondition = 242,
|
||||
|
@ -288,8 +288,8 @@ namespace CSMWorld
|
|||
ColumnId_NpcPersistence = 261,
|
||||
|
||||
ColumnId_RaceAttributes = 262,
|
||||
ColumnId_RaceMaleValue = 263,
|
||||
ColumnId_RaceFemaleValue = 264,
|
||||
ColumnId_Male = 263,
|
||||
// unused
|
||||
ColumnId_RaceSkillBonus = 265,
|
||||
// unused
|
||||
ColumnId_RaceBonus = 267,
|
||||
|
@ -316,6 +316,15 @@ namespace CSMWorld
|
|||
ColumnId_MaxAttack = 284,
|
||||
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
|
||||
// to extend the number of use values.
|
||||
ColumnId_UseValue1 = 0x10000,
|
||||
|
|
|
@ -143,15 +143,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
|
|||
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute,
|
||||
ColumnBase::Flag_Dialogue, false));
|
||||
mRaces.getNestableColumn(index)->addColumn(
|
||||
new NestedChildColumn (Columns::ColumnId_RaceMaleValue, ColumnBase::Display_Integer));
|
||||
new NestedChildColumn (Columns::ColumnId_Male, ColumnBase::Display_Integer));
|
||||
mRaces.getNestableColumn(index)->addColumn(
|
||||
new NestedChildColumn (Columns::ColumnId_RaceFemaleValue, ColumnBase::Display_Integer));
|
||||
new NestedChildColumn (Columns::ColumnId_Female, ColumnBase::Display_Integer));
|
||||
// Race skill bonus
|
||||
mRaces.addColumn (new NestedParentColumn<ESM::Race> (Columns::ColumnId_RaceSkillBonus));
|
||||
index = mRaces.getColumns()-1;
|
||||
mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceSkillsBonusAdapter()));
|
||||
mRaces.getNestableColumn(index)->addColumn(
|
||||
new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact));
|
||||
new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId));
|
||||
mRaces.getNestableColumn(index)->addColumn(
|
||||
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(
|
||||
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId));
|
||||
mSpells.getNestableColumn(index)->addColumn(
|
||||
new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact));
|
||||
new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId));
|
||||
mSpells.getNestableColumn(index)->addColumn(
|
||||
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute));
|
||||
mSpells.getNestableColumn(index)->addColumn(
|
||||
|
@ -329,7 +329,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
|
|||
mEnchantments.getNestableColumn(index)->addColumn(
|
||||
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId));
|
||||
mEnchantments.getNestableColumn(index)->addColumn(
|
||||
new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact));
|
||||
new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId));
|
||||
mEnchantments.getNestableColumn(index)->addColumn(
|
||||
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute));
|
||||
mEnchantments.getNestableColumn(index)->addColumn(
|
||||
|
|
|
@ -1532,6 +1532,8 @@ namespace CSMWorld
|
|||
|
||||
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,
|
||||
RefIdData& data, int index, int position) const
|
||||
{
|
||||
|
@ -1615,6 +1617,7 @@ namespace CSMWorld
|
|||
switch (subColIndex)
|
||||
{
|
||||
case 0:
|
||||
// FIXME: should more than one AI package type be allowed? Check vanilla
|
||||
switch (content.mType)
|
||||
{
|
||||
case ESM::AI_Wander: return 0;
|
||||
|
@ -1642,47 +1645,52 @@ namespace CSMWorld
|
|||
else
|
||||
return QVariant();
|
||||
case 4: // wander idle
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
if (content.mType == ESM::AI_Wander)
|
||||
{
|
||||
return static_cast<int>(content.mWander.mIdle[0]); // FIXME:
|
||||
}
|
||||
return static_cast<int>(content.mWander.mIdle[subColIndex-4]);
|
||||
else
|
||||
return QVariant();
|
||||
case 5: // wander repeat
|
||||
case 12: // wander repeat
|
||||
if (content.mType == ESM::AI_Wander)
|
||||
return content.mWander.mShouldRepeat != 0;
|
||||
else
|
||||
return QVariant();
|
||||
case 6: // activate name
|
||||
case 13: // activate name
|
||||
if (content.mType == ESM::AI_Activate)
|
||||
return QString(content.mActivate.mName.toString().c_str());
|
||||
else
|
||||
return QVariant();
|
||||
case 7: // target id
|
||||
case 14: // target id
|
||||
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||
return QString(content.mTarget.mId.toString().c_str());
|
||||
else
|
||||
return QVariant();
|
||||
case 8: // target cell
|
||||
case 15: // target cell
|
||||
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||
return QString::fromUtf8(content.mCellName.c_str());
|
||||
else
|
||||
return QVariant();
|
||||
case 9:
|
||||
case 16:
|
||||
if (content.mType == ESM::AI_Travel)
|
||||
return content.mTravel.mX;
|
||||
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||
return content.mTarget.mX;
|
||||
else
|
||||
return QVariant();
|
||||
case 10:
|
||||
case 17:
|
||||
if (content.mType == ESM::AI_Travel)
|
||||
return content.mTravel.mY;
|
||||
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||
return content.mTarget.mY;
|
||||
else
|
||||
return QVariant();
|
||||
case 11:
|
||||
case 18:
|
||||
if (content.mType == ESM::AI_Travel)
|
||||
return content.mTravel.mZ;
|
||||
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||
|
@ -1712,11 +1720,12 @@ namespace CSMWorld
|
|||
case 0: // ai package type
|
||||
switch (value.toInt())
|
||||
{
|
||||
case 0: content.mType = ESM::AI_Wander;
|
||||
case 1: content.mType = ESM::AI_Travel;
|
||||
case 2: content.mType = ESM::AI_Follow;
|
||||
case 3: content.mType = ESM::AI_Escort;
|
||||
case 4: content.mType = ESM::AI_Activate;
|
||||
case 0: content.mType = ESM::AI_Wander; break;
|
||||
case 1: content.mType = ESM::AI_Travel; break;
|
||||
case 2: content.mType = ESM::AI_Follow; break;
|
||||
case 3: content.mType = ESM::AI_Escort; break;
|
||||
case 4: content.mType = ESM::AI_Activate; break;
|
||||
default: return; // return without saving
|
||||
}
|
||||
break; // always save
|
||||
|
||||
|
@ -1725,6 +1734,8 @@ namespace CSMWorld
|
|||
content.mWander.mDistance = static_cast<short>(value.toInt());
|
||||
else
|
||||
return; // return without saving
|
||||
|
||||
break; // always save
|
||||
case 2:
|
||||
if (content.mType == ESM::AI_Wander ||
|
||||
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());
|
||||
else
|
||||
return; // return without saving
|
||||
|
||||
break; // always save
|
||||
case 4:
|
||||
if (content.mType == ESM::AI_Wander)
|
||||
break; // FIXME: idle
|
||||
else
|
||||
return; // return without saving
|
||||
case 5:
|
||||
if (content.mType == ESM::AI_Wander)
|
||||
{
|
||||
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 6:
|
||||
case 7:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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)
|
||||
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 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:
|
||||
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
|
||||
{
|
||||
return 12;
|
||||
return 19;
|
||||
}
|
||||
|
||||
virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const
|
||||
|
|
|
@ -83,7 +83,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
|||
mColumns.back().addColumn(
|
||||
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId));
|
||||
mColumns.back().addColumn(
|
||||
new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact));
|
||||
new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId));
|
||||
mColumns.back().addColumn(
|
||||
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute));
|
||||
mColumns.back().addColumn(
|
||||
|
@ -193,8 +193,24 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
|||
new RefIdColumn (Columns::ColumnId_AiDuration, CSMWorld::ColumnBase::Display_Integer));
|
||||
mColumns.back().addColumn(
|
||||
new RefIdColumn (Columns::ColumnId_AiWanderToD, CSMWorld::ColumnBase::Display_Integer));
|
||||
|
||||
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(
|
||||
new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_Boolean));
|
||||
mColumns.back().addColumn(
|
||||
|
@ -491,7 +507,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
|||
skillsMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcSkillsRefIdAdapter()));
|
||||
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), skillsMap));
|
||||
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(
|
||||
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;
|
||||
addDockWidget (Qt::BottomDockWidgetArea, mOperations);
|
||||
|
||||
setContextMenuPolicy(Qt::NoContextMenu);
|
||||
|
||||
updateTitle();
|
||||
|
||||
setupUi();
|
||||
|
|
|
@ -97,7 +97,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
|
|||
{ CSMWorld::ColumnBase::Display_Gender, CSMWorld::Columns::ColumnId_Gender, true },
|
||||
{ CSMWorld::ColumnBase::Display_SoundGeneratorType, CSMWorld::Columns::ColumnId_SoundGeneratorType, 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_EffectId, CSMWorld::Columns::ColumnId_EffectId, false },
|
||||
{ CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false },
|
||||
|
|
|
@ -5,14 +5,17 @@
|
|||
#include <QApplication>
|
||||
|
||||
#include "../../model/world/data.hpp"
|
||||
#include "../../model/world/idtablebase.hpp"
|
||||
#include "../../model/world/columns.hpp"
|
||||
|
||||
CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent)
|
||||
: QLineEdit (parent), mParser (data)
|
||||
: QLineEdit (parent), mParser (data), mIsEmpty(true)
|
||||
{
|
||||
mPalette = palette();
|
||||
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&)),
|
||||
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)),
|
||||
this, SLOT (filterRowsInserted (const QModelIndex&, int, int)),
|
||||
Qt::QueuedConnection);
|
||||
|
||||
mStateColumnIndex = model->findColumnIndex(CSMWorld::Columns::ColumnId_Modification);
|
||||
mDescColumnIndex = model->findColumnIndex(CSMWorld::Columns::ColumnId_Description);
|
||||
}
|
||||
|
||||
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()))
|
||||
{
|
||||
setPalette (mPalette);
|
||||
|
@ -45,7 +61,9 @@ void CSVFilter::EditWidget::textChanged (const QString& text)
|
|||
void CSVFilter::EditWidget::filterDataChanged (const QModelIndex& topLeft,
|
||||
const QModelIndex& bottomRight)
|
||||
{
|
||||
textChanged (text());
|
||||
for (int i = topLeft.column(); i <= bottomRight.column(); ++i)
|
||||
if (i != mStateColumnIndex && i != mDescColumnIndex)
|
||||
textChanged (text());
|
||||
}
|
||||
|
||||
void CSVFilter::EditWidget::filterRowsRemoved (const QModelIndex& parent, int start, int end)
|
||||
|
|
|
@ -25,6 +25,9 @@ namespace CSVFilter
|
|||
|
||||
CSMFilter::Parser mParser;
|
||||
QPalette mPalette;
|
||||
bool mIsEmpty;
|
||||
int mStateColumnIndex;
|
||||
int mDescColumnIndex;
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "../../model/world/columns.hpp"
|
||||
#include "../../model/world/data.hpp"
|
||||
#include "../../model/world/refcollection.hpp"
|
||||
#include "../../model/world/cellcoordinates.hpp"
|
||||
|
||||
#include "elements.hpp"
|
||||
#include "terrainstorage.hpp"
|
||||
|
@ -50,33 +51,39 @@ bool CSVRender::Cell::addObjects (int start, int end)
|
|||
return modified;
|
||||
}
|
||||
|
||||
CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id)
|
||||
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mX(0), mY(0)
|
||||
CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id,
|
||||
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;
|
||||
rootNode->addChild(mCellNode);
|
||||
|
||||
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
||||
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
|
||||
|
||||
int rows = references.rowCount();
|
||||
|
||||
addObjects (0, rows-1);
|
||||
|
||||
const CSMWorld::IdCollection<CSMWorld::Land>& land = mData.getLand();
|
||||
int landIndex = land.searchId(mId);
|
||||
if (landIndex != -1)
|
||||
if (!mDeleted)
|
||||
{
|
||||
const ESM::Land& esmLand = land.getRecord(mId).get();
|
||||
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
||||
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
|
||||
|
||||
if (esmLand.getLandData (ESM::Land::DATA_VHGT))
|
||||
int rows = references.rowCount();
|
||||
|
||||
addObjects (0, rows-1);
|
||||
|
||||
const CSMWorld::IdCollection<CSMWorld::Land>& land = mData.getLand();
|
||||
int landIndex = land.searchId(mId);
|
||||
if (landIndex != -1)
|
||||
{
|
||||
mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1));
|
||||
mTerrain->loadCell(esmLand.mX,
|
||||
esmLand.mY);
|
||||
const ESM::Land& esmLand = land.getRecord(mId).get();
|
||||
|
||||
mX = esmLand.mX;
|
||||
mY = esmLand.mY;
|
||||
if (esmLand.getLandData (ESM::Land::DATA_VHGT))
|
||||
{
|
||||
mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1));
|
||||
mTerrain->loadCell(esmLand.mX,
|
||||
esmLand.mY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,6 +129,9 @@ bool CSVRender::Cell::referenceableAboutToBeRemoved (const QModelIndex& parent,
|
|||
bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft,
|
||||
const QModelIndex& bottomRight)
|
||||
{
|
||||
if (mDeleted)
|
||||
return false;
|
||||
|
||||
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
||||
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
|
||||
|
||||
|
@ -189,6 +199,9 @@ bool CSVRender::Cell::referenceAboutToBeRemoved (const QModelIndex& parent, int
|
|||
if (parent.isValid())
|
||||
return false;
|
||||
|
||||
if (mDeleted)
|
||||
return false;
|
||||
|
||||
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
|
||||
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
|
||||
|
||||
|
@ -209,5 +222,57 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int
|
|||
if (parent.isValid())
|
||||
return false;
|
||||
|
||||
if (mDeleted)
|
||||
return false;
|
||||
|
||||
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
|
||||
|
||||
#include "object.hpp"
|
||||
#include "cellarrow.hpp"
|
||||
|
||||
class QModelIndex;
|
||||
|
||||
|
@ -25,6 +26,7 @@ namespace osg
|
|||
namespace CSMWorld
|
||||
{
|
||||
class Data;
|
||||
class CellCoordinates;
|
||||
}
|
||||
|
||||
namespace CSVRender
|
||||
|
@ -36,8 +38,9 @@ namespace CSVRender
|
|||
osg::ref_ptr<osg::Group> mCellNode;
|
||||
std::map<std::string, Object *> mObjects;
|
||||
std::auto_ptr<Terrain::TerrainGrid> mTerrain;
|
||||
int mX;
|
||||
int mY;
|
||||
CSMWorld::CellCoordinates mCoordinates;
|
||||
std::auto_ptr<CellArrow> mCellArrows[4];
|
||||
bool mDeleted;
|
||||
|
||||
/// Ignored if cell does not have an object with the given ID.
|
||||
///
|
||||
|
@ -51,7 +54,19 @@ namespace CSVRender
|
|||
|
||||
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();
|
||||
|
||||
|
@ -75,6 +90,15 @@ namespace CSVRender
|
|||
/// \return Did this call result in a modification of the visual representation of
|
||||
/// this cell?
|
||||
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 "tagbase.hpp"
|
||||
#include "worldspacewidget.hpp"
|
||||
|
||||
CSVRender::WorldspaceWidget& CSVRender::EditMode::getWorldspaceWidget()
|
||||
{
|
||||
return *mWorldspaceWidget;
|
||||
}
|
||||
|
||||
CSVRender::EditMode::EditMode (WorldspaceWidget *worldspaceWidget, const QIcon& icon,
|
||||
unsigned int mask, const QString& tooltip, QWidget *parent)
|
||||
: 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)
|
||||
{
|
||||
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
|
||||
#define CSV_RENDER_EDITMODE_H
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include "../widget/modebutton.hpp"
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
class WorldspaceWidget;
|
||||
class TagBase;
|
||||
|
||||
class EditMode : public CSVWidget::ModeButton
|
||||
{
|
||||
|
@ -14,6 +17,10 @@ namespace CSVRender
|
|||
WorldspaceWidget *mWorldspaceWidget;
|
||||
unsigned int mMask;
|
||||
|
||||
protected:
|
||||
|
||||
WorldspaceWidget& getWorldspaceWidget();
|
||||
|
||||
public:
|
||||
|
||||
EditMode (WorldspaceWidget *worldspaceWidget, const QIcon& icon, unsigned int mask,
|
||||
|
@ -22,6 +29,51 @@ namespace CSVRender
|
|||
unsigned int getInteractionMask() const;
|
||||
|
||||
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()
|
||||
{
|
||||
}
|
||||
|
@ -124,7 +129,7 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode,
|
|||
mOutline = new osgFX::Scribe;
|
||||
mOutline->addChild(mBaseNode);
|
||||
|
||||
mBaseNode->setUserData(new ObjectHolder(this));
|
||||
mBaseNode->setUserData(new ObjectTag(this));
|
||||
|
||||
parentNode->addChild(mBaseNode);
|
||||
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
#include <osg/ref_ptr>
|
||||
#include <osg/Referenced>
|
||||
|
||||
class QModelIndex;
|
||||
#include "tagbase.hpp"
|
||||
|
||||
class QModelIndex;
|
||||
|
||||
namespace osg
|
||||
{
|
||||
|
@ -35,21 +36,19 @@ namespace CSMWorld
|
|||
|
||||
namespace CSVRender
|
||||
{
|
||||
|
||||
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
|
||||
class ObjectHolder : public osg::Referenced
|
||||
class ObjectTag : public TagBase
|
||||
{
|
||||
public:
|
||||
ObjectHolder(Object* obj)
|
||||
: mObject(obj)
|
||||
{
|
||||
}
|
||||
public:
|
||||
|
||||
Object* mObject;
|
||||
ObjectTag (Object* object);
|
||||
|
||||
Object* mObject;
|
||||
};
|
||||
|
||||
|
||||
class Object
|
||||
{
|
||||
const CSMWorld::Data& mData;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include "pagedworldspacewidget.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QApplication>
|
||||
|
||||
#include <osgGA/TrackballManipulator>
|
||||
|
||||
|
@ -21,20 +23,19 @@
|
|||
bool CSVRender::PagedWorldspaceWidget::adjustCells()
|
||||
{
|
||||
bool modified = false;
|
||||
bool wasEmpty = mCells.empty();
|
||||
|
||||
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());
|
||||
|
||||
while (iter!=mCells.end())
|
||||
{
|
||||
int index = cells.searchId (iter->first.getId (mWorldspace));
|
||||
|
||||
if (!mSelection.has (iter->first) || index==-1 ||
|
||||
cells.getRecord (index).mState==CSMWorld::RecordBase::State_Deleted)
|
||||
if (!mSelection.has (iter->first))
|
||||
{
|
||||
// remove
|
||||
delete iter->second;
|
||||
mCells.erase (iter++);
|
||||
|
||||
|
@ -42,12 +43,33 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells()
|
|||
}
|
||||
else
|
||||
{
|
||||
// check if name or region field has changed
|
||||
// FIXME: config setting
|
||||
//std::string name = cells.getRecord(index).get().mName;
|
||||
//std::string region = cells.getRecord(index).get().mRegion;
|
||||
// update
|
||||
int index = cells.searchId (iter->first.getId (mWorldspace));
|
||||
|
||||
// cell marker update goes here
|
||||
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
|
||||
//std::string name = cells.getRecord(index).get().mName;
|
||||
//std::string region = cells.getRecord(index).get().mRegion;
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
++iter;
|
||||
}
|
||||
|
@ -58,20 +80,43 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells()
|
|||
for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end();
|
||||
++iter)
|
||||
{
|
||||
int index = cells.searchId (iter->getId (mWorldspace));
|
||||
|
||||
if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted &&
|
||||
mCells.find (*iter)==mCells.end())
|
||||
if (mCells.find (*iter)==mCells.end())
|
||||
{
|
||||
Cell *cell = new Cell (mDocument.getData(), mRootNode,
|
||||
iter->getId (mWorldspace));
|
||||
mCells.insert (std::make_pair (*iter, cell));
|
||||
|
||||
addCellToScene (*iter);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return modified;
|
||||
|
@ -105,6 +150,76 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons (
|
|||
"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,
|
||||
const QModelIndex& bottomRight)
|
||||
{
|
||||
|
@ -184,6 +299,72 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction()
|
|||
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)
|
||||
: WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"),
|
||||
mControlElements(NULL), mDisplayCellCoord(true)
|
||||
|
@ -314,6 +495,15 @@ unsigned int CSVRender::PagedWorldspaceWidget::getVisibilityMask() const
|
|||
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::SceneToolbar *parent)
|
||||
{
|
||||
|
|
|
@ -53,6 +53,20 @@ namespace CSVRender
|
|||
|
||||
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:
|
||||
|
||||
PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document);
|
||||
|
@ -79,12 +93,17 @@ namespace CSVRender
|
|||
|
||||
virtual unsigned int getVisibilityMask() const;
|
||||
|
||||
/// \param elementMask Elements to be affected by the clear operation
|
||||
virtual void clearSelection (int elementMask);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);
|
||||
|
||||
virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool);
|
||||
|
||||
virtual void handleMouseClick (osg::ref_ptr<TagBase> tag, const std::string& button, bool shift);
|
||||
|
||||
signals:
|
||||
|
||||
void cellSelectionChanged (const CSMWorld::CellSelection& selection);
|
||||
|
|
|
@ -110,6 +110,8 @@ bool RenderWidget::eventFilter(QObject* obj, QEvent* event)
|
|||
keyPressEvent(static_cast<QKeyEvent*>(event));
|
||||
if (event->type() == QEvent::KeyRelease)
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
void CSVRender::UnpagedWorldspaceWidget::clearSelection (int elementMask)
|
||||
{
|
||||
mCell->setSelection (elementMask, Cell::Selection_Clear);
|
||||
flagAsModified();
|
||||
}
|
||||
|
||||
void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
|
||||
const QModelIndex& bottomRight)
|
||||
{
|
||||
|
|
|
@ -43,6 +43,9 @@ namespace CSVRender
|
|||
virtual bool handleDrop (const std::vector<CSMWorld::UniversalId>& data,
|
||||
DropType type);
|
||||
|
||||
/// \param elementMask Elements to be affected by the clear operation
|
||||
virtual void clearSelection (int elementMask);
|
||||
|
||||
private:
|
||||
|
||||
virtual void referenceableDataChanged (const QModelIndex& topLeft,
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <QDropEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QApplication>
|
||||
|
||||
#include <osgGA/TrackballManipulator>
|
||||
#include <osgGA/FirstPersonManipulator>
|
||||
|
@ -18,6 +19,8 @@
|
|||
#include "../../model/world/universalid.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
|
||||
#include "../../model/settings/usersettings.hpp"
|
||||
|
||||
#include "../widget/scenetoolmode.hpp"
|
||||
#include "../widget/scenetooltoggle2.hpp"
|
||||
#include "../widget/scenetoolrun.hpp"
|
||||
|
@ -25,10 +28,22 @@
|
|||
#include "object.hpp"
|
||||
#include "elements.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)
|
||||
: SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document),
|
||||
mInteractionMask (0)
|
||||
mInteractionMask (0), mEditMode (0), mLocked (false), mDragging (false)
|
||||
{
|
||||
setAcceptDrops(true);
|
||||
|
||||
|
@ -59,6 +74,17 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg
|
|||
this, SLOT (debugProfileDataChanged (const QModelIndex&, const QModelIndex&)));
|
||||
connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (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 ()
|
||||
|
@ -178,11 +204,14 @@ CSVWidget::SceneToolRun *CSVRender::WorldspaceWidget::makeRunTool (
|
|||
CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeEditModeSelector (
|
||||
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 (
|
||||
|
@ -254,6 +283,26 @@ unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const
|
|||
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 (
|
||||
CSVWidget::SceneToolToggle2 *tool)
|
||||
{
|
||||
|
@ -265,9 +314,7 @@ void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons (
|
|||
void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool)
|
||||
{
|
||||
/// \todo replace EditMode with suitable subclasses
|
||||
tool->addButton (
|
||||
new EditMode (this, QIcon (":placeholder"), Element_Reference, "Instance editing"),
|
||||
"object");
|
||||
tool->addButton (new InstanceMode (this, tool), "object");
|
||||
tool->addButton (
|
||||
new EditMode (this, QIcon (":placeholder"), Element_Pathgrid, "Pathgrid editing"),
|
||||
"pathgrid");
|
||||
|
@ -288,6 +335,95 @@ void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event)
|
|||
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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
setVisibilityMask (getVisibilityMask());
|
||||
|
@ -365,74 +507,97 @@ void CSVRender::WorldspaceWidget::updateOverlay()
|
|||
|
||||
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)
|
||||
{
|
||||
if (event->button() != Qt::RightButton)
|
||||
return;
|
||||
std::string button = mapButton (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 (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;
|
||||
}
|
||||
if (!mDragging)
|
||||
mDragMode = button;
|
||||
}
|
||||
|
||||
void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event)
|
||||
{
|
||||
if(event->button() == Qt::RightButton)
|
||||
std::string button = mapButton (event);
|
||||
|
||||
if (mDragging)
|
||||
{
|
||||
/*
|
||||
if(!getViewport())
|
||||
if (mDragMode=="p-navi" || mDragMode=="s-navi")
|
||||
{
|
||||
SceneWidget::mouseReleaseEvent(event);
|
||||
return;
|
||||
|
||||
}
|
||||
else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="select")
|
||||
{
|
||||
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
||||
|
||||
editMode.dragCompleted();
|
||||
mDragging = false;
|
||||
}
|
||||
*/
|
||||
//mMouse->mouseReleaseEvent(event);
|
||||
}
|
||||
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)
|
||||
|
@ -441,21 +606,47 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event)
|
|||
{
|
||||
//mMouse->mouseDoubleClickEvent(event);
|
||||
}
|
||||
//SceneWidget::mouseDoubleClickEvent(event);
|
||||
}
|
||||
|
||||
void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event)
|
||||
{
|
||||
//if(!mMouse->wheelEvent(event))
|
||||
RenderWidget::wheelEvent(event);
|
||||
if (mDragging)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if(event->key() == Qt::Key_Escape)
|
||||
{
|
||||
//mMouse->cancelDrag();
|
||||
if (mDragging)
|
||||
{
|
||||
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
||||
|
||||
editMode.dragAborted();
|
||||
mDragging = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
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
|
||||
#define OPENCS_VIEW_WORLDSPACEWIDGET_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#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 <apps/opencs/model/world/tablemimedata.hpp>
|
||||
#include "scenewidget.hpp"
|
||||
#include "elements.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
|
@ -23,6 +26,9 @@ namespace CSVWidget
|
|||
|
||||
namespace CSVRender
|
||||
{
|
||||
class TagBase;
|
||||
class CellArrow;
|
||||
|
||||
class WorldspaceWidget : public SceneWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -31,6 +37,16 @@ namespace CSVRender
|
|||
CSVWidget::SceneToolRun *mRun;
|
||||
CSMDoc::Document& mDocument;
|
||||
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:
|
||||
|
||||
|
@ -93,14 +109,21 @@ namespace CSVRender
|
|||
/// marked for interaction.
|
||||
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:
|
||||
|
||||
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);
|
||||
|
||||
virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool);
|
||||
|
||||
CSMDoc::Document& getDocument();
|
||||
|
||||
virtual void updateOverlay();
|
||||
|
||||
virtual void mouseMoveEvent (QMouseEvent *event);
|
||||
|
@ -110,6 +133,9 @@ namespace CSVRender
|
|||
virtual void wheelEvent (QWheelEvent *event);
|
||||
virtual void keyPressEvent (QKeyEvent *event);
|
||||
|
||||
virtual void handleMouseClick (osg::ref_ptr<TagBase> tag, const std::string& button,
|
||||
bool shift);
|
||||
|
||||
private:
|
||||
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
|
@ -118,6 +144,13 @@ namespace CSVRender
|
|||
|
||||
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;
|
||||
|
||||
private slots:
|
||||
|
@ -144,6 +177,7 @@ namespace CSVRender
|
|||
|
||||
void debugProfileAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||
|
||||
void editModeChanged (const std::string& id);
|
||||
|
||||
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()
|
||||
{
|
||||
std::map<ModeButton *, std::string>::const_iterator iter =
|
||||
|
|
|
@ -41,6 +41,9 @@ namespace CSVWidget
|
|||
/// The ownership of \a button is transferred to *this.
|
||||
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:
|
||||
|
||||
void modeChanged (const std::string& id);
|
||||
|
|
|
@ -47,6 +47,16 @@ std::string CSVWorld::GenericCreator::getId() const
|
|||
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::pushCommand (std::auto_ptr<CSMWorld::CreateCommand> command,
|
||||
|
|
|
@ -60,6 +60,8 @@ namespace CSVWorld
|
|||
|
||||
virtual std::string getId() const;
|
||||
|
||||
virtual std::string getIdValidatorResult() const;
|
||||
|
||||
/// Allow subclasses to add additional data to \a command.
|
||||
virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const;
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "../render/pagedworldspacewidget.hpp"
|
||||
#include "../render/unpagedworldspacewidget.hpp"
|
||||
#include "../render/editmode.hpp"
|
||||
|
||||
#include "../widget/scenetoolbar.hpp"
|
||||
#include "../widget/scenetoolmode.hpp"
|
||||
|
@ -121,15 +122,14 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp
|
|||
CSVWidget::SceneToolRun *runTool = widget->makeRunTool (toolbar);
|
||||
toolbar->addTool (runTool);
|
||||
|
||||
CSVWidget::SceneToolMode *editModeTool = widget->makeEditModeSelector (toolbar);
|
||||
toolbar->addTool (editModeTool);
|
||||
toolbar->addTool (widget->makeEditModeSelector (toolbar));
|
||||
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
void CSVWorld::SceneSubView::setEditLock (bool locked)
|
||||
{
|
||||
|
||||
mScene->setEditLock (locked);
|
||||
}
|
||||
|
||||
void CSVWorld::SceneSubView::setStatusBar (bool show)
|
||||
|
@ -147,6 +147,12 @@ std::string CSVWorld::SceneSubView::getTitle() const
|
|||
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)
|
||||
{
|
||||
setUniversalId(id);
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace CSVRender
|
|||
namespace CSVWidget
|
||||
{
|
||||
class SceneToolbar;
|
||||
class SceneToolMode;
|
||||
}
|
||||
|
||||
namespace CSVWorld
|
||||
|
@ -58,6 +59,8 @@ namespace CSVWorld
|
|||
|
||||
virtual std::string getTitle() const;
|
||||
|
||||
virtual void updateUserSetting (const QString& name, const QStringList& value);
|
||||
|
||||
private:
|
||||
|
||||
void makeConnections(CSVRender::PagedWorldspaceWidget* widget);
|
||||
|
|
|
@ -198,26 +198,41 @@ void CSVWorld::ScriptSubView::useHint (const std::string& hint)
|
|||
if (hint.empty())
|
||||
return;
|
||||
|
||||
if (hint[0]=='l')
|
||||
{
|
||||
std::istringstream stream (hint.c_str()+1);
|
||||
|
||||
char ignore;
|
||||
int line;
|
||||
int column;
|
||||
|
||||
if (stream >> ignore >> line >> column)
|
||||
unsigned line = 0, column = 0;
|
||||
char c;
|
||||
std::istringstream stream (hint.c_str()+1);
|
||||
switch(hint[0]){
|
||||
case 'R':
|
||||
case 'r':
|
||||
{
|
||||
QTextCursor cursor = mEditor->textCursor();
|
||||
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
|
||||
QString source = mModel->data (index).toString();
|
||||
unsigned pos, dummy;
|
||||
if (!(stream >> c >> dummy >> pos) )
|
||||
return;
|
||||
|
||||
cursor.movePosition (QTextCursor::Start);
|
||||
if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line))
|
||||
cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column);
|
||||
|
||||
mEditor->setFocus();
|
||||
mEditor->setTextCursor (cursor);
|
||||
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();
|
||||
|
||||
cursor.movePosition (QTextCursor::Start);
|
||||
if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line))
|
||||
cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column);
|
||||
|
||||
mEditor->setFocus();
|
||||
mEditor->setTextCursor (cursor);
|
||||
}
|
||||
|
||||
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 "referenceablecreator.hpp"
|
||||
#include "referencecreator.hpp"
|
||||
#include "startscriptcreator.hpp"
|
||||
#include "scenesubview.hpp"
|
||||
#include "dialoguecreator.hpp"
|
||||
#include "infocreator.hpp"
|
||||
|
@ -42,7 +43,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
|||
CSMWorld::UniversalId::Type_BodyParts,
|
||||
CSMWorld::UniversalId::Type_SoundGens,
|
||||
CSMWorld::UniversalId::Type_Pathgrids,
|
||||
CSMWorld::UniversalId::Type_StartScripts,
|
||||
|
||||
CSMWorld::UniversalId::Type_None // end marker
|
||||
};
|
||||
|
@ -51,6 +51,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
|||
manager.add (sTableTypes[i],
|
||||
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GenericCreator> >);
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_StartScripts,
|
||||
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<StartScriptCreator> >);
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Cells,
|
||||
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<CellCreator> >);
|
||||
|
||||
|
@ -123,7 +126,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
|||
CSMWorld::UniversalId::Type_BodyPart,
|
||||
CSMWorld::UniversalId::Type_SoundGen,
|
||||
CSMWorld::UniversalId::Type_Pathgrid,
|
||||
CSMWorld::UniversalId::Type_StartScript,
|
||||
|
||||
CSMWorld::UniversalId::Type_None // end marker
|
||||
};
|
||||
|
@ -133,6 +135,10 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
|||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView,
|
||||
CreatorFactory<GenericCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_StartScript,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView,
|
||||
CreatorFactory<StartScriptCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Skill,
|
||||
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
|
||||
{
|
||||
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::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
|
||||
|
|
|
@ -139,9 +139,6 @@ namespace MWDialogue
|
|||
|
||||
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
|
||||
const MWWorld::Store<ESM::Dialogue> &dialogs =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>();
|
||||
|
@ -165,12 +162,19 @@ namespace MWDialogue
|
|||
// TODO play sound
|
||||
}
|
||||
|
||||
// first topics update so that parseText knows the keywords to highlight
|
||||
updateTopics();
|
||||
|
||||
parseText (info->mResponse);
|
||||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
||||
executeScript (info->mResultScript);
|
||||
mLastTopic = Misc::StringUtils::lowerCase(it->mId);
|
||||
|
||||
// update topics again to accomodate changes resulting from executeScript
|
||||
updateTopics();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -420,7 +424,6 @@ namespace MWDialogue
|
|||
{
|
||||
if(mDialogueMap.find(keyword) != mDialogueMap.end())
|
||||
{
|
||||
ESM::Dialogue ndialogue = mDialogueMap[keyword];
|
||||
if (mDialogueMap[keyword].mType == ESM::Dialogue::Topic)
|
||||
{
|
||||
executeTopic (keyword);
|
||||
|
|
|
@ -170,25 +170,25 @@ namespace MWGui
|
|||
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)
|
||||
{
|
||||
print("#FF00FF" + msg + "\n");
|
||||
print(msg + "\n", "#FF00FF");
|
||||
}
|
||||
|
||||
void Console::printError(const std::string &msg)
|
||||
{
|
||||
print("#FF2222" + msg + "\n");
|
||||
print(msg + "\n", "#FF2222");
|
||||
}
|
||||
|
||||
void Console::execute (const std::string& command)
|
||||
{
|
||||
// Log the command
|
||||
print("#FFFFFF> " + command + "\n");
|
||||
print("> " + command + "\n");
|
||||
|
||||
Compiler::Locals locals;
|
||||
Compiler::Output output (locals);
|
||||
|
|
|
@ -48,9 +48,8 @@ namespace MWGui
|
|||
|
||||
void onResChange(int width, int height);
|
||||
|
||||
// Print a message to the console. Messages may contain color
|
||||
// code, eg. "#FFFFFF this is white".
|
||||
void print(const std::string &msg);
|
||||
// Print a message to the console, in specified color.
|
||||
void print(const std::string &msg, const std::string& color = "#FFFFFF");
|
||||
|
||||
// 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),
|
||||
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())
|
||||
updatePreviewSize();
|
||||
|
||||
mMainWidget->setPosition(pos);
|
||||
mMainWidget->setSize(size);
|
||||
adjustPanes();
|
||||
}
|
||||
|
||||
|
|
|
@ -235,40 +235,64 @@ namespace MWGui
|
|||
draw();
|
||||
}
|
||||
|
||||
bool LoadingScreen::needToDrawLoadingScreen()
|
||||
{
|
||||
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()
|
||||
== MWBase::StateManager::State_NoGame);
|
||||
if (!showWallpaper && diff < initialDelay*1000)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void LoadingScreen::draw()
|
||||
{
|
||||
if (mTimer.time_m() > mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0)
|
||||
if (!needToDrawLoadingScreen())
|
||||
return;
|
||||
|
||||
bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState()
|
||||
== MWBase::StateManager::State_NoGame);
|
||||
if (showWallpaper && mTimer.time_m() > mLastWallpaperChangeTime + 5000*1)
|
||||
{
|
||||
bool showWallpaper = (MWBase::Environment::get().getStateManager()->getState()
|
||||
== MWBase::StateManager::State_NoGame);
|
||||
|
||||
if (showWallpaper && mTimer.time_m() > mLastWallpaperChangeTime + 5000*1)
|
||||
{
|
||||
mLastWallpaperChangeTime = mTimer.time_m();
|
||||
changeWallpaper();
|
||||
}
|
||||
|
||||
// Turn off rendering except the GUI
|
||||
int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask();
|
||||
int oldCullMask = mViewer->getCamera()->getCullMask();
|
||||
mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI);
|
||||
mViewer->getCamera()->setCullMask(MWRender::Mask_GUI);
|
||||
|
||||
MWBase::Environment::get().getInputManager()->update(0, true, true);
|
||||
|
||||
//osg::Timer timer;
|
||||
mViewer->frame(mViewer->getFrameStamp()->getSimulationTime());
|
||||
//std::cout << "frame took " << timer.time_m() << std::endl;
|
||||
|
||||
//if (mViewer->getIncrementalCompileOperation())
|
||||
//std::cout << "num to compile " << mViewer->getIncrementalCompileOperation()->getToCompile().size() << std::endl;
|
||||
|
||||
// resume 3d rendering
|
||||
mViewer->getUpdateVisitor()->setTraversalMask(oldUpdateMask);
|
||||
mViewer->getCamera()->setCullMask(oldCullMask);
|
||||
|
||||
mLastRenderTime = mTimer.time_m();
|
||||
mLastWallpaperChangeTime = mTimer.time_m();
|
||||
changeWallpaper();
|
||||
}
|
||||
|
||||
// Turn off rendering except the GUI
|
||||
int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask();
|
||||
int oldCullMask = mViewer->getCamera()->getCullMask();
|
||||
mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI);
|
||||
mViewer->getCamera()->setCullMask(MWRender::Mask_GUI);
|
||||
|
||||
MWBase::Environment::get().getInputManager()->update(0, true, true);
|
||||
|
||||
//osg::Timer timer;
|
||||
mViewer->frame(mViewer->getFrameStamp()->getSimulationTime());
|
||||
//std::cout << "frame took " << timer.time_m() << std::endl;
|
||||
|
||||
//if (mViewer->getIncrementalCompileOperation())
|
||||
//std::cout << "num to compile " << mViewer->getIncrementalCompileOperation()->getToCompile().size() << std::endl;
|
||||
|
||||
// resume 3d rendering
|
||||
mViewer->getUpdateVisitor()->setTraversalMask(oldUpdateMask);
|
||||
mViewer->getCamera()->setCullMask(oldCullMask);
|
||||
|
||||
mLastRenderTime = mTimer.time_m();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ namespace MWGui
|
|||
|
||||
private:
|
||||
void findSplashScreens();
|
||||
bool needToDrawLoadingScreen();
|
||||
|
||||
const VFS::Manager* mVFS;
|
||||
osg::ref_ptr<osgViewer::Viewer> mViewer;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "spellmodel.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -79,8 +81,13 @@ namespace MWGui
|
|||
const std::string enchantId = item.getClass().getEnchantment(item);
|
||||
if (enchantId.empty())
|
||||
continue;
|
||||
const ESM::Enchantment* enchant =
|
||||
esmStore.get<ESM::Enchantment>().find(item.getClass().getEnchantment(item));
|
||||
const ESM::Enchantment* enchant = esmStore.get<ESM::Enchantment>().search(enchantId);
|
||||
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)
|
||||
continue;
|
||||
|
||||
|
|
|
@ -8,11 +8,6 @@
|
|||
namespace MWGui
|
||||
{
|
||||
|
||||
namespace Widgets
|
||||
{
|
||||
class MWScrollBar;
|
||||
}
|
||||
|
||||
class WaitDialogProgressBar : public WindowBase
|
||||
{
|
||||
public:
|
||||
|
@ -51,7 +46,7 @@ namespace MWGui
|
|||
MyGUI::Button* mUntilHealedButton;
|
||||
MyGUI::Button* mWaitButton;
|
||||
MyGUI::Button* mCancelButton;
|
||||
MWGui::Widgets::MWScrollBar* mHourSlider;
|
||||
MyGUI::ScrollBar* mHourSlider;
|
||||
|
||||
TimeAdvancer mTimeAdvancer;
|
||||
bool mSleeping;
|
||||
|
|
|
@ -20,8 +20,9 @@ namespace MWMechanics
|
|||
struct AiFollowStorage : AiTemporaryBase
|
||||
{
|
||||
float mTimer;
|
||||
bool mMoving;
|
||||
|
||||
AiFollowStorage() : mTimer(0.f) {}
|
||||
AiFollowStorage() : mTimer(0.f), mMoving(false) {}
|
||||
};
|
||||
|
||||
int AiFollow::mFollowIndexCounter = 0;
|
||||
|
@ -64,10 +65,11 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
|||
|
||||
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
|
||||
if (!mActive)
|
||||
{
|
||||
AiFollowStorage& storage = state.get<AiFollowStorage>();
|
||||
storage.mTimer -= duration;
|
||||
|
||||
if (storage.mTimer < 0)
|
||||
|
@ -126,7 +128,15 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
|||
//Set the target destination from the actor
|
||||
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;
|
||||
|
||||
|
@ -141,9 +151,9 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
|||
}
|
||||
|
||||
//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
|
||||
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
|
||||
|
||||
return false;
|
||||
|
|
|
@ -88,7 +88,8 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur
|
|||
MWWorld::Ptr door = getNearbyDoor(actor);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -295,7 +295,7 @@ namespace MWMechanics
|
|||
creatureStats.getSpells().add(*it);
|
||||
|
||||
// forced update and current value adjustments
|
||||
//mActors.updateActor (ptr, 0);
|
||||
mActors.updateActor (ptr, 0);
|
||||
|
||||
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)
|
||||
return 100;
|
||||
|
||||
|
@ -817,6 +820,10 @@ namespace MWMechanics
|
|||
sndMgr->playSound3D(mCaster, "Spell Failure " + schools[school], 1.0f, 1.0f);
|
||||
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))
|
||||
|
|
|
@ -312,7 +312,7 @@ namespace MWMechanics
|
|||
|
||||
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())
|
||||
return true;
|
||||
else
|
||||
|
@ -321,7 +321,7 @@ namespace MWMechanics
|
|||
|
||||
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)
|
||||
|
|
|
@ -1275,15 +1275,26 @@ namespace MWRender
|
|||
material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1));
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
|
@ -1320,13 +1331,16 @@ namespace MWRender
|
|||
{
|
||||
mHeadController = NULL;
|
||||
|
||||
NodeMap::iterator found = mNodeMap.find("bip01 head");
|
||||
if (found != mNodeMap.end() && dynamic_cast<osg::MatrixTransform*>(found->second.get()))
|
||||
if (mPtr.getClass().isBipedal(mPtr))
|
||||
{
|
||||
osg::Node* node = found->second;
|
||||
mHeadController = new RotateController(mObjectRoot.get());
|
||||
node->addUpdateCallback(mHeadController);
|
||||
mActiveControllers.insert(std::make_pair(node, mHeadController));
|
||||
NodeMap::iterator found = mNodeMap.find("bip01 head");
|
||||
if (found != mNodeMap.end() && dynamic_cast<osg::MatrixTransform*>(found->second.get()))
|
||||
{
|
||||
osg::Node* node = found->second;
|
||||
mHeadController = new RotateController(mObjectRoot.get());
|
||||
node->addUpdateCallback(mHeadController);
|
||||
mActiveControllers.insert(std::make_pair(node, mHeadController));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -307,6 +307,9 @@ protected:
|
|||
|
||||
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:
|
||||
|
||||
Animation(const MWWorld::Ptr &ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem);
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
#include <osg/UserDataContainer>
|
||||
#include <osg/MatrixTransform>
|
||||
#include <osg/Depth>
|
||||
|
||||
#include <osgUtil/RenderBin>
|
||||
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
|
@ -28,6 +31,7 @@
|
|||
|
||||
#include "camera.hpp"
|
||||
#include "rotatecontroller.hpp"
|
||||
#include "renderbin.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -303,6 +307,50 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
|
|||
|
||||
mViewMode = viewMode;
|
||||
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()
|
||||
|
|
|
@ -81,6 +81,8 @@ private:
|
|||
void addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts,
|
||||
bool enchantedGlow=false, osg::Vec4f* glowColor=NULL);
|
||||
|
||||
virtual void setRenderBin();
|
||||
|
||||
osg::ref_ptr<NeckController> mFirstPersonNeckController;
|
||||
|
||||
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.
|
||||
/// Beware of RenderBin nesting, in most cases you will want to use setNestRenderBins(false).
|
||||
enum RenderBins
|
||||
{
|
||||
RenderBin_Sky = -1,
|
||||
RenderBin_Default = 0,
|
||||
RenderBin_Default = 0, // osg::StateSet::OPAQUE_BIN
|
||||
RenderBin_Water = 9,
|
||||
RenderBin_OcclusionQuery = 10,
|
||||
RenderBin_SunGlare = 11
|
||||
RenderBin_DepthSorted = 10, // osg::StateSet::TRANSPARENT_BIN
|
||||
RenderBin_OcclusionQuery = 11,
|
||||
RenderBin_FirstPerson = 12,
|
||||
RenderBin_SunGlare = 13
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -493,6 +493,8 @@ namespace MWRender
|
|||
texture->setInternalFormat(GL_RGB);
|
||||
texture->setTextureSize(w, h);
|
||||
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);
|
||||
|
||||
image->setDataType(GL_UNSIGNED_BYTE);
|
||||
|
|
|
@ -724,22 +724,30 @@ private:
|
|||
, mTimeOfDayFade(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)
|
||||
{
|
||||
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv);
|
||||
|
||||
float angleRadians = getAngleToSunInRadians(cv->getCurrentCamera());
|
||||
float angleRadians = getAngleToSunInRadians(*cv->getCurrentRenderStage()->getInitialViewMatrix());
|
||||
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);
|
||||
|
||||
const float sunGlareFaderMax = 0.5f;
|
||||
float fade = value * sunGlareFaderMax;
|
||||
float fade = value * mSunGlareFaderMax;
|
||||
|
||||
fade *= mTimeOfDayFade * mGlareView * visibleRatio;
|
||||
|
||||
|
@ -754,17 +762,8 @@ private:
|
|||
|
||||
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->setEmission(osg::Material::FRONT_AND_BACK, sunGlareFaderColor);
|
||||
mat->setEmission(osg::Material::FRONT_AND_BACK, mColor);
|
||||
|
||||
stateset->setAttributeAndModes(mat, osg::StateAttribute::ON);
|
||||
|
||||
|
@ -785,10 +784,10 @@ private:
|
|||
}
|
||||
|
||||
private:
|
||||
float getAngleToSunInRadians(osg::Camera* camera) const
|
||||
float getAngleToSunInRadians(const osg::Matrix& viewMatrix) const
|
||||
{
|
||||
osg::Vec3d eye, center, up;
|
||||
camera->getViewMatrixAsLookAt(eye, center, up);
|
||||
viewMatrix.getLookAt(eye, center, up);
|
||||
|
||||
osg::Vec3d forward = center - eye;
|
||||
osg::Vec3d sun = mSunTransform->getPosition();
|
||||
|
@ -802,6 +801,9 @@ private:
|
|||
osg::ref_ptr<osg::PositionAttitudeTransform> mSunTransform;
|
||||
float mTimeOfDayFade;
|
||||
float mGlareView;
|
||||
osg::Vec4f mColor;
|
||||
float mSunGlareFaderMax;
|
||||
float mSunGlareFaderAngleMax;
|
||||
};
|
||||
|
||||
osg::ref_ptr<Updater> mUpdater;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/manualref.hpp"
|
||||
|
||||
namespace MWScript
|
||||
{
|
||||
|
@ -42,9 +43,9 @@ namespace MWScript
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -82,7 +83,8 @@ namespace MWScript
|
|||
store.get<ESM::Probe>().search (name) ||
|
||||
store.get<ESM::Repair>().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
|
||||
|
|
|
@ -140,7 +140,11 @@ void MWWorld::ContainerStore::unstack(const Ptr &ptr, const Ptr& container)
|
|||
{
|
||||
if (ptr.getRefData().getCount() <= 1)
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -411,41 +415,48 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::
|
|||
void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner,
|
||||
int count, bool topLevel, const std::string& levItem)
|
||||
{
|
||||
ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count);
|
||||
try {
|
||||
ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count);
|
||||
|
||||
if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name())
|
||||
{
|
||||
const ESM::ItemLevList* levItem = ref.getPtr().get<ESM::ItemLevList>()->mBase;
|
||||
|
||||
if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each)
|
||||
if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name())
|
||||
{
|
||||
for (int i=0; i<std::abs(count); ++i)
|
||||
addInitialItem(id, owner, count > 0 ? 1 : -1, true, levItem->mId);
|
||||
return;
|
||||
const ESM::ItemLevList* levItem = ref.getPtr().get<ESM::ItemLevList>()->mBase;
|
||||
|
||||
if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each)
|
||||
{
|
||||
for (int i=0; i<std::abs(count); ++i)
|
||||
addInitialItem(id, owner, count > 0 ? 1 : -1, true, levItem->mId);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string id = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false);
|
||||
if (id.empty())
|
||||
return;
|
||||
addInitialItem(id, owner, count, false, levItem->mId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string id = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false);
|
||||
if (id.empty())
|
||||
return;
|
||||
addInitialItem(id, owner, count, false, levItem->mId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// A negative count indicates restocking items
|
||||
// For a restocking levelled item, remember what we spawned so we can delete it later when the merchant restocks
|
||||
if (!levItem.empty() && count < 0)
|
||||
{
|
||||
if (mLevelledItemMap.find(id) == mLevelledItemMap.end())
|
||||
mLevelledItemMap[id] = 0;
|
||||
mLevelledItemMap[id] += std::abs(count);
|
||||
}
|
||||
count = std::abs(count);
|
||||
// A negative count indicates restocking items
|
||||
// For a restocking levelled item, remember what we spawned so we can delete it later when the merchant restocks
|
||||
if (!levItem.empty() && count < 0)
|
||||
{
|
||||
if (mLevelledItemMap.find(id) == mLevelledItemMap.end())
|
||||
mLevelledItemMap[id] = 0;
|
||||
mLevelledItemMap[id] += std::abs(count);
|
||||
}
|
||||
count = std::abs(count);
|
||||
|
||||
ref.getPtr().getCellRef().setOwner(owner);
|
||||
addImp (ref.getPtr(), count);
|
||||
ref.getPtr().getCellRef().setOwner(owner);
|
||||
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)
|
||||
|
|
|
@ -645,8 +645,15 @@ void MWWorld::InventoryStore::updateRechargingItems()
|
|||
{
|
||||
if (it->getClass().getEnchantment(*it) != "")
|
||||
{
|
||||
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(
|
||||
it->getClass().getEnchantment(*it));
|
||||
std::string enchantmentId = 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
|
||||
|| enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
||||
mRechargingItems.push_back(std::make_pair(it, static_cast<float>(enchantment->mData.mCharge)));
|
||||
|
|
|
@ -1029,7 +1029,8 @@ namespace MWWorld
|
|||
// 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;
|
||||
scpt.load(esm);
|
||||
Misc::StringUtils::toLower(scpt.mId);
|
||||
|
@ -1045,7 +1046,8 @@ namespace MWWorld
|
|||
// 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;
|
||||
s.load(esm);
|
||||
|
|
|
@ -204,6 +204,10 @@ namespace MWWorld
|
|||
mLevitationEnabled = true;
|
||||
mTeleportEnabled = true;
|
||||
|
||||
mGodMode = false;
|
||||
mScriptsEnabled = true;
|
||||
mSky = true;
|
||||
|
||||
// Rebuild player
|
||||
setupPlayer();
|
||||
|
||||
|
@ -297,9 +301,6 @@ namespace MWWorld
|
|||
|
||||
mDoorStates.clear();
|
||||
|
||||
mGodMode = false;
|
||||
mScriptsEnabled = true;
|
||||
mSky = true;
|
||||
mTeleportEnabled = true;
|
||||
mLevitationEnabled = true;
|
||||
|
||||
|
@ -2659,10 +2660,6 @@ namespace MWWorld
|
|||
{
|
||||
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);
|
||||
}
|
||||
else if (actor.getClass().hasInventoryStore(actor))
|
||||
|
|
|
@ -652,6 +652,13 @@ namespace Compiler
|
|||
return true;
|
||||
}
|
||||
|
||||
if (code ==Scanner::S_plus && mNextOperand)
|
||||
{
|
||||
// Also unary, but +, just ignore it
|
||||
mTokenLoc = loc;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (code==Scanner::S_open)
|
||||
{
|
||||
if (mNextOperand)
|
||||
|
|
|
@ -179,7 +179,7 @@ namespace Compiler
|
|||
extensions.registerInstruction ("setjournalindex", "cl", opcodeSetJournalIndex);
|
||||
extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex);
|
||||
extensions.registerInstruction ("addtopic", "S" , opcodeAddTopic);
|
||||
extensions.registerInstruction ("choice", "j/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice);
|
||||
extensions.registerInstruction ("choice", "j/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice);
|
||||
extensions.registerInstruction("forcegreeting","",opcodeForceGreeting,
|
||||
opcodeForceGreetingExplicit);
|
||||
extensions.registerInstruction("goodbye", "", opcodeGoodbye);
|
||||
|
|
|
@ -555,7 +555,7 @@ namespace Compiler
|
|||
}
|
||||
|
||||
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);
|
||||
parseExpression (scanner, loc);
|
||||
|
|
|
@ -175,7 +175,7 @@ namespace Compiler
|
|||
{
|
||||
value += c;
|
||||
}
|
||||
else if (isStringCharacter (c))
|
||||
else if (c!='-' && isStringCharacter (c))
|
||||
{
|
||||
error = true;
|
||||
value += c;
|
||||
|
|
|
@ -132,7 +132,34 @@ namespace Interpreter
|
|||
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()
|
||||
|
@ -202,19 +229,29 @@ namespace Interpreter
|
|||
{
|
||||
assert (codeSize>=4);
|
||||
|
||||
mRuntime.configure (code, codeSize, context);
|
||||
begin();
|
||||
|
||||
int opcodes = static_cast<int> (code[0]);
|
||||
|
||||
const Type_Code *codeBlock = code + 4;
|
||||
|
||||
while (mRuntime.getPC()>=0 && mRuntime.getPC()<opcodes)
|
||||
try
|
||||
{
|
||||
Type_Code code = codeBlock[mRuntime.getPC()];
|
||||
mRuntime.setPC (mRuntime.getPC()+1);
|
||||
execute (code);
|
||||
mRuntime.configure (code, codeSize, context);
|
||||
|
||||
int opcodes = static_cast<int> (code[0]);
|
||||
|
||||
const Type_Code *codeBlock = code + 4;
|
||||
|
||||
while (mRuntime.getPC()>=0 && mRuntime.getPC()<opcodes)
|
||||
{
|
||||
Type_Code code = codeBlock[mRuntime.getPC()];
|
||||
mRuntime.setPC (mRuntime.getPC()+1);
|
||||
execute (code);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
end();
|
||||
throw;
|
||||
}
|
||||
|
||||
mRuntime.clear();
|
||||
end();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define INTERPRETER_INTERPRETER_H_INCLUDED
|
||||
|
||||
#include <map>
|
||||
#include <stack>
|
||||
|
||||
#include "runtime.hpp"
|
||||
#include "types.hpp"
|
||||
|
@ -14,6 +15,8 @@ namespace Interpreter
|
|||
|
||||
class Interpreter
|
||||
{
|
||||
std::stack<Runtime> mCallstack;
|
||||
bool mRunning;
|
||||
Runtime mRuntime;
|
||||
std::map<int, Opcode1 *> mSegment0;
|
||||
std::map<int, Opcode2 *> mSegment1;
|
||||
|
@ -32,6 +35,10 @@ namespace Interpreter
|
|||
|
||||
void abortUnknownSegment (Type_Code code);
|
||||
|
||||
void begin();
|
||||
|
||||
void end();
|
||||
|
||||
public:
|
||||
|
||||
Interpreter();
|
||||
|
|
|
@ -57,8 +57,8 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
// Collect all properties affecting the given node that should be applied to an osg::Material.
|
||||
void collectMaterialProperties(const Nif::Node* nifNode, std::vector<const Nif::Property*>& out)
|
||||
// Collect all properties affecting the given drawable that should be handled on drawable basis rather than on the node hierarchy above it.
|
||||
void collectDrawableProperties(const Nif::Node* nifNode, std::vector<const Nif::Property*>& out)
|
||||
{
|
||||
const Nif::PropertyList& props = nifNode->props;
|
||||
for (size_t i = 0; i <props.length();++i)
|
||||
|
@ -70,6 +70,7 @@ namespace
|
|||
case Nif::RC_NiMaterialProperty:
|
||||
case Nif::RC_NiVertexColorProperty:
|
||||
case Nif::RC_NiSpecularProperty:
|
||||
case Nif::RC_NiAlphaProperty:
|
||||
out.push_back(props[i].getPtr());
|
||||
break;
|
||||
default:
|
||||
|
@ -78,7 +79,7 @@ namespace
|
|||
}
|
||||
}
|
||||
if (nifNode->parent)
|
||||
collectMaterialProperties(nifNode->parent, out);
|
||||
collectDrawableProperties(nifNode->parent, out);
|
||||
}
|
||||
|
||||
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
|
||||
// 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
|
||||
{
|
||||
public:
|
||||
|
@ -160,24 +162,34 @@ namespace
|
|||
struct UpdateMorphGeometry : public osg::Drawable::CullCallback
|
||||
{
|
||||
UpdateMorphGeometry()
|
||||
: mLastFrameNumber(0)
|
||||
{
|
||||
}
|
||||
|
||||
UpdateMorphGeometry(const UpdateMorphGeometry& copy, const osg::CopyOp& copyop)
|
||||
: osg::Drawable::CullCallback(copy, copyop)
|
||||
, mLastFrameNumber(0)
|
||||
{
|
||||
}
|
||||
|
||||
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);
|
||||
if (!geom)
|
||||
return false;
|
||||
|
||||
if (mLastFrameNumber == nv->getFrameStamp()->getFrameNumber())
|
||||
return false;
|
||||
mLastFrameNumber = nv->getFrameStamp()->getFrameNumber();
|
||||
|
||||
geom->transformSoftwareMethod();
|
||||
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
|
||||
|
@ -861,9 +873,9 @@ namespace NifOsg
|
|||
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
|
||||
geode->addDrawable(partsys);
|
||||
|
||||
std::vector<const Nif::Property*> materialProps;
|
||||
collectMaterialProperties(nifNode, materialProps);
|
||||
applyMaterialProperties(parentNode, materialProps, composite, true, animflags);
|
||||
std::vector<const Nif::Property*> drawableProps;
|
||||
collectDrawableProperties(nifNode, drawableProps);
|
||||
applyDrawableProperties(parentNode, drawableProps, composite, true, animflags);
|
||||
|
||||
// Particles don't have normals, so can't be diffuse lit.
|
||||
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.
|
||||
// - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them
|
||||
// above the actual renderable would be tedious.
|
||||
std::vector<const Nif::Property*> materialProps;
|
||||
collectMaterialProperties(triShape, materialProps);
|
||||
applyMaterialProperties(parentNode, materialProps, composite, !data->colors->empty(), animflags);
|
||||
std::vector<const Nif::Property*> drawableProps;
|
||||
collectDrawableProperties(triShape, drawableProps);
|
||||
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)
|
||||
|
@ -1212,42 +1224,12 @@ namespace NifOsg
|
|||
case Nif::RC_NiVertexColorProperty:
|
||||
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;
|
||||
}
|
||||
case Nif::RC_NiAlphaProperty:
|
||||
{
|
||||
const Nif::NiAlphaProperty* alphaprop = static_cast<const Nif::NiAlphaProperty*>(property);
|
||||
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);
|
||||
// Handled on drawable level to prevent RenderBin nesting issues
|
||||
break;
|
||||
}
|
||||
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)
|
||||
{
|
||||
osg::StateSet* stateset = node->getOrCreateStateSet();
|
||||
|
@ -1433,6 +1415,43 @@ namespace NifOsg
|
|||
mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||
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;
|
||||
};
|
||||
|
||||
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.
|
||||
// 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
|
||||
|
@ -82,14 +92,8 @@ namespace SceneUtil
|
|||
{
|
||||
if (!mLightManager)
|
||||
{
|
||||
for (unsigned int i=0;i<nv->getNodePath().size(); ++i)
|
||||
{
|
||||
if (LightManager* lightManager = dynamic_cast<LightManager*>(nv->getNodePath()[i]))
|
||||
{
|
||||
mLightManager = lightManager;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mLightManager = findLightManager(nv->getNodePath());
|
||||
|
||||
if (!mLightManager)
|
||||
throw std::runtime_error("can't find parent LightManager");
|
||||
}
|
||||
|
@ -126,15 +130,13 @@ namespace SceneUtil
|
|||
};
|
||||
|
||||
LightManager::LightManager()
|
||||
: mLightsInViewSpace(false)
|
||||
, mStartLight(0)
|
||||
: mStartLight(0)
|
||||
{
|
||||
setUpdateCallback(new LightManagerUpdateCallback);
|
||||
}
|
||||
|
||||
LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op)
|
||||
: osg::Group(copy, copyop)
|
||||
, mLightsInViewSpace(false)
|
||||
, mStartLight(copy.mStartLight)
|
||||
{
|
||||
|
||||
|
@ -142,8 +144,8 @@ namespace SceneUtil
|
|||
|
||||
void LightManager::update()
|
||||
{
|
||||
mLightsInViewSpace = false;
|
||||
mLights.clear();
|
||||
mLightsInViewSpace.clear();
|
||||
|
||||
// do an occasional cleanup for orphaned lights
|
||||
if (mStateSetCache.size() > 5000)
|
||||
|
@ -161,22 +163,6 @@ namespace SceneUtil
|
|||
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)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -258,14 +268,7 @@ namespace SceneUtil
|
|||
|
||||
if (!mLightManager)
|
||||
{
|
||||
for (unsigned int i=0;i<nv->getNodePath().size(); ++i)
|
||||
{
|
||||
if (LightManager* lightManager = dynamic_cast<LightManager*>(nv->getNodePath()[i]))
|
||||
{
|
||||
mLightManager = lightManager;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mLightManager = findLightManager(nv->getNodePath());
|
||||
if (!mLightManager)
|
||||
{
|
||||
traverse(node, nv);
|
||||
|
@ -273,13 +276,14 @@ namespace SceneUtil
|
|||
}
|
||||
}
|
||||
|
||||
mLightManager->prepareForCamera(cv->getCurrentCamera());
|
||||
|
||||
// Possible optimizations:
|
||||
// - cull list of lights by the camera frustum
|
||||
// - 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())
|
||||
{
|
||||
|
@ -288,10 +292,10 @@ namespace SceneUtil
|
|||
osg::Matrixf mat = *cv->getModelViewMatrix();
|
||||
transformBoundingSphere(mat, nodeBound);
|
||||
|
||||
std::vector<const LightManager::LightSourceTransform*> lightList;
|
||||
LightManager::LightList lightList;
|
||||
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))
|
||||
lightList.push_back(&l);
|
||||
}
|
||||
|
|
|
@ -74,18 +74,23 @@ namespace SceneUtil
|
|||
// Called automatically by the LightSource's UpdateCallback
|
||||
void addLight(LightSource* lightSource, osg::Matrix worldMat);
|
||||
|
||||
void prepareForCamera(osg::Camera* cam);
|
||||
|
||||
struct LightSourceTransform
|
||||
{
|
||||
LightSource* mLightSource;
|
||||
osg::Matrix mWorldMatrix;
|
||||
osg::BoundingSphere mViewBound;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
|
@ -98,7 +103,8 @@ namespace SceneUtil
|
|||
// Lights collected from the scene graph. Only valid during the cull traversal.
|
||||
std::vector<LightSourceTransform> mLights;
|
||||
|
||||
bool mLightsInViewSpace;
|
||||
typedef std::vector<LightSourceViewBound> LightSourceViewBoundCollection;
|
||||
std::map<osg::observer_ptr<osg::Camera>, LightSourceViewBoundCollection> mLightsInViewSpace;
|
||||
|
||||
// < Light list hash , StateSet >
|
||||
typedef std::map<size_t, osg::ref_ptr<osg::StateSet> > LightStateSetMap;
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
|
||||
RigGeometry::RigGeometry()
|
||||
: mSkeleton(NULL)
|
||||
, mFirstFrame(true)
|
||||
, mLastFrameNumber(0)
|
||||
, mBoundsFirstFrame(true)
|
||||
{
|
||||
setCullCallback(new UpdateRigGeometry);
|
||||
|
@ -72,7 +72,7 @@ RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op)
|
|||
: osg::Geometry(copy, copyop)
|
||||
, mSkeleton(NULL)
|
||||
, mInfluenceMap(copy.mInfluenceMap)
|
||||
, mFirstFrame(copy.mFirstFrame)
|
||||
, mLastFrameNumber(0)
|
||||
, mBoundsFirstFrame(copy.mBoundsFirstFrame)
|
||||
{
|
||||
setSourceGeometry(copy.mSourceGeometry);
|
||||
|
@ -206,9 +206,12 @@ void RigGeometry::update(osg::NodeVisitor* nv)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!mSkeleton->getActive() && !mFirstFrame)
|
||||
if (!mSkeleton->getActive() && mLastFrameNumber != 0)
|
||||
return;
|
||||
mFirstFrame = false;
|
||||
|
||||
if (mLastFrameNumber == nv->getFrameStamp()->getFrameNumber())
|
||||
return;
|
||||
mLastFrameNumber = nv->getFrameStamp()->getFrameNumber();
|
||||
|
||||
mSkeleton->updateBoneMatrices(nv);
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace SceneUtil
|
|||
|
||||
BoneSphereMap mBoneSphereMap;
|
||||
|
||||
bool mFirstFrame;
|
||||
unsigned int mLastFrameNumber;
|
||||
bool mBoundsFirstFrame;
|
||||
|
||||
bool initFromParentSkeleton(osg::NodeVisitor* nv);
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
</Widget>
|
||||
<Widget type="MWScrollBar" skin="MW_HScroll" position="7 61 578 18" align="Left Top HStretch" name="CountSlider">
|
||||
<Property key="MoveToClick" value="true"/>
|
||||
<Property key="Page" value="1"/>
|
||||
<Property key="WheelPage" value="1"/>
|
||||
</Widget>
|
||||
<Widget type="HBox" skin="" position="0 88 585 24" align="Right Bottom">
|
||||
<Widget type="Widget" skin="" position="0 12 0 0">
|
||||
|
|
Loading…
Reference in a new issue