Shader.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. package me.hammerle.snuviengine.api;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.nio.FloatBuffer;
  5. import java.nio.file.Files;
  6. import java.util.LinkedList;
  7. import java.util.List;
  8. import org.lwjgl.BufferUtils;
  9. import static org.lwjgl.opengl.GL11.*;
  10. import static org.lwjgl.opengl.GL14.*;
  11. import static org.lwjgl.opengl.GL20.*;
  12. public final class Shader
  13. {
  14. private static int program = -1;
  15. private static int width = 1024;
  16. private static int height = 600;
  17. private static int scale = 2;
  18. private static final List<Runnable> TASKS = new LinkedList<>();
  19. protected static boolean initDone = false;
  20. private final static FontRenderer FONT_RENDERER = new FontRenderer();
  21. private final static ColorRenderer COLOR_RENDERER = new ColorRenderer();
  22. // uniform stuff
  23. private static int unifViewMatrix = -1;
  24. private static int unifModelMatrix = -1;
  25. private static MatrixStack modelMatrix;
  26. private static int unifAmbientLight = -1;
  27. private static int[][] unifLight;
  28. private static int unifUseTexture = -1;
  29. private static int unifUseColor = -1;
  30. private static int unifUseLight = -1;
  31. protected static void init()
  32. {
  33. program = createShaderProgram("shaders/vertex.vs", "shaders/fragment.fs");
  34. glUseProgram(program);
  35. unifViewMatrix = glGetUniformLocation(program, "viewMatrix");
  36. updateViewMatrix();
  37. unifModelMatrix = glGetUniformLocation(program, "modelMatrix");
  38. modelMatrix = new MatrixStack(20);
  39. updateMatrix();
  40. unifAmbientLight = glGetUniformLocation(program, "ambientLight");
  41. setAmbientLight(1.0f, 1.0f, 1.0f);
  42. unifLight = new int[32][3];
  43. for(int index = 0; index < unifLight.length; index++)
  44. {
  45. unifLight[index][0] = glGetUniformLocation(program, "lights[" + index + "].color");
  46. unifLight[index][1] = glGetUniformLocation(program, "lights[" + index + "].pos");
  47. unifLight[index][2] = glGetUniformLocation(program, "lights[" + index + "].strength");
  48. setLightColor(index, 0.0f, 0.0f, 0.0f);
  49. setLightLocation(index, 0.0f, 0.0f);
  50. setLightStrength(index, 0.0f);
  51. }
  52. unifUseTexture = glGetUniformLocation(program, "useTexture");
  53. setTextureEnabled(false);
  54. unifUseColor = glGetUniformLocation(program, "useColor");
  55. setColorEnabled(false);
  56. unifUseLight = glGetUniformLocation(program, "useLight");
  57. setLightEnabled(false);
  58. setViewPort(width, height);
  59. initDone = true;
  60. }
  61. protected static void addTask(Runnable r)
  62. {
  63. TASKS.add(r);
  64. }
  65. protected static void doTasks()
  66. {
  67. if(!TASKS.isEmpty())
  68. {
  69. TASKS.forEach(r -> r.run());
  70. TASKS.clear();
  71. }
  72. }
  73. public static FontRenderer getFontRenderer()
  74. {
  75. return FONT_RENDERER;
  76. }
  77. public static ColorRenderer getColorRenderer()
  78. {
  79. return COLOR_RENDERER;
  80. }
  81. private static void updateViewMatrix()
  82. {
  83. FloatBuffer buffer = BufferUtils.createFloatBuffer(16);
  84. buffer.put(2.0f / width);
  85. buffer.put(0.0f);
  86. buffer.put(0.0f);
  87. buffer.put(0.0f);
  88. buffer.put(0.0f);
  89. buffer.put(-2.0f / height);
  90. buffer.put(0.0f);
  91. buffer.put(0.0f);
  92. buffer.put(0.0f);
  93. buffer.put(0.0f);
  94. buffer.put(-1.0f / height);
  95. buffer.put(0.0f);
  96. buffer.put(-1.0f);
  97. buffer.put(1.0f);
  98. buffer.put(0.5f);
  99. buffer.put(1.0f);
  100. buffer.flip();
  101. glUniformMatrix4fv(unifViewMatrix, false, buffer);
  102. }
  103. protected static void setViewPort(int width, int height)
  104. {
  105. scale = 1;
  106. while(width / (scale + 1) >= 400 && height / (scale + 1) >= 300)
  107. {
  108. scale++;
  109. }
  110. Shader.width = width / scale;
  111. Shader.height = height / scale;
  112. updateViewMatrix();
  113. }
  114. public static int getViewScale()
  115. {
  116. return scale;
  117. }
  118. public static int getViewWidth()
  119. {
  120. return width;
  121. }
  122. public static int getViewHeight()
  123. {
  124. return height;
  125. }
  126. public static void updateMatrix()
  127. {
  128. glUniformMatrix4fv(unifModelMatrix, false, modelMatrix.getData());
  129. }
  130. public static void pushMatrix()
  131. {
  132. modelMatrix.push();
  133. }
  134. public static void popMatrix()
  135. {
  136. modelMatrix.pop();
  137. }
  138. public static void translate(float tx, float ty)
  139. {
  140. modelMatrix.translate(tx, ty);
  141. }
  142. public static void translateTo(float tx, float ty)
  143. {
  144. modelMatrix.translateTo(tx, ty);
  145. }
  146. public static void scale(float sx, float sy)
  147. {
  148. modelMatrix.scale(sx, sy);
  149. }
  150. public static void rotate(float angle)
  151. {
  152. modelMatrix.rotate(angle);
  153. }
  154. public static void setAmbientLight(float r, float g, float b)
  155. {
  156. glUniform3f(unifAmbientLight, r, g, b);
  157. }
  158. private static void checkLightIndex(int index)
  159. {
  160. if(index < 0 || index > unifLight.length)
  161. {
  162. throw new ShaderException("'" + index + "' is not a valid light index");
  163. }
  164. }
  165. public static void setLightColor(int index, float r, float g, float b)
  166. {
  167. checkLightIndex(index);
  168. glUniform3f(unifLight[index][0], r, g, b);
  169. }
  170. public static void setLightLocation(int index, float x, float y)
  171. {
  172. checkLightIndex(index);
  173. glUniform2f(unifLight[index][1], x, y);
  174. }
  175. public static void setLightStrength(int index, float strength)
  176. {
  177. checkLightIndex(index);
  178. glUniform1f(unifLight[index][2], strength);
  179. }
  180. public static void setTextureEnabled(boolean use)
  181. {
  182. glUniform1i(unifUseTexture, use ? 1 : 0);
  183. }
  184. public static void setColorEnabled(boolean use)
  185. {
  186. glUniform1i(unifUseColor, use ? 1 : 0);
  187. }
  188. public static void setLightEnabled(boolean use)
  189. {
  190. glUniform1i(unifUseLight, use ? 1 : 0);
  191. }
  192. public static void setDepthTestEnabled(boolean use)
  193. {
  194. if(use)
  195. {
  196. glEnable(GL_DEPTH_TEST);
  197. glDepthFunc(GL_LEQUAL);
  198. }
  199. else
  200. {
  201. glDisable(GL_DEPTH_TEST);
  202. }
  203. }
  204. public static void setBlendingEnabled(boolean use)
  205. {
  206. if(use)
  207. {
  208. glEnable(GL_BLEND);
  209. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  210. glBlendEquation(GL_FUNC_ADD);
  211. }
  212. else
  213. {
  214. glDisable(GL_BLEND);
  215. }
  216. }
  217. // -------------------------------------------------------------------------
  218. // general stuff
  219. // -------------------------------------------------------------------------
  220. private static String[] readFile(String path)
  221. {
  222. try
  223. {
  224. File f = new File(path);
  225. List<String> list = Files.readAllLines(f.toPath());
  226. list.replaceAll(s -> s + "\n");
  227. return list.toArray(new String[list.size()]);
  228. }
  229. catch(IOException ex)
  230. {
  231. throw new ShaderException("failed reading shader file '" + path + "'");
  232. }
  233. }
  234. private static String getError()
  235. {
  236. StringBuilder sb = new StringBuilder();
  237. int glErr = glGetError();
  238. while(glErr != GL_NO_ERROR)
  239. {
  240. sb.append(glErr);
  241. sb.append(" ");
  242. glErr = glGetError();
  243. }
  244. return sb.toString();
  245. }
  246. private static int createShaderProgram(String vertex, String fragment)
  247. {
  248. // ---------------------------------------------------------------------
  249. // vertex shader
  250. // ---------------------------------------------------------------------
  251. String vShaderSource[] = readFile(vertex);
  252. int vShader = glCreateShader(GL_VERTEX_SHADER);
  253. glShaderSource(vShader, vShaderSource);
  254. glCompileShader(vShader);
  255. String error = getError();
  256. if(!error.isEmpty())
  257. {
  258. throw new ShaderException("failed compiling vertex shader '" + vertex + "' " + error);
  259. }
  260. int compiled = glGetShaderi(vShader, GL_COMPILE_STATUS);
  261. if(compiled != 1)
  262. {
  263. throw new ShaderException("failed compiling vertex shader '" + vertex + "' " + compiled + " " + glGetShaderInfoLog(vShader));
  264. }
  265. // ---------------------------------------------------------------------
  266. // fragment shader
  267. // ---------------------------------------------------------------------
  268. String fShaderSource[] = readFile(fragment);
  269. int fShader = glCreateShader(GL_FRAGMENT_SHADER);
  270. glShaderSource(fShader, fShaderSource);
  271. glCompileShader(fShader);
  272. error = getError();
  273. if(!error.isEmpty())
  274. {
  275. throw new ShaderException("failed compiling fragment shader '" + fragment + "' " + error);
  276. }
  277. compiled = glGetShaderi(fShader, GL_COMPILE_STATUS);
  278. if(compiled != 1)
  279. {
  280. throw new ShaderException("failed compiling fragment shader '" + fragment + "' " + compiled + " " + glGetShaderInfoLog(fShader));
  281. }
  282. // ---------------------------------------------------------------------
  283. // linking
  284. // ---------------------------------------------------------------------
  285. int vfprogram = glCreateProgram();
  286. glAttachShader(vfprogram, vShader);
  287. glAttachShader(vfprogram, fShader);
  288. glLinkProgram(vfprogram);
  289. error = getError();
  290. if(!error.isEmpty())
  291. {
  292. throw new ShaderException("failed linking shaders '" + vertex + "' and '" + fragment + "' " + error);
  293. }
  294. compiled = glGetProgrami(vfprogram, GL_LINK_STATUS);
  295. if(compiled != 1)
  296. {
  297. throw new ShaderException("failed linking shaders '" + vertex + "' and '" + fragment + "' " + compiled + " " + glGetProgramInfoLog(vfprogram));
  298. }
  299. glDeleteShader(vShader);
  300. glDeleteShader(fShader);
  301. return vfprogram;
  302. }
  303. }