[OpenGL Part 2] Vertexes, VBOs and VAOs

Introduction


OpenGL is complicated. Whereas SDL2 is relatively small with a few objects and functions, OpenGL is huge with lots of different elements. Fortunately it’s also very well documented. And, as we saw in the previous part, it’s not hard to get something on the screen ( thanks to SDL2 )

In this part, we’ll first take a look at vertexes before we look at how to draw a simple object.

Drawing an object in 3D


Now that we’ll be working in 3D, we need to do things a little differently. In SDL2 we only used the position and size of each object. Each object was basically just an image that we drew on the screen and moved around. We never told SDL2 anything about how it looked, how big it was, etc. SDL2 simply took a texture and put it on the screen.

But in OpenGL we’ll be rendering an except shape so that we can view it from any angle, which would be almost impossible in SDL2. It also enables us to color it, apply textures and change the lighting in code. We do this by defining a mesh like you see above. It’s all just a bunch of points in 3D space defined by vectors. A vector in this context is just a simple mathematical unit that defines a position. We’ll be using 3D ones, so they’ll each have three values ( x, y, z ) When we have these vectors we can tell OpenGL the exact shape of an object, and then we can draw it in 3D using OpenGL

Vertex vs vector


In OpenGL we use something called a vertex. A vertex is a lot like a vector in that in represents a single point. The difference between a vertex and a vector is that a vector is just the position of a single point. But a vertex contains the vector of the point and it can also hold other things at the same time, like the color of that point, and other things we’ll come to in a later part. So, in essence, a vertex contains everything we need to draw one of these points. And when we draw an object, like a dice, we need to give OpenGL one vertex for each point.

The dice about has 8 vertexes :

  • left, top, front
  • left, bottom, front
  • right, bottom, front
  • right, top, front
  • left, top, back
  • left, bottom, back
  • right, bottom, back
  • right, top, back

Each part of the vertex is usually referred to as an attribute. For instance the vectors/positions is one attribute, colors is another attribute and so on…

OpenGL programming method


In contrast to other APIs / libraries, OpenGL is not object oriented. There’s really no objects at all, mostly because a lot of the vertex data is stored on the GPU. So instead you need to handle the models, textures, etc on our own.

OpenGL does, however, have some notion of object. But instead of being a concrete struct like SDL_Texture as we have in SDL2, it’s just an ID to a type of data. The only way to refer to this data through OpenGL is by using ID’s. This is mostly because the objects are stored on the GPU, and you want to keep them there without transferring/streaming them back and forth.

So let’s take a look at two of the most important objects we’ll be using in OpenGL.

VBO – Vertex Buffer Object


The VBO(Vertex Buffer Object) is one of the “objects” of OpenGL. It holds all of a single vertex attributes for an object. Not all vertexes, but all vertexes of one type, like all positions or all colors. So you’ll end up with one VBO for positions, one VBO for colors, etc…

In order to create a VBO, we first need some data. So let’s take a collection of vectors and put them in a VBO. To keep things simple, we’ll just use a square. Our square has four positions, one of each corner. Let’s create a simple array containing all of these points.

That’s the simple part. Now we need to tell OpenGL to create the actual VBO for us. This requires a few steps so let’s look at them one at the time.

glGenBuffers


This function generates a VBO for us, so that we can store our vertex attribute into it. It also gives us back an ID for this buffer so that we can use it for referring to this VBO later.

Note : GLsizei is simply just an unsigned integer like uint32_t and GLuint is just a signed integer like int32_t

Parameters :

  • GLsizei n – the number of buffer we want. One per attribute, so we’ll keep it at 1. But if we were going to add colors, we’d use 2.
  • GLuint* buffers – this is were we get the ID’s of our buffers back as an array.

So now, let’s generate our VBOs :

The second line creates an array for holding our ID’s and the third line tells OpenGL to allocate countVBOs VBOs for us. Since arrays works a lot like pointers in C++, we can just pass in vbo, and OpenGL will automatically give us as many IDs as we ask for.

Now we have our VBO and it has the ID stored in vbo[0]

glBindBuffer


This function is deceptively simple, so it’s important to understand it because it can lead to some confusion. And if you call it at the wrong time or don’t call it, your application will most likely crash!

The function simply sets a buffer as the current buffer. We use it to tell OpenGL that this is the buffer we are working on now.

Parameters :

  • GLenum target target – the type of buffer we want this to be. In our case, it’s GL_ARRAY_BUFFER
  • GLuint buffer – the ID of the buffer we want to bind / set as active

You might have notices the new type, GLenum. This is just a huge enum that contains all the predefined flags in OpenGL. These flags are used by a lot of different functions for a lot of different things, so I’ll just explain them as they come.

GL_ARRAY_BUFFER is the value we use for vertex data like positions and colors.

Using it is really simple :

glBufferData


Now that we have bound the buffer, we can tell OpenGL to store this data for us.

Now this might seem complicated, but it’s quite logical when you see what the parameters are for.

Parameters :

  • GLenum target n – the type of buffer we want this to be. We’ll use the same as for glGenBuffers : "GL_ARRAY_BUFFER"
  • GLsizeiptr size – the size of the data in bytes.
  • const GLvoid* data – the data that should be stored
  • GLenum usage – how the data should be used. We will just use GL_STATIC_DRAW which means we won’t be modifying it after this, we’ll only be using it for rendering.

The second argument, GLsizeiptr size, might seem a bit weird. First of all, what is a GLsizeiptr? Think of it as a very big integer. It’s basically a special type they used for when you need to store huge numbers. But don’t worry too much about this, we’ll be using it as a standard unsigned int.

The third argument, const GLvoid* data is a pointer to the data. A const GLvoid* ( or simply just void* ) is a pointer that can be pointing to anything. It can be floats, chars, ints, std::strings… Anything! So in reality, it doesn’t know anything about the data at all. This also means it doesn’t know the size either, which is why we need that second argument, GLsizeiptr size

Finally, here is how we’ll use it :

sizeof(GLfloat) simply gives us the size of a single GLfloat. So we just multiply that by the number of individual GLfloats in our array, square.

Here’s the entire code for setting up a VBO so that you can digest it all before moving on to the next part.

Now we have created a VBO but how do we render it? And what if we have more than just one VBO for the same object? Enter VAO, Vertex Array Object

VAO – vertex array object


A VBO represents a single vertex attribute ( like positions or color ). A VAO is a lot like VBO, they’re used in the same way. The difference is that a VBO represents a single attribute, but a VAO can combine several attributes / VBOs so that we have all the vertex data in a single object. This is a lot simpler when it comes to rendering ; we can simply render the VAO, then move on to the next one without even thinking about the VBOs

We still need a VBO for every attribute though, and we need to put them into the VAO one by one until we have a single object. The VBOs is only needed for creating or updating the VAOs. All other times we just use the VAOs

glGenVertexArrays


Think of this as glGenBuffers, only for VAOs. It generates a VAO for us to use later.

Here’s the signature :

The parameters are the exact same as for glGenBuffers so I won’t be going into them in any more depth.

Here’s how we’ll use it

glBindVertexArray


Just like glGenVertexArrays is the VAO equivalent of glGenBuffer, glBindVertexArray is the VAO equivalent of glBindBuffer. So this function sets the VAO as the active one. Note that these are not mutually exclusive, we can have both a VBO and a VAO active at the same time.

Parameters :

  • GLuint array – the ID of the vertex array to bind.

As you can see, this signature only has one argument. Why? Well in OpenGL there are several data we can store in a VBO, not just vertex data. But a VAO is more of a wrapper object for vertex data, so there is just one type.

Usage :

glVertexAttribPointer


Now this is where things get a little complicated. This method is what associates our vertex data from the currently selected VBO with the current VAO. We use it to tell OpenGL were in the VAO the data from the current VBO should be stored.

Parameters :

  • GLuint index – An ID we define that refers to this attribute. We’ll need this later so that we can refer to this vertex attribute
  • GLint size – the number of values per attribute ( 1 to 4). In our case it’s 3 since our attributes have 3 values (x, y and z)
  • GLenum type – the datatype the attributes are in. In our case it’s GL_FLOAT
  • GLboolean normalized – whether the data should be normalized ( more on this in a later part. ) For now we’ll use GL_FALSE
  • GLsizei stride – specifies an interval between vertex attributes. We don’t use that so we’ll just use 0 here
  • const GLvoid * pointer – the starting point of the data to use. We don’t use this either, so we’ll just use 0 here as ell.

As you can see, it’s really not as bad as it looks. The fourth argument, normalized isn’t really important for us now. And the two last ones only deals with cases were we put several vertex attributes in the same array ( like if we put positions and colors ) in the same array.

The important thing here is that it puts a type of vertex attribute data form a VBO into a VAO. It uses the current active VAO and VBO, so we need to call glBindBuffer and glBindVertexArray first.

Here’s how we’ll be using it :

Note that if you haven’t called glBindBuffer() before calling this function, it won’t work properly and your application might crash.

glEnableVertexAttribArray


After we’ve set up the VBOs and VAOs, we need to enable the attribute within the VAO because, by default, every vertex attribute array ( like our positions. ) are disabled. This means we’ll have to enable every vertex attribute we create and assign with glVertexAttribPointer. In our case, we just need to call it once since we are only enabling positions.

Parameters :

  • GLuint index – The index of the vertex attribute array we want to enable.

With all of that out of the way, we can look at an example of how to set up a VBO and VAO :

Hopefully this wasn’t too bad. It’s important that you understand what a VBO is, what a VAO is, what their relation is and how to use them. Knowing this will save you from a lot of confusion and frustration in the future.

I placed the binding of the VAO and VBO in an awkward order to demonstrate the ordering of these functions. The ordering doesn’t matter as long as you bind the VBO before using glBufferData and glBindVertexArray before you call glVertexAttribPointer. Take a look in the code below for a better way of ordering these functions : )

A quick note about shaders


Before we can get anything on the screen, we’ll need a shader. Shaders are small programs that runs on the actual GPU/graphics card. We only have to define a vertex shader. This shader deals with things like moving/rotating/scaling objects. We also have a framgment shader which deals with setting the correct colors.

I won’t be going any deeper into shaders than that this time. But we do need them, which means we also have to set them up properly. So I made a simple helper class that does all of that for us. I’ll post it below with the other code so you can copy it and get the example up and running. The next part will be about sharers and why we need them, so hopefully the code will make a bit more sense then.

The code


The code consists of three pieces ; the main .cpp file were most of the code is, the Shader.h which is where all of the shader related code is, and the shaders ; the vertex shader ( tutorial2.vert ), and the fragment shader ( tutorial2.frag )

I have added setting of colors to the code, along with an example of glEnableVertexAttribArray. I hope it gives you a good idea of how to use these functions. In the next part we’ll take a close look at the shader, how to set them up and how to write our own.

The code is take from here. Though I have changed it quite a lot.

main.cpp


Here is our main file :

As you can see, it also sets color. It does this in the same way as it sets positions. I added it to further demonstrate how to bind the buffers correctly.

Shader.h


Here is the shader helper file. Don’t mind it too much, I’ll go into more detail about how it works the next time.

tutorial2.vert


This is our first shader, the vertex shader. Make sure you name it tutorial2.vert and put it along with the other files

tutorial2.frag


And finally, the fragment shader. Make sure you name it tutorial2.frag and put it along with the other files

Compiling


Using clang

clang++ main.cpp -lGL -lGLEW -lSDL2 -std=c++11 -o Test

Using gcc/g++

g++ main.cpp -lGL -lGLEW -lSDL2 -std=c++11 -o Test

Conclusion


Finally we have something on the screen! The process is a bit tedious and not 3D yet. But we’ll be going into 3D territory soon. And that’s when things get really cool.

I hope this tutorial has helped you understand VBOs and VAOs along with the concept of vertexes. My goal is to go through things thoroughly, giving you a good understanding of how things work. The better you know how things work, the easier it will be to write code.


Feel free to comment if you have anything to say or ask questions if anything is unclear. I always appreciate getting comments.

You can also email me : olevegard@headerphile.com

[OpenGL – Part 1] OpenGL using SDL2

Introduction


In order to program in 3D, you need a 3D library. Sure, you could base your game of an already existing engine. But that’s not what this blog is about! Instead, we’ll
used a graphics library. The most common ones are OpenGL or DirectX.

Since DirectX is a Microsoft technology and only works under Windows, we will be using OpenGL. This means the applications we make will work on just about any operating system.

Note : I recommend that you read at least the first few parts of my SDL2 tutorial before continuing. My SDL2 tutorial will explain the SDL2 elements like SDL_Window in more detail. The first few parts are really short and should give you a basic understanding of SDL2

What is OpenGL


OpenGL is a specification or an abstract API if you will. It is not an actual implementation. It doesn’t do anything on its own. But rather, it just defines a lot of functions and data types that we can use in our program. Then it’s the job of the underlying implementation to actually do the job. This implementation is part of the graphics card driver. The means that the implementation varies from platform to platform. The Linux version is different from the Windows version. It’s also different based on the hardware. So a nVidia version is different from an ATI version.

We really won’t be giving this too much thought, we’ll only use the functions and types defined by the OpenGL specification. But it’s useful to know exactly what OpenGL is.

Old vs new


Back in the day, programming in OpenGL was tricky. Setting it up was a mess, you had several different libraries to keep track of like glu, glut and glew. I’m still not quite sure what all of them did. On top of that, the code itself was rather bad too. Really not intuitive and not as flexible as the new version. But after version 3.0 a lot changed. Lots of code was deprecated and lots of new stuff were added. So new we can write very simple and concise OpenGL that’s also multi platform.

GLEW


I briefly mentioned GLEW( OpenGL Extension Wrangler Library ) above as one of the libraries that made OpenGL confusing. But that’s really not GLEWs fault. GLEW is actually quite simple, it just lets us write OpenGL code in a simple, platform-independent way. We won’t be noticing it a lot, except for an init call, so there’s really no need to learn a lot about it. But it’s always nice to know what its there for.

OpenGL and SDL2


SDL2 makes setting up OpenGL really easy. You can use SDL2 to create your window and hook up a rendering context ( I’ll explain what a rendering context is later. ) If we didn’t do this using OpenGL we’d have to do it in different ways on different platforms. The code would get messy and really complicated. SDL2 lets us do all of this in a really simple way. I

Rendering context


A rendering context is a structure that keeps track of all of our resources, basically every thing we want to put on the screen. It also keeps some state like what version of OpenGL we are using and some other stuff. We need a rendering context before we can do any OpenGL stuff. A rendering context is connected to a window ( like SDL_Window ). It can be connected to just one window, several windows and a window can have several rendering contexts.

An SDL_Renderer is a kind of a rendering context, but SDL_Renderer only supports the SDL2 way of rendering, which is 2d. But now we want 3d, and it’s here that OpenGL comes in. SDL2 even has its own rendering context object, SDL_GLContext. We’ll see how to create it later.

Setting it up


Now let’s try to set up a simple OpenGL application. It won’t be much different from the first SDL2 application we made, the point is just to set up OpenGL.

Libraries and header files


First of all, if you haven’t already, you should set up SDL2. You can do this by following my guide.

Linux / Mac

If you’re on Linux or Mac, you don’t have to set up anything else. All you need is an extra compilation flag which I’ll show you later.

Windows

If you’re on Windows things are a little trickier.

  1. Download the libraries, headers and binaries from the GLEW web page
  2. Put the “glew.h” header file in a folder named “GL” in the same directory as you put the “SDL” folder
  3. Put the “glew32d.lib” file in the directory you place “SDL.lib
  4. In the Visual Studio -> Project Properties -> Linker -> Input add glew32d.lib;opengl32.lib;
    • You also need SDL2.lib like in the guide, so your string should start with glew32d.lib;opengl32.lib;sdl2main.lib;sdl2.lib;
  5. Puth the .dll in your project folder

That should be it. If you get the error 0xc000007b you’ve probably mixed up 32 / 64 bits lib or dll files.

Creating the window


The first part of the code should look very familiar to that of plain SDL2

In fact, the only new thing here is the SDL_WINDOW_OPENGL which tells SDL2 that we will be using this window for OpenGL and not SDL2.

Just like with plain SDL2, we end up with a SDL_Window. And now that we have created it, we just need to connect a rendering context to it.

Setting the variables


Before we create and connect the rendering context, we’ll set a few variables to tell SDL2 and OpenGL which version of OpenGL we want to use. To do this, we use the function SDL_GL_SetAttribute

Parameters :

  • attr – the attribute we want to set.
  • value – the value we want to set it to

For a list of all SDL_GLattrs, click here.

Return

0 on success, otherwise negative.

So now let’s use it to set a few variables :

Context profile mask


Here we set SDL_GL_CONTEXT_PROFILE_MASK to SDL_GL_CONTEXT_PROFILE_CORE
This means that the old, deprecated code are disabled, only the newer versions can be used.

You can also use this to limit your application to which means your code will work on smart phones too. But it also means we’ll have less functionality, so we won’t be doing that.

Context version


Set up so that we use version 3.2 of OpenGL. We could set the number higher to use a new version, but your graphics card might not support that. This means we wont have access to all of OpenGL, but for now, 3.2 is sufficient for our needs.

Double-buffering


We need to tell OpenGL we want double-buffering. Which basically means that we draw to a hidden “screen” ( or buffer ) When we are done drawing to it, we swap the buffer we drew on with the buffer on the screen so that it becomes visible. Then we start drawing on the buffer we just swapped out ( which is now invisibe). This way, we never draw directly on the screen, making the game look a lot smoother

The buffer/screen we are drawing on is usually called the “back buffer” and the one on the screen is called the “front buffer”

Connecting a rendering context


Now that we’ve set up the properties, we need to connect our rendering context. Fortunately, SDL2 makes this really simple, all we need is the SDL_GL_CreateContext method :

Parameters :

  • window – the SDL_Window we want the code>rendering context to connect to.

Return

A valid SDL_GLContext on succes, otherwise NULL.

Initializing GLEW


After initializing SDL2 we need to initialize GLEW so that it can take care of our OpenGL calls. There is a two steps to this :

This tells OpenGL that we want to use OpenGL 3.0 stuff and later.

Depending on your graphics card driver, some functions might not be available through the standard lookup mechanism. This means that GLEW can’t find it for us, and the application will crash. glewExperimental enables us to use functionality. So there might be functions that exists, are valid and will work, but the isn’t normally available. glewExperimental tells GLEW that we want to use these functions as well.

A side note : in my experience, this is needed even when using very basic OpenGL stuff, so it’s possible that some graphics card drivers report a lot of functions as experimental resulting in the need for glewExperimental = GL_TRUE


As you probably guessed, this simply initializes GLEW so that it can take care of looking up functions for us. And that’s really all we need as far as GLEW goes.

Drawing stuff


Finally, let’s use OpenGL to draw something. I’ll just cover the very basics in this part, more interesting stuff next time!

OpenGL and colors


For the most part, OpenGL uses float values for colors. So instead of 255 being “max color”, 1.0 is max color. So means no color and 0.5 means 50 % color ( same as 255 / 2 = 127 in SDL2)

glClearColor


In order to clear the screen with a single color, we first need to set which colors to clear it with. For that, we can use glClearColor.

Parameters :

  • red – the amount of red ( 0.0 – 1.0 ).
  • green – the amount of green ( 0.0 – 1.0 ).
  • blue – the amount of blue ( 0.0 – 1.0 ).
  • alpha – the amount of alpha ( 0.0 – 1.0 ).

If you specify a value higher than 1.0, it’ll be clamped to 1.0 which means that any number higher than 1.0 will be changed to 1.0.

You can think of this function as the same as

SDL_SetRenderDrawColor(&renderer, r, g, b, a)

The parameters are a little different, but both sets the color that will be used in the next step.

glClear


In order to update / fill the screen with the color we sat above using glClearColor(), we use glClear()

Parameters :

  • GLbitfield is basically an enum that tells us what we want to clear. We’ll use GL_COLOR_BUFFER_BIT which means we want to clear the colors, reseting the screen to the color we set using glClearColor

You can think of this function as the same as

SDL_RenderClear(&renderer);

SDL_GL_SwapWindow


This function swaps the back buffer ( were we are currently drawing ) with the front buffer ( the one currently on the screen) . So you could say that this function does the actual double-buffering.

Parameters :

window the SDL_Window we want to swap the buffers on

You can think of this function as the same as

SDL_RenderPresent(&renderer);

Basically ; it pushes things onto the screen.

Setting background color example.


Setting the background color in OpenGL is just as simple as in SDL2.

In SDL2, you can do something like this :

To do the same in OpenGL, you can do :

A small example


Let’s put it all together and make a small example. This example uses the event system in SDL2, so if you’re unfamiliar with that, you should read up on it.

In order to compile on Linux / Mac, you can simplu run

clang++ main.cpp -lGL -lGLEW -lSDL2 -std=c++11 -o Test

or

g++ main.cpp -lGL -lGLEW -lSDL2 -std=c++11 -o Test

In the application, you can press r, g, b to swap the color

Conclusion


Setting up OpenGL with SDL2 is easy! And now that we have it set up, we can do lots of fancy 3D stuff. I have been thinking about writing this for a long time, and I finally got around to it. I really hope you enjoy it and want to learn more about OpenGL. 3D is much more fun than 2D, and I promise things will get more interesting when we get the basics out of the way

Code attribution


The code in this post was based on the code from this post


Feel free to comment if you have anything to say or ask questions if anything is unclear. I always appreciate getting comments.

You can also email me : olevegard@headerphile.com

[SDL2 – Part 1b] Setting up Visual Studio for SDL2

Setup Visual Studio for SDL2


Finally, I’ve gotten around to making a quick guide for setting up Visual Studio for SDL2. This guide also includes a fix that makes it possible to use SDL2 with Visual Studio 2015

In order to use SDL2 on Windows, you have to set up your IDE to use it. Here’s the guide for how to do that using Visual Studio. The steps are generally the same for all versions of Visual Studio, but there is an issue with Visual Studio 2015

Visual Studio 2015


They changed a lot in the 2015 versjon of Visual Studio. This change means that you get a linker error when you try to build an SDL2 project.

It took me a little trial and error to fix this, but I ended up building the SDLmain from source. You can find it here.

1. Getting the libs

You can find the files you need here. For VisualStudio you need to download :

SDL2-devel-2.x.x-VC.zip (Visual C++ 32/64-bit)

This includes both the .lib and the .h files.

Or, as mentioned above, if you’re using Visual Studio 2015, you need a .lib file build with Visual Studio 2015. You can either do this yourself, or download the ones I compiled.

Placing the includes/libs


Now take all the .h files in include and move them into a folder named SDL2. You can put this folder anywhere you want as long as the folder containing all the .h files is called SDL2. The reason for this is that we use #include <SDL2/SDL.h>

Do the same for the .lib files. The name of the directory you put them in is irrelevant in this case, just put them somewhere you remember. ( You might have to put other .libs in here at a later point in time )

2 Setting up libs


Start up Visual Studio, create a new project and add / write a .cpp ( for instance you can use the main.cpp in the first part of the tutorial. )

Now we need to set up VisualStudio so it knows where to find the header files we placed in the step above

Right click on the project and click “Properties”


VS Install 1

Select C/C++, select “Additional include directories” and click “Edit”


VS Install 2

Click “New Line”, then navigate the folder containg the SDL2 folder and click “Select Folder”


VS Install 3

You should now see something like this :

VS Install 4

Click OK. Now we’re done with the header files, time for the lib files.

Under “Linker”, select “Additional Library Directories


VS Install 5

Do the same thing you did for the header files, but this time navigate to the folder conataining the .lib files.

Navigate to “Input” and enter “SDL2main.lib;SDL2.lib;” in front of the others


VS Install 6

3 Copying .dll files


The .dll files are needed to run SDL2 applications. When it comes to placing them you have two options :

In the project directory

This is the same folder as your .exe file. This means you have to copy them every time you create a new project, which can be a little annoying and easy to forget

In your Windows system directories

When Windows looks for dll files, it’ll look in a few standard directories in addition to the directory the .exe file is in. Putting it in one of these means the dll will always be there, and you don’t have to worry about copying.

The directories are as follows :

  • In x86 this directory is C:/Windows/system32/
  • In x64 this directory is C:/Windows/SysWOW64/ though you might have to place them in System32/ as well.

4 Setting correct subsytem


You’ll probably also have to set the correct subsystem. Go to Linker -> System and set SubSytem to Console(/SUBSYSTEM:CONSOLE)

VS Install 7

Adding other libs


Now that we have this set up, we can add other SDL2 libs like SDL2_image, SDL2_ttf, etc.. All you have to do, is to download the Visual Studio libs like before and copy the header files and lib files to the same folders as above. You also need to add the name of the new .lib file to “Input” under “Linker” And finally you need to copy the new dlls as mentioned above.

SDL2_image

You can find the libs here ( download the one with VC in it. ) Add

SDL2_image.lib

to Linker / Input

SDL2_ttf

You can find the libs here ( download the one with VC in it. ) Add

SDL2_ttf.lib

to Linker / Input

SDL2_net

You can find the libs here ( download the one with VC in it. ) Add

SDL2_net.lib

to Linker / Input


Feel free to comment if you have anything to say or ask questions if anything is unclear. I always appreciate getting comments.

You can also email me : olevegard@headerphile.com