About Monkey 2 › Forums › Monkey 2 Projects › Monkey2 OpenGL Experiments
This topic contains 13 replies, has 4 voices, and was last updated by 
 EdzUp
 2 years, 4 months ago.
- 
		AuthorPosts
 - 
		
			
				
October 16, 2016 at 10:28 pm #4461
Here is the basic OpenGL rendering test for Monkey2:
Monkey12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697#Import "<mojo>"Using std..Using mojo..Using gles20..Function glLoadProgram:GLuint(vertexSource:String, fragmentSource:String)Local vs := mojo.graphics.glutil.glCompile(GL_VERTEX_SHADER, vertexSource)Local fs := mojo.graphics.glutil. glCompile(GL_FRAGMENT_SHADER, fragmentSource)Local program := glCreateProgram()glAttachShader(program, vs)glAttachShader(program, fs)mojo.graphics.glutil.glLink(program)glDeleteShader(vs)glDeleteShader(fs)Return programEndFunction LoadSimpleShader:GLuint()Local vertex:String = "attribute vec3 Position;attribute vec3 Color;varying vec3 OutColor;void main() {gl_Position = vec4(Position, 1);OutColor = Color;}"Local fragment:String = "varying vec3 OutColor;void main() {gl_FragColor = vec4(OutColor, 0);}"Local program := glLoadProgram(vertex, fragment)glBindAttribLocation(program, 0, "Position")glBindAttribLocation(program, 1, "Color")Return programEndClass MyWindow Extends GLWindowField vbo:GLuintField shader:GLuintField canvas:CanvasMethod New()' Setup OpenGLglViewport(0, 0, Width, Height)glClearColor(0.1, 0.1, 0.5, 1.0)' declare the shape verticesLocal vertices:Float[] = New Float[](-1,-1,0, 1,0,0,1,-1,0, 0,1,0,0, 1,0, 0,0,1)' Load Shadershader = LoadSimpleShader()Print("Program ID: " + shader)Print("Attribute Location: " + glGetAttribLocation(shader, "Position"))' Create vertex bufferglGenBuffers(1, Varptr vbo)glBindBuffer(GL_ARRAY_BUFFER, vbo)glBufferData(GL_ARRAY_BUFFER, vertices.Length * 4, vertices.Data, GL_DYNAMIC_DRAW)EndMethod OnRender(canvas:mojo.graphics.Canvas) OverrideApp.RequestRender()Super.OnRender(canvas)canvas.DrawText("Monkey2 OpenGL Test", 10, 10)EndMethod OnRenderGL() OverrideglClear(GL_COLOR_BUFFER_BIT)glUseProgram(shader)glBindBuffer(GL_ARRAY_BUFFER, vbo)glEnableVertexAttribArray(0)glEnableVertexAttribArray(1)glVertexAttribPointer(0, 3, GL_FLOAT, False, 24, Cast<Void Ptr>(0))glVertexAttribPointer(1, 3, GL_FLOAT, False, 24, Cast<Void Ptr>(12))glDrawArrays(GL_TRIANGLES, 0, 3)EndEndFunction Main()New AppInstanceNew MyWindowApp.Run()EndLater on I will try to figure out the Matrix4 class and make it 3D. If you have any other ideas say it here.
October 17, 2016 at 11:35 pm #4492Very cool!
Technically speaking, you’re meant to bracket your GL code (outside of OnRenderGL) calls between BeginGL() and EndGL() or you’ll be affecting the ‘shared’ context, but it seems to be working anyway!
I’ve added a few docs to GLWindow too.
October 18, 2016 at 6:43 pm #4518Hi Mark, I don’t know why are there two gl contexts in your design, one for GLWindow and one for Window. Is it mostly for resource organization? Essentially the BeginGL/EndGL performs that swap.
Monkey12345Method OnRender( canvas:Canvas ) OverrideBeginGL()OnRenderGL()EndGL()EndOctober 18, 2016 at 8:04 pm #4519Hi Mark, I don’t know why are there two gl contexts in your design,
A couple of reasons:
- Since I have no idea what GL states custom non-mojo code is modifying, using a single context would mean mojo would have to push/pop/reset (or do something fancy ) with *ALL* GL state before/after any custom GL code runs. This would involved resetting viewport, framebuffer, texture bindings etc which is slow.
 - It allows for the possibility of users creating GL3/GL4 contexts (TODO – might not work).
 
Essentially the BeginGL/EndGL performs that swap.
Yes, but it only happens inside OnRender(). The constructor is still running in mojo’s GL context. Again, not sure why it’s working (your glClearColor should be affecting the mojo GL context) but it looks like creating a GL context is also making it current. This could be an Angle thing though.
November 1, 2016 at 1:36 am #4714I did not think of that. Indeed you wouldn’t “trust” the user messing with the original context of mojo in case something goes wrong. Nice one!
November 21, 2016 at 2:12 pm #5310Now I have created a 3D cube example.
Update 29 Nov 2016: I have fixed some odd problems with the cube and cleaned up the example.
The only problem is that I get weird draw Z order in the faces of the cube.This problem is fixed, I have declared the order of vertices in a proper manner.
The vertex declaration is from a C++ glm example, the matrix math is from OpenTK library.I switched into using the Monogame math since it’s much lean and clean implementation.
Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290#Import "<mojo>"Using std..Using mojo..Using gles20..Function glLoadProgram:GLuint(vertexSource:String, fragmentSource:String)Local vs := mojo.graphics.glutil.glCompile(GL_VERTEX_SHADER, vertexSource)Local fs := mojo.graphics.glutil. glCompile(GL_FRAGMENT_SHADER, fragmentSource)Local program := glCreateProgram()glAttachShader(program, vs)glAttachShader(program, fs)mojo.graphics.glutil.glLink(program)glDeleteShader(vs)glDeleteShader(fs)Return programEndFunction LoadShader:GLuint()Local vertex:String = "uniform mat4 Matrix;attribute vec3 Position;varying vec3 OutColor;void main(){gl_Position = Matrix * vec4(Position, 1);// Higher vertices can be yellow and lower can be red.OutColor = (Position.y < 0.0) ? vec3(1, 0, 0) : vec3(1, 1, 0);}"Local fragment:String = "varying vec3 OutColor;void main(){gl_FragColor = vec4(OutColor, 1);}"Local program := glLoadProgram(vertex, fragment)glBindAttribLocation(program, 0, "Position")Return programEndClass Matrix' Matrix class is based on Monogame math.PrivateField data:Float[] = New Float[16]PublicField M11:Float, M12:Float, M13:Float, M14:FloatField M21:Float, M22:Float, M23:Float, M24:FloatField M31:Float, M32:Float, M33:Float, M34:FloatField M41:Float, M42:Float, M43:Float, M44:FloatProperty ToArray:Float[]()data[0] = M11data[1] = M12data[2] = M13data[3] = M14data[4] = M21data[5] = M22data[6] = M23data[7] = M24data[8] = M31data[9] = M32data[10] = M33data[11] = M34data[12] = M41data[13] = M42data[14] = M43data[15] = M44Return dataEndOperator*:Matrix(matrix:Matrix)Local result := New Matrixresult.M11 = (Self.M11 * matrix.M11) + (Self.M12 * matrix.M21) + (Self.M13 * matrix.M31) + (Self.M14 * matrix.M41)result.M12 = (Self.M11 * matrix.M12) + (Self.M12 * matrix.M22) + (Self.M13 * matrix.M32) + (Self.M14 * matrix.M42)result.M13 = (Self.M11 * matrix.M13) + (Self.M12 * matrix.M23) + (Self.M13 * matrix.M33) + (Self.M14 * matrix.M43)result.M14 = (Self.M11 * matrix.M14) + (Self.M12 * matrix.M24) + (Self.M13 * matrix.M34) + (Self.M14 * matrix.M44)result.M21 = (Self.M21 * matrix.M11) + (Self.M22 * matrix.M21) + (Self.M23 * matrix.M31) + (Self.M24 * matrix.M41)result.M22 = (Self.M21 * matrix.M12) + (Self.M22 * matrix.M22) + (Self.M23 * matrix.M32) + (Self.M24 * matrix.M42)result.M23 = (Self.M21 * matrix.M13) + (Self.M22 * matrix.M23) + (Self.M23 * matrix.M33) + (Self.M24 * matrix.M43)result.M24 = (Self.M21 * matrix.M14) + (Self.M22 * matrix.M24) + (Self.M23 * matrix.M34) + (Self.M24 * matrix.M44)result.M31 = (Self.M31 * matrix.M11) + (Self.M32 * matrix.M21) + (Self.M33 * matrix.M31) + (Self.M34 * matrix.M41)result.M32 = (Self.M31 * matrix.M12) + (Self.M32 * matrix.M22) + (Self.M33 * matrix.M32) + (Self.M34 * matrix.M42)result.M33 = (Self.M31 * matrix.M13) + (Self.M32 * matrix.M23) + (Self.M33 * matrix.M33) + (Self.M34 * matrix.M43)result.M34 = (Self.M31 * matrix.M14) + (Self.M32 * matrix.M24) + (Self.M33 * matrix.M34) + (Self.M34 * matrix.M44)result.M41 = (Self.M41 * matrix.M11) + (Self.M42 * matrix.M21) + (Self.M43 * matrix.M31) + (Self.M44 * matrix.M41)result.M42 = (Self.M41 * matrix.M12) + (Self.M42 * matrix.M22) + (Self.M43 * matrix.M32) + (Self.M44 * matrix.M42)result.M43 = (Self.M41 * matrix.M13) + (Self.M42 * matrix.M23) + (Self.M43 * matrix.M33) + (Self.M44 * matrix.M43)result.M44 = (Self.M41 * matrix.M14) + (Self.M42 * matrix.M24) + (Self.M43 * matrix.M34) + (Self.M44 * matrix.M44)Return resultEndFunction Identity:Matrix()Local result := New Matrixresult.M11 = 1.0result.M22 = 1.0result.M33 = 1.0result.M44 = 1.0Return resultEndFunction Translation:Matrix(x:Float, y:Float, z:Float)Local result := Identity()result.M41 = xresult.M42 = yresult.M43 = zReturn resultEndFunction RotateX:Matrix(angle:Float)Local cos:Float = Cast<Float>(Cos(angle))Local sin:Float = Cast<Float>(Sin(angle))Local result := Identity()result.M22 = cosresult.M23 = sinresult.M32 = -sinresult.M33 = cosReturn resultEndFunction RotateY:Matrix(angle:Float)Local cos:Float = Cast<Float>(Cos(angle))Local sin:Float = Cast<Float>(Sin(angle))Local result := Identity()result.M11 = cosresult.M13 = -sinresult.M31 = sinresult.M33 = cosReturn resultEndFunction Perspective:Matrix(fovy:Float, aspect:Float, near:Float, far:float)Local yMax:Float = near * Tan(0.5 * fovy)Local yMin:Float = -yMaxLocal xMin:Float = yMin * aspectLocal xMax:Float = yMax * aspectReturn Frustum(xMin, xMax, yMin, yMax, near, far)EndFunction Frustum:Matrix(left:Float, right:Float, bottom:Float, top:Float, near:Float, far:Float)Local invRL:Float = 1.0 / (right - left)Local invTB:Float = 1.0 / (top - bottom)Local invFN:Float = 1.0 / (far - near)Local result := New Matrix()result.M11 = 2.0 * near * invRLresult.M12 = 0.0result.M13 = 0.0result.M14 = 0.0result.M21 = 0.0result.M22 = 2.0 * near * invTBresult.M23 = 0.0result.M24 = 0.0result.M31 = (right + left) * invRLresult.M32 = (top + bottom) * invTBresult.M33 = -(far + near) * invFNresult.M34 = -1.0result.M41 = 0.0result.M42 = 0.0result.M43 = -2.0 * far * near * invFNresult.M44 = 0.0Return resultEndEndClass MyWindow Extends GLWindowField vbo:GLuintField ebo:GLuintField shader:GLuintField elementsLength:IntField matrixView:MatrixField matrixProjection:MatrixField matrixViewProjection:MatrixField matrixUniform:IntMethod _LoadShader()EndMethod _LoadVertexBuffer()EndMethod New()' enable OpenGL statesglClearColor(0.1, 0.1, 0.5, 1.0)glEnable(GL_DEPTH_TEST)glEnable(GL_CULL_FACE)' define the shape for a cube'' 7_________6' / / Top vertices' 4________5'' 3_________2' / / Bottom Vertices' 0________1Local vertices := New Float[](-1, -1, -1,1, -1, -1,1, -1, 1,-1, -1, 1,-1, 1, -1,1, 1, -1,1, 1, 1,-1, 1, 1)Local elements := New Int[](4, 7, 6, 6, 5, 4, ' Top0, 1, 2, 2, 3, 0, ' Bottom0, 3, 7, 7, 4, 0, ' Left1, 5, 6, 6, 2, 1, ' Right3, 2, 6, 6, 7, 3, ' Front0, 4, 5, 5, 1, 0) ' BackelementsLength = elements.Length' load shadershader = LoadShader()Print("Program ID: " + shader)Print("Attribute Location: " + glGetAttribLocation(shader, "Position"))' create vertex bufferglGenBuffers(1, Varptr vbo)glBindBuffer(GL_ARRAY_BUFFER, vbo)glBufferData(GL_ARRAY_BUFFER, vertices.Length * 4, vertices.Data, GL_STATIC_DRAW)' create element bufferglGenBuffers(1, Varptr ebo)glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)glBufferData(GL_ELEMENT_ARRAY_BUFFER, elements.Length * 4, elements.Data, GL_STATIC_DRAW)' create matrix stuffmatrixProjection = Matrix.Perspective(Pi / 4.0, Cast<Float>(Width)/Height, 0.5, 100)matrixViewProjection = New MatrixmatrixUniform = glGetUniformLocation(shader, "Matrix")EndMethod OnRender(canvas:mojo.graphics.Canvas) OverrideApp.RequestRender()Super.OnRender(canvas)canvas.DrawText("Monkey2 OpenGL", 10, 10)EndMethod OnRenderGL() Override' update the view projection matrixmatrixView = Matrix.RotateY(App.Millisecs * -0.0005) * Matrix.RotateX(Sin(App.Millisecs*0.0001))matrixView *= Matrix.Translation(0, 0, -5)matrixViewProjection = matrixView * matrixProjection' use the shader and update the matrix uniformglUseProgram(shader)glUniformMatrix4fv(matrixUniform, 1, False, matrixViewProjection.ToArray.Data)' bind the vertex buffer object and enable the vertex attributesglBindBuffer(GL_ARRAY_BUFFER, vbo)glEnableVertexAttribArray(0)glVertexAttribPointer(0, 3, GL_FLOAT, False, 0, Cast<Void Ptr>(0))' bind the element buffer objectglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)' finally do the drawingglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)glDrawElements(GL_TRIANGLES, elementsLength, GL_UNSIGNED_INT, Cast<Int Ptr>(0))EndEndFunction Main()New AppInstanceNew MyWindowApp.Run()EndNovember 23, 2016 at 3:16 pm #5387Nice indeed. Some years Ago I was trying to learn OpenGL so I looked at a few tutorials and started learning it. But with out much luck. At the time I had a project I was working on and didn’t really concentrate on learning it. I did managed to convert a few tutorials from C++ to BlitzMax. When I saw your project, I remembered I had translated a C++ OpenGL cube to Blizmax. I pulled it out and tried to see If I could convert it to Monkey2 GLES but no luck. I don’t know enough about OpenGL to do it. Here is the source and my lousy attempt at converting it to monkey2:
source code with Blitzmax executable:
https://www.dropbox.com/s/x8w95ggaj7tv6bq/texturecube.zip?dl=0
source code Only:
Attachments:
November 29, 2016 at 1:03 am #5476Nice example, I would try to extract as many useful elements as possible.
Another user in the forums created a cool 3D example with Monkey2, it would be a nice idea to hotlink for easy access.
http://monkey2.monkey-x.com/forums/topic/monkey2-opengl-experiments/#post-5310Perhaps I will start doing texture loading as well to create a nice snippet and proceed also adding some further abstractions. Like a Mesh class or a Texture class, without going into heavy implementations.
December 6, 2016 at 9:09 am #5607Would it be possible to use OpenGL 1.x with this system, the reason I am wondering is simply MonkeyX2 could actually replace all BRL products. Max and MX1 run with OpenGL 1.x (IIRC 1.4) which would be cool to have a renderer that would cater for these systems as well.
After looking in Currys recently there were several Laptops that had old Intel chips in them that to be honest would be along those lines?
December 8, 2016 at 9:50 am #5650OpenGL 1.x can be used in C and in other languages (I have used C# OpenTK a lot). In Monkey2 theoretically a wrapper could be written to access the OpenGL 1.x library functions. However doing so, would mean that a tremendous good strategy would exist, it’s a huge investment writing for legacy hardware.
December 8, 2016 at 10:01 am #5651After a long time, since I found a chance today I created this little fancy OpenGL example.
Video:
https://1drv.ms/v/s!AquVr9J7xRcsgXYmcIlKcvFD94LwIt was some code I made a few years ago for OpenTK, now I ported it to Monkey2, I don’t remember where exactly I got the shader from, if you know who made it you can inform me so I can add credits (lots of thanks to the developer if he/she is reading).
Apart from that shader, if you replace the fragment part with any shader from here http://glslsandbox.com/ you could have virtually any GLSL sample available. Keep in mind to the Uniform variables only and some GLSL specifications (there are some differences between GLES and GLSL and you might get errors).
Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111#Import "<mojo>"Using std..Using mojo..Using gles20..Function glLoadProgram:GLuint(vertexSource:String, fragmentSource:String)Local vs := mojo.graphics.glutil.glCompile(GL_VERTEX_SHADER, vertexSource)Local fs := mojo.graphics.glutil. glCompile(GL_FRAGMENT_SHADER, fragmentSource)Local program := glCreateProgram()glAttachShader(program, vs)glAttachShader(program, fs)mojo.graphics.glutil.glLink(program)glDeleteShader(vs)glDeleteShader(fs)Return programEndFunction LoadShader:GLuint()Local vertex:String = "attribute vec3 Position;void main() {gl_Position = vec4(Position, 1);}"Local fragment:String = "uniform float time;uniform vec2 mouse;uniform vec2 resolution;#define PI 3.14159void main( void ){vec2 p = (gl_FragCoord.xy / resolution.xy ) - 0.5;float sx = 0.2 * (p.x + 0.5) * sin(100.0 * p.x * (mouse.x) - 10.0 * time);float dy = 1.0 / (50. * abs(p.y - sx));dy += 1./ (50.0 * length(p - vec2(p.x, 0.)));gl_FragColor = vec4((p.x + 0.5) * dy, 0.5 * dy, dy, 1.0);}"Local program := glLoadProgram(vertex, fragment)glBindAttribLocation(program, 0, "Position")Return programEndClass MyWindow Extends GLWindowField vbo:GLuintField shader:GLuintField canvas:CanvasMethod New()glClearColor(0.1, 0.1, 0.5, 1.0)' load the shadershader = LoadShader()Print("Program ID: " + shader)Print("Attribute Location ~qPosition~q: " + glGetAttribLocation(shader, "Position"))Print("Uniform Location ~qtime~q: " + glGetUniformLocation(shader, "time"))Print("Uniform Location ~qmouse~q: " + glGetUniformLocation(shader, "mouse"))Print("Uniform Location ~qresolution~q: " + glGetUniformLocation(shader, "resolution"))' define a quad shape consisted out of two triangles: 0 1 2 , 2 3 0' 3-------2' | . |' | . |' | . |' 0-------1Local vertices:Float[] = New Float[](-1,-1,0, 1,-1,0, 1,1,0, -1,-1,0, 1,1,0, -1,1,0)' create the vertex bufferglGenBuffers(1, Varptr vbo)glBindBuffer(GL_ARRAY_BUFFER, vbo)glBufferData(GL_ARRAY_BUFFER, vertices.Length * 4, vertices.Data, GL_DYNAMIC_DRAW)EndMethod OnRender(canvas:mojo.graphics.Canvas) OverrideApp.RequestRender()Super.OnRender(canvas)canvas.DrawText("Monkey2 OpenGL Test", 10, 1 * 20)canvas.DrawText("Mouse Location: " + MouseLocation.X, 10, 2 * 20, 0, 0)EndMethod OnRenderGL() Override' clear the screenglClear(GL_COLOR_BUFFER_BIT)' load the shader and update uniformsglUseProgram(shader)glUniform1f(0, Millisecs() * 0.001)glUniform2f(1, Cast<Float>(MouseLocation.X / 500.0), Cast<Float>(MouseLocation.Y))glUniform2f(2, Cast<Float>(Width), Cast<Float>(Height))' bind the buffer, enable vertex attributesglBindBuffer(GL_ARRAY_BUFFER, vbo)glEnableVertexAttribArray(0)glVertexAttribPointer(0, 3, GL_FLOAT, False, 0, Cast<Void Ptr>(0))' draw the vertex dataglDrawArrays(GL_TRIANGLES, 0, 6)EndEndFunction Main()New AppInstanceNew MyWindowApp.Run()EndDecember 8, 2016 at 10:24 am #5654very interesting
will look into 1.x GL as it would be a nice exercise in working the grey cells
December 9, 2016 at 12:19 am #5667Hi EdzUp, you could jump straight into action and try to do some tutorials. You could use Blitzmax or C++ according to what you feel more comfortable with.
In the exact example, to draw 2 triangles ala GL1 I would simply use these statements: glBegin, glVertex, glEnd. This is the core of all the rendering pipeline (the fixed function pipeline). If you can draw let’s say a triangle, or a colored cube, you can draw and navigate inside a humongous level created with Blender. On the other hand the modern shader based pipeline is much more tricky to get started and understand. There is a need for the perfect combination of these elements before you draw anything: shader, vertex buffer, vertex attributes.
December 9, 2016 at 12:41 pm #5681I’ve been coding for some thirty odd years (since ’81
). I would normally use glDrawElements to render stuff as glBegin etc is convoluted for rendering more complex stuff
 - 
		AuthorPosts
 
You must be logged in to reply to this topic.