Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/resources/curve_texture.cpp
20791 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
#include "servers/rendering/rendering_server.h"
34
35
void CurveTexture::_bind_methods() {
36
ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveTexture::set_width);
37
38
ClassDB::bind_method(D_METHOD("set_curve", "curve"), &CurveTexture::set_curve);
39
ClassDB::bind_method(D_METHOD("get_curve"), &CurveTexture::get_curve);
40
41
ClassDB::bind_method(D_METHOD("set_texture_mode", "texture_mode"), &CurveTexture::set_texture_mode);
42
ClassDB::bind_method(D_METHOD("get_texture_mode"), &CurveTexture::get_texture_mode);
43
44
ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width");
45
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "RGB,Red"), "set_texture_mode", "get_texture_mode");
46
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_curve", "get_curve");
47
48
BIND_ENUM_CONSTANT(TEXTURE_MODE_RGB);
49
BIND_ENUM_CONSTANT(TEXTURE_MODE_RED);
50
}
51
52
void CurveTexture::set_width(int p_width) {
53
ERR_FAIL_COND(p_width < 32 || p_width > 4096);
54
55
if (_width == p_width) {
56
return;
57
}
58
59
_width = p_width;
60
_update();
61
}
62
63
int CurveTexture::get_width() const {
64
return _width;
65
}
66
67
void CurveTexture::ensure_default_setup(float p_min, float p_max) {
68
if (_curve.is_null()) {
69
Ref<Curve> curve = Ref<Curve>(memnew(Curve));
70
curve->add_point(Vector2(0, 1));
71
curve->add_point(Vector2(1, 1));
72
curve->set_min_value(p_min);
73
curve->set_max_value(p_max);
74
set_curve(curve);
75
// Min and max is 0..1 by default
76
}
77
}
78
79
void CurveTexture::set_curve(Ref<Curve> p_curve) {
80
if (_curve != p_curve) {
81
if (_curve.is_valid()) {
82
_curve->disconnect_changed(callable_mp(this, &CurveTexture::_update));
83
}
84
_curve = p_curve;
85
if (_curve.is_valid()) {
86
_curve->connect_changed(callable_mp(this, &CurveTexture::_update));
87
}
88
_update();
89
}
90
}
91
92
void CurveTexture::_update() {
93
Vector<uint8_t> data;
94
data.resize(_width * sizeof(float) * (texture_mode == TEXTURE_MODE_RGB ? 3 : 1));
95
96
// The array is locked in that scope
97
{
98
uint8_t *wd8 = data.ptrw();
99
float *wd = (float *)wd8;
100
101
if (_curve.is_valid()) {
102
Curve &curve = **_curve;
103
for (int i = 0; i < _width; ++i) {
104
float t = i / static_cast<float>(_width);
105
if (texture_mode == TEXTURE_MODE_RGB) {
106
wd[i * 3 + 0] = curve.sample_baked(t);
107
wd[i * 3 + 1] = wd[i * 3 + 0];
108
wd[i * 3 + 2] = wd[i * 3 + 0];
109
} else {
110
wd[i] = curve.sample_baked(t);
111
}
112
}
113
114
} else {
115
for (int i = 0; i < _width; ++i) {
116
if (texture_mode == TEXTURE_MODE_RGB) {
117
wd[i * 3 + 0] = 0;
118
wd[i * 3 + 1] = 0;
119
wd[i * 3 + 2] = 0;
120
} else {
121
wd[i] = 0;
122
}
123
}
124
}
125
}
126
127
Ref<Image> image = memnew(Image(_width, 1, false, texture_mode == TEXTURE_MODE_RGB ? Image::FORMAT_RGBF : Image::FORMAT_RF, data));
128
129
if (_texture.is_valid()) {
130
if (_current_texture_mode != texture_mode || _current_width != _width) {
131
RID new_texture = RS::get_singleton()->texture_2d_create(image);
132
RS::get_singleton()->texture_replace(_texture, new_texture);
133
} else {
134
RS::get_singleton()->texture_2d_update(_texture, image);
135
}
136
} else {
137
_texture = RS::get_singleton()->texture_2d_create(image);
138
}
139
_current_texture_mode = texture_mode;
140
_current_width = _width;
141
142
emit_changed();
143
}
144
145
Ref<Curve> CurveTexture::get_curve() const {
146
return _curve;
147
}
148
149
void CurveTexture::set_texture_mode(TextureMode p_mode) {
150
ERR_FAIL_COND(p_mode < TEXTURE_MODE_RGB || p_mode > TEXTURE_MODE_RED);
151
if (texture_mode == p_mode) {
152
return;
153
}
154
texture_mode = p_mode;
155
_update();
156
}
157
CurveTexture::TextureMode CurveTexture::get_texture_mode() const {
158
return texture_mode;
159
}
160
161
RID CurveTexture::get_rid() const {
162
if (!_texture.is_valid()) {
163
_texture = RS::get_singleton()->texture_2d_placeholder_create();
164
}
165
return _texture;
166
}
167
168
CurveTexture::~CurveTexture() {
169
if (_texture.is_valid()) {
170
ERR_FAIL_NULL(RenderingServer::get_singleton());
171
RS::get_singleton()->free_rid(_texture);
172
}
173
}
174
175
//////////////////
176
177
void CurveXYZTexture::_bind_methods() {
178
ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveXYZTexture::set_width);
179
180
ClassDB::bind_method(D_METHOD("set_curve_x", "curve"), &CurveXYZTexture::set_curve_x);
181
ClassDB::bind_method(D_METHOD("get_curve_x"), &CurveXYZTexture::get_curve_x);
182
183
ClassDB::bind_method(D_METHOD("set_curve_y", "curve"), &CurveXYZTexture::set_curve_y);
184
ClassDB::bind_method(D_METHOD("get_curve_y"), &CurveXYZTexture::get_curve_y);
185
186
ClassDB::bind_method(D_METHOD("set_curve_z", "curve"), &CurveXYZTexture::set_curve_z);
187
ClassDB::bind_method(D_METHOD("get_curve_z"), &CurveXYZTexture::get_curve_z);
188
189
ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096,suffix:px"), "set_width", "get_width");
190
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_x", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_curve_x", "get_curve_x");
191
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_y", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_curve_y", "get_curve_y");
192
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_z", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_curve_z", "get_curve_z");
193
}
194
195
void CurveXYZTexture::set_width(int p_width) {
196
ERR_FAIL_COND(p_width < 32 || p_width > 4096);
197
198
if (_width == p_width) {
199
return;
200
}
201
202
_width = p_width;
203
_update();
204
}
205
206
int CurveXYZTexture::get_width() const {
207
return _width;
208
}
209
210
void CurveXYZTexture::ensure_default_setup(float p_min, float p_max) {
211
if (_curve_x.is_null()) {
212
Ref<Curve> curve = Ref<Curve>(memnew(Curve));
213
curve->add_point(Vector2(0, 1));
214
curve->add_point(Vector2(1, 1));
215
curve->set_min_value(p_min);
216
curve->set_max_value(p_max);
217
set_curve_x(curve);
218
}
219
220
if (_curve_y.is_null()) {
221
Ref<Curve> curve = Ref<Curve>(memnew(Curve));
222
curve->add_point(Vector2(0, 1));
223
curve->add_point(Vector2(1, 1));
224
curve->set_min_value(p_min);
225
curve->set_max_value(p_max);
226
set_curve_y(curve);
227
}
228
229
if (_curve_z.is_null()) {
230
Ref<Curve> curve = Ref<Curve>(memnew(Curve));
231
curve->add_point(Vector2(0, 1));
232
curve->add_point(Vector2(1, 1));
233
curve->set_min_value(p_min);
234
curve->set_max_value(p_max);
235
set_curve_z(curve);
236
}
237
}
238
239
void CurveXYZTexture::set_curve_x(Ref<Curve> p_curve) {
240
if (_curve_x != p_curve) {
241
if (_curve_x.is_valid()) {
242
_curve_x->disconnect_changed(callable_mp(this, &CurveXYZTexture::_update));
243
}
244
_curve_x = p_curve;
245
if (_curve_x.is_valid()) {
246
_curve_x->connect_changed(callable_mp(this, &CurveXYZTexture::_update), CONNECT_REFERENCE_COUNTED);
247
}
248
_update();
249
}
250
}
251
252
void CurveXYZTexture::set_curve_y(Ref<Curve> p_curve) {
253
if (_curve_y != p_curve) {
254
if (_curve_y.is_valid()) {
255
_curve_y->disconnect_changed(callable_mp(this, &CurveXYZTexture::_update));
256
}
257
_curve_y = p_curve;
258
if (_curve_y.is_valid()) {
259
_curve_y->connect_changed(callable_mp(this, &CurveXYZTexture::_update), CONNECT_REFERENCE_COUNTED);
260
}
261
_update();
262
}
263
}
264
265
void CurveXYZTexture::set_curve_z(Ref<Curve> p_curve) {
266
if (_curve_z != p_curve) {
267
if (_curve_z.is_valid()) {
268
_curve_z->disconnect_changed(callable_mp(this, &CurveXYZTexture::_update));
269
}
270
_curve_z = p_curve;
271
if (_curve_z.is_valid()) {
272
_curve_z->connect_changed(callable_mp(this, &CurveXYZTexture::_update), CONNECT_REFERENCE_COUNTED);
273
}
274
_update();
275
}
276
}
277
278
void CurveXYZTexture::_update() {
279
Vector<uint8_t> data;
280
data.resize(_width * sizeof(float) * 3);
281
282
// The array is locked in that scope
283
{
284
uint8_t *wd8 = data.ptrw();
285
float *wd = (float *)wd8;
286
287
if (_curve_x.is_valid()) {
288
Curve &curve_x = **_curve_x;
289
for (int i = 0; i < _width; ++i) {
290
float t = i / static_cast<float>(_width);
291
wd[i * 3 + 0] = curve_x.sample_baked(t);
292
}
293
294
} else {
295
for (int i = 0; i < _width; ++i) {
296
wd[i * 3 + 0] = 0;
297
}
298
}
299
300
if (_curve_y.is_valid()) {
301
Curve &curve_y = **_curve_y;
302
for (int i = 0; i < _width; ++i) {
303
float t = i / static_cast<float>(_width);
304
wd[i * 3 + 1] = curve_y.sample_baked(t);
305
}
306
307
} else {
308
for (int i = 0; i < _width; ++i) {
309
wd[i * 3 + 1] = 0;
310
}
311
}
312
313
if (_curve_z.is_valid()) {
314
Curve &curve_z = **_curve_z;
315
for (int i = 0; i < _width; ++i) {
316
float t = i / static_cast<float>(_width);
317
wd[i * 3 + 2] = curve_z.sample_baked(t);
318
}
319
320
} else {
321
for (int i = 0; i < _width; ++i) {
322
wd[i * 3 + 2] = 0;
323
}
324
}
325
}
326
327
Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RGBF, data));
328
329
if (_texture.is_valid()) {
330
if (_current_width != _width) {
331
RID new_texture = RS::get_singleton()->texture_2d_create(image);
332
RS::get_singleton()->texture_replace(_texture, new_texture);
333
} else {
334
RS::get_singleton()->texture_2d_update(_texture, image);
335
}
336
} else {
337
_texture = RS::get_singleton()->texture_2d_create(image);
338
}
339
_current_width = _width;
340
341
emit_changed();
342
}
343
344
Ref<Curve> CurveXYZTexture::get_curve_x() const {
345
return _curve_x;
346
}
347
348
Ref<Curve> CurveXYZTexture::get_curve_y() const {
349
return _curve_y;
350
}
351
352
Ref<Curve> CurveXYZTexture::get_curve_z() const {
353
return _curve_z;
354
}
355
356
RID CurveXYZTexture::get_rid() const {
357
if (!_texture.is_valid()) {
358
_texture = RS::get_singleton()->texture_2d_placeholder_create();
359
}
360
return _texture;
361
}
362
363
CurveXYZTexture::~CurveXYZTexture() {
364
if (_texture.is_valid()) {
365
ERR_FAIL_NULL(RenderingServer::get_singleton());
366
RS::get_singleton()->free_rid(_texture);
367
}
368
}
369
370