📄 qpaintengine_d3d.cpp
字号:
STDMETHOD(SetFVF)(DWORD FVF); STDMETHOD(SetVertexShader)(LPDIRECT3DVERTEXSHADER9 pShader); STDMETHOD(SetVertexShaderConstantF)(UINT RegisterIndex, CONST FLOAT *pConstantData, UINT RegisterCount); STDMETHOD(SetVertexShaderConstantI)(UINT RegisterIndex, CONST INT *pConstantData, UINT RegisterCount); STDMETHOD(SetVertexShaderConstantB)(UINT RegisterIndex, CONST BOOL *pConstantData, UINT RegisterCount); STDMETHOD(SetPixelShader)(LPDIRECT3DPIXELSHADER9 pShader); STDMETHOD(SetPixelShaderConstantF)(UINT RegisterIndex, CONST FLOAT *pConstantData, UINT RegisterCount); STDMETHOD(SetPixelShaderConstantI)(UINT RegisterIndex, CONST INT *pConstantData, UINT RegisterCount); STDMETHOD(SetPixelShaderConstantB)(UINT RegisterIndex, CONST BOOL *pConstantData, UINT RegisterCount);private: LPDIRECT3DVERTEXSHADER9 m_vertexshader; LPDIRECT3DPIXELSHADER9 m_pixelshader; LPDIRECT3DBASETEXTURE9 m_textures[D3D_STAGE_COUNT]; DWORD m_texturestates[D3D_STAGE_COUNT][D3D_TEXTURE_STATES]; DWORD m_samplerstates[D3D_STAGE_COUNT][D3D_SAMPLE_STATES]; DWORD m_renderstate[D3D_RENDER_STATES]; qreal m_radgradfd; bool m_cosmetic_pen; int m_pass; int m_maskchannel; int m_brushmode; LPDIRECT3DBASETEXTURE9 m_texture; D3DXMATRIX m_projection; D3DXMATRIX m_d3dIdentityMatrix; bool m_isIdentity; QTransform m_transformation; LPDIRECT3DDEVICE9 m_pDevice; ID3DXEffect *m_effect; LONG m_refs; bool m_changed; qreal m_xoffset, m_yoffset; static int m_mask_channels[4][4];};//// font cache stuff//struct QD3DGlyphCoord { // stores the offset and size of a glyph texture qreal x; qreal y; qreal width; qreal height; qreal log_width; qreal log_height; QFixed x_offset; QFixed y_offset;};struct QD3DFontTexture { int x_offset; // current glyph offset within the texture int y_offset; int width; int height; IDirect3DTexture9 *texture;};typedef QHash<glyph_t, QD3DGlyphCoord*> QD3DGlyphHash;typedef QHash<QFontEngine*, QD3DGlyphHash*> QD3DFontGlyphHash;typedef QHash<quint64, QD3DFontTexture*> QD3DFontTexHash;class QD3DGlyphCache : public QObject{ Q_OBJECTpublic: QD3DGlyphCache() : QObject(0) , current_cache(0) {} ~QD3DGlyphCache(); QD3DGlyphCoord *lookup(QFontEngine *, glyph_t); void cacheGlyphs(QDirect3DPaintEngine *, const QTextItemInt &, const QVarLengthArray<glyph_t> &, bool); void cleanCache(); inline QD3DFontTexture *fontTexture(QFontEngine *engine) { return font_textures.constFind(reinterpret_cast<quint64>(engine)).value(); }public slots: void fontEngineDestroyed(QObject *);private: QImage clearTypeGlyph(QFontEngine *, glyph_t glyph); QD3DGlyphHash *current_cache; QD3DFontTexHash font_textures; QD3DFontGlyphHash font_cache;};QD3DGlyphCache::~QD3DGlyphCache(){}QD3DGlyphCoord *QD3DGlyphCache::lookup(QFontEngine *, glyph_t g){ Q_ASSERT(current_cache != 0); QD3DGlyphHash::const_iterator it = current_cache->constFind(g); if (it == current_cache->constEnd()) return 0; return it.value();}void QD3DGlyphCache::cleanCache(){ QList<quint64> keys = font_textures.keys(); for (int i=0; i<keys.size(); ++i) font_textures.value(keys.at(i))->texture->Release(); qDeleteAll(font_textures); qDeleteAll(font_cache); font_textures.clear(); font_cache.clear(); current_cache = 0;}void QD3DGlyphCache::fontEngineDestroyed(QObject *object){// qDebug() << "=> font engine destroyed: " << object; QFontEngine *engine = static_cast<QFontEngine *>(object); QD3DFontGlyphHash::iterator cache_it = font_cache.find(engine); if (cache_it != font_cache.end()) { QD3DGlyphHash *cache = font_cache.take(engine); delete cache; } quint64 font_key = reinterpret_cast<quint64>(engine); QD3DFontTexture *tex = font_textures.take(font_key); if (tex) { tex->texture->Release(); delete tex; }}QImage QD3DGlyphCache::clearTypeGlyph(QFontEngine *engine, glyph_t glyph){ glyph_metrics_t gm = engine->boundingBox(glyph); int glyph_x = qFloor(gm.x.toReal()); int glyph_y = qFloor(gm.y.toReal()); int glyph_width = qCeil((gm.x + gm.width).toReal()) - glyph_x + 2; int glyph_height = qCeil((gm.y + gm.height).toReal()) - glyph_y + 2; if (glyph_width + glyph_x <= 0 || glyph_height <= 0) return QImage(); QImage im(glyph_width + glyph_x, glyph_height, QImage::Format_ARGB32_Premultiplied); im.fill(0xff000000); // solid black QPainter p(&im); p.setPen(Qt::white); p.setBrush(Qt::NoBrush); QTextItemInt ti; ti.ascent = engine->ascent(); ti.descent = engine->descent(); ti.width = glyph_width; ti.fontEngine = engine; ti.num_glyphs = 1; QGlyphLayout glyphLayout; ti.glyphs = &glyphLayout; glyphLayout.glyph = glyph; memset(&glyphLayout.attributes, 0, sizeof(glyphLayout.attributes)); glyphLayout.advance.x = glyph_width; p.drawTextItem(QPointF(-glyph_x, -glyph_y), ti); p.end(); return im;}#if 0static void dump_font_texture(QD3DFontTexture *tex){ QColor color(Qt::red); D3DLOCKED_RECT rect; if (FAILED(tex->texture->LockRect(0, &rect, 0, 0))) { qDebug() << "debug: unable to lock texture rect."; return; }// cleartype version// uint *tex_data = (uint *) rect.pBits;// QImage im(tex->width, tex->height, QImage::Format_ARGB32);// for (int y=0; y<tex->height; ++y) {// for (int x=0; x<tex->width; ++x) {// im.setPixel(x, y, ((*(tex_data+x+y*tex->width))));// }// } uchar *tex_data = (uchar *) rect.pBits; QImage im(rect.Pitch, tex->height, QImage::Format_ARGB32); for (int y=0; y<tex->height; ++y) { for (int x=0; x<rect.Pitch; ++x) { uchar val = ((*(tex_data+x+y*rect.Pitch))); im.setPixel(x, y, 0xff000000 | (val << 16) | (val << 8) | val); } } tex->texture->UnlockRect(0); static int i= 0; im.save(QString("tx%1.png").arg(i++));}#endifvoid QD3DGlyphCache::cacheGlyphs(QDirect3DPaintEngine *engine, const QTextItemInt &ti, const QVarLengthArray<glyph_t> &glyphs, bool clearType){ IDirect3DDevice9 *device = engine->d_func()->m_d3d_device; QD3DFontGlyphHash::const_iterator cache_it = font_cache.constFind(ti.fontEngine); QD3DGlyphHash *cache = 0; if (cache_it == font_cache.constEnd()) { cache = new QD3DGlyphHash; font_cache.insert(ti.fontEngine, cache); connect(ti.fontEngine, SIGNAL(destroyed(QObject *)), SLOT(fontEngineDestroyed(QObject *))); } else { cache = cache_it.value(); } current_cache = cache; D3DFORMAT tex_format = clearType ? D3DFMT_A8R8G8B8 : D3DFMT_A8; quint64 font_key = reinterpret_cast<quint64>(ti.fontEngine); QD3DFontTexHash::const_iterator it = font_textures.constFind(font_key); QD3DFontTexture *font_tex = 0; if (it == font_textures.constEnd()) { // alloc a new texture, put it into the cache int tex_height = qCeil(ti.ascent.toReal() + ti.descent.toReal()) + 5; int tex_width = tex_height * 30; // ### IDirect3DTexture9 *tex; if (FAILED(device->CreateTexture(tex_width, tex_height, 1, 0, tex_format, D3DPOOL_MANAGED, &tex, NULL))) { qWarning("QD3DGlyphCache::cacheGlyphs(): can't allocate font texture (%dx%d).", tex_width, tex_height); return; } else {// qDebug() << "=> new font texture: " << QSize(tex_width,tex_height); font_tex = new QD3DFontTexture; font_tex->texture = tex; font_tex->x_offset = 0; font_tex->y_offset = 0; font_tex->width = tex_width; font_tex->height = tex_height; font_textures.insert(font_key, font_tex); } } else { font_tex = it.value(); // make it current render target.. } // cache each glyph for (int i=0; i<glyphs.size(); ++i) { QD3DGlyphHash::const_iterator it = cache->constFind(glyphs[i]); if (it == cache->constEnd()) { glyph_metrics_t metrics = ti.fontEngine->boundingBox(glyphs[i]); int glyph_width = qCeil(metrics.width.toReal()) + 5; int glyph_height = qCeil(ti.ascent.toReal() + ti.descent.toReal()) + 5; if (font_tex->x_offset + glyph_width > font_tex->width) { // no room on the current line, start new glyph strip int strip_height = glyph_height; font_tex->x_offset = 0; font_tex->y_offset += strip_height; if (font_tex->y_offset >= font_tex->height) { // if no room in the current texture - realloc a larger texture int old_tex_height = font_tex->height; font_tex->height += strip_height; IDirect3DTexture9 *new_tex; if (FAILED(device->CreateTexture(font_tex->width, font_tex->height, 1, 0, tex_format, D3DPOOL_MANAGED, &new_tex, NULL))) { qWarning("QD3DGlyphCache(): can't re-allocate font texture."); return; } else {// qDebug() << " -> new glyph strip added:" << QSize(font_tex->width,font_tex->height); D3DLOCKED_RECT new_rect, old_rect; if (FAILED(font_tex->texture->LockRect(0, &old_rect, 0, D3DLOCK_READONLY))) { qDebug() << "QD3DGlyphCache: unable to lock texture rect."; return; } if (FAILED(new_tex->LockRect(0, &new_rect, 0, 0))) { qDebug() << "QD3DGlyphCache: unable to lock texture rect."; return; } memcpy(new_rect.pBits, old_rect.pBits, new_rect.Pitch * old_tex_height); font_tex->texture->UnlockRect(0); new_tex->UnlockRect(0); engine->d_func()->flushBatch(); font_tex->texture->Release(); font_tex->texture = new_tex; } // update the texture coords and the y offset for the existing glyphs in // the cache, because of the texture size change QD3DGlyphHash::iterator it = cache->begin(); while (it != cache->end()) { it.value()->height = (it.value()->height * old_tex_height) / font_tex->height; it.value()->y = (it.value()->y * old_tex_height) / font_tex->height; ++it; } } } QD3DGlyphCoord *d3d_glyph = new QD3DGlyphCoord; d3d_glyph->x = qreal(font_tex->x_offset) / font_tex->width; d3d_glyph->y = qreal(font_tex->y_offset) / font_tex->height; d3d_glyph->width = qreal(glyph_width) / font_tex->width; d3d_glyph->height = qreal(glyph_height) / font_tex->height; d3d_glyph->log_width = d3d_glyph->width * font_tex->width; d3d_glyph->log_height = d3d_glyph->height * font_tex->height; d3d_glyph->x_offset = -metrics.x; d3d_glyph->y_offset = metrics.y; QImage glyph_im; if (clearType) glyph_im = clearTypeGlyph(ti.fontEngine, glyphs[i]); else glyph_im = ti.fontEngine->alphaMapForGlyph(glyphs[i]).convertToFormat(QImage::Format_Indexed8); // write glyph to texture D3DLOCKED_RECT rect; RECT glyph_rect = { font_tex->x_offset, font_tex->y_offset, font_tex->x_offset + glyph_im.width(), font_tex->y_offset + glyph_im.height() };// qDebug() << " > new glyph char added:" << QSize(glyph_im.width(), glyph_im.height()); if (FAILED(font_tex->texture->LockRect(0, &rect, &glyph_rect, 0))) { qDebug() << "QD3DGlyphCache: unable to lock texture rect."; return; } // ### unify these loops if (clearType) { int ppl = rect.Pitch / 4; uint *tex_data = (uint *) rect.pBits; for (int y=0; y<glyph_im.height(); ++y) { uint *s = (uint *) glyph_im.scanLine(y); for (int x=0; x<glyph_im.width(); ++x) { tex_data[ppl*y + x] = *s; ++s; } } } else { int ppl = rect.Pitch; uchar *tex_data = (uchar *) rect.pBits; for (int y=0; y<glyph_im.height(); ++y) { uchar *s = (uchar *) glyph_im.scanLine(y); for (int x=0; x<glyph_im.width(); ++x) { tex_data[ppl*y + x] = *s; ++s; } } } font_tex->texture->UnlockRect(0); // debug// dump_font_texture(font_tex); if (font_tex->x_offset + glyph_width > font_tex->width) { font_tex->x_offset = 0; font_tex->y_offset += glyph_height; } else { font_tex->x_offset += glyph_width; } cache->insert(glyphs[i], d3d_glyph); } }}Q_GLOBAL_STATIC(QD3DGlyphCache, qd3d_glyph_cache)//// end font caching stuff////// D3D image cache stuff//// ### keep the GL stuff in mind..typedef void (*_qt_image_cleanup_hook_64)(qint64);extern Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64;static void qd3d_image_cleanup(qint64 key);class QD3DImage{public: QD3DImage(IDirect3DDevice9 *device, const QImage &image); ~QD3DImage(); IDirect3DTexture9 *texture;};static QList<IDirect3DTexture9 *> qd3d_release_list;QD3DImage::QD3DImage(IDirect3DDevice9 *device, const QImage &image){ texture = 0; Q_ASSERT(device); QImage im = image.convertToFormat(QImage::Format_ARGB32); if (FAILED(device->CreateTexture(im.width(), im.height(), 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &texture, 0))) { qWarning("QD3DImage(): unable to create Direct3D texture."); return; }// qDebug(" -> created image texture: %p - 0x%08x%08x",texture,uint (image.cacheKey() >> 32),uint (image.cacheKey() & 0xffffffff)); D3DLOCKED_RECT rect; if (FAILED(texture->LockRect(0, &rect, 0, 0))) { qDebug() << "QD3DImage: unable to lock texture rect."; return; } DWORD *dst = (DWORD *) rect.pBits; DWORD *src = (DWORD *) im.scanLine(0); Q_ASSERT((rect.Pitch/4) == (im.bytesPerLine()/4)); memcpy(dst, src, rect.Pitch*im.height()); texture->UnlockRect(0);}QD3DImage::~QD3DImage(){ if (texture) qd3d_release_list.append(texture);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -