Aegisub/vsfilter/libssf/GlyphPath.cpp

164 lines
4.0 KiB
C++

/*
* Copyright (C) 2003-2006 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 "GlyphPath.h"
namespace ssf
{
GlyphPath::GlyphPath(const GlyphPath& path)
{
*this = path;
}
void GlyphPath::operator = (const GlyphPath& path)
{
types.Copy(path.types);
points.Copy(path.points);
}
bool GlyphPath::IsEmpty()
{
return types.IsEmpty() || points.IsEmpty();
}
void GlyphPath::RemoveAll()
{
types.RemoveAll();
points.RemoveAll();
}
void GlyphPath::MovePoints(const CPoint& o)
{
size_t n = points.GetCount();
POINT* p = points.GetData();
unsigned int i = 0;
if(!!(g_cpuid.m_flags & CCpuID::sse2) && !((DWORD_PTR)p & 7))
{
for( ; i < n && ((DWORD_PTR)&p[i] & 15); i++)
{
p[i].x += o.x;
p[i].y += o.y;
}
__m128i oo = _mm_set_epi32(o.y, o.x, o.y, o.x);
for(unsigned int j = i + ((n - i) & ~7); i < j; i += 8)
{
__m128i r0 = _mm_load_si128((__m128i*)&p[i+0]);
__m128i r1 = _mm_load_si128((__m128i*)&p[i+2]);
__m128i r2 = _mm_load_si128((__m128i*)&p[i+4]);
__m128i r3 = _mm_load_si128((__m128i*)&p[i+6]);
_mm_store_si128((__m128i*)&p[i+0], _mm_add_epi32(r0, oo));
_mm_store_si128((__m128i*)&p[i+2], _mm_add_epi32(r1, oo));
_mm_store_si128((__m128i*)&p[i+4], _mm_add_epi32(r2, oo));
_mm_store_si128((__m128i*)&p[i+6], _mm_add_epi32(r3, oo));
}
}
for(; i < n; i++)
{
p[i].x += o.x;
p[i].y += o.y;
}
}
void GlyphPath::Enlarge(const GlyphPath& src, float size)
{
types.SetCount(src.types.GetCount());
points.SetCount(src.points.GetCount());
memcpy(types.GetData(), src.types.GetData(), types.GetCount());
size_t start = 0, end = 0;
for(size_t i = 0, j = src.types.GetCount(); i <= j; i++)
{
if(i > 0 && (i == j || (src.types[i] & ~PT_CLOSEFIGURE) == PT_MOVETO))
{
end = i-1;
bool cw = true; // TODO: determine orientation (ttf is always cw and we are sill before Transform)
float rotate = cw ? -M_PI_2 : M_PI_2;
CPoint prev = src.points[end];
CPoint cur = src.points[start];
for(size_t k = start; k <= end; k++)
{
CPoint next = k < end ? src.points[k+1] : src.points[start];
for(int l = k-1; prev == cur; l--)
{
if(l < (int)start) l = end;
prev = src.points[l];
}
for(int l = k+1; next == cur; l++)
{
if(l > (int)end) l = start;
next = src.points[l];
}
CPoint in = cur - prev;
CPoint out = next - cur;
float angle_in = atan2((float)in.y, (float)in.x);
float angle_out = atan2((float)out.y, (float)out.x);
float angle_diff = angle_out - angle_in;
if(angle_diff < 0) angle_diff += M_PI*2;
if(angle_diff > M_PI) angle_diff -= M_PI*2;
float scale = cos(angle_diff / 2);
CPoint p;
if(angle_diff < 0)
{
if(angle_diff > -M_PI/8) {if(scale < 1) scale = 1;}
else {if(scale < 0.50) scale = 0.50;}
}
else
{
if(angle_diff < M_PI/8) {if(scale < 0.75) scale = 0.75;}
else {if(scale < 0.25) scale = 0.25;}
}
if(scale < 0.1) scale = 0.1;
float angle = angle_in + angle_diff / 2 - rotate;
float radius = -size / scale; // FIXME
p.x = (int)(radius * cos(angle) + 0.5);
p.y = (int)(radius * sin(angle) + 0.5);
points[k] = cur + p;
prev = cur;
cur = next;
}
start = end+1;
}
}
}
}