1 module hoekjed.kern.verver; 2 import bindbc.opengl; 3 import hoekjed.kern; 4 import std.array : replace; 5 import std.conv; 6 7 class VerverFout : Exception { 8 this(string melding) { 9 super("Fout in Verver:\n" ~ melding); 10 } 11 } 12 13 class Verver { 14 public struct BronPaar{ 15 string hoekV, snipperV; 16 } 17 18 public static Verver[BronPaar] ververs; 19 static Verver huidig = null; 20 21 HoekVerver hoekV; 22 SnipperVerver snipperV; 23 protected uint verwijzing; 24 25 public static immutable Vec!4 plaatsvervangerkleur = { 26 [250.0 / 255.0, 176.0 / 255.0, 22.0 / 255.0, 1] 27 }; 28 29 @property public static Verver plaatsvervanger() { 30 static Verver voorbeeld; 31 if (voorbeeld is null) 32 voorbeeld = Verver.laad(kleur_hoekverver, kleur_snipperverver); 33 voorbeeld.zetUniform("kleur", plaatsvervangerkleur); 34 return voorbeeld; 35 } 36 37 final void gebruik() { 38 if (huidig is this) 39 return; 40 glUseProgram(verwijzing); 41 huidig = this; 42 } 43 44 private this(){} 45 46 private this(HoekVerver hoekV, SnipperVerver snipperV) { 47 this.hoekV = hoekV; 48 this.snipperV = snipperV; 49 this.verwijzing = glCreateProgram(); 50 glAttachShader(verwijzing, hoekV.verwijzing); 51 glAttachShader(verwijzing, snipperV.verwijzing); 52 glLinkProgram(verwijzing); 53 54 int volbracht; 55 glGetProgramiv(verwijzing, GL_LINK_STATUS, &volbracht); 56 if (volbracht == 0) 57 throw new VerverFout( 58 "Kon Verver " ~ verwijzing.to!string ~ " niet samenstellen:\n" ~ krijg_foutmelding()); 59 } 60 61 /// Laadt Ververs met gegeven verversbestanden. Hergebruikt (deel)ververs indien mogelijk. 62 public static Verver laad(string hoekV, string snipperV){ 63 Verver verver = Verver.ververs.get(BronPaar(hoekV, snipperV), null); 64 if(verver is null){ 65 HoekVerver hV = HoekVerver.ververs.get(hoekV, new HoekVerver(hoekV)); 66 SnipperVerver sV = SnipperVerver.ververs.get(snipperV, new SnipperVerver(snipperV)); 67 verver = new Verver(hV, sV); 68 Verver.ververs[BronPaar(hoekV, snipperV)] = verver; 69 } 70 return verver; 71 } 72 73 void zetUniform(Zicht zicht) { 74 this.zetUniform("projectieM", zicht.projectieM); 75 this.zetUniform("zichtM", zicht.zichtM); 76 } 77 78 void zetUniform(V : Mat!(L, 1, S), uint L, S)(string naam, V waarde) 79 if (L >= 1 && L <= 4) { // zet Vec 80 const int uniformplek = glGetUniformLocation(verwijzing, naam.ptr); 81 if (uniformplek == -1) 82 return foutmelding_ontbrekende_uniform(naam); 83 84 enum string waardes = "waarde.x" ~ (L == 1 ? "" : ",waarde.y" ~ (L == 2 85 ? "" : ",waarde.z" ~ (L == 3 ? "" : ",waarde.w"))); 86 enum string soort = is(S == uint) ? "ui" : (is(S == int) 87 ? "i" : (is(S == float) ? "f" : (is(S == double) ? "d" : ""))); 88 static assert(soort != "", "Soort " ~ S ~ " niet ondersteund voor zetUniform."); 89 mixin("glProgramUniform" ~ L.to!string ~ soort ~ "(verwijzing, uniformplek, " ~ waardes ~ ");"); 90 } 91 92 void zetUniform(V : Mat!(L, 1, S)[], uint L, S)(string naam, V waarde) 93 if (L >= 1 && L <= 4) { // zet Vec[] 94 const int uniformplek = glGetUniformLocation(verwijzing, naam.ptr); 95 if (uniformplek == -1) 96 foutmelding_ontbrekende_uniform(naam); 97 98 enum string soort = is(S == uint) ? "ui" : (is(S == int) 99 ? "i" : (is(S == float) ? "f" : (is(S == double) ? "d" : ""))); 100 static assert(soort != "", "Soort " ~ S ~ " niet ondersteund voor zetUniform."); 101 mixin("glProgramUniform" ~ L.to!string ~ soort 102 ~ "v(verwijzing, uniformplek, cast(uint) waarde.length, cast(" ~ S.stringof ~ "*) waarde.ptr);"); 103 } 104 105 void zetUniform(V : Mat!(R, K, nauwkeurigheid), uint R, uint K)(string naam, V waarde) 106 if (R > 1 && R <= 4 && K > 1 && K <= 4) { // Zet Mat 107 const int uniformplek = glGetUniformLocation(verwijzing, naam.ptr); 108 if (uniformplek == -1) 109 return foutmelding_ontbrekende_uniform(naam); 110 111 mixin("glProgramUniformMatrix" ~ (R == K ? K.to!string : (K.to!string ~ "x" ~ R.to!string)) ~ ( 112 is(nauwkeurigheid == float) ? "f" : "d") ~ "v(verwijzing, uniformplek, 1, true, waarde[0].ptr);"); 113 } 114 115 void zetUniform(V : Mat!(R, K, nauwkeurigheid)[], uint R, uint K)(string naam, V waarde) 116 if (R > 1 && R <= 4 && K > 1 && K <= 4) { // Zet Mat[] 117 const int uniformplek = glGetUniformLocation(verwijzing, naam.ptr); 118 if (uniformplek == -1) 119 return foutmelding_ontbrekende_uniform(naam); 120 121 mixin("glProgramUniformMatrix" ~ (R == K ? K.to!string : (K.to!string ~ "x" ~ R.to!string)) ~ ( 122 is(nauwkeurigheid == float) 123 ? "f" : "d") ~ "v(verwijzing, uniformplek, waarde.length, true, waarde.ptr);"); 124 } 125 126 private string krijg_foutmelding() { 127 int lengte; 128 glGetProgramiv(this.verwijzing, GL_INFO_LOG_LENGTH, &lengte); 129 char[] melding = new char[lengte]; 130 glGetProgramInfoLog(this.verwijzing, lengte, null, melding.ptr); 131 return cast(string) melding.idup; 132 } 133 134 private void foutmelding_ontbrekende_uniform(string naam) { 135 import std.stdio; 136 137 stderr.writeln( 138 "Verver " ~ verwijzing.to!string ~ " kon uniform " ~ naam 139 ~ " niet vinden.\n" ~ krijg_foutmelding()); 140 } 141 142 public static string kleur_hoekverver = ` 143 #version 460 144 145 layout(location=0)in vec3 h_plek; 146 layout(location=1)in vec3 h_normaal; 147 layout(location=2)in vec2 h_beeldplek; 148 149 uniform mat4 projectieM; 150 uniform mat4 zichtM; 151 uniform mat4 tekenM; 152 153 out vec4 gl_Position; 154 155 void main(){ 156 gl_Position = projectieM * zichtM * tekenM * vec4(h_plek, 1.0); 157 } 158 `; 159 160 public static string kleur_snipperverver = ` 161 #version 460 162 163 uniform vec4 kleur; 164 165 out vec4 u_kleur; 166 167 void main(){ 168 u_kleur = kleur; 169 } 170 `; 171 } 172 173 alias HoekVerver = DeelVerver!GL_VERTEX_SHADER; 174 alias SnipperVerver = DeelVerver!GL_FRAGMENT_SHADER; 175 176 class DeelVerver(uint soort) { 177 protected uint verwijzing; 178 179 static DeelVerver!(soort)[string] ververs; 180 181 private string krijg_foutmelding() { 182 int lengte; 183 glGetShaderiv(this.verwijzing, GL_INFO_LOG_LENGTH, &lengte); 184 char[] melding = new char[lengte]; 185 glGetShaderInfoLog(this.verwijzing, lengte, null, &melding[0]); 186 return cast(string) melding.idup; 187 } 188 189 this(string bestand) { 190 import std.file : readText, exists; 191 192 this.verwijzing = glCreateShader(soort); 193 string bron; 194 if (exists(bestand)) // Gegeven bestand is een verwijzing naar een bestand met verfinhoud. 195 bron = readText(bestand); 196 else // Gegeven bestand is verfinhoud. 197 bron = bestand; 198 bron = bron.replace("nauwkeurigheid", nauwkeurigheid.stringof); 199 static if (is(nauwkeurigheid == double)) { 200 bron = bron.replace(" vec", " dvec"); 201 bron = bron.replace(" mat", " dmat"); 202 } 203 auto p = bron.ptr; 204 glShaderSource(verwijzing, 1, &p, null); 205 glCompileShader(verwijzing); 206 207 int volbracht; 208 glGetShaderiv(verwijzing, GL_COMPILE_STATUS, &volbracht); 209 if (volbracht == 0) 210 throw new VerverFout("Kon DeelVerver " ~ verwijzing.to!string ~ " niet bouwen:\n" ~ cast( 211 string) krijg_foutmelding()); 212 213 this.ververs[bestand] = this; 214 } 215 }