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_canvas_gles2.cpp2
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp4
-rw-r--r--drivers/gles2/rasterizer_gles2.h2
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp152
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.h16
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp34
-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.h2
-rw-r--r--drivers/gles2/shaders/canvas.glsl5
-rw-r--r--drivers/gles2/shaders/copy.glsl29
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp4
-rw-r--r--drivers/gles3/rasterizer_gles3.h2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp85
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h4
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp47
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h1
-rw-r--r--drivers/gles3/shader_compiler_gles3.cpp13
-rw-r--r--drivers/gles3/shaders/canvas.glsl5
-rw-r--r--drivers/gles3/shaders/copy.glsl36
-rw-r--r--drivers/gles3/shaders/ssao.glsl6
-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/net_socket_posix.cpp6
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp16
-rw-r--r--drivers/windows/file_access_windows.cpp8
32 files changed, 715 insertions, 540 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_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp
index ee722e9d6c..b82186162d 100644
--- a/drivers/gles2/rasterizer_canvas_gles2.cpp
+++ b/drivers/gles2/rasterizer_canvas_gles2.cpp
@@ -1081,6 +1081,8 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
} else {
glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 3, buffer + color_ofs);
}
+ } else {
+ glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, 1.0, 1.0, 1.0, 1.0);
}
if (multi_mesh->custom_data_floats) {
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 268b0f1c90..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);
@@ -1027,6 +1035,7 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G
e->light_index = RenderList::MAX_LIGHTS;
e->use_accum_ptr = &e->use_accum;
e->instancing = (e->instance->base_type == VS::INSTANCE_MULTIMESH) ? 1 : 0;
+ e->front_facing = false;
if (e->geometry->last_pass != render_pass) {
e->geometry->last_pass = render_pass;
@@ -1046,6 +1055,10 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G
e->material_index = e->material->index;
+ if (mirror) {
+ e->front_facing = true;
+ }
+
e->refprobe_0_index = RenderList::MAX_REFLECTION_PROBES; //refprobe disabled by default
e->refprobe_1_index = RenderList::MAX_REFLECTION_PROBES; //refprobe disabled by default
@@ -1257,7 +1270,29 @@ static const GLenum gl_primitive[] = {
GL_TRIANGLE_FAN
};
-bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, bool p_alpha_pass, Size2i p_skeleton_tex_size) {
+void RasterizerSceneGLES2::_set_cull(bool p_front, bool p_disabled, bool p_reverse_cull) {
+
+ bool front = p_front;
+ if (p_reverse_cull)
+ front = !front;
+
+ if (p_disabled != state.cull_disabled) {
+ if (p_disabled)
+ glDisable(GL_CULL_FACE);
+ else
+ glEnable(GL_CULL_FACE);
+
+ state.cull_disabled = p_disabled;
+ }
+
+ if (front != state.cull_front) {
+
+ glCullFace(front ? GL_FRONT : GL_BACK);
+ state.cull_front = front;
+ }
+}
+
+bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_material, bool p_alpha_pass, Size2i p_skeleton_tex_size) {
// material parameters
@@ -1295,21 +1330,6 @@ bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m
} break;
}
- switch (p_material->shader->spatial.cull_mode) {
- case RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_DISABLED: {
- glDisable(GL_CULL_FACE);
- } break;
-
- case RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_BACK: {
- glEnable(GL_CULL_FACE);
- glCullFace(p_reverse_cull ? GL_FRONT : GL_BACK);
- } break;
- case RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_FRONT: {
- glEnable(GL_CULL_FACE);
- glCullFace(p_reverse_cull ? GL_BACK : GL_FRONT);
- } break;
- }
-
int tc = p_material->textures.size();
const Pair<StringName, RID> *textures = p_material->textures.ptr();
@@ -2202,6 +2222,11 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
int prev_blend_mode = -2; //will always catch the first go
+ state.cull_front = false;
+ state.cull_disabled = false;
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+
if (p_alpha_pass) {
glEnable(GL_BLEND);
} else {
@@ -2244,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;
@@ -2264,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;
}
@@ -2441,12 +2466,14 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
if (rebind || material != prev_material) {
storage->info.render.material_switch_count++;
- shader_rebind = _setup_material(material, p_reverse_cull, p_alpha_pass, Size2i(skeleton ? skeleton->size * 3 : 0, 0));
+ shader_rebind = _setup_material(material, p_alpha_pass, Size2i(skeleton ? skeleton->size * 3 : 0, 0));
if (shader_rebind) {
storage->info.render.shader_rebind_count++;
}
}
+ _set_cull(e->front_facing, material->shader->spatial.cull_mode == RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_DISABLED, p_reverse_cull);
+
if (i == 0 || shader_rebind) { //first time must rebind
if (p_shadow) {
@@ -2695,7 +2722,8 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
Environment *env = NULL;
int viewport_width, viewport_height;
- int viewport_x, viewport_y;
+ int viewport_x = 0;
+ int viewport_y = 0;
bool probe_interior = false;
bool reverse_cull = false;
@@ -2823,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);
@@ -2835,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;
}
@@ -2871,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;
@@ -2899,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
@@ -2911,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
}
@@ -2952,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 bd1a61688c..c95385eb24 100644
--- a/drivers/gles2/rasterizer_scene_gles2.h
+++ b/drivers/gles2/rasterizer_scene_gles2.h
@@ -198,14 +198,15 @@ public:
int directional_light_count;
int reflection_probe_count;
- bool cull_front;
- bool cull_disabled;
bool used_sss;
bool using_contact_shadows;
VS::ViewportDebugDraw debug_draw;
*/
+ bool cull_front;
+ bool cull_disabled;
+
bool used_screen_texture;
bool shadow_is_dual_parabolloid;
float dual_parbolloid_direction;
@@ -353,6 +354,8 @@ public:
float bg_energy;
float sky_ambient;
+ int camera_feed_id;
+
Color ambient_color;
float ambient_energy;
float ambient_sky_contribution;
@@ -380,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),
@@ -412,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);
@@ -503,8 +508,7 @@ public:
enum {
MAX_LIGHTS = 255,
MAX_REFLECTION_PROBES = 255,
- DEFAULT_MAX_ELEMENTS = 65536,
- SORT_KEY_PRIORITY_SHIFT = 56
+ DEFAULT_MAX_ELEMENTS = 65536
};
int max_elements;
@@ -518,6 +522,7 @@ public:
bool use_accum; //is this an add pass for multipass
bool *use_accum_ptr;
+ bool front_facing;
union {
//TODO: should be endian swapped on big endian
@@ -685,7 +690,8 @@ public:
void _draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy, const Basis &p_sky_orientation);
- _FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, bool p_alpha_pass, Size2i p_skeleton_tex_size = Size2i(0, 0));
+ _FORCE_INLINE_ void _set_cull(bool p_front, bool p_disabled, bool p_reverse_cull);
+ _FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES2::Material *p_material, bool p_alpha_pass, Size2i p_skeleton_tex_size = Size2i(0, 0));
_FORCE_INLINE_ void _setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton);
_FORCE_INLINE_ void _setup_light_type(LightInstance *p_light, ShadowAtlas *shadow_atlas);
_FORCE_INLINE_ void _setup_light(LightInstance *p_light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform);
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index 7a701d4956..9fe7e43b43 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;
@@ -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;
@@ -4681,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;
@@ -4712,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);
@@ -4736,7 +4758,9 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
glBindRenderbuffer(GL_RENDERBUFFER, 0);
- } else {
+ } else
+#endif
+ {
rt->multisample_active = false;
}
@@ -5595,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.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/canvas.glsl b/drivers/gles2/shaders/canvas.glsl
index 7dce784f52..0818942b0a 100644
--- a/drivers/gles2/shaders/canvas.glsl
+++ b/drivers/gles2/shaders/canvas.glsl
@@ -112,7 +112,12 @@ void main() {
#ifdef USE_INSTANCING
mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0)));
color *= instance_color;
+
+#ifdef USE_INSTANCE_CUSTOM
vec4 instance_custom = instance_custom_data;
+#else
+ vec4 instance_custom = vec4(0.0);
+#endif
#else
mat4 extra_matrix_instance = extra_matrix;
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/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 dbc6d87e0c..b3a1d32bf4 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) {
@@ -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);
@@ -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 558b1b4783..0840717d68 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -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;
@@ -3772,28 +3781,30 @@ PoolVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_m
Surface *surface = mesh->surfaces[p_surface];
- ERR_FAIL_COND_V(surface->index_array_len == 0, PoolVector<uint8_t>());
-
PoolVector<uint8_t> ret;
ret.resize(surface->index_array_byte_size);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_id);
+
+ if (surface->index_array_byte_size > 0) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_id);
#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__)
- {
- PoolVector<uint8_t>::Write w = ret.write();
- glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, surface->index_array_byte_size, w.ptr());
- }
+ {
+ PoolVector<uint8_t>::Write w = ret.write();
+ glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, surface->index_array_byte_size, w.ptr());
+ }
#else
- void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, surface->index_array_byte_size, GL_MAP_READ_BIT);
- ERR_FAIL_NULL_V(data, PoolVector<uint8_t>());
- {
- PoolVector<uint8_t>::Write w = ret.write();
- copymem(w.ptr(), data, surface->index_array_byte_size);
- }
- glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+ void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, surface->index_array_byte_size, GL_MAP_READ_BIT);
+ ERR_FAIL_NULL_V(data, PoolVector<uint8_t>());
+ {
+ PoolVector<uint8_t>::Write w = ret.write();
+ copymem(w.ptr(), data, surface->index_array_byte_size);
+ }
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
#endif
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
return ret;
}
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index 3d86558407..badb656e96 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;
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/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 0d1e7ee4a1..a46b31c92e 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -117,7 +117,12 @@ void main() {
#ifdef USE_INSTANCING
mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0)));
color *= instance_color;
+
+#ifdef USE_INSTANCE_CUSTOM
vec4 instance_custom = instance_custom_data;
+#else
+ vec4 instance_custom = vec4(0.0);
+#endif
#else
mat4 extra_matrix_instance = extra_matrix;
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/gles3/shaders/ssao.glsl b/drivers/gles3/shaders/ssao.glsl
index be44365169..d9cdc3fc1f 100644
--- a/drivers/gles3/shaders/ssao.glsl
+++ b/drivers/gles3/shaders/ssao.glsl
@@ -16,15 +16,15 @@ void main() {
#define TWO_PI 6.283185307179586476925286766559
#ifdef SSAO_QUALITY_HIGH
-#define NUM_SAMPLES (80)
+#define NUM_SAMPLES (16)
#endif
#ifdef SSAO_QUALITY_LOW
-#define NUM_SAMPLES (15)
+#define NUM_SAMPLES (8)
#endif
#if !defined(SSAO_QUALITY_LOW) && !defined(SSAO_QUALITY_HIGH)
-#define NUM_SAMPLES (40)
+#define NUM_SAMPLES (12)
#endif
// If using depth mip levels, the log of the maximum pixel offset before we need to switch to a lower
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/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp
index 8b523f9f8d..fcd1c3be4b 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_posix.cpp
@@ -306,7 +306,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 +317,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 +334,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();
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 c13300d09f..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) {
@@ -340,13 +340,11 @@ uint64_t FileAccessWindows::_get_modified_time(const String &p_file) {
}
uint32_t FileAccessWindows::_get_unix_permissions(const String &p_file) {
- ERR_PRINT("Windows does not support unix permissions");
return 0;
}
Error FileAccessWindows::_set_unix_permissions(const String &p_file, uint32_t p_permissions) {
- ERR_PRINT("Windows does not support unix permissions");
- return FAILED;
+ return ERR_UNAVAILABLE;
}
FileAccessWindows::FileAccessWindows() :