bool CAnimationManager::ProcessFrame()

in Firmware/ExpressivePixelsCore/CAnimationManager.cpp [192:361]


bool CAnimationManager::ProcessFrame(ACTIVE_ANIMATIONSEQUENCE *pSequence, uint8_t *pFrameAsBytes)
{
	char        frameType;	
	uint16_t    pixelCount;
	uint16_t	totalPixels = m_pCDisplayTopology != NULL ? m_pCDisplayTopology->TotalPixels() : m_pCDisplayArray->TotalPixels();
	
	// Only read more if there are frames remaining
	if(pSequence->currentFrameOffset < pSequence->Sequence.Meta.cbFrames)
	{		
		// Read frame type
		if(!ReadAnimationBytes(pSequence, (uint8_t *) &frameType, sizeof(frameType)))
			return true;
	
		// Determine the animation frame type or action
		switch(frameType)
		{
		case 'I':
			// Extract the pixel count
			if(!ReadAnimationBytes(pSequence, (uint8_t *) &pixelCount, sizeof(pixelCount)))
				return true;
			//DEBUGLOGLN("Animator KEY frame %d pixels", pixelCount);
			
			// Process pixels
			for(int i = 0 ; i < pixelCount ; i++)
			{
				uint8_t  paletteIndex;
				uint16_t pixelPosition;
			
				// Extract palette index
				if(!ReadAnimationBytes(pSequence, (uint8_t *) &paletteIndex, sizeof(paletteIndex)))
					return true;

				if (paletteIndex <= pSequence->Sequence.Meta.cbPallete - 1)
				{
					PALETTE_ENTRY *paletteEntry = pSequence->Sequence.pPalette + paletteIndex;
					uint32_t color = CDisplayArray::ColorFromBytes(paletteEntry->r, paletteEntry->g, paletteEntry->b);

					// Figure topographical position
					if(m_pCDisplayTopology != NULL)
						pixelPosition = m_nRotation == 0 ? m_pCDisplayTopology->Map(i) : m_pCDisplayTopology->MapRotated(i, m_nRotation);
					else
						pixelPosition = i;							
					if (pixelPosition != TOPOLOGYPIXEL_UNASSIGNED)
					{
						if (pFrameAsBytes != NULL)
							m_pCDisplayArray->GetPixelBytes(color, pFrameAsBytes + (i * 3), pFrameAsBytes + (i * 3) + 1, pFrameAsBytes + (i * 3) + 2);
						else
							// Extract color from palette and set LED color
							m_pCDisplayArray->SetPixelColor(pixelPosition, color);
					}
				}			
			}
			if (pFrameAsBytes == NULL)
				m_pCDisplayArray->Show();
			break;

		case 'P':
			// Extract the pixel count
			if(!ReadAnimationBytes(pSequence, (uint8_t *) &pixelCount, sizeof(pixelCount)))
				return true;
			//DEBUGLOGLN("Animator Predictive frame %d pixels", pixelCount);
			
			// Process pixels
			for(int i = 0 ; i < pixelCount ; i++)
			{
				uint8_t  paletteIndex;
				uint16_t logicalPixelPosition = 0;
				uint16_t physicalPixelPosition = TOPOLOGYPIXEL_UNASSIGNED;

				// Determine if 8 or 16 bit pixel position size
				uint8_t pixelPositionByteSize = totalPixels > 256 ? sizeof(uint16_t) : sizeof(uint8_t);
			
				// Extract pixel position
				if(!ReadAnimationBytes(pSequence, (uint8_t *) &logicalPixelPosition, pixelPositionByteSize))
					return true;

				// Extract palette index
				if(!ReadAnimationBytes(pSequence, (uint8_t *) &paletteIndex, sizeof(paletteIndex)))
					return true;

				if (paletteIndex < pSequence->Sequence.Meta.cbPallete)
				{				
					PALETTE_ENTRY *paletteEntry = pSequence->Sequence.pPalette + paletteIndex;
					uint32_t color = CDisplayArray::ColorFromBytes(paletteEntry->r, paletteEntry->g, paletteEntry->b);
				
					if (m_pCDisplayTopology != NULL)
						physicalPixelPosition = m_nRotation == 0 ? m_pCDisplayTopology->Map(logicalPixelPosition) : m_pCDisplayTopology->MapRotated(logicalPixelPosition, m_nRotation);
				
					// If a positional pixel
					if(physicalPixelPosition != TOPOLOGYPIXEL_UNASSIGNED)
					{
						if (pFrameAsBytes != NULL)
							m_pCDisplayArray->GetPixelBytes(color, pFrameAsBytes + (logicalPixelPosition * 3), pFrameAsBytes + (logicalPixelPosition * 3) + 1, pFrameAsBytes + (logicalPixelPosition * 3) + 2);
						else
							// Extract color from palette and set LED color
							m_pCDisplayArray->SetPixelColor(physicalPixelPosition, color);
					}
				}
			}
			if (pFrameAsBytes == NULL)
				m_pCDisplayArray->Show();
			break;

		case 'D':		
			uint16_t delayMillis;
		
			if (!ReadAnimationBytes(pSequence, (uint8_t *) &delayMillis, sizeof(delayMillis)))
				return true;
			m_activeDelayMillis = delayMillis;
			m_previousDelayMillis = millis();
			DEBUGLOGLN("WAIT %d", m_activeDelayMillis);
			break;
		
		case 'F':
			uint16_t fadeMillis;
		
			if (!ReadAnimationBytes(pSequence, (uint8_t *) &fadeMillis, sizeof(fadeMillis)))
				return true;
			m_activeFadeKernel = 0;
			m_activeFadeMillis = fadeMillis;
			m_previousFadeMillis = millis();
			DEBUGLOGLN("FADE over %d ms", m_activeFadeMillis);
			return false;
		}
	}

	// See if all of the animation bytes have been read
	if(pFrameAsBytes == NULL && pSequence->currentFrameOffset >= pSequence->Sequence.Meta.cbFrames)
	{
		//DEBUGLOGLN("Animator ALL animation bytes read %d >= %d", pSequence->currentFrameOffset ,pSequence->Sequence.framesByteLen);
		
		/*** Last frame in animation now complete ***/
		if(pSequence->Sequence.Meta.loopCount == 1)
			return true;
		else
		{
			if (pSequence->Sequence.Meta.loopCount > 1)
			{
				if (pSequence->Sequence.Meta.loopCount < 255)
				{
					// This animation repeats
					pSequence->currentRepeatIteration++;

					// If all repeats complete
					if(pSequence->currentRepeatIteration >= pSequence->Sequence.Meta.loopCount)
					{
						//DEBUGLOGLN("Animator ALL repeats complete %d >= %d", pSequence->currentRepeatIteration, pSequence->Sequence.loopCount);
						// Return full complete
						return true;
					}
				}
			}
			else if (m_disableInfiniteLooping)
				return true;

			// Start the animation over again
			pSequence->currentFrameOffset = 0;
			
#ifdef VARIANTCAPABILITY_STORAGE			
			if (pSequence->Sequence.pFile != NULL)
				CStorage::Seek(pSequence->Sequence.pFile, pSequence->Sequence.frameBytesStartOffset);
#endif			
			m_pCDisplayArray->Clear();
		}
	}

	// Animation still in progress
	//DEBUGLOGLN("Animation still in progress");
	return false;
}