framework2

Форк
0
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

11
using std::vector;
12
using std::string;
13

14
const 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);
18
	return CAIRO_STATUS_SUCCESS;
19
}
20

21
ofCairoRenderer::ofCairoRenderer()
22
:graphics3d(this)
23
,projection(1)
24
,modelView(1)
25
{
26
	type = PDF;
27
	surface = nullptr;
28
	cr = nullptr;
29
	bBackgroundAuto = true;
30
	page = 0;
31
	multiPage = false;
32
	b3D = false;
33
	currentMatrixMode=OF_MATRIX_MODELVIEW;
34
}
35

36
ofCairoRenderer::~ofCairoRenderer(){
37
	close();
38
}
39

40
void ofCairoRenderer::setup(const of::filesystem::path & _filename, Type _type, bool multiPage_, bool b3D_, ofRectangle outputsize){
41
	if( outputsize.width == 0 || outputsize.height == 0 ){
42
		outputsize.set(0, 0, ofGetViewportWidth(), ofGetViewportHeight());
43
	}
44

45
	filename = _filename;
46
	type = _type;
47
	streamBuffer.clear();
48

49
	if(type == FROM_FILE_EXTENSION){
50
		auto ext = filename.extension();
51
		if(ext == of::filesystem::path{".svg"} || ext == of::filesystem::path{".SVG"} ){
52
			type = SVG;
53
		}else if(ext == of::filesystem::path {".pdf"} || ext == of::filesystem::path{".PDF"} ){
54
			type = PDF;
55
		}else{ // default to image
56
			type = IMAGE;
57
		}
58
	}
59

60
	if(filename != "") {
61
		switch(type) {
62
			case PDF:
63
			case SVG:
64
			case IMAGE:
65
				ofFilePath::createEnclosingDirectory(filename);
66
			case FROM_FILE_EXTENSION:
67
				break;
68
		}
69
	}
70

71
	switch(type){
72
	case PDF:
73
		if(filename==""){
74
			surface = 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()
77
			surface = cairo_pdf_surface_create(ofToDataPath(filename).c_str(),outputsize.width, outputsize.height);
78
		}
79
		break;
80
	case SVG:
81
		if(filename==""){
82
			surface = 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()
85
			surface = cairo_svg_surface_create(ofToDataPath(filename).c_str(),outputsize.width, outputsize.height);
86
		}
87
		break;
88
	case IMAGE:
89
		imageBuffer.allocate(outputsize.width, outputsize.height, OF_PIXELS_BGRA);
90
		imageBuffer.set(0);
91
		surface = cairo_image_surface_create_for_data(imageBuffer.getData(),CAIRO_FORMAT_ARGB32,outputsize.width, outputsize.height,outputsize.width*4);
92
		break;
93
	case FROM_FILE_EXTENSION:
94
		ofLogFatalError("ofCairoRenderer") << "setup(): couldn't determine type from extension for filename: \"" << _filename << "\"!";
95
		break;
96
	default:
97
		ofLogError("ofCairoRenderer") << "setup(): encountered unknown type for filename \"" << _filename << "\"";
98
		break;
99
	}
100

101
	cr = cairo_create(surface);
102
	cairo_set_antialias(cr,CAIRO_ANTIALIAS_SUBPIXEL);
103
	viewportRect = outputsize;
104
	originalViewport = outputsize;
105
	viewport(viewportRect);
106
	page = 0;
107
	b3D = b3D_;
108
	multiPage = multiPage_;
109
	setupGraphicDefaults();
110
}
111

112
void ofCairoRenderer::setupMemoryOnly(Type _type, bool multiPage_, bool b3D_, ofRectangle outputsize){
113
	setup("",_type,multiPage_,b3D_,outputsize);
114
}
115

116
void ofCairoRenderer::flush(){
117
	if(surface){
118
		cairo_surface_flush(surface);
119
	}
120
}
121

122
void ofCairoRenderer::close(){
123
	if(surface){
124
		cairo_surface_flush(surface);
125
		if(type==IMAGE && filename!=""){
126
			ofSaveImage(imageBuffer,filename);
127
		}
128
		cairo_surface_finish(surface);
129
		cairo_surface_destroy(surface);
130
		surface = nullptr;
131
	}
132
	if(cr){
133
		cairo_destroy(cr);
134
		cr = nullptr;
135
	}
136
}
137

138

139
void ofCairoRenderer::startRender(){
140
	setStyle(currentStyle);
141
	if(page==0 || !multiPage){
142
		page=1;
143
	}else{
144
		page++;
145
		if(getBackgroundAuto()){
146
			cairo_show_page(cr);
147
			clear();
148
		}else{
149
			cairo_copy_page(cr);
150
		}
151
	}
152
}
153

154
void ofCairoRenderer::finishRender(){
155
	cairo_surface_flush(surface);
156
}
157

158
void ofCairoRenderer::setStyle(const ofStyle & style){
159
	//color
160
	setColor((int)style.color.r, (int)style.color.g, (int)style.color.b, (int)style.color.a);
161

162
	//bg color
163
	setBackgroundColor(style.bgColor);
164

165
	//circle resolution - don't worry it only recalculates the display list if the res has changed
166
	setCircleResolution(style.circleResolution);
167

168
	setSphereResolution(style.sphereResolution);
169

170
	setCurveResolution(style.curveResolution);
171

172
	//line width - finally!
173
	setLineWidth(style.lineWidth);
174

175
	//rect mode: corner/center
176
	setRectMode(style.rectMode);
177

178
	//poly mode: winding type
179
	setPolyMode(style.polyMode);
180

181
	//fill
182
	setFillMode(style.bFill?OF_FILLED:OF_OUTLINE);
183

184
	//smoothing
185
	//setSmoothingEnabled(style.smoothing);
186

187
	//blending
188
	setBlendMode(style.blendingMode);
189

190
	//bitmap draw mode
191
	//setDrawBitmapMode(style.drawBitmapMode);
192
	currentStyle = style;
193
}
194

195
void ofCairoRenderer::setCurveResolution(int resolution){
196
	currentStyle.curveResolution = resolution;
197
	path.setCurveResolution(resolution);
198
}
199

200
void ofCairoRenderer::draw(const ofPath & shape) const{
201
	cairo_new_path(cr);
202
	const vector<ofPath::Command> & commands = shape.getCommands();
203
	for(int i=0;i<(int)commands.size();i++){
204
		draw(commands[i]);
205
	}
206

207
	cairo_fill_rule_t cairo_poly_mode;
208
	if(shape.getWindingMode()==OF_POLY_WINDING_ODD) cairo_poly_mode=CAIRO_FILL_RULE_EVEN_ODD;
209
	else cairo_poly_mode=CAIRO_FILL_RULE_WINDING;
210

211
	cairo_set_fill_rule(cr,cairo_poly_mode);
212

213

214
	ofColor prevColor;
215
	if(shape.getUseShapeColor()){
216
		prevColor = currentStyle.color;
217
	}
218

219
	if(shape.isFilled()){
220
		if(shape.getUseShapeColor()){
221
			ofColor c = shape.getFillColor();
222
			c.a = shape.getFillColor().a;
223
			cairo_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

226
		if(shape.hasOutline()){
227
			cairo_fill_preserve( cr );
228
		}else{
229
			cairo_fill(cr);
230
		}
231
	}
232
	if(shape.hasOutline()){
233
		float lineWidth = currentStyle.lineWidth;
234
		if(shape.getUseShapeColor()){
235
			ofColor c = shape.getStrokeColor();
236
			c.a = shape.getStrokeColor().a;
237
			cairo_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
		}
239
		cairo_set_line_width( cr, shape.getStrokeWidth() );
240
		cairo_stroke( cr );
241
		cairo_set_line_width( cr, lineWidth );
242
	}
243

244
	if(shape.getUseShapeColor()){
245
		const_cast<ofCairoRenderer*>(this)->setColor(prevColor);
246
	}
247
}
248

249
void ofCairoRenderer::draw(const ofPolyline & poly) const{
250
	cairo_new_path(cr);
251
	for(int i=0;i<(int)poly.size();i++){
252
		cairo_line_to(cr,poly.getVertices()[i].x,poly.getVertices()[i].y);
253
	}
254
	if(poly.isClosed())
255
		cairo_close_path(cr);
256
	cairo_stroke( cr );
257
}
258

259
void ofCairoRenderer::draw(const vector<glm::vec3> & vertexData, ofPrimitiveMode drawMode) const{
260
	if(vertexData.size()==0) return;
261
	ofCairoRenderer * mut_this = const_cast<ofCairoRenderer*>(this);
262
	mut_this->pushMatrix();
263

264
	cairo_matrix_t matrix;
265
	cairo_matrix_init_identity(&matrix);
266
	cairo_new_path(cr);
267
	//if(indices.getNumIndices()){
268

269
		int i = 1;
270
		auto v = transform(vertexData[0]);
271
		glm::vec3 v2;
272
		cairo_move_to(cr,v.x,v.y);
273
		if(drawMode==OF_PRIMITIVE_TRIANGLE_STRIP){
274
			v = transform(vertexData[1]);
275
			cairo_line_to(cr,v.x,v.y);
276
			v = transform(vertexData[2]);
277
			cairo_line_to(cr,v.x,v.y);
278
			i=2;
279
		}
280
		for(; i<(int)vertexData.size(); i++){
281
			v = transform(vertexData[i]);
282
			switch(drawMode){
283
			case(OF_PRIMITIVE_TRIANGLES):
284
				if((i+1)%3==0){
285
					cairo_line_to(cr,v.x,v.y);
286
					v2 = transform(vertexData[i-2]);
287
					cairo_line_to(cr,v2.x,v2.y);
288
					cairo_move_to(cr,v.x,v.y);
289
				}else if((i+3)%3==0){
290
					cairo_move_to(cr,v.x,v.y);
291
				}else{
292
					cairo_line_to(cr,v.x,v.y);
293
				}
294

295
			break;
296
			case(OF_PRIMITIVE_TRIANGLE_STRIP):
297
					v2 = transform(vertexData[i-2]);
298
					cairo_line_to(cr,v.x,v.y);
299
					cairo_line_to(cr,v2.x,v2.y);
300
					cairo_move_to(cr,v.x,v.y);
301
			break;
302
			case(OF_PRIMITIVE_TRIANGLE_FAN):
303
					/*triangles.addIndex((GLuint)0);
304
						triangles.addIndex((GLuint)1);
305
						triangles.addIndex((GLuint)2);
306
						for(int i = 2; i < primitive.getNumVertices()-1;i++){
307
							triangles.addIndex((GLuint)0);
308
							triangles.addIndex((GLuint)i);
309
							triangles.addIndex((GLuint)i+1);
310
						}*/
311
			break;
312
			default:break;
313
			}
314
		}
315

316
	cairo_move_to(cr,vertexData[vertexData.size()-1].x,vertexData[vertexData.size()-1].y);
317
	cairo_stroke( cr );
318
	mut_this->popMatrix();
319
}
320

321

322
glm::vec3 ofCairoRenderer::transform(glm::vec3 vec) const{
323
	if(!b3D) return vec;
324
	auto vec4 = projection * modelView * glm::vec4(vec, 1.0);
325
	vec = 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);
328
	vec = {vec.x/vec.z*viewportRect.width*0.5, vec.y/vec.z*viewportRect.height*0.5, 0.f};
329
	return vec;
330
}
331

332
void ofCairoRenderer::draw(const ofMesh & primitive, ofPolyRenderMode mode, bool useColors, bool useTextures, bool useNormals) const{
333
    if(useColors || useTextures || useNormals){
334
        ofLogWarning("ofCairoRenderer") << "draw(): cairo mesh rendering doesn't support colors, textures, or normals. drawing wireframe ...";
335
    }
336
	if(primitive.getNumVertices() == 0){
337
		return;
338
	}
339
	if(primitive.getNumIndices() == 0){
340
		ofMesh indexedMesh = primitive;
341
		indexedMesh.setupIndicesAuto();
342
		draw(indexedMesh, mode, useColors, useTextures, useNormals);
343
		return;
344
	}
345
	cairo_new_path(cr);
346

347
	cairo_matrix_t matrix;
348
	cairo_matrix_init_identity(&matrix);
349
	cairo_new_path(cr);
350

351
	std::size_t i = 1;
352
	auto v = transform(primitive.getVertex(primitive.getIndex(0)));
353
	glm::vec3 v2;
354
	cairo_move_to(cr,v.x,v.y);
355
	if(primitive.getMode()==OF_PRIMITIVE_TRIANGLE_STRIP){
356
		v = transform(primitive.getVertex(primitive.getIndex(1)));
357
		cairo_line_to(cr,v.x,v.y);
358
		v = transform(primitive.getVertex(primitive.getIndex(2)));
359
		cairo_line_to(cr,v.x,v.y);
360
		i=2;
361
	}
362
	for(; i<primitive.getNumIndices(); i++){
363
		v = transform(primitive.getVertex(primitive.getIndex(i)));
364
		switch(primitive.getMode()){
365
		case(OF_PRIMITIVE_TRIANGLES):
366
			if((i+1)%3==0){
367
				cairo_line_to(cr,v.x,v.y);
368
				v2 = transform(primitive.getVertex(primitive.getIndex(i-2)));
369
				cairo_line_to(cr,v2.x,v2.y);
370
				cairo_move_to(cr,v.x,v.y);
371
			}else if((i+3)%3==0){
372
				cairo_move_to(cr,v.x,v.y);
373
			}else{
374
				cairo_line_to(cr,v.x,v.y);
375
			}
376

377
		break;
378
		case(OF_PRIMITIVE_TRIANGLE_STRIP):
379
				v2 = transform(primitive.getVertex(primitive.getIndex(i-2)));
380
				cairo_line_to(cr,v.x,v.y);
381
				cairo_line_to(cr,v2.x,v2.y);
382
				cairo_move_to(cr,v.x,v.y);
383
		break;
384
		case(OF_PRIMITIVE_TRIANGLE_FAN):
385
				/*triangles.addIndex((GLuint)0);
386
					triangles.addIndex((GLuint)1);
387
					triangles.addIndex((GLuint)2);
388
					for(int i = 2; i < primitive.getNumVertices()-1;i++){
389
						triangles.addIndex((GLuint)0);
390
						triangles.addIndex((GLuint)i);
391
						triangles.addIndex((GLuint)i+1);
392
					}*/
393
		break;
394
		default:break;
395
		}
396
	}
397

398
	cairo_move_to(cr,primitive.getVertex(primitive.getIndex(primitive.getNumIndices()-1)).x,primitive.getVertex(primitive.getIndex(primitive.getNumIndices()-1)).y);
399

400
	if(currentStyle.lineWidth>0){
401

402
		cairo_stroke( cr );
403
	}
404
}
405

406
//----------------------------------------------------------
407
void ofCairoRenderer::draw( const of3dPrimitive& model, ofPolyRenderMode renderType  )  const{
408

409
	const_cast<ofCairoRenderer*>(this)->pushMatrix();
410
	const_cast<ofCairoRenderer*>(this)->multMatrix(model.getGlobalTransformMatrix());
411

412
    const ofMesh& mesh = model.getMesh();
413
    draw( mesh, renderType );
414

415
	const_cast<ofCairoRenderer*>(this)->popMatrix();
416

417
}
418

419
void ofCairoRenderer::draw(const ofNode& node) const{
420
	const_cast<ofCairoRenderer*>(this)->pushMatrix();
421
	const_cast<ofCairoRenderer*>(this)->multMatrix(node.getGlobalTransformMatrix());
422
	node.customDraw(this);
423
	const_cast<ofCairoRenderer*>(this)->popMatrix();
424
}
425

426
void ofCairoRenderer::draw(const ofPath::Command & command) const{
427
	if(!surface || !cr) return;
428
	ofCairoRenderer * mut_this = const_cast<ofCairoRenderer*>(this);
429
	switch(command.type){
430
	case ofPath::Command::moveTo:
431
		curvePoints.clear();
432
		cairo_move_to(cr,command.to.x,command.to.y);
433
		break;
434

435
	case ofPath::Command::lineTo:
436
		curvePoints.clear();
437
		cairo_line_to(cr,command.to.x,command.to.y);
438
		break;
439

440

441
	case ofPath::Command::curveTo:
442
		curvePoints.push_back(command.to);
443

444
		//code adapted from ofxVectorGraphics to convert catmull rom to bezier
445
		if(curvePoints.size()==4){
446
			auto p1=curvePoints[0];
447
			auto p2=curvePoints[1];
448
			auto p3=curvePoints[2];
449
			auto p4=curvePoints[3];
450

451
			//SUPER WEIRD MAGIC CONSTANT = 1/6 (this works 100% can someone explain it?)
452
			auto cp1 = p2 + ( p3 - p1 ) * (1.0f/6.f);
453
			auto cp2 = p3 + ( p2 - p4 ) * (1.0f/6.f);
454

455
			cairo_curve_to( cr, cp1.x, cp1.y, cp2.x, cp2.y, p3.x, p3.y );
456
			curvePoints.pop_front();
457
		}
458
		break;
459

460

461
	case ofPath::Command::bezierTo:
462
		curvePoints.clear();
463
		cairo_curve_to(cr,command.cp1.x,command.cp1.y,command.cp2.x,command.cp2.y,command.to.x,command.to.y);
464
		break;
465

466
	case ofPath::Command::quadBezierTo:
467
		curvePoints.clear();
468
		cairo_curve_to(cr,command.cp1.x,command.cp1.y,command.cp2.x,command.cp2.y,command.to.x,command.to.y);
469
		break;
470

471

472
	case ofPath::Command::arc:
473
		curvePoints.clear();
474
		// elliptic arcs not directly supported in cairo, lets scale y
475
		if(command.radiusX!=command.radiusY){
476
			float ellipse_ratio = command.radiusY/command.radiusX;
477
			mut_this->pushMatrix();
478
			mut_this->translate(0,-command.to.y*ellipse_ratio);
479
			mut_this->scale(1,ellipse_ratio);
480
			mut_this->translate(0,command.to.y/ellipse_ratio);
481
			cairo_arc(cr,command.to.x, command.to.y, command.radiusX, ofDegToRad(command.angleBegin), ofDegToRad(command.angleEnd));
482
			//cairo_set_matrix(cr,&stored_matrix);
483
			mut_this->popMatrix();
484
		}else{
485
			cairo_arc(cr,command.to.x, command.to.y, command.radiusX, ofDegToRad(command.angleBegin), ofDegToRad(command.angleEnd));
486
		}
487
		break;
488

489
	case ofPath::Command::arcNegative:
490
		curvePoints.clear();
491
		// elliptic arcs not directly supported in cairo, lets scale y
492
		if(command.radiusX!=command.radiusY){
493
			float ellipse_ratio = command.radiusY/command.radiusX;
494
			mut_this->pushMatrix();
495
			mut_this->translate(0,-command.to.y*ellipse_ratio);
496
			mut_this->scale(1,ellipse_ratio);
497
			mut_this->translate(0,command.to.y/ellipse_ratio);
498
			cairo_arc_negative(cr,command.to.x, command.to.y, command.radiusX, ofDegToRad(command.angleBegin), ofDegToRad(command.angleEnd));
499
			//cairo_set_matrix(cr,&stored_matrix);
500
			mut_this->popMatrix();
501
		}else{
502
			cairo_arc_negative(cr,command.to.x, command.to.y, command.radiusX,  ofDegToRad(command.angleBegin), ofDegToRad(command.angleEnd));
503
		}
504
	break;
505

506
	case ofPath::Command::close:
507
		cairo_close_path(cr);
508
		break;
509

510
	}
511

512

513
}
514

515
//--------------------------------------------
516
void ofCairoRenderer::draw(const ofPixels & raw, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const{
517
	bool shouldCrop = sx != 0 || sy != 0 || sw != w || sh != h;
518
	ofPixels cropped;
519
	if(shouldCrop) {
520
		cropped.allocate(sw, sh, raw.getPixelFormat());
521
		raw.cropTo(cropped, sx, sy, sw, sh);
522
	}
523
	const ofPixels & pix = shouldCrop ? cropped : raw;
524

525
	ofCairoRenderer * mut_this = const_cast<ofCairoRenderer*>(this);
526
	mut_this->pushMatrix();
527
	mut_this->translate(x,y,z);
528
	mut_this->scale(w/pix.getWidth(),h/pix.getHeight());
529
	cairo_surface_t *image;
530
	int stride=0;
531
	int picsize = pix.getWidth()* pix.getHeight();
532
	const unsigned char *imgPix = pix.getData();
533

534
	vector<unsigned char> swapPixels;
535

536
	switch(pix.getImageType()){
537
	case OF_IMAGE_COLOR:
538
#ifdef TARGET_LITTLE_ENDIAN
539
		swapPixels.resize(picsize * 4);
540

541
		for(int p= 0; p<picsize; p++) {
542
			swapPixels[p*4] = imgPix[p*3 +2];
543
			swapPixels[p*4 +1] = imgPix[p*3 +1];
544
			swapPixels[p*4 +2] = imgPix[p*3];
545
		}
546
#else
547
		swapPixels.resize(picsize * 4);
548

549
		for(int p= 0; p<picsize; p++) {
550
			swapPixels[p*4] = imgPix[p*3];
551
			swapPixels[p*4 +1] = imgPix[p*3 +1];
552
			swapPixels[p*4 +2] = imgPix[p*3 +2];
553
		}
554
#endif
555
		stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, pix.getWidth());
556
		image = cairo_image_surface_create_for_data(&swapPixels[0], CAIRO_FORMAT_RGB24, pix.getWidth(), pix.getHeight(), stride);
557
		break;
558
	case OF_IMAGE_COLOR_ALPHA:
559
#ifdef TARGET_LITTLE_ENDIAN
560
		swapPixels.resize(picsize * 4);
561

562
		for(int p= 0; p<picsize; p++) {
563
			swapPixels[p*4] = imgPix[p*4+2];
564
			swapPixels[p*4 +1] = imgPix[p*4+1];
565
			swapPixels[p*4 +2] = imgPix[p*4];
566
			swapPixels[p*4 +3] = imgPix[p*4+3];
567
		}
568
		stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, pix.getWidth());
569
		image = cairo_image_surface_create_for_data(&swapPixels[0], CAIRO_FORMAT_ARGB32, pix.getWidth(), pix.getHeight(), stride);
570
#else
571
		stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, pix.getWidth());
572
		image = cairo_image_surface_create_for_data(pix.getData(), CAIRO_FORMAT_ARGB32, pix.getWidth(), pix.getHeight(), stride);
573
#endif
574
		break;
575
	case OF_IMAGE_GRAYSCALE:
576
		swapPixels.resize(picsize * 4);
577

578
		for(int p= 0; p<picsize; p++) {
579
			swapPixels[p*4] = imgPix[p];
580
			swapPixels[p*4 +1] = imgPix[p];
581
			swapPixels[p*4 +2] = imgPix[p];
582
		}
583
		stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, pix.getWidth());
584
		image = cairo_image_surface_create_for_data(&swapPixels[0], CAIRO_FORMAT_RGB24, pix.getWidth(), pix.getHeight(), stride);
585
		break;
586
	case OF_IMAGE_UNDEFINED:
587
	default:
588
		ofLogError("ofCairoRenderer") << "draw(): trying to draw undefined image type "
589
			<< ofToString(pix.getImageType());
590
		mut_this->popMatrix();
591
		return;
592
		break;
593
	}
594
	cairo_set_source_surface (cr, image, 0,0);
595
	cairo_paint (cr);
596
	cairo_surface_flush(image);
597
	cairo_surface_destroy (image);
598
	mut_this->popMatrix();
599
}
600

601
//--------------------------------------------
602
void ofCairoRenderer::draw(const ofImage & img, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const{
603
	draw(img.getPixels(),x,y,z,w,h,sx,sy,sw,sh);
604
}
605

606
//--------------------------------------------
607
void ofCairoRenderer::draw(const ofFloatImage & image, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const{
608
	ofPixels tmp = image.getPixels();
609
	draw(tmp,x,y,z,w,h,sx,sy,sw,sh);
610
}
611

612
//--------------------------------------------
613
void ofCairoRenderer::draw(const ofShortImage & image, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const{
614
	ofPixels tmp = image.getPixels();
615
	draw(tmp,x,y,z,w,h,sx,sy,sw,sh);
616
}
617

618
//--------------------------------------------
619
void ofCairoRenderer::draw(const ofBaseVideoDraws & video, float x, float y, float w, float h) const{
620
	draw(video.getPixels(),x,y,0,w,h,x,y,w,h);
621
}
622

623
ofPath & ofCairoRenderer::getPath(){
624
	return path;
625
}
626

627
//--------------------------------------------
628
void ofCairoRenderer::setRectMode(ofRectMode mode){
629
	currentStyle.rectMode = mode;
630
}
631

632
//--------------------------------------------
633
ofRectMode ofCairoRenderer::getRectMode(){
634
	return currentStyle.rectMode;
635
}
636

637
//--------------------------------------------
638
void ofCairoRenderer::setFillMode(ofFillFlag fill){
639
	currentStyle.bFill = fill;
640
	if(currentStyle.bFill){
641
		path.setFilled(true);
642
		path.setStrokeWidth(0);
643
	}else{
644
		path.setFilled(false);
645
		path.setStrokeWidth(currentStyle.lineWidth);
646
	}
647
}
648

649
//--------------------------------------------
650
ofFillFlag ofCairoRenderer::getFillMode(){
651
	if(currentStyle.bFill){
652
		return OF_FILLED;
653
	}else{
654
		return OF_OUTLINE;
655
	}
656
}
657

658
//--------------------------------------------
659
void ofCairoRenderer::setLineWidth(float lineWidth){
660
	currentStyle.lineWidth = lineWidth;
661
	if(!currentStyle.bFill){
662
		path.setStrokeWidth(lineWidth);
663
	}
664
	cairo_set_line_width( cr, lineWidth );
665
}
666

667
//----------------------------------------------------------
668
void ofCairoRenderer::setDepthTest(bool depthTest) {
669
	// cairo does not do any depth testing
670
}
671

672
//--------------------------------------------
673
void ofCairoRenderer::setBlendMode(ofBlendMode blendMode){
674
	switch (blendMode){
675
		case OF_BLENDMODE_ALPHA:{
676
			cairo_set_operator(cr,CAIRO_OPERATOR_OVER);
677
			break;
678
		}
679

680
		case OF_BLENDMODE_ADD:{
681
			cairo_set_operator(cr,CAIRO_OPERATOR_ADD);
682
			break;
683
		}
684
#if (CAIRO_VERSION_MAJOR==1 && CAIRO_VERSION_MINOR>=10) || CAIRO_VERSION_MAJOR>1
685
		case OF_BLENDMODE_MULTIPLY:{
686
			cairo_set_operator(cr,CAIRO_OPERATOR_MULTIPLY);
687
			break;
688
		}
689

690
		case OF_BLENDMODE_SCREEN:{
691
			cairo_set_operator(cr,CAIRO_OPERATOR_SCREEN);
692
			break;
693
		}
694

695
		case OF_BLENDMODE_SUBTRACT:{
696
			cairo_set_operator(cr,CAIRO_OPERATOR_DIFFERENCE);
697
			break;
698
		}
699
#endif
700

701
		default:
702
			break;
703
	}
704
}
705

706
//--------------------------------------------
707
void ofCairoRenderer::setLineSmoothing(bool smooth){
708

709
}
710

711

712
// color options
713
//--------------------------------------------
714
void ofCairoRenderer::setColor(int r, int g, int b){
715
	setColor(r,g,b,255);
716
};
717

718
//--------------------------------------------
719
void ofCairoRenderer::setColor(int r, int g, int b, int a){
720
	cairo_set_source_rgba(cr, (float)r/255.0, (float)g/255.0, (float)b/255.0, (float)a/255.0);
721
	currentStyle.color.set(r,g,b,a);
722
};
723

724
//--------------------------------------------
725
void ofCairoRenderer::setColor(const ofColor & c){
726
	setColor(c.r,c.g,c.b,c.a);
727
};
728

729
//--------------------------------------------
730
void ofCairoRenderer::setColor(const ofColor & c, int _a){
731
	setColor(c.r,c.g,c.b,_a);
732
};
733

734
//--------------------------------------------
735
void ofCairoRenderer::setColor(int gray){
736
	setColor(gray,gray,gray,255);
737
};
738

739
//--------------------------------------------
740
void ofCairoRenderer::setHexColor( int hexColor ){
741
	int r = (hexColor >> 16) & 0xff;
742
	int g = (hexColor >> 8) & 0xff;
743
	int b = (hexColor >> 0) & 0xff;
744
	setColor(r,g,b);
745
};
746

747
//--------------------------------------------
748
// transformations
749
//our openGL wrappers
750
glm::mat4 ofCairoRenderer::getCurrentMatrix(ofMatrixMode matrixMode_) const{
751
	ofLogWarning() << "getCurrentMatrix not yet implemented for Cairo Renderer.";
752
	return glm::mat4(1.0);
753
}
754

755
//----------------------------------------------------------
756
void ofCairoRenderer::pushMatrix(){
757
	if(!surface || !cr) return;
758
	cairo_matrix_t matrix;
759
	cairo_get_matrix(cr,&matrix);
760
	matrixStack.push(matrix);
761

762
	if(!b3D) return;
763
	modelViewStack.push(modelView);
764
}
765

766
//----------------------------------------------------------
767
void ofCairoRenderer::popMatrix(){
768
	if(!surface || !cr) return;
769
	cairo_set_matrix(cr,&matrixStack.top());
770
	matrixStack.pop();
771

772
	if(!b3D) return;
773
	modelView = modelViewStack.top();
774
	modelViewStack.pop();
775
}
776

777
//----------------------------------------------------------
778
void ofCairoRenderer::translate(float x, float y, float z ){
779
	if(!surface || !cr) return;
780
	cairo_matrix_t matrix;
781
	cairo_get_matrix(cr,&matrix);
782
	cairo_matrix_translate(&matrix,x,y);
783
	cairo_set_matrix(cr,&matrix);
784

785
	if(!b3D) return;
786
	modelView = glm::translate(modelView, {x,y,z});
787

788
}
789

790
//----------------------------------------------------------
791
void ofCairoRenderer::translate(const glm::vec3 & p){
792
	translate(p.x,p.y,p.z);
793
}
794

795
//----------------------------------------------------------
796
void ofCairoRenderer::scale(float xAmnt, float yAmnt, float zAmnt ){
797
	if(!surface || !cr) return;
798
	// temporary fix for a issue where Cairo never recovers after setting scale = 0
799
	if (xAmnt == 0) xAmnt = std::numeric_limits<float>::epsilon();
800
	if (yAmnt == 0) yAmnt = std::numeric_limits<float>::epsilon();
801

802
	cairo_matrix_t matrix;
803
	cairo_get_matrix(cr,&matrix);
804
	cairo_matrix_scale(&matrix,xAmnt,yAmnt);
805
	cairo_set_matrix(cr,&matrix);
806

807
	if(!b3D) return;
808
	modelView = glm::scale(modelView, {xAmnt,yAmnt,zAmnt});
809
}
810

811
//----------------------------------------------------------
812
void ofCairoRenderer::matrixMode(ofMatrixMode mode){
813
	currentMatrixMode = mode;
814
}
815

816
//----------------------------------------------------------
817
void ofCairoRenderer::loadIdentityMatrix (void){
818
	if(!surface || !cr) return;
819
	if(currentMatrixMode==OF_MATRIX_MODELVIEW){
820
		cairo_matrix_t matrix;
821
		cairo_matrix_init_identity(&matrix);
822
		cairo_set_matrix(cr,&matrix);
823
	}
824

825
	if(!b3D) return;
826
	if(currentMatrixMode==OF_MATRIX_MODELVIEW){
827
		modelView = glm::mat4(1.0);
828
	}else if(currentMatrixMode==OF_MATRIX_PROJECTION){
829
		projection = glm::mat4(1.0);
830
	}
831
}
832

833
//----------------------------------------------------------
834
void ofCairoRenderer::loadMatrix (const glm::mat4 & m){
835
	if(!surface || !cr) return;
836
	if(!b3D) return;
837
	if(currentMatrixMode==OF_MATRIX_MODELVIEW){
838
		modelView = m;
839
	}else if(currentMatrixMode==OF_MATRIX_PROJECTION){
840
		projection = m;
841
	}
842
}
843

844
//----------------------------------------------------------
845
void ofCairoRenderer::loadMatrix (const float * m){
846
	loadMatrix(glm::make_mat4(m));
847
}
848

849
//----------------------------------------------------------
850
void ofCairoRenderer::multMatrix (const glm::mat4 & m){
851
	if(!surface || !cr) return;
852
	if(!b3D) return;
853
	if(currentMatrixMode==OF_MATRIX_MODELVIEW){
854
		modelView = m * modelView;
855
	}else if(currentMatrixMode==OF_MATRIX_PROJECTION){
856
		projection = m * projection;
857
	}
858
}
859

860
//----------------------------------------------------------
861
void ofCairoRenderer::multMatrix (const float * m){
862
	multMatrix(glm::make_mat4(m));
863
}
864

865
//----------------------------------------------------------
866
void ofCairoRenderer::rotateRad(float radians, float vecX, float vecY, float vecZ){
867
    if(!surface || !cr) return;
868

869
    // we can only do Z-axis rotations via cairo_matrix_rotate.
870
    if(vecZ == 1.0f) {
871
    	cairo_matrix_t matrix;
872
    	cairo_get_matrix(cr,&matrix);
873
		cairo_matrix_rotate(&matrix,radians);
874
        cairo_set_matrix(cr,&matrix);
875
    }
876

877
    if(!b3D) return;
878
	modelView = glm::rotate(modelView, radians, glm::vec3(vecX,vecY,vecZ));
879
}
880

881
//----------------------------------------------------------
882
void ofCairoRenderer::rotateXRad(float radians){
883
	rotateRad(radians,1,0,0);
884
}
885
//----------------------------------------------------------
886
void ofCairoRenderer::rotateYRad(float radians){
887
	rotateRad(radians,0,1,0);
888
}
889

890
//----------------------------------------------------------
891
void ofCairoRenderer::rotateZRad(float radians){
892
	rotateRad(radians,0,0,1);
893
}
894

895
//----------------------------------------------------------
896
void ofCairoRenderer::rotateRad(float radians){
897
	rotateZRad(radians);
898
}
899

900
//----------------------------------------------------------
901
void ofCairoRenderer::setupScreen(){
902
	if(!surface || !cr) return;
903

904
	setupScreenPerspective();	// assume defaults
905
}
906

907
//----------------------------------------------------------
908
// screen coordinate things / default gl values
909
void ofCairoRenderer::pushView(){
910
	viewportStack.push(viewportRect);
911
}
912

913
//----------------------------------------------------------
914
void ofCairoRenderer::popView(){
915
	viewportRect = viewportStack.top();
916
	viewportStack.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)
923
void ofCairoRenderer::viewport(ofRectangle v){
924
	viewport(v.x,v.y,v.width,v.height);
925
}
926

927
//----------------------------------------------------------
928
void ofCairoRenderer::viewport(float x, float y, float width, float height, bool invertY){
929
	if(width < 0) width = originalViewport.width;
930
	if(height < 0) height = originalViewport.height;
931
    ofLogVerbose("ofCairoRenderer::viewport") << "Setting viewport to: " << width << ", " << height;
932

933
	if (invertY){
934
		y = -y;
935
	}
936

937

938
	viewportRect.set(x, y, width, height);
939

940
	cairo_reset_clip(cr);
941
	cairo_new_path(cr);
942
	cairo_move_to(cr,viewportRect.x,viewportRect.y);
943
	cairo_line_to(cr,viewportRect.x+viewportRect.width,viewportRect.y);
944
	cairo_line_to(cr,viewportRect.x+viewportRect.width,viewportRect.y+viewportRect.height);
945
	cairo_line_to(cr,viewportRect.x,viewportRect.y+viewportRect.height);
946
	cairo_clip(cr);
947
};
948

949
//----------------------------------------------------------
950
void ofCairoRenderer::setupScreenPerspective(float width, float height, float fov, float nearDist, float farDist){
951
	if(!b3D) return;
952
	if(width < 0) width = originalViewport.width;
953
	if(height < 0) height = originalViewport.height;
954
	ofOrientation orientation = ofGetOrientation();
955

956
	float viewW = originalViewport.width;
957
	float viewH = originalViewport.height;
958

959
	float eyeX = viewW / 2;
960
	float eyeY = viewH / 2;
961
	float halfFov = glm::pi<float>() * fov / 360.0f;
962
	float theTan = tanf(halfFov);
963
	float dist = eyeY / theTan;
964
	float aspect = (float) viewW / viewH;
965

966
	if(nearDist == 0) nearDist = dist / 10.0f;
967
	if(farDist == 0) farDist = dist * 10.0f;
968

969
	projection = glm::perspective(ofDegToRad(fov),aspect,nearDist,farDist);
970
	modelView = glm::lookAt(glm::vec3(eyeX,eyeY,dist),glm::vec3(eyeX,eyeY,0),glm::vec3(0,1,0));
971

972

973
	switch(orientation) {
974
		case OF_ORIENTATION_180:
975
			modelView = glm::rotate(modelView,-glm::pi<float>(),glm::vec3(0,0,1));
976
			if(isVFlipped()){
977
				modelView = glm::scale(modelView, glm::vec3(-1,1,1));
978
				modelView = glm::translate(modelView, glm::vec3(width,0,0));
979
			}else{
980
				modelView = glm::translate(modelView, glm::vec3(width, -height, 0));
981
			}
982

983
			break;
984

985
		case OF_ORIENTATION_90_RIGHT:
986
			modelView = glm::rotate(modelView,-glm::half_pi<float>(),glm::vec3(0,0,1));
987
			if(!isVFlipped()){
988
				modelView = glm::scale(modelView, glm::vec3(1,-1,1));
989
				modelView = glm::translate(modelView, glm::vec3(-width,-height,0));
990
			}
991
			break;
992

993
		case OF_ORIENTATION_90_LEFT:
994
			modelView = glm::rotate(modelView,glm::half_pi<float>(),glm::vec3(0,0,1));
995
			if(isVFlipped()){
996
				modelView = glm::translate(modelView, glm::vec3(0,-height,0));
997
			}else{
998
				modelView = glm::scale(modelView, glm::vec3(1,-1,1));
999
			}
1000
			break;
1001

1002
		case OF_ORIENTATION_DEFAULT:
1003
		default:
1004
			if(isVFlipped()){
1005
				modelView = glm::scale(modelView, glm::vec3(-1,-1,1));
1006
				modelView = glm::translate(modelView, glm::vec3(-width,-height,0));
1007
			}
1008
			break;
1009
	}
1010
};
1011

1012
//----------------------------------------------------------
1013
void ofCairoRenderer::setupScreenOrtho(float width, float height, float nearDist, float farDist){
1014
	if(!b3D) return;
1015
	if(width < 0) width = viewportRect.width;
1016
	if(height < 0) height = viewportRect.height;
1017
	ofOrientation orientation = ofGetOrientation();
1018

1019
	float viewW = viewportRect.width;
1020
	float viewH = viewportRect.height;
1021

1022
	ofSetCoordHandedness(OF_RIGHT_HANDED);
1023

1024
	if(isVFlipped()) {
1025
		ofSetCoordHandedness(OF_LEFT_HANDED);
1026
	}
1027
	projection = glm::ortho(0.f, viewW, 0.f, viewH, nearDist, farDist);
1028

1029
	modelView = glm::mat4(1.0f);
1030

1031
	switch(orientation) {
1032
		case OF_ORIENTATION_180:
1033
			modelView = glm::rotate(modelView,-glm::pi<float>(),glm::vec3(0,0,1));
1034
			if(isVFlipped()){
1035
				modelView = glm::scale(modelView, glm::vec3(-1,1,1));
1036
				modelView = glm::translate(modelView, glm::vec3(width,0,0));
1037
			}else{
1038
				modelView = glm::translate(modelView, glm::vec3(width, -height, 0));
1039
			}
1040

1041
			break;
1042

1043
		case OF_ORIENTATION_90_RIGHT:
1044
			modelView = glm::rotate(modelView,-glm::half_pi<float>(),glm::vec3(0,0,1));
1045
			if(!isVFlipped()){
1046
				modelView = glm::scale(modelView, glm::vec3(1,-1,1));
1047
				modelView = glm::translate(modelView, glm::vec3(-width,-height,0));
1048
			}
1049
			break;
1050

1051
		case OF_ORIENTATION_90_LEFT:
1052
			modelView = glm::rotate(modelView,glm::half_pi<float>(),glm::vec3(0,0,1));
1053
			if(isVFlipped()){
1054
				modelView = glm::translate(modelView, glm::vec3(0,-height,0));
1055
			}else{
1056
				modelView = glm::scale(modelView, glm::vec3(1,-1,1));
1057
			}
1058
			break;
1059

1060
		case OF_ORIENTATION_DEFAULT:
1061
		default:
1062
			if(isVFlipped()){
1063
				modelView = glm::scale(modelView, glm::vec3(-1,-1,1));
1064
				modelView = glm::translate(modelView, glm::vec3(-width,-height,0));
1065
			}
1066
			break;
1067
	}
1068
};
1069

1070
//----------------------------------------------------------
1071
ofRectangle ofCairoRenderer::getCurrentViewport() const{
1072
	return viewportRect;
1073
};
1074

1075
//----------------------------------------------------------
1076
ofRectangle ofCairoRenderer::getNativeViewport() const{
1077
	return viewportRect;
1078
};
1079

1080
//----------------------------------------------------------
1081
int ofCairoRenderer::getViewportWidth() const{
1082
	return viewportRect.width;
1083
};
1084

1085
//----------------------------------------------------------
1086
int ofCairoRenderer::getViewportHeight() const{
1087
	return viewportRect.height;
1088
};
1089

1090
//----------------------------------------------------------
1091
void ofCairoRenderer::setOrientation(ofOrientation orientation, bool vFlip){
1092
	ofLogError("ofCairoRenderer") << "orientation not supported yet";
1093
}
1094

1095
//----------------------------------------------------------
1096
bool ofCairoRenderer::isVFlipped() const{
1097
	return true;
1098
}
1099

1100
//----------------------------------------------------------
1101
void ofCairoRenderer::loadViewMatrix(const glm::mat4 & m){
1102
	ofLogError("ofCairoRenderer") << "view matrix not supported yet";
1103
}
1104

1105
//----------------------------------------------------------
1106
void ofCairoRenderer::multViewMatrix(const glm::mat4 & m){
1107
	ofLogError("ofCairoRenderer") << "view matrix not supported yet";
1108
}
1109

1110
//----------------------------------------------------------
1111
glm::mat4 ofCairoRenderer::getCurrentViewMatrix() const{
1112
	ofLogError("ofCairoRenderer") << "view matrix not supported yet";
1113
	return glm::mat4(1.0);
1114
}
1115

1116
//----------------------------------------------------------
1117
glm::mat4 ofCairoRenderer::getCurrentNormalMatrix() const{
1118
	ofLogError("ofCairoRenderer") << "normal matrix not supported yet";
1119
	return glm::mat4(1.0);
1120
}
1121

1122
//----------------------------------------------------------
1123
glm::mat4 ofCairoRenderer::getCurrentOrientationMatrix() const{
1124
	ofLogError("ofCairoRenderer") << "orientation matrix not supported yet";
1125
	return glm::mat4(1.0);
1126
}
1127

1128
//----------------------------------------------------------
1129
void ofCairoRenderer::setCircleResolution(int){
1130

1131
}
1132

1133
void ofCairoRenderer::setPolyMode(ofPolyWindingMode mode){
1134
	currentStyle.polyMode = mode;
1135
	path.setPolyWindingMode(mode);
1136
}
1137

1138
//----------------------------------------------------------
1139
void ofCairoRenderer::setCoordHandedness(ofHandednessType handedness){
1140

1141
};
1142

1143
//----------------------------------------------------------
1144
ofHandednessType ofCairoRenderer::getCoordHandedness() const{
1145
	return OF_LEFT_HANDED;
1146
};
1147

1148
//----------------------------------------------------------
1149
void ofCairoRenderer::setupGraphicDefaults(){
1150
	setStyle(ofStyle());
1151
	path.setMode(ofPath::COMMANDS);
1152
	path.setUseShapeColor(false);
1153
	clear();
1154

1155
	cairo_matrix_t matrix;
1156
	cairo_matrix_init_scale(&matrix, 1.0, 1.0);
1157
	cairo_matrix_init_translate(&matrix, 0.0, 0.0);
1158
	cairo_set_matrix(cr,&matrix);
1159
};
1160

1161
//----------------------------------------------------------
1162
void ofCairoRenderer::clear(){
1163
	if(!surface || ! cr) return;
1164
	cairo_set_source_rgba(cr,currentStyle.bgColor.r/255., currentStyle.bgColor.g/255., currentStyle.bgColor.b/255., currentStyle.bgColor.a/255.);
1165
	cairo_paint(cr);
1166
	setColor(currentStyle.color);
1167
}
1168

1169
//----------------------------------------------------------
1170
void ofCairoRenderer::clear(float r, float g, float b, float a) {
1171
	if(!surface || ! cr) return;
1172
	cairo_set_source_rgba(cr,r/255., g/255., b/255., a/255.);
1173
	cairo_paint(cr);
1174
	setColor(currentStyle.color);
1175

1176
}
1177

1178
//----------------------------------------------------------
1179
void ofCairoRenderer::clear(float brightness, float a) {
1180
	clear(brightness, brightness, brightness, a);
1181
}
1182

1183
//----------------------------------------------------------
1184
void ofCairoRenderer::clearAlpha() {
1185
}
1186

1187

1188
void ofCairoRenderer::setBitmapTextMode(ofDrawBitmapMode mode){
1189
	currentStyle.drawBitmapMode = mode;
1190
}
1191

1192
ofStyle ofCairoRenderer::getStyle() const{
1193
	return currentStyle;
1194
}
1195

1196
void ofCairoRenderer::pushStyle(){
1197
	styleHistory.push_back(currentStyle);
1198
	//if we are over the max number of styles we have set, then delete the oldest styles.
1199
	if( styleHistory.size() > OF_MAX_STYLE_HISTORY ){
1200
		styleHistory.pop_front();
1201
		//should we warn here?
1202
		ofLogWarning("ofGraphics") << "ofPushStyle(): maximum number of style pushes << " << OF_MAX_STYLE_HISTORY << " reached, did you forget to pop somewhere?";
1203
	}
1204
}
1205

1206
void ofCairoRenderer::popStyle(){
1207
	if( styleHistory.size() ){
1208
		setStyle(styleHistory.back());
1209
		styleHistory.pop_back();
1210
	}
1211
}
1212

1213
//----------------------------------------------------------
1214
void ofCairoRenderer::setBackgroundAuto(bool bAuto){
1215
	bBackgroundAuto = bAuto;
1216
}
1217

1218
//----------------------------------------------------------
1219
bool ofCairoRenderer::getBackgroundAuto(){
1220
	return bBackgroundAuto;
1221
}
1222

1223
//----------------------------------------------------------
1224
void ofCairoRenderer::setBackgroundColor(const ofColor & c){
1225
	currentStyle.bgColor = c;
1226
}
1227

1228
//----------------------------------------------------------
1229
ofColor ofCairoRenderer::getBackgroundColor(){
1230
	return currentStyle.bgColor;
1231
}
1232

1233
//----------------------------------------------------------
1234
void ofCairoRenderer::background(const ofColor & c){
1235
	setBackgroundColor(c);
1236
	clear(c.r,c.g,c.b,c.a);
1237
}
1238

1239
//----------------------------------------------------------
1240
void ofCairoRenderer::background(float brightness) {
1241
	background(ofColor(brightness));
1242
}
1243

1244
//----------------------------------------------------------
1245
void ofCairoRenderer::background(int hexColor, float _a){
1246
	background ( (hexColor >> 16) & 0xff, (hexColor >> 8) & 0xff, (hexColor >> 0) & 0xff, _a);
1247
}
1248

1249
//----------------------------------------------------------
1250
void ofCairoRenderer::background(int r, int g, int b, int a){
1251
	background(ofColor(r,g,b,a));
1252
}
1253

1254

1255
//----------------------------------------------------------
1256
void ofCairoRenderer::drawLine(float x1, float y1, float z1, float x2, float y2, float z2) const{
1257
	cairo_new_path(cr);
1258
	cairo_move_to(cr,x1,y1);
1259
	cairo_line_to(cr,x2,y2);
1260

1261
	cairo_stroke( cr );
1262
}
1263

1264
//----------------------------------------------------------
1265
void ofCairoRenderer::drawRectangle(float x, float y, float z, float w, float h) const{
1266

1267
	cairo_new_path(cr);
1268

1269
	if (currentStyle.rectMode == OF_RECTMODE_CORNER){
1270
		cairo_move_to(cr,x,y);
1271
		cairo_line_to(cr,x+w, y);
1272
		cairo_line_to(cr,x+w, y+h);
1273
		cairo_line_to(cr,x, y+h);
1274
	}else{
1275
		cairo_move_to(cr,x-w/2.0f, y-h/2.0f);
1276
		cairo_line_to(cr,x+w/2.0f, y-h/2.0f);
1277
		cairo_line_to(cr,x+w/2.0f, y+h/2.0f);
1278
		cairo_line_to(cr,x-w/2.0f, y+h/2.0f);
1279
	}
1280

1281
	cairo_close_path(cr);
1282

1283
	if(currentStyle.bFill==OF_FILLED){
1284
		cairo_fill( cr );
1285
	}else{
1286
		cairo_stroke( cr );
1287
	}
1288
}
1289

1290
//----------------------------------------------------------
1291
void ofCairoRenderer::drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3) const{
1292
	cairo_new_path(cr);
1293

1294
	cairo_move_to(cr, x1, y1);
1295
	cairo_line_to(cr, x2, y2);
1296
	cairo_line_to(cr, x3, y3);
1297

1298

1299
	cairo_close_path(cr);
1300

1301
	if(currentStyle.bFill==OF_FILLED){
1302
		cairo_fill( cr );
1303
	}else{
1304
		cairo_stroke( cr );
1305
	}
1306
}
1307

1308
//----------------------------------------------------------
1309
void ofCairoRenderer::drawCircle(float x, float y, float z, float radius) const{
1310
	cairo_new_path(cr);
1311
	cairo_arc(cr, x, y, radius, 0, glm::two_pi<float>());
1312

1313
	cairo_close_path(cr);
1314

1315
	if(currentStyle.bFill==OF_FILLED){
1316
		cairo_fill( cr );
1317
	}else{
1318
		cairo_stroke( cr );
1319
	}
1320
}
1321

1322
//----------------------------------------------------------
1323
void ofCairoRenderer::enableAntiAliasing(){
1324
	cairo_set_antialias(cr,CAIRO_ANTIALIAS_SUBPIXEL);
1325
}
1326

1327
//----------------------------------------------------------
1328
void ofCairoRenderer::disableAntiAliasing(){
1329
	cairo_set_antialias(cr,CAIRO_ANTIALIAS_NONE);
1330
}
1331

1332
//----------------------------------------------------------
1333
void ofCairoRenderer::drawEllipse(float x, float y, float z, float width, float height) const{
1334
	ofCairoRenderer * mutThis = const_cast<ofCairoRenderer*>(this);
1335
	cairo_new_path(cr);
1336
	float ellipse_ratio = height/width;
1337
	mutThis->pushMatrix();
1338
	mutThis->translate(0,-y*ellipse_ratio);
1339
	mutThis->scale(1,ellipse_ratio);
1340
	mutThis->translate(0,y/ellipse_ratio);
1341
	cairo_arc(cr, x, y, width*0.5, 0, glm::two_pi<float>());
1342
	mutThis->popMatrix();
1343

1344
	cairo_close_path(cr);
1345

1346

1347
	if(currentStyle.bFill==OF_FILLED){
1348
		cairo_fill( cr );
1349
	}else{
1350
		cairo_stroke( cr );
1351
	}
1352
}
1353

1354
void ofCairoRenderer::drawString(string text, float x, float y, float z) const{
1355
	cairo_select_font_face (cr, "Mono", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
1356
	cairo_set_font_size (cr, 10);
1357
	vector<string> lines = ofSplitString(text, "\n");
1358
	for(int i=0;i<(int)lines.size();i++){
1359
		cairo_move_to (cr, x, y+i*14.3);
1360
		cairo_show_text (cr, lines[i].c_str() );
1361
	}
1362
}
1363

1364
void ofCairoRenderer::drawString(const ofTrueTypeFont & font, string text, float x, float y) const{
1365
	font.drawStringAsShapes(text,x,y);
1366
}
1367

1368
cairo_t * ofCairoRenderer::getCairoContext(){
1369
	return cr;
1370
}
1371

1372
cairo_surface_t * ofCairoRenderer::getCairoSurface(){
1373
	return surface;
1374
}
1375

1376
ofPixels & ofCairoRenderer::getImageSurfacePixels(){
1377
	if(type!=IMAGE){
1378
		ofLogError("ofCairoRenderer") << "getImageSurfacePixels(): can only get pixels from image surface";
1379
	}
1380
	return imageBuffer;
1381
}
1382

1383
ofBuffer & ofCairoRenderer::getContentBuffer(){
1384
	if(filename!="" || (type!=SVG && type!=PDF)){
1385
		ofLogError("ofCairoRenderer") << "getContentBuffer(): can only get buffer from memory allocated renderer for svg or pdf";
1386
	}
1387
	return streamBuffer;
1388
}
1389

1390
const of3dGraphics & ofCairoRenderer::get3dGraphics() const{
1391
	return graphics3d;
1392
}
1393

1394
of3dGraphics & ofCairoRenderer::get3dGraphics(){
1395
	return graphics3d;
1396
}
1397

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.