//---------------------------------------------------------------------------- void NodeCamera::SortByDepth(TArray<NodeCamera*>& rCameras) { for (UInt i = 0; i < rCameras.GetQuantity()-1; ++i) { for (UInt j = 0; j < rCameras.GetQuantity()-i-1; ++j) { if (rCameras[j]->GetDepth() > rCameras[j+1]->GetDepth()) { NodeCamera* pTemp = rCameras[j]; rCameras[j] = rCameras[j+1]; rCameras[j+1] = pTemp; } } } }
//---------------------------------------------------------------------------- PdrDisplayList::PdrDisplayList(PdrRendererData* pRendererData, const PdrIndexBuffer& rIBuffer, UInt indexCount, UInt startIndex, const TArray<PdrVertexFormat::VertexElement>& rElements) { // Note that the display-list buffer area must be forced out of // the CPU cache since it will be written using the write-gather pipe mSize = ((8 + indexCount * rElements.GetQuantity()*2) & 0xFFFFFFE0) + 64 ; mpData = memalign(32, mSize); WIRE_ASSERT(mpData); DCInvalidateRange(mpData, mSize); GXBeginDisplayList(mpData, mSize); pRendererData->Draw(rElements, rIBuffer.GetBuffer(), indexCount, startIndex); mDisplayListSize = GXEndDisplayList(); WIRE_ASSERT(mDisplayListSize && mDisplayListSize <= mSize); DCFlushRange(mpData, mSize); }
//---------------------------------------------------------------------------- Vector3F SplineCamera::GetHermite(TArray<Transformation*>& rControlPoints, UInt idx, Float t) { WIRE_ASSERT(idx > 0 && idx < rControlPoints.GetQuantity()-2); Float t2 = t * t; Float t3 = t2 * t; Vector3F p0 = (*(rControlPoints[idx - 1])).GetTranslate(); Vector3F p1 = (*(rControlPoints[idx])).GetTranslate(); Vector3F p2 = (*(rControlPoints[idx + 1])).GetTranslate(); Vector3F p3 = (*(rControlPoints[idx + 2])).GetTranslate(); const Float tension = 0.5f; // 0.5 is catmull-rom Vector3F v4 = tension * (p2 - p0); Vector3F v5 = tension * (p3 - p1); Float blend1 = 2 * t3 - 3 * t2 + 1; Float blend2 = -2 * t3 + 3 * t2; Float blend3 = t3 - 2 * t2 + t; Float blend4 = t3 - t2; return blend1 * p1 + blend2 * p2 + blend3 * v4 + blend4 * v5; }
//---------------------------------------------------------------------------- void Node::PrepareForStaticBatching(Bool forceWorldIsCurrent, Bool duplicateShared, TArray<MergeArray*>* pMergeArrays) { Bool isInitiator = pMergeArrays == NULL; if (isInitiator) { PrepareForDynamicBatching(forceWorldIsCurrent, duplicateShared); pMergeArrays = WIRE_NEW TArray<MergeArray*>; } if (mspRenderObject && WorldIsCurrent && WorldBoundIsCurrent && World.IsIdentity()) { Mesh* pMesh = mspRenderObject->GetMesh(); Bool isNewMesh = true; for (UInt i = 0; i < pMergeArrays->GetQuantity(); i++) { MergeArray* pMeshArray = (*pMergeArrays)[i]; Mesh::VertexBuffers& rMVABs = (*pMeshArray)[0]->GetMesh()-> GetVertexBuffers(); Mesh::VertexBuffers& rMVBs = pMesh->GetVertexBuffers(); Bool isIdentical = true; if (rMVABs.GetQuantity() == rMVBs.GetQuantity()) { for (UInt j = 0; j < rMVBs.GetQuantity(); j++) { if (rMVBs[j]->GetAttributes().GetKey() != rMVABs[j]->GetAttributes().GetKey()) { isIdentical = false; break; } } } if (isIdentical) { pMeshArray->Append(mspRenderObject); isNewMesh = false; break; } } if (isNewMesh) { MergeArray* pNewArray = WIRE_NEW MergeArray; pNewArray->Append(mspRenderObject); pMergeArrays->Append(pNewArray); } } for (UInt i = 0; i < GetQuantity(); i++) { Node* pChild = DynamicCast<Node>(GetChild(i)); if (pChild) { pChild->PrepareForStaticBatching(forceWorldIsCurrent, duplicateShared, pMergeArrays); } } if (isInitiator) { TArray<MergeArray*>* pSortedArrays = WIRE_NEW TArray<MergeArray*>; for (UInt i = 0; i < pMergeArrays->GetQuantity(); i++) { MergeArray* pMergeArray = (*pMergeArrays)[i]; const UInt maxVtxQty = 0x10000; UInt vtxCount = 0; UInt idxCount = 0; MergeArray* pSortedArray = WIRE_NEW MergeArray(pMergeArray-> GetQuantity(), 16); pSortedArrays->Append(pSortedArray); for (UInt i = 0; i < pMergeArray->GetQuantity(); i++) { Mesh* pMesh = (*pMergeArray)[i]->GetMesh(); if ((vtxCount + pMesh->GetVertexCount()) < maxVtxQty) { vtxCount += pMesh->GetVertexCount(); idxCount += pMesh->GetIndexCount(); } else { pSortedArray = WIRE_NEW MergeArray(pMergeArray-> GetQuantity(), 16); pSortedArrays->Append(pSortedArray); vtxCount = 0; idxCount = 0; } pSortedArray->Append((*pMergeArray)[i]); } WIRE_DELETE pMergeArray; } WIRE_DELETE pMergeArrays; pMergeArrays = NULL; for (UInt i = 0; i < pSortedArrays->GetQuantity(); i++) { MergeArray* pSortedArray = (*pSortedArrays)[i]; MergeMeshes(pSortedArray); WIRE_DELETE pSortedArray; } WIRE_DELETE pSortedArrays; pSortedArrays = NULL; } }
//---------------------------------------------------------------------------- void NodeCamera::Draw(TArray<NodeCamera*>& rNodeCameras, Spatial* pRoot, Culler& rCuller, Renderer* pRenderer) { WIRE_ASSERT(pRenderer && pRoot); if (!pRenderer || !pRoot) { return; } const UInt maxCameraCount = 64; if (rNodeCameras.GetQuantity() >= 64) { WIRE_ASSERT(false); return; } // cull all skyboxes attached to cameras in the scene Spatial::CullingMode tempCullingModes[maxCameraCount]; for (UInt i = 0; i < rNodeCameras.GetQuantity(); i++) { NodeCamera* pNodeCamera = rNodeCameras[i]; WIRE_ASSERT(pNodeCamera); Node* pSkybox = pNodeCamera->mspSkybox; if (pSkybox && pNodeCamera->IsEnabled()) { tempCullingModes[i] = pSkybox->Culling; pSkybox->Culling = Spatial::CULL_ALWAYS; } } for (UInt i = 0; i < rNodeCameras.GetQuantity(); i++) { NodeCamera* pNodeCamera = rNodeCameras[i]; WIRE_ASSERT(pNodeCamera && pNodeCamera->Get()); if (!pNodeCamera->IsEnabled()) { continue; } Camera* pCamera = pNodeCamera->Get(); rCuller.SetCamera(pCamera); rCuller.ComputeVisibleSet(pRoot); Float left; Float right; Float top; Float bottom; pCamera->GetViewport(left, right, top, bottom); UInt width = pRenderer->GetWidth(); UInt height = pRenderer->GetHeight(); Vector4F rect; rect.X() = MathF::Round(left*width); rect.Y() = MathF::Round((1.0F-top)*height); rect.Z() = MathF::Round((right-left)*width); rect.W() = MathF::Round((top-bottom)*height); ColorRGBA clearColor = pRenderer->GetClearColor(); switch (rNodeCameras[i]->mClearFlag) { case CF_ALL: pRenderer->SetClearColor(pNodeCamera->GetClearColor()); pRenderer->ClearBuffers(true, true, rect); pRenderer->SetClearColor(clearColor); break; case CF_Z_ONLY: pRenderer->ClearBuffers(false, true, rect); break; case CF_NONE: break; default: WIRE_ASSERT(false); } pRenderer->SetCamera(pCamera); pRenderer->Draw(rCuller.GetVisibleSets()); Node* pSkybox = pNodeCamera->mspSkybox; if (pSkybox) { pSkybox->Culling = Spatial::CULL_NEVER; rCuller.ComputeVisibleSet(pSkybox); pRenderer->Draw(rCuller.GetVisibleSets()); pSkybox->Culling = Spatial::CULL_ALWAYS; } } // restore culling mode of all skyboxes attached to cameras in the scene for (UInt i = 0; i < rNodeCameras.GetQuantity(); i++) { NodeCamera* pNodeCamera = rNodeCameras[i]; WIRE_ASSERT(pNodeCamera); Node* pSkybox = pNodeCamera->mspSkybox; if (pSkybox && pNodeCamera->IsEnabled()) { pSkybox->Culling = tempCullingModes[i]; } } }
//---------------------------------------------------------------------------- Texture2D* Sample5::CreateTexture() { if (mspTexture) { return mspTexture; } // define the properties of the image to be used as a texture const UInt width = 256; const UInt height = 256; const Image2D::FormatMode format = Image2D::FM_RGB888; const UInt bpp = Image2D::GetBytesPerPixel(format); ColorRGB* const pColorDst = WIRE_NEW ColorRGB[width*height]; // create points with random x,y position and color TArray<Cell> cells; Random random; for (UInt i = 0; i < 10; i++) { Cell cell; cell.point.X() = random.GetFloat() * width; cell.point.Y() = random.GetFloat() * height; cell.color.R() = random.GetFloat(); cell.color.G() = random.GetFloat(); cell.color.B() = random.GetFloat(); Float max = 0.0F; max = max < cell.color.R() ? cell.color.R() : max; max = max < cell.color.G() ? cell.color.G() : max; max = max < cell.color.B() ? cell.color.B() : max; max = 1.0F / max; cell.color *= max; cells.Append(cell); } // iterate over all texels and use the distance to the 2 closest random // points to calculate the texel's color Float max = 0; for (UInt y = 0; y < height; y++) { for (UInt x = 0; x < width; x++) { Float minDist = MathF::MAX_REAL; Float min2Dist = MathF::MAX_REAL; UInt minIndex = 0; for (UInt i = 0; i < cells.GetQuantity(); i++) { Vector2F pos(static_cast<Float>(x), static_cast<Float>(y)); // Handle tiling Vector2F vec = cells[i].point - pos; vec.X() = MathF::FAbs(vec.X()); vec.Y() = MathF::FAbs(vec.Y()); vec.X() = vec.X() > width/2 ? width-vec.X() : vec.X(); vec.Y() = vec.Y() > height/2 ? height-vec.Y() : vec.Y(); Float distance = vec.Length(); if (minDist > distance) { min2Dist = minDist; minDist = distance; minIndex = i; } else if (min2Dist > distance) { min2Dist = distance; } } Float factor = (min2Dist - minDist) + 3; ColorRGB color = cells[minIndex].color * factor; pColorDst[y*width+x] = color; max = max < color.R() ? color.R() : max; max = max < color.G() ? color.G() : max; max = max < color.B() ? color.B() : max; } } // convert and normalize the ColorRGBA float array to an 8-bit per // channel texture max = 255.0F / max; UChar* const pDst = WIRE_NEW UChar[width * height * bpp]; for (UInt i = 0; i < width*height; i++) { ColorRGB color = pColorDst[i]; pDst[i*bpp] = static_cast<UChar>(color.R() * max); pDst[i*bpp+1] = static_cast<UChar>(color.G() * max); pDst[i*bpp+2] = static_cast<UChar>(color.B() * max); } Image2D* pImage = WIRE_NEW Image2D(format, width, height, pDst); Texture2D* pTexture = WIRE_NEW Texture2D(pImage); // The texture tiles are supposed to be seamless, therefore // we need the UV set to be repeating. pTexture->SetWrapType(0, Texture2D::WT_REPEAT); pTexture->SetWrapType(1, Texture2D::WT_REPEAT); // save the texture for later reference mspTexture = pTexture; return pTexture; }