Antkeeper  0.0.1
texture.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Christopher J. Howard
3  *
4  * This file is part of Antkeeper source code.
5  *
6  * Antkeeper source code is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Antkeeper source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <engine/gl/texture.hpp>
25 
26 namespace {
27 
28  enum texture_type: std::uint8_t
29  {
30  texture_type_1d,
31  texture_type_1d_array,
32  texture_type_2d,
33  texture_type_2d_array,
34  texture_type_3d,
35  texture_type_cube,
36  texture_type_cube_array
37  };
38 
39  [[nodiscard]] std::unique_ptr<gl::texture> load_texture(::resource_manager& resource_manager, deserialize_context& ctx, std::uint8_t texture_type)
40  {
41  // Read file format identifier
42  std::uint32_t format_identifier{0};
43  ctx.read32_le(reinterpret_cast<std::byte*>(&format_identifier), 1);
44 
45  // Validate file format identifier (U+1F5BC = framed picture)
46  if (format_identifier != 0xbc969ff0)
47  {
48  throw deserialize_error("Invalid texture file.");
49  }
50 
51  // Read file format version
52  std::uint32_t format_version{0};
53  ctx.read32_le(reinterpret_cast<std::byte*>(&format_version), 1);
54 
55  // Validate file format version
56  if (format_version != 1)
57  {
58  throw deserialize_error("Unsupported texture file version.");
59  }
60 
61  // Read image path
62  std::uint32_t image_path_length{0};
63  ctx.read32_le(reinterpret_cast<std::byte*>(&image_path_length), 1);
64  std::string image_path(image_path_length, '\0');
65  ctx.read8(reinterpret_cast<std::byte*>(image_path.data()), image_path_length);
66 
67  // Load image
68  std::shared_ptr<gl::image> image;
69  switch (texture_type)
70  {
71  case texture_type_1d:
72  case texture_type_1d_array:
73  image = resource_manager.load<gl::image_1d>(image_path);
74  break;
75 
76  case texture_type_2d:
77  case texture_type_2d_array:
78  image = resource_manager.load<gl::image_2d>(image_path);
79  break;
80 
81  case texture_type_3d:
82  image = resource_manager.load<gl::image_3d>(image_path);
83  break;
84 
85  case texture_type_cube:
86  case texture_type_cube_array:
87  image = resource_manager.load<gl::image_cube>(image_path);
88  break;
89 
90  default:
91  throw deserialize_error("Invalid texture type.");
92  }
93 
94  // Read image view parameters
96  std::uint32_t first_mip_level;
97  std::uint32_t mip_level_count;
98  std::uint32_t first_array_layer;
99  std::uint32_t array_layer_count;
100  ctx.read32_le(reinterpret_cast<std::byte*>(&format), 1);
101  ctx.read32_le(reinterpret_cast<std::byte*>(&first_mip_level), 1);
102  ctx.read32_le(reinterpret_cast<std::byte*>(&mip_level_count), 1);
103  ctx.read32_le(reinterpret_cast<std::byte*>(&first_array_layer), 1);
104  ctx.read32_le(reinterpret_cast<std::byte*>(&array_layer_count), 1);
105 
106  // Handle automatic mip level count (`0`)
107  if (!mip_level_count)
108  {
109  mip_level_count = image->get_mip_levels();
110  }
111 
112  // Handle automatic array layer count (`0`)
113  if (!array_layer_count)
114  {
115  array_layer_count = image->get_array_layers();
116  }
117 
118  // Read sampler parameters
119  gl::sampler_filter mag_filter;
120  gl::sampler_filter min_filter;
121  gl::sampler_mipmap_mode mipmap_mode;
122  gl::sampler_address_mode address_mode_u;
123  gl::sampler_address_mode address_mode_v;
124  gl::sampler_address_mode address_mode_w;
125  float mip_lod_bias;
126  float max_anisotropy;
127  std::uint8_t compare_enabled;
129  float min_lod;
130  float max_lod;
131  std::array<float, 4> border_color;
132  ctx.read8(reinterpret_cast<std::byte*>(&mag_filter), 1);
133  ctx.read8(reinterpret_cast<std::byte*>(&min_filter), 1);
134  ctx.read8(reinterpret_cast<std::byte*>(&mipmap_mode), 1);
135  ctx.read8(reinterpret_cast<std::byte*>(&address_mode_u), 1);
136  ctx.read8(reinterpret_cast<std::byte*>(&address_mode_v), 1);
137  ctx.read8(reinterpret_cast<std::byte*>(&address_mode_w), 1);
138  ctx.read32_le(reinterpret_cast<std::byte*>(&mip_lod_bias), 1);
139  ctx.read32_le(reinterpret_cast<std::byte*>(&max_anisotropy), 1);
140  ctx.read8(reinterpret_cast<std::byte*>(&compare_enabled), 1);
141  ctx.read8(reinterpret_cast<std::byte*>(&compare_op), 1);
142  ctx.read32_le(reinterpret_cast<std::byte*>(&min_lod), 1);
143  ctx.read32_le(reinterpret_cast<std::byte*>(&max_lod), 1);
144  ctx.read32_le(reinterpret_cast<std::byte*>(border_color.data()), 4);
145 
146  // Construct sampler
147  std::shared_ptr<gl::sampler> sampler = std::make_shared<gl::sampler>
148  (
149  mag_filter,
150  min_filter,
151  mipmap_mode,
152  address_mode_u,
153  address_mode_v,
154  address_mode_w,
155  mip_lod_bias,
156  max_anisotropy,
157  compare_enabled,
158  compare_op,
159  min_lod,
160  max_lod,
161  border_color
162  );
163 
164  // Construct image view and texture
165  switch (texture_type)
166  {
167  case texture_type_1d:
168  {
169  auto image_view = std::make_shared<gl::image_view_1d>(image, format, first_mip_level, mip_level_count, first_array_layer);
170  return std::make_unique<gl::texture_1d>(std::move(image_view), std::move(sampler));
171  }
172 
173  case texture_type_1d_array:
174  {
175  auto image_view = std::make_shared<gl::image_view_1d_array>(image, format, first_mip_level, mip_level_count, first_array_layer, array_layer_count);
176  return std::make_unique<gl::texture_1d_array>(std::move(image_view), std::move(sampler));
177  }
178 
179  case texture_type_2d:
180  {
181  auto image_view = std::make_shared<gl::image_view_2d>(image, format, first_mip_level, mip_level_count, first_array_layer);
182  return std::make_unique<gl::texture_2d>(std::move(image_view), std::move(sampler));
183  }
184 
185  case texture_type_2d_array:
186  {
187  auto image_view = std::make_shared<gl::image_view_2d_array>(image, format, first_mip_level, mip_level_count, first_array_layer, array_layer_count);
188  return std::make_unique<gl::texture_2d_array>(std::move(image_view), std::move(sampler));
189  }
190 
191  case texture_type_3d:
192  {
193  auto image_view = std::make_shared<gl::image_view_3d>(image, format, first_mip_level, mip_level_count);
194  return std::make_unique<gl::texture_3d>(std::move(image_view), std::move(sampler));
195  }
196 
197  case texture_type_cube:
198  {
199  auto image_view = std::make_shared<gl::image_view_cube>(image, format, first_mip_level, mip_level_count, first_array_layer);
200  return std::make_unique<gl::texture_cube>(std::move(image_view), std::move(sampler));
201  }
202 
203  case texture_type_cube_array:
204  {
205  auto image_view = std::make_shared<gl::image_view_cube_array>(image, format, first_mip_level, mip_level_count, first_array_layer, array_layer_count);
206  return std::make_unique<gl::texture_cube_array>(std::move(image_view), std::move(sampler));
207  }
208 
209  default:
210  return nullptr;
211  }
212  }
213 
214 }
215 
216 template <>
218 {
219  return std::unique_ptr<gl::texture_1d>(static_cast<gl::texture_1d*>(load_texture(resource_manager, ctx, texture_type_1d).release()));
220 }
221 
222 template <>
224 {
225  return std::unique_ptr<gl::texture_1d_array>(static_cast<gl::texture_1d_array*>(load_texture(resource_manager, ctx, texture_type_1d_array).release()));
226 }
227 
228 template <>
230 {
231  return std::unique_ptr<gl::texture_2d>(static_cast<gl::texture_2d*>(load_texture(resource_manager, ctx, texture_type_2d).release()));
232 }
233 
234 template <>
236 {
237  return std::unique_ptr<gl::texture_2d_array>(static_cast<gl::texture_2d_array*>(load_texture(resource_manager, ctx, texture_type_2d_array).release()));
238 }
239 
240 template <>
242 {
243  return std::unique_ptr<gl::texture_3d>(static_cast<gl::texture_3d*>(load_texture(resource_manager, ctx, texture_type_3d).release()));
244 }
245 
246 template <>
248 {
249  return std::unique_ptr<gl::texture_cube>(static_cast<gl::texture_cube*>(load_texture(resource_manager, ctx, texture_type_cube).release()));
250 }
251 
252 template <>
254 {
255  return std::unique_ptr<gl::texture_cube_array>(static_cast<gl::texture_cube_array*>(load_texture(resource_manager, ctx, texture_type_cube_array).release()));
256 }
An exception of this type is thrown when an error occurs during deserialization.
1D image.
Definition: image.hpp:257
2D image.
Definition: image.hpp:274
3D image.
Definition: image.hpp:292
Cube-compatible 2D image.
Definition: image.hpp:310
1D texture array.
Definition: texture.hpp:107
1D texture.
Definition: texture.hpp:73
2D texture array.
Definition: texture.hpp:175
2D texture.
Definition: texture.hpp:141
3D texture.
Definition: texture.hpp:209
Cube texture array.
Definition: texture.hpp:277
Cube texture.
Definition: texture.hpp:243
static std::unique_ptr< T > load(::resource_manager &resource_manager, deserialize_context &ctx)
Loads a resource.
Manages the loading, caching, and saving of resources.
std::shared_ptr< T > load(const std::filesystem::path &path)
Loads and caches a resource.
format
Image and vertex formats.
Definition: format.hpp:29
sampler_address_mode
Behaviors of sampling with texture coordinates outside an image.
sampler_mipmap_mode
Mipmap modes used for texture lookups.
sampler_filter
Filters used for texture lookups.
compare_op
Comparison operators.
Definition: compare-op.hpp:29
Provides access to a deserialization state.
virtual std::size_t read32_le(std::byte *data, std::size_t count) noexcept(false)=0
Reads 32-bit (double word) little-endian data.
virtual std::size_t read8(std::byte *data, std::size_t count) noexcept(false)=0
Reads 8-bit (byte) data.