Exemple #1
0
void CCollisionManager::ClipFaceFaceVerts(vec3* verts0,
                                          int* vertIndexs0,
                                          vec3* verts1,
                                          int* vertIndexs1,
                                          vec3* vertsX,
                                          int* numVertsX)
{
   SortVertices(verts0, vertIndexs0);
   SortVertices(verts1, vertIndexs1);

   // Work out the normal for the face
   vec3 v0 = verts0[1] - verts0[0];
   vec3 v1 = verts0[2] - verts0[0];
   vec3 n  = cross(v1, v0);
   n = normalize(n);

   // Project all the vertices onto a shared plane, plane0
   vec3 vertsTemp1[4];
   for (int i=0; i<4; i++)
   {
      vertsTemp1[i] = verts1[i] + (n * dot(n, verts0[0]-verts1[i]));
   }

   static vec3 temp[50];
   int numVerts = 0;

   for (int c=0; c<2; c++)
   {
      vec3* vertA = vertsTemp1;
      vec3* vertB = verts0;
      if (c==1)
      {
         vertA = verts0;
         vertB = vertsTemp1;
      }

      // Work out the normal for the face
      vec3 v0 = vertA[1] - vertA[0];
      vec3 v1 = vertA[2] - vertA[0];
      vec3 n  = cross(v1, v0);
      n = normalize(n);

      for (int i=0; i<4; i++)
      {
         vec3 s0 = vertA[i];
         vec3 s1 = vertA[(i+1)%4];
         vec3 sx = s0 + n*10.0f;

         // Work out the normal for the face
         vec3 sv0 = s1 - s0;
         vec3 sv1 = sx - s0;
         vec3 sn  = cross(sv1, sv0);
         sn = normalize(sn);

         float d = dot(s0, sn);


         for (int j=0; j<4; j++)
         {
            vec3 p0 = vertB[j];
            vec3 p1 = vertB[(j+1)%4]; // Loops back to the 0th for the last one

            float d0 = dot(p0, sn) - d;
            float d1 = dot(p1, sn) - d;

            // Check there on opposite sides of the plane
            if ( (d0 * d1) < 0.0f)
            {
               vec3 pX = p0   +   ( dot(sn, (s0-p0)) /  dot(sn, (p1-p0)) )  *  (p1 - p0);

               if (VertInsideFace(vertA, pX, 0.1f))
               {
                  temp[numVerts] = pX;
                  numVerts++;
               }
            }

            if (VertInsideFace(vertA, p0))
            {
               temp[numVerts] = p0;
               numVerts++;
            }
         }
      }
   }

   // Remove verts which are very close to each other
   for (int i=0; i<numVerts; i++)
   {
      for (int j=i; j<numVerts; j++)
      {
         if (i!=j)
         {
            auto squaredLength = length(temp[i] - temp[j]);
            squaredLength *= squaredLength;
            float dist = squaredLength;

            if (dist < 6.5f)
            {
               for (int k=j; k<numVerts; k++)
               {
                  temp[k] = temp[k+1];
               }
               numVerts--;
            }
         }
      }
   }

   *numVertsX = numVerts;
   for (int i=0; i<numVerts; i++)
   {
      vertsX[i] = temp[i];
   }
}
/*!***************************************************************************
 @Function		PVRTGeometrySort
 @Modified		pVtxData		Pointer to array of vertices
 @Modified		pwIdx			Pointer to array of indices
 @Input			nStride			Size of a vertex (in bytes)
 @Input			nVertNum		Number of vertices. Length of pVtxData array
 @Input			nTriNum			Number of triangles. Length of pwIdx array is 3* this
 @Input			nBufferVtxLimit	Number of vertices that can be stored in a buffer
 @Input			nBufferTriLimit	Number of triangles that can be stored in a buffer
 @Input			dwFlags			PVRTGEOMETRY_SORT_* flags
 @Description	Triangle sorter
*****************************************************************************/
void PVRTGeometrySort(
	void				* const pVtxData,
	PVRTGEOMETRY_IDX	* const pwIdx,
	const int			nStride,
	const int			nVertNum,
	const int			nTriNum,
	const int			nBufferVtxLimit,
	const int			nBufferTriLimit,
	const unsigned int	dwFlags)
{
	CObject				sOb(pwIdx, nVertNum, nTriNum, nBufferVtxLimit, nBufferTriLimit);
	CBlock				sBlock(nBufferVtxLimit, nBufferTriLimit);
	PVRTGEOMETRY_IDX	*pwIdxOut;
	int					nTriCnt, nVtxCnt;
	int					nOutTriCnt, nOutVtxCnt, nOutBlockCnt;
	int					nMeshToResize;
#ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
	int					i;
	int					pnBlockTriCnt[PVRVGPBLOCKTEST_MAX_BLOCKS];
	SVGPModel			sVGPMdlBefore;
	SVGPModel			sVGPMdlAfter;
#endif

	if(dwFlags & PVRTGEOMETRY_SORT_VERTEXCACHE) {
#ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
		VGP590Test(&sVGPMdlBefore, pwIdx, nTriNum);
		_RPT4(_CRT_WARN, "OptimiseTriListPVR() Before: Tri: %d, Vtx: %d, vtx/tri=%f Blocks=%d\n", nTriNum, sVGPMdlBefore.nVtxCnt, (float)sVGPMdlBefore.nVtxCnt / (float)nTriNum, sVGPMdlBefore.nBlockCnt);
#endif

		pwIdxOut	= (PVRTGEOMETRY_IDX*)malloc(nTriNum * 3 * sizeof(*pwIdxOut));
		_ASSERT(pwIdxOut);

		// Sort geometry into blocks
		nOutTriCnt		= 0;
		nOutVtxCnt		= 0;
		nOutBlockCnt	= 0;
		do {
			// Clear & fill the block
			sBlock.Clear();
			nMeshToResize = sBlock.Fill(&sOb);

			// Copy indices into output
			sBlock.Output(&pwIdxOut[3*nOutTriCnt], &nVtxCnt, &nTriCnt, &sOb);
			sOb.m_nTriNumFree	-= nTriCnt;
			nOutTriCnt			+= nTriCnt;

			if(nMeshToResize >= 0) {
				SMesh	*pMesh;
				_ASSERT(nMeshToResize <= (nBufferVtxLimit-3));
				pMesh = &sOb.m_pvMesh[nMeshToResize].back();
				sOb.ResizeMesh(pMesh->nVtxNum, pMesh->ppVtx);
				sOb.m_pvMesh[nMeshToResize].pop_back();
			}

			_ASSERT(nVtxCnt <= nBufferVtxLimit);
			_ASSERT(nTriCnt <= nBufferTriLimit);

#ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
			_ASSERT(nOutBlockCnt < PVRVGPBLOCKTEST_MAX_BLOCKS);
			pnBlockTriCnt[nOutBlockCnt] = nTriCnt;
#endif
			nOutVtxCnt += nVtxCnt;
			nOutBlockCnt++;

//			_RPT4(_CRT_WARN, "%d/%d tris (+%d), %d blocks\n", nOutTriCnt, nTriNum, nTriCnt, nOutBlockCnt);

			_ASSERT(nTriCnt == nBufferTriLimit || (nBufferVtxLimit - nVtxCnt) < 3 || nOutTriCnt == nTriNum);
		} while(nOutTriCnt < nTriNum);

		_ASSERT(nOutTriCnt == nTriNum);
		// The following will fail if optimising a subset of the mesh (e.g. a bone batching)
		//_ASSERT(nOutVtxCnt >= nVertNum);

		// Done!
		memcpy(pwIdx, pwIdxOut, nTriNum * 3 * sizeof(*pwIdx));
		FREE(pwIdxOut);

		_RPT3(_CRT_WARN, "OptimiseTriListPVR() In: Tri: %d, Vtx: %d, vtx/tri=%f\n", nTriNum, nVertNum, (float)nVertNum / (float)nTriNum);
		_RPT4(_CRT_WARN, "OptimiseTriListPVR() HW: Tri: %d, Vtx: %d, vtx/tri=%f Blocks=%d\n", nOutTriCnt, nOutVtxCnt, (float)nOutVtxCnt / (float)nOutTriCnt, nOutBlockCnt);

#ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
		VGP590Test(&sVGPMdlAfter, pwIdx, nTriNum);
		_RPT4(_CRT_WARN, "OptimiseTriListPVR() After : Tri: %d, Vtx: %d, vtx/tri=%f Blocks=%d\n", nTriNum, sVGPMdlAfter.nVtxCnt, (float)sVGPMdlAfter.nVtxCnt / (float)nTriNum, sVGPMdlAfter.nBlockCnt);
		_ASSERTE(sVGPMdlAfter.nVtxCnt <= sVGPMdlBefore.nVtxCnt);
		_ASSERTE(sVGPMdlAfter.nBlockCnt <= sVGPMdlBefore.nBlockCnt);

		for(i = 0; i < nOutBlockCnt; ++i) {
			_ASSERT(pnBlockTriCnt[i] == sVGPMdlAfter.pnBlockTriCnt[i]);
		}
#endif
	}

	if(!(dwFlags & PVRTGEOMETRY_SORT_IGNOREVERTS)) {
		// Re-order the vertices so maybe they're accessed in a more linear
		// manner. Should cut page-breaks on the initial memory read of
		// vertices. Affects both the order of vertices, and the values
		// of indices, but the triangle order is unchanged.
		SortVertices(pVtxData, pwIdx, nStride, nVertNum, nTriNum*3);
	}
}
Exemple #3
0
void sreLODModel::UploadToGPU(int attribute_mask, int dynamic_flags) {
    // Check that all attributes defined in attribute_mask are present in the model
    // (enabled in sreBaseModel::flags).
    if ((attribute_mask & flags) != attribute_mask)
        sreFatalError("Error (sreLODModel::UploadToGPU): Not all requested attributes are present the base model.");
    if (attribute_mask == 0)
        sreFatalError("Error (sreLODModel::UploadToGPU): attribute_mask = 0 (unexpected).");

    // This is not the best place to initialize this table (which is used when drawing objects).
    if (!attribute_list_table_initialized)
        sreGenerateAttributeListTable();

    bool shadow =
        (sre_internal_rendering_flags & SRE_RENDERING_FLAG_SHADOW_VOLUME_SUPPORT)
        && !(flags & SRE_LOD_MODEL_NO_SHADOW_VOLUME_SUPPORT)
        && (flags & SRE_LOD_MODEL_IS_SHADOW_VOLUME_MODEL);

    if (flags & SRE_LOD_MODEL_BILLBOARD) {
        // Special case for billboards; little has to be uploaded yet.
        glGenBuffers(1, &GL_attribute_buffer[SRE_ATTRIBUTE_POSITION]);
        if (flags & SRE_LOD_MODEL_LIGHT_HALO)
            glGenBuffers(1, &GL_attribute_buffer[SRE_ATTRIBUTE_NORMAL]);
        if (attribute_mask & SRE_TEXCOORDS_MASK) {
            // Any texture coordinates (for use with an emission map) have to be uploaded.
            glGenBuffers(1, &GL_attribute_buffer[SRE_ATTRIBUTE_TEXCOORDS]);
            glBufferData(GL_ARRAY_BUFFER, nu_vertices * sizeof(float) * 2, texcoords,
               GL_STATIC_DRAW);
        }
        // Set the non-interleaved attribute info (just the lower 8 bits are used).
        // The interleaved information is set to zero.
        attribute_info.attribute_masks = attribute_mask;
        if (nu_triangles == 0)
            // For single billboards, no triangles are allocated (they always consist
            // of a two triangle fan with the order of the vertex data).
            return;
        goto copy_indices;
    }

    //DEBUG
//    cache_coherency_sorting_hint = 0;

    // Determine a sorting order that optimizes cache coherency.
    {
    uint64_t best_cost = UINT64_MAX;
    int best_sorting_dimension = 0;
    const char *predefined_str;
    if (cache_coherency_sorting_hint != SRE_SORTING_HINT_UNDEFINED) {
        best_sorting_dimension = cache_coherency_sorting_hint;
	if (cache_coherency_sorting_hint == SRE_SORTING_HINT_DO_NOT_SORT)
            predefined_str = "predefined, keep original order";
        else
            predefined_str = "predefined";
    }
    else {
        uint64_t preexisting_cost = CalculateCacheCoherency();
        sreBaseModel *clone = new sreBaseModel;
        CloneGeometry(clone);
        for (int dim = 0; dim < 48; dim++) {
            clone->SortVertices(dim);
            uint64_t cost = clone->CalculateCacheCoherency();
//            sreMessage(SRE_MESSAGE_INFO, "Sorting dimension = %d, cost = %llu.", dim, cost);
            if (cost < best_cost) {
               best_cost = cost;
               best_sorting_dimension = dim;
            }
        }
        delete clone;
        if (preexisting_cost <= best_cost) {
            best_sorting_dimension = SRE_SORTING_HINT_DO_NOT_SORT;
            predefined_str = "kept original order";
        }
        else
            predefined_str = "calculated";
    }
    if (best_sorting_dimension != SRE_SORTING_HINT_DO_NOT_SORT)
        SortVertices(best_sorting_dimension);
    sreMessage(SRE_MESSAGE_LOG, "sreLODModel::UploadToGPU: Model %d sorting order %d (%s).", id,
        best_sorting_dimension, predefined_str);
    }

    int total_nu_vertices;
    sreLODModelShadowVolume *model_shadow_volume;
    if (shadow) {
        model_shadow_volume = (sreLODModelShadowVolume *)this;
        total_nu_vertices = nu_vertices * 2; // Times two for extruded vertices.
    }
    else
        total_nu_vertices = nu_vertices;

    Vector4D *positions_4D;
    if (attribute_mask & SRE_POSITION_MASK) {
        // Create 4D array for vertex position buffer from aligned 3D positions in
	// sreBaseModel geometry.
        positions_4D = new Vector4D[total_nu_vertices];
        // Copy vertex positions, adding a w component of 1.0 for the shaders.
        for (int i = 0; i < nu_vertices; i++)
            positions_4D[i] = Vector4D(vertex[i], 1.0f);

        // Create vertices extruded to infinity for shadow volumes.
        if (shadow) {
            for (int i = 0; i < nu_vertices; i++)
                // w = 0 for extruded vertices.
                positions_4D[i + nu_vertices] = Vector4D(vertex[i], 0.0f);
            model_shadow_volume->vertex_index_shadow_offset = nu_vertices;
        }
    }

    // Interleaving vertex attributes may increase GPU cache/memory performance, especially
    // on low-end GPUs.
    // Currently it isn't really optimal when extruded vertex positions for shadow volumes
    // are used, because the second half of the buffer will contain gaps for the non-position
    // attributes.

    // The current behaviour, when SRE_INTERLEAVED_BUFFERS_ENABLED is set, is to simply
    // combine all the model's attributes in one interleaved buffer. However, support is
    // in place for any combination of non-interleaved and up to three interleaved vertex
    // buffers.

    // When extruded shadow volume vertices are required, or dynamic_flags is set, no
    // interleaved buffers are created.
    if (sre_internal_interleaved_vertex_buffers_mode == SRE_INTERLEAVED_BUFFERS_ENABLED
    && dynamic_flags == 0 && !shadow && !OnlyOneAttributeSet(attribute_mask)) {
        // Interleave attribute data.
        NewVertexBufferInterleaved(attribute_mask, positions_4D, shadow);
        // Set the interleaved attribute info. Interleaved slot 0 is used, located
        // at bits 8-15. The non-interleaved information is set to zero.
        attribute_info.attribute_masks = attribute_mask << 8;
        goto finish;
    }

    // The attribute arrays for vertex normals, texcoords, tangents and colors in the
    // model data structure are already properly formatted to be forwarded to the GPU.

    NewVertexBuffers(attribute_mask, dynamic_flags, positions_4D, shadow);
    // Set the non-interleaved attribute info (just the lower 8 bits are used).
    // The interleaved information is set to zero.
    attribute_info.attribute_masks = attribute_mask;

finish :
    if (attribute_mask & SRE_POSITION_MASK)
        // 4D positions no longer required.
        delete [] positions_4D;

    sreMessage(SRE_MESSAGE_LOG,
        "sreLODModel::UploadToGPU: Uploading model %d, attribute_mask 0x%02X.",
        id, attribute_mask);

    // If the model is in any way instanced (at least one attribute shared), then we can
    // be sure that the triangle vertex indices are already present on the GPU and will
    // also be shared.
    if ((attribute_mask ^ flags) & attribute_mask) {
        if (shadow && (attribute_mask & SRE_POSITION_MASK))
            goto calculate_edges;
        // Finished.
        return;
    }

copy_indices:
    // Copy triangle vertex indices.
    unsigned short *triangle_vertex_indices;
    // Decide whether to use short indices (range 0 - 65535);
    // when PRIMITIVE_RESTART is allowed for drawing shadow volumes, the highest index
    // is reserved.
    int max_short_index;
    max_short_index = 65535;
#ifndef NO_PRIMITIVE_RESTART
    if (shadow && GLEW_NV_primitive_restart)
        max_short_index = 65534;
#endif
    if (total_nu_vertices > max_short_index) {
        // Keep new/delete happy by using unsigned short.
        triangle_vertex_indices = new unsigned short[nu_triangles * 3 * 2];
        unsigned int *indices = (unsigned int *)triangle_vertex_indices;
        for (int i = 0; i < nu_triangles; i++)
            for (int j = 0; j < 3; j++)
                indices[i * 3 + j] = triangle[i].vertex_index[j];
        GL_indexsize = 4;
    }
    else {
        triangle_vertex_indices = new unsigned short[nu_triangles * 3 * 2];
        unsigned short *indices16 = triangle_vertex_indices;
        for (int i = 0; i < nu_triangles; i++)
            for (int j = 0; j < 3; j++)
                indices16[i * 3 + j] = triangle[i].vertex_index[j];
        GL_indexsize = 2;
        sreMessage(SRE_MESSAGE_LOG,
            "Less or equal to %d vertices in object (including extruded shadow vertices), "
            "using 16-bit indices.", max_short_index + 1);
    }
    // Upload triangle vertex indices.
    glGenBuffers(1, &GL_element_buffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_element_buffer);
    sreCheckGLError("OpenGL error before element array buffer creation.\n");
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, nu_triangles * 3 * GL_indexsize,
        triangle_vertex_indices, GL_STATIC_DRAW);
    if (glGetError() != GL_NO_ERROR)
        sreFatalError("OpenGL error occurred during element array buffer creation.");
    delete [] triangle_vertex_indices;

    if (!shadow)
        return; // Finished.

calculate_edges :
    // Create edge array for shadow silhouette determination (shadow volumes).
    if (model_shadow_volume->nu_edges == 0)
        model_shadow_volume->CalculateEdges();
    else
        sreMessage(SRE_MESSAGE_WARNING,
            "Warning: sreLODModel::UploadToGPU: edges already calculated "
            "(shouldn't happen).");
}