Example #1
0
void Mesh::StopAnimation() {
  DEVASSERT(IsAnimated());

  if (IsAnimated()) {
    m_AnimationState.StopAnimation();
  }
}
Example #2
0
void Mesh::AddAnimationListener(const SAnimationListener& AnimationListener) {
  DEVASSERT(IsAnimated());

  if (IsAnimated()) {
    m_AnimationState.AddAnimationListener(AnimationListener);
  }
}
Example #3
0
const Animation* Mesh::GetPlayingAnimation() const {
  DEVASSERT(IsAnimated());

  if (IsAnimated()) {
    return m_AnimationState.GetPlayingAnimation();
  } else {
    return nullptr;
  }
}
Example #4
0
Animation* Mesh::GetAnimation(const SimpleString& Name) const {
  DEVASSERT(IsAnimated());

  if (IsAnimated()) {
    return m_Bones->GetAnimation(Name);
  }

  return nullptr;
}
Example #5
0
void Mesh::SetAnimation(int AnimationIndex,
                        AnimationState::SPlayAnimationParams& PlayParams) {
  DEVASSERT(IsAnimated());

  if (IsAnimated()) {
    PlayParams.m_SuppressAnimEvents = true;
    m_AnimationState.PlayAnimation(m_Bones->GetAnimation(AnimationIndex),
                                   PlayParams);
  }
}
Example #6
0
void Mesh::PlayAnimation(const HashedString& AnimationName,
                         AnimationState::SPlayAnimationParams& PlayParams) {
  DEVASSERT(IsAnimated());

  if (IsAnimated()) {
    PlayParams.m_SuppressAnimEvents = false;
    m_AnimationState.PlayAnimation(m_Bones->GetAnimation(AnimationName),
                                   PlayParams);
  }
}
Example #7
0
bool ieImageDisplay::SwitchFrame(ieSearchDirection eDir)
{
	ieFrameParams &fp = FrameParams();

	ieImage *pimNew = nullptr;
	switch (eDir) {
	case ieSearchDirection::NextFile:
		pimNew = fp.pimNext;
		break;
	case ieSearchDirection::PrevFile:
		pimNew = fp.pimPrev;
		break;
	case ieSearchDirection::FirstFile:
		SelectFirstFrame();
		return true;
	}

	if (!pimNew) {
		if (IsAnimated() && fp.bLooped && (eDir == ieSearchDirection::NextFile)) {
			SelectFirstFrame();
			return true;
		}
		return false;
	}

	if (IsAnimated()) {
		if (fp.eRestoreTo == ieFrameParams::eRestoreBackground) {
			ie_FillRect(pimComp, fp.xyOffs, pimOrig->WH(), ieBGRA2fBGRA(fp.clrBackground));
		} else if (fp.eRestoreTo == ieFrameParams::eRestorePrevious) {
			if (fp.pimRest) {
				ie_CopyRect(pimComp, fp.xyOffs, fp.pimRest, { 0, 0 }, pimOrig->WH());
			}
		}
		ieFrameParams &fpNew = pimNew->FrameParams();
		if ((fpNew.eRestoreTo == ieFrameParams::eRestorePrevious) && !fpNew.pimRest) {
			iePImage pimRestore = fpNew.pimRest = ieImage::Create(pimComp->PixelFormat(), pimNew->WH(), false, false);
			if (pimRestore) {
				ie_CopyRect(pimRestore, { 0, 0 }, pimComp, fpNew.xyOffs, pimNew->WH());
			}
		}
		InvalidateAdju();
	} else {
		InvalidateComp();
	}

	pimOrig = pimNew;
	PrepareComp(true);

	return true;
}
Example #8
0
ImageType::ImageType(const unsigned id, const CMString& file, IStream* pStream)
	: ImageBase(id)
{
	m_bmp = NULL;
	m_pPropertyItem = NULL;
	m_nCurrentFrame = 0;
	m_nFrameCount = 0;

	if (!InitGdiPlus()) return;

	if (pStream)
		m_bmp = new Gdiplus::Bitmap(pStream);
	else
		m_bmp = new Gdiplus::Bitmap(T2W_SM(file.c_str()));

	if (m_bmp->GetLastStatus() != Gdiplus::Ok) {
		delete m_bmp;
		m_bmp = NULL;
		return;
	}

	GUID pageGuid = Gdiplus::FrameDimensionTime;
	m_nFrameCount = m_bmp->GetFrameCount(&pageGuid);

	if (IsAnimated()) {
		int nSize = m_bmp->GetPropertyItemSize(PropertyTagFrameDelay);
		m_pPropertyItem = (Gdiplus::PropertyItem*) new char[nSize];
		m_bmp->GetPropertyItem(PropertyTagFrameDelay, nSize, m_pPropertyItem);
	}
}
Example #9
0
void ImageType::SelectFrame(int frame)
{
	if ((unsigned)frame >= (unsigned)m_nFrameCount) frame = 0;
	if (IsAnimated() && frame != m_nCurrentFrame) {
		m_nCurrentFrame = frame;
		GUID pageGuid = Gdiplus::FrameDimensionTime;
		m_bmp->SelectActiveFrame(&pageGuid, frame);
	}
}
SceneNodeAnimation * ColladaSceneNode::ExportNodeAnimation(FCDSceneNode * originalNode, float32 startTime, float32 endTime, float32 fps)
{
	if (!IsAnimated(originalNode))return 0;
		
	
	int frameCount = (endTime - startTime) * fps;
	float32 t0 = startTime;
	float32 tInc = (endTime - startTime) / (float)frameCount;
	
	
	std::vector<SceneNodeAnimationKey> keys;
	
	for (int k = 0; k < frameCount; ++k)
	{
		SceneNodeAnimationKey key = ExportAnimationKey(originalNode, t0);
//		duplicate keys
//		if (keys.size() != 0)
//		{
//			SceneNodeAnimationKey & keyPrev = keys[keys.size() - 1];
//			if ((keyPrev.translation == key.translation)
//				&& (keyPrev.rotation == key.rotation))
//			{
//				keyPrev.time = t0;
//			}else
//			{
//				keys.push_back(key);
//			}
//		}else
		{
			keys.push_back(key);
		}
		t0 += tInc;
	}
	
	
	SceneNodeAnimation * anim = new SceneNodeAnimation(keys.size());
	anim->SetDuration(endTime);
	for (int k = 0; k < (int)keys.size(); ++k)
	{
		anim->SetKey(k, keys[k]);
	}
	
	printf("= keys export: frameCount: %d keyCount:%ld compression: %f\n", frameCount, keys.size(), 100.0f * (float32)keys.size() / (float32)frameCount);
		 
	ExportAnimationKey(originalNode, 0);
	return anim;
}
Example #11
0
void Cube3D::Render()
{
	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glLoadIdentity ();
	glTranslatef(0.0, 0.0, -20.0);

	glRotatef(angles[1], 1.0, 0.0, 0.0);
	glRotatef(angles[2], 0.0, 1.0, 0.0);

	for (int z = 0; z <= 2; ++z)
	  for (int y = 0; y <= 2; ++y)
	    for (int x = 0; x <= 2; ++x)
	    {
		Cubelet* c = GetCubelet(x, y, z);
		if(!IsAnimated(c)) c->Render();
	    }

	if(TransCount)
	{
		GLfloat angle[3] = {(TransAxis == X) ? 1.0 : 0.0,
				    (TransAxis == Y) ? 1.0 : 0.0,
				    (TransAxis == Z) ? 1.0 : 0.0};

		GLfloat step[2] = {(    TransRot  < 0) ?  1.0 : -1.0,
				   (abs(TransRot) < 1) ? -1.0 :  1.0};

		step[1] = -step[0] + step[0]*step[1];
		
		glPushMatrix();
		
		glRotatef(angles[0]*step[0], angle[0], angle[1], angle[2]);
		for(int i = 0; i < 9; ++i)
			Transform[i]->Render();
		
		if(TransCount == 2)
		{
			glRotatef(angles[0]*step[1], angle[0], angle[1], angle[2]);
			for(int i = 9; i < 18; ++i)
				Transform[i]->Render();
		}

		glPopMatrix();
	}
	
}
Example #12
0
void ieImageDisplay::PrepareComp(bool bForceUpdate)
{
	if (pimComp && !bForceUpdate) return;
	if (pimAdju) InvalidateAdju();

	if (IsAnimated()) {

		ieFrameParams &fp = pimOrig->FrameParams();
		bool bFirstFrame = (fp.pimPrev == nullptr) || !pimComp;
		if (bFirstFrame) {

			// Create comp
			iePImage pim = ieImage::Create(iePixelFormat::BGRA, { max(fp.whCanvas.nX, pimOrig->X()), max(fp.whCanvas.nY, pimOrig->Y()) }, true, false);
			if (pim) {
				pim->SetAlphaType(pimOrig->AlphaType());

				if (pimComp && (pimComp != pimOrig)) pimComp->Release();
				pimComp = pim;

				// Fill with background
				ie_FillRect(pimComp, { 0, 0 }, pimComp->WH(), ieBGRA2fBGRA(fp.clrBackground));
			}
		}
		
		// Blend in image
		if (pimComp) {
			if (fp.bAlphaBlend) {
				ie_AlphaBlendPreMult(pimComp, fp.xyOffs, pimOrig);
			}
			else {
				ie_CopyRect(pimComp, fp.xyOffs, pimOrig);
			}
		}

		if (bForceUpdate) PrepareDisp();

	} else {

		if (pimComp != pimOrig) {
			if (pimComp) pimComp->Release();
			pimComp = pimOrig;
		}
	}
}
Example #13
0
void Mesh::UpdateBones() {
  DEVASSERT(IsAnimated());

  // Deferred creation of bone matrices
  if (!m_BoneMatrices) {
    ASSERT(m_Bones->GetNumBones() <= MAX_BONE_MATRICES);
    m_BoneMatrices = new Matrix[m_Bones->GetNumBones()];
    m_DirtyBoneMatrices = true;
  }

  if (m_DirtyBoneMatrices) {
    m_DirtyBoneMatrices = false;

    m_AnimationState.UpdateBones(m_Bones, m_BoneMatrices);

    for (uint BoneModifierIndex = 0; BoneModifierIndex < m_BoneModifiers.Size();
         ++BoneModifierIndex) {
      m_BoneModifiers[BoneModifierIndex]->Modify(m_Bones, m_BoneMatrices);
    }
  }
}
Example #14
0
void ieImageDisplay::SelectFirstFrame()
{
	ieImage *pim = pimOrig, *pimPrev;
	while ((pimPrev = pim->FrameParams().pimPrev) != nullptr) {
		pim = pimPrev;
	}

	if (pim != pimOrig) {
		
		if (IsAnimated()) {
			//if (pimOrig->FrameParams().bRestore2Bkg) ie_FillRect(pimComp, pimOrig->FrameParams().xyOffs, pimOrig->WH(), ieBGRA2fBGRA(pimOrig->FrameParams().clrBackground));
			ie_FillRect(pimComp, { 0, 0 }, pimComp->WH(), ieBGRA2fBGRA(pimOrig->FrameParams().clrBackground));
			InvalidateDisp();
		} else {
			InvalidateComp();
		}

		pimOrig = pim;
		PrepareComp(true);
	}
}
Example #15
0
void Mesh::Tick(float DeltaTime) {
  if (IsAnimated()) {
    m_DirtyBoneMatrices = true;
    m_AnimationState.Tick(DeltaTime);
  }
}
Example #16
0
void Mesh::GetAnimationVelocity(Vector& OutVelocity,
                                Angles& OutRotationalVelocity) {
  DEBUGASSERT(IsAnimated());
  return m_AnimationState.GetAnimationVelocity(OutVelocity,
                                               OutRotationalVelocity);
}
// Updates the player object.
void Player::Update(float timeDelta, Level& level)
{
	// Calculate movement speed based on the timeDelta since the last update.
	sf::Vector2f movementSpeed(0.f, 0.f);
	sf::Vector2f previousPosition = m_position;

	// Calculate where the current movement will put us.
	ANIMATION_STATE animState = static_cast<ANIMATION_STATE>(m_currentTextureIndex);

	if (Input::IsKeyPressed(Input::KEY::KEY_LEFT))
	{
		// Set movement speed.
		movementSpeed.x = -m_speed * timeDelta;

		// Chose animation state.
		animState = ANIMATION_STATE::WALK_LEFT;
	}
	else if (Input::IsKeyPressed(Input::KEY::KEY_RIGHT))
	{
		// Set movement speed.
		movementSpeed.x = m_speed * timeDelta;

		// Chose animation state.
		animState = ANIMATION_STATE::WALK_RIGHT;
	}

	if (Input::IsKeyPressed(Input::KEY::KEY_UP))
	{
		// Set movement speed.
		movementSpeed.y = -m_speed * timeDelta;

		// Chose animation state.
		animState = ANIMATION_STATE::WALK_UP;
	}
	else if (Input::IsKeyPressed(Input::KEY::KEY_DOWN))
	{
		// Set movement speed.
		movementSpeed.y = m_speed * timeDelta;

		// Chose animation state.
		animState = ANIMATION_STATE::WALK_DOWN;
	}

	// Calculate horizontal movement.
	if (CausesCollision(sf::Vector2f(movementSpeed.x, 0.0f), level))
	{
		m_position.x = previousPosition.x;
	}
	else
	{
		m_position.x += movementSpeed.x;
	}

	// Calculate horizontal movement.
	if (CausesCollision(sf::Vector2f(0.0f, movementSpeed.y), level))
	{
		m_position.y = previousPosition.y;
	}
	else
	{
		m_position.y += movementSpeed.y;
	}

	// update the sprite position
	m_sprite.setPosition(m_position);

	// Set the sprite.
	if (m_currentTextureIndex != static_cast<int>(animState))
	{
		m_currentTextureIndex = static_cast<int>(animState);
		m_sprite.setTexture(TextureManager::GetTexture(m_textureIDs[m_currentTextureIndex]));
	}

	// set animation speed
	if ((movementSpeed.x == 0) && (movementSpeed.y == 0))
	{
		// the character is still
		if (IsAnimated())
		{
			// Update sprite to idle version.
			// In our enum we have 4 walking sprites followed by 4 idle sprites.
			// Given this, we can simply add 4 to a walking sprite to get its idle counterpart.
			m_currentTextureIndex += 4;
			m_sprite.setTexture(TextureManager::GetTexture(m_textureIDs[m_currentTextureIndex]));

			// Stop movement animations.
			SetAnimated(false);
		}
	}
	else
	{
		// the character is moving
		if (!IsAnimated())
		{
			// Update sprite to walking version.
			m_currentTextureIndex -= 4;
			m_sprite.setTexture(TextureManager::GetTexture(m_textureIDs[m_currentTextureIndex]));

			// Start movement animations.
			SetAnimated(true);
		}
	}

	// Calculate aim based on mouse.
	sf::Vector2i mousePos = sf::Mouse::getPosition();
	m_aimSprite.setPosition((float)mousePos.x, (float)mousePos.y);

	// Check if shooting.
	if ((m_attackDelta += timeDelta) > 0.25f)
	{
		if (Input::IsKeyPressed(Input::KEY::KEY_ATTACK))
		{
			// Mark player as attacking.
			m_isAttacking = true;
		}
	}

	// Determine if the player can take damage.
	if (!m_canTakeDamage)
	{
		if ((m_damageDelta += timeDelta) > 1.f)
		{
			m_canTakeDamage = true;
			m_damageDelta = 0.f;
		}
	}

	// Increase player mana.
	if ((m_manaDelta += timeDelta) > 0.20)
	{
		if (m_mana < m_maxMana)
		{
			m_mana += 1;
		}

		m_manaDelta = 0.f;
	}
}
Example #18
0
   bool ReadGifData(){

      enum{                   //gif-extension flags
         GE_TRANSPARENT = 1,
         GE_USER_INPUT = 2,
                              //2-4: disposal method
      };
      struct{                 //graphic control extension
         byte blocksize;      //block size: 4 bytes
         byte flags;
         word delay;          //delay time (1/100 seconds)
         byte transparent;    //transparent color index
      } gif_extension;
      bool gfx_extension_found = false;

      //frame_disposal = DISPOSAL_UNDEFINED;

                              //now we have 3 possibilities:
                              // a) get and extension block (blocks with additional information)
                              // b) get an image separator (introductor to an image)
                              // c) get the trailer char (end of gif file)
      while(!fl->IsEof()){
         byte code;
         if(!fl->ReadByte(code))
            return false;
         switch(code){
         case 0x21:
            {
                              //*a* extension block - only in Gif89a or newer
               byte subcode;
               fl->ReadByte(subcode);
               switch(subcode){
               case 0xf9:
                  {
                                 //graphic control extension
                     fl->Read(&gif_extension, 5);
                     assert(gif_extension.blocksize==4);
                     gfx_extension_found = true;
                     if(transparent){
                              //restore previous transparent color to non-transparent
                        assert(transparent_index!=0x100);
                        S_rgb *pal = use_local_palette ? local_palette : global_palette;
                        pal[transparent_index].a = 0xff;
                     }
                     transparent = (gif_extension.flags&GE_TRANSPARENT);
                     transparent_index = transparent ? gif_extension.transparent : 0x100;

                              //process disposal
                     if(curr_frame==-1)
                        MemSet(pic_buffer, background, size_x*size_y);
                     else
                     if(frame_disposal==DISPOSAL_RESTORE_BGND){
                        byte *d = pic_buffer + decoded_rect.y*size_x + decoded_rect.x;
                        for(int y=0; y<decoded_rect.sy; y++){
                           MemSet(d, background, decoded_rect.sx);
                           d += size_x;
                        }
                     }

                     frame_disposal = (E_DISPOSAL)(gif_extension.flags>>2);

#ifdef DEBUG_FIXED_ANIM_TIME
                     frame_persist_time = gif_extension.delay ? DEBUG_FIXED_ANIM_TIME : 0;
#else
                     frame_persist_time = gif_extension.delay;
                     if(!frame_persist_time)
                        frame_persist_time = 10;
                     frame_persist_time *= 10;
#endif

                                 //block terminator (always 0)
                     byte term;
                     fl->ReadByte(term);
                  }
                  break;

               case 0xfe:        //comment extension
               case 0x01:        //plaintext extension
               case 0xff:        //application extension
               default:          //unknown extension
                                 //read (and ignore) data sub-blocks
                  while(true){
                     byte block_length;
                     if(!fl->ReadByte(block_length))
                        return false;
                     if(!block_length)
                        break;
#ifdef _DEBUG_
                     byte *bp = new byte[block_length];
                     fl->Read(bp, block_length);
                     delete[] bp;
#else
                     if(!fl->Seek(fl->Tell() + block_length))
                        return false;
#endif
                  }
                  break;
               }
            }
            break;

         case 0x2c:
            {
                              //*b* image (0x2c image separator)
               enum{
                              //0-2: size of local color table
                              //3-4: (reserved)
                  FLG_SORT = 0x20,
                  FLG_INTERLACE = 0x40,
                  FLG_LOCAL_COLOR = 0x80,
               };

                              //read image descriptor
               struct{
                  word xpos;
                  word ypos;
                  word width;
                  word height;
                  byte flags;
               } gif_id;
               fl->Read(&gif_id, 9);
               bool local_colormap = (gif_id.flags&FLG_LOCAL_COLOR);

#if 0
               /*
               if(gfx_extension_found){
                  nextimage->transparent = (gifgce.flags&0x01) ? gifgce.transparent : -1;
                  nextimage->transparency = (gifgce.flags&0x1c)>1 ? 1 : 0;
                  nextimage->delay = gifgce.delay*10;
               }
               */
#endif
               decoded_rect = S_rect(gif_id.xpos, gif_id.ypos, gif_id.width, gif_id.height);

               if(local_colormap){
                              //read color map (if descriptor says so)
                  int num_colors = 2 << (gif_id.flags&7);
                  ReadPalette(local_palette, num_colors);
                  use_local_palette = true;
               }else{
                              //otherwise use global
                  use_local_palette = false;
               }
               if(transparent// && frame_disposal==DISPOSAL_RESTORE_BGND
                  ){
                  S_rgb *pal = use_local_palette ? local_palette : global_palette;
                  pal[transparent_index].a = 0;
               }

               interlaced = (gif_id.flags&FLG_INTERLACE);
                              //1st byte of img block (codesize)
               fl->ReadByte(init_code_size);
               assert(init_code_size>0 && init_code_size<=8);
               //if(init_code_size>8)
                  //init_code_size = 8;

               BeginLZWDecode();

               if(interlaced){
                  decoded_img.Resize(decoded_rect.sx*decoded_rect.sy, background);
                  
                  DecodeInterlaced();
               }
               curr_line = 0;
               ++curr_frame;
               gfx_extension_found = false;
               return true;
            }
            break;

         case 0x3b:
                              //*c* trailer: end of gif info
                              //standard end
            if(!IsAnimated())
               return true;
            fl->Seek(beg_anim_file_offset);
            curr_frame = -1;
            break;
         }
      }
      return true;
   }
Example #19
0
void ieImageDisplay::PrepareAdju(volatile bool *pbCancel)
{
	if (pimDisp) InvalidateDisp();

	if (!pimComp) {
		PrepareComp();
		if (!pimComp) return;
	}

	if (pimAdju) return;

	iePImage pimSrc = pimComp;

	ieOrientation eRotation = iap.GetRotation();
	float fSharpness = iap.GetSharpness();

	bool bDoStep1 = !bBlendOnDraw && !IsAnimated() && (pimSrc->AlphaType() != ieAlphaType::None);
	bool bDoStep2 = iap.AnyColorAdjustment();
	bool bDoStep3 = (eRotation != ieOrientation::Rotate0);
	bool bDoStep4 = iap.AnyTrim();
	bool bDoStep5 = fSharpness != 0.0f;

	bool bNewInStep1 = bDoStep1;
	bool bNewInStep2 = bDoStep2 && !bNewInStep1;
	bool bNewInStep3 = bDoStep3;
	bool bNewInStep4 = bDoStep4;
	bool bNewInStep5 = bDoStep5 && (pimSrc->CLUT()|| (!bNewInStep4 && !bNewInStep3 && !bNewInStep2 && !bNewInStep1));
	
	bool bWantDraw5 = bDispMustBeDraweable && ieCanBeDrawable(pimSrc->PixelFormat());	// If it's wBGRA/wL/fBGRA/fL we'll defer to PrepareDisp() to create a draweable copy. NB: If !pComp->Draw() and no step is done, then again it's up to PrepareDisp() to prepare something draweable...
	bool bWantDraw4 = bWantDraw5 && !bNewInStep5;
	bool bWantDraw3 = bWantDraw4 && !bNewInStep4;
	bool bWantDraw2 = bWantDraw3 && !bNewInStep3;
	bool bWantDraw1 = bWantDraw2 && !bNewInStep2;

	if (bDoStep1) {

		// Alpha blend with background
		//if (pimSrc == pimComp) { always true here

			bool bOldFixedPallete = gie_pClrOptions->bFixedCLUT;
			bool bOldSharedPallete = gie_pClrOptions->bSharedCLUT;
			gie_pClrOptions->bFixedCLUT = false;
			gie_pClrOptions->bSharedCLUT = false;

			pimSrc = pimSrc->CreateCopy(false, bWantDraw1, false);

			gie_pClrOptions->bFixedCLUT = bOldFixedPallete;
			gie_pClrOptions->bSharedCLUT = bOldSharedPallete;
		//}

		ie_AlphaBlendPreMultWithClr(pimSrc, ieBGRA2fBGRA(pimOrig->FrameParams().clrBackground));

		if (pbCancel && *pbCancel) return;
	}

	if (bDoStep2) {

		// Do color adjustment
		iePImage pimClrAdj = (pimSrc != pimComp) ? pimSrc : ieImage::Create(pimSrc->PixelFormat(), pimSrc->WH(), bWantDraw2, false);
		if (!pimClrAdj) {
			iap.Reset();
		} else {
			ie_AdjustClrs(pimClrAdj, pimSrc, iap);
			if ((pimSrc != pimClrAdj) && (pimSrc != pimComp)) pimSrc->Release();
			pimSrc = pimClrAdj;

			if (pbCancel && !*pbCancel) return;
		}
	}

	if (bDoStep3) {

		// Rotate
		ieWH wh{ pimSrc->WH() };
		int t;

		switch (ieRotationOf(eRotation)) {
		case ieOrientation::Rotate90:
		case ieOrientation::Rotate270:
			t = wh.nX;
			wh.nX = wh.nY;
			wh.nY = t;
			break;
		}

		iePImage pimRotated = ieImage::Create(pimSrc->PixelFormat(), wh, bWantDraw3, false);

		if (!pimRotated) {
			iap.SetRotation(ieOrientation::Rotate0);
		} else {
			ie_RotateImage(pimRotated, pimSrc, eRotation);
			if (pimSrc != pimComp) pimSrc->Release();
			pimSrc = pimRotated;
		}

		if (pbCancel && *pbCancel) return;
	}

	if (bDoStep4) {

		// Trim
		ieXY xy;
		ieWH wh;
		iap.GetTrim(xy, wh);

		iePImage pimTrimmed = ieImage::Create(pimSrc->PixelFormat(), wh, bWantDraw4, false);
		if (!pimTrimmed) {
			iap.SetTrim();
		} else if (ieFailed(ie_TrimImage(pimTrimmed, pimSrc, xy))) {
			pimTrimmed->Release();
			iap.SetTrim();
		} else {
			if (pimSrc != pimComp) pimSrc->Release();
			pimSrc = pimTrimmed;
		}

		if (pbCancel && *pbCancel) return;
	}

	if (bDoStep5) {

		// Adjust sharpness
		const float fRadius = 2.5f;
		const int iMinDelta = 7;
		
		iePImage pimSharp;
		if (pimSrc->CLUT()) {
			pimSharp = pimSrc->CreateCopy(false, bWantDraw5, false, iePixelFormat::BGRA);
		} else if (pimSrc == pimComp) {
			pimSharp = pimSrc->CreateCopy(false, bWantDraw5, false);
		} else {
			pimSharp = pimSrc;
		}
		if (!pimSharp) {
			iap.SetSharpness(0.0f);
		} else if (ieFailed(ie_SharpenImage(pimSharp, pimSrc, fSharpness, fRadius, iMinDelta))) {
			if (pimSharp != pimSrc) pimSharp->Release();
			iap.SetSharpness(0.0f);
		} else if (pimSharp != pimSrc) {
			if (pimSrc != pimComp) pimSrc->Release();
			pimSrc = pimSharp;
		}

		if (pbCancel && *pbCancel) return;
	}

	if (pimAdju && (pimAdju != pimComp)) pimAdju->Release();
	pimAdju = pimSrc;
}