summaryrefslogtreecommitdiff
path: root/scene/resources/texture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources/texture.cpp')
-rw-r--r--scene/resources/texture.cpp487
1 files changed, 479 insertions, 8 deletions
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index f979c5c758..f0ac30a76e 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -6,6 +6,7 @@
/* http://www.godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -458,25 +459,27 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla
flags = f->get_32(); //texture flags!
uint32_t df = f->get_32(); //data format
+ /*
print_line("width: " + itos(tw));
print_line("height: " + itos(th));
print_line("flags: " + itos(flags));
print_line("df: " + itos(df));
+ */
if (request_3d_callback && df & FORMAT_BIT_DETECT_3D) {
- print_line("request detect 3D at " + p_path);
+ //print_line("request detect 3D at " + p_path);
VS::get_singleton()->texture_set_detect_3d_callback(texture, _requested_3d, this);
} else {
- print_line("not requesting detect 3D at " + p_path);
+ //print_line("not requesting detect 3D at " + p_path);
VS::get_singleton()->texture_set_detect_3d_callback(texture, NULL, NULL);
}
if (request_srgb_callback && df & FORMAT_BIT_DETECT_SRGB) {
- print_line("request detect srgb at " + p_path);
+ //print_line("request detect srgb at " + p_path);
VS::get_singleton()->texture_set_detect_srgb_callback(texture, _requested_srgb, this);
} else {
+ //print_line("not requesting detect srgb at " + p_path);
VS::get_singleton()->texture_set_detect_srgb_callback(texture, NULL, NULL);
- print_line("not requesting detect srgb at " + p_path);
}
if (!(df & FORMAT_BIT_STREAM)) {
@@ -492,7 +495,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla
uint32_t mipmaps = f->get_32();
uint32_t size = f->get_32();
- print_line("mipmaps: " + itos(mipmaps));
+ //print_line("mipmaps: " + itos(mipmaps));
while (mipmaps > 1 && p_size_limit > 0 && (sw > p_size_limit || sh > p_size_limit)) {
@@ -538,7 +541,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla
mipmap_images.push_back(img);
}
- print_line("mipmap read total: " + itos(mipmap_images.size()));
+ //print_line("mipmap read total: " + itos(mipmap_images.size()));
memdelete(f); //no longer needed
@@ -625,7 +628,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla
{
PoolVector<uint8_t>::Write w = img_data.write();
int bytes = f->get_buffer(w.ptr(), total_size - ofs);
- print_line("requested read: " + itos(total_size - ofs) + " but got: " + itos(bytes));
+ //print_line("requested read: " + itos(total_size - ofs) + " but got: " + itos(bytes));
memdelete(f);
@@ -918,7 +921,7 @@ void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile
}
void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose) const {
- //this might not necesarily work well if using a rect, needs to be fixed properly
+ //this might not necessarily work well if using a rect, needs to be fixed properly
Rect2 rc = region;
if (!atlas.is_valid())
@@ -1367,3 +1370,471 @@ CubeMap::~CubeMap() {
BIND_CONSTANT( CUBEMAP_FRONT );
BIND_CONSTANT( CUBEMAP_BACK );
*/
+///////////////////////////
+
+void CurveTexture::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_max", "max"), &CurveTexture::set_max);
+ ClassDB::bind_method(D_METHOD("get_max"), &CurveTexture::get_max);
+
+ ClassDB::bind_method(D_METHOD("set_min", "min"), &CurveTexture::set_min);
+ ClassDB::bind_method(D_METHOD("get_min"), &CurveTexture::get_min);
+
+ ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveTexture::set_width);
+
+ ClassDB::bind_method(D_METHOD("set_points", "points"), &CurveTexture::set_points);
+ ClassDB::bind_method(D_METHOD("get_points"), &CurveTexture::get_points);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "min", PROPERTY_HINT_RANGE, "-1024,1024"), "set_min", "get_min");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "max", PROPERTY_HINT_RANGE, "-1024,1024"), "set_max", "get_max");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "32,4096"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "points"), "set_points", "get_points");
+}
+void CurveTexture::set_max(float p_max) {
+
+ max = p_max;
+ emit_changed();
+}
+float CurveTexture::get_max() const {
+
+ return max;
+}
+
+void CurveTexture::set_min(float p_min) {
+
+ min = p_min;
+ emit_changed();
+}
+float CurveTexture::get_min() const {
+
+ return min;
+}
+void CurveTexture::set_width(int p_width) {
+
+ ERR_FAIL_COND(p_width < 32 || p_width > 4096);
+ width = p_width;
+ if (points.size())
+ set_points(points);
+}
+int CurveTexture::get_width() const {
+
+ return width;
+}
+
+static void _plot_curve(const Vector2 &p_a, const Vector2 &p_b, const Vector2 &p_c, const Vector2 &p_d, float *p_heights, bool *p_useds, int p_width, float p_min, float p_max) {
+
+ float geometry[4][4];
+ float tmp1[4][4];
+ float tmp2[4][4];
+ float deltas[4][4];
+ double x, dx, dx2, dx3;
+ double y, dy, dy2, dy3;
+ double d, d2, d3;
+ int lastx;
+ int newx;
+ float lasty;
+ float newy;
+ int ntimes;
+ int i, j;
+
+ int xmax = p_width;
+
+ /* construct the geometry matrix from the segment */
+ for (i = 0; i < 4; i++) {
+ geometry[i][2] = 0;
+ geometry[i][3] = 0;
+ }
+
+ geometry[0][0] = (p_a[0] * xmax);
+ geometry[1][0] = (p_b[0] * xmax);
+ geometry[2][0] = (p_c[0] * xmax);
+ geometry[3][0] = (p_d[0] * xmax);
+
+ geometry[0][1] = (p_a[1]);
+ geometry[1][1] = (p_b[1]);
+ geometry[2][1] = (p_c[1]);
+ geometry[3][1] = (p_d[1]);
+
+ /* subdivide the curve ntimes (1000) times */
+ ntimes = 4 * xmax;
+ /* ntimes can be adjusted to give a finer or coarser curve */
+ d = 1.0 / ntimes;
+ d2 = d * d;
+ d3 = d * d * d;
+
+ /* construct a temporary matrix for determining the forward differencing deltas */
+ tmp2[0][0] = 0;
+ tmp2[0][1] = 0;
+ tmp2[0][2] = 0;
+ tmp2[0][3] = 1;
+ tmp2[1][0] = d3;
+ tmp2[1][1] = d2;
+ tmp2[1][2] = d;
+ tmp2[1][3] = 0;
+ tmp2[2][0] = 6 * d3;
+ tmp2[2][1] = 2 * d2;
+ tmp2[2][2] = 0;
+ tmp2[2][3] = 0;
+ tmp2[3][0] = 6 * d3;
+ tmp2[3][1] = 0;
+ tmp2[3][2] = 0;
+ tmp2[3][3] = 0;
+
+ /* compose the basis and geometry matrices */
+
+ static const float CR_basis[4][4] = {
+ { -0.5, 1.5, -1.5, 0.5 },
+ { 1.0, -2.5, 2.0, -0.5 },
+ { -0.5, 0.0, 0.5, 0.0 },
+ { 0.0, 1.0, 0.0, 0.0 },
+ };
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] +
+ CR_basis[i][1] * geometry[1][j] +
+ CR_basis[i][2] * geometry[2][j] +
+ CR_basis[i][3] * geometry[3][j]);
+ }
+ }
+ /* compose the above results to get the deltas matrix */
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ deltas[i][j] = (tmp2[i][0] * tmp1[0][j] +
+ tmp2[i][1] * tmp1[1][j] +
+ tmp2[i][2] * tmp1[2][j] +
+ tmp2[i][3] * tmp1[3][j]);
+ }
+ }
+
+ /* extract the x deltas */
+ x = deltas[0][0];
+ dx = deltas[1][0];
+ dx2 = deltas[2][0];
+ dx3 = deltas[3][0];
+
+ /* extract the y deltas */
+ y = deltas[0][1];
+ dy = deltas[1][1];
+ dy2 = deltas[2][1];
+ dy3 = deltas[3][1];
+
+ lastx = CLAMP(x, 0, xmax);
+ lasty = y;
+
+ p_heights[lastx] = lasty;
+ p_useds[lastx] = true;
+
+ /* loop over the curve */
+ for (i = 0; i < ntimes; i++) {
+ /* increment the x values */
+ x += dx;
+ dx += dx2;
+ dx2 += dx3;
+
+ /* increment the y values */
+ y += dy;
+ dy += dy2;
+ dy2 += dy3;
+
+ newx = CLAMP((Math::round(x)), 0, xmax);
+ newy = CLAMP(y, p_min, p_max);
+
+ /* if this point is different than the last one...then draw it */
+ if ((lastx != newx) || (lasty != newy)) {
+ p_useds[newx] = true;
+ p_heights[newx] = newy;
+ }
+
+ lastx = newx;
+ lasty = newy;
+ }
+}
+
+void CurveTexture::set_points(const PoolVector<Vector2> &p_points) {
+
+ points = p_points;
+
+ PoolVector<uint8_t> data;
+ PoolVector<bool> used;
+ data.resize(width * sizeof(float));
+ used.resize(width);
+ {
+ PoolVector<uint8_t>::Write wd8 = data.write();
+ float *wd = (float *)wd8.ptr();
+ PoolVector<bool>::Write wu = used.write();
+ int pc = p_points.size();
+ PoolVector<Vector2>::Read pr = p_points.read();
+
+ for (int i = 0; i < width; i++) {
+ wd[i] = 0.0;
+ wu[i] = false;
+ }
+
+ Vector2 prev = Vector2(0, 0);
+ Vector2 prev2 = Vector2(0, 0);
+
+ for (int i = -1; i < pc; i++) {
+
+ Vector2 next;
+ Vector2 next2;
+ if (i + 1 >= pc) {
+ next = Vector2(1, 0);
+ } else {
+ next = Vector2(pr[i + 1].x, pr[i + 1].y);
+ }
+
+ if (i + 2 >= pc) {
+ next2 = Vector2(1, 0);
+ } else {
+ next2 = Vector2(pr[i + 2].x, pr[i + 2].y);
+ }
+
+ /*if (i==-1 && prev.offset==next.offset) {
+ prev=next;
+ continue;
+ }*/
+
+ _plot_curve(prev2, prev, next, next2, wd, wu.ptr(), width, min, max);
+
+ prev2 = prev;
+ prev = next;
+ }
+ }
+
+ Image image(width, 1, false, Image::FORMAT_RF, data);
+
+ VS::get_singleton()->texture_allocate(texture, width, 1, Image::FORMAT_RF, VS::TEXTURE_FLAG_FILTER);
+ VS::get_singleton()->texture_set_data(texture, image);
+
+ emit_changed();
+}
+
+PoolVector<Vector2> CurveTexture::get_points() const {
+
+ return points;
+}
+
+RID CurveTexture::get_rid() const {
+
+ return texture;
+}
+
+CurveTexture::CurveTexture() {
+
+ max = 1;
+ min = 0;
+ width = 2048;
+ texture = VS::get_singleton()->texture_create();
+}
+CurveTexture::~CurveTexture() {
+ VS::get_singleton()->free(texture);
+}
+//////////////////
+
+//setter and getter names for property serialization
+#define COLOR_RAMP_GET_OFFSETS "get_offsets"
+#define COLOR_RAMP_GET_COLORS "get_colors"
+#define COLOR_RAMP_SET_OFFSETS "set_offsets"
+#define COLOR_RAMP_SET_COLORS "set_colors"
+
+GradientTexture::GradientTexture() {
+ //Set initial color ramp transition from black to white
+ points.resize(2);
+ points[0].color = Color(0, 0, 0, 1);
+ points[0].offset = 0;
+ points[1].color = Color(1, 1, 1, 1);
+ points[1].offset = 1;
+ is_sorted = true;
+ update_pending = false;
+ width = 2048;
+
+ texture = VS::get_singleton()->texture_create();
+ _queue_update();
+}
+
+GradientTexture::~GradientTexture() {
+ VS::get_singleton()->free(texture);
+}
+
+void GradientTexture::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("add_point", "offset", "color"), &GradientTexture::add_point);
+ ClassDB::bind_method(D_METHOD("remove_point", "offset", "color"), &GradientTexture::remove_point);
+
+ ClassDB::bind_method(D_METHOD("set_offset", "point", "offset"), &GradientTexture::set_offset);
+ ClassDB::bind_method(D_METHOD("get_offset", "point"), &GradientTexture::get_offset);
+
+ ClassDB::bind_method(D_METHOD("set_color", "point", "color"), &GradientTexture::set_color);
+ ClassDB::bind_method(D_METHOD("get_color", "point"), &GradientTexture::get_color);
+
+ ClassDB::bind_method(D_METHOD("set_width", "width"), &GradientTexture::set_width);
+
+ ClassDB::bind_method(D_METHOD("interpolate", "offset"), &GradientTexture::get_color_at_offset);
+
+ ClassDB::bind_method(D_METHOD("get_point_count"), &GradientTexture::get_points_count);
+
+ ClassDB::bind_method(D_METHOD("_update"), &GradientTexture::_update);
+
+ ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_OFFSETS, "offsets"), &GradientTexture::set_offsets);
+ ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_OFFSETS), &GradientTexture::get_offsets);
+
+ ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_COLORS, "colors"), &GradientTexture::set_colors);
+ ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_COLORS), &GradientTexture::get_colors);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "offsets"), COLOR_RAMP_SET_OFFSETS, COLOR_RAMP_GET_OFFSETS);
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "colors"), COLOR_RAMP_SET_COLORS, COLOR_RAMP_GET_COLORS);
+}
+
+void GradientTexture::_queue_update() {
+
+ if (update_pending)
+ return;
+
+ call_deferred("_update");
+}
+
+void GradientTexture::_update() {
+
+ update_pending = false;
+
+ PoolVector<uint8_t> data;
+ data.resize(width * 4);
+ {
+ PoolVector<uint8_t>::Write wd8 = data.write();
+ for (int i = 0; i < width; i++) {
+ float ofs = float(i) / (width - 1);
+
+ Color color = get_color_at_offset(ofs);
+ wd8[i * 4 + 0] = uint8_t(CLAMP(color.r * 255.0, 0, 255));
+ wd8[i * 4 + 1] = uint8_t(CLAMP(color.g * 255.0, 0, 255));
+ wd8[i * 4 + 2] = uint8_t(CLAMP(color.b * 255.0, 0, 255));
+ wd8[i * 4 + 3] = uint8_t(CLAMP(color.a * 255.0, 0, 255));
+ }
+ }
+
+ Image image(width, 1, false, Image::FORMAT_RGBA8, data);
+
+ VS::get_singleton()->texture_allocate(texture, width, 1, Image::FORMAT_RGBA8, VS::TEXTURE_FLAG_FILTER);
+ VS::get_singleton()->texture_set_data(texture, image);
+
+ emit_changed();
+}
+
+void GradientTexture::set_width(int p_width) {
+
+ width = p_width;
+ _queue_update();
+}
+int GradientTexture::get_width() const {
+
+ return width;
+}
+
+Vector<float> GradientTexture::get_offsets() const {
+ Vector<float> offsets;
+ offsets.resize(points.size());
+ for (int i = 0; i < points.size(); i++) {
+ offsets[i] = points[i].offset;
+ }
+ return offsets;
+}
+
+Vector<Color> GradientTexture::get_colors() const {
+ Vector<Color> colors;
+ colors.resize(points.size());
+ for (int i = 0; i < points.size(); i++) {
+ colors[i] = points[i].color;
+ }
+ return colors;
+}
+
+void GradientTexture::set_offsets(const Vector<float> &p_offsets) {
+ points.resize(p_offsets.size());
+ for (int i = 0; i < points.size(); i++) {
+ points[i].offset = p_offsets[i];
+ }
+ is_sorted = false;
+ emit_changed();
+ _queue_update();
+}
+
+void GradientTexture::set_colors(const Vector<Color> &p_colors) {
+ if (points.size() < p_colors.size())
+ is_sorted = false;
+ points.resize(p_colors.size());
+ for (int i = 0; i < points.size(); i++) {
+ points[i].color = p_colors[i];
+ }
+ emit_changed();
+ _queue_update();
+}
+
+Vector<GradientTexture::Point> &GradientTexture::get_points() {
+ return points;
+}
+
+void GradientTexture::add_point(float p_offset, const Color &p_color) {
+
+ Point p;
+ p.offset = p_offset;
+ p.color = p_color;
+ is_sorted = false;
+ points.push_back(p);
+
+ emit_changed();
+ _queue_update();
+}
+
+void GradientTexture::remove_point(int p_index) {
+
+ ERR_FAIL_INDEX(p_index, points.size());
+ ERR_FAIL_COND(points.size() <= 2);
+ points.remove(p_index);
+ emit_changed();
+ _queue_update();
+}
+
+void GradientTexture::set_points(Vector<GradientTexture::Point> &p_points) {
+ points = p_points;
+ is_sorted = false;
+ emit_changed();
+ _queue_update();
+}
+
+void GradientTexture::set_offset(int pos, const float offset) {
+ if (points.size() <= pos)
+ points.resize(pos + 1);
+ points[pos].offset = offset;
+ is_sorted = false;
+ emit_changed();
+ _queue_update();
+}
+
+float GradientTexture::get_offset(int pos) const {
+ if (points.size() > pos)
+ return points[pos].offset;
+ return 0; //TODO: Maybe throw some error instead?
+}
+
+void GradientTexture::set_color(int pos, const Color &color) {
+ if (points.size() <= pos) {
+ points.resize(pos + 1);
+ is_sorted = false;
+ }
+ points[pos].color = color;
+ emit_changed();
+ _queue_update();
+}
+
+Color GradientTexture::get_color(int pos) const {
+ if (points.size() > pos)
+ return points[pos].color;
+ return Color(0, 0, 0, 1); //TODO: Maybe throw some error instead?
+}
+
+int GradientTexture::get_points_count() const {
+ return points.size();
+}