void make_input_image_class_cnae (INPUT_DESC *input, int w, int h) { char message[256]; input->tfw = nearest_power_of_2 (w); input->tfh = nearest_power_of_2 (h); input->ww = w; input->wh = h; switch(TYPE_SHOW) { case SHOW_FRAME: input->vpw = input->neuron_layer->dimentions.x; input->vph = input->neuron_layer->dimentions.y; break; case SHOW_WINDOW: input->vph = h; input->vpw = w; break; default: sprintf(message,"%d. It can be SHOW_FRAME or SHOW_WINDOW.",TYPE_SHOW); Erro ("Invalid Type Show ", message, " Error in update_input_image."); return; } input->vpxo = 0; input->vpyo = h - input->vph; if(input->image == NULL) input->image = (GLubyte *) alloc_mem (input->tfw * input->tfh * 3 * sizeof (GLubyte)); }
void image_compress_squish(Image *p_image) { int w=p_image->get_width(); int h=p_image->get_height(); if (p_image->get_mipmaps() == 0) { ERR_FAIL_COND( !w || w % 4 != 0); ERR_FAIL_COND( !h || h % 4 != 0); } else { ERR_FAIL_COND( !w || w !=nearest_power_of_2(w) ); ERR_FAIL_COND( !h || h !=nearest_power_of_2(h) ); }; if (p_image->get_format()>=Image::FORMAT_BC1) return; //do not compress, already compressed Image::AlphaMode alpha = p_image->detect_alpha(); Image::Format target_format; int shift=0; int squish_comp=squish::kColourRangeFit; switch(alpha) { case Image::ALPHA_NONE: target_format = Image::FORMAT_BC1; shift=1; squish_comp|=squish::kDxt1; break; case Image::ALPHA_BIT: target_format = Image::FORMAT_BC2; squish_comp|=squish::kDxt3; break; case Image::ALPHA_BLEND: target_format = Image::FORMAT_BC3; squish_comp|=squish::kDxt5; break; } p_image->convert(Image::FORMAT_RGBA); //always expects rgba int mm_count = p_image->get_mipmaps(); DVector<uint8_t> data; int target_size = Image::get_image_data_size(w,h,target_format,mm_count); data.resize(target_size); DVector<uint8_t>::Read rb = p_image->get_data().read(); DVector<uint8_t>::Write wb = data.write(); int dst_ofs=0; for(int i=0;i<=mm_count;i++) { int src_ofs = p_image->get_mipmap_offset(i); squish::CompressImage( &rb[src_ofs],w,h,&wb[dst_ofs],squish_comp); dst_ofs+=(MAX(4,w)*MAX(4,h))>>shift; w>>=1; h>>=1; } rb = DVector<uint8_t>::Read(); wb = DVector<uint8_t>::Write(); p_image->create(p_image->get_width(),p_image->get_height(),p_image->get_mipmaps(),target_format,data); }
void make_input_image_character(INPUT_DESC *input) { int i; char message[256]; int w, h; w = input->neuron_layer->dimentions.x; h = input->neuron_layer->dimentions.y; // Computes the input image dimentions input->tfw = nearest_power_of_2(w); input->tfh = nearest_power_of_2(h); // Saves the image dimentions input->ww = w; input->wh = h; // Computes the input image dimentions input->tfw = nearest_power_of_2(w); input->tfh = nearest_power_of_2(h); switch (TYPE_SHOW) { case SHOW_FRAME: input->vpw = input->neuron_layer->dimentions.x; input->vph = input->neuron_layer->dimentions.y; break; case SHOW_WINDOW: input->vpw = input->ww; input->vph = input->wh; break; default: sprintf(message,"%d. It can be SHOW_FRAME or SHOW_WINDOW.",TYPE_SHOW); Erro("Invalid Type Show ", message, " Error in update_input_image."); return; } input->vpxo = 0; input->vpyo = w - input->vph; if (input->image == (GLubyte *) NULL) { input->image = (GLubyte *) alloc_mem (3 * input->tfw * input->tfh * sizeof(GLubyte)); for (i = 0; i < input->tfh * input->tfw * 3; i++) input->image[i] = 0; } return; }
void PacketPeerStream::set_input_buffer_max_size(int p_max_size) { //warning may lose packets ERR_EXPLAIN("Buffer in use, resizing would cause loss of data"); ERR_FAIL_COND(ring_buffer.data_left()); ring_buffer.resize(nearest_shift(p_max_size + 4)); temp_buffer.resize(nearest_power_of_2(p_max_size + 4)); }
void VisualServerCanvas::canvas_light_set_shadow_buffer_size(RID p_light, int p_size) { ERR_FAIL_COND(p_size < 32 || p_size > 16384); RasterizerCanvas::Light *clight = canvas_light_owner.get(p_light); ERR_FAIL_COND(!clight); int new_size = nearest_power_of_2(p_size); if (new_size == clight->shadow_buffer_size) return; clight->shadow_buffer_size = nearest_power_of_2(p_size); if (clight->shadow_buffer.is_valid()) { VSG::storage->free(clight->shadow_buffer); clight->shadow_buffer = VSG::storage->canvas_light_shadow_buffer_create(clight->shadow_buffer_size); } }
Error AudioDriverXAudio2::init() { active = false; thread_exited = false; exit_thread = false; pcm_open = false; samples_in = NULL; mix_rate = 48000; // FIXME: speaker_mode seems unused in the Xaudio2 driver so far speaker_mode = SPEAKER_MODE_STEREO; channels = 2; int latency = GLOBAL_DEF("audio/output_latency", 25); buffer_size = nearest_power_of_2(latency * mix_rate / 1000); samples_in = memnew_arr(int32_t, buffer_size * channels); for (int i = 0; i < AUDIO_BUFFERS; i++) { samples_out[i] = memnew_arr(int16_t, buffer_size * channels); xaudio_buffer[i].AudioBytes = buffer_size * channels * sizeof(int16_t); xaudio_buffer[i].pAudioData = (const BYTE *)(samples_out[i]); xaudio_buffer[i].Flags = 0; } HRESULT hr; hr = XAudio2Create(&xaudio, 0, XAUDIO2_DEFAULT_PROCESSOR); if (hr != S_OK) { ERR_EXPLAIN("Error creating XAudio2 engine."); ERR_FAIL_V(ERR_UNAVAILABLE); } hr = xaudio->CreateMasteringVoice(&mastering_voice); if (hr != S_OK) { ERR_EXPLAIN("Error creating XAudio2 mastering voice."); ERR_FAIL_V(ERR_UNAVAILABLE); } wave_format.nChannels = channels; wave_format.cbSize = 0; wave_format.nSamplesPerSec = mix_rate; wave_format.wFormatTag = WAVE_FORMAT_PCM; wave_format.wBitsPerSample = 16; wave_format.nBlockAlign = channels * wave_format.wBitsPerSample >> 3; wave_format.nAvgBytesPerSec = mix_rate * wave_format.nBlockAlign; hr = xaudio->CreateSourceVoice(&source_voice, &wave_format, 0, XAUDIO2_MAX_FREQ_RATIO, &voice_callback); if (hr != S_OK) { ERR_EXPLAIN("Error creating XAudio2 source voice. " + itos(hr)); ERR_FAIL_V(ERR_UNAVAILABLE); } mutex = Mutex::create(); thread = Thread::create(AudioDriverXAudio2::thread_func, this); return OK; };
Error AudioDriverPulseAudio::init() { active = false; thread_exited = false; exit_thread = false; pcm_open = false; samples_in = NULL; samples_out = NULL; mix_rate = GLOBAL_DEF("audio/mix_rate",44100); speaker_mode = SPEAKER_MODE_STEREO; channels = 2; pa_sample_spec spec; spec.format = PA_SAMPLE_S16LE; spec.channels = channels; spec.rate = mix_rate; int latency = GLOBAL_DEF("audio/output_latency", 25); buffer_size = nearest_power_of_2(latency * mix_rate / 1000); pa_buffer_attr attr; // set to appropriate buffer size from global settings attr.tlength = buffer_size; // set them to be automatically chosen attr.prebuf = (uint32_t)-1; attr.maxlength = (uint32_t)-1; attr.minreq = (uint32_t)-1; int error_code; pulse = pa_simple_new( NULL, // default server "Godot", // application name PA_STREAM_PLAYBACK, NULL, // default device "Sound", // stream description &spec, NULL, // use default channel map &attr, // use buffering attributes from above &error_code ); if (pulse == NULL) { fprintf(stderr, "PulseAudio ERR: %s\n", pa_strerror(error_code));\ ERR_FAIL_COND_V(pulse == NULL, ERR_CANT_OPEN); } samples_in = memnew_arr(int32_t, buffer_size * channels); samples_out = memnew_arr(int16_t, buffer_size * channels); mutex = Mutex::create(); thread = Thread::create(AudioDriverPulseAudio::thread_func, this); return OK; }
Error AudioDriverAndroid::init(){ mutex = Mutex::create(); /* // TODO: pass in/return a (Java) device ID, also whether we're opening for input or output this->spec.samples = Android_JNI_OpenAudioDevice(this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples); SDL_CalculateAudioSpec(&this->spec); if (this->spec.samples == 0) { // Init failed? SDL_SetError("Java-side initialization failed!"); return 0; } */ //Android_JNI_SetupThread(); // __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device"); JNIEnv *env = ThreadAndroid::get_env(); int mix_rate = GLOBAL_DEF("audio/mix_rate",44100); int latency = GLOBAL_DEF("audio/output_latency",25); latency=50; unsigned int buffer_size = nearest_power_of_2( latency * mix_rate / 1000 ); if (OS::get_singleton()->is_stdout_verbose()) { print_line("audio buffer size: "+itos(buffer_size)); } __android_log_print(ANDROID_LOG_INFO,"godot","Initializing audio! params: %i,%i ",mix_rate,buffer_size); audioBuffer = env->CallObjectMethod(io,_init_audio, mix_rate, buffer_size); ERR_FAIL_COND_V( audioBuffer == NULL, ERR_INVALID_PARAMETER); audioBuffer = env->NewGlobalRef(audioBuffer); jboolean isCopy = JNI_FALSE; audioBufferPinned = env->GetShortArrayElements((jshortArray)audioBuffer, &isCopy); audioBufferFrames = env->GetArrayLength((jshortArray)audioBuffer); audioBuffer32 = memnew_arr(int32_t,audioBufferFrames); return OK; }
Error AudioDriverDummy::init() { active=false; thread_exited=false; exit_thread=false; pcm_open = false; samples_in = NULL; mix_rate = 44100; speaker_mode = SPEAKER_MODE_STEREO; channels = 2; int latency = GLOBAL_DEF("audio/output_latency",25); buffer_size = nearest_power_of_2( latency * mix_rate / 1000 ); samples_in = memnew_arr(int32_t, buffer_size*channels); mutex=Mutex::create(); thread = Thread::create(AudioDriverDummy::thread_func, this); return OK; };
Error AudioDriverMediaKit::init() { active = false; mix_rate = 44100; output_format = OUTPUT_STEREO; channels = 2; int latency = GLOBAL_DEF("audio/output_latency", 25); buffer_size = nearest_power_of_2(latency * mix_rate / 1000); samples_in = memnew_arr(int32_t, buffer_size * channels); media_raw_audio_format format; format = media_raw_audio_format::wildcard; format.frame_rate = mix_rate; format.channel_count = channels; format.format = media_raw_audio_format::B_AUDIO_INT; format.byte_order = B_MEDIA_LITTLE_ENDIAN; format.buffer_size = buffer_size * sizeof(int32_t) * channels; player = new BSoundPlayer( &format, "godot_sound_server", AudioDriverMediaKit::PlayBuffer, NULL, this ); if (player->InitCheck() != B_OK) { fprintf(stderr, "MediaKit ERR: can not create a BSoundPlayer instance\n"); ERR_FAIL_COND_V(player == NULL, ERR_CANT_OPEN); } mutex = Mutex::create(); player->Start(); return OK; }
Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<ResourceImportMetadata>& p_from,EditorExportPlatform::ImageCompression p_compr, bool p_external){ ERR_FAIL_COND_V(p_from->get_source_count()==0,ERR_INVALID_PARAMETER); Ref<ResourceImportMetadata> from=p_from; Ref<ImageTexture> texture; Vector<Ref<AtlasTexture> > atlases; bool atlas = from->get_option("atlas"); int flags=from->get_option("flags"); uint32_t tex_flags=0; if (flags&EditorTextureImportPlugin::IMAGE_FLAG_REPEAT) tex_flags|=Texture::FLAG_REPEAT; if (flags&EditorTextureImportPlugin::IMAGE_FLAG_FILTER) tex_flags|=Texture::FLAG_FILTER; if (!(flags&EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS)) tex_flags|=Texture::FLAG_MIPMAPS; int shrink=1; if (from->has_option("shrink")) shrink=from->get_option("shrink"); if (atlas) { //prepare atlas! Vector< Image > sources; bool alpha=false; bool crop = from->get_option("crop"); EditorProgress ep("make_atlas","Build Atlas For: "+p_path.get_file(),from->get_source_count()+3); print_line("sources: "+itos(from->get_source_count())); for(int i=0;i<from->get_source_count();i++) { String path = EditorImportPlugin::expand_source_path(from->get_source_path(i)); ep.step("Loading Image: "+path,i); print_line("source path: "+path); Image src; Error err = ImageLoader::load_image(path,&src); if (err) { EditorNode::add_io_error("Couldn't load image: "+path); return err; } if (src.detect_alpha()) alpha=true; sources.push_back(src); } ep.step("Converting Images",sources.size()); for(int i=0;i<sources.size();i++) { if (alpha) { sources[i].convert(Image::FORMAT_RGBA); } else { sources[i].convert(Image::FORMAT_RGB); } } //texturepacker is not really good for optimizing, so.. //will at some point likely replace with my own //first, will find the nearest to a square packing int border=1; Vector<Size2i> src_sizes; Vector<Rect2> crops; ep.step("Cropping Images",sources.size()+1); for(int j=0;j<sources.size();j++) { Size2i s; if (crop) { Rect2 crop = sources[j].get_used_rect(); print_line("CROP: "+crop); s=crop.size; crops.push_back(crop); } else { s=Size2i(sources[j].get_width(),sources[j].get_height()); } s+=Size2i(border*2,border*2); src_sizes.push_back(s); //add a line to constraint width } Vector<Point2i> dst_positions; Size2i dst_size; EditorAtlas::fit(src_sizes,dst_positions,dst_size); print_line("size that workeD: "+itos(dst_size.width)+","+itos(dst_size.height)); ep.step("Blitting Images",sources.size()+2); Image atlas; atlas.create(nearest_power_of_2(dst_size.width),nearest_power_of_2(dst_size.height),0,alpha?Image::FORMAT_RGBA:Image::FORMAT_RGB); for(int i=0;i<sources.size();i++) { int x=dst_positions[i].x; int y=dst_positions[i].y; Ref<AtlasTexture> at = memnew( AtlasTexture ); Size2 sz = Size2(sources[i].get_width(),sources[i].get_height()); if (crop && sz!=crops[i].size) { Rect2 rect = crops[i]; rect.size=sz-rect.size; at->set_region(Rect2(x+border,y+border,crops[i].size.width,crops[i].size.height)); at->set_margin(rect); atlas.blit_rect(sources[i],crops[i],Point2(x+border,y+border)); } else { at->set_region(Rect2(x+border,y+border,sz.x,sz.y)); atlas.blit_rect(sources[i],Rect2(0,0,sources[i].get_width(),sources[i].get_height()),Point2(x+border,y+border)); } String apath = p_path.get_base_dir().plus_file(from->get_source_path(i).get_file().basename()+".atex"); print_line("Atlas Tex: "+apath); at->set_path(apath); atlases.push_back(at); } if (ResourceCache::has(p_path)) { texture = Ref<ImageTexture> ( ResourceCache::get(p_path)->cast_to<ImageTexture>() ); } else { texture = Ref<ImageTexture>( memnew( ImageTexture ) ); } texture->create_from_image(atlas,tex_flags); } else { ERR_FAIL_COND_V(from->get_source_count()!=1,ERR_INVALID_PARAMETER); String src_path = EditorImportPlugin::expand_source_path(from->get_source_path(0)); if (ResourceCache::has(p_path)) { Resource *r = ResourceCache::get(p_path); texture = Ref<ImageTexture> ( r->cast_to<ImageTexture>() ); Image img; Error err = img.load(src_path); ERR_FAIL_COND_V(err!=OK,ERR_CANT_OPEN); texture->create_from_image(img); } else { texture=ResourceLoader::load(src_path,"ImageTexture"); } ERR_FAIL_COND_V(texture.is_null(),ERR_CANT_OPEN); if (!p_external) from->set_source_md5(0,FileAccess::get_md5(src_path)); } int format=from->get_option("format"); float quality=from->get_option("quality"); if (!p_external) { from->set_editor(get_name()); texture->set_path(p_path); texture->set_import_metadata(from); } if (atlas) { if (p_external) { //used by exporter Array rects(true); for(int i=0;i<atlases.size();i++) { rects.push_back(atlases[i]->get_region()); rects.push_back(atlases[i]->get_margin()); } from->set_option("rects",rects); } else { //used by importer for(int i=0;i<atlases.size();i++) { String apath = atlases[i]->get_path(); atlases[i]->set_atlas(texture); Error err = ResourceSaver::save(apath,atlases[i]); if (err) { EditorNode::add_io_error("Couldn't save atlas image: "+apath); return err; } from->set_source_md5(i,FileAccess::get_md5(apath)); } } } if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS || format==IMAGE_FORMAT_COMPRESS_DISK_LOSSY) { Image image=texture->get_data(); ERR_FAIL_COND_V(image.empty(),ERR_INVALID_DATA); bool has_alpha=image.detect_alpha(); if (!has_alpha && image.get_format()==Image::FORMAT_RGBA) { image.convert(Image::FORMAT_RGB); } if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_FIX_BORDER_ALPHA) { image.fix_alpha_edges(); } if (shrink>1) { int orig_w=image.get_width(); int orig_h=image.get_height(); image.resize(orig_w/shrink,orig_h/shrink); texture->create_from_image(image,tex_flags); texture->set_size_override(Size2(orig_w,orig_h)); } else { texture->create_from_image(image,tex_flags); } if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS) { texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSLESS); } else { texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY); } texture->set_lossy_storage_quality(quality); Error err = ResourceSaver::save(p_path,texture); if (err!=OK) { EditorNode::add_io_error("Couldn't save converted texture: "+p_path); return err; } } else { print_line("compress..."); Image image=texture->get_data(); ERR_FAIL_COND_V(image.empty(),ERR_INVALID_DATA); bool has_alpha=image.detect_alpha(); if (!has_alpha && image.get_format()==Image::FORMAT_RGBA) { image.convert(Image::FORMAT_RGB); } if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_FIX_BORDER_ALPHA) { image.fix_alpha_edges(); } int orig_w=image.get_width(); int orig_h=image.get_height(); if (shrink>1) { image.resize(orig_w/shrink,orig_h/shrink); texture->create_from_image(image,tex_flags); texture->set_size_override(Size2(orig_w,orig_h)); } if (!(flags&IMAGE_FLAG_NO_MIPMAPS)) { image.generate_mipmaps(); } if (format!=IMAGE_FORMAT_UNCOMPRESSED) { compress_image(p_compr,image,flags&IMAGE_FLAG_COMPRESS_EXTRA); } print_line("COMPRESSED TO: "+itos(image.get_format())); texture->create_from_image(image,tex_flags); if (shrink>1) { texture->set_size_override(Size2(orig_w,orig_h)); } uint32_t save_flags=ResourceSaver::FLAG_COMPRESS; Error err = ResourceSaver::save(p_path,texture,save_flags); if (err!=OK) { EditorNode::add_io_error("Couldn't save converted texture: "+p_path); return err; } } return OK; }
void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Variant &r_ret,Variant::CallError &r_error) { r_error.error=Variant::CallError::CALL_OK; #ifdef DEBUG_ENABLED #define VALIDATE_ARG_COUNT(m_count) \ if (p_arg_count<m_count) {\ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;\ r_error.argument=m_count;\ r_ret=Variant();\ return;\ }\ if (p_arg_count>m_count) {\ r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;\ r_error.argument=m_count;\ r_ret=Variant();\ return;\ } #define VALIDATE_ARG_NUM(m_arg) \ if (!p_args[m_arg]->is_num()) {\ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;\ r_error.argument=m_arg;\ r_error.expected=Variant::REAL;\ r_ret=Variant();\ return;\ } #else #define VALIDATE_ARG_COUNT(m_count) #define VALIDATE_ARG_NUM(m_arg) #endif //using a switch, so the compiler generates a jumptable switch(p_func) { case MATH_SIN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::sin((double)*p_args[0]); } break; case MATH_COS: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::cos((double)*p_args[0]); } break; case MATH_TAN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::tan((double)*p_args[0]); } break; case MATH_SINH: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::sinh((double)*p_args[0]); } break; case MATH_COSH: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::cosh((double)*p_args[0]); } break; case MATH_TANH: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::tanh((double)*p_args[0]); } break; case MATH_ASIN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::asin((double)*p_args[0]); } break; case MATH_ACOS: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::acos((double)*p_args[0]); } break; case MATH_ATAN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::atan((double)*p_args[0]); } break; case MATH_ATAN2: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::atan2((double)*p_args[0],(double)*p_args[1]); } break; case MATH_SQRT: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::sqrt((double)*p_args[0]); } break; case MATH_FMOD: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::fmod((double)*p_args[0],(double)*p_args[1]); } break; case MATH_FPOSMOD: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::fposmod((double)*p_args[0],(double)*p_args[1]); } break; case MATH_FLOOR: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::floor((double)*p_args[0]); } break; case MATH_CEIL: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::ceil((double)*p_args[0]); } break; case MATH_ROUND: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::round((double)*p_args[0]); } break; case MATH_ABS: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()==Variant::INT) { int64_t i = *p_args[0]; r_ret=ABS(i); } else if (p_args[0]->get_type()==Variant::REAL) { double r = *p_args[0]; r_ret=Math::abs(r); } else { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::REAL; r_ret=Variant(); } } break; case MATH_SIGN: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()==Variant::INT) { int64_t i = *p_args[0]; r_ret= i < 0 ? -1 : ( i > 0 ? +1 : 0); } else if (p_args[0]->get_type()==Variant::REAL) { real_t r = *p_args[0]; r_ret= r < 0.0 ? -1.0 : ( r > 0.0 ? +1.0 : 0.0); } else { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::REAL; r_ret=Variant(); } } break; case MATH_POW: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::pow((double)*p_args[0],(double)*p_args[1]); } break; case MATH_LOG: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::log((double)*p_args[0]); } break; case MATH_EXP: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::exp((double)*p_args[0]); } break; case MATH_ISNAN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::is_nan((double)*p_args[0]); } break; case MATH_ISINF: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::is_inf((double)*p_args[0]); } break; case MATH_EASE: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::ease((double)*p_args[0],(double)*p_args[1]); } break; case MATH_DECIMALS: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::step_decimals((double)*p_args[0]); } break; case MATH_STEPIFY: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::stepify((double)*p_args[0],(double)*p_args[1]); } break; case MATH_LERP: { VALIDATE_ARG_COUNT(3); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); r_ret=Math::lerp((double)*p_args[0],(double)*p_args[1],(double)*p_args[2]); } break; case MATH_DECTIME: { VALIDATE_ARG_COUNT(3); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); r_ret=Math::dectime((double)*p_args[0],(double)*p_args[1],(double)*p_args[2]); } break; case MATH_RANDOMIZE: { Math::randomize(); r_ret=Variant(); } break; case MATH_RAND: { r_ret=Math::rand(); } break; case MATH_RANDF: { r_ret=Math::randf(); } break; case MATH_RANDOM: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::random((double)*p_args[0],(double)*p_args[1]); } break; case MATH_SEED: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); uint64_t seed=*p_args[0]; Math::seed(seed); r_ret=Variant(); } break; case MATH_RANDSEED: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); uint64_t seed=*p_args[0]; int ret = Math::rand_from_seed(&seed); Array reta; reta.push_back(ret); reta.push_back(seed); r_ret=reta; } break; case MATH_DEG2RAD: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::deg2rad((double)*p_args[0]); } break; case MATH_RAD2DEG: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::rad2deg((double)*p_args[0]); } break; case MATH_LINEAR2DB: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::linear2db((double)*p_args[0]); } break; case MATH_DB2LINEAR: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::db2linear((double)*p_args[0]); } break; case LOGIC_MAX: { VALIDATE_ARG_COUNT(2); if (p_args[0]->get_type()==Variant::INT && p_args[1]->get_type()==Variant::INT) { int64_t a = *p_args[0]; int64_t b = *p_args[1]; r_ret=MAX(a,b); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); real_t a = *p_args[0]; real_t b = *p_args[1]; r_ret=MAX(a,b); } } break; case LOGIC_MIN: { VALIDATE_ARG_COUNT(2); if (p_args[0]->get_type()==Variant::INT && p_args[1]->get_type()==Variant::INT) { int64_t a = *p_args[0]; int64_t b = *p_args[1]; r_ret=MIN(a,b); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); real_t a = *p_args[0]; real_t b = *p_args[1]; r_ret=MIN(a,b); } } break; case LOGIC_CLAMP: { VALIDATE_ARG_COUNT(3); if (p_args[0]->get_type()==Variant::INT && p_args[1]->get_type()==Variant::INT && p_args[2]->get_type()==Variant::INT) { int64_t a = *p_args[0]; int64_t b = *p_args[1]; int64_t c = *p_args[2]; r_ret=CLAMP(a,b,c); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); real_t a = *p_args[0]; real_t b = *p_args[1]; real_t c = *p_args[2]; r_ret=CLAMP(a,b,c); } } break; case LOGIC_NEAREST_PO2: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); int64_t num = *p_args[0]; r_ret = nearest_power_of_2(num); } break; case OBJ_WEAKREF: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()!=Variant::OBJECT) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; r_ret=Variant(); return; } if (p_args[0]->is_ref()) { REF r = *p_args[0]; if (!r.is_valid()) { r_ret=Variant(); return; } Ref<WeakRef> wref = memnew( WeakRef ); wref->set_ref(r); r_ret=wref; } else { Object *obj = *p_args[0]; if (!obj) { r_ret=Variant(); return; } Ref<WeakRef> wref = memnew( WeakRef ); wref->set_obj(obj); r_ret=wref; } } break; case FUNC_FUNCREF: { VALIDATE_ARG_COUNT(2); if (p_args[0]->get_type()!=Variant::OBJECT) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; r_ret=Variant(); return; } if (p_args[1]->get_type()!=Variant::STRING && p_args[1]->get_type()!=Variant::NODE_PATH) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=1; r_error.expected=Variant::STRING; r_ret=Variant(); return; } Ref<FuncRef> fr = memnew( FuncRef); fr->set_instance(*p_args[0]); fr->set_function(*p_args[1]); r_ret=fr; } break; case TYPE_CONVERT: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(1); int type=*p_args[1]; if (type<0 || type>=Variant::VARIANT_MAX) { r_ret=RTR("Invalid type argument to convert(), use TYPE_* constants."); r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::INT; return; } else { r_ret=Variant::construct(Variant::Type(type),p_args,1,r_error); } } break; case TYPE_OF: { VALIDATE_ARG_COUNT(1); r_ret = p_args[0]->get_type(); } break; case TYPE_EXISTS: { VALIDATE_ARG_COUNT(1); r_ret = ClassDB::class_exists(*p_args[0]); } break; case TEXT_CHAR: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); CharType result[2] = {*p_args[0], 0}; r_ret=String(result); } break; case TEXT_STR: { String str; for(int i=0;i<p_arg_count;i++) { String os = p_args[i]->operator String(); if (i==0) str=os; else str+=os; } r_ret=str; } break; case TEXT_PRINT: { String str; for(int i=0;i<p_arg_count;i++) { str+=p_args[i]->operator String(); } //str+="\n"; print_line(str); r_ret=Variant(); } break; case TEXT_PRINT_TABBED: { String str; for(int i=0;i<p_arg_count;i++) { if (i) str+="\t"; str+=p_args[i]->operator String(); } //str+="\n"; print_line(str); r_ret=Variant(); } break; case TEXT_PRINT_SPACED: { String str; for(int i=0;i<p_arg_count;i++) { if (i) str+=" "; str+=p_args[i]->operator String(); } //str+="\n"; print_line(str); r_ret=Variant(); } break; case TEXT_PRINTERR: { String str; for(int i=0;i<p_arg_count;i++) { str+=p_args[i]->operator String(); } //str+="\n"; OS::get_singleton()->printerr("%s\n",str.utf8().get_data()); r_ret=Variant(); } break; case TEXT_PRINTRAW: { String str; for(int i=0;i<p_arg_count;i++) { str+=p_args[i]->operator String(); } //str+="\n"; OS::get_singleton()->print("%s",str.utf8().get_data()); r_ret=Variant(); } break; case VAR_TO_STR: { VALIDATE_ARG_COUNT(1); String vars; VariantWriter::write_to_string(*p_args[0],vars); r_ret=vars; } break; case STR_TO_VAR: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()!=Variant::STRING) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::STRING; r_ret=Variant(); return; } VariantParser::StreamString ss; ss.s=*p_args[0]; String errs; int line; Error err = VariantParser::parse(&ss,r_ret,errs,line); if (err!=OK) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::STRING; r_ret="Parse error at line "+itos(line)+": "+errs; return; } } break; case VAR_TO_BYTES: { VALIDATE_ARG_COUNT(1); PoolByteArray barr; int len; Error err = encode_variant(*p_args[0],NULL,len); if (err) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::NIL; r_ret="Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."; return; } barr.resize(len); { PoolByteArray::Write w = barr.write(); encode_variant(*p_args[0],w.ptr(),len); } r_ret=barr; } break; case BYTES_TO_VAR: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()!=Variant::POOL_BYTE_ARRAY) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::POOL_BYTE_ARRAY; r_ret=Variant(); return; } PoolByteArray varr=*p_args[0]; Variant ret; { PoolByteArray::Read r=varr.read(); Error err = decode_variant(ret,r.ptr(),varr.size(),NULL); if (err!=OK) { r_ret=RTR("Not enough bytes for decoding bytes, or invalid format."); r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::POOL_BYTE_ARRAY; return; } } r_ret=ret; } break; case GEN_RANGE: { switch(p_arg_count) { case 0: { r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument=1; r_ret=Variant(); } break; case 1: { VALIDATE_ARG_NUM(0); int count=*p_args[0]; Array arr; if (count<=0) { r_ret=arr; return; } Error err = arr.resize(count); if (err!=OK) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_ret=Variant(); return; } for(int i=0;i<count;i++) { arr[i]=i; } r_ret=arr; } break; case 2: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); int from=*p_args[0]; int to=*p_args[1]; Array arr; if (from>=to) { r_ret=arr; return; } Error err = arr.resize(to-from); if (err!=OK) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_ret=Variant(); return; } for(int i=from;i<to;i++) arr[i-from]=i; r_ret=arr; } break; case 3: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); int from=*p_args[0]; int to=*p_args[1]; int incr=*p_args[2]; if (incr==0) { r_ret=RTR("step argument is zero!"); r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; return; } Array arr; if (from>=to && incr>0) { r_ret=arr; return; } if (from<=to && incr<0) { r_ret=arr; return; } //calculate how many int count=0; if (incr>0) { count=((to-from-1)/incr)+1; } else { count=((from-to-1)/-incr)+1; } Error err = arr.resize(count); if (err!=OK) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_ret=Variant(); return; } if (incr>0) { int idx=0; for(int i=from;i<to;i+=incr) { arr[idx++]=i; } } else { int idx=0; for(int i=from;i>to;i+=incr) { arr[idx++]=i; } } r_ret=arr; } break; default: { r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_error.argument=3; r_ret=Variant(); } break; } } break; case RESOURCE_LOAD: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()!=Variant::STRING) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::STRING; r_ret=Variant(); } else { r_ret=ResourceLoader::load(*p_args[0]); } } break; case INST2DICT: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()==Variant::NIL) { r_ret=Variant(); } else if (p_args[0]->get_type()!=Variant::OBJECT) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_ret=Variant(); } else { Object *obj = *p_args[0]; if (!obj) { r_ret=Variant(); } else if (!obj->get_script_instance() || obj->get_script_instance()->get_language()!=GDScriptLanguage::get_singleton()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::DICTIONARY; r_ret=RTR("Not a script with an instance"); return; } else { GDInstance *ins = static_cast<GDInstance*>(obj->get_script_instance()); Ref<GDScript> base = ins->get_script(); if (base.is_null()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::DICTIONARY; r_ret=RTR("Not based on a script"); return; } GDScript *p = base.ptr(); Vector<StringName> sname; while(p->_owner) { sname.push_back(p->name); p=p->_owner; } sname.invert(); if (!p->path.is_resource_file()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::DICTIONARY; r_ret=Variant(); r_ret=RTR("Not based on a resource file"); return; } NodePath cp(sname,Vector<StringName>(),false); Dictionary d; d["@subpath"]=cp; d["@path"]=p->path; p = base.ptr(); while(p) { for(Set<StringName>::Element *E=p->members.front();E;E=E->next()) { Variant value; if (ins->get(E->get(),value)) { String k = E->get(); if (!d.has(k)) { d[k]=value; } } } p=p->_base; } r_ret=d; } } } break; case DICT2INST: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()!=Variant::DICTIONARY) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::DICTIONARY; r_ret=Variant(); return; } Dictionary d = *p_args[0]; if (!d.has("@path")) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; r_ret=RTR("Invalid instance dictionary format (missing @path)"); return; } Ref<Script> scr = ResourceLoader::load(d["@path"]); if (!scr.is_valid()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; r_ret=RTR("Invalid instance dictionary format (can't load script at @path)"); return; } Ref<GDScript> gdscr = scr; if (!gdscr.is_valid()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; r_ret=Variant(); r_ret=RTR("Invalid instance dictionary format (invalid script at @path)"); return; } NodePath sub; if (d.has("@subpath")) { sub=d["@subpath"]; } for(int i=0;i<sub.get_name_count();i++) { gdscr = gdscr->subclasses[ sub.get_name(i)]; if (!gdscr.is_valid()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; r_ret=Variant(); r_ret=RTR("Invalid instance dictionary (invalid subclasses)"); return; } } r_ret = gdscr->_new(NULL,0,r_error); GDInstance *ins = static_cast<GDInstance*>(static_cast<Object*>(r_ret)->get_script_instance()); Ref<GDScript> gd_ref = ins->get_script(); for(Map<StringName,GDScript::MemberInfo>::Element *E = gd_ref->member_indices.front(); E; E = E->next()) { if(d.has(E->key())) { ins->members[E->get().index] = d[E->key()]; } } } break; case VALIDATE_JSON: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()!=Variant::STRING) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::STRING; r_ret=Variant(); return; } String errs; int errl; Error err = JSON::parse(*p_args[0],r_ret,errs,errl); if (err!=OK) { r_ret=itos(errl)+":"+errs; } else { r_ret=""; } } break; case PARSE_JSON: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()!=Variant::STRING) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::STRING; r_ret=Variant(); return; } String errs; int errl; Error err = JSON::parse(*p_args[0],r_ret,errs,errl); if (err!=OK) { r_ret=Variant(); } } break; case TO_JSON: { VALIDATE_ARG_COUNT(1); r_ret = JSON::print(*p_args[0]); } break; case HASH: { VALIDATE_ARG_COUNT(1); r_ret=p_args[0]->hash(); } break; case COLOR8: { if (p_arg_count<3) { r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument=3; r_ret=Variant(); return; } if (p_arg_count>4) { r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_error.argument=4; r_ret=Variant(); return; } VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); Color color((float)*p_args[0]/255.0f,(float)*p_args[1]/255.0f,(float)*p_args[2]/255.0f); if (p_arg_count==4) { VALIDATE_ARG_NUM(3); color.a=(float)*p_args[3]/255.0f; } r_ret=color; } break; case COLORN: { if (p_arg_count<1) { r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument=1; r_ret=Variant(); return; } if (p_arg_count>2) { r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_error.argument=2; r_ret=Variant(); return; } if (p_args[0]->get_type()!=Variant::STRING) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_ret=Variant(); } else { Color color = Color::named(*p_args[0]); if (p_arg_count==2) { VALIDATE_ARG_NUM(1); color.a=*p_args[1]; } r_ret=color; } } break; case PRINT_STACK: { ScriptLanguage* script = GDScriptLanguage::get_singleton(); for (int i=0; i < script->debug_get_stack_level_count(); i++) { print_line("Frame "+itos(i)+" - "+script->debug_get_stack_level_source(i)+":"+itos(script->debug_get_stack_level_line(i))+" in function '"+script->debug_get_stack_level_function(i)+"'"); }; } break; case INSTANCE_FROM_ID: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()!=Variant::INT && p_args[0]->get_type()!=Variant::REAL) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::INT; r_ret=Variant(); break; } uint32_t id=*p_args[0]; r_ret=ObjectDB::get_instance(id); } break; case FUNC_MAX: { ERR_FAIL(); } break; } }
void DynamicFontAtSize::_update_char(CharType p_char) { if (char_map.has(p_char)) return; font->lock(); int w,h,xofs,yofs; unsigned char * cpbitmap = stbtt_GetCodepointBitmap(&font->info, scale, scale, p_char, &w, &h, &xofs, &yofs ); if (!cpbitmap) { //no glyph int advance; stbtt_GetCodepointHMetrics(&font->info, p_char, &advance, 0); //print_line("char has no bitmap: "+itos(p_char)+" but advance is "+itos(advance*scale)); Character ch; ch.texture_idx=-1; ch.advance=advance*scale; ch.h_align=0; ch.v_align=0; char_map[p_char]=ch; font->unlock(); return; } int mw=w+rect_margin*2; int mh=h+rect_margin*2; if (mw>4096 || mh>4096) { stbtt_FreeBitmap(cpbitmap,NULL); font->unlock(); ERR_FAIL_COND(mw>4096); ERR_FAIL_COND(mh>4096); } //find a texture to fit this... int tex_index=-1; int tex_x=0; int tex_y=0; for(int i=0;i<textures.size();i++) { CharTexture &ct=textures[i]; if (mw > ct.texture_size || mh > ct.texture_size) //too big for this texture continue; tex_y=0x7FFFFFFF; tex_x=0; for(int j=0;j<ct.texture_size-mw;j++) { int max_y=0; for(int k=j;k<j+mw;k++) { int y = ct.offsets[k]; if (y>max_y) max_y=y; } if (max_y<tex_y) { tex_y=max_y; tex_x=j; } } if (tex_y==0x7FFFFFFF || tex_y+mh > ct.texture_size) continue; //fail, could not fit it here tex_index=i; break; } // print_line("CHAR: "+String::chr(p_char)+" TEX INDEX: "+itos(tex_index)+" X: "+itos(tex_x)+" Y: "+itos(tex_y)); if (tex_index==-1) { //could not find texture to fit, create one int texsize = MAX(size*8,256); if (mw>texsize) texsize=mw; //special case, adapt to it? if (mh>texsize) texsize=mh; //special case, adapt to it? texsize=nearest_power_of_2(texsize); texsize=MIN(texsize,4096); CharTexture tex; tex.texture_size=texsize; tex.imgdata.resize(texsize*texsize*2); //grayscale alpha { //zero texture DVector<uint8_t>::Write w = tex.imgdata.write(); for(int i=0;i<texsize*texsize*2;i++) { w[i]=0; } } tex.offsets.resize(texsize); for(int i=0;i<texsize;i++) //zero offsets tex.offsets[i]=0; textures.push_back(tex); tex_index=textures.size()-1; } //fit character in char texture CharTexture &tex=textures[tex_index]; { DVector<uint8_t>::Write wr = tex.imgdata.write(); for(int i=0;i<h;i++) { for(int j=0;j<w;j++) { int ofs = ( (i+tex_y+rect_margin)*tex.texture_size+j+tex_x+rect_margin)*2; wr[ofs+0]=255; //grayscale as 1 wr[ofs+1]=cpbitmap[i*w+j]; //alpha as 0 } } } //blit to image and texture { Image img(tex.texture_size,tex.texture_size,0,Image::FORMAT_GRAYSCALE_ALPHA,tex.imgdata); if (tex.texture.is_null()) { tex.texture.instance(); tex.texture->create_from_image(img,Texture::FLAG_FILTER); } else { tex.texture->set_data(img); //update } } // update height array for(int k=tex_x;k<tex_x+mw;k++) { tex.offsets[k]=tex_y+mh; } int advance; stbtt_GetCodepointHMetrics(&font->info, p_char, &advance, 0); Character chr; chr.h_align=xofs; chr.v_align=yofs + get_ascent(); chr.advance=advance*scale; chr.texture_idx=tex_index; chr.rect=Rect2(tex_x+rect_margin,tex_y+rect_margin,w,h); //print_line("CHAR: "+String::chr(p_char)+" TEX INDEX: "+itos(tex_index)+" RECT: "+chr.rect+" X OFS: "+itos(xofs)+" Y OFS: "+itos(yofs)); char_map[p_char]=chr; stbtt_FreeBitmap(cpbitmap,NULL); font->unlock(); }
Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<ResourceImportMetadata>& p_from,EditorExportPlatform::ImageCompression p_compr, bool p_external){ ERR_FAIL_COND_V(p_from->get_source_count()==0,ERR_INVALID_PARAMETER); Ref<ResourceImportMetadata> from=p_from; Ref<ImageTexture> texture; Vector<Ref<AtlasTexture> > atlases; bool atlas = from->get_option("atlas"); bool large = from->get_option("large"); int flags=from->get_option("flags"); int format=from->get_option("format"); float quality=from->get_option("quality"); uint32_t tex_flags=0; if (flags&EditorTextureImportPlugin::IMAGE_FLAG_REPEAT) tex_flags|=Texture::FLAG_REPEAT; if (flags&EditorTextureImportPlugin::IMAGE_FLAG_FILTER) tex_flags|=Texture::FLAG_FILTER; if (!(flags&EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS)) tex_flags|=Texture::FLAG_MIPMAPS; if (flags&EditorTextureImportPlugin::IMAGE_FLAG_CONVERT_TO_LINEAR) tex_flags|=Texture::FLAG_CONVERT_TO_LINEAR; if (flags&EditorTextureImportPlugin::IMAGE_FLAG_USE_ANISOTROPY) tex_flags|=Texture::FLAG_ANISOTROPIC_FILTER; print_line("path: "+p_path+" flags: "+itos(tex_flags)); float shrink=1; if (from->has_option("shrink")) shrink=from->get_option("shrink"); if (large) { ERR_FAIL_COND_V(from->get_source_count()!=1,ERR_INVALID_PARAMETER); String src_path = EditorImportPlugin::expand_source_path(from->get_source_path(0)); int cell_size=from->get_option("large_cell_size"); ERR_FAIL_COND_V(cell_size<128 || cell_size>16384,ERR_CANT_OPEN); EditorProgress pg("ltex","Import Large Texture",3); pg.step("Load Source Image",0); Image img; Error err = ImageLoader::load_image(src_path,&img); if (err) { return err; } pg.step("Slicing",1); Map<Vector2,Image> pieces; for(int i=0;i<img.get_width();i+=cell_size) { int w = MIN(img.get_width()-i,cell_size); for(int j=0;j<img.get_height();j+=cell_size) { int h = MIN(img.get_height()-j,cell_size); Image piece(w,h,0,img.get_format()); piece.blit_rect(img,Rect2(i,j,w,h),Point2(0,0)); if (!piece.is_invisible()) { pieces[Vector2(i,j)]=piece; //print_line("ADDING PIECE AT "+Vector2(i,j)); } } } Ref<LargeTexture> existing; if (ResourceCache::has(p_path)) { existing = ResourceCache::get(p_path); } if (existing.is_valid()) { existing->clear(); } else { existing = Ref<LargeTexture>(memnew( LargeTexture )); } existing->set_size(Size2(img.get_width(),img.get_height())); pg.step("Inserting",2); for (Map<Vector2,Image>::Element *E=pieces.front();E;E=E->next()) { Ref<ImageTexture> imgtex = Ref<ImageTexture>( memnew( ImageTexture ) ); imgtex->create_from_image(E->get(),tex_flags); _process_texture_data(imgtex,format,quality,flags,p_compr,tex_flags,shrink); existing->add_piece(E->key(),imgtex); } if (!p_external) { from->set_editor(get_name()); existing->set_path(p_path); existing->set_import_metadata(from); } pg.step("Saving",3); err = ResourceSaver::save(p_path,existing); if (err!=OK) { EditorNode::add_io_error("Couldn't save large texture: "+p_path); return err; } return OK; } else if (atlas) { //prepare atlas! Vector< Image > sources; Vector< Image > tsources; bool alpha=false; bool crop = from->get_option("crop"); EditorProgress ep("make_atlas","Build Atlas For: "+p_path.get_file(),from->get_source_count()+3); print_line("sources: "+itos(from->get_source_count())); for(int i=0;i<from->get_source_count();i++) { String path = EditorImportPlugin::expand_source_path(from->get_source_path(i)); String md5 = FileAccess::get_md5(path); from->set_source_md5(i,FileAccess::get_md5(path)); ep.step("Loading Image: "+path,i); print_line("source path: "+path+" md5 "+md5); Image src; Error err = ImageLoader::load_image(path,&src); if (err) { EditorNode::add_io_error("Couldn't load image: "+path); return err; } if (src.detect_alpha()) alpha=true; tsources.push_back(src); } ep.step("Converting Images",sources.size()); int base_index=0; Map<uint64_t,int> source_md5; Map<int,List<int> > source_map; for(int i=0;i<tsources.size();i++) { Image src = tsources[i]; if (alpha) { src.convert(Image::FORMAT_RGBA); } else { src.convert(Image::FORMAT_RGB); } DVector<uint8_t> data = src.get_data(); MD5_CTX md5; DVector<uint8_t>::Read r=data.read(); MD5Init(&md5); int len=data.size(); for(int j=0;j<len;j++) { uint8_t b = r[j]; b>>=2; //to aid in comparing MD5Update(&md5,(unsigned char*)&b,1); } MD5Final(&md5); uint64_t *cmp = (uint64_t*)md5.digest; //less bits, but still useful for this tsources[i]=Image(); //clear if (source_md5.has(*cmp)) { int sidx=source_md5[*cmp]; source_map[sidx].push_back(i); print_line("REUSING "+from->get_source_path(i)); } else { int sidx=sources.size(); source_md5[*cmp]=sidx; sources.push_back(src); List<int> sm; sm.push_back(i); source_map[sidx]=sm; } } //texturepacker is not really good for optimizing, so.. //will at some point likely replace with my own //first, will find the nearest to a square packing int border=1; Vector<Size2i> src_sizes; Vector<Rect2> crops; ep.step("Cropping Images",sources.size()+1); for(int j=0;j<sources.size();j++) { Size2i s; if (crop) { Rect2 crop = sources[j].get_used_rect(); print_line("CROP: "+crop); s=crop.size; crops.push_back(crop); } else { s=Size2i(sources[j].get_width(),sources[j].get_height()); } s+=Size2i(border*2,border*2); src_sizes.push_back(s); //add a line to constraint width } Vector<Point2i> dst_positions; Size2i dst_size; EditorAtlas::fit(src_sizes,dst_positions,dst_size); print_line("size that workeD: "+itos(dst_size.width)+","+itos(dst_size.height)); ep.step("Blitting Images",sources.size()+2); bool blit_to_po2=tex_flags&Texture::FLAG_MIPMAPS; int atlas_w=dst_size.width; int atlas_h=dst_size.height; if (blit_to_po2) { atlas_w=nearest_power_of_2(dst_size.width); atlas_h=nearest_power_of_2(dst_size.height); } Image atlas; atlas.create(atlas_w,atlas_h,0,alpha?Image::FORMAT_RGBA:Image::FORMAT_RGB); atlases.resize(from->get_source_count()); for(int i=0;i<sources.size();i++) { int x=dst_positions[i].x; int y=dst_positions[i].y; Size2 sz = Size2(sources[i].get_width(),sources[i].get_height()); Rect2 region; Rect2 margin; if (crop && sz!=crops[i].size) { Rect2 rect = crops[i]; rect.size=sz-rect.size; region=Rect2(x+border,y+border,crops[i].size.width,crops[i].size.height); margin=rect; atlas.blit_rect(sources[i],crops[i],Point2(x+border,y+border)); } else { region=Rect2(x+border,y+border,sz.x,sz.y); atlas.blit_rect(sources[i],Rect2(0,0,sources[i].get_width(),sources[i].get_height()),Point2(x+border,y+border)); } ERR_CONTINUE( !source_map.has(i) ); for (List<int>::Element *E=source_map[i].front();E;E=E->next()) { String apath = p_path.get_base_dir().plus_file(from->get_source_path(E->get()).get_file().basename()+".atex"); Ref<AtlasTexture> at; if (ResourceCache::has(apath)) { at = Ref<AtlasTexture>( ResourceCache::get(apath)->cast_to<AtlasTexture>() ); } else { at = Ref<AtlasTexture>( memnew( AtlasTexture ) ); } at->set_region(region); at->set_margin(margin); at->set_path(apath); atlases[E->get()]=at; print_line("Atlas Tex: "+apath); } } if (ResourceCache::has(p_path)) { texture = Ref<ImageTexture> ( ResourceCache::get(p_path)->cast_to<ImageTexture>() ); } else { texture = Ref<ImageTexture>( memnew( ImageTexture ) ); } texture->create_from_image(atlas,tex_flags); } else {
void Geometry::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size) { //super simple, almost brute force scanline stacking fitter //it's pretty basic for now, but it tries to make sure that the aspect ratio of the //resulting atlas is somehow square. This is necessary because video cards have limits //on texture size (usually 2048 or 4096), so the more square a texture, the more chances //it will work in every hardware. // for example, it will prioritize a 1024x1024 atlas (works everywhere) instead of a // 256x8192 atlas (won't work anywhere). ERR_FAIL_COND(p_rects.size() == 0); Vector<_AtlasWorkRect> wrects; wrects.resize(p_rects.size()); for (int i = 0; i < p_rects.size(); i++) { wrects[i].s = p_rects[i]; wrects[i].idx = i; } wrects.sort(); int widest = wrects[0].s.width; Vector<_AtlasWorkRectResult> results; for (int i = 0; i <= 12; i++) { int w = 1 << i; int max_h = 0; int max_w = 0; if (w < widest) continue; Vector<int> hmax; hmax.resize(w); for (int j = 0; j < w; j++) hmax[j] = 0; //place them int ofs = 0; int limit_h = 0; for (int j = 0; j < wrects.size(); j++) { if (ofs + wrects[j].s.width > w) { ofs = 0; } int from_y = 0; for (int k = 0; k < wrects[j].s.width; k++) { if (hmax[ofs + k] > from_y) from_y = hmax[ofs + k]; } wrects[j].p.x = ofs; wrects[j].p.y = from_y; int end_h = from_y + wrects[j].s.height; int end_w = ofs + wrects[j].s.width; if (ofs == 0) limit_h = end_h; for (int k = 0; k < wrects[j].s.width; k++) { hmax[ofs + k] = end_h; } if (end_h > max_h) max_h = end_h; if (end_w > max_w) max_w = end_w; if (ofs == 0 || end_h > limit_h) //while h limit not reached, keep stacking ofs += wrects[j].s.width; } _AtlasWorkRectResult result; result.result = wrects; result.max_h = max_h; result.max_w = max_w; results.push_back(result); } //find the result with the best aspect ratio int best = -1; real_t best_aspect = 1e20; for (int i = 0; i < results.size(); i++) { real_t h = nearest_power_of_2(results[i].max_h); real_t w = nearest_power_of_2(results[i].max_w); real_t aspect = h > w ? h / w : w / h; if (aspect < best_aspect) { best = i; best_aspect = aspect; } } r_result.resize(p_rects.size()); for (int i = 0; i < p_rects.size(); i++) { r_result[results[best].result[i].idx] = results[best].result[i].p; } r_size = Size2(results[best].max_w, results[best].max_h); }
Error AudioDriverRtAudio::init() { active=false; mutex=NULL; dac = memnew( RtAudio ); ERR_EXPLAIN("Cannot initialize RtAudio audio driver: No devices present.") ERR_FAIL_COND_V( dac->getDeviceCount() < 1, ERR_UNAVAILABLE ); String channels = GLOBAL_DEF("audio/output","stereo"); if (channels=="5.1") output_format=OUTPUT_5_1; else if (channels=="quad") output_format=OUTPUT_QUAD; else if (channels=="mono") output_format=OUTPUT_MONO; else output_format=OUTPUT_STEREO; RtAudio::StreamParameters parameters; parameters.deviceId = dac->getDefaultOutputDevice(); RtAudio::StreamOptions options; // options. // RtAudioStreamFlags flags; /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE). */// // unsigned int numberOfBuffers; /*!< Number of stream buffers. */ // std::string streamName; /*!< A stream name (currently used only in Jack). */ // int priority; /*!< Scheduling priority of callback thread (only used with flag RTAUDIO_SCHEDULE_REALTIME). */ parameters.firstChannel = 0; mix_rate = GLOBAL_DEF("audio/mix_rate",44100); int latency = GLOBAL_DEF("audio/output_latency",25); unsigned int buffer_size = nearest_power_of_2( latency * mix_rate / 1000 ); if (OS::get_singleton()->is_stdout_verbose()) { print_line("audio buffer size: "+itos(buffer_size)); } // bool success=false; while( true) { switch(output_format) { case OUTPUT_MONO: parameters.nChannels = 1; break; case OUTPUT_STEREO: parameters.nChannels = 2; break; case OUTPUT_QUAD: parameters.nChannels = 4; break; case OUTPUT_5_1: parameters.nChannels = 6; break; }; try { dac->openStream( ¶meters, NULL, RTAUDIO_SINT32, mix_rate, &buffer_size, &callback, this,&options ); mutex = Mutex::create(true); active=true; break; } catch ( RtAudioError& e ) { // try with less channels ERR_PRINT("Unable to open audio, retrying with fewer channels.."); switch(output_format) { case OUTPUT_MONO: ERR_EXPLAIN("Unable to open audio."); ERR_FAIL_V( ERR_UNAVAILABLE ); break; case OUTPUT_STEREO: output_format=OUTPUT_MONO; break; case OUTPUT_QUAD: output_format=OUTPUT_STEREO; break; case OUTPUT_5_1: output_format=OUTPUT_QUAD; break; }; } } return OK; }
void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Variant &r_ret,Variant::CallError &r_error) { r_error.error=Variant::CallError::CALL_OK; #ifdef DEBUG_ENABLED #define VALIDATE_ARG_COUNT(m_count) \ if (p_arg_count<m_count) {\ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;\ r_error.argument=m_count;\ return;\ }\ if (p_arg_count>m_count) {\ r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;\ r_error.argument=m_count;\ return;\ } #define VALIDATE_ARG_NUM(m_arg) \ if (!p_args[m_arg]->is_num()) {\ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;\ r_error.argument=m_arg;\ r_error.expected=Variant::REAL;\ return;\ } #else #define VALIDATE_ARG_COUNT(m_count) #define VALIDATE_ARG_NUM(m_arg) #endif //using a switch, so the compiler generates a jumptable switch(p_func) { case MATH_SIN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::sin(*p_args[0]); } break; case MATH_COS: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::cos(*p_args[0]); } break; case MATH_TAN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::tan(*p_args[0]); } break; case MATH_SINH: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::sinh(*p_args[0]); } break; case MATH_COSH: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::cosh(*p_args[0]); } break; case MATH_TANH: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::tanh(*p_args[0]); } break; case MATH_ASIN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::asin(*p_args[0]); } break; case MATH_ACOS: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::acos(*p_args[0]); } break; case MATH_ATAN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::atan(*p_args[0]); } break; case MATH_ATAN2: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::atan2(*p_args[0],*p_args[1]); } break; case MATH_SQRT: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::sqrt(*p_args[0]); } break; case MATH_FMOD: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::fmod(*p_args[0],*p_args[1]); } break; case MATH_FPOSMOD: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::fposmod(*p_args[0],*p_args[1]); } break; case MATH_FLOOR: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::floor(*p_args[0]); } break; case MATH_CEIL: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::ceil(*p_args[0]); } break; case MATH_ROUND: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::round(*p_args[0]); } break; case MATH_ABS: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()==Variant::INT) { int64_t i = *p_args[0]; r_ret=ABS(i); } else if (p_args[0]->get_type()==Variant::REAL) { real_t r = *p_args[0]; r_ret=Math::abs(r); } else { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::REAL; } } break; case MATH_SIGN: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()==Variant::INT) { int64_t i = *p_args[0]; r_ret= i < 0 ? -1 : ( i > 0 ? +1 : 0); } else if (p_args[0]->get_type()==Variant::REAL) { real_t r = *p_args[0]; r_ret= r < 0.0 ? -1.0 : ( r > 0.0 ? +1.0 : 0.0); } else { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::REAL; } } break; case MATH_POW: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::pow(*p_args[0],*p_args[1]); } break; case MATH_LOG: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::log(*p_args[0]); } break; case MATH_EXP: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::exp(*p_args[0]); } break; case MATH_ISNAN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::is_nan(*p_args[0]); } break; case MATH_ISINF: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::is_inf(*p_args[0]); } break; case MATH_EASE: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::ease(*p_args[0],*p_args[1]); } break; case MATH_DECIMALS: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::decimals(*p_args[0]); } break; case MATH_STEPIFY: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::stepify(*p_args[0],*p_args[1]); } break; case MATH_LERP: { VALIDATE_ARG_COUNT(3); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); r_ret=Math::lerp(*p_args[0],*p_args[1],*p_args[2]); } break; case MATH_DECTIME: { VALIDATE_ARG_COUNT(3); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); r_ret=Math::dectime(*p_args[0],*p_args[1],*p_args[2]); } break; case MATH_RANDOMIZE: { Math::randomize(); r_ret=Variant(); } break; case MATH_RAND: { r_ret=Math::rand(); } break; case MATH_RANDF: { r_ret=Math::randf(); } break; case MATH_RANDOM: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::random(*p_args[0],*p_args[1]); } break; case MATH_RANDSEED: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); uint32_t seed=*p_args[0]; int ret = Math::rand_from_seed(&seed); Array reta; reta.push_back(ret); reta.push_back(seed); r_ret=reta; } break; case MATH_DEG2RAD: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::deg2rad(*p_args[0]); } break; case MATH_RAD2DEG: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::rad2deg(*p_args[0]); } break; case MATH_LINEAR2DB: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::linear2db(*p_args[0]); } break; case MATH_DB2LINEAR: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::db2linear(*p_args[0]); } break; case LOGIC_MAX: { VALIDATE_ARG_COUNT(2); if (p_args[0]->get_type()==Variant::INT && p_args[1]->get_type()==Variant::INT) { int64_t a = *p_args[0]; int64_t b = *p_args[1]; r_ret=MAX(a,b); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); real_t a = *p_args[0]; real_t b = *p_args[1]; r_ret=MAX(a,b); } } break; case LOGIC_MIN: { VALIDATE_ARG_COUNT(2); if (p_args[0]->get_type()==Variant::INT && p_args[1]->get_type()==Variant::INT) { int64_t a = *p_args[0]; int64_t b = *p_args[1]; r_ret=MIN(a,b); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); real_t a = *p_args[0]; real_t b = *p_args[1]; r_ret=MIN(a,b); } } break; case LOGIC_CLAMP: { VALIDATE_ARG_COUNT(3); if (p_args[0]->get_type()==Variant::INT && p_args[1]->get_type()==Variant::INT && p_args[2]->get_type()==Variant::INT) { int64_t a = *p_args[0]; int64_t b = *p_args[1]; int64_t c = *p_args[2]; r_ret=CLAMP(a,b,c); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); real_t a = *p_args[0]; real_t b = *p_args[1]; real_t c = *p_args[2]; r_ret=CLAMP(a,b,c); } } break; case LOGIC_NEAREST_PO2: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); int64_t num = *p_args[0]; r_ret = nearest_power_of_2(num); } break; case OBJ_WEAKREF: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()!=Variant::OBJECT) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; return; } if (p_args[0]->is_ref()) { REF r = *p_args[0]; if (!r.is_valid()) { r_ret=Variant(); return; } Ref<WeakRef> wref = memnew( WeakRef ); wref->set_ref(r); r_ret=wref; } else { Object *obj = *p_args[0]; if (!obj) { r_ret=Variant(); return; } Ref<WeakRef> wref = memnew( WeakRef ); wref->set_obj(obj); r_ret=wref; } } break; case FUNC_FUNCREF: { VALIDATE_ARG_COUNT(2); if (p_args[0]->get_type()!=Variant::OBJECT) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; r_ret=Variant(); return; } if (p_args[1]->get_type()!=Variant::STRING && p_args[1]->get_type()!=Variant::NODE_PATH) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=1; r_error.expected=Variant::STRING; r_ret=Variant(); return; } Ref<FuncRef> fr = memnew( FuncRef); Object *obj = *p_args[0]; fr->set_instance(*p_args[0]); fr->set_function(*p_args[1]); r_ret=fr; } break; case TYPE_CONVERT: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(1); int type=*p_args[1]; if (type<0 || type>=Variant::VARIANT_MAX) { ERR_PRINT("Invalid type argument to convert()"); r_ret=Variant::NIL; } else { r_ret=Variant::construct(Variant::Type(type),p_args,1,r_error); } } break; case TYPE_OF: { VALIDATE_ARG_COUNT(1); r_ret = p_args[0]->get_type(); } break; case TEXT_STR: { String str; for(int i=0;i<p_arg_count;i++) { String os = p_args[i]->operator String();; if (i==0) str=os; else str+=os; } r_ret=str; } break; case TEXT_PRINT: { String str; for(int i=0;i<p_arg_count;i++) { str+=p_args[i]->operator String(); } //str+="\n"; print_line(str); r_ret=Variant(); } break; case TEXT_PRINT_TABBED: { String str; for(int i=0;i<p_arg_count;i++) { if (i) str+="\t"; str+=p_args[i]->operator String(); } //str+="\n"; print_line(str); r_ret=Variant(); } break; case TEXT_PRINTERR: { String str; for(int i=0;i<p_arg_count;i++) { str+=p_args[i]->operator String(); } //str+="\n"; OS::get_singleton()->printerr("%s\n",str.utf8().get_data()); r_ret=Variant(); } break; case TEXT_PRINTRAW: { String str; for(int i=0;i<p_arg_count;i++) { str+=p_args[i]->operator String(); } //str+="\n"; OS::get_singleton()->print("%s\n",str.utf8().get_data()); r_ret=Variant(); } break; case GEN_RANGE: { switch(p_arg_count) { case 0: { r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument=1; } break; case 1: { VALIDATE_ARG_NUM(0); int count=*p_args[0]; Array arr(true); if (count<=0) { r_ret=arr; return; } Error err = arr.resize(count); if (err!=OK) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_ret=Variant(); return; } for(int i=0;i<count;i++) { arr[i]=i; } r_ret=arr; } break; case 2: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); int from=*p_args[0]; int to=*p_args[1]; Array arr(true); if (from>=to) { r_ret=arr; return; } Error err = arr.resize(to-from); if (err!=OK) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_ret=Variant(); return; } for(int i=from;i<to;i++) arr[i-from]=i; r_ret=arr; } break; case 3: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); int from=*p_args[0]; int to=*p_args[1]; int incr=*p_args[2]; if (incr==0) { ERR_EXPLAIN("step argument is zero!"); r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; ERR_FAIL(); } Array arr(true); if (from>=to && incr>0) { r_ret=arr; return; } if (from<=to && incr<0) { r_ret=arr; return; } //calculate how many int count=0; if (incr>0) { count=((to-from-1)/incr)+1; } else { count=((from-to-1)/-incr)+1; } Error err = arr.resize(count); if (err!=OK) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_ret=Variant(); return; } if (incr>0) { int idx=0; for(int i=from;i<to;i+=incr) { arr[idx++]=i; } } else { int idx=0; for(int i=from;i>to;i+=incr) { arr[idx++]=i; } } r_ret=arr; } break; default: { r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_error.argument=3; } break; } } break; case RESOURCE_LOAD: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()!=Variant::STRING) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_ret=Variant(); } r_ret=ResourceLoader::load(*p_args[0]); } break; case INST2DICT: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()==Variant::NIL) { r_ret=Variant(); } else if (p_args[0]->get_type()!=Variant::OBJECT) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_ret=Variant(); } else { Object *obj = *p_args[0]; if (!obj) { r_ret=Variant(); } else if (!obj->get_script_instance() || obj->get_script_instance()->get_language()!=GDScriptLanguage::get_singleton()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::DICTIONARY; ERR_PRINT("Not a script with an instance"); } else { GDInstance *ins = static_cast<GDInstance*>(obj->get_script_instance()); Ref<GDScript> base = ins->get_script(); if (base.is_null()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::DICTIONARY; ERR_PRINT("Not based on a script"); return; } GDScript *p = base.ptr(); Vector<StringName> sname; while(p->_owner) { sname.push_back(p->name); p=p->_owner; } sname.invert(); if (!p->path.is_resource_file()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::DICTIONARY; print_line("PATH: "+p->path); ERR_PRINT("Not based on a resource file"); return; } NodePath cp(sname,Vector<StringName>(),false); Dictionary d(true); d["@subpath"]=cp; d["@path"]=p->path; p = base.ptr(); while(p) { for(Set<StringName>::Element *E=p->members.front();E;E=E->next()) { Variant value; if (ins->get(E->get(),value)) { String k = E->get(); if (!d.has(k)) { d[k]=value; } } } p=p->_base; } r_ret=d; } } } break; case DICT2INST: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()!=Variant::DICTIONARY) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::DICTIONARY; return; } Dictionary d = *p_args[0]; if (!d.has("@path")) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; return; } Ref<Script> scr = ResourceLoader::load(d["@path"]); if (!scr.is_valid()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; return; } Ref<GDScript> gdscr = scr; if (!gdscr.is_valid()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; return; } NodePath sub; if (d.has("@subpath")) { sub=d["@subpath"]; } for(int i=0;i<sub.get_name_count();i++) { gdscr = gdscr->subclasses[ sub.get_name(i)]; if (!gdscr.is_valid()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; return; } } r_ret = gdscr->_new(NULL,0,r_error); } break; case HASH: { VALIDATE_ARG_COUNT(1); r_ret=p_args[0]->hash(); } break; case PRINT_STACK: { ScriptLanguage* script = GDScriptLanguage::get_singleton(); for (int i=0; i < script->debug_get_stack_level_count(); i++) { print_line("Frame "+itos(i)+" - "+script->debug_get_stack_level_source(i)+":"+itos(script->debug_get_stack_level_line(i))+" in function '"+script->debug_get_stack_level_function(i)+"'"); }; } break; case FUNC_MAX: { ERR_FAIL_V(); } break; } }
virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { switch(func) { case VisualScriptBuiltinFunc::MATH_SIN: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::sin(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_COS: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::cos(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_TAN: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::tan(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_SINH: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::sinh(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_COSH: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::cosh(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_TANH: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::tanh(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ASIN: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::asin(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ACOS: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::acos(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ATAN: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::atan(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ATAN2: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *p_outputs[0]=Math::atan2(*p_inputs[0],*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_SQRT: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::sqrt(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_FMOD: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *p_outputs[0]=Math::fmod(*p_inputs[0],*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_FPOSMOD: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *p_outputs[0]=Math::fposmod(*p_inputs[0],*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_FLOOR: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::floor(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_CEIL: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::ceil(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ROUND: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::round(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ABS: { if (p_inputs[0]->get_type()==Variant::INT) { int64_t i = *p_inputs[0]; *p_outputs[0]=ABS(i); } else if (p_inputs[0]->get_type()==Variant::REAL) { real_t r = *p_inputs[0]; *p_outputs[0]=Math::abs(r); } else { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::REAL; } } break; case VisualScriptBuiltinFunc::MATH_SIGN: { if (p_inputs[0]->get_type()==Variant::INT) { int64_t i = *p_inputs[0]; *p_outputs[0]= i < 0 ? -1 : ( i > 0 ? +1 : 0); } else if (p_inputs[0]->get_type()==Variant::REAL) { real_t r = *p_inputs[0]; *p_outputs[0]= r < 0.0 ? -1.0 : ( r > 0.0 ? +1.0 : 0.0); } else { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::REAL; } } break; case VisualScriptBuiltinFunc::MATH_POW: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *p_outputs[0]=Math::pow(*p_inputs[0],*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_LOG: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::log(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_EXP: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::exp(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ISNAN: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::is_nan(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ISINF: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::is_inf(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_EASE: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *p_outputs[0]=Math::ease(*p_inputs[0],*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_DECIMALS: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::step_decimals(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_STEPIFY: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *p_outputs[0]=Math::stepify(*p_inputs[0],*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_LERP: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); *p_outputs[0]=Math::lerp(*p_inputs[0],*p_inputs[1],*p_inputs[2]); } break; case VisualScriptBuiltinFunc::MATH_DECTIME: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); *p_outputs[0]=Math::dectime(*p_inputs[0],*p_inputs[1],*p_inputs[2]); } break; case VisualScriptBuiltinFunc::MATH_RANDOMIZE: { Math::randomize(); } break; case VisualScriptBuiltinFunc::MATH_RAND: { *p_outputs[0]=Math::rand(); } break; case VisualScriptBuiltinFunc::MATH_RANDF: { *p_outputs[0]=Math::randf(); } break; case VisualScriptBuiltinFunc::MATH_RANDOM: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *p_outputs[0]=Math::random(*p_inputs[0],*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_SEED: { VALIDATE_ARG_NUM(0); uint32_t seed=*p_inputs[0]; Math::seed(seed); } break; case VisualScriptBuiltinFunc::MATH_RANDSEED: { VALIDATE_ARG_NUM(0); uint32_t seed=*p_inputs[0]; int ret = Math::rand_from_seed(&seed); Array reta; reta.push_back(ret); reta.push_back(seed); *p_outputs[0]=reta; } break; case VisualScriptBuiltinFunc::MATH_DEG2RAD: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::deg2rad(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_RAD2DEG: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::rad2deg(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_LINEAR2DB: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::linear2db(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_DB2LINEAR: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::db2linear(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::LOGIC_MAX: { if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) { int64_t a = *p_inputs[0]; int64_t b = *p_inputs[1]; *p_outputs[0]=MAX(a,b); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); real_t a = *p_inputs[0]; real_t b = *p_inputs[1]; *p_outputs[0]=MAX(a,b); } } break; case VisualScriptBuiltinFunc::LOGIC_MIN: { if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) { int64_t a = *p_inputs[0]; int64_t b = *p_inputs[1]; *p_outputs[0]=MIN(a,b); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); real_t a = *p_inputs[0]; real_t b = *p_inputs[1]; *p_outputs[0]=MIN(a,b); } } break; case VisualScriptBuiltinFunc::LOGIC_CLAMP: { if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT && p_inputs[2]->get_type()==Variant::INT) { int64_t a = *p_inputs[0]; int64_t b = *p_inputs[1]; int64_t c = *p_inputs[2]; *p_outputs[0]=CLAMP(a,b,c); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); real_t a = *p_inputs[0]; real_t b = *p_inputs[1]; real_t c = *p_inputs[2]; *p_outputs[0]=CLAMP(a,b,c); } } break; case VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2: { VALIDATE_ARG_NUM(0); int64_t num = *p_inputs[0]; *p_outputs[0] = nearest_power_of_2(num); } break; case VisualScriptBuiltinFunc::OBJ_WEAKREF: { if (p_inputs[0]->get_type()!=Variant::OBJECT) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; return 0; } if (p_inputs[0]->is_ref()) { REF r = *p_inputs[0]; if (!r.is_valid()) { return 0; } Ref<WeakRef> wref = memnew( WeakRef ); wref->set_ref(r); *p_outputs[0]=wref; } else { Object *obj = *p_inputs[0]; if (!obj) { return 0; } Ref<WeakRef> wref = memnew( WeakRef ); wref->set_obj(obj); *p_outputs[0]=wref; } } break; case VisualScriptBuiltinFunc::FUNC_FUNCREF: { if (p_inputs[0]->get_type()!=Variant::OBJECT) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; return 0; } if (p_inputs[1]->get_type()!=Variant::STRING && p_inputs[1]->get_type()!=Variant::NODE_PATH) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=1; r_error.expected=Variant::STRING; return 0; } Ref<FuncRef> fr = memnew( FuncRef); fr->set_instance(*p_inputs[0]); fr->set_function(*p_inputs[1]); *p_outputs[0]=fr; } break; case VisualScriptBuiltinFunc::TYPE_CONVERT: { VALIDATE_ARG_NUM(1); int type=*p_inputs[1]; if (type<0 || type>=Variant::VARIANT_MAX) { *p_outputs[0]=RTR("Invalid type argument to convert(), use TYPE_* constants."); r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::INT; return 0; } else { *p_outputs[0]=Variant::construct(Variant::Type(type),p_inputs,1,r_error); } } break; case VisualScriptBuiltinFunc::TYPE_OF: { *p_outputs[0] = p_inputs[0]->get_type(); } break; case VisualScriptBuiltinFunc::TYPE_EXISTS: { *p_outputs[0] = ObjectTypeDB::type_exists(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::TEXT_STR: { String str = *p_inputs[0]; *p_outputs[0]=str; } break; case VisualScriptBuiltinFunc::TEXT_PRINT: { String str = *p_inputs[0]; print_line(str); } break; case VisualScriptBuiltinFunc::TEXT_PRINTERR: { String str = *p_inputs[0]; //str+="\n"; OS::get_singleton()->printerr("%s\n",str.utf8().get_data()); } break; case VisualScriptBuiltinFunc::TEXT_PRINTRAW: { String str = *p_inputs[0]; //str+="\n"; OS::get_singleton()->print("%s",str.utf8().get_data()); } break; case VisualScriptBuiltinFunc::VAR_TO_STR: { String vars; VariantWriter::write_to_string(*p_inputs[0],vars); *p_outputs[0]=vars; } break; case VisualScriptBuiltinFunc::STR_TO_VAR: { if (p_inputs[0]->get_type()!=Variant::STRING) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::STRING; return 0; } VariantParser::StreamString ss; ss.s=*p_inputs[0]; String errs; int line; Error err = VariantParser::parse(&ss,*p_outputs[0],errs,line); if (err!=OK) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::STRING; *p_outputs[0]="Parse error at line "+itos(line)+": "+errs; return 0; } } break; case VisualScriptBuiltinFunc::VAR_TO_BYTES: { ByteArray barr; int len; Error err = encode_variant(*p_inputs[0],NULL,len); if (err) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::NIL; *p_outputs[0]="Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."; return 0; } barr.resize(len); { ByteArray::Write w = barr.write(); encode_variant(*p_inputs[0],w.ptr(),len); } *p_outputs[0]=barr; } break; case VisualScriptBuiltinFunc::BYTES_TO_VAR: { if (p_inputs[0]->get_type()!=Variant::RAW_ARRAY) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::RAW_ARRAY; return 0; } ByteArray varr=*p_inputs[0]; Variant ret; { ByteArray::Read r=varr.read(); Error err = decode_variant(ret,r.ptr(),varr.size(),NULL); if (err!=OK) { *p_outputs[0]=RTR("Not enough bytes for decoding bytes, or invalid format."); r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::RAW_ARRAY; return 0; } } *p_outputs[0]=ret; } break; default: {} } return 0; }
Error AudioDriverALSA::init() { active=false; thread_exited=false; exit_thread=false; pcm_open = false; samples_in = NULL; samples_out = NULL; mix_rate = GLOBAL_DEF("audio/mix_rate",44100); output_format = OUTPUT_STEREO; channels = 2; int status; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; #define CHECK_FAIL(m_cond)\ if (m_cond) {\ fprintf(stderr,"ALSA ERR: %s\n",snd_strerror(status));\ snd_pcm_close(pcm_handle);\ ERR_FAIL_COND_V(m_cond,ERR_CANT_OPEN);\ } //todo, add //6 chans - "plug:surround51" //4 chans - "plug:surround40"; status = snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); ERR_FAIL_COND_V( status<0, ERR_CANT_OPEN ); snd_pcm_hw_params_alloca(&hwparams); status = snd_pcm_hw_params_any(pcm_handle, hwparams); CHECK_FAIL( status<0 ); status = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); CHECK_FAIL( status<0 ); //not interested in anything else status = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE); CHECK_FAIL( status<0 ); //todo: support 4 and 6 status = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2); CHECK_FAIL( status<0 ); status = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &mix_rate, NULL); CHECK_FAIL( status<0 ); int latency = GLOBAL_DEF("audio/output_latency",25); buffer_size = nearest_power_of_2( latency * mix_rate / 1000 ); // set buffer size from project settings status = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size); CHECK_FAIL( status<0 ); // make period size 1/8 period_size = buffer_size >> 3; status = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &period_size, NULL); CHECK_FAIL( status<0 ); unsigned int periods=2; status = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &periods, NULL); CHECK_FAIL( status<0 ); status = snd_pcm_hw_params(pcm_handle,hwparams); CHECK_FAIL( status<0 ); //snd_pcm_hw_params_free(&hwparams); snd_pcm_sw_params_alloca(&swparams); status = snd_pcm_sw_params_current(pcm_handle, swparams); CHECK_FAIL( status<0 ); status = snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, period_size); CHECK_FAIL( status<0 ); status = snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1); CHECK_FAIL( status<0 ); status = snd_pcm_sw_params(pcm_handle, swparams); CHECK_FAIL( status<0 ); samples_in = memnew_arr(int32_t, period_size*channels); samples_out = memnew_arr(int16_t, period_size*channels); snd_pcm_nonblock(pcm_handle, 0); mutex=Mutex::create(); thread = Thread::create(AudioDriverALSA::thread_func, this); return OK; };
static void _compress_etc(Image *p_img) { Image img = *p_img; int imgw=img.get_width(),imgh=img.get_height(); ERR_FAIL_COND( nearest_power_of_2(imgw)!=imgw || nearest_power_of_2(imgh)!=imgh ); if (img.get_format()!=Image::FORMAT_RGB8) img.convert(Image::FORMAT_RGB8); int mmc=img.get_mipmap_count(); if (mmc==0) img.generate_mipmaps(); // force mipmaps, so it works on most hardware DVector<uint8_t> res_data; DVector<uint8_t> dst_data; DVector<uint8_t>::Read r = img.get_data().read(); int mc=0; rg_etc1::etc1_pack_params pp; pp.m_quality=rg_etc1::cLowQuality; for(int i=0;i<=mmc;i++) { int bw=MAX(imgw/4,1); int bh=MAX(imgh/4,1); const uint8_t *src = &r[img.get_mipmap_offset(i)]; int mmsize = MAX(bw,1)*MAX(bh,1)*8; dst_data.resize(dst_data.size()+mmsize); DVector<uint8_t>::Write w=dst_data.write(); uint8_t *dst = &w[dst_data.size()-mmsize]; // print_line("bh: "+itos(bh)+" bw: "+itos(bw)); for(int y=0;y<bh;y++) { for(int x=0;x<bw;x++) { // print_line("x: "+itos(x)+" y: "+itos(y)); uint8_t block[4*4*4]; zeromem(block,4*4*4); uint8_t cblock[8]; int maxy = MIN(imgh,4); int maxx = MIN(imgw,4); for(int yy=0;yy<maxy;yy++) { for(int xx=0;xx<maxx;xx++) { uint32_t dst_ofs = (yy*4+xx)*4; uint32_t src_ofs = ((y*4+yy)*imgw+x*4+xx)*3; block[dst_ofs+0]=src[src_ofs+0]; block[dst_ofs+1]=src[src_ofs+1]; block[dst_ofs+2]=src[src_ofs+2]; block[dst_ofs+3]=255; } } rg_etc1::pack_etc1_block(cblock, (const unsigned int*)block, pp); for(int j=0;j<8;j++) { dst[j]=cblock[j]; } dst+=8; } } imgw=MAX(1,imgw/2); imgh=MAX(1,imgh/2); mc++; } *p_img=Image(p_img->get_width(),p_img->get_height(),(mc-1)?true:false,Image::FORMAT_ETC,dst_data); }