Error ResourceInteractiveLoaderBinary::poll(){ if (error!=OK) return error; int s = stage; if (s<external_resources.size()) { RES res = ResourceLoader::load(external_resources[s].path,external_resources[s].type); if (res.is_null()) { if (!ResourceLoader::get_abort_on_missing_resources()) { ResourceLoader::notify_load_error("Resource Not Found: "+external_resources[s].path); } else { error=ERR_FILE_CORRUPT; ERR_EXPLAIN("Can't load dependency: "+external_resources[s].path); ERR_FAIL_V(error); } } else { resource_cache.push_back(res); } stage++; return OK; } s-=external_resources.size(); if (s>=internal_resources.size()) { error=ERR_BUG; ERR_FAIL_COND_V(s>=internal_resources.size(),error); } bool main = s==(internal_resources.size()-1); //maybe it is loaded already String path; if (!main) { path=internal_resources[s].path; if (path.begins_with("local://")) path=path.replace("local://",res_path+"::"); if (ResourceCache::has(path)) { //already loaded, don't do anything stage++; error=OK; return error; } } else { path=res_path; } uint64_t offset = internal_resources[s].offset; f->seek(offset); String t = get_unicode_string(); Object *obj = ObjectTypeDB::instance(t); if (!obj) { error=ERR_FILE_CORRUPT; ERR_EXPLAIN(local_path+":Resource of unrecognized type in file: "+t); } ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT); Resource *r = obj->cast_to<Resource>(); if (!r) { error=ERR_FILE_CORRUPT; memdelete(obj); //bye ERR_EXPLAIN(local_path+":Resoucre type in resource field not a resource, type is: "+obj->get_type()); ERR_FAIL_COND_V(!r,ERR_FILE_CORRUPT); } RES res = RES( r ); r->set_path(path); int pc = f->get_32(); //set properties for(int i=0;i<pc;i++) { uint32_t name_idx = f->get_32(); if (name_idx>=(uint32_t)string_map.size()) { error=ERR_FILE_CORRUPT; ERR_FAIL_V(ERR_FILE_CORRUPT); } Variant value; error = parse_variant(value); if (error) return error; res->set(string_map[name_idx],value); } #ifdef TOOLS_ENABLED res->set_edited(false); #endif stage++; resource_cache.push_back(res); if (main) { if (importmd_ofs) { f->seek(importmd_ofs); Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata ); imd->set_editor(get_unicode_string()); int sc = f->get_32(); for(int i=0;i<sc;i++) { String src = get_unicode_string(); String md5 = get_unicode_string(); imd->add_source(src,md5); } int pc = f->get_32(); for(int i=0;i<pc;i++) { String name = get_unicode_string(); Variant val; parse_variant(val); imd->set_option(name,val); } res->set_import_metadata(imd); } f->close(); resource=res; error=ERR_FILE_EOF; } else { error=OK; } return OK; }
Error PoolAllocator::resize(ID p_mem,int p_new_size) { mt_lock(); Entry *e=get_entry(p_mem); if (!e) { mt_unlock(); ERR_FAIL_COND_V(!e,ERR_INVALID_PARAMETER); } if (needs_locking && e->lock) { mt_unlock(); ERR_FAIL_COND_V(e->lock,ERR_ALREADY_IN_USE); } int alloc_size = aligned(p_new_size); if (aligned(e->len)==alloc_size) { e->len=p_new_size; mt_unlock(); return OK; } else if (e->len>(uint32_t)p_new_size) { free_mem += aligned(e->len); free_mem -= alloc_size; e->len=p_new_size; mt_unlock(); return OK; } //p_new_size = align(p_new_size) int _total = pool_size; // - static_area_size; int _free = free_mem; // - static_area_size; if ((_free + aligned(e->len)) - alloc_size < 0) { mt_unlock(); ERR_FAIL_V( ERR_OUT_OF_MEMORY ); }; EntryIndicesPos entry_indices_pos; bool index_found = find_entry_index(&entry_indices_pos,e); if (!index_found) { mt_unlock(); ERR_FAIL_COND_V(!index_found,ERR_BUG); } //no need to move stuff around, it fits before the next block int next_pos; if (entry_indices_pos+1 == entry_count) { next_pos = pool_size; // - static_area_size; } else { next_pos = entry_array[entry_indices[entry_indices_pos+1]].pos; }; if ((next_pos - e->pos) > alloc_size) { free_mem+=aligned(e->len); e->len=p_new_size; free_mem-=alloc_size; mt_unlock(); return OK; } //it doesn't fit, compact around BEFORE current index (make room behind) compact(entry_indices_pos+1); if ((next_pos - e->pos) > alloc_size) { //now fits! hooray! free_mem+=aligned(e->len); e->len=p_new_size; free_mem-=alloc_size; mt_unlock(); if (free_mem<free_mem_peak) free_mem_peak=free_mem; return OK; } //STILL doesn't fit, compact around AFTER current index (make room after) compact_up(entry_indices_pos+1); if ((entry_array[entry_indices[entry_indices_pos+1]].pos - e->pos) > alloc_size) { //now fits! hooray! free_mem+=aligned(e->len); e->len=p_new_size; free_mem-=alloc_size; mt_unlock(); if (free_mem<free_mem_peak) free_mem_peak=free_mem; return OK; } mt_unlock(); ERR_FAIL_V(ERR_OUT_OF_MEMORY); }
bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2& p_from, const Vector2& p_to,RayResult &r_result,const Set<RID>& p_exclude,uint32_t p_user_mask) { ERR_FAIL_COND_V(space->locked,false); Vector2 begin,end; Vector2 normal; begin=p_from; end=p_to; normal=(end-begin).normalized(); int amount = space->broadphase->cull_segment(begin,end,space->intersection_query_results,Space2DSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results); //todo, create another array tha references results, compute AABBs and check closest point to ray origin, sort, and stop evaluating results when beyond first collision bool collided=false; Vector2 res_point,res_normal; int res_shape; const CollisionObject2DSW *res_obj; real_t min_d=1e10; for(int i=0;i<amount;i++) { if (space->intersection_query_results[i]->get_type()==CollisionObject2DSW::TYPE_AREA) continue; //ignore area if (p_exclude.has( space->intersection_query_results[i]->get_self())) continue; const CollisionObject2DSW *col_obj=space->intersection_query_results[i]; int shape_idx=space->intersection_query_subindex_results[i]; Matrix32 inv_xform = col_obj->get_shape_inv_transform(shape_idx) * col_obj->get_inv_transform(); Vector2 local_from = inv_xform.xform(begin); Vector2 local_to = inv_xform.xform(end); /*local_from = col_obj->get_inv_transform().xform(begin); local_from = col_obj->get_shape_inv_transform(shape_idx).xform(local_from); local_to = col_obj->get_inv_transform().xform(end); local_to = col_obj->get_shape_inv_transform(shape_idx).xform(local_to);*/ const Shape2DSW *shape = col_obj->get_shape(shape_idx); Vector2 shape_point,shape_normal; if (shape->intersect_segment(local_from,local_to,shape_point,shape_normal)) { //print_line("inters sgment!"); Matrix32 xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); shape_point=xform.xform(shape_point); real_t ld = normal.dot(shape_point); if (ld<min_d) { min_d=ld; res_point=shape_point; res_normal=inv_xform.basis_xform_inv(shape_normal).normalized(); res_shape=shape_idx; res_obj=col_obj; collided=true; } } } if (!collided) return false; r_result.collider_id=res_obj->get_instance_id(); if (r_result.collider_id!=0) r_result.collider=ObjectDB::get_instance(r_result.collider_id); r_result.normal=res_normal; r_result.position=res_point; r_result.rid=res_obj->get_self(); r_result.shape=res_shape; return true; }
Error EditorTextureImportPlugin::_process_texture_data(Ref<ImageTexture> &texture,int format, float quality,int flags,EditorExportPlatform::ImageCompression p_compr,int tex_flags,float shrink) { 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 (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_PREMULT_ALPHA) { image.premultiply_alpha(); } if (flags&IMAGE_FLAG_CONVERT_NORMAL_TO_XY) { image.normalmap_to_xy(); } //if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) { // image.srgb_to_linear(); //} if (shrink>1) { int orig_w=image.get_width(); int orig_h=image.get_height(); image.resize(orig_w/shrink,orig_h/shrink,Image::INTERPOLATE_CUBIC); 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); } else { 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 (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_PREMULT_ALPHA) { image.premultiply_alpha(); } if (flags&IMAGE_FLAG_CONVERT_NORMAL_TO_XY) { image.normalmap_to_xy(); } //if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) { // // print_line("CONVERT BECAUSE: "+itos(flags)); // image.srgb_to_linear(); //} int orig_w=image.get_width(); int orig_h=image.get_height(); if (shrink>1) { image.resize(orig_w/shrink,orig_h/shrink,Image::INTERPOLATE_CUBIC); 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); } texture->create_from_image(image,tex_flags); if (shrink>1 || (format!=IMAGE_FORMAT_UNCOMPRESSED && (image.get_width()!=orig_w || image.get_height()!=orig_h))) { texture->set_size_override(Size2(orig_w,orig_h)); } //uint32_t save_flags=ResourceSaver::FLAG_COMPRESS; } return OK; }
Transform2D Camera2D::get_camera_transform() { if (!get_tree()) return Transform2D(); ERR_FAIL_COND_V(custom_viewport && !ObjectDB::get_instance(custom_viewport_id), Transform2D()); Size2 screen_size = viewport->get_visible_rect().size; Point2 new_camera_pos = get_global_transform().get_origin(); Point2 ret_camera_pos; if (!first) { if (anchor_mode == ANCHOR_MODE_DRAG_CENTER) { if (h_drag_enabled && !Engine::get_singleton()->is_editor_hint()) { camera_pos.x = MIN(camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT])); camera_pos.x = MAX(camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * drag_margin[MARGIN_LEFT])); } else { if (h_ofs < 0) { camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT] * h_ofs; } else { camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_LEFT] * h_ofs; } } if (v_drag_enabled && !Engine::get_singleton()->is_editor_hint()) { camera_pos.y = MIN(camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM])); camera_pos.y = MAX(camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * drag_margin[MARGIN_TOP])); } else { if (v_ofs < 0) { camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_TOP] * v_ofs; } else { camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM] * v_ofs; } } } else if (anchor_mode == ANCHOR_MODE_FIXED_TOP_LEFT) { camera_pos = new_camera_pos; } Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom) : Point2()); Rect2 screen_rect(-screen_offset + camera_pos, screen_size * zoom); if (offset != Vector2()) screen_rect.position += offset; if (limit_smoothing_enabled) { if (screen_rect.position.x < limit[MARGIN_LEFT]) camera_pos.x -= screen_rect.position.x - limit[MARGIN_LEFT]; if (screen_rect.position.x + screen_rect.size.x > limit[MARGIN_RIGHT]) camera_pos.x -= screen_rect.position.x + screen_rect.size.x - limit[MARGIN_RIGHT]; if (screen_rect.position.y + screen_rect.size.y > limit[MARGIN_BOTTOM]) camera_pos.y -= screen_rect.position.y + screen_rect.size.y - limit[MARGIN_BOTTOM]; if (screen_rect.position.y < limit[MARGIN_TOP]) camera_pos.y -= screen_rect.position.y - limit[MARGIN_TOP]; } if (smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) { float c = smoothing * get_fixed_process_delta_time(); smoothed_camera_pos = ((camera_pos - smoothed_camera_pos) * c) + smoothed_camera_pos; ret_camera_pos = smoothed_camera_pos; //camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing; } else { ret_camera_pos = smoothed_camera_pos = camera_pos; } } else { ret_camera_pos = smoothed_camera_pos = camera_pos = new_camera_pos; first = false; } Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom) : Point2()); float angle = get_global_transform().get_rotation(); if (rotating) { screen_offset = screen_offset.rotated(angle); } Rect2 screen_rect(-screen_offset + ret_camera_pos, screen_size * zoom); if (screen_rect.position.x < limit[MARGIN_LEFT]) screen_rect.position.x = limit[MARGIN_LEFT]; if (screen_rect.position.x + screen_rect.size.x > limit[MARGIN_RIGHT]) screen_rect.position.x = limit[MARGIN_RIGHT] - screen_rect.size.x; if (screen_rect.position.y + screen_rect.size.y > limit[MARGIN_BOTTOM]) screen_rect.position.y = limit[MARGIN_BOTTOM] - screen_rect.size.y; if (screen_rect.position.y < limit[MARGIN_TOP]) screen_rect.position.y = limit[MARGIN_TOP]; if (offset != Vector2()) { screen_rect.position += offset; if (screen_rect.position.x + screen_rect.size.x > limit[MARGIN_RIGHT]) screen_rect.position.x = limit[MARGIN_RIGHT] - screen_rect.size.x; if (screen_rect.position.y + screen_rect.size.y > limit[MARGIN_BOTTOM]) screen_rect.position.y = limit[MARGIN_BOTTOM] - screen_rect.size.y; if (screen_rect.position.x < limit[MARGIN_LEFT]) screen_rect.position.x = limit[MARGIN_LEFT]; if (screen_rect.position.y < limit[MARGIN_TOP]) screen_rect.position.y = limit[MARGIN_TOP]; } camera_screen_center = screen_rect.position + screen_rect.size * 0.5; Transform2D xform; if (rotating) { xform.set_rotation(angle); } xform.scale_basis(zoom); xform.set_origin(screen_rect.position /*.floor()*/); /* if (0) { xform = get_global_transform() * xform; } else { xform.elements[2]+=get_global_transform().get_origin(); } */ return (xform).affine_inverse(); }
Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const PoolVector<uint8_t> &p_body) { ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(!p_url.begins_with("/"), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA); String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n"; if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) { // Don't append the standard ports request += "Host: " + conn_host + "\r\n"; } else { request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n"; } bool add_clen = p_body.size() > 0; bool add_uagent = true; bool add_accept = true; for (int i = 0; i < p_headers.size(); i++) { request += p_headers[i] + "\r\n"; if (add_clen && p_headers[i].findn("Content-Length:") == 0) { add_clen = false; } if (add_uagent && p_headers[i].findn("User-Agent:") == 0) { add_uagent = false; } if (add_accept && p_headers[i].findn("Accept:") == 0) { add_accept = false; } } if (add_clen) { request += "Content-Length: " + itos(p_body.size()) + "\r\n"; // Should it add utf8 encoding? } if (add_uagent) { request += "User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n"; } if (add_accept) { request += "Accept: */*\r\n"; } request += "\r\n"; CharString cs = request.utf8(); PoolVector<uint8_t> data; data.resize(cs.length()); { PoolVector<uint8_t>::Write data_write = data.write(); for (int i = 0; i < cs.length(); i++) { data_write[i] = cs[i]; } } data.append_array(p_body); PoolVector<uint8_t>::Read r = data.read(); Error err = connection->put_data(&r[0], data.size()); if (err) { close(); status = STATUS_CONNECTION_ERROR; return err; } status = STATUS_REQUESTING; return OK; }
PoolByteArray HTTPClient::read_response_body_chunk() { ERR_FAIL_COND_V(status != STATUS_BODY, PoolByteArray()); Error err = OK; if (chunked) { while (true) { if (chunk_left == 0) { // Reading length uint8_t b; int rec = 0; err = _get_http_data(&b, 1, rec); if (rec == 0) break; chunk.push_back(b); if (chunk.size() > 32) { ERR_PRINT("HTTP Invalid chunk hex len"); status = STATUS_CONNECTION_ERROR; return PoolByteArray(); } if (chunk.size() > 2 && chunk[chunk.size() - 2] == '\r' && chunk[chunk.size() - 1] == '\n') { int len = 0; for (int i = 0; i < chunk.size() - 2; i++) { char c = chunk[i]; int v = 0; if (c >= '0' && c <= '9') v = c - '0'; else if (c >= 'a' && c <= 'f') v = c - 'a' + 10; else if (c >= 'A' && c <= 'F') v = c - 'A' + 10; else { ERR_PRINT("HTTP Chunk len not in hex!!"); status = STATUS_CONNECTION_ERROR; return PoolByteArray(); } len <<= 4; len |= v; if (len > (1 << 24)) { ERR_PRINT("HTTP Chunk too big!! >16mb"); status = STATUS_CONNECTION_ERROR; return PoolByteArray(); } } if (len == 0) { // End reached! status = STATUS_CONNECTED; chunk.clear(); return PoolByteArray(); } chunk_left = len + 2; chunk.resize(chunk_left); } } else { int rec = 0; err = _get_http_data(&chunk.write[chunk.size() - chunk_left], chunk_left, rec); if (rec == 0) { break; } chunk_left -= rec; if (chunk_left == 0) { if (chunk[chunk.size() - 2] != '\r' || chunk[chunk.size() - 1] != '\n') { ERR_PRINT("HTTP Invalid chunk terminator (not \\r\\n)"); status = STATUS_CONNECTION_ERROR; return PoolByteArray(); } PoolByteArray ret; ret.resize(chunk.size() - 2); { PoolByteArray::Write w = ret.write(); copymem(w.ptr(), chunk.ptr(), chunk.size() - 2); } chunk.clear(); return ret; } break; } } } else { int to_read = !read_until_eof ? MIN(body_left, read_chunk_size) : read_chunk_size; PoolByteArray ret; ret.resize(to_read); int _offset = 0; while (read_until_eof || to_read > 0) { int rec = 0; { PoolByteArray::Write w = ret.write(); err = _get_http_data(w.ptr() + _offset, to_read, rec); } if (rec < 0) { if (to_read > 0) // Ended up reading less ret.resize(_offset); break; } else { _offset += rec; if (!read_until_eof) { body_left -= rec; to_read -= rec; } else { if (rec < to_read) { ret.resize(_offset); err = ERR_FILE_EOF; break; } ret.resize(_offset + to_read); } } } if (!read_until_eof) { if (body_left == 0) { status = STATUS_CONNECTED; } return ret; } else { if (err == ERR_FILE_EOF) { err = OK; // EOF is expected here close(); return ret; } } } if (err != OK) { close(); if (err == ERR_FILE_EOF) { status = STATUS_DISCONNECTED; // Server disconnected } else { status = STATUS_CONNECTION_ERROR; } } else if (body_left == 0 && !chunked) { status = STATUS_CONNECTED; } return PoolByteArray(); }
Variant Object::get_meta(const String& p_name) const { ERR_FAIL_COND_V(!metadata.has(p_name),Variant()); return metadata[p_name]; }
Mutex *Mutex::create(bool p_recursive) { ERR_FAIL_COND_V( !create_func, 0 ); return create_func(p_recursive); }
Array VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channel, Vector3i min, Vector3i max) { uint64_t time_before = OS::get_singleton()->get_ticks_usec(); ERR_FAIL_COND_V(_library.is_null(), Array()); ERR_FAIL_COND_V(channel >= VoxelBuffer::MAX_CHANNELS, Array()); const VoxelLibrary &library = **_library; for (unsigned int i = 0; i < MAX_MATERIALS; ++i) { Arrays &a = _arrays[i]; a.positions.clear(); a.normals.clear(); a.uvs.clear(); a.colors.clear(); a.indices.clear(); } float baked_occlusion_darkness; if (_bake_occlusion) baked_occlusion_darkness = _baked_occlusion_darkness / 3.0; // The technique is Culled faces. // Could be improved with greedy meshing: https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/ // However I don't feel it's worth it yet: // - Not so much gain for organic worlds with lots of texture variations // - Works well with cubes but not with any shape // - Slower // => Could be implemented in a separate class? // Data must be padded, hence the off-by-one Vector3i::sort_min_max(min, max); const Vector3i pad(1, 1, 1); min.clamp_to(pad, max); max.clamp_to(min, buffer.get_size() - pad); int index_offset = 0; // Iterate 3D padded data to extract voxel faces. // This is the most intensive job in this class, so all required data should be as fit as possible. // The buffer we receive MUST be dense (i.e not compressed, and channels allocated). // That means we can use raw pointers to voxel data inside instead of using the higher-level getters, // and then save a lot of time. uint8_t *type_buffer = buffer.get_channel_raw(Voxel::CHANNEL_TYPE); // _ // | \ // /\ \\ // / /|\\\ // | |\ \\\ // | \_\ \\| // | | ) // \ | | // \ / CRASH_COND(type_buffer == NULL); //CRASH_COND(memarr_len(type_buffer) != buffer.get_volume() * sizeof(uint8_t)); // Build lookup tables so to speed up voxel access. // These are values to add to an address in order to get given neighbor. int row_size = buffer.get_size().y; int deck_size = buffer.get_size().x * row_size; int side_neighbor_lut[Cube::SIDE_COUNT]; side_neighbor_lut[Cube::SIDE_LEFT] = row_size; side_neighbor_lut[Cube::SIDE_RIGHT] = -row_size; side_neighbor_lut[Cube::SIDE_BACK] = -deck_size; side_neighbor_lut[Cube::SIDE_FRONT] = deck_size; side_neighbor_lut[Cube::SIDE_BOTTOM] = -1; side_neighbor_lut[Cube::SIDE_TOP] = 1; int edge_neighbor_lut[Cube::EDGE_COUNT]; edge_neighbor_lut[Cube::EDGE_BOTTOM_BACK] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_BACK]; edge_neighbor_lut[Cube::EDGE_BOTTOM_FRONT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_FRONT]; edge_neighbor_lut[Cube::EDGE_BOTTOM_LEFT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_LEFT]; edge_neighbor_lut[Cube::EDGE_BOTTOM_RIGHT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_RIGHT]; edge_neighbor_lut[Cube::EDGE_BACK_LEFT] = side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_LEFT]; edge_neighbor_lut[Cube::EDGE_BACK_RIGHT] = side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_RIGHT]; edge_neighbor_lut[Cube::EDGE_FRONT_LEFT] = side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_LEFT]; edge_neighbor_lut[Cube::EDGE_FRONT_RIGHT] = side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_RIGHT]; edge_neighbor_lut[Cube::EDGE_TOP_BACK] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_BACK]; edge_neighbor_lut[Cube::EDGE_TOP_FRONT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_FRONT]; edge_neighbor_lut[Cube::EDGE_TOP_LEFT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_LEFT]; edge_neighbor_lut[Cube::EDGE_TOP_RIGHT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_RIGHT]; int corner_neighbor_lut[Cube::CORNER_COUNT]; corner_neighbor_lut[Cube::CORNER_BOTTOM_BACK_LEFT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_LEFT]; corner_neighbor_lut[Cube::CORNER_BOTTOM_BACK_RIGHT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_RIGHT]; corner_neighbor_lut[Cube::CORNER_BOTTOM_FRONT_RIGHT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_RIGHT]; corner_neighbor_lut[Cube::CORNER_BOTTOM_FRONT_LEFT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_LEFT]; corner_neighbor_lut[Cube::CORNER_TOP_BACK_LEFT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_LEFT]; corner_neighbor_lut[Cube::CORNER_TOP_BACK_RIGHT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_RIGHT]; corner_neighbor_lut[Cube::CORNER_TOP_FRONT_RIGHT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_RIGHT]; corner_neighbor_lut[Cube::CORNER_TOP_FRONT_LEFT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_LEFT]; uint64_t time_prep = OS::get_singleton()->get_ticks_usec() - time_before; time_before = OS::get_singleton()->get_ticks_usec(); for (unsigned int z = min.z; z < max.z; ++z) { for (unsigned int x = min.x; x < max.x; ++x) { for (unsigned int y = min.y; y < max.y; ++y) { // min and max are chosen such that you can visit 1 neighbor away from the current voxel without size check // TODO In this intensive routine, there is a way to make voxel access fastest by getting a pointer to the channel, // and using offset lookup to get neighbors rather than going through get_voxel validations int voxel_index = y + x * row_size + z * deck_size; int voxel_id = type_buffer[voxel_index]; if (voxel_id != 0 && library.has_voxel(voxel_id)) { const Voxel &voxel = library.get_voxel_const(voxel_id); Arrays &arrays = _arrays[voxel.get_material_id()]; // Hybrid approach: extract cube faces and decimate those that aren't visible, // and still allow voxels to have geometry that is not a cube // Sides for (unsigned int side = 0; side < Cube::SIDE_COUNT; ++side) { const PoolVector<Vector3> &positions = voxel.get_model_side_positions(side); int vertex_count = positions.size(); if (vertex_count != 0) { int neighbor_voxel_id = type_buffer[voxel_index + side_neighbor_lut[side]]; // TODO Better face visibility test if (is_face_visible(library, voxel, neighbor_voxel_id)) { // The face is visible int shaded_corner[8] = { 0 }; if (_bake_occlusion) { // Combinatory solution for https://0fps.net/2013/07/03/ambient-occlusion-for-minecraft-like-worlds/ for (unsigned int j = 0; j < 4; ++j) { unsigned int edge = Cube::g_side_edges[side][j]; int edge_neighbor_id = type_buffer[voxel_index + edge_neighbor_lut[edge]]; if (!is_transparent(library, edge_neighbor_id)) { shaded_corner[Cube::g_edge_corners[edge][0]] += 1; shaded_corner[Cube::g_edge_corners[edge][1]] += 1; } } for (unsigned int j = 0; j < 4; ++j) { unsigned int corner = Cube::g_side_corners[side][j]; if (shaded_corner[corner] == 2) { shaded_corner[corner] = 3; } else { int corner_neigbor_id = type_buffer[voxel_index + corner_neighbor_lut[corner]]; if (!is_transparent(library, corner_neigbor_id)) { shaded_corner[corner] += 1; } } } } PoolVector<Vector3>::Read rv = positions.read(); PoolVector<Vector2>::Read rt = voxel.get_model_side_uv(side).read(); // Subtracting 1 because the data is padded Vector3 pos(x - 1, y - 1, z - 1); // Append vertices of the faces in one go, don't use push_back { int append_index = arrays.positions.size(); arrays.positions.resize(arrays.positions.size() + vertex_count); Vector3 *w = arrays.positions.ptrw() + append_index; for (unsigned int i = 0; i < vertex_count; ++i) { w[i] = rv[i] + pos; } } { int append_index = arrays.uvs.size(); arrays.uvs.resize(arrays.uvs.size() + vertex_count); memcpy(arrays.uvs.ptrw() + append_index, rt.ptr(), vertex_count * sizeof(Vector2)); } { int append_index = arrays.normals.size(); arrays.normals.resize(arrays.normals.size() + vertex_count); Vector3 *w = arrays.normals.ptrw() + append_index; for (unsigned int i = 0; i < vertex_count; ++i) { w[i] = Cube::g_side_normals[side].to_vec3(); } } if (_bake_occlusion) { // Use color array int append_index = arrays.colors.size(); arrays.colors.resize(arrays.colors.size() + vertex_count); Color *w = arrays.colors.ptrw() + append_index; for (unsigned int i = 0; i < vertex_count; ++i) { Vector3 v = rv[i]; // General purpose occlusion colouring. // TODO Optimize for cubes // TODO Fix occlusion inconsistency caused by triangles orientation? Not sure if worth it float shade = 0; for (unsigned int j = 0; j < 4; ++j) { unsigned int corner = Cube::g_side_corners[side][j]; if (shaded_corner[corner]) { float s = baked_occlusion_darkness * static_cast<float>(shaded_corner[corner]); float k = 1.0 - Cube::g_corner_position[corner].distance_to(v); if (k < 0.0) k = 0.0; s *= k; if (s > shade) shade = s; } } float gs = 1.0 - shade; w[i] = Color(gs, gs, gs); } } const PoolVector<int> &side_indices = voxel.get_model_side_indices(side); PoolVector<int>::Read ri = side_indices.read(); unsigned int index_count = side_indices.size(); { int i = arrays.indices.size(); arrays.indices.resize(arrays.indices.size() + index_count); int *w = arrays.indices.ptrw(); for(unsigned int j = 0; j < index_count; ++j) { w[i++] = index_offset + ri[j]; } } index_offset += vertex_count; } } } // Inside if (voxel.get_model_positions().size() != 0) { // TODO Get rid of push_backs const PoolVector<Vector3> &vertices = voxel.get_model_positions(); int vertex_count = vertices.size(); PoolVector<Vector3>::Read rv = vertices.read(); PoolVector<Vector3>::Read rn = voxel.get_model_normals().read(); PoolVector<Vector2>::Read rt = voxel.get_model_uv().read(); Vector3 pos(x - 1, y - 1, z - 1); for (unsigned int i = 0; i < vertex_count; ++i) { arrays.normals.push_back(rn[i]); arrays.uvs.push_back(rt[i]); arrays.positions.push_back(rv[i] + pos); } if(_bake_occlusion) { // TODO handle ambient occlusion on inner parts arrays.colors.push_back(Color(1,1,1)); } const PoolVector<int> &indices = voxel.get_model_indices(); PoolVector<int>::Read ri = indices.read(); unsigned int index_count = indices.size(); for(unsigned int i = 0; i < index_count; ++i) { arrays.indices.push_back(index_offset + ri[i]); } index_offset += vertex_count; } } } } } uint64_t time_meshing = OS::get_singleton()->get_ticks_usec() - time_before; time_before = OS::get_singleton()->get_ticks_usec(); // Commit mesh // print_line(String("Made mesh v: ") + String::num(_arrays[0].positions.size()) // + String(", i: ") + String::num(_arrays[0].indices.size())); Array surfaces; // TODO We could return a single byte array and use Mesh::add_surface down the line? for (int i = 0; i < MAX_MATERIALS; ++i) { const Arrays &arrays = _arrays[i]; if (arrays.positions.size() != 0) { /*print_line("Arrays:"); for(int i = 0; i < arrays.positions.size(); ++i) print_line(String(" P {0}").format(varray(arrays.positions[i]))); for(int i = 0; i < arrays.normals.size(); ++i) print_line(String(" N {0}").format(varray(arrays.normals[i]))); for(int i = 0; i < arrays.uvs.size(); ++i) print_line(String(" UV {0}").format(varray(arrays.uvs[i])));*/ Array mesh_arrays; mesh_arrays.resize(Mesh::ARRAY_MAX); { PoolVector<Vector3> positions; PoolVector<Vector2> uvs; PoolVector<Vector3> normals; PoolVector<Color> colors; PoolVector<int> indices; raw_copy_to(positions, arrays.positions); raw_copy_to(uvs, arrays.uvs); raw_copy_to(normals, arrays.normals); raw_copy_to(colors, arrays.colors); raw_copy_to(indices, arrays.indices); mesh_arrays[Mesh::ARRAY_VERTEX] = positions; mesh_arrays[Mesh::ARRAY_TEX_UV] = uvs; mesh_arrays[Mesh::ARRAY_NORMAL] = normals; mesh_arrays[Mesh::ARRAY_COLOR] = colors; mesh_arrays[Mesh::ARRAY_INDEX] = indices; } surfaces.append(mesh_arrays); } } uint64_t time_commit = OS::get_singleton()->get_ticks_usec() - time_before; //print_line(String("P: {0}, M: {1}, C: {2}").format(varray(time_prep, time_meshing, time_commit))); return surfaces; }
Variant Object::_call_bind(const StringName& p_name, const Variant& p_arg1, const Variant& p_arg2, const Variant& p_arg3, const Variant& p_arg4) { ERR_FAIL_COND_V(p_argcount<1,Variant()); return call(p_name, p_arg1, p_arg2, p_arg3, p_arg4); };
bool Main::start() { ERR_FAIL_COND_V(!_start_success,false); bool editor=false; String doc_tool; bool doc_base=true; String game_path; String script; String test; String screen; String optimize; String optimize_preset; String _export_platform; String _import; String _import_script; String dumpstrings; bool noquit=false; bool convert_old=false; bool export_debug=false; List<String> args = OS::get_singleton()->get_cmdline_args(); for (int i=0;i<args.size();i++) { if (args[i]=="-doctool" && i <(args.size()-1)) { doc_tool=args[i+1]; i++; }else if (args[i]=="-nodocbase") { doc_base=false; } else if ((args[i]=="-script" || args[i]=="-s") && i <(args.size()-1)) { script=args[i+1]; i++; } else if ((args[i]=="-level" || args[i]=="-l") && i <(args.size()-1)) { OS::get_singleton()->_custom_level=args[i+1]; i++; } else if (args[i]=="-test" && i <(args.size()-1)) { test=args[i+1]; i++; } else if (args[i]=="-optimize" && i <(args.size()-1)) { optimize=args[i+1]; i++; } else if (args[i]=="-optimize_preset" && i <(args.size()-1)) { optimize_preset=args[i+1]; i++; } else if (args[i]=="-export" && i <(args.size()-1)) { editor=true; //needs editor _export_platform=args[i+1]; i++; } else if (args[i]=="-export_debug" && i <(args.size()-1)) { editor=true; //needs editor _export_platform=args[i+1]; export_debug=true; i++; } else if (args[i]=="-import" && i <(args.size()-1)) { editor=true; //needs editor _import=args[i+1]; i++; } else if (args[i]=="-import_script" && i <(args.size()-1)) { editor=true; //needs editor _import_script=args[i+1]; i++; } else if (args[i]=="-noquit" ) { noquit=true; } else if (args[i]=="-dumpstrings" && i <(args.size()-1)) { editor=true; //needs editor dumpstrings=args[i+1]; i++; } else if (args[i]=="-editor" || args[i]=="-e") { editor=true; } else if (args[i]=="-convert_old") { convert_old=true; } else if (args[i].length() && args[i][0] != '-' && game_path == "") { game_path=args[i]; } } if (editor) Globals::get_singleton()->set("editor_active",true); String main_loop_type; #ifdef TOOLS_ENABLED if(doc_tool!="") { DocData doc; doc.generate(doc_base); DocData docsrc; if (docsrc.load(doc_tool)==OK) { print_line("Doc exists. Merging.."); doc.merge_from(docsrc); } else { print_line("No Doc exists. Generating empty."); } doc.save(doc_tool); return false; } if (optimize!="") editor=true; //need editor #endif if(script=="" && game_path=="" && !editor && String(GLOBAL_DEF("application/main_scene",""))!="") { game_path=GLOBAL_DEF("application/main_scene",""); } MainLoop *main_loop=NULL; if (editor) { main_loop = memnew(SceneTree); }; if (test!="") { #ifdef DEBUG_ENABLED main_loop = test_main(test,args); if (!main_loop) return false; #endif } else if (script!="") { Ref<Script> script_res = ResourceLoader::load(script); ERR_EXPLAIN("Can't load script: "+script); ERR_FAIL_COND_V(script_res.is_null(),false); if( script_res->can_instance() /*&& script_res->inherits_from("SceneTreeScripted")*/) { StringName instance_type=script_res->get_instance_base_type(); Object *obj = ObjectTypeDB::instance(instance_type); MainLoop *script_loop = obj?obj->cast_to<MainLoop>():NULL; if (!script_loop) { if (obj) memdelete(obj); ERR_EXPLAIN("Can't load script '"+script+"', it does not inherit from a MainLoop type"); ERR_FAIL_COND_V(!script_loop,false); } script_loop->set_init_script(script_res); main_loop=script_loop; } else { return false; } } else { main_loop_type=GLOBAL_DEF("application/main_loop_type",""); } if (!main_loop && main_loop_type=="") main_loop_type="SceneTree"; if (!main_loop) { if (!ObjectTypeDB::type_exists(main_loop_type)) { OS::get_singleton()->alert("godot: error: MainLoop type doesn't exist: "+main_loop_type); return false; } else { Object *ml = ObjectTypeDB::instance(main_loop_type); if (!ml) { ERR_EXPLAIN("Can't instance MainLoop type"); ERR_FAIL_V(false); } main_loop=ml->cast_to<MainLoop>(); if (!main_loop) { memdelete(ml); ERR_EXPLAIN("Invalid MainLoop type"); ERR_FAIL_V(false); } } } if (main_loop->is_type("SceneTree")) { SceneTree *sml = main_loop->cast_to<SceneTree>(); #ifdef TOOLS_ENABLED EditorNode *editor_node=NULL; if (editor) { editor_node = memnew( EditorNode ); sml->get_root()->add_child(editor_node); //root_node->set_editor(editor); //startup editor if (_export_platform!="") { editor_node->export_platform(_export_platform,game_path,export_debug,"",true); game_path=""; //no load anything } } #endif if (!editor) { //standard helpers that can be changed from main config String stretch_mode = GLOBAL_DEF("display/stretch_mode","disabled"); String stretch_aspect = GLOBAL_DEF("display/stretch_aspect","ignore"); Size2i stretch_size = Size2(GLOBAL_DEF("display/width",0),GLOBAL_DEF("display/height",0)); SceneTree::StretchMode sml_sm=SceneTree::STRETCH_MODE_DISABLED; if (stretch_mode=="2d") sml_sm=SceneTree::STRETCH_MODE_2D; else if (stretch_mode=="viewport") sml_sm=SceneTree::STRETCH_MODE_VIEWPORT; SceneTree::StretchAspect sml_aspect=SceneTree::STRETCH_ASPECT_IGNORE; if (stretch_aspect=="keep") sml_aspect=SceneTree::STRETCH_ASPECT_KEEP; else if (stretch_aspect=="keep_width") sml_aspect=SceneTree::STRETCH_ASPECT_KEEP_WIDTH; else if (stretch_aspect=="keep_height") sml_aspect=SceneTree::STRETCH_ASPECT_KEEP_HEIGHT; sml->set_screen_stretch(sml_sm,sml_aspect,stretch_size); sml->set_auto_accept_quit(GLOBAL_DEF("application/auto_accept_quit",true)); String appname = Globals::get_singleton()->get("application/name"); appname = TranslationServer::get_singleton()->translate(appname); OS::get_singleton()->set_window_title(appname); } else { GLOBAL_DEF("display/stretch_mode","disabled"); Globals::get_singleton()->set_custom_property_info("display/stretch_mode",PropertyInfo(Variant::STRING,"display/stretch_mode",PROPERTY_HINT_ENUM,"disabled,2d,viewport")); GLOBAL_DEF("display/stretch_aspect","ignore"); Globals::get_singleton()->set_custom_property_info("display/stretch_aspect",PropertyInfo(Variant::STRING,"display/stretch_aspect",PROPERTY_HINT_ENUM,"ignore,keep,keep_width,keep_height")); sml->set_auto_accept_quit(GLOBAL_DEF("application/auto_accept_quit",true)); } if (game_path!="") { String local_game_path=game_path.replace("\\","/"); if (!local_game_path.begins_with("res://")) { bool absolute=(local_game_path.size()>1) && (local_game_path[0]=='/' || local_game_path[1]==':'); if (!absolute) { if (Globals::get_singleton()->is_using_datapack()) { local_game_path="res://"+local_game_path; } else { int sep=local_game_path.find_last("/"); if (sep==-1) { DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); local_game_path=da->get_current_dir()+"/"+local_game_path; memdelete(da) ; } else { DirAccess *da = DirAccess::open(local_game_path.substr(0,sep)); if (da) { local_game_path=da->get_current_dir()+"/"+local_game_path.substr(sep+1,local_game_path.length());; memdelete(da); } } } } } local_game_path=Globals::get_singleton()->localize_path(local_game_path); #ifdef TOOLS_ENABLED if (editor) { if (_import!="") { //editor_node->import_scene(_import,local_game_path,_import_script); if (!noquit) sml->quit(); game_path=""; //no load anything } else { Error serr = editor_node->load_scene(local_game_path); if (serr==OK) { if (optimize!="") { editor_node->save_optimized_copy(optimize,optimize_preset); if (!noquit) sml->quit(); } if (dumpstrings!="") { editor_node->save_translatable_strings(dumpstrings); if (!noquit) sml->quit(); } } } //editor_node->set_edited_scene(game); } else { #endif { //autoload List<PropertyInfo> props; Globals::get_singleton()->get_property_list(&props); for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { String s = E->get().name; if (!s.begins_with("autoload/")) continue; String name = s.get_slicec('/',1); String path = Globals::get_singleton()->get(s); RES res = ResourceLoader::load(path); ERR_EXPLAIN("Can't autoload: "+path); ERR_CONTINUE(res.is_null()); Node *n=NULL; if (res->is_type("PackedScene")) { Ref<PackedScene> ps = res; n=ps->instance(); } else if (res->is_type("Script")) { Ref<Script> s = res; StringName ibt = s->get_instance_base_type(); ERR_EXPLAIN("Script does not inherit a Node: "+path); ERR_CONTINUE( !ObjectTypeDB::is_type(ibt,"Node") ); Object *obj = ObjectTypeDB::instance(ibt); ERR_EXPLAIN("Cannot instance node for autoload type: "+String(ibt)); ERR_CONTINUE( obj==NULL ); n = obj->cast_to<Node>(); n->set_script(s.get_ref_ptr()); } ERR_EXPLAIN("Path in autoload not a node or script: "+path); ERR_CONTINUE(!n); n->set_name(name); sml->get_root()->add_child(n); } } Node *scene=NULL; Ref<PackedScene> scenedata = ResourceLoader::load(local_game_path); if (scenedata.is_valid()) scene=scenedata->instance(); ERR_EXPLAIN("Failed loading scene: "+local_game_path); ERR_FAIL_COND_V(!scene,false) //sml->get_root()->add_child(scene); sml->add_current_scene(scene); String iconpath = GLOBAL_DEF("application/icon","Variant()"""); if (iconpath!="") { Image icon; if (icon.load(iconpath)==OK) OS::get_singleton()->set_icon(icon); } //singletons #ifdef TOOLS_ENABLED } #endif } #ifdef TOOLS_ENABLED /*if (_export_platform!="") { sml->quit(); }*/ /* if (sml->get_root_node()) { Console *console = memnew( Console ); sml->get_root_node()->cast_to<RootNode>()->set_console(console); if (GLOBAL_DEF("console/visible_default",false).operator bool()) { console->show(); } else {P console->hide(); }; } */ if (script=="" && test=="" && game_path=="" && !editor) { ProjectManager *pmanager = memnew( ProjectManager ); sml->get_root()->add_child(pmanager); } #endif } OS::get_singleton()->set_main_loop( main_loop ); return true; }
Vector<uint8_t> GDTokenizerBuffer::parse_code_string(const String& p_code) { Vector<uint8_t> buf; Map<StringName,int> identifier_map; HashMap<Variant,int,VariantHasher> constant_map; Map<uint32_t,int> line_map; Vector<uint32_t> token_array; GDTokenizerText tt; tt.set_code(p_code); int line=-1; while(true) { if (tt.get_token_line()!=line) { line=tt.get_token_line(); line_map[line]=token_array.size(); } uint32_t token=tt.get_token(); switch(tt.get_token()) { case TK_IDENTIFIER: { StringName id = tt.get_token_identifier(); if (!identifier_map.has(id)) { int idx = identifier_map.size(); identifier_map[id]=idx; } token|=identifier_map[id]<<TOKEN_BITS; } break; case TK_CONSTANT: { Variant c = tt.get_token_constant(); if (!constant_map.has(c)) { int idx = constant_map.size(); constant_map[c]=idx; } token|=constant_map[c]<<TOKEN_BITS; } break; case TK_BUILT_IN_TYPE: { token|=tt.get_token_type()<<TOKEN_BITS; } break; case TK_BUILT_IN_FUNC: { token|=tt.get_token_built_in_func()<<TOKEN_BITS; } break; case TK_NEWLINE: { token|=tt.get_token_line_indent()<<TOKEN_BITS; } break; case TK_ERROR: { ERR_FAIL_V(Vector<uint8_t>()); } break; default: {} }; token_array.push_back(token); if (tt.get_token()==TK_EOF) break; tt.advance(); } //reverse maps Map<int,StringName> rev_identifier_map; for(Map<StringName,int>::Element *E=identifier_map.front();E;E=E->next()) { rev_identifier_map[E->get()]=E->key(); } Map<int,Variant> rev_constant_map; const Variant *K =NULL; while((K=constant_map.next(K))) { rev_constant_map[constant_map[*K]]=*K; } Map<int,uint32_t> rev_line_map; for(Map<uint32_t,int>::Element *E=line_map.front();E;E=E->next()) { rev_line_map[E->get()]=E->key(); } //save header buf.resize(24); buf[0]='G'; buf[1]='D'; buf[2]='S'; buf[3]='C'; encode_uint32(BYTECODE_VERSION,&buf[4]); encode_uint32(identifier_map.size(),&buf[8]); encode_uint32(constant_map.size(),&buf[12]); encode_uint32(line_map.size(),&buf[16]); encode_uint32(token_array.size(),&buf[20]); //save identifiers for(Map<int,StringName>::Element *E=rev_identifier_map.front();E;E=E->next()) { CharString cs = String(E->get()).utf8(); int len = cs.length()+1; int extra = 4-(len%4); if (extra==4) extra=0; uint8_t ibuf[4]; encode_uint32(len+extra,ibuf); for(int i=0;i<4;i++) { buf.push_back(ibuf[i]); } for(int i=0;i<len;i++) { buf.push_back(cs[i]^0xb6); } for(int i=0;i<extra;i++) { buf.push_back(0^0xb6); } } for(Map<int,Variant>::Element *E=rev_constant_map.front();E;E=E->next()) { int len; Error err = encode_variant(E->get(),NULL,len); ERR_FAIL_COND_V(err!=OK,Vector<uint8_t>()); int pos=buf.size(); buf.resize(pos+len); encode_variant(E->get(),&buf[pos],len); } for(Map<int,uint32_t>::Element *E=rev_line_map.front();E;E=E->next()) { uint8_t ibuf[8]; encode_uint32(E->key(),&ibuf[0]); encode_uint32(E->get(),&ibuf[4]); for(int i=0;i<8;i++) buf.push_back(ibuf[i]); } for(int i=0;i<token_array.size();i++) { uint32_t token = token_array[i]; if (token&~TOKEN_MASK) { uint8_t buf4[4]; encode_uint32(token_array[i]|TOKEN_BYTE_MASK,&buf4[0]); for(int j=0;j<4;j++) { buf.push_back(buf4[j]); } } else { buf.push_back(token); } } return buf; }
Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) { const uint8_t *buf=p_buffer.ptr(); int total_len=p_buffer.size(); ERR_FAIL_COND_V( p_buffer.size()<24 || p_buffer[0]!='G' || p_buffer[1]!='D' || p_buffer[2]!='S' || p_buffer[3]!='C',ERR_INVALID_DATA); int version = decode_uint32(&buf[4]); if (version>BYTECODE_VERSION) { ERR_EXPLAIN("Bytecode is too New! Please use a newer engine version."); ERR_FAIL_COND_V(version>BYTECODE_VERSION,ERR_INVALID_DATA); } int identifier_count = decode_uint32(&buf[8]); int constant_count = decode_uint32(&buf[12]); int line_count = decode_uint32(&buf[16]); int token_count = decode_uint32(&buf[20]); const uint8_t *b=buf; b=&buf[24]; total_len-=24; identifiers.resize(identifier_count); for(int i=0;i<identifier_count;i++) { int len = decode_uint32(b); ERR_FAIL_COND_V(len>total_len,ERR_INVALID_DATA); b+=4; Vector<uint8_t> cs; cs.resize(len); for(int j=0;j<len;j++) { cs[j]=b[j]^0xb6; } cs[cs.size()-1]=0; String s; s.parse_utf8((const char*)cs.ptr()); b+=len; total_len-=len+4; identifiers[i]=s; } constants.resize(constant_count); for(int i=0;i<constant_count;i++) { Variant v; int len; Error err = decode_variant(v,b,total_len,&len); if (err) return err; b+=len; total_len-=len; constants[i]=v; } ERR_FAIL_COND_V(line_count*8>total_len,ERR_INVALID_DATA); for(int i=0;i<line_count;i++) { uint32_t token=decode_uint32(b); b+=4; uint32_t linecol=decode_uint32(b); b+=4; lines.insert(token,linecol); total_len-=8; } tokens.resize(token_count); for(int i=0;i<token_count;i++) { ERR_FAIL_COND_V( total_len < 1, ERR_INVALID_DATA); if ((*b)&TOKEN_BYTE_MASK) { //little endian always ERR_FAIL_COND_V( total_len < 4, ERR_INVALID_DATA); tokens[i]=decode_uint32(b)&~TOKEN_BYTE_MASK; b+=4; } else { tokens[i]=*b; b+=1; total_len--; } } token=0; return OK; }
float AnimationPlayer::get_current_animation_length() const { ERR_FAIL_COND_V(!playback.current.from,0); return playback.current.from->animation->get_length(); }
Ref<World> Spatial::get_world() const { ERR_FAIL_COND_V(!is_inside_world(),Ref<World>()); return data.viewport->find_world(); }
DVector<DVector<Face3> > Geometry::separate_objects(DVector<Face3> p_array) { DVector<DVector<Face3> > objects; int len = p_array.size(); DVector<Face3>::Read r = p_array.read(); const Face3 *arrayptr = r.ptr(); DVector<_FaceClassify> fc; fc.resize(len); DVector<_FaceClassify>::Write fcw = fc.write(); _FaceClassify *_fcptr = fcw.ptr(); for (int i = 0; i < len; i++) { _fcptr[i].face = arrayptr[i]; } bool error = _connect_faces(_fcptr, len, -1); if (error) { ERR_FAIL_COND_V(error, DVector<DVector<Face3> >()); // invalid geometry } /* group connected faces in separate objects */ int group = 0; for (int i = 0; i < len; i++) { if (!_fcptr[i].valid) continue; if (_group_face(_fcptr, len, i, group)) { group++; } } /* group connected faces in separate objects */ for (int i = 0; i < len; i++) { _fcptr[i].face = arrayptr[i]; } if (group >= 0) { objects.resize(group); DVector<DVector<Face3> >::Write obw = objects.write(); DVector<Face3> *group_faces = obw.ptr(); for (int i = 0; i < len; i++) { if (!_fcptr[i].valid) continue; if (_fcptr[i].group >= 0 && _fcptr[i].group < group) { group_faces[_fcptr[i].group].push_back(_fcptr[i].face); } } } return objects; }
int MultiplayerAPI::get_network_unique_id() const { ERR_FAIL_COND_V(!network_peer.is_valid(), 0); return network_peer->get_unique_id(); }
Error HTTPClient::poll() { switch (status) { case STATUS_RESOLVING: { ERR_FAIL_COND_V(resolving == IP::RESOLVER_INVALID_ID, ERR_BUG); IP::ResolverStatus rstatus = IP::get_singleton()->get_resolve_item_status(resolving); switch (rstatus) { case IP::RESOLVER_STATUS_WAITING: return OK; // Still resolving case IP::RESOLVER_STATUS_DONE: { IP_Address host = IP::get_singleton()->get_resolve_item_address(resolving); Error err = tcp_connection->connect_to_host(host, conn_port); IP::get_singleton()->erase_resolve_item(resolving); resolving = IP::RESOLVER_INVALID_ID; if (err) { status = STATUS_CANT_CONNECT; return err; } status = STATUS_CONNECTING; } break; case IP::RESOLVER_STATUS_NONE: case IP::RESOLVER_STATUS_ERROR: { IP::get_singleton()->erase_resolve_item(resolving); resolving = IP::RESOLVER_INVALID_ID; close(); status = STATUS_CANT_RESOLVE; return ERR_CANT_RESOLVE; } break; } } break; case STATUS_CONNECTING: { StreamPeerTCP::Status s = tcp_connection->get_status(); switch (s) { case StreamPeerTCP::STATUS_CONNECTING: { return OK; } break; case StreamPeerTCP::STATUS_CONNECTED: { if (ssl) { Ref<StreamPeerSSL> ssl; if (!handshaking) { // Connect the StreamPeerSSL and start handshaking ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create()); ssl->set_blocking_handshake_enabled(false); Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, conn_host); if (err != OK) { close(); status = STATUS_SSL_HANDSHAKE_ERROR; return ERR_CANT_CONNECT; } connection = ssl; handshaking = true; } else { // We are already handshaking, which means we can use your already active SSL connection ssl = static_cast<Ref<StreamPeerSSL> >(connection); ssl->poll(); // Try to finish the handshake } if (ssl->get_status() == StreamPeerSSL::STATUS_CONNECTED) { // Handshake has been successful handshaking = false; status = STATUS_CONNECTED; return OK; } else if (ssl->get_status() != StreamPeerSSL::STATUS_HANDSHAKING) { // Handshake has failed close(); status = STATUS_SSL_HANDSHAKE_ERROR; return ERR_CANT_CONNECT; } // ... we will need to poll more for handshake to finish } else { status = STATUS_CONNECTED; } return OK; } break; case StreamPeerTCP::STATUS_ERROR: case StreamPeerTCP::STATUS_NONE: { close(); status = STATUS_CANT_CONNECT; return ERR_CANT_CONNECT; } break; } } break; case STATUS_BODY: case STATUS_CONNECTED: { // Check if we are still connected if (ssl) { Ref<StreamPeerSSL> tmp = connection; tmp->poll(); if (tmp->get_status() != StreamPeerSSL::STATUS_CONNECTED) { status = STATUS_CONNECTION_ERROR; return ERR_CONNECTION_ERROR; } } else if (tcp_connection->get_status() != StreamPeerTCP::STATUS_CONNECTED) { status = STATUS_CONNECTION_ERROR; return ERR_CONNECTION_ERROR; } // Connection established, requests can now be made return OK; } break; case STATUS_REQUESTING: { while (true) { uint8_t byte; int rec = 0; Error err = _get_http_data(&byte, 1, rec); if (err != OK) { close(); status = STATUS_CONNECTION_ERROR; return ERR_CONNECTION_ERROR; } if (rec == 0) return OK; // Still requesting, keep trying! response_str.push_back(byte); int rs = response_str.size(); if ( (rs >= 2 && response_str[rs - 2] == '\n' && response_str[rs - 1] == '\n') || (rs >= 4 && response_str[rs - 4] == '\r' && response_str[rs - 3] == '\n' && response_str[rs - 2] == '\r' && response_str[rs - 1] == '\n')) { // End of response, parse. response_str.push_back(0); String response; response.parse_utf8((const char *)response_str.ptr()); Vector<String> responses = response.split("\n"); body_size = -1; chunked = false; body_left = 0; chunk_left = 0; read_until_eof = false; response_str.clear(); response_headers.clear(); response_num = RESPONSE_OK; // Per the HTTP 1.1 spec, keep-alive is the default, but in practice // it's safe to assume it only if the explicit header is found, allowing // to handle body-up-to-EOF responses on naive servers; that's what Curl // and browsers do bool keep_alive = false; for (int i = 0; i < responses.size(); i++) { String header = responses[i].strip_edges(); String s = header.to_lower(); if (s.length() == 0) continue; if (s.begins_with("content-length:")) { body_size = s.substr(s.find(":") + 1, s.length()).strip_edges().to_int(); body_left = body_size; } else if (s.begins_with("transfer-encoding:")) { String encoding = header.substr(header.find(":") + 1, header.length()).strip_edges(); if (encoding == "chunked") { chunked = true; } } else if (s.begins_with("connection: keep-alive")) { keep_alive = true; } if (i == 0 && responses[i].begins_with("HTTP")) { String num = responses[i].get_slicec(' ', 1); response_num = num.to_int(); } else { response_headers.push_back(header); } } if (body_size != -1 || chunked) { status = STATUS_BODY; } else if (!keep_alive) { read_until_eof = true; status = STATUS_BODY; } else { status = STATUS_CONNECTED; } return OK; } } // Wait for response return OK; } break; case STATUS_DISCONNECTED: { return ERR_UNCONFIGURED; } break; case STATUS_CONNECTION_ERROR: case STATUS_SSL_HANDSHAKE_ERROR: { return ERR_CONNECTION_ERROR; } break; case STATUS_CANT_CONNECT: { return ERR_CANT_CONNECT; } break; case STATUS_CANT_RESOLVE: { return ERR_CANT_RESOLVE; } break; } return OK; }
bool MultiplayerAPI::is_network_server() const { ERR_FAIL_COND_V(!network_peer.is_valid(), false); return network_peer->is_server(); }
void* MemoryPoolStaticMalloc::_alloc(size_t p_bytes,const char *p_description) { ERR_FAIL_COND_V(p_bytes==0,0); MutexLock lock(mutex); #ifdef DEBUG_MEMORY_ENABLED size_t total; #if defined(_add_overflow) if (_add_overflow(p_bytes, sizeof(RingPtr), &total)) return NULL; #else total = p_bytes + sizeof(RingPtr); #endif void *mem=malloc(total); /// add for size and ringlist if (!mem) { printf("**ERROR: out of memory while allocating %lu bytes by %s?\n", (unsigned long) p_bytes, p_description); printf("**ERROR: memory usage is %lu\n", (unsigned long) get_total_usage()); }; ERR_FAIL_COND_V(!mem,0); //out of memory, or unreasonable request /* setup the ringlist element */ RingPtr *ringptr = (RingPtr*)mem; /* setup the ringlist element data (description and size ) */ ringptr->size = p_bytes; ringptr->descr=p_description; if (ringlist) { /* existing ringlist */ /* assign next */ ringptr->next = ringlist->next; ringlist->next = ringptr; /* assign prev */ ringptr->prev = ringlist; ringptr->next->prev = ringptr; } else { /* non existing ringlist */ ringptr->next=ringptr; ringptr->prev=ringptr; ringlist=ringptr; } total_mem+=p_bytes; /* update statistics */ if (total_mem > max_mem ) max_mem = total_mem; total_pointers++; if (total_pointers > max_pointers) max_pointers=total_pointers; return ringptr + 1; /* return memory after ringptr */ #else void *mem=malloc(p_bytes); ERR_FAIL_COND_V(!mem,0); //out of memory, or unreasonable request return mem; #endif }
bool MultiplayerAPI::is_refusing_new_network_connections() const { ERR_FAIL_COND_V(!network_peer.is_valid(), false); return network_peer->is_refusing_new_connections(); }
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 {
Node *Node::duplicate(bool p_use_instancing) const { Node *node=NULL; bool instanced=false; if (cast_to<InstancePlaceholder>()) { const InstancePlaceholder *ip = cast_to<const InstancePlaceholder>(); InstancePlaceholder *nip = memnew( InstancePlaceholder ); nip->set_instance_path( ip->get_instance_path() ); node=nip; } else if (p_use_instancing && get_filename()!=String()) { Ref<PackedScene> res = ResourceLoader::load(get_filename()); ERR_FAIL_COND_V(res.is_null(),NULL); node=res->instance(); ERR_FAIL_COND_V(!node,NULL); instanced=true; } else { Object *obj = ObjectTypeDB::instance(get_type()); ERR_FAIL_COND_V(!obj,NULL); node = obj->cast_to<Node>(); if (!node) memdelete(obj); ERR_FAIL_COND_V(!node,NULL); } if (get_filename()!="") { //an instance node->set_filename(get_filename()); } List<PropertyInfo> plist; get_property_list(&plist); for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) { if (!(E->get().usage&PROPERTY_USAGE_STORAGE)) continue; String name = E->get().name; node->set( name, get(name) ); } node->set_name(get_name()); List<GroupInfo> gi; get_groups(&gi); for (List<GroupInfo>::Element *E=gi.front();E;E=E->next()) { node->add_to_group(E->get().name, E->get().persistent); } _duplicate_signals(this, node); for(int i=0;i<get_child_count();i++) { if (get_child(i)->data.parent_owned) continue; if (instanced && get_child(i)->data.owner==this) continue; //part of instance Node *dup = get_child(i)->duplicate(p_use_instancing); if (!dup) { memdelete(node); return NULL; } node->add_child(dup); } return node; }
PoolAllocator::ID PoolAllocator::alloc(int p_size) { ERR_FAIL_COND_V(p_size<1,POOL_ALLOCATOR_INVALID_ID); #ifdef DEBUG_ENABLED if (p_size > free_mem) OS::get_singleton()->debug_break(); #endif ERR_FAIL_COND_V(p_size>free_mem,POOL_ALLOCATOR_INVALID_ID); mt_lock(); if (entry_count==entry_max) { mt_unlock(); ERR_PRINT("entry_count==entry_max"); return POOL_ALLOCATOR_INVALID_ID; } int size_to_alloc=aligned(p_size); EntryIndicesPos new_entry_indices_pos; if (!find_hole(&new_entry_indices_pos, size_to_alloc)) { /* No hole could be found, try compacting mem */ compact(); /* Then search again */ if (!find_hole(&new_entry_indices_pos, size_to_alloc)) { mt_unlock(); ERR_PRINT("memory can't be compacted further"); return POOL_ALLOCATOR_INVALID_ID; } } EntryArrayPos new_entry_array_pos; bool found_free_entry=get_free_entry(&new_entry_array_pos); if (!found_free_entry) { mt_unlock(); ERR_FAIL_COND_V( !found_free_entry , POOL_ALLOCATOR_INVALID_ID ); } /* move all entry indices up, make room for this one */ for (int i=entry_count;i>new_entry_indices_pos;i-- ) { entry_indices[i]=entry_indices[i-1]; } entry_indices[new_entry_indices_pos]=new_entry_array_pos; entry_count++; Entry &entry=entry_array[ entry_indices[ new_entry_indices_pos ] ]; entry.len=p_size; entry.pos=(new_entry_indices_pos==0)?0:entry_end(entry_array[ entry_indices[ new_entry_indices_pos-1 ] ]); //alloc either at begining or end of previous entry.lock=0; entry.check=(check_count++)&CHECK_MASK; free_mem-=size_to_alloc; if (free_mem<free_mem_peak) free_mem_peak=free_mem; ID retval = (entry_indices[ new_entry_indices_pos ]<<CHECK_BITS)|entry.check; mt_unlock(); //ERR_FAIL_COND_V( (uintptr_t)get(retval)%align != 0, retval ); return retval; }
bool Node::is_greater_than(const Node *p_node) const { ERR_FAIL_NULL_V(p_node,false); ERR_FAIL_COND_V( !data.inside_tree, false ); ERR_FAIL_COND_V( !p_node->data.inside_tree, false ); ERR_FAIL_COND_V( data.depth<0, false); ERR_FAIL_COND_V( p_node->data.depth<0, false); #ifdef NO_ALLOCA Vector<int> this_stack; Vector<int> that_stack; this_stack.resize(data.depth); that_stack.resize(p_node->data.depth); #else int *this_stack=(int*)alloca(sizeof(int)*data.depth); int *that_stack=(int*)alloca(sizeof(int)*p_node->data.depth); #endif const Node *n = this; int idx=data.depth-1; while(n) { ERR_FAIL_INDEX_V(idx, data.depth,false); this_stack[idx--]=n->data.pos; n=n->data.parent; } ERR_FAIL_COND_V(idx!=-1,false); n = p_node; idx=p_node->data.depth-1; while(n) { ERR_FAIL_INDEX_V(idx, p_node->data.depth,false); that_stack[idx--]=n->data.pos; n=n->data.parent; } ERR_FAIL_COND_V(idx!=-1,false); idx=0; bool res; while(true) { // using -2 since out-of-tree or nonroot nodes have -1 int this_idx = (idx >= data.depth)? -2 : this_stack[idx]; int that_idx = (idx >= p_node->data.depth)? -2 : that_stack[idx]; if (this_idx > that_idx) { res=true; break; } else if (this_idx < that_idx) { res=false; break; } else if (this_idx == -2 ) { res=false; // equal break; } idx++; } return res; }
bool Physics2DDirectSpaceStateSW::cast_motion(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion, MotionCastCollision &r_result, const Set<RID>& p_exclude,uint32_t p_user_mask) { Shape2DSW *shape = static_cast<Physics2DServerSW*>(Physics2DServer::get_singleton())->shape_owner.get(p_shape); ERR_FAIL_COND_V(!shape,0); Rect2 aabb = p_xform.xform(shape->get_aabb()); aabb=aabb.merge(Rect2(aabb.pos+p_motion,aabb.size)); //motion int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,Space2DSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results); bool collided=false; r_result.travel=1; MotionCallbackRayCastData best_normal; best_normal.best_len=1e20; for(int i=0;i<amount;i++) { if (space->intersection_query_results[i]->get_type()==CollisionObject2DSW::TYPE_AREA) continue; //ignore area if (p_exclude.has( space->intersection_query_results[i]->get_self())) continue; //ignore excluded const CollisionObject2DSW *col_obj=space->intersection_query_results[i]; int shape_idx=space->intersection_query_subindex_results[i]; Matrix32 col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); //test initial overlap, does it collide if going all the way? if (!CollisionSolver2DSW::solve(shape,p_xform,p_motion,col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL)) { continue; } //test initial overlap if (CollisionSolver2DSW::solve(shape,p_xform,Vector2(),col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL)) { r_result.collider_id=col_obj->get_instance_id(); r_result.collider=r_result.collider_id!=0 ? ObjectDB::get_instance(col_obj->get_instance_id()) : NULL; r_result.shape=shape_idx; r_result.rid=col_obj->get_self(); r_result.travel=0; r_result.point=Vector2(); r_result.normal=Vector2(); return true; } #if 0 Vector2 mnormal=p_motion.normalized(); Matrix32 col_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); ShapeSW *col_shape = col_obj->get_shape(shape_idx); real_t min,max; col_shape->project_rangev(mnormal,col_shape_xform,min,max); real_t width = max-min; int a; Vector2 s[2]; col_shape->get_supports(col_shape_xform.basis_xform(mnormal).normalized(),s,a); Vector2 from = col_shape_xform.xform(s[0]); Vector2 to = from + p_motion; Matrix32 from_inv = col_shape_xform.affine_inverse(); Vector2 local_from = from_inv.xform(from-mnormal*width*0.1); //start from a little inside the bounding box Vector2 local_to = from_inv.xform(to); Vector2 rpos,rnorm; if (!col_shape->intersect_segment(local_from,local_to,rpos,rnorm)) return false; //ray hit something Vector2 hitpos = p_xform_B.xform(rpos); #endif //just do kinematic solving float low=0; float hi=1; Vector2 mnormal=p_motion.normalized(); for(int i=0;i<8;i++) { //steps should be customizable.. Matrix32 xfa = p_xform; float ofs = (low+hi)*0.5; Vector2 sep=mnormal; //important optimization for this to work fast enough bool collided = CollisionSolver2DSW::solve(shape,p_xform,p_motion*ofs,col_obj->get_shape(shape_idx),col_obj_xform,Vector2(),NULL,NULL,&sep); if (collided) { hi=ofs; } else { low=ofs; } } best_normal.shape_B=col_obj->get_shape(shape_idx); best_normal.motion=p_motion*hi; best_normal.b_xform=col_obj_xform; best_normal.b_xform_inv=col_obj_xform.affine_inverse(); bool sc = CollisionSolver2DSW::solve(shape,p_xform,p_motion*hi,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2() ,_motion_cbk_result,&best_normal); print_line("CLD: "+itos(sc)); if (collided && low>=r_result.travel) continue; collided=true; r_result.travel=low; r_result.collider_id=col_obj->get_instance_id(); r_result.collider=r_result.collider_id!=0 ? ObjectDB::get_instance(col_obj->get_instance_id()) : NULL; r_result.shape=shape_idx; r_result.rid=col_obj->get_self(); } if (collided) { ERR_FAIL_COND_V(best_normal.best_normal==Vector2(),false); r_result.normal=best_normal.best_normal; r_result.point=best_normal.best_contact; } return collided; }
float AnimationPlayer::get_current_animation_pos() const { ERR_FAIL_COND_V(!playback.current.from,0); return playback.current.pos; }
int BroadPhase2DHashGrid::get_subindex(ID p_id) const { const Map<ID,Element>::Element *E=element_map.find(p_id); ERR_FAIL_COND_V(!E,-1); return E->get().subindex; }
Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_resource,uint32_t p_flags) { Error err; if (p_flags&ResourceSaver::FLAG_COMPRESS) { FileAccessCompressed *fac = memnew( FileAccessCompressed ); fac->configure("RSCC"); f=fac; err = fac->_open(p_path,FileAccess::WRITE); if (err) memdelete(f); } else { f=FileAccess::open(p_path,FileAccess::WRITE,&err); } ERR_FAIL_COND_V(err,err); FileAccessRef _fref(f); relative_paths=p_flags&ResourceSaver::FLAG_RELATIVE_PATHS; skip_editor=p_flags&ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES; bundle_resources=p_flags&ResourceSaver::FLAG_BUNDLE_RESOURCES; big_endian=p_flags&ResourceSaver::FLAG_SAVE_BIG_ENDIAN; no_extensions=p_flags&ResourceSaver::FLAG_NO_EXTENSION; local_path=p_path.get_base_dir(); //bin_meta_idx = get_string_index("__bin_meta__"); //is often used, so create _find_resources(p_resource,true); if (!(p_flags&ResourceSaver::FLAG_COMPRESS)) { //save header compressed static const uint8_t header[4]={'R','S','R','C'}; f->store_buffer(header,4); } if (big_endian) { f->store_32(1); f->set_endian_swap(true); } else f->store_32(0); f->store_32(0); //64 bits file, false for now f->store_32(VERSION_MAJOR); f->store_32(VERSION_MINOR); f->store_32(FORMAT_VERSION); //f->store_32(saved_resources.size()+external_resources.size()); // load steps -not needed save_unicode_string(p_resource->get_type()); uint64_t md_at = f->get_pos(); f->store_64(0); //offset to impoty metadata for(int i=0;i<14;i++) f->store_32(0); // reserved List<ResourceData> resources; { for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) { ResourceData &rd = resources.push_back(ResourceData())->get(); rd.type=E->get()->get_type(); List<PropertyInfo> property_list; E->get()->get_property_list( &property_list ); for(List<PropertyInfo>::Element *F=property_list.front();F;F=F->next()) { if (skip_editor && F->get().name.begins_with("__editor")) continue; if (F->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && F->get().usage&PROPERTY_USAGE_BUNDLE)) { Property p; p.name_idx=get_string_index(F->get().name); p.value=E->get()->get(F->get().name); if (F->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && p.value.is_zero()) continue; p.pi=F->get(); rd.properties.push_back(p); } } } } f->store_32(strings.size()); //string table size for(int i=0;i<strings.size();i++) { //print_bl("saving string: "+strings[i]); save_unicode_string(strings[i]); } // save external resource table f->store_32(external_resources.size()); //amount of external resources for(Set<RES>::Element *E=external_resources.front();E;E=E->next()) { save_unicode_string(E->get()->get_save_type()); String path = E->get()->get_path(); if (no_extensions) path=path.basename()+".*"; save_unicode_string(path); } // save internal resource table f->store_32(saved_resources.size()); //amount of internal resources Vector<uint64_t> ofs_pos; for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) { RES r = E->get(); if (r->get_path()=="" || r->get_path().find("::")!=-1) save_unicode_string("local://"+itos(ofs_pos.size())); else save_unicode_string(r->get_path()); //actual external ofs_pos.push_back(f->get_pos()); f->store_64(0); //offset in 64 bits } Vector<uint64_t> ofs_table; // int saved_idx=0; //now actually save the resources for(List<ResourceData>::Element *E=resources.front();E;E=E->next()) { ResourceData & rd = E->get(); ofs_table.push_back(f->get_pos()); save_unicode_string(rd.type); f->store_32(rd.properties.size()); for (List<Property>::Element *F=rd.properties.front();F;F=F->next()) { Property &p=F->get(); f->store_32(p.name_idx); write_variant(p.value,F->get().pi); } } for(int i=0;i<ofs_table.size();i++) { f->seek(ofs_pos[i]); f->store_64(ofs_table[i]); } f->seek_end(); if (p_resource->get_import_metadata().is_valid()) { uint64_t md_pos = f->get_pos(); Ref<ResourceImportMetadata> imd=p_resource->get_import_metadata(); save_unicode_string(imd->get_editor()); f->store_32(imd->get_source_count()); for(int i=0;i<imd->get_source_count();i++) { save_unicode_string(imd->get_source_path(i)); save_unicode_string(imd->get_source_md5(i)); } List<String> options; imd->get_options(&options); f->store_32(options.size()); for(List<String>::Element *E=options.front();E;E=E->next()) { save_unicode_string(E->get()); write_variant(imd->get_option(E->get())); } f->seek(md_at); f->store_64(md_pos); f->seek_end(); } f->store_buffer((const uint8_t*)"RSRC",4); //magic at end f->close(); return OK; }