так чтобы это делать — как раз надо расширять и Rider, и Frame интерфейсами для создания и вывода растров. и добавлять соответствующий интерфейс в bottleneck. у меня эти интерфейсы вдобавок жёстко заточены на наличие заднего буфера с валидной картинкой, и ожидают, что можно делать альфа-блендинг с тем, что было нарисовано раньше.
так-то я переделал StdRasters на мой новый интерфейс, можно из любой загруженой картинки получить растр для рисования (или чтения пикселей). а декодеры живут в хосте. собственно, у меня так сейчас (см. мой Ports):
Код:
TYPE
(* raster with direct access to bitmap data.
the data is always in RGBA format compatible with Color. A may be unused. *)
RasterData* = POINTER TO RasterDataDesc;
RasterDataDesc* = ARRAY OF INTEGER;
Raster* = POINTER TO ABSTRACT RECORD
w-, h-: INTEGER; (* in pixels, i.e. in array elements *)
unit-: INTEGER; (* original unit *)
data-: RasterData (* NIL when not locked *)
END;
(** RasterDirectory **)
(* produce empty raster; NewRaster will call Init on it *)
PROCEDURE (d: RasterDirectory) New- (): Raster, NEW, ABSTRACT;
(** Raster **)
(* draw alpha-blended image at the given rect; pixofs is the first image byte in img, pixstride is image width in img.
WARNING! coordinates and dimensions are in pixels, not in universal coords! *)
PROCEDURE (rd: Rider) BlendImage* (x, y, w, h, pixofs, pixstride: INTEGER; IN img: RasterDataDesc), NEW, ABSTRACT;
(* TODO: various blit modes and scaling *)
(* draw methods respect image alpha channel *)
PROCEDURE (r: Raster) Draw* (rd: Rider; x, y, unit: INTEGER), NEW, ABSTRACT;
PROCEDURE (r: Raster) DrawScaled* (rd: Rider; x, y, unit: INTEGER; sx, sy: SHORTREAL; q: INTEGER), NEW, ABSTRACT;
(* will be called by NewRaster after setting dimensions and unit *)
PROCEDURE (r: Raster) Init-, NEW, ABSTRACT;
(* will be called by Resize after setting dimensions and unit; free to wipe the content *)
PROCEDURE (r: Raster) Resized-, NEW, ABSTRACT;
(* can return NIL if raster is immutable *)
PROCEDURE (r: Raster) GetData- (): RasterData, NEW, ABSTRACT;
PROCEDURE (r: Raster) ReleaseData-, NEW, ABSTRACT;
(* wipes the contents, and sets the new size *)
PROCEDURE (r: Raster) Resize* (w, h, unit: INTEGER), NEW;
BEGIN ASSERT(w >= 0, 20); ASSERT(h >= 0, 21); ASSERT(unit > 0, 22); ASSERT(r.data = NIL, 23);
w := w DIV unit; h := h DIV unit;
IF (w = 0) OR (h = 0) THEN w := 0; h := 0 END;
IF (r.w # w) OR (r.h # h) THEN
r.w := w; r.h := h; r.unit := unit;
r.Resized
END
END Resize;
(* WARNING! locks are NOT recursive! *)
(* there is no need to call Unlock if r.data is NIL *)
PROCEDURE (r: Raster) Lock*, NEW;
BEGIN ASSERT(r.w >= 0, 20); ASSERT(r.h >= 0, 21); ASSERT(r.unit > 0, 22); ASSERT(r.data = NIL, 23);
r.data := r.GetData()
END Lock;
PROCEDURE (r: Raster) Unlock*, NEW;
BEGIN ASSERT(r.w >= 0, 20); ASSERT(r.h >= 0, 21); ASSERT(r.unit > 0, 22);
IF r.data # NIL THEN r.ReleaseData; r.data := NIL END
END Unlock;
(* this procedure put here because i couldn't find a better place for it.
all coordinates are in pixels. color is Ports.Color.
if r.data is NIL, then the raster will be locked, and then unlocked. *)
PROCEDURE (r: Raster) DrawText* (font: Fonts.Font; x, y: INTEGER; IN s: ARRAY OF CHAR; color: Color), NEW, ABSTRACT;
PROCEDURE (r: Raster) DrawTextClip* (font: Fonts.Font; x, y: INTEGER; IN s: ARRAY OF CHAR; color: Color;
x1, y1, x2, y2: INTEGER), NEW, ABSTRACT;
PROCEDURE (r: Raster) DrawSpace* (font: Fonts.Font; x, y, w: INTEGER; color: Color), NEW, ABSTRACT;
PROCEDURE (r: Raster) DrawSpaceClip* (font: Fonts.Font; x, y, w: INTEGER; color: Color;
x1, y1, x2, y2: INTEGER), NEW, ABSTRACT;
(* create new drawable raster; size in UC *)
PROCEDURE NewRaster* (w, h, unit: INTEGER): Raster;
я к тому, что если уж делать растры вручную — то нет ни одной причины не позволять прямой доступ к их пикселям: тогда пользователи смогут и сами их рисовать, и реализовывать дополнительные загрузчики картинок в разных форматах через стандартный интерфейс.
ну, и я предусмотрел вариант, когда реально картинка хранится не в обычном массиве: именно для этого введены `Lock()` и `Unlock()`. в варианте с gtk, например, массив для пикселов растра не создаётся, пока растр хоть раз не залочат: небольшая экономия, загруженый пиксмап остаётся в gtk, если на нём не рисуют потом. а вин-версия LC через GDI+, да, на том же интерфейсе. только она при `Lock()` пикселы вообще не возвращает: так можно, это штатно.
можно перевести mainline на подобный интерфейс сначала, а потом постепенно допиливать загрузки и блиты картинок уже: интерфейс позволяет разные методы использовать для этого, прозрачно для всего остального кода.