void primitives_to_mesh()

in roboschool/cpp-household/render-simple-primitives.cpp [8:222]


void primitives_to_mesh(const shared_ptr<ShapeDetailLevels>& m, int want_detail, int s)
{
	std::vector<shared_ptr<SimpleRender::Shape>>& shapes = m->detail_levels[want_detail];
	const std::vector<shared_ptr<SimpleRender::Shape>>& best_detail = m->detail_levels[DETAIL_BEST];

	int shapes_count = best_detail.size();
	shapes.resize(shapes_count);

	{
		shared_ptr<SimpleRender::Shape> lower_detail;
		if (want_detail==DETAIL_BEST) {
			lower_detail = best_detail[s];
		} else {
			lower_detail.reset(new SimpleRender::Shape);
			*lower_detail = *(best_detail[s]); // copy by value
		}

		if (lower_detail->primitive_type==SimpleRender::Shape::MESH) {
			// TODO: simplify
			// now leave copied best_detail

		} else if (lower_detail->primitive_type==SimpleRender::Shape::STATIC_MESH) {
			// visualizing collision shape, leave it as it is

		} else if (lower_detail->primitive_type==SimpleRender::Shape::BOX) {
			assert(lower_detail->v.empty());
			double n[] = {
			+1, 0, 0,
			-1, 0, 0,
			0, +1, 0,
			0, -1, 0,
			0, 0, +1,
			0, 0, -1 };
			for (int f=0; f<6; f++) {
				double side[] = {
				+1, +1,
				-1, +1,
				-1, -1,
				+1, -1 };
				int zero1 = n[3*f + 0]==0 ? 0 : 1;
				int zero2 = n[3*f + 2]==0 ? 2 : 1;
				int sign = n[3*f + 0] + n[3*f + 1] + n[3*f + 2];
				if (f==2 || f==3) sign *= -1;
				int ind_reloc[] = { 0,1,3, 3,1,2 }; // Triangles that together make up rect 0123
				for (int i=0; i<6; ++i) {
					int idx = ind_reloc[i];
					lower_detail->push_normal(n[3*f + 0], n[3*f + 1], n[3*f + 2]);
					float v[3];
					v[0] = n[3*f+0];
					v[1] = n[3*f+1];
					v[2] = n[3*f+2];
					if (sign > 0) {
						v[zero1] = side[2*idx + 0];
						v[zero2] = side[2*idx + 1];
					} else {
						v[zero1] = side[6 - 2*idx];
						v[zero2] = side[7 - 2*idx];
					}
					lower_detail->push_vertex(v[0]*0.5*lower_detail->box->size_x, v[1]*0.5*lower_detail->box->size_y, v[2]*0.5*lower_detail->box->size_z);
				}
			}

		} else if (lower_detail->primitive_type==SimpleRender::Shape::CYLINDER) {
			assert(lower_detail->v.empty());
			int side_faces;
			switch (want_detail) {
			case 0: side_faces = 16; break;
			case 1: side_faces =  8; break;
			default: side_faces = 3; break;
			}
			float l = lower_detail->cylinder->length;
			float r = lower_detail->cylinder->radius;
			for (int c=0; c<side_faces; c++) {
				float angle1 = float(c)   / side_faces * 2 * M_PI;
				float angle2 = float(c+1) / side_faces * 2 * M_PI;
				float n1[3], n2[3];
				n1[0] = cos(angle1); n1[1] = sin(angle1); n1[2] = 0;
				n2[0] = cos(angle2); n2[1] = sin(angle2); n2[2] = 0;
				lower_detail->push_vertex(n1[0]*r, n1[1]*r, +l*0.5);
				lower_detail->push_vertex(n2[0]*r, n2[1]*r, +l*0.5);
				lower_detail->push_vertex(   0.0f,       0, +l*0.5);
				lower_detail->push_normal(0.0f, 0, 1);
				lower_detail->push_normal(0.0f, 0, 1);
				lower_detail->push_normal(0.0f, 0, 1);
				lower_detail->push_vertex(n1[0]*r, n1[1]*r, -l*0.5);
				lower_detail->push_vertex(   0.0f,       0, -l*0.5);
				lower_detail->push_vertex(n2[0]*r, n2[1]*r, -l*0.5);
				lower_detail->push_normal(0.0f, 0, -1);
				lower_detail->push_normal(0.0f, 0, -1);
				lower_detail->push_normal(0.0f, 0, -1);
			}
			for (int c=0; c<side_faces; c++) {
				float angle1 = float(c)   / side_faces * 2 * M_PI;
				float angle2 = float(c+1) / side_faces * 2 * M_PI;
				float n1[3], n2[3];
				n1[0] = cos(angle1); n1[1] = sin(angle1); n1[2] = 0;
				n2[0] = cos(angle2); n2[1] = sin(angle2); n2[2] = 0;
				lower_detail->push_vertex(n1[0]*r, n1[1]*r, -l*0.5);
				lower_detail->push_vertex(n2[0]*r, n2[1]*r, -l*0.5);
				lower_detail->push_vertex(n2[0]*r, n2[1]*r, +l*0.5);
				lower_detail->push_normal(n1[0], n1[1], n1[2]);
				lower_detail->push_normal(n2[0], n2[1], n2[2]);
				lower_detail->push_normal(n2[0], n2[1], n2[2]);

				lower_detail->push_vertex(n1[0]*r, n1[1]*r, -l*0.5);
				lower_detail->push_vertex(n2[0]*r, n2[1]*r, +l*0.5);
				lower_detail->push_vertex(n1[0]*r, n1[1]*r, +l*0.5);
				lower_detail->push_normal(n1[0], n1[1], n1[2]);
				lower_detail->push_normal(n2[0], n2[1], n2[2]);
				lower_detail->push_normal(n1[0], n1[1], n1[2]);
			}

		} else if (lower_detail->primitive_type==SimpleRender::Shape::SPHERE || lower_detail->primitive_type==SimpleRender::Shape::CAPSULE) {
			assert(lower_detail->v.empty());
			std::vector<aiVector3D> v(12, aiVector3D());
			// Icosahedron
			double theta = 26.56505117707799 * M_PI / 180.0;
			v[0] = aiVector3D(0,0,-1);
			double phi = M_PI/5;
			for (int i=1; i<6; ++i) {
				v[i] = aiVector3D(cos(theta)*cos(phi), cos(theta)*sin(phi), -sin(theta));
				phi += 2*M_PI / 5;
			}
			phi = 0.0;
			for (int i=6; i<11; ++i) {
				v[i] = aiVector3D(cos(theta)*cos(phi), cos(theta)*sin(phi), sin(theta));
				phi += 2*M_PI / 5;
			}
			v[11] = aiVector3D(0,0,+1);
			int idx[] = {
			0,2,1,
			0,3,2,
			0,4,3,
			0,5,4,
			0,1,5,
			1,2,7,
			2,3,8,
			3,4,9,
			4,5,10,
			5,1,6,
			1,7,6,
			2,8,7,
			3,9,8,
			4,10,9,
			5,6,10,
			6,7,11,
			7,8,11,
			8,9,11,
			9,10,11,
			10,6,11,
			};
			for (int i=0; i<20*3; i++)
				lower_detail->push_vertex(v[idx[i]].x, v[idx[i]].y, v[idx[i]].z);

			int repeat;
			switch (want_detail) {
			case DETAIL_BEST:  repeat = 2; break;
			case DETAIL_LOWER: repeat = 1; break;
			default: repeat = 0;
			}

			for (int c=0; c<repeat; c++) { // improve detail
				std::vector<float> v;
				v.swap(lower_detail->v);
				for (int i=0; i<(int)v.size(); i+=9) {
					aiVector3D e0(v[i+0], v[i+1], v[i+2]);
					aiVector3D e1(v[i+3], v[i+4], v[i+5]);
					aiVector3D e2(v[i+6], v[i+7], v[i+8]);
					aiVector3D mid01(e0.x+e1.x, e0.y+e1.y, e0.z+e1.z);
					aiVector3D mid12(e1.x+e2.x, e1.y+e2.y, e1.z+e2.z);
					aiVector3D mid20(e2.x+e0.x, e2.y+e0.y, e2.z+e0.z);
					mid01.Normalize();
					mid12.Normalize();
					mid20.Normalize();
					lower_detail->push_vertex(mid01.x, mid01.y, mid01.z);
					lower_detail->push_vertex(mid12.x, mid12.y, mid12.z);
					lower_detail->push_vertex(mid20.x, mid20.y, mid20.z);
					lower_detail->push_vertex(e0.x, e0.y, e0.z);
					lower_detail->push_vertex(mid01.x, mid01.y, mid01.z);
					lower_detail->push_vertex(mid20.x, mid20.y, mid20.z);
					lower_detail->push_vertex(e1.x, e1.y, e1.z);
					lower_detail->push_vertex(mid12.x, mid12.y, mid12.z);
					lower_detail->push_vertex(mid01.x, mid01.y, mid01.z);
					lower_detail->push_vertex(e2.x, e2.y, e2.z);
					lower_detail->push_vertex(mid20.x, mid20.y, mid20.z);
					lower_detail->push_vertex(mid12.x, mid12.y, mid12.z);
				}
			}

			bool capsule = lower_detail->primitive_type==SimpleRender::Shape::CAPSULE;
			float rad = capsule ? lower_detail->cylinder->radius : lower_detail->sphere->radius;
			float len = capsule ? lower_detail->cylinder->length/2 : 0;
			for (int i=0; i<(int)lower_detail->v.size()/3; i++) {
				lower_detail->norm.push_back(lower_detail->v[3*i+0]);
				lower_detail->norm.push_back(lower_detail->v[3*i+1]);
				lower_detail->norm.push_back(lower_detail->v[3*i+2]);
				lower_detail->v[3*i+0] *= rad;
				lower_detail->v[3*i+1] *= rad;
				lower_detail->v[3*i+2] *= rad;
				if (capsule) {
					if (lower_detail->v[3*i+2] > 0) {
						lower_detail->v[3*i+2] += len;
					} else if (lower_detail->v[3*i+2] < 0) {
						lower_detail->v[3*i+2] -= len;
					}
				}
			}

		} else {
			assert(!"unknown shape");
		}

		shapes[s] = lower_detail;
	}
}