///////////////////////////////////////////////////////////// /// Met à jour les pixels de la texture /// /// \param Rect : Rectangle à mettre à jour dans la texture /// //////////////////////////////////////////////////////////// void DX9Texture::Update(const CRectangle& Rect) { CA_ASSERT(CRectangle(0, 0, m_Size.x, m_Size.y).Intersects(Rect) == INT_IN, "DX9Texture::Update() : rectangle out of bounds"); // Si le format des pixels à copier est le même que celui de la texture on fait une simple copie, // sinon on effectue une conversion if (m_Format == m_Data.GetFormat()) { // Verrouillage de la texture D3DLOCKED_RECT LockedRect; RECT Lock = {Rect.Left(), Rect.Top(), Rect.Right(), Rect.Bottom()}; DXCheck(m_Texture->LockRect(0, &LockedRect, &Lock, 0)); // Copie des pixels UpdateSurface(LockedRect, Rect); // Déverrouillage de la texture m_Texture->UnlockRect(0); } else { // Récupération du device SmartPtr<IDirect3DDevice9, CResourceCOM> Device; m_Texture->GetDevice(&GetPtr(Device)); // Création d'une texture en mémoire système pour y copier les pixels SmartPtr<IDirect3DSurface9, CResourceCOM> Src; if (FAILED(Device->CreateOffscreenPlainSurface(Rect.Width(), Rect.Height(), DX9Enum::Get(m_Data.GetFormat()), D3DPOOL_SYSTEMMEM, &GetPtr(Src), nullptr))) throw DX9Exception("CreateOffscreenPlainSurface", "DX9Texture::Update"); // Verrouillage de la texture temporaire D3DLOCKED_RECT LockedRect; Src->LockRect(&LockedRect, nullptr, 0); // Copie des pixels UpdateSurface(LockedRect, Rect); // Déverrouillage de la texture temporaire Src->UnlockRect(); // Récupération de la surface de niveau 0 de la texture SmartPtr<IDirect3DSurface9, CResourceCOM> Dest; m_Texture->GetSurfaceLevel(0, &GetPtr(Dest)); // Copie de la surface Src sur la surface Dest (c'est ici qu'est effectuée la conversion de format) RECT DestRect = {Rect.Left(), Rect.Top(), Rect.Right(), Rect.Bottom()}; if (FAILED(D3DXLoadSurfaceFromSurface(Dest, nullptr, &DestRect, Src, nullptr, nullptr, D3DX_DEFAULT, 0))) throw DX9Exception("D3DXLoadSurfaceFromSurface", "DX9Texture::Update"); } // Génération des niveaux de mipmapping si nécessaire if (m_HasMipmaps) { if (m_AutoMipmaps) m_Texture->GenerateMipSubLevels(); else D3DXFilterTexture(m_Texture, nullptr, D3DX_DEFAULT, D3DX_DEFAULT); } }
//////////////////////////////////////////////////////////// /// Copie les pixels de la texture sur une surface verrouillée /// /// \param LockedRect : Structure contenant les infos de verrouillage /// \param Rect : Rectangle source à copier /// //////////////////////////////////////////////////////////// void DX9Texture::UpdateSurface(const D3DLOCKED_RECT& LockedRect, const CRectangle& Rect) { // Récupération d'un pointeur sur les pixels source et destination unsigned char* DestPix = reinterpret_cast<unsigned char*>(LockedRect.pBits); const unsigned char* SrcPix = m_Data.GetData() + (Rect.Left() + Rect.Top() * m_Size.x) * GetBytesPerPixel(m_Data.GetFormat()); // Copie des pixels sur la surface unsigned int Bpp = GetBytesPerPixel(m_Data.GetFormat()); for (int i = 0; i < Rect.Height(); ++i) { std::copy(SrcPix, SrcPix + Rect.Width() * Bpp, DestPix); SrcPix += m_Size.x * Bpp; DestPix += LockedRect.Pitch; } }
void DX9SpriteBatch::Draw( ITextureBase *Texture2D, CRectangle &PositionInTexture, Vector2I &Origin, Vector2F &Position, float Rotation, Vector2F &Scale, CColor &Color, float ZOrder, eSpriteEffects SpriteEffect ) { CDX9Texture *tex = dynamic_cast<CDX9Texture *>(Texture2D); RECT src; src.left = PositionInTexture.Left(); src.right = PositionInTexture.Right(); src.top = PositionInTexture.Top(); src.bottom = PositionInTexture.Bottom(); D3DXVECTOR2 center(static_cast<float>(Origin.x), static_cast<float>(Origin.y)); D3DXVECTOR2 pos(Position.x - Origin.x, Position.y - Origin.y); D3DXMATRIX transform; DXCheck(D3DXMatrixTransformation2D(&transform, NULL, NULL, &D3DXVECTOR2(Scale.x, Scale.y), ¢er, Rotation, &pos)); if (SUCCEEDED(DXCheck(m_D3DSprite->SetTransform(&transform)))) { DXCheck(m_D3DSprite->Draw( tex->GetDxTexture(), &src, NULL, NULL, D3DCOLOR_RGBA(Color.GetRed(), Color.GetGreen(), Color.GetBlue(), Color.GetAlpha()) )); } }
///////////////////////////////////////////////////////////// /// Met à jour les pixels de la texture /// /// \param Rect : Rectangle à mettre à jour dans la texture /// //////////////////////////////////////////////////////////// void GLTexture::Update(const CRectangle& Rect) { CA_ASSERT(CRectangle(0, 0, m_Size.x, m_Size.y).Intersects(Rect) != INT_OUT, "GLTexture::Update() : rectangle out of bounds"); GLCheck(glBindTexture(GL_TEXTURE_2D, m_Texture)); GLEnum::TPixelFmt TexFmt = GLEnum::Get(m_Format); GLEnum::TPixelFmt ImgFmt = GLEnum::Get(m_Data.GetFormat()); if (FormatCompressed(m_Data.GetFormat())) { #if CA_PLATFORM_DESKTOP // Format de pixel compressé - on utilise une extension pour uploader les pixels unsigned long DataSize = Rect.Width() * Rect.Height() * GetBytesPerPixel(m_Data.GetFormat()); if (Rect.Width() == m_Size.x && Rect.Height() == m_Size.y) { // Le rectangle source couvre la totalité de l'image : on envoie directement les données GLRenderer::glCompressedTexSubImage2DARB(GL_TEXTURE_2D, 0, Rect.Left(), Rect.Top(), Rect.Width(), Rect.Height(), ImgFmt.Format, DataSize, m_Data.GetData()); } else { // Le rectangle source ne couvre qu'une partie de l'image : on envoie une sous-image de l'image en mémoire CImage SubData = m_Data.SubImage(Rect); GLRenderer::glCompressedTexSubImage2DARB(GL_TEXTURE_2D, 0, Rect.Left(), Rect.Top(), Rect.Width(), Rect.Height(), ImgFmt.Format, DataSize, SubData.GetData()); } #else throw NEW_AO CNotImplementedException("GLTexture::Update() : compressed format is not supported\n"); #endif // CA_PLATFORM_DESKTOP } else { GLint pixelStore = 0; switch (m_Data.GetFormat()) { case PixelFormat::L_8: ///< Luminosity 8 bits (1 byte) pixelStore = 1; break; case PixelFormat::AL_88: ///< Alpha and luminosity 16 bits (2 bytes) case PixelFormat::ARGB_1555: ///< RGB 16 bits 1555 (2 bytes) case PixelFormat::ARGB_4444: ///< RGB 16 bits 4444 (2 bytes) case PixelFormat::PVRTC2: ///< PVR texture compression. Each pixel is 2 bits. pixelStore = 2; break; case PixelFormat::RGB_888: ///< RGB 24 bits 888 (3 bytes) case PixelFormat::RGB_DXT1: ///< S3 DXT1 texture compression (RGB) // case PixelFormat::ARGB_8888: ///< ARGB 32 bits 8888 (4 bytes) case PixelFormat::PVRTC4: ///< PVR texture compression. Each pixel is 4 bits. case PixelFormat::RGBA_DXT1: ///< S3 DXT1 texture compression (RGBA) case PixelFormat::RGBA_DXT3: ///< S3 DXT3 texture compression (RGBA) case PixelFormat::RGBA_DXT5: ///< S3 DXT5 texture compression (RGBA) pixelStore = 4; break; } GLCheck(glPixelStorei(GL_PACK_ALIGNMENT, pixelStore)); if (!m_HasMipmaps || m_AutoMipmaps) { // Pas de mipmap ou génération hardware : on ne met à jour que le premier niveau if ((Rect.Width() == m_Size.x) && (Rect.Height() == m_Size.y)) { GLCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Rect.Width(), Rect.Height(), ImgFmt.Format, ImgFmt.Type, m_Data.GetData())); } else { CImage SubData = m_Data.SubImage(Rect); GLCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, Rect.Left(), Rect.Top(), Rect.Width(), Rect.Height(), ImgFmt.Format, ImgFmt.Type, SubData.GetData())); } } else { #if CA_PLATFORM_DESKTOP // Plusieurs niveaux de mipmapping et génération software : on met à jour tous les niveaux GLCheck(gluBuild2DMipmaps(GL_TEXTURE_2D, TexFmt.Internal, m_Size.x, m_Size.y, ImgFmt.Format, ImgFmt.Type, m_Data.GetData())); #else if ((Rect.Width() == m_Size.x) && (Rect.Height() == m_Size.y)) { GLCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Rect.Width(), Rect.Height(), ImgFmt.Format, ImgFmt.Type, m_Data.GetData())); } else { CImage SubData = m_Data.SubImage(Rect); GLCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, Rect.Left(), Rect.Top(), Rect.Width(), Rect.Height(), ImgFmt.Format, ImgFmt.Type, SubData.GetData())); } #endif // CA_PLATFORM_DESKTOP GLCheck(glGenerateMipmap(GL_TEXTURE_2D)); } } GLCheck(glBindTexture(GL_TEXTURE_2D, 0)); }