Beispiel #1
0
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;
}
Beispiel #2
0
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);
	}
}
Beispiel #4
0
/** \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);
			}
		}
	}
}
Beispiel #6
0
/**
 *  \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();
}
Beispiel #8
0
/**
 *  \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);
    }
}
Beispiel #9
0
/** \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();
}
Beispiel #10
0
/** \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);
    }
}
Beispiel #11
0
/** \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);
    }
}
Beispiel #12
0
/// 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();
}
Beispiel #13
0
/** \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;
}
Beispiel #14
0
/** \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;
}
Beispiel #15
0
/** \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;
}
Beispiel #16
0
/** \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;
}
Beispiel #17
0
/** \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;
}
Beispiel #18
0
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;
			}
		}
	}
}
Beispiel #19
0
/** \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;
}
Beispiel #20
0
/** \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;
}
Beispiel #23
0
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
    }
}
Beispiel #24
0
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();
}
Beispiel #25
0
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();
}