43 * The ConvolveOp shader is fairly straightforward. For each texel in 44 * the source texture, the shader samples the MxN texels in the surrounding 45 * area, multiplies each by its corresponding kernel value, and then sums 46 * them all together to produce a single color result. Finally, the 47 * resulting value is multiplied by the current OpenGL color, which contains 48 * the extra alpha value. 49 * 50 * Note that this shader source code includes some "holes" marked by "%s". 51 * This allows us to build different shader programs (e.g. one for 52 * 3x3, one for 5x5, and so on) simply by filling in these "holes" with 53 * a call to sprintf(). See the OGLBufImgOps_CreateConvolveProgram() method 54 * for more details. 55 * 56 * REMIND: Currently this shader (and the supporting code in the 57 * EnableConvolveOp() method) only supports 3x3 and 5x5 filters. 58 * Early shader-level hardware did not support non-constant sized 59 * arrays but modern hardware should support them (although I 60 * don't know of any simple way to find out, other than to compile 61 * the shader at runtime and see if the drivers complain). 62 */ 63 static const char *convolveShaderSource = 64 // maximum size supported by this shader 65 "const int MAX_KERNEL_SIZE = %s;" 66 // image to be convolved 67 "uniform sampler%s baseImage;" 68 // image edge limits: 69 // imgEdge.xy = imgMin.xy (anything < will be treated as edge case) 70 // imgEdge.zw = imgMax.xy (anything > will be treated as edge case) 71 "uniform vec4 imgEdge;" 72 // value for each location in the convolution kernel: 73 // kernelVals[i].x = offsetX[i] 74 // kernelVals[i].y = offsetY[i] 75 // kernelVals[i].z = kernel[i] 76 "uniform vec3 kernelVals[MAX_KERNEL_SIZE];" 77 "" 78 "void main(void)" 79 "{" 80 " int i;" 81 " vec4 sum;" 82 "" 83 " if (any(lessThan(gl_TexCoord[0].st, imgEdge.xy)) ||" 84 " any(greaterThan(gl_TexCoord[0].st, imgEdge.zw)))" 85 " {" 86 // (placeholder for edge condition code) 87 " %s" 88 " } else {" 89 " sum = vec4(0.0);" 90 " for (i = 0; i < MAX_KERNEL_SIZE; i++) {" 91 " sum +=" 92 " kernelVals[i].z *" 93 " texture%s(baseImage," 94 " gl_TexCoord[0].st + kernelVals[i].xy);" 95 " }" 96 " }" 97 "" 98 // modulate with gl_Color in order to apply extra alpha 99 " gl_FragColor = sum * gl_Color;" 100 "}"; 101 102 /** 103 * Flags that can be bitwise-or'ed together to control how the shader 104 * source code is generated. 105 */ 106 #define CONVOLVE_RECT (1 << 0) 107 #define CONVOLVE_EDGE_ZERO_FILL (1 << 1) 108 #define CONVOLVE_5X5 (1 << 2) 109 110 /** 111 * The handles to the ConvolveOp fragment program objects. The index to 112 * the array should be a bitwise-or'ing of the CONVOLVE_* flags defined 113 * above. Note that most applications will likely need to initialize one 114 * or two of these elements, so the array is usually sparsely populated. 115 */ 116 static GLhandleARB convolvePrograms[8]; 117 118 /** 119 * The maximum kernel size supported by the ConvolveOp shader. 120 */ 133 char *kernelMax = IS_SET(CONVOLVE_5X5) ? "25" : "9"; 134 char *target = IS_SET(CONVOLVE_RECT) ? "2DRect" : "2D"; 135 char edge[100]; 136 char finalSource[2000]; 137 138 J2dTraceLn1(J2D_TRACE_INFO, 139 "OGLBufImgOps_CreateConvolveProgram: flags=%d", 140 flags); 141 142 if (IS_SET(CONVOLVE_EDGE_ZERO_FILL)) { 143 // EDGE_ZERO_FILL: fill in zero at the edges 144 sprintf(edge, "sum = vec4(0.0);"); 145 } else { 146 // EDGE_NO_OP: use the source pixel color at the edges 147 sprintf(edge, 148 "sum = texture%s(baseImage, gl_TexCoord[0].st);", 149 target); 150 } 151 152 // compose the final source code string from the various pieces 153 sprintf(finalSource, convolveShaderSource, 154 kernelMax, target, edge, target); 155 156 convolveProgram = OGLContext_CreateFragmentProgram(finalSource); 157 if (convolveProgram == 0) { 158 J2dRlsTraceLn(J2D_TRACE_ERROR, 159 "OGLBufImgOps_CreateConvolveProgram: error creating program"); 160 return 0; 161 } 162 163 // "use" the program object temporarily so that we can set the uniforms 164 j2d_glUseProgramObjectARB(convolveProgram); 165 166 // set the "uniform" texture unit binding 167 loc = j2d_glGetUniformLocationARB(convolveProgram, "baseImage"); 168 j2d_glUniform1iARB(loc, 0); // texture unit 0 169 170 // "unuse" the program object; it will be re-bound later as needed 171 j2d_glUseProgramObjectARB(0); 172 173 return convolveProgram; 174 } 282 * to the user's offset value (these are component-wise operations). 283 * Finally, the resulting value is multiplied by the current OpenGL color, 284 * which contains the extra alpha value. 285 * 286 * The RescaleOp spec says that the operation is performed regardless of 287 * whether the source data is premultiplied or non-premultiplied. This is 288 * a problem for the OpenGL pipeline in that a non-premultiplied 289 * BufferedImage will have already been converted into premultiplied 290 * when uploaded to an OpenGL texture. Therefore, we have a special mode 291 * called RESCALE_NON_PREMULT (used only for source images that were 292 * originally non-premultiplied) that un-premultiplies the source color 293 * prior to the rescale operation, then re-premultiplies the resulting 294 * color before returning from the fragment shader. 295 * 296 * Note that this shader source code includes some "holes" marked by "%s". 297 * This allows us to build different shader programs (e.g. one for 298 * GL_TEXTURE_2D targets, one for GL_TEXTURE_RECTANGLE_ARB targets, and so on) 299 * simply by filling in these "holes" with a call to sprintf(). See the 300 * OGLBufImgOps_CreateRescaleProgram() method for more details. 301 */ 302 static const char *rescaleShaderSource = 303 // image to be rescaled 304 "uniform sampler%s baseImage;" 305 // vector containing scale factors 306 "uniform vec4 scaleFactors;" 307 // vector containing offsets 308 "uniform vec4 offsets;" 309 "" 310 "void main(void)" 311 "{" 312 " vec4 srcColor = texture%s(baseImage, gl_TexCoord[0].st);" 313 // (placeholder for un-premult code) 314 " %s" 315 // rescale source value 316 " vec4 result = (srcColor * scaleFactors) + offsets;" 317 // (placeholder for re-premult code) 318 " %s" 319 // modulate with gl_Color in order to apply extra alpha 320 " gl_FragColor = result * gl_Color;" 321 "}"; 322 323 /** 324 * Flags that can be bitwise-or'ed together to control how the shader 325 * source code is generated. 326 */ 327 #define RESCALE_RECT (1 << 0) 328 #define RESCALE_NON_PREMULT (1 << 1) 329 330 /** 331 * The handles to the RescaleOp fragment program objects. The index to 332 * the array should be a bitwise-or'ing of the RESCALE_* flags defined 333 * above. Note that most applications will likely need to initialize one 334 * or two of these elements, so the array is usually sparsely populated. 335 */ 336 static GLhandleARB rescalePrograms[4]; 337 338 /** 339 * Compiles and links the RescaleOp shader program. If successful, this 340 * function returns a handle to the newly created shader program; otherwise 341 * returns 0. 343 static GLhandleARB 344 OGLBufImgOps_CreateRescaleProgram(jint flags) 345 { 346 GLhandleARB rescaleProgram; 347 GLint loc; 348 char *target = IS_SET(RESCALE_RECT) ? "2DRect" : "2D"; 349 char *preRescale = ""; 350 char *postRescale = ""; 351 char finalSource[2000]; 352 353 J2dTraceLn1(J2D_TRACE_INFO, 354 "OGLBufImgOps_CreateRescaleProgram: flags=%d", 355 flags); 356 357 if (IS_SET(RESCALE_NON_PREMULT)) { 358 preRescale = "srcColor.rgb /= srcColor.a;"; 359 postRescale = "result.rgb *= result.a;"; 360 } 361 362 // compose the final source code string from the various pieces 363 sprintf(finalSource, rescaleShaderSource, 364 target, target, preRescale, postRescale); 365 366 rescaleProgram = OGLContext_CreateFragmentProgram(finalSource); 367 if (rescaleProgram == 0) { 368 J2dRlsTraceLn(J2D_TRACE_ERROR, 369 "OGLBufImgOps_CreateRescaleProgram: error creating program"); 370 return 0; 371 } 372 373 // "use" the program object temporarily so that we can set the uniforms 374 j2d_glUseProgramObjectARB(rescaleProgram); 375 376 // set the "uniform" values 377 loc = j2d_glGetUniformLocationARB(rescaleProgram, "baseImage"); 378 j2d_glUniform1iARB(loc, 0); // texture unit 0 379 380 // "unuse" the program object; it will be re-bound later as needed 381 j2d_glUseProgramObjectARB(0); 382 383 return rescaleProgram; 384 } 488 * this fact because the software LookupOp implementation would usually 489 * throw an ArrayIndexOutOfBoundsException in this scenario (although it is 490 * not something demanded by the spec). 491 * 492 * The LookupOp spec says that the operation is performed regardless of 493 * whether the source data is premultiplied or non-premultiplied. This is 494 * a problem for the OpenGL pipeline in that a non-premultiplied 495 * BufferedImage will have already been converted into premultiplied 496 * when uploaded to an OpenGL texture. Therefore, we have a special mode 497 * called LOOKUP_NON_PREMULT (used only for source images that were 498 * originally non-premultiplied) that un-premultiplies the source color 499 * prior to the lookup operation, then re-premultiplies the resulting 500 * color before returning from the fragment shader. 501 * 502 * Note that this shader source code includes some "holes" marked by "%s". 503 * This allows us to build different shader programs (e.g. one for 504 * GL_TEXTURE_2D targets, one for GL_TEXTURE_RECTANGLE_ARB targets, and so on) 505 * simply by filling in these "holes" with a call to sprintf(). See the 506 * OGLBufImgOps_CreateLookupProgram() method for more details. 507 */ 508 static const char *lookupShaderSource = 509 // source image (bound to texture unit 0) 510 "uniform sampler%s baseImage;" 511 // lookup table (bound to texture unit 1) 512 "uniform sampler2D lookupTable;" 513 // offset subtracted from source index prior to lookup step 514 "uniform vec4 offset;" 515 "" 516 "void main(void)" 517 "{" 518 " vec4 srcColor = texture%s(baseImage, gl_TexCoord[0].st);" 519 // (placeholder for un-premult code) 520 " %s" 521 // subtract offset from original index 522 " vec4 srcIndex = srcColor - offset;" 523 // use source value as input to lookup table (note that 524 // "v" texcoords are hardcoded to hit texel centers of 525 // each row/band in texture) 526 " vec4 result;" 527 " result.r = texture2D(lookupTable, vec2(srcIndex.r, 0.125)).r;" 528 " result.g = texture2D(lookupTable, vec2(srcIndex.g, 0.375)).r;" 529 " result.b = texture2D(lookupTable, vec2(srcIndex.b, 0.625)).r;" 530 // (placeholder for alpha store code) 531 " %s" 532 // (placeholder for re-premult code) 533 " %s" 534 // modulate with gl_Color in order to apply extra alpha 535 " gl_FragColor = result * gl_Color;" 536 "}"; 537 538 /** 539 * Flags that can be bitwise-or'ed together to control how the shader 540 * source code is generated. 541 */ 542 #define LOOKUP_RECT (1 << 0) 543 #define LOOKUP_USE_SRC_ALPHA (1 << 1) 544 #define LOOKUP_NON_PREMULT (1 << 2) 545 546 /** 547 * The handles to the LookupOp fragment program objects. The index to 548 * the array should be a bitwise-or'ing of the LOOKUP_* flags defined 549 * above. Note that most applications will likely need to initialize one 550 * or two of these elements, so the array is usually sparsely populated. 551 */ 552 static GLhandleARB lookupPrograms[8]; 553 554 /** 555 * The handle to the lookup table texture object used by the shader. 556 */ 575 J2dTraceLn1(J2D_TRACE_INFO, 576 "OGLBufImgOps_CreateLookupProgram: flags=%d", 577 flags); 578 579 if (IS_SET(LOOKUP_USE_SRC_ALPHA)) { 580 // when numComps is 1 or 3, the alpha is not looked up in the table; 581 // just keep the alpha from the source fragment 582 alpha = "result.a = srcColor.a;"; 583 } else { 584 // when numComps is 4, the alpha is looked up in the table, just 585 // like the other color components from the source fragment 586 alpha = 587 "result.a = texture2D(lookupTable, vec2(srcIndex.a, 0.875)).r;"; 588 } 589 if (IS_SET(LOOKUP_NON_PREMULT)) { 590 preLookup = "srcColor.rgb /= srcColor.a;"; 591 postLookup = "result.rgb *= result.a;"; 592 } 593 594 // compose the final source code string from the various pieces 595 sprintf(finalSource, lookupShaderSource, 596 target, target, preLookup, alpha, postLookup); 597 598 lookupProgram = OGLContext_CreateFragmentProgram(finalSource); 599 if (lookupProgram == 0) { 600 J2dRlsTraceLn(J2D_TRACE_ERROR, 601 "OGLBufImgOps_CreateLookupProgram: error creating program"); 602 return 0; 603 } 604 605 // "use" the program object temporarily so that we can set the uniforms 606 j2d_glUseProgramObjectARB(lookupProgram); 607 608 // set the "uniform" values 609 loc = j2d_glGetUniformLocationARB(lookupProgram, "baseImage"); 610 j2d_glUniform1iARB(loc, 0); // texture unit 0 611 loc = j2d_glGetUniformLocationARB(lookupProgram, "lookupTable"); 612 j2d_glUniform1iARB(loc, 1); // texture unit 1 613 614 // "unuse" the program object; it will be re-bound later as needed 615 j2d_glUseProgramObjectARB(0); 616 | 43 * The ConvolveOp shader is fairly straightforward. For each texel in 44 * the source texture, the shader samples the MxN texels in the surrounding 45 * area, multiplies each by its corresponding kernel value, and then sums 46 * them all together to produce a single color result. Finally, the 47 * resulting value is multiplied by the current OpenGL color, which contains 48 * the extra alpha value. 49 * 50 * Note that this shader source code includes some "holes" marked by "%s". 51 * This allows us to build different shader programs (e.g. one for 52 * 3x3, one for 5x5, and so on) simply by filling in these "holes" with 53 * a call to sprintf(). See the OGLBufImgOps_CreateConvolveProgram() method 54 * for more details. 55 * 56 * REMIND: Currently this shader (and the supporting code in the 57 * EnableConvolveOp() method) only supports 3x3 and 5x5 filters. 58 * Early shader-level hardware did not support non-constant sized 59 * arrays but modern hardware should support them (although I 60 * don't know of any simple way to find out, other than to compile 61 * the shader at runtime and see if the drivers complain). 62 */ 63 64 /** 65 * Flags that can be bitwise-or'ed together to control how the shader 66 * source code is generated. 67 */ 68 #define CONVOLVE_RECT (1 << 0) 69 #define CONVOLVE_EDGE_ZERO_FILL (1 << 1) 70 #define CONVOLVE_5X5 (1 << 2) 71 72 /** 73 * The handles to the ConvolveOp fragment program objects. The index to 74 * the array should be a bitwise-or'ing of the CONVOLVE_* flags defined 75 * above. Note that most applications will likely need to initialize one 76 * or two of these elements, so the array is usually sparsely populated. 77 */ 78 static GLhandleARB convolvePrograms[8]; 79 80 /** 81 * The maximum kernel size supported by the ConvolveOp shader. 82 */ 95 char *kernelMax = IS_SET(CONVOLVE_5X5) ? "25" : "9"; 96 char *target = IS_SET(CONVOLVE_RECT) ? "2DRect" : "2D"; 97 char edge[100]; 98 char finalSource[2000]; 99 100 J2dTraceLn1(J2D_TRACE_INFO, 101 "OGLBufImgOps_CreateConvolveProgram: flags=%d", 102 flags); 103 104 if (IS_SET(CONVOLVE_EDGE_ZERO_FILL)) { 105 // EDGE_ZERO_FILL: fill in zero at the edges 106 sprintf(edge, "sum = vec4(0.0);"); 107 } else { 108 // EDGE_NO_OP: use the source pixel color at the edges 109 sprintf(edge, 110 "sum = texture%s(baseImage, gl_TexCoord[0].st);", 111 target); 112 } 113 114 // compose the final source code string from the various pieces 115 sprintf(finalSource, 116 // maximum size supported by this shader 117 "const int MAX_KERNEL_SIZE = %s;" 118 // image to be convolved 119 "uniform sampler%s baseImage;" 120 // image edge limits: 121 // imgEdge.xy = imgMin.xy (anything < will be treated as edge case) 122 // imgEdge.zw = imgMax.xy (anything > will be treated as edge case) 123 "uniform vec4 imgEdge;" 124 // value for each location in the convolution kernel: 125 // kernelVals[i].x = offsetX[i] 126 // kernelVals[i].y = offsetY[i] 127 // kernelVals[i].z = kernel[i] 128 "uniform vec3 kernelVals[MAX_KERNEL_SIZE];" 129 "" 130 "void main(void)" 131 "{" 132 " int i;" 133 " vec4 sum;" 134 "" 135 " if (any(lessThan(gl_TexCoord[0].st, imgEdge.xy)) ||" 136 " any(greaterThan(gl_TexCoord[0].st, imgEdge.zw)))" 137 " {" 138 // (placeholder for edge condition code) 139 " %s" 140 " } else {" 141 " sum = vec4(0.0);" 142 " for (i = 0; i < MAX_KERNEL_SIZE; i++) {" 143 " sum +=" 144 " kernelVals[i].z *" 145 " texture%s(baseImage," 146 " gl_TexCoord[0].st + kernelVals[i].xy);" 147 " }" 148 " }" 149 "" 150 // modulate with gl_Color in order to apply extra alpha 151 " gl_FragColor = sum * gl_Color;" 152 "}", kernelMax, target, edge, target); 153 154 convolveProgram = OGLContext_CreateFragmentProgram(finalSource); 155 if (convolveProgram == 0) { 156 J2dRlsTraceLn(J2D_TRACE_ERROR, 157 "OGLBufImgOps_CreateConvolveProgram: error creating program"); 158 return 0; 159 } 160 161 // "use" the program object temporarily so that we can set the uniforms 162 j2d_glUseProgramObjectARB(convolveProgram); 163 164 // set the "uniform" texture unit binding 165 loc = j2d_glGetUniformLocationARB(convolveProgram, "baseImage"); 166 j2d_glUniform1iARB(loc, 0); // texture unit 0 167 168 // "unuse" the program object; it will be re-bound later as needed 169 j2d_glUseProgramObjectARB(0); 170 171 return convolveProgram; 172 } 280 * to the user's offset value (these are component-wise operations). 281 * Finally, the resulting value is multiplied by the current OpenGL color, 282 * which contains the extra alpha value. 283 * 284 * The RescaleOp spec says that the operation is performed regardless of 285 * whether the source data is premultiplied or non-premultiplied. This is 286 * a problem for the OpenGL pipeline in that a non-premultiplied 287 * BufferedImage will have already been converted into premultiplied 288 * when uploaded to an OpenGL texture. Therefore, we have a special mode 289 * called RESCALE_NON_PREMULT (used only for source images that were 290 * originally non-premultiplied) that un-premultiplies the source color 291 * prior to the rescale operation, then re-premultiplies the resulting 292 * color before returning from the fragment shader. 293 * 294 * Note that this shader source code includes some "holes" marked by "%s". 295 * This allows us to build different shader programs (e.g. one for 296 * GL_TEXTURE_2D targets, one for GL_TEXTURE_RECTANGLE_ARB targets, and so on) 297 * simply by filling in these "holes" with a call to sprintf(). See the 298 * OGLBufImgOps_CreateRescaleProgram() method for more details. 299 */ 300 301 /** 302 * Flags that can be bitwise-or'ed together to control how the shader 303 * source code is generated. 304 */ 305 #define RESCALE_RECT (1 << 0) 306 #define RESCALE_NON_PREMULT (1 << 1) 307 308 /** 309 * The handles to the RescaleOp fragment program objects. The index to 310 * the array should be a bitwise-or'ing of the RESCALE_* flags defined 311 * above. Note that most applications will likely need to initialize one 312 * or two of these elements, so the array is usually sparsely populated. 313 */ 314 static GLhandleARB rescalePrograms[4]; 315 316 /** 317 * Compiles and links the RescaleOp shader program. If successful, this 318 * function returns a handle to the newly created shader program; otherwise 319 * returns 0. 321 static GLhandleARB 322 OGLBufImgOps_CreateRescaleProgram(jint flags) 323 { 324 GLhandleARB rescaleProgram; 325 GLint loc; 326 char *target = IS_SET(RESCALE_RECT) ? "2DRect" : "2D"; 327 char *preRescale = ""; 328 char *postRescale = ""; 329 char finalSource[2000]; 330 331 J2dTraceLn1(J2D_TRACE_INFO, 332 "OGLBufImgOps_CreateRescaleProgram: flags=%d", 333 flags); 334 335 if (IS_SET(RESCALE_NON_PREMULT)) { 336 preRescale = "srcColor.rgb /= srcColor.a;"; 337 postRescale = "result.rgb *= result.a;"; 338 } 339 340 // compose the final source code string from the various pieces 341 sprintf(finalSource, 342 // image to be rescaled 343 "uniform sampler%s baseImage;" 344 // vector containing scale factors 345 "uniform vec4 scaleFactors;" 346 // vector containing offsets 347 "uniform vec4 offsets;" 348 "" 349 "void main(void)" 350 "{" 351 " vec4 srcColor = texture%s(baseImage, gl_TexCoord[0].st);" 352 // (placeholder for un-premult code) 353 " %s" 354 // rescale source value 355 " vec4 result = (srcColor * scaleFactors) + offsets;" 356 // (placeholder for re-premult code) 357 " %s" 358 // modulate with gl_Color in order to apply extra alpha 359 " gl_FragColor = result * gl_Color;" 360 "}", target, target, preRescale, postRescale); 361 362 rescaleProgram = OGLContext_CreateFragmentProgram(finalSource); 363 if (rescaleProgram == 0) { 364 J2dRlsTraceLn(J2D_TRACE_ERROR, 365 "OGLBufImgOps_CreateRescaleProgram: error creating program"); 366 return 0; 367 } 368 369 // "use" the program object temporarily so that we can set the uniforms 370 j2d_glUseProgramObjectARB(rescaleProgram); 371 372 // set the "uniform" values 373 loc = j2d_glGetUniformLocationARB(rescaleProgram, "baseImage"); 374 j2d_glUniform1iARB(loc, 0); // texture unit 0 375 376 // "unuse" the program object; it will be re-bound later as needed 377 j2d_glUseProgramObjectARB(0); 378 379 return rescaleProgram; 380 } 484 * this fact because the software LookupOp implementation would usually 485 * throw an ArrayIndexOutOfBoundsException in this scenario (although it is 486 * not something demanded by the spec). 487 * 488 * The LookupOp spec says that the operation is performed regardless of 489 * whether the source data is premultiplied or non-premultiplied. This is 490 * a problem for the OpenGL pipeline in that a non-premultiplied 491 * BufferedImage will have already been converted into premultiplied 492 * when uploaded to an OpenGL texture. Therefore, we have a special mode 493 * called LOOKUP_NON_PREMULT (used only for source images that were 494 * originally non-premultiplied) that un-premultiplies the source color 495 * prior to the lookup operation, then re-premultiplies the resulting 496 * color before returning from the fragment shader. 497 * 498 * Note that this shader source code includes some "holes" marked by "%s". 499 * This allows us to build different shader programs (e.g. one for 500 * GL_TEXTURE_2D targets, one for GL_TEXTURE_RECTANGLE_ARB targets, and so on) 501 * simply by filling in these "holes" with a call to sprintf(). See the 502 * OGLBufImgOps_CreateLookupProgram() method for more details. 503 */ 504 505 /** 506 * Flags that can be bitwise-or'ed together to control how the shader 507 * source code is generated. 508 */ 509 #define LOOKUP_RECT (1 << 0) 510 #define LOOKUP_USE_SRC_ALPHA (1 << 1) 511 #define LOOKUP_NON_PREMULT (1 << 2) 512 513 /** 514 * The handles to the LookupOp fragment program objects. The index to 515 * the array should be a bitwise-or'ing of the LOOKUP_* flags defined 516 * above. Note that most applications will likely need to initialize one 517 * or two of these elements, so the array is usually sparsely populated. 518 */ 519 static GLhandleARB lookupPrograms[8]; 520 521 /** 522 * The handle to the lookup table texture object used by the shader. 523 */ 542 J2dTraceLn1(J2D_TRACE_INFO, 543 "OGLBufImgOps_CreateLookupProgram: flags=%d", 544 flags); 545 546 if (IS_SET(LOOKUP_USE_SRC_ALPHA)) { 547 // when numComps is 1 or 3, the alpha is not looked up in the table; 548 // just keep the alpha from the source fragment 549 alpha = "result.a = srcColor.a;"; 550 } else { 551 // when numComps is 4, the alpha is looked up in the table, just 552 // like the other color components from the source fragment 553 alpha = 554 "result.a = texture2D(lookupTable, vec2(srcIndex.a, 0.875)).r;"; 555 } 556 if (IS_SET(LOOKUP_NON_PREMULT)) { 557 preLookup = "srcColor.rgb /= srcColor.a;"; 558 postLookup = "result.rgb *= result.a;"; 559 } 560 561 // compose the final source code string from the various pieces 562 sprintf(finalSource, 563 // source image (bound to texture unit 0) 564 "uniform sampler%s baseImage;" 565 // lookup table (bound to texture unit 1) 566 "uniform sampler2D lookupTable;" 567 // offset subtracted from source index prior to lookup step 568 "uniform vec4 offset;" 569 "" 570 "void main(void)" 571 "{" 572 " vec4 srcColor = texture%s(baseImage, gl_TexCoord[0].st);" 573 // (placeholder for un-premult code) 574 " %s" 575 // subtract offset from original index 576 " vec4 srcIndex = srcColor - offset;" 577 // use source value as input to lookup table (note that 578 // "v" texcoords are hardcoded to hit texel centers of 579 // each row/band in texture) 580 " vec4 result;" 581 " result.r = texture2D(lookupTable, vec2(srcIndex.r, 0.125)).r;" 582 " result.g = texture2D(lookupTable, vec2(srcIndex.g, 0.375)).r;" 583 " result.b = texture2D(lookupTable, vec2(srcIndex.b, 0.625)).r;" 584 // (placeholder for alpha store code) 585 " %s" 586 // (placeholder for re-premult code) 587 " %s" 588 // modulate with gl_Color in order to apply extra alpha 589 " gl_FragColor = result * gl_Color;" 590 "}", target, target, preLookup, alpha, postLookup); 591 592 lookupProgram = OGLContext_CreateFragmentProgram(finalSource); 593 if (lookupProgram == 0) { 594 J2dRlsTraceLn(J2D_TRACE_ERROR, 595 "OGLBufImgOps_CreateLookupProgram: error creating program"); 596 return 0; 597 } 598 599 // "use" the program object temporarily so that we can set the uniforms 600 j2d_glUseProgramObjectARB(lookupProgram); 601 602 // set the "uniform" values 603 loc = j2d_glGetUniformLocationARB(lookupProgram, "baseImage"); 604 j2d_glUniform1iARB(loc, 0); // texture unit 0 605 loc = j2d_glGetUniformLocationARB(lookupProgram, "lookupTable"); 606 j2d_glUniform1iARB(loc, 1); // texture unit 1 607 608 // "unuse" the program object; it will be re-bound later as needed 609 j2d_glUseProgramObjectARB(0); 610 |