Probleme world generation with thread - c++

I'm trying to create a world generation system.
I have a world class that contain a map of terrain that can be increased during the program.
When I do it in the main thread it work fine but their is little freeze when he calculate the vertex and everything, so I tried to use Thread.
So to generate a terrain I do that :
std::thread newThread(&World::addTerrain, this, xIndex, zIndex, 64, 64);
newThread.detach();
(The addTerrain method)
void World::addTerrain(int x, int z, size_t len, size_t col) {
//allTerrain_[x].emplace(std::make_pair(z, Terrain(x*size_, z*size_, size_ / 2.0f, len, col, &shader_, &heightGenerator_)));
allTerrain_[x].emplace(std::make_pair(z, Terrain(x*size_, z*size_, size_/2.0f, len, col, &shader_, &waterShader_, &heightGenerator_)));
}
but when I do this, the new terrain is added to the map, but he look empty (nothing is drawn).
I'm not sure I'm using the right approach, so if you can help me it will be great !

Try this:
Add a mutex to World (terrain_mutex_)
Use a std::lock_guard<std::mutex> when reading from/writing to allTerrain_. Your painting code needs to use this mutex too.
In addTerrain:
void World::addTerrain(int x, int z, size_t len, size_t col) {
{ // lock while copying the terrain
std::lock_guard<std::mutex> guard(terrain_mutex_);
auto terrain_copy = allTerrain_;
}
// add more terrain to the copy
terrain_copy[x].emplace(z, Terrain(x*size_, z*size_, size_/2.0f, len, col,
&shader_, &waterShader_, &heightGenerator_));
{ // lock when swapping in the copy
std::lock_guard<std::mutex> guard(terrain_mutex_);
std::swap(terrain_copy, allTerrain_);
}
}

Related

Get certain pixels with their coordonates from an Image with Qt/QML

We are creating a game where there are maps. On those maps, players can walk, but to know if they can walk somewhere, we have another image, where the path is paint.
The player can move by clicking on the map, if the click match with the collider image, the character should go to the clicked point with a pathfinder. If not, the character don't move.
For example, here is a map and its collision path image :
How can I know if I've clicked on the collider (this is a png with one color and transparency) in Qt ?
I'm using QML and Felgo for rendering so if there is already a way to do it with QML, it's even better, but I can implement it in C++ too.
My second question is how can I do a pathfinder ? I know the algorithms for that but should I move by using pixels ?
I've seen the QPainterPath class which could be what i'm looking for, how can I read all pixels with a certain color of my image and know their coordonates ?
Thanks
QML interface doesn't provide efficient way to resolve your task. It should be done at C++ side.
To get image data you can use:
QImage to load image
Call N times QImage::constScanLine, each time read K pixels. N equals to image height in pixels, K equals to width.
How to deal with returned uchar* of QImage::constScanLine?
You should call QImage::format() to determine pixel format hidden by uchar*. Or you can call QImage::convertToFormat(QImage::Format_RGB32) and always cast pixel data from uchar* to your custom struct like PixelData:
#pragma pack(push, 1)
struct PixelData {
uint8_t padding;
uint8_t r;
uint8_t g;
uint8_t b;
};
#pragma pack(pop)
according to this documentation: https://doc.qt.io/qt-5/qimage.html#Format-enum
Here is compilable solution for loading image into RAM for further effective working with it's data:
#include <QImage>
#pragma pack(push, 1)
struct PixelData {
uint8_t padding;
uint8_t r;
uint8_t g;
uint8_t b;
};
#pragma pack(pop)
void loadImage(const char* path, int& w, int& h, PixelData** data) {
Q_ASSERT(data);
QImage initialImage;
initialImage.load(path);
auto image = initialImage.convertToFormat(QImage::Format_RGB32);
w = image.width();
h = image.height();
*data = new PixelData[w * h];
PixelData* outData = *data;
for (int y = 0; y < h; y++) {
auto scanLine = image.constScanLine(y);
memcpy(outData, scanLine, sizeof(PixelData) * w);
outData += w;
}
}
void pathfinder(const PixelData* data, int w, int h) {
// Your algorithm here
}
void cleanupData(PixelData* data) {
delete[] data;
}
int main(int argc, char *argv[])
{
int width, height;
PixelData* data;
loadImage("D:\\image.png", width, height, &data);
pathfinder(data, width, height);
cleanupData(data);
return 0;
}
You can access each pixel by calling this function
inline const PixelData& getPixel(int x, int y, const PixelData* data, int w) {
return *(data + (w * y) + x);
}
... or use this formula somewhere in your pathfinding algorithm, where it could be more efficient.

Libvlc buffer locking

I'm implementing a 3d VR player and for the video decoding I'm using Libvlc.
To render the video I have a texture buffer and a memory buffer, when VLC decodes a frame the data is copied by the main loop to the texture.
I've tested two different mechanisms to lock the memory buffer when vlc is dumping a frame, first I tried a mutex as the examples show but the performance is awful, also I've tested a lock-free mechanism using atomic operations, the performance is not perfect but better.
The best results I get are just not locking at all the buffer, it works very smooth but some times the main loop and vlc loop gets desinchronized and then tearing and stuttering are noticeable.
So my question is, what is the best approach to lock the buffer? any way to don't loss performance?
Here are the important code parts:
-Video context struct
typedef struct _videoContext
{
libvlc_instance_t* instance;
libvlc_media_t* media;
libvlc_media_player_t* player;
unsigned char *pixeldata;
unsigned char currentFrame;
int width;
int height;
int duration;
int time;
int volume;
bool finished;
std::atomic<bool> lock;
} videoContext;
-Video event functions
static void *lock(void *data, void **p_pixels)
{
videoContext* context = (videoContext*)data;
bool expected = false;
while (!context->lock.compare_exchange_strong(expected, true))
Sleep(0);
p_pixels[0] = context->pixeldata;
return NULL;
}
static void unlock(void *data, void *id, void *const *p_pixels)
{
videoContext* context = (videoContext*)data;
context->time = libvlc_media_player_get_time(context->player);
context->lock.store(false);
context->currentFrame++;
}
-Main loop function
if (vctx->currentFrame != currentFrame && vctx->lock.compare_exchange_strong(exchangeExpected, true))
{
currentFrame = vctx->currentFrame;
Texture::setData(&videoTexture, vctx->pixeldata, vctx->width, vctx->height);
vctx->lock.store(false);
}

glBufferSubData has peaks with small buffer sizes

I am making a simple 2D game engine with OpenGL, and my SpriteRenderer class makes batches of sprites which use the same shader or texture. Once I sort them first by texture, then by shader, and then by depth, the uploadData() method of my SpriteRenderer class uploads the CPU generated vertex data to the GPU. For this I am using the orphaning method, which is said to be faster than a simple glBufferData call.
My problem is, when I have small numbers of sprites (<15), I have frames with huge stalls, but with numbers >20 up to 10 000 it runs smoothly. I wrapped opengl function into c++ classes. If I replace the VertexBufferObject::uploadOrphaned() method by the VertexBufferObject::upload() method, the stall goes away. Here is my vbo class:
//vbo.h
class VertexBufferObject
{
public:
VertexBufferObject();
VertexBufferObject(size_t allocSize);
~VertexBufferObject();
inline ui32 id(){ return (ui32)m_id; }
template <class T>
void addData(const T& data)
{
const byte* convertedData = reinterpret_cast<const byte*>(&data);
size_t size = sizeof(T);
for (ui32 i = 0; i < size; i++)m_data.add(convertedData[i]);
}
void initialize();
void resetData();
void upload(GLenum drawType);
void uploadOrphaned(GLenum drawType);
inline void bind() { ::glBindBuffer(GL_ARRAY_BUFFER, m_id); }
inline void unbind(){ ::glBindBuffer(GL_ARRAY_BUFFER, 0); }
private:
GLuint m_id;
//this is my custom dynamic array class, this is a hobby project
//and I enjoy reinventing the wheel :)
Array<byte> m_data;
and below is the cpp file:
VertexBufferObject::VertexBufferObject() :m_id(0)
{
}
VertexBufferObject::VertexBufferObject(size_t allocSize) : m_id(0), m_data(allocSize)
{
}
VertexBufferObject::~VertexBufferObject()
{
if (m_id != 0) ::glDeleteBuffers(1, &m_id);
}
void VertexBufferObject::initialize()
{
if (m_id == 0) ::glGenBuffers(1, &m_id);
}
void VertexBufferObject::upload(GLenum drawType)
{
glBufferData(GL_ARRAY_BUFFER, m_data.size(), &m_data[0], drawType);
}
void VertexBufferObject::uploadOrphaned(GLenum drawType)
{
glBufferData(GL_ARRAY_BUFFER, m_data.size() * 2, NULL, drawType);
glBufferSubData(GL_ARRAY_BUFFER, 0, m_data.size(), &m_data[0]);
}
void VertexBufferObject::resetData()
{
m_data.strip();
}
I am learning opengl, so my VertexBufferObject class contains what I already know. I know there are other methods to upload data, but I want to understand the reason of the current problem with this simple method. I looked around forums including here, and nobody had a similar issue that I found of. Maybe my class has some errors?

My thread Stops

My problem is that I am starting a Thread to read data from my EyeTracker. I start it using the following functions:
BlinkMode::BlinkMode()
{
bBlink = false;
threadStopped = true;
recordeddata = nullptr;
gT = GazeTracker::getGazeTracker();
canRecord = false;
numCameras = gT->getNumCameras();
if( numCameras >0){
canRecord = true;
}
filename = "blinkmode.txt";
counter = 0;
calipointno = 0 ;
}
void BlinkMode::startRecording()
{
if (!bBlink)
{
// Turn thread loop signal on
bBlink = true;
bBlinkSuccess = false;
bExcessData = false;
blinkThread = std::thread(createBlinkThread, this);
}
}
void BlinkMode::createBlinkThread(void* instance)
{
BlinkMode* pThis = (BlinkMode*) instance;
pThis->bBlink;
if(pThis->canRecord){
pThis->threadStopped = false;
pThis->BlinkModeThread();
pThis->threadStopped = true;
}
}
void BlinkMode::BlinkModeThread ()
{
BlinkMode* pThis = (BlinkMode*) this;
pThis->bBlink;
Matrix mProvData = Matrix (DR_DATAANALYSIS, GT_EYEDATALENGTH);
Matrix aSourceMatrix = Matrix (DR_MAXRECORDEDDATA, GT_EYEDATALENGTH);
recordeddata = new float[DR_MAXRECORDEDDATA][GT_EYEDATALENGTH];
while(bBlink){
if(counter<DR_MAXRECORDEDDATA){
gT->getCurrentData(recordeddata[counter],ALLDATA);
[ETC ...]
The thing is that my boolean bBlink, which is defined as a private volatile boolean in the header file of my class:
class BlinkMode
{
private:
// Monitor thread control signal.
volatile bool bBlink;}
becomes false right after the creation of the Matrix instances, (Matrix is another class of my code). And hence, the while loop is NEVER entered. However, if I comment the Matrix lines, it works! I can even execute the new float "recordeddata", but not the Matrices.
Does that mean that I cannot call another classes while I am inside a Thread or something? Sorry I am pretty new with C++ and I am lost.
Any help please??
Thanks in advance!
The Matrix class is just to initialize Matrices in different ways and do operations with them, kind of like this:
class Matrix
{
public:
// Default constructor
Matrix();
// Default destructor
~Matrix();
// Initialise matrix of rows x cols.
Matrix(const int rows, const int cols);
// Convert a two dimensional array (rows x cols) of integers to a matrix.
Matrix(const int* const* num, const int rows, const int cols);
// Convert a two dimensional array (rows x cols) of floats to a matrix.
Matrix(const float* const* num, const int rows, const int cols);
// Copies the required row into the array.
void getRow(const int row, double[]) const;
// Copies the required row into the matrix.
void getRow(const int row, Matrix&) const;
// Sets the values of a row to the values of the array.
void setRow(const int row, const int[]);
enter code here
So I am just creating 2 objects there, and that is when the boolean automatically changes to false!!
I just created the pThis pointer you mentioned to be able to access the value of the boolean and check when it changes, but it is not relevant for the code... I can erase it and nothing changes...

Trying to make an array of DirectX vertex with out knowing until run time what type they will be

Bit of background for those who don't know DirectX. A vertex is not just an XYZ position, it can have other data in it as well. DirectX uses a system known as Flexible Vertex Format, FVF, to let you define what format you want your vertexs to be in. You define these by passing a number to DirectX that use bitwise or to build it up, eg (D3DFVF_XYZ | D3DFVF_DIFFUSE)means you are going to start using (from when you tell DirectX) vertexs that have an XYZ (three floats) and a RGB components (DWORD / unsigned long).
In order to pass your vertexs to the graphics card, you basicaly lock the memory in the graphics card where your buffer is, and use memcpy to transfer your array over.
Your array is an array of a struct you deffine your self, so in this case you would have made a struct like...
struct CUSTOMVERTEX {
FLOAT X, Y, Z;
DWORD COLOR;
};
You then make an array of type CUSTOMVERTEX and fill in the data fields.
I think my best appraoch is let my class build up an array of each component type, so an array of struct pos{ flaot x,y,z;}; an array of struct colour{ DWROD colour;}; etc.
But I will then need to merge these together so that I have an array structs like CUSTOMVERTEX.
Now, I think I have made a function that will merge to arrays together, but I am not sure if it is going to work as intended, here it is (currently missing the abilaty to actually return this 'interlaced' array)
void Utils::MergeArrays(char *ArrayA, char *ArrayB, int elementSizeA, int elementSizeB, int numElements)
{
char *packedElements = (char*)malloc(numElements* (elementSizeA, elementSizeB));
char *nextElement = packedElements;
for(int i = 0; i < numElements; ++i)
{
memcpy(nextElement, (void*)ArrayA[i], elementSizeA);
nextElement += elementSizeA;
memcpy(nextElement, (void*)ArrayB[i], elementSizeB);
nextElement += elementSizeB;
}
}
when calling this function, you will pass in the two arrays you want merged, and size of the elements in each array and the number of elements in your array.
I was asking about this in chat for a while whilst SO was down. A few things to say.
I am dealing with fairly small data sets, like 100 tops, and this (in theory) is more of an initialisation task, so should only get done once, so a bit of time is ok by me.
My final array that I want to be able to use memcpy on to transfer into the graphics card needs to have no padding, it has to be contiguous data.
EDIT The combined array of vertex data will be transfered to the GPU, this is first done by requesting the GPU to set a void* to the start of the memory I have access to and requesting space the size of my customVertex * NumOfVertex. So if my mergeArray function does loose what the types are within it, that is ok, just a long as I get my single combined array to transfer in one block /EDIT
Finally, their is a dam good chance I am barking up the wrong tree with this, so their may well be a much simpler way to just not have this problem in the first place, but part of me has dug my heals in and wants to get this system working, so I would appreciate knowing how to get such a system to work (the interlacing arrays thing)
Thank you so much... I need to sooth my head now, so I look forward to hearing any ideas on the problem.
No, no, no. The FVF system has been deprecated for years and isn't even available in D3D10 or later. D3D9 uses the VertexElement system. Sample code:
D3DVERTEXELEMENT9 VertexColElements[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
D3DDECL_END(),
};
The FVF system has a number of fundamental flaws - for example, which order the bytes go in.
On top of that, if you want to make a runtime-variant vertex data format, then you will need to write a shader for every possible variant that you may want to have, and compile them all, and spend your life swapping them around. And, the effects on the final product would be insane - for example, how could you possibly write a competitive rendering engine if you decide to take out the lighting data you need to Phong shade?
The reality is that a runtime-variant vertex format is more than a tad insane.
However, I guess I'd better lend a hand. What you really need is a polymorphic function object and some plain memory- D3D takes void*s or somesuch so that's not a big deal. When you call the function object, it adds to the FVF declaration and copies data into the memory.
class FunctionBase {
public:
virtual ~FunctionBase() {}
virtual void Call(std::vector<std::vector<char>>& vertices, std::vector<D3DVERTEXELEMENT9>& vertexdecl, int& offset) = 0;
};
// Example implementation
class Position : public FunctionBase {
virtual void Call(std::vector<std::vector<char>>& vertices, std::vector<D3DVERTEXELEMENT9>& vertexdecl, int& offset) {
std::for_each(vertices.begin(), vertices.end(), [&](std::vector<char>& data) {
float x[3] = {0};
char* ptr = (char*)x;
for(int i = 0; i < sizeof(x); i++) {
data.push_back(ptr[i]);
}
}
vertexdecl.push_back({0, offset, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0});
offset += sizeof(x);
}
};
std::vector<std::vector<char>> vertices;
std::vector<D3DVERTEXELEMENT9> vertexdecl;
vertices.resize(vertex_count);
std::vector<std::shared_ptr<FunctionBase>> functions;
// add to functions here
int offset = 0;
std::for_each(functions.begin(), functions.end(), [&](std::shared_ptr<FunctionBase>& ref) {
ref->Call(vertices, vertexdecl, offset);
});
vertexdecl.push_back(D3DDECL_END());
Excuse my use of lambdas, I use a C++0x compiler.
Your solution looks fine. But if you want something a bit more C++ish, you could try something like this:
Edit My previous solution basically recreated something that already existed, std::pair. I don't know what I was thinking, here's the even more C++ish solution:
template<typename InIt_A, typename InIt_B, typename OutIt>
void MergeArrays(InIt_A ia, InIt_B ib, OutIt out, std::size_t size)
{
for(std::size_t i=0; i<size; i++)
{
*out = make_pair(*ia,*ib);
++out;
++ia;
++ib;
}
}
int main()
{
pos p[100];
color c[100];
typedef pair<pos,color> CustomVertex;
CustomVertex cv[100];
MergeArrays(p,c,cv,100);
}
You shouldn't have to worry about padding, because all elements in a D3D vertex are either 32 bit floats, or 32 bit integers.
Edit
Here's a solution that might work. It will do all your mergings at once, and you don't need to worry about passing around the size:
// declare a different struct for each possible vertex element
struct Position { FLOAT x,y,z; };
struct Normal { FLOAT x,y,z; };
struct Diffuse { BYTE a,r,g,b; };
struct TextureCoordinates { FLOAT u,v; };
// etc...
// I'm not all too sure about all the different elements you can have in a vertex
// But you would want a parameter for each one in this function. Any element that
// you didn't use, you would just pass in a null pointer. Since it's properly
// typed, you won't be able to pass in an array of the wrong type without casting.
std::vector<char> MergeArrays(Position * ppos, Normal * pnorm, Diffuse * pdif, TextureCoordinates * ptex, int size)
{
int element_size = 0;
if(ppos) element_size += sizeof(Position);
if(pnorm) element_size += sizeof(Normal);
if(pdif) element_size += sizeof(Diffuse);
if(ptex) element_size += sizeof(TextureCoordinates);
vector<char> packed(element_size * size);
vector<char>::iterator it = packed.begin();
while(it != packed.end())
{
if(ppos)
{
it = std::copy_n(reinterpret_cast<char*>(ppos), sizeof(Position), it);
ppos++;
}
if(pnorm)
{
it = std::copy_n(reinterpret_cast<char*>(pnorm), sizeof(Normal), it);
pnorm++;
}
if(pdif)
{
it = std::copy_n(reinterpret_cast<char*>(pdif), sizeof(Diffuse), it);
pdif++;
}
if(ptex)
{
it = std::copy_n(reinterpret_cast<char*>(ptex), sizeof(TextureCoordinates), it);
ptex++;
}
}
return packed;
}
// Testing it out. We'll create an array of 10 each of some of the elements.
// We'll use Position, Normal, and Texture Coordinates. We'll pass in a NULL
// for Diffuse.
int main()
{
Position p[10];
Normal n[10];
TextureCoordinates tc[10];
// Fill in the arrays with dummy data that we can easily read. In this
// case, what we'll do is cast each array to a char*, and fill in each
// successive element with an incrementing value.
for(int i=0; i<10*sizeof(Position); i++)
{
reinterpret_cast<char*>(p)[i] = i;
}
for(int i=0; i<10*sizeof(Normal); i++)
{
reinterpret_cast<char*>(n)[i] = i;
}
for(int i=0; i<10*sizeof(TextureCoordinates); i++)
{
reinterpret_cast<char*>(tc)[i] = i;
}
vector<char> v = MergeArrays(p,n,NULL,tc,10);
// Output the vector. It should be interlaced:
// Position-Normal-TexCoordinates-Position-Normal-TexCoordinates-etc...
for_each(v.begin(), v.end(),
[](const char & c) { cout << (int)c << endl; });
cout << endl;
}
Altering your code, this should do it:
void* Utils::MergeArrays(char *ArrayA, char *ArrayB, int elementSizeA, int elementSizeB, int numElements)
{
char *packedElements = (char*)malloc(numElements* (elementSizeA + elementSizeB));
char *nextElement = packedElements;
for(int i = 0; i < numElements; ++i)
{
memcpy(nextElement, ArrayA + i*elementSizeA, elementSizeA);
nextElement += elementSizeA;
memcpy(nextElement, ArrayB + i*elementSizeB, elementSizeB);
nextElement += elementSizeB;
}
return packedElements;
}
Note that you probably want some code that merges all the attributes at once, rather than 2 at a time (think position+normal+texture coordinate+color+...). Also note that you can do that merging at the time you fill out your vertex buffer, so that you don't ever need to allocate packedElements.
Something like:
//pass the Locked buffer in as destArray
void Utils::MergeArrays(char* destArray, char **Arrays, int* elementSizes, int numArrays, int numElements)
{
char* nextElement = destArray;
for(int i = 0; i < numElements; ++i)
{
for (int array=0; array<numArrays; ++array)
{
int elementSize = elementSizes[array];
memcpy(nextElement, Arrays[array] + i*elementSize, elementSize);
nextElement += elementSize;
}
}
}
I don't know DirectX, but the exact same sort of concept exists in OpenGL, and in OpenGL you can specify the location and stride of each vertex attribute. You can have alternating attributes (like your first struct) or you scan store them in different blocks. In OpenGL you use glVertexPointer to set these things up. Considering that DirectX is ultimately running on the same hardware underneath, I suspect there's some way to do the same thing in DirectX, but I don't know what it is.
Some Googling with DirectX and glVertexPointer as keywords turns up SetFVF and SetVertexDeclaration
MSDN on SetFVF, gamedev discussion comparing them