void MapSpecials::applyLineSlopeThing(SLADEMap* map, MapThing* thing) { int lineid = thing->intProperty("arg0"); if (!lineid) { LOG_MESSAGE(1, "Ignoring line slope thing %d with no lineid argument", thing->getIndex()); return; } // These are computed on first use, to avoid extra work if no lines match MapSector* containing_sector = nullptr; double thingz; vector<MapLine*> lines; map->getLinesById(lineid, lines); for (unsigned b = 0; b < lines.size(); b++) { MapLine* line = lines[b]; // Line slope things only affect the sector on the side of the line // that faces the thing double side = MathStuff::lineSide(thing->point(), line->seg()); MapSector* target = nullptr; if (side < 0) target = line->backSector(); else if (side > 0) target = line->frontSector(); if (!target) continue; // Need to know the containing sector's height to find the thing's true height if (!containing_sector) { int containing_sector_idx = map->sectorAt(thing->point()); if (containing_sector_idx < 0) return; containing_sector = map->getSector(containing_sector_idx); thingz = ( containing_sector->getPlane<p>().height_at(thing->point()) + thing->floatProperty("height") ); } // Three points: endpoints of the line, and the thing itself plane_t target_plane = target->getPlane<p>(); fpoint3_t p1(lines[b]->x1(), lines[b]->y1(), target_plane.height_at(lines[b]->point1())); fpoint3_t p2(lines[b]->x2(), lines[b]->y2(), target_plane.height_at(lines[b]->point2())); fpoint3_t p3(thing->xPos(), thing->yPos(), thingz); target->setPlane<p>(MathStuff::planeFromTriangle(p1, p2, p3)); } }
/* MapSector::isWithin * Returns true if the point is inside the sector *******************************************************************/ bool MapSector::isWithin(fpoint2_t point) { // Check with bbox first if (!boundingBox().contains(point)) return false; // Find nearest line in the sector double dist; double min_dist = 999999; MapLine* nline = nullptr; for (unsigned a = 0; a < connected_sides.size(); a++) { // Calculate distance to line //if (connected_sides[a] == NULL) { // LOG_MESSAGE(3, "Warning: connected side #%i is a NULL pointer!", a); // continue; //} else if (connected_sides[a]->getParentLine() == NULL) { // LOG_MESSAGE(3, "Warning: connected side #%i has a NULL pointer parent line!", connected_sides[a]->getIndex()); // continue; //} dist = connected_sides[a]->getParentLine()->distanceTo(point); // Check distance if (dist < min_dist) { nline = connected_sides[a]->getParentLine(); min_dist = dist; } } // No nearest (shouldn't happen) if (!nline) return false; // Check the side of the nearest line double side = MathStuff::lineSide(point, nline->seg()); if (side >= 0 && nline->frontSector() == this) return true; else if (side < 0 && nline->backSector() == this) return true; else return false; }
/* MapSpecials::processEternitySlopes * Process Eternity slope specials *******************************************************************/ void MapSpecials::processEternitySlopes(SLADEMap* map) { // Eternity plans on having a few slope mechanisms, // which must be evaluated in a specific order. // - Plane_Align, in line order // - vertex triangle slopes, in sector order (wip) // - Plane_Copy, in line order // First things first: reset every sector to flat planes for(unsigned a = 0; a < map->nSectors(); a++) { MapSector* target = map->getSector(a); target->setPlane<FLOOR_PLANE>(plane_t::flat(target->getPlaneHeight<FLOOR_PLANE>())); target->setPlane<CEILING_PLANE>(plane_t::flat(target->getPlaneHeight<CEILING_PLANE>())); } // Plane_Align (line special 181) for(unsigned a = 0; a < map->nLines(); a++) { MapLine* line = map->getLine(a); if(line->getSpecial() != 181) continue; MapSector* sector1 = line->frontSector(); MapSector* sector2 = line->backSector(); if(!sector1 || !sector2) { LOG_MESSAGE(1, "Ignoring Plane_Align on one-sided line %d", line->getIndex()); continue; } if(sector1 == sector2) { LOG_MESSAGE(1, "Ignoring Plane_Align on line %d, which has the same sector on both sides", line->getIndex()); continue; } int floor_arg = line->intProperty("arg0"); if(floor_arg == 1) applyPlaneAlign<FLOOR_PLANE>(line, sector1, sector2); else if(floor_arg == 2) applyPlaneAlign<FLOOR_PLANE>(line, sector2, sector1); int ceiling_arg = line->intProperty("arg1"); if(ceiling_arg == 1) applyPlaneAlign<CEILING_PLANE>(line, sector1, sector2); else if(ceiling_arg == 2) applyPlaneAlign<CEILING_PLANE>(line, sector2, sector1); } // Plane_Copy vector<MapSector*> sectors; for(unsigned a = 0; a < map->nLines(); a++) { MapLine* line = map->getLine(a); if(line->getSpecial() != 118) continue; int tag; MapSector* front = line->frontSector(); MapSector* back = line->backSector(); if((tag = line->intProperty("arg0"))) { sectors.clear(); map->getSectorsByTag(tag, sectors); if(sectors.size()) front->setFloorPlane(sectors[0]->getFloorPlane()); } if((tag = line->intProperty("arg1"))) { sectors.clear(); map->getSectorsByTag(tag, sectors); if(sectors.size()) front->setCeilingPlane(sectors[0]->getCeilingPlane()); } if((tag = line->intProperty("arg2"))) { sectors.clear(); map->getSectorsByTag(tag, sectors); if(sectors.size()) back->setFloorPlane(sectors[0]->getFloorPlane()); } if((tag = line->intProperty("arg3"))) { sectors.clear(); map->getSectorsByTag(tag, sectors); if(sectors.size()) back->setCeilingPlane(sectors[0]->getCeilingPlane()); } // The fifth "share" argument copies from one side of the line to the // other if(front && back) { int share = line->intProperty("arg4"); if((share & 3) == 1) back->setFloorPlane(front->getFloorPlane()); else if((share & 3) == 2) front->setFloorPlane(back->getFloorPlane()); if((share & 12) == 4) back->setCeilingPlane(front->getCeilingPlane()); else if((share & 12) == 8) front->setCeilingPlane(back->getCeilingPlane()); } } }
/* MapSpecials::processZDoomSlopes * Process ZDoom slope specials *******************************************************************/ void MapSpecials::processZDoomSlopes(SLADEMap* map) { // ZDoom has a variety of slope mechanisms, which must be evaluated in a // specific order. // - Plane_Align, in line order // - line slope + sector tilt + vavoom, in thing order // - slope copy things, in thing order // - overwrite vertex heights with vertex height things // - vertex triangle slopes, in sector order // - Plane_Copy, in line order // First things first: reset every sector to flat planes for (unsigned a = 0; a < map->nSectors(); a++) { MapSector* target = map->getSector(a); target->setPlane<FLOOR_PLANE>(plane_t::flat(target->getPlaneHeight<FLOOR_PLANE>())); target->setPlane<CEILING_PLANE>(plane_t::flat(target->getPlaneHeight<CEILING_PLANE>())); } // Plane_Align (line special 181) for (unsigned a = 0; a < map->nLines(); a++) { MapLine* line = map->getLine(a); if (line->getSpecial() != 181) continue; MapSector* sector1 = line->frontSector(); MapSector* sector2 = line->backSector(); if (!sector1 || !sector2) { LOG_MESSAGE(1, "Ignoring Plane_Align on one-sided line %d", line->getIndex()); continue; } if (sector1 == sector2) { LOG_MESSAGE(1, "Ignoring Plane_Align on line %d, which has the same sector on both sides", line->getIndex()); continue; } int floor_arg = line->intProperty("arg0"); if (floor_arg == 1) applyPlaneAlign<FLOOR_PLANE>(line, sector1, sector2); else if (floor_arg == 2) applyPlaneAlign<FLOOR_PLANE>(line, sector2, sector1); int ceiling_arg = line->intProperty("arg1"); if (ceiling_arg == 1) applyPlaneAlign<CEILING_PLANE>(line, sector1, sector2); else if (ceiling_arg == 2) applyPlaneAlign<CEILING_PLANE>(line, sector2, sector1); } // Line slope things (9500/9501), sector tilt things (9502/9503), and // vavoom things (1500/1501), all in the same pass for (unsigned a = 0; a < map->nThings(); a++) { MapThing* thing = map->getThing(a); // Line slope things if (thing->getType() == 9500) applyLineSlopeThing<FLOOR_PLANE>(map, thing); else if (thing->getType() == 9501) applyLineSlopeThing<CEILING_PLANE>(map, thing); // Sector tilt things else if (thing->getType() == 9502) applySectorTiltThing<FLOOR_PLANE>(map, thing); else if (thing->getType() == 9503) applySectorTiltThing<CEILING_PLANE>(map, thing); // Vavoom things else if (thing->getType() == 1500) applyVavoomSlopeThing<FLOOR_PLANE>(map, thing); else if (thing->getType() == 1501) applyVavoomSlopeThing<CEILING_PLANE>(map, thing); } // Slope copy things (9510/9511) for (unsigned a = 0; a < map->nThings(); a++) { MapThing* thing = map->getThing(a); if (thing->getType() == 9510 || thing->getType() == 9511) { int target_idx = map->sectorAt(thing->point()); if (target_idx < 0) continue; MapSector* target = map->getSector(target_idx); // First argument is the tag of a sector whose slope should be copied int tag = thing->intProperty("arg0"); if (!tag) { LOG_MESSAGE(1, "Ignoring slope copy thing in sector %d with no argument", target_idx); continue; } vector<MapSector*> tagged_sectors; map->getSectorsByTag(tag, tagged_sectors); if (tagged_sectors.empty()) { LOG_MESSAGE(1, "Ignoring slope copy thing in sector %d; no sectors have target tag %d", target_idx, tag); continue; } if (thing->getType() == 9510) target->setFloorPlane(tagged_sectors[0]->getFloorPlane()); else target->setCeilingPlane(tagged_sectors[0]->getCeilingPlane()); } } // Vertex height things // These only affect the calculation of slopes and shouldn't be stored in // the map data proper, so instead of actually changing vertex properties, // we store them in a hashmap. VertexHeightMap vertex_floor_heights; VertexHeightMap vertex_ceiling_heights; for (unsigned a = 0; a < map->nThings(); a++) { MapThing* thing = map->getThing(a); if (thing->getType() == 1504 || thing->getType() == 1505) { // TODO there could be more than one vertex at this point MapVertex* vertex = map->vertexAt(thing->xPos(), thing->yPos()); if (vertex) { if (thing->getType() == 1504) vertex_floor_heights[vertex] = thing->floatProperty("height"); else if (thing->getType() == 1505) vertex_ceiling_heights[vertex] = thing->floatProperty("height"); } } } // Vertex heights -- only applies for sectors with exactly three vertices. // Heights may be set by UDMF properties, or by a vertex height thing // placed exactly on the vertex (which takes priority over the prop). vector<MapVertex*> vertices; for (unsigned a = 0; a < map->nSectors(); a++) { MapSector* target = map->getSector(a); vertices.clear(); target->getVertices(vertices); if (vertices.size() != 3) continue; applyVertexHeightSlope<FLOOR_PLANE>(target, vertices, vertex_floor_heights); applyVertexHeightSlope<CEILING_PLANE>(target, vertices, vertex_ceiling_heights); } // Plane_Copy vector<MapSector*> sectors; for (unsigned a = 0; a < map->nLines(); a++) { MapLine* line = map->getLine(a); if (line->getSpecial() != 118) continue; int tag; MapSector* front = line->frontSector(); MapSector* back = line->backSector(); if ((tag = line->intProperty("arg0")) && front) { sectors.clear(); map->getSectorsByTag(tag, sectors); if (sectors.size()) front->setFloorPlane(sectors[0]->getFloorPlane()); } if ((tag = line->intProperty("arg1")) && front) { sectors.clear(); map->getSectorsByTag(tag, sectors); if (sectors.size()) front->setCeilingPlane(sectors[0]->getCeilingPlane()); } if ((tag = line->intProperty("arg2")) && back) { sectors.clear(); map->getSectorsByTag(tag, sectors); if (sectors.size()) back->setFloorPlane(sectors[0]->getFloorPlane()); } if ((tag = line->intProperty("arg3")) && back) { sectors.clear(); map->getSectorsByTag(tag, sectors); if (sectors.size()) back->setCeilingPlane(sectors[0]->getCeilingPlane()); } // The fifth "share" argument copies from one side of the line to the // other if (front && back) { int share = line->intProperty("arg4"); if ((share & 3) == 1) back->setFloorPlane(front->getFloorPlane()); else if ((share & 3) == 2) front->setFloorPlane(back->getFloorPlane()); if ((share & 12) == 4) back->setCeilingPlane(front->getCeilingPlane()); else if ((share & 12) == 8) front->setCeilingPlane(back->getCeilingPlane()); } } }