Jump to content

Better Intellisense in Ultra Engine


Ultra Engine makes much better use of class encapsulation with strict public / private / protected members. This makes it so you can only access parts of the API you are meant to use, and prevents confusion about what is and isn't supported. I've also moved all internal engine commands into separate namespaces so you don't have to worry about what a RenderMesh or PhysicsNode does. These classes won't appear in the intellisense suggestions unless you were to add "using namespace UltraRender" to your code, which you should never do.

There's still a lot of extra stuff intellisense shows you from Windows headers and other things:

notsimple.thumb.png.0beb414acdeb9f29b063e823707ab6fe.png

Using the __INTELLISENSE__ macro in Visual Studio, I was able to trick the intellisense compiler into skipping include files that link to third party libraries and system headers the user doesn't need to worry about. This strips all the unnecessary stuff out of the API, leaving just basic C++ commands, some STL classes, and the Ultra Engine API. With all the garbage removed, the API seems much friendlier:

simple.thumb.png.ca3fa73542d45ab3d332009856bb5db6.png

This is one more detail that I feel helps make C++ with Ultra Engine about as easy as C# programming. You can disable this feature by adding _ULTRA_SIMPLE_API=0 in your project macros.

  • Like 4
  • Thanks 1

13 Comments


Recommended Comments

Josh

Posted

Doc URLs have been flattened a bit:
https://www.ultraengine.com/learn/CreateCamera

Getting rid of the language subfolder in the URL is better for SEO and simplfies it a bit, since I am not going to try to make different products based off the same API.

reepblue

Posted

Will this update trickle down to the app kit? Interested giving this a peak.

klepto2

Posted

Keeping everything structured and separate with a public only api is a real good step forward. This will make access to other languages much easier as you just need toward the public interface. But you need to keep in mind that the integration of some third party code especially in Vulkan may need some access to some lowlevel details, eg.: the Vulkan context these pointers should be made public in some way as well. Otherwise I really like the way ultraengine is structured..

  • Upvote 1
Josh

Posted

12 hours ago, reepblue said:

Will this update trickle down to the app kit? Interested giving this a peak.

The full engine will be out soon enough, with all the functionality of UAK included.

12 hours ago, klepto2 said:

Keeping everything structured and separate with a public only api is a real good step forward. This will make access to other languages much easier as you just need toward the public interface. But you need to keep in mind that the integration of some third party code especially in Vulkan may need some access to some lowlevel details, eg.: the Vulkan context these pointers should be made public in some way as well. Otherwise I really like the way ultraengine is structured..

Each threaded system has its own API, and these are usually not so friendly to use. The commands are like RenderNode::SetOrientation(matrix, position, quaternion, scale, color) and have strict rules on how they should be used. And they are also in a bit of flux.

Any custom Vulkan code would need to be run in a callback, since all rendering is taking place asynchronously. It will be interesting to see what kinds of things advanced devs would like to do with it once they start using it.

Josh

Posted

I got 99 problems but low framerate ain't one.

Image1.thumb.png.0319c32975051c6a09cfde8132614cd3.png

hip hop rap GIF

klepto2

Posted

I came across a lot 3rd party libs (eg: nvidias waveworks or shader libs, eg: vkFFt) need at least access to the vkInstance.  If the vkInstance is known everything else can created in the app context. 

Josh

Posted

@klepto2 Communication between threads is very interesting. Each system has a command buffer you add instructions to like this:

commandbuffer->AddCommand(std::bind(&RenderMaterial::SetColor, rendermaterial, color));

It can also use lambda functions, but I try to avoid them because they are difficult to debug.

The World::Render method signals a semaphore that tells the rendering thread "another batch of command is ready, whenever you are". Then the rendering thread executes them all like this:

for (const auto& func : commands)
{
    func();
}

That's how every system works, rendering, physics, animation, navigation, etc.

It would be entirely possible to do something like this:

commandbuffer->AddCommand(std::bind(&WaveWorks::Initialize, vkinstance));
commandbuffer->AddCommand(std::bind(&WaveWorks::Update, waveworksinstance));

And that code would get executed in the rendering thread, along with whatever else was going on.

  • Like 1
  • Thanks 1
klepto2

Posted

That is all I needed to know :) 

It looks very promising, and I am curious to see how it all works together.

Josh

Posted

I think I messed up a bit. C++ modules are probably a better way to control what gets exposed. Instead of this:

#include "UltraEngine.h"

using namespace UltraEngine;

int main(int argc, const char* argv[])
{
...

Your code will look like this:

import UltraEngine;

using namespace UltraEngine;

int main(int argc, const char* argv[])
{
...

And there is no need for any header files for the engine library at all. Hopefully. These are quite new and I'm not completely sure how they work.

Josh

Posted

To build C++ modules, all exported classes and functions go in a single .ixx file like this:

#include "UltraEngine.h"

export module UltraEngine;

namespace UltraEngine
{
	//Export classes
	export Entity;
	export World;
	export Display;
	export Window;

	//Export enums
	export WindowStyles;

	//Export functions
	export std::shared_ptr<World> CreateWorld();
	export std::vector<std::shared_ptr<Display> > GetDisplays();
	export shared_ptr<Window> CreateWindow(const WString&, const int, const int, const int, const int, shared_ptr<Display>, const WindowStyles);

	//Export overloaded function
	extern shared_ptr<Window> CreateWindow(const WString&, const int, const int, const int, const int, shared_ptr<Window>, const WindowStyles);
}

It looks like default arguments are supported, so everything looks good:

https://developercommunity.visualstudio.com/t/default-arguments-in-member-functions-do-not-work/77201

Josh

Posted

I've investigated these completely, and my conclusion right now is that C++20 modules are completely broken in Visual Studio. If you put a module in a static library and then import that lib into another project, you will get an undefined reference linking error for the simplest function, if it isn't written in the .ixx file. If you just declare the function (like a header) then it links and runs fine. I even downloaded the 2022 preview version, and the behavior is exactly the same.

It does look like modules do exactly what I want, Microsoft just doesn't have them working right yet.

reepblue

Posted

I see the examples are updated to use the module approach, so I assume you got it working. Did you try this on macOS and Linux yet? 

Josh

Posted

The documentation display just does a search and replace when the file is loaded, so I can switch it back and forth very easily. These don't appear to be working in Visual Studio yet.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...