Random Rectangles
This example extends the example on the previous page, supplying the coordinates in pixels as before and now rendering randomly sized and coloured rectangles. Again, we base it on the JavaScript code in WebGL Fundamentals by Gregg Tavares.
We obtain the address of the uniform vec4 u_color with the statement
colourLocation := FShaderProgram.UniformLocation("u_color");and supply a random value of the colour for each rectangle with the line
gl.uniform4f(colourLocation, random(), random(), random(), 1);
See below a demo that draws random rectangles using Version 3.0 of Smart Mobile Studio.
unit Form1; // Draws randomly sized and coloured rectangles made up of two triangles with coords in pixels 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; type TForm1 = class(TW3form) protected FCanvas: TW3GraphicContext; gl: JWebGLRenderingContext; rc: TGLRenderingContext; FRectBuffer: TGLArrayBuffer; FFragmentShader: TGLFragmentShader; FVertexShader: TGLVertexShader; FShaderProgram: TGLShaderProgram; FVertexPosAttrib : Integer; resolutionLocation, colourLocation : JWebGLUniformLocation; procedure InitializeObject; override; procedure SetupScene; procedure Render; procedure setRectangle(x, y, width, height: real); 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 FRectBuffer := TGLArrayBuffer.Create(rc); // create vertex shader FVertexShader := TGLVertexShader.Create(rc); FVertexShader.Compile(#" attribute vec2 a_position; uniform vec2 u_resolution; void main() { // convert the rectangle from pixels to 0.0 to 1.0 vec2 zeroToOne = a_position / u_resolution; // convert from 0->1 to 0->2 vec2 zeroToTwo = zeroToOne * 2.0; // convert from 0->2 to -1->+1 (clipspace) vec2 clipSpace = zeroToTwo - 1.0; gl_Position = vec4(clipSpace, 0, 1); }" ); // create fragment shader FFragmentShader := TGLFragmentShader.Create(rc); FFragmentShader.Compile(#" precision mediump float; uniform vec4 u_color; void main() { gl_FragColor = u_color; }" ); // create shader program and link shaders FShaderProgram := TGLShaderProgram.Create(rc); FShaderProgram.Link(FVertexShader, FFragmentShader); FVertexPosAttrib := FShaderProgram.AttribLocation("a_position"); resolutionLocation := FShaderProgram.UniformLocation("u_resolution"); colourLocation := FShaderProgram.UniformLocation("u_color"); end; procedure TForm1.Render; begin gl.ViewportSet(0, 0, FCanvas.Handle.width, FCanvas.Handle.height); gl.clear(gl.COLOR_BUFFER_BIT); // clears background FShaderProgram.Use; gl.enableVertexAttribArray(FVertexPosAttrib); gl.uniform2f(resolutionLocation, FCanvas.Handle.width, FCanvas.Handle.height); FRectBuffer.VertexAttribPointer(FVertexPosAttrib, 2, False, 0, 0); // draw 50 random rectangles in random colors for var i := 0 to 49 do begin // Setup a random rectangle setRectangle(randomInt(300), randomInt(300), randomInt(300), randomInt(300)); // Set a random color. gl.uniform4f(colourLocation, random(), random(), random(), 1); gl.drawArrays(gl.TRIANGLES, 0, 6); end; end; procedure TForm1.setRectangle(x, y, width, height: real); var x1, x2, y1, y2 : real; begin x1 := x; x2 := x + width; y1 := y; y2 := y + height; FRectBuffer.SetData([ x1, y1, x2, y1, x1, y2, x1, y2, x2, y1, x2, y2 ], abuStatic); end; initialization Forms.RegisterForm({$I %FILE%}, TForm1); end.
Using a TW3WebGL Component in Version 3.0 of Smart Mobile Studio
Start a new form-based project in Version 3.0 of Smart Mobile Studio, select the Graphics tab and add a TW3WebGL component then name the component WebGLCanvas. Paste this code into the source view of the form.
unit Form1; interface uses System.Types, System.Types.Convert, System.Objects, System.Time, System.IOUtils, System.Device.Storage, SmartCL.System, SmartCL.Time, SmartCL.Graphics, SmartCL.Components, SmartCL.FileUtils, SmartCL.Device.Storage, SmartCL.Forms, SmartCL.Fonts, SmartCL.Theme, SmartCL.Borders, SmartCL.Application, SmartCL.Controls.WebGL, Khronos.WebGl, GLS.Vectors, W3C.TypedArray; type TForm1 = class(TW3Form) private {$I 'Form1:intf'} protected FWebGL: JWebGLRenderingContext; FRectBuffer: JWebGLBuffer; FFragmentShader, FVertexShader: JWebGLShader; FShaderProgram: JWebGLProgram; FVertexPosAttrib: GLint; resolutionLocation, colorLocation : JWebGLUniformLocation; FIteration: integer := 0; procedure InitializeObject; override; procedure InitShaders; procedure DrawScene; procedure setRectangle(x, y, width, height: real); end; implementation procedure TForm1.InitializeObject; begin inherited; {$I 'Form1:impl'} FWebGL := WebGLCanvas.Scene.Handle; InitShaders; FRectBuffer := FWebGL.createBuffer; FWebGL.bindBuffer(FWebGL.ARRAY_BUFFER, FRectBuffer); FWebGL.clearColor(0.0, 0.0, 1.0, 1.0); // blue FWebGL.enable(FWebGL.DEPTH_TEST); asm window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function( callback ){ window.setTimeout(callback, 1000 / 60); }; })(); end; DrawScene; end; procedure TForm1.InitShaders; begin // create vertex shader FVertexShader := FWebGL.createShader(FWebGL.VERTEX_SHADER); FWebGL.shaderSource(FVertexShader, #" attribute vec2 a_position; uniform vec2 u_resolution; void main() { // convert the rectangle from pixels to 0.0 to 1.0 vec2 zeroToOne = a_position / u_resolution; // convert from 0->1 to 0->2 vec2 zeroToTwo = zeroToOne * 2.0; // convert from 0->2 to -1->+1 (clipspace) vec2 clipSpace = zeroToTwo - 1.0; gl_Position = vec4(clipSpace, 0, 1); }"); // compile vertex shader FWebGL.compileShader(FVertexShader); // create fragment shader FFragmentShader := FWebGL.createShader(FWebGL.FRAGMENT_SHADER); FWebGL.shaderSource(FFragmentShader, #" precision mediump float; uniform vec4 u_color; void main() { gl_FragColor = u_color; }"); // Compile fragment shader. FWebGL.compileShader(FFragmentShader); // Create shader program and attach shaders, then link shader program. FShaderProgram := FWebGL.createProgram; FWebGL.attachShader(FShaderProgram, FVertexShader); FWebGL.attachShader(FShaderProgram, FFragmentShader); FWebGL.linkProgram(FShaderProgram); // Get locations of a_position, u_resolution and u_color. FVertexPosAttrib := FWebGL.getAttribLocation(FShaderProgram, "a_position"); resolutionLocation := FWebGL.getUniformLocation(FShaderProgram, "u_resolution"); colorLocation := FWebGL.getUniformLocation(FShaderProgram, "u_color"); end; procedure TForm1.DrawScene; begin if FIteration < 2 then begin WebGLCanvas.Width := 300; WebGLCanvas.Height := 300; // Set viewport to bounds of WebGL canvas. FWebGL.ViewportSet(0, 0, WebGLCanvas.Width, WebGLCanvas.Height); // Clear background to blue. FWebGL.clear(FWebGL.COLOR_BUFFER_BIT); FWebGL.useProgram(FShaderProgram); FWebGL.enableVertexAttribArray(FVertexPosAttrib); FWebGL.uniform2f(resolutionLocation, WebGLCanvas.Width, WebGLCanvas.Height); FWebGL.vertexAttribPointer(FVertexPosAttrib, 2, FWebGL.FLOAT, False, 0, 0); // Draw 50 random rectangles in random colors. for var i := 0 to 49 do begin // Setup a random rectangle. setRectangle(randomInt(300), randomInt(300), randomInt(300), randomInt(300)); // Set a random color. FWebGL.uniform4f(colorLocation, random(), random(), random(), 1); FWebGL.drawArrays(FWebGL.TRIANGLE_STRIP, 0, 4); end; var renderCallback := @DrawScene; asm window.requestAnimFrame(@renderCallback); end; inc(FIteration); end; end; procedure TForm1.setRectangle(x, y, width, height: real); var x1, x2, y1, y2 : real; Vertices: array of Float; begin x1 := x; x2 := x + width; y1 := y; y2 := y + height; Vertices:= [ x1, y1, x2, y1, x1, y2, x2, y2 ]; FWebGL.bufferData(FWebGL.ARRAY_BUFFER, JFloat32Array.Create(Vertices), FWebGL.STATIC_DRAW); end; initialization Forms.RegisterForm({$I %FILE%}, TForm1); end.