changed a file name
[public/pos.git] / main.cpp
1
2 #ifdef __APPLE__
3 #define glGenVertexArrays glGenVertexArraysAPPLE
4 #define glBindVertexArray glBindVertexArrayAPPLE
5 #endif
6
7 #define GL_GLEXT_PROTOTYPES // for Linux
8
9 #include <GL/glfw.h>
10 #include <iostream>
11 #include <fstream>
12 #include <stdint.h>
13 #include <stdlib.h>
14 #include <vector>
15 #include <assert.h>
16 #include <string>
17 #include <string.h>
18 #include <cmath>
19
20 #define glError() { \
21   GLenum err = glGetError(); \
22   while (err != GL_NO_ERROR) { \
23     std::cerr << "glError: " << (char *)gluErrorString(err) << " at " << __LINE__; \
24     err = glGetError(); \
25   } \
26 }
27
28 // picopng
29 int decodePNG(std::vector<unsigned char>& out_image, unsigned long& image_width, unsigned long& image_height, const unsigned char* in_png, size_t in_size, bool convert_to_rgba32 = true);
30 ////
31
32 typedef struct {
33   float pos[3];
34 } Vertex;
35
36 typedef struct {
37   uint32_t vbo_id;
38   uint32_t ibo_id;
39   uint32_t vao_id;
40   uint32_t num_poly;
41 } Mesh;
42
43 typedef struct {
44   uint32_t prog_id;
45   uint32_t vert_id;
46   uint32_t frag_id;
47 } Shader;
48
49 Shader shaders[1];
50 Mesh popcan;
51 uint32_t popcan_tex_id;
52
53 char basic_vert_shader[] =
54 "varying vec4 color;"
55 "varying vec2 texcoord;"
56 "void main () {"
57 "  color = vec4(clamp(gl_Vertex.y,0.0,0.7),0.3,0.3,1.0);"
58 "  float theta = atan(gl_Vertex.z, gl_Vertex.x+0.1) + 3.142;"
59 "  texcoord = vec2(theta / 6.28, gl_Vertex.y / 7.0 + 0.5);"
60 "  gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;"
61 "}";
62
63 char basic_frag_shader[] =
64 "uniform sampler2D texture;"
65 "varying vec4 color;"
66 "varying vec2 texcoord;"
67 "void main () {"
68 "  gl_FragColor = mix(color, texture2D(texture, texcoord), 0.7);"
69 "}";
70
71 void render () {
72   glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
73   glLoadIdentity ();
74   glUseProgram (shaders[0].prog_id
75           );
76   static float x = 0;
77   glTranslatef (-8,0,-20);
78   glRotatef (x+=0.01, 0,1,0);
79   glRotatef (30.0, 1.0,0,0);
80
81   GLint shader_tex_loc = glGetUniformLocation(shaders[0].prog_id, "texture");
82   glUniform1i(shader_tex_loc, 0);
83   glActiveTexture(GL_TEXTURE0);
84   glBindTexture(GL_TEXTURE_2D, popcan_tex_id);
85   glError();
86
87   glBindVertexArray (popcan.vao_id);
88   glDrawElements(GL_TRIANGLES, popcan.num_poly, GL_UNSIGNED_INT, 0);
89 }
90
91 void print_shader_error (uint32_t id, uint32_t type) {
92   char *log;
93   GLint length=0, result;
94   if (type == GL_COMPILE_STATUS) glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
95   else               glGetProgramiv (id, GL_INFO_LOG_LENGTH, &length);
96   if (length == 0) {
97     std::cerr << "Unknown error.\n";
98     return;
99   }
100   log = new char[length];
101   if (type == GL_COMPILE_STATUS) glGetShaderInfoLog(id, length, &result, log);
102   else               glGetProgramInfoLog(id, length, &result, log);
103   std::cerr << log << "\n";
104   delete[] log;
105 }
106
107 Mesh load_mesh (std::string filename) {
108   Mesh m;
109   uint32_t object_count = 0;
110
111   std::ifstream fin (filename.c_str ());
112   if (!fin.good ()) { std::cerr << "Couldn't open " << filename << "\n"; exit(1); }
113   std::vector<Vertex> vert_data;
114   std::vector<uint32_t> index_data;
115   while (!fin.eof ()) {
116     char line[128];
117     fin.getline(line, 128);
118   if (line[0] == 'o') {
119     object_count++;
120     if (object_count != 1) { std::cerr << "More than one object in mesh.\n"; exit(1); }
121   } else if (line[0] == 'v') {
122       Vertex v;
123       char *fstr = strtok(&(line[1]), " ");
124       v.pos[0] = atof(fstr);
125       fstr = strtok(NULL, " ");
126       v.pos[1] = atof(fstr);
127       fstr = strtok(NULL, " ");
128       v.pos[2] = atof(fstr);
129       assert (strtok (NULL, " ") == NULL);
130       vert_data.push_back(v);
131     } else if (line[0] == 'f') {
132       char *intstr = strtok(&(line[1]), " ");
133       index_data.push_back(atoi (intstr) - 1);
134       intstr = strtok(NULL, " ");
135       index_data.push_back(atoi (intstr) - 1);
136       intstr = strtok(NULL, " ");
137       index_data.push_back(atoi (intstr) - 1);
138       if (strtok(NULL, " ") != NULL) { std::cerr << "You got some quads bro.\n"; exit (1); }
139     }
140   }
141   glGenVertexArrays (1, &(m.vao_id));
142   glBindVertexArray (m.vao_id);
143
144   glGenBuffers(2, &m.vbo_id);
145   glBindBuffer(GL_ARRAY_BUFFER, m.vbo_id);
146   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m.ibo_id);
147   glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*vert_data.size (), &(vert_data[0]), GL_STATIC_DRAW);
148   glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t)*index_data.size (), &(index_data[0]), GL_STATIC_DRAW);
149   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
150   glEnableVertexAttribArray(0);
151   glBindVertexArray (0);
152   m.num_poly = (uint32_t)index_data.size ();
153   std::cerr << "Loaded " << filename << "\n";
154   return m;
155 }
156
157 uint32_t load_texture (std::string filename) {
158   std::vector<unsigned char> image_data;
159   long unsigned int image_w, image_h;
160
161   size_t png_size;
162   std::ifstream fin(filename.c_str());
163   if (!fin.good ()) { std::cerr << "Couldn't open " << filename << "\n"; exit(1); }
164   fin.seekg(0, std::ios::end);
165   png_size = fin.tellg();
166   fin.seekg(0, std::ios::beg);
167
168   unsigned char png_data[png_size];
169   fin.read((char*)png_data, png_size);
170
171   { int r = decodePNG(image_data, image_w, image_h, png_data, png_size);
172     if(r) { std::cerr << "Couldn't read PNG data from " << filename << "\n"; exit(1); }}
173
174   uint32_t tex_id;
175
176   glGenTextures(1, &tex_id);
177   glBindTexture(GL_TEXTURE_2D, tex_id);
178   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
179   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
180   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
181   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
182   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLint)image_w, (GLint)image_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)&(image_data.at(0)));
183   glGenerateMipmap(GL_TEXTURE_2D);
184   glError();
185   std::cerr << "Loaded " << filename << " (" << image_w << "x" << image_h << ")\n";
186   return tex_id;
187 }
188
189 uint32_t compile_individual_shader (const char *src, uint32_t len, uint32_t type) {
190   uint32_t id = glCreateShader (type);
191   glShaderSource (id, 1, &src, NULL);
192   glCompileShader (id);
193
194   GLint compiled;
195   glGetShaderiv (id, GL_COMPILE_STATUS, &compiled);
196   if (compiled == GL_FALSE) {
197     std::cerr << "Error compiling shader: ";
198     print_shader_error(id, GL_COMPILE_STATUS);
199     exit (1);
200   }
201   return id;
202 }
203
204 Shader make_shader (char* vert_src, uint32_t vert_len, char* frag_src, uint32_t frag_len) {
205   Shader s;
206   s.vert_id = compile_individual_shader (vert_src, vert_len, GL_VERTEX_SHADER);
207   s.frag_id = compile_individual_shader (frag_src, frag_len, GL_FRAGMENT_SHADER);
208   s.prog_id = glCreateProgram ();
209   glAttachShader (s.prog_id, s.frag_id);
210   glAttachShader (s.prog_id, s.vert_id);
211   glLinkProgram (s.prog_id);
212   GLint linked;
213   glGetProgramiv(s.prog_id, GL_LINK_STATUS, &linked);
214   if (linked == GL_FALSE) {
215     std::cerr << "Error linking shader: ";
216     print_shader_error (s.prog_id, GL_COMPILE_STATUS);
217     exit (1);
218   }
219   return s;
220 }
221
222
223
224 void GL_init (float w, float h) {
225   glShadeModel (GL_SMOOTH);
226   glEnable (GL_DEPTH_TEST);
227   glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
228
229   glFrontFace (GL_CCW);
230   glCullFace (GL_BACK);
231   glEnable (GL_CULL_FACE);
232
233   glClearColor (0,0,0,0);
234   glEnable (GL_TEXTURE_2D);
235
236   glViewport (0, 0, w, h);
237
238   // TODO: This code is old and bad, needs to go
239   glMatrixMode (GL_PROJECTION);
240   glLoadIdentity();
241   float near = 0.001;
242   float far = 1000.0;
243   float fH = tan(45.0/360.0*M_PI)*near;
244   float fW = fH*w/h;
245   glFrustum(-fW, fW, -fH, fH, near, far);
246   glMatrixMode (GL_MODELVIEW);
247   // TODO: replace above
248
249   popcan = load_mesh ("can.obj");
250   shaders[0] = make_shader (basic_vert_shader, sizeof (basic_vert_shader), basic_frag_shader, sizeof (basic_frag_shader));
251
252   popcan_tex_id = load_texture("can.png");
253 }
254
255 int main () {
256   float scale = 1;
257   float w = 480*scale;
258   float h = 272*scale;
259   if (!glfwInit () || !glfwOpenWindow (w, h, 8,8,8,0,32,0,GLFW_WINDOW)) {
260     std::cerr << "Something GLFW failed.\n";
261     return 1;
262   }
263   GL_init (w, h);
264
265   int running = 1;
266
267   float t0 = glfwGetTime ();
268   uint32_t frames = 0;
269   //glfwSwapInterval (0); // Uncomment this to test FPS without vsync
270   while (running) {
271     float t = glfwGetTime ();
272     if (t-t0 >= 5.0) {
273       std::cerr << (float)frames/5.0 << " FPS\n";
274       t0 = t;
275       frames = 0;
276     }
277     render ();
278     frames++;
279     glfwSwapBuffers ();
280     running = glfwGetWindowParam (GLFW_OPENED);
281   }
282
283   glfwTerminate ();
284 }