PDA

View Full Version : Creating textures



Manel Goucha
07-09-2011, 03:50 AM
Hi, I'm trying to create a texture from a file and from a simple gridmap, a 100 x 100 array map of rgb byte values

but the problem is that the image is loaded to opengl but it gets distorted and with bad effects,

I'm using this:

to Create then image in opengl from a pointer to the image


CreateTexture(Width, Height, Format: Integer; Data: Pointer): Integer;
var
Texture: GLuint;
begin
glGenTextures(1, @Texture);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glBindTexture(GL_TEXTURE_2D, Texture);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

if Format = GL_RGBA
then gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, pData)
else gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, Width, Height, GL_RGB, GL_UNSIGNED_BYTE, pData);

result := Texture;
end;

and this to get the Imagedata from a file wich contains the pixel information like this:

R: Byte;
G: Byte;
B: Byte;


function CreateDSTextureFromData(Data: TTextureData): TDSImage;
var
DataType, Size: Integer;
Image: Pointer;
begin
Result.Width := Length(Data.Data[0]);
Result.Height := Length(Data.Data);
DataType := Data.DataType;

Size := Result.Width * Result.Height * DataType;
GetMem(Image, Size);

case DataType of
3: Result.Texture := CreateTexture(Result.Width, Result.Height, GL_RGB, Image);
4: Result.Texture := CreateTexture(Result.Width, Result.Height, GL_RGBA, Image);
end;

FreeMem(Image);
end
But it seems to doesn't workd, is there any problem?

Thks for any help on this

Dan Bartlett
07-09-2011, 04:31 AM
What are you expecting it to do?

You are allocating some memory with
GetMem(Image, Size); which could contain anything, then passing this to CreateTexture without filling it with any useful data.

Manel Goucha
07-09-2011, 04:36 AM
Yes sorry, I forgot to sent the resto of the code:

the correct code is this:

and it still doesn't work


function CreateDSTextureFromData(Data: TTextureData): TDSImage;
var
DataType: Integer;
Image: Pointer;
Size: Integer;
begin
Result.Width := Length(Data.Data[0]);
Result.Height := Length(Data.Data);
DataType := Data.DataType;

Size := Result.Width * Result.Height * DataType;
GetMem(Image, Size);
Image := @Data.Data; <- is this right?

case DataType of
3: Result.Texture := CreateTexture(Result.Width, Result.Height, GL_RGB, Image);
4: Result.Texture := CreateTexture(Result.Width, Result.Height, GL_RGBA, Image);
end;

FreeMem(Image);
end;

and the structure of the Data:

TTextureData = record
DataType: Integer; <- pixel format
Data: array of array of TRGBA;
end;

and is all the rest right?

thks again

Dan Bartlett
07-09-2011, 07:33 AM
This is even worse now:

GetMem(Image, Size);
Image := @Data.Data; <- is this right?
*call CreateTexture*
FreeMem(Image);

You are allocating Size bytes, and storing the pointer to this value in "Image", then immediately overwriting this pointer with a pointer to the multidimensional dynamic array "Data.Data". Then later you call FreeMem + try to free Size bytes from where "Image" is pointing, which is from "Data.Data". This will most likely cause your program to die horribly.

As well as dangerous calls to GetMem/FreeMem, you don't seem to understand how Delphi's dynamic arrays work, a dynamic array is a pointer to the array data, with hidden fields at a negative offset to the start of the data, containing the length of the array + the reference count. Using a dynamic array of dynamic arrays: eg.

Data: array of array of TRGBA;
Will not provide you with a chunk of memory that is consecutive, but will create an array of pointers to the dynamic arrays that contain each row. Each row could be a different length too. Using @Data.Data will provide a pointer to the start of this array of pointers.

The best solution would probably be to define TTextureData as using a 1D dynamic array to store the image data, with an extra Width + Height field:

TTextureData = record
DataType: Integer; <- pixel format
Width, Height: Integer;
Data: array of TRGBA; //or array of byte
end;


function CreateDSTextureFromData(Data: TTextureData): TDSImage;
var
DataType: Integer;
Image: Pointer;
Size: Integer;
begin
Result.Width := Data.Width;
Result.Height := Data.Height;
DataType := Data.DataType;

Image := @Data.Data;

case DataType of
3: Result.Texture := CreateTexture(Result.Width, Result.Height, GL_RGB, Image);
4: Result.Texture := CreateTexture(Result.Width, Result.Height, GL_RGBA, Image);
end;
end;

If you don't want to move from a multidimensional dynamic array, then each time you want to interact with OpenGL, you will need to copy each row of your image data into a temporary buffer that does contain the data in one consecutive chunk of memory, which is probably why someone suggested the GetMem/FreeMem approach.

Manel Goucha
07-09-2011, 08:09 AM
Thanks, I didn't know how to work with these vars, and yes, I use a multidimensional array, but my problem is to set the poiter correctly, I'm still starting to work with them

but I've tried to convert to a simple array of TRGB using this:


for y := 0 to Image.Height-1 do
begin
Line := Image.ScanLine[y];
for x := 0 to Image.width-1 do
begin
i := y * Image.width + x;
Result.Data[i] := Line[x];
end;
end


and this:

Image := @Data.Data;


case DataType of
Result.Texture := CreateTexture(Result.Width, Result.Height, GL_RGB, Image);

but it still don't work, I'm getting mad with this, is there anything wrong? is there a way that I can send you the code?


thanks again for the time

Manel Goucha
07-10-2011, 07:03 AM
I just don't know how the texture data should be passed to opengl

It must e in one simple array of pixel data with the height and width information only?

Can it work with 2d arrays?

thks