PageRenderTime 94ms CodeModel.GetById 12ms app.highlight 74ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llvosurfacepatch.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1108 lines | 846 code | 176 blank | 86 comment | 98 complexity | b05355290d673137284204883a987731 MD5 | raw file
   1/** 
   2 * @file llvosurfacepatch.cpp
   3 * @brief Viewer-object derived "surface patch", which is a piece of terrain
   4 *
   5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28
  29#include "llvosurfacepatch.h"
  30
  31#include "lldrawpoolterrain.h"
  32
  33#include "lldrawable.h"
  34#include "llface.h"
  35#include "llprimitive.h"
  36#include "llsky.h"
  37#include "llsurfacepatch.h"
  38#include "llsurface.h"
  39#include "llviewerobjectlist.h"
  40#include "llviewerregion.h"
  41#include "llvlcomposition.h"
  42#include "llvovolume.h"
  43#include "pipeline.h"
  44#include "llspatialpartition.h"
  45
  46F32 LLVOSurfacePatch::sLODFactor = 1.f;
  47
  48//============================================================================
  49
  50class LLVertexBufferTerrain : public LLVertexBuffer
  51{
  52public:
  53	LLVertexBufferTerrain() :
  54		LLVertexBuffer(MAP_VERTEX | MAP_NORMAL | MAP_TEXCOORD0 | MAP_TEXCOORD1 | MAP_COLOR, GL_DYNAMIC_DRAW_ARB)
  55	{
  56		//texture coordinates 2 and 3 exist, but use the same data as texture coordinate 1
  57	};
  58
  59	// virtual
  60	void setupVertexBuffer(U32 data_mask)
  61	{	
  62		if (LLGLSLShader::sNoFixedFunction)
  63		{ //just use default if shaders are in play
  64			LLVertexBuffer::setupVertexBuffer(data_mask & ~(MAP_TEXCOORD2 | MAP_TEXCOORD3));
  65			return;
  66		}
  67
  68		U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
  69
  70		//assume tex coords 2 and 3 are present
  71		U32 type_mask = mTypeMask | MAP_TEXCOORD2 | MAP_TEXCOORD3;
  72
  73		if ((data_mask & type_mask) != data_mask)
  74		{
  75			llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
  76		}
  77
  78		if (data_mask & MAP_NORMAL)
  79		{
  80			glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
  81		}
  82		if (data_mask & MAP_TEXCOORD3)
  83		{ //substitute tex coord 0 for tex coord 3
  84			glClientActiveTextureARB(GL_TEXTURE3_ARB);
  85			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
  86			glClientActiveTextureARB(GL_TEXTURE0_ARB);
  87		}
  88		if (data_mask & MAP_TEXCOORD2)
  89		{ //substitute tex coord 0 for tex coord 2
  90			glClientActiveTextureARB(GL_TEXTURE2_ARB);
  91			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
  92			glClientActiveTextureARB(GL_TEXTURE0_ARB);
  93		}
  94		if (data_mask & MAP_TEXCOORD1)
  95		{
  96			glClientActiveTextureARB(GL_TEXTURE1_ARB);
  97			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
  98			glClientActiveTextureARB(GL_TEXTURE0_ARB);
  99		}
 100		if (data_mask & MAP_BINORMAL)
 101		{
 102			glClientActiveTextureARB(GL_TEXTURE2_ARB);
 103			glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
 104			glClientActiveTextureARB(GL_TEXTURE0_ARB);
 105		}
 106		if (data_mask & MAP_TEXCOORD0)
 107		{
 108			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
 109		}
 110		if (data_mask & MAP_COLOR)
 111		{
 112			glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
 113		}
 114		
 115		if (data_mask & MAP_VERTEX)
 116		{
 117			glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
 118		}
 119	}
 120};
 121
 122//============================================================================
 123
 124LLVOSurfacePatch::LLVOSurfacePatch(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 125	:	LLStaticViewerObject(id, pcode, regionp),
 126		mDirtiedPatch(FALSE),
 127		mPool(NULL),
 128		mBaseComp(0),
 129		mPatchp(NULL),
 130		mDirtyTexture(FALSE),
 131		mDirtyTerrain(FALSE),
 132		mLastNorthStride(0),
 133		mLastEastStride(0),
 134		mLastStride(0),
 135		mLastLength(0)
 136{
 137	// Terrain must draw during selection passes so it can block objects behind it.
 138	mbCanSelect = TRUE;
 139	setScale(LLVector3(16.f, 16.f, 16.f)); // Hack for setting scale for bounding boxes/visibility.
 140}
 141
 142
 143LLVOSurfacePatch::~LLVOSurfacePatch()
 144{
 145	mPatchp = NULL;
 146}
 147
 148
 149void LLVOSurfacePatch::markDead()
 150{
 151	if (mPatchp)
 152	{
 153		mPatchp->clearVObj();
 154		mPatchp = NULL;
 155	}
 156	LLViewerObject::markDead();
 157}
 158
 159
 160BOOL LLVOSurfacePatch::isActive() const
 161{
 162	return FALSE;
 163}
 164
 165
 166void LLVOSurfacePatch::setPixelAreaAndAngle(LLAgent &agent)
 167{
 168	mAppAngle = 50;
 169	mPixelArea = 500*500;
 170}
 171
 172
 173void LLVOSurfacePatch::updateTextures()
 174{
 175}
 176
 177
 178LLFacePool *LLVOSurfacePatch::getPool()
 179{
 180	mPool = (LLDrawPoolTerrain*) gPipeline.getPool(LLDrawPool::POOL_TERRAIN, mPatchp->getSurface()->getSTexture());
 181
 182	return mPool;
 183}
 184
 185
 186LLDrawable *LLVOSurfacePatch::createDrawable(LLPipeline *pipeline)
 187{
 188	pipeline->allocDrawable(this);
 189
 190	mDrawable->setRenderType(LLPipeline::RENDER_TYPE_TERRAIN);
 191	
 192	mBaseComp = llfloor(mPatchp->getMinComposition());
 193	S32 min_comp, max_comp, range;
 194	min_comp = llfloor(mPatchp->getMinComposition());
 195	max_comp = llceil(mPatchp->getMaxComposition());
 196	range = (max_comp - min_comp);
 197	range++;
 198	if (range > 3)
 199	{
 200		if ((mPatchp->getMinComposition() - min_comp) > (max_comp - mPatchp->getMaxComposition()))
 201		{
 202			// The top side runs over more
 203			mBaseComp++;
 204		}
 205		range = 3;
 206	}
 207
 208	LLFacePool *poolp = getPool();
 209
 210	mDrawable->addFace(poolp, NULL);
 211
 212	return mDrawable;
 213}
 214
 215static LLFastTimer::DeclareTimer FTM_UPDATE_TERRAIN("Update Terrain");
 216
 217void LLVOSurfacePatch::updateGL()
 218{
 219	if (mPatchp)
 220	{
 221		mPatchp->updateGL();
 222	}
 223}
 224
 225BOOL LLVOSurfacePatch::updateGeometry(LLDrawable *drawable)
 226{
 227	LLFastTimer ftm(FTM_UPDATE_TERRAIN);
 228
 229	dirtySpatialGroup(TRUE);
 230	
 231	S32 min_comp, max_comp, range;
 232	min_comp = lltrunc(mPatchp->getMinComposition());
 233	max_comp = lltrunc(ceil(mPatchp->getMaxComposition()));
 234	range = (max_comp - min_comp);
 235	range++;
 236	S32 new_base_comp = lltrunc(mPatchp->getMinComposition());
 237	if (range > 3)
 238	{
 239		if ((mPatchp->getMinComposition() - min_comp) > (max_comp - mPatchp->getMaxComposition()))
 240		{
 241			// The top side runs over more
 242			new_base_comp++;
 243		}
 244		range = 3;
 245	}
 246
 247	// Pick the two closest detail textures for this patch...
 248	// Then create the draw pool for it.
 249	// Actually, should get the average composition instead of the center.
 250	mBaseComp = new_base_comp;
 251
 252	//////////////////////////
 253	//
 254	// Figure out the strides
 255	//
 256	//
 257
 258	U32 patch_width, render_stride, north_stride, east_stride, length;
 259	render_stride = mPatchp->getRenderStride();
 260	patch_width = mPatchp->getSurface()->getGridsPerPatchEdge();
 261
 262	length = patch_width / render_stride;
 263
 264	if (mPatchp->getNeighborPatch(NORTH))
 265	{
 266		north_stride = mPatchp->getNeighborPatch(NORTH)->getRenderStride();
 267	}
 268	else
 269	{
 270		north_stride = render_stride;
 271	}
 272
 273	if (mPatchp->getNeighborPatch(EAST))
 274	{
 275		east_stride = mPatchp->getNeighborPatch(EAST)->getRenderStride();
 276	}
 277	else
 278	{
 279		east_stride = render_stride;
 280	}
 281
 282	mLastLength = length;
 283	mLastStride = render_stride;
 284	mLastNorthStride = north_stride;
 285	mLastEastStride = east_stride;
 286
 287	return TRUE;
 288}
 289
 290void LLVOSurfacePatch::updateFaceSize(S32 idx)
 291{
 292	if (idx != 0)
 293	{
 294		llwarns << "Terrain partition requested invalid face!!!" << llendl;
 295		return;
 296	}
 297
 298	LLFace* facep = mDrawable->getFace(idx);
 299
 300	S32 num_vertices = 0;
 301	S32 num_indices = 0;
 302	
 303	if (mLastStride)
 304	{
 305		getGeomSizesMain(mLastStride, num_vertices, num_indices);
 306		getGeomSizesNorth(mLastStride, mLastNorthStride, num_vertices, num_indices);
 307		getGeomSizesEast(mLastStride, mLastEastStride, num_vertices, num_indices);
 308	}
 309
 310	facep->setSize(num_vertices, num_indices);	
 311}
 312
 313BOOL LLVOSurfacePatch::updateLOD()
 314{
 315	return TRUE;
 316}
 317
 318void LLVOSurfacePatch::getGeometry(LLStrider<LLVector3> &verticesp,
 319								LLStrider<LLVector3> &normalsp,
 320								LLStrider<LLVector2> &texCoords0p,
 321								LLStrider<LLVector2> &texCoords1p,
 322								LLStrider<U16> &indicesp)
 323{
 324	LLFace* facep = mDrawable->getFace(0);
 325
 326	U32 index_offset = facep->getGeomIndex();
 327
 328	updateMainGeometry(facep, 
 329					verticesp,
 330					normalsp,
 331					texCoords0p,
 332					texCoords1p,
 333					indicesp,
 334					index_offset);
 335	updateNorthGeometry(facep, 
 336						verticesp,
 337						normalsp,
 338						texCoords0p,
 339						texCoords1p,
 340						indicesp,
 341						index_offset);
 342	updateEastGeometry(facep, 
 343						verticesp,
 344						normalsp,
 345						texCoords0p,
 346						texCoords1p,
 347						indicesp,
 348						index_offset);
 349}
 350
 351void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,
 352										LLStrider<LLVector3> &verticesp,
 353										LLStrider<LLVector3> &normalsp,
 354										LLStrider<LLVector2> &texCoords0p,
 355										LLStrider<LLVector2> &texCoords1p,
 356										LLStrider<U16> &indicesp,
 357										U32 &index_offset)
 358{
 359	S32 i, j, x, y;
 360
 361	U32 patch_size, render_stride;
 362	S32 num_vertices, num_indices;
 363	U32 index;
 364
 365	llassert(mLastStride > 0);
 366
 367	render_stride = mLastStride;
 368	patch_size = mPatchp->getSurface()->getGridsPerPatchEdge();
 369	S32 vert_size = patch_size / render_stride;
 370
 371	///////////////////////////
 372	//
 373	// Render the main patch
 374	//
 375	//
 376
 377	num_vertices = 0;
 378	num_indices = 0;
 379	// First, figure out how many vertices we need...
 380	getGeomSizesMain(render_stride, num_vertices, num_indices);
 381
 382	if (num_vertices > 0)
 383	{
 384		facep->mCenterAgent = mPatchp->getPointAgent(8, 8);
 385
 386		// Generate patch points first
 387		for (j = 0; j < vert_size; j++)
 388		{
 389			for (i = 0; i < vert_size; i++)
 390			{
 391				x = i * render_stride;
 392				y = j * render_stride;
 393				mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
 394				verticesp++;
 395				normalsp++;
 396				texCoords0p++;
 397				texCoords1p++;
 398			}
 399		}
 400
 401		for (j = 0; j < (vert_size - 1); j++)
 402		{
 403			if (j % 2)
 404			{
 405				for (i = (vert_size - 1); i > 0; i--)
 406				{
 407					index = (i - 1)+ j*vert_size;
 408					*(indicesp++) = index_offset + index;
 409
 410					index = i + (j+1)*vert_size;
 411					*(indicesp++) = index_offset + index;
 412
 413					index = (i - 1) + (j+1)*vert_size;
 414					*(indicesp++) = index_offset + index;
 415
 416					index = (i - 1) + j*vert_size;
 417					*(indicesp++) = index_offset + index;
 418
 419					index = i + j*vert_size;
 420					*(indicesp++) = index_offset + index;
 421
 422					index = i + (j+1)*vert_size;
 423					*(indicesp++) = index_offset + index;
 424				}
 425			}
 426			else
 427			{
 428				for (i = 0; i < (vert_size - 1); i++)
 429				{
 430					index = i + j*vert_size;
 431					*(indicesp++) = index_offset + index;
 432
 433					index = (i + 1) + (j+1)*vert_size;
 434					*(indicesp++) = index_offset + index;
 435
 436					index = i + (j+1)*vert_size;
 437					*(indicesp++) = index_offset + index;
 438
 439					index = i + j*vert_size;
 440					*(indicesp++) = index_offset + index;
 441
 442					index = (i + 1) + j*vert_size;
 443					*(indicesp++) = index_offset + index;
 444
 445					index = (i + 1) + (j + 1)*vert_size;
 446					*(indicesp++) = index_offset + index;
 447				}
 448			}
 449		}
 450	}
 451	index_offset += num_vertices;
 452}
 453
 454
 455void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
 456										LLStrider<LLVector3> &verticesp,
 457										LLStrider<LLVector3> &normalsp,
 458										LLStrider<LLVector2> &texCoords0p,
 459										LLStrider<LLVector2> &texCoords1p,
 460										LLStrider<U16> &indicesp,
 461										U32 &index_offset)
 462{
 463	S32 vertex_count = 0;
 464	S32 i, x, y;
 465
 466	S32 num_vertices, num_indices;
 467
 468	U32 render_stride = mLastStride;
 469	S32 patch_size = mPatchp->getSurface()->getGridsPerPatchEdge();
 470	S32 length = patch_size / render_stride;
 471	S32 half_length = length / 2;
 472	U32 north_stride = mLastNorthStride;
 473	
 474	///////////////////////////
 475	//
 476	// Render the north strip
 477	//
 478	//
 479
 480	// Stride lengths are the same
 481	if (north_stride == render_stride)
 482	{
 483		num_vertices = 2 * length + 1;
 484		num_indices = length * 6 - 3;
 485
 486		facep->mCenterAgent = (mPatchp->getPointAgent(8, 15) + mPatchp->getPointAgent(8, 16))*0.5f;
 487
 488		// Main patch
 489		for (i = 0; i < length; i++)
 490		{
 491			x = i * render_stride;
 492			y = 16 - render_stride;
 493
 494			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
 495			verticesp++;
 496			normalsp++;
 497			texCoords0p++;
 498			texCoords1p++;
 499			vertex_count++;
 500		}
 501
 502		// North patch
 503		for (i = 0; i <= length; i++)
 504		{
 505			x = i * render_stride;
 506			y = 16;
 507			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
 508			verticesp++;
 509			normalsp++;
 510			texCoords0p++;
 511			texCoords1p++;
 512			vertex_count++;
 513		}
 514
 515
 516		for (i = 0; i < length; i++)
 517		{
 518			// Generate indices
 519			*(indicesp++) = index_offset + i;
 520			*(indicesp++) = index_offset + length + i + 1;
 521			*(indicesp++) = index_offset + length + i;
 522
 523			if (i != length - 1)
 524			{
 525				*(indicesp++) = index_offset + i;
 526				*(indicesp++) = index_offset + i + 1;
 527				*(indicesp++) = index_offset + length + i + 1;
 528			}
 529		}
 530	}
 531	else if (north_stride > render_stride)
 532	{
 533		// North stride is longer (has less vertices)
 534		num_vertices = length + length/2 + 1;
 535		num_indices = half_length*9 - 3;
 536
 537		facep->mCenterAgent = (mPatchp->getPointAgent(7, 15) + mPatchp->getPointAgent(8, 16))*0.5f;
 538
 539		// Iterate through this patch's points
 540		for (i = 0; i < length; i++)
 541		{
 542			x = i * render_stride;
 543			y = 16 - render_stride;
 544
 545			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
 546			verticesp++;
 547			normalsp++;
 548			texCoords0p++;
 549			texCoords1p++;
 550			vertex_count++;
 551		}
 552
 553		// Iterate through the north patch's points
 554		for (i = 0; i <= length; i+=2)
 555		{
 556			x = i * render_stride;
 557			y = 16;
 558
 559			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
 560			verticesp++;
 561			normalsp++;
 562			texCoords0p++;
 563			texCoords1p++;
 564			vertex_count++;
 565		}
 566
 567
 568		for (i = 0; i < length; i++)
 569		{
 570			if (!(i % 2))
 571			{
 572				*(indicesp++) = index_offset + i;
 573				*(indicesp++) = index_offset + i + 1;
 574				*(indicesp++) = index_offset + length + (i/2);
 575
 576				*(indicesp++) = index_offset + i + 1;
 577				*(indicesp++) = index_offset + length + (i/2) + 1;
 578				*(indicesp++) = index_offset + length + (i/2);
 579			}
 580			else if (i < (length - 1))
 581			{
 582				*(indicesp++) = index_offset + i;
 583				*(indicesp++) = index_offset + i + 1;
 584				*(indicesp++) = index_offset + length + (i/2) + 1;
 585			}
 586		}
 587	}
 588	else
 589	{
 590		// North stride is shorter (more vertices)
 591		length = patch_size / north_stride;
 592		half_length = length / 2;
 593		num_vertices = length + half_length + 1;
 594		num_indices = 9*half_length - 3;
 595
 596		facep->mCenterAgent = (mPatchp->getPointAgent(15, 7) + mPatchp->getPointAgent(16, 8))*0.5f;
 597
 598		// Iterate through this patch's points
 599		for (i = 0; i < length; i+=2)
 600		{
 601			x = i * north_stride;
 602			y = 16 - render_stride;
 603
 604			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
 605			verticesp++;
 606			normalsp++;
 607			texCoords0p++;
 608			texCoords1p++;
 609			vertex_count++;
 610		}
 611
 612		// Iterate through the north patch's points
 613		for (i = 0; i <= length; i++)
 614		{
 615			x = i * north_stride;
 616			y = 16;
 617
 618			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
 619			verticesp++;
 620			normalsp++;
 621			texCoords0p++;
 622			texCoords1p++;
 623			vertex_count++;
 624		}
 625
 626		for (i = 0; i < length; i++)
 627		{
 628			if (!(i%2))
 629			{
 630				*(indicesp++) = index_offset + half_length + i;
 631				*(indicesp++) = index_offset + i/2;
 632				*(indicesp++) = index_offset + half_length + i + 1;
 633			}
 634			else if (i < (length - 2))
 635			{
 636				*(indicesp++) = index_offset + half_length + i;
 637				*(indicesp++) = index_offset + i/2;
 638				*(indicesp++) = index_offset + i/2 + 1;
 639
 640				*(indicesp++) = index_offset + half_length + i;
 641				*(indicesp++) = index_offset + i/2 + 1;
 642				*(indicesp++) = index_offset + half_length + i + 1;
 643			}
 644			else
 645			{
 646				*(indicesp++) = index_offset + half_length + i;
 647				*(indicesp++) = index_offset + i/2;
 648				*(indicesp++) = index_offset + half_length + i + 1;
 649			}
 650		}
 651	}
 652	index_offset += num_vertices;
 653}
 654
 655void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
 656										  LLStrider<LLVector3> &verticesp,
 657										  LLStrider<LLVector3> &normalsp,
 658										  LLStrider<LLVector2> &texCoords0p,
 659										  LLStrider<LLVector2> &texCoords1p,
 660										  LLStrider<U16> &indicesp,
 661										  U32 &index_offset)
 662{
 663	S32 i, x, y;
 664
 665	S32 num_vertices, num_indices;
 666
 667	U32 render_stride = mLastStride;
 668	S32 patch_size = mPatchp->getSurface()->getGridsPerPatchEdge();
 669	S32 length = patch_size / render_stride;
 670	S32 half_length = length / 2;
 671
 672	U32 east_stride = mLastEastStride;
 673
 674	// Stride lengths are the same
 675	if (east_stride == render_stride)
 676	{
 677		num_vertices = 2 * length + 1;
 678		num_indices = length * 6 - 3;
 679
 680		facep->mCenterAgent = (mPatchp->getPointAgent(8, 15) + mPatchp->getPointAgent(8, 16))*0.5f;
 681
 682		// Main patch
 683		for (i = 0; i < length; i++)
 684		{
 685			x = 16 - render_stride;
 686			y = i * render_stride;
 687
 688			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
 689			verticesp++;
 690			normalsp++;
 691			texCoords0p++;
 692			texCoords1p++;
 693		}
 694
 695		// East patch
 696		for (i = 0; i <= length; i++)
 697		{
 698			x = 16;
 699			y = i * render_stride;
 700			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
 701			verticesp++;
 702			normalsp++;
 703			texCoords0p++;
 704			texCoords1p++;
 705		}
 706
 707
 708		for (i = 0; i < length; i++)
 709		{
 710			// Generate indices
 711			*(indicesp++) = index_offset + i;
 712			*(indicesp++) = index_offset + length + i;
 713			*(indicesp++) = index_offset + length + i + 1;
 714
 715			if (i != length - 1)
 716			{
 717				*(indicesp++) = index_offset + i;
 718				*(indicesp++) = index_offset + length + i + 1;
 719				*(indicesp++) = index_offset + i + 1;
 720			}
 721		}
 722	}
 723	else if (east_stride > render_stride)
 724	{
 725		// East stride is longer (has less vertices)
 726		num_vertices = length + half_length + 1;
 727		num_indices = half_length*9 - 3;
 728
 729		facep->mCenterAgent = (mPatchp->getPointAgent(7, 15) + mPatchp->getPointAgent(8, 16))*0.5f;
 730
 731		// Iterate through this patch's points
 732		for (i = 0; i < length; i++)
 733		{
 734			x = 16 - render_stride;
 735			y = i * render_stride;
 736
 737			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
 738			verticesp++;
 739			normalsp++;
 740			texCoords0p++;
 741			texCoords1p++;
 742		}
 743		// Iterate through the east patch's points
 744		for (i = 0; i <= length; i+=2)
 745		{
 746			x = 16;
 747			y = i * render_stride;
 748
 749			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
 750			verticesp++;
 751			normalsp++;
 752			texCoords0p++;
 753			texCoords1p++;
 754		}
 755
 756		for (i = 0; i < length; i++)
 757		{
 758			if (!(i % 2))
 759			{
 760				*(indicesp++) = index_offset + i;
 761				*(indicesp++) = index_offset + length + (i/2);
 762				*(indicesp++) = index_offset + i + 1;
 763
 764				*(indicesp++) = index_offset + i + 1;
 765				*(indicesp++) = index_offset + length + (i/2);
 766				*(indicesp++) = index_offset + length + (i/2) + 1;
 767			}
 768			else if (i < (length - 1))
 769			{
 770				*(indicesp++) = index_offset + i;
 771				*(indicesp++) = index_offset + length + (i/2) + 1;
 772				*(indicesp++) = index_offset + i + 1;
 773			}
 774		}
 775	}
 776	else
 777	{
 778		// East stride is shorter (more vertices)
 779		length = patch_size / east_stride;
 780		half_length = length / 2;
 781		num_vertices = length + length/2 + 1;
 782		num_indices = 9*(length/2) - 3;
 783
 784		facep->mCenterAgent = (mPatchp->getPointAgent(15, 7) + mPatchp->getPointAgent(16, 8))*0.5f;
 785
 786		// Iterate through this patch's points
 787		for (i = 0; i < length; i+=2)
 788		{
 789			x = 16 - render_stride;
 790			y = i * east_stride;
 791
 792			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
 793			verticesp++;
 794			normalsp++;
 795			texCoords0p++;
 796			texCoords1p++;
 797		}
 798		// Iterate through the east patch's points
 799		for (i = 0; i <= length; i++)
 800		{
 801			x = 16;
 802			y = i * east_stride;
 803
 804			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
 805			verticesp++;
 806			normalsp++;
 807			texCoords0p++;
 808			texCoords1p++;
 809		}
 810
 811		for (i = 0; i < length; i++)
 812		{
 813			if (!(i%2))
 814			{
 815				*(indicesp++) = index_offset + half_length + i;
 816				*(indicesp++) = index_offset + half_length + i + 1;
 817				*(indicesp++) = index_offset + i/2;
 818			}
 819			else if (i < (length - 2))
 820			{
 821				*(indicesp++) = index_offset + half_length + i;
 822				*(indicesp++) = index_offset + i/2 + 1;
 823				*(indicesp++) = index_offset + i/2;
 824
 825				*(indicesp++) = index_offset + half_length + i;
 826				*(indicesp++) = index_offset + half_length + i + 1;
 827				*(indicesp++) = index_offset + i/2 + 1;
 828			}
 829			else
 830			{
 831				*(indicesp++) = index_offset + half_length + i;
 832				*(indicesp++) = index_offset + half_length + i + 1;
 833				*(indicesp++) = index_offset + i/2;
 834			}
 835		}
 836	}
 837	index_offset += num_vertices;
 838}
 839
 840void LLVOSurfacePatch::setPatch(LLSurfacePatch *patchp)
 841{
 842	mPatchp = patchp;
 843
 844	dirtyPatch();
 845};
 846
 847
 848void LLVOSurfacePatch::dirtyPatch()
 849{
 850	mDirtiedPatch = TRUE;
 851	dirtyGeom();
 852	mDirtyTerrain = TRUE;
 853	LLVector3 center = mPatchp->getCenterRegion();
 854	LLSurface *surfacep = mPatchp->getSurface();
 855
 856	setPositionRegion(center);
 857
 858	F32 scale_factor = surfacep->getGridsPerPatchEdge() * surfacep->getMetersPerGrid();
 859	setScale(LLVector3(scale_factor, scale_factor, mPatchp->getMaxZ() - mPatchp->getMinZ()));
 860}
 861
 862void LLVOSurfacePatch::dirtyGeom()
 863{
 864	if (mDrawable)
 865	{
 866		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
 867		mDrawable->getFace(0)->setVertexBuffer(NULL);
 868		mDrawable->movePartition();
 869	}
 870}
 871
 872void LLVOSurfacePatch::getGeomSizesMain(const S32 stride, S32 &num_vertices, S32 &num_indices)
 873{
 874	S32 patch_size = mPatchp->getSurface()->getGridsPerPatchEdge();
 875
 876	// First, figure out how many vertices we need...
 877	S32 vert_size = patch_size / stride;
 878	if (vert_size >= 2)
 879	{
 880		num_vertices += vert_size * vert_size;
 881		num_indices += 6 * (vert_size - 1)*(vert_size - 1);
 882	}
 883}
 884
 885void LLVOSurfacePatch::getGeomSizesNorth(const S32 stride, const S32 north_stride,
 886										 S32 &num_vertices, S32 &num_indices)
 887{
 888	S32 patch_size = mPatchp->getSurface()->getGridsPerPatchEdge();
 889	S32 length = patch_size / stride;
 890	// Stride lengths are the same
 891	if (north_stride == stride)
 892	{
 893		num_vertices += 2 * length + 1;
 894		num_indices += length * 6 - 3;
 895	}
 896	else if (north_stride > stride)
 897	{
 898		// North stride is longer (has less vertices)
 899		num_vertices += length + (length/2) + 1;
 900		num_indices += (length/2)*9 - 3;
 901	}
 902	else
 903	{
 904		// North stride is shorter (more vertices)
 905		length = patch_size / north_stride;
 906		num_vertices += length + (length/2) + 1;
 907		num_indices += 9*(length/2) - 3;
 908	}
 909}
 910
 911void LLVOSurfacePatch::getGeomSizesEast(const S32 stride, const S32 east_stride,
 912										S32 &num_vertices, S32 &num_indices)
 913{
 914	S32 patch_size = mPatchp->getSurface()->getGridsPerPatchEdge();
 915	S32 length = patch_size / stride;
 916	// Stride lengths are the same
 917	if (east_stride == stride)
 918	{
 919		num_vertices += 2 * length + 1;
 920		num_indices += length * 6 - 3;
 921	}
 922	else if (east_stride > stride)
 923	{
 924		// East stride is longer (has less vertices)
 925		num_vertices += length + (length/2) + 1;
 926		num_indices += (length/2)*9 - 3;
 927	}
 928	else
 929	{
 930		// East stride is shorter (more vertices)
 931		length = patch_size / east_stride;
 932		num_vertices += length + (length/2) + 1;
 933		num_indices += 9*(length/2) - 3;
 934	}
 935}
 936
 937BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp,
 938									  LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
 939	
 940{
 941
 942	if (!lineSegmentBoundingBox(start, end))
 943	{
 944		return FALSE;
 945	}
 946
 947	LLVector3 delta = end-start;
 948		
 949	LLVector3 pdelta = delta;
 950	pdelta.mV[2] = 0;
 951
 952	F32 plength = pdelta.length();
 953	
 954	F32 tdelta = 1.f/plength;
 955
 956	LLVector3 origin = start - mRegionp->getOriginAgent();
 957
 958	if (mRegionp->getLandHeightRegion(origin) > origin.mV[2])
 959	{
 960		//origin is under ground, treat as no intersection
 961		return FALSE;
 962	}
 963
 964	//step one meter at a time until intersection point found
 965
 966	//VECTORIZE THIS
 967	const LLVector4a* exta = mDrawable->getSpatialExtents();
 968
 969	LLVector3 ext[2];
 970	ext[0].set(exta[0].getF32ptr());
 971	ext[1].set(exta[1].getF32ptr());
 972
 973	F32 rad = (delta*tdelta).magVecSquared();
 974
 975	F32 t = 0.f;
 976	while ( t <= 1.f)
 977	{
 978		LLVector3 sample = origin + delta*t;
 979		
 980		if (AABBSphereIntersectR2(ext[0], ext[1], sample+mRegionp->getOriginAgent(), rad))
 981		{
 982			F32 height = mRegionp->getLandHeightRegion(sample);
 983			if (height > sample.mV[2])
 984			{ //ray went below ground, positive intersection
 985				//quick and dirty binary search to get impact point
 986				tdelta = -tdelta*0.5f;
 987				F32 err_dist = 0.001f;
 988				F32 dist = fabsf(sample.mV[2] - height);
 989
 990				while (dist > err_dist && tdelta*tdelta > 0.0f)
 991				{
 992					t += tdelta;
 993					sample = origin+delta*t;
 994					height = mRegionp->getLandHeightRegion(sample);
 995					if ((tdelta < 0 && height < sample.mV[2]) ||
 996						(height > sample.mV[2] && tdelta > 0))
 997					{ //jumped over intersection point, go back
 998						tdelta = -tdelta;
 999					}
1000					tdelta *= 0.5f;
1001					dist = fabsf(sample.mV[2] - height);
1002				}
1003
1004				if (intersection)
1005				{
1006					F32 height = mRegionp->getLandHeightRegion(sample);
1007					if (fabsf(sample.mV[2]-height) < delta.length()*tdelta)
1008					{
1009						sample.mV[2] = mRegionp->getLandHeightRegion(sample);
1010					}
1011					*intersection = sample + mRegionp->getOriginAgent();
1012				}
1013
1014				if (normal)
1015				{
1016					*normal = mRegionp->getLand().resolveNormalGlobal(mRegionp->getPosGlobalFromRegion(sample));
1017				}
1018
1019				return TRUE;
1020			}
1021		}
1022
1023		t += tdelta;
1024		if (t > 1 && t < 1.f+tdelta*0.99f)
1025		{ //make sure end point is checked (saves vertical lines coming up negative)
1026			t = 1.f;
1027		}
1028	}
1029
1030
1031	return FALSE;
1032}
1033
1034void LLVOSurfacePatch::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
1035{
1036	LLVector3 posAgent = getPositionAgent();
1037	LLVector3 scale = getScale();
1038	//make z-axis scale at least 1 to avoid shadow artifacts on totally flat land
1039	scale.mV[VZ] = llmax(scale.mV[VZ], 1.f);
1040	newMin.load3( (posAgent-scale*0.5f).mV); // Changing to 2.f makes the culling a -little- better, but still wrong
1041	newMax.load3( (posAgent+scale*0.5f).mV);
1042	LLVector4a pos;
1043	pos.setAdd(newMin,newMax);
1044	pos.mul(0.5f);
1045	mDrawable->setPositionGroup(pos);
1046}
1047
1048U32 LLVOSurfacePatch::getPartitionType() const
1049{ 
1050	return LLViewerRegion::PARTITION_TERRAIN; 
1051}
1052
1053LLTerrainPartition::LLTerrainPartition()
1054: LLSpatialPartition(LLDrawPoolTerrain::VERTEX_DATA_MASK, FALSE, GL_DYNAMIC_DRAW_ARB)
1055{
1056	mOcclusionEnabled = FALSE;
1057	mInfiniteFarClip = TRUE;
1058	mDrawableType = LLPipeline::RENDER_TYPE_TERRAIN;
1059	mPartitionType = LLViewerRegion::PARTITION_TERRAIN;
1060}
1061
1062LLVertexBuffer* LLTerrainPartition::createVertexBuffer(U32 type_mask, U32 usage)
1063{
1064	return new LLVertexBufferTerrain();
1065}
1066
1067static LLFastTimer::DeclareTimer FTM_REBUILD_TERRAIN_VB("Terrain VB");
1068void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
1069{
1070	LLFastTimer ftm(FTM_REBUILD_TERRAIN_VB);
1071
1072	LLVertexBuffer* buffer = group->mVertexBuffer;
1073
1074	//get vertex buffer striders
1075	LLStrider<LLVector3> vertices;
1076	LLStrider<LLVector3> normals;
1077	LLStrider<LLVector2> texcoords2;
1078	LLStrider<LLVector2> texcoords;
1079	LLStrider<U16> indices;
1080
1081	llassert_always(buffer->getVertexStrider(vertices));
1082	llassert_always(buffer->getNormalStrider(normals));
1083	llassert_always(buffer->getTexCoord0Strider(texcoords));
1084	llassert_always(buffer->getTexCoord1Strider(texcoords2));
1085	llassert_always(buffer->getIndexStrider(indices));
1086
1087	U32 indices_index = 0;
1088	U32 index_offset = 0;
1089
1090	for (std::vector<LLFace*>::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i)
1091	{
1092		LLFace* facep = *i;
1093
1094		facep->setIndicesIndex(indices_index);
1095		facep->setGeomIndex(index_offset);
1096		facep->setVertexBuffer(buffer);
1097
1098		LLVOSurfacePatch* patchp = (LLVOSurfacePatch*) facep->getViewerObject();
1099		patchp->getGeometry(vertices, normals, texcoords, texcoords2, indices);
1100
1101		indices_index += facep->getIndicesCount();
1102		index_offset += facep->getGeomCount();
1103	}
1104
1105	buffer->flush();
1106	mFaceList.clear();
1107}
1108