BlueGo 0.1.2 released!
POSTED ON 17.05.2013 13:06 by VERTEXWAHN
BlueGo 0.1.2 can now build Qt 5.0.2. It can be downloaded from here:
BlueGo0.1.2.zip.
There is also an installer available Bluego0.1.2.msi
BlueGo is a tool which builds Boost, Qt and OpenSceneGraph libraries using Visual Studio 2010/12. You just have to start the application, select
your configuration and hit the Build button- everything else works automatically. The application downloads the library, extracts it and builds it.
Do not reinvent the wheel. Use existing libraries like Qt, boost and OpenSceneGraph. It can be sometime cumbersome to integrate an existing
library, because you do not find the right prebuild libraries for your corresponding compiler or you do not know how to build a specific library
for your platform. In this case BlueGo in conjunction with a build tool like CMake can help you to get started fast and do not waste to mush time
in integration a library into your project.
The following build configurations are available:
- Supported platforms: x86, x64
- Supported compilers: Microsoft Visual Studio 2010, Microsoft Visual Studio 2012
- Supported Qt versions: 4.8.3, 4.8.4, 5.0.0, 5.0.1, 5.0.2
- Supported boost versions: 1.51.0, 1.52.0, 1.53.0
- Supported OpenSceneGraph versions: 3.0.1
More...
Older News
Towards a better Visual AssistX - Suggestions from a user
POSTED ON 12.05.2013 13:39 by VERTEXWAHN
There are many programming tasks that are trivial and should be automated.
Trivial Basic code generation
Implement interface/pure virtual methods
For instance if you derive form an interface you have to override all the methods. Assume the interface class (for instance called Demo) provides 15 methods. You have to copy paste these 15 methods and move them to your derived class (called for instance DummyClass). Since pure virtual methods have at the ending in C++ = 0; you have to remove 15 times = 0; form your code. That is a boring stupid task. I keep always watching you tube movies while doing things like this or listen to music. But hey can this not be automated? So I started to implement a small macro which handles this job. It automatically copies the interface methods for me and creates empty implementations.
This can be watched here:
I suggested this feature for Visual AssistX: http://forums.wholetomato.com/forum/topic.asp?TOPIC_ID=9429. BTW: I do not understand how anybody can use Visual Studio C++ without it.
Auto generated switch
There are many other tasks that could be simply automated. For instance switch statements:
enum eCompany
{
Audi,
BMW,
Cadillac,
Ford,
Jaguar,
Lexus
Maybach,
RollsRoyce,
Saab
};
Imaging you want to, depending on the company, print a logo. Like this:
void printLogo(const eCompany company)
{
swtich ( company)
}
In line 3 a smart assisted programming system could automatically suggest:
swtich ( company)
{
case Audi:
break;
case BMW:
break;
case Cadillac:
break;
case Ford:
break;
case Jaguar:
break;
case Lexus:
break;
case Maybach:
break;
case RollsRoyce:
break;
case Saab:
break;
}
Is that so hard for IDE developers to implement? No it is not. I think this could be done also quite easily with Visual Studio Macro. I also suggested this feature for Visual AssistX (http://forums.wholetomato.com/forum/topic.asp?TOPIC_ID=10321. UPDATE: this works now in Viual AssistX). Great feature!
Auto generated Copy Ctor and Assignment Operator
Most IDEs support generation of getter and setters (like Eclipse for Java). I think something similar should be done for Copy Constructors and Assignment Operators.
The idea: Click left on a class -> Select Generator Shallow Copy Constructor -> a Copy Ctor is automatically generated - similar assignment operators should be generated.
To clarify things I want to give a short example how I imagine that the generator should work. Consider this code:
class Mesh : public BaseMesh
{
public:
//! Default constructor.
Mesh();
//! Virtual destructor.
virtual ~Mesh();
std::vector<mesh_vertex> vertices;
std::vector<std::uint32_t> indices;
protected:
int id;
Transform m_Transform;
private:
};
After generate Ctor/Assignment:
class Mesh : public BaseMesh
{
public:
//! Default constructor.
Mesh();
//! Virtual destructor.
virtual ~Mesh();
std::vector<mesh_vertex> vertices;
std::vector<std::uint32_t> indices;
//! Assignement Operator
//! param[in] source Object that should be assigned to this one
Mesh& operator=( const Mesh& source )
{
// copy members from base class EntityObject
EntityObject::operator=(source);
// copy additional member from this class
vertices = source.vertices;
indices = source.indices;
MaterialID = source.MaterialID;
m_Transform = source.m_Transform;
return *this;
}
//! Ctor
//! param[in] source Object that should be copied
Mesh( const Mesh &source ) : EntityObject(source)
{
vertices = source.vertices;
indices = source.indices;
MaterialID = source.MaterialID;
m_Transform = source.m_Transform;
}
protected:
int id;
Transform m_Transform;
private:
};
This code is redundant in the assignment and CopyCtor:
vertices = source.vertices;
indices = source.indices;
MaterialID = source.MaterialID;
m_Transform = source.m_Transform;
Maybe there should be a private shallowSubclassCopy() method provided that does prevent code duplication:
Mesh::Mesh( const Mesh &source ) :
BaseMesh(source)
{
shallowSubclassCopy(source);
}
Mesh& Mesh::operator=( const Mesh& source )
{
// copy members from base class EntityObject
EntityObject::operator=(source);
// copy additional member from this class
shallowSubclassCopy(source);
return *this;
}
void shallowSubclassCopy( const Mesh &source )
{
vertices = source.vertices;
indices = source.indices;
MaterialID = source.MaterialID;
m_Transform = source.m_Transform;
}
Maybe you can make this optional with a checkbox. [x] Create private shallowSubclassCopy Method to prevent code duplication It is also common to use "copy swap" to implement the assignment operator - this works like this:
class string
{
public:
// ...
string &string::operator=(const string &source)
{
string temp( source ); // first make a copy of the source object
// now swap the internals of the copy with this object
std::swap( temp.str, str );
// just do the same for other internals members
std::swap( temp.m_ID, ID);
std::swap( temp.m_Transform, m_Transform);
// and so on...
return *this;
// destructor of temp is called - str pointer of tmp is deallocated
}
// ..
private:
char* str;
};
It would also be beneficial if the user can choose with a radio control which variant should generated:
( ) Memberwise Copy
(*) Copy Swap
I also sugggestd this for VisualAssistX: <http://forums.wholetomato.com/forum/topic.asp?TOPIC_ID=10202)
Since we have now also Move Semantics there should be also a similar feature to genrate move constructors and move assignment operators.
Intermidiate code geneartion
Remove unnecessary includes
It would be awesome if there would be a Remove unnecessary #includes - Feature for C++ I know this feature was often wished but it was too hard to implement. Why not choose a brute force approach to find out which includes are needed and which are not. When manually done you just comment out one #include after another and do a recompile to find out if a certain include file is really needed. Some time ago I thought about programming a small VB Macro within Visual Studio that just does this automatically - just find each line that contains a #include -> uncomment -> recompile -> if it worked -> just add a comment behind that header file like "VAssistX Detected, that this header file is not needed and commented it out for that reason" In simple cases this approach should work - the final result can look like this:
#include "car.h"
#include "wheel.h"
// #include "foo.h" /* VAssistX Detected, that this header file is not needed and commented it out for that reason */
#include "bar.h"
Things get more complicated if for example wheel.h needs to know something about car.h but car.h and wheel.h are not needed - what I mean is that both header files could be safely removed without a compilation error, but when only one header file is removed the simple brute force approach doesn't work.
What you really need to do is to uncomment all permutations of header files to find out what is really necessary and what is not
Example:
#include "h1.h"
#include "h2.h"
#include "h3.h"
#include "h4.h"
All permutations:
0000 (0 = comment header file out, 1 = leave it unchanged)
0001
0010
0011
..
1111
Some permutation can be skipped because one file can only depend on another if its included later than the file it depends on - also its more likely that depending header files are grouped together, so a combination of 110111111111111111011 is not as mush likely as 110011111111111111111.
Mabye you gather some statistical data from real world projects to find more common patterns - maybe you can allow the user to check for some patterns first.
Recompilation time shouldn't be a big problem (you change only one .cpp file and maybe it is possible to do parallel compilation)
There should be a dialog showing the currently checked header file code (110111111111111111011)
It should be possible to abort this brute force search. Even if it take a long time this is not a problem because it can be started when leaving work and run overnight - in the morning the ongoing search can be aborted and the results can be viewed.
I have real world project with moth than 30 includes in some implementation files. I am always too lazy to check out manually which header files are needed - I am sure there at least 5 files that are not needed but it
cost to mush time to find out which ones are not needed - the downside is that I have unnecessary dependencies in my code. (http://forums.wholetomato.com/forum/topic.asp?TOPIC_ID=10206).
What about code quality? Maybe you are claiming that every time automatic code generation works something is wrong with your software design. Maybe you are right. But there are some use cases where bad software design does not
matter. For instance when creating a throw away prototype.
I implement a very simple form of brute force header removement into BlueGo:
Some time ago I worked on a small program that does what I call assisted programming. It works like this: Imaging some programmer is looking over your shoulder while you are coding. The other programmer is not allowed to talk to you. The other programmer is only allowed to watch your activities and interrupt you at every point. If you are interrupted the other programmer overtakes your keyboard and makes a guess what you have been typed next and types it for you. Afterwards the keyboard is handed back to you and you can decide if you want to overtake the changes or not. This is impractical since a developer who watches your activities is expensive and is not faster in typing as yourself. But if the other programmer is replaced by a computer program that automatically detects patterns and tries to complete your source code it maybe becomes beneficial. See here my prototype. It is based on simple subsumption architecture:
Comments
Fun with hlsl2glsl
POSTED ON 03.02.2013 17:45 by VERTEXWAHN
Recently I played around with hlsl2glslfork. I tried to build it using CMake and Visual Studio 2012 x64. I run in several small problems. I removed hlslang/Include/ConstantUnion.h from CMakeLists.txt. Additionally I removed hlslang/MachineIndependent/parseConst.cpp. I also added hlslang/MachineIndependent/ConstantFolding.cpp to the CMakeLists.txt file. It seems also that bison generates Gen_hlslang_tab.cpp instead of hlslang_tab.cpp. I also fixed this. I removed D\"_HAS_ITERATOR_DEBUGGING=0\" /D\"_SECURE_SCL=0\" from the preprocessor defines. Finally everything worked as expected. I wrote small program to convert a HLSL Shader to GLSL:
bool ReadStringFromFile (const char* pathName, std::string& output)
{
FILE* file = fopen( pathName, "rb" );
if (file == NULL)
return false;
fseek(file, 0, SEEK_END);
size_t length = ftell(file);
fseek(file, 0, SEEK_SET);
if (length < 0)
{
fclose( file );
return false;
}
output.resize(length);
size_t readLength = fread(&*output.begin(), 1, length, file);
fclose(file);
if (readLength != length)
{
output.clear();
return false;
}
return true;
}
bool Hlsl2GlslTest()
{
Hlsl2Glsl_Initialize (NULL, NULL, NULL);
std::string inputPath = "C:/dev/SpriteBatch.hlsl";
ETargetVersion version = ETargetGLSL_ES_100;
std::string input;
if (!ReadStringFromFile (inputPath.c_str(), input))
{
printf (" failed to read input file\n");
return false;
}
ShHandle parser = Hlsl2Glsl_ConstructCompiler (EShLangVertex);
const char* sourceStr = input.c_str();
bool res = true;
bool kDumpShaderAST = true;
unsigned int options = 0;
if (kDumpShaderAST)
options |= ETranslateOpIntermediate;
int parseOk = Hlsl2Glsl_Parse (parser, sourceStr, version, options);
const char* infoLog = Hlsl2Glsl_GetInfoLog( parser );
}
Unfortunately hlsl2glsl only supports Direct3D 9 style HLSL shaders. I also investigated MojoShader (http://icculus.org/mojoshader/). But MojoShader has the same restrictions as hlsl2glsl - it does not support Shader Model 4 (introduced in DirectX 10).
Hardware Tessellation: HLSL vs. GLSL
POSTED ON 12.01.2013 17:43 by VERTEXWAHN
The HLSL way
Modern graphic cards provide hardware tessellation. In this tutorial I want to show how hardware tessellation can be achieved with HSLL via Direct3D 11 (feature Level 11.0 and above) and GLSL via OpenGL 4.2. In this article I will show a very simple tessellation shader which just does flat dicing. First we create a simple triangle.
const vector3f vertices [] = {
vector3f(0.0f, 0.75f, 0.0f),
vector3f(0.75f, -0.75f, 0.0f),
vector3f(-0.75f, -0.75f, 0.0f)
};
For simplicity the vertex shader will not do any transformation. It just passes the vertices through. This is how the triangle looks like without tessellation:
First we will consider how HLSL does tessellation. The Vertex shader just passes the vertices to the hull shader.
struct ApplicationToVertex {
float3 position : position;
};
struct VertexToHull {
float3 position : position;
};
VertexToHull VS_main (ApplicationToVertex app2vs) {
VertexToHull vtf = (VertexToHull)0;
vtf.position = app2vs.position;
return vtf;
}
Afterwards the hull shader hast to determine for each patch the inside and edge tessellation factors. This is done via a patch constant function (patchconstantfunc) called HS_TrianglesConstant in the shown source code. Furthermore the hull shader can tranform the patch control points. In this case we do not do any transformation to keep things simple. The control points are just passed to the fixed function Tessellation stage.
struct HullToDomain {
float3 position : position;
};
struct HS_ConstantOutput { // per patch output
float edgeTesselation[3] : SV_TessFactor;
float insideTesselation[1] : SV_InsideTessFactor;
};
HS_ConstantOutput HS_TrianglesConstant(InputPatch<VertexToHull, 3> ip) {
HS_ConstantOutput o = (HS_ConstantOutput)0;
o.edgeTesselation[0] =
o.edgeTesselation[1] =
o.edgeTesselation[2] = 4.0f;
o.insideTesselation[0] = 6.0f;
return o;
}
[domain("tri")]
[partitioning("fractional_even")]
[outputtopology("triangle_cw")]
[patchconstantfunc("HS_TrianglesConstant")]
[outputcontrolpoints(3)]
HullToDomain HS_main( InputPatch<VertexToHull, 3> I,
uint uCPID : SV_OutputControlPointID ) {
HullToDomain o = (HullToDomain)0;
o.position = I[uCPID].position;
return o;
}
Afterwards the domain shader computes for each subdivided point its new position.
struct DomainToFragment{
float4 position : SV_Position;
};
[domain("tri")]
DomainToFragment DS_main( HS_ConstantOutput HSConstantData,
const OutputPatch<HullToDomain, 3> I,
float3 barycentricCoords : SV_DomainLocation ) {
DomainToFragment O = (DomainToFragment)0;
// The barycentric coordinates
float U = barycentricCoords.x;
float V = barycentricCoords.y;
float W = barycentricCoords.z;
float3 position = I[0].position * W +
I[1].position * U +
I[2].position * V;
// Transform model position with view-projection matrix
O.position = float4 (position.xyz, 1.0);
return O;
}
Finally the pixel shader is called.
struct FragmentToPixel {
float4 color : SV_Target0;
};
FragmentToPixel PS_main (DomainToFragment vtf) {
FragmentToPixel final;
final.color = float4(1.0f, 0.0f, 0.0f, 1.0f);
return final;
}
The final output looks like this:
The GLSL way
Now we can consider the GLSL way of archiving the same result. The vertex shader again passes the vertices to the tessellation control shader stage.
#version 400
in vec3 Position;
out vec3 vPosition;
void main() {
vPosition = Position;
}
The control tessellation shader computes the inner an outer tessellation factors. Interesting to see here is that GLSL does not have something like a patch constant function. Similar the HLSL version the shader passes the control point to the fixed function tessellation primitive generator.
#version 400
layout(vertices = 3) out;
in vec3 vPosition[];
out vec3 tcPosition[];
#define ID gl_InvocationID
void main() {
tcPosition[ID] = vPosition[ID];
if (ID == 0)
{
gl_TessLevelOuter[0] =
gl_TessLevelOuter[1] =
gl_TessLevelOuter[2] = 4.0f;
gl_TessLevelInner[0] = 6.0f;
}
}
The tessellation evaluation shader computes the final positions of the subdivided geometry.
#version 400
layout(triangles, equal_spacing, cw) in;
in vec3 tcPosition[];
out vec3 tePosition;
void main() {
vec3 p0 = gl_TessCoord.x * tcPosition[0];
vec3 p1 = gl_TessCoord.y * tcPosition[1];
vec3 p2 = gl_TessCoord.z * tcPosition[2];
tePosition = p0 + p1 + p2;
gl_Position = vec4(tePosition, 1);
}
Finally the color is written by the pixel shader for each fragment.
#version 400
out vec4 FragColor;
void main() {
FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);
}
Final output of GLSL:
More detailed information
Fun with Boost and CMake
POSTED ON 27.11.2012 00:48 by VERTEXWAHN
Boost Version 1.48.0 has been released on November 15th. Also a new release of CMake has been published around this date (on January 02, 2012). Because I started a new project I decided to use the latest tools available. So I downloaded boost 1.48.0 and extracted into a folder. Afterwards I started the Visual Studio 2010 x64 command prompt, switched to the boost directory and just entered bootstrap followed by bjam -j4. Since my machine has 4 cores I wanted bjam to use all available cores.
bootstrap
bjam -4
After some time bjam reports that it has build boost successfully. Next I starded cmake-gui and selected a CMake based project that has a dependency to the boost library (FIND_PACKAGE(Boost 1.48.0 COMPONENTS filesystem REQUIRED)). I entered the boost directory path and hit the "Configure" button. Then an error message is displayed: "Error in configuration process, project files may be invalid". Unfortunately CMake does not tell me what exactly went wrong - it just says invalid. That is pretty annoying. More appropriate would by "Macro xy in FindBoost failed because of ...". Invalid project configuration could be nearly everything. After commenting out the line FIND_PACKAGE(Boost 1.48.0... in the CMakeList file the error disappears and everything works fine again. So the error comes and goes with the FIND_PACKAGE command. Maybe something went wrong in the build. Then I tried to build boost as described here: https://sites.google.com/site/jmargeta/random
.\bootstrap.bat
.\b2 address-model=64 --build-type=complete stage
Another 15 minutes later I tried to setup CMake again, but no
success - finally I found out what I did wrong. I set the
Boost_DIR Variable to the boost directory, but instead of this one
have to set the BOOST_INCLUDE_DIR variable - it was a lot of pain
to find this out. In the end I wasted a whole day.
Less painful CMake
POSTED ON 25.11.2012 04:28 by VERTEXWAHN
Currently, I am considering simplifying the use of CMake. In the future I will integrate a basic version of my idea into BlueGo. You are presented the same GUI as in CMake GUI. You select the source and the build path. You also select a compiler and a platform. Then you hit the "Go" button which than generates for instance a Visual Studio 2010 project. The difference to CMake here is that you do not need to select the paths of third party libraries. The third party libraries are downloaded and build in the background after hitting the "Go" button. For sure this can take some while. For instance on my main development machine it takes about 6 hours to build Qt and boost. But it is also possible to offer prebuild libraries which will make this step faster. In an improved CMake you do not need to figure out that you have to set the BOOST_ROOT_DIR to the boost directory or that the QT_QMAKE_EXECUTABLE has to be set to C:/thirdparty/vs2010/x64/qt-everywhere-opensource-src-4.8.3/bin/qmake.exe. This will make it possible for developers that have no experience for instance with boost to test the library without the burden of finding out how to build it and how to integrate it in their IDE. Think of world in which you can use every library you want without wasting time to find out how to build it and how to integrate it into your IDE. Linux provides for this reason a package manager but something similar is missing for Windows.
D3DX replacements
POSTED ON 01.10.2012 11:46 by VERTEXWAHN
Since DirectX SDK is part of the Windows SDK D3DX is not any longer supported. If you install also the DirectX
June 2010 SDK you can still use the "old" D3DX libraries and call functions like D3DX11SaveTextureToFile.
But there is a problem with functions like D3DXCompile*, D3DX10Compile*, and D3DX11Compile*. If you use these
functions to compile HLSL code you will use an incorrect older version of the HLSL compiler. So in this post
I want to show you what I did to port my code away from D3DX.
BTW: The Windows SDK can be downloaded from http://msdn.microsoft.com/en-us/windows/desktop/aa904949.
I did not verify if the Windows 8 SDK also works on Windows 7.
First of all math stuff like D3DXMatrixPerspectiveFovRH can be found in the replacement library DirectXMath (formerly called XNAMATH)
which offers for instance XMMatrixPerspectiveFovRH. I search for a replacement for D3DX11SaveTextureToFile. A replacement can be found
in the DirectXTex library - see SaveToDDSFile, SaveToTGAFile (http://directxtex.codeplex.com).
DirectXTex is really nice, but I came up with my own implementation:
// replacement for D3DX11SaveTextureToFileture2D
// create a temporary texture object which is CPU accessible
D3D11_TEXTURE2D_DESC Desc;
// get ArraySize, Format, Width, Height and MipLevels from source texture
m_pTexture2D->GetDesc(&Desc);
Desc.BindFlags = 0;
Desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
Desc.MiscFlags = 0;
Desc.SampleDesc.Count = 1;
Desc.SampleDesc.Quality = 0;
Desc.Usage = D3D11_USAGE_STAGING;
ID3D11Texture2D* NewTexture = nullptr;
HRESULT hr = m_pRenderer->getDevice()->CreateTexture2D( &Desc, nullptr, &NewTexture );
BLUE_ASSERTEx(hr == S_OK, "Create Texture2D failed.");
// copy texture to our temporary texture
m_pRenderer->getImmediateContextD3D()->CopyResource(NewTexture, m_pTexture2D);
// copy texture data to an array
D3D11_MAPPED_SUBRESOURCE Resource;
hr = m_pRenderer->getImmediateContextD3D()->Map( NewTexture, 0, D3D11_MAP_READ, 0, &Resource );
BLUE_ASSERTEx(hr == S_OK, "Map failed.");
const int32_t Size = getWidth() * getHeight() * 4; // size in bytes
int8_t* ImageData = new int8_t[Size];
std::memcpy( ImageData, Resource.pData, Size );
m_pRenderer->getImmediateContextD3D()->Unmap( NewTexture, 0 );
BLUE_ASSERTEx(hr == S_OK, "Unmap failed.");
SAFE_RELEASE( NewTexture );
// now store the image
// ...
// free reserved memory
delete ImageData;
D3DX11CompileFromFile is also deprected. The MSDN suggest to compile shaders offline using Fxc.exe or to use the D3DCompile* functions. The interesting thing here is that Windows Store apps are not allowed to use D3DCompile* functions. Application that contain D3DCompile* functions can be used during development but cannot be distributed as Windows Store apps. Fortunately the DXSDK contains a very similar function called D3DCompileFromFile. I just replaced
hr = D3DX11CompileFromFile(
p_sFilename,
pDefines,
nullptr,
p_sEntryPointName,
ShaderProfile<t_ShaderType>(),
dwShaderFlags,
0,
NULL,
&l_pBytecode,
&l_pErrors,
nullptr);
by
hr = D3DCompileFromFile(
p_sFilename,
pDefines,
D3D_COMPILE_STANDARD_FILE_INCLUDE,
p_sEntryPointName,
ShaderProfile<t_ShaderType>(),
dwShaderFlags,
0,
&l_pBytecode,
&l_pErrors
);
and everything was working again.
References:
Some tests of the new content creation system
POSTED ON 15.06.2012 16:07 by VERTEXWAHN
Some tests of the new content creation system:
Testing LaTeX:
Testing source code formating:
port sys
from PyQt4.QtGui import *
app = QApplication(sys.argv)
button = QPushButton("Hello World", None)
button.show()
app.exec_()
How to find out if Service Pack 1 for Visual Studio is installed
POSTED ON 15.06.2012 15:48 by VERTEXWAHN
Just click 'Help'->'About Microsoft Visual Studio' and you will see the following dialog:
Should I derive private or public from boost::noncopyable?
POSTED ON 15.06.2012 15:47 by VERTEXWAHN
You don't want people making a function like:
void profoundlyUselessFunction(const boost::noncopyable &)
{
// ...
}
The typical use of boost::noncopyable is a "implemented in terms of" relationship, which is best modeled by inheriting privately.
From a technical standpoint, since everything interesting in boost::noncopyable is private already, whether you inherit publicly or privately makes very little difference.
Also very interesting: http://stackoverflow.com/questions/4829696/why-does-boostnoncopyable-require-inheritance.
How to build wxWidgets 2.9.3 with Visual Studo 2010 x64?
POSTED ON 10.05.2012 12:00 by VERTEXWAHN
- Download wxWidgets-2.9.3.zip from http://sourceforge.net/projects/wxwindows/files/2.9.3/
- Extract zip to a folder
- Open Microsoft Visual Studio 2010 x64 tools command prompt
- Change directory in VS command prompt to to the extracted folder (e.g. cd C:\thirdparty\wxWidgets-2.9.3-x64)
- Build shared debug libraries: nmake -f makefile.vc UNICODE=1 BUILD="debug" SHARED=1
- Build shared release libraries: nmake -f makefile.vc UNICODE=1 BUILD="release" SHARED=1









