aboutsummaryrefslogtreecommitdiff
path: root/stockton-render/src/draw/render.rs
blob: b713a8d2a02cc794decc70fe559217f8d7a86bfc (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
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
 * Copyright (C) Oscar Shrimpton 2020
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

use crate::draw::draw_buffers::INITIAL_INDEX_SIZE;
use crate::draw::draw_buffers::INITIAL_VERT_SIZE;
use crate::draw::UvPoint;
use arrayvec::ArrayVec;
use faces::FaceType;
use hal::prelude::*;
use std::convert::TryInto;
use stockton_levels::prelude::*;
use stockton_types::Vector2;

use crate::draw::draw_buffers::DrawBuffers;
use crate::types::*;

use super::texture::TextureRepo;

fn draw_or_queue(
    current_chunk: usize,
    tex_repo: &mut TextureRepo,
    cmd_buffer: &mut CommandBuffer,
    pipeline_layout: &PipelineLayout,
    chunk_start: u32,
    curr_idx_idx: u32,
) {
    if let Some(ds) = tex_repo.attempt_get_descriptor_set(current_chunk) {
        let mut descriptor_sets: ArrayVec<[_; 1]> = ArrayVec::new();
        descriptor_sets.push(ds);
        unsafe {
            cmd_buffer.bind_graphics_descriptor_sets(pipeline_layout, 0, descriptor_sets, &[]);
            cmd_buffer.draw_indexed(chunk_start * 3..(curr_idx_idx * 3) + 1, 0, 0..1);
        }
    } else {
        tex_repo.queue_load(current_chunk).unwrap()
    }
}

pub fn do_render<M: MinBspFeatures<VulkanSystem>>(
    cmd_buffer: &mut CommandBuffer,
    draw_buffers: &mut DrawBuffers<UvPoint>,
    tex_repo: &mut TextureRepo,
    pipeline_layout: &PipelineLayout,
    file: &M,
    faces: &[u32],
) {
    // Iterate over faces, copying them in and drawing groups that use the same texture chunk all at once.
    let mut current_chunk = file.get_face(0).texture_idx as usize / 8;
    let mut chunk_start = 0;

    let mut curr_vert_idx: usize = 0;
    let mut curr_idx_idx: usize = 0;

    for face in faces.iter().map(|idx| file.get_face(*idx)) {
        if current_chunk != face.texture_idx as usize / 8 {
            // Last index was last of group, so draw it all if textures are loaded.
            draw_or_queue(
                current_chunk,
                tex_repo,
                cmd_buffer,
                pipeline_layout,
                chunk_start as u32,
                curr_idx_idx as u32,
            );

            // Next group of same-chunked faces starts here.
            chunk_start = curr_idx_idx;
            current_chunk = face.texture_idx as usize / 8;
        }

        if face.face_type == FaceType::Polygon || face.face_type == FaceType::Mesh {
            // 2 layers of indirection
            let base = face.vertices_idx.start;

            for idx in face.meshverts_idx.clone().step_by(3) {
                let start_idx: u16 = curr_vert_idx.try_into().unwrap();

                for idx2 in idx..idx + 3 {
                    let vert = &file.resolve_meshvert(idx2 as u32, base);
                    let uv = Vector2::new(vert.tex.u[0], vert.tex.v[0]);

                    let uvp = UvPoint(vert.position, face.texture_idx.try_into().unwrap(), uv);
                    draw_buffers.vertex_buffer[curr_vert_idx] = uvp;

                    curr_vert_idx += 1;
                }

                draw_buffers.index_buffer[curr_idx_idx] = (start_idx, start_idx + 1, start_idx + 2);

                curr_idx_idx += 1;

                if curr_vert_idx >= INITIAL_VERT_SIZE.try_into().unwrap()
                    || curr_idx_idx >= INITIAL_INDEX_SIZE.try_into().unwrap()
                {
                    println!("out of vertex buffer space!");
                    break;
                }
            }
        } else {
            // TODO: Other types of faces
        }

        if curr_vert_idx >= INITIAL_VERT_SIZE.try_into().unwrap()
            || curr_idx_idx >= INITIAL_INDEX_SIZE.try_into().unwrap()
        {
            println!("out of vertex buffer space!");
            break;
        }
    }

    // Draw the final group of chunks
    draw_or_queue(
        current_chunk,
        tex_repo,
        cmd_buffer,
        pipeline_layout,
        chunk_start as u32,
        curr_idx_idx as u32,
    );
}