summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dummy/rasterizer_dummy.h4
-rw-r--r--drivers/dummy/texture_loader_dummy.h1
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp4
-rw-r--r--drivers/gles2/rasterizer_gles2.h2
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp96
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.h4
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp47
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.h1
-rw-r--r--drivers/gles2/shader_compiler_gles2.cpp15
-rw-r--r--drivers/gles2/shader_gles2.cpp4
-rw-r--r--drivers/gles2/shader_gles2.h2
-rw-r--r--drivers/gles2/shaders/copy.glsl29
-rw-r--r--drivers/gles2/shaders/scene.glsl57
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp7
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp4
-rw-r--r--drivers/gles3/rasterizer_gles3.h2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp89
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h4
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp35
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h3
-rw-r--r--drivers/gles3/shader_compiler_gles3.cpp13
-rw-r--r--drivers/gles3/shader_gles3.cpp2
-rw-r--r--drivers/gles3/shaders/copy.glsl36
-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/png/resource_saver_png.h1
-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.cpp92
-rw-r--r--drivers/unix/net_socket_posix.h5
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp16
-rw-r--r--drivers/windows/file_access_windows.cpp4
36 files changed, 819 insertions, 601 deletions
diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h
index 253936ca34..3deaef09e7 100644
--- a/drivers/dummy/rasterizer_dummy.h
+++ b/drivers/dummy/rasterizer_dummy.h
@@ -61,6 +61,7 @@ public:
void environment_set_bg_energy(RID p_env, float p_energy) {}
void environment_set_canvas_max_layer(RID p_env, int p_max_layer) {}
void environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy = 1.0, float p_sky_contribution = 0.0) {}
+ void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id){};
void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) {}
void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) {}
@@ -216,6 +217,7 @@ public:
uint32_t texture_get_height(RID p_texture) const { return 0; }
uint32_t texture_get_depth(RID p_texture) const { return 0; }
void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth_3d) {}
+ void texture_bind(RID p_texture, uint32_t p_texture_no) {}
void texture_set_path(RID p_texture, const String &p_path) {
DummyTexture *t = texture_owner.getornull(p_texture);
@@ -780,7 +782,7 @@ public:
RasterizerCanvas *get_canvas() { return &canvas; }
RasterizerScene *get_scene() { return &scene; }
- void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale) {}
+ void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) {}
void initialize() {}
void begin_frame(double frame_step) {}
diff --git a/drivers/dummy/texture_loader_dummy.h b/drivers/dummy/texture_loader_dummy.h
index 3038bffc95..0bc7fa226b 100644
--- a/drivers/dummy/texture_loader_dummy.h
+++ b/drivers/dummy/texture_loader_dummy.h
@@ -35,7 +35,6 @@
#include "scene/resources/texture.h"
class ResourceFormatDummyTexture : public ResourceFormatLoader {
- GDCLASS(ResourceFormatDummyTexture, ResourceFormatLoader)
public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index f49f52e47b..cbd0e4a5d5 100644
--- a/drivers/gles2/rasterizer_gles2.cpp
+++ b/drivers/gles2/rasterizer_gles2.cpp
@@ -338,7 +338,7 @@ void RasterizerGLES2::clear_render_target(const Color &p_color) {
storage->frame.clear_request_color = p_color;
}
-void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale) {
+void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) {
if (p_image.is_null() || p_image->empty())
return;
@@ -360,7 +360,7 @@ void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_c
canvas->canvas_begin();
RID texture = storage->texture_create();
- storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER);
+ storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_use_filter ? VS::TEXTURE_FLAG_FILTER : 0);
storage->texture_set_data(texture, p_image);
Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height());
diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h
index eeed86e263..4d0d961ae4 100644
--- a/drivers/gles2/rasterizer_gles2.h
+++ b/drivers/gles2/rasterizer_gles2.h
@@ -51,7 +51,7 @@ public:
virtual RasterizerCanvas *get_canvas();
virtual RasterizerScene *get_scene();
- virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale);
+ virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true);
virtual void initialize();
virtual void begin_frame(double frame_step);
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index 50cb39b13f..ea29af7d9e 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -36,6 +36,7 @@
#include "core/project_settings.h"
#include "core/vmap.h"
#include "rasterizer_canvas_gles2.h"
+#include "servers/camera/camera_feed.h"
#include "servers/visual/visual_server_raster.h"
#ifndef GLES_OVER_GL
@@ -769,6 +770,13 @@ void RasterizerSceneGLES2::environment_set_ambient_light(RID p_env, const Color
env->ambient_sky_contribution = p_sky_contribution;
}
+void RasterizerSceneGLES2::environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+
+ env->camera_feed_id = p_camera_feed_id;
+}
+
void RasterizerSceneGLES2::environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality) {
Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
@@ -2261,7 +2269,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
bool rebind_reflection = false;
bool rebind_lightmap = false;
- if (!p_shadow) {
+ if (!p_shadow && material->shader) {
bool unshaded = material->shader->spatial.unshaded;
@@ -2281,7 +2289,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
bool depth_prepass = false;
- if (!p_alpha_pass && material->shader && material->shader->spatial.depth_draw_mode == RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) {
+ if (!p_alpha_pass && material->shader->spatial.depth_draw_mode == RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) {
depth_prepass = true;
}
@@ -2843,6 +2851,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
// clear color
Color clear_color(0, 0, 0, 1);
+ Ref<CameraFeed> feed;
if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
clear_color = Color(0, 0, 0, 0);
@@ -2855,6 +2864,9 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
} else if (env->bg_mode == VS::ENV_BG_CANVAS || env->bg_mode == VS::ENV_BG_COLOR || env->bg_mode == VS::ENV_BG_COLOR_SKY) {
clear_color = env->bg_color;
storage->frame.clear_request = false;
+ } else if (env->bg_mode == VS::ENV_BG_CAMERA_FEED) {
+ feed = CameraServer::get_singleton()->get_feed_by_id(env->camera_feed_id);
+ storage->frame.clear_request = false;
} else {
storage->frame.clear_request = false;
}
@@ -2891,7 +2903,66 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
env_radiance_tex = sky->radiance;
}
} break;
+ case VS::ENV_BG_CAMERA_FEED: {
+ if (feed.is_valid() && (feed->get_base_width() > 0) && (feed->get_base_height() > 0)) {
+ // copy our camera feed to our background
+
+ glDisable(GL_BLEND);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_NO_ALPHA, true);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_DISPLAY_TRANSFORM, true);
+
+ if (feed->get_datatype() == CameraFeed::FEED_RGB) {
+ 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);
+
+ 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) {
+ RID camera_Y = feed->get_texture(CameraServer::FEED_Y_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);
+
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::SEP_CBCR_TEXTURE, true);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::YCBCR_TO_RGB, true);
+ };
+
+ storage->shaders.copy.bind();
+ storage->shaders.copy.set_uniform(CopyShaderGLES2::DISPLAY_TRANSFORM, feed->get_transform());
+
+ storage->bind_quad_array();
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ glDisableVertexAttribArray(VS::ARRAY_VERTEX);
+ glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ // turn off everything used
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::SEP_CBCR_TEXTURE, false);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::YCBCR_TO_RGB, false);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_NO_ALPHA, false);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_DISPLAY_TRANSFORM, false);
+ //restore
+ glEnable(GL_BLEND);
+ glDepthMask(GL_TRUE);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ } else {
+ // don't have a feed, just show greenscreen :)
+ clear_color = Color(0.0, 1.0, 0.0, 1.0);
+ }
+ } break;
default: {
// FIXME: implement other background modes
} break;
@@ -2919,7 +2990,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
if (storage->frame.current_rt && state.used_screen_texture) {
//copy screen texture
- if (storage->frame.current_rt && storage->frame.current_rt->multisample_active) {
+ if (storage->frame.current_rt->multisample_active) {
// Resolve framebuffer to front buffer before copying
#ifdef GLES_OVER_GL
@@ -2931,14 +3002,16 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
#elif IPHONE_ENABLED
+
glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo);
glResolveMultisampleFramebufferAPPLE();
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-#else
- // In GLES2 Blit is not available, so just copy color texture manually
+#elif ANDROID_ENABLED
+
+ // In GLES2 AndroidBlit is not available, so just copy color texture manually
_copy_texture_to_front_buffer(storage->frame.current_rt->multisample_color);
#endif
}
@@ -2972,8 +3045,17 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-#else
- // In GLES2 Blit is not available, so just copy color texture manually
+#elif IPHONE_ENABLED
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ glResolveMultisampleFramebufferAPPLE();
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+#elif ANDROID_ENABLED
+
+ // In GLES2 Android Blit is not available, so just copy color texture manually
_copy_texture_to_front_buffer(storage->frame.current_rt->multisample_color);
#endif
}
diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h
index d5a691d0b9..c95385eb24 100644
--- a/drivers/gles2/rasterizer_scene_gles2.h
+++ b/drivers/gles2/rasterizer_scene_gles2.h
@@ -354,6 +354,8 @@ public:
float bg_energy;
float sky_ambient;
+ int camera_feed_id;
+
Color ambient_color;
float ambient_energy;
float ambient_sky_contribution;
@@ -381,6 +383,7 @@ public:
sky_custom_fov(0.0),
bg_energy(1.0),
sky_ambient(0),
+ camera_feed_id(0),
ambient_energy(1.0),
ambient_sky_contribution(0.0),
canvas_max_layer(0),
@@ -413,6 +416,7 @@ public:
virtual void environment_set_bg_energy(RID p_env, float p_energy);
virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer);
virtual void environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy = 1.0, float p_sky_contribution = 0.0);
+ virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id);
virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality);
virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality);
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index c610f31bc1..b08202ae45 100644
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
@@ -91,7 +91,7 @@ GLuint RasterizerStorageGLES2::system_fbo = 0;
//void *glRenderbufferStorageMultisampleAPPLE;
//void *glResolveMultisampleFramebufferAPPLE;
#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleAPPLE
-#else
+#elif ANDROID_ENABLED
#include <GLES2/gl2ext.h>
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
@@ -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
@@ -968,6 +968,15 @@ uint32_t RasterizerStorageGLES2::texture_get_texid(RID p_texture) const {
return texture->tex_id;
}
+void RasterizerStorageGLES2::texture_bind(RID p_texture, uint32_t p_texture_no) {
+ Texture *texture = texture_owner.getornull(p_texture);
+
+ ERR_FAIL_COND(!texture);
+
+ glActiveTexture(GL_TEXTURE0 + p_texture_no);
+ glBindTexture(texture->target, texture->tex_id);
+}
+
uint32_t RasterizerStorageGLES2::texture_get_width(RID p_texture) const {
Texture *texture = texture_owner.getornull(p_texture);
@@ -2418,6 +2427,18 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
}
surface->data = array;
surface->index_data = p_index_array;
+#else
+ // Even on non-tools builds, a copy of the surface->data is needed in certain circumstances.
+ // Rigged meshes using the USE_SKELETON_SOFTWARE path need to read bone data
+ // from surface->data.
+
+ // if USE_SKELETON_SOFTWARE is active
+ if (!config.float_texture_supported) {
+ // if this geometry is used specifically for skinning
+ if (p_format & (VS::ARRAY_FORMAT_BONES | VS::ARRAY_FORMAT_WEIGHTS))
+ surface->data = array;
+ }
+ // An alternative is to always make a copy of surface->data.
#endif
surface->total_data_size += surface->array_byte_size + surface->index_array_byte_size;
@@ -4505,9 +4526,7 @@ void RasterizerStorageGLES2::instance_add_dependency(RID p_base, RasterizerScene
ERR_FAIL_COND(!inst);
} break;
default: {
- if (!inst) {
- ERR_FAIL();
- }
+ ERR_FAIL();
}
}
@@ -4552,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);
}
@@ -4688,6 +4702,7 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
/* BACK FBO */
/* For MSAA */
+#ifndef JAVASCRIPT_ENABLED
if (rt->msaa != VS::VIEWPORT_MSAA_DISABLED && config.multisample_supported) {
rt->multisample_active = true;
@@ -4719,7 +4734,7 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, color_internal_format, rt->width, rt->height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rt->multisample_color);
-#else
+#elif ANDROID_ENABLED
// Render to a texture in android
glGenTextures(1, &rt->multisample_color);
glBindTexture(GL_TEXTURE_2D, rt->multisample_color);
@@ -4743,7 +4758,9 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
glBindRenderbuffer(GL_RENDERBUFFER, 0);
- } else {
+ } else
+#endif
+ {
rt->multisample_active = false;
}
@@ -5602,11 +5619,11 @@ void RasterizerStorageGLES2::initialize() {
//Manually load extensions for android and ios
#ifdef IPHONE_ENABLED
-
+ // appears that IPhone doesn't need to dlopen TODO: test this rigorously before removing
//void *gles2_lib = dlopen(NULL, RTLD_LAZY);
//glRenderbufferStorageMultisampleAPPLE = dlsym(gles2_lib, "glRenderbufferStorageMultisampleAPPLE");
//glResolveMultisampleFramebufferAPPLE = dlsym(gles2_lib, "glResolveMultisampleFramebufferAPPLE");
-#else
+#elif ANDROID_ENABLED
void *gles2_lib = dlopen("libGLESv2.so", RTLD_LAZY);
glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glRenderbufferStorageMultisampleEXT");
diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h
index af57aa3d9b..d139697b86 100644
--- a/drivers/gles2/rasterizer_storage_gles2.h
+++ b/drivers/gles2/rasterizer_storage_gles2.h
@@ -350,6 +350,7 @@ public:
virtual uint32_t texture_get_height(RID p_texture) const;
virtual uint32_t texture_get_depth(RID p_texture) const;
virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth);
+ virtual void texture_bind(RID p_texture, uint32_t p_texture_no);
virtual void texture_set_path(RID p_texture, const String &p_path);
virtual String texture_get_path(RID p_texture) const;
diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp
index 9778d39a21..b48b93944c 100644
--- a/drivers/gles2/shader_compiler_gles2.cpp
+++ b/drivers/gles2/shader_compiler_gles2.cpp
@@ -361,6 +361,21 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
fragment_global += final_code;
}
+ // constants
+
+ for (Map<StringName, SL::ShaderNode::Constant>::Element *E = snode->constants.front(); E; E = E->next()) {
+ String gcode;
+ gcode += "const ";
+ gcode += _prestr(E->get().precision);
+ gcode += _typestr(E->get().type);
+ gcode += " " + _mkid(E->key());
+ gcode += "=";
+ gcode += _dump_node_code(E->get().initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ gcode += ";\n";
+ vertex_global += gcode;
+ fragment_global += gcode;
+ }
+
// functions
Map<StringName, String> function_code;
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/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h
index ebea40e10e..2456a83d35 100644
--- a/drivers/gles2/shader_gles2.h
+++ b/drivers/gles2/shader_gles2.h
@@ -1,4 +1,4 @@
-/*************************************************************************/
+/*************************************************************************/
/* shader_gles2.h */
/*************************************************************************/
/* This file is part of: */
diff --git a/drivers/gles2/shaders/copy.glsl b/drivers/gles2/shaders/copy.glsl
index 931b3f3708..195db7c45f 100644
--- a/drivers/gles2/shaders/copy.glsl
+++ b/drivers/gles2/shaders/copy.glsl
@@ -28,8 +28,15 @@ varying vec2 uv_interp;
#endif
varying vec2 uv2_interp;
+// These definitions are here because the shader-wrapper builder does
+// not understand `#elif defined()`
+#ifdef USE_DISPLAY_TRANSFORM
+#endif
+
#ifdef USE_COPY_SECTION
uniform highp vec4 copy_section;
+#elif defined(USE_DISPLAY_TRANSFORM)
+uniform highp mat4 display_transform;
#endif
void main() {
@@ -48,6 +55,8 @@ void main() {
#ifdef USE_COPY_SECTION
uv_interp = copy_section.xy + uv_interp * copy_section.zw;
gl_Position.xy = (copy_section.xy + (gl_Position.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0;
+#elif defined(USE_DISPLAY_TRANSFORM)
+ uv_interp = (display_transform * vec4(uv_in, 1.0, 1.0)).xy;
#endif
}
@@ -88,6 +97,10 @@ uniform samplerCube source_cube; // texunit:0
uniform sampler2D source; // texunit:0
#endif
+#ifdef SEP_CBCR_TEXTURE
+uniform sampler2D CbCr; //texunit:1
+#endif
+
varying vec2 uv2_interp;
#ifdef USE_MULTIPLIER
@@ -145,10 +158,26 @@ void main() {
#elif defined(USE_CUBEMAP)
vec4 color = textureCube(source_cube, normalize(cube_interp));
+#elif defined(SEP_CBCR_TEXTURE)
+ vec4 color;
+ color.r = texture2D(source, uv_interp).r;
+ color.gb = texture2D(CbCr, uv_interp).rg - vec2(0.5, 0.5);
+ color.a = 1.0;
#else
vec4 color = texture2D(source, uv_interp);
#endif
+#ifdef YCBCR_TO_RGB
+ // YCbCr -> RGB conversion
+
+ // Using BT.601, which is the standard for SDTV is provided as a reference
+ color.rgb = mat3(
+ vec3(1.00000, 1.00000, 1.00000),
+ vec3(0.00000, -0.34413, 1.77200),
+ vec3(1.40200, -0.71414, 0.00000)) *
+ color.rgb;
+#endif
+
#ifdef USE_NO_ALPHA
color.a = 1.0;
#endif
diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl
index 2aef913ae8..ca222362e7 100644
--- a/drivers/gles2/shaders/scene.glsl
+++ b/drivers/gles2/shaders/scene.glsl
@@ -262,7 +262,7 @@ void light_compute(
#endif
SRGB_APPROX(specular_brdf_NL)
- specular_interp += specular_brdf_NL * light_color * attenuation;
+ specular_interp += specular_brdf_NL * light_color * attenuation * (1.0 / M_PI);
}
}
@@ -1641,18 +1641,30 @@ FRAGMENT_SHADER_CODE
#endif // defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2)
- // scales the specular reflections, needs to be be computed before lighting happens,
- // but after environment and reflection probes are added
- //TODO: this curve is not really designed for gammaspace, should be adjusted
- const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
- const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
- vec4 r = roughness * c0 + c1;
- float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0);
- float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
- vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
+ // environment BRDF approximation
- vec3 f0 = F0(metallic, specular, albedo);
- specular_light *= env.x * f0 + env.y;
+ {
+
+#if defined(DIFFUSE_TOON)
+ //simplify for toon, as
+ specular_light *= specular * metallic * albedo * 2.0;
+#else
+
+ // scales the specular reflections, needs to be be computed before lighting happens,
+ // but after environment and reflection probes are added
+ //TODO: this curve is not really designed for gammaspace, should be adjusted
+ const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
+ const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
+ vec4 r = roughness * c0 + c1;
+ float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0);
+ float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
+ vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
+
+ vec3 f0 = F0(metallic, specular, albedo);
+ specular_light *= env.x * f0 + env.y;
+
+#endif
+ }
#ifdef USE_LIGHTMAP
//ambient light will come entirely from lightmap is lightmap is used
@@ -2048,6 +2060,17 @@ FRAGMENT_SHADER_CODE
specular_light += specular_interp * specular_blob_intensity * light_att;
diffuse_light += diffuse_interp * albedo * light_att;
+ // Same as above, needed for VERTEX_LIGHTING or else lights are too bright
+ const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
+ const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
+ vec4 r = roughness * c0 + c1;
+ float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0);
+ float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
+ vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
+
+ vec3 f0 = F0(metallic, specular, albedo);
+ specular_light *= env.x * f0 + env.y;
+
#else
//fragment lighting
light_compute(
@@ -2115,16 +2138,6 @@ FRAGMENT_SHADER_CODE
diffuse_light *= 1.0 - metallic;
ambient_light *= 1.0 - metallic;
- // environment BRDF approximation
-
- {
-
-#if defined(DIFFUSE_TOON)
- //simplify for toon, as
- specular_light *= specular * metallic * albedo * 2.0;
-#endif
- }
-
gl_FragColor = vec4(ambient_light + diffuse_light + specular_light, alpha);
//add emission if in base pass
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_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index bdffb1ecdc..ea15a278d6 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -273,7 +273,7 @@ void RasterizerGLES3::clear_render_target(const Color &p_color) {
storage->frame.clear_request_color = p_color;
}
-void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale) {
+void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) {
if (p_image.is_null() || p_image->empty())
return;
@@ -296,7 +296,7 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
canvas->canvas_begin();
RID texture = storage->texture_create();
- storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER);
+ storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_use_filter ? VS::TEXTURE_FLAG_FILTER : 0);
storage->texture_set_data(texture, p_image);
Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height());
diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h
index ad0d004c9d..8fa208a1aa 100644
--- a/drivers/gles3/rasterizer_gles3.h
+++ b/drivers/gles3/rasterizer_gles3.h
@@ -51,7 +51,7 @@ public:
virtual RasterizerCanvas *get_canvas();
virtual RasterizerScene *get_scene();
- virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale);
+ virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true);
virtual void initialize();
virtual void begin_frame(double frame_step);
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 4552fddfe8..91c0693538 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -34,6 +34,7 @@
#include "core/os/os.h"
#include "core/project_settings.h"
#include "rasterizer_canvas_gles3.h"
+#include "servers/camera/camera_feed.h"
#include "servers/visual/visual_server_raster.h"
#ifndef GLES_OVER_GL
@@ -830,6 +831,12 @@ void RasterizerSceneGLES3::environment_set_ambient_light(RID p_env, const Color
env->ambient_energy = p_energy;
env->ambient_sky_contribution = p_sky_contribution;
}
+void RasterizerSceneGLES3::environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+
+ env->camera_feed_id = p_camera_feed_id;
+}
void RasterizerSceneGLES3::environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality) {
@@ -2419,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;
}
/*
@@ -3304,7 +3311,7 @@ void RasterizerSceneGLES3::_prepare_depth_texture() {
void RasterizerSceneGLES3::_bind_depth_texture() {
if (!state.bound_depth_texture) {
- ERR_FAIL_COND(!state.prepared_depth_texture)
+ ERR_FAIL_COND(!state.prepared_depth_texture);
//bind depth for read
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 8);
glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth);
@@ -4290,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);
@@ -4342,6 +4349,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
Color clear_color(0, 0, 0, 0);
RasterizerStorageGLES3::Sky *sky = NULL;
+ Ref<CameraFeed> feed;
GLuint env_radiance_tex = 0;
if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
@@ -4376,6 +4384,9 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
clear_color = env->bg_color.to_linear();
storage->frame.clear_request = false;
+ } else if (env->bg_mode == VS::ENV_BG_CAMERA_FEED) {
+ feed = CameraServer::get_singleton()->get_feed_by_id(env->camera_feed_id);
+ storage->frame.clear_request = false;
} else {
storage->frame.clear_request = false;
}
@@ -4426,6 +4437,63 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
break;
+ case VS::ENV_BG_CAMERA_FEED:
+ if (feed.is_valid() && (feed->get_base_width() > 0) && (feed->get_base_height() > 0)) {
+ // copy our camera feed to our background
+
+ glDisable(GL_BLEND);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+
+ storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_DISPLAY_TRANSFORM, true);
+ storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true);
+ storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, true);
+
+ if (feed->get_datatype() == CameraFeed::FEED_RGB) {
+ 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);
+
+ 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) {
+ RID camera_Y = feed->get_texture(CameraServer::FEED_Y_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);
+
+ storage->shaders.copy.set_conditional(CopyShaderGLES3::SEP_CBCR_TEXTURE, true);
+ storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, true);
+ };
+
+ storage->shaders.copy.bind();
+ storage->shaders.copy.set_uniform(CopyShaderGLES3::DISPLAY_TRANSFORM, feed->get_transform());
+
+ _copy_screen(true, true);
+
+ //turn off everything used
+ storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_DISPLAY_TRANSFORM, false);
+ storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false);
+ storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, false);
+ storage->shaders.copy.set_conditional(CopyShaderGLES3::SEP_CBCR_TEXTURE, false);
+ storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, false);
+
+ //restore
+ glEnable(GL_BLEND);
+ glDepthMask(GL_TRUE);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ } else {
+ // don't have a feed, just show greenscreen :)
+ clear_color = Color(0.0, 1.0, 0.0, 1.0);
+ }
+ break;
default: {
}
}
@@ -4552,8 +4620,8 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
}
_post_process(env, p_cam_projection);
-
- if (false && shadow_atlas) {
+ // Needed only for debugging
+ /* if (shadow_atlas && storage->frame.current_rt) {
//_copy_texture_to_front_buffer(shadow_atlas->depth);
storage->canvas->canvas_begin();
@@ -4563,7 +4631,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1));
}
- if (false && storage->frame.current_rt) {
+ if (storage->frame.current_rt) {
//_copy_texture_to_front_buffer(shadow_atlas->depth);
storage->canvas->canvas_begin();
@@ -4573,7 +4641,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 16, storage->frame.current_rt->height / 16), Rect2(0, 0, 1, 1));
}
- if (false && reflection_atlas && storage->frame.current_rt) {
+ if (reflection_atlas && storage->frame.current_rt) {
//_copy_texture_to_front_buffer(shadow_atlas->depth);
storage->canvas->canvas_begin();
@@ -4582,7 +4650,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1));
}
- if (false && directional_shadow.fbo) {
+ if (directional_shadow.fbo) {
//_copy_texture_to_front_buffer(shadow_atlas->depth);
storage->canvas->canvas_begin();
@@ -4592,7 +4660,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1));
}
- if (false && env_radiance_tex) {
+ if ( env_radiance_tex) {
//_copy_texture_to_front_buffer(shadow_atlas->depth);
storage->canvas->canvas_begin();
@@ -4603,8 +4671,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- }
-
+ }*/
//disable all stuff
}
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index 59e23e5ac9..910f90edc2 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -376,6 +376,8 @@ public:
float bg_energy;
float sky_ambient;
+ int camera_feed_id;
+
Color ambient_color;
float ambient_energy;
float ambient_sky_contribution;
@@ -461,6 +463,7 @@ public:
sky_custom_fov(0.0),
bg_energy(1.0),
sky_ambient(0),
+ camera_feed_id(0),
ambient_energy(1.0),
ambient_sky_contribution(0.0),
canvas_max_layer(0),
@@ -542,6 +545,7 @@ public:
virtual void environment_set_bg_energy(RID p_env, float p_energy);
virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer);
virtual void environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy = 1.0, float p_sky_contribution = 0.0);
+ virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id);
virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality);
virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality);
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index 561a3cae2d..b280898188 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
@@ -1437,6 +1437,15 @@ uint32_t RasterizerStorageGLES3::texture_get_texid(RID p_texture) const {
return texture->tex_id;
}
+void RasterizerStorageGLES3::texture_bind(RID p_texture, uint32_t p_texture_no) {
+
+ Texture *texture = texture_owner.getornull(p_texture);
+
+ ERR_FAIL_COND(!texture);
+
+ glActiveTexture(GL_TEXTURE0 + p_texture_no);
+ glBindTexture(texture->target, texture->tex_id);
+}
uint32_t RasterizerStorageGLES3::texture_get_width(RID p_texture) const {
Texture *texture = texture_owner.get(p_texture);
@@ -3501,7 +3510,7 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
if (p_vertex_count < (1 << 16)) {
//read 16 bit indices
const uint16_t *src_idx = (const uint16_t *)ir.ptr();
- for (int i = 0; i < index_count; i += 6) {
+ for (int i = 0; i + 5 < index_count; i += 6) {
wr[i + 0] = src_idx[i / 2];
wr[i + 1] = src_idx[i / 2 + 1];
@@ -3515,7 +3524,7 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
//read 16 bit indices
const uint32_t *src_idx = (const uint32_t *)ir.ptr();
- for (int i = 0; i < index_count; i += 6) {
+ for (int i = 0; i + 5 < index_count; i += 6) {
wr[i + 0] = src_idx[i / 2];
wr[i + 1] = src_idx[i / 2 + 1];
@@ -3531,7 +3540,7 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
index_count = p_vertex_count * 2;
wf_indices.resize(index_count);
PoolVector<uint32_t>::Write wr = wf_indices.write();
- for (int i = 0; i < index_count; i += 6) {
+ for (int i = 0; i + 5 < index_count; i += 6) {
wr[i + 0] = i / 2;
wr[i + 1] = i / 2 + 1;
@@ -4635,7 +4644,6 @@ Transform2D RasterizerStorageGLES3::multimesh_instance_get_transform_2d(RID p_mu
}
Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh, int p_index) const {
-
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
ERR_FAIL_COND_V(!multimesh, Color());
ERR_FAIL_INDEX_V(p_index, multimesh->size, Color());
@@ -6065,10 +6073,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;
}
@@ -6466,7 +6471,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;
@@ -6704,9 +6708,7 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base, RasterizerScene
ERR_FAIL_COND(!inst);
} break;
default: {
- if (!inst) {
- ERR_FAIL();
- }
+ ERR_FAIL();
}
}
@@ -6751,15 +6753,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 3d86558407..0a7e47e304 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -358,6 +358,7 @@ public:
virtual uint32_t texture_get_height(RID p_texture) const;
virtual uint32_t texture_get_depth(RID p_texture) const;
virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth);
+ virtual void texture_bind(RID p_texture, uint32_t p_texture_no);
virtual void texture_set_path(RID p_texture, const String &p_path);
virtual String texture_get_path(RID p_texture) const;
@@ -815,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_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp
index e8417900ea..b0f0a71d56 100644
--- a/drivers/gles3/shader_compiler_gles3.cpp
+++ b/drivers/gles3/shader_compiler_gles3.cpp
@@ -472,6 +472,19 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
r_gen_code.fragment_global += interp_mode + "in " + vcode;
}
+ for (Map<StringName, SL::ShaderNode::Constant>::Element *E = pnode->constants.front(); E; E = E->next()) {
+ String gcode;
+ gcode += "const ";
+ gcode += _prestr(E->get().precision);
+ gcode += _typestr(E->get().type);
+ gcode += " " + _mkid(E->key());
+ gcode += "=";
+ gcode += _dump_node_code(E->get().initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ gcode += ";\n";
+ r_gen_code.vertex_global += gcode;
+ r_gen_code.fragment_global += gcode;
+ }
+
Map<StringName, String> function_code;
//code for functions
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/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl
index e1a0813efc..232b9ce7c0 100644
--- a/drivers/gles3/shaders/copy.glsl
+++ b/drivers/gles3/shaders/copy.glsl
@@ -18,10 +18,19 @@ out vec2 uv_interp;
out vec2 uv2_interp;
+// These definitions are here because the shader-wrapper builder does
+// not understand `#elif defined()`
+#ifdef USE_DISPLAY_TRANSFORM
+#endif
+
#ifdef USE_COPY_SECTION
uniform vec4 copy_section;
+#elif defined(USE_DISPLAY_TRANSFORM)
+
+uniform highp mat4 display_transform;
+
#endif
void main() {
@@ -44,6 +53,9 @@ void main() {
uv_interp = copy_section.xy + uv_interp * copy_section.zw;
gl_Position.xy = (copy_section.xy + (gl_Position.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0;
+#elif defined(USE_DISPLAY_TRANSFORM)
+
+ uv_interp = (display_transform * vec4(uv_in, 1.0, 1.0)).xy;
#endif
}
@@ -73,6 +85,8 @@ uniform highp vec4 asym_proj;
#endif
#ifdef USE_TEXTURE2DARRAY
#endif
+#ifdef YCBCR_TO_SRGB
+#endif
#ifdef USE_CUBEMAP
uniform samplerCube source_cube; //texunit:0
@@ -84,6 +98,10 @@ uniform sampler2DArray source_2d_array; //texunit:0
uniform sampler2D source; //texunit:0
#endif
+#ifdef SEP_CBCR_TEXTURE
+uniform sampler2D CbCr; //texunit:1
+#endif
+
/* clang-format on */
#if defined(USE_TEXTURE3D) || defined(USE_TEXTURE2DARRAY)
@@ -166,14 +184,30 @@ void main() {
vec4 color = textureLod(source_3d, vec3(uv_interp, layer), 0.0);
#elif defined(USE_TEXTURE2DARRAY)
vec4 color = textureLod(source_2d_array, vec3(uv_interp, layer), 0.0);
+#elif defined(SEP_CBCR_TEXTURE)
+ vec4 color;
+ color.r = textureLod(source, uv_interp, 0.0).r;
+ color.gb = textureLod(CbCr, uv_interp, 0.0).rg - vec2(0.5, 0.5);
+ color.a = 1.0;
#else
vec4 color = textureLod(source, uv_interp, 0.0);
#endif
#ifdef LINEAR_TO_SRGB
- //regular Linear -> SRGB conversion
+ // regular Linear -> SRGB conversion
vec3 a = vec3(0.055);
color.rgb = mix((vec3(1.0) + a) * pow(color.rgb, vec3(1.0 / 2.4)) - a, 12.92 * color.rgb, lessThan(color.rgb, vec3(0.0031308)));
+
+#elif defined(YCBCR_TO_SRGB)
+
+ // YCbCr -> SRGB conversion
+ // Using BT.709 which is the standard for HDTV
+ color.rgb = mat3(
+ vec3(1.00000, 1.00000, 1.00000),
+ vec3(0.00000, -0.18732, 1.85560),
+ vec3(1.57481, -0.46813, 0.00000)) *
+ color.rgb;
+
#endif
#ifdef SRGB_TO_LINEAR
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/png/resource_saver_png.h b/drivers/png/resource_saver_png.h
index 584ccd4908..9267f2d678 100644
--- a/drivers/png/resource_saver_png.h
+++ b/drivers/png/resource_saver_png.h
@@ -35,7 +35,6 @@
#include "core/io/resource_saver.h"
class ResourceSaverPNG : public ResourceFormatSaver {
- GDCLASS(ResourceSaverPNG, ResourceFormatSaver)
public:
static Error save_image(const String &p_path, const Ref<Image> &p_img);
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 37abccbe27..f8e771aea0 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;
}
@@ -306,7 +362,7 @@ Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) {
sockaddr_storage addr;
size_t addr_size = _set_addr_storage(&addr, p_addr, p_port, _ip_type);
- if (::bind(_sock, (struct sockaddr *)&addr, addr_size) == SOCK_EMPTY) {
+ if (::bind(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
close();
ERR_FAIL_V(ERR_UNAVAILABLE);
}
@@ -317,7 +373,7 @@ Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) {
Error NetSocketPosix::listen(int p_max_pending) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
- if (::listen(_sock, p_max_pending) == SOCK_EMPTY) {
+ if (::listen(_sock, p_max_pending) != 0) {
close();
ERR_FAIL_V(FAILED);
@@ -334,7 +390,7 @@ Error NetSocketPosix::connect_to_host(IP_Address p_host, uint16_t p_port) {
struct sockaddr_storage addr;
size_t addr_size = _set_addr_storage(&addr, p_host, p_port, _ip_type);
- if (::connect(_sock, (struct sockaddr *)&addr, addr_size) == SOCK_EMPTY) {
+ if (::connect(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
NetError err = _get_socket_error();
@@ -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_multi_address, String p_if_name) {
+ return _change_multicast_group(p_multi_address, p_if_name, true);
+}
+
+Error NetSocketPosix::leave_multicast_group(const IP_Address &p_multi_address, String p_if_name) {
+ return _change_multicast_group(p_multi_address, 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();
diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp
index c97849ef07..fea38ee95d 100644
--- a/drivers/wasapi/audio_driver_wasapi.cpp
+++ b/drivers/wasapi/audio_driver_wasapi.cpp
@@ -167,13 +167,13 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
for (ULONG i = 0; i < count && !found; i++) {
- IMMDevice *device = NULL;
+ IMMDevice *tmp_device = NULL;
- hr = devices->Item(i, &device);
+ hr = devices->Item(i, &tmp_device);
ERR_BREAK(hr != S_OK);
IPropertyStore *props = NULL;
- hr = device->OpenPropertyStore(STGM_READ, &props);
+ hr = tmp_device->OpenPropertyStore(STGM_READ, &props);
ERR_BREAK(hr != S_OK);
PROPVARIANT propvar;
@@ -183,7 +183,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
ERR_BREAK(hr != S_OK);
if (p_device->device_name == String(propvar.pwszVal)) {
- hr = device->GetId(&strId);
+ hr = tmp_device->GetId(&strId);
ERR_BREAK(hr != S_OK);
found = true;
@@ -191,7 +191,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
PropVariantClear(&propvar);
props->Release();
- device->Release();
+ tmp_device->Release();
}
if (found) {
@@ -289,7 +289,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
}
DWORD streamflags = 0;
- if (mix_rate != pwfex->nSamplesPerSec) {
+ if ((DWORD)mix_rate != pwfex->nSamplesPerSec) {
streamflags |= AUDCLNT_STREAMFLAGS_RATEADJUST;
pwfex->nSamplesPerSec = mix_rate;
pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nChannels * (pwfex->wBitsPerSample / 8);
@@ -571,7 +571,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
if (ad->audio_output.active) {
ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw());
} else {
- for (unsigned int i = 0; i < ad->samples_in.size(); i++) {
+ for (int i = 0; i < ad->samples_in.size(); i++) {
ad->samples_in.write[i] = 0;
}
}
@@ -699,7 +699,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
ERR_BREAK(hr != S_OK);
// fixme: Only works for floating point atm
- for (int j = 0; j < num_frames_available; j++) {
+ for (UINT32 j = 0; j < num_frames_available; j++) {
int32_t l, r;
if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index 31360d319f..646e744248 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -93,7 +93,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
// a file using the wrong case (which *works* on Windows, but won't on other
// platforms).
if (p_mode_flags == READ) {
- WIN32_FIND_DATAW d = { 0 };
+ WIN32_FIND_DATAW d;
HANDLE f = FindFirstFileW(path.c_str(), &d);
if (f) {
String fname = d.cFileName;
@@ -302,7 +302,7 @@ void FileAccessWindows::store_buffer(const uint8_t *p_src, int p_length) {
}
prev_op = WRITE;
}
- ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != p_length);
+ ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != (size_t)p_length);
}
bool FileAccessWindows::file_exists(const String &p_name) {