Jump to content
  • entry
    1
  • comments
    33
  • views
    1,658

Windows, UAK and GLEW.


SlipperyBrick

3,718 views

 Share

So, I was lurking around the forums looking for some action, you know ... some real crazy action. That kind of action you get from watching a Michael Bay movie, and I got it alright. I got it real good.

Some homies chatting right here, wanting to know how they can get GLEW playing nice with UAK:

Well guess what guys, strap your eyeballs in ... cos I'm about to take them for the ride of their lives!

Lets kick things off by starting up a fresh, raw, uncensored ... raw? Visual Studio project!

A precursor before you continue reading. This is for Windows only, if you are on anything else then God speed.

Project Setup w/ Blank C++ Project.

You can do this one of two ways, or maybe even two of two ways. UAK has a real fancy application that can help you set up a Visual Studio project through Steam. Or, if your an old-schooler (like me), you can simply set up a blank C++ project. Either way, I don't care, cos let's be honest cuh ... if you can't even make a Visual Studio project, then what the heck you doing here, at Slippy's Corner ... at this hour, shouldn't you be in bed by now? Slippy got gat's, you feel me?

For real though, let's put our big boy pants on and ditch the UAK project launcher (sorry Josh).

Fire up Visual Studio and select the "Create a new project" option, choosing "Empty Project" on the right.

blank-project.thumb.png.d32e092cf41e0043d9b0b56285053e2d.png

Once everything has loaded right-click your project in the Solution Explorer and go to Properties (Alt+Enter if your a shortcut loser, just kidding, shortcuts are cool). You'll get the properties page of your project, we want to set some general paths for our Output Directory and Intermediate Directory. Both directories refer to where your built binaries go. Output is where the built Configuration Type goes to (that's the type of application you are making, we are making an executable .exe). Our intermediate path is where all the files our compiler creates and uses to build our application goes:

bin-paths.thumb.png.0ac5181ea03a24704dce838130de262a.png

Feel free to copy mine, or if you have a personal preference then go with that, I won't judge.

As an optional step here, depending on how you set up your project (if you did it through creating a blank C++ project like I suggested above) then you'll have to link up the UAK library and also include the sweet nectar, the elixir of life. The header files.

This is good to go through as its a nice practice run for when we get our hands full of GLEW, real sticky, pungent GLEW. Hey, if you did set up your project using the UAK app on Steam then I'd recommend to delete that and start off with a blank C++ project, if you got the nards! Go on, I dare you.

Ok, enough messing around, lets go and create some folders to keep our project in order (this is optional, only follow this if you have made a blank C++ project).

Right-click your solution in the Solution Explorer within Visual Studio (that's the top-most item in the list) and choose "Open Folder in File Explorer". We want to create a folder here called Dependencies, within that folder make another new folder called UAK. Now, hop into that folder (reminds me of that movie Inception) and make two new folders, one called includes and another called libs.

dependencies.thumb.png.0f3f53b97f919621e26a393b6cf12828.png

Having fun yet? Well there is more, a lot more. We now need to go and get those UAK dependencies, otherwise we won't have access to any UAK code. Head on over to your Steam installation and go to "steamapps > common > Ultra App Kit > Library > Windows > x64 > Debug", in there we should see AppKit.lib. Copy that and paste it in our libs folder that we made earlier. This is the .lib file we will want to link later in Visual Studio.

Now go back to the root Ultra App Kit folder and you should see an Include folder. Select everything in this folder and copy and paste it into our includes folder we made earlier. These files make up the necessary code files that together forms the UAK API.

Ok, so far we have copied the UAK dependencies into their respective folders. Now we can go back to Visual Studio and get into the nitty-gritty.

Right-click your project in the Solution Explorer and open up the properties page again. I gonna warn you here that if you don't follow these instructions explicitly then your computer may combust into a spectacular ball of fire, so listen up carefully! <-- I'm just kidding guys, don't panic.

In the Linker drop-down on the left you should see a General section, click that and it will reveal new options on the right pane. We are looking for the option "Additional Library Directories" you should see it half way down, buried in the abyss of other frightening options we must not touch. Clicking that option will display yet another drop-down on the fields far right, click this and choose <Edit...>.

Now we need to enter the path to our UAK libs folder. There are some special macro's we can use (just copy and paste the below snippet if your lazy):

$(SolutionDir)Dependencies\UAK\libs

If you look in the "Evaluated value:" box you should see it has retrieved the correct path!

Season 4 Wow GIF by NETFLIX

I know right, this is pretty wild!

There is one last step, we need to head to the Input section within the Linker drop-down and in the "Additional Dependencies" field enter AppKit.lib; (don't forget that semi!)

Season 4 Episode 10 GIF by The Office

Now, we are gonna do the same thing for our includes directory, but there is one extra step we need to do for this.

Accept and OK the changes we have made in the project properties as we would like to save the hard work we have made so far. Now in the Solution Explorer we are going to add our first source code file. Right-click the Source Files folder filter in the Solution Explorer and go to Add > New Item. From the new dialog box we want to add a .cpp file. I'm going to call my Application.cpp.

With this file now added we can right-click our project and head to the properties once again!

The keen-eyed readers here will notice that we now have a new drop-down on the left, the C/C++ drop-down. Let's click it and go to the General properties. Similar to what we did with our libs folder, we now want to add our includes folder using the special macro's from before:

$(SolutionDir)Dependencies\UAK\includes

Hit apply and OK to save our changes.

Ok, with all that out of the way we are back on track. Again, I'd like to reiterate that if you didn't make a blank C++ project then all of the above was completely pointless and I can only assume that you continued reading it to expand your vocabulary palette, or maybe my fore-warning wasn't clear enough ... either way, I can only apologise.

Downloading & Linking GLEW.

We are finally here and we are ready to get sticky.

Season 3 Nbc GIF by The Office

We first need to download GLEW, head over to this link where you can get the official GLEW binaries (download the binaries, not the source code) http://glew.sourceforge.net/.

Once we have downloaded and extracted the GLEW zip we should see the following folder structure:

glew-folder-structure.thumb.png.1f08dfeb82b8106d806e6df06b73f36c.png

We are interested in the include and lib folders. First we will deal with the lib folder.

Take a peek inside it, what do you see? Maybe a nice picture of a sunrise, or a .mp3 file called sounds of the ocean, no? Surprise! Its another folder. Lets see whats inside this one. Ok, you gotta be kidding me, two more folders! Let's pick the x64 folder. 

Now before you think your on a roll here with your copying and pasting, take a second to check that we have two .lib files and one has an "s" on the end of its name. What this is referring to is the static version of the GLEW library. Now I'm not going into all the details of dynamic and static linking here, but to make our lives easier lets pick the glew32s.lib file, as you have probably guessed we are going to statically link GLEW in our project.

Before we copy and paste that .lib file we need to head to our solutions directory and go to the Dependencies folder as we have 3 new folders to make. Similar to our UAK folder structure, we are going to do the same thing for GLEW. So, inside Dependencies create a new folder called GLEW (if you can't remember what we did here just go to Visual Studio and right-click your solution file which will be the top-most item in the Solution Explorer list and click "Open Folder in File Explorer"). Inside our newly made GLEW folder, lets make those two new includes and libs folders.

With that all done we can now copy and paste the glew32s.lib file into our libs folder we just created. Now we can head to the include folder where we extracted our GLEW download and copy and paste the GL folder into our includes folder.

This next step is pretty much a rinse and repeat of what we did earlier to get UAK setup in our project. Going back to Visual Studio, we right-click our project and choose Properties. Let's go to the Linker, General option and look for "Additional Library Directories", selecting the fields drop-down and choosing <Edit...>.

To make our lives easier we can double click our UAK entry, copy and paste it underneath and simply change the UAK part of our path to GLEW 😎

Lets not forget the Input section, choose this from the Linker drop-down and enter glew32s.lib in the "Additional Dependencies" field.

As a last step we simply need to include our includes (see what I did there). Go to the C/C++ drop-down and select the General option. Click the top "Additional Include Directories" field drop-down (the little drop-down that appears on the far right) and choose <Edit...>. In the new dialog that appears we can do the same trick we did when we linked our GLEW lib file. Copy and paste our existing UAK entry and change the UAK part of our path to GLEW.

GLEWing It All Together

If you have made it this far then I have to congratulate you. We have successfully included and linked both UAK and GLEW! There are just a few more things we need to set up to get rid of some errors we will inevitably get when starting to use both libraries in our code.

If you are still in the Properties dialog of your project then head on over to the C/C++ section and go to Preprocessor. In here we need to set a definition in the "Preprocessor Definitions" field. Clicking in the field, enter the following definition:

_ULTRA_APPKIT;

This ensures that all the other stuff found in the UAK include files aren't included.

With this we are finally ready to start using GLEW, OpenGL and UAK. We need to include one final, important library ... OpenGL. To do this head back to your project properties by right-clicking your project in the Solution Explorer and choosing Properties. Head to the LinkerInput section and in the "Additional Dependencies" field enter:

opengl32.lib;

An important note, when using GLEW you have to make sure that its initialized after a rendering context has been created.

We do need to include one more library, but this one is easy, its a header-only library which means we don't need to do anything with the linker. Head on over to the GLM Github link here and click the green Code button (somewhere near the top-right of the screen) making sure to select "Download ZIP". Once you have downloaded GLM, extract it (the folder will likely be called "glm-master"). Navigate into the extracted folder and you'll see a folder named glm. Copy this entire folder and paste it inside our Dependencies folder. Now, I challenge you to figure out how you should include GLM in your project Properties (if you don't know how to do it check below in the Conclusion section).

Without getting into the complexities of writing a shader class and coding and parsing GLSL shaders, I have edited the example code from the UAK documentation to include a Vertex struct for us to get some data into the graphics pipeline (maybe another blog for another time)

For now, simply copy and paste the following code into your .cpp file:

#include "UltraEngine.h"

#define GLEW_STATIC
#include <GL/glew.h>
#include <GL/GL.h>
#include <glm.hpp>

using namespace UltraEngine;

struct Vertex
{
    glm::vec3 Position;
    glm::vec3 Normal;
    glm::vec2 TexCoords;
    glm::vec3 Tangent;
    glm::vec3 Bitangent;
    glm::vec4 Colour;

    Vertex()
    {
        Position = { 0.0f, 0.0f, 0.0f };
        Normal = { 0.0f, 0.0f, 0.0f };
        TexCoords = { 0.0f, 0.0f };
        Tangent = { 0.0f, 0.0f, 0.0f };
        Bitangent = { 0.0f, 0.0f, 0.0f };
        Colour = { 0.0f, 0.0f, 0.0f, 0.0f };
    }

    Vertex(glm::vec3 position, glm::vec4 colour)
    {
        this->Position = { position };
        Normal = { 0.0f, 0.0f, 0.0f };
        TexCoords = { 0.0f, 0.0f };
        Tangent = { 0.0f, 0.0f, 0.0f };
        Bitangent = { 0.0f, 0.0f, 0.0f };
        this->Colour = { colour };
    }
};

// Callback function for resizing the viewport
bool ResizeViewport(const Event& ev, shared_ptr<Object> extra)
{
    // If the window resize event is captured
    auto window = ev.source->As<Window>();

    // Get the new size of the applications window
    iVec2 sz = window->ClientSize();

    auto viewport = extra->As<Window>();

    // Set the position and size of the viewport window
    viewport->SetShape(200, 8, sz.x - 200 - 8, sz.y - 16);

    return true;
}

int main(int argc, const char* argv[])
{
    // Get the available displays
    auto displays = GetDisplays();

    // Create a window
    auto window = CreateWindow("OpenGL Example", 0, 0, 800, 600, displays[0], WINDOW_TITLEBAR | WINDOW_RESIZABLE);

    // Create user interface
    auto ui = CreateInterface(window);

    // Get the size of the user-interface
    iVec2 sz = ui->root->ClientSize();

    // Create a treeview widget
    auto treeview = CreateTreeView(8, 8, 200 - 16, sz.y - 16, ui->root);

    // Anchor left, top and bottom of treeview widget
    treeview->SetLayout(1, 0, 1, 1);

    // Add nodes to the treeview widget
    treeview->root->AddNode("Object 1");
    treeview->root->AddNode("Object 2");
    treeview->root->AddNode("Object 3");

    // Create a viewport window
    auto viewport = CreateWindow("", 200, 8, sz.x - 200 - 8, sz.y - 16, window, WINDOW_CHILD);

    // Adjust the size of the viewport when the applications window is resized (this will callback to our ResizeViewport() function)
    ListenEvent(EVENT_WINDOWSIZE, window, ResizeViewport, viewport);

    // Initialize an OpenGL context (get a hdc)
    HWND hwnd = (HWND)(viewport->GetHandle());
    HDC hdc = GetDC(hwnd);

    // Specify the format of the default framebuffer
    PIXELFORMATDESCRIPTOR pfd =
    {
        sizeof(PIXELFORMATDESCRIPTOR),
        1,

        // Flags
        PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,

        // Framebuffer colour format (R, G, B, A)
        PFD_TYPE_RGBA,

        // Framebuffer colour depth (32 bit)
        32,
        0, 0, 0, 0, 0, 0,
        0,
        0,
        0,
        0, 0, 0, 0,

        // Number of bits for depth-buffer
        24,

        // Number of bits for stencil-buffer
        8,

        // Number of render-targets in default framebuffer
        0,
        PFD_MAIN_PLANE,
        0,
        0, 0, 0
    };

    // Select an appropriate pixel format that is supported by the hdc
    int format = ChoosePixelFormat(hdc, &pfd);

    if (SetPixelFormat(hdc, format, &pfd) == 0)
    {
        RuntimeError("SetPixelFormat() failed.");
    }

    // Create an OpenGL rendering context using our current hdc
    HGLRC glcontext = wglCreateContext(hdc);

    if (glcontext == NULL)
    {
        RuntimeError("wglCreateContext() failed.");
    }

    wglMakeCurrent(hdc, glcontext);

    if (glewInit() != GLEW_OK)
    {
        RuntimeError("Failed to init GLEW");
    }

    // Create vertex data for a triangle
    Vertex triangle[3];

    // Bottom right
    triangle[0] = Vertex(glm::vec3(0.5f, -0.5f, 0.0f), glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));

    // Top
    triangle[1] = Vertex(glm::vec3(0.0f, 0.5f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));

    // Bottom left
    triangle[2] = Vertex(glm::vec3(-0.5f, -0.5f, 0.0f), glm::vec4(0.0f, 0.0f, 1.0f, 1.0f));

    unsigned int triVAO;	// A value OpenGL can reference when we want to use this object
    unsigned int triVBO;	// Much like the triVAO, we can refernce this VBO with this value

    // Using the triVAO and triVBO values as a reference to our objects, we generate veretx arrays and buffers using said references
    glGenVertexArrays(1, &triVAO);
    glGenBuffers(1, &triVBO);

    // Bind the VAO first to say which VAO we want to bind subsequent VBOs to, and then we follow up with binding the relevant VBOs
    glBindVertexArray(triVAO);
    glBindBuffer(GL_ARRAY_BUFFER, triVBO);

    // Assigning our triangle array data to our vertex buffer object
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle), &triangle, GL_DYNAMIC_DRAW);

    // Position data
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::Position));

    // Enable the vertex data we formatted above
    glEnableVertexAttribArray(0);

    // Colour data
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::Colour));

    // Enable the vertex data we formatted above
    glEnableVertexAttribArray(1);

    // Render loop (applications run loop)
    while (true)
    {
        // Check for events
        const Event ev = WaitEvent();

        switch (ev.id)
        {
        case EVENT_WINDOWPAINT:
            if (ev.source == viewport)
            {
                // Get and set the current size of the viewport
                iVec2 sz = viewport->ClientSize();
                if (sz.x < 1 or sz.y < 1) break;

                glViewport(0, 0, sz.x, sz.y);

                // Set clear colour of viewport background
                glClearColor(0.15f, 0.15f, 0.15f, 1.0f);

                // Clear colour and depth buffers
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

                // WE ARE RENDERING HERE
                // 
                // Work with our triangle vertex array
                glBindVertexArray(triVAO);

                glDrawArrays(GL_TRIANGLES, 0, sizeof(triangle) / sizeof(Vertex));

                glBindVertexArray(0);

                HWND hwnd = viewport->GetHandle();
                auto hdc = GetDC(hwnd);
                SwapBuffers(hdc);
                ReleaseDC(hwnd, hdc);
            }
            break;

        case EVENT_WINDOWCLOSE:
            if (ev.source == window)
            {
                return 0;
            }
            break;
        }
    }

    return 0;
}

I will come back to this blog at some point and clean up this code but for now running this code will reveal a cool tree view in a panel on the left of the window and a small OpenGL viewport on the right with a white triangle, success!

final.thumb.png.f53fd177a737fe6f770698da5f91ea65.png

Conclusion

And there you have it. GLEW and UAK working together. From here the world's your oyster. Abstract to your hearts content to make some wicked cool stuff with modern OpenGL. If there are any issues during setup please comment below and I'd be happy to help.

P.S. For the people that was wondering how to include GLM the process is the same as when we included UAK and GLEW. Right-click your project and go to Properties, then head to the C/C++ dropdown, choosing the General option. Then add the follow path with those awesome macro's:

$(SolutionDir)Dependencies\GLM

Depending on if you kept the glm folder lowercase or uppercase, change the GLM part of the path to reflect that.

Again, I hope this helped, any questions post below.

Stay safe!

Slippy

  • Like 3
 Share

33 Comments


Recommended Comments



Man, thanks you so much, I tried the blank c++ version aswell, and it doesnt work aswerll. Look if you need help with models or materials ask me, im not so good at programming as you see.

Link to comment
Just now, Vida Marcell said:

Man, thanks you so much, I tried the blank c++ version aswell, and it doesnt work aswerll. Look if you need help with models or materials ask me, im not so good at programming as you see.

Before we get too excited. Double check if that project works for you. You should have exactly what I have in my final screenshot at the bottom of the blog.

Link to comment

It doesnt build for me, but at least vs doesnt screaming for me for the libraries.

it says:  "The build tools for v143 (Platform Toolset = 'v143') cannot be found."

So im gonna update that

Link to comment
2 minutes ago, Vida Marcell said:

It doesnt build for me, but at least vs doesnt screaming for me for the libraries.

it says:  "The build tools for v143 (Platform Toolset = 'v143') cannot be found."

So im gonna update that

Ah my bad, I use Visual Studio 2022. I guess you are using an earlier version. If you go and download Visual Studio 2022 Community Edition then your set.

Link to comment

Yep that would do it. Sounds like you may have copied and pasted the 32bit lib file when you initially set up your project following the tutorial. Glad you got it up and running though. Congratulations! Can't wait to see the cool stuff you make. If you are new to graphics there are plenty of resources available online to learn OpenGL, I'd arguably say it is probably one of the easiest graphics libraries to learn alongside understanding the graphics pipeline.

I do hope to write more blogs, I'm pretty new to it and wasn't sure if the text to image ratio was good enough. But over time I hope to improve. Maybe my next blog will be a trip down the graphics pipeline to explain some of the maths, techniques, and jargon that comes with it.

Link to comment

Thanks, also now i have to give something back. I want to work on a node workflow for uak. It would be helpful for complex softwares.

Link to comment

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...