public kd_node createKDTreeNode(Vector3 pmin, Vector3 pmax, int deep, int cant_f, int [] p_list) { kd_node p_node = new kd_node(); p_node.deep = deep; p_node.p_min = pmin; p_node.p_max = pmax; // creo un nodo leaf p_node.cant_f = cant_f; p_node.p_list = p_list; // si la cantidad de primitivas en el nodo es mayor a cierto limite y el deep no supera el maximo, pruebo dividir el nodo if (cant_f >= MAX_FACE_X_NODE && deep < max_deep) { // divido el nodo en 2: Vector3 dim = pmax - pmin; Vector3 Lmin, Lmax, Rmin, Rmax; int eje; float s; // version eje fijo: selecciono el eje en base a la direccion que mas extension tiene { if (MathF.Abs(dim.Z) >= MathF.Abs(dim.X) && MathF.Abs(dim.Z) >= MathF.Abs(dim.Y)) { eje = 2; // split Z s = (pmin.Z + pmax.Z) * 0.5f; } else if (MathF.Abs(dim.X) >= MathF.Abs(dim.Z) && MathF.Abs(dim.X) >= MathF.Abs(dim.Y)) { eje = 0; // splite X s = (pmin.X + pmax.X) * 0.5f; } else { eje = 1; // split Y s = (pmin.Y + pmax.Y) * 0.5f; } //s = best_split(eje,p_node); } /* * else * { * // version que prueba los 3 ejes: * eje = best_split(p_node, &s); * } */ p_node.split = s; p_node.split_plane = eje; Rmin = Lmin = pmin; Rmax = Lmax = pmax; switch (eje) { case 0: Lmax.X = s; Rmin.X = s; break; case 1: Lmax.Y = s; Rmin.Y = s; break; case 2: Lmax.Z = s; Rmin.Z = s; break; } // clasifico las primitivas int cant_L = 0; int cant_R = 0; int[] list_L = new int[cant_f]; int[] list_R = new int[cant_f]; for (int i = 0; i < cant_f; ++i) { bsp_face f = F[p_list[i]]; if (box_overlap(f.pmin, f.pmax, Lmin, Lmax)) { list_L[cant_L++] = p_list[i]; } if (box_overlap(f.pmin, f.pmax, Rmin, Rmax)) { list_R[cant_R++] = p_list[i]; } } // hago el nodo interior: // libero la memoria original /* * if (p_node.p_list) * { * delete[] p_node.p_list; * p_node.p_list = NULL; * }*/ p_node.p_list = null; // creo los 2 nodos hijos p_node.p_left = createKDTreeNode(Lmin, Lmax, deep + 1, cant_L, list_L); p_node.p_right = createKDTreeNode(Rmin, Rmax, deep + 1, cant_R, list_R); } return(p_node); }
public CBspFile(string fname, GraphicsDevice p_device, ContentManager p_content) { device = p_device; Content = p_content; Effect = Content.Load <Effect>("Effects/PhongShader"); EffectMesh = Content.Load <Effect>("Effects/BasicShader"); var fp = new FileStream(map_folder + fname + ".tgc", FileMode.Open, FileAccess.Read); var arrayByte = new byte[(int)fp.Length]; fp.Read(arrayByte, 0, (int)fp.Length); fp.Close(); initMeshFromData(arrayByte); texture_default = Content.Load <Texture2D>("Textures/barrier"); // cargo las entidades cargarEntidades(fname); createSpriteQuad(); // experimento kdtree con toda la escena + los mesh g_cant_faces = cant_faces; for (int i = 0; i < cant_modelos; ++i) { g_cant_faces += mesh_pool.meshes[modelos[i].nro_mesh].cant_faces; } g_faces = new bsp_face[g_cant_faces]; g_cant_faces = 0; for (var i = 0; i < cant_faces; ++i) { g_faces[g_cant_faces++] = faces[i]; } VertexPosition[] bb_vertices = new VertexPosition[cant_modelos * 36]; var t = 0; for (int i = 0; i < cant_modelos; ++i) { var m = mesh_pool.meshes[modelos[i].nro_mesh]; // TODO: determino si me conviene usar todo el mesh a nivel triangulos // o solo el bounding box /*var dx = m.p_max.X - m.p_min.X; * var dy = m.p_max.Y - m.p_min.Y; * var dz = m.p_max.Z - m.p_min.Z; */ if (true) { // todos los triangulos for (var j = 0; j < m.cant_faces; ++j) { var face = g_faces[g_cant_faces++] = new bsp_face(); for (var k = 0; k < 3; ++k) { face.v[k] = Vector3.Transform(m.faces[j].v[k], modelos[i].world()); face.nro_modelo = i; } } } else { // solo el bounding box oobb var x0 = m.p_min.X; var y0 = m.p_min.Y; var z0 = m.p_min.Z; var x1 = m.p_max.X; var y1 = m.p_max.Y; var z1 = m.p_max.Z; Vector3[] p = new Vector3[8]; p[0] = new Vector3(x0, y0, z0); p[1] = new Vector3(x1, y0, z0); p[2] = new Vector3(x1, y1, z0); p[3] = new Vector3(x0, y1, z0); p[4] = new Vector3(x0, y0, z1); p[5] = new Vector3(x1, y0, z1); p[6] = new Vector3(x1, y1, z1); p[7] = new Vector3(x0, y1, z1); for (var j = 0; j < 8; ++j) { p[j] = Vector3.Transform(p[j], modelos[i].world()); } int[] ndx = { 0, 1, 2, 0, 2, 3, // abajo 4, 5, 6, 4, 6, 7, // arriba 1, 2, 6, 1, 6, 5, // derecha 0, 3, 7, 0, 7, 4, // izquierda 3, 2, 6, 3, 6, 7, // adelante 0, 1, 5, 0, 5, 4 // atras }; for (int j = 0; j < 36; ++j) { bb_vertices[t++] = new VertexPosition(p[ndx[j]]); } } } cant_debug_bb = t; if (cant_debug_bb > 0) { bbVertexBuffer = new VertexBuffer(device, VertexPosition.VertexDeclaration, t, BufferUsage.WriteOnly); bbVertexBuffer.SetData(bb_vertices, 0, t); } // armo el kdtree //kd_tree = new KDTree(cant_faces, faces); kd_tree = new KDTree(g_cant_faces, g_faces); kd_tree.createKDTree(); // imagenes images[cant_images++] = cargarImagen("sprites\\redglow4"); images[cant_images++] = cargarImagen("sprites\\dot"); images[cant_images++] = cargarImagen("sprites\\orangecore1"); images[cant_images++] = cargarImagen("sprites\\laserdot"); // decals createDecals(); }
public void initMeshFromData(byte[] arrayByte) { var t = 0; int cant_v = (int)BitConverter.ToInt32(arrayByte, t); t += 4; float min_x = 1000000; float min_y = 1000000; float min_z = 1000000; float max_x = -1000000; float max_y = -1000000; float max_z = -1000000; ValveVertex[] vertices = new ValveVertex[cant_v]; for (var i = 0; i < cant_v; ++i) { var x = BitConverter.ToSingle(arrayByte, t); t += 4; var z = BitConverter.ToSingle(arrayByte, t); t += 4; var y = BitConverter.ToSingle(arrayByte, t); t += 4; vertices[i].Position.X = x; vertices[i].Position.Y = y; vertices[i].Position.Z = z; if (x < min_x) { min_x = x; } if (y < min_y) { min_y = y; } if (z < min_z) { min_z = z; } if (x > max_x) { max_x = x; } if (y > max_y) { max_y = y; } if (z > max_z) { max_z = z; } vertices[i].TextureCoordinate.X = BitConverter.ToSingle(arrayByte, t); t += 4; vertices[i].TextureCoordinate.Y = BitConverter.ToSingle(arrayByte, t); t += 4; vertices[i].LightmapCoordinate.X = -BitConverter.ToSingle(arrayByte, t); t += 4; vertices[i].LightmapCoordinate.Y = BitConverter.ToSingle(arrayByte, t); t += 4; } // actualizo el bounding box p_min = new Vector3(min_x, min_y, min_z); p_max = new Vector3(max_x, max_y, max_z); size = new Vector3(max_x - min_x, max_y - min_y, max_z - min_z); cg = p_min + size * 0.5f; // computo la normal y de paso actualizo la geoemtria int cant_tri = cant_v / 3; for (int i = 0; i < cant_tri; ++i) { Vector3 v0 = vertices[3 * i].Position; Vector3 v1 = vertices[3 * i + 1].Position; Vector3 v2 = vertices[3 * i + 2].Position; Vector3 N = Vector3.Cross(v1 - v0, v2 - v0); N.Normalize(); vertices[3 * i].Normal = vertices[3 * i + 1].Normal = vertices[3 * i + 2].Normal = N; } VertexBuffer = new VertexBuffer(device, ValveVertex.VertexDeclaration, cant_v, BufferUsage.WriteOnly); VertexBuffer.SetData(vertices); // estructura de subsets cant_subsets = (int)BitConverter.ToInt32(arrayByte, t); t += 4; subset = new bsp_subset[cant_subsets]; texture = new Texture2D[cant_subsets]; for (int i = 0; i < cant_subsets; ++i) { subset[i] = new bsp_subset(); subset[i].cant_items = (int)BitConverter.ToInt32(arrayByte, t); t += 4; string name = getString(arrayByte, t, 256); t += 256; name = name.ToUpper(); subset[i].image_name = name = que_tga_name(name); var tga = tex_folder + name + ".tga"; texture[i] = null; if (File.Exists(tga)) { texture[i] = CTextureLoader.Load(device, tga); } if (texture[i] == null) { Debug.WriteLine(i + "-" + subset[i].image_name); } } // como mucho hay cant_tri faces a los efectos de colision, anulo las que son TOOLS faces = new bsp_face[cant_tri]; cant_faces = 0; var pos = 0; for (var i = 0; i < cant_subsets; i++) { if (!subset[i].image_name.StartsWith("TOOLS")) { for (int j = 0; j < subset[i].cant_items; ++j) { var k = pos + 3 * j; Vector3 v0 = vertices[k].Position; Vector3 v1 = vertices[k + 1].Position; Vector3 v2 = vertices[k + 2].Position; faces[cant_faces] = new bsp_face(); faces[cant_faces].v[0] = v0; faces[cant_faces].v[1] = v1; faces[cant_faces].v[2] = v2; faces[cant_faces].nro_modelo = -1 - i; // escenario cant_faces++; } } pos += subset[i].cant_items * 3; } // leo el lightmap lightmap = new Texture2D(device, 2048, 2048); int lm_size = 2048 * 2048; Color[] data = new Color[lm_size]; for (int pixel = 0; pixel < lm_size; pixel++) { data[pixel].R = arrayByte[t++]; data[pixel].G = arrayByte[t++]; data[pixel].B = arrayByte[t++]; data[pixel].A = (byte)(arrayByte[t++] + 128); } lightmap.SetData(data); }
public bool cargar_smd(String fname) { var fp = new System.IO.StreamReader(fname); var buffer = fp.ReadLine().TrimStart(); while (!buffer.StartsWith("nodes")) { buffer = fp.ReadLine().TrimStart(); } // huesos buffer = fp.ReadLine().TrimStart(); while (!buffer.StartsWith("end")) { // 0 "L_Armdummy" -1 string[] tokens = buffer.Split(' '); bones[cant_bones] = new smd_bone(); bones[cant_bones].id = int.Parse(tokens[0]); bones[cant_bones].name = tokens[1]; bones[cant_bones].parent = int.Parse(tokens[2]); ++cant_bones; buffer = fp.ReadLine().TrimStart(); } // skeleton fp.ReadLine().TrimStart(); // time 0 fp.ReadLine().TrimStart(); buffer = fp.ReadLine().TrimStart(); while (!buffer.StartsWith("end")) { string[] tokens = buffer.Split(' '); int id = int.Parse(tokens[0]); if (id >= 0 && id < cant_bones) { bones[id].startPosition.X = atof(tokens[1]); bones[id].startPosition.Y = atof(tokens[2]); bones[id].startPosition.Z = atof(tokens[3]); bones[id].startRotation.X = atof(tokens[4]); bones[id].startRotation.Y = atof(tokens[5]); bones[id].startRotation.Z = atof(tokens[6]); } buffer = fp.ReadLine().TrimStart(); } // triangles y subsets cant_subsets = 0; subset = new smd_subset[100]; smd_vertex[] vertices = new smd_vertex[65535]; int cant_v = 0; float min_x = 1000000; float min_y = 1000000; float min_z = 1000000; float max_x = -1000000; float max_y = -1000000; float max_z = -1000000; fp.ReadLine().TrimStart(); buffer = fp.ReadLine().TrimStart(); smd_subset cur_subset = null; while (!buffer.StartsWith("end")) { // material var mat = Path.GetFileNameWithoutExtension(buffer); if (que_subset(mat) == -1) { // agrego el subset cur_subset = subset[cant_subsets++] = new smd_subset(mat); } // 3 vertices // 35 4.564999 -13.692499 -4.852700 -0.237700 0.289800 0.927100 0.498400 0.279000 for (int i = 0; i < 3; ++i) { buffer = fp.ReadLine().TrimStart(); string[] tokens = buffer.Split(' '); int id = int.Parse(tokens[0]); Vector3 P = transform(new Vector3(atof(tokens[1]), atof(tokens[2]), atof(tokens[3])), Metric); Vector3 N = transform(new Vector3(atof(tokens[4]), atof(tokens[5]), atof(tokens[6])), Metric); vertices[cant_v].Position.X = P.X; vertices[cant_v].Position.Y = P.Y; vertices[cant_v].Position.Z = P.Z; vertices[cant_v].Normal.X = N.X; vertices[cant_v].Normal.Y = N.Y; vertices[cant_v].Normal.Z = N.Z; vertices[cant_v].TextureCoordinate.X = atof(tokens[7]); vertices[cant_v].TextureCoordinate.Y = -atof(tokens[8]); vertices[cant_v].BlendIndices.X = id; vertices[cant_v].BlendWeight.X = 1; ++cant_v; if (P.X < min_x) { min_x = P.X; } if (P.Y < min_y) { min_y = P.Y; } if (P.Z < min_z) { min_z = P.Z; } if (P.X > max_x) { max_x = P.X; } if (P.Y > max_y) { max_y = P.Y; } if (P.Z > max_z) { max_z = P.Z; } } cur_subset.cant_items++; buffer = fp.ReadLine().TrimStart(); } fp.Close(); setupBones(); // actualizo el bounding box p_min = new Vector3(min_x, min_y, min_z); p_max = new Vector3(max_x, max_y, max_z); size = new Vector3(max_x - min_x, max_y - min_y, max_z - min_z); cg = p_min + size * 0.5f; // Creo el vertex buffer VertexBuffer = new VertexBuffer(device, smd_vertex.VertexDeclaration, cant_v, BufferUsage.WriteOnly); VertexBuffer.SetData(vertices, 0, cant_v); // almaceno los faces a los efectos de colision faces = new bsp_face[cant_v / 3]; cant_faces = 0; var pos = 0; for (var i = 0; i < cant_subsets; i++) { for (int j = 0; j < subset[i].cant_items; ++j) { var k = pos + 3 * j; Vector3 v0 = vertices[k].Position; Vector3 v1 = vertices[k + 1].Position; Vector3 v2 = vertices[k + 2].Position; faces[cant_faces] = new bsp_face(); faces[cant_faces].v[0] = v0; faces[cant_faces].v[1] = v1; faces[cant_faces].v[2] = v2; cant_faces++; } pos += subset[i].cant_items * 3; } initTextures(); // actualizo la pos de cada subset pos = 0; for (var i = 0; i < cant_subsets; i++) { subset[i].pos = pos; pos += subset[i].cant_items * 3; } return(true); }