FreeWRL / FreeX3D 4.3.0
Compositing_Shaders.c
1/****************************************************************************
2 This file is part of the FreeWRL/FreeX3D Distribution.
3
4 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
5
6 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
18****************************************************************************/
19
20/* Aug 9, 2016, Castle Game Engine has given us/freewrl-sourceforge
21 special permission to implement their system
22 for compositing shader permutations via special PLUGS, for use in libfreewrl.
23 For use outside of libfreewrl, please consult Castle Game Engine
24 http://castle-engine.sourceforge.net/compositing_shaders.php
25
26 In the starting default/base shader, structured for web3d lighting model, with PLUG deckarations:
27 ... PLUG: texture_apply (fragment_color, iuse)
28 7
29 In an additive effect shader:
30 void PLUG_texture_color(inout vec4 texture_color,
31 const in vec4 tex_coord)
32 {
33
34 The idea is to call the additive effect function from the main shader, where the same PLUG: <name> is
35 1. paste the additive effect function at the bottom of the main shader, with a uniquized name
36 2. put a forward declaration above the call
37 3. call at the matching PLUG location
38 4. (add in more effects same way)
39 5. compile shaderparts and shaderprogram
40 6. record permutation for re-use, as hash or bitflag of requirements/effects
41*/
42#include <config.h>
43#include <system.h>
44#include <system_threads.h>
45
46#include <display.h>
47#include <internal.h>
48
49#include <libFreeWRL.h>
50#define TRUE 1
51#define FALSE 0
52//type
53// TShaderType = (vertex, geometry, fragment);
54// TShaderSource = array [TShaderType] of a string list;
55//
56enum TShaderType {
57 SHADERPART_VERTEX,
58 SHADERPART_GEOMETRY,
59 SHADERPART_FRAGMENT
60};
61//var
62// { shader for the whole shape }
63// FinalShader: TShaderSource;
64
65
66char *insertBefore(char *current, char *insert, char* wholeBuffer, int wholeBuffersize){
67 //inserts insert at current location
68 char *newcurrent, *here;
69 int insertlen, wholelen, need, movesize;
70
71 wholelen = strlen(current) +1; //plus 1 to get the \0 at the end in memmove
72 insertlen = strlen(insert);
73 need = wholelen + insertlen + 1;
74 movesize = wholelen;
75 newcurrent = current;
76 if(need < wholeBuffersize){
77 here = current;
78 newcurrent = current + insertlen;
79 memmove(newcurrent,current,movesize);
80 memcpy(here,insert,insertlen);
81 }else{
82 ConsoleMessage("Not enough buffer for compositing shader buffsz=%d need=%d\n",wholeBuffersize,need);
83 }
84 //if(1){
85 // char *tmp = strdup(wholeBuffer);
86 // printf("strdup: %s",tmp);
87 // free(tmp);
88 //}
89 return newcurrent;
90}
91void removeAt(char *here, int len){
92 //removes len bytes from string, moving tail bytes up by len bytes
93 int wholelen, movesize;
94 char *source;
95 wholelen = strlen(here) + 1; //take the \0
96 source = here + len;
97 movesize = wholelen - len;
98 memmove(here,source,movesize);
99}
100
101void extractPlugCall(char *start, char *PlugName,char *PlugParameters){
102 //from the addon shader, get the name PLUG_<name>(declaredParameters)
103 char *pns, *pne, *pps, *ppe;
104 int len;
105 pns = strstr(start,"PLUG: ");
106 pns += strlen("PLUG: ");
107 pne = strchr(pns,' ');
108 len = pne - pns;
109 strncpy(PlugName,pns,len);
110 PlugName[len] = '\0';
111 pps = strchr(pne,'(');
112 ppe = strchr(pps,')') + 1;
113 len = ppe - pps;
114 strncpy(PlugParameters,pps,len);
115 PlugParameters[len] = '\0';
116 //printf("PlugName %s PlugParameters %s\n",PlugName,PlugParameters);
117}
118//{ Look for /* PLUG: PlugName (...) */ inside
119 //given CodeForPlugDeclaration.
120 //Return if any occurrence found. }
121 //function LookForPlugDeclaration(
122 // CodeForPlugDeclaration: string list): boolean;
123 //begin
124int LookForPlugDeclarations( char * CodeForPlugDeclarations, int bsize, char *PlugName, char *ProcedureName, char *ForwardDeclaration) {
125 //in the main code, look for matching PLUG: <PlugName>(plugparams) and place a call to ProcedureName(plugparams)
126 //Result := false
127 //for each S: string in CodeForPlugDeclaration do
128 //begin
129 int Result;
130 //i = 0;
131 //while(CodeForPlugDeclarations[i]){
132 char *S;
133 char MainPlugName[100], MainPlugParams[1000];
134 //char PlugDeclarationBuffer[10000];
135 int AnyOccurrencesHere = FALSE; //:= false
136 Result = FALSE;
137 //strcpy_s(PlugDeclarationBuffer,10000,*CodeForPlugDeclarations);
138 S = CodeForPlugDeclarations;
139 do {
140 //while we can find an occurrence
141 // of /* PLUG: PlugName (...) */ inside S do
142 //begin
143 S = strstr(S,"/* PLUG: ");
144 //if(S)
145 // printf("found PLUG:\n");
146 //else
147 // printf("PLUG: not found\n");
148 if(S){
149 char ProcedureCallBuffer[500], *ProcedureCall;
150 extractPlugCall(S,MainPlugName,MainPlugParams);
151 if(!strcmp(MainPlugName,PlugName)){
152 //found the place in the main shader to make the call to addon function
153 //insert into S a call to ProcedureName,
154 //with parameters specified inside the /* PLUG: PlugName (...) */,
155 //right before the place where we found /* PLUG: PlugName (...) */
156 ProcedureCall = ProcedureCallBuffer;
157 sprintf(ProcedureCall,"%s%s;\n",ProcedureName,MainPlugParams);
158 S = insertBefore(S,ProcedureCall,CodeForPlugDeclarations,bsize);
159 AnyOccurrencesHere = TRUE; //:= true
160 Result = TRUE; //:= true
161 }else{
162 //printf("found a PLUG: %s but doesn't match PLUG_%s\n",MainPlugName,PlugName);
163 }
164 S += strlen("/* PLUG:") + strlen(MainPlugName) + strlen(MainPlugParams);
165 }
166 }
167 while(S); //AnyOccurrencesHere);
168 //end
169
170 //if AnyOccurrencesHere then
171 if(AnyOccurrencesHere){
172 //insert the PlugForwardDeclaration into S,
173 //at the place of /* PLUG-DECLARATIONS */ inside
174 //(or at the beginning, if no /* PLUG-DECLARATIONS */)
175 S = CodeForPlugDeclarations;
176 S = strstr(S,"/* PLUG-DECLARATIONS */");
177 if(!S) S = CodeForPlugDeclarations;
178 S = insertBefore(S,ForwardDeclaration,CodeForPlugDeclarations,bsize);
179 //S = *CodeForPlugDeclarations;
180 //*CodeForPlugDeclarations = strdup(PlugDeclarationBuffer);
181 //FREE_IF_NZ(S);
182 }else{
183 printf("didn't find PLUG_%s\n",PlugName);
184 }
185 // i++;
186 //} //end
187 return Result;
188} //end
189
190
191void replaceAll(char *buffer,int bsize, char *oldstr, char *newstr){
192 char *found;
193 while((found = strstr(buffer,oldstr))){
194 removeAt(found,strlen(oldstr));
195 insertBefore(found,newstr,buffer,bsize);
196 }
197
198}
199//procedure Plug(
200// EffectPartType: TShaderType;
201// PlugValue: string;
202// CompleteCode: TShaderSource);
203//char *strpbrk(const char *str1, const char *str2) finds the first character in the string str1 that matches any character specified in str2. This does not include the terminating null-characters.
204void extractPlugName(char *start, char *PlugName,char *PlugDeclaredParameters){
205 //from the addon shader, get the name PLUG_<name>(declaredParameters)
206 char *pns, *pne, *pps, *ppe;
207 int len;
208 pns = strstr(start,"PLUG_");
209 pns += strlen("PLUG_");
210 //pne = strchr(pns,' ');
211 pne = strpbrk(pns," (");
212 len = pne - pns;
213 strncpy(PlugName,pns,len);
214 PlugName[len] = '\0';
215 pps = strchr(pne,'(');
216 ppe = strchr(pps,')') + 1;
217 len = ppe - pps;
218 strncpy(PlugDeclaredParameters,pps,len);
219 PlugDeclaredParameters[len] = '\0';
220 //printf("PlugName %s PlugDeclaredParameters %s\n",PlugName,PlugDeclaredParameters);
221}
222#define SBUFSIZE 65534 //32767 //must hold final size of composited shader part, could do per-gglobal-instance malloced buffer instead and resize to largest composited shader
223#define PBUFSIZE 16384 //must hold largets PlugValue
224int fw_strcpy_s(char *dest, int destsize, const char *source){
225 int ier = -1;
226 if(dest)
227 if(source && strlen(source) < (unsigned)destsize){
228 strcpy(dest,source);
229 ier = 0;
230 }
231 return ier;
232}
233int fw_strcat_s(char *dest, int destsize, const char *source){
234 int ier = -1;
235 if(dest){
236 int destlen = strlen(dest);
237 if(source)
238 if(strlen(source)+destlen < (unsigned)destsize){
239 strcat(dest,source);
240 ier = 0;
241 }
242 }
243 return ier;
244}
245void Plug( int EffectPartType, const char *PlugValue, char **CompleteCode, int *unique_int)
246{
247 //Algo:
248 // outer loop: search for PLUG_<name> in (addon) effect
249 // inner loop: search for matching PLUG: <name> in main shader
250 // if found, paste addon into main:
251 // a) forward declaration at top,
252 // b) method call at PLUG: point
253 // c) method definition at bottom
254 //var
255 // PlugName, ProcedureName, PlugForwardDeclaration: string;
256 char PlugName[100], PlugDeclaredParameters[1000], PlugForwardDeclaration[1000], ProcedureName[100], PLUG_PlugName[100];
257 char Code[SBUFSIZE], Plug[PBUFSIZE];
258 int HasGeometryMain = FALSE, AnyOccurrences;
259 char *found;
260 int err;
261
262 UNUSED(err);
263
264 //var
265 // Code: string list;
266 //begin
267
268 if(!CompleteCode[EffectPartType]) return;
269 err = fw_strcpy_s(Code,SBUFSIZE, CompleteCode[EffectPartType]);
270 err = fw_strcpy_s(Plug,PBUFSIZE, PlugValue);
271
272 //HasGeometryMain := HasGeometryMain or
273 // ( EffectPartType = geometry and
274 // PlugValue contains 'main()' );
275 HasGeometryMain = HasGeometryMain ||
276 ((EffectPartType == SHADERPART_GEOMETRY) && strstr("main(",Plug));
277
278 //while we can find PLUG_xxx inside PlugValue do
279 //begin
280 found = Plug;
281 do {
282 found = strstr(found,"void PLUG_"); //where = strstr(haystack,needle)
283 //if(!found)
284 // printf("I'd like to complain: void PLUG_ isn't found in the addon\n");
285 if(found){
286 //PlugName := the plug name we found, the "xxx" inside PLUG_xxx
287 //PlugDeclaredParameters := parameters declared at PLUG_xxx function
288 extractPlugName(found,PlugName,PlugDeclaredParameters);
289 found += strlen("void PLUG_") + strlen(PlugName) + strlen(PlugDeclaredParameters);
290 //{ Rename found PLUG_xxx to something unique. }
291 //ProcedureName := generate new unique procedure name,
292 //for example take 'plugged_' + some unique integer
293 sprintf(ProcedureName,"%s_%d",PlugName,(*unique_int));
294 (*unique_int)++;
295
296 //replace inside PlugValue all occurrences of 'PLUG_' + PlugName
297 //with ProcedureName
298 sprintf(PLUG_PlugName,"%s%s","PLUG_",PlugName);
299 replaceAll(Plug,PBUFSIZE,PLUG_PlugName,ProcedureName);
300
301 //PlugForwardDeclaration := 'void ' + ProcedureName +
302 //PlugDeclaredParameters + ';' + newline
303 sprintf(PlugForwardDeclaration,"void %s%s;\n",ProcedureName,PlugDeclaredParameters);
304
305 //AnyOccurrences := LookForPlugDeclaration(Code)
306 AnyOccurrences = LookForPlugDeclarations(Code,SBUFSIZE, PlugName,ProcedureName,PlugForwardDeclaration);
307
308 /* If the plug declaration is not found in Code, then try to find it
309 in the final shader. This happens if Code is special for given
310 light/texture effect, but PLUG_xxx is not special to the
311 light/texture effect (it is applicable to the whole shape as well).
312 For example, using PLUG_vertex_object_space inside
313 the X3DTextureNode.effects.
314 */
315 //if not AnyOccurrences and
316 // Code <> Source[EffectPartType] then
317 // AnyOccurrences := LookForPlugDeclaration(Source[EffectPartType])
318 //if(!AnyOccurrences && Code != Source[EffectPartType]){
319 // AnyOccurrences = LookForPlugDeclarations(Source[EffectPartType]);
320 //}
321 //if not AnyOccurrences then
322 // Warning('Plug name ' + PlugName + ' not declared')
323 //}
324 if(!AnyOccurrences){
325 ConsoleMessage("Plug name %s not declared\n",PlugName);
326 }
327 }
328 }while(found);
329 //end
330
331 /*{ regardless if any (and how many) plug points were found,
332 always insert PlugValue into Code. This way EffectPart with a library
333 of utility functions (no PLUG_xxx inside) also works. }*/
334 //Code.Add(PlugValue)
335 //printf("strlen Code = %d strlen PlugValue=%d\n",strlen(Code),strlen(PlugValue));
336 err = fw_strcat_s(Code,SBUFSIZE,Plug);
337 FREE_IF_NZ(CompleteCode[EffectPartType]);
338 CompleteCode[EffectPartType] = strdup(Code);
339} //end
340
341void AddVersion0( int EffectPartType, int versionNumber, char *versionSuffix, char **CompleteCode){
342 //puts #version <number> at top of shader, first line
343 char Code[SBUFSIZE], line[1000];
344 char *found;
345 int err;
346
347 UNUSED(err);
348
349 if (!CompleteCode[EffectPartType]) return;
350 err = fw_strcpy_s(Code, SBUFSIZE, CompleteCode[EffectPartType]);
351
352 found = Code;
353 if (found) {
354 sprintf(line, "#version %d %s\n", versionNumber, versionSuffix);
355 insertBefore(found, line, Code, SBUFSIZE);
356 FREE_IF_NZ(CompleteCode[EffectPartType]);
357 CompleteCode[EffectPartType] = strdup(Code);
358 }
359}
360void AddExtension(int EffectPartType, char* extensionName, char* behavior, char** CompleteCode) {
361 //puts #version <number> at top of shader, first line
362 char Code[SBUFSIZE], line[1000];
363 char* found;
364 int err;
365
366 UNUSED(err);
367
368 if (!CompleteCode[EffectPartType]) return;
369 err = fw_strcpy_s(Code, SBUFSIZE, CompleteCode[EffectPartType]);
370
371 found = strstr(Code, "/*EXTENSIONS");
372 if (found) {
373 sprintf(line, "#extension %s : %s\n", extensionName, behavior);
374 insertBefore(found, line, Code, SBUFSIZE);
375 FREE_IF_NZ(CompleteCode[EffectPartType]);
376 CompleteCode[EffectPartType] = strdup(Code);
377 }
378}
379void AddVersion(int EffectPartType, int versionNumber, char** CompleteCode) {
380 AddVersion0(EffectPartType, versionNumber, "core", CompleteCode);
381}
382void AddDefine0( int EffectPartType, const char *defineName, int defineValue, char **CompleteCode)
383{
384 //same as AddDEfine but you can say a number other than 1
385 char Code[SBUFSIZE], line[1000];
386 char *found;
387 int err;
388
389 UNUSED(err);
390
391 if(!CompleteCode[EffectPartType]) return;
392 err = fw_strcpy_s(Code,SBUFSIZE, CompleteCode[EffectPartType]);
393
394 found = strstr(Code,"/* DEFINE");
395 if(found){
396 sprintf(line,"#define %s %d \n",defineName,defineValue);
397 insertBefore(found,line,Code,SBUFSIZE);
398 FREE_IF_NZ(CompleteCode[EffectPartType]);
399 CompleteCode[EffectPartType] = strdup(Code);
400 }
401}
402void AddDefine( int EffectPartType, const char *defineName, char **CompleteCode){
403 //adds #define <defineName> 1 to shader part, just above "/* DEFINES */" line in ShaderPart
404 // char *CompleteCode[3] has char *vs *gs *fs parts, and will be realloced inside
405 AddDefine0(EffectPartType,defineName,1,CompleteCode);
406}
407
408//procedure EnableEffects(
409// Effects: list of Effect nodes;
410// CompleteCode: TShaderSource);
411//begin
412// for each Effect in Effects do
413// if Effect.enabled and
414// Effect.language matches renderer shader language then
415// for each EffectPart in Effect.parts do
416// Plug(EffectPart.type, GetUrl(EffectPart.url), CompleteCode)
417//end
418void EnableEffect(struct X3D_Node * node, char **CompletedCode, int *unique_int){
419 int i, ipart;
420 char *str;
421
422 ipart=SHADERPART_VERTEX;
423 struct X3D_Effect *effect = (struct X3D_Effect *)node;
424 for(i=0;i<effect->parts.n;i++){
425 struct X3D_EffectPart *part = (struct X3D_EffectPart*)effect->parts.p[i];
426 if(part->_nodeType == NODE_EffectPart){
427 if(!strcmp(part->type->strptr,"FRAGMENT"))
428 ipart = SHADERPART_FRAGMENT;
429 else if(!strcmp(part->type->strptr,"VERTEX"))
430 ipart = SHADERPART_VERTEX;
431 str = part->url.p[0]->strptr;
432 if(!strncmp(str,"data:text/plain,",strlen("data:text/plain,")))
433 str += strlen("data:text/plain,");
434 Plug(ipart,str, CompletedCode, unique_int);
435 }
436 }
437}
438Stack *getEffectStack();
439void EnableEffects( char **CompletedCode, int *unique_int){
440 int i;
441 Stack *effect_stack;
442 effect_stack = getEffectStack();
443 for(i=0;i<vectorSize(effect_stack);i++){
444 struct X3D_Node *node = vector_get(struct X3D_Node*,effect_stack,i);
445 if(node->_nodeType == NODE_Effect){
446 EnableEffect(node,CompletedCode,unique_int);
447 }
448 }
449}
450
451
452
453//maxLights = 8;
454//#if defined (GL_ES_VERSION_2_0)
455//precision highp float;
456//precision mediump float;
457//#endif
458
459/*
460started with: http://svn.code.sf.net/p/castle-engine/code/trunk/castle_game_engine/src/x3d/opengl/glsl/template_mobile.vs
461 castle freewrl
462 uniforms:
463 castle_ModelViewMatrix fw_ModelViewMatrix
464 castle_ProjectionMatrix fw_ProjectionMatrix
465 castle_NormalMatrix fw_NormalMatrix
466 castle_MaterialDiffuseAlpha fw_FrontMaterial.diffuse.a
467 castle_MaterialShininess fw_FrontMaterial.shininess
468 castle_SceneColor fw_FrontMaterial.ambient
469 castle_castle_UnlitColor fw_FrontMaterial.emissive
470 fw_FrontMaterial.specular
471 per-vertex attributes
472 castle_Vertex fw_Vertex
473 castle_Normal fw_Normal
474 castle_ColorPerVertex fw_Color
475
476 defines
477 LIT
478 COLOR_PER_VERTEX
479 CASTLE_BUGGY_GLSL_READ_VARYING
480
481define LIT if have Shape->appearance->material and NOT linepoints
482define TWO if you have backface colors ie X3DTwoSidedMaterial
483 http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/shape.html#TwoSidedMaterial
484define LINE if you have Shape->appearance->material and is linepoints (lines and points use mat.emissive)
485define TEX if you have texture
486define CPV if colorNode && image_channels < 3
487define MAT if material is valid
488*/
489
490/* Generic GLSL vertex shader.
491 Used by ../castlerendererinternalshader.pas to construct the final shader.
492
493 This is converted to template.vs.inc, and is then compiled
494 in program's binary.
495 When you change this file, rerun `make' and then recompile Pascal sources.
496*/
497
498
499static const GLchar* genericVertexGLES2 = "\
500/*EXTENSIONS*/ \n\
501/* DEFINES */ \n\
502#ifdef FULL \n\
503#define attribute in \n\
504#define varying out \n\
505#endif //FULL \n\
506/* Generic GLSL vertex shader, used on OpenGL ES. */ \n\
507#ifdef MOBILE \n\
508// we index into sampler arrays, OK for desktop, mobile needs GLES 3.1 and: \n\
509// https://www.khronos.org/registry/OpenGL/extensions/OES/OES_gpu_shader5.txt \n\
510#extension GL_OES_gpu_shader5 : require //(or enable) \n\
511#endif \n\
512 \n\
513uniform mat4 fw_ModelViewMatrix; \n\
514uniform mat4 fw_ProjectionMatrix; \n\
515uniform mat4 fw_NormalMatrix; \n\
516//#ifdef CUB \n\
517uniform mat4 fw_ModelViewInverseMatrix; \n\
518//#endif //CUB \n\
519attribute vec4 fw_Vertex; \n\
520attribute vec3 fw_Normal; \n\
521#ifdef SKINNING \n\
522attribute int fw_Cindex; \n\
523layout (std430, binding = 10) buffer BufferBlock1 { \n\
524 vec4 PVW []; \n\
525}; \n\
526layout (std430, binding = 11) buffer BufferBlock2 { \n\
527 ivec4 PVI []; \n\
528}; \n\
529layout (std430, binding = 12) buffer BufferObject1 { \n\
530 mat4 JT[]; \n\
531}; \n\
532layout (std430, binding = 13) buffer BufferObject2 { \n\
533 mat3 JN[]; \n\
534}; \n\
535#ifdef DISPLACER \n\
536layout (std430, binding = 14) buffer BufferBlock3 { \n\
537 int dindex []; \n\
538}; \n\
539layout (std430, binding = 15) buffer BufferBlock4 { \n\
540 vec4 displace []; \n\
541}; \n\
542#endif //DISPLACER \n\
543#endif //SKINNING \n\
544#if defined(LINETYPE) && defined(FULL) \n\
545//desktop glsl 130 \n\
546//glsl desktop version 130 can do flat instead of varying \n\
547//which allows the provoking vertex (for GL_LINE_STRIP its the second vertex in a pair) \n\
548//to output something to the frag that isnt interpolated - like .vert computed distance to prev \n\
549flat out vec2 f_prev; \n\
550flat out vec2 f_next; \n\
551flat out float f_linestrip_end; //0 middle, 1 start, 2 end segment\n\
552out vec2 v_curr; \n\
553in vec3 a_prevVertex; \n\
554in vec3 a_nextVertex; \n\
555uniform int u_linetype; \n\
556#endif //LINETYPE \n\
557#if defined(LINETYPE) || defined(POINTP) \n\
558uniform vec4 u_screenresolution; \n\
559#endif // LINETYPE POINTP \n\
560 \n\
561//#ifdef TEX \n\
562uniform mat4 fw_TextureMatrix[4]; \n\
563uniform int nTexMatrix; \n\
564attribute vec4 fw_MultiTexCoord0; \n\
565attribute vec4 fw_MultiTexCoord1; \n\
566attribute vec4 fw_MultiTexCoord2; \n\
567attribute vec4 fw_MultiTexCoord3; \n\
568uniform int nTexCoordChannels; \n\
569uniform int fw_tmap[6]; \n\
570uniform int fw_cmap[6]; \n\
571uniform int fw_ntexcombo; \n\
572uniform int fw_tgen[6]; \n\
573uniform float fw_parameter[7]; \n\
574uniform int fw_parameter_n; \n\
575uniform int flipuv; \n\
576vec4 yupuv(in vec4 uv){ \n\
577 //gltf uv are y-down, so we flag and send the flag here \n\
578 vec4 yup = uv; \n\
579 if(flipuv==1) yup.y = 1.0 - yup.y; \n\
580 return yup; \n\
581} \n\
582//varying vec3 v_texC; \n\
583varying vec3 fw_TexCoord[6]; \n\
584#ifdef TEX3D \n\
585uniform int tex3dUseVertex; \n\
586#endif //TEX3D \n\
587//#ifdef TGEN \n\
588#define TCGT_CAMERASPACENORMAL 0\n \
589#define TCGT_CAMERASPACEPOSITION 1\n \
590#define TCGT_CAMERASPACEREFLECTION 2\n \
591#define TCGT_CAMERASPACEREFLECTIONVECTOR 3\n \
592#define TCGT_COORD 4\n \
593#define TCGT_COORD_EYE 5\n \
594#define TCGT_NOISE 6\n \
595#define TCGT_NOISE_EYE 7\n \
596#define TCGT_REGULAR 8\n \
597#define TCGT_SPHERE 9\n \
598#define TCGT_SPHERE_LOCAL 10\n \
599#define TCGT_SPHERE_REFLECT 11\n \
600#define TCGT_SPHERE_REFLECT_LOCAL 12\n \
601uniform int fw_textureCoordGenType; \n\
602 \n\
603// there were other 3D noise function, this one was short in lines \n\
604#define NOISE 1 \n\
605#ifdef NOISE \n\
606// \n\
607// Description : Array and textureless GLSL 2D/3D/4D simplex \n\
608// noise functions. \n\
609// Author : Ian McEwan, Ashima Arts. \n\
610// Maintainer : stegu \n\
611// Lastmod : 20201014 (stegu) \n\
612// License : Copyright (C) 2011 Ashima Arts. All rights reserved. \n\
613// Distributed under the MIT License. See LICENSE file. \n\
614// https://github.com/ashima/webgl-noise \n\
615// https://github.com/stegu/webgl-noise \n\
616// \n\
617\n\
618vec3 mod289(vec3 x) { \n\
619 return x - floor(x * (1.0 / 289.0)) * 289.0; \n\
620} \n\
621\n\
622vec4 mod289(vec4 x) { \n\
623 return x - floor(x * (1.0 / 289.0)) * 289.0; \n\
624} \n\
625\n\
626vec4 permute(vec4 x) { \n\
627 return mod289(((x * 34.0) + 10.0) * x); \n\
628} \n\
629\n\
630vec4 taylorInvSqrt(vec4 r) \n\
631{ \n\
632 return 1.79284291400159 - 0.85373472095314 * r; \n\
633} \n\
634\n\
635float snoise(vec3 v) \n\
636{ \n\
637 const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0); \n\
638 const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); \n\
639 \n\
640 // First corner \n\
641 vec3 i = floor(v + dot(v, C.yyy)); \n\
642 vec3 x0 = v - i + dot(i, C.xxx); \n\
643 \n\
644 // Other corners \n\
645 vec3 g = step(x0.yzx, x0.xyz); \n\
646 vec3 l = 1.0 - g; \n\
647 vec3 i1 = min(g.xyz, l.zxy); \n\
648 vec3 i2 = max(g.xyz, l.zxy); \n\
649 \n\
650 // x0 = x0 - 0.0 + 0.0 * C.xxx; \n\
651 // x1 = x0 - i1 + 1.0 * C.xxx; \n\
652 // x2 = x0 - i2 + 2.0 * C.xxx; \n\
653 // x3 = x0 - 1.0 + 3.0 * C.xxx; \n\
654 vec3 x1 = x0 - i1 + C.xxx; \n\
655 vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y \n\
656 vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y \n\
657 \n\
658 // Permutations \n\
659 i = mod289(i); \n\
660 vec4 p = permute(permute(permute(\n\
661 i.z + vec4(0.0, i1.z, i2.z, 1.0)) \n\
662 + i.y + vec4(0.0, i1.y, i2.y, 1.0)) \n\
663 + i.x + vec4(0.0, i1.x, i2.x, 1.0)); \n\
664 \n\
665 // Gradients: 7x7 points over a square, mapped onto an octahedron. \n\
666 // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) \n\
667 float n_ = 0.142857142857; // 1.0/7.0 \n\
668 vec3 ns = n_ * D.wyz - D.xzx; \n\
669 \n\
670 vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) \n\
671 \n\
672 vec4 x_ = floor(j * ns.z); \n\
673 vec4 y_ = floor(j - 7.0 * x_); // mod(j,N) \n\
674 \n\
675 vec4 x = x_ * ns.x + ns.yyyy; \n\
676 vec4 y = y_ * ns.x + ns.yyyy; \n\
677 vec4 h = 1.0 - abs(x) - abs(y); \n\
678 \n\
679 vec4 b0 = vec4(x.xy, y.xy); \n\
680 vec4 b1 = vec4(x.zw, y.zw); \n\
681 \n\
682 //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; \n\
683 //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; \n\
684 vec4 s0 = floor(b0) * 2.0 + 1.0; \n\
685 vec4 s1 = floor(b1) * 2.0 + 1.0; \n\
686 vec4 sh = -step(h, vec4(0.0)); \n\
687 \n\
688 vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; \n\
689 vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; \n\
690 \n\
691 vec3 p0 = vec3(a0.xy, h.x); \n\
692 vec3 p1 = vec3(a0.zw, h.y); \n\
693 vec3 p2 = vec3(a1.xy, h.z); \n\
694 vec3 p3 = vec3(a1.zw, h.w); \n\
695 \n\
696 //Normalise gradients \n\
697 vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); \n\
698 p0 *= norm.x; \n\
699 p1 *= norm.y; \n\
700 p2 *= norm.z; \n\
701 p3 *= norm.w; \n\
702 \n\
703 // Mix final noise value \n\
704 vec4 m = max(0.5 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); \n\
705 m = m * m; \n\
706 return 105.0 * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), \n\
707 dot(p2, x2), dot(p3, x3))); \n\
708} \n\
709#endif //NOISE \n\
710//#endif //TGEN \n\
711//#endif //TEX \n\
712#ifdef FILL \n\
713varying vec2 hatchPosition; \n\
714#endif //FILL \n\
715\n\
716 \n\
717varying vec4 castle_vertex_eye; \n\
718varying vec3 castle_normal_eye; \n\
719varying vec4 castle_Color; //DA diffuse ambient term \n\
720 \n\
721//uniform float castle_MaterialDiffuseAlpha; \n\
722//uniform float castle_MaterialShininess; \n\
723/* Color summed with all the lights. \n\
724 Like gl_Front/BackLightModelProduct.sceneColor: \n\
725 material emissive color + material ambient color * global (light model) ambient. \n\
726*/ \n\
727\n\
728#ifdef LIT \n\
729#define MAX_LIGHTS 8 \n\
730uniform int lightcount; \n\
731#ifdef LITE \n\
732//uniform float lightRadius[MAX_LIGHTS]; \n\
733uniform int lightType[MAX_LIGHTS];//ANGLE like this \n\
734struct fw_LightSourceParameters { \n\
735 float ambient; \n\
736 vec3 color; \n\
737 float intensity; \n\
738 vec3 location; \n\
739 vec3 halfVector; \n\
740 vec3 direction; \n\
741 float spotBeamWidth; \n\
742 float spotCutoff; \n\
743 vec3 Attenuations; \n\
744 float lightRadius; \n\
745 bool shadows; \n\
746 float shadowIntensity; \n\
747 int depthmap; \n\
748}; \n\
749\n\
750uniform fw_LightSourceParameters fw_LightSource[MAX_LIGHTS] /* gl_MaxLights */ ;\n\
751#endif //LITE \n\
752#endif //LIT \n\
753\n\
754//uniform vec3 castle_SceneColor; \n\
755//uniform vec4 castle_UnlitColor; \n\
756#ifdef UNLIT \n\
757uniform vec4 fw_UnlitColor; \n\
758#endif //UNLIT \n\
759//#ifdef LIT \n\
760struct fw_MaterialParameters { \n\
761 vec3 diffuse; \n\
762 vec3 emissive; \n\
763 vec3 specular; \n\
764 float ambient; \n\
765 float shininess; \n\
766 float occlusion; \n\
767 float normalScale; \n\
768 float transparency; \n\
769 vec3 baseColor; \n\
770 float metallic; \n\
771 float roughness; \n\
772 int type; \n\
773 // multitextures are disaggregated \n\
774 int tindex[10]; \n\
775 int mode[10]; \n\
776 int source[10]; \n\
777 int func[10]; \n\
778 int samplr[10]; //0 texture2D 1 cubeMap \n\
779 int cmap[10]; \n\
780 int nt; //total single textures \n\
781 //iunit [0] normal [1] emissive [2] occlusion [3] diffuse OR base [4] shininess OR metallicRoughness [5] specular [6] ambient \n\
782 int tcount[7]; //num single textures 1= one texture 0=no texture 2+ = multitexture \n\
783 int tstart[7]; // where in packed tindex list to start looping \n\
784 //int cindex[7]; // which geometry multitexcoord channel 0=default \n\
785}; \n\
786uniform fw_MaterialParameters fw_FrontMaterial; \n\
787//#ifdef TWO \n\
788uniform fw_MaterialParameters fw_BackMaterial; \n\
789uniform int material_side; //see renderfuncs reallydrawonce //0= front and back - no material difference, 1 = front 2=back\n\
790//#endif //TWO \n\
791#ifdef LIT \n\
792varying vec3 castle_ColorES; //emissive shininess term \n\
793vec3 castle_Emissive; \n\
794#endif //LIT \n\
795#ifdef FOG \n\
796struct fogParams \n\
797{ \n\
798 vec4 fogColor; \n\
799 float visibilityRange; \n\
800 float fogScale; //applied on cpu side to visrange \n\
801 int fogType; // 0 None, 1= FOGTYPE_LINEAR, 2 = FOGTYPE_EXPONENTIAL \n\
802 // ifdefed int haveFogCoords; \n\
803}; \n\
804uniform fogParams fw_fogparams; \n\
805#ifdef FOGCOORD \n\
806attribute float fw_FogCoords; \n\
807#endif \n\
808#endif //FOG \n\
809float castle_MaterialDiffuseAlpha; \n\
810float castle_MaterialShininess; \n\
811vec3 castle_SceneColor; \n\
812vec4 castle_UnlitColor; \n\
813vec4 castle_Specular; \n\
814 \n\
815#ifdef CPV \n\
816attribute vec4 fw_Color; //castle_ColorPerVertex; \n\
817varying vec4 cpv_Color; \n\
818#endif //CPV \n\
819#ifdef PARTICLE \n\
820uniform vec3 particlePosition; \n\
821uniform vec3 particleDirection; \n\
822uniform mat4 particleTransform; \n\
823uniform int fw_ParticleGeomType; \n\
824#endif //PARTICLE \n\
825#ifdef POINTP \n\
826uniform float u_pointSize; \n\
827uniform vec3 u_pointAttenuation; \n\
828uniform vec2 u_pointSizeRange; \n\
829uniform int u_pointtColorMode; \n\
830uniform vec3 u_pointPosition; \n\
831uniform int u_pointMethod; \n\
832uniform float u_pointFogCoord; \n\
833uniform vec4 u_pointCPV; \n\
834#endif //POINTP \n\
835 \n\
836 //literal string size break \n" "\
837 vec3 dehomogenize(in mat4 matrix, in vec4 vector){ \n\
838 vec4 tempv = vector; \n\
839 if(tempv.w == 0.0) tempv.w = 1.0; \n\
840 vec4 temp = matrix * tempv; \n\
841 float winv = 1.0/temp.w; \n\
842 return temp.xyz * winv; \n\
843 } \n\
844 bool approx(float a, float b){ \n\
845 if( abs(a - b) < .0001 )return true; \n\
846 return false; \n\
847 } \n\
848struct MaterialInfo \n\
849{ \n\
850 float perceptualRoughness; // roughness value, as authored by the model creator (input to shader) \n\
851 vec3 reflectance0; // full reflectance color (normal incidence angle) \n\
852 \n\
853 float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2]) \n\
854 vec3 diffuseColor; // color contribution from diffuse lighting \n\
855 \n\
856 vec3 reflectance90; // reflectance color at grazing angle \n\
857 vec3 specularColor; // color contribution from specular lighting \n\
858}; \n\
859/* PLUG-DECLARATIONS */ \n\
860vec3 cpv_rgb_replace(in vec3 c3){ \n\
861 vec3 ret = c3; \n\
862 #ifdef CPV //color per vertex \n\
863 ret = fw_Color.rgb; \n\
864 #endif //CPV \n\
865 return ret; \n\
866} \n\
867float cpv_alpha_modulate(in float alpha){\n\
868 float ret = alpha; \n\
869 #ifdef CPV //color per vertex \n\
870 ret = fw_Color.a; \n\
871 #endif //CPV \n\
872 return ret; \n\
873} \n\
874//constant string break " "\n\
875void main(void) \n\
876{ \n\
877//STEP 0: GEOMETRY SECTION \n\
878 #ifdef FOGCOORD \n\
879 float fog_coord = fw_FogCoords; \n\
880 #endif //FOGCOORD \n\
881 #ifdef FILL \n\
882 hatchPosition = fw_Vertex.xy; \n\
883 #endif //FILL \n\
884 //\n\
885 vec4 vertex_object = fw_Vertex; \n\
886 #ifdef SKINNING \n\
887 #ifdef DISPLACER \n\
888 vertex_object.xyz += displace[dindex[fw_Cindex]].xyz; \n\
889 //vertex_object.x += displace[6].x; \n\
890 #endif //DISPLACER \n\
891 ivec4 pvi = PVI[fw_Cindex]; \n\
892 vec4 pvw = PVW[fw_Cindex]; \n\
893 vec4 vo = vec4(0.0); \n\
894 vo += JT[pvi.r-1]*pvw.r*vertex_object; \n\
895 vo += JT[pvi.g-1]*pvw.g*vertex_object; \n\
896 vo += JT[pvi.b-1]*pvw.b*vertex_object; \n\
897 vo += JT[pvi.a-1]*pvw.a*vertex_object; \n\
898 vertex_object = vo; \n\
899 #endif //SKINNING \n\
900 #ifdef PARTICLE \n\
901 if(fw_ParticleGeomType != 4){ \n\
902 mat4 rot, rot2; \n\
903 rot = mat4(1.0); \n\
904 rot2 = mat4(1.0); \n\
905 if(true){ \n\
906 float yaw = atan(particleDirection.y,particleDirection.x); \n\
907 float pitch = asin(particleDirection.z); \n\
908 rot[0][0] = cos(yaw); \n\
909 rot[1][1] = rot[0][0]; \n\
910 rot[0][1] = sin(yaw); \n\
911 rot[1][0] = -rot[0][1]; \n\
912 rot2[0][0] = cos(pitch); \n\
913 rot2[2][2] = rot2[0][0]; \n\
914 rot2[0][2] = sin(pitch); \n\
915 rot2[2][0] = -rot2[0][2]; \n\
916 rot = rot * rot2; \n\
917 vertex_object = rot * particleTransform * vertex_object; \n\
918 //vertex_object.xyz /= vertex_object.w; \n\
919 //vertex_object.w = 1.0; \n\
920 } \n\
921 //vertex_object = particleTransform * vertex_object; \n\
922 vertex_object.xyz += particlePosition; \n\
923 } \n\
924 #endif //PARTICLE \n\
925 vec3 normal_object = fw_Normal; \n\
926 #ifdef SKINNING \n\
927 //ivec4 pvi = PVI[fw_Cindex]; \n\
928 //vec4 pvw = PVW[fw_Cindex]; \n\
929 normal_object = vec3(0.0); \n\
930 normal_object += JN[pvi.r-1]*pvw.r*fw_Normal; \n\
931 normal_object += JN[pvi.g-1]*pvw.g*fw_Normal; \n\
932 normal_object += JN[pvi.b-1]*pvw.b*fw_Normal; \n\
933 normal_object += JN[pvi.a-1]*pvw.a*fw_Normal; \n\
934 #endif //SKINNING \n\
935 /* PLUG: vertex_object_space_change (vertex_object, normal_object) */ \n\
936 /* PLUG: vertex_object_space (vertex_object, normal_object) */ \n\
937 \n\
938 castle_vertex_eye = fw_ModelViewMatrix * vertex_object; \n\
939 #if defined(LINETYPE) && defined(FULL) \n\
940 if(u_linetype > 1){ \n\
941 //get curr, prev, next into screenspace \n\
942 //missing: screen aspect correction\n\
943 vec4 curr = fw_ProjectionMatrix * castle_vertex_eye; \n\
944 vec4 prev = fw_ProjectionMatrix * fw_ModelViewMatrix * vec4(a_prevVertex,1.0); \n\
945 //vec4 next = fw_ProjectionMatrix * fw_ModelViewMatrix * vec4(a_nextVertex,1.0); \n\
946 //projected coords are in -1 to 1 range \n\
947 f_prev = ((prev.xyz/prev.w).xy*.5 + vec2(.5))*u_screenresolution.xy; \n\
948 //f_next = (next.xyz/next.w).xy*u_screenresolution.xy*.5; \n\
949 //using GL_LINE_STRIP the 2nd vertex is the provoking vertex so is next \n\
950 f_next = ((curr.xyz/curr.w).xy*.5 + vec2(.5))*u_screenresolution.xy; \n\
951 v_curr = ((curr.xyz/curr.w).xy*.5 + vec2(.5))*u_screenresolution.xy; \n\
952 //float index aka findex method of determining start/end of polyline \n\
953 float findex = a_nextVertex.x; \n\
954 float fcount = a_nextVertex.y; \n\
955 f_linestrip_end = 0; \n\
956 if(approx(findex -1,0.0)) f_linestrip_end = 1; \n\
957 if(approx(findex,fcount-1.0)) f_linestrip_end += 2; \n\
958 } \n\
959 #endif //LINETYPE \n\
960 #ifdef PARTICLE \n\
961 //sprite: align to viewer \n\
962 if(fw_ParticleGeomType == 4){ \n\
963 vec4 ppos = vec4(particlePosition,1.0); \n\
964 vec4 particle_eye = fw_ModelViewMatrix * ppos; \n\
965 ppos.x += 1.0; \n\
966 vec4 particle_eye1 = fw_ModelViewMatrix * ppos; \n\
967 float pscal = length(particle_eye1.xyz - particle_eye.xyz); \n\
968 castle_vertex_eye = particle_eye + pscal*vertex_object; \n\
969 } \n\
970 #endif //PARTICLE \n\
971 castle_normal_eye = normalize( (fw_NormalMatrix * vec4(normal_object,1.0)).xyz); \n\
972 \n\
973 /* PLUG: vertex_eye_space (castle_vertex_eye, castle_normal_eye) */ \n\
974 \n\
975// STEP 2 MATERIAL SECTION \n\
976 fw_MaterialParameters ourMat = material_side < 2 ? fw_FrontMaterial : fw_BackMaterial; \n\
977 //default unlits in case we dont set them \n\
978 castle_UnlitColor = vec4(1.0,1.0,1.0,1.0); \n\
979 castle_MaterialDiffuseAlpha = 1.0; \n\
980 castle_Color = castle_UnlitColor; \n\
981 #ifdef LIT \n\
982#ifdef PHONG \n\
983 castle_ColorES = vec3(0.0); \n\
984 if(ourMat.type == 0){ \n\
985 castle_MaterialDiffuseAlpha = cpv_alpha_modulate(1.0 - ourMat.transparency); \n\
986 castle_SceneColor = cpv_rgb_replace(vec3(1.0)); //ourMat.emissive; \n\
987 castle_Emissive = ourMat.emissive; \n\
988 castle_Color = vec4(castle_SceneColor, castle_MaterialDiffuseAlpha); \n\
989 }else if(ourMat.type == 1){ \n\
990 castle_MaterialDiffuseAlpha = cpv_alpha_modulate(1.0 - ourMat.transparency); \n\
991 castle_SceneColor = cpv_rgb_replace(vec3(1.0)); \n\
992 castle_Emissive = ourMat.emissive; \n\
993 castle_Color = vec4(castle_SceneColor, castle_MaterialDiffuseAlpha); \n\
994 }else if(ourMat.type == 2){ \n\
995 castle_MaterialDiffuseAlpha = cpv_alpha_modulate(1.0 - ourMat.transparency); \n\
996 castle_MaterialShininess = ourMat.shininess; \n\
997 castle_SceneColor = cpv_rgb_replace(ourMat.diffuse)*ourMat.ambient; \n\
998 castle_Specular = vec4(ourMat.specular,1.0); \n\
999 castle_Emissive = ourMat.emissive; \n\
1000 castle_Color = vec4(castle_SceneColor, castle_MaterialDiffuseAlpha); \n\
1001 }else if(ourMat.type == 3){ \n\
1002 castle_MaterialDiffuseAlpha = cpv_alpha_modulate(1.0 - ourMat.transparency); \n\
1003 castle_SceneColor = cpv_rgb_replace(ourMat.baseColor); \n\
1004 castle_Emissive = ourMat.emissive; \n\
1005 castle_Color = vec4(castle_SceneColor, castle_MaterialDiffuseAlpha); \n\
1006 } \n\
1007#else //PHONG \n\
1008 //GOURAUD \n\
1009 vec3 E = -normalize(castle_vertex_eye.xyz); \n\
1010 vec3 N = normalize (castle_normal_eye); \n\
1011 bool backFacing = (dot(N,E) < 0.0); \n\
1012 if (backFacing) { \n\
1013 N = -N; \n\
1014 } \n\
1015 castle_ColorES = vec3(0.0); \n\
1016 if(ourMat.type == 0){ \n\
1017 // no material aka MAT_NONE, not in specs \n\
1018 castle_MaterialDiffuseAlpha = cpv_alpha_modulate(1.0 - ourMat.transparency); \n\
1019 castle_SceneColor = cpv_rgb_replace(vec3(1.0)); //ourMat.emissive; \n\
1020 castle_Emissive = ourMat.emissive; \n\
1021 castle_Color = vec4(castle_SceneColor, castle_MaterialDiffuseAlpha); \n\
1022 }else if(ourMat.type == 1){ \n\
1023 // unlit emissive \n\
1024 castle_MaterialDiffuseAlpha = cpv_alpha_modulate(1.0 - ourMat.transparency); \n\
1025 castle_SceneColor = cpv_rgb_replace(ourMat.emissive); \n\
1026 castle_Emissive = ourMat.emissive; \n\
1027 castle_Color = vec4(castle_SceneColor, castle_MaterialDiffuseAlpha); \n\
1028 }else if(ourMat.type == 2){ \n\
1029 // Material Phong lighting \n\
1030 castle_MaterialDiffuseAlpha = cpv_alpha_modulate(1.0 - ourMat.transparency); \n\
1031 castle_MaterialShininess = ourMat.shininess; \n\
1032 castle_SceneColor = cpv_rgb_replace(ourMat.diffuse)*ourMat.ambient; \n\
1033 castle_Specular = vec4(ourMat.specular,1.0); \n\
1034 castle_Emissive = ourMat.emissive; \n\
1035 vec3 vcolor = vec3(0.0,0.0,0.0); \n\
1036 #ifdef LITE \n\
1037 /* back Facing materials - flip the normal and grab back materials */ \n\
1038 /* PLUG: add_light_contribution2 (vcolor, castle_ColorES, castle_vertex_eye, N, ourMat.shininess, ourMat.ambient, ourMat.diffuse, ourMat.specular) */ \n\
1039 /* Clamp sum of lights colors to be <= 1. See template.fs for comments. */ \n\
1040 #endif //LITE \n\
1041 castle_Color = vec4(min(vcolor,1.0),castle_MaterialDiffuseAlpha); \n\
1042 }else if(ourMat.type == 3){ \n\
1043 //MAT_PHYSICAL aka physical lighting\n\
1044 castle_MaterialDiffuseAlpha = cpv_alpha_modulate(1.0 - ourMat.transparency); \n\
1045 castle_SceneColor = cpv_rgb_replace(ourMat.baseColor); \n\
1046 castle_Emissive = ourMat.emissive; \n\
1047 vec3 vcolor = vec3(0.0, 0.0, 0.0); \n\
1048 #ifdef LITE \n\
1049 float metallic = ourMat.metallic; \n\
1050 float perceptualRoughness = ourMat.roughness; \n\
1051 vec3 baseColor = castle_SceneColor; //getBaseColor(); \n\
1052 //unlit \n\
1053 vec3 specularColor= vec3(0.0); \n\
1054 vec3 f0 = vec3(0.04); \n\
1055 // ?? baseColor *= getVertexColor().xyz; //hunh? \n\
1056 vec3 diffuseColor = baseColor.rgb * (vec3(1.0) - f0) * (1.0 - metallic); \n\
1057 specularColor = mix(f0, baseColor.rgb, metallic); \n\
1058 //lit \n\
1059 float alphaRoughness = perceptualRoughness * perceptualRoughness; \n\
1060 // Compute reflectance. \n\
1061 float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b); \n\
1062 vec3 specularEnvironmentR0 = specularColor.rgb; \n\
1063 // Anything less than 2% is physically impossible and is instead considered to be shadowing. \n\
1064 vec3 specularEnvironmentR90 = vec3(clamp(reflectance * 50.0, 0.0, 1.0)); \n\
1065 MaterialInfo materialInfo = MaterialInfo( \n\
1066 perceptualRoughness, \n\
1067 specularEnvironmentR0, \n\
1068 alphaRoughness, \n\
1069 diffuseColor, \n\
1070 specularEnvironmentR90, \n\
1071 specularColor \n\
1072 ); \n\
1073 // LIGHTING \n\
1074 //vec3 normal = N; //getNormal(); \n\
1075 /* PLUG: add_light_physical (vcolor, castle_vertex_eye.xyz, N, materialInfo ) */ \n\
1076 #endif //LITE \n\
1077 vcolor += castle_Emissive; //getEmissive(); \n\
1078 castle_Color = vec4(vcolor, castle_MaterialDiffuseAlpha); \n\
1079 } \n\
1080#endif //PHONG \n\
1081 #ifdef LINE \n\
1082 castle_SceneColor = vec3(0.0,0.0,0.0); //line gets color from castle_Emissive \n\
1083 #endif //LINE\n\
1084 #else //LIT \n\
1085 castle_Color.rgb = castle_UnlitColor.rgb; \n\
1086 #endif //LIT \n\
1087 \n\
1088 #ifdef CPV \n\
1089 //background sky comes through here, COLOR_MATERIAL_SHADER only \n\
1090 //castle_Color = fw_Color; \n\
1091 cpv_Color = fw_Color; \n\
1092 #endif //CPV\n\
1093 \n\
1094//STEP 3 TEXTURE COORDINATES AND TRANSFORMS \n\
1095 //#ifdef TEX \n\
1096 vec4 texcoord = yupuv(fw_MultiTexCoord0); \n\
1097 #ifdef TEX3D \n\
1098 //to re-use vertex coords as texturecoords3D, we need them in 0-1 range: CPU calc of fw_TextureMatrix0 \n\
1099 if(tex3dUseVertex == 1) \n\
1100 texcoord = vec4(fw_Vertex.xyz,1.0); \n\
1101 #endif //TEX3D \n\
1102 #ifdef TGEN \n\
1103 { \n\
1104 vec3 vertexNorm; \n\
1105 vec4 vertexPos; \n\
1106 vec3 texcoord3 = texcoord.xyz; \n\
1107 vertexNorm = normalize((fw_NormalMatrix * vec4(fw_Normal,1.0)).xyz); \n\
1108 vertexPos = fw_ModelViewMatrix * fw_Vertex; \n\
1109 /* sphereEnvironMapping Calculation */ \n\
1110 vec3 u=normalize(vec3(vertexPos)); /* u is normalized position, used below more than once */ \n\
1111 vec3 r= reflect(u,vertexNorm); \n\
1112 if (fw_textureCoordGenType==TCGT_SPHERE) { /* TCGT_SPHERE GL_SPHERE_MAP OpenGL Equiv */ \n\
1113 float m=2.0 * sqrt(r.x*r.x + r.y*r.y + (r.z*1.0)*(r.z*1.0)); \n\
1114 texcoord3 = vec3(r.x/m+0.5,r.y/m+0.5,0.0); \n\
1115 }else if (fw_textureCoordGenType==TCGT_CAMERASPACENORMAL) { \n\
1116 /* GL_REFLECTION_MAP used for sampling cubemaps */ \n\
1117 float dotResult = 2.0 * dot(u,r); \n\
1118 texcoord3 = vec3(u-r)*dotResult; \n\
1119 }else if (fw_textureCoordGenType==TCGT_COORD) { \n\
1120 /* 3D textures can use coords in 0-1 range */ \n\
1121 texcoord3 = fw_Vertex.xyz; //xyz; \n\
1122 } else { /* default usage - like default CubeMaps */ \n\
1123 vec3 u=normalize(vec3(fw_ProjectionMatrix * fw_Vertex)); /* myEyeVertex */ \n\
1124 texcoord3 = reflect(u,vertexNorm); \n\
1125 } \n\
1126 texcoord.xyz = texcoord3; \n\
1127 } \n\
1128 #endif //TGEN \n\
1129//constant string break " "\n\
1130 vec4 tcoord[4]; \n\
1131 tcoord[0] = texcoord; //fw_MultiTexCoord0; \n\
1132 tcoord[1] = yupuv(fw_MultiTexCoord1); \n\
1133 tcoord[2] = yupuv(fw_MultiTexCoord2); \n\
1134 tcoord[3] = yupuv(fw_MultiTexCoord3); \n\
1135 mat4 ttrans = mat4(1.0); \n\
1136 vec4 tc = vec4(0.0,0.0,0.0,1.0); \n\
1137 // loop over output (transformed) texcoord \n\
1138 //for(int i=0;i<fw_ntexcombo;i++){ \n\
1139 for(int i=0;i<6;i++){ \n\
1140 int itmap = i >= fw_ntexcombo ? -1 : fw_tmap[i]; //programmer: should it be >= ? \n\
1141 int icmap = i >= fw_ntexcombo ? -1 : fw_cmap[i]; //ditto \n\
1142 //spec rules: not enough transforms? use identity, not enough coords? use last ones\n\
1143 ttrans = mat4(1.0); \n\
1144 if(icmap < 0) icmap = min(i,nTexCoordChannels-1); \n\
1145 tc = tcoord[max(icmap,0)]; \n\
1146 //if(i < nTexMatrix) ttrans = fw_TextureMatrix[i]; \n\
1147 if(itmap > -1 && fw_tgen[itmap] != TCGT_REGULAR) { \n\
1148 vec3 vertexNorm; \n\
1149 vec4 vertexPos; \n\
1150 int tgen_type = fw_tgen[itmap]; \n\
1151 vec3 texcoord3 = tc.xyz; \n\
1152 vertexNorm = normalize((fw_NormalMatrix * vec4(fw_Normal,1.0)).xyz); \n\
1153 vertexPos = fw_ModelViewMatrix * fw_Vertex; \n\
1154 /* sphereEnvironMapping Calculation */ \n\
1155 vec3 u=normalize(vec3(vertexPos)); /* u is normalized position, used below more than once */ \n\
1156 vec3 r= reflect(u,vertexNorm); \n\
1157 if (tgen_type==TCGT_SPHERE) { /* TCGT_SPHERE GL_SPHERE_MAP OpenGL Equiv */ \n\
1158 float m=2.0 * sqrt(dot(r,r)); \n\
1159 texcoord3 = vec3(r.x/m+0.5,r.y/m+0.5,0.0); \n\
1160 }else if (tgen_type==TCGT_SPHERE_LOCAL) { \n\
1161 vec3 ul=normalize(fw_Vertex.xyz); /* u is normalized position, used below more than once */ \n\
1162 vec3 rl= reflect(ul,fw_Normal); \n\
1163 float m=2.0 * sqrt(dot(rl,rl)); \n\
1164 texcoord3 = vec3(rl.x/m+0.5,rl.y/m+0.5,0.0); \n\
1165 }else if (tgen_type==TCGT_CAMERASPACENORMAL) { \n\
1166 texcoord3 = vertexNorm*2.0 -1.0; \n\
1167 }else if (tgen_type==TCGT_CAMERASPACEPOSITION) { \n\
1168 texcoord3 = normalize(vertexPos.xyz)*2.0 -1.0; \n\
1169 }else if (tgen_type==TCGT_COORD) { \n\
1170 /* 3D textures can use coords in 0-1 range */ \n\
1171 texcoord3 = normalize(fw_Vertex.xyz)*2.0 - 1.0; //xyz; \n\
1172 }else if (tgen_type==TCGT_COORD_EYE) { \n\
1173 /* 3D textures can use coords in 0-1 range */ \n\
1174 texcoord3 = normalize(vertexPos.xyz)*2.0 - 1.0; //xyz; \n\
1175 }else if (tgen_type==TCGT_NOISE) { \n\
1176 vec3 uu = fw_Vertex.xyz; \n\
1177 uu.z *= snoise(uu); \n\
1178 texcoord3 = normalize(uu)*2.0 - 1.0; //xyz; \n\
1179 }else if (tgen_type==TCGT_NOISE_EYE) { \n\
1180 texcoord3 = normalize(vertexPos.xyz * snoise(vertexPos.xyz))*2.0 - 1.0; //xyz; \n\
1181 } else if(tgen_type == TCGT_CAMERASPACEREFLECTIONVECTOR || tgen_type == TCGT_CAMERASPACEREFLECTION){ \n\
1182 vec4 camera = fw_ModelViewInverseMatrix * vec4(0.0,0.0,0.0,1.0); \n\
1183 vec3 uu = normalize( vec4(vertex_object + camera).xyz ); \n\
1184 vec3 vv = normalize(fw_Normal); \n\
1185 texcoord3 = normalize(reflect(uu,vv)); //computed in object space \n\
1186 texcoord3.st = -texcoord3.st; //helps with renderman cubemap convention \n\
1187 } else if(tgen_type == TCGT_SPHERE_REFLECT) { \n\
1188 vec3 uu=normalize(vec3(fw_ProjectionMatrix * fw_Vertex)); /* myEyeVertex */ \n\
1189 if(fw_parameter_n == 1){ \n\
1190 float eta = 1.0/fw_parameter[0]; \n\
1191 texcoord3 = normalize(refract(uu,vertexNorm, eta)); \n\
1192 }else \n\
1193 texcoord3 = normalize(reflect(uu,vertexNorm)); \n\
1194 } else if(tgen_type == TCGT_SPHERE_REFLECT_LOCAL) { \n\
1195 vec3 vlocal = vec3(fw_parameter[1],fw_parameter[2],fw_parameter[3]);\n\
1196 vec3 uu=normalize(vec3(vlocal - fw_Vertex.xyz)); \n\
1197 float eta = 1.0/(fw_parameter[0]+.001); \n\
1198 texcoord3 = normalize(refract(uu,fw_Normal, eta)); \n\
1199 } else { /* default usage - like default CubeMaps */ \n\
1200 vec3 uu=normalize(vec3(fw_ProjectionMatrix * fw_Vertex)); /* myEyeVertex */ \n\
1201 texcoord3 = normalize(reflect(uu,vertexNorm)); \n\
1202 } \n\
1203 fw_TexCoord[i] = texcoord3; \n\
1204 } else { \n\
1205 if(itmap > -1) ttrans = fw_TextureMatrix[itmap]; \n\
1206 //if(i < nTexCoordChannels) tc = tcoord[i]; \n\
1207 fw_TexCoord[i] = dehomogenize(ttrans, tc); \n\
1208 } \n\
1209 } \n\
1210 #ifdef CUB_OLD \n\
1211 //cubemap \n\
1212 vec4 camera = fw_ModelViewInverseMatrix * vec4(0.0,0.0,0.0,1.0); \n\
1213 //vec3 u = normalize( vec4(castle_vertex_eye - camera).xyz ); \n\
1214 vec3 u = normalize( vec4(vertex_object + camera).xyz ); \n\
1215 vec3 v = normalize(fw_Normal); \n\
1216 fw_TexCoord[0] = normalize(reflect(u,v)); //computed in object space \n\
1217 fw_TexCoord[0].st = -fw_TexCoord[0].st; //helps with renderman cubemap convention \n\
1218 //for(int i=1;i<6;i++) fw_TexCoord[i] = fw_TexCoord[0]; //programmer: please integrate with multitexture (trans+coord) above\n\
1219 #endif //CUB_OLD \n\
1220 #ifdef FILL \n\
1221 hatchPosition = fw_TexCoord[0].xy; \n\
1222 #endif //FILL \n\
1223 \n\
1224 // #endif //TEX \n\
1225 \n\
1226 gl_Position = fw_ProjectionMatrix * castle_vertex_eye; \n\
1227 \n\
1228 #ifdef POINTP \n\
1229 //particle-system-like PointSet points get special CPV, fogcoord handling, like pointPosition \n\
1230 #ifdef FOGCOORD \n\
1231 fog_coord = u_pointFogCoord; \n\
1232 #endif //FOGCOORD \n\
1233 #ifdef CPV \n\
1234 cpv_Color = u_pointCPV; \n\
1235 #endif //CPV \n\
1236 if(u_pointMethod == 2) { \n\
1237 //OBJECTSCALE - keep sprite-aligned but size fade with distance \n\
1238 vec4 ppos = vec4(u_pointPosition,1.0); \n\
1239 vec4 point_eye = fw_ModelViewMatrix * ppos; \n\
1240 ppos.x += 1.0; \n\
1241 vec4 point_eye1 = fw_ModelViewMatrix * ppos; \n\
1242 float pscal = length(point_eye1.xyz - point_eye.xyz); \n\
1243 castle_vertex_eye = point_eye + pscal*vertex_object*u_pointSize; \n\
1244 gl_Position = fw_ProjectionMatrix * castle_vertex_eye; \n\
1245 }else { \n\
1246 vec4 ppos = vec4(u_pointPosition,1.0); \n\
1247 vec4 castle_vertex_eye = fw_ModelViewMatrix * ppos; \n\
1248 vec4 view_position = fw_ProjectionMatrix * castle_vertex_eye; \n\
1249 float pscal = 1.0; \n\
1250 if(u_pointMethod == 1) { \n\
1251 //simple screen scale \n\
1252 pscal = u_pointSize; \n\
1253 } else if(u_pointMethod == 3) { \n\
1254 // fancy attenuation, screen scale \n\
1255 float zdist = castle_vertex_eye.z; \n\
1256 pscal = u_pointAttenuation.x + zdist*u_pointAttenuation.y + zdist*zdist*u_pointAttenuation.z; \n\
1257 if(pscal > 0.0) pscal = u_pointSize/pscal; \n\
1258 else pscal = u_pointSize; \n\
1259 pscal = max(pscal,u_pointSizeRange.x); \n\
1260 pscal = min(pscal,u_pointSizeRange.y); \n\
1261 } \n\
1262 //convert from screen pixel size to view coords \n\
1263 vec2 view_point = (vec2(pscal)*vertex_object.xy / u_screenresolution.xy) *vec2(2.0)* view_position.w; \n\
1264 view_position.xy += view_point; \n\
1265 gl_Position = view_position; \n\
1266 } \n\
1267 #endif //POINTP \n\
1268 #ifdef FOG \n\
1269 #ifdef FOGCOORD \n\
1270 castle_vertex_eye.z = fog_coord; \n\
1271 #endif //FOGCOORD \n\
1272 #endif //FOG \n\
1273 #ifdef UNLIT \n\
1274 castle_Color = fw_UnlitColor; \n\
1275 #endif //UNLIT \n\
1276} \n";
1277
1278/*
1279Ubershader varying between vertex and fragment shader:
1280varying vec3 fw_TexCoord[6];
1281#ifdef FILL
1282varying vec2 hatchPosition;
1283varying vec4 castle_vertex_eye;
1284varying vec3 castle_normal_eye;
1285varying vec4 castle_Color; //DA diffuse ambient term
1286#ifdef LIT
1287varying vec3 castle_ColorES; //emissive shininess term
1288#ifdef CPV
1289varying vec4 cpv_Color;
1290
1291*/
1292/* Generic GLSL fragment shader.
1293 Used by ../castlerendererinternalshader.pas to construct the final shader.
1294
1295 This is converted to template.fs.inc, and is then compiled
1296 in program's binary.
1297 When you change this file, rerun `make' and then recompile Pascal sources.
1298*/
1299/*
1300 started with: http://svn.code.sf.net/p/castle-engine/code/trunk/castle_game_engine/src/x3d/opengl/glsl/template_mobile.fs
1301 defines:
1302 GL_ES_VERSION_2_0 - non-desktop
1303 HAS_GEOMETRY_SHADER - version 3+ gles
1304*/
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318static const GLchar* genericFragmentCube = "\
1319#version 450 core \n\
1320out vec4 FragColor; \n\
1321in vec3 fw_TexCoord[6]; \n\
1322 \n\
1323uniform samplerCube textureUnitCube[1]; \n\
1324 \n\
1325void main() \n\
1326{ \n\
1327 FragColor = vec4(texture(textureUnitCube[0], fw_TexCoord[0]).rgb, 1.0); \n\
1328} \n\
1329\n";
1330
1331
1332
1333
1334static const GLchar *genericFragmentGLES2 = "\
1335/*EXTENSIONS*/ \n\
1336/* DEFINES */ \n\
1337#ifdef MOBILE \n\
1338precision mediump float; \n\
1339// we index into sampler arrays, OK for desktop, mobile needs GLES 3.1 and: \n\
1340// https://www.khronos.org/registry/OpenGL/extensions/OES/OES_gpu_shader5.txt \n\
1341#extension GL_OES_gpu_shader5 : require //(or enable) \n\
1342//#else \n\
1343//precision highp float; \n\
1344#endif //MOBILE \n\
1345#define varying in \n\
1346#define texture2D texture \n\
1347#define texture3D texture \n\
1348#define textureCube texture \n\
1349#define texture2DProj textureProj \n\
1350#define texture3DProj textureProj \n\
1351out vec4 FragColor; \n\
1352/* Generic GLSL fragment shader, used on OpenGL ES. */ \n\
1353 \n\
1354varying vec4 castle_Color; \n\
1355 \n\
1356#ifdef LITE \n\
1357#define MAX_LIGHTS 8 \n\
1358#ifdef SHADOW \n\
1359//for shadows, shape frag coord transformed into light system by vertex shader \n\
1360uniform mat4 lightMat[8]; \n\
1361#endif //SHADOW \n\
1362uniform int lightcount; \n\
1363//uniform float lightRadius[MAX_LIGHTS]; \n\
1364uniform int lightType[MAX_LIGHTS];//ANGLE like this \n\
1365struct fw_LightSourceParameters { \n\
1366 float ambient; \n\
1367 vec3 color; \n\
1368 float intensity; \n\
1369 vec3 location; \n\
1370 vec3 halfVector; \n\
1371 vec3 direction; \n\
1372 float spotBeamWidth; \n\
1373 float spotCutoff; \n\
1374 vec3 Attenuations; \n\
1375 float lightRadius; \n\
1376 bool shadows; \n\
1377 float shadowIntensity; \n\
1378 int depthmap; \n\
1379}; \n\
1380\n\
1381uniform fw_LightSourceParameters fw_LightSource[MAX_LIGHTS] /* gl_MaxLights */ ;\n\
1382#endif //LITE \n\
1383\n\
1384#ifdef CPV \n\
1385varying vec4 cpv_Color; \n\
1386#endif //CPV \n\
1387struct MaterialInfo \n\
1388{ \n\
1389 float perceptualRoughness; // roughness value, as authored by the model creator (input to shader) \n\
1390 vec3 reflectance0; // full reflectance color (normal incidence angle) \n\
1391 \n\
1392 float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2]) \n\
1393 vec3 diffuseColor; // color contribution from diffuse lighting \n\
1394 \n\
1395 vec3 reflectance90; // reflectance color at grazing angle \n\
1396 vec3 specularColor; // color contribution from specular lighting \n\
1397}; \n\
1398\n\
1399/* PLUG-DECLARATIONS */ \n\
1400//#ifdef TEX \n\
1401uniform int textureCount; \n\
1402varying vec3 fw_TexCoord[6]; \n\
1403#ifdef TEX3D \n\
1404uniform int tex3dTiles[3]; \n\
1405uniform int repeatSTR[3]; \n\
1406uniform int magFilter; \n\
1407#endif //TEX3D \n\
1408#if defined(TEX3D) || defined(TEX3DLAY) \n\
1409uniform sampler2D fw_Texture_unit0; \n\
1410#endif //TEX3D || TEX3DLAY \n\
1411#ifdef TEX3DLAY \n\
1412//uniform sampler2D fw_Texture_unit0; \n\
1413uniform sampler2D fw_Texture_unit1; \n\
1414uniform sampler2D fw_Texture_unit2; \n\
1415uniform sampler2D fw_Texture_unit3; \n\
1416//uniform int textureCount; \n\
1417#endif //TEX3DLAY \n\
1418#if defined(MTEXA) || defined(PROJTEX) \n\
1419uniform sampler2D fw_Texture_unit1; \n\
1420uniform sampler2D fw_Texture_unit2; \n\
1421uniform sampler2D fw_Texture_unit3; \n\
1422uniform ivec2 fw_Texture_mode0; \n\
1423uniform ivec2 fw_Texture_mode1; \n\
1424uniform ivec2 fw_Texture_mode2; \n\
1425uniform ivec2 fw_Texture_mode3; \n\
1426uniform ivec2 fw_Texture_source0; \n\
1427uniform ivec2 fw_Texture_source1; \n\
1428uniform ivec2 fw_Texture_source2; \n\
1429uniform ivec2 fw_Texture_source3; \n\
1430uniform int fw_Texture_function0; \n\
1431uniform int fw_Texture_function1; \n\
1432uniform int fw_Texture_function2; \n\
1433uniform int fw_Texture_function3; \n\
1434//uniform int textureCount; \n\
1435void finalColCalcA(inout vec4 prevColour, in int mode, in int modea, in int func, in sampler2D tex, in vec2 texcoord){ \n\
1436 /* PLUG: finalColCalc ( prevColour, mode, modea, func, tex, texcoord ) */ \n\
1437} \n\
1438#endif //defined(MTEXA) || defined(PROJTEX) \n\
1439#if defined(MTEX) || defined(PROJTEX) \n\
1440uniform vec4 mt_Color; \n\
1441void finalColCalcB(inout vec4 prevColour, in int mode, in int modea, in int func, in vec4 currentColor){ \n\
1442 /* PLUG: finalColCalc0 ( prevColour, mode, modea, func, currentColor ) */ \n\
1443} \n\
1444#endif //defined(MTEX) || defined(PROJTEX) \n\
1445//#endif //TEX \n\
1446//literal string size break \n" "\
1447#ifdef POINTP \n\
1448uniform int u_pointColorMode; \n\
1449#endif //POINTP \n\
1450#if defined(LINETYPE) && defined(FULL) \n\
1451uniform int u_linetype; \n\
1452uniform float u_lineperiod; \n\
1453uniform float u_linewidth; \n\
1454uniform int u_linestrip_start_style; \n\
1455uniform int u_linestrip_end_style; \n\
1456uniform vec2 u_linetype_uv[128]; \n\
1457uniform vec3 u_linetype_tse[128]; \n\
1458uniform vec4 u_screenresolution; \n\
1459 \n\
1460flat in vec2 f_prev; \n\
1461flat in vec2 f_next; \n\
1462flat in float f_linestrip_end; \n\
1463in vec2 v_curr; \n\
1464bool approx(float a, float b){ \n\
1465 if( abs(a-b) < .0001) return true; \n\
1466 return false; \n\
1467} \n\
1468bool on_linetype(inout vec4 frag_color){ \n\
1469 bool on = true; \n\
1470 if(false){ \n\
1471 //procedural dashed line method (not used but works for simple dash)\n\
1472 float distance = length(v_curr - f_prev); \n\
1473 //info about cycle length \n\
1474 float period = 20.0; \n\
1475 float phase = mod(distance,20.0); \n\
1476 if(phase > 10.0) on = false; \n\
1477 }else{ \n\
1478 //parametric dashed line method \n\
1479 vec2 baseline = f_next - f_prev; \n\
1480 vec2 u_dir = normalize(baseline); \n\
1481 vec2 v_dir = normalize(cross(vec3(0,0,1),vec3(u_dir,0.0)).xy); \n\
1482 vec2 ubar; \n\
1483 //gl_FragCoord is relative to whole opengl window, we need viewport \n\
1484 vec2 vpcoord = gl_FragCoord.xy - u_screenresolution.pq; \n\
1485 ubar.s = dot(vpcoord.xy - f_prev, u_dir); \n\
1486 ubar.t = dot(vpcoord.xy - v_curr, v_dir); \n\
1487 float phase = mod(ubar.s, u_lineperiod); \n\
1488 vec2 uu = vec2(0.0,0.0); \n\
1489 bool gap = false; \n\
1490 vec2 dash; \n\
1491 vec3 tse = u_linetype_tse[int(phase)]; \n\
1492 uu = u_linetype_uv[int(phase)]; \n\
1493 gap = int(tse.x + .5) == 0; \n\
1494 dash = vec2(tse.y,tse.z); \n\
1495 vec2 ubarperiod = vec2(phase,ubar.t); \n\
1496 if(gap){ \n\
1497 on = false; \n\
1498 } else { \n\
1499 if( abs(ubarperiod.t - uu.t) > u_linewidth ) on = false; \n\
1500 //if( length(ubarperiod-uu) > u_linewidth *.5 ) on = false; \n\
1501 } \n\
1502 //do fancy linestrip end if required and on linestrip end segment \n\
1503 if( u_linestrip_start_style > 0 || u_linestrip_end_style > 0) \n\
1504 if(!approx(f_linestrip_end,0.0)){ \n\
1505 //a line can be both start and and of polyline \n\
1506 bool s_start = approx(mod(f_linestrip_end,2.0),1.0); \n\
1507 bool s_end = approx(floor(f_linestrip_end/2.0),1.0); \n\
1508 if(s_start){ \n\
1509 vec2 uend = vec2(0.0); \n\
1510 if(u_linestrip_start_style == 1){ \n\
1511 //arrow end \n\
1512 float arrowlength = 14.0; \n\
1513 vec2 head = vec2(uend.s + arrowlength,0.0); \n\
1514 if(ubar.s < head.s){ \n\
1515 on = false; \n\
1516 vec2 range = head - ubar; \n\
1517 float d = 2.0*range.t + range.s; \n\
1518 if(d < arrowlength) on = true; \n\
1519 } \n\
1520 } else if(u_linestrip_start_style == 2){ \n\
1521 //round end \n\
1522 float radius = 6.0; \n\
1523 vec2 center = vec2(0.0); \n\
1524 center.s = (uend.s + radius); \n\
1525 vec2 diameter = uend + vec2(2.0*radius,0.0); \n\
1526 if(ubar.s < diameter.s){ \n\
1527 on = false; \n\
1528 if( length(ubar - center) <= radius ) on = true; \n\
1529 } \n\
1530 } \n\
1531 } \n\
1532 if(s_end){ \n\
1533 vec2 uend = vec2(0.0); \n\
1534 uend.s = dot(f_next - f_prev, u_dir); \n\
1535 //must be end 2.0 \n\
1536 if(u_linestrip_end_style == 1){ \n\
1537 //arrow end \n\
1538 float arrowlength = 14.0; \n\
1539 vec2 head = vec2(uend.s - arrowlength,0.0); \n\
1540 if(ubar.s > head.s){ \n\
1541 on = false; \n\
1542 vec2 range = ubar - head; \n\
1543 float d = 2.0*range.t + range.s; \n\
1544 if(d < arrowlength) on = true; \n\
1545 } \n\
1546 } else if(u_linestrip_end_style == 2){ \n\
1547 //round end \n\
1548 float radius = 6.0; \n\
1549 vec2 center = vec2(0.0); \n\
1550 center.s = (uend.s- radius); \n\
1551 vec2 diameter = uend - vec2(2.0*radius,0.0); \n\
1552 if(ubar.s > diameter.s){ \n\
1553 on = false; \n\
1554 if( length(ubar - center) <= radius ) on = true; \n\
1555 } \n\
1556 } \n\
1557 } \n\
1558 } \n\
1559 }\n\
1560 return on; \n\
1561}\n\
1562#endif //LINETYPE\n\
1563#ifdef FILL \n\
1564struct fillproperties { \n\
1565 vec4 HatchColour; \n\
1566 int HatchAlgo; \n\
1567 bool hatched; \n\
1568 bool filled; \n\
1569}; \n\
1570uniform fillproperties fillprops; \n\
1571varying vec2 hatchPosition; \n\
1572#endif //FILL \n\
1573//literal string size break \n" "\
1574#ifdef FOG \n\
1575struct fogParams \n\
1576{ \n\
1577 vec4 fogColor; \n\
1578 float visibilityRange; \n\
1579 float fogScale; \n\
1580 int fogType; // 0 None, 1= FOGTYPE_LINEAR, 2 = FOGTYPE_EXPONENTIAL \n\
1581 // ifdefed int haveFogCoords; \n\
1582}; \n\
1583uniform fogParams fw_fogparams; \n\
1584#endif //FOG \n\
1585 \n\
1586#ifdef HAS_GEOMETRY_SHADER \n\
1587#define castle_vertex_eye castle_vertex_eye_geoshader \n\
1588#define castle_normal_eye castle_normal_eye_geoshader \n\
1589#endif // HAS_GEOMETRY_SHADER \n\
1590 \n\
1591varying vec4 castle_vertex_eye; \n\
1592varying vec3 castle_normal_eye; \n\
1593//#ifdef LIT \n\
1594//#ifdef LITE \n\
1595//per-fragment lighting ie phong \n\
1596struct fw_MaterialParameters { \n\
1597 vec3 diffuse; \n\
1598 vec3 emissive; \n\
1599 vec3 specular; \n\
1600 float ambient; \n\
1601 float shininess; \n\
1602 float occlusion; \n\
1603 float normalScale; \n\
1604 float transparency; \n\
1605 vec3 baseColor; \n\
1606 float metallic; \n\
1607 float roughness; \n\
1608 int type; \n\
1609 // multitextures are disaggregated \n\
1610 int tindex[10]; \n\
1611 int mode[10]; \n\
1612 int source[10]; \n\
1613 int func[10]; \n\
1614 int samplr[10]; //0 texture2D 1 cubeMap \n\
1615 int cmap[10]; \n\
1616 int nt; //total single textures \n\
1617 //iunit [0] normal [1] emissive [2] occlusion [3] diffuse OR base [4] shininess OR metallicRoughness [5] specular [6] ambient \n\
1618 int tcount[7]; //num single textures 1= one texture 0=no texture 2+ = multitexture \n\
1619 int tstart[7]; // where in packed tindex list to start looping \n\
1620 //int cindex[7]; // which geometry multitexcoord channel 0=default \n\
1621}; \n\
1622uniform fw_MaterialParameters fw_FrontMaterial; \n\
1623//#ifdef TWO \n\
1624uniform fw_MaterialParameters fw_BackMaterial; \n\
1625//#endif //TWO \n\
1626#ifdef LIT \n\
1627//#ifdef LITE \n\
1628//vec3 castle_ColorES; \n\
1629//#else //LITE \n\
1630//per-vertex lighting - interpolated Emissive-specular \n\
1631varying vec3 castle_ColorES; //emissive shininess term \n\
1632//#endif //LITE \n\
1633#endif //LIT\n\
1634//#if defined(TEX) || defined(PROJTEX) \n\
1635#if defined(SHADOW) || defined(CUB) || defined(PROJTEX) \n\
1636//shared samplerCube array -pointlight shadows, cubemapTextures \n\
1637uniform samplerCube textureUnitCube[8]; \n\
1638//shared sampler2D array -PTM or PBR use \n\
1639uniform sampler2D textureUnit[8]; \n\
1640#else //SHADOW || CUB \n\
1641//shared sampler2D array -PTM or PBR use \n\
1642uniform sampler2D textureUnit[16]; \n\
1643#endif //SHADOW || CUB || PROJTEX\n\
1644#if defined(SHADOW) || defined(PROJTEX) //this stuff only works in the fragment shader \n\
1645float local3D2cubedepth(in vec3 local, in float near, in float far) \n\
1646{ \n\
1647 //for cubemap depth, find which of 6 (perspective-rendered depthmap) faces will be sampled, \n\
1648 // and scale local 3d vector to depth map scale for comparison elsewhere \n\
1649 // https://en.wikipedia.org/wiki/Z-buffering#Mathematics \n\
1650 // https://stackoverflow.com/questions/10786951/omnidirectional-shadow-mapping-with-depth-cubemap \n\
1651 vec3 abslocal = abs(local); \n\
1652 float maxAxis = max(abslocal.x, max(abslocal.y, abslocal.z)); \n\
1653 float zfactor = (far + near) / (far - near) - (2.0 * far * near) / (far - near) / maxAxis; \n\
1654 return (zfactor + 1.0) * 0.5; \n\
1655} \n\
1656#endif //SHADOW || PROJTEX \n\
1657#ifdef SHADOW \n\
1658float ShadowCalculation(in int ilight, in vec3 lightdir) \n\
1659{ \n\
1660 float shadow = 0.0; \n\
1661 vec4 lightCoord = lightMat[ilight] * castle_vertex_eye; \n\
1662 vec4 lightNorm = lightMat[ilight] * vec4((castle_vertex_eye.xyz + castle_normal_eye.xyz),1.0); \n\
1663 vec4 fragPosLightSpace = lightCoord; \n\
1664 int type = lightType[ilight]; \n\
1665 vec3 projCoords, projNorm; \n\
1666 // perform perspective divide \n\
1667 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; \n\
1668 //instead of inverseTranspose we transform another point, and subtract \n\
1669 projNorm = lightNorm.xyz/lightNorm.w; \n\
1670 float closestDepth = 10.0; \n\
1671 float currentDepth = 10.0; \n\
1672 if(type == 0){ \n\
1673 //PointLight uses cubemap shadow and 3D lookup coord \n\
1674 vec3 pc = lightCoord.xyz; \n\
1675 pc.yz = -pc.yz; \n\
1676 vec3 nc = normalize(pc); \n\
1677 closestDepth = texture(textureUnitCube[fw_LightSource[ilight].depthmap], nc).r; \n\
1678 currentDepth = local3D2cubedepth(pc,.1,fw_LightSource[ilight].lightRadius); \n\
1679 }else{ \n\
1680 // transform to [0,1] range \n\
1681 projCoords = projCoords * 0.5 + 0.5; \n\
1682 // get closest depth value from light's perspective (using [0,1] range fragPosLight as coords) \n\
1683 closestDepth = texture(textureUnit[fw_LightSource[ilight].depthmap], projCoords.xy).r; \n\
1684 // get depth of current fragment from light's perspective \n\
1685 currentDepth = projCoords.z; \n\
1686 if (projCoords.z > 1.0) \n\
1687 currentDepth = 1.0; \n\
1688 } \n\
1689 // calculate bias (based on depth map resolution and slope) \n\
1690 vec3 normal = normalize(projNorm-projCoords); \n\
1691 //vec3 lightDir = normalize(lightPos - fs_in.FragPos); \n\
1692 vec3 lightDir = normalize(lightdir); \n\
1693 // https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping \n\
1694 // solve shadow acne with a small bias \n\
1695 //float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005); \n\
1696 float bias = 0.005; \n\
1697 // check whether current frag pos is in shadow \n\
1698 shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; \n\
1699 //shadow = (currentDepth - bias - closestDepth)*100.0; \n\
1700 //shadow = currentDepth; \n\
1701 //shadow = 0.0; \n\
1702 //shadow = closestDepth; \n\
1703#ifdef PCF \n\
1704 shadow = 0.0; \n\
1705 vec2 texelSize = 1.0 / textureSize(textureUnit[fw_LightSource[ilight].depthmap], 0); \n\
1706 for (int x = -1; x <= 1; ++x) \n\
1707 { \n\
1708 for (int y = -1; y <= 1; ++y) \n\
1709 { \n\
1710 float pcfDepth = texture(textureUnit[fw_LightSource[ilight].depthmap], projCoords.xy + vec2(x, y) * texelSize).r; \n\
1711 shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0; \n\
1712 } \n\
1713 } \n\
1714 shadow /= 9.0; \n\
1715#endif //PCF \n\
1716 // keep the shadow at 0.0 when outside the far_plane region of the light's frustum. \n\
1717 //if (projCoords.z > 1.0) \n\
1718 // shadow = 0.0; \n\
1719 return shadow; \n\
1720} \n\
1721#endif //SHADOW \n\
1722//#endif //defined(TEX) || defined(PROJTEX) \n\
1723#ifdef PROJTEX \n\
1724//per projector: \n\
1725struct TextureProjectorProperties { \n\
1726 mat4 GenMatCam; \n\
1727 int backCull; \n\
1728 vec3 color; \n\
1729 int tstart; \n\
1730 int tcount; \n\
1731 float farDistance; \n\
1732 int type; //0,1 2D 2 cubemap \n\
1733 float intensity; \n\
1734 int shadows; \n\
1735 float shadowIntensity; \n\
1736 int depthmap; \n\
1737}; \n\
1738uniform struct TextureProjectorProperties ptms[8]; \n\
1739struct TextureDescriptor { \n\
1740//per texture descriptor (projector 1:m texdescriptor m:1 sampler): \n\
1741 int tindex; \n\
1742 int mode; \n\
1743 int source; \n\
1744 int func; \n\
1745 int samplr; \n\
1746}; \n\
1747uniform struct TextureDescriptor tdescs[16]; \n\
1748uniform int ptmCount; \n\
1749vec4 fragProjCalTexCoord(in vec4 frag_color) { \n\
1750 int k=0; \n\
1751 for(int i=0;i<ptmCount;i++) { \n\
1752 struct TextureProjectorProperties ptm = ptms[i]; \n\
1753 //is point on + side of projector ? \n\
1754 vec4 projTexCoord = ptm.GenMatCam * vec4(castle_vertex_eye.xyz,1.0); \n\
1755 vec4 projTexNorm = ptm.GenMatCam * vec4((castle_vertex_eye.xyz + castle_normal_eye.xyz),1.0); \n\
1756 if(ptm.type == 2) { \n\
1757 //ProjectorPoint uses cubemap for diffuse and shadow, and a 3D lookup coord \n\
1758 vec3 pc = projTexCoord.xyz; \n\
1759 bool facingProjector = true; \n\
1760 if(ptm.backCull == 1) \n\
1761 { \n\
1762 vec3 pn = projTexNorm.xyz/projTexNorm.w; \n\
1763 vec3 nvec = normalize(pn - pc); \n\
1764 vec3 pvec = normalize(pc); \n\
1765 float dotval = dot(nvec,pvec); \n\
1766 facingProjector = (dotval <= 0.0); \n\
1767 } \n\
1768 if(facingProjector){ \n\
1769 if(ptm.shadows > 0){ \n\
1770 vec3 nc = normalize(pc); \n\
1771 nc.yz = -nc.yz; \n\
1772 float closestDepth = texture(textureUnitCube[ptm.depthmap], nc).r; \n\
1773 float currentDepth = local3D2cubedepth(pc,.1,ptm.farDistance); \n\
1774 //float currentDepth = length(nc); \n\
1775 //float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005); \n\
1776 float bias = 0.005; \n\
1777 // check whether current frag pos is in shadow \n\
1778 float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; \n\
1779 facingProjector = shadow == 0.0; \n\
1780 } \n\
1781 } \n\
1782 if(facingProjector){ \n\
1783 //pc.yz = -pc.yz; //renderman cubemap convention \n\
1784 vec3 nc = normalize(pc); \n\
1785 struct TextureDescriptor tdesc = tdescs[ptm.tstart]; \n\
1786 frag_color.rgb = texture(textureUnitCube[tdesc.tindex], nc).rgb; \n\
1787 frag_color.rgb = frag_color.rgb * ptm.color * ptm.intensity; \n\
1788 frag_color.a = 1.0; \n\
1789 } \n\
1790 } else { //ptm.type \n\
1791 if( projTexCoord.z > 0.0 ){ \n\
1792 vec4 pp = projTexCoord; \n\
1793 bool inside = (-pp.w < pp.x) && (pp.x < pp.w); \n\
1794 inside = inside && (-pp.w < pp.y) && (pp.y < pp.w); \n\
1795 inside = inside && (-pp.w < pp.z) && (pp.z < pp.w); \n\
1796 if(inside){ \n\
1797 bool facingProjector = true; \n\
1798 vec3 pptex = pp.xyz/pp.w; \n\
1799 if(ptm.backCull == 1) \n\
1800 { \n\
1801 vec3 pn = projTexNorm.xyz/projTexNorm.w; \n\
1802 //if(!gl_FrontFacing) pn = -pn; \n\
1803 vec3 nvec = normalize(pn - pptex.xyz); \n\
1804 vec3 peye = vec3(0.0,0.0,1.0); //normalize(pc); \n\
1805 float dotval = dot(nvec,peye); \n\
1806 facingProjector = (dotval < 0.0); \n\
1807 } \n\
1808 pptex.xyz = pptex.xyz *.5 + .5; \n\
1809 if(facingProjector){ \n\
1810 if(ptm.shadows > 0){ \n\
1811 float currentDepth = pptex.z; \n\
1812 //if (pptex.z > 1.0) \n\
1813 // currentDepth = 1.0; \n\
1814 float closestDepth = texture2D(textureUnit[ptm.depthmap],pptex.xy).r; \n\
1815 //float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005); \n\
1816 float bias = 0.005; \n\
1817 // check whether current frag pos is in shadow \n\
1818 float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; \n\
1819 //frag_color = vec4(vec3(ptmdepthmap[i]),1.0); \n\
1820 //frag_color = vec4(vec3(.2,.2,depthValue),1.0); \n\
1821 facingProjector = shadow == 0.0; //pptex.z < depthValue; \n\
1822 } \n\
1823 } \n\
1824 if(facingProjector){ \n\
1825 //parallel/ortho \n\
1826 vec2 ptex = pptex.xy; \n\
1827 //ptex.x = (ptex.x * .5) + .5; \n\
1828 //ptex.y = (ptex.y * .5) + .5; \n\
1829 int ndesc = ptm.tcount; \n\
1830 struct TextureDescriptor tdesc; \n\
1831 vec4 prev = frag_color; \n\
1832 for(int j=0;j<ndesc;j++){ \n\
1833 tdesc = tdescs[ptm.tstart+j]; \n\
1834 int kk = tdesc.tindex; \n\
1835 int modea = int(tdesc.mode / 100); \n\
1836 int mode = tdesc.mode - 100*modea; \n\
1837 finalColCalcA(prev, mode, modea, tdesc.func, textureUnit[tdesc.tindex], ptex); \n\
1838 } \n\
1839 //frag_color = prev;\n\
1840 frag_color.rgb = prev.rgb * ptm.color * ptm.intensity; \n\
1841 frag_color.a = prev.a; \n\
1842 } \n\
1843 } \n\
1844 } \n\
1845 } //ptm.type \n\
1846 } \n\
1847 return frag_color; \n\
1848} \n\
1849#endif //PROJTEX \n\
1850/* Wrapper for calling PLUG texture_coord_shift */ \n\
1851vec2 texture_coord_shifted(in vec2 tex_coord) \n\
1852{ \n\
1853 /* PLUG: texture_coord_shift (tex_coord) */ \n\
1854 return tex_coord; \n\
1855} \n\
1856//literal string size break \n" "\
1857//statics for multitexturing function\n\
1858vec3 mtex_specular; \n\
1859vec4 mtex_diffuse; \n\
1860//PHYSICAL LIGHTING >> \n\
1861// https://github.com/KhronosGroup/glTF-Sample-Viewer \n\
1862const float M_PI = 3.141592653589793; \n\
1863// sRGB to linear approximation \n\
1864const float GAMMA = 2.2; \n\
1865vec4 SRGBtoLINEAR(vec4 srgbIn) \n\
1866{ \n\
1867 return vec4(pow(srgbIn.xyz, vec3(GAMMA)), srgbIn.w); \n\
1868} \n\
1869const float INV_GAMMA = 1.0 / GAMMA; \n\
1870// linear to sRGB approximation \n\
1871vec3 LINEARtoSRGB(vec3 color) \n\
1872{ \n\
1873 return pow(color, vec3(INV_GAMMA)); \n\
1874} \n\
1875// << PhYSICAL LIGHTING \n\
1876//GETTERS \n\
1877fw_MaterialParameters mat = fw_FrontMaterial; \n\
1878// material.maps: iuse [0] normal [1] emissive [2] occlusion [3] diffuse OR base [4] shininess OR metallicRoughness [5] specular [6] ambient \n\
1879vec4 sample_map(in int iuse, in int istage, in bool apply_gamma){ \n\
1880 //simpler than texture_apply, just for 1 texture \n\
1881 vec4 nc = vec4(1.0,1.0,1.0,1.0); \n\
1882 int tex_index = mat.tindex[mat.tstart[iuse]+istage]; \n\
1883 int coord_index = mat.cmap[mat.tstart[iuse]+istage]; \n\
1884 int samplr = mat.samplr[mat.tstart[iuse]+istage]; \n\
1885 #ifdef CUB \n\
1886 if(samplr == 1) \n\
1887 nc = texture(textureUnitCube[tex_index], fw_TexCoord[coord_index].xyz); \n\
1888 else \n\
1889 #endif //CUB \n\
1890 nc = texture2D(textureUnit[tex_index],fw_TexCoord[coord_index].st); \n\
1891 if(apply_gamma) nc = SRGBtoLINEAR(nc); \n\
1892 return nc; \n\
1893} \n\
1894vec3 getNormal(){ \n\
1895 int normal_image = 0; \n\
1896 vec3 N = normalize (castle_normal_eye); \n\
1897 if (!gl_FrontFacing) //backFacing \n\
1898 N = -N; \n\
1899 if(mat.tcount[normal_image] > 0){ \n\
1900 // https://learnopengl.com/Advanced-Lighting/Normal-Mapping \n\
1901 //texture transform applied in vertex shader \n\
1902 vec2 UV = fw_TexCoord[mat.cmap[mat.tstart[normal_image]]].xy; \n\
1903 \n\
1904 // Retrieve the tangent space matrix \n\
1905 vec3 pos_dx = dFdx(castle_vertex_eye.xyz); \n\
1906 vec3 pos_dy = dFdy(castle_vertex_eye.xyz); \n\
1907 vec3 tex_dx = dFdx(vec3(UV, 0.0)); \n\
1908 vec3 tex_dy = dFdy(vec3(UV, 0.0)); \n\
1909 vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t); \n\
1910 \n\
1911 t = normalize(t - N * dot(N, t)); \n\
1912 vec3 b = normalize(cross(N, t)); \n\
1913 mat3 tbn = mat3(t, b, N); \n\
1914 //vec4 nc = texture2D(textureUnit[mat.tindex[mat.tstart[0]]],fw_TexCoord[mat.cindex[normal_image]].xy); \n\
1915 vec4 nc = sample_map(normal_image,0,false); \n\
1916 vec3 ncn = normalize(vec3(nc.x * 2.0 - 1.0, nc.y*2.0 -1.0, nc.z)); //-1 to 1, -1 to 1, 0 to 1 \n\
1917 vec3 ncns = normalize(ncn*vec3(mat.normalScale,mat.normalScale,1.0)); \n\
1918 //normal.xyz = normalize((textureSample(normalTexture).rgb * vec3(2,2,2) - vec3(1,1,1)) * vec3(normalScale, normalScale, 1)) \n\
1919 //vec3 nscaled = normalize(nc.xyz*vec3(2.0,2.0,2.0) - vec3(1.0,1.0,1.0)*vec3(mat.normalScale,mat.normalScale,1.0)); \n\
1920 //N = normalize(tbn * (2.0 * nc.xyz - 1.0)); \n\
1921 //N = normalize(tbn * (2.0 * nc.xyz - vec3(mat.normalScale,mat.normalScale,1.0))); \n\
1922 N = normalize(tbn * ncns); \n\
1923 } \n\
1924 return N; \n\
1925} \n\
1926vec3 getEmissive(){ \n\
1927 vec3 E = mat.emissive; \n\
1928 int emissive_image = 1; \n\
1929 if(mat.type > 0 && mat.tcount[emissive_image] > 0){ \n\
1930 vec4 ec = sample_map(emissive_image,0,false); \n\
1931 E.rgb *= ec.rgb; \n\
1932 } \n\
1933 return E; \n\
1934} \n\
1935float getAlpha(){ \n\
1936 float A = 1.0; \n\
1937 if(mat.type > 0) { \n\
1938 A -= mat.transparency; \n\
1939 int transparency_image = 3; //diffuse or base image \n\
1940 if(mat.type == 1) transparency_image = 1; //emissive image \n\
1941 if(mat.tcount[transparency_image] > 0) { \n\
1942 vec4 dc = sample_map(transparency_image,0,false); \n\
1943 A *= dc.a; \n\
1944 } \n\
1945 } \n\
1946 return A; \n\
1947} \n\
1948float getOcclusion(){ \n\
1949 float occ = 1.0; //1=not occluded, 0=occluded\n\
1950 if(mat.type == 2 || mat.type == 3) { \n\
1951 int occlusion_image = 2; \n\
1952 if(mat.tcount[occlusion_image] > 0) { \n\
1953 occ = mat.occlusion; //occlusionStrength \n\
1954 vec4 oc = sample_map(occlusion_image,0,false); \n\
1955 occ *= oc.r; //only the red \n\
1956 } \n\
1957 } \n\
1958 return occ; \n\
1959} \n\
1960float getShininess() { \n\
1961 float S = mat.shininess; \n\
1962 int shininess_image = 4; \n\
1963 if(mat.type == 2 && mat.tcount[shininess_image] > 0){ \n\
1964 vec4 sc = sample_map(shininess_image,0,false); \n\
1965 S *= sc.a; \n\
1966 } \n\
1967 return S; \n\
1968} \n\
1969vec3 getSpecular() { \n\
1970 vec3 S = mat.specular; \n\
1971 int specular_image = 5; \n\
1972 if(mat.type == 2 && mat.tcount[specular_image] > 0){ \n\
1973 vec4 sc = sample_map(specular_image,0,false); \n\
1974 S.rgb *= sc.rgb; \n\
1975 } \n\
1976 return S; \n\
1977} \n\
1978float getAmbient(){ \n\
1979 float amb = mat.ambient; \n\
1980 int ambient_image = 6; \n\
1981 if(mat.type == 2 && mat.tcount[ambient_image] > 0){ \n\
1982 vec4 ac = sample_map(ambient_image,0,false); \n\
1983 amb *= ac.r; \n\
1984 } \n\
1985 return amb; \n\
1986} \n\
1987float getMetallic(){ \n\
1988 float met = mat.metallic; \n\
1989 int metallic_image = 4; \n\
1990 if(mat.type == 3 && mat.tcount[metallic_image] > 0){ \n\
1991 vec4 mr = sample_map(metallic_image,0,false); \n\
1992 met *= mr.b; \n\
1993 } \n\
1994 return met; \n\
1995} \n\
1996float getRoughness(){ \n\
1997 float rou = mat.roughness; \n\
1998 int roughness_image = 4; //same as metallic \n\
1999 if(mat.type == 3 && mat.tcount[roughness_image] > 0){ \n\
2000 vec4 mr = sample_map(roughness_image,0,false); \n\
2001 rou *= mr.g; \n\
2002 } \n\
2003 return rou; \n\
2004} \n\
2005vec4 getVertexColor() { \n\
2006 //H: this is supposed to be from vertex shader \n\
2007 vec4 color = vec4(1.0); \n\
2008 #ifdef CPV \n\
2009 color = cpv_Color; \n\
2010 #endif //CPV \n\
2011 return color; \n\
2012} \n\
2013vec4 getMainColor(in vec4 fragColor, in int iuse) { \n\
2014 // https://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/lighting.html#Lightingoff \n\
2015 // table 17-2, 17-3 logic here \n\
2016 // function returns ODrgb (lit) or Irgb (unlit) \n\
2017 // MODT - freewrl out-of-spec option: alwasy modulate texture with diffuse \n\
2018 // MODC - illuminance texture, modulate texture with any CPV/CPF or mat.diffuse if no CPV \n\
2019 // MODA - texture has no interesting alpha, use material.diffuse.a \n\
2020 vec4 dcolor = fragColor; \n\
2021 float mixcpv = 0.0; \n\
2022 #ifdef CPV \n\
2023 mixcpv = 1.0; \n\
2024 #endif //CPV \n\
2025 #ifdef TEX \n\
2026 #ifndef MODC \n\
2027 mixcpv = 0.0; \n\
2028 #endif //MODC \n\
2029 #endif //TEX \n\
2030 vec4 IC = getVertexColor(); \n\
2031 dcolor = mix(dcolor,IC,mixcpv); \n\
2032 #ifdef TEX \n\
2033 if(mat.tcount[iuse] > 0){ \n\
2034 //appearance level textures (vs material level) \n\
2035 vec4 tcolor = vec4(1.0); \n\
2036 #if defined(MODT) || defined(MODC) \n\
2037 tcolor.rgb = dcolor.rgb; \n\
2038 #endif //MODT || MODC \n\
2039 /* PLUG: texture_apply (tcolor, iuse) */ \n\
2040 dcolor.rgb *= tcolor.rgb; \n\
2041 #ifdef MODA \n\
2042 dcolor.a *= tcolor.a; \n\
2043 #else //MODA \n\
2044 dcolor.a = tcolor.a; \n\
2045 #endif //MODA \n\
2046 } \n\
2047 #endif //TEX \n\
2048 return dcolor; \n\
2049} \n\
2050vec4 getGouraudColor() { \n\
2051 vec4 dcolor = castle_Color; \n\
2052 #ifdef LIT\n\
2053 dcolor = vec4(clamp(castle_ColorES + castle_Color.rgb,0.0,1.0),castle_Color.a); \n\
2054 #endif //LIT \n\
2055 #ifdef CPV \n\
2056 dcolor = cpv_Color; \n\
2057 #endif //CPV \n\
2058 #ifdef TEX \n\
2059 int iuse = mat.type < 2 ? 1 : 3; \n\
2060 if(mat.tcount[iuse] > 0){ \n\
2061 vec4 tcolor = vec4(1.0); \n\
2062 #if defined(MODT) || defined(MODC) \n\
2063 tcolor.rgb = dcolor.rgb; \n\
2064 #endif //MODT || MODC \n\
2065 /* PLUG: texture_apply (tcolor, iuse) */ \n\
2066 dcolor.rgb = tcolor.rgb; \n\
2067 #ifdef MODA \n\
2068 dcolor.a *= tcolor.a; \n\
2069 #else //MODA \n\
2070 dcolor.a = tcolor.a; \n\
2071 #endif //MODA \n\
2072 } \n\
2073 #endif //TEX \n\
2074 return dcolor; \n\
2075} \n\
2076uniform int material_side; //see renderfuncs reallydrawonce //0= front and back - no material difference, 1 = front 2=back\n\
2077//literal string size break \n" "\
2078void main(void) \n\
2079{ \n\
2080//STEP0 MATERIALS \n\
2081 #ifdef LIT \n\
2082 mtex_specular = castle_ColorES; \n\
2083 mtex_diffuse = castle_Color; \n\
2084 #endif //LIT \n\
2085 /* back Facing materials - flip the normal and grab back materials */ \n\
2086 if (gl_FrontFacing && material_side == 2) discard; \n\
2087 if(!gl_FrontFacing && material_side == 1) discard; \n\
2088 //if (!gl_FrontFacing){ //backFacing) { \n\
2089 mat = fw_FrontMaterial; \n\
2090 if(material_side == 2){ \n\
2091 //#ifdef TWO \n\
2092 mat = fw_BackMaterial; \n\
2093 //#endif //TWO \n\
2094 } \n\
2095 vec3 N = getNormal(); \n\
2096 \n\
2097//STEP1 INITIALIZE \n\
2098 vec4 fragment_color; \n\
2099 #ifdef LINE \n\
2100 //lines are unlit (no lights) \n\
2101 vec4 dcolor = vec4(1.0); \n\
2102 dcolor.rgb = getEmissive(); \n\
2103 #ifdef CPV \n\
2104 dcolor= getVertexColor(); \n\
2105 #endif //CVP \n\
2106 #ifdef POINTP \n\
2107 #ifdef TEX \n\
2108 //if(textureCount > 0){ \n\
2109 int iuse = mat.type < 2 ? 1 : 3; \n\
2110 if(mat.tcount[iuse] > 0){ \n\
2111 vec3 N = getNormal(); \n\
2112 vec4 tcolor = vec4(1); \n\
2113 /* PLUG: texture_apply (tcolor, iuse) */ \n\
2114 if(u_pointColorMode == 1) dcolor.a = tcolor.a; \n\
2115 if(u_pointColorMode == 2) dcolor = tcolor; \n\
2116 if(u_pointColorMode == 3) { \n\
2117 dcolor.rgb += tcolor.rgb; \n\
2118 dcolor.a = tcolor.a;; \n\
2119 } \n\
2120 } \n\
2121 #endif //TEX \n\
2122 #endif //POINTP \n\
2123 fragment_color = dcolor; \n\
2124 #if defined(LINETYPE) && defined(FULL) \n\
2125 if(u_linetype > 1) \n\
2126 if(!on_linetype(fragment_color)){ \n\
2127 discard; \n\
2128 //fragment_color.a = 0.0; \n\
2129 } \n\
2130 #endif //LINETYPE \n\
2131 #endif //LINE \n\
2132 #ifndef LINE \n\
2133 //mostly 3D geometry \n\
2134 //vec4 diffuseFactor = getDiffuseFactor(); \n\
2135 //fragment_color = diffuseFactor; \n\
2136//STEP0 GOURAUD \n\
2137 #ifndef PHONG \n\
2138 // commandline freewrl --shadingStyle 1 (Gouraud) invokes this \n\
2139 //if(mat.type == 0){ \n\
2140 // as of June 2022 Background still going through here and mat.type = MAT_NONE is default in freewrl \n\
2141 fragment_color = getGouraudColor(); \n\
2142 //} \n\
2143 #endif //not PHONG \n\
2144//STEP1 EMISSIVE \n\
2145 #ifdef PHONG \n\
2146 // commandline freewrl --shadingStyle 2 (Phong, default if not specified) invokes this \n\
2147 if(mat.type == 0){ \n\
2148 // as of June 2022 Background still going through here and mat.type = MAT_NONE is default in freewrl \n\
2149 fragment_color = getGouraudColor(); \n\
2150 } \n\
2151 if(mat.type == 1) { \n\
2152 //MAT_UNLIT - no lighting \n\
2153 //fragment_color.rgb = getEmissive(); \n\
2154 //fragment_color.a = getAlpha(); \n\
2155 int iuse = 1; \n\
2156 vec4 apriori = vec4(mat.emissive, 1.0-mat.transparency); \n\
2157 fragment_color = getMainColor(apriori,iuse); // getEmissive(); \n\
2158 //if the shape is using TextureCoordinateGenerator with some modes (CAMERASPACENORMAL, CAMERASPACEREFLECTIONVECTOR) \n\
2159 // .. then the shader code may need access to normals (where?) \n\
2160 // .. but not use here for lighting \n\
2161 }\n\
2162//STEP2 LIGHTS \n\
2163 //per-fragment lighting aka PHONG shading \n\
2164 if(mat.type == 2){ \n\
2165 //MAT_REGULAR aka phong lighting \n\
2166 #ifdef LITE \n\
2167 //start over with the color, since we have material and lighting in here \n\
2168 vec3 cumulative_specular = vec3(0.0,0.0,0.0); \n\
2169 vec3 cumulative_diffuse = vec3(0.0,0.0,0.0); \n\
2170 fragment_color.a = getAlpha(); \n\
2171 float shiny = getShininess(); \n\
2172 float amby = getAmbient(); \n\
2173 vec4 apriori = vec4(mat.diffuse,1.0-mat.transparency); \n\
2174 int iuse = 3; \n\
2175 fragment_color = getMainColor(apriori,iuse); \n\
2176 vec3 diffy = fragment_color.rgb; //getDiffuseFactor().rgb; //diffuseFactor.rgb; //\n\
2177 vec3 specy = getSpecular(); \n\
2178 vec3 normy = getNormal(); \n\
2179 float occy = getOcclusion(); \n\
2180 /* PLUG: add_light_contribution2 (cumulative_diffuse, cumulative_specular, castle_vertex_eye, normy, shiny, amby, diffy, specy) */ \n\
2181 fragment_color.rgb = cumulative_diffuse + cumulative_specular; \n\
2182 fragment_color.rgb *= occy; \n\
2183 //fragment_color.rgb = clamp(fragment_color.rgb,0.0,1.0); \n\
2184 #endif //LITE \n\
2185 fragment_color.rgb += getEmissive(); \n\
2186 } else if(mat.type == 3){ \n\
2187 //MAT_PHYSICAL aka physical lighting\n\
2188 fragment_color.a = getAlpha(); \n\
2189 #ifdef LITE \n\
2190 float metallic = getMetallic(); \n\
2191 float perceptualRoughness = getRoughness(); \n\
2192 vec4 apriori = vec4(mat.baseColor,1.0-mat.transparency); \n\
2193 int iuse = 3; \n\
2194 fragment_color = getMainColor(apriori,iuse); \n\
2195 vec3 baseColor = fragment_color.rgb; // getBaseColor(); \n\
2196 //unlit \n\
2197 vec3 specularColor= vec3(0.0); \n\
2198 vec3 f0 = vec3(0.04); \n\
2199 // ?? baseColor *= getVertexColor().xyz; //hunh? \n\
2200 vec3 diffuseColor = baseColor.rgb * (vec3(1.0) - f0) * (1.0 - metallic); \n\
2201 specularColor = mix(f0, baseColor.rgb, metallic); \n\
2202 //lit \n\
2203 float alphaRoughness = perceptualRoughness * perceptualRoughness; \n\
2204 // Compute reflectance. \n\
2205 float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b); \n\
2206 vec3 specularEnvironmentR0 = specularColor.rgb; \n\
2207 // Anything less than 2% is physically impossible and is instead considered to be shadowing. \n\
2208 vec3 specularEnvironmentR90 = vec3(clamp(reflectance * 50.0, 0.0, 1.0)); \n\
2209 MaterialInfo materialInfo = MaterialInfo( \n\
2210 perceptualRoughness, \n\
2211 specularEnvironmentR0, \n\
2212 alphaRoughness, \n\
2213 diffuseColor, \n\
2214 specularEnvironmentR90, \n\
2215 specularColor \n\
2216 ); \n\
2217 // LIGHTING \n\
2218 vec3 color = vec3(0.0, 0.0, 0.0); \n\
2219 vec3 normal = getNormal(); \n\
2220 vec3 view = normalize(- castle_vertex_eye.xyz); //hunh?? thought our v_Position was already in Eye space \n\
2221 float occy = getOcclusion(); \n\
2222 //color += apply_lights_physical( materialInfo, normal, view ); \n\
2223 /* PLUG: add_light_physical (color, castle_vertex_eye.xyz, normal, materialInfo ) */ \n\
2224 color *= occy; \n\
2225 fragment_color.rgb = color; \n\
2226 #endif //LITE \n\
2227 fragment_color.rgb += getEmissive(); \n\
2228 } \n\
2229 #endif //PHONG \n\
2230 \n\
2231 #ifdef FILL \n\
2232 //fillPropCalc(fragment_color, hatchPosition); \n\
2233 /* PLUG: fragment_fillPropertiesApply (fragment_color, hatchPosition) */ \n\
2234 #endif //FILL \n\
2235 \n\
2236//STEP3 PROJECTORS AND IBL image based lighting \n\
2237 #ifdef PROJTEX \n\
2238 fragment_color = fragProjCalTexCoord(fragment_color); \n\
2239 #endif //PROJTEX \n\
2240 \n\
2241 #endif //ndef LINE \n\
2242//STEP4 FOG \n\
2243 /* PLUG: fog_apply (fragment_color, N) */ \n\
2244 \n\
2245 fragment_color.rgb = LINEARtoSRGB(fragment_color.rgb); \n\
2246 FragColor = fragment_color; \n\
2247 \n\
2248 /* PLUG: fragment_end (FragColor) */ \n\
2249} \n";
2250
2251
2252
2253static const GLchar *plug_fragment_fillProperties_apply = "\
2254//FILL \n\
2255float either(float x, float y){ \n\
2256 //returns 1 if either are > 0, else 0 \n\
2257 return step(.5,x+y); \n\
2258} \n\
2259float inrange(float curpos, float fx, float linewidth){ \n\
2260 //returns 1.0 if on line, else 0.0 \n\
2261 //return step(fx-linewidth*.5,curpos) - step(fx+linewidth*.5,curpos);; \n\
2262 //either in this cycle or (with +linewidth) the prior cycle \n\
2263 float fxfloor = floor(fx+linewidth); \n\
2264 //return step(ffx,curpos) - step(fract(ffx+linewidth),curpos); \n\
2265 return either(step(fx,curpos) - step(fx+linewidth,curpos),step(fx-fxfloor,curpos) - step(fx-fxfloor+linewidth,curpos)); \n\
2266 //return either(step(fx,curpos) - step(fx+linewidth,curpos),step(fx-1.0,curpos) - step(fx+linewidth-1.0,curpos)); \n\
2267} \n\
2268float inrange3(float curpos, float fx, float linewidth, float cycle_height){ \n\
2269 //returns 1.0 if on line, else 0.0 \n\
2270 float inside = 0.0; \n\
2271 if(cycle_height < 1.0){ \n\
2272 float ncycle = 1.0/cycle_height; \n\
2273 int ny = int(ceil(ncycle)) +2; \n\
2274 for(int i=0;i<ny;i++){ \n\
2275 float ffx = fx + float(i-2)*cycle_height; \n\
2276 inside = either(inside,step(ffx,curpos)-step(ffx+linewidth,curpos)); \n\
2277 } \n\
2278 }else if(cycle_height > 1.0){ \n\
2279 float ncycle = cycle_height; \n\
2280 int ny = int(ceil(ncycle)) +1; \n\
2281 for(int i=0;i<ny;i++){ \n\
2282 float ffx = fx - float(i); \n\
2283 inside = either(inside,step(ffx,curpos)-step(ffx+linewidth,curpos)); \n\
2284 } \n\
2285 } else { \n\
2286 inside = either(step(fx,curpos) - step(fx+linewidth,curpos),step(fx-1.0,curpos) - step(fx+linewidth-1.0,curpos)); \n\
2287 } \n\
2288 return inside; \n\
2289} \n\
2290float rand(float n){return fract(sin(n) * 43758.5453123);} \n\
2291float noise(float p){ \n\
2292 float fl = floor(p); \n\
2293 float fc = fract(p); \n\
2294 return mix(rand(fl), rand(fl + 1.0), fc); \n\
2295} \n\
2296float rand(vec2 c){ \n\
2297 return fract(sin(dot(c.xy ,vec2(12.9898,78.233))) * 43758.5453); \n\
2298} \n\
2299//literal string size break \n" "\
2300//#ifndef FULL \n\
2301void PLUG_fragment_fillPropertiesApply(inout vec4 prevColour, vec2 MCposition) { \n\
2302 // written as procedural texture \n\
2303 // http://learnwebgl.brown37.net/10_surface_properties/texture_mapping_procedural.html \n\
2304 // https://thebookofshaders.com/05/ \n\
2305 // https://isotc.iso.org/livelink/livelink/fetch/-8916524/8916549/8916590/6208440/class_pages/hatchstyle.html \n\
2306 // instead of y = f(x), you set fx = f(current_x)); (where y would need to be, to be on the line) \n\
2307 // then test if current_y is in range(fx-linewidth/2,fx+linewidth/2) \n\
2308 // the x and y are more conveniently processed in cycle-space if you have a repeating pattern \n\
2309 // so if your pattern repeats 10 times per 1 unit of texture coordinates, your cycle is 1/10 = .1 in size \n\
2310 vec4 colour; \n\
2311 vec2 position; // position in cycle, as cycle fraction \n\
2312 float cyclesize; //in texcoords \n\
2313 float linewidth; //in cycle space \n\
2314 position = MCposition; // /HatchScale; \n\
2315 vec2 percent = vec2(0); //fraction of background color to show, usually 1 or 0 \n\
2316 float fx; // f(x) evaluated at x = cyclepostion.x \n\
2317 float fxrange; //normally the pattern is square, if not fxrange is the height, assuming width is 1 \n\
2318 \n\
2319 int ha = fillprops.HatchAlgo; \n\
2320 switch(ha) { \n\
2321 case 0: // horizontal lines \n\
2322 case 1: \n\
2323 cyclesize = .1; \n\
2324 linewidth = .5; \n\
2325 position = fract(MCposition/cyclesize); \n\
2326 fx = .5; \n\
2327 percent.x = 1.0 - inrange(position.y,fx,linewidth); \n\
2328 break; \n\
2329 case 2: // vertical lines \n\
2330 cyclesize = .1; \n\
2331 linewidth = .5; \n\
2332 position = fract(MCposition/cyclesize); \n\
2333 fx = .5; \n\
2334 percent.x = 1.0 - inrange(position.x,fx,linewidth); \n\
2335 break; \n\
2336 case 3: // positive diagonals \n\
2337 cyclesize = .1; \n\
2338 linewidth = .5; \n\
2339 position = fract(MCposition/cyclesize); \n\
2340 fx = position.x; \n\
2341 percent.x = 1.0 - inrange(position.y,fx,linewidth); \n\
2342 break; \n\
2343 case 4: //negative diagonals \n\
2344 cyclesize = .1; \n\
2345 linewidth = .5; \n\
2346 position = fract(MCposition/cyclesize); \n\
2347 fx = 1.0-position.x; \n\
2348 percent.x = 1.0 - inrange(position.y,fx,linewidth); \n\
2349 break; \n\
2350 case 5: // # hv cross hatching \n\
2351 cyclesize = .1; \n\
2352 linewidth = .25; \n\
2353 position = fract(MCposition/cyclesize); \n\
2354 fx = .5; \n\
2355 percent.y = inrange(position.y,fx,linewidth); \n\
2356 percent.x = inrange(position.x,fx,linewidth); \n\
2357 percent.x = 1.0 - either(percent.x, percent.y); \n\
2358 break; \n\
2359 case 6: // diagonal crosshatch \n\
2360 cyclesize = .1; \n\
2361 linewidth = .25; \n\
2362 position = fract(MCposition/cyclesize); \n\
2363 fx = position.x; \n\
2364 percent.x = inrange(position.y,fx,linewidth); \n\
2365 fx = 1.0-position.x; \n\
2366 percent.y = inrange(position.y,fx,linewidth); \n\
2367 percent.x = 1.0 - either(percent.x,percent.y); \n\
2368 break; \n\
2369 case 7: //7 positive diagonals wide \n\
2370 cyclesize = .2; \n\
2371 linewidth = .25; \n\
2372 position = fract(MCposition/cyclesize); \n\
2373 fx = position.x; \n\
2374 percent.x = 1.0 - inrange(position.y,fx,linewidth); \n\
2375 break; \n\
2376 case 8: //8 double positive diagonals, candycane \n\
2377 cyclesize = .4; \n\
2378 linewidth = .15; \n\
2379 position = fract(MCposition/cyclesize); \n\
2380 fx = position.x; \n\
2381 percent.x = inrange(position.y,fx,linewidth); \n\
2382 cyclesize = .4; \n\
2383 linewidth = .15; \n\
2384 position = fract(MCposition/cyclesize); \n\
2385 fx = position.x + .25; \n\
2386 percent.y = inrange(position.y,fx,linewidth); \n\
2387 percent.x = 1.0 - either(percent.x,percent.y); \n\
2388 break; \n\
2389 case 9: //9 positive diagonal dash-diagonal \n\
2390 //solid diagonal \n\
2391 cyclesize = .4; \n\
2392 linewidth = .15; \n\
2393 position = fract(MCposition/cyclesize); \n\
2394 fx = position.x; \n\
2395 percent.x = inrange(position.y,fx,linewidth); \n\
2396 //dash it with negative diagonal \n\
2397 cyclesize = .4; \n\
2398 linewidth = .5; \n\
2399 fx = 1.0 - position.x; \n\
2400 percent.y = inrange(position.y,fx,linewidth); \n\
2401 percent.x = percent.x*percent.y; \n\
2402 //solid diagonal \n\
2403 cyclesize = .4; \n\
2404 linewidth = .15; \n\
2405 position = fract(MCposition/cyclesize); \n\
2406 fx = position.x + .5; \n\
2407 percent.y = inrange(position.y,fx,linewidth); \n\
2408 percent.x = 1.0 - either(percent.x,percent.y); \n\
2409 break; \n\
2410 case 10: //10 wide diagonal crosshatch \n\
2411 cyclesize = .2; \n\
2412 linewidth = .2; \n\
2413 position = fract(MCposition/cyclesize); \n\
2414 fx = position.x; \n\
2415 percent.x = inrange(position.y,fx,linewidth); \n\
2416 fx = 1.0-position.x; \n\
2417 percent.y = inrange(position.y,fx,linewidth); \n\
2418 percent.x = 1.0 - either(percent.x,percent.y); \n\
2419 break; \n\
2420 case 11: //11 positive diagonal railroad \n\
2421 //negative diagonal for railroad ties \n\
2422 cyclesize = .2; \n\
2423 linewidth = .15; \n\
2424 position = fract(MCposition/cyclesize); \n\
2425 fx = 1.0 - position.x; \n\
2426 percent.x = inrange(position.y,fx,linewidth); \n\
2427 //dash it with positive diagonal \n\
2428 cyclesize = .2; \n\
2429 linewidth = .5; \n\
2430 fx = position.x; \n\
2431 percent.y = inrange(position.y,fx,linewidth); \n\
2432 percent.x = percent.x*percent.y; \n\
2433 //HV cross hatch to remove every second tie \n\
2434 cyclesize = .2; \n\
2435 linewidth = .5; \n\
2436 position = fract(MCposition/cyclesize); \n\
2437 fx = .5; \n\
2438 percent.y = inrange(position.y,fx,linewidth); \n\
2439 percent.x = percent.x*percent.y; \n\
2440 //add solid diagonals \n\
2441 cyclesize = .1; \n\
2442 linewidth = .25; \n\
2443 position = fract(MCposition/cyclesize); \n\
2444 fx = position.x + .5; \n\
2445 percent.y = inrange(position.y,fx,linewidth); \n\
2446 percent.x = 1.0 - either(percent.x,percent.y); \n\
2447 break; \n\
2448 case 12: // 12 4 +diag, 4 spaces \n\
2449 //diagonal fill \n\
2450 cyclesize = .1; \n\
2451 linewidth = .4; \n\
2452 position = fract(MCposition/cyclesize); \n\
2453 fx = position.x; \n\
2454 percent.x = inrange(position.y,fx,linewidth); \n\
2455 //remove diagonals \n\
2456 cyclesize = .8; \n\
2457 linewidth = .5; \n\
2458 position = fract(MCposition/cyclesize); \n\
2459 fx = position.x; \n\
2460 percent.y = inrange(position.y,fx,linewidth); \n\
2461 percent.x = 1.0 - percent.x*percent.y; \n\
2462 break; \n\
2463 case 13: //13 cork horizontal dashes \n\
2464 //horizontals \n\
2465 cyclesize = .1; \n\
2466 linewidth = .25; \n\
2467 position = fract(MCposition/cyclesize); \n\
2468 fx = .5; \n\
2469 percent.x = inrange(position.y,fx,linewidth); \n\
2470 //dash using +ve diags \n\
2471 cyclesize = .3; \n\
2472 linewidth = .25; \n\
2473 position = fract(MCposition/cyclesize); \n\
2474 fx = .5 * position.x; \n\
2475 fxrange = .5 * 1.0; \n\
2476 percent.y = 1.0 - inrange3(position.y,fx,linewidth,fxrange); \n\
2477 percent.x = 1.0 - percent.x*percent.y; \n\
2478 break; \n\
2479 case 14: //steps over +ve diags \n\
2480 //HV grid for steps \n\
2481 cyclesize = .1; \n\
2482 linewidth = .25; \n\
2483 position = fract(MCposition/cyclesize); \n\
2484 fx = .5; \n\
2485 percent.y = inrange(position.y,fx,linewidth); \n\
2486 percent.x = inrange(position.x,fx,linewidth); \n\
2487 percent.x = either(percent.x, percent.y); \n\
2488 //clear out parts of grid with +ve diag \n\
2489 cyclesize = .2; \n\
2490 linewidth = .45; \n\
2491 position = fract(MCposition/cyclesize); \n\
2492 fx = position.x + .52; \n\
2493 percent.y = 1.0 - inrange(position.y,fx,linewidth); \n\
2494 percent.x = percent.x*percent.y; \n\
2495 //add +ve diag over steps \n\
2496 cyclesize = .2; \n\
2497 linewidth = .15; \n\
2498 position = fract(MCposition/cyclesize); \n\
2499 fx = position.x + .2; \n\
2500 percent.y = inrange(position.y,fx,linewidth); \n\
2501 percent.x = 1.0 - either(percent.x,percent.y); \n\
2502 break; \n\
2503 case 15: // titaniaum diag diag-dash diag \n\
2504 //diagonal for dashing \n\
2505 cyclesize = .4; \n\
2506 linewidth = .05; \n\
2507 position = fract(MCposition/cyclesize); \n\
2508 fx = position.x + .25; \n\
2509 percent.x = inrange(position.y,fx,linewidth); \n\
2510 //dash with negative diagonal \n\
2511 cyclesize = .3; \n\
2512 linewidth = .2; \n\
2513 position = fract(MCposition/cyclesize); \n\
2514 fx = 1.0 - position.x; \n\
2515 percent.y = 1.0 - inrange(position.y,fx,linewidth); \n\
2516 percent.x = percent.x*percent.y; \n\
2517 //solid diagonals \n\
2518 cyclesize = .2; \n\
2519 linewidth = .1; \n\
2520 position = fract(MCposition/cyclesize); \n\
2521 fx = position.x; \n\
2522 percent.y = inrange(position.y,fx,linewidth); \n\
2523 percent.x = 1.0 - either(percent.x,percent.y); \n\
2524 break; \n\
2525 case 16: //marble diag-dash \n\
2526 //diagonal for dashing \n\
2527 cyclesize = .2; \n\
2528 linewidth = .1; \n\
2529 position = fract(MCposition/cyclesize); \n\
2530 fx = position.x; \n\
2531 percent.x = inrange(position.y,fx,linewidth); \n\
2532 //dash with negative diagonal \n\
2533 cyclesize = .2; \n\
2534 linewidth = .2; \n\
2535 position = fract(MCposition/cyclesize); \n\
2536 fx = 1.0 - position.x; \n\
2537 percent.y = 1.0 - inrange(position.y,fx,linewidth); \n\
2538 percent.x = 1.0 - percent.x*percent.y; \n\
2539 break; \n\
2540 case 17: //earth 5 diags erasing -ve diags \n\
2541 //negaative diags \n\
2542 cyclesize = .1; \n\
2543 linewidth = .1; \n\
2544 position = fract(MCposition/cyclesize); \n\
2545 fx = 1.0 - .5*position.x; \n\
2546 fxrange = 1.0 - .5*1.0; \n\
2547 percent.x = inrange3(position.y,fx,linewidth,fxrange); \n\
2548 //clear gaps with thick +ve diags \n\
2549 cyclesize = .5; \n\
2550 linewidth = .4; \n\
2551 position = fract(MCposition/cyclesize); \n\
2552 fx = position.x; \n\
2553 percent.y = 1.0 - inrange(position.y,fx,linewidth); \n\
2554 percent.x = percent.x*percent.y; \n\
2555 // add 5 diagonals in gap \n\
2556 vec2 percent2 = vec2(0.0); \n\
2557 //diagonal fill \n\
2558 cyclesize = .05; \n\
2559 linewidth = .2; \n\
2560 position = fract(MCposition/cyclesize); \n\
2561 fx = position.x; \n\
2562 percent2.x = inrange(position.y,fx,linewidth); \n\
2563 //remove diagonals \n\
2564 cyclesize = .5; \n\
2565 linewidth = .5; \n\
2566 position = fract(MCposition/cyclesize); \n\
2567 fx = position.x +.5; \n\
2568 percent2.y = 1.0 - inrange(position.y,fx,linewidth); \n\
2569 percent2.x = percent2.x*percent2.y; \n\
2570 percent.x = 1.0 - either(percent.x,percent2.x); \n\
2571 break; \n\
2572 case 18: //sand randcom dots \n\
2573 cyclesize = 1.0; \n\
2574 linewidth = .1; \n\
2575 position = fract(MCposition/cyclesize); \n\
2576 fx = rand(position); \n\
2577 position.x = linewidth*floor(position.x/linewidth); \n\
2578 //fx = noise(position.x*position.y); \n\
2579 percent.x = inrange(position.y,fx,linewidth); \n\
2580 percent.y = inrange(position.x,fx,linewidth); \n\
2581 percent.x = 1.0 - either(percent.x,percent.y); \n\
2582 break; \n\
2583 case 19: //repeating stanggerd rows of dots \n\
2584 // use a find diagonal crosshatch \n\
2585 cyclesize = .05; \n\
2586 linewidth = .5; \n\
2587 position = fract(MCposition/cyclesize); \n\
2588 fx = position.x; \n\
2589 percent.x = inrange(position.y,fx,linewidth); \n\
2590 fx = 1.0-position.x; \n\
2591 percent.y = inrange(position.y,fx,linewidth); \n\
2592 percent.x = either(percent.x,percent.y); \n\
2593 break; \n\
2594 } \n\
2595 \n\
2596 if (fillprops.filled) {colour = prevColour;} else { colour=vec4(0.,0.,0.,0); }\n\
2597 if (fillprops.hatched) { \n\
2598 //colour = mix(fillprops.HatchColour, colour, useBrick.x * useBrick.y); \n\
2599 colour = mix(fillprops.HatchColour, colour, percent.x ); \n\
2600 } \n\
2601 prevColour = colour; \n\
2602} \n\
2603\n";
2604
2605static const GLchar *plug_fragment_fillProperties_apply_120 = "\
2606//FILL \n\
2607float either(float x, float y){ \n\
2608 //returns 1 if either are > 0, else 0 \n\
2609 return step(.5,x+y); \n\
2610} \n\
2611float inrange(float curpos, float fx, float linewidth){ \n\
2612 //returns 1.0 if on line, else 0.0 \n\
2613 //return step(fx-linewidth*.5,curpos) - step(fx+linewidth*.5,curpos);; \n\
2614 //either in this cycle or (with +linewidth) the prior cycle \n\
2615 float fxfloor = floor(fx+linewidth); \n\
2616 //return step(ffx,curpos) - step(fract(ffx+linewidth),curpos); \n\
2617 return either(step(fx,curpos) - step(fx+linewidth,curpos),step(fx-fxfloor,curpos) - step(fx-fxfloor+linewidth,curpos)); \n\
2618 //return either(step(fx,curpos) - step(fx+linewidth,curpos),step(fx-1.0,curpos) - step(fx+linewidth-1.0,curpos)); \n\
2619} \n\
2620float inrange3(float curpos, float fx, float linewidth, float cycle_height){ \n\
2621 //returns 1.0 if on line, else 0.0 \n\
2622 float inside = 0.0; \n\
2623 if(cycle_height < 1.0){ \n\
2624 float ncycle = 1.0/cycle_height; \n\
2625 int ny = int(ceil(ncycle)) +2; \n\
2626 for(int i=0;i<ny;i++){ \n\
2627 float ffx = fx + float(i-2)*cycle_height; \n\
2628 inside = either(inside,step(ffx,curpos)-step(ffx+linewidth,curpos)); \n\
2629 } \n\
2630 }else if(cycle_height > 1.0){ \n\
2631 float ncycle = cycle_height; \n\
2632 int ny = int(ceil(ncycle)) +1; \n\
2633 for(int i=0;i<ny;i++){ \n\
2634 float ffx = fx - float(i); \n\
2635 inside = either(inside,step(ffx,curpos)-step(ffx+linewidth,curpos)); \n\
2636 } \n\
2637 } else { \n\
2638 inside = either(step(fx,curpos) - step(fx+linewidth,curpos),step(fx-1.0,curpos) - step(fx+linewidth-1.0,curpos)); \n\
2639 } \n\
2640 return inside; \n\
2641} \n\
2642float rand(float n){return fract(sin(n) * 43758.5453123);} \n\
2643float noise(float p){ \n\
2644 float fl = floor(p); \n\
2645 float fc = fract(p); \n\
2646 return mix(rand(fl), rand(fl + 1.0), fc); \n\
2647} \n\
2648float rand(vec2 c){ \n\
2649 return fract(sin(dot(c.xy ,vec2(12.9898,78.233))) * 43758.5453); \n\
2650} \n\
2651//literal string size break \n" "\
2652//#else //FULL \n\
2653//literal string size break \n" "\
2654void PLUG_fragment_fillPropertiesApply(inout vec4 prevColour, vec2 MCposition) { \n\
2655 // written as procedural texture \n\
2656 // http://learnwebgl.brown37.net/10_surface_properties/texture_mapping_procedural.html \n\
2657 // https://thebookofshaders.com/05/ \n\
2658 // https://isotc.iso.org/livelink/livelink/fetch/-8916524/8916549/8916590/6208440/class_pages/hatchstyle.html \n\
2659 // instead of y = f(x), you set fx = f(current_x)); (where y would need to be, to be on the line) \n\
2660 // then test if current_y is in range(fx-linewidth/2,fx+linewidth/2) \n\
2661 // the x and y are more conveniently processed in cycle-space if you have a repeating pattern \n\
2662 // so if your pattern repeats 10 times per 1 unit of texture coordinates, your cycle is 1/10 = .1 in size \n\
2663 vec4 colour; \n\
2664 vec2 position; // position in cycle, as cycle fraction \n\
2665 float cyclesize; //in texcoords \n\
2666 float linewidth; //in cycle space \n\
2667 position = MCposition; // /HatchScale; \n\
2668 vec2 percent = vec2(0); //fraction of background color to show, usually 1 or 0 \n\
2669 float fx; // f(x) evaluated at x = cyclepostion.x \n\
2670 float fxrange; //normally the pattern is square, if not fxrange is the height, assuming width is 1 \n\
2671 \n\
2672 int ha = fillprops.HatchAlgo; \n\
2673 if(ha < 10){ \n\
2674 if(ha < 5) { \n\
2675 if(ha < 3) { \n\
2676 if(ha < 2) { // horizontal lines \n\
2677 //case 1: \n\
2678 cyclesize = .1; \n\
2679 linewidth = .5; \n\
2680 position = fract(MCposition/cyclesize); \n\
2681 fx = .5; \n\
2682 percent.x = 1.0 - inrange(position.y,fx,linewidth); \n\
2683 }else if(ha == 2) { \n\
2684 //case 2: // vertical lines \n\
2685 cyclesize = .1; \n\
2686 linewidth = .5; \n\
2687 position = fract(MCposition/cyclesize); \n\
2688 fx = .5; \n\
2689 percent.x = 1.0 - inrange(position.x,fx,linewidth); \n\
2690 } \n\
2691 }else{ //ha < 3 \n\
2692 if(ha == 3) { \n\
2693 //case 3: // positive diagonals \n\
2694 cyclesize = .1; \n\
2695 linewidth = .5; \n\
2696 position = fract(MCposition/cyclesize); \n\
2697 fx = position.x; \n\
2698 percent.x = 1.0 - inrange(position.y,fx,linewidth); \n\
2699 }else{ \n\
2700 //case 4: //negative diagonals \n\
2701 cyclesize = .1; \n\
2702 linewidth = .5; \n\
2703 position = fract(MCposition/cyclesize); \n\
2704 fx = 1.0-position.x; \n\
2705 percent.x = 1.0 - inrange(position.y,fx,linewidth); \n\
2706 }; \n\
2707 } //if else ha < 3 \n\
2708 }else{ //ha < 5 \n\
2709 if(ha < 8) { \n\
2710 if(ha == 5) { \n\
2711 //case 5: // # hv cross hatching \n\
2712 cyclesize = .1; \n\
2713 linewidth = .25; \n\
2714 position = fract(MCposition/cyclesize); \n\
2715 fx = .5; \n\
2716 percent.y = inrange(position.y,fx,linewidth); \n\
2717 percent.x = inrange(position.x,fx,linewidth); \n\
2718 percent.x = 1.0 - either(percent.x, percent.y); \n\
2719 }else if(ha==6){ \n\
2720 //case 6: // diagonal crosshatch \n\
2721 cyclesize = .1; \n\
2722 linewidth = .25; \n\
2723 position = fract(MCposition/cyclesize); \n\
2724 fx = position.x; \n\
2725 percent.x = inrange(position.y,fx,linewidth); \n\
2726 fx = 1.0-position.x; \n\
2727 percent.y = inrange(position.y,fx,linewidth); \n\
2728 percent.x = 1.0 - either(percent.x,percent.y); \n\
2729 }else if(ha==7){ \n\
2730 //case 7: //7 positive diagonals wide \n\
2731 cyclesize = .2; \n\
2732 linewidth = .25; \n\
2733 position = fract(MCposition/cyclesize); \n\
2734 fx = position.x; \n\
2735 percent.x = 1.0 - inrange(position.y,fx,linewidth); \n\
2736 } \n\
2737 }else{ //ha < 8 \n\
2738 if(ha == 8) { \n\
2739 //case 8: //8 double positive diagonals, candycane \n\
2740 cyclesize = .4; \n\
2741 linewidth = .15; \n\
2742 position = fract(MCposition/cyclesize); \n\
2743 fx = position.x; \n\
2744 percent.x = inrange(position.y,fx,linewidth); \n\
2745 cyclesize = .4; \n\
2746 linewidth = .15; \n\
2747 position = fract(MCposition/cyclesize); \n\
2748 fx = position.x + .25; \n\
2749 percent.y = inrange(position.y,fx,linewidth); \n\
2750 percent.x = 1.0 - either(percent.x,percent.y); \n\
2751 }else if(ha==9) { \n\
2752 //case 9: //9 positive diagonal dash-diagonal \n\
2753 //solid diagonal \n\
2754 cyclesize = .4; \n\
2755 linewidth = .15; \n\
2756 position = fract(MCposition/cyclesize); \n\
2757 fx = position.x; \n\
2758 percent.x = inrange(position.y,fx,linewidth); \n\
2759 //dash it with negative diagonal \n\
2760 cyclesize = .4; \n\
2761 linewidth = .5; \n\
2762 fx = 1.0 - position.x; \n\
2763 percent.y = inrange(position.y,fx,linewidth); \n\
2764 percent.x = percent.x*percent.y; \n\
2765 //solid diagonal \n\
2766 cyclesize = .4; \n\
2767 linewidth = .15; \n\
2768 position = fract(MCposition/cyclesize); \n\
2769 fx = position.x + .5; \n\
2770 percent.y = inrange(position.y,fx,linewidth); \n\
2771 percent.x = 1.0 - either(percent.x,percent.y); \n\
2772 }\n\
2773 } //if-else ha < 8 \n\
2774 } // if-else ha < 5 \n\
2775 } else { //ha<10 \n\
2776 if(ha < 15) { \n\
2777 if(ha < 13) {\n\
2778 if(ha == 10) { \n\
2779 //case 10: //10 wide diagonal crosshatch \n\
2780 cyclesize = .2; \n\
2781 linewidth = .2; \n\
2782 position = fract(MCposition/cyclesize); \n\
2783 fx = position.x; \n\
2784 percent.x = inrange(position.y,fx,linewidth); \n\
2785 fx = 1.0-position.x; \n\
2786 percent.y = inrange(position.y,fx,linewidth); \n\
2787 percent.x = 1.0 - either(percent.x,percent.y); \n\
2788 }else if(ha==11){ \n\
2789 //case 11: //11 positive diagonal railroad \n\
2790 //negative diagonal for railroad ties \n\
2791 cyclesize = .2; \n\
2792 linewidth = .15; \n\
2793 position = fract(MCposition/cyclesize); \n\
2794 fx = 1.0 - position.x; \n\
2795 percent.x = inrange(position.y,fx,linewidth); \n\
2796 //dash it with positive diagonal \n\
2797 cyclesize = .2; \n\
2798 linewidth = .5; \n\
2799 fx = position.x; \n\
2800 percent.y = inrange(position.y,fx,linewidth); \n\
2801 percent.x = percent.x*percent.y; \n\
2802 //HV cross hatch to remove every second tie \n\
2803 cyclesize = .2; \n\
2804 linewidth = .5; \n\
2805 position = fract(MCposition/cyclesize); \n\
2806 fx = .5; \n\
2807 percent.y = inrange(position.y,fx,linewidth); \n\
2808 percent.x = percent.x*percent.y; \n\
2809 //add solid diagonals \n\
2810 cyclesize = .1; \n\
2811 linewidth = .25; \n\
2812 position = fract(MCposition/cyclesize); \n\
2813 fx = position.x + .5; \n\
2814 percent.y = inrange(position.y,fx,linewidth); \n\
2815 percent.x = 1.0 - either(percent.x,percent.y); \n\
2816 }else if(ha==12){ \n\
2817 //case 12: // 12 4 +diag, 4 spaces \n\
2818 //diagonal fill \n\
2819 cyclesize = .1; \n\
2820 linewidth = .4; \n\
2821 position = fract(MCposition/cyclesize); \n\
2822 fx = position.x; \n\
2823 percent.x = inrange(position.y,fx,linewidth); \n\
2824 //remove diagonals \n\
2825 cyclesize = .8; \n\
2826 linewidth = .5; \n\
2827 position = fract(MCposition/cyclesize); \n\
2828 fx = position.x; \n\
2829 percent.y = inrange(position.y,fx,linewidth); \n\
2830 percent.x = 1.0 - percent.x*percent.y; \n\
2831 } \n\
2832 } else { //ha < 13 \n\
2833 if(ha == 13) { \n\
2834 //case 13: //13 cork horizontal dashes \n\
2835 //horizontals \n\
2836 cyclesize = .1; \n\
2837 linewidth = .25; \n\
2838 position = fract(MCposition/cyclesize); \n\
2839 fx = .5; \n\
2840 percent.x = inrange(position.y,fx,linewidth); \n\
2841 //dash using +ve diags \n\
2842 cyclesize = .3; \n\
2843 linewidth = .25; \n\
2844 position = fract(MCposition/cyclesize); \n\
2845 fx = .5 * position.x; \n\
2846 fxrange = .5 * 1.0; \n\
2847 percent.y = 1.0 - inrange3(position.y,fx,linewidth,fxrange); \n\
2848 percent.x = 1.0 - percent.x*percent.y; \n\
2849 }else{ \n\
2850 //case 14: //steps over +ve diags \n\
2851 //HV grid for steps \n\
2852 cyclesize = .1; \n\
2853 linewidth = .25; \n\
2854 position = fract(MCposition/cyclesize); \n\
2855 fx = .5; \n\
2856 percent.y = inrange(position.y,fx,linewidth); \n\
2857 percent.x = inrange(position.x,fx,linewidth); \n\
2858 percent.x = either(percent.x, percent.y); \n\
2859 //clear out parts of grid with +ve diag \n\
2860 cyclesize = .2; \n\
2861 linewidth = .45; \n\
2862 position = fract(MCposition/cyclesize); \n\
2863 fx = position.x + .52; \n\
2864 percent.y = 1.0 - inrange(position.y,fx,linewidth); \n\
2865 percent.x = percent.x*percent.y; \n\
2866 //add +ve diag over steps \n\
2867 cyclesize = .2; \n\
2868 linewidth = .15; \n\
2869 position = fract(MCposition/cyclesize); \n\
2870 fx = position.x + .2; \n\
2871 percent.y = inrange(position.y,fx,linewidth); \n\
2872 percent.x = 1.0 - either(percent.x,percent.y); \n\
2873 } \n\
2874 } //if-else ha < 13 \n\
2875 } else { //ha < 15 \n\
2876 if(ha < 18) { \n\
2877 if(ha == 15) { \n\
2878 //case 15: // titaniaum diag diag-dash diag \n\
2879 //diagonal for dashing \n\
2880 cyclesize = .4; \n\
2881 linewidth = .05; \n\
2882 position = fract(MCposition/cyclesize); \n\
2883 fx = position.x + .25; \n\
2884 percent.x = inrange(position.y,fx,linewidth); \n\
2885 //dash with negative diagonal \n\
2886 cyclesize = .3; \n\
2887 linewidth = .2; \n\
2888 position = fract(MCposition/cyclesize); \n\
2889 fx = 1.0 - position.x; \n\
2890 percent.y = 1.0 - inrange(position.y,fx,linewidth); \n\
2891 percent.x = percent.x*percent.y; \n\
2892 //solid diagonals \n\
2893 cyclesize = .2; \n\
2894 linewidth = .1; \n\
2895 position = fract(MCposition/cyclesize); \n\
2896 fx = position.x; \n\
2897 percent.y = inrange(position.y,fx,linewidth); \n\
2898 percent.x = 1.0 - either(percent.x,percent.y); \n\
2899 }else if(ha == 16) { \n\
2900 //case 16: //marble diag-dash \n\
2901 //diagonal for dashing \n\
2902 cyclesize = .2; \n\
2903 linewidth = .1; \n\
2904 position = fract(MCposition/cyclesize); \n\
2905 fx = position.x; \n\
2906 percent.x = inrange(position.y,fx,linewidth); \n\
2907 //dash with negative diagonal \n\
2908 cyclesize = .2; \n\
2909 linewidth = .2; \n\
2910 position = fract(MCposition/cyclesize); \n\
2911 fx = 1.0 - position.x; \n\
2912 percent.y = 1.0 - inrange(position.y,fx,linewidth); \n\
2913 percent.x = 1.0 - percent.x*percent.y; \n\
2914 } else if(ha == 17) { \n\
2915 //case 17: //earth 5 diags erasing -ve diags \n\
2916 //negaative diags \n\
2917 cyclesize = .1; \n\
2918 linewidth = .1; \n\
2919 position = fract(MCposition/cyclesize); \n\
2920 fx = 1.0 - .5*position.x; \n\
2921 fxrange = 1.0 - .5*1.0; \n\
2922 percent.x = inrange3(position.y,fx,linewidth,fxrange); \n\
2923 //clear gaps with thick +ve diags \n\
2924 cyclesize = .5; \n\
2925 linewidth = .4; \n\
2926 position = fract(MCposition/cyclesize); \n\
2927 fx = position.x; \n\
2928 percent.y = 1.0 - inrange(position.y,fx,linewidth); \n\
2929 percent.x = percent.x*percent.y; \n\
2930 // add 5 diagonals in gap \n\
2931 vec2 percent2 = vec2(0.0); \n\
2932 //diagonal fill \n\
2933 cyclesize = .05; \n\
2934 linewidth = .2; \n\
2935 position = fract(MCposition/cyclesize); \n\
2936 fx = position.x; \n\
2937 percent2.x = inrange(position.y,fx,linewidth); \n\
2938 //remove diagonals \n\
2939 cyclesize = .5; \n\
2940 linewidth = .5; \n\
2941 position = fract(MCposition/cyclesize); \n\
2942 fx = position.x +.5; \n\
2943 percent2.y = 1.0 - inrange(position.y,fx,linewidth); \n\
2944 percent2.x = percent2.x*percent2.y; \n\
2945 percent.x = 1.0 - either(percent.x,percent2.x); \n\
2946 } \n\
2947 }else{ //ha < 18 \n\
2948 if(ha == 18) { \n\
2949 //case 18: //sand randcom dots \n\
2950 cyclesize = 1.0; \n\
2951 linewidth = .1; \n\
2952 position = fract(MCposition/cyclesize); \n\
2953 fx = rand(position); \n\
2954 position.x = linewidth*floor(position.x/linewidth); \n\
2955 //fx = noise(position.x*position.y); \n\
2956 percent.x = inrange(position.y,fx,linewidth); \n\
2957 percent.y = inrange(position.x,fx,linewidth); \n\
2958 percent.x = 1.0 - either(percent.x,percent.y); \n\
2959 } else if(ha == 19) { \n\
2960 //case 19: //repeating stanggerd rows of dots \n\
2961 // use a find diagonal crosshatch \n\
2962 cyclesize = .05; \n\
2963 linewidth = .5; \n\
2964 position = fract(MCposition/cyclesize); \n\
2965 fx = position.x; \n\
2966 percent.x = inrange(position.y,fx,linewidth); \n\
2967 fx = 1.0-position.x; \n\
2968 percent.y = inrange(position.y,fx,linewidth); \n\
2969 percent.x = either(percent.x,percent.y); \n\
2970 } \n\
2971 } //if-else ha < 18 \n\
2972 } //if-else ha < 15 \n\
2973 } //if-else ha < 10 \n\
2974 \n\
2975 if (fillprops.filled) {colour = prevColour;} else { colour=vec4(0.,0.,0.,0); }\n\
2976 if (fillprops.hatched) { \n\
2977 //colour = mix(fillprops.HatchColour, colour, useBrick.x * useBrick.y); \n\
2978 colour = mix(fillprops.HatchColour, colour, percent.x ); \n\
2979 } \n\
2980 prevColour = colour; \n\
2981} \n\
2982//#endif //FULL \n\
2983\n";
2984
2985
2986static const GLchar *plug_finalColCalc = "\
2987#if defined(MTEX) || defined(PROJTEX) \n\
2988#define MTMODE_ADD 1\n \
2989#define MTMODE_ADDSIGNED 2\n \
2990#define MTMODE_ADDSIGNED2X 3\n \
2991#define MTMODE_ADDSMOOTH 4\n \
2992#define MTMODE_BLENDCURRENTALPHA 5\n \
2993#define MTMODE_BLENDDIFFUSEALPHA 6\n \
2994#define MTMODE_BLENDFACTORALPHA 7\n \
2995#define MTMODE_BLENDTEXTUREALPHA 8\n \
2996#define MTMODE_DOTPRODUCT3 9\n \
2997#define MTMODE_MODULATE 10\n \
2998#define MTMODE_MODULATE2X 11\n \
2999#define MTMODE_MODULATE4X 12\n \
3000#define MTMODE_MODULATEALPHA_ADDCOLOR 13\n \
3001#define MTMODE_MODULATEINVALPHA_ADDCOLOR 14\n \
3002#define MTMODE_MODULATEINVCOLOR_ADDALPHA 15\n \
3003#define MTMODE_OFF 16\n \
3004#define MTMODE_REPLACE 17\n \
3005#define MTMODE_SELECTARG1 18\n \
3006#define MTMODE_SELECTARG2 19\n \
3007#define MTMODE_SUBTRACT 20\n \
3008#define MTSRC_DIFFUSE 1 \n\
3009#define MTSRC_FACTOR 2 \n\
3010#define MTSRC_SPECULAR 3 \n\
3011#define MTFN_ALPHAREPLICATE 0 \n\
3012#define MTFN_COMPLEMENT 1 \n\
3013#define MT_DEFAULT -1 \n\
3014\n\
3015void PLUG_finalColCalc0(inout vec4 prevColour, in int mode, in int modea, in int func, in vec4 texel) { \n\
3016 vec4 rv = vec4(1.,0.,1.,1.); \n\
3017 if (mode==MTMODE_OFF) { \n\
3018 rv = vec4(prevColour); \n\
3019 } else if (mode==MTMODE_REPLACE) { \n\
3020 rv = texel; \n\
3021 }else if (mode==MTMODE_MODULATE) { \n\
3022 vec3 ct,cf; \n\
3023 float at,af; \n\
3024 cf = prevColour.rgb; \n\
3025 af = prevColour.a; \n\
3026 ct = texel.rgb; \n\
3027 at = texel.a; \n\
3028 rv = vec4(ct*cf, at*af); \n\
3029 } else if (mode==MTMODE_MODULATE2X) { \n\
3030 vec3 ct,cf; \n\
3031 float at,af; \n\
3032 cf = prevColour.rgb; \n\
3033 af = prevColour.a; \n\
3034 ct = texel.rgb; \n\
3035 at = texel.a; \n\
3036 rv = vec4(vec4(ct*cf, at*af)*vec4(2.,2.,2.,2.)); \n\
3037 }else if (mode==MTMODE_MODULATE4X) { \n\
3038 vec3 ct,cf; \n\
3039 float at,af; \n\
3040 cf = prevColour.rgb; \n\
3041 af = prevColour.a; \n\
3042 ct = texel.rgb; \n\
3043 at = texel.a; \n\
3044 rv = vec4(vec4(ct*cf, at*af)*vec4(4.,4.,4.,4.)); \n\
3045 }else if (mode== MTMODE_ADDSIGNED) { \n\
3046 rv = vec4 (prevColour + texel - vec4 (0.5, 0.5, 0.5, -.5)); \n\
3047 } else if (mode== MTMODE_ADDSIGNED2X) { \n\
3048 rv = vec4 ((prevColour + texel - vec4 (0.5, 0.5, 0.5, -.5))*vec4(2.,2.,2.,2.)); \n\
3049 } else if (mode== MTMODE_ADD) { \n\
3050 rv= vec4 (prevColour + texel); \n\
3051 } else if (mode== MTMODE_SUBTRACT) { \n\
3052 rv = vec4 (texel - prevColour); //jas had prev - tex \n\
3053 } else if (mode==MTMODE_ADDSMOOTH) { \n\
3054 rv = vec4 (prevColour + (prevColour - vec4 (1.,1.,1.,1.)) * texel); \n\
3055 } else if (mode==MTMODE_BLENDDIFFUSEALPHA) { \n\
3056 rv = vec4 (mix(prevColour,texel,castle_Color.a)); \n\
3057 } else if (mode==MTMODE_BLENDTEXTUREALPHA) { \n\
3058 rv = vec4 (mix(prevColour,texel,texel.a)); \n\
3059 } else if (mode==MTMODE_BLENDFACTORALPHA) { \n\
3060 rv = vec4 (mix(prevColour,texel,mt_Color.a)); \n\
3061 } else if (mode==MTMODE_BLENDCURRENTALPHA) { \n\
3062 rv = vec4 (mix(prevColour,texel,prevColour.a)); \n\
3063 } else if (mode==MTMODE_SELECTARG1) { \n\
3064 rv = texel; \n\
3065 } else if (mode==MTMODE_SELECTARG2) { \n\
3066 rv = prevColour; \n\
3067 } \n\
3068 if(modea != 0){ \n\
3069 if (modea==MTMODE_OFF) { \n\
3070 rv.a = prevColour.a; \n\
3071 } else if (modea==MTMODE_REPLACE) { \n\
3072 rv.a = 1.0; \n\
3073 }else if (modea==MTMODE_MODULATE) { \n\
3074 float at,af; \n\
3075 af = prevColour.a; \n\
3076 at = texel.a; \n\
3077 rv.a = at*af; \n\
3078 } else if (modea==MTMODE_MODULATE2X) { \n\
3079 float at,af; \n\
3080 af = prevColour.a; \n\
3081 at = texel.a; \n\
3082 rv.a = at*af*2.0; \n\
3083 }else if (modea==MTMODE_MODULATE4X) { \n\
3084 float at,af; \n\
3085 af = prevColour.a; \n\
3086 at = texel.a; \n\
3087 rv.a = at*af*4.0; \n\
3088 }else if (modea== MTMODE_ADDSIGNED) { \n\
3089 rv.a = (prevColour.a + texel.a + .5); \n\
3090 } else if (modea== MTMODE_ADDSIGNED2X) { \n\
3091 rv.a = ((prevColour.a + texel.a + .5))*2.0; \n\
3092 } else if (modea== MTMODE_ADD) { \n\
3093 rv.a = prevColour.a + texel.a; \n\
3094 } else if (modea== MTMODE_SUBTRACT) { \n\
3095 rv.a = texel.a - prevColour.a; //jas had prev - texel \n\
3096 } else if (modea==MTMODE_ADDSMOOTH) { \n\
3097 rv.a = (prevColour.a + (prevColour.a - 1.)) * texel.a; \n\
3098 } else if (modea==MTMODE_BLENDDIFFUSEALPHA) { \n\
3099 rv.a = mix(prevColour.a,texel.a,castle_Color.a); \n\
3100 } else if (modea==MTMODE_BLENDTEXTUREALPHA) { \n\
3101 rv.a = mix(prevColour.a,texel.a,texel.a); \n\
3102 } else if (modea==MTMODE_BLENDFACTORALPHA) { \n\
3103 rv.a = mix(prevColour.a,texel.a,mt_Color.a); \n\
3104 } else if (modea==MTMODE_BLENDCURRENTALPHA) { \n\
3105 rv.a = mix(prevColour.a,texel.a,prevColour.a); \n\
3106 } else if (modea==MTMODE_SELECTARG1) { \n\
3107 rv.a = texel.a; \n\
3108 } else if (modea==MTMODE_SELECTARG2) { \n\
3109 rv.a = prevColour.a; \n\
3110 } \n\
3111 } \n\
3112 if(func == MTFN_COMPLEMENT){ \n\
3113 //rv = vec4(1.0,1.0,1.0,1.0) - rv; \n\
3114 rv = vec4( vec3(1.0,1.0,1.0) - rv.rgb, rv.a); \n\
3115 }else if(func == MTFN_ALPHAREPLICATE){ \n\
3116 rv = vec4(rv.a,rv.a,rv.a,rv.a); \n\
3117 } \n\
3118 prevColour = rv; \n\
3119} \n\
3120#endif //defined(MTEX) || defined(PROJTEX) \n\
3121#if defined(MTEXA) || defined(PROJTEX) \n\
3122void PLUG_finalColCalc(inout vec4 prevColour, in int mode, in int modea, in int func, in sampler2D tex, in vec2 texcoord) { \n\
3123 vec4 texel = texture2D(tex,texcoord); \n\
3124 PLUG_finalColCalc0(prevColour, mode, modea, func, texel); \n\
3125} \n\
3126#endif //defined(MTEX) || defined(PROJTEX) \n";
3127
3128
3129
3130
3131const char *getGenericVertex(void){
3132 return genericVertexGLES2; //genericVertexDesktop
3133}
3134const char *getGenericFragment(){
3135 return genericFragmentGLES2; //genericFragmentDesktop;
3136}
3137#include "../scenegraph/Component_Shape.h"
3138
3139static const GLchar *plug_fragment_end_anaglyph = "\
3140void PLUG_fragment_end (inout vec4 finalFrag){ \n\
3141 float gray = dot(finalFrag.rgb, vec3(0.299, 0.587, 0.114)); \n\
3142 finalFrag = vec4(gray,gray,gray, finalFrag.a); \n\
3143}\n";
3144
3145//TEXTURE 3D
3146/*
3147 4 scenarios:
3148 1. GL has texture3D/EXT_texture3D/OES_texture3D
3149 2. GL no texture3D - emulate
3150 A. 3D image: source imagery is i) 3D image or ii) composed image with image layers all same size
3151 B. 2D layers: source imagery is composed image with z < 7 layers and layers can be different sizes
3152 1 2
3153 A texture3D tiled texture2D
3154 B multi texure2D multi texture2D
3155
3156 for tiled texture2D, there are a few ways to do the tiles:
3157 a) vertical strip: nx x (ny * nz) - our first attempt
3158 layer 0 at top, and sequential layers follow down
3159 b) squarish tiled: ix = iy = ceil(sqrt(nz)); (nx*ix) x (ny*iy)
3160 there will be blank squares. Order:
3161 y-first layer order: fill column, first at top left, before advancing ix right
3162 (option: x-first layer order: fill row, first at top left, before advancing down iy)
3163*/
3164
3165// TILED METHOD FOR TEXTURE3D
3166// texture3D emulator via TILED texture2D
3167// reason for emulating: 2016 GLES2 via ANGLEPROJECT(gles emulator over DirectX on windows)
3168// doesn't have Texture3D or Texture3DOES or Texture3DEXT.
3169// reason for TILES: an oblong Y-STRIP approach exceded max texture size in Y (but had lots left in X)
3170// desktop computer max_size (of 2D image in one dimension) 16384
3171// android phone max_size 4096
3172// and so would be resampled (blurry) in y and good in x
3173// using tiles means room for more full z slices ie 256x256x256 == 4096x4096 == 16M,
3174// 512x512x512 == 134M == 16384x16384/2, and therefore less blurry images
3175// tiles start in upper left with z=0, increase in y,
3176// then when hit ny tiles in a y strip, move right one tile, and restart at top
3177// uniform tex3dTiles[3] = {nx,ny,z}
3178// example ny = 4, nx = 3, z = 11
3179// 1 5 9
3180// 2 6 10
3181// 3 7 11
3182// 4 8
3183//
3184static const GLchar *plug_fragment_texture3D_apply_volume_uber = "\n\
3185vec4 texture3Demu0( sampler2D sampler, in vec3 texcoord3, in int magfilter){ \n\
3186 vec4 rgba = vec4(0.0); \n\
3187 #ifdef TEX3D \n\
3188 //TILED method (vs Y strip method) \n\
3189 vec3 texcoord = texcoord3; \n\
3190 //texcoord.z = 1.0 - texcoord.z; //flip z from RHS to LHS\n\
3191 float depth = max(1.0,float(tex3dTiles[2])); \n\
3192 if(repeatSTR[0] == 0) texcoord.x = clamp(texcoord.x,0.0001,.9999); \n\
3193 else texcoord.x = mod(texcoord.x,1.0); \n\
3194 if(repeatSTR[1] == 0) texcoord.y = clamp(texcoord.y,0.0001,.9999); \n\
3195 else texcoord.y = mod(texcoord.y,1.0); \n\
3196 if(repeatSTR[2] == 0) texcoord.z = clamp(texcoord.z,0.0001,.9999); \n\
3197 else texcoord.z = mod(texcoord.z,1.0); \n\
3198 vec4 texel; \n\
3199 int izf = int(floor(texcoord.z*depth)); //floor z \n\
3200 int izc = int(ceil(texcoord.z*depth)); //ceiling z \n\
3201 izc = izc == tex3dTiles[2] ? izc - 1 : izc; //clamp int z \n\
3202 vec4 ftexel, ctexel; \n\
3203 \n\
3204 int nx = tex3dTiles[0]; //0-11 \n\
3205 int ny = tex3dTiles[1]; \n\
3206 float fnx = 1.0/float(nx); //.1\n\
3207 float fny = 1.0/float(ny); \n\
3208 int ix = izc / ny; //60/11=5\n\
3209 int ixny = ix * ny; //5*11=55\n\
3210 int iy = izc - ixny; //60-55=5 modulus remainder \n\
3211 float cix = float(ix); //5 \n\
3212 float ciy = float(iy); \n\
3213 float xxc = (cix + texcoord.s)*fnx; //(5 + .5)*.1 = .55\n\
3214 float yyc = (ciy + texcoord.t)*fny; \n\
3215 ix = izf / ny; \n\
3216 ixny = ix * ny; \n\
3217 iy = izf - ixny; //modulus remainder \n\
3218 float fix = float(ix); \n\
3219 float fiy = float(iy); \n\
3220 float xxf = (fix + texcoord.s)*fnx; \n\
3221 float yyf = (fiy + texcoord.t)*fny; \n\
3222 \n\
3223 vec2 ftexcoord, ctexcoord; //texcoord is 3D, ftexcoord and ctexcoord are 2D coords\n\
3224 ftexcoord.s = xxf; \n\
3225 ftexcoord.t = yyf; \n\
3226 ctexcoord.s = xxc; \n\
3227 ctexcoord.t = yyc; \n\
3228 ftexel = texture2D(sampler,ftexcoord.st); \n\
3229 ctexel = texture2D(sampler,ctexcoord.st); \n\
3230 float fraction = mod(texcoord.z*depth,1.0); \n\
3231 if(magfilter == 1) \n\
3232 texel = mix(ctexel,ftexel,1.0-fraction); //lerp GL_LINEAR \n\
3233 else \n\
3234 texel = ftexel; //fraction > .5 ? ctexel : ftexel; //GL_NEAREST \n\
3235 rgba = texel; \n\
3236 #endif //TEX3D \n\
3237 return rgba; \n\
3238} \n\
3239vec4 texture3Demu( sampler2D sampler, in vec3 texcoord3){ \n\
3240 //use uniform magfilter \n\
3241 return texture3Demu0( sampler, texcoord3, magFilter); \n\
3242} \n\
3243void PLUG_texture3D( inout vec4 rgba, in vec3 texcoord3 ){ \n\
3244 rgba = texture3Demu(fw_Texture_unit0,texcoord3); \n\
3245} \n\
3246void PLUG_texture_apply (inout vec4 finalFrag, in int iuse ){ \n\
3247\n\
3248int tex_index = mat.tindex[mat.tstart[iuse] ]; \n\
3249int coord_index = mat.cmap[mat.tstart[iuse] ]; \n\
3250int samplr = mat.samplr[mat.tstart[iuse] ]; \n\
3251vec4 rgba; \n\
3252rgba = texture3Demu(textureUnit[tex_index],fw_TexCoord[coord_index]); \n\
3253 //rgba = texture3Demu(fw_Texture_unit0,fw_TexCoord[0]); \n\
3254 //rgba = texture2D(textureUnit[tex_index],fw_TexCoord[coord_index].xy); \n\
3255 finalFrag *= rgba; \n\
3256 \n\
3257}\n";
3258
3259
3260
3261static const GLchar *plug_fragment_texture3Dlayer_apply_uber = "\
3262void PLUG_texture_apply (inout vec4 finalFrag, in int iuse ){ \n\
3263\n\
3264 #ifdef TEX3DLAY \n\
3265int tex_index = mat.tindex[mat.tstart[iuse] ]; \n\
3266int coord_index = mat.cmap[mat.tstart[iuse] ]; \n\
3267int samplr = mat.samplr[mat.tstart[iuse] ]; \n\
3268 vec3 texcoord = fw_TexCoord[coord_index]; \n\
3269 texcoord.z = 1.0 - texcoord.z; //flip z from RHS to LHS\n\
3270 float depth = max(1.0,float(textureCount-1)); \n\
3271 float delta = 1.0/depth; \n\
3272 if(repeatSTR[0] == 0) texcoord.x = clamp(texcoord.x,0.0001,.9999); \n\
3273 else texcoord.x = mod(texcoord.x,1.0); \n\
3274 if(repeatSTR[1] == 0) texcoord.y = clamp(texcoord.y,0.0001,.9999); \n\
3275 else texcoord.y = mod(texcoord.y,1.0); \n\
3276 if(repeatSTR[2] == 0) texcoord.z = clamp(texcoord.z,0.0001,.9999); \n\
3277 else texcoord.z = mod(texcoord.z,1.0); \n\
3278 int flay = int(floor(texcoord.z*depth)); \n\
3279 int clay = int(ceil(texcoord.z*depth)); \n\
3280 vec4 ftexel, ctexel; \n\
3281 //flay = 0; \n\
3282 //clay = 1; \n\
3283 if(flay == 0) ftexel = texture2D(textureUnit[tex_index+0],texcoord.st); \n\
3284 if(clay == 0) ctexel = texture2D(textureUnit[tex_index+0],texcoord.st); \n\
3285 if(flay == 1) ftexel = texture2D(textureUnit[tex_index+1],texcoord.st); \n\
3286 if(clay == 1) ctexel = texture2D(textureUnit[tex_index+1],texcoord.st); \n\
3287 if(flay == 2) ftexel = texture2D(textureUnit[tex_index+2],texcoord.st); \n\
3288 if(clay == 2) ctexel = texture2D(textureUnit[tex_index+2],texcoord.st); \n\
3289 if(flay == 3) ftexel = texture2D(textureUnit[tex_index+3],texcoord.st); \n\
3290 if(clay == 3) ctexel = texture2D(textureUnit[tex_index+3],texcoord.st); \n\
3291 float fraction = mod(texcoord.z*depth,1.0); \n\
3292 vec4 texel; \n\
3293 if(magFilter == 1) \n\
3294 texel = mix(ctexel,ftexel,(1.0-fraction)); //lerp GL_LINEAR \n\
3295 else \n\
3296 texel = fraction > .5 ? ctexel : ftexel; //GL_NEAREST \n\
3297 finalFrag *= texel; \n\
3298 #endif //TEX3DLAY \n\
3299 \n\
3300}\n";
3301
3302static const GLchar* plug_fragment_texture3D_apply_volume = "\n\
3303vec4 texture3Demu0( sampler2D sampler, in vec3 texcoord3, in int magfilter){ \n\
3304 vec4 sampled = vec4(0.0); \n\
3305 #ifdef TEX3D \n\
3306 //TILED method (vs Y strip method) \n\
3307 vec3 texcoord = texcoord3; \n\
3308 //texcoord.z = 1.0 - texcoord.z; //flip z from RHS to LHS\n\
3309 float depth = max(1.0,float(tex3dTiles[2])); \n\
3310 if(repeatSTR[0] == 0) texcoord.x = clamp(texcoord.x,0.0001,.9999); \n\
3311 else texcoord.x = mod(texcoord.x,1.0); \n\
3312 if(repeatSTR[1] == 0) texcoord.y = clamp(texcoord.y,0.0001,.9999); \n\
3313 else texcoord.y = mod(texcoord.y,1.0); \n\
3314 if(repeatSTR[2] == 0) texcoord.z = clamp(texcoord.z,0.0001,.9999); \n\
3315 else texcoord.z = mod(texcoord.z,1.0); \n\
3316 vec4 texel; \n\
3317 int izf = int(floor(texcoord.z*depth)); //floor z \n\
3318 int izc = int(ceil(texcoord.z*depth)); //ceiling z \n\
3319 izc = izc == tex3dTiles[2] ? izc - 1 : izc; //clamp int z \n\
3320 vec4 ftexel, ctexel; \n\
3321 \n\
3322 int nx = tex3dTiles[0]; //0-11 \n\
3323 int ny = tex3dTiles[1]; \n\
3324 float fnx = 1.0/float(nx); //.1\n\
3325 float fny = 1.0/float(ny); \n\
3326 int ix = izc / ny; //60/11=5\n\
3327 int ixny = ix * ny; //5*11=55\n\
3328 int iy = izc - ixny; //60-55=5 modulus remainder \n\
3329 float cix = float(ix); //5 \n\
3330 float ciy = float(iy); \n\
3331 float xxc = (cix + texcoord.s)*fnx; //(5 + .5)*.1 = .55\n\
3332 float yyc = (ciy + texcoord.t)*fny; \n\
3333 ix = izf / ny; \n\
3334 ixny = ix * ny; \n\
3335 iy = izf - ixny; //modulus remainder \n\
3336 float fix = float(ix); \n\
3337 float fiy = float(iy); \n\
3338 float xxf = (fix + texcoord.s)*fnx; \n\
3339 float yyf = (fiy + texcoord.t)*fny; \n\
3340 \n\
3341 vec2 ftexcoord, ctexcoord; //texcoord is 3D, ftexcoord and ctexcoord are 2D coords\n\
3342 ftexcoord.s = xxf; \n\
3343 ftexcoord.t = yyf; \n\
3344 ctexcoord.s = xxc; \n\
3345 ctexcoord.t = yyc; \n\
3346 ftexel = texture2D(sampler,ftexcoord.st); \n\
3347 ctexel = texture2D(sampler,ctexcoord.st); \n\
3348 float fraction = mod(texcoord.z*depth,1.0); \n\
3349 if(magfilter == 1) \n\
3350 texel = mix(ctexel,ftexel,1.0-fraction); //lerp GL_LINEAR \n\
3351 else \n\
3352 texel = ftexel; //fraction > .5 ? ctexel : ftexel; //GL_NEAREST \n\
3353 sampled = texel; \n\
3354 #endif //TEX3D \n\
3355 return sampled; \n\
3356} \n\
3357vec4 texture3Demu( sampler2D sampler, in vec3 texcoord3){ \n\
3358 //use uniform magfilter \n\
3359 return texture3Demu0( sampler, texcoord3, magFilter); \n\
3360} \n\
3361void PLUG_texture3D( inout vec4 sampled, in vec3 texcoord3 ){ \n\
3362 sampled = texture3Demu(fw_Texture_unit0,texcoord3); \n\
3363} \n\
3364void PLUG_texture_apply (inout vec4 finalFrag, in int iuse ){ \n\
3365\n\
3366 vec4 sampled; \n\
3367 sampled = texture3Demu(fw_Texture_unit0,fw_TexCoord[0]); \n\
3368 finalFrag *= sampled; \n\
3369 \n\
3370}\n";
3371
3372
3373
3374static const GLchar* plug_fragment_texture3Dlayer_apply = "\
3375void PLUG_texture_apply (inout vec4 finalFrag, in int iuse ){ \n\
3376\n\
3377 #ifdef TEX3DLAY \n\
3378 vec3 texcoord = fw_TexCoord[0]; \n\
3379 texcoord.z = 1.0 - texcoord.z; //flip z from RHS to LHS\n\
3380 float depth = max(1.0,float(textureCount-1)); \n\
3381 float delta = 1.0/depth; \n\
3382 if(repeatSTR[0] == 0) texcoord.x = clamp(texcoord.x,0.0001,.9999); \n\
3383 else texcoord.x = mod(texcoord.x,1.0); \n\
3384 if(repeatSTR[1] == 0) texcoord.y = clamp(texcoord.y,0.0001,.9999); \n\
3385 else texcoord.y = mod(texcoord.y,1.0); \n\
3386 if(repeatSTR[2] == 0) texcoord.z = clamp(texcoord.z,0.0001,.9999); \n\
3387 else texcoord.z = mod(texcoord.z,1.0); \n\
3388 int flay = int(floor(texcoord.z*depth)); \n\
3389 int clay = int(ceil(texcoord.z*depth)); \n\
3390 vec4 ftexel, ctexel; \n\
3391 //flay = 0; \n\
3392 //clay = 1; \n\
3393 if(flay == 0) ftexel = texture2D(fw_Texture_unit0,texcoord.st); \n\
3394 if(clay == 0) ctexel = texture2D(fw_Texture_unit0,texcoord.st); \n\
3395 if(flay == 1) ftexel = texture2D(fw_Texture_unit1,texcoord.st); \n\
3396 if(clay == 1) ctexel = texture2D(fw_Texture_unit1,texcoord.st); \n\
3397 if(flay == 2) ftexel = texture2D(fw_Texture_unit2,texcoord.st); \n\
3398 if(clay == 2) ctexel = texture2D(fw_Texture_unit2,texcoord.st); \n\
3399 if(flay == 3) ftexel = texture2D(fw_Texture_unit3,texcoord.st); \n\
3400 if(clay == 3) ctexel = texture2D(fw_Texture_unit3,texcoord.st); \n\
3401 float fraction = mod(texcoord.z*depth,1.0); \n\
3402 vec4 texel; \n\
3403 if(magFilter == 1) \n\
3404 texel = mix(ctexel,ftexel,(1.0-fraction)); //lerp GL_LINEAR \n\
3405 else \n\
3406 texel = fraction > .5 ? ctexel : ftexel; //GL_NEAREST \n\
3407 finalFrag *= texel; \n\
3408 #endif //TEX3DLAY \n\
3409 \n\
3410}\n";
3411
3412
3413//MULTITEXTURE
3414// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/texturing.html#MultiTexture
3415 /* PLUG: texture_apply (fragment_color, in int iuse) */
3416/*
3417 mat.
3418 int tindex[10]; \n\
3419 int mode[10]; \n\
3420 int source[10]; \n\
3421 int func[10]; \n\
3422 int nt; //total single textures \n\
3423 //iunit [0] normal [1] emissive [2] occlusion [3] diffuse OR base [4] shininess OR metallicRoughness [5] specular [6] ambient \n\
3424 int tcount[7]; //num single textures 1= one texture 0=no texture 2+ = multitexture \n\
3425 int tstart[7]; // where in packed tindex list to start looping \n\
3426 int cindex[7]; // which geometry multitexcoord channel 0=default \n\
3427
3428 int ndesc = mat.tcount[iunit]; \n\
3429 if(ndesc > 1){ //multitex \n\
3430 int istart = mat.tstart[iunit];\n\
3432 //int index = mat.tindex[mat.tstart[iunit]]; \n\
3433 //vec2 tc = fw_TexCoord[mat.cindex[iunit]].xy; \n\
3434 vec4 prev = nc; \n\
3435 int k=istart; \n\
3436 vec2 ptex = fw_TexCoord[mat.cindex[iunit]].xy; \n\
3437 for(int j=0;j<ndesc;j++,k++){ \n\
3438 //if(j==ndesc) break; \n\
3439 int kk = mat.tindex[k]; \n\
3440 int modea = int(mat.mode[k] / 100); \n\
3441 int mode = mat.mode[k] - 100*modea; \n\
3442 //vec4 cur = sample_map0(kk,false); \n\
3443 vec4 cur = texture2D(textureUnit[kk],ptex); \n\
3444 #ifdef MTEX \n\
3445 finalColCalcB(prev, mode, modea, mat.func[k], cur); \n\
3446 #else //MTEX \n\
3447 prev = cur; \n\
3448 #endif //MTEX \n\
3449 //prev = cur; \n\
3450 //vec4 ncc = texture2D(textureUnit[kk],ptex.xy); \n\
3451 //prev.rgb = clamp(prev.rgb + ncc.rgb,0.0,1.0); \n\
3452 } \n\
3453 //prev = vec4(0.5,1.0,0.5,1.0); \n\
3454 nc = prev; \n\
3455
3456
3457*/
3458static const GLchar *plug_fragment_texture_apply = "\
3459void PLUG_texture_apply (inout vec4 finalFrag, in int iuse ){ \n\
3460 \n\
3461 #ifdef MTEX \n\
3462 int ndesc = mat.tcount[iuse]; \n\
3463 int k = mat.tstart[iuse]; \n\
3464 if(ndesc > 1){ //multitex \n\
3465 vec4 source; \n\
3466 int isource,iasource, mode, modea, j; \n\
3467 for(j=0;j<ndesc;j++,k++){ \n\
3468 modea = int(mat.mode[k] / 100); \n\
3469 mode = mat.mode[k] - 100*modea; \n\
3470 if(mode != MTMODE_OFF) { \n\
3471 iasource = int(mat.source[k] / 100); \n\
3472 isource = mat.source[k] - 100*iasource; \n\
3473 if(isource == MT_DEFAULT) source = finalFrag; \n\
3474 else if(isource == MTSRC_DIFFUSE) source = mtex_diffuse; \n\
3475 else if(isource == MTSRC_SPECULAR) source = vec4(mtex_specular,1.0); \n\
3476 else if(isource == MTSRC_FACTOR) source = mt_Color; \n\
3477 if(iasource != 0){ \n\
3478 if(iasource == MT_DEFAULT) source.a = finalFrag.a; \n\
3479 else if(iasource == MTSRC_DIFFUSE) source.a = mtex_diffuse.a; \n\
3480 else if(iasource == MTSRC_SPECULAR) source.a = 1.0; \n\
3481 else if(iasource == MTSRC_FACTOR) source.a = mt_Color.a; \n\
3482 } \n\
3483 vec4 cur = sample_map(iuse,j,false); \n\
3484 finalColCalcB(source,mode,modea,mat.func[k], cur); \n\
3485 finalFrag = source; \n\
3486 } \n\
3487 } \n\
3488 } else { \n\
3489 /* ONE TEXTURE */ \n\
3490 finalFrag = sample_map(iuse,0,false) * finalFrag; \n\
3491 } \n\
3492 #else //MTEX \n\
3493 /* ONE TEXTURE */ \n\
3494 finalFrag = sample_map(iuse,0,false) * finalFrag; \n\
3495 #endif //MTEX \n\
3496 \n\
3497}\n";
3498
3499
3500
3501/* PLUG: add_light_physical (color, view, normal, materialInfo ); */
3502static const GLchar *plug_frag_lighting_physical = "\n\
3503#ifdef LITE \n\
3504#ifndef M_PI \n\
3505#define M_PI 3.14159265358979 \n\
3506#endif \n\
3507struct AngularInfo \n\
3508{ \n\
3509 float NdotL; // cos angle between normal and light direction \n\
3510 float NdotV; // cos angle between normal and view direction \n\
3511 float NdotH; // cos angle between normal and half vector \n\
3512 float LdotH; // cos angle between light direction and half vector \n\
3513 float VdotH; // cos angle between view direction and half vector \n\
3514 vec3 padding; \n\
3515}; \n\
3516AngularInfo getAngularInfo(vec3 pointToLight, vec3 normal, vec3 view) \n\
3517{ \n\
3518 // Standard one-letter names \n\
3519 vec3 n = normalize(normal); // Outward direction of surface point \n\
3520 vec3 v = normalize(view); // Direction from surface point to view \n\
3521 vec3 l = normalize(pointToLight); // Direction from surface point to light \n\
3522 vec3 h = normalize(l + v); // Direction of the vector between l and v \n\
3523 float NdotL = clamp(dot(n, l), 0.0, 1.0); \n\
3524 float NdotV = clamp(dot(n, v), 0.0, 1.0); \n\
3525 float NdotH = clamp(dot(n, h), 0.0, 1.0); \n\
3526 float LdotH = clamp(dot(l, h), 0.0, 1.0); \n\
3527 float VdotH = clamp(dot(v, h), 0.0, 1.0); \n\
3528 AngularInfo ai = AngularInfo( \n\
3529 NdotL, \n\
3530 NdotV, \n\
3531 NdotH, \n\
3532 LdotH, \n\
3533 VdotH, \n\
3534 vec3(0, 0, 0) \n\
3535 ); \n\
3536 return ai; \n\
3537} \n\
3538// Lambert lighting \n\
3539// see https://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/ \n\
3540vec3 diffuse(MaterialInfo materialInfo) \n\
3541{ \n\
3542 return materialInfo.diffuseColor / M_PI; \n\
3543} \n\
3544// TFresnel reflectance F() \n\
3545vec3 specularReflection(MaterialInfo materialInfo, AngularInfo angularInfo) \n\
3546{ \n\
3547 return materialInfo.reflectance0 + (materialInfo.reflectance90 - materialInfo.reflectance0) * pow(clamp(1.0 - angularInfo.VdotH, 0.0, 1.0), 5.0); \n\
3548} \n\
3549// Smith Joint GGX \n\
3550// Note: Vis = G / (4 * NdotL * NdotV) \n\
3551float visibilityOcclusion(MaterialInfo materialInfo, AngularInfo angularInfo) \n\
3552{ \n\
3553 float NdotL = angularInfo.NdotL; \n\
3554 float NdotV = angularInfo.NdotV; \n\
3555 float alphaRoughnessSq = materialInfo.alphaRoughness * materialInfo.alphaRoughness; \n\
3556 float GGXV = NdotL * sqrt(NdotV * NdotV * (1.0 - alphaRoughnessSq) + alphaRoughnessSq); \n\
3557 float GGXL = NdotV * sqrt(NdotL * NdotL * (1.0 - alphaRoughnessSq) + alphaRoughnessSq); \n\
3558 \n\
3559 float GGX = GGXV + GGXL; \n\
3560 if (GGX > 0.0) \n\
3561 { \n\
3562 return 0.5 / GGX; \n\
3563 } \n\
3564 return 0.0; \n\
3565} \n\
3566// model the distribution of microfacet normals (aka D()) \n\
3567float microfacetDistribution(MaterialInfo materialInfo, AngularInfo angularInfo) \n\
3568{ \n\
3569 float alphaRoughnessSq = materialInfo.alphaRoughness * materialInfo.alphaRoughness; \n\
3570 float f = (angularInfo.NdotH * alphaRoughnessSq - angularInfo.NdotH) * angularInfo.NdotH + 1.0; \n\
3571 return alphaRoughnessSq / (M_PI * f * f); \n\
3572} \n\
3573vec3 getPointShade(vec3 pointToLight, MaterialInfo materialInfo, vec3 normal, vec3 view) \n\
3574{ \n\
3575 AngularInfo angularInfo = getAngularInfo(pointToLight, normal, view); \n\
3576 if (angularInfo.NdotL > 0.0 || angularInfo.NdotV > 0.0) \n\
3577 { \n\
3578 // microfacet specular shading model \n\
3579 vec3 F = specularReflection(materialInfo, angularInfo); \n\
3580 float Vis = visibilityOcclusion(materialInfo, angularInfo); \n\
3581 float D = microfacetDistribution(materialInfo, angularInfo); \n\
3582 // Calculation of analytical lighting contribution \n\
3583 vec3 diffuseContrib = (1.0 - F) * diffuse(materialInfo); \n\
3584 vec3 specContrib = F * Vis * D; \n\
3585 // reflectance (BRDF) scaled by the energy of the light (cosine law) \n\
3586 return angularInfo.NdotL * (diffuseContrib + specContrib); \n\
3587 } \n\
3588 return vec3(0.0, 0.0, 0.0); \n\
3589} \n\
3590void PLUG_add_light_physical (inout vec3 vertexcolor, in vec3 myPosition, in vec3 myNormal, in struct MaterialInfo mat){ \n\
3591 //working in eye space: eye is at 0,0,0 looking generally in direction 0,0,-1 \n\
3592 //myPosition, myNormal - of surface vertex, in eyespace \n\
3593 int i; \n\
3594 vec3 N = normalize (myNormal); \n\
3595 \n\
3596 vec3 E = -normalize(myPosition.xyz); \n \
3597 \n\
3598 // apply the lights to this material \n\
3599 // weird but ANGLE needs constant loop \n\
3600 for (i=0; i<lightcount; i++) {\n\
3601 float on = 1.0; //we only send active/on lights to shader, so this is for radius \n\
3602 float spot = 1.0; \n\
3603 float attenuation = 1.0; //directional default \n\
3604 fw_LightSourceParameters light = fw_LightSource[i]; \n\
3605 int myLightType = lightType[i]; \n\
3606 // VP vector of light direction and distance \n\
3607 vec3 VP = light.location.xyz - myPosition.xyz; \n\
3608 vec3 L = -light.direction; //directional light \n\
3609 if(myLightType < 2){ \n\
3610 //point and spot \n\
3611 L = normalize(VP); \n\
3612 float D = length(VP); // distance to vertex \n\
3613 // are we within range? \n\
3614 if (D > light.lightRadius) on = 0.0; \n\
3615 attenuation = 1.0/max(1.0,(light.Attenuations.x + (light.Attenuations.y * D) + (light.Attenuations.z *D*D))); \n\
3616 } \n\
3617 vec3 shade = getPointShade(-VP, mat, -N, -E); \n\
3618 if (myLightType==1) { \n\
3619 // SpotLight \n\
3620 spot = 0.0; \n\
3621 float cosCut = cos(light.spotCutoff); \n\
3622 float cosBeam = cos(light.spotBeamWidth); \n\
3623 float rayAngle = dot(normalize(-L),normalize(light.direction)); \n\
3624 // check against spotCosCutoff \n\
3625 if (rayAngle > cosCut) { \n\
3626 if(rayAngle > cosBeam) { \n\
3627 spot = 1.0; \n\
3628 } else { \n\
3629 //spot = (rayAngle - cosCut)/(cosBeam - cosCut); \n\
3630 float rayradians = acos(rayAngle); \n\
3631 spot = (light.spotCutoff - rayradians)/(light.spotCutoff - light.spotBeamWidth); \n\
3632 } \n\
3633 } \n\
3634 } \n\
3635 float shadowtest = 1.0; \n\
3636#ifdef SHADOW \n\
3637 if (light.shadows) { \n\
3638 shadowtest = 1.0 - light.shadowIntensity*ShadowCalculation(i,VP); \n\
3639 } \n\
3640#endif //SHADOW \n\
3641 vertexcolor += on * shadowtest * attenuation * spot * light.color * light.intensity * shade; \n\
3642 //vertexcolor += shade; //vec3(0.0,1.0,1.0); \n\
3643 } \n\
3644 vertexcolor = clamp(vertexcolor, 0.0, 1.0); \n\
3645} \n\
3646#endif //LITE \n\
3647";
3648
3649//add_light_contribution (castle_Color, castle_vertex_eye, castle_normal_eye, castle_MaterialShininess)
3650// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/lighting.html#Lightingequations
3651// simplified thoery: lightOut = emissive + f(light_in,material,light_eqn)
3652// ADS: Ambient + Diffuse + Specular
3653// http://www.matrix44.net/cms/notes/opengl-3d-graphics/the-ads-lighting-model
3654// http://http.developer.nvidia.com/CgTutorial/cg_tutorial_chapter05.html
3655// incoming eyeposition and eyenormal are of the surface vertex and normal
3656// .. in the view/eye coordinate system (so eye is at 0,0,0 and eye direction is 0,0,-1
3657
3658 static const GLchar* plug_vertex_lighting_ADSLightModel = "\n\
3659/* use ADSLightModel here the ADS colour is returned from the function. */ \n\
3660#ifdef LITE \n\
3661\n\
3662void PLUG_add_light_contribution2 (inout vec3 vertexcolor, inout vec3 specularcolor, in vec4 myPosition, in vec3 myNormal, \n\
3663 in float mat_shininess, in float mat_ambient, in vec3 mat_diffuse, in vec3 mat_specular){ \n\
3664 //working in eye space: eye is at 0,0,0 looking generally in direction 0,0,-1 \n\
3665 //myPosition, myNormal - of surface vertex, in eyespace \n\
3666 //vertexcolor - diffuse+ambient -will be replaced or modulated by texture color \n\
3667 //specularcolor - specular+emissive or non-diffuse (emissive added outside this function) \n\
3668 //algo: uses Blinn-Phong specular reflection: half-vector pow(N*H,shininess) \n\
3669 // https://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/lighting.html#Lightingequations \n\
3670 // fog and emissive are done elsewhere, this function does: \n\
3671 // SUM(on[i] x attenuation[i] x spot[i] x ILrgb[i] x (ambient[i] + diffuse[i] + specular[i])) \n\
3672 int i; \n\
3673 vec3 N = normalize (myNormal); \n\
3674 \n\
3675 vec3 E = -normalize(myPosition.xyz); \n \
3676 \n\
3677 // apply the lights to this material \n\
3678 // weird but ANGLE needs constant loop \n\
3679 vec3 sum_vertex = vec3(0.,0.,0.); \n\
3680 vec3 sum_specular = vec3(0.,0.,0.); \n\
3681 for (i=0; i<lightcount; i++) {\n\
3682 vec3 diffuse = vec3(0., 0., 0.); \n\
3683 vec3 ambient = vec3(0., 0., 0.); \n\
3684 vec3 specular = vec3(0., 0., 0.); \n\
3685 float on = 1.0; //we only send active/on lights to shader, so this is for radius \n\
3686 float spot = 1.0; \n\
3687 float attenuation = 1.0; //directional default \n\
3688 fw_LightSourceParameters light = fw_LightSource[i]; \n\
3689 int myLightType = lightType[i]; \n\
3690 // VP vector of light direction and distance \n\
3691 vec3 VP = light.location.xyz - myPosition.xyz; \n\
3692 vec3 L = -light.direction; //directional light \n\
3693 if(myLightType < 2){ \n\
3694 //point and spot \n\
3695 L = normalize(VP); \n\
3696 float D = length(VP); // distance to vertex \n\
3697 // are we within range? \n\
3698 if (D > light.lightRadius) on = 0.0; \n\
3699 attenuation = 1.0/max(1.0,(light.Attenuations.x + (light.Attenuations.y * D) + (light.Attenuations.z *D*D))); \n\
3700 } \n\
3701 float NdotL = max(dot(N, L), 0.0); //Lambertian diffuse term \n\
3702 //specular reflection models, phong or blinn-phong \n\
3703 //#define PHONG 1 \n\
3704 #ifdef PHONG \n\
3705 //Phong \n\
3706 vec3 R = normalize(-reflect(L,N)); \n\
3707 float RdotE = max(dot(R,E),0.0); \n\
3708 float specbase = RdotE; \n\
3709 // assume shader gets shininess in 0 to 1 range, and scales it to 0 to 128 range here \n\
3710 float specpow = mat_shininess*128.0; \n\
3711 #else //PHONG \n\
3712 //Blinn-Phong \n\
3713 vec3 H = normalize(L + E); //halfvector x3d specs this is L+v/|L+v|\n\
3714 float NdotH = max(dot(N,H),0.0); \n\
3715 float specbase = NdotH; \n\
3716 float specpow = mat_shininess*128.0; \n\
3717 #endif //PHONG \n\
3718 float powerFactor = 0.0; // for light dropoff \n\
3719 if (specbase > 0.0) { \n\
3720 powerFactor = pow(specbase,specpow); \n\
3721 // tone down the power factor if mat_shininess borders 0 \n\
3722 } \n\
3723 \n\
3724 ambient += light.ambient * mat_diffuse * mat_ambient; \n\
3725 specular += light.intensity * mat_specular *powerFactor; \n\
3726 diffuse += light.intensity * mat_diffuse * NdotL; \n\
3727 if (myLightType==1) { \n\
3728 // SpotLight \n\
3729 spot = 0.0; \n\
3730 float cosCut = cos(light.spotCutoff); \n\
3731 float cosBeam = cos(light.spotBeamWidth); \n\
3732 float rayAngle = dot(normalize(-L),normalize(light.direction)); \n\
3733 // check against spotCosCutoff \n\
3734 if (rayAngle > cosCut) { \n\
3735 if(rayAngle > cosBeam) { \n\
3736 spot = 1.0; \n\
3737 } else { \n\
3738 //spot = (rayAngle - cosCut)/(cosBeam - cosCut); \n\
3739 float rayradians = acos(rayAngle); \n\
3740 spot = (light.spotCutoff - rayradians)/(light.spotCutoff - light.spotBeamWidth); \n\
3741 } \n\
3742 } \n\
3743 } \n\
3744 float shadowtest = 1.0; \n\
3745#ifdef SHADOW \n\
3746 if (light.shadows) { \n\
3747 shadowtest = 1.0 - light.shadowIntensity*ShadowCalculation(i,VP); \n\
3748 } \n\
3749#endif //SHADOW \n\
3750 sum_vertex += on * shadowtest * attenuation * spot * light.color * (ambient + diffuse); \n\
3751 sum_specular += on * shadowtest * attenuation * spot * light.color * (specular); \n\
3752 } \n\
3753 vertexcolor = clamp(sum_vertex + vertexcolor, 0.0, 1.0); \n\
3754 specularcolor = clamp(sum_specular + specularcolor, 0.0, 1.0); \n\
3755} \n\
3756#endif //LITE \n\
3757";
3758
3759// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/lighting.html#t-foginterpolant
3760// PLUG: fog_apply (fragment_color, normal_eye_fragment)
3761static const GLchar *plug_fog_apply = "\
3762void PLUG_fog_apply (inout vec4 finalFrag, in vec3 normal_eye_fragment ){ \n\
3763 float ff = 1.0; \n\
3764 float depth = abs(castle_vertex_eye.z/castle_vertex_eye.w); \n\
3765 if(fw_fogparams.fogType > 0){ \n\
3766 ff = 0.0; \n\
3767 if(fw_fogparams.fogType == 1){ //FOGTYPE_LINEAR \n\
3768 if(depth < fw_fogparams.visibilityRange) \n\
3769 ff = (fw_fogparams.visibilityRange-depth)/fw_fogparams.visibilityRange; \n\
3770 } else { //FOGTYPE_EXPONENTIAL \n\
3771 if(depth < fw_fogparams.visibilityRange){ \n\
3772 ff = exp(-depth/(fw_fogparams.visibilityRange -depth) ); \n\
3773 ff = clamp(ff, 0.0, 1.0); \n\
3774 } \n\
3775 } \n\
3776 finalFrag = mix(finalFrag,fw_fogparams.fogColor,1.0 - ff); \n\
3777 } \n\
3778} \n\
3779";
3780
3781static const GLchar *vertex_plug_clip_apply = "\
3782#ifdef CLIP \n\
3783#define FW_MAXCLIPPLANES 4 \n\
3784uniform int fw_nclipplanes; \n\
3785uniform vec4 fw_clipplanes[FW_MAXCLIPPLANES]; \n\
3786varying float fw_ClipDistance[FW_MAXCLIPPLANES]; \n\
3787 \n\
3788void PLUG_vertex_object_space (in vec4 vertex_object, in vec3 normal_object){ \n\
3789 for ( int i=0; i<fw_nclipplanes; i++ ) \n\
3790 fw_ClipDistance[i] = dot( fw_clipplanes[i], vertex_object); \n\
3791} \n\
3792#endif //CLIP \n\
3793";
3794
3795static const GLchar *frag_plug_clip_apply = "\
3796#ifdef CLIP \n\
3797#define FW_MAXCLIPPLANES 4 \n\
3798uniform int fw_nclipplanes; \n\
3799varying float fw_ClipDistance[FW_MAXCLIPPLANES]; \n\
3800void PLUG_fog_apply (inout vec4 finalFrag, in vec3 normal_eye_fragment ){ \n\
3801 for(int i=0;i<fw_nclipplanes;i++) { \n\
3802 //if(normal_eye_fragment.z > fw_ClipDistance[i]) discard; \n\
3803 if(fw_ClipDistance[i] < 0.0) discard; \n\
3804 } \n\
3805} \n\
3806#endif //CLIP \n\
3807";
3808
3809
3810//assumes little endian
3811void printBitsB(size_t const size, void const * const ptr)
3812{
3813 unsigned char *b = (unsigned char*) ptr;
3814 unsigned char byte;
3815 int i, j;
3816
3817 for (i=size-1;i>=0;i--)
3818 {
3819 for (j=7;j>=0;j--)
3820 {
3821 byte = (b[i] >> j) & 1;
3822 printf("%u", byte);
3823 }
3824 printf(" ");
3825 }
3826 printf("\n");
3827}
3828
3829
3830#if defined(GL_ES_VERSION_2_0)
3831static int isMobile = TRUE;
3832#else
3833static int isMobile = FALSE;
3834#endif
3835int get_GLSL_max_version(){
3836 static int once = FALSE;
3837 static float glsl_version = 0.0f;
3838 static int max_shader_version = 130;
3839 if(!once){
3840 const GLubyte * glsl_version_str = glGetString ( GL_SHADING_LANGUAGE_VERSION);
3841 sscanf(glsl_version_str,"%f",&glsl_version);
3842 max_shader_version = (int)(glsl_version * 100.0f + .4f);
3843 ConsoleMessage("GLSL shader max version %s %d\n", glsl_version_str, max_shader_version );
3844 once = TRUE;
3845 }
3846 return max_shader_version;
3847}
3848#define DESIRE(whichOne,zzz) ((whichOne & zzz)==zzz)
3849static int GLSL_max_version = 0;
3850int getSpecificShaderSourceCastlePlugs (const GLchar **vertexSource, const GLchar **fragmentSource, shaderflagsstruct whichOne)
3851{
3852 //for building the Builtin (similar to fixed-function pipeline, except from shader parts)
3853 //in OpenGL_Utils.c L.2553 set usingCastlePlugs = 1 to get in here.
3854 //whichone - a bitmask of shader requirements, one bit for each requirement, so shader permutation can be built
3855
3856 int retval, unique_int;
3857 char *CompleteCode[3];
3858 char *vs, *fs;
3859
3860 retval = FALSE;
3861 if(whichOne.usershaders ) //& USER_DEFINED_SHADER_MASK)
3862 return retval; //not supported yet as of Aug 9, 2016
3863 retval = TRUE;
3864 if(!GLSL_max_version){
3865 //const GLubyte * glsl_version_str = glGetString ( GL_SHADING_LANGUAGE_VERSION);
3866 //sscanf(glsl_version_str,"%f",&glsl_version);
3867 //max_shader_version = (int)(glsl_version * 100.0f + .4f);
3868 //printf("GLSL shader version support %s %4.2f %d\n", glsl_version_str, glsl_version, max_shader_version );
3869 //once = TRUE;
3870 GLSL_max_version = get_GLSL_max_version();
3871 }
3872 //generic
3873 vs = strdup(getGenericVertex());
3874 fs = strdup(getGenericFragment());
3875 //printf("size of frag shader %d\n",strlen(fs)); //MS vc has literal string size limit 65535
3876
3877 CompleteCode[SHADERPART_VERTEX] = vs;
3878 CompleteCode[SHADERPART_GEOMETRY] = NULL;
3879 CompleteCode[SHADERPART_FRAGMENT] = fs;
3880
3881 // what we really have here: UberShader with CastlePlugs
3882 // UberShader: one giant shader peppered with #ifdefs, and you add #defines at the top for permutations
3883 // CastlePlugs: allows users to add effects on to uberShader with PLUGs
3884 // - and internally, we can do a few permutations with PLUGs too
3885
3886 if(isMobile){
3887 int iver = 100;
3888 char* aver = "";
3889 // https://en.wikipedia.org/wiki/OpenGL_Shading_Language#Versions
3890 // 100 300 es 310 es 410 es
3891 // iver = 320;
3892 // aver = "es";
3893 AddVersion0(SHADERPART_VERTEX, iver, aver, CompleteCode); //lower precision floats
3894 AddVersion0(SHADERPART_FRAGMENT, iver, aver, CompleteCode); //lower precision floats
3895 AddDefine(SHADERPART_FRAGMENT,"MOBILE",CompleteCode); //lower precision floats
3896 }else{
3897 if(GLSL_max_version >= 130) {
3898 int iver = 130; //testing for shader being able to run on low capability machines elsewhere
3899 //https://en.wikipedia.org/wiki/OpenGL_Shading_Language#Versions
3900 // 110 120 130 140 150 330 400 410 420 430 440 450 460
3901 iver = GLSL_max_version; //for maximizing capabilities
3902 AddVersion(SHADERPART_VERTEX, iver, CompleteCode); //lower precision floats
3903 AddVersion(SHADERPART_FRAGMENT, iver, CompleteCode); //lower precision floats
3904 AddDefine(SHADERPART_VERTEX, "FULL", CompleteCode); //lower precision floats
3905 AddDefine(SHADERPART_FRAGMENT, "FULL", CompleteCode); //lower precision floats
3906 }else{
3907 AddVersion(SHADERPART_VERTEX, GLSL_max_version, CompleteCode); //lower precision floats
3908 AddVersion(SHADERPART_FRAGMENT, GLSL_max_version, CompleteCode); //lower precision floats
3909 }
3910 }
3911
3912 // printBitsB(sizeof(int),&whichOne.base); //debugging _shaderflags
3913
3914
3915 unique_int = 0; //helps generate method name PLUG_xxx_<unique_int> to avoid clash when multiple PLUGs supplied for same PLUG point
3916 //Add in:
3917 //Lit
3918 //Fog
3919 //analglyph
3920 if(DESIRE(whichOne.base,WANT_ANAGLYPH))
3921 Plug(SHADERPART_FRAGMENT,plug_fragment_end_anaglyph,CompleteCode,&unique_int); //works, converts frag to gray
3922 //color per vertex
3923 if DESIRE(whichOne.base,COLOUR_MATERIAL_SHADER) {
3924 AddDefine(SHADERPART_VERTEX,"CPV",CompleteCode);
3925 AddDefine(SHADERPART_FRAGMENT,"CPV",CompleteCode);
3926 }
3927 if(DESIRE(whichOne.base,MODULATE_COLOR)){
3928 //we have a grayscale / illuminance image, modulate any color-per-vertes/face
3929 AddDefine(SHADERPART_VERTEX,"MODC",CompleteCode);
3930 AddDefine(SHADERPART_FRAGMENT,"MODC",CompleteCode);
3931 }
3932 if(DESIRE(whichOne.base,MODULATE_ALPHA)){
3933 // image texture doesn't havve an interesting alpha, use material alpha
3934 AddDefine(SHADERPART_FRAGMENT,"MODA",CompleteCode);
3935 }
3936 if(DESIRE(whichOne.base,MODULATE_TEXTURE)){
3937 // freewrl out-of-spec menu option: change single texture replace prior to texture modulate material diffuse
3938 AddDefine(SHADERPART_FRAGMENT,"MODT",CompleteCode);
3939 }
3940 //material appearance
3941 //2 material appearance
3942 //phong vs gourard
3943 if(DESIRE(whichOne.base,MATERIAL_APPEARANCE_SHADER) || DESIRE(whichOne.base,TWO_MATERIAL_APPEARANCE_SHADER)
3944 || DESIRE(whichOne.base,PHYSICAL_MATERIAL_APPEARANCE_SHADER) || DESIRE(whichOne.base,UNLIT_MATERIAL_APPEARANCE_SHADER)){
3945 //we have a material node of some type
3946 AddDefine(SHADERPART_VERTEX,"LIT",CompleteCode);
3947 AddDefine(SHADERPART_FRAGMENT,"LIT",CompleteCode);
3948
3949 if(DESIRE(whichOne.base,TWO_MATERIAL_APPEARANCE_SHADER)){
3950 AddDefine(SHADERPART_FRAGMENT,"TWO",CompleteCode);
3951 AddDefine(SHADERPART_VERTEX,"TWO",CompleteCode);
3952 }
3953 if(DESIRE(whichOne.base,SHADINGSTYLE_GOURAUD) ){ //|| DESIRE(whichOne.base,MULTI_TEX_APPEARANCE_SHADER)){
3954 //when we say gouraud in freewrl, we really mean per-vertex lighting, in vertex shader
3955 AddDefine(SHADERPART_VERTEX,"LITE",CompleteCode); //add some lights
3956 //with v4 Appearance.backMaterial, you could have physical on one side, and regular on the other - both
3957 if(DESIRE(whichOne.base,MATERIAL_APPEARANCE_SHADER) || DESIRE(whichOne.base,TWO_MATERIAL_APPEARANCE_SHADER))
3958 Plug(SHADERPART_VERTEX,plug_vertex_lighting_ADSLightModel,CompleteCode,&unique_int); //use lights
3959 if (DESIRE(whichOne.base, PHYSICAL_MATERIAL_APPEARANCE_SHADER))
3960 Plug(SHADERPART_VERTEX, plug_frag_lighting_physical, CompleteCode, &unique_int); //use lights
3961 }
3962 if(DESIRE(whichOne.base,SHADINGSTYLE_PHONG)){
3963 //when we say phong in freewrl, we really mean per-fragment lighting in fragment shader
3964 AddDefine(SHADERPART_FRAGMENT,"LITE",CompleteCode); //add some lights
3965 AddDefine(SHADERPART_FRAGMENT, "SHADOW", CompleteCode); //add some shadow computations
3966 //with v4 Appearance.backMaterial, you could have physical on one side, and regular on the other - both
3967 if(DESIRE(whichOne.base,PHYSICAL_MATERIAL_APPEARANCE_SHADER))
3968 Plug(SHADERPART_FRAGMENT,plug_frag_lighting_physical,CompleteCode,&unique_int); //use lights
3969 if(DESIRE(whichOne.base,MATERIAL_APPEARANCE_SHADER) || DESIRE(whichOne.base,TWO_MATERIAL_APPEARANCE_SHADER))
3970 Plug(SHADERPART_FRAGMENT,plug_vertex_lighting_ADSLightModel,CompleteCode,&unique_int); //use lights
3971 AddDefine(SHADERPART_FRAGMENT,"PHONG",CompleteCode);
3972 AddDefine(SHADERPART_VERTEX, "PHONG", CompleteCode);
3973 }
3974 //lines and points with material (rendered emissive)
3975 if( DESIRE(whichOne.base,HAVE_LINEPOINTS_COLOR) ) {
3976 AddDefine(SHADERPART_VERTEX,"LINE",CompleteCode);
3977 AddDefine(SHADERPART_FRAGMENT,"LINE",CompleteCode);
3978 }
3979 }
3980 //textureCoordinategen
3981 //cubemap texure
3982 //one tex appearance
3983 //multi tex appearance
3984 //cubemap tex
3985 /* http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/lighting.html#Lightingon
3986 "The Material's transparency field modulates the alpha in the texture. Hence,
3987 a transparency of 0 will result in an alpha equal to that of the texture.
3988 A transparency of 1 will result in an alpha of 0 regardless of the value in the texture."
3989 That doesn't seem to me to be what browsers Octaga, InstantReality, or Cortona are doing,
3990 and its not what table 17-3 and the Lighting equation say is happening.
3991 In the table, alpha is never 'modulated' ie there's never an alpha= AT * (1-TM) term.
3992 - freewrl version 3 and vivaty do modulate.
3993 I've put a define to set if you don't want modulation ie table 17-3.
3994 If you do want to modulate ie the above quote "to modulate", comment out the define
3995 I put a mantis issue to web3d.org for clarification Aug 16, 2016
3996 */
3997 int colCalc_loaded = FALSE;
3998 if(DESIRE(whichOne.base,HAVE_UNLIT_COLOR)){
3999 //used by particles
4000 AddDefine(SHADERPART_VERTEX,"UNLIT",CompleteCode);
4001 AddDefine(SHADERPART_FRAGMENT,"UNLIT",CompleteCode);
4002 }
4003 if(DESIRE(whichOne.base,HAVE_PROJECTIVETEXTURE)){
4004 //May 27, 2022 moved PROJTEX calc to frag to reduce vertex shader component output, limited to 128
4005 AddDefine(SHADERPART_FRAGMENT,"PROJTEX",CompleteCode);
4006 AddDefine(SHADERPART_FRAGMENT,"TEX",CompleteCode);
4007 if(!colCalc_loaded) Plug(SHADERPART_FRAGMENT,plug_finalColCalc,CompleteCode,&unique_int);
4008 colCalc_loaded = TRUE;
4009 }
4010 if (DESIRE(whichOne.base,ONE_TEX_APPEARANCE_SHADER) ||
4011 DESIRE(whichOne.base,HAVE_TEXTURECOORDINATEGENERATOR) ||
4012 DESIRE(whichOne.base,HAVE_CUBEMAP_TEXTURE) ||
4013 DESIRE(whichOne.base,MULTI_TEX_APPEARANCE_SHADER)) {
4014
4015 AddDefine(SHADERPART_VERTEX,"TEX",CompleteCode);
4016 AddDefine(SHADERPART_FRAGMENT,"TEX",CompleteCode);
4017 if(DESIRE(whichOne.base,HAVE_TEXTURECOORDINATEGENERATOR) )
4018 AddDefine(SHADERPART_VERTEX,"TGEN",CompleteCode);
4019 if(DESIRE(whichOne.base,TEX3D_SHADER)){
4020 //in theory, if the texcoordgen "COORD" and TextureTransform3D are set in scenefile
4021 // and working properly in freewrl, then don't need TEX3D for that node in VERTEX shader
4022 // which is using tex3dbbox (shape->_extent reworked) to get vertex coords in 0-1 range
4023 // x Sept 4, 2016 either TextureTransform3D or CoordinateGenerator "COORD" isn't working right for Texture3D
4024 // so we're using the bbox method
4025 //vertex str texture coords computed same for both volume and layered tex3d
4026 AddDefine(SHADERPART_VERTEX,"TEX3D",CompleteCode);
4027 AddDefine(SHADERPART_FRAGMENT,"TEX3D",CompleteCode);
4028 //fragment part different:
4029 if(DESIRE(whichOne.base,TEX3D_LAYER_SHADER)){
4030 //up to 6 textures, with lerp between floor,ceil textures
4031 AddDefine(SHADERPART_FRAGMENT,"TEX3DLAY",CompleteCode);
4032 Plug(SHADERPART_FRAGMENT,plug_fragment_texture3Dlayer_apply_uber,CompleteCode,&unique_int);
4033 }else{
4034 //TEX3D_VOLUME_SHADER
4035 //AddDefine(SHADERPART_FRAGMENT,"TEX3D",CompleteCode);
4036 Plug(SHADERPART_FRAGMENT,plug_fragment_texture3D_apply_volume_uber,CompleteCode,&unique_int);
4037 }
4038 }else {
4039 if(DESIRE(whichOne.base,HAVE_CUBEMAP_TEXTURE)){
4040 AddDefine(SHADERPART_VERTEX,"CUB",CompleteCode);
4041 AddDefine(SHADERPART_FRAGMENT,"CUB",CompleteCode);
4042 //AddExtension(SHADERPART_FRAGMENT, "GL_NV_","enable", CompleteCode);
4043 }
4044 if(DESIRE(whichOne.base,MULTI_TEX_APPEARANCE_SHADER)){
4045 // https://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/texturing.html#MultiTexture
4046 //- source can be DIFFUSE or SPECULAR, from Gauraud (vertex) lighting
4047 AddDefine(SHADERPART_VERTEX,"MTEX",CompleteCode);
4048 AddDefine(SHADERPART_FRAGMENT,"MTEX",CompleteCode);
4049 }
4050
4051 if(!colCalc_loaded) Plug(SHADERPART_FRAGMENT,plug_finalColCalc,CompleteCode,&unique_int);
4052 colCalc_loaded = TRUE;
4053 Plug(SHADERPART_FRAGMENT,plug_fragment_texture_apply,CompleteCode,&unique_int);
4054
4055 }
4056 }
4057
4058 //fill properties / hatching
4059 if(DESIRE(whichOne.base,FILL_PROPERTIES_SHADER)) {
4060 AddDefine(SHADERPART_VERTEX,"FILL",CompleteCode);
4061 AddDefine(SHADERPART_FRAGMENT,"FILL",CompleteCode);
4062 if(GLSL_max_version >= 130) {
4063 Plug(SHADERPART_FRAGMENT,plug_fragment_fillProperties_apply,CompleteCode,&unique_int);
4064 }else{
4065 Plug(SHADERPART_FRAGMENT,plug_fragment_fillProperties_apply_120,CompleteCode,&unique_int);
4066 }
4067 }
4068 //LINETYPES
4069 if(DESIRE(whichOne.base,LINE_PROPERTIES_SHADER)) {
4070 AddDefine(SHADERPART_VERTEX,"LINETYPE",CompleteCode);
4071 AddDefine(SHADERPART_FRAGMENT,"LINETYPE",CompleteCode);
4072 }
4073 //POINT PROPERTIES
4074 if(DESIRE(whichOne.base,POINT_PROPERTIES_SHADER)) {
4075 AddDefine(SHADERPART_VERTEX,"POINTP",CompleteCode);
4076 AddDefine(SHADERPART_FRAGMENT,"POINTP",CompleteCode);
4077 }
4078 //FOG
4079 if(DESIRE(whichOne.base,FOG_APPEARANCE_SHADER)){
4080 AddDefine(SHADERPART_VERTEX,"FOG",CompleteCode);
4081 AddDefine(SHADERPART_FRAGMENT,"FOG",CompleteCode);
4082 if(DESIRE(whichOne.base,HAVE_FOG_COORDS))
4083 AddDefine(SHADERPART_VERTEX,"FOGCOORD",CompleteCode);
4084 Plug(SHADERPART_FRAGMENT,plug_fog_apply,CompleteCode,&unique_int);
4085 }
4086 //CLIPPLANE
4087 //FOG
4088 if(DESIRE(whichOne.base,CLIPPLANE_SHADER)){
4089 AddDefine(SHADERPART_VERTEX,"CLIP",CompleteCode);
4090 Plug(SHADERPART_VERTEX,vertex_plug_clip_apply,CompleteCode,&unique_int);
4091 AddDefine(SHADERPART_FRAGMENT,"CLIP",CompleteCode);
4092 Plug(SHADERPART_FRAGMENT,frag_plug_clip_apply,CompleteCode,&unique_int);
4093 }
4094 if(DESIRE(whichOne.base,PARTICLE_SHADER)){
4095 AddDefine(SHADERPART_VERTEX,"PARTICLE",CompleteCode);
4096 }
4097 if (DESIRE(whichOne.base, SKINNING_SHADER)) {
4098 AddDefine(SHADERPART_VERTEX, "SKINNING", CompleteCode);
4099 if(DESIRE(whichOne.base,DISPLACER_SHADER))
4100 AddDefine(SHADERPART_VERTEX, "DISPLACER", CompleteCode);
4101 }
4102
4103 //EFFECTS - castle game engine effect nodes X3D_Effect with plugs applied here
4104 EnableEffects(CompleteCode,&unique_int);
4105
4106 // stripUnusedDefines(CompleteCode);
4107 // http://freecode.com/projects/unifdef/ example: unifdef -UTEX -UGMTEX shader.vs > out.vs will strip the TEX and MTEX sections out
4108 // or hack something like https://github.com/evanplaice/pypreprocessor
4109 // dug9 hacked py3 for shader pre-processing: http://dug9.users.sourceforge.net/web3d/tests/largetexture/preprocessor_dug9_3T.py
4110
4111 *fragmentSource = CompleteCode[SHADERPART_FRAGMENT]; //original_fragment; //fs;
4112 *vertexSource = CompleteCode[SHADERPART_VERTEX]; //original_vertex; //vs;
4113
4114//SHADER OVERWRITE SECTION, FOR TEMPORARY TESTING
4115// allows substitution of simpler shaders when debugging ("is it the shader, or CPU-side code?")
4116// or exploring new features before integration into ubershader
4117// (but won't allow creative permutations with other effects, for that ubershader integration needed)
4118 // CUB / cubemap - not working in Ubershader / genericFragmentGLES2 April 2022 so made a genericFragmentCube that's dead simple
4119 // if becomes permanent, then make a CUBEMAP_MATERIAL_APPEARANCE_SHADER entry above?
4120 if (0) if (DESIRE(whichOne.base, HAVE_CUBEMAP_TEXTURE)) {
4121 *fragmentSource = genericFragmentCube; //testing cubemap reflection rendering by itself (had problems with frag ubershader Apr 2022).
4122 }
4123 if(0) if (DESIRE(whichOne.base, HAVE_CUBEMAP_TEXTURE)) {
4124 char* fragbuf = malloc(64000);
4125 memset(fragbuf, 0, 64000);
4126 FILE* fp = fopen("C:\\Users\\dougs\\Documents\\dev\\source2\\freewrk_tmp\\hacked_frag.txt", "r+");
4127 int ir = fread(fragbuf, 1, 64000, fp);
4128 fragbuf[ir] = 0;
4129 //char *eof = strstr(fragbuf, "EOF");
4130 //*eof = '\0';
4131 // printf("%s", fragbuf);
4132 *fragmentSource = fragbuf;
4133 }
4134
4135 //printf("size of finished fragment shader %d bytes\n",strlen(*fragmentSource));
4136//#define DEBUGSHADER 1
4137#ifdef DEBUGSHADER
4138 {
4139 //after writing to file you can run unifdef, sunifdef or coan on output to see reduced shader
4140 // http://coan2.sourceforge.net/
4141 //coan source -m composed_shader.vert > shader.vert
4142 FILE *fp = fopen("C:/tmp/composed_shader.vert","w+");
4143 fwrite(*vertexSource,strlen(*vertexSource),1,fp);
4144 fclose(fp);
4145 fp = fopen("C:/tmp/composed_shader.frag","w+");
4146 fwrite(*fragmentSource,strlen(*fragmentSource),1,fp);
4147 fclose(fp);
4148 printf("wrote shader\n");
4149 }
4150#endif //DEBUGSHADER
4151#undef DEBUGSHADER
4152
4153 return retval;
4154}
4155
4156// START MIT, VOLUME RENDERING >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
4157static const GLchar* plug_vertex_lighting_ADSLightModel_volume = "\n\
4158/* use ADSLightModel here the ADS colour is returned from the function. */ \n\
4159void PLUG_add_light_contribution2 (inout vec3 vertexcolor, inout vec3 specularcolor, in vec4 myPosition, in vec3 myNormal, \n\
4160 in float mat_shininess, in float mat_ambient, in vec3 mat_diffuse, in vec3 mat_specular){ \n\
4161 //working in eye space: eye is at 0,0,0 looking generally in direction 0,0,-1 \n\
4162 //myPosition, myNormal - of surface vertex, in eyespace \n\
4163 //vertexcolor - diffuse+ambient -will be replaced or modulated by texture color \n\
4164 //specularcolor - specular+emissive or non-diffuse (emissive added outside this function) \n\
4165 //algo: uses Blinn-Phong specular reflection: half-vector pow(N*H,shininess) \n\
4166 // https://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/lighting.html#Lightingequations \n\
4167 // fog and emissive are done elsewhere, this function does: \n\
4168 // SUM(on[i] x attenuation[i] x spot[i] x ILrgb[i] x (ambient[i] + diffuse[i] + specular[i])) \n\
4169 int i; \n\
4170 vec3 N = normalize (myNormal); \n\
4171 \n\
4172 vec3 E = -normalize(myPosition.xyz); \n \
4173 \n\
4174 // apply the lights to this material \n\
4175 // weird but ANGLE needs constant loop \n\
4176 vec3 sum_vertex = vec3(0.,0.,0.); \n\
4177 vec3 sum_specular = vec3(0.,0.,0.); \n\
4178 for (i=0; i<lightcount; i++) {\n\
4179 vec3 diffuse = vec3(0., 0., 0.); \n\
4180 vec3 ambient = vec3(0., 0., 0.); \n\
4181 vec3 specular = vec3(0., 0., 0.); \n\
4182 float on = 1.0; //we only send active/on lights to shader, so this is for radius \n\
4183 float spot = 1.0; \n\
4184 float attenuation = 1.0; //directional default \n\
4185 fw_LightSourceParameters light = fw_LightSource[i]; \n\
4186 int myLightType = lightType[i]; \n\
4187 // VP vector of light direction and distance \n\
4188 vec3 VP = light.location.xyz - myPosition.xyz; \n\
4189 vec3 L = -light.direction; //directional light \n\
4190 if(myLightType < 2){ \n\
4191 //point and spot \n\
4192 L = normalize(VP); \n\
4193 float D = length(VP); // distance to vertex \n\
4194 // are we within range? \n\
4195 if (D > light.lightRadius) on = 0.0; \n\
4196 attenuation = 1.0/max(1.0,(light.Attenuations.x + (light.Attenuations.y * D) + (light.Attenuations.z *D*D))); \n\
4197 } \n\
4198 float NdotL = max(dot(N, L), 0.0); //Lambertian diffuse term \n\
4199 //specular reflection models, phong or blinn-phong \n\
4200 //#define PHONG 1 \n\
4201 #ifdef PHONG \n\
4202 //Phong \n\
4203 vec3 R = normalize(-reflect(L,N)); \n\
4204 float RdotE = max(dot(R,E),0.0); \n\
4205 float specbase = RdotE; \n\
4206 // assume shader gets shininess in 0 to 1 range, and scales it to 0 to 128 range here \n\
4207 float specpow = mat_shininess*128.0; \n\
4208 #else //PHONG \n\
4209 //Blinn-Phong \n\
4210 vec3 H = normalize(L + E); //halfvector x3d specs this is L+v/|L+v|\n\
4211 float NdotH = max(dot(N,H),0.0); \n\
4212 float specbase = NdotH; \n\
4213 float specpow = mat_shininess*128.0; \n\
4214 #endif //PHONG \n\
4215 float powerFactor = 0.0; // for light dropoff \n\
4216 if (specbase > 0.0) { \n\
4217 powerFactor = pow(specbase,specpow); \n\
4218 // tone down the power factor if mat_shininess borders 0 \n\
4219 } \n\
4220 \n\
4221 ambient += light.ambient * mat_diffuse * mat_ambient; \n\
4222 specular += light.intensity * mat_specular *powerFactor; \n\
4223 diffuse += light.intensity * mat_diffuse * NdotL; \n\
4224 if (myLightType==1) { \n\
4225 // SpotLight \n\
4226 spot = 0.0; \n\
4227 float spotDot = dot (-L,light.direction); \n\
4228 // check against spotCosCutoff \n\
4229 if (spotDot > light.spotCutoff) { \n\
4230 if(spotDot > light.spotBeamWidth) { \n\
4231 spot = 1.0; \n\
4232 } else { \n\
4233 spot = (spotDot - light.spotCutoff)/(light.spotBeamWidth - light.spotCutoff); \n\
4234 } \n\
4235 } \n\
4236 } \n\
4237 sum_vertex += on * attenuation * spot * light.color * (ambient + diffuse); \n\
4238 sum_specular += on * attenuation * spot * light.color * (specular); \n\
4239 } \n\
4240 vertexcolor = clamp(sum_vertex + vertexcolor, 0.0, 1.0); \n\
4241 specularcolor = clamp(sum_specular + specularcolor, 0.0, 1.0); \n\
4242} \n\
4243";
4244
4245/* Generic GLSL vertex shader, used on OpenGL ES. */
4246static const GLchar *volumeVertexGLES2 = " \n\
4247#define varying out \n\
4248#define atribute in \n\
4249uniform mat4 fw_ModelViewMatrix; \n\
4250uniform mat4 fw_ProjectionMatrix; \n\
4251attribute vec4 fw_Vertex; \n\
4252 \n\
4253/* PLUG-DECLARATIONS */ \n\
4254 \n\
4255varying vec4 castle_vertex_eye; \n\
4256varying vec4 castle_Color; \n\
4257 \n\
4258void main(void) \n\
4259{ \n\
4260 vec4 vertex_object = fw_Vertex; \n\
4261 vec3 normal_object = vec3(0.0); \n\
4262 /* PLUG: vertex_object_space (vertex_object, normal_object) */ \n\
4263 castle_vertex_eye = fw_ModelViewMatrix * vertex_object; \n\
4264 \n\
4265 castle_Color = vec4(1.0,.5,.5,1.0); \n\
4266 \n\
4267 gl_Position = fw_ProjectionMatrix * castle_vertex_eye; \n\
4268 \n\
4269} \n\
4270";
4271
4272
4273
4274
4275
4276/* Generic GLSL fragment shader, used on OpenGL ES. */
4277static const GLchar *volumeFragmentGLES2 = " \n\
4278/*EXTENSIONS*/ \n\
4279/* DEFINES */ \n\
4280#ifdef MOBILE \n\
4281//precision highp float; \n\
4282precision mediump float; \n\
4283#endif //MOBILE \n\
4284#define varying in \n\
4285#define texture2D texture \n\
4286#define texture3D texture \n\
4287#define textureCube texture \n\
4288#define texture2DProj textureProj \n\
4289#define texture3DProj textureProj \n\
4290out vec4 FragColor; \n\
4291 \n\
4292 vec4 HeatMapColor(float value, float minValue, float maxValue) \n\
4293{ \n\
4294 //used for debugging. If min=0,max=1 then magenta is 0, blue,green,yellow, red is 1 \n\
4295 vec4 ret; \n\
4296 int HEATMAP_COLORS_COUNT; \n\
4297 vec4 colors[6]; \n\
4298 HEATMAP_COLORS_COUNT = 6; \n\
4299 colors[0] = vec4(0.32, 0.00, 0.32, 1.0); \n\
4300 colors[1] = vec4( 0.00, 0.00, 1.00, 1.00); \n\
4301 colors[2] = vec4(0.00, 1.00, 0.00, 1.00); \n\
4302 colors[3] = vec4(1.00, 1.00, 0.00, 1.00); \n\
4303 colors[4] = vec4(1.00, 0.60, 0.00, 1.00); \n\
4304 colors[5] = vec4(1.00, 0.00, 0.00, 1.00); \n\
4305 float ratio=(float(HEATMAP_COLORS_COUNT)-1.0)*clamp((value-minValue)/(maxValue-minValue),0.0,1.0); \n\
4306 int indexMin=int(floor(ratio)); \n\
4307 int indexMax= indexMin+1 < HEATMAP_COLORS_COUNT-1 ? indexMin+1 : HEATMAP_COLORS_COUNT-1; \n\
4308 ret = mix(colors[indexMin], colors[indexMax], ratio-float(indexMin)); \n\
4309 if(value < minValue) ret = vec4(0.0,0.0,0.0,1.0); \n\
4310 if(value > maxValue) ret = vec4(1.0,1.0,1.0,1.0); \n\
4311 return ret; \n\
4312} \n\
4313vec4 debug_color; \n\
4314float hash( float n ) \n\
4315{ \n\
4316 return fract(sin(n)*43758.5453); \n\
4317} \n\
4318float noise( vec3 xyz ) \n\
4319{ \n\
4320 // The noise function returns a value in the range -1.0f -> 1.0f \n\
4321 vec3 p = floor(xyz); \n\
4322 vec3 f = fract(xyz); \n\
4323 \n\
4324 f = f*f*(3.0-2.0*f); \n\
4325 float n = p.x + p.y*57.0 + 113.0*p.z; \n\
4326 \n\
4327 return mix(mix(mix( hash(n+0.0), hash(n+1.0),f.x), \n\
4328 mix( hash(n+57.0), hash(n+58.0),f.x),f.y), \n\
4329 mix(mix( hash(n+113.0), hash(n+114.0),f.x), \n\
4330 mix( hash(n+170.0), hash(n+171.0),f.x),f.y),f.z); \n\
4331} \n\
4332vec3 noise3( in vec3 xyz, in float range ){ \n\
4333 vec3 rxyz = vec3(xyz); \n\
4334 rxyz.x += noise(xyz)*range; \n\
4335 rxyz.y += noise(xyz)*range; \n\
4336 rxyz.z += noise(xyz)*range; \n\
4337 return rxyz; \n\
4338} \n\
4339 \n\
4340varying vec4 castle_vertex_eye; \n\
4341varying vec4 castle_Color; \n\
4342uniform mat4 fw_ModelViewProjInverse; \n\
4343//uniform float fw_FocalLength; \n\
4344uniform vec4 fw_viewport; \n\
4345uniform vec3 fw_dimensions; \n\
4346//uniform vec3 fw_RayOrigin; \n\
4347uniform sampler2D fw_Texture_unit0; \n\
4348uniform sampler2D fw_Texture_unit1; \n\
4349uniform sampler2D fw_Texture_unit2; \n\
4350uniform sampler2D fw_Texture_unit3; \n\
4351uniform int fw_gradTexture; \n\
4352vec4 texture3Demu0( sampler2D sampler, in vec3 texcoord3, int magfilter); \n\
4353uniform int magFilter; \n\
4354#ifdef TEX3D \n\
4355uniform int tex3dTiles[3]; \n\
4356uniform int repeatSTR[3]; \n\
4357#endif //TEX3D \n\
4358#ifdef SEGMENT \n\
4359uniform int fw_nIDs; \n\
4360uniform int fw_enableIDs[10]; \n\
4361uniform int fw_surfaceStyles[2]; \n\
4362uniform int fw_nStyles; \n\
4363vec4 texture3Demu( sampler2D sampler, in vec3 texcoord3); \n\
4364bool inEnabledSegment(in vec3 texcoords, inout int jstyle){ \n\
4365 bool inside = true; \n\
4366 jstyle = 1; //DEFAULT \n\
4367 vec4 segel = texture3Demu0(fw_Texture_unit1,texcoords,0); \n\
4368 //convert from GL_FLOAT 0-1 to int 0-255 \n\
4369 //Q. is there a way to do int images in GLES2? \n\
4370 int ID = int(floor(segel.a * 255.0 + .1)); \n\
4371 //debug_color = HeatMapColor(float(ID),0.0,5.0); \n\
4372 //debug_color.a = .2; \n\
4373 if(ID < fw_nIDs){ \n\
4374 //specs: The indices of this array corresponds to the segment identifier. \n\
4375 inside = fw_enableIDs[ID] == 0 ? false : true; \n\
4376 } \n\
4377 if(inside){ \n\
4378 int kstyle = fw_nStyles-1; \n\
4379 kstyle = ID < fw_nStyles ? ID : kstyle; \n\
4380 jstyle = fw_surfaceStyles[kstyle]; \n\
4381 jstyle = jstyle == 1 ? 0 : jstyle; \n\
4382 } \n\
4383 return inside; \n\
4384} \n\
4385#endif //SEGMENT \n\
4386#ifdef ISO \n\
4387uniform float fw_stepSize; \n\
4388uniform float fw_tolerance; \n\
4389uniform float fw_surfaceVals[]; \n\
4390uniform int fw_nVals; \n\
4391uniform int fw_surfaceStyles[]; \n\
4392uniform int fw_nStyles; \n\
4393#endif //ISO \n\
4394 \n\
4395struct Ray { \n\
4396 vec3 Origin; \n\
4397 vec3 Dir; \n\
4398}; \n\
4399struct AABB { \n\
4400 vec3 Min; \n\
4401 vec3 Max; \n\
4402}; \n\
4403bool IntersectBox(Ray r, AABB aabb, out float t0, out float t1) \n\
4404{ \n\
4405 vec3 invR = 1.0 / r.Dir; \n\
4406 vec3 tbot = invR * (aabb.Min-r.Origin); \n\
4407 vec3 ttop = invR * (aabb.Max-r.Origin); \n\
4408 vec3 tmin = min(ttop, tbot); \n\
4409 vec3 tmax = max(ttop, tbot); \n\
4410 vec2 t = max(tmin.xx, tmin.yz); \n\
4411 t0 = max(t.x, t.y); \n\
4412 t = min(tmax.xx, tmax.yz); \n\
4413 t1 = min(t.x, t.y); \n\
4414 return t0 <= t1; \n\
4415} \n\
4416/* PLUG-DECLARATIONS */ \n\
4417 \n\
4418vec3 fw_TexCoord[1]; \n\
4419#ifdef CLIP \n\
4420#define FW_MAXCLIPPLANES 4 \n\
4421uniform int fw_nclipplanes; \n\
4422uniform vec4 fw_clipplanes[FW_MAXCLIPPLANES]; \n\
4423bool clip (in vec3 vertex_object){ \n\
4424 bool iclip = false; \n\
4425 for ( int i=0; i<fw_nclipplanes; i++ ) { \n\
4426 if( dot( fw_clipplanes[i], vec4(vertex_object,1.0)) < 0.0) \n\
4427 iclip = true; \n\
4428 } \n\
4429 return iclip; \n\
4430} \n\
4431#endif //CLIP \n\
4432vec3 vertex_eye; \n\
4433vec3 normal_eye; \n\
4434vec4 raysum; \n\
4435void main(void) \n\
4436{ \n\
4437 debug_color = vec4(0.0); \n\
4438 float maxDist = length(fw_dimensions); //1.414214; //sqrt(2.0); \n\
4439 int numSamples = 128; \n\
4440 float fnumSamples = float(numSamples); \n\
4441 float stepSize = maxDist/fnumSamples; \n\
4442 float densityFactor = 5.0/fnumSamples; //.88; // 1.0=normal H3D, .5 see deeper \n\
4443 \n\
4444 vec4 fragment_color; \n\
4445 //vec4 raysum; \n\
4446 vec3 rayDirection; \n\
4447 //convert window to frustum \n\
4448 rayDirection.xy = 2.0 * (gl_FragCoord.xy - fw_viewport.xy) / fw_viewport.zw - vec2(1.0); \n\
4449 rayDirection.z = 0.0; \n\
4450 vec3 rayOrigin; // = fw_RayOrigin; \n\
4451 //the equivalent of gluUnproject \n\
4452 //by unprojecting 2 points on ray here, this should also work with ortho viewpoint \n\
4453 vec4 ray4 = vec4(rayDirection,1.0); \n\
4454 vec4 org4 = ray4; \n\
4455 //if I back up the ray origin by -1.0 the front plane clipping works properly \n\
4456 ray4.z = 0.0; //1.0; \n\
4457 org4.z = -1.0; //0.0; \n\
4458 ray4 = fw_ModelViewProjInverse * ray4; \n\
4459 org4 = fw_ModelViewProjInverse * org4; \n\
4460 ray4 /= ray4.w; \n\
4461 org4 /= org4.w; \n\
4462 rayDirection = normalize(ray4.xyz - org4.xyz); \n\
4463 rayOrigin = org4.xyz; \n\
4464 \n\
4465 Ray eye = Ray( rayOrigin, rayDirection); \n\
4466 vec3 half_dimensions = fw_dimensions * .5; \n\
4467 vec3 minus_half_dimensions = half_dimensions * -1.0; \n\
4468 AABB aabb = AABB(minus_half_dimensions,half_dimensions); \n\
4469 \n\
4470 float tnear, tfar; \n\
4471 IntersectBox(eye, aabb, tnear, tfar); \n\
4472 if (tnear < 0.0) tnear = 0.0; \n\
4473 vec3 rayStart = eye.Origin + eye.Dir * tnear; \n\
4474 vec3 rayStop = eye.Origin + eye.Dir * tfar; \n\
4475 // Perform the ray marching: \n\
4476 vec3 pos = rayStart; \n\
4477 vec3 step = normalize(rayStop-rayStart) * stepSize; \n\
4478 float totaltravel = distance(rayStop, rayStart); \n\
4479 float travel = totaltravel; \n\
4480 float T = 1.0; \n\
4481 vec3 Lo = vec3(0.0); \n\
4482 normal_eye = rayDirection; \n\
4483 vec3 pos2 = pos; \n\
4484 // Transform from object space to texture coordinate space: \n\
4485 pos2 = (pos2+half_dimensions)/fw_dimensions; \n\
4486 pos2 = clamp(pos2,0.001,.999); \n\
4487 raysum = vec4(0.0); \n\
4488 float depth = 0.0; \n\
4489 float lastdensity; \n\
4490 float lastdensity_iso; \n\
4491 \n\
4492 for (int i=0; i < numSamples; ++i) { \n\
4493 //raysum = HeatMapColor(travel,0.0,2.0); \n\
4494 //break; \n\
4495 // ...lighting and absorption stuff here... \n\
4496 pos2 = pos; \n\
4497 vertex_eye = pos2; \n\
4498 // Transform from object space to texture coordinate space: \n\
4499 pos2 = (pos2+half_dimensions)/fw_dimensions; \n\
4500 //pos2.z = 1.0 - pos2.z; //RHS to LHS \n\
4501 pos2 = clamp(pos2,0.001,.999); \n\
4502 vec3 texcoord3 = pos2; \n\
4503 bool iclip = false; \n\
4504 #ifdef CLIP \n\
4505 iclip = clip(vertex_eye); //clip(totaltravel - travel); \n\
4506 #endif //CLIP \n\
4507 if(!iclip) { \n\
4508 fragment_color = vec4(1.0,0.0,1.0,1.0); //do I need a default? seems not \n\
4509 /* UNP_LUG: texture3D ( fragment_color, texcoord3) */ \n\
4510 fragment_color = texture3Demu0( fw_Texture_unit0, texcoord3, magFilter); \n\
4511 #ifdef SEGMENT \n\
4512 int jstyle = 1; \n\
4513 if(inEnabledSegment(texcoord3,jstyle)){ \n\
4514 #endif //SEGMENT \n\
4515 //assuming we had a scalar input image and put L into .a, \n\
4516 // and computed gradient and put in .rgb : \n\
4517 float density = fragment_color.a; //recover the scalar value \n\
4518 vec3 gradient = fragment_color.rgb - vec3(.5,.5,.5); //we added 127 to (-127 to 127) in CPU gradient computation\n\
4519 if(fw_gradTexture == 1) { \n\
4520 float gradmag = texture3Demu0( fw_Texture_unit3, texcoord3, magFilter).a; \n\
4521 gradient = vec3(gradmag,gradmag,gradmag); \n\
4522 } \n\
4523 if(fw_gradTexture == 3){ \n\
4524 gradient = texture3Demu0( fw_Texture_unit3, texcoord3, magFilter).xyz - vec3(.5,.5,.5); \n\
4525 } \n\
4526 //vec4 voxel = vec4(density,density,density,density); //this is where the black visual voxels come from\n\
4527 vec4 voxel = vec4(density,density,density,density); //this is where the black visual voxels come from\n\
4528 \n\
4529 #ifdef ISO \n\
4530 if(i==0){ \n\
4531 lastdensity = density; \n\
4532 lastdensity_iso = 0.0; \n\
4533 } \n\
4534 int MODE = fw_nVals == 1 ? 1 : 3; \n\
4535 MODE = fw_stepSize != 0.0 && MODE == 1 ? 2 : 1; \n\
4536 #ifdef ISO_MODE3 \n\
4537 if(MODE == 3){ \n\
4538 for(int i=0;i<fw_nVals;i++){ \n\
4539 float iso = fw_surfaceVals[i]; \n\
4540 if( sign( density - iso) != sign( lastdensity - iso) && length(gradient) > fw_tolerance ){ \n\
4541 voxel.a = 1.0; \n\
4542 int jstyle = min(i,fw_nStyles-1); \n\
4543 jstyle = fw_surfaceStyles[jstyle]; \n\
4544 if(jstyle == 1){ \n\
4545 /* PLUG: voxel_apply_DEFAULT (voxel, gradient) */ \n\
4546 } else if(jstyle == 2) { \n\
4547 /* PLUG: voxel_apply_OPACITY (voxel, gradient) */ \n\
4548 } else if(jstyle == 3) { \n\
4549 /* PLUG: voxel_apply_BLENDED (voxel, gradient) */ \n\
4550 } else if(jstyle == 4) { \n\
4551 /* PLUG: voxel_apply_BOUNDARY (voxel, gradient) */ \n\
4552 } else if(jstyle == 5) { \n\
4553 /* PLUG: voxel_apply_CARTOON (voxel, gradient) */ \n\
4554 } else if(jstyle == 6) { \n\
4555 /* PLUG: voxel_apply_DEFAULT (voxel, gradient) */ \n\
4556 } else if(jstyle == 7) { \n\
4557 /* PLUG: voxel_apply_EDGE (voxel, gradient) */ \n\
4558 } else if(jstyle == 8) { \n\
4559 /* PLUG: voxel_apply_PROJECTION (voxel, gradient) */ \n\
4560 } else if(jstyle == 9) { \n\
4561 /* PLUG: voxel_apply_SHADED (voxel, gradient) */ \n\
4562 } else if(jstyle == 10) { \n\
4563 /* PLUG: voxel_apply_SILHOUETTE (voxel, gradient) */ \n\
4564 } else if(jstyle == 11) { \n\
4565 /* PLUG: voxel_apply_TONE (voxel, gradient) */ \n\
4566 } \n\
4567 } else { \n\
4568 voxel = vec4(0.0); //similar to discard \n\
4569 } \n\
4570 } \n\
4571 lastdensity = density; \n\
4572 } \n\
4573 #else //ISO_MODE3 \n\
4574 if(MODE == 1){ \n\
4575 float iso = fw_surfaceVals[0]; \n\
4576 if( sign( density - iso) != sign( lastdensity - iso) && length(gradient) > fw_tolerance ){ \n\
4577 //debug_color = HeatMapColor(iso,0.0,.3); \n\
4578 voxel.a = 1.0; \n\
4579 /* PLUG: voxel_apply (voxel, gradient) */ \n\
4580 } else { \n\
4581 voxel = vec4(0.0); //similar to discard \n\
4582 } \n\
4583 lastdensity = density; \n\
4584 } else if(MODE == 2){ \n\
4585 float iso = fw_surfaceVals[0]; \n\
4586 float density_iso = density / fw_stepSize; \n\
4587 if( sign( density_iso - iso) != sign( lastdensity_iso - iso) && length(gradient) > fw_tolerance ){ \n\
4588 voxel.a = 1.0; \n\
4589 /* PLUG: voxel_apply (voxel, gradient) */ \n\
4590 } else { \n\
4591 voxel = vec4(0.0); //similar to discard \n\
4592 } \n\
4593 lastdensity = density; \n\
4594 lastdensity_iso = density_iso; \n\
4595 } \n\
4596 #endif //ISO_MODE3 \n\
4597 #else //ISO \n\
4598 #ifdef SEGMENT \n\
4599 //debug_color = HeatMapColor(float(jstyle),1.0,12.0); \n\
4600 //debug_color.a = .2; \n\
4601 if(jstyle == 1){ \n\
4602 /* PLUG: voxel_apply_DEFAULT (voxel, gradient) */ \n\
4603 } else if(jstyle == 2) { \n\
4604 /* PLUG: voxel_apply_OPACITY (voxel, gradient) */ \n\
4605 } else if(jstyle == 3) { \n\
4606 /* PLUG: voxel_apply_BLENDED (voxel, gradient) */ \n\
4607 } else if(jstyle == 4) { \n\
4608 /* PLUG: voxel_apply_BOUNDARY (voxel, gradient) */ \n\
4609 } else if(jstyle == 5) { \n\
4610 /* PLUG: voxel_apply_CARTOON (voxel, gradient) */ \n\
4611 } else if(jstyle == 6) { \n\
4612 /* PLUG: voxel_apply_DEFAULT (voxel, gradient) */ \n\
4613 } else if(jstyle == 7) { \n\
4614 /* PLUG: voxel_apply_EDGE (voxel, gradient) */ \n\
4615 } else if(jstyle == 8) { \n\
4616 /* PLUG: voxel_apply_PROJECTION (voxel, gradient) */ \n\
4617 } else if(jstyle == 9) { \n\
4618 /* PLUG: voxel_apply_SHADED (voxel, gradient) */ \n\
4619 } else if(jstyle == 10) { \n\
4620 /* PLUG: voxel_apply_SILHOUETTE (voxel, gradient) */ \n\
4621 } else if(jstyle == 11) { \n\
4622 /* PLUG: voxel_apply_TONE (voxel, gradient) */ \n\
4623 } \n\
4624 #else //SEGMENT \n\
4625 //non-iso rendering styles \n\
4626 //void PLUG_voxel_apply (inout vec4 voxel, inout vec3 gradient) \n\
4627 /* PLUG: voxel_apply (voxel, gradient) */ \n\
4628 #endif //SEGMENT \n\
4629 #endif //ISO \n\
4630 density = voxel.a; \n\
4631 //debug_color = HeatMapColor(densityFactor,0.134,.135); \n\
4632 T = (1.0 - raysum.a); \n\
4633 raysum.a += density * T; \n\
4634 raysum.rgb += voxel.rgb * T * density; \n\
4635 if(raysum.a > .99) { \n\
4636 break; \n\
4637 } \n\
4638 #ifdef SEGMENT \n\
4639 } //if inEnabledSegment \n\
4640 #endif //SEGMENT \n\
4641 } //iclip \n\
4642 travel -= stepSize; \n\
4643 depth += stepSize; \n\
4644 if(travel <= 0.0) break; \n\
4645 pos += step; \n\
4646 \n\
4647 } \n\
4648 //void PLUG_ray_apply (inout vec4 raysum) \n\
4649 /* PLUG: ray_apply (raysum) */ \n\
4650 if(true) FragColor = raysum; \n\
4651 else FragColor = debug_color; \n\
4652} \n\
4653";
4654
4655
4656//void PLUG_voxel_apply (inout vec4 voxel, inout vec3 gradient) {
4657
4658// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#OpacityMapVolumeStyle
4659// opacity with intensity == intensity lookup/transferFunction
4660
4661static const GLchar *plug_voxel_DEFAULT = "\
4662void voxel_apply_DEFAULT (inout vec4 voxel, inout vec3 gradient) { \n\
4663 float alpha = voxel.a; \n\
4664 //voxel.a = voxel.r; \n\
4665 //voxel.rgb = vec3(alpha); \n\
4666} \n\
4667void PLUG_voxel_apply_DEFAULT (inout vec4 voxel, inout vec3 gradient) { \n\
4668 voxel_apply_DEFAULT(voxel,gradient); \n\
4669} \n\
4670void PLUG_voxel_apply (inout vec4 voxel, inout vec3 gradient) { \n\
4671 voxel_apply_DEFAULT(voxel,gradient); \n\
4672} \n\
4673";
4674
4675// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#OpacityMapVolumeStyle
4676static const GLchar *plug_voxel_OPACITY = "\
4677uniform int fw_opacTexture; \n\
4678//uniform sampler2D fw_Texture_unit3; \n\
4679void voxel_apply_OPACITY (inout vec4 voxel, inout vec3 gradient) { \n\
4680 if(fw_opacTexture == 1){ \n\
4681 vec4 lookup_color; \n\
4682 float lum = voxel.r; \n\
4683 vec2 texcoord = vec2(lum,0.0); \n\
4684 //this is too simple for the lookups in the specs \n\
4685 //http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#t-transferFunctionTextureCoordinateMapping \n\
4686 lookup_color = texture2D(fw_Texture_unit3,texcoord); \n\
4687 voxel.rgb = lookup_color.rgb; \n\
4688 voxel.a = lum; \n\
4689 }else{ \n\
4690 //like default \n\
4691 float alpha = voxel.a; \n\
4692 voxel.a = voxel.r; \n\
4693 voxel.rgb = vec3(alpha); \n\
4694 } \n\
4695} \n\
4696void PLUG_voxel_apply_OPACITY (inout vec4 voxel, inout vec3 gradient) { \n\
4697 voxel_apply_OPACITY(voxel, gradient); \n\
4698} \n\
4699void PLUG_voxel_apply (inout vec4 voxel, inout vec3 gradient) { \n\
4700 voxel_apply_OPACITY(voxel, gradient); \n\
4701} \n\
4702";
4703
4704// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#BlendedVolumeStyle
4705static const GLchar *plug_voxel_BLENDED = "\
4706void PLUG_voxel_apply (inout vec4 voxel, inout vec3 gradient) { \n\
4707} \n\
4708";
4709
4710// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#BoundaryEnhancementVolumeStyle
4711static const GLchar *plug_voxel_BOUNDARY = "\n\
4712uniform float fw_boundaryOpacity; \n\
4713uniform float fw_retainedOpacity; \n\
4714uniform float fw_opacityFactor; \n\
4715void voxel_apply_BOUNDARY (inout vec4 voxel, inout vec3 gradient) { \n\
4716 float magnitude = length(gradient); \n\
4717 float factor = (fw_retainedOpacity + fw_boundaryOpacity*pow(magnitude,fw_opacityFactor) ); \n\
4718 voxel.a = voxel.a * factor; \n\
4719 //debug_color = HeatMapColor(factor,0.0,1.0); \n\
4720} \n\
4721void PLUG_voxel_apply_BOUNDARY (inout vec4 voxel, inout vec3 gradient) { \n\
4722 voxel_apply_BOUNDARY(voxel, gradient); \n\
4723} \n\
4724void PLUG_voxel_apply (inout vec4 voxel, inout vec3 gradient) { \n\
4725 voxel_apply_BOUNDARY(voxel, gradient); \n\
4726} \n\
4727";
4728
4729// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#CartoonVolumeStyle
4730static const GLchar *plug_voxel_CARTOON = "\n\
4731uniform int fw_colorSteps; \n\
4732uniform vec4 fw_orthoColor; \n\
4733uniform vec4 fw_paraColor; \n\
4734void voxel_apply_CARTOON (inout vec4 voxel, inout vec3 gradient) { \n\
4735 float len = length(gradient); \n\
4736 if(len > 0.01) { \n\
4737 vec3 ng = normalize(gradient); \n\
4738 float ndotv = dot(normal_eye,ng); \n\
4739 if(ndotv > 0.01 && voxel.a > 0.0) { \n\
4740 ndotv = floor(ndotv/float(fw_colorSteps))*float(fw_colorSteps); \n\
4741 vec4 color = mix(fw_orthoColor,fw_paraColor,ndotv); \n\
4742 //voxel.rgb = color.rgb*voxel.a; \n\
4743 voxel.rgb = color.rgb; \n\
4744 } else { \n\
4745 voxel = vec4(0.0); //similar to discard \n\
4746 } \n\
4747 } else { \n\
4748 voxel = vec4(0.0); //similar to discard \n\
4749 } \n\
4750} \n\
4751void PLUG_voxel_apply_CARTOON (inout vec4 voxel, inout vec3 gradient) { \n\
4752 voxel_apply_CARTOON(voxel, gradient); \n\
4753} \n\
4754void PLUG_voxel_apply (inout vec4 voxel, inout vec3 gradient) { \n\
4755 voxel_apply_CARTOON(voxel, gradient); \n\
4756} \n\
4757";
4758
4759// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#ComposedVolumeStyle
4760static const GLchar *plug_voxel_COMPOSED = "\
4761void PLUG_voxel_apply (inout vec4 voxel, inout vec3 gradient) { \n\
4762} \n\
4763";
4764
4765// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#EdgeEnhancementVolumeStyle
4766static const GLchar *plug_voxel_EDGE = "\
4767uniform float fw_cosGradientThreshold; \n\
4768uniform vec4 fw_edgeColor; \n\
4769void voxel_apply_EDGE (inout vec4 voxel, inout vec3 gradient) { \n\
4770 float len = length(gradient); \n\
4771 if(len > 0.01) { \n\
4772 vec3 ng = normalize(gradient); \n\
4773 float ndotv = abs(dot(normal_eye,ng)); \n\
4774 if( ndotv < fw_cosGradientThreshold ) { \n\
4775 voxel = mix(voxel,fw_edgeColor,1.0 -ndotv); \n\
4776 } \n\
4777 } \n\
4778} \n\
4779void PLUG_voxel_apply_EDGE (inout vec4 voxel, inout vec3 gradient) { \n\
4780 voxel_apply_EDGE(voxel, gradient); \n\
4781} \n\
4782void PLUG_voxel_apply (inout vec4 voxel, inout vec3 gradient) { \n\
4783 voxel_apply_EDGE(voxel, gradient); \n\
4784} \n\
4785";
4786
4787// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#ProjectionVolumeStyle
4788static const GLchar *plug_voxel_PROJECTION = "\n\
4789uniform float fw_intensityThreshold; \n\
4790uniform int fw_projType; \n\
4791float MAXPROJ = 0.0; \n\
4792float MINPROJ = 1.0; \n\
4793float AVEPROJ = 0.0; \n\
4794float LMIP = 0.0; \n\
4795vec4 RGBAPROJ; \n\
4796int PROJCOUNT = 0; \n\
4797void voxel_apply_PROJECTION (inout vec4 voxel, inout vec3 gradient) { \n\
4798 PROJCOUNT++; \n\
4799 float cval = length(voxel.rgb); \n\
4800 if(fw_projType == 1){ \n\
4801 //MIN \n\
4802 if(cval < MINPROJ){ \n\
4803 MINPROJ = cval; \n\
4804 RGBAPROJ = voxel; \n\
4805 } \n\
4806 }else if(fw_projType == 2){ \n\
4807 //MAX \n\
4808 if(fw_intensityThreshold > 0.0){ \n\
4809 //LMIP \n\
4810 if(LMIP == 0.0) { \n\
4811 LMIP = cval; \n\
4812 RGBAPROJ = voxel; \n\
4813 } \n\
4814 } else { \n\
4815 //MIP \n\
4816 if(cval > MAXPROJ){ \n\
4817 MAXPROJ = cval; \n\
4818 RGBAPROJ = voxel; \n\
4819 } \n\
4820 } \n\
4821 }else if(fw_projType==3){ \n\
4822 //AVERAGE \n\
4823 AVEPROJ += cval; \n\
4824 RGBAPROJ += voxel; \n\
4825 } \n\
4826} \n\
4827void PLUG_voxel_apply_PROJECTION (inout vec4 voxel, inout vec3 gradient) { \n\
4828 voxel_apply_PROJECTION(voxel, gradient); \n\
4829} \n\
4830void PLUG_voxel_apply (inout vec4 voxel, inout vec3 gradient) { \n\
4831 voxel_apply_PROJECTION(voxel, gradient); \n\
4832} \n\
4833void PLUG_ray_apply (inout vec4 raysum) { \n\
4834 float value = 0.0; \n\
4835 vec4 color = vec4(1.0); \n\
4836 if(fw_projType == 1){ \n\
4837 //MIN \n\
4838 value = MINPROJ; \n\
4839 color = RGBAPROJ; \n\
4840 }else if(fw_projType == 2){ \n\
4841 //MAX \n\
4842 if(fw_intensityThreshold > 0.0){ \n\
4843 //LMIP \n\
4844 value = LMIP; \n\
4845 color = RGBAPROJ; \n\
4846 } else { \n\
4847 //MIP \n\
4848 value = MAXPROJ; \n\
4849 color = RGBAPROJ; \n\
4850 } \n\
4851 }else if(fw_projType==3){ \n\
4852 //AVERAGE \n\
4853 value = AVEPROJ / float(PROJCOUNT); \n\
4854 color = RGBAPROJ / float(PROJCOUNT); \n\
4855 } \n\
4856 //raysum.rgb = color.rgb * color.a; \n\
4857 //raysum.a = color.a; \n\
4858 \n\
4859 raysum.rgb = vec3(value,value,value); \n\
4860// raysum.a = 1.0 - value; \n\
4861 //raysum.a = value;\n\
4862 //raysum.a = color.a; \n\
4863 //raysum = color; \n\
4864} \n\
4865";
4866
4867// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#ShadedVolumeStyle
4868static const GLchar *plug_voxel_SHADED = "\
4869#ifdef LITE \n\
4870#define MAX_LIGHTS 8 \n\
4871uniform int lightcount; \n\
4872//uniform float lightRadius[MAX_LIGHTS]; \n\
4873uniform int lightType[MAX_LIGHTS];//ANGLE like this \n\
4874struct fw_LightSourceParameters { \n\
4875 float ambient; \n\
4876 vec3 color; \n\
4877 float intensity; \n\
4878 vec3 location; \n\
4879 vec3 halfVector; \n\
4880 vec3 direction; \n\
4881 float spotBeamWidth; \n\
4882 float spotCutoff; \n\
4883 vec3 Attenuations; \n\
4884 float lightRadius; \n\
4885 bool shadows; \n\
4886 float shadowIntensity; \n\
4887 int depthmap; \n\
4888}; \n\
4889\n\
4890uniform fw_LightSourceParameters fw_LightSource[MAX_LIGHTS] /* gl_MaxLights */ ;\n\
4891#endif //LITE \n\
4892 \n\
4893#ifdef FOG \n\
4894struct fogParams \n\
4895{ \n\
4896 vec4 fogColor; \n\
4897 float visibilityRange; \n\
4898 float fogScale; \n\
4899 int fogType; // 0 None, 1= FOGTYPE_LINEAR, 2 = FOGTYPE_EXPONENTIAL \n\
4900 // ifdefed int haveFogCoords; \n\
4901}; \n\
4902uniform fogParams fw_fogparams; \n\
4903#endif //FOG \n\
4904#ifdef LIT \n\
4905#ifdef LITE \n\
4906//per-fragment lighting ie phong \n\
4907struct fw_MaterialParameters { \n\
4908 vec3 diffuse; \n\
4909 vec3 emissive; \n\
4910 vec3 specular; \n\
4911 float ambient; \n\
4912 float shininess; \n\
4913 float occlusion; \n\
4914 float transparency; \n\
4915 vec3 baseColor; \n\
4916 float metallic; \n\
4917 float roughness; \n\
4918 int type; \n\
4919 // multitextures are disaggregated \n\
4920 int tindex[10]; \n\
4921 int mode[10]; \n\
4922 int source[10]; \n\
4923 int func[10]; \n\
4924 int samplr[10]; //0 texture2D 1 cubeMap \n\
4925 int cmap[10]; \n\
4926 int nt; //total single textures \n\
4927 //iunit [0] normal [1] emissive [2] occlusion [3] diffuse OR base [4] shininess OR metallicRoughness [5] specular [6] ambient \n\
4928 int tcount[7]; //num single textures 1= one texture 0=no texture 2+ = multitexture \n\
4929 int tstart[7]; // where in packed tindex list to start looping \n\
4930 //int cindex[7]; // which geometry multitexcoord channel 0=default \n\
4931}; \n\
4932uniform fw_MaterialParameters fw_FrontMaterial; \n\
4933//#ifdef TWO \n\
4934uniform fw_MaterialParameters fw_BackMaterial; \n\
4935//#endif //TWO \n\
4936vec3 castle_ColorES; \n\
4937#else //LITE \n\
4938//per-vertex lighting - interpolated Emissive-specular \n\
4939varying vec3 castle_ColorES; //emissive shininess term \n\
4940#endif //LITE \n\
4941#endif //LIT\n\
4942uniform int fw_phase; \n\
4943uniform int fw_lighting; \n\
4944uniform int fw_shadows; \n\
4945void voxel_apply_SHADED (inout vec4 voxel, inout vec3 gradient) { \n\
4946 float len = length(gradient); \n\
4947 vec3 ng = vec3(0.0); \n\
4948 if(len > 0.0) \n\
4949 ng = normalize(gradient); \n\
4950 vec3 color = vec3(1.0); \n\
4951 #ifdef LIT \n\
4952 vec3 castle_ColorES = fw_FrontMaterial.specular; \n\
4953 color.rgb = fw_FrontMaterial.diffuse.rgb; \n\
4954 #else //LIT \n\
4955 color.rgb = vec3(0,0,0.0,0.0); \n\
4956 vec3 castle_ColorES = vec3(0.0,0.0,0.0); \n\
4957 #endif //LIT \n\
4958 // void add_light_contribution2(inout vec3 vertexcolor, inout vec3 specularcolor, in vec4 myPosition, in vec3 myNormal, \n\
4959 // in float mat_shininess, in float mat_ambient, in vec3 mat_diffuse, in vec3 mat_specular); \n\
4960 vec4 vertex_eye4 = vec4(vertex_eye,1.0); \n\
4961 /* PLUG: add_light_contribution2 (color, castle_ColorES, vertex_eye4, ng, fw_FrontMaterial.shininess, fw_FrontMaterial.ambient, fw_FrontMaterial.diffuse, fw_FrontMaterial.specular) */ \n\
4962 // voxel.rgb = color.rgb; \n\
4963 color = mix(color,castle_ColorES,dot(ng,normal_eye)); \n\
4964 voxel.rgb = color.rgb; \n\
4965 //voxel.rgb = voxel.rgb * color.rgb; \n\
4966} \n\
4967void PLUG_voxel_apply_SHADED (inout vec4 voxel, inout vec3 gradient) { \n\
4968 voxel_apply_SHADED(voxel, gradient); \n\
4969} \n\
4970void PLUG_voxel_apply (inout vec4 voxel, inout vec3 gradient) { \n\
4971 voxel_apply_SHADED(voxel, gradient); \n\
4972} \n\
4973";
4974
4975// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#SilhouetteEnhancementVolumeStyle
4976static const GLchar *plug_voxel_SILHOUETTE = "\n\
4977uniform float fw_BoundaryOpacity; \n\
4978uniform float fw_RetainedOpacity; \n\
4979uniform float fw_Sharpness; \n\
4980void voxel_apply_SILHOUETTE (inout vec4 voxel, inout vec3 gradient) { \n\
4981 float len = length(gradient); \n\
4982 if(len > 0.01) { \n\
4983 vec3 ng = normalize(gradient); \n\
4984 float ndotv = abs(dot(ng,normal_eye)); \n\
4985 float factor = (fw_RetainedOpacity + fw_BoundaryOpacity*pow(1.0 - ndotv,fw_Sharpness)); \n\
4986 //float factor = (fw_RetainedOpacity + pow(fw_BoundaryOpacity*(1.0 - ndotv),fw_Sharpness)); \n\
4987 //debug_color = HeatMapColor(factor,0.0,1.0); \n\
4988 voxel.a = voxel.a * factor; \n\
4989 } \n\
4990} \n\
4991void PLUG_voxel_apply_SILHOUETTE (inout vec4 voxel, inout vec3 gradient) { \n\
4992 voxel_apply_SILHOUETTE(voxel, gradient); \n\
4993} \n\
4994void PLUG_voxel_apply (inout vec4 voxel, inout vec3 gradient) { \n\
4995 voxel_apply_SILHOUETTE(voxel, gradient); \n\
4996} \n\
4997";
4998
4999// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#ToneMappedVolumeStyle
5000static const GLchar *plug_voxel_TONE = "\
5001uniform vec4 fw_coolColor; \n\
5002uniform vec4 fw_warmColor; \n\
5003void voxel_apply_TONE (inout vec4 voxel, inout vec3 gradient) { \n\
5004 float len = length(gradient); \n\
5005 if(len > 0.0) { \n\
5006 vec3 color; \n\
5007 vec3 ng = normalize(gradient); \n\
5008 //vec3 L = normalize(vec3(-.707,-.707,.707)); \n\
5009 float cc = (1.0 + dot(normal_eye,ng))*.5; \n\
5010 //float cc = (1.0 + dot(L,ng))*.5; \n\
5011 //debug_color = HeatMapColor(cc,0.0,1.0); \n\
5012 color = mix(fw_coolColor.rgb,fw_warmColor.rgb,cc); \n\
5013 voxel = vec4(color,voxel.a); \n\
5014 } else { \n\
5015 voxel.a = 0.0; \n\
5016 //debug_color = vec4(0.0); \n\
5017 } \n\
5018} \n\
5019void PLUG_voxel_apply_TONE (inout vec4 voxel, inout vec3 gradient) { \n\
5020 voxel_apply_TONE(voxel, gradient); \n\
5021} \n\
5022void PLUG_voxel_apply (inout vec4 voxel, inout vec3 gradient) { \n\
5023 voxel_apply_TONE(voxel, gradient); \n\
5024} \n\
5025";
5026
5027// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/volume.html#BlendedVolumeStyle
5028// blended (BlendedVolumeStyle) works (was interpreted and implemented by dug9, Oct 2016)
5029// by rendering 2 volumedatas to 2 fbo textures, then running
5030// this shader to blend the 2 fbo textures and spit out fragments just
5031// where the box is. Use with the regular volume Vertex shader so
5032// only frags over the box show, and so we get box depth for depth blending
5033// with the main scene
5034static const GLchar *volumeBlendedFragmentGLES2 = " \n\
5035/* DEFINES */ \n\
5036#ifdef MOBILE \n\
5037//precision highp float; \n\
5038precision mediump float; \n\
5039#endif //MOBILE \n\
5040#define varying in \n\
5041#define texture2D texture \n\
5042#define texture3D texture \n\
5043#define textureCube texture \n\
5044#define texture2DProj textureProj \n\
5045#define texture3DProj textureProj \n\
5046out vec4 FragColor; \n\
5047 vec4 HeatMapColor(float value, float minValue, float maxValue) \n\
5048{ \n\
5049 //used for debugging. If min=0,max=1 then magenta is 0, blue,green,yellow, red is 1 \n\
5050 vec4 ret; \n\
5051 int HEATMAP_COLORS_COUNT; \n\
5052 vec4 colors[6]; \n\
5053 HEATMAP_COLORS_COUNT = 6; \n\
5054 colors[0] = vec4(0.32, 0.00, 0.32, 1.0); \n\
5055 colors[1] = vec4( 0.00, 0.00, 1.00, 1.00); \n\
5056 colors[2] = vec4(0.00, 1.00, 0.00, 1.00); \n\
5057 colors[3] = vec4(1.00, 1.00, 0.00, 1.00); \n\
5058 colors[4] = vec4(1.00, 0.60, 0.00, 1.00); \n\
5059 colors[5] = vec4(1.00, 0.00, 0.00, 1.00); \n\
5060 float ratio=(float(HEATMAP_COLORS_COUNT)-1.0)*clamp((value-minValue)/(maxValue-minValue),0.0,1.0); \n\
5061 int indexMin=int(floor(ratio)); \n\
5062 int indexMax= indexMin+1 < HEATMAP_COLORS_COUNT-1 ? indexMin+1 : HEATMAP_COLORS_COUNT-1; \n\
5063 ret = mix(colors[indexMin], colors[indexMax], ratio-float(indexMin)); \n\
5064 if(value < minValue) ret = vec4(0.0,0.0,0.0,1.0); \n\
5065 if(value > maxValue) ret = vec4(1.0,1.0,1.0,1.0); \n\
5066 return ret; \n\
5067} \n\
5068vec4 debug_color; \n\
5069 \n\
5070uniform vec4 fw_viewport; \n\
5071uniform sampler2D fw_Texture_unit0; \n\
5072uniform sampler2D fw_Texture_unit1; \n\
5073uniform sampler2D fw_Texture_unit2; \n\
5074uniform sampler2D fw_Texture_unit3; \n\
5075uniform float fw_iwtc1; \n\
5076uniform float fw_iwtc2; \n\
5077uniform int fw_iwtf1; \n\
5078uniform int fw_iwtf2; \n\
5079uniform int fw_haveTransfers; \n\
5080vec3 weightcolor( in vec3 color, in int func, in float wt, in float ov, in float oblend, in sampler2D table){ \n\
5081 vec3 ret; \n\
5082 if(func == 1){ \n\
5083 ret = color * wt; \n\
5084 }else if(func == 2){ \n\
5085 ret = color * ov; \n\
5086 }else if(func == 3){ \n\
5087 ret = color * oblend; \n\
5088 }else if(func == 4){ \n\
5089 ret = color * (1.0 - oblend); \n\
5090 }else if(func == 5){ \n\
5091 vec2 texcoord = color.rg;\n\
5092 ret = color * texture2D(table,texcoord).r; \n\
5093 } \n\
5094 return ret; \n\
5095} \n\
5096float weightalpha( in float alpha, in int func, in float wt, in float ov, in float oblend, in sampler2D table){ \n\
5097 float ret; \n\
5098 if(func == 1){ \n\
5099 ret = alpha * wt; \n\
5100 }else if(func == 2){ \n\
5101 ret = alpha * ov; \n\
5102 }else if(func == 3){ \n\
5103 ret = alpha * oblend; \n\
5104 }else if(func == 4){ \n\
5105 ret = alpha * (1.0 - oblend); \n\
5106 }else if(func == 5){ \n\
5107 vec2 texcoord = vec2(alpha,0);\n\
5108 ret = alpha * texture2D(table,texcoord).r; \n\
5109 } \n\
5110 return ret; \n\
5111} \n\
5112void main(void) \n\
5113{ \n\
5114 vec2 fc = (gl_FragCoord.xy - fw_viewport.xy) / fw_viewport.zw; \n\
5115 vec4 frag0 = texture2D(fw_Texture_unit0,fc); \n\
5116 vec4 frag1 = texture2D(fw_Texture_unit1,fc); \n\
5117 vec3 cv = frag0.rgb; \n\
5118 float ov = frag0.a; \n\
5119 vec3 cblend = frag1.rgb; \n\
5120 float oblend = frag1.a; \n\
5121 vec3 cvw, cbw; \n\
5122 float ovw, obw; \n\
5123 cvw = weightcolor(cv,fw_iwtf1,fw_iwtc1,ov,oblend,fw_Texture_unit2); \n\
5124 ovw = weightalpha(ov,fw_iwtf1,fw_iwtc1,ov,oblend,fw_Texture_unit2); \n\
5125 cbw = weightcolor(cblend,fw_iwtf2,fw_iwtc2,ov,oblend,fw_Texture_unit3); \n\
5126 obw = weightalpha(oblend,fw_iwtf2,fw_iwtc2,ov,oblend,fw_Texture_unit3); \n\
5127 vec3 cg = clamp( cvw + cbw, 0.0, 1.0); \n\
5128 float og = clamp(ovw + obw, 0.0, 1.0); \n\
5129 \n\
5130 FragColor = vec4(cg,og); \n\
5131} \n\
5132";
5133
5134
5135const char *getVolumeVertex(void){
5136 return volumeVertexGLES2; //genericVertexDesktop
5137}
5138const char *getVolumeFragment(){
5139 return volumeFragmentGLES2; //genericFragmentDesktop;
5140}
5141int getSpecificShaderSourceVolume (const GLchar **vertexSource, const GLchar **fragmentSource, shaderflagsstruct whichOne)
5142{
5143 //for building the Builtin (similar to fixed-function pipeline, except from shader parts)
5144 //in OpenGL_Utils.c L.2553 set usingCastlePlugs = 1 to get in here.
5145 //whichone - a bitmask of shader requirements, one bit for each requirement, so shader permutation can be built
5146
5147 int retval, unique_int;
5148 unsigned int volflags;
5149 unsigned char volflag[7];
5150 int kflags,i,k;
5151 char *CompleteCode[3];
5152 char *vs, *fs;
5153 retval = FALSE;
5154 if(whichOne.usershaders ) //& USER_DEFINED_SHADER_MASK)
5155 return retval; //not supported yet as of Aug 9, 2016
5156 retval = TRUE;
5157
5158 //generic
5159 vs = strdup(getVolumeVertex());
5160 fs = strdup(getVolumeFragment());
5161
5162 CompleteCode[SHADERPART_VERTEX] = vs;
5163 CompleteCode[SHADERPART_GEOMETRY] = NULL;
5164 if(whichOne.volume == SHADERFLAGS_VOLUME_STYLE_BLENDED << 4){
5165 CompleteCode[SHADERPART_FRAGMENT] = STRDUP(volumeBlendedFragmentGLES2);
5166
5167 }else{
5168 CompleteCode[SHADERPART_FRAGMENT] = fs;
5169 }
5170
5171 // what we really have here: UberShader with CastlePlugs
5172 // UberShader: one giant shader peppered with #ifdefs, and you add #defines at the top for permutations
5173 // CastlePlugs: allows users to add effects on to uberShader with PLUGs
5174 // - and internally, we can do a few permutations with PLUGs too
5175 if (!GLSL_max_version) {
5176 //const GLubyte * glsl_version_str = glGetString ( GL_SHADING_LANGUAGE_VERSION);
5177 //sscanf(glsl_version_str,"%f",&glsl_version);
5178 //max_shader_version = (int)(glsl_version * 100.0f + .4f);
5179 //printf("GLSL shader version support %s %4.2f %d\n", glsl_version_str, glsl_version, max_shader_version );
5180 //once = TRUE;
5181 GLSL_max_version = get_GLSL_max_version();
5182 }
5183
5184 if (isMobile) {
5185 int iver = 100;
5186 char* aver = "";
5187 // https://en.wikipedia.org/wiki/OpenGL_Shading_Language#Versions
5188 // 100 300 es 310 es 410 es
5189 // iver = 320;
5190 // aver = "es";
5191 AddVersion0(SHADERPART_VERTEX, iver, aver, CompleteCode); //lower precision floats
5192 AddVersion0(SHADERPART_FRAGMENT, iver, aver, CompleteCode); //lower precision floats
5193 AddDefine(SHADERPART_FRAGMENT, "MOBILE", CompleteCode); //lower precision floats
5194 }
5195 else {
5196 if (GLSL_max_version >= 130) {
5197 int iver = 130; //testing for shader being able to run on low capability machines elsewhere
5198 //https://en.wikipedia.org/wiki/OpenGL_Shading_Language#Versions
5199 // 110 120 130 140 150 330 400 410 420 430 440 450 460
5200 // May 1, 2022 volume rendering did not render with iver latest, but rendered with 130
5201 iver = GLSL_max_version; //for maximizing capabilities
5202 //iver = 400;
5203 AddVersion(SHADERPART_VERTEX, iver, CompleteCode); //lower precision floats
5204 AddVersion(SHADERPART_FRAGMENT, iver, CompleteCode); //lower precision floats
5205 AddDefine(SHADERPART_VERTEX, "FULL", CompleteCode); //lower precision floats
5206 AddDefine(SHADERPART_FRAGMENT, "FULL", CompleteCode); //lower precision floats
5207 }
5208 else {
5209 AddVersion(SHADERPART_VERTEX, GLSL_max_version, CompleteCode); //lower precision floats
5210 AddVersion(SHADERPART_FRAGMENT, GLSL_max_version, CompleteCode); //lower precision floats
5211 }
5212 }
5213
5214 if(whichOne.volume == SHADERFLAGS_VOLUME_STYLE_BLENDED << 4){
5215 *fragmentSource = CompleteCode[SHADERPART_FRAGMENT]; //original_fragment; //fs;
5216 *vertexSource = CompleteCode[SHADERPART_VERTEX]; //original_vertex; //vs;
5217 return retval;
5218 }
5219
5220 unique_int = 0; //helps generate method name PLUG_xxx_<unique_int> to avoid clash when multiple PLUGs supplied for same PLUG
5221
5222 //if(DESIRE(whichOne.volume,TEX3D_SHADER)){
5223 AddDefine(SHADERPART_FRAGMENT,"TEX3D",CompleteCode);
5224 Plug(SHADERPART_FRAGMENT,plug_fragment_texture3D_apply_volume,CompleteCode,&unique_int); //uses TILED
5225 //}
5226
5227 if(DESIRE(whichOne.volume,SHADERFLAGS_VOLUME_DATA_BASIC)){
5228 AddDefine(SHADERPART_FRAGMENT,"BASIC",CompleteCode);
5229 }
5230 if(DESIRE(whichOne.volume,SHADERFLAGS_VOLUME_DATA_ISO)){
5231 AddDefine(SHADERPART_FRAGMENT,"ISO",CompleteCode);
5232 if(DESIRE(whichOne.volume,SHADERFLAGS_VOLUME_DATA_ISO_MODE3)){
5233 AddDefine(SHADERPART_FRAGMENT,"ISO_MODE3",CompleteCode);
5234 }
5235 }
5236 if(DESIRE(whichOne.volume,SHADERFLAGS_VOLUME_DATA_SEGMENT)){
5237 AddDefine(SHADERPART_FRAGMENT,"SEGMENT",CompleteCode);
5238 }
5239 if(DESIRE(whichOne.base,CLIPPLANE_SHADER)){
5240 AddDefine(SHADERPART_FRAGMENT,"CLIP",CompleteCode);
5241 // we use a special function in frag for clip for volume
5242 }
5243
5244 //unsigned int 32 bits - 4 for basic, leaves 28/4 = max 7 styles
5245 //work from left to right (the order declared), skip any 0/null/empties
5246 volflags = whichOne.volume;
5247 // this was just here, but is defined above. volflag[7];
5248 kflags = 0;
5249 for(i=0;i<7;i++){
5250 int iflag = (volflags >> (7-i)*4) & 0xF;
5251 if(iflag){
5252 volflag[kflags] = iflag;
5253 kflags++;
5254 }
5255 }
5256 //now volflag[] is in the order declared with no 0s/nulls
5257 for(k=0;k<kflags;k++){
5258 switch(volflag[k]){
5259 case SHADERFLAGS_VOLUME_STYLE_DEFAULT:
5260 AddDefine(SHADERPART_FRAGMENT,"DEFAULT",CompleteCode);
5261 Plug(SHADERPART_FRAGMENT,plug_voxel_DEFAULT,CompleteCode,&unique_int);
5262 break;
5263 case SHADERFLAGS_VOLUME_STYLE_OPACITY:
5264 AddDefine(SHADERPART_FRAGMENT,"OPACITY",CompleteCode);
5265 Plug(SHADERPART_FRAGMENT,plug_voxel_OPACITY,CompleteCode,&unique_int);
5266 break;
5267 case SHADERFLAGS_VOLUME_STYLE_BLENDED:
5268 AddDefine(SHADERPART_FRAGMENT,"BLENDED",CompleteCode);
5269 Plug(SHADERPART_FRAGMENT,plug_voxel_BLENDED,CompleteCode,&unique_int);
5270 break;
5271 case SHADERFLAGS_VOLUME_STYLE_BOUNDARY:
5272 AddDefine(SHADERPART_FRAGMENT,"BOUNDARY",CompleteCode);
5273 Plug(SHADERPART_FRAGMENT,plug_voxel_BOUNDARY,CompleteCode,&unique_int);
5274 break;
5275 case SHADERFLAGS_VOLUME_STYLE_CARTOON:
5276 AddDefine(SHADERPART_FRAGMENT,"CARTOON",CompleteCode);
5277 Plug(SHADERPART_FRAGMENT,plug_voxel_CARTOON,CompleteCode,&unique_int);
5278 break;
5279 case SHADERFLAGS_VOLUME_STYLE_COMPOSED:
5280 AddDefine(SHADERPART_FRAGMENT,"COMPOSED",CompleteCode);
5281 Plug(SHADERPART_FRAGMENT,plug_voxel_COMPOSED,CompleteCode,&unique_int);
5282 break;
5283 case SHADERFLAGS_VOLUME_STYLE_EDGE:
5284 AddDefine(SHADERPART_FRAGMENT,"EDGE",CompleteCode);
5285 Plug(SHADERPART_FRAGMENT,plug_voxel_EDGE,CompleteCode,&unique_int);
5286 break;
5287 case SHADERFLAGS_VOLUME_STYLE_PROJECTION:
5288 AddDefine(SHADERPART_FRAGMENT,"PROJECTION",CompleteCode);
5289 Plug(SHADERPART_FRAGMENT,plug_voxel_PROJECTION,CompleteCode,&unique_int);
5290 break;
5291 case SHADERFLAGS_VOLUME_STYLE_SHADED:
5292 AddDefine(SHADERPART_FRAGMENT,"SHADED",CompleteCode);
5293 Plug(SHADERPART_FRAGMENT,plug_voxel_SHADED,CompleteCode,&unique_int);
5294 //if you want a plug within a plug, then if you include the higher level
5295 // plug first, then the lower level plug should find its tartget in the CompleteCode
5296 AddDefine(SHADERPART_FRAGMENT,"LIT",CompleteCode);
5297 AddDefine(SHADERPART_FRAGMENT,"LITE",CompleteCode);
5298 Plug(SHADERPART_FRAGMENT,plug_vertex_lighting_ADSLightModel_volume,CompleteCode,&unique_int);
5299 break;
5300 case SHADERFLAGS_VOLUME_STYLE_SILHOUETTE:
5301 AddDefine(SHADERPART_FRAGMENT,"SILHOUETTE",CompleteCode);
5302 Plug(SHADERPART_FRAGMENT,plug_voxel_SILHOUETTE,CompleteCode,&unique_int);
5303 break;
5304 case SHADERFLAGS_VOLUME_STYLE_TONE:
5305 AddDefine(SHADERPART_FRAGMENT,"TONE",CompleteCode);
5306 Plug(SHADERPART_FRAGMENT,plug_voxel_TONE,CompleteCode,&unique_int);
5307 break;
5308 default:
5309 //if 0, just skip
5310 break;
5311 }
5312 }
5313
5314
5315 //shader doesn't compile?
5316 //in visual studio, this is a good place to get the composed shader source, then paste into
5317 // an editor that has line numbers, to get to the ERROR line
5318 *fragmentSource = CompleteCode[SHADERPART_FRAGMENT]; //original_fragment; //fs;
5319 *vertexSource = CompleteCode[SHADERPART_VERTEX]; //original_vertex; //vs;
5320//#define DEBUGSHADER 1
5321#ifdef DEBUGSHADER
5322 {
5323 //after writing to file you can run unifdef, sunifdef or coan on output to see reduced shader
5324 // http://coan2.sourceforge.net/
5325 //coan source -m composed_shader.vert > shader.vert
5326 FILE *fp = fopen("C:/tmp/composed_shader.vert","w+");
5327 fwrite(*vertexSource,strlen(*vertexSource),1,fp);
5328 fclose(fp);
5329 fp = fopen("C:/tmp/composed_shader.frag","w+");
5330 fwrite(*fragmentSource,strlen(*fragmentSource),1,fp);
5331 fclose(fp);
5332 }
5333#endif //DEBUGSHADER
5334 return retval;
5335
5336}
5337// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< END MIT, VOLUME RENDERING
5338
5339// depth map rendering
5340// https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping
5341// Phase I generate depth map
5342char* vertexDepth = "#version 330 core \n\
5343//layout(location = 0) in vec3 fw_Vertex; \n\
5344in vec4 fw_Vertex; \n\
5345\n\
5346uniform mat4 fw_ModelViewMatrix; \n\
5347uniform mat4 fw_ProjectionMatrix; \n\
5348\n\
5349void main() \n\
5350{ \n\
5351 gl_Position = fw_ProjectionMatrix * fw_ModelViewMatrix * fw_Vertex; \n\
5352} ";
5353char* vertexDepthParticle = "#version 330 core \n\
5354//layout(location = 0) in vec3 fw_Vertex; \n\
5355#define PARTICLE 1 \n\
5356in vec4 fw_Vertex; \n\
5357\n\
5358uniform mat4 fw_ModelViewMatrix; \n\
5359uniform mat4 fw_ProjectionMatrix; \n\
5360#ifdef PARTICLE \n\
5361uniform vec3 particlePosition; \n\
5362uniform vec3 particleDirection; \n\
5363unifomr mat4 particleTransform; \n\
5364uniform int fw_ParticleGeomType; \n\
5365#endif //PARTICLE \n\
5366\n\
5367void main() \n\
5368{ \n\
5369 vec4 vertex = fw_Vertex; \n\
5370 #ifdef PARTICLE \n\
5371 if(fw_ParticleGeomType != 4){ \n\
5372 mat4 rot, rot2; \n\
5373 rot = mat4(1.0); \n\
5374 rot2 = mat4(1.0); \n\
5375 float yaw = atan(particleDirection.y,particleDirection.x); \n\
5376 float pitch = asin(particleDirection.z); \n\
5377 rot[0][0] = cos(yaw); \n\
5378 rot[1][1] = rot[0][0]; \n\
5379 rot[0][1] = sin(yaw); \n\
5380 rot[1][0] = -rot[0][1]; \n\
5381 rot2[0][0] = cos(pitch); \n\
5382 rot2[2][2] = rot2[0][0]; \n\
5383 rot2[0][2] = sin(pitch); \n\
5384 rot2[2][0] = -rot2[0][2]; \n\
5385 rot = rot * rot2; \n\
5386 vertex_object = rot * particleTransform * vertex_object; \n\
5387 //vertex_object.xyz /= vertex_object.w; \n\
5388 //vertex_object.w = 1.0; \n\
5389 } \n\
5390 //vertex_object = particleTransform * vertex_object; \n\
5391 vertex.xyz += particlePosition; \n\
5392 } \n\
5393 //sprite: align to viewer \n\
5394 if(fw_ParticleGeomType == 4){ \n\
5395 vec4 ppos = vec4(particlePosition,1.0); \n\
5396 vec4 particle_eye = fw_ModelViewMatrix * ppos; \n\
5397 ppos.x += 1.0; \n\
5398 vec4 particle_eye1 = fw_ModelViewMatrix * ppos; \n\
5399 float pscal = length(particle_eye1.xyz - particle_eye.xyz); \n\
5400 vertex = particle_eye + pscal*vertex; \n\
5401 } else \n\
5402 #endif //PARTICLE \n\
5403 vertex = fw_ProjectionMatrix * fw_ModelViewMatrix * vertex; \n\
5404 gl_Position = vertex; \n\
5405} ";
5406
5407char* fragDepth = "#version 330 core \n\
5408 \n\
5409void main() \n\
5410{ \n\
5411 gl_FragDepth = gl_FragCoord.z; \n\
5412 //gl_FragColor = vec4(vec3(gl_FragCoord.z),1.0); \n\
5413} ";
5414int getSpecificShaderSourceDepth(const GLchar** vertexSource, const GLchar** fragmentSource, shaderflagsstruct whichOne) {
5415 if(DESIRE(whichOne.base, PARTICLE_SHADER))
5416 *vertexSource = strdup(vertexDepthParticle);
5417 else
5418 *vertexSource = strdup(vertexDepth);
5419 *fragmentSource = strdup(fragDepth);
5420 return TRUE;
5421}
5422
5423//DEBUG quad rendering
5424char* vertexQuad = "#version 330 core \n\
5425layout(location = 0) in vec3 aPos; \n\
5426layout(location = 1) in vec2 aTexCoords; \n\
5427\n\
5428out vec2 TexCoords; \n\
5429 \n\
5430void main() \n\
5431{ \n\
5432 TexCoords = aTexCoords; \n\
5433 gl_Position = vec4(aPos, 1.0); \n\
5434} \n\
5435";
5436char* vertexQuadMatrix = "#version 330 core \n\
5437layout(location = 0) in vec3 aPos; \n\
5438layout(location = 1) in vec2 aTexCoords; \n\
5439uniform mat4 fw_ModelViewMatrix; \n\
5440\n\
5441out vec2 TexCoords; \n\
5442 \n\
5443void main() \n\
5444{ \n\
5445 TexCoords = aTexCoords; \n\
5446 gl_Position = fw_ModelViewMatrix * vec4(aPos, 1.0); \n\
5447} \n\
5448";
5449char* fragmentQuadNormal = "#version 330 core \n\
5450out vec4 FragColor; \n\
5451in vec2 TexCoords; \n\
5452uniform sampler2D textureUnit; \n\
5453void main() \n\
5454{ \n\
5455 FragColor = texture(textureUnit, TexCoords); \n\
5456} \n\
5457";
5458char* fragmentQuadDepthOrtho = "#version 330 core \n\
5459out vec4 FragColor; \n\
5460in vec2 TexCoords; \n\
5461uniform sampler2D textureUnit; \n\
5462void main() \n\
5463{ \n\
5464 float depthValue = texture(textureUnit, TexCoords).r; \n\
5465 FragColor = vec4(vec3(depthValue), 1.0); // orthographic \n\
5466} \n\
5467";
5468char* fragmentQuadDepthPerspective = "#version 330 core \n\
5469out vec4 FragColor; \n\
5470in vec2 TexCoords; \n\
5471uniform sampler2D textureUnit; \n\
5472uniform float near_plane; \n\
5473uniform float far_plane; \n\
5474 \n\
5475// required when using a perspective projection matrix \n\
5476float LinearizeDepth(float depth) \n\
5477{ \n\
5478 float z = depth * 2.0 - 1.0; // Back to NDC \n\
5479 return (2.0 * near_plane * far_plane) / (far_plane + near_plane - z * (far_plane - near_plane)); \n\
5480} \n\
5481 \n\
5482void main() \n\
5483{ \n\
5484 float depthValue = texture(textureUnit, TexCoords).r; \n\
5485 FragColor = vec4(vec3(LinearizeDepth(depthValue) / far_plane), 1.0); // perspective \n\
5486 //FragColor = vec4(vec3(depthValue), 1.0); // orthographic \n\
5487} \n\
5488";
5489char* fragmentQuadDepthCube = "#version 330 core \n\
5490out vec4 FragColor; \n\
5491in vec2 TexCoords; \n\
5492uniform samplerCube textureUnit; \n\
5493//uniform samplerCube textureUnitCube[16]; //challenge test to see if [16] cubemaps is a problem \n\
5494//uniform int depthunit; \n\
5495uniform float near_plane; \n\
5496uniform float far_plane; \n\
5497 \n\
5498// required when using a perspective projection matrix \n\
5499float LinearizeDepth(float depth) \n\
5500{ \n\
5501 float z = depth * 2.0 - 1.0; // Back to NDC \n\
5502 return (2.0 * near_plane * far_plane) / (far_plane + near_plane - z * (far_plane - near_plane)); \n\
5503} \n\
5504 \n\
5505void main() \n\
5506{ \n\
5507 float phi = (TexCoords.x * 2.0 -1.0)*.5*3.14159623; \n\
5508 float theta = (TexCoords.y * 2.0 -.5)*3.14159623; \n\
5509 vec3 tc = vec3(cos(theta)*cos(phi),sin(theta)*cos(phi),sin(phi)); \n\
5510 //float depthValue = texture(textureUnitCube[depthunit], tc).r; \n\
5511 float depthValue = texture(textureUnit, tc).r; \n\
5512 //vec3 cc = (tc*.5 +.5)*depthValue;\n\
5513 //vec3 cc = vec3(TexCoords.x,TexCoords.y,depthValue); \n\
5514 //FragColor = vec4(cc,1.0); \n\
5515 //if(depthValue == 1.0) depthValue = 0.0; \n\
5516 //depthValue = (depthValue - .8)*4.0; \n\
5517 //FragColor = vec4(vec3(depthValue),1.0); \n\
5518 FragColor = vec4(vec3(LinearizeDepth(depthValue) / far_plane), 1.0); // perspective \n\
5519 //FragColor = vec4(vec3(depthValue), 1.0); // orthographic \n\
5520} \n\
5521";
5522
5523char* fragmentQuadColorCube = "#version 330 core \n\
5524out vec4 FragColor; \n\
5525in vec2 TexCoords; \n\
5526uniform samplerCube textureUnit; \n\
5527void main() \n\
5528{ \n\
5529 float phi = (TexCoords.x * 2.0 -1.0)*.5*3.14159623; \n\
5530 float theta = (TexCoords.y * 2.0 -.5)*3.14159623; \n\
5531 vec3 tc = vec3(cos(theta)*cos(phi),sin(theta)*cos(phi),sin(phi)); \n\
5532 FragColor = texture(textureUnit, tc); \n\
5533} \n\
5534";
5535
5536char* fragmentQuadDepthCubeTee = "#version 330 core \n\
5537out vec4 FragColor; \n\
5538in vec2 TexCoords; \n\
5539uniform samplerCube textureUnit; \n\
5540uniform float near_plane; \n\
5541uniform float far_plane; \n\
5542 \n\
5543// required when using a perspective projection matrix \n\
5544float LinearizeDepth(float depth) \n\
5545{ \n\
5546 float z = depth * 2.0 - 1.0; // Back to NDC \n\
5547 return (2.0 * near_plane * far_plane) / (far_plane + near_plane - z * (far_plane - near_plane)); \n\
5548} \n\
5549 \n\
5550void main() \n\
5551{ \n\
5552 float row = floor(TexCoords.y * 3.0); \n\
5553 int irow = int(round(row)); \n\
5554 float y = min((TexCoords.y*3.0 - row),1.0)*2.0 - 1.0; \n\
5555 float col = floor(TexCoords.x * 4.0); \n\
5556 int icol = int(round(col));\n\
5557 float x = min((TexCoords.x*4.0 - col),1.0)*2.0 - 1.0; \n\
5558 if(irow == 0 || irow == 2) \n\
5559 if (icol != 1) discard; \n\
5560 vec3 tc; \n\
5561 if(irow == 1 && icol == 0) tc = vec3(-1.0,y,-x); \n\
5562 if (irow == 1 && icol == 1) tc = vec3(x, y, -1.0); \n\
5563 if (irow == 1 && icol == 2) tc = vec3(1.0, y, x); \n\
5564 if (irow == 1 && icol == 3) tc = vec3(-x, y, 1.0); \n\
5565 if (irow == 0 && icol == 1) tc = vec3(x, -1.0, -y); \n\
5566 if (irow == 2 && icol == 1) tc = vec3(x, 1.0, y); \n\
5567 tc = normalize(tc); \n\
5568 float depthValue = texture(textureUnit, tc).r; \n\
5569 FragColor = vec4(vec3(LinearizeDepth(depthValue) / far_plane), 1.0); // perspective \n\
5570} \n\
5571";
5572
5573int getSpecificShaderSourceDebug(const GLchar** vertexSource, const GLchar** fragmentSource, shaderflagsstruct whichOne) {
5574 if(whichOne.debug == 7)
5575 *vertexSource = strdup(vertexQuadMatrix);
5576 else
5577 *vertexSource = strdup(vertexQuad);
5578
5579 switch (whichOne.debug) {
5580 case 1:
5581 case 7:
5582 *fragmentSource = strdup(fragmentQuadNormal);
5583 break;
5584 case 2:
5585 *fragmentSource = strdup(fragmentQuadDepthOrtho);
5586 break;
5587 case 3:
5588 *fragmentSource = strdup(fragmentQuadDepthPerspective);
5589 break;
5590 case 4:
5591 *fragmentSource = strdup(fragmentQuadDepthCube);
5592 break;
5593 case 5:
5594 *fragmentSource = strdup(fragmentQuadColorCube);
5595 break;
5596 case 6:
5597 *fragmentSource = strdup(fragmentQuadDepthCubeTee);
5598 break;
5599 }
5600 return TRUE;
5601}
5602