A Implementation of Essential OpenGL Examples Using Duell Tool

Bachelor Arbeit

Alexis Iakovenko-Marinitch Fachbereich Mathematik und Informatik Institut f¨urInformatik Freie Universit¨atBerlin, Deutschland July 29, 2016

Gutachter: Prof. Dr. Tim Landgraf und Dipl. Inf. Till Zoppke Betreuer: Dipl. Inf. Till Zoppke Externer Betreuer: Sven Otto, GameDuell GmbH

Selbstst¨andigkeitserkl¨arung

Hiermit best¨atigeich, dass ich die vorliegende Ausarbeitung mit dem Titel A Haxe Implementation of Essential OpenGL Examples Using Duell Tool selbstst¨andigund ohne unerlaubte Hilfe angefertigt habe. Ich versichere, dass ich ausschließlich die angegebenen Quellen in Anspruch genom- men habe.

Statement of Authorship

I declare that this thesis entitled A Haxe Implementation of Essential OpenGL Ex- amples Using Duell Tool is the result of my own research except as cited in the references. The thesis has not been accepted for any degree and is not concurrently submitted in candidature of any other degree. Except where acknowledged in the customary manner, the material presented in this thesis is, to the best of my knowl- edge, original and has not been submitted in whole or part for a degree in any university.

Alexis Iakovenko-Marinitch Berlin, July 29, 2016

Abstract

With the augmenting variety of platforms on the market, supporting as many of them became an inevitable obstacle to confront in order to reach as many users as possible. Platforms support different native languages, such as for Android or Objective-C for iOS. The most straight-forward way to support both of these platforms is to produce native codes for each of them, which is greatly cost and time consuming. There are several tools to avoid programming in the native languages of targeted platforms and to achieve cross-platform programming, but using them generally results in a performance loss. For video games, such a loss can be critical, which is why native programming is favored in order to get the best performance possible from the targeted platforms. In this paper we investigate the productivity and efficiency of cross-platform pro- gramming with Haxe by reimplementing essential OpenGL features while targeting two platforms at the same time, Android and Windows. The result of our research showed that, while the consumed time in programming cost trivially less effort than native coding on each of the different platforms, Haxe did not engender any significant performance loss. To deepen this investigation, expanding the scenes’ complexity or making an ac- tual game would put the devices to test in more extreme conditions.

Contents

1 Introduction 1 1.1 Motivation ...... 1 1.2 Problem ...... 2 1.3 Plan ...... 3

2 Haxe and Duell Tool 5 2.1 Haxe ...... 5 2.2 Duell Tool ...... 6 2.2.1 Running a project with Duell ...... 6

3 OpenGL 7 3.1 Introduction ...... 7 3.2 OpenGL ES ...... 7 3.3 The flow of an OpenGL program ...... 8 3.3.1 Initialization ...... 8 3.3.2 Updating and rendering cycle ...... 9 3.3.3 Destroying ...... 9 3.4 Shading ...... 9 3.4.1 Vertex Shader ...... 9 3.4.2 Fragment Shader ...... 10 3.5 OpenGL in Haxe with DuellKit ...... 10

4 The Examples 13 4.1 Hello World! ...... 13 4.1.1 The triangle ...... 14 4.1.2 The colors ...... 14 4.2 3D scene ...... 15 4.2.1 The 3D Objects ...... 15 4.2.2 The Lighting ...... 16 4.2.3 The Texturing ...... 16 4.3 Text ...... 16 4.3.1 Bitmap Font Rendering ...... 18

5 Implementation 19 5.1 Global structure ...... 19 5.2 Triangle ...... 19 5.2.1 Vertex and Index buffers ...... 19

7 5.2.2 Rendering ...... 20 5.3 3D model and lighting ...... 22 5.3.1 .Obj Format ...... 22 5.3.2 Model, view and projection matrices ...... 26 5.3.3 Texturing ...... 29 5.3.4 Lighting ...... 30 5.3.5 Final output ...... 34 5.4 Text ...... 34 5.4.1 Texture map ...... 35 5.4.2 Texture coordinates ...... 35 5.4.3 Background ...... 37 5.4.4 Final output ...... 38

6 Testing and evaluation 39 6.1 Triangle ...... 39 6.1.1 Features ...... 39 6.1.2 Performances ...... 40 6.1.3 Conclusion ...... 40 6.2 3D model and lighting ...... 40 6.2.1 Features ...... 41 6.2.2 Performances ...... 41 6.2.3 Conclusion ...... 41 6.3 Text ...... 41 6.3.1 Features ...... 41 6.3.2 Performances ...... 42 6.3.3 Conclusion ...... 42

7 Summing up and perspectives 43

Bibliography 45 List of Figures

3.1 In green the Index Buffer’s content. In blue the vertices coordinates.9

4.1 The first PowerVR example ...... 13 4.2 The second PowerVR example ...... 15 4.3 The third PowerVR example ...... 16 4.4 Parameters of a single character ...... 17 4.5 Texture map for a geometry of quads ...... 18

5.1 Result of the first example ...... 22 5.2 The UV mapping of a cube in Blender ...... 24 5.3 The UV map for a human ...... 24 5.4 The looks of the texture and the final model ...... 25 5.5 Three teapots set in World Space ...... 26 5.6 On the Left two teapots and a camera in World Space; On the right ev- erything is transformed into View Space (World Space is represented only to help visualize the transformation) ...... 27 5.7 Perspective Projection ...... 28 5.8 A lit and an unlit sphere ...... 30 5.9 .obj 3D object textured and lit ...... 34 5.10 Texture atlas ...... 35 5.11 Tile, Tile width, letter width ...... 36 5.12 Texture for the background ...... 37 5.13 Bitmap Text output ...... 38

6.1 Comparison between example 1 and its implementation ...... 39 6.2 Comparison between example 2 and its implementation ...... 40 6.3 Comparison between example 3 and its implementation ...... 42

Chapter 1 Introduction

A graphic engine is a part of a program responsible for the rendering of 2D or of an application[1]. It can achieve several goals. Most of the time, a graphic engine facilitates the work of a developer, so that he can focus on the actual application’s functionalities. For example, a game developer should not burden himself with the rendering technology behind his game, but concentrate on the game mechanics, logics and implementation instead[2]. But rendering something on the screen is not enough. A graphic engine must fulfill specific requirements, depending on the application a developer wants to make. To cover the majority of their users’ needs and allow them to be used for different projects and contexts, graphic engines should be easy to use and offer a large variety of functionalities and tools. Some noteworthy technologies are: texturing, loading 3D models, shaders, lighting, shadows, transparency, particle system, fog, reflection, text/UI rendering. . . [3, 4, 5] However offering these tools is not the only challenge a graphic engine must overcome. In addition to producing pretty images on the screen, the rendering process must happen efficiently. For our use case, games, the rendering happens in real-time and must be achieved in fractions of seconds so that the animations and game mechanics appear fluid to the player, giving him the best experience possible. To that effect, constructing a graphic engine requires an enormous amount of work and versatile expertises in the computer science sector.

1.1 Motivation

Because of the never ending improvements of graphics processing units, 3D is not only a standard for PCs but also for mobiles[6, 7]. There are several different popular platforms[8, 9] on the market which make it profitable to create multi-platform code and develop softwares which will work on as many devices as possible. More and more 2D and 3D cross-platform games and graphic engines are being created and are arousing important interest around them[10]. However adding support for an additional platform can require a lot more programming hours and severe additional costs. There are many reasons for this. Different platforms require programming in different languages: Java for Android, Objective-C/Swift for iOS and so on[11, 12]. This means programming the same features multiple times and the mastering of different programming languages is necessary. To resolve this problem, there exist lots of tools which help the developer with one code to create software working

1 Chapter 1 Introduction on multiple devices[13, 14]. Generally those tools reduce the programming time drastically, but show significant drops in performance. The main goal of this thesis is to show that using multi-platform tools is a viable option for developing a cross- platform graphic engine.

1.2 Problem

In order to investigate the viability of programming a cross-platform graphic engine with multi-platform tools, we decided to approach a company that is using such tools everyday. GameDuell GmbH is a company developing video games accross multiple plat- forms, such as iOS, Android, Facebook and web [15]. With the aim of solving the problem of cross-platform developing, GameDuell is using a cross-platform pro- gramming language called Haxe [16]. The company published succesful 2D cross- platform games [15, 17] coded with Haxe, using a tool they made to facilitate the cross-platform development, the Duell Tool, which provides plugins for iOS, Android, Flash and HTML5. They are very confident with the resulting productiv- ity when using Haxe and the Duell Tool for 2D games, yet for the third dimension, they are still in the research phase. With the purpose of contributing to their research, we will use the Haxe multi- platform combined with the Duell Tool and show that the gain in required development time of a graphic engine’s fundamental 3D features significantly outweighs the loss of performance resulting from the multi-platform programming. PowerVR is a tool based on OpenGL which facilitates the development of graphic applications. The documentation of PowerVR provides a precise list of 3D ex- amples with fundamental OpenGL features, which were already implemented for Android and Windows using their respective native languages. Since OpenGL is multi-platform and an industry’s standard [18], we will base ourselves on this list. We will reimplement the 3D examples in Haxe, producing a single code which triv- ially requires less effort in programming time. For a successful outcome we expect to see a similar image on the screen as in the examples and we accept a slight, insignificant drop in framerate. To compare our results with the ones of PowerVR, we will target Android and HTML5 for Windows. The result of our experiment will prove the development of multi-platform 3D functionalities to be cost-efficient with Haxe and the Duell Tool in term of hours of programming and give the groundwork to developers of a documented open- cross-platform graphic engine. This work will also help to evaluate the realisation of some tasks.

2 1.3 Plan

1.3 Plan

First we will present the Haxe programming language and a useful tool accompany- ing it: the Duell Tool. Then we will introduce the OpenGL libraries and its relevant functionalities. After that we will describe the 3D examples and features in details as well as the OpenGL theory behind them. This will lead to the actual implementa- tion in Haxe and OpenGL of these 3D features which we will explain and document. At last we will analyze and interpret the results of our implementation by testing and evaluating these on different devices.

3 Chapter 1 Introduction

4 Chapter 2 Haxe and Duell Tool

In this chapter we will introduce the Haxe programming language and the Duell tool accompanying it.

2.1 Haxe

Haxe is an open-source multi-platform programming language. It is a high level strictly typed programming language and is used by the Haxe to generate native code on targeted platforms like Javascript, Flash, C++ and so on. The syntax is similar to Java or C++ which makes it accessible and fast to learn. It is also an object-oriented language. The Haxe programming language was designed so that it adapts to the different platform-dependent functionalities and assures an efficient cross platform development. Haxe was used for example to create the kha-Engine, a cross-platform .

Code samples In Haxe, this is how you declare a variable: var myVariable: Int = 0;

Declaring a class goes as follows: class OpenGLTest { public f u n c t i o n new() { resetOpenGLState() ; onCreate() ; }

public function resetOpenGLState(?a: Int): Void { } }

5 Chapter 2 Haxe and Duell Tool

The new() function is called at the OpenGLTest Object’s instantiation. Since it acts like a constructor, it does not have any return type. resetOpenGLState() is a standard method. It has one parameter a of type Int. The ? sign before means that this parameter is optional. We can see that the return type Void is written at the end of the signature. Different examples and comparaison between Java and Haxe code can be found inside the Haxe documentation1.

2.2 Duell Tool

The Duell Tool is a command line tool developed from scratch by GameDuell[16]. It allows the developer to easily install libraries, build code and applications on different devices[19]. The Duell Tool recognizes the different needed plugins of a Haxe project and automatically downloads them.

2.2.1 Running a project with Duell Instructions for the setup can be found on the Duell’s GitHub2. To run a project on the browser with the Duell Tool, executing the following command line in the project folder is all that is required: duell build −browser

First the Duell Tool will ask us if we want to do any update and, if some libraries are missing, ask us if we are willing to download the necessary plugins. When everything is updated and fine, it will launch the default browser (for us Chrome) and run our OpenGL application. To run the application on Android, the command is similar: duell build android

If the Android SDK hasn’t been installed before, it will inform us with the neces- sary steps to make it so.

1Haxe documentation: http://old.haxe.org/doc/java/externs, accessed: 27.07.2016 2Duell GitHub: https://github.com/gameduell/duell, accessed: 27.07.2016

6 Chapter 3 OpenGL

3.1 Introduction

OpenGL (Open Graphics ) is a cross-platform graphics application program- ming interface (API) for real-time 2D and 3D rendering launched in 1992 by Silicon Graphics, an American high-performance computing manufacturer producing com- puter hardware and software. OpenGL allows the program to declare the geometric shape of an object as a set of points, triangles, polygons and textures and then produces an image to the screen by computing view projections, distances, camera properties and optional post-rendering processes. OpenGL became the industry’s most widely used API for 2D and 3D graphics applications [20] and is supported by a large variety of platforms.

3.2 OpenGL ES

OpenGL ES (Open Graphics Library for Embedded Systems) is a specification by Khronos Group derived from OpenGL defining a cross-language and multi-platform API for 3D graphics applications development. OpenGL ES is designed for embed- ded systems like smartphones, tablets and consoles and is basically a simplification of OpenGL with lighter memory and central processing unit (CPU) cost. OpenGL ES is lighter and support more platforms which are likely to have less Random-access memory (RAM), so many functionalities of OpenGL were left out. For the sake of CPUs not able to compute floating operations, OpenGL ES includes profiles for both floating-point and fixed-point systems. Mobile developers must ensure that their software properly functions on different devices with different hardwares. It is necessary for them to be able to pass on their needs to OpenGL ES and let it make internal choices. It is also important that the rendering is controlled the same way. There are five main versions of OpenGL ES. For this experience, we will use OpenGL ES 2.0 which was released in 2007 and which is based on OpenGL 2.0. One of the most noticeable aspect of this version is the use of a shader system based on a variation of the GLSL language. These shaders will be used to produce lighting and render textures in our scenes. The next versions of OpenGL ES (3.0, 3.1 and

7 Chapter 3 OpenGL

Vulkan) support shader as well, but because of their relatively recent release dates, they currently aren’t fully supported by Haxe, so we won’t look into them in this thesis.

3.3 The flow of an OpenGL program

In this section we will look into the different parts of an OpenGL program. The structure is similar to those of most applications. It contains an initialization, a main loop and an ending phase.

3.3.1 Initialization

Before starting an OpenGL program, OpenGL must be initialized. This process permits the developer to set some parameters that won’t be changed during the ex- ecution, such as the camera’s properties, the allowed rendering properties or simply the background color. Before coming to the main loop, ideally all geometric shapes of the to-be rendereed scene must already be calculated and saved, using Vertex Buffers and Index Buffers.

Vertex Buffer

The Vertex Buffer stores vertices’ datas from a geometric shape and will be passed on to our draw call later. A single vertex contains the informations of a single point in space, such as its position coordinates, colors, texture coordinates or normals.

Index Buffer

In order to create triangles, we need to link the Vertex Buffer’s points between them. To accomplish this, the vertices’ indices are saved in the Index Buffer by sequentially appending three linked vertices’ indices forming a triangle (Fig. 3.1).

8 3.4 Shading

Figure 3.1: In green the Index Buffer’s content. In blue the vertices coordinates.

The Index Buffer is also to be passed to the draw call.

3.3.2 Updating and rendering cycle Before rendering a scene, miscellaneous calculations can be made. In a game for example, the positions and rotations of objects must be determined through the physic engine. Also the rules of the game have to be updated mostly each frame. After the updating is done, the drawing of the previous frame must be cleared by calling the GL.clear(...) function. Then comes the shaders’ linking which we will see in the next section. Finally we can bind our Vertex Buffer to OpenGL and call our draw function to render geometric shapes stored in the binded Vertex Buffer.

3.3.3 Destroying At the end of an OpenGL applications, or when leaving a scene, the shaders, buffers and loaded textures of the current scene must be deleted to avoid any memory leak.

3.4 Shading

To display anything in OpenGL ES 2.0 we have to pass our vertex informations to a shader. Generally, a 3D shader is a program acting on 3D geometry to produce special effects. In our case, we are interested in two types of shaders: the vertex shader and fragment shader. A shader needs to be compiled at the beginning of an application and linked at rendering time to be applied.

3.4.1 Vertex Shader A vertex shader acts on each vertex of a given geometric shape. It manipulates different parameters of a vertex like its position, shape, color or texture. One of the

9 Chapter 3 OpenGL most basic goals of a vertex shader is to transform the 3D positions of a vertex to the 2D coordinate system of our screen display. attribute highp vec4 a P o s i t i o n ; attribute lowp vec4 a Color ; varying lowp vec4 v Color ; void main ( ) { g l P o s i t i o n = a P o s i t i o n ; v Color = a Color ; }

This shader programs takes the position (a Position) and color (a Color) infor- mations of our vertices that we will pass in and applies them to OpenGL. The highp and lowp keywords define the level (high or low) of precision for our attributes. At- tribute variables (here a Position and a Color) come from the vertex buffers we created. Varying variables (here v Color) will be passed to the fragment shader that we will see in the next section. This vertex shader is only enough to draw colored 2D geometric shapes on the screen. We will describe how to project 3D shapes with shaders in another chapter.

3.4.2 Fragment Shader A fragment shader, also called pixel shader, acts on a geometric shape on each pixel color value. It can produces interesting effects like lighting, bumpmap, shadows. . . Here is a simple fragment shader that applies the color passed from the vertex shader to OpenGL. varying lowp vec4 v Color ; void main ( ) { gl FragColor = v Color ; }

We will see in another chapter how to use fragment shaders to produce lighting effects.

3.5 OpenGL in Haxe with DuellKit

To make calls to the OpenGL library, we use the prefix GL. For example: GL. enable(GLDefines .BLEND) ; //Enables blending

10 3.5 OpenGL in Haxe with DuellKit

In this line of code we can also see that all OpenGL constants are defined with the namespace GLDefines.

11 Chapter 3 OpenGL

12 Chapter 4 The Examples

In this chapter we will analyze the examples provided by PowerVR and decompose them into different functionalities. That way we will be able to figure out what technologies and techniques we will use for these functionalities and what challenges we may encounter during their implementation.

4.1 Hello World!

Figure 4.1: The first PowerVR example

13 Chapter 4 The Examples

This first example (Fig. 4.1) is a typical ”Hello World!” application in 3D-programming. Displaying a triangle on the screen is the simplest thing a developer can achieve in 3D without showing absolutely nothing. While the result of this ”Hello World!” program may not look impressive, it has a great meaning for us. By implementing this example, we will get to know the basics of OpenGL which are essential to 3D- programming. Also, if you know how to draw one triangle, you have the potential to draw as many as you want, which means: if you can render one triangle, you can build a world.

4.1.1 The triangle

To display this triangle we will have to make the use of Vertex Buffers. To define the shape and position of this triangle, we will define three vertices (one for each point) with the correct position coordinates. The vertex buffer is then used by OpenGL to render the scene.

4.1.2 The colors

In this scene we can see two different colors. The strong cyan in the background and pale yellow in the triangle. The one in the background is defined through OpenGL when clearing the scene before each rendering. The one in the triangle is to be defined within the Vertex Buffer.

Because of the simplicity of this scene, we can expect to get a very similar result after our implementation.

14 4.2 3D scene

4.2 3D scene

Figure 4.2: The second PowerVR example

This scene (Fig. 4.2) looks and is much more complicated that the previous one. Here we can see 3D objects which are textured and shadows on them which are generated by a lighting effect. This example will prove much more challenging than the first one.

4.2.1 The 3D Objects We can’t see this in the screenshot but when launching the application the dwarf is animated. He is rotating around his arms, which are rotating as well with the hands as rotation axis. The facts that the body and the arms are rotating with different axis implies that there are bone datas stored in the 3D model as well. PowerVR is using their own library format .pod to store the whole scene. The .pod format contains many different datas in a binary file: The vertices, texture coordinates, normals, bones and rigging, animations, lighting... We cannot cover them all in this thesis and for simplicity reasons we will not implement animations in our scene. Furthermore we chose to use another simpler format for our implementation: the .obj format.

15 Chapter 4 The Examples

4.2.2 The Lighting To make the lighting effects we will make the use of shaders. Also we will have to get to know the different types of lighting and the meaning of normals.

4.2.3 The Texturing To apply a texture on our mesh we’ll need to load a texture, which is a 2D im- age. When rendering we’ll apply it to our mesh via OpenGL and pass the texture coordinates datas as well.

4.3 Text

Figure 4.3: The third PowerVR example

In this third example (Fig. 4.3) we can see 2D text on the top left and bottom right corner of the window. It is rendered on top of the scene and is working like an UI (). The text in the middle is defiling like in the Star Wars introduction, towards the top of the screen with a sense of depth. To be more precise, the text in the middle is actually in the 3D scene, which we’ll have to handle differently from

16 4.3 Text the UI text. As the text sequence states, the library making this output supports UTF8 sequences for font rendering. OpenGL has no built in functions to render text[21]. There are libraries to render font for Haxe but they only support programs based on OpenFL1 or using the ogl library2, which is not our case. This means we will need to make our own font rendering system using only OpenGL.

Figure 4.4: Parameters of a single character

Dealing with text is much more complicated than newcomers might think. All characters have different parameters, as shown in the figure 4.4. To produce some- thing acceptable, we must consider them all and calculate different settings for dif- ferent contexts. Also, to represent all language in the world, tens of thousands of characters need to be supported. We have to consider as well that text could be written from the right to left, from top to bottom... In most cases, complex techniques to polish the quality rendering are needed to get a result as clean as possible. A famous paper from Valve3 explains one they develop for their well know engine Source4.

1OpenFL: http://lib.haxe.org/p/bitmapFont/, accessed: 21.06.2016 2ogl: http://lib.haxe.org/p/gl3font/, accessed: 21.06.2016 3Improved Alpha-Tested Magnification for Vector Textures and Special Effects: http: //www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification. pdf 4Source Engine: http://www.moddb.com/engines/source

17 Chapter 4 The Examples

To simplify our needs, we will look at the Bitmap Font rendering technique. Though ”2D texture-mapped fonts suffer from several drawbacks, including poor quality and aliasing”, they do provide a quick and portable way to render text[21]. Since our goal is not to produce the best font rendering system in the market, we will use this classical rendering technique which doesn’t require any external library and is very common in OpenGL projects.

4.3.1 Bitmap Font Rendering The principle of the Bitmap Font Rendering technique is to use a texture map and apply the right texture coordinates to a geometry of quads (Fig. 4.5). To make the output look acceptable it is recommended to define the width for each character.

Figure 4.5: Texture map for a geometry of quads

We will go more in depth into this technique in the next chapter.

18 Chapter 5 Implementation

In this chapter we will review in detail the OpenGL aspects and functions behind every one of the 3D examples’ implementation.

5.1 Global structure

To help us with the implementation, Sven Otto1, lead Software Developer at Game- Duell, provided us with a template in Haxe for OpenGL creations. The template is open-source and is available on GitHub2. The Main class contains the list of examples that will be executed. It is controlling inputs to change between scenes. The change happens by swiping with the mouse on the computer (finger on the phone) to the right or to the left. The input library from Haxelib takes care of the click and touch detection. All examples have their own class, inheriting the OpenGLTest mother class. The OpenGLTest class has a few standard methods like (re)initializing the OpenGL state, clearing the scene, adding and removing the scene from the DuellKit framework.

5.2 Triangle

The first example we want to implement is one of the simplest there is: a triangle. The triangle acts like a “Hello World!” for developing in 3D. To create our triangle, we will need a vertex shader to define the vertex positions and a fragment shader to define the color of the triangle. We will need to use a vertex buffer in order to pass the coordinates and colors to the shaders. Since our triangle will be displayed on a 2D coordinate system, we do not need to think about projection yet and we can use our vertex shader from the previous chapter. Since we only need to apply color to the triangle, the previous fragment shader will suffice as well. First, let’s create our vertex and index buffers.

5.2.1 Vertex and Index buffers

1Sven Otto: http://www.osa.fu-berlin.de/informatik_msc/perspektiven/ softwareentwickler/index. 2Haxe OpenGL-Tutorial: https://github.com/nensanders/opengl-tutorial

19 Chapter 5 Implementation

var vertexBufferValues: Array = [ −0.5, 0.0, 0.0, 1.0, 1.0, 1.0, 0.66, 1.0, // v e r t e x 0 0, 0.8, 0.0, 1.0, 1.0, 1.0, 0.66, 1.0, // v e r t e x 1 0.5, 0.0, 0.0, 1.0, 1.0, 1.0, 0.66, 1.0]; // v e r t e x 2

This will be the vertex buffer of our triangle. The first four values of a vertex are the x, y, z and w coordinates. The four next are the r, g, b and a values of the color. We need to pass this buffer to an OpenGL buffer and bind it. vertexBufferData.writeFloatArray(vertexBufferValues , DataType. DataTypeFloat32) ; vertexBufferData.offset = 0;

vertexBuffer = GL.createBuffer(); //Creates OpenGL buffer GL. bindBuffer(GLDefines .ARRAY BUFFER, vertexBuffer); GL. bufferData(GLDefines .ARRAY BUFFER, vertexBufferData , GLDefines .STATIC DRAW) ; GL. bindBuffer(GLDefines .ARRAY BUFFER, GL. nullBuffer) ;

With the same principle, we attribute our index buffer to an OpenGL buffer. These are our indices: var indexBufferValues: Array = [ 0 , 1 , 2 ] ;

Now let’s see how we render all this to our screen.

5.2.2 Rendering Before every rendering frame of a scene, we need to tell OpenGL to clear the ren- dering of the previous frame with this command: GL. clear (GLDefines.COLOR BUFFER BIT) ;

Then we use our shader programs. GL.useProgram(shaderProgram) ;

We bind our vertex and index buffer GL. bindBuffer(GLDefines .ARRAY BUFFER, vertexBuffer); GL. bindBuffer (GLDefines .ELEMENT ARRAY BUFFER, indexBuffer);

And only enable the necessary attribute arrays, in our case for position and color. GL.enableVertexAttribArray(positionAttributeIndex); GL.enableVertexAttribArray(colorAttributeIndex);

GL. disableVertexAttribArray(2) ;

20 5.2 Triangle

GL. disableVertexAttribArray(3) ; GL. disableVertexAttribArray(4) ; GL. disableVertexAttribArray(5) ; GL. disableVertexAttribArray(6) ; GL. disableVertexAttribArray(7) ;

We allocate enough space for attribute pointers:

var : Int = positionAttributeCount ∗ sizeOfFloat + colorAttributeCount ∗ sizeOfFloat;

var attributeOffset: Int = 0; GL. vertexAttribPointer(positionAttributeIndex , positionAttributeCount , GLDefines.FLOAT, false , s t r i d e , attributeOffset);

attributeOffset = positionAttributeCount ∗ sizeOfFloat; GL. vertexAttribPointer(colorAttributeIndex , colorAttributeCount , GLDefines.FLOAT, false , s t r i d e , attributeOffset);

And finally call the draw operation:

var indexOffset: Int = 0; GL. drawElements(GLDefines .TRIANGLES, indexCount , GLDefines .UNSIGNED SHORT, indexOffset);

Not to forget, we bind the buffers and program to null to set it to the initial state:

GL. bindBuffer(GLDefines .ARRAY BUFFER, GL. nullBuffer) ; GL. bindBuffer (GLDefines .ELEMENT ARRAY BUFFER, GL. nullBuffer); GL.useProgram(GL. nullProgram) ;

The figure 5.1 shows the final output:

21 Chapter 5 Implementation

Figure 5.1: Result of the first example

The making of this example is very simple but serves as a “Hello World!” for our application. It will also be used as the base for our next examples which will be using the same methods we just saw.

5.3 3D model and lighting

This example is more interesting, since we finally display 3D geometric shapes on the screen. And not any shape, a 3D model loaded from a .obj file. Here we will also cover texturing and add some lighting effect to our object.

5.3.1 .Obj Format A Wavefront .obj is a file format developed by Wavefront Technologies. It contains informations of a 3D model created with 3D modelling software like Blender, Maya, 3Dmax... It contains informations about its vertices, face indexing, normals and texture coordinates. To get those informations, we need to read the .obj as we would read a text file and parse these datas accordingly to a specific schema. In this section we will analyze the structure of a .obj file, find what informations are relevant to us and how to parse them.

Vertex positions

The coordinates of a vertex is listed after the keyword v.

22 5.3 3D model and lighting

v 1.000000 −1.000000 −1.000000 v 1.000000 −1.000000 1.000000 v −1.000000 −1.000000 1.000000 v −1.000000 −1.000000 −1.000000 v 1.000000 1.000000 −1.000000 v 1.000000 1.000000 1.000001 v −1.000000 1.000000 1.000000 v −1.000000 1.000000 −1.000000

These lines, for example, define the vertices’ X, Y and Z positions of a cube.

Vertex normals

In 3D, the normal of a face is the vector orthogonal to it. When rendering a scene with lighting effects, the color itensity of a triangle is defined, amongst other things, by the position of the light source and the way it bounces on the polygon. This makes normals very important to 3D rendering to calculate the lighting effects on 3D objects. Similarly to the positions, normals are defined after the keyword vn".

vn 0.000000 −1.000000 0.000000 vn 0.000000 1.000000 0.000000 vn 1.000000 0.000000 0.000000 vn −0.000000 −0.000000 1.000000 vn −1.000000 −0.000000 −0.000000 vn 0.000000 0.000000 −1.000000

Since there should be a normal defined for each triangle, we can expect the same amount of normals as vertex positions.

Texture coordinates

To apply textures on a 3D shape in an optimal way, we should avoid loading several images and only use one. But this means we have to define which parts of the image correspond to which part of the object. For example if we have a 3D model of a house, there will be a part of the image for the tiles of the roof, a part of the image for a window, and maybe a part of the image for the door. All these parts are saved on a single texture and have specific 2D positions on this texture. UV coordinates link these 2D positions to a 3D vertex, so that we can apply the right parts of the texture on the right vertices.

23 Chapter 5 Implementation

Figure 5.2: The UV mapping of a cube in Blender

For a simple case like a cube (Fig. 5.2), this method might seem trivial. There are cases where UV mapping can be a lot more complex, like those of creatures or human beings (Fig. 5.3 and 5.4).

Figure 5.3: The UV map for a human

24 5.3 3D model and lighting

Figure 5.4: The looks of the texture and the final model

Similarly to the positions and normals, the UV coordinates are defined after the keyword vt. vt 0.500 1 vt 0.500 0 ...

Unlike the positions and normals, the UV coordinates only contain 2 dimensions, X, Y, since it corresponds to the positioning of a vertex on a 2D image.

Indexing Finally the last part of a .obj file contains the list of our faces with the id of the co