RTS.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:62k
- /*
- * Copyright (C) 2003-2005 Gabest
- * http://www.gabest.org
- *
- * This Program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This Program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Make; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- */
- #include "stdafx.h"
- #include <math.h>
- #include <time.h>
- #include "RTS.h"
- // WARNING: this isn't very thread safe, use only one RTS a time.
- static HDC g_hDC;
- static int g_hDC_refcnt = 0;
- static long revcolor(long c)
- {
- return ((c&0xff0000)>>16) + (c&0xff00) + ((c&0xff)<<16);
- }
- //////////////////////////////////////////////////////////////////////////////////////////////
- // CMyFont
- CMyFont::CMyFont(STSStyle& style)
- {
- LOGFONT lf;
- memset(&lf, 0, sizeof(lf));
- lf <<= style;
- lf.lfHeight = (LONG)(style.fontSize+0.5);
- lf.lfOutPrecision = OUT_TT_PRECIS;
- lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
- lf.lfQuality = ANTIALIASED_QUALITY;
- lf.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
- lf.lfEscapement = lf.lfOrientation = 0;
- if(!CreateFontIndirect(&lf))
- {
- _tcscpy(lf.lfFaceName, _T("Arial"));
- CreateFontIndirect(&lf);
- }
- HFONT hOldFont = (HFONT)SelectObject(g_hDC, *this);
- TEXTMETRIC tm;
- BOOL b = GetTextMetrics(g_hDC, &tm);
- DWORD ret = GetLastError();
- m_ascent = ((tm.tmAscent + 4) >> 3);
- m_descent = ((tm.tmDescent + 4) >> 3);
- SelectObject(g_hDC, hOldFont);
- }
- // CWord
- CWord::CWord(STSStyle& style, CStringW str, int ktype, int kstart, int kend)
- : m_style(style), m_str(str)
- , m_width(0), m_ascent(0), m_descent(0)
- , m_ktype(ktype), m_kstart(kstart), m_kend(kend)
- , m_fDrawn(false), m_p(INT_MAX, INT_MAX)
- , m_fLineBreak(false), m_fWhiteSpaceChar(false)
- , m_pOpaqueBox(NULL)
- {
- if(str.IsEmpty())
- {
- m_fWhiteSpaceChar = m_fLineBreak = true;
- }
- CMyFont font(m_style);
- m_ascent = (int)(m_style.fontScaleY/100*font.m_ascent);
- m_descent = (int)(m_style.fontScaleY/100*font.m_descent);
- m_width = 0;
- }
- CWord::~CWord()
- {
- if(m_pOpaqueBox) delete m_pOpaqueBox;
- }
- bool CWord::Append(CWord* w)
- {
- if(!(m_style == w->m_style)
- || m_fLineBreak || w->m_fLineBreak
- || w->m_kstart != w->m_kend || m_ktype != w->m_ktype) return(false);
- m_fWhiteSpaceChar = m_fWhiteSpaceChar && w->m_fWhiteSpaceChar;
- m_str += w->m_str;
- m_width += w->m_width;
- m_fDrawn = false;
- m_p = CPoint(INT_MAX, INT_MAX);
- return(true);
- }
- void CWord::Paint(CPoint p, CPoint org)
- {
- if(!m_str) return;
- if(!m_fDrawn)
- {
- if(!CreatePath()) return;
- Transform(CPoint((org.x-p.x)*8, (org.y-p.y)*8));
- if(!ScanConvert()) return;
- if(m_style.borderStyle == 0 && m_style.outlineWidth > 0)
- {
- if(!CreateWidenedRegion((int)(m_style.outlineWidth+0.5))) return;
- }
- else if(m_style.borderStyle == 1)
- {
- if(!CreateOpaqueBox()) return;
- }
- m_fDrawn = true;
- if(!Rasterize(p.x&7, p.y&7, m_style.fBlur)) return;
- }
- else if((m_p.x&7) != (p.x&7) || (m_p.y&7) != (p.y&7))
- {
- Rasterize(p.x&7, p.y&7, m_style.fBlur);
- }
- m_p = p;
- if(m_pOpaqueBox)
- m_pOpaqueBox->Paint(p, org);
- }
- void CWord::Transform(CPoint org)
- {
- double scalex = m_style.fontScaleX/100;
- double scaley = m_style.fontScaleY/100;
- double caz = cos((3.1415/180)*m_style.fontAngleZ);
- double saz = sin((3.1415/180)*m_style.fontAngleZ);
- double cax = cos((3.1415/180)*m_style.fontAngleX);
- double sax = sin((3.1415/180)*m_style.fontAngleX);
- double cay = cos((3.1415/180)*m_style.fontAngleY);
- double say = sin((3.1415/180)*m_style.fontAngleY);
- for(int i = 0; i < mPathPoints; i++)
- {
- double x, y, z, xx, yy, zz;
- x = scalex * mpPathPoints[i].x - org.x;
- y = scaley * mpPathPoints[i].y - org.y;
- z = 0;
- xx = x*caz + y*saz;
- yy = -(x*saz - y*caz);
- zz = z;
- x = xx;
- y = yy*cax + zz*sax;
- z = yy*sax - zz*cax;
- xx = x*cay + z*say;
- yy = y;
- zz = x*say - z*cay;
- zz = max(zz, -19000);
- x = (xx * 20000) / (zz + 20000);
- y = (yy * 20000) / (zz + 20000);
- mpPathPoints[i].x = (LONG)(x + org.x + 0.5);
- mpPathPoints[i].y = (LONG)(y + org.y + 0.5);
- }
- }
- bool CWord::CreateOpaqueBox()
- {
- if(m_pOpaqueBox) return(true);
- STSStyle style = m_style;
- style.borderStyle = 0;
- style.outlineWidth = 0;
- style.colors[0] = m_style.colors[2];
- style.alpha[0] = m_style.alpha[2];
- int w = (int)(m_style.outlineWidth + 0.5);
- CStringW str;
- str.Format(L"m %d %d l %d %d %d %d %d %d",
- -w, -w,
- m_width+w, -w,
- m_width+w, m_ascent+m_descent+w,
- -w, m_ascent+m_descent+w);
- m_pOpaqueBox = new CPolygon(style, str, 0, 0, 0, 1.0/8, 1.0/8, 0);
- return(!!m_pOpaqueBox);
- }
- // CText
- CText::CText(STSStyle& style, CStringW str, int ktype, int kstart, int kend)
- : CWord(style, str, ktype, kstart, kend)
- {
- if(m_str.GetLength() == 1 && m_str[0] == ' ')
- {
- m_fWhiteSpaceChar = true;
- }
- CMyFont font(m_style);
- HFONT hOldFont = (HFONT)SelectObject(g_hDC, font);
- if(m_style.fontSpacing || (long)GetVersion() < 0)
- {
- bool bFirstPath = true;
- for(LPCWSTR s = m_str; *s; s++)
- {
- CSize extent;
- if(!GetTextExtentPoint32W(g_hDC, s, 1, &extent)) {SelectObject(g_hDC, hOldFont); ASSERT(0); return;}
- m_width += extent.cx + (int)m_style.fontSpacing;
- }
- // m_width -= (int)m_style.fontSpacing; // TODO: subtract only at the end of the line
- }
- else
- {
- CSize extent;
- if(!GetTextExtentPoint32W(g_hDC, m_str, wcslen(str), &extent)) {SelectObject(g_hDC, hOldFont); ASSERT(0); return;}
- m_width += extent.cx;
- }
- m_width = (int)(m_style.fontScaleX/100*m_width + 4) >> 3;
- SelectObject(g_hDC, hOldFont);
- }
- CWord* CText::Copy()
- {
- return(new CText(m_style, m_str, m_ktype, m_kstart, m_kend));
- }
- bool CText::Append(CWord* w)
- {
- return(dynamic_cast<CText*>(w) && CWord::Append(w));
- }
- bool CText::CreatePath()
- {
- CMyFont font(m_style);
- HFONT hOldFont = (HFONT)SelectObject(g_hDC, font);
- int width = 0;
- if(m_style.fontSpacing || (long)GetVersion() < 0)
- {
- bool bFirstPath = true;
- for(LPCWSTR s = m_str; *s; s++)
- {
- CSize extent;
- if(!GetTextExtentPoint32W(g_hDC, s, 1, &extent)) {SelectObject(g_hDC, hOldFont); ASSERT(0); return(false);}
- PartialBeginPath(g_hDC, bFirstPath); bFirstPath = false;
- TextOutW(g_hDC, 0, 0, s, 1);
- PartialEndPath(g_hDC, width, 0);
- width += extent.cx + (int)m_style.fontSpacing;
- }
- }
- else
- {
- CSize extent;
- if(!GetTextExtentPoint32W(g_hDC, m_str, m_str.GetLength(), &extent)) {SelectObject(g_hDC, hOldFont); ASSERT(0); return(false);}
- BeginPath(g_hDC);
- TextOutW(g_hDC, 0, 0, m_str, m_str.GetLength());
- EndPath(g_hDC);
- }
- SelectObject(g_hDC, hOldFont);
- return(true);
- }
- // CPolygon
- CPolygon::CPolygon(STSStyle& style, CStringW str, int ktype, int kstart, int kend, double scalex, double scaley, int baseline)
- : CWord(style, str, ktype, kstart, kend)
- , m_scalex(scalex), m_scaley(scaley), m_baseline(baseline)
- {
- ParseStr();
- }
- CPolygon::~CPolygon()
- {
- }
- CWord* CPolygon::Copy()
- {
- return(new CPolygon(m_style, m_str, m_ktype, m_kstart, m_kend, m_scalex, m_scaley, m_baseline));
- }
- bool CPolygon::Append(CWord* w)
- {
- int width = m_width;
- CPolygon* p = dynamic_cast<CPolygon*>(w);
- if(!p) return(false);
- // TODO
- return(false);
- return(true);
- }
- bool CPolygon::GetLONG(CStringW& str, LONG& ret)
- {
- LPWSTR s = (LPWSTR)(LPCWSTR)str, e = s;
- ret = wcstol(str, &e, 10);
- str = str.Mid(e - s);
- return(e > s);
- }
- bool CPolygon::GetPOINT(CStringW& str, POINT& ret)
- {
- return(GetLONG(str, ret.x) && GetLONG(str, ret.y));
- }
- bool CPolygon::ParseStr()
- {
- if(m_pathTypesOrg.GetSize() > 0) return(true);
- CPoint p;
- int i, j, lastsplinestart = -1, firstmoveto = -1, lastmoveto = -1;
- CStringW str = m_str;
- str.SpanIncluding(L"mnlbspc 0123456789");
- str.Replace(L"m", L"*m");
- str.Replace(L"n", L"*n");
- str.Replace(L"l", L"*l");
- str.Replace(L"b", L"*b");
- str.Replace(L"s", L"*s");
- str.Replace(L"p", L"*p");
- str.Replace(L"c", L"*c");
- int k = 0;
- for(CStringW s = str.Tokenize(L"*", k); !s.IsEmpty(); s = str.Tokenize(L"*", k))
- {
- WCHAR c = s[0];
- s.TrimLeft(L"mnlbspc ");
- switch(c)
- {
- case 'm':
- lastmoveto = m_pathTypesOrg.GetSize();
- if(firstmoveto == -1) firstmoveto = lastmoveto;
- while(GetPOINT(s, p)) {m_pathTypesOrg.Add(PT_MOVETO); m_pathPointsOrg.Add(p);}
- break;
- case 'n':
- while(GetPOINT(s, p)) {m_pathTypesOrg.Add(PT_MOVETONC); m_pathPointsOrg.Add(p);}
- break;
- case 'l':
- while(GetPOINT(s, p)) {m_pathTypesOrg.Add(PT_LINETO); m_pathPointsOrg.Add(p);}
- break;
- case 'b':
- j = m_pathTypesOrg.GetSize();
- while(GetPOINT(s, p)) {m_pathTypesOrg.Add(PT_BEZIERTO); m_pathPointsOrg.Add(p); j++;}
- j = m_pathTypesOrg.GetSize() - ((m_pathTypesOrg.GetSize()-j)%3);
- m_pathTypesOrg.SetSize(j); m_pathPointsOrg.SetSize(j);
- break;
- case 's':
- j = lastsplinestart = m_pathTypesOrg.GetSize();
- i = 3;
- while(i-- && GetPOINT(s, p)) {m_pathTypesOrg.Add(PT_BSPLINETO); m_pathPointsOrg.Add(p); j++;}
- if(m_pathTypesOrg.GetSize()-lastsplinestart < 3) {m_pathTypesOrg.SetSize(lastsplinestart); m_pathPointsOrg.SetSize(lastsplinestart); lastsplinestart = -1;}
- // no break here
- case 'p':
- while(GetPOINT(s, p)) {m_pathTypesOrg.Add(PT_BSPLINEPATCHTO); m_pathPointsOrg.Add(p); j++;}
- break;
- case 'c':
- if(lastsplinestart > 0)
- {
- m_pathTypesOrg.Add(PT_BSPLINEPATCHTO);
- m_pathTypesOrg.Add(PT_BSPLINEPATCHTO);
- m_pathTypesOrg.Add(PT_BSPLINEPATCHTO);
- p = m_pathPointsOrg[lastsplinestart-1]; // we need p for temp storage, because operator [] will return a reference to CPoint and Add() may reallocate its internal buffer (this is true for MFC 7.0 but not for 6.0, hehe)
- m_pathPointsOrg.Add(p);
- p = m_pathPointsOrg[lastsplinestart];
- m_pathPointsOrg.Add(p);
- p = m_pathPointsOrg[lastsplinestart+1];
- m_pathPointsOrg.Add(p);
- lastsplinestart = -1;
- }
- break;
- default:
- break;
- }
- }
- /*
- LPCWSTR str = m_str;
- while(*str)
- {
- while(*str && *str != 'm' && *str != 'n' && *str != 'l' && *str != 'b' && *str != 's' && *str != 'p' && *str != 'c') str++;
- if(!*str) break;
- switch(*str++)
- {
- case 'm':
- lastmoveto = m_pathTypesOrg.GetSize();
- if(firstmoveto == -1) firstmoveto = lastmoveto;
- while(GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_MOVETO); m_pathPointsOrg.Add(p);}
- break;
- case 'n':
- while(GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_MOVETONC); m_pathPointsOrg.Add(p);}
- break;
- case 'l':
- while(GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_LINETO); m_pathPointsOrg.Add(p);}
- break;
- case 'b':
- j = m_pathTypesOrg.GetSize();
- while(GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_BEZIERTO); m_pathPointsOrg.Add(p); j++;}
- j = m_pathTypesOrg.GetSize() - ((m_pathTypesOrg.GetSize()-j)%3);
- m_pathTypesOrg.SetSize(j); m_pathPointsOrg.SetSize(j);
- break;
- case 's':
- j = lastsplinestart = m_pathTypesOrg.GetSize();
- i = 3;
- while(i-- && GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_BSPLINETO); m_pathPointsOrg.Add(p); j++;}
- if(m_pathTypesOrg.GetSize()-lastsplinestart < 3) {m_pathTypesOrg.SetSize(lastsplinestart); m_pathPointsOrg.SetSize(lastsplinestart); lastsplinestart = -1;}
- // no break here
- case 'p':
- while(GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_BSPLINEPATCHTO); m_pathPointsOrg.Add(p); j++;}
- break;
- case 'c':
- if(lastsplinestart > 0)
- {
- m_pathTypesOrg.Add(PT_BSPLINEPATCHTO);
- m_pathTypesOrg.Add(PT_BSPLINEPATCHTO);
- m_pathTypesOrg.Add(PT_BSPLINEPATCHTO);
- p = m_pathPointsOrg[lastsplinestart-1]; // we need p for temp storage, because operator [] will return a reference to CPoint and Add() may reallocate its internal buffer (this is true for MFC 7.0 but not for 6.0, hehe)
- m_pathPointsOrg.Add(p);
- p = m_pathPointsOrg[lastsplinestart];
- m_pathPointsOrg.Add(p);
- p = m_pathPointsOrg[lastsplinestart+1];
- m_pathPointsOrg.Add(p);
- lastsplinestart = -1;
- }
- break;
- default:
- break;
- }
- if(firstmoveto > 0) break;
- }
- */
- if(lastmoveto == -1 || firstmoveto > 0)
- {
- m_pathTypesOrg.RemoveAll();
- m_pathPointsOrg.RemoveAll();
- return(false);
- }
- int minx = INT_MAX, miny = INT_MAX, maxx = -INT_MAX, maxy = -INT_MAX;
- for(i = 0; i < m_pathTypesOrg.GetSize(); i++)
- {
- m_pathPointsOrg[i].x = (int)(64 * m_scalex * m_pathPointsOrg[i].x);
- m_pathPointsOrg[i].y = (int)(64 * m_scaley * m_pathPointsOrg[i].y);
- if(minx > m_pathPointsOrg[i].x) minx = m_pathPointsOrg[i].x;
- if(miny > m_pathPointsOrg[i].y) miny = m_pathPointsOrg[i].y;
- if(maxx < m_pathPointsOrg[i].x) maxx = m_pathPointsOrg[i].x;
- if(maxy < m_pathPointsOrg[i].y) maxy = m_pathPointsOrg[i].y;
- }
- m_width = max(maxx - minx, 0);
- m_ascent = max(maxy - miny, 0);
- int baseline = (int)(64 * m_scaley * m_baseline);
- m_descent = baseline;
- m_ascent -= baseline;
- m_width = ((int)(m_style.fontScaleX/100 * m_width) + 4) >> 3;
- m_ascent = ((int)(m_style.fontScaleY/100 * m_ascent) + 4) >> 3;
- m_descent = ((int)(m_style.fontScaleY/100 * m_descent) + 4) >> 3;
- return(true);
- }
- bool CPolygon::CreatePath()
- {
- int len = m_pathTypesOrg.GetSize();
- if(len == 0) return(false);
- if(mPathPoints != len)
- {
- mpPathTypes = (BYTE*)realloc(mpPathTypes, len*sizeof(BYTE));
- mpPathPoints = (POINT*)realloc(mpPathPoints, len*sizeof(POINT));
- if(!mpPathTypes || !mpPathPoints) return(false);
- mPathPoints = len;
- }
- memcpy(mpPathTypes, m_pathTypesOrg.GetData(), len*sizeof(BYTE));
- memcpy(mpPathPoints, m_pathPointsOrg.GetData(), len*sizeof(POINT));
- return(true);
- }
- // CClipper
- CClipper::CClipper(CStringW str, CSize size, double scalex, double scaley)
- : CPolygon(STSStyle(), str, 0, 0, 0, scalex, scaley, 0)
- {
- m_size.cx = m_size.cy = 0;
- m_pAlphaMask = NULL;
- if(size.cx < 0 || size.cy < 0 || !(m_pAlphaMask = new BYTE[size.cx*size.cy])) return;
- m_size = size;
- memset(m_pAlphaMask, 0, size.cx*size.cy);
- Paint(CPoint(0, 0), CPoint(0, 0));
- int w = mOverlayWidth, h = mOverlayHeight;
- int x = (mOffsetX+4)>>3, y = (mOffsetY+4)>>3;
- int xo = 0, yo = 0;
- if(x < 0) {xo = -x; w -= -x; x = 0;}
- if(y < 0) {yo = -y; h -= -y; y = 0;}
- if(x+w > m_size.cx) w = m_size.cx-x;
- if(y+h > m_size.cy) h = m_size.cy-y;
- if(w <= 0 || h <= 0) return;
- const BYTE* src = mpOverlayBuffer + 2*(mOverlayWidth * yo + xo);
- BYTE* dst = m_pAlphaMask + m_size.cx * y + x;
- while(h--)
- {
- for(int wt=0; wt<w; ++wt)
- dst[wt] = src[wt*2];
- src += 2*mOverlayWidth;
- dst += m_size.cx;
- }
- }
- CClipper::~CClipper()
- {
- if(m_pAlphaMask) delete [] m_pAlphaMask;
- m_pAlphaMask = NULL;
- }
- CWord* CClipper::Copy()
- {
- return(new CClipper(m_str, m_size, m_scalex, m_scaley));
- }
- bool CClipper::Append(CWord* w)
- {
- return(false);
- }
- // CLine
- CLine::~CLine()
- {
- POSITION pos = GetHeadPosition();
- while(pos) delete GetNext(pos);
- }
- void CLine::Compact()
- {
- POSITION pos = GetHeadPosition();
- while(pos)
- {
- CWord* w = GetNext(pos);
- if(!w->m_fWhiteSpaceChar) break;
- m_width -= w->m_width;
- delete w;
- RemoveHead();
- }
- pos = GetTailPosition();
- while(pos)
- {
- CWord* w = GetPrev(pos);
- if(!w->m_fWhiteSpaceChar) break;
- m_width -= w->m_width;
- delete w;
- RemoveTail();
- }
- if(IsEmpty()) return;
- CLine l;
- l.AddTail(this);
- RemoveAll();
- CWord* last = NULL;
- pos = l.GetHeadPosition();
- while(pos)
- {
- CWord* w = l.GetNext(pos);
- if(!last || !last->Append(w))
- AddTail(last = w->Copy());
- }
- m_ascent = m_descent = m_border = 0;
- pos = GetHeadPosition();
- while(pos)
- {
- CWord* w = GetNext(pos);
- if(m_ascent < w->m_ascent) m_ascent = w->m_ascent;
- if(m_descent < w->m_descent) m_descent = w->m_descent;
- if(m_border < w->m_style.outlineWidth) m_border = (int)(w->m_style.outlineWidth+0.5);
- }
- }
- CRect CLine::PaintShadow(SubPicDesc& spd, CRect& clipRect, BYTE* pAlphaMask, CPoint p, CPoint org, int time, int alpha)
- {
- CRect bbox(0, 0, 0, 0);
- POSITION pos = GetHeadPosition();
- while(pos)
- {
- CWord* w = GetNext(pos);
- if(w->m_fLineBreak) return(bbox); // should not happen since this class is just a line of text without any breaks
- if(w->m_style.shadowDepth > 0)
- {
- int x = p.x + (int)(w->m_style.shadowDepth+0.5);
- int y = p.y + m_ascent - w->m_ascent + (int)(w->m_style.shadowDepth+0.5);
- DWORD a = 0xff - w->m_style.alpha[3];
- if(alpha > 0) a = MulDiv(a, 0xff - alpha, 0xff);
- COLORREF shadow = revcolor(w->m_style.colors[3]) | (a<<24);
- long sw[6] = {shadow, -1};
- w->Paint(CPoint(x, y), org);
- if(w->m_style.borderStyle == 0)
- {
- bbox |= w->Draw(spd, clipRect, pAlphaMask, x, y, sw,
- w->m_ktype > 0 || w->m_style.alpha[0] < 0xff,
- w->m_style.outlineWidth > 0 && !(w->m_ktype == 2 && time < w->m_kstart));
- }
- else if(w->m_style.borderStyle == 1 && w->m_pOpaqueBox)
- {
- bbox |= w->m_pOpaqueBox->Draw(spd, clipRect, pAlphaMask, x, y, sw, true, false);
- }
- }
- p.x += w->m_width;
- }
- return(bbox);
- }
- CRect CLine::PaintOutline(SubPicDesc& spd, CRect& clipRect, BYTE* pAlphaMask, CPoint p, CPoint org, int time, int alpha)
- {
- CRect bbox(0, 0, 0, 0);
- POSITION pos = GetHeadPosition();
- while(pos)
- {
- CWord* w = GetNext(pos);
- if(w->m_fLineBreak) return(bbox); // should not happen since this class is just a line of text without any breaks
- // if((w->m_style.outlineWidth > 0 || w->m_style.borderStyle == 1 && w->m_style.outlineWidth == 0) && !(w->m_ktype == 2 && time < w->m_kstart))
- if(w->m_style.outlineWidth > 0 && !(w->m_ktype == 2 && time < w->m_kstart))
- {
- int x = p.x;
- int y = p.y + m_ascent - w->m_ascent;
- DWORD aoutline = w->m_style.alpha[2];
- if(alpha > 0) aoutline += MulDiv(alpha, 0xff - w->m_style.alpha[2], 0xff);
- COLORREF outline = revcolor(w->m_style.colors[2]) | ((0xff-aoutline)<<24);
- long sw[6] = {outline, -1};
- w->Paint(CPoint(x, y), org);
- if(w->m_style.borderStyle == 0)
- {
- bbox |= w->Draw(spd, clipRect, pAlphaMask, x, y, sw, !w->m_style.alpha[0] && !w->m_style.alpha[1], true);
- }
- else if(w->m_style.borderStyle == 1 && w->m_pOpaqueBox)
- {
- bbox |= w->m_pOpaqueBox->Draw(spd, clipRect, pAlphaMask, x, y, sw, true/*!w->m_style.alpha[0] && !w->m_style.alpha[1]*/, false);
- }
- }
- p.x += w->m_width;
- }
- return(bbox);
- }
- CRect CLine::PaintBody(SubPicDesc& spd, CRect& clipRect, BYTE* pAlphaMask, CPoint p, CPoint org, int time, int alpha)
- {
- CRect bbox(0, 0, 0, 0);
- POSITION pos = GetHeadPosition();
- while(pos)
- {
- CWord* w = GetNext(pos);
- if(w->m_fLineBreak) return(bbox); // should not happen since this class is just a line of text without any breaks
- int x = p.x;
- int y = p.y + m_ascent - w->m_ascent;
- // colors
- DWORD aprimary = w->m_style.alpha[0];
- if(alpha > 0) aprimary += MulDiv(alpha, 0xff - w->m_style.alpha[0], 0xff);
- COLORREF primary = revcolor(w->m_style.colors[0]) | ((0xff-aprimary)<<24);
- DWORD asecondary = w->m_style.alpha[1];
- if(alpha > 0) asecondary += MulDiv(alpha, 0xff - w->m_style.alpha[1], 0xff);
- COLORREF secondary = revcolor(w->m_style.colors[1]) | ((0xff-asecondary)<<24);
- long sw[6] = {primary, 0, secondary};
- // karaoke
- double t;
- if(w->m_ktype == 0 || w->m_ktype == 2)
- {
- t = time < w->m_kstart ? 0 : 1;
- }
- else if(w->m_ktype == 1)
- {
- if(time < w->m_kstart) t = 0;
- else if(time < w->m_kend)
- {
- t = 1.0 * (time - w->m_kstart) / (w->m_kend - w->m_kstart);
- double angle = fmod(w->m_style.fontAngleZ, 360.0);
- if(angle > 90 && angle < 270)
- {
- t = 1-t;
- COLORREF tmp = sw[0]; sw[0] = sw[2]; sw[2] = tmp;
- }
- }
- else t = 1.0;
- }
- if(t >= 1)
- {
- sw[1] = 0xffffffff;
- }
- sw[3] = (int)(w->m_style.outlineWidth + t*w->m_width) >> 3;
- sw[4] = sw[2];
- sw[5] = 0x00ffffff;
- w->Paint(CPoint(x, y), org);
- bbox |= w->Draw(spd, clipRect, pAlphaMask, x, y, sw, true, false);
- p.x += w->m_width;
- }
- return(bbox);
- }
- // CSubtitle
- CSubtitle::CSubtitle()
- {
- memset(m_effects, 0, sizeof(Effect*)*EF_NUMBEROFEFFECTS);
- m_pClipper = NULL;
- m_scalex = m_scaley = 1;
- }
- CSubtitle::~CSubtitle()
- {
- Empty();
- }
- void CSubtitle::Empty()
- {
- POSITION pos = GetHeadPosition();
- while(pos) delete GetNext(pos);
- pos = m_words.GetHeadPosition();
- while(pos) delete m_words.GetNext(pos);
- for(int i = 0; i < EF_NUMBEROFEFFECTS; i++) {if(m_effects[i]) delete m_effects[i];}
- memset(m_effects, 0, sizeof(Effect*)*EF_NUMBEROFEFFECTS);
- if(m_pClipper) delete m_pClipper;
- m_pClipper = NULL;
- }
- int CSubtitle::GetFullWidth()
- {
- int width = 0;
- POSITION pos = m_words.GetHeadPosition();
- while(pos) width += m_words.GetNext(pos)->m_width;
- return(width);
- }
- int CSubtitle::GetFullLineWidth(POSITION pos)
- {
- int width = 0;
- while(pos)
- {
- CWord* w = m_words.GetNext(pos);
- if(w->m_fLineBreak) break;
- width += w->m_width;
- }
- return(width);
- }
- int CSubtitle::GetWrapWidth(POSITION pos, int maxwidth)
- {
- if(m_wrapStyle == 0 || m_wrapStyle == 3)
- {
- if(maxwidth > 0)
- {
- // int fullwidth = GetFullWidth();
- int fullwidth = GetFullLineWidth(pos);
- int minwidth = fullwidth / ((abs(fullwidth) / maxwidth) + 1);
- int width = 0, wordwidth = 0;
- while(pos && width < minwidth)
- {
- CWord* w = m_words.GetNext(pos);
- wordwidth = w->m_width;
- if(abs(width + wordwidth) < abs(maxwidth)) width += wordwidth;
- }
- maxwidth = width;
- if(m_wrapStyle == 3 && pos) maxwidth -= wordwidth;
- }
- }
- else if(m_wrapStyle == 1)
- {
- // maxwidth = maxwidth;
- }
- else if(m_wrapStyle == 2)
- {
- maxwidth = INT_MAX;
- }
- return(maxwidth);
- }
- CLine* CSubtitle::GetNextLine(POSITION& pos, int maxwidth)
- {
- if(pos == NULL) return(NULL);
- CLine* ret = new CLine();
- if(!ret) return(NULL);
- ret->m_width = ret->m_ascent = ret->m_descent = ret->m_border = 0;
- maxwidth = GetWrapWidth(pos, maxwidth);
- bool fEmptyLine = true;
- while(pos)
- {
- CWord* w = m_words.GetNext(pos);
- if(ret->m_ascent < w->m_ascent) ret->m_ascent = w->m_ascent;
- if(ret->m_descent < w->m_descent) ret->m_descent = w->m_descent;
- if(ret->m_border < w->m_style.outlineWidth) ret->m_border = (int)(w->m_style.outlineWidth+0.5);
- if(w->m_fLineBreak)
- {
- if(fEmptyLine) {ret->m_ascent /= 2; ret->m_descent /= 2; ret->m_border = 0;}
- ret->Compact();
- return(ret);
- }
- fEmptyLine = false;
- bool fWSC = w->m_fWhiteSpaceChar;
- int width = w->m_width;
- POSITION pos2 = pos;
- while(pos2)
- {
- if(m_words.GetAt(pos2)->m_fWhiteSpaceChar != fWSC
- || m_words.GetAt(pos2)->m_fLineBreak) break;
- CWord* w2 = m_words.GetNext(pos2);
- width += w2->m_width;
- }
- if((ret->m_width += width) <= maxwidth || ret->IsEmpty())
- {
- ret->AddTail(w->Copy());
-
- while(pos != pos2)
- {
- ret->AddTail(m_words.GetNext(pos)->Copy());
- }
- pos = pos2;
- }
- else
- {
- if(pos) m_words.GetPrev(pos);
- else pos = m_words.GetTailPosition();
- ret->m_width -= width;
- break;
- }
- }
- ret->Compact();
- return(ret);
- }
- void CSubtitle::CreateClippers(CSize size)
- {
- size.cx >>= 3;
- size.cy >>= 3;
- if(m_effects[EF_BANNER] && m_effects[EF_BANNER]->param[2])
- {
- int width = m_effects[EF_BANNER]->param[2];
- int w = size.cx, h = size.cy;
- if(!m_pClipper)
- {
- CStringW str;
- str.Format(L"m %d %d l %d %d %d %d %d %d", 0, 0, w, 0, w, h, 0, h);
- m_pClipper = new CClipper(str, size, 1, 1);
- if(!m_pClipper) return;
- }
- int da = (64<<8)/width;
- BYTE* am = m_pClipper->m_pAlphaMask;
- for(int j = 0; j < h; j++, am += w)
- {
- int a = 0;
- int k = min(width, w);
-
- for(int i = 0; i < k; i++, a += da)
- am[i] = (am[i]*a)>>14;
- a = 0x40<<8;
- k = w-width;
- if(k < 0) {a -= -k*da; k = 0;}
-
- for(int i = k; i < w; i++, a -= da)
- am[i] = (am[i]*a)>>14;
- }
- }
- else if(m_effects[EF_SCROLL] && m_effects[EF_SCROLL]->param[4])
- {
- int height = m_effects[EF_SCROLL]->param[4];
- int w = size.cx, h = size.cy;
- if(!m_pClipper)
- {
- CStringW str;
- str.Format(L"m %d %d l %d %d %d %d %d %d", 0, 0, w, 0, w, h, 0, h);
- m_pClipper = new CClipper(str, size, 1, 1);
- if(!m_pClipper) return;
- }
- int da = (64<<8)/height;
- int a = 0;
- int k = m_effects[EF_SCROLL]->param[0]>>3;
- int l = k+height;
- if(k < 0) {a += -k*da; k = 0;}
- if(l > h) {l = h;}
- if(k < h)
- {
- BYTE* am = &m_pClipper->m_pAlphaMask[k*w];
- memset(m_pClipper->m_pAlphaMask, 0, am - m_pClipper->m_pAlphaMask);
- for(int j = k; j < l; j++, a += da)
- {
- for(int i = 0; i < w; i++, am++)
- *am = ((*am)*a)>>14;
- }
- }
- da = -(64<<8)/height;
- a = 0x40<<8;
- l = m_effects[EF_SCROLL]->param[1]>>3;
- k = l-height;
- if(k < 0) {a += -k*da; k = 0;}
- if(l > h) {l = h;}
- if(k < h)
- {
- BYTE* am = &m_pClipper->m_pAlphaMask[k*w];
- int j = k;
- for(; j < l; j++, a += da)
- {
- for(int i = 0; i < w; i++, am++)
- *am = ((*am)*a)>>14;
- }
- memset(am, 0, (h-j)*w);
- }
- }
- }
- void CSubtitle::MakeLines(CSize size, CRect marginRect)
- {
- CSize spaceNeeded(0, 0);
- bool fFirstLine = true;
- m_topborder = m_bottomborder = 0;
- CLine* l = NULL;
-
- POSITION pos = m_words.GetHeadPosition();
- while(pos)
- {
- l = GetNextLine(pos, size.cx - marginRect.left - marginRect.right);
- if(!l) break;
- if(fFirstLine) {m_topborder = l->m_border; fFirstLine = false;}
- spaceNeeded.cx = max(l->m_width, spaceNeeded.cx);
- spaceNeeded.cy += l->m_ascent + l->m_descent;
- AddTail(l);
- }
- if(l) m_bottomborder = l->m_border;
- m_rect = CRect(
- CPoint((m_scrAlignment%3) == 1 ? marginRect.left
- : (m_scrAlignment%3) == 2 ? (marginRect.left + (size.cx - marginRect.right) - spaceNeeded.cx + 1) / 2
- : (size.cx - marginRect.right - spaceNeeded.cx),
- m_scrAlignment <= 3 ? (size.cy - marginRect.bottom - spaceNeeded.cy)
- : m_scrAlignment <= 6 ? (marginRect.top + (size.cy - marginRect.bottom) - spaceNeeded.cy + 1) / 2
- : marginRect.top),
- spaceNeeded);
- }
- // CScreenLayoutAllocator
- void CScreenLayoutAllocator::Empty()
- {
- m_subrects.RemoveAll();
- }
- void CScreenLayoutAllocator::AdvanceToSegment(int segment, const CSubArray& sa)
- {
- POSITION pos = m_subrects.GetHeadPosition();
- while(pos)
- {
- POSITION prev = pos;
- SubRect& sr = m_subrects.GetNext(pos);
- bool fFound = false;
- if(abs(sr.segment - segment) <= 1) // using abs() makes it possible to play the subs backwards, too :)
- {
- for(int i = 0; i < sa.GetSize() && !fFound; i++)
- {
- if(sa[i] == sr.entry)
- {
- sr.segment = segment;
- fFound = true;
- }
- }
- }
- if(!fFound) m_subrects.RemoveAt(prev);
- }
- }
- CRect CScreenLayoutAllocator::AllocRect(CSubtitle* s, int segment, int entry, int layer, int collisions)
- {
- // TODO: handle collisions == 1 (reversed collisions)
- POSITION pos = m_subrects.GetHeadPosition();
- while(pos)
- {
- SubRect& sr = m_subrects.GetNext(pos);
- if(sr.segment == segment && sr.entry == entry)
- {
- return(sr.r + CRect(0, -s->m_topborder, 0, -s->m_bottomborder));
- }
- }
- CRect r = s->m_rect + CRect(0, s->m_topborder, 0, s->m_bottomborder);
- bool fSearchDown = s->m_scrAlignment > 3;
- bool fOK;
- do
- {
- fOK = true;
- pos = m_subrects.GetHeadPosition();
- while(pos)
- {
- SubRect& sr = m_subrects.GetNext(pos);
- if(layer == sr.layer && !(r & sr.r).IsRectEmpty())
- {
- if(fSearchDown)
- {
- r.bottom = sr.r.bottom + r.Height();
- r.top = sr.r.bottom;
- }
- else
- {
- r.top = sr.r.top - r.Height();
- r.bottom = sr.r.top;
- }
-
- fOK = false;
- }
- }
- }
- while(!fOK);
- SubRect sr;
- sr.r = r;
- sr.segment = segment;
- sr.entry = entry;
- sr.layer = layer;
- m_subrects.AddTail(sr);
-
- return(sr.r + CRect(0, -s->m_topborder, 0, -s->m_bottomborder));
- }
- // CRenderedTextSubtitle
- CRenderedTextSubtitle::CRenderedTextSubtitle(CCritSec* pLock)
- : ISubPicProviderImpl(pLock)
- {
- m_size = CSize(0, 0);
- if(g_hDC_refcnt == 0)
- {
- g_hDC = CreateCompatibleDC(NULL);
- SetBkMode(g_hDC, TRANSPARENT);
- SetTextColor(g_hDC, 0xffffff);
- SetMapMode(g_hDC, MM_TEXT);
- }
- g_hDC_refcnt++;
- }
- CRenderedTextSubtitle::~CRenderedTextSubtitle()
- {
- Deinit();
- g_hDC_refcnt--;
- if(g_hDC_refcnt == 0) DeleteDC(g_hDC);
- }
- void CRenderedTextSubtitle::Copy(CSimpleTextSubtitle& sts)
- {
- CSimpleTextSubtitle::Copy(sts);
- m_size = CSize(0, 0);
- if(CRenderedTextSubtitle* pRTS = dynamic_cast<CRenderedTextSubtitle*>(&sts))
- {
- m_size = pRTS->m_nSize;
- }
- }
- void CRenderedTextSubtitle::Empty()
- {
- Deinit();
- CSimpleTextSubtitle::Empty();
- }
- void CRenderedTextSubtitle::OnChanged()
- {
- CSimpleTextSubtitle::OnChanged();
- POSITION pos = m_subtitleCache.GetStartPosition();
- while(pos)
- {
- int i;
- CSubtitle* s;
- m_subtitleCache.GetNextAssoc(pos, i, s);
- delete s;
- }
- m_subtitleCache.RemoveAll();
- m_sla.Empty();
- }
- bool CRenderedTextSubtitle::Init(CSize size, CRect vidrect)
- {
- Deinit();
- m_size = CSize(size.cx*8, size.cy*8);
- m_vidrect = CRect(vidrect.left*8, vidrect.top*8, vidrect.right*8, vidrect.bottom*8);
- m_sla.Empty();
- return(true);
- }
- void CRenderedTextSubtitle::Deinit()
- {
- POSITION pos = m_subtitleCache.GetStartPosition();
- while(pos)
- {
- int i;
- CSubtitle* s;
- m_subtitleCache.GetNextAssoc(pos, i, s);
- delete s;
- }
- m_subtitleCache.RemoveAll();
- m_sla.Empty();
- m_size = CSize(0, 0);
- m_vidrect.SetRectEmpty();
- }
- void CRenderedTextSubtitle::ParseEffect(CSubtitle* sub, CString str)
- {
- str.Trim();
- if(!sub || str.IsEmpty()) return;
- const TCHAR* s = _tcschr(str, ';');
- if(!s) {s = (LPTSTR)(LPCTSTR)str; s += str.GetLength()-1;}
- s++;
- CString effect = str.Left(s - str);
- if(!effect.CompareNoCase(_T("Banner;")))
- {
- int delay, lefttoright = 0, fadeawaywidth = 0;
- if(_stscanf(s, _T("%d;%d;%d"), &delay, &lefttoright, &fadeawaywidth) < 1) return;
- Effect* e = new Effect;
- if(!e) return;
- sub->m_effects[e->type = EF_BANNER] = e;
- e->param[0] = (int)(max(1.0*delay/sub->m_scalex, 1));
- e->param[1] = lefttoright;
- e->param[2] = (int)(sub->m_scalex*fadeawaywidth);
- sub->m_wrapStyle = 2;
- }
- else if(!effect.CompareNoCase(_T("Scroll up;")) || !effect.CompareNoCase(_T("Scroll down;")))
- {
- int top, bottom, delay, fadeawayheight = 0;
- if(_stscanf(s, _T("%d;%d;%d;%d"), &top, &bottom, &delay, &fadeawayheight) < 3) return;
- if(top > bottom) {int tmp = top; top = bottom; bottom = tmp;}
- Effect* e = new Effect;
- if(!e) return;
- sub->m_effects[e->type = EF_SCROLL] = e;
- e->param[0] = (int)(sub->m_scaley*top*8);
- e->param[1] = (int)(sub->m_scaley*bottom*8);
- e->param[2] = (int)(max(1.0*delay/sub->m_scaley, 1));
- e->param[3] = (effect.GetLength() == 12);
- e->param[4] = (int)(sub->m_scaley*fadeawayheight);
- }
- }
- void CRenderedTextSubtitle::ParseString(CSubtitle* sub, CStringW str, STSStyle& style)
- {
- if(!sub) return;
- str.Replace(L"\N", L"n");
- str.Replace(L"\n", (sub->m_wrapStyle < 2 || sub->m_wrapStyle == 3) ? L" " : L"n");
- str.Replace(L"\h", L"x00A0");
- for(int i = 0, j = 0, len = str.GetLength(); j <= len; j++)
- {
- WCHAR c = str[j];
- if(c != 'n' && c != ' ' && c != 'x00A0' && c != 0)
- continue;
- if(i < j)
- {
- if(CWord* w = new CText(style, str.Mid(i, j-i), m_ktype, m_kstart, m_kend))
- {
- sub->m_words.AddTail(w);
- m_kstart = m_kend;
- }
- }
- if(c == 'n')
- {
- if(CWord* w = new CText(style, CStringW(), m_ktype, m_kstart, m_kend))
- {
- sub->m_words.AddTail(w);
- m_kstart = m_kend;
- }
- }
- else if(c == ' ' || c == 'x00A0')
- {
- if(CWord* w = new CText(style, CStringW(c), m_ktype, m_kstart, m_kend))
- {
- sub->m_words.AddTail(w);
- m_kstart = m_kend;
- }
- }
- i = j+1;
- }
- return;
- }
- void CRenderedTextSubtitle::ParsePolygon(CSubtitle* sub, CStringW str, STSStyle& style)
- {
- if(!sub || !str.GetLength() || !m_nPolygon) return;
- if(CWord* w = new CPolygon(style, str, m_ktype, m_kstart, m_kend, sub->m_scalex/(1<<(m_nPolygon-1)), sub->m_scaley/(1<<(m_nPolygon-1)), m_polygonBaselineOffset))
- {
- sub->m_words.AddTail(w);
- m_kstart = m_kend;
- }
- }
- bool CRenderedTextSubtitle::ParseSSATag(CSubtitle* sub, CStringW str, STSStyle& style, STSStyle& org, bool fAnimate)
- {
- if(!sub) return(false);
- int nTags = 0, nUnrecognizedTags = 0;
- for(int i = 0, j; (j = str.Find('\', i)) >= 0; i = j)
- {
- CStringW cmd;
- for(WCHAR c = str[++j]; c && c != '(' && c != '\'; cmd += c, c = str[++j]);
- cmd.Trim();
- if(cmd.IsEmpty()) continue;
- CArray<CStringW> params;
- if(str[j] == '(')
- {
- CStringW param;
- for(WCHAR c = str[++j]; c && c != ')'; param += c, c = str[++j]);
- param.Trim();
- while(!param.IsEmpty())
- {
- int i = param.Find(','), j = param.Find('\');
- if(i >= 0 && (j < 0 || i < j))
- {
- CStringW s = param.Left(i).Trim();
- if(!s.IsEmpty()) params.Add(s);
- param = i+1 < param.GetLength() ? param.Mid(i+1) : L"";
- }
- else
- {
- param.Trim();
- if(!param.IsEmpty()) params.Add(param);
- param.Empty();
- }
- }
- }
- if(!cmd.Find(L"1c") || !cmd.Find(L"2c") || !cmd.Find(L"3c") || !cmd.Find(L"4c"))
- params.Add(cmd.Mid(2).Trim(L"&H")), cmd = cmd.Left(2);
- else if(!cmd.Find(L"1a") || !cmd.Find(L"2a") || !cmd.Find(L"3a") || !cmd.Find(L"4a"))
- params.Add(cmd.Mid(2).Trim(L"&H")), cmd = cmd.Left(2);
- else if(!cmd.Find(L"alpha"))
- params.Add(cmd.Mid(5).Trim(L"&H")), cmd = cmd.Left(5);
- else if(!cmd.Find(L"an"))
- params.Add(cmd.Mid(2)), cmd = cmd.Left(2);
- else if(!cmd.Find(L"a"))
- params.Add(cmd.Mid(1)), cmd = cmd.Left(1);
- else if(!cmd.Find(L"bord"))
- params.Add(cmd.Mid(4)), cmd = cmd.Left(4);
- else if(!cmd.Find(L"be"))
- params.Add(cmd.Mid(2)), cmd = cmd.Left(2);
- else if(!cmd.Find(L"b"))
- params.Add(cmd.Mid(1)), cmd = cmd.Left(1);
- else if(!cmd.Find(L"clip"))
- ;
- else if(!cmd.Find(L"c"))
- params.Add(cmd.Mid(1).Trim(L"&H")), cmd = cmd.Left(1);
- else if(!cmd.Find(L"fade"))
- ;
- else if(!cmd.Find(L"fe"))
- params.Add(cmd.Mid(2)), cmd = cmd.Left(2);
- else if(!cmd.Find(L"fn"))
- params.Add(cmd.Mid(2)), cmd = cmd.Left(2);
- else if(!cmd.Find(L"frx") || !cmd.Find(L"fry") || !cmd.Find(L"frz"))
- params.Add(cmd.Mid(3)), cmd = cmd.Left(3);
- else if(!cmd.Find(L"fr"))
- params.Add(cmd.Mid(2)), cmd = cmd.Left(2);
- else if(!cmd.Find(L"fscx") || !cmd.Find(L"fscy"))
- params.Add(cmd.Mid(4)), cmd = cmd.Left(4);
- else if(!cmd.Find(L"fsc"))
- params.Add(cmd.Mid(3)), cmd = cmd.Left(3);
- else if(!cmd.Find(L"fsp"))
- params.Add(cmd.Mid(3)), cmd = cmd.Left(3);
- else if(!cmd.Find(L"fs"))
- params.Add(cmd.Mid(2)), cmd = cmd.Left(2);
- else if(!cmd.Find(L"i"))
- params.Add(cmd.Mid(1)), cmd = cmd.Left(1);
- else if(!cmd.Find(L"kf") || !cmd.Find(L"ko"))
- params.Add(cmd.Mid(2)), cmd = cmd.Left(2);
- else if(!cmd.Find(L"k") || !cmd.Find(L"K"))
- params.Add(cmd.Mid(1)), cmd = cmd.Left(1);
- else if(!cmd.Find(L"move"))
- ;
- else if(!cmd.Find(L"org"))
- ;
- else if(!cmd.Find(L"pbo"))
- params.Add(cmd.Mid(3)), cmd = cmd.Left(3);
- else if(!cmd.Find(L"pos"))
- ;
- else if(!cmd.Find(L"p"))
- params.Add(cmd.Mid(1)), cmd = cmd.Left(1);
- else if(!cmd.Find(L"q"))
- params.Add(cmd.Mid(1)), cmd = cmd.Left(1);
- else if(!cmd.Find(L"r"))
- params.Add(cmd.Mid(1)), cmd = cmd.Left(1);
- else if(!cmd.Find(L"shad"))
- params.Add(cmd.Mid(4)), cmd = cmd.Left(4);
- else if(!cmd.Find(L"s"))
- params.Add(cmd.Mid(1)), cmd = cmd.Left(1);
- else if(!cmd.Find(L"t"))
- ;
- else if(!cmd.Find(L"u"))
- params.Add(cmd.Mid(1)), cmd = cmd.Left(1);
- else
- nUnrecognizedTags++;
- nTags++;
- // TODO: call ParseStyleModifier(cmd, params, ..) and move the rest there
- CStringW p = params.GetCount() > 0 ? params[0] : L"";
- if(cmd == "1c" || cmd == L"2c" || cmd == L"3c" || cmd == L"4c")
- {
- int i = cmd[0] - '1';
- DWORD c = wcstol(p, NULL, 16);
- style.colors[i] = !p.IsEmpty()
- ? (((int)CalcAnimation(c&0xff, style.colors[i]&0xff, fAnimate))&0xff
- |((int)CalcAnimation(c&0xff00, style.colors[i]&0xff00, fAnimate))&0xff00
- |((int)CalcAnimation(c&0xff0000, style.colors[i]&0xff0000, fAnimate))&0xff0000)
- : org.colors[i];
- }
- else if(cmd == L"1a" || cmd == L"2a" || cmd == L"3a" || cmd == L"4a")
- {
- int i = cmd[0] - '1';
- style.alpha[i] = !p.IsEmpty()
- ? (BYTE)CalcAnimation(wcstol(p, NULL, 16), style.alpha[i], fAnimate)
- : org.alpha[i];
- }
- else if(cmd == L"alpha")
- {
- for(int i = 0; i < 4; i++)
- {
- style.alpha[i] = !p.IsEmpty()
- ? (BYTE)CalcAnimation(wcstol(p, NULL, 16), style.alpha[i], fAnimate)
- : org.alpha[i];
- }
- }
- else if(cmd == L"an")
- {
- int n = wcstol(p, NULL, 10);
- if(sub->m_scrAlignment < 0)
- sub->m_scrAlignment = (n > 0 && n < 10) ? n : org.scrAlignment;
- }
- else if(cmd == L"a")
- {
- int n = wcstol(p, NULL, 10);
- if(sub->m_scrAlignment < 0)
- sub->m_scrAlignment = (n > 0 && n < 12) ? ((((n-1)&3)+1)+((n&4)?6:0)+((n&8)?3:0)) : org.scrAlignment;
- }
- else if(cmd == L"bord")
- {
- double n = CalcAnimation(wcstod(p, NULL), style.outlineWidth, fAnimate);
- style.outlineWidth = !p.IsEmpty()
- ? (n < 0 ? 0 : n)
- : org.outlineWidth;
- }
- else if(cmd == L"be")
- {
- int n = wcstol(p, NULL, 10);
- style.fBlur = !p.IsEmpty()
- ? (n == 0 ? false : n == 1 ? true : org.fBlur)
- : org.fBlur;
- }
- else if(cmd == L"b")
- {
- int n = wcstol(p, NULL, 10);
- style.fontWeight = !p.IsEmpty()
- ? (n == 0 ? FW_NORMAL : n == 1 ? FW_BOLD : n >= 100 ? n : org.fontWeight)
- : org.fontWeight;
- }
- else if(cmd == L"clip")
- {
- if(params.GetCount() == 1 && !sub->m_pClipper)
- {
- sub->m_pClipper = new CClipper(params[0], CSize(m_size.cx>>3, m_size.cy>>3), sub->m_scalex, sub->m_scaley);
- }
- else if(params.GetCount() == 2 && !sub->m_pClipper)
- {
- int scale = max(wcstol(p, NULL, 10), 1);
- sub->m_pClipper = new CClipper(params[1], CSize(m_size.cx>>3, m_size.cy>>3), sub->m_scalex/(1<<(scale-1)), sub->m_scaley/(1<<(scale-1)));
- }
- else if(params.GetCount() == 4)
- {
- sub->m_clip.SetRect(
- (int)CalcAnimation(sub->m_scalex*wcstol(params[0], NULL, 10), sub->m_clip.left, fAnimate),
- (int)CalcAnimation(sub->m_scaley*wcstol(params[1], NULL, 10), sub->m_clip.top, fAnimate),
- (int)CalcAnimation(sub->m_scalex*wcstol(params[2], NULL, 10), sub->m_clip.right, fAnimate),
- (int)CalcAnimation(sub->m_scaley*wcstol(params[3], NULL, 10), sub->m_clip.bottom, fAnimate));
- }
- }
- else if(cmd == L"c")
- {
- DWORD c = wcstol(p, NULL, 16);
- style.colors[0] = !p.IsEmpty()
- ? (((int)CalcAnimation(c&0xff, style.colors[0]&0xff, fAnimate))&0xff
- |((int)CalcAnimation(c&0xff00, style.colors[0]&0xff00, fAnimate))&0xff00
- |((int)CalcAnimation(c&0xff0000, style.colors[0]&0xff0000, fAnimate))&0xff0000)
- : org.colors[0];
- }
- else if(cmd == L"fade" || cmd == L"fad")
- {
- if(params.GetCount() == 7 && !sub->m_effects[EF_FADE])// {fade(a1=param[0], a2=param[1], a3=param[2], t1=t[0], t2=t[1], t3=t[2], t4=t[3])
- {
- if(Effect* e = new Effect)
- {
- for(int i = 0; i < 3; i++)
- e->param[i] = wcstol(params[i], NULL, 10);
- for(int i = 0; i < 4; i++)
- e->t[i] = wcstol(params[3+i], NULL, 10);
-
- sub->m_effects[EF_FADE] = e;
- }
- }
- else if(params.GetCount() == 2 && !sub->m_effects[EF_FADE]) // {fad(t1=t[1], t2=t[2])
- {
- if(Effect* e = new Effect)
- {
- e->param[0] = e->param[2] = 0xff;
- e->param[1] = 0x00;
- for(int i = 1; i < 3; i++)
- e->t[i] = wcstol(params[i-1], NULL, 10);
- e->t[0] = e->t[3] = -1; // will be substituted with "start" and "end"
- sub->m_effects[EF_FADE] = e;
- }
- }
- }
- else if(cmd == L"fe")
- {
- int n = wcstol(p, NULL, 10);
- style.charSet = !p.IsEmpty()
- ? n
- : org.charSet;
- }
- else if(cmd == L"fn")
- {
- style.fontName = (!p.IsEmpty() && p != '0')
- ? CString(p).Trim()
- : org.fontName;
- }
- else if(cmd == L"frx")
- {
- style.fontAngleX = !p.IsEmpty()
- ? CalcAnimation(wcstod(p, NULL), style.fontAngleX, fAnimate)
- : org.fontAngleX;
- }
- else if(cmd == L"fry")
- {
- style.fontAngleY = !p.IsEmpty()
- ? CalcAnimation(wcstod(p, NULL), style.fontAngleY, fAnimate)
- : org.fontAngleY;
- }
- else if(cmd == L"frz" || cmd == L"fr")
- {
- style.fontAngleZ = !p.IsEmpty()
- ? CalcAnimation(wcstod(p, NULL), style.fontAngleZ, fAnimate)
- : org.fontAngleZ;
- }
- else if(cmd == L"fscx")
- {
- double n = CalcAnimation(wcstol(p, NULL, 10), style.fontScaleX, fAnimate);
- style.fontScaleX = !p.IsEmpty()
- ? ((n < 0) ? 0 : n)
- : org.fontScaleX;
- }
- else if(cmd == L"fscy")
- {
- double n = CalcAnimation(wcstol(p, NULL, 10), style.fontScaleY, fAnimate);
- style.fontScaleY = !p.IsEmpty()
- ? ((n < 0) ? 0 : n)
- : org.fontScaleY;
- }
- else if(cmd == L"fsc")
- {
- style.fontScaleX = org.fontScaleX;
- style.fontScaleY = org.fontScaleY;
- }
- else if(cmd == L"fsp")
- {
- style.fontSpacing = !p.IsEmpty()
- ? CalcAnimation(wcstod(p, NULL), style.fontSpacing, fAnimate)
- : org.fontSpacing;
- }
- else if(cmd == L"fs")
- {
- if(!p.IsEmpty())
- {
- if(p[0] == '-' || p[0] == '+')
- {
- double n = CalcAnimation(style.fontSize + style.fontSize*wcstol(p, NULL, 10)/10, style.fontSize, fAnimate);
- style.fontSize = (n > 0) ? n : org.fontSize;
- }
- else
- {
- double n = CalcAnimation(wcstol(p, NULL, 10), style.fontSize, fAnimate);
- style.fontSize = (n > 0) ? n : org.fontSize;
- }
- }
- else
- {
- style.fontSize = org.fontSize;
- }
- }
- else if(cmd == L"i")
- {
- int n = wcstol(p, NULL, 10);
- style.fItalic = !p.IsEmpty()
- ? (n == 0 ? false : n == 1 ? true : org.fItalic)
- : org.fItalic;
- }
- else if(cmd == L"kf" || cmd == L"K")
- {
- m_ktype = 1;
- m_kstart = m_kend;
- m_kend += !p.IsEmpty()
- ? wcstol(p, NULL, 10)*10
- : 1000;
- }
- else if(cmd == L"ko")
- {
- m_ktype = 2;
- m_kstart = m_kend;
- m_kend += !p.IsEmpty()
- ? wcstol(p, NULL, 10)*10
- : 1000;
- }
- else if(cmd == L"k")
- {
- m_ktype = 0;
- m_kstart = m_kend;
- m_kend += !p.IsEmpty()
- ? wcstol(p, NULL, 10)*10
- : 1000;
- }
- else if(cmd == L"move") // {move(x1=param[0], y1=param[1], x2=param[2], y2=param[3][, t1=t[0], t2=t[1]])}
- {
- if((params.GetCount() == 4 || params.GetCount() == 6) && !sub->m_effects[EF_MOVE])
- {
- if(Effect* e = new Effect)
- {
- e->param[0] = (int)(sub->m_scalex*wcstol(params[0], NULL, 10)*8);
- e->param[1] = (int)(sub->m_scaley*wcstol(params[1], NULL, 10)*8);
- e->param[2] = (int)(sub->m_scalex*wcstol(params[2], NULL, 10)*8);
- e->param[3] = (int)(sub->m_scaley*wcstol(params[3], NULL, 10)*8);
- e->t[0] = e->t[1] = -1;
- if(params.GetCount() == 6)
- {
- for(int i = 0; i < 2; i++)
- e->t[i] = wcstol(params[4+i], NULL, 10);
- }
- sub->m_effects[EF_MOVE] = e;
- }
- }
- }
- else if(cmd == L"org") // {org(x=param[0], y=param[1])}
- {
- if(params.GetCount() == 2 && !sub->m_effects[EF_ORG])
- {
- if(Effect* e = new Effect)
- {
- e->param[0] = (int)(sub->m_scalex*wcstol(params[0], NULL, 10)*8);
- e->param[1] = (int)(sub->m_scaley*wcstol(params[1], NULL, 10)*8);
- sub->m_effects[EF_ORG] = e;
- }
- }
- }
- else if(cmd == L"pbo")
- {
- m_polygonBaselineOffset = wcstol(p, NULL, 10);
- }
- else if(cmd == L"pos")
- {
- if(params.GetCount() == 2 && !sub->m_effects[EF_MOVE])
- {
- if(Effect* e = new Effect)
- {
- e->param[0] = e->param[2] = (int)(sub->m_scalex*wcstol(params[0], NULL, 10)*8);
- e->param[1] = e->param[3] = (int)(sub->m_scaley*wcstol(params[1], NULL, 10)*8);
- e->t[0] = e->t[1] = 0;
- sub->m_effects[EF_MOVE] = e;
- }
- }
- }
- else if(cmd == L"p")
- {
- int n = wcstol(p, NULL, 10);
- m_nPolygon = (n <= 0 ? 0 : n);
- }
- else if(cmd == L"q")
- {
- int n = wcstol(p, NULL, 10);
- sub->m_wrapStyle = !p.IsEmpty() && (0 <= n && n <= 3)
- ? n
- : m_defaultWrapStyle;
- }
- else if(cmd == L"r")
- {
- void* val;
- style = (!p.IsEmpty() && m_styles.Lookup(CString(p), val) && val) ? *((STSStyle*)val) : org;
- }
- else if(cmd == L"shad")
- {
- double n = CalcAnimation(wcstod(p, NULL), style.shadowDepth, fAnimate);
- style.shadowDepth = !p.IsEmpty()
- ? (n < 0 ? 0 : n)
- : org.shadowDepth;
- }
- else if(cmd == L"s")
- {
- int n = wcstol(p, NULL, 10);
- style.fStrikeOut = !p.IsEmpty()
- ? (n == 0 ? false : n == 1 ? true : org.fStrikeOut)
- : org.fStrikeOut;
- }
- else if(cmd == L"t") // t([<t1>,<t2>,][<accel>,]<style modifiers>)
- {
- p.Empty();
- m_animStart = m_animEnd = 0;
- m_animAccel = 1;
- if(params.GetCount() == 1)
- {
- p = params[0];
- }
- else if(params.GetCount() == 2)
- {
- m_animAccel = wcstod(params[0], NULL);
- p = params[1];
- }
- else if(params.GetCount() == 3)
- {
- m_animStart = (int)wcstod(params[0], NULL);
- m_animEnd = (int)wcstod(params[1], NULL);
- p = params[2];
- }
- else if(params.GetCount() == 4)
- {
- m_animStart = wcstol(params[0], NULL, 10);
- m_animEnd = wcstol(params[1], NULL, 10);
- m_animAccel = wcstod(params[2], NULL);
- p = params[3];
- }
- ParseSSATag(sub, p, style, org, true);
- sub->m_fAnimated = true;
- }
- else if(cmd == L"u")
- {
- int n = wcstol(p, NULL, 10);
- style.fUnderline = !p.IsEmpty()
- ? (n == 0 ? false : n == 1 ? true : org.fUnderline)
- : org.fUnderline;
- }
- }
- // return(nUnrecognizedTags < nTags);
- return(true); // there are ppl keeping coments inside {}, lets make them happy now
- }
- bool CRenderedTextSubtitle::ParseHtmlTag(CSubtitle* sub, CStringW str, STSStyle& style, STSStyle& org)
- {
- if(str.Find(L"!--") == 0)
- return(true);
- bool fClosing = str[0] == '/';
- str.Trim(L" /");
- int i = str.Find(' ');
- if(i < 0) i = str.GetLength();
- CStringW tag = str.Left(i).MakeLower();
- str = str.Mid(i).Trim();
- CArray<CStringW> attribs, params;
- while((i = str.Find('=')) > 0)
- {
- attribs.Add(str.Left(i).Trim().MakeLower());
- str = str.Mid(i+1);
- for(i = 0; _istspace(str[i]); i++);
- str = str.Mid(i);
- if(str[0] == '"') {str = str.Mid(1); i = str.Find('"');}
- else i = str.Find(' ');
- if(i < 0) i = str.GetLength();
- params.Add(str.Left(i).Trim().MakeLower());
- str = str.Mid(i+1);
- }
- if(tag == L"text")
- ;
- else if(tag == L"b" || tag == L"strong")
- style.fontWeight = !fClosing ? FW_BOLD : org.fontWeight;
- else if(tag == L"i" || tag == L"em")
- style.fItalic = !fClosing ? true : org.fItalic;
- else if(tag == L"u")
- style.fUnderline = !fClosing ? true : org.fUnderline;
- else if(tag == L"s" || tag == L"strike" || tag == L"del")
- style.fStrikeOut = !fClosing ? true : org.fStrikeOut;
- else if(tag == L"font")
- {
- if(!fClosing)
- {
- for(i = 0; i < attribs.GetCount(); i++)
- {
- if(params[i].IsEmpty()) continue;
- int nColor = -1;
- if(attribs[i] == L"face")
- {
- style.fontName = params[i];
- }
- else if(attribs[i] == L"size")
- {
- if(params[i][0] == '+')
- style.fontSize += wcstol(params[i], NULL, 10);
- else if(params[i][0] == '-')
- style.fontSize -= wcstol(params[i], NULL, 10);
- else
- style.fontSize = wcstol(params[i], NULL, 10);
- }
- else if(attribs[i] == L"color")
- {
- nColor = 0;
- }
- else if(attribs[i] == L"outline-color")
- {
- nColor = 2;
- }
- else if(attribs[i] == L"outline-level")
- {
- style.outlineWidth = wcstol(params[i], NULL, 10);
- }
- else if(attribs[i] == L"shadow-color")
- {
- nColor = 3;
- }
- else if(attribs[i] == L"shadow-level")
- {
- style.shadowDepth = wcstol(params[i], NULL, 10);
- }
- if(nColor >= 0 && nColor < 4)
- {
- CString key = WToT(params[i]).TrimLeft('#');
- void* val;
- if(g_colors.Lookup(key, val))
- style.colors[nColor] = (DWORD)val;
- else if ((style.colors[nColor] = _tcstol(key, NULL, 16)) == 0)
- style.colors[nColor] = 0x00ffffff; // default is white
- style.colors[nColor] = ((style.colors[nColor]>>16)&0xff)|((style.colors[nColor]&0xff)<<16)|(style.colors[nColor]&0x00ff00);
- }
- }
- }
- else
- {
- style.fontName = org.fontName;
- style.fontSize = org.fontSize;
- memcpy(style.colors, org.colors, sizeof(style.colors));
- }
- }
- else if(tag == L"k" && attribs.GetCount() == 1 && attribs[0] == L"t")
- {
- m_ktype = 1;
- m_kstart = m_kend;
- m_kend += wcstol(params[0], NULL, 10);
- }
- else
- return(false);
- return(true);
- }
- double CRenderedTextSubtitle::CalcAnimation(double dst, double src, bool fAnimate)
- {
- int s = m_animStart ? m_animStart : 0;
- int e = m_animEnd ? m_animEnd : m_delay;
- if(fabs(dst-src) >= 0.0001 && fAnimate)
- {
- if(m_time < s) dst = src;
- else if(s <= m_time && m_time < e)
- {
- double t = pow(1.0 * (m_time - s) / (e - s), m_animAccel);
- dst = (1 - t) * src + t * dst;
- }
- // else dst = dst;
- }
- return(dst);
- }
- CSubtitle* CRenderedTextSubtitle::GetSubtitle(int entry)
- {
- CSubtitle* sub;
- if(m_subtitleCache.Lookup(entry, sub))
- {
- if(sub->m_fAnimated) {delete sub; sub = NULL;}
- else return(sub);
- }
- sub = new CSubtitle();
- if(!sub) return(NULL);
- CStringW str = GetStrW(entry, true);
- STSStyle stss, orgstss;
- GetStyle(entry, stss);
- orgstss = stss;
- sub->m_clip.SetRect(0, 0, m_size.cx>>3, m_size.cy>>3);
- sub->m_scrAlignment = -stss.scrAlignment;
- sub->m_wrapStyle = m_defaultWrapStyle;
- sub->m_fAnimated = false;
- sub->m_relativeTo = stss.relativeTo;
- sub->m_scalex = m_dstScreenSize.cx > 0 ? 1.0 * (stss.relativeTo == 1 ? m_vidrect.Width() : m_size.cx) / (m_dstScreenSize.cx*8) : 1.0;
- sub->m_scaley = m_dstScreenSize.cy > 0 ? 1.0 * (stss.relativeTo == 1 ? m_vidrect.Height() : m_size.cy) / (m_dstScreenSize.cy*8) : 1.0;
- m_animStart = m_animEnd = 0;
- m_animAccel = 1;
- m_ktype = m_kstart = m_kend = 0;
- m_nPolygon = 0;
- m_polygonBaselineOffset = 0;
- ParseEffect(sub, GetAt(entry).effect);
- while(!str.IsEmpty())
- {
- bool fParsed = false;
- int i;
- if(str[0] == '{' && (i = str.Find(L'}')) > 0)
- {
- if(fParsed = ParseSSATag(sub, str.Mid(1, i-1), stss, orgstss))
- str = str.Mid(i+1);
- }
- else if(str[0] == '<' && (i = str.Find(L'>')) > 0)
- {
- if(fParsed = ParseHtmlTag(sub, str.Mid(1, i-1), stss, orgstss))
- str = str.Mid(i+1);
- }
- if(fParsed)
- {
- i = str.FindOneOf(L"{<");
- if(i < 0) i = str.GetLength();
- if(i == 0) continue;
- }
- else
- {
- i = str.Mid(1).FindOneOf(L"{<");
- if(i < 0) i = str.GetLength()-1;
- i++;
- }
- STSStyle tmp = stss;
- tmp.fontSize = sub->m_scaley*tmp.fontSize*64;
- tmp.fontSpacing = sub->m_scalex*tmp.fontSpacing*64;
- tmp.outlineWidth *= (m_fScaledBAS ? ((sub->m_scalex+sub->m_scaley)/2) : 1) * 8;
- tmp.shadowDepth *= (m_fScaledBAS ? ((sub->m_scalex+sub->m_scaley)/2) : 1) * 8;
- if(m_nPolygon)
- {
- ParsePolygon(sub, str.Left(i), tmp);
- }
- else
- {
- ParseString(sub, str.Left(i), tmp);
- }
- str = str.Mid(i);
- }
- // just a "work-around" solution... in most cases nobody will want to use org together with moving but without rotating the subs
- if(sub->m_effects[EF_ORG] && (sub->m_effects[EF_MOVE] || sub->m_effects[EF_BANNER] || sub->m_effects[EF_SCROLL]))
- sub->m_fAnimated = true;
- sub->m_scrAlignment = abs(sub->m_scrAlignment);
- STSEntry stse = GetAt(entry);
- CRect marginRect = stse.marginRect;
- if(marginRect.left == 0) marginRect.left = orgstss.marginRect.left;
- if(marginRect.top == 0) marginRect.top = orgstss.marginRect.top;
- if(marginRect.right == 0) marginRect.right = orgstss.marginRect.right;
- if(marginRect.bottom == 0) marginRect.bottom = orgstss.marginRect.bottom;
- marginRect.left = (int)(sub->m_scalex*marginRect.left*8);
- marginRect.top = (int)(sub->m_scaley*marginRect.top*8);
- marginRect.right = (int)(sub->m_scalex*marginRect.right*8);
- marginRect.bottom = (int)(sub->m_scaley*marginRect.bottom*8);
-
- if(stss.relativeTo == 1)
- {
- marginRect.left += m_vidrect.left;
- marginRect.top += m_vidrect.top;
- marginRect.right += m_size.cx - m_vidrect.right;
- marginRect.bottom += m_size.cy - m_vidrect.bottom;
- }
- sub->CreateClippers(m_size);
- sub->MakeLines(m_size, marginRect);
- m_subtitleCache[entry] = sub;
- return(sub);
- }
- //
- STDMETHODIMP CRenderedTextSubtitle::NonDelegatingQueryInterface(REFIID riid, void** ppv)
- {
- CheckPointer(ppv, E_POINTER);
- *ppv = NULL;
- return
- QI(IPersist)
- QI(ISubStream)
- QI(ISubPicProvider)
- __super::NonDelegatingQueryInterface(riid, ppv);
- }
- // ISubPicProvider
- STDMETHODIMP_(POSITION) CRenderedTextSubtitle::GetStartPosition(REFERENCE_TIME rt, double fps)
- {
- int iSegment = -1;
- SearchSubs((int)(rt/10000), fps, &iSegment, NULL);
-
- if(iSegment < 0) iSegment = 0;
- return(GetNext((POSITION)iSegment));
- }
- STDMETHODIMP_(POSITION) CRenderedTextSubtitle::GetNext(POSITION pos)
- {
- int iSegment = (int)pos;
- const STSSegment* stss;
- while((stss = GetSegment(iSegment)) && stss->subs.GetSize() == 0)
- iSegment++;
- return(stss ? (POSITION)(iSegment+1) : NULL);
- }
- STDMETHODIMP_(REFERENCE_TIME) CRenderedTextSubtitle::GetStart(POSITION pos, double fps)
- {
- return(10000i64 * TranslateSegmentStart((int)pos-1, fps));
- }
- STDMETHODIMP_(REFERENCE_TIME) CRenderedTextSubtitle::GetStop(POSITION pos, double fps)
- {
- return(10000i64 * TranslateSegmentEnd((int)pos-1, fps));
- }
- STDMETHODIMP_(bool) CRenderedTextSubtitle::IsAnimated(POSITION pos)
- {
- // TODO
- return(true);
- }
- struct LSub {int idx, layer, readorder;};
- static int lscomp(const void* ls1, const void* ls2)
- {
- int ret = ((LSub*)ls1)->layer - ((LSub*)ls2)->layer;
- if(!ret) ret = ((LSub*)ls1)->readorder - ((LSub*)ls2)->readorder;
- return(ret);
- }
- STDMETHODIMP CRenderedTextSubtitle::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox)
- {
- CRect bbox2(0,0,0,0);
- if(m_size != CSize(spd.w*8, spd.h*8) || m_vidrect != CRect(spd.vidrect.left*8, spd.vidrect.top*8, spd.vidrect.right*8, spd.vidrect.bottom*8))
- Init(CSize(spd.w, spd.h), spd.vidrect);
- int t = (int)(rt / 10000);
- int segment;
- const STSSegment* stss = SearchSubs(t, fps, &segment);
- if(!stss) return S_FALSE;
- // clear any cached subs not in the range of +/-30secs measured from the segment's bounds
- {
- POSITION pos = m_subtitleCache.GetStartPosition();
- while(pos)
- {
- int key;
- CSubtitle* value;
- m_subtitleCache.GetNextAssoc(pos, key, value);
- STSEntry& stse = GetAt(key);
- if(stse.end <= (t-30000) || stse.start > (t+30000))
- {
- delete value;
- m_subtitleCache.RemoveKey(key);
- pos = m_subtitleCache.GetStartPosition();
- }
- }
- }
- m_sla.AdvanceToSegment(segment, stss->subs);
- CArray<LSub> subs;
- for(int i = 0, j = stss->subs.GetSize(); i < j; i++)
- {
- LSub ls;
- ls.idx = stss->subs[i];
- ls.layer = GetAt(stss->subs[i]).layer;
- ls.readorder = GetAt(stss->subs[i]).readorder;
- subs.Add(ls);
- }
- qsort(subs.GetData(), subs.GetSize(), sizeof(LSub), lscomp);
- for(int i = 0, j = subs.GetSize(); i < j; i++)
- {
- int entry = subs[i].idx;
- STSEntry stse = GetAt(entry);
- {
- int start = TranslateStart(entry, fps);
- m_time = t - start;
- m_delay = TranslateEnd(entry, fps) - start;
- }
- CSubtitle* s = GetSubtitle(entry);
- if(!s) continue;
- CRect clipRect = s->m_clip;
- CRect r = s->m_rect;
- CSize spaceNeeded = r.Size();
- // apply the effects
- bool fPosOverride = false, fOrgOverride = false;
- int alpha = 0x00;
- CPoint org2;
- for(int k = 0; k < EF_NUMBEROFEFFECTS; k++)
- {
- if(!s->m_effects[k]) continue;
- switch(k)
- {
- case EF_MOVE: // {move(x1=param[0], y1=param[1], x2=param[2], y2=param[3], t1=t[0], t2=t[1])}
- {
- CPoint p;
- CPoint p1(s->m_effects[k]->param[0], s->m_effects[k]->param[1]);
- CPoint p2(s->m_effects[k]->param[2], s->m_effects[k]->param[3]);
- int t1 = s->m_effects[k]->t[0];
- int t2 = s->m_effects[k]->t[1];
- if(t2 < t1) {int t = t1; t1 = t2; t2 = t;}
- if(t1 <= 0 && t2 <= 0) {t1 = 0; t2 = m_delay;}
- if(m_time <= t1) p = p1;
- else if(t1 < m_time && m_time < t2)
- {
- double t = 1.0*(m_time-t1)/(t2-t1);
- p.x = (int)((1-t)*p1.x + t*p2.x);
- p.y = (int)((1-t)*p1.y + t*p2.y);
- }
- else p = p2;
- r = CRect(
- CPoint((s->m_scrAlignment%3) == 1 ? p.x : (s->m_scrAlignment%3) == 0 ? p.x - spaceNeeded.cx : p.x - (spaceNeeded.cx+1)/2,
- s->m_scrAlignment <= 3 ? p.y - spaceNeeded.cy : s->m_scrAlignment <= 6 ? p.y - (spaceNeeded.cy+1)/2 : p.y),
- spaceNeeded);
- if(s->m_relativeTo == 1)
- r.OffsetRect(m_vidrect.TopLeft());
- fPosOverride = true;
- }
- break;
- case EF_ORG: // {org(x=param[0], y=param[1])}
- {
- org2 = CPoint(s->m_effects[k]->param[0], s->m_effects[k]->param[1]);
- fOrgOverride = true;
- }
- break;
- case EF_FADE: // {fade(a1=param[0], a2=param[1], a3=param[2], t1=t[0], t2=t[1], t3=t[2], t4=t[3]) or {fad(t1=t[1], t2=t[2])
- {
- int t1 = s->m_effects[k]->t[0];
- int t2 = s->m_effects[k]->t[1];
- int t3 = s->m_effects[k]->t[2];
- int t4 = s->m_effects[k]->t[3];
- if(t1 == -1 && t4 == -1) {t1 = 0; t3 = m_delay-t3; t4 = m_delay;}
- if(m_time < t1) alpha = s->m_effects[k]->param[0];
- else if(m_time >= t1 && m_time < t2)
- {
- double t = 1.0 * (m_time - t1) / (t2 - t1);
- alpha = (int)(s->m_effects[k]->param[0]*(1-t) + s->m_effects[k]->param[1]*t);
- }
- else if(m_time >= t2 && m_time < t3) alpha = s->m_effects[k]->param[1];
- else if(m_time >= t3 && m_time < t4)
- {
- double t = 1.0 * (m_time - t3) / (t4 - t3);
- alpha = (int)(s->m_effects[k]->param[1]*(1-t) + s->m_effects[k]->param[2]*t);
- }
- else if(m_time >= t4) alpha = s->m_effects[k]->param[2];
- }
- break;
- case EF_BANNER: // Banner;delay=param[0][;leftoright=param[1];fadeawaywidth=param[2]]
- {
- int left = s->m_relativeTo == 1 ? m_vidrect.left : 0,
- right = s->m_relativeTo == 1 ? m_vidrect.right : m_size.cx;
- r.left = !!s->m_effects[k]->param[1]
- ? (left/*marginRect.left*/ - spaceNeeded.cx) + (int)(m_time*8.0/s->m_effects[k]->param[0])
- : (right /*- marginRect.right*/) - (int)(m_time*8.0/s->m_effects[k]->param[0]);
- r.right = r.left + spaceNeeded.cx;
- clipRect &= CRect(left>>3, clipRect.top, right>>3, clipRect.bottom);
- fPosOverride = true;
- }
- break;
- case EF_SCROLL: // Scroll up/down(toptobottom=param[3]);top=param[0];bottom=param[1];delay=param[2][;fadeawayheight=param[4]]
- {
- r.top = !!s->m_effects[k]->param[3]
- ? s->m_effects[k]->param[0] + (int)(m_time*8.0/s->m_effects[k]->param[2]) - spaceNeeded.cy
- : s->m_effects[k]->param[1] - (int)(m_time*8.0/s->m_effects[k]->param[2]);
- r.bottom = r.top + spaceNeeded.cy;
- CRect cr(0, (s->m_effects[k]->param[0] + 4) >> 3, spd.w, (s->m_effects[k]->param[1] + 4) >> 3);
- if(s->m_relativeTo == 1)
- r.top += m_vidrect.top,
- r.bottom += m_vidrect.top,
- cr.top += m_vidrect.top>>3,
- cr.bottom += m_vidrect.top>>3;
- clipRect &= cr;
- fPosOverride = true;
- }
- break;
- default:
- break;
- }
- }
- if(!fPosOverride && !fOrgOverride && !s->m_fAnimated)
- r = m_sla.AllocRect(s, segment, entry, stse.layer, m_collisions);
- CPoint org;
- org.x = (s->m_scrAlignment%3) == 1 ? r.left : (s->m_scrAlignment%3) == 2 ? r.CenterPoint().x : r.right;
- org.y = s->m_scrAlignment <= 3 ? r.bottom : s->m_scrAlignment <= 6 ? r.CenterPoint().y : r.top;
- if(!fOrgOverride) org2 = org;
- BYTE* pAlphaMask = s->m_pClipper?s->m_pClipper->m_pAlphaMask:NULL;
- CPoint p, p2(0, r.top);
- POSITION pos;
- p = p2;
- pos = s->GetHeadPosition();
- while(pos)
- {
- CLine* l = s->GetNext(pos);
- p.x = (s->m_scrAlignment%3) == 1 ? org.x
- : (s->m_scrAlignment%3) == 0 ? org.x - l->m_width
- : org.x - (l->m_width/2);
- bbox2 |= l->PaintShadow(spd, clipRect, pAlphaMask, p, org2, m_time, alpha);
- p.y += l->m_ascent + l->m_descent;
- }
- p = p2;
- pos = s->GetHeadPosition();
- while(pos)
- {
- CLine* l = s->GetNext(pos);
- p.x = (s->m_scrAlignment%3) == 1 ? org.x
- : (s->m_scrAlignment%3) == 0 ? org.x - l->m_width
- : org.x - (l->m_width/2);
- bbox2 |= l->PaintOutline(spd, clipRect, pAlphaMask, p, org2, m_time, alpha);
- p.y += l->m_ascent + l->m_descent;
- }
- p = p2;
- pos = s->GetHeadPosition();
- while(pos)
- {
- CLine* l = s->GetNext(pos);
- p.x = (s->m_scrAlignment%3) == 1 ? org.x
- : (s->m_scrAlignment%3) == 0 ? org.x - l->m_width
- : org.x - (l->m_width/2);
- bbox2 |= l->PaintBody(spd, clipRect, pAlphaMask, p, org2, m_time, alpha);
- p.y += l->m_ascent + l->m_descent;
- }
- }
- bbox = bbox2;
- return (subs.GetSize() && !bbox2.IsRectEmpty()) ? S_OK : S_FALSE;
- }
- // IPersist
- STDMETHODIMP CRenderedTextSubtitle::GetClassID(CLSID* pClassID)
- {
- return pClassID ? *pClassID = __uuidof(this), S_OK : E_POINTER;
- }
- // ISubStream
- STDMETHODIMP_(int) CRenderedTextSubtitle::GetStreamCount()
- {
- return(1);
- }
- STDMETHODIMP CRenderedTextSubtitle::GetStreamInfo(int iStream, WCHAR** ppName, LCID* pLCID)
- {
- if(iStream != 0) return E_INVALIDARG;
- if(ppName)
- {
- if(!(*ppName = (WCHAR*)CoTaskMemAlloc((m_name.GetLength()+1)*sizeof(WCHAR))))
- return E_OUTOFMEMORY;
- wcscpy(*ppName, CStringW(m_name));
- }
- if(pLCID)
- {
- *pLCID = 0; // TODO
- }
- return S_OK;
- }
- STDMETHODIMP_(int) CRenderedTextSubtitle::GetStream()
- {
- return(0);
- }
- STDMETHODIMP CRenderedTextSubtitle::SetStream(int iStream)
- {
- return iStream == 0 ? S_OK : E_FAIL;
- }
- STDMETHODIMP CRenderedTextSubtitle::Reload()
- {
- CFileStatus s;
- if(!CFile::GetStatus(m_path, s)) return E_FAIL;
- return !m_path.IsEmpty() && Open(m_path, DEFAULT_CHARSET) ? S_OK : E_FAIL;
- }