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