Browse Source

Implemented textures

raster
Bergmann89 4 years ago
parent
commit
354c303ed3
11 changed files with 1000 additions and 14 deletions
  1. +32
    -2
      Cargo.lock
  2. +1
    -0
      glc/Cargo.toml
  3. +16
    -0
      glc/src/error.rs
  4. +1
    -0
      glc/src/lib.rs
  5. +3
    -3
      glc/src/shader.rs
  6. +914
    -0
      glc/src/texture.rs
  7. +4
    -2
      space-crush/resources/shader/quad.frag
  8. +2
    -2
      space-crush/resources/shader/quad.vert
  9. BIN
     
  10. +17
    -3
      space-crush/src/app/misc/mod.rs
  11. +10
    -2
      space-crush/src/app/render/test.rs

+ 32
- 2
Cargo.lock View File

@@ -442,6 +442,16 @@ dependencies = [
"termcolor",
]

[[package]]
name = "flate2"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6234dd4468ae5d1e2dbb06fe2b058696fdc50a339c68a393aefbf00bc81e423"
dependencies = [
"libc",
"miniz-sys",
]

[[package]]
name = "flate2"
version = "1.0.14"
@@ -623,6 +633,7 @@ name = "glc"
version = "0.1.0"
dependencies = [
"gl",
"imagefmt",
"thiserror",
]

@@ -739,6 +750,15 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"

[[package]]
name = "imagefmt"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ccf4a97bdaf8e465ee22c8583834000188c3f44fd3b6b3d15f858cbaf2b362f"
dependencies = [
"flate2 0.2.20",
]

[[package]]
name = "instant"
version = "0.1.9"
@@ -865,6 +885,16 @@ dependencies = [
"autocfg",
]

[[package]]
name = "miniz-sys"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e9e3ae51cea1576ceba0dde3d484d30e6e5b86dee0b2d412fe3a16a15c98202"
dependencies = [
"cc",
"libc",
]

[[package]]
name = "miniz_oxide"
version = "0.3.7"
@@ -1547,7 +1577,7 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d68a369614cd12ca384ca6e75ab0a5ac3a5acbfe8003622e20808a322b9bb652"
dependencies = [
"flate2",
"flate2 1.0.14",
"vfs",
"zip",
]
@@ -1778,6 +1808,6 @@ dependencies = [
"byteorder",
"bzip2",
"crc32fast",
"flate2",
"flate2 1.0.14",
"thiserror",
]

+ 1
- 0
glc/Cargo.toml View File

@@ -6,4 +6,5 @@ edition = "2018"

[dependencies]
gl = { version = "0.1", features = [ "generate_global" ] }
imagefmt = "4.0"
thiserror = "1.0"

+ 16
- 0
glc/src/error.rs View File

@@ -1,6 +1,7 @@
use std::io::Error as IoError;
use std::str::Utf8Error;

use imagefmt::Error as ImageFmtError;
use thiserror::Error;

#[derive(Debug, Error)]
@@ -11,6 +12,9 @@ pub enum Error {
#[error("UTF-8 Error: {0}")]
Utf8Error(Utf8Error),

#[error("Image Format Error: {0}")]
ImageFmtError(ImageFmtError),

#[error("OpenGL Error: {0}")]
GlError(gl::GLenum),

@@ -25,6 +29,12 @@ pub enum Error {

#[error("Invalid Parameter!")]
InvalidParameter,

#[error("Texture Buffer is to small!")]
TextureBufferOverflow,

#[error("Texture Unsupported Format!")]
TextureUnsupportedFormat,
}

impl Error {
@@ -65,3 +75,9 @@ impl From<Utf8Error> for Error {
Self::Utf8Error(err)
}
}

impl From<ImageFmtError> for Error {
fn from(err: ImageFmtError) -> Self {
Self::ImageFmtError(err)
}
}

+ 1
- 0
glc/src/lib.rs View File

@@ -3,5 +3,6 @@ pub mod error;
pub mod matrix;
pub mod misc;
pub mod shader;
pub mod texture;
pub mod vector;
pub mod vertex_array;

+ 3
- 3
glc/src/shader.rs View File

@@ -142,7 +142,7 @@ impl Shader {
Ok(Self { id })
}

pub fn from_reader<R>(type_: Type, mut reader: R) -> Result<Self, Error>
pub fn from_reader<R>(type_: Type, reader: &mut R) -> Result<Self, Error>
where
R: Read,
{
@@ -156,9 +156,9 @@ impl Shader {
where
P: AsRef<Path>,
{
let source = File::open(&path)?;
let mut file = File::open(&path)?;

match Self::from_reader(type_, source) {
match Self::from_reader(type_, &mut file) {
Ok(v) => Ok(v),
Err(Error::ShaderCompile { code, error }) => Err(Error::ShaderCompile {
code: format!("{}\n{}", path.as_ref().display(), code),


+ 914
- 0
glc/src/texture.rs View File

@@ -0,0 +1,914 @@
use std::fs::File;
use std::io::{Read, Seek};
use std::path::Path;

use imagefmt::{read_from, ColFmt, Error as ImageFmtError};

use crate::{
error::Error,
misc::{AsEnum, BindGuard, Bindable},
};

/* Texture */

pub struct Texture {
id: gl::GLuint,
target: Target,
filter_min: FilterMin,
filter_mag: FilterMag,
wrap_s: Wrap,
wrap_t: Wrap,
wrap_r: Wrap,
}

impl Texture {
pub fn new(target: Target) -> Result<Self, Error> {
let mut id = 0;

Error::checked(|| gl::create_textures(target.as_enum(), 1, &mut id))?;

Ok(Self {
id,
target,
filter_min: FilterMin::Nearest,
filter_mag: FilterMag::Nearest,
wrap_s: Wrap::Repeat,
wrap_t: Wrap::Repeat,
wrap_r: Wrap::Repeat,
})
}

pub fn upload(&mut self, data: &Data, generate_mipmap: bool) -> Result<(), Error> {
let info = data.format.info();

if info.gl_format == 0 || info.gl_format_data == 0 || info.gl_format_internal == 0 {
return Err(Error::TextureUnsupportedFormat);
}

let target = self.target.as_enum();
let _guard = BindGuard::new(&*self);

Error::checked(|| {
gl::tex_image_2d(
target,
0,
info.gl_format_internal as gl::GLint,
data.width as gl::GLint,
data.height as gl::GLint,
0,
info.gl_format,
info.gl_format_data,
data.buffer.as_ptr() as *const _,
)
})?;

if generate_mipmap {
Error::checked(|| gl::generate_mipmap(target))?;
}

self.setup()
}

pub fn set_filter(&mut self, min: FilterMin, mag: FilterMag) -> Result<(), Error> {
self.filter_min = min;
self.filter_mag = mag;

self.setup()
}

pub fn set_wrap(&mut self, s: Wrap, t: Wrap, r: Wrap) -> Result<(), Error> {
self.wrap_s = s;
self.wrap_t = t;
self.wrap_r = r;

self.setup()
}

fn setup(&self) -> Result<(), Error> {
Error::checked(|| {
gl::texture_parameter_i(
self.id,
gl::TEXTURE_MIN_FILTER,
self.filter_min.as_enum() as gl::GLint,
)
})?;
Error::checked(|| {
gl::texture_parameter_i(
self.id,
gl::TEXTURE_MAG_FILTER,
self.filter_mag.as_enum() as gl::GLint,
)
})?;
Error::checked(|| {
gl::texture_parameter_i(
self.id,
gl::TEXTURE_WRAP_S,
self.wrap_s.as_enum() as gl::GLint,
)
})?;
Error::checked(|| {
gl::texture_parameter_i(
self.id,
gl::TEXTURE_WRAP_T,
self.wrap_t.as_enum() as gl::GLint,
)
})?;
Error::checked(|| {
gl::texture_parameter_i(
self.id,
gl::TEXTURE_WRAP_R,
self.wrap_r.as_enum() as gl::GLint,
)
})?;

Ok(())
}
}

impl Bindable for Texture {
fn bind(&self) {
gl::bind_texture(self.target.as_enum(), self.id);
}

fn unbind(&self) {
gl::bind_texture(self.target.as_enum(), 0);
}
}

/* Data */

#[derive(Clone, Debug)]
pub struct Data {
width: usize,
height: usize,
format: Format,
buffer: Vec<u8>,
}

impl Data {
pub fn from_parts(width: usize, height: usize, format: Format, buffer: Vec<u8>) -> Self {
Self {
width,
height,
format,
buffer,
}
}

pub fn from_reader<R>(reader: &mut R) -> Result<Self, Error>
where
R: Read + Seek,
{
let image = read_from(reader, ColFmt::Auto)?;

Ok(Self {
width: image.w,
height: image.h,
format: match image.fmt {
ColFmt::Y => Format::Luminance8ub1,
ColFmt::YA => Format::Luminance8Alpha8ub2,
ColFmt::AY => Format::Alpha8Luminance8ub2,
ColFmt::RGB => Format::RGB8ub3,
ColFmt::RGBA => Format::RGBA8ub4,
ColFmt::BGR => Format::BGR8ub3,
ColFmt::BGRA => Format::BGRA8ub4,
ColFmt::ARGB => Format::ARGB8ub4,
ColFmt::ABGR => Format::ABGR8ub4,
ColFmt::Auto => {
return Err(ImageFmtError::Internal("Unexpected Format: Auto").into())
}
},
buffer: image.buf,
})
}

pub fn from_file<P>(path: P) -> Result<Self, Error>
where
P: AsRef<Path>,
{
let mut file = File::open(path)?;

Self::from_reader(&mut file)
}

pub fn format(&self) -> Format {
self.format
}

pub fn width(&self) -> usize {
self.width
}

pub fn height(&self) -> usize {
self.height
}

pub fn convert<F>(&mut self, format: Format, func: F) -> Result<(), Error>
where
F: Fn(usize, usize, &mut PixelData),
{
let dst_info = format.info();

let mut dst_descriptor = format.descriptor();
let mut src_descriptor = self.format.descriptor();

let mut tmp = Vec::with_capacity(self.width * self.height * dst_info.bits_per_pixel / 8);

let mut src = self.buffer.as_slice();
let mut dst = tmp.as_mut_slice();
let mut data = PixelData::default();

for x in 0..self.width {
for y in 0..self.height {
let b = src_descriptor.unmap(&mut data, src)?;
src = &src[b..];

func(x, y, &mut data);

let b = dst_descriptor.map(&data, dst)?;
dst = &mut dst[b..];
}
}

self.buffer = tmp;

Ok(())
}

pub fn convert_to(&mut self, format: Format) -> Result<(), Error> {
if format == self.format {
return Ok(());
}

if self.format.is_bit_equal(&format) {
self.format = format;

return Ok(());
}

let dst_info = format.info();
let src_info = self.format.info();

if src_info.same_size_channels(&dst_info) {
self.convert(format, |_, _, _| {})
} else {
self.convert(format, |_, _, data| {
data.r = data.r.map(|x| x * dst_info.r_max / src_info.r_max);
data.g = data.g.map(|x| x * dst_info.g_max / src_info.g_max);
data.b = data.b.map(|x| x * dst_info.b_max / src_info.b_max);
data.a = data.a.map(|x| x * dst_info.a_max / src_info.a_max);
})
}
}
}

/* FormatDescriptor */

pub trait FormatDescriptor {
fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result<usize, Error>;
fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result<usize, Error>;
}

struct Luminance8ub1Descriptor;

impl FormatDescriptor for Luminance8ub1Descriptor {
fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result<usize, Error> {
check_len(&buf, 1)?;

if data.has_rgb() {
buf[0] = data.luminance() as u8;
} else {
buf[0] = data.a.unwrap_or(0) as u8;
}

Ok(1)
}

fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result<usize, Error> {
check_len(&buf, 1)?;

data.r = Some(buf[0] as u32);
data.g = Some(buf[0] as u32);
data.b = Some(buf[0] as u32);
data.a = None;

Ok(1)
}
}

struct Luminance8Alpha8ub2Descriptor;

impl FormatDescriptor for Luminance8Alpha8ub2Descriptor {
fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result<usize, Error> {
check_len(&buf, 2)?;

buf[0] = data.luminance() as u8;
buf[1] = data.a.unwrap_or(255) as u8;

Ok(2)
}

fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result<usize, Error> {
check_len(&buf, 2)?;

data.r = Some(buf[0] as u32);
data.g = Some(buf[0] as u32);
data.b = Some(buf[0] as u32);
data.a = Some(buf[1] as u32);

Ok(2)
}
}

struct Alpha8Luminance8ub2Descriptor;

impl FormatDescriptor for Alpha8Luminance8ub2Descriptor {
fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result<usize, Error> {
check_len(&buf, 2)?;

buf[0] = data.a.unwrap_or(255) as u8;
buf[1] = data.luminance() as u8;

Ok(2)
}

fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result<usize, Error> {
check_len(&buf, 2)?;

data.r = Some(buf[1] as u32);
data.g = Some(buf[1] as u32);
data.b = Some(buf[1] as u32);
data.a = Some(buf[0] as u32);

Ok(2)
}
}

struct RGB8ub3Descriptor;

impl FormatDescriptor for RGB8ub3Descriptor {
fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result<usize, Error> {
check_len(&buf, 3)?;

buf[0] = data.r.unwrap_or(0) as u8;
buf[1] = data.g.unwrap_or(0) as u8;
buf[2] = data.b.unwrap_or(0) as u8;

Ok(3)
}

fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result<usize, Error> {
check_len(&buf, 3)?;

data.r = Some(buf[0] as u32);
data.g = Some(buf[1] as u32);
data.b = Some(buf[2] as u32);
data.a = None;

Ok(3)
}
}

struct RGBA8ub4Descriptor;

impl FormatDescriptor for RGBA8ub4Descriptor {
fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result<usize, Error> {
check_len(&buf, 4)?;

buf[0] = data.r.unwrap_or(0) as u8;
buf[1] = data.g.unwrap_or(0) as u8;
buf[2] = data.b.unwrap_or(0) as u8;
buf[3] = data.a.unwrap_or(0) as u8;

Ok(4)
}

fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result<usize, Error> {
check_len(&buf, 4)?;

data.r = Some(buf[0] as u32);
data.g = Some(buf[1] as u32);
data.b = Some(buf[2] as u32);
data.a = Some(buf[3] as u32);

Ok(4)
}
}

struct ARGB8ub4Descriptor;

impl FormatDescriptor for ARGB8ub4Descriptor {
fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result<usize, Error> {
check_len(&buf, 4)?;

buf[0] = data.a.unwrap_or(0) as u8;
buf[1] = data.r.unwrap_or(0) as u8;
buf[2] = data.g.unwrap_or(0) as u8;
buf[3] = data.b.unwrap_or(0) as u8;

Ok(4)
}

fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result<usize, Error> {
check_len(&buf, 4)?;

data.a = Some(buf[0] as u32);
data.r = Some(buf[1] as u32);
data.g = Some(buf[2] as u32);
data.b = Some(buf[3] as u32);

Ok(4)
}
}

struct BGR8ub3Descriptor;

impl FormatDescriptor for BGR8ub3Descriptor {
fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result<usize, Error> {
check_len(&buf, 3)?;

buf[0] = data.b.unwrap_or(0) as u8;
buf[1] = data.g.unwrap_or(0) as u8;
buf[2] = data.r.unwrap_or(0) as u8;

Ok(3)
}

fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result<usize, Error> {
check_len(&buf, 3)?;

data.b = Some(buf[1] as u32);
data.g = Some(buf[2] as u32);
data.r = Some(buf[3] as u32);
data.a = None;

Ok(3)
}
}

struct BGRA8ub4Descriptor;

impl FormatDescriptor for BGRA8ub4Descriptor {
fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result<usize, Error> {
check_len(&buf, 4)?;

buf[0] = data.b.unwrap_or(0) as u8;
buf[1] = data.g.unwrap_or(0) as u8;
buf[2] = data.r.unwrap_or(0) as u8;
buf[3] = data.a.unwrap_or(0) as u8;

Ok(4)
}

fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result<usize, Error> {
check_len(&buf, 4)?;

data.b = Some(buf[0] as u32);
data.g = Some(buf[1] as u32);
data.r = Some(buf[2] as u32);
data.a = Some(buf[3] as u32);

Ok(4)
}
}

struct ABGR8ub4Descriptor;

impl FormatDescriptor for ABGR8ub4Descriptor {
fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result<usize, Error> {
check_len(&buf, 4)?;

buf[0] = data.a.unwrap_or(0) as u8;
buf[1] = data.b.unwrap_or(0) as u8;
buf[2] = data.g.unwrap_or(0) as u8;
buf[3] = data.r.unwrap_or(0) as u8;

Ok(4)
}

fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result<usize, Error> {
check_len(&buf, 4)?;

data.a = Some(buf[0] as u32);
data.b = Some(buf[1] as u32);
data.g = Some(buf[2] as u32);
data.r = Some(buf[3] as u32);

Ok(4)
}
}

fn check_len(buf: &[u8], len: usize) -> Result<(), Error> {
if buf.len() < len {
Err(Error::TextureBufferOverflow)
} else {
Ok(())
}
}

/* PixelData */

#[derive(Default)]
pub struct PixelData {
pub r: Option<u32>,
pub g: Option<u32>,
pub b: Option<u32>,
pub a: Option<u32>,
}

impl PixelData {
pub fn has_rgb(&self) -> bool {
self.r.is_some() && self.g.is_some() && self.b.is_some()
}

pub fn luminance(&self) -> u32 {
(LUMINANCE_WEIGHT_R * self.r.unwrap_or(0) as f32
+ LUMINANCE_WEIGHT_G * self.g.unwrap_or(0) as f32
+ LUMINANCE_WEIGHT_B * self.b.unwrap_or(0) as f32) as u32
}
}

const LUMINANCE_WEIGHT_R: f32 = 0.30;
const LUMINANCE_WEIGHT_G: f32 = 0.59;
const LUMINANCE_WEIGHT_B: f32 = 0.11;

/* FormatInfo */

pub struct FormatInfo {
pub gl_format: gl::GLenum,
pub gl_format_data: gl::GLenum,
pub gl_format_internal: gl::GLenum,

pub format_gl_support: Format,
pub format_with_alpha: Format,
pub format_without_alpha: Format,

pub bits_per_pixel: usize,

pub r_max: u32,
pub g_max: u32,
pub b_max: u32,
pub a_max: u32,

pub r_bits: u32,
pub g_bits: u32,
pub b_bits: u32,
pub a_bits: u32,
}

impl FormatInfo {
pub fn same_size_channels(&self, other: &Self) -> bool {
(self.r_bits == other.r_bits || self.r_bits == 0 || other.r_bits == 0)
&& (self.g_bits == other.g_bits || self.g_bits == 0 || other.g_bits == 0)
&& (self.b_bits == other.b_bits || self.b_bits == 0 || other.b_bits == 0)
&& (self.a_bits == other.a_bits || self.a_bits == 0 || other.a_bits == 0)
}
}

static INFO_LUMINANCE8_UB1: FormatInfo = FormatInfo {
gl_format: gl::LUMINANCE,
gl_format_data: gl::UNSIGNED_BYTE,
gl_format_internal: gl::LUMINANCE8,
format_gl_support: Format::Luminance8ub1,
format_with_alpha: Format::Luminance8Alpha8ub2,
format_without_alpha: Format::Luminance8ub1,
bits_per_pixel: 8,
r_max: 255,
g_max: 255,
b_max: 255,
a_max: 0,
r_bits: 8,
g_bits: 8,
b_bits: 8,
a_bits: 0,
};
static INFO_LUMINANCE8_ALPHA8_UB2: FormatInfo = FormatInfo {
gl_format: gl::LUMINANCE_ALPHA,
gl_format_data: gl::UNSIGNED_BYTE,
gl_format_internal: gl::LUMINANCE8_ALPHA8,
format_gl_support: Format::Luminance8Alpha8ub2,
format_with_alpha: Format::Luminance8Alpha8ub2,
format_without_alpha: Format::Luminance8ub1,
bits_per_pixel: 16,
r_max: 255,
g_max: 255,
b_max: 255,
a_max: 255,
r_bits: 8,
g_bits: 8,
b_bits: 8,
a_bits: 8,
};
static INFO_ALPHA8_LUMINANCE8_UB2: FormatInfo = FormatInfo {
gl_format: gl::LUMINANCE_ALPHA,
gl_format_data: gl::UNSIGNED_BYTE,
gl_format_internal: gl::LUMINANCE8_ALPHA8,
format_gl_support: Format::Luminance8Alpha8ub2,
format_with_alpha: Format::Alpha8Luminance8ub2,
format_without_alpha: Format::Luminance8ub1,
bits_per_pixel: 16,
r_max: 255,
g_max: 255,
b_max: 255,
a_max: 255,
r_bits: 8,
g_bits: 8,
b_bits: 8,
a_bits: 8,
};
static INFO_RGB8_UB3: FormatInfo = FormatInfo {
gl_format: gl::RGB,
gl_format_data: gl::UNSIGNED_BYTE,
gl_format_internal: gl::RGB8,
format_gl_support: Format::RGB8ub3,
format_with_alpha: Format::RGBA8ub4,
format_without_alpha: Format::RGB8ub3,
bits_per_pixel: 24,
r_max: 255,
g_max: 255,
b_max: 255,
a_max: 0,
r_bits: 8,
g_bits: 8,
b_bits: 8,
a_bits: 0,
};
static INFO_RGBA8_UB4: FormatInfo = FormatInfo {
gl_format: gl::RGBA,
gl_format_data: gl::UNSIGNED_BYTE,
gl_format_internal: gl::RGBA8,
format_gl_support: Format::RGBA8ub4,
format_with_alpha: Format::RGBA8ub4,
format_without_alpha: Format::RGB8ub3,
bits_per_pixel: 32,
r_max: 255,
g_max: 255,
b_max: 255,
a_max: 255,
r_bits: 8,
g_bits: 8,
b_bits: 8,
a_bits: 8,
};
static INFO_ARGB8_UB4: FormatInfo = FormatInfo {
gl_format: gl::RGBA,
gl_format_data: gl::UNSIGNED_INT_8_8_8_8_REV,
gl_format_internal: gl::RGBA8,
format_gl_support: Format::ARGB8ub4,
format_with_alpha: Format::ARGB8ub4,
format_without_alpha: Format::RGB8ub3,
bits_per_pixel: 32,
r_max: 255,
g_max: 255,
b_max: 255,
a_max: 255,
r_bits: 8,
g_bits: 8,
b_bits: 8,
a_bits: 8,
};
static INFO_BGR8_UB3: FormatInfo = FormatInfo {
gl_format: gl::BGR,
gl_format_data: gl::UNSIGNED_BYTE,
gl_format_internal: gl::RGB8,
format_gl_support: Format::BGR8ub3,
format_with_alpha: Format::BGRA8ub4,
format_without_alpha: Format::BGR8ub3,
bits_per_pixel: 24,
r_max: 255,
g_max: 255,
b_max: 255,
a_max: 0,
r_bits: 8,
g_bits: 8,
b_bits: 8,
a_bits: 0,
};
static INFO_BGRA8_UB4: FormatInfo = FormatInfo {
gl_format: gl::BGR,
gl_format_data: gl::UNSIGNED_BYTE,
gl_format_internal: gl::RGBA8,
format_gl_support: Format::BGRA8ub4,
format_with_alpha: Format::BGRA8ub4,
format_without_alpha: Format::BGR8ub3,
bits_per_pixel: 32,
r_max: 255,
g_max: 255,
b_max: 255,
a_max: 255,
r_bits: 8,
g_bits: 8,
b_bits: 8,
a_bits: 8,
};
static INFO_ABGR8_UB4: FormatInfo = FormatInfo {
gl_format: gl::BGR,
gl_format_data: gl::UNSIGNED_INT_8_8_8_8_REV,
gl_format_internal: gl::RGBA8,
format_gl_support: Format::ABGR8ub4,
format_with_alpha: Format::ABGR8ub4,
format_without_alpha: Format::BGR8ub3,
bits_per_pixel: 32,
r_max: 255,
g_max: 255,
b_max: 255,
a_max: 255,
r_bits: 8,
g_bits: 8,
b_bits: 8,
a_bits: 8,
};

/* Format */

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Format {
/// [LLLL_LLLL]
Luminance8ub1,
/// [LLLL_LLLL][AAAA_AAAA]
Luminance8Alpha8ub2,
/// [AAAA_AAAA][LLLL_LLLL]
Alpha8Luminance8ub2,

/// [RRRR_RRRR][GGGG_GGGG][BBBB_BBBB]
RGB8ub3,
/// [RRRR_RRRR][GGGG_GGGG][BBBB_BBBB][AAAA_AAAA]
RGBA8ub4,
/// [AAAA_AAAA][RRRR_RRRR][GGGG_GGGG][BBBB_BBBB]
ARGB8ub4,

/// [BBBB_BBBB][GGGG_GGGG][RRRR_RRRR]
BGR8ub3,
/// [BBBB_BBBB][GGGG_GGGG][RRRR_RRRR][AAAA_AAAA]
BGRA8ub4,
/// [AAAA_AAAA][BBBB_BBBB][GGGG_GGGG][RRRR_RRRR]
ABGR8ub4,
}

impl Format {
pub fn info(&self) -> &'static FormatInfo {
match self {
Format::Luminance8ub1 => &INFO_LUMINANCE8_UB1,
Format::Luminance8Alpha8ub2 => &INFO_LUMINANCE8_ALPHA8_UB2,
Format::Alpha8Luminance8ub2 => &INFO_ALPHA8_LUMINANCE8_UB2,
Format::RGB8ub3 => &INFO_RGB8_UB3,
Format::RGBA8ub4 => &INFO_RGBA8_UB4,
Format::ARGB8ub4 => &INFO_ARGB8_UB4,
Format::BGR8ub3 => &INFO_BGR8_UB3,
Format::BGRA8ub4 => &INFO_BGRA8_UB4,
Format::ABGR8ub4 => &INFO_ABGR8_UB4,
}
}

pub fn descriptor(&self) -> Box<dyn FormatDescriptor> {
match self {
Format::Luminance8ub1 => Box::new(Luminance8ub1Descriptor),
Format::Luminance8Alpha8ub2 => Box::new(Luminance8Alpha8ub2Descriptor),
Format::Alpha8Luminance8ub2 => Box::new(Alpha8Luminance8ub2Descriptor),
Format::RGB8ub3 => Box::new(RGB8ub3Descriptor),
Format::RGBA8ub4 => Box::new(RGBA8ub4Descriptor),
Format::ARGB8ub4 => Box::new(ARGB8ub4Descriptor),
Format::BGR8ub3 => Box::new(BGR8ub3Descriptor),
Format::BGRA8ub4 => Box::new(BGRA8ub4Descriptor),
Format::ABGR8ub4 => Box::new(ABGR8ub4Descriptor),
}
}

pub fn is_bit_equal(&self, _other: &Self) -> bool {
false
}
}

/* Target */

pub enum Target {
Texture1D,
Texture2D,
Texture3D,
Texture1DArray,
Texture2DArray,
TextureRectangle,
TextureCubeMap,
TextureCubeMapArray,
TextureBuffer,
Texture2DMultisample,
Texture2DMultisampleArray,
}

impl AsEnum for Target {
fn as_enum(&self) -> gl::GLenum {
match self {
Self::Texture1D => gl::TEXTURE_1D,
Self::Texture2D => gl::TEXTURE_2D,
Self::Texture3D => gl::TEXTURE_3D,
Self::Texture1DArray => gl::TEXTURE_1D_ARRAY,
Self::Texture2DArray => gl::TEXTURE_2D_ARRAY,
Self::TextureRectangle => gl::TEXTURE_RECTANGLE,
Self::TextureCubeMap => gl::TEXTURE_CUBE_MAP,
Self::TextureCubeMapArray => gl::TEXTURE_CUBE_MAP_ARRAY,
Self::TextureBuffer => gl::TEXTURE_BUFFER,
Self::Texture2DMultisample => gl::TEXTURE_2D_MULTISAMPLE,
Self::Texture2DMultisampleArray => gl::TEXTURE_2D_MULTISAMPLE_ARRAY,
}
}
}

/* FilterMin */

pub enum FilterMin {
/// Returns the value of the texture element that is nearest
/// (in Manhattan distance) to the specified texture coordinates.
Nearest,

/// Returns the weighted average of the four texture elements
/// that are closest to the specified texture coordinates.
/// These can include items wrapped or repeated from other parts
/// of a texture, depending on the values of GL_TEXTURE_WRAP_S
/// and GL_TEXTURE_WRAP_T, and on the exact mapping.
Linear,

/// Chooses the mipmap that most closely matches the size of the
/// pixel being textured and uses the GL_NEAREST criterion (the
/// texture element closest to the specified texture coordinates)
/// to produce a texture value.
NearestMipmapNearest,

/// Chooses the mipmap that most closely matches the size of the pixel
/// being textured and uses the GL_LINEAR criterion (a weighted average
/// of the four texture elements that are closest to the specified
/// texture coordinates) to produce a texture value.
LinearMipmapNearest,

/// Chooses the two mipmaps that most closely match the size of the pixel
/// being textured and uses the GL_NEAREST criterion (the texture element
/// closest to the specified texture coordinates ) to produce a texture
/// value from each mipmap. The final texture value is a weighted average
/// of those two values.
NearestMipmapLinear,

/// Chooses the two mipmaps that most closely match the size of the pixel
/// being textured and uses the GL_LINEAR criterion (a weighted average of
/// the texture elements that are closest to the specified texture coordinates)
/// to produce a texture value from each mipmap. The final texture value
/// is a weighted average of those two values.
LinearMipmapLinear,
}

impl AsEnum for FilterMin {
fn as_enum(&self) -> gl::GLenum {
match self {
Self::Nearest => gl::NEAREST,
Self::Linear => gl::LINEAR,
Self::NearestMipmapNearest => gl::NEAREST_MIPMAP_NEAREST,
Self::LinearMipmapNearest => gl::LINEAR_MIPMAP_NEAREST,
Self::NearestMipmapLinear => gl::NEAREST_MIPMAP_LINEAR,
Self::LinearMipmapLinear => gl::LINEAR_MIPMAP_LINEAR,
}
}
}

/* FilterMag */

pub enum FilterMag {
/// Returns the value of the texture element that is nearest
/// (in Manhattan distance) to the specified texture coordinates.
Nearest,

/// Returns the weighted average of the texture elements that are
/// closest to the specified texture coordinates. These can include
/// items wrapped or repeated from other parts of a texture, depending
/// on the values of GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T, and on
/// the exact mapping.
Linear,
}

impl AsEnum for FilterMag {
fn as_enum(&self) -> gl::GLenum {
match self {
Self::Nearest => gl::NEAREST,
Self::Linear => gl::LINEAR,
}
}
}

/* Wrap */

pub enum Wrap {
ClampToEdge,
ClampToBorder,
MirrorRepeat,
Repeat,
MirrorClampToEdge,
}

impl AsEnum for Wrap {
fn as_enum(&self) -> gl::GLenum {
match self {
Self::ClampToEdge => gl::CLAMP_TO_EDGE,
Self::ClampToBorder => gl::CLAMP_TO_BORDER,
Self::MirrorRepeat => gl::MIRRORED_REPEAT,
Self::Repeat => gl::REPEAT,
Self::MirrorClampToEdge => gl::MIRROR_CLAMP_TO_EDGE,
}
}
}

+ 4
- 2
space-crush/resources/shader/quad.frag View File

@@ -1,11 +1,13 @@
#version 450 core

in FragmentData {
vec3 color;
vec2 tex_coords;
} data;

uniform sampler2D tex;

out vec4 color;

void main() {
color = vec4(data.color, 1.0);
color = texture(tex, data.tex_coords);
}

+ 2
- 2
space-crush/resources/shader/quad.vert View File

@@ -10,10 +10,10 @@ layout (std140, binding = 0) uniform Camera {
layout (location = 1) uniform mat4 model;

out FragmentData {
vec3 color;
vec2 tex_coords;
} data;

void main() {
data.color = vec3((position.xy + vec2(0.5)), 0.0);
data.tex_coords = position.xy + vec2(0.5);
gl_Position = camera.projection * camera.view * model * vec4(position, 1.0);
}

BIN
View File


+ 17
- 3
space-crush/src/app/misc/mod.rs View File

@@ -9,7 +9,10 @@ use std::iter::Iterator;
use std::ops::Deref;

use self::vfs::Vfs;
use glc::shader::{Program, Shader, Type};
use glc::{
shader::{Program, Shader, Type},
texture::{Data, Target, Texture},
};

use crate::Error;

@@ -18,9 +21,20 @@ where
I: IntoIterator<Item = (Type, &'static str)>,
{
Program::from_shaders_result(iter.into_iter().map(|(t, p)| {
let file = vfs.deref().join(p)?.open_file()?;
let shader = Shader::from_reader(t, file)?;
let mut file = vfs.deref().join(p)?.open_file()?;
let shader = Shader::from_reader(t, &mut file)?;

Ok(shader)
}))
}

pub fn load_texture(vfs: &Vfs, path: &str) -> Result<Texture, Error> {
let mut file = vfs.deref().join(path)?.open_file()?;
let mut data = Data::from_reader(&mut file)?;
data.convert_to(data.format().info().format_gl_support)?;

let mut texture = Texture::new(Target::Texture2D)?;
texture.upload(&data, true)?;

Ok(texture)
}

+ 10
- 2
space-crush/src/app/render/test.rs View File

@@ -2,6 +2,7 @@ use glc::{
matrix::{Angle, Matrix4f},
misc::Bindable,
shader::{Program, Type, Uniform},
texture::{FilterMag, FilterMin, Texture},
vector::Vector3f,
};
use specs::{ReadExpect, System, World};
@@ -9,12 +10,13 @@ use specs::{ReadExpect, System, World};
use crate::Error;

use super::{
super::misc::{geometry::Geometry, load_program, vfs::Vfs},
super::misc::{geometry::Geometry, load_program, load_texture, vfs::Vfs},
init::Global,
};

pub struct Test {
program: Program,
texture: Texture,
model: Matrix4f,
}

@@ -29,6 +31,9 @@ impl Test {
],
)?;

let mut texture = load_texture(&vfs, "resources/textures/test.png")?;
texture.set_filter(FilterMin::LinearMipmapLinear, FilterMag::Linear)?;

let global = world.fetch::<Global>();
program.bind();
global.camera.bind(0)?;
@@ -36,7 +41,8 @@ impl Test {

Ok(Self {
program,
model: Matrix4f::scale(Vector3f::new(100.0, 100.0, 100.0)),
texture,
model: Matrix4f::scale(Vector3f::new(500.0, 500.0, 500.0)),
})
}
}
@@ -51,11 +57,13 @@ impl<'a> System<'a> for Test {
Angle::Deg(10.0 * global.frame_counter.delta()),
);

self.texture.bind();
self.program.bind();
self.program.uniform(1, Uniform::Matrix4f(&self.model));

geometry.render_quad();

self.program.unbind();
self.texture.unbind();
}
}

Loading…
Cancel
Save