Up until now, the cube we have drawn was created by a custom object. There is an easier way of creating basic shapes. This is using primitives.

What primitives are, essentially, is a set of pre-configured objects that you can create instances of to display on your screen.

I have removed all code from the previous tutorial that created the cube, and instead have created a new function that draws a cube, accompanied by a few new friends. First the code creates a fewprimitives. Since objects are created at the origin, we need to translate the object to a spot we want them or else they will all be on top of each other, therefore after we create the objects, we apply a translation translation to the objects, and add them to the 3D root, so that they will be displayed.

```function createShapes(material) {
var cube = o3djs.primitives.createCube(
g_pack,
material,
Math.sqrt(2));   // The length of each side of the cube.

var sphere = o3djs.primitives.createSphere(
g_pack,
material,
1.0,   // Radius of the sphere.
30,    // Number of meridians.
20);    // Number of parallels.

var cylinder = o3djs.primitives.createCylinder(
g_pack,
material,
1.5,   // Depth.
20,    // Number of radial subdivisions.
20);   // Number of vertical subdivisions.

var plane = o3djs.primitives.createPlane(
g_pack,
material,
1,      // Width.
1.618,  // Depth.
3,      // Horizontal subdivisions.
3);     // Vertical subdivisions.

// Make a polygon to extrude for the prism.
var polygon = [];
var n = 10;
for (var i = 0; i < n; ++i) {
var theta = 2.0 * i * Math.PI / n;
var radius = (i % 2) ? 1 : 0.382;
}

var prism = o3djs.primitives.createPrism(
g_pack,
material,
polygon,  // The profile polygon to be extruded.
1);       // The depth of the extrusion.

var disc = o3djs.primitives.createDisc(
g_pack,
material,
7,   // Divisions.
2,   // Stacks (optional).
0,   // Start Stack (optional).
2);  // Stack Power (optional).

// Add the shapes to the transforms.
var transformTable = [
{shape: cube, translation: [-2, 1, 0]},
{shape: sphere, translation: [0, 1, 0]},
{shape: cylinder, translation: [2, 1, 0]},
{shape: plane, translation: [-2, -1, 0]},
{shape: prism, translation: [0, -1, 0]},
{shape: disc, translation: [2, -1, 0]}
];

for (var i = 0; i < transformTable.length; i++) {
var transform = g_pack.createObject('Transform');
transform.translate(transformTable[i].translation);
transform.parent = g_3dRoot;
}
}```

When you run the code, you may notice that the objects are all a rather boring red, with no shading or lighting, which is something that I will address in the next tutorial…

Here is the full listing of the javascript file

```o3djs.require('o3djs.util');
o3djs.require('o3djs.math');
o3djs.require('o3djs.rendergraph');
o3djs.require('o3djs.canvas');
o3djs.require('o3djs.quaternions');
o3djs.require('o3djs.event');
o3djs.require('o3djs.arcball');
o3djs.require('o3djs.primitives');

// Events
// Run the uninit() function when the page has is unloaded.

// global variables
var g_o3dElement;
var g_o3d;
var g_math;
var g_client;
var g_pack;
var g_clock = 0;
var g_timeMult = 1;
var g_cubeTransform;
var g_textCanvas;
var g_paint;
var g_canvasLib;
var g_3dRoot;
var g_hudRoot;
var g_viewInfo;
var g_hudViewInfo;
var g_keyPressDelta = 0.05;

var g_quaternions;
var g_aball;
var g_thisRot;
var g_lastRot;
var g_dragging = false;
var g_camera = {
eye: [0, 0, 10],
target: [0, 0, 0]
};

function startDragging(e) {
g_lastRot = g_thisRot;
g_aball.click([e.x, e.y]);
g_dragging = true;
}

function drag(e) {
if (g_dragging) {
var rotationQuat = g_aball.drag([e.x, e.y]);
var rot_mat = g_quaternions.quaternionToRotation(rotationQuat);
g_thisRot = g_math.matrix4.mul(g_lastRot, rot_mat);
var m = g_3dRoot.localMatrix;
g_math.matrix4.setUpper3x3(m, g_thisRot);
g_3dRoot.localMatrix = m;
}
}

function stopDragging(e) {
g_dragging = false;
}

function scrollMe(e) {
if (e.deltaY) {
g_camera.eye =
g_math.mulScalarVector((e.deltaY < 0 ? 11 : 13) / 12, g_camera.eye);
g_viewInfo.drawContext.view = g_math.matrix4.lookAt(g_camera.eye,
g_camera.target,
[0, 1, 0]);
}
}

function drawText(str) {
// Clear to completely transparent.
g_textCanvas.canvas.clear([0.5, 0.5, 0.5, 0.5]);

// Reuse the global paint object
var paint = g_paint;
paint.color = [1, 1, 1, 1];
paint.textSize = 12;
paint.textTypeface = 'Comic Sans MS';
paint.textAlign = g_o3d.CanvasPaint.LEFT;
g_textCanvas.canvas.drawText(str, 10, 30, paint);

g_textCanvas.updateTexture();
}

/**
* This method gets called every time O3D renders a frame.  Here's
* where we update the cube's transform to make it spin.
* @param {o3d.RenderEvent} renderEvent The render event object that
* gives us the elapsed time since the last time a frame was rendered.
*/
function renderCallback(renderEvent) {
g_clock += renderEvent.elapsedTime * g_timeMult;
drawText("Hello world - " + (Math.round(g_clock * 100) / 100) + "s");
}

/**
* Function performing the rotate action in response to a key-press.
* Rotates the scene based on key pressed. (w ,s, a, d). Note that the
* x,y-axis referenced here are relative to the current view of scene.
* @param {keyPressed} The letter pressed, in lower case.
* @param {delta} The angle by which the scene should be rotated.
* @return true if an action was taken.
*/
function keyPressedAction(keyPressed, delta) {
var actionTaken = false;
switch(keyPressed) {
case 'a':
g_3dRoot.localMatrix =
g_math.matrix4.mul(g_3dRoot.localMatrix,
g_math.matrix4.rotationY(-delta));
actionTaken = true;
break;
case 'd':
g_3dRoot.localMatrix =
g_math.matrix4.mul(g_3dRoot.localMatrix,
g_math.matrix4.rotationY(delta));
actionTaken = true;
break;
case 'w':
g_3dRoot.localMatrix =
g_math.matrix4.mul(g_3dRoot.localMatrix,
g_math.matrix4.rotationX(-delta));
actionTaken = true;
break;
case 's':
g_3dRoot.localMatrix =
g_math.matrix4.mul(g_3dRoot.localMatrix,
g_math.matrix4.rotationX(delta));
actionTaken = true;
break;
}
return actionTaken;
}

/**
* Callback for the keypress event.
* Invokes the action to be performed for the key pressed.
* @param {event} keyPress event passed to us by javascript.
*/
function keyPressedCallback(event) {
event = event || window.event;

// Ignore accelerator key messages.
if (event.metaKey)
return;

var keyChar =String.fromCharCode(o3djs.event.getEventKeyChar(event));
// Just in case they have capslock on.
keyChar = keyChar.toLowerCase();

if (keyPressedAction(keyChar, g_keyPressDelta)) {
o3djs.event.cancel(event);
}
}

function createShapes(material) {
var cube = o3djs.primitives.createCube(
g_pack,
material,
Math.sqrt(2));   // The length of each side of the cube.

var sphere = o3djs.primitives.createSphere(
g_pack,
material,
1.0,   // Radius of the sphere.
30,    // Number of meridians.
20);    // Number of parallels.

var cylinder = o3djs.primitives.createCylinder(
g_pack,
material,
1.5,   // Depth.
20,    // Number of radial subdivisions.
20);   // Number of vertical subdivisions.

var plane = o3djs.primitives.createPlane(
g_pack,
material,
1,      // Width.
1.618,  // Depth.
3,      // Horizontal subdivisions.
3);     // Vertical subdivisions.

// Make a polygon to extrude for the prism.
var polygon = [];
var n = 10;
for (var i = 0; i < n; ++i) {
var theta = 2.0 * i * Math.PI / n;
var radius = (i % 2) ? 1 : 0.382;
}

var prism = o3djs.primitives.createPrism(
g_pack,
material,
polygon,  // The profile polygon to be extruded.
1);       // The depth of the extrusion.

var disc = o3djs.primitives.createDisc(
g_pack,
material,
7,   // Divisions.
2,   // Stacks (optional).
0,   // Start Stack (optional).
2);  // Stack Power (optional).

// Add the shapes to the transforms.
var transformTable = [
{shape: cube, translation: [-2, 1, 0]},
{shape: sphere, translation: [0, 1, 0]},
{shape: cylinder, translation: [2, 1, 0]},
{shape: plane, translation: [-2, -1, 0]},
{shape: prism, translation: [0, -1, 0]},
{shape: disc, translation: [2, -1, 0]}
];

for (var i = 0; i < transformTable.length; i++) {
var transform = g_pack.createObject('Transform');
transform.translate(transformTable[i].translation);
transform.parent = g_3dRoot;
}
}

/**
* Creates the client area.
*/
function init() {
o3djs.util.makeClients(initStep2);
}

/**
* Initializes O3D.
* @param {Array} clientElements Array of o3d object elements.
*/
function initStep2(clientElements) {
// Initializes global variables and libraries.
g_o3dElement = clientElements;
g_client = g_o3dElement.client;
g_o3d = g_o3dElement.o3d;
g_math = o3djs.math;
g_quaternions = o3djs.quaternions;

// Initialize O3D sample libraries.
o3djs.base.init(g_o3dElement);

// Create a pack to manage the objects created.
g_pack = g_client.createPack();

//Create the arcball which is used for the rotation
g_aball = o3djs.arcball.create(300, 300);

//Initialise rotation matrixes
g_lastRot = g_math.matrix4.identity();
g_thisRot = g_math.matrix4.identity();

// Create 2 root transforms, one for the 3d parts and 2d parts.
// This is not strictly neccassary but it is helpful.
g_3dRoot = g_pack.createObject('Transform');
g_hudRoot = g_pack.createObject('Transform');

// Create the render graph for a view.
g_viewInfo = o3djs.rendergraph.createBasicView(
g_pack,
g_3dRoot,
g_client.renderGraphRoot);

// Set the background color to black.
g_viewInfo.clearBuffer.clearColor = [0, 0, 0, 1];

// Create a second view for the hud.
g_hudViewInfo = o3djs.rendergraph.createBasicView(
g_pack,
g_hudRoot,
g_client.renderGraphRoot);

// Make sure the hud gets drawn after the 3d stuff
g_hudViewInfo.root.priority = g_viewInfo.root.priority + 1;

// Turn off clearing the color for the hud since that would erase the
// 3d parts but leave clearing the depth and stencil so the HUD is
//  unaffected by anything done by the 3d parts.
g_hudViewInfo.clearBuffer.clearColorFlag = false;

// Set up a perspective view
g_viewInfo.drawContext.projection = g_math.matrix4.perspective(
g_client.width / g_client.height,
1,                  // Near plane.
5000);              // Far plane.

// Set up our view transformation to look towards the world origin
// where the cube is located.
g_viewInfo.drawContext.view = g_math.matrix4.lookAt(g_camera.eye, //eye
g_camera.target,  // target
[0, 1, 0]); // up

//Set up the 2d orthographic view
g_hudViewInfo.drawContext.projection = g_math.matrix4.orthographic(
0 + 0.5,
g_client.width + 0.5,
g_client.height + 0.5,
0 + 0.5,
0.001,
1000);

g_hudViewInfo.drawContext.view = g_math.matrix4.lookAt(
[0, 0, 1],   // eye
[0, 0, 0],   // target
[0, 1, 0]);  // up

var redEffect = g_pack.createObject('Effect');

// Create a Material for the mesh.
var redMaterial = g_pack.createObject('Material');

// Set the material's drawList.
redMaterial.drawList = g_viewInfo.performanceDrawList;

// Apply our effect to this material. The effect tells the 3D
// hardware which shaders to use.
redMaterial.effect = redEffect;

createShapes(redMaterial);

// Create the global paint object that's used by draw operations.
g_paint = g_pack.createObject('CanvasPaint');

// Creates an instance of the canvas utilities library.
g_canvasLib = o3djs.canvas.create(g_pack, g_hudRoot, g_hudViewInfo);

// Create a canvas that will be used to display the text.
g_textCanvas = g_canvasLib.createXYQuad(70, 70, 0, 100, 50, true);
// Set our render callback for animation.
// This sets a function to be executed every time frame is rendered.
g_client.setRenderCallback(renderCallback);

//Set up a callback to interpret keypresses
window.document.onkeypress = keyPressedCallback;

//Set up mouse events