framework2
1396 строк · 39.9 Кб
1#include "ofCairoRenderer.h"
2#include "ofMesh.h"
3#include "ofImage.h"
4#include "ofTrueTypeFont.h"
5#include "ofGraphics.h"
6#include "ofVideoBaseTypes.h"
7#include "cairo-features.h"
8#include "cairo-pdf.h"
9#include "cairo-svg.h"
10
11using std::vector;
12using std::string;
13
14const string ofCairoRenderer::TYPE="cairo";
15
16_cairo_status ofCairoRenderer::stream_function(void *closure,const unsigned char *data, unsigned int length){
17((ofCairoRenderer*)closure)->streamBuffer.append((const char*)data,length);
18return CAIRO_STATUS_SUCCESS;
19}
20
21ofCairoRenderer::ofCairoRenderer()
22:graphics3d(this)
23,projection(1)
24,modelView(1)
25{
26type = PDF;
27surface = nullptr;
28cr = nullptr;
29bBackgroundAuto = true;
30page = 0;
31multiPage = false;
32b3D = false;
33currentMatrixMode=OF_MATRIX_MODELVIEW;
34}
35
36ofCairoRenderer::~ofCairoRenderer(){
37close();
38}
39
40void ofCairoRenderer::setup(const of::filesystem::path & _filename, Type _type, bool multiPage_, bool b3D_, ofRectangle outputsize){
41if( outputsize.width == 0 || outputsize.height == 0 ){
42outputsize.set(0, 0, ofGetViewportWidth(), ofGetViewportHeight());
43}
44
45filename = _filename;
46type = _type;
47streamBuffer.clear();
48
49if(type == FROM_FILE_EXTENSION){
50auto ext = filename.extension();
51if(ext == of::filesystem::path{".svg"} || ext == of::filesystem::path{".SVG"} ){
52type = SVG;
53}else if(ext == of::filesystem::path {".pdf"} || ext == of::filesystem::path{".PDF"} ){
54type = PDF;
55}else{ // default to image
56type = IMAGE;
57}
58}
59
60if(filename != "") {
61switch(type) {
62case PDF:
63case SVG:
64case IMAGE:
65ofFilePath::createEnclosingDirectory(filename);
66case FROM_FILE_EXTENSION:
67break;
68}
69}
70
71switch(type){
72case PDF:
73if(filename==""){
74surface = cairo_pdf_surface_create_for_stream(&ofCairoRenderer::stream_function,this,outputsize.width, outputsize.height);
75}else{
76// FIXME: Future - once ofToDataPath returns fs::path, remove c_str()
77surface = cairo_pdf_surface_create(ofToDataPath(filename).c_str(),outputsize.width, outputsize.height);
78}
79break;
80case SVG:
81if(filename==""){
82surface = cairo_svg_surface_create_for_stream(&ofCairoRenderer::stream_function,this,outputsize.width, outputsize.height);
83}else{
84// FIXME: Future - once ofToDataPath returns fs::path, remove c_str()
85surface = cairo_svg_surface_create(ofToDataPath(filename).c_str(),outputsize.width, outputsize.height);
86}
87break;
88case IMAGE:
89imageBuffer.allocate(outputsize.width, outputsize.height, OF_PIXELS_BGRA);
90imageBuffer.set(0);
91surface = cairo_image_surface_create_for_data(imageBuffer.getData(),CAIRO_FORMAT_ARGB32,outputsize.width, outputsize.height,outputsize.width*4);
92break;
93case FROM_FILE_EXTENSION:
94ofLogFatalError("ofCairoRenderer") << "setup(): couldn't determine type from extension for filename: \"" << _filename << "\"!";
95break;
96default:
97ofLogError("ofCairoRenderer") << "setup(): encountered unknown type for filename \"" << _filename << "\"";
98break;
99}
100
101cr = cairo_create(surface);
102cairo_set_antialias(cr,CAIRO_ANTIALIAS_SUBPIXEL);
103viewportRect = outputsize;
104originalViewport = outputsize;
105viewport(viewportRect);
106page = 0;
107b3D = b3D_;
108multiPage = multiPage_;
109setupGraphicDefaults();
110}
111
112void ofCairoRenderer::setupMemoryOnly(Type _type, bool multiPage_, bool b3D_, ofRectangle outputsize){
113setup("",_type,multiPage_,b3D_,outputsize);
114}
115
116void ofCairoRenderer::flush(){
117if(surface){
118cairo_surface_flush(surface);
119}
120}
121
122void ofCairoRenderer::close(){
123if(surface){
124cairo_surface_flush(surface);
125if(type==IMAGE && filename!=""){
126ofSaveImage(imageBuffer,filename);
127}
128cairo_surface_finish(surface);
129cairo_surface_destroy(surface);
130surface = nullptr;
131}
132if(cr){
133cairo_destroy(cr);
134cr = nullptr;
135}
136}
137
138
139void ofCairoRenderer::startRender(){
140setStyle(currentStyle);
141if(page==0 || !multiPage){
142page=1;
143}else{
144page++;
145if(getBackgroundAuto()){
146cairo_show_page(cr);
147clear();
148}else{
149cairo_copy_page(cr);
150}
151}
152}
153
154void ofCairoRenderer::finishRender(){
155cairo_surface_flush(surface);
156}
157
158void ofCairoRenderer::setStyle(const ofStyle & style){
159//color
160setColor((int)style.color.r, (int)style.color.g, (int)style.color.b, (int)style.color.a);
161
162//bg color
163setBackgroundColor(style.bgColor);
164
165//circle resolution - don't worry it only recalculates the display list if the res has changed
166setCircleResolution(style.circleResolution);
167
168setSphereResolution(style.sphereResolution);
169
170setCurveResolution(style.curveResolution);
171
172//line width - finally!
173setLineWidth(style.lineWidth);
174
175//rect mode: corner/center
176setRectMode(style.rectMode);
177
178//poly mode: winding type
179setPolyMode(style.polyMode);
180
181//fill
182setFillMode(style.bFill?OF_FILLED:OF_OUTLINE);
183
184//smoothing
185//setSmoothingEnabled(style.smoothing);
186
187//blending
188setBlendMode(style.blendingMode);
189
190//bitmap draw mode
191//setDrawBitmapMode(style.drawBitmapMode);
192currentStyle = style;
193}
194
195void ofCairoRenderer::setCurveResolution(int resolution){
196currentStyle.curveResolution = resolution;
197path.setCurveResolution(resolution);
198}
199
200void ofCairoRenderer::draw(const ofPath & shape) const{
201cairo_new_path(cr);
202const vector<ofPath::Command> & commands = shape.getCommands();
203for(int i=0;i<(int)commands.size();i++){
204draw(commands[i]);
205}
206
207cairo_fill_rule_t cairo_poly_mode;
208if(shape.getWindingMode()==OF_POLY_WINDING_ODD) cairo_poly_mode=CAIRO_FILL_RULE_EVEN_ODD;
209else cairo_poly_mode=CAIRO_FILL_RULE_WINDING;
210
211cairo_set_fill_rule(cr,cairo_poly_mode);
212
213
214ofColor prevColor;
215if(shape.getUseShapeColor()){
216prevColor = currentStyle.color;
217}
218
219if(shape.isFilled()){
220if(shape.getUseShapeColor()){
221ofColor c = shape.getFillColor();
222c.a = shape.getFillColor().a;
223cairo_set_source_rgba(cr, (float)c.r/255.0, (float)c.g/255.0, (float)c.b/255.0, (float)c.a/255.0);
224}
225
226if(shape.hasOutline()){
227cairo_fill_preserve( cr );
228}else{
229cairo_fill(cr);
230}
231}
232if(shape.hasOutline()){
233float lineWidth = currentStyle.lineWidth;
234if(shape.getUseShapeColor()){
235ofColor c = shape.getStrokeColor();
236c.a = shape.getStrokeColor().a;
237cairo_set_source_rgba(cr, (float)c.r/255.0, (float)c.g/255.0, (float)c.b/255.0, (float)c.a/255.0);
238}
239cairo_set_line_width( cr, shape.getStrokeWidth() );
240cairo_stroke( cr );
241cairo_set_line_width( cr, lineWidth );
242}
243
244if(shape.getUseShapeColor()){
245const_cast<ofCairoRenderer*>(this)->setColor(prevColor);
246}
247}
248
249void ofCairoRenderer::draw(const ofPolyline & poly) const{
250cairo_new_path(cr);
251for(int i=0;i<(int)poly.size();i++){
252cairo_line_to(cr,poly.getVertices()[i].x,poly.getVertices()[i].y);
253}
254if(poly.isClosed())
255cairo_close_path(cr);
256cairo_stroke( cr );
257}
258
259void ofCairoRenderer::draw(const vector<glm::vec3> & vertexData, ofPrimitiveMode drawMode) const{
260if(vertexData.size()==0) return;
261ofCairoRenderer * mut_this = const_cast<ofCairoRenderer*>(this);
262mut_this->pushMatrix();
263
264cairo_matrix_t matrix;
265cairo_matrix_init_identity(&matrix);
266cairo_new_path(cr);
267//if(indices.getNumIndices()){
268
269int i = 1;
270auto v = transform(vertexData[0]);
271glm::vec3 v2;
272cairo_move_to(cr,v.x,v.y);
273if(drawMode==OF_PRIMITIVE_TRIANGLE_STRIP){
274v = transform(vertexData[1]);
275cairo_line_to(cr,v.x,v.y);
276v = transform(vertexData[2]);
277cairo_line_to(cr,v.x,v.y);
278i=2;
279}
280for(; i<(int)vertexData.size(); i++){
281v = transform(vertexData[i]);
282switch(drawMode){
283case(OF_PRIMITIVE_TRIANGLES):
284if((i+1)%3==0){
285cairo_line_to(cr,v.x,v.y);
286v2 = transform(vertexData[i-2]);
287cairo_line_to(cr,v2.x,v2.y);
288cairo_move_to(cr,v.x,v.y);
289}else if((i+3)%3==0){
290cairo_move_to(cr,v.x,v.y);
291}else{
292cairo_line_to(cr,v.x,v.y);
293}
294
295break;
296case(OF_PRIMITIVE_TRIANGLE_STRIP):
297v2 = transform(vertexData[i-2]);
298cairo_line_to(cr,v.x,v.y);
299cairo_line_to(cr,v2.x,v2.y);
300cairo_move_to(cr,v.x,v.y);
301break;
302case(OF_PRIMITIVE_TRIANGLE_FAN):
303/*triangles.addIndex((GLuint)0);
304triangles.addIndex((GLuint)1);
305triangles.addIndex((GLuint)2);
306for(int i = 2; i < primitive.getNumVertices()-1;i++){
307triangles.addIndex((GLuint)0);
308triangles.addIndex((GLuint)i);
309triangles.addIndex((GLuint)i+1);
310}*/
311break;
312default:break;
313}
314}
315
316cairo_move_to(cr,vertexData[vertexData.size()-1].x,vertexData[vertexData.size()-1].y);
317cairo_stroke( cr );
318mut_this->popMatrix();
319}
320
321
322glm::vec3 ofCairoRenderer::transform(glm::vec3 vec) const{
323if(!b3D) return vec;
324auto vec4 = projection * modelView * glm::vec4(vec, 1.0);
325vec = glm::vec3(vec4) / vec4.w;
326
327//vec.set(vec.x/vec.z*viewportRect.width*0.5-ofGetWidth()*0.5-viewportRect.x,vec.y/vec.z*viewportRect.height*0.5-ofGetHeight()*0.5-viewportRect.y);
328vec = {vec.x/vec.z*viewportRect.width*0.5, vec.y/vec.z*viewportRect.height*0.5, 0.f};
329return vec;
330}
331
332void ofCairoRenderer::draw(const ofMesh & primitive, ofPolyRenderMode mode, bool useColors, bool useTextures, bool useNormals) const{
333if(useColors || useTextures || useNormals){
334ofLogWarning("ofCairoRenderer") << "draw(): cairo mesh rendering doesn't support colors, textures, or normals. drawing wireframe ...";
335}
336if(primitive.getNumVertices() == 0){
337return;
338}
339if(primitive.getNumIndices() == 0){
340ofMesh indexedMesh = primitive;
341indexedMesh.setupIndicesAuto();
342draw(indexedMesh, mode, useColors, useTextures, useNormals);
343return;
344}
345cairo_new_path(cr);
346
347cairo_matrix_t matrix;
348cairo_matrix_init_identity(&matrix);
349cairo_new_path(cr);
350
351std::size_t i = 1;
352auto v = transform(primitive.getVertex(primitive.getIndex(0)));
353glm::vec3 v2;
354cairo_move_to(cr,v.x,v.y);
355if(primitive.getMode()==OF_PRIMITIVE_TRIANGLE_STRIP){
356v = transform(primitive.getVertex(primitive.getIndex(1)));
357cairo_line_to(cr,v.x,v.y);
358v = transform(primitive.getVertex(primitive.getIndex(2)));
359cairo_line_to(cr,v.x,v.y);
360i=2;
361}
362for(; i<primitive.getNumIndices(); i++){
363v = transform(primitive.getVertex(primitive.getIndex(i)));
364switch(primitive.getMode()){
365case(OF_PRIMITIVE_TRIANGLES):
366if((i+1)%3==0){
367cairo_line_to(cr,v.x,v.y);
368v2 = transform(primitive.getVertex(primitive.getIndex(i-2)));
369cairo_line_to(cr,v2.x,v2.y);
370cairo_move_to(cr,v.x,v.y);
371}else if((i+3)%3==0){
372cairo_move_to(cr,v.x,v.y);
373}else{
374cairo_line_to(cr,v.x,v.y);
375}
376
377break;
378case(OF_PRIMITIVE_TRIANGLE_STRIP):
379v2 = transform(primitive.getVertex(primitive.getIndex(i-2)));
380cairo_line_to(cr,v.x,v.y);
381cairo_line_to(cr,v2.x,v2.y);
382cairo_move_to(cr,v.x,v.y);
383break;
384case(OF_PRIMITIVE_TRIANGLE_FAN):
385/*triangles.addIndex((GLuint)0);
386triangles.addIndex((GLuint)1);
387triangles.addIndex((GLuint)2);
388for(int i = 2; i < primitive.getNumVertices()-1;i++){
389triangles.addIndex((GLuint)0);
390triangles.addIndex((GLuint)i);
391triangles.addIndex((GLuint)i+1);
392}*/
393break;
394default:break;
395}
396}
397
398cairo_move_to(cr,primitive.getVertex(primitive.getIndex(primitive.getNumIndices()-1)).x,primitive.getVertex(primitive.getIndex(primitive.getNumIndices()-1)).y);
399
400if(currentStyle.lineWidth>0){
401
402cairo_stroke( cr );
403}
404}
405
406//----------------------------------------------------------
407void ofCairoRenderer::draw( const of3dPrimitive& model, ofPolyRenderMode renderType ) const{
408
409const_cast<ofCairoRenderer*>(this)->pushMatrix();
410const_cast<ofCairoRenderer*>(this)->multMatrix(model.getGlobalTransformMatrix());
411
412const ofMesh& mesh = model.getMesh();
413draw( mesh, renderType );
414
415const_cast<ofCairoRenderer*>(this)->popMatrix();
416
417}
418
419void ofCairoRenderer::draw(const ofNode& node) const{
420const_cast<ofCairoRenderer*>(this)->pushMatrix();
421const_cast<ofCairoRenderer*>(this)->multMatrix(node.getGlobalTransformMatrix());
422node.customDraw(this);
423const_cast<ofCairoRenderer*>(this)->popMatrix();
424}
425
426void ofCairoRenderer::draw(const ofPath::Command & command) const{
427if(!surface || !cr) return;
428ofCairoRenderer * mut_this = const_cast<ofCairoRenderer*>(this);
429switch(command.type){
430case ofPath::Command::moveTo:
431curvePoints.clear();
432cairo_move_to(cr,command.to.x,command.to.y);
433break;
434
435case ofPath::Command::lineTo:
436curvePoints.clear();
437cairo_line_to(cr,command.to.x,command.to.y);
438break;
439
440
441case ofPath::Command::curveTo:
442curvePoints.push_back(command.to);
443
444//code adapted from ofxVectorGraphics to convert catmull rom to bezier
445if(curvePoints.size()==4){
446auto p1=curvePoints[0];
447auto p2=curvePoints[1];
448auto p3=curvePoints[2];
449auto p4=curvePoints[3];
450
451//SUPER WEIRD MAGIC CONSTANT = 1/6 (this works 100% can someone explain it?)
452auto cp1 = p2 + ( p3 - p1 ) * (1.0f/6.f);
453auto cp2 = p3 + ( p2 - p4 ) * (1.0f/6.f);
454
455cairo_curve_to( cr, cp1.x, cp1.y, cp2.x, cp2.y, p3.x, p3.y );
456curvePoints.pop_front();
457}
458break;
459
460
461case ofPath::Command::bezierTo:
462curvePoints.clear();
463cairo_curve_to(cr,command.cp1.x,command.cp1.y,command.cp2.x,command.cp2.y,command.to.x,command.to.y);
464break;
465
466case ofPath::Command::quadBezierTo:
467curvePoints.clear();
468cairo_curve_to(cr,command.cp1.x,command.cp1.y,command.cp2.x,command.cp2.y,command.to.x,command.to.y);
469break;
470
471
472case ofPath::Command::arc:
473curvePoints.clear();
474// elliptic arcs not directly supported in cairo, lets scale y
475if(command.radiusX!=command.radiusY){
476float ellipse_ratio = command.radiusY/command.radiusX;
477mut_this->pushMatrix();
478mut_this->translate(0,-command.to.y*ellipse_ratio);
479mut_this->scale(1,ellipse_ratio);
480mut_this->translate(0,command.to.y/ellipse_ratio);
481cairo_arc(cr,command.to.x, command.to.y, command.radiusX, ofDegToRad(command.angleBegin), ofDegToRad(command.angleEnd));
482//cairo_set_matrix(cr,&stored_matrix);
483mut_this->popMatrix();
484}else{
485cairo_arc(cr,command.to.x, command.to.y, command.radiusX, ofDegToRad(command.angleBegin), ofDegToRad(command.angleEnd));
486}
487break;
488
489case ofPath::Command::arcNegative:
490curvePoints.clear();
491// elliptic arcs not directly supported in cairo, lets scale y
492if(command.radiusX!=command.radiusY){
493float ellipse_ratio = command.radiusY/command.radiusX;
494mut_this->pushMatrix();
495mut_this->translate(0,-command.to.y*ellipse_ratio);
496mut_this->scale(1,ellipse_ratio);
497mut_this->translate(0,command.to.y/ellipse_ratio);
498cairo_arc_negative(cr,command.to.x, command.to.y, command.radiusX, ofDegToRad(command.angleBegin), ofDegToRad(command.angleEnd));
499//cairo_set_matrix(cr,&stored_matrix);
500mut_this->popMatrix();
501}else{
502cairo_arc_negative(cr,command.to.x, command.to.y, command.radiusX, ofDegToRad(command.angleBegin), ofDegToRad(command.angleEnd));
503}
504break;
505
506case ofPath::Command::close:
507cairo_close_path(cr);
508break;
509
510}
511
512
513}
514
515//--------------------------------------------
516void ofCairoRenderer::draw(const ofPixels & raw, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const{
517bool shouldCrop = sx != 0 || sy != 0 || sw != w || sh != h;
518ofPixels cropped;
519if(shouldCrop) {
520cropped.allocate(sw, sh, raw.getPixelFormat());
521raw.cropTo(cropped, sx, sy, sw, sh);
522}
523const ofPixels & pix = shouldCrop ? cropped : raw;
524
525ofCairoRenderer * mut_this = const_cast<ofCairoRenderer*>(this);
526mut_this->pushMatrix();
527mut_this->translate(x,y,z);
528mut_this->scale(w/pix.getWidth(),h/pix.getHeight());
529cairo_surface_t *image;
530int stride=0;
531int picsize = pix.getWidth()* pix.getHeight();
532const unsigned char *imgPix = pix.getData();
533
534vector<unsigned char> swapPixels;
535
536switch(pix.getImageType()){
537case OF_IMAGE_COLOR:
538#ifdef TARGET_LITTLE_ENDIAN
539swapPixels.resize(picsize * 4);
540
541for(int p= 0; p<picsize; p++) {
542swapPixels[p*4] = imgPix[p*3 +2];
543swapPixels[p*4 +1] = imgPix[p*3 +1];
544swapPixels[p*4 +2] = imgPix[p*3];
545}
546#else
547swapPixels.resize(picsize * 4);
548
549for(int p= 0; p<picsize; p++) {
550swapPixels[p*4] = imgPix[p*3];
551swapPixels[p*4 +1] = imgPix[p*3 +1];
552swapPixels[p*4 +2] = imgPix[p*3 +2];
553}
554#endif
555stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, pix.getWidth());
556image = cairo_image_surface_create_for_data(&swapPixels[0], CAIRO_FORMAT_RGB24, pix.getWidth(), pix.getHeight(), stride);
557break;
558case OF_IMAGE_COLOR_ALPHA:
559#ifdef TARGET_LITTLE_ENDIAN
560swapPixels.resize(picsize * 4);
561
562for(int p= 0; p<picsize; p++) {
563swapPixels[p*4] = imgPix[p*4+2];
564swapPixels[p*4 +1] = imgPix[p*4+1];
565swapPixels[p*4 +2] = imgPix[p*4];
566swapPixels[p*4 +3] = imgPix[p*4+3];
567}
568stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, pix.getWidth());
569image = cairo_image_surface_create_for_data(&swapPixels[0], CAIRO_FORMAT_ARGB32, pix.getWidth(), pix.getHeight(), stride);
570#else
571stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, pix.getWidth());
572image = cairo_image_surface_create_for_data(pix.getData(), CAIRO_FORMAT_ARGB32, pix.getWidth(), pix.getHeight(), stride);
573#endif
574break;
575case OF_IMAGE_GRAYSCALE:
576swapPixels.resize(picsize * 4);
577
578for(int p= 0; p<picsize; p++) {
579swapPixels[p*4] = imgPix[p];
580swapPixels[p*4 +1] = imgPix[p];
581swapPixels[p*4 +2] = imgPix[p];
582}
583stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, pix.getWidth());
584image = cairo_image_surface_create_for_data(&swapPixels[0], CAIRO_FORMAT_RGB24, pix.getWidth(), pix.getHeight(), stride);
585break;
586case OF_IMAGE_UNDEFINED:
587default:
588ofLogError("ofCairoRenderer") << "draw(): trying to draw undefined image type "
589<< ofToString(pix.getImageType());
590mut_this->popMatrix();
591return;
592break;
593}
594cairo_set_source_surface (cr, image, 0,0);
595cairo_paint (cr);
596cairo_surface_flush(image);
597cairo_surface_destroy (image);
598mut_this->popMatrix();
599}
600
601//--------------------------------------------
602void ofCairoRenderer::draw(const ofImage & img, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const{
603draw(img.getPixels(),x,y,z,w,h,sx,sy,sw,sh);
604}
605
606//--------------------------------------------
607void ofCairoRenderer::draw(const ofFloatImage & image, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const{
608ofPixels tmp = image.getPixels();
609draw(tmp,x,y,z,w,h,sx,sy,sw,sh);
610}
611
612//--------------------------------------------
613void ofCairoRenderer::draw(const ofShortImage & image, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const{
614ofPixels tmp = image.getPixels();
615draw(tmp,x,y,z,w,h,sx,sy,sw,sh);
616}
617
618//--------------------------------------------
619void ofCairoRenderer::draw(const ofBaseVideoDraws & video, float x, float y, float w, float h) const{
620draw(video.getPixels(),x,y,0,w,h,x,y,w,h);
621}
622
623ofPath & ofCairoRenderer::getPath(){
624return path;
625}
626
627//--------------------------------------------
628void ofCairoRenderer::setRectMode(ofRectMode mode){
629currentStyle.rectMode = mode;
630}
631
632//--------------------------------------------
633ofRectMode ofCairoRenderer::getRectMode(){
634return currentStyle.rectMode;
635}
636
637//--------------------------------------------
638void ofCairoRenderer::setFillMode(ofFillFlag fill){
639currentStyle.bFill = fill;
640if(currentStyle.bFill){
641path.setFilled(true);
642path.setStrokeWidth(0);
643}else{
644path.setFilled(false);
645path.setStrokeWidth(currentStyle.lineWidth);
646}
647}
648
649//--------------------------------------------
650ofFillFlag ofCairoRenderer::getFillMode(){
651if(currentStyle.bFill){
652return OF_FILLED;
653}else{
654return OF_OUTLINE;
655}
656}
657
658//--------------------------------------------
659void ofCairoRenderer::setLineWidth(float lineWidth){
660currentStyle.lineWidth = lineWidth;
661if(!currentStyle.bFill){
662path.setStrokeWidth(lineWidth);
663}
664cairo_set_line_width( cr, lineWidth );
665}
666
667//----------------------------------------------------------
668void ofCairoRenderer::setDepthTest(bool depthTest) {
669// cairo does not do any depth testing
670}
671
672//--------------------------------------------
673void ofCairoRenderer::setBlendMode(ofBlendMode blendMode){
674switch (blendMode){
675case OF_BLENDMODE_ALPHA:{
676cairo_set_operator(cr,CAIRO_OPERATOR_OVER);
677break;
678}
679
680case OF_BLENDMODE_ADD:{
681cairo_set_operator(cr,CAIRO_OPERATOR_ADD);
682break;
683}
684#if (CAIRO_VERSION_MAJOR==1 && CAIRO_VERSION_MINOR>=10) || CAIRO_VERSION_MAJOR>1
685case OF_BLENDMODE_MULTIPLY:{
686cairo_set_operator(cr,CAIRO_OPERATOR_MULTIPLY);
687break;
688}
689
690case OF_BLENDMODE_SCREEN:{
691cairo_set_operator(cr,CAIRO_OPERATOR_SCREEN);
692break;
693}
694
695case OF_BLENDMODE_SUBTRACT:{
696cairo_set_operator(cr,CAIRO_OPERATOR_DIFFERENCE);
697break;
698}
699#endif
700
701default:
702break;
703}
704}
705
706//--------------------------------------------
707void ofCairoRenderer::setLineSmoothing(bool smooth){
708
709}
710
711
712// color options
713//--------------------------------------------
714void ofCairoRenderer::setColor(int r, int g, int b){
715setColor(r,g,b,255);
716};
717
718//--------------------------------------------
719void ofCairoRenderer::setColor(int r, int g, int b, int a){
720cairo_set_source_rgba(cr, (float)r/255.0, (float)g/255.0, (float)b/255.0, (float)a/255.0);
721currentStyle.color.set(r,g,b,a);
722};
723
724//--------------------------------------------
725void ofCairoRenderer::setColor(const ofColor & c){
726setColor(c.r,c.g,c.b,c.a);
727};
728
729//--------------------------------------------
730void ofCairoRenderer::setColor(const ofColor & c, int _a){
731setColor(c.r,c.g,c.b,_a);
732};
733
734//--------------------------------------------
735void ofCairoRenderer::setColor(int gray){
736setColor(gray,gray,gray,255);
737};
738
739//--------------------------------------------
740void ofCairoRenderer::setHexColor( int hexColor ){
741int r = (hexColor >> 16) & 0xff;
742int g = (hexColor >> 8) & 0xff;
743int b = (hexColor >> 0) & 0xff;
744setColor(r,g,b);
745};
746
747//--------------------------------------------
748// transformations
749//our openGL wrappers
750glm::mat4 ofCairoRenderer::getCurrentMatrix(ofMatrixMode matrixMode_) const{
751ofLogWarning() << "getCurrentMatrix not yet implemented for Cairo Renderer.";
752return glm::mat4(1.0);
753}
754
755//----------------------------------------------------------
756void ofCairoRenderer::pushMatrix(){
757if(!surface || !cr) return;
758cairo_matrix_t matrix;
759cairo_get_matrix(cr,&matrix);
760matrixStack.push(matrix);
761
762if(!b3D) return;
763modelViewStack.push(modelView);
764}
765
766//----------------------------------------------------------
767void ofCairoRenderer::popMatrix(){
768if(!surface || !cr) return;
769cairo_set_matrix(cr,&matrixStack.top());
770matrixStack.pop();
771
772if(!b3D) return;
773modelView = modelViewStack.top();
774modelViewStack.pop();
775}
776
777//----------------------------------------------------------
778void ofCairoRenderer::translate(float x, float y, float z ){
779if(!surface || !cr) return;
780cairo_matrix_t matrix;
781cairo_get_matrix(cr,&matrix);
782cairo_matrix_translate(&matrix,x,y);
783cairo_set_matrix(cr,&matrix);
784
785if(!b3D) return;
786modelView = glm::translate(modelView, {x,y,z});
787
788}
789
790//----------------------------------------------------------
791void ofCairoRenderer::translate(const glm::vec3 & p){
792translate(p.x,p.y,p.z);
793}
794
795//----------------------------------------------------------
796void ofCairoRenderer::scale(float xAmnt, float yAmnt, float zAmnt ){
797if(!surface || !cr) return;
798// temporary fix for a issue where Cairo never recovers after setting scale = 0
799if (xAmnt == 0) xAmnt = std::numeric_limits<float>::epsilon();
800if (yAmnt == 0) yAmnt = std::numeric_limits<float>::epsilon();
801
802cairo_matrix_t matrix;
803cairo_get_matrix(cr,&matrix);
804cairo_matrix_scale(&matrix,xAmnt,yAmnt);
805cairo_set_matrix(cr,&matrix);
806
807if(!b3D) return;
808modelView = glm::scale(modelView, {xAmnt,yAmnt,zAmnt});
809}
810
811//----------------------------------------------------------
812void ofCairoRenderer::matrixMode(ofMatrixMode mode){
813currentMatrixMode = mode;
814}
815
816//----------------------------------------------------------
817void ofCairoRenderer::loadIdentityMatrix (void){
818if(!surface || !cr) return;
819if(currentMatrixMode==OF_MATRIX_MODELVIEW){
820cairo_matrix_t matrix;
821cairo_matrix_init_identity(&matrix);
822cairo_set_matrix(cr,&matrix);
823}
824
825if(!b3D) return;
826if(currentMatrixMode==OF_MATRIX_MODELVIEW){
827modelView = glm::mat4(1.0);
828}else if(currentMatrixMode==OF_MATRIX_PROJECTION){
829projection = glm::mat4(1.0);
830}
831}
832
833//----------------------------------------------------------
834void ofCairoRenderer::loadMatrix (const glm::mat4 & m){
835if(!surface || !cr) return;
836if(!b3D) return;
837if(currentMatrixMode==OF_MATRIX_MODELVIEW){
838modelView = m;
839}else if(currentMatrixMode==OF_MATRIX_PROJECTION){
840projection = m;
841}
842}
843
844//----------------------------------------------------------
845void ofCairoRenderer::loadMatrix (const float * m){
846loadMatrix(glm::make_mat4(m));
847}
848
849//----------------------------------------------------------
850void ofCairoRenderer::multMatrix (const glm::mat4 & m){
851if(!surface || !cr) return;
852if(!b3D) return;
853if(currentMatrixMode==OF_MATRIX_MODELVIEW){
854modelView = m * modelView;
855}else if(currentMatrixMode==OF_MATRIX_PROJECTION){
856projection = m * projection;
857}
858}
859
860//----------------------------------------------------------
861void ofCairoRenderer::multMatrix (const float * m){
862multMatrix(glm::make_mat4(m));
863}
864
865//----------------------------------------------------------
866void ofCairoRenderer::rotateRad(float radians, float vecX, float vecY, float vecZ){
867if(!surface || !cr) return;
868
869// we can only do Z-axis rotations via cairo_matrix_rotate.
870if(vecZ == 1.0f) {
871cairo_matrix_t matrix;
872cairo_get_matrix(cr,&matrix);
873cairo_matrix_rotate(&matrix,radians);
874cairo_set_matrix(cr,&matrix);
875}
876
877if(!b3D) return;
878modelView = glm::rotate(modelView, radians, glm::vec3(vecX,vecY,vecZ));
879}
880
881//----------------------------------------------------------
882void ofCairoRenderer::rotateXRad(float radians){
883rotateRad(radians,1,0,0);
884}
885//----------------------------------------------------------
886void ofCairoRenderer::rotateYRad(float radians){
887rotateRad(radians,0,1,0);
888}
889
890//----------------------------------------------------------
891void ofCairoRenderer::rotateZRad(float radians){
892rotateRad(radians,0,0,1);
893}
894
895//----------------------------------------------------------
896void ofCairoRenderer::rotateRad(float radians){
897rotateZRad(radians);
898}
899
900//----------------------------------------------------------
901void ofCairoRenderer::setupScreen(){
902if(!surface || !cr) return;
903
904setupScreenPerspective(); // assume defaults
905}
906
907//----------------------------------------------------------
908// screen coordinate things / default gl values
909void ofCairoRenderer::pushView(){
910viewportStack.push(viewportRect);
911}
912
913//----------------------------------------------------------
914void ofCairoRenderer::popView(){
915viewportRect = viewportStack.top();
916viewportStack.pop();
917};
918
919//----------------------------------------------------------
920// setup matrices and viewport (upto you to push and pop view before and after)
921// if width or height are 0, assume windows dimensions (ofGetWidth(), ofGetHeight())
922// if nearDist or farDist are 0 assume defaults (calculated based on width / height)
923void ofCairoRenderer::viewport(ofRectangle v){
924viewport(v.x,v.y,v.width,v.height);
925}
926
927//----------------------------------------------------------
928void ofCairoRenderer::viewport(float x, float y, float width, float height, bool invertY){
929if(width < 0) width = originalViewport.width;
930if(height < 0) height = originalViewport.height;
931ofLogVerbose("ofCairoRenderer::viewport") << "Setting viewport to: " << width << ", " << height;
932
933if (invertY){
934y = -y;
935}
936
937
938viewportRect.set(x, y, width, height);
939
940cairo_reset_clip(cr);
941cairo_new_path(cr);
942cairo_move_to(cr,viewportRect.x,viewportRect.y);
943cairo_line_to(cr,viewportRect.x+viewportRect.width,viewportRect.y);
944cairo_line_to(cr,viewportRect.x+viewportRect.width,viewportRect.y+viewportRect.height);
945cairo_line_to(cr,viewportRect.x,viewportRect.y+viewportRect.height);
946cairo_clip(cr);
947};
948
949//----------------------------------------------------------
950void ofCairoRenderer::setupScreenPerspective(float width, float height, float fov, float nearDist, float farDist){
951if(!b3D) return;
952if(width < 0) width = originalViewport.width;
953if(height < 0) height = originalViewport.height;
954ofOrientation orientation = ofGetOrientation();
955
956float viewW = originalViewport.width;
957float viewH = originalViewport.height;
958
959float eyeX = viewW / 2;
960float eyeY = viewH / 2;
961float halfFov = glm::pi<float>() * fov / 360.0f;
962float theTan = tanf(halfFov);
963float dist = eyeY / theTan;
964float aspect = (float) viewW / viewH;
965
966if(nearDist == 0) nearDist = dist / 10.0f;
967if(farDist == 0) farDist = dist * 10.0f;
968
969projection = glm::perspective(ofDegToRad(fov),aspect,nearDist,farDist);
970modelView = glm::lookAt(glm::vec3(eyeX,eyeY,dist),glm::vec3(eyeX,eyeY,0),glm::vec3(0,1,0));
971
972
973switch(orientation) {
974case OF_ORIENTATION_180:
975modelView = glm::rotate(modelView,-glm::pi<float>(),glm::vec3(0,0,1));
976if(isVFlipped()){
977modelView = glm::scale(modelView, glm::vec3(-1,1,1));
978modelView = glm::translate(modelView, glm::vec3(width,0,0));
979}else{
980modelView = glm::translate(modelView, glm::vec3(width, -height, 0));
981}
982
983break;
984
985case OF_ORIENTATION_90_RIGHT:
986modelView = glm::rotate(modelView,-glm::half_pi<float>(),glm::vec3(0,0,1));
987if(!isVFlipped()){
988modelView = glm::scale(modelView, glm::vec3(1,-1,1));
989modelView = glm::translate(modelView, glm::vec3(-width,-height,0));
990}
991break;
992
993case OF_ORIENTATION_90_LEFT:
994modelView = glm::rotate(modelView,glm::half_pi<float>(),glm::vec3(0,0,1));
995if(isVFlipped()){
996modelView = glm::translate(modelView, glm::vec3(0,-height,0));
997}else{
998modelView = glm::scale(modelView, glm::vec3(1,-1,1));
999}
1000break;
1001
1002case OF_ORIENTATION_DEFAULT:
1003default:
1004if(isVFlipped()){
1005modelView = glm::scale(modelView, glm::vec3(-1,-1,1));
1006modelView = glm::translate(modelView, glm::vec3(-width,-height,0));
1007}
1008break;
1009}
1010};
1011
1012//----------------------------------------------------------
1013void ofCairoRenderer::setupScreenOrtho(float width, float height, float nearDist, float farDist){
1014if(!b3D) return;
1015if(width < 0) width = viewportRect.width;
1016if(height < 0) height = viewportRect.height;
1017ofOrientation orientation = ofGetOrientation();
1018
1019float viewW = viewportRect.width;
1020float viewH = viewportRect.height;
1021
1022ofSetCoordHandedness(OF_RIGHT_HANDED);
1023
1024if(isVFlipped()) {
1025ofSetCoordHandedness(OF_LEFT_HANDED);
1026}
1027projection = glm::ortho(0.f, viewW, 0.f, viewH, nearDist, farDist);
1028
1029modelView = glm::mat4(1.0f);
1030
1031switch(orientation) {
1032case OF_ORIENTATION_180:
1033modelView = glm::rotate(modelView,-glm::pi<float>(),glm::vec3(0,0,1));
1034if(isVFlipped()){
1035modelView = glm::scale(modelView, glm::vec3(-1,1,1));
1036modelView = glm::translate(modelView, glm::vec3(width,0,0));
1037}else{
1038modelView = glm::translate(modelView, glm::vec3(width, -height, 0));
1039}
1040
1041break;
1042
1043case OF_ORIENTATION_90_RIGHT:
1044modelView = glm::rotate(modelView,-glm::half_pi<float>(),glm::vec3(0,0,1));
1045if(!isVFlipped()){
1046modelView = glm::scale(modelView, glm::vec3(1,-1,1));
1047modelView = glm::translate(modelView, glm::vec3(-width,-height,0));
1048}
1049break;
1050
1051case OF_ORIENTATION_90_LEFT:
1052modelView = glm::rotate(modelView,glm::half_pi<float>(),glm::vec3(0,0,1));
1053if(isVFlipped()){
1054modelView = glm::translate(modelView, glm::vec3(0,-height,0));
1055}else{
1056modelView = glm::scale(modelView, glm::vec3(1,-1,1));
1057}
1058break;
1059
1060case OF_ORIENTATION_DEFAULT:
1061default:
1062if(isVFlipped()){
1063modelView = glm::scale(modelView, glm::vec3(-1,-1,1));
1064modelView = glm::translate(modelView, glm::vec3(-width,-height,0));
1065}
1066break;
1067}
1068};
1069
1070//----------------------------------------------------------
1071ofRectangle ofCairoRenderer::getCurrentViewport() const{
1072return viewportRect;
1073};
1074
1075//----------------------------------------------------------
1076ofRectangle ofCairoRenderer::getNativeViewport() const{
1077return viewportRect;
1078};
1079
1080//----------------------------------------------------------
1081int ofCairoRenderer::getViewportWidth() const{
1082return viewportRect.width;
1083};
1084
1085//----------------------------------------------------------
1086int ofCairoRenderer::getViewportHeight() const{
1087return viewportRect.height;
1088};
1089
1090//----------------------------------------------------------
1091void ofCairoRenderer::setOrientation(ofOrientation orientation, bool vFlip){
1092ofLogError("ofCairoRenderer") << "orientation not supported yet";
1093}
1094
1095//----------------------------------------------------------
1096bool ofCairoRenderer::isVFlipped() const{
1097return true;
1098}
1099
1100//----------------------------------------------------------
1101void ofCairoRenderer::loadViewMatrix(const glm::mat4 & m){
1102ofLogError("ofCairoRenderer") << "view matrix not supported yet";
1103}
1104
1105//----------------------------------------------------------
1106void ofCairoRenderer::multViewMatrix(const glm::mat4 & m){
1107ofLogError("ofCairoRenderer") << "view matrix not supported yet";
1108}
1109
1110//----------------------------------------------------------
1111glm::mat4 ofCairoRenderer::getCurrentViewMatrix() const{
1112ofLogError("ofCairoRenderer") << "view matrix not supported yet";
1113return glm::mat4(1.0);
1114}
1115
1116//----------------------------------------------------------
1117glm::mat4 ofCairoRenderer::getCurrentNormalMatrix() const{
1118ofLogError("ofCairoRenderer") << "normal matrix not supported yet";
1119return glm::mat4(1.0);
1120}
1121
1122//----------------------------------------------------------
1123glm::mat4 ofCairoRenderer::getCurrentOrientationMatrix() const{
1124ofLogError("ofCairoRenderer") << "orientation matrix not supported yet";
1125return glm::mat4(1.0);
1126}
1127
1128//----------------------------------------------------------
1129void ofCairoRenderer::setCircleResolution(int){
1130
1131}
1132
1133void ofCairoRenderer::setPolyMode(ofPolyWindingMode mode){
1134currentStyle.polyMode = mode;
1135path.setPolyWindingMode(mode);
1136}
1137
1138//----------------------------------------------------------
1139void ofCairoRenderer::setCoordHandedness(ofHandednessType handedness){
1140
1141};
1142
1143//----------------------------------------------------------
1144ofHandednessType ofCairoRenderer::getCoordHandedness() const{
1145return OF_LEFT_HANDED;
1146};
1147
1148//----------------------------------------------------------
1149void ofCairoRenderer::setupGraphicDefaults(){
1150setStyle(ofStyle());
1151path.setMode(ofPath::COMMANDS);
1152path.setUseShapeColor(false);
1153clear();
1154
1155cairo_matrix_t matrix;
1156cairo_matrix_init_scale(&matrix, 1.0, 1.0);
1157cairo_matrix_init_translate(&matrix, 0.0, 0.0);
1158cairo_set_matrix(cr,&matrix);
1159};
1160
1161//----------------------------------------------------------
1162void ofCairoRenderer::clear(){
1163if(!surface || ! cr) return;
1164cairo_set_source_rgba(cr,currentStyle.bgColor.r/255., currentStyle.bgColor.g/255., currentStyle.bgColor.b/255., currentStyle.bgColor.a/255.);
1165cairo_paint(cr);
1166setColor(currentStyle.color);
1167}
1168
1169//----------------------------------------------------------
1170void ofCairoRenderer::clear(float r, float g, float b, float a) {
1171if(!surface || ! cr) return;
1172cairo_set_source_rgba(cr,r/255., g/255., b/255., a/255.);
1173cairo_paint(cr);
1174setColor(currentStyle.color);
1175
1176}
1177
1178//----------------------------------------------------------
1179void ofCairoRenderer::clear(float brightness, float a) {
1180clear(brightness, brightness, brightness, a);
1181}
1182
1183//----------------------------------------------------------
1184void ofCairoRenderer::clearAlpha() {
1185}
1186
1187
1188void ofCairoRenderer::setBitmapTextMode(ofDrawBitmapMode mode){
1189currentStyle.drawBitmapMode = mode;
1190}
1191
1192ofStyle ofCairoRenderer::getStyle() const{
1193return currentStyle;
1194}
1195
1196void ofCairoRenderer::pushStyle(){
1197styleHistory.push_back(currentStyle);
1198//if we are over the max number of styles we have set, then delete the oldest styles.
1199if( styleHistory.size() > OF_MAX_STYLE_HISTORY ){
1200styleHistory.pop_front();
1201//should we warn here?
1202ofLogWarning("ofGraphics") << "ofPushStyle(): maximum number of style pushes << " << OF_MAX_STYLE_HISTORY << " reached, did you forget to pop somewhere?";
1203}
1204}
1205
1206void ofCairoRenderer::popStyle(){
1207if( styleHistory.size() ){
1208setStyle(styleHistory.back());
1209styleHistory.pop_back();
1210}
1211}
1212
1213//----------------------------------------------------------
1214void ofCairoRenderer::setBackgroundAuto(bool bAuto){
1215bBackgroundAuto = bAuto;
1216}
1217
1218//----------------------------------------------------------
1219bool ofCairoRenderer::getBackgroundAuto(){
1220return bBackgroundAuto;
1221}
1222
1223//----------------------------------------------------------
1224void ofCairoRenderer::setBackgroundColor(const ofColor & c){
1225currentStyle.bgColor = c;
1226}
1227
1228//----------------------------------------------------------
1229ofColor ofCairoRenderer::getBackgroundColor(){
1230return currentStyle.bgColor;
1231}
1232
1233//----------------------------------------------------------
1234void ofCairoRenderer::background(const ofColor & c){
1235setBackgroundColor(c);
1236clear(c.r,c.g,c.b,c.a);
1237}
1238
1239//----------------------------------------------------------
1240void ofCairoRenderer::background(float brightness) {
1241background(ofColor(brightness));
1242}
1243
1244//----------------------------------------------------------
1245void ofCairoRenderer::background(int hexColor, float _a){
1246background ( (hexColor >> 16) & 0xff, (hexColor >> 8) & 0xff, (hexColor >> 0) & 0xff, _a);
1247}
1248
1249//----------------------------------------------------------
1250void ofCairoRenderer::background(int r, int g, int b, int a){
1251background(ofColor(r,g,b,a));
1252}
1253
1254
1255//----------------------------------------------------------
1256void ofCairoRenderer::drawLine(float x1, float y1, float z1, float x2, float y2, float z2) const{
1257cairo_new_path(cr);
1258cairo_move_to(cr,x1,y1);
1259cairo_line_to(cr,x2,y2);
1260
1261cairo_stroke( cr );
1262}
1263
1264//----------------------------------------------------------
1265void ofCairoRenderer::drawRectangle(float x, float y, float z, float w, float h) const{
1266
1267cairo_new_path(cr);
1268
1269if (currentStyle.rectMode == OF_RECTMODE_CORNER){
1270cairo_move_to(cr,x,y);
1271cairo_line_to(cr,x+w, y);
1272cairo_line_to(cr,x+w, y+h);
1273cairo_line_to(cr,x, y+h);
1274}else{
1275cairo_move_to(cr,x-w/2.0f, y-h/2.0f);
1276cairo_line_to(cr,x+w/2.0f, y-h/2.0f);
1277cairo_line_to(cr,x+w/2.0f, y+h/2.0f);
1278cairo_line_to(cr,x-w/2.0f, y+h/2.0f);
1279}
1280
1281cairo_close_path(cr);
1282
1283if(currentStyle.bFill==OF_FILLED){
1284cairo_fill( cr );
1285}else{
1286cairo_stroke( cr );
1287}
1288}
1289
1290//----------------------------------------------------------
1291void ofCairoRenderer::drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3) const{
1292cairo_new_path(cr);
1293
1294cairo_move_to(cr, x1, y1);
1295cairo_line_to(cr, x2, y2);
1296cairo_line_to(cr, x3, y3);
1297
1298
1299cairo_close_path(cr);
1300
1301if(currentStyle.bFill==OF_FILLED){
1302cairo_fill( cr );
1303}else{
1304cairo_stroke( cr );
1305}
1306}
1307
1308//----------------------------------------------------------
1309void ofCairoRenderer::drawCircle(float x, float y, float z, float radius) const{
1310cairo_new_path(cr);
1311cairo_arc(cr, x, y, radius, 0, glm::two_pi<float>());
1312
1313cairo_close_path(cr);
1314
1315if(currentStyle.bFill==OF_FILLED){
1316cairo_fill( cr );
1317}else{
1318cairo_stroke( cr );
1319}
1320}
1321
1322//----------------------------------------------------------
1323void ofCairoRenderer::enableAntiAliasing(){
1324cairo_set_antialias(cr,CAIRO_ANTIALIAS_SUBPIXEL);
1325}
1326
1327//----------------------------------------------------------
1328void ofCairoRenderer::disableAntiAliasing(){
1329cairo_set_antialias(cr,CAIRO_ANTIALIAS_NONE);
1330}
1331
1332//----------------------------------------------------------
1333void ofCairoRenderer::drawEllipse(float x, float y, float z, float width, float height) const{
1334ofCairoRenderer * mutThis = const_cast<ofCairoRenderer*>(this);
1335cairo_new_path(cr);
1336float ellipse_ratio = height/width;
1337mutThis->pushMatrix();
1338mutThis->translate(0,-y*ellipse_ratio);
1339mutThis->scale(1,ellipse_ratio);
1340mutThis->translate(0,y/ellipse_ratio);
1341cairo_arc(cr, x, y, width*0.5, 0, glm::two_pi<float>());
1342mutThis->popMatrix();
1343
1344cairo_close_path(cr);
1345
1346
1347if(currentStyle.bFill==OF_FILLED){
1348cairo_fill( cr );
1349}else{
1350cairo_stroke( cr );
1351}
1352}
1353
1354void ofCairoRenderer::drawString(string text, float x, float y, float z) const{
1355cairo_select_font_face (cr, "Mono", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
1356cairo_set_font_size (cr, 10);
1357vector<string> lines = ofSplitString(text, "\n");
1358for(int i=0;i<(int)lines.size();i++){
1359cairo_move_to (cr, x, y+i*14.3);
1360cairo_show_text (cr, lines[i].c_str() );
1361}
1362}
1363
1364void ofCairoRenderer::drawString(const ofTrueTypeFont & font, string text, float x, float y) const{
1365font.drawStringAsShapes(text,x,y);
1366}
1367
1368cairo_t * ofCairoRenderer::getCairoContext(){
1369return cr;
1370}
1371
1372cairo_surface_t * ofCairoRenderer::getCairoSurface(){
1373return surface;
1374}
1375
1376ofPixels & ofCairoRenderer::getImageSurfacePixels(){
1377if(type!=IMAGE){
1378ofLogError("ofCairoRenderer") << "getImageSurfacePixels(): can only get pixels from image surface";
1379}
1380return imageBuffer;
1381}
1382
1383ofBuffer & ofCairoRenderer::getContentBuffer(){
1384if(filename!="" || (type!=SVG && type!=PDF)){
1385ofLogError("ofCairoRenderer") << "getContentBuffer(): can only get buffer from memory allocated renderer for svg or pdf";
1386}
1387return streamBuffer;
1388}
1389
1390const of3dGraphics & ofCairoRenderer::get3dGraphics() const{
1391return graphics3d;
1392}
1393
1394of3dGraphics & ofCairoRenderer::get3dGraphics(){
1395return graphics3d;
1396}
1397