summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp8
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp13
-rw-r--r--drivers/gles2/shader_gles2.cpp4
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp7
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp12
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp19
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h2
-rw-r--r--drivers/gles3/shader_gles3.cpp2
-rw-r--r--drivers/png/image_loader_png.cpp355
-rw-r--r--drivers/png/image_loader_png.h9
-rw-r--r--drivers/png/png_driver_common.cpp205
-rw-r--r--drivers/png/png_driver_common.h48
-rw-r--r--drivers/png/resource_saver_png.cpp137
-rw-r--r--drivers/unix/dir_access_unix.cpp7
-rw-r--r--drivers/unix/ip_unix.cpp78
-rw-r--r--drivers/unix/ip_unix.h2
-rw-r--r--drivers/unix/net_socket_posix.cpp86
-rw-r--r--drivers/unix/net_socket_posix.h5
18 files changed, 461 insertions, 538 deletions
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index a07c6832dc..ea29af7d9e 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -2920,16 +2920,16 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
VS::get_singleton()->texture_bind(camera_RGBA, 0);
- } else if (feed->get_datatype() == CameraFeed::FEED_YCbCr) {
- RID camera_YCbCr = feed->get_texture(CameraServer::FEED_YCbCr_IMAGE);
+ } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR) {
+ RID camera_YCbCr = feed->get_texture(CameraServer::FEED_YCBCR_IMAGE);
VS::get_singleton()->texture_bind(camera_YCbCr, 0);
storage->shaders.copy.set_conditional(CopyShaderGLES2::YCBCR_TO_RGB, true);
- } else if (feed->get_datatype() == CameraFeed::FEED_YCbCr_Sep) {
+ } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR_SEP) {
RID camera_Y = feed->get_texture(CameraServer::FEED_Y_IMAGE);
- RID camera_CbCr = feed->get_texture(CameraServer::FEED_CbCr_IMAGE);
+ RID camera_CbCr = feed->get_texture(CameraServer::FEED_CBCR_IMAGE);
VS::get_singleton()->texture_bind(camera_Y, 0);
VS::get_singleton()->texture_bind(camera_CbCr, 1);
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index 418be136b8..b08202ae45 100644
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
@@ -811,7 +811,7 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer)
data.resize(data_size);
- Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1 ? true : false, real_format, data));
+ Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1, real_format, data));
return Ref<Image>(img);
#else
@@ -4526,9 +4526,7 @@ void RasterizerStorageGLES2::instance_add_dependency(RID p_base, RasterizerScene
ERR_FAIL_COND(!inst);
} break;
default: {
- if (!inst) {
- ERR_FAIL();
- }
+ ERR_FAIL();
}
}
@@ -4573,15 +4571,10 @@ void RasterizerStorageGLES2::instance_remove_dependency(RID p_base, RasterizerSc
ERR_FAIL_COND(!inst);
} break;
default: {
-
- if (!inst) {
- ERR_FAIL();
- }
+ ERR_FAIL();
}
}
- ERR_FAIL_COND(!inst);
-
inst->instance_list.remove(&p_instance->dependency_item);
}
diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp
index df7b170bf4..58eff791ca 100644
--- a/drivers/gles2/shader_gles2.cpp
+++ b/drivers/gles2/shader_gles2.cpp
@@ -182,14 +182,11 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
#endif
- int define_line_ofs = 1;
-
for (int j = 0; j < conditional_count; j++) {
bool enable = (conditional_version.version & (1 << j)) > 0;
if (enable) {
strings.push_back(conditional_defines[j]);
- define_line_ofs++;
DEBUG_PRINT(conditional_defines[j]);
}
}
@@ -206,7 +203,6 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
ERR_FAIL_COND_V(!cc, NULL);
v.code_version = cc->version;
- define_line_ofs += 2;
}
// program
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 30aa22732c..eb5ab53421 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -327,9 +327,6 @@ void RasterizerCanvasGLES3::_draw_polygon(const int *p_indices, int p_index_coun
uint32_t buffer_ofs = 0;
//vertex
-#ifdef DEBUG_ENABLED
- ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size);
-#endif
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_vertices);
glEnableVertexAttribArray(VS::ARRAY_VERTEX);
glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
@@ -694,7 +691,7 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y));
state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y));
- state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, (rect->flags & CANVAS_RECT_CLIP_UV) ? true : false);
+ state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, rect->flags & CANVAS_RECT_CLIP_UV);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -1935,7 +1932,7 @@ void RasterizerCanvasGLES3::draw_window_margins(int *black_margin, RID *black_im
int window_h = window_size.height;
int window_w = window_size.width;
- glBindFramebuffer(GL_FRAMEBUFFER, storage->system_fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
glViewport(0, 0, window_size.width, window_size.height);
canvas_begin();
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 7acb8a22bc..91c0693538 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -2426,7 +2426,7 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G
e->sort_key |= SORT_KEY_LIGHTMAP_CAPTURE_FLAG;
}
- e->sort_key |= uint64_t(p_material->render_priority + 128) << RenderList::SORT_KEY_PRIORITY_SHIFT;
+ e->sort_key |= (uint64_t(p_material->render_priority) + 128) << RenderList::SORT_KEY_PRIORITY_SHIFT;
}
/*
@@ -4297,7 +4297,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT];
use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS];
use_mrt = use_mrt && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW;
- use_mrt = use_mrt && env && (env->bg_mode != VS::ENV_BG_KEEP && env->bg_mode != VS::ENV_BG_CANVAS);
+ use_mrt = use_mrt && (env->bg_mode != VS::ENV_BG_KEEP && env->bg_mode != VS::ENV_BG_CANVAS);
glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
@@ -4454,16 +4454,16 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
RID camera_RGBA = feed->get_texture(CameraServer::FEED_RGBA_IMAGE);
VS::get_singleton()->texture_bind(camera_RGBA, 0);
- } else if (feed->get_datatype() == CameraFeed::FEED_YCbCr) {
- RID camera_YCbCr = feed->get_texture(CameraServer::FEED_YCbCr_IMAGE);
+ } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR) {
+ RID camera_YCbCr = feed->get_texture(CameraServer::FEED_YCBCR_IMAGE);
VS::get_singleton()->texture_bind(camera_YCbCr, 0);
storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, true);
- } else if (feed->get_datatype() == CameraFeed::FEED_YCbCr_Sep) {
+ } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR_SEP) {
RID camera_Y = feed->get_texture(CameraServer::FEED_Y_IMAGE);
- RID camera_CbCr = feed->get_texture(CameraServer::FEED_CbCr_IMAGE);
+ RID camera_CbCr = feed->get_texture(CameraServer::FEED_CBCR_IMAGE);
VS::get_singleton()->texture_bind(camera_Y, 0);
VS::get_singleton()->texture_bind(camera_CbCr, 1);
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index f8a3283869..0f6db2dfb8 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -1252,7 +1252,7 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer)
data.resize(data_size);
- Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1 ? true : false, img_format, data));
+ Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1, img_format, data));
return Ref<Image>(img);
#else
@@ -6074,10 +6074,7 @@ void RasterizerStorageGLES3::particles_set_emitting(RID p_particles, bool p_emit
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
- if (p_emitting != particles->emitting) {
- // Restart is overridden by set_emitting
- particles->restart_request = false;
- }
+
particles->emitting = p_emitting;
}
@@ -6475,7 +6472,6 @@ void RasterizerStorageGLES3::update_particles() {
Particles *particles = particle_update_list.first()->self();
if (particles->restart_request) {
- particles->emitting = true; //restart from zero
particles->prev_ticks = 0;
particles->phase = 0;
particles->prev_phase = 0;
@@ -6713,9 +6709,7 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base, RasterizerScene
ERR_FAIL_COND(!inst);
} break;
default: {
- if (!inst) {
- ERR_FAIL();
- }
+ ERR_FAIL();
}
}
@@ -6760,15 +6754,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base, RasterizerSc
ERR_FAIL_COND(!inst);
} break;
default: {
-
- if (!inst) {
- ERR_FAIL();
- }
+ ERR_FAIL();
}
}
- ERR_FAIL_COND(!inst);
-
inst->instance_list.remove(&p_instance->dependency_item);
}
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index badb656e96..0a7e47e304 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -816,7 +816,7 @@ public:
virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform);
virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform);
virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color);
- virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color);
+ virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_custom_data);
virtual RID multimesh_get_mesh(RID p_multimesh) const;
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index fa7cc00230..ac911993be 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -478,7 +478,7 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() {
glDeleteShader(v.vert_id);
glDeleteProgram(v.id);
v.id = 0;
- ERR_FAIL_COND_V(iloglen <= 0, NULL);
+ ERR_FAIL_COND_V(iloglen < 0, NULL);
}
if (iloglen == 0) {
diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp
index 0bf432c78a..f257fafd93 100644
--- a/drivers/png/image_loader_png.cpp
+++ b/drivers/png/image_loader_png.cpp
@@ -32,186 +32,26 @@
#include "core/os/os.h"
#include "core/print_string.h"
+#include "drivers/png/png_driver_common.h"
#include <string.h>
-void ImageLoaderPNG::_read_png_data(png_structp png_ptr, png_bytep data, png_size_t p_length) {
-
- FileAccess *f = (FileAccess *)png_get_io_ptr(png_ptr);
- f->get_buffer((uint8_t *)data, p_length);
-}
-
-/*
-png_structp png_ptr = png_create_read_struct_2
- (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
- user_error_fn, user_warning_fn, (png_voidp)
- user_mem_ptr, user_malloc_fn, user_free_fn);
-*/
-static png_voidp _png_malloc_fn(png_structp png_ptr, png_size_t size) {
-
- return memalloc(size);
-}
-
-static void _png_free_fn(png_structp png_ptr, png_voidp ptr) {
-
- memfree(ptr);
-}
-
-static void _png_error_function(png_structp, png_const_charp text) {
-
- ERR_PRINT(text);
-}
-
-static void _png_warn_function(png_structp, png_const_charp text) {
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- if (String(text).begins_with("iCCP")) return; // silences annoying spam emitted to output every time the user opened assetlib
- }
-#endif
- WARN_PRINT(text);
-}
-
-typedef void(PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp));
-
-Error ImageLoaderPNG::_load_image(void *rf_up, png_rw_ptr p_func, Ref<Image> p_image) {
-
- png_structp png;
- png_infop info;
-
- //png = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
-
- png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, _png_error_function, _png_warn_function, (png_voidp)NULL,
- _png_malloc_fn, _png_free_fn);
-
- ERR_FAIL_COND_V(!png, ERR_OUT_OF_MEMORY);
-
- info = png_create_info_struct(png);
- if (!info) {
- png_destroy_read_struct(&png, NULL, NULL);
- ERR_PRINT("Out of Memory");
- return ERR_OUT_OF_MEMORY;
- }
-
- if (setjmp(png_jmpbuf(png))) {
-
- png_destroy_read_struct(&png, NULL, NULL);
- ERR_PRINT("PNG Corrupted");
- return ERR_FILE_CORRUPT;
- }
-
- png_set_read_fn(png, (void *)rf_up, p_func);
-
- png_uint_32 width, height;
- int depth, color;
-
- png_read_info(png, info);
- png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL);
-
- //https://svn.gov.pt/projects/ccidadao/repository/middleware-offline/trunk/_src/eidmw/FreeImagePTEiD/Source/FreeImage/PluginPNG.cpp
- //png_get_text(png,info,)
- /*
- printf("Image width:%i\n", width);
- printf("Image Height:%i\n", height);
- printf("Bit depth:%i\n", depth);
- printf("Color type:%i\n", color);
- */
-
- bool update_info = false;
-
- if (depth < 8) { //only bit dept 8 per channel is handled
-
- png_set_packing(png);
- update_info = true;
- };
-
- if (png_get_color_type(png, info) == PNG_COLOR_TYPE_PALETTE) {
- png_set_palette_to_rgb(png);
- update_info = true;
- }
-
- if (depth > 8) {
- png_set_strip_16(png);
- update_info = true;
- }
-
- if (png_get_valid(png, info, PNG_INFO_tRNS)) {
- //png_set_expand_gray_1_2_4_to_8(png);
- png_set_tRNS_to_alpha(png);
- update_info = true;
- }
-
- if (update_info) {
- png_read_update_info(png, info);
- png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL);
- }
-
- int components = 0;
-
- Image::Format fmt;
- switch (color) {
-
- case PNG_COLOR_TYPE_GRAY: {
-
- fmt = Image::FORMAT_L8;
- components = 1;
- } break;
- case PNG_COLOR_TYPE_GRAY_ALPHA: {
-
- fmt = Image::FORMAT_LA8;
- components = 2;
- } break;
- case PNG_COLOR_TYPE_RGB: {
-
- fmt = Image::FORMAT_RGB8;
- components = 3;
- } break;
- case PNG_COLOR_TYPE_RGB_ALPHA: {
-
- fmt = Image::FORMAT_RGBA8;
- components = 4;
- } break;
- default: {
+Error ImageLoaderPNG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
- ERR_PRINT("INVALID PNG TYPE");
- png_destroy_read_struct(&png, &info, NULL);
- return ERR_UNAVAILABLE;
- } break;
+ const size_t buffer_size = f->get_len();
+ PoolVector<uint8_t> file_buffer;
+ Error err = file_buffer.resize(buffer_size);
+ if (err) {
+ f->close();
+ return err;
}
-
- //int rowsize = png_get_rowbytes(png, info);
- int rowsize = components * width;
-
- PoolVector<uint8_t> dstbuff;
-
- dstbuff.resize(rowsize * height);
-
- PoolVector<uint8_t>::Write dstbuff_write = dstbuff.write();
-
- uint8_t *data = dstbuff_write.ptr();
-
- uint8_t **row_p = memnew_arr(uint8_t *, height);
-
- for (unsigned int i = 0; i < height; i++) {
- row_p[i] = &data[components * width * i];
+ {
+ PoolVector<uint8_t>::Write writer = file_buffer.write();
+ f->get_buffer(writer.ptr(), buffer_size);
+ f->close();
}
-
- png_read_image(png, (png_bytep *)row_p);
-
- memdelete_arr(row_p);
-
- p_image->create(width, height, 0, fmt, dstbuff);
-
- png_destroy_read_struct(&png, &info, NULL);
-
- return OK;
-}
-
-Error ImageLoaderPNG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
-
- Error err = _load_image(f, _read_png_data, p_image);
- f->close();
-
- return err;
+ PoolVector<uint8_t>::Read reader = file_buffer.read();
+ return PNGDriverCommon::png_to_image(reader.ptr(), buffer_size, p_image);
}
void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const {
@@ -219,178 +59,53 @@ void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const
p_extensions->push_back("png");
}
-struct PNGReadStatus {
-
- uint32_t offset;
- uint32_t size;
- const unsigned char *image;
-};
-
-static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t p_length) {
-
- PNGReadStatus *rstatus;
- rstatus = (PNGReadStatus *)png_get_io_ptr(png_ptr);
-
- png_size_t to_read = MIN(p_length, rstatus->size - rstatus->offset);
- memcpy(data, &rstatus->image[rstatus->offset], to_read);
- rstatus->offset += to_read;
-
- if (to_read < p_length) {
- memset(&data[to_read], 0, p_length - to_read);
- }
-}
-
-static Ref<Image> _load_mem_png(const uint8_t *p_png, int p_size) {
-
- PNGReadStatus prs;
- prs.image = p_png;
- prs.offset = 0;
- prs.size = p_size;
+Ref<Image> ImageLoaderPNG::load_mem_png(const uint8_t *p_png, int p_size) {
Ref<Image> img;
img.instance();
- Error err = ImageLoaderPNG::_load_image(&prs, user_read_data, img);
+
+ Error err = PNGDriverCommon::png_to_image(p_png, p_size, img);
ERR_FAIL_COND_V(err, Ref<Image>());
return img;
}
-static Ref<Image> _lossless_unpack_png(const PoolVector<uint8_t> &p_data) {
+Ref<Image> ImageLoaderPNG::lossless_unpack_png(const PoolVector<uint8_t> &p_data) {
- int len = p_data.size();
+ const int len = p_data.size();
ERR_FAIL_COND_V(len < 4, Ref<Image>());
PoolVector<uint8_t>::Read r = p_data.read();
ERR_FAIL_COND_V(r[0] != 'P' || r[1] != 'N' || r[2] != 'G' || r[3] != ' ', Ref<Image>());
- return _load_mem_png(&r[4], len - 4);
-}
-
-static void _write_png_data(png_structp png_ptr, png_bytep data, png_size_t p_length) {
-
- PoolVector<uint8_t> &v = *(PoolVector<uint8_t> *)png_get_io_ptr(png_ptr);
- int vs = v.size();
-
- v.resize(vs + p_length);
- PoolVector<uint8_t>::Write w = v.write();
- copymem(&w[vs], data, p_length);
+ return load_mem_png(&r[4], len - 4);
}
-static PoolVector<uint8_t> _lossless_pack_png(const Ref<Image> &p_image) {
-
- Ref<Image> img = p_image->duplicate();
-
- if (img->is_compressed())
- img->decompress();
-
- ERR_FAIL_COND_V(img->is_compressed(), PoolVector<uint8_t>());
-
- png_structp png_ptr;
- png_infop info_ptr;
- png_bytep *row_pointers;
-
- /* initialize stuff */
- png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+PoolVector<uint8_t> ImageLoaderPNG::lossless_pack_png(const Ref<Image> &p_image) {
- ERR_FAIL_COND_V(!png_ptr, PoolVector<uint8_t>());
+ PoolVector<uint8_t> out_buffer;
- info_ptr = png_create_info_struct(png_ptr);
-
- ERR_FAIL_COND_V(!info_ptr, PoolVector<uint8_t>());
-
- if (setjmp(png_jmpbuf(png_ptr))) {
+ // add Godot's own "PNG " prefix
+ if (out_buffer.resize(4) != OK) {
ERR_FAIL_V(PoolVector<uint8_t>());
}
- PoolVector<uint8_t> ret;
- ret.push_back('P');
- ret.push_back('N');
- ret.push_back('G');
- ret.push_back(' ');
- png_set_write_fn(png_ptr, &ret, _write_png_data, NULL);
-
- /* write header */
- if (setjmp(png_jmpbuf(png_ptr))) {
- ERR_FAIL_V(PoolVector<uint8_t>());
+ // scope for writer lifetime
+ {
+ // must be closed before call to image_to_png
+ PoolVector<uint8_t>::Write writer = out_buffer.write();
+ copymem(writer.ptr(), "PNG ", 4);
}
- int pngf = 0;
- int cs = 0;
-
- switch (img->get_format()) {
-
- case Image::FORMAT_L8: {
-
- pngf = PNG_COLOR_TYPE_GRAY;
- cs = 1;
- } break;
- case Image::FORMAT_LA8: {
-
- pngf = PNG_COLOR_TYPE_GRAY_ALPHA;
- cs = 2;
- } break;
- case Image::FORMAT_RGB8: {
-
- pngf = PNG_COLOR_TYPE_RGB;
- cs = 3;
- } break;
- case Image::FORMAT_RGBA8: {
-
- pngf = PNG_COLOR_TYPE_RGB_ALPHA;
- cs = 4;
- } break;
- default: {
-
- if (img->detect_alpha()) {
-
- img->convert(Image::FORMAT_RGBA8);
- pngf = PNG_COLOR_TYPE_RGB_ALPHA;
- cs = 4;
- } else {
-
- img->convert(Image::FORMAT_RGB8);
- pngf = PNG_COLOR_TYPE_RGB;
- cs = 3;
- }
- }
- }
-
- int w = img->get_width();
- int h = img->get_height();
- png_set_IHDR(png_ptr, info_ptr, w, h,
- 8, pngf, PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
-
- png_write_info(png_ptr, info_ptr);
-
- /* write bytes */
- if (setjmp(png_jmpbuf(png_ptr))) {
+ Error err = PNGDriverCommon::image_to_png(p_image, out_buffer);
+ if (err) {
ERR_FAIL_V(PoolVector<uint8_t>());
}
- PoolVector<uint8_t>::Read r = img->get_data().read();
-
- row_pointers = (png_bytep *)memalloc(sizeof(png_bytep) * h);
- for (int i = 0; i < h; i++) {
-
- row_pointers[i] = (png_bytep)&r[i * w * cs];
- }
- png_write_image(png_ptr, row_pointers);
-
- memfree(row_pointers);
-
- /* end write */
- if (setjmp(png_jmpbuf(png_ptr))) {
-
- ERR_FAIL_V(PoolVector<uint8_t>());
- }
-
- png_write_end(png_ptr, NULL);
-
- return ret;
+ return out_buffer;
}
ImageLoaderPNG::ImageLoaderPNG() {
- Image::_png_mem_loader_func = _load_mem_png;
- Image::lossless_unpacker = _lossless_unpack_png;
- Image::lossless_packer = _lossless_pack_png;
+ Image::_png_mem_loader_func = load_mem_png;
+ Image::lossless_unpacker = lossless_unpack_png;
+ Image::lossless_packer = lossless_pack_png;
}
diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h
index c3951979c3..cc789f95d6 100644
--- a/drivers/png/image_loader_png.h
+++ b/drivers/png/image_loader_png.h
@@ -33,17 +33,16 @@
#include "core/io/image_loader.h"
-#include <png.h>
-
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class ImageLoaderPNG : public ImageFormatLoader {
-
- static void _read_png_data(png_structp png_ptr, png_bytep data, png_size_t p_length);
+private:
+ static PoolVector<uint8_t> lossless_pack_png(const Ref<Image> &p_image);
+ static Ref<Image> lossless_unpack_png(const PoolVector<uint8_t> &p_data);
+ static Ref<Image> load_mem_png(const uint8_t *p_png, int p_size);
public:
- static Error _load_image(void *rf_up, png_rw_ptr p_func, Ref<Image> p_image);
virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderPNG();
diff --git a/drivers/png/png_driver_common.cpp b/drivers/png/png_driver_common.cpp
new file mode 100644
index 0000000000..0e849bf2fe
--- /dev/null
+++ b/drivers/png/png_driver_common.cpp
@@ -0,0 +1,205 @@
+/*************************************************************************/
+/* png_driver_common.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "png_driver_common.h"
+
+#include "core/os/os.h"
+
+#include <png.h>
+#include <string.h>
+
+namespace PNGDriverCommon {
+
+// Print any warnings.
+// On error, set explain and return true.
+// Call should be wrapped in ERR_FAIL_COND
+static bool check_error(const png_image &image) {
+ const png_uint_32 failed = PNG_IMAGE_FAILED(image);
+ if (failed & PNG_IMAGE_ERROR) {
+ ERR_EXPLAINC(image.message);
+ return true;
+ } else if (failed) {
+#ifdef TOOLS_ENABLED
+ // suppress this warning, to avoid log spam when opening assetlib
+ const static char *const noisy = "iCCP: known incorrect sRGB profile";
+ const Engine *const eng = Engine::get_singleton();
+ if (eng && eng->is_editor_hint() && !strcmp(image.message, noisy)) {
+ return false;
+ }
+#endif
+ WARN_PRINT(image.message);
+ }
+ return false;
+}
+
+Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image) {
+
+ png_image png_img;
+ zeromem(&png_img, sizeof(png_img));
+ png_img.version = PNG_IMAGE_VERSION;
+
+ // fetch image properties
+ int success = png_image_begin_read_from_memory(&png_img, p_source, p_size);
+ ERR_FAIL_COND_V(check_error(png_img), ERR_FILE_CORRUPT);
+ ERR_FAIL_COND_V(!success, ERR_FILE_CORRUPT);
+
+ // flags to be masked out of input format to give target format
+ const png_uint_32 format_mask = ~(
+ // convert component order to RGBA
+ PNG_FORMAT_FLAG_BGR | PNG_FORMAT_FLAG_AFIRST
+ // convert 16 bit components to 8 bit
+ | PNG_FORMAT_FLAG_LINEAR
+ // convert indexed image to direct color
+ | PNG_FORMAT_FLAG_COLORMAP);
+
+ png_img.format &= format_mask;
+
+ Image::Format dest_format;
+ switch (png_img.format) {
+ case PNG_FORMAT_GRAY:
+ dest_format = Image::FORMAT_L8;
+ break;
+ case PNG_FORMAT_GA:
+ dest_format = Image::FORMAT_LA8;
+ break;
+ case PNG_FORMAT_RGB:
+ dest_format = Image::FORMAT_RGB8;
+ break;
+ case PNG_FORMAT_RGBA:
+ dest_format = Image::FORMAT_RGBA8;
+ break;
+ default:
+ png_image_free(&png_img); // only required when we return before finish_read
+ ERR_PRINT("Unsupported png format");
+ return ERR_UNAVAILABLE;
+ }
+
+ const png_uint_32 stride = PNG_IMAGE_ROW_STRIDE(png_img);
+ PoolVector<uint8_t> buffer;
+ Error err = buffer.resize(PNG_IMAGE_BUFFER_SIZE(png_img, stride));
+ if (err) {
+ png_image_free(&png_img); // only required when we return before finish_read
+ return err;
+ }
+ PoolVector<uint8_t>::Write writer = buffer.write();
+
+ // read image data to buffer and release libpng resources
+ success = png_image_finish_read(&png_img, NULL, writer.ptr(), stride, NULL);
+ ERR_FAIL_COND_V(check_error(png_img), ERR_FILE_CORRUPT);
+ ERR_FAIL_COND_V(!success, ERR_FILE_CORRUPT);
+
+ p_image->create(png_img.width, png_img.height, 0, dest_format, buffer);
+
+ return OK;
+}
+
+Error image_to_png(const Ref<Image> &p_image, PoolVector<uint8_t> &p_buffer) {
+
+ Ref<Image> source_image = p_image->duplicate();
+
+ if (source_image->is_compressed())
+ source_image->decompress();
+
+ ERR_FAIL_COND_V(source_image->is_compressed(), FAILED);
+
+ png_image png_img;
+ zeromem(&png_img, sizeof(png_img));
+ png_img.version = PNG_IMAGE_VERSION;
+ png_img.width = source_image->get_width();
+ png_img.height = source_image->get_height();
+
+ switch (source_image->get_format()) {
+ case Image::FORMAT_L8:
+ png_img.format = PNG_FORMAT_GRAY;
+ break;
+ case Image::FORMAT_LA8:
+ png_img.format = PNG_FORMAT_GA;
+ break;
+ case Image::FORMAT_RGB8:
+ png_img.format = PNG_FORMAT_RGB;
+ break;
+ case Image::FORMAT_RGBA8:
+ png_img.format = PNG_FORMAT_RGBA;
+ break;
+ default:
+ if (source_image->detect_alpha()) {
+ source_image->convert(Image::FORMAT_RGBA8);
+ png_img.format = PNG_FORMAT_RGBA;
+ } else {
+ source_image->convert(Image::FORMAT_RGB8);
+ png_img.format = PNG_FORMAT_RGB;
+ }
+ }
+
+ const PoolVector<uint8_t> image_data = source_image->get_data();
+ const PoolVector<uint8_t>::Read reader = image_data.read();
+
+ // we may be passed a buffer with existing content we're expected to append to
+ const int buffer_offset = p_buffer.size();
+
+ const size_t png_size_estimate = PNG_IMAGE_PNG_SIZE_MAX(png_img);
+
+ // try with estimated size
+ size_t compressed_size = png_size_estimate;
+ int success = 0;
+ { // scope writer lifetime
+ Error err = p_buffer.resize(buffer_offset + png_size_estimate);
+ ERR_FAIL_COND_V(err, err);
+
+ PoolVector<uint8_t>::Write writer = p_buffer.write();
+ success = png_image_write_to_memory(&png_img, &writer[buffer_offset],
+ &compressed_size, 0, reader.ptr(), 0, NULL);
+ ERR_FAIL_COND_V(check_error(png_img), FAILED);
+ }
+ if (!success) {
+ if (compressed_size <= png_size_estimate) {
+ // buffer was big enough, must be some other error
+ ERR_FAIL_V(FAILED);
+ }
+
+ // write failed due to buffer size, resize and retry
+ Error err = p_buffer.resize(buffer_offset + compressed_size);
+ ERR_FAIL_COND_V(err, err);
+
+ PoolVector<uint8_t>::Write writer = p_buffer.write();
+ success = png_image_write_to_memory(&png_img, &writer[buffer_offset],
+ &compressed_size, 0, reader.ptr(), 0, NULL);
+ ERR_FAIL_COND_V(check_error(png_img), FAILED);
+ ERR_FAIL_COND_V(!success, FAILED);
+ }
+
+ // trim buffer size to content
+ Error err = p_buffer.resize(buffer_offset + compressed_size);
+ ERR_FAIL_COND_V(err, err);
+
+ return OK;
+}
+
+} // namespace PNGDriverCommon
diff --git a/drivers/png/png_driver_common.h b/drivers/png/png_driver_common.h
new file mode 100644
index 0000000000..3ff87759fb
--- /dev/null
+++ b/drivers/png/png_driver_common.h
@@ -0,0 +1,48 @@
+/*************************************************************************/
+/* png_driver_common.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef PNG_DRIVER_COMMON_H
+#define PNG_DRIVER_COMMON_H
+
+#include "core/image.h"
+#include "core/pool_vector.h"
+
+namespace PNGDriverCommon {
+
+// Attempt to load png from buffer (p_source, p_size) into p_image
+Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image);
+
+// Append p_image, as a png, to p_buffer.
+// Contents of p_buffer is unspecified if error returned.
+Error image_to_png(const Ref<Image> &p_image, PoolVector<uint8_t> &p_buffer);
+
+} // namespace PNGDriverCommon
+
+#endif
diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp
index 9e8043cbea..89e8ee32cc 100644
--- a/drivers/png/resource_saver_png.cpp
+++ b/drivers/png/resource_saver_png.cpp
@@ -32,17 +32,9 @@
#include "core/image.h"
#include "core/os/file_access.h"
-#include "core/project_settings.h"
+#include "drivers/png/png_driver_common.h"
#include "scene/resources/texture.h"
-#include <png.h>
-
-static void _write_png_data(png_structp png_ptr, png_bytep data, png_size_t p_length) {
-
- FileAccess *f = (FileAccess *)png_get_io_ptr(png_ptr);
- f->store_buffer((const uint8_t *)data, p_length);
-}
-
Error ResourceSaverPNG::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
Ref<ImageTexture> texture = p_resource;
@@ -55,129 +47,27 @@ Error ResourceSaverPNG::save(const String &p_path, const RES &p_resource, uint32
Error err = save_image(p_path, img);
- if (err == OK) {
- }
-
return err;
};
Error ResourceSaverPNG::save_image(const String &p_path, const Ref<Image> &p_img) {
- Ref<Image> img = p_img->duplicate();
-
- if (img->is_compressed())
- img->decompress();
-
- ERR_FAIL_COND_V(img->is_compressed(), ERR_INVALID_PARAMETER);
-
- png_structp png_ptr;
- png_infop info_ptr;
- png_bytep *row_pointers;
-
- /* initialize stuff */
- png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-
- ERR_FAIL_COND_V(!png_ptr, ERR_CANT_CREATE);
+ PoolVector<uint8_t> buffer;
+ Error err = PNGDriverCommon::image_to_png(p_img, buffer);
+ ERR_FAIL_COND_V(err, err);
+ FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V(err, err);
- info_ptr = png_create_info_struct(png_ptr);
+ PoolVector<uint8_t>::Read reader = buffer.read();
- ERR_FAIL_COND_V(!info_ptr, ERR_CANT_CREATE);
-
- if (setjmp(png_jmpbuf(png_ptr))) {
- ERR_FAIL_V(ERR_CANT_OPEN);
- }
- //change this
- Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE, &err);
- if (err) {
- ERR_FAIL_V(err);
- }
-
- png_set_write_fn(png_ptr, f, _write_png_data, NULL);
-
- /* write header */
- if (setjmp(png_jmpbuf(png_ptr))) {
- ERR_FAIL_V(ERR_CANT_OPEN);
+ file->store_buffer(reader.ptr(), buffer.size());
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ memdelete(file);
+ return ERR_CANT_CREATE;
}
- int pngf = 0;
- int cs = 0;
-
- switch (img->get_format()) {
-
- case Image::FORMAT_L8: {
-
- pngf = PNG_COLOR_TYPE_GRAY;
- cs = 1;
- } break;
- case Image::FORMAT_LA8: {
-
- pngf = PNG_COLOR_TYPE_GRAY_ALPHA;
- cs = 2;
- } break;
- case Image::FORMAT_RGB8: {
-
- pngf = PNG_COLOR_TYPE_RGB;
- cs = 3;
- } break;
- case Image::FORMAT_RGBA8: {
-
- pngf = PNG_COLOR_TYPE_RGB_ALPHA;
- cs = 4;
- } break;
- default: {
-
- if (img->detect_alpha()) {
-
- img->convert(Image::FORMAT_RGBA8);
- pngf = PNG_COLOR_TYPE_RGB_ALPHA;
- cs = 4;
- } else {
-
- img->convert(Image::FORMAT_RGB8);
- pngf = PNG_COLOR_TYPE_RGB;
- cs = 3;
- }
- }
- }
-
- int w = img->get_width();
- int h = img->get_height();
- png_set_IHDR(png_ptr, info_ptr, w, h,
- 8, pngf, PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
-
- png_write_info(png_ptr, info_ptr);
-
- /* write bytes */
- if (setjmp(png_jmpbuf(png_ptr))) {
- memdelete(f);
- ERR_FAIL_V(ERR_CANT_OPEN);
- }
-
- PoolVector<uint8_t>::Read r = img->get_data().read();
-
- row_pointers = (png_bytep *)memalloc(sizeof(png_bytep) * h);
- for (int i = 0; i < h; i++) {
-
- row_pointers[i] = (png_bytep)&r[i * w * cs];
- }
- png_write_image(png_ptr, row_pointers);
-
- memfree(row_pointers);
-
- /* end write */
- if (setjmp(png_jmpbuf(png_ptr))) {
-
- memdelete(f);
- ERR_FAIL_V(ERR_CANT_OPEN);
- }
-
- png_write_end(png_ptr, NULL);
- memdelete(f);
-
- /* cleanup heap allocation */
- png_destroy_write_struct(&png_ptr, &info_ptr);
+ file->close();
+ memdelete(file);
return OK;
}
@@ -186,6 +76,7 @@ bool ResourceSaverPNG::recognize(const RES &p_resource) const {
return (p_resource.is_valid() && p_resource->is_class("ImageTexture"));
}
+
void ResourceSaverPNG::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
if (Object::cast_to<Texture>(*p_resource)) {
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index e011176806..251bab5783 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -100,10 +100,7 @@ bool DirAccessUnix::dir_exists(String p_dir) {
struct stat flags;
bool success = (stat(p_dir.utf8().get_data(), &flags) == 0);
- if (success && S_ISDIR(flags.st_mode))
- return true;
-
- return false;
+ return (success && S_ISDIR(flags.st_mode));
}
uint64_t DirAccessUnix::get_modified_time(String p_file) {
@@ -316,7 +313,7 @@ Error DirAccessUnix::change_dir(String p_dir) {
// try_dir is the directory we are trying to change into
String try_dir = "";
if (p_dir.is_rel_path()) {
- String next_dir = current_dir + "/" + p_dir;
+ String next_dir = current_dir.plus_file(p_dir);
next_dir = next_dir.simplify_path();
try_dir = next_dir;
} else {
diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp
index b5feaabc32..ce66f07a19 100644
--- a/drivers/unix/ip_unix.cpp
+++ b/drivers/unix/ip_unix.cpp
@@ -72,11 +72,13 @@
#ifdef __FreeBSD__
#include <netinet/in.h>
#endif
+#include <net/if.h> // Order is important on OpenBSD, leave as last
#endif
static IP_Address _sockaddr2ip(struct sockaddr *p_addr) {
IP_Address ip;
+
if (p_addr->sa_family == AF_INET) {
struct sockaddr_in *addr = (struct sockaddr_in *)p_addr;
ip.set_ipv4((uint8_t *)&(addr->sin_addr));
@@ -129,24 +131,42 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
#if defined(UWP_ENABLED)
-void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
+void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
using namespace Windows::Networking;
using namespace Windows::Networking::Connectivity;
+ // Returns addresses, not interfaces.
auto hostnames = NetworkInformation::GetHostNames();
for (int i = 0; i < hostnames->Size; i++) {
- if (hostnames->GetAt(i)->Type == HostNameType::Ipv4 || hostnames->GetAt(i)->Type == HostNameType::Ipv6 && hostnames->GetAt(i)->IPInformation != nullptr) {
+ auto hostname = hostnames->GetAt(i);
+
+ if (hostname->Type != HostNameType::Ipv4 && hostname->Type != HostNameType::Ipv6)
+ continue;
- r_addresses->push_back(IP_Address(String(hostnames->GetAt(i)->CanonicalName->Data())));
+ String name = hostname->RawName->Data();
+ Map<String, Interface_Info>::Element *E = r_interfaces->find(name);
+ if (!E) {
+ Interface_Info info;
+ info.name = name;
+ info.name_friendly = hostname->DisplayName->Data();
+ info.index = 0;
+ E = r_interfaces->insert(name, info);
+ ERR_CONTINUE(!E);
}
+
+ Interface_Info &info = E->get();
+
+ IP_Address ip = IP_Address(hostname->CanonicalName->Data());
+ info.ip_addresses.push_front(ip);
}
-};
+}
+
#else
-void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
+void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
ULONG buf_size = 1024;
IP_ADAPTER_ADDRESSES *addrs;
@@ -173,29 +193,23 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
while (adapter != NULL) {
+ Interface_Info info;
+ info.name = adapter->AdapterName;
+ info.name_friendly = adapter->FriendlyName;
+ info.index = String::num_uint64(adapter->IfIndex);
+
IP_ADAPTER_UNICAST_ADDRESS *address = adapter->FirstUnicastAddress;
while (address != NULL) {
-
- IP_Address ip;
-
- if (address->Address.lpSockaddr->sa_family == AF_INET) {
-
- SOCKADDR_IN *ipv4 = reinterpret_cast<SOCKADDR_IN *>(address->Address.lpSockaddr);
-
- ip.set_ipv4((uint8_t *)&(ipv4->sin_addr));
- r_addresses->push_back(ip);
-
- } else if (address->Address.lpSockaddr->sa_family == AF_INET6) { // ipv6
-
- SOCKADDR_IN6 *ipv6 = reinterpret_cast<SOCKADDR_IN6 *>(address->Address.lpSockaddr);
-
- ip.set_ipv6(ipv6->sin6_addr.s6_addr);
- r_addresses->push_back(ip);
- };
-
+ int family = address->Address.lpSockaddr->sa_family;
+ if (family != AF_INET && family != AF_INET6)
+ continue;
+ info.ip_addresses.push_front(_sockaddr2ip(address->Address.lpSockaddr));
address = address->Next;
- };
+ }
adapter = adapter->Next;
+ // Only add interface if it has at least one IP
+ if (info.ip_addresses.size() > 0)
+ r_interfaces->insert(info.name, info);
};
memfree(addrs);
@@ -205,7 +219,7 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
#else // UNIX
-void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
+void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
struct ifaddrs *ifAddrStruct = NULL;
struct ifaddrs *ifa = NULL;
@@ -222,8 +236,18 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
if (family != AF_INET && family != AF_INET6)
continue;
- IP_Address ip = _sockaddr2ip(ifa->ifa_addr);
- r_addresses->push_back(ip);
+ Map<String, Interface_Info>::Element *E = r_interfaces->find(ifa->ifa_name);
+ if (!E) {
+ Interface_Info info;
+ info.name = ifa->ifa_name;
+ info.name_friendly = ifa->ifa_name;
+ info.index = String::num_uint64(if_nametoindex(ifa->ifa_name));
+ E = r_interfaces->insert(ifa->ifa_name, info);
+ ERR_CONTINUE(!E);
+ }
+
+ Interface_Info &info = E->get();
+ info.ip_addresses.push_front(_sockaddr2ip(ifa->ifa_addr));
}
if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct);
diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h
index e36535146e..f9bb626cc4 100644
--- a/drivers/unix/ip_unix.h
+++ b/drivers/unix/ip_unix.h
@@ -43,7 +43,7 @@ class IP_Unix : public IP {
static IP *_create_unix();
public:
- virtual void get_local_addresses(List<IP_Address> *r_addresses) const;
+ virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const;
static void make_default();
IP_Unix();
diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp
index 75d51c8503..16562e2c8f 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_posix.cpp
@@ -55,8 +55,12 @@
#include <netinet/tcp.h>
-#if defined(__APPLE__)
-#define MSG_NOSIGNAL SO_NOSIGPIPE
+// BSD calls this flag IPV6_JOIN_GROUP
+#if !defined(IPV6_ADD_MEMBERSHIP) && defined(IPV6_JOIN_GROUP)
+#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
+#endif
+#if !defined(IPV6_DROP_MEMBERSHIP) && defined(IPV6_LEAVE_GROUP)
+#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
#endif
// Some custom defines to minimize ifdefs
@@ -79,10 +83,6 @@
#define SOCK_IOCTL ioctlsocket
#define SOCK_CLOSE closesocket
-// Windows doesn't have this flag
-#ifndef MSG_NOSIGNAL
-#define MSG_NOSIGNAL 0
-#endif
// Workaround missing flag in MinGW
#if defined(__MINGW32__) && !defined(SIO_UDP_NETRESET)
#define SIO_UDP_NETRESET _WSAIOW(IOC_VENDOR, 15)
@@ -221,10 +221,59 @@ bool NetSocketPosix::_can_use_ip(const IP_Address p_ip, const bool p_for_bind) c
}
// Check if socket support this IP type.
IP::Type type = p_ip.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
- if (_ip_type != IP::TYPE_ANY && !p_ip.is_wildcard() && _ip_type != type) {
- return false;
+ return !(_ip_type != IP::TYPE_ANY && !p_ip.is_wildcard() && _ip_type != type);
+}
+
+_FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add) {
+
+ ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(!_can_use_ip(p_ip, false), ERR_INVALID_PARAMETER);
+
+ // Need to force level and af_family to IP(v4) when using dual stacking and provided multicast group is IPv4
+ IP::Type type = _ip_type == IP::TYPE_ANY && p_ip.is_ipv4() ? IP::TYPE_IPV4 : _ip_type;
+ // This needs to be the proper level for the multicast group, no matter if the socket is dual stacking.
+ int level = type == IP::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
+ int ret = -1;
+
+ IP_Address if_ip;
+ uint32_t if_v6id = 0;
+ Map<String, IP::Interface_Info> if_info;
+ IP::get_singleton()->get_local_interfaces(&if_info);
+ for (Map<String, IP::Interface_Info>::Element *E = if_info.front(); E; E = E->next()) {
+ IP::Interface_Info &c = E->get();
+ if (c.name != p_if_name)
+ continue;
+
+ if_v6id = (uint32_t)c.index.to_int64();
+ if (type == IP::TYPE_IPV6)
+ break; // IPv6 uses index.
+
+ for (List<IP_Address>::Element *F = c.ip_addresses.front(); F; F = F->next()) {
+ if (!F->get().is_ipv4())
+ continue; // Wrong IP type
+ if_ip = F->get();
+ break;
+ }
+ break;
}
- return true;
+
+ if (level == IPPROTO_IP) {
+ ERR_FAIL_COND_V(!if_ip.is_valid(), ERR_INVALID_PARAMETER);
+ struct ip_mreq greq;
+ int sock_opt = p_add ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
+ copymem(&greq.imr_multiaddr, p_ip.get_ipv4(), 4);
+ copymem(&greq.imr_interface, if_ip.get_ipv4(), 4);
+ ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
+ } else {
+ struct ipv6_mreq greq;
+ int sock_opt = p_add ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
+ copymem(&greq.ipv6mr_multiaddr, p_ip.get_ipv6(), 16);
+ greq.ipv6mr_interface = if_v6id;
+ ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
+ }
+ ERR_FAIL_COND_V(ret != 0, FAILED);
+
+ return OK;
}
void NetSocketPosix::_set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream) {
@@ -285,6 +334,13 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) {
}
}
#endif
+#if defined(SO_NOSIGPIPE)
+ // Disable SIGPIPE (should only be relevant to stream sockets, but seems to affect UDP too on iOS)
+ int par = 1;
+ if (setsockopt(_sock, SOL_SOCKET, SO_NOSIGPIPE, SOCK_CBUF(&par), sizeof(int)) != 0) {
+ print_verbose("Unable to turn off SIGPIPE on socket");
+ }
+#endif
return OK;
}
@@ -421,7 +477,7 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const {
pfd.events = POLLOUT;
break;
case POLL_TYPE_IN_OUT:
- pfd.events = POLLOUT || POLLIN;
+ pfd.events = POLLOUT | POLLIN;
}
int ret = ::poll(&pfd, 1, p_timeout);
@@ -489,8 +545,10 @@ Error NetSocketPosix::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
int flags = 0;
+#ifdef MSG_NOSIGNAL
if (_is_stream)
flags = MSG_NOSIGNAL;
+#endif
r_sent = ::send(_sock, SOCK_CBUF(p_buffer), p_len, flags);
if (r_sent < 0) {
@@ -625,3 +683,11 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) {
ns->set_blocking_enabled(false);
return Ref<NetSocket>(ns);
}
+
+Error NetSocketPosix::join_multicast_group(const IP_Address &p_ip, String p_if_name) {
+ return _change_multicast_group(p_ip, p_if_name, true);
+}
+
+Error NetSocketPosix::leave_multicast_group(const IP_Address &p_ip, String p_if_name) {
+ return _change_multicast_group(p_ip, p_if_name, false);
+}
diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h
index b7fb3fdc94..ce6dc00d42 100644
--- a/drivers/unix/net_socket_posix.h
+++ b/drivers/unix/net_socket_posix.h
@@ -60,6 +60,7 @@ private:
NetError _get_socket_error();
void _set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream);
+ _FORCE_INLINE_ Error _change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add);
protected:
static NetSocket *_create_func();
@@ -76,7 +77,7 @@ public:
virtual void close();
virtual Error bind(IP_Address p_addr, uint16_t p_port);
virtual Error listen(int p_max_pending);
- virtual Error connect_to_host(IP_Address p_addr, uint16_t p_port);
+ virtual Error connect_to_host(IP_Address p_host, uint16_t p_port);
virtual Error poll(PollType p_type, int timeout) const;
virtual Error recv(uint8_t *p_buffer, int p_len, int &r_read);
virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port);
@@ -93,6 +94,8 @@ public:
virtual void set_tcp_no_delay_enabled(bool p_enabled);
virtual void set_reuse_address_enabled(bool p_enabled);
virtual void set_reuse_port_enabled(bool p_enabled);
+ virtual Error join_multicast_group(const IP_Address &p_multi_address, String p_if_name);
+ virtual Error leave_multicast_group(const IP_Address &p_multi_address, String p_if_name);
NetSocketPosix();
~NetSocketPosix();