├── Angelina_Jolie ├── Angelina_Jolie_0001.txt ├── Angelina_Jolie_0002.txt ├── Angelina_Jolie_0003.txt ├── Angelina_Jolie_0004.txt ├── Angelina_Jolie_0005.txt ├── Angelina_Jolie_0006.txt ├── Angelina_Jolie_0007.txt ├── Angelina_Jolie_0008.txt ├── Angelina_Jolie_0009.txt ├── Angelina_Jolie_0010.txt ├── Angelina_Jolie_0011.txt ├── Angelina_Jolie_0012.txt ├── Angelina_Jolie_0013.txt ├── Angelina_Jolie_0014.txt ├── Angelina_Jolie_0015.txt ├── Angelina_Jolie_0016.txt ├── Angelina_Jolie_0017.txt ├── Angelina_Jolie_0018.txt ├── Angelina_Jolie_0019.txt ├── Angelina_Jolie_0020.txt ├── Angelina_Jolie_0001.jpg ├── Angelina_Jolie_0002.jpg ├── Angelina_Jolie_0003.jpg ├── Angelina_Jolie_0004.jpg ├── Angelina_Jolie_0005.jpg ├── Angelina_Jolie_0006.jpg ├── Angelina_Jolie_0007.jpg ├── Angelina_Jolie_0008.jpg ├── Angelina_Jolie_0009.jpg ├── Angelina_Jolie_0010.jpg ├── Angelina_Jolie_0011.jpg ├── Angelina_Jolie_0012.jpg ├── Angelina_Jolie_0013.jpg ├── Angelina_Jolie_0014.jpg ├── Angelina_Jolie_0015.jpg ├── Angelina_Jolie_0016.jpg ├── Angelina_Jolie_0017.jpg ├── Angelina_Jolie_0018.jpg ├── Angelina_Jolie_0019.jpg └── Angelina_Jolie_0020.jpg ├── README.md ├── stdafx.cpp ├── stdafx.h ├── .gitignore ├── CMakeLists.txt ├── targetver.h ├── OGL_OCV_common.h ├── OGL_OCV_common.cpp ├── HeadPose.cpp ├── glm.h └── glm.cpp /Angelina_Jolie/Angelina_Jolie_0001.txt: -------------------------------------------------------------------------------- 1 | 104 113 2 | 149 112 3 | 131 139 4 | 97 155 5 | 146 155 6 | 49 102 7 | 152 91 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0002.txt: -------------------------------------------------------------------------------- 1 | 101 113 2 | 146 115 3 | 124 139 4 | 107 157 5 | 142 157 6 | 75 96 7 | 174 100 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0003.txt: -------------------------------------------------------------------------------- 1 | 108 113 2 | 152 108 3 | 139 141 4 | 114 155 5 | 149 150 6 | 61 94 7 | 153 85 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0004.txt: -------------------------------------------------------------------------------- 1 | 101 107 2 | 149 110 3 | 120 129 4 | 99 151 5 | 141 152 6 | 77 121 7 | 184 123 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0005.txt: -------------------------------------------------------------------------------- 1 | 101 110 2 | 148 113 3 | 123 142 4 | 105 161 5 | 143 164 6 | 75 85 7 | 191 93 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0006.txt: -------------------------------------------------------------------------------- 1 | 102 109 2 | 145 111 3 | 124 138 4 | 106 154 5 | 143 155 6 | 73 104 7 | 178 102 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0007.txt: -------------------------------------------------------------------------------- 1 | 100 111 2 | 145 112 3 | 118 125 4 | 103 154 5 | 139 152 6 | 83 124 7 | 180 128 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0008.txt: -------------------------------------------------------------------------------- 1 | 101 108 2 | 148 113 3 | 121 130 4 | 103 152 5 | 137 153 6 | 88 110 7 | 176 120 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0009.txt: -------------------------------------------------------------------------------- 1 | 99 108 2 | 142 110 3 | 111 133 4 | 104 152 5 | 134 155 6 | 104 99 7 | 193 111 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0010.txt: -------------------------------------------------------------------------------- 1 | 101 107 2 | 147 109 3 | 125 139 4 | 101 151 5 | 140 152 6 | 75 74 7 | 182 75 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0011.txt: -------------------------------------------------------------------------------- 1 | 111 112 2 | 142 115 3 | 135 132 4 | 105 146 5 | 135 156 6 | 58 103 7 | 146 122 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0012.txt: -------------------------------------------------------------------------------- 1 | 105 120 2 | 144 104 3 | 141 133 4 | 120 158 5 | 148 147 6 | 52 122 7 | 133 93 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0013.txt: -------------------------------------------------------------------------------- 1 | 93 117 2 | 129 112 3 | 104 137 4 | 100 161 5 | 133 157 6 | 91 98 7 | 184 105 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0014.txt: -------------------------------------------------------------------------------- 1 | 102 110 2 | 147 110 3 | 128 136 4 | 110 154 5 | 141 153 6 | 63 83 7 | 168 84 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0015.txt: -------------------------------------------------------------------------------- 1 | 100 115 2 | 146 111 3 | 125 141 4 | 112 157 5 | 141 155 6 | 68 91 7 | 179 93 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0016.txt: -------------------------------------------------------------------------------- 1 | 102 109 2 | 146 111 3 | 121 135 4 | 107 155 5 | 137 155 6 | 89 90 7 | 187 95 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0017.txt: -------------------------------------------------------------------------------- 1 | 97 113 2 | 146 102 3 | 127 139 4 | 117 162 5 | 153 154 6 | 68 99 7 | 186 77 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0018.txt: -------------------------------------------------------------------------------- 1 | 103 108 2 | 145 114 3 | 124 126 4 | 105 153 5 | 133 154 6 | 75 121 7 | 174 131 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0019.txt: -------------------------------------------------------------------------------- 1 | 103 115 2 | 142 111 3 | 117 137 4 | 106 159 5 | 138 156 6 | 95 107 7 | 193 106 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0020.txt: -------------------------------------------------------------------------------- 1 | 102 108 2 | 144 114 3 | 116 136 4 | 104 152 5 | 132 153 6 | 96 100 7 | 198 106 8 | -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0001.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0002.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0003.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0003.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0004.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0004.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0005.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0005.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0006.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0006.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0007.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0007.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0008.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0008.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0009.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0009.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0010.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0010.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0011.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0011.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0012.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0012.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0013.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0013.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0014.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0014.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0015.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0015.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0016.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0016.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0017.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0017.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0018.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0018.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0019.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0019.jpg -------------------------------------------------------------------------------- /Angelina_Jolie/Angelina_Jolie_0020.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/HeadPosePnP/master/Angelina_Jolie/Angelina_Jolie_0020.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HeadPosePnP 2 | =========== 3 | 4 | Head pose estimation using PnP 5 | 6 | - Compile using CMake 7 | 8 | See http://www.morethantechnical.com/2012/10/17/head-pose-estimation-with-opencv-opengl-revisited-w-code/ for tutorial and wlakthrough. 9 | -------------------------------------------------------------------------------- /stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // HeadPose.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #include 11 | //#include 12 | 13 | 14 | // TODO: reference additional headers your program requires here 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # CMake stuff 2 | 3 | CMakeCache.txt 4 | CMakeFiles 5 | Makefile 6 | cmake_install.cmake 7 | install_manifest.txt 8 | 9 | # c++ stuff 10 | 11 | # Compiled Object files 12 | *.slo 13 | *.lo 14 | *.o 15 | 16 | # Compiled Dynamic libraries 17 | *.so 18 | *.dylib 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | 25 | 26 | # OSX stuff 27 | 28 | .DS_Store 29 | .AppleDouble 30 | .LSOverride 31 | Icon 32 | 33 | 34 | # Thumbnails 35 | ._* 36 | 37 | # Files that might appear on external disk 38 | .Spotlight-V100 39 | .Trashes 40 | 41 | 42 | # my stuff 43 | build/ 44 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.6) 2 | project (SimpleHeadPoseEstimator) 3 | 4 | find_package(OpenCV REQUIRED) 5 | find_package(OpenGL REQUIRED) 6 | find_package(GLUT REQUIRED) 7 | 8 | file(GLOB SHPE_SOURCES 9 | *.cpp *.h *.c) 10 | 11 | include_directories(${OPENGL_INCLUDE_DIRS}) 12 | include_directories(${GLUT_INCLUDE_DIR}) 13 | 14 | IF(APPLE) 15 | # we need the X11 OpenGL and not the OSX internal 16 | include_directories(/usr/X11/include/) 17 | link_directories(/usr/X11/lib) 18 | ENDIF(APPLE) 19 | 20 | add_executable(SHPE ${SHPE_SOURCES}) 21 | 22 | target_link_libraries(SHPE ${OpenCV_LIBS} ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES}) 23 | 24 | IF(APPLE) 25 | target_link_libraries(SHPE GL X11 GLU GLUT) 26 | ENDIF(APPLE) 27 | -------------------------------------------------------------------------------- /targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // The following macros define the minimum required platform. The minimum required platform 4 | // is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run 5 | // your application. The macros work by enabling all features available on platform versions up to and 6 | // including the version specified. 7 | 8 | // Modify the following defines if you have to target a platform prior to the ones specified below. 9 | // Refer to MSDN for the latest info on corresponding values for different platforms. 10 | #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. 11 | #define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. 12 | #endif 13 | 14 | -------------------------------------------------------------------------------- /OGL_OCV_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OGL_OCV_common.h 3 | * HeadReplacement 4 | * 5 | * Created by Roy Shilkrot on 11/21/11. 6 | * Copyright 2011 MIT. All rights reserved. 7 | * 8 | */ 9 | 10 | #include 11 | 12 | using namespace cv; 13 | 14 | #if defined(__APPLE__) 15 | # include 16 | #elif defined(__linux__) || defined(__MINGW32__) || defined(WIN32) 17 | # define GLEW_STATIC 18 | //# include 19 | //# include 20 | # include 21 | # include 22 | //# include 23 | #else 24 | # include 25 | #endif 26 | 27 | void copyImgToTex(const Mat& _tex_img, GLuint* texID, double* _twr, double* _thr); 28 | 29 | typedef struct my_texture { 30 | GLuint tex_id; 31 | double twr,thr,aspect_w2h; 32 | Mat image; 33 | my_texture():tex_id(-1),twr(1.0),thr(1.0) {} 34 | bool initialized; 35 | void set(const Mat& ocvimg) { 36 | ocvimg.copyTo(image); 37 | copyImgToTex(image, &tex_id, &twr, &thr); 38 | aspect_w2h = (double)ocvimg.cols/(double)ocvimg.rows; 39 | } 40 | } OpenCVGLTexture; 41 | 42 | void glEnable2D(); // setup 2D drawing 43 | void glDisable2D(); // end 2D drawing 44 | OpenCVGLTexture MakeOpenCVGLTexture(const Mat& _tex_img); // create an OpenCV-OpenGL image 45 | void drawOpenCVImageInGL(const OpenCVGLTexture& tex); // draw an OpenCV-OpenGL image 46 | -------------------------------------------------------------------------------- /OGL_OCV_common.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * OGL_OCV_common.cpp 3 | * Common interop between OpenCV and OpenGL 4 | * 5 | * Created by Roy Shilkrot on 11/21/11. 6 | * Copyright 2011 MIT. All rights reserved. 7 | * 8 | */ 9 | 10 | #include "OGL_OCV_common.h" 11 | 12 | void drawOpenCVImageInGL(const OpenCVGLTexture& tex) { 13 | glDisable(GL_LIGHTING); 14 | glDisable(GL_BLEND); 15 | 16 | int vPort[4]; glGetIntegerv(GL_VIEWPORT, vPort); 17 | 18 | glEnable(GL_TEXTURE_2D); 19 | glBindTexture(GL_TEXTURE_2D, tex.tex_id); 20 | glPushMatrix(); 21 | glColor3ub(255, 255, 255); 22 | 23 | glScaled(vPort[3], vPort[3], 1); 24 | 25 | double aw2h = tex.aspect_w2h, ithr = tex.thr, itwr = tex.twr; 26 | double n[3] = {0,0,-1}; 27 | 28 | GLint face_ori; glGetIntegerv(GL_FRONT_FACE, &face_ori); 29 | glFrontFace(GL_CW); //we're gonna draw clockwise 30 | 31 | glBegin(GL_QUADS); 32 | 33 | glTexCoord2d(0, 0); 34 | glNormal3dv(n); 35 | glVertex2d(0, 0); 36 | 37 | glTexCoord2d(0, ithr); 38 | glNormal3dv(n); 39 | glVertex2d(0, 1); 40 | 41 | glTexCoord2d(itwr, ithr); 42 | glNormal3dv(n); 43 | glVertex2d(aw2h, 1); 44 | 45 | glTexCoord2d(itwr, 0); 46 | glNormal3dv(n); 47 | glVertex2d(aw2h, 0); 48 | 49 | glEnd(); 50 | glPopMatrix(); 51 | 52 | glFrontFace(face_ori); //restore front face orientation 53 | 54 | glDisable(GL_TEXTURE_2D); 55 | glEnable(GL_LIGHTING); 56 | glEnable(GL_BLEND); 57 | } 58 | 59 | void glEnable2D() 60 | { 61 | int vPort[4]; 62 | 63 | glGetIntegerv(GL_VIEWPORT, vPort); 64 | 65 | glMatrixMode(GL_PROJECTION); 66 | glPushMatrix(); 67 | glLoadIdentity(); 68 | 69 | glOrtho(0, vPort[2], 0, vPort[3], -1, 4); 70 | glMatrixMode(GL_MODELVIEW); 71 | glPushMatrix(); 72 | glLoadIdentity(); 73 | glTranslated(0.375, 0.375, 0); 74 | 75 | glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // clear the screen 76 | 77 | glDisable(GL_DEPTH_TEST); 78 | } 79 | 80 | void glDisable2D() 81 | { 82 | glMatrixMode(GL_PROJECTION); 83 | glPopMatrix(); 84 | glMatrixMode(GL_MODELVIEW); 85 | glPopMatrix(); 86 | 87 | glEnable(GL_DEPTH_TEST); 88 | } 89 | 90 | #if defined(WIN32) 91 | #define log2(x) log10((double)(x))/log10(2.0) 92 | #endif 93 | 94 | void copyImgToTex(const Mat& _tex_img, GLuint* texID, double* _twr, double* _thr) { 95 | Mat tex_img = _tex_img; 96 | flip(_tex_img,tex_img,0); 97 | Mat tex_pow2(pow(2.0,ceil(log2(tex_img.rows))),pow(2.0,ceil(log2(tex_img.cols))),CV_8UC3); 98 | std::cout << tex_pow2.rows <<"x"< 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | #if defined(__APPLE__) 18 | # include 19 | # include 20 | #elif defined(__linux__) || defined(__MINGW32__) || defined(WIN32) 21 | # include 22 | # include 23 | #else 24 | # include 25 | #endif 26 | 27 | #include "glm.h" 28 | #include "OGL_OCV_common.h" 29 | 30 | void loadNext(); 31 | void loadWithPoints(Mat& ip, Mat& img); 32 | 33 | const GLfloat light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; 34 | const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; 35 | const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; 36 | const GLfloat light_position[] = { 0.0f, 0.0f, 1.0f, 0.0f }; 37 | 38 | const GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f }; 39 | const GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f }; 40 | const GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; 41 | const GLfloat high_shininess[] = { 100.0f }; 42 | 43 | double rot[9] = {0}; 44 | GLuint textureID; 45 | Mat backPxls; 46 | vector rv(3), tv(3); 47 | Mat rvec(rv),tvec(tv); 48 | Mat camMatrix; 49 | 50 | OpenCVGLTexture imgTex,imgWithDrawing; 51 | 52 | GLMmodel* head_obj; 53 | 54 | void saveOpenGLBuffer() { 55 | static unsigned int opengl_buffer_num = 0; 56 | 57 | int vPort[4]; glGetIntegerv(GL_VIEWPORT, vPort); 58 | Mat_ opengl_image(vPort[3],vPort[2]); 59 | { 60 | Mat_ opengl_image_4b(vPort[3],vPort[2]); 61 | glReadPixels(0, 0, vPort[2], vPort[3], GL_BGRA, GL_UNSIGNED_BYTE, opengl_image_4b.data); 62 | flip(opengl_image_4b,opengl_image_4b,0); 63 | mixChannels(&opengl_image_4b, 1, &opengl_image, 1, &(Vec6i(0,0,1,1,2,2)[0]), 3); 64 | } 65 | stringstream ss; ss << "opengl_buffer_" << opengl_buffer_num++ << ".jpg"; 66 | imwrite(ss.str(), opengl_image); 67 | } 68 | 69 | 70 | void resize(int width, int height) 71 | { 72 | const float ar = (float) width / (float) height; 73 | 74 | glViewport(0, 0, width, height); 75 | 76 | glMatrixMode(GL_PROJECTION); 77 | glLoadIdentity(); 78 | //glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0); 79 | gluPerspective(47,1.0,0.01,1000.0); 80 | 81 | glMatrixMode(GL_MODELVIEW); 82 | glLoadIdentity(); 83 | } 84 | 85 | int __w=250,__h=250; 86 | 87 | void key(unsigned char key, int x, int y) 88 | { 89 | 90 | switch (key) 91 | { 92 | case 27 : 93 | case 'Q': 94 | case 'q': 95 | exit(0); 96 | break; 97 | case 'w': 98 | case 'W': 99 | __w++; 100 | __w = __w%251; 101 | break; 102 | case 'h': 103 | case 'H': 104 | __h++; 105 | __h = __h%250; 106 | break; 107 | case ' ': 108 | saveOpenGLBuffer(); 109 | loadNext(); 110 | break; 111 | default: 112 | break; 113 | } 114 | 115 | glutPostRedisplay(); 116 | } 117 | 118 | void idle(void) 119 | { 120 | glutPostRedisplay(); 121 | } 122 | 123 | 124 | 125 | void myGLinit() { 126 | // glutSetOption ( GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION ) ; 127 | 128 | glEnable(GL_CULL_FACE); 129 | glCullFace(GL_BACK); 130 | 131 | 132 | glShadeModel(GL_SMOOTH); 133 | 134 | glEnable(GL_DEPTH_TEST); 135 | glDepthFunc(GL_LEQUAL); 136 | 137 | glEnable(GL_BLEND); 138 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 139 | 140 | glEnable(GL_LIGHT0); 141 | glEnable(GL_NORMALIZE); 142 | glEnable(GL_COLOR_MATERIAL); 143 | glColorMaterial ( GL_FRONT, GL_AMBIENT_AND_DIFFUSE ); 144 | 145 | glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); 146 | glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); 147 | glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); 148 | glLightfv(GL_LIGHT0, GL_POSITION, light_position); 149 | 150 | glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); 151 | glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); 152 | glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); 153 | glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess); 154 | 155 | glEnable(GL_LIGHTING); 156 | 157 | glMatrixMode(GL_MODELVIEW); 158 | glLoadIdentity(); 159 | 160 | } 161 | 162 | void drawAxes() { 163 | 164 | //Z = red 165 | glPushMatrix(); 166 | glRotated(180,0,1,0); 167 | glColor4d(1,0,0,0.5); 168 | // glutSolidCylinder(0.05,1,15,20); 169 | glBegin(GL_LINES); 170 | glVertex3d(0, 0, 0); glVertex3d(0, 0, 1); 171 | glEnd(); 172 | glTranslated(0,0,1); 173 | glScaled(.1,.1,.1); 174 | glutSolidTetrahedron(); 175 | glPopMatrix(); 176 | 177 | //Y = green 178 | glPushMatrix(); 179 | glRotated(-90,1,0,0); 180 | glColor4d(0,1,0,0.5); 181 | // glutSolidCylinder(0.05,1,15,20); 182 | glBegin(GL_LINES); 183 | glVertex3d(0, 0, 0); glVertex3d(0, 0, 1); 184 | glEnd(); 185 | glTranslated(0,0,1); 186 | glScaled(.1,.1,.1); 187 | glutSolidTetrahedron(); 188 | glPopMatrix(); 189 | 190 | //X = blue 191 | glPushMatrix(); 192 | glRotated(-90,0,1,0); 193 | glColor4d(0,0,1,0.5); 194 | // glutSolidCylinder(0.05,1,15,20); 195 | glBegin(GL_LINES); 196 | glVertex3d(0, 0, 0); glVertex3d(0, 0, 1); 197 | glEnd(); 198 | glTranslated(0,0,1); 199 | glScaled(.1,.1,.1); 200 | glutSolidTetrahedron(); 201 | glPopMatrix(); 202 | } 203 | 204 | void display(void) 205 | { 206 | // draw the image in the back 207 | int vPort[4]; glGetIntegerv(GL_VIEWPORT, vPort); 208 | glEnable2D(); 209 | drawOpenCVImageInGL(imgTex); 210 | glTranslated(vPort[2]/2.0, 0, 0); 211 | drawOpenCVImageInGL(imgWithDrawing); 212 | glDisable2D(); 213 | 214 | glClear(GL_DEPTH_BUFFER_BIT); // we want to draw stuff over the image 215 | 216 | // draw only on left part 217 | glViewport(0, 0, vPort[2]/2, vPort[3]); 218 | 219 | glPushMatrix(); 220 | 221 | gluLookAt(0,0,0,0,0,1,0,-1,0); 222 | 223 | // put the object in the right position in space 224 | Vec3d tvv(tv[0],tv[1],tv[2]); 225 | glTranslated(tvv[0], tvv[1], tvv[2]); 226 | 227 | // rotate it 228 | double _d[16] = { rot[0],rot[1],rot[2],0, 229 | rot[3],rot[4],rot[5],0, 230 | rot[6],rot[7],rot[8],0, 231 | 0, 0, 0 ,1}; 232 | glMultMatrixd(_d); 233 | 234 | // draw the 3D head model 235 | glColor4f(1, 1, 1,0.75); 236 | glmDraw(head_obj, GLM_SMOOTH); 237 | 238 | //----------Axes 239 | glScaled(50, 50, 50); 240 | drawAxes(); 241 | //----------End axes 242 | 243 | glPopMatrix(); 244 | 245 | // restore to looking at complete viewport 246 | glViewport(0, 0, vPort[2], vPort[3]); 247 | 248 | glutSwapBuffers(); 249 | } 250 | 251 | void init_opengl(int argc,char** argv) { 252 | glutInitWindowSize(500,250); 253 | glutInitWindowPosition(40,40); 254 | glutInit(&argc, argv); 255 | glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); // | GLUT_MULTISAMPLE 256 | glutCreateWindow("head pose"); 257 | 258 | myGLinit(); 259 | 260 | glutReshapeFunc(resize); 261 | glutDisplayFunc(display); 262 | glutKeyboardFunc(key); 263 | //glutSpecialFunc(special); 264 | glutIdleFunc(idle); 265 | } 266 | 267 | int start_opengl() { 268 | 269 | glutMainLoop(); 270 | 271 | return 1; 272 | } 273 | 274 | Mat op; 275 | 276 | void loadNext() { 277 | static int counter = 1; 278 | 279 | printf("load %d\n",counter); 280 | 281 | const char* workingDir = "./"; 282 | 283 | char buf[256] = {0}; 284 | sprintf(buf,"%sAngelina_Jolie/Angelina_Jolie_%04d.txt",workingDir,counter); 285 | 286 | vector imagePoints; 287 | ifstream inputfile(buf); 288 | if(inputfile.fail()) { 289 | cerr << "can't read " << buf << endl; return; 290 | } 291 | 292 | for(int i=0;i<7;i++) { 293 | int x=0,y=0; 294 | inputfile >> skipws >> x >> y; 295 | imagePoints.push_back(Point2f((float)x,(float)y)); 296 | } 297 | inputfile.close(); 298 | 299 | Mat ip(imagePoints); 300 | 301 | sprintf(buf,"%sAngelina_Jolie/Angelina_Jolie_%04d.jpg",workingDir,counter); 302 | 303 | Mat img = imread(buf); 304 | 305 | imgTex.set(img); //TODO: what if different size?? 306 | 307 | // paint 2D feature points 308 | for(unsigned int i=0;i(3,3) << max_d, 0, img.cols/2.0, 320 | 0, max_d, img.rows/2.0, 321 | 0, 0, 1.0); 322 | cout << "using cam matrix " << endl << camMatrix << endl; 323 | 324 | double _dc[] = {0,0,0,0}; 325 | solvePnP(op,ip,camMatrix,Mat(1,4,CV_64FC1,_dc),rvec,tvec,false,CV_EPNP); 326 | 327 | Mat rotM(3,3,CV_64FC1,rot); 328 | Rodrigues(rvec,rotM); 329 | double* _r = rotM.ptr(); 330 | printf("rotation mat: \n %.3f %.3f %.3f\n%.3f %.3f %.3f\n%.3f %.3f %.3f\n", 331 | _r[0],_r[1],_r[2],_r[3],_r[4],_r[5],_r[6],_r[7],_r[8]); 332 | 333 | printf("trans vec: \n %.3f %.3f %.3f\n",tv[0],tv[1],tv[2]); 334 | 335 | double _pm[12] = {_r[0],_r[1],_r[2],tv[0], 336 | _r[3],_r[4],_r[5],tv[1], 337 | _r[6],_r[7],_r[8],tv[2]}; 338 | 339 | Matx34d P(_pm); 340 | Mat KP = camMatrix * Mat(P); 341 | // cout << "KP " << endl << KP << endl; 342 | 343 | //reproject object points - check validity of found projection matrix 344 | for (int i=0; i X = (Mat_(4,1) << op.at(i,0),op.at(i,1),op.at(i,2),1.0); 346 | // cout << "object point " << X << endl; 347 | Mat_ opt_p = KP * X; 348 | Point2f opt_p_img(opt_p(0)/opt_p(2),opt_p(1)/opt_p(2)); 349 | // cout << "object point reproj " << opt_p_img << endl; 350 | 351 | circle(img, opt_p_img, 4, Scalar(0,0,255), 1); 352 | } 353 | rotM = rotM.t();// transpose to conform with majorness of opengl matrix 354 | } 355 | 356 | 357 | int main(int argc, char** argv) 358 | { 359 | 360 | vector modelPoints; 361 | // modelPoints.push_back(Point3f(-36.9522f,39.3518f,47.1217f)); //l eye 362 | // modelPoints.push_back(Point3f(35.446f,38.4345f,47.6468f)); //r eye 363 | // modelPoints.push_back(Point3f(-0.0697709f,18.6015f,87.9695f)); //nose 364 | // modelPoints.push_back(Point3f(-27.6439f,-29.6388f,73.8551f)); //l mouth 365 | // modelPoints.push_back(Point3f(28.7793f,-29.2935f,72.7329f)); //r mouth 366 | // modelPoints.push_back(Point3f(-87.2155f,15.5829f,-45.1352f)); //l ear 367 | // modelPoints.push_back(Point3f(85.8383f,14.9023f,-46.3169f)); //r ear 368 | //new model points: 369 | modelPoints.push_back(Point3f(2.37427,110.322,21.7776)); // l eye (v 314) 370 | modelPoints.push_back(Point3f(70.0602,109.898,20.8234)); // r eye (v 0) 371 | modelPoints.push_back(Point3f(36.8301,78.3185,52.0345)); //nose (v 1879) 372 | modelPoints.push_back(Point3f(14.8498,51.0115,30.2378)); // l mouth (v 1502) 373 | modelPoints.push_back(Point3f(58.1825,51.0115,29.6224)); // r mouth (v 695) 374 | modelPoints.push_back(Point3f(-61.8886,127.797,-89.4523)); // l ear (v 2011) 375 | modelPoints.push_back(Point3f(127.603,126.9,-83.9129)); // r ear (v 1138) 376 | 377 | head_obj = glmReadOBJ("head-obj.obj"); 378 | 379 | op = Mat(modelPoints); 380 | Scalar m = mean(Mat(modelPoints)); 381 | //op = op - m; 382 | 383 | //assert(norm(mean(op)) < 1e-05); //make sure is centered 384 | 385 | //op = op + Scalar(0,0,25); 386 | 387 | cout << "model points " << op << endl; 388 | 389 | rvec = Mat(rv); 390 | double _d[9] = {1,0,0, 391 | 0,-1,0, 392 | 0,0,-1}; 393 | Rodrigues(Mat(3,3,CV_64FC1,_d),rvec); 394 | tv[0]=0;tv[1]=0;tv[2]=1; 395 | tvec = Mat(tv); 396 | 397 | camMatrix = Mat(3,3,CV_64FC1); 398 | 399 | init_opengl(argc, argv); // get GL context, for loading textures 400 | 401 | // prepare OpenCV-OpenGL images 402 | imgTex = MakeOpenCVGLTexture(Mat()); 403 | imgWithDrawing = MakeOpenCVGLTexture(Mat()); 404 | 405 | loadNext(); 406 | 407 | start_opengl(); 408 | 409 | return 0; 410 | } 411 | 412 | 413 | -------------------------------------------------------------------------------- /glm.h: -------------------------------------------------------------------------------- 1 | /* 2 | glm.h 3 | Nate Robins, 1997, 2000 4 | nate@pobox.com, http://www.pobox.com/~nate 5 | 6 | Wavefront OBJ model file format reader/writer/manipulator. 7 | 8 | Includes routines for generating smooth normals with 9 | preservation of edges, welding redundant vertices & texture 10 | coordinate generation (spheremap and planar projections) + more. 11 | 12 | Improved version: 13 | Tudor Carean - April 2008 - added texture support 14 | 15 | */ 16 | 17 | 18 | #include 19 | 20 | 21 | #ifndef M_PI 22 | #define M_PI 3.14159265f 23 | #endif 24 | 25 | #define GLM_NONE (0) /* render with only vertices */ 26 | #define GLM_FLAT (1 << 0) /* render with facet normals */ 27 | #define GLM_SMOOTH (1 << 1) /* render with vertex normals */ 28 | #define GLM_TEXTURE (1 << 2) /* render with texture coords */ 29 | #define GLM_COLOR (1 << 3) /* render with colors */ 30 | #define GLM_MATERIAL (1 << 4) /* render with materials */ 31 | 32 | 33 | /* GLMmaterial: Structure that defines a material in a model. 34 | */ 35 | typedef struct _GLMmaterial 36 | { 37 | char* name; /* name of material */ 38 | GLfloat diffuse[4]; /* diffuse component */ 39 | GLfloat ambient[4]; /* ambient component */ 40 | GLfloat specular[4]; /* specular component */ 41 | GLfloat emmissive[4]; /* emmissive component */ 42 | GLfloat shininess; /* specular exponent */ 43 | //this is for textures 44 | GLuint IDTextura; // ID-ul texturii difuze 45 | } GLMmaterial; 46 | 47 | /* GLMtriangle: Structure that defines a triangle in a model. 48 | */ 49 | typedef struct _GLMtriangle { 50 | GLuint vindices[3]; /* array of triangle vertex indices */ 51 | GLuint nindices[3]; /* array of triangle normal indices */ 52 | GLuint tindices[3]; /* array of triangle texcoord indices*/ 53 | GLuint findex; /* index of triangle facet normal */ 54 | //GLuint nrvecini; 55 | GLuint vecini[3]; 56 | bool visible; 57 | } GLMtriangle; 58 | 59 | //adaugat pentru suport texturi 60 | typedef struct _GLMtexture { 61 | char *name; 62 | GLuint id; /* ID-ul texturii */ 63 | GLfloat width; /* width and height for texture coordinates */ 64 | GLfloat height; 65 | } GLMtexture; 66 | 67 | /* GLMgroup: Structure that defines a group in a model. 68 | */ 69 | typedef struct _GLMgroup { 70 | char* name; /* name of this group */ 71 | GLuint numtriangles; /* number of triangles in this group */ 72 | GLuint* triangles; /* array of triangle indices */ 73 | GLuint material; /* index to material for group */ 74 | struct _GLMgroup* next; /* pointer to next group in model */ 75 | } GLMgroup; 76 | 77 | /* GLMmodel: Structure that defines a model. 78 | */ 79 | typedef struct _GLMmodel { 80 | char* pathname; /* path to this model */ 81 | char* mtllibname; /* name of the material library */ 82 | 83 | GLuint numvertices; /* number of vertices in model */ 84 | GLfloat* vertices; /* array of vertices */ 85 | 86 | GLuint numnormals; /* number of normals in model */ 87 | GLfloat* normals; /* array of normals */ 88 | 89 | GLuint numtexcoords; /* number of texcoords in model */ 90 | GLfloat* texcoords; /* array of texture coordinates */ 91 | 92 | GLuint numfacetnorms; /* number of facetnorms in model */ 93 | GLfloat* facetnorms; /* array of facetnorms */ 94 | 95 | GLuint numtriangles; /* number of triangles in model */ 96 | GLMtriangle* triangles; /* array of triangles */ 97 | 98 | GLuint nummaterials; /* number of materials in model */ 99 | GLMmaterial* materials; /* array of materials */ 100 | 101 | GLuint numgroups; /* number of groups in model */ 102 | GLMgroup* groups; /* linked list of groups */ 103 | 104 | // textures 105 | GLuint numtextures; 106 | GLMtexture* textures; 107 | 108 | GLfloat position[3]; /* position of the model */ 109 | 110 | } GLMmodel; 111 | 112 | struct mycallback 113 | { 114 | void (*loadcallback)(int,char *); 115 | int start; 116 | int end; 117 | char *text; 118 | }; 119 | 120 | GLvoid glmDraw(GLMmodel* model, GLuint mode,char *drawonly); 121 | 122 | GLfloat glmDot(GLfloat* u, GLfloat* v); 123 | 124 | /* glmUnitize: "unitize" a model by translating it to the origin and 125 | * scaling it to fit in a unit cube around the origin. Returns the 126 | * scalefactor used. 127 | * 128 | * model - properly initialized GLMmodel structure 129 | */ 130 | GLfloat 131 | glmUnitize(GLMmodel* model); 132 | 133 | /* glmDimensions: Calculates the dimensions (width, height, depth) of 134 | * a model. 135 | * 136 | * model - initialized GLMmodel structure 137 | * dimensions - array of 3 GLfloats (GLfloat dimensions[3]) 138 | */ 139 | GLvoid 140 | glmDimensions(GLMmodel* model, GLfloat* dimensions); 141 | 142 | /* glmScale: Scales a model by a given amount. 143 | * 144 | * model - properly initialized GLMmodel structure 145 | * scale - scalefactor (0.5 = half as large, 2.0 = twice as large) 146 | */ 147 | GLvoid 148 | glmScale(GLMmodel* model, GLfloat scale); 149 | 150 | /* glmReverseWinding: Reverse the polygon winding for all polygons in 151 | * this model. Default winding is counter-clockwise. Also changes 152 | * the direction of the normals. 153 | * 154 | * model - properly initialized GLMmodel structure 155 | */ 156 | GLvoid 157 | glmReverseWinding(GLMmodel* model); 158 | 159 | /* glmFacetNormals: Generates facet normals for a model (by taking the 160 | * cross product of the two vectors derived from the sides of each 161 | * triangle). Assumes a counter-clockwise winding. 162 | * 163 | * model - initialized GLMmodel structure 164 | */ 165 | GLvoid 166 | glmFacetNormals(GLMmodel* model); 167 | 168 | /* glmVertexNormals: Generates smooth vertex normals for a model. 169 | * First builds a list of all the triangles each vertex is in. Then 170 | * loops through each vertex in the the list averaging all the facet 171 | * normals of the triangles each vertex is in. Finally, sets the 172 | * normal index in the triangle for the vertex to the generated smooth 173 | * normal. If the dot product of a facet normal and the facet normal 174 | * associated with the first triangle in the list of triangles the 175 | * current vertex is in is greater than the cosine of the angle 176 | * parameter to the function, that facet normal is not added into the 177 | * average normal calculation and the corresponding vertex is given 178 | * the facet normal. This tends to preserve hard edges. The angle to 179 | * use depends on the model, but 90 degrees is usually a good start. 180 | * 181 | * model - initialized GLMmodel structure 182 | * angle - maximum angle (in degrees) to smooth across 183 | */ 184 | GLvoid 185 | glmVertexNormals(GLMmodel* model, GLfloat angle); 186 | 187 | /* glmLinearTexture: Generates texture coordinates according to a 188 | * linear projection of the texture map. It generates these by 189 | * linearly mapping the vertices onto a square. 190 | * 191 | * model - pointer to initialized GLMmodel structure 192 | */ 193 | GLvoid 194 | glmLinearTexture(GLMmodel* model); 195 | 196 | /* glmSpheremapTexture: Generates texture coordinates according to a 197 | * spherical projection of the texture map. Sometimes referred to as 198 | * spheremap, or reflection map texture coordinates. It generates 199 | * these by using the normal to calculate where that vertex would map 200 | * onto a sphere. Since it is impossible to map something flat 201 | * perfectly onto something spherical, there is distortion at the 202 | * poles. This particular implementation causes the poles along the X 203 | * axis to be distorted. 204 | * 205 | * model - pointer to initialized GLMmodel structure 206 | */ 207 | GLvoid 208 | glmSpheremapTexture(GLMmodel* model); 209 | 210 | /* glmDelete: Deletes a GLMmodel structure. 211 | * 212 | * model - initialized GLMmodel structure 213 | */ 214 | GLvoid 215 | glmDelete(GLMmodel* model); 216 | 217 | /* glmReadOBJ: Reads a model description from a Wavefront .OBJ file. 218 | * Returns a pointer to the created object which should be free'd with 219 | * glmDelete(). 220 | * 221 | * filename - name of the file containing the Wavefront .OBJ format data. 222 | */ 223 | //GLMmodel * glmReadOBJ(char* filename); 224 | GLMmodel* glmReadOBJ(char* filename); 225 | GLMmodel* glmReadOBJ(char* filename,mycallback *call); 226 | 227 | /* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to 228 | * a file. 229 | * 230 | * model - initialized GLMmodel structure 231 | * filename - name of the file to write the Wavefront .OBJ format data to 232 | * mode - a bitwise or of values describing what is written to the file 233 | * GLM_NONE - write only vertices 234 | * GLM_FLAT - write facet normals 235 | * GLM_SMOOTH - write vertex normals 236 | * GLM_TEXTURE - write texture coords 237 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 238 | */ 239 | GLvoid 240 | glmWriteOBJ(GLMmodel* model, char* filename, GLuint mode); 241 | 242 | /* glmDraw: Renders the model to the current OpenGL context using the 243 | * mode specified. 244 | * 245 | * model - initialized GLMmodel structure 246 | * mode - a bitwise OR of values describing what is to be rendered. 247 | * GLM_NONE - render with only vertices 248 | * GLM_FLAT - render with facet normals 249 | * GLM_SMOOTH - render with vertex normals 250 | * GLM_TEXTURE - render with texture coords 251 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 252 | */ 253 | GLvoid 254 | glmDraw(GLMmodel* model, GLuint mode); 255 | 256 | /* glmList: Generates and returns a display list for the model using 257 | * the mode specified. 258 | * 259 | * model - initialized GLMmodel structure 260 | * mode - a bitwise OR of values describing what is to be rendered. 261 | * GLM_NONE - render with only vertices 262 | * GLM_FLAT - render with facet normals 263 | * GLM_SMOOTH - render with vertex normals 264 | * GLM_TEXTURE - render with texture coords 265 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 266 | */ 267 | GLuint 268 | glmList(GLMmodel* model, GLuint mode); 269 | 270 | /* glmWeld: eliminate (weld) vectors that are within an epsilon of 271 | * each other. 272 | * 273 | * model - initialized GLMmodel structure 274 | * epsilon - maximum difference between vertices 275 | * ( 0.00001 is a good start for a unitized model) 276 | * 277 | */ 278 | GLvoid 279 | glmWeld(GLMmodel* model, GLfloat epsilon); 280 | 281 | /* glmReadPPM: read a PPM raw (type P6) file. The PPM file has a header 282 | * that should look something like: 283 | * 284 | * P6 285 | * # comment 286 | * width height max_value 287 | * rgbrgbrgb... 288 | * 289 | * where "P6" is the magic cookie which identifies the file type and 290 | * should be the only characters on the first line followed by a 291 | * carriage return. Any line starting with a # mark will be treated 292 | * as a comment and discarded. After the magic cookie, three integer 293 | * values are expected: width, height of the image and the maximum 294 | * value for a pixel (max_value must be < 256 for PPM raw files). The 295 | * data section consists of width*height rgb triplets (one byte each) 296 | * in binary format (i.e., such as that written with fwrite() or 297 | * equivalent). 298 | * 299 | * The rgb data is returned as an array of unsigned chars (packed 300 | * rgb). The malloc()'d memory should be free()'d by the caller. If 301 | * an error occurs, an error message is sent to stderr and NULL is 302 | * returned. 303 | * 304 | * filename - name of the .ppm file. 305 | * width - will contain the width of the image on return. 306 | * height - will contain the height of the image on return. 307 | * 308 | */ 309 | GLubyte* 310 | glmReadPPM(char* filename, int* width, int* height); 311 | 312 | GLMgroup* 313 | glmFindGroup(GLMmodel* model, char* name); 314 | -------------------------------------------------------------------------------- /glm.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | glm.c 3 | Nate Robins, 1997, 2000 4 | nate@pobox.com, http://www.pobox.com/~nate 5 | 6 | Wavefront OBJ model file format reader/writer/manipulator. 7 | 8 | Includes routines for generating smooth normals with 9 | preservation of edges, welding redundant vertices & texture 10 | coordinate generation (spheremap and planar projections) + more. 11 | 12 | Improved version of GLM - 08.05.2008 Tudor Carean 13 | Added support for textures and loading callbacks 14 | */ 15 | 16 | //#include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include "glm.h" 23 | 24 | 25 | //#define DebugVisibleSurfaces 26 | 27 | #define total_textures 5 28 | 29 | #define T(x) (model->triangles[(x)]) 30 | GLuint glmLoadTexture(char *filename, GLboolean alpha, GLboolean repeat, GLboolean filtering, GLboolean mipmaps, GLfloat *texcoordwidth, GLfloat *texcoordheight); 31 | 32 | /* _GLMnode: general purpose node */ 33 | typedef struct _GLMnode { 34 | GLuint index; 35 | GLboolean averaged; 36 | struct _GLMnode* next; 37 | } GLMnode; 38 | 39 | 40 | /* glmMax: returns the maximum of two floats */ 41 | static GLfloat 42 | glmMax(GLfloat a, GLfloat b) 43 | { 44 | if (b > a) 45 | return b; 46 | return a; 47 | } 48 | 49 | /* glmAbs: returns the absolute value of a float */ 50 | static GLfloat 51 | glmAbs(GLfloat f) 52 | { 53 | if (f < 0) 54 | return -f; 55 | return f; 56 | } 57 | 58 | /* glmDot: compute the dot product of two vectors 59 | * 60 | * u - array of 3 GLfloats (GLfloat u[3]) 61 | * v - array of 3 GLfloats (GLfloat v[3]) 62 | */ 63 | GLfloat glmDot(GLfloat* u, GLfloat* v) 64 | { 65 | assert(u); assert(v); 66 | 67 | return u[0]*v[0] + u[1]*v[1] + u[2]*v[2]; 68 | } 69 | 70 | /* glmCross: compute the cross product of two vectors 71 | * 72 | * u - array of 3 GLfloats (GLfloat u[3]) 73 | * v - array of 3 GLfloats (GLfloat v[3]) 74 | * n - array of 3 GLfloats (GLfloat n[3]) to return the cross product in 75 | */ 76 | static GLvoid 77 | glmCross(GLfloat* u, GLfloat* v, GLfloat* n) 78 | { 79 | assert(u); assert(v); assert(n); 80 | 81 | n[0] = u[1]*v[2] - u[2]*v[1]; 82 | n[1] = u[2]*v[0] - u[0]*v[2]; 83 | n[2] = u[0]*v[1] - u[1]*v[0]; 84 | } 85 | 86 | /* glmNormalize: normalize a vector 87 | * 88 | * v - array of 3 GLfloats (GLfloat v[3]) to be normalized 89 | */ 90 | static GLvoid 91 | glmNormalize(GLfloat* v) 92 | { 93 | GLfloat l; 94 | 95 | assert(v); 96 | 97 | l = (GLfloat)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); 98 | v[0] /= l; 99 | v[1] /= l; 100 | v[2] /= l; 101 | } 102 | 103 | /* glmEqual: compares two vectors and returns GL_TRUE if they are 104 | * equal (within a certain threshold) or GL_FALSE if not. An epsilon 105 | * that works fairly well is 0.000001. 106 | * 107 | * u - array of 3 GLfloats (GLfloat u[3]) 108 | * v - array of 3 GLfloats (GLfloat v[3]) 109 | */ 110 | static GLboolean 111 | glmEqual(GLfloat* u, GLfloat* v, GLfloat epsilon) 112 | { 113 | if (glmAbs(u[0] - v[0]) < epsilon && 114 | glmAbs(u[1] - v[1]) < epsilon && 115 | glmAbs(u[2] - v[2]) < epsilon) 116 | { 117 | return GL_TRUE; 118 | } 119 | return GL_FALSE; 120 | } 121 | 122 | /* glmWeldVectors: eliminate (weld) vectors that are within an 123 | * epsilon of each other. 124 | * 125 | * vectors - array of GLfloat[3]'s to be welded 126 | * numvectors - number of GLfloat[3]'s in vectors 127 | * epsilon - maximum difference between vectors 128 | * 129 | */ 130 | GLfloat* 131 | glmWeldVectors(GLfloat* vectors, GLuint* numvectors, GLfloat epsilon) 132 | { 133 | GLfloat* copies; 134 | GLuint copied; 135 | GLuint i, j; 136 | 137 | copies = (GLfloat*)malloc(sizeof(GLfloat) * 3 * (*numvectors + 1)); 138 | memcpy(copies, vectors, (sizeof(GLfloat) * 3 * (*numvectors + 1))); 139 | 140 | copied = 1; 141 | for (i = 1; i <= *numvectors; i++) { 142 | for (j = 1; j <= copied; j++) { 143 | if (glmEqual(&vectors[3 * i], &copies[3 * j], epsilon)) { 144 | goto duplicate; 145 | } 146 | } 147 | 148 | /* must not be any duplicates -- add to the copies array */ 149 | copies[3 * copied + 0] = vectors[3 * i + 0]; 150 | copies[3 * copied + 1] = vectors[3 * i + 1]; 151 | copies[3 * copied + 2] = vectors[3 * i + 2]; 152 | j = copied; /* pass this along for below */ 153 | copied++; 154 | 155 | duplicate: 156 | /* set the first component of this vector to point at the correct 157 | index into the new copies array */ 158 | vectors[3 * i + 0] = (GLfloat)j; 159 | } 160 | 161 | *numvectors = copied-1; 162 | return copies; 163 | } 164 | 165 | /* glmFindGroup: Find a group in the model */ 166 | GLMgroup* 167 | glmFindGroup(GLMmodel* model, char* name) 168 | { 169 | GLMgroup* group; 170 | 171 | assert(model); 172 | 173 | group = model->groups; 174 | while(group) { 175 | if (!strcmp(name, group->name)) 176 | break; 177 | group = group->next; 178 | } 179 | 180 | return group; 181 | } 182 | 183 | /* glmAddGroup: Add a group to the model */ 184 | GLMgroup* 185 | glmAddGroup(GLMmodel* model, char* name) 186 | { 187 | GLMgroup* group; 188 | 189 | group = glmFindGroup(model, name); 190 | if (!group) { 191 | group = (GLMgroup*)malloc(sizeof(GLMgroup)); 192 | group->name = strdup(name); 193 | group->material = 0; 194 | group->numtriangles = 0; 195 | group->triangles = NULL; 196 | group->next = model->groups; 197 | model->groups = group; 198 | model->numgroups++; 199 | } 200 | 201 | return group; 202 | } 203 | 204 | /* glmFindGroup: Find a material in the model */ 205 | GLuint 206 | glmFindMaterial(GLMmodel* model, char* name) 207 | { 208 | GLuint i; 209 | 210 | /* XXX doing a linear search on a string key'd list is pretty lame, 211 | but it works and is fast enough for now. */ 212 | for (i = 0; i < model->nummaterials; i++) { 213 | if (!strcmp(model->materials[i].name, name)) 214 | goto found; 215 | } 216 | 217 | /* didn't find the name, so print a warning and return the default 218 | material (0). */ 219 | printf("glmFindMaterial(): can't find material \"%s\".\n", name); 220 | i = 0; 221 | 222 | found: 223 | return i; 224 | } 225 | /* glmDirName: return the directory given a path 226 | * 227 | * path - filesystem path 228 | * 229 | * NOTE: the return value should be free'd. 230 | */ 231 | static char* 232 | glmDirName(char* path) 233 | { 234 | char* dir; 235 | char* s; 236 | 237 | dir = strdup(path); 238 | 239 | s = strrchr(dir, '/'); 240 | if (s) 241 | s[1] = '\0'; 242 | else 243 | dir[0] = '\0'; 244 | 245 | return dir; 246 | } 247 | 248 | int glmFindOrAddTexture(GLMmodel* model, char* name,mycallback *call) 249 | { 250 | GLuint i; 251 | char *dir, *filename; 252 | float width, height; 253 | 254 | char *numefis = name; 255 | while (*numefis==' ') numefis++; 256 | 257 | for (i = 0; i < model->numtextures; i++) { 258 | if (!strcmp(model->textures[i].name, numefis)) 259 | return i; 260 | } 261 | char afis[80]; 262 | sprintf(afis,"Loading Textures (%s )...",name); 263 | int procent = ((float)((float)model->numtextures*30/total_textures)/100)*(call->end-call->start)+call->start; 264 | if (call) call->loadcallback(procent,afis); // textures represent 30% from the model (just saying :)) 265 | if (strstr(name,":\\")) 266 | { 267 | filename = (char*)malloc(sizeof(char) * (strlen(name) + 1)); 268 | strcpy(filename,name); 269 | } 270 | else 271 | { 272 | dir = glmDirName(model->pathname); 273 | filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(numefis) + 1)); 274 | 275 | strcpy(filename, dir); 276 | //strcpy(filename, numefis); 277 | strcat(filename, numefis); 278 | free(dir); 279 | } 280 | int lung = strlen(filename); 281 | if (filename[lung-1]<32) filename[lung-1]=0; 282 | if (filename[lung-2]<32) filename[lung-2]=0; 283 | 284 | model->numtextures++; 285 | model->textures = (GLMtexture*)realloc(model->textures, sizeof(GLMtexture)*model->numtextures); 286 | model->textures[model->numtextures-1].name = strdup(numefis); 287 | // model->textures[model->numtextures-1].id = glmLoadTexture(filename, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE, &width, &height); 288 | model->textures[model->numtextures-1].width = width; 289 | model->textures[model->numtextures-1].height = height; 290 | 291 | 292 | free(filename); 293 | 294 | return model->numtextures-1; 295 | } 296 | 297 | 298 | 299 | 300 | /* glmReadMTL: read a wavefront material library file 301 | * 302 | * model - properly initialized GLMmodel structure 303 | * name - name of the material library 304 | */ 305 | static GLvoid 306 | glmReadMTL(GLMmodel* model, char* name, mycallback *call) 307 | { 308 | FILE* file; 309 | char* dir; 310 | char* filename; 311 | char* textura; 312 | char buf[128]; 313 | GLuint nummaterials, i; 314 | 315 | dir = glmDirName(model->pathname); 316 | filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(name) + 1)); 317 | strcpy(filename, dir); 318 | strcat(filename, name); 319 | free(dir); 320 | 321 | file = fopen(filename, "r"); 322 | if (!file) { 323 | fprintf(stderr, "glmReadMTL() failed: can't open material file \"%s\".\n", 324 | filename); 325 | exit(1); 326 | } 327 | free(filename); 328 | 329 | /* count the number of materials in the file */ 330 | nummaterials = 1; 331 | while(fscanf(file, "%s", buf) != EOF) { 332 | switch(buf[0]) { 333 | case '#': /* comment */ 334 | /* eat up rest of line */ 335 | fgets(buf, sizeof(buf), file); 336 | break; 337 | case 'n': /* newmtl */ 338 | fgets(buf, sizeof(buf), file); 339 | nummaterials++; 340 | sscanf(buf, "%s %s", buf, buf); 341 | break; 342 | default: 343 | /* eat up rest of line */ 344 | fgets(buf, sizeof(buf), file); 345 | break; 346 | } 347 | } 348 | 349 | rewind(file); 350 | 351 | model->materials = (GLMmaterial*)malloc(sizeof(GLMmaterial) * nummaterials); 352 | model->nummaterials = nummaterials; 353 | 354 | /* set the default material */ 355 | for (i = 0; i < nummaterials; i++) { 356 | model->materials[i].name = NULL; 357 | model->materials[i].shininess = 65.0; 358 | model->materials[i].diffuse[0] = 0.8; 359 | model->materials[i].diffuse[1] = 0.8; 360 | model->materials[i].diffuse[2] = 0.8; 361 | model->materials[i].diffuse[3] = 1.0; 362 | model->materials[i].ambient[0] = 0.2; 363 | model->materials[i].ambient[1] = 0.2; 364 | model->materials[i].ambient[2] = 0.2; 365 | model->materials[i].ambient[3] = 1.0; 366 | model->materials[i].specular[0] = 0.0; 367 | model->materials[i].specular[1] = 0.0; 368 | model->materials[i].specular[2] = 0.0; 369 | model->materials[i].specular[3] = 1.0; 370 | model->materials[i].IDTextura = -1; 371 | } 372 | model->materials[0].name = strdup("default"); 373 | 374 | /* now, read in the data */ 375 | nummaterials = 0; 376 | while(fscanf(file, "%s", buf) != EOF) { 377 | switch(buf[0]) { 378 | case '#': /* comment */ 379 | /* eat up rest of line */ 380 | fgets(buf, sizeof(buf), file); 381 | break; 382 | case 'n': /* newmtl */ 383 | fgets(buf, sizeof(buf), file); 384 | sscanf(buf, "%s %s", buf, buf); 385 | nummaterials++; 386 | model->materials[nummaterials].name = strdup(buf); 387 | break; 388 | case 'N': 389 | if (buf[1]!='s') break; // 3DS pune 'i' aici pentru indici de refractie si se incurca 390 | fscanf(file, "%f", &model->materials[nummaterials].shininess); 391 | /* wavefront shininess is from [0, 1000], so scale for OpenGL */ 392 | model->materials[nummaterials].shininess /= 1000.0; 393 | model->materials[nummaterials].shininess *= 128.0; 394 | break; 395 | case 'K': 396 | switch(buf[1]) { 397 | case 'd': 398 | fscanf(file, "%f %f %f", 399 | &model->materials[nummaterials].diffuse[0], 400 | &model->materials[nummaterials].diffuse[1], 401 | &model->materials[nummaterials].diffuse[2]); 402 | break; 403 | case 's': 404 | fscanf(file, "%f %f %f", 405 | &model->materials[nummaterials].specular[0], 406 | &model->materials[nummaterials].specular[1], 407 | &model->materials[nummaterials].specular[2]); 408 | break; 409 | case 'a': 410 | fscanf(file, "%f %f %f", 411 | &model->materials[nummaterials].ambient[0], 412 | &model->materials[nummaterials].ambient[1], 413 | &model->materials[nummaterials].ambient[2]); 414 | break; 415 | default: 416 | /* eat up rest of line */ 417 | fgets(buf, sizeof(buf), file); 418 | break; 419 | } 420 | break; 421 | case 'm': 422 | // harta de texturi 423 | filename = (char *)malloc(FILENAME_MAX); 424 | fgets(filename, FILENAME_MAX, file); 425 | textura = strdup(filename); 426 | free(filename); 427 | if(strncmp(buf, "map_Kd", 6) == 0) 428 | { 429 | char afis[80]; 430 | sprintf(afis,"Loading Textures (%s)...",textura); 431 | model->materials[nummaterials].IDTextura = glmFindOrAddTexture(model, textura,call); 432 | free(textura); 433 | } else { 434 | //printf("map %s %s ignored",buf,t_filename); 435 | free(textura); 436 | //fgets(buf, sizeof(buf), file); 437 | } 438 | break; 439 | default: 440 | /* eat up rest of line */ 441 | fgets(buf, sizeof(buf), file); 442 | break; 443 | } 444 | } 445 | } 446 | 447 | /* glmWriteMTL: write a wavefront material library file 448 | * 449 | * model - properly initialized GLMmodel structure 450 | * modelpath - pathname of the model being written 451 | * mtllibname - name of the material library to be written 452 | */ 453 | static GLvoid 454 | glmWriteMTL(GLMmodel* model, char* modelpath, char* mtllibname) 455 | { 456 | FILE* file; 457 | char* dir; 458 | char* filename; 459 | GLMmaterial* material; 460 | GLuint i; 461 | 462 | dir = glmDirName(modelpath); 463 | filename = (char*)malloc(sizeof(char) * (strlen(dir)+strlen(mtllibname))); 464 | strcpy(filename, dir); 465 | strcat(filename, mtllibname); 466 | free(dir); 467 | 468 | /* open the file */ 469 | file = fopen(filename, "w"); 470 | if (!file) { 471 | fprintf(stderr, "glmWriteMTL() failed: can't open file \"%s\".\n", 472 | filename); 473 | exit(1); 474 | } 475 | free(filename); 476 | 477 | /* spit out a header */ 478 | fprintf(file, "# \n"); 479 | fprintf(file, "# Wavefront MTL generated by GLM library\n"); 480 | fprintf(file, "# \n"); 481 | fprintf(file, "# GLM library\n"); 482 | fprintf(file, "# Nate Robins\n"); 483 | fprintf(file, "# ndr@pobox.com\n"); 484 | fprintf(file, "# http://www.pobox.com/~ndr\n"); 485 | fprintf(file, "# \n\n"); 486 | 487 | for (i = 0; i < model->nummaterials; i++) { 488 | material = &model->materials[i]; 489 | fprintf(file, "newmtl %s\n", material->name); 490 | fprintf(file, "Ka %f %f %f\n", 491 | material->ambient[0], material->ambient[1], material->ambient[2]); 492 | fprintf(file, "Kd %f %f %f\n", 493 | material->diffuse[0], material->diffuse[1], material->diffuse[2]); 494 | fprintf(file, "Ks %f %f %f\n", 495 | material->specular[0],material->specular[1],material->specular[2]); 496 | fprintf(file, "Ns %f\n", material->shininess / 128.0 * 1000.0); 497 | fprintf(file, "\n"); 498 | } 499 | } 500 | 501 | 502 | /* glmFirstPass: first pass at a Wavefront OBJ file that gets all the 503 | * statistics of the model (such as #vertices, #normals, etc) 504 | * 505 | * model - properly initialized GLMmodel structure 506 | * file - (fopen'd) file descriptor 507 | */ 508 | static GLvoid glmFirstPass(GLMmodel* model, FILE* file, mycallback *call) 509 | { 510 | GLuint numvertices; /* number of vertices in model */ 511 | GLuint numnormals; /* number of normals in model */ 512 | GLuint numtexcoords; /* number of texcoords in model */ 513 | GLuint numtriangles; /* number of triangles in model */ 514 | GLMgroup* group; /* current group */ 515 | unsigned v, n, t; 516 | char buf[128]; 517 | 518 | /* make a default group */ 519 | group = glmAddGroup(model, "default"); 520 | 521 | numvertices = numnormals = numtexcoords = numtriangles = 0; 522 | while(fscanf(file, "%s", buf) != EOF) { 523 | switch(buf[0]) { 524 | case '#': /* comment */ 525 | /* eat up rest of line */ 526 | fgets(buf, sizeof(buf), file); 527 | break; 528 | case 'v': /* v, vn, vt */ 529 | switch(buf[1]) { 530 | case '\0': /* vertex */ 531 | /* eat up rest of line */ 532 | fgets(buf, sizeof(buf), file); 533 | numvertices++; 534 | break; 535 | case 'n': /* normal */ 536 | /* eat up rest of line */ 537 | fgets(buf, sizeof(buf), file); 538 | numnormals++; 539 | break; 540 | case 't': /* texcoord */ 541 | /* eat up rest of line */ 542 | fgets(buf, sizeof(buf), file); 543 | numtexcoords++; 544 | break; 545 | default: 546 | printf("glmFirstPass(): Unknown token \"%s\".\n", buf); 547 | exit(1); 548 | break; 549 | } 550 | break; 551 | case 'm': //mtllib 552 | fgets(buf, sizeof(buf), file); 553 | sscanf(buf, "%s %s", buf, buf); 554 | model->mtllibname = strdup(buf); 555 | glmReadMTL(model, buf, call); 556 | break; 557 | case 'u': //usemtl 558 | /* eat up rest of line */ 559 | fgets(buf, sizeof(buf), file); 560 | break; 561 | case 'g': /* group */ 562 | /* eat up rest of line */ 563 | fgets(buf, sizeof(buf), file); 564 | #if SINGLE_STRING_GROUP_NAMES 565 | sscanf(buf, "%s", buf); 566 | #else 567 | buf[strlen(buf)-1] = '\0'; /* nuke '\n' */ 568 | #endif 569 | group = glmAddGroup(model, buf); 570 | break; 571 | case 'f': /* face */ 572 | v = n = t = 0; 573 | fscanf(file, "%s", buf); 574 | /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */ 575 | if (strstr(buf, "//")) { 576 | /* v//n */ 577 | sscanf(buf, "%d//%d", &v, &n); 578 | fscanf(file, "%d//%d", &v, &n); 579 | fscanf(file, "%d//%d", &v, &n); 580 | numtriangles++; 581 | group->numtriangles++; 582 | while(fscanf(file, "%d//%d", &v, &n) > 0) { 583 | numtriangles++; 584 | group->numtriangles++; 585 | } 586 | } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) { 587 | /* v/t/n */ 588 | fscanf(file, "%d/%d/%d", &v, &t, &n); 589 | fscanf(file, "%d/%d/%d", &v, &t, &n); 590 | numtriangles++; 591 | group->numtriangles++; 592 | while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) { 593 | numtriangles++; 594 | group->numtriangles++; 595 | } 596 | } else if (sscanf(buf, "%d/%d", &v, &t) == 2) { 597 | /* v/t */ 598 | fscanf(file, "%d/%d", &v, &t); 599 | fscanf(file, "%d/%d", &v, &t); 600 | numtriangles++; 601 | group->numtriangles++; 602 | while(fscanf(file, "%d/%d", &v, &t) > 0) { 603 | numtriangles++; 604 | group->numtriangles++; 605 | } 606 | } else { 607 | /* v */ 608 | fscanf(file, "%d", &v); 609 | fscanf(file, "%d", &v); 610 | numtriangles++; 611 | group->numtriangles++; 612 | while(fscanf(file, "%d", &v) > 0) { 613 | numtriangles++; 614 | group->numtriangles++; 615 | } 616 | } 617 | break; 618 | 619 | default: 620 | /* eat up rest of line */ 621 | fgets(buf, sizeof(buf), file); 622 | break; 623 | } 624 | } 625 | 626 | /* set the stats in the model structure */ 627 | model->numvertices = numvertices; 628 | model->numnormals = numnormals; 629 | model->numtexcoords = numtexcoords; 630 | model->numtriangles = numtriangles; 631 | 632 | /* allocate memory for the triangles in each group */ 633 | group = model->groups; 634 | while(group) { 635 | group->triangles = (GLuint*)malloc(sizeof(GLuint) * group->numtriangles); 636 | group->numtriangles = 0; 637 | group = group->next; 638 | } 639 | } 640 | 641 | /* glmSecondPass: second pass at a Wavefront OBJ file that gets all 642 | * the data. 643 | * 644 | * model - properly initialized GLMmodel structure 645 | * file - (fopen'd) file descriptor 646 | */ 647 | static GLvoid glmSecondPass(GLMmodel* model, FILE* file, mycallback *call) 648 | { 649 | GLuint numvertices; /* number of vertices in model */ 650 | GLuint numnormals; /* number of normals in model */ 651 | GLuint numtexcoords; /* number of texcoords in model */ 652 | GLuint numtriangles; /* number of triangles in model */ 653 | GLfloat* vertices; /* array of vertices */ 654 | GLfloat* normals; /* array of normals */ 655 | GLfloat* texcoords; /* array of texture coordinates */ 656 | GLMgroup* group; /* current group pointer */ 657 | GLuint material; /* current material */ 658 | GLuint v, n, t; 659 | char buf[128]; 660 | char afis[80]; 661 | 662 | /* set the pointer shortcuts */ 663 | vertices = model->vertices; 664 | normals = model->normals; 665 | texcoords = model->texcoords; 666 | group = model->groups; 667 | 668 | /* on the second pass through the file, read all the data into the 669 | allocated arrays */ 670 | numvertices = numnormals = numtexcoords = 1; 671 | numtriangles = 0; 672 | material = 0; 673 | while(fscanf(file, "%s", buf) != EOF) { 674 | switch(buf[0]) { 675 | case '#': /* comment */ 676 | /* eat up rest of line */ 677 | fgets(buf, sizeof(buf), file); 678 | break; 679 | case 'v': /* v, vn, vt */ 680 | switch(buf[1]) { 681 | case '\0': /* vertex */ 682 | fscanf(file, "%f %f %f", 683 | &vertices[3 * numvertices + 0], 684 | &vertices[3 * numvertices + 1], 685 | &vertices[3 * numvertices + 2]); 686 | numvertices++; 687 | if (numvertices%200==0) 688 | if (call) 689 | { 690 | sprintf(afis,"%s (%s )... ",call->text, group->name); 691 | int procent = ((float)((float)numvertices*70/model->numvertices+30)/100)*(call->end-call->start)+call->start; 692 | call->loadcallback(procent,afis); // Modelul e 70% din incarcare 693 | } 694 | break; 695 | case 'n': /* normal */ 696 | fscanf(file, "%f %f %f", 697 | &normals[3 * numnormals + 0], 698 | &normals[3 * numnormals + 1], 699 | &normals[3 * numnormals + 2]); 700 | numnormals++; 701 | break; 702 | case 't': /* texcoord */ 703 | fscanf(file, "%f %f", 704 | &texcoords[2 * numtexcoords + 0], 705 | &texcoords[2 * numtexcoords + 1]); 706 | numtexcoords++; 707 | break; 708 | } 709 | break; 710 | case 'u': 711 | fgets(buf, sizeof(buf), file); 712 | sscanf(buf, "%s %s", buf, buf); 713 | group->material = material = glmFindMaterial(model, buf); 714 | break; 715 | case 'g': /* group */ 716 | /* eat up rest of line */ 717 | fgets(buf, sizeof(buf), file); 718 | #if SINGLE_STRING_GROUP_NAMES 719 | sscanf(buf, "%s", buf); 720 | #else 721 | buf[strlen(buf)-1] = '\0'; /* nuke '\n' */ 722 | #endif 723 | group = glmFindGroup(model, buf); 724 | group->material = material; 725 | break; 726 | case 'f': /* face */ 727 | v = n = t = 0; 728 | T(numtriangles).findex = -1; // ??? 729 | T(numtriangles).vecini[0]=-1; 730 | T(numtriangles).vecini[1]=-1; 731 | T(numtriangles).vecini[2]=-1; 732 | fscanf(file, "%s", buf); 733 | /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */ 734 | if (strstr(buf, "//")) { 735 | /* v//n */ 736 | sscanf(buf, "%d//%d", &v, &n); 737 | T(numtriangles).vindices[0] = v; 738 | if (n== 181228) 739 | { 740 | printf(""); 741 | } 742 | T(numtriangles).nindices[0] = n; 743 | fscanf(file, "%d//%d", &v, &n); 744 | T(numtriangles).vindices[1] = v; 745 | T(numtriangles).nindices[1] = n; 746 | fscanf(file, "%d//%d", &v, &n); 747 | T(numtriangles).vindices[2] = v; 748 | T(numtriangles).nindices[2] = n; 749 | group->triangles[group->numtriangles++] = numtriangles; 750 | numtriangles++; 751 | while(fscanf(file, "%d//%d", &v, &n) > 0) { 752 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 753 | T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0]; 754 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 755 | T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2]; 756 | T(numtriangles).vindices[2] = v; 757 | T(numtriangles).nindices[2] = n; 758 | group->triangles[group->numtriangles++] = numtriangles; 759 | numtriangles++; 760 | } 761 | } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) { 762 | /* v/t/n */ 763 | 764 | T(numtriangles).vindices[0] = v; 765 | T(numtriangles).tindices[0] = t; 766 | T(numtriangles).nindices[0] = n; 767 | fscanf(file, "%d/%d/%d", &v, &t, &n); 768 | T(numtriangles).vindices[1] = v; 769 | T(numtriangles).tindices[1] = t; 770 | T(numtriangles).nindices[1] = n; 771 | fscanf(file, "%d/%d/%d", &v, &t, &n); 772 | T(numtriangles).vindices[2] = v; 773 | T(numtriangles).tindices[2] = t; 774 | T(numtriangles).nindices[2] = n; 775 | group->triangles[group->numtriangles++] = numtriangles; 776 | numtriangles++; 777 | while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) { 778 | if (n== 181228) 779 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 780 | T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0]; 781 | T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0]; 782 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 783 | T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2]; 784 | T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2]; 785 | T(numtriangles).vindices[2] = v; 786 | T(numtriangles).tindices[2] = t; 787 | T(numtriangles).nindices[2] = n; 788 | group->triangles[group->numtriangles++] = numtriangles; 789 | numtriangles++; 790 | } 791 | } else if (sscanf(buf, "%d/%d", &v, &t) == 2) { 792 | /* v/t */ 793 | T(numtriangles).vindices[0] = v; 794 | T(numtriangles).tindices[0] = t; 795 | fscanf(file, "%d/%d", &v, &t); 796 | T(numtriangles).vindices[1] = v; 797 | T(numtriangles).tindices[1] = t; 798 | fscanf(file, "%d/%d", &v, &t); 799 | T(numtriangles).vindices[2] = v; 800 | T(numtriangles).tindices[2] = t; 801 | group->triangles[group->numtriangles++] = numtriangles; 802 | numtriangles++; 803 | while(fscanf(file, "%d/%d", &v, &t) > 0) { 804 | 805 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 806 | T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0]; 807 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 808 | T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2]; 809 | T(numtriangles).vindices[2] = v; 810 | T(numtriangles).tindices[2] = t; 811 | group->triangles[group->numtriangles++] = numtriangles; 812 | numtriangles++; 813 | } 814 | } else { 815 | /* v */ 816 | //if (n== 181228) 817 | sscanf(buf, "%d", &v); 818 | T(numtriangles).vindices[0] = v; 819 | fscanf(file, "%d", &v); 820 | T(numtriangles).vindices[1] = v; 821 | fscanf(file, "%d", &v); 822 | T(numtriangles).vindices[2] = v; 823 | group->triangles[group->numtriangles++] = numtriangles; 824 | numtriangles++; 825 | while(fscanf(file, "%d", &v) > 0) { 826 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 827 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 828 | T(numtriangles).vindices[2] = v; 829 | group->triangles[group->numtriangles++] = numtriangles; 830 | numtriangles++; 831 | } 832 | } 833 | break; 834 | 835 | default: 836 | /* eat up rest of line */ 837 | fgets(buf, sizeof(buf), file); 838 | break; 839 | } 840 | } 841 | 842 | #if 0 843 | /* announce the memory requirements */ 844 | printf(" Memory: %d bytes\n", 845 | numvertices * 3*sizeof(GLfloat) + 846 | numnormals * 3*sizeof(GLfloat) * (numnormals ? 1 : 0) + 847 | numtexcoords * 3*sizeof(GLfloat) * (numtexcoords ? 1 : 0) + 848 | numtriangles * sizeof(GLMtriangle)); 849 | #endif 850 | } 851 | 852 | 853 | /* public functions */ 854 | 855 | 856 | /* glmUnitize: "unitize" a model by translating it to the origin and 857 | * scaling it to fit in a unit cube around the origin. Returns the 858 | * scalefactor used. 859 | * 860 | * model - properly initialized GLMmodel structure 861 | */ 862 | GLfloat 863 | glmUnitize(GLMmodel* model) 864 | { 865 | GLuint i; 866 | GLfloat maxx, minx, maxy, miny, maxz, minz; 867 | GLfloat cx, cy, cz, w, h, d; 868 | GLfloat scale; 869 | 870 | assert(model); 871 | assert(model->vertices); 872 | 873 | /* get the max/mins */ 874 | maxx = minx = model->vertices[3 + 0]; 875 | maxy = miny = model->vertices[3 + 1]; 876 | maxz = minz = model->vertices[3 + 2]; 877 | for (i = 1; i <= model->numvertices; i++) { 878 | if (maxx < model->vertices[3 * i + 0]) 879 | maxx = model->vertices[3 * i + 0]; 880 | if (minx > model->vertices[3 * i + 0]) 881 | minx = model->vertices[3 * i + 0]; 882 | 883 | if (maxy < model->vertices[3 * i + 1]) 884 | maxy = model->vertices[3 * i + 1]; 885 | if (miny > model->vertices[3 * i + 1]) 886 | miny = model->vertices[3 * i + 1]; 887 | 888 | if (maxz < model->vertices[3 * i + 2]) 889 | maxz = model->vertices[3 * i + 2]; 890 | if (minz > model->vertices[3 * i + 2]) 891 | minz = model->vertices[3 * i + 2]; 892 | } 893 | 894 | /* calculate model width, height, and depth */ 895 | w = glmAbs(maxx) + glmAbs(minx); 896 | h = glmAbs(maxy) + glmAbs(miny); 897 | d = glmAbs(maxz) + glmAbs(minz); 898 | 899 | /* calculate center of the model */ 900 | cx = (maxx + minx) / 2.0; 901 | cy = (maxy + miny) / 2.0; 902 | cz = (maxz + minz) / 2.0; 903 | 904 | /* calculate unitizing scale factor */ 905 | scale = 2.0 / glmMax(glmMax(w, h), d); 906 | 907 | /* translate around center then scale */ 908 | for (i = 1; i <= model->numvertices; i++) { 909 | model->vertices[3 * i + 0] -= cx; 910 | model->vertices[3 * i + 1] -= cy; 911 | model->vertices[3 * i + 2] -= cz; 912 | model->vertices[3 * i + 0] *= scale; 913 | model->vertices[3 * i + 1] *= scale; 914 | model->vertices[3 * i + 2] *= scale; 915 | } 916 | 917 | return scale; 918 | } 919 | 920 | /* glmDimensions: Calculates the dimensions (width, height, depth) of 921 | * a model. 922 | * 923 | * model - initialized GLMmodel structure 924 | * dimensions - array of 3 GLfloats (GLfloat dimensions[3]) 925 | */ 926 | GLvoid 927 | glmDimensions(GLMmodel* model, GLfloat* dimensions) 928 | { 929 | GLuint i; 930 | GLfloat maxx, minx, maxy, miny, maxz, minz; 931 | 932 | assert(model); 933 | assert(model->vertices); 934 | assert(dimensions); 935 | 936 | /* get the max/mins */ 937 | maxx = minx = model->vertices[3 + 0]; 938 | maxy = miny = model->vertices[3 + 1]; 939 | maxz = minz = model->vertices[3 + 2]; 940 | for (i = 1; i <= model->numvertices; i++) { 941 | if (maxx < model->vertices[3 * i + 0]) 942 | maxx = model->vertices[3 * i + 0]; 943 | if (minx > model->vertices[3 * i + 0]) 944 | minx = model->vertices[3 * i + 0]; 945 | 946 | if (maxy < model->vertices[3 * i + 1]) 947 | maxy = model->vertices[3 * i + 1]; 948 | if (miny > model->vertices[3 * i + 1]) 949 | miny = model->vertices[3 * i + 1]; 950 | 951 | if (maxz < model->vertices[3 * i + 2]) 952 | maxz = model->vertices[3 * i + 2]; 953 | if (minz > model->vertices[3 * i + 2]) 954 | minz = model->vertices[3 * i + 2]; 955 | } 956 | 957 | /* calculate model width, height, and depth */ 958 | dimensions[0] = glmAbs(maxx) + glmAbs(minx); 959 | dimensions[1] = glmAbs(maxy) + glmAbs(miny); 960 | dimensions[2] = glmAbs(maxz) + glmAbs(minz); 961 | } 962 | 963 | /* glmScale: Scales a model by a given amount. 964 | * 965 | * model - properly initialized GLMmodel structure 966 | * scale - scalefactor (0.5 = half as large, 2.0 = twice as large) 967 | */ 968 | GLvoid 969 | glmScale(GLMmodel* model, GLfloat scale) 970 | { 971 | GLuint i; 972 | 973 | for (i = 1; i <= model->numvertices; i++) { 974 | model->vertices[3 * i + 0] *= scale; 975 | model->vertices[3 * i + 1] *= scale; 976 | model->vertices[3 * i + 2] *= scale; 977 | } 978 | } 979 | 980 | /* glmReverseWinding: Reverse the polygon winding for all polygons in 981 | * this model. Default winding is counter-clockwise. Also changes 982 | * the direction of the normals. 983 | * 984 | * model - properly initialized GLMmodel structure 985 | */ 986 | GLvoid 987 | glmReverseWinding(GLMmodel* model) 988 | { 989 | GLuint i, swap; 990 | 991 | assert(model); 992 | 993 | for (i = 0; i < model->numtriangles; i++) { 994 | swap = T(i).vindices[0]; 995 | T(i).vindices[0] = T(i).vindices[2]; 996 | T(i).vindices[2] = swap; 997 | 998 | if (model->numnormals) { 999 | swap = T(i).nindices[0]; 1000 | T(i).nindices[0] = T(i).nindices[2]; 1001 | T(i).nindices[2] = swap; 1002 | } 1003 | 1004 | if (model->numtexcoords) { 1005 | swap = T(i).tindices[0]; 1006 | T(i).tindices[0] = T(i).tindices[2]; 1007 | T(i).tindices[2] = swap; 1008 | } 1009 | } 1010 | 1011 | /* reverse facet normals */ 1012 | for (i = 1; i <= model->numfacetnorms; i++) { 1013 | model->facetnorms[3 * i + 0] = -model->facetnorms[3 * i + 0]; 1014 | model->facetnorms[3 * i + 1] = -model->facetnorms[3 * i + 1]; 1015 | model->facetnorms[3 * i + 2] = -model->facetnorms[3 * i + 2]; 1016 | } 1017 | 1018 | /* reverse vertex normals */ 1019 | for (i = 1; i <= model->numnormals; i++) { 1020 | model->normals[3 * i + 0] = -model->normals[3 * i + 0]; 1021 | model->normals[3 * i + 1] = -model->normals[3 * i + 1]; 1022 | model->normals[3 * i + 2] = -model->normals[3 * i + 2]; 1023 | } 1024 | } 1025 | 1026 | /* glmFacetNormals: Generates facet normals for a model (by taking the 1027 | * cross product of the two vectors derived from the sides of each 1028 | * triangle). Assumes a counter-clockwise winding. 1029 | * 1030 | * model - initialized GLMmodel structure 1031 | */ 1032 | GLvoid 1033 | glmFacetNormals(GLMmodel* model) 1034 | { 1035 | GLuint i; 1036 | GLfloat u[3]; 1037 | GLfloat v[3]; 1038 | 1039 | assert(model); 1040 | assert(model->vertices); 1041 | 1042 | /* clobber any old facetnormals */ 1043 | if (model->facetnorms) 1044 | free(model->facetnorms); 1045 | 1046 | /* allocate memory for the new facet normals */ 1047 | model->numfacetnorms = model->numtriangles; 1048 | model->facetnorms = (GLfloat*)malloc(sizeof(GLfloat) * 1049 | 3 * (model->numfacetnorms + 1)); 1050 | 1051 | for (i = 0; i < model->numtriangles; i++) 1052 | { 1053 | model->triangles[i].findex = i+1; 1054 | 1055 | u[0] = model->vertices[3 * T(i).vindices[1] + 0] - 1056 | model->vertices[3 * T(i).vindices[0] + 0]; 1057 | u[1] = model->vertices[3 * T(i).vindices[1] + 1] - 1058 | model->vertices[3 * T(i).vindices[0] + 1]; 1059 | u[2] = model->vertices[3 * T(i).vindices[1] + 2] - 1060 | model->vertices[3 * T(i).vindices[0] + 2]; 1061 | 1062 | v[0] = model->vertices[3 * T(i).vindices[2] + 0] - 1063 | model->vertices[3 * T(i).vindices[0] + 0]; 1064 | v[1] = model->vertices[3 * T(i).vindices[2] + 1] - 1065 | model->vertices[3 * T(i).vindices[0] + 1]; 1066 | v[2] = model->vertices[3 * T(i).vindices[2] + 2] - 1067 | model->vertices[3 * T(i).vindices[0] + 2]; 1068 | 1069 | glmCross(u, v, &model->facetnorms[3 * (i+1)]); 1070 | glmNormalize(&model->facetnorms[3 * (i+1)]); 1071 | } 1072 | } 1073 | 1074 | /* glmVertexNormals: Generates smooth vertex normals for a model. 1075 | * First builds a list of all the triangles each vertex is in. Then 1076 | * loops through each vertex in the the list averaging all the facet 1077 | * normals of the triangles each vertex is in. Finally, sets the 1078 | * normal index in the triangle for the vertex to the generated smooth 1079 | * normal. If the dot product of a facet normal and the facet normal 1080 | * associated with the first triangle in the list of triangles the 1081 | * current vertex is in is greater than the cosine of the angle 1082 | * parameter to the function, that facet normal is not added into the 1083 | * average normal calculation and the corresponding vertex is given 1084 | * the facet normal. This tends to preserve hard edges. The angle to 1085 | * use depends on the model, but 90 degrees is usually a good start. 1086 | * 1087 | * model - initialized GLMmodel structure 1088 | * angle - maximum angle (in degrees) to smooth across 1089 | */ 1090 | GLvoid 1091 | glmVertexNormals(GLMmodel* model, GLfloat angle) 1092 | { 1093 | GLMnode* node; 1094 | GLMnode* tail; 1095 | GLMnode** members; 1096 | GLfloat* normals; 1097 | GLuint numnormals; 1098 | GLfloat average[3]; 1099 | GLfloat dot, cos_angle; 1100 | GLuint i, avg; 1101 | 1102 | assert(model); 1103 | assert(model->facetnorms); 1104 | 1105 | /* calculate the cosine of the angle (in degrees) */ 1106 | cos_angle = cos(angle * M_PI / 180.0); 1107 | 1108 | /* nuke any previous normals */ 1109 | if (model->normals) 1110 | free(model->normals); 1111 | 1112 | /* allocate space for new normals */ 1113 | model->numnormals = model->numtriangles * 3; /* 3 normals per triangle */ 1114 | model->normals = (GLfloat*)malloc(sizeof(GLfloat)* 3* (model->numnormals+1)); 1115 | 1116 | /* allocate a structure that will hold a linked list of triangle 1117 | indices for each vertex */ 1118 | members = (GLMnode**)malloc(sizeof(GLMnode*) * (model->numvertices + 1)); 1119 | for (i = 1; i <= model->numvertices; i++) 1120 | members[i] = NULL; 1121 | 1122 | /* for every triangle, create a node for each vertex in it */ 1123 | for (i = 0; i < model->numtriangles; i++) { 1124 | node = (GLMnode*)malloc(sizeof(GLMnode)); 1125 | node->index = i; 1126 | node->next = members[T(i).vindices[0]]; 1127 | members[T(i).vindices[0]] = node; 1128 | 1129 | node = (GLMnode*)malloc(sizeof(GLMnode)); 1130 | node->index = i; 1131 | node->next = members[T(i).vindices[1]]; 1132 | members[T(i).vindices[1]] = node; 1133 | 1134 | node = (GLMnode*)malloc(sizeof(GLMnode)); 1135 | node->index = i; 1136 | node->next = members[T(i).vindices[2]]; 1137 | members[T(i).vindices[2]] = node; 1138 | } 1139 | 1140 | /* calculate the average normal for each vertex */ 1141 | numnormals = 1; 1142 | for (i = 1; i <= model->numvertices; i++) { 1143 | /* calculate an average normal for this vertex by averaging the 1144 | facet normal of every triangle this vertex is in */ 1145 | node = members[i]; 1146 | if (!node) 1147 | fprintf(stderr, "glmVertexNormals(): vertex w/o a triangle\n"); 1148 | average[0] = 0.0; average[1] = 0.0; average[2] = 0.0; 1149 | avg = 0; 1150 | while (node) { 1151 | /* only average if the dot product of the angle between the two 1152 | facet normals is greater than the cosine of the threshold 1153 | angle -- or, said another way, the angle between the two 1154 | facet normals is less than (or equal to) the threshold angle */ 1155 | dot = glmDot(&model->facetnorms[3 * T(node->index).findex], 1156 | &model->facetnorms[3 * T(members[i]->index).findex]); 1157 | if (dot > cos_angle) { 1158 | node->averaged = GL_TRUE; 1159 | average[0] += model->facetnorms[3 * T(node->index).findex + 0]; 1160 | average[1] += model->facetnorms[3 * T(node->index).findex + 1]; 1161 | average[2] += model->facetnorms[3 * T(node->index).findex + 2]; 1162 | avg = 1; /* we averaged at least one normal! */ 1163 | } else { 1164 | node->averaged = GL_FALSE; 1165 | } 1166 | node = node->next; 1167 | } 1168 | 1169 | if (avg) { 1170 | /* normalize the averaged normal */ 1171 | glmNormalize(average); 1172 | 1173 | /* add the normal to the vertex normals list */ 1174 | model->normals[3 * numnormals + 0] = average[0]; 1175 | model->normals[3 * numnormals + 1] = average[1]; 1176 | model->normals[3 * numnormals + 2] = average[2]; 1177 | avg = numnormals; 1178 | numnormals++; 1179 | } 1180 | 1181 | /* set the normal of this vertex in each triangle it is in */ 1182 | node = members[i]; 1183 | while (node) 1184 | { 1185 | if (node->index==204543) 1186 | { 1187 | printf(""); 1188 | } 1189 | if (node->averaged) { 1190 | 1191 | /* if this node was averaged, use the average normal */ 1192 | if (T(node->index).vindices[0] == i) 1193 | T(node->index).nindices[0] = avg; 1194 | else if (T(node->index).vindices[1] == i) 1195 | T(node->index).nindices[1] = avg; 1196 | else if (T(node->index).vindices[2] == i) 1197 | T(node->index).nindices[2] = avg; 1198 | } else { 1199 | 1200 | /* if this node wasn't averaged, use the facet normal */ 1201 | model->normals[3 * numnormals + 0] = 1202 | model->facetnorms[3 * T(node->index).findex + 0]; 1203 | model->normals[3 * numnormals + 1] = 1204 | model->facetnorms[3 * T(node->index).findex + 1]; 1205 | model->normals[3 * numnormals + 2] = 1206 | model->facetnorms[3 * T(node->index).findex + 2]; 1207 | if (T(node->index).vindices[0] == i) 1208 | T(node->index).nindices[0] = numnormals; 1209 | else if (T(node->index).vindices[1] == i) 1210 | T(node->index).nindices[1] = numnormals; 1211 | else if (T(node->index).vindices[2] == i) 1212 | T(node->index).nindices[2] = numnormals; 1213 | numnormals++; 1214 | } 1215 | node = node->next; 1216 | } 1217 | } 1218 | 1219 | model->numnormals = numnormals - 1; 1220 | 1221 | /* free the member information */ 1222 | for (i = 1; i <= model->numvertices; i++) { 1223 | node = members[i]; 1224 | while (node) { 1225 | tail = node; 1226 | node = node->next; 1227 | free(tail); 1228 | } 1229 | } 1230 | free(members); 1231 | 1232 | /* pack the normals array (we previously allocated the maximum 1233 | number of normals that could possibly be created (numtriangles * 1234 | 3), so get rid of some of them (usually alot unless none of the 1235 | facet normals were averaged)) */ 1236 | normals = model->normals; 1237 | model->normals = (GLfloat*)malloc(sizeof(GLfloat)* 3* (model->numnormals+1)); 1238 | for (i = 1; i <= model->numnormals; i++) { 1239 | model->normals[3 * i + 0] = normals[3 * i + 0]; 1240 | model->normals[3 * i + 1] = normals[3 * i + 1]; 1241 | model->normals[3 * i + 2] = normals[3 * i + 2]; 1242 | } 1243 | free(normals); 1244 | } 1245 | 1246 | GLvoid 1247 | glmLinearTexture(GLMmodel* model) 1248 | { 1249 | GLMgroup *group; 1250 | GLfloat dimensions[3]; 1251 | GLfloat x, y, scalefactor; 1252 | GLuint i; 1253 | 1254 | assert(model); 1255 | 1256 | if (model->texcoords) 1257 | free(model->texcoords); 1258 | model->numtexcoords = model->numvertices; 1259 | model->texcoords=(GLfloat*)malloc(sizeof(GLfloat)*2*(model->numtexcoords+1)); 1260 | 1261 | glmDimensions(model, dimensions); 1262 | scalefactor = 2.0 / 1263 | glmAbs(glmMax(glmMax(dimensions[0], dimensions[1]), dimensions[2])); 1264 | 1265 | /* do the calculations */ 1266 | for(i = 1; i <= model->numvertices; i++) { 1267 | x = model->vertices[3 * i + 0] * scalefactor; 1268 | y = model->vertices[3 * i + 2] * scalefactor; 1269 | model->texcoords[2 * i + 0] = (x + 1.0) / 2.0; 1270 | model->texcoords[2 * i + 1] = (y + 1.0) / 2.0; 1271 | } 1272 | 1273 | /* go through and put texture coordinate indices in all the triangles */ 1274 | group = model->groups; 1275 | while(group) { 1276 | for(i = 0; i < group->numtriangles; i++) { 1277 | T(group->triangles[i]).tindices[0] = T(group->triangles[i]).vindices[0]; 1278 | T(group->triangles[i]).tindices[1] = T(group->triangles[i]).vindices[1]; 1279 | T(group->triangles[i]).tindices[2] = T(group->triangles[i]).vindices[2]; 1280 | } 1281 | group = group->next; 1282 | } 1283 | 1284 | #if 0 1285 | printf("glmLinearTexture(): generated %d linear texture coordinates\n", 1286 | model->numtexcoords); 1287 | #endif 1288 | } 1289 | 1290 | /* glmSpheremapTexture: Generates texture coordinates according to a 1291 | * spherical projection of the texture map. Sometimes referred to as 1292 | * spheremap, or reflection map texture coordinates. It generates 1293 | * these by using the normal to calculate where that vertex would map 1294 | * onto a sphere. Since it is impossible to map something flat 1295 | * perfectly onto something spherical, there is distortion at the 1296 | * poles. This particular implementation causes the poles along the X 1297 | * axis to be distorted. 1298 | * 1299 | * model - pointer to initialized GLMmodel structure 1300 | */ 1301 | GLvoid 1302 | glmSpheremapTexture(GLMmodel* model) 1303 | { 1304 | GLMgroup* group; 1305 | GLfloat theta, phi, rho, x, y, z, r; 1306 | GLuint i; 1307 | 1308 | assert(model); 1309 | assert(model->normals); 1310 | 1311 | if (model->texcoords) 1312 | free(model->texcoords); 1313 | model->numtexcoords = model->numnormals; 1314 | model->texcoords=(GLfloat*)malloc(sizeof(GLfloat)*2*(model->numtexcoords+1)); 1315 | 1316 | for (i = 1; i <= model->numnormals; i++) { 1317 | z = model->normals[3 * i + 0]; /* re-arrange for pole distortion */ 1318 | y = model->normals[3 * i + 1]; 1319 | x = model->normals[3 * i + 2]; 1320 | r = sqrt((x * x) + (y * y)); 1321 | rho = sqrt((r * r) + (z * z)); 1322 | 1323 | if(r == 0.0) { 1324 | theta = 0.0; 1325 | phi = 0.0; 1326 | } else { 1327 | if(z == 0.0) 1328 | phi = 3.14159265 / 2.0; 1329 | else 1330 | phi = acos(z / rho); 1331 | 1332 | if(y == 0.0) 1333 | theta = 3.141592365 / 2.0; 1334 | else 1335 | theta = asin(y / r) + (3.14159265 / 2.0); 1336 | } 1337 | 1338 | model->texcoords[2 * i + 0] = theta / 3.14159265; 1339 | model->texcoords[2 * i + 1] = phi / 3.14159265; 1340 | } 1341 | 1342 | /* go through and put texcoord indices in all the triangles */ 1343 | group = model->groups; 1344 | while(group) { 1345 | for (i = 0; i < group->numtriangles; i++) { 1346 | T(group->triangles[i]).tindices[0] = T(group->triangles[i]).nindices[0]; 1347 | T(group->triangles[i]).tindices[1] = T(group->triangles[i]).nindices[1]; 1348 | T(group->triangles[i]).tindices[2] = T(group->triangles[i]).nindices[2]; 1349 | } 1350 | group = group->next; 1351 | } 1352 | } 1353 | 1354 | /* glmDelete: Deletes a GLMmodel structure. 1355 | * 1356 | * model - initialized GLMmodel structure 1357 | */ 1358 | GLvoid 1359 | glmDelete(GLMmodel* model) 1360 | { 1361 | GLMgroup* group; 1362 | GLuint i; 1363 | 1364 | assert(model); 1365 | 1366 | if (model->pathname) free(model->pathname); 1367 | if (model->mtllibname) free(model->mtllibname); 1368 | if (model->vertices) free(model->vertices); 1369 | if (model->normals) free(model->normals); 1370 | if (model->texcoords) free(model->texcoords); 1371 | if (model->facetnorms) free(model->facetnorms); 1372 | if (model->triangles) free(model->triangles); 1373 | if (model->materials) { 1374 | for (i = 0; i < model->nummaterials; i++) 1375 | free(model->materials[i].name); 1376 | free(model->materials); 1377 | } 1378 | if (model->textures) { 1379 | for (i = 0; i < model->numtextures; i++) { 1380 | free(model->textures[i].name); 1381 | glDeleteTextures(1,&model->textures[i].id); 1382 | } 1383 | free(model->textures); 1384 | } 1385 | 1386 | while(model->groups) { 1387 | group = model->groups; 1388 | model->groups = model->groups->next; 1389 | free(group->name); 1390 | free(group->triangles); 1391 | free(group); 1392 | } 1393 | 1394 | free(model); 1395 | } 1396 | 1397 | /* glmReadOBJ: Reads a model description from a Wavefront .OBJ file. 1398 | * Returns a pointer to the created object which should be free'd with 1399 | * glmDelete(). 1400 | * 1401 | * filename - name of the file containing the Wavefront .OBJ format data. 1402 | */ 1403 | 1404 | GLMmodel* glmReadOBJ(char* filename) 1405 | { 1406 | return glmReadOBJ(filename,0); 1407 | } 1408 | GLMmodel* glmReadOBJ(char* filename,mycallback *call) 1409 | { 1410 | GLMmodel* model; 1411 | FILE* file; 1412 | //if (call) call->loadcallback(0,"Loading Models..."); 1413 | /* open the file */ 1414 | file = fopen(filename, "r"); 1415 | if (!file) { 1416 | fprintf(stderr, "glmReadOBJ() failed: can't open data file \"%s\".\n", 1417 | filename); 1418 | exit(1); 1419 | } 1420 | 1421 | /* allocate a new model */ 1422 | model = (GLMmodel*)malloc(sizeof(GLMmodel)); 1423 | model->pathname = strdup(filename); 1424 | model->mtllibname = NULL; 1425 | model->numvertices = 0; 1426 | model->vertices = NULL; 1427 | model->numnormals = 0; 1428 | model->normals = NULL; 1429 | model->numtexcoords = 0; 1430 | model->texcoords = NULL; 1431 | model->numfacetnorms = 0; 1432 | model->facetnorms = NULL; 1433 | model->numtriangles = 0; 1434 | model->triangles = NULL; 1435 | model->nummaterials = 0; 1436 | model->materials = NULL; 1437 | model->numtextures = 0; 1438 | model->textures = NULL; 1439 | model->numgroups = 0; 1440 | model->groups = NULL; 1441 | model->position[0] = 0.0; 1442 | model->position[1] = 0.0; 1443 | model->position[2] = 0.0; 1444 | 1445 | /* make a first pass through the file to get a count of the number 1446 | of vertices, normals, texcoords & triangles */ 1447 | glmFirstPass(model, file, call); 1448 | 1449 | /* allocate memory */ 1450 | model->vertices = (GLfloat*)malloc(sizeof(GLfloat) * 1451 | 3 * (model->numvertices + 1)); 1452 | model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) * 1453 | model->numtriangles); 1454 | if (model->numnormals) { 1455 | model->normals = (GLfloat*)malloc(sizeof(GLfloat) * 1456 | 3 * (model->numnormals + 1)); 1457 | } 1458 | if (model->numtexcoords) { 1459 | model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) * 1460 | 2 * (model->numtexcoords + 1)); 1461 | } 1462 | 1463 | /* rewind to beginning of file and read in the data this pass */ 1464 | rewind(file); 1465 | 1466 | glmSecondPass(model, file,call); 1467 | 1468 | /* close the file */ 1469 | fclose(file); 1470 | 1471 | return model; 1472 | } 1473 | 1474 | /* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to 1475 | * a file. 1476 | * 1477 | * model - initialized GLMmodel structure 1478 | * filename - name of the file to write the Wavefront .OBJ format data to 1479 | * mode - a bitwise or of values describing what is written to the file 1480 | * GLM_NONE - render with only vertices 1481 | * GLM_FLAT - render with facet normals 1482 | * GLM_SMOOTH - render with vertex normals 1483 | * GLM_TEXTURE - render with texture coords 1484 | * GLM_COLOR - render with colors (color material) 1485 | * GLM_MATERIAL - render with materials 1486 | * GLM_COLOR and GLM_MATERIAL should not both be specified. 1487 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 1488 | */ 1489 | GLvoid 1490 | glmWriteOBJ(GLMmodel* model, char* filename, GLuint mode) 1491 | { 1492 | GLuint i; 1493 | FILE* file; 1494 | GLMgroup* group; 1495 | assert(model); 1496 | 1497 | /* do a bit of warning */ 1498 | if (mode & GLM_FLAT && !model->facetnorms) { 1499 | printf("glmWriteOBJ() warning: flat normal output requested " 1500 | "with no facet normals defined.\n"); 1501 | mode &= ~GLM_FLAT; 1502 | } 1503 | if (mode & GLM_SMOOTH && !model->normals) { 1504 | printf("glmWriteOBJ() warning: smooth normal output requested " 1505 | "with no normals defined.\n"); 1506 | mode &= ~GLM_SMOOTH; 1507 | } 1508 | if (mode & GLM_TEXTURE && !model->texcoords) { 1509 | printf("glmWriteOBJ() warning: texture coordinate output requested " 1510 | "with no texture coordinates defined.\n"); 1511 | mode &= ~GLM_TEXTURE; 1512 | } 1513 | if (mode & GLM_FLAT && mode & GLM_SMOOTH) { 1514 | printf("glmWriteOBJ() warning: flat normal output requested " 1515 | "and smooth normal output requested (using smooth).\n"); 1516 | mode &= ~GLM_FLAT; 1517 | } 1518 | if (mode & GLM_COLOR && !model->materials) { 1519 | printf("glmWriteOBJ() warning: color output requested " 1520 | "with no colors (materials) defined.\n"); 1521 | mode &= ~GLM_COLOR; 1522 | } 1523 | if (mode & GLM_MATERIAL && !model->materials) { 1524 | printf("glmWriteOBJ() warning: material output requested " 1525 | "with no materials defined.\n"); 1526 | mode &= ~GLM_MATERIAL; 1527 | } 1528 | if (mode & GLM_COLOR && mode & GLM_MATERIAL) { 1529 | printf("glmWriteOBJ() warning: color and material output requested " 1530 | "outputting only materials.\n"); 1531 | mode &= ~GLM_COLOR; 1532 | } 1533 | 1534 | 1535 | /* open the file */ 1536 | file = fopen(filename, "w"); 1537 | if (!file) { 1538 | fprintf(stderr, "glmWriteOBJ() failed: can't open file \"%s\" to write.\n", 1539 | filename); 1540 | exit(1); 1541 | } 1542 | 1543 | /* spit out a header */ 1544 | fprintf(file, "# \n"); 1545 | fprintf(file, "# Wavefront OBJ generated by GLM library\n"); 1546 | fprintf(file, "# \n"); 1547 | fprintf(file, "# GLM library\n"); 1548 | fprintf(file, "# Nate Robins\n"); 1549 | fprintf(file, "# ndr@pobox.com\n"); 1550 | fprintf(file, "# http://www.pobox.com/~ndr\n"); 1551 | fprintf(file, "# \n"); 1552 | 1553 | if (mode & GLM_MATERIAL && model->mtllibname) { 1554 | fprintf(file, "\nmtllib %s\n\n", model->mtllibname); 1555 | glmWriteMTL(model, filename, model->mtllibname); 1556 | } 1557 | 1558 | /* spit out the vertices */ 1559 | fprintf(file, "\n"); 1560 | fprintf(file, "# %d vertices\n", model->numvertices); 1561 | for (i = 1; i <= model->numvertices; i++) { 1562 | fprintf(file, "v %f %f %f\n", 1563 | model->vertices[3 * i + 0], 1564 | model->vertices[3 * i + 1], 1565 | model->vertices[3 * i + 2]); 1566 | } 1567 | 1568 | /* spit out the smooth/flat normals */ 1569 | if (mode & GLM_SMOOTH) { 1570 | fprintf(file, "\n"); 1571 | fprintf(file, "# %d normals\n", model->numnormals); 1572 | for (i = 1; i <= model->numnormals; i++) { 1573 | fprintf(file, "vn %f %f %f\n", 1574 | model->normals[3 * i + 0], 1575 | model->normals[3 * i + 1], 1576 | model->normals[3 * i + 2]); 1577 | } 1578 | } else if (mode & GLM_FLAT) { 1579 | fprintf(file, "\n"); 1580 | fprintf(file, "# %d normals\n", model->numfacetnorms); 1581 | for (i = 1; i <= model->numnormals; i++) { 1582 | fprintf(file, "vn %f %f %f\n", 1583 | model->facetnorms[3 * i + 0], 1584 | model->facetnorms[3 * i + 1], 1585 | model->facetnorms[3 * i + 2]); 1586 | } 1587 | } 1588 | 1589 | /* spit out the texture coordinates */ 1590 | if (mode & GLM_TEXTURE) { 1591 | fprintf(file, "\n"); 1592 | fprintf(file, "# %d texcoords\n", model->texcoords); 1593 | for (i = 1; i <= model->numtexcoords; i++) { 1594 | fprintf(file, "vt %f %f\n", 1595 | model->texcoords[2 * i + 0], 1596 | model->texcoords[2 * i + 1]); 1597 | } 1598 | } 1599 | 1600 | fprintf(file, "\n"); 1601 | fprintf(file, "# %d groups\n", model->numgroups); 1602 | fprintf(file, "# %d faces (triangles)\n", model->numtriangles); 1603 | fprintf(file, "\n"); 1604 | 1605 | group = model->groups; 1606 | while(group) { 1607 | fprintf(file, "g %s\n", group->name); 1608 | if (mode & GLM_MATERIAL) 1609 | fprintf(file, "usemtl %s\n", model->materials[group->material].name); 1610 | for (i = 0; i < group->numtriangles; i++) { 1611 | if (mode & GLM_SMOOTH && mode & GLM_TEXTURE) { 1612 | fprintf(file, "f %d/%d/%d %d/%d/%d %d/%d/%d\n", 1613 | T(group->triangles[i]).vindices[0], 1614 | T(group->triangles[i]).nindices[0], 1615 | T(group->triangles[i]).tindices[0], 1616 | T(group->triangles[i]).vindices[1], 1617 | T(group->triangles[i]).nindices[1], 1618 | T(group->triangles[i]).tindices[1], 1619 | T(group->triangles[i]).vindices[2], 1620 | T(group->triangles[i]).nindices[2], 1621 | T(group->triangles[i]).tindices[2]); 1622 | } else if (mode & GLM_FLAT && mode & GLM_TEXTURE) { 1623 | fprintf(file, "f %d/%d %d/%d %d/%d\n", 1624 | T(group->triangles[i]).vindices[0], 1625 | T(group->triangles[i]).findex, 1626 | T(group->triangles[i]).vindices[1], 1627 | T(group->triangles[i]).findex, 1628 | T(group->triangles[i]).vindices[2], 1629 | T(group->triangles[i]).findex); 1630 | } else if (mode & GLM_TEXTURE) { 1631 | fprintf(file, "f %d/%d %d/%d %d/%d\n", 1632 | T(group->triangles[i]).vindices[0], 1633 | T(group->triangles[i]).tindices[0], 1634 | T(group->triangles[i]).vindices[1], 1635 | T(group->triangles[i]).tindices[1], 1636 | T(group->triangles[i]).vindices[2], 1637 | T(group->triangles[i]).tindices[2]); 1638 | } else if (mode & GLM_SMOOTH) { 1639 | fprintf(file, "f %d//%d %d//%d %d//%d\n", 1640 | T(group->triangles[i]).vindices[0], 1641 | T(group->triangles[i]).nindices[0], 1642 | T(group->triangles[i]).vindices[1], 1643 | T(group->triangles[i]).nindices[1], 1644 | T(group->triangles[i]).vindices[2], 1645 | T(group->triangles[i]).nindices[2]); 1646 | } else if (mode & GLM_FLAT) { 1647 | fprintf(file, "f %d//%d %d//%d %d//%d\n", 1648 | T(group->triangles[i]).vindices[0], 1649 | T(group->triangles[i]).findex, 1650 | T(group->triangles[i]).vindices[1], 1651 | T(group->triangles[i]).findex, 1652 | T(group->triangles[i]).vindices[2], 1653 | T(group->triangles[i]).findex); 1654 | } else { 1655 | fprintf(file, "f %d %d %d\n", 1656 | T(group->triangles[i]).vindices[0], 1657 | T(group->triangles[i]).vindices[1], 1658 | T(group->triangles[i]).vindices[2]); 1659 | } 1660 | } 1661 | fprintf(file, "\n"); 1662 | group = group->next; 1663 | } 1664 | 1665 | fclose(file); 1666 | } 1667 | 1668 | /* glmDraw: Renders the model to the current OpenGL context using the 1669 | * mode specified. 1670 | * 1671 | * model - initialized GLMmodel structure 1672 | * mode - a bitwise OR of values describing what is to be rendered. 1673 | * GLM_NONE - render with only vertices 1674 | * GLM_FLAT - render with facet normals 1675 | * GLM_SMOOTH - render with vertex normals 1676 | * GLM_TEXTURE - render with texture coords 1677 | * GLM_COLOR - render with colors (color material) 1678 | * GLM_MATERIAL - render with materials 1679 | * GLM_COLOR and GLM_MATERIAL should not both be specified. 1680 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 1681 | */ 1682 | 1683 | GLvoid glmDraw(GLMmodel* model, GLuint mode) 1684 | { 1685 | glmDraw(model,mode,0); 1686 | } 1687 | GLvoid glmDraw(GLMmodel* model, GLuint mode,char *drawonly) 1688 | { 1689 | static GLuint i; 1690 | static GLMgroup* group; 1691 | static GLMtriangle* triangle; 1692 | static GLMmaterial* material; 1693 | GLuint IDTextura; 1694 | 1695 | assert(model); 1696 | assert(model->vertices); 1697 | 1698 | /* do a bit of warning */ 1699 | if (mode & GLM_FLAT && !model->facetnorms) { 1700 | printf("glmDraw() warning: flat render mode requested " 1701 | "with no facet normals defined.\n"); 1702 | mode &= ~GLM_FLAT; 1703 | } 1704 | if (mode & GLM_SMOOTH && !model->normals) { 1705 | printf("glmDraw() warning: smooth render mode requested " 1706 | "with no normals defined.\n"); 1707 | mode &= ~GLM_SMOOTH; 1708 | } 1709 | if (mode & GLM_TEXTURE && !model->texcoords) { 1710 | printf("glmDraw() warning: texture render mode requested " 1711 | "with no texture coordinates defined.\n"); 1712 | mode &= ~GLM_TEXTURE; 1713 | } 1714 | if (mode & GLM_FLAT && mode & GLM_SMOOTH) { 1715 | printf("glmDraw() warning: flat render mode requested " 1716 | "and smooth render mode requested (using smooth).\n"); 1717 | mode &= ~GLM_FLAT; 1718 | } 1719 | if (mode & GLM_COLOR && !model->materials) { 1720 | printf("glmDraw() warning: color render mode requested " 1721 | "with no materials defined.\n"); 1722 | mode &= ~GLM_COLOR; 1723 | } 1724 | if (mode & GLM_MATERIAL && !model->materials) { 1725 | printf("glmDraw() warning: material render mode requested " 1726 | "with no materials defined.\n"); 1727 | mode &= ~GLM_MATERIAL; 1728 | } 1729 | if (mode & GLM_COLOR && mode & GLM_MATERIAL) { 1730 | printf("glmDraw() warning: color and material render mode requested " 1731 | "using only material mode.\n"); 1732 | mode &= ~GLM_COLOR; 1733 | } 1734 | if (mode & GLM_COLOR) 1735 | glEnable(GL_COLOR_MATERIAL); 1736 | else if (mode & GLM_MATERIAL) 1737 | glDisable(GL_COLOR_MATERIAL); 1738 | if (mode & GLM_TEXTURE) { 1739 | glEnable(GL_TEXTURE_2D); 1740 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 1741 | } 1742 | /* perhaps this loop should be unrolled into material, color, flat, 1743 | smooth, etc. loops? since most cpu's have good branch prediction 1744 | schemes (and these branches will always go one way), probably 1745 | wouldn't gain too much? */ 1746 | 1747 | IDTextura = -1; 1748 | group = model->groups; 1749 | while (group) 1750 | { 1751 | if (drawonly) 1752 | if (strcmp(group->name,drawonly)) 1753 | { 1754 | group=group->next; 1755 | continue; 1756 | } 1757 | 1758 | material = &model->materials[group->material]; 1759 | if (material) 1760 | IDTextura = material->IDTextura; 1761 | else IDTextura=-1; 1762 | 1763 | if (mode & GLM_MATERIAL) 1764 | { 1765 | glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, material->ambient); 1766 | glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material->diffuse); 1767 | glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material->specular); 1768 | glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material->shininess); 1769 | } 1770 | 1771 | if (mode & GLM_TEXTURE) 1772 | { 1773 | if(IDTextura == -1) 1774 | glBindTexture(GL_TEXTURE_2D, 0); 1775 | else 1776 | glBindTexture(GL_TEXTURE_2D, model->textures[IDTextura].id); 1777 | } 1778 | 1779 | if (mode & GLM_COLOR) { 1780 | glColor3fv(material->diffuse); 1781 | } 1782 | 1783 | glBegin(GL_TRIANGLES); 1784 | for (i = 0; i < group->numtriangles; i++) { 1785 | triangle = &T(group->triangles[i]); 1786 | #ifdef DebugVisibleSurfaces 1787 | if (!triangle->visible) continue; 1788 | #endif 1789 | if (mode & GLM_FLAT) 1790 | glNormal3fv(&model->facetnorms[3 * triangle->findex]); 1791 | 1792 | if (mode & GLM_SMOOTH) 1793 | glNormal3fv(&model->normals[3 * triangle->nindices[0]]); 1794 | if (mode & GLM_TEXTURE) 1795 | glTexCoord2fv(&model->texcoords[2 * triangle->tindices[0]]); 1796 | glVertex3fv(&model->vertices[3 * triangle->vindices[0]]); 1797 | 1798 | if (mode & GLM_SMOOTH) 1799 | glNormal3fv(&model->normals[3 * triangle->nindices[1]]); 1800 | if (mode & GLM_TEXTURE) 1801 | { 1802 | //if (IDTextura==-1) printf("Warning: GLM_TEXTURE este on dar nu este setata nici o textura in material!"); 1803 | glTexCoord2fv(&model->texcoords[2 * triangle->tindices[1]]); 1804 | } 1805 | glVertex3fv(&model->vertices[3 * triangle->vindices[1]]); 1806 | 1807 | if (mode & GLM_SMOOTH) 1808 | glNormal3fv(&model->normals[3 * triangle->nindices[2]]); 1809 | if (mode & GLM_TEXTURE) 1810 | glTexCoord2fv(&model->texcoords[2 * triangle->tindices[2]]); 1811 | glVertex3fv(&model->vertices[3 * triangle->vindices[2]]); 1812 | 1813 | } 1814 | glEnd(); 1815 | 1816 | group = group->next; 1817 | } 1818 | } 1819 | 1820 | /* glmList: Generates and returns a display list for the model using 1821 | * the mode specified. 1822 | * 1823 | * model - initialized GLMmodel structure 1824 | * mode - a bitwise OR of values describing what is to be rendered. 1825 | * GLM_NONE - render with only vertices 1826 | * GLM_FLAT - render with facet normals 1827 | * GLM_SMOOTH - render with vertex normals 1828 | * GLM_TEXTURE - render with texture coords 1829 | * GLM_COLOR - render with colors (color material) 1830 | * GLM_MATERIAL - render with materials 1831 | * GLM_COLOR and GLM_MATERIAL should not both be specified. 1832 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 1833 | */ 1834 | GLuint 1835 | glmList(GLMmodel* model, GLuint mode) 1836 | { 1837 | GLuint list; 1838 | 1839 | list = glGenLists(1); 1840 | glNewList(list, GL_COMPILE); 1841 | glmDraw(model, mode); 1842 | glEndList(); 1843 | 1844 | return list; 1845 | } 1846 | 1847 | /* glmWeld: eliminate (weld) vectors that are within an epsilon of 1848 | * each other. 1849 | * 1850 | * model - initialized GLMmodel structure 1851 | * epsilon - maximum difference between vertices 1852 | * ( 0.00001 is a good start for a unitized model) 1853 | * 1854 | */ 1855 | GLvoid 1856 | glmWeld(GLMmodel* model, GLfloat epsilon) 1857 | { 1858 | GLfloat* vectors; 1859 | GLfloat* copies; 1860 | GLuint numvectors; 1861 | GLuint i; 1862 | 1863 | /* vertices */ 1864 | numvectors = model->numvertices; 1865 | vectors = model->vertices; 1866 | copies = glmWeldVectors(vectors, &numvectors, epsilon); 1867 | 1868 | #if 0 1869 | printf("glmWeld(): %d redundant vertices.\n", 1870 | model->numvertices - numvectors - 1); 1871 | #endif 1872 | 1873 | for (i = 0; i < model->numtriangles; i++) { 1874 | T(i).vindices[0] = (GLuint)vectors[3 * T(i).vindices[0] + 0]; 1875 | T(i).vindices[1] = (GLuint)vectors[3 * T(i).vindices[1] + 0]; 1876 | T(i).vindices[2] = (GLuint)vectors[3 * T(i).vindices[2] + 0]; 1877 | } 1878 | 1879 | /* free space for old vertices */ 1880 | free(vectors); 1881 | 1882 | /* allocate space for the new vertices */ 1883 | model->numvertices = numvectors; 1884 | model->vertices = (GLfloat*)malloc(sizeof(GLfloat) * 1885 | 3 * (model->numvertices + 1)); 1886 | 1887 | /* copy the optimized vertices into the actual vertex list */ 1888 | for (i = 1; i <= model->numvertices; i++) { 1889 | model->vertices[3 * i + 0] = copies[3 * i + 0]; 1890 | model->vertices[3 * i + 1] = copies[3 * i + 1]; 1891 | model->vertices[3 * i + 2] = copies[3 * i + 2]; 1892 | } 1893 | 1894 | free(copies); 1895 | } 1896 | 1897 | /* glmReadPPM: read a PPM raw (type P6) file. The PPM file has a header 1898 | * that should look something like: 1899 | * 1900 | * P6 1901 | * # comment 1902 | * width height max_value 1903 | * rgbrgbrgb... 1904 | * 1905 | * where "P6" is the magic cookie which identifies the file type and 1906 | * should be the only characters on the first line followed by a 1907 | * carriage return. Any line starting with a # mark will be treated 1908 | * as a comment and discarded. After the magic cookie, three integer 1909 | * values are expected: width, height of the image and the maximum 1910 | * value for a pixel (max_value must be < 256 for PPM raw files). The 1911 | * data section consists of width*height rgb triplets (one byte each) 1912 | * in binary format (i.e., such as that written with fwrite() or 1913 | * equivalent). 1914 | * 1915 | * The rgb data is returned as an array of unsigned chars (packed 1916 | * rgb). The malloc()'d memory should be free()'d by the caller. If 1917 | * an error occurs, an error message is sent to stderr and NULL is 1918 | * returned. 1919 | * 1920 | * filename - name of the .ppm file. 1921 | * width - will contain the width of the image on return. 1922 | * height - will contain the height of the image on return. 1923 | * 1924 | */ 1925 | GLubyte* 1926 | glmReadPPM(char* filename, int* width, int* height) 1927 | { 1928 | FILE* fp; 1929 | int i, w, h, d; 1930 | unsigned char* image; 1931 | char head[70]; /* max line <= 70 in PPM (per spec). */ 1932 | 1933 | fp = fopen(filename, "rb"); 1934 | if (!fp) { 1935 | perror(filename); 1936 | return NULL; 1937 | } 1938 | 1939 | /* grab first two chars of the file and make sure that it has the 1940 | correct magic cookie for a raw PPM file. */ 1941 | fgets(head, 70, fp); 1942 | if (strncmp(head, "P6", 2)) { 1943 | fprintf(stderr, "%s: Not a raw PPM file\n", filename); 1944 | return NULL; 1945 | } 1946 | 1947 | /* grab the three elements in the header (width, height, maxval). */ 1948 | i = 0; 1949 | while(i < 3) { 1950 | fgets(head, 70, fp); 1951 | if (head[0] == '#') /* skip comments. */ 1952 | continue; 1953 | if (i == 0) 1954 | i += sscanf(head, "%d %d %d", &w, &h, &d); 1955 | else if (i == 1) 1956 | i += sscanf(head, "%d %d", &h, &d); 1957 | else if (i == 2) 1958 | i += sscanf(head, "%d", &d); 1959 | } 1960 | 1961 | /* grab all the image data in one fell swoop. */ 1962 | image = (unsigned char*)malloc(sizeof(unsigned char)*w*h*3); 1963 | fread(image, sizeof(unsigned char), w*h*3, fp); 1964 | fclose(fp); 1965 | 1966 | *width = w; 1967 | *height = h; 1968 | return image; 1969 | } 1970 | 1971 | #if 0 1972 | /* normals */ 1973 | if (model->numnormals) { 1974 | numvectors = model->numnormals; 1975 | vectors = model->normals; 1976 | copies = glmOptimizeVectors(vectors, &numvectors); 1977 | 1978 | printf("glmOptimize(): %d redundant normals.\n", 1979 | model->numnormals - numvectors); 1980 | 1981 | for (i = 0; i < model->numtriangles; i++) { 1982 | T(i).nindices[0] = (GLuint)vectors[3 * T(i).nindices[0] + 0]; 1983 | T(i).nindices[1] = (GLuint)vectors[3 * T(i).nindices[1] + 0]; 1984 | T(i).nindices[2] = (GLuint)vectors[3 * T(i).nindices[2] + 0]; 1985 | } 1986 | 1987 | /* free space for old normals */ 1988 | free(vectors); 1989 | 1990 | /* allocate space for the new normals */ 1991 | model->numnormals = numvectors; 1992 | model->normals = (GLfloat*)malloc(sizeof(GLfloat) * 1993 | 3 * (model->numnormals + 1)); 1994 | 1995 | /* copy the optimized vertices into the actual vertex list */ 1996 | for (i = 1; i <= model->numnormals; i++) { 1997 | model->normals[3 * i + 0] = copies[3 * i + 0]; 1998 | model->normals[3 * i + 1] = copies[3 * i + 1]; 1999 | model->normals[3 * i + 2] = copies[3 * i + 2]; 2000 | } 2001 | 2002 | free(copies); 2003 | } 2004 | 2005 | /* texcoords */ 2006 | if (model->numtexcoords) { 2007 | numvectors = model->numtexcoords; 2008 | vectors = model->texcoords; 2009 | copies = glmOptimizeVectors(vectors, &numvectors); 2010 | 2011 | printf("glmOptimize(): %d redundant texcoords.\n", 2012 | model->numtexcoords - numvectors); 2013 | 2014 | for (i = 0; i < model->numtriangles; i++) { 2015 | for (j = 0; j < 3; j++) { 2016 | T(i).tindices[j] = (GLuint)vectors[3 * T(i).tindices[j] + 0]; 2017 | } 2018 | } 2019 | 2020 | /* free space for old texcoords */ 2021 | free(vectors); 2022 | 2023 | /* allocate space for the new texcoords */ 2024 | model->numtexcoords = numvectors; 2025 | model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) * 2026 | 2 * (model->numtexcoords + 1)); 2027 | 2028 | /* copy the optimized vertices into the actual vertex list */ 2029 | for (i = 1; i <= model->numtexcoords; i++) { 2030 | model->texcoords[2 * i + 0] = copies[2 * i + 0]; 2031 | model->texcoords[2 * i + 1] = copies[2 * i + 1]; 2032 | } 2033 | 2034 | free(copies); 2035 | } 2036 | #endif 2037 | 2038 | #if 0 2039 | /* look for unused vertices */ 2040 | /* look for unused normals */ 2041 | /* look for unused texcoords */ 2042 | for (i = 1; i <= model->numvertices; i++) { 2043 | for (j = 0; j < model->numtriangles; i++) { 2044 | if (T(j).vindices[0] == i || 2045 | T(j).vindices[1] == i || 2046 | T(j).vindices[1] == i) 2047 | break; 2048 | } 2049 | } 2050 | #endif 2051 | --------------------------------------------------------------------------------