//#define ENABLE_LOG_PRINTF #include #include "evas_direct3d_object_font.h" #include "evas_direct3d_image_cache.h" #include "evas_direct3d_device.h" #include "evas_direct3d_shader_pack.h" #include "evas_direct3d_vertex_buffer_cache.h" D3DObjectFont::Cache D3DObjectFont::_cache; D3DObjectFont::D3DObjectFont(void *source, int image_id) { _image_id = image_id; _color = 0xff000000; _source = source; D3DImageCache::Current()->AddImageUser(_image_id); } D3DObjectFont::~D3DObjectFont() { D3DImageCache::Current()->RemoveImageUser(_image_id); } void D3DObjectFont::CopyTo(D3DObjectFont *font) { assert(font != NULL); font->_image_id = _image_id; font->_source = _source; D3DImageCache::Current()->AddImageUser(font->_image_id); _glyphs.CopyTo(font->_glyphs); } void D3DObjectFont::BeginCache(int image_id) { if (_cache.enabled) return; int w = D3DImageCache::Current()->GetImageWidth(image_id); int h = D3DImageCache::Current()->GetImageHeight(image_id); _cache.enabled = true; _cache.image_id = image_id; _cache.data.Allocate(w * h); if (_cache.dirty.Length() != h) { _cache.dirty.Allocate(h); memset(_cache.dirty.Data(), 0xff, sizeof(POINT) * _cache.dirty.Length()); } ZeroMemory(_cache.data.Data(), sizeof(DWORD) * _cache.data.Length()); _cache.width = w; _cache.height = h; _cache.valid_rect.left = w; _cache.valid_rect.right = 0; _cache.valid_rect.top = h; _cache.valid_rect.bottom = 0; } void D3DObjectFont::Draw(D3DDevice *d3d) { assert(_cache.image_id == _image_id); } void D3DObjectFont::EndCache(D3DDevice *d3d) { if (!_cache.enabled) return; _cache.enabled = false; if (_cache.data.Length() == 0) return; D3DImageCache::CacheEntryInfo info; ZeroMemory(&info, sizeof(info)); info.id = _cache.image_id; info.width = _cache.width; info.height = _cache.height; if (!D3DImageCache::Current()->UpdateImageDataWithDirtyInfo(info, _cache.data.Data(), _cache.dirty.Data())) //if (!D3DImageCache::Current()->UpdateImageDataDiscard(info, _cache.data.Data())); { return; } D3DShaderPack::Current()->SetVDecl(d3d, D3DShaderPack::VDECL_XYUV); D3DShaderPack::Current()->SetVS(d3d, D3DShaderPack::VS_COPY_UV); D3DShaderPack::Current()->SetPS(d3d, D3DShaderPack::PS_TEX_2); // This image is in s1 D3DImageCache::Current()->SelectImageToDevice(d3d, _cache.image_id); const FLOAT half_x = 0.5f / FLOAT(_cache.width); const FLOAT half_y = 0.5f / FLOAT(_cache.height); FLOAT left = FLOAT(_cache.valid_rect.left - 5) / FLOAT(_cache.width), top = FLOAT(_cache.valid_rect.top - 5) / FLOAT(_cache.height), right = FLOAT(_cache.valid_rect.right + 5) / FLOAT(_cache.width), bottom = FLOAT(_cache.valid_rect.bottom + 5) / FLOAT(_cache.height); const Vertex data[6] = { {left * 2 - 1, 2 * (1 - bottom) - 1, left + half_x, bottom + half_y}, {left * 2 - 1, 2 * (1 - top) - 1, left + half_x, top + half_y}, {right * 2 - 1, 2 * (1 - bottom) - 1, right + half_x, bottom + half_y}, {right * 2 - 1, 2 * (1 - bottom) - 1, right + half_x, bottom + half_y}, {left * 2 - 1, 2 * (1 - top) - 1, left + half_x, top + half_y}, {right * 2 - 1, 2 * (1 - top) - 1, right + half_x, top + half_y}}; d3d->GetDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 2, data, sizeof(Vertex)); //D3DImageCache::Current()->UpdateImageDataWithDirtyInfo(info, NULL, _cache.dirty.Data()); } D3DObjectFont::Glyph *D3DObjectFont::GetGlyph(void *source) { if (_image_id < 0) { Log("Font is not initialized"); return NULL; } for (int i = 0; i < _glyphs.Length(); i++) { if (_glyphs[i]->Compare(source)) return _glyphs[i]; } return NULL; } D3DObjectFont::Glyph *D3DObjectFont::AddGlyph(D3DDevice *d3d, void *source, BYTE *data8, int width, int height, int pitch) { if (_image_id < 0) { Log("Font is not initialized"); return NULL; } for (int i = 0; i < _glyphs.Length(); i++) { if (_glyphs[i]->Compare(source)) return _glyphs[i]; } Ref glyph = new Glyph(source); glyph->_data.Allocate(width * height); glyph->_width = width; glyph->_height = height; for (int i = 0; i < height; i++) CopyMemory(&glyph->_data[i * width], &data8[i * pitch], width); Log("Glyph added (%p) (%dx%d)", source, width, height); _glyphs.Add(glyph); return _glyphs.Last()->Addr(); } void D3DObjectFont::PushForDraw(Glyph *glyph, int x, int y) { BeginCache(_image_id); // Uff, I'm not sure about multiple windows... #define LERP(a, b, t1, t2) (BYTE)(FLOAT(a) * (t1) + FLOAT(b) * (t2)) Color dc, sc; FLOAT a; sc.color = _color; const FLOAT color_alpha = sc.Alpha(); DWORD *data = _cache.data.Data(); BYTE *gdata = glyph->_data.Data(); const int glyph_height = glyph->_height; const int cache_height = _cache.height; const int glyph_width = glyph->_width; const int cache_width = _cache.width; for (int i = 0, yi = y; i < glyph_height && yi < cache_height; i++, yi++) { if (yi < 0) continue; DWORD *dst = data + ((yi) * cache_width + x); BYTE *src = gdata + (i * glyph_width); POINT *dirty_yi = &_cache.dirty[yi]; if (_cache.valid_rect.top > yi) _cache.valid_rect.top = yi; if (_cache.valid_rect.bottom < yi) _cache.valid_rect.bottom = yi; for (int j = 0, xj = x; j < glyph_width && xj < cache_width; j++, xj++, dst++, src++) { if (xj < 0) continue; BYTE glyph_pix = *src; if (glyph_pix == 0) continue; if (dirty_yi->x >= 0 && dirty_yi->y < 0) dirty_yi->x = 0, dirty_yi->y = cache_width - 1; else { if (dirty_yi->x < 0 || dirty_yi->x > xj) dirty_yi->x = xj; if (dirty_yi->y < 0 || dirty_yi->y < xj) dirty_yi->y = xj; } if (_cache.valid_rect.left > xj) _cache.valid_rect.left = xj; if (_cache.valid_rect.right < xj) _cache.valid_rect.right = xj; if (glyph_pix == 0xff && sc.a == 0xff) { *dst = sc.color; continue; } a = FLOAT(glyph_pix) * color_alpha / 255.f; if (*dst == 0) { *dst = (BYTE(255.f * a) << 24) | (0x00ffffff & sc.color); continue; } dc.color = *dst; dc.r = LERP(dc.r, sc.r, 1 - a, a); dc.g = LERP(dc.g, sc.g, 1 - a, a); dc.b = LERP(dc.b, sc.b, 1 - a, a); dc.a = max(dc.a, BYTE(255.f * a)); *dst = dc.color; } } }