From bf25ef1a800501e6f4890e355d15f230444c89e9 Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Tue, 10 Feb 2026 00:49:19 +0300 Subject: [PATCH] Fixed vehicles export --- CMakeLists.txt | 18 +-- assets/blender/scripts/export_vehicles.py | 112 ++++++++++++++++++ assets/blender/vehicles/CMakeLists.txt | 25 ++++ assets/blender/vehicles/boat-sails.blend | 4 +- .../vehicles/cmake/check_file_size.cmake | 11 ++ src/gamedata/EditorGUIModule.cpp | 11 +- src/gamedata/GUIModule.cpp | 108 +++++++++++++---- 7 files changed, 243 insertions(+), 46 deletions(-) create mode 100644 assets/blender/scripts/export_vehicles.py create mode 100644 assets/blender/vehicles/CMakeLists.txt create mode 100644 assets/blender/vehicles/cmake/check_file_size.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index b0ee856..01970fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,7 @@ add_subdirectory(src/tests) add_subdirectory(src/physics) add_subdirectory(src/editor) add_subdirectory(src/crowd) +add_subdirectory(assets/blender/vehicles) add_subdirectory(assets/blender/buildings/parts) add_subdirectory(assets/blender/characters) add_subdirectory(resources) @@ -132,23 +133,6 @@ foreach(BUILDING_FILE ${BUILDINGS_SRC}) endforeach() add_custom_target(import_buildings ALL DEPENDS ${BUILDING_OUTPUT_FILES}) -file(GLOB VEHICLES_SRC ${CMAKE_SOURCE_DIR}/assets/blender/vehicles/*.blend) -set(VEHICLE_OUTPUT_FILES) -foreach(VEHICLE_FILE ${VEHICLES_SRC}) - get_filename_component(FILE_NAME ${VEHICLE_FILE} NAME_WE) - set(VEHICLE_OUTPUT_FILE ${CMAKE_BINARY_DIR}/resources/vehicles/${FILE_NAME}.glb) - add_custom_command( - OUTPUT ${VEHICLE_OUTPUT_FILE} - COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/resources/vehicles - COMMAND ${BLENDER} ${VEHICLE_FILE} - -b -Y -P - ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_buildings.py - -- ${VEHICLE_OUTPUT_FILE} - COMMAND touch ${VEHICLE_OUTPUT_FILE} - DEPENDS ${VEHICLE_FILE}) - list(APPEND VEHICLE_OUTPUT_FILES ${VEHICLE_OUTPUT_FILE}) -endforeach() -add_custom_target(import_vehicles ALL DEPENDS ${VEHICLE_OUTPUT_FILES}) set(CHARACTER_SHAPES_SRC edited-normal-male-base.blend edited-shape-test-male.blend) set(CHARACTER_SHAPES_OUTPUT_FILES) diff --git a/assets/blender/scripts/export_vehicles.py b/assets/blender/scripts/export_vehicles.py new file mode 100644 index 0000000..bf1339d --- /dev/null +++ b/assets/blender/scripts/export_vehicles.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python + +import os, sys, time +import bpy +from math import pi +import glob +import shutil +from mathutils import Vector, Matrix +from math import radians, pi + +argv = sys.argv +argv = argv[argv.index("--") + 1:] + +incpath = os.path.dirname(__file__) + +sys.path.insert(0, incpath) +sys.path.insert(1, incpath + "/blender2ogre") + + +import io_ogre +try: + io_ogre.register() +except: + pass + +gltf_file = argv[0] +print("Exporting to " + gltf_file) +basepath = incpath +# bpy.ops.export_scene.gltf(filepath="", check_existing=True, +# export_import_convert_lighting_mode='SPEC', gltf_export_id="", +# export_format='GLB', ui_tab='GENERAL', export_copyright="", export_image_format='AUTO', +# export_texture_dir="", export_jpeg_quality=75, export_keep_originals=False, +# export_texcoords=True, export_normals=True, export_draco_mesh_compression_enable=False, +# export_draco_mesh_compression_level=6, export_draco_position_quantization=14, +# export_draco_normal_quantization=10, export_draco_texcoord_quantization=12, +# export_draco_color_quantization=10, export_draco_generic_quantization=12, export_tangents=False, +# export_materials='EXPORT', export_original_specular=False, export_colors=True, +# export_attributes=False, use_mesh_edges=False, use_mesh_vertices=False, export_cameras=False, +# use_selection=False, use_visible=False, use_renderable=False, +# use_active_collection_with_nested=True, use_active_collection=False, use_active_scene=False, +# export_extras=False, export_yup=True, export_apply=False, export_animations=True, +# export_frame_range=False, export_frame_step=1, export_force_sampling=True, export_animation_mode='ACTIONS', +# export_nla_strips_merged_animation_name="Animation", export_def_bones=False, +# export_hierarchy_flatten_bones=False, export_optimize_animation_size=True, +# export_optimize_animation_keep_anim_armature=True, export_optimize_animation_keep_anim_object=False, +# export_negative_frame='SLIDE', export_anim_slide_to_zero=False, export_bake_animation=False, +# export_anim_single_armature=True, export_reset_pose_bones=True, export_current_frame=False, +# export_rest_position_armature=True, export_anim_scene_split_object=True, export_skins=True, +# export_all_influences=False, export_morph=True, export_morph_normal=True, +# export_morph_tangent=False, export_morph_animation=True, export_morph_reset_sk_data=True, +# export_lights=False, export_nla_strips=True, will_save_settings=False, filter_glob="*.glb") + +for obj in bpy.data.objects: + if obj.name.endswith("-col"): + bpy.data.objects.remove(obj) + # Set the object as active and switch mode + bpy.context.view_layer.objects.active = obj + bpy.ops.object.mode_set(mode='OBJECT') +#bpy.context.view_layer.objects.active = None + + +scene_file = gltf_file.replace(".glb", "").replace(".gltf", "") + ".scene" + +bpy.ops.ogre.export(filepath=scene_file, + EX_SWAP_AXIS='xz-y', + EX_V2_MESH_TOOL_VERSION='v2', + EX_EXPORT_XML_DELETE=True, + EX_SCENE=True, + EX_SELECTED_ONLY=False, + EX_EXPORT_HIDDEN=False, + EX_FORCE_CAMERA=False, + EX_FORCE_LIGHTS=False, + EX_NODE_ANIMATION=True, + EX_MATERIALS=True, + EX_SEPARATE_MATERIALS=True, + EX_COPY_SHADER_PROGRAMS=True, + EX_MESH=True, + EX_LOD_LEVELS=3, + EX_LOD_DISTANCE=100, + EX_LOD_PERCENT=40 +) + +bpy.ops.export_scene.gltf(filepath=gltf_file, + use_selection=False, + check_existing=False, + export_format='GLB', + export_texture_dir='textures', export_texcoords=True, + export_normals=True, + export_tangents=True, + export_materials='EXPORT', + export_colors=True, + use_mesh_edges=False, + use_mesh_vertices=False, + export_cameras=False, + use_visible=False, + use_renderable=False, + export_yup=True, + export_apply=True, + export_animations=True, + export_force_sampling=True, + export_def_bones=False, + export_current_frame=False, + export_morph=True, + export_morph_animation=False, + export_morph_normal=True, + export_morph_tangent=True, + export_lights=False, + export_skins=True) + +bpy.ops.wm.read_homefile(use_empty=True) +time.sleep(2) +bpy.ops.wm.quit_blender() diff --git a/assets/blender/vehicles/CMakeLists.txt b/assets/blender/vehicles/CMakeLists.txt new file mode 100644 index 0000000..de11c1e --- /dev/null +++ b/assets/blender/vehicles/CMakeLists.txt @@ -0,0 +1,25 @@ +project(vehicles) + +set(VEHICLES_SRC boat-big.blend boat.blend + boat-gobbot.blend boat-sails.blend + raft.blend tiny-boat.blend) +set(VEHICLE_OUTPUT_FILES) + +foreach(VEHICLE_FILE ${VEHICLES_SRC}) + get_filename_component(FILE_NAME ${VEHICLE_FILE} NAME_WE) + set(VEHICLE_OUTPUT_FILE ${CMAKE_BINARY_DIR}/resources/vehicles/${FILE_NAME}.glb) + add_custom_command( + OUTPUT ${VEHICLE_OUTPUT_FILE} ${CMAKE_BINARY_DIR}/resources/vehicles/${FILE_NAME}.scene + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/resources/vehicles + COMMAND ${BLENDER} ${CMAKE_CURRENT_SOURCE_DIR}/${VEHICLE_FILE} + -b -Y -P + ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_vehicles.py + -- ${VEHICLE_OUTPUT_FILE} + COMMAND ${CMAKE_COMMAND} -D FILE=${CMAKE_BINARY_DIR}/resources/vehicles/${FILE_NAME}.glb -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_file_size.cmake + COMMAND ${CMAKE_COMMAND} -D FILE=${CMAKE_BINARY_DIR}/resources/vehicles/${FILE_NAME}.scene -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_file_size.cmake + COMMAND touch ${VEHICLE_OUTPUT_FILE} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${VEHICLE_FILE} ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_vehicles.py) + list(APPEND VEHICLE_OUTPUT_FILES ${VEHICLE_OUTPUT_FILE} ${CMAKE_BINARY_DIR}/resources/vehicles/${FILE_NAME}.scene) +endforeach() + +add_custom_target(import_vehicles ALL DEPENDS ${VEHICLE_OUTPUT_FILES}) diff --git a/assets/blender/vehicles/boat-sails.blend b/assets/blender/vehicles/boat-sails.blend index 74a1e2c..dc9ba1d 100644 --- a/assets/blender/vehicles/boat-sails.blend +++ b/assets/blender/vehicles/boat-sails.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:301499c2a789b753156699cb565e1dfa17fa5d0cf82e9f1cd9301ccde5ed3ec6 -size 297568 +oid sha256:3c8cd09ca4f575fcf694bc1eab6764091c874676ccfc7a92f6b05f9b67a41696 +size 293949 diff --git a/assets/blender/vehicles/cmake/check_file_size.cmake b/assets/blender/vehicles/cmake/check_file_size.cmake new file mode 100644 index 0000000..fcdda2f --- /dev/null +++ b/assets/blender/vehicles/cmake/check_file_size.cmake @@ -0,0 +1,11 @@ +if(EXISTS "${FILE}") + file(SIZE "${FILE}" FILE_SIZE) + if(FILE_SIZE GREATER 0) + message(STATUS "Build-time check: ${FILE} exists and is not empty.") + else() + message(FATAL_ERROR "Build-time check: ${FILE} exists but is empty!") + endif() +else() + message(FATAL_ERROR "Build-time check: ${FILE} does not exist!") +endif() + diff --git a/src/gamedata/EditorGUIModule.cpp b/src/gamedata/EditorGUIModule.cpp index d67a3b5..e176f12 100644 --- a/src/gamedata/EditorGUIModule.cpp +++ b/src/gamedata/EditorGUIModule.cpp @@ -51,11 +51,11 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { , command(COMMAND_NONE) { _midFont = createFont("midFont", "General", - "Jupiteroid-Regular.ttf", 18.0f); + "Jupiteroid-Regular.ttf", 24.0f); _smallFont = createFont("smallFont", "General", - "Jupiteroid-Regular.ttf", 13.0f); + "Jupiteroid-Regular.ttf", 18.0f); _bigFont = createFont("bigFont", "General", "Kenney Bold.ttf", - 32.0f); + 36.0f); smallFont = overlay->addFont("smallFont", "General"); OgreAssert(smallFont, "Could not load font"); midFont = overlay->addFont("midFont", "General"); @@ -1398,8 +1398,9 @@ EditorGUIModule::EditorGUIModule(flecs::world &ecs) .event(flecs::OnSet) .without() .each([](const RenderWindow &window, const App &app, GUI &gui) { - float vpScale = window.dpi / 96 * - window.window->getWidth() / 1600.0f; + float vpScale = window.dpi / 96; + if (vpScale < 1.0f) + vpScale = 1.0f; Ogre::OverlayManager::getSingleton().setPixelRatio( vpScale); std::cout << "Editor GUI configure\n"; diff --git a/src/gamedata/GUIModule.cpp b/src/gamedata/GUIModule.cpp index 3953d78..369aa96 100644 --- a/src/gamedata/GUIModule.cpp +++ b/src/gamedata/GUIModule.cpp @@ -47,11 +47,11 @@ struct GUIListener : public Ogre::RenderTargetListener { : Ogre::RenderTargetListener() { _midFont = createFont("midFont", "General", - "Jupiteroid-Regular.ttf", 18.0f); + "Jupiteroid-Regular.ttf", 24.0f); _smallFont = createFont("smallFont", "General", - "Jupiteroid-Regular.ttf", 13.0f); + "Jupiteroid-Regular.ttf", 18.0f); _bigFont = createFont("bigFont", "General", "Kenney Bold.ttf", - 32.0f); + 36.0f); smallFont = ECS::get().mGuiOverlay->addFont( "smallFont", "General"); OgreAssert(smallFont, "Could not load font"); @@ -370,12 +370,24 @@ struct GUIListener : public Ogre::RenderTargetListener { ImGui::End(); } else if (ECS::get().get().enabled) { if (ECS::get().get().mainMenu) { - ImVec2 size = ImGui::GetMainViewport()->Size; + ImGuiViewport *viewport = + ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(viewport->WorkPos, + ImGuiCond_Always); + ImGui::SetNextWindowSize(viewport->WorkSize, + ImGuiCond_Always); + ImGui::PushStyleVar( + ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar( + ImGuiStyleVar_WindowBorderSize, 0.0f); + +#if 0 ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); ImGui::SetNextWindowSize(ImVec2(size.x + 4, size.y + 1), ImGuiCond_Always); +#endif ImVec4 solidColor = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); ImGui::PushStyleColor(ImGuiCol_WindowBg, @@ -388,31 +400,81 @@ struct GUIListener : public Ogre::RenderTargetListener { ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | - ImGuiWindowFlags_NoFocusOnAppearing | + ImGuiWindowFlags_NoFocusOnAppearing | + ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoBringToFrontOnFocus | 0); - ImGui::PushFont(bigFont); + struct buttons { + std::string label; + std::function callback; + }; + bool new_game = false, cont = false, + load_game = false, opts = false, + quit = false; + struct buttons buttons_data[] = { + { "New Game", + [&](bool pressed) { + new_game = true; + } }, + { "Continue", + [&](bool pressed) { cont = true; } }, + { "Load Game", + [&](bool pressed) { + load_game = true; + } }, + { "Options", + [&](bool pressed) { opts = true; } }, + { "Quit###quit", + [&](bool pressed) { quit = true; } }, + }; + ImVec2 size = ImGui::GetWindowSize(); + float window_width = size.x; + float window_height = size.y; + ImGui::PushFont(bigFont); ImGui::TextWrapped("%s", "Booo!!!!"); - bool pressed = false; - bool new_game = false, cont = false, - load_game = false, opts = false, - quit = false; - ImGui::SetCursorPosY(size.y / 2.0f - 300.0f); - ImGui::SetCursorPosX(size.x / 2.0f - 300.0f); - new_game = ImGui::Button("New Game"); - ImGui::SetCursorPosX(size.x / 2.0f - 300.0f); - cont = ImGui::Button("Continue"); - ImGui::SetCursorPosX(size.x / 2.0f - 300.0f); - load_game = ImGui::Button("Load Game"); - ImGui::SetCursorPosX(size.x / 2.0f - 300.0f); - opts = ImGui::Button("Options"); - ImGui::SetCursorPosX(size.x / 2.0f - 300.0f); - quit = ImGui::Button("Quit###quit"); + float extra_pixels = 20.0f; + float button_width = 0.0f; + float buttons_height = 0.0f; + for (const struct buttons &b : buttons_data) { + ImVec2 text_size = ImGui::CalcTextSize( + b.label.c_str()); + float text_width = text_size.x; + float text_height = text_size.y; + float bwidth = + text_width + + (ImGui::GetStyle() + .FramePadding.x * + 2.0f) + + extra_pixels; + if (button_width < bwidth) + button_width = bwidth; + buttons_height += + text_height + + (ImGui::GetStyle() + .FramePadding.y * + 2.0f); + } + ImGui::SetCursorPosY( + (window_height - buttons_height) * + 0.5f); + for (const struct buttons &b : buttons_data) { + ImGui::SetCursorPosX( + (window_width - button_width) * + 0.5f); + if (ImGui::Button(b.label.c_str(), + ImVec2(button_width, + 0))) + b.callback(true); + } + bool pressed = false; pressed = new_game || cont || load_game || opts || quit; ImGui::PopFont(); ImGui::Spacing(); ImGui::End(); ImGui::PopStyleColor(); + ImGui::PopStyleVar(); + ImGui::PopStyleVar(); if (quit) Ogre::Root::getSingleton() .queueEndRendering(); @@ -686,7 +748,9 @@ void GUIModule::configure() const App &app = ECS::get(); if (gui.mGuiOverlay) return; - float vpScale = window.dpi / 96 * window.window->getWidth() / 1600.0f; + float vpScale = window.dpi / 96; + if (vpScale < 1.0f) + vpScale = 1.0f; Ogre::OverlayManager::getSingleton().setPixelRatio(vpScale); std::cout << "GUI configure\n"; OgreAssert(app.mGuiOverlay, "No ImGUI overlay");