terrData.cpp
Engine/source/terrain/terrData.cpp
Public Typedefs
baseTexFormat
Public Variables
_getTerrainHeight2 ("@brief Gets the terrain height at the specified position\n\n" "@param x The X coordinate in world space\n" "@param y The Y coordinate in world space\n\n" "@return Returns the terrain height at the given point as an F32 value.\n\n" "@ingroup Terrain", NULL, "bool getTerrainHeight( F32 x, F32 y);")
_getTerrainHeightBelowPosition2 ("@brief Takes a world point and find the \"highest\" terrain underneath it\n\n" "@param x The X coordinate in world space\n" "@param y The Y coordinate in world space\n\n" "@return Returns the closest terrain height below the given point as an F32 value.\n\n" "@ingroup Terrain", NULL, "bool getTerrainHeightBelowPosition( F32 x, F32 y);")
_getTerrainUnderWorldPoint1 ("@brief Gets the terrain block that is located under the given world point\n\n" "@param position The world space coordinate you wish to query at. Formatted as (\"x y z\")\n\n" "@return Returns the ID of the requested terrain block (0 if not found).\n\n" "@ingroup Terrain", NULL, "bool getTerrainUnderWorldPoint( Point3F position );")
_getTerrainUnderWorldPoint2 ("@brief Takes a world point and find the \"highest\" terrain underneath it\n\n" "@param x The X coordinate in world space\n" "@param y The Y coordinate in world space\n\n" "@param z The Z coordinate in world space\n\n" "@return Returns the ID of the requested terrain block (0 if not found).\n\n" "@ingroup Terrain", NULL, "bool getTerrainUnderWorldPoint( F32 x, F32 y, F32 z);")
Public Functions
_getTerrainHeight1("@brief Gets the terrain height at the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position\n\n</a>" "@param position The world space point, minus the z(height) value. Formatted as(\"x y\")\n\n" "@return Returns the terrain height at the given point as an <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">value.\n\n</a>" "@ingroup Terrain" , NULL , "bool getTerrainHeight( <a href="/coding/class/classpoint2i/">Point2I</a> position );" )
_getTerrainHeightBelowPosition1("@brief Takes <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> world point and find the \"highest\" terrain underneath <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">it\n\n</a>" "@param position The world space point, minus the z(height) value. Formatted as(\"x y\")\n\n" "@return Returns the closest terrain height below the given point as an <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">value.\n\n</a>" "@ingroup Terrain" , NULL , "bool getTerrainHeightBelowPosition( <a href="/coding/class/classpoint2i/">Point2I</a> position );" )
ConsoleDocClass(TerrainBlock , "@brief Represent <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> terrain object in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> Torque 3D <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">level\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "<a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classterrainblock/">TerrainBlock</a>(theTerrain)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " terrainFile = \"art/terrains/Deathball Desert_0.ter\";\n" " squareSize = \"2\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " tile = \"0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " baseTexSize = \"1024\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " screenError = \"16\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " position = \"-1024 -1024 179.978\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " rotation = \"1 0 0 0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " scale = \"1 1 1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " isRenderEnabled = \"true\";\n" " canSaveDynamicFields = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">TerrainMaterial\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Terrain\n</a>" )
DefineEngineFunction(getTerrainHeight , F32 , (const char *ptOrX, const char *y) , ("") , "(Point2 pos) - gets the terrain height at the specified position." "@param pos The world space point, minus the z(height) <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">value\n</a> Can be formatted as either(\"x y\") or (x,y)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return Returns the terrain height at the given point as an <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">value.\n</a>" "@hide" )
DefineEngineFunction(getTerrainHeightBelowPosition , F32 , (const char *ptOrX, const char *y, const char *z) , ("", "") , "(Point3F pos) - gets the terrain height at the specified position." "@param pos The world space point. Can be formatted as either (\"x y z\") or (x,y,z)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@note This function is useful <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> you simply want <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> grab the terrain height underneath an <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return Returns the terrain height at the given point as an <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">value.\n</a>" "@hide" )
DefineEngineFunction(getTerrainUnderWorldPoint , S32 , (const char *ptOrX, const char *y, const char *z) , ("", "") , "(Point3F x/y/z) Gets the terrain block that is located under the given world <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">point.\n</a>" "@param x/y/z The world coordinates (floating point values) you wish <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> query at. " "These can be formatted as either <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> string (\"x y z\") or separately as (x, y, z)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return Returns the ID of the requested terrain block (0 <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> not found).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@hide" )
DefineEngineMethod(TerrainBlock , save , bool , (const char *fileName) , "@brief Saves the terrain block's terrain <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">name.\n\n</a>" "@param fileName Name and path of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> save terrain data <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> save was successful, false otherwise" )
DefineEngineMethod(TerrainBlock , saveAsset , bool , () , "@brief Saves the terrain block's terrain <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">name.\n\n</a>" "@param fileName Name and path of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> save terrain data <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> save was successful, false otherwise" )
DefineEngineMethod(TerrainBlock , setMaterialsDirty , void , () , "" )
getTerrainUnderWorldPoint(const Point3F & wPos)
ImplementEnumType(baseTexFormat , "Description\n" "@ingroup ?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" )
Detailed Description
Public Typedefs
typedef TerrainBlock::BaseTexFormat baseTexFormat
Public Variables
ConsoleDocFragment _getTerrainHeight2 ("@brief Gets the terrain height at the specified position\n\n" "@param x The X coordinate in world space\n" "@param y The Y coordinate in world space\n\n" "@return Returns the terrain height at the given point as an F32 value.\n\n" "@ingroup Terrain", NULL, "bool getTerrainHeight( F32 x, F32 y);")
ConsoleDocFragment _getTerrainHeightBelowPosition2 ("@brief Takes a world point and find the \"highest\" terrain underneath it\n\n" "@param x The X coordinate in world space\n" "@param y The Y coordinate in world space\n\n" "@return Returns the closest terrain height below the given point as an F32 value.\n\n" "@ingroup Terrain", NULL, "bool getTerrainHeightBelowPosition( F32 x, F32 y);")
ConsoleDocFragment _getTerrainUnderWorldPoint1 ("@brief Gets the terrain block that is located under the given world point\n\n" "@param position The world space coordinate you wish to query at. Formatted as (\"x y z\")\n\n" "@return Returns the ID of the requested terrain block (0 if not found).\n\n" "@ingroup Terrain", NULL, "bool getTerrainUnderWorldPoint( Point3F position );")
ConsoleDocFragment _getTerrainUnderWorldPoint2 ("@brief Takes a world point and find the \"highest\" terrain underneath it\n\n" "@param x The X coordinate in world space\n" "@param y The Y coordinate in world space\n\n" "@param z The Z coordinate in world space\n\n" "@return Returns the ID of the requested terrain block (0 if not found).\n\n" "@ingroup Terrain", NULL, "bool getTerrainUnderWorldPoint( F32 x, F32 y, F32 z);")
EndImplementEnumType
Convex sTerrainConvexList
Public Functions
_getTerrainHeight1("@brief Gets the terrain height at the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position\n\n</a>" "@param position The world space point, minus the z(height) value. Formatted as(\"x y\")\n\n" "@return Returns the terrain height at the given point as an <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">value.\n\n</a>" "@ingroup Terrain" , NULL , "bool getTerrainHeight( <a href="/coding/class/classpoint2i/">Point2I</a> position );" )
_getTerrainHeightBelowPosition1("@brief Takes <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> world point and find the \"highest\" terrain underneath <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">it\n\n</a>" "@param position The world space point, minus the z(height) value. Formatted as(\"x y\")\n\n" "@return Returns the closest terrain height below the given point as an <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">value.\n\n</a>" "@ingroup Terrain" , NULL , "bool getTerrainHeightBelowPosition( <a href="/coding/class/classpoint2i/">Point2I</a> position );" )
ConsoleDocClass(TerrainBlock , "@brief Represent <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> terrain object in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> Torque 3D <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">level\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "<a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classterrainblock/">TerrainBlock</a>(theTerrain)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " terrainFile = \"art/terrains/Deathball Desert_0.ter\";\n" " squareSize = \"2\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " tile = \"0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " baseTexSize = \"1024\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " screenError = \"16\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " position = \"-1024 -1024 179.978\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " rotation = \"1 0 0 0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " scale = \"1 1 1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " isRenderEnabled = \"true\";\n" " canSaveDynamicFields = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">TerrainMaterial\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Terrain\n</a>" )
DefineEngineFunction(getTerrainHeight , F32 , (const char *ptOrX, const char *y) , ("") , "(Point2 pos) - gets the terrain height at the specified position." "@param pos The world space point, minus the z(height) <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">value\n</a> Can be formatted as either(\"x y\") or (x,y)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return Returns the terrain height at the given point as an <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">value.\n</a>" "@hide" )
DefineEngineFunction(getTerrainHeightBelowPosition , F32 , (const char *ptOrX, const char *y, const char *z) , ("", "") , "(Point3F pos) - gets the terrain height at the specified position." "@param pos The world space point. Can be formatted as either (\"x y z\") or (x,y,z)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@note This function is useful <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> you simply want <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> grab the terrain height underneath an <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return Returns the terrain height at the given point as an <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">value.\n</a>" "@hide" )
DefineEngineFunction(getTerrainUnderWorldPoint , S32 , (const char *ptOrX, const char *y, const char *z) , ("", "") , "(Point3F x/y/z) Gets the terrain block that is located under the given world <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">point.\n</a>" "@param x/y/z The world coordinates (floating point values) you wish <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> query at. " "These can be formatted as either <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> string (\"x y z\") or separately as (x, y, z)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return Returns the ID of the requested terrain block (0 <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> not found).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@hide" )
DefineEngineMethod(TerrainBlock , save , bool , (const char *fileName) , "@brief Saves the terrain block's terrain <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">name.\n\n</a>" "@param fileName Name and path of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> save terrain data <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> save was successful, false otherwise" )
DefineEngineMethod(TerrainBlock , saveAsset , bool , () , "@brief Saves the terrain block's terrain <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">name.\n\n</a>" "@param fileName Name and path of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> save terrain data <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> save was successful, false otherwise" )
DefineEngineMethod(TerrainBlock , setMaterialsDirty , void , () , "" )
DefineEnumType(baseTexFormat )
getTerrainUnderWorldPoint(const Point3F & wPos)
IMPLEMENT_CO_NETOBJECT_V1(TerrainBlock )
ImplementEnumType(baseTexFormat , "Description\n" "@ingroup ?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 25// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames 26// Copyright (C) 2015 Faust Logic, Inc. 27//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 28 29#include "platform/platform.h" 30#include "terrain/terrData.h" 31 32#include "terrain/terrCollision.h" 33#include "terrain/terrCell.h" 34#include "terrain/terrRender.h" 35#include "terrain/terrMaterial.h" 36#include "terrain/terrCellMaterial.h" 37#include "gui/worldEditor/terrainEditor.h" 38#include "math/mathIO.h" 39#include "core/stream/fileStream.h" 40#include "core/stream/bitStream.h" 41#include "console/consoleTypes.h" 42#include "sim/netConnection.h" 43#include "core/util/safeDelete.h" 44#include "T3D/objectTypes.h" 45#include "renderInstance/renderPassManager.h" 46#include "scene/sceneRenderState.h" 47#include "materials/materialManager.h" 48#include "materials/baseMatInstance.h" 49#include "gfx/gfxTextureManager.h" 50#include "gfx/gfxCardProfile.h" 51#include "gfx/gfxAPI.h" 52#include "core/resourceManager.h" 53#include "T3D/physics/physicsPlugin.h" 54#include "T3D/physics/physicsBody.h" 55#include "T3D/physics/physicsCollision.h" 56#include "console/engineAPI.h" 57#include "core/util/safeRelease.h" 58 59#include "T3D/assets/TerrainMaterialAsset.h" 60using namespace Torque; 61 62IMPLEMENT_CO_NETOBJECT_V1(TerrainBlock); 63 64ConsoleDocClass( TerrainBlock, 65 "@brief Represent a terrain object in a Torque 3D level\n\n" 66 67 "@tsexample\n" 68 "new TerrainBlock(theTerrain)\n" 69 "{\n" 70 " terrainFile = \"art/terrains/Deathball Desert_0.ter\";\n" 71 " squareSize = \"2\";\n" 72 " tile = \"0\";\n" 73 " baseTexSize = \"1024\";\n" 74 " screenError = \"16\";\n" 75 " position = \"-1024 -1024 179.978\";\n" 76 " rotation = \"1 0 0 0\";\n" 77 " scale = \"1 1 1\";\n" 78 " isRenderEnabled = \"true\";\n" 79 " canSaveDynamicFields = \"1\";\n" 80 "};\n" 81 "@endtsexample\n\n" 82 83 "@see TerrainMaterial\n\n" 84 85 "@ingroup Terrain\n" 86); 87 88 89Signal<void(U32,TerrainBlock*,const Point2I& ,const Point2I&)> TerrainBlock::smUpdateSignal; 90 91F32 TerrainBlock::smLODScale = 1.0f; 92F32 TerrainBlock::smDetailScale = 1.0f; 93 94 95//RBP - Global function declared in Terrdata.h 96TerrainBlock* getTerrainUnderWorldPoint(const Point3F & wPos) 97{ 98 // Cast a ray straight down from the world position and see which 99 // Terrain is the closest to our starting point 100 Point3F startPnt = wPos; 101 Point3F endPnt = wPos + Point3F(0.0f, 0.0f, -10000.0f); 102 103 S32 blockIndex = -1; 104 F32 nearT = 1.0f; 105 106 SimpleQueryList queryList; 107 gServerContainer.findObjects( TerrainObjectType, SimpleQueryList::insertionCallback, &queryList); 108 109 for (U32 i = 0; i < queryList.mList.size(); i++) 110 { 111 Point3F tStartPnt, tEndPnt; 112 TerrainBlock* terrBlock = dynamic_cast<TerrainBlock*>(queryList.mList[i]); 113 terrBlock->getWorldTransform().mulP(startPnt, &tStartPnt); 114 terrBlock->getWorldTransform().mulP(endPnt, &tEndPnt); 115 116 RayInfo ri; 117 if (terrBlock->castRayI(tStartPnt, tEndPnt, &ri, true)) 118 { 119 if (ri.t < nearT) 120 { 121 blockIndex = i; 122 nearT = ri.t; 123 } 124 } 125 } 126 127 if (blockIndex > -1) 128 return (TerrainBlock*)(queryList.mList[blockIndex]); 129 130 return NULL; 131} 132 133 134ConsoleDocFragment _getTerrainUnderWorldPoint1( 135 "@brief Gets the terrain block that is located under the given world point\n\n" 136 "@param position The world space coordinate you wish to query at. Formatted as (\"x y z\")\n\n" 137 "@return Returns the ID of the requested terrain block (0 if not found).\n\n" 138 "@ingroup Terrain", 139 NULL, 140 "bool getTerrainUnderWorldPoint( Point3F position );" 141); 142ConsoleDocFragment _getTerrainUnderWorldPoint2( 143 "@brief Takes a world point and find the \"highest\" terrain underneath it\n\n" 144 "@param x The X coordinate in world space\n" 145 "@param y The Y coordinate in world space\n\n" 146 "@param z The Z coordinate in world space\n\n" 147 "@return Returns the ID of the requested terrain block (0 if not found).\n\n" 148 "@ingroup Terrain", 149 NULL, 150 "bool getTerrainUnderWorldPoint( F32 x, F32 y, F32 z);" 151); 152 153DefineEngineFunction( getTerrainUnderWorldPoint, S32, (const char* ptOrX, const char* y, const char* z), ("", ""), 154 "(Point3F x/y/z) Gets the terrain block that is located under the given world point.\n" 155 "@param x/y/z The world coordinates (floating point values) you wish to query at. " 156 "These can be formatted as either a string (\"x y z\") or separately as (x, y, z)\n" 157 "@return Returns the ID of the requested terrain block (0 if not found).\n\n" 158 "@hide") 159{ 160 Point3F pos; 161 if(!String::isEmpty(ptOrX) && String::isEmpty(y) && String::isEmpty(z)) 162 dSscanf(ptOrX, "%f %f %f", &pos.x, &pos.y, &pos.z); 163 else if(!String::isEmpty(ptOrX) && !String::isEmpty(y) && !String::isEmpty(z)) 164 { 165 pos.x = dAtof(ptOrX); 166 pos.y = dAtof(y); 167 pos.z = dAtof(z); 168 } 169 TerrainBlock* terrain = getTerrainUnderWorldPoint(pos); 170 if(terrain != NULL) 171 { 172 return terrain->getId(); 173 } 174 return 0; 175} 176 177 178typedef TerrainBlock::BaseTexFormat baseTexFormat; 179DefineEnumType(baseTexFormat); 180 181ImplementEnumType(baseTexFormat, 182 "Description\n" 183 "@ingroup ?\n\n") 184{ TerrainBlock::NONE, "NONE", "No cached terrain.\n" }, 185{ TerrainBlock::DDS, "DDS", "Cache the terrain in a DDS format.\n" }, 186{ TerrainBlock::PNG, "PNG", "Cache the terrain in a PNG format.\n" }, 187EndImplementEnumType; 188 189TerrainBlock::TerrainBlock() 190 : mLightMap( NULL ), 191 mLightMapSize( 256 ), 192 mCRC( 0 ), 193 mMaxDetailDistance( 0.0f ), 194 mBaseTexScaleConst( NULL ), 195 mBaseTexIdConst( NULL ), 196 mBaseLayerSizeConst(NULL), 197 mDetailsDirty( false ), 198 mLayerTexDirty( false ), 199 mBaseTexSize( 1024 ), 200 mBaseTexFormat( TerrainBlock::DDS ), 201 mCell( NULL ), 202 mBaseMaterial( NULL ), 203 mDefaultMatInst( NULL ), 204 mSquareSize( 1.0f ), 205 mPhysicsRep( NULL ), 206 mScreenError( 16 ), 207 mCastShadows( true ), 208 mZoningDirty( false ), 209 mUpdateBasetex ( true ), 210 mDetailTextureArray( NULL ), 211 mMacroTextureArray( NULL ), 212 mOrmTextureArray( NULL ), 213 mNormalTextureArray( NULL ) 214{ 215 mTypeMask = TerrainObjectType | StaticObjectType | StaticShapeObjectType; 216 mNetFlags.set(Ghostable | ScopeAlways); 217 mIgnoreZodiacs = false; 218 zode_primBuffer = 0; 219 220 mTerrainAsset = StringTable->EmptyString(); 221 mTerrainAssetId = StringTable->EmptyString(); 222} 223 224 225extern Convex sTerrainConvexList; 226 227TerrainBlock::~TerrainBlock() 228{ 229 // Kill collision 230 sTerrainConvexList.nukeList(); 231 232 SAFE_DELETE(mLightMap); 233 mLightMapTex = NULL; 234 235#ifdef TORQUE_TOOLS 236 TerrainEditor* editor = dynamic_cast<TerrainEditor*>(Sim::findObject("ETerrainEditor")); 237 if (editor) 238 editor->detachTerrain(this); 239#endif 240 deleteZodiacPrimitiveBuffer(); 241 242 SAFE_RELEASE(mDetailTextureArray); 243 SAFE_RELEASE(mMacroTextureArray); 244 SAFE_RELEASE(mNormalTextureArray); 245 SAFE_RELEASE(mOrmTextureArray); 246} 247 248void TerrainBlock::_onTextureEvent( GFXTexCallbackCode code ) 249{ 250 if ( code == GFXZombify ) 251 { 252 if ( mBaseTex.isValid() && 253 mBaseTex->isRenderTarget() ) 254 mBaseTex = NULL; 255 256 mLayerTex = NULL; 257 mLightMapTex = NULL; 258 } 259} 260 261bool TerrainBlock::_setSquareSize( void *obj, const char *index, const char *data ) 262{ 263 TerrainBlock *terrain = static_cast<TerrainBlock*>( obj ); 264 265 F32 newSqaureSize = dAtof( data ); 266 if ( !mIsEqual( terrain->mSquareSize, newSqaureSize ) ) 267 { 268 terrain->mSquareSize = newSqaureSize; 269 270 if ( terrain->isServerObject() && terrain->isProperlyAdded() ) 271 terrain->_updateBounds(); 272 273 terrain->setMaskBits( HeightMapChangeMask | SizeMask ); 274 } 275 276 return false; 277} 278 279bool TerrainBlock::_setBaseTexSize( void *obj, const char *index, const char *data ) 280{ 281 TerrainBlock *terrain = static_cast<TerrainBlock*>( obj ); 282 283 // NOTE: We're limiting the base texture size to 284 // 2048 as anything greater in size becomes too 285 // large to generate for many cards. 286 // 287 // If you want to remove this limit feel free, but 288 // prepare for problems if you don't ship the baked 289 // base texture with your installer. 290 // 291 292 S32 texSize = mClamp( dAtoi( data ), 0, 2048 ); 293 if ( terrain->mBaseTexSize != texSize ) 294 { 295 terrain->mBaseTexSize = texSize; 296 terrain->setMaskBits( MaterialMask ); 297 } 298 299 return false; 300} 301 302bool TerrainBlock::_setBaseTexFormat(void *obj, const char *index, const char *data) 303{ 304 TerrainBlock *terrain = static_cast<TerrainBlock*>(obj); 305 306 EngineEnumTable eTable = _baseTexFormat::_sEnumTable; 307 308 for (U8 i = 0; i < eTable.getNumValues(); i++) 309 { 310 if (strcasecmp(eTable[i].mName, data) == 0) 311 { 312 terrain->mBaseTexFormat = (BaseTexFormat)eTable[i].mInt; 313 terrain->_updateMaterials(); 314 315 if (terrain->isServerObject()) return false; 316 terrain->_updateLayerTexture(); 317 // If the cached base texture is older that the terrain file or 318 // it doesn't exist then generate and cache it. 319 String baseCachePath = terrain->_getBaseTexCacheFileName(); 320 if (Platform::compareModifiedTimes(baseCachePath, terrain->mTerrainAsset->getTerrainFilePath()) < 0 && terrain->mUpdateBasetex) 321 terrain->_updateBaseTexture(true); 322 break; 323 } 324 } 325 326 return false; 327} 328 329bool TerrainBlock::_setLightMapSize( void *obj, const char *index, const char *data ) 330{ 331 TerrainBlock *terrain = static_cast<TerrainBlock*>(obj); 332 333 // Handle inspector value decrements correctly 334 U32 mapSize = dAtoi( data ); 335 if ( mapSize == terrain->mLightMapSize-1 ) 336 mapSize = terrain->mLightMapSize/2; 337 338 // Limit the lightmap size, and ensure it is a power of 2 339 const U32 maxTextureSize = GFX->getCardProfiler()->queryProfile( "maxTextureSize", 1024 ); 340 mapSize = mClamp( getNextPow2( mapSize ), 0, maxTextureSize ); 341 342 if ( terrain->mLightMapSize != mapSize ) 343 { 344 terrain->mLightMapSize = mapSize; 345 terrain->setMaskBits( MaterialMask ); 346 } 347 348 return false; 349} 350 351bool TerrainBlock::setFile( const FileName &terrFileName ) 352{ 353 if ( mTerrainAsset && mTerrainAsset->getTerrainFilePath() == terrFileName ) 354 return mFile != NULL; 355 356 Resource<TerrainFile> file = ResourceManager::get().load( terrFileName ); 357 if( !file ) 358 return false; 359 360 setFile( file ); 361 setMaskBits( FileMask | HeightMapChangeMask ); 362 363 return true; 364} 365 366void TerrainBlock::setFile(const Resource<TerrainFile>& terr) 367{ 368 if (mFile) 369 { 370 GFXTextureManager::removeEventDelegate(this, &TerrainBlock::_onTextureEvent); 371 MATMGR->getFlushSignal().remove(this, &TerrainBlock::_onFlushMaterials); 372 } 373 374 mFile = terr; 375 376 if (!mFile) 377 { 378 Con::errorf("TerrainBlock::setFile() - No valid terrain file!"); 379 return; 380 } 381 382 if (terr->mNeedsResaving) 383 { 384 if (Platform::messageBox("Update Terrain File", "You appear to have a Terrain file in an older format. Do you want Torque to update it?", MBOkCancel, MIQuestion) == MROk) 385 { 386 mFile->save(terr->mFilePath.getFullPath()); 387 mFile->mNeedsResaving = false; 388 } 389 } 390 391 if (terr->mFileVersion != TerrainFile::FILE_VERSION || terr->mNeedsResaving) 392 { 393 Con::errorf(" *********************************************************"); 394 Con::errorf(" *********************************************************"); 395 Con::errorf(" *********************************************************"); 396 Con::errorf(" PLEASE RESAVE THE TERRAIN FILE FOR THIS MISSION! THANKS!"); 397 Con::errorf(" *********************************************************"); 398 Con::errorf(" *********************************************************"); 399 Con::errorf(" *********************************************************"); 400 } 401 402 403 _updateBounds(); 404 405 resetWorldBox(); 406 setRenderTransform(mObjToWorld); 407 408 if (isClientObject()) 409 { 410 if (mCRC != terr.getChecksum()) 411 { 412 NetConnection::setLastError("Your terrain file doesn't match the version that is running on the server."); 413 return; 414 } 415 416 clearLightMap(); 417 418 // Init the detail layer rendering helper. 419 _updateMaterials(); 420 _updateLayerTexture(); 421 422 // If the cached base texture is older that the terrain file or 423 // it doesn't exist then generate and cache it. 424 String baseCachePath = _getBaseTexCacheFileName(); 425 if (Platform::compareModifiedTimes(baseCachePath, mTerrainAsset->getTerrainFilePath()) < 0 && mUpdateBasetex) 426 _updateBaseTexture(true); 427 428 // The base texture should have been cached by now... so load it. 429 mBaseTex.set(baseCachePath, &GFXStaticTextureSRGBProfile, "TerrainBlock::mBaseTex"); 430 431 GFXTextureManager::addEventDelegate(this, &TerrainBlock::_onTextureEvent); 432 MATMGR->getFlushSignal().notify(this, &TerrainBlock::_onFlushMaterials); 433 434 // Build the terrain quadtree. 435 _rebuildQuadtree(); 436 437 // Preload all the materials. 438 mCell->preloadMaterials(); 439 440 mZoningDirty = true; 441 SceneZoneSpaceManager::getZoningChangedSignal().notify(this, &TerrainBlock::_onZoningChanged); 442 } 443 else 444 mCRC = terr.getChecksum(); 445} 446 447bool TerrainBlock::setTerrainAsset(const StringTableEntry terrainAssetId) 448{ 449 if (TerrainAsset::getAssetById(terrainAssetId, &mTerrainAsset)) 450 { 451 //Special exception case. If we've defaulted to the 'no shape' mesh, don't save it out, we'll retain the original ids/paths so it doesn't break 452 //the TSStatic 453 if (!mTerrainAsset.isNull()) 454 { 455 mTerrFileName = StringTable->EmptyString(); 456 } 457 458 setFile(mTerrainAsset->getTerrainResource()); 459 460 setMaskBits(-1); 461 462 return true; 463 } 464 465 return false; 466} 467 468bool TerrainBlock::save(const char *filename) 469{ 470 return mFile->save(filename); 471} 472 473bool TerrainBlock::saveAsset() 474{ 475 if (!mTerrainAsset.isNull() && mTerrainAsset->isAssetValid()) 476 { 477 mTerrainAsset->clearAssetDependencyFields("terrainMaterailAsset"); 478 479 AssetQuery* pAssetQuery = new AssetQuery(); 480 pAssetQuery->registerObject(); 481 482 AssetDatabase.findAssetType(pAssetQuery, "TerrainMaterialAsset"); 483 484 TerrainBlock* clientTerr = static_cast<TerrainBlock*>(getClientObject()); 485 486 for (U32 i = 0; i < pAssetQuery->mAssetList.size(); i++) 487 { 488 //Acquire it so we can check it for matches 489 AssetPtr<TerrainMaterialAsset> terrMatAsset = pAssetQuery->mAssetList[i]; 490 491 for (U32 m = 0; m < clientTerr->mFile->mMaterials.size(); m++) 492 { 493 StringTableEntry intMatName = clientTerr->mFile->mMaterials[m]->getInternalName(); 494 495 StringTableEntry assetMatDefName = terrMatAsset->getMaterialDefinitionName(); 496 if (assetMatDefName == intMatName) 497 { 498 mTerrainAsset->addAssetDependencyField("terrainMaterailAsset", terrMatAsset.getAssetId()); 499 } 500 } 501 502 terrMatAsset.clear(); 503 } 504 505 pAssetQuery->destroySelf(); 506 507 bool saveAssetSuccess = mTerrainAsset->saveAsset(); 508 509 if (!saveAssetSuccess) 510 return false; 511 512 return mFile->save(mTerrainAsset->getTerrainFilePath()); 513 } 514 515 return false; 516} 517 518bool TerrainBlock::_setTerrainFile( void *obj, const char *index, const char *data ) 519{ 520 //TerrainBlock* terrain = static_cast<TerrainBlock*>( obj )->setFile( FileName( data ) ); 521 TerrainBlock* terrain = static_cast<TerrainBlock*>(obj); 522 523 StringTableEntry file = StringTable->insert(data); 524 525 if (file != StringTable->EmptyString()) 526 { 527 StringTableEntry assetId = TerrainAsset::getAssetIdByFilename(file); 528 if (assetId != StringTable->EmptyString()) 529 { 530 if (terrain->setTerrainAsset(assetId)) 531 { 532 terrain->mTerrainAssetId = assetId; 533 terrain->mTerrFileName = StringTable->EmptyString(); 534 535 return false; 536 } 537 } 538 else 539 { 540 terrain->mTerrainAsset = StringTable->EmptyString(); 541 } 542 } 543 544 return true; 545} 546 547bool TerrainBlock::_setTerrainAsset(void* obj, const char* index, const char* data) 548{ 549 TerrainBlock* terr = static_cast<TerrainBlock*>(obj);// ->setFile(FileName(data)); 550 551 terr->mTerrainAssetId = StringTable->insert(data); 552 553 return terr->setTerrainAsset(terr->mTerrainAssetId); 554} 555 556void TerrainBlock::_updateBounds() 557{ 558 if ( !mFile ) 559 return; // quick fix to stop crashing when deleting terrainblocks 560 561 // Setup our object space bounds. 562 mBounds.minExtents.set( 0.0f, 0.0f, 0.0f ); 563 mBounds.maxExtents.set( getWorldBlockSize(), getWorldBlockSize(), 0.0f ); 564 getMinMaxHeight( &mBounds.minExtents.z, &mBounds.maxExtents.z ); 565 566 // Set our mObjBox to be equal to mBounds 567 if ( mObjBox.maxExtents != mBounds.maxExtents || 568 mObjBox.minExtents != mBounds.minExtents ) 569 { 570 mObjBox = mBounds; 571 resetWorldBox(); 572 } 573} 574 575void TerrainBlock::_onZoningChanged( SceneZoneSpaceManager *zoneManager ) 576{ 577 const SceneManager* sm = getSceneManager(); 578 579 if (mCell == NULL || (sm != NULL && sm->getZoneManager() != NULL && zoneManager != sm->getZoneManager())) 580 return; 581 582 mZoningDirty = true; 583} 584 585void TerrainBlock::setHeight( const Point2I &pos, F32 height ) 586{ 587 U16 ht = floatToFixed( height ); 588 mFile->setHeight( pos.x, pos.y, ht ); 589 590 // Note: We do not update the grid here as this could 591 // be called several times in a loop. We depend on the 592 // caller doing a grid update when he is done. 593} 594 595F32 TerrainBlock::getHeight( const Point2I &pos ) 596{ 597 U16 ht = mFile->getHeight( pos.x, pos.y ); 598 return fixedToFloat( ht ); 599} 600 601void TerrainBlock::updateGridMaterials( const Point2I &minPt, const Point2I &maxPt ) 602{ 603 if ( mCell ) 604 { 605 // Tell the terrain cell that something changed. 606 const RectI gridRect( minPt, maxPt - minPt ); 607 mCell->updateGrid( gridRect, true ); 608 } 609 610 // We mark us as dirty... it will be updated 611 // before the next time we render the terrain. 612 mLayerTexDirty = true; 613 614 // Signal anyone that cares that the opacity was changed. 615 smUpdateSignal.trigger( LayersUpdate, this, minPt, maxPt ); 616} 617 618 619Point2I TerrainBlock::getGridPos( const Point3F &worldPos ) const 620{ 621 Point3F terrainPos = worldPos; 622 getWorldTransform().mulP( terrainPos ); 623 624 F32 squareSize = ( F32 ) getSquareSize(); 625 F32 halfSquareSize = squareSize / 2.0; 626 627 F32 x = ( terrainPos.x + halfSquareSize ) / squareSize; 628 F32 y = ( terrainPos.y + halfSquareSize ) / squareSize; 629 630 Point2I gridPos( ( S32 ) mFloor( x ), ( S32 ) mFloor( y ) ); 631 return gridPos; 632} 633 634void TerrainBlock::updateGrid( const Point2I &minPt, const Point2I &maxPt, bool updateClient ) 635{ 636 // On the client we just signal everyone that the height 637 // map has changed... the server does the actual changes. 638 if ( isClientObject() ) 639 { 640 PROFILE_SCOPE( TerrainBlock_updateGrid_Client ); 641 642 // This depends on the client getting this call 'after' the server. 643 // Which is currently the case. 644 _updateBounds(); 645 mZoningDirty = true; 646 647 smUpdateSignal.trigger( HeightmapUpdate, this, minPt, maxPt ); 648 649 // Tell the terrain cell that the height changed. 650 const RectI gridRect( minPt, maxPt - minPt ); 651 mCell->updateGrid( gridRect ); 652 653 // Rebuild the physics representation. 654 if ( mPhysicsRep ) 655 { 656 // Delay the update by a few milliseconds so 657 // that we're not rebuilding during an active 658 // editing operation. 659 mPhysicsRep->queueCallback( 500, Delegate<void()>( this, &TerrainBlock::_updatePhysics ) ); 660 } 661 662 return; 663 } 664 665 // Now on the server we rebuild the 666 // affected area of the grid map. 667 mFile->updateGrid( minPt, maxPt ); 668 669 // Fix up the bounds. 670 _updateBounds(); 671 672 // Rebuild the physics representation. 673 if ( mPhysicsRep ) 674 { 675 // Delay the update by a few milliseconds so 676 // that we're not rebuilding during an active 677 // editing operation. 678 mPhysicsRep->queueCallback( 500, Delegate<void()>( this, &TerrainBlock::_updatePhysics ) ); 679 } 680 681 // Signal again here for any server side observers. 682 smUpdateSignal.trigger( HeightmapUpdate, this, minPt, maxPt ); 683 684 // If this is a server object and the client update 685 // was requested then try to use the local connection 686 // pointer to do it. 687 if ( updateClient && getClientObject() ) 688 ((TerrainBlock*)getClientObject())->updateGrid( minPt, maxPt, false ); 689} 690 691bool TerrainBlock::getHeight( const Point2F &pos, F32 *height ) const 692{ 693 PROFILE_SCOPE( TerrainBlock_getHeight ); 694 695 F32 invSquareSize = 1.0f / mSquareSize; 696 F32 xp = pos.x * invSquareSize; 697 F32 yp = pos.y * invSquareSize; 698 S32 x = S32(xp); 699 S32 y = S32(yp); 700 xp -= (F32)x; 701 yp -= (F32)y; 702 703 const U32 blockMask = mFile->mSize - 1; 704 705 if ( x & ~blockMask || y & ~blockMask ) 706 return false; 707 708 x &= blockMask; 709 y &= blockMask; 710 711 const TerrainSquare *sq = mFile->findSquare( 0, x, y ); 712 if ( sq->flags & TerrainSquare::Empty ) 713 return false; 714 715 F32 zBottomLeft = fixedToFloat( mFile->getHeight( x, y ) ); 716 F32 zBottomRight = fixedToFloat( mFile->getHeight( x + 1, y ) ); 717 F32 zTopLeft = fixedToFloat( mFile->getHeight( x, y + 1 ) ); 718 F32 zTopRight = fixedToFloat( mFile->getHeight( x + 1, y + 1 ) ); 719 720 if ( sq->flags & TerrainSquare::Split45 ) 721 { 722 if (xp>yp) 723 // bottom half 724 *height = zBottomLeft + xp * (zBottomRight-zBottomLeft) + yp * (zTopRight-zBottomRight); 725 else 726 // top half 727 *height = zBottomLeft + xp * (zTopRight-zTopLeft) + yp * (zTopLeft-zBottomLeft); 728 } 729 else 730 { 731 if (1.0f-xp>yp) 732 // bottom half 733 *height = zBottomRight + (1.0f-xp) * (zBottomLeft-zBottomRight) + yp * (zTopLeft-zBottomLeft); 734 else 735 // top half 736 *height = zBottomRight + (1.0f-xp) * (zTopLeft-zTopRight) + yp * (zTopRight-zBottomRight); 737 } 738 739 return true; 740} 741 742bool TerrainBlock::getNormal( const Point2F &pos, Point3F *normal, bool normalize, bool skipEmpty ) const 743{ 744 PROFILE_SCOPE( TerrainBlock_getNormal ); 745 746 F32 invSquareSize = 1.0f / mSquareSize; 747 F32 xp = pos.x * invSquareSize; 748 F32 yp = pos.y * invSquareSize; 749 S32 x = S32(xp); 750 S32 y = S32(yp); 751 xp -= (F32)x; 752 yp -= (F32)y; 753 754 const U32 blockMask = mFile->mSize - 1; 755 756 if ( x & ~blockMask || y & ~blockMask ) 757 return false; 758 759 x &= blockMask; 760 y &= blockMask; 761 762 const TerrainSquare *sq = mFile->findSquare( 0, x, y ); 763 if ( skipEmpty && sq->flags & TerrainSquare::Empty ) 764 return false; 765 766 F32 zBottomLeft = fixedToFloat( mFile->getHeight( x, y ) ); 767 F32 zBottomRight = fixedToFloat( mFile->getHeight( x + 1, y ) ); 768 F32 zTopLeft = fixedToFloat( mFile->getHeight( x, y + 1 ) ); 769 F32 zTopRight = fixedToFloat( mFile->getHeight( x + 1, y + 1 ) ); 770 771 if ( sq->flags & TerrainSquare::Split45 ) 772 { 773 if (xp>yp) 774 // bottom half 775 normal->set(zBottomLeft-zBottomRight, zBottomRight-zTopRight, mSquareSize); 776 else 777 // top half 778 normal->set(zTopLeft-zTopRight, zBottomLeft-zTopLeft, mSquareSize); 779 } 780 else 781 { 782 if (1.0f-xp>yp) 783 // bottom half 784 normal->set(zBottomLeft-zBottomRight, zBottomLeft-zTopLeft, mSquareSize); 785 else 786 // top half 787 normal->set(zTopLeft-zTopRight, zBottomRight-zTopRight, mSquareSize); 788 } 789 790 if (normalize) 791 normal->normalize(); 792 793 return true; 794} 795 796bool TerrainBlock::getSmoothNormal( const Point2F &pos, 797 Point3F *normal, 798 bool normalize, 799 bool skipEmpty ) const 800{ 801 PROFILE_SCOPE( TerrainBlock_getSmoothNormal ); 802 803 F32 invSquareSize = 1.0f / mSquareSize; 804 F32 xp = pos.x * invSquareSize; 805 F32 yp = pos.y * invSquareSize; 806 S32 x = S32(xp); 807 S32 y = S32(yp); 808 809 const U32 blockMask = mFile->mSize - 1; 810 811 if ( x & ~blockMask || y & ~blockMask ) 812 return false; 813 814 x &= blockMask; 815 y &= blockMask; 816 817 const TerrainSquare *sq = mFile->findSquare( 0, x, y ); 818 if ( skipEmpty && sq->flags & TerrainSquare::Empty ) 819 return false; 820 821 F32 h1 = fixedToFloat( mFile->getHeight( x + 1, y ) ); 822 F32 h2 = fixedToFloat( mFile->getHeight( x, y + 1 ) ); 823 F32 h3 = fixedToFloat( mFile->getHeight( x - 1, y ) ); 824 F32 h4 = fixedToFloat( mFile->getHeight( x, y - 1 ) ); 825 826 normal->set( h3 - h1, h4 - h2, mSquareSize * 2.0f ); 827 828 if ( normalize ) 829 normal->normalize(); 830 831 return true; 832} 833 834bool TerrainBlock::getNormalAndHeight( const Point2F &pos, Point3F *normal, F32 *height, bool normalize ) const 835{ 836 PROFILE_SCOPE( TerrainBlock_getNormalAndHeight ); 837 838 F32 invSquareSize = 1.0f / mSquareSize; 839 F32 xp = pos.x * invSquareSize; 840 F32 yp = pos.y * invSquareSize; 841 S32 x = S32(xp); 842 S32 y = S32(yp); 843 xp -= (F32)x; 844 yp -= (F32)y; 845 846 const U32 blockMask = mFile->mSize - 1; 847 848 if ( x & ~blockMask || y & ~blockMask ) 849 return false; 850 851 x &= blockMask; 852 y &= blockMask; 853 854 const TerrainSquare *sq = mFile->findSquare( 0, x, y ); 855 if ( sq->flags & TerrainSquare::Empty ) 856 return false; 857 858 F32 zBottomLeft = fixedToFloat( mFile->getHeight(x, y) ); 859 F32 zBottomRight = fixedToFloat( mFile->getHeight(x + 1, y) ); 860 F32 zTopLeft = fixedToFloat( mFile->getHeight(x, y + 1) ); 861 F32 zTopRight = fixedToFloat( mFile->getHeight(x + 1, y + 1) ); 862 863 if ( sq->flags & TerrainSquare::Split45 ) 864 { 865 if (xp>yp) 866 { 867 // bottom half 868 normal->set(zBottomLeft-zBottomRight, zBottomRight-zTopRight, mSquareSize); 869 *height = zBottomLeft + xp * (zBottomRight-zBottomLeft) + yp * (zTopRight-zBottomRight); 870 } 871 else 872 { 873 // top half 874 normal->set(zTopLeft-zTopRight, zBottomLeft-zTopLeft, mSquareSize); 875 *height = zBottomLeft + xp * (zTopRight-zTopLeft) + yp * (zTopLeft-zBottomLeft); 876 } 877 } 878 else 879 { 880 if (1.0f-xp>yp) 881 { 882 // bottom half 883 normal->set(zBottomLeft-zBottomRight, zBottomLeft-zTopLeft, mSquareSize); 884 *height = zBottomRight + (1.0f-xp) * (zBottomLeft-zBottomRight) + yp * (zTopLeft-zBottomLeft); 885 } 886 else 887 { 888 // top half 889 normal->set(zTopLeft-zTopRight, zBottomRight-zTopRight, mSquareSize); 890 *height = zBottomRight + (1.0f-xp) * (zTopLeft-zTopRight) + yp * (zTopRight-zBottomRight); 891 } 892 } 893 894 if (normalize) 895 normal->normalize(); 896 897 return true; 898} 899 900 901bool TerrainBlock::getNormalHeightMaterial( const Point2F &pos, 902 Point3F *normal, 903 F32 *height, 904 StringTableEntry &matName ) const 905{ 906 PROFILE_SCOPE( TerrainBlock_getNormalHeightMaterial ); 907 908 F32 invSquareSize = 1.0f / mSquareSize; 909 F32 xp = pos.x * invSquareSize; 910 F32 yp = pos.y * invSquareSize; 911 S32 x = S32(xp); 912 S32 y = S32(yp); 913 S32 xm = S32(mFloor( xp + 0.5f )); 914 S32 ym = S32(mFloor( yp + 0.5f )); 915 xp -= (F32)x; 916 yp -= (F32)y; 917 918 const U32 blockMask = mFile->mSize - 1; 919 920 if ( x & ~blockMask || y & ~blockMask ) 921 return false; 922 923 x &= blockMask; 924 y &= blockMask; 925 926 const TerrainSquare *sq = mFile->findSquare( 0, x, y ); 927 if ( sq->flags & TerrainSquare::Empty ) 928 return false; 929 930 F32 zBottomLeft = fixedToFloat( mFile->getHeight(x, y) ); 931 F32 zBottomRight = fixedToFloat( mFile->getHeight(x + 1, y) ); 932 F32 zTopLeft = fixedToFloat( mFile->getHeight(x, y + 1) ); 933 F32 zTopRight = fixedToFloat( mFile->getHeight(x + 1, y + 1) ); 934 935 matName = mFile->getMaterialName( xm, ym ); 936 937 if ( sq->flags & TerrainSquare::Split45 ) 938 { 939 if (xp>yp) 940 { 941 // bottom half 942 normal->set(zBottomLeft-zBottomRight, zBottomRight-zTopRight, mSquareSize); 943 *height = zBottomLeft + xp * (zBottomRight-zBottomLeft) + yp * (zTopRight-zBottomRight); 944 } 945 else 946 { 947 // top half 948 normal->set(zTopLeft-zTopRight, zBottomLeft-zTopLeft, mSquareSize); 949 *height = zBottomLeft + xp * (zTopRight-zTopLeft) + yp * (zTopLeft-zBottomLeft); 950 } 951 } 952 else 953 { 954 if (1.0f-xp>yp) 955 { 956 // bottom half 957 normal->set(zBottomLeft-zBottomRight, zBottomLeft-zTopLeft, mSquareSize); 958 *height = zBottomRight + (1.0f-xp) * (zBottomLeft-zBottomRight) + yp * (zTopLeft-zBottomLeft); 959 } 960 else 961 { 962 // top half 963 normal->set(zTopLeft-zTopRight, zBottomRight-zTopRight, mSquareSize); 964 *height = zBottomRight + (1.0f-xp) * (zTopLeft-zTopRight) + yp * (zTopRight-zBottomRight); 965 } 966 } 967 968 normal->normalize(); 969 970 return true; 971} 972 973U32 TerrainBlock::getMaterialCount() const 974{ 975 return mFile->mMaterials.size(); 976} 977 978void TerrainBlock::addMaterial( const String &name, U32 insertAt ) 979{ 980 TerrainMaterial *mat = TerrainMaterial::findOrCreate( name ); 981 982 if ( insertAt == -1 ) 983 { 984 mFile->mMaterials.push_back( mat ); 985 mFile->_initMaterialInstMapping(); 986 987 bool isSrv = isServerObject(); 988 989 //now we update our asset 990 if (mTerrainAsset) 991 { 992 StringTableEntry terrMatName = StringTable->insert(name.c_str()); 993 994 AssetQuery* aq = new AssetQuery(); 995 U32 foundCount = AssetDatabase.findAssetType(aq, "TerrainMaterialAsset"); 996 997 for (U32 i = 0; i < foundCount; i++) 998 { 999 TerrainMaterialAsset* terrMatAsset = AssetDatabase.acquireAsset<TerrainMaterialAsset>(aq->mAssetList[i]); 1000 if (terrMatAsset && terrMatAsset->getMaterialDefinitionName() == terrMatName) 1001 { 1002 //Do iterative logic to find the next available slot and write to it with our new mat field 1003 mTerrainAsset->setDataField(StringTable->insert("terrainMaterialAsset"), nullptr, aq->mAssetList[i]); 1004 } 1005 } 1006 } 1007 } 1008 else 1009 { 1010 1011 // TODO: Insert and reindex! 1012 1013 } 1014 1015 mDetailsDirty = true; 1016 mLayerTexDirty = true; 1017} 1018 1019void TerrainBlock::removeMaterial( U32 index ) 1020{ 1021 // Cannot delete if only one layer. 1022 if ( mFile->mMaterials.size() == 1 ) 1023 return; 1024 1025 mFile->mMaterials.erase( index ); 1026 mFile->_initMaterialInstMapping(); 1027 1028 for ( S32 i = 0; i < mFile->mLayerMap.size(); i++ ) 1029 { 1030 if ( mFile->mLayerMap[i] >= index && 1031 mFile->mLayerMap[i] != 0 ) 1032 { 1033 mFile->mLayerMap[i]--; 1034 } 1035 } 1036 1037 mDetailsDirty = true; 1038 mLayerTexDirty = true; 1039} 1040 1041void TerrainBlock::updateMaterial( U32 index, const String &name ) 1042{ 1043 if ( index >= mFile->mMaterials.size() ) 1044 return; 1045 1046 mFile->mMaterials[ index ] = TerrainMaterial::findOrCreate( name ); 1047 mFile->_initMaterialInstMapping(); 1048 1049 mDetailsDirty = true; 1050 mLayerTexDirty = true; 1051} 1052 1053TerrainMaterial* TerrainBlock::getMaterial( U32 index ) const 1054{ 1055 if ( index >= mFile->mMaterials.size() ) 1056 return NULL; 1057 1058 return mFile->mMaterials[ index ]; 1059} 1060 1061void TerrainBlock::deleteAllMaterials() 1062{ 1063 mFile->mMaterials.clear(); 1064 mFile->mMaterialInstMapping.clearMatInstList(); 1065} 1066 1067const char* TerrainBlock::getMaterialName( U32 index ) const 1068{ 1069 if ( index < mFile->mMaterials.size() ) 1070 return mFile->mMaterials[ index ]->getInternalName(); 1071 1072 return NULL; 1073} 1074 1075void TerrainBlock::setLightMap( GBitmap *newLightMap ) 1076{ 1077 SAFE_DELETE( mLightMap ); 1078 mLightMap = newLightMap; 1079 mLightMapTex = NULL; 1080} 1081 1082void TerrainBlock::clearLightMap() 1083{ 1084 if ( !mLightMap ) 1085 mLightMap = new GBitmap( mLightMapSize, mLightMapSize, 0, GFXFormatR8G8B8 ); 1086 1087 mLightMap->fillWhite(); 1088 mLightMapTex = NULL; 1089} 1090 1091GFXTextureObject* TerrainBlock::getLightMapTex() 1092{ 1093 if ( mLightMapTex.isNull() && mLightMap ) 1094 { 1095 mLightMapTex.set( mLightMap, 1096 &GFXStaticTextureProfile, 1097 false, 1098 "TerrainBlock::getLightMapTex()" ); 1099 } 1100 1101 return mLightMapTex; 1102} 1103 1104void TerrainBlock::onEditorEnable() 1105{ 1106} 1107 1108void TerrainBlock::onEditorDisable() 1109{ 1110} 1111 1112bool TerrainBlock::onAdd() 1113{ 1114 if(!Parent::onAdd()) 1115 return false; 1116 1117 Resource<TerrainFile> terr; 1118 1119 if (!mTerrainAsset.isNull()) 1120 { 1121 terr = mTerrainAsset->getTerrainResource(); 1122 1123 if (terr == NULL) 1124 { 1125 if (isClientObject()) 1126 NetConnection::setLastError("Unable to load terrain asset: %s", mTerrainAsset.getAssetId()); 1127 return false; 1128 } 1129 1130 setFile(terr); 1131 } 1132 1133 addToScene(); 1134 1135 _updatePhysics(); 1136 1137 return true; 1138} 1139 1140String TerrainBlock::_getBaseTexCacheFileName() const 1141{ 1142 Torque::Path basePath( mTerrainAsset->getTerrainFilePath() ); 1143 basePath.setFileName( basePath.getFileName() + "_basetex" ); 1144 basePath.setExtension( formatToExtension(mBaseTexFormat) ); 1145 return basePath.getFullPath(); 1146} 1147 1148void TerrainBlock::_rebuildQuadtree() 1149{ 1150 SAFE_DELETE( mCell ); 1151 1152 // Recursively build the cells. 1153 mCell = TerrCell::init( this ); 1154 1155 // Build the shared PrimitiveBuffer. 1156 mCell->createPrimBuffer( &mPrimBuffer ); 1157 deleteZodiacPrimitiveBuffer(); 1158} 1159 1160void TerrainBlock::_updatePhysics() 1161{ 1162 if ( !PHYSICSMGR ) 1163 return; 1164 1165 SAFE_DELETE( mPhysicsRep ); 1166 1167 PhysicsCollision *colShape; 1168 1169 // If we can steal the collision shape from the local server 1170 // object then do so as it saves us alot of cpu time and memory. 1171 // 1172 // TODO: We should move this sharing down into TerrFile where 1173 // it probably belongs. 1174 // 1175 if ( getServerObject() ) 1176 { 1177 TerrainBlock *serverTerrain = (TerrainBlock*)getServerObject(); 1178 colShape = serverTerrain->mPhysicsRep->getColShape(); 1179 } 1180 else 1181 { 1182 // Get empty state of each vert 1183 bool *holes = new bool[ getBlockSize() * getBlockSize() ]; 1184 for ( U32 row = 0; row < getBlockSize(); row++ ) 1185 for ( U32 column = 0; column < getBlockSize(); column++ ) 1186 holes[ row + (column * getBlockSize()) ] = mFile->isEmptyAt( row, column ); 1187 1188 colShape = PHYSICSMGR->createCollision(); 1189 colShape->addHeightfield( mFile->getHeightMap().address(), holes, getBlockSize(), mSquareSize, MatrixF::Identity ); 1190 1191 delete [] holes; 1192 } 1193 1194 PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" ); 1195 mPhysicsRep = PHYSICSMGR->createBody(); 1196 mPhysicsRep->init( colShape, 0, 0, this, world ); 1197 mPhysicsRep->setTransform( getTransform() ); 1198} 1199 1200void TerrainBlock::onRemove() 1201{ 1202 removeFromScene(); 1203 SceneZoneSpaceManager::getZoningChangedSignal().remove( this, &TerrainBlock::_onZoningChanged ); 1204 1205 SAFE_DELETE( mPhysicsRep ); 1206 1207 if ( isClientObject() ) 1208 { 1209 mBaseTex = NULL; 1210 mLayerTex = NULL; 1211 SAFE_DELETE( mBaseMaterial ); 1212 SAFE_DELETE( mDefaultMatInst ); 1213 SAFE_DELETE( mCell ); 1214 mPrimBuffer = NULL; 1215 mBaseShader = NULL; 1216 GFXTextureManager::removeEventDelegate( this, &TerrainBlock::_onTextureEvent ); 1217 MATMGR->getFlushSignal().remove( this, &TerrainBlock::_onFlushMaterials ); 1218 } 1219 1220 Parent::onRemove(); 1221} 1222 1223void TerrainBlock::prepRenderImage( SceneRenderState* state ) 1224{ 1225 PROFILE_SCOPE(TerrainBlock_prepRenderImage); 1226 1227 // If we need to update our cached 1228 // zone state then do it now. 1229 if ( mZoningDirty ) 1230 { 1231 mZoningDirty = false; 1232 mCell->updateZoning( getSceneManager()->getZoneManager() ); 1233 } 1234 1235 _renderBlock( state ); 1236} 1237 1238void TerrainBlock::setTransform(const MatrixF & mat) 1239{ 1240 Parent::setTransform( mat ); 1241 1242 // Update world-space OBBs. 1243 if( mCell ) 1244 { 1245 mCell->updateOBBs(); 1246 mZoningDirty = true; 1247 } 1248 1249 if ( mPhysicsRep ) 1250 mPhysicsRep->setTransform( mat ); 1251 1252 setRenderTransform( mat ); 1253 setMaskBits( TransformMask ); 1254 1255 if(isClientObject()) 1256 smUpdateSignal.trigger( HeightmapUpdate, this, Point2I::Zero, Point2I::Max ); 1257} 1258 1259void TerrainBlock::setScale( const VectorF &scale ) 1260{ 1261 // We disable scaling... we never scale! 1262 Parent::setScale( VectorF::One ); 1263} 1264 1265void TerrainBlock::initPersistFields() 1266{ 1267 addGroup( "Media" ); 1268 1269 addProtectedField("terrainAsset", TypeTerrainAssetId, Offset(mTerrainAssetId, TerrainBlock), 1270 &TerrainBlock::_setTerrainAsset, &defaultProtectedGetFn, 1271 "The source terrain data asset."); 1272 1273 addProtectedField( "terrainFile", TypeStringFilename, Offset( mTerrFileName, TerrainBlock ), 1274 &TerrainBlock::_setTerrainFile, &defaultProtectedGetFn, 1275 "The source terrain data file." ); 1276 1277 endGroup( "Media" ); 1278 1279 addGroup( "Misc" ); 1280 1281 addField( "castShadows", TypeBool, Offset( mCastShadows, TerrainBlock ), 1282 "Allows the terrain to cast shadows onto itself and other objects."); 1283 1284 addProtectedField( "squareSize", TypeF32, Offset( mSquareSize, TerrainBlock ), 1285 &TerrainBlock::_setSquareSize, &defaultProtectedGetFn, 1286 "Indicates the spacing between points on the XY plane on the terrain." ); 1287 1288 addProtectedField( "baseTexSize", TypeS32, Offset( mBaseTexSize, TerrainBlock ), 1289 &TerrainBlock::_setBaseTexSize, &defaultProtectedGetFn, 1290 "Size of base texture size per meter." ); 1291 1292 addProtectedField("baseTexFormat", TYPEID<baseTexFormat>(), Offset(mBaseTexFormat, TerrainBlock), 1293 &TerrainBlock::_setBaseTexFormat, &defaultProtectedGetFn, 1294 ""); 1295 1296 addProtectedField( "lightMapSize", TypeS32, Offset( mLightMapSize, TerrainBlock ), 1297 &TerrainBlock::_setLightMapSize, &defaultProtectedGetFn, 1298 "Light map dimensions in pixels." ); 1299 1300 addField( "screenError", TypeS32, Offset( mScreenError, TerrainBlock ), "Not yet implemented." ); 1301 1302 addField( "updateBasetex", TypeBool, Offset( mUpdateBasetex, TerrainBlock ), "Whether or not to update the Base Texture" ); 1303 1304 endGroup( "Misc" ); 1305 1306 addGroup("AFX"); 1307 addField("ignoreZodiacs", TypeBool, Offset(mIgnoreZodiacs, TerrainBlock)); 1308 endGroup("AFX"); 1309 Parent::initPersistFields(); 1310 1311 removeField( "scale" ); 1312 1313 Con::addVariable( "$TerrainBlock::debugRender", TypeBool, &smDebugRender, "Triggers debug rendering of terrain cells\n\n" 1314 "@ingroup Terrain"); 1315 1316 Con::addVariable( "$pref::Terrain::lodScale", TypeF32, &smLODScale, "A global LOD scale used to tweak the default terrain screen error value.\n\n" 1317 "@ingroup Terrain"); 1318 1319 Con::addVariable( "$pref::Terrain::detailScale", TypeF32, &smDetailScale, "A global detail scale used to tweak the material detail distances.\n\n" 1320 "@ingroup Terrain"); 1321} 1322 1323void TerrainBlock::inspectPostApply() 1324{ 1325 Parent::inspectPostApply(); 1326 setMaskBits( MiscMask ); 1327} 1328 1329U32 TerrainBlock::packUpdate(NetConnection* con, U32 mask, BitStream *stream) 1330{ 1331 U32 retMask = Parent::packUpdate( con, mask, stream ); 1332 1333 if ( stream->writeFlag( mask & TransformMask ) ) 1334 mathWrite( *stream, getTransform() ); 1335 1336 if ( stream->writeFlag( mask & FileMask ) ) 1337 { 1338 S32 idasdasdf = getId(); 1339 stream->write(mCRC); 1340 stream->writeString( mTerrainAsset.getAssetId() ); 1341 } 1342 1343 if ( stream->writeFlag( mask & SizeMask ) ) 1344 stream->write( mSquareSize ); 1345 1346 stream->writeFlag( mCastShadows ); 1347 1348 if ( stream->writeFlag( mask & MaterialMask ) ) 1349 { 1350 stream->write( mBaseTexSize ); 1351 stream->write( mLightMapSize ); 1352 } 1353 1354 stream->writeFlag( mask & HeightMapChangeMask ); 1355 1356 if ( stream->writeFlag( mask & MiscMask ) ) 1357 stream->write( mScreenError ); 1358 1359 stream->writeInt(mBaseTexFormat, 32); 1360 1361 stream->writeFlag(mUpdateBasetex); 1362 stream->writeFlag(mIgnoreZodiacs); 1363 1364 return retMask; 1365} 1366 1367void TerrainBlock::unpackUpdate(NetConnection* con, BitStream *stream) 1368{ 1369 Parent::unpackUpdate( con, stream ); 1370 1371 if ( stream->readFlag() ) // TransformMask 1372 { 1373 MatrixF mat; 1374 mathRead( *stream, &mat ); 1375 setTransform( mat ); 1376 } 1377 1378 if ( stream->readFlag() ) // FileMask 1379 { 1380 stream->read(&mCRC); 1381 1382 char buffer[256]; 1383 stream->readString(buffer); 1384 bool validAsset = setTerrainAsset(StringTable->insert(buffer)); 1385 } 1386 1387 if ( stream->readFlag() ) // SizeMask 1388 stream->read( &mSquareSize ); 1389 1390 mCastShadows = stream->readFlag(); 1391 1392 if ( stream->readFlag() ) // MaterialMask 1393 { 1394 U32 baseTexSize; 1395 stream->read( &baseTexSize ); 1396 if ( mBaseTexSize != baseTexSize ) 1397 { 1398 mBaseTexSize = baseTexSize; 1399 if ( isProperlyAdded() ) 1400 _updateBaseTexture( NONE ); 1401 } 1402 1403 U32 lightMapSize; 1404 stream->read( &lightMapSize ); 1405 if ( mLightMapSize != lightMapSize ) 1406 { 1407 mLightMapSize = lightMapSize; 1408 if ( isProperlyAdded() ) 1409 { 1410 SAFE_DELETE( mLightMap ); 1411 clearLightMap(); 1412 } 1413 } 1414 } 1415 1416 if ( stream->readFlag() && isProperlyAdded() ) // HeightMapChangeMask 1417 { 1418 _updateBounds(); 1419 _rebuildQuadtree(); 1420 _updatePhysics(); 1421 mDetailsDirty = true; 1422 mLayerTexDirty = true; 1423 } 1424 1425 if ( stream->readFlag() ) // MiscMask 1426 stream->read( &mScreenError ); 1427 1428 mBaseTexFormat = (BaseTexFormat)stream->readInt(32); 1429 1430 mUpdateBasetex = stream->readFlag(); 1431 mIgnoreZodiacs = stream->readFlag(); 1432} 1433 1434void TerrainBlock::getMinMaxHeight( F32 *minHeight, F32 *maxHeight ) const 1435{ 1436 // We can get the bound height from the last grid level. 1437 const TerrainSquare *sq = mFile->findSquare( mFile->mGridLevels, 0, 0 ); 1438 *minHeight = fixedToFloat( sq->minHeight ); 1439 *maxHeight = fixedToFloat( sq->maxHeight ); 1440} 1441 1442void TerrainBlock::getUtilizedAssets(Vector<StringTableEntry>* usedAssetsList) 1443{ 1444 if (!mTerrainAsset.isNull()) 1445 usedAssetsList->push_back_unique(mTerrainAsset->getAssetId()); 1446} 1447//----------------------------------------------------------------------------- 1448// Console Methods 1449//----------------------------------------------------------------------------- 1450 1451DefineEngineMethod( TerrainBlock, save, bool, ( const char* fileName),, 1452 "@brief Saves the terrain block's terrain file to the specified file name.\n\n" 1453 1454 "@param fileName Name and path of file to save terrain data to.\n\n" 1455 1456 "@return True if file save was successful, false otherwise") 1457{ 1458 char filename[256]; 1459 dStrcpy(filename,fileName,256); 1460 char *ext = dStrrchr(filename, '.'); 1461 if (!ext || dStricmp(ext, ".ter") != 0) 1462 dStrcat(filename, ".ter", 256); 1463 return static_cast<TerrainBlock*>(object)->save(filename); 1464} 1465 1466DefineEngineMethod(TerrainBlock, saveAsset, bool, (), , 1467 "@brief Saves the terrain block's terrain file to the specified file name.\n\n" 1468 1469 "@param fileName Name and path of file to save terrain data to.\n\n" 1470 1471 "@return True if file save was successful, false otherwise") 1472{ 1473 return static_cast<TerrainBlock*>(object)->saveAsset(); 1474} 1475 1476DefineEngineMethod( TerrainBlock, setMaterialsDirty, void, (),, "") 1477{ 1478 static_cast<TerrainBlock*>(object)->setMaterialsDirty(); 1479} 1480 1481//ConsoleMethod(TerrainBlock, save, bool, 3, 3, "(string fileName) - saves the terrain block's terrain file to the specified file name.") 1482//{ 1483// char filename[256]; 1484// dStrcpy(filename,argv[2],256); 1485// char *ext = dStrrchr(filename, '.'); 1486// if (!ext || dStricmp(ext, ".ter") != 0) 1487// dStrcat(filename, ".ter", 256); 1488// return static_cast<TerrainBlock*>(object)->save(filename); 1489//} 1490 1491ConsoleDocFragment _getTerrainHeight1( 1492 "@brief Gets the terrain height at the specified position\n\n" 1493 "@param position The world space point, minus the z (height) value. Formatted as (\"x y\")\n\n" 1494 "@return Returns the terrain height at the given point as an F32 value.\n\n" 1495 "@ingroup Terrain", 1496 NULL, 1497 "bool getTerrainHeight( Point2I position );" 1498); 1499ConsoleDocFragment _getTerrainHeight2( 1500 "@brief Gets the terrain height at the specified position\n\n" 1501 "@param x The X coordinate in world space\n" 1502 "@param y The Y coordinate in world space\n\n" 1503 "@return Returns the terrain height at the given point as an F32 value.\n\n" 1504 "@ingroup Terrain", 1505 NULL, 1506 "bool getTerrainHeight( F32 x, F32 y);" 1507); 1508 1509DefineEngineFunction( getTerrainHeight, F32, (const char* ptOrX, const char* y), (""), "(Point2 pos) - gets the terrain height at the specified position." 1510 "@param pos The world space point, minus the z (height) value\n Can be formatted as either (\"x y\") or (x,y)\n" 1511 "@return Returns the terrain height at the given point as an F32 value.\n" 1512 "@hide") 1513{ 1514 F32 height = 0.0f; 1515 1516 Point2F pos; 1517 if(!String::isEmpty(ptOrX) && String::isEmpty(y)) 1518 dSscanf(ptOrX, "%f %f", &pos.x, &pos.y); 1519 else if(!String::isEmpty(ptOrX) && !String::isEmpty(y)) 1520 { 1521 pos.x = dAtof(ptOrX); 1522 pos.y = dAtof(y); 1523 } 1524 1525 TerrainBlock * terrain = getTerrainUnderWorldPoint(Point3F(pos.x, pos.y, 5000.0f)); 1526 if(terrain && terrain->isServerObject()) 1527 { 1528 Point3F offset; 1529 terrain->getTransform().getColumn(3, &offset); 1530 pos -= Point2F(offset.x, offset.y); 1531 terrain->getHeight(pos, &height); 1532 } 1533 return height; 1534} 1535 1536ConsoleDocFragment _getTerrainHeightBelowPosition1( 1537 "@brief Takes a world point and find the \"highest\" terrain underneath it\n\n" 1538 "@param position The world space point, minus the z (height) value. Formatted as (\"x y\")\n\n" 1539 "@return Returns the closest terrain height below the given point as an F32 value.\n\n" 1540 "@ingroup Terrain", 1541 NULL, 1542 "bool getTerrainHeightBelowPosition( Point2I position );" 1543); 1544ConsoleDocFragment _getTerrainHeightBelowPosition2( 1545 "@brief Takes a world point and find the \"highest\" terrain underneath it\n\n" 1546 "@param x The X coordinate in world space\n" 1547 "@param y The Y coordinate in world space\n\n" 1548 "@return Returns the closest terrain height below the given point as an F32 value.\n\n" 1549 "@ingroup Terrain", 1550 NULL, 1551 "bool getTerrainHeightBelowPosition( F32 x, F32 y);" 1552); 1553 1554DefineEngineFunction( getTerrainHeightBelowPosition, F32, (const char* ptOrX, const char* y, const char* z), ("", ""), 1555 "(Point3F pos) - gets the terrain height at the specified position." 1556 "@param pos The world space point. Can be formatted as either (\"x y z\") or (x,y,z)\n" 1557 "@note This function is useful if you simply want to grab the terrain height underneath an object.\n" 1558 "@return Returns the terrain height at the given point as an F32 value.\n" 1559 "@hide") 1560{ 1561 F32 height = 0.0f; 1562 1563 Point3F pos; 1564 if(!String::isEmpty(ptOrX) && String::isEmpty(y) && String::isEmpty(z)) 1565 dSscanf(ptOrX, "%f %f %f", &pos.x, &pos.y, &pos.z); 1566 else if(!String::isEmpty(ptOrX) && !String::isEmpty(y) && !String::isEmpty(z)) 1567 { 1568 pos.x = dAtof(ptOrX); 1569 pos.y = dAtof(y); 1570 pos.z = dAtof(z); 1571 } 1572 1573 TerrainBlock * terrain = getTerrainUnderWorldPoint(pos); 1574 1575 Point2F nohghtPos(pos.x, pos.y); 1576 1577 if(terrain) 1578 { 1579 if(terrain->isServerObject()) 1580 { 1581 Point3F offset; 1582 terrain->getTransform().getColumn(3, &offset); 1583 nohghtPos -= Point2F(offset.x, offset.y); 1584 terrain->getHeight(nohghtPos, &height); 1585 } 1586 } 1587 1588 return height; 1589} 1590const U16* TerrainBlock::getZodiacPrimitiveBuffer() 1591{ 1592 if (!zode_primBuffer && !mIgnoreZodiacs) 1593 TerrCell::createZodiacPrimBuffer(&zode_primBuffer); 1594 return zode_primBuffer; 1595} 1596 1597void TerrainBlock::deleteZodiacPrimitiveBuffer() 1598{ 1599 if (zode_primBuffer != 0) 1600 { 1601 delete [] zode_primBuffer; 1602 zode_primBuffer = 0; 1603 } 1604} 1605 1606