Exemplo n.º 1
0
int Grid::pixelIntersect(const int2 &screen_pos, bool (*pixelTest)(const ObjectDef&, const int2&), int flags) const {
	IRect grid_box(0, 0, m_size.x, m_size.y);
	
	int best = -1;
	FBox best_box;

	for(int y = grid_box.min.y; y < grid_box.max.y; y++) {
		const int2 &row_rect = m_row_rects[y];
		if(row_rect.x >= screen_pos.y || row_rect.y <= screen_pos.y)
			continue;

		for(int x = grid_box.min.x; x < grid_box.max.x; x++) {
			int node_id = nodeAt(int2(x, y));
			const Node &node = m_nodes[node_id];

			if(!flagTest(node.obj_flags, flags) || !node.rect.isInside(screen_pos))
				continue;
			if(node.is_dirty)
				updateNode(node_id);	

			const Object *objects[node.size];
			int count = extractObjects(node_id, objects, -1, flags);

			for(int n = 0; n < count; n++)
				if(objects[n]->rect().isInside(screen_pos) && pixelTest(*objects[n], screen_pos)) {
					if(best == -1 || drawingOrder(objects[n]->bbox, best_box) == 1) {
						best = objects[n] - &m_objects[0];
						best_box = objects[n]->bbox;
					}
				}
		}
	}

	return best;
}
Exemplo n.º 2
0
	Intersection WorldViewer::pixelIntersect(const int2 &screen_pos, const FindFilter &filter) const {
		Intersection out;
		FBox out_bbox;

		if(filter.flags() & Flags::tile) {
			const TileMap &tile_map = m_world->tileMap();
			vector<int> inds;
			tile_map.findAll(inds, IRect(screen_pos, screen_pos + int2(1, 1)), filter.flags() | Flags::visible);

			for(int i = 0; i < (int)inds.size(); i++) {
				const auto &desc = tile_map[inds[i]];
				
				FBox bbox = desc.bbox;
				
				if(out.empty() || drawingOrder(bbox, out_bbox) == 1)
					if(desc.ptr->testPixel(screen_pos - worldToScreen((int3)bbox.min))) {
						out = ObjectRef(inds[i], false);
						out_bbox = bbox;
					}
			}
		}

		if(filter.flags() & Flags::entity) {
			int ignore_index = m_world->filterIgnoreIndex(filter);

			for(int n = 0; n < (int)m_entities.size(); n++) {
				const Entity *entity = refEntity(n);
				if(!entity || !m_occluder_config.isVisible(m_entities[n].occluder_id) || !Flags::test(entity->flags(), filter.flags()) || n == ignore_index)
					continue;
				if(!entity->testPixel(screen_pos))
					continue;
				FBox bbox = entity->boundingBox();

				//TODO: check this
				if(out.empty() || drawingOrder(bbox, out_bbox) == 1) {
					out = ObjectRef(n, true);
					out_bbox = bbox;
				}
			}
		}

		if(out.empty())
			return Intersection();
		return Intersection(out, intersection(screenRay(screen_pos), out_bbox));
	}
Exemplo n.º 3
0
	void EntitiesEditor::findVisible(vector<int> &out, const IRect &rect) const {
		out.clear();

		std::set<int> indices;
		vector<int> temp;
		temp.reserve(100);

		enum { block_size = 64 };

		for(int gy = m_selection.min.y; gy <= m_selection.max.y; gy += block_size)
			for(int gx = m_selection.min.x; gx <= m_selection.max.x; gx += block_size) {
				temp.clear();

				IRect block_rect(int2(gx, gy), min(int2(gx + block_size, gy + block_size), m_selection.max));
				m_entity_map.findAll(temp, block_rect, Flags::all | Flags::visible);
				for(int n = 0; n < (int)temp.size(); n++)
					if(indices.find(temp[n]) != indices.end()) {
						temp[n--] = temp.back();
						temp.pop_back();
					}

				for(int y = gy, endy = min(m_selection.max.y, gy + block_size); y <= endy; y += 2)
					for(int x = m_selection.min.x, endx = min(gx + block_size, m_selection.max.x); x <= endx; x += 2) {
						int2 point(x, y);
						if(point.x + 1 <= m_selection.max.x && (y & 1))
							point.x++;

						bool tile_isected = false;
						int tile_idx = -1;

						for(int i = 0; i < (int)temp.size(); i++) {
							const auto &object = m_entity_map[temp[i]];
							bool is_trigger = object.ptr->typeId() == EntityId::trigger;

							if(!is_trigger && !object.ptr->testPixel(point))
								continue;
							if(is_trigger && !object.ptr->currentScreenRect().isInside(point))
								continue;

							if(!tile_isected) {
								tile_idx = m_tile_map.pixelIntersect(int2(x, y), Flags::walkable_tile | Flags::visible);
								tile_isected = true;
							}
							if(tile_idx != -1) {
								if(drawingOrder(m_tile_map[tile_idx].bbox, m_entity_map[temp[i]].bbox) == 1)
									continue;
							}
						
							indices.insert(temp[i]);
							temp[i--] = temp.back();
							temp.pop_back();
						}
					}
			}

		out.insert(out.begin(), indices.begin(), indices.end());
	}
Exemplo n.º 4
0
bool OccluderConfig::update(const FBox &bbox) {
	//TODO: hiding when close to a door/window
	FBox test_box(bbox.min.x, bbox.min.y + 1.0f, bbox.min.z, bbox.max.x, 256, bbox.max.z);
	float3 mid_point = asXZY(test_box.center().xz(), bbox.min.y + 2.0f);

	bool vis_changed = update();
	vector<int> temp;
	temp.reserve(256);
	IRect test_rect = (IRect)worldToScreen(bbox);
	const Grid &grid = m_map.m_grid;
	grid.findAll(temp, test_rect);

	vector<int> temp2;
	temp2.reserve(256);

	PodArray<int> overlaps(m_map.size());
	memset(overlaps.data(), 0, m_map.size() * sizeof(int));

	for(int i = 0; i < (int)temp.size(); i++) {
		const auto &object = grid[temp[i]];
		if(object.occluder_id == -1)
			continue;

		const OccluderMap::Occluder &occluder = m_map[object.occluder_id];
		int order = drawingOrder(object.bbox, bbox);
		if(order == 1)
			overlaps[object.occluder_id] = order;
	}

	for(int n = 0; n < (int)m_states.size(); n++) {
		bool is_overlapping = false;
		const OccluderMap::Occluder &occluder = m_map[n];

		if(overlaps[n] == 1) {
			FBox bbox_around(bbox.min - float3(16, 0, 16), bbox.max + float3(16, 0, 16));
			bbox_around.min.y = 0;
			bbox_around.max.y = Grid::max_height;

			temp2.clear();
			grid.findAll(temp2, bbox_around);
			FBox local_box = FBox();

			for(int i = 0; i < (int)temp2.size(); i++) {
				const auto &object = grid[temp2[i]];
				if(object.occluder_id == n)
					local_box = local_box.empty()? object.bbox : sum(local_box, object.bbox);
			}

			is_overlapping = local_box.min.y > mid_point.y;
		}

		if(is_overlapping != m_states[n].is_overlapping) {
			m_states[n].is_overlapping = is_overlapping;
			vis_changed = true;
		}
	}

	if(!vis_changed)
		return false;

	for(int n= 0; n < (int)m_states.size(); n++)
		m_states[n].is_visible = !m_states[n].is_overlapping;

//TODO: isUnder can be precomputed
	for(int n = 0; n < (int)m_states.size(); n++) {
		if(!m_states[n].is_visible)
			continue;

		for(int i = 0; i < (int)m_states.size(); i++)
			if(!m_states[i].is_visible && m_map.isUnder(i, n)) {
				m_states[n].is_visible = false;
				break;
			}
	}

	return true;
}