Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / OpenGL

Introduction to OpenGL with C/C++ on ReactOS

5.00/5 (13 votes)
10 May 2021CPOL24 min read 23.5K  
Check whether ReactOS is able to run OpenGL, determine a convincing IDE and get started with the OpenGL on ReactOS.
This article shows the possibilities of OpenGL in ReactOS, how to select a suitable development environment (IDE) for C/C++, create code documentation and finish with a simple OpenGL application. Also take the first steps towards documentation with DoxyGen.

Table of Contents

  1. Introduction
  2. Selection of the Development Environment
  3. Adding a documentation generator
  4. Using the Code
  5. Points of Interest
  6. History

Introduction

ReactOS is an open source alternative to the Windows operation system. Even if the first version of ReactOS dates back to 1998, there is still no 'stable' version of ReactOS. May be, the most important reason is a lack of attention.

I have been watching the development of React OS for some time. My preferred language is C# - so my first closer look at ReactOS was to investigate whether C# runs on ReactOS. And yes, it runs. Details how to set up ReactOS, how to avoid pitfalls/minimize the trouble installing C# and how get C# running can be found within the tip Introduction to C# on ReactOS.

With this tip, I would like to introduce how to compile and run a first very simple C/C++ OpenGL application at a current ReactOS version. (I go back from my fovoutite programming language C# to my roots - namely C/C++, because the native OpenGL API is written in C and I want to avoid any possible side effect.)

Since I am almost exclusively working with MS Windows in my job and don't want to deal with different hardware, the only way I can think of is to run ReactOS in a virtual machine. In addition, the ReactOS homepage also advises against the productive use of ReactOS. My favorite virtual machines are Oracle VirtualBox and VMWare Player - both are free for private use. The current ReactOS version 0.4.11.

OpenGL Support with build-in Video Drivers

There are a lot of tools to check the OpenGL capabilities of a running Windows installation. Unfortunately, these tools regularly assume a top modern and well maintained Windows installation - because they are mainly aimed at gamers. I found just two tools to check the OpenGL capabilities, that were able to run on ReactOS (that authenticates itself as an outdated Window version).

The first and easier tool is GPUShark by Jerome Guinot. I used the version 0.14.1.0.

The second tool is GPU-Z by TechPowerUp. I used the version 2.25.0.

VMWare Player

VMWare Player (I used VMWare Player version 12.5.9) provides only the build-in VGA compatible virtual graphic card, the only option is to switch the 3D accelleration on or off.

GPUShark reports the same result for 3D accelleration on and off - I guess it is because the standard VGA driver, that is build-in in ReactOS, doesn't use 3D acceleration:

Image 1


  • Update: On VMWare Player version 15.5.6 the ReactOS version 0.4.13 provides 2 extensions.

GPU-Z also reports the same result for 3D accelleration on and off:

Image 2

In summary, I would consider the combination of VMWare Player version 12.5.9 and ReactOS 0.4.11 as very unstable and wouldn't recommend it. This combination has in particular difficulties with switching between 3D acceleration on and off and wit the installation of GPU-Z. Under these circumstances I would prefer Oracle VirtualBox.


  • Update: With VMWare Player version 15.5.6 and ReactOS version 0.4.13 the stability problems seem to be overcome.
  • Hint: Check out the best combination of processor feature virtualization. See Virtual Machine Settings | Hardware | Processors | Virtualization engine.

Oracle VirtualBox

Oracle VirtualBox (I used VirtualBox version 6.0.10) supports three virtual graphic cards: VBoxVGA, MSVGA and VBoxSVGA.

GPUShark reports the same result for all three virtual graphic cards:

Image 3


  • Update: On Oracle VirtualBox version 6.1.10 the ReactOS version 0.4.13 provides 2 extensions.

Furthermore, Oracle VirtualBox offers the possibility to simulate a 3D acceleration for the virtual graphic card. But the result is the same with 3D acceleration switched on and off - I guess it is because the standard VGA driver, that is build-in in ReactOS, doesn't use 3D acceleration.

GPU-Z does not recognize any graphics device information. It reports the same result for all three virtual graphic cards as well, no matter whether 3D acceleration is switched on or off:

Image 4

In summary, I would consider the combination of Oracle VirtualBox version 6.0.10 and ReactOS 0.4.11 as very stable and would recommend it.

Abstract

The bottom line for the build-in video drivers is that ReactOS supports OpenGL version 1.1 in any scenario through CPU simulation without OpenGL extensions, using a selected, very basic, functionality from the great Mesa library (probably only in an antique version). This will be enough to play around a little with OpenGL. But serious OpenGL applications - especially because important extensions like FramebufferObject are missing - can' t be realized with this OpenGL version 1.1.

OpenGL Support with advanced Video Drivers

Again I test the OpenGL capabilities with GPUShark and GPU-Z.

VMWare Player

VMWare Player offers the option to install VMWare tools, which contain various utilities and drivers, including an SVGA II graphics driver. I strongly recommend to use the preVista VMWare tools and to install as few drivers as possible - in my case I only install the SVGA II graphics driver. WARNING: Don't be confused by the fact that VMWare Tools tries to install all drivers and reports an error during the installation of the printer driver. With some patience the setup will run through after confirming the error message.
 

GPUShark reports the same result for 3D accelleration off as before installing the VMWare tools:

Image 5


  • Update: On VMWare Player version 15.5.6 the ReactOS version 0.4.13 provides 2 extensions.

After switching 3D accelleration on GPUShark reports:

Image 6

The ReactOS Application Manager offers a Mesa 3D Graphics Library 17.0.1 installation. The Mesa installation extends the OpenGL capabilities once again to:

Image 7

GPU-Z runs with 3D accelleration off only and reports:

Image 8

ReactOS 0.4.11 hangs if GPU-Z is started with 3D accelleration on.

The situation is completely different after a Mesa installation:

Image 9

Overall, after installing the SVGA II drivers and Mesa, ReactOS seems to run more stable under VMWare Player - but from what I've seen so far, I don't really trust it. An intensive test before using this environment intensively is certainly advisable.


  • Hint: Check out the best combination of processor feature virtualization. See Virtual Machine Settings | Hardware | Processors | Virtualization engine.

Oracle VirtualBox

The Oracle VirtualBox offers the option to install guest additions. These extensions include an advanced video driver. The Oracle VirtualBox player's menu supplies Devices | Insert Guest Additions CD image and the CD provides the "VBoxWindowsAdditions-x86.exe". But be careful with the installation and any changes of the virtual hardware after installation:

  • I strongly recommend to backup the virtual HDD before Windows additions installation. - It is almost impossible to uninstall the Windows additions without crashing the VirtualBox image.
  • I cannot recommend to switch between the virtual graphic cards VBoxVGA, MSVGA and VBoxSVGA after Windows additions installation. My VirtualBox image crashed after a switch to MSVGA from any other virtual graphic card - may be the Windows additions require the VBoxVGA or VBoxSVGA to work properly.
  • Focus on the VBoxVGA virtual graphic card with 3D support. The MSVGA virtual graphic card seems not to cooperate with the Windows additions and the VBoxSVGA virtual graphic card seems not to pass through the 3D acceleration to the guest system. In addition, the VBoxVGA virtual graphic card with 3D support provides various video modes up to a resolution of 1920x1200 - quite enough for my needs at the moment.

As long as the 3D acceleration for the VBoxVGA virtual graphic card is switched off, GPUShark and GPU-Z report the same as shown for the build-in Video Drivers.

Image 10


  • Update: On Oracle VirtualBox version 6.1.10 the ReactOS version 0.4.13 provides 2 extensions.

After switching 3D accelleration on GPUShark reports:

Image 11

The Mesa installation extends the OpenGL capabilities once again to:

Image 12

GPU-Z again does not recognize any graphics device information mo matter whether Mesa is installed or not:

Image 13

Abstract

The bottom line for advanced Video Drivers is, ReactOS supports OpenGL version 2.1 with 72 extensions through VMWare Player's VMWare tools as well as through Oracle's VirtualBox guest additions. This should be enough to realize serious OpenGL applications - in the hope that important extensions like FramebufferObject are included within the 72 extensions.

Even more possibilities are available after installing Mesa 3D Graphics Library 17.0.1. In that case ReactOS actually supports OpenGL version 3.0 with 217 extensions through VMWare Player's VMWare tools as well as through Oracle's VirtualBox guest additions.

Selection of the Development Environment

I've checked these development environments...

Code Lite

CodeLite is a free and open-source (GitHub) full-featured cross platform IDE, distributed under the GNU General Public License V2.0, for C, C++ and other languages (developed by Eran Ifrah).

The current CodeLite version is 13.0, it has been released in Nov 2018 and stabilized in May 2019. But it can't be installed on ReactOS (seems, it is no longer compatible with Windows version 5.2 / WindowsXP).

Instead CodeLite versions 11.0 and 12.0 can be installed on ReactOS.

CodeLite version 11.0 has been released in Oct 2017, CodeLite version 12.0 has been released in Feb 2018. I have tested CodeLite version 12.0. Download and installation runs smoothly.

During installation CodeLite installer scans for pre-installed compiler/build environments and offers the matches for registration, or suggests the installation of "mingw-w64-install.exe". I have registered my pre-installed compiler/build environment "TDM-GCC Compiler Suite for Windows / GCC 5 Series / MinGW 32-bit Edition" at the first go.

I have also tested the installation of "mingw-w64-install.exe". Download and installation runs smoothly. The installer contains the compiler/build environments for 32 and 64 Bit as well as for posix and Win32 with version 8.1.0 and also several older versions down to 4.9.4. I have chosen "Mingw-W64 - i686-8.1.0 - Win32 / GCC 7.3.0". Installation and registration went well.

There is no project template for Win32 C/C++ nor for OpenGL C/C++ (see image 1). Instead, I've created a minimalistic console application and compiled it successfully but was unable to start it - with both currently registered compiler/build environments (TDM GCC 5 Series and MinGW-W64 GCC 7.3.0).

CodeLite's compiler/build environment can also be changed/supplemented later via the menu Settings | Build Settings menu.

Since CodeLite recommends "MinGW GCC 7.1.0", I also installed this compiler and successfully registered it to CodeLite (see image 2). I got the same result for this compiler/build environment as well: My minimalistic console application compiled successfully again (MinGW-W64 GCC 7.1.0), but I was unable to start it.

The error message was the same in all three cases: The application has failed to start because libgcc_s_dw2-l.dll was not found. Re-installing the application might fix this problem.

In addition to that, unfortunately the GUI has many display/display update errors (see image 3). This is especially true for tool bars, drop-down lists and list-views, that are transparent and show the background or outdated content.

All in all, the GUI is not very reactive, I don't feel comfortable working with a GUI full of display/display update errors and in combination with the missing project templates for Win32 C/C++ and for OpenGL C/C++. I don't think I'll be productive with it on ReactOS. That's why I stopped looking for a solution to the error message.

Image 14

Image 15

Image 16


  • Update regarding MinGW: I've also tested MinGW 8.2.0.5. It can be downloaded from https://osdn.net/projects/mingw/releases -> Package MinGW.org Compiler Collection (GCC) as gcc-c++-8.2.0-5-mingw32-bin.tar.xz. I extracited the package to C:\MinGW and CodeLite immediately detected the existence of the compiler during the scan.
  • Update regarding ReactOS 0.4.12: CodeLite version 13.0 still cannot be installed. The CodeLite version 12.0 display errors are still present.

So I decided to continue looking for another suitable IDE.

Dev-C++

Dev-C++ is a free full-featured Windows platform IDE, distributed under the GNU General Public License V2.0, for C, C++ and other languages. Currently, there are two - more or less active - forks.

The first one is Bloodshed Dev-C++ (developed by Johan Mes et. al.). The current version is 5.8.3 and has been released in Nov 2014.

The second one is wxDev-C++ (developed by Colin Laplace et. al.). The current version is 7.4.2 and has been released in Jan 2017.

I decided to install Bloodshed Dev-C++ from file "Dev-Cpp 5.8.3 TDM-GCC 4.8.1 Setup.exe". Download and installation of Bloodshed Dev-C++ version 5.8.3 runs smoothly - I've selected the full installation including the TDM-GCC 4.8.1. It is absolutely no challenge to configure the compiler/build environment - the setup configuration works immediately.

There is a project template for Win32 C/C++ (see image 1) as well as for OpenGL C/C++ (see image 2). I've created two minimalistic applications - one from each of the above mentioned project templates. The generated boilerplate code compiled and ran successfully at the first go.

The GUI is easy, uncluttered, very reactive and all controls work without any display/display update error - it is a pleasure to work with it.

But solutions, that organize multiple projects, are unknown to Dev-C++. This is a drawback if you want to reduce the complexity of large applications by splitting off DLLs.

I think Dev-C++ is a very good IDE for compact applications - but I'm afraid that splitting of DLLs will increase the effort.

Image 17

Image 18

So I decided to continue looking for another suitable IDE.

NetBeans IDE

NetBeansIDE is a free full-featured cross platform IDE, distributed under the Apache License V2.0, for Java, C, C++ and other languages. Since NetBeansIDE is completely based on Java, the availability of a suitable Java runtime environment (JRE) and development kit (JDK) is essential. The latest available 32 Bit JDK (JavaSE) version is JDK 8, the highest recommended NetBeans IDE version for JDK 8 is version 8.2. To run the installer of the NetBeans IDE 8.2, an installed JRE 8 is required.

ReactOS offers the installation of a "Java SE Runtime Environment 8" within it's Applications Manager. This installation may need a second try to succeed - but after a successful installation, the NetBeans IDE 8.2 installer can be started. During the installation, the path to the JDK is queried - without a possibility to skip this specification. Therefore, a preparatory JDK installation is unavoidable.

Currently, a JDK 8 can only be obtained via the official ORACLE download, which requires an ORACLE account and the disclosure of a lot of personal information. For just a test, this seems to be too excessive to me and I abort the test with the NetBeans IDE 8.2.

So I have to go on looking for another suitable IDE.

GeanyIDE

GeanyIDE is a free and open-source (GitHub) full-featured cross platform IDE, distributed under the GNU General Public License V2.0, for C, C++ and other languages.

The current GeanyIDE version is 1.35, it has been released in Apr 2019. Download and installation of GeanyIDE version 1.35 runs smoothly - but it can't be started. The error message is: The procedure entry point GetTickCount64 could not be located in the dynamic link library KERNEL32.dll.

The same can be said about GeanyIDE version is 1.34, that has been released in Dec 2018. Here, the error message is: The procedure entry point GetFileInformationByHandleEx could not be located in the dynamic link library KERNEL32.dll.

For GeanyIDE version 1.33, that has been released in Feb 2018, and GeanyIDE version 1.32, that has been released in Nov 2017, the error message is: The procedure entry point _time32 could not be located in the dynamic link library msvcrt.dll. The installation of Microsoft Visual C++ 2015-2019 Redistributable (x86) doesn't change anything.

GeanyIDE version 1.31, that has been released in Jul 2017, and GeanyIDE version 1.30, that has been released in Mar 2017, can be started - but immediately after the appearance of the IDE the CPU is fully loaded, the wait cursor is shown and the IDE does not react to any user input.

So I have to go on looking for another suitable IDE.

Ajunta Dev Studio

The Ajuta Dev Studio is a free and open source (GitLab) versatile IDE, distributed under the GNU General Public License V2.0, for C, C++ and other languages (developed by a team of enthusiasts). This IDE is unfortunately not available for the Windows platform.

GNAT Programming Studio

The GNAT Programming Studio community edition is a free full-featured cross platform IDE for ADA, C/C++ and other languages (developed by AdaCore). The current GNAT Programming Studio version is 2019, but it is available for 64 Bit only. The latest 32 Bit version is 2017 and comes with the installer "gnat-gpl-2017-x86-windows-bin.exe".

Download and installation runs smoothly. After the installation of almost 2 GByte size, the start of GPS.exe ends up with this error message: The application failed to initialize properly (0xc00000142). Click OK to terminate the application.

Visual Studio Code

Visual Studio Code is a free versatile cross platform IDE by Microsoft, distributed under a proprietary license. The current Visual Studio Code version is 1.38. It is not running on ReactOS. The error message is: This program does not support the version of Windows your computer is running.

Ultimate++

The Ultimate++ is a free and open-source (SVN) full-featured cross platform IDE, distributed under the BSD 2-clause license ("Simplified BSD License" or "FreeBSD License"), for C, C++ and other languages.

The current Ultimate++ version is 2019.1, it has been released in Nov 2018 and stabilized in May 2019. I've chosen the portable version "upp-mingw-13068.7z". Download and extraction runs smoothly. After extracting, Ultimate++ can be started with "theide32.exe".

At first, I wanted to get familiar with Ultimate++ and looked at one existing package. I chose "Bombs" from the collection of examples - but already during the selection of the package, Ultimate++ has frozen my VirtualBox image. I repeated this five times - three with the same result. Two times, I was able to open the "Bombs" example, compile and run it.

However, I managed to create a minimal Win32 application from the "Win32 API project (no U++)" template and got it compiled and running at the first go.

Afterwards, I replaced the generated boilerplate code of the template against a minimalistic Win32 OpenGL application code and added the opengl32 library to the libraries list via menu Project | Package organizer.

After several crashes during the creation of this application, the suspicion seems to be confirmed that the VirtualBox image always freezes when a fly-over help is faded in.

All in all, the biggest disadvantage of Ultimate++ is that the GUI often freezes the VirtualBox image. I don't think I'll be productive with it on ReactOS.

Image 19

So I decided to continue looking for another suitable IDE.

Code::Blocks

Code::Blocks is a free and open-source (SVN) full-featured cross platform IDE, distributed under the GNU General Public License V3.0, for C, C++ and other languages (developed by a team of enthusiasts).

The current Code::Blocks version is 17.12, it has been released in Dec 2017. There are newer nightly builds available for download. I followed the recommendation and chose "codeblocks-17.12mingw-setup.exe". Download and installation runs smoothly. After installation Code::Blocks can be started with "CodeBlocks.exe".

The included compiler/build environment "TDM-GCC Compiler Suite for Windows / GCC 5 Series / MinGW 32-bit Edition" is configured and ready to go immediately after the Code::Blocks installation.

Code::Blocks offers the widest selection of project templates of all IDEs examined so far. I choose the "OpenGL" template and the generated boilerplate code compiled and ran successfully at the first go.

Now of course, I wanted to try GLEW as well. Since ReactOS only supports OpenGL version 2.1, I decided to use the highest version number before GLEW started to support OpenGL 3.0 - hence for GLEW 1.5.0. I have downloaded "glew-1.5.0-win32.zip" and installed it exactly according to the instructions. Adding the library to the linker was a bit tricky. You have to select the context menu Properties from the desired project to open the Project/targets options dialog and press the Project's build options... button on the first page Project settings. Within the Project build options dialog, the second page Linker settings provides the settings you need.

To enable debugging, the Debugger Settings dialog must be started from menu Settings | Debugger and within tree node Default the Executable path must be set. Even if Code::Blocks has several GDBs installed - only the GDB within the path "<installation root>\MinGW\gdb32\bin\gdb32.exe" works for me.

The only disadvantage I can see regarding Code::Blocks is the long loading time of the IDE. But that's okay, because the GUI is richly equipped and very reactive - it is a pleasure to work with it. Nevertheless, I never had a crash or VirtualBox image freeze during the whole time I was working with Code::Blocks.

Code::Blocks is able to combine several projects into one solution, can keep multiple projects open at the same time and supports splitting off DLLs to reduce the complexity of large applications.

All in all, the GUI is very reactive and all controls work without any display/display update error. I'm sure I'll be productive with it on ReactOS.

Image 20

Image 21

I think, this is the most suitable IDE for me and I stop checking development environments.

Conclusion

Only Dev-C++ and Code::Blocks can convince me. While Dev-C++ gives me the impression to be a slim and very fast IDE for small projects "in between", Code::Blocks seems a bit more heavy and powerful.

Adding a documentation generator


  • Update: I have been working with Code::Blocks for several months now. Here I would like to report briefly about the positive surprises I have experienced with DoxyGen.

I admit - I am a programmer of the old school. A reasonable API documentation is important to me. I don't like statements as

  • "The names of the parameters say it all." or
  • "Look at the unit tests if you want to know how the class is used or the method is called."

very much. I want to know whether a parameter can be set to 0/null/NULL and how the method will behave in this case. Does the method assume any fallback values? Can the return value be 0/null/NULL and how is that to be assessed - as an error?

My "home" is C#. That's why I'm very familiar with the XML comments and use it intuitively - unfortunately without thinking in my C++ code in Code::Blocks as well. This is a sample:

C#
/// <summary>
/// Gets the currently registered frame edge.
/// </summary>
/// <returns>The currently registered frame edge on success, or <c>0</c> otherwise.</returns>
UINT GetFrameEdge();

The #1 product for automatic generation of documentation is DoxyGen. A first attempt to install an actual GoxyGen version on ReactOS failed as expected (error message from the Windows shell). I only gave myself a limited time for a second attempt, and so I selected "doxygen-1.8.3.1.windows.bin.zip", unzipped it to a sub-folder within the Code::Blocks installation path and configured it in DoxyBlocks | Open preferences ... menu.

A positive surprise

At first I only wanted DoxyGen to run through and I had already resigned myself to the fact that I had to change the XML comments to compatible exclamation mark comments with a lot of effort - especially since the DoxyGen version is of January 2013.

When I saw the result, I was completely amazed. My XML comments have been converted into a very clean documentation with only the basic settings of DoxyGen (except the path to "doxygen.exe" I did not configure anything):

Image 22

A few quick tips

No self references needed

It is not necessary to set self-references (like <see cref="OgwwBlank"/>) within a class file. The following two comment lines create exactly the same documentation:

C#
/// The <see cref="OgwwBlank"/> class serves as an canvas for OpenGL or an universal empty window with or without frame.

/// The OgwwBlank class serves as an canvas for OpenGL or an universal empty window with or without frame.

And this is, how the compiled help kooks like:

Image 23

Formatting

  • Code formatting tags work fine (like <c>NULL</c>).
  • Multiple lines in comments can be created with <br/>.

Lists

Simple lists in comments can be created with <list>...<item>...</item>...</list>. The following comment lines create a sample list:

C#
/// <remarks>Supported values are the ::DrawEdge() edges<br/>
/// <list type="bullet">
/// <item>BDR_RAISEDINNER - Raised inner edge.</item>
/// <item>BDR_SUNKENINNER - Sunken inner edge.</item>
/// <item>BDR_RAISEDOUTER - Raised outer edge.</item>
/// <item>BDR_SUNKENOUTER - Sunken outer edge.</item>
/// <item>EDGE_BUMP       - Combination of BDR_RAISEDOUTER and BDR_SUNKENINNER.</item>
/// <item>EDGE_ETCHED     - Combination of BDR_SUNKENOUTER and BDR_RAISEDINNER.</item>
/// <item>EDGE_RAISED     - Combination of BDR_RAISEDOUTER and BDR_RAISEDINNER.</item>
/// <item>EDGE_SUNKEN     - Combination of BDR_SUNKENOUTER and BDR_SUNKENINNER.</item>
/// </list>
/// <remarks>

And this is, how the compiled help list kooks like:

Image 24

Tables

Simple tables comments can be created with <list type="table">...<item>...<term>...</term>...<description>...</description>...</item>...</list>.

C++
/// <param name="iImageListType">Type of image list to set.
/// This parameter can be one of the following values:
/// <list type="table">
/// <item><term><c>TVSIL_NORMAL</c></term>
/// <description>Indicates the normal image list, which contains selected, non-selected, and
/// overlay images for the items of a tree-view control.</description></item>
/// <item><term><c>TVSIL_STATE</c></term>
/// <description>Indicates the state image list. You can use state images to indicate
/// application-defined item states. A state image is displayed to the left of an item's
/// selected or non-selected image.</description></item>
/// </list>
/// </param>

And this is, how the compiled help list kooks like:

Image 25

Source file documentation

  • DoxyGen evaluates header (h/hpp) AND code files (c/cpp). If both are maintained, duplicates are created in the documentation if the comments in header and code file are not absolutely identical. Therefore only header (h/hpp) OR code files (c/cpp) should be maintained. The advantage of documentation in the header files is that you can also document class-internal types in this case. An advantage of documentation in the code files is that code comments can also be documented in this case. I have decided to maintain the header files.
  • Different comment styles (XML comments, exclamation mark comments, ...) can be mixed within one file. The following comment lines show s sample with XML comments <summary> and <remarks> as well as exclamation mark comments //!<:
C#
/// <summary>
/// A structure that is used to carry WM_PAINT message supporting window object data and is stored referenced by window.
/// </summary>
/// <remarks>
/// Should be created via ::GlobalAlloc() during WM_NCCREATE message and destroyed via ::GlobalFree() during WM_DESTROY message.
/// Can be accessed cia ::SetWindowLongPtr() and ::GetWindowLongPtr().
/// </remarks>
typedef struct tagBLANKEXTRADATA
{
    BOOL   edOwnerDraw;  //!< Flag whether this window object is ownerdrawn (or not).
    HBRUSH edBackBrush;  //!< Buffer the handle to the background brush (caves a lot of ::Create*Brush() and ::DeleteObject() calls).
    UINT   edFrameEdge;  //!< Supported values are the ::DrawEdge() edges: BDR_RAISEDINNER, BDR_SUNKENINNER, BDR_RAISEDOUTER, BDR_SUNKENOUTER, ...
    UINT   edFrameFlags; //!< Supported values are the ::DrawEdge() flags: BF_ADJUST, BF_BOTTOM, BF_BOTTOMLEFT, BF_BOTTOMRIGHT, BF_DIAGONAL, ...
    UINT   edWidth;      //!< The width of the edge. Currently not used
} BLANKEXTRADATA, *LPBLANKEXTRADATA;

And this is, how the XML comments and exclamation mark comments work together:

Image 26

  • The coexistence of XML comments and exclamation mark comments also works with code examples. The following comment lines show s sample with XML comments <summary> and exclamation mark comments //! \code ... //! \endcode:
C#
/// <summary>
/// The ConvenientWString object is designed to provide simple smart (auto-destructing) <c>WCHAR</c> strings.
/// It is a wrapper around the <c>std::wstring</c> class to provide an interface similar to the C# String class.
/// </summary>
//! \code
//! WString strMyName(L"My name!");
//! // Or alternatively this way:
//! WString strMyName;
//! strMyName = L"My name!";
//! ...
//! // Use it this way:
//! WORD len = wcslen(wszMyName.Get());
//! ...
//! // Destruction takes place automatically on leaving the block.
//! \endcode
class ConvenientWString : public CRttiProvider
...

And this is, how the XML comments and exclamation mark comments work together:

Image 27

Keyword "object"

  • Be careful with the word object within descriptions. It automatically creates a reference to the current class' documentation (e.g. object within the class OgwwBlank creates the same link as <see cref="OgwwBlank"/> - that means object should only be used, if <see cref="OgwwBlank"/> instance is intended).

Suppression of confusing macros

In some cases - I haven't found out exactly when - DoxyGen has problems with Microsoft specific macros. Most often the problem occurs with __declspec(dllexport). Ma solution is to suppress these macros.

C++
// \cond
__declspec(dllexport)
// \endcond

Some insides

The DoxyBlocks plugin, used to run DoxyGen, creates a new doxyfile (DoxyGen's configuration file) into <project-folder>\doxygen, everytime before DoxyGen is invoked. This is useful because it keeps the list of files to be compiled up to date, even if the project has changes. But this also prevents that manual extensions can be made in doxyfile. The source code of the DoxyBlocks plugin is open source and shows that most of the configuration values are simply written hard coded to doxyfile. This is also true for the configuration values of PREDEFINED as well as SEARCH_INCLUDES, INCLUDE_PATH and INCLUDE_FILE_PATTERNS - which is especially annoying when you want to handle conditions processed by the C/C++ preprocessor, like:

C++
#if defined(__GNUC__) || defined(__MINGW32__)
...
#endif

Switching off ENABLE_PREPROCESSING configuration values in general has other disadvantages. And so, to solve the problem, I have exploited exactly the weakness that causes the problem: I define __DOXYGEN__ and undefine it either if a GNU C/C++ or a Microsoft C/C++ preprocessor runs - but not if the DoxyGen preprocessor runs.

C++
#define __DOXGEN__
#if defined(__GNUC__) || defined(__MINGW32__)
#undef __DOXGEN__
#define __GNU_RUNTIME__
#endif
#if defined(_MSC_VER)
#undef __DOXGEN__
#endif
#if defined(__DOXGEN__) || defined(__GNU_RUNTIME__)
...
#endif

With this little trick I can now document (__DOXYGEN__ is defined) and compile (__GNU_RUNTIME__ is defined) my ReactOS specific functions, such as:

Image 28

Using the Code

This is the boilerplate code of the "OpenGL" template, generated by Code::Blocks. I used it for all tests.

C++
#include <windows.h>
#include <gl/gl.h>

LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
void EnableOpenGL(HWND hwnd, HDC*, HGLRC*);
void DisableOpenGL(HWND, HDC, HGLRC);

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nCmdShow)
{
    WNDCLASSEX wcex;
    HWND hwnd;
    HDC hDC;
    HGLRC hRC;
    MSG msg;
    BOOL bQuit = FALSE;
    float theta = 0.0f;

    /* register window class */
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_OWNDC;
    wcex.lpfnWndProc = WindowProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = "GLSample";
    wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);;

    if (!RegisterClassEx(&wcex))
        return 0;

    /* create main window */
    hwnd = CreateWindowEx(0,
                          "GLSample",
                          "OpenGL Sample",
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT,
                          CW_USEDEFAULT,
                          256,
                          256,
                          NULL,
                          NULL,
                          hInstance,
                          NULL);

    ShowWindow(hwnd, nCmdShow);

    /* enable OpenGL for the window */
    EnableOpenGL(hwnd, &hDC, &hRC);

    /* program main loop */
    while (!bQuit)
    {
        /* check for messages */
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            /* handle or dispatch messages */
            if (msg.message == WM_QUIT)
            {
                bQuit = TRUE;
            }
            else
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        else
        {
            /* OpenGL animation code goes here */

            glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
            glClear(GL_COLOR_BUFFER_BIT);

            glPushMatrix();
            glRotatef(theta, 0.0f, 0.0f, 1.0f);

            glBegin(GL_TRIANGLES);

                glColor3f(1.0f, 0.0f, 0.0f);   glVertex2f(0.0f,   1.0f);
                glColor3f(0.0f, 1.0f, 0.0f);   glVertex2f(0.87f,  -0.5f);
                glColor3f(0.0f, 0.0f, 1.0f);   glVertex2f(-0.87f, -0.5f);

            glEnd();

            glPopMatrix();

            SwapBuffers(hDC);

            theta += 1.0f;
            Sleep (1);
        }
    }

    /* shutdown OpenGL */
    DisableOpenGL(hwnd, hDC, hRC);

    /* destroy the window explicitly */
    DestroyWindow(hwnd);

    return msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_CLOSE:
            PostQuitMessage(0);
        break;

        case WM_DESTROY:
            return 0;

        case WM_KEYDOWN:
        {
            switch (wParam)
            {
                case VK_ESCAPE:
                    PostQuitMessage(0);
                break;
            }
        }
        break;

        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

    return 0;
}

void EnableOpenGL(HWND hwnd, HDC* hDC, HGLRC* hRC)
{
    PIXELFORMATDESCRIPTOR pfd;

    int iFormat;

    /* get the device context (DC) */
    *hDC = GetDC(hwnd);

    /* set the pixel format for the DC */
    ZeroMemory(&pfd, sizeof(pfd));

    pfd.nSize = sizeof(pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW |
                  PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;
    pfd.cDepthBits = 16;
    pfd.iLayerType = PFD_MAIN_PLANE;

    iFormat = ChoosePixelFormat(*hDC, &pfd);

    SetPixelFormat(*hDC, iFormat, &pfd);

    /* create and enable the render context (RC) */
    *hRC = wglCreateContext(*hDC);

    wglMakeCurrent(*hDC, *hRC);
}

void DisableOpenGL (HWND hwnd, HDC hDC, HGLRC hRC)
{
    wglMakeCurrent(NULL, NULL);
    wglDeleteContext(hRC);
    ReleaseDC(hwnd, hDC);
}

This is the resulting application of the boilerplate code - a rotating multi-colored triangle:

Image 29

Tip 1: NeonHelium Production maintains an excellent OpenGL tutorial.

Tip 2: There is another excellent OpenGL tutorial provided by opengl-tutorial.org.

The GLEW test, I've introduced with Code::Blocks, changed the code this way:

C++
#include <windows.h>
#include <gl/glew.h>
#include <gl/wglew.h>
//#include <gl/gl.h>

HANDLE hConsole = NULL;


...


void LogToConsoleW(LPCWSTR text)
{
    if (hConsole == NULL)
        hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    if(hConsole != NULL && hConsole != INVALID_HANDLE_VALUE && text != NULL)
    {
        DWORD written;
        WriteConsoleW(hConsole, text, wcslen(text), &written, NULL);
    }
}

void LogToConsoleWI(LPCWSTR format, int val)
{
    if (hConsole == NULL)
        hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    if(hConsole != NULL && hConsole != INVALID_HANDLE_VALUE && format != NULL)
    {
        WORD len = wcslen(format) + 32;
        LPWSTR text = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * len);
        swprintf(text, format, val);

        DWORD written;
        WriteConsoleW(hConsole, text, wcslen(text), &written, NULL);

        LocalFree(text);
    }
}

void LogToConsoleSS(LPCSTR format, LPCSTR val)
{
    if (hConsole == NULL)
        hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    if(hConsole != NULL && hConsole != INVALID_HANDLE_VALUE && format != NULL)
    {
        WORD len = strlen(format) + (val != NULL ? strlen(val) - 1 : 0);
        LPSTR text = (LPSTR)LocalAlloc(LPTR, sizeof(CHAR) * len);
        sprintf(text, format, val);

        DWORD written;
        WriteConsoleA(hConsole, text, strlen(text), &written, NULL);

        LocalFree(text);
    }
}

void LogToConsoleWW(LPCWSTR format, LPCWSTR val)
{
    if (hConsole == NULL)
        hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    if(hConsole != NULL && hConsole != INVALID_HANDLE_VALUE && format != NULL)
    {
        WORD len = wcslen(format) + (val != NULL ? wcslen(val) - 1 : 0);
        LPWSTR text = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * len);
        swprintf(text, format, val);

        DWORD written;
        WriteConsoleW(hConsole, text, wcslen(text), &written, NULL);

        LocalFree(text);
    }
}

void EnableOpenGL(HWND hwnd, HDC* hDC, HGLRC* hRC)

{


...


    LogToConsoleW(L"OpenGL initialized.\n");
    LogToConsoleSS("OpenGL vendor: %s\n", glGetString(GL_VENDOR));
    LogToConsoleSS("OpenGL renderer: %s\n", glGetString(GL_RENDERER));
    LogToConsoleSS("OpenGL version: %s\n", glGetString(GL_VERSION));
    LogToConsoleSS("OpenGL shader: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));

    GLenum err = glewInit();
    if (err != GLEW_OK)
    {
        LogToConsoleW(L"ERROR: GLEW not initialized.\n");
    }
    else
    {
        LogToConsoleW(L"GLEW successfully initialized.\n");
        LogToConsoleSS("GLEW version: %s\n", glewGetString(GLEW_VERSION));
        if (glewIsSupported("GL_ARB_texture_border_clamp"))
            LogToConsoleSS("OpenGL supports 'GL_ARB_texture_border_clamp'.\n",
                           glewGetString(GLEW_VERSION));
    }
}

The result of the changes is this console log:

Image 30

Tip 3: GLEW comes with two interesting test tools: "glewinfo.exe" and "visualinfo.exe". Try them out! On my ReactOS, the "visualinfo.exe" reports GL_EXT_framebuffer_object, GL_ARB_vertex_buffer_object and GL_ARB_pixel_buffer_object to be present.

Points of Interest

Now we are ready to create OpenGL applications for ReactOS. Have fun!

The next logical step for me is to develop a first serious 3D application - which I have addressed in the article More about OpenGL with C/C++ and C# on ReactOS (or Windows)

Meanwhile I noticed that there is no IconEditor that runs satisfying under ReactOS. So I let myself be distracted by this and started writing the article A basic icon editor running on ReactOS (and consequently on Windows XP and newer versions).

History

  • 23rd September, 2019: Initial version
  • 13th May, 2020: Update 1 (new chapter 'Adding a documentation generator')
  • 15th May, 2020: Update 2 (chapter 'Adding a documentation generator' reworked and extended)
  • 14th October, 2020: Update 3 (clear separation of the results between VMWare Player and Oracle VirtualBox; additional tests with Mesa 3D Graphics Library installation; additional tests with up-to-date VMWare Player version 15.5.6, Oracle VirtualBox version 6.1.10 and ReactOS version 0.4.13)
  • 11th May, 2021: Update 4 (DoxyGen table syntax and description, how to suppress confusing macros, added)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)