10 #if ( (defined(__MACH__)) && (defined(__APPLE__)) )
11 #define GLFW_INCLUDE_GLCOREARB
12 #include <GLFW/glfw3.h>
13 #include <OpenGL/gl3ext.h>
16 #include <GLFW/glfw3.h>
18 #define STB_IMAGE_IMPLEMENTATION
19 #include "stb/stb_image.h"
23 static void error_callback(
int error,
const char* description) {
25 fputs(description, stderr);
29 const GLchar* vertexShader[] =
32 "uniform vec4 inColor;"
33 "uniform vec3 inSize;"
35 "uniform float inScreenWidth;"
36 "uniform float inScreenHeight;"
37 "in vec3 VertexPosition;"
42 " uv = (VertexPosition + 0.5).xy;"
43 " vec4 x = vec4(2.0 / inScreenWidth, 0.0, 0.0, 0.0);"
44 " vec4 y = vec4(0.0, 2.0 / inScreenHeight, 0.0, 0.0);"
45 " vec4 z = vec4(0.0, 0.0, -2.0 / 2000, 0.0);"
46 " vec4 d = vec4(-1.0, -1.0, 0.0, 1.0);"
47 " mat4 projection = mat4(x, y, z, d);"
48 " vec3 pos = inSize * VertexPosition + inPos;"
49 " gl_Position = projection * vec4(pos, 1.0);"
53 const GLchar* fragmentShader[] =
56 "uniform sampler2D inImage;"
60 "void main() { FragColor = color * texture(inImage, uv); }"
64 static void PrintShaderErrors(GLuint
id,
const std::string& label)
66 std::cerr << label <<
" failed\n";
68 glGetShaderiv(
id, GL_INFO_LOG_LENGTH, &logLen);
71 char* log = (
char*)malloc(logLen);
73 glGetShaderInfoLog(
id, logLen, &written, log);
74 std::cerr <<
"Shader log: " << log << std::endl;
78 static class Window* theInstance = 0;
117 glfwSetErrorCallback(error_callback);
120 fprintf(stderr,
"ERROR: Cannot initialize GLFW\n");
125 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
126 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
127 glfwWindowHint(GLFW_SAMPLES, 4);
128 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
129 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
131 _window = glfwCreateWindow(_windowWidth, _windowHeight,
"TinyGL C++ Window", 0, 0);
133 fprintf(stderr,
"ERROR: Cannot initialize GLFW window\n");
138 glfwMakeContextCurrent(_window);
139 glfwSetKeyCallback(_window, Window::onKeyboardCb);
140 glfwSetMouseButtonCallback(_window, Window::onMouseButtonCb);
141 glfwSetCursorPosCallback(_window, Window::onMouseMotionCb);
142 glfwSetScrollCallback(_window, Window::onScrollCb);
145 if (glewInit() != GLEW_OK)
147 std::cout <<
"Cannot initialize GLEW\n";
153 glEnable(GL_DEPTH_TEST);
154 glDepthFunc(GL_ALWAYS);
155 glEnable(GL_CULL_FACE);
157 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
181 float*
circle =
new float[3*(numTris+2)];
183 float deltaAngle = 2.0f * 3.1415926535897932384626433832795f / numTris;
184 for (
int i = 1; i < numTris+2; i++) {
185 float angle = (i-1) * deltaAngle;
186 circle[i*3+0] = cos(angle);
187 circle[i*3+1] = sin(angle);
192 glEnable(GL_TEXTURE0);
193 glActiveTexture(GL_TEXTURE0);
195 glGenTextures(1, &texId);
196 _textures[
"default"] = Texture{texId, 1, 1};
197 unsigned char defaultTex[4] = { 255,255,255,255 };
198 glBindTexture(GL_TEXTURE_2D, texId);
199 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
200 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1,
201 GL_RGBA, GL_UNSIGNED_BYTE, defaultTex);
202 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
203 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
206 glGenBuffers(1, &vboId);
207 glBindBuffer(GL_ARRAY_BUFFER, vboId);
208 glBufferData(GL_ARRAY_BUFFER, 9 *
sizeof(
float),
triangle, GL_STATIC_DRAW);
210 glGenVertexArrays(1, &_triVao);
211 glBindVertexArray(_triVao);
212 glEnableVertexAttribArray(0);
213 glBindBuffer(GL_ARRAY_BUFFER, vboId);
214 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLubyte*)NULL);
216 glGenBuffers(1, &vboId);
217 glBindBuffer(GL_ARRAY_BUFFER, vboId);
218 glBufferData(GL_ARRAY_BUFFER, 24 *
sizeof(
float),
square, GL_STATIC_DRAW);
220 glGenVertexArrays(1, &_squareVao);
221 glBindVertexArray(_squareVao);
222 glEnableVertexAttribArray(0);
223 glBindBuffer(GL_ARRAY_BUFFER, vboId);
224 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLubyte*)NULL);
226 glGenBuffers(1, &vboId);
227 glBindBuffer(GL_ARRAY_BUFFER, vboId);
228 glBufferData(GL_ARRAY_BUFFER, 3*(numTris+2) *
sizeof(
float),
circle, GL_STATIC_DRAW);
230 glGenVertexArrays(1, &_circleVao);
231 glBindVertexArray(_circleVao);
232 glEnableVertexAttribArray(0);
233 glBindBuffer(GL_ARRAY_BUFFER, vboId);
234 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLubyte*)NULL);
238 GLuint vshaderId = glCreateShader(GL_VERTEX_SHADER);
239 glShaderSource(vshaderId, 1, vertexShader, NULL);
240 glCompileShader(vshaderId);
241 glGetShaderiv(vshaderId, GL_COMPILE_STATUS, &result);
242 if (result == GL_FALSE)
244 PrintShaderErrors(vshaderId,
"Vertex shader");
247 GLuint fshaderId = glCreateShader(GL_FRAGMENT_SHADER);
248 glShaderSource(fshaderId, 1, fragmentShader, NULL);
249 glCompileShader(fshaderId);
250 glGetShaderiv(fshaderId, GL_COMPILE_STATUS, &result);
251 if (result == GL_FALSE)
253 PrintShaderErrors(fshaderId,
"Fragment shader");
256 GLuint shaderId = glCreateProgram();
257 glAttachShader(shaderId, vshaderId);
258 glAttachShader(shaderId, fshaderId);
259 glLinkProgram(shaderId);
260 glGetShaderiv(shaderId, GL_LINK_STATUS, &result);
261 if (result == GL_FALSE)
263 PrintShaderErrors(shaderId,
"Shader link");
266 glUseProgram(shaderId);
267 _colorUniform = glGetUniformLocation(shaderId,
"inColor");
268 _sizeUniform = glGetUniformLocation(shaderId,
"inSize");
269 _posUniform = glGetUniformLocation(shaderId,
"inPos");
271 GLuint widthUniform = glGetUniformLocation(shaderId,
"inScreenWidth");
272 glUniform1f(widthUniform, _windowWidth);
274 GLuint heightUniform = glGetUniformLocation(shaderId,
"inScreenHeight");
275 glUniform1f(heightUniform, _windowHeight);
277 _imageUniform = glGetUniformLocation(shaderId,
"inImage");
278 glUniform1i(_imageUniform, 0);
294 if (!_window)
return;
297 while (!glfwWindowShouldClose(_window)) {
298 float time = glfwGetTime();
299 _dt = time - _elapsedTime;
302 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
306 glfwSwapBuffers(_window);
323 void loadSprite(
const std::string& name,
const std::string& filename) {
326 unsigned char* data = stbi_load(filename.c_str(), &w, &h, &n, 4);
329 std::cout <<
"ERROR: Cannot load texture " << filename<< std::endl;
333 glEnable(GL_TEXTURE0);
334 glActiveTexture(GL_TEXTURE0);
337 if (_textures.count(name) == 0) {
338 glGenTextures(1, &texId);
339 _textures[name] = Texture{texId, w, h};
341 texId = _textures[name].texId;
344 glBindTexture(GL_TEXTURE_2D, texId);
345 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, w, h);
346 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h,
347 GL_RGBA, GL_UNSIGNED_BYTE, data);
349 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
350 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
351 stbi_image_free(data);
370 void sprite(
const std::string& textureName,
float x,
float y,
float scale = 1) {
372 assert(_textures.count(textureName) > 0);
374 Texture& tex = _textures[textureName];
375 glActiveTexture(GL_TEXTURE0);
376 glBindTexture(GL_TEXTURE_2D, tex.texId);
378 glUniform1i(_imageUniform, 0);
379 glUniform3f(_posUniform, x, y, 0);
380 glUniform3f(_sizeUniform, tex.width*scale, tex.height*scale, 1);
381 glBindVertexArray(_squareVao);
382 glDrawArrays(GL_TRIANGLES, 0, 6);
394 Texture& tex = _textures[
"default"];
395 glBindTexture(GL_TEXTURE_2D, tex.texId);
397 glUniform3f(_posUniform, x, y, 0);
399 glBindVertexArray(_squareVao);
400 glDrawArrays(GL_TRIANGLES, 0, 6);
412 Texture& tex = _textures[
"default"];
413 glBindTexture(GL_TEXTURE_2D, tex.texId);
414 glUniform3f(_posUniform, x, y, 0);
416 glBindVertexArray(_triVao);
417 glDrawArrays(GL_TRIANGLES, 0, 3);
427 void circle(
int x,
int y,
float diameter) {
440 Texture& tex = _textures[
"default"];
441 glBindTexture(GL_TEXTURE_2D, tex.texId);
442 glUniform3f(_posUniform, x, y, 0);
444 glBindVertexArray(_circleVao);
445 glDrawArrays(GL_TRIANGLE_FAN, 0, numTris+2);
455 void color(
float r,
float g,
float b,
float a = 1.0f) {
456 glUniform4f(_colorUniform, r, g, b, a);
514 virtual void scroll(
float dx,
float dy) {}
526 virtual void keyUp(
int key,
int mods) {}
551 int state = glfwGetKey(_window, key);
552 return (state == GLFW_PRESS);
564 int state = glfwGetMouseButton(_window, button);
565 return (state == GLFW_PRESS);
573 glfwGetCursorPos(_window, &xpos, &ypos);
574 return static_cast<float>(xpos);
582 glfwGetCursorPos(_window, &xpos, &ypos);
583 return static_cast<float>(ypos);
607 return static_cast<float>(_windowHeight);
614 return static_cast<float>(_windowWidth);
625 glfwSetWindowShouldClose(_window, GL_TRUE);
635 glClearColor(r, g, b, 1.0f);
636 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
640 static void onScrollCb(GLFWwindow* w,
double xoffset,
double yoffset) {
642 static_cast<float>(xoffset),
643 static_cast<float>(yoffset));
645 static void onMouseMotionCb(GLFWwindow* w,
double x,
double y) {
646 theInstance->onMouseMotion(
static_cast<int>(x),
static_cast<int>(y));
649 static void onMouseButtonCb(GLFWwindow* w,
int button,
int action,
int mods) {
650 theInstance->onMouseButton(button, action, mods);
653 static void onKeyboardCb(GLFWwindow* w,
int key,
int code,
int action,
int mods) {
654 theInstance->onKeyboard(key, code, action, mods);
657 void onMouseMotion(
int x,
int y) {
658 int dx =
mouseX() - _lastx;
659 int dy =
mouseY() - _lasty;
663 void onMouseButton(
int button,
int action,
int mods) {
665 glfwGetCursorPos(_window, &xpos, &ypos);
667 if (action == GLFW_PRESS) {
671 }
else if (action == GLFW_RELEASE) {
675 onMouseMotion(
static_cast<float>(xpos),
static_cast<float>(ypos));
678 void onKeyboard(
int key,
int scancode,
int action,
int mods) {
679 if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
680 glfwSetWindowShouldClose(_window, GL_TRUE);
683 if (action == GLFW_PRESS) {
685 }
else if (action == GLFW_RELEASE) {
691 int _windowWidth, _windowHeight;
694 float _lastx, _lasty;
695 struct GLFWwindow* _window = 0;
696 GLuint _triVao, _squareVao, _circleVao;
697 GLuint _colorUniform, _sizeUniform, _posUniform, _imageUniform;
698 const int numTris = 16;
706 std::map<std::string, Texture> _textures;
709 inline GLFWwindow* window()
const {
return _window; }