-
Posts
2,600 -
Joined
-
Last visited
Content Type
Blogs
Forums
Store
Gallery
Videos
Downloads
Everything posted by reepblue
-
My guess is that Windows is blocking the direct execution because it's a foreign app. Manually run the application tell UAC to trust the app. Or build try building the Preprocessor from the GitHub and use your version. Ether way, I didn't factor that into account. 🫢
-
6 Reasons You Should Use Ultra Game System
reepblue commented on reepblue's blog entry in reepblue's Blog
It's now easier to get started! The system is installable as a project template and component registration is much more streamlined. -
A few changes: This is now installable as a Template. Copy the "C++ Game" into the engine's Template folder and create a new project off of that. I didn't redistribute any SDK files so right now the start.ultra map will not work unless you were to copy over the stock components yourself. Removed start.ultra from the config's start map to prevent said issues. Visual Studio project is now included with all files added. My Component Preprocesor is now being used to make the component registration much more seamless. The app icon is now orange. Fixed any issues causing build errors. Some things I'm considering: Create a new start.ultra map to override the stock one. Ship my own components making use of the rest of the system. I've got more developer textures. I was going to ship it in its own package. I'm not sure including it would more help or bother people. Editing the template solution is really annoying. I might revive my premake setup. This will really help when Ultra Engine goes multiplatform.
-
If you were to have an entity with a component attached to it and in the flowgraph, deleting the component from the entity doesn't reflect on the flowgraph. I know this is a heavy WIP, but thought I should bring it up.
-
This simple application will scan your Components directory and create a function that'll register all your components in the engine. Use this in your Pre-Build event and then call the RegisterComponents() on top of your main entry. I didn't battle test this yet, but it seems to work. You are free to fork it, improve it, etc via GitHub. You can download the exe here.
-
One of the things I don't like is that you need to cut the full line of text by spaces every time. The system I had for Cyclone only had the arguments available in a vector. This is a limitation of the Event System, but having it event based makes commands less static and it's way easier to do component based commands. One thing I still don't like thats in both systems is you need to do size checks on the argument vector before using it to prevent crashing. Other than that, it's a canvas for the programmer to do whatever they need done.
-
Although cxxopts looks interesting, I wanted to stay exclusive to the engine's API for this. I didn't want to do anything that could/would change the workflow of how things are normally done with the engine. I might consider separating the logs by type though, I already have it sorted by colors at this point.
-
Back in July, I set out to create a base for creating a version of Cyclone with Ultra Engine. I've gotten a lot of feedback from the release and started to conceptualize ideas on how to prevent or limit on making the same mistakes. One major goal I had was to compartmentalize the system. This should just exist on it's own and game code should just lay on top of this. This was possible thanks to the event system which cuts down on the number of pointers that need to be passed. Components can just listen to events from the program and act accordingly. Lastly, I've made the decision to open source this on GitHub as this is the kind of thing that users think about when it's too late. People just want to work on their cool games and not worry about the window or if a setting will be applied correctly. So here are 6 reasons/features of the Ultra Game System! 1. Window Management One of the top complaints I got with Cyclone is that users could not resize the window in-game. This was an engine limitation of Leadwerks This is now possible in Ultra Engine but it needs some elbow grease to make it work. The Game System does this for you. All you need to do is call GetProgram()->ResizeApp() and the graphics window class will recreate the window and framebuffer for you. By default, pressing F11 will swap between windowed mode and full screen. 2. Out-Of-Game Settings The Game System has an isolated window application for changing settings. The idea behind this is so there's a way to modify any window or graphics setting if an in-game one is unavailable. You probably shouldn't ship with just this solution as many people prefer to edit any setting within the game itself. This is accessible by using the -settings flag with the program. 3. Action Based Input System Years of research into this paid off when the Input Update for Cyclone released. The knowledge was carried over for the Game System. Only this time it's more dynamic! Simply set the controls in your main.cpp file: // Define default controls. static void InstallControls(shared_ptr<GameController> controller) { if (controller == NULL) return; // Program actions controller->SetAction("Pause", BUTTON_KEY_ESCAPE); controller->SetAction("Terminate", BUTTON_KEY_END); controller->SetAction("ConsoleApp", BUTTON_KEY_F1); controller->SetAction("Fullscreen", BUTTON_KEY_F11); controller->SetAction("Screenshot", BUTTON_KEY_F2); controller->SetAction("Quick Save", BUTTON_KEY_F5); controller->SetAction("Quick Load", BUTTON_KEY_F6); // Camera ButtonAxis moveaxis = { BUTTON_KEY_W, BUTTON_KEY_S, BUTTON_KEY_A, BUTTON_KEY_D }; controller->SetAction("Movement", moveaxis, "InGameControls"); controller->SetAction("Camera", AXIS_MOUSE, "InGameControls"); controller->SetAction("Sprint", BUTTON_KEY_SHIFT, "InGameControls"); controller->SetAction("Crouch", BUTTON_KEY_CONTROL, "InGameControls"); controller->SetAction("Climb", BUTTON_KEY_Q, "InGameControls"); controller->SetAction("Desent", BUTTON_KEY_E, "InGameControls"); controller->SetAction("Jump", BUTTON_KEY_SPACE, "InGameControls"); // Settings controller->SetSetting("Raw Mouse", false); controller->SetSetting("Inverse Mouse", false); controller->SetSetting("Mouse Smoothing", 0.0f); controller->SetSetting("Mouse Look Speed", 1.0f); } Then deriving your components off of the GameObject class, you can use GetInput() for input functionality. virtual void UpdateInput() { // Movement if (allowmovement) { float speed = movespeed / 60.0f; if (GetInput()->Down("Sprint")) { speed *= 10.0f; } else if (GetInput()->Down("Crouch")) { speed *= 0.25f; } if (GetInput()->Down("Climb")) GetEntity()->Translate(0, speed, 0); if (GetInput()->Down("Desent")) GetEntity()->Translate(0, -speed, 0); auto axis = GetInput()->Axis("Movement"); GetEntity()->Move(axis.x * speed, 0, axis.y * speed); } } Best part is the "Controls" tab will reflect whatever you have defined! 4. User Input via Console Having a developer console is essential for developing any game! The Game System has a very simple but flexible console that doesn't need any commands registered beforehand. To define a new command, just poll the EVENT_CONSOLEEXECUTE id in your component's ProcessEvent function. virtual void Start() { Listen(EVENT_CONSOLEEXECUTE, GetProgram()); } virtual bool ProcessEvent(const Event& e) { if (e.id == EVENT_CONSOLEEXECUTE) { auto line = e.text.Split(" "); auto cmd = line[0].ToString(); if (line.size() > 1 && !line[1].empty()) { if (cmd == "crosshair") { bool hide = (bool)line[1].ToInt(); hudcamera->SetHidden(!hide); Print(QuoteString(cmd) + " has been set to: " + line[1]); } } } } 5. Sound Managment A layer of functionality in the Game System allows for cleaner sound origination and playback. You can store sound variables (files, volume, pitch, range, etc) within a JSON script. { "audioProfile": { "file": "Sound/radio_dreamlandloop_mono.wav", "volume": 0.5, "range": 35.0, "loop": true } } Then load the file with the GameSpeaker class. auto file = "Sound/Profiles/Radio.json"; shared_ptr<GameSpeaker> speaker = CreateGameSpeaker(file, GetEntity()->GetPosition()); The GameSpeaker has Save/Load functions so the speaker's time and state can be restored. Here's an example of creating and restoring a GameSpeaker. virtual bool Load(table& properties, shared_ptr<Stream> binstream, shared_ptr<Map> scene, const LoadFlags flags) { Print("Loading component " + QuoteWString(name)); if (speaker) { if (!properties["componentspeaker"].is_null()) speaker->Load(properties["componentspeaker"], binstream, scene, flags); } else { auto file = "Sound/Profiles/Radio.json"; speaker = CreateGameSpeaker(file, GetEntity()->GetPosition()); if (!properties["componentspeaker"].is_null()) speaker->Load(properties["componentspeaker"], binstream, scene, flags); } return true; } virtual bool Save(table& properties, shared_ptr<Stream> binstream, shared_ptr<Map> scene, const SaveFlags flags) { properties["componentspeaker"] = {}; if (speaker) speaker->Save(properties["componentspeaker"], binstream, scene, flags); return true; } As of right now, the sound system doesn't support audio filters as I feel that the filter should be applied within a volume (or to the listener) and not the sound/speaker itself. I'm still thinking about how that should work. 6. Better Render Layer Managment Intergrated today, The Canvas class is a great way to ensure that there is one camera per render layer. I ran into an issue where a component would draw 2D graphics to the framebuffer, but when there were multiple instances of them, multiple cameras were being made and drawing over each other. Using GetCanvas() can prevent this from happening. auto canvas = GetCanvas(world, RENDERLAYER_HUD); auto sprite = CreateSprite(world, 1.0f, 1.0f); sprite->SetPosition((float)sz.x / 2, (float)sz.y / 2); RenderToCanvas(sprite, canvas); The Game System will be my main focus until the Ultra Engine version of Cyclone starts development which will use this as a foundation. I'll also be working on other small things to share so be on the lookout for those!
-
It's in the works.
-
Move the camera to the bottom edge of the framebuffer. 0,0 should be the top left of the screen. Then you can use the size of the framebuffer to position the sprite wherever you want like if you were using the Interface class. local size = framebuffer:GetSize() cam2:SetPosition(size.x * 0.5, size.y * 0.5f)
-
You're not setting your cam2 or your sprite to a new render layer. Not much of a Lua user, but try this. --Get the displays local displays = GetDisplays() --Create window local window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[1]) --Create framebuffer local framebuffer = CreateFramebuffer(window) --Create world local world = CreateWorld() --env map local specmap = LoadTexture("./Materials/Environment/Default/specular.dds") local diffmap = LoadTexture("./Materials/Environment/Default/diffuse.dds") world:SetEnvironmentMap(specmap, ENVIRONMENTMAP_BACKGROUND) world:SetEnvironmentMap(specmap, ENVIRONMENTMAP_SPECULAR) world:SetEnvironmentMap(diffmap, ENVIRONMENTMAP_DIFFUSE) --[[load map local mapname = "Maps/scene1.ultra" local cl = CommandLine() if type(cl["map"]) == "string" then mapname = cl["map"] end local scene = LoadMap(world, mapname) --]] --Create light local light = CreateBoxLight(world) light:SetRange(-10, 10) light:SetArea(15, 15) light:SetRotation(45, 35, 0) light:SetColor(2) --Load a font local font = LoadFont("Fonts/arial.ttf") local fontsize = 36 -- Create a camera local camera = CreateCamera(world,PROJECTION_PERSPECTIVE) camera:SetClearColor(0.125) camera:SetPosition(0, 5, 0) --Create second camera local cam2 = CreateCamera(world,PROJECTION_ORTHOGRAPHIC) cam2:SetPosition(0, 0, 0) cam2:SetClearMode(CLEAR_DEPTH) cam2:SetRenderLayers(1) -- Create sprite local sprite = CreateSprite(world, font,"HEY YOU !",fontsize) sprite:SetColor(1, 1, 1, 1) sprite:SetPosition(0, 0, 0) sprite:SetRenderLayers(1) --Camera controls to look around require 'Components/Player/CameraControls' camera:AddComponent(CameraControls) --main loop while not window:KeyDown(KEY_ESCAPE) do world:Update() world:Render(framebuffer) end This should spawn the sprite in the center of the screen.
-
Was playing with this. This truly makes it super easy to get skyboxes into Ultra Engine! If you place the extension within the Engine's Tool Directory, you can use this script to launch the application right from the editor which is much more convenient. --[[ This extention is intended to be used with Klepto2's PBR Texture Generator https://www.ultraengine.com/community/topic/62344-pbr-texture-generator/ ]]-- local extension = {} extension.toolpath = "/Tools/PBRTextureGen/UltraPBRTextureGen.exe" function extension.hook(event, extension) if event.id == EVENT_WIDGETACTION then RunFile(AppDir()..extension.toolpath) end end -------------------------------------------------------------------- -- Add menu item -------------------------------------------------------------------- local menu = program.menu:FindChild("Scripting", false) if menu == nil then Print("Error: Could not find \"Scripting\" menu.") return end if menu ~= nil then local submenu = menu:FindChild("Generate", false) if submenu == nil then submenu = CreateMenu("Generate", menu) end extension.menuitem = CreateMenu("PBR Texture Generator", submenu) end ListenEvent(EVENT_WIDGETACTION, extension.menuitem, extension.hook, extension)
-
One thing I noticed when making an extension to the editor is that Windows gets really annoying when saving anything manually to the Program Files folder. Another thing is that you may want certain extensions for specific projects. Maybe move "global" extensions to the user Documents folder, and then have the editor also read extensions within the project folder if it doesn't already. On that note, I also think the blacklist filter should also be extended to be project based with an entry defined within the Ultra.json file. Maybe I don't want to see .dds files in a project that I want to use .basis files, etc.
-
It's now live! Blog post will follow soon!
-
I didn't want to make a new topic for this but when are the brush measurement information coming back while the brush is being created? I forgot to put that on my list in the opening post. I assumed it was on the back burner because you wanted to think about how to render the text in 3D.
-
What a wild six years this has been. I remember the first build being a. bunch of boxes in a blue void and look where it is now. Congrats on the release and it should only get better from here. Thank you for having me as part of the process through out the years! Now I'm gonna harass tell all my friends about how they should be using this instead of whatever they are currently using.
-
Revisited my extension to generate basic materials from images and textures. This is good if you want non-game image formats part of your file blacklist. It was very helpful with the conversion script above to convert ten or so basic textures. local extension = {} function extension:CreateBlankMaterial() local defaultpath = CurrentDir().."/Materials/" local file = RequestFile("Select Material Location", defaultpath, "Ultra Engine Material File (*.mat):mat", 0, true) if file ~= nil then local mat = CreateMaterial() if mat ~= nil then mat:SetColor(1,1,1,1) local shaderfamily = LoadShaderFamily("Shaders/PBR.fam") if shaderfamily then mat:SetShaderFamily(shaderfamily) shaderfamily = nil end mat:Save(file); end end end function extension:Image2DDS(path) --Load image local pixmap = LoadPixmap(path) if pixmap==nil then Print("Error: Failed to generate texture \"" .. FixPath(output) .. "\"") return false end local mipchain = {} table.insert(mipchain,pixmap) --Generate mipmaps local w = pixmap.size.x local h = pixmap.size.y local mipmap = pixmap while (w > 4 and h > 4) do w = math.max(4, w / 2) h = math.max(4, h / 2) mipmap = mipmap:Resize(w,h) table.insert(mipchain,mipmap) end --Convert each image to BC1 (DXT1) compression for n=1, #mipchain do mipchain[n] = mipchain[n]:Convert(TEXTURE_BC1) end --Save mipchain to texture file local output = StripExt(path)..".dds" SaveTexture(output, TEXTURE_2D, mipchain, 1, SAVE_DEFAULT) return output end function extension:GenerateMaterialFromTexture() local defaultpath = CurrentDir().."/Materials/" local file = RequestFile("Select Texture", defaultpath, "Supported Files:dds,basis,png,jpg,jpeg,tga,bmp", 0) -- If we're not a texture, convert it if (ExtractExt(file) == "png" or ExtractExt(file) == "jpg" or ExtractExt(file) == "jpeg" or ExtractExt(file) == "tga" or ExtractExt(file) == "bmp") then local image = file file = extension:Image2DDS(image) end local output = StripExt(file)..".mat" if file ~= nil then local mat = CreateMaterial() if mat ~= nil then local tex = LoadTexture(file) if tex~=nil then mat:SetTexture(tex) mat:SetColor(1,1,1,1) local shaderfamily = LoadShaderFamily("Shaders/PBR.fam") if shaderfamily then mat:SetShaderFamily(shaderfamily) shaderfamily = nil end if mat:Save(output) then Print("Successfully saved \"" .. output .. "\"") end else Print("Failed to save \"" .. output .. "\" as texture is invaild!") end end mat = nil else Print("Failed to save \"" .. output .. "\" as file is invaild!") end end function extension.hook(event, extension) if event.id == EVENT_WIDGETACTION then if event.source == extension.menuitem_blankmaterial then extension:CreateBlankMaterial() elseif event.source == extension.menuitem_matfromtex then extension:GenerateMaterialFromTexture() end end end -------------------------------------------------------------------- -- Add menu item -------------------------------------------------------------------- local menu = program.menu:FindChild("Scripting", false) if menu == nil then Print("Error: Could not find \"Scripting\" menu.") return end local submenu = menu:FindChild("Generate Material", false) if submenu == nil then submenu = CreateMenu("Generate Material", menu) end extension.menuitem_blankmaterial = CreateMenu("New Blank Material", submenu) extension.menuitem_matfromtex = CreateMenu("New Material From Texture/Image", submenu) ListenEvent(EVENT_WIDGETACTION, extension.menuitem_blankmaterial, extension.hook, extension) ListenEvent(EVENT_WIDGETACTION, extension.menuitem_matfromtex, extension.hook, extension)
-
It works better as a converter. Works exactly how Leadwerks behaves. I understand the reason for texture creation for being manual since DDS doesn't cover all needs. local converter = {} converter.informat = "png" converter.outformat = "dds" function converter:Convert(path, output) --Load image local pixmap = LoadPixmap(path) if pixmap==nil then Print("Error: Failed to generate texture " ..path) return false end local mipchain = {} table.insert(mipchain,pixmap) --Generate mipmaps local w = pixmap.size.x local h = pixmap.size.y local mipmap = pixmap while (w > 4 and h > 4) do w = math.max(4, w / 2) h = math.max(4, h / 2) mipmap = mipmap:Resize(w,h) table.insert(mipchain,mipmap) end --Convert each image to BC1 (DXT1) compression for n=1, #mipchain do mipchain[n] = mipchain[n]:Convert(TEXTURE_BC1) end --Save mipchain to texture file SaveTexture(output, TEXTURE_2D, mipchain, 1, SAVE_DEFAULT) return true end program:AddConverter(converter)
-
I guess I'm just so used making textures in Leadwerks. That makes my life easier! Code is still useful regardless.
-
Everytime I right click on a PNG image to generate a material, it creates the DDS and a normal map. I just want to simply convert the image to a texture.
-
It seems I can't generate a texture without the editor also making a normal map for each texture which I do not want. I decided to make an extension that would convert the image to a DDS using the code found below. But I'm now getting the "Mipchain contains mipmaps with dimensions smaller than the format's block size" error. How would I fix my code? local extension = {} function CreateNewMaterial() local defaultpath = CurrentDir().."Materials/" local file = RequestFile("Select Material Location", defaultpath, "Ultra Engine Material File (*.mat):mat", 0, true) if file ~= nil then local mat = CreateMaterial() if mat ~= nil then mat:SetColor(1,1,1,1) local shaderfamily = LoadShaderFamily("Shaders/PBR.fam") if shaderfamily then mat:SetShaderFamily(shaderfamily) shaderfamily = nil end mat:Save(file); end end end function GenerateTexture() local defaultpath = CurrentDir().."Materials/" local file = RequestFile("Select Image", defaultpath, "Image:png,tga,jpg,jpeg,bmp", 0, false) --Load image local pixmap = LoadPixmap(file) if pixmap==nil then Print("Error: Failed to generate texture " ..file) return end local mipchain = {} table.insert(mipchain,pixmap) --Generate mipmaps local w = pixmap.size.x local h = pixmap.size.y local mipmap = pixmap while (w > 1 and h > 1) do w = math.max(1, w / 2) h = math.max(1, h / 2) mipmap = mipmap:Resize(w,h) table.insert(mipchain,mipmap) end --Convert each image to BC7 compression for n=1, #mipchain do mipchain[n] = mipchain[n]:Convert(TEXTURE_BC7) end --Save mipchain to texture file local output = StripExt(file)..".dds" SaveTexture(output, TEXTURE_2D, mipchain, 1, SAVE_DEFAULT) end function extension.hook(event, extension) if event.id == EVENT_WIDGETACTION then if event.source == extension.menuitem_newmaterial then CreateNewMaterial() elseif event.source == extension.menuitem_newDDS then GenerateTexture() end end end -------------------------------------------------------------------- -- Add menu item -------------------------------------------------------------------- local menu = program.menu:FindChild("Scripting", false) if menu == nil then Print("Error: Could not find \"Scripting\" menu.") return end local submenu = menu:FindChild("Utilities", false) if submenu == nil then submenu = CreateMenu("Utilities", menu) end extension.menuitem_newmaterial = CreateMenu("Create blank material", submenu) extension.menuitem_newDDS = CreateMenu("Convert image to DDS", submenu) ListenEvent(EVENT_WIDGETACTION, extension.menuitem_newmaterial, extension.hook, extension) ListenEvent(EVENT_WIDGETACTION, extension.menuitem_newDDS, extension.hook, extension)
-
I've noticed that if you jump into a wall, the velocity distributes into forward movement. However, this makes climbing the stack of boxes in the start map difficult as I keep falling off. I think the player physics needs to be tweaked so I can climb the boxes while the controller still feeling natural.
-
I think the probe models are being baked in the cubemaps similar to how the editor icons were. This is the default start map looking at the reflection of the crate model.
- 1 reply
-
- 1
-
End of File and seek position outside of file bounds
reepblue replied to CJO Games's topic in Bug Reports
To be honest, I had no luck using that tool. I accidentally copied over my Cyclone fbx files and it just made a bunch of useless garbage. I have better luck exporting as a gltf right out of blender.