#include "ofGLProgrammableRenderer.h"
#include "ofMesh.h"
#include "ofPath.h"
#include "ofMesh.h"
#include "ofBitmapFont.h"
#include "ofGLUtils.h"
#include "ofImage.h"
#include "ofFbo.h"
#include "ofVbo.h"
#include "of3dPrimitives.h"
#include "ofLight.h"
#include "ofMaterial.h"
#include "ofCamera.h"
#include "ofTrueTypeFont.h"
#include "ofNode.h"
#include "ofVideoBaseTypes.h"
using namespace std;
static const string MODEL_MATRIX_UNIFORM="modelMatrix";
static const string VIEW_MATRIX_UNIFORM="viewMatrix";
static const string MODELVIEW_MATRIX_UNIFORM="modelViewMatrix";
static const string PROJECTION_MATRIX_UNIFORM="projectionMatrix";
static const string MODELVIEW_PROJECTION_MATRIX_UNIFORM="modelViewProjectionMatrix";
static const string TEXTURE_MATRIX_UNIFORM="textureMatrix";
static const string COLOR_UNIFORM="globalColor";
static const string USE_TEXTURE_UNIFORM="usingTexture";
static const string USE_COLORS_UNIFORM="usingColors";
static const string BITMAP_STRING_UNIFORM="bitmapText";
const string ofGLProgrammableRenderer::TYPE="ProgrammableGL";
static bool programmableRendererCreated = false;
bool ofIsGLProgrammableRenderer(){
return programmableRendererCreated;
}
ofGLProgrammableRenderer::ofGLProgrammableRenderer(const ofAppBaseWindow * _window)
:matrixStack(_window)
,graphics3d(this)
{
programmableRendererCreated = true;
bBackgroundAuto = true;
lineMesh.getVertices().resize(2);
lineMesh.setMode(OF_PRIMITIVE_LINES);
triangleMesh.getVertices().resize(3);
rectMesh.getVertices().resize(4);
bitmapStringEnabled = false;
verticesEnabled = true;
colorsEnabled = false;
texCoordsEnabled = false;
normalsEnabled = false;
settingDefaultShader = false;
usingVideoShader = false;
usingCustomShader = false;
wrongUseLoggedOnce = false;
uniqueShader = false;
currentShader = nullptr;
currentTextureTarget = OF_NO_TEXTURE;
currentMaterial = nullptr;
alphaMaskTextureTarget = OF_NO_TEXTURE;
major = 3;
minor = 2;
window = _window;
currentFramebufferId = 0;
defaultFramebufferId = 0;
path.setMode(ofPath::POLYLINES);
path.setUseShapeColor(false);
}
void ofGLProgrammableRenderer::startRender() {
currentFramebufferId = defaultFramebufferId;
framebufferIdStack.push_back(defaultFramebufferId);
matrixStack.setRenderSurface(*window);
beginDefaultShader();
viewport();
#ifdef TARGET_WIN32
if (getBackgroundAuto() == false){
glDrawBuffer (GL_FRONT);
}
#endif
if ( getBackgroundAuto() ){
background(currentStyle.bgColor);
}
}
void ofGLProgrammableRenderer::finishRender() {
if (!uniqueShader) {
glUseProgram(0);
if(!usingCustomShader) currentShader = nullptr;
}
matrixStack.clearStacks();
framebufferIdStack.clear();
}
void ofGLProgrammableRenderer::draw(const ofMesh & vertexData, ofPolyRenderMode renderType, bool useColors, bool useTextures, bool useNormals) const{
if (vertexData.getVertices().empty()) return;
#if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN)
glEnableVertexAttribArray(ofShader::POSITION_ATTRIBUTE);
glVertexAttribPointer(ofShader::POSITION_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, sizeof(ofVec3f), vertexData.getVerticesPointer());
useNormals &= (vertexData.getNumNormals()>0);
if(useNormals){
glEnableVertexAttribArray(ofShader::NORMAL_ATTRIBUTE);
glVertexAttribPointer(ofShader::NORMAL_ATTRIBUTE, 3, GL_FLOAT, GL_TRUE, sizeof(ofVec3f), vertexData.getNormalsPointer());
}else{
glDisableVertexAttribArray(ofShader::NORMAL_ATTRIBUTE);
}
useColors &= (vertexData.getNumColors()>0);
if(useColors){
glEnableVertexAttribArray(ofShader::COLOR_ATTRIBUTE);
glVertexAttribPointer(ofShader::COLOR_ATTRIBUTE, 4,GL_FLOAT, GL_FALSE, sizeof(ofFloatColor), vertexData.getColorsPointer());
}else{
glDisableVertexAttribArray(ofShader::COLOR_ATTRIBUTE);
}
useTextures &= (vertexData.getNumTexCoords()>0);
if(useTextures){
glEnableVertexAttribArray(ofShader::TEXCOORD_ATTRIBUTE);
glVertexAttribPointer(ofShader::TEXCOORD_ATTRIBUTE,2, GL_FLOAT, GL_FALSE, sizeof(ofVec2f), vertexData.getTexCoordsPointer());
}else{
glDisableVertexAttribArray(ofShader::TEXCOORD_ATTRIBUTE);
}
const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(true,useColors,useTextures,useNormals);
GLenum drawMode;
switch(renderType){
case OF_MESH_POINTS:
drawMode = GL_POINTS;
break;
case OF_MESH_WIREFRAME:
drawMode = GL_LINES;
break;
case OF_MESH_FILL:
drawMode = ofGetGLPrimitiveMode(vertexData.getMode());
break;
default:
drawMode = ofGetGLPrimitiveMode(vertexData.getMode());
break;
}
if(vertexData.getNumIndices()){
glDrawElements(drawMode, vertexData.getNumIndices(),GL_UNSIGNED_SHORT,vertexData.getIndexPointer());
}else{
glDrawArrays(drawMode, 0, vertexData.getNumVertices());
}
#else
#ifndef TARGET_OPENGLES
meshVbo.setMesh(vertexData, GL_STREAM_DRAW, useColors, useTextures, useNormals);
glPolygonMode(GL_FRONT_AND_BACK, ofGetGLPolyMode(renderType));
GLenum drawMode = ofGetGLPrimitiveMode(vertexData.getMode());
#else
meshVbo.setMesh(vertexData, GL_STATIC_DRAW, useColors, useTextures, useNormals);
GLenum drawMode;
switch(renderType){
case OF_MESH_POINTS:
drawMode = GL_POINTS;
break;
case OF_MESH_WIREFRAME:
drawMode = GL_LINE_STRIP;
break;
case OF_MESH_FILL:
drawMode = ofGetGLPrimitiveMode(vertexData.getMode());
break;
default:
drawMode = ofGetGLPrimitiveMode(vertexData.getMode());
break;
}
#endif
if(meshVbo.getUsingIndices()) {
drawElements(meshVbo,drawMode, meshVbo.getNumIndices());
} else {
draw(meshVbo, drawMode, 0, vertexData.getNumVertices());
}
#ifndef TARGET_OPENGLES
glPolygonMode(GL_FRONT_AND_BACK, currentStyle.bFill ? GL_FILL : GL_LINE);
#endif
#endif
}
void ofGLProgrammableRenderer::draw(const ofVboMesh & mesh, ofPolyRenderMode renderType) const{
drawInstanced(mesh,renderType,1);
}
void ofGLProgrammableRenderer::drawInstanced(const ofVboMesh & mesh, ofPolyRenderMode renderType, int primCount) const{
if(mesh.getNumVertices()==0) return;
GLuint mode = ofGetGLPrimitiveMode(mesh.getMode());
#ifndef TARGET_OPENGLES
glPolygonMode(GL_FRONT_AND_BACK, ofGetGLPolyMode(renderType));
if(mesh.getNumIndices() && renderType!=OF_MESH_POINTS){
if (primCount <= 1) {
drawElements(mesh.getVbo(),mode,mesh.getNumIndices());
} else {
drawElementsInstanced(mesh.getVbo(),mode,mesh.getNumIndices(),primCount);
}
}else{
if (primCount <= 1) {
draw(mesh.getVbo(),mode,0,mesh.getNumVertices());
} else {
drawInstanced(mesh.getVbo(),mode,0,mesh.getNumVertices(),primCount);
}
}
glPolygonMode(GL_FRONT_AND_BACK, currentStyle.bFill ? GL_FILL : GL_LINE);
#else
if(renderType == OF_MESH_POINTS){
draw(mesh.getVbo(),GL_POINTS,0,mesh.getNumVertices());
}else if(renderType == OF_MESH_WIREFRAME){
if(mesh.getNumIndices()){
drawElements(mesh.getVbo(),GL_LINES,mesh.getNumIndices());
}else{
draw(mesh.getVbo(),GL_LINES,0,mesh.getNumVertices());
}
}else{
if(mesh.getNumIndices()){
drawElements(mesh.getVbo(),mode,mesh.getNumIndices());
}else{
draw(mesh.getVbo(),mode,0,mesh.getNumVertices());
}
}
#endif
}
void ofGLProgrammableRenderer::draw( const of3dPrimitive& model, ofPolyRenderMode renderType) const {
const_cast<ofGLProgrammableRenderer*>(this)->pushMatrix();
const_cast<ofGLProgrammableRenderer*>(this)->multMatrix(model.getGlobalTransformMatrix());
if(model.isUsingVbo()){
draw(static_cast<const ofVboMesh&>(model.getMesh()),renderType);
}else{
draw(model.getMesh(),renderType);
}
const_cast<ofGLProgrammableRenderer*>(this)->popMatrix();
}
void ofGLProgrammableRenderer::draw(const ofNode& node) const{
const_cast<ofGLProgrammableRenderer*>(this)->pushMatrix();
const_cast<ofGLProgrammableRenderer*>(this)->multMatrix(node.getGlobalTransformMatrix());
node.customDraw(this);
const_cast<ofGLProgrammableRenderer*>(this)->popMatrix();
}
void ofGLProgrammableRenderer::draw(const ofPolyline & poly) const{
if(poly.getVertices().empty()) return;
#if defined( TARGET_OPENGLES ) && !defined(TARGET_EMSCRIPTEN)
glEnableVertexAttribArray(ofShader::POSITION_ATTRIBUTE);
glVertexAttribPointer(ofShader::POSITION_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, sizeof(ofVec3f), &poly[0]);
const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(true,false,false,false);
GLenum drawMode = poly.isClosed()?GL_LINE_LOOP:GL_LINE_STRIP;
glDrawArrays(drawMode, 0, poly.size());
#else
meshVbo.setVertexData(&poly.getVertices()[0], poly.size(), GL_DYNAMIC_DRAW);
meshVbo.draw(poly.isClosed()?GL_LINE_LOOP:GL_LINE_STRIP, 0, poly.size());
#endif
}
void ofGLProgrammableRenderer::draw(const ofPath & shape) const{
ofColor prevColor;
if(shape.getUseShapeColor()){
prevColor = currentStyle.color;
}
ofGLProgrammableRenderer * mut_this = const_cast<ofGLProgrammableRenderer*>(this);
if(shape.isFilled()){
const ofMesh & mesh = shape.getTessellation();
if(shape.getUseShapeColor()){
mut_this->setColor( shape.getFillColor(),shape.getFillColor().a);
}
draw(mesh,OF_MESH_FILL);
}
if(shape.hasOutline()){
float lineWidth = currentStyle.lineWidth;
if(shape.getUseShapeColor()){
mut_this->setColor( shape.getStrokeColor(), shape.getStrokeColor().a);
}
mut_this->setLineWidth( shape.getStrokeWidth() );
const vector<ofPolyline> & outlines = shape.getOutline();
for(int i=0; i<(int)outlines.size(); i++)
draw(outlines[i]);
mut_this->setLineWidth(lineWidth);
}
if(shape.getUseShapeColor()){
mut_this->setColor(prevColor);
}
}
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{
if(image.isUsingTexture()){
const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(true,false,true,false);
const ofTexture& tex = image.getTexture();
if(tex.isAllocated()) {
const_cast<ofGLProgrammableRenderer*>(this)->bind(tex,0);
draw(tex.getMeshForSubsection(x,y,z,w,h,sx,sy,sw,sh,isVFlipped(),currentStyle.rectMode),OF_MESH_FILL,false,true,false);
const_cast<ofGLProgrammableRenderer*>(this)->unbind(tex,0);
} else {
ofLogWarning("ofGLProgrammableRenderer") << "draw(): texture is not allocated";
}
}
}
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{
if(image.isUsingTexture()){
const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(true,false,true,false);
const ofTexture& tex = image.getTexture();
if(tex.isAllocated()) {
const_cast<ofGLProgrammableRenderer*>(this)->bind(tex,0);
draw(tex.getMeshForSubsection(x,y,z,w,h,sx,sy,sw,sh,isVFlipped(),currentStyle.rectMode),OF_MESH_FILL,false,true,false);
const_cast<ofGLProgrammableRenderer*>(this)->unbind(tex,0);
} else {
ofLogWarning("ofGLProgrammableRenderer") << "draw(): texture is not allocated";
}
}
}
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{
if(image.isUsingTexture()){
const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(true,false,true,false);
const ofTexture& tex = image.getTexture();
if(tex.isAllocated()) {
const_cast<ofGLProgrammableRenderer*>(this)->bind(tex,0);
draw(tex.getMeshForSubsection(x,y,z,w,h,sx,sy,sw,sh,isVFlipped(),currentStyle.rectMode),OF_MESH_FILL,false,true,false);
const_cast<ofGLProgrammableRenderer*>(this)->unbind(tex,0);
} else {
ofLogWarning("ofGLProgrammableRenderer") << "draw(): texture is not allocated";
}
}
}
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{
const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(true,false,true,false);
if(tex.isAllocated()) {
const_cast<ofGLProgrammableRenderer*>(this)->bind(tex,0);
draw(tex.getMeshForSubsection(x,y,z,w,h,sx,sy,sw,sh,isVFlipped(),currentStyle.rectMode),OF_MESH_FILL,false,true,false);
const_cast<ofGLProgrammableRenderer*>(this)->unbind(tex,0);
} else {
ofLogWarning("ofGLProgrammableRenderer") << "draw(): texture is not allocated";
}
}
void ofGLProgrammableRenderer::draw(const ofBaseVideoDraws & video, float x, float y, float w, float h) const{
if(!video.isInitialized() || !video.isUsingTexture() || video.getTexturePlanes().empty()){
return;
}
const_cast<ofGLProgrammableRenderer*>(this)->bind(video);
draw(video.getTexture().getMeshForSubsection(x,y,0,w,h,0,0,video.getWidth(),video.getHeight(),isVFlipped(),currentStyle.rectMode),OF_MESH_FILL,false,true,false);
const_cast<ofGLProgrammableRenderer*>(this)->unbind(video);
}
void ofGLProgrammableRenderer::draw(const ofVbo & vbo, GLuint drawMode, int first, int total) const{
if(vbo.getUsingVerts()) {
vbo.bind();
const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(vbo.getUsingVerts(),vbo.getUsingColors(),vbo.getUsingTexCoords(),vbo.getUsingNormals());
glDrawArrays(drawMode, first, total);
vbo.unbind();
}
}
void ofGLProgrammableRenderer::drawElements(const ofVbo & vbo, GLuint drawMode, int amt, int offsetelements) const{
if(vbo.getUsingVerts()) {
vbo.bind();
const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(vbo.getUsingVerts(),vbo.getUsingColors(),vbo.getUsingTexCoords(),vbo.getUsingNormals());
#ifdef TARGET_OPENGLES
glDrawElements(drawMode, amt, GL_UNSIGNED_SHORT, (void*)(sizeof(ofIndexType) * offsetelements));
#else
glDrawElements(drawMode, amt, GL_UNSIGNED_INT, (void*)(sizeof(ofIndexType) * offsetelements));
#endif
vbo.unbind();
}
}
void ofGLProgrammableRenderer::drawInstanced(const ofVbo & vbo, GLuint drawMode, int first, int total, int primCount) const{
if(vbo.getUsingVerts()) {
vbo.bind();
const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(vbo.getUsingVerts(),vbo.getUsingColors(),vbo.getUsingTexCoords(),vbo.getUsingNormals());
#ifdef TARGET_OPENGLES
ofLogWarning("ofVbo") << "drawInstanced(): hardware instancing is not supported on OpenGL ES < 3.0";
#else
glDrawArraysInstanced(drawMode, first, total, primCount);
#endif
vbo.unbind();
}
}
void ofGLProgrammableRenderer::drawElementsInstanced(const ofVbo & vbo, GLuint drawMode, int amt, int primCount) const{
if(vbo.getUsingVerts()) {
vbo.bind();
const_cast<ofGLProgrammableRenderer*>(this)->setAttributes(vbo.getUsingVerts(),vbo.getUsingColors(),vbo.getUsingTexCoords(),vbo.getUsingNormals());
#ifdef TARGET_OPENGLES
ofLogWarning("ofVbo") << "drawElementsInstanced(): hardware instancing is not supported on OpenGL ES < 3.0";
#else
glDrawElementsInstanced(drawMode, amt, GL_UNSIGNED_INT, nullptr, primCount);
#endif
vbo.unbind();
}
}
ofPath & ofGLProgrammableRenderer::getPath(){
return path;
}
void ofGLProgrammableRenderer::bind(const ofBaseVideoDraws & video){
if(!video.isInitialized() || !video.isUsingTexture() || video.getTexturePlanes().empty()){
return;
}
const ofShader * shader = nullptr;
if(!usingCustomShader){
shader = getVideoShader(video);
if(shader){
bind(*shader);
setVideoShaderUniforms(video,*shader);
usingVideoShader = true;
}
}
if(!usingVideoShader){
bind(video.getTexture(),0);
}
}
void ofGLProgrammableRenderer::unbind(const ofBaseVideoDraws & video){
if(!video.isInitialized() || !video.isUsingTexture() || video.getTexturePlanes().empty()){
return;
}
if(usingVideoShader){
unbind(*currentShader);
}else{
unbind(video.getTexture(),0);
}
usingVideoShader = false;
}
void ofGLProgrammableRenderer::pushView() {
matrixStack.pushView();
}
void ofGLProgrammableRenderer::popView() {
matrixStack.popView();
uploadMatrices();
viewport(matrixStack.getCurrentViewport());
}
void ofGLProgrammableRenderer::viewport(ofRectangle viewport_){
viewport(viewport_.x,viewport_.y,viewport_.width,viewport_.height,isVFlipped());
}
void ofGLProgrammableRenderer::viewport(float x, float y, float width, float height, bool vflip) {
matrixStack.viewport(x,y,width,height,vflip);
ofRectangle nativeViewport = matrixStack.getNativeViewport();
glViewport(nativeViewport.x,nativeViewport.y,nativeViewport.width,nativeViewport.height);
}
ofRectangle ofGLProgrammableRenderer::getCurrentViewport() const{
return matrixStack.getCurrentViewport();
}
ofRectangle ofGLProgrammableRenderer::getNativeViewport() const{
return matrixStack.getNativeViewport();
}
int ofGLProgrammableRenderer::getViewportWidth() const{
return getCurrentViewport().width;
}
int ofGLProgrammableRenderer::getViewportHeight() const{
return getCurrentViewport().height;
}
bool ofGLProgrammableRenderer::isVFlipped() const{
return matrixStack.isVFlipped();
}
void ofGLProgrammableRenderer::setCoordHandedness(ofHandednessType handedness) {
;
}
ofHandednessType ofGLProgrammableRenderer::getCoordHandedness() const{
return matrixStack.getHandedness();
}
void ofGLProgrammableRenderer::setOrientation(ofOrientation orientation, bool vFlip){
matrixStack.setOrientation(orientation,vFlip);
uploadMatrices();
}
void ofGLProgrammableRenderer::setupScreenPerspective(float width, float height, float fov, float nearDist, float farDist) {
float viewW, viewH;
if(width<0 || height<0){
ofRectangle currentViewport = getCurrentViewport();
viewW = currentViewport.width;
viewH = currentViewport.height;
}else{
viewW = width;
viewH = height;
}
float eyeX = viewW / 2;
float eyeY = viewH / 2;
float halfFov = PI * fov / 360;
float theTan = tanf(halfFov);
float dist = eyeY / theTan;
float aspect = (float) viewW / viewH;
if(nearDist == 0) nearDist = dist / 10.0f;
if(farDist == 0) farDist = dist * 10.0f;
matrixMode(OF_MATRIX_PROJECTION);
auto persp = glm::perspective(ofDegToRad(fov), aspect, nearDist, farDist);
loadMatrix( persp );
matrixMode(OF_MATRIX_MODELVIEW);
auto lookAt = glm::lookAt( glm::vec3{eyeX, eyeY, dist}, glm::vec3{eyeX, eyeY, 0.f}, glm::vec3{0.f, 1.f, 0.f} );
loadViewMatrix(lookAt);
}
void ofGLProgrammableRenderer::setupScreenOrtho(float width, float height, float nearDist, float farDist) {
float viewW, viewH;
if(width<0 || height<0){
ofRectangle currentViewport = getCurrentViewport();
viewW = currentViewport.width;
viewH = currentViewport.height;
}else{
viewW = width;
viewH = height;
}
auto ortho = glm::ortho(0.f, viewW, 0.f, viewH, nearDist, farDist);
matrixMode(OF_MATRIX_PROJECTION);
loadMatrix(ortho);
matrixMode(OF_MATRIX_MODELVIEW);
loadViewMatrix(glm::mat4(1.0));
}
void ofGLProgrammableRenderer::setupGraphicDefaults(){
setStyle(ofStyle());
path.setMode(ofPath::POLYLINES);
path.setUseShapeColor(false);
}
void ofGLProgrammableRenderer::setupScreen(){
beginDefaultShader();
setupScreenPerspective();
}
void ofGLProgrammableRenderer::setCircleResolution(int res){
if((int)circlePolyline.size()!=res+1){
circlePolyline.clear();
circlePolyline.arc(0,0,0,1,1,0,360,res);
circleMesh.getVertices() = circlePolyline.getVertices();
path.setCircleResolution(res);
}
currentStyle.circleResolution = res;
}
void ofGLProgrammableRenderer::setPolyMode(ofPolyWindingMode mode){
currentStyle.polyMode = mode;
path.setPolyWindingMode(mode);
}
void ofGLProgrammableRenderer::pushMatrix(){
matrixStack.pushMatrix();
}
void ofGLProgrammableRenderer::popMatrix(){
matrixStack.popMatrix();
uploadCurrentMatrix();
}
void ofGLProgrammableRenderer::translate(const glm::vec3& p){
translate(p.x, p.y, p.z);
}
void ofGLProgrammableRenderer::translate(float x, float y, float z){
matrixStack.translate(x,y,z);
uploadCurrentMatrix();
}
void ofGLProgrammableRenderer::scale(float xAmnt, float yAmnt, float zAmnt){
matrixStack.scale(xAmnt, yAmnt, zAmnt);
uploadCurrentMatrix();
}
void ofGLProgrammableRenderer::rotateRad(float radians, float vecX, float vecY, float vecZ){
matrixStack.rotateRad(radians, vecX, vecY, vecZ);
uploadCurrentMatrix();
}
void ofGLProgrammableRenderer::rotateXRad(float radians){
rotateRad(radians, 1, 0, 0);
}
void ofGLProgrammableRenderer::rotateYRad(float radians){
rotateRad(radians, 0, 1, 0);
}
void ofGLProgrammableRenderer::rotateZRad(float radians){
rotateRad(radians, 0, 0, 1);
}
void ofGLProgrammableRenderer::rotateRad(float radians){
rotateZRad(radians);
}
void ofGLProgrammableRenderer::matrixMode(ofMatrixMode mode){
matrixStack.matrixMode(mode);
}
void ofGLProgrammableRenderer::loadIdentityMatrix (void){
matrixStack.loadIdentityMatrix();
uploadCurrentMatrix();
}
void ofGLProgrammableRenderer::loadMatrix (const glm::mat4 & m){
matrixStack.loadMatrix(m);
uploadCurrentMatrix();
}
void ofGLProgrammableRenderer::loadMatrix (const float *m){
loadMatrix(glm::make_mat4(m));
}
void ofGLProgrammableRenderer::multMatrix (const glm::mat4 & m){
matrixStack.multMatrix(m);
uploadCurrentMatrix();
}
void ofGLProgrammableRenderer::multMatrix (const float *m){
multMatrix(glm::make_mat4(m));
}
void ofGLProgrammableRenderer::loadViewMatrix(const glm::mat4 & m){
matrixStack.loadViewMatrix(m);
uploadCurrentMatrix();
}
void ofGLProgrammableRenderer::multViewMatrix(const glm::mat4 & m){
matrixStack.multViewMatrix(m);
uploadCurrentMatrix();
}
glm::mat4 ofGLProgrammableRenderer::getCurrentViewMatrix() const{
return matrixStack.getViewMatrix();
}
glm::mat4 ofGLProgrammableRenderer::getCurrentNormalMatrix() const{
return glm::transpose(glm::inverse(getCurrentMatrix(OF_MATRIX_MODELVIEW)));
}
void ofGLProgrammableRenderer::uploadCurrentMatrix(){
if(!currentShader) return;
switch(matrixStack.getCurrentMatrixMode()){
case OF_MATRIX_MODELVIEW:
currentShader->setUniformMatrix4f(MODEL_MATRIX_UNIFORM, matrixStack.getModelMatrix());
currentShader->setUniformMatrix4f(VIEW_MATRIX_UNIFORM, matrixStack.getViewMatrix());
currentShader->setUniformMatrix4f(MODELVIEW_MATRIX_UNIFORM, matrixStack.getModelViewMatrix());
currentShader->setUniformMatrix4f(MODELVIEW_PROJECTION_MATRIX_UNIFORM, matrixStack.getModelViewProjectionMatrix());
if(currentMaterial){
currentMaterial->uploadMatrices(*currentShader,*this);
}
break;
case OF_MATRIX_PROJECTION:
currentShader->setUniformMatrix4f(PROJECTION_MATRIX_UNIFORM, matrixStack.getProjectionMatrix());
currentShader->setUniformMatrix4f(MODELVIEW_PROJECTION_MATRIX_UNIFORM, matrixStack.getModelViewProjectionMatrix());
break;
case OF_MATRIX_TEXTURE:
currentShader->setUniformMatrix4f(TEXTURE_MATRIX_UNIFORM, matrixStack.getTextureMatrix());
break;
}
}
glm::mat4 ofGLProgrammableRenderer::getCurrentMatrix(ofMatrixMode matrixMode_) const {
switch (matrixMode_) {
case OF_MATRIX_MODELVIEW:
return matrixStack.getModelViewMatrix();
break;
case OF_MATRIX_PROJECTION:
return matrixStack.getProjectionMatrix();
break;
case OF_MATRIX_TEXTURE:
return matrixStack.getTextureMatrix();
break;
default:
ofLogWarning() << "Invalid getCurrentMatrix query";
return glm::mat4(1.0);
break;
}
}
glm::mat4 ofGLProgrammableRenderer::getCurrentOrientationMatrix() const {
return matrixStack.getOrientationMatrix();
}
void ofGLProgrammableRenderer::setColor(const ofColor & color){
setColor(color.r,color.g,color.b,color.a);
}
void ofGLProgrammableRenderer::setColor(const ofColor & color, int _a){
setColor(color.r,color.g,color.b,_a);
}
void ofGLProgrammableRenderer::setColor(int _r, int _g, int _b){
setColor(_r, _g, _b, 255);
}
void ofGLProgrammableRenderer::setColor(int _r, int _g, int _b, int _a){
ofColor newColor(_r,_g,_b,_a);
if(newColor!=currentStyle.color){
currentStyle.color = newColor;
if(currentShader){
currentShader->setUniform4f(COLOR_UNIFORM,_r/255.,_g/255.,_b/255.,_a/255.);
}
}
}
void ofGLProgrammableRenderer::setColor(int gray){
setColor(gray, gray, gray);
}
void ofGLProgrammableRenderer::setHexColor(int hexColor){
int r = (hexColor >> 16) & 0xff;
int g = (hexColor >> 8) & 0xff;
int b = (hexColor >> 0) & 0xff;
setColor(r,g,b);
}
void ofGLProgrammableRenderer::setBitmapTextMode(ofDrawBitmapMode mode){
currentStyle.drawBitmapMode = mode;
}
void ofGLProgrammableRenderer::clear(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void ofGLProgrammableRenderer::clear(float r, float g, float b, float a) {
glClearColor(r / 255., g / 255., b / 255., a / 255.);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void ofGLProgrammableRenderer::clear(float brightness, float a) {
clear(brightness, brightness, brightness, a);
}
void ofGLProgrammableRenderer::clearAlpha() {
glColorMask(0, 0, 0, 1);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glColorMask(1, 1, 1, 1);
}
void ofGLProgrammableRenderer::setBackgroundAuto(bool bAuto){
bBackgroundAuto = bAuto;
}
bool ofGLProgrammableRenderer::getBackgroundAuto(){
return bBackgroundAuto;
}
ofColor ofGLProgrammableRenderer::getBackgroundColor(){
return currentStyle.bgColor;
}
void ofGLProgrammableRenderer::setBackgroundColor(const ofColor & c){
currentStyle.bgColor = c;
glClearColor(currentStyle.bgColor[0]/255., currentStyle.bgColor[1]/255., currentStyle.bgColor[2]/255., currentStyle.bgColor[3]/255.);
}
void ofGLProgrammableRenderer::background(const ofColor & c){
setBackgroundColor(c);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
}
void ofGLProgrammableRenderer::background(float brightness) {
background(ofColor(brightness));
}
void ofGLProgrammableRenderer::background(int hexColor, float _a){
background ( (hexColor >> 16) & 0xff, (hexColor >> 8) & 0xff, (hexColor >> 0) & 0xff, _a);
}
void ofGLProgrammableRenderer::background(int r, int g, int b, int a){
background(ofColor(r,g,b,a));
}
void ofGLProgrammableRenderer::setFillMode(ofFillFlag fill){
currentStyle.bFill = (fill==OF_FILLED);
if(currentStyle.bFill){
path.setFilled(true);
path.setStrokeWidth(0);
#ifndef TARGET_OPENGLES
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
}else{
path.setFilled(false);
path.setStrokeWidth(currentStyle.lineWidth);
#ifndef TARGET_OPENGLES
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
#endif
}
}
ofFillFlag ofGLProgrammableRenderer::getFillMode(){
if(currentStyle.bFill){
return OF_FILLED;
}else{
return OF_OUTLINE;
}
}
void ofGLProgrammableRenderer::setRectMode(ofRectMode mode){
currentStyle.rectMode = mode;
}
ofRectMode ofGLProgrammableRenderer::getRectMode(){
return currentStyle.rectMode;
}
void ofGLProgrammableRenderer::setLineWidth(float lineWidth){
currentStyle.lineWidth = lineWidth;
if(!currentStyle.bFill){
path.setStrokeWidth(lineWidth);
}
}
void ofGLProgrammableRenderer::setDepthTest(bool depthTest) {
if(depthTest) {
glEnable(GL_DEPTH_TEST);
} else {
glDisable(GL_DEPTH_TEST);
}
}
void ofGLProgrammableRenderer::setLineSmoothing(bool smooth){
currentStyle.smoothing = smooth;
}
void ofGLProgrammableRenderer::startSmoothing(){
}
void ofGLProgrammableRenderer::endSmoothing(){
}
void ofGLProgrammableRenderer::setBlendMode(ofBlendMode blendMode){
switch (blendMode){
case OF_BLENDMODE_DISABLED:
glDisable(GL_BLEND);
break;
case OF_BLENDMODE_ALPHA:
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
break;
case OF_BLENDMODE_ADD:
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
break;
case OF_BLENDMODE_MULTIPLY:
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA );
break;
case OF_BLENDMODE_SCREEN:
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE);
break;
case OF_BLENDMODE_SUBTRACT:
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
break;
default:
break;
}
currentStyle.blendingMode = blendMode;
}
void ofGLProgrammableRenderer::enablePointSprites(){
#ifdef TARGET_OPENGLES
#ifndef TARGET_PROGRAMMABLE_GL
glEnable(GL_POINT_SPRITE_OES);
#endif
#else
glEnable(GL_PROGRAM_POINT_SIZE);
#endif
}
void ofGLProgrammableRenderer::disablePointSprites(){
#ifdef TARGET_OPENGLES
#ifndef TARGET_PROGRAMMABLE_GL
glEnable(GL_POINT_SPRITE_OES);
#endif
#else
glDisable(GL_PROGRAM_POINT_SIZE);
#endif
}
void ofGLProgrammableRenderer::enableAntiAliasing(){
#if !defined(TARGET_PROGRAMMABLE_GL) || !defined(TARGET_OPENGLES)
glEnable(GL_MULTISAMPLE);
#endif
}
void ofGLProgrammableRenderer::disableAntiAliasing(){
#if !defined(TARGET_PROGRAMMABLE_GL) || !defined(TARGET_OPENGLES)
glDisable(GL_MULTISAMPLE);
#endif
}
const ofShader & ofGLProgrammableRenderer::getCurrentShader() const{
return *currentShader;
}
void ofGLProgrammableRenderer::setAlphaBitmapText(bool bitmapText){
bool wasBitmapStringEnabled = bitmapStringEnabled;
bitmapStringEnabled = bitmapText;
if(wasBitmapStringEnabled!=bitmapText){
if(currentShader) currentShader->setUniform1f(BITMAP_STRING_UNIFORM,bitmapText);
}
}
ofStyle ofGLProgrammableRenderer::getStyle() const{
return currentStyle;
}
void ofGLProgrammableRenderer::pushStyle(){
styleHistory.push_back(currentStyle);
if( styleHistory.size() > OF_MAX_STYLE_HISTORY ){
styleHistory.pop_front();
ofLogWarning("ofGraphics") << "ofPushStyle(): maximum number of style pushes << " << OF_MAX_STYLE_HISTORY << " reached, did you forget to pop somewhere?";
}
}
void ofGLProgrammableRenderer::popStyle(){
if( styleHistory.size() ){
setStyle(styleHistory.back());
styleHistory.pop_back();
}
}
void ofGLProgrammableRenderer::setStyle(const ofStyle & style){
setColor((int)style.color.r, (int)style.color.g, (int)style.color.b, (int)style.color.a);
setBackgroundColor(style.bgColor);
setCircleResolution(style.circleResolution);
setCurveResolution(style.curveResolution);
setLineWidth(style.lineWidth);
setRectMode(style.rectMode);
setPolyMode(style.polyMode);
if(style.bFill ){
setFillMode(OF_FILLED);
}else{
setFillMode(OF_OUTLINE);
}
setBlendMode(style.blendingMode);
currentStyle = style;
}
void ofGLProgrammableRenderer::setCurveResolution(int resolution){
currentStyle.curveResolution = resolution;
path.setCurveResolution(resolution);
}
void ofGLProgrammableRenderer::setAttributes(bool vertices, bool color, bool tex, bool normals){
bool wasColorsEnabled = colorsEnabled;
bool wasUsingTexture = texCoordsEnabled & (currentTextureTarget!=OF_NO_TEXTURE);
texCoordsEnabled = tex;
colorsEnabled = color;
normalsEnabled = normals;
if(!uniqueShader || currentMaterial){
beginDefaultShader();
}
bool usingTexture = tex & (currentTextureTarget!=OF_NO_TEXTURE);
if(wasUsingTexture!=usingTexture){
if(currentShader) currentShader->setUniform1f(USE_TEXTURE_UNIFORM,usingTexture);
}
if(wasColorsEnabled!=color){
if(currentShader) currentShader->setUniform1f(USE_COLORS_UNIFORM,color);
}
}
void ofGLProgrammableRenderer::enableTextureTarget(const ofTexture & tex, int textureLocation){
bool wasUsingTexture = texCoordsEnabled & (currentTextureTarget!=OF_NO_TEXTURE);
currentTextureTarget = tex.texData.textureTarget;
if(!uniqueShader || currentMaterial){
beginDefaultShader();
}
bool usingTexture = texCoordsEnabled & (currentTextureTarget!=OF_NO_TEXTURE);
if(wasUsingTexture!=usingTexture){
if(currentShader) currentShader->setUniform1f(USE_TEXTURE_UNIFORM,usingTexture);
}
if((currentTextureTarget!=OF_NO_TEXTURE) && currentShader){
currentShader->setUniformTexture("src_tex_unit"+ofToString(textureLocation),tex,textureLocation);
}
}
void ofGLProgrammableRenderer::disableTextureTarget(int textureTarget, int textureLocation){
bool wasUsingTexture = texCoordsEnabled & (currentTextureTarget!=OF_NO_TEXTURE);
currentTextureTarget = OF_NO_TEXTURE;
if(!uniqueShader || currentMaterial){
beginDefaultShader();
}
bool usingTexture = texCoordsEnabled & (currentTextureTarget!=OF_NO_TEXTURE);
if(wasUsingTexture!=usingTexture){
if(currentShader) currentShader->setUniform1f(USE_TEXTURE_UNIFORM,usingTexture);
}
glActiveTexture(GL_TEXTURE0+textureLocation);
glBindTexture(textureTarget, 0);
glActiveTexture(GL_TEXTURE0);
}
GLenum ofGLProgrammableRenderer::getCurrentTextureTarget(){
return currentTextureTarget;
}
void ofGLProgrammableRenderer::setAlphaMaskTex(const ofTexture & tex){
alphaMaskTextureTarget = tex.getTextureData().textureTarget;
if(alphaMaskTextureTarget==GL_TEXTURE_2D){
alphaMask2DShader.begin();
}else{
alphaMaskRectShader.begin();
}
enableTextureTarget(tex, 1);
}
void ofGLProgrammableRenderer::disableAlphaMask(){
disableTextureTarget(alphaMaskTextureTarget,1);
if(alphaMaskTextureTarget==GL_TEXTURE_2D){
alphaMask2DShader.end();
}else{
alphaMaskRectShader.end();
}
}
void ofGLProgrammableRenderer::bind(const ofShader & shader){
if(currentShader && *currentShader==shader){
return;
}
glUseProgram(shader.getProgram());
currentShader = &shader;
uploadMatrices();
setDefaultUniforms();
if(!settingDefaultShader){
usingCustomShader = true;
}
}
void ofGLProgrammableRenderer::unbind(const ofShader & shader){
glUseProgram(0);
usingCustomShader = false;
beginDefaultShader();
}
void ofGLProgrammableRenderer::begin(const ofFbo & fbo, ofFboMode mode){
pushView();
pushStyle();
if(mode & OF_FBOMODE_MATRIXFLIP){
matrixStack.setRenderSurface(fbo);
}else{
matrixStack.setRenderSurfaceNoMatrixFlip(fbo);
}
viewport();
if(mode & OF_FBOMODE_PERSPECTIVE){
setupScreenPerspective();
}else{
uploadMatrices();
}
bind(fbo);
}
void ofGLProgrammableRenderer::end(const ofFbo & fbo){
unbind(fbo);
matrixStack.setRenderSurface(*window);
uploadMatrices();
popStyle();
popView();
}
void ofGLProgrammableRenderer::bind(const ofFbo & fbo){
if (currentFramebufferId == fbo.getId()){
ofLogWarning() << "Framebuffer with id: " << fbo.getId() << " cannot be bound onto itself. \n" <<
"Most probably you forgot to end() the current framebuffer before calling begin() again or you forgot to allocate() before calling begin().";
return;
}
framebufferIdStack.push_back(currentFramebufferId);
currentFramebufferId = fbo.getId();
glBindFramebuffer(GL_FRAMEBUFFER, currentFramebufferId);
}
#ifndef TARGET_OPENGLES
void ofGLProgrammableRenderer::bindForBlitting(const ofFbo & fboSrc, ofFbo & fboDst, int attachmentPoint){
if (currentFramebufferId == fboSrc.getId()){
ofLogWarning() << "Framebuffer with id: " << fboSrc.getId() << " cannot be bound onto itself. \n" <<
"Most probably you forgot to end() the current framebuffer before calling getTexture().";
return;
}
framebufferIdStack.push_back(currentFramebufferId);
currentFramebufferId = fboSrc.getId();
glBindFramebuffer(GL_READ_FRAMEBUFFER, currentFramebufferId);
glReadBuffer(GL_COLOR_ATTACHMENT0 + attachmentPoint);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboDst.getIdDrawBuffer());
glDrawBuffer(GL_COLOR_ATTACHMENT0 + attachmentPoint);
}
#endif
void ofGLProgrammableRenderer::unbind(const ofFbo & fbo){
if(framebufferIdStack.empty()){
ofLogError() << "unbalanced fbo bind/unbind binding default framebuffer";
currentFramebufferId = defaultFramebufferId;
}else{
currentFramebufferId = framebufferIdStack.back();
framebufferIdStack.pop_back();
}
glBindFramebuffer(GL_FRAMEBUFFER, currentFramebufferId);
fbo.flagDirty();
}
void ofGLProgrammableRenderer::bind(const ofBaseMaterial & material){
currentMaterial = &material;
currentShader = nullptr;
beginDefaultShader();
}
void ofGLProgrammableRenderer::unbind(const ofBaseMaterial &){
currentMaterial = nullptr;
beginDefaultShader();
}
void ofGLProgrammableRenderer::enableLighting(){
}
void ofGLProgrammableRenderer::disableLighting(){
}
void ofGLProgrammableRenderer::enableLight(int){
}
void ofGLProgrammableRenderer::disableLight(int){
}
bool ofGLProgrammableRenderer::getLightingEnabled(){
return true;
}
void ofGLProgrammableRenderer::bind(const ofTexture & texture, int location){
if(texture.getAlphaMask()){
setAlphaMaskTex(*texture.getAlphaMask());
}
enableTextureTarget(texture,location);
if(ofGetUsingNormalizedTexCoords()) {
matrixMode(OF_MATRIX_TEXTURE);
pushMatrix();
glm::mat4 m = glm::mat4(1.0);
#ifndef TARGET_OPENGLES
if(texture.texData.textureTarget == GL_TEXTURE_RECTANGLE_ARB)
m = glm::scale(m, glm::vec3(texture.texData.width, texture.texData.height, 1.0f));
else
#endif
m = glm::scale(m, glm::vec3(texture.texData.width / texture.texData.tex_w, texture.texData.height / texture.texData.tex_h, 1.0f));
loadMatrix(m);
matrixMode(OF_MATRIX_MODELVIEW);
}
if(texture.isUsingTextureMatrix()){
matrixMode(OF_MATRIX_TEXTURE);
if(!ofGetUsingNormalizedTexCoords()) pushMatrix();
multMatrix(texture.getTextureMatrix());
matrixMode(OF_MATRIX_MODELVIEW);
}
}
void ofGLProgrammableRenderer::unbind(const ofTexture & texture, int location){
disableTextureTarget(texture.texData.textureTarget,location);
if(texture.getAlphaMask()){
disableAlphaMask();
}
if(texture.isUsingTextureMatrix() || ofGetUsingNormalizedTexCoords()) {
matrixMode(OF_MATRIX_TEXTURE);
popMatrix();
matrixMode(OF_MATRIX_MODELVIEW);
}
}
void ofGLProgrammableRenderer::bind(const ofCamera & camera, const ofRectangle & _viewport){
pushView();
viewport(_viewport);
setOrientation(matrixStack.getOrientation(),camera.isVFlipped());
matrixMode(OF_MATRIX_PROJECTION);
loadMatrix(camera.getProjectionMatrix(_viewport));
matrixMode(OF_MATRIX_MODELVIEW);
loadViewMatrix(camera.getModelViewMatrix());
}
void ofGLProgrammableRenderer::unbind(const ofCamera & camera){
popView();
}
void ofGLProgrammableRenderer::uploadMatrices(){
if(!currentShader) return;
currentShader->setUniformMatrix4f(MODEL_MATRIX_UNIFORM, matrixStack.getModelMatrix());
currentShader->setUniformMatrix4f(VIEW_MATRIX_UNIFORM, matrixStack.getViewMatrix());
currentShader->setUniformMatrix4f(MODELVIEW_MATRIX_UNIFORM, matrixStack.getModelViewMatrix());
currentShader->setUniformMatrix4f(PROJECTION_MATRIX_UNIFORM, matrixStack.getProjectionMatrix());
currentShader->setUniformMatrix4f(TEXTURE_MATRIX_UNIFORM, matrixStack.getTextureMatrix());
currentShader->setUniformMatrix4f(MODELVIEW_PROJECTION_MATRIX_UNIFORM, matrixStack.getModelViewProjectionMatrix());
if(currentMaterial){
currentMaterial->uploadMatrices(*currentShader,*this);
}
}
void ofGLProgrammableRenderer::setDefaultUniforms(){
if(!currentShader) return;
currentShader->setUniform4f(COLOR_UNIFORM, currentStyle.color.r/255.,currentStyle.color.g/255.,currentStyle.color.b/255.,currentStyle.color.a/255.);
bool usingTexture = texCoordsEnabled & (currentTextureTarget!=OF_NO_TEXTURE);
currentShader->setUniform1f(USE_TEXTURE_UNIFORM,usingTexture);
currentShader->setUniform1f(USE_COLORS_UNIFORM,colorsEnabled);
if(currentMaterial){
currentMaterial->updateMaterial(*currentShader,*this);
currentMaterial->updateLights(*currentShader,*this);
}
}
void ofGLProgrammableRenderer::beginDefaultShader(){
if(usingCustomShader && !currentMaterial) return;
const ofShader * nextShader = nullptr;
if(!uniqueShader || currentMaterial){
if(currentMaterial){
nextShader = ¤tMaterial->getShader(currentTextureTarget,colorsEnabled,*this);
}else if(bitmapStringEnabled){
nextShader = &bitmapStringShader;
}else if(colorsEnabled && texCoordsEnabled){
switch(currentTextureTarget){
#ifndef TARGET_OPENGLES
case GL_TEXTURE_RECTANGLE_ARB:
nextShader = &defaultTexRectColor;
break;
#endif
case GL_TEXTURE_2D:
nextShader = &defaultTex2DColor;
break;
case OF_NO_TEXTURE:
nextShader = &defaultNoTexColor;
break;
#ifdef TARGET_ANDROID
case GL_TEXTURE_EXTERNAL_OES:
nextShader = &defaultOESTexColor;
break;
#endif
}
}else if(colorsEnabled){
nextShader = &defaultNoTexColor;
}else if(texCoordsEnabled){
switch(currentTextureTarget){
#ifndef TARGET_OPENGLES
case GL_TEXTURE_RECTANGLE_ARB:
nextShader = &defaultTexRectNoColor;
break;
#endif
case GL_TEXTURE_2D:
nextShader = &defaultTex2DNoColor;
break;
case OF_NO_TEXTURE:
nextShader = &defaultNoTexNoColor;
break;
#ifdef TARGET_ANDROID
case GL_TEXTURE_EXTERNAL_OES:
nextShader = &defaultOESTexNoColor;
break;
#endif
}
}else{
nextShader = &defaultNoTexNoColor;
}
}else{
nextShader = &defaultUniqueShader;
}
if(nextShader){
if(!currentShader || *currentShader!=*nextShader){
settingDefaultShader = true;
bind(*nextShader);
settingDefaultShader = false;
}
}
}
void ofGLProgrammableRenderer::drawLine(float x1, float y1, float z1, float x2, float y2, float z2) const{
ofGLProgrammableRenderer * mutThis = const_cast<ofGLProgrammableRenderer*>(this);
lineMesh.getVertices()[0] = {x1,y1,z1};
lineMesh.getVertices()[1] = {x2,y2,z2};
if (currentStyle.smoothing) mutThis->startSmoothing();
draw(lineMesh,OF_MESH_FILL,false,false,false);
if (currentStyle.smoothing) mutThis->endSmoothing();
}
void ofGLProgrammableRenderer::drawRectangle(float x, float y, float z, float w, float h) const{
ofGLProgrammableRenderer * mutThis = const_cast<ofGLProgrammableRenderer*>(this);
if (currentStyle.rectMode == OF_RECTMODE_CORNER){
rectMesh.getVertices()[0] = {x,y,z};
rectMesh.getVertices()[1] = {x+w, y, z};
rectMesh.getVertices()[2] = {x+w, y+h, z};
rectMesh.getVertices()[3] = {x, y+h, z};
}else{
rectMesh.getVertices()[0] = {x-w/2.0f, y-h/2.0f, z};
rectMesh.getVertices()[1] = {x+w/2.0f, y-h/2.0f, z};
rectMesh.getVertices()[2] = {x+w/2.0f, y+h/2.0f, z};
rectMesh.getVertices()[3] = {x-w/2.0f, y+h/2.0f, z};
}
if (currentStyle.smoothing && !currentStyle.bFill) mutThis->startSmoothing();
rectMesh.setMode(currentStyle.bFill ? OF_PRIMITIVE_TRIANGLE_FAN : OF_PRIMITIVE_LINE_LOOP);
draw(rectMesh,OF_MESH_FILL,false,false,false);
if (currentStyle.smoothing && !currentStyle.bFill) mutThis->endSmoothing();
}
void ofGLProgrammableRenderer::drawTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3) const{
ofGLProgrammableRenderer * mutThis = const_cast<ofGLProgrammableRenderer*>(this);
triangleMesh.getVertices()[0] = {x1,y1,z1};
triangleMesh.getVertices()[1] = {x2,y2,z2};
triangleMesh.getVertices()[2] = {x3,y3,z3};
if (currentStyle.smoothing && !currentStyle.bFill) mutThis->startSmoothing();
triangleMesh.setMode(currentStyle.bFill ? OF_PRIMITIVE_TRIANGLE_STRIP : OF_PRIMITIVE_LINE_LOOP);
draw(triangleMesh,OF_MESH_FILL,false,false,false);
if (currentStyle.smoothing && !currentStyle.bFill) mutThis->endSmoothing();
}
void ofGLProgrammableRenderer::drawCircle(float x, float y, float z, float radius) const{
ofGLProgrammableRenderer * mutThis = const_cast<ofGLProgrammableRenderer*>(this);
const auto & circleCache = circlePolyline.getVertices();
for(int i=0;i<(int)circleCache.size();i++){
circleMesh.getVertices()[i] = {radius*circleCache[i].x+x,radius*circleCache[i].y+y,z};
}
if (currentStyle.smoothing && !currentStyle.bFill) mutThis->startSmoothing();
circleMesh.setMode(currentStyle.bFill ? OF_PRIMITIVE_TRIANGLE_FAN : OF_PRIMITIVE_LINE_STRIP);
draw(circleMesh,OF_MESH_FILL,false,false,false);
if (currentStyle.smoothing && !currentStyle.bFill) mutThis->endSmoothing();
}
void ofGLProgrammableRenderer::drawEllipse(float x, float y, float z, float width, float height) const{
ofGLProgrammableRenderer * mutThis = const_cast<ofGLProgrammableRenderer*>(this);
float radiusX = width*0.5;
float radiusY = height*0.5;
const auto & circleCache = circlePolyline.getVertices();
for(int i=0;i<(int)circleCache.size();i++){
circleMesh.getVertices()[i] = {radiusX*circlePolyline[i].x+x,radiusY*circlePolyline[i].y+y,z};
}
if (currentStyle.smoothing && !currentStyle.bFill) mutThis->startSmoothing();
circleMesh.setMode(currentStyle.bFill ? OF_PRIMITIVE_TRIANGLE_FAN : OF_PRIMITIVE_LINE_STRIP);
draw(circleMesh,OF_MESH_FILL,false,false,false);
if (currentStyle.smoothing && !currentStyle.bFill) mutThis->endSmoothing();
}
void ofGLProgrammableRenderer::drawString(string textString, float x, float y, float z) const{
ofGLProgrammableRenderer * mutThis = const_cast<ofGLProgrammableRenderer*>(this);
float sx = 0;
float sy = 0;
bool hasModelView = false;
bool hasProjection = false;
bool hasViewport = false;
ofRectangle rViewport;
glm::mat4 modelView = glm::mat4(1.0);
switch (currentStyle.drawBitmapMode) {
case OF_BITMAPMODE_SIMPLE:
sx += x;
sy += y;
break;
case OF_BITMAPMODE_SCREEN:
hasViewport = true;
mutThis->pushView();
rViewport = matrixStack.getFullSurfaceViewport();
mutThis->viewport(rViewport);
mutThis->matrixMode(OF_MATRIX_PROJECTION);
mutThis->loadIdentityMatrix();
mutThis->matrixMode(OF_MATRIX_MODELVIEW);
modelView = glm::translate(modelView, glm::vec3(-1,-1,0));
modelView = glm::scale(modelView, glm::vec3(2/rViewport.width, 2/rViewport.height, 1));
modelView = glm::translate(modelView, glm::vec3(x,y, 0));
mutThis->loadMatrix(modelView);
break;
case OF_BITMAPMODE_VIEWPORT:
rViewport = getCurrentViewport();
hasProjection = true;
mutThis->matrixMode(OF_MATRIX_PROJECTION);
mutThis->pushMatrix();
mutThis->loadIdentityMatrix();
hasModelView = true;
mutThis->matrixMode(OF_MATRIX_MODELVIEW);
mutThis->pushMatrix();
modelView = glm::translate(modelView, glm::vec3(-1,-1,0));
modelView = glm::scale(modelView, glm::vec3(2/rViewport.width, 2/rViewport.height, 1));
modelView = glm::translate(modelView, glm::vec3(x,y, 0));
mutThis->loadMatrix(modelView);
break;
case OF_BITMAPMODE_MODEL:
hasModelView = true;
mutThis->matrixMode(OF_MATRIX_MODELVIEW);
mutThis->pushMatrix();
mutThis->translate(x, y, z);
break;
case OF_BITMAPMODE_MODEL_BILLBOARD:
{
rViewport = getCurrentViewport();
glm::mat4 mat = matrixStack.getProjectionMatrixNoOrientation() * matrixStack.getModelViewMatrix();
glm::vec4 dScreen4 = mat * glm::vec4(x,y,z,1.0);
glm::vec3 dScreen = glm::vec3(dScreen4) / dScreen4.w;
dScreen += glm::vec3(1.0) ;
dScreen *= 0.5;
dScreen.x += rViewport.x;
dScreen.x *= rViewport.width;
dScreen.y += rViewport.y;
dScreen.y *= rViewport.height;
if (dScreen.z >= 1) return;
hasProjection = true;
mutThis->matrixMode(OF_MATRIX_PROJECTION);
mutThis->pushMatrix();
mutThis->loadIdentityMatrix();
hasModelView = true;
mutThis->matrixMode(OF_MATRIX_MODELVIEW);
mutThis->pushMatrix();
modelView = glm::translate(modelView, glm::vec3(-1,-1,0));
modelView = glm::scale(modelView, glm::vec3(2/rViewport.width, 2/rViewport.height, 1));
modelView = glm::translate(modelView, glm::vec3(dScreen.x, dScreen.y, 0));
mutThis->loadMatrix(modelView);
}
break;
default:
break;
}
mutThis->setAlphaBitmapText(true);
ofMesh charMesh = bitmapFont.getMesh(textString, sx, sy, currentStyle.drawBitmapMode, isVFlipped());
mutThis->bind(bitmapFont.getTexture(),0);
draw(charMesh,OF_MESH_FILL,false,true,false);
mutThis->unbind(bitmapFont.getTexture(),0);
mutThis->setAlphaBitmapText(false);
if (hasViewport){
mutThis->popView();
}else{
if (hasModelView){
mutThis->popMatrix();
}
if (hasProjection)
{
mutThis->matrixMode(OF_MATRIX_PROJECTION);
mutThis->popMatrix();
mutThis->matrixMode(OF_MATRIX_MODELVIEW);
}
}
}
void ofGLProgrammableRenderer::drawString(const ofTrueTypeFont & font, string text, float x, float y) const{
ofGLProgrammableRenderer * mutThis = const_cast<ofGLProgrammableRenderer*>(this);
ofBlendMode blendMode = currentStyle.blendingMode;
mutThis->setBlendMode(OF_BLENDMODE_ALPHA);
mutThis->bind(font.getFontTexture(),0);
draw(font.getStringMesh(text,x,y,isVFlipped()),OF_MESH_FILL);
mutThis->unbind(font.getFontTexture(),0);
mutThis->setBlendMode(blendMode);
}
#define STRINGIFY(x) #x
#ifdef TARGET_OPENGLES
static const string vertex_shader_header =
"%extensions%\n"
"precision highp float;\n"
"#define IN attribute\n"
"#define OUT varying\n"
"#define TEXTURE texture2D\n"
"#define TARGET_OPENGLES\n";
static const string fragment_shader_header =
"%extensions%\n"
"precision highp float;\n"
"#define IN varying\n"
"#define OUT\n"
"#define TEXTURE texture2D\n"
"#define FRAG_COLOR gl_FragColor\n"
"#define TARGET_OPENGLES\n";
#else
static const string vertex_shader_header =
"#version %glsl_version%\n"
"%extensions%\n"
"#define IN in\n"
"#define OUT out\n"
"#define TEXTURE texture\n";
static const string fragment_shader_header =
"#version %glsl_version%\n"
"%extensions%\n"
"#define IN in\n"
"#define OUT out\n"
"#define TEXTURE texture\n"
"#define FRAG_COLOR fragColor\n"
"out vec4 fragColor;\n";
#endif
static const string defaultVertexShader = vertex_shader_header + STRINGIFY(
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 textureMatrix;
uniform mat4 modelViewProjectionMatrix;
IN vec4 position;
IN vec2 texcoord;
IN vec4 color;
IN vec3 normal;
OUT vec4 colorVarying;
OUT vec2 texCoordVarying;
OUT vec4 normalVarying;
void main()
{
colorVarying = color;
texCoordVarying = (textureMatrix*vec4(texcoord.x,texcoord.y,0,1)).xy;
gl_Position = modelViewProjectionMatrix * position;
}
);
static const string defaultFragmentShaderTexRectColor = fragment_shader_header + STRINGIFY(
uniform sampler2DRect src_tex_unit0;
uniform float usingTexture;
uniform float usingColors;
uniform vec4 globalColor;
IN float depth;
IN vec4 colorVarying;
IN vec2 texCoordVarying;
void main(){
FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * colorVarying;
}
);
static const string defaultFragmentShaderTexRectNoColor = fragment_shader_header + STRINGIFY(
uniform sampler2DRect src_tex_unit0;
uniform float usingTexture;
uniform float usingColors;
uniform vec4 globalColor;
IN float depth;
IN vec4 colorVarying;
IN vec2 texCoordVarying;
void main(){
FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying)* globalColor;
}
);
static const string alphaMaskFragmentShaderTexRectNoColor = fragment_shader_header + STRINGIFY(
uniform sampler2DRect src_tex_unit0;
uniform sampler2DRect src_tex_unit1;
uniform float usingTexture;
uniform float usingColors;
uniform vec4 globalColor;
IN float depth;
IN vec4 colorVarying;
IN vec2 texCoordVarying;
void main(){
FRAG_COLOR = vec4(TEXTURE(src_tex_unit0, texCoordVarying).rgb, TEXTURE(src_tex_unit1, texCoordVarying).r)* globalColor;
}
);
static const string alphaMaskFragmentShaderTex2DNoColor = fragment_shader_header + STRINGIFY(
uniform sampler2D src_tex_unit0;
uniform sampler2D src_tex_unit1;
uniform float usingTexture;
uniform float usingColors;
uniform vec4 globalColor;
IN float depth;
IN vec4 colorVarying;
IN vec2 texCoordVarying;
void main(){
FRAG_COLOR = vec4(TEXTURE(src_tex_unit0, texCoordVarying).rgb, TEXTURE(src_tex_unit1, texCoordVarying).r)* globalColor;
}
);
static const string defaultFragmentShaderTex2DColor = fragment_shader_header + STRINGIFY(
uniform sampler2D src_tex_unit0;
uniform float usingTexture;
uniform float usingColors;
uniform vec4 globalColor;
IN float depth;
IN vec4 colorVarying;
IN vec2 texCoordVarying;
void main(){
FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * colorVarying;
}
);
static const string defaultFragmentShaderTex2DNoColor = fragment_shader_header + STRINGIFY(
uniform sampler2D src_tex_unit0;
uniform float usingTexture;
uniform float usingColors;
uniform vec4 globalColor;
IN float depth;
IN vec4 colorVarying;
IN vec2 texCoordVarying;
void main(){
FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * globalColor;
}
);
static const string defaultFragmentShaderOESTexNoColor = fragment_shader_header + STRINGIFY(
uniform samplerExternalOES src_tex_unit0;
uniform float usingTexture;
uniform float usingColors;
uniform vec4 globalColor;
IN float depth;
IN vec4 colorVarying;
IN vec2 texCoordVarying;
void main(){
FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * globalColor;
}
);
static const string defaultFragmentShaderOESTexColor = fragment_shader_header + STRINGIFY(
uniform samplerExternalOES src_tex_unit0;
uniform float usingTexture;
uniform float usingColors;
uniform vec4 globalColor;
IN float depth;
IN vec4 colorVarying;
IN vec2 texCoordVarying;
void main(){
FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * colorVarying;
}
);
static const string defaultFragmentShaderNoTexColor = fragment_shader_header + STRINGIFY (
uniform float usingTexture;
uniform float usingColors;
uniform vec4 globalColor;
IN float depth;
IN vec4 colorVarying;
IN vec2 texCoordVarying;
void main(){
FRAG_COLOR = colorVarying;
}
);
static const string defaultFragmentShaderNoTexNoColor = fragment_shader_header + STRINGIFY(
uniform float usingTexture;
uniform float usingColors;
uniform vec4 globalColor;
IN float depth;
IN vec4 colorVarying;
IN vec2 texCoordVarying;
void main(){
FRAG_COLOR = globalColor;
}
);
static const string bitmapStringVertexShader = vertex_shader_header + STRINGIFY(
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 textureMatrix;
uniform mat4 modelViewProjectionMatrix;
IN vec4 position;
IN vec4 color;
IN vec2 texcoord;
OUT vec2 texCoordVarying;
void main()
{
texCoordVarying = texcoord;
gl_Position = modelViewProjectionMatrix * position;
}
);
static const string bitmapStringFragmentShader = fragment_shader_header + STRINGIFY(
uniform sampler2D src_tex_unit0;
uniform vec4 globalColor;
IN vec2 texCoordVarying;
void main()
{
vec4 tex = TEXTURE(src_tex_unit0, texCoordVarying);
if (tex.a < 0.5) discard;
FRAG_COLOR = globalColor * tex;
}
);
static const string uniqueVertexShader = vertex_shader_header + STRINGIFY(
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 textureMatrix;
uniform mat4 modelViewProjectionMatrix;
uniform float usingTexture;
uniform float usingColors;
uniform vec4 globalColor;
IN vec4 position;
IN vec4 color;
IN vec4 normal;
IN vec2 texcoord;
OUT vec4 colorVarying;
OUT vec2 texCoordVarying;
void main(){
gl_Position = modelViewProjectionMatrix * position;
if(usingTexture>.5) texCoordVarying = (textureMatrix*vec4(texcoord.x,texcoord.y,0,1)).xy;
if(usingColors>.5) colorVarying = color;
else colorVarying = globalColor;
}
);
static const string uniqueFragmentShader = fragment_shader_header + STRINGIFY(
uniform sampler2D src_tex_unit0;
uniform float usingTexture;
uniform float bitmapText;
IN vec4 colorVarying;
IN vec2 texCoordVarying;
void main(){
vec4 tex;
if(usingTexture>.5){
tex = TEXTURE(src_tex_unit0, texCoordVarying);
if(bitmapText>.5 && tex.a < 0.5){
discard;
}else{
FRAG_COLOR = colorVarying*tex;
}
}else{
FRAG_COLOR = colorVarying;
}
}
);
static const string FRAGMENT_SHADER_YUY2 = STRINGIFY(
uniform SAMPLER src_tex_unit0;\n
uniform vec4 globalColor;\n
IN vec4 colorVarying;\n
IN vec2 texCoordVarying;\n
uniform float onePixel;\n
uniform float textureWidth;\n
const vec3 offset = vec3(-0.0625, -0.5, -0.5);\n
const vec3 rcoeff = vec3(1.164, 0.000, 1.596);\n
const vec3 gcoeff = vec3(1.164,-0.391,-0.813);\n
const vec3 bcoeff = vec3(1.164, 2.018, 0.000);\n
void main(){\n
vec3 yuv;\n
yuv.x=TEXTURE(src_tex_unit0,texCoordVarying).r;\n
float x = texCoordVarying.x * textureWidth;\n
if(mod(x,2.0)>0.5){\n
yuv.y=TEXTURE(src_tex_unit0,vec2(texCoordVarying.x-onePixel,texCoordVarying.y)).%g;\n
yuv.z=TEXTURE(src_tex_unit0,texCoordVarying).%g;\n
}else{\n
yuv.y=TEXTURE(src_tex_unit0,texCoordVarying).%g;\n
yuv.z=TEXTURE(src_tex_unit0,vec2(texCoordVarying.x+onePixel,texCoordVarying.y)).%g;\n
}\n
yuv += offset;\n
float r = dot(yuv, rcoeff);\n
float g = dot(yuv, gcoeff);\n
float b = dot(yuv, bcoeff);\n
FRAG_COLOR=vec4(r,g,b,1.0) * globalColor;\n
}\n
);
static const string FRAGMENT_SHADER_NV12_NV21 = STRINGIFY(
uniform SAMPLER Ytex;\n
uniform SAMPLER UVtex;\n
uniform vec4 globalColor;\n
uniform vec2 tex_scaleUV;\n
IN vec4 colorVarying;\n
IN vec2 texCoordVarying;\n
const vec3 offset = vec3(-0.0625, -0.5, -0.5);\n
const vec3 rcoeff = vec3(1.164, 0.000, 1.596);\n
const vec3 gcoeff = vec3(1.164,-0.391,-0.813);\n
const vec3 bcoeff = vec3(1.164, 2.018, 0.000);\n
void main(){\n
vec3 yuv;\n
yuv.x=TEXTURE(Ytex,texCoordVarying).r;\n
yuv.yz=TEXTURE(UVtex,texCoordVarying * tex_scaleUV).%r%g;\n
yuv += offset;\n
float r = dot(yuv, rcoeff);\n
float g = dot(yuv, gcoeff);\n
float b = dot(yuv, bcoeff);\n
FRAG_COLOR=vec4(r,g,b,1.0) * globalColor;\n
}\n
);
static const string FRAGMENT_SHADER_PLANAR_YUV = STRINGIFY(
uniform SAMPLER Ytex;\n
uniform SAMPLER Utex;\n
uniform SAMPLER Vtex;\n
uniform vec2 tex_scaleY;\n
uniform vec2 tex_scaleU;\n
uniform vec2 tex_scaleV;\n
uniform vec4 globalColor;\n
IN vec4 colorVarying;\n
IN vec2 texCoordVarying;\n
const vec3 offset = vec3(-0.0625, -0.5, -0.5);\n
const vec3 rcoeff = vec3(1.164, 0.000, 1.596);\n
const vec3 gcoeff = vec3(1.164,-0.391,-0.813);\n
const vec3 bcoeff = vec3(1.164, 2.018, 0.000);\n
void main(){\n
vec3 yuv;\n
yuv.x=TEXTURE(Ytex,texCoordVarying * tex_scaleY).r;\n
yuv.y=TEXTURE(Utex,texCoordVarying * tex_scaleU).r;\n
yuv.z=TEXTURE(Vtex,texCoordVarying * tex_scaleV).r;\n
yuv += offset;\n
float r = dot(yuv, rcoeff);\n
float g = dot(yuv, gcoeff);\n
float b = dot(yuv, bcoeff);\n
FRAG_COLOR=vec4(r,g,b,1.0) * globalColor;\n
}\n
);
static string defaultShaderHeader(string header, GLenum textureTarget, int major, int minor){
ofStringReplace(header,"%glsl_version%",ofGLSLVersionFromGL(major,minor));
#ifndef TARGET_OPENGLES
if(major<4 && minor<2){
ofStringReplace(header,"%extensions%","#extension GL_ARB_texture_rectangle : enable");
}else{
ofStringReplace(header,"%extensions%","");
}
#else
ofStringReplace(header,"%extensions%","");
#endif
if(textureTarget==GL_TEXTURE_2D){
header += "#define SAMPLER sampler2D\n";
}else{
header += "#define SAMPLER sampler2DRect\n";
}
return header;
}
static string shaderSource(const string & src, int major, int minor){
string shaderSrc = src;
ofStringReplace(shaderSrc,"%glsl_version%",ofGLSLVersionFromGL(major,minor));
#ifndef TARGET_OPENGLES
if(major<4 && minor<2){
ofStringReplace(shaderSrc,"%extensions%","#extension GL_ARB_texture_rectangle : enable");
}else{
ofStringReplace(shaderSrc,"%extensions%","");
}
#else
ofStringReplace(shaderSrc,"%extensions%","");
#endif
return shaderSrc;
}
#ifdef TARGET_ANDROID
static string shaderOESSource(const string & src, int major, int minor){
string shaderSrc = src;
ofStringReplace(shaderSrc,"%glsl_version%",ofGLSLVersionFromGL(major,minor));
ofStringReplace(shaderSrc,"%extensions%","#extension GL_OES_EGL_image_external : require");
return shaderSrc;
}
#endif
static string videoFragmentShaderSource(const ofBaseVideoDraws & video, int major, int minor){
string src;
switch(video.getPixelFormat()){
case OF_PIXELS_YUY2:
src = FRAGMENT_SHADER_YUY2;
#ifndef TARGET_OPENGLES
ofStringReplace(src,"%g","g");
#else
ofStringReplace(src,"%g","a");
#endif
break;
case OF_PIXELS_NV12:
src = FRAGMENT_SHADER_NV12_NV21;
#ifndef TARGET_OPENGLES
ofStringReplace(src,"%r%g","rg");
#else
ofStringReplace(src,"%r%g","ra");
#endif
break;
case OF_PIXELS_NV21:
src = FRAGMENT_SHADER_NV12_NV21;
#ifndef TARGET_OPENGLES
ofStringReplace(src,"%r%g","gr");
#else
ofStringReplace(src,"%r%g","ar");
#endif
break;
case OF_PIXELS_YV12:
case OF_PIXELS_I420:
src = FRAGMENT_SHADER_PLANAR_YUV;
break;
case OF_PIXELS_RGB:
case OF_PIXELS_BGR:
case OF_PIXELS_RGB565:
case OF_PIXELS_RGBA:
case OF_PIXELS_BGRA:
case OF_PIXELS_GRAY:
default:
break;
}
string header = fragment_shader_header;
GLenum textureTarget = video.getTexture().getTextureData().textureTarget;
if(textureTarget==GL_TEXTURE_2D){
header += "#define SAMPLER sampler2D\n";
}
#ifndef TARGET_OPENGLES
else if(textureTarget==GL_TEXTURE_RECTANGLE){
header += "#define SAMPLER sampler2DRect\n";
}
#endif
return shaderSource(header + src, major, minor);
}
string ofGLProgrammableRenderer::defaultVertexShaderHeader(GLenum textureTarget){
return defaultShaderHeader(vertex_shader_header,textureTarget,major,minor);
}
string ofGLProgrammableRenderer::defaultFragmentShaderHeader(GLenum textureTarget){
return defaultShaderHeader(fragment_shader_header,textureTarget,major,minor);
}
void ofGLProgrammableRenderer::setup(int _major, int _minor){
glGetError();
#ifdef TARGET_OPENGLES
GLint currentFrameBuffer;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, ¤tFrameBuffer);
defaultFramebufferId = currentFrameBuffer;
currentFramebufferId = defaultFramebufferId;
#endif
major = _major;
minor = _minor;
#ifdef TARGET_RASPBERRY_PI
uniqueShader = true;
#else
uniqueShader = false;
#endif
if(uniqueShader){
defaultUniqueShader.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(uniqueVertexShader, major, minor));
defaultUniqueShader.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(uniqueFragmentShader, major, minor));
defaultUniqueShader.bindDefaults();
defaultUniqueShader.linkProgram();
beginDefaultShader();
}else{
#ifndef TARGET_OPENGLES
defaultTexRectColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
defaultTexRectNoColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
alphaMaskRectShader.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
#endif
defaultTex2DColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
defaultNoTexColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
defaultTex2DNoColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
defaultNoTexNoColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
alphaMask2DShader.setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major, minor));
#ifndef TARGET_OPENGLES
defaultTexRectColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(defaultFragmentShaderTexRectColor,major, minor));
defaultTexRectNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(defaultFragmentShaderTexRectNoColor,major, minor));
alphaMaskRectShader.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(alphaMaskFragmentShaderTexRectNoColor,major, minor));
#endif
defaultTex2DColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(defaultFragmentShaderTex2DColor,major, minor));
defaultNoTexColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(defaultFragmentShaderNoTexColor,major, minor));
defaultTex2DNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(defaultFragmentShaderTex2DNoColor,major, minor));
defaultNoTexNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(defaultFragmentShaderNoTexNoColor,major, minor));
alphaMask2DShader.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderSource(alphaMaskFragmentShaderTex2DNoColor,major, minor));
bitmapStringShader.setupShaderFromSource(GL_VERTEX_SHADER, shaderSource(bitmapStringVertexShader,major, minor));
bitmapStringShader.setupShaderFromSource(GL_FRAGMENT_SHADER, shaderSource(bitmapStringFragmentShader,major, minor));
#ifndef TARGET_OPENGLES
defaultTexRectColor.bindDefaults();
defaultTexRectNoColor.bindDefaults();
alphaMaskRectShader.bindDefaults();
#endif
defaultTex2DColor.bindDefaults();
defaultNoTexColor.bindDefaults();
defaultTex2DNoColor.bindDefaults();
defaultNoTexNoColor.bindDefaults();
alphaMask2DShader.bindDefaults();
#ifndef TARGET_OPENGLES
defaultTexRectColor.linkProgram();
defaultTexRectNoColor.linkProgram();
alphaMaskRectShader.linkProgram();
#endif
defaultTex2DColor.linkProgram();
defaultNoTexColor.linkProgram();
defaultTex2DNoColor.linkProgram();
defaultNoTexNoColor.linkProgram();
alphaMask2DShader.linkProgram();
bitmapStringShader.bindDefaults();
bitmapStringShader.linkProgram();
#ifdef TARGET_ANDROID
defaultOESTexNoColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderOESSource(defaultVertexShader,major, minor));
defaultOESTexColor.setupShaderFromSource(GL_VERTEX_SHADER,shaderOESSource(defaultVertexShader,major, minor));
defaultOESTexColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderOESSource(defaultFragmentShaderOESTexColor,major, minor));
defaultOESTexNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER,shaderOESSource(defaultFragmentShaderOESTexNoColor,major, minor));
defaultOESTexColor.bindDefaults();
defaultOESTexNoColor.bindDefaults();
defaultOESTexColor.linkProgram();
defaultOESTexNoColor.linkProgram();
#endif
}
setupGraphicDefaults();
viewport();
setupScreenPerspective();
}
const ofShader * ofGLProgrammableRenderer::getVideoShader(const ofBaseVideoDraws & video) const{
const ofShader * shader = nullptr;
GLenum target = video.getTexture().getTextureData().textureTarget;
switch(video.getPixelFormat()){
case OF_PIXELS_YUY2:
if(target==GL_TEXTURE_2D){
shader = &shaderPlanarYUY2;
}else{
shader = &shaderPlanarYUY2Rect;
}
break;
case OF_PIXELS_NV12:
if(target==GL_TEXTURE_2D){
shader = &shaderNV12;
}else{
shader = &shaderNV12Rect;
}
break;
case OF_PIXELS_NV21:
if(target==GL_TEXTURE_2D){
shader = &shaderNV21;
}else{
shader = &shaderNV21Rect;
}
break;
case OF_PIXELS_YV12:
case OF_PIXELS_I420:
if(target==GL_TEXTURE_2D){
shader = &shaderPlanarYUV;
}else{
shader = &shaderPlanarYUVRect;
}
break;
case OF_PIXELS_RGB:
case OF_PIXELS_BGR:
case OF_PIXELS_RGB565:
case OF_PIXELS_RGBA:
case OF_PIXELS_BGRA:
case OF_PIXELS_GRAY:
default:
break;
}
if(shader && !shader->isLoaded()){
ofShader * mutShader = const_cast<ofShader*>(shader);
mutShader->setupShaderFromSource(GL_VERTEX_SHADER,shaderSource(defaultVertexShader,major,minor));
mutShader->setupShaderFromSource(GL_FRAGMENT_SHADER,videoFragmentShaderSource(video,major,minor));
mutShader->bindDefaults();
mutShader->linkProgram();
}
return shader;
}
#ifndef TARGET_OPENGLES
static float getTextureScaleX(const ofBaseVideoDraws & video, int plane){
if(!video.getTexturePlanes().empty()){
return video.getTexturePlanes()[plane].getWidth()/video.getWidth();
}else{
return 1.0;
}
}
static float getTextureScaleY(const ofBaseVideoDraws & video, int plane){
if(!video.getTexturePlanes().empty()){
return video.getTexturePlanes()[plane].getHeight()/video.getHeight();
}else{
return 1.0;
}
}
#endif
void ofGLProgrammableRenderer::setVideoShaderUniforms(const ofBaseVideoDraws & video, const ofShader & shader) const{
switch(video.getPixelFormat()){
case OF_PIXELS_YUY2:
#ifndef TARGET_OPENGLES
if(video.getTexture().getTextureData().textureTarget==GL_TEXTURE_RECTANGLE){
shader.setUniform1f("onePixel",1.0);
shader.setUniform1f("textureWidth",1.0);
}else{
#endif
shader.setUniform1f("onePixel",1.0/video.getWidth());
shader.setUniform1f("textureWidth",video.getWidth());
#ifndef TARGET_OPENGLES
}
#endif
shader.setUniformTexture("src_tex_unit0",video.getTexturePlanes()[0],0);
break;
case OF_PIXELS_NV12:
case OF_PIXELS_NV21:
shader.setUniformTexture("Ytex",video.getTexturePlanes()[0],0);
shader.setUniformTexture("UVtex",video.getTexturePlanes()[1],1);
#ifndef TARGET_OPENGLES
if(video.getTexture().getTextureData().textureTarget==GL_TEXTURE_RECTANGLE){
shader.setUniform2f("tex_scaleUV",getTextureScaleX(video,1),getTextureScaleY(video,1));
}else{
#endif
shader.setUniform2f("tex_scaleUV",1.0,1.0);
#ifndef TARGET_OPENGLES
}
#endif
break;
case OF_PIXELS_YV12:
shader.setUniformTexture("Ytex",video.getTexturePlanes()[0],0);
shader.setUniformTexture("Utex",video.getTexturePlanes()[2],1);
shader.setUniformTexture("Vtex",video.getTexturePlanes()[1],2);
#ifndef TARGET_OPENGLES
if(video.getTexture().getTextureData().textureTarget==GL_TEXTURE_RECTANGLE){
shader.setUniform2f("tex_scaleY",getTextureScaleX(video,0),getTextureScaleY(video,0));
shader.setUniform2f("tex_scaleU",getTextureScaleX(video,2),getTextureScaleY(video,2));
shader.setUniform2f("tex_scaleV",getTextureScaleX(video,1),getTextureScaleY(video,1));
}else{
#endif
shader.setUniform2f("tex_scaleY",1.0,1.0);
shader.setUniform2f("tex_scaleU",1.0,1.0);
shader.setUniform2f("tex_scaleV",1.0,1.0);
#ifndef TARGET_OPENGLES
}
#endif
break;
case OF_PIXELS_I420:
shader.setUniformTexture("Ytex",video.getTexturePlanes()[0],0);
shader.setUniformTexture("Utex",video.getTexturePlanes()[1],1);
shader.setUniformTexture("Vtex",video.getTexturePlanes()[2],2);
#ifndef TARGET_OPENGLES
if(video.getTexture().getTextureData().textureTarget==GL_TEXTURE_RECTANGLE){
shader.setUniform2f("tex_scaleY",getTextureScaleX(video,0),getTextureScaleY(video,0));
shader.setUniform2f("tex_scaleU",getTextureScaleX(video,1),getTextureScaleY(video,1));
shader.setUniform2f("tex_scaleV",getTextureScaleX(video,2),getTextureScaleY(video,2));
}else{
#endif
shader.setUniform2f("tex_scaleY",1.0,1.0);
shader.setUniform2f("tex_scaleU",1.0,1.0);
shader.setUniform2f("tex_scaleV",1.0,1.0);
#ifndef TARGET_OPENGLES
}
#endif
break;
default:
break;
}
}
int ofGLProgrammableRenderer::getGLVersionMajor(){
return major;
}
int ofGLProgrammableRenderer::getGLVersionMinor(){
return minor;
}
void ofGLProgrammableRenderer::saveFullViewport(ofPixels & pixels){
ofRectangle v = getCurrentViewport();
saveScreen(v.x,v.y,v.width,v.height,pixels);
}
void ofGLProgrammableRenderer::saveScreen(int x, int y, int w, int h, ofPixels & pixels){
int sh = getViewportHeight();
#ifndef TARGET_OPENGLES
if(isVFlipped()){
y = sh - y;
y -= h;
}
auto pixelFormat = OF_PIXELS_BGRA;
pixels.allocate(w, h, pixelFormat);
auto glFormat = ofGetGLFormat(pixels);
ofBufferObject buffer;
buffer.allocate(pixels.size(), GL_STATIC_READ);
buffer.bind(GL_PIXEL_PACK_BUFFER);
glReadPixels(x, y, w, h, glFormat, GL_UNSIGNED_BYTE, 0);
buffer.unbind(GL_PIXEL_PACK_BUFFER);
if(unsigned char * p = buffer.map<unsigned char>(GL_READ_ONLY)){
ofPixels src;
src.setFromExternalPixels(p,w,h,pixelFormat);
src.mirrorTo(pixels,true,false);
buffer.unmap();
}else{
ofLogError("ofGLProgrammableRenderer") << "Error saving screen";
}
#else
int sw = getViewportWidth();
int numPixels = w*h;
if( numPixels == 0 ){
ofLogError("ofImage") << "grabScreen(): unable to grab screen, image width and/or height are 0: " << w << "x" << h;
return;
}
pixels.allocate(w, h, OF_PIXELS_RGBA);
switch(matrixStack.getOrientation()){
case OF_ORIENTATION_UNKNOWN:
case OF_ORIENTATION_DEFAULT:
if(isVFlipped()){
y = sh - y;
y -= h;
}
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels.getData());
pixels.mirror(true,false);
break;
case OF_ORIENTATION_180:
if(isVFlipped()){
x = sw - x;
x -= w;
}
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels.getData());
pixels.mirror(false,true);
break;
case OF_ORIENTATION_90_RIGHT:
swap(w,h);
swap(x,y);
if(!isVFlipped()){
x = sw - x;
x -= w;
y = sh - y;
y -= h;
}
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels.getData());
pixels.mirror(true,true);
break;
case OF_ORIENTATION_90_LEFT:
swap(w, h);
swap(x, y);
if(isVFlipped()){
x = sw - x;
x -= w;
y = sh - y;
y -= h;
}
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels.getData());
pixels.mirror(true,true);
break;
}
#endif
}
const of3dGraphics & ofGLProgrammableRenderer::get3dGraphics() const{
return graphics3d;
}
of3dGraphics & ofGLProgrammableRenderer::get3dGraphics(){
return graphics3d;
}
Comments