shared_ptr World::tool_wall()

in roboschool/cpp-household/random-world-tools.cpp [56:418]


shared_ptr<Thingy> World::tool_wall(
	btScalar grid_size, float tex1, float tex_v_zero,
	const std::vector<btScalar>& path, bool closed,
	const std::vector<btScalar>& low,
	const std::vector<btScalar>& hgh,
	const std::string& side_tex_,   float side_tex_scale,
	const std::string& top_tex_,    float top_tex_scale,
	const std::string& bottom_tex_, float bott_tex_scale,
	const std::string& butt_tex_,   float butt_tex_scale)
{
	shared_ptr<Household::Shape> side_shape;
	shared_ptr<Household::Shape> side_cshape;
	if (!side_tex_.empty()) {
		side_shape.reset(new Household::Shape);
		side_shape->material = texture_from_file_cached(side_tex_);
		side_cshape.reset(new Household::Shape);
		side_cshape->primitive_type = Household::Shape::STATIC_MESH;
	}

	shared_ptr<Household::Shape> top_shape;
	shared_ptr<Household::Shape> top_cshape;
	if (!top_tex_.empty()) {
		top_shape.reset(new Household::Shape);
		top_shape->material = texture_from_file_cached(top_tex_);
		top_cshape.reset(new Household::Shape);
		top_cshape->primitive_type = Household::Shape::STATIC_MESH;
	}

	shared_ptr<Household::Shape> bot_shape;
	shared_ptr<Household::Shape> bot_cshape;
	if (!bottom_tex_.empty()) {
		bot_shape.reset(new Household::Shape);
		bot_shape->material = texture_from_file_cached(bottom_tex_);
		bot_cshape.reset(new Household::Shape);
		bot_cshape->primitive_type = Household::Shape::STATIC_MESH;
	}

	shared_ptr<Household::Shape> but_shape;
	shared_ptr<Household::Shape> but_cshape;
	if (!butt_tex_.empty()) {
		but_shape.reset(new Household::Shape);
		but_shape->material = texture_from_file_cached(butt_tex_);
		but_cshape.reset(new Household::Shape);
		but_cshape->primitive_type = Household::Shape::STATIC_MESH;
	}

	int cnt = low.size();
	assert(cnt==(int)hgh.size());
	assert((cnt+(closed?0:1))*2==(int)path.size());

	std::vector<btScalar> path_outer;
	std::vector<btScalar> path_inner;
	std::vector<btScalar> low_expanded;
	std::vector<btScalar> hgh_expanded;
	std::vector<bool> skip_top_bottom;
	std::vector<btVector3> normals;
	for (int c=0; c<cnt; c++) {
		int c0 = (c+cnt-1) % cnt;
		int c1 = (c+0) % cnt;
		int c2 = (c+1) % cnt;
		btVector3 hor0(path[2*c1+0] - path[2*c0+0], path[2*c1+1] - path[2*c0+1], 0);
		btVector3 hor1(path[2*c2+0] - path[2*c1+0], path[2*c2+1] - path[2*c1+1], 0);
		btVector3 ver(0, 0, -1);
		btVector3 norm0 = hor0.cross(ver);
		btVector3 norm1 = hor1.cross(ver);
		norm0.normalize();
		bool norm0_45deg = fabs(fabs(norm0.x()) - fabs(norm0.y())) < 0.01;
		norm1.normalize();
		bool norm1_45deg = fabs(fabs(norm1.x()) - fabs(norm1.y())) < 0.01;
		if (!closed && c==0) norm0 = norm1;
		if (!closed && c==cnt-1) norm1 = norm0;
		btVector3 inwards(0, 0, 0);
		btVector3 outwards;

		if (!norm0_45deg && !norm1_45deg) {
			if (hor0==-hor1)
				outwards = hor0;
			else
				outwards = norm0 + norm1;
			if (!outwards.fuzzyZero()) {
				outwards.normalize();
				btScalar correction = 1 / std::max( fabs(outwards.x()), fabs(outwards.y()) );
				outwards *= correction;
			}
			if (!(norm0 - norm1).fuzzyZero() && norm0.dot(hor1) > 0) // 90 degree turn, paint top/bottom less
				inwards = btVector3(outwards);

		} else if (norm0_45deg && norm1_45deg) {
			outwards = btVector3(0,0,0);

		} else if (norm0_45deg) {
			btScalar reverse = ((norm1.dot(hor0)) > 0) ? +1 : -1;
			outwards = hor0*reverse;
			outwards.normalize();
			btScalar correction = 1 / std::max( fabs(outwards.x()), fabs(outwards.y()) );
			outwards *= correction;

		} else if (norm1_45deg) {
			btScalar reverse = ((norm0.dot(hor1)) > 0) ? +1 : -1;
			outwards = hor1*reverse;
			outwards.normalize();
			btScalar correction = 1 / std::max( fabs(outwards.x()), fabs(outwards.y()) );
			outwards *= correction;
		}

		path_outer.push_back(path[2*c1+0] + grid_size*0.5*outwards.x());
		path_outer.push_back(path[2*c1+1] + grid_size*0.5*outwards.y());
		path_inner.push_back(path[2*c1+0] + grid_size*0.5*inwards.x());
		path_inner.push_back(path[2*c1+1] + grid_size*0.5*inwards.y());
		low_expanded.push_back(low[c1]);
		hgh_expanded.push_back(hgh[c1]);
		skip_top_bottom.push_back(norm1_45deg);
		normals.push_back(norm1);

		bool height_change = hgh[c1] != hgh[c2] || low[c1] != low[c2];
		if (height_change) {
			//assert( (norm0 - norm1).fuzzyZero() && "cannot change height and turn simultaniously");
			path_outer.push_back( (path[2*c1+0] + path[2*c2+0])*0.5 + grid_size*0.5*norm1.x());
			path_outer.push_back( (path[2*c1+1] + path[2*c2+1])*0.5 + grid_size*0.5*norm1.y());
			path_inner.push_back( (path[2*c1+0] + path[2*c2+0])*0.5 );
			path_inner.push_back( (path[2*c1+1] + path[2*c2+1])*0.5 );
			low_expanded.push_back(low[c1]);
			hgh_expanded.push_back(hgh[c1]);
			skip_top_bottom.push_back(norm1_45deg);
			normals.push_back(norm1);

			path_outer.push_back( (path[2*c1+0] + path[2*c2+0])*0.5 + grid_size*0.5*norm1.x());
			path_outer.push_back( (path[2*c1+1] + path[2*c2+1])*0.5 + grid_size*0.5*norm1.y());
			path_inner.push_back( (path[2*c1+0] + path[2*c2+0])*0.5 );
			path_inner.push_back( (path[2*c1+1] + path[2*c2+1])*0.5 );
			low_expanded.push_back(low[c2]);
			hgh_expanded.push_back(hgh[c2]);
			skip_top_bottom.push_back(norm1_45deg);
			normals.push_back(norm1);
		}
	}

	float side_tex_spent = 0;
	cnt = low_expanded.size();
	for (int c=0; c<cnt; c++) {
		int c1 = (c+0) % cnt;
		int c2 = (c+1) % cnt;
		btVector3 norm = normals[c1];

		bool height_only = (btVector3(path_outer[2*c1+0], path_outer[2*c1+1], 0) - btVector3(path_outer[2*c2+0], path_outer[2*c2+1], 0)).fuzzyZero();

		if (side_shape && !height_only) {
			btVector3 p1(path_outer[2*c1+0], path_outer[2*c1+1], low_expanded[c1]);
			btVector3 p2(path_outer[2*c1+0], path_outer[2*c1+1], hgh_expanded[c1]);
			btVector3 p3(path_outer[2*c2+0], path_outer[2*c2+1], hgh_expanded[c1]);
			btVector3 p4(path_outer[2*c2+0], path_outer[2*c2+1], low_expanded[c1]);
			btVector3 center = (p1+p2+p3+p4)/4;
			if (!(p1-p2).fuzzyZero()) { // if zero, wall has no height, that's normal (for doorways)
				if (TEST_GAP) {
					p1 -= sign(p1-center)*TEST_GAP;
					p2 -= sign(p2-center)*TEST_GAP;
					p3 -= sign(p3-center)*TEST_GAP;
					p4 -= sign(p4-center)*TEST_GAP;
				}
				side_shape->push_vertex(p1.x(), p1.y(), p1.z());
				side_shape->push_vertex(p2.x(), p2.y(), p2.z());
				side_shape->push_vertex(p3.x(), p3.y(), p3.z());
				side_shape->push_vertex(p4.x(), p4.y(), p4.z());
				side_cshape->push_vertex(p1.x(), p1.y(), p1.z());
				side_cshape->push_vertex(p2.x(), p2.y(), p2.z());
				side_cshape->push_vertex(p3.x(), p3.y(), p3.z());
				side_cshape->push_vertex(p1.x(), p1.y(), p1.z());
				side_cshape->push_vertex(p3.x(), p3.y(), p3.z());
				side_cshape->push_vertex(p4.x(), p4.y(), p4.z());
				for (int c=0; c<4; c++)
					side_shape->push_normal(norm.x(), norm.y(), norm.z());
				for (int c=0; c<6; c++)
					side_cshape->push_normal(norm.x(), norm.y(), norm.z());
				float next_side_tex_spent = side_tex_spent + (p4-p1).norm();
				side_shape->push_tex(side_tex_spent/side_tex_scale/tex1,      (low_expanded[c1]-tex_v_zero)/side_tex_scale/tex1);
				side_shape->push_tex(side_tex_spent/side_tex_scale/tex1,      (hgh_expanded[c1]-tex_v_zero)/side_tex_scale/tex1);
				side_shape->push_tex(next_side_tex_spent/side_tex_scale/tex1, (hgh_expanded[c1]-tex_v_zero)/side_tex_scale/tex1);
				side_shape->push_tex(next_side_tex_spent/side_tex_scale/tex1, (low_expanded[c1]-tex_v_zero)/side_tex_scale/tex1);
				side_tex_spent = next_side_tex_spent;
			}
		}

		if (top_shape && !skip_top_bottom[c] && hgh_expanded[c1]==hgh_expanded[c2] && !height_only) {
			btVector3 p1(path_outer[2*c2+0], path_outer[2*c2+1], hgh_expanded[c1]);
			btVector3 p2(path_outer[2*c1+0], path_outer[2*c1+1], hgh_expanded[c1]);
			btVector3 p3(path_inner[2*c1+0], path_inner[2*c1+1], hgh_expanded[c1]);
			btVector3 p4(path_inner[2*c2+0], path_inner[2*c2+1], hgh_expanded[c1]);
			btVector3 center = (p1+p2+p3+p4)/4;
			if (TEST_GAP) {
				p1 -= sign(p1-center)*TEST_GAP;
				p2 -= sign(p2-center)*TEST_GAP;
				p3 -= sign(p3-center)*TEST_GAP;
				p4 -= sign(p4-center)*TEST_GAP;
			}
			top_shape->push_vertex(p1.x(), p1.y(), p1.z());
			top_shape->push_vertex(p2.x(), p2.y(), p2.z());
			top_shape->push_vertex(p3.x(), p3.y(), p3.z());
			top_shape->push_vertex(p4.x(), p4.y(), p4.z());
			top_cshape->push_vertex(p1.x(), p1.y(), p1.z());
			top_cshape->push_vertex(p2.x(), p2.y(), p2.z());
			top_cshape->push_vertex(p3.x(), p3.y(), p3.z());
			top_cshape->push_vertex(p1.x(), p1.y(), p1.z());
			top_cshape->push_vertex(p3.x(), p3.y(), p3.z());
			top_cshape->push_vertex(p4.x(), p4.y(), p4.z());
			for (int c=0; c<4; c++)
				top_shape->push_normal(0,0,1);
			for (int c=0; c<6; c++)
				top_cshape->push_normal(0,0,1);
			float next_side_tex_spent = side_tex_spent - (p2-p1).norm();
			btScalar depth = (p2-p3).norm();
			top_shape->push_tex( side_tex_spent/top_tex_scale/tex1,      hgh_expanded[c1]/top_tex_scale/tex1 );
			top_shape->push_tex( next_side_tex_spent/top_tex_scale/tex1, hgh_expanded[c1]/top_tex_scale/tex1 );
			top_shape->push_tex( next_side_tex_spent/top_tex_scale/tex1, (hgh_expanded[c1] + depth)/top_tex_scale/tex1 );
			top_shape->push_tex( side_tex_spent/top_tex_scale/tex1,      (hgh_expanded[c1] + depth)/top_tex_scale/tex1 );
		}

		if (bot_shape && !skip_top_bottom[c] && low_expanded[c1]==low_expanded[c2] && !height_only) {
			btVector3 p1(path_outer[2*c2+0], path_outer[2*c2+1], low_expanded[c1]);
			btVector3 p2(path_inner[2*c2+0], path_inner[2*c2+1], low_expanded[c1]);
			btVector3 p3(path_inner[2*c1+0], path_inner[2*c1+1], low_expanded[c1]);
			btVector3 p4(path_outer[2*c1+0], path_outer[2*c1+1], low_expanded[c1]);
			btVector3 center = (p1+p2+p3+p4)/4;
			if (TEST_GAP) {
				p1 -= sign(p1-center)*TEST_GAP;
				p2 -= sign(p2-center)*TEST_GAP;
				p3 -= sign(p3-center)*TEST_GAP;
				p4 -= sign(p4-center)*TEST_GAP;
			}
			bot_shape->push_vertex(p1.x(), p1.y(), p1.z());
			bot_shape->push_vertex(p2.x(), p2.y(), p2.z());
			bot_shape->push_vertex(p3.x(), p3.y(), p3.z());
			bot_shape->push_vertex(p4.x(), p4.y(), p4.z());
			bot_cshape->push_vertex(p1.x(), p1.y(), p1.z());
			bot_cshape->push_vertex(p2.x(), p2.y(), p2.z());
			bot_cshape->push_vertex(p3.x(), p3.y(), p3.z());
			bot_cshape->push_vertex(p1.x(), p1.y(), p1.z());
			bot_cshape->push_vertex(p3.x(), p3.y(), p3.z());
			bot_cshape->push_vertex(p4.x(), p4.y(), p4.z());
			for (int c=0; c<4; c++)
				bot_shape->push_normal(0,0,-1);
			for (int c=0; c<6; c++)
				bot_cshape->push_normal(0,0,-1);
			float next_side_tex_spent = side_tex_spent - (p4-p1).norm();
			btScalar depth = (p1-p2).norm();
			bot_shape->push_tex( side_tex_spent/bott_tex_scale/tex1,      low_expanded[c1]/bott_tex_scale/tex1 );
			bot_shape->push_tex( side_tex_spent/bott_tex_scale/tex1,      (low_expanded[c1] - depth)/bott_tex_scale/tex1 );
			bot_shape->push_tex( next_side_tex_spent/bott_tex_scale/tex1, (low_expanded[c1] - depth)/bott_tex_scale/tex1 );
			bot_shape->push_tex( next_side_tex_spent/bott_tex_scale/tex1, low_expanded[c1]/bott_tex_scale/tex1 );
		}

		// butt (facing door or window when height change)
		if (hgh_expanded[c1] != hgh_expanded[c2] && but_shape) {
			btVector3 p1(path_outer[2*c1+0], path_outer[2*c1+1], hgh_expanded[c1]);
			btVector3 p2(path_inner[2*c1+0], path_inner[2*c1+1], hgh_expanded[c1]);
			btVector3 p3(path_inner[2*c1+0], path_inner[2*c1+1], hgh_expanded[c2]);
			btVector3 p4(path_outer[2*c1+0], path_outer[2*c1+1], hgh_expanded[c2]);
			btVector3 v1 = p2-p1;
			btVector3 v2 = p4-p1;
			btVector3 n = v1.cross(v2);
			n.normalize();
			if (TEST_GAP) {
				btVector3 center = (p1+p2+p3+p4)/4;
				p1 -= sign(p1-center)*TEST_GAP;
				p2 -= sign(p2-center)*TEST_GAP;
				p3 -= sign(p3-center)*TEST_GAP;
				p4 -= sign(p4-center)*TEST_GAP;
			}
			but_shape->push_vertex(p1.x(), p1.y(), p1.z());
			but_shape->push_vertex(p2.x(), p2.y(), p2.z());
			but_shape->push_vertex(p3.x(), p3.y(), p3.z());
			but_shape->push_vertex(p4.x(), p4.y(), p4.z());
			but_cshape->push_vertex(p1.x(), p1.y(), p1.z());
			but_cshape->push_vertex(p2.x(), p2.y(), p2.z());
			but_cshape->push_vertex(p3.x(), p3.y(), p3.z());
			but_cshape->push_vertex(p1.x(), p1.y(), p1.z());
			but_cshape->push_vertex(p3.x(), p3.y(), p3.z());
			but_cshape->push_vertex(p4.x(), p4.y(), p4.z());
			for (int c=0; c<4; c++)
				but_shape->push_normal(n.x(), n.y(), n.z()); // n.z is zero
			for (int c=0; c<6; c++)
				but_cshape->push_normal(n.x(), n.y(), n.z());
			float next_side_tex_spent = side_tex_spent + (p1-p2).norm() * (hgh_expanded[c1] > hgh_expanded[c2] ? +1:-1);
			but_shape->push_tex(side_tex_spent/butt_tex_scale/tex1,      (hgh_expanded[c1]-tex_v_zero)/butt_tex_scale/tex1);
			but_shape->push_tex(next_side_tex_spent/butt_tex_scale/tex1, (hgh_expanded[c1]-tex_v_zero)/butt_tex_scale/tex1);
			but_shape->push_tex(next_side_tex_spent/butt_tex_scale/tex1, (hgh_expanded[c2]-tex_v_zero)/butt_tex_scale/tex1);
			but_shape->push_tex(side_tex_spent/butt_tex_scale/tex1,      (hgh_expanded[c2]-tex_v_zero)/butt_tex_scale/tex1);
		}

		if (low_expanded[c1] != low_expanded[c2] && but_shape) {
			btVector3 p1(path_outer[2*c1+0], path_outer[2*c1+1], low_expanded[c1]);
			btVector3 p2(path_outer[2*c1+0], path_outer[2*c1+1], low_expanded[c2]);
			btVector3 p3(path_inner[2*c1+0], path_inner[2*c1+1], low_expanded[c2]);
			btVector3 p4(path_inner[2*c1+0], path_inner[2*c1+1], low_expanded[c1]);
			btVector3 v1 = p2-p1;
			btVector3 v2 = p4-p1;
			btVector3 n = v1.cross(v2);
			n.normalize();
			if (TEST_GAP) {
				btVector3 center = (p1+p2+p3+p4)/4;
				p1 -= sign(p1-center)*TEST_GAP;
				p2 -= sign(p2-center)*TEST_GAP;
				p3 -= sign(p3-center)*TEST_GAP;
				p4 -= sign(p4-center)*TEST_GAP;
			}
			but_shape->push_vertex(p1.x(), p1.y(), p1.z());
			but_shape->push_vertex(p2.x(), p2.y(), p2.z());
			but_shape->push_vertex(p3.x(), p3.y(), p3.z());
			but_shape->push_vertex(p4.x(), p4.y(), p4.z());
			but_cshape->push_vertex(p1.x(), p1.y(), p1.z());
			but_cshape->push_vertex(p2.x(), p2.y(), p2.z());
			but_cshape->push_vertex(p3.x(), p3.y(), p3.z());
			but_cshape->push_vertex(p1.x(), p1.y(), p1.z());
			but_cshape->push_vertex(p3.x(), p3.y(), p3.z());
			but_cshape->push_vertex(p4.x(), p4.y(), p4.z());
			for (int c=0; c<4; c++)
				but_shape->push_normal(n.x(), n.y(), n.z()); // n.z is zero
			for (int c=0; c<6; c++)
				but_cshape->push_normal(n.x(), n.y(), n.z());
			float next_side_tex_spent = side_tex_spent + (p2-p3).norm() * (low_expanded[c1] < low_expanded[c2] ? +1:-1);
			but_shape->push_tex(side_tex_spent/tex1,      (low_expanded[c1]-tex_v_zero)/butt_tex_scale/tex1);
			but_shape->push_tex(side_tex_spent/tex1,      (low_expanded[c2]-tex_v_zero)/butt_tex_scale/tex1);
			but_shape->push_tex(next_side_tex_spent/tex1, (low_expanded[c2]-tex_v_zero)/butt_tex_scale/tex1);
			but_shape->push_tex(next_side_tex_spent/tex1, (low_expanded[c1]-tex_v_zero)/butt_tex_scale/tex1);
		}
	}

	shared_ptr<Household::ShapeDetailLevels> shapeset_visual(new Household::ShapeDetailLevels);
	shared_ptr<Household::ShapeDetailLevels> shapeset_collision(new Household::ShapeDetailLevels);
	if (side_shape) {
		shapeset_visual->detail_levels[Household::DETAIL_BEST].push_back(side_shape);
		side_cshape->quads_from = side_cshape->v.size();
		shapeset_collision->detail_levels[Household::DETAIL_BEST].push_back(side_cshape);
	}
	if (top_shape) {
		shapeset_visual->detail_levels[Household::DETAIL_BEST].push_back(top_shape);
		top_cshape->quads_from = top_cshape->v.size();
		shapeset_collision->detail_levels[Household::DETAIL_BEST].push_back(top_cshape);
	}
	if (bot_shape) {
		shapeset_visual->detail_levels[Household::DETAIL_BEST].push_back(bot_shape);
		bot_cshape->quads_from = bot_cshape->v.size();
		shapeset_collision->detail_levels[Household::DETAIL_BEST].push_back(bot_cshape);
	}
	if (but_shape) {
		shapeset_visual->detail_levels[Household::DETAIL_BEST].push_back(but_shape);
		but_cshape->quads_from = but_cshape->v.size();
		shapeset_collision->detail_levels[Household::DETAIL_BEST].push_back(but_cshape);
	}
	shapeset_visual->materials = textures_cache;

	shared_ptr<ThingyClass> klass(new ThingyClass);
	klass->class_name = "WallTool";
	klass->metaclass = METACLASS_WALL;
	klass->shapedet_visual = shapeset_visual;
	klass->shapedet_collision = shapeset_collision;

	klass->make_compound_from_collision_shapes();

	shared_ptr<Thingy> th(new Thingy(klass));
	th->self_collision_ptr = th.get();
	thingy_add(th);
	return th;
}