Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Review phase] Terrain texture selection #1769

Closed
wants to merge 36 commits into from

Conversation

unelsson
Copy link
Collaborator

Terrain texture selection, based on #1414

Feedback and review is greatly appreciated. Plutonicoverkill's code had some reviews, but I don't clearly understand what are the reasonings behind those comments.

@zinnschlag
Copy link
Contributor

And here we reach the point where not having scrawl around really hurts, because I am not familiar with this stuff either.

Anyway, I did a test run and ended up with a segfault on attempting to select terrain: https://gist.github.com/zinnschlag/0916aa134ae01a2484ed24f7f5faef9d

@psi29a psi29a changed the title [Don't merge yet] Terrain texture selection [WIP] Terrain texture selection Jun 19, 2018
@psi29a
Copy link
Member

psi29a commented Jun 19, 2018

Get in the habit of using WIP in stead of Don't Merge :)

@psi29a
Copy link
Member

psi29a commented Jun 19, 2018

I know that @kcat has some experience with terrain... perhaps he can help review?

@unelsson
Copy link
Collaborator Author

unelsson commented Jun 19, 2018

I haven't got any segfaults, was there anything specific you were doing, or just clicking primary select? I don't really know how to read that gistfile, but looks like activate-function doing something with Qt.

I really don't know... Version mismatch? I'm using Qt version 5.11.0

I'll try to click everywhere and see if I can get a segfault somehow. (edit: I can't find a way to crash it)

@zinnschlag
Copy link
Contributor

Just random clicking. Still on Qt 4, but from the stack backtrace it is pretty clear that this is not a Qt problem.

@zinnschlag
Copy link
Contributor

#0 0x00000000008a7451 in ESM::Land::loadData (this=this@entry=0x7fffffffb1c0, flags=flags@entry=2,
target=target@entry=0x0) at /home/marc/OpenMW/openmw/components/esm/loadland.cpp:220
#1 0x00000000008a7c62 in ESM::Land::getLandData (this=0x7fffffffb1c0, flags=flags@entry=2)
at /home/marc/OpenMW/openmw/components/esm/loadland.cpp:349

This looks highly suspicious. Just saying.

@kcat
Copy link
Contributor

kcat commented Jun 19, 2018

I know that @kcat has some experience with terrain... perhaps he can help review?

I'm not particularly familiar with terrain-related stuff. Especially on the editor side of things.

@psi29a
Copy link
Member

psi29a commented Jun 20, 2018

@zinnschlag what file(s) are you loading to trigger this? That stacktrace looks like something in the loadland code.

@zinnschlag
Copy link
Contributor

Morrowind.esm. I doubt that it is the load code itself. Notice the this value? Very unusual. Could be a multi-threading problem or maybe an object life-time problem. Only guessing here.

@psi29a
Copy link
Member

psi29a commented Jun 20, 2018

Qt4 uses threaded renderer whilet Qt5 uses single-threaded renderer... not sure if that makes a difference?

@zinnschlag
Copy link
Contributor

Not really. I was speaking about threading in our terrain system.

@zinnschlag
Copy link
Contributor

Apparently nobody (including me) noticed the elephant in the room: Why is it trying to load terrain when I select a piece of terrain? Obviously the terrain was already loaded. Otherwise it could not have been rendered which means I couldn't have clicked on it to select it.

@Aesylwinn
Copy link
Contributor

Could be your click was interpreted as a being in one of the unloaded cells. Maybe try moving away from loaded cells and try reproducing it. I think the worldpos returned defaults to a set distance when nothing gets clicked on. (Unloaded cells just aren't rendered iirc).

@zinnschlag
Copy link
Contributor

Lol. I compiled your code again and then noticed the warning:

/home/marc/OpenMW/openmw/apps/opencs/view/render/terrainselection.cpp:17:67: warning: a temporary bound to ‘CSVRender::TerrainSelection::mCoords’ only persists until the constructor exits [-Wextra]
:mCoords {coords}, mEsmLand {esmLand}, mParentNode {parentNode}

So, yeah. One of my guesses turned out to be right. Object life-time issue.

@unelsson
Copy link
Collaborator Author

I'm trying to reproduce or understand the issue, but I don't get any errors, warnings or crashes, and furthermore, I'm clueless why mCoords would persist only until the constructor exits, as to my understanding it's defined in terrainselection.hpp correctly. If this is clear, I'd be really grateful if someone could explain this to me.

I've stopped development until this is resolved. I don't know how to approach this problem, as Zini's comments are only info I have of this, and I can't understand a problem in the code. There are some other glitches too, but crashing is so fundamental that it's probably better fixed first. There's a noticeable offset from selection grid to actual world texture grid, and cell borders don't operate/render correctly. Drag-select is also still missing.

@psi29a
Copy link
Member

psi29a commented Jun 26, 2018

What platform are you guys on? Windows, Linux or MacOS? Could be a difference in compilers... msvc vs gcc vs clang?

@unelsson
Copy link
Collaborator Author

Linux *** 4.9.107-2-MANJARO #1 SMP PREEMPT x86_64 GNU/Linux

@zinnschlag
Copy link
Contributor

That you don't get the crash isn't surprising, because undefined behaviour. However that you don't get a warning message is surprising.

Anyway, an easy fix would be to change mCoors from const CSMWorld::CellCoordinates& to simply CellCoordinates. Reference as member variables are rather strange to begin with. Not outright wrong, but most of the time a bad idea. Still trying to track down the source of the problem would be a good idea.

@zinnschlag
Copy link
Contributor

I'm clueless why mCoords would persist only until the constructor exits

Just to make this clear: It is not mCoors (because mCoors is a reference). The compiler is complaining about a temporary that is bound to mCoors.

@unelsson
Copy link
Collaborator Author

To be sure, I compiled it again from the start, and searched the log for that warning, and keywords (terrainselect.cpp) etc. but found no warnings related to this. I don't really understand when using references or pointers is good/bad, but I didn't change anything that didn't work.

Thanks for clarification anyway, it gives me at least one place to look.

@Aesylwinn
Copy link
Contributor

Compiler bug: https://stackoverflow.com/questions/10509603/why-cant-i-initialize-a-reference-in-an-initializer-list-with-uniform-initializ

I'm guessing Zini is using gcc 4. Use regular initialization to work around it.

@psi29a
Copy link
Member

psi29a commented Jun 28, 2018

@zinnschlag if you're toolchain is buggy, time to upgrade ;)

@zinnschlag
Copy link
Contributor

4.8.4. And not upgrading yet (too much stuff that would break and absolutely no time to deal with that).

@unelsson
Copy link
Collaborator Author

unelsson commented Jun 28, 2018

The code is not written by me, and I'm still fairly beginner in C++, so I'm going to milk some knowledge out of you to fix this, and learn.

So, am I understanding this correctly? Because of C++ compiler bug/feature, there's some undefined behavior occurring from list-initialization in format: variable {parameter}

and that would be fixed by using "default initialization" in format: variable (parameter)?

The former should work in C++11, but not necessarily in C++ versions before that? Does this mean that list-initialization cannot be used at all in OpenMW?

In addition, I don't see any advantages for using initializer-list with only one parameter. Is this true?

And fundamentally, I'm understanding that initializer list (member initializer list) is a different thing than list-initialization? Former is the thing happening after : in constructor, and latter is something like variable {}.

To the problem at hand, the problem seems to be affecting mCoords, as it's initialized with a parameter that is a reference. In this case, CSMWorld::CellCoordinates& coords instead of CSMWorld::CellCoordinates coords? I also don't see any advantages in using a reference here.

The full initialization list where the problem occurs also initializes variables mEsmLand {esmLand} and mParentNode {parentNode}, of which mEsmLand is a reference. Shouldn't that be changed also?

Do I need to change both - the list-initialization to default initialization, and references to default variables?

@zinnschlag
Copy link
Contributor

So, am I understanding this correctly? Because of C++ compiler bug/feature, there's some undefined behavior occurring from list-initialization in format: variable {parameter}

and that would be fixed by using "default initialization" in format: variable (parameter)?

I am not entirely sure if that is what is happening here (since the error message is noticeable different from what I am getting). But it is worth a try.

The former should work in C++11, but not necessarily in C++ versions before that

The former is a C++11 feature. It did not exist before C++11.

In addition, I don't see any advantages for using initializer-list with only one parameter. Is this true?

The initiliser-list is nearly always preferable over initilaising in the function body. Its cleaner, for some types it avoids redundant initialisation and for other types it is mandatory.

To the problem at hand, the problem seems to be affecting mCoords, as it's initialized with a parameter that is a reference. In this case, CSMWorld::CellCoordinates& coords instead of CSMWorld::CellCoordinates coords? I also don't see any advantages in using a reference here.

The problem is not the parameter. The problem is the variable itself. mCoors should not be a reference.

Let me reiterate that: Having a reference as a class member variable is usually a bad idea. It is not outright wrong (there are certainly situation where I have used them in the past), but there is typically little benefit to it and a couple of potential disadvantages (objects of the class become un-assignable for example). I would also argue that it is somewhat counter-idiomatic.

The full initialization list where the problem occurs also initializes variables mEsmLand {esmLand} and mParentNode {parentNode}, of which mEsmLand is a reference. Shouldn't that be changed also?

You can not simply remove the reference, because that would make a copy and that would be wrong in this case. However using a pointer instead of a reference would express the intend more clearly.

C++ does not have the concept of value and reference types (as in languages like C#). But CellCoordinates comes pretty close to a value type, while ESM::Land (in this context) is pretty close to a reference type.

@Aesylwinn
Copy link
Contributor

Aesylwinn commented Jun 28, 2018

Initializer list is an ambiguous term. https://en.cppreference.com/w/cpp/utility/initializer_list

Using {} over () is purely personal preference unless using initializing a vector, list, etc. with data. Here the c++ 11 standard was amended and gcc4 implements the original behavior.

@unelsson
Copy link
Collaborator Author

unelsson commented Jun 28, 2018

I ran into error message "no match for 'operator*" when backtracking and changing the reference of mCoords to a pointer, in mcoordinates in cell.cpp line 147. ( https://github.com/unelsson/openmw/blob/5419f4427b66302c2a3f37be751981804fd33b77/apps/opencs/view/render/cell.cpp#L147 ). There's still a reference as a member variable...

Anyway, changed the {} to () and tested, on my computer it works without crashing as it did before.

@zinnschlag
Copy link
Contributor

mCoords to a pointer

Nope. Not mCoors. As mentioned above that is as close as possible to a value type as something in C++ can be. Store it by value and pass it by reference.

@unelsson
Copy link
Collaborator Author

While digging into what's a pointer and what's a reference and what to do, I encountered another thing I didn't understand: What would be the point in auto and static_cast at terrainselection.ccp lines 59-60 & 67-68?

    const auto x = static_cast<int>(std::floor(toCellCoords(worldPos).first));
    const auto y = static_cast<int>(std::floor(toCellCoords(worldPos).second));

Couldn't that be as well just normal conversion from double to int?

    const int x = (int)(toCellCoords(worldPos).first + 0.5);
    const int y = (int)(toCellCoords(worldPos).second + 0.5);

@unelsson
Copy link
Collaborator Author

unelsson commented Sep 9, 2019

Tried to rebase, got into trouble with merge conflicts, which resulted in total destruction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet