diff --git a/Engine/source/terrain/terrData.h b/Engine/source/terrain/terrData.h index 20588ccc0..967bfa0d1 100644 --- a/Engine/source/terrain/terrData.h +++ b/Engine/source/terrain/terrData.h @@ -233,7 +233,8 @@ public: F32 heightScale, F32 metersPerPixel, const Vector &layerMap, - const Vector &materials ); + const Vector &materials, + bool flipYAxis = true ); #ifdef TORQUE_TOOLS bool exportHeightMap( const UTF8 *filePath, const String &format ) const; diff --git a/Engine/source/terrain/terrFile.cpp b/Engine/source/terrain/terrFile.cpp index ccb49f10d..5edd2e2c7 100644 --- a/Engine/source/terrain/terrFile.cpp +++ b/Engine/source/terrain/terrFile.cpp @@ -683,7 +683,8 @@ void TerrainFile::setHeightMap( const Vector &heightmap, bool updateCollisi void TerrainFile::import( const GBitmap &heightMap, F32 heightScale, const Vector &layerMap, - const Vector &materials ) + const Vector &materials, + bool flipYAxis) { AssertFatal( heightMap.getWidth() == heightMap.getHeight(), "TerrainFile::import - Height map is not square!" ); AssertFatal( isPow2( heightMap.getWidth() ), "TerrainFile::import - Height map is not power of two!" ); @@ -702,23 +703,48 @@ void TerrainFile::import( const GBitmap &heightMap, { const F32 toFixedPoint = ( 1.0f / (F32)U16_MAX ) * floatToFixed( heightScale ); const U16 *iBits = (const U16*)heightMap.getBits(); - for ( U32 i = 0; i < mSize * mSize; i++ ) + if ( flipYAxis ) { - U16 height = convertBEndianToHost( *iBits ); - *oBits = (U16)mCeil( (F32)height * toFixedPoint ); - ++oBits; - ++iBits; + for ( U32 i = 0; i < mSize * mSize; i++ ) + { + U16 height = convertBEndianToHost( *iBits ); + *oBits = (U16)mCeil( (F32)height * toFixedPoint ); + ++oBits; + ++iBits; + } + } + else + { + for(S32 y = mSize - 1; y >= 0; y--) { + for(U32 x = 0; x < mSize; x++) { + U16 height = convertBEndianToHost( *iBits ); + mHeightMap[x + y * mSize] = (U16)mCeil( (F32)height * toFixedPoint ); + ++iBits; + } + } } } else { const F32 toFixedPoint = ( 1.0f / (F32)U8_MAX ) * floatToFixed( heightScale ); const U8 *iBits = heightMap.getBits(); - for ( U32 i = 0; i < mSize * mSize; i++ ) + if ( flipYAxis ) { - *oBits = (U16)mCeil( ((F32)*iBits) * toFixedPoint ); - ++oBits; - iBits += heightMap.getBytesPerPixel(); + for ( U32 i = 0; i < mSize * mSize; i++ ) + { + *oBits = (U16)mCeil( ((F32)*iBits) * toFixedPoint ); + ++oBits; + iBits += heightMap.getBytesPerPixel(); + } + } + else + { + for(S32 y = mSize - 1; y >= 0; y--) { + for(U32 x = 0; x < mSize; x++) { + mHeightMap[x + y * mSize] = (U16)mCeil( ((F32)*iBits) * toFixedPoint ); + iBits += heightMap.getBytesPerPixel(); + } + } } } diff --git a/Engine/source/terrain/terrFile.h b/Engine/source/terrain/terrFile.h index 04bac3d9b..3640d3664 100644 --- a/Engine/source/terrain/terrFile.h +++ b/Engine/source/terrain/terrFile.h @@ -152,7 +152,8 @@ public: void import( const GBitmap &heightMap, F32 heightScale, const Vector &layerMap, - const Vector &materials ); + const Vector &materials, + bool flipYAxis = true ); /// Updates the terrain grid for the specified area. void updateGrid( const Point2I &minPt, const Point2I &maxPt ); diff --git a/Engine/source/terrain/terrImport.cpp b/Engine/source/terrain/terrImport.cpp index 28c384e5f..ede106402 100644 --- a/Engine/source/terrain/terrImport.cpp +++ b/Engine/source/terrain/terrImport.cpp @@ -120,8 +120,8 @@ ConsoleStaticMethod( TerrainBlock, createNew, S32, 5, 5, return terrain->getId(); } -ConsoleStaticMethod( TerrainBlock, import, S32, 7, 7, - "( String terrainName, String heightMap, F32 metersPerPixel, F32 heightScale, String materials, String opacityLayers )\n" +ConsoleStaticMethod( TerrainBlock, import, S32, 7, 8, + "( String terrainName, String heightMap, F32 metersPerPixel, F32 heightScale, String materials, String opacityLayers[, bool flipYAxis=true] )\n" "" ) { // Get the parameters. @@ -131,6 +131,7 @@ ConsoleStaticMethod( TerrainBlock, import, S32, 7, 7, F32 heightScale = dAtof(argv[4]); const UTF8 *opacityFiles = argv[5]; const UTF8 *materialsStr = argv[6]; + bool flipYAxis = argc == 8? dAtob(argv[7]) : true; // First load the height map and validate it. Resource heightmap = GBitmap::load( hmap ); @@ -251,12 +252,12 @@ ConsoleStaticMethod( TerrainBlock, import, S32, 7, 7, // Do we have an existing terrain with that name... then update it! TerrainBlock *terrain = dynamic_cast( Sim::findObject( terrainName ) ); if ( terrain ) - terrain->import( (*heightmap), heightScale, metersPerPixel, layerMap, materials ); + terrain->import( (*heightmap), heightScale, metersPerPixel, layerMap, materials, flipYAxis ); else { terrain = new TerrainBlock(); terrain->assignName( terrainName ); - terrain->import( (*heightmap), heightScale, metersPerPixel, layerMap, materials ); + terrain->import( (*heightmap), heightScale, metersPerPixel, layerMap, materials, flipYAxis ); terrain->registerObject(); // Add to mission group! @@ -272,7 +273,8 @@ bool TerrainBlock::import( const GBitmap &heightMap, F32 heightScale, F32 metersPerPixel, const Vector &layerMap, - const Vector &materials ) + const Vector &materials, + bool flipYAxis) { AssertFatal( isServerObject(), "TerrainBlock::import - This should only be called on the server terrain!" ); @@ -299,7 +301,7 @@ bool TerrainBlock::import( const GBitmap &heightMap, } // The file does a bunch of the work. - mFile->import( heightMap, heightScale, layerMap, materials ); + mFile->import( heightMap, heightScale, layerMap, materials, flipYAxis ); // Set the square size. mSquareSize = metersPerPixel;