Jump to content

Josh

Staff
  • Posts

    23,315
  • Joined

  • Last visited

Everything posted by Josh

  1. The reason vectors do this is because if you have a vector that is constantly resizing, its faster to just leave the capacity at its max value, because vector resize can be slow. If you are constantly pushing new objects into it, each added item will require a new memory block to be allocated and copied, so it's usually best to just leave it as-is. In fact, this is what the reserve() method is for: std::vector<int> v; v.reserve(1000); for (int n = 0; n < 1000; ++n) { v.push_back(n); }
  2. The specs on that card look okay, a bit better than a 2060: https://www.techpowerup.com/gpu-specs/geforce-rtx-3050-8-gb.c3858 If you have an existing system it might be cheaper to just upgrade the GPU.
  3. Vectors normally don't reduce their memory when they are resized. You can check their capacity to verify this. But compared to 1.6 GB (most of which is the VS debugger) the amount of memory you are freeing here is tiny. GetMemoryUsage will give you the exact number, only in debug mode.
  4. Are you sure the memory is the same? 10,000 shared pointers probably consume very little memory compared to the rest of the program.
  5. The thread class doesn't actually create a "real" thread until the thread is first launched. In this case, that would be when the Start() method is called. Thread creation is fast-ish. I mean for something like processing a pixmap across multiple threads it's fine to just create the threads and use them once...but if you are constantly creating threads it is better to have a set of threads waiting for work to do. A semaphore is really good for this, better than a mutex, if you can wrap your mind around how they work.
  6. Josh

    Editor WIP

    Yes. I have Lua set up in a way that is similar to the C++ entity component system: https://www.ultraengine.com/learn/EntityComponentSystem?lang=cpp
  7. I found an issue related to window refresh and resizing...still working on it...
  8. Thank you for the very nice description. I just checked forum permissions, and you should be able to post in the normal Bug Reports forum.
  9. Holy crap, you are the Flowgraph King. 🤯 What functionality can I add in Ultra to make this feature better?
  10. MSAA is better than FXAA. Unfortunately, Vulkan does not support a 1X multisampled texture, which means a completely separate set of shaders for when a multisampled texture buffer is in use. When I tried to explain the impracticality of this on the Vulkan forum, someone condescendingly gave me a link to a dictionary definition and explained that "multi" means "more than one". 🙄 This is why we don't yet have MSAA.
  11. Josh

    Editor WIP

    I can't say for sure but it's going faster than I thought it would.
  12. The distance member is used internally by the engine and results in a value from 0 to 1 if the ray test hits anything. You should check if the pickinfo.success member is true or false. It sounds like the ray is not currently intersecting anything. The World::Pick method can be used to determine visibility between two points, if you don't care which object is hit and you just want to see if anything is in the way. If you set the closest parameter to true then the ray will pick the closest object that is hit. The distance between the pickinfo.position Vec3 and the ray origin is your distance.
  13. There might be different ways to do this, but for the new Lua debugger I had to compile a sockets library into a DLL and load it as a Lua module. I had to use the exact same version of Lua as my program was using. I think the modules system could have also changed a bit in between the last version of LuaJIT and Lua 5.3. But yeah, it is definitely possible.
  14. I don't see anything wrong with your code. You could try to manually delete the file after this routine runs. If you are able to delete it, maybe there is a permissions issue. If the file is locked then the program isn't closing the stream. It's better to use ReadFile instead of OpenFile, in this situation, although that shouldn't make any difference. Lua's IO commands are fine to use.
  15. I'm trying to produce an error like this, but it's completely stable on my Nvidia card. Is there any reliable way to make it happen? Do you have version 1.0.1 of the engine installed? It will show the version you're on in the Updates tab in the client app.
  16. Do you think Scintilla can be compiled as a DLL module for Lua to call? It would be interesting to see if we can add a script editor tool as an extension: local function hook(event, scripteditor) --Catch menu event to open script editor if event.id == EVENT_WIDGETACTION then if event.source == scripteditor.menuitem then scripteditor.window:SetHidden(false) scripteditor.window:Activate() end --Intercept asset browser open asset event else if event.id == EVENT_OPENASSET then ext = string.lower(ExtractExt(event.text)) --If it's a code file let's steal the event if ext == "vert" or ext == "frag" or ext == "lua" then local code = LoadString(event.text) scripteditor.codearea:SetText(code) scripteditor.window:SetHidden(false) scripteditor.window:Activate() return false --the rest of the program will never see the event! ha-ha end end end local menu = program.menu:FindChild("Tools") local scripteditor = {} scripteditor.window = CreateWindow("Script Editor", 0,0,800,600,program.window, WINDOW_TITLEBAR + WINDOW_RESIZABLE) scripteditor.ui = CreateInterface(scripteditor.window) scripteditor.codearea = CreateCodeArea()---TODO! scripteditor.menuitem = CreateMenu("Script Editor", menu) --Listen for events ListenEvent(EVENT_WIDGETACTION, scripteditor.menuitem, hook, scripteditor) ListenEvent(EVENT_OPENASSET, program.assetbrowser, hook, scripteditor)
  17. Josh

    Editor WIP

    This shows a script extension that clears the thumbnail cache, adding a handy menu item for the task. Also shown is the popup tooltip-like preview.
  18. If you have a panel with a lot of sub-objects, like the object properties panel in Leadwerks, which has a ton of detailed controls for different entity properties, it can slow down the speed of your redraws when the window or side panel is resized. This is because when a widget is resized, all of its children have to be adjusted, even if they are hidden. An easy way to improve this is to set the widget layout of the panel to (1,0,1,0) when it is hidden: panel->SetHidden(true); panel->SetLayout(1,0,1,0); This locks it to the top-right so it doesn't get resized when the parent resizes, and all of its children can safely be skipped in the layout update routine, since its size does not get modified when the parent resizes. When you show the panel, do it like this: auto parent = panel->GetParent(); auto sz = parent->ClientSize(); panel->SetShape(0,0,sz.x,sz.y); panel->SetLayout(1,1,1,1); panel->SetHidden(false); When I did this with the Ultra Engine editor side tabber panels, the side panel resizing got noticeably faster. Another trick is to set a panel's background alpha to 0 if it's the same color as the underlying surface, and background rendering for that widget will be skipped: panel->SetColor(0,0,0,0); This can make redrawing a little bit faster, especially if you have a lot of overlapping panels.
  19. Updated 1.0.1 Fixed crash on exit mentioned here. May prevent possible crash from occurring when rendering some widgets for the first time in 3D interfaces. TextField widgets no longer respond to up and down keys, just right and left. This is because I plan to use the up and down keys to scroll through previous entries in the editor console, like a command prompt. Added check to prevent windows from being sent into infinite event loops.
  20. Actually, I take that back. I already programmed it with multi-line support: #include "UltraEngine.h" using namespace UltraEngine; int main(int argc, const char* argv[]) { //Get the displays auto displays = GetDisplays(); //Create a window auto window = CreateWindow("Ultra Engine", 0, 0, 800, 600, displays[0]); //Create User Interface auto ui = CreateInterface(window); //Create widget auto label1 = CreateLabel("First line\nSecond line\nThird line", 20, 20, 120, 60, ui->root, LABEL_BORDER | LABEL_CENTER | LABEL_MIDDLE ); while (window->Closed() == false) { WaitEvent(); } return 0; } However, when a 3D GUI is in use the line return is ignored: #include "UltraEngine.h" using namespace UltraEngine; int main(int argc, const char* argv[]) { auto displays = GetDisplays(); auto window = CreateWindow("Ultra Engine", 0, 0, 800, 600, displays[0]); auto framebuffer = CreateFramebuffer(window); auto world = CreateWorld(); auto camera = CreateCamera(world, PROJECTION_ORTHOGRAPHIC); camera->SetPosition(float(framebuffer->size.x) * 0.5f, float(framebuffer->size.y) * 0.5f, 0); auto font = LoadFont("Fonts/arial.ttf"); auto ui = CreateInterface(world, font, framebuffer->size); auto label = CreateLabel("First line\nSecond line\nThird line", 20, 20, 120, 60, ui->root, LABEL_BORDER | LABEL_CENTER | LABEL_MIDDLE ); while (window->Closed() == false) { world->Update(); world->Render(framebuffer); } return 0; } So I need to adjust the sprite creation code to handle multi-line text and then everything should work the same in Vulkan.
  21. PBR is in use by default. The default roughness is 1.0 (maximum) and the default metalness is 0.0 (minimum). If a metal/roughness texture is in use it will be used to multiply the metal / roughness values. Metal/roughness textures are the same as in the glTF format, with the green channel storing roughness and the blue channel storing metallic: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#metallic-roughness-material Finally, PBR lighting relies a lot on reflections. To get the correct look you must apply a diffuse and specular environment map to the world: https://www.ultraengine.com/learn/World_SetEnvironmentMap?lang=cpp The specular texture can also be used as the world background, or for a more abstract look you can use the diffuse texture as the background, as I did here: https://www.ultraengine.com/community/gallery/image/2548-asset-editor-wip/ These textures can be generated from an HDRI image with the Khronos IBL sampler tool, which is included in the Tools folder. This outputs KTX2 files, which can be loaded with the KTX2 plugin, or converted to DDS format with this code: https://www.ultraengine.com/community/blogs/entry/2780-building-a-single-file-4k-hdr-skybox-with-bc6-compression/?tab=comments#comment-14747 There are some ready-made environment maps in DDS format here you can also use: https://github.com/UltraEngine/Assets/tree/main/Materials/Environment
  22. This is the intended behavior. The TextArea widget is intended for displaying multi-line text. It might be possible in the future for labels to support multiple lines, but it needs to be done carefully because labels have a lot of alignment options in their style flags.
  23. You can create a new class derived from the object class like this: class Viewport : public Object { public: shared_ptr<Panel> panel; shared_ptr<Window> window; bool dirty; Viewport() { dirty = false; } }; auto viewport = make_shared<Viewport>(); This class can be cast to an Object, so it can be supplied in the extra parameter of ListenEvent().
  24. Okee-dokee, I have updated the documentation with another example that shows how to create an event-driven desktop application with a 3D viewport embedded in the interface:. See the third example here: https://www.ultraengine.com/learn/CreateInterface?lang=cpp Modal Loops ➰ When a window is resized, the system goes into a loop and doesn't come out of that loop until the mouse is released. This is a "blocking" or modal loop. Windows, Linux, and Mac all work like this. It's an OS-level thing, and I think it must be done to make window resizing as snappy and responsive as possible. If you are using ListenEvent you will intercept WINDOWSIZE events during the loop, but if you are using WaitEvent() you won't see anything until the mouse is let go. Therefore, in order to update the viewport window as the window is being resized, you must use an event listener. When to Render ⏰ In my OpenGL example linked to above I redraw the viewport every time a WINDOWSIZE event occurs, inside the system loop. This is probably not a good idea with Vulkan, because every time the viewport changes size it has to allocate a new color and depth buffer. (OpenGL might also do this, but if so it is hidden from the user.) It's better to resize the viewport dynamically, but only re-render the scene once the resize operation is done, the modal loop exits, and the program execution goes back to the main loop (when the WaitEvent call finishes). If you just resize the viewport without rendering again, the appearance will vary depending on the driver / manufacturer of your GPU. Nvidia drivers will stretch the image and Intel drivers will leave the image as-is, with a "hall of mirrors" effect if the window is made bigger. Either of these behaviors is fine. Minimizing Renders 📷 When you do resize a window, you will see a bunch of WINDOWPAINT events coming out of WaitEvent(), one for each mouse movement you made. If you just render the viewport every time a WINDOWPAINT event occurs, it will make your program unresponsive for a moment after you resize the window, because it has to render the viewport 100 times for no good reason. To prevent this from happening, the example keeps track of the viewport state with the "dirty" variable. If a WINDOWPAINT event occurs and the viewport has not been invalidated yet, the viewport is invalidated (the "dirty" variable is set to true) and a custom VIEWPORTRENDER event is emitted. Since this event goes to the end of the event queue, it will be evaluated last, after all the remaining WINDOWPAINT events are skipped. The result is the viewport will only render once each time the window is resized. When you run the example, the printed output will show exactly what is happening. A Bug! 🐛 🤯 Finally, this example is producing a crash on exit, so I will take a closer look today and get that fixed for you. Fix is available on branch 1.0.1!
  25. This is definitely doable. Basically, you create a child window with no titlebar and manually set its shape any time the parent window moves or resizes. To make a resizable window with a framebuffer, you also need to call AsyncRender(false) at the very beginning of your program: https://www.ultraengine.com/learn/AsyncRender?lang=cpp This will make it so the rendering all takes place inside the World::Render() call, instead of running on a separate thread. This mode is for event-driven programs instead of games that are constantly rendering. I'll put together an example for you tomorrow, but if you feel like taking a stab at it before then, look at the second example on this page: https://github.com/UltraEngine/Documentation/blob/master/CPP/OpenGL.md That is an old example using OpenGL with Ultra App Kit, but it's very similar to setting up a framebuffer in Ultra Engine. I'll get a new example up tomorrow.
×
×
  • Create New...