|
@@ -0,0 +1,243 @@
|
|
|
+#include "Angel.h"
|
|
|
+#include <fstream>
|
|
|
+#include <iostream>
|
|
|
+#include <vector>
|
|
|
+
|
|
|
+const int NumTriangles = 64770; // (6 faces)(2 triangles/face)
|
|
|
+const int NumVertices = 3 * NumTriangles;
|
|
|
+const int TextureWidth = 256;
|
|
|
+const int TextureHeight = 128;
|
|
|
+
|
|
|
+typedef Angel::vec4 point4;
|
|
|
+typedef Angel::vec4 color4;
|
|
|
+
|
|
|
+// Texture objects and storage for texture image
|
|
|
+GLuint textures[1];
|
|
|
+
|
|
|
+GLubyte image[TextureWidth][TextureHeight][3];
|
|
|
+
|
|
|
+// Vertex data arrays
|
|
|
+point4 points[NumVertices];
|
|
|
+vec2 tex_coords[NumVertices];
|
|
|
+
|
|
|
+// Array of rotation angles (in degrees) for each coordinate axis
|
|
|
+enum { Xaxis = 0, Yaxis = 1, Zaxis = 2, NumAxes = 3 };
|
|
|
+int Axis = Xaxis;
|
|
|
+GLfloat Theta[NumAxes] = {0.0, 0.0, 0.0};
|
|
|
+GLuint theta;
|
|
|
+
|
|
|
+//----------------------------------------------------------------------------
|
|
|
+
|
|
|
+void load_model(const std::string &file_name) {
|
|
|
+ std::vector<point4> vertices;
|
|
|
+ std::vector<vec2> tex_cods;
|
|
|
+ std::fstream s(file_name, std::fstream::in);
|
|
|
+ if (!s.is_open()) {
|
|
|
+ std::cerr << "failed to open" << file_name << std::endl;
|
|
|
+ } else {
|
|
|
+ int index = 0;
|
|
|
+ std::string t;
|
|
|
+ float x, y, z;
|
|
|
+ int a, b, c;
|
|
|
+ int num = 0;
|
|
|
+ while (s >> t) {
|
|
|
+ if (t == "v") { // vertices
|
|
|
+ s >> x >> y >> z;
|
|
|
+ vertices.emplace_back(x / 50.0f, z / 50.0f, y / 50.0f, 1.0);
|
|
|
+ } else if (t == "vt") {
|
|
|
+ s >> x >> y;
|
|
|
+ tex_cods.emplace_back(x, y);
|
|
|
+ } else if (t == "f") {
|
|
|
+ s >> a >> b >> c;
|
|
|
+ a--;
|
|
|
+ b--;
|
|
|
+ c--;
|
|
|
+ points[index] = vertices[a];
|
|
|
+ tex_coords[index] = tex_cods[a];
|
|
|
+ index++;
|
|
|
+ points[index] = vertices[b];
|
|
|
+ tex_coords[index] = tex_cods[b];
|
|
|
+ index++;
|
|
|
+ points[index] = vertices[c];
|
|
|
+ tex_coords[index] = tex_cods[c];
|
|
|
+ index++;
|
|
|
+ num++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ std::cout << "There are " << vertices.size() << "vertice(s)"
|
|
|
+ << ", " << tex_cods.size() << "tex cor(s)" << std::endl
|
|
|
+ << "There are " << num << "fragment(s)" << std::endl;
|
|
|
+ s.close();
|
|
|
+ }
|
|
|
+}
|
|
|
+//----------------------------------------------------------------------------
|
|
|
+
|
|
|
+void load_tex(const std::string &file_name) {
|
|
|
+ char cline[1024];
|
|
|
+ char p6[10];
|
|
|
+ int width;
|
|
|
+ int height;
|
|
|
+ int depth;
|
|
|
+ FILE *fp = fopen(file_name.data(), "rb");
|
|
|
+ fgets(cline, sizeof(cline), fp);
|
|
|
+ sscanf(cline, "%s %d %d %d", p6, &width, &height, &depth);
|
|
|
+ std::cout << p6 << "," << width << "," << height << "," << depth << std::endl;
|
|
|
+ fread(image, sizeof(GLubyte), width * height * 3, fp);
|
|
|
+ fclose(fp);
|
|
|
+}
|
|
|
+
|
|
|
+void init() {
|
|
|
+ load_tex("gc_tex.ppm");
|
|
|
+ load_model("gc_tex.obj");
|
|
|
+
|
|
|
+ // Initialize texture objects
|
|
|
+ glGenTextures(1, textures);
|
|
|
+
|
|
|
+ glBindTexture(GL_TEXTURE_2D, textures[0]);
|
|
|
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TextureWidth, TextureHeight, 0, GL_RGB,
|
|
|
+ GL_UNSIGNED_BYTE, image);
|
|
|
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
|
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
|
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
+
|
|
|
+ glActiveTexture(GL_TEXTURE0);
|
|
|
+ glBindTexture(GL_TEXTURE_2D, textures[0]);
|
|
|
+
|
|
|
+ // Create a vertex array object
|
|
|
+ GLuint vao;
|
|
|
+ glGenVertexArrays(1, &vao);
|
|
|
+ glBindVertexArray(vao);
|
|
|
+
|
|
|
+ // Create and initialize a buffer object
|
|
|
+ GLuint buffer;
|
|
|
+ glGenBuffers(1, &buffer);
|
|
|
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
|
|
+ glBufferData(GL_ARRAY_BUFFER, sizeof(points) + sizeof(tex_coords), NULL,
|
|
|
+ GL_STATIC_DRAW);
|
|
|
+
|
|
|
+ // Specify an offset to keep track of where we're placing data in our
|
|
|
+ // vertex array buffer. We'll use the same technique when we
|
|
|
+ // associate the offsets with vertex attribute pointers.
|
|
|
+ GLintptr offset = 0;
|
|
|
+ glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(points), points);
|
|
|
+ offset += sizeof(points);
|
|
|
+
|
|
|
+ glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(tex_coords), tex_coords);
|
|
|
+
|
|
|
+ // Load shaders and use the resulting shader program
|
|
|
+ GLuint program = InitShader("vshader71.glsl", "fshader71.glsl");
|
|
|
+ glUseProgram(program);
|
|
|
+
|
|
|
+ // set up vertex arrays
|
|
|
+ offset = 0;
|
|
|
+ GLuint vPosition = glGetAttribLocation(program, "vPosition");
|
|
|
+ glEnableVertexAttribArray(vPosition);
|
|
|
+ glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0,
|
|
|
+ BUFFER_OFFSET(offset));
|
|
|
+ offset += sizeof(points);
|
|
|
+
|
|
|
+ GLuint vTexCoord = glGetAttribLocation(program, "vTexCoord");
|
|
|
+ glEnableVertexAttribArray(vTexCoord);
|
|
|
+ glVertexAttribPointer(vTexCoord, 2, GL_FLOAT, GL_FALSE, 0,
|
|
|
+ BUFFER_OFFSET(offset));
|
|
|
+
|
|
|
+ // Set the value of the fragment shader texture sampler variable
|
|
|
+ // ("texture") to the the appropriate texture unit. In this case,
|
|
|
+ // zero, for GL_TEXTURE0 which was previously set by calling
|
|
|
+ // glActiveTexture().
|
|
|
+ glUniform1i(glGetUniformLocation(program, "tex"), 0);
|
|
|
+
|
|
|
+ theta = glGetUniformLocation(program, "theta");
|
|
|
+
|
|
|
+ glEnable(GL_DEPTH_TEST);
|
|
|
+
|
|
|
+ glClearColor(1.0, 1.0, 1.0, 1.0);
|
|
|
+}
|
|
|
+
|
|
|
+void display(void) {
|
|
|
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
+
|
|
|
+ glUniform3fv(theta, 1, Theta);
|
|
|
+
|
|
|
+ glDrawArrays(GL_TRIANGLES, 0, NumVertices);
|
|
|
+
|
|
|
+ glutSwapBuffers();
|
|
|
+}
|
|
|
+
|
|
|
+//----------------------------------------------------------------------------
|
|
|
+
|
|
|
+void mouse(int button, int state, int x, int y) {
|
|
|
+ if (state == GLUT_DOWN) {
|
|
|
+ switch (button) {
|
|
|
+ case GLUT_LEFT_BUTTON:
|
|
|
+ Axis = Xaxis;
|
|
|
+ break;
|
|
|
+ case GLUT_MIDDLE_BUTTON:
|
|
|
+ Axis = Yaxis;
|
|
|
+ break;
|
|
|
+ case GLUT_RIGHT_BUTTON:
|
|
|
+ Axis = Zaxis;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//----------------------------------------------------------------------------
|
|
|
+
|
|
|
+void idle(void) {
|
|
|
+ Theta[Axis] += 0.5;
|
|
|
+
|
|
|
+ if (Theta[Axis] > 360.0) {
|
|
|
+ Theta[Axis] -= 360.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ glutPostRedisplay();
|
|
|
+}
|
|
|
+
|
|
|
+//----------------------------------------------------------------------------
|
|
|
+
|
|
|
+void keyboard(unsigned char key, int mousex, int mousey) {
|
|
|
+ switch (key) {
|
|
|
+ case 033: // Escape Key
|
|
|
+ case 'q':
|
|
|
+ case 'Q':
|
|
|
+ exit(EXIT_SUCCESS);
|
|
|
+ break;
|
|
|
+ case 'b':
|
|
|
+ case 'B':
|
|
|
+ glutIdleFunc(idle);
|
|
|
+ break;
|
|
|
+ case 'e':
|
|
|
+ case 'E':
|
|
|
+ glutIdleFunc(NULL);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ glutPostRedisplay();
|
|
|
+}
|
|
|
+
|
|
|
+//----------------------------------------------------------------------------
|
|
|
+
|
|
|
+int main(int argc, char **argv) {
|
|
|
+ glutInit(&argc, argv);
|
|
|
+ glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
|
|
|
+ glutInitWindowSize(512, 512);
|
|
|
+ glutInitContextVersion(3, 1);
|
|
|
+ glutInitContextProfile(GLUT_CORE_PROFILE);
|
|
|
+ glutCreateWindow("flying");
|
|
|
+
|
|
|
+ if (glewInit() != GLEW_OK) {
|
|
|
+ std::cerr << "Failed to initialize GLEW ... exiting" << std::endl;
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
+ }
|
|
|
+
|
|
|
+ init();
|
|
|
+
|
|
|
+ glutDisplayFunc(display);
|
|
|
+ glutKeyboardFunc(keyboard);
|
|
|
+ glutMouseFunc(mouse);
|
|
|
+ glutIdleFunc(idle);
|
|
|
+
|
|
|
+ glutMainLoop();
|
|
|
+ return 0;
|
|
|
+}
|