aboutsummaryrefslogtreecommitdiff
path: root/extension/src/openvic-extension/utility/Utilities.cpp
blob: e3bcce6baec8f2f5842104d4ce5858b7d98e898f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include "Utilities.hpp"

#include <numbers>

#include <godot_cpp/classes/file_access.hpp>
#include <godot_cpp/classes/resource_loader.hpp>
#include <godot_cpp/classes/translation_server.hpp>
#include <godot_cpp/variant/utility_functions.hpp>

#include <gli/convert.hpp>
#include <gli/load_dds.hpp>

using namespace godot;
using namespace OpenVic;

/* Date formatted like this: "January 1, 1836" (with the month localised, if possible). */
String Utilities::date_to_formatted_string(Date date) {
   std::string const& month_name = date.get_month_name();
   const String day_and_year = " " + String::num_int64(date.get_day()) + ", " + String::num_int64(date.get_year());
   TranslationServer const* server = TranslationServer::get_singleton();
   if (server != nullptr) {
      return server->translate(std_to_godot_string_name(month_name)) + day_and_year;
   } else {
      return std_to_godot_string(month_name) + day_and_year;
   }
}

Ref<Resource> Utilities::load_resource(String const& path, String const& type_hint) {
   ResourceLoader* loader = ResourceLoader::get_singleton();
   ERR_FAIL_NULL_V(loader, nullptr);
   return loader->load(path, type_hint);
}

static Ref<Image> load_dds_image(String const& path) {
   gli::texture2d texture { gli::load_dds(Utilities::godot_to_std_string(path)) };
   if (texture.empty()) {
      UtilityFunctions::push_error("Failed to load DDS file: ", path);
      return nullptr;
   }

   static constexpr gli::format expected_format = gli::FORMAT_BGRA8_UNORM_PACK8;
   const bool needs_bgr_to_rgb = texture.format() == expected_format;
   if (!needs_bgr_to_rgb) {
      texture = gli::convert(texture, expected_format);
      if (texture.empty()) {
         UtilityFunctions::push_error("Failed to convert DDS file: ", path);
         return nullptr;
      }
   }

   const gli::texture2d::extent_type extent { texture.extent() };
   const int width = extent.x, height = extent.y, size = width * height * 4;

   /* Only fail if there aren't enough bytes, everything seems to work fine if there are extra bytes and we ignore them */
   if (size > texture.size()) {
      UtilityFunctions::push_error(
         "Texture size ", static_cast<int64_t>(texture.size()), " mismatched with dims-based size ", size, " for ", path
      );
      return nullptr;
   }

   PackedByteArray pixels;
   pixels.resize(size);
   /* Index offset used to control whether we are reading */
   const size_t rb_idx = 2 * needs_bgr_to_rgb;
   uint8_t const* ptr = static_cast<uint8_t const*>(texture.data());
   for (size_t i = 0; i < size; i += 4) {
      pixels[i + 0] = ptr[i + rb_idx];
      pixels[i + 1] = ptr[i + 1];
      pixels[i + 2] = ptr[i + 2 - rb_idx];
      pixels[i + 3] = ptr[i + 3];
   }

   return Image::create_from_data(width, height, false, Image::FORMAT_RGBA8, pixels);
}

Ref<Image> Utilities::load_godot_image(String const& path) {
   if (path.ends_with(".dds")) {
      return load_dds_image(path);
   }
   return Image::load_from_file(path);
}

Ref<FontFile> Utilities::load_godot_font(String const& fnt_path, Ref<Image> const& image) {
   Ref<FontFile> font;
   font.instantiate();
   const Error err = font->load_bitmap_font(fnt_path);
   font->set_texture_image(0, { font->get_fixed_size(), 0 }, 0, image);
   if (err != OK) {
      UtilityFunctions::push_error("Failed to load font (error ", err, "): ", fnt_path);
   }
   return font;
}