1 /**
2 Copyright: Copyright (c) 2017-2018 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 
7 module voxelman.world.mesh.vertex;
8 
9 import voxelman.model.vertex;
10 import voxelman.graphics.gl;
11 import voxelman.graphics.irenderer;
12 import voxelman.graphics.shaderprogram;
13 import voxelman.graphics.shaders;
14 import voxelman.math;
15 import voxelman.graphics.color;
16 
17 //alias MeshVertex = VertexPosUvColor!(float, 3, ubyte, 4);
18 //alias MeshVertex = VertexPosColor!(float, 3, ubyte, 4);
19 //alias MeshVertex = MeshVertex8;
20 alias MeshVertex = MeshVertex16;
21 
22 //alias ChunkShader = ChunkShader8;
23 alias ChunkShader = ChunkShader16;
24 
25 struct MeshVertex16
26 {
27 	vec3 position;
28 	ubyte[2] uv;
29 	ubyte gray;
30 
31 	this(T)(Vector!(T, 3) pos, ubyte[2] uv, ubyte gray) {
32 		set(pos.x, pos.y, pos.z, uv, gray);
33 	}
34 	this(float x, float y, float z, ubyte[2] uv, ubyte gray) {
35 		set(x, y, z, uv, gray);
36 	}
37 
38 	void set(float x, float y, float z, ubyte[2] uv, ubyte gray) {
39 		position.x = x;
40 		position.y = y;
41 		position.z = z;
42 		this.uv = uv;
43 		this.gray = gray;
44 	}
45 
46 	void addOffset(vec3 offset)
47 	{
48 		position += offset;
49 	}
50 
51 	static void setAttributes() {
52 		enum Size = typeof(this).sizeof;
53 		// (int index, int numComponents, AttrT, bool normalize, int totalVertSize, int offset)
54 		setupAttribute!(0, 3, float, false, true, Size, position.offsetof);
55 		setupAttribute!(1, 3, ubyte, false, true, Size, uv.offsetof);
56 	}
57 
58 	void toString()(scope void delegate(const(char)[]) sink) {
59 		import std.format : formattedWrite;
60 		sink.formattedWrite("v(%s, %s, %s)", position, uv, gray);
61 	}
62 }
63 static assert(MeshVertex16.sizeof == 16);
64 
65 struct MeshVertex8
66 {
67 	uint packed_position;
68 	ubyte[2] uv;
69 	ubyte gray;
70 
71 	vec3 position() @property {
72 		return vec3(
73 			(packed_position >>  0) & 1023,
74 			(packed_position >> 10) & 1023,
75 			(packed_position >> 20) & 1023) / 31;
76 	}
77 
78 	this(T)(Vector!(T, 3) pos, ubyte[2] uv, ubyte gray) {
79 		set(cast(int)(pos.x * 31), cast(int)(pos.y * 31), cast(int)(pos.z * 31), uv, gray);
80 	}
81 	this(int x, int y, int z, ubyte[2] uv, ubyte gray) {
82 		set(x * 31, y * 31, z * 31, uv, gray);
83 	}
84 
85 	private void set(int x, int y, int z, ubyte[2] uv, ubyte gray) {
86 		packed_position = ((x & 1023) << 0) | ((y & 1023) << 10) | ((z & 1023) << 20);
87 		this.uv = uv;
88 		this.gray = gray;
89 	}
90 
91 	void addOffset(vec3 offset)
92 	{
93 		uint pos = ((cast(int)(offset.x * 31) & 1023) << 0) | ((cast(int)(offset.y * 31) & 1023) << 10) | ((cast(int)(offset.z * 31) & 1023) << 20);
94 		packed_position += pos;
95 	}
96 
97 	static void setAttributes() {
98 		enum Size = typeof(this).sizeof;
99 		// (int index, int numComponents, AttrT, bool normalize, int totalVertSize, int offset)
100 		glEnableVertexAttribArray(0);
101 		checkgl!glVertexAttribPointer(0, 4, GL_UNSIGNED_INT_2_10_10_10_REV, false, Size, cast(void*)packed_position.offsetof);
102 		setupAttribute!(1, 3, ubyte, false, true, Size, uv.offsetof);
103 		//setupAttribute!(2, 1, ubyte, true, true, Size, gray.offsetof);
104 	}
105 
106 	void toString()(scope void delegate(const(char)[]) sink) {
107 		import std.format : formattedWrite;
108 		sink.formattedWrite("v(%s, %s, %s)", position, uv, gray);
109 	}
110 
111 	/*
112 	this(T)(Vector!(T, 3) pos, ubvec3 color) { set(cast(int)(pos.x * 31), cast(int)(pos.y * 31), cast(int)(pos.z * 31), color.arrayof); }
113 	this(T)(Vector!(T, 3) pos, ubyte[3] color) {set(cast(int)(pos.x * 31), cast(int)(pos.y * 31), cast(int)(pos.z * 31), color); }
114 	this(int x, int y, int z, ubyte[3] color) {set(x * 31, y * 31, z * 31, color); }
115 
116 	void set(int x, int y, int z, ubyte[3] color) {
117 		packed_position = ((x & 1023) << 0) | ((y & 1023) << 10) | ((z & 1023) << 20) | 0b01_00000_00000_00000_00000_00000_00000;
118 		this.color = color;
119 	}
120 
121 	static void setAttributes() {
122 		enum Size = typeof(this).sizeof;
123 		// (int index, int numComponents, AttrT, bool normalize, int totalVertSize, int offset)
124 		glEnableVertexAttribArray(0);
125 		checkgl!glVertexAttribPointer(0, 4, GL_UNSIGNED_INT_2_10_10_10_REV, false, Size, cast(void*)packed_position.offsetof);
126 		setupAttribute!(1, 3, ubyte, true, true, Size, color.offsetof);
127 	}
128 	*/
129 }
130 static assert(MeshVertex8.sizeof == 8);
131 
132 string chunk_vert_shader8 = `
133 #version 330
134 
135 layout(location = 0) in vec3 packed_position;
136 layout(location = 1) in vec3 uv_shade;
137 
138 uniform sampler2D atlas_uniform;
139 uniform mat4 mvp;
140 
141 smooth out float frag_shade;
142 out vec2 frag_uv;
143 
144 void main() {
145 	gl_Position = mvp * vec4(packed_position/31, 1);
146 	frag_uv = uv_shade.xy*32 / textureSize(atlas_uniform, 0);
147 	frag_shade = uv_shade.z / 255;
148 }
149 `;
150 
151 string chunk_frag_shader8 = `
152 #version 330
153 
154 smooth in float frag_shade;
155 in vec2 frag_uv;
156 
157 uniform sampler2D atlas_uniform;
158 uniform float transparency;
159 
160 out vec4 out_color;
161 
162 void main() {
163 	vec3 color = vec3(frag_shade * texture(atlas_uniform, frag_uv));
164 	out_color = vec4(color, transparency);
165 }
166 `;
167 
168 struct ChunkShader8
169 {
170 	ShaderProgram shader;
171 	alias shader this;
172 
173 	GLint transparency_location = -1;
174 	GLint mvp_location = -1;
175 
176 	void setMvp(Matrix4f mvp) { checkgl!glUniformMatrix4fv(mvp_location, 1, GL_FALSE, mvp.arrayof.ptr); }
177 	void setTransparency(float transparency) { checkgl!glUniform1f(transparency_location, transparency); }
178 
179 	void compile(IRenderer renderer) {
180 		shader = renderer.createShaderProgram(chunk_vert_shader8, chunk_frag_shader8);
181 
182 		transparency_location = checkgl!glGetUniformLocation(handle, "transparency");
183 		mvp_location = checkgl!glGetUniformLocation(handle, "mvp");
184 	}
185 }
186 
187 string chunk_vert_shader16 = `
188 #version 330
189 
190 layout(location = 0) in vec3 packed_position;
191 layout(location = 1) in vec3 uv_shade;
192 
193 uniform sampler2D atlas_uniform;
194 uniform mat4 mvp;
195 
196 smooth out float frag_shade;
197 out vec2 frag_uv;
198 
199 void main() {
200 	gl_Position = mvp * vec4(packed_position, 1);
201 	frag_uv = uv_shade.xy*32 / textureSize(atlas_uniform, 0);
202 	frag_shade = uv_shade.z / 255;
203 }
204 `;
205 
206 struct ChunkShader16
207 {
208 	ShaderProgram shader;
209 	alias shader this;
210 
211 	GLint transparency_location = -1;
212 	GLint mvp_location = -1;
213 
214 	void setMvp(Matrix4f mvp) { checkgl!glUniformMatrix4fv(mvp_location, 1, GL_FALSE, mvp.arrayof.ptr); }
215 	void setTransparency(float transparency) { checkgl!glUniform1f(transparency_location, transparency); }
216 
217 	void compile(IRenderer renderer) {
218 		shader = renderer.createShaderProgram(chunk_vert_shader16, chunk_frag_shader8);
219 
220 		transparency_location = checkgl!glGetUniformLocation(handle, "transparency");
221 		mvp_location = checkgl!glGetUniformLocation(handle, "mvp");
222 	}
223 }