#include "region_map_v1.h" #include "../../common/Log.h" RegionMapV1::RegionMapV1() { } RegionMapV1::~RegionMapV1() { map::const_iterator itr; int region_num = 0; for (itr = Regions.begin(); itr != Regions.end();) { Region_Node* node = itr->first; ZBSP_Node* bsp_node = itr->second; map::const_iterator deleteItr = itr; itr++; Regions.erase(deleteItr); safe_delete(node); safe_delete_array(bsp_node); } Regions.clear(); } WaterRegionType RegionMapV1::ReturnRegionType(const glm::vec3& location, float belowY) const { return BSPReturnRegionType(1, glm::vec3(location.y, location.x + 0.5f, location.z)); } bool RegionMapV1::InWater(const glm::vec3& location, float belowY) const { return ReturnRegionType(location, belowY) == RegionTypeWater; } bool RegionMapV1::InLava(const glm::vec3& location) const { return ReturnRegionType(location) == RegionTypeLava; } bool RegionMapV1::InLiquid(const glm::vec3& location) const { return InWater(location) || InLava(location); } bool RegionMapV1::InPvP(const glm::vec3& location) const { return ReturnRegionType(location) == RegionTypePVP; } bool RegionMapV1::InZoneLine(const glm::vec3& location) const { return ReturnRegionType(location) == RegionTypeZoneLine; } bool RegionMapV1::Load(FILE* fp) { uint32 region_size; if (fread(®ion_size, sizeof(region_size), 1, fp) != 1) { return false; } LogWrite(REGION__DEBUG, 0, "RegionMap", "region count = %u", region_size); for (int i = 0; i < region_size; i++) { uint32 region_num; if (fread(®ion_num, sizeof(region_num), 1, fp) != 1) { return false; } uint32 region_type; if (fread(®ion_type, sizeof(region_type), 1, fp) != 1) { return false; } float x, y, z, dist; if (fread(&x, sizeof(x), 1, fp) != 1) { return false; } if (fread(&y, sizeof(y), 1, fp) != 1) { return false; } if (fread(&z, sizeof(z), 1, fp) != 1) { return false; } if (fread(&dist, sizeof(dist), 1, fp) != 1) { return false; } uint32 bsp_tree_size; if (fread(&bsp_tree_size, sizeof(bsp_tree_size), 1, fp) != 1) { return false; } LogWrite(REGION__DEBUG, 0, "RegionMap", "region x,y,z,dist = %f, %f, %f, %f, region bsp tree size: %u", x, y, z, dist, bsp_tree_size); ZBSP_Node* BSP_Root = new ZBSP_Node[bsp_tree_size]; if (fread(BSP_Root, sizeof(ZBSP_Node), bsp_tree_size, fp) != bsp_tree_size) { LogWrite(REGION__ERROR, 0, "RegionMap", "Failed to load region."); return false; } Region_Node* tmpNode = new Region_Node; tmpNode->x = x; tmpNode->y = y; tmpNode->z = z; tmpNode->dist = dist; tmpNode->region_type = region_type; Regions.insert(make_pair(tmpNode, BSP_Root)); } fclose(fp); LogWrite(REGION__DEBUG, 0, "RegionMap", "completed load!"); return true; } WaterRegionType RegionMapV1::BSPReturnRegionType(int32 node_number, const glm::vec3& location) const { map::const_iterator itr; int region_num = 0; for (itr = Regions.begin(); itr != Regions.end(); itr++) { Region_Node* node = itr->first; ZBSP_Node* BSP_Root = itr->second; float x1 = node->x - location.x; float y1 = node->y - location.y; float z1 = node->z - location.z; float dist = sqrt(x1 * x1 + y1 * y1 + z1 * z1); #ifdef REGIONDEBUG printf("Region %i (%i) dist %f / node dist %f. NodeXYZ: %f %f %f, XYZ: %f %f %f.\n", region_num, node->region_type, dist, node->dist, node->x, node->y, node->z, location.x, location.y, location.z); #endif if (dist <= node->dist) { ZBSP_Node* BSP_Root = itr->second; const ZBSP_Node* current_node = &BSP_Root[node_number - 1]; WaterRegionType regionType = RegionTypeUntagged; if (node->region_type == ClassWaterRegion) regionType = BSPReturnRegionWaterRegion(node, BSP_Root, node_number, location, dist); else regionType = BSPReturnRegionTypeNode(node, BSP_Root, node_number, location, dist); if (regionType != RegionTypeNormal) return regionType; } region_num++; } return(RegionTypeNormal); } WaterRegionType RegionMapV1::BSPReturnRegionTypeNode(const Region_Node* region_node, const ZBSP_Node* BSP_Root, int32 node_number, const glm::vec3& location, float distToNode) const { const ZBSP_Node* current_node = &BSP_Root[node_number - 1]; float distance; #ifdef REGIONDEBUG printf("left = %u, right %u\n", current_node->left, current_node->right); #endif if (region_node->region_type == ClassWaterRegion2) { distance = (location.x * current_node->normal[0]) + (location.y * current_node->normal[1]) + (location.z * current_node->normal[2]) + current_node->splitdistance; } else { distance = (location.x * current_node->normal[0]) + (location.y * current_node->normal[1]) + (location.z * current_node->normal[2]) - current_node->splitdistance; } float absDistance = distance; if (absDistance < 0.0f) absDistance *= -1.0f; float absSplitDist = current_node->splitdistance; if (absSplitDist < 0.0f) absSplitDist *= -1.0f; #ifdef REGIONDEBUG printf("distance = %f, normals: %f %f %f, location: %f %f %f, split distance: %f\n", distance, current_node->left, current_node->right, current_node->normal[0], current_node->normal[1], current_node->normal[2], location.x, location.y, location.z, current_node->splitdistance); #endif if ((current_node->left == -2) && (current_node->right == -1 || current_node->right == -2)) { if (region_node->region_type == ClassWaterOcean || region_node->region_type == ClassWaterOcean2) { if ( region_node->region_type == ClassWaterOcean && current_node->right == -1 && current_node->normal[1] >= 0.9f && distance > 0 ) return RegionTypeWater; else return EstablishDistanceAtAngle(region_node, current_node, distance, absDistance, absSplitDist, true); } else { if (distance > 0) return(RegionTypeWater); else return RegionTypeNormal; } } else if ((region_node->region_type == ClassWaterOcean || region_node->region_type == ClassWaterOcean2) && current_node->normal[1] != 1.0f && current_node->normal[1] != -1.0f) { float fraction = abs(current_node->normal[0] * current_node->normal[2]); float diff = distToNode / region_node->dist; if (distance > 0) diff = distance * diff; #ifdef REGIONDEBUG printf("Diff: %f (%f + %f), fraction %f\n", diff, distToNode, distance, fraction); #endif if ((abs(diff) / 2.0f) > (absSplitDist * (1.0f / fraction)) * 2.0f) return RegionTypeNormal; } if (distance == 0.0f) { return(RegionTypeNormal); } if (distance > 0.0f) { #ifdef REGIONDEBUG printf("to left node %i\n", current_node->left); #endif if (current_node->left == -2) { switch(region_node->region_type) { case ClassWaterVolume: case ClassWaterOcean: return RegionTypeWater; break; case ClassWaterOcean2: return EstablishDistanceAtAngle(region_node, current_node, distance, absDistance, absSplitDist, false); break; case ClassWaterCavern: return EstablishDistanceAtAngle(region_node, current_node, distance, absDistance, absSplitDist, true); break; default: return RegionTypeNormal; break; } } else if (current_node->left == -1) { return(RegionTypeNormal); } return BSPReturnRegionTypeNode(region_node, BSP_Root, current_node->left + 1, location, distToNode); } #ifdef REGIONDEBUG printf("to right node %i, sign bit %i\n", current_node->right, signbit(current_node->normal[1])); #endif if (current_node->right == -1) { if (region_node->region_type == ClassWaterOcean2 && signbit(current_node->normal[1]) == 0 && absDistance < absSplitDist) return RegionTypeWater; else if ((region_node->region_type == ClassWaterOcean || region_node->region_type == ClassWaterOcean2) && (current_node->normal[1] > 0.0f && distance < 0.0f && absDistance < absSplitDist)) { return(RegionTypeWater); } return(RegionTypeNormal); } return BSPReturnRegionTypeNode(region_node, BSP_Root, current_node->right + 1, location, distToNode); } WaterRegionType RegionMapV1::BSPReturnRegionWaterRegion(const Region_Node* region_node, const ZBSP_Node* BSP_Root, int32 node_number, const glm::vec3& location, float distToNode) const { const ZBSP_Node* current_node = &BSP_Root[node_number - 1]; float distance; #ifdef REGIONDEBUG printf("left = %u, right %u\n", current_node->left, current_node->right); #endif distance = (location.x * current_node->normal[0]) + (location.y * current_node->normal[1]) + (location.z * current_node->normal[2]) - current_node->splitdistance; #ifdef REGIONDEBUG printf("distance = %f, normals: %f %f %f, location: %f %f %f, split distance: %f\n", distance, current_node->left, current_node->right, current_node->normal[0], current_node->normal[1], current_node->normal[2], location.x, location.y, location.z, current_node->splitdistance); #endif if (distance > 0.0f) { #ifdef REGIONDEBUG printf("to left node %i\n", current_node->left); #endif if (current_node->left == -1) { return(RegionTypeNormal); } else if (current_node->left == -2) { return(RegionTypeWater); } return BSPReturnRegionWaterRegion(region_node, BSP_Root, current_node->left + 1, location, distToNode); } #ifdef REGIONDEBUG printf("to right node %i, sign bit %i\n", current_node->right, signbit(current_node->normal[1])); #endif if (current_node->right == -1) { return(RegionTypeNormal); } return BSPReturnRegionWaterRegion(region_node, BSP_Root, current_node->right + 1, location, distToNode); } WaterRegionType RegionMapV1::EstablishDistanceAtAngle(const Region_Node* region_node, const ZBSP_Node* current_node, float distance, float absDistance, float absSplitDist, bool checkEdgedAngle) const { float fraction = abs(current_node->normal[0] * current_node->normal[2]); #ifdef REGIONDEBUG printf("Distcheck: %f < %f\n", absDistance, absSplitDist); #endif if (absDistance < absSplitDist && (current_node->normal[0] >= 1.0f || current_node->normal[0] <= -1.0f || (current_node->normal[1] >= .9f && distance < 0.0f) || (current_node->normal[1] <= -.9f && distance > 0.0f))) { return RegionTypeWater; } else if (fraction > 0.0f && (region_node->region_type == ClassWaterOcean2 || checkEdgedAngle)) { if (current_node->normal[2] >= 1.0f || current_node->normal[2] <= -1.0f) return RegionTypeNormal; else if (current_node->normal[1] == 0.0f && (current_node->normal[0] < -0.5f || current_node->normal[0] > 0.5f) && ((abs(absDistance * current_node->normal[0]) / 2.0f) < ((abs(absSplitDist * (1.0f / fraction)))))) { return RegionTypeWater; } else if (current_node->normal[1] == 0.0f && (current_node->normal[2] < -0.5f || current_node->normal[2] > 0.5f) && ((abs(absDistance * current_node->normal[2]) / 2.0f) < ((abs(absSplitDist * (1.0f / fraction)))))) { return RegionTypeWater; } } return RegionTypeNormal; }