code for CircleRule rendering.

This commit is contained in:
rachytski 2011-02-05 03:21:51 +02:00 committed by Alex Zolotarev
parent 51eff35455
commit 7a32dcf5c8
14 changed files with 354 additions and 19 deletions

View file

@ -607,6 +607,10 @@ namespace drule {
virtual void Read(FileReaderStream & ar) { read_rules(ar, this); }
virtual void Write(FileWriterStream & ar) const { write_rules(ar, this); }
virtual double GetRadius() const {return m_params.get<0>().m_v;}
virtual int GetStrokeColor() const {return m_params.get<3>().m_v;}
virtual int GetColor() const {return m_params.get<1>().m_v;}
static string arrKeys[6];
};
string CircleRule::arrKeys[] = {

View file

@ -58,6 +58,9 @@ namespace drule
virtual double GetWidth() const { return -1; }
virtual void GetPattern(vector<double> &, double &) const {}
virtual void GetSymbol(string &) const {}
virtual double GetRadius() const {return -1;}
virtual int GetStrokeColor() const {return -1;}
};
class RulesHolder

View file

@ -85,6 +85,29 @@ void DrawerYG::drawSymbol(m2::PointD const & pt, string const & symbolName, yg::
m_pScreen->drawSymbol(pt, m_pSkin->mapSymbol(symbolName.c_str()), pos, depth);
}
void DrawerYG::drawCircle(m2::PointD const & pt, rule_ptr_t pRule, int depth)
{
uint32_t id = pRule->GetID();
if (id == drule::BaseRule::empty_id)
{
yg::CircleInfo info(pRule->GetRadius(),
yg::Color::fromXRGB(pRule->GetColor(), pRule->GetAlpha()),
true);
id = m_pSkin->mapCircleInfo(info);
if (id != drule::BaseRule::empty_id)
pRule->SetID(id);
else
{
//ASSERT ( false, ("Can't find symbol by id = ", (name)) );
return;
}
}
m_pScreen->drawCircle(pt, id, depth);
}
void DrawerYG::drawSymbol(m2::PointD const & pt, rule_ptr_t pRule, yg::EPosition pos, int depth)
{
// Use BaseRule::m_id to cache for point draw rule.
@ -290,6 +313,8 @@ void DrawerYG::Draw(di::DrawInfo const * pInfo, rule_ptr_t * rules, int * depthV
bool const isArea = !pInfo->m_areas.empty();
bool const isName = !pInfo->m_name.empty();
bool const isCircle = (pRule->GetRadius() != -1);
if (!isCaption)
{
/// path is drawn separately in the code above
@ -313,6 +338,8 @@ void DrawerYG::Draw(di::DrawInfo const * pInfo, rule_ptr_t * rules, int * depthV
drawArea(i->m_path, pRule, depth);
else if (isSym)
drawSymbol(i->GetCenter(), pRule, yg::EPosLeft, depth);
if (isCircle)
drawCircle(i->GetCenter(), pRule, depth);
}
}
@ -330,7 +357,11 @@ void DrawerYG::Draw(di::DrawInfo const * pInfo, rule_ptr_t * rules, int * depthV
if (isArea && isN)
{
for (list<di::AreaInfo>::const_iterator i = pInfo->m_areas.begin(); i != pInfo->m_areas.end(); ++i)
{
drawText(i->GetCenter(), pInfo->m_name, pRule, depth);
if (isCircle)
drawCircle(i->GetCenter(), pRule, depth);
}
}
// draw way name
@ -363,6 +394,10 @@ void DrawerYG::Draw(di::DrawInfo const * pInfo, rule_ptr_t * rules, int * depthV
isN = ((pRule->GetType() & drule::node) != 0);
if (!isPath && !isArea && isN)
drawText(pInfo->m_point, pInfo->m_name, pRule, depth);
if (isCircle)
drawCircle(pInfo->m_point, pRule, depth);
}
}
}

View file

@ -63,6 +63,7 @@ private:
protected:
void drawSymbol(m2::PointD const & pt, rule_ptr_t pRule, yg::EPosition pos, int depth);
void drawCircle(m2::PointD const & pt, rule_ptr_t pRule, int depth);
void drawPath(vector<m2::PointD> const & pts, rule_ptr_t pRule, int depth);
void drawPath(vector<m2::PointD> const & pts, rule_ptr_t * rules, int * depthVec, size_t count);
void drawArea(vector<m2::PointD> const & pts, rule_ptr_t pRule, int depth);

View file

@ -4,7 +4,7 @@
namespace yg
{
CircleInfo::CircleInfo(double radius,
CircleInfo::CircleInfo(unsigned radius,
Color const & color,
bool isOutlined,
Color const & outlineColor)
@ -13,4 +13,18 @@ namespace yg
m_isOutlined(isOutlined),
m_outlineColor(outlineColor)
{}
CircleInfo::CircleInfo()
{}
bool operator< (CircleInfo const & l, CircleInfo const & r)
{
if (l.m_radius != r.m_radius)
return l.m_radius < r.m_radius;
if (l.m_color != r.m_color)
return l.m_color < r.m_color;
if (l.m_isOutlined != r.m_isOutlined)
return l.m_isOutlined < r.m_isOutlined;
return l.m_outlineColor < r.m_outlineColor;
}
}

View file

@ -6,15 +6,18 @@ namespace yg
{
struct CircleInfo
{
double m_radius;
unsigned m_radius;
Color m_color;
bool m_isOutlined;
Color m_outlineColor;
CircleInfo();
CircleInfo(
double radius,
unsigned radius,
Color const & color = Color(0, 0, 0, 255),
bool isOutlined = true,
bool isOutlined = false,
Color const & outlineColor = Color(255, 255, 255, 255));
};
bool operator< (CircleInfo const & l, CircleInfo const & r);
}

View file

@ -49,6 +49,16 @@ namespace yg
alphaFromARGB(_c));
}
Color const & Color::operator /= (unsigned k)
{
r /= k;
g /= k;
b /= k;
a /= k;
return *this;
}
bool operator < (Color const & l, Color const & r)
{
if (l.r != r.r) return l.r < r.r;

View file

@ -18,6 +18,8 @@ namespace yg
static Color const fromARGB(uint32_t _c);
static Color const fromXRGB(uint32_t _c, unsigned char _a = 0);
Color const & operator /= (unsigned k);
};
bool operator < (Color const & l, Color const & r);

View file

@ -64,5 +64,24 @@ namespace yg
drawTrianglesList(&sectorPts[0], sectorPts.size(), skin()->mapColor(c), depth);
}
void ShapeRenderer::drawCircle(m2::PointD const & center, uint32_t styleID, double depth)
{
ResourceStyle const * style(skin()->fromID(styleID));
m2::RectU texRect(style->m_texRect);
texRect.Inflate(-1, -1);
m2::PointD pt(center - m2::PointD(texRect.SizeX() / 2, texRect.SizeY() / 2));
pt.x = ceil(pt.x);
pt.y = ceil(pt.y);
drawTexturedPolygon(m2::PointD(0, 0), 0,
texRect.minX(), texRect.minY(), texRect.maxX(), texRect.maxY(),
pt.x, pt.y, pt.x + texRect.SizeX(), pt.y + texRect.SizeY(),
depth,
style->m_pageID);
}
}
}

View file

@ -19,7 +19,7 @@ namespace yg
void drawSector(m2::PointD const & center, double startA, double endA, double r, yg::Color const & c, double depth);
void fillSector(m2::PointD const & center, double startA, double endA, double r, yg::Color const & c, double depth);
// void drawCircle(m2::PointD const & center, uint32_t styleID, double depth);
void drawCircle(m2::PointD const & center, uint32_t styleID, double depth);
};
}
}

View file

@ -131,6 +131,22 @@ namespace yg
return packID(m_currentDynamicPage, m_pages[m_currentDynamicPage]->mapPenInfo(penInfo));
}
uint32_t Skin::mapCircleInfo(CircleInfo const & circleInfo)
{
uint32_t res = invalidPageHandle();
for (uint8_t i = 0; i < m_pages.size(); ++i)
{
res = m_pages[i]->findCircleInfo(circleInfo);
if (res != invalidPageHandle())
return packID(i, res);
}
if (!m_pages[m_currentDynamicPage]->hasRoom(circleInfo))
changeCurrentDynamicPage();
return packID(m_currentDynamicPage, m_pages[m_currentDynamicPage]->mapCircleInfo(circleInfo));
}
bool Skin::mapPenInfo(PenInfo const * penInfos, uint32_t * styleIDS, size_t count)
{
uint8_t savedDynamicPage = m_currentDynamicPage;

View file

@ -62,6 +62,12 @@ namespace yg
: m_penInfo(penInfo),
m_rect(rect){}
CircleUploadCmd::CircleUploadCmd(){}
CircleUploadCmd::CircleUploadCmd(yg::CircleInfo const & circleInfo,
m2::RectU const & rect)
: m_circleInfo(circleInfo),
m_rect(rect){}
ResourceStyle * FontInfo::fromID(uint32_t id, bool isMask) const
{
TChars::const_iterator it = m_chars.find(id);
@ -120,6 +126,7 @@ namespace yg
clearPenInfoHandles();
clearColorHandles();
clearFontHandles();
clearCircleInfoHandles();
m_packer.reset();
}
@ -140,6 +147,14 @@ namespace yg
m_penInfoMap.clear();
}
void SkinPage::clearCircleInfoHandles()
{
for (TCircleInfoMap::const_iterator it = m_circleInfoMap.begin(); it != m_circleInfoMap.end(); ++it)
m_styles.erase(it->second);
m_circleInfoMap.clear();
}
void SkinPage::clearFontHandles()
{
for (TGlyphMap::const_iterator it = m_glyphMap.begin(); it != m_glyphMap.end(); ++it)
@ -261,6 +276,43 @@ namespace yg
return m_packer.hasRoom(gi->m_metrics.m_width + 4, gi->m_metrics.m_height + 4);
}
uint32_t SkinPage::findCircleInfo(CircleInfo const & circleInfo) const
{
TCircleInfoMap::const_iterator it = m_circleInfoMap.find(circleInfo);
if (it == m_circleInfoMap.end())
return m_packer.invalidHandle();
else
return it->second;
}
uint32_t SkinPage::mapCircleInfo(CircleInfo const & circleInfo)
{
uint32_t foundHandle = findCircleInfo(circleInfo);
if (foundHandle != m_packer.invalidHandle())
return foundHandle;
unsigned r = circleInfo.m_isOutlined ? circleInfo.m_radius + 1 : circleInfo.m_radius;
m2::Packer::handle_t handle = m_packer.pack(
r * 2 + 4,
r * 2 + 4);
m2::RectU texRect = m_packer.find(handle).second;
m_circleUploadCommands.push_back(CircleUploadCmd(circleInfo, texRect));
m_circleInfoMap[circleInfo] = handle;
m_styles[handle] = shared_ptr<ResourceStyle>(new GenericStyle(texRect, m_pageID) );
return m_circleInfoMap[circleInfo];
}
bool SkinPage::hasRoom(CircleInfo const & circleInfo) const
{
unsigned r = circleInfo.m_isOutlined ? circleInfo.m_radius + 1 : circleInfo.m_radius;
return m_packer.hasRoom(r * 2 + 4,
r * 2 + 4);
}
uint32_t SkinPage::findPenInfo(PenInfo const & penInfo) const
{
@ -397,17 +449,21 @@ namespace yg
penInfo.m_color.b,
penInfo.m_color.a));
/// making alpha channel opaque
/* /// in non-transparent areas - premultiply color value with alpha and make it opaque
for (size_t x = 2; x < v.width() - 2; ++x)
for (size_t y = 2; y < v.height() - 2; ++y)
{
unsigned char alpha = gil::get_color(v(x, y), gil::alpha_t());
if (alpha != 0)
{
v(x, y) = penColor;
// gil::get_color(v(x, y), gil::alpha_t()) = alpha;
}
}
float fAlpha = alpha / (float)TDynamicTexture::maxChannelVal;
// if (alpha != 0)
// {
gil::get_color(v(x, y), gil::red_t()) *= fAlpha;
gil::get_color(v(x, y), gil::green_t()) *= fAlpha;
gil::get_color(v(x, y), gil::blue_t()) *= fAlpha;
// gil::get_color(v(x, y), gil::alpha_t()) = TDynamicTexture::maxChannelVal;
// }
}*/
}
else
{
@ -478,6 +534,150 @@ namespace yg
m_penUploadCommands.clear();
}
void SkinPage::uploadCircleInfo()
{
for (size_t i = 0; i < m_circleUploadCommands.size(); ++i)
{
yg::CircleInfo & circleInfo = m_circleUploadCommands[i].m_circleInfo;
m2::RectU const & rect = m_circleUploadCommands[i].m_rect;
TDynamicTexture * dynTexture = static_cast<TDynamicTexture*>(m_texture.get());
TDynamicTexture::view_t v = dynTexture->view(rect.SizeX(), rect.SizeY());
agg::rgba8 aggColor(circleInfo.m_color.r,
circleInfo.m_color.g,
circleInfo.m_color.b,
circleInfo.m_color.a);
agg::rgba8 aggOutlineColor(circleInfo.m_outlineColor.r,
circleInfo.m_outlineColor.g,
circleInfo.m_outlineColor.b,
circleInfo.m_outlineColor.a);
circleInfo.m_color /= TDynamicTexture::channelScaleFactor;
TDynamicTexture::pixel_t gilColorTranslucent;
gil::get_color(gilColorTranslucent, gil::red_t()) = circleInfo.m_color.r;
gil::get_color(gilColorTranslucent, gil::green_t()) = circleInfo.m_color.g;
gil::get_color(gilColorTranslucent, gil::blue_t()) = circleInfo.m_color.b;
gil::get_color(gilColorTranslucent, gil::alpha_t()) = 0;
circleInfo.m_outlineColor /= TDynamicTexture::channelScaleFactor;
TDynamicTexture::pixel_t gilOutlineColorTranslucent;
gil::get_color(gilOutlineColorTranslucent, gil::red_t()) = circleInfo.m_outlineColor.r;
gil::get_color(gilOutlineColorTranslucent, gil::green_t()) = circleInfo.m_outlineColor.g;
gil::get_color(gilOutlineColorTranslucent, gil::blue_t()) = circleInfo.m_outlineColor.b;
gil::get_color(gilOutlineColorTranslucent, gil::alpha_t()) = 0;
TDynamicTexture::pixel_t gilColor = gilColorTranslucent;
gil::get_color(gilColor, gil::alpha_t()) = circleInfo.m_color.a;
TDynamicTexture::pixel_t gilOutlineColor = gilOutlineColorTranslucent;
gil::get_color(gilOutlineColor, gil::alpha_t()) = circleInfo.m_outlineColor.a;
/// draw circle
agg::rendering_buffer buf(
(unsigned char *)&v(0, 0),
rect.SizeX(),
rect.SizeY(),
rect.SizeX() * sizeof(TDynamicTexture::pixel_t)
);
typedef AggTraits<TDynamicTexture::traits_t>::pixfmt_t agg_pixfmt_t;
agg_pixfmt_t pixfmt(buf);
agg::renderer_base<agg_pixfmt_t> rbase(pixfmt);
if (circleInfo.m_isOutlined)
gil::fill_pixels(v, gilOutlineColorTranslucent);
else
gil::fill_pixels(v, gilColorTranslucent);
m2::PointD center(circleInfo.m_radius + 2, circleInfo.m_radius + 2);
if (circleInfo.m_isOutlined)
center += m2::PointD(1, 1);
agg::scanline_u8 s;
agg::rasterizer_scanline_aa<> rasterizer;
agg::ellipse ell;
ell.init(center.x,
center.y,
circleInfo.m_isOutlined ? circleInfo.m_radius + 1 : circleInfo.m_radius,
circleInfo.m_isOutlined ? circleInfo.m_radius + 1 : circleInfo.m_radius,
100);
rasterizer.add_path(ell);
agg::render_scanlines_aa_solid(rasterizer,
s,
rbase,
circleInfo.m_isOutlined ? aggOutlineColor : aggColor);
TDynamicTexture::pixel_t px = circleInfo.m_isOutlined ? gilOutlineColor : gilColor;
/// making alpha channel opaque
/* for (size_t x = 2; x < v.width() - 2; ++x)
for (size_t y = 2; y < v.height() - 2; ++y)
{
unsigned char alpha = gil::get_color(v(x, y), gil::alpha_t());
float fAlpha = alpha / (float)TDynamicTexture::maxChannelVal;
if (alpha != 0)
{
gil::get_color(v(x, y), gil::red_t()) *= fAlpha;
gil::get_color(v(x, y), gil::green_t()) *= fAlpha;
gil::get_color(v(x, y), gil::blue_t()) *= fAlpha;
gil::get_color(v(x, y), gil::alpha_t()) = TDynamicTexture::maxChannelVal;
}
}
*/
if (circleInfo.m_isOutlined)
{
/// drawing inner circle
ell.init(center.x,
center.y,
circleInfo.m_radius,
circleInfo.m_radius,
100);
rasterizer.reset();
rasterizer.add_path(ell);
agg::render_scanlines_aa_solid(rasterizer,
s,
rbase,
aggColor);
/* for (size_t x = 2; x < v.width() - 2; ++x)
for (size_t y = 2; y < v.height() - 2; ++y)
{
unsigned char alpha = gil::get_color(v(x, y), gil::alpha_t());
float fAlpha = alpha / (float)TDynamicTexture::maxChannelVal;
// if (alpha != 0)
// {
gil::get_color(v(x, y), gil::red_t()) *= fAlpha;
gil::get_color(v(x, y), gil::green_t()) *= fAlpha;
gil::get_color(v(x, y), gil::blue_t()) *= fAlpha;
// gil::get_color(v(x, y), gil::alpha_t()) = TDynamicTexture::maxChannelVal;
// }
}*/
}
dynTexture->upload(&v(0, 0), rect);
}
m_circleUploadCommands.clear();
}
void SkinPage::uploadGlyphs()
{
for (size_t i = 0; i < m_glyphUploadCommands.size(); ++i)
@ -566,6 +766,7 @@ namespace yg
uploadColors();
uploadPenInfo();
uploadGlyphs();
uploadCircleInfo();
static_cast<gl::ManagedTexture*>(m_texture.get())->unlock();
}
}

View file

@ -9,6 +9,7 @@
#include "../geometry/rect2d.hpp"
#include "pen_info.hpp"
#include "circle_info.hpp"
#include "color.hpp"
#include "glyph_cache.hpp"
@ -47,6 +48,14 @@ namespace yg
PenUploadCmd();
};
struct CircleUploadCmd
{
yg::CircleInfo m_circleInfo;
m2::RectU m_rect;
CircleUploadCmd(yg::CircleInfo const & circleInfo, m2::RectU const & rect);
CircleUploadCmd();
};
struct FontInfo
{
int8_t m_fontSize;
@ -67,17 +76,18 @@ namespace yg
private:
// typedef unordered_map<uint32_t, shared_ptr<ResourceStyle> > TStyles;
typedef map<uint32_t, shared_ptr<ResourceStyle> > TStyles;
TStyles m_styles;
// typedef unordered_map<string, uint32_t> TPointNameMap;
typedef map<string, uint32_t> TPointNameMap;
TPointNameMap m_pointNameMap;
typedef map<PenInfo, uint32_t> TPenInfoMap;
TPenInfoMap m_penInfoMap;
typedef map<CircleInfo, uint32_t> TCircleInfoMap;
TCircleInfoMap m_circleInfoMap;
typedef map<Color, uint32_t> TColorMap;
TColorMap m_colorMap;
@ -91,10 +101,12 @@ namespace yg
vector<ColorUploadCmd> m_colorUploadCommands;
vector<PenUploadCmd> m_penUploadCommands;
vector<GlyphUploadCmd> m_glyphUploadCommands;
vector<CircleUploadCmd> m_circleUploadCommands;
void uploadPenInfo();
void uploadColors();
void uploadGlyphs();
void uploadCircleInfo();
typedef vector<FontInfo> TFonts;
TFonts m_fonts;
@ -113,6 +125,7 @@ namespace yg
void clearColorHandles();
void clearPenInfoHandles();
void clearFontHandles();
void clearCircleInfoHandles();
void clearHandles();
@ -140,6 +153,10 @@ namespace yg
uint32_t mapPenInfo(PenInfo const & penInfo);
bool hasRoom(PenInfo const & penInfo) const;
uint32_t findCircleInfo(CircleInfo const & circleInfo) const;
uint32_t mapCircleInfo(CircleInfo const & circleInfo);
bool hasRoom(CircleInfo const & circleInfo) const;
uint32_t findGlyph(GlyphKey const & g, bool isFixedFont) const;
uint32_t mapGlyph(GlyphKey const & g);
bool hasRoom(GlyphKey const & g) const;

View file

@ -926,6 +926,15 @@ namespace
}
};
struct TestDrawCircle
{
void DoDraw(shared_ptr<yg::gl::Screen> const & p)
{
p->drawCircle(m2::PointD(200, 200), p->skin()->mapCircleInfo(yg::CircleInfo(10, yg::Color(255, 0, 0, 255))), 100);
p->drawCircle(m2::PointD(100, 200), p->skin()->mapCircleInfo(yg::CircleInfo(10, yg::Color(255, 0, 0, 255), true, yg::Color(255, 255, 255, 255))), 100);
}
};
// UNIT_TEST_GL(TestDrawPolyOverflow);
// UNIT_TEST_GL(TestDrawText);
// UNIT_TEST_GL(TestDrawSingleSymbol);
@ -948,14 +957,15 @@ namespace
// UNIT_TEST_GL(TestDrawPathWithSkinPageMiss);
// UNIT_TEST_GL(TestDrawPathWithOffset);
// UNIT_TEST_GL(TestDrawPathJoin);
// UNIT_TEST_GL(TestDrawPathSolid1PX);
// UNIT_TEST_GL(TestDrawPathSolid2PX);
// UNIT_TEST_GL(TestDrawPathSolid);
UNIT_TEST_GL(TestDrawPathSolid1PX);
UNIT_TEST_GL(TestDrawPathSolid2PX);
UNIT_TEST_GL(TestDrawPathSolid);
// UNIT_TEST_GL(TestDrawSector);
// UNIT_TEST_GL(TestDrawPathSolidDiffWidth);
UNIT_TEST_GL(TestDrawPathSolidDiffWidth);
// UNIT_TEST_GL(TestDrawPathSolidWithZ);
// UNIT_TEST_GL(TestDrawPathSolidWithClipRect);
// UNIT_TEST_GL(TestDrawUtilsRect);
// UNIT_TEST_GL(TestDrawUtilsRectFilledTexture);
UNIT_TEST_GL(TestDrawSymbolFiltering);
// UNIT_TEST_GL(TestDrawSymbolFiltering);
UNIT_TEST_GL(TestDrawCircle);
}