diff options
Diffstat (limited to 'scene')
-rw-r--r-- | scene/3d/gi_probe.cpp | 52 | ||||
-rw-r--r-- | scene/3d/gi_probe.h | 11 | ||||
-rw-r--r-- | scene/3d/light.cpp | 3 | ||||
-rw-r--r-- | scene/3d/light.h | 1 | ||||
-rw-r--r-- | scene/animation/animation_player.cpp | 19 | ||||
-rw-r--r-- | scene/animation/animation_player.h | 2 | ||||
-rw-r--r-- | scene/gui/scroll_container.cpp | 4 | ||||
-rw-r--r-- | scene/gui/text_edit.cpp | 17 | ||||
-rw-r--r-- | scene/gui/text_edit.h | 1 | ||||
-rw-r--r-- | scene/io/resource_format_image.cpp | 3 | ||||
-rw-r--r-- | scene/io/resource_format_image.h | 3 | ||||
-rw-r--r-- | scene/register_scene_types.cpp | 14 | ||||
-rw-r--r-- | scene/resources/audio_stream_sample.cpp | 557 | ||||
-rw-r--r-- | scene/resources/audio_stream_sample.h | 128 | ||||
-rw-r--r-- | scene/resources/scene_format_text.cpp | 13 | ||||
-rw-r--r-- | scene/resources/texture.cpp | 373 | ||||
-rw-r--r-- | scene/resources/texture.h | 81 |
17 files changed, 1247 insertions, 35 deletions
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index b29ae211de..4c33590568 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -64,6 +64,18 @@ float GIProbeData::get_energy() const{ } +void GIProbeData::set_propagation(float p_range) { + + VS::get_singleton()->gi_probe_set_propagation(probe,p_range); +} + +float GIProbeData::get_propagation() const{ + + return VS::get_singleton()->gi_probe_get_propagation(probe); + +} + + void GIProbeData::set_interior(bool p_enable) { VS::get_singleton()->gi_probe_set_interior(probe,p_enable); @@ -121,6 +133,9 @@ void GIProbeData::_bind_methods() { ClassDB::bind_method(_MD("set_energy","energy"),&GIProbeData::set_energy); ClassDB::bind_method(_MD("get_energy"),&GIProbeData::get_energy); + ClassDB::bind_method(_MD("set_propagation","propagation"),&GIProbeData::set_propagation); + ClassDB::bind_method(_MD("get_propagation"),&GIProbeData::get_propagation); + ClassDB::bind_method(_MD("set_interior","interior"),&GIProbeData::set_interior); ClassDB::bind_method(_MD("is_interior"),&GIProbeData::is_interior); @@ -134,6 +149,7 @@ void GIProbeData::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::POOL_INT_ARRAY,"dynamic_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_dynamic_data"),_SCS("get_dynamic_data")); ADD_PROPERTY(PropertyInfo(Variant::INT,"dynamic_range",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_dynamic_range"),_SCS("get_dynamic_range")); ADD_PROPERTY(PropertyInfo(Variant::REAL,"energy",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_energy"),_SCS("get_energy")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"propagation",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_propagation"),_SCS("get_propagation")); ADD_PROPERTY(PropertyInfo(Variant::BOOL,"interior",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_interior"),_SCS("is_interior")); ADD_PROPERTY(PropertyInfo(Variant::BOOL,"compress",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_compress"),_SCS("is_compressed")); @@ -214,6 +230,18 @@ float GIProbe::get_energy() const { return energy; } +void GIProbe::set_propagation(float p_propagation) { + + propagation=p_propagation; + if (probe_data.is_valid()) { + probe_data->set_propagation(propagation); + } +} +float GIProbe::get_propagation() const { + + return propagation; +} + void GIProbe::set_interior(bool p_enable) { interior=p_enable; @@ -906,7 +934,7 @@ GIProbe::Baker::MaterialCache GIProbe::_get_material_cache(Ref<Material> p_mater } -void GIProbe::_plot_mesh(const Transform& p_xform, Ref<Mesh>& p_mesh, Baker *p_baker) { +void GIProbe::_plot_mesh(const Transform& p_xform, Ref<Mesh>& p_mesh, Baker *p_baker, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material) { for(int i=0;i<p_mesh->get_surface_count();i++) { @@ -914,7 +942,16 @@ void GIProbe::_plot_mesh(const Transform& p_xform, Ref<Mesh>& p_mesh, Baker *p_b if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES) continue; //only triangles - Baker::MaterialCache material = _get_material_cache(p_mesh->surface_get_material(i),p_baker); + Ref<Material> src_material; + + if (p_override_material.is_valid()) { + src_material=p_override_material; + } else if (i<p_materials.size() && p_materials[i].is_valid()) { + src_material=p_materials[i]; + } else { + src_material=p_mesh->surface_get_material(i); + } + Baker::MaterialCache material = _get_material_cache(src_material,p_baker); Array a = p_mesh->surface_get_arrays(i); @@ -1009,6 +1046,10 @@ void GIProbe::_find_meshes(Node *p_at_node,Baker *p_baker){ Baker::PlotMesh pm; pm.local_xform=xf; pm.mesh=mesh; + for(int i=0;i<mesh->get_surface_count();i++) { + pm.instance_materials.push_back(mi->get_surface_material(i)); + } + pm.override_material=mi->get_material_override(); p_baker->mesh_list.push_back(pm); } @@ -1083,7 +1124,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug){ print_line("plotting mesh "+itos(pmc++)+"/"+itos(baker.mesh_list.size())); - _plot_mesh(E->get().local_xform,E->get().mesh,&baker); + _plot_mesh(E->get().local_xform,E->get().mesh,&baker,E->get().instance_materials,E->get().override_material); } _fixup_plot(0,0,0,0,0,&baker); @@ -1358,6 +1399,9 @@ void GIProbe::_bind_methods() { ClassDB::bind_method(_MD("set_energy","max"),&GIProbe::set_energy); ClassDB::bind_method(_MD("get_energy"),&GIProbe::get_energy); + ClassDB::bind_method(_MD("set_propagation","max"),&GIProbe::set_propagation); + ClassDB::bind_method(_MD("get_propagation"),&GIProbe::get_propagation); + ClassDB::bind_method(_MD("set_interior","enable"),&GIProbe::set_interior); ClassDB::bind_method(_MD("is_interior"),&GIProbe::is_interior); @@ -1372,6 +1416,7 @@ void GIProbe::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"extents"),_SCS("set_extents"),_SCS("get_extents")); ADD_PROPERTY( PropertyInfo(Variant::INT,"dynamic_range",PROPERTY_HINT_RANGE,"1,16,1"),_SCS("set_dynamic_range"),_SCS("get_dynamic_range")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_energy"),_SCS("get_energy")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"propagation",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_propagation"),_SCS("get_propagation")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"interior"),_SCS("set_interior"),_SCS("is_interior")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"compress"),_SCS("set_compress"),_SCS("is_compressed")); ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"data",PROPERTY_HINT_RESOURCE_TYPE,"GIProbeData"),_SCS("set_probe_data"),_SCS("get_probe_data")); @@ -1389,6 +1434,7 @@ GIProbe::GIProbe() { subdiv=SUBDIV_128; dynamic_range=4; energy=1.0; + propagation=1.0; extents=Vector3(10,10,10); color_scan_cell_width=4; bake_texture_size=128; diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h index e416b28791..f03a558908 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/gi_probe.h @@ -32,6 +32,9 @@ public: void set_dynamic_range(int p_range); int get_dynamic_range() const; + void set_propagation(float p_range); + float get_propagation() const; + void set_energy(float p_range); float get_energy() const; @@ -114,6 +117,8 @@ private: int axis_cell_size[3]; struct PlotMesh { + Ref<Material> override_material; + Vector<Ref<Material> > instance_materials; Ref<Mesh> mesh; Transform local_xform; }; @@ -132,6 +137,7 @@ private: Vector3 extents; int dynamic_range; float energy; + float propagation; bool interior; bool compress; @@ -141,7 +147,7 @@ private: Vector<Color> _get_bake_texture(Image &p_image,const Color& p_color); Baker::MaterialCache _get_material_cache(Ref<Material> p_material,Baker *p_baker); void _plot_face(int p_idx, int p_level, int p_x,int p_y,int p_z,const Vector3 *p_vtx, const Vector2* p_uv, const Baker::MaterialCache& p_material, const Rect3 &p_aabb,Baker *p_baker); - void _plot_mesh(const Transform& p_xform, Ref<Mesh>& p_mesh, Baker *p_baker); + void _plot_mesh(const Transform& p_xform, Ref<Mesh>& p_mesh, Baker *p_baker,const Vector<Ref<Material> >& p_materials,const Ref<Material>& p_override_material); void _find_meshes(Node *p_at_node,Baker *p_baker); void _fixup_plot(int p_idx, int p_level,int p_x,int p_y, int p_z,Baker *p_baker); @@ -170,6 +176,9 @@ public: void set_energy(float p_energy); float get_energy() const; + void set_propagation(float p_propagation); + float get_propagation() const; + void set_interior(bool p_enable); bool is_interior() const; diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 0c6c113dd2..799c00d266 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -253,6 +253,7 @@ void Light::_bind_methods() { ADD_PROPERTY( PropertyInfo( Variant::BOOL, "shadow_enabled"), _SCS("set_shadow"), _SCS("has_shadow")); ADD_PROPERTY( PropertyInfo( Variant::COLOR, "shadow_color",PROPERTY_HINT_COLOR_NO_ALPHA), _SCS("set_shadow_color"), _SCS("get_shadow_color")); ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow_bias",PROPERTY_HINT_RANGE,"-16,16,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow_contact",PROPERTY_HINT_RANGE,"0,16,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_CONTACT_SHADOW_SIZE); ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow_max_distance",PROPERTY_HINT_RANGE,"0,65536,0.1"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_MAX_DISTANCE); ADD_GROUP("Editor",""); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "editor_only"), _SCS("set_editor_only"), _SCS("is_editor_only")); @@ -264,6 +265,7 @@ void Light::_bind_methods() { BIND_CONSTANT( PARAM_ATTENUATION ); BIND_CONSTANT( PARAM_SPOT_ANGLE ); BIND_CONSTANT( PARAM_SPOT_ATTENUATION ); + BIND_CONSTANT( PARAM_CONTACT_SHADOW_SIZE ); BIND_CONSTANT( PARAM_SHADOW_MAX_DISTANCE ); BIND_CONSTANT( PARAM_SHADOW_SPLIT_1_OFFSET ); BIND_CONSTANT( PARAM_SHADOW_SPLIT_2_OFFSET ); @@ -297,6 +299,7 @@ Light::Light(VisualServer::LightType p_type) { set_param(PARAM_ATTENUATION,1); set_param(PARAM_SPOT_ANGLE,45); set_param(PARAM_SPOT_ATTENUATION,1); + set_param(PARAM_CONTACT_SHADOW_SIZE,0); set_param(PARAM_SHADOW_MAX_DISTANCE,0); set_param(PARAM_SHADOW_SPLIT_1_OFFSET,0.1); set_param(PARAM_SHADOW_SPLIT_2_OFFSET,0.2); diff --git a/scene/3d/light.h b/scene/3d/light.h index d27b9fed12..4cf0156d5c 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -55,6 +55,7 @@ public: PARAM_ATTENUATION = VS::LIGHT_PARAM_ATTENUATION, PARAM_SPOT_ANGLE = VS::LIGHT_PARAM_SPOT_ANGLE, PARAM_SPOT_ATTENUATION = VS::LIGHT_PARAM_SPOT_ATTENUATION, + PARAM_CONTACT_SHADOW_SIZE= VS::LIGHT_PARAM_CONTACT_SHADOW_SIZE, PARAM_SHADOW_MAX_DISTANCE = VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE, PARAM_SHADOW_SPLIT_1_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET, PARAM_SHADOW_SPLIT_2_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET, diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 958b065881..e02b2b2b41 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -118,17 +118,20 @@ bool AnimationPlayer::_get(const StringName& p_name,Variant &r_ret) const { } else if (name=="blend_times") { - Array array; - - array.resize(blend_times.size()*3); - int idx=0; + Vector<BlendKey> keys; for(Map<BlendKey, float >::Element *E=blend_times.front();E;E=E->next()) { - array.set(idx*3+0,E->key().from); - array.set(idx*3+1,E->key().to); - array.set(idx*3+2,E->get()); - idx++; + keys.ordered_insert(E->key()); } + + Array array; + for(int i=0;i<keys.size();i++) { + + array.push_back(keys[i].from); + array.push_back(keys[i].to); + array.push_back(blend_times[keys[i]]); + } + r_ret=array; } else if (name=="autoplay") { r_ret=autoplay; diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 41bae6c928..7fab651213 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -142,7 +142,7 @@ private: StringName from; StringName to; - bool operator<(const BlendKey& bk) const { return from==bk.from?to<bk.to:from<bk.from; } + bool operator<(const BlendKey& bk) const { return from==bk.from?String(to)<String(bk.to):String(from)<String(bk.from); } }; diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index b3ed9b209a..46312933a7 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -236,14 +236,14 @@ void ScrollContainer::_notification(int p_what) { child_max_size.y = MAX(child_max_size.y, minsize.y); Rect2 r = Rect2(-scroll,minsize); - if (!(scroll_h || h_scroll->is_visible_in_tree())) { + if (!scroll_h || (!h_scroll->is_visible_in_tree() && c->get_h_size_flags()&SIZE_EXPAND)) { r.pos.x=0; if (c->get_h_size_flags()&SIZE_EXPAND) r.size.width=MAX(size.width,minsize.width); else r.size.width=minsize.width; } - if (!(scroll_v || v_scroll->is_visible_in_tree())) { + if (!scroll_v || (!v_scroll->is_visible_in_tree() && c->get_v_size_flags()&SIZE_EXPAND)) { r.pos.y=0; r.size.height=size.height; if (c->get_v_size_flags()&SIZE_EXPAND) diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index d1a8c458ba..6036b3f9df 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -482,14 +482,6 @@ void TextEdit::_notification(int p_what) { Color color = cache.font_color; int in_region=-1; - if (line_length_guideline) { - int x=xmargin_beg+cache.font->get_char_size('0').width*line_length_guideline_col-cursor.x_ofs; - if (x>xmargin_beg && x<xmargin_end) { - Color guideline_color(color.r,color.g,color.b,color.a*0.25f); - VisualServer::get_singleton()->canvas_item_add_line(ci,Point2(x,0),Point2(x,cache.size.height),guideline_color); - } - } - if (syntax_coloring) { if (cache.background_color.a>0.01) { @@ -1080,6 +1072,14 @@ void TextEdit::_notification(int p_what) { } } + if (line_length_guideline) { + int x=xmargin_beg+cache.font->get_char_size('0').width*line_length_guideline_col-cursor.x_ofs; + if (x>xmargin_beg && x<xmargin_end) { + VisualServer::get_singleton()->canvas_item_add_line(ci,Point2(x,0),Point2(x,cache.size.height),cache.line_length_guideline_color); + } + } + + bool completion_below = false; if (completion_active) { // code completion box @@ -3484,6 +3484,7 @@ void TextEdit::_update_caches() { cache.selection_color=get_color("selection_color"); cache.mark_color=get_color("mark_color"); cache.current_line_color=get_color("current_line_color"); + cache.line_length_guideline_color=get_color("line_length_guideline_color"); cache.breakpoint_color=get_color("breakpoint_color"); cache.brace_mismatch_color=get_color("brace_mismatch_color"); cache.word_highlighted_color=get_color("word_highlighted_color"); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 6113fd72c2..437e22ca40 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -91,6 +91,7 @@ class TextEdit : public Control { Color mark_color; Color breakpoint_color; Color current_line_color; + Color line_length_guideline_color; Color brace_mismatch_color; Color word_highlighted_color; Color search_result_color; diff --git a/scene/io/resource_format_image.cpp b/scene/io/resource_format_image.cpp index 2d098d01f5..4d15ab86fd 100644 --- a/scene/io/resource_format_image.cpp +++ b/scene/io/resource_format_image.cpp @@ -27,6 +27,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "resource_format_image.h" + +#if 0 #include "scene/resources/texture.h" #include "io/image_loader.h" #include "globals.h" @@ -260,3 +262,4 @@ ResourceFormatLoaderImage::ResourceFormatLoaderImage() { GLOBAL_DEF("rendering/image_loader/repeat",false); } +#endif diff --git a/scene/io/resource_format_image.h b/scene/io/resource_format_image.h index 6e4ead2a0b..0638e97787 100644 --- a/scene/io/resource_format_image.h +++ b/scene/io/resource_format_image.h @@ -29,6 +29,8 @@ #ifndef RESOURCE_FORMAT_IMAGE_H #define RESOURCE_FORMAT_IMAGE_H +#if 0 + #include "io/resource_loader.h" #include "io/resource_saver.h" /** @@ -49,3 +51,4 @@ public: }; #endif +#endif diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 7e8a033c40..c0eaca24a3 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -85,6 +85,7 @@ #include "scene/gui/graph_node.h" #include "scene/gui/graph_edit.h" #include "scene/gui/tool_button.h" +#include "scene/resources/audio_stream_sample.h" #include "scene/resources/video_stream.h" #include "scene/2d/particles_2d.h" #include "scene/2d/path_2d.h" @@ -230,7 +231,6 @@ #include "scene/resources/scene_format_text.h" -static ResourceFormatLoaderImage *resource_loader_image=NULL; //static ResourceFormatLoaderWAV *resource_loader_wav=NULL; @@ -245,6 +245,8 @@ static ResourceFormatLoaderText *resource_loader_text=NULL; static ResourceFormatLoaderDynamicFont *resource_loader_dynamic_font=NULL; +static ResourceFormatLoaderStreamTexture *resource_loader_stream_texture=NULL; + //static SceneStringNames *string_names; void register_scene_types() { @@ -255,14 +257,14 @@ void register_scene_types() { Node::init_node_hrcr(); - resource_loader_image = memnew( ResourceFormatLoaderImage ); - ResourceLoader::add_resource_format_loader( resource_loader_image ); - //resource_loader_wav = memnew( ResourceFormatLoaderWAV ); //ResourceLoader::add_resource_format_loader( resource_loader_wav ); resource_loader_dynamic_font = memnew( ResourceFormatLoaderDynamicFont ); ResourceLoader::add_resource_format_loader( resource_loader_dynamic_font ); + resource_loader_stream_texture = memnew( ResourceFormatLoaderStreamTexture); + ResourceLoader::add_resource_format_loader( resource_loader_stream_texture ); + #ifdef TOOLS_ENABLED //scene first! @@ -570,6 +572,7 @@ void register_scene_types() { ClassDB::register_virtual_class<Texture>(); ClassDB::register_virtual_class<SkyBox>(); ClassDB::register_class<ImageSkyBox>(); + ClassDB::register_class<StreamTexture>(); ClassDB::register_class<ImageTexture>(); ClassDB::register_class<AtlasTexture>(); ClassDB::register_class<LargeTexture>(); @@ -594,6 +597,7 @@ void register_scene_types() { ClassDB::register_class<AudioPlayer>(); ClassDB::register_virtual_class<VideoStream>(); + ClassDB::register_class<AudioStreamSample>(); OS::get_singleton()->yield(); //may take time to init @@ -643,9 +647,9 @@ void unregister_scene_types() { clear_default_theme(); - memdelete( resource_loader_image ); // memdelete( resource_loader_wav ); memdelete( resource_loader_dynamic_font ); + memdelete( resource_loader_stream_texture ); #ifdef TOOLS_ENABLED diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp new file mode 100644 index 0000000000..21339cb90b --- /dev/null +++ b/scene/resources/audio_stream_sample.cpp @@ -0,0 +1,557 @@ +#include "audio_stream_sample.h" + +void AudioStreamPlaybackSample::start(float p_from_pos) { + + for(int i=0;i<2;i++) { + ima_adpcm[i].step_index=0; + ima_adpcm[i].predictor=0; + ima_adpcm[i].loop_step_index=0; + ima_adpcm[i].loop_predictor=0; + ima_adpcm[i].last_nibble=-1; + ima_adpcm[i].loop_pos=0x7FFFFFFF; + ima_adpcm[i].window_ofs=0; + ima_adpcm[i].ptr=(const uint8_t*)base->data; + ima_adpcm[i].ptr+=AudioStreamSample::DATA_PAD; + } + + seek_pos(p_from_pos); + sign=1; + active=true; +} + +void AudioStreamPlaybackSample::stop() { + + active=false; +} + +bool AudioStreamPlaybackSample::is_playing() const { + + return active; +} + +int AudioStreamPlaybackSample::get_loop_count() const { + + return 0; +} + +float AudioStreamPlaybackSample::get_pos() const { + + return float(offset>>MIX_FRAC_BITS)/base->mix_rate; +} +void AudioStreamPlaybackSample::seek_pos(float p_time) { + + if (base->format==AudioStreamSample::FORMAT_IMA_ADPCM) + return; //no seeking in ima-adpcm + + float max=get_length(); + if (p_time<0) { + p_time=0; + } else if (p_time>=max) { + p_time=max-0.001; + } + + offset = uint64_t(p_time * base->mix_rate)<<MIX_FRAC_BITS; +} + + +template<class Depth,bool is_stereo,bool is_ima_adpcm> +void AudioStreamPlaybackSample::do_resample(const Depth* p_src, AudioFrame *p_dst,int64_t &offset,int32_t &increment,uint32_t amount,IMA_ADPCM_State *ima_adpcm) { + + // this function will be compiled branchless by any decent compiler + + int32_t final,final_r,next,next_r; + while (amount--) { + + int64_t pos=offset >> MIX_FRAC_BITS; + if (is_stereo && !is_ima_adpcm) + pos<<=1; + + if (is_ima_adpcm) { + + int64_t sample_pos = pos + ima_adpcm[0].window_ofs; + + while(sample_pos>ima_adpcm[0].last_nibble) { + + + static const int16_t _ima_adpcm_step_table[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 + }; + + static const int8_t _ima_adpcm_index_table[16] = { + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 + }; + + for(int i=0;i<(is_stereo?2:1);i++) { + + + int16_t nibble,diff,step; + + ima_adpcm[i].last_nibble++; + const uint8_t *src_ptr=ima_adpcm[i].ptr; + + + uint8_t nbb = src_ptr[ (ima_adpcm[i].last_nibble>>1) * (is_stereo?2:1) + i ]; + nibble = (ima_adpcm[i].last_nibble&1)?(nbb>>4):(nbb&0xF); + step=_ima_adpcm_step_table[ima_adpcm[i].step_index]; + + + ima_adpcm[i].step_index += _ima_adpcm_index_table[nibble]; + if (ima_adpcm[i].step_index<0) + ima_adpcm[i].step_index=0; + if (ima_adpcm[i].step_index>88) + ima_adpcm[i].step_index=88; + + diff = step >> 3 ; + if (nibble & 1) + diff += step >> 2 ; + if (nibble & 2) + diff += step >> 1 ; + if (nibble & 4) + diff += step ; + if (nibble & 8) + diff = -diff ; + + ima_adpcm[i].predictor+=diff; + if (ima_adpcm[i].predictor<-0x8000) + ima_adpcm[i].predictor=-0x8000; + else if (ima_adpcm[i].predictor>0x7FFF) + ima_adpcm[i].predictor=0x7FFF; + + + /* store loop if there */ + if (ima_adpcm[i].last_nibble==ima_adpcm[i].loop_pos) { + + ima_adpcm[i].loop_step_index = ima_adpcm[i].step_index; + ima_adpcm[i].loop_predictor = ima_adpcm[i].predictor; + } + + //printf("%i - %i - pred %i\n",int(ima_adpcm[i].last_nibble),int(nibble),int(ima_adpcm[i].predictor)); + + } + + } + + final=ima_adpcm[0].predictor; + if (is_stereo) { + final_r=ima_adpcm[1].predictor; + } + + } else { + final=p_src[pos]; + if (is_stereo) + final_r=p_src[pos+1]; + + if (sizeof(Depth)==1) { /* conditions will not exist anymore when compiled! */ + final<<=8; + if (is_stereo) + final_r<<=8; + } + + if (is_stereo) { + + next=p_src[pos+2]; + next_r=p_src[pos+3]; + } else { + next=p_src[pos+1]; + } + + if (sizeof(Depth)==1) { + next<<=8; + if (is_stereo) + next_r<<=8; + } + + int32_t frac=int64_t(offset&MIX_FRAC_MASK); + + final=final+((next-final)*frac >> MIX_FRAC_BITS); + if (is_stereo) + final_r=final_r+((next_r-final_r)*frac >> MIX_FRAC_BITS); + + } + + + if (!is_stereo) { + final_r=final; //copy to right channel if stereo + } + + p_dst->l=final/32767.0; + p_dst->r=final_r/32767.0; + p_dst++; + + offset+=increment; + } +} + +void AudioStreamPlaybackSample::mix(AudioFrame* p_buffer,float p_rate_scale,int p_frames) { + + if (!base->data || !active) { + for(int i=0;i<p_frames;i++) { + p_buffer[i]=AudioFrame(0,0); + } + return; + } + + int len = base->data_bytes; + switch(base->format) { + case AudioStreamSample::FORMAT_8_BITS: len/=1; break; + case AudioStreamSample::FORMAT_16_BITS: len/=2; break; + case AudioStreamSample::FORMAT_IMA_ADPCM: len*=2; break; + } + + if (base->stereo) { + len/=2; + } + + /* some 64-bit fixed point precaches */ + + int64_t loop_begin_fp=((int64_t)len<< MIX_FRAC_BITS); + int64_t loop_end_fp=((int64_t)base->loop_end << MIX_FRAC_BITS); + int64_t length_fp=((int64_t)len << MIX_FRAC_BITS); + int64_t begin_limit=(base->loop_mode!=AudioStreamSample::LOOP_DISABLED)?loop_begin_fp:0; + int64_t end_limit=(base->loop_mode!=AudioStreamSample::LOOP_DISABLED)?loop_end_fp:length_fp; + bool is_stereo=base->stereo; + + int32_t todo=p_frames; + + float base_rate = AudioServer::get_singleton()->get_mix_rate(); + float srate = base->mix_rate; + srate*=p_rate_scale; + float fincrement = srate / base_rate; + int32_t increment = int32_t(fincrement * MIX_FRAC_LEN); + increment*=sign; + + + //looping + + AudioStreamSample::LoopMode loop_format=base->loop_mode; + AudioStreamSample::Format format = base->format; + + + /* audio data */ + + uint8_t *dataptr=(uint8_t*)base->data; + const void *data=dataptr+AudioStreamSample::DATA_PAD; + AudioFrame *dst_buff=p_buffer; + + + if (format==AudioStreamSample::FORMAT_IMA_ADPCM) { + + if (loop_format!=AudioStreamSample::LOOP_DISABLED) { + ima_adpcm[0].loop_pos=loop_begin_fp>>MIX_FRAC_BITS; + ima_adpcm[1].loop_pos=loop_begin_fp>>MIX_FRAC_BITS; + loop_format=AudioStreamSample::LOOP_FORWARD; + } + } + + while (todo>0) { + + int64_t limit=0; + int32_t target=0,aux=0; + + /** LOOP CHECKING **/ + + if ( increment < 0 ) { + /* going backwards */ + + if ( loop_format!=AudioStreamSample::LOOP_DISABLED && offset < loop_begin_fp ) { + /* loopstart reached */ + if ( loop_format==AudioStreamSample::LOOP_PING_PONG ) { + /* bounce ping pong */ + offset= loop_begin_fp + ( loop_begin_fp-offset ); + increment=-increment; + sign*=-1; + } else { + /* go to loop-end */ + offset=loop_end_fp-(loop_begin_fp-offset); + } + } else { + /* check for sample not reaching begining */ + if(offset < 0) { + + active=false; + break; + } + } + } else { + /* going forward */ + if( loop_format!=AudioStreamSample::LOOP_DISABLED && offset >= loop_end_fp ) { + /* loopend reached */ + + if ( loop_format==AudioStreamSample::LOOP_PING_PONG ) { + /* bounce ping pong */ + offset=loop_end_fp-(offset-loop_end_fp); + increment=-increment; + sign*=-1; + } else { + /* go to loop-begin */ + + if (format==AudioStreamSample::FORMAT_IMA_ADPCM) { + for(int i=0;i<2;i++) { + ima_adpcm[i].step_index=ima_adpcm[i].loop_step_index; + ima_adpcm[i].predictor=ima_adpcm[i].loop_predictor; + ima_adpcm[i].last_nibble=loop_begin_fp>>MIX_FRAC_BITS; + } + offset=loop_begin_fp; + } else { + offset=loop_begin_fp+(offset-loop_end_fp); + } + + } + } else { + /* no loop, check for end of sample */ + if(offset >= length_fp) { + + active=false; + break; + } + } + } + + /** MIXCOUNT COMPUTING **/ + + /* next possible limit (looppoints or sample begin/end */ + limit=(increment < 0) ?begin_limit:end_limit; + + /* compute what is shorter, the todo or the limit? */ + aux=(limit-offset)/increment+1; + target=(aux<todo)?aux:todo; /* mix target is the shorter buffer */ + + /* check just in case */ + if ( target<=0 ) { + active=false; + break; + } + + todo-=target; + + switch(base->format) { + case AudioStreamSample::FORMAT_8_BITS: { + + if (is_stereo) + do_resample<int8_t,true,false>((int8_t*)data,dst_buff,offset,increment,target,ima_adpcm); + else + do_resample<int8_t,false,false>((int8_t*)data,dst_buff,offset,increment,target,ima_adpcm); + } break; + case AudioStreamSample::FORMAT_16_BITS: { + if (is_stereo) + do_resample<int16_t,true,false>((int16_t*)data,dst_buff,offset,increment,target,ima_adpcm); + else + do_resample<int16_t,false,false>((int16_t*)data,dst_buff,offset,increment,target,ima_adpcm); + + } break; + case AudioStreamSample::FORMAT_IMA_ADPCM: { + if (is_stereo) + do_resample<int8_t,true,true>((int8_t*)data,dst_buff,offset,increment,target,ima_adpcm); + else + do_resample<int8_t,false,true>((int8_t*)data,dst_buff,offset,increment,target,ima_adpcm); + + } break; + } + + dst_buff+=target; + + } + + +} + +float AudioStreamPlaybackSample::get_length() const { + + int len = base->data_bytes; + switch(base->format) { + case AudioStreamSample::FORMAT_8_BITS: len/=1; break; + case AudioStreamSample::FORMAT_16_BITS: len/=2; break; + case AudioStreamSample::FORMAT_IMA_ADPCM: len*=2; break; + } + + if (base->stereo) { + len/=2; + } + + + return float(len)/base->mix_rate; +} + + +AudioStreamPlaybackSample::AudioStreamPlaybackSample() { + + active=false; + offset=0; + sign=1; +} + + +///////////////////// + + +void AudioStreamSample::set_format(Format p_format) { + + format=p_format; +} + +AudioStreamSample::Format AudioStreamSample::get_format() const{ + + return format; +} + +void AudioStreamSample::set_loop_mode(LoopMode p_loop_mode){ + + loop_mode=p_loop_mode; +} +AudioStreamSample::LoopMode AudioStreamSample::get_loop_mode() const{ + + return loop_mode; +} + +void AudioStreamSample::set_loop_begin(int p_frame){ + + loop_begin=p_frame; +} +int AudioStreamSample::get_loop_begin() const{ + + return loop_begin; +} + +void AudioStreamSample::set_loop_end(int p_frame){ + + loop_end=p_frame; +} +int AudioStreamSample::get_loop_end() const{ + + return loop_end; +} + + +void AudioStreamSample::set_mix_rate(int p_hz){ + + mix_rate=p_hz; +} +int AudioStreamSample::get_mix_rate() const{ + + return mix_rate; +} +void AudioStreamSample::set_stereo(bool p_enable){ + + stereo=p_enable; +} +bool AudioStreamSample::is_stereo() const{ + + return stereo; +} + +void AudioStreamSample::set_data(const PoolVector<uint8_t>& p_data) { + + AudioServer::get_singleton()->lock(); + if (data) { + AudioServer::get_singleton()->audio_data_free(data); + data=NULL; + data_bytes=0; + } + + int datalen = p_data.size(); + if (datalen) { + + PoolVector<uint8_t>::Read r = p_data.read(); + int alloc_len = datalen+DATA_PAD*2; + data = AudioServer::get_singleton()->audio_data_alloc(alloc_len); //alloc with some padding for interpolation + zeromem(data,alloc_len); + uint8_t *dataptr=(uint8_t*)data; + copymem(dataptr+DATA_PAD,r.ptr(),datalen); + data_bytes=datalen; + } + + AudioServer::get_singleton()->unlock(); + +} +PoolVector<uint8_t> AudioStreamSample::get_data() const{ + + PoolVector<uint8_t> pv; + + if (data) { + pv.resize(data_bytes); + { + + PoolVector<uint8_t>::Write w =pv.write(); + copymem(w.ptr(),data,data_bytes); + } + } + + return pv; +} + + +Ref<AudioStreamPlayback> AudioStreamSample::instance_playback() { + + Ref<AudioStreamPlaybackSample> sample; + sample.instance(); + sample->base=Ref<AudioStreamSample>(this); + return sample; +} + +String AudioStreamSample::get_stream_name() const { + + return ""; +} + +void AudioStreamSample::_bind_methods() { + + ClassDB::bind_method(_MD("set_format","format"),&AudioStreamSample::set_format); + ClassDB::bind_method(_MD("get_format"),&AudioStreamSample::get_format); + + ClassDB::bind_method(_MD("set_loop_mode","loop_mode"),&AudioStreamSample::set_loop_mode); + ClassDB::bind_method(_MD("get_loop_mode"),&AudioStreamSample::get_loop_mode); + + ClassDB::bind_method(_MD("set_loop_begin","loop_begin"),&AudioStreamSample::set_loop_begin); + ClassDB::bind_method(_MD("get_loop_begin"),&AudioStreamSample::get_loop_begin); + + ClassDB::bind_method(_MD("set_loop_end","loop_end"),&AudioStreamSample::set_loop_end); + ClassDB::bind_method(_MD("get_loop_end"),&AudioStreamSample::get_loop_end); + + ClassDB::bind_method(_MD("set_mix_rate","mix_rate"),&AudioStreamSample::set_mix_rate); + ClassDB::bind_method(_MD("get_mix_rate"),&AudioStreamSample::get_mix_rate); + + ClassDB::bind_method(_MD("set_stereo","stereo"),&AudioStreamSample::set_stereo); + ClassDB::bind_method(_MD("is_stereo"),&AudioStreamSample::is_stereo); + + ClassDB::bind_method(_MD("set_data","data"),&AudioStreamSample::set_data); + ClassDB::bind_method(_MD("get_data"),&AudioStreamSample::get_data); + + ADD_PROPERTY(PropertyInfo(Variant::INT,"format",PROPERTY_HINT_ENUM,"8-Bit,16-Bit,IMA-ADPCM"),_SCS("set_format"),_SCS("get_format")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"loop_mode",PROPERTY_HINT_ENUM,"Disabled,Forward,Ping-Pong"),_SCS("set_loop_mode"),_SCS("get_loop_mode")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"loop_begin"),_SCS("set_loop_begin"),_SCS("get_loop_begin")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"loop_end"),_SCS("set_loop_end"),_SCS("get_loop_end")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"mix_rate"),_SCS("set_mix_rate"),_SCS("get_mix_rate")); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"stereo"),_SCS("set_stereo"),_SCS("is_stereo")); + ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY,"data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_data"),_SCS("get_data")); + +} + +AudioStreamSample::AudioStreamSample() +{ + format=FORMAT_8_BITS; + loop_mode=LOOP_DISABLED; + stereo=false; + loop_begin=0; + loop_end=0; + mix_rate=44100; + data=NULL; + data_bytes=0; +} +AudioStreamSample::~AudioStreamSample() { + + + if (data) { + AudioServer::get_singleton()->audio_data_free(data); + data=NULL; + data_bytes=0; + } +} diff --git a/scene/resources/audio_stream_sample.h b/scene/resources/audio_stream_sample.h new file mode 100644 index 0000000000..8c1e74608b --- /dev/null +++ b/scene/resources/audio_stream_sample.h @@ -0,0 +1,128 @@ +#ifndef AUDIOSTREAMSAMPLE_H +#define AUDIOSTREAMSAMPLE_H + +#include "servers/audio/audio_stream.h" + + +class AudioStreamSample; + +class AudioStreamPlaybackSample : public AudioStreamPlayback { + + GDCLASS( AudioStreamPlaybackSample, AudioStreamPlayback ) + enum { + MIX_FRAC_BITS=13, + MIX_FRAC_LEN=(1<<MIX_FRAC_BITS), + MIX_FRAC_MASK=MIX_FRAC_LEN-1, + }; + + struct IMA_ADPCM_State { + + int16_t step_index; + int32_t predictor; + /* values at loop point */ + int16_t loop_step_index; + int32_t loop_predictor; + int32_t last_nibble; + int32_t loop_pos; + int32_t window_ofs; + const uint8_t *ptr; + } ima_adpcm[2]; + + int64_t offset; + int sign; + bool active; +friend class AudioStreamSample; + Ref<AudioStreamSample> base; + + template<class Depth,bool is_stereo,bool is_ima_adpcm> + void do_resample(const Depth* p_src, AudioFrame *p_dst,int64_t &offset,int32_t &increment,uint32_t amount,IMA_ADPCM_State *ima_adpcm); +public: + + virtual void start(float p_from_pos=0.0); + virtual void stop(); + virtual bool is_playing() const; + + virtual int get_loop_count() const; //times it looped + + virtual float get_pos() const; + virtual void seek_pos(float p_time); + + virtual void mix(AudioFrame* p_buffer,float p_rate_scale,int p_frames); + + virtual float get_length() const; //if supported, otherwise return 0 + + + AudioStreamPlaybackSample(); +}; + +class AudioStreamSample : public AudioStream { + GDCLASS(AudioStreamSample,AudioStream) + RES_BASE_EXTENSION("smp") + +public: + + enum Format { + FORMAT_8_BITS, + FORMAT_16_BITS, + FORMAT_IMA_ADPCM + }; + + enum LoopMode { + LOOP_DISABLED, + LOOP_FORWARD, + LOOP_PING_PONG + }; + + +private: +friend class AudioStreamPlaybackSample; + + enum { + DATA_PAD=16 //padding for interpolation + }; + + Format format; + LoopMode loop_mode; + bool stereo; + int loop_begin; + int loop_end; + int mix_rate; + void *data; + uint32_t data_bytes; +protected: + + static void _bind_methods(); +public: + void set_format(Format p_format); + Format get_format() const; + + void set_loop_mode(LoopMode p_loop_mode); + LoopMode get_loop_mode() const; + + void set_loop_begin(int p_frame); + int get_loop_begin() const; + + void set_loop_end(int p_frame); + int get_loop_end() const; + + void set_mix_rate(int p_hz); + int get_mix_rate() const; + + void set_stereo(bool p_enable); + bool is_stereo() const; + + void set_data(const PoolVector<uint8_t>& p_data); + PoolVector<uint8_t> get_data() const; + + + virtual Ref<AudioStreamPlayback> instance_playback(); + virtual String get_stream_name() const; + + AudioStreamSample(); + ~AudioStreamSample(); +}; + +VARIANT_ENUM_CAST(AudioStreamSample::Format) +VARIANT_ENUM_CAST(AudioStreamSample::LoopMode) + +#endif // AUDIOSTREAMSample_H diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp index a913687e7f..9719f321d6 100644 --- a/scene/resources/scene_format_text.cpp +++ b/scene/resources/scene_format_text.cpp @@ -32,7 +32,8 @@ #include "version.h" #include "os/dir_access.h" -#define FORMAT_VERSION 1 +//version 2: changed names for basis, rect3, poolvectors, etc. +#define FORMAT_VERSION 2 #include "version.h" #include "os/dir_access.h" @@ -1158,7 +1159,7 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant& p_variant,b static String _valprop(const String& p_name) { if (p_name.find("\"")!=-1 || p_name.find("=")!=-1 || p_name.find(" ")!=-1) - return "\""+p_name.c_escape()+"\""; + return "\""+p_name.c_escape_multiline()+"\""; return p_name; } @@ -1360,13 +1361,11 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path,const RES& p_re } if (groups.size()) { - String sgroups=" groups=[ "; + String sgroups=" groups=[\n"; for(int j=0;j<groups.size();j++) { - if (j>0) - sgroups+=", "; - sgroups+="\""+groups[j].operator String().c_escape()+"\""; + sgroups+="\""+String(groups[j]).c_escape()+"\",\n"; } - sgroups+=" ]"; + sgroups+="]"; header+=sgroups; } diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index a1ad5d8237..fa89b7ba00 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -453,6 +453,379 @@ ImageTexture::~ImageTexture() { VisualServer::get_singleton()->free( texture ); } +////////////////////////////////////////// + + +void StreamTexture::_requested_3d(void* p_ud) { + + StreamTexture *st = (StreamTexture *)p_ud; + Ref<StreamTexture> stex(st); + ERR_FAIL_COND(!request_3d_callback); + request_3d_callback(stex); +} + +void StreamTexture::_requested_srgb(void* p_ud) { + + StreamTexture *st = (StreamTexture *)p_ud; + Ref<StreamTexture> stex(st); + ERR_FAIL_COND(!request_srgb_callback); + request_srgb_callback(stex); + +} + +StreamTexture::TextureFormatRequestCallback StreamTexture::request_3d_callback=NULL; +StreamTexture::TextureFormatRequestCallback StreamTexture::request_srgb_callback=NULL; + + +uint32_t StreamTexture::get_flags() const { + + return flags; +} +Image::Format StreamTexture::get_format() const { + + return format; +} + + +Error StreamTexture::_load_data(const String& p_path,int &tw,int &th,int& flags,Image& image,int p_size_limit) { + + + FileAccess *f = FileAccess::open(p_path,FileAccess::READ); + ERR_FAIL_COND_V(!f,ERR_CANT_OPEN); + + uint8_t header[4]; + f->get_buffer(header,4); + if (header[0]!='G' || header[1]!='D' || header[2]!='S' || header[3]!='T') { + memdelete(f); + ERR_FAIL_COND_V(header[0]!='G' || header[1]!='D' || header[2]!='S' || header[3]!='T',ERR_FILE_CORRUPT); + } + + tw = f->get_32(); + th = f->get_32(); + flags= f->get_32(); //texture flags! + uint32_t df = f->get_32(); //data format + + print_line("width: "+itos(tw)); + print_line("height: "+itos(th)); + print_line("flags: "+itos(flags)); + print_line("df: "+itos(df)); + + + if (request_3d_callback && df&FORMAT_BIT_DETECT_3D) { + print_line("request detect 3D at "+p_path); + VS::get_singleton()->texture_set_detect_3d_callback(texture,_requested_3d,this); + } else { + print_line("not requesting detect 3D at "+p_path); + VS::get_singleton()->texture_set_detect_3d_callback(texture,NULL,NULL); + } + + if (request_srgb_callback && df&FORMAT_BIT_DETECT_SRGB) { + print_line("request detect srgb at "+p_path); + VS::get_singleton()->texture_set_detect_srgb_callback(texture,_requested_srgb,this); + } else { + VS::get_singleton()->texture_set_detect_srgb_callback(texture,NULL,NULL); + print_line("not requesting detect srgb at "+p_path); + } + + if (!(df&FORMAT_BIT_STREAM)) { + p_size_limit=0; + } + + + if (df&FORMAT_BIT_LOSSLESS || df&FORMAT_BIT_LOSSY) { + //look for a PNG or WEBP file inside + + int sw=tw; + int sh=th; + + uint32_t mipmaps = f->get_32(); + uint32_t size = f->get_32(); + + print_line("mipmaps: "+itos(mipmaps)); + + while(mipmaps>1 && p_size_limit>0 && (sw>p_size_limit || sh>p_size_limit)) { + + f->seek(f->get_pos()+size); + mipmaps = f->get_32(); + size = f->get_32(); + + sw=MAX(sw>>1,1); + sh=MAX(sh>>1,1); + mipmaps--; + } + + //mipmaps need to be read independently, they will be later combined + Vector<Image> mipmap_images; + int total_size=0; + + for(int i=0;i<mipmaps;i++) { + PoolVector<uint8_t> pv; + pv.resize(size); + { + PoolVector<uint8_t>::Write w = pv.write(); + f->get_buffer(w.ptr(),size); + } + + Image img; + if (df&FORMAT_BIT_LOSSLESS) { + img = Image::lossless_unpacker(pv); + } else { + img = Image::lossy_unpacker(pv); + } + + if (img.empty()) { + memdelete(f); + ERR_FAIL_COND_V(img.empty(),ERR_FILE_CORRUPT); + } + total_size+=img.get_data().size(); + + mipmap_images.push_back(img); + } + + print_line("mipmap read total: "+itos(mipmap_images.size())); + + + memdelete(f); //no longer needed + + if (mipmap_images.size()==1) { + + image=mipmap_images[0]; + return OK; + + } else { + PoolVector<uint8_t> img_data; + img_data.resize(total_size); + + { + PoolVector<uint8_t>::Write w=img_data.write(); + + int ofs=0; + for(int i=0;i<mipmap_images.size();i++) { + + PoolVector<uint8_t> id = mipmap_images[i].get_data(); + int len = id.size(); + PoolVector<uint8_t>::Read r = id.read(); + copymem(&w[ofs],r.ptr(),len); + ofs+=len; + } + } + + image = Image(sw,sh,true,mipmap_images[0].get_format(),img_data); + return OK; + } + + } else { + + //look for regular format + Image::Format format = (Image::Format)(df&FORMAT_MASK_IMAGE_FORMAT); + bool mipmaps = df&FORMAT_BIT_HAS_MIPMAPS; + + if (!mipmaps) { + int size = Image::get_image_data_size(tw,th,format,0); + + PoolVector<uint8_t> img_data; + img_data.resize(size); + + { + PoolVector<uint8_t>::Write w=img_data.write(); + f->get_buffer(w.ptr(),size); + } + + memdelete(f); + + image = Image(tw,th,false,format,img_data); + return OK; + } else { + + int sw=tw; + int sh=th; + + int mipmaps = Image::get_image_required_mipmaps(tw,th,format); + int total_size = Image::get_image_data_size(tw,th,format,mipmaps); + int idx=0; + int ofs=0; + + + while(mipmaps>1 && p_size_limit>0 && (sw>p_size_limit || sh>p_size_limit)) { + + sw=MAX(sw>>1,1); + sh=MAX(sh>>1,1); + mipmaps--; + idx++; + } + + if (idx>0) { + ofs=Image::get_image_data_size(tw,th,format,idx-1); + } + + if (total_size - ofs <=0) { + memdelete(f); + ERR_FAIL_V(ERR_FILE_CORRUPT); + } + + f->seek(f->get_pos()+ofs); + + + PoolVector<uint8_t> img_data; + img_data.resize(total_size - ofs); + + { + PoolVector<uint8_t>::Write w=img_data.write(); + int bytes = f->get_buffer(w.ptr(),total_size - ofs); + print_line("requested read: "+itos(total_size - ofs)+" but got: "+itos(bytes)); + + memdelete(f); + + if (bytes != total_size - ofs) { + ERR_FAIL_V(ERR_FILE_CORRUPT); + } + } + + image = Image(sw,sh,true,format,img_data); + + return OK; + } + } + + return ERR_BUG; //unreachable +} + +Error StreamTexture::load(const String& p_path) { + + + int lw,lh,lflags; + Image image; + Error err = _load_data(p_path,lw,lh,lflags,image); + if (err) + return err; + + VS::get_singleton()->texture_allocate(texture,image.get_width(),image.get_height(),image.get_format(),lflags); + VS::get_singleton()->texture_set_data(texture,image); + + w=lw; + h=lh; + flags=lflags; + path_to_file=p_path; + format=image.get_format(); + + return OK; +} +String StreamTexture::get_load_path() const { + + return path_to_file; +} + +int StreamTexture::get_width() const { + + return w; +} +int StreamTexture::get_height() const { + + return h; +} +RID StreamTexture::get_rid() const { + + return texture; +} + + +void StreamTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const { + + if ((w|h)==0) + return; + VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, Size2(w,h)),texture,false,p_modulate,p_transpose); + +} +void StreamTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const { + + if ((w|h)==0) + return; + VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,texture,p_tile,p_modulate,p_transpose); + +} +void StreamTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const{ + + if ((w|h)==0) + return; + VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,texture,p_src_rect,p_modulate,p_transpose); +} + +bool StreamTexture::has_alpha() const { + + return false; +} +void StreamTexture::set_flags(uint32_t p_flags){ + +} + +void StreamTexture::reload_from_file() { + +#ifdef TOOLS_ENABLED + String ipath = get_import_path(); + if (ipath.is_resource_file() && ipath!=path_to_file) { + path_to_file=ipath; + } +#endif + load(path_to_file); +} + +void StreamTexture::_bind_methods() { + + ClassDB::bind_method(_MD("load","path"),&StreamTexture::load); + ClassDB::bind_method(_MD("get_load_path"),&StreamTexture::get_load_path); + + ADD_PROPERTY( PropertyInfo(Variant::STRING,"load_path",PROPERTY_HINT_FILE,"*.stex"),_SCS("load"),_SCS("get_load_path")); +} + + +StreamTexture::StreamTexture() { + + format=Image::FORMAT_MAX; + flags=0; + w=0; + h=0; + + texture = VS::get_singleton()->texture_create(); +} + +StreamTexture::~StreamTexture() { + + VS::get_singleton()->free(texture); +} + + + +RES ResourceFormatLoaderStreamTexture::load(const String &p_path,const String& p_original_path,Error *r_error) { + + Ref<StreamTexture> st; + st.instance(); + Error err = st->load(p_path); + if (r_error) + *r_error=err; + if (err!=OK) + return RES(); + + return st; +} + +void ResourceFormatLoaderStreamTexture::get_recognized_extensions(List<String> *p_extensions) const{ + + p_extensions->push_back("stex"); +} +bool ResourceFormatLoaderStreamTexture::handles_type(const String& p_type) const{ + return p_type=="StreamTexture"; + +} +String ResourceFormatLoaderStreamTexture::get_resource_type(const String &p_path) const{ + + if (p_path.get_extension().to_lower()=="stex") + return "StreamTexture"; + return ""; +} + + + + ////////////////////////////////////////// diff --git a/scene/resources/texture.h b/scene/resources/texture.h index aac3514af3..f684aeb658 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -31,6 +31,7 @@ #include "resource.h" #include "servers/visual_server.h" +#include "io/resource_loader.h" #include "math_2d.h" /** @@ -160,6 +161,86 @@ public: }; + +class StreamTexture : public Texture { + + GDCLASS( StreamTexture, Texture ); +public: + enum DataFormat { + DATA_FORMAT_IMAGE, + DATA_FORMAT_LOSSLESS, + DATA_FORMAT_LOSSY + }; + + enum FormatBits { + FORMAT_MASK_IMAGE_FORMAT=(1<<20)-1, + FORMAT_BIT_LOSSLESS=1<<20, + FORMAT_BIT_LOSSY=1<<21, + FORMAT_BIT_STREAM=1<<22, + FORMAT_BIT_HAS_MIPMAPS=1<<23, + FORMAT_BIT_DETECT_3D=1<<24, + FORMAT_BIT_DETECT_SRGB=1<<25, + }; + +private: + + Error _load_data(const String &p_path, int &tw, int &th, int& flags, Image& image, int p_size_limit=0); + String path_to_file; + RID texture; + Image::Format format; + uint32_t flags; + int w,h; + + virtual void reload_from_file(); + + static void _requested_3d(void* p_ud); + static void _requested_srgb(void* p_ud); + +protected: + + static void _bind_methods(); + +public: + + + typedef void (*TextureFormatRequestCallback)(const Ref<StreamTexture>&); + + static TextureFormatRequestCallback request_3d_callback; + static TextureFormatRequestCallback request_srgb_callback; + + uint32_t get_flags() const; + Image::Format get_format() const; + Error load(const String& p_path); + String get_load_path() const; + + int get_width() const; + int get_height() const; + virtual RID get_rid() const; + + virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const; + virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const; + virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const; + + virtual bool has_alpha() const; + virtual void set_flags(uint32_t p_flags); + + StreamTexture(); + ~StreamTexture(); + +}; + + +class ResourceFormatLoaderStreamTexture : public 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; + virtual bool handles_type(const String& p_type) const; + virtual String get_resource_type(const String &p_path) const; + +}; + + + VARIANT_ENUM_CAST( ImageTexture::Storage ); class AtlasTexture : public Texture { |