Loading...
Searching...
No Matches
ArrayToTexture.hpp
1#pragma once
2
3#include <ossia/detail/pod_vector.hpp>
4
5#include <boost/container/vector.hpp>
6
7#include <halp/controls.hpp>
8#include <halp/geometry.hpp>
9#include <halp/meta.hpp>
10#include <halp/texture.hpp>
11
12#include <algorithm>
13#include <cstring>
14
15#if (!defined(__linux__) && !defined(_MSC_VER))
16#define SCORE_LIBC_HAS_FLOAT16 1
17#elif (defined(__linux__) && defined(__GLIBC__))
18#if __GLIBC_PREREQ(2, 40)
19#define SCORE_LIBC_HAS_FLOAT16 1
20#endif
21#endif
22
23// when you enter the least obvious syntax competition and your opponent is clang builtins
24#if defined(__is_identifier) && !defined(_MSC_VER)
25#if (!__is_identifier(_Float16)) && defined(__FLT16_MANT_DIG__)
26#define SCORE_COMPILER_HAS_FLOAT16 1
27#endif
28#endif
29
30namespace Threedim
31{
33{
34public:
35 halp_meta(name, "Array to texture")
36 halp_meta(category, "Visuals/Utilities")
37 halp_meta(c_name, "array_to_texture")
38 halp_meta(description, "Convert an array of values into texture pixel data.")
39 halp_meta(manual_url, "https://ossia.io/score-docs/processes/array-to-texture.html")
40 halp_meta(uuid, "bb5dc513-3430-4671-8c74-2bba78e53709")
41
42 struct ins
43 {
44 struct : halp::val_port<"Input", std::vector<float>>
45 {
46 void update(ArrayToTexture& self) { self.recreate(); }
47 } in;
48 struct : halp::xy_spinboxes_i32<"Size">
49 {
50 void update(ArrayToTexture& self) { self.recreate(); }
51 } size;
52 struct : halp::enum_t<halp::custom_texture::texture_format, "Format">
53 {
54 void update(ArrayToTexture& self) { self.recreate(); }
55 } format;
56 } inputs;
57
58 struct
59 {
60 halp::texture_output<"Output", halp::custom_texture> main;
61 } outputs;
62
63 void recreate()
64 {
65 const auto format = inputs.format;
66 const auto sz = inputs.size.value;
67 outputs.main.texture.request_format = format;
68 outputs.main.create(sz.x, sz.y);
69 std::size_t to_copy = sz.x * sz.y * outputs.main.texture.components(format);
70 const auto& value = inputs.in.value;
71 to_copy = std::min(to_copy, value.size());
72
73 auto* out = outputs.main.texture.bytes;
74 using enum halp::custom_texture::texture_format;
75 switch(format)
76 {
77 case RGBA8:
78 case BGRA8:
79 case R8:
80 case RG8:
81 case RED_OR_ALPHA8:
82 case R8UI:
83 std::copy_n(value.data(), to_copy, (uint8_t*)out);
84 break;
85
86 case R16:
87 case RG16:
88 std::copy_n(value.data(), to_copy, (uint16_t*)out);
89 break;
90
91 case R32UI:
92 case RG32UI:
93 case RGBA32UI:
94 std::copy_n(value.data(), to_copy, (uint32_t*)out);
95 break;
96
97 case R32F:
98 case RGBA32F:
99 std::copy_n(value.data(), to_copy, (float*)out);
100 break;
101
102 case R16F:
103 case RGBA16F:
104
105#if (SCORE_LIBC_HAS_FLOAT16 && SCORE_COMPILER_HAS_FLOAT16)
106 std::copy_n(value.data(), to_copy, (_Float16*)out);
107#else
108 {
109 // No native _Float16: software IEEE 754 binary16 conversion
110 // (round-to-nearest-even) so the upload is still meaningful.
111 auto* dst = (uint16_t*)out;
112 for(std::size_t i = 0; i < to_copy; i++)
113 {
114 const float f = value.data()[i];
115 uint32_t x;
116 std::memcpy(&x, &f, 4);
117 const uint32_t sign = (x >> 16) & 0x8000;
118 x &= 0x7FFFFFFF;
119 if(x >= 0x47800000) // overflow / inf / NaN -> inf (or NaN)
120 dst[i] = sign | 0x7C00 | (x > 0x7F800000 ? 0x200 : 0);
121 else if(x < 0x38800000) // too small for a normal half
122 {
123 const uint32_t shift = 126 - (x >> 23); // >= 14
124 uint32_t half = 0;
125 if(shift <= 24)
126 {
127 const uint32_t mant = (x & 0x7FFFFF) | 0x800000;
128 half = mant >> shift;
129 half += ((mant >> (shift - 1)) & 1)
130 && ((mant & ((1u << (shift - 1)) - 1)) || (half & 1));
131 }
132 dst[i] = sign | half;
133 }
134 else
135 {
136 uint32_t half = ((x - 0x38000000) >> 13);
137 half += ((x >> 12) & 1) && ((x & 0xFFF) || (half & 1));
138 dst[i] = sign | half;
139 }
140 }
141 }
142#endif
143 break;
144
145 default:
146 break;
147 }
148 outputs.main.upload();
149 }
150};
151
152}
Definition ArrayToTexture.hpp:33
Definition ArrayToTexture.hpp:43