Page 1 of 1

OpenGL example code

PostPosted: Tue May 22, 2012 1:40 pm
by _Alex_
Hi,

Here is a OpenGL example code using OpenTK library.

Code: Select all
use System
use System.Diagnostics
use System.Drawing
use System.IO
use OpenTK
use OpenTK.Graphics
use OpenTK.Graphics.OpenGL

class HelloGL3 inherits GameWindow
   var vertexShaderHandle as int
   var fragmentShaderHandle as int
   var shaderProgramHandle as int
   var modelviewMatrixLocation as int
   var projectionMatrixLocation as int
   var vaoHandle as int
   var positionVboHandle as int
   var normalVboHandle as int
   var eboHandle as int
   var vertexShaderSource as String = '\n#version 130\n\nprecision highp float;\n\nuniform mat4 projection_matrix;\nuniform mat4 modelview_matrix;\n\nin vec3 in_position;\nin vec3 in_normal;\n\nout vec3 normal;\n\nvoid main(void)\n{\n  //works only for orthogonal modelview\n  normal = (modelview_matrix * vec4(in_normal, 0)).xyz;\n  \n  gl_Position = projection_matrix * modelview_matrix * vec4(in_position, 1);\n}\n\t'
   var fragmentShaderSource as String = '\n#version 130\n\nprecision highp float;\n\nconst vec3 ambient = vec3(0.1, 0.1, 0.1);\nconst vec3 lightVecNormalized = normalize(vec3(0.5, 0.5, 2.0));\nconst vec3 lightColor = vec3(0.9, 0.9, 0.7);\n\nin vec3 normal;\n\nout vec4 out_frag_color;\n\nvoid main(void)\n{\n  float diffuse = clamp(dot(lightVecNormalized, normalize(normal)), 0.0, 1.0);\n  out_frag_color = vec4(ambient + diffuse * lightColor, 1.0);\n}\t\n\t'
   var positionVboData as Vector3[] = @[Vector3(-1.0 to float32, -1.0  to float32,  1.0 to float32), Vector3( 1.0 to float32, -1.0 to float32,  1.0 to float32), Vector3( 1.0 to float32,  1.0 to float32,  1.0 to float32), Vector3(-1.0 to float32,  1.0 to float32,  1.0 to float32), Vector3(-1.0 to float32, -1.0 to float32, -1.0 to float32), Vector3( 1.0 to float32, -1.0 to float32, -1.0 to float32), Vector3( 1.0 to float32,  1.0 to float32, -1.0 to float32), Vector3(-1.0 to float32,  1.0 to float32, -1.0 to float32) ]
   var indicesVboData as int[] = @[ 0, 1, 2, 2, 3, 0,  3, 2, 6, 6, 7, 3,  7, 6, 5, 5, 4, 7,  4, 0, 3, 3, 7, 4,  0, 1, 5, 5, 4, 0,  1, 5, 6, 6, 2, 1, ]
      # // front face
      # 0, 1, 2, 2, 3, 0,
      # // top face
      # 3, 2, 6, 6, 7, 3,
      # // back face
      # 7, 6, 5, 5, 4, 7,
      # // left face
      # 4, 0, 3, 3, 7, 4,
      # // bottom face
      # 0, 1, 5, 5, 4, 0,
      # // right face
      # 1, 5, 6, 6, 2, 1,
      # ]

   var projectionMatrix as Matrix4
   var modelviewMatrix as Matrix4

   cue init
      base.init(
         640 , 480 ,
         GraphicsMode(),
         "OpenGL 3 Example",
         0 to OpenTK.GameWindowFlags, DisplayDevice.default,
         3, 0, GraphicsContextFlags.ForwardCompatible | GraphicsContextFlags.Debug
         )
   
   def onLoad(e as System.EventArgs?) is override,protected
      .vSync = VSyncMode.On
      .createShaders
      .createVBOs
      .createVAOs
      # // Other state
      GL.enable(EnableCap.DepthTest)
      GL.clearColor(System.Drawing.Color.midnightBlue)

   def createShaders # is override,protected
      .vertexShaderHandle = GL.createShader(ShaderType.VertexShader)
      .fragmentShaderHandle = GL.createShader(ShaderType.FragmentShader)

      GL.shaderSource(.vertexShaderHandle, .vertexShaderSource)
      GL.shaderSource(.fragmentShaderHandle, .fragmentShaderSource)

      GL.compileShader(.vertexShaderHandle)
      GL.compileShader(.fragmentShaderHandle)

      Debug.writeLine(GL.getShaderInfoLog(.vertexShaderHandle))
      Debug.writeLine(GL.getShaderInfoLog(.fragmentShaderHandle))

      # Create program
      .shaderProgramHandle = GL.createProgram

      GL.attachShader(.shaderProgramHandle, .vertexShaderHandle)
      GL.attachShader(.shaderProgramHandle, .fragmentShaderHandle)

      GL.linkProgram(.shaderProgramHandle)

      Debug.writeLine(GL.getProgramInfoLog(.shaderProgramHandle))

      GL.useProgram(.shaderProgramHandle)
      
      # Set uniforms
      .projectionMatrixLocation = GL.getUniformLocation(.shaderProgramHandle, "projection_matrix")
      .modelviewMatrixLocation =  GL.getUniformLocation(.shaderProgramHandle, "modelview_matrix")

      aspectRatio as float = .clientSize.width / (.clientSize.height to float)
      Matrix4.createPerspectiveFieldOfView((Math.pi / 4) to float32, aspectRatio to float32, 1 to float32, 100 to float32, out .projectionMatrix)
      .modelviewMatrix = Matrix4.lookAt(Vector3(0, 3, 5), Vector3(0, 0, 0), Vector3(0, 1, 0))

      GL.uniformMatrix4(.projectionMatrixLocation, false , inout .projectionMatrix)
      GL.uniformMatrix4(.modelviewMatrixLocation , false , inout .modelviewMatrix)

   def createVBOs # is override,protected
      GL.genBuffers(1, out .positionVboHandle)
      GL.bindBuffer(BufferTarget.ArrayBuffer, .positionVboHandle)
      GL.bufferData<of Vector3>(
         BufferTarget.ArrayBuffer,
         IntPtr(.positionVboData.length * Vector3.sizeInBytes),
         .positionVboData,
         BufferUsageHint.StaticDraw
         )

      GL.genBuffers(1, out .normalVboHandle)
      GL.bindBuffer(BufferTarget.ArrayBuffer, .normalVboHandle)
      GL.bufferData<of Vector3>(
         BufferTarget.ArrayBuffer,
         IntPtr(.positionVboData.length * Vector3.sizeInBytes),
         .positionVboData,
         BufferUsageHint.StaticDraw
         )

      GL.genBuffers(1, out .eboHandle)
      GL.bindBuffer(BufferTarget.ElementArrayBuffer, .eboHandle)
      GL.bufferData(
         BufferTarget.ElementArrayBuffer,
         IntPtr(Cobra.Lang.NumericTypeInfo(uint).size * .indicesVboData.length),
         .indicesVboData,
         BufferUsageHint.StaticDraw
         )

      GL.bindBuffer(BufferTarget.ArrayBuffer, 0)
      GL.bindBuffer(BufferTarget.ElementArrayBuffer, 0)

   def createVAOs # is override,protected
      # GL3 allows us to store the vertex layout in a "vertex array object" (VAO).
      # This means we do not have to re-issue VertexAttribPointer calls
      # every time we try to use a different vertex layout - these calls are
      # stored in the VAO so we simply need to bind the correct VAO.
      GL.genVertexArrays(1, out .vaoHandle)
      GL.bindVertexArray(.vaoHandle)

      GL.enableVertexAttribArray(0)
      GL.bindBuffer(BufferTarget.ArrayBuffer, .positionVboHandle)
      GL.vertexAttribPointer(0, 3, VertexAttribPointerType.Float, true, Vector3.sizeInBytes, 0)
      GL.bindAttribLocation(.shaderProgramHandle, 0, "in_position")

      GL.enableVertexAttribArray(1)
      GL.bindBuffer(BufferTarget.ArrayBuffer, .normalVboHandle)
      GL.vertexAttribPointer(1, 3, VertexAttribPointerType.Float, true, Vector3.sizeInBytes, 0)
      GL.bindAttribLocation(.shaderProgramHandle, 1, "in_normal")

      GL.bindBuffer(BufferTarget.ElementArrayBuffer, .eboHandle)

      GL.bindVertexArray(0)

   def onUpdateFrame(e as FrameEventArgs?) is override,protected
      rotation as Matrix4 = Matrix4.createRotationY(e.time to float32)
      Matrix4.mult(inout rotation, inout .modelviewMatrix, out .modelviewMatrix)
      GL.uniformMatrix4(.modelviewMatrixLocation, false, inout .modelviewMatrix)

      if .keyboard[OpenTK.Input.Key.Escape]
         .exit

   def onRenderFrame(e as FrameEventArgs?) is override,protected
      GL.viewport(0, 0, .width, .height)
      
      GL.clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit)

      GL.bindVertexArray(.vaoHandle)
      GL.drawElements(BeginMode.Triangles, .indicesVboData.length,
         DrawElementsType.UnsignedInt, IntPtr.zero)

      .swapBuffers
   
   # [STAThread]
   # public static void Main()
   # {
      # using (HelloGL3 example = new HelloGL3())
      # {
         # Utilities.SetWindowTitle(example)
         # example.Run(30)
      # }
   # }


class Program
   def main has STAThread
      example = HelloGL3()
      example.run


Re: OpenGL example code

PostPosted: Tue May 22, 2012 1:46 pm
by _Alex_
Notice how vertexShaderSource is unreadable without multi-line string.

Also omitting brackets in
Code: Select all
example = HelloGL3()
stores `HelloGL3` class reference into `example` variable not the instance of it.

Re: OpenGL example code

PostPosted: Tue May 22, 2012 3:22 pm
by Charles
-- I'll have to take it for a spin. We also have an OpenTK how-to here:

http://cobra-language.com/how-to/OpenTK/

-- Note the use of the @number directive. You can also use suffixes instead of casting like "1.0_f32"

-- Multiline strings are in our future.

-- Being able to refer to classes is a feature.

-- Now I'm not making any promises here, but just floating an idea: Would it make sense for the Cobra parser to support shader source grammar in the language? You'd get syntax highlighting and basic error checking at compile time. It would probably be enabled by a command line flag. Just a thought.

Re: OpenGL example code

PostPosted: Tue May 22, 2012 4:43 pm
by _Alex_
Charles wrote:-- Now I'm not making any promises here, but just floating an idea: Would it make sense for the Cobra parser to support shader source grammar in the language? You'd get syntax highlighting and basic error checking at compile time. It would probably be enabled by a command line flag. Just a thought.

Nice idea.

Re: OpenGL example code

PostPosted: Wed May 23, 2012 4:14 am
by hopscc
-- Multiline strings are in our future.


Evidently somewhere between negative 1 and 3 years in our future...
See ticket:120 and last posting in Forum Discussion Multiline Strings

Re: OpenGL example code

PostPosted: Wed May 23, 2012 11:11 am
by Charles
Without looking back, what I recall is that we didn't agree on how multiline strings should work and then other things like fixes, installer improvements, etc. took precedence. Which is still happening today. I just found a bug when invoking an unknown underscore method such as "_foo(0)" which causes the compiler to choke.

I'm trying to do the minimum for the next release after which I can revisit multiline strings.

Re: OpenGL example code

PostPosted: Sun Jul 01, 2012 2:57 pm
by Charles
A couple coding tips.
# Instead of:
var foo as String = 'xxxxxx'
# You can skip the explicit type:
var foo = 'xxxxxx'
# Cobra will infer the String and it will still be a static type

# for the shader source, you can use one liners like you have:
var vertexShaderSource as String = '\n#version 130\n\nprecision highp float;...'
# or you can use string concatenation and line continuation like so:
var vertexShaderSource = '' + _
'#version 130' + _
'precision highp float;' + _
'uniform mat4 projection_matrix;' + _
'uniform mat4 modelview_matrix;' + _
'in vec3 in_position;' + _
'in vec3 in_normal;' + _
'out vec3 normal;' + _
'void main(void) {' + _
' //works only for orthogonal modelview' + _
' normal = (modelview_matrix * vec4(in_normal, 0)).xyz;' + _
' gl_Position = projection_matrix * modelview_matrix * vec4(in_position, 1);' + _
'}'
# or you can read from a file:
var vertexShaderSource = ''
...
cue init
base.init(...)
vertexSharedSource = File.readAllText('vertex-shared.cl')
# as mentioned earlier, multiline strings are in the future, but you can
# get by with any of the three above techniques for now

# Instead of an array followed by comments:
var indicesVboData as int[] = @[ 0, 1, 2, 2, 3, 0, 3, 2, 6, 6, 7, 3, ...
# // front face
# 0, 1, 2, 2, 3, 0,
# // top face
# 3, 2, 6, 6, 7, 3,
...
# You can go multi-line (and leave out the explicit type again):
var indicesVboData = @[
0, 1, 2, 2, 3, 0, # front face
3, 2, 6, 6, 7, 3, # top face
7, 6, 5, 5, 4, 7, # back face
4, 0, 3, 3, 7, 4, # left face
0, 1, 5, 5, 4, 0, # bottom face
1, 5, 6, 6, 2, 1, # right face
]
# The closing bracket has to match the "var" level or the parser gets confused.
# I'll add a ticket for that.

# for enums, this is okay:
ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit
# but you can also use this terser style:
ClearBufferMask(ColorBufferBit, DepthBufferBit)

Also, Cobra has a "using" statement just like C# so wherever you see it is a C# program, you can do the same in Cobra.

Do you mind if I include your sample in the Cobra test suite to verify that future enhancements don't break its compilation? I ask because I was doing some recent work on method overload resolution and I did break your sample. So it would be good to have in the test suite.