Exemple #1
0
void CBitmap::Blur(int iterations, float weight)
{
	if (type == BitmapTypeDDS) {
		return;
	}

	CBitmap* src = this;
	CBitmap* dst = new CBitmap();
	dst->channels = src->channels;
	dst->Alloc(xsize,ysize);

	for (int i=0; i < iterations; ++i){
		{
			for_mt(0, ysize, [&](const int y) {
				for (int x=0; x < xsize; x++) {
					for (int j=0; j < channels; j++) {
						kernelBlur(dst, src->mem, x, y, j, weight);
					}
				}
			});
		}
		std::swap(src, dst);
	}

	if (dst == this) {
		// make sure we don't delete `this`
		std::swap(src, dst);
	}

	delete dst;
}
void CGrassDrawer::DrawNearBillboards(const std::vector<InviewNearGrass>& inviewNearGrass)
{
	if (farnearVA->drawIndex() == 0) {
		auto* va_tn = farnearVA->GetTypedVertexArray<VA_TYPE_TN>(inviewNearGrass.size() * numTurfs * 4);
		for_mt(0, inviewNearGrass.size(), [&](const int i){
			const InviewNearGrass& gi = inviewNearGrass[i];
			DrawBillboard(gi.x, gi.y, gi.dist, &va_tn[i * numTurfs * 4]);
		});
	}

	farnearVA->DrawArrayTN(GL_QUADS);
}
Exemple #3
0
/*
 *  Draws a trigonometric circle in 'resolution' steps, with a slope modifier
 */
void glBallisticCircle(const float3& center, const float radius,
                       const CWeapon* weapon,
                       unsigned int resolution, float slope)
{
    int rdiv = 50;
    resolution *= 2;
    rdiv *= 1;
    CVertexArray* va = GetVertexArray();
    va->Initialize();
    va->EnlargeArrays(resolution, 0, VA_SIZE_0);

    float3* vertices = reinterpret_cast<float3*>(va->drawArray);
    va->drawArrayPos = va->drawArray + resolution * 3;

    for_mt(0, resolution, [&](const int i) {
        const float radians = (2.0f * PI) * (float)i / (float)resolution;
        float rad = radius;
        float sinR = fastmath::sin(radians);
        float cosR = fastmath::cos(radians);
        float3 pos;
        pos.x = center.x + (sinR * rad);
        pos.z = center.z + (cosR * rad);
        pos.y = CGround::GetHeightAboveWater(pos.x, pos.z, false);
        float heightDiff = (pos.y - center.y) * 0.5f;
        rad -= heightDiff * slope;
        float adjRadius = weapon ? weapon->GetRange2D(heightDiff * weapon->heightMod) : rad;
        float adjustment = rad * 0.5f;
        float ydiff = 0;
        for(int j = 0; j < rdiv && math::fabs(adjRadius - rad) + ydiff > .01 * rad; j++) {
            if (adjRadius > rad) {
                rad += adjustment;
            } else {
                rad -= adjustment;
                adjustment /= 2;
            }
            pos.x = center.x + (sinR * rad);
            pos.z = center.z + (cosR * rad);
            float newY = CGround::GetHeightAboveWater(pos.x, pos.z, false);
            ydiff = math::fabs(pos.y - newY);
            pos.y = newY;
            heightDiff = (pos.y - center.y);
            adjRadius = weapon ? weapon->GetRange2D(heightDiff * weapon->heightMod) : rad;
        }
        pos.x = center.x + (sinR * adjRadius);
        pos.z = center.z + (cosR * adjRadius);
        pos.y = CGround::GetHeightAboveWater(pos.x, pos.z, false) + 5.0f;

        vertices[i] = pos;
    });

    va->DrawArray0(GL_LINE_LOOP);
}
inline static void BlurVertical(
	const int maxx,
	const int maxy,
	const int smoothrad,
	const float resolution,
	const std::vector<float>& mesh,
	std::vector<float>& smoothed)
{
	const float n = 2.0f * smoothrad + 1.0f;
	const float recipn = 1.0f / n;
	const int lineSize = maxx + 1;

	for_mt(0, maxx+1, [&](const int x) {
		float avg = 0.0f;

		for (int y = 0; y <= 2 * smoothrad; ++y) {
			avg += mesh[x + y * lineSize];
		}

		for (int y = 0; y <= maxy; ++y) {
			const int idx = x + y * lineSize;

			if (y <= smoothrad || y > (maxy - smoothrad)) {
				// map-border case
				smoothed[idx] = 0.0f;

				const int ystart = std::max(y - smoothrad, 0);
				const int yend   = std::min(y + smoothrad, maxy);

				for (int y1 = ystart; y1 <= yend; ++y1) {
					smoothed[idx] += mesh[x + y1 * lineSize];
				}

				const float gh = CGround::GetHeightAboveWater(x * resolution, y * resolution);
				const float sh = smoothed[idx] / (yend - ystart + 1);

				smoothed[idx] = std::min(readMap->GetCurrMaxHeight(), std::max(gh, sh));
			} else {
				// non-border case
				avg += mesh[x + (y + smoothrad) * lineSize] - mesh[x + (y - smoothrad - 1) * lineSize];

				const float gh = CGround::GetHeightAboveWater(x * resolution, y * resolution);
				const float sh = recipn * avg;

				smoothed[idx] = std::min(readMap->GetCurrMaxHeight(), std::max(gh, sh));
			}

			assert(smoothed[idx] <= std::max(readMap->GetCurrMaxHeight(), 0.0f));
			assert(smoothed[idx] >=          readMap->GetCurrMinHeight()       );
		}
	});
}
inline static void BlurHorizontal(
	const int maxx,
	const int maxy,
	const int smoothrad,
	const float resolution,
	const std::vector<float>& mesh,
	std::vector<float>& smoothed)
{
	const float n = 2.0f * smoothrad + 1.0f;
	const float recipn = 1.0f / n;
	const int lineSize = maxx + 1;

	for_mt(0, maxy+1, [&](const int y) {
		float avg = 0.0f;

		for (int x = 0; x <= 2 * smoothrad; ++x) {
			avg += mesh[x + y * lineSize];
		}

		for (int x = 0; x <= maxx; ++x) {
			const int idx = x + y * lineSize;

			if (x <= smoothrad || x > (maxx - smoothrad)) {
				// map-border case
				smoothed[idx] = 0.0f;

				const int xstart = std::max(x - smoothrad, 0);
				const int xend   = std::min(x + smoothrad, maxx);

				for (int x1 = xstart; x1 <= xend; ++x1) {
					smoothed[idx] += mesh[x1 + y * lineSize];
				}

				const float gh = CGround::GetHeightAboveWater(x * resolution, y * resolution);
				const float sh = smoothed[idx] / (xend - xstart + 1);

				smoothed[idx] = std::min(readMap->GetCurrMaxHeight(), std::max(gh, sh));
			} else {
				// non-border case
				avg += mesh[idx + smoothrad] - mesh[idx - smoothrad - 1];

				const float gh = CGround::GetHeightAboveWater(x * resolution, y * resolution);
				const float sh = recipn * avg;

				smoothed[idx] = std::min(readMap->GetCurrMaxHeight(), std::max(gh, sh));
			}

			assert(smoothed[idx] <= std::max(readMap->GetCurrMaxHeight(), 0.0f));
			assert(smoothed[idx] >=          readMap->GetCurrMinHeight()       );
		}
	});
}
Exemple #6
0
void CGrassDrawer::DrawFarBillboards(const std::vector<GrassStruct*>& inviewFarGrass)
{
	// update far grass blocks
	if (updateBillboards) {
		updateBillboards = false;

		for_mt(0, inviewFarGrass.size(), [&](const int i) {
			GrassStruct& g = *inviewFarGrass[i];

			if (g.lastFar == 0) {
				// TODO: VA's need to be uploaded each frame, switch to VBO's
				// force the patch-quads to be recreated
				g.lastFar = globalRendering->drawFrame;
				g.lastDist = -1.0f;
			}

			const float distSq = GetGrassBlockCamDist((g.posX + 0.5f) * grassBlockSize, (g.posZ + 0.5f) * grassBlockSize, true);

			if (distSq == g.lastDist)
				return;

			const bool inAlphaRange1 = (    distSq < Square(maxDetailedDist + 128.0f * 1.5f)) || (    distSq > Square(maxGrassDist - 128.0f));
			const bool inAlphaRange2 = (g.lastDist < Square(maxDetailedDist + 128.0f * 1.5f)) || (g.lastDist > Square(maxGrassDist - 128.0f));

			if (!inAlphaRange1 && (inAlphaRange1 == inAlphaRange2))
				return;

			g.lastDist = distSq;
			CVertexArray* va = &g.va;
			va->Initialize();

			// (4*4)*numTurfs quads
			for (int y2 = g.posZ * grassBlockSize; y2 < (g.posZ + 1) * grassBlockSize; ++y2) {
				for (int x2 = g.posX * grassBlockSize; x2 < (g.posX  + 1) * grassBlockSize; ++x2) {
					if (!grassMap[y2 * mapDims.mapx / grassSquareSize + x2])
						continue;

					const float dist = GetGrassBlockCamDist(x2, y2);
					auto* va_tn = va->GetTypedVertexArray<VA_TYPE_TN>(numTurfs * 4);
					DrawBillboard(x2, y2, dist, va_tn);
				}
			}
		});
	}

	// render far grass blocks
	for (GrassStruct* g: inviewFarGrass) {
		g->va.DrawArrayTN(GL_QUADS);
	}
}
void CGrassDrawer::DrawFarBillboards(const std::vector<GrassStruct*>& inviewFarGrass)
{
	// update far grass blocks
	if (updateBillboards) {
		updateBillboards = false;

		for_mt(0, inviewFarGrass.size(), [&](const int i){
			GrassStruct& g = *inviewFarGrass[i];
			if (!g.va) {
				//TODO vertex arrays need to be send each frame to the gpu, that's slow. switch to VBOs.
				CVertexArray* va = new CVertexArray;
				g.va = va;
				g.lastDist = -1; // force a recreate
			}

			const float distSq = GetCamDistOfGrassBlock((g.posX + 0.5f) * grassBlockSize, (g.posZ + 0.5f) * grassBlockSize, true);
			if (distSq == g.lastDist)
				return;

			bool inAlphaRange1 = (    distSq < Square(maxDetailedDist + 128.f * 1.5f)) || (    distSq > Square(maxGrassDist - 128.f));
			bool inAlphaRange2 = (g.lastDist < Square(maxDetailedDist + 128.f * 1.5f)) || (g.lastDist > Square(maxGrassDist - 128.f));
			if (!inAlphaRange1 && (inAlphaRange1 == inAlphaRange2)) {
				return;
			}

			g.lastDist = distSq;
			CVertexArray* va = g.va;
			va->Initialize();

			for (int y2 = g.posZ * grassBlockSize; y2 < (g.posZ + 1) * grassBlockSize; ++y2) {
				for (int x2 = g.posX * grassBlockSize; x2 < (g.posX  + 1) * grassBlockSize; ++x2) {
					if (!grassMap[y2 * mapDims.mapx / grassSquareSize + x2]) {
						continue;
					}

					const float dist = GetCamDistOfGrassBlock(x2, y2);
					auto* va_tn = va->GetTypedVertexArray<VA_TYPE_TN>(numTurfs * 4);
					DrawBillboard(x2, y2, dist, va_tn);
				}
			}
		});
	}

	// render far grass blocks
	for (const GrassStruct* g: inviewFarGrass) {
		g->va->DrawArrayTN(GL_QUADS);
	}
}
Exemple #8
0
// ---------------------------------------------------------------------
// Create an approximate mesh of the landscape.
//
bool CRoamMeshDrawer::Tessellate(const float3& campos, int viewradius)
{
	// Perform Tessellation
	// hint: threading just helps a little with huge cpu usage in retessellation, still better than nothing

	//  _____
	// |0|_|_|..
	// |_|_|_|..
	// |_|_|8|..
	//  .....
	// split the patches in 3x3 sized blocks. The tessellation itself can
	// extend into the neighbor patches (check Patch::Split). So we could
	// not multi-thread the whole loop w/o mutexes (in ::Split).
	// But instead we take a safety distance between the thread's working
	// area (which is 2 patches), so they don't conflict with each other.
	bool forceTess = false;

	for (int idx = 0; idx < 9; ++idx) {
		for_mt(0, roamPatches.size(), [&](const int i){
			Patch* it = &roamPatches[i];

			const int X = it->m_WorldX;
			const int Z = it->m_WorldY;
			const int subindex = (X % 3) + (Z % 3) * 3;

			if ((subindex == idx) && it->IsVisible()) {
				if (!it->Tessellate(campos, viewradius))
					forceTess = true;
			}
		});

		if (forceTess)
			return true;
	}

	return false;
}
/**
 * Get CRC of the data in the specified archive.
 * Returns 0 if file could not be opened.
 */
unsigned int CArchiveScanner::GetCRC(const std::string& arcName)
{
	CRC crc;
	std::list<std::string> files;

	// Try to open an archive
	boost::scoped_ptr<IArchive> ar(archiveLoader.OpenArchive(arcName));
	if (!ar) {
		return 0; // It wasn't an archive
	}

	// Load ignore list.
	boost::scoped_ptr<IFileFilter> ignore(CreateIgnoreFilter(ar.get()));

	// Insert all files to check in lowercase format
	for (unsigned fid = 0; fid != ar->NumFiles(); ++fid) {
		std::string name;
		int size;
		ar->FileInfo(fid, name, size);

		if (ignore->Match(name)) {
			continue;
		}

		StringToLowerInPlace(name); // case insensitive hash
		files.push_back(name);
	}

	// Sort by FileName
	files.sort();

	// Push the filenames into a std::vector, cause OMP can better iterate over those
	std::vector<CRCPair> crcs;
	crcs.reserve(files.size());
	CRCPair crcp;
	for (std::string& f: files) {
		crcp.filename = &f;
		crcs.push_back(crcp);
	}

	// Compute CRCs of the files
	// Hint: Multithreading only speedups `.sdd` loading. For those the CRC generation is extremely slow -
	//       it has to load the full file to calc it! For the other formats (sd7, sdz, sdp) the CRC is saved
	//       in the metainformation of the container and so the loading is much faster. Neither does any of our
	//       current (2011) packing libraries support multithreading :/
	for_mt(0, crcs.size(), [&](const int i) {
		CRCPair& crcp = crcs[i];
		const unsigned int nameCRC = CRC::GetCRC(crcp.filename->data(), crcp.filename->size());
		const unsigned fid = ar->FindFile(*crcp.filename);
		const unsigned int dataCRC = ar->GetCrc32(fid);
		crcp.nameCRC = nameCRC;
		crcp.dataCRC = dataCRC;
	#if !defined(DEDICATED) && !defined(UNITSYNC)
		Watchdog::ClearTimer(WDT_MAIN);
	#endif
	});

	// Add file CRCs to the main archive CRC
	for (CRCPair& crcp: crcs) {
		crc.Update(crcp.nameCRC);
		crc.Update(crcp.dataCRC);
	#if !defined(DEDICATED) && !defined(UNITSYNC)
		Watchdog::ClearTimer();
	#endif
	}

	// A value of 0 is used to indicate no crc.. so never return that
	// Shouldn't happen all that often
	unsigned int digest = crc.GetDigest();
	if (digest == 0) digest = 4711;
	return digest;
}
Exemple #10
0
/**
 * Get CRC of the data in the specified archive.
 * Returns 0 if file could not be opened.
 */
unsigned int CArchiveScanner::GetCRC(const std::string& arcName)
{
	CRC crc;

	struct CRCPair {
		std::string* filename;
		unsigned int nameCRC;
		unsigned int dataCRC;
	};

	// try to open an archive
	std::unique_ptr<IArchive> ar(archiveLoader.OpenArchive(arcName));

	if (ar == nullptr)
		return 0;

	// load ignore list, and insert all files to check in lowercase format
	std::unique_ptr<IFileFilter> ignore(CreateIgnoreFilter(ar.get()));
	std::vector<std::string> files;
	std::vector<CRCPair> crcs;

	files.reserve(ar->NumFiles());
	crcs.reserve(ar->NumFiles());

	for (unsigned fid = 0; fid != ar->NumFiles(); ++fid) {
		const std::pair<std::string, int>& info = ar->FileInfo(fid);

		if (ignore->Match(info.first))
			continue;

		// create case-insensitive hashes
		files.push_back(StringToLower(info.first));
	}

	// sort by filename
	std::stable_sort(files.begin(), files.end());

	for (std::string& f: files) {
		crcs.push_back(CRCPair{&f, 0, 0});
	}

	// compute CRCs of the files
	// Hint: Multithreading only speedups `.sdd` loading. For those the CRC generation is extremely slow -
	//       it has to load the full file to calc it! For the other formats (sd7, sdz, sdp) the CRC is saved
	//       in the metainformation of the container and so the loading is much faster. Neither does any of our
	//       current (2011) packing libraries support multithreading :/
	for_mt(0, crcs.size(), [&](const int i) {
		CRCPair& crcp = crcs[i];
		assert(crcp.filename == &files[i]);
		const unsigned int nameCRC = CRC::GetCRC(crcp.filename->data(), crcp.filename->size());
		const unsigned fid = ar->FindFile(*crcp.filename);
		const unsigned int dataCRC = ar->GetCrc32(fid);
		crcp.nameCRC = nameCRC;
		crcp.dataCRC = dataCRC;
	#if !defined(DEDICATED) && !defined(UNITSYNC)
		Watchdog::ClearTimer(WDT_MAIN);
	#endif
	});

	// Add file CRCs to the main archive CRC
	for (const CRCPair& crcp: crcs) {
		crc.Update(crcp.nameCRC);
		crc.Update(crcp.dataCRC);
	#if !defined(DEDICATED) && !defined(UNITSYNC)
		Watchdog::ClearTimer();
	#endif
	}

	// A value of 0 is used to indicate no crc.. so never return that
	// Shouldn't happen all that often
	const unsigned int digest = crc.GetDigest();
	return (digest == 0)? 4711: digest;
}
Exemple #11
0
/**
 * Retessellates the current terrain
 */
void CRoamMeshDrawer::Update()
{
	//FIXME this retessellates with the current camera frustum, shadow pass and others don't have to see the same patches!

	// CCamera* cam = (inShadowPass)? camera: cam2;
	CCamera* cam = cam2;

	// Update Patch visibility
	Patch::UpdateVisibility(cam, roamPatches, numPatchesX);

	// Check if a retessellation is needed
#define RETESSELLATE_MODE 1
	bool retessellate = false;

	{
		SCOPED_TIMER("ROAM::ComputeVariance");
		for (int i = 0; i < (numPatchesX * numPatchesY); ++i) { //FIXME multithread?
			Patch& p = roamPatches[i];
		#if (RETESSELLATE_MODE == 2)
			if (p.IsVisible()) {
				if (patchVisGrid[i] == 0) {
					patchVisGrid[i] = 1;
					retessellate = true;
				}
				if (p.IsDirty()) {
					//FIXME don't retessellate on small heightmap changes?
					p.ComputeVariance();
					retessellate = true;
				}
			} else {
				patchVisGrid[i] = 0;
			}
		#else
			if (char(p.IsVisible()) != patchVisGrid[i]) {
				patchVisGrid[i] = char(p.IsVisible());
				retessellate = true;
			}
			if (p.IsVisible() && p.IsDirty()) {
				//FIXME don't retessellate on small heightmap changes?
				p.ComputeVariance();
				retessellate = true;
			}
		#endif
		}
	}

	// Further conditions that can cause a retessellation
#if (RETESSELLATE_MODE == 2)
	static const float maxCamDeltaDistSq = 500.0f * 500.0f;
	retessellate |= ((cam->GetPos() - lastCamPos).SqLength() > maxCamDeltaDistSq);
#endif
	retessellate |= forceRetessellate;
	retessellate |= (lastGroundDetail != smfGroundDrawer->GetGroundDetail());

	bool retessellateAgain = false;

	// Retessellate
	if (retessellate) {
		{ SCOPED_TIMER("ROAM::Tessellate");
			//FIXME this tessellates with current camera + viewRadius
			//  so it doesn't retessellate patches that are e.g. only vis. in the shadow frustum
			Reset();
			retessellateAgain = Tessellate(cam->GetPos(), smfGroundDrawer->GetGroundDetail());
		}

		{ SCOPED_TIMER("ROAM::GenerateIndexArray");
			for_mt(0, roamPatches.size(), [&](const int i){
				Patch* it = &roamPatches[i];
				if (it->IsVisible()) {
					it->GenerateIndices();
				}
			});
		}

		{ SCOPED_TIMER("ROAM::Upload");
			for (std::vector<Patch>::iterator it = roamPatches.begin(); it != roamPatches.end(); ++it) {
				if (it->IsVisible()) {
					it->Upload();
				}
			}
		}

		/*{
			int tricount = 0;
			for (std::vector<Patch>::iterator it = roamPatches.begin(); it != roamPatches.end(); it++) {
				if (it->IsVisible()) {
					tricount += it->GetTriCount();
				}
			}

			LOG_L(L_DEBUG, "ROAM dbg: Framechange, fram=%i tris=%i, viewrad=%i, cd=%f, camera=(%5.0f, %5.0f, %5.0f) camera2=  (%5.0f, %5.0f, %5.0f)",
				globalRendering->drawFrame,
				tricount,
				smfGroundDrawer->viewRadius,
				(cam->pos - lastCamPos).SqLength();,
				camera->GetPos().x,
				camera->GetPos().y,
				camera->GetPos().z,
				cam2->pos.x,
				cam2->pos.y,
				cam2->pos.z
				);
		}*/

		lastGroundDetail = smfGroundDrawer->GetGroundDetail();
		lastCamPos = cam->GetPos();
		forceRetessellate = retessellateAgain;
	}
}