| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617 |
- /******************************************************************************/
- #include "stdafx.h"
- namespace EE{
- namespace Game{
- /******************************************************************************/
- // AREA OBJECT
- /******************************************************************************/
- Bool Area::Data::AreaObj::save(File &f, CChar *path)C
- {
- f.cmpUIntV(0); // version
- f<<id;
- if(super::saveData(f, path))
- return f.ok();
- return false;
- }
- Bool Area::Data::AreaObj::load(File &f, CChar *path)
- {
- switch(f.decUIntV())
- {
- case 0:
- {
- f>>id;
- if(super::loadData(f, path))
- if(f.ok())return true;
- }break;
- }
- return false;
- }
- Bool Area::Data::AreaObj::loadOld(File &f)
- {
- id.randomize();
- if(super::loadData(f))
- if(f.ok())return true;
- return false;
- }
- /******************************************************************************/
- // AREA PATH
- /******************************************************************************/
- void AreaPath2D::zero()
- {
- _changed=false;
- _groups =0;
- }
- AreaPath2D::AreaPath2D() {zero();}
- void AreaPath2D::del()
- {
- _map.del();
- _neighbor.del();
- zero();
- }
- void AreaPath2D::create(Int size)
- {
- _map.createSoftTry(size, size, 1, IMAGE_I8);
- _map.clear();
- group();
- }
- void AreaPath2D::createFromQuarter(AreaPath2D &src, Bool right, Bool forward, WorldSettings &settings)
- {
- src._map.crop(_map, right ? src._map.w()/2 : 0, forward ? src._map.h()/2 : 0, src._map.w()/2, src._map.h()/2);
- _map.resize(settings.path2DRes(), settings.path2DRes(), FILTER_NONE);
- group();
- }
- void AreaPath2D::createFromQuad(AreaPath2D *lb, AreaPath2D *rb, AreaPath2D *lf, AreaPath2D *rf, WorldSettings &settings)
- {
- create(settings.path2DRes());
- REPD(y, _map.h())
- REPD(x, _map.w())
- {
- AreaPath2D *src=null;
- Bool right =(x>=(_map.w()/2)), // if right half should be taken
- forward=(y>=(_map.h()/2)); // if forward half should be taken
- if(right)
- {
- if(forward)src=rf;else src=rb;
- }
- else // left
- {
- if(forward)src=lf;else src=lb;
- }
- if(src)
- {
- Int src_x=((right ? x-_map.w()/2 : x)*src->_map.w())/(_map.w()/2),
- src_y=((forward ? y-_map.h()/2 : y)*src->_map.h())/(_map.h()/2);
- _map.pixel(x, y, src->_map.pixel(src_x, src_y));
- }
- }
- group();
- }
- /******************************************************************************/
- Bool AreaPath2D::walkable(Int x, Int y)C
- {
- return (InRange(x, _map.w()) && InRange(y, _map.h())) ? _map.pixB(x, y)!=0xFF : false;
- }
- AreaPath2D& AreaPath2D::walkable(Int x, Int y, Bool walkable)
- {
- if(InRange(x, _map.w())
- && InRange(y, _map.h()))
- {
- _map.pixB(x, y)=(walkable ? 0xFE : 0xFF);
- _changed=true;
- }
- return T;
- }
- /******************************************************************************/
- Bool AreaPath2D::fullyWalkable()
- {
- REPD(y, _map.h())
- REPD(x, _map.w())if(!walkable(x, y))return false;
- return true;
- }
- /******************************************************************************/
- void AreaPath2D::group()
- {
- // set groups
- {
- #define BLOCKED 0xFFFF
- UShort path [MAX_PATH_RES][MAX_PATH_RES], // [y][x]
- new_group[65536];
- Bool parent [65536];
- // set map
- Int groups=0;
- REPD(y, _map.h())
- REPD(x, _map.w())path[y][x]=(walkable(x, y) ? groups++ : BLOCKED);
- // set group remap
- REP(groups)new_group[i]=i;
- // join
- REP((Max(_map.w(), _map.h())>=48) ? 3 : 2) // steps
- {
- REP(groups)parent[i]=false;
- // link with neighbors
- FREPD(y, _map.h())
- FREPD(x, _map.w())
- {
- UInt g=path[y][x];
- if( g!=BLOCKED && new_group[g]==g) // it's not blocked and it's a main group (it can be linked)
- {
- Bool right=false, left=false, up=false, down=false;
- Int r =x+1 , l =x-1 , u =y+1 , d =y-1 ;
- // try linking right
- if(InRange(r, _map.w()))
- {
- UInt n =path[y][r]; // neighbor
- if( n!=BLOCKED)
- {
- right=true;
- if(n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
- }
- }
- // try linking up
- if(InRange(u, _map.h()))
- {
- UInt n =path[u][x]; // neighbor
- if( n!=BLOCKED)
- {
- up=true;
- if(n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
- }
- }
-
- #if 0
- // try linking left
- if(InRange(l, _map.w()))
- {
- UInt n =path[y][l]; // neighbor
- if( n!=BLOCKED)
- {
- left=true;
- if(n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
- }
- }
- // try linking down
- if(InRange(d, _map.h()))
- {
- UInt n =path[d][x]; // neighbor
- if( n!=BLOCKED)
- {
- down=true;
- if(n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
- }
- }
- #endif
-
- // try linking diagonal
- #if 1
- if(right || up)if(InRange(r, _map.w()) && InRange(u, _map.h()))
- {
- UInt n =path[u][r]; // neighbor
- if( n!=BLOCKED && n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
- }
- #if 0
- if(left || up)if(InRange(l, AREA_PATH_RES) && InRange(u, AREA_PATH_RES))
- {
- UInt n =path[u][l]; // neighbor
- if( n!=BLOCKED && n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
- }
- if(right || down)if(InRange(r, AREA_PATH_RES) && InRange(d, AREA_PATH_RES))
- {
- UInt n =path[d][r]; // neighbor
- if( n!=BLOCKED && n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
- }
- if(left || down)if(InRange(l, AREA_PATH_RES) && InRange(d, AREA_PATH_RES))
- {
- UInt n =path[d][l]; // neighbor
- if( n!=BLOCKED && n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
- }
- #endif
- #endif
- }
- }
- // update groups map
- REPD(y, _map.h())
- REPD(x, _map.w())
- {
- UInt g =path[y][x];
- if( g!=BLOCKED)path[y][x]=new_group[g];
- }
- }
- // set target map
- T._groups=0;
- REP(groups)new_group[i]=BLOCKED; // set not yet added to target 'path' map
- REPD(y, _map.h())
- REPD(x, _map.w())
- {
- UInt g =path[y][x];
- if( g!=BLOCKED)
- {
- UShort &n=new_group[g];
- if( n==BLOCKED)n=T._groups++; // not yet added
- _map.pixB(x, y)=n; // set target map
- }
- }
- }
- // find neighbors
- VecI2 offset[]=
- {
- VecI2(-1, 1),
- VecI2( 0, 1),
- VecI2( 1, 1),
- VecI2(-1, 0),
- };
- _neighbor.clear();
- REPD(y, _map.h())
- REPD(x, _map.w())
- {
- Int a =_map.pixB(x, y);
- if( a!=0xFF)
- {
- REPA(offset)
- {
- Int sx=x+offset[i].x,
- sy=y+offset[i].y;
- if(InRange(sx, _map.w())
- && InRange(sy, _map.h()))
- {
- Int b =_map.pixB(sx,sy);
- if( b!=0xFF && a!=b)
- {
- Byte cost=5;
- if(offset[i].x && offset[i].y) // if diagonal
- {
- // if blocked diagonal
- if(!walkable(sx, y)
- && !walkable( x, sy))continue; // don't add
- cost=7; // increase the movement cost
- }
- // check if the neighbor entry already exists
- Int min, max; MinMax(a, b, min, max);
- REPA(_neighbor)
- {
- Neighbor &n=_neighbor[i];
- if(n.a==min && n.b==max){MIN(n.cost, cost); goto exists;}
- }
- _neighbor.New().set(min, max, cost);
- exists:;
- }
- }
- }
- }
- }
- _changed=false;
- }
- /******************************************************************************/
- void AreaPath2D::resize(Int size)
- {
- _map.resize(size, size, FILTER_NONE);
- group();
- }
- /******************************************************************************/
- Bool AreaPath2D::save(File &f)C
- {
- f.cmpUIntV(1); // version
- f<<_groups;
- if(_map . save (f))
- if(_neighbor._saveRaw(f))
- return f.ok();
- return false;
- }
- Bool AreaPath2D::load(File &f)
- {
- _changed=false;
- switch(f.decUIntV()) // version
- {
- case 1:
- {
- f>>_groups;
- if(_map . load (f))
- if(_neighbor._loadRaw(f))
- if(f.ok())return true;
- }break;
- case 0:
- {
- Byte path[32][32]; // [y][x]
- f>>path>>_groups;
- if(_neighbor._loadRaw(f))
- if(_map.createSoftTry(32, 32, 1, IMAGE_I8))
- {
- REPD(y, _map.h())
- REPD(x, _map.w())_map.pixB(x, y)=path[y][x];
- if(f.ok())return true;
- }
- }break;
- }
- del(); return false;
- }
- /******************************************************************************/
- // AREA DATA
- /******************************************************************************/
- Area::Data::~Data()
- {
- Delete(_path_mesh);
- Delete(_path2D );
- }
- Area::Data::Data(Area &area)
- {
- T._area =&area;
- T._path_mesh=null;
- T._path2D =null;
- T._path_node_offset=0;
- }
- Bool Area::Data::save(File &f)
- {
- ChunkWriter cw(f);
- if(height.is() || material_map.is() || materials.elms())if(File *f=cw.beginChunk("Heightmap", 0))
- {
- if(!height .save(*f))return false;
- if(!material_map.save(*f))return false;
- f->putInt(materials.elms()); REPA(materials)f->_putStr(materials[i].name());
- }
- if(mesh .is ())if(File *f=cw.beginChunk("Mesh" , 0))if(!mesh.save(*f))return false;
- if(phys .is ())if(File *f=cw.beginChunk("Phys" , 0))if(!phys.save(*f))return false;
- if(objs .elms())if(File *f=cw.beginChunk("Object" , 1))FREPA(objs)if(!objs[i].save(*f))return false;
- if(decals .elms())if(File *f=cw.beginChunk("Decal" , 0))if(!decals ._save(*f))return false;
- if(mesh_overlays.elms())if(File *f=cw.beginChunk("Mesh Overlay", 0))if(!mesh_overlays._save(*f))return false;
- if(_path_mesh )if(File *f=cw.beginChunk("PathMesh" , 0))if(!_path_mesh -> save(*f))return false;
- if(_path2D )if(File *f=cw.beginChunk("AreaPath" , 0))if(!_path2D -> save(*f))return false;
- if(waters .elms())if(File *f=cw.beginChunk("Water" , 0))if(!waters ._save(*f))return false;
- if(!customSave(cw))return false;
- cw.endChunkList();
- return f.ok();
- }
- Bool Area::Data::load(File &f)
- {
- for(ChunkReader cr(f); File *f=cr();)
- {
- if(cr.name()=="HeightmapMesh")switch(cr.ver())
- {
- case 0: mesh.loadAdd(*f); break;
- }else
- if(cr.name()=="HeightmapPhys")switch(cr.ver())
- {
- case 0: phys.loadAdd(*f); break;
- }else
- if(cr.name()=="ObjectMesh")switch(cr.ver())
- {
- case 0: mesh.loadAdd(*f); break;
- }else
- if(cr.name()=="ObjectPhys")switch(cr.ver())
- {
- case 0: phys.loadAdd(*f); break;
- }else
- if(cr.name()=="Heightmap")switch(cr.ver())
- {
- case 0: if(!height.load(*f))break; if(!material_map.load(*f))break; materials.setNum(f->getInt()); REPAO(materials)=f->_getStr(); break;
- }else
- if(cr.name()=="Mesh")switch(cr.ver())
- {
- case 0: mesh.loadAdd(*f); break;
- }else
- if(cr.name()=="Phys")switch(cr.ver())
- {
- case 0: phys.loadAdd(*f); break;
- }else
- if(cr.name()=="Object")switch(cr.ver())
- {
- case 1: for(; !f->end(); )if(!objs.New().load (*f)){objs.removeLast(); break;} break;
- case 0: for(; !f->end(); )if(!objs.New().loadOld(*f)){objs.removeLast(); break;} break;
- }else
- if(cr.name()=="Decal")switch(cr.ver())
- {
- case 0: decals._load(*f); break;
- }else
- if(cr.name()=="Mesh Overlay")switch(cr.ver())
- {
- case 0: mesh_overlays._load(*f); break;
- }else
- if(cr.name()=="PathMesh")switch(cr.ver())
- {
- case 0: New(Delete(_path_mesh))->load(*f); break;
- }else
- if(cr.name()=="AreaPath")switch(cr.ver())
- {
- case 0: New(Delete(_path2D))->load(*f); break;
- }else
- if(cr.name()=="Water")switch(cr.ver())
- {
- case 0: waters._load(*f); break;
- }else
- {
- customLoad(*f, cr.name(), cr.ver());
- }
- }
- // setup terrain/foliage objects (these containers should not be saved, because they are dynamically created from 'objs' which are already stored)
- terrain_objs_box.zero(); Bool have_terrain_box=false, have_foliage_box=false;
- foliage_objs_box.zero();
- terrain_objs.clear();
- foliage_objs.clear();
- FREPA(objs) // add in order
- {
- C AreaObj &obj=objs[i];
- switch(obj.access())
- {
- case OBJ_ACCESS_TERRAIN: if(obj.base())
- {
- TerrainObj &ter_obj=terrain_objs.New();
- ter_obj.obj =obj.base();
- ter_obj.matrix =obj.matrixFinal();
- ter_obj.mesh_variation=obj.meshVariationIndex();
- if(ter_obj.obj->mesh())
- {
- Box box=ter_obj.obj->mesh()->ext*ter_obj.matrix;
- if(have_terrain_box)terrain_objs_box|=box;
- else {terrain_objs_box =box; have_terrain_box=true;}
- }
- }break;
- case OBJ_ACCESS_GRASS:
- {
- Int mesh_variation=obj.meshVariationIndex();
- GrassObj *foliage=null; REPA(foliage_objs){GrassObj &fo=foliage_objs[i]; if(fo.mesh==obj.mesh() && fo.phys==obj.phys() && fo.mesh_variation==mesh_variation){foliage=&fo; break;}}
- if(!foliage) // create new one
- {
- foliage=&foliage_objs.New();
- foliage->shrink =false;
- foliage->mesh =obj.mesh();
- foliage->phys =obj.phys();
- foliage->mesh_variation=mesh_variation;
- }
- GrassObj::Instance &instance=foliage->instances.New(); // set new instance
- instance.matrix=obj.matrixFinal();
- if(obj.mesh())
- {
- Box box=obj.mesh()->ext*instance.matrix;
- if(have_foliage_box)foliage_objs_box|=box;
- else {foliage_objs_box =box; have_foliage_box=true;}
- }
- }break;
- }
- }
- if(f.ok())return true;
- /*del();*/ return false;
- }
- /******************************************************************************/
- // AREA
- /******************************************************************************/
- Area::~Area()
- {
- Delete(_data);
- }
- Area::Area(C VecI2 &xy, Ptr grid_user)
- {
- T._visited=false;
- T._temp =false;
- T._xz =xy;
- T._state =AREA_UNLOADED;
- T._data =null;
- T._saved_obj.writeMem(1024);
- T._world =(WorldManager*)grid_user;
- }
- /******************************************************************************/
- Flt Area::hmHeight(C Vec2 &xz, Bool smooth)C
- {
- if(_data)
- {
- Image &height=_data->height;
- if( height.is())
- {
- Vec2 pixel=xz/world()->areaSize(); // in area coordinates space
- pixel.x-=T._xz.x; //
- pixel.y-=T._xz.y; // local fraction
- pixel.x*=height.w()-1;
- pixel.y*=height.h()-1; // image space
- return smooth ? height.pixelFLinear( pixel.x , pixel.y, true)
- : height.pixelF (RoundPos(pixel.x), RoundPos(pixel.y) );
- }
- }
- return 0;
- }
- /******************************************************************************/
- C MaterialPtr& Area::hmMaterial(C Vec2 &xz)C
- {
- if(_data)
- {
- Image &map=_data->material_map;
- if( map.is())
- {
- Vec2 pixel=xz/world()->areaSize(); // in area coordinates space
- pixel.x-=T._xz.x; //
- pixel.y-=T._xz.y; // local fraction
- pixel.x*=map.w()-1;
- pixel.y*=map.h()-1; // image space
- UInt index=map.pixel(RoundPos(pixel.x), RoundPos(pixel.y)); // material index
- if(InRange(index, _data->materials))return _data->materials[index];
- }
- }
- return MaterialNull;
- }
- /******************************************************************************/
- Area::Data* Area::getData()
- {
- if(state()!=AREA_UNLOADED)if(!data())world()->_area_data(_data, T); // first check state, then data (in case the Area is being loaded in background thread)
- return data();
- }
- /******************************************************************************/
- void Area::setShader()
- {
- if(_data)
- {
- _data-> mesh.setShader();
- _data->customSetShader();
- }
- }
- /******************************************************************************/
- Bool Area::saveObj(Obj &obj)
- {
- #if 1 // save using Obj Type ID (this allows to load objects correctly after obj type name has changed, as long as it has the same ID as before)
- C UID &obj_type_id=ObjType.elmID(world()->objType(obj));
- if( obj_type_id.valid())
- {
- ChunkWriter cw; cw.appendChunkList(_saved_obj);
- if(File *f=cw.beginChunk(EncodeRaw(obj_type_id), 1)) // OBJ_TYPE id
- {
- if(!obj.save(*f))return false; // object data
- cw.endChunk();
- }
- }
- #else // save using Obj Type Name
- CChar8 *obj_type_name=ObjType.elmName(world()->objType(obj));
- if(Is( obj_type_name))
- {
- ChunkWriter cw; cw.appendChunkList(_saved_obj);
- if(File *f=cw.beginChunk(obj_type_name, 0)) // OBJ_TYPE name
- {
- if(!obj.save(*f))return false; // object data
- cw.endChunk();
- }
- }
- #endif
- return _saved_obj.ok();
- }
- Bool Area::saveObjs()
- {
- _saved_obj.reset();
- FREPA(_objs)
- {
- Obj &obj=*_objs[i];
- if( !obj.isConst() && obj.canBeSaved())if(!saveObj(obj))return false; // don't save constant objects, and save only those which want to be saved
- }
- return true;
- }
- Bool Area::save(File &f, C VecI2 &xy)
- {
- if(_visited || _saved_obj.size()) // if visited or has any objects to save
- {
- f<<xy<<_visited;
- f.cmpUIntV(_saved_obj.size());
- _saved_obj.pos(0); if(!_saved_obj.copy(f))return false;
- return f.ok();
- }
- return true;
- }
- Bool Area::load(File &f)
- {
- f>>_visited;
- Int size=f.decUIntV();
- return f.ok() && f.copy(_saved_obj, size);
- }
- /******************************************************************************/
- }}
- /******************************************************************************/
|