reepblue Posted January 3, 2023 Share Posted January 3, 2023 Ok, then how would someone make a loading bar or spinner when the map is loading? I recall this being asked around a lot during the Leadwerks days. Would I put the spinner on the separate thread instead since that just needs to rotate/change images? Something else to consider is you probably want background map loading when VR gets implemented. Maybe official level streaming support can come later, idk. I'm more worried about my skinned meshes not reloading and some of my prefabs still have their UVs messed up when it comes to scene loading at the moment than a silly spinny wheel. Cyclone - Ultra Game System - Component Preprocessor - Tex2TGA - Darkness Awaits Template (Leadwerks) If you like my work, consider supporting me on Patreon! Link to comment Share on other sites More sharing options...
Josh Posted January 3, 2023 Author Share Posted January 3, 2023 The renderer actually will keep going while the map is loading, even if it is blocking the main thread. In VR this means you can still look around at whatever is currently in the world, and everything works fine. You can use a shader the uses the current time to rotate one of those never-ending load indicators because it does not require any new information to come from the blocked main thread. I have thought about a LoadScene callback you could use to relay the loading progress from the main thread to the rendering thread, but I am not sure yet how that would work. Calling World::Render() in the middle of a callback would cause the scene to appear piece-by-piece. Maybe that would work if you were using render layers to control what the camera sees, or loading the scene into a separate world from the one that is being rendered. I'm not sure yet. My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
reepblue Posted January 3, 2023 Share Posted January 3, 2023 I guess I'll have experiment with it more outside debug mode as the application cames to a screeching hault when loading big maps. In reale it's 10x faster. 8 minutes ago, Josh said: You can use a shader the uses the current time to rotate one of those never-ending load indicators because it does not require any new information to come from the blocked main thread. Hopefully this will be easier to do in the future. Kind of shy to learn shaders with them being massive this time around. Cyclone - Ultra Game System - Component Preprocessor - Tex2TGA - Darkness Awaits Template (Leadwerks) If you like my work, consider supporting me on Patreon! Link to comment Share on other sites More sharing options...
klepto2 Posted January 3, 2023 Share Posted January 3, 2023 just a small proof of concept i made: The top line ShaderValidator::ShaderCompiler::Compile(); is the interessting part. This method parses all json shaderfamilies and extracts the required shader files and tries to locate the correct source and target. then it takes all of the found shaders and recompiles them to Spirv-binary files in code before any shader is loaded. 1 Windows 10 Pro 64-Bit-Version NVIDIA Geforce 1080 TI Link to comment Share on other sites More sharing options...
Josh Posted January 3, 2023 Author Share Posted January 3, 2023 Update Made a lot of members protected in the WIdget class that should not be public Fixed FileType not detecting package files @reepblueYour example is now working correctly, but I just noticed that when loading your provided scene from a ZIP file is was quite a lot slower than when I extracted the material files to the project folder. 1 My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
reepblue Posted January 3, 2023 Share Posted January 3, 2023 9 minutes ago, Josh said: @reepblueYour example is now working correctly, but I just noticed that when loading your provided scene from a ZIP file is was quite a lot slower than when I extracted the material files to the project folder Thanks, Think the speed has something to do how the zip is compressed? I used 7z with the -a flag to make the zip. I recently found ZipLib which is a modern C++ zip library that can be used to package games. I only got to compiling it as one static library last night. I also noticed that the package only works if the extension is.zip. in Cyclone, I have my packages as .pak but I understand that this can cause conflicts with package plugins. Cyclone - Ultra Game System - Component Preprocessor - Tex2TGA - Darkness Awaits Template (Leadwerks) If you like my work, consider supporting me on Patreon! Link to comment Share on other sites More sharing options...
Josh Posted January 3, 2023 Author Share Posted January 3, 2023 That was my first thought, but the decompression speed is fine. Ultra has a "feature" that tries to detect files that may be locked by another process, like when a paint program saves an image: //Load disk files #ifdef _WIN32 FILE* file = _wfopen(rpath.c_str(), L"rb"); #else std::string ss = rpath.ToUTF8String(); FILE* file = fopen(ss.c_str(), "rb"); #endif //Locked files (file is being written to by another process or thread) if (file == NULL and FileType(rpath) == 1) { int duration = 250; for (int n = 0; n < 5; ++n) { Sleep(duration); file = _wfopen(rpath.c_str(), L"rb"); if (file != NULL) break; duration *= 2; } } This was being triggered by every file loaded from the package because FileType was always returning 1, indicating that a file existed on the hard drive. And of course the file could not be loaded this way, so it was adding 1.25 second delay for each file. My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Josh Posted January 3, 2023 Author Share Posted January 3, 2023 Update Fixed zip file slow loading speed Zip packages are now detected by examining the file header instead of checking the file extension, so you can name them anything you want and they will still work 1 1 My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Josh Posted January 3, 2023 Author Share Posted January 3, 2023 18 hours ago, reepblue said: Also, @SpiderPig said something about the fog being broken and here's a picture of it. Load any lvl# map of Cyclone to notice no fog in the void. I got this artifact randomly and took a screen of it. Does this only happen when fog is enabled, or all the time? My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
SpiderPig Posted January 3, 2023 Share Posted January 3, 2023 6 hours ago, Josh said: It's working perfectly. Notice the MOUSELEAVE event is even being emitted when you hover over the child. This is exactly what it is supposed to do. Don't think in terms of hierarchies, think in terms of "which widget is directly under the mouse cursor?". Oh I understand now. So if I wanted to send the MOUSE_ENTER and MOUSE_MOVE events to the parents I simply need to call the call-back on the parent too? Pretty much exactly what @Dreikblack said but in my case like this: bool EventCallback(const Event& event, shared_ptr<Object> extra) { //Do Stuff auto parent = event.source->As<Widget>()->Getparent(); if(parent != nullptr) { event.source = parent; EventCallback(event, extra); } } This example no longer works with Widget::Initialize being inaccessible. https://www.ultraengine.com/learn/CustomWidgets?lang=cpp Link to comment Share on other sites More sharing options...
SpiderPig Posted January 3, 2023 Share Posted January 3, 2023 Alas I can no longer set a blocks texture. Could you make a method for this instead? my_widget->blocks[block_index].texture = texture; Link to comment Share on other sites More sharing options...
Josh Posted January 3, 2023 Author Share Posted January 3, 2023 Is the child always in the way, and doesn't get used for anything? Is it just decorative? If that is the case, you can call child->SetInteractive(false) and it will be ignored by events. Any mouse events will occur on the parent, and the child will be considered just visual. This is how I made the icon and text labels appear on the project buttons in the client app. 1 My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
SpiderPig Posted January 3, 2023 Share Posted January 3, 2023 3 minutes ago, Josh said: Is the child always in the way, and doesn't get used for anything? Is it just decorative? If that is the case, you can call child->SetInteractive(false) and it will be ignored by events. Any mouse events will occur on the parent, and the child will be considered just visual. This is how I made the icon and text labels appear on the project buttons in the client app. Perfect! That'll do it. Thankyou. 1 Link to comment Share on other sites More sharing options...
Josh Posted January 3, 2023 Author Share Posted January 3, 2023 11 minutes ago, SpiderPig said: This example no longer works with Widget::Initialize being inaccessible. https://www.ultraengine.com/learn/CustomWidgets?lang=cpp Thank you. I updated the example here: https://github.com/UltraEngine/Documentation/blob/master/CPP/CustomWidgets.md It will take 24 hours for the documentation cache to refresh, so just copy it from Github. 1 My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
reepblue Posted January 3, 2023 Share Posted January 3, 2023 15 minutes ago, Josh said: Does this only happen when fog is enabled, or all the time? I noticed this for the first time last night, but none of the maps don't seem to have fog enabled. Cyclone - Ultra Game System - Component Preprocessor - Tex2TGA - Darkness Awaits Template (Leadwerks) If you like my work, consider supporting me on Patreon! Link to comment Share on other sites More sharing options...
SpiderPig Posted January 3, 2023 Share Posted January 3, 2023 I'd like to use a custom widget for a button that uses textures, one for the normal state and another for the hover. I don't know if I should do it like this though, the textures don't show. In one project the normal state shows but the hover state doesn't, here neither show up. #include "UltraEngine.h" using namespace UltraEngine; //Declare new style constants enum CustomWidgetStyle { CUSTOMWIDGET_DEFAULT = 0 }; //Declare new widget class class CustomWidget : public Widget { //Custom members bool hover; shared_ptr<Texture> t1, t2; protected: virtual bool Initialize(const WString& text, const int x, const int y, const int width, const int height, shared_ptr<Widget> parent, const int style) { t1 = LoadTexture("pinkgrid.dds"); t2 = LoadTexture("bluegrid.dds"); return Widget::Initialize(text, x, y, width, height, parent, style); } //Called when the mouse moves if this widget has the focus virtual void MouseMove(const int x, const int y) {} //Called when the mouse cursor enters the widget bounds virtual void MouseEnter(const int x, const int y) { hover = true; Redraw(); } //Called when the mouse cursor leaves the widget bounds virtual void MouseLeave(const int x, const int y) { hover = false; Redraw(); } //Called when the mouse button is pressed virtual void MouseDown(const MouseButton button, const int x, const int y) { if (button == MOUSE_LEFT) EmitEvent(EVENT_WIDGETACTION, Self()); } //Called when the mouse button is released virtual void MouseUp(const MouseButton button, const int x, const int y) {} //Called when another widget becomes selected virtual void LoseFocus() {} //Called when mouse double-click occurs virtual void DoubleClick(const MouseButton button, const int x, const int y) {} //Called when mouse triple-click occurs virtual void TripleClick(const MouseButton button, const int x, const int y) {} //Called when widget is selected virtual void GainFocus() {} //Called when key is pressed virtual void KeyDown(const KeyCode key) {} //Called when key is released virtual void KeyUp(const KeyCode key) {} //Called for each keydown event virtual void KeyChar(const int keychar) {} //Called when mouse wheel turns and mouse is hovered over this widget virtual void MouseWheel(const int delta, const int x, const int y) {} //Called each time the widget is redrawn virtual void Draw(const int x, const int y, const int width, const int height) { blocks.clear(); //Background rectangle int b = AddBlock(iVec2(0), this->size, Vec4(1)); blocks[b].texture = (hover ? t1 : t2); //Foreground text AddBlock(text, iVec2(0), this->size, Vec4(1), TEXT_CENTER | TEXT_MIDDLE); } public: //Constructor CustomWidget() : hover(false) {} friend shared_ptr<Widget> CreateCustomWidget(const WString&, const int, const int, const int, const int, shared_ptr<Widget>, const CustomWidgetStyle); }; //Create function shared_ptr<Widget> CreateCustomWidget(const WString& text, const int x, const int y, const int width, const int height, shared_ptr<Widget> parent, const CustomWidgetStyle style) { auto widget = std::make_shared<CustomWidget>(); widget->Initialize(text, x, y, width, height, parent, style); return widget; } 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); camera->Move(0, 0, -3); auto box = CreateBox(world); auto default_font = LoadFont("Fonts\\arial.ttf"); auto ui = CreateInterface(world, default_font, framebuffer->size); ui->SetRenderLayers(2); ui->root->SetColor(0.0f, 0.0f, 0.0f, 0.0f); auto ui_camera = CreateCamera(world, PROJECTION_ORTHOGRAPHIC); ui_camera->SetPosition((float)framebuffer->size.x * 0.5f, (float)framebuffer->size.y * 0.5f, 0); ui_camera->SetRenderLayers(2); ui_camera->SetClearMode(CLEAR_DEPTH); //Create widget auto widget = CreateCustomWidget("Custom", 20, 20, 120, 36, ui->root, CUSTOMWIDGET_DEFAULT); auto panel = CreatePanel(100, 100, 100, 100, ui->root); panel->SetColor(1, 0, 0); while (true) { while (PeekEvent()) { auto ev = WaitEvent(); switch (ev.id) { case EVENT_WIDGETACTION: Print("Widget action: " + String(ev.data)); break; case EVENT_WINDOWCLOSE: return 0; break; } } world->Update(); world->Render(framebuffer); } return 0; } Images.zip Link to comment Share on other sites More sharing options...
SpiderPig Posted January 3, 2023 Share Posted January 3, 2023 10 hours ago, Josh said: Widgets don't have a persistent order. Widget blocks are assigned an order any time anything changes. The number of widget blocks, and whether they are hidden or shown, can change from one action to the next. What's really needed here is a widget block that can display a line. I don't want to add this until there is time to test on Quartz, GDI, and XRender, because I don't want to start adding features to the 3D GUI that are not supported by a GUI created on a window. Yeah I agree. Having said that though, I would still like to know at what depth the widget is at. In my case I would ping the depth every loop and set my sprites accordingly anyway, so it doesn't matter if it changes. At least it would be a fix until you're ready to work on widget blocks supporting lines. Link to comment Share on other sites More sharing options...
Josh Posted January 3, 2023 Author Share Posted January 3, 2023 11 minutes ago, SpiderPig said: I'd like to use a custom widget for a button that uses textures, one for the normal state and another for the hover. I don't know if I should do it like this though, the textures don't show. In one project the normal state shows but the hover state doesn't, here neither show up. Ah, you have discovered why I keep talking about consistency. I was trying to figure out why none of the sprite creation code was getting called, and finally realized you created the interface on a window. So naturally, a Vulkan texture would not appear. auto ui = CreateInterface(window); My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
SpiderPig Posted January 3, 2023 Share Posted January 3, 2023 Oooohh of course I'll set it up as a 2D camera and see if it does the same thing as my other project. Link to comment Share on other sites More sharing options...
SpiderPig Posted January 3, 2023 Share Posted January 3, 2023 I've updated my example above. I may be doing something stupid but the custom widgets Draw() method is not being called? The red panel works fine. Link to comment Share on other sites More sharing options...
SpiderPig Posted January 3, 2023 Share Posted January 3, 2023 Essentially a repost of the problem I posted earlier but with an additional problem. The panel on the right has a border drawn on the pixmap itself but it is not visible on the panel. The panels here are sized 64x64 and the textures are 128x128. I might be making the wrong assumption that the widgets texture coords are 0 to 1 respectively regards of their size? There's also the alpha issue here too. #include "UltraEngine.h" #include "ComponentSystem.h" using namespace UltraEngine; int main(int argc, const char* argv[]) { auto displays = GetDisplays(); auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR); auto world = CreateWorld(); auto framebuffer = CreateFramebuffer(window); auto camera = CreateCamera(world); camera->SetClearColor(0.125); camera->SetFov(70); camera->SetPosition(0, 0, -3); auto font = LoadFont("Fonts\\arial.ttf"); auto ui = CreateInterface(world, font, framebuffer->size); ui->SetRenderLayers(2); ui->root->SetColor(0.0f, 0.0f, 0.0f, 0.0f); auto ui_camera = CreateCamera(world, PROJECTION_ORTHOGRAPHIC); ui_camera->SetPosition((float)framebuffer->size.x * 0.5f, (float)framebuffer->size.y * 0.5f, 0); ui_camera->SetRenderLayers(2); ui_camera->SetClearMode(CLEAR_DEPTH); auto light = CreateBoxLight(world); light->SetRotation(35, 45, 0); light->SetRange(-10, 10); auto box = CreateBox(world); box->SetColor(0, 0, 1); auto actor = CreateActor(box); auto component = actor->AddComponent<Mover>(); component->rotation.y = 45; auto widget = CreatePanel(600, 350, 64, 64, ui->root, PANEL_BORDER); widget->SetColor(1.0f, 1.0f, 1.0f, 0.25f); widget->SetPixmap(LoadPixmap("Background.dds")); auto w2 = CreatePanel(670, 350, 64, 64, ui->root); w2->SetColor(1.0f, 1.0f, 1.0f, 0.25f); w2->SetPixmap(LoadPixmap("NewBackground.dds")); while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false) { world->Update(); world->Render(framebuffer); } return 0; } Background.zip Link to comment Share on other sites More sharing options...
Josh Posted January 3, 2023 Author Share Posted January 3, 2023 Why indeed? I am looking into this. Stay tuned for more fun tomorrow... 1 My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Josh Posted January 4, 2023 Author Share Posted January 4, 2023 @reepblue I'm not sure what I am looking for. Everything looks okay if I use this code to load a map: #include "UltraEngine.h" #include "ComponentSystem.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, 1280, 720, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR); //Create a framebuffer auto framebuffer = CreateFramebuffer(window); //Create a world auto world = CreateWorld(); //Create a camera auto camera = CreateCamera(world); camera->SetPosition(0, 0, -4); camera->SetClearColor(0,0,1); auto actor = CreateActor(camera); actor->AddComponent<CameraControls>(); auto scene = LoadScene(world, "maps/lvl6.map"); auto box = CreateBox(world); while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false) { world->Update(); world->Render(framebuffer); } return 0; } My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Josh Posted January 4, 2023 Author Share Posted January 4, 2023 I notice the signs have a strange error in their cubemap reflections. If I recall correctly, this is caused by texture assignment in a custom shader...there's a texture being used for a normal map that isn't a normal map, something like that. My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Josh Posted January 4, 2023 Author Share Posted January 4, 2023 12 hours ago, SpiderPig said: I'd like to use a custom widget for a button that uses textures, one for the normal state and another for the hover. I don't know if I should do it like this though, the textures don't show. In one project the normal state shows but the hover state doesn't, here neither show up. You just need to send events to the interface, since it is not created on a window, and it will work fine: while (PeekEvent()) { auto ev = WaitEvent(); switch (ev.id) { case EVENT_WIDGETACTION: Print("Widget action: " + String(ev.data)); break; case EVENT_WINDOWCLOSE: return 0; break; } ui->ProcessEvent(ev); } You probably want to change the widget background color because right now your draw method creates white text on a white background. 1 My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Recommended Posts