Terrain Editing

Involved development of the OpenMW construction set.
Post Reply
unelsson
Posts: 227
Joined: 17 Mar 2018, 14:57

Re: Terrain Editing

Post by unelsson »

Got this far with testing code today... Idea is to std::cout all kinds of stuff from CSMWorld::UniversalId::Type_LandTextures just to see what it has eaten. There seems to be functions for searching with Id, but I haven't succesfully used anything yet. It's of class IdTable, rows 0,1,2 have Id's 1,2,3 etc. which I understand would be the Id's used to get filenames of textures and used as data in land texture grid. Had problems with dynamic casting document, though I'm not sure if that's needed anyway. Although this project is far beyoynd my coding skills, at least I'm learning a lot all the time. Will continue later...

Code: Select all

CSMDoc::Document& document = getWorldspaceWidget().getDocument();
    CSMWorld::IdTable& ltexs = dynamic_cast<CSMWorld::IdTable&> (
        *document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));

    std::cout << "rowCount: " << ltexs.rowCount() << std::endl;
    std::cout << "columnCount: " << ltexs.columnCount() << std::endl;
User avatar
Zini
Posts: 5538
Joined: 06 Aug 2011, 15:16

Re: Terrain Editing

Post by Zini »

The getTableModel function returns a pointer to a QAbstractItemModel of which IdTable is a subclass. QAbstractItemModel provides an interface for basic table operations (e.g. rowCount, columnCount). Therefore in the code example you have given the cast would be unnecessary. However if you need special functions from IdTable, then the cast is required.

Regarding the search function: That would be getRecord and that is actually a find function (i.e. searching for something that doesn't exist would be an error).

I guess you ran into searchColumnIndex instead? There are two ways to address columns, either via a ColumnId or via a numeric index (first column in a table has index 0, second column has index 1 and so on). The searchColumnIndex and findColumnIndex are merely a way to translate between these.
unelsson
Posts: 227
Joined: 17 Mar 2018, 14:57

Re: Terrain Editing

Post by unelsson »

Thanks again Zini, made some small progress.

I was now able to get some data out of CSMWorld::UniversalId::Type_LandTextures. I decided to just cout everything to understand what's in there.

Code: Select all

    //Load Land Texture Data
    CSMDoc::Document& document = getWorldspaceWidget().getDocument();
    CSMWorld::IdTable& ltexs = dynamic_cast<CSMWorld::IdTable&> (
        *document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));

    //Temporary code for debugging purposes
    std::cout << "rowCount: " << ltexs.rowCount() << std::endl;
    std::cout << "columnCount: " << ltexs.columnCount() << std::endl;

    for( int i = 0; i < ltexs.rowCount(); i = i + 1 ) {
      for( int j = 0; j < ltexs.columnCount(); j = j + 1 ) {
        QModelIndex index = ltexs.index(i,j);

        QVariant qv = ltexs.data(index, 0);   //return mColumns.at (column)->get (mRecords.at (index));
        QString qs = qv.toString();
        std::string utf8_text = qs.toUtf8().constData();

        std::cout << "Typename: " << qv.typeName() << ", i = " << i << ", j = " << j << ", value = "<< utf8_text << std::endl;;
      }
    }
The result is something like this:

Code: Select all

Typename: QString, i = 0, j = 0, value = L0#0
Typename: int, i = 0, j = 1, value = 2
Typename: int, i = 0, j = 2, value = 90
Typename: QString, i = 0, j = 3, value = Sand
Typename: int, i = 0, j = 4, value = 0
Typename: int, i = 0, j = 5, value = 0
Typename: QString, i = 0, j = 6, value = Tx_sand_01.tga
Typename: QString, i = 1, j = 0, value = L0#1
Typename: int, i = 1, j = 1, value = 2
Typename: int, i = 1, j = 2, value = 90
Typename: QString, i = 1, j = 3, value = Rock_Coastal
Typename: int, i = 1, j = 4, value = 0
Typename: int, i = 1, j = 5, value = 1
Typename: QString, i = 1, j = 6, value = Tx_coastal_rock_01.tga
Typename: QString, i = 2, j = 0, value = L0#2
Typename: int, i = 2, j = 1, value = 2
Typename: int, i = 2, j = 2, value = 90
Typename: QString, i = 2, j = 3, value = Road Dirt
Typename: int, i = 2, j = 4, value = 0
Typename: int, i = 2, j = 5, value = 2
Typename: QString, i = 2, j = 6, value = Tx_dirtroad_01.tga
...
So it seems to be in order:
1 = L0#[TEXTURENUMBER]
2 = 2
3 = 90
4 = [NICKNAME]
5 = 0
6 = [INT] (is this the one used as id in land texture grids?)
7 = [FILENAME]

Zinnslagh at Github: "There is also CSMWorld::UniversalId::Type_Textures, which lists all bitmap resources via their filename." That would be the next data structure to understand, does it have all textures loaded as bitmaps?

I also tried to get my brush buttons (that are modebuttons, submode) to accept drag&drop, but was unable to do so. For debugging, I tested setAcceptDrops(true) to almost every constructor I could think of and tried making new dropEvent's and dragEnterEvent's with event->acceptProposedAction() under CSVWidget::ModeButton, CSVWidget::BrushButton (new class I briefly tried to create), and to CSVRender::TerrainTextureMode. Nothing seemed to work, there is something blocking the drag somewhere. On the other hand, I was able to enable dragging to TerrainTextureMode via worldspacewidget, but that doesn't really provide the functionality of dragging texture to brush.
User avatar
Zini
Posts: 5538
Joined: 06 Aug 2011, 15:16

Re: Terrain Editing

Post by Zini »

There seem to be a couple of misunderstandings. There is no need to test or cout anything. The tables are defined in CSMWorld::Data::Data. You can just look them up in the source.

The LandTexture table is the list of textures used in the land texture grid. The actual land texture grid can be found in the Land table.
Zinnslagh at Github
Lol! Haven't seen my name butchered that badly (not offended, I am used to it by now)
That would be the next data structure to understand, does it have all textures loaded as bitmaps?
Textures are be loaded into the resources system when OpenSceneGraph needs them. You might be able to hook into it, but that sounds like a lot of unnecessary work. For use in buttons I would just load the files directly. The Type_Textures table is just a simple list of filenames.

Not sure about the drag and drop problem. Not that familiar with this part of Qt and I don't have time to research it right now.

Edit: Okay, file handling seems to be a bit more complicated. You probably want to go through our virtual file system (found in components/vfs. CSMWorld::Data has an instance of that (mVFS). Depending how you intend to access the texture this may require extra work.
unelsson
Posts: 227
Joined: 17 Mar 2018, 14:57

Re: Terrain Editing

Post by unelsson »

Testing and using cout is just my method to ensure that I'm on right track. Looking through the code isn't always easy for me, I get often lost in it with all the classes built on baseclasses, templates etc. For me, the process goes something like this: To look through CSMWorld::Data::Data -> grep -rl "CSMWorld::Data::Data" -> data.cpp. See line "addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Textures)), UniversalId::Type_Texture);" -> I don't understand what any of this means, so I have to read a lot of functions and definitions, and it takes ages to find it all out. Often the chain of commands and classes is so long that I can't be sure if I understood it correctly, therefore using cout is a way for me to ensure that I'm getting the data I want before I develop things further. I keep learning by doing, but on the other hand, all advice regarding coding or OpenMW is greatly appreciated.

I'll see about the virtual file system, and get deeper into Qt's drag&drop. It will take time though.

Sorry bout the name. Zinnschlag. Right?
unelsson
Posts: 227
Joined: 17 Mar 2018, 14:57

Re: Terrain Editing

Post by unelsson »

Now, for my programming exercise though:

Code: Select all

CSMWorld::IdTable& ltexsdata = static_cast<CSMWorld::IdTable&> (
        *document.getData().getTableModel (CSMWorld::UniversalId::Type_Textures)); //ResourceTable
Code above with static_cast seems to work with Type_Textures. That gives me all the texture filenames to play with. I tried with dynamic_cast, but it gives me a bad cast. I have no idea why. I don't know any alternative to casting to read the data in tables Type_Textures or Type_LandTextures.

Next job -> Understanding Qt's drag&drop and opencs vfs, so that I can drag&drop a texture to brush button, and read the texture bitmap to use it as an overlay to brush icon.

edit: By allowing drag&drop via scenetoolmode.hpp I was able to get most of the buttons accept drag. Scene visibility-buttons and Run OpenMW buttons still don't accept drag&drop. It seems most buttons are following their parents permissions on drag&drop, even if all modebuttons are set to accept drag&drop by default. I wonder if there's something strange about button size, as dragging above modebuttons results in drag events of the parent (scenetoolmode) instead of the buttons own dragevents.

edit2: Tried to implement new window class, and open it, but although everything does compile and run, nothing is shown. Might be either that the window gets destroyed before it's properly seen (tested this with brushWindow.show(); sleep(1); but still nothing), or related to something OpenMW-CS under the hood.. I don't know.. event filter? threads?
unelsson
Posts: 227
Joined: 17 Mar 2018, 14:57

Re: Terrain Editing

Post by unelsson »

About my previous problem with window opening:

Having this at TerrainTextureMode::activate or in constructor of TerrainTextureMode does not result in a visible window.

Code: Select all

BrushWindow brushWindow;
Whereas defining variable at header, and defining brushWindow here, seems to work. Is it a parenting issue then?

Code: Select all

CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, QWidget *parent)
: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent)
, mSubMode (0), brushWindow(new BrushWindow(this))
{}
edit: About my previous problem with drag&drop, I can get my class BrushButton (QPushButton) to accept dragged content in a separate window. For some reason, similar methods with ModeButton inside SceneToolMode don't work. I have yet to try whether this BrushButton class works inside SceneToolMode.
User avatar
Zini
Posts: 5538
Joined: 06 Aug 2011, 15:16

Re: Terrain Editing

Post by Zini »

Code above with static_cast seems to work with Type_Textures. That gives me all the texture filenames to play with. I tried with dynamic_cast, but it gives me a bad cast. I have no idea why. I don't know any alternative to casting to read the data in tables Type_Textures or Type_LandTextures.
That's why you shouldn't use static_cast when dealing with polymorphism. This code is wrong and by using a static_cast instead of a dynamic_cast you disable all checks, meaning you run into undefined behaviour.

The textures table is not an IdTable and therefore you are not allowed to cast it to one. That your code didn't explode was pure luck (or bad luck, depending on how you see it). As mentioned before the relevant code is in CSMWorld::Data::Data. Have a look again at the addModel section at the bottom.

Regarding your window issue: I don't have enough context to answer your question.

Edit: If you are having problems with the class hierarchy it might be worth a try to run a tool with visualisation functions over it (e.g. doxygen with the right settings).

Edit 2: It seems we still have support for doxygen (in the docs directory). But that hasn't been touched in years. No idea if it still works.
unelsson
Posts: 227
Joined: 17 Mar 2018, 14:57

Re: Terrain Editing

Post by unelsson »

Thanks for the clarification. I've read that static_cast doesn't do some checks, and can lead to trouble. I don't really understand that deeply though. I noticed that ResourceTable is based on something called IdTableBase, so I decided to just try with static_casting to IdTable. For some reason I didn't realize I could just dynamic_cast to ResourceTable instead.
unelsson
Posts: 227
Joined: 17 Mar 2018, 14:57

Re: Terrain Editing

Post by unelsson »

So, status update of pull request #1665. I have decided to go with creating a separate window for texture brush settings. Currently it's possible to select from four brush shapes, drag&drop textures from landtextures-window to buttons, and the window will hold the id of dragged texture. Next thing would be to create a slider and box for setting brush size.

My coding is getting better and faster, and I expect slightly faster development speed as I understand the code a bit better now. I have also cleaned up the code a bit, but there's still work to do. I'm also not sure if there are memory leaks in the code - currently I've tried to use standard classes or qt-derived classes for widgets and variables. Therefore I intend to leave as much of the memory management to Qt and std-libraries as possible.
Post Reply