I have this structure:
struct Vertex {
Vertex(float px, float py, float pz,
float nx, float ny, float nz,
float tx, float ty) : position(px, py, pz),
normals(nx, ny, nz),
texCoords(tx, ty) {}
XMFLOAT3 position;
XMFLOAT3 normals;
XMFLOAT2 texCoords;
};
and I need to fill an array of that with some vectors:
std::vector<XMFLOAT3> positions;
std::vector<XMFLOAT3> normals;
std::vector<XMFLOAT2> texCoords;
The length of the array is given by
int numVertices;
I' d like to fill the array of struct Vertex with the vectors given. How can I do that?
I tried to initialize the array in this way:
Vertex points[numVertices];
but that var does not have a constant value.
Thank you for your help.
std::vector is the best option to create a dynamic array.
It takes care of memory management for you.
You can access the contents of the array using std::vector::data, std::vector::operator[], std::vector::iterator.
You can process each element of a std::vector using a range-for loop.
Instead of
Vertex points[numVertices];
use
std::vector<Vertex> points(numVertices);
If you must use raw arrays, you can try this. Assuming XMFLOAT3, XMFLOAT2 is something like follows:
struct XMFLOAT3 {
XMFLOAT3(float x, float y, float z) : _x(x), _y(y), _z(z) {};
float _x;
float _y;
float _z;
};
struct XMFLOAT2 {
XMFLOAT2(float x, float y) : _x(x), _y(y) {};
float _x;
float _y;
};
define an init function to initialize Vertex array by dynamically allocating and initializing the elements as:
Vertex **
initVertex(int numVertices)
{
Vertex **points = new Vertex *[numVertices];
for (int i = 0; i < numVertices; ++i) {
points[i] = new Vertex(positions[i]._x, positions[i]._y, positions[i]._x,
normals[i]._x, normals[i]._y, normals[i]._z,
texCoords[i]._x, texCoords[i]._y);
}
return points;
}
You can use Vertex **points = initVertex(numVertices) and dereference each element.
If you must have Vertex *points then you can use this function to create the initialized array of Vertices:
Vertex *
initVertex2(int numVertices)
{
char *points_buf = new char[sizeof(Vertex) * numVertices];
Vertex *points = reinterpret_cast<Vertex *>(points_buf);
for (int i = 0; i < numVertices; ++i) {
new (points_buf + i * sizeof(Vertex))
Vertex(positions[i]._x, positions[i]._y, positions[i]._x,
normals[i]._x, normals[i]._y, normals[i]._z,
texCoords[i]._x, texCoords[i]._y);
}
return points;
}
And call it Vertex *points = initVertex2(numVertices) and use array indexing to access each element.
Related
I've been this trying for several hours now. I cannot find a way to pass a fixed-size array to an operator. I found some stuff here on stackoverflow and tried it that way, as you can see in my code, but it won't work at all. The task is, that the code shouldn't be compiled if the array is not of size 3, that means, that if the array is of size 2 or size 4, that I should get a compile error. Can someone tell me how to implement this? Thanks in advance! :)
class Vec3 {
private:
int x, y, z;
public:
Vec3 (int x, int y, int z) : x(x), y(y), z(z) {}
int getX () const
{
return x;
}
int getY () const
{
return y;
}
int getZ () const
{
return z;
}
};
Vec3 operator+(Vec3 &vec, int (*arr)[3]) {
int x,y,z;
x = vec.getX() + (*arr)[0];
y = vec.getY() + (*arr)[1];
z = vec.getZ() + (*arr)[2];
Vec3 result(x,y,z);
return result;
}
int main () {
Vec3 v1 (1,2,3);
int v3 [] = {2,4,6};
cout << "v1 + v3 = " << v1 + v3 << endl;
return 0;
}
You got the syntax slightly wrong. Instead of
Vec3 operator+(Vec3 &vec, int (*arr)[3])
it must be
Vec3 operator+(Vec3 &vec, int (&arr)[3])
to pass the array by reference. And you can drop the value-of-operator (*) before the array-access, so you end up with
Vec3 operator+(Vec3 &vec, int (&arr)[3]) {
int x,y,z;
x = vec.getX() + arr[0];
y = vec.getY() + arr[1];
z = vec.getZ() + arr[2];
Vec3 result(x,y,z);
return result;
}
Use template to do it:
template<size_t N>
Vec3 operator+(Vec3 &vec, int (&arr)[N]) {
static_assert(N==3,"wrong size of array");
// the rest of the code , small fix: arr[0] etc
static assert will be triggered when N is not equal to 3.
Demo
How can I convert the following class to a fixed-length float array?
class Vertex
{
public:
Vertex( float x = 0,
float y = 0,
float z = 0)
: x(x), y(y), z(z) {}
float x, y, z;
};
For example, I would like to use it like so:
Vertex v(0, 1, 0);
float arr[3] = v; // How to convert here?
Thanks!
Edit:
I should have added some background information before posting this question.
The reason why I'm using C-style arrays is because I want to combine the high level vertex objects into a vertex array for rendering with OpenGL, which as far as I know requires a collection of raw arrays (float[3]) or structs.
For that purpose I think user2079303's answer is the best option. However, if a more elegant solution exists that would be even better. :)
#include <iostream>
#include <array>
using namespace std;
class Vertex
{
public:
Vertex( float x = 0,
float y = 0,
float z = 0)
: x(x), y(y), z(z) {}
operator array<float, 3>() const {
return {x,y,z};
}
/* See #user2079303's answer for a compile-time check of the array dimension */
void fillArray(float arr[3]) {
arr[0] = x;
arr[1] = y;
arr[2] = z;
}
float x, y, z;
};
int main() {
Vertex v(1,1.4,2);
array<float, 3> arr = v;
float arr2[3];
v.fillArray(arr2);
for (int i = 0; i < 3; i++) {
cout << arr[i] << " " << arr2[i] << endl;
}
return 0;
}
Live Demo
std::array is as efficient as using a C-style array, no performance is lost. You can also use std::vector instead.
You can't just return and copy an array, even in C. That's why if you absolutely want to use a C array, you have to have a function like fillArray.
A class cannot be convertible to a (raw) array, because the cast operator would have to return an array, which is not allowed in c++. Furthermore, arrays cannot be copy-initialized anyway.
What you can do is define an array, and pass it to a function that populates the array according to the contents of an object:
void Vertex::fill_arr(float (&arr)[3]) {
arr[0] = x;
arr[1] = y;
arr[2] = z;
}
// usage
Vertex v(1, 2, 3);
float arr[3];
v.fill_arr(arr);
Another option is to use std::array which can be returned and copy-initialized normally.
You have many options, and it which you choose depends a lot on context. Here are four different ways to "convert" your vertex:
class Vertex
{
public:
Vertex(float x = 0,
float y = 0,
float z = 0)
: x(x), y(y), z(z) {}
operator array<float, 3> () const {
return {x, y, z};
}
array<float, 3> array_copy() const {
return {x, y, z};
}
unique_ptr<float[]> c_array_copy() const {
return unique_ptr<float[]>(new float[3]{ x, y, z });
}
void copy_into(float in[3]) const {
in[0] = x;
in[1] = y;
in[2] = z;
}
float x, y, z;
};
First, you can just cast the class using the () operator:
cout << "Direct access" << endl;
auto as_array = (array<float, 3>)vertex;
cout << as_array[0] << as_array[1] << as_array[2] << endl;
Second, you can let copy semantics to some work for you with array_copy():
cout << "Get a copy" << endl;
auto as_copy = vertex.array_copy();
cout << as_copy[0] << as_copy[1] << as_copy[2] << endl;
Third, you can get a more c-style array copy with a unique pointer to a dynamically allocated array:
cout << "Get a c-style copy" << endl;
auto as_c_copy = vertex.c_array_copy();
cout << as_c_copy[0] << as_c_copy[1] << as_c_copy[2] << endl;
Finally, you can copy into an out-parameter:
cout << "Copy onto an out-parameter" << endl;
float copied[3];
vertex.copy_into(copied);
cout << copied[0] << copied[1] << copied[2] << endl;
As I say, which you choose really depends on context and performance requirements.
Note that in no case can you just return a c-style array.
You can define a conversion operator to construct your array. Also I would suggest using a std::array instead of a raw array.
#include <array>
class Vertex
{
public:
Vertex(float x = 0.0f, float y = 0.0f, float z = 0.0f)
: x(x), y(y), z(z)
{}
float x;
float y;
float z;
operator const std::array<float, 3>() const
{
return {x, y, z};
}
};
int main()
{
Vertex v(0.0f, 1.0f, 0.0f);
std::array<float, 3> arr = v;
}
I have the following
std::vector<Cube> well = vector<Cube>();
createCube(well, x, y, z, id);
Later I try to insert a Cube into the vector like this,
void Viewer::createCube(std::vector<Cube> vec, int x, int y, int z, int id) {
float rgb[] = {0.0f, 0.0f, 1.0f};
vec.push_back(Cube(QMatrix4x4(), -1));
int loc = vec.size() - 1;
std::cout << "loc:" << loc << std::endl;
vec.at(vec.size() - 1).matrix.translate(x,y,z);
}
I get output loc = 0.
Why is it not the new Cube to my Vector?
You are passing the vector by value to the createCube function; that means that your vector is copied and then the element is added to the new vector and not to the original one. You can fix it by changing your method signature to:
void Viewer::createCube(std::vector<Cube>& vec, int x, int y, int z, int id)
For a little project I've been trying to build a application using OpenCL in combination with OpenGL using the relative python bindings (pyOpenGL and PyOpenCL). Toe be more precise it's supposed to be a generalized raytracer.
After installing both the OpenCL Intel SDK and the NVIDIA CUDA toolkit and using the IDE by intel to write the program I've encountered a problem:
Whenever I try to build the program either the intel compiler "stopped working" or the NVIDIA one gives me a "invalid value - " message. If I however only compile the program everything goes well and nothing bad happens.
If I deliberately place a mistake into the code, both compilers return proper compiler errors with line numbers and all that.
I was able to narrow down the problem to the __kernal function but I really can't understand why it wouldn't build but still compile? Is there something I'm missing?
(please excuse the probably bad opencl code. First time I'm writing in anything similar to C)
The Kernal:
__kernel void raytrace(__write_only image2d_t renderTexture,
int2 pos, __constant float projectionsMatrix[16],
//Mesh Data
__constant int* meshIndecies, __constant float3* meshVertices,
__constant float3* meshNormals, __constant float2* meshUV,
__constant int* meshTriangleIndecies, __constant int* meshTriangles,
//Material Data
__constant float4* emissions, __constant float4* ambients,
__constant float4* diffuses, __constant float4* speculars,
__constant float* shininesses,
//Object Data
__constant float* matricies, __constant int* meshes,
__constant int* materials) {
Mesh* meshData;
int pcMeshv = 0;
int pcMesht = 0;
for (int cMesh = 0; cMesh < sizeof(meshIndecies)/sizeof(int); cMesh++) {
Mesh data;
//assign data
for (int index = 0; index < meshIndecies[cMesh] - pcMeshv; index++) {
data.vertices[index] = meshVertices[pcMeshv + index];
data.normals[index] = meshNormals[pcMeshv + index];
data.uv[index] = meshUV[pcMeshv + index];
}
pcMeshv = meshIndecies[cMesh];
for (int index = 0; index < meshTriangleIndecies[cMesh] - pcMesht; index++) {
data.triangles[index] = meshTriangles[pcMesht + index];
}
pcMesht = meshTriangleIndecies[cMesh];
//add data to array
meshData[cMesh] = data;
}
Material* materialData;
for (int index = 0; index < sizeof(shininesses)/sizeof(float); index++) {
Material data;
data.emission = emissions[index];
data.ambient = ambients[index];
data.diffuse = diffuses[index];
data.specular = speculars[index];
data.shininess = shininesses[index];
materialData[index] = data;
}
Object* objectData;
for (int index = 0; index < sizeof(meshes)/sizeof(int); index++) {
Object data;
data.mesh = &meshData[meshes[index]];
data.material = &materialData[materials[index]];
for (int i = 0; i < 16; i++) {
data.matrix[i] = matricies[index*16 + i];
}
objectData[index] = data;
}
//begin trace
trace(renderTexture, pos, projectionsMatrix,
objectData, 0);
}
The Structs:
typedef struct {
float3* vertices;
float3* normals;
float2* uv;
uint* triangles;
} Mesh;
typedef struct {
float shininess;
float4 specular;
float4 emission;
float4 ambient;
float4 diffuse;
} Material;
typedef struct {
Mesh* mesh;
Material* material;
float matrix[16];
} Object;
typedef struct {
__constant float4 ambient;
__constant float4 specular;
__constant float4 diffuse;
__constant float4 position;
__constant float3 spotDirection;
__constant float spotExponent;
__constant float spotCutoff;
__constant float constantAttenuation;
__constant float linearAttenuation;
__constant float quadraticAttenuation;
} Light;
typedef struct {
float3 origin;
float3 direction;
} Ray;
typedef struct {
float3 point;
float3 normal;
float3 bary;
float dist;
uint triangle_index;
Object* object;
} RaycastHit;
Thanks for you help,
Benproductions1
I want to make a 2d, 3 by 3 ,array like this:
double *array;
void setArray(double x, double y, double z){
array = {{x,0,0},
{0,y,0},
{0,0,z}};
}
I read some posts suggested something like this:
double **array = new double*[3];
void setArray(double x, double y, double z){
array[0] = new double*[3];
array[0][0] = x;
array[0][1] = 0;
array[0][2] = 0;
...
if there any method I can set a 2d array directly using values {{x,0,0},{0,y,0},{0,0,z}}?
Thanks in advance.
If you want to use lists like {{x,0,0},{0,y,0},{0,0,z}}, you should use arrays with hard-coded size:
double *array; // no good
double array[3][3]; // OK
Fill them with copying:
void setArray(double x, double y, double z){
double temp[3][3] = {{x,0,0},
{0,y,0},
{0,0,z}};
memcpy(&array, &temp, sizeof(array));
}
If you don't need jagged array, and the size is known at design time you can use this syntax to declare it:
double array[3][3];
However, if you want to use an initialisation list, you could do it like this:
typedef double Array[3][3];
Array& array(double x = 0.0, double y = 0.0, double z = 0.0) {
static double array_[3][3] = {{x,0,0},{0,y,0},{0,0,z}};
return array_;
}
// init:
array(4,5,8);
// access:
array()[0,2];