Page 1 of 1

shader 3D Editor

Posted: Tue Sep 23, 2025 6:29 pm
by pf shadoko
Hi guys,

My little shader editor.
It's not very practical to use (which is why I hesitated to publish it), but it saves a lot of time.

To use it in your 3D code:
- Add: IncludeFile “...\shader_editor.pb” (corresponding to the code below)
- Use engine3D in debug mode: “InitEngine3D(#PB_Engine3D_DebugLog)”
- Your material must be created in a procedure
- Add below: editshadermaterial(@procedure_namel())

e.g.:
Procedure ShaderMaterial()
...
EndProcedure

editshadermaterial(@ShaderMaterial())

- When closing the editor, the shader code is copied to the clipboard (included in “CreateShader(...)”)
Select the line “CreateShader...” and paste it
- To add an automatic parameter (at the cursor position), click on “Auto param.”

shader_editor.pb

Code: Select all

; Editeur Shader3D

EnableExplicit

;{ =========================== String
#separateurs=" =:;,()[]{}+-/*.\<>?%|&§"+#CR$+#LF$+Chr(34)+#TAB$

Procedure.s lirefic(nom.s)
  Protected txt.s,n
  n=ReadFile(-1,nom,#PB_File_SharedRead):txt=ReadString(n,#PB_File_IgnoreEOL):CloseFile(n)   
  ProcedureReturn txt
EndProcedure

Procedure ecrirefic(nom.s,txt.s,verif.b=1)
  Protected n
  If  FileSize(nom)>0
    If verif And MessageRequester("Attention","Le fichier "+nom+" existe déjà"+#CRLF$+"remplacer ?",#PB_MessageRequester_YesNo) <>#PB_MessageRequester_Yes:ProcedureReturn:EndIf
    DeleteFile(nom)
  EndIf
  n=OpenFile(-1,nom):WriteString(n,txt):CloseFile(n)   
EndProcedure

Procedure Split(Array t.s(1),l.s,sep.s=",",nmax=200)
  Protected ap,p,n,ls
  Dim t(nmax)
  ls=Len(sep)
  l+sep
  p=1-ls
  Repeat
    ap=p+ls:p=FindString(l,sep,ap)
    If p=0:Break:EndIf
    n+1
    t(n)= Mid(l,ap,p-ap)
  ForEver
  ReDim t(n)
  ProcedureReturn n
EndProcedure

Procedure.s supspace(l.s)
  Protected i
  Protected.s ll,ac,c
  
  l=ReplaceString(l,#TAB$," ")
  l=ReplaceString(l,#LF$," ")
  l=ReplaceString(l,#CR$," ")
  i=0:While i<Len(l)
    Repeat
      i+1
      ac=c:c=Mid(l,i,1)
    Until c<>" " Or ac<>" "
    ll+c        
  Wend
  ProcedureReturn Trim(ll)
EndProcedure

Procedure.s Stringparse(t.s,before.s,after.s,pi=0)
  Protected pf
  
  pi=FindString(t,before,pi+1)
  If pi=0:ProcedureReturn:EndIf 
  pf=FindString(t,after,pi+Len(before)):If pf=0:pf=Len(t):EndIf
  pi+Len(before)
  ProcedureReturn Mid(t,pi,pf-pi)
EndProcedure

Procedure.s lirefct(Array p.s(1),txt.s,pd=1)
  #g=Chr(34)
  Protected i,n,np,pi,pf,l,p,ch
  Protected.s c,fct
  Dim p(100)
  pi=FindString(txt,"(",pd)
  fct=Trim(Mid(txt,pd,pi-pd))
  pi+1
  ; ----------- recherche parametre
  For i=pi To Len(txt)
    c=Mid(txt,i,1)
    If ch=0
      If (c="," Or c=")") And np<=0:n+1:p(n)=Trim(Mid(txt,pi,i-pi)):pi=i+1:EndIf
      If c="(":np+1:EndIf
      If c=")":np-1:EndIf
    EndIf
    If c=#g:ch=~ch:EndIf
    If np<0:Break:EndIf
  Next
  ReDim p(n)
  ProcedureReturn fct
EndProcedure

Procedure FindStringRev(t.s,find.s,p=0,mode=#PB_String_CaseSensitive)
  Protected l=Len(find)
  If p=0:p=Len(t):EndIf
  Repeat
    If p=0 Or Mid(t,p,L)=find:Break:EndIf
    p-1
  ForEver
  ProcedureReturn p
EndProcedure

Procedure.i FindStringww(txt.s,mot.s,p=1,mode=0); findstring whole word
  Repeat
    p=FindString(txt,mot,p,mode):If p=0:Break:EndIf
    If FindString(#separateurs,Mid(txt,p-1,1))>0 And FindString(#separateurs,Mid(txt,p+Len(mot),1))>0:ProcedureReturn p:EndIf
    p+Len(mot)
  ForEver
EndProcedure

Procedure.s ReplaceStringww(txt.s,mot.s,rep.s,p=1,mode=0); ReplaceString whole word
  Protected lm,lr
  
  lm=Len(mot)
  lr=Len(rep)
  Repeat
    p=FindStringww(txt,mot,p+1,mode):If p=0:Break:EndIf
    txt=Left(txt,p-1)+rep+Mid(txt,p+lm)
    ;p+lm-lr+1
  ForEver
  ProcedureReturn txt
EndProcedure

Procedure.s ReplaceStringwwnum(txt.s,mot.s,rep.s,p=1,mode=0); ReplaceString whole word
  Protected i
  For i=0 To 9
    txt=ReplaceStringww(txt,mot+Str(i),rep+Str(i),p,mode)
  Next
  ProcedureReturn txt
EndProcedure
;}

Declare shaderexport(compression,format)

Structure sparamauto
  type.s
  param.s
  nomc.s
  nomOgre.s
  comment.s
EndStructure

Global Dim lword.s(20)
Global SciPos,SciStart, SciLine, SciCol, SciIndent,KeyWord.s 
Global wedit,gSc,gsticky, gparamauto
Global wparam,gpauto_liste,gpauto_comment

Global e_sid, e_vpg.s,e_fpg.s,e_materialproc, e_return.s, e_tile.s="Shader Editor "

Global Dim paramauto.sparamauto(136)

Enumeration ScStyle
  #Style_Keyword
  #Style_input
  #Style_Type
  #Style_UniformI
  #Style_VaryingI
  #Style_Uniform
  #Style_Varying
  #Style_Variable
  #Style_Macro
  #Style_Comment
  #Style_NonKeyword
EndEnumeration

Macro ssm(message,param=0,lparam=0)
  ScintillaSendMessage(gSc,message,param,lparam)
EndMacro

Procedure.s ssmgettext()
  Protected *buf,bufsize,txt.s
  bufsize=ssm(#SCI_GETLENGTH)+1
  *buf=AllocateMemory(bufsize)
  ssm(#SCI_GETTEXT,bufsize,*buf)
  txt=PeekS(*buf,-1,#PB_UTF8)
  FreeMemory(*buf)
  ProcedureReturn txt
EndProcedure

Procedure.s ssmGETCURLINE()
  Protected *buf,bufsize,txt.s
  bufsize=100
  *buf=AllocateMemory(bufsize)
  ssm(#SCI_GETCURLINE,bufsize,*buf)
  txt=PeekS(*buf,-1,#PB_UTF8)
  FreeMemory(*buf)
  ProcedureReturn txt
EndProcedure

Procedure paramautoevent()
  Protected n
  If Event()=#PB_Event_CloseWindow:CloseWindow(EventWindow()):ProcedureReturn:EndIf
  
  n=GetGadgetState(gpauto_liste):If n<0:ProcedureReturn:EndIf
  If EventType()=#PB_EventType_LeftClick:SetGadgetText(gpauto_comment,paramauto(n)\type+"   "+paramauto(n)\nomc+"    ("+paramauto(n)\nomOgre+")"+#LF$+#LF$+paramauto(n)\comment):EndIf
  ;SetGadgetText(gpauto_comment,lparam()\nom+#CR$+lparam()\type+#CR$+lparam()\valdef)
  If EventType()=#PB_EventType_LeftDoubleClick
    ssm(#SCI_INSERTTEXT,ssm(#SCI_GETANCHOR),UTF8("uniform "+paramauto(n)\type+" "+paramauto(n)\nomc+";//+"+n+#LF$))
    CloseWindow(EventWindow())
  EndIf
EndProcedure

Procedure waffparamauto()
  Protected i,col,nom.s
  
  wparam=OpenWindow(-1,0,0,800,416,e_tile+" Auto parameters",#PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_Tool,WindowID(wedit))
  gpauto_liste=ListIconGadget(-1,8,8,250,400,"Param_Auto",250-22,#PB_ListIcon_FullRowSelect)
  HideGadget(gpauto_liste,1)
  For i=0 To ArraySize(paramauto())
    col=$eeeeee
    nom= LCase(paramauto(i)\nomOgre)
    If FindString(nom,"time"):col=$aaaaaa:EndIf
    If FindString(nom,"colour"):col=$8888ff:EndIf
    If FindString(nom,"position"):col=$ff6666:EndIf
    If FindString(nom,"direction"):col=$ff8888:EndIf
    If FindString(nom,"matrix"):col=$88ccff:EndIf
    If FindString(nom,"array"):col=$66aadd:EndIf
    AddGadgetItem(gpauto_liste,-1,Str(i)+"    "+paramauto(i)\nomc)
    SetGadgetItemColor(gpauto_liste,i,#PB_Gadget_BackColor,col)
  Next
  HideGadget(gpauto_liste,0)
  BindEvent(#PB_Event_Gadget,@paramautoevent(),wparam,gpauto_liste)
  BindEvent(#PB_Event_CloseWindow,@paramautoevent(),wparam)
  gpauto_comment=EditorGadget(-1,266,8,526,400,#PB_Editor_ReadOnly|#PB_Editor_WordWrap)
EndProcedure

Procedure ScintillaProperties()
  ;Style par defaut du gadget scintilla (Couleur de fond et de caractére, police .....)
  ssm(#SCI_STYLESETFORE, #STYLE_DEFAULT, $0)           ;Couleur des caracteres du ScintillaGadget
  ssm(#SCI_STYLESETBACK, #STYLE_DEFAULT, $aaddee)      ;Couleur de fond du ScintillaGadget
  ssm(#SCI_STYLESETFONT,#STYLE_DEFAULT, UTF8("Consolas"))       ;Police à utiliser
  ssm(#SCI_STYLESETSIZE, #STYLE_DEFAULT, 10)                    ;Taille de la police
  ssm(#SCI_STYLECLEARALL) 
  ssm(#SCI_SETCARETLINEVISIBLE, #True);Activation et couleur de la ligne en cours d'édition
  ssm(#SCI_SETCARETLINEBACK, RGB(255, 228, 181))
  ssm(#SCI_STYLESETFORE, #STYLE_BRACELIGHT, $ff) :ssm(#SCI_STYLESETBOLD, #STYLE_BRACELIGHT, 1)
  
  ;ssm(#SCI_SETUSETABS, #False);Les tabulations sont remplacées par des espaces 
  ssm(#SCI_SETINDENT, 4)		;Nombre d'espaces pour une tabulation
  
  ssm(#SCI_SETMARGINTYPEN, 0, #SC_MARGIN_NUMBER);Affichage de la colone de numérotation des lignes               
  ssm(#SCI_SETMARGINWIDTHN, 0, 30)              ;Largeur de la colonne
  ssm(#SCI_STYLESETBACK, #STYLE_LINENUMBER, $aaccdd)  ;Couleur de fond
  ssm(#SCI_STYLESETFORE, #STYLE_LINENUMBER, $ffffff)  ;Couleur des numéros
  
  ;ssm(#SCI_SETMARGINMASKN, 2, #SC_MASK_FOLDERS);Affichage de la colonne de pliages de code
  ;ssm(#SCI_SETMARGINWIDTHN, 2, 20)
  ssm(#SCI_SETMARGINSENSITIVEN, 2, #True)
  
  ;   ssm(#SCI_BRACEScStyleINDICATOR, #True)
  
  ssm(#SCI_AUTOCSETMAXHEIGHT, 20);Parametres de la liste d'autocomplétion des mots clés
  ssm(#SCI_AUTOCSETMAXWIDTH, 150)
  ssm(#SCI_AUTOCSETAUTOHIDE, #True)
  ssm(#SCI_AUTOCSETCHOOSESINGLE, #True)
  ssm(#SCI_AUTOCSETIGNORECASE, #True) 
  ssm(#SCI_AUTOCSETORDER, #SC_ORDER_PERFORMSORT);Tri de la liste d'autocomplétion
                                                ;ssm(#SCI_AUTOCCANCEL, #True)
  
  ;Coloration syntaxique
  Macro style(num,col,bold=0,ital=0,under=0)
    ssm(#SCI_STYLESETFORE, num, col)
    If bold:ssm(#SCI_STYLESETBOLD, num, 1):EndIf
    If ital:ssm(#SCI_STYLESETITALIC, num, 1):EndIf
    If under:ssm(#SCI_STYLESETUNDERLINE, num, 1):EndIf
  EndMacro
  style(#Style_Type, $888800,1,0,0)
  style(#Style_Keyword, $88,1,0,0)
  style(#Style_input, $ff0000,0,0,0)
  style(#Style_UniformI, $880000,0,1)
  style(#Style_Uniform, $880000)
  style(#Style_VaryingI, $880088,0,1)
  style(#Style_Varying, $880088,0,0)
  style(#Style_Variable, $004488)
  style(#Style_Macro, $0044aa,0,1)
  style(#Style_Comment, $8800,0,1)
  style(#Style_NonKeyword, 0)
EndProcedure

Procedure ScStyle(*sn.SCNotification,majliste=0)
  Protected.s ac.s,c.s,word.s,aword,aaword,txt.s
  Protected StyleID,aStyleID,	i,k,l
  Protected lg,poslgf,pos,posf=*sn\position
  
  Macro addkw(liste,mot)
    If FindString(liste," "+mot+" ")=0:liste+mot+" ":EndIf
  EndMacro
    
  If majliste 
      lword(#Style_Varying)=" "
      lword(#Style_Uniform)=" "
      lword(#Style_Variable)=" "
    pos=0
    posf=ssm(#SCI_GETLENGTH)
  Else	
    pos= ssm(#SCI_GETENDSTYLED)	
    lg=ssm(#SCI_LINEFROMPOSITION,pos)
    pos=ssm(#SCI_POSITIONFROMLINE,lg)-1
  EndIf
  
  While pos <= posf
    ssm(#SCI_STARTSTYLING, pos,0)
    word="":l=0:Repeat:ac=c:c=Chr(ssm(#SCI_GETCHARAT, pos+l)):If FindString(#separateurs,c):Break:EndIf:word+c:l+1:Until pos+l>=posf
    If l
      astyleID=StyleID:StyleID=#Style_NonKeyword
      If majliste And astyleID=#Style_Type;:Debug ""+aaword+" "+aword+" "+word
          If aaword="varying" Or aaword="out":addkw(lword(#Style_Varying),word):EndIf
          If aaword="uniform":addkw(lword(#Style_Uniform),word):EndIf
          If aaword=""       :addkw(lword(#Style_Variable),word):EndIf
        EndIf
      aaword=aword:aword=word
      For k=0 To #Style_NonKeyword
        If FindString(lword(k)," "+word+" ") :StyleID=k:Break:EndIf
      Next
      ssm(#SCI_SETSTYLING, l, StyleID)
      pos+l:ssm(#SCI_STARTSTYLING, pos,0)
    EndIf
    If ac+c="//"
      poslgf=ssm(#SCI_GETLINEENDPOSITION,ssm(#SCI_LINEFROMPOSITION,pos))+1:l=poslgf-pos:pos=poslgf:ssm(#SCI_SETSTYLING, l, #Style_Comment)	
    Else
      pos+1:ssm(#SCI_SETSTYLING, 1, #Style_NonKeyword)	
    EndIf
    If c=";" Or c="}" Or c="{":aaword="":aword="":EndIf
  Wend
EndProcedure

Procedure ScCallBack(g, *sn.SCNotification)
  Static i,ag, lw,l,ti
  
  gSc=g;:	If ag<>g:ag=g:majScintilla():EndIf	
  SciPos = ssm(#SCI_GETANCHOR);Determination de la position à l'intérieur de la chaine scintilla 
  SciStart=ssm(#SCI_WORDSTARTPOSITION, SciPos, 1)
  SciLine = ssm(#SCI_LINEFROMPOSITION, SciPos);Determination de la ligne en cours
  SciCol = ssm(#SCI_GETCOLUMN, SciPos)        ;Determination de la colonne en cours
  
  ;Debug ""+g+"   "+*sn\nmhdr\code+"  "+*sn\length
  ;If *sn\text:Debug PeekS(*sn\text,-1,#PB_UTF8):endif
  ;If *sn\nmhdr\code<>2013 And *sn\nmhdr\code<>2000 :Debug ""+*sn\nmhdr\code+"-"+ssmGETCURLINE():EndIf
  
  If ElapsedMilliseconds()-ti>5000:ScStyle(*sn,1):ti=ElapsedMilliseconds():EndIf
  
  Select *sn\nmhdr\code			
    Case #SCN_MODIFIED
      
    Case #SCN_CHARADDED			
      ;Autocomplétion
      KeyWord="":For i=0 To #Style_Macro:KeyWord+Mid(lword(i),2):Next:KeyWord=Trim(KeyWord)
      l=scipos-SciStart
      If l>1 And *sn\ch>='a' And *sn\ch<='z':ssm(#SCI_AUTOCSHOW, l, UTF8(KeyWord)):EndIf
      
    Case #SCN_STYLENEEDED
      ScStyle(*sn)
      
    Case #SCN_MARGINCLICK
      ssm(#SCI_TOGGLEFOLD, ssm(#SCI_LINEFROMPOSITION, *sn\Position))
      
    Case #SCN_UPDATEUI
      If FindString("()[]{}",Chr(ssm(#SCI_GETCHARAT,scipos-1))):ssm(#SCI_BRACEHIGHLIGHT, scipos-1, ssm(#SCI_BRACEMATCH,scipos-1))
      ElseIf FindString("()[]{}",Chr(ssm(#SCI_GETCHARAT,scipos))):ssm(#SCI_BRACEHIGHLIGHT, scipos, ssm(#SCI_BRACEMATCH,scipos))
        Else:ssm(#SCI_BRACEBADLIGHT,-1):EndIf
  EndSelect
EndProcedure

Procedure editorevent()
  Protected aw=GetActiveWindow()
  Select Event()
    Case #PB_Event_CloseWindow:
      shaderexport(2,0):SetClipboardText(e_return)
      ;ClearDebugOutput():ShowDebugOutput():Debug e_return
      ;chemin=SaveFileRequester("save as","C:\PureBasic-code\MaterialScriptsGeneric\","Material (*.material)|*.material",0):If chemin<>"":script(chemin):EndIf
      End
    Case #PB_Event_Menu
      Select EventMenu()
        Case 1:If shaderexport(2,0) And aw<>-1:ReleaseMouse(0):SetWindowState(wedit,#PB_Window_Minimize):EndIf
      EndSelect
    Case #PB_Event_Timer
      If aw<>-1 And Left(GetWindowTitle(aw),Len(e_tile))<>e_tile:SetWindowState(wedit,#PB_Window_Minimize):ReleaseMouse(0):EndIf
      ;If KeyboardPushed(#PB_Key_F5):DisableWindow(wedit,0):ResizeWindow(wedit,#PB_Ignore,#PB_Ignore,wdx,wdy):SetWindowState(wedit,#PB_Window_Normal):ReleaseMouse(1):EndIf
      If KeyboardPushed(#PB_Key_F5):SetWindowState(wedit,#PB_Window_Normal):ReleaseMouse(1):SetActiveGadget(gSc):EndIf
    Case #PB_Event_Gadget
      If EventType()=#PB_EventType_Change
        Select EventGadget()
        EndSelect
      EndIf		
      If EventType()=#PB_EventType_LeftClick
        Select EventGadget()
          Case gsticky:StickyWindow(wedit,GetGadgetState(gsticky))
          Case gparamauto:waffparamauto()
        EndSelect
      EndIf		
  EndSelect
EndProcedure

Procedure editorShow() 
  Protected i,event,g.s=Chr(34),c.s,opt,hs,lg.s=#LF$+LSet("", 80, "_")+#LF$
  
  ExamineDesktops():hs=DesktopHeight(0)*0.6
  wedit=OpenWindow(-1,  00,  30, 800, hs, e_tile+" [F5] Test/Editor", #PB_Window_SystemMenu)
    
   AddKeyboardShortcut(wedit,#PB_Shortcut_F5,1)
   AddWindowTimer(wedit,333,100)
   BindEvent(#PB_Event_Menu,@editorevent(),wedit ,#PB_All ,#PB_All )
   BindEvent(#PB_Event_CloseWindow,@editorevent(),wedit ,#PB_All ,#PB_All )
   BindEvent(#PB_Event_Gadget,@editorevent(),wedit ,#PB_All ,#PB_All )
   BindEvent(#PB_Event_Timer,@editorevent(),wedit ,#PB_All ,#PB_All )
   gsticky=ButtonGadget(-1,800-50-8,0,50,30,"Sticky",#PB_Button_Toggle)
   gparamauto=ButtonGadget(-1,8,0,80,30,"Param auto")
   gSc=ScintillaGadget(-1, 0, 30   , 800, WindowHeight(wedit,#PB_Window_InnerCoordinate)-30, @ScCallBack()):
   ScintillaProperties();:BindGadgetEvent(gSc,@waffparamauto(),#PB_EventType_RightClick)
  ;Neutraliser la touche TAB et les caractéres spéciaux
  RemoveKeyboardShortcut(wedit, #PB_Shortcut_Tab)
  
  ssm(#SCI_SETTEXT, 0,UTF8(InsertString(lg,"Vertex",40)+e_vpg+InsertString(lg,"Fragment",40)+e_fpg))
EndProcedure

Procedure init()	
  Protected i,atc.s=" "
  
  Restore paramauto
  For i=0 To 136
    With paramauto(i)
      Read.s \type
      Read.s \param
      Read.s \nomc
      Read.s \nomOgre
      Read.s \comment
      atc+\nomc+" "
    EndWith
  Next
  ;lword(#Style_UniformI)=atc
  ;lword(#Style_VaryingI)=" ouv ovcolor olightdir oviewdir olightatt onormal ofogf opos_w "
  lword(#Style_Type)=" float vec2 vec3 vec4 bool bvec2 bvec3 bvec4 int ivec2 ivec3 ivec4 mat2 mat3 mat4 sampler1D sampler2D sampler3D samplerCube sampler2DShadow "
  lword(#Style_Keyword)="const dFdx dFdy floor ceil sin cos tan atan mod for fract abs attribute ftransform uniform varying normalize distance length if else clamp mix min max cross dot reflect refract pow texture return step smoothstep "
  lword(#Style_input)=" tangent gl_Vertex gl_Normal gl_Color gl_Position gl_TextureMatrix gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 gl_FragColor gl_FragCoord gl_FragDepth gl_FrontFacing "
  ;lword(#Style_Macro)=" tbn diff spec fresnel "	
EndProcedure

Structure suniform
  nom.s
  nomc.s
  param.s
EndStructure

Procedure.s shCodec(txt.s,sens=0)
  Protected.s sh,np,ll,c,fl
  Protected i,j,pg,p,pp,n,nl
  Dim l.s(0)
  Dim c.s(0)
  NewList u.suniform()
  
  If sens=0:fl="%":Else:fl=#LF$:EndIf
  txt=ReplaceString(txt,#CRLF$,#LF$)
  sh=""
  nl=Split(l(),txt,fl)
  For j=1 To nl
    ll=supspace(l(j))
    Split(c(),ll," ")
    If sens=0
      For i=2 To Len(#separateurs)
        c=Mid(#separateurs,i,1)
        ll=ReplaceString(ll," "+c,c)
        ll=ReplaceString(ll,c+" ",c)
      Next
    EndIf
    If c(1)="uniform"
      p=FindString(c(3),";//+")
      If p And ArraySize(c())<4 ; pas de param opt
        n=Val(Mid(c(3),p+4))
        pp=FindString(c(3),"["):If pp:p=pp:EndIf
        AddElement(u()):u()\nom=Left(c(3),p-1):If sens=0:u()\nomc="P"+n:Else:u()\nomc=paramauto(n)\nomc:EndIf
      EndIf
    EndIf
    sh+ll:If j<nl:sh+fl:EndIf
  Next		
  ForEach u():sh=ReplaceStringww(sh,u()\nom,u()\nomc):Next

  ProcedureReturn sh
EndProcedure

Procedure shaderexport(compression,format)
  Protected txt.s,chemin.s,g.s=Chr(34),t.s=ssmgettext()
  
  e_vpg=Stringparse(t,"___"+#LF$,#LF$+"___")
  e_fpg=Stringparse(t+"%","___"+#LF$,"%",FindString(t,"___"+#LF$)+1)
  If compression
    e_vpg=ReplaceString(e_vpg,#LF$,"%"):e_vpg=ReplaceString(e_vpg,#CR$,"")
    e_fpg=ReplaceString(e_fpg,#LF$,"%"):e_fpg=ReplaceString(e_fpg,#CR$,"")
  EndIf
  If compression=2:e_vpg=shCodec(e_vpg):e_fpg=shCodec(e_fpg):EndIf
  
  Select format
    Case 0;pb
      txt="CreateShader("+e_sid+","+g+e_vpg+g+","+g+e_fpg+g+")"+#CRLF$
    Case 1;c
      txt=","+g+e_vpg+g+#CRLF$+","+g+e_fpg+g+#CRLF$
    Case 2;gen
      txt="v="+g+e_vpg+g+#CRLF$+"f="+g+e_fpg+g+#CRLF$
  EndSelect
  
  CreateShader(e_sid,e_vpg,e_fpg)
  RenderWorld()
  
  Static posf,m.s,l  
  Protected ok=1,p,log.s,fic.s=GetCurrentDirectory()+"Ogre"
  CopyFile(fic+".log", fic+".tmp") 
  log=lirefic(fic+".tmp")
  
  Macro sokmess(balise,pgtype)
    p=FindString(log,"sh"+e_sid+balise,posf)
    If p
      m=Mid(log,p+11,FindString(log,#LF$,p+11)-(p+11))
      l=Val(Stringparse(m,"0:",":"))+CountString(Left(t,FindString(t,"_"+pgtype+"_")),#LF$)+1
      MessageRequester(e_tile+"ERROR "+pgtype+" shader",  m+#CRLF$+"ligne "+l)
      ok=0
    EndIf
  EndMacro
  ;ogre v1.8
  sokmess("VPERROR","Vertex")
  sokmess("FPERROR","Fragment")
  ;ogre v1.14
  sokmess("VP' ERROR","Vertex")
  sokmess("FP' ERROR","Fragment")
  posf=FileSize(fic+".tmp")

  If ok:e_return=txt:CallFunctionFast(e_materialproc):EndIf    
  ProcedureReturn ok
EndProcedure

Procedure  CreateShader_(shaderid,vertexprogram.s,fragmentprogram.s)
  CreateShader(shaderid,vertexprogram,fragmentprogram)
EndProcedure

Macro CreateShader(shaderid,vertexprogram,fragmentprogram)
  e_sid=shaderid
  e_vpg=vertexprogram
  e_fpg=fragmentprogram
  CreateShader_(shaderid,vertexprogram,fragmentprogram)
  
  e_vpg=ReplaceString(e_vpg,"%",#LF$)
  e_fpg=ReplaceString(e_fpg,"%",#LF$)
  e_vpg=shCodec(e_vpg,1)
  e_fpg=shCodec(e_fpg,1)
  ReleaseMouse(1)
EndMacro

Procedure editshadermaterial(proc)
  e_materialproc=proc
  editorShow()
EndProcedure

init()

DataSection 
  paramauto:
  Data.s "mat4","","world_mx","world_matrix","The current world matrix"
  Data.s "mat4","","inverse_world_mx","inverse_world_matrix","The current world matrix, inverted"
  Data.s "mat4","","transpose_world_mx","transpose_world_matrix","Provides transpose of world matrix."
  Data.s "mat4","","inverse_transpose_world_mx","inverse_transpose_world_matrix","The current world matrix, inverted & transposed"
  Data.s "mat4","","bone_3x4","bone_matrix_array_3x4","An array of bone matrices, each represented as only a 3x4 matrix (3 rows of4columns) usually for doing hardware skinning.You should make enough entries available in your vertex program for the number ofbones in use, i.e. an array of numBones*3 float4’s."
  Data.s "mat4","","bone_mx","bone_matrix_array","The current array of bone matrices, used for blending"
  Data.s "mat4","","bone_dualquaternion_2x4","bone_dualquaternion_array_2x4","The current array of bone matrices transformed to an array of dual quaternions,represented as a 2x4 matrix"
  Data.s "mat4","","bone_scale_shear_matrix_3x4","bone_scale_shear_matrix_array_3x4","The scale and shear components of the current array of bone matrices"
  Data.s "mat4","","view_mx","view_matrix","The current view matrix"
  Data.s "mat4","","inverse_view_mx","inverse_view_matrix","The current view matrix, inverted"
  Data.s "mat4","","transpose_view_mx","transpose_view_matrix","Provides transpose of view matrix."
  Data.s "mat4","","inverse_transpose_view_mx","inverse_transpose_view_matrix","Provides inverse transpose of view matrix."
  Data.s "mat4","","projection_mx","projection_matrix","The current projection matrix"
  Data.s "mat4","","inverse_projection_mx","inverse_projection_matrix","Provides inverse of projection matrix."
  Data.s "mat4","","transpose_projection_mx","transpose_projection_matrix","Provides transpose of projection matrix."
  Data.s "mat4","","inverse_transpose_projection_mx","inverse_transpose_projection_matrix","Provides inverse transpose of projection matrix."
  Data.s "mat4","","viewproj_mx","viewproj_matrix","The current view & projection matrices concatenated"
  Data.s "mat4","","inverse_viewproj_mx","inverse_viewproj_matrix","Provides inverse of concatenated view and projection matrices."
  Data.s "mat4","","transpose_viewproj_mx","transpose_viewproj_matrix","Provides transpose of concatenated view and projection matrices."
  Data.s "mat4","","inverse_transpose_viewproj_mx","inverse_transpose_viewproj_matrix","Provides inverse transpose of concatenated view and projection matrices."
  Data.s "mat4","","worldview_mx","worldview_matrix","The current world & view matrices concatenated"
  Data.s "mat4","","inverse_worldview_mx","inverse_worldview_matrix","The current world & view matrices concatenated, then inverted"
  Data.s "mat4","","transpose_worldview_mx","transpose_worldview_matrix","Provides transpose of concatenated world and view matrices."
  Data.s "mat4","","inverse_transpose_worldview_mx","inverse_transpose_worldview_matrix","The current world & view matrices concatenated, then inverted & transposed"
  Data.s "mat4","","normal_mx","normal_matrix","Provides inverse transpose of the upper 3x3 of the worldview matrix.ivalent to @c gl_NormalMatrix."
  Data.s "mat4","","worldviewproj_mx","worldviewproj_matrix","The current world, view & projection matrices concatenated"
  Data.s "mat4","","inverse_worldviewproj_mx","inverse_worldviewproj_matrix","Provides inverse of concatenated world, view and projection matrices."
  Data.s "mat4","","transpose_worldviewproj_mx","transpose_worldviewproj_matrix","Provides transpose of concatenated world, view and projection matrices."
  Data.s "mat4","","inverse_transpose_worldviewproj_mx","inverse_transpose_worldviewproj_matrix","Provides inverse transpose of concatenated world, view and projectionrices."
  Data.s "float","","render_target_flipping","render_target_flipping","render target related values-1 if requires texture flipping, +1 otherwise. It's useful when you bypassedjection matrix transform, still able use this value to adjust transformed yition."
  Data.s "float","","vertex_winding","vertex_winding","-1 if the winding has been inverted, +1 otherwise..g. for reflections"
  Data.s "vec4","","fog_colour","fog_colour","Fog colour"
  Data.s "vec4","","fog_params","fog_params","Fog params: `(density, linear start, linear end, 1/(end-start))`"
  Data.s "vec4","","surface_ambient_colour","surface_ambient_colour","Surface ambient colour, as set in Pass::setAmbient"
  Data.s "vec4","","surface_diffuse_colour","surface_diffuse_colour","Surface diffuse colour, as set in Pass::setDiffuse"
  Data.s "vec4","","surface_specular_colour","surface_specular_colour","Surface specular colour, as set in Pass::setSpecular"
  Data.s "vec4","","surface_emissive_colour","surface_emissive_colour","Surface emissive colour, as set in Pass::setSelfIllumination"
  Data.s "float","","shininess","surface_shininess","Surface shininess, as set in Pass::setShininess"
  Data.s "float","","surface_alpha_rejection_value","surface_alpha_rejection_value","Surface alpha rejection value, not as set in @ref Pass::setAlphaRejectValue, but afloating number between 0.0f and 1.0f instead (255.0f /@ref Pass::getAlphaRejectValue())"
  Data.s "float","","light_count","light_count","The number of active light sources"
  Data.s "vec4","","ambient_light_colour","ambient_light_colour","The ambient light colour set in the scene"
  Data.s "vec4","0","light_diffuse_colour","light_diffuse_colour","Light diffuse colour (index determined by setAutoConstant call).this requires an index in the ’extra_params’ field, and relates to the ’nth’ closestlight which could affect this object(i.e. 0 refers to the closest light - note that directional lights are always firstin the list and always present).NB if there are no lights this close, then the parameter will be set to black."
  Data.s "vec4","0","light_specular_colour","light_specular_colour","Light specular colour (index determined by setAutoConstant call)"
  Data.s "vec4","0","light_att","light_attenuation","Light attenuation parameters.acked as `(range, constant, linear, quadric)`.or area lights this contains the height half-vector `(x, y, z, 0)` of the light in viewspace."
  Data.s "vec4","0","spotlight_params","spotlight_params","Spotlight parameters.ked as `(innerFactor, outerFactor, falloff, spotType)`erFactor and outerFactor are cos(angle/2)spotType parameter is 0.0f for non-spotlights, 1.0f for spotlights and 2.0f fora spotlights.area lights this contains the width half-vector `(x, y, z, 2)` of the light in viewspace.o for non-spotlights the inner and outer factors are 1 and 0 respectively"
  Data.s "vec4","0","light_pos","light_position","A light position in world space (index determined by setAutoConstant call).s requires an index in the ’extra_params’ field, and relates to the ’nth’ closestht which could affect this object (i.e. 0 refers to the closest light).if there are no lights this close, then the parameter will be set to all zeroes.e that this property will work with all kinds of lights, even directional lights,ce the parameter is set as a 4D vector.nt lights will be `(pos.x, pos.y, pos.z, 1.0f)` whilst directional lights will bedir.x, -dir.y, -dir.z, 0.0f)`.rations like dot products will work consistently on both."
  Data.s "vec4","0","light_pos_os","light_position_object_space","A light position in object space (index determined by setAutoConstant call)"
  Data.s "vec4","0","light_pos_vs","light_position_view_space","A light position in view space (index determined by setAutoConstant call)"
  Data.s "vec4","0","light_dir","light_direction","A light direction in world space (index determined by setAutoConstant call)@deprecated this property only works on directional lights, and we recommend thatyou use light_position instead since that returns a generic 4D vector."
  Data.s "vec4","0","light_dir_os","light_direction_object_space","A light direction in object space (index determined by setAutoConstant call)"
  Data.s "vec4","0","light_dir_vs","light_direction_view_space","A light direction in view space (index determined by setAutoConstant call)"
  Data.s "float","0","light_distance_os","light_distance_object_space","The distance of the light from the center of the objectseful approximation as an alternative to per-vertex distanceculations."
  Data.s "float","","light_power_scale","light_power_scale","Light power level, a single scalar as set in Light::setPowerScale  (index determinedsetAutoConstant call) */"
  Data.s "vec4","","light_diffuse_colour_power_scaled","light_diffuse_colour_power_scaled","Light diffuse colour pre-scaled by Light::setPowerScale (index determined bysetAutoConstant call)"
  Data.s "vec4","","light_specular_colour_power_scaled","light_specular_colour_power_scaled","Light specular colour pre-scaled by Light::setPowerScale (index determined bysetAutoConstant call)"
  Data.s "vec4","0","light_diffuse_colour_array","light_diffuse_colour_array","Array of light diffuse colours (count set by extra param)"
  Data.s "vec4","0","light_specular_colour_array","light_specular_colour_array","Array of light specular colours (count set by extra param)"
  Data.s "vec4","0","light_diffuse_colour_power_scaled_array","light_diffuse_colour_power_scaled_array","Array of light diffuse colours scaled by light power (count set by extra param)"
  Data.s "vec4","0","light_specular_colour_power_scaled_array","light_specular_colour_power_scaled_array","Array of light specular colours scaled by light power (count set by extra param)"
  Data.s "float","0","light_attenuation_array","light_attenuation_array","Array of light attenuation parameters.@copydetails #ACT_LIGHT_ATTENUATION (count set by extra param)"
  Data.s "vec4","0","light_pos_array","light_position_array","Array of light positions in world space (count set by extra param)"
  Data.s "vec4","0","light_pos_os_array","light_position_object_space_array","Array of light positions in object space (count set by extra param)"
  Data.s "vec4","0","light_pos_vs_array","light_position_view_space_array","Array of light positions in view space (count set by extra param)"
  Data.s "vec4","0","light_dir_array","light_direction_array","Array of light directions in world space (count set by extra param)"
  Data.s "vec4","0","light_dir_os_array","light_direction_object_space_array","Array of light directions in object space (count set by extra param)"
  Data.s "vec4","0","light_dir_vs_array","light_direction_view_space_array","Array of light directions in view space (count set by extra param)"
  Data.s "float","0","light_distance_os_array","light_distance_object_space_array","Array of distances of the lights from the center of the objectseful approximation as an alternative to per-vertex distanceculations. (count set by extra param)"
  Data.s "float","","light_power_scale_array","light_power_scale_array","Array of light power levels, a single scalar as set in Light::setPowerScaleunt set by extra param)"
  Data.s "float","0","spotlight_params_array","spotlight_params_array","Spotlight parameters arraycopydetails #ACT_SPOTLIGHT_PARAMScount set by extra param)"
  Data.s "vec4","","ambient_ml","derived_ambient_light_colour","The derived ambient light colour, with 'r', 'g', 'b' components filled withduct of surface ambient colour and ambient light colour, respectively,'a' component filled with surface diffuse alpha component."
  Data.s "vec4","","derived_scene_colour","derived_scene_colour","The derived scene colour, with 'r', 'g' and 'b' components filled with sumderived ambient light colour and surface emissive colour, respectively,'a' component filled with surface diffuse alpha component."
  Data.s "vec4","0","diffuse_ml","derived_light_diffuse_colour","The derived light diffuse colour (index determined by setAutoConstant call),h 'r', 'g' and 'b' components filled with product of surface diffuse colour,ht power scale and light diffuse colour, respectively, and 'a' component filledh surfacefuse alpha component."
  Data.s "vec4","0","specular_ml","derived_light_specular_colour","The derived light specular colour (index determined by setAutoConstant call),h 'r', 'g' and 'b' components filled with product of surface specular colourlight specular colour, respectively, and 'a' component filled with surfacecular alpha component."
  Data.s "vec4","0","diffuse_ml_array","derived_light_diffuse_colour_array","Array of derived light diffuse colours (count set by extra param)"
  Data.s "vec4","0","specular_ml_array","derived_light_specular_colour_array","Array of derived light specular colours (count set by extra param)"
  Data.s "float","","light_number","light_number","The absolute light number of a local light index. Each pass may haveumber of lights passed to it, and each of these lights will haveindex in the overall light list, which will differ from the localht index due to factors like setStartLight and setIteratePerLight.s binding provides the global light index for a local index."
  Data.s "float","","light_casts_shadows","light_casts_shadows","Returns (int) 1 if the  given light casts shadows, 0 otherwise (index set in extraparam)"
  Data.s "","","light_casts_shadows_array","light_casts_shadows_array","Returns (int) 1 if the  given light casts shadows, 0 otherwise (index set in extraparam)"
  Data.s "float","","shadow_extrusion_distance","shadow_extrusion_distance","The distance a shadow volume should be extruded when usingite extrusion programs."
  Data.s "vec4","","camera_pos","camera_position","The current camera's position in world space"
  Data.s "vec4","","camera_pos_os","camera_position_object_space","The current camera's position in object space"
  Data.s "","","camera_relative_position","camera_relative_position","The current camera's position in world space even when camera relative rendering is enabled"
  Data.s "mat4","0","texture_viewproj_matrix","texture_viewproj_matrix","The view/projection matrix of the assigned texture projection frustum.licable to vertex programs which have been specified as the ’shadow receiver’ vertexgram alternative, or where a texture unit is marked as content_type shadow; thisvides details of the view/projection matrix for the current shadow projector. Theional ’extra_params’ entry specifies which light the projector refers to (for thee of content_type shadow where more than one shadow texture may be present in agle pass), where 0 is the default and refers to the first light referenced in thiss."
  Data.s "float","0","texture_viewproj_matrix_array","texture_viewproj_matrix_array","Array of view/projection matrices of the first n texture projection frustums"
  Data.s "mat4","","texture_worldviewproj_matrix","texture_worldviewproj_matrix","The view/projection matrix of the assigned texture projection frustum,bined with the current world matrix"
  Data.s "float","0","texture_worldviewproj_matrix_array","texture_worldviewproj_matrix_array","Array of world/view/projection matrices of the first n texture projection frustums"
  Data.s "mat4","0","spotlight_viewproj_matrix","spotlight_viewproj_matrix","The view/projection matrix of a given spotlight"
  Data.s "float","0","spotlight_viewproj_matrix_array","spotlight_viewproj_matrix_array","Array of view/projection matrix of a given spotlight"
  Data.s "mat4","","spotlight_worldviewproj_matrix","spotlight_worldviewproj_matrix","The view/projection matrix of a given spotlight projection frustum,bined with the current world matrix"
  Data.s "","","spotlight_worldviewproj_matrix_array","spotlight_worldviewproj_matrix_array","An array of the view/projection matrix of a given spotlight projection frustum,bined with the current world matrix"
  Data.s "vec4","0","custom","custom","A custom parameter which will come from the renderable, using 'data' as thentifiers allows you to map a custom parameter on an individual Renderable (seederable::setCustomParameter) to a parameter on a GPU program. It requires that youplete the ’extra_params’ field with the index that was used in thederable::setCustomParameter call, and this will ensure that whenever this Renderableused, it will have it’s custom parameter mapped in. It’s very important that thisameter has been defined on all Renderables that are assigned the material thattains this automatic mapping, otherwise the process will fail."
  Data.s "float","","time","time","provides current elapsed time"
  Data.s "float","0","time_0_x","time_0_x","Single float value, which repeats itself based on given asameter 'cycle time'."
  Data.s "float","","costime_0_x","costime_0_x","Cosine of 'Time0_X'."
  Data.s "float","","sintime_0_x","sintime_0_x","Sine of 'Time0_X'."
  Data.s "float","","tantime_0_x","tantime_0_x","Tangent of 'Time0_X'."
  Data.s "float","","time_0_x_packed","time_0_x_packed","Vector of 'Time0_X', 'SinTime0_X', 'CosTime0_X',nTime0_X'."
  Data.s "float","","time_0_1","time_0_1","Single float value, which represents scaled time value [0..1],ch repeats itself based on given as parameter 'cycle time'."
  Data.s "float","","costime_0_1","costime_0_1","Cosine of 'Time0_1'."
  Data.s "float","","sintime_0_1","sintime_0_1","Sine of 'Time0_1'."
  Data.s "float","","tantime_0_1","tantime_0_1","Tangent of 'Time0_1'."
  Data.s "float","","time_0_1_packed","time_0_1_packed","Vector of 'Time0_1', 'SinTime0_1', 'CosTime0_1',nTime0_1'."
  Data.s "float","","time_0_2pi","time_0_2pi","Single float value, which represents scaled time value [0..2*Pi],ch repeats itself based on given as parameter 'cycle time'."
  Data.s "float","","costime_0_2pi","costime_0_2pi","Cosine of 'Time0_2PI'."
  Data.s "float","","sintime_0_2pi","sintime_0_2pi","Sine of 'Time0_2PI'."
  Data.s "float","","tantime_0_2pi","tantime_0_2pi","Tangent of 'Time0_2PI'."
  Data.s "float","","time_0_2pi_packed","time_0_2pi_packed","Vector of 'Time0_2PI', 'SinTime0_2PI', 'CosTime0_2PI',nTime0_2PI'."
  Data.s "float","","frame_time","frame_time","provides the scaled frame time, returned as a floating point value."
  Data.s "float","","fps","fps","provides the calculated frames per second, returned as a floating point value."
  Data.s "float","","viewport_width","viewport_width","viewport-related valuesCurrent viewport width (in pixels) as floating point value."
  Data.s "float","","viewport_height","viewport_height","Current viewport height (in pixels) as floating point value."
  Data.s "float","","inverse_viewport_width","inverse_viewport_width","This variable represents `1/ViewportWidth`."
  Data.s "float","","inverse_viewport_height","inverse_viewport_height","This variable represents `1/ViewportHeight`."
  Data.s "float","","viewport","viewport_size","Viewport dimensions.ked as `(ViewportWidth, ViewportHeight, 1/ViewportWidth, 1/ViewportHeight)`"
  Data.s "vec4","","view_dir","view_direction","view parametersThis variable provides the view direction vector (world space)."
  Data.s "float","","view_side_vector","view_side_vector","This variable provides the view side vector (world space)."
  Data.s "float","","view_up_vector","view_up_vector","This variable provides the view up vector (world space)."
  Data.s "float","","fov","fov","This variable provides the field of view as a floating point value."
  Data.s "float","","near_clip_distance","near_clip_distance","This variable provides the near clip distance as a floating point value."
  Data.s "float","","far_clip_distance","far_clip_distance","This variable provides the far clip distance as a floating point value."
  Data.s "float","","pass_number","pass_number","provides the pass index number within the techniquethe active material."
  Data.s "float","","pass_iteration_number","pass_iteration_number","provides the current iteration number of the pass. The iterationber is the number of times the current render operation hasn drawn for the active pass."
  Data.s "float","","animation_parametric","animation_parametric","Provides a parametric animation value [0..1], only availablere the renderable specifically implements it.morph animation, sets the parametric value.1) representing the distance between the first position keyframe (bound toitions) and the second position keyframe (bound to the first free texturerdinate) so that the vertex program can interpolate between them. For posemation, indicates a group of up to 4 parametric weight values applying to auence of up to 4 poses (each one bound to x, y, z and w of the constant), one forh pose. The original positions are held in the usual position buffer, and thesets to take those positions to the pose where weight == 1.0 are in the first ’n’e texture coordinates; ’n’ being determined by the value passed toludes_pose_animation. If more than 4 simultaneous poses are required, then you’lld more than 1 shader constant to hold the parametric values, in which case youuld use this binding more than once, referencing a different constant entry; theond one will contain the parametrics for poses 5-8, the third for poses 9-12, andon."
  Data.s "float","","texel_offsets","texel_offsets","Provides the texel offsets required by this rendersystem to mapels to pixels. Packed asbsoluteHorizontalOffset, absoluteVerticalOffset, horizontalOffset / viewportWidth, verticalOffset / viewportHeight)`"
  Data.s "vec4","","scene_depth_range","scene_depth_range","Provides information about the depth range of the scene as viewedm the current camera.sed as `(minDepth, maxDepth, depthRange, 1 / depthRange)`"
  Data.s "vec4","","shadow_scene_depth_range","shadow_scene_depth_range","Provides information about the depth range of the scene as viewedm a given shadow camera. Requires an index parameter which mapsa light index relative to the current light list.sed as `(minDepth, maxDepth, depthRange, 1 / depthRange)`"
  Data.s "","","shadow_scene_depth_range_array","shadow_scene_depth_range_array","Provides an array of information about the depth range of the scene as viewedm a given shadow camera. Requires an index parameter which mapsa light index relative to the current light list.sed as `(minDepth, maxDepth, depthRange, 1 / depthRange)`"
  Data.s "vec4","","shadow_colour","shadow_colour","Provides the fixed shadow colour as configured via SceneManager::setShadowColour;ful for integrated modulative shadows."
  Data.s "vec4","","texture_size","texture_size","Provides texture size of the texture unit (index determined by setAutoConstantl). Packed as `(width, height, depth, numMipMaps)`"
  Data.s "vec4","","inverse_texture_size","inverse_texture_size","Provides inverse texture size of the texture unit (index determined byAutoConstantl). Packed as `(1 / width, 1 / height, 1 / depth, 1 / numMipMaps)`"
  Data.s "vec4","","packed_texture_size","packed_texture_size","Provides packed texture size of the texture unit (index determined byAutoConstantl). Packed as `(width, height, 1 / width, 1 / height)`"
  Data.s "mat4","0","texture_matrix","texture_matrix","Provides the current transform matrix of the texture unit (index determined byAutoConstantl), as seen by the fixed-function pipeline.s requires an index in the ’extra_params’ field, and relates to the ’nth’ texturet of the pass in question.if the given index exceeds the number of texture units available for this pass,n the parameter will be set to Matrix4::IDENTITY."
  Data.s "vec4","","lod_camera_pos","lod_camera_position","Provides the position of the LOD camera in world space, allowing youperform separate LOD calculations in shaders independent of the renderingera. If there is no separate LOD camera then this is the real cameraition. See Camera::setLodCamera."
  Data.s "vec4","","lod_camera_pos_os","lod_camera_position_object_space","Provides the position of the LOD camera in object space, allowing youperform separate LOD calculations in shaders independent of the renderingera. If there is no separate LOD camera then this is the real cameraition. See Camera::setLodCamera."
  Data.s "????","","light_custom","light_custom","Binds custom per-light constants to the shaders. */"
  Data.s "","","point_params","point_params","Point attenuation params.Packed as `(size, constant, linear, quadratic)`"
  Data.s "","","material_lod_index","material_lod_index","the LOD index as selected by the active LodStrategy"
  
EndDataSection	

DisableExplicit

Example of use: (quantification of the normal)

Code: Select all

IncludeFile  "...\shader_editor.pb"

InitEngine3D(#PB_Engine3D_DebugLog):InitSprite():InitKeyboard():InitMouse()

ExamineDesktops():dx=DesktopWidth(0)*0.8:dy=DesktopHeight(0)*0.8
OpenWindow(0, 0,0, DesktopUnscaledX(dx),DesktopUnscaledY(dy), "CreateShaderMaterial - [Esc] quit",#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0), 0, 0, dx, dy, 0, 0, 0)

Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures", #PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures/nvidia", #PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Packs/desert.zip", #PB_3DArchive_Zip)
Parse3DScripts()

SkyBox("desert07.jpg")

Macro lt(face):LoadTexture(#PB_Any,"desert07_"+face+".jpg"):EndMacro
tx_Cubic=CreateCubicTexture(#PB_Any,lt("px"),lt("nx"),lt("py"),lt("ny"),lt("pz"),lt("nz"))
tx_rock_diff=LoadTexture(#PB_Any,"dirt_grayrocky_diffusespecular.jpg")
tx_rock_normal=LoadTexture(#PB_Any,"dirt_grayrocky_normalheight.jpg")

CreateCamera(0, 0, 0, 100, 100):MoveCamera(0,0,8,16):CameraLookAt(0,0,0,0)
CreateLight(0, $ffffff, 8000, 5700,4500);  ;light on the sun of the skybox !
AmbientColor($444444)

CreateCone(0,2,3)
CreateCapsule(1,1,1.5)
CreateSphere(2,1.5,32,32)
CreateTorus(3,1.5,0.6,32,32)
CreateTube(4,1.5,1,2)

CreateShader(0,"%#version 130%uniform mat4 P0;//+0%uniform mat4 P25;//+25%uniform vec4 P79;//+79%uniform vec4 P45;//+45%uniform vec4 P32;//+32%%varying vec3 oviewdir;%varying vec3 olightdir;%varying vec3 onormal;%varying vec4 ovcolor;%varying vec2 ouv;%varying float ofogf;%%void main()%{%vec4 pos=P0*gl_Vertex;%oviewdir=normalize(P79.xyz-pos.xyz);%olightdir=normalize(P45.xyz-pos.xyz);%gl_Position=P25*gl_Vertex;%onormal=gl_Normal;%ouv=(gl_TextureMatrix[0]*gl_MultiTexCoord0).xy;%ovcolor=gl_Color;%ofogf=P32.z>0?min(abs(gl_Position.z)*P32.w,1):0;%}","#version 130%%uniform vec4 P69;//+69%uniform vec4 P71;//+71%uniform vec4 P31;//+31%uniform mat4 P0;//+0%%uniform samplerCube cubemap;//0%uniform sampler2D diffuseMap;//1%%uniform float fc;//4%uniform float glossy;//0.5%%varying vec3 oviewdir;%varying vec3 olightdir;%varying vec3 onormal;%varying vec4 ovcolor;%varying vec2 ouv;%varying float ofogf;%%void main()%{%vec3 normal=normalize(floor(onormal*fc)/fc);normal=mat3(P0)*normal;%vec3 viewdir=normalize(oviewdir);%vec3 lightdir=normalize(olightdir);%%float dif=max(dot(lightdir,normal),0);%vec3 r=reflect(-oviewdir,normal);r.z*=-1;%vec4 tcolor1=texture(diffuseMap,ouv)*ovcolor;%vec4 tcolor2=texture(cubemap,r);%%vec4 color=mix(vec4(tcolor1.rgb,1)*(P69+P71*dif),tcolor2,glossy);%gl_FragColor=mix(color,P31,ofogf);%}%")

Procedure ShaderMaterial()
  Shared tx_Cubic,tx_rock_diff,tx_rock_normal
  For i=0 To 9
    CreateShaderMaterial(i,0)
    MaterialShaderTexture(i,TextureID(tx_Cubic),TextureID(tx_rock_diff),0,0)
    SetMaterialAttribute(i,#PB_Material_TAM,#PB_Material_ClampTAM,0)
    SetMaterialColor(i,3,RGB(128+Random(127),128+Random(127),128+Random(127)))
    MaterialShininess(i,32*Pow(2,Random(5)),$ffffff)
    ;MaterialShaderParameter(i,#PB_Shader_Fragment,"fc",#PB_Shader_Float,Random(6,2),0,0,0)
    MaterialShaderParameter(i,#PB_Shader_Fragment,"glossy",#PB_Shader_Float,Random(3,1)/4,0,0,0)
    CreateEntity(i,MeshID(i%5),MaterialID(i)):RotateEntity(i,Random(360),Random(360),Random(360),#PB_Absolute)
  Next
EndProcedure

editshadermaterial(@ShaderMaterial())

ShaderMaterial()


Procedure CameraUserControl(camera,speed.f=0.1,smooth.f=0.1,yfixed.f=1e10)
  Static.f MouseX,Mousey,depx,depz,sdepx,sdepz,     fdf.b
  
  depx=-speed*(KeyboardPushed(#PB_Key_Left)-KeyboardPushed(#PB_Key_Right))
  depz=-speed*(KeyboardPushed(#PB_Key_Down)-KeyboardPushed(#PB_Key_Up)-MouseWheel()*20)
  If KeyboardReleased(#PB_Key_F12):fdf=1-fdf:If fdf:CameraRenderMode(0,#PB_Camera_Wireframe):Else:CameraRenderMode(0,#PB_Camera_Textured):EndIf:EndIf
  MouseX = -MouseDeltaX() *  0.05
  MouseY = -MouseDeltaY() *  0.05
  RotateCamera(camera, MouseY, MouseX, 0, #PB_Relative)
  sdepx+(depx-sdepx)*smooth
  sdepz+(depz-sdepz)*smooth
  MoveCamera  (camera, sdepX, 0, -sdepz)
  If yfixed<>1e10:MoveCamera(camera,CameraX(camera),yfixed,CameraZ(camera),#PB_Absolute):EndIf
EndProcedure

Repeat
  While WindowEvent():Wend
  ExamineKeyboard()
  ExamineMouse()
  CameraUserControl(0)
  
  da.f+0.001
  For i=0 To 9
    a.f=i*2*#PI/10+da
    MoveEntity(i,Cos(a)*8,2,Sin(a)*8,#PB_Absolute):RotateEntity(i,0.2,0.2,0.2,#PB_Relative)
  Next
  RenderWorld()
  FlipBuffers()    
Until KeyboardReleased(#PB_Key_Escape) Or MouseButton(3)


Re: shader 3D Editor

Posted: Tue Sep 23, 2025 6:42 pm
by marc_256
pf shadoko,

thanks for your post,
I will give it a try, but I need first to understand it ...

It seems to be very useful.

marc

Re: shader 3D Editor

Posted: Tue Sep 23, 2025 7:01 pm
by miso
Thanks for your work, great addition.

Re: shader 3D Editor

Posted: Thu Oct 09, 2025 6:10 pm
by minimy
WOOOOOWWWW! Thanks pf_shadoko!!!
This is the bible of the shaders makers.
I was looking for information about any param of glsl but only found very limited information and a little confuse. Your code is like fresh wind.
Haleluya, haleluya! :lol:

Re: shader 3D Editor

Posted: Thu Oct 09, 2025 6:15 pm
by minimy
Yes marc, with shaders you can make a lot of effects and take the control sending params.
It's really worth the effort to learn them and be able to use them in 3D scenes.
One thing that I am still not entirely clear about is whether the process is carried out entirely by the GPU or also uses the CPU

Re: shader 3D Editor

Posted: Thu Oct 09, 2025 6:36 pm
by minimy
A question i change the glsl in the editor but nothing happend.
Need pass the glsl in this line?
CreateShader(0,"%#version 130%uniform mat4 P0;//+0%uniform mat4 P25;//...... )
I just don't quite understand the syntax of this format to include it in PB (im old haha)