diff options
Diffstat (limited to 'Src/Plugins/Visualization/vis_milk2/textmgr.cpp')
-rw-r--r-- | Src/Plugins/Visualization/vis_milk2/textmgr.cpp | 700 |
1 files changed, 700 insertions, 0 deletions
diff --git a/Src/Plugins/Visualization/vis_milk2/textmgr.cpp b/Src/Plugins/Visualization/vis_milk2/textmgr.cpp new file mode 100644 index 00000000..12fe540b --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/textmgr.cpp @@ -0,0 +1,700 @@ +/* + LICENSE + ------- +Copyright 2005-2013 Nullsoft, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of Nullsoft nor the names of its contributors may be used to + endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "textmgr.h" +#include "support.h" +#include "utility.h" + +#define MAX_MSG_CHARS (65536*2) +#define SafeRelease(x) { if (x) {x->Release(); x=NULL;} } +wchar_t g_szMsgPool[2][MAX_MSG_CHARS]; + +/* + NOTES ON CTextManager + + *** -desktop mode was SLOOOW when songtitles are on!, esp. since anim. songtitles... + -> decided to cache output of ID3DXFont by rendering to a (vidmem) texture, + ** only when things change. ** That became CTextManager. + -uses GDI-based ID3DXFont to draw text to a 2nd (VIDEO MEMORY) surface, + but each frame, it only draws what is necessary (what's changed + since last frame). It then blits that image (additively) to + the back buffer each frame. (note that dark boxes wouldn't work + w/additive drawing, since they're black, so those have to be + manually drawn (as black boxes) by the plugin shell, AS WELL AS + entered into the CTextManager queue as dark boxes, to handle + erasure, dirty rectangles, etc.) + + PROS/CONS: + (+) Supports all GDI features: italics, kerning, international fonts, formatting, &, etc. + (-) takes a lot of memory + (-) if texture can't be created @ proper size, fonts will appear too big + -> so don't use texture at all, in that case. + -> at least this way it will work well on all newer cards [w/memory] + (-) it's still going to crawl *when the text changes*, + because d3dx will upload textures to vidmem & blit them *once for each change*. + + OTHER CONCERNS/KIV: + -what if m_lpDDSText can't be created @ actual size of window? + If it's bigger, that's ok; but if it's smaller, that should result + in a clipped area for the text - hmm.... +*/ + +CTextManager::CTextManager() +{ +} + +CTextManager::~CTextManager() +{ +} + +void CTextManager::Init(LPDIRECT3DDEVICE9 lpDevice, IDirect3DTexture9* lpTextSurface, int bAdditive) +{ + m_lpDevice = lpDevice; + m_lpTextSurface = lpTextSurface; + m_blit_additively = bAdditive; + + m_b = 0; + m_nMsg[0] = 0; + m_nMsg[1] = 0; + m_next_msg_start_ptr = g_szMsgPool[m_b]; +} + +void CTextManager::Finish() +{ +} + +void CTextManager::ClearAll() +{ + m_nMsg[m_b] = 0; + m_next_msg_start_ptr = g_szMsgPool[m_b]; +} + +void CTextManager::DrawBox(LPRECT pRect, DWORD boxColor) +{ + if (!pRect) + return; + + if ((m_nMsg[m_b] < MAX_MSGS) && + (DWORD)m_next_msg_start_ptr - (DWORD)g_szMsgPool[m_b] + 0 + 1 < MAX_MSG_CHARS) + { + *m_next_msg_start_ptr = 0; + + m_msg[m_b][m_nMsg[m_b]].msg = m_next_msg_start_ptr; + m_msg[m_b][m_nMsg[m_b]].pfont = NULL; + m_msg[m_b][m_nMsg[m_b]].rect = *pRect; + m_msg[m_b][m_nMsg[m_b]].flags = 0; + m_msg[m_b][m_nMsg[m_b]].color = 0xFFFFFFFF; + m_msg[m_b][m_nMsg[m_b]].bgColor = boxColor; + m_nMsg[m_b]++; + m_next_msg_start_ptr += 1; + } +} + +int CTextManager::DrawText(LPD3DXFONT pFont, char* szText, RECT* pRect, DWORD flags, DWORD color, bool bBox, DWORD boxColor) +{ + // these aren't supported by D3DX9: + flags &= ~(DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX); + + if (!(pFont && pRect && szText)) + return 0; + + if (flags & DT_CALCRECT) + return pFont->DrawText(NULL, szText, -1, pRect, flags, color); + + if (!m_lpDevice /*|| !m_lpTextSurface*/) + return 0; + + int len = strlen(szText); + + if ((m_nMsg[m_b] < MAX_MSGS) && + (DWORD)m_next_msg_start_ptr - (DWORD)g_szMsgPool[m_b] + len + 1 < MAX_MSG_CHARS) + { + wcscpy(m_next_msg_start_ptr, AutoWide(szText)); + + m_msg[m_b][m_nMsg[m_b]].msg = m_next_msg_start_ptr; + m_msg[m_b][m_nMsg[m_b]].pfont = pFont; + m_msg[m_b][m_nMsg[m_b]].rect = *pRect; + m_msg[m_b][m_nMsg[m_b]].flags = flags; + m_msg[m_b][m_nMsg[m_b]].color = color; + m_msg[m_b][m_nMsg[m_b]].bgColor = boxColor; + + // shrink rects on new frame's text strings; important for deletions + int h = pFont->DrawText(NULL, szText, len, &m_msg[m_b][m_nMsg[m_b]].rect, flags | DT_CALCRECT, color); + + m_nMsg[m_b]++; + m_next_msg_start_ptr += len + 1; + + if (bBox) + { + // adds a message with no text, but the rect is the same as the text, so it creates a black box + DrawBox(&m_msg[m_b][m_nMsg[m_b]-1].rect, boxColor); + // now swap it with the text that precedes it, so it draws first, and becomes a background + td_string x = m_msg[m_b][m_nMsg[m_b]-1]; + m_msg[m_b][m_nMsg[m_b]-1] = m_msg[m_b][m_nMsg[m_b]-2]; + m_msg[m_b][m_nMsg[m_b]-2] = x; + } + return h; + } + + // no room for more text? ok, but still return accurate info: + RECT r2 = *pRect; + int h = pFont->DrawText(NULL, szText, len, &r2, flags | DT_CALCRECT, color); + return h; +} + +int CTextManager::DrawTextW(LPD3DXFONT pFont, wchar_t* szText, RECT* pRect, DWORD flags, DWORD color, bool bBox, DWORD boxColor) +{ + // these aren't supported by D3DX9: + flags &= ~(DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX); + + if (!(pFont && pRect && szText)) + return 0; + + if (flags & DT_CALCRECT) + return pFont->DrawTextW(NULL, szText, -1, pRect, flags, color); + + if (!m_lpDevice /*|| !m_lpTextSurface*/) + return 0; + + int len = wcslen(szText); + + if ((m_nMsg[m_b] < MAX_MSGS) && + (DWORD)m_next_msg_start_ptr - (DWORD)g_szMsgPool[m_b] + len + 1 < MAX_MSG_CHARS) + { + wcscpy(m_next_msg_start_ptr, szText); + + m_msg[m_b][m_nMsg[m_b]].msg = m_next_msg_start_ptr; + m_msg[m_b][m_nMsg[m_b]].pfont = pFont; + m_msg[m_b][m_nMsg[m_b]].rect = *pRect; + m_msg[m_b][m_nMsg[m_b]].flags = flags; + m_msg[m_b][m_nMsg[m_b]].color = color; + m_msg[m_b][m_nMsg[m_b]].bgColor = boxColor; + + // shrink rects on new frame's text strings; important for deletions + int h = pFont->DrawTextW(NULL, szText, len, &m_msg[m_b][m_nMsg[m_b]].rect, flags | DT_CALCRECT, color); + + m_nMsg[m_b]++; + m_next_msg_start_ptr += len + 1; + + if (bBox) + { + // adds a message with no text, but the rect is the same as the text, so it creates a black box + DrawBox(&m_msg[m_b][m_nMsg[m_b]-1].rect, boxColor); + // now swap it with the text that precedes it, so it draws first, and becomes a background + td_string x = m_msg[m_b][m_nMsg[m_b]-1]; + m_msg[m_b][m_nMsg[m_b]-1] = m_msg[m_b][m_nMsg[m_b]-2]; + m_msg[m_b][m_nMsg[m_b]-2] = x; + } + return h; + } + + // no room for more text? ok, but still return accurate info: + RECT r2 = *pRect; + int h = pFont->DrawTextW(NULL, szText, len, &r2, flags | DT_CALCRECT, color); + return h; +} + +#define MATCH(i,j) ( m_msg[m_b][i].pfont == m_msg[1-m_b][j].pfont && \ + m_msg[m_b][i].flags == m_msg[1-m_b][j].flags && \ + m_msg[m_b][i].color == m_msg[1-m_b][j].color && \ + m_msg[m_b][i].bgColor == m_msg[1-m_b][j].bgColor && \ + memcmp(&m_msg[m_b][i].rect, &m_msg[1-m_b][j].rect, sizeof(RECT))==0 && \ + wcscmp(m_msg[m_b][i].msg, m_msg[1-m_b][j].msg)==0 ) + +void CTextManager::DrawNow() +{ + if (!m_lpDevice) + return; + + if (m_nMsg[m_b] > 0 || m_nMsg[1-m_b] > 0) // second condition req'd for clearing text in VJ mode + { + D3DXMATRIX Ortho2D; + pMatrixOrthoLH(&Ortho2D, 2.0f, -2.0f, 0.0f, 1.0f); + m_lpDevice->SetTransform(D3DTS_PROJECTION, &Ortho2D); + + #define NUM_DIRTY_RECTS 3 + RECT dirty_rect[NUM_DIRTY_RECTS]; + int dirty_rects_ready = 0; + + int bRTT = (m_lpTextSurface==NULL) ? 0 : 1; + LPDIRECT3DSURFACE9 pBackBuffer=NULL;//, pZBuffer=NULL; + D3DSURFACE_DESC desc_backbuf, desc_text_surface; + + // clear added/deleted flags + void* last_dark_box = NULL; + for (int i=0; i<m_nMsg[m_b]; i++) + { + m_msg[m_b][i].deleted = m_msg[m_b][i].added = 0; + m_msg[m_b][i].prev_dark_box_ptr = last_dark_box; + last_dark_box = (m_msg[m_b][i].pfont) ? last_dark_box : (void*)&m_msg[m_b][i]; + } + last_dark_box = NULL; + int j = 0; + for (j = 0; j<m_nMsg[1-m_b]; j++) + { + m_msg[1-m_b][j].deleted = m_msg[1-m_b][j].added = 0; + m_msg[1-m_b][j].prev_dark_box_ptr = last_dark_box; + last_dark_box = (m_msg[1-m_b][j].pfont) ? last_dark_box : (void*)&m_msg[1-m_b][j]; + } + + int bRedrawText = 0; + if (!bRTT || (m_nMsg[m_b]>0 && m_nMsg[1-m_b]==0)) + { + bRedrawText = 2; // redraw ALL + } + else + { + // try to synchronize the text strings from last frame + this frame, + // and label additions & deletions. algorithm will catch: + // -insertion of any # of items in one spot + // -deletion of any # of items from one spot + // -changes to 1 item + // -changes to 2 consecutive items + // (provided that the 2 text strings immediately bounding the + // additions/deletions/change(s) are left unchanged.) + // in any other case, all the text is just re-rendered. + + int i = 0; + int j = 0; + while (i < m_nMsg[m_b] && j < m_nMsg[1-m_b]) + { + // MATCH macro: first idx is record # for current stuff; second idx is record # for prev frame stuff. + if (MATCH(i,j)) + { + i++; + j++; + } + else + { + int continue_now = 0; + + // scan to see if something was added: + for (int i2=i+1; i2<m_nMsg[m_b]; i2++) + if (MATCH(i2,j)) + { + for (int i3=i; i3<i2; i3++) + m_msg[m_b][i3].added = 1; + i = i2; + bRedrawText = 1; + continue_now = 1; + break; + } + if (continue_now) + continue; + + // scan to see if something was deleted: + for (int j2=j+1; j2<m_nMsg[1-m_b]; j2++) + if (MATCH(i,j2)) + { + for (int j3=j; j3<j2; j3++) + m_msg[1-m_b][j3].deleted = 1; + j = j2; + bRedrawText = 1; + continue_now = 1; + break; + } + if (continue_now) + continue; + + // scan to see if just a small group of 1-4 items were changed + // [and are followed by two identical items again] + int break_now = 0; + for (int chgd=1; chgd<=4; chgd++) + { + if (i>=m_nMsg[m_b]-chgd || j>=m_nMsg[1-m_b]-chgd) + { + // only a few items left in one of the lists -> just finish it + bRedrawText = 1; + break_now = 1; + break; + } + if (i<m_nMsg[m_b]-chgd && j<m_nMsg[1-m_b]-chgd && MATCH(i+chgd, j+chgd)) + { + for (int k=0; k<chgd; k++) + { + m_msg[ m_b][i+k].added = 1; + m_msg[1-m_b][j+k].deleted = 1; + } + i += chgd; + j += chgd; + + bRedrawText = 1; + continue_now = 1; + break; + } + } + if (break_now) + break; + if (continue_now) + continue; + + // otherwise, nontrivial case -> just re-render whole thing + bRedrawText = 2; // redraw ALL + break; + } + } + + if (bRedrawText < 2) + { + while (i < m_nMsg[m_b]) + { + m_msg[m_b][i].added = 1; + bRedrawText = 1; + i++; + } + + while (j < m_nMsg[1-m_b]) + { + m_msg[1-m_b][j].deleted = 1; + bRedrawText = 1; + j++; + } + } + } + + // ------------------------------------------------------------ + + // 0. remember old render target & get surface descriptions + m_lpDevice->GetRenderTarget( 0, &pBackBuffer ); + pBackBuffer->GetDesc(&desc_backbuf); + + if (bRTT) + { + //if (m_lpDevice->GetDepthStencilSurface( &pZBuffer ) != D3D_OK) + // pZBuffer = NULL; // ok if return val != D3D_OK - just means there is no zbuffer. + if (m_lpTextSurface->GetLevelDesc(0, &desc_text_surface) != D3D_OK) + bRTT = 0; + + m_lpDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + m_lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + m_lpDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT ); + m_lpDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE ); + + m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); + m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); + m_lpDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); + + m_lpDevice->SetRenderState( D3DRS_ZENABLE, FALSE ); + } + else + { + desc_text_surface = desc_backbuf; + } + + if (bRTT && bRedrawText) + do + { + // 1. change render target + m_lpDevice->SetTexture(0, NULL); + + IDirect3DSurface9* pNewTarget = NULL; + if (m_lpTextSurface->GetSurfaceLevel(0, &pNewTarget) != D3D_OK) + { + bRTT = 0; + break; + } + if (m_lpDevice->SetRenderTarget(0, pNewTarget) != D3D_OK) + { + pNewTarget->Release(); + bRTT = 0; + break; + } + //m_lpDevice->SetDepthStencilSurface( ??? ); + pNewTarget->Release(); + + m_lpDevice->SetTexture(0, NULL); + + // 2. clear to black + //m_lpDevice->SetTexture(0, NULL); + m_lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + m_lpDevice->SetVertexShader( NULL ); + m_lpDevice->SetFVF( WFVERTEX_FORMAT ); + m_lpDevice->SetPixelShader( NULL ); + WFVERTEX v3[4]; + if (bRedrawText==2) + { + DWORD clearcolor = m_msg[m_b][j].bgColor;//0xFF000000;// | ((rand()%32)<<16) | ((rand()%32)<<8) | ((rand()%32)); + int i = 0; + for (i=0; i<4; i++) + { + v3[i].x = -1.0f + 2.0f*(i%2); + v3[i].y = -1.0f + 2.0f*(i/2); + v3[i].z = 0; + v3[i].Diffuse = clearcolor; + } + m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v3, sizeof(WFVERTEX)); + } + else + { + // 1. erase (draw black box over) any old text items deleted. + // also, update the dirty rects; stuff that was ABOVE/BELOW these guys will need redrawn! + // (..picture them staggered) + int j = 0; + for (j=0; j<m_nMsg[1-m_b]; j++) + { + // erase text from PREV frame if it was deleted. + if (m_msg[1-m_b][j].deleted) + { + float x0 = -1.0f + 2.0f*m_msg[1-m_b][j].rect.left/(float)desc_text_surface.Width; + float x1 = -1.0f + 2.0f*m_msg[1-m_b][j].rect.right/(float)desc_text_surface.Width; + float y0 = -1.0f + 2.0f*m_msg[1-m_b][j].rect.top/(float)desc_text_surface.Height; + float y1 = -1.0f + 2.0f*m_msg[1-m_b][j].rect.bottom/(float)desc_text_surface.Height; + int i = 0; + for (i=0; i<4; i++) + { + v3[i].x = (i%2) ? x0 : x1; + v3[i].y = (i/2) ? y0 : y1; + v3[i].z = 0; + v3[i].Diffuse = m_msg[m_b][j].bgColor;//0xFF000000;//0xFF300000; + } + m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v3, sizeof(WFVERTEX)); + + //---------------------------------- + + // special case: + // if something is erased, but it's totally inside a dark box, + // then don't add it to the dirty rectangle. + td_string* pDarkBox = (td_string*)m_msg[1-m_b][j].prev_dark_box_ptr; + int add_to_dirty_rect = 1; + while (pDarkBox && add_to_dirty_rect) + { + RECT t; + UnionRect(&t, &pDarkBox->rect, &m_msg[1-m_b][j].rect); + if (EqualRect(&t, &pDarkBox->rect)) + add_to_dirty_rect = 0; + pDarkBox = (td_string*)pDarkBox->prev_dark_box_ptr; + } + + // also, update dirty rects + // first, check to see if this shares area or a border w/any of the going dirty rects, + // and if so, expand that dirty rect. + if (add_to_dirty_rect) + { + int done = 0; + RECT t; + RECT r1 = m_msg[1-m_b][j].rect; + RECT r2 = m_msg[1-m_b][j].rect; + r2.top -= 1; + r2.left -= 1; + r2.right += 1; + r2.bottom += 1; + for (i=0; i<dirty_rects_ready; i++) + { + if (IntersectRect(&t, &r2, &dirty_rect[i])) + { + // expand the dirty rect to include r1 + UnionRect(&t, &r1, &dirty_rect[i]); + dirty_rect[i] = t; + done = 1; + break; + } + } + if (done==1) continue; + + // if it's in a new spot, and there are still unused dirty rects, use those + if (dirty_rects_ready < NUM_DIRTY_RECTS) + { + dirty_rect[dirty_rects_ready] = r1; + dirty_rects_ready++; + continue; + } + + // otherwise, find the closest dirty rect... + float nearest_dist; + int nearest_id; + for (i=0; i<NUM_DIRTY_RECTS; i++) + { + int dx=0, dy=0; + + if (r1.left > dirty_rect[i].right) + dx = r1.left - dirty_rect[i].right; + else if (dirty_rect[i].left > r1.right) + dx = dirty_rect[i].left - r1.right; + + if (r1.top > dirty_rect[i].bottom) + dy = r1.top - dirty_rect[i].bottom; + else if (dirty_rect[i].top > r1.bottom) + dy = dirty_rect[i].top - r1.bottom; + + float dist = sqrtf((float)(dx*dx + dy*dy)); + if (i==0 || dist < nearest_dist) + { + nearest_dist = dist; + nearest_id = i; + } + } + //...and expand it to include this one. + UnionRect(&t, &r1, &dirty_rect[nearest_id]); + dirty_rect[nearest_id] = t; + } + } + } + + // 2. erase AND REDRAW any of *this* frame's text that falls in dirty rects + // from erasures of *prev* frame's deleted text: + for (j=0; j<m_nMsg[m_b]; j++) + { + RECT t; + // note: none of these could be 'deleted' status yet. + if (!m_msg[m_b][j].added) + { + // check vs. dirty rects so far; if intersects any, erase + redraw this one. + for (int i=0; i<dirty_rects_ready; i++) + if (m_msg[m_b][j].pfont && // exclude dark boxes... //fixme? + IntersectRect(&t, &dirty_rect[i], &m_msg[m_b][j].rect)) + { + float x0 = -1.0f + 2.0f*m_msg[m_b][j].rect.left/(float)desc_text_surface.Width; + float x1 = -1.0f + 2.0f*m_msg[m_b][j].rect.right/(float)desc_text_surface.Width; + float y0 = -1.0f + 2.0f*m_msg[m_b][j].rect.top/(float)desc_text_surface.Height; + float y1 = -1.0f + 2.0f*m_msg[m_b][j].rect.bottom/(float)desc_text_surface.Height; + for (int i=0; i<4; i++) + { + v3[i].x = (i%2) ? x0 : x1; + v3[i].y = (i/2) ? y0 : y1; + v3[i].z = 0; + v3[i].Diffuse = m_msg[m_b][j].bgColor;//0xFF000000;//0xFF000030; + } + m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v3, sizeof(WFVERTEX)); + + m_msg[m_b][j].deleted = 1; + m_msg[m_b][j].added = 1; + bRedrawText = 1; + } + } + } + } + } + while (0); + + // 3. render text to TEXT surface + if (bRedrawText) + { + m_lpDevice->SetTexture(0, NULL); + m_lpDevice->SetTexture(1, NULL); + m_lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + m_lpDevice->SetVertexShader( NULL ); + m_lpDevice->SetPixelShader( NULL ); + m_lpDevice->SetFVF( WFVERTEX_FORMAT ); + + for (int i=0; i<m_nMsg[m_b]; i++) + if (bRedrawText==2 || m_msg[m_b][i].added==1) + if (m_msg[m_b][i].pfont) // dark boxes have pfont==NULL + // warning: in DX9, the DT_WORD_ELLIPSIS and DT_NOPREFIX flags cause no text to render!! + m_msg[m_b][i].pfont->DrawTextW(NULL, m_msg[m_b][i].msg, -1, &m_msg[m_b][i].rect, m_msg[m_b][i].flags, m_msg[m_b][i].color); + else if (m_msg[m_b][i].added || bRedrawText==2 || !bRTT) + { + WFVERTEX v3[4]; + float x0 = -1.0f + 2.0f*m_msg[m_b][i].rect.left/(float)desc_text_surface.Width; + float x1 = -1.0f + 2.0f*m_msg[m_b][i].rect.right/(float)desc_text_surface.Width; + float y0 = -1.0f + 2.0f*m_msg[m_b][i].rect.top/(float)desc_text_surface.Height; + float y1 = -1.0f + 2.0f*m_msg[m_b][i].rect.bottom/(float)desc_text_surface.Height; + for (int k=0; k<4; k++) + { + v3[k].x = (k%2) ? x0 : x1; + v3[k].y = (k/2) ? y0 : y1; + v3[k].z = 0; + v3[k].Diffuse = m_msg[m_b][i].bgColor;//0xFF303000; + } + m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v3, sizeof(WFVERTEX)); + } + } + + if (bRTT) + { + // 4. restore render target + if (bRedrawText) + { + m_lpDevice->SetTexture(0, NULL); + m_lpDevice->SetRenderTarget( 0, pBackBuffer );//, pZBuffer ); + //m_lpDevice->SetDepthStencilSurface( pZBuffer ); + } + + // 5. blit text surface to backbuffer + m_lpDevice->SetTexture(0, m_lpTextSurface); + m_lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, m_blit_additively ? TRUE : FALSE); + m_lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + m_lpDevice->SetRenderState(D3DRS_DESTBLEND, m_blit_additively ? D3DBLEND_ONE : D3DBLEND_ZERO); + m_lpDevice->SetVertexShader( NULL ); + m_lpDevice->SetPixelShader( NULL ); + m_lpDevice->SetFVF( SPRITEVERTEX_FORMAT ); + + SPRITEVERTEX v3[4]; + ZeroMemory(v3, sizeof(SPRITEVERTEX)*4); + float fx = desc_text_surface.Width / (float)desc_backbuf.Width ; + float fy = desc_text_surface.Height / (float)desc_backbuf.Height; + for (int i=0; i<4; i++) + { + v3[i].x = (i%2==0) ? -1 : -1 + 2*fx; + v3[i].y = (i/2==0) ? -1 : -1 + 2*fy; + v3[i].z = 0; + v3[i].tu = ((i%2==0) ? 0.0f : 1.0f) + 0.5f/desc_text_surface.Width; // FIXES BLURRY TEXT even when bilinear interp. is on (which can't be turned off on all cards!) + v3[i].tv = ((i/2==0) ? 0.0f : 1.0f) + 0.5f/desc_text_surface.Height; // FIXES BLURRY TEXT even when bilinear interp. is on (which can't be turned off on all cards!) + v3[i].Diffuse = 0xFFFFFFFF; + } + + DWORD oldblend[3]; + //m_lpDevice->GetTextureStageState(0, D3DTSS_MAGFILTER, &oldblend[0]); + //m_lpDevice->GetTextureStageState(1, D3DTSS_MINFILTER, &oldblend[1]); + //m_lpDevice->GetTextureStageState(2, D3DTSS_MIPFILTER, &oldblend[2]); + m_lpDevice->GetSamplerState(0, D3DSAMP_MAGFILTER, &oldblend[0]); + m_lpDevice->GetSamplerState(1, D3DSAMP_MINFILTER, &oldblend[1]); + m_lpDevice->GetSamplerState(2, D3DSAMP_MIPFILTER, &oldblend[2]); + m_lpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + m_lpDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_POINT); + m_lpDevice->SetSamplerState(2, D3DSAMP_MIPFILTER, D3DTEXF_POINT); + + m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v3, sizeof(SPRITEVERTEX)); + + m_lpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, oldblend[0]); + m_lpDevice->SetSamplerState(1, D3DSAMP_MINFILTER, oldblend[1]); + m_lpDevice->SetSamplerState(2, D3DSAMP_MIPFILTER, oldblend[2]); + + m_lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + } + + SafeRelease(pBackBuffer); + //SafeRelease(pZBuffer); + + m_lpDevice->SetTexture(0, NULL); + m_lpDevice->SetTexture(1, NULL); + m_lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + m_lpDevice->SetVertexShader( NULL ); + m_lpDevice->SetPixelShader( NULL ); + m_lpDevice->SetFVF( SPRITEVERTEX_FORMAT ); + + //D3DXMATRIX ident; + //D3DXMatrixIdentity(&ident); + //m_lpDevice->SetTransform(D3DTS_PROJECTION, &ident); + } + + // flip: + m_b = 1 - m_b; + + ClearAll(); +}
\ No newline at end of file |