1use std::cmp::Ordering;
2use std::ffi::CStr;
3use crate::gl;
4
5#[derive(Debug, Copy, Clone, PartialEq, Eq)]
11pub struct Version(pub Api, pub u8, pub u8);
12
13#[derive(Debug, Copy, Clone, PartialEq, Eq)]
15pub enum Api {
16 Gl,
18 GlEs,
20}
21
22impl PartialOrd for Version {
23 #[inline]
24 fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
25 if self.0 != other.0 {
26 return None;
27 }
28
29 match self.1.cmp(&other.1) {
30 Ordering::Equal => Some(self.2.cmp(&other.2)),
31 a => Some(a)
32 }
33 }
34}
35
36pub unsafe fn get_gl_version(gl: &gl::Gl) -> Version {
43 let version = gl.GetString(gl::VERSION);
44 let version = String::from_utf8(CStr::from_ptr(version as *const _).to_bytes().to_vec()).unwrap();
45
46 if version.starts_with("WebGL ") {
49 return Version(Api::GlEs, 2, 0);
50 }
51
52 let (version, api) = if version.starts_with("OpenGL ES ") {
53 (&version[10..], Api::GlEs)
54 } else if version.starts_with("OpenGL ES-") {
55 (&version[13..], Api::GlEs)
56 } else {
57 (&version[..], Api::Gl)
58 };
59
60 let version = version.split(' ').next().expect("glGetString(GL_VERSION) returned an empty \
61 string");
62
63 let mut iter = version.split('.');
64 let major = iter.next().unwrap();
65 let minor = iter.next().expect("glGetString(GL_VERSION) did not return a correct version");
66
67 Version(
68 api,
69 major.parse().ok().expect("failed to parse GL major version"),
70 minor.parse().ok().expect("failed to parse GL minor version"),
71 )
72}
73
74pub fn get_supported_glsl_version(gl_version: &Version) -> Version {
81 match gl_version.0 {
82 Api::Gl => {
83 if *gl_version >= Version(gl_version.0, 3, 3) {
85 return *gl_version;
86 }
87
88 match *gl_version {
90 Version(a, 2, 0) => Version(a, 1, 1),
91 Version(a, 2, 1) => Version(a, 1, 2),
92 Version(a, 3, 0) => Version(a, 1, 3),
93 Version(a, 3, 1) => Version(a, 1, 4),
94 Version(a, 3, 2) => Version(a, 1, 5),
95 _ => panic!("no corresponding glsl version exists")
96 }
97 },
98 Api::GlEs => {
99 if *gl_version >= Version(gl_version.0, 3, 0) {
101 return *gl_version;
102 }
103
104 if *gl_version == Version(gl_version.0, 2, 0){
106 Version(Api::GlEs, 1, 0)
107 } else {
108 panic!("no corresponding glsl version exists")
109 }
110 }
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::{Version, Api, get_supported_glsl_version};
117
118 macro_rules! assert_versions {
119 ( $api:path, $gl_major:expr, $gl_minor:expr => $glsl_major:expr, $glsl_minor:expr) => {
120 assert_eq!(
121 get_supported_glsl_version(&Version($api, $gl_major, $gl_minor)),
122 Version($api, $glsl_major, $glsl_minor)
123 );
124 }
125 }
126
127 #[test]
128 fn valid_gl_versions() {
129 assert_versions!(Api::Gl, 2, 0 => 1, 1);
131 assert_versions!(Api::Gl, 2, 1 => 1, 2);
132 assert_versions!(Api::Gl, 3, 0 => 1, 3);
133 assert_versions!(Api::Gl, 3, 1 => 1, 4);
134 assert_versions!(Api::Gl, 3, 2 => 1, 5);
135
136 assert_versions!(Api::Gl, 3, 3 => 3, 3);
138 assert_versions!(Api::Gl, 4, 0 => 4, 0);
139 assert_versions!(Api::Gl, 4, 5 => 4, 5);
140 }
141
142 #[test]
143 fn valid_gles_versions() {
144 assert_versions!(Api::GlEs, 2, 0 => 1, 0);
146
147 assert_versions!(Api::GlEs, 3, 0 => 3, 0);
149 assert_versions!(Api::GlEs, 3, 1 => 3, 1);
150 }
151
152 #[test]
153 #[should_panic]
154 fn invalid_gl_version() {
155 get_supported_glsl_version(&Version(Api::Gl, 1, 0));
156 }
157
158 #[test]
159 #[should_panic]
160 fn invalid_gles_version() {
161 get_supported_glsl_version(&Version(Api::GlEs, 1, 0));
162 }
163}