summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/3d/gi_probe.cpp52
-rw-r--r--scene/3d/gi_probe.h11
-rw-r--r--scene/3d/light.cpp3
-rw-r--r--scene/3d/light.h1
-rw-r--r--scene/animation/animation_player.cpp19
-rw-r--r--scene/animation/animation_player.h2
-rw-r--r--scene/gui/scroll_container.cpp4
-rw-r--r--scene/gui/text_edit.cpp17
-rw-r--r--scene/gui/text_edit.h1
-rw-r--r--scene/io/resource_format_image.cpp3
-rw-r--r--scene/io/resource_format_image.h3
-rw-r--r--scene/register_scene_types.cpp14
-rw-r--r--scene/resources/audio_stream_sample.cpp557
-rw-r--r--scene/resources/audio_stream_sample.h128
-rw-r--r--scene/resources/scene_format_text.cpp13
-rw-r--r--scene/resources/texture.cpp373
-rw-r--r--scene/resources/texture.h81
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 {