Exemplo n.º 1
0
	FBox EntitiesEditor::computeOvergroundBox(const FBox &bbox) const {
		int over_ground = 0;
		FBox test_box = bbox;
		test_box.max.y = test_box.min.y + 1.0f;

		while(over_ground < 16 && m_tile_map.findAny(test_box - float3(0, 1 + over_ground, 0)) == -1)
			over_ground++;

		if(over_ground)
			return FBox(asXZY(bbox.min.xz(), bbox.min.y - over_ground), asXZY(bbox.max.xz(), bbox.min.y));
		return FBox::empty();
	}
Exemplo n.º 2
0
	const IBox View::computeCursor(const int2 &start, const int2 &end, const int3 &bbox, int height, int offset) const {
		float2 height_off = worldToScreen(float3(0, height, 0));
		int3 gbox(cellSize(), 1, cellSize());

		int3 start_pos = asXZ((int2)( screenToWorld(float2(start + pos()) - height_off) + float2(0.5f, 0.5f)));
		int3 end_pos   = asXZ((int2)( screenToWorld(float2(end   + pos()) - height_off) + float2(0.5f, 0.5f)));

		start_pos.y = end_pos.y = height + offset;
		
		{
			int apos1 = start_pos.x % gbox.x;
			int apos2 = apos1 - gbox.x + bbox.x;
			start_pos.x -= apos1 < gbox.x - apos1 || bbox.x >= gbox.x? apos1 : apos2;
		}
		{
			int apos1 = start_pos.z % gbox.z;
			int apos2 = apos1 - gbox.z + bbox.z;
			start_pos.z -= apos1 < gbox.z - apos1 || bbox.z >= gbox.z? apos1 : apos2;
		}
		if(end == start)
			end_pos = start_pos;
		
		int3 dir(end_pos.x >= start_pos.x? 1 : -1, 1, end_pos.z >= start_pos.z? 1 : -1);
		int3 size(::abs(end_pos.x - start_pos.x), 1, ::abs(end_pos.z - start_pos.z));
		size += bbox - int3(1, 1, 1);
		size.x -= size.x % bbox.x;
		size.z -= size.z % bbox.z;
		size = max(bbox, size);

		if(dir.x < 0)
			start_pos.x += bbox.x;
		if(dir.z < 0)
			start_pos.z += bbox.z;
		end_pos = start_pos + dir * size;

		if(start_pos.x > end_pos.x) swap(start_pos.x, end_pos.x);
		if(start_pos.z > end_pos.z) swap(start_pos.z, end_pos.z);
		
		int2 dims = m_tile_map.dimensions();
		start_pos = asXZY(clamp(start_pos.xz(), int2(0, 0), dims), start_pos.y);
		  end_pos = asXZY(clamp(  end_pos.xz(), int2(0, 0), dims),   end_pos.y);

		return IBox(start_pos, end_pos);

	}
Exemplo n.º 3
0
	void View::update(const InputState &state) {
		if(state.isKeyDown('g')) {
			if(m_is_visible) {
				if(m_cell_size == 3)
					m_cell_size = 6;
				else if(m_cell_size == 6)
					m_cell_size = 9;
				else {
					m_cell_size = 1;
					m_is_visible = false;
				}
			}
			else {
				m_cell_size = 3;
				m_is_visible = true;
			}
		}
			
		int height_change = state.mouseWheelMove() +
							(state.isKeyDownAuto(InputKey::pagedown)? -1 : 0) +
							(state.isKeyDownAuto(InputKey::pageup)? 1 : 0);
		if(height_change)
			m_height = clamp(m_height + height_change, 0, (int)Grid::max_height);
		
		{
			int actions[TileGroup::Group::side_count] = {
				InputKey::kp_1, 
				InputKey::kp_2,
				InputKey::kp_3,
				InputKey::kp_6,
				InputKey::kp_9,
				InputKey::kp_8,
				InputKey::kp_7,
				InputKey::kp_4
			};
			
			for(int n = 0; n < arraySize(actions); n++)
				if(state.isKeyDownAuto(actions[n]))
					m_view_pos += worldToScreen(TileGroup::Group::s_side_offsets[n] * m_cell_size);
		}

		if((state.isKeyPressed(InputKey::lctrl) && state.isMouseButtonPressed(InputButton::left)) ||
		   state.isMouseButtonPressed(InputButton::middle))
			m_view_pos -= state.mouseMove();

		IRect rect = worldToScreen(IBox(int3(0, 0, 0), asXZY(m_tile_map.dimensions(), 256)));
		m_view_pos = clamp(m_view_pos, rect.min, rect.max - m_view_size);
	}
Exemplo n.º 4
0
	bool Turret::canSee(EntityRef target_ref, bool simple_test) {
		const Entity *target = refEntity(target_ref);
		if(!target || isDead())
			return false;

		const FBox &box = boundingBox();
		const FBox &target_box = target->boundingBox();
		float dist = distance(box, target_box);
		float3 eye_pos = asXZY(box.center().xz(), box.min.y + box.height() * 0.75f);

		if(dist > max_distance)
			return false;

		if(simple_test)
			return true;

		//TODO: move to ThinkingEntity?
		return world()->isVisible(eye_pos, target_ref, ref(), target->typeId() == EntityId::actor? 4 : 3);
	}
Exemplo n.º 5
0
	void EntitiesEditor::drawBoxHelpers(Renderer2D &out, const IBox &box) const {
		int3 pos = box.min, bbox = box.max - box.min;
		int3 tsize = asXZY(m_tile_map.dimensions(), 32);

		drawLine(out, int3(0, pos.y, pos.z), int3(tsize.x, pos.y, pos.z), Color(0, 255, 0, 127));
		drawLine(out, int3(0, pos.y, pos.z + bbox.z), int3(tsize.x, pos.y, pos.z + bbox.z), Color(0, 255, 0, 127));
		
		drawLine(out, int3(pos.x, pos.y, 0), int3(pos.x, pos.y, tsize.z), Color(0, 255, 0, 127));
		drawLine(out, int3(pos.x + bbox.x, pos.y, 0), int3(pos.x + bbox.x, pos.y, tsize.z), Color(0, 255, 0, 127));

		int3 tpos(pos.x, 0, pos.z);
		drawBBox(out, IBox(tpos, tpos + int3(bbox.x, pos.y, bbox.z)), Color(0, 0, 255, 127));
		
		drawLine(out, int3(0, 0, pos.z), int3(tsize.x, 0, pos.z), Color(0, 0, 255, 127));
		drawLine(out, int3(0, 0, pos.z + bbox.z), int3(tsize.x, 0, pos.z + bbox.z), Color(0, 0, 255, 127));
		
		drawLine(out, int3(pos.x, 0, 0), int3(pos.x, 0, tsize.z), Color(0, 0, 255, 127));
		drawLine(out, int3(pos.x + bbox.x, 0, 0), int3(pos.x + bbox.x, 0, tsize.z), Color(0, 0, 255, 127));
	}
Exemplo n.º 6
0
	void WorldViewer::update(double time_diff) {
		FWK_PROFILE("WorldViewer::update");
		Actor *spectator = m_world->refEntity<Actor>(m_spectator);

		if((int)m_entities.size() != m_world->entityCount())
			m_entities.resize(m_world->entityCount());
		
		if(!m_spectator) {
			for(int n = 0; n < (int)m_entities.size(); n++) {
				Entity *entity = m_world->refEntity(n);
				VisEntity &vis_entity = m_entities[n];
				vis_entity.ref = entity? entity->ref() : EntityRef();
				vis_entity.mode = entity? VisEntity::visible : VisEntity::invisible;
				vis_entity.occluder_id = -1;
			}
			return;
		}

		if(!spectator)
			return;

		FBox bbox = spectator->boundingBox();
		m_cur_pos = bbox.center();
		m_eye_pos = asXZY(m_cur_pos.xz(), bbox.min.y + bbox.height() * 0.75f);

		for(int n = 0; n < (int)m_entities.size(); n++) {
			Entity *entity = m_world->refEntity(n);
			VisEntity &vis_entity = m_entities[n];

			if(!entity) {
				vis_entity = VisEntity();
				continue;
			}
			
			const auto *desc = m_world->refEntityDesc(n);
			DASSERT(desc);

			bool is_visible = m_see_all || spectator == entity || spectator->canSee(entity->ref(), !isMovable(*entity));

			if(vis_entity.ref != entity->ref()) {
				vis_entity = VisEntity();
				vis_entity.ref = entity->ref();
				vis_entity.mode = is_visible? VisEntity::visible : VisEntity::invisible;
			}

			if(is_visible) {
				vis_entity.occluder_id = desc->occluder_id;

				if(vis_entity.mode == VisEntity::visible)
					continue;

				if(vis_entity.mode == VisEntity::shadowed || vis_entity.mode == VisEntity::pre_blending_out) {
					vis_entity.shadow.reset();
					vis_entity.mode = VisEntity::visible;
				}
				else {
					float blend_value = 0.0;
					if(vis_entity.mode == VisEntity::blending_in)
						blend_value = vis_entity.blend_value;
					else if(vis_entity.mode == VisEntity::blending_out)
						blend_value = blend_time - vis_entity.blend_value;

					blend_value += time_diff;
					vis_entity.mode = blend_value > blend_time? VisEntity::visible : VisEntity::blending_in;
					vis_entity.blend_value = blend_value;
				}
			}
			else {
				if(vis_entity.mode == VisEntity::shadowed || vis_entity.mode == VisEntity::invisible)
					continue;

				if(vis_entity.mode == VisEntity::visible) {
					vis_entity.blend_value = 0.0f;
					vis_entity.mode = VisEntity::pre_blending_out;
				}

				if(vis_entity.mode == VisEntity::pre_blending_out) {
					vis_entity.blend_value += time_diff;

					if(vis_entity.blend_value > blend_time) {
						if(isMovable(*entity)) {
							vis_entity.mode = VisEntity::blending_out;
							vis_entity.blend_value = vis_entity.blend_value - blend_time;
						}
						else {
							vis_entity.mode = VisEntity::shadowed;
							vis_entity.occluder_id = desc->occluder_id;
							vis_entity.shadow.reset(entity->clone());
						}
					}
				}
				else {
					float blend_value = 0.0f;

					if(vis_entity.mode == VisEntity::blending_in)
						blend_value = blend_time - vis_entity.blend_value;
					else if(vis_entity.mode == VisEntity::blending_out)
						blend_value = vis_entity.blend_value;

					vis_entity.blend_value = blend_value + time_diff;
					vis_entity.mode = VisEntity::blending_out;

					if(vis_entity.blend_value > blend_time)
						vis_entity.mode = VisEntity::invisible;
				}
			}
		}

		if(m_occluder_config.update(spectator->boundingBox()))
			m_world->tileMap().updateVisibility(m_occluder_config);
	}
Exemplo n.º 7
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;
}
Exemplo n.º 8
0
	bool EntitiesEditor::onMouseDrag(const InputState &state, int2 start, int2 current, int key, int is_final) {
		bool shift_pressed = state.isKeyPressed(InputKey::lshift);
		if(key == 0 && !state.isKeyPressed(InputKey::lctrl)) {
			computeCursor(start, current, shift_pressed);
			m_is_selecting = !is_final;

			if(m_mode == Mode::selecting && is_final && is_final != -1) {
				findVisible(m_selected_ids, m_selection);
				computeCursor(current, current, shift_pressed);
			}
			else if(m_mode == Mode::placing) {
				if(m_proto->typeId() == EntityId::trigger) {
					Trigger *trigger = static_cast<Trigger*>(m_proto.get());

					if(m_trigger_mode == 0) {
						m_trigger_box = m_view.computeCursor(start, current, int3(1, 1, 1), m_cursor_pos.y, 0);
					
						if(state.isMouseButtonDown(InputButton::right)) {
							m_trigger_mode = 1;
							m_trigger_offset = current;
						}
					}

					IBox new_box = m_trigger_box;
					if(m_trigger_mode == 1) {
						int offset = screenToWorld(int2(0, m_trigger_offset.y - current.y)).y;
						if(offset < 0)
							new_box.min.y += offset;
						else
							new_box.max.y += offset;
					}
					
					trigger->setBox((FBox)new_box);
					m_cursor_pos = trigger->pos();
			
					if(is_final > 0) {
						m_entity_map.add(PEntity(m_proto->clone()));
					}
					if(is_final) {
						m_trigger_mode = 0;
						trigger->setBox(FBox(0, 0, 0, 1, 1, 1) + trigger->pos());
					}
				}
				else if(is_final > 0)
					m_entity_map.add(PEntity(m_proto->clone()));
			}

			return true;
		}
		else if(key == 1 && m_mode == Mode::selecting) {
			if(!m_is_moving) {
				m_is_moving_vertically = state.isKeyPressed(InputKey::lshift);
				m_is_moving = true;
			}

			if(m_is_moving_vertically)
				m_move_offset = int3(0, screenToWorld(int2(0, start.y - current.y)).y, 0);
			else
				m_move_offset = asXZY(screenToWorld(current - start), 0);

			if(is_final)
				m_is_moving = false;

			if(is_final > 0) {
				for(int n = 0; n < (int)m_selected_ids.size(); n++) {
					auto &object = m_entity_map[m_selected_ids[n]];
					object.ptr->setPos(object.ptr->pos() + float3(m_move_offset));
					m_entity_map.update(m_selected_ids[n]);
				}
			}

			return true;
		}

		return false;
	}