1use crate::cx::*;
2
3pub enum GLShaderType {
4 OpenGL,
5 WebGL1
6}
7
8impl Cx {
9
10 pub fn gl_assemble_uniforms(unis: &Vec<ShVar>) -> String {
11 let mut out = String::new();
12 for uni in unis {
13 out.push_str("uniform ");
14 out.push_str(&uni.ty);
15 out.push_str(" ");
16 out.push_str(&uni.name);
17 out.push_str(";\n")
18 };
19 out
20 }
21
22 pub fn ceil_div4(base: usize) -> usize {
23 let r = base >> 2;
24 if base & 3 != 0 {
25 return r + 1
26 }
27 r
28 }
29
30 pub fn gl_assemble_texture_slots(unis: &Vec<ShVar>) -> String {
31 let mut out = String::new();
32 for uni in unis {
33 out.push_str("uniform ");
34 match uni.ty.as_ref() {
35 "texture2d" => out.push_str("sampler2D"),
36 _ => out.push_str("unknown_texture_type")
37 };
38 out.push_str(" ");
39 out.push_str(&uni.name);
40 out.push_str(";\n")
41 };
42 out
43 }
44
45 pub fn gl_assemble_vartype(i: usize, total: usize, left: usize) -> String {
46 if i == total - 1 {
47 match left {
48 1 => "float",
49 2 => "vec2",
50 3 => "vec3",
51 _ => "vec4"
52 }.to_string()
53 }
54 else {
55 "vec4".to_string()
56 }
57 }
58
59
60 pub fn gl_assemble_varblock(thing: &str, base: &str, slots: usize) -> String {
61 let mut out = String::new();
63 let total = Self::ceil_div4(slots);
64 for i in 0..total {
65 out.push_str(thing);
66 out.push_str(" ");
67 out.push_str(&Self::gl_assemble_vartype(i, total, slots & 3));
68 out.push_str(" ");
69 out.push_str(base);
70 out.push_str(&i.to_string());
71 out.push_str(";\n");
72 }
73 out
74 }
75
76 pub fn gl_assemble_vardef(var: &ShVar) -> String {
77 let mut out = String::new();
79 out.push_str(&var.ty);
80 out.push_str(" ");
81 out.push_str(&var.name);
82 out.push_str(";\n");
83 out
84 }
85
86 pub fn gl_assemble_unpack(base: &str, slot: usize, total_slots: usize, sv: &ShVar) -> String {
87 let mut out = String::new();
88 out.push_str(" ");
90 out.push_str(&sv.name);
91 out.push_str("=");
92 let id = (slot)>>2;
93
94 if sv.ty == "vec2" {
96 match slot & 3 {
97 0 => {
98 out.push_str(base);
99 out.push_str(&id.to_string());
100 out.push_str(".xy;\r\n");
101 return out
102 }
103 1 => {
104 out.push_str(base);
105 out.push_str(&id.to_string());
106 out.push_str(".yz;\r\n");
107 return out
108 }
109 2 => {
110 out.push_str(base);
111 out.push_str(&id.to_string());
112 out.push_str(".zw;\r\n");
113 return out
114 }
115 _ => ()
116 }
117 }
118 if sv.ty == "vec3" {
119 match slot & 3 {
120 0 => {
121 out.push_str(base);
122 out.push_str(&id.to_string());
123 out.push_str(".xyz;\r\n");
124 return out
125 }
126 1 => {
127 out.push_str(base);
128 out.push_str(&id.to_string());
129 out.push_str(".yzw;\r\n");
130 return out
131 }
132 _ => ()
133 }
134 }
135 if sv.ty == "vec4" {
136 if slot & 3 == 0 {
137 out.push_str(base);
138 out.push_str(&id.to_string());
139 out.push_str(".xyzw;\r\n");
140 return out
141 }
142 }
143 if sv.ty != "float" {
144 out.push_str(&sv.ty);
145 out.push_str("(");
146 }
147
148 let svslots = match sv.ty.as_ref() {
150 "float" => 1,
151 "vec2" => 2,
152 "vec3" => 3,
153 _ => 4
154 };
155
156 for i in 0..svslots {
157 if i != 0 {
158 out.push_str(", ");
159 }
160 out.push_str(base);
161
162 let id = (slot + i)>>2;
163 let ext = (slot + i) & 3;
164
165 out.push_str(&id.to_string());
166 out.push_str(
167 match ext {
168 0 => {
169 if (id == total_slots>>2) && total_slots & 3 == 1 {
170 ""
171 }
172 else {
173 ".x"
174 }
175 }
176 1 => ".y",
177 2 => ".z",
178 _ => ".w"
179 }
180 );
181 }
182 if sv.ty != "float" {
183 out.push_str(")");
184 }
185 out.push_str(";\n");
186 out
187 }
188
189 pub fn gl_assemble_pack_chunk(base: &str, id: usize, chunk: &str, sv: &ShVar) -> String {
190 let mut out = String::new();
191 out.push_str(" ");
192 out.push_str(base);
193 out.push_str(&id.to_string());
194 out.push_str(chunk);
195 out.push_str(&sv.name);
196 out.push_str(";\n");
197 out
198 }
199
200 pub fn gl_assemble_pack(base: &str, slot: usize, total_slots: usize, sv: &ShVar) -> String {
201 let mut out = String::new();
203 let id = (slot)>>2;
204
205 if sv.ty == "vec2" {
207 match slot & 3 {
208 0 => return Self::gl_assemble_pack_chunk(base, id, ".xy =", &sv),
209 1 => return Self::gl_assemble_pack_chunk(base, id, ".yz =", &sv),
210 2 => return Self::gl_assemble_pack_chunk(base, id, ".zw =", &sv),
211 _ => ()
212 }
213 }
214 if sv.ty == "vec3" {
215 match slot & 3 {
216 0 => return Self::gl_assemble_pack_chunk(base, id, ".xyz =", &sv),
217 1 => return Self::gl_assemble_pack_chunk(base, id, ".yzw =", &sv),
218 _ => ()
219 }
220 }
221 if sv.ty == "vec4" {
222 if slot & 3 == 0 {
223 return Self::gl_assemble_pack_chunk(base, id, ".xyzw =", &sv);
224 }
225 }
226
227 let svslots = match sv.ty.as_ref() {
228 "float" => 1,
229 "vec2" => 2,
230 "vec3" => 3,
231 _ => 4
232 };
233
234 for i in 0..svslots {
235 out.push_str(" ");
236 out.push_str(base);
237 let id = (slot + i)>>2;
238 let ext = (slot + i) & 3;
239 out.push_str(&id.to_string());
240 out.push_str(
241 match ext {
242 0 => {
243 if (id == total_slots>>2) && total_slots & 3 == 1 { ""
245 }
246 else {
247 ".x"
248 }
249 }
250 1 => ".y",
251 2 => ".z",
252 _ => ".w"
253 }
254 );
255 out.push_str(" = ");
256 out.push_str(&sv.name);
257 out.push_str(
258 match i {
259 0 => {
260 if sv.ty == "float" {
261 ""
262 }
263 else {
264 ".x"
265 }
266 }
267 1 => ".y",
268 2 => ".z",
269 _ => ".w"
270 }
271 );
272 out.push_str(";\r\n");
273 }
274 out
275 }
276
277 pub fn gl_assemble_shader(sg: &ShaderGen, shtype: GLShaderType) -> Result<(String, String, CxShaderMapping), SlErr> {
278
279 let mut vtx_out = String::new();
280 let mut pix_out = String::new();
281 match shtype {
282 GLShaderType::OpenGL => {
283 vtx_out.push_str("#version 100\n");
284 pix_out.push_str("#version 100\n");
285 pix_out.push_str("#extension GL_OES_standard_derivatives : enable\n");
286 vtx_out.push_str("precision highp float;\n");
287 pix_out.push_str("precision highp float;\n");
288 vtx_out.push_str("precision highp int;\n");
289 pix_out.push_str("precision highp int;\n");
290 },
291 GLShaderType::WebGL1 => {
292 pix_out.push_str("#extension GL_OES_standard_derivatives : enable\n");
293 vtx_out.push_str("precision highp float;\n");
294 pix_out.push_str("precision highp float;\n");
295 vtx_out.push_str("precision highp int;\n");
296 pix_out.push_str("precision highp int;\n");
297 }
298 }
299
300 vtx_out.push_str("vec4 texture2Dflip(sampler2D sampler, vec2 pos){return texture2D(sampler, vec2(pos.x, 1.0-pos.y));}\n");
301 pix_out.push_str("vec4 texture2Dflip(sampler2D sampler, vec2 pos){return texture2D(sampler, vec2(pos.x, 1.0-pos.y));}\n");
302
303 let texture_slots = sg.flat_vars(|v| if let ShVarStore::Texture = *v{true} else {false});
305 let geometries = sg.flat_vars(|v| if let ShVarStore::Geometry = *v{true} else {false});
306 let instances = sg.flat_vars(|v| if let ShVarStore::Instance(_) = *v{true} else {false});
307 let mut varyings = sg.flat_vars(|v| if let ShVarStore::Varying = *v{true} else {false});
308 let locals = sg.flat_vars(|v| if let ShVarStore::Local = *v{true} else {false});
309 let pass_uniforms = sg.flat_vars(|v| if let ShVarStore::PassUniform = *v{true} else {false});
310 let view_uniforms = sg.flat_vars(|v| if let ShVarStore::ViewUniform = *v{true} else {false});
311 let draw_uniforms = sg.flat_vars(|v| if let ShVarStore::DrawUniform = *v{true} else {false});
312 let uniforms = sg.flat_vars(|v| if let ShVarStore::Uniform(_) = *v{true} else {false});
313
314 let mut const_cx = SlCx {
315 depth: 0,
316 target: SlTarget::Constant,
317 defargs_fn: "".to_string(),
318 defargs_call: "".to_string(),
319 call_prefix: "_".to_string(),
320 shader_gen: sg,
321 scope: Vec::new(),
322 fn_deps: Vec::new(),
323 fn_done: Vec::new(),
324 auto_vary: Vec::new()
325 };
326 let consts = sg.flat_consts();
327 let mut consts_out = String::new();
328 for cnst in &consts {
329 let const_init = assemble_const_init(cnst, &mut const_cx) ?;
330 if cnst.ty != const_init.ty {
331 return Err(SlErr {msg: format!("Constant {} init value {} is not the right type {}", cnst.name, const_init.sl, cnst.ty)})
332 }
333 consts_out.push_str("const ");
334 consts_out.push_str(" ");
335 consts_out.push_str(&cnst.ty);
336 consts_out.push_str(" ");
337 consts_out.push_str(&cnst.name);
338 consts_out.push_str(" = ");
339 consts_out.push_str(&const_init.sl);
340 consts_out.push_str(";\n");
341 }
342
343 let mut vtx_cx = SlCx {
344 depth: 0,
345 target: SlTarget::Vertex,
346 defargs_fn: "".to_string(),
347 defargs_call: "".to_string(),
348 call_prefix: "".to_string(),
349 shader_gen: sg,
350 scope: Vec::new(),
351 fn_deps: vec!["vertex".to_string()],
352 fn_done: Vec::new(),
353 auto_vary: Vec::new()
354 };
355 let vtx_fns = assemble_fn_and_deps(sg, &mut vtx_cx) ?;
356
357 let mut pix_cx = SlCx {
358 depth: 0,
359 target: SlTarget::Pixel,
360 defargs_fn: "".to_string(),
361 defargs_call: "".to_string(),
362 call_prefix: "".to_string(),
363 shader_gen: sg,
364 scope: Vec::new(),
365 fn_deps: vec!["pixel".to_string()],
366 fn_done: Vec::new(),
367 auto_vary: Vec::new()
368 };
369 let pix_fns = assemble_fn_and_deps(sg, &mut pix_cx) ?;
370
371 for auto in &pix_cx.auto_vary {
372 varyings.push(auto.clone());
373 }
374
375 let geometry_slots = sg.compute_slot_total(&geometries);
377 let instance_slots = sg.compute_slot_total(&instances);
378 let varying_slots = sg.compute_slot_total(&varyings);
379 let mut shared = String::new();
380 shared.push_str("// Consts\n");
381 shared.push_str(&consts_out);
382 shared.push_str("//Pass uniforms\n");
383 shared.push_str(&Self::gl_assemble_uniforms(&pass_uniforms));
384 shared.push_str("//View uniforms\n");
385 shared.push_str(&Self::gl_assemble_uniforms(&view_uniforms));
386 shared.push_str("//Draw uniforms\n");
387 shared.push_str(&Self::gl_assemble_uniforms(&draw_uniforms));
388 shared.push_str("//Uniforms\n");
389 shared.push_str(&Self::gl_assemble_uniforms(&uniforms));
390 shared.push_str("//Texture slots\n");
391 shared.push_str(&Self::gl_assemble_texture_slots(&texture_slots));
392 shared.push_str("// Varyings\n");
393 shared.push_str(&Self::gl_assemble_varblock("varying", "varying", varying_slots));
394
395 for local in &locals {shared.push_str(&Self::gl_assemble_vardef(&local));}
396
397 pix_out.push_str(&shared);
398
399 vtx_out.push_str(&shared);
400
401 let mut vtx_main = "void main(){\n".to_string();
402 let mut pix_main = "void main(){\n".to_string();
403
404 vtx_out.push_str("// Geometry attributes\n");
405 vtx_out.push_str(&Self::gl_assemble_varblock("attribute", "geomattr", geometry_slots));
406 let mut slot_id = 0;
407 for geometry in &geometries {
408 vtx_out.push_str(&Self::gl_assemble_vardef(&geometry));
409 vtx_main.push_str(&Self::gl_assemble_unpack("geomattr", slot_id, geometry_slots, &geometry));
410 slot_id += sg.get_type_slots(&geometry.ty);
411 }
412
413 vtx_out.push_str("// Instance attributes\n");
414 vtx_out.push_str(&Self::gl_assemble_varblock("attribute", "instattr", instance_slots));
415 let mut slot_id = 0;
416 for instance in &instances {
417 vtx_out.push_str(&Self::gl_assemble_vardef(&instance));
418 vtx_main.push_str(&Self::gl_assemble_unpack("instattr", slot_id, instance_slots, &instance));
419 slot_id += sg.get_type_slots(&instance.ty);
420 }
421
422
423 vtx_main.push_str("\n gl_Position = vertex();\n");
424 vtx_main.push_str("\n // Varying packing\n");
425
426 pix_main.push_str("\n // Varying unpacking\n");
427
428 let mut slot_id = 0;
430 for vary in &varyings {
431 if geometries.iter().find( | v | v.name == vary.name).is_none() &&
433 instances.iter().find( | v | v.name == vary.name).is_none() {
434 vtx_out.push_str(&Self::gl_assemble_vardef(&vary));
435 }
436 pix_out.push_str(&Self::gl_assemble_vardef(&vary));
437 vtx_main.push_str(&Self::gl_assemble_pack("varying", slot_id, varying_slots, &vary));
439 pix_main.push_str(&Self::gl_assemble_unpack("varying", slot_id, varying_slots, &vary));
441 slot_id += sg.get_type_slots(&vary.ty);
442 }
443
444 pix_main.push_str("\n gl_FragColor = pixel();\n");
445 vtx_main.push_str("\n}\n\0");
446 pix_main.push_str("\n}\n\0");
447
448 vtx_out.push_str("//Vertex shader\n");
449 vtx_out.push_str(&vtx_fns);
450 pix_out.push_str("//Pixel shader\n");
451 pix_out.push_str(&pix_fns);
452
453 vtx_out.push_str("//Main function\n");
454 vtx_out.push_str(&vtx_main);
455
456 pix_out.push_str("//Main function\n");
457 pix_out.push_str(&pix_main);
458
459 if sg.log != 0 {
460 }
463 let uniform_props = UniformProps::construct(sg, &uniforms);
467 Ok((vtx_out, pix_out, CxShaderMapping {
468 instance_props: InstanceProps::construct(sg, &instances),
469 rect_instance_props: RectInstanceProps::construct(sg, &instances),
470 uniform_props,
471 instances,
472 geometries,
473 instance_slots,
474 geometry_slots,
475 draw_uniforms,
476 view_uniforms,
477 pass_uniforms,
478 uniforms,
479 texture_slots,
480 }))
481 }
482}
483
484
485impl<'a> SlCx<'a> {
486 pub fn map_call(&self, name: &str, args: &Vec<Sl>) -> MapCallResult {
487 match name {
488 "matrix_comp_mult" => return MapCallResult::Rename("matrixCompMult".to_string()),
489 "less_than" => return MapCallResult::Rename("less_than".to_string()),
490 "less_than_equal" => return MapCallResult::Rename("lessThanEqual".to_string()),
491 "greater_than" => return MapCallResult::Rename("greaterThan".to_string()),
492 "greater_than_equal" => return MapCallResult::Rename("greaterThanEqual".to_string()),
493 "not_equal" => return MapCallResult::Rename("notEqual".to_string()),
494 "sample2d" => {
495 return MapCallResult::Rename("texture2Dflip".to_string())
496 },
497 "fmod" => {
498 return MapCallResult::Rename("mod".to_string())
499 },
500 "dfdx" => {
501 return MapCallResult::Rename("dFdx".to_string())
502 },
503 "dfdy" => {
504 return MapCallResult::Rename("dFdy".to_string())
505 },
506 "color" => {
507 let col = color(&args[0].sl);
508 return MapCallResult::Rewrite(
509 format!("vec4({},{},{},{})", col.r, col.g, col.b, col.a),
510 "vec4".to_string()
511 );
512 },
513 _ => return MapCallResult::None
514 }
515 }
516
517 pub fn mat_mul(&self, left: &str, right: &str) -> String {
518 format!("{}*{}", left, right)
519 }
520
521 pub fn map_type(&self, ty: &str) -> String {
522 match ty {
523 "texture2d" => return "sampler2D".to_string(),
524 _ => return ty.to_string()
525 }
526 }
527
528 pub fn map_constructor(&self, name: &str, args: &Vec<Sl>)->String{
529 let mut out = String::new();
530 out.push_str(&self.map_type(name));
531 out.push_str("(");
532 for (i,arg) in args.iter().enumerate(){
533 if i != 0{
534 out.push_str(", ");
535 }
536 out.push_str(&arg.sl);
537 }
538 out.push_str(")");
539 return out;
540 }
541
542 pub fn map_var(&mut self, var: &ShVar) -> String {
543 match var.store {
544 ShVarStore::Instance(_) => {
545 if let SlTarget::Pixel = self.target {
546 if self.auto_vary.iter().find( | v | v.name == var.name).is_none() {
547 self.auto_vary.push(var.clone());
548 }
549 }
550 },
551 ShVarStore::Geometry => {
552 if let SlTarget::Pixel = self.target {
553 if self.auto_vary.iter().find( | v | v.name == var.name).is_none() {
554 self.auto_vary.push(var.clone());
555 }
556 }
557 },
558 _ => ()
559 }
560 var.name.clone()
561 }
562
563}