dimanche 28 juin 2015

Undefined symbols for architecture x86_64 on Mac

I'm using CLion with GCC 7.8 for coding in C++. We have this code, which using for "rendering" image from *.OBJ files.

#ifndef __GEOMETRY_H__
#define __GEOMETRY_H__

#include <cmath>

template <class t> struct Vec2 {
    t x, y;
    Vec2<t>() : x(t()), y(t()) {}
    Vec2<t>(t _x, t _y) : x(_x), y(_y) {}
    Vec2<t>(const Vec2<t> &v) : x(t()), y(t()) { *this = v; }
    Vec2<t> & operator =(const Vec2<t> &v) {
        if (this != &v) {
            x = v.x;
            y = v.y;
        }
        return *this;
    }
    Vec2<t> operator +(const Vec2<t> &V) const { return Vec2<t>(x+V.x, y+V.y); }
    Vec2<t> operator -(const Vec2<t> &V) const { return Vec2<t>(x-V.x, y-V.y); }
    Vec2<t> operator *(float f)          const { return Vec2<t>(x*f, y*f); }
    t& operator[](const int i) { if (x<=0) return x; else return y; }
    template <class > friend std::ostream& operator<<(std::ostream& s, Vec2<t>& v);
};

template <class t> struct Vec3 {
    t x, y, z;
    Vec3<t>() : x(t()), y(t()), z(t()) { }
    Vec3<t>(t _x, t _y, t _z) : x(_x), y(_y), z(_z) {}
    template <class u> Vec3<t>(const Vec3<u> &v);
    Vec3<t>(const Vec3<t> &v) : x(t()), y(t()), z(t()) { *this = v; }
    Vec3<t> & operator =(const Vec3<t> &v) {
        if (this != &v) {
            x = v.x;
            y = v.y;
            z = v.z;
        }
        return *this;
    }
    Vec3<t> operator ^(const Vec3<t> &v) const { return Vec3<t>(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x); }
    Vec3<t> operator +(const Vec3<t> &v) const { return Vec3<t>(x+v.x, y+v.y, z+v.z); }
    Vec3<t> operator -(const Vec3<t> &v) const { return Vec3<t>(x-v.x, y-v.y, z-v.z); }
    Vec3<t> operator *(float f)          const { return Vec3<t>(x*f, y*f, z*f); }
    t       operator *(const Vec3<t> &v) const { return x*v.x + y*v.y + z*v.z; }
    float norm () const { return std::sqrt(x*x+y*y+z*z); }
    Vec3<t> & normalize(t l=1) { *this = (*this)*(l/norm()); return *this; }
    t& operator[](const int i) { if (i<=0) return x; else if (i==1) return y; else return z; }
    template <class > friend std::ostream& operator<<(std::ostream& s, Vec3<t>& v);
};

typedef Vec2<float> Vec2f;
typedef Vec2<int>   Vec2i;
typedef Vec3<float> Vec3f;
typedef Vec3<int>   Vec3i;

template <> template <> Vec3<int>::Vec3(const Vec3<float> &v);
template <> template <> Vec3<float>::Vec3(const Vec3<int> &v);


template <class t> std::ostream& operator<<(std::ostream& s, Vec2<t>& v) {
    s << "(" << v.x << ", " << v.y << ")\n";
    return s;
}

template <class t> std::ostream& operator<<(std::ostream& s, Vec3<t>& v) {
    s << "(" << v.x << ", " << v.y << ", " << v.z << ")\n";
    return s;
}

#endif //__GEOMETRY_H__

This template used in my main.cpp file, something like that:

void triangle(Vec3i t0, Vec3i t1, Vec3i t2, TGAImage &image, TGAColor color, int *zbuffer) {
    if (t0.y == t1.y && t0.y == t2.y) return;
    // sort point by Y coordinate
    if (t0.y > t1.y) std::swap(t0, t1);
    if (t0.y > t2.y) std::swap(t0, t2);
    if (t1.y > t2.y) std::swap(t1, t2);

    int total_height = t2.y - t0.y;

    for (int i=0; i<total_height; i++) {
        bool second_half = i > t1.y - t0.y || t1.y == t0.y;
        int segment_height = second_half ? t2.y - t1.y : t1.y - t0.y;

        float alpha = (float)i / total_height;
        float beta  = (float)(i - (second_half ? t1.y - t0.y : 0)) / segment_height;

        Vec3i A =               t0 + Vec3f(t2 - t0) * alpha;
        Vec3i B = second_half ? t1 + Vec3f(t2 - t1) * beta : t0 + Vec3f(t1 - t0) * beta;

        if (A.x > B.x) std::swap(A, B);

        for (int j=A.x; j<=B.x; j++) {
            float phi = B.x == A.x ? 1. : (float)(j - A.x) / (float)(B.x - A.x);
            Vec3i P = Vec3f(A) + Vec3f(B - A) * phi;
            int idx = P.x + P.y * width;
            // Z-buffer
            if (zbuffer[idx] < P.z) {
                zbuffer[idx] = P.z;
                image.set(P.x, P.y, color);
            }
        }
    }
}

void add_light_zbuffer(Vec3f light_dir, Model &model, TGAImage &image, int* zbuffer) {
    for (int i=0; i<model.nfaces(); i++) {
        std::vector<int> face = model.face(i);
        Vec3i screen_coords[3];
        Vec3f world_coords[3];
        for (int j = 0; j < 3; j++) {
            Vec3f v = model.vert(face[j]);
            screen_coords[j] = Vec3i((v.x + 1.) * width  / 2.,
                                     (v.y + 1.) * height / 2.,
                                     (v.z + 1.) * depth  / 2.);
            world_coords[j] = v;
        }

        // calculate light intensity
        Vec3f n = (world_coords[2] - world_coords[0]) ^ (world_coords[1] - world_coords[0]);
        n.normalize();
        float intensity = n * light_dir;
        // and apply it on image
        if (intensity > 0) {
            triangle(screen_coords[0], screen_coords[1], screen_coords[2], image,
                     TGAColor((unsigned char)(intensity * 255),
                              (unsigned char)(intensity * 255),
                              (unsigned char)(intensity * 255),
                              (unsigned char) 255),
                     zbuffer);
        }
    }
}


void scene_3d_zbuffer() {
    TGAImage render(width, height, TGAImage::RGB);
    Model* model = new Model("../assets/african_head.obj");

    int* zbuffer = new int[width * height];
    for (int i=0; i<width * height; i++) {
        zbuffer[i] = std::numeric_limits<int>::min();
    }

    Vec3f light_dir = Vec3f(0, 0, -1);
    add_light_zbuffer(light_dir, *model, render, zbuffer);

    render.flip_vertically();
    render.write_tga_file("output3_2.tga");
    delete zbuffer;
    delete model;
}

But after start building by CMake 3.2.2, I taken this messages in my console:

[ 25%] Linking CXX executable /Users/savicvalera/code/LearnComputerGraphics/bin/Lesson_3_Deleting_hidden_surfaces
[ 66%] Built target Lesson_1_Bresenham_algorithm
Built target Lesson_2_Trinagles_rasterization
Undefined symbols for architecture x86_64:
  "Vec3<float>::Vec3<int>(Vec3<int> const&)", referenced from:
      triangle(Vec3<int>, Vec3<int>, Vec3<int>, TGAImage&, TGAColor, int*) in main.cpp.o
  "Vec3<int>::Vec3<float>(Vec3<float> const&)", referenced from:
      triangle(Vec3<int>, Vec3<int>, Vec3<int>, TGAImage&, TGAColor, int*) in main.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [/Users/savicvalera/code/LearnComputerGraphics/bin/Lesson_3_Deleting_hidden_surfaces] Error 1
make[1]: *** [CMakeFiles/Lesson_3_Deleting_hidden_surfaces.dir/all] Error 2
make: *** [all] Error 2 

And my question is: what happens with code, and why build failed every time?

Aucun commentaire:

Enregistrer un commentaire