| 741 | } |
| 742 | |
| 743 | bool TerrainBlock::getNormal( const Point2F &pos, Point3F *normal, bool normalize, bool skipEmpty ) const |
| 744 | { |
| 745 | PROFILE_SCOPE( TerrainBlock_getNormal ); |
| 746 | |
| 747 | F32 invSquareSize = 1.0f / mSquareSize; |
| 748 | F32 xp = pos.x * invSquareSize; |
| 749 | F32 yp = pos.y * invSquareSize; |
| 750 | S32 x = S32(xp); |
| 751 | S32 y = S32(yp); |
| 752 | xp -= (F32)x; |
| 753 | yp -= (F32)y; |
| 754 | |
| 755 | const U32 blockMask = mFile->mSize - 1; |
| 756 | |
| 757 | if ( x & ~blockMask || y & ~blockMask ) |
| 758 | return false; |
| 759 | |
| 760 | x &= blockMask; |
| 761 | y &= blockMask; |
| 762 | |
| 763 | const TerrainSquare *sq = mFile->findSquare( 0, x, y ); |
| 764 | if ( skipEmpty && sq->flags & TerrainSquare::Empty ) |
| 765 | return false; |
| 766 | |
| 767 | F32 zBottomLeft = fixedToFloat( mFile->getHeight( x, y ) ); |
| 768 | F32 zBottomRight = fixedToFloat( mFile->getHeight( x + 1, y ) ); |
| 769 | F32 zTopLeft = fixedToFloat( mFile->getHeight( x, y + 1 ) ); |
| 770 | F32 zTopRight = fixedToFloat( mFile->getHeight( x + 1, y + 1 ) ); |
| 771 | |
| 772 | if ( sq->flags & TerrainSquare::Split45 ) |
| 773 | { |
| 774 | if (xp>yp) |
| 775 | // bottom half |
| 776 | normal->set(zBottomLeft-zBottomRight, zBottomRight-zTopRight, mSquareSize); |
| 777 | else |
| 778 | // top half |
| 779 | normal->set(zTopLeft-zTopRight, zBottomLeft-zTopLeft, mSquareSize); |
| 780 | } |
| 781 | else |
| 782 | { |
| 783 | if (1.0f-xp>yp) |
| 784 | // bottom half |
| 785 | normal->set(zBottomLeft-zBottomRight, zBottomLeft-zTopLeft, mSquareSize); |
| 786 | else |
| 787 | // top half |
| 788 | normal->set(zTopLeft-zTopRight, zBottomRight-zTopRight, mSquareSize); |
| 789 | } |
| 790 | |
| 791 | if (normalize) |
| 792 | normal->normalize(); |
| 793 | |
| 794 | return true; |
| 795 | } |
| 796 | |
| 797 | bool TerrainBlock::getSmoothNormal( const Point2F &pos, |
| 798 | Point3F *normal, |
no test coverage detected