/////////////////////////////////////////////////////////////////////////////// // File: BlobRenderer.cpp // // Copyright 2001 Pipeworks Software // // WORK HALTED: Patent issues // /////////////////////////////////////////////////////////////////////////////// #include #include "xbs_math.h" #include "xbs_app.h" #include "Blobs.h" #include "BlobRenderer.h" /////////////////////////////////////////////////////////////////////////////// #define LLI_RAND_MAX 0x00010000 #define LLI_RAND_MASK 0x0000FFFF /////////////////////////////////////////////////////////////////////////////// float FRand01() { static QRand qrand; static float mul = 1.0f / ((float)LLI_RAND_MAX); return ((float)(qrand.Rand()&LLI_RAND_MASK)) * mul; } /////////////////////////////////////////////////////////////////////////////// float FRand11() { static QRand qrand; static float mul = 2.0f / ((float)LLI_RAND_MAX); return (((float)(qrand.Rand()&LLI_RAND_MASK)) * mul) - 1.0f; } /////////////////////////////////////////////////////////////////////////////// BlobRenderer::BlobRenderer() { m_pLLI = NULL; m_pBlobArray = NULL; m_NumBlobs = 0; m_Threshhold = 1.0f; m_dwNumVertices = 0; m_dwNumIndices = 0; m_pBlobVB = NULL; m_pBlobIB = NULL; m_pField = NULL; m_pVertexIndices = NULL; } /////////////////////////////////////////////////////////////////////////////// BlobRenderer::~BlobRenderer() { destroy(); } /////////////////////////////////////////////////////////////////////////////// void BlobRenderer::destroy() { if (m_pBlobVB) m_pBlobVB->Release(); if (m_pBlobIB) m_pBlobIB->Release(); delete m_pField; delete m_pVertexIndices; m_pBlobArray = NULL; m_pLLI = NULL; m_pBlobArray = NULL; m_NumBlobs = 0; m_dwNumVertices = 0; m_dwNumIndices = 0; m_pBlobVB = NULL; m_pBlobIB = NULL; m_pField = NULL; m_pVertexIndices = NULL; } /////////////////////////////////////////////////////////////////////////////// void BlobRenderer::render() { int next_affiliation = m_pSources[0]->dAffiliation; int i; for (i=1; idAffiliation); } for (int affiliation = next_affiliation; affiliation < m_NumBlobs; affiliation = next_affiliation) { next_affiliation = m_NumBlobs; D3DVECTOR pt_min, pt_max; pt_min = pt_max = bs.ptPosition; bool b_unset = true; // For this affiliation, iterate through all the sources, adjusting // the min/max for any blobs with the correct affiliation. for (int i=0; i affiliation) next_affiliation = min(aff, next_affiliation); if (aff == affiliation) { if (b_unset) { b_unset = false; pt_min = pt_max = bs.ptPosition; pt_min.x -= bs.fConsiderationRadius; pt_min.y -= bs.fConsiderationRadius; pt_min.z -= bs.fConsiderationRadius; pt_max.x += bs.fConsiderationRadius; pt_max.y += bs.fConsiderationRadius; pt_max.z += bs.fConsiderationRadius; } else { pt_min.x = min(pt_min.x, bs.ptPosition.x - bs.fConsiderationRadius); pt_min.y = min(pt_min.y, bs.ptPosition.y - bs.fConsiderationRadius); pt_min.z = min(pt_min.z, bs.ptPosition.z - bs.fConsiderationRadius); pt_max.x = min(pt_max.x, bs.ptPosition.x + bs.fConsiderationRadius); pt_max.y = min(pt_max.y, bs.ptPosition.y + bs.fConsiderationRadius); pt_max.z = min(pt_max.z, bs.ptPosition.z + bs.fConsiderationRadius); } } } // Now have the boundaries for the rendering region. Blobs outside the area may // affect the energy threshold, but no polygons will be drawn outside it. int sx, sy, sz, ex, ey, ez; getCoords(pt_min, &sx, &sy, &sz); getCoords(pt_max, &ex, &ey, &ez); ex++; ey++; ez++; int len_x = ex - sx + 1; int len_y = ey - sy + 1; int len_z = ez - sz + 1; int len_xy = len_x*len_y; int len_xyz = len_xy * len_z; if (len_x*len_y*len_z > m_FieldX*m_FieldY*m_FieldZ) { continue; // can't render it, it is too big } // Clear the part of the field that will be used. Note that this does not // share the rows/columns/levels that would be used if the entire field // was used. Instead, the minimum amount of memory is used in a contiguous // fashion. for (i=0; iLock(0, len_xyz*6, (BYTE**) &pbv_buf, D3DLOCK_DISCARD)) { continue; } if (D3D_OK != m_pBlobIB->Lock(0, max_tris*3, (BYTE**) &pbv_buf, D3DLOCK_DISCARD)) { m_pBlobVB->Unlock(); continue; } int num_tris = 0; int num_verts = 0; BlobVertex* p_vert = p_verts; u16* p_index = p_indices; // This buffer stores the vertex indices (or -1) for the vertex on each segment // of a voxel. The offsets march through the buffer, returning to zero when they // reach the voxel_wrap value. m_pVertexIndices[voxel_offset] is for the voxel // with the current point in the max_pt position. int voxel_offset = 0; int voxel_offset_x = 6*1; int voxel_offset_y = 6*len_x; int voxel_offset_z = 6*len_xy; int voxel_wrap = 6*(len_xy+1); memset(m_pVertexIndices, -1, sizeof(int) * voxel_wrap); D3DVECTOR pos; pos.z = pt_min.z; for (int w=sz; w m_Threshhold) in_or_out |= 0x0001; if (p_field[ 1] > m_Threshhold) in_or_out |= 0x0002; if (p_field[ len_x ] > m_Threshhold) in_or_out |= 0x0004; if (p_field[ len_x+1] > m_Threshhold) in_or_out |= 0x0008; if (p_field[len_xy ] > m_Threshhold) in_or_out |= 0x0010; if (p_field[len_xy+ 1] > m_Threshhold) in_or_out |= 0x0020; if (p_field[len_xy+len_x ] > m_Threshhold) in_or_out |= 0x0040; if (p_field[len_xy+len_x+1] > m_Threshhold) in_or_out |= 0x0080; if ((in_or_out!=0) && (in_or_out!=0x00FF)) { // Not all corners are the same. Analyze the five tetrahedrons. // The five tetrahedrons are defined as corners: const int odd_tetrahedrons[20] = { 0,1,2,4, 5,1,4,7, 3,1,2,7, 6,2,7,4, 1,2,4,7 }; const int even_tetrahedrons[20] = { 1,0,5,3, 7,3,5,6, 2,0,6,3, 4,0,6,5, 0,6,5,3 }; const int* tetrahedrons = ((u+v+w)&0x01) ? odd_tetrahedrons : even_tetrahedrons; for (int tet=0; tet<5; tet++) { int mask = 0; mask |= (1<<(tetrahedrons[4*tet+0])); mask |= (1<<(tetrahedrons[4*tet+1])); mask |= (1<<(tetrahedrons[4*tet+2])); mask |= (1<<(tetrahedrons[4*tet+3])); int masked = in_or_out & mask; if ((masked!=0) && (masked!=mask)) { // Mixed corners for this tetrahedron. Triangles are needed. int ins[4]; int outs[4]; int num_in = 0; int num_out = 0; if (mask & 0x0001) ins[num_in++] = 0; if (mask & 0x0002) ins[num_in++] = 1; if (mask & 0x0004) ins[num_in++] = 2; if (mask & 0x0008) ins[num_in++] = 3; if (mask & 0x0010) ins[num_in++] = 4; if (mask & 0x0020) ins[num_in++] = 5; if (mask & 0x0040) ins[num_in++] = 6; if (mask & 0x0080) ins[num_in++] = 7; if (num_in==1) { // One is in, three are out. D3DVECTOR pos_in = pos; if (ins[0] & 0x01) pos_in.x += m_FieldToWorld.x * 0.5f; if (ins[0] & 0x02) pos_in.y += m_FieldToWorld.y * 0.5f; if (ins[0] & 0x04) pos_in.z += m_FieldToWorld.z * 0.5f; } } } } } } } // Render. m_pBlobIB->Unlock(); m_pBlobVB->Unlock(); } } /////////////////////////////////////////////////////////////////////////////// void BlobRenderer::init( const BlobSource* p_blob_sources, int num_blobs, float xy_spacing, float z_spacing, const D3DVECTOR& center, const D3DVECTOR& half_dim) { m_FieldX = (int)((half_dim.x * 2.0f / xy_spacing) + 2.0f); m_FieldY = (int)((half_dim.y * 2.0f / xy_spacing) + 2.0f); m_FieldZ = (int)((half_dim.z * 2.0f / z_spacing) + 2.0f); m_FieldXY = m_FieldX * m_FieldY; m_pField = new float[m_FieldXY * m_FieldZ]; m_pVertexIndices = new int[(m_FieldXY+1) * 6]; Sub(&m_LowerLeftCorner, center, half_dim); m_FieldToWorld.x = xy_spacing; m_FieldToWorld.y = xy_spacing; m_FieldToWorld.z = z_spacing; m_WorldToField.x = 1.0f / xy_spacing; m_WorldToField.y = 1.0f / xy_spacing; m_WorldToField.z = 1.0f / z_spacing; // Create a vertex buffer, too. } /////////////////////////////////////////////////////////////////////////////// void BlobRenderer::getCoords(const D3DVECTOR& pos, int* p_x, int* p_y, int* p_z, D3DVECTOR* p_remainder) { float fx = (pos.x - m_LowerLeftCorner.x) * m_WorldToField.x; float fy = (pos.y - m_LowerLeftCorner.y) * m_WorldToField.y; float fz = (pos.z - m_LowerLeftCorner.z) * m_WorldToField.z; *p_x = (int) (fx); *p_y = (int) (fy); *p_z = (int) (fz); if (p_remainder) { p_remainder->x = fx - ((float)*p_x); p_remainder->y = fy - ((float)*p_y); p_remainder->z = fz - ((float)*p_z); } return (*p_z * m_FieldXY) + (*p_y * m_FieldX) + (*p_x); } /////////////////////////////////////////////////////////////////////////////// void BlobRenderer::getWorldPos(D3DVECTOR* pos, int x, int y, int z) { pos->x = m_LowerLeftCorner.x + ((float)x) * m_FieldToWorld.x; pos->y = m_LowerLeftCorner.y + ((float)y) * m_FieldToWorld.y; pos->z = m_LowerLeftCorner.z + ((float)z) * m_FieldToWorld.z; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// TestBlobRenderer::TestBlobRenderer() { } /////////////////////////////////////////////////////////////////////////////// TestBlobRenderer::~TestBlobRenderer() { destroy(); } /////////////////////////////////////////////////////////////////////////////// void TestBlobRenderer::create() { for (int i=0; i