123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700 |
- /*
- 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();
- }
|