summaryrefslogtreecommitdiff
path: root/src/gfx/map/mesh.rs
blob: 3d56ad8966cba1dc537d267edb4915000f0db8fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use super::{LeavesMode, MapRenderSettings, MeshgenInfo, Vertex, CUBE, FACE_DIR};
use cgmath::Point3;
use mt_net::MapBlock;

#[derive(Clone)]
pub(super) struct MeshData {
    pub vertices: Vec<Vertex>,
    pub vertices_blend: Vec<Vertex>,
}

impl MeshData {
    pub fn new(cap: usize) -> Self {
        Self {
            vertices: Vec::with_capacity(cap),
            vertices_blend: Vec::with_capacity(cap),
        }
    }

    pub fn cap(&self) -> usize {
        std::cmp::max(self.vertices.capacity(), self.vertices_blend.capacity())
    }
}

pub(super) fn create_mesh(
    mkinfo: &MeshgenInfo,
    settings: &MapRenderSettings,
    _pos: Point3<i16>,
    block: &MapBlock,
    nbors: [Option<&MapBlock>; 6],
    buffer: &mut MeshData,
) {
    for (index, &content) in block.param_0.iter().enumerate() {
        let def = match &mkinfo.nodes[content as usize] {
            Some(x) => x,
            None => continue,
        };

        use mt_net::{DrawType, Param1Type};
        use std::array::from_fn as array;

        let mut tiles = &def.tiles;
        let mut draw_type = def.draw_type;

        match draw_type {
            DrawType::AllFacesOpt => {
                draw_type = match settings.leaves {
                    LeavesMode::Opaque => DrawType::Cube,
                    LeavesMode::Simple => {
                        tiles = &def.special_tiles;

                        DrawType::GlassLike
                    }
                    LeavesMode::Fancy => DrawType::AllFaces,
                };
            }
            DrawType::None => continue,
            _ => {}
        }

        let light = match def.param1_type {
            Param1Type::Light => block.param_1[index] as f32 / 15.0, // FIXME
            _ => 1.0,
        };

        let vertices = if def.alpha == mt_net::Alpha::Blend {
            &mut buffer.vertices_blend
        } else {
            &mut buffer.vertices
        };

        let pos: [i16; 3] = array(|i| ((index >> (4 * i)) & 0xf) as i16);

        for (f, face) in CUBE.iter().enumerate() {
            if draw_type == DrawType::Cube || draw_type == DrawType::Liquid {
                let c = [1, 1, 0, 0, 2, 2][f];

                let mut nblk = block;
                let mut npos = pos;
                npos[c] += FACE_DIR[f][c];

                if !(0..16).contains(&npos[c]) {
                    nblk = match nbors[f].as_ref() {
                        Some(x) => x,
                        None => continue,
                    };

                    npos[c] = (npos[c] + 16) % 16;
                }

                let nidx = npos[0] | (npos[1] << 4) | (npos[2] << 8);
                let ncontent = nblk.param_0[nidx as usize];

                if let Some(ndef) = &mkinfo.nodes[ncontent as usize] {
                    if match draw_type {
                        DrawType::Cube => ndef.draw_type == DrawType::Cube,
                        DrawType::Liquid => ndef.draw_type == DrawType::Cube || ncontent == content,
                        _ => false,
                    } {
                        continue;
                    }
                }
            }

            let tile = &tiles[f];
            let texture = mkinfo.textures[tile.texture.custom].cube_tex_coords[f];

            let mut add_vertex = |vertex: (usize, &([f32; 3], [f32; 2]))| {
                vertices.push(Vertex {
                    pos: array(|i| pos[i] as f32 + vertex.1 .0[i]),
                    tex_coords: texture[vertex.0],
                    light,
                });
            };

            face.iter().enumerate().for_each(&mut add_vertex);
            if !tile.flags.contains(mt_net::TileFlag::BackfaceCull) {
                face.iter().enumerate().rev().for_each(&mut add_vertex);
            }
        }
    }
}