Sunday, June 5, 2011

Render text with canvas 2D

Hello everyone, and welcome to my 4th tutorial about WebGL! This week we shall try something more interesting than spinning a box - Instead of explaining what we are going to do, just take a look at the video below:

You can even put dirty content on it!


The code is not so different then the one from the previous tutorial. But this time, instead of using some static images, let's write our own simple textures - in real time! As before, you download the source code for this tutorial here . I am going to skip the introduction part and head straight over to the important things - how to render a texture with text content.

Step no.1 - create another canvas where we will render our text. That canvas is then going to be copied to a texture which will be used on our box. The new thing here is - we don't need WebGL to create this texture, instead  we can use anoter context - the 2D context. To get access to the 2D API, we use the same function as for WebGL, just with the '2d' parameter. That would then look like this:

context2D = document.getElementById('textCanvas').getContext('2d');

Our entry function has also a few new lines (all context2D calls refer to the textCanvas, all gl calls to the 3d scene):

  • setUpTextArea() - set's up the text format, colors, positioning etc.
  • writeTextToCanvas(Sring text, int textureIndex) - renders the text to a texture

        ....
        initBuffers();

        setUpTextArea();
       for (var ii = 0; ii< 6; ++ii){
         writeTextToCanvas('Type here!', ii);
       }
        gl.clearColor(0.5, 0.5, 0.5, 1.0);
       gl.enable(gl.DEPTH_TEST);
                .... 


So, the setUpTextArea() function does some the initial housekeeping. It's pretty straight forward once you understand the mehtods:


  function setUpTextArea(){
   context2D.font = 'normal 35px Verdana';
   context2D.fillStyle = 'rgba(0,0,0,255)';
   context2D.fillRect(0,0, 300, 300);
   context2D.lineWidth = 5;
    context2D.strokeStyle = 'rgba(0,0,0,255)';
   context2D.textAlign = 'center';
   context2D.textBaseline = 'middle';
}

The font property is I believe pretty obvious - play around with it to see the different looks! The fillStyle property is the actual drawing color - here we set it up to non-transparent black. LineWidth, textAlign and textBaseLine specify the formating properties (2d rendering context API). strokeStyle specifies the outline or shadow of the text - here we have set it also to black. All good? Let's continue.


The next function, writeTextToCanvas(), is actually writing the text for us. It looks like this:


function writeTextToCanvas(text, idx){
context2D.save();

context2D.clearRect ( 0 , 0 , 300 , 300);
context2D.fillStyle = faceColors[idx];
context2D.fillRect(0,0, 300, 300);

context2D.fillStyle = 'rgba(255, 255, 255, 255)';
context2D.strokeText(text, 150, 150);
context2D.fillText(text, 150, 150);

setTextureFromCanvas(context2D.canvas, textures[idx], idx);

context2D.restore();

}
     var faceColors = ['rgba(0, 0, 255, 255)', 'rgba(255, 0, 0, 255)',

                       'rgba(0, 255, 0, 255)', 'rgba(0, 0, 0, 255)',
                       'rgba(255, 0, 255, 255)', 'rgba(0, 255, 255, 255)'];


(Update: 300 is the width and height of the canvas, that's why it's hard coded. I was quite in a rush writing this, no hard feelings!)


The save() and restore() functions are something like push() and pop() in OpenGL - they are used for state management. At the beginning of this function I save my current set-up (which was the initialization), and at the end, once I have my texture created, I restore it again - this way I am always at my starting point when I want to create a texture. Now, a couple of things are important here:
  • strokeText() - writes the outline of the specified text starting at the specified position (with the previously set alignment etc.)
  • clearRectangle() - erases an previously draw objects from the canvas (from point (0,0) to (300,300))
  • fillRectangle() - fills the rectangle with the specified color (from point (0,0) to (300,300))
  • fillText() - writes the text itself (in essence the same function as strokeText())
  • setTextureFromCanvas() - renders the current canvas content to a WebGL Texture object (parameters canvas, a texture object to render on, and an index as a reference to a cube face)
Now, you might think that the last one is quite complicated? Well, it's not at all! In fact, it's almost the same function we used in the previous tutorial, except that instead from an image we are now loading our content from a canvas element! Pretty simple, right? In case you don't believe me, here is the sample code:

function setTextureFromCanvas(canvas, textTexture, idx) {
 gl.activeTexture(gl.TEXTURE0 + idx);
gl.bindTexture(gl.TEXTURE_2D, textTexture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE,          canvas);
if (isPowerOfTwo(canvas.width) && isPowerOfTwo(canvas.height)){
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
}else{
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  }
gl.bindTexture(gl.TEXTURE_2D, textTexture);
gl.uniform1i(shaderTextureIndices[idx], idx); 
}

The big difference between the function from the previous tutorial is and this is that we use a canvas instead of an image. Also this function get's called dynamically as we write the text value - it generates the text and automatically binds the new texture to the shader (the same one as in the previous tutorial). That's why we set the current activeTexture at the begging of this function. All clear? Hope it is, if not drop me a line. And don't complain about my web page style - I'm not a designer :)

6 comments:

  1. The link to the source code is broken. Is there a live demo some where?

    ReplyDelete
  2. Can't you fix the links to the source (also in the previous tutorial)... ?

    ReplyDelete
  3. fix links to the source - drop box outdated probably

    ReplyDelete
  4. I will recommend anyone looking for Business loan to Le_Meridian they helped me with Four Million USD loan to startup my Quilting business and it's was fast When obtaining a loan from them it was surprising at how easy they were to work with. They can finance up to the amount of $500,000,000.000 (Five Hundred Million Dollars) in any region of the world as long as there 1.9% ROI can be guaranteed on the projects.The process was fast and secure. It was definitely a positive experience.Avoid scammers on here and contact Le_Meridian Funding Service On. lfdsloans@lemeridianfds.com / lfdsloans@outlook.com. WhatsApp...+ 19893943740. if you looking for business loan.

    ReplyDelete
  5. DEAR APPLICANT,

    We offer Affordable loan at 3% interest rate available for local and international borrowers. We are certified,trustworthy, reliable, efficient, Fast and dynamic and a co-operate financier for real estate and any kinds of business financing,we offer the following:* Personal Loans * Student Loan * Business Loans * Consolidation Loan * Combination Loan* *Home Enhancement* Car Loan *Construction Loan e.t.c

    We are Christian organization founded, people in needs of assistance helps, such as financial help. So, if you go through financial difficulties or you are in any financial mess, and you need funds, to start you need your own business, or you need a loan to pay off your debts or pay your bills, start a nice business, or you will find it difficult, to obtain capital loan from local banks, for the Bible says , "" Anyone who asks, receives Luke 11.10, and who seeks, finds, and who knocks on the door, the door will be opened ", so do not miss this chance, because Jesus is the same yesterday, today, and forever more. Please this is for serious minded and God-fearing people.

    Fill the application form below for further information.

    Full Name:___________
    Sex:________
    Age:______
    Country:__________
    Address___________
    State: ________
    Tel:______
    Occupation: __________
    Monthly Income:___________
    Loan Amount Needed ($) :__________
    Amount in Words:
    Loan Duration:__________
    Pan Card or Voters Id No:__________

    We await your responds

    Regards
    Trust Bridge Financial Service
    E_mail: trustbridgefinancialservice943@yahoo.com

    ReplyDelete