Konstruisto: Update #9 – Trees!

It’s been a long time since the last update – exactly 993 days. Luckily, there are new features coming in, what lead to implementing… trees!

We’re almost there now.

I pushed 122 new commits since the last update, current total 282. What has changed?

Trees

A completely new feature, you can paint trees over terrain. Brush supports modifiers:

  • Shift increases brush radius
  • Ctrl decreases brush radius
  • Alt will switch to single tree placement mode

Placing building or a road will remove all trees on affected tiles.

A group of trees placed on the ground.

New rendering pipeline

I spent majority of time implementing a new rendering pipeline for objects. After engine loads models through Assimp, new renderer packs them up to a single buffer for static geometry. It also holds definitions of materials (basic Phong shading right now). On flush() renderer sorts all draw commands to minimize state changes and sends OpenGL batches to GPU. Instancing is supported with transform matrices per instance.

Terrain chunk full of trees rendering at 62 FPS.

New collision system

I created a new, simpler collision system where bodies are separate from game object representation. With layers, you can for example place a road which crosses another one, but not a building. This also fixes a few weird quirks when placing roads.

Buildings and roads in the forest.

Game saves

Combinations Ctrl+S and Ctrl+L will save/load buildings, roads and camera position. This is a feature from 2018, I’m yet to port it to new collision system (in February?).

Code repository

Go and see https://github.com/kantoniak/konstruisto. There are Star and Watch buttons in the sidebar (right). Repository contains setup scripts for both Visual Studio and makefile/clang++. Have fun!

Clang++ with MinGW headers on Windows

Introduction

To build Konstruisto on Windows, we need to set up Clang++ compilation with MinGW headers. It’s not a complicated process, but can take some time if you don’t know where to start. Please note we are setting up only 64-bit builds here.

I assume you have some terminal emulator installed (Git Bash does the job here). Make sure you can open .7z archives (you can download 7-Zip for free).

Downloading LLVM

LLVM is a set of tools for compilation of various languages. It contains clang++. To get the latest stable version, go to their Downloads Page and choose latest stable Windows (64-bit) binaries. We use LLVM 7.0.0 in this article.

Make sure LLVM’s bin folder is in PATH, and restart terminal emulator if it was already running.

LLVM in Path

Missing headers

Let’s create clang-test.cpp. Now, clang++ will complain about missing headers:

Clang++: No MSVC installation

On Windows, it tries to find Visual Studio compiler first, and the message says it was not found. Compilation may be successful if you already have MSVC installed, but it’s not what we’re looking for. Setting target to x86_64-pc-windows-gnu says we want 64-bit binaries using gcc headers:

Clang++: No gcc headers

These are still missing, as we haven’t installed sources. Add --verbose to see where clang was looking:

kantoniak@kantoniak-razer:~ $ clang++ –verbose -target x86_64-pc-windows-gnu clang-test.cpp
clang version 7.0.0 (tags/RELEASE_700/final)
Target: x86_64-pc-windows-gnu
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin
“C:\\Program Files\\LLVM\\bin\\clang++.exe” -cc1 -triple x86_64-pc-windows-gnu -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name clang-test.cpp -mrelocation-model pic -pic-level 2 -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -v -resource-dir “C:\\Program Files\\LLVM\\lib\\clang\\7.0.0” -internal-isystem “C:\\Program Files\\LLVM\\x86_64-w64-mingw32\\include\\c++” -internal-isystem “C:\\Program Files\\LLVM\\x86_64-w64-mingw32\\include\\c++\\x86_64-w64-mingw32” -internal-isystem “C:\\Program Files\\LLVM\\x86_64-w64-mingw32\\include\\c++\\backward” -internal-isystem “C:\\Program Files\\LLVM\\x86_64-w64-mingw32\\include\\c++\\” -internal-isystem “C:\\Program Files\\LLVM\\x86_64-w64-mingw32\\include\\c++\\\\x86_64-w64-mingw32” -internal-isystem “C:\\Program Files\\LLVM\\x86_64-w64-mingw32\\include\\c++\\\\backward” -internal-isystem “C:\\Program Files\\LLVM\\include\\c++\\” -internal-isystem “C:\\Program Files\\LLVM\\include\\c++\\\\x86_64-w64-mingw32” -internal-isystem “C:\\Program Files\\LLVM\\include\\c++\\\\backward” -internal-isystem “include\\c++” -internal-isystem “include\\c++\\x86_64-w64-mingw32” -internal-isystem “include\\c++\\backward” -internal-isystem “C:\\Program Files\\LLVM\\lib\\clang\\7.0.0\\include” -internal-isystem “C:\\Program Files\\LLVM\\x86_64-w64-mingw32/sys-root/mingw/include” -internal-isystem “C:\\Program Files\\LLVM\\x86_64-w64-mingw32\\include” -internal-isystem “C:\\Program Files\\LLVM\\include” -fdeprecated-macro -fdebug-compilation-dir “C:\\Users\\krzys” -ferror-limit 19 -fmessage-length 0 -fno-use-cxa-atexit -fobjc-runtime=gcc -fcxx-exceptions -fexceptions -fseh-exceptions -fdiagnostics-show-option -o “C:\\Users\\krzys\\AppData\\Local\\Temp\\clang-test-4710bf.o” -x c++ clang-test.cpp
clang -cc1 version 7.0.0 based upon LLVM 7.0.0 default target x86_64-pc-win32
ignoring nonexistent directory “C:\Program Files\LLVM\x86_64-w64-mingw32\include\c++”
ignoring nonexistent directory “C:\Program Files\LLVM\x86_64-w64-mingw32\include\c++\x86_64-w64-mingw32”
ignoring nonexistent directory “C:\Program Files\LLVM\x86_64-w64-mingw32\include\c++\backward”
ignoring nonexistent directory “C:\Program Files\LLVM\x86_64-w64-mingw32\include\c++\”
ignoring nonexistent directory “C:\Program Files\LLVM\x86_64-w64-mingw32\include\c++\\x86_64-w64-mingw32”
ignoring nonexistent directory “C:\Program Files\LLVM\x86_64-w64-mingw32\include\c++\\backward”
ignoring nonexistent directory “C:\Program Files\LLVM\include\c++\”
ignoring nonexistent directory “C:\Program Files\LLVM\include\c++\\x86_64-w64-mingw32”
ignoring nonexistent directory “C:\Program Files\LLVM\include\c++\\backward”
ignoring nonexistent directory “include\c++”
ignoring nonexistent directory “include\c++\x86_64-w64-mingw32”
ignoring nonexistent directory “include\c++\backward”
ignoring nonexistent directory “C:\Program Files\LLVM\x86_64-w64-mingw32/sys-root/mingw/include”
ignoring nonexistent directory “C:\Program Files\LLVM\x86_64-w64-mingw32\include”
#include “…” search starts here:
#include <…> search starts here:
C:\Program Files\LLVM\lib\clang\7.0.0\include
C:\Program Files\LLVM\include
End of search list.
clang-test.cpp:1:10: fatal error: ‘iostream’ file not found
#include
^~~~~~~~~~
1 error generated.

MinGW-w64

We will download MinGW-w64 which contains headers we need for clang. Go to project’s page on SourceForge, choose latest stable build with POSIX threads and SEH exception model. In this article, we use x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z. Unpack archive (I put mingw64 in C:\Program Files\). You will find a number of standard tools in bin folder. Add this folder to PATH, so that clang can find it.

MinGW in Path

Tip: make is bundled as mingw32-make.exe. You can run mklink "C:\Program Files\mingw64\bin\make.exe" "C:\Program Files\mingw64\bin\mingw32-make.exe" in Windows’ CMD as Administrator to create a soft link from make.

Building with clang++

MSVC is the default toolchain for Windows, so you will have to set target manually. Everything works now!

Clang++: Working setup

Verbose output:

kantoniak@kantoniak-razer:~ $ clang++ –verbose -target x86_64-pc-windows-gnu clang-test.cpp
clang version 7.0.0 (tags/RELEASE_700/final)
Target: x86_64-pc-windows-gnu
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin
“C:\\Program Files\\LLVM\\bin\\clang++.exe” -cc1 -triple x86_64-pc-windows-gnu -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name clang-test.cpp -mrelocation-model pic -pic-level 2 -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -v -resource-dir “C:\\Program Files\\LLVM\\lib\\clang\\7.0.0” -internal-isystem “C:\\Program Files\\mingw64\\x86_64-w64-mingw32\\include\\c++” -internal-isystem “C:\\Program Files\\mingw64\\x86_64-w64-mingw32\\include\\c++\\x86_64-w64-mingw32” -internal-isystem “C:\\Program Files\\mingw64\\x86_64-w64-mingw32\\include\\c++\\backward” -internal-isystem “C:\\Program Files\\mingw64\\x86_64-w64-mingw32\\include\\c++\\8.1.0” -internal-isystem “C:\\Program Files\\mingw64\\x86_64-w64-mingw32\\include\\c++\\8.1.0\\x86_64-w64-mingw32” -internal-isystem “C:\\Program Files\\mingw64\\x86_64-w64-mingw32\\include\\c++\\8.1.0\\backward” -internal-isystem “C:\\Program Files\\mingw64\\include\\c++\\8.1.0” -internal-isystem “C:\\Program Files\\mingw64\\include\\c++\\8.1.0\\x86_64-w64-mingw32” -internal-isystem “C:\\Program Files\\mingw64\\include\\c++\\8.1.0\\backward” -internal-isystem “C:\\Program Files\\mingw64\\lib\\gcc\\x86_64-w64-mingw32\\8.1.0\\include\\c++” -internal-isystem “C:\\Program Files\\mingw64\\lib\\gcc\\x86_64-w64-mingw32\\8.1.0\\include\\c++\\x86_64-w64-mingw32” -internal-isystem “C:\\Program Files\\mingw64\\lib\\gcc\\x86_64-w64-mingw32\\8.1.0\\include\\c++\\backward” -internal-isystem “C:\\Program Files\\LLVM\\lib\\clang\\7.0.0\\include” -internal-isystem “C:\\Program Files\\mingw64\\x86_64-w64-mingw32/sys-root/mingw/include” -internal-isystem “C:\\Program Files\\mingw64\\x86_64-w64-mingw32\\include” -internal-isystem “C:\\Program Files\\mingw64\\include” -fdeprecated-macro -fdebug-compilation-dir “C:\\Users\\krzys” -ferror-limit 19 -fmessage-length 0 -fno-use-cxa-atexit -fobjc-runtime=gcc -fcxx-exceptions -fexceptions -fseh-exceptions -fdiagnostics-show-option -o “C:\\Users\\krzys\\AppData\\Local\\Temp\\clang-test-f81641.o” -x c++ clang-test.cpp
clang -cc1 version 7.0.0 based upon LLVM 7.0.0 default target x86_64-pc-win32
ignoring nonexistent directory “C:\Program Files\mingw64\x86_64-w64-mingw32\include\c++”
ignoring nonexistent directory “C:\Program Files\mingw64\x86_64-w64-mingw32\include\c++\x86_64-w64-mingw32”
ignoring nonexistent directory “C:\Program Files\mingw64\x86_64-w64-mingw32\include\c++\backward”
ignoring nonexistent directory “C:\Program Files\mingw64\x86_64-w64-mingw32\include\c++\8.1.0”
ignoring nonexistent directory “C:\Program Files\mingw64\x86_64-w64-mingw32\include\c++\8.1.0\x86_64-w64-mingw32”
ignoring nonexistent directory “C:\Program Files\mingw64\x86_64-w64-mingw32\include\c++\8.1.0\backward”
ignoring nonexistent directory “C:\Program Files\mingw64\include\c++\8.1.0”
ignoring nonexistent directory “C:\Program Files\mingw64\include\c++\8.1.0\x86_64-w64-mingw32”
ignoring nonexistent directory “C:\Program Files\mingw64\include\c++\8.1.0\backward”
ignoring nonexistent directory “C:\Program Files\mingw64\x86_64-w64-mingw32/sys-root/mingw/include”
#include “…” search starts here:
#include <…> search starts here:
C:\Program Files\mingw64\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++
C:\Program Files\mingw64\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\x86_64-w64-mingw32
C:\Program Files\mingw64\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\backward
C:\Program Files\LLVM\lib\clang\7.0.0\include
C:\Program Files\mingw64\x86_64-w64-mingw32\include
C:\Program Files\mingw64\include
End of search list.
“C:\\Program Files\\mingw64\\bin\\ld.exe” -m i386pep -Bdynamic -o a.exe “C:\\Program Files\\mingw64\\x86_64-w64-mingw32\\lib\\crt2.o” “C:\\Program Files\\mingw64\\lib\\gcc\\x86_64-w64-mingw32\\8.1.0\\crtbegin.o” “-LC:\\Program Files\\mingw64\\lib\\gcc\\x86_64-w64-mingw32\\8.1.0” “-LC:\\Program Files\\mingw64\\x86_64-w64-mingw32\\lib” “-LC:\\Program Files\\mingw64\\lib” “-LC:\\Program Files\\mingw64\\x86_64-w64-mingw32/sys-root/mingw/lib” “C:\\Users\\krzys\\AppData\\Local\\Temp\\clang-test-f81641.o” -lstdc++ -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt -ladvapi32 -lshell32 -luser32 -lkernel32 -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt “C:\\Program Files\\mingw64\\lib\\gcc\\x86_64-w64-mingw32\\8.1.0\\crtend.o”

Have fun!

You can build Konstruisto now 😉

Quick Tip: Cool features of Chromium DevTools

Chromium Developer Tools is a powerful suite with many features you probably didn’t know about. Here are three of them I find very helpful, but not so popular.

DevTools console output with style

When you output to the console, you can also style text. This is done by putting %c sequence before the styled block. There can be more than one such block. Then you pass CSS styles in the following arguments:

console.log("%cHello developers!\n%cThis is a sample message.", "font: bold 14px/1.35 Arial;", "font: normal 12px/1.35 Arial;");

Styling text in Dev Tools

Copy JavaScript content to clipboard

Dev Tools allow you to copy to clipboard the value of a variable. You just have to invoke the copy function:

var test = "Lorem ipsum dolor sit amet enim";
copy(test);

And now you can paste string Lorem ipsum dolor sit amet enim anywhere.

Make the whole website editable

This is not so much a tip regarding console, you can paste the code there. You can allow editing any text on the web page simply setting

document.body.contentEditable = true

Now you will be able to put the cursor inside every text block and modify it as you want.

GoogleTest installation and introduction

GoogleTest is one of the C++ testing frameworks. It is built following xUnit architecture, so you should be able to start quickly if you have had any previous experience with other testing suites. If you don’t, it’s high time to start testing.

GoogleTest Installation

We will use latest GitHub release (1.8.0). You need to download the ZIP and build the code. Then we make a static library out of it.

wget https://github.com/google/googletest/archive/release-1.8.0.zip --no-check-certificate
unzip release-1.8.0 && rm release-1.8.0
mkdir -p googletest-release-1.8.0/googletest/lib/
cd googletest-release-1.8.0/googletest/lib/
g++ -isystem ../include -I../ -pthread -c "../src/gtest-all.cc"
ar -rv libgtest.a gtest-all.o
cd -

Now we are ready to build code. Continue reading

Konstruisto: Weeks #8 & #9 – Added tests, first Blender model

Since the last post, I took some time to better prepare environment. That means there are no new features. I pushed only two commits, total 160. I did set up Google Test and modified makefile to include missing DLLs for Windows releases.

My first low poly model

I also started playing with Blender to make some models. It takes a lot of time and there are lots of new things to learn, but I managed to finish a simple hospital model. I don’t know yet what should be published in the repository for blender models and I didn’t decide on file format yet, so it’s not included in the repo.

I don’t publish builds this time.

Changelog

  • Set up Google Test framework
  • Fixed missing DLLs for Windows releases
  • First Blender model

Code repository

Go and see https://github.com/kantoniak/konstruisto. You can build from there or download binary release below. There are Star and Watch buttons in the sidebar (right).

WordPress plugins: Creating widgets

I noticed my series on WordPress plugins misses widgets. It’s a good fortune because I needed to show some social icons in the sidebar.

This is how the widget looks like.

You will find the source code in my repo: https://github.com/kantoniak/kantoniak-about-me, along with the link to vector icons made by Allan McAvoy.

Update: Plugin is already available here: https://wordpress.org/plugins/kantoniak-about-me/. To install it from the dashboard, go to Plugins/Add New, change search criteria to Author and look for kantoniak. Continue reading

How to submit to WordPress Plugin Directory

It’s the time to start uploading to extension gallery. We have created two plugins so far:

I will describe the process on the example of the second one. You can find it here: https://wordpress.org/plugins/demo-shortcodes/. To install it from the dashboard, go to Plugins/Add New, change search criteria to Author and look for kantoniak.

Plugin preview

Continue reading

Quick Tip: Mouse picking

Mouse picking can be found in nearly every 3D game now. In many cases, it’s crucial to let the user interact with the world by directly pointing at some objects. One of the possible approaches is to convert pointer position to some vector/ray inside the world and do hit-testing. To achieve this I use GLM library which handles mathematical routines for OpenGL.

Continue reading