QtOpenGLSpriteBatch.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /**
  2. * Copyright (c) 2011 Nokia Corporation.
  3. *
  4. * CAUTION: This class is in early, experimental state.
  5. * NOTE, !!!! SOURCE ORIGINA HAS BEEN REMOVED FROM THIS VERSION OF THE SPRITEBATCH!!!
  6. *
  7. */
  8. #include <QMatrix4x4>
  9. #include <QDebug>
  10. #include <math.h>
  11. #include <memory.h>
  12. #include "QtOpenGLSpriteBatch.h"
  13. /*
  14. Shaders for the spritebatch rendering with a color multiply
  15. */
  16. const char* strSpriteBatchFragmentShaderColorMultiplty =
  17. "uniform sampler2D sampler2d;\n"
  18. "varying lowp vec4 vertexColor;\n"
  19. "varying lowp vec2 texCoord;\n"
  20. "void main (void)\n"
  21. "{\n"
  22. " gl_FragColor = texture2D(sampler2d, texCoord)*vertexColor;\n"
  23. "}";
  24. const char* strSpriteBatchVertexShaderColorMultiply =
  25. "attribute highp vec3 vertex;\n"
  26. "uniform mediump mat4 projMatrix;\n"
  27. "uniform mediump mat4 im[16];\n" // input
  28. "varying mediump vec2 texCoord;\n"
  29. "varying mediump vec4 vertexColor;\n"
  30. "void main(void)\n"
  31. "{\n"
  32. "mediump mat4 thisim = im[ int(vertex.z) ];\n"
  33. //"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"
  34. "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"
  35. "gl_Position = vec4(transVertex,1,1) * projMatrix;\n"
  36. "vertexColor = vec4( thisim[3][0], thisim[3][1], thisim[3][2], thisim[3][3] );\n"
  37. //"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"
  38. "mediump vec2 suv = vec2(thisim[2][2], thisim[2][3])*vertex.x + vec2(-thisim[2][3], thisim[2][2])*vertex.y;\n"
  39. "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"
  40. "}";
  41. /*
  42. Shaders for the spritebatch rendering with pure texture
  43. */
  44. const char* strSpriteBatchFragmentShaderPureTexture =
  45. "uniform sampler2D sampler2d;\n"
  46. "varying mediump vec2 texCoord;\n"
  47. "void main (void)\n"
  48. "{\n"
  49. " gl_FragColor = texture2D(sampler2d, texCoord);\n"
  50. "}";
  51. const char* strSpriteBatchVertexShaderPureTexture =
  52. "attribute highp vec3 vertex;\n"
  53. "uniform mediump mat4 projMatrix;\n"
  54. "uniform mediump mat4 im[16];\n" // input
  55. "varying mediump vec2 texCoord;\n"
  56. "void main(void)\n"
  57. "{\n"
  58. "mediump mat4 thisim = im[ int(vertex.z) ];\n"
  59. //"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"
  60. "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"
  61. "gl_Position = vec4(transVertex,1,1) * projMatrix;\n"
  62. //"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"
  63. "mediump vec2 suv = vec2(thisim[2][2], thisim[2][3])*vertex.x + vec2(-thisim[2][3], thisim[2][2])*vertex.y;\n"
  64. "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"
  65. "}";
  66. QtOpenGLSpriteBatch::QtOpenGLSpriteBatch(int w, int h, QObject *parent ) : QObject(parent), SpriteBatch(w,h)
  67. {
  68. for (int f=0; f<COSINE_TABLE_SIZE; f++)
  69. cosineTable[f] = cosf( (float)f / (float)COSINE_TABLE_SIZE * 3.14159f * 2.0f );
  70. batchCounter = 0;
  71. for (int f=0; f<2; f++) {
  72. QGLShader *vshader = new QGLShader(QGLShader::Vertex, this);
  73. const char *src = strSpriteBatchVertexShaderColorMultiply;
  74. if (f!=0) src = strSpriteBatchVertexShaderPureTexture;
  75. if (vshader->compileSourceCode( src ) == false)
  76. qDebug() << "QOGLSBatch: Failed to compile fragment shader" << f;
  77. else
  78. qDebug() << "compiled vs" << f;
  79. QGLShader *fshader = new QGLShader(QGLShader::Fragment, this);
  80. src = strSpriteBatchFragmentShaderColorMultiplty;
  81. if (f!=0) src = strSpriteBatchFragmentShaderPureTexture;
  82. if (fshader->compileSourceCode( src ) == false)
  83. qDebug() << "QOGLSBatch: Failed to compile fragment shader" << f;
  84. else
  85. qDebug() << "compiled" << f;
  86. program[f].addShader( vshader );
  87. program[f].addShader( fshader );
  88. program[f].bindAttributeLocation( "vertex", 0 );
  89. if (program[f].link() == false)
  90. qDebug() << "Error linking the program:"<<f;
  91. else
  92. qDebug() << "linked program:"<<f;
  93. samplerLocation[f] = program[f].uniformLocation("sampler2d");
  94. inputMatrixLocation[f] = program[f].uniformLocation("im");
  95. projmLocation[f] = program[f].uniformLocation("projMatrix");
  96. }
  97. qtvbo = new QGLBuffer( QGLBuffer::VertexBuffer );
  98. if (qtvbo->create() == false)
  99. qDebug() << "Failed to create vertexbuffer.";
  100. else
  101. qDebug() << "Created the vertexbufferobject";
  102. qtvbo->setUsagePattern( QGLBuffer::StaticDraw );
  103. GLfloat vertices[] = {-0.5f,-0.5f,0.0f, 0.5f,-0.5f,0.0f, 0.5f,0.5f,0.0f, // triangle 1
  104. -0.5f,-0.5f,0.0f, 0.5f,0.5f,0.0f, -0.5f,0.5f,0.0f}; // triangle 2
  105. GLfloat *tempVertices = new GLfloat[ 3 * 6 * BATCH_SIZE];
  106. for (int f=0; f<BATCH_SIZE; f++) {
  107. memcpy( tempVertices+f*3*6, vertices, 3*6*sizeof(GLfloat ));
  108. for (int g=0; g<6; g++) tempVertices[ f*3*6+2+g*3 ] = f; // mark the index for each triangle
  109. }
  110. qtvbo->bind();
  111. qtvbo->allocate( tempVertices, BATCH_SIZE*6*sizeof(GLfloat)*3 );
  112. //glBindBuffer(GL_ARRAY_BUFFER, vbo );
  113. //glBufferData(GL_ARRAY_BUFFER, BATCH_SIZE *6*sizeof(GLfloat)*3, tempVertices, GL_STATIC_DRAW );
  114. delete [] tempVertices;
  115. }
  116. QtOpenGLSpriteBatch::~QtOpenGLSpriteBatch()
  117. {
  118. if (qtvbo) delete qtvbo;
  119. qtvbo = 0;
  120. }
  121. void QtOpenGLSpriteBatch::flushSprites(bool useTable)
  122. {
  123. if (batchCounter<1) return; // nothing to fill
  124. float angletointmul = (float)COSINE_TABLE_SIZE/3.14159f/2.0f;
  125. int selectedProgram = 0;
  126. if (allWhite==true) selectedProgram = 1;
  127. //if (selectedProgram==1) qDebug() << "flushing with whiteprogram";
  128. if (currentProgram!=selectedProgram) setActiveProgram( selectedProgram );
  129. // Fill the inputTempMatrices
  130. //float *m = inputMatrixTemp;
  131. SpriteDrawInfo *sdi = batchCollection;
  132. for (int f=0; f<batchCounter; f++)
  133. {
  134. qreal *m = inputMatrixtemp[f].data();
  135. // targetposition
  136. m[8+0] = sdi->posx;
  137. m[8+1] = sdi->posy;
  138. // source angle
  139. if (useTable) {
  140. int siangle = ((int)( sdi->sourceAngle * angletointmul ) & COSINE_TABLE_AND);
  141. m[8+2] = cosineTable[ siangle ];
  142. m[8+3] = cosineTable[(siangle+COSINE_TABLE_SIZE/4)&COSINE_TABLE_AND];
  143. } else {
  144. m[8+2] = cosf( sdi->sourceAngle );
  145. m[8+3] = sinf( sdi->sourceAngle );
  146. }
  147. // Destination orientation
  148. if (sdi->manualTransformActive)
  149. {
  150. m[0] = sdi->manualTransformMatrix[0][0];
  151. m[1] = sdi->manualTransformMatrix[0][1];
  152. m[4] = sdi->manualTransformMatrix[1][0];
  153. m[5] = sdi->manualTransformMatrix[1][1];
  154. }
  155. else
  156. {
  157. if (useTable) {
  158. int iangle = ((int)( sdi->angle * angletointmul ) & COSINE_TABLE_AND);
  159. m[0] = cosineTable[iangle] * sdi->scaleX;
  160. m[1] = cosineTable[(iangle+COSINE_TABLE_SIZE/4)&COSINE_TABLE_AND] * sdi->scaleX;
  161. m[4+0] = cosineTable[(iangle+COSINE_TABLE_SIZE/4)&COSINE_TABLE_AND] * sdi->scaleY;
  162. m[4+1] = -cosineTable[iangle] * sdi->scaleY;
  163. } else {
  164. m[0] = cosf( sdi->angle ) * sdi->scaleX;
  165. m[1] = sinf( sdi->angle ) * sdi->scaleX;
  166. m[4+0] = sinf( sdi->angle ) * sdi->scaleY;
  167. m[4+1] = -cosf( sdi->angle ) * sdi->scaleY;
  168. }
  169. }
  170. // Source rectangle
  171. m[2] = sdi->sourcex;
  172. m[3] = sdi->sourcey;
  173. m[4+2] = sdi->sourceWidth;
  174. m[4+3] = sdi->sourceHeight;
  175. m[12+0] = sdi->r;
  176. m[12+1] = sdi->g;
  177. m[12+2] = sdi->b;
  178. m[12+3] = sdi->a;
  179. sdi++;
  180. }
  181. program[currentProgram].setUniformValueArray(inputMatrixLocation[currentProgram], inputMatrixtemp, batchCounter );
  182. glDrawArrays(GL_TRIANGLES, 0, 6*batchCounter);
  183. // Reset batch
  184. batchCounter = 0;
  185. allWhite = true;
  186. }
  187. #define WHITE_LIMIT 0.999f
  188. void QtOpenGLSpriteBatch::draw ( SpriteDrawInfo *sdi, int spriteCount )
  189. {
  190. SpriteDrawInfo *i = sdi;
  191. while (spriteCount>0) {
  192. bool completelyWhite = false;
  193. if ( i->r>WHITE_LIMIT && i->g>WHITE_LIMIT && i->b>WHITE_LIMIT && i->a > WHITE_LIMIT ) completelyWhite = true;
  194. if (allWhite==true && completelyWhite==false && batchCounter>=2) {
  195. // current would break the "allWhite"-flag. Flush this batch before adding it.
  196. //qDebug() << "Using the white program..";
  197. flushSprites();
  198. }
  199. if (i->textureHandle != currentTexture ) {
  200. // Texture have been changed, flush currently collected renderingdata
  201. flushSprites();
  202. // Change our current texture and activate it.
  203. currentTexture = i->textureHandle;
  204. glBindTexture( GL_TEXTURE_2D, currentTexture );
  205. }
  206. if (!completelyWhite) allWhite = false;
  207. memcpy( batchCollection + batchCounter, i, sizeof( SpriteDrawInfo ) );
  208. batchCounter++;
  209. if (batchCounter>=BATCH_SIZE) flushSprites();
  210. i++;
  211. spriteCount--;
  212. }
  213. }
  214. void QtOpenGLSpriteBatch::setActiveProgram( int programIndex )
  215. {
  216. program[programIndex].bind();
  217. program[programIndex].setUniformValue(samplerLocation[programIndex], 0);
  218. program[programIndex].setUniformValue( projmLocation[programIndex], projectionMatrix );
  219. program[programIndex].enableAttributeArray(0);
  220. program[programIndex].setAttributeBuffer(0, GL_FLOAT, 0, 3, 0 );
  221. currentProgram = programIndex;
  222. }
  223. void QtOpenGLSpriteBatch::begin( BlendMode bmode, TransformMode dTransform, float *customProjectionMatrix)
  224. {
  225. currentDestinationTransform = dTransform;
  226. if (customProjectionMatrix) {
  227. // set projection
  228. QMatrix4x4 projTemp( (qreal*)customProjectionMatrix );
  229. // NOTE, DEBUG, ERROR, WARNING, TODO ..... THIS might have to be transposed. Test when using !!!!!! Otherwise you won't see anything.
  230. projectionMatrix = projTemp;
  231. //program.setUniformValue( projmLocation, projTemp );
  232. } else {
  233. // NOTE, .. HACK FOR HARMATTAN
  234. #ifdef Q_WS_MAEMO_6_removed_as_firecup_is_landscape_app
  235. qreal mproj[16] = {
  236. 0, 2.0f/(float)targetWidth, 0, 0,
  237. 2.0f/(float)targetHeight, 0, 0, 0, // final height
  238. 0, 0, 1, 0,
  239. -1.0f,-1.0f, 0, 1 };
  240. #else
  241. // WITH Other GL - implementations, the matrix is otherway around.
  242. // NOTE, SERIOUS ERROR FOUND IN QTOPENGL. different matrix orientations with setUniformValue / and setUniformValueArray (QMatrix4x4).
  243. qreal mproj[16] = {
  244. 2.0f/(float)targetWidth, 0, 0, 0,
  245. 0, -2.0f/(float)targetHeight, 0, 0,
  246. 0, 0, 1, 0,
  247. -1.0f,1.0f, 0, 1,
  248. };
  249. #endif
  250. projectionMatrix = QMatrix4x4( mproj );
  251. //QMatrix4x4 projTemp( mproj );
  252. //program.setUniformValue( projmLocation, projTemp );
  253. }
  254. glDisable( GL_DEPTH_TEST );
  255. glDepthMask( GL_FALSE );
  256. glEnable( GL_BLEND );
  257. if (bmode==eALPHA)
  258. glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  259. else
  260. glBlendFunc( GL_SRC_ALPHA, GL_ONE);
  261. glDisable( GL_CULL_FACE );
  262. qtvbo->bind();
  263. currentTexture = 0;
  264. allWhite = true;
  265. currentProgram = -1;
  266. }
  267. void QtOpenGLSpriteBatch::end()
  268. {
  269. // Draw everything that is collected.
  270. flushSprites();
  271. }