Aaron Symons Posted January 26, 2015 Share Posted January 26, 2015 Howdy! Since it looks like I can't create threads using Lua, how would I go about creating an animated loading screen during a map change using Lua? The program seems to freeze during this process, and I wish to display images, text, etc and update these of their own accord while loading the next map. For example, I wish to display: an animated loading icon, and displaying an image slideshow. Many thanks in advance! Quote Win7 64-bit | Intel i7-3770 3.40GHz | NVIDIA GeForce GTX 660 Link to comment Share on other sites More sharing options...
Rick Posted January 26, 2015 Share Posted January 26, 2015 This comes up every so often and I don't think there is an ideal situation for what you want. There is a callback in the Map:Load() where in the callback you can change images and draw to the screen but it'll still be choppy as it's loading each asset as loading takes time. You'd be better off doing images that change every so often and a progress bar that is OK to stick and not be very fluid. There doesn't seem to be a way to get total entity count before loading either so you either have to do that on your own or guess to get the max value of your progress bar. Or if you know how long it takes to generally load the map you can just make the progress go off that instead of increasing for each asset. Quote Link to comment Share on other sites More sharing options...
Aaron Symons Posted January 27, 2015 Author Share Posted January 27, 2015 Hi Rick. Thanks for your help! I've got myself some "Loading..." text displaying during the map load now. Not really what I wanted, but it'll do - better than a blank screen! I tried to draw the name of the current entity being loaded, but it didn't display. I might be missing something simple, so I may pursue a better loading screen in the future. Thanks again for your help! Quote Win7 64-bit | Intel i7-3770 3.40GHz | NVIDIA GeForce GTX 660 Link to comment Share on other sites More sharing options...
martyj Posted February 19, 2015 Share Posted February 19, 2015 How did you manage to even draw "loading..."? My map has a good 30 seconds of loading textures and shaders before it even hits the map loading hooks. Quote Link to comment Share on other sites More sharing options...
AnthonyPython Posted February 19, 2015 Share Posted February 19, 2015 draw it right before changing the map? Quote OS: Windows 10 Pro CPU: i3-10100 CPU @ 3.60GHz GPU: NVIDIA 2060 Super - 8 GB RAM: 32 GB Link to comment Share on other sites More sharing options...
Thirsty Panther Posted February 19, 2015 Share Posted February 19, 2015 Have small intro map. In this map you have your "start", "options" and "quit" buttons. This will load quickly. Then when the player selects "start" show your loading message. The player then get to watch this while your map loads. You could also play music while waiting as it keeps playing into the next map. Quote Link to comment Share on other sites More sharing options...
Rick Posted February 19, 2015 Share Posted February 19, 2015 How did you manage to even draw "loading..."? My map has a good 30 seconds of loading textures and shaders before it even hits the map loading hooks. Yeah, you'd want to draw it before you load the map. This also means you'd have an extra self.context:Sync(false) most likely after you draw your "Loading..." text using the context. Quote Link to comment Share on other sites More sharing options...
Aaron Symons Posted February 19, 2015 Author Share Posted February 19, 2015 The way I displayed the loading text (in App.lua): function App:LoadingScreen() self.context:SetFont(self.DefaultFont) local loadingText = "L O A D I N G . . ." local x = (App.window:GetWidth() / 2) - (self.DefaultFont:GetTextWidth(loadingText) / 2) local y = (App.window:GetHeight() / 2) - (self.DefaultFont:GetHeight() / 2) -- Fill screen with black self.context:SetColor(0, 0, 0) self.context:DrawRect(0, 0, App.window:GetWidth(), App.window:GetHeight()) -- Draw "Loading" text self.context:SetColor(1, 1, 1) self.context:DrawText(loadingText, x, y) end function LoadingScreen() App:LoadingScreen() end function App:ShouldSwitchMap() -- Clear all entities self.world:Clear() -- Load the next map Time:Pause() if Map:Load(self.mapfile, "LoadingScreen") == false then return false end Time:Resume() end You probably don't need to "fill the screen with black" by drawing the rectangle, but that's what I have until I update it and I hope this helps. 1 Quote Win7 64-bit | Intel i7-3770 3.40GHz | NVIDIA GeForce GTX 660 Link to comment Share on other sites More sharing options...
AnthonyPython Posted February 20, 2015 Share Posted February 20, 2015 The way I displayed the loading text (in App.lua): function App:LoadingScreen() self.context:SetFont(self.DefaultFont) local loadingText = "L O A D I N G . . ." local x = (App.window:GetWidth() / 2) - (self.DefaultFont:GetTextWidth(loadingText) / 2) local y = (App.window:GetHeight() / 2) - (self.DefaultFont:GetHeight() / 2) -- Fill screen with black self.context:SetColor(0, 0, 0) self.context:DrawRect(0, 0, App.window:GetWidth(), App.window:GetHeight()) -- Draw "Loading" text self.context:SetColor(1, 1, 1) self.context:DrawText(loadingText, x, y) end function LoadingScreen() App:LoadingScreen() end function App:ShouldSwitchMap() -- Clear all entities self.world:Clear() -- Load the next map Time:Pause() if Map:Load(self.mapfile, "LoadingScreen") == false then return false end Time:Resume() end You probably don't need to "fill the screen with black" by drawing the rectangle, but that's what I have until I update it and I hope this helps. besides drawing a black rectangle you could use a table with the images loadingscreen = {} loadingscreen[0](image stuff here) loadingscreen[1](image stuff here) loadingscreen[2](image stuff here) etc... and just call it in the update world so as long as it's true, cycle through each pic.while it loads till it loads set to false, this would be fine showing pictures for my game, not sure if you just want pic., of course I'd rather have a animated screen, but even portal 2's loading screen some times lagg's from loading. Quote OS: Windows 10 Pro CPU: i3-10100 CPU @ 3.60GHz GPU: NVIDIA 2060 Super - 8 GB RAM: 32 GB Link to comment Share on other sites More sharing options...
martyj Posted February 20, 2015 Share Posted February 20, 2015 Wow, I can't believe I never thought of that last night. Dam. I wish LE was better at map loading for a loading screen. Although there are other priorities tbh. 1 Quote Link to comment Share on other sites More sharing options...
Rick Posted February 20, 2015 Share Posted February 20, 2015 @Aaron Does that work for you? It seems like it wouldn't because when you load the map it should call that callback function for each entity it's loading, but you are drawing to the context, but it is my understanding that whatever you draw to the context will not actually be displayed until context:Sync() is drawn (http://www.leadwerks.com/werkspace/page/documentation/_/command-reference/context/contextsync-r48). I don't see that being called in your LoadingScreen() function so how would what you are drawing there be shown on the screen? Quote Link to comment Share on other sites More sharing options...
AnthonyPython Posted February 20, 2015 Share Posted February 20, 2015 Wow, I can't believe I never thought of that last night. Dam. I wish LE was better at map loading for a loading screen. Although there are other priorities tbh. yep there are more bigger and better Priority's to be done first instead of a small thing like this(like the vegitation tool, carving tool, and road tool) Quote OS: Windows 10 Pro CPU: i3-10100 CPU @ 3.60GHz GPU: NVIDIA 2060 Super - 8 GB RAM: 32 GB Link to comment Share on other sites More sharing options...
Aaron Symons Posted February 20, 2015 Author Share Posted February 20, 2015 besides drawing a black rectangle you could use a table with the images loadingscreen = {} loadingscreen[0](image stuff here) loadingscreen[1](image stuff here) loadingscreen[2](image stuff here) etc... and just call it in the update world so as long as it's true, cycle through each pic.while it loads till it loads set to false, this would be fine showing pictures for my game, not sure if you just want pic., of course I'd rather have a animated screen, but even portal 2's loading screen some times lagg's from loading. Yeah. That's my next step. I'll be using Blender to render an animation to png files and cycle through them using a similar method to your suggestion. @Aaron Does that work for you? It seems like it wouldn't because when you load the map it should call that callback function for each entity it's loading, but you are drawing to the context, but it is my understanding that whatever you draw to the context will not actually be displayed until context:Sync() is drawn (http://www.leadwerks.com/werkspace/page/documentation/_/command-reference/context/contextsync-r48). I don't see that being called in your LoadingScreen() function so how would what you are drawing there be shown on the screen? This definitely works for me. There is no other code included in my Loading Screen "system", only what you see here. I wonder if the call to update the context in App.lua is still running during Map:Load(), as the world (self.world) is never destroyed or created for each map load - the original always exists. Quote Win7 64-bit | Intel i7-3770 3.40GHz | NVIDIA GeForce GTX 660 Link to comment Share on other sites More sharing options...
Rick Posted February 20, 2015 Share Posted February 20, 2015 I wonder if the call to update the context in App.lua is still running during Map:Load(), as the world (self.world) is never destroyed or created for each map load - the original always exists. It shouldn't be. Map:Load() is a blocking function and doesn't come back until it's done as far as I know (yes it calls the callback for each entity it loads but shouldn't come back from the Load() call in order to reach your context:Sync() in your main loop). The world doesn't have anything to do with 2D drawing though as far as I know, but even then Sync() on the context is what draws to the screen the 2D stuff. I must be missing something here because that doesn't make sense to me how this is working. How long does your map take to load? Can you post your entire App.lua file? Yeah, I just tested that if you don't call Context::Sync() nothing is drawn to the screen. I just get a white screen, so I don't think this is perhaps working the way you think it is. How are you getting out of your ShouldSwitchMap() function because there is no if check in there to see if you should indeed switch maps, so if that function is being called all the time in App:Loop() then it would be switching maps all the time. So my impression is whatever you are seeing was left over from the last frame that Context:Sync() was called in, but that wouldn't be what you are drawing in the map loader callback. That's why it confusing and seeing you App.lua would probably clear things up. Quote Link to comment Share on other sites More sharing options...
martyj Posted February 20, 2015 Share Posted February 20, 2015 I have an idea. So when you load a map, it is making different Sytem::Print calls to print to the console on which texture, shader, ect it is loading. In a project I did a few years ago, we had a developer who left in all his debug messages. (And there was a TON!). So to get rid of them, I overwrote the built in log function with my own. This function would still log in "development" mode, but would do nothing in production. The following code is untested and is based on some Objective C code I wrote a year ago. Mind you this is only theoretical for C++ version of LE. Not Lua. I also don't know how this will work with Visual studios and C++. I know something like this will work with GCC and C. In theory C++ gets compiled to a C library using name mangling. static bool loadingMap = false; void NewSystemLog(const std::string& s) { if(loadingMap) { Context* context = Context::GetCurrent(); //Draw loading screen context->Sync(true); } } int main() { void(*logFunc)(const std::string& s); logFunc = System::Print; System::Print = NewSystemLog; } // App.cpp App::Loop() { loadingMap = true; if(!Map::Load("Maps/test.map")) { System::Print("Error loading map"); } loadingMap = false; } Since System::Print is an overloaded function what you might ahve to do is surround your code in extern "C" {} brackets and reference System::Print by the name mangled function. When I get home tonight I will test it out and update with my findings. Quote Link to comment Share on other sites More sharing options...
AnthonyPython Posted February 20, 2015 Share Posted February 20, 2015 I have an idea. So when you load a map, it is making different Sytem::Print calls to print to the console on which texture, shader, ect it is loading. In a project I did a few years ago, we had a developer who left in all his debug messages. (And there was a TON!). So to get rid of them, I overwrote the built in log function with my own. This function would still log in "development" mode, but would do nothing in production. The following code is untested and is based on some Objective C code I wrote a year ago. Mind you this is only theoretical for C++ version of LE. Not Lua. I also don't know how this will work with Visual studios and C++. I know something like this will work with GCC and C. In theory C++ gets compiled to a C library using name mangling. static bool loadingMap = false; void NewSystemLog(const std::string& s) { if(loadingMap) { Context* context = Context::GetCurrent(); //Draw loading screen context->Sync(true); } } int main() { void(*logFunc)(const std::string& s); logFunc = System::Print; System::Print = NewSystemLog; } // App.cpp App::Loop() { loadingMap = true; if(!Map::Load("Maps/test.map")) { System::Print("Error loading map"); } loadingMap = false; } Since System::Print is an overloaded function what you might ahve to do is surround your code in extern "C" {} brackets and reference System::Print by the name mangled function. When I get home tonight I will test it out and update with my findings. in lua I guess you can use a check to see if you are in debug or not to print this stuff out, in only debug and not in the product Quote OS: Windows 10 Pro CPU: i3-10100 CPU @ 3.60GHz GPU: NVIDIA 2060 Super - 8 GB RAM: 32 GB Link to comment Share on other sites More sharing options...
martyj Posted February 20, 2015 Share Posted February 20, 2015 I am pretty sure it won't work in Lua as the code that runs when you load a map is native C++ code. So overriding the Print in Lua isn't the same as overriding the print in C++. So I think in order to hack in Animated loading screens you have to use C++. Quote Link to comment Share on other sites More sharing options...
Rick Posted February 20, 2015 Share Posted February 20, 2015 You can do an animated loading screen in Lua. But both in C++ or Lua you will have pauses as the models get loaded. Map:Load() has a callback function called for each entity. That's where you would cycle through the images and then you'd call Context:Sync() to show that to the screen. Quote Link to comment Share on other sites More sharing options...
AnthonyPython Posted February 21, 2015 Share Posted February 21, 2015 You can do an animated loading screen in Lua. But both in C++ or Lua you will have pauses as the models get loaded. Map:Load() has a callback function called for each entity. That's where you would cycle through the images and then you'd call Context:Sync() to show that to the screen. Plus on a Side Note: this can determine if it is choppy/laggy while it is loading everything. Quote OS: Windows 10 Pro CPU: i3-10100 CPU @ 3.60GHz GPU: NVIDIA 2060 Super - 8 GB RAM: 32 GB Link to comment Share on other sites More sharing options...
Rick Posted February 21, 2015 Share Posted February 21, 2015 Plus, before publishing you can do a output of a count to get a total entity count and then make a progress bar off of that to make it 100% accurate with entity count. Quote Link to comment Share on other sites More sharing options...
AnthonyPython Posted February 21, 2015 Share Posted February 21, 2015 Plus, before publishing you can do a output of a count to get a total entity count and then make a progress bar off of that to make it 100% accurate with entity count. Which would be great Quote OS: Windows 10 Pro CPU: i3-10100 CPU @ 3.60GHz GPU: NVIDIA 2060 Super - 8 GB RAM: 32 GB Link to comment Share on other sites More sharing options...
Aaron Symons Posted February 21, 2015 Author Share Posted February 21, 2015 It shouldn't be. Map:Load() is a blocking function and doesn't come back until it's done as far as I know (yes it calls the callback for each entity it loads but shouldn't come back from the Load() call in order to reach your context:Sync() in your main loop). The world doesn't have anything to do with 2D drawing though as far as I know, but even then Sync() on the context is what draws to the screen the 2D stuff. I must be missing something here because that doesn't make sense to me how this is working. How long does your map take to load? Can you post your entire App.lua file? Yeah, I just tested that if you don't call Context::Sync() nothing is drawn to the screen. I just get a white screen, so I don't think this is perhaps working the way you think it is. How are you getting out of your ShouldSwitchMap() function because there is no if check in there to see if you should indeed switch maps, so if that function is being called all the time in App:Loop() then it would be switching maps all the time. So my impression is whatever you are seeing was left over from the last frame that Context:Sync() was called in, but that wouldn't be what you are drawing in the map loader callback. That's why it confusing and seeing you App.lua would probably clear things up. Sorry! You were right. I accidentally missed out a line in my code when I posted it on here ( in LoadingScreen() ) where I Sync() the context before drawing. Sorry about that! I'm not sure if syncing after drawing would make any difference, perhaps I'll experiment. I'm updating it to now show an "animated" loading icon. Quote Win7 64-bit | Intel i7-3770 3.40GHz | NVIDIA GeForce GTX 660 Link to comment Share on other sites More sharing options...
Rick Posted February 21, 2015 Share Posted February 21, 2015 Sorry! You were right. I accidentally missed out a line in my code when I posted it on here ( in LoadingScreen() ) where I Sync() the context before drawing. Sorry about that! I'm not sure if syncing after drawing would make any difference, perhaps I'll experiment. I'm updating it to now show an "animated" loading icon. I knew I wasn't going crazy It matters. Nothing new is drawn if you don't sync. It'll just be the last thing that was drawn on the screen. Syncing draws everything. 2D and 3D. If you have your normal App.lua and comment out the sync call you'll get a white screen. Quote Link to comment Share on other sites More sharing options...
Aaron Symons Posted February 21, 2015 Author Share Posted February 21, 2015 I knew I wasn't going crazy It matters. Nothing new is drawn if you don't sync. It'll just be the last thing that was drawn on the screen. Syncing draws everything. 2D and 3D. If you have your normal App.lua and comment out the sync call you'll get a white screen. You're not going crazy at all! I think I might be regressing in IQ, though! My last comment, I meant that I'm not sure if "Sync() then DrawText()" would make much difference to "DrawText() then Sync()" in this case, seeing as it's just a loading screen. I have my animated loading screen working wonderfully now! Thank you Rick, you've been most helpful. One quick aside question: is there a way to change the compression of multiple texture files at once in Leadwerks? I've just had to spend nearly twenty minutes changing the compression of over 300 texture files for my "animation" (I uncompressed them in order to have transparency, as well as nice smooth graphics). If not, hopefully I can do something through code instead, unless I'm missing something yet again. Quote Win7 64-bit | Intel i7-3770 3.40GHz | NVIDIA GeForce GTX 660 Link to comment Share on other sites More sharing options...
nick.ace Posted May 18, 2015 Share Posted May 18, 2015 Sorry to revive this old thread, but did anyone ever get the C++ hook to work? This is basically what I have (obviously I left out all the surrounding code, but that shouldn't have any impact on this): void Loading(Entity *e, Object *o) { System::Print("it worked"); } bool App::Loop() { Map::Load("testmap.map","Loading"); } Am I calling the hook function correctly? Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.