Exemplo n.º 1
0
//
// return memory required, in K, for a given grid size
//
int SMTerrain::MemoryRequired(int iDimension)
{
	int k = 0;

	int n = vt_log2(iDimension - 1);
	int iLevels = 2 * n + 2;

#if ASSUME_LOWEST_LEVEL
	int iUsedNodes = (1 << (iLevels-2));
#else
	int iUsedNodes = (1 << (iLevels-1));
#endif

	k += (iDimension * iDimension * sizeof(HeightType)) / 1024;	// heightfield
	k += (iUsedNodes * sizeof(VarianceType)) / 1024;			// variance
	k += (DEFAULT_POLYGON_TARGET * 3 * sizeof(BinTri)) / 1024;

	return k;
}
Exemplo n.º 2
0
void TileDlg::SetTilingOptions(TilingOptions &opt)
{
	m_strToFile = wxString(opt.fname, wxConvUTF8);
	m_iColumns = opt.cols;
	m_iRows = opt.rows;
	m_iLOD0Size = opt.lod0size;
	m_iNumLODs = opt.numlods;
	m_bOmitFlatTiles = opt.bOmitFlatTiles;
	m_bMaskUnknown = opt.bMaskUnknownAreas;
	m_bImageAlpha = opt.bImageAlpha;

	m_bCompressNone = !opt.bUseTextureCompression;
	if (opt.bUseTextureCompression)
	{
		m_bCompressOGL = (opt.eCompressionType == TC_OPENGL);
		m_bCompressSquishFast = (opt.eCompressionType == TC_SQUISH_FAST);
		m_bCompressSquishSlow = (opt.eCompressionType == TC_SQUISH_SLOW);
		m_bCompressJPEG = (opt.eCompressionType == TC_JPEG);
	}

	m_iLODChoice = vt_log2(m_iLOD0Size)-5;

	UpdateInfo();
}
Exemplo n.º 3
0
bool vtElevLayer::WriteElevationTileset(TilingOptions &opts, BuilderView *pView)
{
	// Avoid trouble with '.' and ',' in Europe
	ScopedLocale normal_numbers(LC_NUMERIC, "C");

	// Check that options are valid
	CheckCompressionMethod(opts);

	// grid size
	int base_tilesize = opts.lod0size;

	int gridcols, gridrows;
	m_pGrid->GetDimensions(gridcols, gridrows);

	DRECT area = m_pGrid->GetEarthExtents();
	DPoint2 tile_dim(area.Width()/opts.cols, area.Height()/opts.rows);
	DPoint2 cell_size = tile_dim / base_tilesize;

	const vtProjection &proj = m_pGrid->GetProjection();
	vtString units = GetLinearUnitName(proj.GetUnits());
	units.MakeLower();
	int zone = proj.GetUTMZone();
	vtString crs;
	if (proj.IsGeographic())
		crs = "LL";
	else if (zone != 0)
		crs = "UTM";
	else
		crs = "Other";

	// Try to create directory to hold the tiles
	vtString dirname = opts.fname;
	RemoveFileExtensions(dirname);
	if (!vtCreateDir(dirname))
		return false;

	// We won't know the exact height extents until the tiles have generated,
	//  so gather extents as we produce the tiles and write the INI later.
	float minheight = 1E9, maxheight = -1E9;

	ColorMap cmap;
	vtElevLayer::SetupDefaultColors(cmap);	// defaults
	vtString dirname_image = opts.fname_images;
	RemoveFileExtensions(dirname_image);
	if (opts.bCreateDerivedImages)
	{
		if (!vtCreateDir(dirname_image))
			return false;

		vtString cmap_fname = opts.draw.m_strColorMapFile;
		vtString cmap_path = FindFileOnPaths(vtGetDataPath(), "GeoTypical/" + cmap_fname);
		if (cmap_path == "")
			DisplayAndLog("Couldn't find color map.");
		else
		{
			if (!cmap.Load(cmap_path))
				DisplayAndLog("Couldn't load color map.");
		}
	}

	ImageGLCanvas *pCanvas = NULL;
#if USE_OPENGL
	wxFrame *frame = new wxFrame;
	if (opts.bCreateDerivedImages && opts.bUseTextureCompression && opts.eCompressionType == TC_OPENGL)
	{
		frame->Create(g_bld->m_pParentWindow, -1, _T("Texture Compression OpenGL Context"),
			wxPoint(100,400), wxSize(280, 300), wxCAPTION | wxCLIP_CHILDREN);
		pCanvas = new ImageGLCanvas(frame);
	}
#endif

	// make a note of which lods exist
	LODMap lod_existence_map(opts.cols, opts.rows);

	bool bFloat = m_pGrid->IsFloatMode();
	bool bJPEG = (opts.bUseTextureCompression && opts.eCompressionType == TC_JPEG);

	int i, j, lod;
	int total = opts.rows * opts.cols, done = 0;
	for (j = 0; j < opts.rows; j++)
	{
		for (i = 0; i < opts.cols; i++)
		{
			// We might want to skip certain tiles
			if (opts.iMinRow != -1 &&
				(i < opts.iMinCol || i > opts.iMaxCol ||
				 j < opts.iMinRow || j > opts.iMaxRow))
				continue;

			DRECT tile_area;
			tile_area.left = area.left + tile_dim.x * i;
			tile_area.right = area.left + tile_dim.x * (i+1);
			tile_area.bottom = area.bottom + tile_dim.y * j;
			tile_area.top = area.bottom + tile_dim.y * (j+1);

			int col = i;
			int row = opts.rows-1-j;

			// draw our progress in the main view
			if (pView)
				pView->ShowGridMarks(area, opts.cols, opts.rows, col, opts.rows-1-row);

			// Extract the highest LOD we need
			vtElevationGrid base_lod(tile_area, IPoint2(base_tilesize+1, base_tilesize+1),
				bFloat, proj);

			bool bAllInvalid = true;
			bool bAllZero = true;
			int iNumInvalid = 0;
			DPoint2 p;
			int x, y;
			for (y = base_tilesize; y >= 0; y--)
			{
				p.y = area.bottom + (j*tile_dim.y) + ((double)y / base_tilesize * tile_dim.y);
				for (x = 0; x <= base_tilesize; x++)
				{
					p.x = area.left + (i*tile_dim.x) + ((double)x / base_tilesize * tile_dim.x);

					float fvalue = m_pGrid->GetFilteredValue(p);
					base_lod.SetFValue(x, y, fvalue);

					if (fvalue == INVALID_ELEVATION)
						iNumInvalid++;
					else
					{
						bAllInvalid = false;

						// Gather height extents
						if (fvalue < minheight)
							minheight = fvalue;
						if (fvalue > maxheight)
							maxheight = fvalue;
					}
					if (fvalue != 0)
						bAllZero = false;
				}
			}
			// Increment whether we omit or not
			done++;

			// If there is no real data there, omit this tile
			if (bAllInvalid)
				continue;

			// Omit all-zero tiles (flat sea-level) if desired
			if (opts.bOmitFlatTiles && bAllZero)
				continue;

			// Now we know this tile will be included, so note the LODs present
			int base_tile_exponent = vt_log2(base_tilesize);
			lod_existence_map.set(i, j, base_tile_exponent, base_tile_exponent-(opts.numlods-1));

			if (iNumInvalid > 0)
			{
				UpdateProgressDialog2(done*99/total, 0, _("Filling gaps"));

				bool bGood;
				int method = g_Options.GetValueInt(TAG_GAP_FILL_METHOD);
				if (method == 1)
					bGood = base_lod.FillGaps(NULL, progress_callback_minor);
				else if (method == 2)
					bGood = base_lod.FillGapsSmooth(NULL, progress_callback_minor);
				else if (method == 3)
					bGood = (base_lod.FillGapsByRegionGrowing(2, 5, progress_callback_minor) != -1);
				if (!bGood)
					return false;

				opts.iNoDataFilled += iNumInvalid;
			}

			// Create a matching derived texture tileset
			if (opts.bCreateDerivedImages)
			{
				// Create a matching derived texture tileset
				vtDIB dib;
				base_lod.ComputeHeightExtents();

				if (opts.bImageAlpha)
				{
					dib.Create(IPoint2(base_tilesize, base_tilesize), 32);
					base_lod.ColorDibFromElevation(&dib, &cmap, 4000, RGBAi(0,0,0,0));
				}
				else
				{
					dib.Create(IPoint2(base_tilesize, base_tilesize), 24);
					base_lod.ColorDibFromElevation(&dib, &cmap, 4000, RGBi(255,0,0));
				}

				if (opts.draw.m_bShadingQuick)
					base_lod.ShadeQuick(&dib, SHADING_BIAS, true);
				else if (opts.draw.m_bShadingDot)
				{
					FPoint3 light_dir = LightDirection(opts.draw.m_iCastAngle,
						opts.draw.m_iCastDirection);

					// Don't cast shadows for tileset; they won't cast
					//  correctly from one tile to the next.
					base_lod.ShadeDibFromElevation(&dib, light_dir, 1.0f,
						opts.draw.m_fAmbient, opts.draw.m_fGamma, true);
				}

				for (int k = 0; k < opts.numlods; k++)
				{
					vtString fname = MakeFilenameDB(dirname_image, col, row, k);

					int tilesize = base_tilesize >> k;

					vtMiniDatabuf output_buf;
					output_buf.xsize = tilesize;
					output_buf.ysize = tilesize;
					output_buf.zsize = 1;
					output_buf.tsteps = 1;
					output_buf.SetBounds(proj, tile_area);

					int depth = dib.GetDepth() / 8;
					int iUncompressedSize = tilesize * tilesize * depth;
					uchar *rgb_bytes = (uchar *) malloc(iUncompressedSize);

					uchar *dst = rgb_bytes;
					if (opts.bImageAlpha)
					{
						RGBAi rgba;
						for (int ro = 0; ro < base_tilesize; ro += (1<<k))
							for (int co = 0; co < base_tilesize; co += (1<<k))
							{
								dib.GetPixel32(co, ro, rgba);
								*dst++ = rgba.r;
								*dst++ = rgba.g;
								*dst++ = rgba.b;
								*dst++ = rgba.a;
							}
					}
					else
					{
						RGBi rgb;
						for (int ro = 0; ro < base_tilesize; ro += (1<<k))
							for (int co = 0; co < base_tilesize; co += (1<<k))
							{
								dib.GetPixel24(co, ro, rgb);
								*dst++ = rgb.r;
								*dst++ = rgb.g;
								*dst++ = rgb.b;
							}
					}

					// Write and optionally compress the image
					WriteMiniImage(fname, opts, rgb_bytes, output_buf,
						iUncompressedSize, pCanvas);

					// Free the uncompressed image
					free(rgb_bytes);
				}
			}

			for (lod = 0; lod < opts.numlods; lod++)
			{
				int tilesize = base_tilesize >> lod;

				vtString fname = MakeFilenameDB(dirname, col, row, lod);

				// make a message for the progress dialog
				wxString msg;
				msg.Printf(_("Writing tile '%hs', size %dx%d"),
					(const char *)fname, tilesize, tilesize);
				UpdateProgressDialog2(done*99/total, 0, msg);

				vtMiniDatabuf buf;
				buf.SetBounds(proj, tile_area);
				buf.alloc(tilesize+1, tilesize+1, 1, 1, bFloat ? 2 : 1);
				float *fdata = (float *) buf.data;
				short *sdata = (short *) buf.data;

				DPoint2 p;
				for (int y = base_tilesize; y >= 0; y -= (1<<lod))
				{
					p.y = area.bottom + (j*tile_dim.y) + ((double)y / base_tilesize * tile_dim.y);
					for (int x = 0; x <= base_tilesize; x += (1<<lod))
					{
						p.x = area.left + (i*tile_dim.x) + ((double)x / base_tilesize * tile_dim.x);

						if (bFloat)
						{
							*fdata = base_lod.GetFilteredValue(p);
							fdata++;
						}
						else
						{
							*sdata = (short) base_lod.GetFilteredValue(p);
							sdata++;
						}
					}
				}
				if (buf.savedata(fname) == 0)
				{
					// what should we do if writing a tile fails?
				}
			}
		}
	}
Exemplo n.º 4
0
//
// Initialize the terrain LOD structures
//
// Allocates the height/variance arrays
// Fills in the arrays with initial values
//
// fZScale converts from height values (meters) to world coordinates
//
DTErr SMTerrain::Init(const vtElevationGrid *pGrid, float fZScale)
{
	DTErr err = BasicInit(pGrid);
	if (err != DTErr_OK)
		return err;

	if (m_iColumns != m_iRows)
		return DTErr_NOTSQUARE;

	// get size of array
	m_iDim = m_iColumns;

	// compute n (log2 of grid size)
	m_n = vt_log2(m_iDim - 1);

	// ensure that the grid is size (1 << n) + 1
	int required_size = (1<<m_n) + 1;
	if (m_iColumns != required_size || m_iRows != required_size)
		return DTErr_NOTPOWER2;

	// the triangle bintree will have (2n + 2) levels
	// these levels are numbered with 1-based numbering, (1 2 3...)
	m_iLevels = 2 * m_n + 2;

	// Default: create 8x8 blocks (eg. 1024 -> 128*128 (actually, 129))
	m_iBlockN = m_n - 3;	// 8x8 blocks
	// safety check
	if (m_iBlockN < 0) m_iBlockN = 0;

	m_iBlockLevel = 2 * (m_n - m_iBlockN) + 1;
	m_iBlockCutoff = 1 << (2 * (m_n - m_iBlockN));
	m_iBlockArrayDim = 1 << (m_n - m_iBlockN);

	// Allocate a 2D array of blocks
	int i, j;
	m_pBlockArray = new BlockPtr[m_iBlockArrayDim];
	for (i = 0; i < m_iBlockArrayDim; i++)
		m_pBlockArray[i] = new Block[m_iBlockArrayDim];

	// the triangle bintree will have ((1 << levels) - 1) nodes
	m_iNodes = (1 << m_iLevels) - 1;

	// the bottom level of the bintree cannot be split
	m_iSplitCutoff = (1 << (m_iLevels-2));

#if !ASSUME_LOWEST_LEVEL
	// however, we don't need to store variance for the bottom-most nodes
	// of the tree, so use one less level, and add 1 for 1-based numbering
	m_iUsedNodes = (1 << (m_iLevels-1));

#else
// APPROXIMATION
	// Seumas says he gets away with levels-4 !! Let's try a less
	// radical approximation: levels-2
	m_iUsedNodes = (1 << (m_iLevels-2));
#endif

	// allocate arrays
	m_pData = new HeightType[m_iColumns * m_iRows];

	// this is potentially a big chunk of memory, so it may fail
	if (!m_pData)
		return DTErr_NOMEM;

	// copy data from supplied elevation grid
	float elev;
	for (i = 0; i < m_iColumns; i++)
	{
		for (j = 0; j < m_iRows; j++)
		{
			elev = pGrid->GetFValue(i, j);
			m_pData[offset(i,j)] = (HeightType)(PACK_SCALE * elev);
		}
	}
	m_fZScale = fZScale / PACK_SCALE;

	// find indices of corner vertices
	m_sw = offset(0, 0);
	m_nw = offset(0, m_iRows-1);
	m_ne = offset(m_iColumns-1, m_iRows-1);
	m_se = offset(m_iColumns-1, 0);

	m_iPolygonTarget = DEFAULT_POLYGON_TARGET;
	m_fQualityConstant= 0.1f;		// safe initial value
	m_iDrawnTriangles = -1;
	hack_detail_pass = false;

	return DTErr_OK;
}