Index: code/trunk/cmake/CompilerConfigGCC.cmake
===================================================================
--- code/trunk/cmake/CompilerConfigGCC.cmake	(revision 8421)
+++ code/trunk/cmake/CompilerConfigGCC.cmake	(revision 8729)
@@ -43,4 +43,11 @@
 IF(_compare_result GREATER -1)
   SET(PCH_COMPILER_SUPPORT TRUE)
+ENDIF()
+
+# __COUNTER__ macro was only added in GCC 4.3
+# It might be required to make full build units work
+COMPARE_VERSION_STRINGS("${GCC_VERSION}" "4.3.0" _compare_result)
+IF(_compare_result GREATER -1)
+  SET(HAVE_COUNTER_MACRO TRUE)
 ENDIF()
 
Index: code/trunk/cmake/CompilerConfigMSVC.cmake
===================================================================
--- code/trunk/cmake/CompilerConfigMSVC.cmake	(revision 8421)
+++ code/trunk/cmake/CompilerConfigMSVC.cmake	(revision 8729)
@@ -33,4 +33,8 @@
 # Orxonox only supports MSVC 8 and above, which gets asserted above
 SET(PCH_COMPILER_SUPPORT TRUE)
+
+# __COUNTER__ macro has been around since VS 2005
+# It might be required to make full build units work
+SET(HAVE_COUNTER_MACRO TRUE)
 
 
Index: code/trunk/cmake/tools/BuildUnits.cmake
===================================================================
--- code/trunk/cmake/tools/BuildUnits.cmake	(revision 8729)
+++ code/trunk/cmake/tools/BuildUnits.cmake	(revision 8729)
@@ -0,0 +1,146 @@
+ #
+ #             ORXONOX - the hottest 3D action shooter ever to exist
+ #                             > www.orxonox.net <
+ #
+ #        This program is free software; you can redistribute it and/or
+ #         modify it under the terms of the GNU General Public License
+ #        as published by the Free Software Foundation; either version 2
+ #            of the License, or (at your option) any later version.
+ #
+ #       This program is distributed in the hope that it will be useful,
+ #        but WITHOUT ANY WARRANTY; without even the implied warranty of
+ #        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ #                 GNU General Public License for more details.
+ #
+ #   You should have received a copy of the GNU General Public License along
+ #      with this program; if not, write to the Free Software Foundation,
+ #     Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ #
+ #
+ #  Author:
+ #    Reto Grieder
+ #
+
+FUNCTION(GENERATE_BUILD_UNITS _target_name _all_files_var)
+  SET(_source_files)
+  SET(_total_file_count 0)
+
+  # Count the number of actual C++ source files
+  FOREACH(_file ${${_all_files_var}})
+    # Only look at C++ source files
+    IF(_file MATCHES "\\.(cpp|cc|cxx)$")
+      # Some files might be marked as not to compile at all
+      GET_SOURCE_FILE_PROPERTY(_skip1 ${_file} HEADER_FILE_ONLY)
+      GET_SOURCE_FILE_PROPERTY(_skip2 ${_file} EXCLUDE_FROM_BUILD_UNITS)
+      IF(NOT _skip1 AND NOT _skip2)
+        GET_SOURCE_FILE_PROPERTY(_size ${_file} BUILD_UNIT_SIZE)
+        IF(NOT _size)
+          SET(_size 1)
+        ENDIF()
+        # Append file AND size to the list (like storing an std::pair)
+        LIST(APPEND _source_files ${_file} ${_size})
+        MATH(EXPR _total_file_count "${_total_file_count} + ${_size}")
+        # Don't compile
+        SET_SOURCE_FILES_PROPERTIES(${_file} PROPERTIES HEADER_FILE_ONLY TRUE)
+      ENDIF()
+    ENDIF()
+  ENDFOREACH(_file)
+
+  # Get number of build units we have to make. The default is NR_OF_BUILD_UNITS
+  # However we can specify different values in a config file
+  SET(_config ${BUILD_UNITS_CONFIG_${NR_OF_BUILD_UNITS}_THREADS})
+  SET(_nr_of_units)
+  IF(_config)
+    LIST(FIND _config ${_target_name} _index)
+    IF(NOT _index EQUAL -1)
+      # Nr of build units is the next element in the list (we assume it exists)
+      MATH(EXPR _index "${_index} + 1")
+      LIST(GET _config ${_index} _nr_of_units)
+    ENDIF()
+  ENDIF()
+  IF(NOT _nr_of_units)
+    # Use default as specified (e.g. "full4" --> 4) or 1 for externals
+    IF(_arg_ORXONOX_EXTERNAL)
+      SET(_nr_of_units 1)
+    ELSE()
+      SET(_nr_of_units ${NR_OF_BUILD_UNITS})
+    ENDIF()
+  ENDIF()
+
+  # Disable precompiled header files for targets with two or less build units
+  IF(_nr_of_units LESS 3)
+    SET(PCH_DISABLE_${_target_name} TRUE PARENT_SCOPE)
+  ENDIF()
+
+  SET(_remaining_files ${_total_file_count})
+  SET(_remaining_units ${_nr_of_units})
+  SET(_unit_nr 1)
+  # Loop counts back from ${_nr_of_units} to 1
+  FOREACH(_remaining_units RANGE ${_nr_of_units} 1 -1)
+    # Use integer division to get the current build unit size
+    MATH(EXPR _aimed_size "${_remaining_files} / ${_remaining_units}")
+
+    SET(_current_size 0)
+    SET(_current_unit)
+
+    SET(_file_index 0)
+    LIST(LENGTH _source_files _list_size)
+    WHILE(${_file_index} LESS ${_list_size} AND NOT ${_current_size} EQUAL ${_aimed_size})
+      # _source_files stores pairs of values (file followed by its size)
+      MATH(EXPR _size_index "${_file_index} + 1")
+      LIST(GET _source_files ${_file_index} _file)
+      LIST(GET _source_files ${_size_index} _size)
+
+      MATH(EXPR _new_size "${_current_size} + ${_size}")
+      IF(${_new_size} GREATER ${_aimed_size})
+        # Try next file in list (jump 2 because pairs are stored)
+        MATH(EXPR _file_index "${_file_index} + 2")
+      ELSE()
+        SET(_current_size ${_new_size})
+        LIST(APPEND _current_unit ${_file})
+        # Remove from _source_files list
+        LIST(REMOVE_AT _source_files ${_file_index} ${_size_index})
+        MATH(EXPR _list_size "${_list_size} - 2")
+      ENDIF()
+    ENDWHILE()
+
+    # Finalise
+    LIST(LENGTH _current_unit _nr_of_included_files)
+    IF(_nr_of_included_files EQUAL 1)
+      # If unit consists of one file, we can compile it the old fashioned way
+      SET_SOURCE_FILES_PROPERTIES(${_current_unit} PROPERTIES HEADER_FILE_ONLY FALSE)
+    ELSEIF(_nr_of_included_files GREATER 1)
+      # Assemble unit by writing some #include statements
+      SET(_include_string)
+      FOREACH(_file ${_current_unit})
+        SET(_include_string "${_include_string}#include \"${_file}\"\n")
+      ENDFOREACH(_file)
+
+      # Generate the filename
+      IF(NOT _nr_of_units EQUAL 1)
+        SET(_suffix ${_unit_nr})
+      ENDIF()
+      SET(_unit_file ${CMAKE_CURRENT_BINARY_DIR}/${_target_name}BuildUnit${_suffix}.cc)
+      # Only write if content has changed (avoids recompile)
+      IF(EXISTS ${_unit_file})
+        FILE(READ ${_unit_file} _file_include_string)
+      ENDIF()
+      IF(NOT _include_string STREQUAL "${_file_include_string}")
+        FILE(WRITE ${_unit_file} "${_include_string}")
+      ENDIF()
+
+      LIST(APPEND _build_units ${_unit_file})
+
+      # Increase file name counter
+      MATH(EXPR _unit_nr "${_unit_nr} + 1")
+    ENDIF()
+
+    # Compute remaining files
+    MATH(EXPR _remaining_files "${_remaining_files} - ${_current_size}")
+  ENDFOREACH(_remaining_units)
+
+  # Add units to list of source files (function, not macro --> parent scope)
+  # Do this ONCE because parent scope changes will NOT be visible here
+  SET(${_all_files_var} ${${_all_files_var}} ${_build_units} PARENT_SCOPE)
+
+ENDFUNCTION(GENERATE_BUILD_UNITS)
Index: code/trunk/cmake/tools/GenerateToluaBindings.cmake
===================================================================
--- code/trunk/cmake/tools/GenerateToluaBindings.cmake	(revision 8421)
+++ code/trunk/cmake/tools/GenerateToluaBindings.cmake	(revision 8729)
@@ -49,16 +49,21 @@
   SET(_tolua_pkgfile "${CMAKE_CURRENT_BINARY_DIR}/tolua.pkg")
   SET(_tolua_cxxfile "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/ToluaBind${_tolua_package}.cc")
-  SET(_tolua_hfile   "${CMAKE_BINARY_DIR}/src/toluabind/${CMAKE_CFG_INTDIR}/ToluaBind${_tolua_package}.h")
+  #SET(_tolua_hfile   "${CMAKE_BINARY_DIR}/src/toluabind/${CMAKE_CFG_INTDIR}/ToluaBind${_tolua_package}.h")
 
   SET(${_target_source_files}
     ${${_target_source_files}}
     ${_tolua_cxxfile}
-    ${_tolua_hfile}
     PARENT_SCOPE
   )
 
-  # Disable annoying GCC warnings
   IF(CMAKE_COMPILER_IS_GNU)
+    # Disable annoying GCC warnings
     SET_SOURCE_FILES_PROPERTIES(${_tolua_cxxfile} PROPERTIES COMPILE_FLAGS "-w")
+  ENDIF()
+
+  IF(MSVC)
+    # Including the file in a build unit is impossible because CMAKE_CFG_INTDIR
+    # exands to an expression that the compiler doesn't understand
+    SET_SOURCE_FILES_PROPERTIES(${_tolua_cxxfile} PROPERTIES EXCLUDE_FROM_BUILD_UNITS TRUE)
   ENDIF()
 
@@ -70,11 +75,16 @@
   ENDFOREACH(_tolua_inputfile)
 
+  IF(TOLUA_PARSER_HOOK_SCRIPT)
+    # Hook scripts may contain functions that act as Tolua hooks
+    SET(_hook_script -L "${TOLUA_PARSER_HOOK_SCRIPT}")
+  ENDIF()
+
   ADD_CUSTOM_COMMAND(
-    OUTPUT ${_tolua_cxxfile} ${_tolua_hfile}
+    OUTPUT ${_tolua_cxxfile}
     COMMAND toluaapp_orxonox -n ${_tolua_package}
                              -w ${CMAKE_CURRENT_SOURCE_DIR}
                              -o ${_tolua_cxxfile}
-                             -H ${_tolua_hfile}
                              -s ${TOLUA_PARSER_SOURCE}
+                                ${_hook_script}
                                 ${_tolua_pkgfile}
     DEPENDS           ${TOLUA_PARSER_DEPENDENCIES}
Index: code/trunk/cmake/tools/SourceFileUtilities.cmake
===================================================================
--- code/trunk/cmake/tools/SourceFileUtilities.cmake	(revision 8421)
+++ code/trunk/cmake/tools/SourceFileUtilities.cmake	(revision 8729)
@@ -25,8 +25,8 @@
  #                             adds the current directory.
  #                             Also compiles multiple source files into a single
- #                             one by including them
- #                             Use COMPILATION_[BEGIN|END] in
+ #                             translation unit (faster)
+ #                             Use [END_]BUILD_UNIT in
  #                             [ADD|SET]_SOURCE_FILES and specify the name of
- #                             the new source file after COMPILATION_BEGIN
+ #                             the new source file after BUILD_UNIT
  #    GET_ALL_HEADER_FILES   - Finds all header files recursively.
  #    GENERATE_SOURCE_GROUPS - Set Visual Studio source groups.
@@ -36,5 +36,5 @@
   SET(_source_files)
   FOREACH(_file ${ARGN})
-    IF(_file MATCHES "^(COMPILATION_BEGIN|COMPILATION_END)$")
+    IF(_file MATCHES "^(BUILD_UNIT|END_BUILD_UNIT)$")
       # Append keywords verbatim
       LIST(APPEND _source_files ${_file})
Index: code/trunk/cmake/tools/TargetUtilities.cmake
===================================================================
--- code/trunk/cmake/tools/TargetUtilities.cmake	(revision 8421)
+++ code/trunk/cmake/tools/TargetUtilities.cmake	(revision 8729)
@@ -40,4 +40,5 @@
  #      NO_INSTALL:        Do not install the target at all
  #      NO_VERSION:        Prevents adding any version to a target
+ #      NO_BUILD_UNITS:    Disables automatic (full) build units
  #
  #    Lists:
@@ -54,4 +55,7 @@
  #      PCH_EXCLUDE:       Source files to be excluded from PCH support
  #      OUTPUT_NAME:       If you want a different name than the target name
+ #      EXCLUDE_FROM_BUILD_UNITS: Specifies files that are not put into
+ #                         automatic (full) build units. They can still
+ #                         explicitely be included in a BUILD_UNIT (partial)
  #  Note:
  #    This function also installs the target!
@@ -62,4 +66,5 @@
  #
 
+INCLUDE(BuildUnits)
 INCLUDE(CMakeDependentOption)
 INCLUDE(CapitaliseName)
@@ -87,44 +92,52 @@
   SET(_switches   FIND_HEADER_FILES  EXCLUDE_FROM_ALL  ORXONOX_EXTERNAL
                   NO_DLL_INTERFACE   NO_SOURCE_GROUPS  PCH_NO_DEFAULT 
-                  NO_INSTALL         NO_VERSION        ${_additional_switches})
+                  NO_INSTALL         NO_VERSION        NO_BUILD_UNITS
+                  ${_additional_switches})
   SET(_list_names LINK_LIBRARIES     VERSION           SOURCE_FILES
                   DEFINE_SYMBOL      TOLUA_FILES       PCH_FILE
                   PCH_EXCLUDE        OUTPUT_NAME       LINK_LIBS_LINUX
-                  LINK_LIBS_WIN32    LINK_LIBS_APPLE   LINK_LIBS_UNIX)
+                  LINK_LIBS_WIN32    LINK_LIBS_APPLE   LINK_LIBS_UNIX
+                  EXCLUDE_FROM_BUILD_UNITS)
 
   PARSE_MACRO_ARGUMENTS("${_switches}" "${_list_names}" ${ARGN})
 
-  # Process source files with support for compilations
+  # Process source files with support for build units
   # Note: All file paths are relative to the root source directory, even the
-  #       name of the compilation file.
+  #       name of the build unit.
   SET(_${_target_name}_source_files)
-  SET(_get_compilation_file FALSE)
-  SET(_add_to_compilation FALSE)
+  SET(_get_build_unit_file FALSE)
+  SET(_add_to_build_unit FALSE)
   FOREACH(_file ${_arg_SOURCE_FILES})
-    IF(_file STREQUAL "COMPILATION_BEGIN")
-      # Next file is the name of the compilation
-      SET(_get_compilation_file TRUE)
-    ELSEIF(_file STREQUAL "COMPILATION_END")
-      IF(NOT _compilation_file)
-        MESSAGE(FATAL_ERROR "No name provided for source file compilation")
-      ENDIF()
-      IF(NOT DISABLE_COMPILATIONS)
-        IF(NOT _compilation_include_string)
-          MESSAGE(STATUS "Warning: Empty source file compilation!")
-        ENDIF()
-        IF(EXISTS ${_compilation_file})
-          FILE(READ ${_compilation_file} _include_string_file)
-        ENDIF()
-        IF(NOT _compilation_include_string STREQUAL "${_include_string_file}")
-          FILE(WRITE ${_compilation_file} "${_compilation_include_string}")
-        ENDIF()
-        LIST(APPEND _${_target_name}_source_files ${_compilation_file})
-      ENDIF()
-      SET(_add_to_compilation FALSE)
-    ELSEIF(_get_compilation_file)
-      SET(_compilation_file ${CMAKE_BINARY_DIR}/${_file})
-      SET(_get_compilation_file FALSE)
-      SET(_add_to_compilation TRUE)
-      SET(_compilation_include_string)
+    IF(_file STREQUAL "BUILD_UNIT")
+      # Next file is the name of the build unit
+      SET(_get_build_unit_file TRUE)
+    ELSEIF(_file STREQUAL "END_BUILD_UNIT")
+      IF(NOT _build_unit_file)
+        MESSAGE(FATAL_ERROR "No name provided for build unit")
+      ENDIF()
+      IF(ENABLE_BUILD_UNITS)
+        IF(NOT _build_unit_include_string)
+          MESSAGE(STATUS "Warning: Empty build unit!")
+        ENDIF()
+        IF(EXISTS ${_build_unit_file})
+          FILE(READ ${_build_unit_file} _include_string_file)
+        ENDIF()
+        IF(NOT _build_unit_include_string STREQUAL "${_include_string_file}")
+          FILE(WRITE ${_build_unit_file} "${_build_unit_include_string}")
+        ENDIF()
+        LIST(APPEND _${_target_name}_source_files ${_build_unit_file})
+        LIST(APPEND _${_target_name}_build_units ${_build_unit_file})
+        # Store the number of files included. May be used for full build units.
+        SET_SOURCE_FILES_PROPERTIES(${_build_unit_file}
+          PROPERTIES BUILD_UNIT_SIZE "${_build_unit_count}")
+      ENDIF()
+      SET(_add_to_build_unit FALSE)
+    ELSEIF(_get_build_unit_file)
+      # Note: ${_file} is relative to the binary directory
+      SET(_build_unit_file ${CMAKE_BINARY_DIR}/${_file})
+      SET(_get_build_unit_file FALSE)
+      SET(_add_to_build_unit TRUE)
+      SET(_build_unit_include_string)
+      SET(_build_unit_count "0")
     ELSE()
       # Default, add source file
@@ -146,8 +159,9 @@
       LIST(APPEND _${_target_name}_source_files ${_file})
 
-      # Handle compilations
-      IF(_add_to_compilation AND NOT DISABLE_COMPILATIONS)
+      # Handle build units
+      IF(_add_to_build_unit AND ENABLE_BUILD_UNITS)
         IF(_file MATCHES "\\.(c|cc|cpp|cxx)$")
-          SET(_compilation_include_string "${_compilation_include_string}#include \"${_file}\"\n")
+          SET(_build_unit_include_string "${_build_unit_include_string}#include \"${_file}\"\n")
+          MATH(EXPR _build_unit_count "1 + ${_build_unit_count}")
         ENDIF()
         # Don't compile these files, even if they are source files
@@ -183,4 +197,18 @@
   ENDIF()
 
+  # Mark files to be excluded from build units
+  IF(_arg_EXCLUDE_FROM_BUILD_UNITS)
+    SET_SOURCE_FILES_PROPERTIES(${_arg_EXCLUDE_FROM_BUILD_UNITS}
+      PROPERTIES EXCLUDE_FROM_BUILD_UNITS TRUE)
+  ENDIF()
+
+  # Full build units
+  IF(ENABLE_BUILD_UNITS AND NOT _arg_NO_BUILD_UNITS)
+    # Use full build units even in partial mode for externals
+    IF(ENABLE_BUILD_UNITS MATCHES "full" OR _arg_ORXONOX_EXTERNAL)
+      GENERATE_BUILD_UNITS(${_target_name} _${_target_name}_files)
+    ENDIF()
+  ENDIF()
+
   # First part (pre target) of precompiled header files
   IF(PCH_COMPILER_SUPPORT AND _arg_PCH_FILE)
@@ -196,5 +224,5 @@
     MARK_AS_ADVANCED(PCH_ENABLE_${_target_name_upper})
 
-    IF(PCH_ENABLE_${_target_name_upper})
+    IF(PCH_ENABLE_${_target_name_upper} AND NOT PCH_DISABLE_${_target_name})
       PRECOMPILED_HEADER_FILES_PRE_TARGET(${_target_name} ${_arg_PCH_FILE} _${_target_name}_files EXCLUDE ${_arg_PCH_EXCLUDE})
     ENDIF()
@@ -344,5 +372,5 @@
 
   # Second part of precompiled header files
-  IF(PCH_COMPILER_SUPPORT AND PCH_ENABLE_${_target_name_upper} AND _arg_PCH_FILE)
+  IF(PCH_COMPILER_SUPPORT AND PCH_ENABLE_${_target_name_upper} AND _arg_PCH_FILE AND NOT PCH_DISABLE_${_target_name})
     PRECOMPILED_HEADER_FILES_POST_TARGET(${_target_name} ${_arg_PCH_FILE})
   ENDIF()
