Shader.java 11 KB

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