use crate::core::shader::object::{VertexArray, Buffer, ObjectState, Object, TextureBuffer};
use crate::core::shader::program::Program;
use crate::core::resource::image::Image;
use crate::core::shader::data::ObjectData;
use crate::core::math::mvp;
use crate::core::project::Draw;
use crate::core::math::transform::Transform;
use crate::core::shader::Shader;
const VERTEX_SHADER_SOURCE: &str = r#"
#version 330
layout (location = 0) in vec2 position;
layout (location = 1) in vec2 texcoord;
layout (location = 2) in vec2 offset;
layout (location = 3) in vec2 scale;
layout (location = 4) in vec4 color;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
out vec2 oTexCoord;
out vec4 oColor;
void main() {
vec2 scale_position = position * scale;
vec2 offset_position = scale_position + offset;
gl_Position = projection * view * model * vec4(offset_position, 0.0, 1.0);
oTexCoord = texcoord;
oColor = color;
}
"#;
const FRAGMENT_SHADER_SOURCE: &str = r#"
#version 330
uniform sampler2D sampler;
in vec2 oTexCoord;
in vec4 oColor;
out vec4 color;
void main() {
vec4 t = texture(sampler, oTexCoord);
t.r = oColor.r;
t.g = oColor.g;
t.b = oColor.b;
t.a = t.a * oColor.a;
color = t;
}
"#;
type TransformData = [f32; 8];
pub struct Text {
program: Program,
vertex_array: VertexArray,
model_buffer: Buffer, texture_buffer: TextureBuffer, transform_buffer: Buffer, transform_data: Vec<TransformData>,
image_data: Image,
state: ObjectState,
}
impl Text {
pub fn new(image: &Image) -> Result<Self, String> {
let text = Self {
program: Program::default(),
vertex_array: VertexArray::default(),
model_buffer: Buffer::default(),
texture_buffer: TextureBuffer::default(),
transform_buffer: Buffer::default(),
transform_data: vec![],
image_data: image.clone(),
state: ObjectState::Ok,
};
Ok(text)
}
}
impl Object for Text {
fn add(&mut self, object_data: &ObjectData) {
let (x_offset, y_offset) = object_data.offset;
let (width, height) = object_data.dim;
let color = object_data.color;
let opacity = object_data.opacity;
let transform_data: TransformData = [
x_offset, y_offset, width, height, color.r, color.g, color.b, opacity
];
self.transform_data.push(transform_data);
}
fn set(&mut self, i: usize, object_data: &ObjectData) {
let (x_offset, y_offset) = object_data.offset;
let (width, height) = object_data.dim;
let color = object_data.color;
let opacity = object_data.opacity;
let transform_data: TransformData = [
x_offset, y_offset, width, height, color.r, color.g, color.b, opacity
];
self.transform_data[i] = transform_data;
}
fn remove(&mut self, i: usize) {
self.transform_data.remove(i);
}
fn remove_all(&mut self) {
self.transform_data = vec![];
}
fn load(&mut self) -> Result<(), String> {
let model_data: [f32; 4*4] = [
1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, ];
let transform_data = self.transform_data.concat();
unsafe {
let vertex_shader = Shader::new(VERTEX_SHADER_SOURCE, gl::VERTEX_SHADER)?;
let fragment_shader = Shader::new(FRAGMENT_SHADER_SOURCE, gl::FRAGMENT_SHADER)?;
self.program = Program::new(&vertex_shader, &fragment_shader)?;
self.vertex_array = VertexArray::new();
self.vertex_array.bind();
self.model_buffer = Buffer::new(gl::ARRAY_BUFFER, gl::STATIC_DRAW);
self.model_buffer.set_data(&model_data.to_vec());
gl::VertexAttribPointer(0, 2, gl::FLOAT, gl::FALSE, 16, 0 as *const _); gl::VertexAttribPointer(1, 2, gl::FLOAT, gl::FALSE, 16, 8 as *const _); gl::EnableVertexAttribArray(0);
gl::EnableVertexAttribArray(1);
self.texture_buffer = TextureBuffer::new();
self.texture_buffer.set_data(&self.image_data.to_rgba_image());
self.transform_buffer = Buffer::new(gl::ARRAY_BUFFER, gl::DYNAMIC_DRAW);
self.transform_buffer.set_data(&transform_data);
gl::VertexAttribPointer(2, 2, gl::FLOAT, gl::FALSE, 32, 0 as *const _); gl::VertexAttribPointer(3, 2, gl::FLOAT, gl::FALSE, 32, 8 as *const _); gl::VertexAttribPointer(4, 4, gl::FLOAT, gl::FALSE, 32, 16 as *const _); gl::VertexAttribDivisor(2, 1);
gl::VertexAttribDivisor(3, 1);
gl::VertexAttribDivisor(4, 1);
gl::EnableVertexAttribArray(2);
gl::EnableVertexAttribArray(3);
gl::EnableVertexAttribArray(4);
}
self.state = ObjectState::Ok;
Ok(())
}
fn reload(&mut self) {
let transform_data = self.transform_data.concat();
self.transform_buffer.set_data(&transform_data);
self.state = ObjectState::Ok;
}
fn draw(&mut self, draw: &Draw, camera: &Transform, model_transform: &Transform) -> Result<(), String> {
match self.state {
ObjectState::Reload => self.reload(),
ObjectState::Ok => (),
}
let projection = mvp::ortho(&draw.window);
let view = camera.matrix();
let model = model_transform.matrix();
unsafe {
self.program.bind();
self.vertex_array.bind();
self.texture_buffer.bind();
let projection_location = self.program.get_uniform_location("projection")?;
let view_location = self.program.get_uniform_location("view")?;
let model_location = self.program.get_uniform_location("model")?;
gl::UniformMatrix4fv(projection_location, 1, gl::FALSE, projection.as_ptr());
gl::UniformMatrix4fv(view_location, 1, gl::FALSE, view.as_ptr());
gl::UniformMatrix4fv(model_location, 1, gl::FALSE, model.as_ptr());
gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, self.transform_data.len() as i32);
}
Ok(())
}
fn set_state(&mut self, object_state: ObjectState) {
self.state = object_state;
}
}