Exemplo n.º 1
0
  ezResult Mesh::ComputeNormals()
  {
    ezStopwatch timer;

    const VertexDataStream* positionStreamRaw = GetDataStream(ezGALVertexAttributeSemantic::Position);
    if (positionStreamRaw == nullptr)
    {
      ezLog::Error("Can't compute vertex normals for the mesh '{0}', because it doesn't have vertex positions.", m_Name);
      return EZ_FAILURE;
    }
    const TypedVertexDataStreamView<ezVec3> positionStream(*positionStreamRaw);

    VertexDataStream* normalStreamRaw = AddDataStream(ezGALVertexAttributeSemantic::Normal, 3);
    TypedVertexDataStreamView_ReadWrite<ezVec3> normalStream(*normalStreamRaw);

    // Normals have same mapping as positions.
    normalStream->m_IndexToData = positionStreamRaw->m_IndexToData;
    // Reset all normals to zero.
    normalStream->m_Data.SetCountUninitialized(positionStreamRaw->m_Data.GetCount());
    ezMemoryUtils::ZeroFill<char>(normalStream->m_Data.GetData(), normalStream->m_Data.GetCount());


    // Compute unnormalized triangle normals and add them to all vertices.
    // This way large triangles have an higher influence on the vertex normal.
    for (const Triangle& triangle : m_Triangles)
    {
      const VertexIndex v0 = triangle.m_Vertices[0];
      const VertexIndex v1 = triangle.m_Vertices[1];
      const VertexIndex v2 = triangle.m_Vertices[2];

      const ezVec3 p0 = positionStream.GetValue(v0);
      const ezVec3 p1 = positionStream.GetValue(v1);
      const ezVec3 p2 = positionStream.GetValue(v2);

      const ezVec3 d01 = p1 - p0;
      const ezVec3 d02 = p2 - p0;

      const ezVec3 triNormal = d01.CrossRH(d02);
      normalStream.SetValue(v0, normalStream.GetValue(v0) +
                                    triNormal); // (possible optimization: have a special addValue to avoid unnecessary lookup)
      normalStream.SetValue(v1, normalStream.GetValue(v1) + triNormal);
      normalStream.SetValue(v2, normalStream.GetValue(v2) + triNormal);
    }

    // Normalize normals.
    for (ezUInt32 n = 0; n < normalStream->m_Data.GetCount(); n += sizeof(ezVec3))
      reinterpret_cast<ezVec3*>(&normalStream->m_Data[n])->NormalizeIfNotZero();

    ezLog::Debug("Computed mesh normals ('{0}') in '{1}'s", m_Name, ezArgF(timer.GetRunningTotal().GetSeconds(), 2));
    return EZ_SUCCESS;
  }
Exemplo n.º 2
0
// IM-2014-07-31: [[ ImageLoader ]] Use image loader method to identify stream format
uint32_t MCEncodedImageRep::GetDataCompression()
{
	if (m_have_compression)
		return m_compression;

	IO_handle t_stream;
	t_stream = nil;
	
	MCImageLoaderFormat t_format;
	
	if (GetDataStream(t_stream) && MCImageLoader::IdentifyFormat(t_stream, t_format))
		/* UNCHECKED */ MCImageLoaderFormatToCompression(t_format, m_compression);

	if (t_stream != nil)
		MCS_close(t_stream);

	return m_compression;
}
Exemplo n.º 3
0
bool MCEncodedImageRep::SetupImageLoader()
{
	if (m_loader != nil)
		return true;
	
	bool t_success;
	t_success = true;
	
	IO_handle t_stream;
	t_stream = nil;
	
	MCImageLoader *t_loader;
	t_loader = nil;
	
	if (t_success)
		t_success = GetDataStream(t_stream);
	
	if (t_success)
		t_success = MCImageLoader::LoaderForStream(t_stream, t_loader);
	
	if (t_success)
	{
		m_stream = t_stream;
		m_loader = t_loader;
		
		m_have_compression = MCImageLoaderFormatToCompression(m_loader->GetFormat(), m_compression);
	}
	else
	{
		if (t_loader != nil)
			delete t_loader;
		
		// PM-2015-10-20: [[ Bug 15256 ]] Prevent crash when loading a remote image and there is no internet connection
		if (t_stream != nil)
			MCS_close(t_stream);
	}
	
	return t_success;
}
Exemplo n.º 4
0
  ezResult Mesh::ComputeTangents()
  {
    ezStopwatch timer;

    struct MikkInterfaceImpl
    {
      MikkInterfaceImpl(Mesh& mesh, const VertexDataStream& position, const VertexDataStream& normal, const VertexDataStream& tex)
          : triangles(mesh.m_Triangles)
          , positionStream(position)
          , normalStream(normal)
          , texStream(tex)
          , tangentStream(*mesh.AddDataStream(ezGALVertexAttributeSemantic::Tangent, 3)) // Make sure tangent stream exists.
          , bitangentStream(*mesh.AddDataStream(ezGALVertexAttributeSemantic::BiTangent, 1))

          , bitangentIndexNegative(0)
          , bitangentIndexPositive(sizeof(float))
      {
        float biTangentSignValues[] = {-1.0f, 1.0f};
        bitangentStream.AddValues(ezMakeArrayPtr(biTangentSignValues));
      }

      ezArrayPtr<Triangle> triangles;
      const TypedVertexDataStreamView<ezVec3> positionStream;
      const TypedVertexDataStreamView<ezVec3> normalStream;
      const TypedVertexDataStreamView<ezVec2> texStream;
      TypedVertexDataStreamView_ReadWrite<ezVec3> tangentStream;
      TypedVertexDataStreamView_ReadWrite<float> bitangentStream;
      VertexDataIndex bitangentIndexPositive;
      VertexDataIndex bitangentIndexNegative;

      ezHashTable<ezVec3, VertexDataIndex> tangentDataMap;

      int GetNumFaces() const { return triangles.GetCount(); }
      int GetNumVerticesOfFace(const int iFace) const { return 3; }

      void GetPosition(float fvPosOut[], const int iFace, const int iVert) const
      {
        ezVec3 p = positionStream.GetValue(triangles[iFace].m_Vertices[iVert]);
        fvPosOut[0] = p.x;
        fvPosOut[1] = p.y;
        fvPosOut[2] = p.z;
      }
      void GetNormal(float fvNormOut[], const int iFace, const int iVert) const
      {
        ezVec3 n = normalStream.GetValue(triangles[iFace].m_Vertices[iVert]);
        fvNormOut[0] = n.x;
        fvNormOut[1] = n.y;
        fvNormOut[2] = n.z;
      }
      void GetTexCoord(float fvTexcOut[], const int iFace, const int iVert) const
      {
        ezVec2 uv = texStream.GetValue(triangles[iFace].m_Vertices[iVert]);
        fvTexcOut[0] = uv.x;
        fvTexcOut[1] = uv.y;
      }

      void SetTSpaceBasic(const float fvTangent[], const float fSign, const int iFace, const int iVert)
      {
        // Need to reconstruct indexing using hashmap lookups.
        // (will get a call to SetTSpaceBasic for every triangle vertex, not for every data vertex.)
        VertexIndex v = triangles[iFace].m_Vertices[iVert];
        ezVec3 key = ezVec3(fvTangent[0], fvTangent[1], fvTangent[2]);
        VertexDataIndex existingTangentIndex;
        if (tangentDataMap.TryGetValue(key, existingTangentIndex))
        {
          tangentStream->SetDataIndex(v, existingTangentIndex);
        }
        else
        {
          tangentStream.SetValue(v, ezVec3(fvTangent[0], fvTangent[1], fvTangent[2]));
          tangentDataMap.Insert(key, tangentStream->GetDataIndex(v));
        }

        // For bitangent sign its easy: There are only 2 signs and we've set the data already.
        if (fSign >= 1.0f)
          bitangentStream->SetDataIndex(v, bitangentIndexPositive);
        else
          bitangentStream->SetDataIndex(v, bitangentIndexNegative);
      }
    };

    // If there is already a data stream with 3 component bitangents, remove it.
    {
      VertexDataStream* bitangents = GetDataStream(ezGALVertexAttributeSemantic::BiTangent);
      if (bitangents && bitangents->GetNumElementsPerVertex() != 1)
        RemoveDataStream(ezGALVertexAttributeSemantic::BiTangent);
    }

    const VertexDataStream* positionStream = GetDataStream(ezGALVertexAttributeSemantic::Position);
    if (positionStream == nullptr)
    {
      ezLog::Error("Can't compute vertex tangents for the mesh '{0}', because it doesn't have vertex positions.", m_Name);
      return EZ_FAILURE;
    }
    const VertexDataStream* normalStream = GetDataStream(ezGALVertexAttributeSemantic::Normal);
    if (normalStream == nullptr)
    {
      ezLog::Error("Can't compute tangents for the mesh '{0}', because it doesn't have vertex normals.", m_Name);
      return EZ_FAILURE;
    }
    const VertexDataStream* texStream = GetDataStream(ezGALVertexAttributeSemantic::TexCoord0);
    if (texStream == nullptr || texStream->GetNumElementsPerVertex() != 2)
    {
      ezLog::Error("Can't compute tangents for the mesh '{0}', because it doesn't have TexCoord0 stream with two components.", m_Name);
      return EZ_FAILURE;
    }

    MikkInterfaceImpl mikkInterface(*this, *positionStream, *normalStream, *texStream);

    // Use Morton S. Mikkelsen's tangent calculation.
    SMikkTSpaceContext context;
    SMikkTSpaceInterface functions;
    context.m_pUserData = &mikkInterface;
    context.m_pInterface = &functions;
    functions.m_getNumFaces = [](const SMikkTSpaceContext* pContext) {
      return static_cast<MikkInterfaceImpl*>(pContext->m_pUserData)->GetNumFaces();
    };
    functions.m_getNumVerticesOfFace = [](const SMikkTSpaceContext* pContext, const int iFace) {
      return static_cast<MikkInterfaceImpl*>(pContext->m_pUserData)->GetNumVerticesOfFace(iFace);
    };
    functions.m_getPosition = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert) {
      return static_cast<MikkInterfaceImpl*>(pContext->m_pUserData)->GetPosition(fvPosOut, iFace, iVert);
    };
    functions.m_getNormal = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert) {
      return static_cast<MikkInterfaceImpl*>(pContext->m_pUserData)->GetNormal(fvPosOut, iFace, iVert);
    };
    functions.m_getTexCoord = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert) {
      return static_cast<MikkInterfaceImpl*>(pContext->m_pUserData)->GetTexCoord(fvPosOut, iFace, iVert);
    };
    functions.m_setTSpaceBasic = [](const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace,
                                    const int iVert) {
      return static_cast<MikkInterfaceImpl*>(pContext->m_pUserData)->SetTSpaceBasic(fvTangent, fSign, iFace, iVert);
    };
    functions.m_setTSpace = nullptr;

    if (!genTangSpaceDefault(&context))
    {
      ezLog::Error("Failed to compute compute tangents for the mesh {0}.", m_Name);
      return EZ_FAILURE;
    }

    ezLog::Debug("Computed mesh normals ('{0}') in '{1}'s", m_Name, ezArgF(timer.GetRunningTotal().GetSeconds(), 2));
    return EZ_SUCCESS;
  }
Exemplo n.º 5
0
bool MCEncodedImageRep::LoadImageFrames(MCImageFrame *&r_frames, uindex_t &r_frame_count, bool &r_frames_premultiplied)
{
	bool t_success = true;

	// IM-2013-02-18 - switching this back to using MCImageImport as we need to
	// determine the compression type for m_compression

	IO_handle t_stream = nil;
	IO_handle t_mask_stream = nil;

	MCImageCompressedBitmap *t_compressed = nil;
	MCImageBitmap *t_bitmap = nil;

	MCPoint t_hotspot = {1, 1};
	char *t_name = nil;

	t_success = GetDataStream(t_stream) &&
		MCImageImport(t_stream, t_mask_stream, t_hotspot, t_name, t_compressed, t_bitmap);

	if (t_stream != nil)
		MCS_close(t_stream);

	MCImageFrame *t_frames;
	t_frames = nil;
	
	uindex_t t_frame_count;
	t_frame_count = 0;
	
	if (t_success)
	{
		if (t_compressed != nil)
			t_success = MCImageDecompress(t_compressed, t_frames, t_frame_count);
		else
		{
			t_success = MCMemoryNewArray(1, t_frames);
			if (t_success)
			{
				t_frames[0].image = t_bitmap;
				t_frames[0].density = 1.0;
				t_bitmap = nil;
				t_frame_count = 1;
			}
		}
	}

	if (t_success)
	{

		m_width = t_frames[0].image->width;
		m_height = t_frames[0].image->height;

		if (t_compressed != nil)
			m_compression = t_compressed->compression;

		m_have_geometry = true;
		
		r_frames = t_frames;
		r_frame_count = t_frame_count;
		r_frames_premultiplied = false;
	}

	MCCStringFree(t_name);
	
	MCImageFreeBitmap(t_bitmap);
	MCImageFreeCompressedBitmap(t_compressed);

	return t_success;
}