diff --git a/CMakeLists.txt b/CMakeLists.txt
index fde1ffdc5c8..29d75685c71 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -892,6 +892,7 @@ set( CGAMELIST
${GAMELOGIC_DIR}/cgame/cg_rocket_dataformatter.cpp
${GAMELOGIC_DIR}/cgame/cg_gameinfo.cpp
${GAMELOGIC_DIR}/cgame/cg_parseutils.cpp
+ ${GAMELOGIC_DIR}/cgame/Filter.cpp
${ENGINE_DIR}/client/cg_api.h
${ENGINE_DIR}/client/cg_msgdef.h
${ENGINE_DIR}/qcommon/print_translated.h
diff --git a/src/gamelogic/cgame/Filter.cpp b/src/gamelogic/cgame/Filter.cpp
new file mode 100644
index 00000000000..e5d4d17c7f3
--- /dev/null
+++ b/src/gamelogic/cgame/Filter.cpp
@@ -0,0 +1,94 @@
+/*
+===========================================================================
+
+Copyright 2015 Unvanquished Developers
+
+This file is part of Daemon.
+
+Daemon 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 3 of the License, or
+(at your option) any later version.
+
+Daemon 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 Daemon. If not, see .
+
+===========================================================================
+*/
+
+#include "cg_local.h"
+
+template
+Filter::Filter( int a_width )
+{
+ this->width = a_width;
+}
+
+template
+void Filter::Insert( T sample )
+{
+ this->samples.remove_if(
+ [&]( std::pair& sample )
+ {
+ return cg.time - sample.first > width;
+ }
+ );
+ this->samples.emplace( this->samples.begin( ), cg.time, sample );
+}
+
+template
+void Filter::Reset( )
+{
+ this->samples.clear( );
+}
+
+
+template
+T MAFilter::Get( )
+{
+ T total = 0;
+
+ for( auto s : this->samples )
+ total += s.second;
+
+ return total / this->samples.size( );
+}
+
+template
+T CubicMAFilter::Get( )
+{
+ T total = 0;
+ float weight, total_weight = 0;
+
+ for( auto s: this->samples )
+ {
+ weight = 1.0f - (float)( cg.time - s.first ) / this->width;
+ weight = weight * weight * weight;
+ total_weight += weight;
+ total += s.second * weight;
+ }
+
+ return total / total_weight;
+}
+
+template
+T GaussianMAFilter::Get( )
+{
+ T total = 0;
+ float weight, total_weight = 0;
+
+ for( auto s: this->samples )
+ {
+ weight = (float)( cg.time - s.first ) / this->width;
+ weight = exp( -8.0f * weight * weight );
+ total_weight += weight;
+ total += s.second * weight;
+ }
+
+ return total / total_weight;
+}
diff --git a/src/gamelogic/cgame/cg_local.h b/src/gamelogic/cgame/cg_local.h
index ae96215346d..f53bbed1a64 100644
--- a/src/gamelogic/cgame/cg_local.h
+++ b/src/gamelogic/cgame/cg_local.h
@@ -2375,5 +2375,48 @@ float CG_Rocket_ProgressBarValueByName( const char *name );
// cg_gameinfo.c
//
void CG_LoadArenas();
+
+//
+// Filter.cpp
+//
+
+template
+class Filter
+{
+protected:
+ std::list > samples;
+ int width;
+
+public:
+ Filter( int a_width );
+ void Insert( T sample );
+ void Reset( );
+ virtual T Get( ) = 0;
+};
+
+template
+class MAFilter: public Filter
+{
+public:
+ using Filter::Filter;
+ T Get( );
+};
+
+template
+class CubicMAFilter: public Filter
+{
+public:
+ using Filter::Filter;
+ T Get( );
+};
+
+template
+class GaussianMAFilter: public Filter
+{
+public:
+ using Filter::Filter;
+ T Get( );
+};
+
#endif