atomes 1.3.1
atomes: an atomic scale modeling tool box
Loading...
Searching...
No Matches
ogl_shaders.c
Go to the documentation of this file.
1/* This file is part of the 'atomes' software
2
3'atomes' is free software: you can redistribute it and/or modify it under the terms
4of the GNU Affero General Public License as published by the Free Software Foundation,
5either version 3 of the License, or (at your option) any later version.
6
7'atomes' is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9See the GNU General Public License for more details.
10
11You should have received a copy of the GNU Affero General Public License along with 'atomes'.
12If not, see <https://www.gnu.org/licenses/>
13
14Copyright (C) 2022-2026 by CNRS and University of Strasbourg */
15
21
22/*
23* This file: 'ogl_shaders.c'
24*
25* Contains:
26*
27
28 - The OpenGL shaders for the atomes program
29
30*
31* Notes:
32*
33
34 LLM tools (ChatGPT, Gemini via Antigravity, Claude) were used at few occasions to prepare some sections of this file, including:
35 - To write parts of the ray-tracing shaders
36 - To write parts the gradient background shaders
37
38*/
39
40#include "global.h"
41
42// Point shaders:
43
44// const GLchar * point_vertex;
45// const GLchar * point_colors;
46
47//#define GLSL(src) "#version 430 core\n" #src
48#define GLSL(src) "#version 150\n" #src
49
50const GLchar * point_vertex = GLSL(
51 uniform mat4 mvp;
52 in vec3 vert;
53 in vec3 offset;
54 in float size;
55 in vec4 vertColor;
56
57 out vec4 vert_color;
58 void main()
59 {
60 vert_color = vertColor;
61 gl_PointSize = size;
62 gl_Position = mvp * vec4(vert + offset, 1.0);
63 }
64);
65
66const GLchar * point_color = GLSL(
67 in vec4 vert_color;
68 out vec4 fragment_color;
69 void main()
70 {
71 fragment_color = vert_color;
72 }
73);
74
75// Basic line shaders
76
77// const GLchar * line_vertex;
78// const GLchar * line_colors;
79
80const GLchar * line_vertex = GLSL(
81 uniform mat4 mvp;
82 in vec3 vert;
83 in vec4 vertColor;
84
85 out vec4 vert_color;
86 void main()
87 {
88 vert_color = vertColor;
89 gl_Position = mvp * vec4(vert, 1.0);
90 }
91);
92
93const GLchar * line_color = GLSL(
94 in vec4 vert_color;
95 out vec4 fragment_color;
96 void main()
97 {
98 fragment_color = vert_color;
99 }
100);
101
102const GLchar * line_stipple = GLSL(
103 layout(lines) in;
104 layout(line_strip, max_vertices=2) out;
105 in vec4 vert_color[];
106 uniform float depth;
107
108 out float line_pos;
109 out vec4 v_color;
110 void main()
111 {
112 vec2 win_pos_0 = gl_in[0].gl_Position.xy;
113 vec2 win_pos_1 = gl_in[1].gl_Position.xy;
114 gl_Position = gl_in[0].gl_Position;
115 line_pos = 0.0;
116 v_color = vert_color[0];
117 EmitVertex();
118 gl_Position = gl_in[1].gl_Position;
119 float psize = 3.0; // No particular reason, just seems right
120 line_pos = psize * length(win_pos_1 - win_pos_0);
121 line_pos *= depth;
122 v_color = vert_color[1];
123 EmitVertex();
124 EndPrimitive();
125 }
126);
127
128const GLchar * angle_vertex = GLSL(
129 uniform mat4 mvp;
130 in vec3 vert;
131 in vec4 vertColor;
132
133 out vec4 vert_color;
134 void main()
135 {
136 vert_color = vertColor;
137 gl_Position = vec4(vert, 1.0);
138 }
139);
140
141const GLchar * angle_stipple = GLSL(
142 layout(triangles) in;
143 layout(line_strip, max_vertices=20) out;
144 in vec4 vert_color[];
145
146 uniform float depth;
147 uniform mat4 mvp;
148 uniform mat4 un_view;
149 uniform mat4 text_proj;
150 uniform vec4 viewp;
151
152 out float line_pos;
153 out vec4 v_color;
154
155 const float PI = 3.14159265359;
156
157 mat4 translate_this (in vec3 coord)
158 {
159 mat4 translate;
160 translate[0] = vec4(1.0, 0.0, 0.0, 0.0);
161 translate[1] = vec4(0.0, 1.0, 0.0, 0.0);
162 translate[2] = vec4(0.0, 0.0, 1.0, 0.0);
163 translate[3][0] = coord.x;
164 translate[3][1] = coord.y;
165 translate[3][2] = coord.z;
166 translate[3][3] = 1.0;
167 return translate;
168 }
169
170 vec3 project (in vec3 coord)
171 {
172 mat4 n_mvp = (mvp * translate_this (coord));
173 vec4 res = n_mvp * vec4(vec3(0.0), 1.0);
174 if (res.w != 0.0)
175 {
176 res.w = 1.0 / res.w;
177 res.x = res.w * res.x + 1.0;
178 res.y = res.w * res.y + 1.0;
179 res.z = res.w * res.z + 1.0;
180 return vec3 (res.x*viewp.z+viewp.x, res.y*viewp.w+viewp.y, res.z);
181 }
182 else
183 {
184 return vec3 (0.0, 0.0, -1.0);
185 }
186 }
187
188 float angle2d (in vec2 at, in vec2 bt, in vec2 ct)
189 {
190 vec2 ab = bt - at;
191 vec2 bc = bt - ct;
192 float theta = dot(ab,bc) / (length(ab) * length(bc));
193 if (theta < -1.0)
194 {
195 return acos (-2.0 - theta);
196 }
197 else if (theta > 1.0)
198 {
199 return acos (2.0 - theta);
200 }
201 else
202 {
203 return acos (theta);
204 }
205 }
206
207 void main()
208 {
209 vec3 pa = project (gl_in[0].gl_Position.xyz);
210 vec3 pb = project (gl_in[1].gl_Position.xyz);
211 vec3 pc = project (gl_in[2].gl_Position.xyz);
212 vec2 pd;
213 pd.x = pb.x + 100.0;
214 pd.y = pb.y;
215 float alpha = angle2d (pa.xy, pb.xy, pd);
216 float beta = angle2d (pc.xy, pb.xy, pd);
217 float theta = angle2d (pa.xy, pb.xy, pc.xy);
218 if (pa.y > pb.y && pc.y > pb.y)
219 {
220 beta = min (alpha, beta);
221 }
222 else if (pa.y < pb.y && pc.y < pb.y)
223 {
224 beta = min (-alpha, -beta);
225 // or beta = - max (alpha, beta);
226 }
227 else
228 {
229 vec2 pe;
230 vec2 pf;
231 pe.y = max(pa.y, pc.y);
232 if (pe.y == pa.y)
233 {
234 pe.x = pa.x;
235 pf.y = pc.y;
236 pf.x = pc.x;
237 }
238 else
239 {
240 pe.x = pc.x;
241 pf.y = pa.y;
242 pf.x = pa.x;
243 }
244 beta = angle2d (pe, pb.xy, pd);
245 alpha = angle2d (pf, pb.xy, pd);
246 if (beta + alpha < PI)
247 {
248 beta -= theta;
249 }
250 }
251
252 float psize = 3.0; // No particular reason, just seems right
253 float tan_factor = tan(theta/10.0);
254 float radial_factor = cos(theta/10.0);
255 float dist = min(length(pb-pa), length(pb-pc)) / 3.0;
256 float x = dist * cos(beta);
257 float y = dist * sin(beta);
258 float tx;
259 float ty;
260
261 vec2 apos;
262 vec2 bpos;
263 v_color = vert_color[0];
264
265 vec4 pos_s = mvp * gl_in[0].gl_Position;
266 vec4 pos_e = mvp * gl_in[1].gl_Position;
267 line_pos = 0.0;
268 gl_Position = pos_s;
269 EmitVertex();
270 float line_save = psize * length(pos_e.xy - pos_s.xy);
271 line_pos = line_save;
272 line_pos *= depth;
273 gl_Position = pos_e;
274 EmitVertex();
275 int i;
276 line_pos = -1.0;
277 EmitVertex();
278 for (i = 0; i < 11; i++)
279 {
280 apos = vec2(x,y);
281 gl_Position = text_proj * (vec4(pb, 1.0) + vec4(apos.x, apos.y, 0.0, 1.0));
282 EmitVertex();
283 if (i == 0)
284 {
285 line_pos = line_save;
286 EmitVertex();
287 }
288 tx = -y;
289 ty = x;
290 x += tx * tan_factor;
291 y += ty * tan_factor;
292 x *= radial_factor;
293 y *= radial_factor;
294 bpos = vec2(x,y);
295 line_pos += psize * length(bpos - apos) / 20.0;
296 }
297 EmitVertex();
298 line_save = line_pos;
299 line_pos = -1.0;
300 EmitVertex();
301 gl_Position = pos_e;
302 EmitVertex();
303 line_pos = line_save;
304 line_pos *= depth;
305 EmitVertex();
306 pos_s = mvp * gl_in[2].gl_Position;
307 line_pos += depth * psize * length(pos_s.xy - pos_e.xy);
308 gl_Position = pos_s;
309 EmitVertex();
310 EndPrimitive();
311 }
312);
313
314const GLchar * line_stipple_color = GLSL(
315 uniform int factor;
316 uniform uint pattern;
317 in float line_pos;
318 in vec4 v_color;
319
320 out vec4 fragment_color;
321 void main()
322 {
323 fragment_color = v_color;
324 if (line_pos == -1.0) discard;
325 uint bit = uint(round(line_pos/factor)) % 16U;
326 if ((pattern & (1U<<bit)) == 0U) discard;
327 }
328);
329
330const GLchar * angle_color = GLSL(
331 uniform int factor;
332 uniform uint pattern;
333 in float line_pos;
334 in vec4 v_color;
335
336 out vec4 fragment_color;
337 void main()
338 {
339 fragment_color = v_color;
340 if (line_pos == -1.0) discard;
341 }
342);
343
344// Triangle shader
345
346const GLchar * full_vertex = GLSL(
347 uniform mat4 mvp;
348 uniform mat4 m_view;
349 in vec3 vert;
350 in vec3 vertNormal;
351 in vec4 vertColor;
352
353 out vec4 surfaceColor;
354 out vec3 surfacePosition;
355 out vec3 surfaceNormal;
356 out vec3 surfaceToCamera;
357 void main ()
358 {
359 surfaceColor = vertColor;
360
361 surfacePosition = vec3(m_view * vec4(vert, 1.0f));
362 surfaceNormal = mat3(m_view) * vertNormal;
363 surfaceToCamera = normalize (- surfacePosition);
364 gl_Position = mvp * vec4(vert, 1.0f);
365 }
366);
367
368// Sphere
369
370const GLchar * sphere_vertex = GLSL(
371 uniform mat4 mvp;
372 uniform mat4 m_view;
373
374 in vec3 vert;
375 in vec3 offset;
376 in vec4 vertColor;
377 in float radius;
378
379 out vec4 surfaceColor;
380 out vec3 surfacePosition;
381 out vec3 surfaceNormal;
382 out vec3 surfaceToCamera;
383 void main ()
384 {
385 surfaceColor = vertColor;
386 vec4 pos = vec4 (radius*vert + offset, 1.0);
387 surfacePosition = vec3(m_view * pos);
388 surfaceNormal = mat3(m_view) * vert;
389 surfaceToCamera = normalize (- surfacePosition);
390 gl_PointSize = 1.0;
391 gl_Position = mvp * pos;
392 }
393);
394
395// Cylinder
396
397const GLchar * cylinder_vertex = GLSL(
398 uniform mat4 mvp;
399 uniform mat4 m_view;
400 in vec4 quat;
401 in float height;
402 in float radius;
403 in vec3 offset;
404 in vec3 vert;
405 in vec4 vertColor;
406
407 out vec4 surfaceColor;
408 out vec3 surfacePosition;
409 out vec3 surfaceNormal;
410 out vec3 surfaceToCamera;
411
412 vec3 rotate_this (in vec3 v, in vec4 quat)
413 {
414 vec3 u = vec3(quat.x, quat.y, quat.z);
415 float s = quat.w;
416 return 2.0 * dot(u,v) * u + (s*s - dot(u,u)) * v + 2.0 * s * cross (u,v);
417 }
418
419 void main ()
420 {
421 surfaceColor = vertColor;
422 vec3 pos = vec3(radius*vert.x, radius*vert.y, height*vert.z);
423 vec3 norm = normalize (vec3(vert.x, vert.y, 0.0));
424 if (quat.w != 0.0)
425 {
426 pos = rotate_this (pos, quat);
427 norm = rotate_this (norm, quat);
428 }
429 pos += offset;
430 surfacePosition = vec3(m_view * vec4(pos,1.0));
431 surfaceNormal = mat3(m_view) * norm;
432 surfaceToCamera = normalize (- surfacePosition);
433 gl_Position = mvp * vec4(pos,1.0);
434 }
435);
436
437const GLchar * cone_vertex = GLSL(
438 uniform mat4 mvp;
439 uniform mat4 m_view;
440 in vec4 quat;
441 in float height;
442 in float radius;
443 in vec3 offset;
444 in vec3 vert;
445 in vec4 vertColor;
446
447 out vec4 surfaceColor;
448 out vec3 surfacePosition;
449 out vec3 surfaceNormal;
450 out vec3 surfaceToCamera;
451
452 vec3 rotate_this (in vec3 v, in vec4 quat)
453 {
454 vec3 u = vec3(quat.x, quat.y, quat.z);
455 float s = quat.w;
456 return 2.0 * dot(u,v) * u + (s*s - dot(u,u)) * v + 2.0 * s * cross (u,v);
457 }
458
459 void main ()
460 {
461 surfaceColor = vertColor;
462 vec3 pos = vec3(radius*vert.x, radius*vert.y, height*vert.z);
463 // The normal calculation changes / cylinders
464 float B = sqrt(radius*radius + height*height);
465 vec3 norm = vec3(height*vert.x/B, height*vert.y/B, radius/B);
466 if (quat.w != 0.0)
467 {
468 pos = rotate_this (pos, quat);
469 norm = rotate_this (norm, quat);
470 }
471 pos += offset;
472 surfacePosition = vec3(m_view * vec4(pos,1.0));
473 surfaceNormal = mat3(m_view) * norm;
474 surfaceToCamera = normalize (- surfacePosition);
475 gl_Position = mvp * vec4(pos,1.0);
476 }
477);
478
479const GLchar * cap_vertex = GLSL(
480 uniform mat4 mvp;
481 uniform mat4 m_view;
482 in vec4 quat;
483 in float radius;
484 in vec3 offset;
485 in vec3 vert;
486 in vec4 vertColor;
487
488 out vec4 surfaceColor;
489 out vec3 surfacePosition;
490 out vec3 surfaceNormal;
491 out vec3 surfaceToCamera;
492
493 vec3 rotate_this (in vec3 v, in vec4 quat)
494 {
495 vec3 u = vec3(quat.x, quat.y, quat.z);
496 float s = quat.w;
497 return 2.0 * dot(u,v) * u + (s*s - dot(u,u)) * v + 2.0 * s * cross (u,v);
498 }
499
500 void main ()
501 {
502 surfaceColor = vertColor;
503 vec3 pos = vec3(radius*vert.x, radius*vert.y, vert.z);
504 vec3 norm = vec3(0.0, 0.0, -1.0);
505 if (quat.w != 0.0)
506 {
507 pos = rotate_this (pos, quat);
508 norm = rotate_this (norm, quat);
509 }
510 pos += offset;
511 surfacePosition = vec3(m_view * vec4(pos,1.0));
512 surfaceNormal = mat3(m_view) * norm;
513 surfaceToCamera = normalize (- surfacePosition);
514 gl_Position = mvp * vec4(pos,1.0);
515 }
516);
517
518const GLchar * gs_cylinder_geom = GLSL(
519 layout (lines) in;
520 layout (triangle_strip, max_vertices=64) out;
521
522 uniform mat4 mvp;
523 uniform mat4 m_view;
524 uniform int quality;
525 uniform float radius;
526
527 in vec4 vertCol[];
528
529 out vec4 surfaceColor;
530 out vec3 surfacePosition;
531 out vec3 surfaceNormal;
532 out vec3 surfaceToCamera;
533
534 float pi = 3.141592653;
535
536 vec3 create_perp (in vec3 axis)
537 {
538 vec3 u = vec3(0.0, 0.0, 1.0);
539 vec3 v = vec3(0.0, 1.0, 0.0);
540 vec3 res = cross(u, axis);
541 if (length(res) == 0.0)
542 {
543 res = cross (v, axis);
544 }
545 return res;
546 }
547
548 void main()
549 {
550 vec3 v1 = gl_in[0].gl_Position.xyz;
551 vec3 v2 = gl_in[1].gl_Position.xyz;
552 vec3 axis = normalize(v2 - v1);
553 vec3 perp_x = create_perp (axis);
554 vec3 perp_y = cross (axis, perp_x);
555 float step = 2.0 * pi / float(quality - 1);
556 for(int i=0; i<quality; i++)
557 {
558 float a = i * step;
559 float ca = cos(a);
560 float sa = sin(a);
561
562 vec3 normal = normalize(ca*perp_x + sa*perp_y);
563 vec3 p1 = v1 + radius * normal;
564 vec3 p2 = v2 + radius * normal;
565
566 surfaceNormal = mat3(m_view) * normal;
567 gl_Position = mvp * vec4(p1, 1.0);
568
569 surfacePosition = vec3(m_view * vec4(p1, 1.0));
570 surfaceToCamera = normalize (- surfacePosition);
571 surfaceColor = vertCol[0];
572 EmitVertex();
573
574 gl_Position = mvp * vec4 (p2, 1.0);
575 surfacePosition = vec3(m_view * vec4(p2, 1.0));
576 surfaceToCamera = normalize (- surfacePosition);
577 surfaceColor = vertCol[1];
578 EmitVertex();
579 }
580 EndPrimitive();
581 }
582);
583
584const GLchar * string_vertex = GLSL(
585 uniform mat4 mvp;
586 uniform mat4 un_view;
587 uniform mat4 text_proj;
588 uniform vec4 viewp;
589 uniform vec4 pos_shift;
590 in vec2 vert;
591 in vec2 tcoord;
592 in vec3 offset;
593 out float angle;
594
595 out vec2 text_coords;
596 mat4 translate_this (in vec3 coord)
597 {
598 mat4 translate;
599 translate[0] = vec4(1.0, 0.0, 0.0, 0.0);
600 translate[1] = vec4(0.0, 1.0, 0.0, 0.0);
601 translate[2] = vec4(0.0, 0.0, 1.0, 0.0);
602 translate[3][0] = coord.x;
603 translate[3][1] = coord.y;
604 translate[3][2] = coord.z;
605 translate[3][3] = 1.0;
606
607 return translate;
608 }
609
610 vec4 project (in vec3 coord)
611 {
612 mat4 n_mvp = ((mvp * translate_this (coord)) * un_view) * translate_this (pos_shift.xyz);
613 vec4 res = n_mvp * vec4(vec3(0.0), 1.0);
614 if (res.w != 0.0)
615 {
616 res.w = 1.0 / res.w;
617 res.x = res.w * res.x + 1.0;
618 res.y = res.w * res.y + 1.0;
619 res.z = res.w * res.z + 1.0;
620 return vec4 (res.x*viewp.z+viewp.x, res.y*viewp.w+viewp.y, pos_shift.w*res.z, 1.0);
621 }
622 else
623 {
624 return vec4 (0.0, 0.0, -1.0, 0.0);
625 }
626 }
627
628 void main()
629 {
630 text_coords = tcoord;
631 vec4 pos = project (offset) + vec4(vert, 0.0, 1.0);
632 gl_Position = text_proj * pos;
633 }
634);
635
636const GLchar * full_color = GLSL(
637
638 int PHONG = 1;
639 int BLINN = 2;
640 int COOK_BLINN = 3;
641 int COOK_BECKMANN = 4;
642 int COOK_GGX = 5;
643
644 struct Light {
645 int type;
646 vec3 position;
647 vec3 direction;
648 vec3 intensity;
649 float constant;
650 float linear;
651 float quadratic;
652 float cone_angle;
653 float spot_inner;
654 float spot_outer;
655 };
656
657 struct Material {
658 vec3 albedo;
659 float metallic;
660 float roughness;
661 float ambient_occlusion;
662 float gamma;
663 float alpha;
664 };
665
666 struct Fog {
667 int mode;
668 int based;
669 float density;
670 vec2 depth;
671 vec3 color;
672 };
673
674 uniform Light AllLights[10];
675 uniform Material mat;
676 uniform Fog fog;
677 uniform int lights_on;
678 uniform int numLights;
679
680 in vec4 surfaceColor;
681 in vec3 surfacePosition;
682 in vec3 surfaceNormal;
683 in vec3 surfaceToCamera;
684
685 out vec4 fragment_color;
686
687 const float PI = 3.14159265359;
688 const float EPS = 1e-5;
689
690 // clamping to 0 - 1 range
691 float saturate (in float value)
692 {
693 return clamp(value, 0.0, 1.0);
694 }
695
696 // phong (lambertian) diffuse term
697 float phong_diffuse()
698 {
699 return (1.0 / PI);
700 }
701
702 // compute Fresnel specular factor for given base specular and product
703 // product could be NdV or VdH depending on used technique
704 vec3 fresnel_factor (in vec3 f0, in float product)
705 {
706 return mix(f0, vec3(1.0), pow(1.01 - product, 5.0));
707 }
708
709 // following functions are copies of UE4
710 // for computing cook-torrance specular lighting terms
711
712 float D_blinn(in float roughness, in float NdH)
713 {
714 float m = roughness * roughness;
715 float m2 = m * m;
716 float n = 2.0 / m2 - 2.0;
717 return (n + 2.0) / (2.0 * PI) * pow(NdH, n);
718 }
719
720 float D_beckmann(in float roughness, in float NdH)
721 {
722 float m = roughness * roughness;
723 float m2 = m * m;
724 float NdH2 = NdH * NdH;
725 return exp((NdH2 - 1.0) / (m2 * NdH2)) / (PI * m2 * NdH2 * NdH2);
726 }
727
728 float D_GGX(in float roughness, in float NdH)
729 {
730 float m = roughness * roughness;
731 float m2 = m * m;
732 float d = (NdH * m2 - NdH) * NdH + 1.0;
733 return m2 / (PI * d * d);
734 }
735
736 float G_schlick(in float roughness, in float NdV, in float NdL)
737 {
738 float k = roughness * roughness * 0.5;
739 float V = NdV * (1.0 - k) + k;
740 float L = NdL * (1.0 - k) + k;
741 return 0.25 / (V * L);
742 }
743
744 // simple phong specular calculation with normalization
745 vec3 phong_specular(in vec3 V, in vec3 L, in vec3 N, in vec3 specular, in float roughness)
746 {
747 vec3 R = reflect(-L, N);
748 float spec = max(0.0, dot(V, R));
749
750 float k = 1.999 / (roughness * roughness);
751
752 return min(1.0, 3.0 * 0.0398 * k) * pow(spec, min(10000.0, k)) * specular;
753 }
754
755 // simple blinn specular calculation with normalization
756 vec3 blinn_specular(in float NdH, in vec3 specular, in float roughness)
757 {
758 float k = 1.999 / (roughness * roughness);
759
760 return min(1.0, 3.0 * 0.0398 * k) * pow(NdH, min(10000.0, k)) * specular;
761 }
762
763 // cook-torrance specular calculation
764 vec3 cooktorrance_specular (in int cook, in float NdL, in float NdV, in float NdH, in vec3 specular, in float roughness)
765 {
766 float D;
767 if (cook == COOK_BLINN)
768 {
769 D = D_blinn(roughness, NdH);
770 }
771 else if (cook == COOK_BECKMANN)
772 {
773 D = D_beckmann(roughness, NdH);
774 }
775 else if (cook == COOK_GGX)
776 {
777 D = D_GGX(roughness, NdH);
778 }
779
780 float G = G_schlick(roughness, NdV, NdL);
781
782 float rim = mix(1.0 - roughness * 0.9, 1.0, NdV);
783
784 return (1.0 / rim) * specular * G * D;
785 }
786
787 vec3 Apply_lighting_model (in int model, in Light light, in vec3 specular)
788 {
789 vec3 v_pos = surfacePosition;
790 // L, V, H vectors
791 vec3 L;
792 float A;
793 float I = 1.0;
794 if (light.type == 0)
795 {
796 // Directional light
797 L = normalize (-light.direction);
798 A = 1.0;
799 }
800 else
801 {
802 L = light.position - v_pos;
803 float dist = length (L);
804 L = normalize(L);
805 A = 1.0 / (light.constant + light.linear*dist + light.quadratic*dist*dist);
806 if (light.type == 2)
807 {
808 float theta = dot(L, normalize(light.position-light.direction));
809 if(theta > light.cone_angle)
810 {
811 float epsilon = light.spot_inner - light.spot_outer;
812 I = saturate((theta - light.spot_outer) / epsilon);
813 }
814 else
815 {
816 return vec3(0.0001);
817 }
818 }
819 }
820 vec3 V = normalize(-v_pos);
821 vec3 H = normalize(L + V);
822 vec3 N = surfaceNormal;
823
824 // compute material reflectance
825 float NdL = max(0.0, dot(N, L));
826 float NdV = max(0.001, dot(N, V));
827 float NdH = max(0.001, dot(N, H));
828 float HdV = max(0.001, dot(H, V));
829 float LdV = max(0.001, dot(L, V));
830
831 // fresnel term is common for any, except phong
832 // so it will be calculated inside ifdefs
833 vec3 specfresnel;
834 vec3 specref;
835 if (model == PHONG)
836 {
837 // specular reflectance with PHONG
838 specfresnel = fresnel_factor (specular, NdV);
839 specref = phong_specular (V, L, N, specfresnel, mat.roughness);
840 }
841 else if (model == BLINN)
842 {
843 // specular reflectance with BLINN
844 specfresnel = fresnel_factor (specular, HdV);
845 specref = blinn_specular (NdH, specfresnel, mat.roughness);
846 }
847 else
848 {
849 // specular reflectance with COOK-TORRANCE
850 specfresnel = fresnel_factor(specular, HdV);
851 specref = cooktorrance_specular(model, NdL, NdV, NdH, specfresnel, mat.roughness);
852 }
853
854 specref *= vec3(NdL);
855
856 // diffuse is common for any model
857 vec3 diffref = (vec3(1.0) - specfresnel) * phong_diffuse() * NdL;
858
859 // compute lighting
860 vec3 reflected_light = vec3(0);
861 vec3 diffuse_light = vec3(0); // initial value == constant ambient light
862
863 // point light
864 vec3 light_color = light.intensity * A * I;
865 reflected_light += specref * light_color;
866 diffuse_light += diffref * light_color;
867
868 // final result
869 return diffuse_light * mix(mat.albedo, vec3(0.0), mat.metallic) + reflected_light;
870 }
871
872 vec3 Apply_fog (in vec3 lightColor)
873 {
874 //distance
875 float dist = 0.0;
876 float fogFactor = 0.0;
877
878 //compute distance used in fog equations
879 if (fog.based == 0)
880 {
881 //plane based
882 dist = abs (surfacePosition.z);
883 }
884 else
885 {
886 //range based
887 dist = length (surfacePosition);
888 }
889
890 if (fog.mode == 1) // linear fog
891 {
892 fogFactor = (fog.depth.x - dist)/(fog.depth.y - fog.depth.x);
893 }
894 else if (fog.mode == 2) // exponential fog
895 {
896 fogFactor = 1.0 / exp (dist * fog.density);
897 }
898 else
899 {
900 fogFactor = 1.0 / exp((dist * fog.density)* (dist * fog.density));
901 }
902 fogFactor = saturate (fogFactor);
903 return mix (fog.color, lightColor, fogFactor);
904 }
905
906 float computeAO(vec3 N)
907 {
908 float ao = 0.5 + 0.5 * N.y; // plage 0.0 -> 1.0
909 ao = pow(ao, 1.0); // gamma pour adoucir
910 ao *= mat.ambient_occlusion;
911 return saturate(ao);
912 }
913
914 void main ()
915 {
916 // Properties
917 vec3 color;
918 float alpha;
919 if (lights_on == 0)
920 {
921 color = vec3(1.0);
922 alpha = surfaceColor.w;
923 }
924 else
925 {
926 // mix between metal and non-metal material, for non-metal
927 // constant base specular factor of 0.04 grey is used
928 vec3 specular = mix(vec3(0.04), mat.albedo, mat.metallic);
929 color = vec3(0.0);
930 for(int i = 0; i < numLights; i++)
931 {
932 color += Apply_lighting_model (lights_on, AllLights[i], specular);
933 }
934 color = pow(color, vec3(1.0/mat.gamma));
935 float ao = computeAO(surfaceNormal);
936 color *= ao;
937 alpha = surfaceColor.w * mat.alpha;
938 }
939
940 if (fog.mode > 0)
941 {
942 vec3 col = Apply_fog(surfaceColor.rgb*color);
943 fragment_color = vec4 (col * alpha, alpha);
944 }
945 else
946 {
947 fragment_color = vec4 ((surfaceColor.rgb*color) * alpha, alpha);
948 }
949 }
950);
951
952/* ===========================================================================
953 * Perfect-impostor shaders (plot -> ray_tracing).
954 *
955 * Principle: each primitive (sphere, cylinder, cone, cap) is rendered as a
956 * camera-aligned billboard quad (4 vertices, GL_TRIANGLE_STRIP).
957 * The fragment shader performs an exact analytic ray intersection
958 * and additionally writes gl_FragDepth with the depth of the actual hit point,
959 * giving pixel-perfect silhouettes AND correct depth-buffer occlusion between
960 * overlapping atoms / bonds.
961 *
962 * Billboard proxy geometry (draw_billboard_quad, see d_atoms.c):
963 * vertices[0] = (-1,-1, 0) GL_TRIANGLE_STRIP layout:
964 * vertices[1] = (-1,+1, 0) tri 0: verts 0-1-2
965 * vertices[2] = (+1,-1, 0) tri 1: verts 1-2-3
966 * vertices[3] = (+1,+1, 0)
967 * indices: 0 1 2 3
968 *
969 * Instance buffer layouts are IDENTICAL to the non-impostor counterparts
970 * (ATOM_BUFF_SIZE, CYLI_BUFF_SIZE, CAPS_BUFF_SIZE) so no changes are needed
971 * to the buffer-filling code in d_*.c.
972 * ===========================================================================*/
973
974/* --------------------------------------------------------------------------
975 * Sphere impostor – vertex shader
976 * Build a camera-aligned billboard quad that tightly covers the projected
977 * sphere footprint. All work is done in view space; m_proj is used for
978 * the final clip-space position.
979 * --------------------------------------------------------------------------*/
980const GLchar * sphere_vertex_ray = GLSL(
981 uniform mat4 m_view;
982 uniform mat4 m_proj;
983 uniform int view_is_ortho;
984
985 in vec3 vert; /* billboard corner: (-1,-1,0)…(+1,+1,0) */
986 in vec3 offset; /* sphere center, world space (from instance data) */
987 in float radius; /* sphere radius (from instance data) */
988 in vec4 vertColor; /* RGBA color (from instance data) */
989
990 out vec4 surfaceColor;
991 out vec3 surfacePosition;
992 out vec3 imp_a; /* sphere center, view space */
993 out vec3 imp_b; /* unused for sphere – set to 0 */
994 out float imp_r; /* sphere radius (world-space units) */
995 flat out int form_type; /* 0 = sphere */
996 flat out float clip_r_a; /* sphere clip radius at imp_a endpoint (0 for non-cylinders) */
997 flat out float clip_r_b; /* sphere clip radius at imp_b endpoint (0 for non-cylinders) */
998
999 void main ()
1000 {
1001 surfaceColor = vertColor;
1002
1003 /* Sphere centre in view space */
1004 vec3 center_vs = vec3(m_view * vec4(offset, 1.0));
1005
1006 /* View-space radius with scale correction */
1007 float r_vs = radius * length(mat3(m_view) * vec3(1.0, 0.0, 0.0));
1008
1009 /* Billboard quad shifted forward to be in front of the sphere focal plane,
1010 and inflated by 2.0x to cover perspective distortion at screen edges. */
1011 // vec3 billboard_vs = center_vs + (2.0 * r_vs) * vec3(vert.x, vert.y, 1.0);
1012
1013 float inflation = (view_is_ortho == 0) ? 1.05 : 2.0;
1014 vec3 billboard_vs = center_vs + (inflation * r_vs) * vec3(vert.x, vert.y, 1.0);
1015
1016 surfacePosition = billboard_vs;
1017
1018 imp_a = center_vs;
1019 imp_b = vec3(0.0);
1020 imp_r = r_vs;
1021 form_type = 0;
1022 clip_r_a = 0.0; /* spheres have no clipping */
1023 clip_r_b = 0.0;
1024 gl_Position = m_proj * vec4(billboard_vs, 1.0);
1025 gl_Position.z = max(gl_Position.z, -gl_Position.w);
1026 }
1027);
1028
1029/* --------------------------------------------------------------------------
1030 * Cylinder impostor – vertex shader
1031 * Build a tight axis-aligned bounding-box billboard from the two cylinder
1032 * endpoints (reconstructed from instance data).
1033 * --------------------------------------------------------------------------*/
1034const GLchar * cylinder_vertex_ray = GLSL(
1035 uniform mat4 m_view;
1036 uniform mat4 m_proj;
1037 uniform int view_is_ortho;
1038
1039 in vec4 quat; /* rotation quaternion {w,x,y,z} */
1040 in float height; /* full cylinder length (from instance data) */
1041 in float radius; /* cylinder radius */
1042 in vec3 offset; /* cylinder midpoint, world space */
1043 in vec3 vert; /* billboard corner: (-1,-1,0)…(+1,+1,0) */
1044 in vec4 vertColor;
1045 /* Sphere clip radii at the two cylinder endpoints (CYLI_BUFF_SIZE+2 layout).
1046 r_sphere_a = sphere radius at the atom-side endpoint (imp_a / local z=+0.5h).
1047 r_sphere_b = sphere radius at the midpoint-side endpoint (0.0 for half-bonds). */
1048 in float r_sphere_a;
1049 in float r_sphere_b;
1050
1051 out vec4 surfaceColor;
1052 out vec3 surfacePosition;
1053 out vec3 imp_a; /* endpoint p1, view space */
1054 out vec3 imp_b; /* endpoint p2, view space */
1055 out float imp_r; /* view-space radius */
1056 flat out int form_type; /* 1 = cylinder */
1057 flat out float clip_r_a; /* passed through to fragment for endpoint clipping */
1058 flat out float clip_r_b;
1059
1060 vec3 rotate_this (in vec3 v, in vec4 q)
1061 {
1062 vec3 u = vec3(q.x, q.y, q.z);
1063 float s = q.w;
1064 return 2.0 * dot(u, v) * u + (s*s - dot(u, u)) * v + 2.0 * s * cross(u, v);
1065 }
1066
1067 void main ()
1068 {
1069 surfaceColor = vertColor;
1070
1071 /* Reconstruct world-space endpoints from instance data */
1072 vec3 local_p1 = vec3(0.0, 0.0, 0.5 * height);
1073 vec3 local_p2 = vec3(0.0, 0.0, -0.5 * height);
1074 if (quat.w != 0.0)
1075 {
1076 local_p1 = rotate_this(local_p1, quat);
1077 local_p2 = rotate_this(local_p2, quat);
1078 }
1079 vec3 p1_vs = vec3(m_view * vec4(offset + local_p1, 1.0));
1080 vec3 p2_vs = vec3(m_view * vec4(offset + local_p2, 1.0));
1081
1082 /* View-space radius with scale correction */
1083 float r_vs = radius * length(mat3(m_view) * vec3(1.0, 0.0, 0.0));
1084
1085 /* Dual-endpoint perspective-aware inflation */
1086 float inflation = (view_is_ortho == 0) ? 1.05 : 2.0;
1087 float r_vs_bb = inflation * r_vs;
1088
1089 /* View-space AABB of both endpoint discs */
1090 float xmin = min(p1_vs.x, p2_vs.x) - r_vs_bb;
1091 float xmax = max(p1_vs.x, p2_vs.x) + r_vs_bb;
1092 float ymin = min(p1_vs.y, p2_vs.y) - r_vs_bb;
1093 float ymax = max(p1_vs.y, p2_vs.y) + r_vs_bb;
1094 float z_bb = max(p1_vs.z, p2_vs.z) + r_vs_bb;
1095
1096 float bx = mix(xmin, xmax, (vert.x + 1.0) * 0.5);
1097 float by = mix(ymin, ymax, (vert.y + 1.0) * 0.5);
1098 vec3 billboard_vs = vec3(bx, by, z_bb);
1099
1100 surfacePosition = billboard_vs;
1101
1102 imp_a = p1_vs;
1103 imp_b = p2_vs;
1104 imp_r = r_vs;
1105 form_type = 1;
1106 /* Pass sphere clip radii to the fragment shader.
1107 clip_r_a is scaled to view space the same way as imp_r. */
1108 float r_scale = length(mat3(m_view) * vec3(1.0, 0.0, 0.0));
1109 clip_r_a = r_sphere_a * r_scale;
1110 clip_r_b = r_sphere_b * r_scale;
1111
1112 gl_Position = m_proj * vec4(billboard_vs, 1.0);
1113 gl_Position.z = max(gl_Position.z, -gl_Position.w);
1114 }
1115);
1116
1117/* --------------------------------------------------------------------------
1118 * Cone impostor – vertex shader
1119 * Same as cylinder impostor but accounts for the asymmetric radii:
1120 * ra = 0 at p1 (apex, local z = +0.5·height), rb = radius at p2 (base).
1121 * --------------------------------------------------------------------------*/
1122const GLchar * cone_vertex_ray = GLSL(
1123 uniform mat4 m_view;
1124 uniform mat4 m_proj;
1125 uniform int view_is_ortho;
1126
1127 in vec4 quat;
1128 in float height;
1129 in float radius; /* base radius; apex radius is 0 */
1130 in vec3 offset;
1131 in vec3 vert;
1132 in vec4 vertColor;
1133
1134 out vec4 surfaceColor;
1135 out vec3 surfacePosition;
1136 out vec3 imp_a; /* apex, view space */
1137 out vec3 imp_b; /* base center, view space */
1138 out float imp_r; /* base radius, view space */
1139 flat out int form_type; /* 3 = cone */
1140 flat out float clip_r_a; /* 0.0 – cones are arrowheads, no sphere junction */
1141 flat out float clip_r_b;
1142
1143 vec3 rotate_this (in vec3 v, in vec4 q)
1144 {
1145 vec3 u = vec3(q.x, q.y, q.z);
1146 float s = q.w;
1147 return 2.0 * dot(u, v) * u + (s*s - dot(u, u)) * v + 2.0 * s * cross(u, v);
1148 }
1149
1150 void main ()
1151 {
1152 surfaceColor = vertColor;
1153
1154 /* p1 = apex (ra=0, local z=+0.5h), p2 = base (rb=radius, local z=-0.5h) */
1155 vec3 local_apex = vec3(0.0, 0.0, 0.5 * height);
1156 vec3 local_base = vec3(0.0, 0.0, -0.5 * height);
1157 if (quat.w != 0.0)
1158 {
1159 local_apex = rotate_this(local_apex, quat);
1160 local_base = rotate_this(local_base, quat);
1161 }
1162 vec3 p_apex_vs = vec3(m_view * vec4(offset + local_apex, 1.0));
1163 vec3 p_base_vs = vec3(m_view * vec4(offset + local_base, 1.0));
1164
1165 float r_vs = radius * length(mat3(m_view) * vec3(1.0, 0.0, 0.0));
1166
1167 float inflation = (view_is_ortho == 0) ? 1.05 : 2.0;
1168 float r_vs_bb = inflation * r_vs;
1169
1170 /* Asymmetric AABB: apex contributes radius 0, base contributes r_vs_bb */
1171 float xmin = min(p_apex_vs.x, p_base_vs.x - r_vs_bb);
1172 float xmax = max(p_apex_vs.x, p_base_vs.x + r_vs_bb);
1173 float ymin = min(p_apex_vs.y, p_base_vs.y - r_vs_bb);
1174 float ymax = max(p_apex_vs.y, p_base_vs.y + r_vs_bb);
1175 /* z: front face = closest of apex/base z + base radius (conservative bound). */
1176 float z_bb = max(p_apex_vs.z, p_base_vs.z) + r_vs_bb;
1177
1178 // float bx = (vert.x > 0.0) ? xmax : xmin;
1179 // float by = (vert.y > 0.0) ? ymax : ymin;
1180 float bx = mix(xmin, xmax, (vert.x + 1.0) * 0.5);
1181 float by = mix(ymin, ymax, (vert.y + 1.0) * 0.5);
1182 vec3 billboard_vs = vec3(bx, by, z_bb);
1183
1184 surfacePosition = billboard_vs;
1185
1186 /* imp_a = apex, imp_b = base centre (matches intersect_cone convention) */
1187 imp_a = p_apex_vs;
1188 imp_b = p_base_vs;
1189 imp_r = r_vs;
1190 form_type = 3;
1191 clip_r_a = 0.0;
1192 clip_r_b = 0.0;
1193
1194 gl_Position = m_proj * vec4(billboard_vs, 1.0);
1195 gl_Position.z = max(gl_Position.z, -gl_Position.w);
1196 }
1197);
1198
1199/* --------------------------------------------------------------------------
1200 * Cap impostor – vertex shader
1201 * A cap is a flat disk; its impostor is a square billboard centered on the
1202 * disk center with half-side = radius.
1203 * --------------------------------------------------------------------------*/
1204const GLchar * cap_vertex_ray = GLSL(
1205 uniform mat4 m_view;
1206 uniform mat4 m_proj;
1207 uniform int view_is_ortho;
1208
1209 in vec4 quat;
1210 in float radius;
1211 in vec3 offset; /* cap center, world space */
1212 in vec3 vert; /* billboard corner */
1213 in vec4 vertColor;
1214
1215 out vec4 surfaceColor;
1216 out vec3 surfacePosition;
1217 out vec3 imp_a; /* cap center, view space */
1218 out vec3 imp_b; /* cap normal, view space */
1219 out float imp_r; /* cap radius */
1220 flat out int form_type; /* 2 = cap */
1221 flat out float clip_r_a; /* 0.0 – caps are at midpoints, no sphere junction */
1222 flat out float clip_r_b;
1223
1224 vec3 rotate_this (in vec3 v, in vec4 q)
1225 {
1226 vec3 u = vec3(q.x, q.y, q.z);
1227 float s = q.w;
1228 return 2.0 * dot(u, v) * u + (s*s - dot(u, u)) * v + 2.0 * s * cross(u, v);
1229 }
1230
1231 void main ()
1232 {
1233 surfaceColor = vertColor;
1234 vec3 center_vs = vec3(m_view * vec4(offset, 1.0));
1235
1236 /* Normal of the disk in view space */
1237 vec3 norm_local = vec3(0.0, 0.0, -1.0);
1238 if (quat.w != 0.0) norm_local = rotate_this(norm_local, quat);
1239 vec3 norm_vs = normalize (mat3(m_view) * norm_local);
1240
1241 float r_vs = radius * length(mat3(m_view) * vec3(1.0, 0.0, 0.0));
1242 float inflation = (view_is_ortho == 0) ? 1.05 : 2.0;
1243
1244 /* Camera-aligned square billboard, inflated for robustness. */
1245 vec3 billboard_vs = center_vs + (inflation * r_vs) * vec3(vert.x, vert.y, 1.0);
1246
1247 surfacePosition = billboard_vs;
1248
1249 imp_a = center_vs;
1250 imp_b = norm_vs;
1251 imp_r = r_vs;
1252 form_type = 2;
1253 clip_r_a = 0.0;
1254 clip_r_b = 0.0;
1255
1256 gl_Position = m_proj * vec4(billboard_vs, 1.0);
1257 gl_Position.z = max(gl_Position.z, -gl_Position.w);
1258 }
1259);
1260
1261/* --------------------------------------------------------------------------
1262 * Perfect-impostor fragment shader.
1263 * --------------------------------------------------------------------------*/
1264const GLchar * full_color_ray = GLSL(
1265
1266 int PHONG = 1;
1267 int BLINN = 2;
1268 int COOK_BLINN = 3;
1269 int COOK_BECKMANN = 4;
1270 int COOK_GGX = 5;
1271
1272 struct Light {
1273 int type;
1274 vec3 position;
1275 vec3 direction;
1276 vec3 intensity;
1277 float constant;
1278 float linear;
1279 float quadratic;
1280 float cone_angle;
1281 float spot_inner;
1282 float spot_outer;
1283 };
1284
1285 struct Material {
1286 vec3 albedo;
1287 float metallic;
1288 float roughness;
1289 float ambient_occlusion;
1290 float gamma;
1291 float alpha;
1292 };
1293
1294 struct Fog {
1295 int mode;
1296 int based;
1297 float density;
1298 vec2 depth;
1299 vec3 color;
1300 };
1301
1302 struct Hit {
1303 vec3 pos;
1304 vec3 normal;
1305 };
1306
1307 uniform Light AllLights[10];
1308 uniform Material mat;
1309 uniform Fog fog;
1310 uniform int lights_on;
1311 uniform int numLights;
1312 uniform int view_is_ortho;
1313 uniform mat4 m_proj;
1314
1315 in vec4 surfaceColor;
1316 in vec3 surfacePosition;
1317
1318 // Standardized Raytracing parameters
1319 in vec3 imp_a;
1320 in vec3 imp_b;
1321 in float imp_r;
1322 flat in int form_type;
1323 /* Sphere clip radii at the two cylinder endpoints (passed from cylinder_vertex_ray).
1324 Non-zero only for cylinders (form_type==1). When a cylinder hit lies inside the
1325 sphere at either endpoint, the fragment is discarded — the sphere impostor handles
1326 that region. This eliminates z-fighting at sphere/cylinder junctions without any
1327 depth bias, which would break 3D depth perception. */
1328 flat in float clip_r_a;
1329 flat in float clip_r_b;
1330
1331 out vec4 fragment_color;
1332
1333 const float PI = 3.14159265359;
1334 const float EPS = 1e-5;
1335
1336 // clamping to 0 - 1 range
1337 float saturate (in float value)
1338 {
1339 return clamp(value, 0.0, 1.0);
1340 }
1341
1342 // phong (lambertian) diffuse term
1343 float phong_diffuse()
1344 {
1345 return (1.0 / PI);
1346 }
1347
1348 // compute Fresnel specular factor for given base specular and product
1349 // product could be NdV or VdH depending on used technique
1350 vec3 fresnel_factor (in vec3 f0, in float product)
1351 {
1352 return mix(f0, vec3(1.0), pow(1.01 - product, 5.0));
1353 }
1354
1355 // following functions are copies of UE4
1356 // for computing Cook-Torrance specular lighting terms
1357
1358 float D_blinn(in float roughness, in float NdH)
1359 {
1360 float m = roughness * roughness;
1361 float m2 = m * m;
1362 float n = 2.0 / m2 - 2.0;
1363 return (n + 2.0) / (2.0 * PI) * pow(NdH, n);
1364 }
1365
1366 float D_beckmann(in float roughness, in float NdH)
1367 {
1368 float m = roughness * roughness;
1369 float m2 = m * m;
1370 float NdH2 = NdH * NdH;
1371 return exp((NdH2 - 1.0) / (m2 * NdH2)) / (PI * m2 * NdH2 * NdH2);
1372 }
1373
1374 float D_GGX(in float roughness, in float NdH)
1375 {
1376 float m = roughness * roughness;
1377 float m2 = m * m;
1378 float d = (NdH * m2 - NdH) * NdH + 1.0;
1379 return m2 / (PI * d * d);
1380 }
1381
1382 float G_schlick(in float roughness, in float NdV, in float NdL)
1383 {
1384 float k = roughness * roughness * 0.5;
1385 float V = NdV * (1.0 - k) + k;
1386 float L = NdL * (1.0 - k) + k;
1387 return 0.25 / (V * L);
1388 }
1389
1390 // simple Phong specular calculation with normalization
1391 vec3 phong_specular(in vec3 V, in vec3 L, in vec3 N, in vec3 specular, in float roughness)
1392 {
1393 vec3 R = reflect(-L, N);
1394 float spec = max(0.0, dot(V, R));
1395
1396 float k = 1.999 / (roughness * roughness);
1397
1398 return min(1.0, 3.0 * 0.0398 * k) * pow(spec, min(10000.0, k)) * specular;
1399 }
1400
1401 // simple Blinn specular calculation with normalization
1402 vec3 blinn_specular(in float NdH, in vec3 specular, in float roughness)
1403 {
1404 float k = 1.999 / (roughness * roughness);
1405
1406 return min(1.0, 3.0 * 0.0398 * k) * pow(NdH, min(10000.0, k)) * specular;
1407 }
1408
1409 // Cook-Torrance specular calculation
1410 vec3 cooktorrance_specular (in int cook, in float NdL, in float NdV, in float NdH, in vec3 specular, in float roughness)
1411 {
1412 float D;
1413 if (cook == COOK_BLINN)
1414 {
1415 D = D_blinn(roughness, NdH);
1416 }
1417 else if (cook == COOK_BECKMANN)
1418 {
1419 D = D_beckmann(roughness, NdH);
1420 }
1421 else if (cook == COOK_GGX)
1422 {
1423 D = D_GGX(roughness, NdH);
1424 }
1425
1426 float G = G_schlick(roughness, NdV, NdL);
1427
1428 float rim = mix(1.0 - roughness * 0.9, 1.0, NdV);
1429
1430 return (1.0 / rim) * specular * G * D;
1431 }
1432
1433 vec3 Apply_lighting_model (in int model, in Light light, in vec3 specular, in vec3 v_pos, in vec3 N)
1434 {
1435 // L, V, H vectors
1436 vec3 L;
1437 float A;
1438 float I = 1.0;
1439 if (light.type == 0)
1440 {
1441 // Directional light
1442 L = normalize (-light.direction);
1443 A = 1.0;
1444 }
1445 else
1446 {
1447 L = light.position - v_pos;
1448 float dist = length (L);
1449 L = normalize(L);
1450 A = 1.0 / (light.constant + light.linear*dist + light.quadratic*dist*dist);
1451 if (light.type == 2)
1452 {
1453 float theta = dot(L, normalize(light.position-light.direction));
1454 if(theta > light.cone_angle)
1455 {
1456 float epsilon = light.spot_inner - light.spot_outer;
1457 I = saturate((theta - light.spot_outer) / epsilon);
1458 }
1459 else
1460 {
1461 return vec3(0.0001);
1462 }
1463 }
1464 }
1465 vec3 V = normalize(-v_pos);
1466 vec3 H = normalize(L + V);
1467
1468 // compute material reflectance
1469 float NdL = max(0.0, dot(N, L));
1470 float NdV = max(0.001, dot(N, V));
1471 float NdH = max(0.001, dot(N, H));
1472 float HdV = max(0.001, dot(H, V));
1473 float LdV = max(0.001, dot(L, V));
1474
1475 // Fresnel term is common for any, except Phong
1476 // so it will be calculated inside ifdefs
1477 vec3 specfresnel;
1478 vec3 specref;
1479 if (model == PHONG)
1480 {
1481 // specular reflectance with Phong
1482 specfresnel = fresnel_factor (specular, NdV);
1483 specref = phong_specular (V, L, N, specfresnel, mat.roughness);
1484 }
1485 else if (model == BLINN)
1486 {
1487 // specular reflectance with Blinn
1488 specfresnel = fresnel_factor (specular, HdV);
1489 specref = blinn_specular (NdH, specfresnel, mat.roughness);
1490 }
1491 else
1492 {
1493 // specular reflectance with Cook-Torrance
1494 specfresnel = fresnel_factor(specular, HdV);
1495 specref = cooktorrance_specular (model, NdL, NdV, NdH, specfresnel, mat.roughness);
1496 }
1497
1498 specref *= vec3(NdL);
1499
1500 // diffuse is common for any model
1501 vec3 diffref = (vec3(1.0) - specfresnel) * phong_diffuse() * NdL;
1502
1503 // compute lighting
1504 vec3 reflected_light = vec3(0);
1505 vec3 diffuse_light = vec3(0); // initial value == constant ambient light
1506
1507 // point light
1508 vec3 light_color = light.intensity * A * I;
1509 reflected_light += specref * light_color;
1510 diffuse_light += diffref * light_color;
1511
1512 // final result
1513 return diffuse_light * mix(mat.albedo, vec3(0.0), mat.metallic) + reflected_light;
1514 }
1515
1516 vec3 Apply_fog (in vec3 lightColor, in vec3 v_pos, in vec3 normal)
1517 {
1518 // distance
1519 float dist = 0.0;
1520 float fogFactor = 0.0;
1521
1522 // compute distance used in fog equations
1523 if (fog.based == 0)
1524 {
1525 // plane based
1526 dist = abs (v_pos.z);
1527 }
1528 else
1529 {
1530 // range based
1531 dist = length (v_pos);
1532 }
1533
1534 if (fog.mode == 1) // linear fog
1535 {
1536 fogFactor = (fog.depth.x - dist)/(fog.depth.y - fog.depth.x);
1537 }
1538 else if (fog.mode == 2) // exponential fog
1539 {
1540 fogFactor = 1.0 / exp (dist * fog.density);
1541 }
1542 else
1543 {
1544 fogFactor = 1.0 / exp((dist * fog.density)* (dist * fog.density));
1545 }
1546 fogFactor = saturate (fogFactor);
1547
1548 //float viewAngle = dot(normalize(-v_pos), normalize(normal));
1549 // fogFactor *= mix(0.7, 1.0, viewAngle);
1550
1551 return mix (fog.color, lightColor, fogFactor);
1552 }
1553
1554 bool intersect_sphere(vec3 ro, vec3 rd, vec3 c, float r, out Hit hit)
1555 {
1556 vec3 oc = ro - c;
1557 vec3 cr = cross(rd, oc);
1558 float d2 = dot(cr, cr);
1559
1560 float r2 = r*r;
1561 if (d2 > r2) return false;
1562
1563 float tca = -dot(oc, rd);
1564 float thc = sqrt(r2 - d2);
1565
1566 float t = tca - thc;
1567 if (t < EPS) t = tca + thc;
1568 if (t < EPS) return false;
1569
1570 hit.pos = ro + rd*t;
1571 hit.normal = normalize(hit.pos - c);
1572 return true;
1573 }
1574
1575 // Numerically stable cylinder intersection via cross products.
1576 bool intersect_cylinder(vec3 ro, vec3 rd, vec3 pa, vec3 pb, float ra, out Hit hit)
1577 {
1578 vec3 ba = pb - pa;
1579 vec3 oc = ro - pa;
1580
1581 float baba = dot(ba, ba);
1582 float bard = dot(ba, rd);
1583 float baoc = dot(ba, oc);
1584
1585 vec3 vb = cross(rd, ba);
1586 vec3 va = cross(oc, ba);
1587
1588 float k2 = dot(vb, vb);
1589 if (k2 < 1e-10) return false; // Parallel to axis off-center
1590
1591 float k1 = dot(va, vb);
1592 float k0 = dot(va, va) - ra * ra * baba;
1593
1594 float h = k1 * k1 - k2 * k0;
1595 if (h < 0.0) return false;
1596
1597 h = sqrt(h);
1598 float t = (-k1 - h) / k2;
1599 if (t < EPS) t = (-k1 + h) / k2;
1600 if (t < EPS) return false;
1601
1602 float y = baoc + t * bard;
1603 if (y > -EPS && y < baba + EPS)
1604 {
1605 hit.pos = ro + t * rd;
1606 hit.normal = normalize((hit.pos - pa) * baba - ba * y);
1607 return true;
1608 }
1609 return false;
1610 }
1611
1612 bool intersect_cone(vec3 ro, vec3 rd, vec3 pa, vec3 pb, float ra, out Hit hit)
1613 {
1614 vec3 ba = pb - pa;
1615 vec3 oa = ro - pa;
1616
1617 float m0 = dot(ba,ba);
1618 float m1 = dot(oa,ba);
1619 float m2 = dot(rd,ba);
1620
1621 if (m0 < 1e-6) return false;
1622
1623 float k = (ra*ra) / m0;
1624 float m = dot(rd,ba)/m0; // ~ cos angle of ray with axis
1625 float n = dot(oa,ba)/m0;
1626 float a = dot(rd,rd) - m2*m2*(1.0+k)/m0;
1627 float b = dot(rd,oa) - m2*m1*(1.0+k)/m0;
1628 float c = dot(oa,oa) - m1*m1*(1.0+k)/m0;
1629
1630 float h = b*b - a*c;
1631 if (h < 0.0) return false;
1632
1633 h = sqrt(h);
1634
1635 float t1 = (-b - h)/a;
1636 float t2 = (-b + h)/a;
1637 float t = 1e20;
1638
1639 if (t1 > EPS) t = t1;
1640 if (t2 > EPS && t2 < t) t = t2;
1641
1642 if (t == 1e20) return false;
1643
1644 float y = m1 + t*m2;
1645
1646 if (y > -EPS && y < m0 + EPS)
1647 {
1648 hit.pos = ro + t * rd;
1649 hit.normal = normalize(m0*(hit.pos-pa) - ba*(1.0+k)*y);
1650 return true;
1651 }
1652 return false;
1653 }
1654
1655 bool intersect_cap(vec3 ro, vec3 rd, vec3 center, vec3 normal, float radius, out Hit hit)
1656 {
1657 float denom = dot(normal, rd);
1658 if (abs(denom) < 1e-6) return false;
1659
1660 float t = dot(center - ro, normal) / denom;
1661 if (t < EPS) return false;
1662
1663 vec3 p = ro + t * rd;
1664 vec3 v = p - center;
1665 if (dot(v, v) > radius * radius) return false;
1666
1667 hit.pos = p;
1668 hit.normal = normal;
1669 // Orient normal towards ray
1670 if (dot(hit.normal, rd) > 0.0) hit.normal = -hit.normal;
1671
1672 return true;
1673 }
1674
1675 bool intersect_scene(vec3 ro, vec3 rd, out Hit hit)
1676 {
1677 if (form_type == 0) // Sphere
1678 {
1679 return intersect_sphere(ro, rd, imp_a, imp_r, hit);
1680 }
1681 else if (form_type == 1) // Cylinder
1682 {
1683 return intersect_cylinder(ro, rd, imp_a, imp_b, imp_r, hit);
1684 }
1685 else if (form_type == 2) // Cap
1686 {
1687 return intersect_cap(ro, rd, imp_a, imp_b, imp_r, hit);
1688 }
1689 else if (form_type == 3) // Cone
1690 {
1691 return intersect_cone(ro, rd, imp_a, imp_b, imp_r, hit);
1692 }
1693 return false;
1694 }
1695
1696 float computeAO(vec3 pos, vec3 N)
1697 {
1698 const int AO_SAMPLES = 16;
1699 const float EPS_AO = 0.001;
1700
1701 float maxDist = imp_r * 8.0;
1702 float occlusion = 0.0;
1703 vec3 tangent = normalize(abs(N.x) > 0.5 ? cross(N, vec3(0,1,0)) : cross(N, vec3(1,0,0)));
1704 vec3 bitangent = cross(N, tangent);
1705
1706 for(int i = 0; i < AO_SAMPLES; i++)
1707 {
1708 float u = float(i)/float(AO_SAMPLES);
1709 float v = fract(sin(float(i)*91.345) * 47453.545);
1710
1711 float phi = 2.0 * PI * v;
1712 float cosTheta = sqrt(1.0 - u);
1713 float sinTheta = sqrt(u);
1714 vec3 dir = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
1715
1716 // passage dans l’espace du tangent
1717 dir = normalize(dir.x*tangent + dir.y*bitangent + dir.z*N);
1718
1719 Hit tmp;
1720 if(intersect_scene(pos + N * EPS_AO, dir, tmp))
1721 {
1722 float dist = length(tmp.pos - pos);
1723 // float weight = 1.0 - saturate(dist / maxDist);
1724 float weight = exp(-dist * 2.0 / maxDist);
1725 occlusion += weight;
1726 }
1727 }
1728
1729 float ao = 1.0 - (occlusion / float(AO_SAMPLES));
1730 ao = pow(ao, mat.gamma); // softening
1731 // Safety clamp between 0.0 and 1.0
1732 return saturate(ao);
1733 }
1734
1735 float ray_computeAO(vec3 N)
1736 {
1737 // Up orientation (Y is the up vector)
1738 float ao = 0.5 + 0.5 * N.y;
1739
1740 // Softening
1741 ao = pow(ao, mat.gamma);
1742
1743 // Safety clamp between 0.0 and 1.0
1744 return saturate(ao);
1745 }
1746
1747 void main ()
1748 {
1749 /* Ray from camera origin through billboard fragment (view space) */
1750 vec3 surfaceToCamera = normalize(-surfacePosition);
1751 vec3 ray_origin = surfacePosition;
1752 vec3 ray_dir;
1753 if (view_is_ortho == 0)
1754 {
1755 ray_dir = vec3(0.0, 0.0, -1.0); // Parallel rays (Orthographic)
1756 }
1757 else
1758 {
1759 ray_dir = normalize(surfacePosition); // Perspective
1760 }
1761 Hit the_hit;
1762 bool hit = false;
1763
1764 hit = intersect_scene (ray_origin, ray_dir, the_hit);
1765
1766 if (! hit) discard;
1767 if (dot(the_hit.normal, surfaceToCamera) < 0.0) the_hit.normal = -the_hit.normal;
1768
1769 /* Sphere-entry clipping for cylinders (form_type == 1):
1770 discard cylinder pixels that lie inside the sphere at each endpoint,
1771 so the sphere impostor has exclusive ownership of those pixels.
1772 This eliminates z-fighting at sphere/cylinder junctions analytically,
1773 with no depth bias that would break 3D depth perception. */
1774 const float CLIP_MARGIN = 1.00f; // Optional extra margin
1775 if (clip_r_a > 0.0)
1776 {
1777 float r_clip = clip_r_a * CLIP_MARGIN;
1778 if (dot(the_hit.pos - imp_a, the_hit.pos - imp_a) < r_clip * r_clip) discard;
1779 }
1780 if (clip_r_b > 0.0)
1781 {
1782 float r_clip = clip_r_b * CLIP_MARGIN;
1783 if (dot(the_hit.pos - imp_b, the_hit.pos - imp_b) < r_clip * r_clip) discard;
1784 }
1785
1786 vec4 hit_clip = m_proj * vec4(the_hit.pos, 1.0);
1787 if (hit_clip.w <= 0.0) discard;
1788 gl_FragDepth = clamp((hit_clip.z / hit_clip.w + 1.0) * 0.5, 0.0, 1.0);
1789
1790 /* Lighting */
1791 vec3 color;
1792 float alpha;
1793 if (lights_on == 0)
1794 {
1795 color = vec3(1.0);
1796 alpha = surfaceColor.w;
1797 }
1798 else
1799 {
1800 // mix between metal and non-metal material, for non-metal
1801 // constant base specular factor of 0.04 grey is used
1802 vec3 specular = mix(vec3(0.04), mat.albedo, mat.metallic);
1803 color = vec3(0.0);
1804 vec3 diffuse = vec3(0.0);
1805 int i;
1806 for(i = 0; i < numLights; i++)
1807 {
1808 diffuse += Apply_lighting_model (lights_on, AllLights[i], specular, the_hit.pos, the_hit.normal);
1809 }
1810 float ao = computeAO (the_hit.pos, the_hit.normal) * ray_computeAO (the_hit.normal);
1811
1812 diffuse *= (ao * mat.ambient_occlusion);
1813 vec3 lit_color = pow(diffuse,vec3(1.0/mat.gamma));
1814 color = surfaceColor.rgb*lit_color;
1815 alpha = surfaceColor.w*mat.alpha;
1816 }
1817
1818 if (fog.mode > 0)
1819 {
1820 vec3 col = Apply_fog(color, the_hit.pos, the_hit.normal);
1821 fragment_color = vec4 (col * alpha, alpha);
1822 }
1823 else
1824 {
1825 fragment_color = vec4 (color * alpha, alpha);
1826 }
1827 }
1828);
1829
1830/* ===========================================================================
1831 * End of perfect-impostor shaders
1832 * ===========================================================================*/
1833
1834const GLchar * angstrom_vertex = GLSL(
1835 uniform mat4 mvp;
1836 uniform mat4 un_view;
1837 uniform mat4 text_proj;
1838 uniform vec4 viewp;
1839 uniform vec4 pos_shift;
1840 uniform int tilted;
1841
1842 in vec2 vert;
1843 in vec2 tcoord;
1844 in vec3 offset;
1845 in vec3 at_a;
1846 in vec3 at_b;
1847
1848 out vec2 text_coords;
1849
1850 float angle2d (in vec2 at, in vec2 bt, in vec2 ct)
1851 {
1852 vec2 ab = bt - at;
1853 vec2 bc = bt - ct;
1854 float theta = dot(ab,bc) / (length(ab) * length(bc));
1855 if (theta < -1.0)
1856 {
1857 return acos (-2.0 - theta);
1858 }
1859 else if (theta > 1.0)
1860 {
1861 return acos (2.0 - theta);
1862 }
1863 else
1864 {
1865 return acos (theta);
1866 }
1867 }
1868
1869 mat4 rotate_this_z (in float theta)
1870 {
1871 return mat4 ( vec4( cos(theta), sin(theta), 0.0, 0.0),
1872 vec4(-sin(theta), cos(theta), 0.0, 0.0),
1873 vec4( 0.0, 0.0, 1.0, 0.0),
1874 vec4( 0.0, 0.0, 0.0, 1.0));
1875 }
1876
1877 mat4 translate_this (in vec3 coord)
1878 {
1879 mat4 translate;
1880 translate[0] = vec4(1.0, 0.0, 0.0, 0.0);
1881 translate[1] = vec4(0.0, 1.0, 0.0, 0.0);
1882 translate[2] = vec4(0.0, 0.0, 1.0, 0.0);
1883 translate[3][0] = coord.x;
1884 translate[3][1] = coord.y;
1885 translate[3][2] = coord.z;
1886 translate[3][3] = 1.0;
1887
1888 return translate;
1889 }
1890
1891 vec4 project (in vec3 coord, vec4 shift)
1892 {
1893 mat4 n_mvp = mvp * translate_this (coord) * un_view;
1894 vec4 res = n_mvp * vec4(vec3(0.0), 1.0);
1895 res = translate_this (vec3(shift.x/viewp.z, shift.y/viewp.w, shift.z)) * res;
1896 if (res.w != 0.0)
1897 {
1898 res.w = 1.0 / res.w;
1899 res.x = res.w * res.x + 1.0;
1900 res.y = res.w * res.y + 1.0;
1901 res.z = res.w * res.z + 1.0;
1902 return vec4 (res.x*viewp.z+viewp.x, res.y*viewp.w+viewp.y, shift.w*res.z, 1.0);
1903 }
1904 else
1905 {
1906 return vec4 (0.0, 0.0, -1.0, 0.0);
1907 }
1908 }
1909
1910 void main()
1911 {
1912 text_coords = tcoord;
1913 float rot_angle = 0.0;
1914 vec4 shift = pos_shift;
1915 if (tilted > 0)
1916 {
1917 vec3 pos_a = project (at_a, vec4(0.0)).xyz;
1918 vec3 pos_b = project (at_b, vec4(0.0)).xyz;
1919 vec2 pa;
1920 vec2 pb;
1921 vec2 pc;
1922 pa.y = max(pos_a.y, pos_b.y);
1923 if (pa.y == pos_a.y)
1924 {
1925 pa.x = pos_a.x;
1926 pb.x = pos_b.x;
1927 pb.y = pos_b.y;
1928 }
1929 else
1930 {
1931 pa.x = pos_b.x;
1932 pb.x = pos_a.x;
1933 pb.y = pos_a.y;
1934 }
1935 pc.x = pa.x;
1936 pc.y = pb.y;
1937 rot_angle = - angle2d (pa, pb, pc);
1938 if (pa.x < pb.x)
1939 {
1940 rot_angle = -rot_angle;
1941 shift.x = -shift.x;
1942 }
1943 }
1944 vec4 pos;
1945 if (rot_angle != 0.0)
1946 {
1947 pos = project(offset, shift) + vec4(vert, 0.0, 1.0) * rotate_this_z(rot_angle);
1948 }
1949 else
1950 {
1951 pos = project(offset, shift) + vec4(vert, 0.0, 1.0);
1952 }
1953 gl_Position = text_proj * pos;
1954 }
1955);
1956
1957const GLchar * degree_vertex = GLSL(
1958 uniform mat4 mvp;
1959 uniform mat4 un_view;
1960 uniform mat4 text_proj;
1961 uniform vec4 viewp;
1962 uniform vec4 pos_shift;
1963 uniform int tilted;
1964
1965 in vec2 vert;
1966 in vec2 tcoord;
1967 in vec3 offset;
1968 in vec3 at_a;
1969 in vec3 at_b;
1970 in vec3 at_c;
1971
1972 const float PI = 3.14159265359;
1973
1974 out vec2 text_coords;
1975
1976 float angle2d (in vec2 at, in vec2 bt, in vec2 ct)
1977 {
1978 vec2 ab = bt - at;
1979 vec2 bc = bt - ct;
1980 float theta = dot(ab,bc) / (length(ab) * length(bc));
1981 if (theta < -1.0)
1982 {
1983 return acos (-2.0 - theta);
1984 }
1985 else if (theta > 1.0)
1986 {
1987 return acos (2.0 - theta);
1988 }
1989 else
1990 {
1991 return acos (theta);
1992 }
1993 }
1994
1995 mat4 rotate_this_z (in float theta)
1996 {
1997 return mat4 ( vec4( cos(theta), sin(theta), 0.0, 0.0),
1998 vec4(-sin(theta), cos(theta), 0.0, 0.0),
1999 vec4( 0.0, 0.0, 1.0, 0.0),
2000 vec4( 0.0, 0.0, 0.0, 1.0));
2001 }
2002
2003 mat4 translate_this (in vec3 coord)
2004 {
2005 mat4 translate;
2006 translate[0] = vec4(1.0, 0.0, 0.0, 0.0);
2007 translate[1] = vec4(0.0, 1.0, 0.0, 0.0);
2008 translate[2] = vec4(0.0, 0.0, 1.0, 0.0);
2009 translate[3][0] = coord.x;
2010 translate[3][1] = coord.y;
2011 translate[3][2] = coord.z;
2012 translate[3][3] = 1.0;
2013
2014 return translate;
2015 }
2016
2017 vec4 project (in vec3 coord, vec4 shift)
2018 {
2019 mat4 n_mvp = mvp * translate_this (coord) * un_view;
2020 vec4 res = n_mvp * vec4(vec3(0.0), 1.0);
2021 res = translate_this (vec3(shift.x/viewp.z, shift.y/viewp.w, shift.z)) * res;
2022 if (res.w != 0.0)
2023 {
2024 res.w = 1.0 / res.w;
2025 res.x = res.w * res.x + 1.0;
2026 res.y = res.w * res.y + 1.0;
2027 res.z = res.w * res.z + 1.0;
2028 return vec4 (res.x*viewp.z+viewp.x, res.y*viewp.w+viewp.y, shift.w*res.z, 1.0);
2029 }
2030 else
2031 {
2032 return vec4 (0.0, 0.0, -1.0, 0.0);
2033 }
2034 }
2035
2036 void main()
2037 {
2038 text_coords = tcoord;
2039 float rot_angle = 0.0;
2040 vec4 shift = pos_shift;
2041 vec3 pos_a = project (at_a, vec4(0.0)).xyz;
2042 vec3 pos_b = project (at_b, vec4(0.0)).xyz;
2043 vec3 pos_c = project (at_c, vec4(0.0)).xyz;
2044 vec2 pa = pos_a.xy;
2045 vec2 pb = pos_b.xy;
2046 vec2 pc = pos_c.xy;
2047 vec2 pd;
2048 float theta = angle2d (pa, pb, pc);
2049 pd.x = pb.x + 100.0;
2050 pd.y = pb.y;
2051 float alpha;
2052 float beta;
2053 float gamma;
2054 vec2 sign;
2055 sign.x = 1.0;
2056 sign.y = 1.0;
2057
2058 beta = angle2d (pa, pb, pd);
2059 alpha = angle2d (pc, pb, pd);
2060 if (pa.y > pb.y && pc.y > pb.y)
2061 {
2062 gamma = min (alpha, beta);
2063 }
2064 else if (pa.y < pb.y && pc.y < pb.y)
2065 {
2066 gamma = min (-alpha, -beta);
2067 }
2068 else
2069 {
2070 vec2 pe;
2071 vec2 pf;
2072 pe.y = max(pa.y, pc.y);
2073 if (pe.y == pa.y)
2074 {
2075 pe.x = pa.x;
2076 pf.y = pc.y;
2077 pf.x = pc.x;
2078 }
2079 else
2080 {
2081 pe.x = pc.x;
2082 pf.y = pa.y;
2083 pf.x = pa.x;
2084 }
2085 beta = angle2d (pe, pb, pd);
2086 gamma = beta;
2087 alpha = angle2d (pf, pb, pd);
2088 if (beta + alpha < PI)
2089 {
2090 gamma -= theta;
2091 }
2092 }
2093 rot_angle = PI/2.0 - gamma - theta/2.0;
2094 vec3 a = at_b + ((at_a - at_b)/3.0 + (at_c - at_b)/3.0)/2.0;
2095 vec4 b = project (a, shift);
2096 float dist = min(length(pb-pa), length(pb-pc)) / 3.0;
2097 float x = pb.x + (shift.x+dist) * sin(rot_angle);
2098 float y = pb.y + (shift.y+dist) * cos(rot_angle);
2099 if (pa.y < pb.y && pc.y < pb.y)
2100 {
2101 gamma = - max (alpha, beta);
2102 }
2103 else if (pa.y > pb.y || pc.y > pb.y)
2104 {
2105 gamma += PI;
2106 }
2107 rot_angle = PI/2.0 - gamma - theta/2.0;
2108 vec3 c = vec3(x, y, b.z);
2109 vec4 pos = vec4(c, 1.0);
2110 if (tilted > 0)
2111 {
2112 rot_angle += PI;
2113 pos += vec4(vert, 0.0, 1.0) * rotate_this_z(rot_angle);
2114 }
2115 else
2116 {
2117 pos += vec4(vert, 0.0, 1.0);
2118 }
2119 gl_Position = text_proj * pos;
2120 }
2121);
2122
2123const GLchar * string_color = GLSL(
2124 uniform sampler2DRect tex;
2125 uniform vec4 vert_color;
2126 uniform vec4 viewp;
2127 uniform int tilted;
2128 in vec2 text_coords;
2129
2130 out vec4 fragment_color;
2131 void main()
2132 {
2133 vec2 coords = text_coords;
2134 vec4 color = vert_color * vec4(1.0, 1.0, 1.0, texture (tex, text_coords).r);
2135 fragment_color = vec4(color.rgb * color.a, color.a);
2136 }
2137);
2138
2139const GLchar * string_color_2d = GLSL(
2140 uniform sampler2DRect tex;
2141 uniform vec4 vert_color;
2142 in vec2 text_coords;
2143
2144 out vec4 fragment_color;
2145 void main()
2146 {
2147 vec4 sampled = vec4(1.0, 1.0, 1.0, texture (tex, text_coords).r);
2148 vec4 color = vert_color * sampled;
2149 fragment_color = vec4(color.rgb * color.a, color.a);
2150 }
2151);
2152
2153const GLchar * background_vertex = GLSL(
2154 in vec2 vert;
2155
2156 out vec2 fragment_coord;
2157 void main ()
2158 {
2159 fragment_coord = 0.5*vert + 0.5;
2160 gl_Position = vec4(vert, 0.0, 1.0);
2161 }
2162);
2163
2164const GLchar * background_linear = GLSL(
2165 in vec2 fragment_coord;
2166 uniform vec4 first_color;
2167 uniform vec4 second_color;
2168 uniform int gradient;
2169 uniform float position;
2170
2171 out vec4 fragment_color;
2172 void main ()
2173 {
2174 float horizontal = 1.0 - fragment_coord.x;
2175 float vertical = fragment_coord.y;
2176 float factor;
2177 switch (gradient)
2178 {
2179 case 1:
2180 // Linear right to left
2181 factor = clamp ((horizontal - position) * 2.0 + 0.5, 0.0, 1.0);
2182 break;
2183 case 2:
2184 // Linear bottom right to top left
2185 factor = clamp ((0.5*(horizontal + vertical) - position) * 2.0 + 0.5, 0.0, 1.0);
2186 break;
2187 case 3:
2188 // Linear bottom left to top right
2189 factor = clamp ((0.5*(fragment_coord.x + vertical) - position) * 2.0 + 0.5, 0.0, 1.0);
2190 break;
2191 default:
2192 // Linear top to bottom
2193 factor = clamp ((vertical - position) * 2.0 + 0.5, 0.0, 1.0);
2194 break;
2195 }
2196 fragment_color = mix(first_color, second_color, factor);
2197 }
2198);
2199
2200const GLchar * background_circular = GLSL(
2201 in vec2 fragment_coord;
2202 uniform vec4 first_color;
2203 uniform vec4 second_color;
2204 uniform int gradient;
2205 uniform float position;
2206
2207 out vec4 fragment_color;
2208 void main ()
2209 {
2210 float dist;
2211 float factor;
2212 vec2 center;
2213 switch (gradient)
2214 {
2215 case 0:
2216 // Circular right to left
2217 center = vec2 (0.0, 0.5); // left side centered vertically
2218 dist = distance (fragment_coord, center) + position - 0.5;
2219 // sqrt((1.0 - 0.0)^2 + (1.0 - 0.5)^2) ~ 1.118
2220 factor = clamp (dist / 1.118, 0.0, 1.0);
2221 break;
2222 case 1:
2223 // Circular left to right
2224 center = vec2 (1.0, 0.5); // right side centered vertically
2225 dist = distance (fragment_coord, center) + position - 0.5;
2226 factor = clamp (dist / 1.118, 0.0, 1.0);
2227 break;
2228 case 2:
2229 // Top to bottom
2230 center = vec2 (0.5, 1.0); // right side centered vertically
2231 dist = distance (fragment_coord, center) + position - 0.5;
2232 factor = clamp (dist / 1.118, 0.0, 1.0);
2233 break;
2234 case 3:
2235 // Bottom to top
2236 center = vec2 (0.5, 0.0); // right side centered vertically
2237 dist = distance (fragment_coord, center) + position - 0.5;
2238 factor = clamp (dist / 1.118, 0.0, 1.0);
2239 break;
2240 case 4:
2241 // Circular bottom right to top left
2242 center = vec2 (1.0, 0.0); // bottom right corner
2243 dist = distance (fragment_coord, center) + position - 0.5;
2244 factor = clamp (dist / 1.4142, 0.0, 1.0);
2245 break;
2246 case 5:
2247 // Circular bottom left to top right
2248 center = vec2 (0.0, 0.0); // bottom right corner
2249 dist = distance (fragment_coord, center) + position - 0.5;
2250 factor = clamp (dist / 1.4142, 0.0, 1.0);
2251 break;
2252 case 6:
2253 // Circular top right to bottom left
2254 center = vec2 (1.0, 1.0); // top right corner
2255 dist = distance (fragment_coord, center) + position - 0.5;
2256 factor = clamp (dist / 1.4142, 0.0, 1.0);
2257 break;
2258 case 7:
2259 // Circular top left to bottom right
2260 center = vec2 (0.0, 1.0); // top left corner
2261 dist = distance (fragment_coord, center) + position - 0.5;
2262 factor = clamp (dist / 1.4142, 0.0, 1.0);
2263 break;
2264 default:
2265 center = vec2 (0.5, 0.5); // from the center
2266 dist = distance (fragment_coord, center) + position - 0.5;
2267 factor = clamp (dist / 0.707, 0.0, 1.0);
2268 break;
2269 }
2270 fragment_color = mix (first_color, second_color, factor);
2271 }
2272);
void translate(project *this_proj, int status, int axis, vec3_t trans)
translate
Definition atom_move.c:230
double xmax
Definition curve.c:68
PangoLayout * layout
Definition curve.c:80
double ymax
Definition curve.c:68
ColRGBA col
Definition d_measures.c:77
double dist
Definition d_measures.c:73
int * shift
Definition d_measures.c:72
double *** cross
Definition dlp_edit.c:418
double pi
Definition global.c:202
Global variable declarations Global convenience function declarations Global data structure defin...
struct project project
data structure for the 'atomes' project
Definition global.h:1013
#define min(a, b)
Definition global.h:93
#define max(a, b)
Definition global.h:92
int step
Definition ogl_draw.c:76
struct distance distance
Definition glwin.h:121
position
Definition m_proj.c:48
int main(int argc, char *argv[])
initialization of the atomes program
Definition main.c:1183
double precision, dimension(98), parameter c
double precision, dimension(3) rim
double precision phi
double precision p1
double precision p2
double y
Definition ogl_draw.c:63
double x
Definition ogl_draw.c:63
const GLchar * full_color
const GLchar * string_color_2d
const GLchar * string_vertex
const GLchar * line_stipple_color
const GLchar * cap_vertex_ray
const GLchar * angle_stipple
const GLchar * angle_vertex
const GLchar * background_circular
const GLchar * gs_cylinder_geom
const GLchar * background_vertex
const GLchar * cylinder_vertex
const GLchar * full_color_ray
const GLchar * string_color
const GLchar * cylinder_vertex_ray
const GLchar * full_vertex
const GLchar * line_color
Definition ogl_shaders.c:93
const GLchar * line_stipple
const GLchar * cap_vertex
const GLchar * background_linear
#define GLSL(src)
Definition ogl_shaders.c:48
const GLchar * angle_color
const GLchar * cone_vertex_ray
const GLchar * line_vertex
Definition ogl_shaders.c:80
const GLchar * sphere_vertex
const GLchar * point_vertex
Definition ogl_shaders.c:50
const GLchar * cone_vertex
const GLchar * degree_vertex
const GLchar * point_color
Definition ogl_shaders.c:66
const GLchar * sphere_vertex_ray
const GLchar * angstrom_vertex
Definition glwin.h:234
int based
Definition glwin.h:236
int mode
Definition glwin.h:235
vec3_t color
Definition glwin.h:239
float density
Definition glwin.h:237
float depth[2]
Definition glwin.h:238
Definition glwin.h:182
vec3_t direction
Definition glwin.h:187
int type
Definition glwin.h:183
vec3_t intensity
Definition glwin.h:188
vec3_t albedo
Definition glwin.h:212
Definition glwin.h:115
Definition glwin.h:332
GtkWidget * res[2]
Definition w_encode.c:342