Hello all.
I am writing piece of software that works with sprites. It should be able to use external resources that are stored in png images (I cannot embed them). Also, I don't need all of them, but only some subset (subset of sprites in every png). So for now my plan is the following:
1. Ask use for the path to original sprites
2. Pick needed sprites, process them, and save near the application
3. Load processed sprites at runtime (no modifications at this step)
But I have problem with step 2 (I tried to do the processing from original resources at runtime, but it was very slow (I also do repainting), so decided to spend a few megabytes of RAM to speed up everything and do processing beforehand and only load result at runtime).
What's needed for a sprite file:
1. Get several first sprites from png image (I know sizes for each file).
2. Duplicate them with flips to get "full row".
3. Copy the row several times, but repainting some colors (I have color mapping what should be replaced).
4. Save all this into a png file that will be used further on.
I don't want to use OpenGL or similar and also would like not to depend on an external library (but still consider it as an option if using standard mechanism is problematic).
For now I have:
PNG := TPortableNetworkGraphic.Create();
Sprites := TImageList.Create(nil);
try
PNG.LoadFromFile(SourceFile);
Sprites.Width := PNG.Width div 5;
Sprites.Height := getHeightByName(SpriteName);
// Sprites.BkColor := clBlack;
// Sprites.DrawingStyle := dsTransparent;
for p := 1 to 10 do begin
Sprites.AddSliced(PNG, 5, 1); // Quick way to extract needed sprites from png
// HERE I NEED TO ADD FLIPPED/ROTATED EXISTING SPRITES
// Repaint sprites
for i := 0 to ROW_SPRITES_COUNT - 1 do begin
SpriteIndex := p * ROW_SPRITES_COUNT + i;
SpriteBitmap := TBitmap.Create();
try
Sprites.GetBitmap(SpriteIndex, SpriteBitmap);
RepaintSprite(SpriteBitmap, ORIGINAL_COLOR, DESIRED_COLOR);
Sprites.Replace(SpriteIndex, SpriteBitmap, nil);
finally
SpriteBitmap.Free();
end;
end;
end;
// Save image list to png file
Bitmap := TBitmap.Create();
Bitmap.Height := Sprites.Height;
Bitmap.Width := Sprites.Width * Sprites.Count;
for i:=0 to (Sprites.Count - 1) do
Sprites.Draw(Bitmap.Canvas, i * Sprites.Width, 0 , i);
try
// THIS LOSE TRANSPARENCY WHICH IS NEEDED
// I have to use png imgae instead bitmap here but I can get only bitmap from image list, what to do?
Bitmap.SaveToFile(DestFile);
finally
Bitmap.Free();
end;
finally
Sprites.Free();
PNG.Free();
end;
// --------------------------------------------
procedure RepaintSprite
if (ColorFrom = ColorTo) then Exit;
Bitmap.BeginUpdate();
for y:=0 to (Bitmap.Height - 1) do begin
for x:=0 to (Bitmap.Width - 1) do begin
// I know that it is possible to read whole row, but I read somewhere
// that it may bring trouble on different platforms, is it true?
PixelColor := Bitmap.Canvas.Pixels[x, y];
for i:=0 to SHADES_NUMBER do begin
if (PixelColor = SPRITES_COLORS[ColorFrom][i]) then begin
Bitmap.Canvas.Pixels[x, y] := SPRITES_COLORS[ColorTo][i];
break;
end;
end;
end;
end;
Bitmap.EndUpdate();
To sum up:
1. How to copy & flip sprites and and them into the same imagelist (or maybe I do not need image list at all here, but then I have to read sprites from original png myself, but I don't know how to copy an area and keep transparency...)?
2. Repaint. First, how to correctly replace (or maybe add after repaint) in imagelist. Second, but not critical, optimization. Pixel access is very slow, but can I safely use faster method (and keep cross platform support)? At least I can repaint first, so after flip I don't need to repaint again.
3. How to save back to png file. How to get sprite from imagelist keeping transparency and draw on resulting png in memory?
I do not need compatibility with Delphi, so using Lazarus specific classes are completely ok, but I need to support cross platform compilation.
I don't have much experience with images processing in Lazarus or Pascal, so sorry for several, probably silly questions (for people who know)... I googled, but there are different problems with different solutions... And people use different approaches: TBitmap, TImage, TPicture, TCanvas, Masks, etc (actually it should be sort of the same, but again if you know details about implementations). I got somewhat lost. Code above is what I was able to achieve for now...
Thank you in advance.