I just got started trying to learn how to code graphics using C++. When compiling a linear interpolation code, the code does not run and sends VC++ to the xmemory file. No errors or warnings given, thus leaving me with nothing to work on. What did I do wrong? I suspect the problem is connected to the way I assign the vectors, yet none of my changes have worked.
Here is the code:
#include "SDL.h"
#include <iostream>
#include <glm/glm.hpp>
#include <vector>
#include "SDLauxiliary.h"
using namespace std;
using glm::vec3;
using std::vector;
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
SDL_Surface* screen;
void Draw();
void Interpolate( float a, float b, vector<float>& result ) {
int i = 0;
for ( float x=a;x < b+1; ++x )
{
result[i] = x;
i = i + 1;
}
}
void InterpolateVec( vec3 a, vec3 b, vector<vec3>& resultvec ) {
int i = 0;
for (int add=0; add < 4; ++add) {
float count1 = (b[add]-a[add])/resultvec.size() + a[add];
float count2 = (b[add]-a[add])/resultvec.size() + a[add];
float count3 = (b[add]-a[add])/resultvec.size() + a[add];
resultvec[i].x = (count1, count2, count3);
resultvec[i].y = (count1, count2, count3);
resultvec[i].z = (count1, count2, count3);
i = i + 1;
}
}
int main( int argc, char* argv[] )
{
vector<float> result(10); // Create a vector width 10 floats
Interpolate(5, 14, result); // Fill it with interpolated values
for( int i=0; i < result.size(); ++i )
cout << result[i] << " "; // Print the result to the terminal
vector<vec3> resultvec( 4 );
vec3 a(1,4,9.2);
vec3 b(4,1,9.8);
InterpolateVec( a, b, resultvec );
for( int i=0; i<resultvec.size(); ++i )
{
cout << "( "
<< resultvec[i].x << ", "
<< resultvec[i].y << ", "
<< resultvec[i].z << " ) ";
}
screen = InitializeSDL( SCREEN_WIDTH, SCREEN_HEIGHT );
while( NoQuitMessageSDL() )
{
Draw();
}
SDL_SaveBMP( screen, "screenshot.bmp" );
return 0;
}
void Draw()
{
for( int y=0; y<SCREEN_HEIGHT; ++y )
{
for( int x=0; x<SCREEN_WIDTH; ++x )
{
vec3 color(1,0,1);
PutPixelSDL( screen, x, y, color );
}
}
if( SDL_MUSTLOCK(screen) )
SDL_UnlockSurface(screen);
SDL_UpdateRect( screen, 0, 0, 0, 0 );
}
I can not post a comment to the question so I'll write my thoughts as answer.
resultvec[i].x = (count1, count2, count3);
resultvec[i].y = (count1, count2, count3);
resultvec[i].z = (count1, count2, count3);
It looks like you (or one of your library) overload operator, for float to make vec2 and after vec3. Nice solution, but if I right, then no reason to assign each components to that value and your code will be similiar to:
resultvec[i] = (count1, count2, count3);
Again this is just a hypothesis! I can not compile your code and see the error.
Also I am not understand why you using i, which equal to add.
Strange that some of you could not compile the code; it may be that you have not installed the libraries (the n00b speculating, yay ...).
So here is what I did to make it work (less code is better in this case, as the first comment stated):
void InterpolateVec( vec3 a, vec3 b, vector<vec3>& resultvec ) {
resultvec[0].x = a[0];
resultvec[0].y = a[1];
resultvec[0].z = a[2];
float count1 = (b[0]-a[0])/(resultvec.size() - 1);
float count2 = (b[1]-a[1])/(resultvec.size() - 1);
float count3 = (b[2]-a[2])/(resultvec.size() - 1);
for (int add=1; add < 5; ++add) {
a[0] = a[0] + count1;
a[1] = a[1] + count2;
a[2] = a[2] + count3;
resultvec[add].x = a[0];
resultvec[add].y = a[1];
resultvec[add].z = a[2];
}
}
I discovered (after many an hour ...) was that I did not need to add count1, count2 and count3; vec3 is such a type that adding count1 does what I wanted it to; assigning color (i.e. something like (0,0,1)). Am I making since? My vocabulary is not that technical I know.
Or, you could save some time and let glm::vec3 do what glm::vec3 is supposed to do.
In the mean time; here, have a cookie (cookie.png)
void Interpolate(vec3 a, vec3 b, vector<vec3>& result) {
vec3 diffStep = (b-a) * (1.0f / (result.size() - 1)); // Operator overloading
result[0] = vec3(a);
for(int i = 1; i < result.size(); i++) {
result[i] = result[i-1] + diffStep;
}
}
Related
I got two functions:
The add_cpu function works fine, but the add_gpu function does not.
I tried to check sum options on my GPU driver Software and read my code over and over again. I tried the exact same code on an other machine and it worked fine.
The checkError result on current machine is 1, what it shouldn't be.
And checkError result on my Laptop is 0, what is correct.
Does anyone have any suggestion of what is the problem with the graphic card or the system?
I have no clue what's the problem here.
Did I miss some sort of option?
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <iostream>
#include <math.h>
#define out std::cout <<
#define end << std::endl
__global__
void add_gpu( int n, float* x, float* y ) {
for ( int i = 0; i < n; i++ ) y[i] = x[i] + y[i];
}
void add_cpu( int n, float* x, float* y ) {
for ( int i = 0; i < n; i++ ) y[i] = x[i] + y[i];
}
void init( int n, float* x, float* y ) {
for ( int i = 0; i < n; i++ ) {
x[i] = 1.0f;
y[i] = 2.0f;
}
}
int checkError( int n, float f, float* y ) {
float c = 0.0f;
for ( int i = 0; i < n; i++ ) c = fmax( c, fabs( y[i] - f ) );
return c;
}
void print( int n, float* obj, char* str = "obj: " ) {
out str << obj[0];
for ( int i = 1; i < n; i++ ) out ", " << obj[i];
out "" end;
}
int main( ) {
int n = 1 << 5;
float* x, * y;
float error = 0.0f;
cudaMallocManaged( &x, n * sizeof( float ) );
cudaMallocManaged( &y, n * sizeof( float ) );
init( n, x, y );
print( n, x, "x" );
print( n, y, "y" );
add_gpu<< <1, 1 >> > ( n, x, y );
//add_cpu(n, x, y);
cudaDeviceSynchronize( );
print( n, y, "y" );
error = checkError( n, 3.0f, y );
out "error: " << error end;
cudaFree( x );
cudaFree( y );
return 0;
}
I don't see exactly where the problem is but in order to debug it you should check the cuda errors.
Most cuda functions return a cuda status. You can maybe use a little wrapper function like this to check the errors
checkCudaError(const cudaError_t error) {
if (error != cudaSuccess) {
std::cout << "Cuda error: " << cudaGetErrorString(error) << std::endl;
// maybe do something else
}
}
and call function like cudaMallocManaged() this way
checkCudaError(cudaMallocManaged(&x, n * sizeof(float));
For all operations which are performed on the device (like custom kernels) you should run the kernel and after that call
cudaGetLastError()
and maybe also use checkCudaError()
checkCudaError(cudaGetLastError())
Note that cudaGetLastError() will always return a error if at some point an error occured and so you have to find the place where the first error occures. That is why you should check cuda error every time the GPU was used in some way.
https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__MEMORY.html#group__CUDART__MEMORY_1gc263dbe6574220cc776b45438fc351e8
Without copying the data to the device your GPU doesnt know the data and without copying them back your host doesnt know the results
I made a function that makes the inverse and then another multithreaded, as long I have to make inverse of arrays >2000 x 2000.
A 1000x1000 array unthreated takes 2.5 seconds (on a i5-4460 4 cores 2.9ghz)
and multithreaded takes 7.25 seconds
I placed the multithreads in the part that most time consumption is taken. Whai is wrong?
Is due vectors are used instead of 2 dimensions arrays?
This is the minimum code to test both versions:
#include<iostream>
#include <vector>
#include <stdlib.h>
#include <time.h>
#include <chrono>
#include <thread>
const int NUCLEOS = 8;
#ifdef __linux__
#include <unistd.h> //usleep()
typedef std::chrono::system_clock t_clock; //try to use high_resolution_clock on new linux x64 computer!
#else
typedef std::chrono::high_resolution_clock t_clock;
#pragma warning(disable:4996)
#endif
using namespace std;
std::chrono::time_point<t_clock> start_time, stop_time = start_time; char null_char = '\0';
void timer(char *title = 0, int data_size = 1) { stop_time = t_clock::now(); double us = (double)chrono::duration_cast<chrono::microseconds>(stop_time - start_time).count(); if (title) printf("%s time = %7lgms = %7lg MOPs\n", title, (double)us*1e-3, (double)data_size / us); start_time = t_clock::now(); }
//makes columns 0
void colum_zero(vector< vector<double> > &x, vector< vector<double> > &y, int pos0, int pos1,int dim, int ord);
//returns inverse of x, x is not modified, not threaded
vector< vector<double> > inverse(vector< vector<double> > x)
{
if (x.size() != x[0].size())
{
cout << "ERROR on inverse() not square array" << endl; getchar(); return{};//returns a null
}
size_t dim = x.size();
int i, j, ord;
vector< vector<double> > y(dim,vector<double>(dim,0));//initializes output = 0
//init_2Dvector(y, dim, dim);
//1. Unity array y:
for (i = 0; i < dim; i++)
{
y[i][i] = 1.0;
}
double diagon, coef;
double *ptrx, *ptry, *ptrx2, *ptry2;
for (ord = 0; ord<dim; ord++)
{
//2 Hacemos diagonal de x =1
int i2;
if (fabs(x[ord][ord])<1e-15) //If that element is 0, a line that contains a non zero is added
{
for (i2 = ord + 1; i2<dim; i2++)
{
if (fabs(x[i2][ord])>1e-15) break;
}
if (i2 >= dim)
return{};//error, returns null
for (i = 0; i<dim; i++)//added a line without 0
{
x[ord][i] += x[i2][i];
y[ord][i] += y[i2][i];
}
}
diagon = 1.0/x[ord][ord];
ptry = &y[ord][0];
ptrx = &x[ord][0];
for (i = 0; i < dim; i++)
{
*ptry++ *= diagon;
*ptrx++ *= diagon;
}
//uses the same function but not threaded:
colum_zero(x,y,0,dim,dim,ord);
}//end ord
return y;
}
//threaded version
vector< vector<double> > inverse_th(vector< vector<double> > x)
{
if (x.size() != x[0].size())
{
cout << "ERROR on inverse() not square array" << endl; getchar(); return{};//returns a null
}
int dim = (int) x.size();
int i, ord;
vector< vector<double> > y(dim, vector<double>(dim, 0));//initializes output = 0
//init_2Dvector(y, dim, dim);
//1. Unity array y:
for (i = 0; i < dim; i++)
{
y[i][i] = 1.0;
}
std::thread tarea[NUCLEOS];
double diagon;
double *ptrx, *ptry;// , *ptrx2, *ptry2;
for (ord = 0; ord<dim; ord++)
{
//2 Hacemos diagonal de x =1
int i2;
if (fabs(x[ord][ord])<1e-15) //If a diagonal element=0 it is added a column that is not 0 the diagonal element
{
for (i2 = ord + 1; i2<dim; i2++)
{
if (fabs(x[i2][ord])>1e-15) break;
}
if (i2 >= dim)
return{};//error, returns null
for (i = 0; i<dim; i++)//It is looked for a line without zero to be added to make the number a non zero one to avoid later divide by 0
{
x[ord][i] += x[i2][i];
y[ord][i] += y[i2][i];
}
}
diagon = 1.0 / x[ord][ord];
ptry = &y[ord][0];
ptrx = &x[ord][0];
for (i = 0; i < dim; i++)
{
*ptry++ *= diagon;
*ptrx++ *= diagon;
}
int pos0 = 0, N1 = dim;//initial array position
if ((N1<1) || (N1>5000))
{
cout << "It is detected out than 1-5000 simulations points=" << N1 << " ABORT or press enter to continue" << endl; getchar();
}
//cout << "Initiation of " << NUCLEOS << " threads" << endl;
for (int thread = 0; thread<NUCLEOS; thread++)
{
int pos1 = (int)((thread + 1)*N1 / NUCLEOS);//next position
tarea[thread] = std::thread(colum_zero, std::ref(x), std::ref(y), pos0, pos1, dim, ord);//ojo, coil current=1!!!!!!!!!!!!!!!!!!
pos0 = pos1;//next thread will work at next point
}
for (int thread = 0; thread<NUCLEOS; thread++)
{
tarea[thread].join();
//cout << "Thread num: " << thread << " end\n";
}
}//end ord
return y;
}
//makes columns 0
void colum_zero(vector< vector<double> > &x, vector< vector<double> > &y, int pos0, int pos1,int dim, int ord)
{
double coef;
double *ptrx, *ptry, *ptrx2, *ptry2;
//Hacemos '0' la columna ord salvo elemento diagonal:
for (int i = pos0; i<pos1; i++)//Begin to end for every thread
{
if (i == ord) continue;
coef = x[i][ord];//element to make 0
if (fabs(coef)<1e-15) continue; //If already zero, it is avoided
ptry = &y[i][0];
ptry2 = &y[ord][0];
ptrx = &x[i][0];
ptrx2 = &x[ord][0];
for (int j = 0; j < dim; j++)
{
*ptry++ = *ptry - coef * (*ptry2++);//1ª matriz
*ptrx++ = *ptrx - coef * (*ptrx2++);//2ª matriz
}
}
}
void test_6_inverse(int dim)
{
vector< vector<double> > vec1(dim, vector<double>(dim));
for (int i=0;i<dim;i++)
for (int j = 0; j < dim; j++)
{
vec1[i][j] = (-1.0 + 2.0*rand() / RAND_MAX) * 10000;
}
vector< vector<double> > vec2,vec3;
double ini, end;
ini = (double)clock();
vec2 = inverse(vec1);
end = (double)clock();
cout << "=== Time inverse unthreaded=" << (end - ini) / CLOCKS_PER_SEC << endl;
ini=end;
vec3 = inverse_th(vec1);
end = (double)clock();
cout << "=== Time inverse threaded=" << (end - ini) / CLOCKS_PER_SEC << endl;
cout<<vec2[2][2]<<" "<<vec3[2][2]<<endl;//to make the sw to do de inverse
cout << endl;
}
int main()
{
test_6_inverse(1000);
cout << endl << "=== END ===" << endl; getchar();
return 1;
}
After looking deeper in the code of the colum_zero() function I have seen that one thread rewrites in the data to be used by another threads, so the threads are not INDEPENDENT from each other. Fortunately the compiler detect it and avoid it.
Conclusions:
It is not recommended to try Gauss-Jordan method alone to make multithreads
If somebody detects that in multithread is slower and the initial function is spreaded correctly for every thread, perhaps is due one thread results are used by another
The main function inverse() works and can be used by other programmers, so this question should not be deleted
Non answered question:
What is a matrix inverse method that could be spreaded in a lot of independent threads to be used in a gpu?
I want to genetically recreate a given image
I try to do this in sfml.
I have created a self-parting square that tries to evolve to look
like source image
Sadly, this thing crashes and I have no idea why, I suppose everything is handled nice and the vector appending shouldn't be a problem.
Please check out the code:
The main function:
#include "divisablesquare.h"
#include <SFML/Graphics.hpp>
#include <iostream>
#include <cstring>
#include <string>
#include <error.h>
#include <algorithm>
namespace GLOBAL
{
bool DEBUG_MODE = false;
};
int IDX = 0;
int main(int argc, char * argv[])
{
srand(time(NULL));
std::string def;
for(int i = 1; i < argc; i++)
{
def = argv[i];
std::string def2 = def;
std::transform(def2.begin(), def2.end(), def2.begin(), ::tolower);
if(strcmp(def2.c_str(), "--debug") == 0)
{
GLOBAL::DEBUG_MODE = true;
std::cerr << "Running in debug mode" << std::endl;
}
else
{
break;
}
}
sf::Image sourceImage;
sf::Texture sample;
if(!sourceImage.loadFromFile(def) && GLOBAL::DEBUG_MODE)
{
std::cerr << "Failed to open specified image!" << std::endl;
}
sample.loadFromImage(sourceImage);
sf::RectangleShape sourceRect;
sourceRect.setSize((sf::Vector2f)sourceImage.getSize());
sourceRect.setTexture(&sample);
sf::RenderWindow mainWindow(sf::VideoMode(sourceImage.getSize().x*2+10, sourceImage.getSize().y), "Genetic Image Generator");
std::vector<DivisableSquare> dSquares;
{
DivisableSquare starter(&dSquares, &sourceImage);
starter.init(128, 128, 128, sourceImage.getSize().x, sourceImage.getSize().y, sourceImage.getSize().x + 10, 0);
starter.Shape.setPosition({(float)sourceImage.getSize().x + 10, 0});
starter.Shape.setFillColor({128,128,128});
starter.Shape.setSize({(float)sourceImage.getSize().x, (float)sourceImage.getSize().y});
dSquares.push_back(starter);
}
sf::Clock clock;
while(mainWindow.isOpen())
{
sf::Time elapsed = clock.getElapsedTime();
if(elapsed.asMilliseconds() > 1000)
{
clock.restart();
dSquares.at(rand() % dSquares.size()).Partup();
}
sf::Event mainEvent;
while(mainWindow.pollEvent(mainEvent))
{
if(mainEvent.type == sf::Event::Closed)
mainWindow.close();
}
mainWindow.clear();
mainWindow.draw(sourceRect);
for(auto &&ref: dSquares)
{
mainWindow.draw(ref.Shape);
}
mainWindow.display();
}
}
divisablesquare header:
#ifndef DIVISABLESQUARE_H
#define DIVISABLESQUARE_H
#include <vector>
#include <SFML/Graphics.hpp>
class DivisableSquare
{
private:
sf::Image * parentImage;
std::vector<DivisableSquare> * ParentContainter;
unsigned short red, green, blue;
double width, height;
double posX, posY;
int id;
public:
~DivisableSquare();
sf::RectangleShape Shape;
DivisableSquare(std::vector<DivisableSquare>*, sf::Image*);
void init(unsigned short, unsigned short, unsigned short, unsigned int, unsigned int, unsigned int, unsigned int);
void Partup();
};
#endif // DIVISABLESQUARE_H
and the c++ file:
#include "divisablesquare.h"
#include <random>
#include <algorithm>
#include <iostream>
extern int IDX;
DivisableSquare::DivisableSquare(std::vector<DivisableSquare> *pc, sf::Image*tp)
{
this->ParentContainter = pc;
this->parentImage = tp;
this->id = IDX;
IDX++;
}
DivisableSquare::~DivisableSquare()
{
}
void DivisableSquare::init(unsigned short r, unsigned short g, unsigned short b,
unsigned int width, unsigned int height, unsigned int posX, unsigned int posY)
{
this->red = r;
this->blue = b;
this->green = g;
this->width = width;
this->height = height;
this->posX = posX;
this->posY = posY;
}
void DivisableSquare::Partup()
{
if(this->width < 2 && this->height < 2)
return;
double percentCut = (rand()%60 + 20)/100;
bool horizontalCut = rand()%2;
double posX1, posX2;
double posY1, posY2;
double width1, width2;
double height1, height2;
if(horizontalCut)
{
posX1 = this->posX;
posX2 = (this->posX+this->width)*percentCut;
posY1 = this->posY;
posY2 = this->posY;
width1 = this->width*percentCut;
width2 = this->width*(1-percentCut);
height1 = this->height;
height2 = this->height;
}
else
{
posX1 = this->posX;
posX2 = this->posX;
posY1 = this->posY;
posY2 = (this->posY + this->height)*percentCut;
width1 = this->width;
width2 = this->width;
height1 = this->height*percentCut;
height2 = this->height*(1-percentCut);
}
struct RGB
{
float r, g, b;
float parentCmp;
float originalCmp;
float averageCmp;
/**
* Make sure to append originalCmp later
* also remove "= 0"
* DONE
*/
};
std::vector<RGB> originalPixels1;
std::vector<RGB> originalPixels2;
for(unsigned int i = posX1; i < posX1+width1; i++)
{
for(unsigned int j = posY1; j < posY1+height1; j++)
{
if(this->parentImage->getSize().x > i && this->parentImage->getSize().y > j)
{
RGB pixel;
pixel.r = this->parentImage->getPixel(i, j).r;
pixel.g = this->parentImage->getPixel(i, j).g;
pixel.b = this->parentImage->getPixel(i, j).b;
originalPixels1.push_back(pixel);
}
}
}
for(unsigned int i = posX2; i < posX2+width2; i++)
{
for(unsigned int j = posY2; j < posY2+height2; j++)
{
if(this->parentImage->getSize().x > i && this->parentImage->getSize().y > j)
{
RGB pixel;
pixel.r = this->parentImage->getPixel(i, j).r;
pixel.g = this->parentImage->getPixel(i, j).g;
pixel.b = this->parentImage->getPixel(i, j).b;
originalPixels2.push_back(pixel);
}
}
}
RGB pix1 = {0,0,0,0,0,0}, pix2={0,0,0,0,0,0};
for(auto &&ref : originalPixels1)
{
pix1.r += ref.r;
pix1.g += ref.g;
pix1.b += ref.b;
}
pix1.r /= originalPixels1.size();
pix1.g /= originalPixels1.size();
pix1.b /= originalPixels1.size();
for(auto &&ref : originalPixels2)
{
pix2.r += ref.r;
pix2.g += ref.g;
pix2.b += ref.b;
}
pix2.r /= originalPixels1.size();
pix2.g /= originalPixels1.size();
pix2.b /= originalPixels1.size();
auto comparVal = [](RGB v1, RGB v2)
{
float val1 = 0.2126*v1.r + 0.7152*v1.g + 0.0722*v1.b;
float val2 = 0.2126*v2.r + 0.7152*v2.g + 0.0722*v2.b;
return (val1 > val2) ? val1-val2 : val2-val1;
};//smaller - better
RGB first[100];
RGB second[100];
for(int i = 0; i < 100; i++)
{
first[i].r = rand() % 255;
first[i].g = rand() % 255;
first[i].b = rand() % 255;
second[i].r = rand() % 255;
second[i].g = rand() % 255;
second[i].b = rand() % 255;
}
// insert orginalcmp here
for(int i = 0; i < 100; i++)
{
first[i].originalCmp = comparVal(first[i], pix1);
second[i].originalCmp = comparVal(second[i], pix2);
}
RGB pRgb;
pRgb.r = this->red;
pRgb.b = this->blue;
pRgb.b = this->blue;
for(int i = 0; i < 100; i++)
{
first[i].parentCmp = comparVal(first[i], pRgb);
second[i].parentCmp = comparVal(second[i], pRgb);
first[i].averageCmp = (first[i].originalCmp+first[i].parentCmp)/2;
second[i].averageCmp = (second[i].originalCmp+second[i].parentCmp)/2;
}
std::sort(first, first+100, [](const RGB& l, const RGB& r){return r.averageCmp > l.averageCmp;});
std::sort(second, second+100, [](const RGB& l, const RGB& r){return r.averageCmp > l.averageCmp;});
RGB bestfirst = first[rand()%10], bestsecond = second[rand()%10];
DivisableSquare firstSQ(this->ParentContainter, this->parentImage);
DivisableSquare secondSQ(this->ParentContainter, this->parentImage);
firstSQ.init(bestfirst.r, bestfirst.g, bestfirst.b, width1, height1, posX1, posY1);
secondSQ.init(bestsecond.r, bestsecond.g, bestsecond.b, width2, height2, posX2, posY2);
firstSQ.Shape.setFillColor({(sf::Uint8)bestfirst.r, (sf::Uint8)bestfirst.g, (sf::Uint8)bestfirst.b});
secondSQ.Shape.setFillColor({(sf::Uint8)bestsecond.r, (sf::Uint8)bestsecond.g, (sf::Uint8)bestsecond.b});
firstSQ.Shape.setSize({(float)width1, (float)height1});
secondSQ.Shape.setSize({(float)width2, (float)height2});
firstSQ.Shape.setPosition({(float)posX1 + this->parentImage->getSize().x + 10, (float)posY1});
secondSQ.Shape.setPosition({(float)posX2 + this->parentImage->getSize().x + 10, (float)posY2});
this->ParentContainter->push_back(firstSQ);
this->ParentContainter->push_back(secondSQ);
//crash here
for(unsigned int i = 0; i < this->ParentContainter->size(); i++)
{
if(this->ParentContainter->at(i).id == this->id)
this->ParentContainter->erase(this->ParentContainter->begin()+i);
}
}
I know this is a poor code but i just wanted to test things out, what could cause a vector::push_back to crash my app?
The problem is that you're adding to dSquares while executing code using a member of the vector. When the vector is resized (during the this->ParentContainter->push_back(firstSQ); call), the object that this points to is moved (since it is part of the vector). However, this keeps pointing at the previous location of the object, and when you try to push the second new square you access this deallocated memory, resulting in Undefined Behavior and (in this case) a crash.
A possible fix is to call dSquares.reserve(dSquares.size() + 2); before you call dSquares.at(rand() % dSquares.size()).Partup();. This will allocate extra memory of the (potential) two new objects that are added so that when you call push_back within Partup a reallocation of the vector will not occur.
Another possibility is to erase the parent square first, then push the two new squares to the vector. When you push the first new square, it won't have to resize the vector (since there will be space for at least one element from removing the parent). Pushing the second element might result in a resize, so dereferencing this after that push could still crash.
I'm using QtCreator to code an algorithm that I have already coded on Matlab.
When coding this program, I have two errors. The firts one (APPCRASH) appears just when I build and execute the program normally, but not when I try to debug it (Heisenbug) and it appears on the function 'matriceA'. I tried to make the variables volatile and to write the matrix A term formulas on other function, hoping that that will stop the compiler optimization (I think that the compiler optimization might cause the problem), but I have not been able to solve the problem. I have not tried to to compile the project using the option -o0 because my professor (it's an university project) has to be able to compile it normally (without specific options).
The second one is a SISSEGV segmentation fault. It happens when the code arrives to "DestroyFloatArray(&b, width);" on InpaintingColor.
And here the codes:
clanu_process.cpp (it's little messy because I've tried a lot of things...)
#include "clanu_process.h"
#include "iomanip"
void InpaintingColor(float **Rout, float **Gout, float **Bout, float **Rin, float **Gin, float **Bin, float **Mask, int width, int height, double param)
{
cout << "1" << endl;
float alphak = 0, bethak = 0, res = 0;
float **b = 0, **xk = 0, **dk = 0, **rk = 0, **Ark = 0, **tmp1 = 0,**tmp2 = 0,**tmp3 = 0;
Ark = AllocateFloatArray( width, height);
tmp1 = AllocateFloatArray( width, height);
tmp2 = AllocateFloatArray( width, height);
tmp3 = AllocateFloatArray( width, height);
xk = AllocateFloatArray( width, height);
dk = AllocateFloatArray( width, height);
rk = AllocateFloatArray( width, height);
b = AllocateFloatArray( width, height);
cout << "2" << endl;
res = 1e8;
matrixProductByScalar(b,1.0/(3.0*256),Rin,width,height);
matrixDuplicate(xk, b, width, height);
// APPCRASH error
matriceA(Ark,xk,Mask,width,height);
//More code
// SIGSEGV error
DestroyFloatArray(&b, width);
DestroyFloatArray(&xk, width);
DestroyFloatArray(&dk, width);
DestroyFloatArray(&rk, width);
DestroyFloatArray(&Ark, width);
DestroyFloatArray(&tmp1, width);
DestroyFloatArray(&tmp2, width);
DestroyFloatArray(&tmp3, width);
}
float** matriceA(float **A, float **I, float **Masque, int N2, int N1){
volatile bool bool_iplus = false, bool_imoins = false, bool_jmoins = false, bool_jplus = false;
volatile int iplus = 0, imoins = 0, jplus = 0, jmoins = 0;
for(int i = 1; i <= N1; i++){
bool_iplus = i<N1;
iplus = i+1 < N1 ? i+1 : N1;
bool_imoins = i>1;
imoins = i-1 > 1 ? i-1 : 1;
for(int j = 1; j <= N2; j++){
bool_jplus = j<N2;
jplus = j+1 < N2 ? j+1 : N2;
bool_jmoins = j>1;
jmoins = j -1 > 1 ? j-1 : 1;
if(Masque[i-1][j-1]!=0){
//cout << "if - " << i << ", " << j<< endl;
A[i-1][j-1] = (1.0/36)*(16*I[i-1][j-1]
+ 4*(
(bool_iplus?I[iplus-1][j-1]:0)
+ (bool_imoins?I[imoins-1][j-1]:0)
+ (bool_jplus?I[i-1][jplus-1]:0)
+ (bool_jmoins?I[i-1][jmoins-1]:0)
)+(
(bool_iplus&&bool_jplus?I[iplus-1][jplus-1]:0)
+ (bool_imoins&&bool_jplus?I[imoins-1][jplus-1]:0)
+ (bool_imoins&&bool_jmoins?I[imoins-1][jmoins-1]:0))
+ (bool_iplus&&bool_jmoins?I[iplus-1][jmoins-1]:0));
}else{
//cout << "else - " << i << ", " << j << endl;
A[i-1][j-1]=
-(1.0*N1*N2)*(
-8.0*I[i-1][j-1]
+ I[iplus-1][j-1]
+ I[imoins-1][j-1]
+ I[i-1][jplus-1]
+ I[i-1][jmoins-1]
+ I[iplus-1][jplus-1]
+ I[imoins-1][jplus-1]
+ I[imoins-1][jmoins-1]
+ I[iplus-1][jmoins-1]);
}
}
}
return A;
}
The functions AllocateFloatArray and DestroyFloatArray
float ** AllocateFloatArray(int width, int height)
{
float ** r = new float*[width];
for(int i=0; i<width; i++)
r[i] = new float[height];
return r;
}
void DestroyFloatArray(float ***a, int width)
{
if( *a == 0 ) return;
for(int i=0; i<width; i++)
delete[] a[0][i];
delete[] *a;
*a = 0;
}
Thank you for your time.
I'm no sure that it's the cause of your problem but...
Your function "Matrix operations" (sum(), matrixSubstraction(), matrixAddition(), matrixProductByElement(), matrixProductByScalar(), and matrixDuplicate()) are ranging the first index from zero to width and the second one from zero to height.
If I'm not wrong, this is correct and is consistent with allocation/deallocation (AllocateFloatArray() and DestroyFloatArray()).
But look at the two matriceA() functions; they are defined as
float** matriceA(float **A, float **I, int N2, int N1)
float** matriceA(float **A, float **I, float **Masque, int N2, int N1)
In both functions the first index range from zero to N1 and the second one from zero to N2; by example
for(int i = 1; i <= N1; i++){
// ...
for(int j = 1; j <= N2; j++){
// ...
A[i-1][j-1] = (1.0/36)*(16*I[i-1][j-1] // ...
Good. But you call matriceA() in this way
matriceA(Ark,rk,Mask,width,height);
Briefly: you allocate your matrices as width * height matrices; your "matrix operations" are using they as width * height matrices but your matriceA() function are using they as height * width.
Wonderful way to devastate the memory.
I suppose the solution could be
1) switch N1 and N2 in matriceA() definition
2) or switch width and height in matriceA() calling
p.s.: sorry for my bad English.
I am trying to implement the rasterization method in cc+. I am trying to implement an interpolation function that handles the interpolation between the x,y and z vertices. That way I can save the inverse of z in a depth buffer.
At this point I get only the vertices drawn on the rendered image. Can someone see what is wrong with my code? I have posted the full code so you can see the whole program.
Many thanks in advance.
EDIT
I saw that I had made an error in vertexshader by writing pixel.zinv = 1 / vPrime.z instead of p.zinv = 1/ vPrime.z. Now nothing renders, just a black screen.
EDIT 2
My check to see if a pixel should be painted was wrong.
if (depthBuffer[row[i].x][row[i].y] < row[i].zinv)
is correct. Now I get little pieces of color.
#include <iostream>
#include <glm/glm.hpp>
#include <SDL.h>
#include "SDLauxiliary.h"
#include "TestModel.h"
using namespace std;
using glm::vec2;
using glm::vec3;
using glm::ivec2;
using glm::mat3;
using glm::max;
// ----------------------------------------------------------------------------
// GLOBAL VARIABLES
int cc = 0;
const int SCREEN_WIDTH = 500;
const int SCREEN_HEIGHT = 500;
SDL_Surface* screen;
int t;
vector<Triangle> triangles;
vec3 cameraPos(0, 0, -3.001);
float f = 500;
double yaw = 0;
vec3 c1(cos(yaw), 0, -sin(yaw));
vec3 c2(0, 1, 0);
vec3 c3(sin(yaw), 0, cos(yaw));
glm::mat3 R(c1, c2, c3);
float translation = 0.1; // use this to set translation increment
const float PI = 3.1415927;
vec3 currentColor;
float depthBuffer[SCREEN_HEIGHT][SCREEN_WIDTH];
// ----------------------------------------------------------------------------
// STUCTURES
struct Pixel
{
int x;
int y;
float zinv;
}pixel;
// ----------------------------------------------------------------------------
// FUNCTIONS
void Update();
void Draw();
void VertexShader(const vec3& v, Pixel& p);
void Interpolate(ivec2 a, ivec2 b, vector<ivec2>& result);
void DrawLineSDL(SDL_Surface* surface, ivec2 a, ivec2 b, vec3 color);
void DrawPolygonEdges(const vector<vec3>& vertices);
void ComputePolygonRows(const vector<Pixel>& vertexPixels, vector<Pixel>& leftPixels, vector<Pixel>& rightPixels);
void DrawPolygonRows(const vector<Pixel>& leftPixels, const vector<Pixel>& rightPixels);
void DrawPolygon(const vector<vec3>& vertices);
void Interpolate2(Pixel a, Pixel b, vector<Pixel>& result);
int main(int argc, char* argv[])
{
LoadTestModel(triangles);
screen = InitializeSDL(SCREEN_WIDTH, SCREEN_HEIGHT);
t = SDL_GetTicks(); // Set start value for timer.
while (NoQuitMessageSDL())
{
Draw();
}
//Draw();
//cin.get();
SDL_SaveBMP(screen, "screenshot.bmp");
return 0;
}
void Draw()
{
SDL_FillRect(screen, 0, 0);
if (SDL_MUSTLOCK(screen))
SDL_LockSurface(screen);
for (int y = 0; y<SCREEN_HEIGHT; ++y)
for (int x = 0; x<SCREEN_WIDTH; ++x)
depthBuffer[y][x] = 0;
for (int i = 0; i<triangles.size(); ++i)
{
currentColor = triangles[i].color;
vector<vec3> vertices(3);
int aa = 24;
vertices[0] = triangles[i].v0;
vertices[1] = triangles[i].v1;
vertices[2] = triangles[i].v2;
DrawPolygon(vertices);
}
if (SDL_MUSTLOCK(screen))
SDL_UnlockSurface(screen);
SDL_UpdateRect(screen, 0, 0, 0, 0);
}
void VertexShader(const vec3& v, Pixel& p)
{
vec3 vPrime = (v - cameraPos)*R;
p.zinv = 1 / vPrime.z;
p.x = f * vPrime.x / vPrime.z + SCREEN_WIDTH / 2;
p.y = f * vPrime.y / vPrime.z + SCREEN_HEIGHT / 2;
//cout << p.x << " this is it " << p.y << endl;
depthBuffer[p.x][p.y] = pixel.zinv;
}
void ComputePolygonRows(const vector<Pixel>& vertexPixels,
vector<Pixel>& leftPixels, vector<Pixel>& rightPixels)
{
// Find y-min,max for the 3 vertices
vec3 vp(vertexPixels[0].y, vertexPixels[1].y, vertexPixels[2].y);
Pixel start; Pixel end; Pixel middle;
int yMin = 1000;
int yMax = -1000;
int w=0; int s=0;
for (int k = 0; k < vertexPixels.size(); ++k)
{
if (vp[k] <= yMin)
{
yMin = vp[k];
end = vertexPixels[k];
w = k;
}
}
for (int k = 0; k < vertexPixels.size(); ++k)
{
if (vp[k] >= yMax)
{
yMax = vp[k];
start = vertexPixels[k];
s = k;
}
}
for (int k = 0; k < vertexPixels.size(); ++k)
{
if (vertexPixels[k].y != start.y
&& vertexPixels[k].y != end.y)
{
middle = vertexPixels[k];
}
if (w!= k && s!= k)
{
middle = vertexPixels[k];
}
}
int ROWS = yMax - yMin + 1;
leftPixels.resize(ROWS);
rightPixels.resize(ROWS);
for (int i = 0; i<ROWS; ++i)
{
leftPixels[i].x = +numeric_limits<int>::max();
rightPixels[i].x = -numeric_limits<int>::max();
}
int pixels1 = glm::abs(start.y - end.y) + 1;
vector<Pixel> line1(pixels1);
Interpolate2(end, start, line1);
int pixels2 = glm::abs(end.y - middle.y) + 1;
vector<Pixel> line2(pixels2);
Interpolate2(end, middle, line2);
int pixels3 = glm::abs(middle.y - start.y) + 1;
vector<Pixel> line3(pixels3);
Interpolate2(middle, start, line3);
vector<Pixel> side1(ROWS);
for (int i = 0; i < line2.size(); ++i)
{
side1[i] = line2[i];
}
for (int i = 0; i < line3.size(); ++i)
{
side1[line2.size()+i-1] = line3[i];
}
for (int i = 0; i < ROWS; ++i)
{
if (line1[i].x < leftPixels[i].x)
{
leftPixels[i] = line1[i];
}
if (line1[i].x > rightPixels[i].x)
{
rightPixels[i] = line1[i];
}
if (side1[i].x < leftPixels[i].x)
{
leftPixels[i] = side1[i];
}
if (side1[i].x > rightPixels[i].x)
{
rightPixels[i] = side1[i];
}
}
}
void DrawPolygonRows(const vector<Pixel>& leftPixels, const vector<Pixel>& rightPixels)
{
//cout << cc++ << endl;
for (int k = 0; k < leftPixels.size(); ++k)
{
int pixels = glm::abs(leftPixels[k].x - rightPixels[k].x) + 1;
vector<Pixel> row(pixels);
Interpolate2(leftPixels[k], rightPixels[k], row);
for (int i = 0; i < pixels; ++i)
{
if (depthBuffer[row[i].x][row[i].y] < row[i].zinv)
{
PutPixelSDL(screen, row[i].x, row[i].y, currentColor);
depthBuffer[row[i].x][row[i].y] = row[i].zinv;
}
}
}
}
void DrawPolygon(const vector<vec3>& vertices)
{
int V = vertices.size();
vector<Pixel> vertexPixels(V);
for (int i = 0; i<V; ++i)
VertexShader(vertices[i], vertexPixels[i]);
vector<Pixel> leftPixels;
vector<Pixel> rightPixels;
ComputePolygonRows(vertexPixels, leftPixels, rightPixels);
DrawPolygonRows(leftPixels, rightPixels);
}
void Interpolate2(Pixel a, Pixel b, vector<Pixel>& result)
{
int N = result.size();
float stepx = (b.x - a.x) / float(glm::max(N - 1, 1));
float stepy = (b.y - a.y) / float(glm::max(N - 1, 1));
float stepz = (b.zinv - a.zinv) / float(glm::max(N - 1, 1));
float currentx = a.x;
float currenty = a.y;
float currentz = a.zinv;
for (int i = 0; i<N; ++i)
{
result[i].x = currentx;
result[i].y = currenty;
result[i].zinv = currentz;
currentx = a.x;
currenty = a.y;
currentz = a.zinv;
currentx += stepx;
currenty += stepy;
currentz += stepz;
}
}
The last loop in the last function seems incorrect to me. You define currentx outside the loop. Then, define a local variable inside the loop with the same name and use it later in the loop. I'd suggest not using the same name for variable inside the loop and outside it to make it more readable. Also, using global variables make the code difficult to read too, since I prefer to look at a function as a separate entity for analysis.