Example #1
0
void SpriteSheet::ExtractSpriteFrom( char* Grid, int GridW, int GridH, int StartX, int StartY )
{
  // Know where we start
	gridalloc_minx = StartX;
	gridalloc_miny = StartY;
	gridalloc_maxx = StartX;
  gridalloc_maxy = StartY;

  // Follow the grid around for adjactent [1] cells
  AllocateGrid( Grid, GridW, GridH, StartX, StartY );

  // Add sprite to sheet
  AddSprite( gridalloc_minx * gridalloc_size, gridalloc_miny * gridalloc_size, ((gridalloc_maxx - gridalloc_minx) + 1) * gridalloc_size, ((gridalloc_maxy - gridalloc_miny) + 1) * gridalloc_size );
}
Example #2
0
GridMemStruct* GridMemList_AddGridDesc(GridDesc* pgrid)
{
	GridMemStruct* pnewGridMemStruct;

//printf("IN: GridMemList_AddGridDesc\n");
	pnewGridMemStruct = (GridMemStruct*) malloc(sizeof(GridMemStruct));
	pnewGridMemStruct->pgrid = (GridDesc*) malloc(sizeof(GridDesc));
	*(pnewGridMemStruct->pgrid) = *pgrid;
	strcpy(pnewGridMemStruct->pgrid->chr_type, pgrid->chr_type);
	strcpy(pnewGridMemStruct->pgrid->title, pgrid->title);
	pnewGridMemStruct->buffer = AllocateGrid(pnewGridMemStruct->pgrid);
	pnewGridMemStruct->array = CreateGridArray(pnewGridMemStruct->pgrid);
	pnewGridMemStruct->active = 1;
	pnewGridMemStruct->grid_read = 0;

	GridMemList_AddElement(pnewGridMemStruct);

	return(pnewGridMemStruct);

}
Example #3
0
void SpriteSheet::AllocateGrid( char* Grid, int GridW, int GridH, int StartX, int StartY )
{
  // Allocate tile
  Grid[ (StartY * GridW) + StartX ] = 2;
  if( StartX < gridalloc_minx )
  {
    gridalloc_minx = StartX;
  }
  if( StartY < gridalloc_miny )
  {
    gridalloc_miny = StartY;
  }
  if( StartX > gridalloc_maxx )
  {
    gridalloc_maxx = StartX;
  }
  if( StartY > gridalloc_maxy )
  {
    gridalloc_maxy = StartY;
  }

  for( int y = -1; y < 2; y++ )
  {
    for( int x = -1; x < 2; x++ )
    {
      if( y != 0 || x != 0 )
      {

        if( StartX + x >= 0 && StartX + x < GridW && StartY + y >= 0 && StartY + y < GridH )
        {
          // Adjacent tile exists, is it for allocating?
          if( Grid[ ((StartY + y) * GridW) + (StartX + x) ] == 1 )
          {
            AllocateGrid( Grid, GridW, GridH, StartX + x, StartY + y );
          }
        }
      }
    }
  }
}
Example #4
0
void* NLL_AllocateGrid(GridDesc* pgrid)
{
	int index, nactive, ngrid_read, n;
	void* fptr = NULL;
	GridMemStruct* pGridMemStruct = NULL;

//printf("IN: NLL_AllocateGrid\n");

	if (USE_GRID_LIST) {

		if ((index = GridMemList_IndexOfGridDesc(0, pgrid)) >= 0){
			// already in list
			pGridMemStruct = GridMemList_ElementAt(index);
			pGridMemStruct->active = 1;
			fptr = pGridMemStruct->buffer;
if (message_flag >= GRIDMEM_MESSAGE)
printf("GridMemManager: Grid exists in mem (%d/%d): %s\n", index, GridMemListNumElements, pGridMemStruct->pgrid->title);
			return(fptr);
		} else {
			// check number of active grids in list
			nactive = 0;
			ngrid_read = 0;
			for (n = 0; n < GridMemList_NumElements(); n++) {
				pGridMemStruct = GridMemList_ElementAt(n);
				nactive += pGridMemStruct->active;
				ngrid_read += pGridMemStruct->grid_read;
			}
			// list already full of active grids, do normal allocation
			if (MaxNum3DGridMemory > 0 && nactive >= MaxNum3DGridMemory) {
				fptr = AllocateGrid(pgrid);
if (message_flag >= GRIDMEM_MESSAGE)
printf("GridMemManager: Memory full (%d/%d): %s\n", index, GridMemListNumElements, pGridMemStruct->pgrid->title);
				return(fptr);
			}
			// ok
			// remove an inactive grid if necessary
			if (MaxNum3DGridMemory > 0 && ngrid_read >= MaxNum3DGridMemory) {
				for (n = GridMemList_NumElements() - 1; n >= 0; n--) {
					pGridMemStruct = GridMemList_ElementAt(n);
					if (!pGridMemStruct->active && pGridMemStruct->grid_read) {
						GridMemList_RemoveElementAt(n);
						break;
					}
				}
			}
			// create new list element
			pGridMemStruct = GridMemList_AddGridDesc(pgrid);
			fptr = pGridMemStruct->buffer;
			if (fptr == NULL) {
				// error allocating grid memory or out of memory
				GridMemList_RemoveElementAt(GridMemList_NumElements() -1);
			}
			return(fptr);
		}

	} else {
		fptr = AllocateGrid(pgrid);
		return(fptr);
	}

}
Example #5
0
int Rotate90CW(int argc, char *argv[])
{
	int istat, narg;

	char fn_grid_in[FILENAME_MAX];
	char fn_grid_out[FILENAME_MAX];
	FILE *fp_grid_in;
	FILE *fp_grid_in_hdr;

	GridDesc grid_in, grid_out;
	
	int ix, iy, iz;
	float val;

	

	// open input grid file

	strcpy(fn_grid_in, argv[2]);
	if ((istat = OpenGrid3dFile(fn_grid_in, &fp_grid_in, &fp_grid_in_hdr,
			&grid_in, "", NULL)) < 0)
	{
		puterr("ERROR opening input grid file.");
		return(-1);
	}

	// cread and initialize output grid

	// output file name
	strcpy(fn_grid_out, argv[3]);

	// create output grid description
	grid_out = grid_in;
	grid_out.numx = grid_in.numy;
	grid_out.numy = grid_in.numx;

	// allocate grid
	grid_out.buffer = AllocateGrid(&grid_out);
	if (grid_out.buffer == NULL) {
		puterr("ERROR: allocating memory for output grid buffer.\n");
		return(-1);
	}

	// create grid array access pointers
	grid_out.array = CreateGridArray(&grid_out);
	if (grid_out.array == NULL) {
		puterr("ERROR: creating array for accessing output grid buffer.\n");
		return(-1);
	}

	// rotate input grid file into output grid

	for (ix = 0; ix < grid_in.numx; ix++) {
		printf("ix = %d/%d\r", ix, grid_in.numx);
		for (iy = 0; iy < grid_in.numy; iy++) {
			for (iz = 0; iz < grid_in.numz; iz++) {
				val = ReadGrid3dValue(fp_grid_in, ix, iy, iz, &grid_in);
				grid_out.array[iy][grid_out.numy - ix - 1][iz] = val;
			}
		}
	}
	printf("\n");


	// save sum grid to disk

	if ((istat = WriteGrid3dBuf(&grid_out, NULL, fn_grid_out, "rot90CW")) < 0) {
		puterr("ERROR: writing rotated grid to disk.\n");
		return(-1);
	}


	close(fp_grid_in);
	close(fp_grid_in_hdr);

	return(0);

}
Example #6
0
/**
 * Loads elevation from a USGS DEM file.
 *
 * Some non-standard variations of the DEM format are supported.
 *
 * You should call SetupLocalCS() after loading if you will be doing
 * heightfield operations on this grid.
 *
 * \returns \c true if the file was successfully opened and read.
 */
bool vtElevationGrid::LoadFromDEM(const char *szFileName,
								  bool progress_callback(int), vtElevError *err)
{
	// Free buffers to prepare to receive new data
	FreeData();

	if (progress_callback != NULL) progress_callback(0);

	FILE *fp = vtFileOpen(szFileName,"rb");
	if (!fp)		// Cannot Open File
	{
		SetError(err, vtElevError::FILE_OPEN, "Couldn't open file '%s'", szFileName);
		return false;
	}

	// check for version of DEM format
	int		iRow, iColumn;
	char buffer[158];

	fseek(fp, 864, 0);
	if (fread(buffer, 144, 1, fp) != 1)
	{
		SetError(err, vtElevError::READ_DATA, "Couldn't read DEM data from '%s'", szFileName);
		return false;
	}
	bool bOldFormat = (strncmp(buffer, "     1     1", 12) == 0);
	bool bNewFormat = false;
	bool bFixedLength = true;
	int  iDataStartOffset = 1024;	// set here to avoid compiler warning
	int  i, j;

	if (bOldFormat)
		iDataStartOffset = 1024;	// 1024 is record length
	else
	{
		fseek(fp, 1024, 0);		// Check for New Format
		IConvert(fp, 6, iRow);
		IConvert(fp, 6, iColumn);
		if (iRow==1 && iColumn==1)	// File OK?
		{
			bNewFormat = true;
			iDataStartOffset = 1024;
		}
		else
		{
			// might be the Non-fixed-length record format
			// Record B can start anywhere from 865 to 1023
			// Record B is identified by starting with the row/column
			//  of its first profile, "     1     1"
			fseek(fp, 865, 0);
			if (fread(buffer, 158, 1, fp) != 1)
			{
				SetError(err, vtElevError::READ_DATA, "Couldn't read DEM data from '%s'", szFileName);
				fclose(fp);
				return false;
			}
			for (i = 0; i < 158-12; i++)
			{
				if (!strncmp(buffer+i, "     1     1", 12))
				{
					// Found it
					bFixedLength = false;
					iDataStartOffset = 865+i;
					break;
				}
			}
			if (i == 158-12)
			{
				// Not a DEM file
				SetError(err, vtElevError::READ_DATA, "Couldn't read DEM data from '%s'", szFileName);
				fclose(fp);
				return false;
			}
		}
	}

	// Read the embedded DEM name
	char szName[41];
	fseek(fp, 0, 0);
	if (fgets(szName, 41, fp) == NULL)
		return false;
	int len = strlen(szName);	// trim trailing whitespace
	while (len > 0 && szName[len-1] == ' ')
	{
		szName[len-1] = 0;
		len--;
	}
	m_strOriginalDEMName = szName;

	fseek(fp, 156, 0);
	int iCoordSystem, iUTMZone;
	IConvert(fp, 6, iCoordSystem);
	IConvert(fp, 6, iUTMZone);

	fseek(fp, 168, 0);
	double dProjParams[15];
	for (i = 0; i < 15; i++)
	{
		if (!DConvert(fp, 24, dProjParams[i], DEBUG_DEM))
			return false;
	}

	int iDatum = EPSG_DATUM_NAD27;	// default

	// OLD format header ends at byte 864 (0x360); new format has Datum
	if (bNewFormat)
	{
		// year of data compilation
		char szDateBuffer[5];
		fseek(fp, 876, 0);		// 0x36C
		if (fread(szDateBuffer, 4, 1, fp) != 1)
			return false;
		szDateBuffer[4] = 0;

		// Horizontal datum
		// 1=North American Datum 1927 (NAD 27)
		// 2=World Geodetic System 1972 (WGS 72)
		// 3=WGS 84
		// 4=NAD 83
		// 5=Old Hawaii Datum
		// 6=Puerto Rico Datum
		fseek(fp, 890, 0);	// 0x37A
		int datum;
		IConvert(fp, 2, datum);
		VTLOG("DEM Reader: Read Datum Value %d\n", datum);
		switch (datum)
		{
			case 1: iDatum = EPSG_DATUM_NAD27; break;
			case 2: iDatum = EPSG_DATUM_WGS72; break;
			case 3: iDatum = EPSG_DATUM_WGS84; break;
			case 4:	iDatum = EPSG_DATUM_NAD83; break;
			case 5: iDatum = EPSG_DATUM_OLD_HAWAIIAN; break;
			case 6: iDatum = EPSG_DATUM_PUERTO_RICO; break;
		}
	}

	fseek(fp, 528, 0);
	int iGUnit, iVUnit;
	IConvert(fp, 6, iGUnit);
	IConvert(fp, 6, iVUnit);

	// Ground (Horizontal) Units in meters
	double	fGMeters;
	switch (iGUnit)
	{
	case 0: fGMeters = 1.0;		break;	// 0 = radians (never encountered)
	case 1: fGMeters = 0.3048;	break;	// 1 = feet
	case 2: fGMeters = 1.0;		break;	// 2 = meters
	case 3: fGMeters = 30.922;	break;	// 3 = arc-seconds
	}

	// Vertical Units in meters
	double	fVertUnits;
	switch (iVUnit)
	{
	case 1:  fVertUnits = 0.3048;  break;	// feet to meter conversion
	case 2:  fVertUnits = 1.0;	   break;	// meters == meters
	default: fVertUnits = 1.0;	   break;	// anything else, assume meters
	}

	fseek(fp, 816, 0);
	double dxdelta, dydelta, dzdelta;
	DConvert(fp, 12, dxdelta, DEBUG_DEM);	// dxdelta (unused)
	DConvert(fp, 12, dydelta, DEBUG_DEM);
	DConvert(fp, 12, dzdelta, DEBUG_DEM);

	m_bFloatMode = false;

	// Read the coordinates of the 4 corners
	VTLOG("DEM corners:\n");
	DPoint2	corners[4];			// SW, NW, NE, SE
	fseek(fp, 546, 0);
	for (i = 0; i < 4; i++)
	{
		DConvert(fp, 24, corners[i].x, DEBUG_DEM);
		DConvert(fp, 24, corners[i].y, DEBUG_DEM);
	}
	for (i = 0; i < 4; i++)
		VTLOG(" (%lf, %lf)", corners[i].x, corners[i].y);
	VTLOG("\n");

	// Set up the projection and corners
	bool bGeographic = (iCoordSystem == 0);
	if (bGeographic)
	{
		for (i = 0; i < 4; i++)
		{
			// convert arcseconds to degrees
			m_Corners[i].x = corners[i].x / 3600.0;
			m_Corners[i].y = corners[i].y / 3600.0;
		}
	}
	else
	{
		// some linear coordinate system
		for (i = 0; i < 4; i++)
			m_Corners[i] = corners[i];
	}

	// Special case.  Some old DEMs claim to be NAD27, but they are of Hawai'i,
	//  and Hawai'i has no NAD27, it is actually OHD.
	if (iDatum == EPSG_DATUM_NAD27)
	{
		DRECT Hawaii(0,0,0,0);
		if (bGeographic)
			Hawaii.SetRect(-164, 24, -152, 17);
		else if (iCoordSystem == 1)	// UTM
		{
			if (iUTMZone == 4)
				Hawaii.SetRect(240000, 2600000, 1000000, 2000000);
			else if (iUTMZone == 5)
				Hawaii.SetRect(-400000, 2600000, 400000, 2000000);
		}
		for (i = 0; i < 4; i++)
		{
			if (Hawaii.ContainsPoint(m_Corners[i]))
				iDatum = EPSG_DATUM_OLD_HAWAIIAN;
		}
	}

	bool bSuccessfulCRS = true;
	switch (iCoordSystem)
	{
	case 0:		// geographic (lat-lon)
		iUTMZone = -1;
		bSuccessfulCRS = m_proj.SetProjectionSimple(false, iUTMZone, iDatum);
		break;
	case 1:		// utm
		m_proj.SetProjectionSimple(true, iUTMZone, iDatum);
		break;
	case 3:		// Albers Conical Equal Area
		{
			// The Official DEM documentation says:
			// "Note: All angles (latitudes, longitudes, or azimuth) are
			// required in degrees, minutes, and arc seconds in the packed
			// real number format +DDDOMMOSS.SSSSS."
			// However, what i've actually seen is values like:
			//  0.420000000000000D+06' -> 420000
			// for 42 degrees, which is off by a decimal point from the DEM docs.
			// So, intepret the values with factor of 10000 to convert to degrees:

			// double semi_major = dProjParams[0];		// unused
			// double eccentricity = dProjParams[1];	// unused
			double lat_1st_std_parallel = dProjParams[2] / 10000;
			double lat_2nd_std_parallel = dProjParams[3] / 10000;
			double lon_central_meridian = dProjParams[4] / 10000;
			double lat_origin = dProjParams[5] / 10000;
			double false_easting = dProjParams[6];
			double false_northing = dProjParams[7];

			m_proj.SetGeogCSFromDatum(iDatum);
			m_proj.SetACEA(lat_1st_std_parallel, lat_2nd_std_parallel, lat_origin,
				lon_central_meridian, false_easting, false_northing);
		}
		break;
	case 2:		// State Plane (!)
	case 4:		// Lambert Conformal
	case 5:		// Mercator
	case 6:		// Polar Stereographic
	case 7:		// Polyconic
	case 8:		// Equidistant Conic Type A / B
	case 9:		// Transverse Mercator
	case 10:	// Stereographic
	case 11:	// Lambert Azimuthal Equal-Area
	case 12:	// Azimuthal Equidistant
	case 13:	// Gnomonic
	case 14:	// Orthographic
	case 15:	// General Vertical Near-Side Perspective
	case 16:	// Sinusoidal (Plate Caree)
	case 17:	// Equirectangular
	case 18:	// Miller Cylindrical
	case 19:	// Van Der Grinten I
	case 20:	// Oblique Mercator
		VTLOG("Warning!  We don't yet support DEM coordinate system %d.\n", iCoordSystem);
		break;
	}

	// We must have a functional CRS, or it will sebsequently fail
	if (!bSuccessfulCRS)
	{
		SetError(err, vtElevError::READ_CRS, "Couldn't determine CRS of DEM file");
		return false;
	}

	double dElevMin, dElevMax;
	DConvert(fp, 24, dElevMin, DEBUG_DEM);
	DConvert(fp, 24, dElevMax, DEBUG_DEM);

	fseek(fp, 852, 0);
	int iRows, iProfiles;
	IConvert(fp, 6, iRows);	// This "Rows" value will always be 1
	IConvert(fp, 6, iProfiles);
	VTLOG("DEM profiles: %d\n", iProfiles);

	m_iSize.x = iProfiles;

	// values we'll need while scanning the elevation profiles
	int		iProfileRows, iProfileCols;
	int		iElev;
	double	dLocalDatumElev, dProfileMin, dProfileMax;
	int		ygap;
	double	dMinY;
	DPoint2 start;

	if (bGeographic)
	{
		// If it's in degrees, it's flush square, so we can simply
		// derive the extents (m_EarthExtents) from the quad corners (m_Corners)
		ComputeExtentsFromCorners();
		dMinY = std::min(corners[0].y, corners[3].y);
	}
	else
	{
		VTLOG("DEM scanning to compute extents\n");
		m_EarthExtents.SetInsideOut();

		if (!bFixedLength)
			fseek(fp, iDataStartOffset, 0);
		// Need to scan over all the profiles, accumulating the TRUE
		// extents of the actual data points.
		int record = 0;
		int data_len;
		for (i = 0; i < iProfiles; i++)
		{
			if (progress_callback != NULL)
				progress_callback(i*49/iProfiles);

			if (bFixedLength)
				fseek(fp, iDataStartOffset + (record * 1024), 0);

			// We cannot use IConvert here, because there *might* be a spurious LF
			// after the number - seen in some rare files.
			if (fscanf(fp, "%d", &iRow) != 1)
			{
				SetError(err, vtElevError::READ_DATA, "Error reading DEM at profile %d of %d",
					i, iProfiles);
				return false;
			}
			IConvert(fp, 6, iColumn);
			// assert(iColumn == i+1);
			IConvert(fp, 6, iProfileRows);
			IConvert(fp, 6, iProfileCols);

			DConvert(fp, 24, start.x);
			DConvert(fp, 24, start.y);
			m_EarthExtents.GrowToContainPoint(start);
			start.y += ((iProfileRows-1) * dydelta);
			m_EarthExtents.GrowToContainPoint(start);

			if (bFixedLength)
			{
				record++;
				data_len = 144 + (iProfileRows * 6);
				while (data_len > 1020)	// max bytes in a record
				{
					data_len -= 1020;
					record++;
				}
			}
			else
			{
				DConvert(fp, 24, dLocalDatumElev);
				DConvert(fp, 24, dProfileMin);
				DConvert(fp, 24, dProfileMax);
				for (j = 0; j < iProfileRows; j++)
				{
					// We cannot use IConvert here, because there *might* be a spurious LF
					// after the number - seen in some rare files.
					if (fscanf(fp, "%d", &iElev) != 1)
						return false;
				}
			}
		}
		dMinY = m_EarthExtents.bottom;
	}
	VTLOG("DEM extents LRTB: %lf, %lf, %lf, %lf\n", m_EarthExtents.left,
		m_EarthExtents.right, m_EarthExtents.top, m_EarthExtents.bottom);

	// Compute number of rows
	double	fRows;
	if (bGeographic)
	{
		// degrees
		fRows = m_EarthExtents.Height() / dydelta * 3600.0f;
		m_iSize.y = (int)fRows + 1;	// 1 more than quad spacing
	}
	else
	{
		// some linear coordinate system
		fRows = m_EarthExtents.Height() / dydelta;
		m_iSize.y = (int)(fRows + 0.5) + 1;	// round to the nearest integer
	}

	// safety check
	if (m_iSize.y > 20000)
		return false;

	if (!AllocateGrid(err))
		return false;

	// jump to start of actual data
	fseek(fp, iDataStartOffset, 0);

	for (i = 0; i < iProfiles; i++)
	{
		if (progress_callback != NULL)
			progress_callback(50+i*49/iProfiles);

		// We cannot use IConvert here, because there *might* be a spurious LF
		// after the number - seen in some rare files.
		if (fscanf(fp, "%d", &iRow) != 1)
			return false;
		IConvert(fp, 6, iColumn);
		//assert(iColumn == i+1);

		IConvert(fp, 6, iProfileRows);
		IConvert(fp, 6, iProfileCols);

		DConvert(fp, 24, start.x);
		DConvert(fp, 24, start.y);
		DConvert(fp, 24, dLocalDatumElev);
		DConvert(fp, 24, dProfileMin);
		DConvert(fp, 24, dProfileMax);

		ygap = (int)((start.y - dMinY)/dydelta);

		for (j = ygap; j < (ygap + iProfileRows); j++)
		{
			//assert(j >=0 && j < m_iSize.y);	// useful safety check

			// We cannot use IConvert here, because there *might* be a spurious LF
			// after the number - seen in some rare files.
			if (fscanf(fp, "%d", &iElev) != 1)
				return false;
			if (iElev == -32767 || iElev == -32768)
				SetValue(i, j, INVALID_ELEVATION);
			else
			{
				// The DEM spec says:
				// "A value in this array would be multiplied by the "z" spatial
				// resolution (data element 15, record type A) and added to the
				// "Elevation of local datum for the profile" (data element 4, record
				// type B) to obtain the elevation for the point."
				SetValue(i, j, (short) iElev + (short) dLocalDatumElev);
			}
		}
	}
	fclose(fp);

	m_fVMeters = (float) (fVertUnits * dzdelta);
	ComputeHeightExtents();
	if (m_fMinHeight != dElevMin || m_fMaxHeight != dElevMax)
		VTLOG("DEM Reader: elevation extents in .dem (%.1f, %.1f) don't match data (%.1f, %.1f).\n",
		dElevMin, dElevMax, m_fMinHeight, m_fMaxHeight);

	return true;
}
Example #7
0
int main(int argc, char *argv[])
{
    int errs = 0;
    int wrank, wsize;
    int gsizes[3], distribs[3], dargs[3], psizes[3];
    int px, py, nx, ny, rx, ry, bx, by;
    int *srcArray, *destArray;
    int i, j, ii, jj, loc;
    MPI_Datatype darraytype;

    MTest_Init(0, 0);
    MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
    MPI_Comm_size(MPI_COMM_WORLD, &wsize);

    /* Test 1: Simple, 1-D cyclic decomposition */
    if (AllocateGrid(1, 3 * wsize, &srcArray, &destArray)) {
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    /* Simple cyclic with 1-dim global array */
    gsizes[0] = 3 * wsize;
    distribs[0] = MPI_DISTRIBUTE_CYCLIC;
    dargs[0] = 1;
    psizes[0] = wsize;
    MPI_Type_create_darray(wsize, wrank, 1,
                           gsizes, distribs, dargs, psizes, MPI_ORDER_C, MPI_INT, &darraytype);

    /* Check the created datatype.  Because cyclic, should represent
     * a strided type */
    if (PackUnpack(darraytype, srcArray, destArray, 3)) {
        fprintf(stderr, "Error in pack/unpack check\n");
        MPI_Abort(MPI_COMM_WORLD, 1);
    }
    /* Now, check for correct data */
    for (i = 0; i < 3; i++) {
        if (destArray[i] != wrank + i * wsize) {
            fprintf(stderr, "1D: %d: Expected %d but saw %d\n", i, wrank + i * wsize, destArray[i]);
            errs++;
        }
    }

    free(destArray);
    free(srcArray);
    MPI_Type_free(&darraytype);

    /* Test 2: Simple, 1-D cyclic decomposition, with block size=2 */
    if (AllocateGrid(1, 4 * wsize, &srcArray, &destArray)) {
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    /* Simple cyclic with 1-dim global array */
    gsizes[0] = 4 * wsize;
    distribs[0] = MPI_DISTRIBUTE_CYCLIC;
    dargs[0] = 2;
    psizes[0] = wsize;
    MPI_Type_create_darray(wsize, wrank, 1,
                           gsizes, distribs, dargs, psizes, MPI_ORDER_C, MPI_INT, &darraytype);

    /* Check the created datatype.  Because cyclic, should represent
     * a strided type */
    if (PackUnpack(darraytype, srcArray, destArray, 4)) {
        fprintf(stderr, "Error in pack/unpack check\n");
        MPI_Abort(MPI_COMM_WORLD, 1);
    }
    loc = 0;
    /* for each cyclic element */
    for (i = 0; i < 2; i++) {
        /* For each element in block */
        for (j = 0; j < 2; j++) {
            if (destArray[loc] != 2 * wrank + i * 2 * wsize + j) {
                fprintf(stderr, "1D(2): %d: Expected %d but saw %d\n",
                        i, 2 * wrank + i * 2 * wsize + j, destArray[loc]);
                errs++;
            }
            loc++;
        }
    }

    free(destArray);
    free(srcArray);
    MPI_Type_free(&darraytype);

    /* 2D: Create some 2-D decompositions */
    px = wsize / 2;
    py = 2;
    rx = wrank % px;
    ry = wrank / px;

    if (px * py != wsize) {
        fprintf(stderr, "An even number of processes is required\n");
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    /* Cyclic/Cyclic */
    if (AllocateGrid(5 * px, 7 * py, &srcArray, &destArray)) {
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    /* Simple cyclic/cyclic. Note in C order, the [1] index varies most
     * rapidly */
    gsizes[0] = ny = 7 * py;
    gsizes[1] = nx = 5 * px;
    distribs[0] = MPI_DISTRIBUTE_CYCLIC;
    distribs[1] = MPI_DISTRIBUTE_CYCLIC;
    dargs[0] = 1;
    dargs[1] = 1;
    psizes[0] = py;
    psizes[1] = px;
    MPI_Type_create_darray(wsize, wrank, 2,
                           gsizes, distribs, dargs, psizes, MPI_ORDER_C, MPI_INT, &darraytype);

    /* Check the created datatype.  Because cyclic, should represent
     * a strided type */
    if (PackUnpack(darraytype, srcArray, destArray, 5 * 7)) {
        fprintf(stderr, "Error in pack/unpack check\n");
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    loc = 0;
    for (j = 0; j < 7; j++) {
        for (i = 0; i < 5; i++) {
            int expected = rx + ry * nx + i * px + j * nx * py;
            if (destArray[loc] != expected) {
                errs++;
                fprintf(stderr, "2D(cc): [%d,%d] = %d, expected %d\n",
                        i, j, destArray[loc], expected);
            }
            loc++;
        }
    }

    free(srcArray);
    free(destArray);
    MPI_Type_free(&darraytype);

    /* Cyclic(2)/Cyclic(3) */
    if (AllocateGrid(6 * px, 4 * py, &srcArray, &destArray)) {
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    /* Block cyclic/cyclic. Note in C order, the [1] index varies most
     * rapidly */
    gsizes[0] = ny = 4 * py;
    gsizes[1] = nx = 6 * px;
    distribs[0] = MPI_DISTRIBUTE_CYCLIC;
    distribs[1] = MPI_DISTRIBUTE_CYCLIC;
    dargs[0] = by = 2;
    dargs[1] = bx = 3;
    psizes[0] = py;
    psizes[1] = px;
    MPI_Type_create_darray(wsize, wrank, 2,
                           gsizes, distribs, dargs, psizes, MPI_ORDER_C, MPI_INT, &darraytype);

    /* Check the created datatype.  Because cyclic, should represent
     * a strided type */
    if (PackUnpack(darraytype, srcArray, destArray, 4 * 6)) {
        fprintf(stderr, "Error in pack/unpack check\n");
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    loc = 0;
    for (j = 0; j < 4 / by; j++) {
        for (jj = 0; jj < by; jj++) {
            for (i = 0; i < 6 / bx; i++) {
                for (ii = 0; ii < bx; ii++) {
                    int expected = rx * bx + ry * by * nx + i * bx * px + ii +
                        (j * by * py + jj) * nx;
                    if (destArray[loc] != expected) {
                        errs++;
                        fprintf(stderr, "2D(c(2)c(3)): [%d,%d] = %d, expected %d\n",
                                i * bx + ii, j * by + jj, destArray[loc], expected);
                    }
                    loc++;
                }
            }
        }
    }

    free(srcArray);
    free(destArray);
    MPI_Type_free(&darraytype);

    MTest_Finalize(errs);

    return MTestReturnValue(errs);
}
int main(int argc, char* argv[])
{
    int** grid;            // grid containing the cells and whether they are alive or dead
    
    // set up curses for displaying the grid
#ifdef USE_CURSES
    initscr();
    if(has_colors())
    {
        start_color();
        init_pair(1, COLOR_BLACK, COLOR_WHITE);
        init_pair(2, COLOR_WHITE, COLOR_CYAN);
    }
#endif
    
    // allocate the grid
    grid = AllocateGrid();
    if(grid == NULL)
    {
        printf("ERROR: Could not allocate memory for grid\n");
        return -1;
    }
    
    // initialize and print the grid
    InitGrid(grid);
#ifdef PRINT_GRID
    PrintGrid(grid);
#endif
    
    for(int time = 1; time <= TIME_STEPS; ++time)
    {
        // sleep to observe updates
#ifdef PRINT_GRID
        usleep(SLEEP_TIME);
#endif
        
        // allocate temporary grid for storing the simultaneous update
        int** tempGrid = AllocateGrid();
        if(tempGrid == NULL)
        {
            printf("ERROR: Could not allocate memory for grid\n");
            return -1;
        }
    
        for(int i = 0; i < GRID_SIZE; ++i)
        {
            for(int j = 0; j < GRID_SIZE; ++j)
            {
                int numNeighborAlive = 0;
            
                for(int k = -1; k <= 1; ++k)
                {
                    for(int l = -1; l <= 1; ++l)
                    {
                        int row = (i + k) % GRID_SIZE;
                        int col = (j + l) % GRID_SIZE;
                        
                        if(row == -1)
                            row = GRID_SIZE - 1;
                        if(col == -1)
                            col = GRID_SIZE - 1;
                    
                        if( (row != i) || (col != j) )
                            numNeighborAlive += grid[row][col];
                    }
                }
                
                switch(numNeighborAlive)
                {
                case 2:
                    tempGrid[i][j] = grid[i][j];
                    break;
                    
                case 3:
                    tempGrid[i][j] = 1;
                    break;
                    
                default:
                    tempGrid[i][j] = 0;
                }
            }
        }
        
        free(grid);
        grid = tempGrid;
        
#ifdef USE_CURSES
        move(0, 0);
#endif
#ifdef PRINT_GRID
    PrintGrid(grid);
#endif
    }
    
    CountLive(grid);
    
#ifdef USE_CURSES
    printw("\nPress any key to continue...");
    refresh();
    getchar();
#endif
    
    free(grid);
#ifdef USE_CURSES
    endwin();
#endif

    return 0;
}