Canvas 3d JS Library

where 3D is born!
  • rss
  • What is C3DL?
  • Download
  • Tutorials
    • Tutorial #1: Installing Canvas 3D Addon
    • Tutorial #2: A Scene and a Cube
    • Tutorial #3: Update Callback
    • Tutorial #4: Models 101
  • Development News
  • Demos
    • Typing Game V2.1
    • Typing Game V3 (0.3 Release)
    • Explorer
    • Flickr - Picking
    • Ricochet
    • FSOSS Pictures
    • Puzzler
  • Resources
  • Contact
  • About

C3DL Canvas2DPresenter Proposal

giberson | 16 September, 2008 | 20:36
This proposal addresses some of the issues brought up in Andrew’s post about providing a text API for the C3DL framework with out over complicating parametrization or usage. The nature of how text is accomplished is inherently related to a 2D drawing API, so the proposal tackles both issues. The suggested method for providing an easy to use, fast interface for 2D drawing and text is to provide an extended canvas element with a built in “to GL Texture” method. A method that which when called, converts the content currently on the 2D context into a GL Texture that can be applied to any model or primitive. From there, we can add any additional helpers to speed up and improve efficiency of drawing or writing text–as demonstrated by the TextHelper function which provides a wrapper to the above stated canvas2DPresenter designed to simply drawing text. Use cases for the proposed methods are show below the code for the function. I apologize for the inconsistency in thoroughness, as some parts of the code have been left as ambiguous pseudo code — ie present() which actually creates the GL Texture. This was left in its condition as the code is available in other areas of the source code. Changes to the Scene object:
/**
* Helper function that takes a any texture (but especially a texture from canvas2DPresenter.present()) and applies it to a 3D plane.
*
* @return PlanePrimitive
*/
this.addTexturePlane(glTexture) {
// create a 3d plane
// .. var plane = new PlanePrimitive();
// apply glTexture to plane
// .. plane.addTexture(glTexture);
// add plane to scene
this.addObjectToScene(plane);
// return reference to plane so user can adjust position/orientation if desired
return plane;
}

/**
* Helper Function that takes any texture (but especially a texture from canvas2dPresneter.present()) and applies it to a given model.
* However, ideally, this method should be obsolete as any model should incorporate a method that applies a given texture to itself.
*/
this.addTextureToModel = function(glTexture, model)
{
model.applyTexture(glTexture);
}

/**
Create a 2D canvas for drawing text and other stuff. Keep a reference to it.
*/
this.create2Dcanvas = function(width, height)
{
var newCanvas = document.createElement('canvas');
newCanvas.id = 'changemetorandomstring';
newCanvas.width = width;
newCanvas.height = height;
cvs.appendChild(newCanvas);

canvas2Dlist.push(newCanvas);

return newCanvas;
}

/**
* returns a new canvas element with an additional function "present" which generates a glTexture to be applied to models/primitives.
*
* @return CanvasElement
*/
this.create2DPresenter = function () {
var newcanvas = document.createElement('canvas');

/**
* Takes current 2d canvas context and turns it into a glTexture
*
* @return glTexture
*/
newcanvas.present = function () {
// psuedo code
var texture = createGlTexture(this);
return texture;
}
// return extended canvas element
return newcanvas;
}

/**
* TextHelper is a wrapper to the extended canvas we get from create2DPresenter that has been specialized for text writing.
*
* @return TextHelper
*/
	this.getTextHelper = function () {
		// return an object TextHelper
		return function () {
			// set some defaults so it works with out any setup calls
			this.fontStyle = "12pt Sans-Serif";
			this.width = 0; // default to auto
			this.height = 0; // default to auto
			this.fillStyle = '#000000'; // supports any valid canvas fillStyle (grad, rgb, rgba, #hex)
			this.globalAlpha = 1.0; // float: 1 = opaque, 0 = transparent
			this.backgroundFillStyle = null; // default to no background

			this.drawtext = function (text) {
				/**
				 * Get ourselves a cavas2dPresenter that lets us have access to canvas's built in 2d api (including text) with a built in toGlCanvas method.
			     */
			 	this.canvas = Scene.create2DPresenter();
			 	this.context = this.canvas.getContext("2d");

			 	var w, h, lw, lh;
			 	var fsize;

				lw = this.width;
				lh = this.height;
				// if width or height was set manually, we dont want to reset
				// to autosize after drawing text, so we save current values and
				// refer to them to check if we reset to 0 (autosize) or leave it as is.

			 	// calculate width/height
		 		var tempSpan = document.createElement('span');
		 		var tempText = document.createTextNode(text);
		 		tempSpan.appendChild(tempText);
		 		tempSpan.style.font = this.fontStyle;
		 		// get the font-size used
		 		fsize = parseInt(tempSpan.style.fontSize);
		 		tempSpan.style.visibility = 'hidden'; // dont show element on page
		 		tempSpan.style.padding = '0';
		 		document.body.appendChild(tempSpan);
		 		// chose set size, or html size, or 1
		 		w = this.width || tempSpan.offsetWidth || 1; // no zeros allowed!
		 		h = this.height || tempSpan.offsetHeight || 1; // no zeros allowed!
		 		// remove junk html tag
		 		document.body.removeChild(tempSpan);

				if(!lw) this.width = 0; // reset for autosize
				if(!lh) this.height = 0; // reset for autosize

				// round w/h to power of 2
				// ..

				// if background color was specified
				this.canvas.width = w;
				this.canvas.height = h;
				if(this.backgroundFillStyle) {
					this.context.fillStyle = this.backgroundFillStyle;
			 		this.context.fillRect(0, 0, w, h);
				}

				// apply helper settings to context
				this.context.fillStyle = this.fillStyle;
				this.context.globalAlpha = this.globalAlpha;
				this.context.width = w;
				this.context.height = h;

				// move to draw origin
				// height hack to center verticaly & account for span padding
				// works best on pt values for font size
				this.context.translate(0, h - ((h-fsize)/2));
			    // render text using font style
			    this.context.mozTextStyle = this.fontStyle;
			    this.context.mozDrawText(text);
			    this.canvas.focus();
			 }

			 /**
			  * Accessor to our canvas2DPresenter present method
			  * @return
			  */
			 this.present = function () {
			 	return this.canvas.present();
			 }
		}();
	}
The suggested use then, to either draw in 2D or draw text, is to ask the API for a canvas2DPresenter, work with it as you would any canvas element for graphic drawing (see Mozilla Developer Center on Drawing with the Canvas) and then call the extended present() to generate a GL Texture for you. Once you have the texture, you can do anything you want with it, from applying it to a model, or a primitive shape. Example usage:
   var c2dp = Scene.create2DPresenter();
   var ctx = c2dp.getContext('2D');

   c2dp.width = 150;
   c2dp.height = 150;
   ctx.beginPath();
   ctx.arc(75,75,50,0,Math.PI*2,true); // Outer circle
   ctx.moveTo(110,75);
   ctx.arc(75,75,35,0,Math.PI,false);   // Mouth (clockwise)
   ctx.moveTo(65,65);
   ctx.arc(60,65,5,0,Math.PI*2,true);  // Left eye
   ctx.moveTo(95,65);
   ctx.arc(90,65,5,0,Math.PI*2,true);  // Right eye
   ctx.stroke();

   var texture = c2dp.present();

   var model = new PrimitivePlane();
   model.applyTexture(texture);
   Scene.addModel(model);
Example using a specialized helper
   var th = Scene.textHelper();
   th.drawText("Hello World");
   var texture = th.present();

   var model = new PrimitivePlane();
   model.applyTexture(texture);
   Scene.addModel(model);

// more advanced usage of helper
   var th3 = new textHelper();
   var lingrad = th3.context.createLinearGradient(0,0,0,150);
   lingrad.addColorStop(0, '#00ABEB');
   lingrad.addColorStop(0.5, '#fff');

   var img = document.getElementById('pattern');
   var ptrn = th3.context.createPattern(img, 'repeat');
   th3.fillStyle = ptrn;
   th3.fontStyle = "40pt Arial Black";
   th3.drawtext("Hello World!");

   var texture = th3.present();
   var model = new PrimitivePlane();
   model.applyTexture(texture);
   Scene.addModel(model);
My use cases employ a fictional PrimitivePlane class that ideally creates a 3D plane facing the viewer and applies its texture stretched onto the plane. In any case I hope this post clarified my ideas for the canvas2D drawing and text support implementation.
Categories
c3dl development
Comments rss
Comments rss

« Google Demo still coming…. Release script »

2 responses

Vlad was in town and he demo'd some of the

Cathy Leung | 18 September, 2008 | 14:27

Vlad was in town and he demo’d some of the other stuff he was doing with 2D canvas in combination with other technology. I think this could have even more potential than we had initially planned.

Thanks for posting this Jeremy

Andrew Smith | 18 September, 2008 | 18:19

Thanks for posting this Jeremy

Leave a comment

You can use these tags : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Search

Demos

  • Explorer
  • Flickr - Picking
  • FSOSS Pictures
  • Puzzler
  • Ricochet
  • Typing Game V2.1
  • Typing Game V3 (0.3 Release)

C3DL Development News

Bounding Boxes on Collada Objects

I ran into a nasty bug that has left me scratching my head recently. It involved taking the work Patrick has done on picking, more specifically his bounding box code and integrating it with Collada objects. It seemed pretty straightforward when I first started working on it, but I have had little success. [...]

A hair away…

Alas, I have approached the summit. With my hands, I have created a Mac application, which runs, and has the customized chrome interface. This alone is an incredible feat for me, since I rarely create GUI-based programs, and I certainly haven’t developed them on a Mac before. The only problem is that the canvas element [...]

Tutorials

  • Tutorial #1: Installing Canvas 3D Addon
  • Tutorial #2: A Scene and a Cube
  • Tutorial #3: Update Callback
  • Tutorial #4: Models 101

Archives

C3DL Development News

Recent Comments

  • December 2008
  • November 2008
  • October 2008
  • September 2008
  • August 2008
  • July 2008
  • June 2008
  • May 2008
  • April 2008
  • March 2008
  • February 2008
  • January 2008
  • December 2007
  • Bounding Boxes on Collada Objects
  • A hair away…
  • Particle Systems
  • Welcome aboard
  • C3DL Namespace refactoring
  • Library Changes
  • Portable Canvas v0.2!
  • Namespaces and const
  • DAE Scenegraph
  • The Matrix Stack
  • That is absolutely a... - Cathy
  • I'm not so certain t... - Cathy Leung
  • For name spaces, my... - Jeremy Giberson
  • Great! Really really... - Edson Mattos
  • Beautiful!... - Funtomas
  • Was no need to conta... - Andrew Smith
  • Andrew, have you con... - Funtomas
  • Thanks for posting t... - Andrew Smith
  • Vlad was in town and... - Cathy Leung
  • the upside down issu... - Cathy Leung



Canvas 3d JS Library

©2007- 2008 Canvas 3d JS Library

Disclaimer: This website is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 2.5 Canada License.
The Canvas 3d JS Library and Demos found on this website are licenced under the MIT License

Creative Commons License