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?
For solving this issue necessary add links on cpp/h files into CMake file. For example, in this situation was:
project(Lesson_3_Deleting_hidden_surfaces)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES src/IntroCG/Lesson_3_Deleting_hidden_surfaces/main.cpp)
add_executable(Lesson_3_Deleting_hidden_surfaces ${SOURCE_FILES}
src/IntroCG/tgaimage.cpp src/IntroCG/tgaimage.h
src/IntroCG/model.cpp src/IntroCG/model.h
src/IntroCG/painter.cpp src/IntroCG/painter.h)
and became
project(Lesson_3_Deleting_hidden_surfaces)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES src/IntroCG/Lesson_3_Deleting_hidden_surfaces/main.cpp)
add_executable(Lesson_3_Deleting_hidden_surfaces ${SOURCE_FILES}
src/IntroCG/geometry.cpp src/IntroCG/geometry.h
src/IntroCG/tgaimage.cpp src/IntroCG/tgaimage.h
src/IntroCG/model.cpp src/IntroCG/model.h
src/IntroCG/painter.cpp src/IntroCG/painter.h)
Related
I am studying Shading and how light interacts with objects. I found a great website and wanted to implement knowledge from https://www.scratchapixel.com/lessons/3d-basic-rendering/introduction-to-shading/shading-normals in my own way.
I wrote a code. It is supposed to calculate a facing ratio (cosine of the angle between a normal vector and a light Ray ) and generate a ".BMP" image with that. I took a surface as an object (well, on the image it will be a circle). The idea was to calculate the effect of this ratio on the color of the surface, i.e how light and object interact.
The code is as follows
template <typename T>
class Vec3
{
private:
T x, y, z;
public:
Vec3(): x{0},y{0},z{0} {}
Vec3(T xx): x{xx}, y{xx},z{xx} {}
Vec3(T xx, T yy, T zz): x{xx}, y{yy}, z{zz} {}
friend Vec3<T> operator+(const Vec3<T>& vec1, const Vec3<T>& vec2) { return Vec3<T>(vec1.x + vec2.x, vec1.y + vec2.y, vec1.z + vec2.z); }
friend Vec3<T> operator-(const Vec3<T>& vec1, const Vec3<T>& vec2) { return Vec3<T>(vec1.x - vec2.x, vec1.y - vec2.y, vec1.z - vec2.z); }
friend Vec3<T> operator*(const Vec3<T>& vec1, const Vec3<T>& vec2) { return Vec3<T>(vec1.x * vec2.x, vec1.y * vec2.y, vec1.z * vec2.z); }
friend Vec3<T> operator*(const Vec3<T>& vec1, const T& k) { return Vec3<T>(vec1.x * k, vec1.y * k, vec1.z * k); }
friend Vec3<T> operator/(const Vec3<T>& vec1, const T& k) { return Vec3<T>(vec1.x / k, vec1.y / k, vec1.z / k); }
Vec3<T> operator - () const { return Vec3<T>(-x, -y, -z); }
T dot (const Vec3<T>& v) const { return x * v.x + y * v.y + z * v.z; }
T lengthWithoutRoot() const { return x * x + y * y + z * z; }
T length() const { return sqrt(lengthWithoutRoot()); }
Vec3& normalize()
{
T nor2 = lengthWithoutRoot();
if (nor2 > 0) {
T divider = 1 / sqrt(nor2);
x *= divider, y *= divider, z *= divider;
}
return *this;
}
Vec3<T> reflection(const Vec3<T>& prim,const Vec3<T>& normal) // TO BE CHECKED
{
Vec3<T> reflection = prim - 2 * (prim.dot(normal)) * normal;
return reflection;
}
friend std::ostream& operator<<(std::ostream &out, const Vec3<T>& vec)
{
out << '(' << vec.x << ',' << vec.y << ',' << vec.z << ')';
return out;
}
const T& getX() { return x; }
const T& getY() { return y; }
const T& getZ() { return z; }
};
typedef Vec3<float> Vec3f;
class Sphere
{
private:
Vec3f center;
float radius;
public:
Sphere(const Vec3f& c, const float& r): center{c}, radius{r} {}
bool intersect(const Vec3f& primRay)
{
Vec3f vecRadius = center - primRay;
float distLength = vecRadius.length();
if (distLength > radius)
return false;
return true;
}
bool intersectSurface(const Vec3f& primRay)
{
Vec3f vecRadius = center - primRay;
float distLength = vecRadius.length();
if (distLength == radius)
return true;
return false;
}
float alphaPositive(const Vec3f& p, const Vec3f& source)
{
Vec3f primRay = (source-p).normalize();
Vec3f normal = (p-center).normalize();
float diff = primRay.dot(normal);
return std::max(diff,0.f) ;
}
};
int main()
{
Sphere sphere (Vec3f{ 250.0f, 250.0f, 0.0 }, 150.0f );
Vec3f source{ 100,200,0.0 };
Vec3f color{ 255,255,255 };
std::ofstream file;
file.open("DIF_SPHERE36.ppm");
file << "P6\n" << height << " " << width << "\n255\n";
for (float h = 0; h < 500; ++h)
{
for (float w = 0; w < 500; ++w)
{
Vec3f primRay = { h,w,0.0 };
if (sphere.intersect(primRay))
{
float facingRatio= sphere.alphaPositive(primRay, source);
color = Vec3f{255,0,0}*facingRatio;
file << unsigned char(color.getX()) << unsigned char(color.getY()) << unsigned char(color.getZ());
}
else
file << unsigned char(255) << unsigned char(255) << unsigned char(255);
}
}
file.close();
return 0;
}
However. I get smth strange, even when I try to change 'source' coordinates.
Facing ratio is calculated in alphaPositive function This is what a code must generate according to the idea
Thank you all for your comments.
I made following conclusions:
In function alphaPositive I had to use return std::max(diff,0.1f) instead of return std::max(diff,0.f).
Had to change positioning of the Object and Light by adding z-coordinates.
With that I managed to get a sphere with some effects.
I have the simple class "vec2". I would like this class to be able to store doubles and double references in the class template, or even int and int references. Here is the desired behavior-
vec2<double> base(5, 5); //normal vec2
vec2<double&> reference(base.x, base.y); //vec2 reference to vec2 "base"
vec2<double> third;
base.x++; //base.x equals 6, this also changes reference.x to 6;
third = reference; //conversion between vec2<double> and vec2<double&>
I would also like modifying a reference instance of vec2 to be impossible, except by changing the variables it is referencing- so the following code would give a compiler error
vec2<double&> reference(base.x, base.y); //vec2 reference to vec2 "base"
reference.x = 5; //undesired behaviour
Is there a way to make the members x and y public when dealing with non-reference class types, but private when the class type is a reference? This would require methods specific to when it is a reference that will return the values of x and y. In the reference version it would also need to not have the overloaded operator methods that can affect the references. I slightly understand template specialization, but not enough to actually implement it.
Anyways, the main point of this is to find out how to take a class of type vec2<double>, and convert it to a class of type vec2<double&>.
Or, conversely, take a class of type vec2<double&>, and convert it to a class of type vec2<double>.
Here is my simple vec2 class-
template <class T> class vec2{
public:
vec2(){
x = 0;
y = 0;
}
vec2(T X, T Y){
x = X;
y = Y;
}
void normalize(){ //this function should inaccesable to any "reference version" of vec2
*this /= magnitude();
}
void rotate(double radians, vec2 center){ //this should also be inaccesable to reference versions
vec2 ogPts = *this -= center;
x = ogPts.x*cos(radians) - ogPts.y*sin(radians);
y = ogPts.y*cos(radians) + ogPts.x*sin(radians);
*this += center;
}
double magnitude() const{
return sqrt(x * x + y * y); //this should be available to both
}
T x;
T y;
vec2 operator+(const vec2 &v) const{ //available to both
return vec2(x+v.x, y+v.y);
}
vec2 operator-(const vec2 &v) const{ //available to both
return vec2(x-v.x, y-v.y);
}
vec2 operator*(const vec2 &v) const{ //available to both
return vec2(x*v.x, y*v.y);
}
vec2 operator*(T v) const{ //available to both, but should work even if v is not a reference variable and T is a reference
return vec2(x*v, y*v);
}
vec2 operator/(T v) const{ //available to both, but should work even if v is not a reference variable and T is a reference
return vec2(x/v, y/v);
}
vec2 operator+=(const vec2 &v){ //inaccesable to reference versions of the class
x += v.x;
y += v.y;
return *this;
}
vec2 operator-=(const vec2 &v){ //inaccesable to reference versions
x -= v.x;
y -= v.y;
return *this;
}
vec2 operator*=(const vec2 &v){ //inaccesable to reference versions
x *= v.x;
y *= v.y;
return *this;
}
vec2 operator*=(T v){ //inaccesable to reference versions
x *= v;
y *= v;
return *this;
}
vec2 operator/=(T v){ //inaccesable to reference versions
x /= v;
y /= v;
return *this;
}
bool operator==(const vec2 &v) const{ //this should be available to both
return (v.x == x && v.y == y);
}
bool operator!=(const vec2 &v) const{ //this should be available to both
return (v.x != x || v.y != y);
}
};
Any help is much appreciated! I haven't worked with templates much, in fact, I just started yesterday! Thanks in advance for your time!
I did a bit more research, and managed to learn a lot on template specialization. Here is the functioning vec2 class which implements everything I wanted, plus a "perpindiculate" function and a "swap" function-
template <class T> class vec2{
public:
vec2(){
x = 0;
y = 0;
}
vec2(T X, T Y){
x = X;
y = Y;
}
operator vec2<T&>(){
return vec2<T&>(x, y);
}
void swap(){
std::swap(x, y);
}
void perpindiculate(){
std::swap(x, y);
y = -y;
}
void normalize(){
*this /= magnitude();
}
void rotate(double radians, vec2 center){
vec2 ogPts = *this -= center;
x = ogPts.x*cos(radians) - ogPts.y*sin(radians);
y = ogPts.y*cos(radians) + ogPts.x*sin(radians);
*this += center;
}
double magnitude() const{
return sqrt(x * x + y * y);
}
vec2 operator+(const vec2 &v) const{
return vec2(x+v.x, y+v.y);
}
vec2 operator-(const vec2 &v) const{
return vec2(x-v.x, y-v.y);
}
vec2 operator*(const vec2 &v) const{
return vec2(x*v.x, y*v.y);
}
vec2 operator*(T v) const{
return vec2(x*v, y*v);
}
vec2 operator/(T v) const{
return vec2(x/v, y/v);
}
vec2 operator+=(const vec2 &v){
x += v.x;
y += v.y;
return *this;
}
vec2 operator-=(const vec2 &v){
x -= v.x;
y -= v.y;
return *this;
}
vec2 operator*=(const vec2 &v){
x *= v.x;
y *= v.y;
return *this;
}
vec2 operator*=(T v){
x *= v;
y *= v;
return *this;
}
vec2 operator/=(T v){
x /= v;
y /= v;
return *this;
}
bool operator==(const vec2 &v) const{
return (v.x == x && v.y == y);
}
bool operator!=(const vec2 &v) const{
return (v.x != x || v.y != y);
}
T x;
T y;
};
template<class T>
class vec2<T&>{
public:
vec2(T& X, T& Y) : x{X}, y{Y} {}
operator vec2<T>(){
return vec2<T>(x, y);
}
vec2<T> swap() const{
return vec2<T>(y, x);
}
vec2<T> perpindiculate() const{
return vec2<T>(-y, x);
}
vec2<T> normalize() const{
return *this / magnitude();
}
vec2<T> rotate(double radians, vec2 center) const{
return vec2<T>(x*cos(radians) - y*sin(radians), y*cos(radians) + x*sin(radians));
}
double magnitude() const{
return sqrt(x * x + y * y);
}
vec2 operator+(const vec2 &v) const{
return vec2(x+v.x, y+v.y);
}
vec2 operator-(const vec2 &v) const{
return vec2(x-v.x, y-v.y);
}
vec2 operator*(const vec2 &v) const{
return vec2(x*v.x, y*v.y);
}
vec2 operator*(T& v) const{
return vec2(x*v, y*v);
}
vec2 operator/(T& v) const{
return vec2(x/v, y/v);
}
bool operator==(const vec2 &v) const{
return (v.x == x && v.y == y);
}
bool operator!=(const vec2 &v) const{
return (v.x != x || v.y != y);
}
T getx(){
return x;
}
T gety(){
return y;
}
private:
T& x;
T& y;
};
Here is an example of it working-
double x = 5; //create future reference variables
double y = 3;
vec2<double&> vecref(x, y); //create vec2 referring to x and y
x = 7; //change x and y values, also changing vecref's values as well
y = 8;
vec2<double> vecOffRef = vecref; //conversion from a reference vec to a normal one
vec2<double&> vecOffRefref = vecOffRef; //conversion from a normal vec to a reference one
vecOffRef.normalize(); //normalize vec, also normalizing vecOffRefref
/* x equals 7, y = 8
vecRef equals (7, 8)
vecOffRef equals (0.6585, .7525)
vecOffRefRef equals (0.6585, .7525) */
A simplified version. By making the fields private, they can't be modified. I didn't try implementing all the operator= methods, but your code should work.
I'm not quite sure where your confusion is. A scan didn't see any problems, except I'd make the fields private so no one can touch them, and add accessor methods instead.
#include <iostream>
using namespace std;
template <class T>
class MyClass {
private:
T x;
T y;
public:
MyClass(T _x, T _y) : x(_x), y(_y) {}
T getX() const { return x; }
T getY() const { return y; }
};
int main(int, char **) {
double x {1.0};
double y {2.5};
MyClass<double> withDouble(x, y);
MyClass<double &> withRef{x, y};
cout << "withDouble: " << withDouble.getX() << ", " << withDouble.getY() << endl;
cout << "withRef: " << withRef.getX() << ", " << withRef.getY() << endl;
x = 3.9;
y = 5.4;
cout << "withRef: " << withRef.getX() << ", " << withRef.getY() << endl;
}
I have a window application of 1024 width and 768 height and contains a bunch of meteorites, ships and boats. The meteorites freely roam across the window driven by forces.
The forces are: random position, towards/away from boat, towards/away from ship and cohesion, seperation, alignment to other meteorites
I feel like the forces are not fully working since they sometimes move off the screen and move with inverted velocity eg: they are roaming from top right straight to top left and when reached go straight to bottom left.
Are my calculations correct or did I mess up something at the forces?
Meteorite header:
#include <chrono>
#include <cmath>
#include <array>
#include <random>
#include <algorithm>
using scalar = float;
template <typename Scalar> class basic_vector2d {
public:
constexpr basic_vector2d() noexcept = default;
constexpr basic_vector2d(Scalar x, Scalar y) noexcept : x_{ x }, y_{ y } {}
constexpr Scalar x() const noexcept { return x_; }
constexpr void x(Scalar newX) noexcept { x_ = newX; }
constexpr Scalar y() const noexcept { return y_; }
constexpr void y(Scalar newY) noexcept { y_ = newY; }
constexpr bool operator==(basic_vector2d other) const noexcept {
return x_ == other.x_ && y_ == other.y_;
}
constexpr bool operator!=(basic_vector2d other) const noexcept {
return x_ != other.x_ || y_ != other.y_;
}
constexpr basic_vector2d& operator+=(basic_vector2d other) noexcept {
x_ += other.x_;
y_ += other.y_;
return *this;
}
constexpr basic_vector2d& operator-=(basic_vector2d other) noexcept {
x_ -= other.x_;
y_ -= other.y_;
return *this;
}
constexpr basic_vector2d& operator*=(Scalar s) noexcept {
x_ *= s;
y_ *= s;
return *this;
}
constexpr basic_vector2d& operator/=(Scalar s) noexcept {
x_ /= s;
y_ /= s;
return *this;
}
private:
Scalar x_{};
Scalar y_{};
};
template <typename Scalar>
constexpr basic_vector2d<Scalar> operator-(basic_vector2d<Scalar> a,
basic_vector2d<Scalar> b) {
return { a.x() - b.x(), a.y() - b.y() };
}
template <typename Scalar>
constexpr basic_vector2d<Scalar> operator+(basic_vector2d<Scalar> a,
basic_vector2d<Scalar> b) {
return { a.x() + b.x(), a.y() + b.y() };
}
template <typename Scalar>
constexpr basic_vector2d<Scalar> operator*(basic_vector2d<Scalar> v, scalar s) {
return v *= s;
}
template <typename Scalar>
constexpr basic_vector2d<Scalar> operator*(scalar s, basic_vector2d<Scalar> v) {
return operator*(v, s);
}
template <typename Scalar>
constexpr basic_vector2d<Scalar> operator/(basic_vector2d<Scalar> v, scalar s) {
return v /= s;
}
template <typename Scalar>
constexpr basic_vector2d<Scalar> operator/(scalar s, basic_vector2d<Scalar> v) {
return operator/(v, s);
}
template <typename Scalar>
constexpr scalar dot(basic_vector2d<Scalar> a, basic_vector2d<Scalar> b) {
return a.x() * b.x() + a.y() * b.y();
}
template <typename Scalar> constexpr auto norm(basic_vector2d<Scalar> p) {
return std::sqrt(dot(p, p));
}
template <typename Scalar>
constexpr basic_vector2d<Scalar> normalize(basic_vector2d<Scalar> p) {
auto ls = norm(p);
return { p.x() / ls, p.y() / ls };
}
using vector2d = basic_vector2d<scalar>;
template <typename T> class basic_size {
public:
constexpr basic_size() noexcept = default;
constexpr basic_size(T width, T height) noexcept
: width_{ width }, height_{ height } {}
constexpr T width() const noexcept { return width_; }
constexpr T height() const noexcept { return height_; }
constexpr void width(T new_width) noexcept { width_ = new_width; }
constexpr void height(T new_height) noexcept { height_ = new_height; }
constexpr basic_size& operator*=(T x) {
width(width() * x);
height(height() * x);
return *this;
}
private:
T width_{};
T height_{};
};
using size = basic_size<scalar>;
template <typename Scalar> class basic_rectangle {
public:
constexpr basic_rectangle(basic_vector2d<Scalar> top_left,
basic_size<Scalar> size)
: top_left_{ top_left }, size_{ size } {}
constexpr basic_vector2d<Scalar> const& top_left() const noexcept {
return top_left_;
}
constexpr basic_size<Scalar> const& size() const noexcept { return size_; }
private:
basic_vector2d<Scalar> top_left_;
basic_size<Scalar> size_;
};
using rectangle = basic_rectangle<scalar>;
inline float to_seconds(std::chrono::nanoseconds dt) {
return std::chrono::duration_cast<std::chrono::duration<float>>(dt).count();
}
class meteorite {
public:
meteorite(int id, vector2d location);
int id;
/*!
* Called every tick
* \param dt the time that has passed since the previous tick
*/
void act(std::chrono::nanoseconds dt);
vector2d location() const { return location_; }
std::vector<vector2d> random_meteorite_locations(std::size_t n);
private:
vector2d velocity;
scalar max_velocity;
vector2d location_;
vector2d acceleration;
void location(vector2d loc) { location_ = loc; }
void random_position_force();
void screen_force(std::chrono::nanoseconds dt);
void move(std::chrono::nanoseconds dt);
void add_force(vector2d force);
void island_avoidance();
};
Meteorite source:
#include "meteorite.h"
meteorite::meteorite(int id, vector2d location) : id(id), velocity{ 0, 0 }, max_velocity(0.15), acceleration{ 0, 0 }, location_(location) {}
void meteorite::act(std::chrono::nanoseconds dt) {
move(dt);
}
void meteorite::move(std::chrono::nanoseconds dt) {
this->location(this->location() + velocity);
random_position_force();
screen_force(dt);
this->velocity += this->acceleration * to_seconds(dt);
// prevent velocity from exceeding max_velocity
float velocity_length = std::sqrt((this->velocity.x() * this->velocity.x()) + (this->velocity.y() * this->velocity.y()));
if (velocity_length >= this->max_velocity) {
this->velocity = normalize(this->velocity) * this->max_velocity;
}
/*directions:
* y -1 up
* y 1 down
*
* x 1 right
* x -1 left
*/
// reset acceleration to 0 for the next set of forces to be applied
this->acceleration = vector2d(0, 0);
}
// add force propeling meteorite to a random position
void meteorite::random_position_force() {
float x = (rand() % 100 - 50);
float y = (rand() % 100 - 50);
add_force(this->velocity + vector2d((x / 5), (y / 5)));
}
void meteorite::add_force(vector2d force) {
this->acceleration += force;
}
void meteorite::screen_force(std::chrono::nanoseconds dt)
{
auto new_position = this->location() + (this->velocity + (this->acceleration * to_seconds(dt)));
auto height = 1068 - 32;
auto width = 724 - 32;
if (new_position.x() <= 32) {
vector2d screen_vector = vector2d(0, 0);
if (this->acceleration.x() < 0)
{
screen_vector = vector2d(-this->acceleration.x() * 2, 0);
}
add_force(screen_vector);
}
else if (new_position.x() >= width)
{
vector2d screen_vector = vector2d(0, 0);
if (this->acceleration.x() > 0)
{
screen_vector = vector2d(-this->acceleration.x() * 2, 0);
}
add_force(screen_vector);
}
if (new_position.y() <= 32) {
vector2d screen_vector = vector2d(0, 0);
if (this->acceleration.y() < 0)
{
screen_vector = vector2d(0, -this->acceleration.y() * 2);
}
add_force(screen_vector);
}
else if (new_position.y() >= height)
{
vector2d screen_vector = vector2d(0, 0);
if (this->acceleration.y() > 0)
{
screen_vector = vector2d(0, -this->acceleration.y() * 2);
}
add_force(screen_vector);
}
}
std::vector<vector2d> meteorite::random_meteorite_locations(std::size_t n) {
// from 0x2 to 13x17 = 195
// from 13x0 to 28x9 = 135
// from 20x9 to 32x19 = 120
// from 6x17 to 25x24 = 133
// sum = 583
std::random_device rd{};
std::default_random_engine re{ rd() };
std::uniform_int_distribution<> id{ 0, 583 };
std::uniform_real_distribution<scalar> sd{ 0, 1 };
auto rv = [&](rectangle const& r) {
return r.top_left() + vector2d{ r.size().width() * sd(re),
r.size().height() * sd(re) };
};
std::array<rectangle, 4> rects{
rectangle{vector2d{0.1f, 2}, size{13, 15}},
rectangle{vector2d{13.f, 0.1f}, size{15, 9}},
rectangle{vector2d{20, 9}, size{12, 10}},
rectangle{vector2d{6, 17}, size{17, 6}} };
auto to_index = [](int i) -> std::size_t {
if (i < 195)
return 0;
else if (i < 330)
return 1;
else if (i < 450)
return 2;
else
return 3;
};
std::vector<vector2d> result(n);
std::generate_n(result.begin(), result.size(), [&] {
auto val = id(re);
auto index = to_index(val);
auto rect = rects[index];
return 32 * rv(rect);
});
return result;
}
Main.cpp
#include <iostream>
#include "meteorite.h"
int main()
{
meteorite m = meteorite{ 0, {} };
std::vector<meteorite*> meteorites;
std::vector<vector2d> locations = m.random_meteorite_locations(1);
int i = 1;
for (auto& loc : locations) {
meteorites.push_back(new meteorite(i, loc));
}
auto t_prev = std::chrono::high_resolution_clock::now();
while (true) {
auto t_current = std::chrono::high_resolution_clock::now();
std::chrono::nanoseconds dt = std::chrono::nanoseconds(200);
t_prev = t_current;
for (auto& m : meteorites) {
m->act(dt);
std::cout << m->location().x() << " " << m->location().y() << "\n";
}
}
for (auto& m : meteorites) {
delete m;
}
}
You're computing the new position incorrectly in both places, move() and screen_force(). You're doing s = s0 + (v + a * t), but you should be doing s = s0 + v * t + (a * t^2) / 2.
Here's a working example:
http://cpp.sh/9uu3w
I am defining a Vec2 class with a friend functions. I am getting the error: argument list for class template Vec2 is missing for the friend function: friend Vec2 operator * (const T &r, const Vec2 &v).
template<typename T>
class Vec2
{
public:
Vec2() : x(0), y(0) {}
Vec2(T xx) : x(xx), y(xx) {}
Vec2(T xx, T yy) : x(xx), y(yy) {}
Vec2 operator + (const Vec2 &v) const
{ return Vec2(x + v.x, y + v.y); }
Vec2 operator / (const T &r) const
{ return Vec2(x / r, y / r); }
Vec2 operator * (const T &r) const
{ return Vec2(x * r, y * r); }
Vec2& operator /= (const T &r)
{ x /= r, y /= r; return *this; }
Vec2& operator *= (const T &r)
{ x *= r, y *= r; return *this; }
friend std::ostream& operator << (std::ostream &s, const Vec2<T> &v)
{
return s << '[' << v.x << ' ' << v.y << ']';
}
friend Vec2 operator * (const T &r, const Vec2<T> &v)
{ return Vec2(v.x * r, v.y * r); }
T x, y;
};
normally when i get this error, I go looking for a function i forgot to define, but i'm getting this from the assignment operator of a class, and i never declared it. The error goes like this:
1>SYNC_D3D11Model_Defs.obj : error LNK2019: unresolved external symbol "public: struct SYNC::Vector2 & __thiscall SYNC::Vector2::operator=(struct SYNC::Vector2 const &)" (??4Vector2#SYNC##QAEAAU01#ABU01##Z) referenced in function "public: struct VERTEX_TYPE & __thiscall VERTEX_TYPE::operator=(struct VERTEX_TYPE const &)" (??4VERTEX_TYPE##QAEAAU0#ABU0##Z)
1>SYNC_D3D11Model_Defs.obj : error LNK2019: unresolved external symbol "public: struct SYNC::Vector4 & __thiscall SYNC::Vector4::operator=(struct SYNC::Vector4 const &)" (??4Vector4#SYNC##QAEAAU01#ABU01##Z) referenced in function "public: struct VERTEX_TYPE & __thiscall VERTEX_TYPE::operator=(struct VERTEX_TYPE const &)" (??4VERTEX_TYPE##QAEAAU0#ABU0##Z)
which essentially boils down to, VERTEX_TYPE::operator= is trying to use SYNC::Vector2::operator=(const SYNC::Vector2 &) and SYNC::Vector4::operator=(SYNC::Vector2 &) but cannot find the defintions. The problem with this is, 1) I never declared, defined, or used the assignment operator in VERTEX_TYPE, 2) even if i had, those functions are indeed defined within the .cpp. Here see for yourself. These are the two offending structs and their definitions.
SYNC_Vectors.h
#ifndef SYNC_VECTORS_H
#define SYNC_VECTORS_H
#include <cmath>
namespace SYNC
{
struct Vector2
{
Vector2();
Vector2(const Vector2 & vec);
Vector2(const float & x, const float & y);
~Vector2();
inline Vector2 & operator=(const Vector2 & rhs);
inline Vector2 operator+(Vector2 rhs);
inline Vector2 operator-(Vector2 rhs);
inline Vector2 operator*(const float & scalar);
friend inline Vector2 operator*(const float & scalar, Vector2 rhs);
inline Vector2 & operator+=(const Vector2 & rhs);
inline Vector2 & operator-=(const Vector2 & rhs);
inline Vector2 & operator*=(const float & scalar);
bool operator==(const Vector2 & rhs);
bool operator!=(const Vector2 & rhs);
inline Vector2 & operator++();
inline Vector2 & operator--();
inline void Normal(Vector2 & rhs);
Vector2 & Normalize();
void Normalize(Vector2 & rhs);
Vector2 & Dot(const Vector2 & rhs1, const Vector2 & rhs2);
static float Cross(const Vector2 & lhs, Vector2 & rhs);
float x;
float y;
};
struct Vector3
{
Vector3();
Vector3(const Vector3 & vec);
Vector3(const float & x, const float & y, const float & z);
virtual ~Vector3();
inline Vector3 & operator=(const Vector3 & rhs);
inline Vector3 operator+(Vector3 rhs);
inline Vector3 operator-(Vector3 rhs);
inline Vector3 operator*(const float & scalar);
friend inline Vector3 operator*(const float & scalar, Vector3 rhs);
inline Vector3 & operator+=(const Vector3 & rhs);
inline Vector3 & operator-=(const Vector3 & rhs);
inline Vector3 & operator*=(const float & rhs);
inline bool operator==(const Vector3 & rhs);
inline bool operator!=(const Vector3 & rhs);
inline Vector3 & operator++();
inline Vector3 & operator--();
void Normalize();
void Normalize(Vector3 rhs);
void Dot(const Vector3 & vec1, const Vector3 & vec2);
void Cross(const Vector3 & vec1, const Vector3 & vec2);
float x;
float y;
float z;
};
struct Vector4
{
Vector4();
Vector4(const Vector4 & rhs);
Vector4(const float & x, const float & y, const float & z, const float & w);
~Vector4();
inline Vector4 & operator=(const Vector4 & rhs);
inline Vector4 operator+(Vector4 rhs);
inline Vector4 operator-(Vector4 rhs);
inline Vector4 operator*(const float & scalar);
friend inline Vector4 operator*(const float & scalar, Vector4 rhs);
inline Vector4 & operator+=(const Vector4 & rhs);
inline Vector4 & operator-=(const Vector4 & rhs);
inline Vector4 & operator*=(const float & rhs);
inline bool operator==(const Vector4 & rhs);
inline bool operator!=(const Vector4 & rhs);
inline Vector4 & operator++();
inline Vector4 & operator--();
float x;
float y;
float z;
float w;
};
struct Quaternion
{
Quaternion();
Quaternion(const Quaternion & rhs);
Quaternion(const Vector3 & v, const float & w);
~Quaternion();
inline Quaternion & operator=(const Quaternion & rhs);
inline bool operator==(const Quaternion & rhs);
inline bool operator!=(const Quaternion & rhs);
inline Quaternion operator*(Quaternion rhs);
inline Quaternion & mul(const Quaternion & rhs);
inline void Conjugate();
inline void Conjugate(Quaternion &);
inline void Normalize();
inline void Normalize(Quaternion &);
Vector3 v;
float w;
};
}
#endif
SYNC_Vectors.cpp
#include "SYNC_Vectors.h"
//-----------------------------------------
// SYNC::Vector2 defintions
//-----------------------------------------
SYNC::Vector2::Vector2()
{
x = 0;
y = 0;
}
SYNC::Vector2::Vector2(const Vector2 & vec)
{
x = vec.x;
y = vec.y;
}
SYNC::Vector2::Vector2(const float & ix, const float & iy)
{
x = ix;
y = iy;
}
SYNC::Vector2::~Vector2()
{
}
SYNC::Vector2 & SYNC::Vector2::operator=(const SYNC::Vector2 & rhs)
{
x = rhs.x;
y = rhs.y;
return *this;
}
SYNC::Vector2 SYNC::Vector2::operator+(SYNC::Vector2 rhs)
{
rhs.x += x;
rhs.y += y;
return rhs;
}
SYNC::Vector2 SYNC::Vector2::operator-(SYNC::Vector2 rhs)
{
rhs.x -= x;
rhs.y -= y;
return rhs;
}
SYNC::Vector2 SYNC::Vector2::operator*(const float & scalar)
{
SYNC::Vector2 ret( x * scalar, y * scalar);
return ret;
}
SYNC::Vector2 operator*(const float & scalar, SYNC::Vector2 rhs)
{
rhs.x *= scalar;
rhs.y *= scalar;
return rhs;
}
SYNC::Vector2 & SYNC::Vector2::operator+=(const Vector2 & rhs)
{
x += rhs.x;
y += rhs.y;
return *this;
}
SYNC::Vector2 & SYNC::Vector2::operator-=(const Vector2 & rhs)
{
x -= rhs.x;
y -= rhs.y;
return *this;
}
SYNC::Vector2 & SYNC::Vector2::operator*=(const float & scalar)
{
x *= scalar;
y *= scalar;
return *this;
}
bool SYNC::Vector2::operator==(const Vector2 & rhs)
{
if(rhs.x == x && rhs.y == y)
return true;
else
return false;
}
bool SYNC::Vector2::operator!=(const Vector2 & rhs)
{
if(rhs.x != x || rhs.y != y)
return true;
else
return false;
}
SYNC::Vector2 & SYNC::Vector2::operator++()
{
x++;
y++;
return *this;
}
SYNC::Vector2 & SYNC::Vector2::operator--()
{
x--;
y--;
return *this;
}
void SYNC::Vector2::Normal(Vector2 & rhs)
{
rhs.x = y;
rhs.y = -x;
}
SYNC::Vector2 & SYNC::Vector2::Normalize()
{
if(x > 0.000001 || y > 0.000001)
{
float length = sqrt((x * x) + (y * y));
x /= length;
y /= length;
}
else
{
x = 0;
y = 0;
}
return *this;
}
void SYNC::Vector2::Normalize(Vector2 & rhs)
{
if(x > 0.000001 || y > 0.000001)
{
float length = sqrt((x * x) + (y * y));
rhs.x = x / length;
rhs.y = y / length;
}
else
{
rhs.x = 0;
rhs.y = 0;
}
}
SYNC::Vector2 & SYNC::Vector2::Dot(const Vector2 & rhs1, const Vector2 & rhs2)
{
x = rhs1.x * rhs2.x;
y = rhs1.y * rhs2.y;
return *this;
}
float SYNC::Vector2::Cross(const Vector2 & rhs1, Vector2 & rhs2)
{
return ((rhs1.x * rhs2.y) - (rhs1.y * rhs2.x));
}
//-----------------------------------------
// SYNC::Vector3 defintions
//-----------------------------------------
SYNC::Vector3::Vector3()
{
x = 0;
y = 0;
z = 0;
}
SYNC::Vector3::Vector3(const Vector3 & vec)
{
x = vec.x;
y = vec.y;
z = vec.z;
}
SYNC::Vector3::Vector3(const float & ix, const float & iy, const float & iz)
{
x = ix;
y = iy;
z = iz;
}
SYNC::Vector3::~Vector3()
{
}
SYNC::Vector3 & SYNC::Vector3::operator=(const Vector3 & rhs)
{
x = rhs.x;
y = rhs.y;
z = rhs.z;
return *this;
}
SYNC::Vector3 SYNC::Vector3::operator+(Vector3 rhs)
{
rhs.x += x;
rhs.y += y;
rhs.z += z;
return rhs;
}
SYNC::Vector3 SYNC::Vector3::operator-(Vector3 rhs)
{
rhs.x -= x;
rhs.y -= y;
rhs.z -= z;
return rhs;
}
SYNC::Vector3 SYNC::Vector3::operator*(const float & rhs)
{
Vector3 ret(x * rhs, y * rhs, z * rhs);
return ret;
}
SYNC::Vector3 operator*(const float & scalar, SYNC::Vector3 rhs)
{
rhs.x *= scalar;
rhs.y *= scalar;
rhs.z *= scalar;
return rhs;
}
SYNC::Vector3 & SYNC::Vector3::operator+=(const Vector3 & rhs)
{
x += rhs.x;
y += rhs.y;
z += rhs.z;
return *this;
}
SYNC::Vector3 & SYNC::Vector3::operator-=(const Vector3 & rhs)
{
x -= rhs.x;
y -= rhs.y;
z -= rhs.z;
return *this;
}
SYNC::Vector3 & SYNC::Vector3::operator*=(const float & rhs)
{
x *= rhs;
y *= rhs;
z *= rhs;
return *this;
}
bool SYNC::Vector3::operator==(const Vector3 & rhs)
{
if(x == rhs.x && y == rhs.y && z == rhs.z)
return true;
else
return false;
}
bool SYNC::Vector3::operator!=(const Vector3 & rhs)
{
if(x != rhs.x || y != rhs.y || z != rhs.z)
return true;
else
return false;
}
SYNC::Vector3 & SYNC::Vector3::operator++()
{
x++;
y++;
z++;
return *this;
}
SYNC::Vector3 & SYNC::Vector3::operator--()
{
x--;
y--;
z--;
return *this;
}
void SYNC::Vector3::Normalize()
{
if(x > 0.000001 || y > 0.000001 || z > 0.000001)
{
float length = sqrt((x * x) + (y * y) + (z * z));
x /= length;
y /= length;
z /= length;
}
else
{
x = 0;
y = 0;
z = 0;
}
}
void SYNC::Vector3::Normalize(Vector3 rhs)
{
if(x > 0.000001 || y > 0.000001 || z > 0.000001)
{
float length = sqrt((x * x) + (y * y) + (z * z));
rhs.x /= length;
rhs.y /= length;
rhs.z /= length;
}
else
{
rhs.x = 0;
rhs.y = 0;
rhs.z = 0;
}
}
void SYNC::Vector3::Dot(const Vector3 & vec1, const Vector3 & vec2)
{
x = vec1.x * vec2.x;
y = vec1.y * vec2.y;
z = vec1.z * vec2.z;
}
void SYNC::Vector3::Cross(const Vector3 & vec1, const Vector3 & vec2)
{
x = ((vec1.y * vec2.z) - (vec1.z * vec2.y));
y = ((vec1.z * vec2.x) - (vec1.x * vec2.z));
z = ((vec1.x * vec2.y) - (vec1.y * vec2.x));
}
//-----------------------------------------
// SYNC::Vector4 defintions
//-----------------------------------------
SYNC::Vector4::Vector4()
{
x = 0;
y = 0;
z = 0;
w = 0;
}
SYNC::Vector4::Vector4(const Vector4 & rhs)
{
x = rhs.x;
y = rhs.y;
z = rhs.z;
w = rhs.w;
}
SYNC::Vector4::Vector4(const float & ix, const float & iy, const float & iz, const float & iw)
{
x = ix;
y = iy;
z = iz;
w = iw;
}
SYNC::Vector4::~Vector4()
{
}
SYNC::Vector4 & SYNC::Vector4::operator=(const Vector4 & rhs)
{
x = rhs.x;
y = rhs.y;
z = rhs.z;
w = rhs.w;
return *this;
}
SYNC::Vector4 SYNC::Vector4::operator+(Vector4 rhs)
{
rhs.x += x;
rhs.y += y;
rhs.z += z;
rhs.w += w;
return rhs;
}
SYNC::Vector4 SYNC::Vector4::operator-(Vector4 rhs)
{
rhs.x += x;
rhs.y += y;
rhs.z += z;
rhs.w += w;
return rhs;
}
SYNC::Vector4 SYNC::Vector4::operator*(const float & rhs)
{
Vector4 ret( x * rhs, y * rhs, z * rhs, w * rhs);
return ret;
}
SYNC::Vector4 operator*(const float & scalar, SYNC::Vector4 rhs)
{
rhs.x *= scalar;
rhs.y *= scalar;
rhs.z *= scalar;
rhs.w *= scalar;
return rhs;
}
SYNC::Vector4 & SYNC::Vector4::operator+=(const Vector4 & rhs)
{
x += rhs.x;
y += rhs.y;
z += rhs.z;
w += rhs.w;
return *this;
}
SYNC::Vector4 & SYNC::Vector4::operator-=(const Vector4 & rhs)
{
x += rhs.x;
y += rhs.y;
z += rhs.z;
w += rhs.w;
return *this;
}
SYNC::Vector4 & SYNC::Vector4::operator*=(const float & rhs)
{
x *= rhs;
y *= rhs;
z *= rhs;
w *= rhs;
}
bool SYNC::Vector4::operator==(const Vector4 & rhs)
{
if(x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w)
return true;
else
return false;
}
bool SYNC::Vector4::operator!=(const Vector4 & rhs)
{
if(x != rhs.x || y != rhs.y || z != rhs.z || w != rhs.w)
return true;
else
return false;
}
SYNC::Vector4 & SYNC::Vector4::operator++()
{
x++;
y++;
z++;
w++;
}
SYNC::Vector4 & SYNC::Vector4::operator--()
{
x--;
y--;
z--;
w--;
}
//---------------------------------
// SYNC::Quaternion definitions
//---------------------------------
SYNC::Quaternion::Quaternion()
{
v.x = 0;
v.y = 0;
v.z = 0;
w = 0;
}
SYNC::Quaternion::Quaternion(const Quaternion & rhs)
{
v.x = rhs.v.x;
v.y = rhs.v.y;
v.z = rhs.v.z;
w = rhs.w;
}
SYNC::Quaternion::Quaternion(const Vector3 & iv, const float & iw)
{
v = iv;
w = iw;
}
SYNC::Quaternion::~Quaternion()
{
}
SYNC::Quaternion & SYNC::Quaternion::operator=(const Quaternion & rhs)
{
v = rhs.v;
w = rhs.w;
}
bool SYNC::Quaternion::operator==(const Quaternion & rhs)
{
if(v == rhs.v && w == rhs.w)
return true;
else
return false;
}
bool SYNC::Quaternion::operator!=(const Quaternion & rhs)
{
if(v != rhs.v || w != rhs.w)
return true;
else
return false;
}
SYNC::Quaternion SYNC::Quaternion::operator*(Quaternion rhs)
{
rhs.v.x = (w * rhs.v.x) + (v.x * rhs.w) + (v.y * rhs.v.z) - (v.z * rhs.v.y);
rhs.v.y = (w * rhs.v.y) - (v.x * rhs.v.z) + (v.y * rhs.w) + (v.z * rhs.v.x);
rhs.v.z = (w * rhs.v.z) + (v.x * rhs.v.y) - (v.y * rhs.v.x) + (v.z * rhs.w);
rhs.w = (w * rhs.w) - (v.x * rhs.v.x) - (v.y * rhs.v.y) - (v.z * rhs.v.z);
return rhs;
}
SYNC::Quaternion & SYNC::Quaternion::mul(const Quaternion & rhs)
{
v.x = (w * rhs.v.x) + (v.x * rhs.w) + (v.y * rhs.v.z) - (v.z * rhs.v.y);
v.y = (w * rhs.v.y) - (v.x * rhs.v.z) + (v.y * rhs.w) + (v.z * rhs.v.x);
v.z = (w * rhs.v.z) + (v.x * rhs.v.y) - (v.y * rhs.v.x) + (v.z * rhs.w);
w = (w * rhs.w) - (v.x * rhs.v.x) - (v.y * rhs.v.y) - (v.z * rhs.v.z);
return *this;
}
void SYNC::Quaternion::Conjugate()
{
v *= -1;
}
void SYNC::Quaternion::Conjugate(Quaternion & rhs)
{
rhs.v = v * -1;
rhs.w = w;
}
void SYNC::Quaternion::Normalize()
{
float length = sqrt((w*w) + (v.x * v.x) + (v.y * v.y) + (v.z * v.z));
if(length > 0.000001)
{
v.x /= length;
v.y /= length;
v.z /= length;
w /= length;
}
else
{
v.x = 0;
v.y = 0;
v.z = 0;
w = 0;
}
}
void SYNC::Quaternion::Normalize(Quaternion & rhs)
{
float length = sqrt((w*w) + (v.x * v.x) + (v.y * v.y) + (v.z * v.z));
if(length > 0.000001)
{
rhs.v.x = v.x / length;
rhs.v.y = v.y / length;
rhs.v.z = v.z / length;
rhs.w = w / length;
}
else
{
rhs.v.x = 0;
rhs.v.y = 0;
rhs.v.z = 0;
rhs.w = 0;
}
}
syncmod.h
#ifndef SYNCMOD_H
#define SYNCMOD_H
#include <fstream>
#include <map>
#include <string>
#include "SYNC_Vectors.h"
struct SYNCMODEL_HEADER
{
char id[8];
short ver[2];
long m_numOfVertices;
long m_numOfIndices;
std::string m_modelName;
};
struct VERTEX_TYPE
{
SYNC::Vector3 position;
SYNC::Vector4 color;
SYNC::Vector3 normal;
SYNC::Vector3 binormal;
SYNC::Vector3 tangent;
SYNC::Vector2 textureCoords;
};
class SYNCMODEL_MATERIAL_HEADER
{
enum DATA_TYPE{MATERIAL_SHORT , MATERIAL_INT, MATERIAL_LONG, MATERIAL_FLOAT, MATERIAL_DOUBLE};
struct Data_Index
{
DATA_TYPE type;
char * accessor;
};
int m_numOfElements;
std::map<std::string, Data_Index> m_Indices;
};
std::ifstream & operator>>(std::ifstream & stream, SYNCMODEL_HEADER & header);
#endif
syncmod.cpp
#include "syncmod.h"
std::ifstream & operator>>(std::ifstream & stream, SYNCMODEL_HEADER & header)
{
stream.read(header.id, 8);
stream.read(reinterpret_cast<char *>(&header.ver), sizeof(short) * 2);
stream.read(reinterpret_cast<char *>(&header.m_numOfVertices), sizeof(long));
stream.read(reinterpret_cast<char *>(&header.m_numOfIndices), sizeof(long));
std::getline(stream, header.m_modelName, '\0');
stream.seekg(static_cast<int>(stream.tellg()) - 1);
return stream;
}
anyone know what the heck is going on here?
edit: Just an additional observation here, why is it throwing up flags with just the assignment operator of these two and not SYNC::Vector3?
The header SYNC_Vectors.h declares:
inline Vector2 & operator=(const Vector2 & rhs);
and the source file SYNC_Vectors.cpp defines:
SYNC::Vector2 & SYNC::Vector2::operator=(const SYNC::Vector2 & rhs)
Remove the inline from the declaration and things should get better. <g> Or, as we've discussed, put the definitions of the inline functions into SYNC_Vectors.h, either by copying the text or with a #include directive at the end of the file. For the latter, most people use a distinctive extension, often .inl.