[C++/DX9] Weird texture editing & render issue

Started by
0 comments, last by Programmer16 16 years, 2 months ago
I coded up some drawing routines for my Texture class, including a Layer class (it all wraps up creating an instance of IDirect3DSurface9, locking, setting/getting pixel data, and unlocking.) It all works fine...except if I try to use it during runtime. The weird part? It does work...kind of. If I save the texture to a file, the file looks perfect, however it doesn't render correctly. I've double checked all of my code and the texture is being rendered every frame. Here's the code for my wrappers

class Texture
{
public:
	static TextureManager TexturePool;
	typedef boost::shared_ptr<Texture> Pointer;

	class Layer
	{
		IDirect3DSurface9 *ComPtr;
		D3DLOCKED_RECT LockedRect;
		dft::Math::Rectangle LockedSection;
		DWORD *Bits;
		Texture *Owner;
		friend Texture;
	public:
		typedef boost::shared_ptr<Layer> Pointer;

		Layer();
		~Layer();
		bool Create(dft::Graphics::Texture *SourceTexture, int Layer = 0);

		bool Lock(dft::Math::Rectangle *LockSection, int Flags = D3DLOCK_READONLY);
		dft::Graphics::Color GetPixel(int X, int Y);
		dft::Graphics::Color GetPixel(const dft::Math::Point Location);
		dft::Graphics::Color *GetPixelChunk(dft::Math::Rectangle *SourceRectangle);
		void SetPixel(int X, int Y, dft::Graphics::Color PixelColor);
		void SetPixel(const dft::Math::Point Location, dft::Graphics::Color PixelColor);
		void DrawLine(int StartX, int StartY, int EndX, int EndY, dft::Graphics::Color PixelColor);
		void DrawLine(const dft::Math::Point &StartPoint, const dft::Math::Point &EndPoint, dft::Graphics::Color PixelColor);
		void DrawRectangle(int X, int Y, int Width, int Height, dft::Graphics::Color PixelColor);
		void DrawRectangle(const dft::Math::Rectangle &DestinationRectangle, dft::Graphics::Color PixelColor);
		void DrawRectangle(const dft::Math::Point &Location, const dft::Math::Dimensions &Size, dft::Graphics::Color PixelColor);
		void DrawChunk(const dft::Math::Point &Location, dft::Graphics::Color *Chunk, const dft::Math::Dimensions &ChunkSize);
		void CopyFromLayer(Layer::Pointer Source, const dft::Math::Rectangle &SourceRectangle, const dft::Math::Rectangle &Destination);
		void Unlock();
	};

	class Information
	{
	public:
		int Levels;
		unsigned long Usage;
		D3DFORMAT Format;
		D3DPOOL Pool;
		unsigned long Filter;
		unsigned long MipFilter;
	};

	IDirect3DTexture9 *ComPtr;
	std::string FilePath;
	Math::Dimensions Size;
	Math::Dimensions ImageSize;
	Device *GfxDevice;
	Information Info;

	Texture();
	~Texture();

	ReturnValueEx<HRESULT> LoadFromFile(Device &GfxDevice, const std::string &FilePath);
	ReturnValueEx<HRESULT> LoadFromFileEx(Device &GfxDevice, const std::string &FilePath, int Width, int Height, int Levels, unsigned long Usage, D3DFORMAT Format, D3DPOOL Pool, unsigned long Filter, unsigned long MipFilter);
	ReturnValueEx<HRESULT> CreateBlank(Device &GfxDevice, int Width, int Height, int Levels, unsigned long Usage, D3DFORMAT Format, D3DPOOL Pool, const std::string &Name);
	ReturnValueEx<HRESULT> Save(const std::string &OutputFilePath, D3DXIMAGE_FILEFORMAT ImageFileFormat);
	Layer::Pointer GetLayer(int Layer = 0);
	bool Reload();
	void Release();

	static Pointer GetTexture(Device &GfxDevice, const std::string &Path);
};

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Texture::Layer::Layer()
{
	Bits = 0;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Texture::Layer::~Layer()
{
	if(ComPtr)
	{
		ComPtr->Release();
		ComPtr = 0;
	}
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool Texture::Layer::Create(dft::Graphics::Texture *SourceTexture, int Layer)
{
	if(!SourceTexture)
		return false;
	if(FAILED(SourceTexture->ComPtr->GetSurfaceLevel(Layer, &ComPtr)))
		return false;
	Owner = SourceTexture;
	return true;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool Texture::Layer::Lock(dft::Math::Rectangle *LockSection, int Flags)
{
	if(FAILED(ComPtr->LockRect(&LockedRect, LockSection != 0 ? &LockSection->ToRECT() : 0, Flags)))
		return false;
	Bits =(DWORD*)(LockedRect.pBits);
	if(LockSection)
		LockedSection = *LockSection;
	else if(Owner)
		LockedSection = dft::Math::Rectangle(0, 0, Owner->Size);
	return true;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
dft::Graphics::Color Texture::Layer::GetPixel(int X, int Y)
{
	if(X > (LockedSection.Width() - LockedSection.Left) || Y > (LockedSection.Height() - LockedSection.Top) || X < 0 || Y < 0 || !Bits)
		return dft::Graphics::Color::FromArgb(0, 0, 0, 0);
	return Bits[((LockedRect.Pitch / sizeof(DWORD)) * Y) + X];
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
dft::Graphics::Color Texture::Layer::GetPixel(const dft::Math::Point Location)
{
	return GetPixel(Location.X, Location.Y);
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
dft::Graphics::Color *Texture::Layer::GetPixelChunk(dft::Math::Rectangle *SourceRectangle)
{
	if(!Bits)
		return 0;

	if(SourceRectangle)
	{
		if(SourceRectangle->Width() == 0 || SourceRectangle->Height() == 0)
			return 0;
	}
	else
		SourceRectangle = &LockedSection;

	dft::Graphics::Color *Output = new dft::Graphics::Color[SourceRectangle->Area()];
	for(int Y = SourceRectangle->Top; Y < SourceRectangle->Bottom; ++Y)
	{
		for(int X = SourceRectangle->Left; X < SourceRectangle->Right; ++X)
		{
			int Index = ((Y - SourceRectangle->Top) * SourceRectangle->Width()) + (X - SourceRectangle->Left);
			Output[((Y - SourceRectangle->Top) * SourceRectangle->Width()) + (X - SourceRectangle->Left)] = GetPixel(X, Y);
		}
	}
	return Output;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void Texture::Layer::SetPixel(int X, int Y, dft::Graphics::Color PixelColor)
{
	if(X > (LockedSection.Width() - LockedSection.Left) || Y > (LockedSection.Height() - LockedSection.Top) || X < 0 || Y < 0 || !Bits)
		return;
	Bits[((LockedRect.Pitch / sizeof(DWORD)) * Y) + X] = PixelColor;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void Texture::Layer::SetPixel(const dft::Math::Point Location, dft::Graphics::Color PixelColor)
{
	SetPixel(Location.X, Location.Y, PixelColor);
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void Texture::Layer::DrawLine(int StartX, int StartY, int EndX, int EndY, dft::Graphics::Color PixelColor)
{
	bool Steep = abs(EndY - StartY) > abs(EndX - StartX);
	if(Steep)
	{
		StartX ^= StartY;
		StartY ^= StartX;
		StartX ^= StartY;

		EndX ^= EndY;
		EndY ^= EndX;
		EndX ^= EndY;
	}

	if(StartX > EndX)
	{
		StartX ^= EndX;
		EndX ^= StartX;
		StartX ^= EndX;

		StartY ^= EndY;
		EndY ^= StartY;
		StartY ^= EndY;
	}

	int DeltaX = EndX - StartX;
	int DeltaY = abs(EndY - StartY);
	int Error = -(DeltaX + 1) / 2;
	int YStep = 0;
	int Y = StartY;
	if(StartY < EndY)
		YStep = 1;
	else
		YStep = -1;

	for(int X = StartX; X < EndX; ++X)
	{
		if(Steep)
			SetPixel(Y, X, PixelColor);
		else
			SetPixel(X, Y, PixelColor);
		Error = Error + DeltaY;
		if(Error >= 0)
		{
			Y = Y + YStep;
			Error = Error - DeltaX;
		}
	}
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void Texture::Layer::DrawLine(const dft::Math::Point &StartPoint, const dft::Math::Point &EndPoint, dft::Graphics::Color PixelColor)
{
	DrawLine(StartPoint.X, StartPoint.Y, EndPoint.X, EndPoint.Y, PixelColor);
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void Texture::Layer::DrawRectangle(int X, int Y, int Width, int Height, dft::Graphics::Color PixelColor)
{
	for(int CurrentY = Y; CurrentY < (Y + Height); ++CurrentY)
	{
		DrawLine(X, CurrentY, X + Width, CurrentY, PixelColor);
	}
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void Texture::Layer::DrawRectangle(const dft::Math::Rectangle &DestinationRectangle, dft::Graphics::Color PixelColor)
{
	DrawRectangle(DestinationRectangle.Left, DestinationRectangle.Top, DestinationRectangle.Width(), DestinationRectangle.Height(), PixelColor);
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void Texture::Layer::DrawRectangle(const dft::Math::Point &Location, const dft::Math::Dimensions &Size, dft::Graphics::Color PixelColor)
{
	DrawRectangle(Location.X, Location.Y, Size.Width, Size.Height, PixelColor);
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void Texture::Layer::DrawChunk(const dft::Math::Point &Location, dft::Graphics::Color *Chunk, const dft::Math::Dimensions &ChunkSize)
{
	if(!Chunk)
		return;

	for(int Y = 0; Y < ChunkSize.Height; ++Y)
	{
		for(int X = 0; X < ChunkSize.Width; ++X)
		{
			SetPixel(Location.X + X, Location.Y + Y, Chunk[(Y * ChunkSize.Width) + X]);
		}
	}
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void Texture::Layer::CopyFromLayer(Layer::Pointer Source, const dft::Math::Rectangle &SourceRectangle, const dft::Math::Rectangle &Destination)
{
	dft::Graphics::Color *Chunk = Source->GetPixelChunk(&dft::Math::Rectangle(SourceRectangle));
	if(!Chunk)
		return;

	dft::Math::Dimensions ChunkSize = SourceRectangle.Size();
	int ColumnCount = (int)(ceil(((float)Destination.Width() / (float)ChunkSize.Width)));
	int RowCount = (int)(ceil(((float)Destination.Height() / (float)ChunkSize.Height)));
	for(int Row = 0; Row < RowCount; ++Row)
	{
		for(int Column = 0; Column < ColumnCount; ++Column)
		{
			DrawChunk(dft::Math::Point((ChunkSize.Width * Column) + Destination.Left, (ChunkSize.Height * Row) + Destination.Top), Chunk, ChunkSize);
		}
	}
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void Texture::Layer::Unlock()
{
	ComPtr->UnlockRect();
	Bits = 0;
	ZeroMemory(&LockedRect, sizeof(D3DLOCKED_RECT));
	LockedSection = LockedSection.Zero;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Texture::Texture()
{
	ComPtr = 0;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Texture::~Texture()
{
	Release();
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
ReturnValueEx<HRESULT> Texture::LoadFromFile(Device &GfxDevice, const std::string &FilePath)
{
	return LoadFromFileEx(GfxDevice, FilePath, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_FILTER_NONE);
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
ReturnValueEx<HRESULT> Texture::LoadFromFileEx(Device &GfxDevice, const std::string &FilePath, int Width, int Height, int Levels, unsigned long Usage, D3DFORMAT Format, D3DPOOL Pool, unsigned long Filter, unsigned long MipFilter)
{
	this->GfxDevice = &GfxDevice;
	std::string AbsoluteFilePath = FileSystem::GetAbsolutePath(FilePath);
	HRESULT Result = S_OK;
	D3DXIMAGE_INFO ImageInfo;
	if(FAILED(Result = D3DXCreateTextureFromFileEx(GfxDevice.ComPtr, AbsoluteFilePath.c_str(), Width, Height, Levels, Usage, Format, Pool, Filter, MipFilter, 0, &ImageInfo, 0, &ComPtr)))
		return ReturnValueEx<HRESULT>(false, Result, String::Format("Failed to load texture \"%s\". - %s", AbsoluteFilePath.c_str(), DXGetErrorDescription9(Result)));

	D3DSURFACE_DESC Desc;
	ComPtr->GetLevelDesc(0, &Desc);
	Size = Math::Dimensions(Desc.Width, Desc.Height);
	this->ImageSize = dft::Math::Dimensions(ImageInfo.Width, ImageInfo.Height);
	this->FilePath = AbsoluteFilePath;
	Info.Levels = Levels;
	Info.Usage = Usage;
	Info.Format = Format;
	Info.Pool = Pool;
	Info.Filter = Filter;
	Info.MipFilter = MipFilter;
	return ReturnValueEx<HRESULT>(true, Result, String::Format("Loaded the texture \"%s\".", FilePath.c_str()));
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
ReturnValueEx<HRESULT> Texture::CreateBlank(Device &GfxDevice, int Width, int Height, int Levels, unsigned long Usage, D3DFORMAT Format, D3DPOOL Pool, const std::string &Name)
{
	HRESULT Result = S_OK;
	if(FAILED((Result = GfxDevice.ComPtr->CreateTexture(Width, Height, Levels, Usage, Format, Pool, &ComPtr, 0))))
		return ReturnValueEx<HRESULT>(false, Result, String::Format("Failed to create a blank texture with the name \"%s\". - %s", Name.c_str(), DXGetErrorDescription9(Result)));

	D3DSURFACE_DESC Desc;
	ComPtr->GetLevelDesc(0, &Desc);
	Size = Math::Dimensions(Desc.Width, Desc.Height);
	this->FilePath = Name;
	return ReturnValueEx<HRESULT>(true, Result, String::Format("Created the blank texture \"%s\".", FilePath.c_str()));
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
ReturnValueEx<HRESULT> Texture::Save(const std::string &OutputFilePath, D3DXIMAGE_FILEFORMAT ImageFileFormat)
{
	HRESULT Result = S_OK;
	if(FAILED(Result = D3DXSaveTextureToFile(dft::FileSystem::GetAbsolutePath(OutputFilePath).c_str(), ImageFileFormat, ComPtr, 0)))
		return ReturnValueEx<HRESULT>(false, Result, String::Format("Failed to save the texture \"%s\" to the file \"%s\". - %s", FilePath.c_str(), OutputFilePath.c_str(), DXGetErrorDescription9(Result)));
	return ReturnValueEx<HRESULT>(true, Result, String::Format("Successfully saved the texture \"%s\" to the file \"%s.\"", FilePath.c_str(), OutputFilePath.c_str()));
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Texture::Layer::Pointer Texture::GetLayer(int LayerIndex)
{
	Layer::Pointer NewLayer(new Layer);
	if(NewLayer->Create(this, LayerIndex))
		return NewLayer;
	return Layer::Pointer();
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool Texture::Reload()
{
	if(!GfxDevice)
		return false;
	Information Info = this->Info;
	std::string FilePath = this->FilePath;
	Release();
	return LoadFromFileEx(*GfxDevice, FilePath, Size.Width, Size.Height, Info.Levels, Info.Usage, Info.Format, Info.Pool, Info.Filter, Info.MipFilter).Succeeded;
	return true;
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void Texture::Release()
{
	if(ComPtr)
	{
		ComPtr->Release();
		ComPtr = 0;
		FilePath = "";
		Size = Math::Dimensions(0, 0);
		ZeroMemory(&Info, sizeof(Information));
	}
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Texture::Pointer Texture::GetTexture(Device &GfxDevice, const std::string &Path)
{
	return TexturePool.GetTexture(GfxDevice, Path);
}



And here's my project's code that uses it:

// Creating the texture -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// this works fine
ScratchTexture->CreateBlank(GfxDevice, Background->Size.Width, Background->Size.Height, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, Name + "Scratch");
dft::Graphics::Texture::Layer::Pointer Layer = ScratchTexture->GetLayer(0);
Layer->Lock(0);
for(std::vector<ScratchArea>::iterator Itor = ScratchAreas.begin(); Itor != ScratchAreas.end(); ++Itor)
Layer->DrawRectangle(Itor->Location, Itor->Size, dft::Graphics::Color(255, 128, 128, 128));
Layer->Unlock();

// Modifying Function -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
dft::Math::Point Temp = Event.Position;
dft::Graphics::Texture::Layer::Pointer Layer = ScratchTexture->GetLayer(0);
Layer->Lock(0);
Layer->DrawLine(Temp.X - 4, Temp.Y + 4, Temp.X + 4, Temp.Y - 4, dft::Graphics::Color(0, 0, 0, 0));
Layer->DrawLine(Temp.X - 4, Temp.Y + 3, Temp.X + 3, Temp.Y - 4, dft::Graphics::Color(0, 0, 0, 0));
Layer->DrawLine(Temp.X - 3, Temp.Y + 4, Temp.X + 4, Temp.Y - 3, dft::Graphics::Color(0, 0, 0, 0));
Layer->Unlock();
// temp line ##TEMP##
ScratchTexture->Save("Output.png", D3DXIFF_PNG);



If you need any other information, just say so and I'll post it.
Advertisement
Ok, thanks to EDI we've got the problem fixed. The problem was that I was locking the texture using D3DLOCK_READONLY (forgot that I had the Lock method default to read only.) The weird part being that it worked at all and not giving me some form of access violation or error.

This topic is closed to new replies.

Advertisement