Wiki

Clone wiki

PolyVox / Building PolyVox with CodeBlocks MinGW and Ogre3D


Last tested version of PolyVox: Unknown


Disclaimer

These are the steps I took to make it work. I make no promises that this is the best way to do it or that the following steps will work for all users. This is just meant to get you up and running and in no way represents best practices.

What you need

MinGW - www.mingw.org
CodeBlocks - www.codeblocks.org 12.11
CMake - www.cmake.org Win32 Installer version 2.8
Ogre3D - www.ogre3d.org 1.8.1 SDK for MinGW
PolyVox - http://www.volumesoffun.com/polyvox-download/ version 0.2.1

Ogre3D AppWizard for CodeBlocks - bitbucket.org/jacmoe/ogreappwizards/downloads

You'll need to download all of these. I've included the versions I used at the time of writing. Install MinGW and make sure you include the C++ compiler and that the bin directory (eg. C:/MinGW/bin) gets added to your Path. Make sure you got the setup of CodeBlocks that does not include MinGW. Install CodeBlocks and select GCC as your default compiler. I recommend you create a C++ console application and build/run it to make sure it's all working. Install CMake. Extract the Ogre3D SDK to wherever you want it to live, mine is at C:/OgreSDK/OgreSDK_MinGW_v1-8-1. Do the same for PolyVox, again mine is just C:/PolyVox. Hold on to the Ogre AppWizard for now, we'll use it later.

Environment Variables

We'll need to set up three Environment Variables so our projects know where to find things. These are OGRE_HOME, *BOOST_ROOT and POLYVOX_HOME. These need to be set to the directories where you put each of these things in the previous step. Boost is inside the Ogre3D directory. So, for example, with the directories I used you can set these variables by typing the following commands into a command prompt:

setx OGRE_HOME "C:\OgreSDK\OgreSDK_MinGW_v1-8-1"

setx BOOST_ROOT "C:\OgreSDK\OgreSDK_MinGW_v1-8-1\boost"

setx POLYVOX_HOME "C:\PolyVox"

(*BOOST_ROOT may not be necessary given we are now compiling with C++11, but I haven't tested without it.)

Build PolyVox

Now that we've done that we can run the CMake GUI. Browse source to POLYVOX_HOME (C:/PolyVox for me) and build to POLYVOX_HOME/build (C:/PolyVox/build) then hit Configure. The first time you do this it will pop up a window with a dropdown. In the dropdown select CodeBlocks - MinGW Makefiles and hit finish. If you've added everything you need to your path then that should work. If it doesn't, you may have to tell it where your compilers are. To get that window to appear again when you hit configure go to File->Delete Cache. This time when you configure also select Specify native compilers then hit next. For the C and C++ compilers browse to where you installed MinGW and go to the bin directory. For C select mingw32-gcc.exe and for C++ select mingw32-g++.exe. If you get an error about a libgmp being missing you didn't add MinGW/bin to your path.

The checkboxes are for test and example applications and for python bindings. I deselected all of mine. If you plan to use them then go ahead and select them, but since we're using Ogre we probably don't have Qt which is what they were built to work with. It should build fine either way. When you make up your mind push generate. That shouldn't take very long and now we're done with CMake and can close it.

Go into CodeBlocks File->Open and browse to PolyVox/build there should be a codeblocks project called PolyVox. Open that project and hit build. If that works with no errors then congratulations! You just built PolyVox!

Setting up the Wizard

Now, close CodeBlocks and we'll set up some files for the CodeBlocks wizard to make creating projects for Ogre and PolyVox easier.

Browse to your CodeBlocks install directory and open share/CodeBlocks/templates/wizard and edit config.script

Optional: Ogre3D Only Wizard

We're going to set up the Ogre3D Application Wizard just for Ogre applications first, not including PolyVox. We're then going to go through the same steps with some slight variations to set it up to work with PolyVox. If you're not interested in setting up the wizard for Ogre applications without PolyVox you can skip this step and go to where we set it up to include PolyVox as well.

In config.script add the line:

    RegisterWizard(wizProject,     _T("ogre3d"),       _T("Ogre3d project"),        _T("2D/3D Graphics"));

to the RegisterWizards() function. I put mine right under the line for an Ogre Project. Now open the Ogre CodeBlocks AppWizard zip and copy the ogre3d folder to that same directory you opened (CodeBlocks/share/CodeBlocks/templates/wizard) At this point you have added the Ogre3D application to the application wizard in CodeBlocks. However, when I did this it didn't properly link to boost and so the applications wouldn't work. To fix this we need to open the wizard.script file in the ogre3d folder you just copied. You can do this by opening codeblocks and clicking create new project and then right clicking on the Ogre3D project and clicking edit this script (you may have to right click and run CodeBlocks as administrator in order for it to be able to edit this file).

There are several lines that need to be added to this. For whatever reason the Ogre3D AppWizard doesn't properly add the boost libraries so we're going to add them in. To make it easy just replace the SetupProject function with this:

// setup the already created project
function SetupProject(project)
{
    // set project options

    // Windows platform
    if (PLATFORM == PLATFORM_MSW)
    {
		project.AddIncludeDir(_T("$(OGRE_HOME)/include"));
		project.AddIncludeDir(_T("$(OGRE_HOME)/include/OGRE"));
		project.AddIncludeDir(_T("$(OGRE_HOME)/include/OIS"));
		project.AddIncludeDir(_T("$(OGRE_HOME)/boost"));
		project.AddLibDir(_T("$(OGRE_HOME)/bin/$(TARGET_NAME)"));
		project.AddLibDir(_T("$(OGRE_HOME)/boost/lib"));

        project.AddCompilerOption(_T("-mthreads"));
        project.AddCompilerOption(_T("-fmessage-length=0"));
        project.AddCompilerOption(_T("-fexceptions"));
        project.AddCompilerOption(_T("-fident"));
        project.AddCompilerOption(_T("-DWIN32"));
        project.AddCompilerOption(_T("-D_WINDOWS"));

        // help the linker
        project.AddLinkerOption(_T("-Wl,--enable-runtime-pseudo-reloc"));
        project.AddLinkerOption(_T("-Wl,--enable-auto-image-base"));
        project.AddLinkerOption(_T("-Wl,--enable-auto-import"));
        project.AddLinkerOption(_T("-Wl,--add-stdcall-alias"));
        project.AddLinkerOption(_T("-mthreads"));
    }
    else
    {
        // TODO: do some Linux stuff ?
		project.AddLinkLib(_T("GL"));
    }

    // enable compiler warnings (project-wide)
    WarningsOn(project, Wizard.GetCompilerID());
    // enable C++ exceptions (project-wide)
    CppExceptionsOn(project, Wizard.GetCompilerID());

    // Debug
    local target = project.GetBuildTarget(Wizard.GetDebugName());
    if (!IsNull(target))
    {
        target.SetTargetType(ttConsoleOnly); // ttConsoleOnly: console for debugging

        target.SetWorkingDir(_T("$(OGRE_HOME)/bin/Debug"));
        project.AddLibDir(_T("$(OGRE_HOME)/bin/Debug"));
        // TODO: linux package contains samples?

        if (target.GetWorkingDir().Matches(_T("")))
            target.SetOutputFilename(target.SuggestOutputFilename());
        else
            target.SetOutputFilename(target.GetWorkingDir() + wxFILE_SEP_PATH + target.SuggestOutputFilename());
//        target.SetOutputFilename(Wizard.GetDebugOutputDir() + Wizard.GetProjectName() + DOT_EXT_EXECUTABLE);

        target.AddLinkLib(_T("OgreMain_d"));
        target.AddLinkLib(_T("OIS_d"));
        target.AddLinkLib(_T("libboost_chrono-mgw47-mt-d-1_51"));
        target.AddLinkLib(_T("libboost_date_time-mgw47-mt-d-1_51"));
        target.AddLinkLib(_T("libboost_system-mgw47-mt-d-1_51"));
        target.AddLinkLib(_T("libboost_thread-mgw47-mt-d-1_51"));
        if (PLATFORM == PLATFORM_MSW)
        {
            target.AddCompilerOption(_T("-D_DEBUG"));
        }

        // enable generation of debugging symbols for target
        DebugSymbolsOn(target, Wizard.GetCompilerID());
    }

    // Release
    target = project.GetBuildTarget(Wizard.GetReleaseName());
    if (!IsNull(target))
    {
        target.SetTargetType(ttExecutable); // ttExecutable: no console

        target.SetWorkingDir(_T("$(OGRE_HOME)/bin/Release"));
        project.AddLibDir(_T("$(OGRE_HOME)/bin/Release"));
        // TODO: linux package contains samples?

        if (target.GetWorkingDir().Matches(_T("")))
            target.SetOutputFilename(target.SuggestOutputFilename());
        else
            target.SetOutputFilename(target.GetWorkingDir() + wxFILE_SEP_PATH + target.SuggestOutputFilename());
//        target.SetOutputFilename(Wizard.GetReleaseOutputDir() + Wizard.GetProjectName() + DOT_EXT_EXECUTABLE);

        target.AddLinkLib(_T("OgreMain"));
        target.AddLinkLib(_T("OIS"));
        target.AddLinkLib(_T("libboost_chrono-mgw47-mt-1_51"));
        target.AddLinkLib(_T("libboost_date_time-mgw47-mt-1_51"));
        target.AddLinkLib(_T("libboost_system-mgw47-mt-1_51"));
        target.AddLinkLib(_T("libboost_thread-mgw47-mt-1_51"));
        if (PLATFORM == PLATFORM_MSW)
        {
            target.AddCompilerOption(_T("-DNDEBUG"));
        }
        // enable optimizations for target
        OptimizationsOn(target, Wizard.GetCompilerID());
    }

    return true;
}

That should be all you need! Now you can create an Ogre3D application and compile and run it. If everything is working properly it should launch a window to select video features and then start rendering a black screen at high framerates.

Ogre3D and PolyVox Wizard

The steps here are almost identical to those above. In config.script add the line:

    RegisterWizard(wizProject,     _T("ogre3dpolyvox"),_T("Ogre3d PolyVox project"),_T("2D/3D Graphics"));

in the function RegisterWizards(). Then extract the ogre3d folder from the Ogre CodeBlocks AppWizard zip file and rename it to ogre3dpolyvox then copy it to the directory where you found config.script (CodeBlocks/share/CodeBlocks/templates/wizard). Now we need to change the wizard.script file in ogre3dpolyvox to add a few lines to make boost and polyvox work. You can open this by opening codeblocks and clicking create new project and then right clicking on the Ogre3D PolyVox project and clicking edit this script (you may have to right click and run CodeBlocks as administrator in order for it to be able to edit this file).

As before the libraries for boost are missing, so we'll add those. Also, we add the include and libraries for PolyVox and enable C++11 support for the compiler. For simplicity you can just replace the SetupProject function with what's below:

// setup the already created project
function SetupProject(project)
{
    // set project options

    // Windows platform
    if (PLATFORM == PLATFORM_MSW)
    {
		project.AddIncludeDir(_T("$(OGRE_HOME)/include"));
		project.AddIncludeDir(_T("$(OGRE_HOME)/include/OGRE"));
		project.AddIncludeDir(_T("$(OGRE_HOME)/include/OIS"));
		project.AddIncludeDir(_T("$(OGRE_HOME)/boost"));
		project.AddIncludeDir(_T("$(POLYVOX_HOME)/library/PolyVoxCore/include"));
		project.AddIncludeDir(_T("$(POLYVOX_HOME)/library/PolyVoxUtil/include"));
		project.AddLibDir(_T("$(OGRE_HOME)/bin/$(TARGET_NAME)"));
		project.AddLibDir(_T("$(OGRE_HOME)/boost/lib"));
		project.AddLibDir(_T("$(POLYVOX_HOME)/build/library/PolyVoxCore"));
		project.AddLibDir(_T("$(POLYVOX_HOME)/build/library/PolyVoxUtil"));

        project.AddCompilerOption(_T("-mthreads"));
        project.AddCompilerOption(_T("-fmessage-length=0"));
        project.AddCompilerOption(_T("-fexceptions"));
        project.AddCompilerOption(_T("-fident"));
        project.AddCompilerOption(_T("-DWIN32"));
        project.AddCompilerOption(_T("-D_WINDOWS"));
        project.AddCompilerOption(_T("-std=c++11"));

        // help the linker
        project.AddLinkerOption(_T("-Wl,--enable-runtime-pseudo-reloc"));
        project.AddLinkerOption(_T("-Wl,--enable-auto-image-base"));
        project.AddLinkerOption(_T("-Wl,--enable-auto-import"));
        project.AddLinkerOption(_T("-Wl,--add-stdcall-alias"));
        project.AddLinkerOption(_T("-mthreads"));

        project.AddLinkLib(_T("libPolyVoxCore"));
        project.AddLinkLib(_T("libPolyVoxUtil"));
    }
    else
    {
        // TODO: do some Linux stuff ?
		project.AddLinkLib(_T("GL"));
    }

    // enable compiler warnings (project-wide)
    WarningsOn(project, Wizard.GetCompilerID());
    // enable C++ exceptions (project-wide)
    CppExceptionsOn(project, Wizard.GetCompilerID());

    // Debug
    local target = project.GetBuildTarget(Wizard.GetDebugName());
    if (!IsNull(target))
    {
        target.SetTargetType(ttConsoleOnly); // ttConsoleOnly: console for debugging

        target.SetWorkingDir(_T("$(OGRE_HOME)/bin/Debug"));
        project.AddLibDir(_T("$(OGRE_HOME)/bin/Debug"));
        // TODO: linux package contains samples?

        if (target.GetWorkingDir().Matches(_T("")))
            target.SetOutputFilename(target.SuggestOutputFilename());
        else
            target.SetOutputFilename(target.GetWorkingDir() + wxFILE_SEP_PATH + target.SuggestOutputFilename());
//        target.SetOutputFilename(Wizard.GetDebugOutputDir() + Wizard.GetProjectName() + DOT_EXT_EXECUTABLE);

        target.AddLinkLib(_T("OgreMain_d"));
        target.AddLinkLib(_T("OIS_d"));
        target.AddLinkLib(_T("libboost_chrono-mgw47-mt-d-1_51"));
        target.AddLinkLib(_T("libboost_date_time-mgw47-mt-d-1_51"));
        target.AddLinkLib(_T("libboost_system-mgw47-mt-d-1_51"));
        target.AddLinkLib(_T("libboost_thread-mgw47-mt-d-1_51"));
        if (PLATFORM == PLATFORM_MSW)
        {
            target.AddCompilerOption(_T("-D_DEBUG"));
        }

        // enable generation of debugging symbols for target
        DebugSymbolsOn(target, Wizard.GetCompilerID());
    }

    // Release
    target = project.GetBuildTarget(Wizard.GetReleaseName());
    if (!IsNull(target))
    {
        target.SetTargetType(ttExecutable); // ttExecutable: no console

        target.SetWorkingDir(_T("$(OGRE_HOME)/bin/Release"));
        project.AddLibDir(_T("$(OGRE_HOME)/bin/Release"));
        // TODO: linux package contains samples?

        if (target.GetWorkingDir().Matches(_T("")))
            target.SetOutputFilename(target.SuggestOutputFilename());
        else
            target.SetOutputFilename(target.GetWorkingDir() + wxFILE_SEP_PATH + target.SuggestOutputFilename());
//        target.SetOutputFilename(Wizard.GetReleaseOutputDir() + Wizard.GetProjectName() + DOT_EXT_EXECUTABLE);

        target.AddLinkLib(_T("OgreMain"));
        target.AddLinkLib(_T("OIS"));
        target.AddLinkLib(_T("libboost_chrono-mgw47-mt-1_51"));
        target.AddLinkLib(_T("libboost_date_time-mgw47-mt-1_51"));
        target.AddLinkLib(_T("libboost_system-mgw47-mt-1_51"));
        target.AddLinkLib(_T("libboost_thread-mgw47-mt-1_51"));
        if (PLATFORM == PLATFORM_MSW)
        {
            target.AddCompilerOption(_T("-DNDEBUG"));
        }
        // enable optimizations for target
        OptimizationsOn(target, Wizard.GetCompilerID());
    }

    return true;
}

That should be all you need. You should now be able to use this wizard to create a new project that will include everything you need to work with Ogre3D and PolyVox and automatically sets up a basic Ogre3D framework.

Rendering a Voxel Sphere

However, this doesn't demonstrate PolyVox at all. Let's add some code to use PolyVox and to actually display something. I want to stress at this point that this is just example code to get you started and is definitely not the best way to do this.

Create a project in codeblocks and select the Ogre3D PolyVox project. When that is created you should have BaseApplication.cpp and <yourappname>Application.cpp in the Sources folder and corresponding .h files in the Headers folder. We're going to use the basics from the PolyVox tutorial here and then add the mesh to the scenegraph using the Ogre3D ManualObject. To start we're going to need to include some additional files. Open <yourappname>Application.h in the Headers folder and near the top add the following includes:

#include "PolyVoxCore/CubicSurfaceExtractorWithNormals.h"
#include "PolyVoxCore/MarchingCubesSurfaceExtractor.h"
#include "PolyVoxCore/SurfaceMesh.h"
#include "PolyVoxCore/SimpleVolume.h"
#include <cmath>

Now open <yourappname>Application.cpp. We're going to just copy the function to create a sphere in a volume from the tutorial. Copy the following function into your file and make sure it's above the createScene method.

void createSphereInVolume(SimpleVolume<uint8_t>& volData, float fRadius)
{
        //This vector hold the position of the center of the volume
        Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2);

        //This three-level for loop iterates over every voxel in the volume
        for (int z = 0; z < volData.getDepth(); z++)
        {
                for (int y = 0; y < volData.getHeight(); y++)
                {
                        for (int x = 0; x < volData.getWidth(); x++)
                        {
                                //Store our current position as a vector...
                                Vector3DFloat v3dCurrentPos(x,y,z);
                                //And compute how far the current position is from the center of the volume
                                float fDistToCenter = (v3dCurrentPos - v3dVolCenter).length();

                                uint8_t uVoxelValue = 0;

                                //If the current voxel is less than 'radius' units from the center then we make it solid.
                                if(fDistToCenter <= fRadius)
                                {
                                        //Our new voxel value
                                        uVoxelValue = 255;
                                }

                                //Wrte the voxel value into the volume
                                volData.setVoxelAt(x, y, z, uVoxelValue);
                        }
                }
        }
}

Now to set up the scene. Put the following in your createScene method:

    SimpleVolume<uint8_t> volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(63, 63, 63)));
    createSphereInVolume(volData, 30);

    SurfaceMesh<PositionMaterialNormal> mesh;

    //MarchingCubesSurfaceExtractor< SimpleVolume<uint8_t> > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh);
    CubicSurfaceExtractorWithNormals< SimpleVolume<uint8_t> > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh);

    surfaceExtractor.execute();
    cerr << mesh.getNoOfIndices() << ' ' << mesh.getNoOfVertices() << endl;

    // Set the scene's ambient light
    mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5f, 0.5f, 0.5f));

    //Create a ManualObject
    Ogre::ManualObject* manual = mSceneMgr->createManualObject("manual");

    //Begin a section of the ManualObject (we're only using one section)
    manual->begin("BaseWhiteNoLighting", Ogre::RenderOperation::OT_TRIANGLE_LIST);

    //Iterate through all the vertices in the mesh produced by the surface extractor
    //and add them to the ManualObject section.
    for(vector<PositionMaterialNormal>::const_iterator it = mesh.getVertices().begin(); it != mesh.getVertices().end(); ++it)
    {
        const Vector3DFloat& vertexPos = it->getPosition();
        const Vector3DFloat& vertexNorm = it->getNormal();
        manual->position(vertexPos.getX(),vertexPos.getY(),vertexPos.getZ());
        manual->normal(vertexNorm.getX(),vertexNorm.getY(),vertexNorm.getZ());
        manual->colour(abs(vertexNorm.getX()),abs(vertexNorm.getY()),abs(vertexNorm.getZ()));
    }

    //Now we iterate through all the indices from the mesh and also add them to the ManualObject section
    for(vector<uint32_t>::const_iterator it = mesh.getIndices().begin(); it != mesh.getIndices().end(); ++it)
    {
        manual->index(*it);
    }

    //End the section then add the ManualObject to the scenegraph
    manual->end();
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual);

    // Create a Light and set its position
    Ogre::Light* light = mSceneMgr->createLight("MainLight");
    light->setPosition(20.0f, 80.0f, 50.0f);

This is mostly a combination of the basic Ogre3D tutorial and the basic PolyVox tutorial code. The only thing I've added is the ManualObject which is how we convert the PolyVox mesh to one that's usable by Ogre. I used the absolute value of the normal vectors for vertex colours just to give it some detail so you can see the shape better.

You should be able to build that and run it and after selecting your video mode it should have a blocky sphere somewhere just up and to the right of where the camera is facing. You can use the mouse and wasd to move the camera around.

Updated