14#include <lagrange/image/RawInputImage.h>
15#include <lagrange/utils/warning.h>
22template <
typename Archive>
28 ar.object([&](
auto& ar) {
29 ar(
"width") & m_width;
30 ar(
"height") & m_height;
31 ar(
"row_byte_stride") & m_row_byte_stride;
32 ar(
"pixel_precision") & m_pixel_precision;
33 ar(
"color_space") & m_color_space;
34 ar(
"tex_format") & m_tex_format;
35 ar(
"wrap_u") & m_wrap_u;
36 ar(
"wrap_v") & m_wrap_v;
37 ar(
"storage_format") & m_storage_format;
42 using ArrayScalar = int32_t;
43 const bool padding_required = (0 != ((get_row_stride() * m_height) %
sizeof(ArrayScalar)));
44 const size_t aligned_image_size =
45 get_row_stride() * m_height /
sizeof(ArrayScalar) + (padding_required ? 1 : 0);
48 std::vector<unsigned char> buf(aligned_image_size *
sizeof(ArrayScalar));
49 ArrayScalar* data =
reinterpret_cast<ArrayScalar*
>(buf.data());
54 static_cast<const unsigned char*
>(get_pixel_data()) - get_pixel_data_offset(),
55 get_row_stride() * m_height,
60 ar(
"pixels").template array_of<ArrayScalar>(
65 [&](
size_t i,
auto& ar) { ar& data[i]; });
68 LA_IGNORE_SHADOW_WARNING_END
72 typename TexcoordScalar,
75 typename InternalScalar,
76 uint32_t InternalNumChannels>
78 const TexcoordScalar u,
79 const TexcoordScalar v,
80 const texture_filtering filtering)
const
82 using ReturnTraits = PixelTraits<Scalar, NumChannels>;
83 using ReturnPixel =
typename ReturnTraits::Pixel;
84 using InternalTraits = PixelTraits<InternalScalar, InternalNumChannels>;
85 using InternalPixel =
typename InternalTraits::Pixel;
87 ReturnPixel rtn = ReturnTraits::zero();
90 const TexcoordScalar _0 =
static_cast<TexcoordScalar
>(0);
91 const TexcoordScalar _1 =
static_cast<TexcoordScalar
>(1);
92 const TexcoordScalar _05 =
static_cast<TexcoordScalar
>(0.5);
96 std::is_same<TexcoordScalar, float>::value || std::is_same<TexcoordScalar, double>::value,
97 "RawInputImage::sample, texcoord must be float or double");
99 std::is_same<Scalar, unsigned char>::value || std::is_same<Scalar, Eigen::half>::value ||
100 std::is_same<Scalar, float>::value || std::is_same<Scalar, double>::value,
101 "RawInputImage::sample, unsupported Scalar");
103 0u < NumChannels && NumChannels <= (static_cast<uint32_t>(texture_format::max) >> 8u),
104 "RawInputImage::sample, unsupported NumChannels");
106 std::is_same<InternalScalar, unsigned char>::value ||
107 std::is_same<InternalScalar, Eigen::half>::value ||
108 std::is_same<InternalScalar, float>::value ||
109 std::is_same<InternalScalar, double>::value,
110 "RawInputImage::sample, unsupported InternalScalar");
112 0u < InternalNumChannels &&
113 InternalNumChannels <= (static_cast<uint32_t>(texture_format::max) >> 8u),
114 "RawInputImage::sample, unsupported InternalNumChannels");
117 if (
sizeof(InternalScalar) != get_size_precision()) {
118 throw std::runtime_error(
"RawInputImage::sample, INTERNAL_PRECISION is incorrect!");
120 if (InternalNumChannels != get_num_channels()) {
121 throw std::runtime_error(
"RawInputImage::sample, InternalNumChannels is incorrect!");
125 if (std::is_same<Scalar, Eigen::half>::value ||
126 std::is_same<InternalScalar, Eigen::half>::value) {
127 throw std::runtime_error(
"RawInputImage::sample, half is not implemented yet!");
130 throw std::runtime_error(
"RawInputImage::sample, sRGB is not implemented yet!");
134 auto wrap = [_0, _1](
const TexcoordScalar c,
const wrap_mode m) -> TexcoordScalar {
135 if (_0 <= c && c <= _1) {
138 return c - std::floor(c);
140 return std::clamp(c, _0, _1);
142 const auto f = std::floor(c);
143 if (
static_cast<int>(f) & 1) {
149 throw std::runtime_error(
"unknown wrap_mode!");
153 auto _u = wrap(u, m_wrap_u);
154 auto _v = wrap(v, m_wrap_v);
155 assert(_0 <= _u && _u <= _1);
156 assert(_0 <= _v && _v <= _1);
164 const auto size_pixel = get_size_pixel();
165 const auto row_stride = get_row_stride();
166 const auto ptr =
static_cast<const unsigned char*
>(get_pixel_data()) - get_pixel_data_offset();
167 auto get_pixel = [&](
size_t x,
size_t y) -> InternalPixel {
168 assert(x < m_width && y < m_height);
169 return *
reinterpret_cast<const InternalPixel*
>(ptr + x * size_pixel + y * row_stride);
173 const auto x_coord = _u *
static_cast<TexcoordScalar
>(m_width);
174 const auto y_coord = _v *
static_cast<TexcoordScalar
>(m_height);
175 const auto min_num_channels = std::min(NumChannels, InternalNumChannels);
177 const auto x = std::clamp(
178 static_cast<size_t>(x_coord),
179 static_cast<size_t>(0),
180 static_cast<size_t>(m_width - 1));
181 const auto y = std::clamp(
182 static_cast<size_t>(y_coord),
183 static_cast<size_t>(0),
184 static_cast<size_t>(m_height - 1));
185 const auto pix = get_pixel(x, y);
186 for (uint32_t i = 0; i < min_num_channels; ++i) {
187 ReturnTraits::coeff(rtn, i) =
static_cast<Scalar>(InternalTraits::coeff(pix, i));
191 [=](
const TexcoordScalar coord,
193 const wrap_mode wrap_) -> std::tuple<size_t, size_t, TexcoordScalar> {
194 assert(_0 <= coord && coord <=
static_cast<TexcoordScalar
>(size));
195 size_t coord0, coord1;
201 }
else if (coord + _05 >=
static_cast<TexcoordScalar
>(size)) {
204 t = coord - (
static_cast<TexcoordScalar
>(coord0) + _05);
207 coord0 = std::min(size - 2,
static_cast<size_t>(coord - _05));
209 t = coord - (
static_cast<TexcoordScalar
>(coord0) + _05);
211 return std::make_tuple(coord0, coord1, t);
213 const auto sample_x = sample_coord(x_coord, m_width, m_wrap_u);
214 const auto sample_y = sample_coord(y_coord, m_height, m_wrap_v);
215 InternalPixel pix[4] = {
216 get_pixel(std::get<0>(sample_x), std::get<0>(sample_y)),
217 get_pixel(std::get<1>(sample_x), std::get<0>(sample_y)),
218 get_pixel(std::get<0>(sample_x), std::get<1>(sample_y)),
219 get_pixel(std::get<1>(sample_x), std::get<1>(sample_y))};
220 TexcoordScalar weight[4] = {
221 (_1 - std::get<2>(sample_x)) * (_1 - std::get<2>(sample_y)),
222 std::get<2>(sample_x) * (_1 - std::get<2>(sample_y)),
223 (_1 - std::get<2>(sample_x)) * std::get<2>(sample_y),
224 std::get<2>(sample_x) * std::get<2>(sample_y)};
225 for (uint32_t i = 0; i < min_num_channels; ++i) {
226 TexcoordScalar sum = _0;
227 for (
int j = 0; j < 4; ++j) {
228 sum +=
static_cast<TexcoordScalar
>(InternalTraits::coeff(pix[j], i)) * weight[j];
230 ReturnTraits::coeff(rtn, i) =
static_cast<Scalar>(sum);
233 throw std::runtime_error(
"RawInputImage::sample, unknown filtering type!");
239template <
typename TexcoordScalar,
typename Scalar, u
int32_t NumChannels>
241 const TexcoordScalar u,
242 const TexcoordScalar v,
246 using ReturnPixel =
typename ReturnTraits::Pixel;
248 ReturnPixel rtn = ReturnTraits::zero();
252 4u == (
static_cast<uint32_t
>(texture_format::max) >> 8u),
253 "the max channels are not 4 any more, need to update the following code");
255 const auto channels = get_num_channels();
257#define LA_RAWINPUTIMAGE_SAMPLE_IMPL(P, C, V) \
258 if (P == m_pixel_precision && C == channels) { \
259 return sample<TexcoordScalar, Scalar, NumChannels, V, C>(u, v, filtering); \
282#undef LA_RAWINPUTIMAGE_SAMPLE_IMPL
283 throw std::runtime_error(
284 "RawInputImage::sample, cannot deduce InternalScalar or InternalNumChannels!");
288template <
typename TexcoordScalar,
typename Scalar, u
int32_t NumChannels>
290 const TexcoordScalar u,
291 const TexcoordScalar v,
294 static_assert(std::is_floating_point_v<Scalar>,
"Pixel scalar type must be floating point");
@ Scalar
Mesh attribute must have exactly 1 channel.
Definition AttributeFwd.h:56
#define LA_IGNORE_SHADOW_WARNING_BEGIN
Ignore shadow warnings.
Definition warning.h:68
Basic image data structure.
Main namespace for Lagrange.