/**
 * @file llsurface.h
 * @brief Description of LLSurface class
 *
 * $LicenseInfo:firstyear=2000&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#ifndef LL_LLSURFACE_H
#define LL_LLSURFACE_H

//#include "vmath.h"
#include "v3math.h"
#include "v3dmath.h"
#include "v4math.h"
#include "m3math.h"
#include "m4math.h"
#include "llquaternion.h"

#include "v4coloru.h"
#include "v4color.h"

#include "llvowater.h"
#include "llpatchvertexarray.h"
#include "llviewertexture.h"

class LLTimer;
class LLUUID;
class LLAgent;

static const U8 NO_EDGE    = 0x00;
static const U8 EAST_EDGE  = 0x01;
static const U8 NORTH_EDGE = 0x02;
static const U8 WEST_EDGE  = 0x04;
static const U8 SOUTH_EDGE = 0x08;

static const S32 ONE_MORE_THAN_NEIGHBOR = 1;
static const S32 EQUAL_TO_NEIGHBOR      = 0;
static const S32 ONE_LESS_THAN_NEIGHBOR = -1;

const S32 ABOVE_WATERLINE_ALPHA = 32;  // The alpha of water when the land elevation is above the waterline.

class LLViewerRegion;
class LLSurfacePatch;
class LLBitPack;
class LLGroupHeader;

class LLSurface
{
public:
    LLSurface(U32 type, LLViewerRegion *regionp = NULL);
    virtual ~LLSurface();

    static void initClasses(); // Do class initialization for LLSurface and its child classes.

    void create(const S32 surface_grid_width,
                const S32 surface_patch_width,
                const LLVector3d &origin_global,
                const F32 width);   // Allocates and initializes surface

    void setRegion(LLViewerRegion *regionp);

    void setOriginGlobal(const LLVector3d &origin_global);

    void connectNeighbor(LLSurface *neighborp, U32 direction);
    void disconnectNeighbor(LLSurface *neighborp);
    void disconnectAllNeighbors();

    virtual void decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, bool b_large_patch);
    virtual void updatePatchVisibilities(LLAgent &agent);

    inline F32 getZ(const U32 k) const              { return mSurfaceZ[k]; }
    inline F32 getZ(const S32 i, const S32 j) const { return mSurfaceZ[i + j*mGridsPerEdge]; }

    LLVector3 getOriginAgent() const;
    const LLVector3d &getOriginGlobal() const;
    F32 getMetersPerGrid() const;
    S32 getGridsPerEdge() const;
    S32 getPatchesPerEdge() const;
    S32 getGridsPerPatchEdge() const;
    U32 getRenderStride(const U32 render_level) const;
    U32 getRenderLevel(const U32 render_stride) const;

    // Returns the height of the surface immediately above (or below) location,
    // or if location is not above surface returns zero.
    F32 resolveHeightRegion(const F32 x, const F32 y) const;
    F32 resolveHeightRegion(const LLVector3 &location) const
            { return resolveHeightRegion( location.mV[VX], location.mV[VY] ); }
    F32 resolveHeightGlobal(const LLVector3d &position_global) const;
    LLVector3 resolveNormalGlobal(const LLVector3d& v) const;               //  Returns normal to surface

    LLSurfacePatch *resolvePatchRegion(const F32 x, const F32 y) const;
    LLSurfacePatch *resolvePatchRegion(const LLVector3 &position_region) const;
    LLSurfacePatch *resolvePatchGlobal(const LLVector3d &position_global) const;
    LLSurfacePatch *getPatch(const S32 x, const S32 y) const;

    // Update methods (called during idle, normally)
    template<bool PBR>
    bool idleUpdate(F32 max_update_time);

    bool containsPosition(const LLVector3 &position);

    void moveZ(const S32 x, const S32 y, const F32 delta);

    LLViewerRegion *getRegion() const               { return mRegionp; }

    F32 getMinZ() const                             { return mMinZ; }
    F32 getMaxZ() const                             { return mMaxZ; }

    void setWaterHeight(F32 height);
    F32 getWaterHeight() const;

    LLViewerTexture *getSTexture();

    bool hasZData() const                           { return mHasZData; }

    void dirtyAllPatches(); // Use this to dirty all patches when changing terrain parameters

    void dirtySurfacePatch(LLSurfacePatch *patchp);
    LLVOWater *getWaterObj()                        { return mWaterObjp; }

    static void setTextureSize(const S32 texture_size);

    friend class LLSurfacePatch;
    friend std::ostream& operator<<(std::ostream &s, const LLSurface &S);

    void getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegions );
    void getNeighboringRegionsStatus( std::vector<S32>& regions );

public:
    // Number of grid points on one side of a region, including +1 buffer for
    // north and east edge.
    S32 mGridsPerEdge;

    F32 mOOGridsPerEdge;            // Inverse of grids per edge

    S32 mPatchesPerEdge;            // Number of patches on one side of a region
    S32 mNumberOfPatches;           // Total number of patches


    // Each surface points at 8 neighbors (or NULL)
    // +---+---+---+
    // |NW | N | NE|
    // +---+---+---+
    // | W | 0 | E |
    // +---+---+---+
    // |SW | S | SE|
    // +---+---+---+
    LLSurface *mNeighbors[8]; // Adjacent patches

    U32 mType;              // Useful for identifying derived classes

    F32 mDetailTextureScale;    //  Number of times to repeat detail texture across this surface

protected:
    void createSTexture();
    void initTextures();

    void createPatchData();     // Allocates memory for patches.
    void destroyPatchData();    // Deallocates memory for patches.

protected:
    LLVector3d  mOriginGlobal;      // In absolute frame
    LLSurfacePatch *mPatchList;     // Array of all patches

    // Array of grid data, mGridsPerEdge * mGridsPerEdge
    F32 *mSurfaceZ;

    // Array of grid normals, mGridsPerEdge * mGridsPerEdge
    LLVector3 *mNorm;

    std::set<LLSurfacePatch *> mDirtyPatchList;


    // The textures should never be directly initialized - use the setter methods!
    LLPointer<LLViewerTexture> mSTexturep;      // Texture for surface

    LLPointer<LLVOWater>    mWaterObjp;

    // When we want multiple cameras we'll need one of each these for each camera
    S32 mVisiblePatchCount;

    U32         mGridsPerPatchEdge;         // Number of grid points on a side of a patch
    F32         mMetersPerGrid;             // Converts (i,j) indecies to distance
    F32         mMetersPerEdge;             // = mMetersPerGrid * (mGridsPerEdge-1)

    LLPatchVertexArray mPVArray;

    bool        mHasZData;              // We've received any patch data for this surface.
    F32         mMinZ;                  // min z for this region (during the session)
    F32         mMaxZ;                  // max z for this region (during the session)

    S32         mSurfacePatchUpdateCount;                   // Number of frames since last update.

private:
    LLViewerRegion *mRegionp; // Patch whose coordinate system this surface is using.
    static S32  sTextureSize;               // Size of the surface texture
};

extern template bool LLSurface::idleUpdate</*PBR=*/false>(F32 max_update_time);
extern template bool LLSurface::idleUpdate</*PBR=*/true>(F32 max_update_time);



//        .   __.
//     Z /|\   /| Y                                 North
//        |   /
//        |  /             |<----------------- mGridsPerSurfaceEdge --------------->|
//        | /              __________________________________________________________
//        |/______\ X     /_______________________________________________________  /
//                /      /      /      /      /      /      /      /M*M-2 /M*M-1 / /
//                      /______/______/______/______/______/______/______/______/ /
//                     /      /      /      /      /      /      /      /      / /
//                    /______/______/______/______/______/______/______/______/ /
//                   /      /      /      /      /      /      /      /      / /
//                  /______/______/______/______/______/______/______/______/ /
//      West       /      /      /      /      /      /      /      /      / /
//                /______/______/______/______/______/______/______/______/ /     East
//               /...   /      /      /      /      /      /      /      / /
//              /______/______/______/______/______/______/______/______/ /
//       _.    / 2M   /      /      /      /      /      /      /      / /
//       /|   /______/______/______/______/______/______/______/______/ /
//      /    / M    / M+1  / M+2  / ...  /      /      /      / 2M-1 / /
//     j    /______/______/______/______/______/______/______/______/ /
//         / 0    / 1    / 2    / ...  /      /      /      / M-1  / /
//        /______/______/______/______/______/______/______/______/_/
//                                South             |<-L->|
//             i -->
//
// where M = mSurfPatchWidth
// and L = mPatchGridWidth
//
// Notice that mGridsPerSurfaceEdge = a power of two + 1
// This provides a buffer on the east and north edges that will allow us to
// fill the cracks between adjacent surfaces when rendering.
#endif