Skip to main content

Tooltopia

Part of recent events I've been busy on a streaming module of terrain rendering allowing an virtually unlimited terrain. While this is trivial there is still a problem of getting content. Luckily there are published elevation files,  SMRT or  it's predecessor DEM, from earth's key locations e.g. Taiwan. To process elevation information we do what we engineers do best, write tools.




I decided to step out of my comfort box and give C++CLI a shot.  Despite what people say mixed-mode assembly capabilities of C++CLI is quite a nice. We get to write all the goodies of .net exception being pretty syntax, and  we get to have low-level memory accessibility. It is truly ideal for some quick visualizations  without the need of going through the standard project setup workflow: downloading boost, downloading Qt, compiling them, add in some other third party libraries, reinvent code.
private: System::Void loadToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
  System::Windows::Forms::OpenFileDialog^ dialog = gcnew System::Windows::Forms::OpenFileDialog();
  dialog->Filter = "SRTM (*.hgt)|*.hgt";
  dialog->Multiselect = true;

  float minAltitude = -62;
  float maxAltitude = 3811;
  float altitudeRange = maxAltitude - minAltitude;

  if( dialog->ShowDialog() == System::Windows::Forms::DialogResult::OK )
  {

  System::Drawing::Color ocean = System::Drawing::Color::FromArgb(255, 60, 80, 100);
  System::Drawing::Bitmap^ gradiant = gcnew System::Drawing::Bitmap(1,1024, System::Drawing::Imaging::PixelFormat::Format32bppArgb);
  if( gradiant != nullptr  )
  {
   System::Drawing::Drawing2D::LinearGradientBrush^ brush = gcnew System::Drawing::Drawing2D::LinearGradientBrush(
    System::Drawing::Rectangle(0,0,1,1024), System::Drawing::Color::Black, System::Drawing::Color::White,
    System::Drawing::Drawing2D::LinearGradientMode::Vertical);

   System::Drawing::Drawing2D::ColorBlend^ blend = gcnew System::Drawing::Drawing2D::ColorBlend();
   blend->Positions = gcnew cli::array<float>(14);
   blend->Colors = gcnew cli::array<System::Drawing::Color>(14);
   blend->Positions[ 0] =(  -62 - minAltitude) / altitudeRange; blend->Colors[ 0] = System::Drawing::Color::FromArgb(255, 139, 146, 112);
   blend->Positions[ 1] =(  284 - minAltitude) / altitudeRange; blend->Colors[ 1] = System::Drawing::Color::FromArgb(255, 158, 159, 117);
   blend->Positions[ 2] =(  578 - minAltitude) / altitudeRange; blend->Colors[ 2] = System::Drawing::Color::FromArgb(255, 177, 173, 123);
   blend->Positions[ 3] =(  872 - minAltitude) / altitudeRange; blend->Colors[ 3] = System::Drawing::Color::FromArgb(255, 196, 186, 129);
   blend->Positions[ 4] =( 1166 - minAltitude) / altitudeRange; blend->Colors[ 4] = System::Drawing::Color::FromArgb(255, 215, 200, 135);
   blend->Positions[ 5] =( 1460 - minAltitude) / altitudeRange; blend->Colors[ 5] = System::Drawing::Color::FromArgb(255, 208, 190, 128);
   blend->Positions[ 6] =( 1754 - minAltitude) / altitudeRange; blend->Colors[ 6] = System::Drawing::Color::FromArgb(255, 202, 180, 121);
   blend->Positions[ 7] =( 2048 - minAltitude) / altitudeRange; blend->Colors[ 7] = System::Drawing::Color::FromArgb(255, 195, 170, 114);
   blend->Positions[ 8] =( 2342 - minAltitude) / altitudeRange; blend->Colors[ 8] = System::Drawing::Color::FromArgb(255, 189, 160, 107);
   blend->Positions[ 9] =( 2636 - minAltitude) / altitudeRange; blend->Colors[ 9] = System::Drawing::Color::FromArgb(255, 183, 150, 101);
   blend->Positions[10] =( 2930 - minAltitude) / altitudeRange; blend->Colors[10] = System::Drawing::Color::FromArgb(255, 179, 154, 113);
   blend->Positions[11] =( 3224 - minAltitude) / altitudeRange; blend->Colors[11] = System::Drawing::Color::FromArgb(255, 175, 158, 126);
   blend->Positions[12] =( 3518 - minAltitude) / altitudeRange; blend->Colors[12] = System::Drawing::Color::FromArgb(255, 171, 162, 138);
   blend->Positions[13] =( 3811 - minAltitude) / altitudeRange; blend->Colors[13] = System::Drawing::Color::FromArgb(255, 167, 167, 151);
   brush->InterpolationColors = blend;

   System::Drawing::Graphics^ g = System::Drawing::Graphics::FromImage(gradiant);
   g->FillRectangle( brush, System::Drawing::Rectangle(0,0,1,1024));
   delete g;
  }

  int minLongitude = 0x7FFFFFFF, maxLongitude = 0xFFFFFFFF;
  int minLatitude = 0x7FFFFFFF, maxLatitude = 0xFFFFFFFF;
     System::Text::RegularExpressions::Regex^ regex = gcnew System::Text::RegularExpressions::Regex("(N|S)(d+)(E|W)(d+).hgt");
  for( int i = 0; i < dialog->FileNames->Length; i++ )
  {
   System::Text::RegularExpressions::Match^ matches = regex->Match( dialog->FileNames[i] );
   System::IO::FileInfo^ info = gcnew System::IO::FileInfo( dialog->FileNames[i] );
   int numberOfEntries = (info->Length / 2), gridSize = System::Math::Sqrt( numberOfEntries );
   int latitude = System::Int32::Parse( matches->Groups[2]->Value );
   int longitude = System::Int32::Parse( matches->Groups[4]->Value );
   minLatitude = System::Math::Min( minLatitude, latitude );
   maxLatitude = System::Math::Max( maxLatitude, latitude + 1 );
   minLongitude = System::Math::Min( minLongitude, longitude );
   maxLongitude = System::Math::Max( maxLongitude, longitude + 1 );
  }

  int numberOfBlocksWidth = maxLongitude - minLongitude;
  int numberOfBlocksHeight = maxLatitude - minLatitude;
  int pixelsWidth = (numberOfBlocksWidth * 1201);
  int pixelsHeight = (numberOfBlocksHeight * 1201);

  cli::array<signed short,2>^ values = gcnew cli::array<signed short,2>(pixelsWidth, pixelsHeight);
  for( int y = 0; y < pixelsHeight; y++ ) for( int x = 0; x < pixelsWidth; x++ )
   values[x,y] = -100;

  System::Drawing::Bitmap^ bitmap = gcnew System::Drawing::Bitmap(pixelsWidth,pixelsHeight, System::Drawing::Imaging::PixelFormat::Format32bppArgb );
  System::Drawing::Graphics^ g = System::Drawing::Graphics::FromImage(bitmap);
  g->Clear( ocean );
  delete g;

  for( int i = 0; i < dialog->FileNames->Length; i++ )
  {
   System::Text::RegularExpressions::Match^ matches = regex->Match( dialog->FileNames[i] );
   System::IO::FileStream^ fs = System::IO::File::OpenRead(dialog->FileNames[i]);
   int latitude = System::Int32::Parse( matches->Groups[2]->Value );
   int longitude = System::Int32::Parse( matches->Groups[4]->Value );
   int length = fs->Length / 2, gsize= System::Math::Sqrt( length );

   int pixelOffsetX = gsize * (longitude - minLongitude), pixelOffsetY = gsize * (latitude - minLatitude);
   //pixelOffsetX = pixelsWidth - gsize - pixelOffsetX;
   pixelOffsetY = pixelsHeight - gsize - pixelOffsetY;

   System::Drawing::Imaging::BitmapData^ data = bitmap->LockBits(  System::Drawing::Rectangle(pixelOffsetX,pixelOffsetY,gsize,gsize), System::Drawing::Imaging::ImageLockMode::WriteOnly, System::Drawing::Imaging::PixelFormat::Format32bppArgb );
   for(int y=0; y < gsize; y++)
   {
    System::Byte* row=   (System::Byte*)(data->Scan0.ToPointer() ) + System::Int32(y*data->Stride);
    for(int x=0; x< gsize; x++)
    {     

     signed short value = (fs->ReadByte() << 8) | (fs->ReadByte()  << 0);
     values[pixelOffsetX + x, pixelOffsetY + y] = value;
     signed short valueClamped = System::Math::Max( System::Math::Min( value, (signed short)maxAltitude ), (signed short)minAltitude );
     signed int pixelOffset = (int)((valueClamped - minAltitude) / altitudeRange * 1023.0);
     System::Drawing::Color color = gradiant->GetPixel( 0, pixelOffset);
     if( value <= 0 )  color = ocean;

     row[x * 4 + 0] = color.B;
     row[x * 4 + 1] = color.G;
     row[x * 4 + 2] = color.R;
     row[x * 4 + 3] = 255;
    }
   }

   bitmap->UnlockBits(data );
   fs->Close();
  }       

  pictureBox1->Image = bitmap;
  pictureBox1->Bounds = System::Drawing::Rectangle(0,0, numberOfBlocksWidth * 1201, numberOfBlocksHeight * 1201);
  data_values = values;
  data_size_x = numberOfBlocksWidth * 1201;
  data_size_y = numberOfBlocksHeight * 1201;
  }
 }



Comments

Popular posts from this blog

Roadtrip to Germany-Switzerland-Austria-Czech pt. 1

Last month I had the luxury to go down for a road trip through various countries in Germany. Despite it being early fall season we actually had a lot of sunshine, and it was uncanny to see the beautiful scenery we passed through. Our favorite place was on the road from Salzburg to Halstadt where we were headed for the famous sky outlook. We came across a lake surrounded by mountains (presumable alps), the nature is unfathomable.  

Helsinki in summer

Last year I was briefly in Helsinki during the summer festival which was held in august. On my way back to the Netherlands I saw the logo of the Unity office on building. The first impressions I had coming into this city are the large streets and the relatively 'big buildings', very different from in the Netherlands.

Material & shader management

In the upcoming changes in my editor I implemented the material system inspired on  Frostbite engine of DICE, binaries are download-able on the project page. Also I've implemented an conversion tool and file-format for future mesh formats using Assimp.