//! adds a characters to a text vertex buffer
void GeometryProvider::AddCharacter(VertexBuffer* pVertexBuffer, Font* pFont, char c, const Vector2& vCharacterPos, u32 currentCharacter, const Color& color)
{
    SHOOT_ASSERT(currentCharacter*6+6 <= pVertexBuffer->GetMaxVertices(), "TextVertexBuffer overflow");
    u32 index = (c - ' ');
    if(index > 111)
    {
        index = ('?' - ' '); // use ? for missing characters
    }
    u32 row = index / pFont->GetNumCharactersPerLine();
    u32 column = index % pFont->GetNumCharactersPerLine();

    Vector2 textureSize = pFont->GetTextureSize();
    Vector2 characterSize = pFont->GetCharacterSize();
    Vector2 uvSize(characterSize.X/textureSize.X, characterSize.Y/textureSize.Y);
    Vector2 uvStart(column*uvSize.X, row*uvSize.Y);
    Vector2 uvEnd = uvStart + uvSize;

    AABBox2D srcRect(uvStart, uvEnd);
    AABBox2D destRect(vCharacterPos, vCharacterPos+characterSize);
    Vertex3D* pVertices = pVertexBuffer->GetVertices();
    u32 i = currentCharacter;
    pVertices[i*6+0].UV = Vector2(srcRect.Min().X, srcRect.Min().Y);
    pVertices[i*6+0].Pos = Vector3::Create(destRect.Min().X, destRect.Min().Y, 0.0f);
    pVertices[i*6+1].UV = Vector2(srcRect.Max().X, srcRect.Min().Y);
    pVertices[i*6+1].Pos = Vector3::Create(destRect.Max().X, destRect.Min().Y, 0.0f);
    pVertices[i*6+2].UV = Vector2(srcRect.Min().X, srcRect.Max().Y);
    pVertices[i*6+2].Pos = Vector3::Create(destRect.Min().X, destRect.Max().Y, 0.0f);
    pVertices[i*6+3].UV = Vector2(srcRect.Min().X, srcRect.Max().Y);
    pVertices[i*6+3].Pos = Vector3::Create(destRect.Min().X, destRect.Max().Y, 0.0f);
    pVertices[i*6+4].UV = Vector2(srcRect.Max().X, srcRect.Min().Y);
    pVertices[i*6+4].Pos = Vector3::Create(destRect.Max().X, destRect.Min().Y, 0.0f);
    pVertices[i*6+5].UV = Vector2(srcRect.Max().X, srcRect.Max().Y);
    pVertices[i*6+5].Pos = Vector3::Create(destRect.Max().X, destRect.Max().Y, 0.0f);

    for(u32 j=0; j<6; ++j)
    {
        pVertices[i*6+j].color = color;
    }
}
bool mjpeg_decoder_t::decode_complete(void const *&y, void const *&u, void const *&v, void *&opaque, unsigned &displayIdx, int &picType, bool &errors )
{
        displayIdx = 0 ;
	errors = false ;
	if( startedDecode_ && !vpu_IsBusy() ){
                DecOutputInfo outinfo = {0};
		RetCode ret = vpu_DecGetOutputInfo(handle_, &outinfo);
debugPrint("vpu_DecGetOutputInfo(%d): %d display, %d decode\n", ret, outinfo.indexFrameDisplay, outinfo.indexFrameDecoded);
		if (ret == RETCODE_SUCCESS) {
			startedDecode_ = false ;
			debugPrint("success %d\n", outinfo.decodingSuccess);
			debugPrint("indexFrame decoded %d (0x%x)\n", outinfo.indexFrameDecoded, outinfo.indexFrameDecoded);
			debugPrint("indexFrame display %d (0x%x)\n", outinfo.indexFrameDisplay, outinfo.indexFrameDisplay);
			debugPrint("picType %d\n", outinfo.picType);
			picType = outinfo.picType ;
			if( 0 != outinfo.numOfErrMBs) {
				debugPrint("%d errMBs\n", outinfo.numOfErrMBs);
				errors = true ;
			}
			debugPrint("qpInfo %p\n", outinfo.qpInfo);
			debugPrint("hscale %d\n", outinfo.hScaleFlag);
			debugPrint("vscale %d\n", outinfo.vScaleFlag);
			debugPrint("index rangemap %d\n", outinfo.indexFrameRangemap);
			debugPrint("prescan result %d\n", outinfo.prescanresult);
			debugPrint("picstruct %d\n", outinfo.pictureStructure);
			debugPrint("topfield first %d\n", outinfo.topFieldFirst);
			debugPrint("repeat first %d\n", outinfo.repeatFirstField);
			debugPrint("field seq %d\n", outinfo.fieldSequence);
			debugPrint("size %dx%d\n", outinfo.decPicWidth, outinfo.decPicHeight);
			debugPrint("nsps %d\n", outinfo.notSufficientPsBuffer);
			debugPrint("nsslice %d\n", outinfo.notSufficientSliceBuffer);
			debugPrint("success %d\n", outinfo.decodingSuccess);
			debugPrint("interlaced %d\n", outinfo.interlacedFrame);
			debugPrint("mp4packed %d\n", outinfo.mp4PackedPBframe);
			debugPrint("h264Npf %d\n", outinfo.h264Npf);
			debugPrint("prog/repeat %d\n", outinfo.progressiveFrame);
			debugPrint("crop %d:%d->%d:%d\n", outinfo.decPicCrop.left,outinfo.decPicCrop.top, outinfo.decPicCrop.right, outinfo.decPicCrop.bottom);
			if( (0 <= outinfo.indexFrameDisplay) && (fbcount > outinfo.indexFrameDisplay) ){
				unsigned mask = 1<<outinfo.indexFrameDisplay ;
				assert(0 != (decoder_fbs&mask));
				decoder_fbs &= ~mask ;
				assert(0 == (app_fbs & mask));
				app_fbs |= mask ;

				frame_buf *pfb = pfbpool+outinfo.indexFrameDisplay ;
				y = (void *)(pfb->addrY + pfb->desc.virt_uaddr - pfb->desc.phy_addr);
				u = (char *)y + ySize();
				v = (char *)u + uvSize();
                                displayIdx = outinfo.indexFrameDisplay ;
				debugPrint("returning display index %u:%p\n", displayIdx,y);
				return true ;
			} else {
				fprintf(stderr, "Invalid display fb index: %d\n", outinfo.indexFrameDisplay);
				startDecode();
			}
		} else {
			fprintf( stderr, "Error %d from vpu_DecGetOutputInfo\n", ret );
		}
	} else {
		debugPrint( "VPU is busy\n" );
                vpu_WaitForInt(0);
	}

	return false ;
}