MegaGlest/source/glest_game/ai/influence_map.h

256 lines
7.6 KiB
C++

// ==============================================================
// This file is part of Glest (www.glest.org)
//
// Copyright (C) 2009 James McCulloch
//
// You can redistribute this code 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
// ==============================================================
#ifndef _GAME_SEARCH_INLUENCE_MAP_H_
#define _GAME_SEARCH_INLUENCE_MAP_H_
#include "vec.h"
#include "types.h"
#include <algorithm>
namespace Glest { namespace Game {
using Shared::Platform::uint32;
typedef Shared::Graphics::Vec2i Point;
struct Rectangle {
Rectangle() : x(0), y(0), w(0), h(0) {}
Rectangle(int x, int y, int w, int h) : x(x), y(y), w(w), h(h) {}
int x, y, w, h;
};
const Point invalidPos(-1,-1);
// =====================================================
// class InfluenceMap
// =====================================================
template<typename iType, typename MapType> class InfluenceMap {
public:
InfluenceMap(Rectangle b, iType def) : def(def), x(b.x), y(b.y), w(b.w), h(b.h) {}
iType getInfluence(Point pos) {
pos = translate(pos);
if (pos != invalidPos) {
return static_cast<MapType*>(this)->get(pos);
}
return def;
}
bool setInfluence(Point pos, iType val) {
pos = translate(pos);
if (pos != invalidPos) {
static_cast<MapType*>(this)->set(pos, val);
return true;
}
return false;
}
Point translate(Point p) {
const int nx = p.x - x;
const int ny = p.y - y;
if (nx >= 0 && ny >=0 && nx < w && ny < h) {
return Point(nx, ny);
}
return invalidPos;
}
Point getPos() const { return Point(x, y); }
Rectangle getBounds() const { return Rectangle(x, y, w, h); }
protected:
iType def; // defualt value for positions not within (this) maps dimensions
int x , y, w, h; // Dimensions of this map.
};
// =====================================================
// class TypeMap
// =====================================================
template<typename type = float> class TypeMap : public InfluenceMap<type, TypeMap<type> > {
friend class InfluenceMap<type, TypeMap<type> >;
public:
TypeMap(Rectangle b, type def) : InfluenceMap<type, TypeMap<type> >(b,def) {
data = new type[b.w*b.h];
}
~TypeMap() { delete [] data; }
void zeroMap() { memset(data, 0, sizeof(type) * this->w * this->h); }
void clearMap(type val) { std::fill_n(data, this->w * this->h, val); }
private:
type get(Point p) { return data[p.y * this->w + p.x]; }
void set(Point p, type v) { data[p.y * this->w + p.x] = v; }
type *data;
};
// =====================================================
// class PatchMap
// =====================================================
/** bit packed InfluenceMap, values are bit packed into 32 bit 'sections' (possibly padded)
* Not usefull for bits >= 7, just use TypeMap<uint8>, TypeMap<uint16> etc...
* bit wastage:
* bits == 1, 2 or 4: no wastage in full sections
* bits == 3, 5 or 6: 2 bits wasted per full section
*/
template<int bits> class PatchMap : public InfluenceMap<uint32, PatchMap<bits> > {
friend class InfluenceMap<uint32, PatchMap<bits> >;
public:
PatchMap(Rectangle b, uint32 def) : InfluenceMap<uint32,PatchMap<bits> >(b,def) {
//cout << "PatchMap<" << bits << "> max_value = "<< max_value <<", [width = " << b.w << " height = " << b.h << "]\n";
sectionsPerRow = b.w / sectionSize + 1;
//cout << "section size = " << sectionSize << ", sections per row = " << sectionsPerRow << endl;
data = new uint32[b.h * sectionsPerRow];
}
//only for infuence_map_test.cpp:249
PatchMap<bits> &operator=(const PatchMap<bits> &op){
//FIXME: better when moved to InfluenceMap::operator=...
this->def = op.def;
this->x = op.x; this->y = op.y; this->w = op.w; this->h = op.h;
//
sectionsPerRow = op.sectionsPerRow;
delete[] data;
data = new uint32[op.h * sectionsPerRow];
memcpy(data, op.data, op.h * sectionsPerRow);
return *this;
}
~PatchMap() { delete [] data; }
void zeroMap() { memset(data, 0, sizeof(uint32) * sectionsPerRow * this->h); }
void clearMap(uint32 val) {
// assert(val < max_value);
data[0] = 0;
for ( int i=0; i < sectionSize - 1; ++i) {
data[0] |= val;
data[0] <<= bits;
}
data[0] |= val;
for ( int i=1; i < sectionsPerRow; ++i ) {
data[i] = data[0];
}
const int rowSize = sectionsPerRow * sizeof(uint32);
for ( int i=1; i < this->h; ++i ) {
uint32 *ptr = &data[i * sectionsPerRow];
memcpy(ptr, data, rowSize);
}
}
private:
uint32 get(Point p) {
int sectionNdx = p.y * sectionsPerRow + p.x / sectionSize;
int subSectionNdx = p.x % sectionSize;
uint32 val = (data[sectionNdx] >> (subSectionNdx * bits)) & max_value;
//cout << "get(" << p.x << "," << p.y << "). section=" << sectionNdx
// << ", subsection=" << subSectionNdx << " = " << val <<endl;
return val;
}
void set(Point p, uint32 v) {
if (v > max_value) { //clamp?
v = max_value;
}
int sectionNdx = p.y * sectionsPerRow + p.x / sectionSize;
int subSectionNdx = p.x % sectionSize;
uint32 val = v << bits * subSectionNdx;
uint32 mask = max_value << bits * subSectionNdx;
data[sectionNdx] &= ~mask; // blot out old value
data[sectionNdx] |= val; // put in the new value
}/*
void logSection(int s) {
cout << "[";
for ( int j = 31; j >= 0; --j ) {
uint32 bitmask = 1 << j;
if ( data[s] & bitmask ) cout << "1";
else cout << "0";
if ( j && j % bits == 0 ) cout << " ";
}
cout << "]" << endl;
}*/
static const uint32 max_value = (1 << bits) - 1;
static const int sectionSize = 32 / bits;
int sectionsPerRow;
uint32 *data;
};
// =====================================================
// class FlowMap
// =====================================================
/** bit packed 'offset' map, where offset is of the form -1 <= x <= 1 && -1 <= y <= 1 */
class FlowMap : public InfluenceMap<Point, FlowMap> {
friend class InfluenceMap<Point, FlowMap>;
private:
Point expand(uint32 v) {
Point res(0,0);
if ( v & 8 ) { res.x = -1; }
else if ( v & 4 ) { res.x = 1; }
if ( v & 2 ) { res.y = -1; }
else if ( v & 1 ) { res.y = 1; }
return res;
}
uint32 pack(Point v) {
uint32 res = 0;
if ( v.x ) { res = 1 << (v.x > 0 ? 2 : 3); }
if ( v.y ) { res |= 1 << (v.y > 0 ? 0 : 1); }
return res;
}
public:
FlowMap(Rectangle b, Point def) : InfluenceMap<Point,FlowMap>(b,def) {
blocksPerRow = b.w / 8 + 1;
data = new uint32[b.h * blocksPerRow];
}
~FlowMap() { delete [] data; }
void zeroMap() { memset(data, 0, sizeof(uint32) * blocksPerRow * h); }
void clearMap(Point val) {
uint32 v = pack(val);
data[0] = 0;
for ( int i=0; i < 7; ++i ) {
data[0] |= v;
data[0] <<= 4;
}
data[0] |= v;
for ( int i=1; i < blocksPerRow; ++i ) {
data[i] = data[0];
}
const int rowSize = blocksPerRow * sizeof(uint32);
for ( int i=1; i < h; ++i ) {
uint32 *ptr = &data[i * blocksPerRow];
memcpy(ptr, data, rowSize);
}
}
private:
Point get(Point p) {
const int blockNdx = p.y * blocksPerRow + p.x / 8;
const int subBlockNdx = p.x % 8;
uint32 val = (data[blockNdx] >> (subBlockNdx * 4)) & 15;
return expand(val);
}
void set(Point p, Point v) {
int blockNdx = p.y * blocksPerRow + p.x / 8;
int subBlockNdx = p.x % 8;
uint32 val = pack(v) << 4 * subBlockNdx;
uint32 mask = 15 << 4 * subBlockNdx;
data[blockNdx] &= ~mask; // blot out old value
data[blockNdx] |= val; // put in the new value
}/*
void logSection(int s) {
cout << "[";
for ( int j = 31; j >= 0; --j ) {
uint32 bitmask = 1 << j;
if ( data[s] & bitmask ) cout << "1";
else cout << "0";
if ( j && j % 4 == 0 ) cout << " ";
}
cout << "]" << endl;
}*/
int blocksPerRow;
uint32 *data; // 8 values each
};
}}
#endif