Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/resources/curve_texture.cpp
9902 views
1
/**************************************************************************/
2
/* curve_texture.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "curve_texture.h"
32
33
void CurveTexture::_bind_methods() {
34
ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveTexture::set_width);
35
36
ClassDB::bind_method(D_METHOD("set_curve", "curve"), &CurveTexture::set_curve);
37
ClassDB::bind_method(D_METHOD("get_curve"), &CurveTexture::get_curve);
38
39
ClassDB::bind_method(D_METHOD("set_texture_mode", "texture_mode"), &CurveTexture::set_texture_mode);
40
ClassDB::bind_method(D_METHOD("get_texture_mode"), &CurveTexture::get_texture_mode);
41
42
ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width");
43
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "RGB,Red"), "set_texture_mode", "get_texture_mode");
44
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
45
46
BIND_ENUM_CONSTANT(TEXTURE_MODE_RGB);
47
BIND_ENUM_CONSTANT(TEXTURE_MODE_RED);
48
}
49
50
void CurveTexture::set_width(int p_width) {
51
ERR_FAIL_COND(p_width < 32 || p_width > 4096);
52
53
if (_width == p_width) {
54
return;
55
}
56
57
_width = p_width;
58
_update();
59
}
60
61
int CurveTexture::get_width() const {
62
return _width;
63
}
64
65
void CurveTexture::ensure_default_setup(float p_min, float p_max) {
66
if (_curve.is_null()) {
67
Ref<Curve> curve = Ref<Curve>(memnew(Curve));
68
curve->add_point(Vector2(0, 1));
69
curve->add_point(Vector2(1, 1));
70
curve->set_min_value(p_min);
71
curve->set_max_value(p_max);
72
set_curve(curve);
73
// Min and max is 0..1 by default
74
}
75
}
76
77
void CurveTexture::set_curve(Ref<Curve> p_curve) {
78
if (_curve != p_curve) {
79
if (_curve.is_valid()) {
80
_curve->disconnect_changed(callable_mp(this, &CurveTexture::_update));
81
}
82
_curve = p_curve;
83
if (_curve.is_valid()) {
84
_curve->connect_changed(callable_mp(this, &CurveTexture::_update));
85
}
86
_update();
87
}
88
}
89
90
void CurveTexture::_update() {
91
Vector<uint8_t> data;
92
data.resize(_width * sizeof(float) * (texture_mode == TEXTURE_MODE_RGB ? 3 : 1));
93
94
// The array is locked in that scope
95
{
96
uint8_t *wd8 = data.ptrw();
97
float *wd = (float *)wd8;
98
99
if (_curve.is_valid()) {
100
Curve &curve = **_curve;
101
for (int i = 0; i < _width; ++i) {
102
float t = i / static_cast<float>(_width);
103
if (texture_mode == TEXTURE_MODE_RGB) {
104
wd[i * 3 + 0] = curve.sample_baked(t);
105
wd[i * 3 + 1] = wd[i * 3 + 0];
106
wd[i * 3 + 2] = wd[i * 3 + 0];
107
} else {
108
wd[i] = curve.sample_baked(t);
109
}
110
}
111
112
} else {
113
for (int i = 0; i < _width; ++i) {
114
if (texture_mode == TEXTURE_MODE_RGB) {
115
wd[i * 3 + 0] = 0;
116
wd[i * 3 + 1] = 0;
117
wd[i * 3 + 2] = 0;
118
} else {
119
wd[i] = 0;
120
}
121
}
122
}
123
}
124
125
Ref<Image> image = memnew(Image(_width, 1, false, texture_mode == TEXTURE_MODE_RGB ? Image::FORMAT_RGBF : Image::FORMAT_RF, data));
126
127
if (_texture.is_valid()) {
128
if (_current_texture_mode != texture_mode || _current_width != _width) {
129
RID new_texture = RS::get_singleton()->texture_2d_create(image);
130
RS::get_singleton()->texture_replace(_texture, new_texture);
131
} else {
132
RS::get_singleton()->texture_2d_update(_texture, image);
133
}
134
} else {
135
_texture = RS::get_singleton()->texture_2d_create(image);
136
}
137
_current_texture_mode = texture_mode;
138
_current_width = _width;
139
140
emit_changed();
141
}
142
143
Ref<Curve> CurveTexture::get_curve() const {
144
return _curve;
145
}
146
147
void CurveTexture::set_texture_mode(TextureMode p_mode) {
148
ERR_FAIL_COND(p_mode < TEXTURE_MODE_RGB || p_mode > TEXTURE_MODE_RED);
149
if (texture_mode == p_mode) {
150
return;
151
}
152
texture_mode = p_mode;
153
_update();
154
}
155
CurveTexture::TextureMode CurveTexture::get_texture_mode() const {
156
return texture_mode;
157
}
158
159
RID CurveTexture::get_rid() const {
160
if (!_texture.is_valid()) {
161
_texture = RS::get_singleton()->texture_2d_placeholder_create();
162
}
163
return _texture;
164
}
165
166
CurveTexture::~CurveTexture() {
167
if (_texture.is_valid()) {
168
ERR_FAIL_NULL(RenderingServer::get_singleton());
169
RS::get_singleton()->free(_texture);
170
}
171
}
172
173
//////////////////
174
175
void CurveXYZTexture::_bind_methods() {
176
ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveXYZTexture::set_width);
177
178
ClassDB::bind_method(D_METHOD("set_curve_x", "curve"), &CurveXYZTexture::set_curve_x);
179
ClassDB::bind_method(D_METHOD("get_curve_x"), &CurveXYZTexture::get_curve_x);
180
181
ClassDB::bind_method(D_METHOD("set_curve_y", "curve"), &CurveXYZTexture::set_curve_y);
182
ClassDB::bind_method(D_METHOD("get_curve_y"), &CurveXYZTexture::get_curve_y);
183
184
ClassDB::bind_method(D_METHOD("set_curve_z", "curve"), &CurveXYZTexture::set_curve_z);
185
ClassDB::bind_method(D_METHOD("get_curve_z"), &CurveXYZTexture::get_curve_z);
186
187
ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width");
188
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_x", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_x", "get_curve_x");
189
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_y", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_y", "get_curve_y");
190
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_z", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_z", "get_curve_z");
191
}
192
193
void CurveXYZTexture::set_width(int p_width) {
194
ERR_FAIL_COND(p_width < 32 || p_width > 4096);
195
196
if (_width == p_width) {
197
return;
198
}
199
200
_width = p_width;
201
_update();
202
}
203
204
int CurveXYZTexture::get_width() const {
205
return _width;
206
}
207
208
void CurveXYZTexture::ensure_default_setup(float p_min, float p_max) {
209
if (_curve_x.is_null()) {
210
Ref<Curve> curve = Ref<Curve>(memnew(Curve));
211
curve->add_point(Vector2(0, 1));
212
curve->add_point(Vector2(1, 1));
213
curve->set_min_value(p_min);
214
curve->set_max_value(p_max);
215
set_curve_x(curve);
216
}
217
218
if (_curve_y.is_null()) {
219
Ref<Curve> curve = Ref<Curve>(memnew(Curve));
220
curve->add_point(Vector2(0, 1));
221
curve->add_point(Vector2(1, 1));
222
curve->set_min_value(p_min);
223
curve->set_max_value(p_max);
224
set_curve_y(curve);
225
}
226
227
if (_curve_z.is_null()) {
228
Ref<Curve> curve = Ref<Curve>(memnew(Curve));
229
curve->add_point(Vector2(0, 1));
230
curve->add_point(Vector2(1, 1));
231
curve->set_min_value(p_min);
232
curve->set_max_value(p_max);
233
set_curve_z(curve);
234
}
235
}
236
237
void CurveXYZTexture::set_curve_x(Ref<Curve> p_curve) {
238
if (_curve_x != p_curve) {
239
if (_curve_x.is_valid()) {
240
_curve_x->disconnect_changed(callable_mp(this, &CurveXYZTexture::_update));
241
}
242
_curve_x = p_curve;
243
if (_curve_x.is_valid()) {
244
_curve_x->connect_changed(callable_mp(this, &CurveXYZTexture::_update), CONNECT_REFERENCE_COUNTED);
245
}
246
_update();
247
}
248
}
249
250
void CurveXYZTexture::set_curve_y(Ref<Curve> p_curve) {
251
if (_curve_y != p_curve) {
252
if (_curve_y.is_valid()) {
253
_curve_y->disconnect_changed(callable_mp(this, &CurveXYZTexture::_update));
254
}
255
_curve_y = p_curve;
256
if (_curve_y.is_valid()) {
257
_curve_y->connect_changed(callable_mp(this, &CurveXYZTexture::_update), CONNECT_REFERENCE_COUNTED);
258
}
259
_update();
260
}
261
}
262
263
void CurveXYZTexture::set_curve_z(Ref<Curve> p_curve) {
264
if (_curve_z != p_curve) {
265
if (_curve_z.is_valid()) {
266
_curve_z->disconnect_changed(callable_mp(this, &CurveXYZTexture::_update));
267
}
268
_curve_z = p_curve;
269
if (_curve_z.is_valid()) {
270
_curve_z->connect_changed(callable_mp(this, &CurveXYZTexture::_update), CONNECT_REFERENCE_COUNTED);
271
}
272
_update();
273
}
274
}
275
276
void CurveXYZTexture::_update() {
277
Vector<uint8_t> data;
278
data.resize(_width * sizeof(float) * 3);
279
280
// The array is locked in that scope
281
{
282
uint8_t *wd8 = data.ptrw();
283
float *wd = (float *)wd8;
284
285
if (_curve_x.is_valid()) {
286
Curve &curve_x = **_curve_x;
287
for (int i = 0; i < _width; ++i) {
288
float t = i / static_cast<float>(_width);
289
wd[i * 3 + 0] = curve_x.sample_baked(t);
290
}
291
292
} else {
293
for (int i = 0; i < _width; ++i) {
294
wd[i * 3 + 0] = 0;
295
}
296
}
297
298
if (_curve_y.is_valid()) {
299
Curve &curve_y = **_curve_y;
300
for (int i = 0; i < _width; ++i) {
301
float t = i / static_cast<float>(_width);
302
wd[i * 3 + 1] = curve_y.sample_baked(t);
303
}
304
305
} else {
306
for (int i = 0; i < _width; ++i) {
307
wd[i * 3 + 1] = 0;
308
}
309
}
310
311
if (_curve_z.is_valid()) {
312
Curve &curve_z = **_curve_z;
313
for (int i = 0; i < _width; ++i) {
314
float t = i / static_cast<float>(_width);
315
wd[i * 3 + 2] = curve_z.sample_baked(t);
316
}
317
318
} else {
319
for (int i = 0; i < _width; ++i) {
320
wd[i * 3 + 2] = 0;
321
}
322
}
323
}
324
325
Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RGBF, data));
326
327
if (_texture.is_valid()) {
328
if (_current_width != _width) {
329
RID new_texture = RS::get_singleton()->texture_2d_create(image);
330
RS::get_singleton()->texture_replace(_texture, new_texture);
331
} else {
332
RS::get_singleton()->texture_2d_update(_texture, image);
333
}
334
} else {
335
_texture = RS::get_singleton()->texture_2d_create(image);
336
}
337
_current_width = _width;
338
339
emit_changed();
340
}
341
342
Ref<Curve> CurveXYZTexture::get_curve_x() const {
343
return _curve_x;
344
}
345
346
Ref<Curve> CurveXYZTexture::get_curve_y() const {
347
return _curve_y;
348
}
349
350
Ref<Curve> CurveXYZTexture::get_curve_z() const {
351
return _curve_z;
352
}
353
354
RID CurveXYZTexture::get_rid() const {
355
if (!_texture.is_valid()) {
356
_texture = RS::get_singleton()->texture_2d_placeholder_create();
357
}
358
return _texture;
359
}
360
361
CurveXYZTexture::~CurveXYZTexture() {
362
if (_texture.is_valid()) {
363
ERR_FAIL_NULL(RenderingServer::get_singleton());
364
RS::get_singleton()->free(_texture);
365
}
366
}
367
368