Beginners' questions: Understanding OpenMW/OpenCS code

Everything about development and the OpenMW source code.
unelsson
Posts: 227
Joined: 17 Mar 2018, 14:57

Beginners' questions: Understanding OpenMW/OpenCS code

Post by unelsson »

Someone said "only stupid questions are those left unasked". So...

I'm making a thread for beginner/beginner-intermediate coders questions on understanding C++ code of OpenMW. Googling etc. goes far, but then there comes a point where it's easier to understand by asking questions directly related to OpenMW. This hopefully doesn't take time away from actual development, but instead gives an opportunity for experienced developers to help us beginners. And why not, beginners might be able to help other beginners too!

* * * * * Here comes the first question * * * * *

I've learned quite a bit this week, but there are still common structures in code that I don't properly grasp. Currently I'm trying to understand what's in struct CSMWorld::LandHeightsColumn. I understand that it's a struct, based on Column that's a template, based on CSMWorld::NestableColumn, finally based on struct ColumnBase. With the following code, I've been able to cout basic integers belonging to LandHeightsColumn's part that's based on ColumnBase.

(code requires #include columnimp.hpp)

Code: Select all

CSMWorld::LandHeightsColumn MyLandHeightsColumn; // struct LandHeightsColumn : public Column<Land>
std::cout << MyLandHeightsColumn.mColumnId << std::endl;
std::cout << MyLandHeightsColumn.getId() << std::endl;
However, I don't know how to access LandHeightsColumn's get or set. The question is - how do I access that?

To understand this further - there are more defining questions: Is LandHeightsColumn::get() a function that returns a QVariant that has "values"? Or is it a QVariant variable? Should the following code work, if I had a proper argument?

Code: Select all

QVariant MyAlsoLandHeightsColumn;
    MyAlsoLandHeightsColumn = MyLandHeightsColumn.get(ARGUMENT?);
    int i[] = MyAlsoLandHeightsColumn.toInt();
Below is a definition from columnimp.hpp

Code: Select all

    LandHeightsColumn::LandHeightsColumn()
        : Column<Land>(Columns::ColumnId_LandHeightsIndex, ColumnBase::Display_String, 0)
    {
    }

    QVariant LandHeightsColumn::get(const Record<Land>& record) const
    {
        const int Size = Land::LAND_NUM_VERTS;
        const Land& land = record.get();

        DataType values(Size, 0);

        if (land.isDataLoaded(Land::DATA_VHGT))
        {
            for (int i = 0; i < Size; ++i)
                values[i] = land.getLandData()->mHeights[i];
        }

        QVariant variant;
        variant.setValue(values);
        return variant;
    }
Last edited by unelsson on 28 Mar 2018, 11:19, edited 3 times in total.
unelsson
Posts: 227
Joined: 17 Mar 2018, 14:57

Re: Beginners' questions: Understanding OpenMW code

Post by unelsson »

Q_DECLARE_METATYPE(CSMWorld::LandHeightsColumn::DataType)
This was at the end of the code. Didn't notice it before. This is a good clue on what that is in code above. Next would be to find out what that Record<Land> type is and where are records stored in OpenCS code.
Last edited by unelsson on 28 Mar 2018, 11:18, edited 2 times in total.
unelsson
Posts: 227
Joined: 17 Mar 2018, 14:57

Re: Beginners' questions: Understanding OpenMW code

Post by unelsson »

As I'm still looking for properly understanding the first question. However I went on and tried to get into CS's data structures. I find it pretty complex, so if someone would like to open this up, I'd be grateful. Here's though where I'm standing right now:

data.hpp defines classes, like mLand to hold data. mLand is of class idCollection.
data.cpp adds Columns to idCollection mLand. Technically mLand therefore is a class idCollection that holds data structures.
idcollection.hpp defines that idCollection is based on CollectionBase, which is a class defined in collectionbase.hpp.

To Collections, therefore also to idCollection, you can add Column(s), that are templates defined in columnbase.hpp.
Column(s) are templates, if I got this right, based on class NestableColumn, that's based on struct ColumnBase.

LandHeightColumn, defined in columnimp.hpp, is a struct, based on template Column. (Column->NestableColumn->ColumnBase).
To get back to start, data.cpp line "mLand.addColumn (new LandHeightsColumn);" can be said to be class iDCollection holding struct LandHeightsColumn that is a Column that is a NestableColumn that is a ColumnBase. Am I on right track?
User avatar
Zini
Posts: 5538
Joined: 06 Aug 2011, 15:16

Re: Beginners' questions: Understanding OpenMW/OpenCS code

Post by Zini »

Sorry, that I didn't see this earlier. Let me sum things up a bit and if you then still have questions you can ask them again.

The OpenMW-CS data structures consist of two layers: There is the data itself in CSMWorld::Data. And then there are tables used to expose this data to Qt.

The Data is made up of a individual collection, each holding a list of records.

Code that wants to read the data can use either. However code that wants to change the data must go through the command system. You can not ever (outside of loading) manipulate document data directly.

The column structs function as a binding element between the low level data structures (in Data) and the tables. As a rule of thumb you don't use Columns directly. You would only work on them if you were to rewrite or other modify the data structure itself, which is not likely to be part of this task.
unelsson
Posts: 227
Joined: 17 Mar 2018, 14:57

Re: Beginners' questions: Understanding OpenMW/OpenCS code

Post by unelsson »

I can't get variable value from a button to parent window, so maybe someone can help. I've tried running get functions at child with parent()->getFunction() and vice versa, I've also tried QT's connect, but it denies nested classes having custom signals and slots. I've also tried to just connect without signal/slot -macros, but doing that I run into pages of compile errors.

edit: is using nested classes even sensible here?

Code: Select all

CSVRender::TerrainTextureMode::activate
{
    BrushWindow called brushWindow is created here.
}

CSVRender::TerrainTextureMode::BrushWindow
{
    Here I want to do something with mBrushTexture that is nested inside objects button1, button2, button3 and button4 of BrushButton-class.
}

CSVRender::TerrainTextureMode::BrushWindow::BrushWindow
{
    Buttons of class BrushButton (CSVRender::TerrainTextureMode::BrushWindow::BrushButton) are created. They are called button1, button2, button3 and button4. They are parents of "this".
}

void CSVRender::TerrainTextureMode::BrushWindow::BrushButton::dropEvent (QDropEvent *event)
{
    std::string mBrushTexture gets a value here.
}
edit: I read at Qt's site that something called Boost might interfere with signals and connections? What's the case with openMW?
User avatar
Zini
Posts: 5538
Joined: 06 Aug 2011, 15:16

Re: Beginners' questions: Understanding OpenMW/OpenCS code

Post by Zini »

I don't have the slightest idea what you are talking about. Anyway, with Qts precompiler as tricky as it is using nested classes that derive from QObject is not a great idea.
unelsson
Posts: 227
Joined: 17 Mar 2018, 14:57

Re: Beginners' questions: Understanding OpenMW/OpenCS code

Post by unelsson »

Zini wrote: 07 Apr 2018, 13:05 I don't have the slightest idea what you are talking about. Anyway, with Qts precompiler as tricky as it is using nested classes that derive from QObject is not a great idea.
Me neither :lol:

But thanks for the tip. I moved everything out of nested classes, changed class names more unique, and qt connect works like it should now.
unelsson
Posts: 227
Joined: 17 Mar 2018, 14:57

Re: Beginners' questions: Understanding OpenMW/OpenCS code

Post by unelsson »

I'm working on OpenCS texture editing brushes, and got into trouble with converting textures to brush icons. It's essentially about converting osg images to Qt pixmaps. There are several examples online, but I can't make anything work. Code below is modified from opencs/view/render/cellwater.cpp.

Code: Select all

std::string textureName = "textures/tx_sand_01.dds";
    Resource::ImageManager* imageManager = mData.getResourceSystem()->getImageManager();
    osg::ref_ptr<osg::Texture2D> brushTextureOsg = new osg::Texture2D();  // Texture2D
    brushTextureOsg->setImage(imageManager->getImage(textureName));

    // How to convert osg::Texture2d brushTextureOsg to Qpixmap pixmap
    // It's easy to get osg::image with brushTextureOsg->getImage() if it helps

    QPixmap pixmap;
    pixmap.fromImage(img);

    QIcon brushIcon(pixmapObject);
    return brushIcon;
More straightforward method, I assume, would be to use VFS::Manager to open files, but I'm unfamiliar how istream-stuff works.
User avatar
Zini
Posts: 5538
Joined: 06 Aug 2011, 15:16

Re: Beginners' questions: Understanding OpenMW/OpenCS code

Post by Zini »

It seems osg::Image has a data function and QPixMap has a loadFromData function. If you can make sure that the QPixMap is initialised properly and that the data formats are matching, these should go together nicely.
unelsson
Posts: 227
Joined: 17 Mar 2018, 14:57

Re: Beginners' questions: Understanding OpenMW/OpenCS code

Post by unelsson »

Something like that was mentioned some forum's online, and after some troubleshooting and googling it turns out osg has pixformat 33776 -> 0x83f0 -> GL_COMPRESSED_RGB_S3TC_DXT1_EXT and Qt only accepts uncompressed (or files compressed as common types like jpg or png). Troublesome.
Post Reply