framework2

Форк
0
/
ofGLProgrammableRenderer.cpp 
2825 строк · 89.2 Кб
1
#include "ofGLProgrammableRenderer.h"
2
#include "ofMesh.h"
3
#include "ofPath.h"
4
#include "ofBitmapFont.h"
5
#include "ofGLUtils.h"
6
#include "ofImage.h"
7
#include "ofFbo.h"
8
#include "ofVboMesh.h"
9
#include "of3dPrimitives.h"
10
#include "ofLight.h"
11
#include "ofMaterialBaseTypes.h"
12
#include "ofCamera.h"
13
#include "ofTrueTypeFont.h"
14
#include "ofNode.h"
15
#include "ofVideoBaseTypes.h"
16

17
using std::vector;
18
using std::string;
19
using std::swap;
20

21
static const string MODEL_MATRIX_UNIFORM="modelMatrix";
22
static const string VIEW_MATRIX_UNIFORM="viewMatrix";
23
static const string MODELVIEW_MATRIX_UNIFORM="modelViewMatrix";
24
static const string PROJECTION_MATRIX_UNIFORM="projectionMatrix";
25
static const string MODELVIEW_PROJECTION_MATRIX_UNIFORM="modelViewProjectionMatrix";
26
static const string TEXTURE_MATRIX_UNIFORM="textureMatrix";
27
static const string COLOR_UNIFORM="globalColor";
28

29
static const string USE_TEXTURE_UNIFORM="usingTexture";
30
static const string USE_COLORS_UNIFORM="usingColors";
31
static const string BITMAP_STRING_UNIFORM="bitmapText";
32

33

34
const string ofGLProgrammableRenderer::TYPE="ProgrammableGL";
35
static bool programmableRendererCreated = false;
36

37
bool ofIsGLProgrammableRenderer(){
38
	return programmableRendererCreated;
39
}
40

41

42
//----------------------------------------------------------
43
ofGLProgrammableRenderer::ofGLProgrammableRenderer(const ofAppBaseWindow * _window)
44
:matrixStack(_window)
45
,graphics3d(this)
46
{
47
	programmableRendererCreated = true;
48
	bBackgroundAuto = true;
49

50
	lineMesh.getVertices().resize(2);
51
	lineMesh.setMode(OF_PRIMITIVE_LINES);
52
	triangleMesh.getVertices().resize(3);
53
	rectMesh.getVertices().resize(4);
54

55
	bitmapStringEnabled = false;
56
    verticesEnabled = true;
57
    colorsEnabled = false;
58
    texCoordsEnabled = false;
59
    normalsEnabled = false;
60
	settingDefaultShader = false;
61
	usingVideoShader = false;
62
	usingCustomShader = false;
63

64
	wrongUseLoggedOnce = false;
65

66
	uniqueShader = false;
67

68
	currentShader = nullptr;
69

70
	currentTextureTarget = OF_NO_TEXTURE;
71
	currentMaterial = nullptr;
72
	alphaMaskTextureTarget = OF_NO_TEXTURE;
73
	
74
	currentShadow = nullptr;
75
	bIsShadowDepthPass = false;
76

77
	major = 3;
78
	minor = 2;
79
	window = _window;
80

81
	currentFramebufferId = 0;
82
	defaultFramebufferId = 0;
83
	path.setMode(ofPath::POLYLINES);
84
    path.setUseShapeColor(false);
85
	currentEyePos = {0.f,0.f,0.f};
86
}
87

88
//----------------------------------------------------------
89
void ofGLProgrammableRenderer::startRender() {
90
	currentFramebufferId = defaultFramebufferId;
91
	framebufferIdStack.push_back(defaultFramebufferId);
92
	matrixStack.setRenderSurface(*window);
93
	beginDefaultShader();
94
	viewport();
95
    // to do non auto clear on PC for now - we do something like "single" buffering --
96
    // it's not that pretty but it work for the most part
97

98
    #ifdef TARGET_WIN32
99
    if (getBackgroundAuto() == false){
100
        glDrawBuffer (GL_FRONT);
101
    }
102
    #endif
103

104
	if ( getBackgroundAuto() ){// || ofGetFrameNum() < 3){
105
		background(currentStyle.bgColor);
106
	}
107
}
108

109
//----------------------------------------------------------
110
void ofGLProgrammableRenderer::finishRender() {
111
	if (!uniqueShader) {
112
		glUseProgram(0);
113
		if(!usingCustomShader) currentShader = nullptr;
114
	}
115
	matrixStack.clearStacks();
116
	framebufferIdStack.clear();
117
}
118

119
//----------------------------------------------------------
120
void ofGLProgrammableRenderer::draw(const ofMesh & vertexData, ofPolyRenderMode renderType, bool useColors, bool useTextures, bool useNormals) const{
121
	if (vertexData.getVertices().empty()) return;
122
	
123
	
124
	// tig: note that for GL3+ we use glPolygonMode to draw wireframes or filled meshes, and not the primitive mode.
125
	// the reason is not purely aesthetic, but more conformant with the behaviour of ofGLRenderer. Whereas
126
	// gles2.0 doesn't allow for a polygonmode.
127
	// Also gles2 still supports vertex array syntax for uploading data to attributes and it seems to be faster than
128
	// vbo's for meshes that are updated frequently so let's use that instead
129
	
130
	//if (bSmoothHinted) startSmoothing();
131

132
#if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN)
133
	glEnableVertexAttribArray(ofShader::POSITION_ATTRIBUTE);
134
	glVertexAttribPointer(ofShader::POSITION_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, sizeof(typename ofMesh::VertexType), vertexData.getVerticesPointer());
135
	
136
	useNormals &= (vertexData.getNumNormals()>0);
137
	if(useNormals){
138
		glEnableVertexAttribArray(ofShader::NORMAL_ATTRIBUTE);
139
		glVertexAttribPointer(ofShader::NORMAL_ATTRIBUTE, 3, GL_FLOAT, GL_TRUE, sizeof(typename ofMesh::NormalType), vertexData.getNormalsPointer());
140
	}else{
141
		glDisableVertexAttribArray(ofShader::NORMAL_ATTRIBUTE);
142
	}
143
	
144
	useColors &= (vertexData.getNumColors()>0);
145
	if(useColors){
146
		glEnableVertexAttribArray(ofShader::COLOR_ATTRIBUTE);
147
		glVertexAttribPointer(ofShader::COLOR_ATTRIBUTE, 4,GL_FLOAT, GL_FALSE, sizeof(ofFloatColor), vertexData.getColorsPointer());
148
	}else{
149
		glDisableVertexAttribArray(ofShader::COLOR_ATTRIBUTE);
150
	}
151

152
	useTextures &= (vertexData.getNumTexCoords()>0);
153
	if(useTextures){
154
		glEnableVertexAttribArray(ofShader::TEXCOORD_ATTRIBUTE);
155
		glVertexAttribPointer(ofShader::TEXCOORD_ATTRIBUTE,2, GL_FLOAT, GL_FALSE, sizeof(typename ofMesh::TexCoordType), vertexData.getTexCoordsPointer());
156
	}else{
157
		glDisableVertexAttribArray(ofShader::TEXCOORD_ATTRIBUTE);
158
	}
159

160

161
	const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(true,useColors,useTextures,useNormals);
162

163
	GLenum drawMode;
164
	switch(renderType){
165
	case OF_MESH_POINTS:
166
		drawMode = GL_POINTS;
167
		break;
168
	case OF_MESH_WIREFRAME:
169
		drawMode = GL_LINES;
170
		break;
171
	case OF_MESH_FILL:
172
		drawMode = ofGetGLPrimitiveMode(vertexData.getMode());
173
		break;
174
	default:
175
		drawMode = ofGetGLPrimitiveMode(vertexData.getMode());
176
		break;
177
	}
178

179
	if(vertexData.getNumIndices()){
180
		glDrawElements(drawMode, vertexData.getNumIndices(),GL_UNSIGNED_SHORT,vertexData.getIndexPointer());
181
	}else{
182
		glDrawArrays(drawMode, 0, vertexData.getNumVertices());
183
	}
184
#else
185
	
186

187
#ifndef TARGET_OPENGLES
188
	meshVbo.setMesh(vertexData, GL_STREAM_DRAW, useColors, useTextures, useNormals);
189
	glPolygonMode(GL_FRONT_AND_BACK, ofGetGLPolyMode(renderType));
190
	GLenum drawMode = ofGetGLPrimitiveMode(vertexData.getMode());
191
#else
192
	meshVbo.setMesh(vertexData, GL_STATIC_DRAW, useColors, useTextures, useNormals);
193
	GLenum drawMode;
194
	switch(renderType){
195
	case OF_MESH_POINTS:
196
		drawMode = GL_POINTS;
197
		break;
198
	case OF_MESH_WIREFRAME:
199
		drawMode = GL_LINE_STRIP;
200
		break;
201
	case OF_MESH_FILL:
202
		drawMode = ofGetGLPrimitiveMode(vertexData.getMode());
203
		break;
204
	default:
205
		drawMode = ofGetGLPrimitiveMode(vertexData.getMode());
206
		break;
207
	}
208
#endif
209
	if(meshVbo.getUsingIndices()) {
210
		drawElements(meshVbo,drawMode, meshVbo.getNumIndices());
211
	} else {
212
		draw(meshVbo, drawMode, 0, vertexData.getNumVertices());
213
	}
214
	
215
	// tig: note further that we could glGet() and store the current polygon mode, but don't, since that would
216
	// infer a massive performance hit. instead, we revert the glPolygonMode to mirror the current ofFill state
217
	// after we're finished drawing, following the principle of least surprise.
218
	// ideally the glPolygonMode (or the polygon draw mode) should be part of ofStyle so that we can keep track
219
	// of its state on the client side...
220

221
#ifndef TARGET_OPENGLES
222
	glPolygonMode(GL_FRONT_AND_BACK, currentStyle.bFill ?  GL_FILL : GL_LINE);
223
#endif
224
	
225
#endif
226
	
227
	//if (bSmoothHinted) endSmoothing();
228
}
229

230
//----------------------------------------------------------
231
void ofGLProgrammableRenderer::draw(const ofVboMesh & mesh, ofPolyRenderMode renderType) const{
232
	drawInstanced(mesh,renderType,1);
233
}
234

235
//----------------------------------------------------------
236
void ofGLProgrammableRenderer::drawInstanced(const ofVboMesh & mesh, ofPolyRenderMode renderType, int primCount) const{
237
	if(mesh.getNumVertices()==0) return;
238
	GLuint mode = ofGetGLPrimitiveMode(mesh.getMode());
239
#ifndef TARGET_OPENGLES
240
	glPolygonMode(GL_FRONT_AND_BACK, ofGetGLPolyMode(renderType));
241
	if(mesh.getNumIndices() && renderType!=OF_MESH_POINTS){
242
		if (primCount <= 1) {
243
			drawElements(mesh.getVbo(),mode,mesh.getNumIndices());
244
		} else {
245
			drawElementsInstanced(mesh.getVbo(),mode,mesh.getNumIndices(),primCount);
246
		}
247
	}else{
248
		if (primCount <= 1) {
249
			draw(mesh.getVbo(),mode,0,mesh.getNumVertices());
250
		} else {
251
			drawInstanced(mesh.getVbo(),mode,0,mesh.getNumVertices(),primCount);
252
		}
253
	}
254

255
	// tig: note further that we could glGet() and store the current polygon mode, but don't, since that would
256
	// infer a massive performance hit. instead, we revert the glPolygonMode to mirror the current ofFill state
257
	// after we're finished drawing, following the principle of least surprise.
258
	// ideally the glPolygonMode (or the polygon draw mode) should be part of ofStyle so that we can keep track
259
	// of its state on the client side...
260

261
	glPolygonMode(GL_FRONT_AND_BACK, currentStyle.bFill ?  GL_FILL : GL_LINE);
262
#else
263
	if(renderType == OF_MESH_POINTS){
264
		draw(mesh.getVbo(),GL_POINTS,0,mesh.getNumVertices());
265
	}else if(renderType == OF_MESH_WIREFRAME){
266
		if(mesh.getNumIndices()){
267
			drawElements(mesh.getVbo(),GL_LINES,mesh.getNumIndices());
268
		}else{
269
			draw(mesh.getVbo(),GL_LINES,0,mesh.getNumVertices());
270
		}
271
	}else{
272
		if(mesh.getNumIndices()){
273
			drawElements(mesh.getVbo(),mode,mesh.getNumIndices());
274
		}else{
275
			draw(mesh.getVbo(),mode,0,mesh.getNumVertices());
276
		}
277
	}
278
#endif
279
}
280

281
//----------------------------------------------------------
282
void ofGLProgrammableRenderer::draw( const of3dPrimitive& model, ofPolyRenderMode renderType) const {
283
	const_cast<ofGLProgrammableRenderer*>(this)->pushMatrix();
284
	const_cast<ofGLProgrammableRenderer*>(this)->multMatrix(model.getGlobalTransformMatrix());
285
	if(model.isUsingVbo()){
286
		draw(static_cast<const ofVboMesh&>(model.getMesh()),renderType);
287
	}else{
288
		draw(model.getMesh(),renderType);
289
	}
290
	const_cast<ofGLProgrammableRenderer*>(this)->popMatrix();
291
}
292

293
//----------------------------------------------------------
294
void ofGLProgrammableRenderer::draw(const ofNode& node) const{
295
	const_cast<ofGLProgrammableRenderer*>(this)->pushMatrix();
296
	const_cast<ofGLProgrammableRenderer*>(this)->multMatrix(node.getGlobalTransformMatrix());
297
	node.customDraw(this);
298
	const_cast<ofGLProgrammableRenderer*>(this)->popMatrix();
299
}
300

301
//----------------------------------------------------------
302
void ofGLProgrammableRenderer::draw(const ofPolyline & poly) const{
303
	if(poly.getVertices().empty()) return;
304

305
	// use smoothness, if requested:
306
	//if (bSmoothHinted) startSmoothing();
307

308
#if defined( TARGET_OPENGLES ) && !defined(TARGET_EMSCRIPTEN)
309

310
	glEnableVertexAttribArray(ofShader::POSITION_ATTRIBUTE);
311
	glVertexAttribPointer(ofShader::POSITION_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, sizeof(typename ofPolyline::VertexType), &poly[0]);
312

313
	const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(true,false,false,false);
314

315
	GLenum drawMode = poly.isClosed()?GL_LINE_LOOP:GL_LINE_STRIP;
316

317
	glDrawArrays(drawMode, 0, poly.size());
318

319
#else
320

321
	meshVbo.setVertexData(&poly.getVertices()[0], poly.size(), GL_DYNAMIC_DRAW);
322
	meshVbo.draw(poly.isClosed()?GL_LINE_LOOP:GL_LINE_STRIP, 0, poly.size());
323

324
#endif
325
	// use smoothness, if requested:
326
	//if (bSmoothHinted) endSmoothing();
327
}
328

329
//----------------------------------------------------------
330
void ofGLProgrammableRenderer::draw(const ofPath & shape) const{
331
	ofColor prevColor;
332
	if(shape.getUseShapeColor()){
333
		prevColor = currentStyle.color;
334
	}
335
	ofGLProgrammableRenderer * mut_this = const_cast<ofGLProgrammableRenderer*>(this);
336
	if(shape.isFilled()){
337
		const ofMesh & mesh = shape.getTessellation();
338
		if(shape.getUseShapeColor()){
339
			mut_this->setColor( shape.getFillColor(),shape.getFillColor().a);
340
		}
341
		draw(mesh,OF_MESH_FILL);
342
	}
343
	if(shape.hasOutline()){
344
		float lineWidth = currentStyle.lineWidth;
345
		if(shape.getUseShapeColor()){
346
			mut_this->setColor( shape.getStrokeColor(), shape.getStrokeColor().a);
347
		}
348
		mut_this->setLineWidth( shape.getStrokeWidth() );
349
		const vector<ofPolyline> & outlines = shape.getOutline();
350
		for(int i=0; i<(int)outlines.size(); i++)
351
			draw(outlines[i]);
352
		mut_this->setLineWidth(lineWidth);
353
	}
354
	if(shape.getUseShapeColor()){
355
		mut_this->setColor(prevColor);
356
	}
357
}
358

359
//----------------------------------------------------------
360
void ofGLProgrammableRenderer::draw(const ofImage & image, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const{
361
	if(image.isUsingTexture()){
362
		const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(true,false,true,false);
363
		const ofTexture& tex = image.getTexture();
364
		if(tex.isAllocated()) {
365
			const_cast<ofGLProgrammableRenderer*>(this)->bind(tex,0);
366
			draw(tex.getMeshForSubsection(x,y,z,w,h,sx,sy,sw,sh,isVFlipped(),currentStyle.rectMode),OF_MESH_FILL,false,true,false);
367
			const_cast<ofGLProgrammableRenderer*>(this)->unbind(tex,0);
368
		} else {
369
			ofLogWarning("ofGLProgrammableRenderer") << "draw(): texture is not allocated";
370
		}
371
	}
372
}
373

374
//----------------------------------------------------------
375
void ofGLProgrammableRenderer::draw(const ofFloatImage & image, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const{
376
	if(image.isUsingTexture()){
377
		const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(true,false,true,false);
378
		const ofTexture& tex = image.getTexture();
379
		if(tex.isAllocated()) {
380
			const_cast<ofGLProgrammableRenderer*>(this)->bind(tex,0);
381
			draw(tex.getMeshForSubsection(x,y,z,w,h,sx,sy,sw,sh,isVFlipped(),currentStyle.rectMode),OF_MESH_FILL,false,true,false);
382
			const_cast<ofGLProgrammableRenderer*>(this)->unbind(tex,0);
383
		} else {
384
			ofLogWarning("ofGLProgrammableRenderer") << "draw(): texture is not allocated";
385
		}
386
	}
387
}
388

389
//----------------------------------------------------------
390
void ofGLProgrammableRenderer::draw(const ofShortImage & image, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const{
391
	if(image.isUsingTexture()){
392
		const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(true,false,true,false);
393
		const ofTexture& tex = image.getTexture();
394
		if(tex.isAllocated()) {
395
			const_cast<ofGLProgrammableRenderer*>(this)->bind(tex,0);
396
			draw(tex.getMeshForSubsection(x,y,z,w,h,sx,sy,sw,sh,isVFlipped(),currentStyle.rectMode),OF_MESH_FILL,false,true,false);
397
			const_cast<ofGLProgrammableRenderer*>(this)->unbind(tex,0);
398
		} else {
399
			ofLogWarning("ofGLProgrammableRenderer") << "draw(): texture is not allocated";
400
		}
401
	}
402
}
403

404
//----------------------------------------------------------
405
void ofGLProgrammableRenderer::draw(const ofTexture & tex, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const{
406
	const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(true,false,true,false);
407
	if(tex.isAllocated()) {
408
		const_cast<ofGLProgrammableRenderer*>(this)->bind(tex,0);
409
		draw(tex.getMeshForSubsection(x,y,z,w,h,sx,sy,sw,sh,isVFlipped(),currentStyle.rectMode),OF_MESH_FILL,false,true,false);
410
		const_cast<ofGLProgrammableRenderer*>(this)->unbind(tex,0);
411
	} else {
412
		ofLogWarning("ofGLProgrammableRenderer") << "draw(): texture is not allocated";
413
	}
414
}
415

416
//----------------------------------------------------------
417
void ofGLProgrammableRenderer::draw(const ofBaseVideoDraws & video, float x, float y, float w, float h) const{
418
	if(!video.isInitialized() || !video.isUsingTexture() || video.getTexturePlanes().empty()){
419
		return;
420
	}
421
	const_cast<ofGLProgrammableRenderer*>(this)->bind(video);
422
	draw(video.getTexture().getMeshForSubsection(x,y,0,w,h,0,0,video.getWidth(),video.getHeight(),isVFlipped(),currentStyle.rectMode),OF_MESH_FILL,false,true,false);
423
	const_cast<ofGLProgrammableRenderer*>(this)->unbind(video);
424
}
425

426
//----------------------------------------------------------
427
void ofGLProgrammableRenderer::draw(const ofVbo & vbo, GLuint drawMode, int first, int total) const{
428
	if(vbo.getUsingVerts()) {
429
		vbo.bind();
430
		const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(vbo.getUsingVerts(),vbo.getUsingColors(),vbo.getUsingTexCoords(),vbo.getUsingNormals());
431
		glDrawArrays(drawMode, first, total);
432
		vbo.unbind();
433
	}
434
}
435

436
//----------------------------------------------------------
437
void ofGLProgrammableRenderer::drawElements(const ofVbo & vbo, GLuint drawMode, int amt, int offsetelements) const{
438
	if(vbo.getUsingVerts()) {
439
		vbo.bind();
440
		const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(vbo.getUsingVerts(),vbo.getUsingColors(),vbo.getUsingTexCoords(),vbo.getUsingNormals());
441
#ifdef TARGET_OPENGLES
442
        glDrawElements(drawMode, amt, GL_UNSIGNED_SHORT, (void*)(sizeof(ofIndexType) * offsetelements));
443
#else
444
        glDrawElements(drawMode, amt, GL_UNSIGNED_INT, (void*)(sizeof(ofIndexType) * offsetelements));
445
#endif
446
		vbo.unbind();
447
	}
448
}
449

450
//----------------------------------------------------------
451
void ofGLProgrammableRenderer::drawInstanced(const ofVbo & vbo, GLuint drawMode, int first, int total, int primCount) const{
452
	if(vbo.getUsingVerts()) {
453
		vbo.bind();
454
		const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(vbo.getUsingVerts(),vbo.getUsingColors(),vbo.getUsingTexCoords(),vbo.getUsingNormals());
455
#ifdef TARGET_OPENGLES
456
		// todo: activate instancing once OPENGL ES supports instancing, starting with version 3.0
457
		// unfortunately there is currently no easy way within oF to query the current OpenGL version.
458
		// https://www.khronos.org/opengles/sdk/docs/man3/xhtml/glDrawElementsInstanced.xml
459
		ofLogWarning("ofVbo") << "drawInstanced(): hardware instancing is not supported on OpenGL ES < 3.0";
460
		// glDrawArraysInstanced(drawMode, first, total, primCount);
461
#else
462
		glDrawArraysInstanced(drawMode, first, total, primCount);
463
#endif
464
		vbo.unbind();
465
	}
466
}
467

468
//----------------------------------------------------------
469
void ofGLProgrammableRenderer::drawElementsInstanced(const ofVbo & vbo, GLuint drawMode, int amt, int primCount) const{
470
	if(vbo.getUsingVerts()) {
471
		vbo.bind();
472
		const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(vbo.getUsingVerts(),vbo.getUsingColors(),vbo.getUsingTexCoords(),vbo.getUsingNormals());
473
#ifdef TARGET_OPENGLES
474
        // todo: activate instancing once OPENGL ES supports instancing, starting with version 3.0
475
        // unfortunately there is currently no easy way within oF to query the current OpenGL version.
476
        // https://www.khronos.org/opengles/sdk/docs/man3/xhtml/glDrawElementsInstanced.xml
477
        ofLogWarning("ofVbo") << "drawElementsInstanced(): hardware instancing is not supported on OpenGL ES < 3.0";
478
        // glDrawElementsInstanced(drawMode, amt, GL_UNSIGNED_SHORT, nullptr, primCount);
479
#else
480
        glDrawElementsInstanced(drawMode, amt, GL_UNSIGNED_INT, nullptr, primCount);
481
#endif
482
		vbo.unbind();
483
	}
484
}
485

486
//----------------------------------------------------------
487
ofPath & ofGLProgrammableRenderer::getPath(){
488
	return path;
489
}
490

491
//----------------------------------------------------------
492
void ofGLProgrammableRenderer::bind(const ofBaseVideoDraws & video){
493
	if(!video.isInitialized() || !video.isUsingTexture() || video.getTexturePlanes().empty()){
494
		return;
495
	}
496
	const ofShader * shader = nullptr;
497
	if(!usingCustomShader){
498
		shader = getVideoShader(video);
499
		if(shader){
500
			bind(*shader);
501
			setVideoShaderUniforms(video,*shader);
502
			usingVideoShader = true;
503
		}
504
	}
505

506
	if(!usingVideoShader){
507
		bind(video.getTexture(),0);
508
	}
509
}
510

511
//----------------------------------------------------------
512
void ofGLProgrammableRenderer::unbind(const ofBaseVideoDraws & video){
513
	if(!video.isInitialized() || !video.isUsingTexture() || video.getTexturePlanes().empty()){
514
		return;
515
	}
516
	if(usingVideoShader){
517
		unbind(*currentShader);
518
	}else{
519
		unbind(video.getTexture(),0);
520
	}
521
	usingVideoShader = false;
522
}
523

524
//----------------------------------------------------------
525
void ofGLProgrammableRenderer::pushView() {
526
	matrixStack.pushView();
527
}
528

529
//----------------------------------------------------------
530
void ofGLProgrammableRenderer::popView() {
531
	matrixStack.popView();
532
	uploadMatrices();
533
	viewport(matrixStack.getCurrentViewport());
534
}
535

536
//----------------------------------------------------------
537
void ofGLProgrammableRenderer::viewport(ofRectangle viewport_){
538
	viewport(viewport_.x,viewport_.y,viewport_.width,viewport_.height,isVFlipped());
539
}
540

541
//----------------------------------------------------------
542
void ofGLProgrammableRenderer::viewport(float x, float y, float width, float height, bool vflip) {
543
	matrixStack.viewport(x,y,width,height,vflip);
544
	ofRectangle nativeViewport = matrixStack.getNativeViewport();
545
	glViewport(nativeViewport.x,nativeViewport.y,nativeViewport.width,nativeViewport.height);
546
}
547

548
//----------------------------------------------------------
549
ofRectangle ofGLProgrammableRenderer::getCurrentViewport() const{
550
	return matrixStack.getCurrentViewport();
551
}
552

553
//----------------------------------------------------------
554
ofRectangle ofGLProgrammableRenderer::getNativeViewport() const{
555
    return matrixStack.getNativeViewport();
556
}
557

558
//----------------------------------------------------------
559
int ofGLProgrammableRenderer::getViewportWidth() const{
560
	return getCurrentViewport().width;
561
}
562

563
//----------------------------------------------------------
564
int ofGLProgrammableRenderer::getViewportHeight() const{
565
	return getCurrentViewport().height;
566
}
567

568
//----------------------------------------------------------
569
bool ofGLProgrammableRenderer::isVFlipped() const{
570
	return matrixStack.isVFlipped();
571
}
572

573
//----------------------------------------------------------
574
void ofGLProgrammableRenderer::setCoordHandedness(ofHandednessType handedness) {
575
	;
576
}
577

578
//----------------------------------------------------------
579
ofHandednessType ofGLProgrammableRenderer::getCoordHandedness() const{
580
	return matrixStack.getHandedness();
581
}
582

583
//----------------------------------------------------------
584
void ofGLProgrammableRenderer::setOrientation(ofOrientation orientation, bool vFlip){
585
	matrixStack.setOrientation(orientation,vFlip);
586
	uploadMatrices();
587

588
}
589

590
//----------------------------------------------------------
591
void ofGLProgrammableRenderer::setupScreenPerspective(float width, float height, float fov, float nearDist, float farDist) {
592
	float viewW, viewH;
593
	if(width<0 || height<0){
594
		ofRectangle currentViewport = getCurrentViewport();
595

596
		viewW = currentViewport.width;
597
		viewH = currentViewport.height;
598
	}else{
599
		viewW = width;
600
		viewH = height;
601
	}
602

603
	float eyeX = viewW / 2;
604
	float eyeY = viewH / 2;
605
	float halfFov = glm::pi<float>() * fov / 360.0f;
606
	float theTan = tanf(halfFov);
607
	float dist = eyeY / theTan;
608
	float aspect = (float) viewW / viewH;
609

610
	if(nearDist == 0) nearDist = dist / 10.0f;
611
	if(farDist == 0) farDist = dist * 10.0f;
612

613

614
	matrixMode(OF_MATRIX_PROJECTION);
615
	auto persp = glm::perspective(ofDegToRad(fov), aspect, nearDist, farDist);
616
	loadMatrix( persp );
617

618
	matrixMode(OF_MATRIX_MODELVIEW);
619
	auto lookAt = glm::lookAt( glm::vec3{eyeX, eyeY, dist},  glm::vec3{eyeX, eyeY, 0.f},  glm::vec3{0.f, 1.f, 0.f} );
620
	loadViewMatrix(lookAt);
621
	
622
	currentEyePos = glm::vec3{eyeX, eyeY, dist};
623
	
624
}
625

626
//----------------------------------------------------------
627
void ofGLProgrammableRenderer::setupScreenOrtho(float width, float height, float nearDist, float farDist) {
628
	float viewW, viewH;
629
	if(width<0 || height<0){
630
		ofRectangle currentViewport = getCurrentViewport();
631

632
		viewW = currentViewport.width;
633
		viewH = currentViewport.height;
634
	}else{
635
		viewW = width;
636
		viewH = height;
637
	}
638

639
	auto ortho = glm::ortho(0.f, viewW, 0.f, viewH, nearDist, farDist);
640

641
	matrixMode(OF_MATRIX_PROJECTION);
642
	loadMatrix(ortho); // make ortho our new projection matrix.
643

644
	matrixMode(OF_MATRIX_MODELVIEW);
645
	loadViewMatrix(glm::mat4(1.0));
646
	
647
	currentEyePos = glm::vec3{viewW/2.0f, viewH/2.0f, nearDist };
648
}
649

650
//----------------------------------------------------------
651
//Resets openGL parameters back to OF defaults
652
void ofGLProgrammableRenderer::setupGraphicDefaults(){
653
	setStyle(ofStyle());
654
	path.setMode(ofPath::POLYLINES);
655
	path.setUseShapeColor(false);
656
}
657

658
//----------------------------------------------------------
659
void ofGLProgrammableRenderer::setupScreen(){
660
	beginDefaultShader();
661
	setupScreenPerspective();	// assume defaults
662
}
663

664
//----------------------------------------------------------
665
void ofGLProgrammableRenderer::setCircleResolution(int res){
666
	if((int)circlePolyline.size()!=res+1){
667
		circlePolyline.clear();
668
		circlePolyline.arc(0,0,0,1,1,0,360,res);
669
		circleMesh.getVertices() = circlePolyline.getVertices();
670
		path.setCircleResolution(res);
671
	}
672
	currentStyle.circleResolution = res; 
673
}
674

675
//----------------------------------------------------------
676
void ofGLProgrammableRenderer::setPolyMode(ofPolyWindingMode mode){
677
	currentStyle.polyMode = mode;
678
	path.setPolyWindingMode(mode);
679
}
680

681
//our openGL wrappers
682
//----------------------------------------------------------
683
void ofGLProgrammableRenderer::pushMatrix(){
684
	matrixStack.pushMatrix();
685
}
686

687
//----------------------------------------------------------
688
void ofGLProgrammableRenderer::popMatrix(){
689
	matrixStack.popMatrix();
690
	uploadCurrentMatrix();
691
}
692

693
//----------------------------------------------------------
694
void ofGLProgrammableRenderer::translate(const glm::vec3& p){
695
	translate(p.x, p.y, p.z);
696
}
697

698
//----------------------------------------------------------
699
void ofGLProgrammableRenderer::translate(float x, float y, float z){
700
	matrixStack.translate(x,y,z);
701
	uploadCurrentMatrix();
702
}
703

704
//----------------------------------------------------------
705
void ofGLProgrammableRenderer::scale(float xAmnt, float yAmnt, float zAmnt){
706
	matrixStack.scale(xAmnt, yAmnt, zAmnt);
707
	uploadCurrentMatrix();
708
}
709

710
//----------------------------------------------------------
711
void ofGLProgrammableRenderer::rotateRad(float radians, float vecX, float vecY, float vecZ){
712
	matrixStack.rotateRad(radians, vecX, vecY, vecZ);
713
	uploadCurrentMatrix();
714
}
715

716
//----------------------------------------------------------
717
void ofGLProgrammableRenderer::rotateXRad(float radians){
718
	rotateRad(radians, 1, 0, 0);
719
}
720

721
//----------------------------------------------------------
722
void ofGLProgrammableRenderer::rotateYRad(float radians){
723
	rotateRad(radians, 0, 1, 0);
724
}
725

726
//----------------------------------------------------------
727
void ofGLProgrammableRenderer::rotateZRad(float radians){
728
	rotateRad(radians, 0, 0, 1);
729
}
730

731
//same as ofRotateZ
732
//----------------------------------------------------------
733
void ofGLProgrammableRenderer::rotateRad(float radians){
734
	rotateZRad(radians);
735
}
736

737
//----------------------------------------------------------
738
void ofGLProgrammableRenderer::matrixMode(ofMatrixMode mode){
739
	matrixStack.matrixMode(mode);
740
}
741

742
//----------------------------------------------------------
743
void ofGLProgrammableRenderer::loadIdentityMatrix (void){
744
	matrixStack.loadIdentityMatrix();
745
	uploadCurrentMatrix();
746
}
747

748
//----------------------------------------------------------
749
void ofGLProgrammableRenderer::loadMatrix (const glm::mat4 & m){
750
	matrixStack.loadMatrix(m);
751
	uploadCurrentMatrix();
752
}
753

754
//----------------------------------------------------------
755
void ofGLProgrammableRenderer::loadMatrix (const float *m){
756
	loadMatrix(glm::make_mat4(m));
757
}
758

759
//----------------------------------------------------------
760
void ofGLProgrammableRenderer::multMatrix (const glm::mat4 & m){
761
	matrixStack.multMatrix(m);
762
	uploadCurrentMatrix();
763
}
764

765
//----------------------------------------------------------
766
void ofGLProgrammableRenderer::multMatrix (const float *m){
767
	multMatrix(glm::make_mat4(m));
768
}
769

770
//----------------------------------------------------------
771
void ofGLProgrammableRenderer::loadViewMatrix(const glm::mat4 & m){
772
	matrixStack.loadViewMatrix(m);
773
	uploadCurrentMatrix();
774
}
775

776
//----------------------------------------------------------
777
void ofGLProgrammableRenderer::multViewMatrix(const glm::mat4 & m){
778
	matrixStack.multViewMatrix(m);
779
	uploadCurrentMatrix();
780
}
781

782
//----------------------------------------------------------
783
glm::mat4 ofGLProgrammableRenderer::getCurrentViewMatrix() const{
784
	return matrixStack.getViewMatrix();
785
}
786

787
//----------------------------------------------------------
788
glm::mat4 ofGLProgrammableRenderer::getCurrentNormalMatrix() const{
789
	return glm::transpose(glm::inverse(getCurrentMatrix(OF_MATRIX_MODELVIEW)));
790
}
791

792
//----------------------------------------------------------
793
glm::mat4 ofGLProgrammableRenderer::getCurrentModelMatrix() const{
794
	return matrixStack.getModelMatrix();
795
}
796

797
//----------------------------------------------------------
798
glm::vec3 ofGLProgrammableRenderer::getCurrentEyePosition() const {
799
	return currentEyePos;
800
}
801

802
//----------------------------------------------------------
803
void ofGLProgrammableRenderer::uploadCurrentMatrix(){
804
	if(!currentShader) return;
805
	// uploads the current matrix to the current shader.
806
	switch(matrixStack.getCurrentMatrixMode()){
807
	case OF_MATRIX_MODELVIEW:
808
		currentShader->setUniformMatrix4f(MODEL_MATRIX_UNIFORM, matrixStack.getModelMatrix());
809
		currentShader->setUniformMatrix4f(VIEW_MATRIX_UNIFORM, matrixStack.getViewMatrix());
810
		currentShader->setUniformMatrix4f(MODELVIEW_MATRIX_UNIFORM, matrixStack.getModelViewMatrix());
811
		currentShader->setUniformMatrix4f(MODELVIEW_PROJECTION_MATRIX_UNIFORM, matrixStack.getModelViewProjectionMatrix());
812
		if(currentMaterial){
813
			currentMaterial->uploadMatrices(*currentShader,*this);
814
		}
815
		break;
816
	case OF_MATRIX_PROJECTION:
817
		currentShader->setUniformMatrix4f(PROJECTION_MATRIX_UNIFORM, matrixStack.getProjectionMatrix());
818
		currentShader->setUniformMatrix4f(MODELVIEW_PROJECTION_MATRIX_UNIFORM, matrixStack.getModelViewProjectionMatrix());
819
		break;
820
	case OF_MATRIX_TEXTURE:
821
		currentShader->setUniformMatrix4f(TEXTURE_MATRIX_UNIFORM, matrixStack.getTextureMatrix());
822
		break;
823
	}
824

825
}
826

827
//----------------------------------------------------------
828
glm::mat4 ofGLProgrammableRenderer::getCurrentMatrix(ofMatrixMode matrixMode_) const {
829
	switch (matrixMode_) {
830
		case OF_MATRIX_MODELVIEW:
831
			return matrixStack.getModelViewMatrix();
832
			break;
833
		case OF_MATRIX_PROJECTION:
834
			return matrixStack.getProjectionMatrix();
835
			break;
836
		case OF_MATRIX_TEXTURE:
837
			return matrixStack.getTextureMatrix();
838
			break;
839
		default:
840
			ofLogWarning() << "Invalid getCurrentMatrix query";
841
			return glm::mat4(1.0);
842
			break;
843
	}
844
}
845

846
//----------------------------------------------------------
847
glm::mat4 ofGLProgrammableRenderer::getCurrentOrientationMatrix() const {
848
	return matrixStack.getOrientationMatrix();
849
}
850
//----------------------------------------------------------
851
void ofGLProgrammableRenderer::setColor(const ofColor & color){
852
	setColor(color.r,color.g,color.b,color.a);
853
}
854

855
//----------------------------------------------------------
856
void ofGLProgrammableRenderer::setColor(const ofColor & color, int _a){
857
	setColor(color.r,color.g,color.b,_a);
858
}
859

860
//----------------------------------------------------------
861
void ofGLProgrammableRenderer::setColor(int _r, int _g, int _b){
862
	setColor(_r, _g, _b, 255);
863
}
864

865
//----------------------------------------------------------
866
void ofGLProgrammableRenderer::setColor(int _r, int _g, int _b, int _a){
867
	ofColor newColor(_r,_g,_b,_a);
868
	if(newColor!=currentStyle.color){
869
        currentStyle.color = newColor;
870
		if(currentShader){
871
			currentShader->setUniform4f(COLOR_UNIFORM,_r/255.,_g/255.,_b/255.,_a/255.);
872
		}
873
	}
874
}
875

876
//----------------------------------------------------------
877
void ofGLProgrammableRenderer::setColor(int gray){
878
	setColor(gray, gray, gray);
879
}
880

881
//----------------------------------------------------------
882
void ofGLProgrammableRenderer::setHexColor(int hexColor){
883
	int r = (hexColor >> 16) & 0xff;
884
	int g = (hexColor >> 8) & 0xff;
885
	int b = (hexColor >> 0) & 0xff;
886
	setColor(r,g,b);
887
}
888

889
//----------------------------------------------------------
890
void ofGLProgrammableRenderer::setBitmapTextMode(ofDrawBitmapMode mode){
891
	currentStyle.drawBitmapMode = mode;
892
}
893

894
//----------------------------------------------------------
895
void ofGLProgrammableRenderer::clear(){
896
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
897
}
898

899
//----------------------------------------------------------
900
void ofGLProgrammableRenderer::clear(float r, float g, float b, float a) {
901
	glClearColor(r / 255., g / 255., b / 255., a / 255.);
902
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
903
}
904

905
//----------------------------------------------------------
906
void ofGLProgrammableRenderer::clear(float brightness, float a) {
907
	clear(brightness, brightness, brightness, a);
908
}
909

910
//----------------------------------------------------------
911
void ofGLProgrammableRenderer::clearAlpha() {
912
	glColorMask(0, 0, 0, 1);
913
	glClearColor(0, 0, 0, 1);
914
	glClear(GL_COLOR_BUFFER_BIT);
915
	glColorMask(1, 1, 1, 1);
916
}
917

918
//----------------------------------------------------------
919
void ofGLProgrammableRenderer::setBackgroundAuto(bool bAuto){
920
	bBackgroundAuto = bAuto;
921
}
922

923
//----------------------------------------------------------
924
bool ofGLProgrammableRenderer::getBackgroundAuto(){
925
	return bBackgroundAuto;
926
}
927

928
//----------------------------------------------------------
929
ofColor ofGLProgrammableRenderer::getBackgroundColor(){
930
	return currentStyle.bgColor;
931
}
932

933
//----------------------------------------------------------
934
void ofGLProgrammableRenderer::setBackgroundColor(const ofColor & c){
935
	currentStyle.bgColor = c;
936
	glClearColor(currentStyle.bgColor[0]/255., currentStyle.bgColor[1]/255., currentStyle.bgColor[2]/255., currentStyle.bgColor[3]/255.);
937
}
938

939
//----------------------------------------------------------
940
void ofGLProgrammableRenderer::background(const ofColor & c){
941
	setBackgroundColor(c);
942
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
943
}
944

945
//----------------------------------------------------------
946
void ofGLProgrammableRenderer::background(float brightness) {
947
	background(ofColor(brightness));
948
}
949

950
//----------------------------------------------------------
951
void ofGLProgrammableRenderer::background(int hexColor, float _a){
952
	background ( (hexColor >> 16) & 0xff, (hexColor >> 8) & 0xff, (hexColor >> 0) & 0xff, _a);
953
}
954

955
//----------------------------------------------------------
956
void ofGLProgrammableRenderer::background(int r, int g, int b, int a){
957
	background(ofColor(r,g,b,a));
958
}
959

960
//----------------------------------------------------------
961
void ofGLProgrammableRenderer::setFillMode(ofFillFlag fill){
962
	currentStyle.bFill = (fill==OF_FILLED);
963
	if(currentStyle.bFill){
964
		path.setFilled(true);
965
		path.setStrokeWidth(0);
966
		#ifndef TARGET_OPENGLES
967
			// GLES does not support glPolygonMode
968
			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
969
		#endif
970
	}else{
971
		path.setFilled(false);
972
		path.setStrokeWidth(currentStyle.lineWidth);
973
		#ifndef TARGET_OPENGLES
974
			// GLES does not support glPolygonMode
975
			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
976
		#endif
977
	}
978
}
979

980
//----------------------------------------------------------
981
ofFillFlag ofGLProgrammableRenderer::getFillMode(){
982
	if(currentStyle.bFill){
983
		return OF_FILLED;
984
	}else{
985
		return OF_OUTLINE;
986
	}
987
}
988

989
//----------------------------------------------------------
990
void ofGLProgrammableRenderer::setRectMode(ofRectMode mode){
991
	currentStyle.rectMode = mode;
992
}
993

994
//----------------------------------------------------------
995
ofRectMode ofGLProgrammableRenderer::getRectMode(){
996
	return currentStyle.rectMode;
997
}
998

999
//----------------------------------------------------------
1000
void ofGLProgrammableRenderer::setLineWidth(float lineWidth){
1001
	// tig: glLinewidth is 'kind of' deprecated.
1002
	// http://www.opengl.org/registry/doc/glspec32.core.20090803.pdf
1003
	// p.330: "LineWidth values greater than 1.0 will generate an
1004
	// INVALID_VALUE error".
1005
	// use geometry shaders to draw lines of varying thickness...
1006

1007
	currentStyle.lineWidth = lineWidth;
1008
	if(!currentStyle.bFill){
1009
		path.setStrokeWidth(lineWidth);
1010
	}
1011
	//glLineWidth(lineWidth);
1012
}
1013

1014
//----------------------------------------------------------
1015
void ofGLProgrammableRenderer::setDepthTest(bool depthTest) {
1016
	if(depthTest) {
1017
		glEnable(GL_DEPTH_TEST);
1018
	} else {
1019
		glDisable(GL_DEPTH_TEST);
1020
	}
1021
}
1022

1023
//----------------------------------------------------------
1024
void ofGLProgrammableRenderer::setLineSmoothing(bool smooth){
1025
	currentStyle.smoothing = smooth;
1026
}
1027

1028
//----------------------------------------------------------
1029
void ofGLProgrammableRenderer::startSmoothing(){
1030
    // TODO :: needs ES2 code.
1031
}
1032

1033
//----------------------------------------------------------
1034
void ofGLProgrammableRenderer::endSmoothing(){
1035
    // TODO :: needs ES2 code.
1036
}
1037

1038
//----------------------------------------------------------
1039
void ofGLProgrammableRenderer::setBlendMode(ofBlendMode blendMode){
1040
	switch (blendMode){
1041
		case OF_BLENDMODE_DISABLED:
1042
			glDisable(GL_BLEND);
1043
			break;
1044

1045
		case OF_BLENDMODE_ALPHA:
1046
			glEnable(GL_BLEND);
1047
			glBlendEquation(GL_FUNC_ADD);
1048
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1049
			break;
1050

1051
		case OF_BLENDMODE_ADD:
1052
			glEnable(GL_BLEND);
1053
			glBlendEquation(GL_FUNC_ADD);
1054
			glBlendFunc(GL_SRC_ALPHA, GL_ONE);
1055
			break;
1056

1057
		case OF_BLENDMODE_MULTIPLY:
1058
			glEnable(GL_BLEND);
1059
			glBlendEquation(GL_FUNC_ADD);
1060
			glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA /* GL_ZERO or GL_ONE_MINUS_SRC_ALPHA */);
1061
			break;
1062

1063
		case OF_BLENDMODE_SCREEN:
1064
			glEnable(GL_BLEND);
1065
			glBlendEquation(GL_FUNC_ADD);
1066
			glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE);
1067
			break;
1068

1069
		case OF_BLENDMODE_SUBTRACT:
1070
			glEnable(GL_BLEND);
1071
			glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
1072
			glBlendFunc(GL_SRC_ALPHA, GL_ONE);
1073
			break;
1074

1075
		default:
1076
			break;
1077
	}
1078
	currentStyle.blendingMode = blendMode;
1079
}
1080

1081
//----------------------------------------------------------
1082
void ofGLProgrammableRenderer::enablePointSprites(){
1083
#ifdef TARGET_OPENGLES
1084
	#ifndef TARGET_PROGRAMMABLE_GL
1085
		glEnable(GL_POINT_SPRITE_OES);
1086
	#endif
1087
#else
1088
	glEnable(GL_PROGRAM_POINT_SIZE);
1089
#endif
1090
}
1091

1092
//----------------------------------------------------------
1093
void ofGLProgrammableRenderer::disablePointSprites(){
1094
#ifdef TARGET_OPENGLES
1095
	#ifndef TARGET_PROGRAMMABLE_GL
1096
		glEnable(GL_POINT_SPRITE_OES);
1097
	#endif
1098
#else
1099
	glDisable(GL_PROGRAM_POINT_SIZE);
1100
#endif
1101
}
1102

1103

1104
//----------------------------------------------------------
1105
void ofGLProgrammableRenderer::enableAntiAliasing(){
1106
#if !defined(TARGET_PROGRAMMABLE_GL) || !defined(TARGET_OPENGLES)
1107
	glEnable(GL_MULTISAMPLE);
1108
#endif
1109
}
1110

1111
//----------------------------------------------------------
1112
void ofGLProgrammableRenderer::disableAntiAliasing(){
1113
#if !defined(TARGET_PROGRAMMABLE_GL) || !defined(TARGET_OPENGLES)
1114
	glDisable(GL_MULTISAMPLE);
1115
#endif
1116
}
1117

1118
//----------------------------------------------------------
1119
const ofShader & ofGLProgrammableRenderer::getCurrentShader() const{
1120
	return *currentShader;
1121
}
1122

1123
//----------------------------------------------------------
1124
void ofGLProgrammableRenderer::setAlphaBitmapText(bool bitmapText){
1125
	bool wasBitmapStringEnabled = bitmapStringEnabled;
1126
	bitmapStringEnabled = bitmapText;
1127

1128
	if(wasBitmapStringEnabled!=bitmapText){
1129
		if(currentShader) currentShader->setUniform1f(BITMAP_STRING_UNIFORM,bitmapText);
1130
	}
1131
}
1132

1133
ofStyle ofGLProgrammableRenderer::getStyle() const{
1134
	return currentStyle;
1135
}
1136

1137
void ofGLProgrammableRenderer::pushStyle(){
1138
	styleHistory.push_back(currentStyle);
1139
	//if we are over the max number of styles we have set, then delete the oldest styles.
1140
	if( styleHistory.size() > OF_MAX_STYLE_HISTORY ){
1141
		styleHistory.pop_front();
1142
		//should we warn here?
1143
		ofLogWarning("ofGraphics") << "ofPushStyle(): maximum number of style pushes << " << OF_MAX_STYLE_HISTORY << " reached, did you forget to pop somewhere?";
1144
	}
1145
}
1146

1147
void ofGLProgrammableRenderer::popStyle(){
1148
	if( styleHistory.size() ){
1149
		setStyle(styleHistory.back());
1150
		styleHistory.pop_back();
1151
	}
1152
}
1153

1154
void ofGLProgrammableRenderer::setStyle(const ofStyle & style){
1155

1156
	//color
1157
	setColor((int)style.color.r, (int)style.color.g, (int)style.color.b, (int)style.color.a);
1158

1159
	//bg color
1160
	setBackgroundColor(style.bgColor);
1161

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

1165
	setCurveResolution(style.curveResolution);
1166

1167
	//line width - finally!
1168
	setLineWidth(style.lineWidth);
1169

1170
	//ofSetDepthTest(style.depthTest); removed since it'll break old projects setting depth test through glEnable
1171

1172
	//rect mode: corner/center
1173
	setRectMode(style.rectMode);
1174

1175
	//poly mode: winding type
1176
	setPolyMode(style.polyMode);
1177

1178
	//fill
1179
	if(style.bFill ){
1180
		setFillMode(OF_FILLED);
1181
	}else{
1182
		setFillMode(OF_OUTLINE);
1183
	}
1184

1185
	//smoothing
1186
	/*if(style.smoothing ){
1187
		enableSmoothing();
1188
	}else{
1189
		disableSmoothing();
1190
	}*/
1191

1192
	//blending
1193
	setBlendMode(style.blendingMode);
1194

1195
	currentStyle = style;
1196
}
1197

1198
void ofGLProgrammableRenderer::setCurveResolution(int resolution){
1199
	currentStyle.curveResolution = resolution;
1200
	path.setCurveResolution(resolution);
1201
}
1202

1203
//----------------------------------------------------------
1204
void ofGLProgrammableRenderer::setAttributes(bool vertices, bool color, bool tex, bool normals){
1205
	bool wasColorsEnabled = colorsEnabled;
1206
	bool wasUsingTexture = texCoordsEnabled & (currentTextureTarget!=OF_NO_TEXTURE);
1207

1208
	texCoordsEnabled = tex;
1209
	colorsEnabled = color;
1210
	normalsEnabled = normals;
1211

1212
	if(!uniqueShader || currentMaterial){
1213
		beginDefaultShader();
1214
	}
1215

1216
	bool usingTexture = tex & (currentTextureTarget!=OF_NO_TEXTURE);
1217
	if(wasUsingTexture!=usingTexture){
1218
		if(currentShader) currentShader->setUniform1f(USE_TEXTURE_UNIFORM,usingTexture);
1219
	}
1220
	if(wasColorsEnabled!=color){
1221
		if(currentShader) currentShader->setUniform1f(USE_COLORS_UNIFORM,color);
1222
	}
1223
}
1224

1225
//----------------------------------------------------------
1226
void ofGLProgrammableRenderer::enableTextureTarget(const ofTexture & tex, int textureLocation){
1227
	bool wasUsingTexture = texCoordsEnabled & (currentTextureTarget!=OF_NO_TEXTURE);
1228
	currentTextureTarget = tex.texData.textureTarget;
1229

1230
	if(!uniqueShader || currentMaterial){
1231
		beginDefaultShader();
1232
	}
1233

1234
	bool usingTexture = texCoordsEnabled & (currentTextureTarget!=OF_NO_TEXTURE);
1235
	if(wasUsingTexture!=usingTexture){
1236
		if(currentShader) currentShader->setUniform1f(USE_TEXTURE_UNIFORM,usingTexture);
1237
	}
1238

1239
	if((currentTextureTarget!=OF_NO_TEXTURE) && currentShader){
1240
		currentShader->setUniformTexture("src_tex_unit"+ofToString(textureLocation),tex,textureLocation);
1241
	}
1242
}
1243

1244
//----------------------------------------------------------
1245
void ofGLProgrammableRenderer::disableTextureTarget(int textureTarget, int textureLocation){
1246
	bool wasUsingTexture = texCoordsEnabled & (currentTextureTarget!=OF_NO_TEXTURE);
1247
	currentTextureTarget = OF_NO_TEXTURE;
1248

1249
	if(!uniqueShader || currentMaterial){
1250
		beginDefaultShader();
1251
	}
1252

1253
	bool usingTexture = texCoordsEnabled & (currentTextureTarget!=OF_NO_TEXTURE);
1254
	if(wasUsingTexture!=usingTexture){
1255
		if(currentShader) currentShader->setUniform1f(USE_TEXTURE_UNIFORM,usingTexture);
1256
	}
1257
	glActiveTexture(GL_TEXTURE0+textureLocation);
1258
	glBindTexture(textureTarget, 0);
1259
	glActiveTexture(GL_TEXTURE0);
1260
}
1261

1262
//----------------------------------------------------------
1263
GLenum ofGLProgrammableRenderer::getCurrentTextureTarget(){
1264
	return currentTextureTarget;
1265
}
1266

1267
//----------------------------------------------------------
1268
void ofGLProgrammableRenderer::setAlphaMaskTex(const ofTexture & tex){
1269
	alphaMaskTextureTarget = tex.getTextureData().textureTarget;
1270
	if(alphaMaskTextureTarget==GL_TEXTURE_2D){
1271
		alphaMask2DShader.begin();
1272
	}else{
1273
		alphaMaskRectShader.begin();
1274
	}
1275
	enableTextureTarget(tex, 1);
1276
}
1277

1278
//----------------------------------------------------------
1279
void ofGLProgrammableRenderer::disableAlphaMask(){
1280
	disableTextureTarget(alphaMaskTextureTarget,1);
1281
	if(alphaMaskTextureTarget==GL_TEXTURE_2D){
1282
		alphaMask2DShader.end();
1283
	}else{
1284
		alphaMaskRectShader.end();
1285
	}
1286
}
1287

1288
//----------------------------------------------------------
1289
void ofGLProgrammableRenderer::bind(const ofShader & shader){
1290
    if(currentShader && *currentShader==shader){
1291
		return;
1292
    }
1293
	
1294
	if(bIsShadowDepthPass) {
1295
		// if we are not the shadow shader, lets unbind it
1296
		if(!settingDefaultShader && currentShadow && currentShader ) {
1297
			// lets assume it's bound?
1298
			if(!bCustomShadowShader) {
1299
				glUseProgram(0);
1300
			}
1301
			// we are assuming that since it's a custom depth shader, it all will be taken care of ...
1302
			bCustomShadowShader=true;
1303
		}
1304
	}
1305
	
1306
	glUseProgram(shader.getProgram());
1307

1308
	currentShader = &shader;
1309
	uploadMatrices();
1310
	setDefaultUniforms();
1311
	if(!settingDefaultShader){
1312
		usingCustomShader = true;
1313
	}
1314
}
1315

1316
//----------------------------------------------------------
1317
void ofGLProgrammableRenderer::unbind(const ofShader & shader){
1318
	glUseProgram(0);
1319
	usingCustomShader = false;
1320
	bCustomShadowShader=false;
1321
	beginDefaultShader();
1322
}
1323

1324
//----------------------------------------------------------
1325
void ofGLProgrammableRenderer::begin(const ofFbo & fbo, ofFboMode mode){
1326
	pushView();
1327
    pushStyle();
1328
    if(mode & OF_FBOMODE_MATRIXFLIP){
1329
        matrixStack.setRenderSurface(fbo);
1330
    }else{
1331
        matrixStack.setRenderSurfaceNoMatrixFlip(fbo);
1332
    }
1333
	viewport();
1334
    if(mode & OF_FBOMODE_PERSPECTIVE){
1335
		setupScreenPerspective();
1336
	}else{
1337
		uploadMatrices();
1338
	}
1339
	bind(fbo);
1340
}
1341

1342
//----------------------------------------------------------
1343
void ofGLProgrammableRenderer::end(const ofFbo & fbo){
1344
	unbind(fbo);
1345
	matrixStack.setRenderSurface(*window);
1346
	uploadMatrices();
1347
	popStyle();
1348
	popView();
1349
}
1350

1351
//----------------------------------------------------------
1352
void ofGLProgrammableRenderer::bind(const ofFbo & fbo){
1353
	if (currentFramebufferId == fbo.getId()){
1354
		ofLogWarning() << "Framebuffer with id: " << fbo.getId() << " cannot be bound onto itself. \n" <<
1355
			"Most probably you forgot to end() the current framebuffer before calling begin() again or you forgot to allocate() before calling begin().";
1356
		return;
1357
	}
1358
	// this method could just as well have been placed in ofBaseGLRenderer
1359
	// and shared over both programmable and fixed function renderer.
1360
	// I'm keeping it here, so that if we want to do more fancyful
1361
	// named framebuffers with GL 4.5+, we can have 
1362
	// different implementations.
1363
	framebufferIdStack.push_back(currentFramebufferId);
1364
	currentFramebufferId = fbo.getId();
1365
	glBindFramebuffer(GL_FRAMEBUFFER, currentFramebufferId);
1366
}
1367

1368
#ifndef TARGET_OPENGLES
1369
//----------------------------------------------------------
1370
void ofGLProgrammableRenderer::bindForBlitting(const ofFbo & fboSrc, ofFbo & fboDst, int attachmentPoint){
1371
	if (currentFramebufferId == fboSrc.getId()){
1372
		ofLogWarning() << "Framebuffer with id: " << fboSrc.getId() << " cannot be bound onto itself. \n" <<
1373
			"Most probably you forgot to end() the current framebuffer before calling getTexture().";
1374
		return;
1375
	}
1376
	// this method could just as well have been placed in ofBaseGLRenderer
1377
	// and shared over both programmable and fixed function renderer.
1378
	// I'm keeping it here, so that if we want to do more fancyful
1379
	// named framebuffers with GL 4.5+, we can have
1380
	// different implementations.
1381
	framebufferIdStack.push_back(currentFramebufferId);
1382
	currentFramebufferId = fboSrc.getId();
1383
	glBindFramebuffer(GL_READ_FRAMEBUFFER, currentFramebufferId);
1384
	glReadBuffer(GL_COLOR_ATTACHMENT0 + attachmentPoint);
1385
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboDst.getIdDrawBuffer());
1386
	glDrawBuffer(GL_COLOR_ATTACHMENT0 + attachmentPoint);
1387
}
1388
#endif
1389

1390
//----------------------------------------------------------
1391
void ofGLProgrammableRenderer::unbind(const ofFbo & fbo){
1392
	if(framebufferIdStack.empty()){
1393
		ofLogError() << "unbalanced fbo bind/unbind binding default framebuffer";
1394
		currentFramebufferId = defaultFramebufferId;
1395
	}else{
1396
		currentFramebufferId = framebufferIdStack.back();
1397
		framebufferIdStack.pop_back();
1398
	}
1399
	glBindFramebuffer(GL_FRAMEBUFFER, currentFramebufferId);
1400
	fbo.flagDirty();
1401
}
1402

1403
//----------------------------------------------------------
1404
void ofGLProgrammableRenderer::bind(const ofBaseMaterial & material){
1405
	if( bIsShadowDepthPass ) {
1406
//		currentMaterial = nullptr;
1407
		// we are the shadow depth pass right now, we don't need
1408
		// textures or lighting, etc.
1409
		return;
1410
	}
1411
	currentMaterial = &material;
1412
    // FIXME: this invalidates the previous shader to avoid that
1413
    // when binding 2 materials one after another, the second won't
1414
    // get the right parameters.
1415
	currentMaterial->bind(*this);
1416
    currentShader = nullptr;
1417
    beginDefaultShader();
1418
}
1419

1420
//----------------------------------------------------------
1421
void ofGLProgrammableRenderer::bind(const ofShadow & shadow) {
1422
	currentShadow = &shadow;
1423
	bIsShadowDepthPass = true;
1424
	beginDefaultShader();
1425
}
1426

1427
//----------------------------------------------------------
1428
void ofGLProgrammableRenderer::bind(const ofShadow & shadow, GLenum aCubeFace) {
1429
	shadowCubeFace = aCubeFace;
1430
	bind( shadow );
1431
}
1432

1433
//----------------------------------------------------------
1434
void ofGLProgrammableRenderer::unbind(const ofBaseMaterial &){
1435
	if(currentMaterial) {
1436
		currentMaterial->unbind(*this);
1437
	}
1438
    currentMaterial = nullptr;
1439
	if( bIsShadowDepthPass ) {
1440
		// we are the shadow depth pass right now, we don't need
1441
		// textures or lighting, etc.
1442
		return;
1443
	}
1444
	beginDefaultShader();
1445
}
1446

1447
//----------------------------------------------------------
1448
void ofGLProgrammableRenderer::unbind(const ofShadow & shadow) {
1449
	currentShadow = nullptr;
1450
	bIsShadowDepthPass = false;
1451
	bCustomShadowShader = false;
1452
	beginDefaultShader();
1453
}
1454

1455
//----------------------------------------------------------
1456
void ofGLProgrammableRenderer::unbind(const ofShadow & shadow, GLenum aCubeFace) {
1457
	unbind(shadow);
1458
}
1459

1460
//----------------------------------------------------------
1461
void ofGLProgrammableRenderer::enableLighting(){
1462

1463
}
1464

1465
//----------------------------------------------------------
1466
void ofGLProgrammableRenderer::disableLighting(){
1467
}
1468

1469
//----------------------------------------------------------
1470
void ofGLProgrammableRenderer::enableLight(int){
1471

1472
}
1473

1474
//----------------------------------------------------------
1475
void ofGLProgrammableRenderer::disableLight(int){
1476

1477
}
1478

1479
//----------------------------------------------------------
1480
bool ofGLProgrammableRenderer::getLightingEnabled(){
1481
    return true;
1482
}
1483

1484
//----------------------------------------------------------
1485
void ofGLProgrammableRenderer::bind(const ofTexture & texture, int location){
1486
	//we could check if it has been allocated - but we don't do that in draw()
1487
	if(texture.getAlphaMask()){
1488
		setAlphaMaskTex(*texture.getAlphaMask());
1489
	}
1490
	enableTextureTarget(texture,location);
1491

1492

1493
	if(ofGetUsingNormalizedTexCoords()) {
1494
		matrixMode(OF_MATRIX_TEXTURE);
1495
		pushMatrix();
1496
		glm::mat4 m = glm::mat4(1.0);
1497

1498
#ifndef TARGET_OPENGLES
1499
		if(texture.texData.textureTarget == GL_TEXTURE_RECTANGLE_ARB)
1500
			m = glm::scale(m, glm::vec3(texture.texData.width, texture.texData.height, 1.0f));
1501
		else
1502
#endif
1503
			m = glm::scale(m, glm::vec3(texture.texData.width / texture.texData.tex_w, texture.texData.height / texture.texData.tex_h, 1.0f));
1504

1505
		loadMatrix(m);
1506
		matrixMode(OF_MATRIX_MODELVIEW);
1507
	}
1508
	if(texture.isUsingTextureMatrix()){
1509
		matrixMode(OF_MATRIX_TEXTURE);
1510
		if(!ofGetUsingNormalizedTexCoords()) pushMatrix();
1511
		multMatrix(texture.getTextureMatrix());
1512
		matrixMode(OF_MATRIX_MODELVIEW);
1513
	}
1514
}
1515

1516
//----------------------------------------------------------
1517
void ofGLProgrammableRenderer::unbind(const ofTexture & texture, int location){
1518
	disableTextureTarget(texture.texData.textureTarget,location);
1519
	if(texture.getAlphaMask()){
1520
		disableAlphaMask();
1521
	}
1522

1523
	if(texture.isUsingTextureMatrix() || ofGetUsingNormalizedTexCoords()) {
1524
		matrixMode(OF_MATRIX_TEXTURE);
1525
		popMatrix();
1526
		matrixMode(OF_MATRIX_MODELVIEW);
1527
	}
1528
}
1529

1530
//----------------------------------------------------------
1531
void ofGLProgrammableRenderer::bind(const ofCamera & camera, const ofRectangle & _viewport){
1532
	pushView();
1533
	viewport(_viewport);
1534
	setOrientation(matrixStack.getOrientation(),camera.isVFlipped());
1535
	matrixMode(OF_MATRIX_PROJECTION);
1536
	loadMatrix(camera.getProjectionMatrix(_viewport));
1537
	matrixMode(OF_MATRIX_MODELVIEW);
1538
	loadViewMatrix(camera.getModelViewMatrix());
1539
	currentEyePos = camera.getPosition();
1540
}
1541

1542
//----------------------------------------------------------
1543
void ofGLProgrammableRenderer::unbind(const ofCamera & camera){
1544
	popView();
1545
}
1546

1547

1548
//----------------------------------------------------------
1549
void ofGLProgrammableRenderer::uploadMatrices(){
1550
	if(!currentShader) return;
1551
	currentShader->setUniformMatrix4f(MODEL_MATRIX_UNIFORM, matrixStack.getModelMatrix());
1552
	currentShader->setUniformMatrix4f(VIEW_MATRIX_UNIFORM, matrixStack.getViewMatrix());
1553
	currentShader->setUniformMatrix4f(MODELVIEW_MATRIX_UNIFORM, matrixStack.getModelViewMatrix());
1554
	currentShader->setUniformMatrix4f(PROJECTION_MATRIX_UNIFORM, matrixStack.getProjectionMatrix());
1555
	currentShader->setUniformMatrix4f(TEXTURE_MATRIX_UNIFORM, matrixStack.getTextureMatrix());
1556
	currentShader->setUniformMatrix4f(MODELVIEW_PROJECTION_MATRIX_UNIFORM, matrixStack.getModelViewProjectionMatrix());
1557
	if(currentMaterial){
1558
		currentMaterial->uploadMatrices(*currentShader,*this);
1559
	}
1560
}
1561

1562
//----------------------------------------------------------
1563
void ofGLProgrammableRenderer::setDefaultUniforms(){
1564
	if(!currentShader) return;
1565
	currentShader->setUniform4f(COLOR_UNIFORM, currentStyle.color.r/255.,currentStyle.color.g/255.,currentStyle.color.b/255.,currentStyle.color.a/255.);
1566
	bool usingTexture = texCoordsEnabled & (currentTextureTarget!=OF_NO_TEXTURE);
1567
	currentShader->setUniform1f(USE_TEXTURE_UNIFORM,usingTexture);
1568
	currentShader->setUniform1f(USE_COLORS_UNIFORM,colorsEnabled);
1569
	if(currentMaterial){
1570
		currentMaterial->updateMaterial(*currentShader,*this);
1571
		currentMaterial->updateLights(*currentShader,*this);
1572
		currentMaterial->updateShadows(*currentShader,*this);
1573
		currentMaterial->updateEnvironmentMaps(*currentShader, *this);
1574
	}
1575
	if(currentShadow) {
1576
		if( currentShadow->isMultiCubeFacePass() ) {
1577
			currentShadow->updateDepth(*currentShader, shadowCubeFace, *this);
1578
		} else {
1579
			currentShadow->updateDepth(*currentShader, *this);
1580
		}
1581
	}
1582
}
1583

1584
//----------------------------------------------------------
1585
void ofGLProgrammableRenderer::beginDefaultShader(){
1586
	if(usingCustomShader && !currentMaterial && !currentShadow)	return;
1587
	if( currentShadow && bCustomShadowShader ) return;
1588

1589
	const ofShader * nextShader = nullptr;
1590

1591
	if(!uniqueShader || currentMaterial || currentShadow ){
1592
		if(currentShadow) {
1593
			nextShader = &currentShadow->getDepthShader(*this);
1594
		} else if(currentMaterial){
1595
//			std::cout << "ofGLProgrammableRenderer::beginDefaultShader: " << currentTextureTarget << " | " << ofGetFrameNum() << std::endl;
1596
            nextShader = &currentMaterial->getShader(currentTextureTarget,colorsEnabled,*this);
1597

1598
		}else if(bitmapStringEnabled){
1599
			nextShader = &bitmapStringShader;
1600

1601
		}else if(colorsEnabled && texCoordsEnabled){
1602
			switch(currentTextureTarget){
1603
	#ifndef TARGET_OPENGLES
1604
			case GL_TEXTURE_RECTANGLE_ARB:
1605
				nextShader = &defaultTexRectColor;
1606
				break;
1607
	#endif
1608
			case GL_TEXTURE_2D:
1609
				nextShader = &defaultTex2DColor;
1610
				break;
1611
			case OF_NO_TEXTURE:
1612
				nextShader = &defaultNoTexColor;
1613
				break;
1614
	#ifdef TARGET_ANDROID
1615
			case GL_TEXTURE_EXTERNAL_OES:
1616
				nextShader = &defaultOESTexColor;
1617
				break;
1618
	#endif
1619
			}
1620

1621
		}else if(colorsEnabled){
1622
			nextShader = &defaultNoTexColor;
1623

1624
		}else if(texCoordsEnabled){
1625
			switch(currentTextureTarget){
1626
	#ifndef TARGET_OPENGLES
1627
			case GL_TEXTURE_RECTANGLE_ARB:
1628
				nextShader = &defaultTexRectNoColor;
1629
				break;
1630
	#endif
1631
			case GL_TEXTURE_2D:
1632
				nextShader = &defaultTex2DNoColor;
1633
				break;
1634
			case OF_NO_TEXTURE:
1635
				nextShader = &defaultNoTexNoColor;
1636
				break;
1637
	#ifdef TARGET_ANDROID
1638
			case GL_TEXTURE_EXTERNAL_OES:
1639
				nextShader = &defaultOESTexNoColor;
1640
				break;
1641
	#endif
1642
			}
1643

1644
		}else{
1645
			nextShader = &defaultNoTexNoColor;
1646
		}
1647

1648
	}else{
1649
		nextShader = &defaultUniqueShader;
1650
	}
1651

1652
	if(nextShader){
1653
        if(!currentShader || *currentShader!=*nextShader){
1654
			settingDefaultShader = true;
1655
			bind(*nextShader);
1656
			settingDefaultShader = false;
1657
		}
1658
	}
1659
}
1660

1661
//----------------------------------------------------------
1662
void ofGLProgrammableRenderer::drawLine(float x1, float y1, float z1, float x2, float y2, float z2) const{
1663
	ofGLProgrammableRenderer * mutThis = const_cast<ofGLProgrammableRenderer*>(this);
1664
	lineMesh.getVertices()[0] = {x1,y1,z1};
1665
	lineMesh.getVertices()[1] = {x2,y2,z2};
1666
    
1667
	// use smoothness, if requested:
1668
	if (currentStyle.smoothing) mutThis->startSmoothing();
1669
    
1670
	draw(lineMesh,OF_MESH_FILL,false,false,false);
1671
    
1672
	// use smoothness, if requested:
1673
	if (currentStyle.smoothing) mutThis->endSmoothing();
1674
}
1675

1676
//----------------------------------------------------------
1677
void ofGLProgrammableRenderer::drawRectangle(float x, float y, float z, float w, float h) const{
1678
	ofGLProgrammableRenderer * mutThis = const_cast<ofGLProgrammableRenderer*>(this);
1679
	if (currentStyle.rectMode == OF_RECTMODE_CORNER){
1680
		rectMesh.getVertices()[0] = {x,y,z};
1681
		rectMesh.getVertices()[1] = {x+w, y, z};
1682
		rectMesh.getVertices()[2] = {x+w, y+h, z};
1683
		rectMesh.getVertices()[3] = {x, y+h, z};
1684
	}else{
1685
		rectMesh.getVertices()[0] = {x-w/2.0f, y-h/2.0f, z};
1686
		rectMesh.getVertices()[1] = {x+w/2.0f, y-h/2.0f, z};
1687
		rectMesh.getVertices()[2] = {x+w/2.0f, y+h/2.0f, z};
1688
		rectMesh.getVertices()[3] = {x-w/2.0f, y+h/2.0f, z};
1689
	}
1690
    
1691
	// use smoothness, if requested:
1692
	if (currentStyle.smoothing && !currentStyle.bFill) mutThis->startSmoothing();
1693

1694
	rectMesh.setMode(currentStyle.bFill ? OF_PRIMITIVE_TRIANGLE_FAN : OF_PRIMITIVE_LINE_LOOP);
1695
	draw(rectMesh,OF_MESH_FILL,false,false,false);
1696
    
1697
	// use smoothness, if requested:
1698
	if (currentStyle.smoothing && !currentStyle.bFill) mutThis->endSmoothing();
1699
}
1700

1701
//----------------------------------------------------------
1702
void ofGLProgrammableRenderer::drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3) const{
1703
	ofGLProgrammableRenderer * mutThis = const_cast<ofGLProgrammableRenderer*>(this);
1704
	triangleMesh.getVertices()[0] = {x1,y1,z1};
1705
	triangleMesh.getVertices()[1] = {x2,y2,z2};
1706
	triangleMesh.getVertices()[2] = {x3,y3,z3};
1707
    
1708
	// use smoothness, if requested:
1709
	if (currentStyle.smoothing && !currentStyle.bFill) mutThis->startSmoothing();
1710

1711
	triangleMesh.setMode(currentStyle.bFill ? OF_PRIMITIVE_TRIANGLE_STRIP : OF_PRIMITIVE_LINE_LOOP);
1712
	draw(triangleMesh,OF_MESH_FILL,false,false,false);
1713
    
1714
	// use smoothness, if requested:
1715
	if (currentStyle.smoothing && !currentStyle.bFill) mutThis->endSmoothing();
1716
}
1717

1718
//----------------------------------------------------------
1719
void ofGLProgrammableRenderer::drawCircle(float x, float y, float z,  float radius) const{
1720
	ofGLProgrammableRenderer * mutThis = const_cast<ofGLProgrammableRenderer*>(this);
1721
	const auto & circleCache = circlePolyline.getVertices();
1722
	for(int i=0;i<(int)circleCache.size();i++){
1723
		circleMesh.getVertices()[i] = {radius*circleCache[i].x+x,radius*circleCache[i].y+y,z};
1724
	}
1725
    
1726
	// use smoothness, if requested:
1727
	if (currentStyle.smoothing && !currentStyle.bFill) mutThis->startSmoothing();
1728

1729
	circleMesh.setMode(currentStyle.bFill ? OF_PRIMITIVE_TRIANGLE_FAN : OF_PRIMITIVE_LINE_STRIP);
1730
	draw(circleMesh,OF_MESH_FILL,false,false,false);
1731
	
1732
	// use smoothness, if requested:
1733
	if (currentStyle.smoothing && !currentStyle.bFill) mutThis->endSmoothing();
1734
}
1735

1736
//----------------------------------------------------------
1737
void ofGLProgrammableRenderer::drawEllipse(float x, float y, float z, float width, float height) const{
1738
	ofGLProgrammableRenderer * mutThis = const_cast<ofGLProgrammableRenderer*>(this);
1739
	float radiusX = width*0.5;
1740
	float radiusY = height*0.5;
1741
	const auto & circleCache = circlePolyline.getVertices();
1742
	for(int i=0;i<(int)circleCache.size();i++){
1743
		circleMesh.getVertices()[i] = {radiusX*circlePolyline[i].x+x,radiusY*circlePolyline[i].y+y,z};
1744
	}
1745
    
1746
	// use smoothness, if requested:
1747
	if (currentStyle.smoothing && !currentStyle.bFill) mutThis->startSmoothing();
1748

1749
	circleMesh.setMode(currentStyle.bFill ? OF_PRIMITIVE_TRIANGLE_FAN : OF_PRIMITIVE_LINE_STRIP);
1750
	draw(circleMesh,OF_MESH_FILL,false,false,false);
1751
    
1752
	// use smoothness, if requested:
1753
	if (currentStyle.smoothing && !currentStyle.bFill) mutThis->endSmoothing();
1754
}
1755

1756
//----------------------------------------------------------
1757
void ofGLProgrammableRenderer::drawString(string textString, float x, float y, float z) const{
1758
	ofGLProgrammableRenderer * mutThis = const_cast<ofGLProgrammableRenderer*>(this);
1759
	float sx = 0;
1760
	float sy = 0;
1761

1762
	///////////////////////////
1763
	// APPLY TRANSFORM / VIEW
1764
	///////////////////////////
1765
	//
1766

1767
	bool hasModelView = false;
1768
	bool hasProjection = false;
1769
	bool hasViewport = false;
1770

1771
	ofRectangle rViewport;
1772
	glm::mat4 modelView = glm::mat4(1.0);
1773

1774
	switch (currentStyle.drawBitmapMode) {
1775

1776
		case OF_BITMAPMODE_SIMPLE:
1777

1778
			sx += x;
1779
			sy += y;
1780
			break;
1781

1782
		case OF_BITMAPMODE_SCREEN:
1783

1784
			hasViewport = true;
1785
			mutThis->pushView();
1786

1787
			rViewport = matrixStack.getFullSurfaceViewport();
1788
			mutThis->viewport(rViewport);
1789

1790
			mutThis->matrixMode(OF_MATRIX_PROJECTION);
1791
			mutThis->loadIdentityMatrix();
1792
			mutThis->matrixMode(OF_MATRIX_MODELVIEW);
1793

1794
			modelView = glm::translate(modelView, glm::vec3(-1,-1,0));
1795
			modelView = glm::scale(modelView, glm::vec3(2/rViewport.width, 2/rViewport.height, 1));
1796
			modelView = glm::translate(modelView, glm::vec3(x,y, 0));
1797
			mutThis->loadMatrix(modelView);
1798
			break;
1799

1800
		case OF_BITMAPMODE_VIEWPORT:
1801

1802
			rViewport = getCurrentViewport();
1803

1804
			hasProjection = true;
1805
			mutThis->matrixMode(OF_MATRIX_PROJECTION);
1806
			mutThis->pushMatrix();
1807
			mutThis->loadIdentityMatrix();
1808

1809
			hasModelView = true;
1810
			mutThis->matrixMode(OF_MATRIX_MODELVIEW);
1811
			mutThis->pushMatrix();
1812

1813
			modelView = glm::translate(modelView, glm::vec3(-1,-1,0));
1814
			modelView = glm::scale(modelView, glm::vec3(2/rViewport.width, 2/rViewport.height, 1));
1815
			modelView = glm::translate(modelView, glm::vec3(x,y, 0));
1816
			mutThis->loadMatrix(modelView);
1817
			break;
1818

1819
		case OF_BITMAPMODE_MODEL:
1820

1821
			hasModelView = true;
1822
			mutThis->matrixMode(OF_MATRIX_MODELVIEW);
1823
			mutThis->pushMatrix();
1824

1825
			mutThis->translate(x, y, z);
1826
			break;
1827

1828
		case OF_BITMAPMODE_MODEL_BILLBOARD:
1829
		{
1830
			//our aim here is to draw to screen
1831
			//at the viewport position related
1832
			//to the world position x,y,z
1833

1834
			// tig: we want to get the signed normalised screen coordinates (-1,+1) of our point (x,y,z)
1835
			// that's projection * modelview * point in GLSL multiplication order
1836
			// then doing the good old (v + 1.0) / 2. to get unsigned normalized screen (0,1) coordinates.
1837
			// we then multiply x by width and y by height to get window coordinates.
1838
			
1839
			rViewport = getCurrentViewport();
1840
			
1841
			glm::mat4 mat = matrixStack.getProjectionMatrixNoOrientation()  * matrixStack.getModelViewMatrix();
1842
			glm::vec4 dScreen4 = mat * glm::vec4(x,y,z,1.0);
1843
			glm::vec3 dScreen = glm::vec3(dScreen4) / dScreen4.w;
1844
			dScreen += glm::vec3(1.0) ;
1845
			dScreen *= 0.5;
1846
			
1847
			dScreen.x += rViewport.x;
1848
			dScreen.x *= rViewport.width;
1849

1850
			dScreen.y += rViewport.y;
1851
			dScreen.y *= rViewport.height;
1852
			
1853
			if (dScreen.z >= 1) return;
1854

1855

1856
			hasProjection = true;
1857
			mutThis->matrixMode(OF_MATRIX_PROJECTION);
1858
			mutThis->pushMatrix();
1859
			mutThis->loadIdentityMatrix();
1860

1861
			hasModelView = true;
1862
			mutThis->matrixMode(OF_MATRIX_MODELVIEW);
1863
			mutThis->pushMatrix();
1864

1865
			modelView = glm::translate(modelView, glm::vec3(-1,-1,0));
1866
			modelView = glm::scale(modelView, glm::vec3(2/rViewport.width, 2/rViewport.height, 1));
1867
			modelView = glm::translate(modelView, glm::vec3(dScreen.x, dScreen.y, 0));
1868
			mutThis->loadMatrix(modelView);
1869
		}
1870
			break;
1871

1872
		default:
1873
			break;
1874
	}
1875
	//
1876
	///////////////////////////
1877

1878
	// tig: we switch over to our built-in bitmapstring shader
1879
	// to render text. This gives us more flexibility & control
1880
	// and does not mess/interfere with client side shaders.
1881

1882
	// (c) enable texture once before we start drawing each char (no point turning it on and off constantly)
1883
	//We do this because its way faster
1884
	mutThis->setAlphaBitmapText(true);
1885
	ofMesh charMesh = bitmapFont.getMesh(textString, sx, sy, currentStyle.drawBitmapMode, isVFlipped());
1886
	mutThis->bind(bitmapFont.getTexture(),0);
1887
	draw(charMesh,OF_MESH_FILL,false,true,false);
1888
	mutThis->unbind(bitmapFont.getTexture(),0);
1889
	mutThis->setAlphaBitmapText(false);
1890

1891

1892
	if (hasViewport){
1893
		mutThis->popView();
1894
	}else{
1895
		if (hasModelView){
1896
			mutThis->popMatrix();
1897
		}
1898

1899
		if (hasProjection)
1900
		{
1901
			mutThis->matrixMode(OF_MATRIX_PROJECTION);
1902
			mutThis->popMatrix();
1903
			mutThis->matrixMode(OF_MATRIX_MODELVIEW);
1904
		}
1905
	}
1906
}
1907

1908

1909
//----------------------------------------------------------
1910
void ofGLProgrammableRenderer::drawString(const ofTrueTypeFont & font, string text, float x, float y) const{
1911
	ofGLProgrammableRenderer * mutThis = const_cast<ofGLProgrammableRenderer*>(this);
1912
	ofBlendMode blendMode = currentStyle.blendingMode;
1913

1914
	mutThis->setBlendMode(OF_BLENDMODE_ALPHA);
1915

1916
	mutThis->bind(font.getFontTexture(),0);
1917
	draw(font.getStringMesh(text,x,y,isVFlipped()),OF_MESH_FILL);
1918
	mutThis->unbind(font.getFontTexture(),0);
1919

1920
	mutThis->setBlendMode(blendMode);
1921
}
1922

1923
#define STRINGIFY(x) #x
1924

1925

1926
// ----------------------------------------------------------------------
1927
// tig: GLSL #150 shaders written against spec:
1928
// http://www.opengl.org/registry/doc/GLSLangSpec.1.50.09.pdf
1929

1930
#ifdef TARGET_OPENGLES
1931
static const string vertex_shader_header =
1932
		"%extensions%\n"
1933
		"precision highp float;\n"
1934
		"#define IN attribute\n"
1935
		"#define OUT varying\n"
1936
		"#define TEXTURE texture2D\n"
1937
		"#define TARGET_OPENGLES\n";
1938
static const string fragment_shader_header =
1939
		"%extensions%\n"
1940
		"precision highp float;\n"
1941
		"#define IN varying\n"
1942
		"#define OUT\n"
1943
		"#define TEXTURE texture2D\n"
1944
		"#define FRAG_COLOR gl_FragColor\n"
1945
		"#define TARGET_OPENGLES\n";
1946
#else
1947
static const string vertex_shader_header =
1948
		"#version %glsl_version%\n"
1949
		"%extensions%\n"
1950
		"#define IN in\n"
1951
		"#define OUT out\n"
1952
		"#define TEXTURE texture\n";
1953
static const string fragment_shader_header =
1954
		"#version %glsl_version%\n"
1955
		"%extensions%\n"
1956
		"#define IN in\n"
1957
		"#define OUT out\n"
1958
		"#define TEXTURE texture\n"
1959
		"#define FRAG_COLOR fragColor\n"
1960
		"out vec4 fragColor;\n";
1961
#endif
1962

1963
static const string defaultVertexShader = vertex_shader_header + STRINGIFY(
1964
	uniform mat4 projectionMatrix;
1965
	uniform mat4 modelViewMatrix;
1966
	uniform mat4 textureMatrix;
1967
	uniform mat4 modelViewProjectionMatrix;
1968

1969
	IN vec4  position;
1970
	IN vec2  texcoord;
1971
	IN vec4  color;
1972
	IN vec3  normal;
1973

1974
	OUT vec4 colorVarying;
1975
	OUT vec2 texCoordVarying;
1976
	OUT vec4 normalVarying;
1977

1978
	void main()
1979
	{
1980
		colorVarying = color;
1981
		texCoordVarying = (textureMatrix*vec4(texcoord.x,texcoord.y,0,1)).xy;
1982
		gl_Position = modelViewProjectionMatrix * position;
1983
	}
1984
);
1985

1986
// ----------------------------------------------------------------------
1987

1988
static const string defaultFragmentShaderTexRectColor = fragment_shader_header + STRINGIFY(
1989

1990
	uniform sampler2DRect src_tex_unit0;
1991
	uniform float usingTexture;
1992
	uniform float usingColors;
1993
	uniform vec4 globalColor;
1994

1995
	IN float depth;
1996
	IN vec4 colorVarying;
1997
	IN vec2 texCoordVarying;
1998

1999

2000
	void main(){
2001
		FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * colorVarying;
2002
	}
2003
);
2004

2005
// ----------------------------------------------------------------------
2006

2007
static const string defaultFragmentShaderTexRectNoColor = fragment_shader_header + STRINGIFY(
2008

2009
	uniform sampler2DRect src_tex_unit0;
2010
	uniform float usingTexture;
2011
	uniform float usingColors;
2012
	uniform vec4 globalColor;
2013

2014
	IN float depth;
2015
	IN vec4 colorVarying;
2016
	IN vec2 texCoordVarying;
2017

2018
	void main(){
2019
		FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying)* globalColor;
2020
	}
2021
);
2022

2023
// ----------------------------------------------------------------------
2024

2025
static const string alphaMaskFragmentShaderTexRectNoColor = fragment_shader_header + STRINGIFY(
2026

2027
	uniform sampler2DRect src_tex_unit0;
2028
	uniform sampler2DRect src_tex_unit1;
2029
	uniform float usingTexture;
2030
	uniform float usingColors;
2031
	uniform vec4 globalColor;
2032

2033
	IN float depth;
2034
	IN vec4 colorVarying;
2035
	IN vec2 texCoordVarying;
2036

2037
	void main(){
2038
		FRAG_COLOR = vec4(TEXTURE(src_tex_unit0, texCoordVarying).rgb,  TEXTURE(src_tex_unit1, texCoordVarying).r)* globalColor;
2039
	}
2040
);
2041

2042
// ----------------------------------------------------------------------
2043

2044
static const string alphaMaskFragmentShaderTex2DNoColor = fragment_shader_header + STRINGIFY(
2045

2046
	uniform sampler2D src_tex_unit0;
2047
	uniform sampler2D src_tex_unit1;
2048
	uniform float usingTexture;
2049
	uniform float usingColors;
2050
	uniform vec4 globalColor;
2051

2052
	IN float depth;
2053
	IN vec4 colorVarying;
2054
	IN vec2 texCoordVarying;
2055

2056
	void main(){
2057
		FRAG_COLOR = vec4(TEXTURE(src_tex_unit0, texCoordVarying).rgb,  TEXTURE(src_tex_unit1, texCoordVarying).r)* globalColor;
2058
	}
2059
);
2060

2061
// ----------------------------------------------------------------------
2062

2063
static const string defaultFragmentShaderTex2DColor = fragment_shader_header + STRINGIFY(
2064

2065
	uniform sampler2D src_tex_unit0;
2066
	uniform float usingTexture;
2067
	uniform float usingColors;
2068
	uniform vec4 globalColor;
2069

2070
	IN float depth;
2071
	IN vec4 colorVarying;
2072
	IN vec2 texCoordVarying;
2073

2074
	void main(){
2075
		FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * colorVarying;
2076
	}
2077
);
2078

2079
// ----------------------------------------------------------------------
2080

2081
static const string defaultFragmentShaderTex2DNoColor = fragment_shader_header + STRINGIFY(
2082

2083
	uniform sampler2D src_tex_unit0;
2084
	uniform float usingTexture;
2085
	uniform float usingColors;
2086
	uniform vec4 globalColor;
2087

2088
	IN float depth;
2089
	IN vec4 colorVarying;
2090
	IN vec2 texCoordVarying;
2091
	void main(){
2092
		FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * globalColor;
2093
	}
2094
);
2095

2096
// ----------------------------------------------------------------------
2097

2098
static const string defaultFragmentShaderOESTexNoColor = fragment_shader_header + STRINGIFY(
2099
    
2100
    uniform samplerExternalOES src_tex_unit0;
2101
    uniform float usingTexture;
2102
    uniform float usingColors;
2103
    uniform vec4 globalColor;
2104
    
2105
    IN float depth;
2106
    IN vec4 colorVarying;
2107
    IN vec2 texCoordVarying;
2108
    
2109
    void main(){
2110
        FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * globalColor;
2111
    }
2112
);
2113

2114
// ----------------------------------------------------------------------
2115

2116
static const string defaultFragmentShaderOESTexColor = fragment_shader_header + STRINGIFY(
2117
																							
2118
	uniform samplerExternalOES src_tex_unit0;
2119
	uniform float usingTexture;
2120
	uniform float usingColors;
2121
	uniform vec4 globalColor;
2122
	
2123
	IN float depth;
2124
	IN vec4 colorVarying;
2125
	IN vec2 texCoordVarying;
2126
	
2127
	void main(){
2128
		FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * colorVarying;
2129
	}
2130
);
2131

2132
// ----------------------------------------------------------------------
2133

2134
static const string defaultFragmentShaderNoTexColor = fragment_shader_header + STRINGIFY (
2135

2136
	uniform float usingTexture;
2137
	uniform float usingColors;
2138
	uniform vec4 globalColor;
2139

2140
	IN float depth;
2141
	IN vec4 colorVarying;
2142
	IN vec2 texCoordVarying;
2143

2144
	void main(){
2145
		FRAG_COLOR = colorVarying;
2146
	}
2147
);
2148

2149
// ----------------------------------------------------------------------
2150

2151
static const string defaultFragmentShaderNoTexNoColor = fragment_shader_header + STRINGIFY(
2152

2153
	uniform float usingTexture;
2154
	uniform float usingColors;
2155
	uniform vec4 globalColor;
2156

2157
	IN float depth;
2158
	IN vec4 colorVarying;
2159
	IN vec2 texCoordVarying;
2160

2161
	void main(){
2162
		FRAG_COLOR = globalColor;
2163
	}
2164
);
2165

2166
// ----------------------------------------------------------------------
2167

2168
static const string bitmapStringVertexShader = vertex_shader_header + STRINGIFY(
2169

2170
	uniform mat4 projectionMatrix;
2171
	uniform mat4 modelViewMatrix;
2172
	uniform mat4 textureMatrix;
2173
	uniform mat4 modelViewProjectionMatrix;
2174

2175
	IN vec4  position;
2176
	IN vec4  color;
2177
	IN vec2  texcoord;
2178

2179
	OUT vec2 texCoordVarying;
2180

2181
	void main()
2182
	{
2183
		texCoordVarying = texcoord;
2184
		gl_Position = modelViewProjectionMatrix * position;
2185
	}
2186
);
2187

2188
// ----------------------------------------------------------------------
2189

2190
static const string bitmapStringFragmentShader = fragment_shader_header + STRINGIFY(
2191

2192
	uniform sampler2D src_tex_unit0;
2193
	uniform vec4 globalColor;
2194

2195
	IN vec2 texCoordVarying;
2196

2197
	void main()
2198
	{
2199
		
2200
		vec4 tex = TEXTURE(src_tex_unit0, texCoordVarying);
2201
		// We will not write anything to the framebuffer if we have a transparent pixel
2202
		// This makes sure we don't mess up our depth buffer.
2203
		if (tex.a < 0.5) discard;
2204
		FRAG_COLOR = globalColor * tex;
2205
	}
2206
);
2207

2208
// ----------------------------------------------------------------------
2209
// changing shaders in raspberry pi is very expensive so we use only one shader there
2210
// in desktop openGL these are not used but we declare it to avoid more ifdefs
2211

2212
static const string uniqueVertexShader = vertex_shader_header + STRINGIFY(
2213
        
2214
	uniform mat4 modelViewMatrix;
2215
	uniform mat4 projectionMatrix;
2216
	uniform mat4 textureMatrix;
2217
	uniform mat4 modelViewProjectionMatrix;
2218
	uniform float usingTexture;
2219
	uniform float usingColors;
2220
	uniform vec4 globalColor;
2221

2222
	IN vec4 position;
2223
	IN vec4 color;
2224
	IN vec4 normal;
2225
	IN vec2 texcoord;
2226

2227
	OUT vec4 colorVarying;
2228
	OUT vec2 texCoordVarying;
2229

2230
	void main(){
2231
		gl_Position = modelViewProjectionMatrix * position;
2232
		if(usingTexture>.5) texCoordVarying = (textureMatrix*vec4(texcoord.x,texcoord.y,0,1)).xy;
2233
		if(usingColors>.5) colorVarying = color;
2234
		else colorVarying = globalColor;
2235
	}
2236
);
2237

2238
// ----------------------------------------------------------------------
2239
static const string uniqueFragmentShader = fragment_shader_header + STRINGIFY(
2240
        
2241
	uniform sampler2D src_tex_unit0;
2242
	uniform float usingTexture;
2243
	uniform float bitmapText;
2244

2245
	IN vec4 colorVarying;
2246
	IN vec2 texCoordVarying;
2247

2248
	void main(){
2249
		vec4 tex;
2250
		if(usingTexture>.5){
2251
			tex = TEXTURE(src_tex_unit0, texCoordVarying);
2252
			if(bitmapText>.5 && tex.a < 0.5){
2253
				discard;
2254
			}else{
2255
				FRAG_COLOR = colorVarying*tex;
2256
			}
2257
		}else{
2258
			FRAG_COLOR = colorVarying;
2259
		}
2260
	}
2261
);
2262

2263
// ----------------------------------------------------------------------
2264
// video color space conversion shaders
2265
static const string FRAGMENT_SHADER_YUY2 = STRINGIFY(
2266
	uniform SAMPLER src_tex_unit0;\n
2267
	uniform vec4 globalColor;\n
2268

2269
	IN vec4 colorVarying;\n
2270
	IN vec2 texCoordVarying;\n
2271
	uniform float onePixel;\n
2272
	uniform float textureWidth;\n
2273

2274
    const vec3 offset = vec3(-0.0625, -0.5, -0.5);\n
2275
    const vec3 rcoeff = vec3(1.164, 0.000, 1.596);\n
2276
    const vec3 gcoeff = vec3(1.164,-0.391,-0.813);\n
2277
    const vec3 bcoeff = vec3(1.164, 2.018, 0.000);\n
2278

2279

2280
	void main(){\n
2281
        vec3 yuv;\n
2282
	    yuv.x=TEXTURE(src_tex_unit0,texCoordVarying).r;\n
2283
		float x = texCoordVarying.x * textureWidth;\n
2284
		if(mod(x,2.0)>0.5){\n
2285
			yuv.y=TEXTURE(src_tex_unit0,vec2(texCoordVarying.x-onePixel,texCoordVarying.y)).%g;\n
2286
			yuv.z=TEXTURE(src_tex_unit0,texCoordVarying).%g;\n
2287
		}else{\n
2288
			yuv.y=TEXTURE(src_tex_unit0,texCoordVarying).%g;\n
2289
			yuv.z=TEXTURE(src_tex_unit0,vec2(texCoordVarying.x+onePixel,texCoordVarying.y)).%g;\n
2290
		}\n
2291
        yuv += offset;\n
2292
        float r = dot(yuv, rcoeff);\n
2293
        float g = dot(yuv, gcoeff);\n
2294
        float b = dot(yuv, bcoeff);\n
2295
        FRAG_COLOR=vec4(r,g,b,1.0) * globalColor;\n
2296
	}\n
2297
);
2298

2299
// ----------------------------------------------------------------------
2300
static const string FRAGMENT_SHADER_NV12_NV21 = STRINGIFY(
2301
	uniform SAMPLER Ytex;\n
2302
	uniform SAMPLER UVtex;\n
2303
	uniform vec4 globalColor;\n
2304
    uniform vec2 tex_scaleUV;\n
2305

2306
	IN vec4 colorVarying;\n
2307
	IN vec2 texCoordVarying;\n
2308

2309
    const vec3 offset = vec3(-0.0625, -0.5, -0.5);\n
2310
    const vec3 rcoeff = vec3(1.164, 0.000, 1.596);\n
2311
    const vec3 gcoeff = vec3(1.164,-0.391,-0.813);\n
2312
    const vec3 bcoeff = vec3(1.164, 2.018, 0.000);\n
2313

2314

2315
	void main(){\n
2316
        vec3 yuv;\n
2317
	    yuv.x=TEXTURE(Ytex,texCoordVarying).r;\n
2318
	    yuv.yz=TEXTURE(UVtex,texCoordVarying * tex_scaleUV).%r%g;\n
2319
        yuv += offset;\n
2320
        float r = dot(yuv, rcoeff);\n
2321
        float g = dot(yuv, gcoeff);\n
2322
        float b = dot(yuv, bcoeff);\n
2323
        FRAG_COLOR=vec4(r,g,b,1.0) * globalColor;\n
2324
	}\n
2325
);
2326

2327
// ----------------------------------------------------------------------
2328
static const string FRAGMENT_SHADER_PLANAR_YUV = STRINGIFY(
2329
	uniform SAMPLER Ytex;\n
2330
	uniform SAMPLER Utex;\n
2331
	uniform SAMPLER Vtex;\n
2332
    uniform vec2 tex_scaleY;\n
2333
    uniform vec2 tex_scaleU;\n
2334
    uniform vec2 tex_scaleV;\n
2335
	uniform vec4 globalColor;\n
2336

2337
	IN vec4 colorVarying;\n
2338
	IN vec2 texCoordVarying;\n
2339

2340
    const vec3 offset = vec3(-0.0625, -0.5, -0.5);\n
2341
    const vec3 rcoeff = vec3(1.164, 0.000, 1.596);\n
2342
    const vec3 gcoeff = vec3(1.164,-0.391,-0.813);\n
2343
    const vec3 bcoeff = vec3(1.164, 2.018, 0.000);\n
2344

2345

2346
	void main(){\n
2347
        vec3 yuv;\n
2348
	    yuv.x=TEXTURE(Ytex,texCoordVarying * tex_scaleY).r;\n
2349
	    yuv.y=TEXTURE(Utex,texCoordVarying * tex_scaleU).r;\n
2350
	    yuv.z=TEXTURE(Vtex,texCoordVarying * tex_scaleV).r;\n
2351
        yuv += offset;\n
2352
        float r = dot(yuv, rcoeff);\n
2353
        float g = dot(yuv, gcoeff);\n
2354
        float b = dot(yuv, bcoeff);\n
2355
        FRAG_COLOR=vec4(r,g,b,1.0) * globalColor;\n
2356
	}\n
2357
);
2358

2359
static string defaultShaderHeader(string header, GLenum textureTarget, int major, int minor){
2360
	ofStringReplace(header,"%glsl_version%",ofGLSLVersionFromGL(major,minor));
2361
#ifndef TARGET_OPENGLES
2362
	if(major<4 && minor<2){
2363
		ofStringReplace(header,"%extensions%","#extension GL_ARB_texture_rectangle : enable");
2364
	}else{
2365
		ofStringReplace(header,"%extensions%","");
2366
	}
2367
#else 
2368
	ofStringReplace(header,"%extensions%","#extension GL_OES_standard_derivatives : enable");
2369
#endif
2370
	if(textureTarget==GL_TEXTURE_2D){
2371
		header += "#define SAMPLER sampler2D\n";
2372
	}else{
2373
		header += "#define SAMPLER sampler2DRect\n";
2374
	}
2375
	return header;
2376
}
2377

2378

2379
static string shaderSource(const string & src, int major, int minor){
2380
	string shaderSrc = src;
2381
	ofStringReplace(shaderSrc,"%glsl_version%",ofGLSLVersionFromGL(major,minor));
2382
#ifndef TARGET_OPENGLES
2383
	if(major<4 && minor<2){
2384
		ofStringReplace(shaderSrc,"%extensions%","#extension GL_ARB_texture_rectangle : enable");
2385
	}else{
2386
		ofStringReplace(shaderSrc,"%extensions%","");
2387
	}
2388
#else
2389
	ofStringReplace(shaderSrc,"%extensions%","");
2390
#endif
2391
	return shaderSrc;
2392
}
2393

2394
#ifdef TARGET_ANDROID
2395
static string shaderOESSource(const string & src, int major, int minor){
2396
	string shaderSrc = src;
2397
	ofStringReplace(shaderSrc,"%glsl_version%",ofGLSLVersionFromGL(major,minor));
2398
	ofStringReplace(shaderSrc,"%extensions%","#extension GL_OES_EGL_image_external : require");
2399
	return shaderSrc;
2400
}
2401
#endif
2402

2403
static string videoFragmentShaderSource(const ofBaseVideoDraws & video, int major, int minor){
2404
	string src;
2405
	switch(video.getPixelFormat()){
2406
		case OF_PIXELS_YUY2:
2407
			src = FRAGMENT_SHADER_YUY2;
2408
			#ifndef TARGET_OPENGLES
2409
				ofStringReplace(src,"%g","g");
2410
			#else
2411
				ofStringReplace(src,"%g","a");
2412
			#endif
2413
			break;
2414
		case OF_PIXELS_NV12:
2415
			src = FRAGMENT_SHADER_NV12_NV21;
2416
			#ifndef TARGET_OPENGLES
2417
				ofStringReplace(src,"%r%g","rg");
2418
			#else
2419
				ofStringReplace(src,"%r%g","ra");
2420
			#endif
2421
			break;
2422
		case OF_PIXELS_NV21:
2423
			src = FRAGMENT_SHADER_NV12_NV21;
2424
			#ifndef TARGET_OPENGLES
2425
				ofStringReplace(src,"%r%g","gr");
2426
			#else
2427
				ofStringReplace(src,"%r%g","ar");
2428
			#endif
2429
			break;
2430
		case OF_PIXELS_YV12:
2431
		case OF_PIXELS_I420:
2432
			src = FRAGMENT_SHADER_PLANAR_YUV;
2433
			break;
2434
		case OF_PIXELS_RGB:
2435
		case OF_PIXELS_BGR:
2436
		case OF_PIXELS_RGB565:
2437
		case OF_PIXELS_RGBA:
2438
		case OF_PIXELS_BGRA:
2439
		case OF_PIXELS_GRAY:
2440
		default:
2441
			break;
2442
	}
2443

2444
	string header = fragment_shader_header;
2445
	GLenum textureTarget = video.getTexture().getTextureData().textureTarget;
2446
	if(textureTarget==GL_TEXTURE_2D){
2447
		header += "#define SAMPLER sampler2D\n";
2448
	}
2449
#ifndef TARGET_OPENGLES
2450
	else if(textureTarget==GL_TEXTURE_RECTANGLE){
2451
		header += "#define SAMPLER sampler2DRect\n";
2452
	}
2453
#endif
2454
	return shaderSource(header + src, major, minor);
2455
}
2456

2457
string ofGLProgrammableRenderer::defaultVertexShaderHeader(GLenum textureTarget){
2458
	return defaultShaderHeader(vertex_shader_header,textureTarget,major,minor);
2459
}
2460

2461
string ofGLProgrammableRenderer::defaultFragmentShaderHeader(GLenum textureTarget){
2462
	return defaultShaderHeader(fragment_shader_header,textureTarget,major,minor);
2463
}
2464

2465
void ofGLProgrammableRenderer::setup(int _major, int _minor){
2466
	glGetError();
2467
#ifdef TARGET_OPENGLES
2468
	// OpenGL ES might have set a default frame buffer for
2469
	// MSAA rendering to the window, bypassing ofFbo, so we
2470
	// can't trust ofFbo to have correctly tracked the bind
2471
	// state. Therefore, we are forced to use the slower glGet() method
2472
	// to be sure to get the correct default framebuffer.
2473
	GLint currentFrameBuffer;
2474
	glGetIntegerv(GL_FRAMEBUFFER_BINDING, &currentFrameBuffer);
2475
	defaultFramebufferId = currentFrameBuffer;
2476
    currentFramebufferId = defaultFramebufferId;
2477
#endif
2478

2479
	major = _major;
2480
	minor = _minor;
2481
#ifdef TARGET_RASPBERRY_PI
2482
	uniqueShader = true;
2483
#else
2484
	uniqueShader = false;
2485
#endif
2486

2487
	if(uniqueShader){
2488
		defaultUniqueShader.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(uniqueVertexShader, major, minor));
2489
		defaultUniqueShader.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(uniqueFragmentShader, major, minor));
2490
		defaultUniqueShader.bindDefaults();
2491
		defaultUniqueShader.linkProgram();
2492
		beginDefaultShader();
2493
	}else{
2494
	#ifndef TARGET_OPENGLES
2495
		defaultTexRectColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
2496
		defaultTexRectNoColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
2497
		alphaMaskRectShader.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
2498
	#endif
2499
		defaultTex2DColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
2500
		defaultNoTexColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
2501
		defaultTex2DNoColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
2502
		defaultNoTexNoColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
2503
		alphaMask2DShader.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
2504

2505
	#ifndef TARGET_OPENGLES
2506
		defaultTexRectColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(defaultFragmentShaderTexRectColor,major, minor));
2507
		defaultTexRectNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(defaultFragmentShaderTexRectNoColor,major, minor));
2508
		alphaMaskRectShader.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(alphaMaskFragmentShaderTexRectNoColor,major, minor));
2509
	#endif
2510
		defaultTex2DColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(defaultFragmentShaderTex2DColor,major, minor));
2511
		defaultNoTexColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(defaultFragmentShaderNoTexColor,major, minor));
2512
		defaultTex2DNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(defaultFragmentShaderTex2DNoColor,major, minor));
2513
		defaultNoTexNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(defaultFragmentShaderNoTexNoColor,major, minor));
2514
		alphaMask2DShader.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(alphaMaskFragmentShaderTex2DNoColor,major, minor));
2515

2516

2517
		bitmapStringShader.setupShaderFromSource(GL_VERTEX_SHADER, shaderSource(bitmapStringVertexShader,major, minor));
2518
		bitmapStringShader.setupShaderFromSource(GL_FRAGMENT_SHADER, shaderSource(bitmapStringFragmentShader,major, minor));
2519

2520
#ifndef TARGET_OPENGLES
2521
		defaultTexRectColor.bindDefaults();
2522
		defaultTexRectNoColor.bindDefaults();
2523
		alphaMaskRectShader.bindDefaults();
2524
#endif
2525
		defaultTex2DColor.bindDefaults();
2526
		defaultNoTexColor.bindDefaults();
2527
		defaultTex2DNoColor.bindDefaults();
2528
		defaultNoTexNoColor.bindDefaults();
2529
		alphaMask2DShader.bindDefaults();
2530

2531
#ifndef TARGET_OPENGLES
2532
		defaultTexRectColor.linkProgram();
2533
		defaultTexRectNoColor.linkProgram();
2534
		alphaMaskRectShader.linkProgram();
2535
#endif
2536
		defaultTex2DColor.linkProgram();
2537
		defaultNoTexColor.linkProgram();
2538
		defaultTex2DNoColor.linkProgram();
2539
		defaultNoTexNoColor.linkProgram();
2540
		alphaMask2DShader.linkProgram();
2541

2542
		bitmapStringShader.bindDefaults();
2543
		bitmapStringShader.linkProgram();
2544
		
2545
		
2546
#ifdef TARGET_ANDROID
2547
		defaultOESTexNoColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderOESSource(defaultVertexShader,major, minor));
2548
		defaultOESTexColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderOESSource(defaultVertexShader,major, minor));
2549
		defaultOESTexColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderOESSource(defaultFragmentShaderOESTexColor,major, minor));
2550
		defaultOESTexNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderOESSource(defaultFragmentShaderOESTexNoColor,major, minor));
2551
		
2552
		defaultOESTexColor.bindDefaults();
2553
		defaultOESTexNoColor.bindDefaults();
2554
		
2555
		defaultOESTexColor.linkProgram();
2556
		defaultOESTexNoColor.linkProgram();
2557
#endif
2558
	}
2559

2560
	setupGraphicDefaults();
2561
	viewport();
2562
	setupScreenPerspective();
2563
}
2564

2565
const ofShader * ofGLProgrammableRenderer::getVideoShader(const ofBaseVideoDraws & video) const{
2566
	const ofShader * shader = nullptr;
2567
	GLenum target = video.getTexture().getTextureData().textureTarget;
2568
	switch(video.getPixelFormat()){
2569
		case OF_PIXELS_YUY2:
2570
			if(target==GL_TEXTURE_2D){
2571
				shader = &shaderPlanarYUY2;
2572
			}else{
2573
				shader = &shaderPlanarYUY2Rect;
2574
			}
2575
			break;
2576
		case OF_PIXELS_NV12:
2577
			if(target==GL_TEXTURE_2D){
2578
				shader = &shaderNV12;
2579
			}else{
2580
				shader = &shaderNV12Rect;
2581
			}
2582
			break;
2583
		case OF_PIXELS_NV21:
2584
			if(target==GL_TEXTURE_2D){
2585
				shader = &shaderNV21;
2586
			}else{
2587
				shader = &shaderNV21Rect;
2588
			}
2589
			break;
2590
		case OF_PIXELS_YV12:
2591
		case OF_PIXELS_I420:
2592
			if(target==GL_TEXTURE_2D){
2593
				shader = &shaderPlanarYUV;
2594
			}else{
2595
				shader = &shaderPlanarYUVRect;
2596
			}
2597
			break;
2598
		case OF_PIXELS_RGB:
2599
		case OF_PIXELS_BGR:
2600
		case OF_PIXELS_RGB565:
2601
		case OF_PIXELS_RGBA:
2602
		case OF_PIXELS_BGRA:
2603
		case OF_PIXELS_GRAY:
2604
		default:
2605
			break;
2606
	}
2607
	if(shader && !shader->isLoaded()){
2608
		ofShader * mutShader = const_cast<ofShader*>(shader);
2609
		mutShader->setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major,minor));
2610
		mutShader->setupShaderFromSource(GL_FRAGMENT_SHADER,videoFragmentShaderSource(video,major,minor));
2611
		mutShader->bindDefaults();
2612
		mutShader->linkProgram();
2613
	}
2614
	return shader;
2615
}
2616

2617
#ifndef TARGET_OPENGLES
2618
static float getTextureScaleX(const ofBaseVideoDraws & video, int plane){
2619
	if(!video.getTexturePlanes().empty()){
2620
		return video.getTexturePlanes()[plane].getWidth()/video.getWidth();
2621
	}else{
2622
		return 1.0;
2623
	}
2624
}
2625

2626
static float getTextureScaleY(const ofBaseVideoDraws & video, int plane){
2627
	if(!video.getTexturePlanes().empty()){
2628
		return video.getTexturePlanes()[plane].getHeight()/video.getHeight();
2629
	}else{
2630
		return 1.0;
2631
	}
2632
}
2633
#endif
2634

2635
void ofGLProgrammableRenderer::setVideoShaderUniforms(const ofBaseVideoDraws & video, const ofShader & shader) const{
2636
	switch(video.getPixelFormat()){
2637
		case OF_PIXELS_YUY2:
2638
#ifndef TARGET_OPENGLES
2639
			if(video.getTexture().getTextureData().textureTarget==GL_TEXTURE_RECTANGLE){
2640
				shader.setUniform1f("onePixel",1.0);
2641
				shader.setUniform1f("textureWidth",1.0);
2642
			}else{
2643
#endif
2644
				shader.setUniform1f("onePixel",1.0/video.getWidth());
2645
				shader.setUniform1f("textureWidth",video.getWidth());
2646
#ifndef TARGET_OPENGLES
2647
			}
2648
#endif
2649
			shader.setUniformTexture("src_tex_unit0",video.getTexturePlanes()[0],0);
2650
			break;
2651
		case OF_PIXELS_NV12:
2652
		case OF_PIXELS_NV21:
2653
			shader.setUniformTexture("Ytex",video.getTexturePlanes()[0],0);
2654
			shader.setUniformTexture("UVtex",video.getTexturePlanes()[1],1);
2655
#ifndef TARGET_OPENGLES
2656
			if(video.getTexture().getTextureData().textureTarget==GL_TEXTURE_RECTANGLE){
2657
				shader.setUniform2f("tex_scaleUV",getTextureScaleX(video,1),getTextureScaleY(video,1));
2658
			}else{
2659
#endif
2660
				shader.setUniform2f("tex_scaleUV",1.0,1.0);
2661
#ifndef TARGET_OPENGLES
2662
			}
2663
#endif
2664
			break;
2665
		case OF_PIXELS_YV12:
2666
			shader.setUniformTexture("Ytex",video.getTexturePlanes()[0],0);
2667
			shader.setUniformTexture("Utex",video.getTexturePlanes()[2],1);
2668
			shader.setUniformTexture("Vtex",video.getTexturePlanes()[1],2);
2669
#ifndef TARGET_OPENGLES
2670
			if(video.getTexture().getTextureData().textureTarget==GL_TEXTURE_RECTANGLE){
2671
				shader.setUniform2f("tex_scaleY",getTextureScaleX(video,0),getTextureScaleY(video,0));
2672
				shader.setUniform2f("tex_scaleU",getTextureScaleX(video,2),getTextureScaleY(video,2));
2673
				shader.setUniform2f("tex_scaleV",getTextureScaleX(video,1),getTextureScaleY(video,1));
2674
			}else{
2675
#endif
2676
				shader.setUniform2f("tex_scaleY",1.0,1.0);
2677
				shader.setUniform2f("tex_scaleU",1.0,1.0);
2678
				shader.setUniform2f("tex_scaleV",1.0,1.0);
2679
#ifndef TARGET_OPENGLES
2680
			}
2681
#endif
2682
			break;
2683
		case OF_PIXELS_I420:
2684
			shader.setUniformTexture("Ytex",video.getTexturePlanes()[0],0);
2685
			shader.setUniformTexture("Utex",video.getTexturePlanes()[1],1);
2686
			shader.setUniformTexture("Vtex",video.getTexturePlanes()[2],2);
2687
#ifndef TARGET_OPENGLES
2688
			if(video.getTexture().getTextureData().textureTarget==GL_TEXTURE_RECTANGLE){
2689
				shader.setUniform2f("tex_scaleY",getTextureScaleX(video,0),getTextureScaleY(video,0));
2690
				shader.setUniform2f("tex_scaleU",getTextureScaleX(video,1),getTextureScaleY(video,1));
2691
				shader.setUniform2f("tex_scaleV",getTextureScaleX(video,2),getTextureScaleY(video,2));
2692
			}else{
2693
#endif
2694
				shader.setUniform2f("tex_scaleY",1.0,1.0);
2695
				shader.setUniform2f("tex_scaleU",1.0,1.0);
2696
				shader.setUniform2f("tex_scaleV",1.0,1.0);
2697
#ifndef TARGET_OPENGLES
2698
			}
2699
#endif
2700
			break;
2701
		default:
2702
			break;
2703
	}
2704
}
2705

2706
int ofGLProgrammableRenderer::getGLVersionMajor(){
2707
	return major;
2708
}
2709

2710
int ofGLProgrammableRenderer::getGLVersionMinor(){
2711
	return minor;
2712
}
2713

2714

2715
void ofGLProgrammableRenderer::saveFullViewport(ofPixels & pixels){
2716
	ofRectangle v = getCurrentViewport();
2717
	saveScreen(v.x,v.y,v.width,v.height,pixels);
2718
}
2719

2720
void ofGLProgrammableRenderer::saveScreen(int x, int y, int w, int h, ofPixels & pixels){
2721
    int sh = getViewportHeight();
2722

2723

2724
    #ifndef TARGET_OPENGLES
2725
	if(isVFlipped()){
2726
		y = sh - y;
2727
		y -= h; // top, bottom issues
2728
	}
2729
	auto pixelFormat = OF_PIXELS_BGRA;
2730
	pixels.allocate(w, h, pixelFormat);
2731
	auto glFormat = ofGetGLFormat(pixels);
2732

2733

2734
	ofBufferObject buffer;
2735
	buffer.allocate(pixels.size(), GL_STATIC_READ);
2736

2737
	buffer.bind(GL_PIXEL_PACK_BUFFER);
2738
	glReadPixels(x, y, w, h, glFormat, GL_UNSIGNED_BYTE, 0); // read the memory....
2739
	buffer.unbind(GL_PIXEL_PACK_BUFFER);
2740

2741
	if(unsigned char * p = buffer.map<unsigned char>(GL_READ_ONLY)){
2742
		ofPixels src;
2743
		src.setFromExternalPixels(p,w,h,pixelFormat);
2744
		src.mirrorTo(pixels,true,false);
2745
		buffer.unmap();
2746
	}else{
2747
		ofLogError("ofGLProgrammableRenderer") << "Error saving screen";
2748
	}
2749

2750
	#else
2751

2752
	int sw = getViewportWidth();
2753
	int numPixels   = w*h;
2754
	if( numPixels == 0 ){
2755
		ofLogError("ofImage") << "grabScreen(): unable to grab screen, image width and/or height are 0: " << w << "x" << h;
2756
		return;
2757
	}
2758
	pixels.allocate(w, h, OF_PIXELS_RGBA);
2759

2760
	switch(matrixStack.getOrientation()){
2761
	case OF_ORIENTATION_UNKNOWN:
2762
	case OF_ORIENTATION_DEFAULT:
2763

2764
		if(isVFlipped()){
2765
			y = sh - y;   // screen is flipped vertically.
2766
			y -= h;
2767
		}
2768

2769
		glPixelStorei(GL_PACK_ALIGNMENT, 1);
2770
		glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels.getData());
2771
		pixels.mirror(true,false);
2772
		break;
2773
	case OF_ORIENTATION_180:
2774

2775
		if(isVFlipped()){
2776
			x = sw - x;   // screen is flipped horizontally.
2777
			x -= w;
2778
		}
2779

2780
		glPixelStorei(GL_PACK_ALIGNMENT, 1);
2781
		glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels.getData());
2782
		pixels.mirror(false,true);
2783
		break;
2784
	case OF_ORIENTATION_90_RIGHT:
2785
		swap(w,h);
2786
		swap(x,y);
2787
		if(!isVFlipped()){
2788
			x = sw - x;   // screen is flipped horizontally.
2789
			x -= w;
2790

2791
			y = sh - y;   // screen is flipped vertically.
2792
			y -= h;
2793
		}
2794

2795
		glPixelStorei(GL_PACK_ALIGNMENT, 1);
2796
		glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels.getData());
2797
		pixels.mirror(true,true);
2798
		break;
2799
	case OF_ORIENTATION_90_LEFT:
2800
		swap(w, h);
2801
		swap(x, y);
2802
		if(isVFlipped()){
2803
			x = sw - x;   // screen is flipped horizontally.
2804
			x -= w;
2805

2806
			y = sh - y;   // screen is flipped vertically.
2807
			y -= h;
2808
		}
2809

2810
		glPixelStorei(GL_PACK_ALIGNMENT, 1);
2811
		glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels.getData());
2812
		pixels.mirror(true,true);
2813
		break;
2814
	}
2815

2816
	#endif
2817
}
2818

2819
const of3dGraphics & ofGLProgrammableRenderer::get3dGraphics() const{
2820
	return graphics3d;
2821
}
2822

2823
of3dGraphics & ofGLProgrammableRenderer::get3dGraphics(){
2824
	return graphics3d;
2825
}
2826

2827

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

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

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

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