├── CMakeLists-base.txt ├── CMakeLists.txt ├── README.md ├── src ├── CMakeLists.txt ├── bounding_device.cu ├── bounding_host.cc ├── voxelizer_api.cu ├── voxelizer_device.cu ├── voxelizer_host.cc └── voxelizer_imp.cuh └── test ├── CMakeLists.txt ├── glm ├── .svn │ ├── all-wcprops │ ├── dir-prop-base │ ├── entries │ └── text-base │ │ ├── glm.cpp.svn-base │ │ └── glm.h.svn-base ├── glm.cpp └── glm.h ├── main.cc ├── main.cu ├── voxelizer_demo.cu ├── voxelizer_demo.h ├── voxelizer_test.cu └── voxelizer_test.h /CMakeLists-base.txt: -------------------------------------------------------------------------------- 1 | project(${proj_name}) 2 | 3 | option(BUILD_SHARED 4 | "On to build shared libraries, off for static libraries." 5 | OFF) 6 | 7 | option(BUILD_DEBUG 8 | "On to build release version, off for debug version." 9 | OFF) 10 | 11 | if (BUILD_SHARED) 12 | add_definitions(-DBUILD_SHARED) 13 | set(LIB_TYPE SHARED) 14 | else () 15 | set(LIB_TYPE STATIC) 16 | endif (BUILD_SHARED) 17 | 18 | # there should be no comma between the name and value 19 | set(lib_dir ${PROJECT_SOURCE_DIR}/lib) 20 | set(bin_dir ${PROJECT_SOURCE_DIR}/bin) 21 | set(work_dir ${PROJECT_SOURCE_DIR}/..) 22 | 23 | if (WIN32) 24 | set(magic_dir D:) 25 | else () 26 | set(magic_dir /media/D) 27 | endif (WIN32) 28 | 29 | if (BUILD_DEBUG) 30 | set(CMAKE_BUILD_TYPE "Debug") 31 | else () 32 | set(CMAKE_BUILD_TYPE "Release") 33 | endif (BUILD_DEBUG) 34 | 35 | if (MSVC) 36 | foreach(OUTPUT_CONFIG ${CMAKE_CONFIGURATION_TYPES}) 37 | message(STATUS "OUTPUT_CONFIG=${OUTPUT_CONFIG}") 38 | string(TOUPPER ${OUTPUT_CONFIG} OUTPUT_CONFIG) 39 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUT_CONFIG} ${lib_dir}) 40 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUT_CONFIG} ${lib_dir}) 41 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUT_CONFIG} ${bin_dir}) 42 | endforeach(OUTPUT_CONFIG ${CMAKE_CONFIGURATION_TYPES}) 43 | else () 44 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${lib_dir}) 45 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${lib_dir}) 46 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${bin_dir}) 47 | endif (MSVC) 48 | 49 | message(STATUS "BIN_DIR=${bin_dir}") 50 | message(STATUS "LIB_DIR=${lib_dir}") 51 | message(STATUS "WORK_DIR=${work_dir}") 52 | message(STATUS "LIB_TYPE = ${lib_type}") 53 | message(STATUS "MAGIC_DIR = ${magic_dir}") 54 | 55 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(proj_name VOXELIZER) 2 | 3 | cmake_minimum_required(VERSION 2.8) 4 | 5 | include(CMakeLists-base.txt) 6 | 7 | if (WIN32) 8 | set(NV_COMPUTE_SDK_ROOT 9 | E:/NVIDIA Corporation/NVIDIA GPU Computing SDK 4.0) 10 | else () 11 | set(NV_COMPUTE_SDK_ROOT ~/NVIDIA_GPU_Computing_SDK) 12 | endif (WIN32) 13 | 14 | include(FindCUDA) 15 | include_directories(${work_dir}/axle/include 16 | ${magic_dir}/glm-0.9.3.B 17 | ${NV_COMPUTE_SDK_ROOT}/C/common/inc 18 | ${NV_COMPUTE_SDK_ROOT}/shared/inc 19 | ./include) 20 | 21 | find_package(CUDA REQUIRED) 22 | 23 | add_subdirectory(src ${lib_dir}) 24 | add_subdirectory(test ${bin_dir}) 25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | voxelizer 2 | ========= 3 | 4 | implementation of Fast parallel surface and solid voxelization on GPUs 5 | 6 | only implemented surface voxelization so far 7 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(inc_path ../include/voxel) 2 | file(GLOB lib_inc ${inc_path}/*.h) 3 | file(GLOB lib_src *.cc *.cu) 4 | 5 | include_directories(${MAGIC_DIR}/cudpp/include) 6 | 7 | #set(CUDA_NVCC_FLAGS "-arch=sm_20") 8 | 9 | set(GENCODE_SM10 -gencode=arch=compute_10,code=sm_10 -gencode=arch=compute_10,code=compute_10) 10 | set(GENCODE_SM13 -gencode=arch=compute_13,code=sm_13 -gencode=arch=compute_13,code=compute_13) 11 | set(GENCODE_SM20 -gencode=arch=compute_20,code=sm_20 -gencode=arch=compute_20,code=compute_20) 12 | 13 | set(target_name "voxelizer") 14 | 15 | cuda_add_library(${target_name} ${LIB_TYPE} 16 | ${lib_src} ${lib_inc} 17 | OPTIONS ${GENCODE_SM13} ${GENCODE_SM20} 18 | ) 19 | 20 | set(output "${target_name}") 21 | set(debug_output "${output}_d") 22 | 23 | set_target_properties(${target_name} PROPERTIES OUTPUT_NAME_DEBUG ${debug_output}) 24 | set_target_properties(${target_name} PROPERTIES OUTPUT_NAME_RELEASE ${output}) 25 | 26 | -------------------------------------------------------------------------------- /src/bounding_device.cu: -------------------------------------------------------------------------------- 1 | #include "voxel/bounding.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "axle/core/debug.h" 7 | 8 | namespace voxel { 9 | __device__ void update_bound(const float f, float *bbox0, float *bbox1) { 10 | if (f < *bbox0) *bbox0 = f; 11 | if (f > *bbox1) *bbox1 = f; 12 | } 13 | 14 | __device__ void update_bound(const float *vertex, const int tri_idx, const int N, 15 | float *bbox0, float *bbox1) { 16 | int c_idx = tri_idx; 17 | update_bound(vertex[0], &bbox0[c_idx], &bbox1[c_idx]); 18 | c_idx += N; 19 | update_bound(vertex[1], &bbox0[c_idx], &bbox1[c_idx]); 20 | c_idx += N; 21 | update_bound(vertex[2], &bbox0[c_idx], &bbox1[c_idx]); 22 | } 23 | 24 | __global__ void compute_bounkernel(const float *vertices, const int *triangles, 25 | const int N, float *bbox0, float *bbox1) { 26 | int tri_idx = blockIdx.x * blockDim.x + threadIdx.x; 27 | if (tri_idx >= N) return; 28 | 29 | //bbox0[i] == bbox0[i].x 30 | //bbox0[i + N] == bbox0[i].y 31 | //bbox0[i + N + N] == bbox0[i].z 32 | for (int c = 0, c_idx = tri_idx; c < 3; ++c, c_idx += N) { 33 | bbox0[c_idx] = INFINITY; 34 | bbox1[c_idx] = -INFINITY; 35 | } 36 | for (int c = 0, vert_idx = tri_idx; c < 3; ++c, vert_idx += N) { 37 | update_bound(&vertices[3 * triangles[vert_idx]], tri_idx, N, bbox0, bbox1); 38 | } 39 | } 40 | 41 | int ComputeBoundDevice(const float *vertices, const int *triangles, 42 | const int N, float *tri_bbox0, float *tri_bbox1) { 43 | assert(NULL != vertices && NULL != triangles && 44 | NULL != tri_bbox0 && NULL != tri_bbox1); 45 | 46 | if (NULL == vertices || NULL == triangles || 47 | NULL == tri_bbox0 || NULL == tri_bbox1) return ax::kInvalidArg; 48 | 49 | const int block_size = 1024; 50 | // int block_num = (N + block_size - 1) / block_size; 51 | int block_num = N / block_size; 52 | if (N & 0x3ff) ++block_num; 53 | compute_bounkernel<<>>(vertices, triangles, N, 54 | tri_bbox0, tri_bbox1); 55 | cudaError_t cudaStatus; 56 | cudaStatus = cudaDeviceSynchronize(); 57 | if (cudaSuccess != cudaStatus ) { 58 | ax::Logger::Debug("compute bound kernel failed!\n"); 59 | return ax::kFailed; 60 | } 61 | return ax::kOK; 62 | } 63 | 64 | int UnionBoundDevice(const float *tri_bbox0, const float *tri_bbox1, 65 | const int N, float *bbox0, float *bbox1) { 66 | //ax::Logger::Log("UnionBoundDevice"); 67 | //CUDPPHandle cudpp_handle; 68 | //cudppCreate(&cudpp_handle); 69 | //CUDPPConfiguration config; 70 | //config.op = CUDPP_MIN; 71 | //config.datatype = CUDPP_FLOAT; 72 | //config.algorithm = CUDPP_REDUCE; 73 | //config.options = CUDPP_OPTION_FORWARD; 74 | 75 | //CUDPPHandle min_reduce_plan = 0, max_reduce_plan = 0; 76 | //V_RET(CreatePlan(cudpp_handle, config, N, 1, 0, &min_reduce_plan)); 77 | 78 | //config.op = CUDPP_MAX; 79 | //V_RET(CreatePlan(cudpp_handle, config, N, 1, 0, &max_reduce_plan)); 80 | 81 | //for (int i = 0, offset = 0; i < 3; ++i, offset += N) { 82 | // //find mins for every component of tri_bbox0 83 | // V_RET(Reduce(min_reduce_plan, tri_bbox0 + offset, N, &bbox0[i])); 84 | // 85 | // //find maxs for every component of tri_bbox1 86 | // V_RET(Reduce(max_reduce_plan, tri_bbox1 + offset, N, &bbox1[i])); 87 | //} 88 | return ax::kOK; 89 | } 90 | 91 | } // voxel 92 | -------------------------------------------------------------------------------- /src/bounding_host.cc: -------------------------------------------------------------------------------- 1 | #include "voxel/bounding.h" 2 | 3 | #include 4 | 5 | #include "axle/core/types.h" 6 | //#include 7 | 8 | namespace voxel { 9 | class MaxOp { 10 | public: 11 | void operator()(const float f, float *res) const { 12 | assert(NULL != res); 13 | if (f > *res) *res = f; 14 | } 15 | static const float s_init_val; 16 | }; 17 | const float MaxOp::s_init_val = -FLT_MAX; 18 | 19 | class MinOp { 20 | public: 21 | void operator()(const float f, float *res) const { 22 | assert(NULL != res); 23 | if (f < *res) *res = f; 24 | } 25 | static const float s_init_val; 26 | }; 27 | const float MinOp::s_init_val = FLT_MAX; 28 | 29 | template 30 | inline int Reduce(const float *h_in, int N, const Op &op, float *h_out) { 31 | assert(NULL != h_out); 32 | *h_out = op.s_init_val; 33 | for (int i = 0; i < N; ++i) { 34 | op(h_in[i], h_out); 35 | } 36 | return ax::kOK; 37 | } 38 | 39 | int UnionBoundHost(const float *h_tri_bbox0, const float *h_tri_bbox1, const int N, 40 | float *h_bbox0, float *h_bbox1) { 41 | if (N < 1) return ax::kOK; 42 | MinOp min_op; 43 | MaxOp max_op; 44 | for (int i = 0, offset = 0; i < 3; ++i, offset += N) { 45 | Reduce(h_tri_bbox0 + offset, N, min_op, &h_bbox0[i]); 46 | Reduce(h_tri_bbox1 + offset, N, max_op, &h_bbox1[i]); 47 | } 48 | return ax::kOK; 49 | } 50 | 51 | void UpdateBound(const float f, const int c_idx, float *bbox0, float *bbox1) { 52 | if (f < bbox0[c_idx]) bbox0[c_idx] = f; 53 | if (f > bbox1[c_idx]) bbox1[c_idx] = f; 54 | } 55 | 56 | void UpdateBound(const float *vertex, const int tri_idx, const int N, 57 | float *bbox0, float *bbox1) { 58 | int c_idx = tri_idx; 59 | UpdateBound(vertex[0], c_idx, bbox0, bbox1); 60 | c_idx += N; 61 | UpdateBound(vertex[1], c_idx, bbox0, bbox1); 62 | c_idx += N; 63 | UpdateBound(vertex[2], c_idx, bbox0, bbox1); 64 | } 65 | 66 | int ComputeBoundSerial(const float *vertices, const int *triangles, 67 | const int N, const int begin, const int end, 68 | float *bbox0, float *bbox1); 69 | 70 | class ComputeBoundTask { 71 | public: 72 | ComputeBoundTask(const float *vertices, const int *triangles, const int N, 73 | const int begin, const int end, float *bbox0, float *bbox1) 74 | : vertices_(vertices), triangles_(triangles), N_(N), 75 | begin_(begin), end_(end), bbox0_(bbox0), bbox1_(bbox1) { } 76 | void operator()() { 77 | ComputeBoundSerial(vertices_, triangles_, N_, begin_, end_, bbox0_, bbox1_); 78 | } 79 | private: 80 | const int begin_, end_; 81 | const float *vertices_; 82 | const int *triangles_; 83 | const int N_; 84 | float *bbox0_; 85 | float *bbox1_; 86 | }; 87 | 88 | int ComputeBoundSerial(const float *vertices, const int *triangles, 89 | const int N, const int begin, const int end, 90 | float *bbox0, float *bbox1) { 91 | for (int tri_idx = begin; tri_idx < end; ++tri_idx) { 92 | for (int c = 0, c_idx = tri_idx; c < 3; ++c, c_idx += N) { 93 | bbox0[c_idx] = FLT_MAX; bbox1[c_idx] = -FLT_MAX; 94 | } 95 | for (int c = 0, vert_idx = tri_idx; c < 3; ++c, vert_idx += N) { 96 | UpdateBound(&vertices[3 * triangles[vert_idx]], tri_idx, N, 97 | bbox0, bbox1); 98 | } 99 | } 100 | return ax::kOK; 101 | } 102 | 103 | int ComputeBoundParallel(const float *vertices, const int *triangles, 104 | const int N, const int n_cores, 105 | float *bbox0, float *bbox1) { 106 | const int n_threads = n_cores; 107 | const int thread_size = N / n_threads; 108 | boost::thread_group tg; 109 | int begin = 0; 110 | for (int i = 0; i < n_threads - 1; ++i) { 111 | int end = begin + thread_size; 112 | tg.create_thread(ComputeBoundTask(vertices, triangles, N, begin, end, 113 | bbox0, bbox1)); 114 | begin = end; 115 | } 116 | tg.create_thread(ComputeBoundTask(vertices, triangles, N, begin, N, 117 | bbox0, bbox1)); 118 | tg.join_all(); 119 | return ax::kOK; 120 | } 121 | 122 | int ComputeBoundHost(const float *h_vertices, const int *h_triangles, const int N, 123 | float *h_tri_bbox0, float *h_tri_bbox1) { 124 | int n_cores = 4; 125 | if (n_cores > 1) { 126 | return ComputeBoundParallel(h_vertices, h_triangles, N, n_cores, 127 | h_tri_bbox0, h_tri_bbox1); 128 | } else { 129 | return ComputeBoundSerial(h_vertices, h_triangles, N, 0, N, 130 | h_tri_bbox0, h_tri_bbox1); 131 | } 132 | } 133 | 134 | } // voxel 135 | -------------------------------------------------------------------------------- /src/voxelizer_api.cu: -------------------------------------------------------------------------------- 1 | #include "voxel/voxelizer_api.h" 2 | //#include "axle/core/debug.h" 3 | 4 | namespace voxel { 5 | static const float epsilon = 0.00001; 6 | bool check_error(const float val1, const float val2) { 7 | return fabs(val1 - val2) > epsilon; 8 | } 9 | 10 | bool CheckVoxels(const DVectorInt &dvols, const HVectorInt &hvols) { 11 | const HVectorInt dvols2(dvols); 12 | const int vol_sz = hvols.size(); 13 | for (int i = 0; i < vol_sz; ++i) { 14 | if (hvols[i] != dvols2[i]) { 15 | //ax::Logger::Debug("voxelize error"); 16 | } 17 | } 18 | return true; 19 | } 20 | 21 | __global__ void KernelCopyResult(const int *input, int n, int *output) { 22 | int pidx = blockIdx.x * blockDim.x + threadIdx.x; 23 | if (pidx < n) output[pidx] = input[pidx]; 24 | } 25 | 26 | extern "C" void Voxelize(ax::TriMeshPtr mesh, int dim[3], tVoxels *voxels) { 27 | ax::SeqTimer::Begin("mesh convert..."); 28 | voxel::dVoxelizableMeshPtr dmesh = voxel::ConvertFromTriMesh(mesh); 29 | ax::SeqTimer::End(); 30 | ax::SeqTimer::Begin("cuda voxelization"); 31 | voxel::DeviceVoxels vols; 32 | dmesh->ComputeTriBBox(); 33 | dmesh->ComputeMeshBBox(); 34 | 35 | RET(vols.Initialize(HVectorFloat(dmesh->bbox0()), 36 | HVectorFloat(dmesh->bbox1()), dim)); 37 | voxel::Voxelize(thrust::raw_pointer_cast(&dmesh->vertices().front()), 38 | thrust::raw_pointer_cast(&dmesh->triangles().front()), 39 | dmesh->n_triangles(), 40 | thrust::raw_pointer_cast(&dmesh->tri_bbox0().front()), 41 | thrust::raw_pointer_cast(&dmesh->tri_bbox1().front()), 42 | vols); 43 | ax::SeqTimer::End(); 44 | 45 | cudaMemcpyKind copyKind = (voxels->target == kDevice ? 46 | cudaMemcpyDeviceToDevice : cudaMemcpyDeviceToHost); 47 | 48 | ax::SeqTimer::Begin("read back voxels..."); 49 | cudaMemcpy(voxels->data, vols.vols_ptr(), vols.vols().size() * sizeof(int), 50 | copyKind); 51 | cudaMemcpy(voxels->bbox0, vols.bbox0_ptr(), 3 * sizeof(float), copyKind); 52 | cudaMemcpy(voxels->delta, vols.delta_ptr(), 3 * sizeof(float), copyKind); 53 | for (int i = 0; i < 3; ++i) { 54 | voxels->dim[i] = vols.dim(i); 55 | voxels->bbox1[i] = voxels->bbox0[i] + voxels->dim[i] * voxels->delta[i]; 56 | } 57 | ax::SeqTimer::End(); 58 | } 59 | } // voxel 60 | -------------------------------------------------------------------------------- /src/voxelizer_device.cu: -------------------------------------------------------------------------------- 1 | #include "voxel/voxelizer_device.h" 2 | #include "voxelizer_imp.cuh" 3 | 4 | #ifdef VOXELIZER_DEVICE 5 | #include 6 | 7 | namespace voxel { 8 | int Voxelize(const float *d_vertices, const int *d_triangles, const int N, 9 | const float *d_tri_bbox0, const float *d_tri_bbox1, 10 | DeviceVoxels &vols) { 11 | // (x, y, z) --> (x + y * n) * (n / 32) + z / 32, and z % 32 index in the byte 12 | const int block_size = 128; 13 | int block_num = (N + block_size - 1) / block_size; 14 | thrust::device_vector ttt(N); 15 | 16 | device::voxelize_kernel<<>>( 17 | d_vertices, d_triangles, N, d_tri_bbox0, d_tri_bbox1, vols.bbox0_ptr(), 18 | vols.delta_ptr(), vols.inv_delta_ptr(), vols.stride_ptr(), vols.vols_ptr() 19 | #ifdef STASTICS_DEVICE 20 | ,thrust::raw_pointer_cast(&ttt.front()) 21 | #endif 22 | ); 23 | 24 | cudaError_t cudaStatus; 25 | /* cudaStatus = cudaDeviceSynchronize(); 26 | if (cudaSuccess != cudaStatus ) { 27 | ax::Logger::Debug("voxelize kernel failed!\n"); 28 | return kFailed; 29 | }*/ 30 | 31 | /*thrust::device_vector start(N), end(N); 32 | device::test_kernel<<>>( 33 | d_tri_bbox0, d_tri_bbox1, vols.inv_delta_ptr(), vols.bbox0_ptr(), N, 34 | thrust::raw_pointer_cast(&start.front()), 35 | thrust::raw_pointer_cast(&end.front())); 36 | cutilCheckMsg("test_kernel()"); 37 | 38 | cudaStatus = cudaDeviceSynchronize(); 39 | if (cudaSuccess != cudaStatus ) { 40 | ax::Logger::Debug("test kernel failed!\n"); 41 | return kFailed; 42 | }*/ 43 | 44 | //float startxxx = start[2077]; 45 | //float endxxx = end[2077]; 46 | //printf("startxxx: %.12f\n", startxxx); 47 | //printf("endxxx: %.12f\n", endxxx); 48 | //printf("xxxxxx: %.12f\n", startxxx - endxxx); 49 | 50 | //thrust::device_vector s(128, startxxx); 51 | //thrust::device_vector e(128, endxxx); 52 | //thrust::device_vector res(128); 53 | //device::test2_kernel<<<1, 128>>>( 54 | // thrust::raw_pointer_cast(&s.front()), 55 | // thrust::raw_pointer_cast(&e.front()), 56 | // thrust::raw_pointer_cast(&res.front())); 57 | //cutilCheckMsg("test_kernel()"); 58 | 59 | //cudaStatus = cudaDeviceSynchronize(); 60 | //if (cudaSuccess != cudaStatus ) { 61 | // ax::Logger::Debug("test kernel failed!\n"); 62 | // return kFailed; 63 | //} 64 | //float ss = s[0]; 65 | //float ee = e[0]; 66 | //float r = res[0]; 67 | //printf("startxxx: %.12f\n", ss); 68 | //printf("endxxx: %.12f\n", ee); 69 | //printf("xxxxxx: %.12f\n", r); 70 | //const int n_stastics = 128; 71 | //int count[n_stastics]; 72 | //memset(count, 0, sizeof(int) * n_stastics); 73 | // 74 | //thrust::host_vector h_ttt(ttt); 75 | //for (int i = 0; i < N; ++i) { 76 | // int t = h_ttt[i]; 77 | // ++count[t]; 78 | //} 79 | //ax::Logger::Debug("not preprocessed:", count[0]); 80 | //ax::Logger::Debug("preprocessed:", count[1]); 81 | //ax::Logger::Debug("processed:", count[2]); 82 | //ax::Logger::Debug("simply processed in X:", count[3]); 83 | //ax::Logger::Debug("simply processed:", count[4]); 84 | ////ax::Logger::Debug("normal error:", count[10000]); 85 | return ax::kOK; 86 | } 87 | } // voxel 88 | #endif // VOXELIZER_DEVICE -------------------------------------------------------------------------------- /src/voxelizer_host.cc: -------------------------------------------------------------------------------- 1 | #include "voxel/voxelizer_host.h" 2 | #include "voxelizer_imp.cuh" 3 | 4 | #ifdef VOXELIZER_HOST 5 | namespace voxel { 6 | int Voxelize(const float *vertices, const int *triangles, const int N, 7 | const float *tri_bbox0, const float *tri_bbox1, 8 | HostVoxels &vols) { 9 | // (x, y, z) --> (x + y * n) * (n / 32) + z / 32, and z % 32 index in the byte 10 | // check vols data 11 | /* float d0 = vols.delta()[0]; 12 | float d1 = vols.delta()[1]; 13 | float d2 = vols.delta()[2]; 14 | ax::Logger::Debug("inv_delta_", d0); 15 | ax::Logger::Debug("inv_delta_", d1); 16 | ax::Logger::Debug("inv_delta_", d2);*/ 17 | 18 | for (int i = 0; i < N; ++i) { 19 | host::voxelize_kernel(i, vertices, triangles, N, tri_bbox0, tri_bbox1, 20 | vols.bbox0_ptr(), vols.delta_ptr(), 21 | vols.inv_delta_ptr(), vols.stride_ptr(), 22 | vols.vols_ptr()); 23 | } 24 | 25 | /* float startxxx = tri_bbox1[2077] * vols.inv_delta_ptr()[0]; 26 | float endxxx = vols.bbox0_ptr()[0] * vols.inv_delta_ptr()[0]; 27 | printf("startxxx: %.12f\n", startxxx); 28 | printf("endxxx: %.12f\n", endxxx); 29 | printf("xxxxxx: %.12f\n", startxxx - endxxx);*/ 30 | 31 | 32 | return ax::kOK; 33 | } 34 | } // voxel 35 | #endif // VOXELIZER_HOST 36 | -------------------------------------------------------------------------------- /src/voxelizer_imp.cuh: -------------------------------------------------------------------------------- 1 | #if defined(SYS_IS_WINDOWS) 2 | #include 3 | #endif 4 | 5 | #if defined(VOXELIZER_DEVICE) 6 | #include 7 | #define _DEVICE_ __device__ 8 | #define _CONSTANT_ __constant__ 9 | #define _GLOBAL_ __global__ 10 | #define NAMESPACE device 11 | #elif defined(VOXELIZER_HOST) 12 | #define _DEVICE_ 13 | #define _CONSTANT_ 14 | #define _GLOBAL_ 15 | #define NAMESPACE host 16 | inline void atomicOr(int *ptr, int val) { 17 | *ptr |= val; 18 | } 19 | #endif 20 | 21 | 22 | #include "axle/core.h" 23 | 24 | namespace voxel { 25 | namespace NAMESPACE { 26 | 27 | _DEVICE_ float dot3(const float *a, const float *b) { 28 | return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; 29 | } 30 | 31 | _DEVICE_ float *cross(const float *a, const float *b, float *c) { 32 | c[0] = a[1] * b[2] - a[2] * b[1]; 33 | c[1] = a[2] * b[0] - a[0] * b[2]; 34 | c[2] = a[0] * b[1] - a[1] * b[0]; 35 | return c; 36 | } 37 | 38 | _DEVICE_ float dot3(const float *a, const float *b, 39 | const int i1, const int i2) { 40 | return a[i1] * b[i1] + a[i2] * b[i2]; 41 | } 42 | 43 | _DEVICE_ float *minus3(const float *a, const float *b, float *c) { 44 | c[0] = a[0] - b[0]; 45 | c[1] = a[1] - b[1]; 46 | c[2] = a[2] - b[2]; 47 | return c; 48 | } 49 | 50 | _DEVICE_ float *minus3(float *a, const float *b) { 51 | a[0] -= b[0]; 52 | a[1] -= b[1]; 53 | a[2] -= b[2]; 54 | return a; 55 | } 56 | 57 | _DEVICE_ void get_tri_vertices(const float *vertices, const int *triangles, 58 | const int N, 59 | int idx, const float *tri_vertices[3]) { 60 | tri_vertices[0] = &vertices[3 * triangles[idx]]; 61 | idx += N; 62 | tri_vertices[1] = &vertices[3 * triangles[idx]]; 63 | idx += N; 64 | tri_vertices[2] = &vertices[3 * triangles[idx]]; 65 | } 66 | 67 | _DEVICE_ void get_edges(const float *vertices[3], float edges[3][3]) { 68 | minus3(vertices[1], vertices[0], edges[0]); 69 | minus3(vertices[2], vertices[1], edges[1]); 70 | minus3(vertices[0], vertices[2], edges[2]); 71 | } 72 | 73 | // only one component 74 | 75 | _DEVICE_ void compute_plane_d(const float *v, const float *delta, 76 | const int x, const int y, const int z, 77 | float n_d_xy[3]) { 78 | n_d_xy[z] = -dot3(n_d_xy, v, x, y); 79 | 80 | float tmp = delta[x] * n_d_xy[x]; 81 | if (tmp > 0) n_d_xy[z] += tmp; 82 | tmp = delta[y] * n_d_xy[y]; 83 | if (tmp > 0) n_d_xy[z] += tmp; 84 | } 85 | 86 | _DEVICE_ void compute_plane_n_d_1(const float *v, const float *e, 87 | const int x, const int y, const int z, 88 | const float *delta, float n_d_xy[3]) { 89 | n_d_xy[x] = -e[y]; 90 | n_d_xy[y] = e[x]; 91 | compute_plane_d(v, delta, x, y, z, n_d_xy); 92 | } 93 | _DEVICE_ void compute_plane_n_d_0(const float *v, const float *e, 94 | const int x, const int y, const int z, 95 | const float *delta, float n_d_xy[3]) { 96 | n_d_xy[x] = e[y]; 97 | n_d_xy[y] = -e[x]; 98 | compute_plane_d(v, delta, x, y, z, n_d_xy); 99 | } 100 | 101 | _DEVICE_ void compute_plane_n_d(const float *v[3], const float e[3][3], 102 | const int x, const int y, const int z, 103 | const float *n, const float *delta, 104 | float n_d_xy[3][3]) { 105 | if (n[z] < 0) { 106 | compute_plane_n_d_0(v[0], e[0], x, y, z, delta, n_d_xy[0]); 107 | compute_plane_n_d_0(v[1], e[1], x, y, z, delta, n_d_xy[1]); 108 | compute_plane_n_d_0(v[2], e[2], x, y, z, delta, n_d_xy[2]); 109 | } else { 110 | compute_plane_n_d_1(v[0], e[0], x, y, z, delta, n_d_xy[0]); 111 | compute_plane_n_d_1(v[1], e[1], x, y, z, delta, n_d_xy[1]); 112 | compute_plane_n_d_1(v[2], e[2], x, y, z, delta, n_d_xy[2]); 113 | } 114 | } 115 | 116 | _CONSTANT_ int modulo[] = { 1, 2, 0 }; 117 | 118 | _DEVICE_ int *VolPtr(int *vols, const int start[3], const int vol_stride[3], int int_begin) { 119 | return vols + int_begin*vol_stride[Z] + start[Y]*vol_stride[Y] + 120 | start[X] * vol_stride[X]; 121 | } 122 | 123 | _DEVICE_ bool preprocess(const int start[3], const int end[3], 124 | const int int_begin, const int int_end, 125 | const int bit_begin, const int bit_end, 126 | const int vol_stride[3], int *vols, int *axis) { 127 | // in an int, 0 index the least sinificant bit 128 | int flag = 0; 129 | if (start[X] == end[X]) { 130 | ++flag; 131 | *axis = X; 132 | } 133 | 134 | if (start[Y] == end[Y]) { 135 | if (flag > 0) { 136 | // set all along axis Z, and return; 137 | int *vol_ptr_z = VolPtr(vols, start, vol_stride, int_begin); 138 | if (int_begin == int_end) { 139 | // set range [bit_begin, bit_end] 140 | if (bit_end == 31) { 141 | int bits = -1 << bit_begin; 142 | atomicOr(vol_ptr_z, bits); 143 | } else { 144 | int bits = (1 << (bit_end+1)) - (1 << bit_begin); 145 | atomicOr(vol_ptr_z, bits); 146 | } 147 | } else { 148 | //set range [bit_begin, 31], and range[0, bit_end] 149 | int bits = -1 << bit_begin; 150 | atomicOr(vol_ptr_z, bits); 151 | for (int i = int_begin + 1; i < int_end; ++i) { 152 | // set the ints in range (ptr_begin, ptr_end) 153 | bits = 0xffffffff; 154 | vol_ptr_z += vol_stride[Z]; 155 | atomicOr(vol_ptr_z, bits); 156 | } 157 | if (bit_end == 31) { 158 | bits = 0xffffffff; 159 | } else { 160 | bits = (1 << (bit_end + 1)) - 1; 161 | } 162 | vol_ptr_z += vol_stride[Z]; 163 | atomicOr(vol_ptr_z, bits); 164 | } 165 | return true; 166 | } 167 | ++flag; 168 | *axis = Y; 169 | } 170 | 171 | if (start[Z] == end[Z]) { 172 | if (flag > 0) { 173 | // set all, along axis (1-axis), and return; 174 | int bits = 1 << bit_begin; 175 | 176 | int *vol = VolPtr(vols, start, vol_stride, int_begin); 177 | int other_axis = 1 - *axis; 178 | for (int i = start[other_axis]; i <= end[other_axis]; ++i) { 179 | // add the bit to *vol; 180 | atomicOr(vol, bits); 181 | vol += vol_stride[other_axis]; 182 | } 183 | return true; 184 | } 185 | ++flag; 186 | *axis = Z; 187 | } 188 | return false; 189 | } 190 | 191 | _DEVICE_ bool projection_test(const float p[3], const int x, const int y, 192 | const int z, const float n_d_ii[3][3]) { 193 | if ((dot3(n_d_ii[0], p, x, y) + n_d_ii[0][z]) < 0) return false; 194 | if ((dot3(n_d_ii[1], p, x, y) + n_d_ii[1][z]) < 0) return false; 195 | if ((dot3(n_d_ii[2], p, x, y) + n_d_ii[2][z]) < 0) return false; 196 | return true; 197 | } 198 | 199 | // [begin, end) 200 | _DEVICE_ int process_range(const int begin, const int end, const float n[3], 201 | float p[3], const float d1, const float d2, 202 | const float delta_z, 203 | const float n_d_xy[][3], 204 | const float n_d_yz[][3], 205 | const float n_d_zx[][3]) { 206 | int bits = 0; 207 | for (int z = begin; z < end; ++z, p[Z] += delta_z) { 208 | // evaluate Eq. 1 209 | float n_dot_p = dot3(n, p); 210 | if ((n_dot_p + d1) * (n_dot_p + d2) > 0) continue; 211 | 212 | if (projection_test(p, Y, Z, X, n_d_yz) && 213 | projection_test(p, Z, X, Y, n_d_zx)) { 214 | // set the bit to val 215 | int bit = 1 << z; 216 | bits |= bit; 217 | } 218 | } 219 | return bits; 220 | } 221 | 222 | _DEVICE_ int process_range(const int begin, const int end, float p[3], 223 | const int x, const int y, const int z, 224 | const float delta_z, const float n_d_ii[3][3]) { 225 | int bits = 0; 226 | for (int i = begin; i < end; ++i, p[Z] += delta_z) { 227 | if (projection_test(p, x, y, z, n_d_ii)) { 228 | // set the bit to val 229 | bits |= 1 << i; 230 | } 231 | } 232 | return bits; 233 | } 234 | 235 | 236 | _DEVICE_ void process_simple(const float *v[3], const float e[3][3], 237 | const float n[3], const int axis, 238 | const float bbox0[3], const float delta[3], 239 | const int start[3], const int end[3], 240 | const int int_begin, const int int_end, 241 | const int bit_begin, const int bit_end, 242 | const int vol_stride[3], int *vols) { 243 | // only projection test against the plane formed by other two axises 244 | int axis1 = modulo[axis]; 245 | int axis2 = modulo[axis1]; 246 | float n_d_ii[3][3]; 247 | compute_plane_n_d(v, e, axis1, axis2, axis, n, delta, n_d_ii); 248 | 249 | // iterate over all voxels in the 2d range 250 | float p[3]; 251 | if (axis == Z) { 252 | // only one bit is to be set 253 | int bit = 1 << bit_begin; 254 | // p[X] = bbox0[X] + start[X] * delta[X]; 255 | p[Y] = bbox0[Y] + start[Y] * delta[Y]; 256 | int *vol_ptr_y = VolPtr(vols, start, vol_stride, int_begin); 257 | for (int y = start[Y]; y <= end[Y]; ++y) { 258 | p[X] = bbox0[X] + start[X] * delta[X]; 259 | int *vol_ptr_x = vol_ptr_y; 260 | for (int x = start[X]; x <= end[X]; ++x) { 261 | if (projection_test(p, X, Y, Z, n_d_ii)) { 262 | // set the bit 263 | atomicOr(vol_ptr_x, bit); 264 | } 265 | p[X] += delta[X]; 266 | vol_ptr_x += vol_stride[X]; 267 | } 268 | p[Y] += delta[Y]; 269 | vol_ptr_y += vol_stride[Y]; 270 | } 271 | } else { 272 | //axis_i == X or Y 273 | // process in Z-X or Y-Z plane 274 | int axis_i = 1 - axis; 275 | p[axis] = bbox0[axis] + start[axis] * delta[axis]; 276 | p[axis_i] = bbox0[axis_i] + start[axis_i] * delta[axis_i]; 277 | int *vol_ptr = VolPtr(vols, start, vol_stride, int_begin); 278 | float p_start_z = bbox0[Z] + start[Z] * delta[Z]; 279 | if (int_begin == int_end) { 280 | for (int i = start[axis_i]; i <= end[axis_i]; ++i) { 281 | p[Z] = p_start_z; 282 | int bits = process_range(bit_begin, bit_end + 1, p, axis1, axis2, 283 | axis, delta[Z], n_d_ii); 284 | atomicOr(vol_ptr, bits); 285 | 286 | p[axis_i] += delta[axis_i]; 287 | vol_ptr += vol_stride[axis_i]; 288 | } 289 | } else { 290 | for (int i = start[axis_i]; i <= end[axis_i]; ++i) { 291 | p[Z] = p_start_z; 292 | int *vol_ptr_z = vol_ptr; 293 | int bits = process_range(bit_begin, 32, p, axis1, axis2, axis, 294 | delta[Z], n_d_ii); 295 | atomicOr(vol_ptr_z, bits); 296 | for (int i = int_begin + 1; i < int_end; ++i) { 297 | bits = process_range(0, 32, p, axis1, axis2, axis, delta[Z], n_d_ii); 298 | vol_ptr_z += vol_stride[Z]; 299 | atomicOr(vol_ptr_z, bits); 300 | } 301 | bits = process_range(0, bit_end + 1, p, axis1, axis2, axis, 302 | delta[Z], n_d_ii); 303 | vol_ptr_z += vol_stride[Z]; 304 | atomicOr(vol_ptr_z, bits); 305 | 306 | p[axis_i] += delta[axis_i]; 307 | vol_ptr += vol_stride[axis_i]; 308 | } 309 | } 310 | } 311 | } 312 | 313 | // iterate over all voxels in the 3d range 314 | // for each 315 | // evaluate Eq. 1 316 | // continue if > 0 317 | // evaluate Eq. 3 318 | // atomic OR if true 319 | 320 | _DEVICE_ void compute_d1_d2(const float n[3], const float v0[3], 321 | const float delta[3], float *d1, float *d2) { 322 | float c[3] = { 0.0, 0.0, 0.0 }; 323 | if (n[X] > 0) c[X] = delta[X]; 324 | if (n[Y] > 0) c[Y] = delta[Y]; 325 | if (n[Z] > 0) c[Z] = delta[Z]; 326 | float tmp[3]; 327 | *d1 = dot3(n, minus3(c, v0, tmp)); 328 | minus3(delta, c, tmp); 329 | *d2 = dot3(n, minus3(tmp, v0)); 330 | } 331 | 332 | _DEVICE_ void process( 333 | const float *v[3], const float e[3][3], const float n[3], 334 | const float bbox0[3], const float delta[3], 335 | const int start[3], const int end[3], 336 | const int int_begin, const int int_end, 337 | const int bit_begin, const int bit_end, 338 | const int *vol_stride, int *vols) { 339 | // plane test, and all projection tests 340 | float d1, d2; 341 | compute_d1_d2(n, v[0], delta, &d1, &d2); 342 | 343 | float n_d_xy[3][3]; //first idx for edge, second (0, 1) for n, (2) for d 344 | float n_d_yz[3][3]; //first idx for edge, second (1, 2) for n, (0) for d 345 | float n_d_zx[3][3]; //first idx for edge, second (0, 2) for n, (1) for d 346 | 347 | compute_plane_n_d(v, e, X, Y, Z, n, delta, n_d_xy); 348 | compute_plane_n_d(v, e, Y, Z, X, n, delta, n_d_yz); 349 | compute_plane_n_d(v, e, Z, X, Y, n, delta, n_d_zx); 350 | 351 | float p[3], p_start[3]; 352 | p_start[X] = bbox0[X] + start[X] * delta[X]; 353 | p_start[Y] = bbox0[Y] + start[Y] * delta[Y]; 354 | p_start[Z] = bbox0[Z] + start[Z] * delta[Z]; 355 | p[Y] = p_start[Y]; 356 | int *vol_ptr_y = VolPtr(vols, start, vol_stride, int_begin); 357 | if (int_begin == int_end) { 358 | for (int y = start[Y]; y <= end[Y]; ++y) { 359 | p[X] = p_start[X]; 360 | int *vol_ptr_x = vol_ptr_y; 361 | 362 | for (int x = start[X]; x <= end[X]; ++x) { 363 | if (projection_test(p, X, Y, Z, n_d_xy)) { 364 | p[Z] = p_start[Z]; 365 | int *vol_ptr_z = vol_ptr_x; 366 | int bits = process_range(bit_begin, bit_end + 1, n, p, d1, d2, 367 | delta[Z], n_d_xy, n_d_yz, n_d_zx); 368 | atomicOr(vol_ptr_z, bits); 369 | } 370 | p[X] += delta[X]; 371 | vol_ptr_x += vol_stride[X]; 372 | } 373 | p[Y] += delta[Y]; 374 | vol_ptr_y += vol_stride[Y]; 375 | } 376 | } else { 377 | for (int y = start[Y]; y <= end[Y]; ++y) { 378 | p[X] = p_start[X]; 379 | int *vol_ptr_x = vol_ptr_y; 380 | 381 | for (int x = start[X]; x <= end[X]; ++x) { 382 | if (projection_test(p, X, Y, Z, n_d_xy)) { 383 | p[Z] = p_start[Z]; 384 | int *vol_ptr_z = vol_ptr_x; 385 | 386 | int bits = process_range(bit_begin, 32, n, p, d1, d2, delta[Z], 387 | n_d_xy, n_d_yz, n_d_zx); 388 | atomicOr(vol_ptr_z, bits); 389 | for (int i = int_begin + 1; i < int_end; ++i) { 390 | bits = process_range(0, 32, n, p, d1, d2, delta[Z], 391 | n_d_xy, n_d_yz, n_d_zx); 392 | vol_ptr_z += vol_stride[Z]; 393 | atomicOr(vol_ptr_z, bits); 394 | } 395 | bits = process_range(0, bit_end + 1, n, p, d1, d2, delta[Z], 396 | n_d_xy, n_d_yz, n_d_zx); 397 | vol_ptr_z += vol_stride[Z]; 398 | atomicOr(vol_ptr_z, bits); 399 | } 400 | p[X] += delta[X]; 401 | vol_ptr_x += vol_stride[X]; 402 | } 403 | p[Y] += delta[Y]; 404 | vol_ptr_y += vol_stride[Y]; 405 | } 406 | } 407 | } 408 | 409 | _DEVICE_ void get_start_end(const float *tri_bbox0, const float *tri_bbox1, 410 | const int tri_idx, const int N, 411 | const float *inv_delta, const float *bbox0, 412 | int start[3], int end[32]) { 413 | int c_idx = tri_idx; 414 | start[0] = (tri_bbox0[c_idx] - bbox0[0]) * inv_delta[0]; 415 | end[0] = (tri_bbox1[c_idx] - bbox0[0]) * inv_delta[0]; 416 | c_idx += N; 417 | start[1] = (tri_bbox0[c_idx] - bbox0[1]) * inv_delta[1]; 418 | end[1] = (tri_bbox1[c_idx] - bbox0[1]) * inv_delta[1]; 419 | c_idx += N; 420 | start[2] = (tri_bbox0[c_idx] - bbox0[2]) * inv_delta[2]; 421 | end[2] = (tri_bbox1[c_idx] - bbox0[2]) * inv_delta[2]; 422 | } 423 | 424 | #if defined(VOXELIZER_HOST) 425 | _GLOBAL_ void voxelize_kernel( 426 | const int tri_idx, 427 | const float *vertices, const int *triangles, const int N, 428 | const float *tri_bbox0, const float *tri_bbox1, 429 | const float *bbox0, const float *delta, const float *inv_delta, 430 | const int *vol_stride, int *vols) { 431 | #endif 432 | 433 | #if defined(VOXELIZER_DEVICE) 434 | #ifdef STASTICS_DEVICE 435 | _GLOBAL_ void voxelize_kernel( 436 | const float *vertices, const int *triangles, const int N, 437 | const float *tri_bbox0, const float *tri_bbox1, 438 | const float *bbox0, const float *delta, const float *inv_delta, 439 | const int *vol_stride, int *vols, int *statsics) { 440 | #else 441 | _GLOBAL_ void voxelize_kernel( 442 | const float *vertices, const int *triangles, const int N, 443 | const float *tri_bbox0, const float *tri_bbox1, 444 | const float *bbox0, const float *delta, const float *inv_delta, 445 | const int *vol_stride, int *vols) { 446 | #endif 447 | const int tri_idx = blockIdx.x * blockDim.x + threadIdx.x; 448 | if (tri_idx >= N) return; 449 | #endif 450 | 451 | int start[3], end[3]; 452 | //range [start, end] 453 | get_start_end(tri_bbox0, tri_bbox1, tri_idx, N, inv_delta, bbox0, start, end); 454 | 455 | int int_begin = start[Z] >> 5; 456 | int bit_begin = start[Z] & 31; 457 | int int_end = end[Z] >> 5; 458 | int bit_end = end[Z] & 31; 459 | 460 | #ifdef STASTICS_DEVICE 461 | stastics[tri_idx] = 1; 462 | #endif 463 | int axis = -1; 464 | if (preprocess(start, end, int_begin, int_end, bit_begin, bit_end, 465 | vol_stride, vols, &axis)) return; 466 | #ifdef STASTICS_DEVICE 467 | if (axis < 0) { 468 | stastics[tri_idx] = 2; 469 | } else { 470 | if (X == axis) { 471 | stastics[tri_idx] = 3; 472 | } else { 473 | stastics[tri_idx] = 4; 474 | } 475 | } 476 | #endif 477 | 478 | const float *v[3]; 479 | get_tri_vertices(vertices, triangles, N, tri_idx, v); 480 | 481 | float e[3][3]; 482 | get_edges(v, e); 483 | 484 | float n[3]; 485 | cross(e[0], e[1], n); 486 | 487 | if (axis < 0) { 488 | process(v, e, n, bbox0, delta, start, end, int_begin, int_end, 489 | bit_begin, bit_end, vol_stride, vols); 490 | } else { 491 | process_simple(v, e, n, axis, bbox0, delta, start, end, int_begin, 492 | int_end, bit_begin, bit_end, vol_stride, vols); 493 | } 494 | } 495 | 496 | #ifdef VOXELIZER_DEVICE 497 | _GLOBAL_ void test_kernel(const float *tri_bbox0, const float *tri_bbox1, 498 | const float *inv_delta, const float *bbox0, 499 | const int N, float *start, float *end) { 500 | const int tri_idx = blockIdx.x * blockDim.x + threadIdx.x; 501 | if (tri_idx >= N) return; 502 | 503 | int c_idx = tri_idx; 504 | start[c_idx] = tri_bbox1[c_idx] * inv_delta[0]; 505 | end[c_idx] = bbox0[0] * inv_delta[0]; 506 | } 507 | _GLOBAL_ void test2_kernel(const float *t1, const float *t0, float *o) { 508 | float tmp1 = t1[threadIdx.x]; 509 | float tmp2 = t0[threadIdx.x]; 510 | o[threadIdx.x] = tmp1 - tmp2; 511 | } 512 | #endif 513 | } // NAMESPACE 514 | } // voxel 515 | 516 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(VOXELIZER_TEST_SRC main.cu voxelizer_demo.cu voxelizer_test.cu) 2 | 3 | link_directories(${work_dir}/voxelizer/lib 4 | ${work_dir}/axle/lib) 5 | 6 | #LINK_LIBRARIES("-laxle ") 7 | set(CUDA_NVCC_FLAGS "-arch=sm_20") 8 | set(CMAKE_CXX_FLAGS "-DCHEETAH_DEBUG") 9 | if (WIN32) 10 | set(LIB_LIST glu32 glut32 glew32 devil) 11 | else () 12 | set(LIB_LIST GLU glut GLEW IL ILU boost_thread) 13 | endif (WIN32) 14 | 15 | set(target_name "test") 16 | 17 | CUDA_ADD_EXECUTABLE(${target_name} ${VOXELIZER_TEST_SRC}) 18 | 19 | set(output "${target_name}/${target_name}") 20 | set(debug_output "${output}_d") 21 | 22 | set_target_properties(${target_name} PROPERTIES OUTPUT_NAME_DEBUG ${debug_output}) 23 | set_target_properties(${target_name} PROPERTIES OUTPUT_NAME_RELEASE ${output}) 24 | 25 | set(libs optimized axle optimized voxelizer debug axle_d debug voxelizer_d ${LIB_LIST}) 26 | target_link_libraries(${target_name} ${libs}) 27 | 28 | -------------------------------------------------------------------------------- /test/glm/.svn/all-wcprops: -------------------------------------------------------------------------------- 1 | K 25 2 | svn:wc:ra_dav:version-url 3 | V 35 4 | /svn/!svn/ver/2/trunk/voxelizer/glm 5 | END 6 | glm.cpp 7 | K 25 8 | svn:wc:ra_dav:version-url 9 | V 43 10 | /svn/!svn/ver/2/trunk/voxelizer/glm/glm.cpp 11 | END 12 | glm.h 13 | K 25 14 | svn:wc:ra_dav:version-url 15 | V 41 16 | /svn/!svn/ver/2/trunk/voxelizer/glm/glm.h 17 | END 18 | -------------------------------------------------------------------------------- /test/glm/.svn/dir-prop-base: -------------------------------------------------------------------------------- 1 | K 14 2 | bugtraq:number 3 | V 4 4 | true 5 | END 6 | -------------------------------------------------------------------------------- /test/glm/.svn/entries: -------------------------------------------------------------------------------- 1 | 10 2 | 3 | dir 4 | 9 5 | https://voxelizer.googlecode.com/svn/trunk/voxelizer/glm 6 | https://voxelizer.googlecode.com/svn 7 | 8 | 9 | 10 | 2011-12-02T10:04:55.454268Z 11 | 2 12 | hpsoar 13 | has-props 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 54e54b2d-6611-56a0-dff2-ca0261f7a1c9 28 | 29 | glm.cpp 30 | file 31 | 32 | 33 | 34 | 35 | 2011-10-19T05:14:35.867113Z 36 | 2a462ba2625cb52b773c703246c0003e 37 | 2011-12-02T10:04:55.454268Z 38 | 2 39 | hpsoar 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 67367 62 | 63 | glm.h 64 | file 65 | 66 | 67 | 68 | 69 | 2011-10-19T05:14:35.868113Z 70 | aaff1ef5860be6f1db3b4e2abf832a09 71 | 2011-12-02T10:04:55.454268Z 72 | 2 73 | hpsoar 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 9272 96 | 97 | -------------------------------------------------------------------------------- /test/glm/.svn/text-base/glm.cpp.svn-base: -------------------------------------------------------------------------------- 1 | /* 2 | * GLM library. Wavefront .obj file format reader/writer/manipulator. 3 | * 4 | * Written by Nate Robins, 1997. 5 | * email: ndr@pobox.com 6 | * www: http://www.pobox.com/~ndr 7 | */ 8 | 9 | /* includes */ 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | //#include 17 | #include 18 | 19 | #include 20 | 21 | #define M_PI 3.141592653589793238462643383279502884197169399375105820974944592 22 | 23 | /* defines */ 24 | #define T(x) model->triangles[(x)] 25 | 26 | static const char* default_group_name = "No Group"; 27 | static const char* default_material_name = "No Material"; 28 | 29 | 30 | /* enums */ 31 | enum { X, Y, Z, W }; /* elements of a vertex */ 32 | 33 | 34 | /* typedefs */ 35 | 36 | /* _GLMnode: general purpose node 37 | */ 38 | typedef struct _GLMnode { 39 | unsigned int index; 40 | bool averaged; 41 | struct _GLMnode* next; 42 | } GLMnode; 43 | 44 | 45 | /* private functions */ 46 | 47 | /* _glmMax: returns the maximum of two floats */ 48 | 49 | static float 50 | _glmMax(float a, float b) 51 | { 52 | if (a > b) 53 | return a; 54 | return b; 55 | } 56 | 57 | /* _glmAbs: returns the absolute value of a float */ 58 | static float 59 | _glmAbs(float f) 60 | { 61 | if (f < 0) 62 | return -f; 63 | return f; 64 | } 65 | 66 | /* _glmDot: compute the dot product of two vectors 67 | * 68 | * u - array of 3 floats (float u[3]) 69 | * v - array of 3 floats (float v[3]) 70 | */ 71 | static float 72 | _glmDot(float* u, float* v) 73 | { 74 | assert(u); 75 | assert(v); 76 | 77 | /* compute the dot product */ 78 | return u[X] * v[X] + u[Y] * v[Y] + u[Z] * v[Z]; 79 | } 80 | 81 | /* _glmCross: compute the cross product of two vectors 82 | * 83 | * u - array of 3 floats (float u[3]) 84 | * v - array of 3 floats (float v[3]) 85 | * n - array of 3 floats (float n[3]) to return the cross product in 86 | */ 87 | static void 88 | _glmCross(float* u, float* v, float* n) 89 | { 90 | assert(u); 91 | assert(v); 92 | assert(n); 93 | 94 | /* compute the cross product (u x v for right-handed [ccw]) */ 95 | n[X] = u[Y] * v[Z] - u[Z] * v[Y]; 96 | n[Y] = u[Z] * v[X] - u[X] * v[Z]; 97 | n[Z] = u[X] * v[Y] - u[Y] * v[X]; 98 | } 99 | 100 | /* _glmNormalize: normalize a vector 101 | * 102 | * n - array of 3 floats (float n[3]) to be normalized 103 | */ 104 | static void 105 | _glmNormalize(float* n) 106 | { 107 | float l; 108 | 109 | assert(n); 110 | 111 | /* normalize */ 112 | l = 1.0f/sqrtf(n[X] * n[X] + n[Y] * n[Y] + n[Z] * n[Z]); 113 | n[0] *= l; 114 | n[1] *= l; 115 | n[2] *= l; 116 | } 117 | 118 | /* _glmEqual: compares two vectors and returns true if they are 119 | * equal (within a certain threshold) or false if not. An epsilon 120 | * that works fairly well is 0.000001. 121 | * 122 | * u - array of 3 floats (float u[3]) 123 | * v - array of 3 floats (float v[3]) 124 | */ 125 | static bool 126 | _glmEqual(float* u, float* v, float epsilon) 127 | { 128 | if (_glmAbs(u[0] - v[0]) < epsilon && 129 | _glmAbs(u[1] - v[1]) < epsilon && 130 | _glmAbs(u[2] - v[2]) < epsilon) 131 | { 132 | return true; 133 | } 134 | return false; 135 | } 136 | 137 | /* _glmWeldVectors: eliminate (weld) vectors that are within an 138 | * epsilon of each other. 139 | * 140 | * vectors - array of float[3]'s to be welded 141 | * numvectors - number of float[3]'s in vectors 142 | * epsilon - maximum difference between vectors 143 | * 144 | */ 145 | static float* 146 | _glmWeldVectors(float* vectors, unsigned int* numvectors, float epsilon) 147 | { 148 | float* copies; 149 | unsigned int copied; 150 | unsigned int i, j; 151 | 152 | copies = (float*)malloc(sizeof(float) * 3 * (*numvectors + 1)); 153 | memcpy(copies, vectors, (sizeof(float) * 3 * (*numvectors + 1))); 154 | 155 | copied = 1; 156 | for (i = 1; i <= *numvectors; i++) { 157 | for (j = 1; j <= copied; j++) { 158 | if (_glmEqual(&vectors[3 * i], &copies[3 * j], epsilon)) { 159 | goto duplicate; 160 | } 161 | } 162 | 163 | /* must not be any duplicates -- add to the copies array */ 164 | copies[3 * copied + 0] = vectors[3 * i + 0]; 165 | copies[3 * copied + 1] = vectors[3 * i + 1]; 166 | copies[3 * copied + 2] = vectors[3 * i + 2]; 167 | j = copied; /* pass this along for below */ 168 | copied++; 169 | 170 | duplicate: 171 | /* set the first component of this vector to point at the correct 172 | index into the new copies array */ 173 | vectors[3 * i + 0] = (float)j; 174 | } 175 | 176 | *numvectors = copied-1; 177 | return copies; 178 | } 179 | 180 | /* _glmFindGroup: Find a group in the model 181 | */ 182 | static GLMgroup* 183 | _glmFindGroup(GLMmodel* model, char* name) 184 | { 185 | GLMgroup* group; 186 | 187 | assert(model); 188 | 189 | group = model->groups; 190 | while(group) { 191 | if (!strcmp(name, group->name)) 192 | break; 193 | group = group->next; 194 | } 195 | 196 | return group; 197 | } 198 | 199 | /* _glmAddGroup: Add a group to the model 200 | */ 201 | static GLMgroup* 202 | _glmAddGroup(GLMmodel* model, char* name) 203 | { 204 | GLMgroup* group; 205 | 206 | group = _glmFindGroup(model, name); 207 | if (!group) { 208 | group = (GLMgroup*)malloc(sizeof(GLMgroup)); 209 | group->name = strdup(name); 210 | group->material = 0; 211 | group->mtlname = 0; 212 | group->numtriangles = 0; 213 | group->triangles = NULL; 214 | group->next = model->groups; 215 | model->groups = group; 216 | model->numgroups++; 217 | } 218 | 219 | 220 | return group; 221 | } 222 | 223 | /* _glmFindGroup: Find a material in the model 224 | */ 225 | static unsigned int 226 | _glmFindMaterial(GLMmodel* model, char* name) 227 | { 228 | unsigned int i; 229 | 230 | for (i = 0; i < model->nummaterials; i++) { 231 | if (model->materials[i].name && !strcmp(model->materials[i].name, name)) 232 | goto found; 233 | } 234 | 235 | /* didn't find the name, so set it as the default material */ 236 | /* printf("_glmFindMaterial(): can't find material \"%s\".\n", name); */ 237 | i = 0; 238 | 239 | found: 240 | return i; 241 | } 242 | 243 | 244 | /* _glmDirName: return the directory given a path 245 | * 246 | * path - filesystem path 247 | * 248 | * The return value should be free'd. 249 | */ 250 | static char* 251 | _glmDirName(char* path) 252 | { 253 | char* dir; 254 | char* s; 255 | 256 | dir = strdup(path); 257 | 258 | s = strrchr(dir, '/'); 259 | if (s) 260 | s[1] = '\0'; 261 | else 262 | dir[0] = '\0'; 263 | 264 | return dir; 265 | } 266 | 267 | 268 | /* _glmReadMTL: read a wavefront material library file 269 | * 270 | * model - properly initialized GLMmodel structure 271 | * name - name of the material library 272 | */ 273 | static int 274 | _glmReadMTL(GLMmodel* model, char* name) 275 | { 276 | FILE* file; 277 | char* dir; 278 | char* filename; 279 | char buf[2048]; 280 | unsigned int nummaterials, i; 281 | 282 | dir = _glmDirName(model->pathname); 283 | filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(name) + 1)); 284 | strcpy(filename, dir); 285 | strcat(filename, name); 286 | free(dir); 287 | 288 | /* open the file */ 289 | file = fopen(filename, "r"); 290 | if (!file) { 291 | fprintf(stderr, "_glmReadMTL() failed: can't open material file \"%s\".\n", 292 | filename); 293 | free(filename); 294 | return 1; 295 | } 296 | free(filename); 297 | 298 | /* count the number of materials in the file */ 299 | nummaterials = 1; 300 | while(fscanf(file, "%s", buf) != EOF) { 301 | switch(buf[0]) { 302 | case '#': /* comment */ 303 | /* eat up rest of line */ 304 | fgets(buf, sizeof(buf), file); 305 | break; 306 | case 'n': /* newmtl */ 307 | fgets(buf, sizeof(buf), file); 308 | nummaterials++; 309 | sscanf(buf, "%s %s", buf, buf); 310 | break; 311 | default: 312 | /* eat up rest of line */ 313 | fgets(buf, sizeof(buf), file); 314 | break; 315 | } 316 | } 317 | 318 | rewind(file); 319 | 320 | /* allocate memory for the materials */ 321 | model->materials = (GLMmaterial*)malloc(sizeof(GLMmaterial) * nummaterials); 322 | model->nummaterials = nummaterials; 323 | 324 | /* set the default material */ 325 | for (i = 0; i < nummaterials; i++) { 326 | model->materials[i].name = NULL; 327 | model->materials[i].shininess = 0; 328 | model->materials[i].refraction = 1; 329 | model->materials[i].alpha = 1; 330 | model->materials[i].shader = GLM_FLAT_SHADE; 331 | model->materials[i].reflectivity = 0; 332 | 333 | model->materials[i].diffuse[0] = 0.7f; 334 | model->materials[i].diffuse[1] = 0.7f; 335 | model->materials[i].diffuse[2] = 0.7f; 336 | model->materials[i].diffuse[3] = 1.0f; 337 | model->materials[i].ambient[0] = 0.2f; 338 | model->materials[i].ambient[1] = 0.2f; 339 | model->materials[i].ambient[2] = 0.2f; 340 | model->materials[i].ambient[3] = 1.0f; 341 | model->materials[i].specular[0] = 0.0f; 342 | model->materials[i].specular[1] = 0.0f; 343 | model->materials[i].specular[2] = 0.0f; 344 | model->materials[i].specular[3] = 1.0f; 345 | model->materials[i].emmissive[0] = 0.0f; 346 | model->materials[i].emmissive[1] = 0.0f; 347 | model->materials[i].emmissive[2] = 0.0f; 348 | model->materials[i].emmissive[3] = 1.0f; 349 | 350 | model->materials[i].ambient_map[0] = '\0'; 351 | model->materials[i].diffuse_map[0] = '\0'; 352 | model->materials[i].specular_map[0] = '\0'; 353 | model->materials[i].dissolve_map[0] = '\0'; 354 | 355 | model->materials[i].ambient_map_scaling[0] = 0; 356 | model->materials[i].ambient_map_scaling[1] = 0; 357 | model->materials[i].diffuse_map_scaling[0] = 0; 358 | model->materials[i].diffuse_map_scaling[1] = 0; 359 | model->materials[i].specular_map_scaling[0] = 0; 360 | model->materials[i].specular_map_scaling[1] = 0; 361 | model->materials[i].dissolve_map_scaling[0] = 0; 362 | model->materials[i].dissolve_map_scaling[1] = 0; 363 | } 364 | model->materials[0].name = strdup("NO_ASSIGNED_MATERIAL"); 365 | 366 | /* now, read in the data */ 367 | nummaterials = 0; 368 | while(fscanf(file, "%s", buf) != EOF) { 369 | switch(buf[0]) { 370 | case '#': /* comment */ 371 | /* eat up rest of line */ 372 | fgets(buf, sizeof(buf), file); 373 | break; 374 | case 'n': /* newmtl */ 375 | 376 | // Make sure the previous material has a name. 377 | assert( model->materials[nummaterials].name ); 378 | 379 | // Read in the new material name. 380 | fgets(buf, sizeof(buf), file); 381 | sscanf(buf, "%s %s", buf, buf); 382 | nummaterials++; 383 | model->materials[nummaterials].name = strdup(buf); 384 | break; 385 | case 'N': 386 | fscanf(file, "%f", &model->materials[nummaterials].shininess); 387 | break; 388 | case 'T': // Tr 389 | fscanf(file, "%f", &model->materials[nummaterials].refraction); 390 | break; 391 | case 'd': // d 392 | fscanf(file, "%f", &model->materials[nummaterials].alpha); 393 | break; 394 | case 'i': // illum 395 | fscanf(file, "%d", &model->materials[nummaterials].shader); 396 | break; 397 | case 'r': // reflectivity 398 | fscanf(file, "%f", &model->materials[nummaterials].reflectivity); 399 | break; 400 | case 'R': // reflectivity 401 | float r[3]; 402 | fscanf(file, "%f %f %f", r, r+1, r+2); 403 | model->materials[nummaterials].reflectivity = (r[0]+r[1]+r[2]) / 3.0f; 404 | break; 405 | case 'm': 406 | { 407 | char* map_name = 0; 408 | float* scaling = 0; 409 | // Determine which type of map. 410 | if (strcmp(buf,"map_Ka")==0) { 411 | map_name = model->materials[nummaterials].ambient_map; 412 | scaling = model->materials[nummaterials].ambient_map_scaling; 413 | } else if (strcmp(buf,"map_Kd")==0) { 414 | map_name = model->materials[nummaterials].diffuse_map; 415 | scaling = model->materials[nummaterials].diffuse_map_scaling; 416 | } else if (strcmp(buf,"map_Ks")==0) { 417 | map_name = model->materials[nummaterials].specular_map; 418 | scaling = model->materials[nummaterials].ambient_map_scaling; 419 | } else if (strcmp(buf,"map_D")==0) { 420 | map_name = model->materials[nummaterials].dissolve_map; 421 | scaling = model->materials[nummaterials].dissolve_map_scaling; 422 | } else { 423 | // We don't know what kind of map it is, so ignore it 424 | fprintf(stderr, "Unknown map: \"%s\" found at %s(%d)\n", buf, 425 | __FILE__, __LINE__); 426 | break; 427 | } 428 | 429 | char string_litteral[2048]; 430 | sprintf(string_litteral, "%%%ds", (int)MaxStringLength-1); 431 | //fprintf(stderr, "string_litteral = %s\n", string_litteral); 432 | 433 | // Check to see if we have scaled textures or not 434 | fscanf(file, string_litteral, map_name); 435 | if (strcmp(map_name, "-s") == 0) { 436 | // pick up the float scaled textures 437 | fscanf(file, "%f %f", &scaling[0], &scaling[1]); 438 | // Now the name of the file 439 | fscanf(file, string_litteral, map_name); 440 | //fprintf(stderr, " scale = %f %f ,", scaling[0], scaling[1]); 441 | } 442 | //fprintf(stderr, "name = %s\n", map_name); 443 | } // end case 'm' 444 | break; 445 | 446 | case 'K': 447 | switch(buf[1]) { 448 | case 'd': 449 | fscanf(file, "%f %f %f", 450 | &model->materials[nummaterials].diffuse[0], 451 | &model->materials[nummaterials].diffuse[1], 452 | &model->materials[nummaterials].diffuse[2]); 453 | break; 454 | case 's': 455 | fscanf(file, "%f %f %f", 456 | &model->materials[nummaterials].specular[0], 457 | &model->materials[nummaterials].specular[1], 458 | &model->materials[nummaterials].specular[2]); 459 | break; 460 | case 'a': 461 | fscanf(file, "%f %f %f", 462 | &model->materials[nummaterials].ambient[0], 463 | &model->materials[nummaterials].ambient[1], 464 | &model->materials[nummaterials].ambient[2]); 465 | break; 466 | default: 467 | /* eat up rest of line */ 468 | fgets(buf, sizeof(buf), file); 469 | break; 470 | } 471 | break; 472 | default: 473 | /* eat up rest of line */ 474 | fgets(buf, sizeof(buf), file); 475 | break; 476 | } 477 | } 478 | 479 | // Make sure we found the same number of materials the second time around. 480 | // Note that glm adds a default material to the beginning of the array 481 | assert((nummaterials+1) == model->nummaterials); 482 | 483 | fclose( file ); 484 | 485 | return 0; 486 | } 487 | 488 | /* _glmWriteMTL: write a wavefront material library file 489 | * 490 | * model - properly initialized GLMmodel structure 491 | * modelpath - pathname of the model being written 492 | * mtllibname - name of the material library to be written 493 | */ 494 | static int 495 | _glmWriteMTL(GLMmodel* model, char* modelpath, char* mtllibname) 496 | { 497 | FILE* file; 498 | char* dir; 499 | char* filename; 500 | GLMmaterial* material; 501 | unsigned int i; 502 | 503 | dir = _glmDirName(modelpath); 504 | filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(mtllibname))); 505 | strcpy(filename, dir); 506 | strcat(filename, mtllibname); 507 | free(dir); 508 | 509 | /* open the file */ 510 | file = fopen(filename, "w"); 511 | if (!file) { 512 | fprintf(stderr, "_glmWriteMTL() failed: can't open file \"%s\".\n", 513 | filename); 514 | free(filename); 515 | return 1; 516 | } 517 | free(filename); 518 | 519 | /* spit out a header */ 520 | fprintf(file, "# \n"); 521 | fprintf(file, "# Wavefront MTL generated by GLM library\n"); 522 | fprintf(file, "# \n"); 523 | fprintf(file, "# GLM library copyright (C) 1997 by Nate Robins\n"); 524 | fprintf(file, "# email: ndr@pobox.com\n"); 525 | fprintf(file, "# www: http://www.pobox.com/~ndr\n"); 526 | fprintf(file, "# \n\n"); 527 | 528 | for (i = 0; i < model->nummaterials; i++) { 529 | material = &model->materials[i]; 530 | fprintf(file, "newmtl %s\n", material->name); 531 | fprintf(file, "Ka %f %f %f\n", 532 | material->ambient[0], material->ambient[1], material->ambient[2]); 533 | fprintf(file, "Kd %f %f %f\n", 534 | material->diffuse[0], material->diffuse[1], material->diffuse[2]); 535 | fprintf(file, "Ks %f %f %f\n", 536 | material->specular[0],material->specular[1],material->specular[2]); 537 | fprintf(file, "Ns %f\n", material->shininess); 538 | fprintf(file, "\n"); 539 | } 540 | return 0; 541 | } 542 | 543 | /* _glmFirstPass: first pass at a Wavefront OBJ file that gets all the 544 | * statistics of the model (such as #vertices, #normals, etc) 545 | * 546 | * model - properly initialized GLMmodel structure 547 | * file - (fopen'd) file descriptor 548 | */ 549 | static int 550 | _glmFirstPass(GLMmodel* model, FILE* file) 551 | { 552 | unsigned int numvertices; /* number of vertices in model */ 553 | unsigned int numnormals; /* number of normals in model */ 554 | unsigned int numtexcoords; /* number of texcoords in model */ 555 | unsigned int numtriangles; /* number of triangles in model */ 556 | 557 | 558 | 559 | GLMgroup* group; /* current group */ 560 | char* current_group_base_name = strdup(default_group_name); 561 | char* current_material_name = strdup(default_material_name); 562 | int v, n, t; 563 | char buf[2048]; 564 | 565 | /* make a default group */ 566 | group = _glmAddGroup(model, current_group_base_name); 567 | 568 | numvertices = numnormals = numtexcoords = numtriangles = 0; 569 | 570 | while(fscanf(file, "%s", buf) != EOF) { 571 | switch(buf[0]) { 572 | case '#': /* comment */ 573 | /* eat up rest of line */ 574 | fgets(buf, sizeof(buf), file); 575 | break; 576 | case 'v': /* v, vn, vt */ 577 | switch(buf[1]) { 578 | case '\0': { /* vertex */ 579 | /* eat up rest of line */ 580 | fgets(buf, sizeof(buf), file); 581 | 582 | // TODO: Check if colors for this vertex 583 | float vx,vy,vz; 584 | int val = -1; 585 | sscanf(buf,"%f %f %f %d",&vx, &vy, &vz, &val); 586 | if (val >= 0) { 587 | model->usePerVertexColors = true; 588 | } 589 | 590 | numvertices++; 591 | break; 592 | } 593 | case 'n': /* normal */ 594 | /* eat up rest of line */ 595 | fgets(buf, sizeof(buf), file); 596 | numnormals++; 597 | break; 598 | case 't': /* texcoord */ 599 | /* eat up rest of line */ 600 | fgets(buf, sizeof(buf), file); 601 | numtexcoords++; 602 | break; 603 | default: 604 | printf("_glmFirstPass(): Unknown token \"%s\".\n", buf); 605 | /* Could error out here, but we'll just skip it for now.*/ 606 | /* return 1; */ 607 | break; 608 | } 609 | break; 610 | case 'm': 611 | fgets(buf, sizeof(buf), file); 612 | sscanf(buf, "%s %s", buf, buf); 613 | model->mtllibname = strdup(buf); 614 | if (_glmReadMTL(model, buf)) { 615 | 616 | break; /* Dont bail if MTL file not found */ 617 | 618 | /* Uh oh. Trouble reading in the material file. */ 619 | if (current_group_base_name) free(current_group_base_name); 620 | if (current_material_name) free(current_material_name); 621 | return 1; 622 | } 623 | break; 624 | case 'u': 625 | /* We need to create groups with their own materials */ 626 | fgets(buf, sizeof(buf), file); 627 | sscanf(buf, "%s %s", buf, buf); 628 | if (current_material_name) free(current_material_name); 629 | current_material_name = strdup(buf); 630 | sprintf(buf, "%s_MAT_%s", 631 | current_group_base_name, current_material_name); 632 | group = _glmAddGroup(model, buf); 633 | break; 634 | case 'o': 635 | case 'g': /* group */ 636 | fgets(buf, sizeof(buf), file); 637 | sscanf(buf, "%s", buf); 638 | if (current_group_base_name) free(current_group_base_name); 639 | current_group_base_name = strdup(buf); 640 | sprintf(buf, "%s_MAT_%s", 641 | current_group_base_name, current_material_name); 642 | group = _glmAddGroup(model, buf); 643 | break; 644 | case 'f': /* face */ 645 | v = n = t = 0; 646 | fscanf(file, "%s", buf); 647 | /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */ 648 | if (strstr(buf, "//")) { 649 | /* v//n */ 650 | sscanf(buf, "%d//%d", &v, &n); 651 | fscanf(file, "%d//%d", &v, &n); 652 | fscanf(file, "%d//%d", &v, &n); 653 | numtriangles++; 654 | group->numtriangles++; 655 | while(fscanf(file, "%d//%d", &v, &n) > 0) { 656 | numtriangles++; 657 | group->numtriangles++; 658 | } 659 | } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) { 660 | /* v/t/n */ 661 | fscanf(file, "%d/%d/%d", &v, &t, &n); 662 | fscanf(file, "%d/%d/%d", &v, &t, &n); 663 | numtriangles++; 664 | group->numtriangles++; 665 | while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) { 666 | numtriangles++; 667 | group->numtriangles++; 668 | } 669 | } else if (sscanf(buf, "%d/%d", &v, &t) == 2) { 670 | /* v/t */ 671 | fscanf(file, "%d/%d", &v, &t); 672 | fscanf(file, "%d/%d", &v, &t); 673 | numtriangles++; 674 | group->numtriangles++; 675 | while(fscanf(file, "%d/%d", &v, &t) > 0) { 676 | numtriangles++; 677 | group->numtriangles++; 678 | } 679 | } else { 680 | /* v */ 681 | fscanf(file, "%d", &v); 682 | fscanf(file, "%d", &v); 683 | numtriangles++; 684 | group->numtriangles++; 685 | while(fscanf(file, "%d", &v) > 0) { 686 | numtriangles++; 687 | group->numtriangles++; 688 | } 689 | } 690 | break; 691 | 692 | default: 693 | /* eat up rest of line */ 694 | fgets(buf, sizeof(buf), file); 695 | break; 696 | } 697 | } 698 | 699 | // #if 0 700 | /* announce the model statistics */ 701 | // printf(" Vertices: %d\n", numvertices); 702 | // printf(" Normals: %d\n", numnormals); 703 | // printf(" Texcoords: %d\n", numtexcoords); 704 | // printf(" Triangles: %d\n", numtriangles); 705 | // printf(" Groups: %d\n", model->numgroups); 706 | // #endif 707 | 708 | /* set the stats in the model structure */ 709 | model->numvertices = numvertices; 710 | model->numnormals = numnormals; 711 | model->numtexcoords = numtexcoords; 712 | model->numtriangles = numtriangles; 713 | 714 | /* allocate memory for the triangles in each group */ 715 | group = model->groups; 716 | while(group) { 717 | group->triangles = (unsigned int*)malloc(sizeof(unsigned int) * group->numtriangles); 718 | group->numtriangles = 0; 719 | group = group->next; 720 | } 721 | 722 | if (current_group_base_name) free(current_group_base_name); 723 | if (current_material_name) free(current_material_name); 724 | return 0; 725 | } 726 | 727 | /* _glmSecondPass: second pass at a Wavefront OBJ file that gets all 728 | * the data. 729 | * 730 | * model - properly initialized GLMmodel structure 731 | * file - (fopen'd) file descriptor 732 | */ 733 | static void 734 | _glmSecondPass(GLMmodel* model, FILE* file) 735 | { 736 | unsigned int numvertices; /* number of vertices in model */ 737 | unsigned int numnormals; /* number of normals in model */ 738 | unsigned int numtexcoords; /* number of texcoords in model */ 739 | unsigned int numtriangles; /* number of triangles in model */ 740 | float* vertices; /* array of vertices */ 741 | unsigned char* vertexColors; /* array of vertex colors */ 742 | float* normals; /* array of normals */ 743 | float* texcoords; /* array of texture coordinates */ 744 | GLMgroup* group; /* current group pointer */ 745 | unsigned int material; /* current material */ 746 | char* grpname; /* current group base name */ 747 | char* mtlname; /* current material name */ 748 | int v, n, t; 749 | char buf[2048]; 750 | 751 | /* set the pointer shortcuts */ 752 | vertices = model->vertices; 753 | vertexColors = model->vertexColors; 754 | normals = model->normals; 755 | texcoords = model->texcoords; 756 | group = model->groups; 757 | 758 | /* on the second pass through the file, read all the data into the 759 | allocated arrays */ 760 | numvertices = numnormals = numtexcoords = 1; 761 | numtriangles = 0; 762 | material = 0; 763 | grpname = strdup(default_group_name); 764 | mtlname = strdup(default_material_name); 765 | while(fscanf(file, "%s", buf) != EOF) { 766 | switch(buf[0]) { 767 | case '#': /* comment */ 768 | /* eat up rest of line */ 769 | fgets(buf, sizeof(buf), file); 770 | break; 771 | case 'v': /* v, vn, vt */ 772 | switch(buf[1]) { 773 | case '\0': /* vertex */ 774 | if (!model->usePerVertexColors) { 775 | fscanf(file, "%f %f %f", 776 | &vertices[3 * numvertices + X], 777 | &vertices[3 * numvertices + Y], 778 | &vertices[3 * numvertices + Z]); 779 | } 780 | else { 781 | int r,g,b; 782 | fscanf(file, "%f %f %f %d %d %d", 783 | &vertices[3 * numvertices + X], 784 | &vertices[3 * numvertices + Y], 785 | &vertices[3 * numvertices + Z], &r, &g, &b); 786 | vertexColors[3 * numvertices + X] = (unsigned char)r; 787 | vertexColors[3 * numvertices + Y] = (unsigned char)g; 788 | vertexColors[3 * numvertices + Z] = (unsigned char)b; 789 | } 790 | numvertices++; 791 | break; 792 | case 'n': /* normal */ 793 | fscanf(file, "%f %f %f", 794 | &normals[3 * numnormals + X], 795 | &normals[3 * numnormals + Y], 796 | &normals[3 * numnormals + Z]); 797 | numnormals++; 798 | break; 799 | case 't': /* texcoord */ 800 | fscanf(file, "%f %f", 801 | &texcoords[2 * numtexcoords + X], 802 | &texcoords[2 * numtexcoords + Y]); 803 | numtexcoords++; 804 | break; 805 | } 806 | break; 807 | case 'u': // usemtl 808 | fgets(buf, sizeof(buf), file); 809 | sscanf(buf, "%s %s", buf, buf); 810 | if (mtlname) free(mtlname); 811 | mtlname = strdup(buf); 812 | material = _glmFindMaterial(model, buf); 813 | sprintf(buf, "%s_MAT_%s", 814 | grpname, mtlname); 815 | group = _glmFindGroup(model, buf); 816 | group->material = material; 817 | group->mtlname = strdup(mtlname); 818 | break; 819 | case 'o': 820 | case 'g': /* group */ 821 | /* eat up rest of line */ 822 | fgets(buf, sizeof(buf), file); 823 | sscanf(buf, "%s", buf); 824 | if (grpname) free(grpname); 825 | grpname = strdup(buf); 826 | sprintf(buf, "%s_MAT_%s", 827 | grpname, mtlname); 828 | group = _glmFindGroup(model, buf); 829 | group->material = material; 830 | group->mtlname = strdup(mtlname); 831 | break; 832 | case 'f': /* face */ 833 | v = n = t = 0; 834 | fscanf(file, "%s", buf); 835 | /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */ 836 | if (strstr(buf, "//")) { 837 | /* v//n */ 838 | sscanf(buf, "%d//%d", &v, &n); 839 | T(numtriangles).vindices[0] = (v >= 0) ? v : (numvertices + v); 840 | T(numtriangles).nindices[0] = n; 841 | T(numtriangles).tindices[0] = 0; 842 | fscanf(file, "%d//%d", &v, &n); 843 | T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v); 844 | T(numtriangles).nindices[1] = n; 845 | T(numtriangles).tindices[1] = 0; 846 | fscanf(file, "%d//%d", &v, &n); 847 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 848 | T(numtriangles).nindices[2] = n; 849 | T(numtriangles).tindices[2] = 0; 850 | group->triangles[group->numtriangles++] = numtriangles; 851 | numtriangles++; 852 | while(fscanf(file, "%d//%d", &v, &n) > 0) { 853 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 854 | T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0]; 855 | T(numtriangles).tindices[0] = 0; 856 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 857 | T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2]; 858 | T(numtriangles).tindices[1] = 0; 859 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 860 | T(numtriangles).nindices[2] = n; 861 | T(numtriangles).tindices[2] = 0; 862 | group->triangles[group->numtriangles++] = numtriangles; 863 | numtriangles++; 864 | } 865 | } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) { 866 | /* v/t/n */ 867 | T(numtriangles).vindices[0] = (v >= 0) ? v : (numvertices + v); 868 | T(numtriangles).nindices[0] = n; 869 | T(numtriangles).tindices[0] = t; 870 | fscanf(file, "%d/%d/%d", &v, &t, &n); 871 | T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v); 872 | T(numtriangles).nindices[1] = n; 873 | T(numtriangles).tindices[1] = t; 874 | fscanf(file, "%d/%d/%d", &v, &t, &n); 875 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 876 | T(numtriangles).nindices[2] = n; 877 | T(numtriangles).tindices[2] = t; 878 | group->triangles[group->numtriangles++] = numtriangles; 879 | numtriangles++; 880 | while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) { 881 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 882 | T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0]; 883 | T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0]; 884 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 885 | T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2]; 886 | T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2]; 887 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 888 | T(numtriangles).nindices[2] = n; 889 | T(numtriangles).tindices[2] = t; 890 | group->triangles[group->numtriangles++] = numtriangles; 891 | numtriangles++; 892 | } 893 | } else if (sscanf(buf, "%d/%d", &v, &t) == 2) { 894 | /* v/t */ 895 | T(numtriangles).vindices[0] = (v >= 0) ? v : (numvertices + v); 896 | T(numtriangles).nindices[0] = 0; 897 | T(numtriangles).tindices[0] = t; 898 | fscanf(file, "%d/%d", &v, &t); 899 | T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v); 900 | T(numtriangles).nindices[1] = 0; 901 | T(numtriangles).tindices[1] = t; 902 | fscanf(file, "%d/%d", &v, &t); 903 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 904 | T(numtriangles).nindices[2] = 0; 905 | T(numtriangles).tindices[2] = t; 906 | group->triangles[group->numtriangles++] = numtriangles; 907 | numtriangles++; 908 | while(fscanf(file, "%d/%d", &v, &t) > 0) { 909 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 910 | T(numtriangles).nindices[0] = 0; 911 | T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0]; 912 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 913 | T(numtriangles).nindices[1] = 0; 914 | T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2]; 915 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 916 | T(numtriangles).nindices[2] = 0; 917 | T(numtriangles).tindices[2] = t; 918 | group->triangles[group->numtriangles++] = numtriangles; 919 | numtriangles++; 920 | } 921 | } else { 922 | /* v */ 923 | sscanf(buf, "%d", &v); 924 | T(numtriangles).vindices[0] = (v >= 0) ? v : (numvertices + v); 925 | T(numtriangles).nindices[0] = 0; 926 | T(numtriangles).tindices[0] = 0; 927 | fscanf(file, "%d", &v); 928 | T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v); 929 | T(numtriangles).nindices[1] = 0; 930 | T(numtriangles).tindices[1] = 0; 931 | fscanf(file, "%d", &v); 932 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 933 | T(numtriangles).nindices[2] = 0; 934 | T(numtriangles).tindices[2] = 0; 935 | group->triangles[group->numtriangles++] = numtriangles; 936 | numtriangles++; 937 | while(fscanf(file, "%d", &v) > 0) { 938 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 939 | T(numtriangles).nindices[0] = 0; 940 | T(numtriangles).tindices[0] = 0; 941 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 942 | T(numtriangles).nindices[1] = 0; 943 | T(numtriangles).tindices[1] = 0; 944 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 945 | T(numtriangles).nindices[2] = 0; 946 | T(numtriangles).tindices[2] = 0; 947 | group->triangles[group->numtriangles++] = numtriangles; 948 | numtriangles++; 949 | } 950 | } 951 | break; 952 | 953 | default: 954 | /* eat up rest of line */ 955 | fgets(buf, sizeof(buf), file); 956 | break; 957 | } 958 | } 959 | 960 | #if 0 961 | /* announce the memory requirements */ 962 | printf(" Memory: %d bytes\n", 963 | numvertices * 3*sizeof(float) + 964 | numnormals * 3*sizeof(float) * (numnormals ? 1 : 0) + 965 | numtexcoords * 3*sizeof(float) * (numtexcoords ? 1 : 0) + 966 | numtriangles * sizeof(GLMtriangle)); 967 | #endif 968 | if (grpname) free(grpname); 969 | if (mtlname) free(mtlname); 970 | } 971 | 972 | 973 | 974 | 975 | /* public functions */ 976 | 977 | /* glmUnitize: "unitize" a model by translating it to the origin and 978 | * scaling it to fit in a unit cube around the origin. Returns the 979 | * scalefactor used. 980 | * 981 | * model - properly initialized GLMmodel structure 982 | */ 983 | float 984 | glmUnitize(GLMmodel* model) 985 | { 986 | unsigned int i; 987 | float maxx, minx, maxy, miny, maxz, minz; 988 | float cx, cy, cz, w, h, d; 989 | float scale; 990 | 991 | assert(model); 992 | assert(model->vertices); 993 | 994 | /* get the max/mins */ 995 | maxx = minx = model->vertices[3 + X]; 996 | maxy = miny = model->vertices[3 + Y]; 997 | maxz = minz = model->vertices[3 + Z]; 998 | for (i = 1; i <= model->numvertices; i++) { 999 | if (maxx < model->vertices[3 * i + X]) 1000 | maxx = model->vertices[3 * i + X]; 1001 | if (minx > model->vertices[3 * i + X]) 1002 | minx = model->vertices[3 * i + X]; 1003 | 1004 | if (maxy < model->vertices[3 * i + Y]) 1005 | maxy = model->vertices[3 * i + Y]; 1006 | if (miny > model->vertices[3 * i + Y]) 1007 | miny = model->vertices[3 * i + Y]; 1008 | 1009 | if (maxz < model->vertices[3 * i + Z]) 1010 | maxz = model->vertices[3 * i + Z]; 1011 | if (minz > model->vertices[3 * i + Z]) 1012 | minz = model->vertices[3 * i + Z]; 1013 | } 1014 | 1015 | /* calculate model width, height, and depth */ 1016 | w = _glmAbs(maxx) + _glmAbs(minx); 1017 | h = _glmAbs(maxy) + _glmAbs(miny); 1018 | d = _glmAbs(maxz) + _glmAbs(minz); 1019 | 1020 | /* calculate center of the model */ 1021 | cx = (maxx + minx) / 2.0f; 1022 | cy = (maxy + miny) / 2.0f; 1023 | cz = (maxz + minz) / 2.0f; 1024 | 1025 | /* calculate unitizing scale factor */ 1026 | scale = 2.0f / _glmMax(_glmMax(w, h), d); 1027 | 1028 | /* translate around center then scale */ 1029 | for (i = 1; i <= model->numvertices; i++) { 1030 | model->vertices[3 * i + X] -= cx; 1031 | model->vertices[3 * i + Y] -= cy; 1032 | model->vertices[3 * i + Z] -= cz; 1033 | model->vertices[3 * i + X] *= scale; 1034 | model->vertices[3 * i + Y] *= scale; 1035 | model->vertices[3 * i + Z] *= scale; 1036 | } 1037 | 1038 | return scale; 1039 | } 1040 | 1041 | /* glmDimensions: Calculates the dimensions (width, height, depth) of 1042 | * a model. 1043 | * 1044 | * model - initialized GLMmodel structure 1045 | * dimensions - array of 3 floats (float dimensions[3]) 1046 | */ 1047 | void 1048 | glmDimensions(GLMmodel* model, float* dimensions) 1049 | { 1050 | unsigned int i; 1051 | float maxx, minx, maxy, miny, maxz, minz; 1052 | 1053 | assert(model); 1054 | assert(model->vertices); 1055 | assert(dimensions); 1056 | 1057 | /* get the max/mins */ 1058 | maxx = minx = model->vertices[3 + X]; 1059 | maxy = miny = model->vertices[3 + Y]; 1060 | maxz = minz = model->vertices[3 + Z]; 1061 | for (i = 1; i <= model->numvertices; i++) { 1062 | if (maxx < model->vertices[3 * i + X]) 1063 | maxx = model->vertices[3 * i + X]; 1064 | if (minx > model->vertices[3 * i + X]) 1065 | minx = model->vertices[3 * i + X]; 1066 | 1067 | if (maxy < model->vertices[3 * i + Y]) 1068 | maxy = model->vertices[3 * i + Y]; 1069 | if (miny > model->vertices[3 * i + Y]) 1070 | miny = model->vertices[3 * i + Y]; 1071 | 1072 | if (maxz < model->vertices[3 * i + Z]) 1073 | maxz = model->vertices[3 * i + Z]; 1074 | if (minz > model->vertices[3 * i + Z]) 1075 | minz = model->vertices[3 * i + Z]; 1076 | } 1077 | 1078 | /* calculate model width, height, and depth */ 1079 | dimensions[X] = _glmAbs(maxx) + _glmAbs(minx); 1080 | dimensions[Y] = _glmAbs(maxy) + _glmAbs(miny); 1081 | dimensions[Z] = _glmAbs(maxz) + _glmAbs(minz); 1082 | } 1083 | 1084 | /* 1085 | * glmBoundingBox: Calculates the min/max positions of the model 1086 | */ 1087 | void 1088 | glmBoundingBox(GLMmodel *model, float *minpos, float *maxpos) 1089 | { 1090 | unsigned int i; 1091 | float maxx, minx, maxy, miny, maxz, minz; 1092 | 1093 | assert(model); 1094 | assert(model->vertices); 1095 | assert(minpos); 1096 | assert(maxpos); 1097 | 1098 | /* get the max/mins */ 1099 | maxx = minx = model->vertices[3 + X]; 1100 | maxy = miny = model->vertices[3 + Y]; 1101 | maxz = minz = model->vertices[3 + Z]; 1102 | for (i = 1; i <= model->numvertices; i++) { 1103 | if (maxx < model->vertices[3 * i + X]) 1104 | maxx = model->vertices[3 * i + X]; 1105 | if (minx > model->vertices[3 * i + X]) 1106 | minx = model->vertices[3 * i + X]; 1107 | 1108 | if (maxy < model->vertices[3 * i + Y]) 1109 | maxy = model->vertices[3 * i + Y]; 1110 | if (miny > model->vertices[3 * i + Y]) 1111 | miny = model->vertices[3 * i + Y]; 1112 | 1113 | if (maxz < model->vertices[3 * i + Z]) 1114 | maxz = model->vertices[3 * i + Z]; 1115 | if (minz > model->vertices[3 * i + Z]) 1116 | minz = model->vertices[3 * i + Z]; 1117 | } 1118 | 1119 | minpos[0] = minx; 1120 | minpos[1] = miny; 1121 | minpos[2] = minz; 1122 | maxpos[0] = maxx; 1123 | maxpos[1] = maxy; 1124 | maxpos[2] = maxz; 1125 | 1126 | } 1127 | 1128 | /* glmScale: Scales a model by a given amount. 1129 | * 1130 | * model - properly initialized GLMmodel structure 1131 | * scale - scalefactor (0.5 = half as large, 2.0 = twice as large) 1132 | */ 1133 | void 1134 | glmScale(GLMmodel* model, float scale) 1135 | { 1136 | unsigned int i; 1137 | 1138 | for (i = 1; i <= model->numvertices; i++) { 1139 | model->vertices[3 * i + X] *= scale; 1140 | model->vertices[3 * i + Y] *= scale; 1141 | model->vertices[3 * i + Z] *= scale; 1142 | } 1143 | } 1144 | 1145 | /* glmReverseWinding: Reverse the polygon winding for all polygons in 1146 | * this model. Default winding is counter-clockwise. Also changes 1147 | * the direction of the normals. 1148 | * 1149 | * model - properly initialized GLMmodel structure 1150 | */ 1151 | void 1152 | glmReverseWinding(GLMmodel* model) 1153 | { 1154 | unsigned int i, swap; 1155 | 1156 | assert(model); 1157 | 1158 | for (i = 0; i < model->numtriangles; i++) { 1159 | swap = T(i).vindices[0]; 1160 | T(i).vindices[0] = T(i).vindices[2]; 1161 | T(i).vindices[2] = swap; 1162 | 1163 | if (model->numnormals) { 1164 | swap = T(i).nindices[0]; 1165 | T(i).nindices[0] = T(i).nindices[2]; 1166 | T(i).nindices[2] = swap; 1167 | } 1168 | 1169 | if (model->numtexcoords) { 1170 | swap = T(i).tindices[0]; 1171 | T(i).tindices[0] = T(i).tindices[2]; 1172 | T(i).tindices[2] = swap; 1173 | } 1174 | } 1175 | 1176 | /* reverse facet normals */ 1177 | for (i = 1; i <= model->numfacetnorms; i++) { 1178 | model->facetnorms[3 * i + X] = -model->facetnorms[3 * i + X]; 1179 | model->facetnorms[3 * i + Y] = -model->facetnorms[3 * i + Y]; 1180 | model->facetnorms[3 * i + Z] = -model->facetnorms[3 * i + Z]; 1181 | } 1182 | 1183 | /* reverse vertex normals */ 1184 | for (i = 1; i <= model->numnormals; i++) { 1185 | model->normals[3 * i + X] = -model->normals[3 * i + X]; 1186 | model->normals[3 * i + Y] = -model->normals[3 * i + Y]; 1187 | model->normals[3 * i + Z] = -model->normals[3 * i + Z]; 1188 | } 1189 | } 1190 | 1191 | /* glmFacetNormals: Generates facet normals for a model (by taking the 1192 | * cross product of the two vectors derived from the sides of each 1193 | * triangle). Assumes a counter-clockwise winding. 1194 | * 1195 | * model - initialized GLMmodel structure 1196 | */ 1197 | void 1198 | glmFacetNormals(GLMmodel* model) 1199 | { 1200 | unsigned int i; 1201 | float u[3]; 1202 | float v[3]; 1203 | 1204 | assert(model); 1205 | assert(model->vertices); 1206 | 1207 | /* clobber any old facetnormals */ 1208 | if (model->facetnorms) 1209 | free(model->facetnorms); 1210 | 1211 | /* allocate memory for the new facet normals */ 1212 | model->numfacetnorms = model->numtriangles; 1213 | model->facetnorms = (float*)malloc(sizeof(float) * 1214 | 3 * (model->numfacetnorms + 1)); 1215 | 1216 | for (i = 0; i < model->numtriangles; i++) { 1217 | model->triangles[i].findex = i+1; 1218 | 1219 | u[X] = model->vertices[3 * T(i).vindices[1] + X] - 1220 | model->vertices[3 * T(i).vindices[0] + X]; 1221 | u[Y] = model->vertices[3 * T(i).vindices[1] + Y] - 1222 | model->vertices[3 * T(i).vindices[0] + Y]; 1223 | u[Z] = model->vertices[3 * T(i).vindices[1] + Z] - 1224 | model->vertices[3 * T(i).vindices[0] + Z]; 1225 | 1226 | v[X] = model->vertices[3 * T(i).vindices[2] + X] - 1227 | model->vertices[3 * T(i).vindices[0] + X]; 1228 | v[Y] = model->vertices[3 * T(i).vindices[2] + Y] - 1229 | model->vertices[3 * T(i).vindices[0] + Y]; 1230 | v[Z] = model->vertices[3 * T(i).vindices[2] + Z] - 1231 | model->vertices[3 * T(i).vindices[0] + Z]; 1232 | 1233 | _glmCross(u, v, &model->facetnorms[3 * (i+1)]); 1234 | _glmNormalize(&model->facetnorms[3 * (i+1)]); 1235 | } 1236 | } 1237 | 1238 | /* glmVertexNormals: Generates smooth vertex normals for a model. 1239 | * First builds a list of all the triangles each vertex is in. Then 1240 | * loops through each vertex in the the list averaging all the facet 1241 | * normals of the triangles each vertex is in. Finally, sets the 1242 | * normal index in the triangle for the vertex to the generated smooth 1243 | * normal. If the dot product of a facet normal and the facet normal 1244 | * associated with the first triangle in the list of triangles the 1245 | * current vertex is in is greater than the cosine of the angle 1246 | * parameter to the function, that facet normal is not added into the 1247 | * average normal calculation and the corresponding vertex is given 1248 | * the facet normal. This tends to preserve hard edges. The angle to 1249 | * use depends on the model, but 90 degrees is usually a good start. 1250 | * 1251 | * model - initialized GLMmodel structure 1252 | * angle - maximum angle (in degrees) to smooth across 1253 | */ 1254 | void 1255 | glmVertexNormals(GLMmodel* model, float angle) 1256 | { 1257 | GLMnode* node; 1258 | GLMnode* tail; 1259 | GLMnode** members; 1260 | float* normals; 1261 | unsigned int numnormals; 1262 | float average[3]; 1263 | float dot, cos_angle; 1264 | unsigned int i, avg; 1265 | 1266 | assert(model); 1267 | assert(model->facetnorms); 1268 | 1269 | /* calculate the cosine of the angle (in degrees) */ 1270 | cos_angle = cosf(angle * (float)M_PI / 180.0f); 1271 | 1272 | /* nuke any previous normals */ 1273 | if (model->normals) 1274 | free(model->normals); 1275 | 1276 | /* allocate space for new normals */ 1277 | model->numnormals = model->numtriangles * 3; /* 3 normals per triangle */ 1278 | model->normals = (float*)malloc(sizeof(float)* 3* (model->numnormals+1)); 1279 | 1280 | /* allocate a structure that will hold a linked list of triangle 1281 | indices for each vertex */ 1282 | members = (GLMnode**)malloc(sizeof(GLMnode*) * (model->numvertices + 1)); 1283 | for (i = 1; i <= model->numvertices; i++) 1284 | members[i] = NULL; 1285 | 1286 | /* for every triangle, create a node for each vertex in it */ 1287 | for (i = 0; i < model->numtriangles; i++) { 1288 | node = (GLMnode*)malloc(sizeof(GLMnode)); 1289 | node->index = i; 1290 | node->next = members[T(i).vindices[0]]; 1291 | members[T(i).vindices[0]] = node; 1292 | 1293 | node = (GLMnode*)malloc(sizeof(GLMnode)); 1294 | node->index = i; 1295 | node->next = members[T(i).vindices[1]]; 1296 | members[T(i).vindices[1]] = node; 1297 | 1298 | node = (GLMnode*)malloc(sizeof(GLMnode)); 1299 | node->index = i; 1300 | node->next = members[T(i).vindices[2]]; 1301 | members[T(i).vindices[2]] = node; 1302 | } 1303 | 1304 | /* calculate the average normal for each vertex */ 1305 | numnormals = 1; 1306 | for (i = 1; i <= model->numvertices; i++) { 1307 | /* calculate an average normal for this vertex by averaging the 1308 | facet normal of every triangle this vertex is in */ 1309 | node = members[i]; 1310 | if (!node) 1311 | fprintf(stderr, "glmVertexNormals(): vertex w/o a triangle\n"); 1312 | average[0] = 0.0; average[1] = 0.0; average[2] = 0.0; 1313 | avg = 0; 1314 | while (node) { 1315 | /* only average if the dot product of the angle between the two 1316 | facet normals is greater than the cosine of the threshold 1317 | angle -- or, said another way, the angle between the two 1318 | facet normals is less than (or equal to) the threshold angle */ 1319 | dot = _glmDot(&model->facetnorms[3 * T(node->index).findex], 1320 | &model->facetnorms[3 * T(members[i]->index).findex]); 1321 | if (dot > cos_angle) { 1322 | node->averaged = true; 1323 | average[0] += model->facetnorms[3 * T(node->index).findex + 0]; 1324 | average[1] += model->facetnorms[3 * T(node->index).findex + 1]; 1325 | average[2] += model->facetnorms[3 * T(node->index).findex + 2]; 1326 | avg = 1; /* we averaged at least one normal! */ 1327 | } else { 1328 | node->averaged = false; 1329 | } 1330 | node = node->next; 1331 | } 1332 | 1333 | if (avg) { 1334 | /* normalize the averaged normal */ 1335 | _glmNormalize(average); 1336 | 1337 | /* add the normal to the vertex normals list */ 1338 | model->normals[3 * numnormals + 0] = average[0]; 1339 | model->normals[3 * numnormals + 1] = average[1]; 1340 | model->normals[3 * numnormals + 2] = average[2]; 1341 | avg = numnormals; 1342 | numnormals++; 1343 | } 1344 | 1345 | /* set the normal of this vertex in each triangle it is in */ 1346 | node = members[i]; 1347 | while (node) { 1348 | if (node->averaged) { 1349 | /* if this node was averaged, use the average normal */ 1350 | if (T(node->index).vindices[0] == i) 1351 | T(node->index).nindices[0] = avg; 1352 | else if (T(node->index).vindices[1] == i) 1353 | T(node->index).nindices[1] = avg; 1354 | else if (T(node->index).vindices[2] == i) 1355 | T(node->index).nindices[2] = avg; 1356 | } else { 1357 | /* if this node wasn't averaged, use the facet normal */ 1358 | model->normals[3 * numnormals + 0] = 1359 | model->facetnorms[3 * T(node->index).findex + 0]; 1360 | model->normals[3 * numnormals + 1] = 1361 | model->facetnorms[3 * T(node->index).findex + 1]; 1362 | model->normals[3 * numnormals + 2] = 1363 | model->facetnorms[3 * T(node->index).findex + 2]; 1364 | if (T(node->index).vindices[0] == i) 1365 | T(node->index).nindices[0] = numnormals; 1366 | else if (T(node->index).vindices[1] == i) 1367 | T(node->index).nindices[1] = numnormals; 1368 | else if (T(node->index).vindices[2] == i) 1369 | T(node->index).nindices[2] = numnormals; 1370 | numnormals++; 1371 | } 1372 | node = node->next; 1373 | } 1374 | } 1375 | 1376 | model->numnormals = numnormals - 1; 1377 | 1378 | /* free the member information */ 1379 | for (i = 1; i <= model->numvertices; i++) { 1380 | node = members[i]; 1381 | while (node) { 1382 | tail = node; 1383 | node = node->next; 1384 | free(tail); 1385 | } 1386 | } 1387 | free(members); 1388 | 1389 | /* pack the normals array (we previously allocated the maximum 1390 | number of normals that could possibly be created (numtriangles * 1391 | 3), so get rid of some of them (usually alot unless none of the 1392 | facet normals were averaged)) */ 1393 | normals = model->normals; 1394 | model->normals = (float*)malloc(sizeof(float)* 3* (model->numnormals+1)); 1395 | for (i = 1; i <= model->numnormals; i++) { 1396 | model->normals[3 * i + 0] = normals[3 * i + 0]; 1397 | model->normals[3 * i + 1] = normals[3 * i + 1]; 1398 | model->normals[3 * i + 2] = normals[3 * i + 2]; 1399 | } 1400 | free(normals); 1401 | 1402 | // printf("glmVertexNormals(): %u normals generated\n", model->numnormals); 1403 | } 1404 | 1405 | 1406 | /* glmLinearTexture: Generates texture coordinates according to a 1407 | * linear projection of the texture map. It generates these by 1408 | * linearly mapping the vertices onto a square. 1409 | * 1410 | * model - pointer to initialized GLMmodel structure 1411 | */ 1412 | void 1413 | glmLinearTexture(GLMmodel* model) 1414 | { 1415 | GLMgroup *group; 1416 | float dimensions[3]; 1417 | float x, y, scalefactor; 1418 | unsigned int i; 1419 | 1420 | assert(model); 1421 | 1422 | if (model->texcoords) 1423 | free(model->texcoords); 1424 | model->numtexcoords = model->numvertices; 1425 | model->texcoords=(float*)malloc(sizeof(float)*2*(model->numtexcoords+1)); 1426 | 1427 | glmDimensions(model, dimensions); 1428 | scalefactor = 2.0f / 1429 | _glmAbs(_glmMax(_glmMax(dimensions[0], dimensions[1]), dimensions[2])); 1430 | 1431 | /* do the calculations */ 1432 | for(i = 1; i <= model->numvertices; i++) { 1433 | x = model->vertices[3 * i + 0] * scalefactor; 1434 | y = model->vertices[3 * i + 2] * scalefactor; 1435 | model->texcoords[2 * i + 0] = (x + 1.0f) / 2.0f; 1436 | model->texcoords[2 * i + 1] = (y + 1.0f) / 2.0f; 1437 | } 1438 | 1439 | /* go through and put texture coordinate indices in all the triangles */ 1440 | group = model->groups; 1441 | while(group) { 1442 | for(i = 0; i < group->numtriangles; i++) { 1443 | T(group->triangles[i]).tindices[0] = T(group->triangles[i]).vindices[0]; 1444 | T(group->triangles[i]).tindices[1] = T(group->triangles[i]).vindices[1]; 1445 | T(group->triangles[i]).tindices[2] = T(group->triangles[i]).vindices[2]; 1446 | } 1447 | group = group->next; 1448 | } 1449 | 1450 | #if 0 1451 | printf("glmLinearTexture(): generated %d linear texture coordinates\n", 1452 | model->numtexcoords); 1453 | #endif 1454 | } 1455 | 1456 | /* glmSpheremapTexture: Generates texture coordinates according to a 1457 | * spherical projection of the texture map. Sometimes referred to as 1458 | * spheremap, or reflection map texture coordinates. It generates 1459 | * these by using the normal to calculate where that vertex would map 1460 | * onto a sphere. Since it is impossible to map something flat 1461 | * perfectly onto something spherical, there is distortion at the 1462 | * poles. This particular implementation causes the poles along the X 1463 | * axis to be distorted. 1464 | * 1465 | * model - pointer to initialized GLMmodel structure 1466 | */ 1467 | void 1468 | glmSpheremapTexture(GLMmodel* model) 1469 | { 1470 | GLMgroup* group; 1471 | float theta, phi, rho, x, y, z, r; 1472 | unsigned int i; 1473 | 1474 | assert(model); 1475 | assert(model->normals); 1476 | 1477 | if (model->texcoords) 1478 | free(model->texcoords); 1479 | model->numtexcoords = model->numnormals; 1480 | model->texcoords=(float*)malloc(sizeof(float)*2*(model->numtexcoords+1)); 1481 | 1482 | /* do the calculations */ 1483 | for (i = 1; i <= model->numnormals; i++) { 1484 | z = model->normals[3 * i + 0]; /* re-arrange for pole distortion */ 1485 | y = model->normals[3 * i + 1]; 1486 | x = model->normals[3 * i + 2]; 1487 | r = sqrtf((x * x) + (y * y)); 1488 | rho = sqrtf((r * r) + (z * z)); 1489 | 1490 | if(r == 0.0f) { 1491 | theta = 0.0f; 1492 | phi = 0.0f; 1493 | } else { 1494 | if(z == 0.0) 1495 | phi = 3.14159265f / 2.0f; 1496 | else 1497 | phi = acosf(z / rho); 1498 | 1499 | #if WE_DONT_NEED_THIS_CODE 1500 | if(x == 0.0f) 1501 | theta = 3.14159265f / 2.0f; /* asin(y / r); */ 1502 | else 1503 | theta = acosf(x / r); 1504 | #endif 1505 | 1506 | if(y == 0.0f) 1507 | theta = 3.141592365f / 2.0f; /* acos(x / r); */ 1508 | else 1509 | theta = asinf(y / r) + (3.14159265f / 2.0f); 1510 | } 1511 | 1512 | model->texcoords[2 * i + 0] = theta / 3.14159265f; 1513 | model->texcoords[2 * i + 1] = phi / 3.14159265f; 1514 | } 1515 | 1516 | /* go through and put texcoord indices in all the triangles */ 1517 | group = model->groups; 1518 | while(group) { 1519 | for (i = 0; i < group->numtriangles; i++) { 1520 | T(group->triangles[i]).tindices[0] = T(group->triangles[i]).nindices[0]; 1521 | T(group->triangles[i]).tindices[1] = T(group->triangles[i]).nindices[1]; 1522 | T(group->triangles[i]).tindices[2] = T(group->triangles[i]).nindices[2]; 1523 | } 1524 | group = group->next; 1525 | } 1526 | 1527 | #if 0 1528 | printf("glmSpheremapTexture(): generated %d spheremap texture coordinates\n", 1529 | model->numtexcoords); 1530 | #endif 1531 | } 1532 | 1533 | /* glmDelete: Deletes a GLMmodel structure. 1534 | * 1535 | * model - initialized GLMmodel structure 1536 | */ 1537 | void 1538 | glmDelete(GLMmodel* model) 1539 | { 1540 | GLMgroup* group; 1541 | unsigned int i; 1542 | 1543 | assert(model); 1544 | 1545 | if (model->pathname) free(model->pathname); 1546 | if (model->mtllibname) free(model->mtllibname); 1547 | if (model->vertices) free(model->vertices); 1548 | if (model->normals) free(model->normals); 1549 | if (model->texcoords) free(model->texcoords); 1550 | if (model->facetnorms) free(model->facetnorms); 1551 | if (model->triangles) free(model->triangles); 1552 | if (model->materials) { 1553 | for (i = 0; i < model->nummaterials; i++) 1554 | if (model->materials[i].name) free(model->materials[i].name); 1555 | free(model->materials); 1556 | } 1557 | while(model->groups) { 1558 | group = model->groups; 1559 | /* Take the group off the linked list. */ 1560 | model->groups = model->groups->next; 1561 | if (group->name) free(group->name); 1562 | if (group->triangles) free(group->triangles); 1563 | if (group->mtlname) free(group->mtlname); 1564 | free(group); 1565 | } 1566 | 1567 | free(model); 1568 | } 1569 | 1570 | /* glmReadOBJ: Reads a model description from a Wavefront .OBJ file. 1571 | * Returns a pointer to the created object which should be free'd with 1572 | * glmDelete(). 1573 | * 1574 | * filename - name of the file containing the Wavefront .OBJ format data. 1575 | */ 1576 | GLMmodel* 1577 | glmReadOBJ(const char* filename) 1578 | { 1579 | GLMmodel* model; 1580 | FILE* file; 1581 | 1582 | /* open the file */ 1583 | file = fopen(filename, "r"); 1584 | if (!file) { 1585 | perror("glmReadOBJ() failed: can't open data file"); 1586 | return 0; 1587 | } 1588 | 1589 | #if 0 1590 | /* announce the model name */ 1591 | printf("Model: %s\n", filename); 1592 | #endif 1593 | 1594 | /* allocate a new model */ 1595 | model = (GLMmodel*)malloc(sizeof(GLMmodel)); 1596 | model->pathname = strdup(filename); 1597 | model->mtllibname = NULL; 1598 | model->numvertices = 0; 1599 | model->vertices = NULL; 1600 | model->numnormals = 0; 1601 | model->normals = NULL; 1602 | model->numtexcoords = 0; 1603 | model->texcoords = NULL; 1604 | model->numfacetnorms = 0; 1605 | model->facetnorms = NULL; 1606 | model->numtriangles = 0; 1607 | model->triangles = NULL; 1608 | model->nummaterials = 0; 1609 | model->materials = NULL; 1610 | model->numgroups = 0; 1611 | model->groups = NULL; 1612 | model->position[0] = 0.0; 1613 | model->position[1] = 0.0; 1614 | model->position[2] = 0.0; 1615 | model->usePerVertexColors = 0; 1616 | /* make a first pass through the file to get a count of the number 1617 | of vertices, normals, texcoords & triangles */ 1618 | if (_glmFirstPass(model, file)) { 1619 | /* There was a problem here, so cleanup and exit. */ 1620 | glmDelete(model); 1621 | fclose(file); 1622 | return 0; 1623 | } 1624 | 1625 | /* allocate memory */ 1626 | model->vertices = (float*)malloc(sizeof(float) * 1627 | 3 * (model->numvertices + 1)); 1628 | model->vertexColors = (unsigned char*)malloc(sizeof(unsigned char) * 1629 | 3 * (model->numvertices + 1)); 1630 | model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) * 1631 | model->numtriangles); 1632 | if (model->numnormals) { 1633 | model->normals = (float*)malloc(sizeof(float) * 1634 | 3 * (model->numnormals + 1)); 1635 | } 1636 | if (model->numtexcoords) { 1637 | model->texcoords = (float*)malloc(sizeof(float) * 1638 | 2 * (model->numtexcoords + 1)); 1639 | } 1640 | 1641 | /* rewind to beginning of file and read in the data this pass */ 1642 | rewind(file); 1643 | 1644 | _glmSecondPass(model, file); 1645 | 1646 | /* close the file */ 1647 | fclose(file); 1648 | 1649 | return model; 1650 | } 1651 | 1652 | /* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to 1653 | * a file. 1654 | * 1655 | * model - initialized GLMmodel structure 1656 | * filename - name of the file to write the Wavefront .OBJ format data to 1657 | * mode - a bitwise or of values describing what is written to the file 1658 | * GLM_NONE - render with only vertices 1659 | * GLM_FLAT - render with facet normals 1660 | * GLM_SMOOTH - render with vertex normals 1661 | * GLM_TEXTURE - render with texture coords 1662 | * GLM_COLOR - render with colors (color material) 1663 | * GLM_MATERIAL - render with materials 1664 | * GLM_COLOR and GLM_MATERIAL should not both be specified. 1665 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 1666 | */ 1667 | int 1668 | glmWriteOBJ(GLMmodel* model, char* filename, unsigned int mode) 1669 | { 1670 | unsigned int i; 1671 | FILE* file; 1672 | GLMgroup* group; 1673 | 1674 | assert(model); 1675 | 1676 | /* do a bit of warning */ 1677 | if (mode & GLM_FLAT && !model->facetnorms) { 1678 | printf("glmWriteOBJ() warning: flat normal output requested " 1679 | "with no facet normals defined.\n"); 1680 | mode &= ~GLM_FLAT; 1681 | } 1682 | if (mode & GLM_SMOOTH && !model->normals) { 1683 | printf("glmWriteOBJ() warning: smooth normal output requested " 1684 | "with no normals defined.\n"); 1685 | mode &= ~GLM_SMOOTH; 1686 | } 1687 | if (mode & GLM_TEXTURE && !model->texcoords) { 1688 | printf("glmWriteOBJ() warning: texture coordinate output requested " 1689 | "with no texture coordinates defined.\n"); 1690 | mode &= ~GLM_TEXTURE; 1691 | } 1692 | if (mode & GLM_FLAT && mode & GLM_SMOOTH) { 1693 | printf("glmWriteOBJ() warning: flat normal output requested " 1694 | "and smooth normal output requested (using smooth).\n"); 1695 | mode &= ~GLM_FLAT; 1696 | } 1697 | 1698 | /* open the file */ 1699 | file = fopen(filename, "w"); 1700 | if (!file) { 1701 | fprintf(stderr, "glmWriteOBJ() failed: can't open file \"%s\" to write.\n", 1702 | filename); 1703 | return 1; 1704 | } 1705 | 1706 | /* spit out a header */ 1707 | fprintf(file, "# \n"); 1708 | fprintf(file, "# Wavefront OBJ generated by GLM library\n"); 1709 | fprintf(file, "# \n"); 1710 | fprintf(file, "# GLM library copyright (C) 1997 by Nate Robins\n"); 1711 | fprintf(file, "# email: ndr@pobox.com\n"); 1712 | fprintf(file, "# www: http://www.pobox.com/~ndr\n"); 1713 | fprintf(file, "# \n"); 1714 | 1715 | if (mode & GLM_MATERIAL && model->mtllibname) { 1716 | fprintf(file, "\nmtllib %s\n\n", model->mtllibname); 1717 | if (_glmWriteMTL(model, filename, model->mtllibname)) { 1718 | /* Problem opening up the material file for output. */ 1719 | fclose(file); 1720 | return 1; 1721 | } 1722 | } 1723 | 1724 | /* spit out the vertices */ 1725 | fprintf(file, "\n"); 1726 | fprintf(file, "# %u vertices\n", model->numvertices); 1727 | for (i = 1; i <= model->numvertices; i++) { 1728 | fprintf(file, "v %f %f %f\n", 1729 | model->vertices[3 * i + 0], 1730 | model->vertices[3 * i + 1], 1731 | model->vertices[3 * i + 2]); 1732 | } 1733 | 1734 | /* spit out the smooth/flat normals */ 1735 | if (mode & GLM_SMOOTH) { 1736 | fprintf(file, "\n"); 1737 | fprintf(file, "# %u normals\n", model->numnormals); 1738 | for (i = 1; i <= model->numnormals; i++) { 1739 | fprintf(file, "vn %f %f %f\n", 1740 | model->normals[3 * i + 0], 1741 | model->normals[3 * i + 1], 1742 | model->normals[3 * i + 2]); 1743 | } 1744 | } else if (mode & GLM_FLAT) { 1745 | fprintf(file, "\n"); 1746 | fprintf(file, "# %u normals\n", model->numfacetnorms); 1747 | for (i = 1; i <= model->numnormals; i++) { 1748 | fprintf(file, "vn %f %f %f\n", 1749 | model->facetnorms[3 * i + 0], 1750 | model->facetnorms[3 * i + 1], 1751 | model->facetnorms[3 * i + 2]); 1752 | } 1753 | } 1754 | 1755 | /* spit out the texture coordinates */ 1756 | if (mode & GLM_TEXTURE) { 1757 | fprintf(file, "\n"); 1758 | fprintf(file, "# %u texcoords\n", model->numtexcoords); 1759 | for (i = 1; i <= model->numtexcoords; i++) { 1760 | fprintf(file, "vt %f %f\n", 1761 | model->texcoords[2 * i + 0], 1762 | model->texcoords[2 * i + 1]); 1763 | } 1764 | } 1765 | 1766 | fprintf(file, "\n"); 1767 | fprintf(file, "# %u groups\n", model->numgroups); 1768 | fprintf(file, "# %u faces (triangles)\n", model->numtriangles); 1769 | fprintf(file, "\n"); 1770 | 1771 | group = model->groups; 1772 | while(group) { 1773 | fprintf(file, "g %s\n", group->name); 1774 | if (mode & GLM_MATERIAL) 1775 | fprintf(file, "usemtl %s\n", model->materials[group->material].name); 1776 | for (i = 0; i < group->numtriangles; i++) { 1777 | if (mode & GLM_SMOOTH && mode & GLM_TEXTURE) { 1778 | fprintf(file, "f %u/%u/%u %u/%u/%u %u/%u/%u\n", 1779 | T(group->triangles[i]).vindices[0], 1780 | T(group->triangles[i]).nindices[0], 1781 | T(group->triangles[i]).tindices[0], 1782 | T(group->triangles[i]).vindices[1], 1783 | T(group->triangles[i]).nindices[1], 1784 | T(group->triangles[i]).tindices[1], 1785 | T(group->triangles[i]).vindices[2], 1786 | T(group->triangles[i]).nindices[2], 1787 | T(group->triangles[i]).tindices[2]); 1788 | } else if (mode & GLM_FLAT && mode & GLM_TEXTURE) { 1789 | fprintf(file, "f %u/%u %u/%u %u/%u\n", 1790 | T(group->triangles[i]).vindices[0], 1791 | T(group->triangles[i]).findex, 1792 | T(group->triangles[i]).vindices[1], 1793 | T(group->triangles[i]).findex, 1794 | T(group->triangles[i]).vindices[2], 1795 | T(group->triangles[i]).findex); 1796 | } else if (mode & GLM_TEXTURE) { 1797 | fprintf(file, "f %u/%u %u/%u %u/%u\n", 1798 | T(group->triangles[i]).vindices[0], 1799 | T(group->triangles[i]).tindices[0], 1800 | T(group->triangles[i]).vindices[1], 1801 | T(group->triangles[i]).tindices[1], 1802 | T(group->triangles[i]).vindices[2], 1803 | T(group->triangles[i]).tindices[2]); 1804 | } else if (mode & GLM_SMOOTH) { 1805 | fprintf(file, "f %u//%u %u//%u %u//%u\n", 1806 | T(group->triangles[i]).vindices[0], 1807 | T(group->triangles[i]).nindices[0], 1808 | T(group->triangles[i]).vindices[1], 1809 | T(group->triangles[i]).nindices[1], 1810 | T(group->triangles[i]).vindices[2], 1811 | T(group->triangles[i]).nindices[2]); 1812 | } else if (mode & GLM_FLAT) { 1813 | fprintf(file, "f %u//%u %u//%u %u//%u\n", 1814 | T(group->triangles[i]).vindices[0], 1815 | T(group->triangles[i]).findex, 1816 | T(group->triangles[i]).vindices[1], 1817 | T(group->triangles[i]).findex, 1818 | T(group->triangles[i]).vindices[2], 1819 | T(group->triangles[i]).findex); 1820 | } else { 1821 | fprintf(file, "f %u %u %u\n", 1822 | T(group->triangles[i]).vindices[0], 1823 | T(group->triangles[i]).vindices[1], 1824 | T(group->triangles[i]).vindices[2]); 1825 | } 1826 | } 1827 | fprintf(file, "\n"); 1828 | group = group->next; 1829 | } 1830 | 1831 | fclose(file); 1832 | return 0; 1833 | } 1834 | 1835 | /* glmWeld: eliminate (weld) vectors that are within an epsilon of 1836 | * each other. 1837 | * 1838 | * model - initialized GLMmodel structure 1839 | * epsilon - maximum difference between vertices 1840 | * ( 0.00001 is a good start for a unitized model) 1841 | * 1842 | */ 1843 | void 1844 | glmWeld(GLMmodel* model, float epsilon) 1845 | { 1846 | float* vectors; 1847 | float* copies; 1848 | unsigned int numvectors; 1849 | unsigned int i; 1850 | 1851 | /* vertices */ 1852 | numvectors = model->numvertices; 1853 | vectors = model->vertices; 1854 | copies = _glmWeldVectors(vectors, &numvectors, epsilon); 1855 | 1856 | printf("glmWeld(): %u redundant vertices.\n", 1857 | model->numvertices - numvectors - 1); 1858 | 1859 | for (i = 0; i < model->numtriangles; i++) { 1860 | T(i).vindices[0] = (unsigned int)vectors[3 * T(i).vindices[0] + 0]; 1861 | T(i).vindices[1] = (unsigned int)vectors[3 * T(i).vindices[1] + 0]; 1862 | T(i).vindices[2] = (unsigned int)vectors[3 * T(i).vindices[2] + 0]; 1863 | } 1864 | 1865 | /* free space for old vertices */ 1866 | free(vectors); 1867 | 1868 | /* allocate space for the new vertices */ 1869 | model->numvertices = numvectors; 1870 | model->vertices = (float*)malloc(sizeof(float) * 1871 | 3 * (model->numvertices + 1)); 1872 | 1873 | /* copy the optimized vertices into the actual vertex list */ 1874 | for (i = 1; i <= model->numvertices; i++) { 1875 | model->vertices[3 * i + 0] = copies[3 * i + 0]; 1876 | model->vertices[3 * i + 1] = copies[3 * i + 1]; 1877 | model->vertices[3 * i + 2] = copies[3 * i + 2]; 1878 | } 1879 | 1880 | free(copies); 1881 | } 1882 | 1883 | #if 0 /** This is left in only as a reference to how to get to the data. */ 1884 | /* glmDraw: Renders the model to the current OpenGL context using the 1885 | * mode specified. 1886 | * 1887 | * model - initialized GLMmodel structure 1888 | * mode - a bitwise OR of values describing what is to be rendered. 1889 | * GLM_NONE - render with only vertices 1890 | * GLM_FLAT - render with facet normals 1891 | * GLM_SMOOTH - render with vertex normals 1892 | * GLM_TEXTURE - render with texture coords 1893 | * GLM_COLOR - render with colors (color material) 1894 | * GLM_MATERIAL - render with materials 1895 | * GLM_COLOR and GLM_MATERIAL should not both be specified. 1896 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 1897 | */ 1898 | GLvoid 1899 | glmDraw(GLMmodel* model, unsigned int mode) 1900 | { 1901 | unsigned int i; 1902 | GLMgroup* group; 1903 | 1904 | assert(model); 1905 | assert(model->vertices); 1906 | 1907 | /* do a bit of warning */ 1908 | if (mode & GLM_FLAT && !model->facetnorms) { 1909 | printf("glmDraw() warning: flat render mode requested " 1910 | "with no facet normals defined.\n"); 1911 | mode &= ~GLM_FLAT; 1912 | } 1913 | if (mode & GLM_SMOOTH && !model->normals) { 1914 | printf("glmDraw() warning: smooth render mode requested " 1915 | "with no normals defined.\n"); 1916 | mode &= ~GLM_SMOOTH; 1917 | } 1918 | if (mode & GLM_TEXTURE && !model->texcoords) { 1919 | printf("glmDraw() warning: texture render mode requested " 1920 | "with no texture coordinates defined.\n"); 1921 | mode &= ~GLM_TEXTURE; 1922 | } 1923 | if (mode & GLM_FLAT && mode & GLM_SMOOTH) { 1924 | printf("glmDraw() warning: flat render mode requested " 1925 | "and smooth render mode requested (using smooth).\n"); 1926 | mode &= ~GLM_FLAT; 1927 | } 1928 | if (mode & GLM_COLOR && !model->materials) { 1929 | printf("glmDraw() warning: color render mode requested " 1930 | "with no materials defined.\n"); 1931 | mode &= ~GLM_COLOR; 1932 | } 1933 | if (mode & GLM_MATERIAL && !model->materials) { 1934 | printf("glmDraw() warning: material render mode requested " 1935 | "with no materials defined.\n"); 1936 | mode &= ~GLM_MATERIAL; 1937 | } 1938 | if (mode & GLM_COLOR && mode & GLM_MATERIAL) { 1939 | printf("glmDraw() warning: color and material render mode requested " 1940 | "using only material mode\n"); 1941 | mode &= ~GLM_COLOR; 1942 | } 1943 | if (mode & GLM_COLOR) 1944 | glEnable(GL_COLOR_MATERIAL); 1945 | if (mode & GLM_MATERIAL) 1946 | glDisable(GL_COLOR_MATERIAL); 1947 | 1948 | glPushMatrix(); 1949 | glTranslatef(model->position[0], model->position[1], model->position[2]); 1950 | 1951 | glBegin(GL_TRIANGLES); 1952 | group = model->groups; 1953 | while (group) { 1954 | if (mode & GLM_MATERIAL) { 1955 | glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, 1956 | model->materials[group->material].ambient); 1957 | glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 1958 | model->materials[group->material].diffuse); 1959 | glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, 1960 | model->materials[group->material].specular); 1961 | glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 1962 | model->materials[group->material].shininess); 1963 | } 1964 | 1965 | if (mode & GLM_COLOR) { 1966 | glColor3fv(model->materials[group->material].diffuse); 1967 | } 1968 | 1969 | for (i = 0; i < group->numtriangles; i++) { 1970 | if (mode & GLM_FLAT) 1971 | glNormal3fv(&model->facetnorms[3 * T(group->triangles[i]).findex]); 1972 | 1973 | if (mode & GLM_SMOOTH) 1974 | glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[0]]); 1975 | if (mode & GLM_TEXTURE) 1976 | glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[0]]); 1977 | 1978 | if (model->usePerVertexColors) { 1979 | glColor3ubv( &model->vertexColors[3 * T(group->triangles[i]).vindices[0]] ); 1980 | } 1981 | 1982 | glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[0]]); 1983 | #if 0 1984 | printf("%f %f %f\n", 1985 | model->vertices[3 * T(group->triangles[i]).vindices[0] + X], 1986 | model->vertices[3 * T(group->triangles[i]).vindices[0] + Y], 1987 | model->vertices[3 * T(group->triangles[i]).vindices[0] + Z]); 1988 | #endif 1989 | 1990 | if (mode & GLM_SMOOTH) 1991 | glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[1]]); 1992 | if (mode & GLM_TEXTURE) 1993 | glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[1]]); 1994 | if (model->usePerVertexColors) { 1995 | glColor3ubv( &model->vertexColors[3 * T(group->triangles[i]).vindices[1]] ); 1996 | } 1997 | glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[1]]); 1998 | #if 0 1999 | printf("%f %f %f\n", 2000 | model->vertices[3 * T(group->triangles[i]).vindices[1] + X], 2001 | model->vertices[3 * T(group->triangles[i]).vindices[1] + Y], 2002 | model->vertices[3 * T(group->triangles[i]).vindices[1] + Z]); 2003 | #endif 2004 | 2005 | if (mode & GLM_SMOOTH) 2006 | glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[2]]); 2007 | if (mode & GLM_TEXTURE) 2008 | glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[2]]); 2009 | if (model->usePerVertexColors) { 2010 | glColor3ubv( &model->vertexColors[3 * T(group->triangles[i]).vindices[2]] ); 2011 | } 2012 | glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[2]]); 2013 | #if 0 2014 | printf("%f %f %f\n", 2015 | model->vertices[3 * T(group->triangles[i]).vindices[2] + X], 2016 | model->vertices[3 * T(group->triangles[i]).vindices[2] + Y], 2017 | model->vertices[3 * T(group->triangles[i]).vindices[2] + Z]); 2018 | #endif 2019 | 2020 | } 2021 | 2022 | group = group->next; 2023 | } 2024 | glEnd(); 2025 | 2026 | glPopMatrix(); 2027 | } 2028 | #endif 2029 | 2030 | -------------------------------------------------------------------------------- /test/glm/.svn/text-base/glm.h.svn-base: -------------------------------------------------------------------------------- 1 | /* 2 | * GLM library. Wavefront .obj file format reader/writer/manipulator. 3 | * 4 | * Written by Nate Robins, 1997. 5 | * email: ndr@pobox.com 6 | * www: http://www.pobox.com/~ndr 7 | */ 8 | 9 | #ifndef RTRT_GLM_H 10 | #define RTRT_GLM_H 11 | 12 | 13 | /* includes */ 14 | 15 | /* defines */ 16 | #if 0 17 | #define GLM_NONE (0) /* render with only vertices */ 18 | #define GLM_FLAT (1 << 0) /* render with facet normals */ 19 | #define GLM_SMOOTH (1 << 1) /* render with vertex normals */ 20 | #define GLM_TEXTURE (1 << 2) /* render with texture coords */ 21 | #define GLM_COLOR (1 << 3) /* render with colors */ 22 | #define GLM_MATERIAL (1 << 4) /* render with materials */ 23 | #endif 24 | 25 | enum { 26 | GLM_NONE = (0), 27 | GLM_FLAT = (1 << 0), 28 | GLM_SMOOTH = (1 << 1), 29 | GLM_TEXTURE = (1 << 2), 30 | GLM_COLOR = (1 << 3), 31 | GLM_MATERIAL = (1 << 4), 32 | GLM_FLAT_SHADE = (1 << 5), 33 | GLM_SPECULAR_SHADE = (1 << 6) 34 | }; 35 | 36 | enum Sizes { 37 | MaxStringLength = 128 38 | }; 39 | 40 | /* structs */ 41 | 42 | /* GLMmaterial: Structure that defines a material in a model. 43 | */ 44 | typedef struct _GLMmaterial 45 | { 46 | char* name; /* name of material */ 47 | float diffuse[4]; // Kd diffuse component 48 | float ambient[4]; // Ka ambient component 49 | float specular[4]; // Ks specular component 50 | float emmissive[4]; // emmissive component 51 | float shininess; // Ns specular exponent 52 | float refraction; // Tr 53 | float alpha; // d 54 | float reflectivity; // reflection 55 | int shader; // illum 56 | 57 | // Texture maps, zero length if not specified. 58 | char ambient_map [MaxStringLength]; // map_Ka 59 | char diffuse_map [MaxStringLength]; // map_Kd 60 | char specular_map[MaxStringLength]; // map_Ks 61 | char dissolve_map[MaxStringLength]; // map_D 62 | 63 | // Scaling for texture maps (initialized to 0 for not set) 64 | float ambient_map_scaling[2]; 65 | float diffuse_map_scaling[2]; 66 | float specular_map_scaling[2]; 67 | float dissolve_map_scaling[2]; 68 | 69 | } GLMmaterial; 70 | 71 | /* GLMtriangle: Structure that defines a triangle in a model. 72 | */ 73 | typedef struct { 74 | unsigned int vindices[3]; /* array of triangle vertex indices */ 75 | unsigned int nindices[3]; /* array of triangle normal indices */ 76 | unsigned int tindices[3]; /* array of triangle texcoord indices*/ 77 | unsigned int findex; /* index of triangle facet normal */ 78 | } GLMtriangle; 79 | 80 | /* GLMgroup: Structure that defines a group in a model. 81 | */ 82 | typedef struct _GLMgroup { 83 | char* name; /* name of this group */ 84 | unsigned int numtriangles; /* number of triangles in this group */ 85 | unsigned int* triangles; /* array of triangle indices */ 86 | unsigned int material; /* index to material for group */ 87 | char* mtlname; /*name of the material for this group*/ 88 | struct _GLMgroup* next; /* pointer to next group in model */ 89 | } GLMgroup; 90 | 91 | /* GLMmodel: Structure that defines a model. 92 | */ 93 | typedef struct { 94 | char* pathname; /* path to this model */ 95 | char* mtllibname; /* name of the material library */ 96 | 97 | unsigned int numvertices; /* number of vertices in model */ 98 | float* vertices; /* array of vertices 99 | [x1,y1,z1,x2,y2,z2...] */ 100 | unsigned char* vertexColors; /* array of vertex colors */ 101 | 102 | unsigned int numnormals; /* number of normals in model */ 103 | float* normals; /* array of normals */ 104 | 105 | unsigned int numtexcoords; /* number of texcoords in model */ 106 | float* texcoords; /* array of texture coordinates */ 107 | 108 | unsigned int numfacetnorms; /* number of facetnorms in model */ 109 | float* facetnorms; /* array of facetnorms */ 110 | 111 | unsigned int numtriangles; /* number of triangles in model */ 112 | GLMtriangle* triangles; /* array of triangles */ 113 | 114 | unsigned int nummaterials; /* number of materials in model */ 115 | GLMmaterial* materials; /* array of materials */ 116 | 117 | /* This is the thing you will want to iterate over. Each group has 118 | an associated list of triangles, material, and name. */ 119 | unsigned int numgroups; /* number of groups in model */ 120 | GLMgroup* groups; /* linked list of groups */ 121 | 122 | float position[3]; /* position of the model */ 123 | 124 | bool usePerVertexColors; /* Are there per vertex colors? */ 125 | 126 | } GLMmodel; 127 | 128 | 129 | /* public functions */ 130 | 131 | /* glmUnitize: "unitize" a model by translating it to the origin and 132 | * scaling it to fit in a unit cube around the origin. Returns the 133 | * scalefactor used. 134 | * 135 | * model - properly initialized GLMmodel structure 136 | */ 137 | float 138 | glmUnitize(GLMmodel* model); 139 | 140 | /* 141 | * glmBoundingBox: Calculates the min/max positions of the model 142 | */ 143 | void 144 | glmBoundingBox(GLMmodel *model, float *minpos, float *maxpos); 145 | 146 | 147 | /* glmDimensions: Calculates the dimensions (width, height, depth) of 148 | * a model. 149 | * 150 | * model - initialized GLMmodel structure 151 | * dimensions - array of 3 floats (float dimensions[3]) 152 | */ 153 | void 154 | glmDimensions(GLMmodel* model, float* dimensions); 155 | 156 | /* glmScale: Scales a model by a given amount. 157 | * 158 | * model - properly initialized GLMmodel structure 159 | * scale - scalefactor (0.5 = half as large, 2.0 = twice as large) 160 | */ 161 | void 162 | glmScale(GLMmodel* model, float scale); 163 | 164 | /* glmReverseWinding: Reverse the polygon winding for all polygons in 165 | * this model. Default winding is counter-clockwise. Also changes 166 | * the direction of the normals. 167 | * 168 | * model - properly initialized GLMmodel structure 169 | */ 170 | void 171 | glmReverseWinding(GLMmodel* model); 172 | 173 | /* glmFacetNormals: Generates facet normals for a model (by taking the 174 | * cross product of the two vectors derived from the sides of each 175 | * triangle). Assumes a counter-clockwise winding. 176 | * 177 | * model - initialized GLMmodel structure 178 | */ 179 | void 180 | glmFacetNormals(GLMmodel* model); 181 | 182 | /* glmVertexNormals: Generates smooth vertex normals for a model. 183 | * First builds a list of all the triangles each vertex is in. Then 184 | * loops through each vertex in the the list averaging all the facet 185 | * normals of the triangles each vertex is in. Finally, sets the 186 | * normal index in the triangle for the vertex to the generated smooth 187 | * normal. If the dot product of a facet normal and the facet normal 188 | * associated with the first triangle in the list of triangles the 189 | * current vertex is in is greater than the cosine of the angle 190 | * parameter to the function, that facet normal is not added into the 191 | * average normal calculation and the corresponding vertex is given 192 | * the facet normal. This tends to preserve hard edges. The angle to 193 | * use depends on the model, but 90 degrees is usually a good start. 194 | * 195 | * model - initialized GLMmodel structure 196 | * angle - maximum angle (in degrees) to smooth across 197 | */ 198 | void 199 | glmVertexNormals(GLMmodel* model, float angle); 200 | 201 | /* glmLinearTexture: Generates texture coordinates according to a 202 | * linear projection of the texture map. It generates these by 203 | * linearly mapping the vertices onto a square. 204 | * 205 | * model - pointer to initialized GLMmodel structure 206 | */ 207 | void 208 | glmLinearTexture(GLMmodel* model); 209 | 210 | /* glmSpheremapTexture: Generates texture coordinates according to a 211 | * spherical projection of the texture map. Sometimes referred to as 212 | * spheremap, or reflection map texture coordinates. It generates 213 | * these by using the normal to calculate where that vertex would map 214 | * onto a sphere. Since it is impossible to map something flat 215 | * perfectly onto something spherical, there is distortion at the 216 | * poles. This particular implementation causes the poles along the X 217 | * axis to be distorted. 218 | * 219 | * model - pointer to initialized GLMmodel structure 220 | */ 221 | void 222 | glmSpheremapTexture(GLMmodel* model); 223 | 224 | /* glmDelete: Deletes a GLMmodel structure. 225 | * 226 | * model - initialized GLMmodel structure 227 | */ 228 | void 229 | glmDelete(GLMmodel* model); 230 | 231 | /* glmReadOBJ: Reads a model description from a Wavefront .OBJ file. 232 | * Returns a pointer to the created object which should be free'd with 233 | * glmDelete(). 234 | * 235 | * filename - name of the file containing the Wavefront .OBJ format data. 236 | * 237 | * returns 0 if there was a problem reading the file. 238 | */ 239 | GLMmodel* 240 | glmReadOBJ(const char* filename); 241 | 242 | /* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to 243 | * a file. 244 | * 245 | * model - initialized GLMmodel structure 246 | * filename - name of the file to write the Wavefront .OBJ format data to 247 | * mode - a bitwise or of values describing what is written to the file 248 | * GLM_NONE - write only vertices 249 | * GLM_FLAT - write facet normals 250 | * GLM_SMOOTH - write vertex normals 251 | * GLM_TEXTURE - write texture coords 252 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 253 | * 254 | * returns 1 if there was error, 0 otherwise. 255 | * 256 | */ 257 | int 258 | glmWriteOBJ(GLMmodel* model, char* filename, unsigned int mode); 259 | 260 | /* glmWeld: eliminate (weld) vectors that are within an epsilon of 261 | * each other. 262 | * 263 | * model - initialized GLMmodel structure 264 | * epsilon - maximum difference between vertices 265 | * ( 0.00001 is a good start for a unitized model) 266 | * 267 | */ 268 | void 269 | glmWeld(GLMmodel* model, float epsilon); 270 | 271 | 272 | #endif 273 | -------------------------------------------------------------------------------- /test/glm/glm.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * GLM library. Wavefront .obj file format reader/writer/manipulator. 3 | * 4 | * Written by Nate Robins, 1997. 5 | * email: ndr@pobox.com 6 | * www: http://www.pobox.com/~ndr 7 | */ 8 | 9 | /* includes */ 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | //#include 17 | #include 18 | 19 | #include 20 | 21 | #define M_PI 3.141592653589793238462643383279502884197169399375105820974944592 22 | 23 | /* defines */ 24 | #define T(x) model->triangles[(x)] 25 | 26 | static const char* default_group_name = "No Group"; 27 | static const char* default_material_name = "No Material"; 28 | 29 | 30 | /* enums */ 31 | enum { X, Y, Z, W }; /* elements of a vertex */ 32 | 33 | 34 | /* typedefs */ 35 | 36 | /* _GLMnode: general purpose node 37 | */ 38 | typedef struct _GLMnode { 39 | unsigned int index; 40 | bool averaged; 41 | struct _GLMnode* next; 42 | } GLMnode; 43 | 44 | 45 | /* private functions */ 46 | 47 | /* _glmMax: returns the maximum of two floats */ 48 | 49 | static float 50 | _glmMax(float a, float b) 51 | { 52 | if (a > b) 53 | return a; 54 | return b; 55 | } 56 | 57 | /* _glmAbs: returns the absolute value of a float */ 58 | static float 59 | _glmAbs(float f) 60 | { 61 | if (f < 0) 62 | return -f; 63 | return f; 64 | } 65 | 66 | /* _glmDot: compute the dot product of two vectors 67 | * 68 | * u - array of 3 floats (float u[3]) 69 | * v - array of 3 floats (float v[3]) 70 | */ 71 | static float 72 | _glmDot(float* u, float* v) 73 | { 74 | assert(u); 75 | assert(v); 76 | 77 | /* compute the dot product */ 78 | return u[X] * v[X] + u[Y] * v[Y] + u[Z] * v[Z]; 79 | } 80 | 81 | /* _glmCross: compute the cross product of two vectors 82 | * 83 | * u - array of 3 floats (float u[3]) 84 | * v - array of 3 floats (float v[3]) 85 | * n - array of 3 floats (float n[3]) to return the cross product in 86 | */ 87 | static void 88 | _glmCross(float* u, float* v, float* n) 89 | { 90 | assert(u); 91 | assert(v); 92 | assert(n); 93 | 94 | /* compute the cross product (u x v for right-handed [ccw]) */ 95 | n[X] = u[Y] * v[Z] - u[Z] * v[Y]; 96 | n[Y] = u[Z] * v[X] - u[X] * v[Z]; 97 | n[Z] = u[X] * v[Y] - u[Y] * v[X]; 98 | } 99 | 100 | /* _glmNormalize: normalize a vector 101 | * 102 | * n - array of 3 floats (float n[3]) to be normalized 103 | */ 104 | static void 105 | _glmNormalize(float* n) 106 | { 107 | float l; 108 | 109 | assert(n); 110 | 111 | /* normalize */ 112 | l = 1.0f/sqrtf(n[X] * n[X] + n[Y] * n[Y] + n[Z] * n[Z]); 113 | n[0] *= l; 114 | n[1] *= l; 115 | n[2] *= l; 116 | } 117 | 118 | /* _glmEqual: compares two vectors and returns true if they are 119 | * equal (within a certain threshold) or false if not. An epsilon 120 | * that works fairly well is 0.000001. 121 | * 122 | * u - array of 3 floats (float u[3]) 123 | * v - array of 3 floats (float v[3]) 124 | */ 125 | static bool 126 | _glmEqual(float* u, float* v, float epsilon) 127 | { 128 | if (_glmAbs(u[0] - v[0]) < epsilon && 129 | _glmAbs(u[1] - v[1]) < epsilon && 130 | _glmAbs(u[2] - v[2]) < epsilon) 131 | { 132 | return true; 133 | } 134 | return false; 135 | } 136 | 137 | /* _glmWeldVectors: eliminate (weld) vectors that are within an 138 | * epsilon of each other. 139 | * 140 | * vectors - array of float[3]'s to be welded 141 | * numvectors - number of float[3]'s in vectors 142 | * epsilon - maximum difference between vectors 143 | * 144 | */ 145 | static float* 146 | _glmWeldVectors(float* vectors, unsigned int* numvectors, float epsilon) 147 | { 148 | float* copies; 149 | unsigned int copied; 150 | unsigned int i, j; 151 | 152 | copies = (float*)malloc(sizeof(float) * 3 * (*numvectors + 1)); 153 | memcpy(copies, vectors, (sizeof(float) * 3 * (*numvectors + 1))); 154 | 155 | copied = 1; 156 | for (i = 1; i <= *numvectors; i++) { 157 | for (j = 1; j <= copied; j++) { 158 | if (_glmEqual(&vectors[3 * i], &copies[3 * j], epsilon)) { 159 | goto duplicate; 160 | } 161 | } 162 | 163 | /* must not be any duplicates -- add to the copies array */ 164 | copies[3 * copied + 0] = vectors[3 * i + 0]; 165 | copies[3 * copied + 1] = vectors[3 * i + 1]; 166 | copies[3 * copied + 2] = vectors[3 * i + 2]; 167 | j = copied; /* pass this along for below */ 168 | copied++; 169 | 170 | duplicate: 171 | /* set the first component of this vector to point at the correct 172 | index into the new copies array */ 173 | vectors[3 * i + 0] = (float)j; 174 | } 175 | 176 | *numvectors = copied-1; 177 | return copies; 178 | } 179 | 180 | /* _glmFindGroup: Find a group in the model 181 | */ 182 | static GLMgroup* 183 | _glmFindGroup(GLMmodel* model, char* name) 184 | { 185 | GLMgroup* group; 186 | 187 | assert(model); 188 | 189 | group = model->groups; 190 | while(group) { 191 | if (!strcmp(name, group->name)) 192 | break; 193 | group = group->next; 194 | } 195 | 196 | return group; 197 | } 198 | 199 | /* _glmAddGroup: Add a group to the model 200 | */ 201 | static GLMgroup* 202 | _glmAddGroup(GLMmodel* model, char* name) 203 | { 204 | GLMgroup* group; 205 | 206 | group = _glmFindGroup(model, name); 207 | if (!group) { 208 | group = (GLMgroup*)malloc(sizeof(GLMgroup)); 209 | group->name = strdup(name); 210 | group->material = 0; 211 | group->mtlname = 0; 212 | group->numtriangles = 0; 213 | group->triangles = NULL; 214 | group->next = model->groups; 215 | model->groups = group; 216 | model->numgroups++; 217 | } 218 | 219 | 220 | return group; 221 | } 222 | 223 | /* _glmFindGroup: Find a material in the model 224 | */ 225 | static unsigned int 226 | _glmFindMaterial(GLMmodel* model, char* name) 227 | { 228 | unsigned int i; 229 | 230 | for (i = 0; i < model->nummaterials; i++) { 231 | if (model->materials[i].name && !strcmp(model->materials[i].name, name)) 232 | goto found; 233 | } 234 | 235 | /* didn't find the name, so set it as the default material */ 236 | /* printf("_glmFindMaterial(): can't find material \"%s\".\n", name); */ 237 | i = 0; 238 | 239 | found: 240 | return i; 241 | } 242 | 243 | 244 | /* _glmDirName: return the directory given a path 245 | * 246 | * path - filesystem path 247 | * 248 | * The return value should be free'd. 249 | */ 250 | static char* 251 | _glmDirName(char* path) 252 | { 253 | char* dir; 254 | char* s; 255 | 256 | dir = strdup(path); 257 | 258 | s = strrchr(dir, '/'); 259 | if (s) 260 | s[1] = '\0'; 261 | else 262 | dir[0] = '\0'; 263 | 264 | return dir; 265 | } 266 | 267 | 268 | /* _glmReadMTL: read a wavefront material library file 269 | * 270 | * model - properly initialized GLMmodel structure 271 | * name - name of the material library 272 | */ 273 | static int 274 | _glmReadMTL(GLMmodel* model, char* name) 275 | { 276 | FILE* file; 277 | char* dir; 278 | char* filename; 279 | char buf[2048]; 280 | unsigned int nummaterials, i; 281 | 282 | dir = _glmDirName(model->pathname); 283 | filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(name) + 1)); 284 | strcpy(filename, dir); 285 | strcat(filename, name); 286 | free(dir); 287 | 288 | /* open the file */ 289 | file = fopen(filename, "r"); 290 | if (!file) { 291 | fprintf(stderr, "_glmReadMTL() failed: can't open material file \"%s\".\n", 292 | filename); 293 | free(filename); 294 | return 1; 295 | } 296 | free(filename); 297 | 298 | /* count the number of materials in the file */ 299 | nummaterials = 1; 300 | while(fscanf(file, "%s", buf) != EOF) { 301 | switch(buf[0]) { 302 | case '#': /* comment */ 303 | /* eat up rest of line */ 304 | fgets(buf, sizeof(buf), file); 305 | break; 306 | case 'n': /* newmtl */ 307 | fgets(buf, sizeof(buf), file); 308 | nummaterials++; 309 | sscanf(buf, "%s %s", buf, buf); 310 | break; 311 | default: 312 | /* eat up rest of line */ 313 | fgets(buf, sizeof(buf), file); 314 | break; 315 | } 316 | } 317 | 318 | rewind(file); 319 | 320 | /* allocate memory for the materials */ 321 | model->materials = (GLMmaterial*)malloc(sizeof(GLMmaterial) * nummaterials); 322 | model->nummaterials = nummaterials; 323 | 324 | /* set the default material */ 325 | for (i = 0; i < nummaterials; i++) { 326 | model->materials[i].name = NULL; 327 | model->materials[i].shininess = 0; 328 | model->materials[i].refraction = 1; 329 | model->materials[i].alpha = 1; 330 | model->materials[i].shader = GLM_FLAT_SHADE; 331 | model->materials[i].reflectivity = 0; 332 | 333 | model->materials[i].diffuse[0] = 0.7f; 334 | model->materials[i].diffuse[1] = 0.7f; 335 | model->materials[i].diffuse[2] = 0.7f; 336 | model->materials[i].diffuse[3] = 1.0f; 337 | model->materials[i].ambient[0] = 0.2f; 338 | model->materials[i].ambient[1] = 0.2f; 339 | model->materials[i].ambient[2] = 0.2f; 340 | model->materials[i].ambient[3] = 1.0f; 341 | model->materials[i].specular[0] = 0.0f; 342 | model->materials[i].specular[1] = 0.0f; 343 | model->materials[i].specular[2] = 0.0f; 344 | model->materials[i].specular[3] = 1.0f; 345 | model->materials[i].emmissive[0] = 0.0f; 346 | model->materials[i].emmissive[1] = 0.0f; 347 | model->materials[i].emmissive[2] = 0.0f; 348 | model->materials[i].emmissive[3] = 1.0f; 349 | 350 | model->materials[i].ambient_map[0] = '\0'; 351 | model->materials[i].diffuse_map[0] = '\0'; 352 | model->materials[i].specular_map[0] = '\0'; 353 | model->materials[i].dissolve_map[0] = '\0'; 354 | 355 | model->materials[i].ambient_map_scaling[0] = 0; 356 | model->materials[i].ambient_map_scaling[1] = 0; 357 | model->materials[i].diffuse_map_scaling[0] = 0; 358 | model->materials[i].diffuse_map_scaling[1] = 0; 359 | model->materials[i].specular_map_scaling[0] = 0; 360 | model->materials[i].specular_map_scaling[1] = 0; 361 | model->materials[i].dissolve_map_scaling[0] = 0; 362 | model->materials[i].dissolve_map_scaling[1] = 0; 363 | } 364 | model->materials[0].name = strdup("NO_ASSIGNED_MATERIAL"); 365 | 366 | /* now, read in the data */ 367 | nummaterials = 0; 368 | while(fscanf(file, "%s", buf) != EOF) { 369 | switch(buf[0]) { 370 | case '#': /* comment */ 371 | /* eat up rest of line */ 372 | fgets(buf, sizeof(buf), file); 373 | break; 374 | case 'n': /* newmtl */ 375 | 376 | // Make sure the previous material has a name. 377 | assert( model->materials[nummaterials].name ); 378 | 379 | // Read in the new material name. 380 | fgets(buf, sizeof(buf), file); 381 | sscanf(buf, "%s %s", buf, buf); 382 | nummaterials++; 383 | model->materials[nummaterials].name = strdup(buf); 384 | break; 385 | case 'N': 386 | fscanf(file, "%f", &model->materials[nummaterials].shininess); 387 | break; 388 | case 'T': // Tr 389 | fscanf(file, "%f", &model->materials[nummaterials].refraction); 390 | break; 391 | case 'd': // d 392 | fscanf(file, "%f", &model->materials[nummaterials].alpha); 393 | break; 394 | case 'i': // illum 395 | fscanf(file, "%d", &model->materials[nummaterials].shader); 396 | break; 397 | case 'r': // reflectivity 398 | fscanf(file, "%f", &model->materials[nummaterials].reflectivity); 399 | break; 400 | case 'R': // reflectivity 401 | float r[3]; 402 | fscanf(file, "%f %f %f", r, r+1, r+2); 403 | model->materials[nummaterials].reflectivity = (r[0]+r[1]+r[2]) / 3.0f; 404 | break; 405 | case 'm': 406 | { 407 | char* map_name = 0; 408 | float* scaling = 0; 409 | // Determine which type of map. 410 | if (strcmp(buf,"map_Ka")==0) { 411 | map_name = model->materials[nummaterials].ambient_map; 412 | scaling = model->materials[nummaterials].ambient_map_scaling; 413 | } else if (strcmp(buf,"map_Kd")==0) { 414 | map_name = model->materials[nummaterials].diffuse_map; 415 | scaling = model->materials[nummaterials].diffuse_map_scaling; 416 | } else if (strcmp(buf,"map_Ks")==0) { 417 | map_name = model->materials[nummaterials].specular_map; 418 | scaling = model->materials[nummaterials].ambient_map_scaling; 419 | } else if (strcmp(buf,"map_D")==0) { 420 | map_name = model->materials[nummaterials].dissolve_map; 421 | scaling = model->materials[nummaterials].dissolve_map_scaling; 422 | } else { 423 | // We don't know what kind of map it is, so ignore it 424 | fprintf(stderr, "Unknown map: \"%s\" found at %s(%d)\n", buf, 425 | __FILE__, __LINE__); 426 | break; 427 | } 428 | 429 | char string_litteral[2048]; 430 | sprintf(string_litteral, "%%%ds", (int)MaxStringLength-1); 431 | //fprintf(stderr, "string_litteral = %s\n", string_litteral); 432 | 433 | // Check to see if we have scaled textures or not 434 | fscanf(file, string_litteral, map_name); 435 | if (strcmp(map_name, "-s") == 0) { 436 | // pick up the float scaled textures 437 | fscanf(file, "%f %f", &scaling[0], &scaling[1]); 438 | // Now the name of the file 439 | fscanf(file, string_litteral, map_name); 440 | //fprintf(stderr, " scale = %f %f ,", scaling[0], scaling[1]); 441 | } 442 | //fprintf(stderr, "name = %s\n", map_name); 443 | } // end case 'm' 444 | break; 445 | 446 | case 'K': 447 | switch(buf[1]) { 448 | case 'd': 449 | fscanf(file, "%f %f %f", 450 | &model->materials[nummaterials].diffuse[0], 451 | &model->materials[nummaterials].diffuse[1], 452 | &model->materials[nummaterials].diffuse[2]); 453 | break; 454 | case 's': 455 | fscanf(file, "%f %f %f", 456 | &model->materials[nummaterials].specular[0], 457 | &model->materials[nummaterials].specular[1], 458 | &model->materials[nummaterials].specular[2]); 459 | break; 460 | case 'a': 461 | fscanf(file, "%f %f %f", 462 | &model->materials[nummaterials].ambient[0], 463 | &model->materials[nummaterials].ambient[1], 464 | &model->materials[nummaterials].ambient[2]); 465 | break; 466 | default: 467 | /* eat up rest of line */ 468 | fgets(buf, sizeof(buf), file); 469 | break; 470 | } 471 | break; 472 | default: 473 | /* eat up rest of line */ 474 | fgets(buf, sizeof(buf), file); 475 | break; 476 | } 477 | } 478 | 479 | // Make sure we found the same number of materials the second time around. 480 | // Note that glm adds a default material to the beginning of the array 481 | assert((nummaterials+1) == model->nummaterials); 482 | 483 | fclose( file ); 484 | 485 | return 0; 486 | } 487 | 488 | /* _glmWriteMTL: write a wavefront material library file 489 | * 490 | * model - properly initialized GLMmodel structure 491 | * modelpath - pathname of the model being written 492 | * mtllibname - name of the material library to be written 493 | */ 494 | static int 495 | _glmWriteMTL(GLMmodel* model, char* modelpath, char* mtllibname) 496 | { 497 | FILE* file; 498 | char* dir; 499 | char* filename; 500 | GLMmaterial* material; 501 | unsigned int i; 502 | 503 | dir = _glmDirName(modelpath); 504 | filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(mtllibname))); 505 | strcpy(filename, dir); 506 | strcat(filename, mtllibname); 507 | free(dir); 508 | 509 | /* open the file */ 510 | file = fopen(filename, "w"); 511 | if (!file) { 512 | fprintf(stderr, "_glmWriteMTL() failed: can't open file \"%s\".\n", 513 | filename); 514 | free(filename); 515 | return 1; 516 | } 517 | free(filename); 518 | 519 | /* spit out a header */ 520 | fprintf(file, "# \n"); 521 | fprintf(file, "# Wavefront MTL generated by GLM library\n"); 522 | fprintf(file, "# \n"); 523 | fprintf(file, "# GLM library copyright (C) 1997 by Nate Robins\n"); 524 | fprintf(file, "# email: ndr@pobox.com\n"); 525 | fprintf(file, "# www: http://www.pobox.com/~ndr\n"); 526 | fprintf(file, "# \n\n"); 527 | 528 | for (i = 0; i < model->nummaterials; i++) { 529 | material = &model->materials[i]; 530 | fprintf(file, "newmtl %s\n", material->name); 531 | fprintf(file, "Ka %f %f %f\n", 532 | material->ambient[0], material->ambient[1], material->ambient[2]); 533 | fprintf(file, "Kd %f %f %f\n", 534 | material->diffuse[0], material->diffuse[1], material->diffuse[2]); 535 | fprintf(file, "Ks %f %f %f\n", 536 | material->specular[0],material->specular[1],material->specular[2]); 537 | fprintf(file, "Ns %f\n", material->shininess); 538 | fprintf(file, "\n"); 539 | } 540 | return 0; 541 | } 542 | 543 | /* _glmFirstPass: first pass at a Wavefront OBJ file that gets all the 544 | * statistics of the model (such as #vertices, #normals, etc) 545 | * 546 | * model - properly initialized GLMmodel structure 547 | * file - (fopen'd) file descriptor 548 | */ 549 | static int 550 | _glmFirstPass(GLMmodel* model, FILE* file) 551 | { 552 | unsigned int numvertices; /* number of vertices in model */ 553 | unsigned int numnormals; /* number of normals in model */ 554 | unsigned int numtexcoords; /* number of texcoords in model */ 555 | unsigned int numtriangles; /* number of triangles in model */ 556 | 557 | 558 | 559 | GLMgroup* group; /* current group */ 560 | char* current_group_base_name = strdup(default_group_name); 561 | char* current_material_name = strdup(default_material_name); 562 | int v, n, t; 563 | char buf[2048]; 564 | 565 | /* make a default group */ 566 | group = _glmAddGroup(model, current_group_base_name); 567 | 568 | numvertices = numnormals = numtexcoords = numtriangles = 0; 569 | 570 | while(fscanf(file, "%s", buf) != EOF) { 571 | switch(buf[0]) { 572 | case '#': /* comment */ 573 | /* eat up rest of line */ 574 | fgets(buf, sizeof(buf), file); 575 | break; 576 | case 'v': /* v, vn, vt */ 577 | switch(buf[1]) { 578 | case '\0': { /* vertex */ 579 | /* eat up rest of line */ 580 | fgets(buf, sizeof(buf), file); 581 | 582 | // TODO: Check if colors for this vertex 583 | float vx,vy,vz; 584 | int val = -1; 585 | sscanf(buf,"%f %f %f %d",&vx, &vy, &vz, &val); 586 | if (val >= 0) { 587 | model->usePerVertexColors = true; 588 | } 589 | 590 | numvertices++; 591 | break; 592 | } 593 | case 'n': /* normal */ 594 | /* eat up rest of line */ 595 | fgets(buf, sizeof(buf), file); 596 | numnormals++; 597 | break; 598 | case 't': /* texcoord */ 599 | /* eat up rest of line */ 600 | fgets(buf, sizeof(buf), file); 601 | numtexcoords++; 602 | break; 603 | default: 604 | printf("_glmFirstPass(): Unknown token \"%s\".\n", buf); 605 | /* Could error out here, but we'll just skip it for now.*/ 606 | /* return 1; */ 607 | break; 608 | } 609 | break; 610 | case 'm': 611 | fgets(buf, sizeof(buf), file); 612 | sscanf(buf, "%s %s", buf, buf); 613 | model->mtllibname = strdup(buf); 614 | if (_glmReadMTL(model, buf)) { 615 | 616 | break; /* Dont bail if MTL file not found */ 617 | 618 | /* Uh oh. Trouble reading in the material file. */ 619 | if (current_group_base_name) free(current_group_base_name); 620 | if (current_material_name) free(current_material_name); 621 | return 1; 622 | } 623 | break; 624 | case 'u': 625 | /* We need to create groups with their own materials */ 626 | fgets(buf, sizeof(buf), file); 627 | sscanf(buf, "%s %s", buf, buf); 628 | if (current_material_name) free(current_material_name); 629 | current_material_name = strdup(buf); 630 | sprintf(buf, "%s_MAT_%s", 631 | current_group_base_name, current_material_name); 632 | group = _glmAddGroup(model, buf); 633 | break; 634 | case 'o': 635 | case 'g': /* group */ 636 | fgets(buf, sizeof(buf), file); 637 | sscanf(buf, "%s", buf); 638 | if (current_group_base_name) free(current_group_base_name); 639 | current_group_base_name = strdup(buf); 640 | sprintf(buf, "%s_MAT_%s", 641 | current_group_base_name, current_material_name); 642 | group = _glmAddGroup(model, buf); 643 | break; 644 | case 'f': /* face */ 645 | v = n = t = 0; 646 | fscanf(file, "%s", buf); 647 | /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */ 648 | if (strstr(buf, "//")) { 649 | /* v//n */ 650 | sscanf(buf, "%d//%d", &v, &n); 651 | fscanf(file, "%d//%d", &v, &n); 652 | fscanf(file, "%d//%d", &v, &n); 653 | numtriangles++; 654 | group->numtriangles++; 655 | while(fscanf(file, "%d//%d", &v, &n) > 0) { 656 | numtriangles++; 657 | group->numtriangles++; 658 | } 659 | } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) { 660 | /* v/t/n */ 661 | fscanf(file, "%d/%d/%d", &v, &t, &n); 662 | fscanf(file, "%d/%d/%d", &v, &t, &n); 663 | numtriangles++; 664 | group->numtriangles++; 665 | while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) { 666 | numtriangles++; 667 | group->numtriangles++; 668 | } 669 | } else if (sscanf(buf, "%d/%d", &v, &t) == 2) { 670 | /* v/t */ 671 | fscanf(file, "%d/%d", &v, &t); 672 | fscanf(file, "%d/%d", &v, &t); 673 | numtriangles++; 674 | group->numtriangles++; 675 | while(fscanf(file, "%d/%d", &v, &t) > 0) { 676 | numtriangles++; 677 | group->numtriangles++; 678 | } 679 | } else { 680 | /* v */ 681 | fscanf(file, "%d", &v); 682 | fscanf(file, "%d", &v); 683 | numtriangles++; 684 | group->numtriangles++; 685 | while(fscanf(file, "%d", &v) > 0) { 686 | numtriangles++; 687 | group->numtriangles++; 688 | } 689 | } 690 | break; 691 | 692 | default: 693 | /* eat up rest of line */ 694 | fgets(buf, sizeof(buf), file); 695 | break; 696 | } 697 | } 698 | 699 | // #if 0 700 | /* announce the model statistics */ 701 | // printf(" Vertices: %d\n", numvertices); 702 | // printf(" Normals: %d\n", numnormals); 703 | // printf(" Texcoords: %d\n", numtexcoords); 704 | // printf(" Triangles: %d\n", numtriangles); 705 | // printf(" Groups: %d\n", model->numgroups); 706 | // #endif 707 | 708 | /* set the stats in the model structure */ 709 | model->numvertices = numvertices; 710 | model->numnormals = numnormals; 711 | model->numtexcoords = numtexcoords; 712 | model->numtriangles = numtriangles; 713 | 714 | /* allocate memory for the triangles in each group */ 715 | group = model->groups; 716 | while(group) { 717 | group->triangles = (unsigned int*)malloc(sizeof(unsigned int) * group->numtriangles); 718 | group->numtriangles = 0; 719 | group = group->next; 720 | } 721 | 722 | if (current_group_base_name) free(current_group_base_name); 723 | if (current_material_name) free(current_material_name); 724 | return 0; 725 | } 726 | 727 | /* _glmSecondPass: second pass at a Wavefront OBJ file that gets all 728 | * the data. 729 | * 730 | * model - properly initialized GLMmodel structure 731 | * file - (fopen'd) file descriptor 732 | */ 733 | static void 734 | _glmSecondPass(GLMmodel* model, FILE* file) 735 | { 736 | unsigned int numvertices; /* number of vertices in model */ 737 | unsigned int numnormals; /* number of normals in model */ 738 | unsigned int numtexcoords; /* number of texcoords in model */ 739 | unsigned int numtriangles; /* number of triangles in model */ 740 | float* vertices; /* array of vertices */ 741 | unsigned char* vertexColors; /* array of vertex colors */ 742 | float* normals; /* array of normals */ 743 | float* texcoords; /* array of texture coordinates */ 744 | GLMgroup* group; /* current group pointer */ 745 | unsigned int material; /* current material */ 746 | char* grpname; /* current group base name */ 747 | char* mtlname; /* current material name */ 748 | int v, n, t; 749 | char buf[2048]; 750 | 751 | /* set the pointer shortcuts */ 752 | vertices = model->vertices; 753 | vertexColors = model->vertexColors; 754 | normals = model->normals; 755 | texcoords = model->texcoords; 756 | group = model->groups; 757 | 758 | /* on the second pass through the file, read all the data into the 759 | allocated arrays */ 760 | numvertices = numnormals = numtexcoords = 1; 761 | numtriangles = 0; 762 | material = 0; 763 | grpname = strdup(default_group_name); 764 | mtlname = strdup(default_material_name); 765 | while(fscanf(file, "%s", buf) != EOF) { 766 | switch(buf[0]) { 767 | case '#': /* comment */ 768 | /* eat up rest of line */ 769 | fgets(buf, sizeof(buf), file); 770 | break; 771 | case 'v': /* v, vn, vt */ 772 | switch(buf[1]) { 773 | case '\0': /* vertex */ 774 | if (!model->usePerVertexColors) { 775 | fscanf(file, "%f %f %f", 776 | &vertices[3 * numvertices + X], 777 | &vertices[3 * numvertices + Y], 778 | &vertices[3 * numvertices + Z]); 779 | } 780 | else { 781 | int r,g,b; 782 | fscanf(file, "%f %f %f %d %d %d", 783 | &vertices[3 * numvertices + X], 784 | &vertices[3 * numvertices + Y], 785 | &vertices[3 * numvertices + Z], &r, &g, &b); 786 | vertexColors[3 * numvertices + X] = (unsigned char)r; 787 | vertexColors[3 * numvertices + Y] = (unsigned char)g; 788 | vertexColors[3 * numvertices + Z] = (unsigned char)b; 789 | } 790 | numvertices++; 791 | break; 792 | case 'n': /* normal */ 793 | fscanf(file, "%f %f %f", 794 | &normals[3 * numnormals + X], 795 | &normals[3 * numnormals + Y], 796 | &normals[3 * numnormals + Z]); 797 | numnormals++; 798 | break; 799 | case 't': /* texcoord */ 800 | fscanf(file, "%f %f", 801 | &texcoords[2 * numtexcoords + X], 802 | &texcoords[2 * numtexcoords + Y]); 803 | numtexcoords++; 804 | break; 805 | } 806 | break; 807 | case 'u': // usemtl 808 | fgets(buf, sizeof(buf), file); 809 | sscanf(buf, "%s %s", buf, buf); 810 | if (mtlname) free(mtlname); 811 | mtlname = strdup(buf); 812 | material = _glmFindMaterial(model, buf); 813 | sprintf(buf, "%s_MAT_%s", 814 | grpname, mtlname); 815 | group = _glmFindGroup(model, buf); 816 | group->material = material; 817 | group->mtlname = strdup(mtlname); 818 | break; 819 | case 'o': 820 | case 'g': /* group */ 821 | /* eat up rest of line */ 822 | fgets(buf, sizeof(buf), file); 823 | sscanf(buf, "%s", buf); 824 | if (grpname) free(grpname); 825 | grpname = strdup(buf); 826 | sprintf(buf, "%s_MAT_%s", 827 | grpname, mtlname); 828 | group = _glmFindGroup(model, buf); 829 | group->material = material; 830 | group->mtlname = strdup(mtlname); 831 | break; 832 | case 'f': /* face */ 833 | v = n = t = 0; 834 | fscanf(file, "%s", buf); 835 | /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */ 836 | if (strstr(buf, "//")) { 837 | /* v//n */ 838 | sscanf(buf, "%d//%d", &v, &n); 839 | T(numtriangles).vindices[0] = (v >= 0) ? v : (numvertices + v); 840 | T(numtriangles).nindices[0] = n; 841 | T(numtriangles).tindices[0] = 0; 842 | fscanf(file, "%d//%d", &v, &n); 843 | T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v); 844 | T(numtriangles).nindices[1] = n; 845 | T(numtriangles).tindices[1] = 0; 846 | fscanf(file, "%d//%d", &v, &n); 847 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 848 | T(numtriangles).nindices[2] = n; 849 | T(numtriangles).tindices[2] = 0; 850 | group->triangles[group->numtriangles++] = numtriangles; 851 | numtriangles++; 852 | while(fscanf(file, "%d//%d", &v, &n) > 0) { 853 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 854 | T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0]; 855 | T(numtriangles).tindices[0] = 0; 856 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 857 | T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2]; 858 | T(numtriangles).tindices[1] = 0; 859 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 860 | T(numtriangles).nindices[2] = n; 861 | T(numtriangles).tindices[2] = 0; 862 | group->triangles[group->numtriangles++] = numtriangles; 863 | numtriangles++; 864 | } 865 | } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) { 866 | /* v/t/n */ 867 | T(numtriangles).vindices[0] = (v >= 0) ? v : (numvertices + v); 868 | T(numtriangles).nindices[0] = n; 869 | T(numtriangles).tindices[0] = t; 870 | fscanf(file, "%d/%d/%d", &v, &t, &n); 871 | T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v); 872 | T(numtriangles).nindices[1] = n; 873 | T(numtriangles).tindices[1] = t; 874 | fscanf(file, "%d/%d/%d", &v, &t, &n); 875 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 876 | T(numtriangles).nindices[2] = n; 877 | T(numtriangles).tindices[2] = t; 878 | group->triangles[group->numtriangles++] = numtriangles; 879 | numtriangles++; 880 | while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) { 881 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 882 | T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0]; 883 | T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0]; 884 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 885 | T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2]; 886 | T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2]; 887 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 888 | T(numtriangles).nindices[2] = n; 889 | T(numtriangles).tindices[2] = t; 890 | group->triangles[group->numtriangles++] = numtriangles; 891 | numtriangles++; 892 | } 893 | } else if (sscanf(buf, "%d/%d", &v, &t) == 2) { 894 | /* v/t */ 895 | T(numtriangles).vindices[0] = (v >= 0) ? v : (numvertices + v); 896 | T(numtriangles).nindices[0] = 0; 897 | T(numtriangles).tindices[0] = t; 898 | fscanf(file, "%d/%d", &v, &t); 899 | T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v); 900 | T(numtriangles).nindices[1] = 0; 901 | T(numtriangles).tindices[1] = t; 902 | fscanf(file, "%d/%d", &v, &t); 903 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 904 | T(numtriangles).nindices[2] = 0; 905 | T(numtriangles).tindices[2] = t; 906 | group->triangles[group->numtriangles++] = numtriangles; 907 | numtriangles++; 908 | while(fscanf(file, "%d/%d", &v, &t) > 0) { 909 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 910 | T(numtriangles).nindices[0] = 0; 911 | T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0]; 912 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 913 | T(numtriangles).nindices[1] = 0; 914 | T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2]; 915 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 916 | T(numtriangles).nindices[2] = 0; 917 | T(numtriangles).tindices[2] = t; 918 | group->triangles[group->numtriangles++] = numtriangles; 919 | numtriangles++; 920 | } 921 | } else { 922 | /* v */ 923 | sscanf(buf, "%d", &v); 924 | T(numtriangles).vindices[0] = (v >= 0) ? v : (numvertices + v); 925 | T(numtriangles).nindices[0] = 0; 926 | T(numtriangles).tindices[0] = 0; 927 | fscanf(file, "%d", &v); 928 | T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v); 929 | T(numtriangles).nindices[1] = 0; 930 | T(numtriangles).tindices[1] = 0; 931 | fscanf(file, "%d", &v); 932 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 933 | T(numtriangles).nindices[2] = 0; 934 | T(numtriangles).tindices[2] = 0; 935 | group->triangles[group->numtriangles++] = numtriangles; 936 | numtriangles++; 937 | while(fscanf(file, "%d", &v) > 0) { 938 | T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0]; 939 | T(numtriangles).nindices[0] = 0; 940 | T(numtriangles).tindices[0] = 0; 941 | T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2]; 942 | T(numtriangles).nindices[1] = 0; 943 | T(numtriangles).tindices[1] = 0; 944 | T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v); 945 | T(numtriangles).nindices[2] = 0; 946 | T(numtriangles).tindices[2] = 0; 947 | group->triangles[group->numtriangles++] = numtriangles; 948 | numtriangles++; 949 | } 950 | } 951 | break; 952 | 953 | default: 954 | /* eat up rest of line */ 955 | fgets(buf, sizeof(buf), file); 956 | break; 957 | } 958 | } 959 | 960 | #if 0 961 | /* announce the memory requirements */ 962 | printf(" Memory: %d bytes\n", 963 | numvertices * 3*sizeof(float) + 964 | numnormals * 3*sizeof(float) * (numnormals ? 1 : 0) + 965 | numtexcoords * 3*sizeof(float) * (numtexcoords ? 1 : 0) + 966 | numtriangles * sizeof(GLMtriangle)); 967 | #endif 968 | if (grpname) free(grpname); 969 | if (mtlname) free(mtlname); 970 | } 971 | 972 | 973 | 974 | 975 | /* public functions */ 976 | 977 | /* glmUnitize: "unitize" a model by translating it to the origin and 978 | * scaling it to fit in a unit cube around the origin. Returns the 979 | * scalefactor used. 980 | * 981 | * model - properly initialized GLMmodel structure 982 | */ 983 | float 984 | glmUnitize(GLMmodel* model) 985 | { 986 | unsigned int i; 987 | float maxx, minx, maxy, miny, maxz, minz; 988 | float cx, cy, cz, w, h, d; 989 | float scale; 990 | 991 | assert(model); 992 | assert(model->vertices); 993 | 994 | /* get the max/mins */ 995 | maxx = minx = model->vertices[3 + X]; 996 | maxy = miny = model->vertices[3 + Y]; 997 | maxz = minz = model->vertices[3 + Z]; 998 | for (i = 1; i <= model->numvertices; i++) { 999 | if (maxx < model->vertices[3 * i + X]) 1000 | maxx = model->vertices[3 * i + X]; 1001 | if (minx > model->vertices[3 * i + X]) 1002 | minx = model->vertices[3 * i + X]; 1003 | 1004 | if (maxy < model->vertices[3 * i + Y]) 1005 | maxy = model->vertices[3 * i + Y]; 1006 | if (miny > model->vertices[3 * i + Y]) 1007 | miny = model->vertices[3 * i + Y]; 1008 | 1009 | if (maxz < model->vertices[3 * i + Z]) 1010 | maxz = model->vertices[3 * i + Z]; 1011 | if (minz > model->vertices[3 * i + Z]) 1012 | minz = model->vertices[3 * i + Z]; 1013 | } 1014 | 1015 | /* calculate model width, height, and depth */ 1016 | w = _glmAbs(maxx) + _glmAbs(minx); 1017 | h = _glmAbs(maxy) + _glmAbs(miny); 1018 | d = _glmAbs(maxz) + _glmAbs(minz); 1019 | 1020 | /* calculate center of the model */ 1021 | cx = (maxx + minx) / 2.0f; 1022 | cy = (maxy + miny) / 2.0f; 1023 | cz = (maxz + minz) / 2.0f; 1024 | 1025 | /* calculate unitizing scale factor */ 1026 | scale = 2.0f / _glmMax(_glmMax(w, h), d); 1027 | 1028 | /* translate around center then scale */ 1029 | for (i = 1; i <= model->numvertices; i++) { 1030 | model->vertices[3 * i + X] -= cx; 1031 | model->vertices[3 * i + Y] -= cy; 1032 | model->vertices[3 * i + Z] -= cz; 1033 | model->vertices[3 * i + X] *= scale; 1034 | model->vertices[3 * i + Y] *= scale; 1035 | model->vertices[3 * i + Z] *= scale; 1036 | } 1037 | 1038 | return scale; 1039 | } 1040 | 1041 | /* glmDimensions: Calculates the dimensions (width, height, depth) of 1042 | * a model. 1043 | * 1044 | * model - initialized GLMmodel structure 1045 | * dimensions - array of 3 floats (float dimensions[3]) 1046 | */ 1047 | void 1048 | glmDimensions(GLMmodel* model, float* dimensions) 1049 | { 1050 | unsigned int i; 1051 | float maxx, minx, maxy, miny, maxz, minz; 1052 | 1053 | assert(model); 1054 | assert(model->vertices); 1055 | assert(dimensions); 1056 | 1057 | /* get the max/mins */ 1058 | maxx = minx = model->vertices[3 + X]; 1059 | maxy = miny = model->vertices[3 + Y]; 1060 | maxz = minz = model->vertices[3 + Z]; 1061 | for (i = 1; i <= model->numvertices; i++) { 1062 | if (maxx < model->vertices[3 * i + X]) 1063 | maxx = model->vertices[3 * i + X]; 1064 | if (minx > model->vertices[3 * i + X]) 1065 | minx = model->vertices[3 * i + X]; 1066 | 1067 | if (maxy < model->vertices[3 * i + Y]) 1068 | maxy = model->vertices[3 * i + Y]; 1069 | if (miny > model->vertices[3 * i + Y]) 1070 | miny = model->vertices[3 * i + Y]; 1071 | 1072 | if (maxz < model->vertices[3 * i + Z]) 1073 | maxz = model->vertices[3 * i + Z]; 1074 | if (minz > model->vertices[3 * i + Z]) 1075 | minz = model->vertices[3 * i + Z]; 1076 | } 1077 | 1078 | /* calculate model width, height, and depth */ 1079 | dimensions[X] = _glmAbs(maxx) + _glmAbs(minx); 1080 | dimensions[Y] = _glmAbs(maxy) + _glmAbs(miny); 1081 | dimensions[Z] = _glmAbs(maxz) + _glmAbs(minz); 1082 | } 1083 | 1084 | /* 1085 | * glmBoundingBox: Calculates the min/max positions of the model 1086 | */ 1087 | void 1088 | glmBoundingBox(GLMmodel *model, float *minpos, float *maxpos) 1089 | { 1090 | unsigned int i; 1091 | float maxx, minx, maxy, miny, maxz, minz; 1092 | 1093 | assert(model); 1094 | assert(model->vertices); 1095 | assert(minpos); 1096 | assert(maxpos); 1097 | 1098 | /* get the max/mins */ 1099 | maxx = minx = model->vertices[3 + X]; 1100 | maxy = miny = model->vertices[3 + Y]; 1101 | maxz = minz = model->vertices[3 + Z]; 1102 | for (i = 1; i <= model->numvertices; i++) { 1103 | if (maxx < model->vertices[3 * i + X]) 1104 | maxx = model->vertices[3 * i + X]; 1105 | if (minx > model->vertices[3 * i + X]) 1106 | minx = model->vertices[3 * i + X]; 1107 | 1108 | if (maxy < model->vertices[3 * i + Y]) 1109 | maxy = model->vertices[3 * i + Y]; 1110 | if (miny > model->vertices[3 * i + Y]) 1111 | miny = model->vertices[3 * i + Y]; 1112 | 1113 | if (maxz < model->vertices[3 * i + Z]) 1114 | maxz = model->vertices[3 * i + Z]; 1115 | if (minz > model->vertices[3 * i + Z]) 1116 | minz = model->vertices[3 * i + Z]; 1117 | } 1118 | 1119 | minpos[0] = minx; 1120 | minpos[1] = miny; 1121 | minpos[2] = minz; 1122 | maxpos[0] = maxx; 1123 | maxpos[1] = maxy; 1124 | maxpos[2] = maxz; 1125 | 1126 | } 1127 | 1128 | /* glmScale: Scales a model by a given amount. 1129 | * 1130 | * model - properly initialized GLMmodel structure 1131 | * scale - scalefactor (0.5 = half as large, 2.0 = twice as large) 1132 | */ 1133 | void 1134 | glmScale(GLMmodel* model, float scale) 1135 | { 1136 | unsigned int i; 1137 | 1138 | for (i = 1; i <= model->numvertices; i++) { 1139 | model->vertices[3 * i + X] *= scale; 1140 | model->vertices[3 * i + Y] *= scale; 1141 | model->vertices[3 * i + Z] *= scale; 1142 | } 1143 | } 1144 | 1145 | /* glmReverseWinding: Reverse the polygon winding for all polygons in 1146 | * this model. Default winding is counter-clockwise. Also changes 1147 | * the direction of the normals. 1148 | * 1149 | * model - properly initialized GLMmodel structure 1150 | */ 1151 | void 1152 | glmReverseWinding(GLMmodel* model) 1153 | { 1154 | unsigned int i, swap; 1155 | 1156 | assert(model); 1157 | 1158 | for (i = 0; i < model->numtriangles; i++) { 1159 | swap = T(i).vindices[0]; 1160 | T(i).vindices[0] = T(i).vindices[2]; 1161 | T(i).vindices[2] = swap; 1162 | 1163 | if (model->numnormals) { 1164 | swap = T(i).nindices[0]; 1165 | T(i).nindices[0] = T(i).nindices[2]; 1166 | T(i).nindices[2] = swap; 1167 | } 1168 | 1169 | if (model->numtexcoords) { 1170 | swap = T(i).tindices[0]; 1171 | T(i).tindices[0] = T(i).tindices[2]; 1172 | T(i).tindices[2] = swap; 1173 | } 1174 | } 1175 | 1176 | /* reverse facet normals */ 1177 | for (i = 1; i <= model->numfacetnorms; i++) { 1178 | model->facetnorms[3 * i + X] = -model->facetnorms[3 * i + X]; 1179 | model->facetnorms[3 * i + Y] = -model->facetnorms[3 * i + Y]; 1180 | model->facetnorms[3 * i + Z] = -model->facetnorms[3 * i + Z]; 1181 | } 1182 | 1183 | /* reverse vertex normals */ 1184 | for (i = 1; i <= model->numnormals; i++) { 1185 | model->normals[3 * i + X] = -model->normals[3 * i + X]; 1186 | model->normals[3 * i + Y] = -model->normals[3 * i + Y]; 1187 | model->normals[3 * i + Z] = -model->normals[3 * i + Z]; 1188 | } 1189 | } 1190 | 1191 | /* glmFacetNormals: Generates facet normals for a model (by taking the 1192 | * cross product of the two vectors derived from the sides of each 1193 | * triangle). Assumes a counter-clockwise winding. 1194 | * 1195 | * model - initialized GLMmodel structure 1196 | */ 1197 | void 1198 | glmFacetNormals(GLMmodel* model) 1199 | { 1200 | unsigned int i; 1201 | float u[3]; 1202 | float v[3]; 1203 | 1204 | assert(model); 1205 | assert(model->vertices); 1206 | 1207 | /* clobber any old facetnormals */ 1208 | if (model->facetnorms) 1209 | free(model->facetnorms); 1210 | 1211 | /* allocate memory for the new facet normals */ 1212 | model->numfacetnorms = model->numtriangles; 1213 | model->facetnorms = (float*)malloc(sizeof(float) * 1214 | 3 * (model->numfacetnorms + 1)); 1215 | 1216 | for (i = 0; i < model->numtriangles; i++) { 1217 | model->triangles[i].findex = i+1; 1218 | 1219 | u[X] = model->vertices[3 * T(i).vindices[1] + X] - 1220 | model->vertices[3 * T(i).vindices[0] + X]; 1221 | u[Y] = model->vertices[3 * T(i).vindices[1] + Y] - 1222 | model->vertices[3 * T(i).vindices[0] + Y]; 1223 | u[Z] = model->vertices[3 * T(i).vindices[1] + Z] - 1224 | model->vertices[3 * T(i).vindices[0] + Z]; 1225 | 1226 | v[X] = model->vertices[3 * T(i).vindices[2] + X] - 1227 | model->vertices[3 * T(i).vindices[0] + X]; 1228 | v[Y] = model->vertices[3 * T(i).vindices[2] + Y] - 1229 | model->vertices[3 * T(i).vindices[0] + Y]; 1230 | v[Z] = model->vertices[3 * T(i).vindices[2] + Z] - 1231 | model->vertices[3 * T(i).vindices[0] + Z]; 1232 | 1233 | _glmCross(u, v, &model->facetnorms[3 * (i+1)]); 1234 | _glmNormalize(&model->facetnorms[3 * (i+1)]); 1235 | } 1236 | } 1237 | 1238 | /* glmVertexNormals: Generates smooth vertex normals for a model. 1239 | * First builds a list of all the triangles each vertex is in. Then 1240 | * loops through each vertex in the the list averaging all the facet 1241 | * normals of the triangles each vertex is in. Finally, sets the 1242 | * normal index in the triangle for the vertex to the generated smooth 1243 | * normal. If the dot product of a facet normal and the facet normal 1244 | * associated with the first triangle in the list of triangles the 1245 | * current vertex is in is greater than the cosine of the angle 1246 | * parameter to the function, that facet normal is not added into the 1247 | * average normal calculation and the corresponding vertex is given 1248 | * the facet normal. This tends to preserve hard edges. The angle to 1249 | * use depends on the model, but 90 degrees is usually a good start. 1250 | * 1251 | * model - initialized GLMmodel structure 1252 | * angle - maximum angle (in degrees) to smooth across 1253 | */ 1254 | void 1255 | glmVertexNormals(GLMmodel* model, float angle) 1256 | { 1257 | GLMnode* node; 1258 | GLMnode* tail; 1259 | GLMnode** members; 1260 | float* normals; 1261 | unsigned int numnormals; 1262 | float average[3]; 1263 | float dot, cos_angle; 1264 | unsigned int i, avg; 1265 | 1266 | assert(model); 1267 | assert(model->facetnorms); 1268 | 1269 | /* calculate the cosine of the angle (in degrees) */ 1270 | cos_angle = cosf(angle * (float)M_PI / 180.0f); 1271 | 1272 | /* nuke any previous normals */ 1273 | if (model->normals) 1274 | free(model->normals); 1275 | 1276 | /* allocate space for new normals */ 1277 | model->numnormals = model->numtriangles * 3; /* 3 normals per triangle */ 1278 | model->normals = (float*)malloc(sizeof(float)* 3* (model->numnormals+1)); 1279 | 1280 | /* allocate a structure that will hold a linked list of triangle 1281 | indices for each vertex */ 1282 | members = (GLMnode**)malloc(sizeof(GLMnode*) * (model->numvertices + 1)); 1283 | for (i = 1; i <= model->numvertices; i++) 1284 | members[i] = NULL; 1285 | 1286 | /* for every triangle, create a node for each vertex in it */ 1287 | for (i = 0; i < model->numtriangles; i++) { 1288 | node = (GLMnode*)malloc(sizeof(GLMnode)); 1289 | node->index = i; 1290 | node->next = members[T(i).vindices[0]]; 1291 | members[T(i).vindices[0]] = node; 1292 | 1293 | node = (GLMnode*)malloc(sizeof(GLMnode)); 1294 | node->index = i; 1295 | node->next = members[T(i).vindices[1]]; 1296 | members[T(i).vindices[1]] = node; 1297 | 1298 | node = (GLMnode*)malloc(sizeof(GLMnode)); 1299 | node->index = i; 1300 | node->next = members[T(i).vindices[2]]; 1301 | members[T(i).vindices[2]] = node; 1302 | } 1303 | 1304 | /* calculate the average normal for each vertex */ 1305 | numnormals = 1; 1306 | for (i = 1; i <= model->numvertices; i++) { 1307 | /* calculate an average normal for this vertex by averaging the 1308 | facet normal of every triangle this vertex is in */ 1309 | node = members[i]; 1310 | if (!node) 1311 | fprintf(stderr, "glmVertexNormals(): vertex w/o a triangle\n"); 1312 | average[0] = 0.0; average[1] = 0.0; average[2] = 0.0; 1313 | avg = 0; 1314 | while (node) { 1315 | /* only average if the dot product of the angle between the two 1316 | facet normals is greater than the cosine of the threshold 1317 | angle -- or, said another way, the angle between the two 1318 | facet normals is less than (or equal to) the threshold angle */ 1319 | dot = _glmDot(&model->facetnorms[3 * T(node->index).findex], 1320 | &model->facetnorms[3 * T(members[i]->index).findex]); 1321 | if (dot > cos_angle) { 1322 | node->averaged = true; 1323 | average[0] += model->facetnorms[3 * T(node->index).findex + 0]; 1324 | average[1] += model->facetnorms[3 * T(node->index).findex + 1]; 1325 | average[2] += model->facetnorms[3 * T(node->index).findex + 2]; 1326 | avg = 1; /* we averaged at least one normal! */ 1327 | } else { 1328 | node->averaged = false; 1329 | } 1330 | node = node->next; 1331 | } 1332 | 1333 | if (avg) { 1334 | /* normalize the averaged normal */ 1335 | _glmNormalize(average); 1336 | 1337 | /* add the normal to the vertex normals list */ 1338 | model->normals[3 * numnormals + 0] = average[0]; 1339 | model->normals[3 * numnormals + 1] = average[1]; 1340 | model->normals[3 * numnormals + 2] = average[2]; 1341 | avg = numnormals; 1342 | numnormals++; 1343 | } 1344 | 1345 | /* set the normal of this vertex in each triangle it is in */ 1346 | node = members[i]; 1347 | while (node) { 1348 | if (node->averaged) { 1349 | /* if this node was averaged, use the average normal */ 1350 | if (T(node->index).vindices[0] == i) 1351 | T(node->index).nindices[0] = avg; 1352 | else if (T(node->index).vindices[1] == i) 1353 | T(node->index).nindices[1] = avg; 1354 | else if (T(node->index).vindices[2] == i) 1355 | T(node->index).nindices[2] = avg; 1356 | } else { 1357 | /* if this node wasn't averaged, use the facet normal */ 1358 | model->normals[3 * numnormals + 0] = 1359 | model->facetnorms[3 * T(node->index).findex + 0]; 1360 | model->normals[3 * numnormals + 1] = 1361 | model->facetnorms[3 * T(node->index).findex + 1]; 1362 | model->normals[3 * numnormals + 2] = 1363 | model->facetnorms[3 * T(node->index).findex + 2]; 1364 | if (T(node->index).vindices[0] == i) 1365 | T(node->index).nindices[0] = numnormals; 1366 | else if (T(node->index).vindices[1] == i) 1367 | T(node->index).nindices[1] = numnormals; 1368 | else if (T(node->index).vindices[2] == i) 1369 | T(node->index).nindices[2] = numnormals; 1370 | numnormals++; 1371 | } 1372 | node = node->next; 1373 | } 1374 | } 1375 | 1376 | model->numnormals = numnormals - 1; 1377 | 1378 | /* free the member information */ 1379 | for (i = 1; i <= model->numvertices; i++) { 1380 | node = members[i]; 1381 | while (node) { 1382 | tail = node; 1383 | node = node->next; 1384 | free(tail); 1385 | } 1386 | } 1387 | free(members); 1388 | 1389 | /* pack the normals array (we previously allocated the maximum 1390 | number of normals that could possibly be created (numtriangles * 1391 | 3), so get rid of some of them (usually alot unless none of the 1392 | facet normals were averaged)) */ 1393 | normals = model->normals; 1394 | model->normals = (float*)malloc(sizeof(float)* 3* (model->numnormals+1)); 1395 | for (i = 1; i <= model->numnormals; i++) { 1396 | model->normals[3 * i + 0] = normals[3 * i + 0]; 1397 | model->normals[3 * i + 1] = normals[3 * i + 1]; 1398 | model->normals[3 * i + 2] = normals[3 * i + 2]; 1399 | } 1400 | free(normals); 1401 | 1402 | // printf("glmVertexNormals(): %u normals generated\n", model->numnormals); 1403 | } 1404 | 1405 | 1406 | /* glmLinearTexture: Generates texture coordinates according to a 1407 | * linear projection of the texture map. It generates these by 1408 | * linearly mapping the vertices onto a square. 1409 | * 1410 | * model - pointer to initialized GLMmodel structure 1411 | */ 1412 | void 1413 | glmLinearTexture(GLMmodel* model) 1414 | { 1415 | GLMgroup *group; 1416 | float dimensions[3]; 1417 | float x, y, scalefactor; 1418 | unsigned int i; 1419 | 1420 | assert(model); 1421 | 1422 | if (model->texcoords) 1423 | free(model->texcoords); 1424 | model->numtexcoords = model->numvertices; 1425 | model->texcoords=(float*)malloc(sizeof(float)*2*(model->numtexcoords+1)); 1426 | 1427 | glmDimensions(model, dimensions); 1428 | scalefactor = 2.0f / 1429 | _glmAbs(_glmMax(_glmMax(dimensions[0], dimensions[1]), dimensions[2])); 1430 | 1431 | /* do the calculations */ 1432 | for(i = 1; i <= model->numvertices; i++) { 1433 | x = model->vertices[3 * i + 0] * scalefactor; 1434 | y = model->vertices[3 * i + 2] * scalefactor; 1435 | model->texcoords[2 * i + 0] = (x + 1.0f) / 2.0f; 1436 | model->texcoords[2 * i + 1] = (y + 1.0f) / 2.0f; 1437 | } 1438 | 1439 | /* go through and put texture coordinate indices in all the triangles */ 1440 | group = model->groups; 1441 | while(group) { 1442 | for(i = 0; i < group->numtriangles; i++) { 1443 | T(group->triangles[i]).tindices[0] = T(group->triangles[i]).vindices[0]; 1444 | T(group->triangles[i]).tindices[1] = T(group->triangles[i]).vindices[1]; 1445 | T(group->triangles[i]).tindices[2] = T(group->triangles[i]).vindices[2]; 1446 | } 1447 | group = group->next; 1448 | } 1449 | 1450 | #if 0 1451 | printf("glmLinearTexture(): generated %d linear texture coordinates\n", 1452 | model->numtexcoords); 1453 | #endif 1454 | } 1455 | 1456 | /* glmSpheremapTexture: Generates texture coordinates according to a 1457 | * spherical projection of the texture map. Sometimes referred to as 1458 | * spheremap, or reflection map texture coordinates. It generates 1459 | * these by using the normal to calculate where that vertex would map 1460 | * onto a sphere. Since it is impossible to map something flat 1461 | * perfectly onto something spherical, there is distortion at the 1462 | * poles. This particular implementation causes the poles along the X 1463 | * axis to be distorted. 1464 | * 1465 | * model - pointer to initialized GLMmodel structure 1466 | */ 1467 | void 1468 | glmSpheremapTexture(GLMmodel* model) 1469 | { 1470 | GLMgroup* group; 1471 | float theta, phi, rho, x, y, z, r; 1472 | unsigned int i; 1473 | 1474 | assert(model); 1475 | assert(model->normals); 1476 | 1477 | if (model->texcoords) 1478 | free(model->texcoords); 1479 | model->numtexcoords = model->numnormals; 1480 | model->texcoords=(float*)malloc(sizeof(float)*2*(model->numtexcoords+1)); 1481 | 1482 | /* do the calculations */ 1483 | for (i = 1; i <= model->numnormals; i++) { 1484 | z = model->normals[3 * i + 0]; /* re-arrange for pole distortion */ 1485 | y = model->normals[3 * i + 1]; 1486 | x = model->normals[3 * i + 2]; 1487 | r = sqrtf((x * x) + (y * y)); 1488 | rho = sqrtf((r * r) + (z * z)); 1489 | 1490 | if(r == 0.0f) { 1491 | theta = 0.0f; 1492 | phi = 0.0f; 1493 | } else { 1494 | if(z == 0.0) 1495 | phi = 3.14159265f / 2.0f; 1496 | else 1497 | phi = acosf(z / rho); 1498 | 1499 | #if WE_DONT_NEED_THIS_CODE 1500 | if(x == 0.0f) 1501 | theta = 3.14159265f / 2.0f; /* asin(y / r); */ 1502 | else 1503 | theta = acosf(x / r); 1504 | #endif 1505 | 1506 | if(y == 0.0f) 1507 | theta = 3.141592365f / 2.0f; /* acos(x / r); */ 1508 | else 1509 | theta = asinf(y / r) + (3.14159265f / 2.0f); 1510 | } 1511 | 1512 | model->texcoords[2 * i + 0] = theta / 3.14159265f; 1513 | model->texcoords[2 * i + 1] = phi / 3.14159265f; 1514 | } 1515 | 1516 | /* go through and put texcoord indices in all the triangles */ 1517 | group = model->groups; 1518 | while(group) { 1519 | for (i = 0; i < group->numtriangles; i++) { 1520 | T(group->triangles[i]).tindices[0] = T(group->triangles[i]).nindices[0]; 1521 | T(group->triangles[i]).tindices[1] = T(group->triangles[i]).nindices[1]; 1522 | T(group->triangles[i]).tindices[2] = T(group->triangles[i]).nindices[2]; 1523 | } 1524 | group = group->next; 1525 | } 1526 | 1527 | #if 0 1528 | printf("glmSpheremapTexture(): generated %d spheremap texture coordinates\n", 1529 | model->numtexcoords); 1530 | #endif 1531 | } 1532 | 1533 | /* glmDelete: Deletes a GLMmodel structure. 1534 | * 1535 | * model - initialized GLMmodel structure 1536 | */ 1537 | void 1538 | glmDelete(GLMmodel* model) 1539 | { 1540 | GLMgroup* group; 1541 | unsigned int i; 1542 | 1543 | assert(model); 1544 | 1545 | if (model->pathname) free(model->pathname); 1546 | if (model->mtllibname) free(model->mtllibname); 1547 | if (model->vertices) free(model->vertices); 1548 | if (model->normals) free(model->normals); 1549 | if (model->texcoords) free(model->texcoords); 1550 | if (model->facetnorms) free(model->facetnorms); 1551 | if (model->triangles) free(model->triangles); 1552 | if (model->materials) { 1553 | for (i = 0; i < model->nummaterials; i++) 1554 | if (model->materials[i].name) free(model->materials[i].name); 1555 | free(model->materials); 1556 | } 1557 | while(model->groups) { 1558 | group = model->groups; 1559 | /* Take the group off the linked list. */ 1560 | model->groups = model->groups->next; 1561 | if (group->name) free(group->name); 1562 | if (group->triangles) free(group->triangles); 1563 | if (group->mtlname) free(group->mtlname); 1564 | free(group); 1565 | } 1566 | 1567 | free(model); 1568 | } 1569 | 1570 | /* glmReadOBJ: Reads a model description from a Wavefront .OBJ file. 1571 | * Returns a pointer to the created object which should be free'd with 1572 | * glmDelete(). 1573 | * 1574 | * filename - name of the file containing the Wavefront .OBJ format data. 1575 | */ 1576 | GLMmodel* 1577 | glmReadOBJ(const char* filename) 1578 | { 1579 | GLMmodel* model; 1580 | FILE* file; 1581 | 1582 | /* open the file */ 1583 | file = fopen(filename, "r"); 1584 | if (!file) { 1585 | perror("glmReadOBJ() failed: can't open data file"); 1586 | return 0; 1587 | } 1588 | 1589 | #if 0 1590 | /* announce the model name */ 1591 | printf("Model: %s\n", filename); 1592 | #endif 1593 | 1594 | /* allocate a new model */ 1595 | model = (GLMmodel*)malloc(sizeof(GLMmodel)); 1596 | model->pathname = strdup(filename); 1597 | model->mtllibname = NULL; 1598 | model->numvertices = 0; 1599 | model->vertices = NULL; 1600 | model->numnormals = 0; 1601 | model->normals = NULL; 1602 | model->numtexcoords = 0; 1603 | model->texcoords = NULL; 1604 | model->numfacetnorms = 0; 1605 | model->facetnorms = NULL; 1606 | model->numtriangles = 0; 1607 | model->triangles = NULL; 1608 | model->nummaterials = 0; 1609 | model->materials = NULL; 1610 | model->numgroups = 0; 1611 | model->groups = NULL; 1612 | model->position[0] = 0.0; 1613 | model->position[1] = 0.0; 1614 | model->position[2] = 0.0; 1615 | model->usePerVertexColors = 0; 1616 | /* make a first pass through the file to get a count of the number 1617 | of vertices, normals, texcoords & triangles */ 1618 | if (_glmFirstPass(model, file)) { 1619 | /* There was a problem here, so cleanup and exit. */ 1620 | glmDelete(model); 1621 | fclose(file); 1622 | return 0; 1623 | } 1624 | 1625 | /* allocate memory */ 1626 | model->vertices = (float*)malloc(sizeof(float) * 1627 | 3 * (model->numvertices + 1)); 1628 | model->vertexColors = (unsigned char*)malloc(sizeof(unsigned char) * 1629 | 3 * (model->numvertices + 1)); 1630 | model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) * 1631 | model->numtriangles); 1632 | if (model->numnormals) { 1633 | model->normals = (float*)malloc(sizeof(float) * 1634 | 3 * (model->numnormals + 1)); 1635 | } 1636 | if (model->numtexcoords) { 1637 | model->texcoords = (float*)malloc(sizeof(float) * 1638 | 2 * (model->numtexcoords + 1)); 1639 | } 1640 | 1641 | /* rewind to beginning of file and read in the data this pass */ 1642 | rewind(file); 1643 | 1644 | _glmSecondPass(model, file); 1645 | 1646 | /* close the file */ 1647 | fclose(file); 1648 | 1649 | return model; 1650 | } 1651 | 1652 | /* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to 1653 | * a file. 1654 | * 1655 | * model - initialized GLMmodel structure 1656 | * filename - name of the file to write the Wavefront .OBJ format data to 1657 | * mode - a bitwise or of values describing what is written to the file 1658 | * GLM_NONE - render with only vertices 1659 | * GLM_FLAT - render with facet normals 1660 | * GLM_SMOOTH - render with vertex normals 1661 | * GLM_TEXTURE - render with texture coords 1662 | * GLM_COLOR - render with colors (color material) 1663 | * GLM_MATERIAL - render with materials 1664 | * GLM_COLOR and GLM_MATERIAL should not both be specified. 1665 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 1666 | */ 1667 | int 1668 | glmWriteOBJ(GLMmodel* model, char* filename, unsigned int mode) 1669 | { 1670 | unsigned int i; 1671 | FILE* file; 1672 | GLMgroup* group; 1673 | 1674 | assert(model); 1675 | 1676 | /* do a bit of warning */ 1677 | if (mode & GLM_FLAT && !model->facetnorms) { 1678 | printf("glmWriteOBJ() warning: flat normal output requested " 1679 | "with no facet normals defined.\n"); 1680 | mode &= ~GLM_FLAT; 1681 | } 1682 | if (mode & GLM_SMOOTH && !model->normals) { 1683 | printf("glmWriteOBJ() warning: smooth normal output requested " 1684 | "with no normals defined.\n"); 1685 | mode &= ~GLM_SMOOTH; 1686 | } 1687 | if (mode & GLM_TEXTURE && !model->texcoords) { 1688 | printf("glmWriteOBJ() warning: texture coordinate output requested " 1689 | "with no texture coordinates defined.\n"); 1690 | mode &= ~GLM_TEXTURE; 1691 | } 1692 | if (mode & GLM_FLAT && mode & GLM_SMOOTH) { 1693 | printf("glmWriteOBJ() warning: flat normal output requested " 1694 | "and smooth normal output requested (using smooth).\n"); 1695 | mode &= ~GLM_FLAT; 1696 | } 1697 | 1698 | /* open the file */ 1699 | file = fopen(filename, "w"); 1700 | if (!file) { 1701 | fprintf(stderr, "glmWriteOBJ() failed: can't open file \"%s\" to write.\n", 1702 | filename); 1703 | return 1; 1704 | } 1705 | 1706 | /* spit out a header */ 1707 | fprintf(file, "# \n"); 1708 | fprintf(file, "# Wavefront OBJ generated by GLM library\n"); 1709 | fprintf(file, "# \n"); 1710 | fprintf(file, "# GLM library copyright (C) 1997 by Nate Robins\n"); 1711 | fprintf(file, "# email: ndr@pobox.com\n"); 1712 | fprintf(file, "# www: http://www.pobox.com/~ndr\n"); 1713 | fprintf(file, "# \n"); 1714 | 1715 | if (mode & GLM_MATERIAL && model->mtllibname) { 1716 | fprintf(file, "\nmtllib %s\n\n", model->mtllibname); 1717 | if (_glmWriteMTL(model, filename, model->mtllibname)) { 1718 | /* Problem opening up the material file for output. */ 1719 | fclose(file); 1720 | return 1; 1721 | } 1722 | } 1723 | 1724 | /* spit out the vertices */ 1725 | fprintf(file, "\n"); 1726 | fprintf(file, "# %u vertices\n", model->numvertices); 1727 | for (i = 1; i <= model->numvertices; i++) { 1728 | fprintf(file, "v %f %f %f\n", 1729 | model->vertices[3 * i + 0], 1730 | model->vertices[3 * i + 1], 1731 | model->vertices[3 * i + 2]); 1732 | } 1733 | 1734 | /* spit out the smooth/flat normals */ 1735 | if (mode & GLM_SMOOTH) { 1736 | fprintf(file, "\n"); 1737 | fprintf(file, "# %u normals\n", model->numnormals); 1738 | for (i = 1; i <= model->numnormals; i++) { 1739 | fprintf(file, "vn %f %f %f\n", 1740 | model->normals[3 * i + 0], 1741 | model->normals[3 * i + 1], 1742 | model->normals[3 * i + 2]); 1743 | } 1744 | } else if (mode & GLM_FLAT) { 1745 | fprintf(file, "\n"); 1746 | fprintf(file, "# %u normals\n", model->numfacetnorms); 1747 | for (i = 1; i <= model->numnormals; i++) { 1748 | fprintf(file, "vn %f %f %f\n", 1749 | model->facetnorms[3 * i + 0], 1750 | model->facetnorms[3 * i + 1], 1751 | model->facetnorms[3 * i + 2]); 1752 | } 1753 | } 1754 | 1755 | /* spit out the texture coordinates */ 1756 | if (mode & GLM_TEXTURE) { 1757 | fprintf(file, "\n"); 1758 | fprintf(file, "# %u texcoords\n", model->numtexcoords); 1759 | for (i = 1; i <= model->numtexcoords; i++) { 1760 | fprintf(file, "vt %f %f\n", 1761 | model->texcoords[2 * i + 0], 1762 | model->texcoords[2 * i + 1]); 1763 | } 1764 | } 1765 | 1766 | fprintf(file, "\n"); 1767 | fprintf(file, "# %u groups\n", model->numgroups); 1768 | fprintf(file, "# %u faces (triangles)\n", model->numtriangles); 1769 | fprintf(file, "\n"); 1770 | 1771 | group = model->groups; 1772 | while(group) { 1773 | fprintf(file, "g %s\n", group->name); 1774 | if (mode & GLM_MATERIAL) 1775 | fprintf(file, "usemtl %s\n", model->materials[group->material].name); 1776 | for (i = 0; i < group->numtriangles; i++) { 1777 | if (mode & GLM_SMOOTH && mode & GLM_TEXTURE) { 1778 | fprintf(file, "f %u/%u/%u %u/%u/%u %u/%u/%u\n", 1779 | T(group->triangles[i]).vindices[0], 1780 | T(group->triangles[i]).nindices[0], 1781 | T(group->triangles[i]).tindices[0], 1782 | T(group->triangles[i]).vindices[1], 1783 | T(group->triangles[i]).nindices[1], 1784 | T(group->triangles[i]).tindices[1], 1785 | T(group->triangles[i]).vindices[2], 1786 | T(group->triangles[i]).nindices[2], 1787 | T(group->triangles[i]).tindices[2]); 1788 | } else if (mode & GLM_FLAT && mode & GLM_TEXTURE) { 1789 | fprintf(file, "f %u/%u %u/%u %u/%u\n", 1790 | T(group->triangles[i]).vindices[0], 1791 | T(group->triangles[i]).findex, 1792 | T(group->triangles[i]).vindices[1], 1793 | T(group->triangles[i]).findex, 1794 | T(group->triangles[i]).vindices[2], 1795 | T(group->triangles[i]).findex); 1796 | } else if (mode & GLM_TEXTURE) { 1797 | fprintf(file, "f %u/%u %u/%u %u/%u\n", 1798 | T(group->triangles[i]).vindices[0], 1799 | T(group->triangles[i]).tindices[0], 1800 | T(group->triangles[i]).vindices[1], 1801 | T(group->triangles[i]).tindices[1], 1802 | T(group->triangles[i]).vindices[2], 1803 | T(group->triangles[i]).tindices[2]); 1804 | } else if (mode & GLM_SMOOTH) { 1805 | fprintf(file, "f %u//%u %u//%u %u//%u\n", 1806 | T(group->triangles[i]).vindices[0], 1807 | T(group->triangles[i]).nindices[0], 1808 | T(group->triangles[i]).vindices[1], 1809 | T(group->triangles[i]).nindices[1], 1810 | T(group->triangles[i]).vindices[2], 1811 | T(group->triangles[i]).nindices[2]); 1812 | } else if (mode & GLM_FLAT) { 1813 | fprintf(file, "f %u//%u %u//%u %u//%u\n", 1814 | T(group->triangles[i]).vindices[0], 1815 | T(group->triangles[i]).findex, 1816 | T(group->triangles[i]).vindices[1], 1817 | T(group->triangles[i]).findex, 1818 | T(group->triangles[i]).vindices[2], 1819 | T(group->triangles[i]).findex); 1820 | } else { 1821 | fprintf(file, "f %u %u %u\n", 1822 | T(group->triangles[i]).vindices[0], 1823 | T(group->triangles[i]).vindices[1], 1824 | T(group->triangles[i]).vindices[2]); 1825 | } 1826 | } 1827 | fprintf(file, "\n"); 1828 | group = group->next; 1829 | } 1830 | 1831 | fclose(file); 1832 | return 0; 1833 | } 1834 | 1835 | /* glmWeld: eliminate (weld) vectors that are within an epsilon of 1836 | * each other. 1837 | * 1838 | * model - initialized GLMmodel structure 1839 | * epsilon - maximum difference between vertices 1840 | * ( 0.00001 is a good start for a unitized model) 1841 | * 1842 | */ 1843 | void 1844 | glmWeld(GLMmodel* model, float epsilon) 1845 | { 1846 | float* vectors; 1847 | float* copies; 1848 | unsigned int numvectors; 1849 | unsigned int i; 1850 | 1851 | /* vertices */ 1852 | numvectors = model->numvertices; 1853 | vectors = model->vertices; 1854 | copies = _glmWeldVectors(vectors, &numvectors, epsilon); 1855 | 1856 | printf("glmWeld(): %u redundant vertices.\n", 1857 | model->numvertices - numvectors - 1); 1858 | 1859 | for (i = 0; i < model->numtriangles; i++) { 1860 | T(i).vindices[0] = (unsigned int)vectors[3 * T(i).vindices[0] + 0]; 1861 | T(i).vindices[1] = (unsigned int)vectors[3 * T(i).vindices[1] + 0]; 1862 | T(i).vindices[2] = (unsigned int)vectors[3 * T(i).vindices[2] + 0]; 1863 | } 1864 | 1865 | /* free space for old vertices */ 1866 | free(vectors); 1867 | 1868 | /* allocate space for the new vertices */ 1869 | model->numvertices = numvectors; 1870 | model->vertices = (float*)malloc(sizeof(float) * 1871 | 3 * (model->numvertices + 1)); 1872 | 1873 | /* copy the optimized vertices into the actual vertex list */ 1874 | for (i = 1; i <= model->numvertices; i++) { 1875 | model->vertices[3 * i + 0] = copies[3 * i + 0]; 1876 | model->vertices[3 * i + 1] = copies[3 * i + 1]; 1877 | model->vertices[3 * i + 2] = copies[3 * i + 2]; 1878 | } 1879 | 1880 | free(copies); 1881 | } 1882 | 1883 | #if 0 /** This is left in only as a reference to how to get to the data. */ 1884 | /* glmDraw: Renders the model to the current OpenGL context using the 1885 | * mode specified. 1886 | * 1887 | * model - initialized GLMmodel structure 1888 | * mode - a bitwise OR of values describing what is to be rendered. 1889 | * GLM_NONE - render with only vertices 1890 | * GLM_FLAT - render with facet normals 1891 | * GLM_SMOOTH - render with vertex normals 1892 | * GLM_TEXTURE - render with texture coords 1893 | * GLM_COLOR - render with colors (color material) 1894 | * GLM_MATERIAL - render with materials 1895 | * GLM_COLOR and GLM_MATERIAL should not both be specified. 1896 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 1897 | */ 1898 | GLvoid 1899 | glmDraw(GLMmodel* model, unsigned int mode) 1900 | { 1901 | unsigned int i; 1902 | GLMgroup* group; 1903 | 1904 | assert(model); 1905 | assert(model->vertices); 1906 | 1907 | /* do a bit of warning */ 1908 | if (mode & GLM_FLAT && !model->facetnorms) { 1909 | printf("glmDraw() warning: flat render mode requested " 1910 | "with no facet normals defined.\n"); 1911 | mode &= ~GLM_FLAT; 1912 | } 1913 | if (mode & GLM_SMOOTH && !model->normals) { 1914 | printf("glmDraw() warning: smooth render mode requested " 1915 | "with no normals defined.\n"); 1916 | mode &= ~GLM_SMOOTH; 1917 | } 1918 | if (mode & GLM_TEXTURE && !model->texcoords) { 1919 | printf("glmDraw() warning: texture render mode requested " 1920 | "with no texture coordinates defined.\n"); 1921 | mode &= ~GLM_TEXTURE; 1922 | } 1923 | if (mode & GLM_FLAT && mode & GLM_SMOOTH) { 1924 | printf("glmDraw() warning: flat render mode requested " 1925 | "and smooth render mode requested (using smooth).\n"); 1926 | mode &= ~GLM_FLAT; 1927 | } 1928 | if (mode & GLM_COLOR && !model->materials) { 1929 | printf("glmDraw() warning: color render mode requested " 1930 | "with no materials defined.\n"); 1931 | mode &= ~GLM_COLOR; 1932 | } 1933 | if (mode & GLM_MATERIAL && !model->materials) { 1934 | printf("glmDraw() warning: material render mode requested " 1935 | "with no materials defined.\n"); 1936 | mode &= ~GLM_MATERIAL; 1937 | } 1938 | if (mode & GLM_COLOR && mode & GLM_MATERIAL) { 1939 | printf("glmDraw() warning: color and material render mode requested " 1940 | "using only material mode\n"); 1941 | mode &= ~GLM_COLOR; 1942 | } 1943 | if (mode & GLM_COLOR) 1944 | glEnable(GL_COLOR_MATERIAL); 1945 | if (mode & GLM_MATERIAL) 1946 | glDisable(GL_COLOR_MATERIAL); 1947 | 1948 | glPushMatrix(); 1949 | glTranslatef(model->position[0], model->position[1], model->position[2]); 1950 | 1951 | glBegin(GL_TRIANGLES); 1952 | group = model->groups; 1953 | while (group) { 1954 | if (mode & GLM_MATERIAL) { 1955 | glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, 1956 | model->materials[group->material].ambient); 1957 | glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 1958 | model->materials[group->material].diffuse); 1959 | glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, 1960 | model->materials[group->material].specular); 1961 | glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 1962 | model->materials[group->material].shininess); 1963 | } 1964 | 1965 | if (mode & GLM_COLOR) { 1966 | glColor3fv(model->materials[group->material].diffuse); 1967 | } 1968 | 1969 | for (i = 0; i < group->numtriangles; i++) { 1970 | if (mode & GLM_FLAT) 1971 | glNormal3fv(&model->facetnorms[3 * T(group->triangles[i]).findex]); 1972 | 1973 | if (mode & GLM_SMOOTH) 1974 | glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[0]]); 1975 | if (mode & GLM_TEXTURE) 1976 | glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[0]]); 1977 | 1978 | if (model->usePerVertexColors) { 1979 | glColor3ubv( &model->vertexColors[3 * T(group->triangles[i]).vindices[0]] ); 1980 | } 1981 | 1982 | glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[0]]); 1983 | #if 0 1984 | printf("%f %f %f\n", 1985 | model->vertices[3 * T(group->triangles[i]).vindices[0] + X], 1986 | model->vertices[3 * T(group->triangles[i]).vindices[0] + Y], 1987 | model->vertices[3 * T(group->triangles[i]).vindices[0] + Z]); 1988 | #endif 1989 | 1990 | if (mode & GLM_SMOOTH) 1991 | glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[1]]); 1992 | if (mode & GLM_TEXTURE) 1993 | glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[1]]); 1994 | if (model->usePerVertexColors) { 1995 | glColor3ubv( &model->vertexColors[3 * T(group->triangles[i]).vindices[1]] ); 1996 | } 1997 | glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[1]]); 1998 | #if 0 1999 | printf("%f %f %f\n", 2000 | model->vertices[3 * T(group->triangles[i]).vindices[1] + X], 2001 | model->vertices[3 * T(group->triangles[i]).vindices[1] + Y], 2002 | model->vertices[3 * T(group->triangles[i]).vindices[1] + Z]); 2003 | #endif 2004 | 2005 | if (mode & GLM_SMOOTH) 2006 | glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[2]]); 2007 | if (mode & GLM_TEXTURE) 2008 | glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[2]]); 2009 | if (model->usePerVertexColors) { 2010 | glColor3ubv( &model->vertexColors[3 * T(group->triangles[i]).vindices[2]] ); 2011 | } 2012 | glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[2]]); 2013 | #if 0 2014 | printf("%f %f %f\n", 2015 | model->vertices[3 * T(group->triangles[i]).vindices[2] + X], 2016 | model->vertices[3 * T(group->triangles[i]).vindices[2] + Y], 2017 | model->vertices[3 * T(group->triangles[i]).vindices[2] + Z]); 2018 | #endif 2019 | 2020 | } 2021 | 2022 | group = group->next; 2023 | } 2024 | glEnd(); 2025 | 2026 | glPopMatrix(); 2027 | } 2028 | #endif 2029 | 2030 | -------------------------------------------------------------------------------- /test/glm/glm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GLM library. Wavefront .obj file format reader/writer/manipulator. 3 | * 4 | * Written by Nate Robins, 1997. 5 | * email: ndr@pobox.com 6 | * www: http://www.pobox.com/~ndr 7 | */ 8 | 9 | #ifndef RTRT_GLM_H 10 | #define RTRT_GLM_H 11 | 12 | 13 | /* includes */ 14 | 15 | /* defines */ 16 | #if 0 17 | #define GLM_NONE (0) /* render with only vertices */ 18 | #define GLM_FLAT (1 << 0) /* render with facet normals */ 19 | #define GLM_SMOOTH (1 << 1) /* render with vertex normals */ 20 | #define GLM_TEXTURE (1 << 2) /* render with texture coords */ 21 | #define GLM_COLOR (1 << 3) /* render with colors */ 22 | #define GLM_MATERIAL (1 << 4) /* render with materials */ 23 | #endif 24 | 25 | enum { 26 | GLM_NONE = (0), 27 | GLM_FLAT = (1 << 0), 28 | GLM_SMOOTH = (1 << 1), 29 | GLM_TEXTURE = (1 << 2), 30 | GLM_COLOR = (1 << 3), 31 | GLM_MATERIAL = (1 << 4), 32 | GLM_FLAT_SHADE = (1 << 5), 33 | GLM_SPECULAR_SHADE = (1 << 6) 34 | }; 35 | 36 | enum Sizes { 37 | MaxStringLength = 128 38 | }; 39 | 40 | /* structs */ 41 | 42 | /* GLMmaterial: Structure that defines a material in a model. 43 | */ 44 | typedef struct _GLMmaterial 45 | { 46 | char* name; /* name of material */ 47 | float diffuse[4]; // Kd diffuse component 48 | float ambient[4]; // Ka ambient component 49 | float specular[4]; // Ks specular component 50 | float emmissive[4]; // emmissive component 51 | float shininess; // Ns specular exponent 52 | float refraction; // Tr 53 | float alpha; // d 54 | float reflectivity; // reflection 55 | int shader; // illum 56 | 57 | // Texture maps, zero length if not specified. 58 | char ambient_map [MaxStringLength]; // map_Ka 59 | char diffuse_map [MaxStringLength]; // map_Kd 60 | char specular_map[MaxStringLength]; // map_Ks 61 | char dissolve_map[MaxStringLength]; // map_D 62 | 63 | // Scaling for texture maps (initialized to 0 for not set) 64 | float ambient_map_scaling[2]; 65 | float diffuse_map_scaling[2]; 66 | float specular_map_scaling[2]; 67 | float dissolve_map_scaling[2]; 68 | 69 | } GLMmaterial; 70 | 71 | /* GLMtriangle: Structure that defines a triangle in a model. 72 | */ 73 | typedef struct { 74 | unsigned int vindices[3]; /* array of triangle vertex indices */ 75 | unsigned int nindices[3]; /* array of triangle normal indices */ 76 | unsigned int tindices[3]; /* array of triangle texcoord indices*/ 77 | unsigned int findex; /* index of triangle facet normal */ 78 | } GLMtriangle; 79 | 80 | /* GLMgroup: Structure that defines a group in a model. 81 | */ 82 | typedef struct _GLMgroup { 83 | char* name; /* name of this group */ 84 | unsigned int numtriangles; /* number of triangles in this group */ 85 | unsigned int* triangles; /* array of triangle indices */ 86 | unsigned int material; /* index to material for group */ 87 | char* mtlname; /*name of the material for this group*/ 88 | struct _GLMgroup* next; /* pointer to next group in model */ 89 | } GLMgroup; 90 | 91 | /* GLMmodel: Structure that defines a model. 92 | */ 93 | typedef struct { 94 | char* pathname; /* path to this model */ 95 | char* mtllibname; /* name of the material library */ 96 | 97 | unsigned int numvertices; /* number of vertices in model */ 98 | float* vertices; /* array of vertices 99 | [x1,y1,z1,x2,y2,z2...] */ 100 | unsigned char* vertexColors; /* array of vertex colors */ 101 | 102 | unsigned int numnormals; /* number of normals in model */ 103 | float* normals; /* array of normals */ 104 | 105 | unsigned int numtexcoords; /* number of texcoords in model */ 106 | float* texcoords; /* array of texture coordinates */ 107 | 108 | unsigned int numfacetnorms; /* number of facetnorms in model */ 109 | float* facetnorms; /* array of facetnorms */ 110 | 111 | unsigned int numtriangles; /* number of triangles in model */ 112 | GLMtriangle* triangles; /* array of triangles */ 113 | 114 | unsigned int nummaterials; /* number of materials in model */ 115 | GLMmaterial* materials; /* array of materials */ 116 | 117 | /* This is the thing you will want to iterate over. Each group has 118 | an associated list of triangles, material, and name. */ 119 | unsigned int numgroups; /* number of groups in model */ 120 | GLMgroup* groups; /* linked list of groups */ 121 | 122 | float position[3]; /* position of the model */ 123 | 124 | bool usePerVertexColors; /* Are there per vertex colors? */ 125 | 126 | } GLMmodel; 127 | 128 | 129 | /* public functions */ 130 | 131 | /* glmUnitize: "unitize" a model by translating it to the origin and 132 | * scaling it to fit in a unit cube around the origin. Returns the 133 | * scalefactor used. 134 | * 135 | * model - properly initialized GLMmodel structure 136 | */ 137 | float 138 | glmUnitize(GLMmodel* model); 139 | 140 | /* 141 | * glmBoundingBox: Calculates the min/max positions of the model 142 | */ 143 | void 144 | glmBoundingBox(GLMmodel *model, float *minpos, float *maxpos); 145 | 146 | 147 | /* glmDimensions: Calculates the dimensions (width, height, depth) of 148 | * a model. 149 | * 150 | * model - initialized GLMmodel structure 151 | * dimensions - array of 3 floats (float dimensions[3]) 152 | */ 153 | void 154 | glmDimensions(GLMmodel* model, float* dimensions); 155 | 156 | /* glmScale: Scales a model by a given amount. 157 | * 158 | * model - properly initialized GLMmodel structure 159 | * scale - scalefactor (0.5 = half as large, 2.0 = twice as large) 160 | */ 161 | void 162 | glmScale(GLMmodel* model, float scale); 163 | 164 | /* glmReverseWinding: Reverse the polygon winding for all polygons in 165 | * this model. Default winding is counter-clockwise. Also changes 166 | * the direction of the normals. 167 | * 168 | * model - properly initialized GLMmodel structure 169 | */ 170 | void 171 | glmReverseWinding(GLMmodel* model); 172 | 173 | /* glmFacetNormals: Generates facet normals for a model (by taking the 174 | * cross product of the two vectors derived from the sides of each 175 | * triangle). Assumes a counter-clockwise winding. 176 | * 177 | * model - initialized GLMmodel structure 178 | */ 179 | void 180 | glmFacetNormals(GLMmodel* model); 181 | 182 | /* glmVertexNormals: Generates smooth vertex normals for a model. 183 | * First builds a list of all the triangles each vertex is in. Then 184 | * loops through each vertex in the the list averaging all the facet 185 | * normals of the triangles each vertex is in. Finally, sets the 186 | * normal index in the triangle for the vertex to the generated smooth 187 | * normal. If the dot product of a facet normal and the facet normal 188 | * associated with the first triangle in the list of triangles the 189 | * current vertex is in is greater than the cosine of the angle 190 | * parameter to the function, that facet normal is not added into the 191 | * average normal calculation and the corresponding vertex is given 192 | * the facet normal. This tends to preserve hard edges. The angle to 193 | * use depends on the model, but 90 degrees is usually a good start. 194 | * 195 | * model - initialized GLMmodel structure 196 | * angle - maximum angle (in degrees) to smooth across 197 | */ 198 | void 199 | glmVertexNormals(GLMmodel* model, float angle); 200 | 201 | /* glmLinearTexture: Generates texture coordinates according to a 202 | * linear projection of the texture map. It generates these by 203 | * linearly mapping the vertices onto a square. 204 | * 205 | * model - pointer to initialized GLMmodel structure 206 | */ 207 | void 208 | glmLinearTexture(GLMmodel* model); 209 | 210 | /* glmSpheremapTexture: Generates texture coordinates according to a 211 | * spherical projection of the texture map. Sometimes referred to as 212 | * spheremap, or reflection map texture coordinates. It generates 213 | * these by using the normal to calculate where that vertex would map 214 | * onto a sphere. Since it is impossible to map something flat 215 | * perfectly onto something spherical, there is distortion at the 216 | * poles. This particular implementation causes the poles along the X 217 | * axis to be distorted. 218 | * 219 | * model - pointer to initialized GLMmodel structure 220 | */ 221 | void 222 | glmSpheremapTexture(GLMmodel* model); 223 | 224 | /* glmDelete: Deletes a GLMmodel structure. 225 | * 226 | * model - initialized GLMmodel structure 227 | */ 228 | void 229 | glmDelete(GLMmodel* model); 230 | 231 | /* glmReadOBJ: Reads a model description from a Wavefront .OBJ file. 232 | * Returns a pointer to the created object which should be free'd with 233 | * glmDelete(). 234 | * 235 | * filename - name of the file containing the Wavefront .OBJ format data. 236 | * 237 | * returns 0 if there was a problem reading the file. 238 | */ 239 | GLMmodel* 240 | glmReadOBJ(const char* filename); 241 | 242 | /* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to 243 | * a file. 244 | * 245 | * model - initialized GLMmodel structure 246 | * filename - name of the file to write the Wavefront .OBJ format data to 247 | * mode - a bitwise or of values describing what is written to the file 248 | * GLM_NONE - write only vertices 249 | * GLM_FLAT - write facet normals 250 | * GLM_SMOOTH - write vertex normals 251 | * GLM_TEXTURE - write texture coords 252 | * GLM_FLAT and GLM_SMOOTH should not both be specified. 253 | * 254 | * returns 1 if there was error, 0 otherwise. 255 | * 256 | */ 257 | int 258 | glmWriteOBJ(GLMmodel* model, char* filename, unsigned int mode); 259 | 260 | /* glmWeld: eliminate (weld) vectors that are within an epsilon of 261 | * each other. 262 | * 263 | * model - initialized GLMmodel structure 264 | * epsilon - maximum difference between vertices 265 | * ( 0.00001 is a good start for a unitized model) 266 | * 267 | */ 268 | void 269 | glmWeld(GLMmodel* model, float epsilon); 270 | 271 | 272 | #endif 273 | -------------------------------------------------------------------------------- /test/main.cc: -------------------------------------------------------------------------------- 1 | #include "voxelizer_demo.h" 2 | #include 3 | #include "cheetah/core/options.h" 4 | 5 | using namespace voxel; 6 | int main(int argc, char *argv[]) { 7 | glutInit(&argc, argv); 8 | cheetah::core::InitOptions(); 9 | 10 | VoxelizerDemo demo; 11 | int dim = 128; 12 | bool uniform = false; 13 | if (argc > 3 && atoi(argv[3]) != 0) uniform = true; 14 | if (argc > 2) dim = atoi(argv[2]); 15 | if (argc > 1) demo.Initialize(argv[1], dim, uniform); 16 | else demo.Initialize("bunny.obj", dim, uniform); 17 | demo.Run(); 18 | return 0; 19 | } -------------------------------------------------------------------------------- /test/main.cu: -------------------------------------------------------------------------------- 1 | #include "voxelizer_demo.h" 2 | #include 3 | #include "axle/core/options.h" 4 | 5 | using namespace voxel; 6 | int main(int argc, char *argv[]) { 7 | glutInit(&argc, argv); 8 | ax::InitOptions(); 9 | 10 | VoxelizerDemo demo; 11 | int dim = 128; 12 | bool uniform = true; 13 | if (argc > 3 && atoi(argv[3]) != 0) uniform = true; 14 | if (argc > 2) dim = atoi(argv[2]); 15 | if (argc > 1) demo.Initialize(argv[1], dim, uniform); 16 | else demo.Initialize("mahua2.obj", dim, uniform); 17 | demo.Run(); 18 | return 0; 19 | } -------------------------------------------------------------------------------- /test/voxelizer_demo.cu: -------------------------------------------------------------------------------- 1 | #include "voxelizer_demo.h" 2 | 3 | #include 4 | 5 | #include "axle/cg/utils.h" 6 | #include "axle/cg/model_gl.h" 7 | #include "axle/core/options.h" 8 | #include "axle/core/utils.h" 9 | #include "axle/core/timer.h" 10 | 11 | #include "axle/core/debug.h" 12 | #include "voxel/voxelizer_api.h" 13 | 14 | namespace voxel { 15 | VoxelizerDemo::VoxelizerDemo() 16 | : ax::GlutWindow("Voxelizer Demo",10, 10, 800, 600, 17 | GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH), 18 | camera_(glm::vec3(-2.68, 0, 2.55), glm::vec3(0, 0, 0)) { 19 | camera_.set_min_dist(0.1); 20 | camera_.set_fovy(30.0); 21 | camera_.set_velocity(0, 0, 1); 22 | method_ = kGL; 23 | 24 | iters_ = 10; 25 | mode_ = kUniform; 26 | dim_ = 256; 27 | } 28 | 29 | VoxelizerDemo::~VoxelizerDemo() { 30 | 31 | } 32 | 33 | int DrawVoxel(const HVectorInt &vols, const HVectorFloat &delta, 34 | const int x_dim, const int y_dim, const int z_dim, const int int_dim) { 35 | float t[3] = { 0.f, 0.f, 0.f }; 36 | int count = 0; 37 | const int *ptr = thrust::raw_pointer_cast(&vols.front()); 38 | const int *vol_ptr = ptr; 39 | 40 | for (int z = 0; z < int_dim; ++z) { 41 | t[Y] = 0; 42 | for (int y = 0; y < y_dim; ++y) { 43 | t[X] = 0; 44 | for (int x = 0; x < x_dim; ++x) { 45 | int bits = *ptr; 46 | t[Z] = delta[Z] * 32 * z; 47 | for (int i = 0; i < 32; ++i) { 48 | if (bits & (1 << i)) { 49 | glPushMatrix(); 50 | ax::DrawCube(t[0], t[1], t[2], t[0] + delta[0], t[1] + delta[1], t[2] + delta[2]); 51 | glPopMatrix(); 52 | } 53 | t[Z] += delta[Z]; 54 | } 55 | ++ptr; 56 | t[X] += delta[X]; 57 | } 58 | t[Y] += delta[Y]; 59 | } 60 | } 61 | //for (int y = 0; y < y_dim; ++y) { 62 | // t[2] = 0.f; 63 | // for (int z = 0; z < z_dim; ++z) { 64 | // t[0] = 0.f; 65 | // for (int x = 0; x < x_int_dim; ++x) { 66 | // int bits = *ptr; 67 | // int bit = 1; 68 | // for (int i = 0; i < 32; ++i) { 69 | // if (bits & bit) { 70 | // glPushMatrix(); 71 | // //[x, y, z * 32 + i] 72 | // //glTranslatef(t[0], t[1], t[2]); 73 | // ax::DrawCube(t[0], t[1], t[2], t[0] + delta[0], 74 | // t[1] + delta[1], t[2] + delta[2]); 75 | // //glutSolidCube(delta[0]); 76 | // glPopMatrix(); 77 | // ++count; 78 | // } 79 | // bit <<= 1; 80 | // t[0] += delta[0]; 81 | // } 82 | // ++ptr; 83 | // } 84 | // t[2] += delta[2]; 85 | // } 86 | // t[1] += delta[1]; 87 | //} 88 | return count; 89 | } 90 | 91 | uint32 CreateVoxelDisplayList(const HVectorInt &vols, const HVectorFloat &delta, 92 | const HVectorFloat &bbox0, const int x_dim, 93 | const int y_dim, const int z_dim, const int int_dim) { 94 | uint32 voxel_list = glGenLists(1); 95 | if (voxel_list) { 96 | glNewList(voxel_list, GL_COMPILE); 97 | glPushMatrix(); 98 | glTranslatef(bbox0[0], -delta[1] * y_dim * 0.5, bbox0[2]); 99 | int count = DrawVoxel(vols, delta, x_dim, y_dim, z_dim, int_dim); 100 | 101 | /*glPushAttrib(GL_LIGHTING_BIT|GL_POLYGON_BIT|GL_LINE_BIT); 102 | glDisable(GL_LIGHTING); 103 | glLineWidth(1.5); 104 | glColor3f(0, 0, 0); 105 | glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 106 | DrawVoxel(vols, delta, x_int_dim, y_dim, z_dim); 107 | glPopAttrib();*/ 108 | 109 | glPopMatrix(); 110 | ax::Logger::Debug("voxels:", count); 111 | glEndList(); 112 | } 113 | return voxel_list; 114 | } 115 | 116 | void DrawBound(const HVectorFloat &tri_bbox0, 117 | const HVectorFloat &tri_bbox1, const int N) { 118 | for (int i = 0; i < N; ++i) { 119 | ax::DrawCube(tri_bbox0[i], tri_bbox0[i + N], tri_bbox0[i + _2X(N)], 120 | tri_bbox1[i], tri_bbox1[i + N], tri_bbox1[i + _2X(N)]); 121 | } 122 | } 123 | uint32 CreateBoundDisplayList(const HVectorFloat &tri_bbox0, 124 | const HVectorFloat &tri_bbox1, const int N) { 125 | uint32 bbox_list = glGenLists(1); 126 | if (bbox_list) { 127 | glNewList(bbox_list, GL_COMPILE); 128 | /* glEnable(GL_AUTO_NORMAL); */ 129 | glColor3f(0, 1, 0); 130 | DrawBound(tri_bbox0, tri_bbox1, N); 131 | 132 | glPushAttrib(GL_LIGHTING_BIT|GL_POLYGON_BIT|GL_LINE_BIT); 133 | glDisable(GL_LIGHTING); 134 | glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 135 | glLineWidth(1.5); 136 | glColor3f(0, 0, 0); 137 | DrawBound(tri_bbox0, tri_bbox1, N); 138 | glPopAttrib(); 139 | /*glDisable(GL_AUTO_NORMAL); */ 140 | glEndList(); 141 | } 142 | return bbox_list; 143 | } 144 | 145 | bool VoxelizerDemo::Initialize(const char *model_file, int dim, bool uniform) { 146 | glewInit(); 147 | ax::Logger::Debug("load model", model_file); 148 | 149 | V_RET(mesh_ = ax::LoadObj(ax::UserOptions::GetFullModelPath(model_file).c_str())); 150 | V_RET(glmesh_ = ax::GLMesh::Create(mesh_)); 151 | this->glmesh_->PreProcess(ax::kUseVBO); 152 | 153 | V_RET(this->dmesh_ = voxel::ConvertFromTriMesh(this->mesh_)); 154 | V_RET(this->hmesh_ = voxel::ConvertFromTriMesh(this->mesh_)); 155 | 156 | this->RunTest(); 157 | //bbox0 [p0c0 p1c0 ...][p0c1 p1c1 ...][p0c2 p1c2 ...] 158 | //bbox1 [p0c0 p1c0 ...][p0c1 p1c1 ...][p0c2 p1c2 ...] 159 | //pi stands for a point of the bounding box correspond to the ith triangle 160 | //ci stands for the ith component of the point 161 | // !!!!!! a test should be taken to show how the initial value is set 162 | 163 | return true; 164 | } 165 | 166 | void VoxelizerDemo::RunTest() { 167 | this->dmesh_->ComputeTriBBox(); 168 | ax::SeqTimer::Begin("bbox"); 169 | this->dmesh_->ComputeMeshBBox(); 170 | ax::SeqTimer::End(); 171 | this->hmesh_->ComputeTriBBox(); 172 | this->hmesh_->ComputeMeshBBox(); 173 | 174 | std::vector bbox0(3), bbox1(3); 175 | cudaMemcpy(&bbox0[0], thrust::raw_pointer_cast(&this->dmesh_->bbox0().front()), sizeof(float)*3, cudaMemcpyDeviceToHost); 176 | cudaMemcpy(&bbox1[0], thrust::raw_pointer_cast(&this->dmesh_->bbox1().front()), sizeof(float)*3, cudaMemcpyDeviceToHost); 177 | 178 | this->dvoxels_.Initialize(HVectorFloat(this->dmesh_->bbox0()), 179 | HVectorFloat(this->dmesh_->bbox1()), 180 | dim_, mode_); 181 | this->hvoxels_.Initialize(this->hmesh_->bbox0(), this->hmesh_->bbox1(), 182 | dim_, mode_); 183 | 184 | //voxel::Voxelize(thrust::raw_pointer_cast(&this->dmesh_->vertices().front()), 185 | // thrust::raw_pointer_cast(&this->dmesh_->triangles().front()), 186 | // this->dmesh_->n_triangles(), 187 | // thrust::raw_pointer_cast(&this->dmesh_->tri_bbox0().front()), 188 | // thrust::raw_pointer_cast(&this->dmesh_->tri_bbox1().front()), 189 | // this->dvoxels_); 190 | 191 | voxel::Voxelize(thrust::raw_pointer_cast(&this->hmesh_->vertices().front()), 192 | thrust::raw_pointer_cast(&this->hmesh_->triangles().front()), 193 | this->hmesh_->n_triangles(), 194 | thrust::raw_pointer_cast(&this->hmesh_->tri_bbox0().front()), 195 | thrust::raw_pointer_cast(&this->hmesh_->tri_bbox1().front()), 196 | this->hvoxels_); 197 | 198 | ax::SeqTimer::Begin("voxel"); 199 | ::tVoxels tvoxels; 200 | tvoxels.data = this->dvoxels_.vols_ptr(); 201 | tvoxels.target = voxel::kDevice; 202 | int tmp_dim[3] = { 512, 512, 128 }; 203 | ::Voxelize(this->mesh_, tmp_dim, &tvoxels); 204 | ax::SeqTimer::End(); 205 | 206 | 207 | //voxel::CheckVoxels(this->dvoxels_.vols(), this->hvoxels_.vols()); 208 | const HostVoxels &vols = this->hvoxels_; 209 | if (voxel_list_) glDeleteLists(voxel_list_, 1); 210 | voxel_list_ = CreateVoxelDisplayList(HVectorInt(this->hvoxels_.vols()), 211 | vols.delta(), vols.bbox0(), 212 | vols.dim(X), vols.dim(Y), vols.dim(Z), vols.int_dim()); 213 | /* if (bbox_list_) glDeleteLists(bbox_list_, 1); 214 | bbox_list_ = CreateBoundDisplayList(h_test_->tri_bbox0(), 215 | h_test_->tri_bbox1(), 216 | h_test_->n_triangles());*/ 217 | } 218 | 219 | void VoxelizerDemo::OnPaint() { 220 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 221 | glMatrixMode(GL_MODELVIEW); 222 | glm::mat4 m = camera_.ViewMatrix(); 223 | glLoadMatrixf(&m[0][0]); 224 | 225 | GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; 226 | GLfloat mat_shininess[] = { 50.0 }; 227 | GLfloat mat_diffuse[] = { 0., 0.8, .0, 1.0 }; 228 | glm::vec4 light_position(camera_.position(), 0); 229 | 230 | glClearColor (0.0, 0.0, 0.0, 0.0); 231 | 232 | // glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); 233 | glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); 234 | // glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); 235 | glLightfv(GL_LIGHT0, GL_POSITION, &light_position[0]); 236 | 237 | glEnable(GL_LIGHTING); 238 | glEnable(GL_LIGHT0); 239 | glEnable(GL_DEPTH_TEST); 240 | glShadeModel(GL_FLAT); 241 | 242 | //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 243 | 244 | //glutSolidSphere(0.1, 32, 32); 245 | ax::CheckErrorsGL("hello"); 246 | if (kGL == method_) { 247 | glmesh_->Draw(NULL, ax::kNone); 248 | } else if (kBBox == method_) { 249 | //glCallList(bbox_list_); 250 | } else { 251 | glCallList(voxel_list_); 252 | } 253 | 254 | glDisable(GL_LIGHT0); 255 | glDisable(GL_LIGHTING); 256 | 257 | ax::DisplayStatistics("frame rate", fps_counter_.Update(), "fps"); 258 | glutSwapBuffers(); 259 | } 260 | 261 | void VoxelizerDemo::OnResize(int width, int height) { 262 | if (width == 0 || height == 0) return; 263 | 264 | glViewport(0, 0, width, height); 265 | 266 | camera_.set_aspect_ratio(static_cast(width)/height); 267 | glMatrixMode(GL_PROJECTION); 268 | glm::mat4 m = camera_.ProjMatrix(); 269 | glLoadMatrixf(&m[0][0]); 270 | } 271 | 272 | void VoxelizerDemo::OnIdle() { 273 | this->RePaint(); 274 | } 275 | 276 | void VoxelizerDemo::OnKeyDown(const int key, const int x, const int y) { 277 | switch (key) { 278 | case 'a': 279 | camera_.Yaw(-1); 280 | break; 281 | case 'd': 282 | camera_.Yaw(1); 283 | break; 284 | case 'w': 285 | camera_.Walk(1); 286 | break; 287 | case 's': 288 | camera_.Walk(-1); 289 | break; 290 | case 'q': 291 | camera_.Pitch(1); 292 | break; 293 | case 'z': 294 | camera_.Pitch(-1); 295 | break; 296 | case 'n': 297 | method_ = (method_ + 1) % 3; 298 | break; 299 | case 'j': 300 | dim_ <<= 1; 301 | this->RunTest(); 302 | break; 303 | case 'k': 304 | dim_ >>= 1; 305 | this->RunTest(); 306 | break; 307 | case 'h': 308 | if (iters_ > 5) { 309 | iters_ -= 5; 310 | this->RunTest(); 311 | } 312 | break; 313 | case 'l': 314 | iters_ += 5; 315 | this->RunTest(); 316 | break; 317 | case 'm': 318 | mode_ = (mode_ + 1) % 3; 319 | this->RunTest(); 320 | break; 321 | } 322 | } 323 | } // voxel 324 | -------------------------------------------------------------------------------- /test/voxelizer_demo.h: -------------------------------------------------------------------------------- 1 | #ifndef VOXELIZER_VOXELIZER_TEST_H 2 | #define VOXELIZER_VOXELIZER_TEST_H 3 | 4 | #include "axle/core/settings.h" 5 | 6 | #include "axle/cg/fps_counter.h" 7 | #include "axle/cg/camera.h" 8 | #include 9 | #include "axle/ui/glut_window.h" 10 | #include "axle/cg/glmesh.h" 11 | #include "voxel/voxelizer_api.h" 12 | 13 | namespace voxel { 14 | //typedef VoxelizeTest HostVoxelizeTest; 15 | //typedef VoxelizeTest DeviceVoxelizeTest; 16 | 17 | class VoxelizerDemo : public ax::GlutWindow { 18 | private: 19 | enum { kGL, kBBox, kVoxel }; 20 | public: 21 | VoxelizerDemo(); 22 | ~VoxelizerDemo(); 23 | bool Initialize(const char *model_file, int dim, bool uniform); 24 | void OnIdle(); 25 | void OnPaint(); 26 | void OnResize(int width, int height); 27 | void OnKeyDown(int key, int x, int y); 28 | private: 29 | void RunTest(); 30 | private: 31 | ax::OrbitPerspectiveCameraGL camera_; 32 | ax::FpsCounter fps_counter_; 33 | 34 | /* DeviceVoxelizeTest *d_test_; 35 | HostVoxelizeTest *h_test_;*/ 36 | 37 | voxel::dVoxelizableMeshPtr dmesh_; 38 | voxel::hVoxelizableMeshPtr hmesh_; 39 | voxel::Voxels dvoxels_; 40 | voxel::Voxels hvoxels_; 41 | 42 | ax::TriMeshPtr mesh_; 43 | ax::ObjectPtr glmesh_; 44 | 45 | uint32 voxel_list_; 46 | uint32 bbox_list_; 47 | 48 | int method_; 49 | int mode_; 50 | int dim_; 51 | int iters_; 52 | }; 53 | } // namespace voxel 54 | 55 | #endif // VOXELIZER_VOXELIZER_TEST_H 56 | -------------------------------------------------------------------------------- /test/voxelizer_test.cu: -------------------------------------------------------------------------------- 1 | #include "voxelizer_test.h" 2 | 3 | namespace voxel { 4 | 5 | 6 | } // voxel -------------------------------------------------------------------------------- /test/voxelizer_test.h: -------------------------------------------------------------------------------- 1 | #ifndef VOXELIZER_TEST_VOXELIZER_TEST_H 2 | #define VOXELIZER_TEST_VOXELIZER_TEST_H 3 | 4 | 5 | 6 | #endif // VOXELIZER_TEST_VOXELIZER_TEST_H 7 | --------------------------------------------------------------------------------