428 lines
14 KiB
C++
428 lines
14 KiB
C++
/***************************************************************
|
||
* Name: wxCairo.cpp
|
||
* Purpose: Code for Application Frame
|
||
* Author: Igor I (info@tiptopcity.com)
|
||
* Created: 2009-05-24
|
||
* Copyright: Igor I (www.tiptopcity.com)
|
||
* License:
|
||
**************************************************************/
|
||
|
||
#ifdef WX_PRECOMP
|
||
#include "wx_pch.h"
|
||
#endif
|
||
|
||
//------------------------------------------------------------------------------
|
||
//#include <cairo/cairo-svg.h>
|
||
//#include <librsvg/rsvg.h>
|
||
//#include <librsvg/rsvg-cairo.h>
|
||
#if defined(_WIN32) || defined(_WINDOWS) || defined(_BORLAND) || defined(__BORLANDC__)
|
||
#include <cairo/cairo-win32.h>
|
||
#else
|
||
|
||
#endif
|
||
|
||
#include <cairo/cairo.h>
|
||
//#include <librsvg/rsvg.h>
|
||
//#include <librsvg/rsvg-cairo.h>
|
||
//#include <svg_cairo.c>
|
||
#include <math.h>
|
||
#include <string.h>
|
||
|
||
#include "wxCairo.h"
|
||
#include "stdTools.h"
|
||
//#include "wxgui/debug.h"
|
||
//------------------------------------------------------------------------------
|
||
struct stdword{
|
||
std::string str;
|
||
int width;
|
||
};
|
||
//------------------------------------------------------------------------------
|
||
wxCairo::wxCairo()
|
||
{
|
||
glId=0;
|
||
m_buffer=NULL;
|
||
m_surface=NULL;
|
||
m_cr=NULL;
|
||
m_format = CAIRO_FORMAT_RGB24;
|
||
m_width=0; m_height=0;
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
wxCairo::~wxCairo()
|
||
{
|
||
if(m_buffer!=NULL) delete m_buffer;
|
||
if(m_surface!=NULL) cairo_surface_destroy(m_surface);
|
||
if(m_cr!=NULL) cairo_destroy(m_cr);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
unsigned char* wxCairo::CreateBuffer(int width,int height)
|
||
{
|
||
if(width!=m_width || m_height!=height)
|
||
{
|
||
if(m_buffer!=NULL) delete m_buffer;
|
||
m_width=width; m_height=height;
|
||
m_buffer = new unsigned char[width*height*4]; //RGBA
|
||
memset(m_buffer, 0, width*height*4); //Обнулим массив
|
||
Init();
|
||
return m_buffer;
|
||
}else
|
||
{
|
||
memset(m_buffer, 0, width*height*4); //Обнулим(отчистим) массив
|
||
return m_buffer;
|
||
}
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
bool wxCairo::Init()
|
||
{
|
||
if(m_surface!=NULL) cairo_surface_destroy(m_surface);
|
||
if(m_cr!=NULL) cairo_destroy(m_cr);
|
||
m_surface = cairo_image_surface_create_for_data(m_buffer, m_format, m_width, m_height, m_width*4);
|
||
m_cr = cairo_create(m_surface);
|
||
cairo_set_antialias(m_cr, CAIRO_ANTIALIAS_NONE);
|
||
return true;
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
/*void wxCairo::Draw(wxPaintDC& dc)
|
||
{
|
||
// Convert from Cairo RGB24 format to wxImage BGR format.
|
||
unsigned char *dRGB = new unsigned char[m_width*m_height*3];
|
||
//unsigned char *dA = new unsigned char[m_width*m_height];
|
||
for(int y=0;y<m_height;y++)
|
||
{
|
||
for(int x=0;x<m_width;x++)
|
||
{
|
||
dRGB[x*3+y*m_width*3] = m_buffer[x*4+2+y*m_width*4];
|
||
dRGB[x*3+1+y*m_width*3] = m_buffer[x*4+1+y*m_width*4];
|
||
dRGB[x*3+2+y*m_width*3] = m_buffer[x*4+y*m_width*4];
|
||
|
||
//dA[x*y] = 255;
|
||
}
|
||
}
|
||
// Blit final image to the screen.
|
||
//wxImage img=wxImage(m_width, m_height, dRGB, dA, true);
|
||
wxImage img=wxImage(m_width, m_height, dRGB, true);
|
||
//if(img.HasAlpha())
|
||
//{
|
||
wxBitmap m_bitmap(img);
|
||
dc.DrawBitmap(m_bitmap, 0, 0, true);
|
||
//}
|
||
delete dRGB;
|
||
//delete dA;
|
||
}*/
|
||
//------------------------------------------------------------------------------
|
||
//Нарисуем чтонибудь для примера в текущем буфере
|
||
bool wxCairo::Test()
|
||
{
|
||
// White background.
|
||
//cairo_set_source_rgb(m_cr, 1.0, 1.0, 1.0);
|
||
//cairo_rectangle(m_cr, 0, 0, m_width, m_height);
|
||
//cairo_fill(m_cr);
|
||
|
||
//draw stuff
|
||
cairo_select_font_face(m_cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
|
||
cairo_set_font_size(m_cr, 32.0);
|
||
cairo_set_source_rgb(m_cr, 0.0, 0.0, 1.0);
|
||
cairo_move_to(m_cr, 10.0, 50.0);
|
||
|
||
std::string str="Привет мир!";
|
||
//const wxCharBuffer buff = str.mb_str(wxConvUTF8);
|
||
cairo_show_text (m_cr, str.c_str());
|
||
|
||
//Curve
|
||
double x=25.6, y=128.0;
|
||
double x1=102.4, y1=230.4,
|
||
x2=153.6, y2=25.6,
|
||
x3=230.4, y3=128.0;
|
||
|
||
cairo_move_to (m_cr, x, y);
|
||
cairo_curve_to (m_cr, x1, y1, x2, y2, x3, y3);
|
||
|
||
cairo_set_line_width (m_cr, 10.0);
|
||
cairo_stroke (m_cr);
|
||
|
||
cairo_set_source_rgba (m_cr, 1, 0.2, 0.2, 0.6);
|
||
cairo_set_line_width (m_cr, 6.0);
|
||
cairo_move_to (m_cr,x,y); cairo_line_to (m_cr,x1,y1);
|
||
cairo_move_to (m_cr,x2,y2); cairo_line_to (m_cr,x3,y3);
|
||
cairo_stroke (m_cr);
|
||
|
||
//SVG
|
||
/*cairo_surface_t *surface;
|
||
//cairo_t *cr;
|
||
|
||
surface = cairo_svg_surface_create("Svg.svg", 390, 60);
|
||
cr = cairo_create(surface);
|
||
|
||
cairo_set_source_rgb(m_cr, 0, 0, 0);
|
||
cairo_select_font_face (m_cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
||
cairo_set_font_size (m_cr, 40.0);
|
||
|
||
cairo_move_to(m_cr, 10.0, 50.0);
|
||
cairo_show_text(m_cr, "Disziplin ist Macht.");
|
||
|
||
cairo_surface_destroy(surface);
|
||
//cairo_destroy(cr);*/
|
||
|
||
/*double IMAGE_WIDTH = 256;
|
||
double IMAGE_HEIGHT = 256;
|
||
cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, IMAGE_WIDTH, IMAGE_HEIGHT);
|
||
cairo_t* cr = cairo_create(surface);
|
||
cairo_scale(cr, IMAGE_WIDTH, IMAGE_HEIGHT);
|
||
svg_cairo_t* svgc;
|
||
svg_cairo_create(&svgc);
|
||
gtk_init(&argc, &argv); // 1) doesn't work
|
||
svg_cairo_parse(svgc, "data/home.svg");
|
||
// gtk_init(&argc, &argv); // 2) works
|
||
unsigned w, h;
|
||
svg_cairo_get_size(svgc, &w, &h);
|
||
cairo_scale(cr, 1.0 / w, 1.0 / h);
|
||
svg_cairo_render(svgc, cr);
|
||
svg_cairo_destroy(svgc);
|
||
cairo_surface_write_to_png(surface, "out.png");
|
||
cairo_destroy(cr);
|
||
cairo_surface_destroy(surface);
|
||
return 0;*/
|
||
|
||
return true;
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
void wxCairo::MoveTo(double x, double y)
|
||
{
|
||
cairo_move_to(m_cr,x,y);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
void wxCairo::LineTo(double x, double y)
|
||
//void wxCairo::LineTo(double y, double x)
|
||
{
|
||
cairo_line_to(m_cr,x,y);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
void wxCairo::SetLineWidth(double width)
|
||
{
|
||
cairo_set_line_width(m_cr, width);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
void wxCairo::ShowText(std::wstring& str)
|
||
{
|
||
std::string utf8=convUTF16ToUTF8(str);
|
||
cairo_show_text (m_cr, utf8.c_str());
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
void wxCairo::SetSourceRGBA(double red, double green, double blue, double alpha)
|
||
{
|
||
cairo_set_source_rgba(m_cr, red, green, blue, alpha);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
void wxCairo::SetSourceRGB(double red, double green, double blue)
|
||
{ cairo_set_source_rgb(m_cr, red, green, blue);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
void wxCairo::Rectangle (double x, double y, double width, double height)
|
||
{ cairo_rectangle (m_cr, x, y, width, height);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
//Не рисовать то что не входит в последний геом объект
|
||
void wxCairo::Clip()
|
||
{ cairo_clip(m_cr);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
void wxCairo::ResetClip()
|
||
{ cairo_reset_clip(m_cr);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
void wxCairo::Fill()
|
||
{ cairo_fill(m_cr);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
//Обводка
|
||
//Операция cairo_stroke() применяет виртуальный карандаш вдоль контура.Это позволяет источнику передать через маску тонкую(или толстую) линию вдоль контура, в соответствие с карандашной толщиной линии, стилем точек, и наконечниками линии.
|
||
void wxCairo::Stroke()
|
||
{ cairo_stroke(m_cr);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
//Преобразовать рисунок в битовый массив
|
||
void wxCairo::toBitArray(unsigned char* bitArray)
|
||
{
|
||
int pos = 0;
|
||
for (int y = 0; y<m_height; y++)
|
||
{
|
||
for (int x = 0; x<m_width; x++)
|
||
{
|
||
unsigned char r = m_buffer[x * 4 + 2 + y*m_width * 4];
|
||
unsigned char g = m_buffer[x * 4 + 1 + y*m_width * 4];
|
||
unsigned char b = m_buffer[x * 4 + y*m_width * 4];
|
||
unsigned char px = (r + g + b) / 3.0f;
|
||
|
||
int posB=floor(pos / 8.0f); //Номер байта
|
||
|
||
if (px < 127) //Чёрный это 1
|
||
{
|
||
setBit(&bitArray[posB], pos - posB * 8, true);
|
||
//
|
||
}else //Белый это 0
|
||
{
|
||
setBit(&bitArray[posB], pos - posB * 8, false);
|
||
}
|
||
pos++;
|
||
}
|
||
}
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
void wxCairo::setBit(unsigned char *mas, const unsigned char pos, bool val)
|
||
{
|
||
unsigned char mask = 128;
|
||
unsigned char loc = pos / 8;
|
||
mask = mask >> (pos - loc * 8);
|
||
if (val) mas[loc] = mas[loc] | mask;
|
||
else
|
||
{
|
||
mask = ~mask; //Отрицание
|
||
mas[loc] = mas[loc] & mask;
|
||
}
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
void wxCairo::setFontface(std::string family,bool slant,bool weight)
|
||
{
|
||
cairo_font_slant_t s;
|
||
if (slant) s = CAIRO_FONT_SLANT_ITALIC; else s = CAIRO_FONT_SLANT_NORMAL;
|
||
cairo_font_weight_t w;
|
||
if (weight) w = CAIRO_FONT_WEIGHT_BOLD; else w = CAIRO_FONT_WEIGHT_NORMAL;
|
||
|
||
cairo_select_font_face(m_cr,family.c_str(),s,w);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
void wxCairo::setFontface(const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight)
|
||
{
|
||
cairo_select_font_face(m_cr, family, slant, weight);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
//the new font size, in user space units
|
||
void wxCairo::setFontSize(double size)
|
||
{
|
||
cairo_set_font_size(m_cr,size);
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
void wxCairo::seveToPNG(std::string filePath)
|
||
{
|
||
cairo_surface_write_to_png(m_surface, filePath.c_str());
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
//Ширина текста в пикселях
|
||
double wxCairo::getTextWidth(std::wstring& str)
|
||
{
|
||
std::string utf8 = convUTF16ToUTF8(str);
|
||
cairo_text_extents_t ext;
|
||
cairo_text_extents(m_cr, utf8.c_str(), &ext);
|
||
return ext.width;
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
//Высота текста в пикселях
|
||
double wxCairo::getTextHeight(std::wstring& str)
|
||
{
|
||
std::string utf8 = convUTF16ToUTF8(str);
|
||
cairo_text_extents_t ext;
|
||
cairo_text_extents(m_cr, utf8.c_str(), &ext);
|
||
return ext.height;
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
//Вывести текст по центру области
|
||
void wxCairo::ShowTextCenter(std::wstring& str, int xStart, int xEnd, int y)
|
||
{
|
||
std::string utf8 = convUTF16ToUTF8(str);
|
||
|
||
cairo_text_extents_t ext;
|
||
cairo_text_extents(m_cr, utf8.c_str(), &ext);
|
||
|
||
ext.width = xStart + (((xEnd - xStart) / 2.0f) - (ext.width / 2.0f));
|
||
cairo_move_to(m_cr, ext.width, y);
|
||
|
||
cairo_show_text(m_cr, utf8.c_str());
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
//Вывести текст с переносом на следующую строку с выравниванием по словам, высота символов однирна
|
||
//xStart начало для вычисления центра
|
||
//xEnd конец для вычисления центра
|
||
//y высота
|
||
void wxCairo::ShowTextBR(std::wstring& str, int xStart, int xEnd, int y)
|
||
{
|
||
/*stdword line;
|
||
std::vector<stdword> parts;
|
||
|
||
int maxH=0;
|
||
std::vector<std::wstring> array =split(str,L' ');
|
||
for (std::vector<std::wstring>::iterator it = array.begin() ; it != array.end(); ++it)
|
||
{
|
||
std::wstring s=*it;
|
||
line.word = convUTF16ToUTF8(s);
|
||
cairo_text_extents(m_cr, line.word.c_str(), &line.ext);
|
||
line.ext.width+=line.ext.width/s.length(); //Так как пробел почемуто обрезается при расчёте ширины
|
||
parts.push_back(line);
|
||
if(maxH<line.ext.height) maxH=line.ext.height;
|
||
}
|
||
|
||
int w=xStart;
|
||
for (std::vector<stdword>::iterator it = parts.begin() ; it != parts.end(); ++it)
|
||
{
|
||
line=*it;
|
||
if(w+line.ext.width<xEnd)
|
||
{
|
||
cairo_move_to(m_cr, w, y);
|
||
w+=line.ext.width;
|
||
}else
|
||
{
|
||
w=xStart;
|
||
y+=maxH;
|
||
cairo_move_to(m_cr, w, y);
|
||
w+=line.ext.width;
|
||
}
|
||
cairo_show_text(m_cr, line.word.c_str());
|
||
}*/
|
||
}
|
||
//------------------------------------------------------------------------------
|
||
//------------------------------------------------------------------------------
|
||
//Вывести текст с переносом на следующую строку с выравниванием по словам, высота символов однирна
|
||
//xStart начало для вычисления центра
|
||
//xEnd конец для вычисления центра
|
||
//y высота
|
||
void wxCairo::ShowTextCenterBR(std::wstring& str, int xStart, int xEnd, int y)
|
||
{
|
||
std::vector<std::wstring> array =split(str,L' '); //Для разбивки на слова
|
||
int height=0; //Высота символов
|
||
std::vector<stdword> parts; //Для разбивки на строки
|
||
|
||
stdword line;
|
||
line.width=0;
|
||
line.str="";
|
||
for (std::vector<std::wstring>::iterator it = array.begin() ; it != array.end(); ++it)
|
||
{
|
||
std::wstring s=*it;
|
||
std::string word = convUTF16ToUTF8(s);
|
||
cairo_text_extents_t ext;
|
||
cairo_text_extents(m_cr, word.c_str(), &ext);
|
||
ext.width+=ext.width/s.length(); //Так как пробел почемуто обрезается при расчёте ширины
|
||
if(height<ext.height) height=ext.height; //Высота символов
|
||
|
||
if(line.width+ext.width<xEnd-xStart)
|
||
{
|
||
line.width+=ext.width;
|
||
line.str+=word+' ';
|
||
}else
|
||
{
|
||
parts.push_back(line);
|
||
line.width=0;
|
||
line.str="";
|
||
}
|
||
}
|
||
parts.push_back(line);
|
||
|
||
//Отображаю текст по центру
|
||
for (std::vector<stdword>::iterator it = parts.begin() ; it != parts.end(); ++it)
|
||
{
|
||
stdword line=*it;
|
||
int width = xStart + (((xEnd - xStart) / 2.0f) - (line.width / 2.0f));
|
||
cairo_move_to(m_cr, width, y);
|
||
cairo_show_text(m_cr, line.str.c_str());
|
||
y+=height;
|
||
}
|
||
}
|
||
//------------------------------------------------------------------------------
|