// ============================================================== // 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 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 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(this)->get(pos); } return def; } bool setInfluence(Point pos, iType val) { pos = translate(pos); if (pos != invalidPos) { static_cast(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 class TypeMap : public InfluenceMap > { friend class InfluenceMap >; public: TypeMap(Rectangle b, type def) : InfluenceMap >(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, TypeMap 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 class PatchMap : public InfluenceMap > { friend class InfluenceMap >; public: PatchMap(Rectangle b, uint32 def) : InfluenceMap >(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 &operator=(const PatchMap &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 < 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 { friend class InfluenceMap; 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(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