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/register_scene_types.cpp2
-rw-r--r--scene/resources/audio_stream_sample.cpp557
-rw-r--r--scene/resources/audio_stream_sample.h128
-rw-r--r--scene/resources/texture.cpp44
-rw-r--r--scene/resources/texture.h10
7 files changed, 800 insertions, 4 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/register_scene_types.cpp b/scene/register_scene_types.cpp
index 0ad140f7c3..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"
@@ -596,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
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/texture.cpp b/scene/resources/texture.cpp
index a853b62254..fa89b7ba00 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -456,6 +456,26 @@ ImageTexture::~ImageTexture() {
//////////////////////////////////////////
+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 {
@@ -490,6 +510,23 @@ Error StreamTexture::_load_data(const String& p_path,int &tw,int &th,int& flags,
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;
}
@@ -635,6 +672,7 @@ Error StreamTexture::_load_data(const String& p_path,int &tw,int &th,int& flags,
{
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);
@@ -722,6 +760,12 @@ 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);
}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 919c588894..f684aeb658 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -178,6 +178,8 @@ public:
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:
@@ -191,6 +193,9 @@ private:
virtual void reload_from_file();
+ static void _requested_3d(void* p_ud);
+ static void _requested_srgb(void* p_ud);
+
protected:
static void _bind_methods();
@@ -198,6 +203,11 @@ protected:
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);