/** * @file llvowater.cpp * @brief LLVOWater class implementation * * $LicenseInfo:firstyear=2005&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$ */ #include "llviewerprecompiledheaders.h" #include "llvowater.h" #include "llviewercontrol.h" #include "lldrawable.h" #include "lldrawpoolwater.h" #include "llface.h" #include "llsky.h" #include "llsurface.h" #include "llviewercamera.h" #include "llviewertexturelist.h" #include "llviewerregion.h" #include "llworld.h" #include "pipeline.h" #include "llspatialpartition.h" /////////////////////////////////// template inline T LERP(T a, T b, F32 factor) { return a + (b - a) * factor; } LLVOWater::LLVOWater(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) : LLStaticViewerObject(id, pcode, regionp), mRenderType(LLPipeline::RENDER_TYPE_WATER) { // Terrain must draw during selection passes so it can block objects behind it. mbCanSelect = false; setScale(LLVector3(256.f, 256.f, 0.f)); // Hack for setting scale for bounding boxes/visibility. mIsEdgePatch = false; } void LLVOWater::markDead() { LLViewerObject::markDead(); } bool LLVOWater::isActive() const { return false; } void LLVOWater::setPixelAreaAndAngle(LLAgent &agent) { mAppAngle = 50; mPixelArea = 500*500; } // virtual void LLVOWater::updateTextures() { } // Never gets called void LLVOWater::idleUpdate(LLAgent &agent, const F64 &time) { } LLDrawable *LLVOWater::createDrawable(LLPipeline *pipeline) { pipeline->allocDrawable(this); mDrawable->setLit(false); mDrawable->setRenderType(mRenderType); LLDrawPoolWater *pool = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER); mDrawable->setNumFaces(1, pool, LLWorld::getInstance()->getDefaultWaterTexture()); return mDrawable; } bool LLVOWater::updateGeometry(LLDrawable *drawable) { LL_PROFILE_ZONE_SCOPED; LLFace *face; if (drawable->getNumFaces() < 1) { LLDrawPoolWater *poolp = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER); drawable->addFace(poolp, NULL); } face = drawable->getFace(0); if (!face) { return true; } // LLVector2 uvs[4]; // LLVector3 vtx[4]; LLStrider verticesp, normalsp; LLStrider texCoordsp; LLStrider indicesp; U16 index_offset; // A quad is 4 vertices and 6 indices (making 2 triangles) static const unsigned int vertices_per_quad = 4; static const unsigned int indices_per_quad = 6; S32 size_x = LLPipeline::sRenderTransparentWater ? 8 : 1; S32 size_y = LLPipeline::sRenderTransparentWater ? 8 : 1; const LLVector3& scale = getScale(); size_x *= (S32)llmin(llround(scale.mV[0] / 256.f), 8); size_y *= (S32)llmin(llround(scale.mV[1] / 256.f), 8); const S32 num_quads = size_x * size_y; face->setSize(vertices_per_quad * num_quads, indices_per_quad * num_quads); LLVertexBuffer* buff = face->getVertexBuffer(); if (!buff || buff->getNumIndices() != face->getIndicesCount() || buff->getNumVerts() != face->getGeomCount() || face->getIndicesStart() != 0 || face->getGeomIndex() != 0) { buff = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK); if (!buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount())) { LL_WARNS() << "Failed to allocate Vertex Buffer on water update to " << face->getGeomCount() << " vertices and " << face->getIndicesCount() << " indices" << LL_ENDL; } face->setIndicesIndex(0); face->setGeomIndex(0); face->setVertexBuffer(buff); } index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); LLVector3 position_agent; position_agent = getPositionAgent(); face->mCenterAgent = position_agent; face->mCenterLocal = position_agent; S32 x, y; F32 step_x = getScale().mV[0] / size_x; F32 step_y = getScale().mV[1] / size_y; const LLVector3 up(0.f, step_y * 0.5f, 0.f); const LLVector3 right(step_x * 0.5f, 0.f, 0.f); const LLVector3 normal(0.f, 0.f, 1.f); F32 size_inv_x = 1.f / size_x; F32 size_inv_y = 1.f / size_y; for (y = 0; y < size_y; y++) { for (x = 0; x < size_x; x++) { S32 toffset = index_offset + 4*(y*size_x + x); position_agent = getPositionAgent() - getScale() * 0.5f; position_agent.mV[VX] += (x + 0.5f) * step_x; position_agent.mV[VY] += (y + 0.5f) * step_y; position_agent.mV[VX] = (F32)llround(position_agent.mV[VX]); position_agent.mV[VY] = (F32)llround(position_agent.mV[VY]); *verticesp++ = position_agent - right + up; *verticesp++ = position_agent - right - up; *verticesp++ = position_agent + right + up; *verticesp++ = position_agent + right - up; *texCoordsp++ = LLVector2(x*size_inv_x, (y+1)*size_inv_y); *texCoordsp++ = LLVector2(x*size_inv_x, y*size_inv_y); *texCoordsp++ = LLVector2((x+1)*size_inv_x, (y+1)*size_inv_y); *texCoordsp++ = LLVector2((x+1)*size_inv_x, y*size_inv_y); *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *indicesp++ = toffset + 0; *indicesp++ = toffset + 1; *indicesp++ = toffset + 2; *indicesp++ = toffset + 1; *indicesp++ = toffset + 3; *indicesp++ = toffset + 2; } } buff->unmapBuffer(); mDrawable->movePartition(); LLPipeline::sCompiles++; return true; } void LLVOWater::initClass() { } void LLVOWater::cleanupClass() { } void setVecZ(LLVector3& v) { v.mV[VX] = 0; v.mV[VY] = 0; v.mV[VZ] = 1; } void LLVOWater::setIsEdgePatch(const bool edge_patch) { mIsEdgePatch = edge_patch; } void LLVOWater::updateSpatialExtents(LLVector4a &newMin, LLVector4a& newMax) { LLVector4a pos; pos.load3(getPositionAgent().mV); LLVector4a scale; scale.load3(getScale().mV); scale.mul(0.5f); newMin.setSub(pos, scale); newMax.setAdd(pos, scale); pos.setAdd(newMin,newMax); pos.mul(0.5f); mDrawable->setPositionGroup(pos); } U32 LLVOWater::getPartitionType() const { if (mIsEdgePatch) { return LLViewerRegion::PARTITION_VOIDWATER; } return LLViewerRegion::PARTITION_WATER; } U32 LLVOVoidWater::getPartitionType() const { return LLViewerRegion::PARTITION_VOIDWATER; } LLWaterPartition::LLWaterPartition(LLViewerRegion* regionp) : LLSpatialPartition(0, false, regionp) { mInfiniteFarClip = true; mDrawableType = LLPipeline::RENDER_TYPE_WATER; mPartitionType = LLViewerRegion::PARTITION_WATER; } LLVoidWaterPartition::LLVoidWaterPartition(LLViewerRegion* regionp) : LLWaterPartition(regionp) { mOcclusionEnabled = false; mDrawableType = LLPipeline::RENDER_TYPE_VOIDWATER; mPartitionType = LLViewerRegion::PARTITION_VOIDWATER; }