I have written a small container class which groups a 3D position, a normal vector and a texture coordinate into one object. It uses the glm library for the actual data types (vec2 and vec3). This class is named Vertex
. Here is the source:
Vertex.h
#ifndef CPP3D_VERTEX_H
#define CPP3D_VERTEX_H
#include <iostream>
#include <glm/glm.hpp>
namespace cpp3d {
class Vertex {
public:
glm::vec3 position;
glm::vec3 normal;
glm::vec2 texCoord;
Vertex();
Vertex(const glm::vec3& position);
Vertex(const glm::vec3& position, const glm::vec3& normal);
Vertex(const glm::vec3& position, const glm::vec3& normal, const glm::vec2& texCoord);
bool operator==(const Vertex& other);
};
std::ostream& operator<<(std::ostream &stream, const Vertex& vertex);
std::istream& operator>>(std::istream &stream, Vertex& vertex);
}
#endif
Vertex.cc
#include "Vertex.h"
namespace cpp3d {
using namespace glm;
using namespace std;
Vertex::Vertex() {
}
Vertex::Vertex(const vec3& position) :
position(position) {
}
Vertex::Vertex(const vec3& position, const vec3& normal) :
position(position), normal(normal) {
}
Vertex::Vertex(const vec3& position, const vec3& normal, const vec2& texCoord) :
position(position), normal(normal), texCoord(texCoord) {
}
bool Vertex::operator ==(const Vertex& other) {
return position == other.position && normal == other.normal && texCoord == other.texCoord;
}
ostream& operator<<(ostream &stream, const Vertex& vertex) {
stream.write(reinterpret_cast<const char *>(&vertex), sizeof(vertex));
return stream;
}
istream& operator>>(istream &stream, Vertex& vertex) {
stream.read(reinterpret_cast<char *>(&vertex), sizeof(vertex));
return stream;
}
}
As you can see I've overloaded the stream operators to write and read the data the object contains. For this I simply dump the whole object which results in writing eight float numbers so the output will be 32 bytes. I know that this is a very simple file format but I want to read the data as fast as possible so I don't want to parse text files. I also don't really care about different endiannesses (unless it can be implemented without speed impact). And I know the file format will change when I add more members to the class (This will most likely not happen but when it happens then I also want to change the file format anyway)
My main concern is if this code guarantees that it always writes and reads 32 bytes. I'm pretty new to C++ and my ancient C knowledge tells me that there is (or was) some kind of packed structs and aligned structs where the compiler could decide to align 8 bit values to 16 bits for some reason. I don't want some compiler (current or future ones) to store the 32 bit floats in 64 bit values because this obviously changes the binary data format. Can this happen with my code when compiled on specific platforms? If yes, what's the best way to write binary floats to a stream then? Shall I write each coordinate in each vector with a separate call to write()
? Or are there other/better techniques to write and read the binary data?
If you see other issues with my code which are not related to my question please feel free to comment anyway. As a C++ newbie I'm eager to learn.
glm::vec*
structs do not change, you can probably get away with this. It would be safer to write to each data member separately. Just make sure your class is trivially copyable. \$\endgroup\$