static void getStack(CONTEXT& context, char* out, int max_size) { BOOL result; HANDLE process; HANDLE thread; STACKFRAME64 stack; char symbol_mem[sizeof(IMAGEHLP_SYMBOL64) + 256]; IMAGEHLP_SYMBOL64* symbol = (IMAGEHLP_SYMBOL64*)symbol_mem; DWORD64 displacement; char name[256]; copyString(out, max_size, "Crash callstack:\n"); memset(&stack, 0, sizeof(STACKFRAME64)); process = GetCurrentProcess(); thread = GetCurrentThread(); displacement = 0; DWORD machineType; #ifdef _WIN64 machineType = IMAGE_FILE_MACHINE_IA64; stack.AddrPC.Offset = context.Rip; stack.AddrPC.Mode = AddrModeFlat; stack.AddrStack.Offset = context.Rsp; stack.AddrStack.Mode = AddrModeFlat; stack.AddrFrame.Offset = context.Rbp; stack.AddrFrame.Mode = AddrModeFlat; #else machineType = IMAGE_FILE_MACHINE_I386; stack.AddrPC.Offset = context.Eip; stack.AddrPC.Mode = AddrModeFlat; stack.AddrStack.Offset = context.Esp; stack.AddrStack.Mode = AddrModeFlat; stack.AddrFrame.Offset = context.Ebp; stack.AddrFrame.Mode = AddrModeFlat; #endif do { result = StackWalk64(machineType, process, thread, &stack, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL); symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); symbol->MaxNameLength = 255; SymGetSymFromAddr64(process, (ULONG64)stack.AddrPC.Offset, &displacement, symbol); UnDecorateSymbolName(symbol->Name, (PSTR)name, 256, UNDNAME_COMPLETE); catString(out, max_size, symbol->Name); catString(out, max_size, "\n"); } while (result); }
bool Shader::generateInstances() { for (int i = 0; i < m_instances.size(); ++i) { LUMIX_DELETE(m_allocator, m_instances[i]); } m_instances.clear(); uint32 count = 1 << m_combintions.m_define_count; auto* binary_manager = m_resource_manager.get(ResourceManager::SHADER_BINARY); char basename[MAX_PATH_LENGTH]; PathUtils::getBasename(basename, sizeof(basename), getPath().c_str()); for (uint32 mask = 0; mask < count; ++mask) { ShaderInstance* instance = LUMIX_NEW(m_allocator, ShaderInstance)(*this); m_instances.push(instance); instance->m_define_mask = getDefineMaskFromDense(mask); for (int pass_idx = 0; pass_idx < m_combintions.m_pass_count; ++pass_idx) { const char* pass = m_combintions.m_passes[pass_idx]; char path[MAX_PATH_LENGTH]; copyString(path, "shaders/compiled/"); catString(path, basename); catString(path, "_"); catString(path, pass); char mask_str[10]; int actual_mask = mask & m_combintions.m_vs_local_mask[pass_idx]; toCString(actual_mask, mask_str, sizeof(mask_str)); catString(path, mask_str); catString(path, "_vs.shb"); Path vs_path(path); auto* vs_binary = static_cast<ShaderBinary*>(binary_manager->load(vs_path)); addDependency(*vs_binary); instance->m_binaries[pass_idx * 2] = vs_binary; copyString(path, "shaders/compiled/"); catString(path, basename); catString(path, "_"); catString(path, pass); actual_mask = mask & m_combintions.m_fs_local_mask[pass_idx]; toCString(actual_mask, mask_str, sizeof(mask_str)); catString(path, mask_str); catString(path, "_fs.shb"); Path fs_path(path); auto* fs_binary = static_cast<ShaderBinary*>(binary_manager->load(fs_path)); addDependency(*fs_binary); instance->m_binaries[pass_idx * 2 + 1] = fs_binary; } } return true; }
void outputToVS(const char* system, const char* message) { char tmp[2048]; copyString(tmp, system); catString(tmp, ": "); catString(tmp, message); catString(tmp, "\r"); OutputDebugString(tmp); }
IPlugin* load(const char* path) override { char path_with_ext[MAX_PATH_LENGTH]; copyString(path_with_ext, path); const char* ext = #ifdef _WIN32 ".dll"; #elif defined __linux__ ".so"; #else #error Unknown platform #endif if (!PathUtils::hasExtension(path, ext + 1)) catString(path_with_ext, ext); g_log_info.log("Core") << "loading plugin " << path_with_ext; typedef IPlugin* (*PluginCreator)(Engine&); auto* lib = loadLibrary(path_with_ext); if (lib) { PluginCreator creator = (PluginCreator)getLibrarySymbol(lib, "createPlugin"); if (creator) { IPlugin* plugin = creator(m_engine); if (!plugin) { g_log_error.log("Core") << "createPlugin failed."; LUMIX_DELETE(m_engine.getAllocator(), plugin); ASSERT(false); } else { addPlugin(plugin); m_libraries.push(lib); m_library_loaded.invoke(lib); g_log_info.log("Core") << "Plugin loaded."; Debug::StackTree::refreshModuleList(); return plugin; } } else { g_log_error.log("Core") << "No createPlugin function in plugin."; } unloadLibrary(lib); } else { auto* plugin = StaticPluginRegister::create(path, m_engine); if (plugin) { g_log_info.log("Core") << "Plugin loaded."; addPlugin(plugin); return plugin; } g_log_warning.log("Core") << "Failed to load plugin."; } return nullptr; }
FileIterator* createFileIterator(const char* path, IAllocator& allocator) { char tmp[MAX_PATH_LENGTH]; copyString(tmp, path); catString(tmp, "/*"); auto* iter = LUMIX_NEW(allocator, FileIterator); iter->allocator = &allocator; iter->handle = FindFirstFile(tmp, &iter->ffd); iter->is_valid = iter->handle != INVALID_HANDLE_VALUE; return iter; }
void registerUniverse(UniverseContext* ctx, lua_State* L) { lua_pushlightuserdata(L, ctx); lua_setglobal(L, "g_universe_context"); for (auto* scene : ctx->m_scenes) { const char* name = scene->getPlugin().getName(); char tmp[128]; copyString(tmp, "g_scene_"); catString(tmp, name); lua_pushlightuserdata(L, scene); lua_setglobal(L, tmp); } lua_pushlightuserdata(L, ctx ? ctx->m_universe : nullptr); lua_setglobal(L, "g_universe"); }
bool Model::parseMeshes(FS::IFile& file) { int object_count = 0; file.read(&object_count, sizeof(object_count)); if (object_count <= 0) return false; m_meshes.reserve(object_count); char model_dir[MAX_PATH_LENGTH]; PathUtils::getDir(model_dir, MAX_PATH_LENGTH, getPath().c_str()); for (int i = 0; i < object_count; ++i) { int32 str_size; file.read(&str_size, sizeof(str_size)); char material_name[MAX_PATH_LENGTH]; file.read(material_name, str_size); if (str_size >= MAX_PATH_LENGTH) return false; material_name[str_size] = 0; char material_path[MAX_PATH_LENGTH]; copyString(material_path, model_dir); catString(material_path, material_name); catString(material_path, ".mat"); auto* material_manager = m_resource_manager.get(ResourceManager::MATERIAL); Material* material = static_cast<Material*>(material_manager->load(Path(material_path))); int32 attribute_array_offset = 0; file.read(&attribute_array_offset, sizeof(attribute_array_offset)); int32 attribute_array_size = 0; file.read(&attribute_array_size, sizeof(attribute_array_size)); int32 indices_offset = 0; file.read(&indices_offset, sizeof(indices_offset)); int32 mesh_tri_count = 0; file.read(&mesh_tri_count, sizeof(mesh_tri_count)); file.read(&str_size, sizeof(str_size)); if (str_size >= MAX_PATH_LENGTH) { material_manager->unload(*material); return false; } char mesh_name[MAX_PATH_LENGTH]; mesh_name[str_size] = 0; file.read(mesh_name, str_size); bgfx::VertexDecl def; parseVertexDef(file, &def); m_meshes.emplace(def, material, attribute_array_offset, attribute_array_size, indices_offset, mesh_tri_count * 3, mesh_name, m_allocator); addDependency(*material); } return true; }
bool Model::parseMeshesOld(bgfx::VertexDecl global_vertex_decl, FS::IFile& file, FileVersion version, u32 global_flags) { int object_count = 0; file.read(&object_count, sizeof(object_count)); if (object_count <= 0) return false; m_meshes.reserve(object_count); char model_dir[MAX_PATH_LENGTH]; PathUtils::getDir(model_dir, MAX_PATH_LENGTH, getPath().c_str()); struct Offsets { i32 attribute_array_offset; i32 attribute_array_size; i32 indices_offset; i32 mesh_tri_count; }; Array<Offsets> mesh_offsets(m_allocator); for (int i = 0; i < object_count; ++i) { i32 str_size; file.read(&str_size, sizeof(str_size)); char material_name[MAX_PATH_LENGTH]; file.read(material_name, str_size); if (str_size >= MAX_PATH_LENGTH) return false; material_name[str_size] = 0; char material_path[MAX_PATH_LENGTH]; copyString(material_path, model_dir); catString(material_path, material_name); catString(material_path, ".mat"); auto* material_manager = m_resource_manager.getOwner().get(Material::TYPE); Material* material = static_cast<Material*>(material_manager->load(Path(material_path))); Offsets& offsets = mesh_offsets.emplace(); file.read(&offsets.attribute_array_offset, sizeof(offsets.attribute_array_offset)); file.read(&offsets.attribute_array_size, sizeof(offsets.attribute_array_size)); file.read(&offsets.indices_offset, sizeof(offsets.indices_offset)); file.read(&offsets.mesh_tri_count, sizeof(offsets.mesh_tri_count)); file.read(&str_size, sizeof(str_size)); if (str_size >= MAX_PATH_LENGTH) { material_manager->unload(*material); return false; } char mesh_name[MAX_PATH_LENGTH]; mesh_name[str_size] = 0; file.read(mesh_name, str_size); bgfx::VertexDecl vertex_decl = global_vertex_decl; if (version <= FileVersion::SINGLE_VERTEX_DECL) { parseVertexDecl(file, &vertex_decl); if (i != 0 && global_vertex_decl.m_hash != vertex_decl.m_hash) { g_log_error.log("Renderer") << "Model " << getPath().c_str() << " contains meshes with different vertex declarations."; } if(i == 0) global_vertex_decl = vertex_decl; } m_meshes.emplace(material, vertex_decl, mesh_name, m_allocator); addDependency(*material); } i32 indices_count = 0; file.read(&indices_count, sizeof(indices_count)); if (indices_count <= 0) return false; u32 INDICES_16BIT_FLAG = 1; int index_size = global_flags & INDICES_16BIT_FLAG ? 2 : 4; Array<u8> indices(m_allocator); indices.resize(indices_count * index_size); file.read(&indices[0], indices.size()); i32 vertices_size = 0; file.read(&vertices_size, sizeof(vertices_size)); if (vertices_size <= 0) return false; Array<u8> vertices(m_allocator); vertices.resize(vertices_size); file.read(&vertices[0], vertices.size()); int vertex_count = 0; for (const Offsets& offsets : mesh_offsets) { vertex_count += offsets.attribute_array_size / global_vertex_decl.getStride(); } if (version > FileVersion::BOUNDING_SHAPES_PRECOMPUTED) { file.read(&m_bounding_radius, sizeof(m_bounding_radius)); file.read(&m_aabb, sizeof(m_aabb)); } float bounding_radius_squared = 0; Vec3 min_vertex(0, 0, 0); Vec3 max_vertex(0, 0, 0); int vertex_size = global_vertex_decl.getStride(); int position_attribute_offset = global_vertex_decl.getOffset(bgfx::Attrib::Position); int uv_attribute_offset = global_vertex_decl.getOffset(bgfx::Attrib::TexCoord0); int weights_attribute_offset = global_vertex_decl.getOffset(bgfx::Attrib::Weight); int bone_indices_attribute_offset = global_vertex_decl.getOffset(bgfx::Attrib::Indices); bool keep_skin = global_vertex_decl.has(bgfx::Attrib::Weight) && global_vertex_decl.has(bgfx::Attrib::Indices); for (int i = 0; i < m_meshes.size(); ++i) { Offsets& offsets = mesh_offsets[i]; Mesh& mesh = m_meshes[i]; mesh.indices_count = offsets.mesh_tri_count * 3; mesh.indices.resize(mesh.indices_count * index_size); copyMemory(&mesh.indices[0], &indices[offsets.indices_offset * index_size], mesh.indices_count * index_size); int mesh_vertex_count = offsets.attribute_array_size / global_vertex_decl.getStride(); int mesh_attributes_array_offset = offsets.attribute_array_offset; mesh.vertices.resize(mesh_vertex_count); mesh.uvs.resize(mesh_vertex_count); if (keep_skin) mesh.skin.resize(mesh_vertex_count); for (int j = 0; j < mesh_vertex_count; ++j) { int offset = mesh_attributes_array_offset + j * vertex_size; if (keep_skin) { mesh.skin[j].weights = *(const Vec4*)&vertices[offset + weights_attribute_offset]; copyMemory(mesh.skin[j].indices, &vertices[offset + bone_indices_attribute_offset], sizeof(mesh.skin[j].indices)); } mesh.vertices[j] = *(const Vec3*)&vertices[offset + position_attribute_offset]; mesh.uvs[j] = *(const Vec2*)&vertices[offset + uv_attribute_offset]; float sq_len = mesh.vertices[j].squaredLength(); bounding_radius_squared = Math::maximum(bounding_radius_squared, sq_len > 0 ? sq_len : 0); min_vertex.x = Math::minimum(min_vertex.x, mesh.vertices[j].x); min_vertex.y = Math::minimum(min_vertex.y, mesh.vertices[j].y); min_vertex.z = Math::minimum(min_vertex.z, mesh.vertices[j].z); max_vertex.x = Math::maximum(max_vertex.x, mesh.vertices[j].x); max_vertex.y = Math::maximum(max_vertex.y, mesh.vertices[j].y); max_vertex.z = Math::maximum(max_vertex.z, mesh.vertices[j].z); } } if (version <= FileVersion::BOUNDING_SHAPES_PRECOMPUTED) { m_bounding_radius = sqrt(bounding_radius_squared); m_aabb = AABB(min_vertex, max_vertex); } for (int i = 0; i < m_meshes.size(); ++i) { Mesh& mesh = m_meshes[i]; Offsets offsets = mesh_offsets[i]; ASSERT(!bgfx::isValid(mesh.index_buffer_handle)); if (global_flags & INDICES_16BIT_FLAG) { mesh.flags.set(Mesh::Flags::INDICES_16_BIT); } int indices_size = index_size * mesh.indices_count; const bgfx::Memory* mem = bgfx::copy(&indices[offsets.indices_offset * index_size], indices_size); mesh.index_buffer_handle = bgfx::createIndexBuffer(mem, index_size == 4 ? BGFX_BUFFER_INDEX32 : 0); if (!bgfx::isValid(mesh.index_buffer_handle)) return false; ASSERT(!bgfx::isValid(mesh.vertex_buffer_handle)); const bgfx::Memory* vertices_mem = bgfx::copy(&vertices[offsets.attribute_array_offset], offsets.attribute_array_size); mesh.vertex_buffer_handle = bgfx::createVertexBuffer(vertices_mem, mesh.vertex_decl); if (!bgfx::isValid(mesh.vertex_buffer_handle)) return false; } return true; }
bool Model::parseMeshes(const bgfx::VertexDecl& global_vertex_decl, FS::IFile& file, FileVersion version, u32 global_flags) { if (version <= FileVersion::MULTIPLE_VERTEX_DECLS) return parseMeshesOld(global_vertex_decl, file, version, global_flags); int object_count = 0; file.read(&object_count, sizeof(object_count)); if (object_count <= 0) return false; char model_dir[MAX_PATH_LENGTH]; PathUtils::getDir(model_dir, MAX_PATH_LENGTH, getPath().c_str()); m_meshes.reserve(object_count); for (int i = 0; i < object_count; ++i) { bgfx::VertexDecl vertex_decl; if (!parseVertexDeclEx(file, &vertex_decl)) return false; i32 str_size; file.read(&str_size, sizeof(str_size)); char material_name[MAX_PATH_LENGTH]; file.read(material_name, str_size); if (str_size >= MAX_PATH_LENGTH) return false; material_name[str_size] = 0; char material_path[MAX_PATH_LENGTH]; copyString(material_path, model_dir); catString(material_path, material_name); catString(material_path, ".mat"); auto* material_manager = m_resource_manager.getOwner().get(Material::TYPE); Material* material = static_cast<Material*>(material_manager->load(Path(material_path))); file.read(&str_size, sizeof(str_size)); char mesh_name[MAX_PATH_LENGTH]; mesh_name[str_size] = 0; file.read(mesh_name, str_size); m_meshes.emplace(material, vertex_decl, mesh_name, m_allocator); addDependency(*material); } for (int i = 0; i < object_count; ++i) { Mesh& mesh = m_meshes[i]; int index_size; int indices_count; file.read(&index_size, sizeof(index_size)); if (index_size != 2 && index_size != 4) return false; file.read(&indices_count, sizeof(indices_count)); if (indices_count <= 0) return false; mesh.indices.resize(index_size * indices_count); file.read(&mesh.indices[0], mesh.indices.size()); if (index_size == 2) mesh.flags.set(Mesh::Flags::INDICES_16_BIT); mesh.indices_count = indices_count; const bgfx::Memory* indices_mem = bgfx::copy(&mesh.indices[0], mesh.indices.size()); mesh.index_buffer_handle = bgfx::createIndexBuffer(indices_mem); } for (int i = 0; i < object_count; ++i) { Mesh& mesh = m_meshes[i]; int data_size; file.read(&data_size, sizeof(data_size)); const bgfx::Memory* vertices_mem = bgfx::alloc(data_size); file.read(vertices_mem->data, vertices_mem->size); const bgfx::VertexDecl& vertex_decl = mesh.vertex_decl; int position_attribute_offset = vertex_decl.getOffset(bgfx::Attrib::Position); int uv_attribute_offset = vertex_decl.getOffset(bgfx::Attrib::TexCoord0); int weights_attribute_offset = vertex_decl.getOffset(bgfx::Attrib::Weight); int bone_indices_attribute_offset = vertex_decl.getOffset(bgfx::Attrib::Indices); bool keep_skin = vertex_decl.has(bgfx::Attrib::Weight) && vertex_decl.has(bgfx::Attrib::Indices); int vertex_size = mesh.vertex_decl.getStride(); int mesh_vertex_count = vertices_mem->size / mesh.vertex_decl.getStride(); mesh.vertices.resize(mesh_vertex_count); mesh.uvs.resize(mesh_vertex_count); if (keep_skin) mesh.skin.resize(mesh_vertex_count); const u8* vertices = vertices_mem->data; for (int j = 0; j < mesh_vertex_count; ++j) { int offset = j * vertex_size; if (keep_skin) { mesh.skin[j].weights = *(const Vec4*)&vertices[offset + weights_attribute_offset]; copyMemory(mesh.skin[j].indices, &vertices[offset + bone_indices_attribute_offset], sizeof(mesh.skin[j].indices)); } mesh.vertices[j] = *(const Vec3*)&vertices[offset + position_attribute_offset]; mesh.uvs[j] = *(const Vec2*)&vertices[offset + uv_attribute_offset]; } mesh.vertex_buffer_handle = bgfx::createVertexBuffer(vertices_mem, mesh.vertex_decl); } file.read(&m_bounding_radius, sizeof(m_bounding_radius)); file.read(&m_aabb, sizeof(m_aabb)); return true; }
bool Material::deserializeTexture(JsonSerializer& serializer, const char* material_dir) { char path[MAX_PATH_LENGTH]; serializer.deserializeObjectBegin(); char label[256]; bool keep_data = false; uint32 flags = 0; int atlas_size = -1; while (!serializer.isObjectEnd()) { serializer.deserializeLabel(label, sizeof(label)); if (compareString(label, "source") == 0) { serializer.deserialize(path, MAX_PATH_LENGTH, ""); if (path[0] != '\0') { char texture_path[MAX_PATH_LENGTH]; if (path[0] != '/' && path[0] != '\\') { copyString(texture_path, material_dir); catString(texture_path, path); } else { copyString(texture_path, path); } m_textures[m_texture_count] = static_cast<Texture*>( m_resource_manager.get(ResourceManager::TEXTURE)->load(Path(texture_path))); addDependency(*m_textures[m_texture_count]); } } else if (compareString(label, "atlas_size") == 0) { serializer.deserialize(atlas_size, -1); } else if (compareString(label, "min_filter") == 0) { serializer.deserialize(label, sizeof(label), ""); if (compareString(label, "point") == 0) { flags |= BGFX_TEXTURE_MIN_POINT; } else if (compareString(label, "anisotropic") == 0) { flags |= BGFX_TEXTURE_MIN_ANISOTROPIC; } else { g_log_error.log("Renderer") << "Unknown texture filter \"" << label << "\" in material " << getPath().c_str(); } } else if (compareString(label, "mag_filter") == 0) { serializer.deserialize(label, sizeof(label), ""); if (compareString(label, "point") == 0) { flags |= BGFX_TEXTURE_MAG_POINT; } else if (compareString(label, "anisotropic") == 0) { flags |= BGFX_TEXTURE_MAG_ANISOTROPIC; } else { g_log_error.log("Renderer") << "Unknown texture filter \"" << label << "\" in material " << getPath().c_str(); } } else if (compareString(label, "u_clamp") == 0) { bool b; serializer.deserialize(b, false); if (b) { flags |= BGFX_TEXTURE_U_CLAMP; } } else if (compareString(label, "v_clamp") == 0) { bool b; serializer.deserialize(b, false); if (b) { flags |= BGFX_TEXTURE_V_CLAMP; } } else if (compareString(label, "w_clamp") == 0) { bool b; serializer.deserialize(b, false); if (b) { flags |= BGFX_TEXTURE_W_CLAMP; } } else if (compareString(label, "keep_data") == 0) { serializer.deserialize(keep_data, false); } else { g_log_warning.log("Renderer") << "Unknown data \"" << label << "\" in material " << getPath().c_str(); return false; } } if (m_textures[m_texture_count]) { m_textures[m_texture_count]->setAtlasSize(atlas_size); m_textures[m_texture_count]->setFlags(flags); if (keep_data) { m_textures[m_texture_count]->addDataReference(); } } serializer.deserializeObjectEnd(); ++m_texture_count; return true; }