Rectangle with Coordinates in Pixels

In this example the vertex coordinates are stored in the buffer as pixels and the vertex shader program converts them to clipspace. For the conversion, the x and y coordinates of each pixel must be divided by the width and the height of the canvas, respectively. The vector u_resolution stores the width and height. It is a uniform (with prefix u) rather than an attribute because it remains unchanged for each vertex. We obtain its location with the line
resolutionLocation := FShaderProgram.UniformLocation("u_resolution");
and input its value with the statement
gl.uniform2f(resolutionLocation, FCanvas.Handle.width, FCanvas.Handle.height);.
Comments in the code of the vertex shader are prefixed with // (like one-line comments in Pascal and C). The variable vectors zeroToOne, zeroToTwo and clipSpace are declared in-line.

The example on the next page uses coordinates in pixels and renders rectangles that are randomly sized and coloured.

unit Form1;
// Draws a green rectangle 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 : JWebGLUniformLocation;
    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
  //Put x and y pixel coords of vertices in buffer
  FRectBuffer := TGLArrayBuffer.Create(rc);
  FRectBuffer.SetData([
    10, 20,
    80, 20,
    10, 30,
    10, 30,
    80, 20,
    80, 30
    ], abuStatic);

  // 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(#"
    void main() {
      gl_FragColor = vec4(0, 1, 0, 1);  // green
    }");

  // create shader program and link shaders
  FShaderProgram := TGLShaderProgram.Create(rc);
  FShaderProgram.Link(FVertexShader, FFragmentShader);

  FVertexPosAttrib := FShaderProgram.AttribLocation("a_position");
  resolutionLocation := FShaderProgram.UniformLocation("u_resolution");
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);
  gl.drawArrays(gl.TRIANGLES, 0, 6);
end;
 
initialization
  Forms.RegisterForm({$I %FILE%}, TForm1);
end.    
Programming - a skill for life!

Using WebGL for advanced graphics in Smart Mobile Studio