RecStatus::Type EncoderLink::GetRecordingStatus(void) { RecStatus::Type retval = RecStatus::Aborted; if (local) retval = tv->GetRecordingStatus(); else if (HasSockAndIncrRef()) { ReferenceLocker rlocker(sock); retval = sock->GetRecordingStatus(m_capturecardnum); } else LOG(VB_GENERAL, LOG_ERR, QString("Wanted to get status on recorder %1,\n\t\t\t" "but the backend is not there anymore\n") .arg(m_capturecardnum)); if (retval != RecStatus::Recording && retval != RecStatus::Tuning && retval != RecStatus::Failing) { endRecordingTime = MythDate::current().addDays(-2); startRecordingTime = endRecordingTime; chanid = 0; } return retval; }
void PtexReader::PackedFace::reduce(FaceData*& face, PtexReader* r, Res newres, PtexUtils::ReduceFn reducefn) { // get reduce lock and make sure we still need to reduce AutoMutex rlocker(r->reducelock); if (face) { // another thread must have generated it while we were waiting AutoLockCache clocker(_cache->cachelock); // make sure it's still there now that we have the lock if (face) { face->ref(); return; } } // allocate a new face and reduce image DataType dt = r->datatype(); int nchan = r->nchannels(); PackedFace* pf = new PackedFace((void**)&face, _cache, newres, _pixelsize, _pixelsize * newres.size()); // reduce and copy into new face reducefn(_data, _pixelsize * _res.u(), _res.u(), _res.v(), pf->_data, _pixelsize * newres.u(), dt, nchan); AutoLockCache clocker(_cache->cachelock); face = pf; // clean up unused data _cache->purgeData(); }
void CellObjectImplementation::destroyAllPlayerItems() { ManagedReference<SceneObject*> strongParent = getParent().get(); if (strongParent == NULL) return; int containerSize = getContainerObjectsSize(); for (int j = containerSize - 1; j >= 0; --j) { ReadLocker rlocker(getContainerLock()); ManagedReference<SceneObject*> containerObject = getContainerObject(j); rlocker.release(); if (strongParent->containsChildObject(containerObject)) continue; if (containerObject->isCreatureObject()) continue; containerObject->destroyObjectFromWorld(true); //containerObject->broadcastDestroy(containerObject, false); //removeObject(containerObject, false); containerObject->destroyObjectFromDatabase(true); } }
/** \fn EncoderLink::MatchesRecording(const ProgramInfo *rec) * \brief Returns true if rec is actually being recorded by TVRec. * * This waits for TVRec to enter a state other than kState_ChangingState * Then it checks TVRec::GetRecording() against rec. * \param rec Recording to check against TVRec::GetRecording(). * \sa IsRecording(const ProgramInfo*) */ bool EncoderLink::MatchesRecording(const ProgramInfo *rec) { bool retval = false; ProgramInfo *tvrec = NULL; if (local) { while (kState_ChangingState == GetState()) usleep(100); if (IsBusyRecording()) tvrec = tv->GetRecording(); if (tvrec) { retval = tvrec->IsSameRecording(*rec); delete tvrec; } } else { if (HasSockAndIncrRef()) { ReferenceLocker rlocker(sock); retval = sock->EncoderIsRecording(m_capturecardnum, rec); } } return retval; }
void ResourceManagerImplementation::givePlayerResource(CreatureObject* playerCreature, const String& restype, const int quantity) { ManagedReference<ResourceSpawn* > spawn = getResourceSpawn(restype); if(spawn == NULL) { playerCreature->sendSystemMessage("Selected spawn does not exist."); return; } ManagedReference<SceneObject*> inventory = playerCreature->getSlottedObject("inventory"); if(inventory != NULL && !inventory->isContainerFullRecursive()) { Locker locker(spawn); Reference<ResourceContainer*> newResource = spawn->createResource(quantity); if(newResource != NULL) { spawn->extractResource("", quantity); Locker rlocker(newResource); if (inventory->transferObject(newResource, -1, true)) { inventory->broadcastObject(newResource, true); } else { newResource->destroyObjectFromDatabase(true); } } } }
/** * \brief Appends total and used disk space in Kilobytes * * \param o_strlist list to append to */ void EncoderLink::GetDiskSpace(QStringList &o_strlist) { if (HasSockAndIncrRef()) { ReferenceLocker rlocker(sock); sock->GetDiskSpace(o_strlist); } }
int ZoneImplementation::getInRangeObjects(float x, float y, float range, SortedVector<ManagedReference<QuadTreeEntry*> >* objects, bool readLockZone) { //Locker locker(_this.getReferenceUnsafeStaticCast()); bool readlock = readLockZone && !_this.getReferenceUnsafeStaticCast()->isLockedByCurrentThread(); Vector<ManagedReference<QuadTreeEntry*> > buildingObjects; // _this.getReferenceUnsafeStaticCast()->rlock(readlock); try { _this.getReferenceUnsafeStaticCast()->rlock(readlock); quadTree->inRange(x, y, range, *objects); _this.getReferenceUnsafeStaticCast()->runlock(readlock); } catch (...) { _this.getReferenceUnsafeStaticCast()->runlock(readlock); } for (int i = 0; i < objects->size(); ++i) { SceneObject* sceneObject = cast<SceneObject*>(objects->get(i).get()); BuildingObject* building = dynamic_cast<BuildingObject*>(sceneObject); if (building != NULL) { for (int j = 1; j <= building->getMapCellSize(); ++j) { CellObject* cell = building->getCell(j); if (cell != NULL) { try { ReadLocker rlocker(cell->getContainerLock()); for (int h = 0; h < cell->getContainerObjectsSize(); ++h) { ManagedReference<SceneObject*> obj = cell->getContainerObject(h); if (obj != NULL) buildingObjects.add(obj.get()); } } catch (...) { } } } } else if (sceneObject != NULL && (sceneObject->isVehicleObject() || sceneObject->isMount())) { ManagedReference<SceneObject*> rider = sceneObject->getSlottedObject("rider"); if (rider != NULL) buildingObjects.add(rider.get()); } } //_this.getReferenceUnsafeStaticCast()->runlock(readlock); for (int i = 0; i < buildingObjects.size(); ++i) objects->put(buildingObjects.get(i)); return objects->size(); }
/** * \brief Tells TVRec where to put the next LiveTV recording. */ void EncoderLink::SetNextLiveTVDir(QString dir) { if (local) tv->SetNextLiveTVDir(dir); else if (HasSockAndIncrRef()) { ReferenceLocker rlocker(sock); sock->SetNextLiveTVDir(m_capturecardnum, dir); } }
/** \brief Tell a slave to go to sleep */ bool EncoderLink::GoToSleep(void) { if (IsLocal() || !HasSockAndIncrRef()) return false; ReferenceLocker rlocker(sock); lastSleepTime = MythDate::current(); return sock->GoToSleep(); }
/** \fn EncoderLink::CancelNextRecording(bool) * \brief Tells TVRec to cancel the next recording. * * This is used when the user is watching "Live TV" and does not * want to allow the recorder to be taken for a pending recording. * * \sa RecordPending(const ProgramInfo*, int, bool) */ void EncoderLink::CancelNextRecording(bool cancel) { if (local) tv->CancelNextRecording(cancel); else if (HasSockAndIncrRef()) { ReferenceLocker rlocker(sock); sock->CancelNextRecording(m_capturecardnum, cancel); } }
/** \fn EncoderLink::RecordPending(const ProgramInfo*, int, bool) * \brief Tells TVRec there is a pending recording "rec" in "secsleft" seconds. * * \param rec Recording to make. * \param secsleft Seconds to wait before starting recording. * \param hasLater If true, a later non-conflicting showing is available. * \sa StartRecording(const ProgramInfo*), CancelNextRecording(bool) */ void EncoderLink::RecordPending(const ProgramInfo *rec, int secsleft, bool hasLater) { if (local) tv->RecordPending(rec, secsleft, hasLater); else if (HasSockAndIncrRef()) { ReferenceLocker rlocker(sock); sock->RecordPending(m_capturecardnum, rec, secsleft, hasLater); } }
/// Checks if program is stored locally bool EncoderLink::CheckFile(ProgramInfo *pginfo) { if (HasSockAndIncrRef()) { ReferenceLocker rlocker(sock); return sock->CheckFile(pginfo); } pginfo->SetPathname(GetPlaybackURL(pginfo)); return pginfo->IsLocal(); }
/** \fn EncoderLink::SetSignalMonitoringRate(int,int) * \brief Sets the signal monitoring rate. * * May be a local or remote query. * * \sa TVRec::SetSignalMonitoringRate(int,int), * RemoteEncoder::SetSignalMonitoringRate(int,int) * \param rate Milliseconds between each signal check, * 0 to disable, -1 to preserve old value. * \param notifyFrontend If 1 SIGNAL messages are sent to the frontend, * if 0 SIGNAL messages will not be sent, and if * -1 the old value is preserved. * \return Old rate if it succeeds, -1 if it fails. */ int EncoderLink::SetSignalMonitoringRate(int rate, int notifyFrontend) { if (local) return tv->SetSignalMonitoringRate(rate, notifyFrontend); else if (HasSockAndIncrRef()) { ReferenceLocker rlocker(sock); return sock->SetSignalMonitoringRate(m_capturecardnum, rate, notifyFrontend); } return -1; }
/** \fn EncoderLink::GetMaxBitrate() * \brief Returns maximum bits per second this recorder might output. * * \sa TVRec::GetFreeSpace(long long), RemoteEncoder::GetFreeSpace(long long) * May be a local or remote query. */ long long EncoderLink::GetMaxBitrate() { if (local) return tv->GetMaxBitrate(); else if (HasSockAndIncrRef()) { ReferenceLocker rlocker(sock); return sock->GetMaxBitrate(m_capturecardnum); } return -1; }
/** \fn EncoderLink::IsBusy(InputInfo*,int) * \brief Returns true if the recorder is busy, or will be within the * next time_buffer seconds. * \sa IsBusyRecording(void), TVRec::IsBusy(InputInfo*) */ bool EncoderLink::IsBusy(InputInfo *busy_input, int time_buffer) { if (local) return tv->IsBusy(busy_input, time_buffer); if (HasSockAndIncrRef()) { ReferenceLocker rlocker(sock); return sock->IsBusy(m_capturecardnum, busy_input, time_buffer); } return false; }
/** \fn EncoderLink::GetRecording() * \brief Returns TVRec's current recording. * * Caller is responsible for deleting the ProgramInfo when done with it. * \return Returns TVRec's current recording if it succeeds, NULL otherwise. */ ProgramInfo *EncoderLink::GetRecording(void) { ProgramInfo *info = NULL; if (local) info = tv->GetRecording(); else if (HasSockAndIncrRef()) { ReferenceLocker rlocker(sock); info = sock->GetRecording(m_capturecardnum); } return info; }
/** \fn EncoderLink::GetFreeInputs(const vector<uint>&) const * \brief Returns TVRec's recorders connected inputs. * * \sa TVRec::GetFreeInputs(const vector<uint>&) const */ vector<InputInfo> EncoderLink::GetFreeInputs( const vector<uint> &excluded_cardids) { vector<InputInfo> list; if (local) list = tv->GetFreeInputs(excluded_cardids); else if (HasSockAndIncrRef()) { ReferenceLocker rlocker(sock); list = sock->GetFreeInputs(m_capturecardnum, excluded_cardids); } return list; }
void StructureManager::moveFirstItemTo(CreatureObject* creature, StructureObject* structure) { if (!structure->isBuildingObject()) return; ManagedReference<BuildingObject*> building = cast<BuildingObject*>(structure); Locker _lock(building, creature); for (uint32 i = 1; i <= building->getTotalCellNumber(); ++i) { ManagedReference<CellObject*> cell = building->getCell(i); int size = cell->getContainerObjectsSize(); for (int j = 0; j < cell->getContainerObjectsSize(); ++j) { ReadLocker rlocker(cell->getContainerLock()); ManagedReference<SceneObject*> childObject = cell->getContainerObject(j); rlocker.release(); if (childObject->isVendor()) continue; //if (!building->containsChildObject(childObject) && !childObject->isCreatureObject()) { if (creature->getParent() != NULL && !building->containsChildObject(childObject) && !childObject->isCreatureObject()) { if (creature->getParent().get()->getParent().get() == childObject->getParent().get()->getParent().get()) { childObject->teleport(creature->getPositionX(), creature->getPositionZ(), creature->getPositionY(), creature->getParentID()); creature->sendSystemMessage( "@player_structure:moved_first_item"); //The first item in your house has been moved to your location. } return; } } } }
/** \fn EncoderLink::GetFlags(void) const * \brief Returns the flag state of the recorder. * \sa TVRec::GetFlags(void) const, \ref recorder_subsystem */ uint EncoderLink::GetFlags(void) { uint retval = 0; if (!IsConnected()) return retval; if (local) retval = tv->GetFlags(); else if (HasSockAndIncrRef()) { ReferenceLocker rlocker(sock); retval = sock->GetEncoderState(m_capturecardnum); } else LOG(VB_GENERAL, LOG_ERR, LOC + "GetFlags failed"); return retval; }
/** \fn EncoderLink::GetState() * \brief Returns the TVState of the recorder. * \sa TVRec::GetState(), \ref recorder_subsystem */ TVState EncoderLink::GetState(void) { TVState retval = kState_Error; if (!IsConnected()) return retval; if (local) retval = tv->GetState(); else if (HasSockAndIncrRef()) { ReferenceLocker rlocker(sock); retval = (TVState)sock->GetEncoderState(m_capturecardnum); } else LOG(VB_GENERAL, LOG_ERR, QString("Broken for card: %1") .arg(m_capturecardnum)); return retval; }
int CellObjectImplementation::getCurrentNumberOfPlayerItems() { int count = 0; ManagedReference<SceneObject*> strongParent = getParent().get(); if (strongParent != NULL) { for (int j = 0; j < getContainerObjectsSize(); ++j) { ReadLocker rlocker(getContainerLock()); ManagedReference<SceneObject*> containerObject = getContainerObject(j); rlocker.release(); if (!strongParent->containsChildObject(containerObject) && !containerObject->isCreatureObject() && !containerObject->isVendor()) { if (containerObject->isContainerObject()) count += containerObject->getCountableObjectsRecursive(); ++count; } } } return count; }
void PlanetManagerImplementation::loadClientRegions() { TemplateManager* templateManager = TemplateManager::instance(); IffStream* iffStream = templateManager->openIffFile("datatables/clientregion/" + zone->getZoneName() + ".iff"); Reference<PlanetMapCategory*> cityCat = TemplateManager::instance()->getPlanetMapCategoryByName("city"); if (iffStream == NULL) { info("No client regions found."); return; } DataTableIff dtiff; dtiff.readObject(iffStream); for (int i = 0; i < dtiff.getTotalRows(); ++i) { String regionName; float x, y, radius; DataTableRow* row = dtiff.getRow(i); row->getValue(0, regionName); row->getValue(1, x); row->getValue(2, y); row->getValue(3, radius); ManagedReference<CityRegion*> cityRegion = regionMap.getRegion(regionName); if (cityRegion == NULL) { cityRegion = new CityRegion(); Locker locker(cityRegion); cityRegion->deploy(); cityRegion->setRegionName(regionName); cityRegion->setZone(zone); regionMap.addRegion(cityRegion); } Locker locker(cityRegion); ManagedReference<Region*> region = cityRegion->addRegion(x, y, radius, false); locker.release(); if (region != NULL) { Locker rlocker(region); if (cityRegion->getRegionsCount() == 1) {//Register the first region only. region->setPlanetMapCategory(cityCat); zone->registerObjectWithPlanetaryMap(region); } region->setMunicipalZone(true); ManagedReference<SceneObject*> scenery = NULL; if (gcwManager != NULL) { int strongholdFaction = gcwManager->isStrongholdCity(regionName); if (strongholdFaction == GCWManager::IMPERIALHASH || regionName.contains("imperial")) { scenery = zone->getZoneServer()->createObject(STRING_HASHCODE("object/static/particle/particle_distant_ships_imperial.iff"), 0); } else if (strongholdFaction == GCWManager::REBELHASH || regionName.contains("rebel")) { scenery = zone->getZoneServer()->createObject(STRING_HASHCODE("object/static/particle/particle_distant_ships_rebel.iff"), 0); } else { scenery = zone->getZoneServer()->createObject(STRING_HASHCODE("object/static/particle/particle_distant_ships.iff"), 0); } } else { scenery = zone->getZoneServer()->createObject(STRING_HASHCODE("object/static/particle/particle_distant_ships.iff"), 0); } Locker slocker(scenery, region); scenery->initializePosition(x, zone->getHeight(x, y) + 100, y); region->attachScenery(scenery); } ManagedReference<ActiveArea*> noBuild = zone->getZoneServer()->createObject(STRING_HASHCODE("object/active_area.iff"), 0).castTo<ActiveArea*>(); Locker areaLocker(noBuild); noBuild->initializePosition(x, 0, y); ManagedReference<CircularAreaShape*> areaShape = new CircularAreaShape(); Locker shapeLocker(areaShape); areaShape->setRadius(radius * 2); areaShape->setAreaCenter(x, y); noBuild->setAreaShape(areaShape); noBuild->setRadius(radius * 2); noBuild->setNoBuildArea(true); // Cities already have "Municipal" protection so the structure no-build should not apply to camps noBuild->setCampingPermitted(true); Locker zoneLocker(zone); zone->transferObject(noBuild, -1, true); } info("Added " + String::valueOf(regionMap.getTotalRegions()) + " client regions."); delete iffStream; }
void FileReadThread::process() { // entered with m_mutex locked and m_queue non-empty Profiler profiler("FileReadThread::process", true); int token = m_queue.begin()->first; Request request = m_queue.begin()->second; m_mutex.unlock(); #ifdef DEBUG_FILE_READ_THREAD std::cerr << "FileReadThread::process: reading " << request.start << ", " << request.size << " on " << request.fd << std::endl; #endif bool successful = false; bool seekFailed = false; ssize_t r = 0; { MutexLocker rlocker(request.mutex, "FileReadThread::process::request.mutex"); if (::lseek(request.fd, request.start, SEEK_SET) == (off_t)-1) { seekFailed = true; } else { // if request.size is large, we want to avoid making a single // system call to read it all as it may block too much static const size_t blockSize = 256 * 1024; size_t size = request.size; char *destination = request.data; while (size > 0) { size_t readSize = size; if (readSize > blockSize) readSize = blockSize; ssize_t br = ::read(request.fd, destination, readSize); if (br < 0) { r = br; break; } else { r += br; if (br < ssize_t(readSize)) break; } destination += readSize; size -= readSize; } } } if (seekFailed) { ::perror("Seek failed"); std::cerr << "ERROR: FileReadThread::process: seek to " << request.start << " failed" << std::endl; request.size = 0; } else { if (r < 0) { ::perror("ERROR: FileReadThread::process: Read failed"); std::cerr << "ERROR: FileReadThread::process: read of " << request.size << " at " << request.start << " failed" << std::endl; request.size = 0; } else if (r < ssize_t(request.size)) { std::cerr << "WARNING: FileReadThread::process: read " << request.size << " returned only " << r << " bytes" << std::endl; request.size = r; usleep(100000); } else { successful = true; } } // Check that the token hasn't been cancelled and the thread // hasn't been asked to finish m_mutex.lock(); request.successful = successful; if (m_queue.find(token) != m_queue.end() && !m_exiting) { m_queue.erase(token); m_readyRequests[token] = request; #ifdef DEBUG_FILE_READ_THREAD std::cerr << "FileReadThread::process: done, marking as ready (success = " << m_readyRequests[token].successful << ")" << std::endl; #endif } else { #ifdef DEBUG_FILE_READ_THREAD if (m_exiting) { std::cerr << "FileReadThread::process: exiting" << std::endl; } else { std::cerr << "FileReadThread::process: request disappeared" << std::endl; } #endif } }
void PtexReader::blendFaces(FaceData*& face, int faceid, Res res, bool blendu) { Res pres; // parent res, 1 higher in blend direction int length; // length of blend edge (1xN or Nx1) int e1, e2; // neighboring edge ids if (blendu) { assert(res.ulog2 < 0); // res >= 0 requires reduction, not blending length = (res.vlog2 <= 0 ? 1 : res.v()); e1 = e_bottom; e2 = e_top; pres = Res(res.ulog2+1, res.vlog2); } else { assert(res.vlog2 < 0); length = (res.ulog2 <= 0 ? 1 : res.u()); e1 = e_right; e2 = e_left; pres = Res(res.ulog2, res.vlog2+1); } // get neighbor face ids FaceInfo& f = _faceinfo[faceid]; int nf1 = f.adjfaces[e1], nf2 = f.adjfaces[e2]; // compute rotation of faces relative to current int r1 = (f.adjedge(e1)-e1+2)&3; int r2 = (f.adjedge(e2)-e2+2)&3; // swap u and v res for faces rotated +/- 90 degrees Res pres1 = pres, pres2 = pres; if (r1 & 1) pres1.swapuv(); if (r2 & 1) pres2.swapuv(); // ignore faces that have insufficient res (unlikely, but possible) if (nf1 >= 0 && !(_faceinfo[nf1].res >= pres)) nf1 = -1; if (nf2 >= 0 && !(_faceinfo[nf2].res >= pres)) nf2 = -1; // get parent face data int nf = 1; // number of faces to blend (1 to 3) bool flip[3]; // true if long dimension needs to be flipped PtexFaceData* psrc[3]; // the face data psrc[0] = getData(faceid, pres); flip[0] = 0; // don't flip main face if (nf1 >= 0) { // face must be flipped if rot is 1 or 2 for blendu, or 2 or 3 for blendv // thus, just add the blendu bool val to align the ranges and check bit 1 // also, no need to flip if length is zero flip[nf] = length ? (r1 + blendu) & 1 : 0; psrc[nf++] = getData(nf1, pres1); } if (nf2 >= 0) { flip[nf] = length ? (r2 + blendu) & 1 : 0; psrc[nf++] = getData(nf2, pres2); } // get reduce lock and make sure we still need to reduce AutoMutex rlocker(reducelock); if (face) { // another thread must have generated it while we were waiting AutoLockCache locker(_cache->cachelock); // make sure it's still there now that we have the lock if (face) { face->ref(); // release parent data for (int i = 0; i < nf; i++) psrc[i]->release(); return; } } // allocate a new face data (1 x N or N x 1) DataType dt = datatype(); int nchan = nchannels(); int size = _pixelsize * length; PackedFace* pf = new PackedFace((void**)&face, _cache, res, _pixelsize, size); void* data = pf->getData(); if (nf == 1) { // no neighbors - just copy face memcpy(data, psrc[0]->getData(), size); } else { float weight = 1.0f / nf; memset(data, 0, size); for (int i = 0; i < nf; i++) PtexUtils::blend(psrc[i]->getData(), weight, data, flip[i], length, dt, nchan); } { AutoLockCache clocker(_cache->cachelock); face = pf; // clean up unused data _cache->purgeData(); } // release parent data for (int i = 0; i < nf; i++) psrc[i]->release(); }
void PtexReader::TiledFaceBase::reduce(FaceData*& face, PtexReader* r, Res newres, PtexUtils::ReduceFn reducefn) { // get reduce lock and make sure we still need to reduce AutoMutex rlocker(r->reducelock); if (face) { // another thread must have generated it while we were waiting AutoLockCache clocker(_cache->cachelock); // make sure it's still there now that we have the lock if (face) { face->ref(); return; } } /* Tiled reductions should generally only be anisotropic (just u or v, not both) since isotropic reductions are precomputed and stored on disk. (This function should still work for isotropic reductions though.) In the anisotropic case, the number of tiles should be kept the same along the direction not being reduced in order to preserve the laziness of the file access. In contrast, if reductions were not tiled, then any reduction would read all the tiles and defeat the purpose of tiling. */ // keep new face local until fully initialized FaceData* volatile newface = 0; // don't tile if either dimension is 1 (rare, would complicate blendFaces too much) // also, don't tile triangle reductions (too complicated) Res newtileres; bool isTriangle = r->_header.meshtype == mt_triangle; if (newres.ulog2 == 1 || newres.vlog2 == 1 || isTriangle) { newtileres = newres; } else { // propagate the tile res to the reduction newtileres = _tileres; // but make sure tile isn't larger than the new face! if (newtileres.ulog2 > newres.ulog2) newtileres.ulog2 = newres.ulog2; if (newtileres.vlog2 > newres.vlog2) newtileres.vlog2 = newres.vlog2; } // determine how many tiles we will have on the reduction int newntiles = newres.ntiles(newtileres); if (newntiles == 1) { // no need to keep tiling, reduce tiles into a single face // first, get all tiles and check if they are constant (with the same value) PtexFaceData** tiles = (PtexFaceData**) alloca(_ntiles * sizeof(PtexFaceData*)); bool allConstant = true; for (int i = 0; i < _ntiles; i++) { PtexFaceData* tile = tiles[i] = getTile(i); allConstant = (allConstant && tile->isConstant() && (i == 0 || (0 == memcmp(tiles[0]->getData(), tile->getData(), _pixelsize)))); } if (allConstant) { // allocate a new constant face newface = new ConstantFace((void**)&face, _cache, _pixelsize); memcpy(newface->getData(), tiles[0]->getData(), _pixelsize); } else if (isTriangle) { // reassemble all tiles into temporary contiguous image // (triangle reduction doesn't work on tiles) int tileures = _tileres.u(); int tilevres = _tileres.v(); int sstride = _pixelsize * tileures; int dstride = sstride * _ntilesu; int dstepv = dstride * tilevres - sstride*(_ntilesu-1); char* tmp = (char*) malloc(_ntiles * _tileres.size() * _pixelsize); char* tmpptr = tmp; for (int i = 0; i < _ntiles;) { PtexFaceData* tile = tiles[i]; if (tile->isConstant()) PtexUtils::fill(tile->getData(), tmpptr, dstride, tileures, tilevres, _pixelsize); else PtexUtils::copy(tile->getData(), sstride, tmpptr, dstride, tilevres, sstride); i++; tmpptr += i%_ntilesu ? sstride : dstepv; } // allocate a new packed face newface = new PackedFace((void**)&face, _cache, newres, _pixelsize, _pixelsize * newres.size()); // reduce and copy into new face reducefn(tmp, _pixelsize * _res.u(), _res.u(), _res.v(), newface->getData(), _pixelsize * newres.u(), _dt, _nchan); free(tmp); } else { // allocate a new packed face newface = new PackedFace((void**)&face, _cache, newres, _pixelsize, _pixelsize*newres.size()); int tileures = _tileres.u(); int tilevres = _tileres.v(); int sstride = _pixelsize * tileures; int dstride = _pixelsize * newres.u(); int dstepu = dstride/_ntilesu; int dstepv = dstride*newres.v()/_ntilesv - dstepu*(_ntilesu-1); char* dst = (char*) newface->getData(); for (int i = 0; i < _ntiles;) { PtexFaceData* tile = tiles[i]; if (tile->isConstant()) PtexUtils::fill(tile->getData(), dst, dstride, newres.u()/_ntilesu, newres.v()/_ntilesv, _pixelsize); else reducefn(tile->getData(), sstride, tileures, tilevres, dst, dstride, _dt, _nchan); i++; dst += i%_ntilesu ? dstepu : dstepv; } } // release the tiles for (int i = 0; i < _ntiles; i++) tiles[i]->release(); } else { // otherwise, tile the reduced face newface = new TiledReducedFace((void**)&face, _cache, newres, newtileres, _dt, _nchan, this, reducefn); } AutoLockCache clocker(_cache->cachelock); face = newface; // clean up unused data _cache->purgeData(); }