#include "ElementRendererHeaders.hpp" #include "GridElement.hpp" //#define SPEW_CULL_INFO "your_name_here" //############################################################################ //############################ GridElement ################################ //############################################################################ HGOSHEAP ElementRenderer::GridElement::s_Heap = NULL; ElementRenderer::GridElement::ClassData* ElementRenderer::GridElement::DefaultData = NULL; ElementRenderer::Element::SyncMethod ElementRenderer::GridElement::SyncMethods[4]= { SYNC_METHOD(ListElement, CleanRoot), SYNC_METHOD(ListElement, Clean), SYNC_METHOD(ListElement, DirtyRoot), SYNC_METHOD(ListElement, Dirty) }; ElementRenderer::Element::CullMethod ElementRenderer::GridElement::CullMethods= CULL_METHOD(GridElement, Grid, Grid); ElementRenderer::Element::DrawMethod ElementRenderer::GridElement::DrawMethods[DrawStateCount]= { DRAW_METHOD(GridElement, Inherit), DRAW_METHOD(GridElement, Override) }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::GridElement::InitializeClass() { Verify(!DefaultData); Verify(!s_Heap); s_Heap = gos_CreateMemoryHeap("Grid", 0, g_LibraryHeap); Check_Pointer(s_Heap); DefaultData = new ClassData( GridElementClassID, "ElementRenderer::GridElement", BaseClass::DefaultData, reinterpret_cast(&Make) ); Check_Object(DefaultData); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::GridElement::TerminateClass() { Check_Object(DefaultData); delete DefaultData; DefaultData = NULL; Check_Pointer(s_Heap); gos_DestroyMemoryHeap(s_Heap); s_Heap = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::GridElement::GridElement( ClassData *class_data, Stuff::MemoryStream *stream, int version, ShapeHolder shapes ): ListElement(class_data, stream, version, shapes) { Check_Pointer(this); Check_Object(stream); if (version>=11) *stream >> m_rowCellCount >> m_columnCellCount; else { int row, col; *stream >> row >> col; Verify(static_cast(row) <= 255); Verify(static_cast(col) <= 255); m_rowCellCount = static_cast(row); m_columnCellCount = static_cast(col); } *stream >> m_rowCellSize >> m_columnCellSize >> m_rowOffset >> m_columnOffset; unsigned index = (GetCullMode() == NeverCullMode); index |= IsMatrixDirty() ? 2 : 0; Verify(index < 4); m_sync = SyncMethods[index]; m_cameraCull = CullMethods.m_cameraCull; m_rayCull = CullMethods.m_rayCull; m_sphereTest = CullMethods.m_sphereTest; index = (m_state>>DrawStateBit) & DrawStateMask; Verify(index < DrawStateCount); m_draw = DrawMethods[index]; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::GridElement::GridElement( BYTE rowSize, BYTE columnSize, Stuff::Scalar row_offset, Stuff::Scalar column_offset, Stuff::Scalar total_row_size, Stuff::Scalar total_column_size, ClassData *class_data ): ListElement(class_data) { Check_Pointer(this); m_rowCellCount = rowSize; m_columnCellCount = columnSize; m_rowOffset = row_offset; m_columnOffset = column_offset; m_rowCellSize = total_row_size/m_rowCellCount; m_columnCellSize = total_column_size/m_columnCellCount; Verify(rowSize*columnSize < 65536); m_activeChildren = static_cast(rowSize*columnSize); SetSize(m_activeChildren); unsigned index = (GetCullMode() == NeverCullMode); index |= IsMatrixDirty() ? 2 : 0; Verify(index < 4); m_sync = SyncMethods[index]; m_cameraCull = CullMethods.m_cameraCull; m_rayCull = CullMethods.m_rayCull; m_sphereTest = CullMethods.m_sphereTest; index = (m_state>>DrawStateBit) & DrawStateMask; Verify(index < DrawStateCount); m_draw = DrawMethods[index]; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::GridElement::~GridElement() { Check_Object(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::GridElement* ElementRenderer::GridElement::Make( Stuff::MemoryStream *stream, int version, ShapeHolder shapes ) { Check_Object(stream); gos_PushCurrentHeap(s_Heap); GridElement *element = new GridElement(DefaultData, stream, version, shapes); gos_PopCurrentHeap(); return element; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::GridElement::Save(Stuff::MemoryStream *stream) { Check_Object(this); Check_Object(stream); BaseClass::Save(stream); *stream << m_rowCellCount << m_columnCellCount << m_rowCellSize << m_columnCellSize << m_rowOffset << m_columnOffset; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::GridElement::TestInstance() { Verify(IsDerivedFrom(DefaultData)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::GridElement::AttachIndexedChild( BYTE row, BYTE column, Element *element ) { Check_Object(this); Verify(row*m_columnCellCount+column < m_list.GetLength()); m_list[row*m_columnCellCount+column] = element; SetParentElement(element, this); if (element->GetCullMode() != AlwaysCullMode) { if (element->m_localOBB.sphereRadius > 0.0f || element->AreBoundsWrong()) element->SetVolumeCullMode(); else element->SetNeverCullMode(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // WORD ElementRenderer::GridElement::FindElementIndex( Stuff::Scalar row, Stuff::Scalar column ) { Check_Object(this); column -= m_columnOffset; row -= m_rowOffset; column /= m_columnCellSize; row /= m_rowCellSize; if (column>=0.0f && column=0.0f && row( Stuff::Truncate_Float_To_Byte(row)*m_columnCellCount + Stuff::Truncate_Float_To_Byte(column) ); Verify(index < m_list.GetLength()); return index; } return static_cast(m_list.GetLength()); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::GridElement::SetSize(WORD max_size) { Check_Object(this); m_list.SetLength(max_size); m_activeChildren = max_size; for (WORD i=0; i(m_rowCellCount*m_columnCellCount)); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::GridElement::GetDimensions( Stuff::Scalar *row_offset, Stuff::Scalar *column_offset, Stuff::Scalar *row_cell_size, Stuff::Scalar *column_cell_size ) { Check_Object(this); Check_Pointer(row_offset); Check_Pointer(column_offset); Check_Pointer(row_cell_size); Check_Pointer(column_cell_size); *row_offset = m_rowOffset; *column_offset = m_columnOffset; *row_cell_size = m_rowCellSize; *column_cell_size = m_columnCellSize; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::GridElement::SetSyncState() { Check_Object(this); Verify( GetCullMode() == RootMode || GetCullMode() == NeverCullMode ); Verify(!IsSyncDeferred() && !AreBoundsWrong()); unsigned index = (GetCullMode() == NeverCullMode); index |= IsMatrixDirty() ? 2 : 0; Verify(index < 4); m_sync = SyncMethods[index]; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::GridElement::SetCullState() { Check_Object(this); m_cameraCull = CullMethods.m_cameraCull; m_rayCull = CullMethods.m_rayCull; m_sphereTest = CullMethods.m_sphereTest; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::GridElement::SetDrawState() { Check_Object(this); unsigned index = (m_state>>DrawStateBit) & DrawStateMask; Verify(index < DrawStateCount); m_draw = DrawMethods[index]; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool ElementRenderer::GridElement::CastCulledRay(CollisionQuery *query) { Check_Object(this); Check_Object(query); Verify(!query->m_data); // //---------------------- // Test all the children //---------------------- // if (IterateLine(query, TestCell)) { if (!query->m_data) query->m_data = m_data; return true; } return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::Element* ElementRenderer::GridElement::FindSmallestElementContainingCulled(SphereTest *test) { Check_Object(this); Check_Object(test); // //------------------ // Draw our children //------------------ // Element *result = this; for (int i=0; iFindSmallestElementContaining(test); if (temp) result = temp; } return result; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void* ElementRenderer::GridElement::TestCell( GridElement *grid, WORD cell, CollisionQuery *query, Stuff::Scalar enter, Stuff::Scalar leave ) { Check_Object(grid); Check_Object(query); Verify(cell < grid->m_activeChildren); Element *element = grid->m_list[cell]; Check_Object(element); return reinterpret_cast(element->CastRay(query)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // inline static bool Trim( Stuff::Scalar dot, Stuff::Scalar separation, Stuff::Scalar *enter, Stuff::Scalar *leave ) { Check_Pointer(enter); Check_Pointer(leave); Verify(Stuff::Small_Enough(dot, 1.0f)); if (dot > Stuff::SMALL) { Stuff::Scalar distance = -separation / dot - Stuff::SMALL; if (distance < *leave) *leave = distance; return *enter <= *leave; } else if (dot < -Stuff::SMALL) { Stuff::Scalar distance = -separation / dot + Stuff::SMALL; if (distance > *enter) *enter = distance; return *enter <= *leave; } else return separation <= Stuff::SMALL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // inline static bool Leave_Trim( Stuff::Scalar dot, Stuff::Scalar separation, Stuff::Scalar *leave ) { Check_Pointer(leave); Verify(Stuff::Small_Enough(dot, 1.0f)); if (dot > Stuff::SMALL) { Stuff::Scalar distance = -separation / dot; if (distance < *leave) { *leave = distance; return true; } } return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void* ElementRenderer::GridElement::IterateLine( CollisionQuery *query, CellTest call_back ) { Check_Object(this); Check_Object(query); Check_Pointer(call_back); Verify(query->m_line->m_length >= 0.0f); #if defined(SPEW_CULL_INFO) int tested=0; #endif // //------------------------------------------------------------------- // Find the cell coordinates of the the beginning and end of the m_line //------------------------------------------------------------------- // Stuff::Scalar x_scale = 1.0f / m_columnCellSize; Stuff::Scalar z_scale = 1.0f / m_rowCellSize; Verify(Stuff::Close_Enough(x_scale, z_scale)); Check_Object(query->m_line); Stuff::Line3D *line = query->m_line; Stuff::Scalar x_origin = (line->m_origin.x - m_columnOffset) * x_scale; Stuff::Scalar z_origin = (line->m_origin.z - m_rowOffset) * z_scale; Stuff::Point3D end; line->FindEnd(&end); Stuff::Scalar x_end = (end.x - m_columnOffset) * x_scale; Stuff::Scalar z_end = (end.z - m_rowOffset) * z_scale; // //----------------------------------------------------------------------------- // If the m_line is within a single cell, just test that one. If the cell is // outside the grid boundaries, return no hit. We don't use our Truncate // functions here because we do not know the extents of the line we are testing //----------------------------------------------------------------------------- // BYTE x = static_cast(x_origin); BYTE z = static_cast(z_origin); if (x == static_cast(x_end) && z == static_cast(z_end)) { #if defined(SPEW_CULL_INFO) SPEW((SPEW_CULL_INFO, "single cell test")); #endif if (x < m_columnCellCount && z < m_rowCellCount) return (*call_back)( this, static_cast(z*m_columnCellCount + x), query, 0, line->m_length ); return NULL; } // //---------------------------------------------------------------------- // The m_line crosses cells, so we first have to clip it to the grid // boundaries. We will treat the box boundaries as four plane equations //---------------------------------------------------------------------- // Stuff::Scalar enter = 0.0f; Stuff::Scalar leave = line->m_length; if ( !Trim( -line->m_direction.x, m_columnOffset - line->m_origin.x, &enter, &leave ) ) { #if defined(SPEW_CULL_INFO) SPEW((SPEW_CULL_INFO, "Line doesn't hit grid")); #endif return NULL; } if ( !Trim( line->m_direction.x, line->m_origin.x - (m_columnOffset + m_columnCellCount*m_columnCellSize), &enter, &leave ) ) { #if defined(SPEW_CULL_INFO) SPEW((SPEW_CULL_INFO, "Line doesn't hit grid")); #endif return NULL; } if ( !Trim( -line->m_direction.z, m_rowOffset - line->m_origin.z, &enter, &leave ) ) { #if defined(SPEW_CULL_INFO) SPEW((SPEW_CULL_INFO, "Line doesn't hit grid")); #endif return NULL; } if ( !Trim( line->m_direction.z, line->m_origin.z - (m_rowOffset + m_rowCellCount*m_rowCellSize), &enter, &leave ) ) { #if defined(SPEW_CULL_INFO) SPEW((SPEW_CULL_INFO, "Line doesn't hit grid")); #endif return NULL; } // //--------------------------------------------------------------------------- // Now project the origin and end of the m_line in cell space and cast those // into the integer indices we need. The clamps are there to deal with error // not caught by trim //--------------------------------------------------------------------------- // line->Project(enter, &end); x_origin = (end.x - m_columnOffset) * x_scale; z_origin = (end.z - m_rowOffset) * z_scale; if (x_origin <= 0.0f) x = 0; else if (x_origin >= m_columnCellCount) x = static_cast(m_columnCellCount-1); else x = Stuff::Truncate_Float_To_Byte(x_origin); if (z_origin <= 0.0f) z = 0; else if (z_origin >= m_rowCellCount) z = static_cast(m_rowCellCount-1); else z = Stuff::Truncate_Float_To_Byte(z_origin); Verify(x < m_columnCellCount && z < m_rowCellCount); line->Project(leave, &end); x_end = (end.x - m_columnOffset) * x_scale; z_end = (end.z - m_rowOffset) * z_scale; BYTE last_x, last_z; if (x_end <= 0.0f) last_x = 0; else if (x_end >= m_columnCellCount) last_x = static_cast(m_columnCellCount-1); else last_x = Stuff::Truncate_Float_To_Byte(x_end); if (z_end <= 0.0f) last_z = 0; else if (z_end >= m_rowCellCount) last_z = static_cast(m_rowCellCount-1); else last_z = Stuff::Truncate_Float_To_Byte(z_end); Verify(last_x < m_columnCellCount && last_z < m_rowCellCount); // //-------------------------------- // Crawl over the cells one by one //-------------------------------- // Stuff::Scalar cell_leave = enter; while (true) { #if defined(SPEW_CULL_INFO) ++tested; #endif Verify(x < m_columnCellCount && z < m_rowCellCount); // //------------------------------------------------------------------- // Clip the m_line to the x boundaries of the current cell and remember // way to leave //------------------------------------------------------------------- // enter = cell_leave; Stuff::Scalar x_leave = leave; int dx=0; if ( Leave_Trim( -line->m_direction.x, m_columnOffset + x*m_columnCellSize - line->m_origin.x, &x_leave ) ) dx = -1; if ( Leave_Trim( line->m_direction.x, line->m_origin.x - (m_columnOffset + (x+1)*m_columnCellSize), &x_leave ) ) dx = 1; // //------------------------------------------------------------------- // Clip the m_line to the z boundaries of the current cell and remember // way to leave //------------------------------------------------------------------- // int dz=0; Stuff::Scalar z_leave = leave; if ( Leave_Trim( -line->m_direction.z, m_rowOffset + z*m_rowCellSize - line->m_origin.z, &z_leave ) ) dz = -1; if ( Leave_Trim( line->m_direction.z, line->m_origin.z - (m_rowOffset + (z+1)*m_rowCellSize), &z_leave ) ) dz = 1; // //---------------------------------------------------------------- // Pick which axis we leave on first. Make sure we handle corners // appropriately //---------------------------------------------------------------- // if (x_leave < z_leave-Stuff::SMALL) { dz = 0; cell_leave = x_leave; } if (z_leave < x_leave-Stuff::SMALL) { dx = 0; cell_leave = z_leave; } else cell_leave = x_leave; // //-------------------------------------------------------- // See if there is anything to hit, and if so, we are done //-------------------------------------------------------- // Stuff::Scalar old_length = query->m_line->m_length; void *result = (*call_back)( this, static_cast(z*m_columnCellCount + x), query, enter, cell_leave ); if (result != NULL) { #if defined(SPEW_CULL_INFO) SPEW((SPEW_CULL_INFO, "Hit! %d of %d cells tested", tested, m_columnCellCount*m_rowCellCount)); #endif if (query->m_line->m_length <= cell_leave) return result; else query->m_line->m_length = old_length; } // //-------------------------------------------------------------------- // If we have reached the end, we are done, otherwise move to the next // cell //-------------------------------------------------------------------- // if (x == last_x && z == last_z || !dx && !dz) break; x = static_cast(x + dx); z = static_cast(z + dz); } // //------------------------- // We couldn't hit anything //------------------------- // #if defined(SPEW_CULL_INFO) SPEW((SPEW_CULL_INFO, "Missed: %d of %d cells tested", tested, m_columnCellCount*m_rowCellCount)); #endif return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int ElementRenderer::GridElement::GridCullMethod(CameraElement *camera) { Check_Object(this); Check_Object(camera); return BaseClass::NeverCullMethod(camera); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int ElementRenderer::GridElement::GridSphereTestMethod(SphereTest *query) { Check_Object(this); Check_Object(query); return BaseClass::NeverSphereTestMethod(query); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool ElementRenderer::GridElement::GridRayCullMethod(CollisionQuery *query) { Check_Object(this); Check_Object(query); Verify(!query->m_data); return BaseClass::NeverRayCullMethod(query); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::GridElement::InheritDrawMethod( CameraElement *camera, const StateChange *inherited_state, int culling_state ) { Check_Object(this); Check_Object(inherited_state); Check_Object(camera); Verify(culling_state != -1); // //---------------------- // Draw all the children //---------------------- // Stuff::Point3D theCorners[4]; theCorners[0].y = 0.0f; theCorners[1].y = 0.0f; theCorners[2].y = 0.0f; theCorners[3].y = 0.0f; const Stuff::Point3D *cullPoints = camera->GetCullPoints(); int pxmin, pxmax, pzmin, pzmax, in[5], out[4]; int i, j, k; pxmin = pxmax = pzmin = pzmax = 0; for(i=1;i<5;i++) { if(cullPoints[i].x < cullPoints[pxmin].x) { pxmin = i; } if(cullPoints[i].x > cullPoints[pxmax].x) { pxmax = i; } if(cullPoints[i].z < cullPoints[pzmin].z) { pzmin = i; } if(cullPoints[i].z > cullPoints[pzmax].z) { pzmax = i; } } int inCount=0, outCount=0; in[inCount++] = pzmin; if(pzmin!=pxmin) { in[inCount++] = pxmin; if(pxmin!=pzmax) { in[inCount++] = pzmax; if(pzmax!=pxmax && pxmax!=pzmin) { in[inCount++] = pxmax; } } else { in[inCount++] = pxmax; } } else { in[inCount++] = pzmax; Verify(pzmax!=pxmax && pxmax!=pzmin); in[inCount++] = pxmax; } Verify(inCount<5); for(i=0;i<5;i++) { for(j=0;j 0.0f) { break; } } if(jj+1;k--) { in[k] = in[k-1]; } in[j+1] = out[i]; inCount++; } } #ifdef _ARMOR // // Checking for a convex hull // for(i=0;i= 0.0f); } #endif #ifdef SPEW_CULL_INFO int d = 0; #endif const Stuff::Scalar theCageCorrector = 4.5f; int minZ, maxZ, minX, maxX; minZ = (int)floor((cullPoints[pzmin].z-m_rowOffset-theCageCorrector)/m_rowCellSize); if(minZ<0) { minZ = 0; } maxZ = (int)ceil((cullPoints[pzmax].z-m_rowOffset+theCageCorrector)/m_rowCellSize); if(maxZ > m_rowCellCount) { maxZ = m_rowCellCount; } theCorners[0].z = m_rowOffset + minZ*m_rowCellSize; theCorners[1].z = theCorners[0].z; theCorners[2].z = theCorners[0].z + m_rowCellSize; theCorners[3].z = theCorners[2].z; minX = (int)floor((cullPoints[pxmin].x-m_columnOffset-theCageCorrector)/m_columnCellSize); if(minX<0) { minX = 0; } maxX = (int)ceil((cullPoints[pxmax].x-m_columnOffset+theCageCorrector)/m_columnCellSize); if(maxX > m_columnCellCount) { maxX = m_columnCellCount; } for (j=minZ; j=inCount) { end = 0; } if(cullPoints[in[end]].z > cullPoints[in[k]].z) { if(p1 < 0 && theCorners[1].z > cullPoints[in[k]].z && theCorners[1].z < cullPoints[in[end]].z) { p1 = k; } if(p2 < 0 && theCorners[2].z > cullPoints[in[k]].z && theCorners[2].z < cullPoints[in[end]].z) { p2 = k; } } } if(p1<0 && p2<0) { if(theCorners[1].x > cullPoints[pxmin].x) { inOrOut = true; } } else { Stuff::Vector3D vc; if(p1==p2) { end = p1+1; if(end>=inCount) { end = 0; } vc.Cross(theCorners[1], cullPoints[in[p1]], cullPoints[in[end]]); if(vc.y < 0.0f) { inOrOut = true; } else { end = p2+1; if(end>=inCount) { end = 0; } vc.Cross(theCorners[2], cullPoints[in[p2]], cullPoints[in[end]]); if(vc.y < 0.0f) { inOrOut = true; } } } else { if(p2<0) { end = p1+1; if(end>=inCount) { end = 0; } vc.Cross(theCorners[1], cullPoints[in[p1]], cullPoints[in[end]]); if(vc.y < 0.0f) { inOrOut = true; } } if(p1<0) { end = p2+1; if(end>=inCount) { end = 0; } vc.Cross(theCorners[2], cullPoints[in[p2]], cullPoints[in[end]]); if(vc.y < 0.0f) { inOrOut = true; } } if(p1>=0 && p2>=0) { Verify(p2>p1); for(k=p1+1;k cullPoints[in[k]].x) { inOrOut = true; break; } } } } } } else { // // Check the x-max side // } if(inOrOut==true) */ { Element *element = m_list[j*m_columnCellCount+i]; Check_Object(element); #ifdef _ARMOR if(element->GetCullMode() == VolumeCullMode) { Verify(element->GetWorldOBB().localToParent.entries[3] >= theCorners[0].x); Verify(element->GetWorldOBB().localToParent.entries[3] <= theCorners[1].x); Verify(element->GetWorldOBB().localToParent.entries[11] >= theCorners[0].z); Verify(element->GetWorldOBB().localToParent.entries[11] <= theCorners[3].z); } #endif camera->DrawElement(element, inherited_state); #ifdef SPEW_CULL_INFO d++; #endif } theCorners[0].x += m_columnCellSize; theCorners[1].x += m_columnCellSize; theCorners[2].x += m_columnCellSize; theCorners[3].x += m_columnCellSize; } theCorners[0].z += m_rowCellSize; theCorners[1].z += m_rowCellSize; theCorners[2].z += m_rowCellSize; theCorners[3].z += m_rowCellSize; } #ifdef SPEW_CULL_INFO SPEW((SPEW_CULL_INFO, "Drawn: %d Culled: %d", d, (m_rowCellCount*m_columnCellCount)-d)); #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void ElementRenderer::GridElement::OverrideDrawMethod( CameraElement *camera, const StateChange *inherited_state, int culling_state ) { Check_Object(this); Check_Object(inherited_state); Check_Object(camera); Verify(culling_state != -1); // //------------------- // Mix the properties //------------------- // Check_Object(m_stateChange); StateChange mixed; mixed.Mix(*inherited_state, *m_stateChange); MixLights( mixed.m_lights, inherited_state->m_lights, m_stateChange->m_lights ); // //---------------------- // Draw all the children //---------------------- // Stuff::Point3D theCorners[4]; theCorners[0].y = 0.0f; theCorners[1].y = 0.0f; theCorners[2].y = 0.0f; theCorners[3].y = 0.0f; const Stuff::Point3D *cullPoints = camera->GetCullPoints(); int pxmin, pxmax, pzmin, pzmax, in[5], out[4]; int i, j, k; pxmin = pxmax = pzmin = pzmax = 0; for(i=1;i<5;i++) { if(cullPoints[i].x < cullPoints[pxmin].x) { pxmin = i; } if(cullPoints[i].x > cullPoints[pxmax].x) { pxmax = i; } if(cullPoints[i].z < cullPoints[pzmin].z) { pzmin = i; } if(cullPoints[i].z > cullPoints[pzmax].z) { pzmax = i; } } int inCount=0, outCount=0; in[inCount++] = pzmin; if(pzmin!=pxmin) { in[inCount++] = pxmin; if(pxmin!=pzmax) { in[inCount++] = pzmax; if(pzmax!=pxmax && pxmax!=pzmin) { in[inCount++] = pxmax; } } else { in[inCount++] = pxmax; } } else { in[inCount++] = pzmax; Verify(pzmax!=pxmax && pxmax!=pzmin); in[inCount++] = pxmax; } Verify(inCount<5); for(i=0;i<5;i++) { for(j=0;j 0.0f) { break; } } if(jj+1;k--) { in[k] = in[k-1]; } in[j+1] = out[i]; inCount++; } } #ifdef SPEW_CULL_INFO int d = 0; #endif int minZ, maxZ, minX, maxX; minZ = (int)floor((cullPoints[pzmin].z-m_rowOffset)/m_rowCellSize); if(minZ<0) { minZ = 0; } maxZ = (int)ceil((cullPoints[pzmax].z-m_rowOffset)/m_rowCellSize); if(maxZ > m_rowCellCount) { maxZ = m_rowCellCount; } theCorners[0].z = m_rowOffset + minZ*m_rowCellSize; theCorners[1].z = theCorners[0].z; theCorners[2].z = theCorners[0].z + m_rowCellSize; theCorners[3].z = theCorners[2].z; minX = (int)floor((cullPoints[pxmin].x-m_columnOffset)/m_columnCellSize); if(minX<0) { minX = 0; } maxX = (int)ceil((cullPoints[pxmax].x-m_columnOffset)/m_columnCellSize); if(maxX > m_columnCellCount) { maxX = m_columnCellCount; } for (j=minZ; jDrawElement(element, inherited_state); #ifdef SPEW_CULL_INFO d++; } else { nd++; #endif } theCorners[0].x += m_rowCellSize; theCorners[1].x += m_rowCellSize; theCorners[2].x += m_rowCellSize; theCorners[3].x += m_rowCellSize; } theCorners[0].z += m_columnCellSize; theCorners[1].z += m_columnCellSize; theCorners[2].z += m_columnCellSize; theCorners[3].z += m_columnCellSize; } #ifdef SPEW_CULL_INFO SPEW((SPEW_CULL_INFO, "Drawn: %d Culled: %d", d, nd)); #endif }