PDA

View Full Version : Loading DX Textures in an imagelist - which is the fastest?



Firlefanz
26-09-2005, 10:16 AM
Hello!

I am using the Omega headers and I am also a member there.
This is a problem of Omega, but everybody with knowledge in DirectX could help, so I post it here, maybe someone has a good Idea.

Omega has his own OmegaImagelists (like in DelphiX) which can store images. My problem is I have 19 mb of huge imagelists and it takes a long time to load them all, too long for me.

A solution would be having all images standalone on the harddisc, but I don't like that solution, 600+ images.

The problem is the Init method takes too long, and I am sure there can be an easier and faster solution.

How it works (in my understanding)

1) Loadfromfile loads the imagelist in a stream.
2) Init calls no 3 for every item
3) Item.Init saves the TPicture to a stream, then creates the texture needed from the new stream.

This one is called first to load the imagelist.


procedure TImageListCollection.LoadFromFile(const Filename: string);
var
Stream: TMemoryStream;
begin
Stream := TMemoryStream.Create;
Stream.LoadFromFile(Filename);
self.LoadFromStream(Stream);
Stream.Free;
end;


Then the Init is called.



procedure TOmegaImageList.Init;
var
i: integer;
begin
if FOmegaScreen = nil then
exit;
FRenderer.OmegaScreen := FOmegaScreen;
FRenderer.Init;
if FOmegaScreen.Device = nil then
exit;
for i := 0 to ImageList.Count - 1 do
ImageList.Items[i].Init;
end;


This one is calling the init of each ImagelistItem then.



procedure TImageListItem.Init;
var
FD3DSurfaceDesc: TD3DSurface_DESC;
Stream: TMemoryStream;
sRealFilePath: string;
begin
//Load picture from filepath if present
FFilePath := Trim(FFilePath);
if Length(FFilepath) > 0 then
begin
//Make relative paths absolute
if (Pos(':', FFilepath) = 0) and (Pos('\\', FFilepath) = 0) then
begin
ChDir(ExtractFilePath(Application.ExeName));
sRealFilepath := ExpandFileName(FFilepath);
end
else
sRealFilepath := FFilepath;
if FileExists(sRealFilePath) then
FPicture.LoadFromFile(sRealFilepath);
end;

if (FPicture.Graphic = nil) then
exit;

FDevice :=
TOmegaImageList(TImageListCollection(Collection).G etOwner).FOmegaScreen.Device;
FRenderer :=
TOmegaImageList(TImageListCollection(Collection).G etOwner).FRenderer;
{
If (FDevice = nil) then
begin
MessageBox(0, pChar('Error: no device assigned!'), 'Error', MB_ICONERROR);
Application.Terminate;
end;
If (FRenderer = nil) then
begin
MessageBox(0, pChar('Error: no renderer assigned!'), 'Error', MB_ICONERROR);
Application.Terminate;
end;
}
Stream := TMemoryStream.Create;
try
FPicture.Graphic.SaveToStream(Stream);
if FTileHeight <= 0 then
FTileHeight &#58;= FPicture.Graphic.Height;
if FTileWidth <= 0 then
FTileWidth &#58;= FPicture.Graphic.Width;
if not assigned&#40;self.FImage&#41; then
if Self.Transparent = true then
begin
if failed&#40;D3DXCreateTextureFromFileInMemoryEx&#40;
FDevice, Stream.Memory, Stream.Size,
0, 0, 0, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
D3DX_FILTER_NONE, D3DX_FILTER_NONE,
$FF000000 or Cardinal&#40;TColor&#40;OmegaColor&#40;self.TransparentColor, 0&#41;&#41;&#41;,
//Self.TransparentColor,
nil, nil, Self.FImage&#41;&#41; then
begin
MessageBox&#40;0, pChar&#40;'Error creating texture ' + Self.FName&#41;, 'Error',
MB_ICONERROR&#41;;
Stream.Free;
Application.Terminate;
end;
end
else
begin
if failed&#40;D3DXCreateTextureFromFileInMemoryEx&#40;
FDevice, Stream.Memory, Stream.Size,
0, 0, 0, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
D3DX_FILTER_NONE, D3DX_FILTER_NONE,
0, nil, nil, Self.FImage&#41;&#41; then
begin
MessageBox&#40;0, pChar&#40;'Error creating texture ' + Self.FName&#41;, 'Error',
MB_ICONERROR&#41;;
Stream.Free;
Application.Terminate;
end;
end;
Self.FImage.GetLevelDesc&#40;0, FD3DSurfaceDesc&#41;;
FRealWidth &#58;= FD3DSurfaceDesc.Width;
FRealHeight &#58;= FD3DSurfaceDesc.Height;
if FRealWidth < 2 then
FRealWidth &#58;= 2;
if FRealHeight < 2 then
FRealHeight &#58;= 2;
FHeight &#58;= FPicture.Height;
if FHeight = 0 then
FHeight &#58;= 1;
FWidth &#58;= FPicture.Width;
if FWidth = 0 then
FWidth &#58;= 1;
FNumOfRows &#58;= FHeight div FTileHeight;
FNumOfColumns &#58;= FWidth div FTileWidth;
finally
Stream.Free;
if Length&#40;FFilePath&#41; > 0 then
begin
FPicture.Free;
FPicture &#58;= TPicture.Create;
end;
end;
end;


So isn't it possible to make a new methode called 'LoadandInit' that loads all and makes the textures and works somehow faster, maybe without that TPicture and Savetostream etc?

How can I make it faster?

Thanks,
Firle[/code]

JSoftware
26-09-2005, 12:03 PM
using a momorystream wouldn't that force the file to be loaded into memory before reading from it? why not use filestream? it doesn't load the file into memory

Sly
26-09-2005, 10:53 PM
Just reading through that code, I see many areas for improvement.

Try changing TImageListCollection.LoadFromFile to use a TFileStream instead of a TMemoryStream. This will prevent the initial hit of allocating 19MB of memory and loading the entire file into it.

procedure TImageListCollection.LoadFromFile&#40;const Filename&#58; string&#41;;
var
Stream&#58; TFileStream;
begin
Stream &#58;= TFileStream.Create&#40;Filename, fmOpenRead or fmShareDenyNone;
try
LoadFromStream&#40;Stream&#41;;
finally
Stream.Free;
end;
end;

Not much can be done about TOmegaImageList.Init.

TImageListItem.Init could be improved in several places.

- FFilePath should have been trimmed before it was saved. Therefore there should be no need to always trim FFilePath every time you enter this method. Move the call to Trim to inside the if statement. But that's only a tiny problem.

- For every item in the list, you are creating a TMemoryStream and saving the image back to it so that D3DX can load that very same picture back in again. Very inefficient. That's where most of your time is being taken up.

If you don't want 600+ files on your harddisk, then this imagelist is not a very efficient way to avoid that. A better solution would be to use a system similar to a PAK file where multiple files are lumped together into one big file. Manually create each instance of TImageListItem and set the Filename property. Then you just create a TMemoryStream, load the file from the PAK file into the stream, pass that to D3DX, free the stream. Still not the most efficient method, but it should be more efficient than the current method.

I could possibly create a proof of concept for this, but I won't be able to do that for a couple of days.

Anonymous
27-09-2005, 05:31 AM
Hello Sly,

thanks a lot for your suggestions. The above code does not work, sorry. It says 'UngA¼ltiges Stream Format', translated 'Not working stream format' or something.

I know this is not very efficient, this is why I want to change it but myself I don't know how.

Thanks for your suggestions,

Firle

Sly
27-09-2005, 05:35 AM
I'll download the latest Omega tonight and see if I can get something working.

Firlefanz
27-09-2005, 06:15 AM
Ooops, that Guest was me.

The delphisanctuary site is still down. You can download the package from my site:

DX8 package two versions in the first comment of me, DX9 package (which I use) is a few more statements under it.

http://www.ericbehme.de/phpBB2/viewtopic.php?t=132

Thanks a lot for your help, I hope you find something, that would be great!

Firle

JSoftware
27-09-2005, 06:44 AM
or maybe even a hashtable for the images?

Firlefanz
27-09-2005, 06:51 AM
Hello,

the problem is I want to keep the Imagelist-Unit because it has a lot of other methods I still need.

So maybe a new LoadandInit Method would help, and then a method to save exisitng lists to the new format, but the Imagelist itself must work like it did before. Other units like OmegaSprite etc are depending on it, so we still need the format like it is now.

Never tried a hashtable myself ;)

Firle

Sly
27-09-2005, 07:23 AM
I don't think a hash-table would help in this case because it is not searching that is taking the time. It is the loading, saving, loading of each texture during the init that is taking all of the time.

Firlefanz
27-09-2005, 07:43 AM
I agree. The init method which is calling the Item.Init, that then saves Picture to stream and load texture from stream takes 90% of the time.

Firle

Sly
27-09-2005, 01:31 PM
I just tried the following code
procedure TImageListCollection.LoadFromFile&#40;const Filename&#58; string&#41;;
var
Stream&#58; TFileStream;
begin
Stream &#58;= TFileStream.Create&#40;Filename, fmOpenRead or fmShareDenyNone&#41;;
try
LoadFromStream&#40;Stream&#41;;
finally
Stream.Free;
end;
end;
and it loaded the images fine. I'm not sure why it would have given you a 'stream not working' or similar error.

Working on the Image.Init now.

Firlefanz
27-09-2005, 01:38 PM
Hmmm - I have to test it. The error could be because I am using an addition Cryption on my imagelist, if it works fine for you...

I can test that. If you have our Imegalisteditor, you can take a look there, it can also use that optional Cryption. I you need any source or maybe the Imagelisteditor please tell me, I have most things from Bobbys site at home.

Thanks! :D
Firle

Sly
27-09-2005, 02:43 PM
I wasn't using encryption. I'm not sure how that callback works. It takes a stream and returns a stream. Is it the same stream it returns or a new stream?

Anonymous
27-09-2005, 05:04 PM
Hi Sly,

this is the Decryption method:


function MyDecrypt&#40;s&#58; TStream&#41;&#58; TStream;
var arrbyte&#58; array of byte;
i, size&#58; Integer;
r&#58; byte;
Key&#58; Word;
begin
size &#58;= s.Size; SetLength&#40;arrbyte, size&#41;;
s.Position &#58;= 0; s.Read&#40;arrbyte&#91;0&#93;, SizeOf&#40;arrbyte&#91;0&#93;&#41; * size&#41;;
Key &#58;= password;
for i &#58;= 0 to High&#40;arrbyte&#41; do // for every byte in the stream
begin
r &#58;= arrbyte&#91;i&#93;;
arrbyte&#91;i&#93; &#58;= arrbyte&#91;i&#93; xor &#40;Key shr 8&#41;;
Key &#58;= &#40;r + Key&#41; * C1 + C2;
end;
s.Position &#58;= 0; s.Write&#40;arrbyte&#91;0&#93;, SizeOf&#40;arrbyte&#91;0&#93;&#41; * size&#41;;
result &#58;= s;
end;


I load an Imagelist like this:

ImageListEditor.ImageList.DecodeFunction := MyDecrypt;
imagelisteditor.ImageList.LoadFromFile('grafix\ima gelisteditor.oil');
Imagelisteditor.init;

Does this help?

Firle

Firlefanz
27-09-2005, 05:07 PM
Was me again, sorry. If you get it to work without the encryption, it is also fine, it is a nice feature but not so important I think for most Omega users, because Dan already wrote a tool which can hack it so the encryption is not very good anyway.

Firle

Sly
27-09-2005, 09:56 PM
Hi Sly,

this is the Decryption method:


function MyDecrypt&#40;s&#58; TStream&#41;&#58; TStream;
var arrbyte&#58; array of byte;
i, size&#58; Integer;
r&#58; byte;
Key&#58; Word;
begin
size &#58;= s.Size; SetLength&#40;arrbyte, size&#41;;
s.Position &#58;= 0; s.Read&#40;arrbyte&#91;0&#93;, SizeOf&#40;arrbyte&#91;0&#93;&#41; * size&#41;;
Key &#58;= password;
for i &#58;= 0 to High&#40;arrbyte&#41; do // for every byte in the stream
begin
r &#58;= arrbyte&#91;i&#93;;
arrbyte&#91;i&#93; &#58;= arrbyte&#91;i&#93; xor &#40;Key shr 8&#41;;
Key &#58;= &#40;r + Key&#41; * C1 + C2;
end;
s.Position &#58;= 0; s.Write&#40;arrbyte&#91;0&#93;, SizeOf&#40;arrbyte&#91;0&#93;&#41; * size&#41;;
result &#58;= s;
end;


I load an Imagelist like this:

ImageListEditor.ImageList.DecodeFunction := MyDecrypt;
imagelisteditor.ImageList.LoadFromFile('grafix\ima gelisteditor.oil');
Imagelisteditor.init;

Does this help?

Firle
That's going to be a huge timesink as well, plus it forces the use of TMemoryStream unless you want to write back over the same file you loaded from.

In your case, the LoadFromFile method will allocate 19MB and load the entire file into it. The DecodeFunction will then allocate another 19MB buffer, copy the entirity of the memory stream into that buffer, walk over every byte of that buffer, and copy the entire buffer back into the same stream that was passed in. Then it proceeds to save each image separately back to a memory stream and load the image back from the memory stream.

I'm at work now, so I cannot do any more stuff on the speed-up until I get home tonight. There is probably only so much that can be done with the existing file format. What it really needs is a new file format that does not go through the component streaming system.

technomage
27-09-2005, 11:12 PM
I'm just had a look at this thread. I have some comments about the use of TMemroyStream. This can be a great little class to use. However in order to make the most of it I would make use of the capacity property. Also you coul d try and only have one TMemroyStream that all the Init calls use.

You set the capacity to your max size of image then continually use that same stream as a buffer. One of the problems with TMemoryStream is it allocates memory on the fly if you write to it and the capacity < size. it's always better to grad a whole chunk in one go.

Hopefully using one TMemoryStream buffer will cut down on having to create and destroy the stream each time as well.

Hope this helps.

Sly
27-09-2005, 11:20 PM
That might help a bit for the part of the code where it saves the image back to the stream, but I don't think that is the major timesink.

Sly
28-09-2005, 02:31 PM
I'm going to have to call shenanigans on this issue. Trying to interpret the bitmap data and write it into a texture is driving me nuts. Plus the Delphi 2005 IDE is working against me. Why do Borland make such a crap IDE and crap debugger?

Firlefanz
29-09-2005, 06:22 AM
Hi Sly! (sounds cool, Hi Sly :wink: )

Can't you perhaps use D3DXSaveTextureToFile to make an Export to texture format? Or does that not help?

How do you get along? Found some improvements or something?
Or will you make something new for loading and exporting?

Firle

Sly
29-09-2005, 03:55 PM
Try this replacement OmegaImageList.pas
OmegaImageList.zip (http://users.on.net/~sly/files/OmegaImageList.zip)

It behaves exactly the same as the standard OmegaImageList, except it has some additional functionality.

OmegaImageList.ImageList.LoadFromFileData(Filename : String);
OmegaImageList.ImageList.LoadFromStreamData(Stream : TStream);
OmegaImageList.ImageList.SaveToFileData(Filename: String);
OmegaImageList.ImageList.SaveToStreamData(Stream: TStream);

To test it out, load your imagelist as normal, then after the call to OmegaImageList.Init, call OmegaImageList.ImageList.SaveToFileData() with a different filename. Run your application and it should write out a file.

Comment out the calls to LoadFromFile, Init and SaveToFileData. Add in their place a call to OmegaImageList.ImageList.LoadFromFileData(). No call to Init() is required! Run the game and see if there is any speed difference.

Here is my test code.

&#123;.$DEFINE CREATEFILE&#125;
&#123;$DEFINE LOADFILE&#125;

procedure TForm3.FormCreate&#40;Sender&#58; TObject&#41;;
&#123;$IFDEF CREATEFILE&#125;
var
Item&#58; TImageListItem;
Index&#58; Integer;
&#123;$ENDIF CREATEFILE&#125;
begin
OmegaScreen1.Init;

&#123;$IFDEF CREATEFILE&#125;
for Index &#58;= 1 to 7 do
begin
Item &#58;= OmegaImageList1.ImageList.Add;
Item.Filepath &#58;= 'D&#58;\Files\Bitmaps\Tatiana\Tatiana' + IntToStr&#40;Index&#41; + '.jpg';
Item.TileWidth &#58;= -1;
Item.TileHeight &#58;= -1;
end;
OmegaImageList1.Init;

OmegaImageList1.ImageList.SaveToFileData&#40;'D&#58;\Temp\ tatiana.oil'&#41;;
&#123;$ENDIF CREATEFILE&#125;

&#123;$IFDEF LOADFILE&#125;
OmegaImageList1.ImageList.LoadFromFileData&#40;'D&#58;\Tem p\tatiana.oil'&#41;;
&#123;$ENDIF LOADFILE&#125;
end;

procedure TForm3.FormPaint&#40;Sender&#58; TObject&#41;;
var
Index&#58; Integer;
begin
OmegaScreen1.BeginRender;
OmegaScreen1.ClearScreen&#40;0, 0, 0&#41;;
for Index &#58;= 0 to OmegaImageList1.ImageList.Count - 1 do
OmegaImageList1.ImageList.Items&#91;Index&#93;.Draw&#40;Index * 32, Index * 32, Index&#41;;
OmegaScreen1.EndRender;
end;

The file is essentially a binary dump of the required properties of each image item, plus a PNG file written out by D3DXSaveTextureToFileInMemory(), all packed into one file. The file is loaded one image at a time, so memory usage has been cut dramatically.

Hope that helps. I scared myself because that code worked first time. Let me know how it goes.

It's time for me to go to bed seeing as it is now 1:50am and I have to get up at 7am.

Edit: I also added "uses Jpeg;" so that it could load JPGs.

Firlefanz
30-09-2005, 06:33 AM
Hallo Sly,

thanks a lot! I have downloaded it and I will test it when I am home again (currently at work). :D

Firle

Firlefanz
30-09-2005, 07:49 AM
Hello Sly and everybody interested,

the Omega forum is back again.
I made a post to let them know you are working on our Imegalistproblem (thanks again):

http://www.delphisanctuary.com/forums/viewtopic.php?p=9&sid=523985326c77c48ac2d9920d3e29dcb1#9

Firle

Sly
30-09-2005, 11:03 AM
Firlefanz, to answer your question in your forum about how to process all your 600 files with pngout, open a command prompt, cd to the directory containing your PNGs, and type this command

for %I in (*.png) do pngout.exe %I

Either have pngout.exe in your PATH, in the same directory as the PNGs, or specify the full path to it, such as

for %I in (*.png) do c:\utils\pngout.exe %I

Firlefanz
30-09-2005, 11:15 AM
This is again a good hint, thanks. But the problem is I have them in imagelists.

Perhaps I could alter the Imagelsiteditor with a new method:

1) Export all images with a process number at the beginning of the filename to a temp dir
2) for %I in (*.png) do imagelisteditorpath\pngout.exe %I progress each single image
3) Clear the imagelist, reload each single image by beginning number and remove that number.

Do you know if they only get smaller on harddisk (filesize) or also in memory? Than this would be worth the effort...

Firle

Firlefanz
01-10-2005, 11:29 AM
Hi Sly,

I did like you said. I produced some 'sly' files which are a bit smaller (some k) than my oil files.

But when loading them, and then drawing them to, screen, I get an error.

In OmegaScreen.setblendmode called from Draw4Col, I am examinig further, maybe I fogot something....

Firle

Firlefanz
01-10-2005, 11:36 AM
In Draw4Col, it seems

FRenderer.OmegaScreen.SetBlendMode(BlendMode);

than FRenderer.OmegaScreen the OmegaScreen is nil.

I did it like this:

Imagelistloading:=TOmegaImageList.Create(Commandof orm);
Imagelistloading.SetOmegaScreen(xenscreen);
//ImageListloading.ImageList.DecodeFunction := MyDecrypt;
//imagelistloading.ImageList.LoadFromFile('grafix\im agelistloading.oil');
//Imagelistloading.init;
//imagelistloading.ImageList.SaveToFileData('grafix\ imagelistloading.sly');
imagelistloading.ImageList.loadfromFileData('grafi x\imagelistloading.sly');

I also tried another Imagelistloading.SetOmegaScreen(xenscreen);
after that, but when drawing an item the first time I get that error.

Firle

Firlefanz
01-10-2005, 11:50 AM
Hi Sly,

I also added a new test button to my imagelisteditor (if you don't have it I can send you the code) and tried to read your new imagelistfile there with loadfromfiledata. It adds the image to my list, but cannot open the picture.

Did I forget something?

Firle

Sly
01-10-2005, 12:58 PM
The ImageListEditor won't be able to open the picture because the Picture property is empty. There is no point having the image in Picture as well as a texture. That is a waste of memory. Is there a way around it in the ImageListEditor? Can you draw the texture instead of using the Picture property?

To fix the crash, try adding these lines at the top of TImageListCollection.LoadFromStreamData.

TOmegaImageList&#40;Owner&#41;.FRenderer.OmegaScreen &#58;= TOmegaImageList&#40;Owner&#41;.OmegaScreen;
TOmegaImageList&#40;Owner&#41;.FRenderer.Init;

That is something that TOmegaImageList.Init did but I forgot to do. I didn't notice it because I was using TImageListItem.Draw, not Draw4Col.

Note: The size of the file is dependant on the file type that is specified in the call to D3DXSaveTextureToFileInMemory. I first tried DDS format, but its file sizes were huge. I'm currently using PNG, but you could experiment with different file types.

I don't know what effect pngout.exe has on the sizes of PNGs in memory.

Firlefanz
01-10-2005, 01:48 PM
Hello Sly and thanks a lot for the fix, I'll try that tomorrow. :)
And also thanks for the info. I'll let you know how I proceed, thanks :wink:

I don't need that stuff in the Imagelisteditor, it was just a test.

Firle

Sly
01-10-2005, 02:09 PM
Reading up on pngout, it only reduces the file size by using better compression. The image data once unpacked is exactly the same. In the case we are looking at, it will not help us in any way.

Trivia: pngout is written by Ken Silverman, the author of the Build engine used for Duke Nukem 3D, Shadow Warrior, Blood, etc.

Sly
03-10-2005, 03:28 AM
Any results, Firlefanz?

Firlefanz
03-10-2005, 03:26 PM
Hi Sly,

had no time yesterday, I'll try and let you know, thanks. :wink:

Firle

Firlefanz
04-10-2005, 05:29 PM
Hi Sly,

loading is working now and displkaying with Draw and Draw4Col is also working. It just seems we have still a little problem with transparency or something. My mouse cursor was transparent before, now it is displayed without transparency (black). This was the same problem I had when trying to use DDS format. It uses Draw method, blendmode is 0, all colors and alpha are 255. Any idea?

Firle

Sly
04-10-2005, 10:10 PM
Have you tried timing the difference between the old-style loading and the new one? It would be interesting to see if there is a significant improvement to the load times.

I never tried a transparent image. I will try to find out what's going wrong with it when I get home.

Sly
06-10-2005, 10:55 PM
I cannot even get a masked image to work with the standard OmegaImageList. Firle, is there anything special I have to do other than set Transparent to True and set the TransparentColor?

Firlefanz
07-10-2005, 05:34 AM
Hi Sly,

create two image, store them in your imagelist and save.

Then load, fill your screen with one image. The other image should have some black areas. Then set Transparent=true and transparentcolor=rgb(0,0,0) and draw it on mouse coordinates. It is not transparent in my case.

The old imagelist stored those both values, is it just I have to set them after loading again myself now?

I didn't have much time to test it all enough, but I will this weekend. :wink:

Thanks,
Firle

Sly
07-10-2005, 05:47 AM
The new file does store both the Transparent flag and the TransparentColor, so I'm confused as to why it isn't working. But then, I couldn' get masking to work when manually adding the image to the list either and setting both those properties.

Do I need to use a certain BlendMode to get the image to show masked? I was using the default of bmNormal. Is that right?

Anonymous
07-10-2005, 06:59 AM
Bmnormal should be working fine. Perhaps you can sent me a sample or should I make a sample for you?

firle

Sly
07-10-2005, 07:05 AM
If you could send me an example that you know works, that would be helpful.

Email is stevewilliams@kromestudios.com

Sly
07-10-2005, 12:50 PM
I tried it as you said, and the transparency worked fine. If you could send me a non-working sample, I'll try to find out what is going on.

I think my initial problem was that my transparency colour might have been a little incorrect. Using a sample of black as transparent worked fine.

Firlefanz
24-10-2005, 07:04 AM
Hi Sly,

very sorry about the late reply, but I was too busy last weeks and had no time for nothing, sorry! I'll try to make a sample when I am home again, thanks!

I am also using Alpha Channel in one Imagelist now, would that also work? I'll try it.

Firle

Sly
24-10-2005, 07:20 AM
It should all work. At least, all the images I have tried worked. I have not specifically tried one with an alpha channel, but since it saves the image as a PNG internally, and PNG supports alpha channel, it should simply work.

Firlefanz
25-10-2005, 06:58 PM
I am so busy now, too bad. :x

I made some adds to my Imagelisteditor, it can now Export all imagelists to your format (and lots of other things of course). If you are interested, I can post it. I still need to create a sample, I hope I can do it soon, this weekend I'll have some time. :wink:

Thanks again and sorry for not testing it much, but I soon will.

Firle

Firlefanz
30-10-2005, 01:23 PM
Hello Sly,

at least I did it and made a sample, which should also calculate the loading time. The result was interesting, but I don't know perhaps I did something wrong. It seems you are loading 2-3 times faster, this would be great. Have to test it with other stuff also. :wink:

First my Imagelisteditor (not looking very good now because added some stuff somewhere without care ;)) It has a button on the right Save filedata, with it you can load an Imagelist and then save it to your new format. I used it to convert a huge imagelist with starships.

http://www.ericbehme.de/download/imagelisteditor.zip

Works very well. Then my sample to load imagelists both ways and calculte the time. It is also very interesting the transparency error I had first is not there anymore, I'll examine further. The file is very big because of the huge imagelists to test...

And please don't anybody use my starship images, most of them are for our next game. Just a sample and I needed a huge imagelist to test. :D

Perhaps anybody can take a look and say if my results are correct? Would be great. :wink:

http://www.ericbehme.de/download/OmegaImageTest.zip

Firle

Sly
30-10-2005, 10:28 PM
I'll give it a test when I get home tonight.

Sly
31-10-2005, 01:47 PM
I gave it a test. I got ~6.8 seconds for loading the old format and ~2.8 seconds for loading my format. Seems like a decent speed increase if I say so myself. :wink:

Firlefanz
31-10-2005, 01:52 PM
I had the same. Looks like a very good speed increase to me, thanks Sly.
Did you see that little spaceship at the mouse cursor both times and was it transparent, no black square around it?

Do you think the way of calculating the time was correct (in the source)?

Thanks a lot,
Firle

Sly
01-11-2005, 01:22 AM
The time calculation was pretty much right, I think. I didn't look at it too closely, but it looks ok.

Yes, the spaceship was nicely transparent around the edges. :)

As a side note, I also tried using some other file formats that D3DX can use, such as DDS and TGA. The file with the images saved as DDS was ~60MB, but read in about the same time as the PNG version. The TGA version was around 43MB and once again, read in approximately the same time. So I think we have a winner with what we have.

Firlefanz
01-11-2005, 08:25 AM
Woah! We absolutely have a winner. :D

That DDS stuff I wanted to try, too. But I wouldn't use it either because I am having images that don't have power of 2 in height and width. :wink:

But an interesting point. Now I'll translate all my imagelists and see how the loading time is, then I'll try alphachannel and include it into my game and also ask Bobby to include your changes into the CVS. I already made a new topic at DelphiSanctuary butt all were to busy to do some testing, but I am sure they'll be glad if they see the results now.

Very good job done! :D Thanks again.
I am having two problem with the Omega headers still, both with the SpriteEngine. One is ordering by Z values the other is a custom Collision detection I made myself, both are not running without errors.
Are you also into that stuff? :shock: I worked myself on it and need someone to take a look why it is not working perfect...

But thanks again, this is a very good step ahead for the imagelists!

Firle

Firlefanz
01-11-2005, 09:21 AM
Hi Sly!

Exported all imagelists to your format and changed everything in my game to your loading method.

Now again the old problem:

http://www.ericbehme.de/bilder/temp/test.jpg

Looks like it is not transparent or transparent color is wrong?
I hope it is no bigger problem? Loading pretty fast... :wink:

Any idea? I'll examine...

Firle

Firlefanz
01-11-2005, 09:26 AM
Hello Sly,

this both does not help:

imagelistmenu.ImageList.Items[0].TransparentColor:=clblack;
imagelistmenu.ImageList.Items[0].Transparent:=true;

or

imagelistmenu.ImageList.Items[0].SetTransparentColor(clblack);
imagelistmenu.ImageList.Items[0].Transparent:=true;

Firle

Firlefanz
01-11-2005, 09:40 AM
One more thing: I kept the Imagelistwhatever.Init after LoadfromFiledata, if I don't use it anymore I get an error when drawing my GUI, the GUI items are drawn with Draw4Col. If I throw the Init out, I get an error there, if I keep it it is working (except of transparency).

It would be perfect if I get a fix for that transparency and perhaps you could alter my sample to Draw4Col to see if it is a simple thing to change or if I should still use init.

Thanks a lot,
Firle

Firlefanz
01-11-2005, 10:42 AM
Hi Sly,

reading all the thread again I found this one:



The ImageListEditor won't be able to open the picture because the Picture property is empty. There is no point having the image in Picture as well as a texture. That is a waste of memory. Is there a way around it in the ImageListEditor? Can you draw the texture instead of using the Picture property?

To fix the crash, try adding these lines at the top of TImageListCollection.LoadFromStreamData.
Code:
TOmegaImageList(Owner).FRenderer.OmegaScreen := TOmegaImageList(Owner).OmegaScreen;
TOmegaImageList(Owner).FRenderer.Init;


That is something that TOmegaImageList.Init did but I forgot to do. I didn't notice it because I was using TImageListItem.Draw, not Draw4Col.


Okay, now it even works without the init and Draw4Col is also perfect now.

Only the transparency problem remains. Still examining. :shock: :wink:

Firle

Firlefanz
01-11-2005, 10:46 AM
Transparency problem is not always. Just in some cases.

Drawing my cursor:



procedure TCommandoForm.Draw_Mouse;
begin
if xenscreen.FullScreen then ImageListmenu.ImageList.Items&#91;0&#93;.Draw&#40;mouse.Cursor Pos.X,mouse.CursorPos.y,0,0,0,1,1,255,255,255,255, round&#40;nwatertimer&#41;,bmnormal&#41;
else ImageListmenu.ImageList.Items&#91;0&#93;.Draw&#40;
&#40;mouse.CursorPos.X-CommandoForm.Left&#41;*xenscreen.Width div CommandoForm.Width
,&#40;mouse.CursorPos.y-CommandoForm.Top&#41;*xenscreen.Width div CommandoForm.Width,0,0,0,1,1,255,255,255,255,round &#40;nwatertimer&#41;,bmnormal&#41;;
end;


Strange. In other cases it is working, and before I used your method it was also working. Cannot be a big problem, must be a minor one. :roll:

Firle

Sly
01-11-2005, 01:15 PM
This is a strange one. I will have to have a look at it, but I won't be able to get to it before the weekend. I am performing in a dance concert and we have rehearsals Wednesday and Thursday night, with the performances on Friday night, Saturday afternoon and Saturday night.

Firlefanz
01-11-2005, 04:14 PM
Hi Sly,

sounds cool. Good luck on your dance contest! :mrgreen:

I'll look myself into it. If this is the only place, no problem.

I'll do some tests now and let you know the next days, thanks!

Firle

Firlefanz
01-11-2005, 04:21 PM
The mouse cursor seems to be the only place where this is a problem, everything else if just fine! Great! :D

The only thing is that the alpha-channel is not working anymore. But this is a minor problem, I only use it for one special imagelist and I can load it the old way.

Seems it is working fine :wink:

Firle

Firlefanz
02-11-2005, 07:25 AM
Hi Sly,

did you change anything else but these methods?



OmegaImageList.ImageList.LoadFromFileData(Filename : String);
OmegaImageList.ImageList.LoadFromStreamData(Stream : TStream);
OmegaImageList.ImageList.SaveToFileData(Filename: String);
OmegaImageList.ImageList.SaveToStreamData(Stream: TStream);


So one minor thing is the alpha channel of the images, it is gone. You can simply create some alpha channel for a png image when loading an old imagelist (the one with the sample or your own) with png images, then press one of the both alpha creation buttons in the imagelisteditor.
You can save and load it, it is still there, if you export it to your format it is gone.

This is just a minor problem, if you can fix it would be good, if not or if loading takes longer then or something I would use the old format for imagelists with alpha and your new format for all others.

I will now again open a topic in DelphiSanctuary and try to get your changes into the CVS. Thanks again,

Firle

Sly
02-11-2005, 10:17 PM
I think they were the only methods that I added/changed.

I will have a closer look at the alpha channel problem.

Firlefanz
11-11-2005, 06:11 AM
Hi Sly :D

found something on the AlphaChannel for PNG issue?
I can send you an imagelist if you like.

If it is not working no problem, but it would be interesting to know.

Thanks :wink:

Firle

Sly
11-11-2005, 02:15 PM
Would you believe that it is the way D3DX saves out to PNG files? If I change the format to use DDS or BMP files, it works. The downside to that is the file size grows quite a bit. It still loads quickly, but the file is a lot larger. As a comparison, my test file is 51KB as PNG, 277KB as BMP and 369KB as DDS.

So D3DX can load alpha from PNG files ok, but if you save the texture back out to a file using D3DX and load it again using D3DX, the alpha no longer works. The alpha is there in the image. I tested this by loading the saved PNG into PaintShop Pro and the alpha channel is there. Something goes wrong, but I cannot tell what.

To test the fix, search in OmegaImageList.pas for D3DXIFF_PNG and change it to D3DXIFF_DDS or D3DXIFF_BMP. Save out your image lists again from the original source images and try loading them. The alpha should work now.

Anonymous
11-11-2005, 06:26 PM
Hi Sly,

this is no problem. All my stuff with Alphachannel now is stored in one imagelist, and this imagelist I load and save the old way. I have a dozen more, they are quick-loaded your way without alphachannel. :D

Thanks a lot for the info!

Firle