void TerrainBlock::buildConvex(const Box3F& box,Convex* convex) { sTerrainConvexList.collectGarbage(); // if (box.maxExtents.z < -TerrainThickness || box.minExtents.z > fixedToFloat(gridMap[BlockShift]->maxHeight)) return; // Transform the bounding sphere into the object's coord space. Note that this // not really optimal. Box3F osBox = box; mWorldToObj.mul(osBox); AssertWarn(mObjScale == Point3F(1, 1, 1), "Error, handle the scale transform on the terrain"); S32 xStart = (S32)mFloor( osBox.minExtents.x / mSquareSize ); S32 xEnd = (S32)mCeil ( osBox.maxExtents.x / mSquareSize ); S32 yStart = (S32)mFloor( osBox.minExtents.y / mSquareSize ); S32 yEnd = (S32)mCeil ( osBox.maxExtents.y / mSquareSize ); S32 xExt = xEnd - xStart; if (xExt > MaxExtent) xExt = MaxExtent; mHeightMax = floatToFixed(osBox.maxExtents.z); mHeightMin = (osBox.minExtents.z < 0)? 0: floatToFixed(osBox.minExtents.z); for (S32 y = yStart; y < yEnd; y++) { S32 yi = y & BlockMask; // for (S32 x = xStart; x < xEnd; x++) { S32 xi = x & BlockMask; GridSquare *gs = findSquare(0, Point2I(xi, yi)); // If we disable repeat, then skip non-primary if(!mTile && (x!=xi || y!=yi)) continue; // holes only in the primary terrain block if (((gs->flags & GridSquare::Empty) && x == xi && y == yi) || gs->minHeight > mHeightMax || gs->maxHeight < mHeightMin) continue; U32 sid = (x << 16) + (y & ((1 << 16) - 1)); Convex* cc = 0; // See if the square already exists as part of the working set. CollisionWorkingList& wl = convex->getWorkingList(); for (CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext) if (itr->mConvex->getType() == TerrainConvexType && static_cast<TerrainConvex*>(itr->mConvex)->squareId == sid) { cc = itr->mConvex; break; } if (cc) continue; // Create a new convex. TerrainConvex* cp = new TerrainConvex; sTerrainConvexList.registerObject(cp); convex->addToWorkingList(cp); cp->halfA = true; cp->square = 0; cp->mObject = this; cp->squareId = sid; cp->material = getMaterial(xi,yi)->index;//RDTODO cp->box.minExtents.set((F32)(x * mSquareSize), (F32)(y * mSquareSize), fixedToFloat(gs->minHeight)); cp->box.maxExtents.x = cp->box.minExtents.x + mSquareSize; cp->box.maxExtents.y = cp->box.minExtents.y + mSquareSize; cp->box.maxExtents.z = fixedToFloat(gs->maxHeight); mObjToWorld.mul(cp->box); // Build points Point3F* pos = cp->point; for (int i = 0; i < 4 ; i++,pos++) { S32 dx = i >> 1; S32 dy = dx ^ (i & 1); pos->x = (F32)((x + dx) * mSquareSize); pos->y = (F32)((y + dy) * mSquareSize); pos->z = fixedToFloat(getHeight(xi + dx, yi + dy)); } // Build normals, then split into two Convex objects if the // square is concave if ((cp->split45 = gs->flags & GridSquare::Split45) == true) { VectorF *vp = cp->point; mCross(vp[0] - vp[1],vp[2] - vp[1],&cp->normal[0]); cp->normal[0].normalize(); mCross(vp[2] - vp[3],vp[0] - vp[3],&cp->normal[1]); cp->normal[1].normalize(); if (mDot(vp[3] - vp[1],cp->normal[0]) > 0) { TerrainConvex* nc = new TerrainConvex(*cp); sTerrainConvexList.registerObject(nc); convex->addToWorkingList(nc); nc->halfA = false; nc->square = cp; cp->square = nc; } } else { VectorF *vp = cp->point; mCross(vp[3] - vp[0],vp[1] - vp[0],&cp->normal[0]); cp->normal[0].normalize(); mCross(vp[1] - vp[2],vp[3] - vp[2],&cp->normal[1]); cp->normal[1].normalize(); if (mDot(vp[2] - vp[0],cp->normal[0]) > 0) { TerrainConvex* nc = new TerrainConvex(*cp); sTerrainConvexList.registerObject(nc); convex->addToWorkingList(nc); nc->halfA = false; nc->square = cp; cp->square = nc; } } } } }