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
135
136
137
138
139
140
141
142
143
144
use c_str_macro::c_str;
use reverie_util::math::nalgebra::{Matrix4, Point3, Vector3};

use crate::{
    gl::{self, Gl},
    shader::{Program, Shader, Uniform::*, UniformVariables},
    texture::ImageLoadInfo,
    vao::Vao,
};

pub trait Renderer<T> {
    fn render(&self, gl: Gl, vao: &Vao, extra: T);
}

#[derive(Debug)]
pub struct Phong3DRenderer {
    program: Program,
}

impl Phong3DRenderer {
    pub fn new(program: Program) -> Self {
        Self { program }
    }
}

pub struct PhongRenderingInfo<'a> {
    /* ベクトルではなく色 */
    pub material_specular: &'a Vector3<f32>,
    pub material_shininess: f32,
    pub light_direction: &'a Vector3<f32>,
    /* ambient, diffuse, specular はベクトルではなく色 */
    pub ambient: &'a Vector3<f32>,
    pub diffuse: &'a Vector3<f32>,
    pub specular: &'a Vector3<f32>,
    pub alpha: f32,
}

pub struct Phong3DRenderingInfo<'a> {
    pub phong: &'a PhongRenderingInfo<'a>,
    pub model_matrix: &'a Matrix4<f32>,
    pub view_matrix: &'a Matrix4<f32>,
    pub projection_matrix: &'a Matrix4<f32>,
    pub camera_pos: &'a Point3<f32>,
    pub texture: &'a ImageLoadInfo<'a>,
}

impl Renderer<&Phong3DRenderingInfo<'_>> for Phong3DRenderer {
    fn render(&self, gl: Gl, vao: &Vao, extra: &Phong3DRenderingInfo) {
        let uniforms = {
            use crate::shader::Uniform::*;
            let mut uniforms = UniformVariables::new();
            uniforms.add(c_str!("uModel"), Matrix4(extra.model_matrix));
            uniforms.add(c_str!("uView"), Matrix4(extra.view_matrix));
            uniforms.add(c_str!("uProjection"), Matrix4(extra.projection_matrix));
            uniforms.add(
                c_str!("uViewPosition"),
                TripleFloat(extra.camera_pos.x, extra.camera_pos.y, extra.camera_pos.z),
            );
            uniforms
        };

        unsafe {
            self.program
                .set_uniform(c_str!("uAlpha"), &Float(extra.phong.alpha));
            self.program.set_uniform(
                c_str!("uMaterial.specular"),
                &Vector3(extra.phong.material_specular),
            );
            self.program.set_uniform(
                c_str!("uMaterial.shininess"),
                &Float(extra.phong.material_shininess),
            );
            self.program
                .set_uniform(c_str!("uLight.direction"), &Vector3(extra.phong.light_direction));
            self.program
                .set_uniform(c_str!("uLight.ambient"), &Vector3(extra.phong.ambient));
            self.program
                .set_uniform(c_str!("uLight.diffuse"), &Vector3(extra.phong.diffuse));
            self.program
                .set_uniform(c_str!("uLight.specular"), &Vector3(extra.phong.specular));

            self.program.set_used();
            self.program.set_uniforms(&uniforms);
        }

        unsafe {
            gl.BindTexture(gl::TEXTURE_2D, extra.texture.raw_gl_id());
            vao.draw_triangles(&uniforms);
            gl.BindTexture(gl::TEXTURE_2D, 0);
        }
    }
}

#[derive(Debug)]
pub struct Color3DRenderer {
    program: Program,
}

impl Color3DRenderer {
    pub fn new(gl: &Gl) -> Self {
        let vert_shader =
            Shader::from_vert_code(gl.clone(), c_str!(include_str!("../../resources/color3d.vert")))
                .unwrap();
        let frag_shader =
            Shader::from_frag_code(gl.clone(), c_str!(include_str!("../../resources/color3d.frag")))
                .unwrap();
        let program = Program::from_shaders(gl.clone(), &[vert_shader, frag_shader]).unwrap();
        Self { program }
    }
}

pub struct Color3DRenderingInfo<'a> {
    pub model_matrix: &'a Matrix4<f32>,
    pub view_matrix: &'a Matrix4<f32>,
    pub projection_matrix: &'a Matrix4<f32>,
    pub camera_pos: &'a Point3<f32>,
}

impl Renderer<&Color3DRenderingInfo<'_>> for Color3DRenderer {
    fn render(&self, gl: Gl, vao: &Vao, extra: &Color3DRenderingInfo) {
        let uniforms = {
            use crate::shader::Uniform::*;
            let mut uniforms = UniformVariables::new();
            uniforms.add(c_str!("uModel"), Matrix4(extra.model_matrix));
            uniforms.add(c_str!("uView"), Matrix4(extra.view_matrix));
            uniforms.add(c_str!("uProjection"), Matrix4(extra.projection_matrix));
            uniforms.add(
                c_str!("uViewPosition"),
                TripleFloat(extra.camera_pos.x, extra.camera_pos.y, extra.camera_pos.z),
            );
            uniforms
        };

        unsafe {
            self.program.set_used();
            self.program.set_uniforms(&uniforms);
        }

        unsafe {
            gl.BindTexture(gl::TEXTURE_2D, 0);
            vao.draw(&uniforms, gl::LINES);
        }
    }
}