From cf0c71c6511b2a66dfe3335e2c21929ade49e500 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 30 Aug 2019 22:01:03 +0300 Subject: [PATCH 01/24] Water shader cleanup --- files/shaders/water_fragment.glsl | 101 +++++++++--------------------- files/shaders/water_vertex.glsl | 2 +- 2 files changed, 31 insertions(+), 72 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index cc211a3d64..2ad4ddeb6b 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -48,11 +48,6 @@ const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745); const float RAIN_RIPPLE_GAPS = 5.0; const float RAIN_RIPPLE_RADIUS = 0.1; -int modulo(int v1, int v2) -{ - return v1 - v2 * int(floor(float(v1) / float(v2))); -} - vec2 randOffset(vec2 c) { return fract(vec2( @@ -170,8 +165,6 @@ void main(void) vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1.0-screenCoords.y); - vec2 nCoord = vec2(0.0); - #define waterTimer osg_SimulationTime vec3 normal0 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.05, 0.04, waterTimer, -0.015, -0.005, vec3(0.0,0.0,0.0))).rgb - 1.0; @@ -195,100 +188,66 @@ void main(void) vec2 smallWaves = mix(vec2(SMALL_WAVES_X,SMALL_WAVES_Y),vec2(SMALL_WAVES_RAIN_X,SMALL_WAVES_RAIN_Y),rainIntensity); float bump = mix(BUMP,BUMP_RAIN,rainIntensity); - vec3 normal = (normal0 * bigWaves.x + normal1 * bigWaves.y + - normal2 * midWaves.x + normal3 * midWaves.y + - normal4 * smallWaves.x + normal5 * smallWaves.y + - rippleAdd); - - normal = normalize(vec3(normal.x * bump, normal.y * bump, normal.z)); - - normal = vec3(-normal.x, -normal.y, normal.z); - - // normal for sunlight scattering - vec3 lNormal = (normal0 * bigWaves.x * 0.5 + normal1 * bigWaves.y * 0.5 + - normal2 * midWaves.x * 0.2 + normal3 * midWaves.y * 0.2 + - normal4 * smallWaves.x * 0.1 + normal5 * smallWaves.y * 0.1 + - rippleAdd).xyz; - - lNormal = normalize(vec3(lNormal.x * bump, lNormal.y * bump, lNormal.z)); - lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z); + vec3 normal = (normal0 * bigWaves.x + normal1 * bigWaves.y + normal2 * midWaves.x + + normal3 * midWaves.y + normal4 * smallWaves.x + normal5 * smallWaves.y + rippleAdd); + normal = normalize(vec3(-normal.x * bump, -normal.y * bump, normal.z)); vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(gl_LightSource[0].position.xyz, 0.0)).xyz); vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz; vec3 vVec = normalize(position.xyz - cameraPos.xyz); - float isUnderwater = (cameraPos.z > 0.0) ? 0.0 : 1.0; - - // sunlight scattering - vec3 pNormal = vec3(0,0,1); - vec3 lR = reflect(lVec, lNormal); - vec3 llR = reflect(lVec, pNormal); - - float sunHeight = lVec.z; float sunFade = length(gl_LightModel.ambient.xyz); - float s = clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0); - float lightScatter = shadow * clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * s * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0); - vec3 scatterColour = mix(vec3(SCATTER_COLOUR)*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); - // fresnel float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); // air to water; water to air - float fresnel = fresnel_dielectric(vVec, normal, ior); - - fresnel = clamp(fresnel, 0.0, 1.0); + float fresnel = clamp(fresnel_dielectric(vVec, normal, ior), 0.0, 1.0); + vec2 screenCoordsOffset = normal.xy * REFL_BUMP; #if REFRACTION float depthSample = linearizeDepth(texture2D(refractionDepthMap,screenCoords).x); - float depthSampleDistorted = linearizeDepth(texture2D(refractionDepthMap,screenCoords-(normal.xy*REFR_BUMP)).x); + float depthSampleDistorted = linearizeDepth(texture2D(refractionDepthMap,screenCoords-screenCoordsOffset).x); float surfaceDepth = linearizeDepth(gl_FragCoord.z); float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum - float shore = clamp(realWaterDepth / BUMP_SUPPRESS_DEPTH,0,1); -#else - float shore = 1.0; + screenCoordsOffset *= clamp(realWaterDepth / BUMP_SUPPRESS_DEPTH,0,1); #endif - vec2 screenCoordsOffset = normal.xy * REFL_BUMP * shore; - // reflection vec3 reflection = texture2D(reflectionMap, screenCoords + screenCoordsOffset).rgb; - // refraction + // specular + float specular = pow(max(dot(reflect(vVec, normal), lVec), 0.0),SPEC_HARDNESS) * shadow; + + vec3 waterColor = WATER_COLOR * sunFade; + #if REFRACTION + // refraction vec3 refraction = texture2D(refractionMap, screenCoords - screenCoordsOffset).rgb; // brighten up the refraction underwater - refraction = (cameraPos.z < 0.0) ? clamp(refraction * 1.5, 0.0, 1.0) : refraction; -#endif - // specular - vec3 R = reflect(vVec, normal); - float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; - - vec3 waterColor = WATER_COLOR; - waterColor = waterColor * length(gl_LightModel.ambient.xyz); - -#if REFRACTION - if (cameraPos.z > 0.0) + if (cameraPos.z < 0.0) + refraction = clamp(refraction * 1.5, 0.0, 1.0); + else refraction = mix(refraction, waterColor, clamp(depthSampleDistorted/VISIBILITY, 0.0, 1.0)); - gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * gl_LightSource[0].specular.xyz; + // sunlight scattering + // normal for sunlight scattering + vec3 lNormal = (normal0 * bigWaves.x * 0.5 + normal1 * bigWaves.y * 0.5 + normal2 * midWaves.x * 0.2 + + normal3 * midWaves.y * 0.2 + normal4 * smallWaves.x * 0.1 + normal5 * smallWaves.y * 0.1 + rippleAdd); + lNormal = normalize(vec3(-lNormal.x * bump, -lNormal.y * bump, lNormal.z)); + float sunHeight = lVec.z; + vec3 scatterColour = mix(SCATTER_COLOUR*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); + vec3 lR = reflect(lVec, lNormal); + float lightScatter = shadow * clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0) * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0); + gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * gl_LightSource[0].specular.xyz + vec3(rainRipple.w) * 0.2; + gl_FragData[0].w = 1.0; #else - gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * gl_LightSource[0].specular.xyz; + gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * gl_LightSource[0].specular.xyz + vec3(rainRipple.w) * 0.7; + gl_FragData[0].w = clamp(fresnel*6.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0); //clamp(fresnel*2.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0); #endif + // fog float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); -#if REFRACTION - gl_FragData[0].xyz += vec3(rainRipple.w) * 0.2; -#else - gl_FragData[0].xyz += vec3(rainRipple.w) * 0.7; -#endif - -#if REFRACTION - gl_FragData[0].w = 1.0; -#else - gl_FragData[0].w = clamp(fresnel*6.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0); //clamp(fresnel*2.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0); -#endif - applyShadowDebugOverlay(); } diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index 575f8f3c2f..2377f0af4b 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -16,7 +16,7 @@ void main(void) 0.5, 0.5, 0.5, 1.0); vec4 texcoordProj = ((scalemat) * ( gl_Position)); - screenCoordsPassthrough = vec3(texcoordProj.x, texcoordProj.y, texcoordProj.w); + screenCoordsPassthrough = texcoordProj.xyw; position = gl_Vertex; From d6722c74928d960fb45b14a25b8f6c54bd87133e Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 7 Apr 2019 11:10:02 +0300 Subject: [PATCH 02/24] Terrain texture selection, support for vertex selection --- CHANGELOG.md | 1 + apps/opencs/CMakeLists.txt | 2 +- .../view/render/pagedworldspacewidget.cpp | 2 +- apps/opencs/view/render/terrainselection.cpp | 271 ++++++++++++++++ apps/opencs/view/render/terrainselection.hpp | 75 +++++ .../opencs/view/render/terraintexturemode.cpp | 288 ++++++++++++++---- .../opencs/view/render/terraintexturemode.hpp | 25 +- 7 files changed, 610 insertions(+), 54 deletions(-) create mode 100644 apps/opencs/view/render/terrainselection.cpp create mode 100644 apps/opencs/view/render/terrainselection.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index fa84ec10ae..f8beb82cbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -143,6 +143,7 @@ Feature #3025: Analogue gamepad movement controls Feature #3442: Default values for fallbacks from ini file Feature #3610: Option to invert X axis + Feature #3871: Editor: Terrain Selection Feature #3893: Implicit target for "set" function in console Feature #3980: In-game option to disable controller Feature #3999: Shift + Double Click should maximize/restore menu size diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index b0bd95eb95..00855dad0c 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -89,7 +89,7 @@ opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget previewwidget editmode instancemode instanceselectionmode instancemovemode orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller - cellwater terraintexturemode actor + cellwater terraintexturemode actor terrainselection ) opencs_units_noqt (view/render diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 7f31373ee8..540a15dd10 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -140,7 +140,7 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain shape editing"), "terrain-shape"); tool->addButton ( - new TerrainTextureMode (this, tool), + new TerrainTextureMode (this, mRootNode, tool), "terrain-texture"); tool->addButton ( new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain vertex paint editing"), diff --git a/apps/opencs/view/render/terrainselection.cpp b/apps/opencs/view/render/terrainselection.cpp new file mode 100644 index 0000000000..5725a35c08 --- /dev/null +++ b/apps/opencs/view/render/terrainselection.cpp @@ -0,0 +1,271 @@ +#include "terrainselection.hpp" + +#include + +#include +#include +#include + +#include + +#include "../../model/world/cellcoordinates.hpp" +#include "../../model/world/columnimp.hpp" +#include "../../model/world/idtable.hpp" + +#include "cell.hpp" +#include "worldspacewidget.hpp" + +namespace +{ + const int cellSize {ESM::Land::REAL_SIZE}; + const int landSize {ESM::Land::LAND_SIZE}; + const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE}; +} + +CSVRender::TerrainSelection::TerrainSelection(osg::Group* parentNode, WorldspaceWidget *worldspaceWidget, TerrainSelectionType type): +mParentNode(parentNode), mWorldspaceWidget (worldspaceWidget), mDraggedOperationFlag(false), mSelectionType(type) +{ + mGeometry = new osg::Geometry(); + + mSelectionNode = new osg::Group(); + mSelectionNode->addChild(mGeometry); + + activate(); +} + +CSVRender::TerrainSelection::~TerrainSelection() +{ + deactivate(); +} + +std::vector> CSVRender::TerrainSelection::getTerrainSelection() const +{ + return mSelection; +} + +void CSVRender::TerrainSelection::onlySelect(const std::vector> localPositions) +{ + mSelection.clear(); + for(auto const& value: localPositions) + { + mSelection.emplace_back(value); + } + update(); +} + +void CSVRender::TerrainSelection::addSelect(const std::pair localPos) +{ + if (std::find(mSelection.begin(), mSelection.end(), localPos) == mSelection.end()) + mSelection.emplace_back(localPos); + update(); +} + +void CSVRender::TerrainSelection::toggleSelect(const std::vector> localPositions, bool toggleInProgress) +{ + if (toggleInProgress == true) + { + for(auto const& localPos: localPositions) + { + auto iter = std::find(mSelection.begin(), mSelection.end(), localPos); + auto itertemp = std::find(mTemporarySelection.begin(), mTemporarySelection.end(), localPos); + mDraggedOperationFlag = true; + + if (itertemp == mTemporarySelection.end()) + { + if (iter != mSelection.end()) + { + mSelection.erase(iter); + } + else + { + mSelection.emplace_back(localPos); + } + } + + mTemporarySelection.push_back(localPos); + } + } + else if (mDraggedOperationFlag == false) + { + for(auto const& localPos: localPositions) + { + const auto iter = std::find(mSelection.begin(), mSelection.end(), localPos); + if (iter != mSelection.end()) + { + mSelection.erase(iter); + } + else + { + mSelection.emplace_back(localPos); + } + } + } + else + { + mDraggedOperationFlag = false; + mTemporarySelection.clear(); + } + update(); +} + +void CSVRender::TerrainSelection::activate() +{ + mParentNode->addChild(mSelectionNode); +} + +void CSVRender::TerrainSelection::deactivate() +{ + mParentNode->removeChild(mSelectionNode); +} + +void CSVRender::TerrainSelection::update() +{ + mSelectionNode->removeChild(mGeometry); + mGeometry = new osg::Geometry(); + + const osg::ref_ptr vertices (new osg::Vec3Array); + + switch (mSelectionType) + { + case TerrainSelectionType::Texture : drawTextureSelection(vertices); + break; + case TerrainSelectionType::Shape : drawShapeSelection(vertices); + break; + } + + mGeometry->setVertexArray(vertices); + osg::ref_ptr drawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES); + drawArrays->setCount(vertices->size()); + mGeometry->addPrimitiveSet(drawArrays); + mSelectionNode->addChild(mGeometry); +} + +void CSVRender::TerrainSelection::drawShapeSelection(const osg::ref_ptr vertices) +{ + if (!mSelection.empty()) + { + for (std::pair localPos : mSelection) + { + int x (localPos.first); + int y (localPos.second); + + float xWorldCoord(CSMWorld::CellCoordinates::vertexSelectionToWorldCoords(x)); + float yWorldCoord(CSMWorld::CellCoordinates::vertexSelectionToWorldCoords(y)); + + osg::Vec3f pointXY(xWorldCoord, yWorldCoord, calculateLandHeight(x, y) + 2); + + vertices->push_back(pointXY); + vertices->push_back(osg::Vec3f(xWorldCoord, CSMWorld::CellCoordinates::vertexSelectionToWorldCoords(y - 1), calculateLandHeight(x, y - 1) + 2)); + vertices->push_back(pointXY); + vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::vertexSelectionToWorldCoords(x - 1), yWorldCoord, calculateLandHeight(x - 1, y) + 2)); + + const auto north = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x, y + 1)); + if (north == mSelection.end()) + { + vertices->push_back(pointXY); + vertices->push_back(osg::Vec3f(xWorldCoord, CSMWorld::CellCoordinates::vertexSelectionToWorldCoords(y + 1), calculateLandHeight(x, y + 1) + 2)); + } + + const auto east = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x + 1, y)); + if (east == mSelection.end()) + { + vertices->push_back(pointXY); + vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::vertexSelectionToWorldCoords(x + 1), yWorldCoord, calculateLandHeight(x + 1, y) + 2)); + } + } + } +} + +void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptr vertices) +{ + if (!mSelection.empty()) + { + + // Nudge selection by 1/4th of a texture size, similar how blendmaps are nudged + const float nudgePercentage = 0.25f; + const int nudgeOffset = (cellSize / landTextureSize) * nudgePercentage; + const int landHeightsNudge = (cellSize / landSize) / (landSize - 1); // Does this work with all land size configurations? + + const int textureSizeToLandSizeModifier = (landSize - 1) / landTextureSize; + + for (std::pair localPos : mSelection) + { + int x (localPos.first); + int y (localPos.second); + + // convert texture selection to global vertex coordinates at selection box corners + int x1 = x * textureSizeToLandSizeModifier + landHeightsNudge; + int x2 = x * textureSizeToLandSizeModifier + textureSizeToLandSizeModifier + landHeightsNudge; + int y1 = y * textureSizeToLandSizeModifier - landHeightsNudge; + int y2 = y * textureSizeToLandSizeModifier + textureSizeToLandSizeModifier - landHeightsNudge; + + // Draw edges (check all sides, draw lines between vertices, +1 height to keep lines above ground) + // Check adjancent selections, draw lines only to edges of the selection + const auto north = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x, y + 1)); + if (north == mSelection.end()) + { + for(int i = 1; i < (textureSizeToLandSizeModifier + 1); i++) + { + float drawPreviousX = CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x)+(i-1)*(cellSize / (landSize - 1)); + float drawCurrentX = CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x)+i*(cellSize / (landSize - 1)); + vertices->push_back(osg::Vec3f(drawPreviousX + nudgeOffset, CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y + 1) - nudgeOffset, calculateLandHeight(x1+(i-1), y2)+2)); + vertices->push_back(osg::Vec3f(drawCurrentX + nudgeOffset, CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y + 1) - nudgeOffset, calculateLandHeight(x1+i, y2)+2)); + } + } + + const auto south = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x, y - 1)); + if (south == mSelection.end()) + { + for(int i = 1; i < (textureSizeToLandSizeModifier + 1); i++) + { + float drawPreviousX = CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x)+(i-1)*(cellSize / (landSize - 1)); + float drawCurrentX = CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x)+i*(cellSize / (landSize - 1)); + vertices->push_back(osg::Vec3f(drawPreviousX + nudgeOffset, CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y) - nudgeOffset, calculateLandHeight(x1+(i-1), y1)+2)); + vertices->push_back(osg::Vec3f(drawCurrentX + nudgeOffset, CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y) - nudgeOffset, calculateLandHeight(x1+i, y1)+2)); + } + } + + const auto east = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x + 1, y)); + if (east == mSelection.end()) + { + for(int i = 1; i < (textureSizeToLandSizeModifier + 1); i++) + { + float drawPreviousY = CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y)+(i-1)*(cellSize / (landSize - 1)); + float drawCurrentY = CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y)+i*(cellSize / (landSize - 1)); + vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x + 1) + nudgeOffset, drawPreviousY - nudgeOffset, calculateLandHeight(x2, y1+(i-1))+2)); + vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x + 1) + nudgeOffset, drawCurrentY - nudgeOffset, calculateLandHeight(x2, y1+i)+2)); + } + } + + const auto west = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x - 1, y)); + if (west == mSelection.end()) + { + for(int i = 1; i < (textureSizeToLandSizeModifier + 1); i++) + { + float drawPreviousY = CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y)+(i-1)*(cellSize / (landSize - 1)); + float drawCurrentY = CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y)+i*(cellSize / (landSize - 1)); + vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x) + nudgeOffset, drawPreviousY - nudgeOffset, calculateLandHeight(x1, y1+(i-1))+2)); + vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x) + nudgeOffset, drawCurrentY - nudgeOffset, calculateLandHeight(x1, y1+i)+2)); + } + } + } + } +} + +int CSVRender::TerrainSelection::calculateLandHeight(int x, int y) // global vertex coordinates +{ + int cellX = std::floor((1.0f*x / (landSize - 1))); + int cellY = std::floor((1.0f*y / (landSize - 1))); + int localX = x - cellX * (landSize - 1); + int localY = y - cellY * (landSize - 1); + + std::string cellId = CSMWorld::CellCoordinates::generateId(cellX, cellY); + + CSMDoc::Document& document = mWorldspaceWidget->getDocument(); + CSMWorld::IdTable& landTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Land)); + int landshapeColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandHeightsIndex); + const CSMWorld::LandHeightsColumn::DataType mPointer = landTable.data(landTable.getModelIndex(cellId, landshapeColumn)).value(); + + return mPointer[localY*landSize + localX]; +} diff --git a/apps/opencs/view/render/terrainselection.hpp b/apps/opencs/view/render/terrainselection.hpp new file mode 100644 index 0000000000..02916fa937 --- /dev/null +++ b/apps/opencs/view/render/terrainselection.hpp @@ -0,0 +1,75 @@ +#ifndef CSV_RENDER_TERRAINSELECTION_H +#define CSV_RENDER_TERRAINSELECTION_H + +#include +#include + +#include +#include +#include + +#include +#include "../../model/world/cellcoordinates.hpp" + +namespace osg +{ + class Group; +} + +namespace CSVRender +{ + struct WorldspaceHitResult; + class WorldspaceWidget; + + enum class TerrainSelectionType + { + Texture, + Shape + }; + + /// \brief Class handling the terrain selection data and rendering + class TerrainSelection + { + + public: + + TerrainSelection(osg::Group* parentNode, WorldspaceWidget *worldspaceWidget, TerrainSelectionType type); + ~TerrainSelection(); + + void onlySelect(const std::vector> localPositions); + void addSelect(const std::pair localPos); + void toggleSelect(const std::vector> localPositions, bool); + + void activate(); + void deactivate(); + + std::vector> getTerrainSelection() const; + + protected: + + void addToSelection(osg::Vec3d worldPos); + void toggleSelection(osg::Vec3d worldPos); + void deselect(); + + void update(); + + void drawShapeSelection(const osg::ref_ptr vertices); + void drawTextureSelection(const osg::ref_ptr vertices); + + int calculateLandHeight(int x, int y); + + private: + + osg::Group* mParentNode; + WorldspaceWidget *mWorldspaceWidget; + osg::ref_ptr mBaseNode; + osg::ref_ptr mGeometry; + osg::ref_ptr mSelectionNode; + std::vector> mSelection; // Global terrain selection coordinate in either vertex or texture units + std::vector> mTemporarySelection; // Used during toggle to compare the most recent drag operation + bool mDraggedOperationFlag; //true during drag operation, false when click-operation + TerrainSelectionType mSelectionType; + }; +} + +#endif diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 4205188e40..82737e9283 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include #include "../widget/modebutton.hpp" @@ -34,14 +36,18 @@ #include "pagedworldspacewidget.hpp" #include "mask.hpp" #include "object.hpp" // Something small needed regarding pointers from here () +#include "terrainselection.hpp" #include "worldspacewidget.hpp" -CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) +CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, osg::Group* parentNode, QWidget *parent) : EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent), mBrushTexture("L0#0"), mBrushSize(0), mBrushShape(0), - mTextureBrushScenetool(0) + mTextureBrushScenetool(0), + mDragMode(InteractionType_None), + mParentNode(parentNode), + mIsEditing(false) { } @@ -62,6 +68,11 @@ void CSVRender::TerrainTextureMode::activate(CSVWidget::SceneToolbar* toolbar) connect(this, SIGNAL(passBrushTexture(std::string)), mTextureBrushScenetool, SLOT(updateBrushHistory(std::string))); } + if (!mTerrainTextureSelection) + { + mTerrainTextureSelection.reset(new TerrainSelection(mParentNode, &getWorldspaceWidget(), TerrainSelectionType::Texture)); + } + EditMode::activate(toolbar); toolbar->addTool (mTextureBrushScenetool); } @@ -74,6 +85,12 @@ void CSVRender::TerrainTextureMode::deactivate(CSVWidget::SceneToolbar* toolbar) delete mTextureBrushScenetool; mTextureBrushScenetool = 0; } + + if (mTerrainTextureSelection) + { + mTerrainTextureSelection.reset(); + } + EditMode::deactivate(toolbar); } @@ -95,7 +112,7 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); int index = landtexturesCollection.searchId(mBrushTexture); - if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit == true) + if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit && hit.tag == 0) { undoStack.beginMacro ("Edit texture records"); if(allowLandTextureEditing(mCellId)==true) @@ -109,10 +126,18 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult void CSVRender::TerrainTextureMode::primarySelectPressed(const WorldspaceHitResult& hit) { + if(hit.hit && hit.tag == 0) + { + selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 0, false); + } } void CSVRender::TerrainTextureMode::secondarySelectPressed(const WorldspaceHitResult& hit) { + if(hit.hit && hit.tag == 0) + { + selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 1, false); + } } bool CSVRender::TerrainTextureMode::primaryEditStartDrag (const QPoint& pos) @@ -129,13 +154,16 @@ bool CSVRender::TerrainTextureMode::primaryEditStartDrag (const QPoint& pos) QUndoStack& undoStack = document.getUndoStack(); + mDragMode = InteractionType_PrimaryEdit; + CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); int index = landtexturesCollection.searchId(mBrushTexture); - if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) + if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit && hit.tag == 0) { undoStack.beginMacro ("Edit texture records"); - if(allowLandTextureEditing(mCellId)==true && hit.hit == true) + mIsEditing = true; + if(allowLandTextureEditing(mCellId)==true) { undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); editTerrainTextureGrid(hit); @@ -152,47 +180,91 @@ bool CSVRender::TerrainTextureMode::secondaryEditStartDrag (const QPoint& pos) bool CSVRender::TerrainTextureMode::primarySelectStartDrag (const QPoint& pos) { + WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask()); + mDragMode = InteractionType_PrimarySelect; + if (!hit.hit || hit.tag != 0) + { + mDragMode = InteractionType_None; + return false; + } + selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 0, true); return false; } bool CSVRender::TerrainTextureMode::secondarySelectStartDrag (const QPoint& pos) { + WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask()); + mDragMode = InteractionType_SecondarySelect; + if (!hit.hit || hit.tag != 0) + { + mDragMode = InteractionType_None; + return false; + } + selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 1, true); return false; } void CSVRender::TerrainTextureMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor) { - WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask()); - CSMDoc::Document& document = getWorldspaceWidget().getDocument(); - - CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); - int index = landtexturesCollection.searchId(mBrushTexture); - - if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit == true) + if (mDragMode == InteractionType_PrimaryEdit) { - editTerrainTextureGrid(hit); + WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask()); + std::string cellId = getWorldspaceWidget().getCellId (hit.worldPos); + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + + CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); + int index = landtexturesCollection.searchId(mBrushTexture); + + if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit && hit.tag == 0) + { + editTerrainTextureGrid(hit); + } + } + + if (mDragMode == InteractionType_PrimarySelect) + { + WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask()); + if (hit.hit && hit.tag == 0) selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 0, true); + } + + if (mDragMode == InteractionType_SecondarySelect) + { + WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask()); + if (hit.hit && hit.tag == 0) selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 1, true); } } -void CSVRender::TerrainTextureMode::dragCompleted(const QPoint& pos) { - CSMDoc::Document& document = getWorldspaceWidget().getDocument(); - QUndoStack& undoStack = document.getUndoStack(); - - CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); - int index = landtexturesCollection.searchId(mBrushTexture); - - if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) +void CSVRender::TerrainTextureMode::dragCompleted(const QPoint& pos) +{ + if (mDragMode == InteractionType_PrimaryEdit) { - undoStack.endMacro(); + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + QUndoStack& undoStack = document.getUndoStack(); + + CSMWorld::IdCollection& landtexturesCollection = document.getData().getLandTextures(); + int index = landtexturesCollection.searchId(mBrushTexture); + + if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) + { + if (mIsEditing == true) + { + undoStack.endMacro(); + mIsEditing = false; + } + } } } -void CSVRender::TerrainTextureMode::dragAborted() { +void CSVRender::TerrainTextureMode::dragAborted() +{ } -void CSVRender::TerrainTextureMode::dragWheel (int diff, double speedFactor) {} +void CSVRender::TerrainTextureMode::dragWheel (int diff, double speedFactor) +{ +} -void CSVRender::TerrainTextureMode::handleDropEvent (QDropEvent *event) { +void CSVRender::TerrainTextureMode::handleDropEvent (QDropEvent *event) +{ const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped @@ -236,8 +308,8 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe int cellY = cellCoordinates_pair.first.getY(); // The coordinates of hit in mCellId - int xHitInCell (float(((hit.worldPos.x() - (cellX* cellSize)) * landTextureSize / cellSize) - 0.5)); - int yHitInCell (float(((hit.worldPos.y() - (cellY* cellSize)) * landTextureSize / cellSize) + 0.5)); + int xHitInCell (float(((hit.worldPos.x() - (cellX* cellSize)) * landTextureSize / cellSize) - 0.25)); + int yHitInCell (float(((hit.worldPos.y() - (cellY* cellSize)) * landTextureSize / cellSize) + 0.25)); if (xHitInCell < 0) { xHitInCell = xHitInCell + landTextureSize; @@ -249,7 +321,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe cellY = cellY + 1; } - mCellId = "#" + std::to_string(cellX) + " " + std::to_string(cellY); + mCellId = CSMWorld::CellCoordinates::generateId(cellX, cellY); if(allowLandTextureEditing(mCellId)==true) {} std::string iteratedCellId; @@ -266,13 +338,13 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe if (mBrushShape == 0) { - CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value(); - CSMWorld::LandTexturesColumn::DataType mNew(mPointer); + CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value(); + CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer); if(allowLandTextureEditing(mCellId)==true) { - mNew[yHitInCell*landTextureSize+xHitInCell] = brushInt; - pushEditToCommand(mNew, document, landTable, mCellId); + newTerrain[yHitInCell*landTextureSize+xHitInCell] = brushInt; + pushEditToCommand(newTerrain, document, landTable, mCellId); } } @@ -292,19 +364,19 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe { for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++) { - iteratedCellId = "#" + std::to_string(i_cell) + " " + std::to_string(j_cell); + iteratedCellId = CSMWorld::CellCoordinates::generateId(i_cell, j_cell); if(allowLandTextureEditing(iteratedCellId)==true) { - CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value(); - CSMWorld::LandTexturesColumn::DataType mNew(mPointer); + CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value(); + CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer); for(int i = 0; i < landTextureSize; i++) { for(int j = 0; j < landTextureSize; j++) { - if (i_cell == cellX && j_cell == cellY && abs(i-xHitInCell) < r && abs(j-yHitInCell) < r) + if (i_cell == cellX && j_cell == cellY && abs(i-xHitInCell) < r && abs(j-yHitInCell) < r) { - mNew[j*landTextureSize+i] = brushInt; + newTerrain[j*landTextureSize+i] = brushInt; } else { @@ -316,11 +388,11 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j; if (i_cell == cellX) distanceX = abs(i-xHitInCell); if (j_cell == cellY) distanceY = abs(j-yHitInCell); - if (distanceX < r && distanceY < r) mNew[j*landTextureSize+i] = brushInt; + if (distanceX < r && distanceY < r) newTerrain[j*landTextureSize+i] = brushInt; } } } - pushEditToCommand(mNew, document, landTable, iteratedCellId); + pushEditToCommand(newTerrain, document, landTable, iteratedCellId); } } } @@ -342,11 +414,11 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe { for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++) { - iteratedCellId = "#" + std::to_string(i_cell) + " " + std::to_string(j_cell); + iteratedCellId = CSMWorld::CellCoordinates::generateId(i_cell, j_cell); if(allowLandTextureEditing(iteratedCellId)==true) { - CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value(); - CSMWorld::LandTexturesColumn::DataType mNew(mPointer); + CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value(); + CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer); for(int i = 0; i < landTextureSize; i++) { for(int j = 0; j < landTextureSize; j++) @@ -363,7 +435,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe if (i_cell == cellX) distanceX = abs(i-xHitInCell); if (j_cell == cellY) distanceY = abs(j-yHitInCell); distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); - if (distance < rf) mNew[j*landTextureSize+i] = brushInt; + if (distance < rf) newTerrain[j*landTextureSize+i] = brushInt; } else { @@ -376,11 +448,11 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe if (i_cell == cellX) distanceX = abs(i-xHitInCell); if (j_cell == cellY) distanceY = abs(j-yHitInCell); distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); - if (distance < rf) mNew[j*landTextureSize+i] = brushInt; + if (distance < rf) newTerrain[j*landTextureSize+i] = brushInt; } } } - pushEditToCommand(mNew, document, landTable, iteratedCellId); + pushEditToCommand(newTerrain, document, landTable, iteratedCellId); } } } @@ -388,9 +460,87 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe if (mBrushShape == 3) { - // Not implemented + CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value(); + CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer); + + if(allowLandTextureEditing(mCellId)==true && !mCustomBrushShape.empty()) + { + for(auto const& value: mCustomBrushShape) + { + if(yHitInCell + value.second >= 0 && yHitInCell + value.second <= 15 && xHitInCell + value.first >= 0 && xHitInCell + value.first <= 15) + { + newTerrain[(yHitInCell+value.second)*landTextureSize+xHitInCell+value.first] = brushInt; + } + else + { + int cellXDifference = std::floor(1.0f*(xHitInCell + value.first)/landTextureSize); + int cellYDifference = std::floor(1.0f*(yHitInCell + value.second)/landTextureSize); + int xInOtherCell = xHitInCell + value.first - cellXDifference * landTextureSize; + int yInOtherCell = yHitInCell + value.second - cellYDifference * landTextureSize; + + std::string cellId = CSMWorld::CellCoordinates::generateId(cellX+cellXDifference, cellY+cellYDifference); + if (allowLandTextureEditing(cellId)==true) + { + CSMWorld::LandTexturesColumn::DataType newTerrainPointerOtherCell = landTable.data(landTable.getModelIndex(cellId, textureColumn)).value(); + CSMWorld::LandTexturesColumn::DataType newTerrainOtherCell(newTerrainPointerOtherCell); + newTerrainOtherCell[yInOtherCell*landTextureSize+xInOtherCell] = brushInt; + pushEditToCommand(newTerrainOtherCell, document, landTable, cellId); + } + } + } + pushEditToCommand(newTerrain, document, landTable, mCellId); + } + } +} + +void CSVRender::TerrainTextureMode::selectTerrainTextures(std::pair texCoords, unsigned char selectMode, bool dragOperation) +{ + int r = mBrushSize / 2; + std::vector> selections; + + if (mBrushShape == 0) + { + selections.emplace_back(texCoords); } + if (mBrushShape == 1) + { + for(int i = texCoords.first - r; i <= texCoords.first + r; ++i) + { + for(int j = texCoords.second - r; j <= texCoords.second + r; ++j) + { + selections.emplace_back(std::make_pair(i, j)); + } + } + } + + if (mBrushShape == 2) + { + for(int i = texCoords.first - r; i <= texCoords.first + r; ++i) + { + for(int j = texCoords.second - r; j <= texCoords.second + r; ++j) + { + int distanceX = abs(i - texCoords.first); + int distanceY = abs(j - texCoords.second); + int distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); + if (distance < r) selections.emplace_back(std::make_pair(i, j)); + } + } + } + + if (mBrushShape == 3) + { + if(!mCustomBrushShape.empty()) + { + for(auto const& value: mCustomBrushShape) + { + selections.emplace_back(std::make_pair(texCoords.first + value.first, texCoords.second + value.second)); + } + } + } + + if(selectMode == 0) mTerrainTextureSelection->onlySelect(selections); + if(selectMode == 1) mTerrainTextureSelection->toggleSelect(selections, dragOperation); } void CSVRender::TerrainTextureMode::pushEditToCommand(CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document, @@ -405,8 +555,8 @@ void CSVRender::TerrainTextureMode::pushEditToCommand(CSMWorld::LandTexturesColu QModelIndex index(landTable.getModelIndex (cellId, landTable.findColumnIndex (CSMWorld::Columns::ColumnId_LandTexturesIndex))); QUndoStack& undoStack = document.getUndoStack(); - undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId)); undoStack.push (new CSMWorld::ModifyCommand(landTable, index, changedLand)); + undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId)); } void CSVRender::TerrainTextureMode::createTexture(std::string textureFileName) @@ -422,18 +572,21 @@ void CSVRender::TerrainTextureMode::createTexture(std::string textureFileName) int counter=0; bool freeIndexFound = false; - do { + do + { const size_t maxCounter = std::numeric_limits::max() - 1; try { newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter); if (ltexTable.getRecord(newId).isDeleted() == 0) counter = (counter + 1) % maxCounter; - } catch (const std::exception& e) + } + catch (const std::exception& e) { newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter); freeIndexFound = true; } - } while (freeIndexFound == false); + } + while (freeIndexFound == false); std::size_t idlocation = textureFileName.find("Texture: "); textureFileName = textureFileName.substr (idlocation + 9); @@ -527,7 +680,8 @@ bool CSVRender::TerrainTextureMode::allowLandTextureEditing(std::string cellId) return true; } -void CSVRender::TerrainTextureMode::dragMoveEvent (QDragMoveEvent *event) { +void CSVRender::TerrainTextureMode::dragMoveEvent (QDragMoveEvent *event) +{ } void CSVRender::TerrainTextureMode::setBrushSize(int brushSize) @@ -538,9 +692,41 @@ void CSVRender::TerrainTextureMode::setBrushSize(int brushSize) void CSVRender::TerrainTextureMode::setBrushShape(int brushShape) { mBrushShape = brushShape; + + //Set custom brush shape + if (mBrushShape == 3 && !mTerrainTextureSelection->getTerrainSelection().empty()) + { + auto terrainSelection = mTerrainTextureSelection->getTerrainSelection(); + int selectionCenterX = 0; + int selectionCenterY = 0; + int selectionAmount = 0; + + for(auto const& value: terrainSelection) + { + selectionCenterX = selectionCenterX + value.first; + selectionCenterY = selectionCenterY + value.second; + ++selectionAmount; + } + selectionCenterX = selectionCenterX / selectionAmount; + selectionCenterY = selectionCenterY / selectionAmount; + + mCustomBrushShape.clear(); + std::pair differentialPos {}; + for(auto const& value: terrainSelection) + { + differentialPos.first = value.first - selectionCenterX; + differentialPos.second = value.second - selectionCenterY; + mCustomBrushShape.push_back(differentialPos); + } + } } void CSVRender::TerrainTextureMode::setBrushTexture(std::string brushTexture) { mBrushTexture = brushTexture; } + +CSVRender::PagedWorldspaceWidget& CSVRender::TerrainTextureMode::getPagedWorldspaceWidget() +{ + return dynamic_cast(getWorldspaceWidget()); +} diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index 10ea842c98..81669ed74f 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -4,6 +4,7 @@ #include "editmode.hpp" #include +#include #include #include @@ -18,6 +19,8 @@ #include "../../model/world/landtexture.hpp" #endif +#include "terrainselection.hpp" + namespace CSVWidget { class SceneToolTextureBrush; @@ -25,6 +28,7 @@ namespace CSVWidget namespace CSVRender { + class PagedWorldspaceWidget; class TerrainTextureMode : public EditMode { @@ -32,8 +36,17 @@ namespace CSVRender public: + enum InteractionType + { + InteractionType_PrimaryEdit, + InteractionType_PrimarySelect, + InteractionType_SecondaryEdit, + InteractionType_SecondarySelect, + InteractionType_None + }; + /// \brief Editmode for terrain texture grid - TerrainTextureMode(WorldspaceWidget*, QWidget* parent = nullptr); + TerrainTextureMode(WorldspaceWidget*, osg::Group* parentNode, QWidget* parent = nullptr); void primaryOpenPressed (const WorldspaceHitResult& hit); @@ -68,6 +81,9 @@ namespace CSVRender /// \brief Handle brush mechanics, maths regarding worldspace hit etc. void editTerrainTextureGrid (const WorldspaceHitResult& hit); + /// \brief Handle brush mechanics for texture selection + void selectTerrainTextures (std::pair, unsigned char, bool); + /// \brief Push texture edits to command macro void pushEditToCommand (CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document, CSMWorld::IdTable& landTable, std::string cellId); @@ -83,12 +99,19 @@ namespace CSVRender std::string mBrushTexture; int mBrushSize; int mBrushShape; + std::vector> mCustomBrushShape; CSVWidget::SceneToolTextureBrush *mTextureBrushScenetool; + int mDragMode; + osg::Group* mParentNode; + bool mIsEditing; + std::unique_ptr mTerrainTextureSelection; const int cellSize {ESM::Land::REAL_SIZE}; const int landSize {ESM::Land::LAND_SIZE}; const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE}; + PagedWorldspaceWidget& getPagedWorldspaceWidget(); + signals: void passBrushTexture(std::string brushTexture); From 1a08944a8b04eecbf61c47ee7f3d3565782d8065 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 7 Apr 2019 20:58:03 +0300 Subject: [PATCH 03/24] Remove unused code, clarifications, optimizations --- apps/opencs/view/render/terrainselection.cpp | 6 +-- .../opencs/view/render/terraintexturemode.cpp | 38 +++++++------------ .../opencs/view/render/terraintexturemode.hpp | 2 - 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/apps/opencs/view/render/terrainselection.cpp b/apps/opencs/view/render/terrainselection.cpp index 5725a35c08..8fd0d8aed7 100644 --- a/apps/opencs/view/render/terrainselection.cpp +++ b/apps/opencs/view/render/terrainselection.cpp @@ -66,12 +66,12 @@ void CSVRender::TerrainSelection::toggleSelect(const std::vector& landtexturesCollection = document.getData().getLandTextures(); int index = landtexturesCollection.searchId(mBrushTexture); - if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit && hit.tag == 0) + if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit && hit.tag == 0) { undoStack.beginMacro ("Edit texture records"); if(allowLandTextureEditing(mCellId)==true) @@ -505,25 +505,24 @@ void CSVRender::TerrainTextureMode::selectTerrainTextures(std::pair te if (mBrushShape == 1) { - for(int i = texCoords.first - r; i <= texCoords.first + r; ++i) + for (int i = -r; i <= r; i++) { - for(int j = texCoords.second - r; j <= texCoords.second + r; ++j) + for (int j = -r; j <= r; j++) { - selections.emplace_back(std::make_pair(i, j)); + selections.emplace_back(i + texCoords.first, j + texCoords.second); } } } if (mBrushShape == 2) { - for(int i = texCoords.first - r; i <= texCoords.first + r; ++i) + for (int i = -r; i <= r; i++) { - for(int j = texCoords.second - r; j <= texCoords.second + r; ++j) + for (int j = -r; j <= r; j++) { - int distanceX = abs(i - texCoords.first); - int distanceY = abs(j - texCoords.second); - int distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); - if (distance < r) selections.emplace_back(std::make_pair(i, j)); + osg::Vec2f coords(i,j); + if (std::round(coords.length()) < r) + selections.emplace_back(i + texCoords.first, j + texCoords.second); } } } @@ -534,7 +533,7 @@ void CSVRender::TerrainTextureMode::selectTerrainTextures(std::pair te { for(auto const& value: mCustomBrushShape) { - selections.emplace_back(std::make_pair(texCoords.first + value.first, texCoords.second + value.second)); + selections.emplace_back(texCoords.first + value.first, texCoords.second + value.second); } } } @@ -585,8 +584,7 @@ void CSVRender::TerrainTextureMode::createTexture(std::string textureFileName) newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter); freeIndexFound = true; } - } - while (freeIndexFound == false); + } while (freeIndexFound == false); std::size_t idlocation = textureFileName.find("Texture: "); textureFileName = textureFileName.substr (idlocation + 9); @@ -711,13 +709,8 @@ void CSVRender::TerrainTextureMode::setBrushShape(int brushShape) selectionCenterY = selectionCenterY / selectionAmount; mCustomBrushShape.clear(); - std::pair differentialPos {}; - for(auto const& value: terrainSelection) - { - differentialPos.first = value.first - selectionCenterX; - differentialPos.second = value.second - selectionCenterY; - mCustomBrushShape.push_back(differentialPos); - } + for (auto const& value: terrainSelection) + mCustomBrushShape.emplace_back(value.first - selectionCenterX, value.second - selectionCenterY); } } @@ -725,8 +718,3 @@ void CSVRender::TerrainTextureMode::setBrushTexture(std::string brushTexture) { mBrushTexture = brushTexture; } - -CSVRender::PagedWorldspaceWidget& CSVRender::TerrainTextureMode::getPagedWorldspaceWidget() -{ - return dynamic_cast(getWorldspaceWidget()); -} diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index 81669ed74f..1f18409b03 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -110,8 +110,6 @@ namespace CSVRender const int landSize {ESM::Land::LAND_SIZE}; const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE}; - PagedWorldspaceWidget& getPagedWorldspaceWidget(); - signals: void passBrushTexture(std::string brushTexture); From 20ab7df19fe6a2a7aa3b2f9c2c52b6cc187e95bd Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 7 Apr 2019 21:48:55 +0300 Subject: [PATCH 04/24] Fixes, cleanup. --- apps/opencs/view/render/terrainselection.cpp | 4 ++-- apps/opencs/view/render/terraintexturemode.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/terrainselection.cpp b/apps/opencs/view/render/terrainselection.cpp index 8fd0d8aed7..ab94da3544 100644 --- a/apps/opencs/view/render/terrainselection.cpp +++ b/apps/opencs/view/render/terrainselection.cpp @@ -110,12 +110,12 @@ void CSVRender::TerrainSelection::toggleSelect(const std::vectoraddChild(mSelectionNode); + if (!mParentNode->containsNode(mSelectionNode)) mParentNode->addChild(mSelectionNode); } void CSVRender::TerrainSelection::deactivate() { - mParentNode->removeChild(mSelectionNode); + if (mParentNode->containsNode(mSelectionNode)) mParentNode->removeChild(mSelectionNode); } void CSVRender::TerrainSelection::update() diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index 1f18409b03..72e7df9dee 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -6,6 +6,8 @@ #include #include +#include + #include #include @@ -28,8 +30,6 @@ namespace CSVWidget namespace CSVRender { - class PagedWorldspaceWidget; - class TerrainTextureMode : public EditMode { Q_OBJECT From 46ee6398925621f761ee110f9ddaae14decc5344 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sun, 7 Apr 2019 23:11:13 +0300 Subject: [PATCH 05/24] pass by const ref and other fixes --- apps/opencs/view/render/terrainselection.cpp | 8 +++++--- apps/opencs/view/render/terraintexturemode.cpp | 2 +- apps/opencs/view/render/terraintexturemode.hpp | 9 ++++++--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/render/terrainselection.cpp b/apps/opencs/view/render/terrainselection.cpp index ab94da3544..359338c674 100644 --- a/apps/opencs/view/render/terrainselection.cpp +++ b/apps/opencs/view/render/terrainselection.cpp @@ -56,8 +56,10 @@ void CSVRender::TerrainSelection::onlySelect(const std::vector localPos) { if (std::find(mSelection.begin(), mSelection.end(), localPos) == mSelection.end()) - mSelection.emplace_back(localPos); - update(); + { + mSelection.emplace_back(localPos); + update(); + } } void CSVRender::TerrainSelection::toggleSelect(const std::vector> localPositions, bool toggleInProgress) @@ -115,7 +117,7 @@ void CSVRender::TerrainSelection::activate() void CSVRender::TerrainSelection::deactivate() { - if (mParentNode->containsNode(mSelectionNode)) mParentNode->removeChild(mSelectionNode); + mParentNode->removeChild(mSelectionNode); } void CSVRender::TerrainSelection::update() diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 8218d65965..ad13e80bee 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -493,7 +493,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe } } -void CSVRender::TerrainTextureMode::selectTerrainTextures(std::pair texCoords, unsigned char selectMode, bool dragOperation) +void CSVRender::TerrainTextureMode::selectTerrainTextures(const std::pair& texCoords, unsigned char selectMode, bool dragOperation) { int r = mBrushSize / 2; std::vector> selections; diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index 72e7df9dee..d2ad99aaf0 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -6,8 +6,6 @@ #include #include -#include - #include #include @@ -23,6 +21,11 @@ #include "terrainselection.hpp" +namespace osg +{ + class Group; +} + namespace CSVWidget { class SceneToolTextureBrush; @@ -82,7 +85,7 @@ namespace CSVRender void editTerrainTextureGrid (const WorldspaceHitResult& hit); /// \brief Handle brush mechanics for texture selection - void selectTerrainTextures (std::pair, unsigned char, bool); + void selectTerrainTextures (const std::pair& texCoords, unsigned char selectMode, bool dragOperation); /// \brief Push texture edits to command macro void pushEditToCommand (CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document, From 001ca68cc719436bedbe6a11109ba55d967ea1b2 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Mon, 8 Apr 2019 11:33:11 +0300 Subject: [PATCH 06/24] Remove empty lines --- apps/opencs/view/render/terrainselection.cpp | 1 - apps/opencs/view/render/terrainselection.hpp | 1 - 2 files changed, 2 deletions(-) diff --git a/apps/opencs/view/render/terrainselection.cpp b/apps/opencs/view/render/terrainselection.cpp index 359338c674..f7db31e1e6 100644 --- a/apps/opencs/view/render/terrainselection.cpp +++ b/apps/opencs/view/render/terrainselection.cpp @@ -182,7 +182,6 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptr Date: Mon, 6 May 2019 12:22:16 +0300 Subject: [PATCH 07/24] Make less copies --- apps/opencs/view/render/terrainselection.cpp | 16 ++++++---------- apps/opencs/view/render/terrainselection.hpp | 6 +++--- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/apps/opencs/view/render/terrainselection.cpp b/apps/opencs/view/render/terrainselection.cpp index f7db31e1e6..45b06e8f6e 100644 --- a/apps/opencs/view/render/terrainselection.cpp +++ b/apps/opencs/view/render/terrainselection.cpp @@ -43,17 +43,13 @@ std::vector> CSVRender::TerrainSelection::getTerrainSelectio return mSelection; } -void CSVRender::TerrainSelection::onlySelect(const std::vector> localPositions) +void CSVRender::TerrainSelection::onlySelect(const std::vector> &localPositions) { - mSelection.clear(); - for(auto const& value: localPositions) - { - mSelection.emplace_back(value); - } + mSelection = localPositions; update(); } -void CSVRender::TerrainSelection::addSelect(const std::pair localPos) +void CSVRender::TerrainSelection::addSelect(const std::pair &localPos) { if (std::find(mSelection.begin(), mSelection.end(), localPos) == mSelection.end()) { @@ -62,7 +58,7 @@ void CSVRender::TerrainSelection::addSelect(const std::pair localPos) } } -void CSVRender::TerrainSelection::toggleSelect(const std::vector> localPositions, bool toggleInProgress) +void CSVRender::TerrainSelection::toggleSelect(const std::vector> &localPositions, bool toggleInProgress) { if (toggleInProgress == true) { @@ -146,7 +142,7 @@ void CSVRender::TerrainSelection::drawShapeSelection(const osg::ref_ptr localPos : mSelection) + for (std::pair &localPos : mSelection) { int x (localPos.first); int y (localPos.second); @@ -189,7 +185,7 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptr localPos : mSelection) + for (std::pair &localPos : mSelection) { int x (localPos.first); int y (localPos.second); diff --git a/apps/opencs/view/render/terrainselection.hpp b/apps/opencs/view/render/terrainselection.hpp index 7a20bd87f2..ed4548fa7d 100644 --- a/apps/opencs/view/render/terrainselection.hpp +++ b/apps/opencs/view/render/terrainselection.hpp @@ -35,9 +35,9 @@ namespace CSVRender TerrainSelection(osg::Group* parentNode, WorldspaceWidget *worldspaceWidget, TerrainSelectionType type); ~TerrainSelection(); - void onlySelect(const std::vector> localPositions); - void addSelect(const std::pair localPos); - void toggleSelect(const std::vector> localPositions, bool); + void onlySelect(const std::vector> &localPositions); + void addSelect(const std::pair &localPos); + void toggleSelect(const std::vector> &localPositions, bool); void activate(); void deactivate(); From 39ab449431b77662d2ccc4aba1fbeb233c7ac47b Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Mon, 6 May 2019 12:56:04 +0300 Subject: [PATCH 08/24] Only allow selection of cells in view --- apps/opencs/model/world/cellcoordinates.cpp | 7 ++++ apps/opencs/model/world/cellcoordinates.hpp | 2 + .../opencs/view/render/terraintexturemode.cpp | 40 +++++++++++++++++-- .../opencs/view/render/terraintexturemode.hpp | 3 ++ 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/cellcoordinates.cpp b/apps/opencs/model/world/cellcoordinates.cpp index 1e545e38de..55adc3eff1 100644 --- a/apps/opencs/model/world/cellcoordinates.cpp +++ b/apps/opencs/model/world/cellcoordinates.cpp @@ -113,6 +113,13 @@ int CSMWorld::CellCoordinates::vertexSelectionToInCellCoords(int pos) return static_cast(pos - std::floor(static_cast(pos) / (landSize - 1)) * (landSize - 1)); } +std::string CSMWorld::CellCoordinates::textureGlobalToCellId(std::pair textureGlobal) +{ + int x = std::floor(static_cast(textureGlobal.first) / landTextureSize); + int y = std::floor(static_cast(textureGlobal.second) / landTextureSize); + return generateId(x, y); +} + std::string CSMWorld::CellCoordinates::vertexGlobalToCellId(std::pair vertexGlobal) { int x = std::floor(static_cast(vertexGlobal.first) / (landSize - 1)); diff --git a/apps/opencs/model/world/cellcoordinates.hpp b/apps/opencs/model/world/cellcoordinates.hpp index 3b21195174..c6c2c7ccd6 100644 --- a/apps/opencs/model/world/cellcoordinates.hpp +++ b/apps/opencs/model/world/cellcoordinates.hpp @@ -63,6 +63,8 @@ namespace CSMWorld ///Converts local cell's heightmap coordinates from the global vertex coordinate static int vertexSelectionToInCellCoords(int); + static std::string textureGlobalToCellId(std::pair); + ///Converts global vertex coordinates to cell id static std::string vertexGlobalToCellId(std::pair); }; diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index ad13e80bee..fae18f8c21 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -493,6 +493,21 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe } } +bool CSVRender::TerrainTextureMode::isInCellSelection(const int& globalSelectionX, const int& globalSelectionY) +{ + if (CSVRender::PagedWorldspaceWidget *paged = dynamic_cast (&getWorldspaceWidget())) + { + CSMWorld::CellSelection selection = paged->getCellSelection(); + if (selection.has (CSMWorld::CellCoordinates::fromId( + CSMWorld::CellCoordinates::textureGlobalToCellId(std::make_pair(globalSelectionX, globalSelectionY))).first)) + { + return true; + } + } + return false; +} + + void CSVRender::TerrainTextureMode::selectTerrainTextures(const std::pair& texCoords, unsigned char selectMode, bool dragOperation) { int r = mBrushSize / 2; @@ -500,7 +515,7 @@ void CSVRender::TerrainTextureMode::selectTerrainTextures(const std::pair& texCoords, unsigned char selectMode, bool dragOperation); From 5a143fe99d01e455e7e2d24d6789b72de4928318 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Mon, 6 May 2019 12:59:28 +0300 Subject: [PATCH 09/24] Remove extra include --- apps/opencs/view/render/terraintexturemode.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index fae18f8c21..42c3a5d392 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -36,7 +36,6 @@ #include "pagedworldspacewidget.hpp" #include "mask.hpp" #include "object.hpp" // Something small needed regarding pointers from here () -#include "terrainselection.hpp" #include "worldspacewidget.hpp" CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, osg::Group* parentNode, QWidget *parent) From 1dcee833a12d8cf632b5d4d9a447b9e105a42a17 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Mon, 6 May 2019 13:02:49 +0300 Subject: [PATCH 10/24] Less verbose syntax --- apps/opencs/view/render/terrainselection.cpp | 2 +- .../opencs/view/render/terraintexturemode.cpp | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/render/terrainselection.cpp b/apps/opencs/view/render/terrainselection.cpp index 45b06e8f6e..4a5deb4b00 100644 --- a/apps/opencs/view/render/terrainselection.cpp +++ b/apps/opencs/view/render/terrainselection.cpp @@ -60,7 +60,7 @@ void CSVRender::TerrainSelection::addSelect(const std::pair &localPos) void CSVRender::TerrainSelection::toggleSelect(const std::vector> &localPositions, bool toggleInProgress) { - if (toggleInProgress == true) + if (toggleInProgress) { for(auto const& localPos: localPositions) { diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 42c3a5d392..dee60f2b32 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -114,7 +114,7 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit && hit.tag == 0) { undoStack.beginMacro ("Edit texture records"); - if(allowLandTextureEditing(mCellId)==true) + if(allowLandTextureEditing(mCellId)) { undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); editTerrainTextureGrid(hit); @@ -162,7 +162,7 @@ bool CSVRender::TerrainTextureMode::primaryEditStartDrag (const QPoint& pos) { undoStack.beginMacro ("Edit texture records"); mIsEditing = true; - if(allowLandTextureEditing(mCellId)==true) + if(allowLandTextureEditing(mCellId)) { undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); editTerrainTextureGrid(hit); @@ -245,7 +245,7 @@ void CSVRender::TerrainTextureMode::dragCompleted(const QPoint& pos) if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) { - if (mIsEditing == true) + if (mIsEditing) { undoStack.endMacro(); mIsEditing = false; @@ -299,7 +299,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe *document.getData().getTableModel (CSMWorld::UniversalId::Type_Land)); mCellId = getWorldspaceWidget().getCellId (hit.worldPos); - if(allowLandTextureEditing(mCellId)==true) {} + if(allowLandTextureEditing(mCellId)) {} std::pair cellCoordinates_pair = CSMWorld::CellCoordinates::fromId (mCellId); @@ -321,7 +321,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe } mCellId = CSMWorld::CellCoordinates::generateId(cellX, cellY); - if(allowLandTextureEditing(mCellId)==true) {} + if(allowLandTextureEditing(mCellId)) {} std::string iteratedCellId; @@ -340,7 +340,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value(); CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer); - if(allowLandTextureEditing(mCellId)==true) + if(allowLandTextureEditing(mCellId)) { newTerrain[yHitInCell*landTextureSize+xHitInCell] = brushInt; pushEditToCommand(newTerrain, document, landTable, mCellId); @@ -364,7 +364,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++) { iteratedCellId = CSMWorld::CellCoordinates::generateId(i_cell, j_cell); - if(allowLandTextureEditing(iteratedCellId)==true) + if(allowLandTextureEditing(iteratedCellId)) { CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value(); CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer); @@ -414,7 +414,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++) { iteratedCellId = CSMWorld::CellCoordinates::generateId(i_cell, j_cell); - if(allowLandTextureEditing(iteratedCellId)==true) + if(allowLandTextureEditing(iteratedCellId)) { CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value(); CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer); @@ -462,7 +462,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value(); CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer); - if(allowLandTextureEditing(mCellId)==true && !mCustomBrushShape.empty()) + if(allowLandTextureEditing(mCellId) && !mCustomBrushShape.empty()) { for(auto const& value: mCustomBrushShape) { @@ -478,7 +478,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe int yInOtherCell = yHitInCell + value.second - cellYDifference * landTextureSize; std::string cellId = CSMWorld::CellCoordinates::generateId(cellX+cellXDifference, cellY+cellYDifference); - if (allowLandTextureEditing(cellId)==true) + if (allowLandTextureEditing(cellId)) { CSMWorld::LandTexturesColumn::DataType newTerrainPointerOtherCell = landTable.data(landTable.getModelIndex(cellId, textureColumn)).value(); CSMWorld::LandTexturesColumn::DataType newTerrainOtherCell(newTerrainPointerOtherCell); From 3becacf6d1c385e7a6136ea3b18da0f09a3381ee Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Thu, 9 May 2019 20:31:36 +0300 Subject: [PATCH 11/24] Remove globals, const int& -> int, values to const ref. --- apps/opencs/model/world/cellcoordinates.cpp | 37 +++++++----------- apps/opencs/model/world/cellcoordinates.hpp | 8 ++-- apps/opencs/view/render/terrainselection.cpp | 39 ++++++++----------- apps/opencs/view/render/terrainselection.hpp | 4 -- .../opencs/view/render/terraintexturemode.cpp | 10 ++--- .../opencs/view/render/terraintexturemode.hpp | 2 +- 6 files changed, 41 insertions(+), 59 deletions(-) diff --git a/apps/opencs/model/world/cellcoordinates.cpp b/apps/opencs/model/world/cellcoordinates.cpp index 55adc3eff1..ce48b5a128 100644 --- a/apps/opencs/model/world/cellcoordinates.cpp +++ b/apps/opencs/model/world/cellcoordinates.cpp @@ -8,13 +8,6 @@ #include #include -namespace -{ - const int cellSize {ESM::Land::REAL_SIZE}; - const int landSize {ESM::Land::LAND_SIZE}; - const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE}; -} - CSMWorld::CellCoordinates::CellCoordinates() : mX (0), mY (0) {} CSMWorld::CellCoordinates::CellCoordinates (int x, int y) : mX (x), mY (y) {} @@ -76,10 +69,10 @@ std::pair CSMWorld::CellCoordinates::coordinatesToCellIndex (float x, return std::make_pair (std::floor (x / Constants::CellSizeInUnits), std::floor (y / Constants::CellSizeInUnits)); } -std::pair CSMWorld::CellCoordinates::toTextureCoords(osg::Vec3d worldPos) +std::pair CSMWorld::CellCoordinates::toTextureCoords(const osg::Vec3d& worldPos) { - const auto xd = static_cast(worldPos.x() * landTextureSize / cellSize - 0.25f); - const auto yd = static_cast(worldPos.y() * landTextureSize / cellSize + 0.25f); + const auto xd = static_cast(worldPos.x() * ESM::Land::LAND_TEXTURE_SIZE / ESM::Land::REAL_SIZE - 0.25f); + const auto yd = static_cast(worldPos.y() * ESM::Land::LAND_TEXTURE_SIZE / ESM::Land::REAL_SIZE + 0.25f); const auto x = static_cast(std::floor(xd)); const auto y = static_cast(std::floor(yd)); @@ -87,10 +80,10 @@ std::pair CSMWorld::CellCoordinates::toTextureCoords(osg::Vec3d worldP return std::make_pair(x, y); } -std::pair CSMWorld::CellCoordinates::toVertexCoords(osg::Vec3d worldPos) +std::pair CSMWorld::CellCoordinates::toVertexCoords(const osg::Vec3d& worldPos) { - const auto xd = static_cast(worldPos.x() * (landSize - 1) / cellSize + 0.5f); - const auto yd = static_cast(worldPos.y() * (landSize - 1) / cellSize + 0.5f); + const auto xd = static_cast(worldPos.x() * (ESM::Land::LAND_SIZE - 1) / ESM::Land::REAL_SIZE + 0.5f); + const auto yd = static_cast(worldPos.y() * (ESM::Land::LAND_SIZE - 1) / ESM::Land::REAL_SIZE + 0.5f); const auto x = static_cast(std::floor(xd)); const auto y = static_cast(std::floor(yd)); @@ -100,30 +93,30 @@ std::pair CSMWorld::CellCoordinates::toVertexCoords(osg::Vec3d worldPo float CSMWorld::CellCoordinates::textureSelectionToWorldCoords(int pos) { - return cellSize * static_cast(pos) / landTextureSize; + return ESM::Land::REAL_SIZE * static_cast(pos) / ESM::Land::LAND_TEXTURE_SIZE; } float CSMWorld::CellCoordinates::vertexSelectionToWorldCoords(int pos) { - return cellSize * static_cast(pos) / (landSize - 1); + return ESM::Land::REAL_SIZE * static_cast(pos) / (ESM::Land::LAND_SIZE - 1); } int CSMWorld::CellCoordinates::vertexSelectionToInCellCoords(int pos) { - return static_cast(pos - std::floor(static_cast(pos) / (landSize - 1)) * (landSize - 1)); + return static_cast(pos - std::floor(static_cast(pos) / (ESM::Land::LAND_SIZE - 1)) * (ESM::Land::LAND_SIZE - 1)); } -std::string CSMWorld::CellCoordinates::textureGlobalToCellId(std::pair textureGlobal) +std::string CSMWorld::CellCoordinates::textureGlobalToCellId(const std::pair& textureGlobal) { - int x = std::floor(static_cast(textureGlobal.first) / landTextureSize); - int y = std::floor(static_cast(textureGlobal.second) / landTextureSize); + int x = std::floor(static_cast(textureGlobal.first) / ESM::Land::LAND_TEXTURE_SIZE); + int y = std::floor(static_cast(textureGlobal.second) / ESM::Land::LAND_TEXTURE_SIZE); return generateId(x, y); } -std::string CSMWorld::CellCoordinates::vertexGlobalToCellId(std::pair vertexGlobal) +std::string CSMWorld::CellCoordinates::vertexGlobalToCellId(const std::pair& vertexGlobal) { - int x = std::floor(static_cast(vertexGlobal.first) / (landSize - 1)); - int y = std::floor(static_cast(vertexGlobal.second) / (landSize - 1)); + int x = std::floor(static_cast(vertexGlobal.first) / (ESM::Land::LAND_SIZE - 1)); + int y = std::floor(static_cast(vertexGlobal.second) / (ESM::Land::LAND_SIZE - 1)); return generateId(x, y); } diff --git a/apps/opencs/model/world/cellcoordinates.hpp b/apps/opencs/model/world/cellcoordinates.hpp index c6c2c7ccd6..554aff32be 100644 --- a/apps/opencs/model/world/cellcoordinates.hpp +++ b/apps/opencs/model/world/cellcoordinates.hpp @@ -49,10 +49,10 @@ namespace CSMWorld static std::pair coordinatesToCellIndex (float x, float y); ///Converts worldspace coordinates to global texture selection, taking in account the texture offset. - static std::pair toTextureCoords(osg::Vec3d worldPos); + static std::pair toTextureCoords(const osg::Vec3d& worldPos); ///Converts worldspace coordinates to global vertex selection. - static std::pair toVertexCoords(osg::Vec3d worldPos); + static std::pair toVertexCoords(const osg::Vec3d& worldPos); ///Converts global texture coordinate to worldspace coordinate that is at the upper left corner of the selected texture. static float textureSelectionToWorldCoords(int); @@ -63,10 +63,10 @@ namespace CSMWorld ///Converts local cell's heightmap coordinates from the global vertex coordinate static int vertexSelectionToInCellCoords(int); - static std::string textureGlobalToCellId(std::pair); + static std::string textureGlobalToCellId(const std::pair&); ///Converts global vertex coordinates to cell id - static std::string vertexGlobalToCellId(std::pair); + static std::string vertexGlobalToCellId(const std::pair&); }; bool operator== (const CellCoordinates& left, const CellCoordinates& right); diff --git a/apps/opencs/view/render/terrainselection.cpp b/apps/opencs/view/render/terrainselection.cpp index 4a5deb4b00..93a9046899 100644 --- a/apps/opencs/view/render/terrainselection.cpp +++ b/apps/opencs/view/render/terrainselection.cpp @@ -15,13 +15,6 @@ #include "cell.hpp" #include "worldspacewidget.hpp" -namespace -{ - const int cellSize {ESM::Land::REAL_SIZE}; - const int landSize {ESM::Land::LAND_SIZE}; - const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE}; -} - CSVRender::TerrainSelection::TerrainSelection(osg::Group* parentNode, WorldspaceWidget *worldspaceWidget, TerrainSelectionType type): mParentNode(parentNode), mWorldspaceWidget (worldspaceWidget), mDraggedOperationFlag(false), mSelectionType(type) { @@ -180,10 +173,10 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptr &localPos : mSelection) { @@ -203,8 +196,8 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptrpush_back(osg::Vec3f(drawPreviousX + nudgeOffset, CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y + 1) - nudgeOffset, calculateLandHeight(x1+(i-1), y2)+2)); vertices->push_back(osg::Vec3f(drawCurrentX + nudgeOffset, CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y + 1) - nudgeOffset, calculateLandHeight(x1+i, y2)+2)); } @@ -215,8 +208,8 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptrpush_back(osg::Vec3f(drawPreviousX + nudgeOffset, CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y) - nudgeOffset, calculateLandHeight(x1+(i-1), y1)+2)); vertices->push_back(osg::Vec3f(drawCurrentX + nudgeOffset, CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y) - nudgeOffset, calculateLandHeight(x1+i, y1)+2)); } @@ -227,8 +220,8 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptrpush_back(osg::Vec3f(CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x + 1) + nudgeOffset, drawPreviousY - nudgeOffset, calculateLandHeight(x2, y1+(i-1))+2)); vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x + 1) + nudgeOffset, drawCurrentY - nudgeOffset, calculateLandHeight(x2, y1+i)+2)); } @@ -239,8 +232,8 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptrpush_back(osg::Vec3f(CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x) + nudgeOffset, drawPreviousY - nudgeOffset, calculateLandHeight(x1, y1+(i-1))+2)); vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x) + nudgeOffset, drawCurrentY - nudgeOffset, calculateLandHeight(x1, y1+i)+2)); } @@ -251,10 +244,10 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptr(); - return mPointer[localY*landSize + localX]; + return mPointer[localY*ESM::Land::LAND_SIZE + localX]; } diff --git a/apps/opencs/view/render/terrainselection.hpp b/apps/opencs/view/render/terrainselection.hpp index ed4548fa7d..cf2da2b8ea 100644 --- a/apps/opencs/view/render/terrainselection.hpp +++ b/apps/opencs/view/render/terrainselection.hpp @@ -46,10 +46,6 @@ namespace CSVRender protected: - void addToSelection(osg::Vec3d worldPos); - void toggleSelection(osg::Vec3d worldPos); - void deselect(); - void update(); void drawShapeSelection(const osg::ref_ptr vertices); diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index dee60f2b32..08a437b372 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -492,7 +492,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe } } -bool CSVRender::TerrainTextureMode::isInCellSelection(const int& globalSelectionX, const int& globalSelectionY) +bool CSVRender::TerrainTextureMode::isInCellSelection(int globalSelectionX, int globalSelectionY) { if (CSVRender::PagedWorldspaceWidget *paged = dynamic_cast (&getWorldspaceWidget())) { @@ -732,12 +732,12 @@ void CSVRender::TerrainTextureMode::setBrushShape(int brushShape) for(auto const& value: terrainSelection) { - selectionCenterX = selectionCenterX + value.first; - selectionCenterY = selectionCenterY + value.second; + selectionCenterX += value.first; + selectionCenterY += value.second; ++selectionAmount; } - selectionCenterX = selectionCenterX / selectionAmount; - selectionCenterY = selectionCenterY / selectionAmount; + selectionCenterX /= selectionAmount; + selectionCenterY /= selectionAmount; mCustomBrushShape.clear(); for (auto const& value: terrainSelection) diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index 392f1ce297..0d670d725f 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -85,7 +85,7 @@ namespace CSVRender void editTerrainTextureGrid (const WorldspaceHitResult& hit); /// \brief Check if global selection coordinate belongs to cell in view - bool isInCellSelection(const int& globalSelectionX, const int& globalSelectionY); + bool isInCellSelection(int globalSelectionX, int globalSelectionY); /// \brief Handle brush mechanics for texture selection void selectTerrainTextures (const std::pair& texCoords, unsigned char selectMode, bool dragOperation); From 780055899d2f8287f7a6bc7849c576607c031f36 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Thu, 9 May 2019 21:26:34 +0300 Subject: [PATCH 12/24] Don't add empty primitive sets to geometry. --- apps/opencs/view/render/terrainselection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/terrainselection.cpp b/apps/opencs/view/render/terrainselection.cpp index 93a9046899..cefcfa1175 100644 --- a/apps/opencs/view/render/terrainselection.cpp +++ b/apps/opencs/view/render/terrainselection.cpp @@ -127,7 +127,7 @@ void CSVRender::TerrainSelection::update() mGeometry->setVertexArray(vertices); osg::ref_ptr drawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES); drawArrays->setCount(vertices->size()); - mGeometry->addPrimitiveSet(drawArrays); + if (vertices->size() != 0) mGeometry->addPrimitiveSet(drawArrays); mSelectionNode->addChild(mGeometry); } From 6dc3d8b44b3c363a75f0d95764a2a9880df921e0 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Thu, 9 May 2019 21:34:14 +0300 Subject: [PATCH 13/24] More readable code --- apps/opencs/view/render/terraintexturemode.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 08a437b372..468574c032 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -496,12 +496,9 @@ bool CSVRender::TerrainTextureMode::isInCellSelection(int globalSelectionX, int { if (CSVRender::PagedWorldspaceWidget *paged = dynamic_cast (&getWorldspaceWidget())) { - CSMWorld::CellSelection selection = paged->getCellSelection(); - if (selection.has (CSMWorld::CellCoordinates::fromId( - CSMWorld::CellCoordinates::textureGlobalToCellId(std::make_pair(globalSelectionX, globalSelectionY))).first)) - { - return true; - } + std::pair textureCoords = std::make_pair(globalSelectionX, globalSelectionY); + std::string cellId = CSMWorld::CellCoordinates::textureGlobalToCellId(textureCoords); + return paged->getCellSelection().has(CSMWorld::CellCoordinates::fromId(cellId).first); } return false; } From 08809231894e554544d58d7fcb18942d3cdf7207 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sat, 11 May 2019 21:07:22 +0300 Subject: [PATCH 14/24] Consistency for variable and header argument names. --- apps/opencs/model/world/cellcoordinates.cpp | 12 +++--- apps/opencs/model/world/cellcoordinates.hpp | 13 +++--- apps/opencs/view/render/terrainselection.cpp | 44 ++++++++++---------- apps/opencs/view/render/terrainselection.hpp | 2 +- 4 files changed, 36 insertions(+), 35 deletions(-) diff --git a/apps/opencs/model/world/cellcoordinates.cpp b/apps/opencs/model/world/cellcoordinates.cpp index ce48b5a128..9f98c7b4c6 100644 --- a/apps/opencs/model/world/cellcoordinates.cpp +++ b/apps/opencs/model/world/cellcoordinates.cpp @@ -91,19 +91,19 @@ std::pair CSMWorld::CellCoordinates::toVertexCoords(const osg::Vec3d& return std::make_pair(x, y); } -float CSMWorld::CellCoordinates::textureSelectionToWorldCoords(int pos) +float CSMWorld::CellCoordinates::textureGlobalToWorldCoords(int textureGlobal) { - return ESM::Land::REAL_SIZE * static_cast(pos) / ESM::Land::LAND_TEXTURE_SIZE; + return ESM::Land::REAL_SIZE * static_cast(textureGlobal) / ESM::Land::LAND_TEXTURE_SIZE; } -float CSMWorld::CellCoordinates::vertexSelectionToWorldCoords(int pos) +float CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(int vertexGlobal) { - return ESM::Land::REAL_SIZE * static_cast(pos) / (ESM::Land::LAND_SIZE - 1); + return ESM::Land::REAL_SIZE * static_cast(vertexGlobal) / (ESM::Land::LAND_SIZE - 1); } -int CSMWorld::CellCoordinates::vertexSelectionToInCellCoords(int pos) +int CSMWorld::CellCoordinates::vertexGlobalToInCellCoords(int vertexGlobal) { - return static_cast(pos - std::floor(static_cast(pos) / (ESM::Land::LAND_SIZE - 1)) * (ESM::Land::LAND_SIZE - 1)); + return static_cast(vertexGlobal - std::floor(static_cast(vertexGlobal) / (ESM::Land::LAND_SIZE - 1)) * (ESM::Land::LAND_SIZE - 1)); } std::string CSMWorld::CellCoordinates::textureGlobalToCellId(const std::pair& textureGlobal) diff --git a/apps/opencs/model/world/cellcoordinates.hpp b/apps/opencs/model/world/cellcoordinates.hpp index 554aff32be..77d76f6efb 100644 --- a/apps/opencs/model/world/cellcoordinates.hpp +++ b/apps/opencs/model/world/cellcoordinates.hpp @@ -55,18 +55,19 @@ namespace CSMWorld static std::pair toVertexCoords(const osg::Vec3d& worldPos); ///Converts global texture coordinate to worldspace coordinate that is at the upper left corner of the selected texture. - static float textureSelectionToWorldCoords(int); + static float textureGlobalToWorldCoords(int textureGlobal); ///Converts global vertex coordinate to worldspace coordinate - static float vertexSelectionToWorldCoords(int); + static float vertexGlobalToWorldCoords(int vertexGlobal); - ///Converts local cell's heightmap coordinates from the global vertex coordinate - static int vertexSelectionToInCellCoords(int); + ///Converts global vertex coordinate to local cell's heightmap coordinates + static int vertexGlobalToInCellCoords(int vertexGlobal); - static std::string textureGlobalToCellId(const std::pair&); + ///Converts global texture coordinates to cell id + static std::string textureGlobalToCellId(const std::pair& textureGlobal); ///Converts global vertex coordinates to cell id - static std::string vertexGlobalToCellId(const std::pair&); + static std::string vertexGlobalToCellId(const std::pair& vertexGlobal); }; bool operator== (const CellCoordinates& left, const CellCoordinates& right); diff --git a/apps/opencs/view/render/terrainselection.cpp b/apps/opencs/view/render/terrainselection.cpp index cefcfa1175..225cfc20b6 100644 --- a/apps/opencs/view/render/terrainselection.cpp +++ b/apps/opencs/view/render/terrainselection.cpp @@ -140,28 +140,28 @@ void CSVRender::TerrainSelection::drawShapeSelection(const osg::ref_ptrpush_back(pointXY); - vertices->push_back(osg::Vec3f(xWorldCoord, CSMWorld::CellCoordinates::vertexSelectionToWorldCoords(y - 1), calculateLandHeight(x, y - 1) + 2)); + vertices->push_back(osg::Vec3f(xWorldCoord, CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(y - 1), calculateLandHeight(x, y - 1) + 2)); vertices->push_back(pointXY); - vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::vertexSelectionToWorldCoords(x - 1), yWorldCoord, calculateLandHeight(x - 1, y) + 2)); + vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(x - 1), yWorldCoord, calculateLandHeight(x - 1, y) + 2)); const auto north = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x, y + 1)); if (north == mSelection.end()) { vertices->push_back(pointXY); - vertices->push_back(osg::Vec3f(xWorldCoord, CSMWorld::CellCoordinates::vertexSelectionToWorldCoords(y + 1), calculateLandHeight(x, y + 1) + 2)); + vertices->push_back(osg::Vec3f(xWorldCoord, CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(y + 1), calculateLandHeight(x, y + 1) + 2)); } const auto east = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x + 1, y)); if (east == mSelection.end()) { vertices->push_back(pointXY); - vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::vertexSelectionToWorldCoords(x + 1), yWorldCoord, calculateLandHeight(x + 1, y) + 2)); + vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(x + 1), yWorldCoord, calculateLandHeight(x + 1, y) + 2)); } } } @@ -196,10 +196,10 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptrpush_back(osg::Vec3f(drawPreviousX + nudgeOffset, CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y + 1) - nudgeOffset, calculateLandHeight(x1+(i-1), y2)+2)); - vertices->push_back(osg::Vec3f(drawCurrentX + nudgeOffset, CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y + 1) - nudgeOffset, calculateLandHeight(x1+i, y2)+2)); + float drawPreviousX = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x) + (i - 1) * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1)); + float drawCurrentX = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x) + i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1)); + vertices->push_back(osg::Vec3f(drawPreviousX + nudgeOffset, CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y + 1) - nudgeOffset, calculateLandHeight(x1+(i-1), y2)+2)); + vertices->push_back(osg::Vec3f(drawCurrentX + nudgeOffset, CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y + 1) - nudgeOffset, calculateLandHeight(x1+i, y2)+2)); } } @@ -208,10 +208,10 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptrpush_back(osg::Vec3f(drawPreviousX + nudgeOffset, CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y) - nudgeOffset, calculateLandHeight(x1+(i-1), y1)+2)); - vertices->push_back(osg::Vec3f(drawCurrentX + nudgeOffset, CSMWorld::CellCoordinates::textureSelectionToWorldCoords(y) - nudgeOffset, calculateLandHeight(x1+i, y1)+2)); + float drawPreviousX = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x) + (i - 1) *(ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1)); + float drawCurrentX = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x) + i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1)); + vertices->push_back(osg::Vec3f(drawPreviousX + nudgeOffset, CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y) - nudgeOffset, calculateLandHeight(x1+(i-1), y1)+2)); + vertices->push_back(osg::Vec3f(drawCurrentX + nudgeOffset, CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y) - nudgeOffset, calculateLandHeight(x1+i, y1)+2)); } } @@ -220,10 +220,10 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptrpush_back(osg::Vec3f(CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x + 1) + nudgeOffset, drawPreviousY - nudgeOffset, calculateLandHeight(x2, y1+(i-1))+2)); - vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x + 1) + nudgeOffset, drawCurrentY - nudgeOffset, calculateLandHeight(x2, y1+i)+2)); + float drawPreviousY = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y) + (i - 1) * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1)); + float drawCurrentY = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y) + i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1)); + vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x + 1) + nudgeOffset, drawPreviousY - nudgeOffset, calculateLandHeight(x2, y1+(i-1))+2)); + vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x + 1) + nudgeOffset, drawCurrentY - nudgeOffset, calculateLandHeight(x2, y1+i)+2)); } } @@ -232,10 +232,10 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptrpush_back(osg::Vec3f(CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x) + nudgeOffset, drawPreviousY - nudgeOffset, calculateLandHeight(x1, y1+(i-1))+2)); - vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureSelectionToWorldCoords(x) + nudgeOffset, drawCurrentY - nudgeOffset, calculateLandHeight(x1, y1+i)+2)); + float drawPreviousY = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y) + (i - 1) * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1)); + float drawCurrentY = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y) + i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1)); + vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x) + nudgeOffset, drawPreviousY - nudgeOffset, calculateLandHeight(x1, y1+(i-1))+2)); + vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x) + nudgeOffset, drawCurrentY - nudgeOffset, calculateLandHeight(x1, y1+i)+2)); } } } diff --git a/apps/opencs/view/render/terrainselection.hpp b/apps/opencs/view/render/terrainselection.hpp index cf2da2b8ea..ba80aeb073 100644 --- a/apps/opencs/view/render/terrainselection.hpp +++ b/apps/opencs/view/render/terrainselection.hpp @@ -37,7 +37,7 @@ namespace CSVRender void onlySelect(const std::vector> &localPositions); void addSelect(const std::pair &localPos); - void toggleSelect(const std::vector> &localPositions, bool); + void toggleSelect(const std::vector> &localPositions, bool toggleInProgress); void activate(); void deactivate(); From 4ccb951126a21e6e597fe2770112350b929e9192 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Fri, 31 May 2019 11:28:48 +0300 Subject: [PATCH 15/24] move check to outermost scope --- apps/opencs/view/render/terraintexturemode.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 468574c032..b8181eed59 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -235,7 +235,7 @@ void CSVRender::TerrainTextureMode::drag (const QPoint& pos, int diffX, int diff void CSVRender::TerrainTextureMode::dragCompleted(const QPoint& pos) { - if (mDragMode == InteractionType_PrimaryEdit) + if (mDragMode == InteractionType_PrimaryEdit && mIsEditing) { CSMDoc::Document& document = getWorldspaceWidget().getDocument(); QUndoStack& undoStack = document.getUndoStack(); @@ -245,11 +245,8 @@ void CSVRender::TerrainTextureMode::dragCompleted(const QPoint& pos) if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted()) { - if (mIsEditing) - { - undoStack.endMacro(); - mIsEditing = false; - } + undoStack.endMacro(); + mIsEditing = false; } } } From 9788a776b9395857506b567cd89fdbf0f6c27b5f Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 10 Sep 2019 22:54:43 +0300 Subject: [PATCH 16/24] Avoid Qt "opening user openmw.cfg twice" warning --- apps/launcher/maindialog.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 2982a30f7a..637017ce81 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -329,6 +329,7 @@ bool Launcher::MainDialog::setupGameSettings() stream.setCodec(QTextCodec::codecForName("UTF-8")); mGameSettings.readUserFile(stream); + file.close(); } // Now the rest - priority: user > local > global @@ -353,8 +354,8 @@ bool Launcher::MainDialog::setupGameSettings() stream.setCodec(QTextCodec::codecForName("UTF-8")); mGameSettings.readFile(stream); + file.close(); } - file.close(); } return true; From 6b74630f6e112f18f8d7d38c0b584f8a1682cf4e Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 10 Sep 2019 21:56:10 +0300 Subject: [PATCH 17/24] Preparation work Phase out canBeActivated() to unify activation checks Use getName() for the name caption in tooltips Always use tooltips for non-activator objects Invert hasTooltip default value --- apps/openmw/mwclass/activator.cpp | 6 ++---- apps/openmw/mwclass/activator.hpp | 2 +- apps/openmw/mwclass/actor.cpp | 10 ---------- apps/openmw/mwclass/actor.hpp | 2 -- apps/openmw/mwclass/apparatus.cpp | 9 +-------- apps/openmw/mwclass/apparatus.hpp | 3 --- apps/openmw/mwclass/armor.cpp | 9 +-------- apps/openmw/mwclass/armor.hpp | 3 --- apps/openmw/mwclass/bodypart.cpp | 5 +++++ apps/openmw/mwclass/bodypart.hpp | 3 +++ apps/openmw/mwclass/book.cpp | 9 +-------- apps/openmw/mwclass/book.hpp | 3 --- apps/openmw/mwclass/clothing.cpp | 9 +-------- apps/openmw/mwclass/clothing.hpp | 3 --- apps/openmw/mwclass/container.cpp | 10 +--------- apps/openmw/mwclass/container.hpp | 4 +--- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/creaturelevlist.cpp | 5 +++++ apps/openmw/mwclass/creaturelevlist.hpp | 3 +++ apps/openmw/mwclass/door.cpp | 9 +-------- apps/openmw/mwclass/door.hpp | 3 --- apps/openmw/mwclass/ingredient.cpp | 9 +-------- apps/openmw/mwclass/ingredient.hpp | 3 --- apps/openmw/mwclass/itemlevlist.cpp | 5 +++++ apps/openmw/mwclass/itemlevlist.hpp | 3 +++ apps/openmw/mwclass/light.cpp | 6 ++---- apps/openmw/mwclass/light.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 9 +-------- apps/openmw/mwclass/lockpick.hpp | 3 --- apps/openmw/mwclass/misc.cpp | 13 ++++--------- apps/openmw/mwclass/misc.hpp | 3 --- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwclass/potion.cpp | 9 +-------- apps/openmw/mwclass/potion.hpp | 3 --- apps/openmw/mwclass/probe.cpp | 9 +-------- apps/openmw/mwclass/probe.hpp | 3 --- apps/openmw/mwclass/repair.cpp | 9 +-------- apps/openmw/mwclass/repair.hpp | 3 --- apps/openmw/mwclass/static.cpp | 5 +++++ apps/openmw/mwclass/static.hpp | 3 +++ apps/openmw/mwclass/weapon.cpp | 9 +-------- apps/openmw/mwclass/weapon.hpp | 3 --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwworld/class.cpp | 7 +------ apps/openmw/mwworld/class.hpp | 6 +----- apps/openmw/mwworld/player.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 6 +++--- 49 files changed, 66 insertions(+), 187 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 411b720fe4..c54b1c3691 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -89,9 +89,7 @@ namespace MWClass bool Activator::hasToolTip (const MWWorld::ConstPtr& ptr) const { - const MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mName != ""); + return !getName(ptr).empty(); } bool Activator::allowTelekinesis(const MWWorld::ConstPtr &ptr) const { @@ -103,7 +101,7 @@ namespace MWClass const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count); + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count); std::string text; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index b92dc75cbd..1821317d8b 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -24,7 +24,7 @@ namespace MWClass /// can return an empty string. virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) + ///< @return true if this object has a tooltip when focused (default implementation: true) virtual bool allowTelekinesis(const MWWorld::ConstPtr& ptr) const; ///< Return whether this class of object can be activated with telekinesis diff --git a/apps/openmw/mwclass/actor.cpp b/apps/openmw/mwclass/actor.cpp index aa356f62d1..4eb9728a1a 100644 --- a/apps/openmw/mwclass/actor.cpp +++ b/apps/openmw/mwclass/actor.cpp @@ -91,14 +91,4 @@ namespace MWClass { return true; } - - bool Actor::canBeActivated(const MWWorld::Ptr& ptr) const - { - MWMechanics::CreatureStats &stats = getCreatureStats(ptr); - - if (stats.getAiSequence().isInCombat() && !stats.isDead()) - return false; - - return true; - } } diff --git a/apps/openmw/mwclass/actor.hpp b/apps/openmw/mwclass/actor.hpp index c3720050cc..7cdee8061f 100644 --- a/apps/openmw/mwclass/actor.hpp +++ b/apps/openmw/mwclass/actor.hpp @@ -42,8 +42,6 @@ namespace MWClass virtual bool isActor() const; - virtual bool canBeActivated(const MWWorld::Ptr& ptr) const; - // not implemented Actor(const Actor&); Actor& operator= (const Actor&); diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index ca610efc29..b8c855d562 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -93,19 +93,12 @@ namespace MWClass return ref->mBase->mIcon; } - bool Apparatus::hasToolTip (const MWWorld::ConstPtr& ptr) const - { - const MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mName != ""); - } - MWGui::ToolTipInfo Apparatus::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count); + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index e9b6457635..98459cbd61 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -33,9 +33,6 @@ namespace MWClass virtual int getValue (const MWWorld::ConstPtr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. - virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 44e708d5b0..265b386cdb 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -199,19 +199,12 @@ namespace MWClass return ref->mBase->mIcon; } - bool Armor::hasToolTip (const MWWorld::ConstPtr& ptr) const - { - const MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mName != ""); - } - MWGui::ToolTipInfo Armor::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count); + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 6b098fa9ab..7e069701bc 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -43,9 +43,6 @@ namespace MWClass /// Return the index of the skill this item corresponds to when equipped or -1, if there is /// no such skill. - virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/bodypart.cpp b/apps/openmw/mwclass/bodypart.cpp index 41a9d998e0..0315d3ddb0 100644 --- a/apps/openmw/mwclass/bodypart.cpp +++ b/apps/openmw/mwclass/bodypart.cpp @@ -31,6 +31,11 @@ namespace MWClass return std::string(); } + bool BodyPart::hasToolTip(const MWWorld::ConstPtr& ptr) const + { + return false; + } + void BodyPart::registerSelf() { std::shared_ptr instance (new BodyPart); diff --git a/apps/openmw/mwclass/bodypart.hpp b/apps/openmw/mwclass/bodypart.hpp index 79c7c860de..cad39a2e46 100644 --- a/apps/openmw/mwclass/bodypart.hpp +++ b/apps/openmw/mwclass/bodypart.hpp @@ -21,6 +21,9 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: true) + static void registerSelf(); virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index ce08ce4224..36d623c094 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -109,19 +109,12 @@ namespace MWClass return ref->mBase->mIcon; } - bool Book::hasToolTip (const MWWorld::ConstPtr& ptr) const - { - const MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mName != ""); - } - MWGui::ToolTipInfo Book::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count); + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 4cb51ff583..9cb6fcafcc 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -27,9 +27,6 @@ namespace MWClass virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; ///< Return name of the script attached to ptr - virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index c252085952..a1a6d63680 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -157,19 +157,12 @@ namespace MWClass return ref->mBase->mIcon; } - bool Clothing::hasToolTip (const MWWorld::ConstPtr& ptr) const - { - const MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mName != ""); - } - MWGui::ToolTipInfo Clothing::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count); + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 81b5c2ef41..fd5a197b34 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -35,9 +35,6 @@ namespace MWClass /// Return the index of the skill this item corresponds to when equipped or -1, if there is /// no such skill. - virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 2b36f23390..917e7c9c15 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -252,26 +252,18 @@ namespace MWClass bool Container::hasToolTip (const MWWorld::ConstPtr& ptr) const { - if (getName(ptr).empty()) - return false; - if (const MWWorld::CustomData* data = ptr.getRefData().getCustomData()) return !canBeHarvested(ptr) || data->asContainerCustomData().mContainerStore.hasVisibleItems(); return true; } - bool Container::canBeActivated(const MWWorld::Ptr& ptr) const - { - return hasToolTip(ptr); - } - MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName); + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)); std::string text; int lockLevel = ptr.getCellRef().getLockLevel(); diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index b137411870..b49f864d7c 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -28,7 +28,7 @@ namespace MWClass ///< Generate action for activation virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) + ///< @return true if this object has a tooltip when focused (default implementation: true) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. @@ -63,8 +63,6 @@ namespace MWClass const; ///< Write additional state from \a ptr into \a state. - virtual bool canBeActivated(const MWWorld::Ptr& ptr) const; - static void registerSelf(); virtual void respawn (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index ba0bbf97f9..09040df024 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -586,7 +586,7 @@ namespace MWClass const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName); + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)); std::string text; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index e3689204a7..ffdf8be16e 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -48,7 +48,7 @@ namespace MWClass /// can return an empty string. virtual bool hasToolTip(const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) + ///< @return true if this object has a tooltip when focused (default implementation: true) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index b8c4cbb620..1dab9e4839 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -39,6 +39,11 @@ namespace MWClass return ""; } + bool CreatureLevList::hasToolTip(const MWWorld::ConstPtr& ptr) const + { + return false; + } + void CreatureLevList::respawn(const MWWorld::Ptr &ptr) const { ensureCustomData(ptr); diff --git a/apps/openmw/mwclass/creaturelevlist.hpp b/apps/openmw/mwclass/creaturelevlist.hpp index 25b5cbddfb..7fe4b1b4db 100644 --- a/apps/openmw/mwclass/creaturelevlist.hpp +++ b/apps/openmw/mwclass/creaturelevlist.hpp @@ -15,6 +15,9 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: true) + static void registerSelf(); virtual void getModelsToPreload(const MWWorld::Ptr& ptr, std::vector& models) const; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 4f144e1f7a..4d4ec05fbd 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -281,19 +281,12 @@ namespace MWClass registerClass (typeid (ESM::Door).name(), instance); } - bool Door::hasToolTip (const MWWorld::ConstPtr& ptr) const - { - const MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mName != ""); - } - MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName); + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)); std::string text; diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index b3e4e383c3..e1e9976804 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -32,9 +32,6 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index b632953919..74f38b2a20 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -105,19 +105,12 @@ namespace MWClass return ref->mBase->mIcon; } - bool Ingredient::hasToolTip (const MWWorld::ConstPtr& ptr) const - { - const MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mName != ""); - } - MWGui::ToolTipInfo Ingredient::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count); + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 668fea29a9..8598b40d74 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -24,9 +24,6 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/itemlevlist.cpp b/apps/openmw/mwclass/itemlevlist.cpp index d2c246a851..5608a8d233 100644 --- a/apps/openmw/mwclass/itemlevlist.cpp +++ b/apps/openmw/mwclass/itemlevlist.cpp @@ -10,6 +10,11 @@ namespace MWClass return ""; } + bool ItemLevList::hasToolTip(const MWWorld::ConstPtr& ptr) const + { + return false; + } + void ItemLevList::registerSelf() { std::shared_ptr instance (new ItemLevList); diff --git a/apps/openmw/mwclass/itemlevlist.hpp b/apps/openmw/mwclass/itemlevlist.hpp index a8b313185c..6e3832c279 100644 --- a/apps/openmw/mwclass/itemlevlist.hpp +++ b/apps/openmw/mwclass/itemlevlist.hpp @@ -13,6 +13,9 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: true) + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index f31df3aed2..3612e6d003 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -141,9 +141,7 @@ namespace MWClass bool Light::hasToolTip (const MWWorld::ConstPtr& ptr) const { - const MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mName != ""); + return showsInInventory(ptr); } MWGui::ToolTipInfo Light::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const @@ -151,7 +149,7 @@ namespace MWClass const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count); + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 013b9eee34..432e4a7077 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -23,7 +23,7 @@ namespace MWClass /// can return an empty string. virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) + ///< @return true if this object has a tooltip when focused (default implementation: true) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 33d4632cae..b4cd51638a 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -104,19 +104,12 @@ namespace MWClass return ref->mBase->mIcon; } - bool Lockpick::hasToolTip (const MWWorld::ConstPtr& ptr) const - { - const MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mName != ""); - } - MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count); + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index c8df860f67..29d1c06312 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -24,9 +24,6 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index af68f4743c..1a03021aef 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -134,13 +134,6 @@ namespace MWClass return ref->mBase->mIcon; } - bool Miscellaneous::hasToolTip (const MWWorld::ConstPtr& ptr) const - { - const MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mName != ""); - } - MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); @@ -159,14 +152,16 @@ namespace MWClass else // gold displays its count also if it's 1. countString = " (" + std::to_string(count) + ")"; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + countString; + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + countString; info.icon = ref->mBase->mIcon; if (ref->mRef.getSoul() != "") { const ESM::Creature *creature = store.get().search(ref->mRef.getSoul()); - if (creature) + if (creature && !creature->mName.empty()) info.caption += " (" + creature->mName + ")"; + else if (creature) + info.caption += " (" + creature->mId + ")"; } std::string text; diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 77e7d105bf..ff6c80f5af 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -24,9 +24,6 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 868ab9d85d..6458ba589e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1071,7 +1071,7 @@ namespace MWClass MWGui::ToolTipInfo info; info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)); - if(fullHelp && ptr.getRefData().getCustomData() && ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf()) + if(fullHelp && !ref->mBase->mName.empty() && ptr.getRefData().getCustomData() && ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf()) { info.caption += " ("; info.caption += MyGUI::TextIterator::toTagsString(ref->mBase->mName); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index e91dc7113b..6b8c336172 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -61,7 +61,7 @@ namespace MWClass ///< Return container store virtual bool hasToolTip(const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) + ///< @return true if this object has a tooltip when focused (default implementation: true) virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 5c40f17d3e..59c2fc006c 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -98,19 +98,12 @@ namespace MWClass return ref->mBase->mIcon; } - bool Potion::hasToolTip (const MWWorld::ConstPtr& ptr) const - { - const MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mName != ""); - } - MWGui::ToolTipInfo Potion::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count); + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 90dbe5281e..cb66c66828 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -24,9 +24,6 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 0a0c1548fa..72d9c1d9c8 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -104,19 +104,12 @@ namespace MWClass return ref->mBase->mIcon; } - bool Probe::hasToolTip (const MWWorld::ConstPtr& ptr) const - { - const MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mName != ""); - } - MWGui::ToolTipInfo Probe::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count); + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 86f6f677a8..a64c0166f3 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -24,9 +24,6 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 9050d9f94e..f334c21a10 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -93,13 +93,6 @@ namespace MWClass return ref->mBase->mIcon; } - bool Repair::hasToolTip (const MWWorld::ConstPtr& ptr) const - { - const MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mName != ""); - } - bool Repair::hasItemHealth (const MWWorld::ConstPtr& ptr) const { return true; @@ -117,7 +110,7 @@ namespace MWClass const MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count); + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; std::string text; diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index f60dbad909..20fe50b962 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -24,9 +24,6 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index a6e4fe5e79..5551b3d731 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -45,6 +45,11 @@ namespace MWClass return ""; } + bool Static::hasToolTip(const MWWorld::ConstPtr& ptr) const + { + return false; + } + void Static::registerSelf() { std::shared_ptr instance (new Static); diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index 076c39cf10..98e2fcf653 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -20,6 +20,9 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: true) + static void registerSelf(); virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 82740a2e19..ab010af063 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -155,20 +155,13 @@ namespace MWClass return ref->mBase->mIcon; } - bool Weapon::hasToolTip (const MWWorld::ConstPtr& ptr) const - { - const MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mName != ""); - } - MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const { const MWWorld::LiveCellRef *ref = ptr.get(); const ESM::WeaponType* weaponType = MWMechanics::getWeaponType(ref->mBase->mData.mType); MWGui::ToolTipInfo info; - info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count); + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count); info.icon = ref->mBase->mIcon; const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 423ba0dd27..4a35901e89 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -25,9 +25,6 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation - virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 7547f086b2..d450c014c4 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -959,7 +959,7 @@ namespace MWMechanics return true; } - if (!target.getClass().canBeActivated(target)) + if (!target.getClass().hasToolTip(target)) return true; // TODO: implement a better check to check if target is owned bed diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 191552bc5a..637a8d3da2 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -109,11 +109,6 @@ namespace MWWorld throw std::runtime_error("class cannot block"); } - bool Class::canBeActivated(const Ptr& ptr) const - { - return !getName(ptr).empty(); - } - void Class::onHit(const Ptr& ptr, float damage, bool ishealth, const Ptr& object, const Ptr& attacker, const osg::Vec3f& hitPosition, bool successful) const { throw std::runtime_error("class cannot be hit"); @@ -298,7 +293,7 @@ namespace MWWorld bool Class::hasToolTip (const ConstPtr& ptr) const { - return false; + return true; } std::string Class::getEnchantment (const ConstPtr& ptr) const diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 964ef19a5f..add70c4b6b 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -95,7 +95,7 @@ namespace MWWorld /// (default implementation: throw an exception) virtual bool hasToolTip (const ConstPtr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) + ///< @return true if this object has a tooltip when focused (default implementation: true) virtual MWGui::ToolTipInfo getToolTipInfo (const ConstPtr& ptr, int count) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. @@ -140,10 +140,6 @@ namespace MWWorld ///< Play the appropriate sound for a blocked attack, depending on the currently equipped shield /// (default implementation: throw an exception) - virtual bool canBeActivated(const Ptr& ptr) const; - ///< \return Can the player activate this object? - /// (default implementation: true if object's user-readable name is not empty, false otherwise) - virtual std::shared_ptr activate (const Ptr& ptr, const Ptr& actor) const; ///< Generate action for activation (default implementation: return a null action). diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 9e2d9d6ff4..8e047677bc 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -236,7 +236,7 @@ namespace MWWorld if (toActivate.isEmpty()) return; - if (!toActivate.getClass().canBeActivated(toActivate)) + if (!toActivate.getClass().hasToolTip(toActivate)) return; MWBase::Environment::get().getWorld()->activate(toActivate, player); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 07680e76f3..7aa9d6023a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3023,7 +3023,7 @@ namespace MWWorld target = getFacedObject(); // if the faced object can not be activated, do not use it - if (!target.isEmpty() && !target.getClass().canBeActivated(target)) + if (!target.isEmpty() && !target.getClass().hasToolTip(target)) target = nullptr; if (target.isEmpty()) @@ -3082,7 +3082,7 @@ namespace MWWorld { target = result2.mHitObject; hitPosition = result2.mHitPointWorld; - if (dist2 > getMaxActivationDistance() && !target.isEmpty() && !target.getClass().canBeActivated(target)) + if (dist2 > getMaxActivationDistance() && !target.isEmpty() && !target.getClass().hasToolTip(target)) target = nullptr; } } @@ -3650,7 +3650,7 @@ namespace MWWorld if (fromProjectile && effectInfo.mArea <= 0) continue; // Don't play explosion for projectiles with 0-area effects - if (!fromProjectile && effectInfo.mRange == ESM::RT_Touch && (!ignore.isEmpty()) && (!ignore.getClass().isActor() && !ignore.getClass().canBeActivated(ignore))) + if (!fromProjectile && effectInfo.mRange == ESM::RT_Touch && !ignore.isEmpty() && !ignore.getClass().isActor() && !ignore.getClass().hasToolTip(ignore)) continue; // Don't play explosion for touch spells on non-activatable objects except when spell is from the projectile enchantment // Spawn the explosion orb effect From 718dbd3f9a24503196d6935e931ab037b5cf3d24 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 11 Sep 2019 00:06:50 +0300 Subject: [PATCH 18/24] Use object ID as the substitution for their name (bug #5158) --- CHANGELOG.md | 1 + apps/openmw/mwclass/activator.hpp | 3 +-- apps/openmw/mwclass/apparatus.cpp | 3 ++- apps/openmw/mwclass/apparatus.hpp | 3 +-- apps/openmw/mwclass/armor.cpp | 3 ++- apps/openmw/mwclass/armor.hpp | 3 +-- apps/openmw/mwclass/bodypart.hpp | 3 +-- apps/openmw/mwclass/book.cpp | 3 ++- apps/openmw/mwclass/book.hpp | 3 +-- apps/openmw/mwclass/clothing.cpp | 3 ++- apps/openmw/mwclass/clothing.hpp | 3 +-- apps/openmw/mwclass/container.cpp | 3 ++- apps/openmw/mwclass/container.hpp | 3 +-- apps/openmw/mwclass/creature.cpp | 3 ++- apps/openmw/mwclass/creature.hpp | 3 +-- apps/openmw/mwclass/creaturelevlist.hpp | 3 +-- apps/openmw/mwclass/door.cpp | 3 ++- apps/openmw/mwclass/door.hpp | 3 +-- apps/openmw/mwclass/ingredient.cpp | 3 ++- apps/openmw/mwclass/ingredient.hpp | 3 +-- apps/openmw/mwclass/itemlevlist.hpp | 3 +-- apps/openmw/mwclass/light.cpp | 5 +++-- apps/openmw/mwclass/light.hpp | 3 +-- apps/openmw/mwclass/lockpick.cpp | 3 ++- apps/openmw/mwclass/lockpick.hpp | 3 +-- apps/openmw/mwclass/misc.cpp | 3 ++- apps/openmw/mwclass/misc.hpp | 3 +-- apps/openmw/mwclass/npc.cpp | 4 +++- apps/openmw/mwclass/npc.hpp | 3 +-- apps/openmw/mwclass/potion.cpp | 3 ++- apps/openmw/mwclass/potion.hpp | 3 +-- apps/openmw/mwclass/probe.cpp | 3 ++- apps/openmw/mwclass/probe.hpp | 3 +-- apps/openmw/mwclass/repair.cpp | 3 ++- apps/openmw/mwclass/repair.hpp | 3 +-- apps/openmw/mwclass/static.hpp | 3 +-- apps/openmw/mwclass/weapon.cpp | 3 ++- apps/openmw/mwclass/weapon.hpp | 3 +-- apps/openmw/mwworld/class.hpp | 3 +-- 39 files changed, 57 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa84ec10ae..372f9c7610 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -138,6 +138,7 @@ Bug #5134: Doors rotation by "Lock" console command is inconsistent Bug #5137: Textures with Clamp Mode set to Clamp instead of Wrap are too dark outside the boundaries Bug #5149: Failing lock pick attempts isn't always a crime + Bug #5188: Objects without a name don't fallback to their ID Feature #1774: Handle AvoidNode Feature #2229: Improve pathfinding AI Feature #3025: Analogue gamepad movement controls diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 1821317d8b..d5175b739c 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -20,8 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: true) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index b8c855d562..518695fabf 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -45,8 +45,9 @@ namespace MWClass std::string Apparatus::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); + const std::string& name = ref->mBase->mName; - return ref->mBase->mName; + return !name.empty() ? name : ref->mBase->mId; } std::shared_ptr Apparatus::activate (const MWWorld::Ptr& ptr, diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 98459cbd61..ea06f74bd5 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -20,8 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual std::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 265b386cdb..e649bba12b 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -53,8 +53,9 @@ namespace MWClass std::string Armor::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); + const std::string& name = ref->mBase->mName; - return ref->mBase->mName; + return !name.empty() ? name : ref->mBase->mId; } std::shared_ptr Armor::activate (const MWWorld::Ptr& ptr, diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 7e069701bc..e25a4ae8aa 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -19,8 +19,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual std::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/bodypart.hpp b/apps/openmw/mwclass/bodypart.hpp index cad39a2e46..b75dee7544 100644 --- a/apps/openmw/mwclass/bodypart.hpp +++ b/apps/openmw/mwclass/bodypart.hpp @@ -18,8 +18,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: true) diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 36d623c094..4ea71e3ac2 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -50,8 +50,9 @@ namespace MWClass std::string Book::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); + const std::string& name = ref->mBase->mName; - return ref->mBase->mName; + return !name.empty() ? name : ref->mBase->mId; } std::shared_ptr Book::activate (const MWWorld::Ptr& ptr, diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 9cb6fcafcc..6bdb4e79bd 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -17,8 +17,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual std::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index a1a6d63680..6d7960aac2 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -48,8 +48,9 @@ namespace MWClass std::string Clothing::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); + const std::string& name = ref->mBase->mName; - return ref->mBase->mName; + return !name.empty() ? name : ref->mBase->mId; } std::shared_ptr Clothing::activate (const MWWorld::Ptr& ptr, diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index fd5a197b34..e71e9b307b 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -17,8 +17,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual std::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 917e7c9c15..958f8351ec 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -224,8 +224,9 @@ namespace MWClass std::string Container::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); + const std::string& name = ref->mBase->mName; - return ref->mBase->mName; + return !name.empty() ? name : ref->mBase->mId; } MWWorld::ContainerStore& Container::getContainerStore (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index b49f864d7c..87826da880 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -20,8 +20,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual std::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 09040df024..aed0882edb 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -214,8 +214,9 @@ namespace MWClass std::string Creature::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); + const std::string& name = ref->mBase->mName; - return ref->mBase->mName; + return !name.empty() ? name : ref->mBase->mId; } MWMechanics::CreatureStats& Creature::getCreatureStats (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index ffdf8be16e..35688ed1ac 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -44,8 +44,7 @@ namespace MWClass ///< Add reference into a cell for rendering virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual bool hasToolTip(const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: true) diff --git a/apps/openmw/mwclass/creaturelevlist.hpp b/apps/openmw/mwclass/creaturelevlist.hpp index 7fe4b1b4db..3a05f5272c 100644 --- a/apps/openmw/mwclass/creaturelevlist.hpp +++ b/apps/openmw/mwclass/creaturelevlist.hpp @@ -12,8 +12,7 @@ namespace MWClass public: virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: true) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 4d4ec05fbd..3a0e13e625 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -102,8 +102,9 @@ namespace MWClass std::string Door::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); + const std::string& name = ref->mBase->mName; - return ref->mBase->mName; + return !name.empty() ? name : ref->mBase->mId; } std::shared_ptr Door::activate (const MWWorld::Ptr& ptr, diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index e1e9976804..fa566b98e2 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -25,8 +25,7 @@ namespace MWClass virtual bool useAnim() const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual std::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 74f38b2a20..bd61131bfc 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -47,8 +47,9 @@ namespace MWClass std::string Ingredient::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); + const std::string& name = ref->mBase->mName; - return ref->mBase->mName; + return !name.empty() ? name : ref->mBase->mId; } std::shared_ptr Ingredient::activate (const MWWorld::Ptr& ptr, diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 8598b40d74..8b2ea4f86a 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -17,8 +17,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual std::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/itemlevlist.hpp b/apps/openmw/mwclass/itemlevlist.hpp index 6e3832c279..36019f491d 100644 --- a/apps/openmw/mwclass/itemlevlist.hpp +++ b/apps/openmw/mwclass/itemlevlist.hpp @@ -10,8 +10,7 @@ namespace MWClass public: virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: true) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 3612e6d003..3bdf10f475 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -70,9 +70,10 @@ namespace MWClass const MWWorld::LiveCellRef *ref = ptr.get(); if (ref->mBase->mModel.empty()) - return ""; + return std::string(); - return ref->mBase->mName; + const std::string& name = ref->mBase->mName; + return !name.empty() ? name : ref->mBase->mId; } std::shared_ptr Light::activate (const MWWorld::Ptr& ptr, diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 432e4a7077..ba3179971e 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -19,8 +19,7 @@ namespace MWClass virtual bool useAnim() const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: true) diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index b4cd51638a..9b8abc8f23 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -47,8 +47,9 @@ namespace MWClass std::string Lockpick::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); + const std::string& name = ref->mBase->mName; - return ref->mBase->mName; + return !name.empty() ? name : ref->mBase->mId; } std::shared_ptr Lockpick::activate (const MWWorld::Ptr& ptr, diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 29d1c06312..20ca2d1666 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -17,8 +17,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual std::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 1a03021aef..4eb3eabef3 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -56,8 +56,9 @@ namespace MWClass std::string Miscellaneous::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); + const std::string& name = ref->mBase->mName; - return ref->mBase->mName; + return !name.empty() ? name : ref->mBase->mId; } std::shared_ptr Miscellaneous::activate (const MWWorld::Ptr& ptr, diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index ff6c80f5af..4812deb5f8 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -17,8 +17,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual std::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 6458ba589e..83c989bd49 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -531,7 +531,9 @@ namespace MWClass } const MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mName; + const std::string& name = ref->mBase->mName; + + return !name.empty() ? name : ref->mBase->mId; } MWMechanics::CreatureStats& Npc::getCreatureStats (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 6b8c336172..9b92f63382 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -48,8 +48,7 @@ namespace MWClass ///< Add reference into a cell for rendering virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual MWMechanics::CreatureStats& getCreatureStats (const MWWorld::Ptr& ptr) const; ///< Return creature stats diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 59c2fc006c..4af97e6345 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -49,8 +49,9 @@ namespace MWClass std::string Potion::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); + const std::string& name = ref->mBase->mName; - return ref->mBase->mName; + return !name.empty() ? name : ref->mBase->mId; } std::shared_ptr Potion::activate (const MWWorld::Ptr& ptr, diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index cb66c66828..8ec4aef446 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -17,8 +17,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual std::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 72d9c1d9c8..dba4e8c063 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -47,8 +47,9 @@ namespace MWClass std::string Probe::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); + const std::string& name = ref->mBase->mName; - return ref->mBase->mName; + return !name.empty() ? name : ref->mBase->mId; } std::shared_ptr Probe::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index a64c0166f3..51a5f8231a 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -17,8 +17,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual std::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index f334c21a10..8907c8212e 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -44,8 +44,9 @@ namespace MWClass std::string Repair::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); + const std::string& name = ref->mBase->mName; - return ref->mBase->mName; + return !name.empty() ? name : ref->mBase->mId; } std::shared_ptr Repair::activate (const MWWorld::Ptr& ptr, diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 20fe50b962..5d2cfb6828 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -17,8 +17,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual std::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index 98e2fcf653..6b3b8088c5 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -17,8 +17,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: true) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index ab010af063..0d6a27cf60 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -53,8 +53,9 @@ namespace MWClass std::string Weapon::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); + const std::string& name = ref->mBase->mName; - return ref->mBase->mName; + return !name.empty() ? name : ref->mBase->mId; } std::shared_ptr Weapon::activate (const MWWorld::Ptr& ptr, diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 4a35901e89..2c1197b69e 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -18,8 +18,7 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual std::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index add70c4b6b..1e3eefe33d 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -83,8 +83,7 @@ namespace MWWorld ///< Add reference into a cell for rendering (default implementation: don't render anything). virtual std::string getName (const ConstPtr& ptr) const = 0; - ///< \return name (the one that is to be presented to the user; not the internal one); - /// can return an empty string. + ///< \return name or ID; can return an empty string. virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; ///< Adjust position to stand on ground. Must be called post model load From 8baddefdbd808c73568bd376521f0e507da318e3 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 13 Sep 2019 19:54:19 +0300 Subject: [PATCH 19/24] Refactor extra data and particle modifier handling Objects no longer inherit from extra data class "Controlled" harmful abstraction no longer exists Introduced NiParticleModifier/NiParticleCollider abstractions Extra data size reading moved into the base read() method --- .../nifloader/testbulletnifloader.cpp | 11 ++--- components/nif/base.hpp | 42 ++++++++----------- components/nif/controlled.cpp | 35 ++++++++++++---- components/nif/controlled.hpp | 30 +++++++++---- components/nif/controller.hpp | 4 +- components/nif/extra.cpp | 11 +---- components/nif/recordptr.hpp | 6 ++- components/nifbullet/bulletnifloader.cpp | 9 +--- components/nifosg/nifloader.cpp | 12 +++--- 9 files changed, 82 insertions(+), 78 deletions(-) diff --git a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp index c94907e684..7598b63b05 100644 --- a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp +++ b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp @@ -211,15 +211,10 @@ namespace value.extra = Nif::ExtraPtr(nullptr); } - void init(Nif::Controlled& value) - { - init(static_cast(value)); - value.controller = Nif::ControllerPtr(nullptr); - } - void init(Nif::Named& value) { - init(static_cast(value)); + value.extra = Nif::ExtraPtr(nullptr); + value.controller = Nif::ControllerPtr(nullptr); } void init(Nif::Node& value) @@ -254,7 +249,7 @@ namespace value.phase = 0; value.timeStart = 0; value.timeStop = 0; - value.target = Nif::ControlledPtr(nullptr); + value.target = Nif::NamedPtr(nullptr); } void copy(const btTransform& src, Nif::Transformation& dst) diff --git a/components/nif/base.hpp b/components/nif/base.hpp index 4b2e40dec0..f67de02216 100644 --- a/components/nif/base.hpp +++ b/components/nif/base.hpp @@ -10,17 +10,19 @@ namespace Nif { -/** A record that can have extra data. The extra data objects - themselves descend from the Extra class, and all the extra data - connected to an object form a linked list -*/ +// An extra data record. All the extra data connected to an object form a linked list. class Extra : public Record { public: - ExtraPtr extra; + ExtraPtr next; // Next extra data record in the list - void read(NIFStream *nif) { extra.read(nif); } - void post(NIFFile *nif) { extra.post(nif); } + void read(NIFStream *nif) + { + next.read(nif); + nif->getUInt(); // Size of the record + } + + void post(NIFFile *nif) { next.post(nif); } }; class Controller : public Record @@ -30,43 +32,33 @@ public: int flags; float frequency, phase; float timeStart, timeStop; - ControlledPtr target; + NamedPtr target; void read(NIFStream *nif); void post(NIFFile *nif); }; -/// Anything that has a controller -class Controlled : public Extra +/// Has name, extra-data and controller +class Named : public Record { public: + std::string name; + ExtraPtr extra; ControllerPtr controller; void read(NIFStream *nif) { - Extra::read(nif); + name = nif->getString(); + extra.read(nif); controller.read(nif); } void post(NIFFile *nif) { - Extra::post(nif); + extra.post(nif); controller.post(nif); } }; - -/// Has name, extra-data and controller -class Named : public Controlled -{ -public: - std::string name; - - void read(NIFStream *nif) - { - name = nif->getString(); - Controlled::read(nif); - } -}; typedef Named NiSequenceStreamHelper; } // Namespace diff --git a/components/nif/controlled.cpp b/components/nif/controlled.cpp index 52e7a7302f..51ccf85412 100644 --- a/components/nif/controlled.cpp +++ b/components/nif/controlled.cpp @@ -31,28 +31,40 @@ namespace Nif data.post(nif); } + void NiParticleModifier::read(NIFStream *nif) + { + next.read(nif); + controller.read(nif); + } + + void NiParticleModifier::post(NIFFile *nif) + { + next.post(nif); + controller.post(nif); + } + void NiParticleGrowFade::read(NIFStream *nif) { - Controlled::read(nif); + NiParticleModifier::read(nif); growTime = nif->getFloat(); fadeTime = nif->getFloat(); } void NiParticleColorModifier::read(NIFStream *nif) { - Controlled::read(nif); + NiParticleModifier::read(nif); data.read(nif); } void NiParticleColorModifier::post(NIFFile *nif) { - Controlled::post(nif); + NiParticleModifier::post(nif); data.post(nif); } void NiGravity::read(NIFStream *nif) { - Controlled::read(nif); + NiParticleModifier::read(nif); mDecay = nif->getFloat(); mForce = nif->getFloat(); @@ -61,11 +73,17 @@ namespace Nif mDirection = nif->getVector3(); } - void NiPlanarCollider::read(NIFStream *nif) + void NiParticleCollider::read(NIFStream *nif) { - Controlled::read(nif); + NiParticleModifier::read(nif); mBounceFactor = nif->getFloat(); + } + + void NiPlanarCollider::read(NIFStream *nif) + { + NiParticleCollider::read(nif); + /*unknown*/nif->getFloat(); for (int i=0;i<10;++i) @@ -77,7 +95,7 @@ namespace Nif void NiParticleRotation::read(NIFStream *nif) { - Controlled::read(nif); + NiParticleModifier::read(nif); /* byte (0 or 1) @@ -89,9 +107,8 @@ namespace Nif void NiSphericalCollider::read(NIFStream* nif) { - Controlled::read(nif); + NiParticleCollider::read(nif); - mBounceFactor = nif->getFloat(); mRadius = nif->getFloat(); mCenter = nif->getVector3(); } diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index be48e912ea..00ff45eda9 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -66,7 +66,16 @@ public: void post(NIFFile *nif); }; -class NiParticleGrowFade : public Controlled +struct NiParticleModifier : public Record +{ + NiParticleModifierPtr next; + ControllerPtr controller; + + void read(NIFStream *nif); + void post(NIFFile *nif); +}; + +class NiParticleGrowFade : public NiParticleModifier { public: float growTime; @@ -75,7 +84,7 @@ public: void read(NIFStream *nif); }; -class NiParticleColorModifier : public Controlled +class NiParticleColorModifier : public NiParticleModifier { public: NiColorDataPtr data; @@ -84,7 +93,7 @@ public: void post(NIFFile *nif); }; -class NiGravity : public Controlled +class NiGravity : public NiParticleModifier { public: float mForce; @@ -99,29 +108,32 @@ public: void read(NIFStream *nif); }; +struct NiParticleCollider : public NiParticleModifier +{ + float mBounceFactor; + void read(NIFStream *nif); +}; + // NiPinaColada -class NiPlanarCollider : public Controlled +class NiPlanarCollider : public NiParticleCollider { public: void read(NIFStream *nif); - float mBounceFactor; - osg::Vec3f mPlaneNormal; float mPlaneDistance; }; -class NiSphericalCollider : public Controlled +class NiSphericalCollider : public NiParticleCollider { public: - float mBounceFactor; float mRadius; osg::Vec3f mCenter; void read(NIFStream *nif); }; -class NiParticleRotation : public Controlled +class NiParticleRotation : public NiParticleModifier { public: void read(NIFStream *nif); diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 113a7becdd..52ab6f1f61 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -72,8 +72,8 @@ public: int activeCount; std::vector particles; - ExtraPtr affectors; - ExtraPtr colliders; + NiParticleModifierPtr affectors; + NiParticleModifierPtr colliders; void read(NIFStream *nif); void post(NIFFile *nif); diff --git a/components/nif/extra.cpp b/components/nif/extra.cpp index b7e2216688..cb654d5a0d 100644 --- a/components/nif/extra.cpp +++ b/components/nif/extra.cpp @@ -6,8 +6,6 @@ namespace Nif void NiStringExtraData::read(NIFStream *nif) { Extra::read(nif); - - nif->getInt(); // size of string + 4. Really useful... string = nif->getString(); } @@ -15,8 +13,6 @@ void NiTextKeyExtraData::read(NIFStream *nif) { Extra::read(nif); - nif->getInt(); // 0 - int keynum = nif->getInt(); list.resize(keynum); for(int i=0; igetInt(); - int s = nif->getUShort(); - - nif->skip(s * sizeof(float)); // vertex weights I guess + nif->skip(nif->getUShort() * sizeof(float)); // vertex weights I guess } diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index e23beb7869..fbd148a046 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -127,7 +127,7 @@ class NiUVData; class NiPosData; class NiVisData; class Controller; -class Controlled; +class Named; class NiSkinData; class NiFloatData; struct NiMorphData; @@ -141,6 +141,7 @@ class NiSourceTexture; class NiRotatingParticlesData; class NiAutoNormalParticlesData; class NiPalette; +struct NiParticleModifier; typedef RecordPtrT NodePtr; typedef RecordPtrT ExtraPtr; @@ -148,7 +149,7 @@ typedef RecordPtrT NiUVDataPtr; typedef RecordPtrT NiPosDataPtr; typedef RecordPtrT NiVisDataPtr; typedef RecordPtrT ControllerPtr; -typedef RecordPtrT ControlledPtr; +typedef RecordPtrT NamedPtr; typedef RecordPtrT NiSkinDataPtr; typedef RecordPtrT NiMorphDataPtr; typedef RecordPtrT NiPixelDataPtr; @@ -162,6 +163,7 @@ typedef RecordPtrT NiSourceTexturePtr; typedef RecordPtrT NiRotatingParticlesDataPtr; typedef RecordPtrT NiAutoNormalParticlesDataPtr; typedef RecordPtrT NiPalettePtr; +typedef RecordPtrT NiParticleModifierPtr; typedef RecordListT NodeList; typedef RecordListT PropertyList; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 2f24a40674..5993d04fdf 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -260,18 +260,13 @@ void BulletNifLoader::handleNode(const std::string& fileName, const Nif::Node *n Log(Debug::Info) << "RootCollisionNode is not attached to the root node in " << fileName << ". Treating it as a common NiTriShape."; // Check for extra data - Nif::Extra const *e = node; - while (!e->extra.empty()) + for (Nif::ExtraPtr e = node->extra; !e.empty(); e = e->next) { - // Get the next extra data in the list - e = e->extra.getPtr(); - assert(e != nullptr); - if (e->recType == Nif::RC_NiStringExtraData) { // String markers may contain important information // affecting the entire subtree of this node - Nif::NiStringExtraData *sd = (Nif::NiStringExtraData*)e; + Nif::NiStringExtraData *sd = (Nif::NiStringExtraData*)e.getPtr(); if (Misc::StringUtils::ciCompareLen(sd->string, "NC", 2) == 0) { diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 568286a4d6..7699271d35 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -222,9 +222,9 @@ namespace NifOsg extractTextKeys(static_cast(extra.getPtr()), target.mTextKeys); - extra = extra->extra; + extra = extra->next; Nif::ControllerPtr ctrl = seq->controller; - for(;!extra.empty() && !ctrl.empty();(extra=extra->extra),(ctrl=ctrl->next)) + for(;!extra.empty() && !ctrl.empty();(extra=extra->next),(ctrl=ctrl->next)) { if(extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController) { @@ -524,7 +524,7 @@ namespace NifOsg node->getOrCreateUserDataContainer()->addUserObject( new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation)); - for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->extra) + for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->next) { if(e->recType == Nif::RC_NiTextKeyExtraData && textKeys) { @@ -802,13 +802,13 @@ namespace NifOsg } } - void handleParticlePrograms(Nif::ExtraPtr affectors, Nif::ExtraPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) + void handleParticlePrograms(Nif::NiParticleModifierPtr affectors, Nif::NiParticleModifierPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) { osgParticle::ModularProgram* program = new osgParticle::ModularProgram; attachTo->addChild(program); program->setParticleSystem(partsys); program->setReferenceFrame(rf); - for (; !affectors.empty(); affectors = affectors->extra) + for (; !affectors.empty(); affectors = affectors->next) { if (affectors->recType == Nif::RC_NiParticleGrowFade) { @@ -833,7 +833,7 @@ namespace NifOsg else Log(Debug::Info) << "Unhandled particle modifier " << affectors->recName << " in " << mFilename; } - for (; !colliders.empty(); colliders = colliders->extra) + for (; !colliders.empty(); colliders = colliders->next) { if (colliders->recType == Nif::RC_NiPlanarCollider) { From 790531671a6e44d02b10dca77fa95a35b99d0d0f Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 13 Sep 2019 21:29:49 +0300 Subject: [PATCH 20/24] Fix tests --- apps/openmw_test_suite/nifloader/testbulletnifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp index 7598b63b05..b02b8b9ef7 100644 --- a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp +++ b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp @@ -208,7 +208,7 @@ namespace void init(Nif::Extra& value) { - value.extra = Nif::ExtraPtr(nullptr); + value.next = Nif::ExtraPtr(nullptr); } void init(Nif::Named& value) @@ -879,7 +879,7 @@ namespace TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_not_first_extra_data_string_starting_with_nc_should_return_shape_with_null_collision_shape) { - mNiStringExtraData.extra = Nif::ExtraPtr(&mNiStringExtraData2); + mNiStringExtraData.next = Nif::ExtraPtr(&mNiStringExtraData2); mNiStringExtraData2.string = "NC___"; mNiStringExtraData2.recType = Nif::RC_NiStringExtraData; mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData); From 480000da07fe5e8138a73226df4aff752f2c1388 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 15 Sep 2019 23:17:36 +0300 Subject: [PATCH 21/24] Use Open action as fallback for companion activation (bug #5161) --- CHANGELOG.md | 1 + apps/openmw/mwclass/creature.cpp | 15 ++++++--------- apps/openmw/mwclass/npc.cpp | 24 ++++++++++++------------ 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8beb82cbf..b3f458f095 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -138,6 +138,7 @@ Bug #5134: Doors rotation by "Lock" console command is inconsistent Bug #5137: Textures with Clamp Mode set to Clamp instead of Wrap are too dark outside the boundaries Bug #5149: Failing lock pick attempts isn't always a crime + Bug #5161: Creature companions can't be activated when they are knocked down Feature #1774: Handle AvoidNode Feature #2229: Improve pathfinding AI Feature #3025: Analogue gamepad movement controls diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index ba0bbf97f9..855f083afd 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -454,18 +454,15 @@ namespace MWClass // otherwise wait until death animation if(stats.isDeathAnimationFinished()) return std::shared_ptr(new MWWorld::ActionOpen(ptr)); - - // death animation is not finished, do nothing - return std::shared_ptr (new MWWorld::FailedAction("")); } + else if (!stats.getAiSequence().isInCombat() && !stats.getKnockedDown()) + return std::shared_ptr(new MWWorld::ActionTalk(ptr)); - if(stats.getAiSequence().isInCombat()) - return std::shared_ptr(new MWWorld::FailedAction("")); + // Tribunal and some mod companions oddly enough must use open action as fallback + if (!getScript(ptr).empty() && ptr.getRefData().getLocals().getIntVar(getScript(ptr), "companion")) + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); - if(stats.getKnockedDown()) - return std::shared_ptr(new MWWorld::FailedAction("")); - - return std::shared_ptr(new MWWorld::ActionTalk(ptr)); + return std::shared_ptr(new MWWorld::FailedAction("")); } MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 868ab9d85d..0eabe8ff28 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -884,22 +884,22 @@ namespace MWClass // otherwise wait until death animation if(stats.isDeathAnimationFinished()) return std::shared_ptr(new MWWorld::ActionOpen(ptr)); + } + else if (!stats.getAiSequence().isInCombat()) + { + if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak) || stats.getKnockedDown()) + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // stealing - // death animation is not finished, do nothing - return std::shared_ptr (new MWWorld::FailedAction("")); + // Can't talk to werewolves + if (!getNpcStats(ptr).isWerewolf()) + return std::shared_ptr(new MWWorld::ActionTalk(ptr)); } - if(stats.getAiSequence().isInCombat()) - return std::shared_ptr(new MWWorld::FailedAction("")); + // Tribunal and some mod companions oddly enough must use open action as fallback + if (!getScript(ptr).empty() && ptr.getRefData().getLocals().getIntVar(getScript(ptr), "companion")) + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); - if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak) || stats.getKnockedDown()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // stealing - - // Can't talk to werewolfs - if(getNpcStats(ptr).isWerewolf()) - return std::shared_ptr (new MWWorld::FailedAction("")); - - return std::shared_ptr(new MWWorld::ActionTalk(ptr)); + return std::shared_ptr (new MWWorld::FailedAction("")); } MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr) From 83f61d16366b2c93699c2dbbc0d14ec22b9c3d56 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Thu, 12 Sep 2019 22:15:41 +0300 Subject: [PATCH 22/24] Support target color in NiMaterialColorController (bug #5159) --- CHANGELOG.md | 3 ++- components/nifosg/controller.cpp | 38 ++++++++++++++++++++++++++++---- components/nifosg/controller.hpp | 16 ++++++++++---- components/nifosg/nifloader.cpp | 8 ++++++- 4 files changed, 55 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4adb325341..dbd44a9cfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -138,8 +138,9 @@ Bug #5134: Doors rotation by "Lock" console command is inconsistent Bug #5137: Textures with Clamp Mode set to Clamp instead of Wrap are too dark outside the boundaries Bug #5149: Failing lock pick attempts isn't always a crime - Bug #5188: Objects without a name don't fallback to their ID + Bug #5159: NiMaterialColorController can only control the diffuse color Bug #5161: Creature companions can't be activated when they are knocked down + Bug #5188: Objects without a name don't fallback to their ID Feature #1774: Handle AvoidNode Feature #2229: Improve pathfinding AI Feature #3025: Analogue gamepad movement controls diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 4029e9b158..1842e00170 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -385,8 +385,9 @@ void AlphaController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) } } -MaterialColorController::MaterialColorController(const Nif::NiPosData *data) +MaterialColorController::MaterialColorController(const Nif::NiPosData *data, TargetColor color) : mData(data->mKeyList, osg::Vec3f(1,1,1)) + , mTargetColor(color) { } @@ -397,6 +398,7 @@ MaterialColorController::MaterialColorController() MaterialColorController::MaterialColorController(const MaterialColorController ©, const osg::CopyOp ©op) : StateSetUpdater(copy, copyop), Controller(copy) , mData(copy.mData) + , mTargetColor(copy.mTargetColor) { } @@ -413,9 +415,37 @@ void MaterialColorController::apply(osg::StateSet *stateset, osg::NodeVisitor *n { osg::Vec3f value = mData.interpKey(getInputValue(nv)); osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); - diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); + switch (mTargetColor) + { + case Diffuse: + { + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); + break; + } + case Specular: + { + osg::Vec4f specular = mat->getSpecular(osg::Material::FRONT_AND_BACK); + specular.set(value.x(), value.y(), value.z(), specular.a()); + mat->setSpecular(osg::Material::FRONT_AND_BACK, specular); + break; + } + case Emissive: + { + osg::Vec4f emissive = mat->getEmission(osg::Material::FRONT_AND_BACK); + emissive.set(value.x(), value.y(), value.z(), emissive.a()); + mat->setEmission(osg::Material::FRONT_AND_BACK, emissive); + break; + } + case Ambient: + default: + { + osg::Vec4f ambient = mat->getAmbient(osg::Material::FRONT_AND_BACK); + ambient.set(value.x(), value.y(), value.z(), ambient.a()); + mat->setAmbient(osg::Material::FRONT_AND_BACK, ambient); + } + } } } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 36217f31a3..d5fb56f0ef 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -281,11 +281,15 @@ namespace NifOsg class MaterialColorController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller { - private: - Vec3Interpolator mData; - public: - MaterialColorController(const Nif::NiPosData *data); + enum TargetColor + { + Ambient = 0, + Diffuse = 1, + Specular = 2, + Emissive = 3 + }; + MaterialColorController(const Nif::NiPosData *data, TargetColor color); MaterialColorController(); MaterialColorController(const MaterialColorController& copy, const osg::CopyOp& copyop); @@ -294,6 +298,10 @@ namespace NifOsg virtual void setDefaults(osg::StateSet* stateset); virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); + + private: + Vec3Interpolator mData; + TargetColor mTargetColor; }; class FlipController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 7699271d35..58e336b5d7 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -750,7 +750,13 @@ namespace NifOsg else if (ctrl->recType == Nif::RC_NiMaterialColorController) { const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); - osg::ref_ptr osgctrl(new MaterialColorController(matctrl->data.getPtr())); + // Two bits that correspond to the controlled material color. + // 00: Ambient + // 01: Diffuse + // 10: Specular + // 11: Emissive + MaterialColorController::TargetColor targetColor = static_cast((matctrl->flags >> 4) & 3); + osg::ref_ptr osgctrl(new MaterialColorController(matctrl->data.getPtr(), targetColor)); setupController(matctrl, osgctrl, animflags); composite->addController(osgctrl); } From 4a6d2cbaff17a27a0eac0676804db1a56ecf80b9 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 16 Sep 2019 14:18:41 +0400 Subject: [PATCH 23/24] Do not allow player to take items from evidence chests (bug #3609) --- CHANGELOG.md | 1 + apps/openmw/mwclass/container.cpp | 6 ++++-- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 5 +++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbd44a9cfc..1422eee754 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Bug #3109: SetPos/Position handles actors differently Bug #3282: Unintended behaviour when assigning F3 and Windows keys Bug #3550: Companion from mod attacks the air after combat has ended + Bug #3609: Items from evidence chest are not considered to be stolen if player is allowed to use the chest Bug #3623: Display scaling breaks mouse recognition Bug #3725: Using script function in a non-conditional expression breaks script compilation Bug #3733: Normal maps are inverted on mirrored UVs diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 958f8351ec..243b6ce117 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -275,9 +275,11 @@ namespace MWClass if (ptr.getCellRef().getTrap() != "") text += "\n#{sTrapped}"; - if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getCellRefString(ptr.getCellRef()); + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) + { text += MWGui::ToolTips::getCellRefString(ptr.getCellRef()); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); + if (Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "stolen_goods")) + text += "\nYou can not use evidence chests"; } info.text = text; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d450c014c4..6a35224bc7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -950,6 +950,7 @@ namespace MWMechanics return true; const MWWorld::CellRef& cellref = target.getCellRef(); + // there is no harm to use unlocked doors int lockLevel = cellref.getLockLevel(); if (target.getClass().isDoor() && @@ -1005,6 +1006,10 @@ namespace MWMechanics if (!cellref.getOwner().empty()) victim = MWBase::Environment::get().getWorld()->searchPtr(cellref.getOwner(), true, false); + // A special case for evidence chest - we should not allow to take items even if it is technically permitted + if (Misc::StringUtils::ciEqual(cellref.getRefId(), "stolen_goods")) + return false; + return (!isOwned && !isFactionOwned); } From 85bb4a76f6d7020c4fabce652826d0c62527d89a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 16 Sep 2019 14:20:43 +0400 Subject: [PATCH 24/24] Improve faction items handling (bug #5164) --- CHANGELOG.md | 1 + apps/openmw/mwbase/mechanicsmanager.hpp | 4 +-- apps/openmw/mwgui/tooltips.cpp | 19 +++++++++++--- .../mwmechanics/mechanicsmanagerimp.cpp | 25 ++++++++++++------- .../mwmechanics/mechanicsmanagerimp.hpp | 4 +-- 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1422eee754..ebf884d860 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -141,6 +141,7 @@ Bug #5149: Failing lock pick attempts isn't always a crime Bug #5159: NiMaterialColorController can only control the diffuse color Bug #5161: Creature companions can't be activated when they are knocked down + Bug #5164: Faction owned items handling is incorrect Bug #5188: Objects without a name don't fallback to their ID Feature #1774: Handle AvoidNode Feature #2229: Improve pathfinding AI diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index aecff2cc6d..d1bb5a83d9 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -130,8 +130,8 @@ namespace MWBase * If this parameter is false, it will be determined by a line-of-sight and awareness check. * @return was the crime seen? */ - virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, - OffenseType type, int arg=0, bool victimAware=false) = 0; + virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, + const std::string& factionId="", int arg=0, bool victimAware=false) = 0; /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 3891cf8a26..d6d51d4463 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -651,9 +651,22 @@ namespace MWGui { std::string ret; ret += getMiscString(cellref.getOwner(), "Owner"); - ret += getMiscString(cellref.getFaction(), "Faction"); - if (cellref.getFactionRank() > 0) - ret += getValueString(cellref.getFactionRank(), "Rank"); + const std::string factionId = cellref.getFaction(); + ret += getMiscString(factionId, "Faction"); + if (!factionId.empty() && cellref.getFactionRank() >= 0) + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Faction *fact = store.get().search(factionId); + if (fact != nullptr) + { + int rank = cellref.getFactionRank(); + const std::string rankName = fact->mRanks[rank]; + if (rankName.empty()) + ret += getValueString(cellref.getFactionRank(), "Rank"); + else + ret += getMiscString(rankName, "Rank"); + } + } std::vector > itemOwners = MWBase::Environment::get().getMechanicsManager()->getStolenItemOwners(cellref.getRefId()); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 6a35224bc7..de1780ce7c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -950,7 +950,6 @@ namespace MWMechanics return true; const MWWorld::CellRef& cellref = target.getCellRef(); - // there is no harm to use unlocked doors int lockLevel = cellref.getLockLevel(); if (target.getClass().isDoor() && @@ -1030,7 +1029,7 @@ namespace MWMechanics if (isAllowedToUse(ptr, bed, victim)) return false; - if(commitCrime(ptr, victim, OT_SleepingInOwnedBed)) + if(commitCrime(ptr, victim, OT_SleepingInOwnedBed, bed.getCellRef().getFaction())) { MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage64}"); return true; @@ -1044,7 +1043,7 @@ namespace MWMechanics MWWorld::Ptr victim; if (isAllowedToUse(ptr, item, victim)) return; - commitCrime(ptr, victim, OT_Trespassing); + commitCrime(ptr, victim, OT_Trespassing, item.getCellRef().getFaction()); } std::vector > MechanicsManager::getStolenItemOwners(const std::string& itemid) @@ -1125,7 +1124,7 @@ namespace MWMechanics // move items from player to owner and report about theft victim.getClass().getContainerStore(victim).add(item, toRemove, victim); store.remove(item, toRemove, player); - commitCrime(player, victim, OT_Theft, item.getClass().getValue(item) * toRemove); + commitCrime(player, victim, OT_Theft, item.getCellRef().getFaction(), item.getClass().getValue(item) * toRemove); } void MechanicsManager::confiscateStolenItems(const MWWorld::Ptr &player, const MWWorld::Ptr &targetContainer) @@ -1212,11 +1211,11 @@ namespace MWMechanics mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count; } if (alarm) - commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); + commitCrime(ptr, victim, OT_Theft, ownerCellRef->getFaction(), item.getClass().getValue(item) * count); } - bool MechanicsManager::commitCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, int arg, bool victimAware) + bool MechanicsManager::commitCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, const std::string& factionId, int arg, bool victimAware) { // NOTE: victim may be empty @@ -1263,13 +1262,13 @@ namespace MWMechanics } if (crimeSeen) - reportCrime(player, victim, type, arg); + reportCrime(player, victim, type, factionId, arg); else if (type == OT_Assault && !victim.isEmpty()) { bool reported = false; if (victim.getClass().isClass(victim, "guard") && !victim.getClass().getCreatureStats(victim).getAiSequence().hasPackage(AiPackage::TypeIdPursue)) - reported = reportCrime(player, victim, type, arg); + reported = reportCrime(player, victim, type, std::string(), arg); if (!reported) startCombat(victim, player); // TODO: combat should be started with an "unaware" flag, which makes the victim flee? @@ -1300,7 +1299,7 @@ namespace MWMechanics return true; } - bool MechanicsManager::reportCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, int arg) + bool MechanicsManager::reportCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, const std::string& factionId, int arg) { const MWWorld::Store& store = MWBase::Environment::get().getWorld()->getStore().get(); @@ -1471,6 +1470,14 @@ namespace MWMechanics player.getClass().getNpcStats(player).expell(factionID); } } + else if (!factionId.empty()) + { + const std::map& playerRanks = player.getClass().getNpcStats(player).getFactionRanks(); + if (playerRanks.find(Misc::StringUtils::lowerCase(factionId)) != playerRanks.end()) + { + player.getClass().getNpcStats(player).expell(factionId); + } + } if (type == OT_Assault && !victim.isEmpty() && !victim.getClass().getCreatureStats(victim).getAiSequence().isInCombat(player) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 5a8826a6a5..9e8ce87d15 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -130,7 +130,7 @@ namespace MWMechanics * @return was the crime seen? */ virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, - OffenseType type, int arg=0, bool victimAware=false) override; + OffenseType type, const std::string& factionId="", int arg=0, bool victimAware=false) override; /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) override; @@ -247,7 +247,7 @@ namespace MWMechanics bool canReportCrime(const MWWorld::Ptr &actor, const MWWorld::Ptr &victim, std::set &playerFollowers); bool reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, - OffenseType type, int arg=0); + OffenseType type, const std::string& factionId, int arg=0); }; }