123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- /**
- * Copyright (c) 2011 Nokia Corporation.
- *
- * CAUTION: This class is in early, experimental state.
- * NOTE, !!!! SOURCE ORIGINA HAS BEEN REMOVED FROM THIS VERSION OF THE SPRITEBATCH!!!
- *
- */
- #include <QMatrix4x4>
- #include <QDebug>
- #include <math.h>
- #include <memory.h>
- #include "QtOpenGLSpriteBatch.h"
- /*
- Shaders for the spritebatch rendering with a color multiply
- */
- const char* strSpriteBatchFragmentShaderColorMultiplty =
- "uniform sampler2D sampler2d;\n"
- "varying lowp vec4 vertexColor;\n"
- "varying lowp vec2 texCoord;\n"
- "void main (void)\n"
- "{\n"
- " gl_FragColor = texture2D(sampler2d, texCoord)*vertexColor;\n"
- "}";
- const char* strSpriteBatchVertexShaderColorMultiply =
- "attribute highp vec3 vertex;\n"
- "uniform mediump mat4 projMatrix;\n"
- "uniform mediump mat4 im[16];\n" // input
- "varying mediump vec2 texCoord;\n"
- "varying mediump vec4 vertexColor;\n"
- "void main(void)\n"
- "{\n"
- "mediump mat4 thisim = im[ int(vertex.z) ];\n"
- //"highp vec2 transVertex = vec2( thisim[2][0], thisim[2][1] ) + mat2( thisim[0][0], thisim[0][1], thisim[1][0], thisim[1][1]) * (vertex.xy-vec2(thisim[2][2]-0.5, thisim[2][3]-0.5));\n"
- "highp vec2 transVertex = vec2( thisim[2][0], thisim[2][1] ) + mat2( thisim[0][0], thisim[0][1], thisim[1][0], thisim[1][1]) * (vertex.xy);\n"
- "gl_Position = vec4(transVertex,1,1) * projMatrix;\n"
- "vertexColor = vec4( thisim[3][0], thisim[3][1], thisim[3][2], thisim[3][3] );\n"
- //"texCoord = (vec2(0.5+vertex.x, 0.5-vertex.y)) * vec2(thisim[1][2], thisim[1][3]) + vec2(thisim[0][2], thisim[0][3]);\n"
- "mediump vec2 suv = vec2(thisim[2][2], thisim[2][3])*vertex.x + vec2(-thisim[2][3], thisim[2][2])*vertex.y;\n"
- "texCoord = (vec2(0.5+suv.x, 0.5-suv.y)) * vec2(thisim[1][2], thisim[1][3]) + vec2(thisim[0][2], thisim[0][3]);\n"
- "}";
- /*
- Shaders for the spritebatch rendering with pure texture
- */
- const char* strSpriteBatchFragmentShaderPureTexture =
- "uniform sampler2D sampler2d;\n"
- "varying mediump vec2 texCoord;\n"
- "void main (void)\n"
- "{\n"
- " gl_FragColor = texture2D(sampler2d, texCoord);\n"
- "}";
- const char* strSpriteBatchVertexShaderPureTexture =
- "attribute highp vec3 vertex;\n"
- "uniform mediump mat4 projMatrix;\n"
- "uniform mediump mat4 im[16];\n" // input
- "varying mediump vec2 texCoord;\n"
- "void main(void)\n"
- "{\n"
- "mediump mat4 thisim = im[ int(vertex.z) ];\n"
- //"highp vec2 transVertex = vec2( thisim[2][0], thisim[2][1] ) + mat2( thisim[0][0], thisim[0][1], thisim[1][0], thisim[1][1]) * (vertex.xy-vec2(thisim[2][2]-0.5, thisim[2][3]-0.5));\n"
- "mediump vec2 transVertex = vec2( thisim[2][0], thisim[2][1] ) + mat2( thisim[0][0], thisim[0][1], thisim[1][0], thisim[1][1]) * (vertex.xy);\n"
- "gl_Position = vec4(transVertex,1,1) * projMatrix;\n"
- //"texCoord = (vec2(0.5+vertex.x, 0.5-vertex.y)) * vec2(thisim[1][2], thisim[1][3]) + vec2(thisim[0][2], thisim[0][3]);\n"
- "mediump vec2 suv = vec2(thisim[2][2], thisim[2][3])*vertex.x + vec2(-thisim[2][3], thisim[2][2])*vertex.y;\n"
- "texCoord = (vec2(0.5+suv.x, 0.5-suv.y)) * vec2(thisim[1][2], thisim[1][3]) + vec2(thisim[0][2], thisim[0][3]);\n"
- "}";
- QtOpenGLSpriteBatch::QtOpenGLSpriteBatch(int w, int h, QObject *parent ) : QObject(parent), SpriteBatch(w,h)
- {
- for (int f=0; f<COSINE_TABLE_SIZE; f++)
- cosineTable[f] = cosf( (float)f / (float)COSINE_TABLE_SIZE * 3.14159f * 2.0f );
- batchCounter = 0;
- for (int f=0; f<2; f++) {
- QGLShader *vshader = new QGLShader(QGLShader::Vertex, this);
- const char *src = strSpriteBatchVertexShaderColorMultiply;
- if (f!=0) src = strSpriteBatchVertexShaderPureTexture;
- if (vshader->compileSourceCode( src ) == false)
- qDebug() << "QOGLSBatch: Failed to compile fragment shader" << f;
- else
- qDebug() << "compiled vs" << f;
- QGLShader *fshader = new QGLShader(QGLShader::Fragment, this);
- src = strSpriteBatchFragmentShaderColorMultiplty;
- if (f!=0) src = strSpriteBatchFragmentShaderPureTexture;
- if (fshader->compileSourceCode( src ) == false)
- qDebug() << "QOGLSBatch: Failed to compile fragment shader" << f;
- else
- qDebug() << "compiled" << f;
- program[f].addShader( vshader );
- program[f].addShader( fshader );
- program[f].bindAttributeLocation( "vertex", 0 );
- if (program[f].link() == false)
- qDebug() << "Error linking the program:"<<f;
- else
- qDebug() << "linked program:"<<f;
- samplerLocation[f] = program[f].uniformLocation("sampler2d");
- inputMatrixLocation[f] = program[f].uniformLocation("im");
- projmLocation[f] = program[f].uniformLocation("projMatrix");
- }
- qtvbo = new QGLBuffer( QGLBuffer::VertexBuffer );
- if (qtvbo->create() == false)
- qDebug() << "Failed to create vertexbuffer.";
- else
- qDebug() << "Created the vertexbufferobject";
- qtvbo->setUsagePattern( QGLBuffer::StaticDraw );
- GLfloat vertices[] = {-0.5f,-0.5f,0.0f, 0.5f,-0.5f,0.0f, 0.5f,0.5f,0.0f, // triangle 1
- -0.5f,-0.5f,0.0f, 0.5f,0.5f,0.0f, -0.5f,0.5f,0.0f}; // triangle 2
- GLfloat *tempVertices = new GLfloat[ 3 * 6 * BATCH_SIZE];
- for (int f=0; f<BATCH_SIZE; f++) {
- memcpy( tempVertices+f*3*6, vertices, 3*6*sizeof(GLfloat ));
- for (int g=0; g<6; g++) tempVertices[ f*3*6+2+g*3 ] = f; // mark the index for each triangle
- }
- qtvbo->bind();
- qtvbo->allocate( tempVertices, BATCH_SIZE*6*sizeof(GLfloat)*3 );
- //glBindBuffer(GL_ARRAY_BUFFER, vbo );
- //glBufferData(GL_ARRAY_BUFFER, BATCH_SIZE *6*sizeof(GLfloat)*3, tempVertices, GL_STATIC_DRAW );
- delete [] tempVertices;
- }
- QtOpenGLSpriteBatch::~QtOpenGLSpriteBatch()
- {
- if (qtvbo) delete qtvbo;
- qtvbo = 0;
- }
- void QtOpenGLSpriteBatch::flushSprites(bool useTable)
- {
- if (batchCounter<1) return; // nothing to fill
- float angletointmul = (float)COSINE_TABLE_SIZE/3.14159f/2.0f;
- int selectedProgram = 0;
- if (allWhite==true) selectedProgram = 1;
- //if (selectedProgram==1) qDebug() << "flushing with whiteprogram";
- if (currentProgram!=selectedProgram) setActiveProgram( selectedProgram );
- // Fill the inputTempMatrices
- //float *m = inputMatrixTemp;
- SpriteDrawInfo *sdi = batchCollection;
- for (int f=0; f<batchCounter; f++)
- {
- qreal *m = inputMatrixtemp[f].data();
- // targetposition
- m[8+0] = sdi->posx;
- m[8+1] = sdi->posy;
- // source angle
- if (useTable) {
- int siangle = ((int)( sdi->sourceAngle * angletointmul ) & COSINE_TABLE_AND);
- m[8+2] = cosineTable[ siangle ];
- m[8+3] = cosineTable[(siangle+COSINE_TABLE_SIZE/4)&COSINE_TABLE_AND];
- } else {
- m[8+2] = cosf( sdi->sourceAngle );
- m[8+3] = sinf( sdi->sourceAngle );
- }
- // Destination orientation
- if (sdi->manualTransformActive)
- {
- m[0] = sdi->manualTransformMatrix[0][0];
- m[1] = sdi->manualTransformMatrix[0][1];
- m[4] = sdi->manualTransformMatrix[1][0];
- m[5] = sdi->manualTransformMatrix[1][1];
- }
- else
- {
- if (useTable) {
- int iangle = ((int)( sdi->angle * angletointmul ) & COSINE_TABLE_AND);
- m[0] = cosineTable[iangle] * sdi->scaleX;
- m[1] = cosineTable[(iangle+COSINE_TABLE_SIZE/4)&COSINE_TABLE_AND] * sdi->scaleX;
- m[4+0] = cosineTable[(iangle+COSINE_TABLE_SIZE/4)&COSINE_TABLE_AND] * sdi->scaleY;
- m[4+1] = -cosineTable[iangle] * sdi->scaleY;
- } else {
- m[0] = cosf( sdi->angle ) * sdi->scaleX;
- m[1] = sinf( sdi->angle ) * sdi->scaleX;
- m[4+0] = sinf( sdi->angle ) * sdi->scaleY;
- m[4+1] = -cosf( sdi->angle ) * sdi->scaleY;
- }
- }
- // Source rectangle
- m[2] = sdi->sourcex;
- m[3] = sdi->sourcey;
- m[4+2] = sdi->sourceWidth;
- m[4+3] = sdi->sourceHeight;
- m[12+0] = sdi->r;
- m[12+1] = sdi->g;
- m[12+2] = sdi->b;
- m[12+3] = sdi->a;
- sdi++;
- }
- program[currentProgram].setUniformValueArray(inputMatrixLocation[currentProgram], inputMatrixtemp, batchCounter );
- glDrawArrays(GL_TRIANGLES, 0, 6*batchCounter);
- // Reset batch
- batchCounter = 0;
- allWhite = true;
- }
- #define WHITE_LIMIT 0.999f
- void QtOpenGLSpriteBatch::draw ( SpriteDrawInfo *sdi, int spriteCount )
- {
- SpriteDrawInfo *i = sdi;
- while (spriteCount>0) {
- bool completelyWhite = false;
- if ( i->r>WHITE_LIMIT && i->g>WHITE_LIMIT && i->b>WHITE_LIMIT && i->a > WHITE_LIMIT ) completelyWhite = true;
- if (allWhite==true && completelyWhite==false && batchCounter>=2) {
- // current would break the "allWhite"-flag. Flush this batch before adding it.
- //qDebug() << "Using the white program..";
- flushSprites();
- }
- if (i->textureHandle != currentTexture ) {
- // Texture have been changed, flush currently collected renderingdata
- flushSprites();
- // Change our current texture and activate it.
- currentTexture = i->textureHandle;
- glBindTexture( GL_TEXTURE_2D, currentTexture );
- }
- if (!completelyWhite) allWhite = false;
- memcpy( batchCollection + batchCounter, i, sizeof( SpriteDrawInfo ) );
- batchCounter++;
- if (batchCounter>=BATCH_SIZE) flushSprites();
- i++;
- spriteCount--;
- }
- }
- void QtOpenGLSpriteBatch::setActiveProgram( int programIndex )
- {
- program[programIndex].bind();
- program[programIndex].setUniformValue(samplerLocation[programIndex], 0);
- program[programIndex].setUniformValue( projmLocation[programIndex], projectionMatrix );
- program[programIndex].enableAttributeArray(0);
- program[programIndex].setAttributeBuffer(0, GL_FLOAT, 0, 3, 0 );
- currentProgram = programIndex;
- }
- void QtOpenGLSpriteBatch::begin( BlendMode bmode, TransformMode dTransform, float *customProjectionMatrix)
- {
- currentDestinationTransform = dTransform;
- if (customProjectionMatrix) {
- // set projection
- QMatrix4x4 projTemp( (qreal*)customProjectionMatrix );
- // NOTE, DEBUG, ERROR, WARNING, TODO ..... THIS might have to be transposed. Test when using !!!!!! Otherwise you won't see anything.
- projectionMatrix = projTemp;
- //program.setUniformValue( projmLocation, projTemp );
- } else {
- // NOTE, .. HACK FOR HARMATTAN
- #ifdef Q_WS_MAEMO_6_removed_as_firecup_is_landscape_app
- qreal mproj[16] = {
- 0, 2.0f/(float)targetWidth, 0, 0,
- 2.0f/(float)targetHeight, 0, 0, 0, // final height
- 0, 0, 1, 0,
- -1.0f,-1.0f, 0, 1 };
- #else
- // WITH Other GL - implementations, the matrix is otherway around.
- // NOTE, SERIOUS ERROR FOUND IN QTOPENGL. different matrix orientations with setUniformValue / and setUniformValueArray (QMatrix4x4).
- qreal mproj[16] = {
- 2.0f/(float)targetWidth, 0, 0, 0,
- 0, -2.0f/(float)targetHeight, 0, 0,
- 0, 0, 1, 0,
- -1.0f,1.0f, 0, 1,
- };
- #endif
- projectionMatrix = QMatrix4x4( mproj );
- //QMatrix4x4 projTemp( mproj );
- //program.setUniformValue( projmLocation, projTemp );
- }
- glDisable( GL_DEPTH_TEST );
- glDepthMask( GL_FALSE );
- glEnable( GL_BLEND );
- if (bmode==eALPHA)
- glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- else
- glBlendFunc( GL_SRC_ALPHA, GL_ONE);
- glDisable( GL_CULL_FACE );
- qtvbo->bind();
- currentTexture = 0;
- allWhite = true;
- currentProgram = -1;
- }
- void QtOpenGLSpriteBatch::end()
- {
- // Draw everything that is collected.
- flushSprites();
- }
|