mirror of https://github.com/buggins/dlangui.git
image cache:
This commit is contained in:
parent
dccd5d8f88
commit
a41841b2bc
|
|
@ -18,9 +18,13 @@ uint blendARGB(uint dst, uint src, uint alpha) {
|
||||||
|
|
||||||
class DrawBuf : RefCountedObject {
|
class DrawBuf : RefCountedObject {
|
||||||
protected Rect _clipRect;
|
protected Rect _clipRect;
|
||||||
|
/// returns current width
|
||||||
@property int width() { return 0; }
|
@property int width() { return 0; }
|
||||||
|
/// returns current height
|
||||||
@property int height() { return 0; }
|
@property int height() { return 0; }
|
||||||
|
/// returns clipping rectangle, when clipRect.isEmpty == true -- means no clipping.
|
||||||
@property ref Rect clipRect() { return _clipRect; }
|
@property ref Rect clipRect() { return _clipRect; }
|
||||||
|
/// sets new clipping rectangle, when clipRect.isEmpty == true -- means no clipping.
|
||||||
@property void clipRect(const ref Rect rect) {
|
@property void clipRect(const ref Rect rect) {
|
||||||
_clipRect = rect;
|
_clipRect = rect;
|
||||||
_clipRect.intersect(Rect(0, 0, width, height));
|
_clipRect.intersect(Rect(0, 0, width, height));
|
||||||
|
|
@ -40,6 +44,9 @@ class DrawBuf : RefCountedObject {
|
||||||
}
|
}
|
||||||
void beforeDrawing() { }
|
void beforeDrawing() { }
|
||||||
void afterDrawing() { }
|
void afterDrawing() { }
|
||||||
|
/// returns buffer bits per pixel
|
||||||
|
@property int bpp() { return 0; }
|
||||||
|
/// returns pointer to ARGB scanline, null if y is out of range or buffer doesn't provide access to its memory
|
||||||
uint * scanLine(int y) { return null; }
|
uint * scanLine(int y) { return null; }
|
||||||
abstract void resize(int width, int height);
|
abstract void resize(int width, int height);
|
||||||
abstract void fill(uint color);
|
abstract void fill(uint color);
|
||||||
|
|
@ -52,9 +59,13 @@ class DrawBuf : RefCountedObject {
|
||||||
~this() { clear(); }
|
~this() { clear(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alias DrawBufRef = Ref!DrawBuf;
|
||||||
|
|
||||||
class ColorDrawBufBase : DrawBuf {
|
class ColorDrawBufBase : DrawBuf {
|
||||||
int _dx;
|
int _dx;
|
||||||
int _dy;
|
int _dy;
|
||||||
|
/// returns buffer bits per pixel
|
||||||
|
override @property int bpp() { return 32; }
|
||||||
@property override int width() { return _dx; }
|
@property override int width() { return _dx; }
|
||||||
@property override int height() { return _dy; }
|
@property override int height() { return _dy; }
|
||||||
override void fillRect(int left, int top, int right, int bottom, uint color) {
|
override void fillRect(int left, int top, int right, int bottom, uint color) {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
module dlangui.graphics.fonts;
|
module dlangui.graphics.fonts;
|
||||||
public import dlangui.graphics.drawbuf;
|
public import dlangui.graphics.drawbuf;
|
||||||
public import dlangui.core.types;
|
public import dlangui.core.types;
|
||||||
public import dlangui.core.logger;
|
public import dlangui.core.logger;
|
||||||
import std.algorithm;
|
import std.algorithm;
|
||||||
|
|
||||||
enum FontFamily : int {
|
enum FontFamily : int {
|
||||||
SansSerif,
|
SansSerif,
|
||||||
Serif,
|
Serif,
|
||||||
Fantasy,
|
Fantasy,
|
||||||
Cursive,
|
Cursive,
|
||||||
MonoSpace
|
MonoSpace
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Glyph
|
struct Glyph
|
||||||
{
|
{
|
||||||
ubyte blackBoxX; ///< 0: width of glyph
|
ubyte blackBoxX; ///< 0: width of glyph
|
||||||
|
|
@ -82,101 +82,101 @@ struct GlyphCache
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Font : RefCountedObject {
|
class Font : RefCountedObject {
|
||||||
abstract @property int size();
|
abstract @property int size();
|
||||||
abstract @property int height();
|
abstract @property int height();
|
||||||
abstract @property int weight();
|
abstract @property int weight();
|
||||||
abstract @property int baseline();
|
abstract @property int baseline();
|
||||||
abstract @property bool italic();
|
abstract @property bool italic();
|
||||||
abstract @property string face();
|
abstract @property string face();
|
||||||
abstract @property FontFamily family();
|
abstract @property FontFamily family();
|
||||||
abstract @property bool isNull();
|
abstract @property bool isNull();
|
||||||
// measure text string, return accumulated widths[] (distance to end of n-th character), returns number of measured chars.
|
// measure text string, return accumulated widths[] (distance to end of n-th character), returns number of measured chars.
|
||||||
abstract int measureText(const dchar[] text, ref int[] widths, int maxWidth);
|
abstract int measureText(const dchar[] text, ref int[] widths, int maxWidth);
|
||||||
// draw text string to buffer
|
// draw text string to buffer
|
||||||
abstract void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color);
|
abstract void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color);
|
||||||
abstract Glyph * getCharGlyph(dchar ch);
|
abstract Glyph * getCharGlyph(dchar ch);
|
||||||
|
|
||||||
// clear usage flags for all entries
|
// clear usage flags for all entries
|
||||||
abstract void checkpoint();
|
abstract void checkpoint();
|
||||||
// removes entries not used after last call of checkpoint() or cleanup()
|
// removes entries not used after last call of checkpoint() or cleanup()
|
||||||
abstract void cleanup();
|
abstract void cleanup();
|
||||||
|
|
||||||
void clear() {}
|
void clear() {}
|
||||||
|
|
||||||
~this() { clear(); }
|
~this() { clear(); }
|
||||||
}
|
}
|
||||||
alias FontRef = Ref!Font;
|
alias FontRef = Ref!Font;
|
||||||
|
|
||||||
struct FontList {
|
struct FontList {
|
||||||
FontRef[] _list;
|
FontRef[] _list;
|
||||||
uint _len;
|
uint _len;
|
||||||
~this() {
|
~this() {
|
||||||
for (uint i = 0; i < _len; i++) {
|
for (uint i = 0; i < _len; i++) {
|
||||||
_list[i].clear();
|
_list[i].clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// returns item by index
|
// returns item by index
|
||||||
ref FontRef get(int index) {
|
ref FontRef get(int index) {
|
||||||
return _list[index];
|
return _list[index];
|
||||||
}
|
}
|
||||||
// returns index of found item, -1 if not found
|
// returns index of found item, -1 if not found
|
||||||
int find(int size, int weight, bool italic, FontFamily family, string face) {
|
int find(int size, int weight, bool italic, FontFamily family, string face) {
|
||||||
for (int i = 0; i < _len; i++) {
|
for (int i = 0; i < _len; i++) {
|
||||||
Font item = _list[i].get;
|
Font item = _list[i].get;
|
||||||
if (item.family != family)
|
if (item.family != family)
|
||||||
continue;
|
continue;
|
||||||
if (item.size != size)
|
if (item.size != size)
|
||||||
continue;
|
continue;
|
||||||
if (item.italic != italic || item.weight != weight)
|
if (item.italic != italic || item.weight != weight)
|
||||||
continue;
|
continue;
|
||||||
if (!equal(item.face, face))
|
if (!equal(item.face, face))
|
||||||
continue;
|
continue;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ref FontRef add(Font item) {
|
ref FontRef add(Font item) {
|
||||||
Log.d("FontList.add() enter");
|
Log.d("FontList.add() enter");
|
||||||
if (_len >= _list.length) {
|
if (_len >= _list.length) {
|
||||||
_list.length = _len < 16 ? 16 : _list.length * 2;
|
_list.length = _len < 16 ? 16 : _list.length * 2;
|
||||||
}
|
}
|
||||||
_list[_len++] = item;
|
_list[_len++] = item;
|
||||||
Log.d("FontList.add() exit");
|
Log.d("FontList.add() exit");
|
||||||
return _list[_len - 1];
|
return _list[_len - 1];
|
||||||
}
|
}
|
||||||
// remove unused items - with reference == 1
|
// remove unused items - with reference == 1
|
||||||
void cleanup() {
|
void cleanup() {
|
||||||
for (int i = 0; i < _len; i++)
|
for (int i = 0; i < _len; i++)
|
||||||
if (_list[i].refCount <= 1)
|
if (_list[i].refCount <= 1)
|
||||||
_list[i].clear();
|
_list[i].clear();
|
||||||
int dst = 0;
|
int dst = 0;
|
||||||
for (int i = 0; i < _len; i++) {
|
for (int i = 0; i < _len; i++) {
|
||||||
if (!_list[i].isNull)
|
if (!_list[i].isNull)
|
||||||
if (i != dst)
|
if (i != dst)
|
||||||
_list[dst++] = _list[i];
|
_list[dst++] = _list[i];
|
||||||
}
|
}
|
||||||
_len = dst;
|
_len = dst;
|
||||||
for (int i = 0; i < _len; i++)
|
for (int i = 0; i < _len; i++)
|
||||||
_list[i].cleanup();
|
_list[i].cleanup();
|
||||||
}
|
}
|
||||||
void checkpoint() {
|
void checkpoint() {
|
||||||
for (int i = 0; i < _len; i++)
|
for (int i = 0; i < _len; i++)
|
||||||
_list[i].checkpoint();
|
_list[i].checkpoint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FontManager {
|
class FontManager {
|
||||||
static __gshared FontManager _instance;
|
static __gshared FontManager _instance;
|
||||||
static @property void instance(FontManager manager) {
|
static @property void instance(FontManager manager) {
|
||||||
_instance = manager;
|
_instance = manager;
|
||||||
}
|
}
|
||||||
static @property FontManager instance() {
|
static @property FontManager instance() {
|
||||||
return _instance;
|
return _instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract ref FontRef getFont(int size, int weight, bool italic, FontFamily family, string face);
|
abstract ref FontRef getFont(int size, int weight, bool italic, FontFamily family, string face);
|
||||||
|
|
||||||
// clear usage flags for all entries
|
// clear usage flags for all entries
|
||||||
abstract void checkpoint();
|
abstract void checkpoint();
|
||||||
|
|
@ -184,5 +184,5 @@ class FontManager {
|
||||||
// removes entries not used after last call of checkpoint() or cleanup()
|
// removes entries not used after last call of checkpoint() or cleanup()
|
||||||
abstract void cleanup();
|
abstract void cleanup();
|
||||||
|
|
||||||
~this() {}
|
~this() {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,77 @@ module dlangui.graphics.images;
|
||||||
import dlangui.graphics.drawbuf;
|
import dlangui.graphics.drawbuf;
|
||||||
import std.stream;
|
import std.stream;
|
||||||
import libpng.png;
|
import libpng.png;
|
||||||
import core.sys.posix.setjmp;
|
|
||||||
|
/// decoded image cache
|
||||||
|
class ImageCache {
|
||||||
|
|
||||||
|
static class ImageCacheItem {
|
||||||
|
string _filename;
|
||||||
|
DrawBufRef _drawbuf;
|
||||||
|
bool _error; // flag to avoid loading of file if it has been failed once
|
||||||
|
bool _used;
|
||||||
|
this(string filename) {
|
||||||
|
_filename = filename;
|
||||||
|
}
|
||||||
|
@property ref DrawBufRef get() {
|
||||||
|
if (!_drawbuf.isNull || _error) {
|
||||||
|
_used = true;
|
||||||
|
return _drawbuf;
|
||||||
|
}
|
||||||
|
_drawbuf = loadImage(_filename);
|
||||||
|
_used = true;
|
||||||
|
if (_drawbuf.isNull)
|
||||||
|
_error = true;
|
||||||
|
return _drawbuf;
|
||||||
|
}
|
||||||
|
/// remove from memory, will cause reload on next access
|
||||||
|
void compact() {
|
||||||
|
if (!_drawbuf.isNull)
|
||||||
|
_drawbuf.clear();
|
||||||
|
}
|
||||||
|
/// mark as not used
|
||||||
|
void checkpoint() {
|
||||||
|
_used = false;
|
||||||
|
}
|
||||||
|
/// cleanup if unused since last checkpoint
|
||||||
|
void cleanup() {
|
||||||
|
if (!_used)
|
||||||
|
compact();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImageCacheItem[string] _map;
|
||||||
|
|
||||||
|
/// get and cache image
|
||||||
|
ref DrawBufRef get(string filename) {
|
||||||
|
if (filename in _map) {
|
||||||
|
return _map[filename].get;
|
||||||
|
}
|
||||||
|
ImageCacheItem item = new ImageCacheItem(filename);
|
||||||
|
_map[filename] = item;
|
||||||
|
return item.get;
|
||||||
|
}
|
||||||
|
// clear usage flags for all entries
|
||||||
|
void checkpoint() {
|
||||||
|
foreach (item; _map)
|
||||||
|
item.checkpoint();
|
||||||
|
}
|
||||||
|
// removes entries not used after last call of checkpoint() or cleanup()
|
||||||
|
void cleanup() {
|
||||||
|
foreach (item; _map)
|
||||||
|
item.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// load and decode image from file to ColorDrawBuf, returns null if loading or decoding is failed
|
||||||
|
ColorDrawBuf loadImage(string filename) {
|
||||||
|
try {
|
||||||
|
std.stream.File f = new std.stream.File(filename);
|
||||||
|
scope(exit) { f.close(); }
|
||||||
|
return loadImage(f);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// load and decode image from stream to ColorDrawBuf, returns null if loading or decoding is failed
|
/// load and decode image from stream to ColorDrawBuf, returns null if loading or decoding is failed
|
||||||
ColorDrawBuf loadImage(InputStream stream) {
|
ColorDrawBuf loadImage(InputStream stream) {
|
||||||
|
|
@ -37,6 +107,7 @@ extern (C) void lvpng_read_func(png_structp png, png_bytep buf, png_size_t len)
|
||||||
throw new ImageDecodingException("Error while reading PNG image");
|
throw new ImageDecodingException("Error while reading PNG image");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// load and decode PNG image
|
||||||
ColorDrawBuf loadPngImage(InputStream stream)
|
ColorDrawBuf loadPngImage(InputStream stream)
|
||||||
{
|
{
|
||||||
png_structp png_ptr = null;
|
png_structp png_ptr = null;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue