//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRLightMap::SetDrawData ( GOSVertexPool *vp, Stuff::Matrix4D *mat, MLRClippingState& clippingState, MLRState& _state ) { vertexPool = vp; stream->Rewind(); *stream << (int)Matrix4D; *stream << reinterpret_cast<int>(mat); *stream << (int)ClippingState; clippingState.Save(stream); *stream << (int)MasterRenderState; _state.Save(stream); }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int MLRIndexedTriangleCloud::Clip(MLRClippingState clippingFlags, GOSVertexPool *vt) { int myNumberUsedClipVertex, myNumberUsedClipIndex, myNumberUsedClipLength; myNumberUsedClipVertex = 0; myNumberUsedClipIndex = 0; myNumberUsedClipLength = 0; Verify(*usedNrOfTriangles > 0); // //------------------------ // Handle the indexed case //------------------------ // memset(visibleIndexedVertices->GetData(), 0, *usedNrOfPoints); // //----------------------------------------------------------------- // Step through each polygon, making sure that we don't try to clip // backfaced polygons //----------------------------------------------------------------- // int i, j, k, k0, k1, *cs = (int *)clipPerVertex->GetData(); unsigned short l; int index0, index1, index2, ret = 0; int mask; Scalar a = 0.0f; for(i=0,j=0;i<*usedNrOfTriangles;j+=3,++i) { index0 = index[j]; index1 = index[j+1]; index2 = index[j+2]; // //--------------------------------------------------------------- // Test each vertex of the polygon against the allowed clipping // planes, and accumulate status for which planes always clip and // which planes clipped at least once //--------------------------------------------------------------- // theAnd = cs[index0]; theAnd &= (cs[index1] & cs[index2]); theOr |= (cs[index1] | cs[index2]); theAnd = theOr = 0; //ASSUME NO CLIPPING NEEDED FOR MC2. Its just not done here! // //------------------------------------------------------------------- // If any bit is set for all vertices, then the polygon is completely // outside the viewing space and we don't have to draw it. On the // other hand, if no bits at all were ever set, we can do a trivial // accept of the polygon //------------------------------------------------------------------- // if (theAnd != 0) { testList[i] = 0; #ifdef LAB_ONLY Set_Statistic(PolysClippedButOutside, PolysClippedButOutside+1); #endif } else if (theOr == 0) { testList[i] = 1; ret++; (*visibleIndexedVertices)[index0] = 1; (*visibleIndexedVertices)[index1] = 1; (*visibleIndexedVertices)[index2] = 1; #ifdef LAB_ONLY Set_Statistic(PolysClippedButInside, PolysClippedButInside+1); #endif } // //----------------------------------------------------------------- // It is not a trivial case, so we must now do real clipping on the // polygon //----------------------------------------------------------------- // else { unsigned short numberVerticesPerPolygon = 0; // //--------------------------------------------------------------- // Handle the case of a single clipping plane by stepping through // the vertices and finding the edge it originates //--------------------------------------------------------------- // bool firstIsIn; if (theOr.GetNumberOfSetBits() == 1) { #ifdef LAB_ONLY Set_Statistic(PolysClippedButOnePlane, PolysClippedButOnePlane+1); #endif for(k=j;k<j+3;k++) { k0 = index[k]; k1 = index[(k+1) < j+3 ? k+1 : j]; // //---------------------------------------------------- // If this vertex is inside the viewing space, copy it // directly to the clipping buffer //---------------------------------------------------- // int clipped_index = myNumberUsedClipVertex + numberVerticesPerPolygon; theTest = cs[k0]; if(theTest == 0) { firstIsIn = true; (*clipExtraCoords)[clipped_index] = (*transformedCoords)[k0]; (*clipExtraColors)[clipped_index] = colors[k0]; (*clipExtraTexCoords)[clipped_index] = texCoords[k0]; numberVerticesPerPolygon++; clipped_index++; // //------------------------------------------------------- // We don't need to clip this edge if the next vertex is // also in the viewing space, so just move on to the next // vertex //------------------------------------------------------- // if(cs[k1] == 0) { continue; } } // //--------------------------------------------------------- // This vertex is outside the viewing space, so if the next // vertex is also outside the viewing space, no clipping is // needed and we throw this vertex away. Since only one // clipping plane is involved, it must be in the same space // as the first vertex //--------------------------------------------------------- // else { firstIsIn = false; if(cs[k1] != 0) { Verify(cs[k1] == cs[k0]); continue; } } // //-------------------------------------------------- // We now find the distance along the edge where the // clipping plane will intersect //-------------------------------------------------- // int ct = 0; mask = 1; theTest |= cs[k1]; // //----------------------------------------------------- // Find the boundary conditions that match our clipping // plane //----------------------------------------------------- // for (l=0; l<MLRClippingState::NextBit; l++) { if(theTest.IsClipped(mask)) { // GetDoubleBC(l, bc0, bc1, transformedCoords[k0], transformedCoords[k1]); // //------------------------------------------- // Find the clipping interval from bc0 to bc1 //------------------------------------------- // if(firstIsIn==true) { a = GetLerpFactor(l, (*transformedCoords)[k0], (*transformedCoords)[k1]); } else { a = GetLerpFactor(l, (*transformedCoords)[k1], (*transformedCoords)[k0]); } Verify(a >= 0.0f && a <= 1.0f); ct = l; break; } mask <<= 1; } // //------------------------------ // Lerp the homogeneous position //------------------------------ // if(firstIsIn==true) { (*clipExtraCoords)[clipped_index].Lerp( (*transformedCoords)[k0], (*transformedCoords)[k1], a ); DoClipTrick((*clipExtraCoords)[clipped_index], ct); // //---------------------------------------------------------- // If there are colors, lerp them in screen space for now as // most cards do that anyway //---------------------------------------------------------- // #if COLOR_AS_DWORD (*clipExtraColors)[clipped_index] = Color_DWORD_Lerp ( colors[k0], colors[k1], a ); #else (*clipExtraColors)[clipped_index].Lerp( colors[k0], colors[k1], a ); #endif // //----------------------------------------------------- // If there are texture uv's, we need to lerp them in a // perspective correct manner //----------------------------------------------------- // (*clipExtraTexCoords)[clipped_index].Lerp ( texCoords[k0], texCoords[k1], a ); } else { (*clipExtraCoords)[clipped_index].Lerp( (*transformedCoords)[k1], (*transformedCoords)[k0], a ); DoClipTrick((*clipExtraCoords)[clipped_index], ct); // //---------------------------------------------------------- // If there are colors, lerp them in screen space for now as // most cards do that anyway //---------------------------------------------------------- // #if COLOR_AS_DWORD (*clipExtraColors)[clipped_index] = Color_DWORD_Lerp ( colors[k1], colors[k0], a ); #else (*clipExtraColors)[clipped_index].Lerp( colors[k1], colors[k0], a ); #endif // //----------------------------------------------------- // If there are texture uv's, we need to lerp them in a // perspective correct manner //----------------------------------------------------- // (*clipExtraTexCoords)[clipped_index].Lerp ( texCoords[k1], texCoords[k0], a ); } // //-------------------------------- // Bump the polygon's vertex count //-------------------------------- // numberVerticesPerPolygon++; } (*clipExtraLength)[myNumberUsedClipLength] = numberVerticesPerPolygon; #ifdef _ARMOR (*clipExtraLength)[myNumberUsedClipLength] &= ~0x8000; #endif } // //--------------------------------------------------------------- // We have to handle multiple planes. We do this by creating two // buffers and we switch between them as we clip plane by plane //--------------------------------------------------------------- // else { #ifdef LAB_ONLY Set_Statistic(PolysClippedButGOnePlane, PolysClippedButGOnePlane+1); #endif ClipData2 srcPolygon, dstPolygon; int dstBuffer = 1; srcPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); srcPolygon.colors = clipBuffer[dstBuffer].colors.GetData(); srcPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); srcPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); // //---------------------------------------------------------- // unravel and copy the original data into the source buffer //---------------------------------------------------------- // for(k=j,l=0;k<j+3;k++,l++) { int indexK = index[k]; srcPolygon.coords[l] = (*transformedCoords)[indexK]; srcPolygon.colors[l] = colors[indexK]; srcPolygon.texCoords[l] = texCoords[indexK]; srcPolygon.clipPerVertex[l] = (*clipPerVertex)[indexK]; } srcPolygon.length = l; // //-------------------------------- // Point to the destination buffer //-------------------------------- // dstBuffer = 0; dstPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); dstPolygon.colors = clipBuffer[dstBuffer].colors.GetData(); dstPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); dstPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); dstPolygon.length = 0; // //----------------------------------------------------------- // Spin through each plane that clipped the primitive and use // it to actually clip the primitive //----------------------------------------------------------- // mask = 1; MLRClippingState theNewOr(0); int loop = 4; #if HUNT_CLIP_ERROR for(k=0;k<srcPolygon.length;k++) { DEBUG_STREAM << setiosflags( ios::scientific) << setprecision(20) << srcPolygon.coords[k].x << " " << srcPolygon.coords[k].y << " " << srcPolygon.coords[k].z << " " << srcPolygon.coords[k].w << '\n'; } #endif #if HUNT_CLIP_ERROR DEBUG_STREAM << "TheOriginalOR: " << hex << theOr.GetClippingState() << dec << '\n'; #endif do { for(l=0; l<MLRClippingState::NextBit; l++) { if(theOr.IsClipped(mask)) { // //----------------------------------- // Clip each vertex against the plane //----------------------------------- // #if HUNT_CLIP_ERROR DEBUG_STREAM << l << ": " << '\n'; #endif for(k=0;k<srcPolygon.length;k++) { k1 = (k+1) < srcPolygon.length ? k+1 : 0; theTest = srcPolygon.clipPerVertex[k]; // //---------------------------------------------------- // If this vertex is inside the viewing space, copy it // directly to the clipping buffer //---------------------------------------------------- // if(theTest.IsClipped(mask) == 0) { firstIsIn = true; dstPolygon.coords[dstPolygon.length] = srcPolygon.coords[k]; #if HUNT_CLIP_ERROR DEBUG_STREAM << k << " goes " << setiosflags( ios::scientific) << setprecision(20) << srcPolygon.coords[k].x << " " << srcPolygon.coords[k].y << " " << srcPolygon.coords[k].z << " " << srcPolygon.coords[k].w << '\n'; #endif dstPolygon.clipPerVertex[dstPolygon.length] = srcPolygon.clipPerVertex[k]; dstPolygon.colors[dstPolygon.length] = srcPolygon.colors[k]; dstPolygon.texCoords[dstPolygon.length] = srcPolygon.texCoords[k]; dstPolygon.length++; // //------------------------------------------------------- // We don't need to clip this edge if the next vertex is // also in the viewing space, so just move on to the next // vertex //------------------------------------------------------- // if(srcPolygon.clipPerVertex[k1].IsClipped(mask) == 0) { continue; } } // //--------------------------------------------------------- // This vertex is outside the viewing space, so if the next // vertex is also outside the viewing space, no clipping is // needed and we throw this vertex away. Since only one // clipping plane is involved, it must be in the same space // as the first vertex //--------------------------------------------------------- // else { firstIsIn = false; if(srcPolygon.clipPerVertex[k1].IsClipped(mask) != 0) { Verify( srcPolygon.clipPerVertex[k1].IsClipped(mask) == srcPolygon.clipPerVertex[k].IsClipped(mask) ); continue; } } // //------------------------------------------- // Find the clipping interval from bc0 to bc1 //------------------------------------------- // if(firstIsIn == true) { a = GetLerpFactor (l, srcPolygon.coords[k], srcPolygon.coords[k1]); Verify(a >= 0.0f && a <= 1.0f); // //------------------------------ // Lerp the homogeneous position //------------------------------ // dstPolygon.coords[dstPolygon.length].Lerp( srcPolygon.coords[k], srcPolygon.coords[k1], a ); #if HUNT_CLIP_ERROR DEBUG_STREAM << "True " << a << " " << k << " " << k1 << " we get " << dstPolygon.length << '\n'; DEBUG_STREAM << setiosflags( ios::scientific) << setprecision(20) << dstPolygon.coords[dstPolygon.length].x << " " << dstPolygon.coords[dstPolygon.length].y << " " << dstPolygon.coords[dstPolygon.length].z << " " << dstPolygon.coords[dstPolygon.length].w << '\n'; #endif DoClipTrick(dstPolygon.coords[dstPolygon.length], l); // //---------------------------------------------------------- // If there are colors, lerp them in screen space for now as // most cards do that anyway //---------------------------------------------------------- // #if COLOR_AS_DWORD dstPolygon.colors[dstPolygon.length] = Color_DWORD_Lerp( srcPolygon.colors[k], srcPolygon.colors[k1], a ); #else dstPolygon.colors[dstPolygon.length].Lerp( srcPolygon.colors[k], srcPolygon.colors[k1], a ); #endif // //----------------------------------------------------- // If there are texture uv's, we need to lerp them in a // perspective correct manner //----------------------------------------------------- // dstPolygon.texCoords[dstPolygon.length].Lerp ( srcPolygon.texCoords[k], srcPolygon.texCoords[k1], a ); } else { a = GetLerpFactor (l, srcPolygon.coords[k1], srcPolygon.coords[k]); Verify(a >= 0.0f && a <= 1.0f); // //------------------------------ // Lerp the homogeneous position //------------------------------ // dstPolygon.coords[dstPolygon.length].Lerp( srcPolygon.coords[k1], srcPolygon.coords[k], a ); #if HUNT_CLIP_ERROR DEBUG_STREAM << "False " << a << " " << k << " " << k1 << " we get " << dstPolygon.length << '\n'; DEBUG_STREAM << setiosflags( ios::scientific) << setprecision(20) << dstPolygon.coords[dstPolygon.length].x << " " << dstPolygon.coords[dstPolygon.length].y << " " << dstPolygon.coords[dstPolygon.length].z << " " << dstPolygon.coords[dstPolygon.length].w << '\n'; #endif DoClipTrick(dstPolygon.coords[dstPolygon.length], l); // //---------------------------------------------------------- // If there are colors, lerp them in screen space for now as // most cards do that anyway //---------------------------------------------------------- // #if COLOR_AS_DWORD dstPolygon.colors[dstPolygon.length] = Color_DWORD_Lerp( srcPolygon.colors[k1], srcPolygon.colors[k], a ); #else dstPolygon.colors[dstPolygon.length].Lerp( srcPolygon.colors[k1], srcPolygon.colors[k], a ); #endif // //----------------------------------------------------- // If there are texture uv's, we need to lerp them in a // perspective correct manner //----------------------------------------------------- // dstPolygon.texCoords[dstPolygon.length].Lerp ( srcPolygon.texCoords[k1], srcPolygon.texCoords[k], a ); } // //------------------------------------- // We have to generate a new clip state //------------------------------------- // dstPolygon.clipPerVertex[dstPolygon.length].Clip4dVertex(&dstPolygon.coords[dstPolygon.length]); // //---------------------------------- // Bump the new polygon vertex count //---------------------------------- // dstPolygon.length++; } // //----------------------------------------------- // Swap source and destination buffer pointers in // preparation for the next plane test //----------------------------------------------- // srcPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); srcPolygon.colors = clipBuffer[dstBuffer].colors.GetData(); srcPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); srcPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); srcPolygon.length = dstPolygon.length; dstBuffer = !dstBuffer; dstPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); dstPolygon.colors = clipBuffer[dstBuffer].colors.GetData(); dstPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); dstPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); dstPolygon.length = 0; } mask = mask << 1; } theNewOr = 0; for(k=0;k<srcPolygon.length;k++) { theNewOr |= srcPolygon.clipPerVertex[k]; } #if HUNT_CLIP_ERROR DEBUG_STREAM << "TheOR: " << hex << theNewOr.GetClippingState() << dec << '\n'; #endif theOr = theNewOr; } while (theNewOr != 0 && loop--); // //-------------------------------------------------- // could not clip this rare case, just ignore it //-------------------------------------------------- // if(theNewOr != 0) { testList[i] = 0; continue; } // //-------------------------------------------------- // Move the most recent polygon into the clip buffer //-------------------------------------------------- // #if HUNT_CLIP_ERROR DEBUG_STREAM << "Final: " << srcPolygon.length << '\n'; #endif for(k=0;k<srcPolygon.length;k++) { int clipped_index = myNumberUsedClipVertex + k; #if HUNT_CLIP_ERROR DEBUG_STREAM << setiosflags( ios::scientific) << setprecision(20) << srcPolygon.coords[k].x << " " << srcPolygon.coords[k].y << " " << srcPolygon.coords[k].z << " " << srcPolygon.coords[k].w << '\n'; #endif (*clipExtraCoords)[clipped_index] = srcPolygon.coords[k]; (*clipExtraColors)[clipped_index] = srcPolygon.colors[k]; (*clipExtraTexCoords)[clipped_index] = srcPolygon.texCoords[k]; } numberVerticesPerPolygon = srcPolygon.length; #if HUNT_CLIP_ERROR DEBUG_STREAM << "---" << '\n'; #endif (*clipExtraLength)[myNumberUsedClipLength] = numberVerticesPerPolygon; #ifdef _ARMOR (*clipExtraLength)[myNumberUsedClipLength] |= 0x8000; #endif } myNumberUsedClipVertex += numberVerticesPerPolygon; myNumberUsedClipLength++; ret++; // clip // dont draw the original testList[i] = 0; } } Check_Object(vt); gos_vertices = vt->GetActualVertexPool(); numGOSVertices = 0; gos_indices = vt->GetActualIndexPool(); numGOSIndices = 0; unsigned short strideIndex; for(j=0,strideIndex=0;j<*usedNrOfPoints;j++) { if((*visibleIndexedVertices)[j] == 0) { strideIndex++; } else { indexOffset[j] = static_cast<unsigned short>(j-strideIndex); GOSCopyData( &gos_vertices[numGOSVertices], transformedCoords->GetData(), colors, texCoords, j ); #ifdef LAB_ONLY if(gShowClippedPolys) { gos_vertices[numGOSVertices].argb = 0xff0000ff; gos_vertices[numGOSVertices].u = 0.0f; gos_vertices[numGOSVertices].v = 0.0f; } #endif numGOSVertices++; } } for(i=0,j=0;i<*usedNrOfTriangles;j+=3,++i) { if(testList[i] == 0) { continue; } Verify((vt->GetLastIndex() + 3 + numGOSIndices) < vt->GetLength()); Verify(indexOffset[index[j]] < numGOSVertices); gos_indices[numGOSIndices] = indexOffset[index[j]]; Verify(indexOffset[index[j+2]] < numGOSVertices); gos_indices[numGOSIndices+1] = indexOffset[index[j+2]]; Verify(indexOffset[index[j+1]] < numGOSVertices); gos_indices[numGOSIndices+2] = indexOffset[index[j+1]]; numGOSIndices += 3; } unsigned short stride; if(myNumberUsedClipLength > 0) { for(i=0,j=0;i<myNumberUsedClipLength;i++) { #ifdef _ARMOR stride = static_cast<unsigned short>((*clipExtraLength)[i] & 0x7fff); #else stride = static_cast<unsigned short>((*clipExtraLength)[i]); #endif for(k=1;k<stride-1;k++) { Verify((vt->GetLast() + 3 + numGOSVertices) < vt->GetLength()); Verify((vt->GetLastIndex() + 3 + numGOSIndices) < vt->GetLength()); GOSCopyTriangleData( &gos_vertices[numGOSVertices], clipExtraCoords->GetData(), clipExtraColors->GetData(), clipExtraTexCoords->GetData(), j, j+k+1, j+k ); #ifdef LAB_ONLY if(gShowClippedPolys) { if((*clipExtraLength)[i] & 0x8000) { gos_vertices[numGOSVertices].argb = 0xffff0000; gos_vertices[numGOSVertices].u = 0.0f; gos_vertices[numGOSVertices].v = 0.0f; gos_vertices[numGOSVertices+1].argb = 0xffff0000; gos_vertices[numGOSVertices+1].u = 0.0f; gos_vertices[numGOSVertices+1].v = 0.0f; gos_vertices[numGOSVertices+2].argb = 0xffff0000; gos_vertices[numGOSVertices+2].u = 0.0f; gos_vertices[numGOSVertices+2].v = 0.0f; } else { gos_vertices[numGOSVertices].argb = 0xffff9999; gos_vertices[numGOSVertices].u = 0.0f; gos_vertices[numGOSVertices].v = 0.0f; gos_vertices[numGOSVertices+1].argb = 0xffff9999; gos_vertices[numGOSVertices+1].u = 0.0f; gos_vertices[numGOSVertices+1].v = 0.0f; gos_vertices[numGOSVertices+2].argb = 0xffff9999; gos_vertices[numGOSVertices+2].u = 0.0f; gos_vertices[numGOSVertices+2].v = 0.0f; } } #endif Verify((vt->GetLastIndex() + 3 + numGOSIndices) < vt->GetLength()); Verify(numGOSIndices%3 == 0); gos_indices[numGOSIndices] = (unsigned short)numGOSVertices; gos_indices[numGOSIndices+1] = (unsigned short)(numGOSVertices + 1); gos_indices[numGOSIndices+2] = (unsigned short)(numGOSVertices + 2); numGOSVertices += 3; numGOSIndices += 3; } j += stride; } #if HUNT_CLIP_ERROR DEBUG_STREAM << "***" << endl << endl; #endif } vt->Increase(numGOSVertices); vt->IncreaseIndex(numGOSIndices); return numGOSIndices; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Now it gets serious int MLRIndexedPolyMesh::Clip(MLRClippingState clippingFlags, GOSVertexPool *vt) { StartCycleTiming( &Statistics::MLR_ClipTime ); SET_MLRIndexedPolyMesh_CLIP(); Check_Object(this); unsigned short stride, l; int i, j, k, ret = 0; int len = lengths.GetLength(); Verify(len == testList.GetLength()); Verify(clippingFlags.GetClippingState() != 0); // //-------------------------------------- // See if we don't have to draw anything //-------------------------------------- // if(len <= 0) { visible = 0; CLEAR_MLRIndexedPolyMesh_CLIP(); EndCycleTiming( &Statistics::MLR_ClipTime ); return visible; } int mask, end, k0, k1, ct=0; Scalar a=0.0f; // Scalar bc0=0.0f, bc1=0.0f; int myNumberUsedClipVertex, myNumberUsedClipIndex, myNumberUsedClipLength; myNumberUsedClipVertex = 0; myNumberUsedClipIndex = 0; myNumberUsedClipLength = 0; Verify(index.GetLength() > 0); if(visibleIndexedVerticesKey == false) { FindVisibleVertices(); } // //------------------------ // Handle the indexed case //------------------------ // // //----------------------------------------------------------------- // Step through each vertex and check visibility // backfaced polygons //----------------------------------------------------------------- // k = transformedCoords.GetLength(); Stuff::Vector4D *v4d = transformedCoords.GetData(); MLRClippingState *cs = clipPerVertex.GetData(); for(i=0;i<k;i++,v4d++,cs++) { if(visibleIndexedVertices[i] == 0) { continue; } cs->SetClippingState(0); if( clippingFlags.IsFarClipped() && v4d->w < v4d->z) { cs->SetFarClip(); } if( clippingFlags.IsNearClipped() && v4d->z < 0.0f) { cs->SetNearClip(); } if( clippingFlags.IsRightClipped() && v4d->x < 0.0f) { cs->SetRightClip(); } if( clippingFlags.IsLeftClipped() && v4d->w < v4d->x) { cs->SetLeftClip(); } if( clippingFlags.IsBottomClipped() && v4d->y < 0.0f) { cs->SetBottomClip(); } if(clippingFlags.IsTopClipped() && v4d->w < v4d->y) { cs->SetTopClip(); } #ifdef LAB_ONLY if( (*cs)==0) { Statistics::MLR_NonClippedVertices++; } else { Statistics::MLR_ClippedVertices++; } #endif } // initialize visibleIndexedVertices memset(visibleIndexedVertices.GetData(), 0, visibleIndexedVertices.GetSize()); // //----------------------------------------------------------------- // Step through each polygon, making sure that we don't try to clip // backfaced polygons //----------------------------------------------------------------- // for(i=0,j=0;i<len;i++) { stride = lengths[i]; if(testList[i] == 0) { j += stride; continue; } // //--------------------------------------------------------------- // Test each vertex of the polygon against the allowed clipping // planes, and accumulate status for which planes always clip and // which planes clipped at least once //--------------------------------------------------------------- // theAnd.SetClippingState(0x3f); theOr.SetClippingState(0); end = j+stride; for(k=j;k<end;k++) { theAnd &= clipPerVertex[index[k]]; theOr |= clipPerVertex[index[k]]; } theAnd = theOr = 0; //ASSUME NO CLIPPING NEEDED FOR MC2. Its just not done here! // //------------------------------------------------------------------- // If any bit is set for all vertices, then the polygon is completely // outside the viewing space and we don't have to draw it. On the // other hand, if no bits at all were ever set, we can do a trivial // accept of the polygon //------------------------------------------------------------------- // if (theAnd != 0) { testList[i] = 0; #ifdef LAB_ONLY Statistics::MLR_PolysClippedButOutside++; #endif } else if (theOr == 0) { ret++; for(k=j;k<end;k++) { visibleIndexedVertices[index[k]] = 1; } #ifdef LAB_ONLY Statistics::MLR_PolysClippedButInside++; #endif } // //----------------------------------------------------------------- // It is not a trivial case, so we must now do real clipping on the // polygon //----------------------------------------------------------------- // else { unsigned short numberVerticesPerPolygon = 0; // //--------------------------------------------------------------- // Handle the case of a single clipping plane by stepping through // the vertices and finding the edge it originates //--------------------------------------------------------------- // if (theOr.GetNumberOfSetBits() == 1) { #ifdef LAB_ONLY Statistics::MLR_PolysClippedButOnePlane++; #endif for(k=j;k<end;k++) { k0 = index[k]; k1 = index[(k+1) < end ? k+1 : j]; // //---------------------------------------------------- // If this vertex is inside the viewing space, copy it // directly to the clipping buffer //---------------------------------------------------- // int clipped_index = myNumberUsedClipVertex + numberVerticesPerPolygon; theTest = clipPerVertex[k0]; if(theTest == 0) { clipExtraCoords[clipped_index] = transformedCoords[k0]; Verify((*actualColors).GetLength() > 0); clipExtraColors[clipped_index] = (*actualColors)[k0]; Verify(texCoords.GetLength() > 0); clipExtraTexCoords[clipped_index] = texCoords[k0]; numberVerticesPerPolygon++; clipped_index++; // //------------------------------------------------------- // We don't need to clip this edge if the next vertex is // also in the viewing space, so just move on to the next // vertex //------------------------------------------------------- // if(clipPerVertex[k1] == 0) { continue; } } // //--------------------------------------------------------- // This vertex is outside the viewing space, so if the next // vertex is also outside the viewing space, no clipping is // needed and we throw this vertex away. Since only one // clipping plane is involved, it must be in the same space // as the first vertex //--------------------------------------------------------- // else if(clipPerVertex[k1] != 0) { Verify(clipPerVertex[k1] == clipPerVertex[k0]); continue; } // //-------------------------------------------------- // We now find the distance along the edge where the // clipping plane will intersect //-------------------------------------------------- // mask = 1; theTest |= clipPerVertex[k1]; // //----------------------------------------------------- // Find the boundary conditions that match our clipping // plane //----------------------------------------------------- // for (l=0; l<MLRClippingState::NextBit; l++) { if(theTest.IsClipped(mask)) { // GetDoubleBC(l, bc0, bc1, transformedCoords[k0], transformedCoords[k1]); // //------------------------------------------- // Find the clipping interval from bc0 to bc1 //------------------------------------------- // // Verify(!Close_Enough(bc0, bc1)); // a = bc0 / (bc0 - bc1); a = GetLerpFactor(l, transformedCoords[k0], transformedCoords[k1]); Verify(a >= 0.0f && a <= 1.0f); ct = l; break; } mask <<= 1; } // //------------------------------ // Lerp the homogeneous position //------------------------------ // clipExtraCoords[clipped_index].Lerp( transformedCoords[k0], transformedCoords[k1], a ); clipExtraCoords[clipped_index][clipTrick[ct][0]] = clipTrick[ct][1] ? clipExtraCoords[clipped_index].w : 0.0f; // //---------------------------------------------------------- // If there are colors, lerp them in screen space for now as // most cards do that anyway //---------------------------------------------------------- // Verify((*actualColors).GetLength() > 0); #if COLOR_AS_DWORD clipExtraColors[clipped_index] = Color_DWORD_Lerp ( (*actualColors)[k0], (*actualColors)[k1], a ); #else clipExtraColors[clipped_index].Lerp( (*actualColors)[k0], (*actualColors)[k1], a ); #endif // //----------------------------------------------------- // If there are texture uv's, we need to lerp them in a // perspective correct manner //----------------------------------------------------- // Verify(texCoords.GetLength() > 0); clipExtraTexCoords[clipped_index].Lerp ( texCoords[k0], texCoords[k1], a ); // //-------------------------------- // Bump the polygon's vertex count //-------------------------------- // numberVerticesPerPolygon++; } } // //--------------------------------------------------------------- // We have to handle multiple planes. We do this by creating two // buffers and we switch between them as we clip plane by plane //--------------------------------------------------------------- // else { #ifdef LAB_ONLY Statistics::MLR_PolysClippedButGOnePlane++; #endif ClipPolygon clipBuffer[2]; ClipData srcPolygon, dstPolygon; int dstBuffer = 1; Verify((*actualColors).GetLength() > 0); Verify(texCoords.GetLength() > 0); srcPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); srcPolygon.colors = clipBuffer[dstBuffer].colors.GetData(); srcPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); srcPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); // //---------------------------------------------------------- // unravel and copy the original data into the source buffer //---------------------------------------------------------- // for(k=j,l=0;k<end;k++,l++) { int indexK = index[k]; srcPolygon.coords[l] = transformedCoords[indexK]; srcPolygon.colors[l] = (*actualColors)[indexK]; srcPolygon.texCoords[l] = texCoords[indexK]; srcPolygon.clipPerVertex[l] = clipPerVertex[indexK]; } srcPolygon.length = l; srcPolygon.flags |= 3; // //-------------------------------- // Point to the destination buffer //-------------------------------- // dstBuffer = 0; dstPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); dstPolygon.colors = clipBuffer[dstBuffer].colors.GetData(); dstPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); dstPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); dstPolygon.flags = srcPolygon.flags; dstPolygon.length = 0; // //----------------------------------------------------------- // Spin through each plane that clipped the primitive and use // it to actually clip the primitive //----------------------------------------------------------- // mask = 1; for(l=0; l<MLRClippingState::NextBit; l++) { if(theOr.IsClipped(mask)) { // //----------------------------------- // Clip each vertex against the plane //----------------------------------- // for(k=0;k<srcPolygon.length;k++) { k1 = (k+1) < srcPolygon.length ? k+1 : 0; theTest = srcPolygon.clipPerVertex[k]; // //---------------------------------------------------- // If this vertex is inside the viewing space, copy it // directly to the clipping buffer //---------------------------------------------------- // if(theTest.IsClipped(mask) == 0) { dstPolygon.coords[dstPolygon.length] = srcPolygon.coords[k]; dstPolygon.clipPerVertex[dstPolygon.length] = srcPolygon.clipPerVertex[k]; if(srcPolygon.flags & 0x1) { dstPolygon.colors[dstPolygon.length] = srcPolygon.colors[k]; } if(srcPolygon.flags & 0x2) { dstPolygon.texCoords[dstPolygon.length] = srcPolygon.texCoords[k]; } dstPolygon.length++; // //------------------------------------------------------- // We don't need to clip this edge if the next vertex is // also in the viewing space, so just move on to the next // vertex //------------------------------------------------------- // if(srcPolygon.clipPerVertex[k1].IsClipped(mask) == 0) { continue; } } // //--------------------------------------------------------- // This vertex is outside the viewing space, so if the next // vertex is also outside the viewing space, no clipping is // needed and we throw this vertex away. Since only one // clipping plane is involved, it must be in the same space // as the first vertex //--------------------------------------------------------- // else if(srcPolygon.clipPerVertex[k1].IsClipped(mask) != 0) { Verify( srcPolygon.clipPerVertex[k1].IsClipped(mask) == srcPolygon.clipPerVertex[k].IsClipped(mask) ); continue; } // //------------------------------------------- // Find the clipping interval from bc0 to bc1 //------------------------------------------- // // GetDoubleBC(l, bc0, bc1, srcPolygon.coords[k], srcPolygon.coords[k1]); // Verify(!Close_Enough(bc0, bc1)); // a = bc0 / (bc0 - bc1); a = GetLerpFactor (l, srcPolygon.coords[k], srcPolygon.coords[k1]); Verify(a >= 0.0f && a <= 1.0f); // //------------------------------ // Lerp the homogeneous position //------------------------------ // dstPolygon.coords[dstPolygon.length].Lerp( srcPolygon.coords[k], srcPolygon.coords[k1], a ); dstPolygon.coords[dstPolygon.length][clipTrick[l][0]] = clipTrick[l][1] ? dstPolygon.coords[dstPolygon.length].w : 0.0f; // //---------------------------------------------------------- // If there are colors, lerp them in screen space for now as // most cards do that anyway //---------------------------------------------------------- // if(srcPolygon.flags & 1) { #if COLOR_AS_DWORD dstPolygon.colors[dstPolygon.length] = Color_DWORD_Lerp( srcPolygon.colors[k], srcPolygon.colors[k1], a ); #else dstPolygon.colors[dstPolygon.length].Lerp( srcPolygon.colors[k], srcPolygon.colors[k1], a ); #endif } // //----------------------------------------------------- // If there are texture uv's, we need to lerp them in a // perspective correct manner //----------------------------------------------------- // if(srcPolygon.flags & 2) { dstPolygon.texCoords[dstPolygon.length].Lerp ( srcPolygon.texCoords[k], srcPolygon.texCoords[k1], a ); } // //------------------------------------- // We have to generate a new clip state //------------------------------------- // dstPolygon.clipPerVertex[dstPolygon.length].SetClippingState(0); switch (l) { case 0: if(clippingFlags.IsTopClipped()) { if(dstPolygon.coords[dstPolygon.length].w < dstPolygon.coords[dstPolygon.length].y) { dstPolygon.clipPerVertex[dstPolygon.length].SetTopClip(); } } case 1: if(clippingFlags.IsBottomClipped()) { if(dstPolygon.coords[dstPolygon.length].y < 0.0f) { dstPolygon.clipPerVertex[dstPolygon.length].SetBottomClip(); } } case 2: if(clippingFlags.IsLeftClipped()) { if(dstPolygon.coords[dstPolygon.length].w < dstPolygon.coords[dstPolygon.length].x) { dstPolygon.clipPerVertex[dstPolygon.length].SetLeftClip(); } } case 3: if(clippingFlags.IsRightClipped()) { if(dstPolygon.coords[dstPolygon.length].x < 0.0f) { dstPolygon.clipPerVertex[dstPolygon.length].SetRightClip(); } } case 4: if(clippingFlags.IsNearClipped()) { if(dstPolygon.coords[dstPolygon.length].z < 0.0f) { dstPolygon.clipPerVertex[dstPolygon.length].SetNearClip(); } } case 5: if(clippingFlags.IsFarClipped()) { if(dstPolygon.coords[dstPolygon.length].w < dstPolygon.coords[dstPolygon.length].z) { dstPolygon.clipPerVertex[dstPolygon.length].SetFarClip(); } } } // //---------------------------------- // Bump the new polygon vertex count //---------------------------------- // dstPolygon.length++; } // //----------------------------------------------- // Swap source and destination buffer pointers in // preparation for the next plane test //----------------------------------------------- // srcPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); srcPolygon.colors = clipBuffer[dstBuffer].colors.GetData(); srcPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); srcPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); srcPolygon.length = dstPolygon.length; dstBuffer = !dstBuffer; dstPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); dstPolygon.colors = clipBuffer[dstBuffer].colors.GetData(); dstPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); dstPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); dstPolygon.length = 0; } mask = mask << 1; } // //-------------------------------------------------- // Move the most recent polygon into the clip buffer //-------------------------------------------------- // for(k=0;k<srcPolygon.length;k++) { int clipped_index = myNumberUsedClipVertex + k; clipExtraCoords[clipped_index] = srcPolygon.coords[k]; if(srcPolygon.flags & 0x1) { clipExtraColors[clipped_index] = srcPolygon.colors[k]; } if(srcPolygon.flags & 0x2) { clipExtraTexCoords[clipped_index] = srcPolygon.texCoords[k]; } } numberVerticesPerPolygon = srcPolygon.length; } clipExtraLength[myNumberUsedClipLength] = numberVerticesPerPolygon; myNumberUsedClipVertex += numberVerticesPerPolygon; myNumberUsedClipLength++; ret++; // clip // dont draw the original testList[i] = 0; } j += stride; } Check_Object(vt); gos_vertices = vt->GetActualVertexPool(); numGOSVertices = 0; gos_indices = vt->GetActualIndexPool(); numGOSIndices = 0; k = visibleIndexedVertices.GetLength(); for(j=0,stride=0;j<k;j++) { if(visibleIndexedVertices[j] == 0) { stride++; } else { visibleIndexedVertices[j] = stride; // //-------------------------------------------------------- // JM claims all vertices are in. lets check it. who knows //-------------------------------------------------------- // Verify(transformedCoords[j].x >= 0.0f && transformedCoords[j].x <= transformedCoords[j].w ); Verify(transformedCoords[j].y >= 0.0f && transformedCoords[j].y <= transformedCoords[j].w ); Verify(transformedCoords[j].z >= 0.0f && transformedCoords[j].z <= transformedCoords[j].w ); GOSCopyData( &gos_vertices[numGOSVertices], transformedCoords.GetData(), actualColors->GetData(), texCoords.GetData(), j ); numGOSVertices++; } } for(i=0,j=0;i<len;i++) { stride = lengths[i]; Verify(stride >= 3); if(testList[i] == 0) { j += stride; continue; } for(k=1;k<stride-1;k++) { Verify((vt->GetLastIndex() + 3 + numGOSIndices) < vt->GetLength()); gos_indices[numGOSIndices] = (unsigned short)(index[j] - visibleIndexedVertices[index[j]]); gos_indices[numGOSIndices+1] = (unsigned short)(index[j+k+1] - visibleIndexedVertices[index[j+k+1]]); gos_indices[numGOSIndices+2] = (unsigned short)(index[j+k] - visibleIndexedVertices[index[j+k]]); numGOSIndices += 3; } j += stride; } if(myNumberUsedClipLength > 0) { for(i=0,j=0;i<myNumberUsedClipLength;i++) { stride = clipExtraLength[i]; for(k=1;k<stride-1;k++) { Verify((vt->GetLast() + 3 + numGOSVertices) < vt->GetLength()); Verify((vt->GetLastIndex() + 3 + numGOSIndices) < vt->GetLength()); GOSCopyTriangleData( &gos_vertices[numGOSVertices], clipExtraCoords.GetData(), clipExtraColors.GetData(), clipExtraTexCoords.GetData(), j, j+k+1, j+k ); Verify(numGOSIndices%3 == 0); gos_indices[numGOSIndices] = numGOSVertices; gos_indices[numGOSIndices+1] = (unsigned short)(numGOSVertices + 1); gos_indices[numGOSIndices+2] = (unsigned short)(numGOSVertices + 2); numGOSVertices += 3; numGOSIndices += 3; } j += stride; } } vt->IncreaseIndex(numGOSIndices); vt->Increase(numGOSVertices); visible = numGOSVertices ? 1 : 0; if(visible) { } else { } CLEAR_MLRIndexedPolyMesh_CLIP(); EndCycleTiming( &Statistics::MLR_ClipTime ); return ret; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MLRLightMap::DrawLightMaps(MLRSorter *sorter) { Check_Object(stream); void *ptr, *end = stream->GetPointer(); Stuff::Matrix4D *currentMatrix=NULL; MLRClippingState currentClippingState; MLRState currentState, masterState; unsigned short stride; int i, pointerValue; Stuff::Point3D *coords = NULL; Stuff::RGBAColor color; Stuff::RGBAColor *colors = NULL; Vector2DScalar *texCoords = NULL; DWORD argb = 0xffffffff; Check_Object(vertexPool); GOSVertex* gos_vertices = vertexPool->GetActualVertexPool(); int numGOSVertices = 0; int msd; MemoryStreamData type; stream->Rewind(); ptr = stream->GetPointer(); while(ptr < end) { *stream >> msd; type = static_cast<MemoryStreamData>(msd); switch(msd) { case Matrix4D: *stream >> pointerValue; currentMatrix = reinterpret_cast<Stuff::Matrix4D*>(pointerValue); break; case ClippingState: currentClippingState.Load(stream); break; case MasterRenderState: masterState.Load(stream, Current_MLR_Version); break; case LightMapRenderState: { MLRState lightmapState; lightmapState.Load(stream, Current_MLR_Version); lightmapState.Combine(masterState, lightmapState); if(numGOSVertices && (lightmapState != currentState)) { vertexPool->Increase(numGOSVertices); SortData *sd = sorter->SetRawData ( gos_vertices, numGOSVertices, currentState, SortData::TriList ); if(currentState.GetDrawNowMode()==MLRState::DrawNowOnMode) { SortData::DrawFunc drawFunc = sd->Draw[sd->type]; (sd->*drawFunc)(); } else { sorter->AddSortRawData(sd); } gos_vertices = vertexPool->GetActualVertexPool(); numGOSVertices = 0; } currentState = lightmapState; } break; case Polygon: { *stream >> stride; Verify(stride<=Limits::Max_Number_Vertices_Per_Polygon); *stream >> color; argb = GOSCopyColor(&color); coords = (Stuff::Point3D *)stream->GetPointer(); stream->AdvancePointer(stride*sizeof(Stuff::Point3D)); texCoords = (Vector2DScalar *)stream->GetPointer(); stream->AdvancePointer(stride*sizeof(Vector2DScalar)); MLRClippingState theAnd(0x3f), theOr(0); MLRClippingState *cs = clippingStates->GetData(); Vector4D *v4d = transformedCoords->GetData(); for(i=0;i<stride;i++,v4d++,cs++) { v4d->Multiply(coords[i], *currentMatrix); if(currentClippingState!=0) { cs->Clip4dVertex(v4d); theAnd &= *cs; theOr |= *cs; } #if defined(_ARMOR) else { Verify((*transformedCoords)[i].x >= 0.0f && (*transformedCoords)[i].x <= (*transformedCoords)[i].w ); Verify((*transformedCoords)[i].y >= 0.0f && (*transformedCoords)[i].y <= (*transformedCoords)[i].w ); Verify((*transformedCoords)[i].z >= 0.0f && (*transformedCoords)[i].z <= (*transformedCoords)[i].w ); } #endif } if(theOr == 0) { for(i=1;i<stride-1;i++) { Verify((vertexPool->GetLast() + 3 + numGOSVertices) < vertexPool->GetLength()); GOSCopyTriangleData( &gos_vertices[numGOSVertices], transformedCoords->GetData(), texCoords, 0, i + 1, i ); gos_vertices[numGOSVertices].argb = argb; gos_vertices[numGOSVertices+1].argb = argb; gos_vertices[numGOSVertices+2].argb = argb; numGOSVertices+=3; } } else { if(theAnd != 0) { break; } else { int k, k0, k1, l, mask, ct = 0; Scalar a = 0.0f; int numberVerticesPerPolygon = 0; // //--------------------------------------------------------------- // Handle the case of a single clipping plane by stepping through // the vertices and finding the edge it originates //--------------------------------------------------------------- // bool firstIsIn; MLRClippingState theTest; if (theOr.GetNumberOfSetBits() == 1) { #ifdef LAB_ONLY Set_Statistic(PolysClippedButOnePlane, PolysClippedButOnePlane+1); #endif for(k=0;k<stride;k++) { int clipped_index = numberVerticesPerPolygon; k0 = k; k1 = (k+1) < stride ? k+1 : 0; // //---------------------------------------------------- // If this vertex is inside the viewing space, copy it // directly to the clipping buffer //---------------------------------------------------- // theTest = (*clippingStates)[k0]; if(theTest == 0) { firstIsIn = true; (*clipExtraCoords)[clipped_index] = (*transformedCoords)[k0]; Verify((*clipExtraCoords)[clipped_index].x >= 0.0f && (*clipExtraCoords)[clipped_index].x <= (*clipExtraCoords)[clipped_index].w ); Verify((*clipExtraCoords)[clipped_index].y >= 0.0f && (*clipExtraCoords)[clipped_index].y <= (*clipExtraCoords)[clipped_index].w ); Verify((*clipExtraCoords)[clipped_index].z >= 0.0f && (*clipExtraCoords)[clipped_index].z <= (*clipExtraCoords)[clipped_index].w ); (*clipExtraTexCoords)[clipped_index] = texCoords[k0]; numberVerticesPerPolygon++; clipped_index++; // //------------------------------------------------------- // We don't need to clip this edge if the next vertex is // also in the viewing space, so just move on to the next // vertex //------------------------------------------------------- // if((*clippingStates)[k1] == 0) { continue; } } // //--------------------------------------------------------- // This vertex is outside the viewing space, so if the next // vertex is also outside the viewing space, no clipping is // needed and we throw this vertex away. Since only one // clipping plane is involved, it must be in the same space // as the first vertex //--------------------------------------------------------- // else { firstIsIn = false; if((*clippingStates)[k1] != 0) { Verify((*clippingStates)[k1] == (*clippingStates)[k0]); continue; } } // //-------------------------------------------------- // We now find the distance along the edge where the // clipping plane will intersect //-------------------------------------------------- // mask = 1; theTest |= (*clippingStates)[k1]; // //----------------------------------------------------- // Find the boundary conditions that match our clipping // plane //----------------------------------------------------- // for (l=0; l<MLRClippingState::NextBit; l++) { if(theTest.IsClipped(mask)) { // GetDoubleBC(l, bc0, bc1, transformedCoords[k0], transformedCoords[k1]); // //------------------------------------------- // Find the clipping interval from bc0 to bc1 //------------------------------------------- // if(firstIsIn==true) { a = GetLerpFactor(l, (*transformedCoords)[k0], (*transformedCoords)[k1]); } else { a = GetLerpFactor(l, (*transformedCoords)[k1], (*transformedCoords)[k0]); } Verify(a >= 0.0f && a <= 1.0f); ct = l; break; } mask <<= 1; } // //------------------------------ // Lerp the homogeneous position //------------------------------ // if(firstIsIn==true) { (*clipExtraCoords)[clipped_index].Lerp( (*transformedCoords)[k0], (*transformedCoords)[k1], a ); DoClipTrick((*clipExtraCoords)[clipped_index], ct); Verify((*clipExtraCoords)[clipped_index].x >= 0.0f && (*clipExtraCoords)[clipped_index].x <= (*clipExtraCoords)[clipped_index].w ); Verify((*clipExtraCoords)[clipped_index].y >= 0.0f && (*clipExtraCoords)[clipped_index].y <= (*clipExtraCoords)[clipped_index].w ); Verify((*clipExtraCoords)[clipped_index].z >= 0.0f && (*clipExtraCoords)[clipped_index].z <= (*clipExtraCoords)[clipped_index].w ); // //----------------------------------------------------- // If there are texture uv's, we need to lerp them in a // perspective correct manner //----------------------------------------------------- // (*clipExtraTexCoords)[clipped_index].Lerp ( texCoords[k0], texCoords[k1], a ); } else { (*clipExtraCoords)[clipped_index].Lerp( (*transformedCoords)[k1], (*transformedCoords)[k0], a ); DoClipTrick((*clipExtraCoords)[clipped_index], ct); Verify((*clipExtraCoords)[clipped_index].x >= 0.0f && (*clipExtraCoords)[clipped_index].x <= (*clipExtraCoords)[clipped_index].w ); Verify((*clipExtraCoords)[clipped_index].y >= 0.0f && (*clipExtraCoords)[clipped_index].y <= (*clipExtraCoords)[clipped_index].w ); Verify((*clipExtraCoords)[clipped_index].z >= 0.0f && (*clipExtraCoords)[clipped_index].z <= (*clipExtraCoords)[clipped_index].w ); // //----------------------------------------------------- // If there are texture uv's, we need to lerp them in a // perspective correct manner //----------------------------------------------------- // (*clipExtraTexCoords)[clipped_index].Lerp ( texCoords[k1], texCoords[k0], a ); } // //-------------------------------- // Bump the polygon's vertex count //-------------------------------- // numberVerticesPerPolygon++; } } // //--------------------------------------------------------------- // We have to handle multiple planes. We do this by creating two // buffers and we switch between them as we clip plane by plane //--------------------------------------------------------------- // else { #ifdef LAB_ONLY Set_Statistic(PolysClippedButGOnePlane, PolysClippedButGOnePlane+1); #endif ClipData2 srcPolygon, dstPolygon; int dstBuffer = 1; srcPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); srcPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); srcPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); // //---------------------------------------------------------- // unravel and copy the original data into the source buffer //---------------------------------------------------------- // for(k=0;k<stride;k++) { srcPolygon.coords[k] = (*transformedCoords)[k]; srcPolygon.texCoords[k] = texCoords[k]; srcPolygon.clipPerVertex[k] = (*clippingStates)[k]; } srcPolygon.length = stride; // //-------------------------------- // Point to the destination buffer //-------------------------------- // dstBuffer = 0; dstPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); dstPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); dstPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); dstPolygon.length = 0; // //----------------------------------------------------------- // Spin through each plane that clipped the primitive and use // it to actually clip the primitive //----------------------------------------------------------- // mask = 1; MLRClippingState theNewOr(0); int loop = 4; do { for(l=0; l<MLRClippingState::NextBit; l++) { if(theOr.IsClipped(mask)) { // //----------------------------------- // Clip each vertex against the plane //----------------------------------- // for(k=0;k<srcPolygon.length;k++) { k1 = (k+1) < srcPolygon.length ? k+1 : 0; theTest = srcPolygon.clipPerVertex[k]; // //---------------------------------------------------- // If this vertex is inside the viewing space, copy it // directly to the clipping buffer //---------------------------------------------------- // if(theTest.IsClipped(mask) == 0) { firstIsIn = true; dstPolygon.coords[dstPolygon.length] = srcPolygon.coords[k]; dstPolygon.clipPerVertex[dstPolygon.length] = srcPolygon.clipPerVertex[k]; dstPolygon.texCoords[dstPolygon.length] = srcPolygon.texCoords[k]; dstPolygon.length++; // //------------------------------------------------------- // We don't need to clip this edge if the next vertex is // also in the viewing space, so just move on to the next // vertex //------------------------------------------------------- // if(srcPolygon.clipPerVertex[k1].IsClipped(mask) == 0) { continue; } } // //--------------------------------------------------------- // This vertex is outside the viewing space, so if the next // vertex is also outside the viewing space, no clipping is // needed and we throw this vertex away. Since only one // clipping plane is involved, it must be in the same space // as the first vertex //--------------------------------------------------------- // else { firstIsIn = false; if(srcPolygon.clipPerVertex[k1].IsClipped(mask) != 0) { Verify( srcPolygon.clipPerVertex[k1].IsClipped(mask) == srcPolygon.clipPerVertex[k].IsClipped(mask) ); continue; } } // //------------------------------------------- // Find the clipping interval from bc0 to bc1 //------------------------------------------- // if(firstIsIn == true) { a = GetLerpFactor (l, srcPolygon.coords[k], srcPolygon.coords[k1]); Verify(a >= 0.0f && a <= 1.0f); // //------------------------------ // Lerp the homogeneous position //------------------------------ // dstPolygon.coords[dstPolygon.length].Lerp( srcPolygon.coords[k], srcPolygon.coords[k1], a ); DoClipTrick(dstPolygon.coords[dstPolygon.length], l); // //----------------------------------------------------- // If there are texture uv's, we need to lerp them in a // perspective correct manner //----------------------------------------------------- // dstPolygon.texCoords[dstPolygon.length].Lerp ( srcPolygon.texCoords[k], srcPolygon.texCoords[k1], a ); } else { a = GetLerpFactor (l, srcPolygon.coords[k1], srcPolygon.coords[k]); Verify(a >= 0.0f && a <= 1.0f); // //------------------------------ // Lerp the homogeneous position //------------------------------ // dstPolygon.coords[dstPolygon.length].Lerp( srcPolygon.coords[k1], srcPolygon.coords[k], a ); DoClipTrick(dstPolygon.coords[dstPolygon.length], l); // //----------------------------------------------------- // If there are texture uv's, we need to lerp them in a // perspective correct manner //----------------------------------------------------- // dstPolygon.texCoords[dstPolygon.length].Lerp ( srcPolygon.texCoords[k1], srcPolygon.texCoords[k], a ); } // //------------------------------------- // We have to generate a new clip state //------------------------------------- // dstPolygon.clipPerVertex[dstPolygon.length].Clip4dVertex(&dstPolygon.coords[dstPolygon.length]); // //---------------------------------- // Bump the new polygon vertex count //---------------------------------- // dstPolygon.length++; } // //----------------------------------------------- // Swap source and destination buffer pointers in // preparation for the next plane test //----------------------------------------------- // srcPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); srcPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); srcPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); srcPolygon.length = dstPolygon.length; dstBuffer = !dstBuffer; dstPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); dstPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); dstPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); dstPolygon.length = 0; } mask = mask << 1; } theNewOr = 0; for(k=0;k<srcPolygon.length;k++) { theNewOr |= srcPolygon.clipPerVertex[k]; } theOr == theNewOr; loop++; } while (theNewOr != 0 && loop--); Verify(theNewOr == 0); // //-------------------------------------------------- // Move the most recent polygon into the clip buffer //-------------------------------------------------- // for(k=0;k<srcPolygon.length;k++) { (*clipExtraCoords)[k] = srcPolygon.coords[k]; Verify((*clipExtraCoords)[k].x >= 0.0f && (*clipExtraCoords)[k].x <= (*clipExtraCoords)[k].w ); Verify((*clipExtraCoords)[k].y >= 0.0f && (*clipExtraCoords)[k].y <= (*clipExtraCoords)[k].w ); Verify((*clipExtraCoords)[k].z >= 0.0f && (*clipExtraCoords)[k].z <= (*clipExtraCoords)[k].w ); (*clipExtraTexCoords)[k] = srcPolygon.texCoords[k]; } numberVerticesPerPolygon = srcPolygon.length; } // clip for(i=1;i<numberVerticesPerPolygon-1;i++) { Verify((vertexPool->GetLast() + 3 + numGOSVertices) < vertexPool->GetLength()); GOSCopyTriangleData( &gos_vertices[numGOSVertices], clipExtraCoords->GetData(), clipExtraTexCoords->GetData(), 0, i + 1, i ); gos_vertices[numGOSVertices].argb = argb; gos_vertices[numGOSVertices+1].argb = argb; gos_vertices[numGOSVertices+2].argb = argb; numGOSVertices+=3; } } } } break; case PolygonWithColor: { *stream >> stride; Verify(stride<=Limits::Max_Number_Vertices_Per_Polygon); coords = (Stuff::Point3D *)stream->GetPointer(); stream->AdvancePointer(stride*sizeof(Stuff::Point3D)); colors = (Stuff::RGBAColor *)stream->GetPointer(); stream->AdvancePointer(stride*sizeof(Stuff::RGBAColor)); texCoords = (Vector2DScalar *)stream->GetPointer(); stream->AdvancePointer(stride*sizeof(Vector2DScalar)); MLRClippingState theAnd(0x3f), theOr(0); MLRClippingState *cs = clippingStates->GetData(); Vector4D *v4d = transformedCoords->GetData(); for(i=0;i<stride;i++,v4d++,cs++) { v4d->Multiply(coords[i], *currentMatrix); if(currentClippingState!=0) { cs->Clip4dVertex(v4d); theAnd &= *cs; theOr |= *cs; } #if defined(_ARMOR) else { Verify((*transformedCoords)[i].x >= 0.0f && (*transformedCoords)[i].x <= (*transformedCoords)[i].w ); Verify((*transformedCoords)[i].y >= 0.0f && (*transformedCoords)[i].y <= (*transformedCoords)[i].w ); Verify((*transformedCoords)[i].z >= 0.0f && (*transformedCoords)[i].z <= (*transformedCoords)[i].w ); } #endif } if(theOr == 0) { for(i=1;i<stride-1;i++) { Verify((vertexPool->GetLast() + 3 + numGOSVertices) < vertexPool->GetLength()); GOSCopyTriangleData( &gos_vertices[numGOSVertices], transformedCoords->GetData(), colors, texCoords, 0, i + 1, i ); numGOSVertices+=3; } } else { if(theAnd != 0) { break; } else { int k, k0, k1, l, mask, ct = 0; Scalar a = 0.0f; int numberVerticesPerPolygon = 0; // //--------------------------------------------------------------- // Handle the case of a single clipping plane by stepping through // the vertices and finding the edge it originates //--------------------------------------------------------------- // bool firstIsIn; MLRClippingState theTest; if (theOr.GetNumberOfSetBits() == 1) { #ifdef LAB_ONLY Set_Statistic(PolysClippedButOnePlane, PolysClippedButOnePlane+1); #endif for(k=0;k<stride;k++) { int clipped_index = numberVerticesPerPolygon; k0 = k; k1 = (k+1) < stride ? k+1 : 0; // //---------------------------------------------------- // If this vertex is inside the viewing space, copy it // directly to the clipping buffer //---------------------------------------------------- // theTest = (*clippingStates)[k0]; if(theTest == 0) { firstIsIn = true; (*clipExtraCoords)[clipped_index] = (*transformedCoords)[k0]; Verify((*clipExtraCoords)[clipped_index].x >= 0.0f && (*clipExtraCoords)[clipped_index].x <= (*clipExtraCoords)[clipped_index].w ); Verify((*clipExtraCoords)[clipped_index].y >= 0.0f && (*clipExtraCoords)[clipped_index].y <= (*clipExtraCoords)[clipped_index].w ); Verify((*clipExtraCoords)[clipped_index].z >= 0.0f && (*clipExtraCoords)[clipped_index].z <= (*clipExtraCoords)[clipped_index].w ); (*clipExtraColors)[clipped_index] = colors[k0]; (*clipExtraTexCoords)[clipped_index] = texCoords[k0]; numberVerticesPerPolygon++; clipped_index++; // //------------------------------------------------------- // We don't need to clip this edge if the next vertex is // also in the viewing space, so just move on to the next // vertex //------------------------------------------------------- // if((*clippingStates)[k1] == 0) { continue; } } // //--------------------------------------------------------- // This vertex is outside the viewing space, so if the next // vertex is also outside the viewing space, no clipping is // needed and we throw this vertex away. Since only one // clipping plane is involved, it must be in the same space // as the first vertex //--------------------------------------------------------- // else { firstIsIn = false; if((*clippingStates)[k1] != 0) { Verify((*clippingStates)[k1] == (*clippingStates)[k0]); continue; } } // //-------------------------------------------------- // We now find the distance along the edge where the // clipping plane will intersect //-------------------------------------------------- //) mask = 1; theTest |= (*clippingStates)[k1]; // //----------------------------------------------------- // Find the boundary conditions that match our clipping // plane //----------------------------------------------------- // for (l=0; l<MLRClippingState::NextBit; l++) { if(theTest.IsClipped(mask)) { // GetDoubleBC(l, bc0, bc1, transformedCoords[k0], transformedCoords[k1]); // //------------------------------------------- // Find the clipping interval from bc0 to bc1 //------------------------------------------- // if(firstIsIn==true) { a = GetLerpFactor(l, (*transformedCoords)[k0], (*transformedCoords)[k1]); } else { a = GetLerpFactor(l, (*transformedCoords)[k1], (*transformedCoords)[k0]); } Verify(a >= 0.0f && a <= 1.0f); ct = l; break; } mask <<= 1; } // //------------------------------ // Lerp the homogeneous position //------------------------------ // if(firstIsIn==true) { (*clipExtraCoords)[clipped_index].Lerp( (*transformedCoords)[k0], (*transformedCoords)[k1], a ); DoClipTrick((*clipExtraCoords)[clipped_index], ct); Verify((*clipExtraCoords)[clipped_index].x >= 0.0f && (*clipExtraCoords)[clipped_index].x <= (*clipExtraCoords)[clipped_index].w ); Verify((*clipExtraCoords)[clipped_index].y >= 0.0f && (*clipExtraCoords)[clipped_index].y <= (*clipExtraCoords)[clipped_index].w ); Verify((*clipExtraCoords)[clipped_index].z >= 0.0f && (*clipExtraCoords)[clipped_index].z <= (*clipExtraCoords)[clipped_index].w ); // //----------------------------------------------------- // If there are texture uv's, we need to lerp them in a // perspective correct manner //----------------------------------------------------- // (*clipExtraTexCoords)[clipped_index].Lerp ( texCoords[k0], texCoords[k1], a ); (*clipExtraColors)[clipped_index].Lerp ( colors[k0], colors[k1], a ); } else { (*clipExtraCoords)[clipped_index].Lerp( (*transformedCoords)[k1], (*transformedCoords)[k0], a ); DoClipTrick((*clipExtraCoords)[clipped_index], ct); Verify((*clipExtraCoords)[clipped_index].x >= 0.0f && (*clipExtraCoords)[clipped_index].x <= (*clipExtraCoords)[clipped_index].w ); Verify((*clipExtraCoords)[clipped_index].y >= 0.0f && (*clipExtraCoords)[clipped_index].y <= (*clipExtraCoords)[clipped_index].w ); Verify((*clipExtraCoords)[clipped_index].z >= 0.0f && (*clipExtraCoords)[clipped_index].z <= (*clipExtraCoords)[clipped_index].w ); // //----------------------------------------------------- // If there are texture uv's, we need to lerp them in a // perspective correct manner //----------------------------------------------------- // (*clipExtraTexCoords)[clipped_index].Lerp ( texCoords[k1], texCoords[k0], a ); (*clipExtraColors)[clipped_index].Lerp ( colors[k1], colors[k0], a ); } // //-------------------------------- // Bump the polygon's vertex count //-------------------------------- // numberVerticesPerPolygon++; } } // //--------------------------------------------------------------- // We have to handle multiple planes. We do this by creating two // buffers and we switch between them as we clip plane by plane //--------------------------------------------------------------- // else { #ifdef LAB_ONLY Set_Statistic(PolysClippedButGOnePlane, PolysClippedButGOnePlane+1); #endif ClipData2 srcPolygon, dstPolygon; int dstBuffer = 1; srcPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); srcPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); srcPolygon.colors = clipBuffer[dstBuffer].colors.GetData(); srcPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); // //---------------------------------------------------------- // unravel and copy the original data into the source buffer //---------------------------------------------------------- // for(k=0;k<stride;k++) { srcPolygon.coords[k] = (*transformedCoords)[k]; srcPolygon.texCoords[k] = texCoords[k]; srcPolygon.colors[k] = colors[k]; srcPolygon.clipPerVertex[k] = (*clippingStates)[k]; } srcPolygon.length = stride; // //-------------------------------- // Point to the destination buffer //-------------------------------- // dstBuffer = 0; dstPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); dstPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); dstPolygon.colors = clipBuffer[dstBuffer].colors.GetData(); dstPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); dstPolygon.length = 0; // //----------------------------------------------------------- // Spin through each plane that clipped the primitive and use // it to actually clip the primitive //----------------------------------------------------------- // mask = 1; MLRClippingState theNewOr(0); int loop = 4; do { for(l=0; l<MLRClippingState::NextBit; l++) { if(theOr.IsClipped(mask)) { // //----------------------------------- // Clip each vertex against the plane //----------------------------------- // for(k=0;k<srcPolygon.length;k++) { k1 = (k+1) < srcPolygon.length ? k+1 : 0; theTest = srcPolygon.clipPerVertex[k]; // //---------------------------------------------------- // If this vertex is inside the viewing space, copy it // directly to the clipping buffer //---------------------------------------------------- // if(theTest.IsClipped(mask) == 0) { firstIsIn = true; dstPolygon.coords[dstPolygon.length] = srcPolygon.coords[k]; dstPolygon.clipPerVertex[dstPolygon.length] = srcPolygon.clipPerVertex[k]; dstPolygon.texCoords[dstPolygon.length] = srcPolygon.texCoords[k]; dstPolygon.colors[dstPolygon.length] = srcPolygon.colors[k]; dstPolygon.length++; // //------------------------------------------------------- // We don't need to clip this edge if the next vertex is // also in the viewing space, so just move on to the next // vertex //------------------------------------------------------- // if(srcPolygon.clipPerVertex[k1].IsClipped(mask) == 0) { continue; } } // //--------------------------------------------------------- // This vertex is outside the viewing space, so if the next // vertex is also outside the viewing space, no clipping is // needed and we throw this vertex away. Since only one // clipping plane is involved, it must be in the same space // as the first vertex //--------------------------------------------------------- // else { firstIsIn = false; if(srcPolygon.clipPerVertex[k1].IsClipped(mask) != 0) { Verify( srcPolygon.clipPerVertex[k1].IsClipped(mask) == srcPolygon.clipPerVertex[k].IsClipped(mask) ); continue; } } // //------------------------------------------- // Find the clipping interval from bc0 to bc1 //------------------------------------------- // if(firstIsIn == true) { a = GetLerpFactor (l, srcPolygon.coords[k], srcPolygon.coords[k1]); Verify(a >= 0.0f && a <= 1.0f); // //------------------------------ // Lerp the homogeneous position //------------------------------ // dstPolygon.coords[dstPolygon.length].Lerp( srcPolygon.coords[k], srcPolygon.coords[k1], a ); DoClipTrick(dstPolygon.coords[dstPolygon.length], l); // //----------------------------------------------------- // If there are texture uv's, we need to lerp them in a // perspective correct manner //----------------------------------------------------- // dstPolygon.texCoords[dstPolygon.length].Lerp ( srcPolygon.texCoords[k], srcPolygon.texCoords[k1], a ); dstPolygon.colors[dstPolygon.length].Lerp ( srcPolygon.colors[k], srcPolygon.colors[k1], a ); } else { a = GetLerpFactor (l, srcPolygon.coords[k1], srcPolygon.coords[k]); Verify(a >= 0.0f && a <= 1.0f); // //------------------------------ // Lerp the homogeneous position //------------------------------ // dstPolygon.coords[dstPolygon.length].Lerp( srcPolygon.coords[k1], srcPolygon.coords[k], a ); DoClipTrick(dstPolygon.coords[dstPolygon.length], l); // //----------------------------------------------------- // If there are texture uv's, we need to lerp them in a // perspective correct manner //----------------------------------------------------- // dstPolygon.texCoords[dstPolygon.length].Lerp ( srcPolygon.texCoords[k1], srcPolygon.texCoords[k], a ); dstPolygon.colors[dstPolygon.length].Lerp ( srcPolygon.colors[k1], srcPolygon.colors[k], a ); } // //------------------------------------- // We have to generate a new clip state //------------------------------------- // dstPolygon.clipPerVertex[dstPolygon.length].Clip4dVertex(&dstPolygon.coords[dstPolygon.length]); // //---------------------------------- // Bump the new polygon vertex count //---------------------------------- // dstPolygon.length++; } // //----------------------------------------------- // Swap source and destination buffer pointers in // preparation for the next plane test //----------------------------------------------- // srcPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); srcPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); srcPolygon.colors = clipBuffer[dstBuffer].colors.GetData(); srcPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); srcPolygon.length = dstPolygon.length; dstBuffer = !dstBuffer; dstPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); dstPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); dstPolygon.colors = clipBuffer[dstBuffer].colors.GetData(); dstPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); dstPolygon.length = 0; } mask = mask << 1; } theNewOr = 0; for(k=0;k<srcPolygon.length;k++) { theNewOr |= srcPolygon.clipPerVertex[k]; } theOr == theNewOr; loop++; } while (theNewOr != 0 && loop--); Verify(theNewOr == 0); // //-------------------------------------------------- // Move the most recent polygon into the clip buffer //-------------------------------------------------- // for(k=0;k<srcPolygon.length;k++) { (*clipExtraCoords)[k] = srcPolygon.coords[k]; Verify((*clipExtraCoords)[k].x >= 0.0f && (*clipExtraCoords)[k].x <= (*clipExtraCoords)[k].w ); Verify((*clipExtraCoords)[k].y >= 0.0f && (*clipExtraCoords)[k].y <= (*clipExtraCoords)[k].w ); Verify((*clipExtraCoords)[k].z >= 0.0f && (*clipExtraCoords)[k].z <= (*clipExtraCoords)[k].w ); (*clipExtraTexCoords)[k] = srcPolygon.texCoords[k]; (*clipExtraColors)[k] = srcPolygon.colors[k]; } numberVerticesPerPolygon = srcPolygon.length; } // clip for(i=1;i<numberVerticesPerPolygon-1;i++) { Verify((vertexPool->GetLast() + 3 + numGOSVertices) < vertexPool->GetLength()); GOSCopyTriangleData( &gos_vertices[numGOSVertices], clipExtraCoords->GetData(), clipExtraColors->GetData(), clipExtraTexCoords->GetData(), 0, i + 1, i ); numGOSVertices+=3; } } } } break; } ptr = stream->GetPointer(); } if(numGOSVertices) { vertexPool->Increase(numGOSVertices); SortData *sd = sorter->SetRawData ( gos_vertices, numGOSVertices, currentState, SortData::TriList ); if(currentState.GetDrawNowMode()==MLRState::DrawNowOnMode) { SortData::DrawFunc drawFunc = sd->Draw[sd->type]; (sd->*drawFunc)(); } else { sorter->AddSortRawData(sd); } } }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // uint32_t MLRNGonCloud::Clip(MLRClippingState clippingFlags, GOSVertexPool* vt) { Check_Object(this); size_t i, j, k; size_t end, len = *usedNrOfNGons, ret = 0; #if EFECT_CLIPPED // this effect gets not clipped int32_t l, mask, k1, ct = 0; float a = 0.0f, bc0, bc1; #endif Check_Object(vt); gos_vertices = vt->GetActualVertexPool(); Check_Pointer(gos_vertices); numGOSVertices = 0; // //-------------------------------------- // See if we don't have to draw anything //-------------------------------------- // if(clippingFlags.GetClippingState() == 0 || len <= 0) { if(len <= 0) { visible = 0; } else { // //------------------------------- // Handle the non-indexed version //------------------------------- // for(i = 0, j = 0; i < len; i++, j += numOfVertices) { // if(IsOn(i) == false) // { // continue; // } uint32_t inColor = GOSCopyColor(&colors[2 * i]); uint32_t outColor = GOSCopyColor(&colors[2 * i + 1]); for(size_t z = 1; z < numOfVertices - 1; z++) { GOSCopyTriangleData( &gos_vertices[numGOSVertices], transformedCoords->GetData(), j, z + j + 1, z + j, true ); gos_vertices[numGOSVertices].argb = inColor; gos_vertices[numGOSVertices + 1].argb = outColor; gos_vertices[numGOSVertices + 2].argb = outColor; numGOSVertices += 3; } } Check_Object(vt); vt->Increase(numGOSVertices); visible = uint32_t(numGOSVertices ? 1 : 0); } return visible; } int32_t myNumberUsedClipVertex, myNumberUsedClipIndex, myNumberUsedClipLength; myNumberUsedClipVertex = 0; myNumberUsedClipIndex = 0; myNumberUsedClipLength = 0; // //------------------------------- // Handle the non-indexed version //------------------------------- // // //----------------------------------------------------------------- // Step through each polygon, making sure that we don't try to clip // backfaced polygons //----------------------------------------------------------------- // for(i = 0, j = 0; i < len; i++, j += numOfVertices) { // if(IsOn(i) == false) // { // continue; // } TurnVisible(i); // //--------------------------------------------------------------- // Test each vertex of the polygon against the allowed clipping // planes, and accumulate status for which planes always clip and // which planes clipped at least once //--------------------------------------------------------------- // theAnd.SetClippingState(0x3f); theOr.SetClippingState(0); end = j + numOfVertices; Stuff::Vector4D* v4d = transformedCoords->GetData() + j; MLRClippingState* cs = clipPerVertex->GetData() + j; for(k = j; k < end; k++, v4d++, cs++) { cs->Clip4dVertex(v4d); theAnd &= (*clipPerVertex)[k]; theOr |= (*clipPerVertex)[k]; #ifdef LAB_ONLY if(*cs == 0) { Set_Statistic(NonClippedVertices, NonClippedVertices + 1); } else { Set_Statistic(ClippedVertices, ClippedVertices + 1); } #endif } theAnd = theOr = 0; //ASSUME NO CLIPPING NEEDED FOR MC2. Its just not done here! // //------------------------------------------------------------------- // If any bit is set for all vertices, then the polygon is completely // outside the viewing space and we don't have to draw it. On the // other hand, if no bits at all were ever set, we can do a trivial // accept of the polygon //------------------------------------------------------------------- // if(theAnd != 0) { TurnInVisible(i); } else if(theOr == 0) { TurnVisible(i); uint32_t inColor = GOSCopyColor(&colors[2 * i]); uint32_t outColor = GOSCopyColor(&colors[2 * i + 1]); for(size_t z = 1; z < numOfVertices - 1; z++) { GOSCopyTriangleData( &gos_vertices[numGOSVertices], transformedCoords->GetData(), j, z + j + 1, z + j, true ); gos_vertices[numGOSVertices].argb = inColor; gos_vertices[numGOSVertices + 1].argb = outColor; gos_vertices[numGOSVertices + 2].argb = outColor; #ifdef LAB_ONLY if(gShowClippedPolys) { gos_vertices[numGOSVertices].argb = 0xff0000ff; gos_vertices[numGOSVertices].u = 0.0f; gos_vertices[numGOSVertices].v = 0.0f; gos_vertices[numGOSVertices + 1].argb = 0xff0000ff; gos_vertices[numGOSVertices + 1].u = 0.0f; gos_vertices[numGOSVertices + 1].v = 0.0f; gos_vertices[numGOSVertices + 2].argb = 0xff0000ff; gos_vertices[numGOSVertices + 2].u = 0.0f; gos_vertices[numGOSVertices + 2].v = 0.0f; } #endif numGOSVertices += 3; } ret++; } // //----------------------------------------------------------------- // It is not a trivial case, so we must now do real clipping on the // polygon //----------------------------------------------------------------- // else { #if EFECT_CLIPPED // this effect gets not clipped int32_t numberVerticesPerPolygon = 0; // //--------------------------------------------------------------- // Handle the case of a single clipping plane by stepping through // the vertices and finding the edge it originates //--------------------------------------------------------------- // if(theOr.GetNumberOfSetBits() == 1) { for(k = j; k < end; k++) { k1 = (k + 1 < end) ? k + 1 : j; // //---------------------------------------------------- // If this vertex is inside the viewing space, copy it // directly to the clipping buffer //---------------------------------------------------- // int32_t clipped_index = myNumberUsedClipVertex + numberVerticesPerPolygon; theTest = clipPerVertex[k]; if(theTest == 0) { clipExtraCoords[clipped_index] = transformedCoords[k]; if(k == j) { clipExtraColors[clipped_index] = colors[2 * i]; } else { clipExtraColors[clipped_index] = colors[2 * i + 1]; } numberVerticesPerPolygon++; clipped_index++; // //------------------------------------------------------- // We don't need to clip this edge if the next vertex is // also in the viewing space, so just move on to the next // vertex //------------------------------------------------------- // if(clipPerVertex[k1] == 0) { continue; } } // //--------------------------------------------------------- // This vertex is outside the viewing space, so if the next // vertex is also outside the viewing space, no clipping is // needed and we throw this vertex away. Since only one // clipping plane is involved, it must be in the same space // as the first vertex //--------------------------------------------------------- // else if(clipPerVertex[k1] != 0) { Verify(clipPerVertex[k1] == clipPerVertex[k]); continue; } // //-------------------------------------------------- // We now find the distance along the edge where the // clipping plane will intersect //-------------------------------------------------- // mask = 1; theTest |= clipPerVertex[k1]; // //----------------------------------------------------- // Find the boundary conditions that match our clipping // plane //----------------------------------------------------- // for(l = 0; l < MLRClippingState::NextBit; l++) { if(theTest.IsClipped(mask)) { // //------------------------------------------- // Find the clipping interval from bc0 to bc1 //------------------------------------------- // a = GetLerpFactor(l, (*transformedCoords)[k], (*transformedCoords)[k1]); Verify(a >= 0.0f && a <= 1.0f); ct = l; break; } mask <<= 1; } // //------------------------------ // Lerp the homogeneous position //------------------------------ // clipExtraCoords[clipped_index].Lerp( transformedCoords[k], transformedCoords[k1], a ); DoClipTrick(clipExtraCoords[clipped_index], ct); // //---------------------------------------------------------- // If there are colors, lerp them in screen space for now as // most cards do that anyway //---------------------------------------------------------- // clipExtraColors[clipped_index].Lerp( (k == j) ? colors[2 * i] : colors[2 * i + 1], (k1 == j) ? colors[2 * i] : colors[2 * i + 1], a ); // //-------------------------------- // Bump the polygon's vertex count //-------------------------------- // numberVerticesPerPolygon++; } } // //--------------------------------------------------------------- // We have to handle multiple planes. We do this by creating two // buffers and we switch between them as we clip plane by plane //--------------------------------------------------------------- // else { EffectClipData srcPolygon, dstPolygon; int32_t dstBuffer = 0; specialClipColors[0] = colors[2 * i]; for(l = 1; l < numOfVertices; l++) { specialClipColors[l] = colors[2 * i + 1]; } // //----------------------------------------------------- // Point the source polygon buffer at our original data //----------------------------------------------------- // srcPolygon.coords = &transformedCoords[j]; srcPolygon.clipPerVertex = &clipPerVertex[j]; srcPolygon.flags = 0; srcPolygon.colors = specialClipColors.GetData(); srcPolygon.length = numOfVertices; // //-------------------------------- // Point to the destination buffer //-------------------------------- // dstPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); dstPolygon.colors = clipBuffer[dstBuffer].colors.GetData(); dstPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); dstPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); dstPolygon.flags = srcPolygon.flags; dstPolygon.length = 0; // //----------------------------------------------------------- // Spin through each plane that clipped the primitive and use // it to actually clip the primitive //----------------------------------------------------------- // mask = 1; MLRClippingState theNewOr(0); int32_t loop = 4; do { for(l = 0; l < MLRClippingState::NextBit; l++) { if(theOr.IsClipped(mask)) { // //----------------------------------- // Clip each vertex against the plane //----------------------------------- // for(k = 0; k < srcPolygon.length; k++) { k1 = (k + 1 < srcPolygon.length) ? k + 1 : 0; theTest = srcPolygon.clipPerVertex[k]; // //---------------------------------------------------- // If this vertex is inside the viewing space, copy it // directly to the clipping buffer //---------------------------------------------------- // if(theTest.IsClipped(mask) == 0) { dstPolygon.coords[dstPolygon.length] = srcPolygon.coords[k]; dstPolygon.clipPerVertex[dstPolygon.length] = srcPolygon.clipPerVertex[k]; dstPolygon.colors[dstPolygon.length] = srcPolygon.colors[k]; dstPolygon.length++; // //------------------------------------------------------- // We don't need to clip this edge if the next vertex is // also in the viewing space, so just move on to the next // vertex //------------------------------------------------------- // if(srcPolygon.clipPerVertex[k1].IsClipped(mask) == 0) { continue; } } // //--------------------------------------------------------- // This vertex is outside the viewing space, so if the next // vertex is also outside the viewing space, no clipping is // needed and we throw this vertex away. Since only one // clipping plane is involved, it must be in the same space // as the first vertex //--------------------------------------------------------- // else if(srcPolygon.clipPerVertex[k1].IsClipped(mask) != 0) { Verify( srcPolygon.clipPerVertex[k1].IsClipped(mask) == srcPolygon.clipPerVertex[k].IsClipped(mask) ); continue; } // //------------------------------------------- // Find the clipping interval from bc0 to bc1 //------------------------------------------- // bc0 = GetBC(l, srcPolygon.coords[k]); bc1 = GetBC(l, srcPolygon.coords[k1]); Verify(!Close_Enough(bc0, bc1)); a = bc0 / (bc0 - bc1); Verify(a >= 0.0f && a <= 1.0f); // //------------------------------ // Lerp the homogeneous position //------------------------------ // dstPolygon.coords[dstPolygon.length].Lerp( srcPolygon.coords[k], srcPolygon.coords[k1], a ); DoCleanClipTrick(dstPolygon.coords[dstPolygon.length], l); // //---------------------------------------------------------- // If there are colors, lerp them in screen space for now as // most cards do that anyway //---------------------------------------------------------- // dstPolygon.colors[dstPolygon.length].Lerp( srcPolygon.colors[k], srcPolygon.colors[k1], a ); // //------------------------------------- // We have to generate a new clip state //------------------------------------- // dstPolygon.clipPerVertex[dstPolygon.length].Clip4dVertex(&dstPolygon.coords[dstPolygon.length]); // //---------------------------------- // Bump the new polygon vertex count //---------------------------------- // dstPolygon.length++; } // //----------------------------------------------- // Swap source and destination buffer pointers in // preparation for the next plane test //----------------------------------------------- // srcPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); srcPolygon.colors = clipBuffer[dstBuffer].colors.GetData(); // srcPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); srcPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); srcPolygon.length = dstPolygon.length; dstBuffer = !dstBuffer; dstPolygon.coords = clipBuffer[dstBuffer].coords.GetData(); dstPolygon.colors = clipBuffer[dstBuffer].colors.GetData(); // dstPolygon.texCoords = clipBuffer[dstBuffer].texCoords.GetData(); dstPolygon.clipPerVertex = clipBuffer[dstBuffer].clipPerVertex.GetData(); dstPolygon.length = 0; } mask = mask << 1; } theNewOr = 0; for(k = 0; k < srcPolygon.length; k++) { theNewOr |= srcPolygon.clipPerVertex[k]; } theOr == theNewOr; loop++; } while(theNewOr != 0 && loop--); Verify(theNewOr == 0); // //-------------------------------------------------- // Move the most recent polygon into the clip buffer //-------------------------------------------------- // for(k = 0; k < srcPolygon.length; k++) { int32_t clipped_index = myNumberUsedClipVertex + k; if(srcPolygon.coords[k].z == srcPolygon.coords[k].w) { srcPolygon.coords[k].z -= SMALL; } clipExtraCoords[clipped_index] = srcPolygon.coords[k]; clipExtraColors[clipped_index] = srcPolygon.colors[k]; } numberVerticesPerPolygon = srcPolygon.length; } clipExtraLength[myNumberUsedClipLength] = numberVerticesPerPolygon; myNumberUsedClipVertex += numberVerticesPerPolygon; myNumberUsedClipLength++; ret++; // clip // dont draw the original TurnInVisible(i); #endif } } #if EFECT_CLIPPED // this effect gets not clipped if(myNumberUsedClipLength > 0) { for(i = 0, j = 0; i < myNumberUsedClipLength; i++) { int32_t stride = clipExtraLength[i]; for(k = 1; k < stride - 1; k++) { Verify((vt->GetLast() + 3 + numGOSVertices) < vt->GetLength()); GOSCopyTriangleData( &gos_vertices[numGOSVertices], clipExtraCoords.GetData(), clipExtraColors.GetData(), j, j + k + 1, j + k, true ); #ifdef LAB_ONLY if(gShowClippedPolys) { gos_vertices[numGOSVertices].argb = 0xffff0000; gos_vertices[numGOSVertices].u = 0.0f; gos_vertices[numGOSVertices].v = 0.0f; gos_vertices[numGOSVertices + 1].argb = 0xffff0000; gos_vertices[numGOSVertices + 1].u = 0.0f; gos_vertices[numGOSVertices + 1].v = 0.0f; gos_vertices[numGOSVertices + 2].argb = 0xffff0000; gos_vertices[numGOSVertices + 2].u = 0.0f; gos_vertices[numGOSVertices + 2].v = 0.0f; } #endif numGOSVertices += 3; } j += stride; } } #endif vt->Increase(numGOSVertices); visible = uint32_t(numGOSVertices ? 1 : 0); if(visible) { } else { } return visible; }