# Rotating Triangle

We now rotate the triangle with graded shading. As of May 2014 there is no 3D equivalent of the Canvas Game Project in SMS, so movement is implemented with a callback to the Render procedure in a visual components (form-based) project.

We use a projection matrix and a ModelView matrix to calculate the display at regular intervals. The fractional part of the real number returned by the now function is the fraction of the day, so 0.5 is midday. Multiplying by the constant 24 * 3600 converts this to seconds.

We removed the square from the original HelloWebGL demo and centred the triangle by giving the camera x and y coordinates of 0. We set the z coordinate to be negative so that the triangle is in front of the camera. The first argument passed to the Matrix4.CreatePerspective routine, the camera field of view, is 40. We advise you to try to understand as much as possible of the triangle code before moving on to tetrahedra and cubes. As usual, experimenting with the code is useful to aid your learning. Here are some suggestions for experimenting with the code.

• Change the value of the first Matrix4.CreatePerspective argument slightly from 40 to see the a smaller angle close in on the triangle making it appear bigger.
• Change the colours of the three vertices from red, green and blue.
• Change the shader code so that the triangle is uniformly coloured.
• Change gl.TRIANGLES to one of the other possibilities enumerated in Unit w3c.WebGL (POINTS, LINES, LINE_LOOP, LINE_STRIP, TRIANGLES, TRIANGLE_STRIP or TRIANGLE_FAN).

The code for the rotating triangle follows the demo. If these demonstrations do not run in your current browser, please try another such as Chrome, Firefox, Safari or Opera. If you see no display at school, the security system might have blocked it. You can try instead this direct link to the program running on its own page.

## Code of Triangle3D

This code compiles with Versions 2.2 and 3.0 of Smart Mobile Studio.

```unit Form1;

interface

uses
System.Types, W3C.TypedArray, SmartCL.System, SmartCL.Graphics,
SmartCL.Controls, SmartCL.Components, SmartCL.Forms, SmartCL.Fonts,
SmartCL.Borders, SmartCL.Application, Khronos.WebGl, GLS.Base, GLS.Vectors;

type
TForm1 = class(TW3form)
protected
FCanvas : TW3GraphicContext;
gl : JWebGLRenderingContext;
rc : TGLRenderingContext;
FTriangleBuffer, FColorBuffer : TGLArrayBuffer;
FVertexPosAttrib, FVertexColorAttrib : Integer;
procedure InitializeObject; override;
procedure SetupScene;
procedure Render;
end;

implementation

procedure TForm1.InitializeObject;
begin
inherited;
FCanvas := TW3GraphicContext.Create(Self.Handle);
gl := JWebGLRenderingContext(FCanvas.Handle.getContext('experimental-webgl'));
rc := TGLRenderingContext.Create;
rc.GL := gl;
gl.canvas.width := 300;
gl.canvas.height := 300;
SetupScene;
Render;
end;

procedure TForm1.SetupScene;
begin
gl.clearColor(0.0, 0.0, 0.25, 1.0); // Set clear color to blue, fully opaque
gl.clearDepth(1.0);                 // Clear everything
gl.enable(gl.DEPTH_TEST);           // Enable depth testing
gl.depthFunc(gl.LEQUAL);            // Near things obscure far things

FColorBuffer := TGLArrayBuffer.Create(rc);
FColorBuffer.SetData([
1.0, 0.0, 0.0, //red
0.0, 1.0, 0.0, //green
0.0, 0.0, 1.0  //blue
], abuStatic);

FTriangleBuffer := TGLArrayBuffer.Create(rc);
FTriangleBuffer.SetData([
0.0,  1.0,  0.0,
-1.0, -1.0,  0.0,
1.0, -1.0,  0.0
], abuStatic);

attribute vec3 aVertexPosition;
attribute vec3 aVertexColor;

uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;

varying vec4 vColor;

void main(void) {
gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aVertexPosition, 1.0);
vColor = vec4(aVertexColor, 1.0);
}");

precision mediump float;
varying vec4 vColor;
void main(void) {
gl_FragColor = vColor;
}");

asm
window.requestAnimFrame = (function(){
return  window.requestAnimationFrame       ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame    ||
window.oRequestAnimationFrame      ||
window.msRequestAnimationFrame     ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
end;
end;

procedure TForm1.Render;
const
cSpeed = 24 * 3600;
var
ProjectionMatrix, ModelViewMatrix : Matrix4;
ModelViewStack : array of Matrix4;
begin
gl.ViewportSet(0, 0, FCanvas.Handle.width, FCanvas.Handle.height);
gl.clear(gl.COLOR_BUFFER_BIT);  // clears background

ProjectionMatrix := Matrix4.CreatePerspective(40, FCanvas.width / FCanvas.height, 0.1, 100);
ModelViewMatrix := Matrix4.Identity;
gl.enableVertexAttribArray(FVertexPosAttrib);
gl.enableVertexAttribArray(FVertexColorAttrib);

// move centre of triangle directly in front of camera
ModelViewMatrix := ModelViewMatrix.Translate([0, 0, -4]);

ModelViewMatrix := ModelViewMatrix.RotateY(Frac(Now) * cSpeed);

FTriangleBuffer.VertexAttribPointer(FVertexPosAttrib, 3, False, 0, 0);
FColorBuffer.VertexAttribPointer(FVertexColorAttrib, 3, False, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, 3);

var renderCallback := @Render;
asm
window.requestAnimFrame(@renderCallback);
end;
end;

initialization
Forms.RegisterForm({\$I %FILE%}, TForm1);

end.

```
Programming - a skill for life!

Using WebGL for Advanced Graphics in Smart Mobile Studio