void CityOnPlanet::PutCityBit(MTRand &rand, const matrix4x4d &rot, vector3d p1, vector3d p2, vector3d p3, vector3d p4) { double rad = (p1-p2).Length()*0.5; LmrModel *model(0); double modelRadXZ(0); const LmrCollMesh *cmesh(0); vector3d cent = (p1+p2+p3+p4)*0.25; cityflavourdef_t *flavour(0); citybuildinglist_t *buildings(0); // pick a building flavour (city, windfarm, etc) for (int flv=0; flv<CITYFLAVOURS; flv++) { flavour = &cityflavour[flv]; buildings = &s_buildingLists[flavour->buildingListIdx]; int tries; for (tries=20; tries--; ) { const citybuilding_t &bt = buildings->buildings[rand.Int32(buildings->numBuildings)]; model = bt.resolvedModel; modelRadXZ = bt.xzradius; cmesh = bt.collMesh; if (modelRadXZ < rad) break; if (tries == 0) return; } bool tooDistant = ((flavour->center - cent).Length()*(1.0/flavour->size) > rand.Double()); if (!tooDistant) break; else flavour = 0; } if (flavour == 0) { if (rad > MIN_SEG_SIZE) goto always_divide; else return; } if (rad > modelRadXZ*2.0) { always_divide: vector3d a = (p1+p2)*0.5; vector3d b = (p2+p3)*0.5; vector3d c = (p3+p4)*0.5; vector3d d = (p4+p1)*0.5; vector3d e = (p1+p2+p3+p4)*0.25; PutCityBit(rand, rot, p1, a, e, d); PutCityBit(rand, rot, a, p2, b, e); PutCityBit(rand, rot, e, b, p3, c); PutCityBit(rand, rot, d, e, c, p4); } else { cent = cent.Normalized(); double height = m_planet->GetTerrainHeight(cent); /* don't position below sealevel! */ if (height - m_planet->GetSBody()->GetRadius() <= 0.0) return; cent = cent * height; assert(cmesh); Geom *geom = new Geom(cmesh->geomTree); int rotTimes90 = rand.Int32(4); matrix4x4d grot = rot * matrix4x4d::RotateYMatrix(M_PI*0.5*double(rotTimes90)); geom->MoveTo(grot, cent); geom->SetUserData(this); // f->AddStaticGeom(geom); BuildingDef def = { model, cmesh->GetBoundingRadius(), rotTimes90, cent, geom, false }; m_buildings.push_back(def); } }
heap::heap(live_heap &&h) { assert(h.is_contiguous()); log_debug("freezing heap with ID %d, %d item pointers, %d bytes payload", h.get_cnt(), h.pointers.size(), h.min_length); /* The length of addressed items is measured from the item to the * address of the next item, or the end of the heap. We may receive * packets (and hence pointers) out-of-order, so we have to sort. * The mask preserves both the address and the immediate-mode flag, * so that all addressed items sort together. * * The sort needs to be stable, because there can be zero-length fields. * TODO: these can still break if they cross packet boundaries. */ item_pointer_t sort_mask = immediate_mask | ((item_pointer_t(1) << h.heap_address_bits) - 1); auto compare = [sort_mask](item_pointer_t a, item_pointer_t b) { return (a & sort_mask) < (b & sort_mask); }; std::stable_sort(h.pointers.begin(), h.pointers.end(), compare); pointer_decoder decoder(h.heap_address_bits); // Determine how much memory is needed to store immediates std::size_t n_immediates = 0; for (std::size_t i = 0; i < h.pointers.size(); i++) { item_pointer_t pointer = h.pointers[i]; if (decoder.is_immediate(pointer)) n_immediates++; } // Allocate memory const std::size_t immediate_size = h.heap_address_bits / 8; const std::size_t id_size = sizeof(item_pointer_t) - immediate_size; if (n_immediates > 0) immediate_payload.reset(new uint8_t[immediate_size * n_immediates]); uint8_t *next_immediate = immediate_payload.get(); items.reserve(h.pointers.size()); for (std::size_t i = 0; i < h.pointers.size(); i++) { item new_item; item_pointer_t pointer = h.pointers[i]; new_item.id = decoder.get_id(pointer); if (new_item.id == 0) continue; // just padding new_item.is_immediate = decoder.is_immediate(pointer); if (new_item.is_immediate) { new_item.ptr = next_immediate; new_item.length = immediate_size; item_pointer_t pointer_be = htobe<item_pointer_t>(pointer); std::memcpy( next_immediate, reinterpret_cast<const std::uint8_t *>(&pointer_be) + id_size, immediate_size); log_debug("Found new immediate item ID %d, value %d", new_item.id, decoder.get_immediate(pointer)); next_immediate += immediate_size; } else { s_item_pointer_t start = decoder.get_address(pointer); s_item_pointer_t end; if (i + 1 < h.pointers.size() && !decoder.is_immediate(h.pointers[i + 1])) end = decoder.get_address(h.pointers[i + 1]); else end = h.min_length; if (start == end) { log_debug("skipping empty item %d", new_item.id); continue; } new_item.ptr = h.payload.get() + start; new_item.length = end - start; log_debug("found new addressed item ID %d, offset %d, length %d", new_item.id, start, end - start); } items.push_back(new_item); } cnt = h.cnt; flavour_ = flavour(maximum_version, 8 * sizeof(item_pointer_t), h.heap_address_bits, h.bug_compat); payload = std::move(h.payload); // Reset h so that it still satisfies its invariants h = live_heap(0, h.bug_compat); }