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

Refactor courtesy @gavrant #46

Merged
merged 20 commits into from
Aug 30, 2023
Merged

Refactor courtesy @gavrant #46

merged 20 commits into from
Aug 30, 2023

Conversation

hexabits
Copy link
Owner

No description provided.

gavrant added 20 commits May 17, 2023 23:24
- Instead of a tiny 512x512 window, open the UV editor maximized and more zoomed in
- Changed the window's type from Tool to Window. This shows the editor in Windows task bar and adds maximize/minimize buttons to its title bar.
…ight in the Name column of Block Details instead of a tooltip (for example, "Vertex 123")
…makes the code more readable.

- Fixed some compiler warnings.
- Minor refactoring here and there.
…nif data.

Primary goal: making sure that the properties of internal classes are reset on each update. That should fix some bugs happening when a nif is changed in NifSkope.
Secondary goals: optimizations and better structure of the code.

Bonuses:
- Replaced NifModel::getUserVersion2() with new NifModel::getBSVersion(). The latter has a better name and returns the version from cache (created once, on file load) instead of reading it from the header every time.
- Added static NifModel functions for very common casts of QModelIndex to NifModel.
- Replaced many "protected property + basic getter and setter" in Property classes with just "public property" to simplify the code.
- Deleted some obsolete/unused properties and functions, mainly in IControllable family of classes (nif nodes and properties).
- Fixed some compiler warnings.
- Better naming, minor optimizations, cleanup here and there.
Also fixed the wireframe flickering on the same shapes with alpha.
Skyrim SE or newer nifs used to be especially prone to these bugs.
Added pre-allocation of the result QVector.
2 big(-ish) classes sharing a single glmesh file has become unwieldy.
Main goals of the whole model refactoring:
- For NifItem and *Model (BaseModel, NifModel, etc.) methods with a QString parameter provide QLatin1String and 'const char *' overloads. QLatin1String("foo") is much faster than "foo" with its under-the-hood conversion to QString because in Qt 5 QLatin1String("foo") could be done at compile time. And this will make something like reading Skyrim SE shapes several (4 to 8) times faster.
- For *Model methods working with QModelIndex child items provide convenient overloads to work with 'NifItem *' instead. Overall, gradually migrate from using QModelIndex to 'NifItem *', at least on low level, to avoid back-and-forth conversions between QModelIndex and 'NifItem *' and to simplify the code overall.

Bonuses in this commit:
- NifItem: name(), type(), ... getters now return 'const QString &' instead of QString, to avoid wasting resources on creating a QString copy when it's not needed.
- NifItem: new hasName and hasType methods as a replacement for 'name() == "foo"' and 'type() == "foo"' ('const char *' overloads - for performance (see main goal #1), QString and QLatin1String - for uniformity).
- NifItem: new get<T> method as a shortcut for this->itemData.value.get<T>().
- NifItem: static versions of get<T> and getArray<T> methods, with a nullptr check for the item.
…ils...") if it has been called before in this session and that message box has been closed with "X" button instead of "OK".

Bonuses for Message::append:
- Set the minimum width of the message box to about a quarter of the screen resolution.
- The details are shown by default now (saves one click on "Show Details...").
- For each main window of NifSkope, its own message box is now created instead of dumping messages from all main windows into a single box.
- NifItem: Reworked cached data (row index, child link items) to make it more reliably updated.
- NifItem: Added a lot of shortcut functions to its itemData.value methods.
- BaseModel/NifModel/KfmModel: Expanded and standardized overloads for various item getters, setters and checkers. With putting more emphasis on working with NifItem * instead of QModelIndex and with some string tricks (const char * -> QLatin1String), it should result in a smaller and faster code overall.
- Many NifItem getters and setters now show a message box if they detect a problem instead of silently returning a default value or false. This is more for debug purposes, to catch and polish any rough spots in the code.
- Got rid of a bunch of repeating code (for example, in item condition evaluation).
- Gave some functions better names (for example, updateArray -> updateArraySize).
…itions for NifItem methods in BaseModel/NifModel/KfmModel classes.

See get<T> in BaseModel as an example.
…r::interpolate.

This fixes animations of some effects in NifSkope.
@hexabits hexabits merged commit 318dd1a into hexabits:dev8 Aug 30, 2023
@gavrant
Copy link

gavrant commented Sep 3, 2023

Hi! Glad that my changes have been merged, I'm all for it, was going to create a PR myself when I'm done. But there's one problem: it happened way too early. Must admit, the merged commits were still somewhat WIP and not polished for public release. For example, by now I know that I've made a few mistakes in them. And I'm currently in the middle of upgrading Mesh-Shape classes (focuses: significanly improved vertex/triangle selection, some bug fixes in nif data updates, better performance for Skyrim SE and newer meshes). And also halfway through that upgrade it finally hit me how to make all the NifModel getting/setting/checking code (the bulk of NifModel - NifItem - QModelIndex stuff) far easier to write and read. In other words, a huge "refactoring of the refactored" incoming.

@hexabits
Copy link
Owner Author

hexabits commented Sep 4, 2023

@gavrant
Is anything inherently broken? NifSkope 2.0 has always been "Dev" pre-alpha releases, i.e. use at your own risk. I reviewed most of your changes and didn't have any objections, only glowing praise.

Also I will be merging lots of things from other branches but I have to do most of it manually now since your refactor was so significant (though very welcome). So maybe keep an eye on pushes because you may start having merge conflicts with my branch.

@gavrant
Copy link

gavrant commented Sep 4, 2023

Nothing seriously broken, it's mostly stuff like a typo in an error message, BaseModel::getItem not passing reportErrors arg downstream, or set<int>( header, "BS Header\\BS Version", 0 ) in NifModel::loadHeader doing nothing because of the set<int>( header, "User Version", 0 ) right above.

At the moment, the biggest issue for me is that I'm somewhat at a crossroads of what to do with my "how to make all the NifModel getting/setting/checking code far easier to write and read" idea. Here's an example of working with NifModel items to illustrate the idea:

void Foo( const NifModel * nif, const QModelIndex & index, int link )
{
    // Get first (0) child of "Children" subitem of index, then get its value as link and convert it to a NifItem.
    // With the old code it would be:
    // auto block1 = nif->getBlockItem( nif->getLink( nif->getItem( index, "Children" ), 0 ) );
    auto block1 = ( *nif >> index >> "Children" >> 0 ).getLinkBlock();

    // Same as above, but report the error if it fails to get "Children" or 0 subitems.
    // Also check if the result link block inherits BSTriShape.
    auto block2 = ( *nif >> index ).child( "Children" ).child( 0 ).getLinkBlock( "BSTriShape" );

    // Resolve link as a NifItem, get its "Name" subitem, get its value as QString
    QString someStr = ( *nif >> link >> "Name" ).get<QString>();
    
    if ( block1.inherits( "BSTriShape" ) ) {
        // Get tangent value of each vertex in "Vertex Data"
        for ( auto vertex : ( block1 >> "Vertex Data" ).childIterator() )
            Vector3 t = ( vertex >> "Tangent" ).get<Vector3>();
    }
    
    ( block1 >> "Name" ).set<QString>( "Hello" ); // Compile error because nif is a const pointer
}

Note that the code does not use NifItem pointers directly, it's all actually objects of a container class for NifItem * instead, to make it more in the "functional programming" style.

Pros: in my opinion, this makes the code shorter and cleaner, easier to read and write. It would also allow to ditch tons of overloads for methods in NifModel class.

Cons: without a rewrite of all the existing code (spells, nodes, etc.) it's somewhat semi-useless. And not only a total rewrite would require a lot of time from me (I can afford that), but it will make merging code from other people very arduous, far more so than it is now with my previous refactor.

What's your opinion? Is this idea worthy of implementing and merging here, despite all the time and effort it would require from me and you? Maybe it's worthy, but without the total rewrite of spells, nodes, etc.?

@hexabits
Copy link
Owner Author

hexabits commented Sep 4, 2023

@gavrant

Oh also, btw, if you run File Checker and there are any errors, the new reportError stuff will create errors because the checker is threaded and the dialogs can't be created from another thread.

I'll read and respond to your new message after I'm done trying to debug these issues with updating NifSkope to the latest nif.xml.

@hexabits
Copy link
Owner Author

hexabits commented Sep 4, 2023

I'll read and respond to it even further in a bit, but initial thoughts, I really don't like the syntax.

Secondly, I think the most important thing about a major refactor would be moving away from naive strings as the field identifiers. It's extremely problematic when it comes to nifxml changing names and then NifSkope not knowing about it. The use of an incorrect field identifier should ideally be a compile error. I have some prototypes of how to approach this buried somewhere, maybe in my Gists, and I will dig those up sometime to show you.

@gavrant what is your Discord username? I think maybe we should chat on there instead. I can send you a friend requrest. Edit: Or you can just request me, mine is hexabit.

@gavrant
Copy link

gavrant commented Sep 4, 2023

I guess the dot in hexabit. is not actually a part of the Discord username? Just in case, my username is the same as here - gavrant.

@hexabits
Copy link
Owner Author

hexabits commented Sep 4, 2023

@gavrant no the dot is intentional. Someone managed to somehow take my name when discord switched to the new format... XD .. It says you're not accepting friend requests so you'll have to request me.

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

Successfully merging this pull request may close these issues.

2 participants