c++ / SFML - Memory leak shown in valgrind report - c++

I've this little code that repeatedly draws a shape using SFML. It aborts abruptly with different error messages, like corrupted size vs. prev_size / Aborted (core dumped), munmap_chunk(): invalid pointer / or Segmentation fault (core dumped).
I used valgrind to track down what looks like some memory leak, but the report is rather cryptic to me. Nevertheless, as far as I understand the thing, "definitely lost: 4,096 bytes in 1 blocks" is not a good omen. The most puzzling is that it does not abort when I run it through valgrind.
I'll keep on investigating, but if anyone could give me a hint, that would be great.
Best regards,
MC
g++ -std=c++11 ./k.cpp -o ./k -Wfatal-errors -lsfml-graphics -lsfml-window -lsfml-system
#include "SFML/Graphics.hpp"
#include <iostream>
#include <math.h>
#include <random>
#include <stdio.h>
#include <string>
using namespace std;
struct point {
double x;
double y;
};
struct curve {
int index;
point centerPoint;
double radius;
sf::ConvexShape shape;
sf::Text curveName;
point curveNamePosition;
};
curve computeCurve(point centerPoint, double radius) {
unsigned short numberOfPoints = 200;
curve curve;
curve.shape.setPointCount(numberOfPoints);
curve.centerPoint.x = centerPoint.x;
curve.centerPoint.y = centerPoint.y;
curve.radius = radius;
double alpha = 2 * M_PI / numberOfPoints;
unsigned short a = 1;
point point;
for (unsigned short i = 0; i < numberOfPoints + 1; i++) {
point.x = radius * (0.5 + cos(2 * a * alpha * i) / 2) * cos(alpha * i) +
centerPoint.x;
point.y = radius * sin(a * alpha * i) + centerPoint.y;
curve.shape.setPoint(i, sf::Vector2f(point.x, point.y));
};
for (unsigned short i = 0; i < numberOfPoints - 1; i++) {
point.x = radius * (0.5 + cos(2 * a * alpha * i) / 2) * cos(alpha * i) +
centerPoint.x;
point.y = -radius * sin(a * alpha * i) + centerPoint.y;
curve.shape.setPoint(2 * numberOfPoints - i,
sf::Vector2f(point.x, point.y));
};
curve.shape.setOrigin(curve.centerPoint.x, curve.centerPoint.y);
curve.shape.setPosition(curve.centerPoint.x, curve.centerPoint.y);
curve.curveNamePosition.x = curve.centerPoint.x;
curve.curveNamePosition.y = curve.centerPoint.y;
curve.curveName.setString("Curve");
curve.curveName.setPosition(curve.centerPoint.x, curve.centerPoint.y);
return curve;
}
int main(int argc, char **argv) {
const unsigned short windowWidth = 800;
const unsigned short windowHeight = 800;
sf::RenderWindow window(sf::VideoMode(windowWidth, windowHeight), "Demo",
sf::Style::Default); // Default / None // Fullscreen
string myfontFileName = "./media/Arial.ttf";
sf::Font myFont;
if (!myFont.loadFromFile(myfontFileName)) {
cout << "Could not find the font " << myfontFileName << endl;
}
sf::Event myEvent;
sf::Clock curveClock;
// Initialization
point centerPoint;
centerPoint.x = 300;
centerPoint.y = 300;
double radius = 200;
curve mt = computeCurve(centerPoint, radius);
mt.shape.setOutlineColor(sf::Color::Red);
mt.shape.setFillColor(sf::Color(40, 140, 10, 127));
mt.shape.setOutlineThickness(1.f);
mt.curveName.setFont(myFont);
mt.curveName.setCharacterSize(20);
mt.curveName.setFillColor(sf::Color::White);
std::random_device randomDevice;
std::mt19937 seed(randomDevice());
while (window.isOpen()) {
while (window.pollEvent(myEvent)) {
if (myEvent.type == sf::Event::EventType::Closed) {
window.close();
}
}
window.clear();
if (curveClock.getElapsedTime().asMilliseconds() > 200.0f) {
std::uniform_int_distribution<std::mt19937::result_type> rDistribution(
10, 300);
double radius = rDistribution(seed);
std::uniform_int_distribution<std::mt19937::result_type> cDistribution(
100, 300);
centerPoint.x = cDistribution(seed);
centerPoint.y = cDistribution(seed);
mt = computeCurve(centerPoint, radius);
mt.shape.setOutlineColor(sf::Color::Red);
mt.shape.setFillColor(sf::Color(40, 140, 10, 127));
mt.shape.setOutlineThickness(1.f);
mt.curveName.setFont(myFont);
mt.curveName.setCharacterSize(20);
mt.curveName.setFillColor(sf::Color::White);
curveClock.restart();
}
window.draw(mt.shape);
window.draw(mt.curveName);
window.display();
}
return EXIT_SUCCESS;
}

There was definitely an error in the way the equation was defined. Here is a corrected code if someone is interested.
Best regards,
MC
#include "SFML/Graphics.hpp"
#include <iostream>
#include <math.h>
#include <random>
#include <stdio.h>
#include <string>
using namespace std;
struct point {
double x;
double y;
};
struct curve {
int index;
point centerPoint;
double radius;
sf::ConvexShape shape;
sf::Text name;
point namePosition;
};
curve computeCurve(point centerPoint, double radius) {
std::random_device randomDevice;
std::mt19937 seed(randomDevice());
std::uniform_int_distribution<std::mt19937::result_type> aDistribution(1, 4);
int a = aDistribution(seed);
unsigned short numberOfPoints = 100 * a;
curve curve;
curve.shape.setPointCount(numberOfPoints);
curve.centerPoint.x = centerPoint.x;
curve.centerPoint.y = centerPoint.y;
curve.radius = radius;
double alpha = 2 * M_PI / numberOfPoints;
point point;
for (unsigned short i = 0; i < numberOfPoints + 1; i++) {
point.x = radius * (0.5 + cos(2 * a * alpha * i) / 2) * cos(alpha * i) +
centerPoint.x;
point.y = radius * sin(a * alpha * i) + centerPoint.y;
curve.shape.setPoint(i, sf::Vector2f(point.x, point.y));
};
curve.shape.setOrigin(curve.centerPoint.x, curve.centerPoint.y);
curve.shape.setPosition(curve.centerPoint.x, curve.centerPoint.y);
curve.namePosition.x = curve.centerPoint.x;
curve.namePosition.y = curve.centerPoint.y;
curve.name.setString("Curve");
curve.name.setPosition(curve.centerPoint.x, curve.centerPoint.y);
return curve;
}
curve computeCardioid(point centerPoint, double radius) {
double perimeter = 8 * radius;
int numberOfPoints = max(floor(perimeter / 3), 20.0d);
curve curve;
curve.shape.setPointCount(numberOfPoints);
curve.centerPoint.x = centerPoint.x;
curve.centerPoint.y = centerPoint.y;
curve.radius = radius;
double alpha = 2 * M_PI / numberOfPoints;
point point;
for (unsigned short i = 0; i < numberOfPoints; i++) {
point.x = 2 * radius * (1 - cos(alpha * i)) * cos(alpha * i) +
curve.centerPoint.x;
point.y = 2 * radius * (1 - cos(alpha * i)) * sin(alpha * i) +
curve.centerPoint.y;
curve.shape.setPoint(i, sf::Vector2f(point.x, point.y));
};
curve.shape.setOrigin(curve.centerPoint.x - 1.5 * radius,
curve.centerPoint.y);
curve.shape.setPosition(curve.centerPoint.x, curve.centerPoint.y);
curve.namePosition.x = curve.centerPoint.x;
curve.namePosition.y = curve.centerPoint.y;
curve.name.setString("Card");
curve.name.setPosition(curve.centerPoint.x, curve.centerPoint.y);
return curve;
}
int main(int argc, char **argv) {
const unsigned short windowWidth = 800;
const unsigned short windowHeight = 800;
sf::RenderWindow window(sf::VideoMode(windowWidth, windowHeight), "Demo",
sf::Style::Default); // Default / None // Fullscreen
string myfontFileName = "./media/Arial.ttf";
sf::Font myFont;
if (!myFont.loadFromFile(myfontFileName)) {
cout << "Could not find the font " << myfontFileName << endl;
}
sf::Event myEvent;
sf::Clock curveClock;
// Initialization
point centerPoint;
centerPoint.x = 300;
centerPoint.y = 300;
double radius = 200;
curve curve = computeCurve(centerPoint, radius);
curve.shape.setOutlineColor(sf::Color::Red);
curve.shape.setFillColor(sf::Color(40, 140, 10, 127));
curve.shape.setOutlineThickness(1.f);
curve.name.setFont(myFont);
curve.name.setCharacterSize(20);
curve.name.setFillColor(sf::Color::White);
random_device randomDevice;
mt19937 seed(randomDevice());
while (window.isOpen()) {
while (window.pollEvent(myEvent)) {
if (myEvent.type == sf::Event::EventType::Closed) {
window.close();
}
}
window.clear();
if (curveClock.getElapsedTime().asMilliseconds() > 1000.0f) {
uniform_int_distribution<mt19937::result_type> rDistribution(10, 300);
double radius = rDistribution(seed);
point centerPoint;
uniform_int_distribution<mt19937::result_type> cDistribution(100, 300);
centerPoint.x = cDistribution(seed);
centerPoint.y = cDistribution(seed);
curve = computeCurve(centerPoint, radius);
curve.shape.setOutlineColor(sf::Color::Red);
curve.shape.setFillColor(sf::Color(40, 140, 10, 127));
curve.shape.setOutlineThickness(1.f);
curve.name.setFont(myFont);
curve.name.setCharacterSize(20);
curve.name.setFillColor(sf::Color::White);
curveClock.restart();
}
window.draw(curve.shape);
window.draw(curve.name);
window.display();
}
return EXIT_SUCCESS;
}

Related

How to fill sf::VertexArray of sf::TriangleStrip with color?

I would like to increase the drawing performance by using a single sf::VertexArray to display thousands of circles. To make sure it works, I wrote this example:
#include <SFML/Graphics.hpp>
#include <iostream>
#define WIDTH 100
#define HEIGHT 100
int main() {
sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT), "RTREE",
sf::Style::Close);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) window.close();
}
sf::CircleShape circle(50);
circle.setPosition(100,100);
size_t count = circle.getPointCount();
sf::VertexArray objects(sf::TriangleStrip, count);
for (int i = 0; i < count; i++) {
objects.append(circle.getPoint(i));
}
for (int i = 0; i < objects.getVertexCount(); i++) {
objects[i].color = sf::Color::Blue;
}
window.clear();
window.draw(objects);
window.display();
}
}
However, the color only applies to the line, not the fill:
Is it possible to fill the shape with a single color?
You are right, displaying more than 1000 circles with a window.draw between each of them result in poor performances. The vertexArray is indeed a good solution.
You used sf::TriangleStrip which does not work as you expected. Your verticles are indeed painted, but they are only on the edge of the circle. You need to use either sf::TriangleFan or sf::Triangles if you want more than one circle per array.
Here an example. I was able to display 513'000 verticles at 60 fps (each circle is about 30 verticles, which is about 10'000 circles.
#include <SFML/Graphics.hpp>
#include <cmath>
#include <iostream>
#include <sstream>
#define WIDTH 800
#define HEIGHT 800
using namespace std;
template <typename T>
std::string to_string_with_precision(const T a_value, const int n = 6)
{
std::ostringstream out;
out.precision(n);
out << std::fixed << a_value;
return out.str();
}
void addCircle(sf::VertexArray &array, sf::Vector2f position, float radius, sf::Color color) {
size_t count = 30;
for (int i = 0; i < count; i += 1) {
sf::Vertex v0;
v0.position = sf::Vector2f(position.x, position.y);
v0.color = color;
array.append(v0);
sf::Vertex v1;
float angle = i * 2 * M_PI / count;
v1.position = sf::Vector2f(position.x + cos(angle) * radius, position.y + sin(angle) * radius);
v1.color = color;
array.append(v1);
sf::Vertex v2;
angle = (i + 1) * 2 * M_PI / count;
v2.position = sf::Vector2f(position.x + cos(angle) * radius, position.y + sin(angle) * radius);
v2.color = color;
array.append(v2);
}
}
#define FRAMERATE 120
int main() {
sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT), "RTREE", sf::Style::Close);
// Fps text
sf::Font font;
if (!font.loadFromFile("../assets/collegiate.ttf")) {
std::cout << "Error loading font" << std::endl;
}
sf::Text fps;
fps.setFont(font);
fps.setPosition(10, 10);
fps.setCharacterSize(16);
fps.setFillColor(sf::Color::White);
// Time management
sf::Clock clock;
sf::Time timeSinceLastUpdate = sf::Time::Zero;
sf::Time timePerFrame = sf::seconds(1.f / FRAMERATE);
sf::Time timeSinceLastDraw = sf::Time::Zero;
window.setFramerateLimit(FRAMERATE);
float vr = 0;
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) window.close();
}
size_t count = 15;
sf::Color color = sf::Color::Red;
color.a = 50;
sf::Color color2 = sf::Color::Blue;
color2.a = 20;
sf::VertexArray objects(sf::Triangles);
for (int k = 0; k < 5; k++) {
sf::Color c = k % 2 ? color : color2;
for (int j = 20; j < 400; j += 5) {
for (int i = 0; i < count; i++) {
float angle = i * 2 * M_PI / count;
angle += (i % 2 ? vr : -vr) * k * (k % 2 ? 1 : -1);
addCircle(objects, sf::Vector2f(WIDTH / 2 + cos(angle) * j, HEIGHT / 2 + sin(angle) * j), j / 5, c);
}
}
}
timeSinceLastDraw = clock.restart();
timeSinceLastUpdate += timeSinceLastDraw;
double timeFps = 1.f / timeSinceLastDraw.asSeconds();
fps.setString("verticles: " + to_string_with_precision(objects.getVertexCount(), 0) + " fps: " + to_string_with_precision(timeFps, 0));
while (timeSinceLastUpdate > timePerFrame) {
timeSinceLastUpdate -= timePerFrame;
vr += 0.01;
}
window.clear();
window.draw(objects);
window.draw(fps);
window.display();
}
}

Wrong normal for triangles

I am making a 3D game using SFML. I want to use normals to check if the triangle need to be draw in a terrain (triangle) mesh.Here is my code:
vec3d line1, line2, normal;
line1.x = terrain.tris[i].p[0].x - terrain.tris[i].p[1].x;
line1.y = terrain.tris[i].p[0].y - terrain.tris[i].p[1].y;
line1.z = terrain.tris[i].p[0].z - terrain.tris[i].p[1].z;
line2.x = terrain.tris[i].p[1].x - terrain.tris[i].p[2].x;
line2.y = terrain.tris[i].p[1].y - terrain.tris[i].p[2].y;
line2.z = terrain.tris[i].p[1].z - terrain.tris[i].p[2].z;
normal.x = line1.y * line2.z - line1.z * line2.y;
normal.y = line1.z * line2.x - line1.x * line2.z;
normal.z = line1.x * line2.y - line1.y * line2.x;
vec3d vCameraRay = Vector_Sub(terrain.tris[i].p[0], cam.pos);
if (Vector_DotProduct(normal, vCameraRay) < 0.0f){
do_something();
}
Vector_DotProduct:
float Vector_DotProduct(vec3d& v1, vec3d& v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
Vector_sub:
vec3d Vector_Sub(vec3d& v1, vec3d& v2) {
return { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
}
And the vec3d is just a struct that contains
float x, y, z;
But whenever I run the program, I always get this
problem
The triangles that should be displayed was considered "Not visable" by my program(The normal of it is wrong), but the calculation seems right to me!
The code for producing triangle grid:
for (int i = 0; i < 2; i++) {
for (int y = 0; y < wds; y++) {
for (int x = 0; x < wds; x++) {
if (x + 1 < wds && y + 1 < wds) {
vec3d point[3];
switch (i) {
case 0:
point[0] = { (float)(y + 1) * scl + p.x, height * h[y + 1][x + 1], (float)(x + 1) * scl + p.z };
point[1] = { (float)y * scl + p.x, height * h[y][x], (float)x * scl + p.z };
point[2] = { (float)y * scl + p.x, height * h[y][x + 1], (float)(x + 1) * scl + p.z };
break;
case 1:
point[0] = { (float)(y + 1) * scl + p.x, height * h[y + 1][x + 1], (float)(x + 1) * scl + p.z };
point[2] = { (float)y * scl + p.x, height * h[y][x], (float)x * scl + p.z };
point[1] = { (float)(y + 1) * scl + p.x, height * h[y + 1][x], (float)x * scl + p.z };
break;
};
triangle out = { point[0], point[1], point[2] };
tris.push_back(out);
}
}
}
}
The wds is for the size of the grid(side length), the scl is the size of per grid, the h is the height map(two dimentions), and p is the position of the upper left corner.
My 3D point to camera point code:
float mx = p.x - pos.x;
float my = p.y - pos.y;
float mz = p.z - pos.z;
float dx = cos(rot.y) * (sin(rot.z) * my + cos(rot.z) * mx) - sin(rot.y) * mz;
float dy = sin(rot.x) * (cos(rot.y) * mz + sin(rot.y) * (sin(rot.z) * my + cos(rot.z) * mx)) + cos(rot.x) * (cos(rot.z) * my + sin(rot.z) * mx);
float dz = cos(rot.x) * (cos(rot.y) * mz + sin(rot.y) * (sin(rot.z) * my + cos(rot.z) * mx)) - sin(rot.x) * (cos(rot.z) * my + sin(rot.z) * mx);
return { dx, dy, dz };
The rot is the rotation of the camera, p is the position of the camera, and the pos is the 3D point I want to transfer to camera point.
I have been working on this problem for almost a week, but nothing seems to work.It will be a lot of help if you guys can find the problem. Thanks in advance!
Full Code
Init.h:
#ifndef _INIT_H_
#define _INIT_H_
#define WIDTH 1200
#define HEIGHT 800
#endif
Noise.h: noice function
#pragma once
#ifndef _NOISE_H_
#define _NOISE_H_
extern int primeIndex;
extern int numOctaves;
extern double persistence;
extern int primes[10][3];
#endif
#include <math.h>
float Noise(int i, int x, int y);
float SmoothedNoise(int i, int x, int y);
float Interpolate(float a, float b, float x);
float InterpolatedNoise(int i, float x, float y);
float noise(float x, float y);
Noise.cpp:
#include "Noise.h"
int primeIndex = 0;
int numOctaves = 7;
double persistence = 0.5;
int primes[10][3] = {
{ 995615039, 600173719, 701464987 },
{ 831731269, 162318869, 136250887 },
{ 174329291, 946737083, 245679977 },
{ 362489573, 795918041, 350777237 },
{ 457025711, 880830799, 909678923 },
{ 787070341, 177340217, 593320781 },
{ 405493717, 291031019, 391950901 },
{ 458904767, 676625681, 424452397 },
{ 531736441, 939683957, 810651871 },
{ 997169939, 842027887, 423882827 }
};
float Noise(int i, int x, int y) {
int n = x + y * 57;
n = (n << 13) ^ n;
int a = primes[i][0], b = primes[i][1], c = primes[i][2];
int t = (n * (n * n * a + b) + c) & 0x7fffffff;
return 1.0 - (float)(t) / 1073741824.0;
}
float SmoothedNoise(int i, int x, int y) {
float corners = (Noise(i, x - 1, y - 1) + Noise(i, x + 1, y - 1) +
Noise(i, x - 1, y + 1) + Noise(i, x + 1, y + 1)) / 16,
sides = (Noise(i, x - 1, y) + Noise(i, x + 1, y) + Noise(i, x, y - 1) +
Noise(i, x, y + 1)) / 8,
center = Noise(i, x, y) / 4;
return corners + sides + center;
}
float Interpolate(float a, float b, float x) {
float ft = x * 3.1415927,
f = (1 - cos(ft)) * 0.5;
return a * (1 - f) + b * f;
}
float InterpolatedNoise(int i, float x, float y) {
int integer_X = x;
float fractional_X = x - integer_X;
int integer_Y = y;
float fractional_Y = y - integer_Y;
float v1 = SmoothedNoise(i, integer_X, integer_Y),
v2 = SmoothedNoise(i, integer_X + 1, integer_Y),
v3 = SmoothedNoise(i, integer_X, integer_Y + 1),
v4 = SmoothedNoise(i, integer_X + 1, integer_Y + 1),
i1 = Interpolate(v1, v2, fractional_X),
i2 = Interpolate(v3, v4, fractional_X);
return Interpolate(i1, i2, fractional_Y);
}
float noise(float x, float y) {
float total = 0,
frequency = pow(2, numOctaves),
amplitude = 1;
for (int i = 0; i < numOctaves; ++i) {
frequency /= 2;
amplitude *= persistence;
total += InterpolatedNoise((primeIndex + i) % 10,
x / frequency, y / frequency) * amplitude;
}
return total / frequency;
}
Struct.h:
#pragma once
#ifndef _STRUCT_H_
#define _STRUCT_H_
#endif
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <list>
#include "Init.h"
struct vec3d {
float x = 0;
float y = 0;
float z = 0;
};
struct vec2d {
float x = 0;
float y = 0;
};
struct triangle {
vec3d p[3];
int color[3] = { 255, 255, 255 };
vec3d normal;
};
Terrain.h: terrain generation
#pragma once
#ifndef _TERRAIN_H_
#define _TERRAIN_H_
#endif
#include <vector>
#include "Struct.h"
#include "Noise.h"
#define wds 50
#define scl 20
#define width 1000
#define height 120
struct Terrain {
public:
std::vector<triangle> tris;
vec3d p = { -width / 2, 0.0f, -width / 2 };
float h[wds][wds];
void triangle_Strip();
};
Terrain.cpp:
#include "Terrain.h"
void Terrain::make_value() {
for (int y = 0; y < wds; y++) {
for (int x = 0; x < wds; x++) {
int a = abs(p.z / scl + x), b = abs(p.x / scl + y);
h[y][x] = noise(a, b) * 30;
}
}
}
void Terrain::triangle_Strip() {
tris.clear();
for (int i = 0; i < 2; i++) {
for (int y = 0; y < wds; y++) {
for (int x = 0; x < wds; x++) {
if (x + 1 < wds && y + 1 < wds) {
vec3d point[3];
switch (i) {
case 0:
point[0] = { (float)(y + 1) * scl + p.x, height * h[y + 1][x + 1], (float)(x + 1) * scl + p.z };
point[1] = { (float)y * scl + p.x, height * h[y][x], (float)x * scl + p.z };
point[2] = { (float)y * scl + p.x, height * h[y][x + 1], (float)(x + 1) * scl + p.z };
break;
case 1:
point[0] = { (float)(y + 1) * scl + p.x, height * h[y + 1][x + 1], (float)(x + 1) * scl + p.z };
point[2] = { (float)y * scl + p.x, height * h[y][x], (float)x * scl + p.z };
point[1] = { (float)(y + 1) * scl + p.x, height * h[y + 1][x], (float)x * scl + p.z };
break;
};
triangle out = { point[0], point[1], point[2] };
tris.push_back(out);
}
}
}
}
}
Camera.h: camera class, get3dcoord which is get camera point, get2dcoord which is get screen point
#pragma once
#ifndef _CAMERA_H_
#define _CAMERA_H_
#endif
#include "Mat.h"
#include "Init.h"
#include "Struct.h"
class Cam {
public:
vec3d pos;
vec3d rot;
float fov;
float speed;
Cam(vec3d p, vec3d r, float f, float s);
vec3d get3dcoord(vec3d p);
vec3d get2dcoord(vec3d p);
};
Camera.cpp:
#include "Camera.h"
Cam::Cam(vec3d p, vec3d r, float f, float s) {
pos = p;
rot = r;
fov = f;
speed = s;
}
vec3d Cam::get3dcoord(vec3d p) {
float mx = p.x - pos.x;
float my = p.y - pos.y;
float mz = p.z - pos.z;
float dx = cos(rot.y) * (sin(rot.z) * my + cos(rot.z) * mx) - sin(rot.y) * mz;
float dy = sin(rot.x) * (cos(rot.y) * mz + sin(rot.y) * (sin(rot.z) * my + cos(rot.z) * mx)) + cos(rot.x) * (cos(rot.z) * my + sin(rot.z) * mx);
float dz = cos(rot.x) * (cos(rot.y) * mz + sin(rot.y) * (sin(rot.z) * my + cos(rot.z) * mx)) - sin(rot.x) * (cos(rot.z) * my + sin(rot.z) * mx);
return { dx, dy, dz };
}
vec3d Cam::get2dcoord(vec3d p) {
float e = (float)tan(fov / 2) * (float)(WIDTH / 2);
float x = (WIDTH / 2) + (e * p.x) / p.z;
float y = (HEIGHT / 2) + (e * p.y) / p.z;
return { x, y, 0 };
}
3D engine.h: main
#pragma once
#ifndef _3D_ENGINE_H_
#define _3D_ENGINE_H_
#endif
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <iostream>
#include <stdlib.h>
#include <sstream>
#include <list>
#include "Struct.h"
#include "Camera.h"
#include "Init.h"
#include "Noise.h"
#include "Terrain.h"
#define endl "\n"
void draw_triangle(vec3d p1, vec3d p2, vec3d p3, int color[]);
vec3d Vector_Sub(vec3d& v1, vec3d& v2);
float Vector_DotProduct(vec3d& v1, vec3d& v2);
3D engine.cpp:
#include "3D engine.h"
sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT), "3D game in progress");
const sf::Vector2i windowCenter(WIDTH / 2, HEIGHT / 2);
Cam cam({ 0.0f, -40.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, 90, 2.0f);
Terrain terrain;
sf::VertexArray TriangleToDraw(sf::Triangles);
void draw_triangle(vec3d p1, vec3d p2, vec3d p3, int color[]) {
sf::VertexArray tri(sf::Triangles, 3);
tri[0].position = sf::Vector2f(p1.x, p1.y);
tri[1].position = sf::Vector2f(p2.x, p2.y);
tri[2].position = sf::Vector2f(p3.x, p3.y);
tri[0].color = sf::Color((int)color[0], (int)color[1], (int)color[2]);
tri[1].color = sf::Color((int)color[0], (int)color[1], (int)color[2]);
tri[2].color = sf::Color((int)color[0], (int)color[1], (int)color[2]);
TriangleToDraw.append(tri[0]);
TriangleToDraw.append(tri[1]);
TriangleToDraw.append(tri[2]);
}
vec3d Vector_Sub(vec3d& v1, vec3d& v2) {
return { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
}
float Vector_DotProduct(vec3d& v1, vec3d& v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
int main() {
window.setMouseCursorVisible(false);
sf::Mouse::setPosition(windowCenter, window);
terrain.make_value();
terrain.triangle_Strip();
while (window.isOpen()) {
TriangleToDraw.clear();
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
if ((event.type == sf::Event::MouseLeft || event.type == sf::Event::MouseMoved) && sf::Mouse::getPosition(window) != windowCenter) {
sf::Vector2i pos = sf::Mouse::getPosition(window);
int x_a = pos.x;
int y_a = pos.y;
float movex = (float)(x_a - windowCenter.x) / 500.0f;
float movey = (float)(y_a - windowCenter.y) / 500.0f;
cam.rot.x -= movey;
cam.rot.y += movex;
sf::Mouse::setPosition(windowCenter, window);
}
}
float x = sin(cam.rot.y) * cam.speed; float z = cos(cam.rot.y) * cam.speed;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) { cam.pos.x -= x; cam.pos.z -= z; /*terrain.p.x -= x; terrain.p.z -= z;*/ }
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) { cam.pos.x += x; cam.pos.z += z; /*terrain.p.x += x; terrain.p.z += z;*/ }
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) { cam.pos.x += z; cam.pos.z -= x; /*terrain.p.x += z; terrain.p.z -= x;*/ }
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) { cam.pos.x -= z; cam.pos.z += x; /*terrain.p.x -= z; terrain.p.z += x;*/ }
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space)) cam.pos.y += cam.speed;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LSHIFT)) cam.pos.y -= cam.speed;
window.clear(sf::Color(0, 0, 0));
std::vector<triangle> triangles;
for (int i = 0, len = terrain.tris.size(); i < len; i++) {
std::vector<vec3d> projected(3);
for (int r = 0; r < 3; r++) projected[r] = cam.get3dcoord(terrain.tris[i].p[r]);
vec3d line1, line2, normal;
line1.x = projected[0].x - projected[1].x;
line1.y = projected[0].y - projected[1].y;
line1.z = projected[0].z - projected[1].z;
line2.x = projected[1].x - projected[2].x;
line2.y = projected[1].y - projected[2].y;
line2.z = projected[1].z - projected[2].z;
normal.x = line1.y * line2.z - line1.z * line2.y;
normal.y = line1.z * line2.x - line1.x * line2.z;
normal.z = line1.x * line2.y - line1.y * line2.x;
float l = sqrtf(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);
normal.x /= l; normal.y /= l; normal.z /= l;
vec3d vCameraRay1 = Vector_Sub(projected[0], cam.pos);
if (Vector_DotProduct(normal, vCameraRay1) < 0.0f && projected[0].z < 0.0f && projected[1].z < 0.0f && projected[2].z < 0.0f/*avoid points behind the camera to be projected*/) {
vec3d light = { 0.0f, 0.0f, 1.0f };
float lNormal = sqrtf(powf(light.x, 2) + powf(light.y, 2) + powf(light.z, 2));
light.x /= lNormal; light.y /= lNormal; light.z /= lNormal;
float dp = std::max(0.3f, Vector_DotProduct(light, normal));
int c = 255 * dp;
triangles.push_back({projected[0], projected[1], projected[2], {c, c, c}});
}
}
std::sort(triangles.begin(), triangles.end(), [](triangle& t1, triangle& t2)
{
float z1 = (t1.p[0].z + t1.p[1].z + t1.p[2].z) / 3.0f;
float z2 = (t2.p[0].z + t2.p[1].z + t2.p[2].z) / 3.0f;
return z1 < z2;
});
for (triangle tri : triangles) {
draw_triangle(cam.get2dcoord(tri.p[0]), cam.get2dcoord(tri.p[1]), cam.get2dcoord(tri.p[2]), tri.color);
}
window.draw(TriangleToDraw);
window.display();
}
return 0;
}
One of the triangle that had the wrong normal:
Normal: -0.08
vCameraRay: -588.2, 19.0, -662.5
Vector Dotproduct: -74.7
Triangle Point1: 19.03, -35.10, -75.69
Triangle Point2: -1.28, -27.57, -92.94
Triangle Point3: -0.96, -25.79, -71.35
Camera position: 2.20, 627.26, 0.03
One of the triangle that had the wrong Dot Product:
Normal: 0.59
vCameraRay: 468.41, 13.59, -634.75
Vector DotProduct: -55.05
Triangle Point1: 13.59, -7.29, -55.05
Triangle Point2: 19.19, 7.04, -37.72
Trianlge Point3: 0.00, 9.75, -28.36
Camera pos: 0.00, 627.45, 0.00

Double Pendulum returning nan results. Why?

When I run this code the double pendulum shows for a split second and then disappears. It seems most of the variables in the formula, num1, num2, etc., start returning nan after that split second when the pendulum disappears. Can anyone see why? I thought it had to do with converting degrees to radians at 180 degrees so I added the if statement in my convert function.
Here is the link to the Double Pendulum motion formula. I broke down the formula into pieces for simplicity's sake. https://www.myphysicslab.com/pendulum/double-pendulum-en.html
This idea came from Coding Train's Double Pendulum video: https://www.youtube.com/watch?v=uWzPe_S-RVE
#undef __STRICT_ANSI__
#include "window.h"
#include <SFML/Graphics.hpp>
#include <GL/glew.h>
#include <cmath>
#include <iostream>
namespace Window
{
sf::ContextSettings settings;
sf::RenderWindow window(sf::VideoMode(600, 600), "Window", sf::Style::Close | sf::Style::Titlebar, settings);
void init()
{
settings.depthBits = 24;
settings.majorVersion = 4;
settings.minorVersion = 6; //OpenGL 4.6
glewInit();
glViewport(0,0, 600, 600);
}
void close()
{
window.close();
}
void update()
{
window.display();
}
void checkForClose()
{
sf::Event windowEvent;
while (window.pollEvent(windowEvent))
{
if (windowEvent.type == sf::Event::Closed)
{
close();
}
}
}
bool isOpen()
{
return window.isOpen();
}
double convDeg(double deg)
{
if (deg == 180.0)
{
return 0.0;
}
else
{
return deg * M_PI / 180.0;
}
}
void runLoop()
{
double r1 = 100;
double m1 = 40;
double a1 = 90;
double a1_v = 0;
double r2 = 100;
double m2 = 40;
double a2 = 30;
double a2_v = 0;
double x1 = 0;
double x2 = 0;
double y1 = 0;
double y2 = 0;
double g = 0.005;
double num1 = 0;
double num2 = 0;
double num3 = 0;
double num4 = 0;
double den = 0;
double a1_a = 0;
double a2_a = 0;
while (window.isOpen())
{
num1 = -g * (2 * m1 + m2) * std::sin(convDeg(a1));
num2 = -m2 * g * std::sin(convDeg(a1-2*a2));
num3 = -2*std::sin(convDeg(a1-a2))*m2;
num4 = a2_v*a2_v*r2+a1_v*a1_v*r1*std::cos(convDeg(a1-a2));
den = r1 * (2*m1+m2-m2*cos(convDeg(2*a1-2*a2)));
a1_a = (num1 + num2 + num3*num4) / den;
num1 = 2 * std::sin(convDeg(a1-a2));
num2 = (a1_v*a1_v*r1*(m1+m2));
num3 = g * (m1 + m2) * std::cos(convDeg(a1));
num4 = a2_v*a2_v*r2*m2*std::cos(convDeg(a1-a2));
den = r2 * (2*m1+m2-m2*std::cos(convDeg(2*a1-2*a2)));
a2_a = (num1*(num2+num3+num4)) / den;
x1 = 300 + (r1 * std::sin((convDeg(a1))));
y1 = 300 + (r1 * std::cos((convDeg(a1))));
x2 = x1 + (r2 * std::sin((convDeg(a2))));
y2 = y1 + (r2 * std::cos((convDeg(a2))));
a1_v += a1_a;
a2_v += a2_a;
a1 += a1_v;
a2 += a2_v;
sf::Vertex pOne[] =
{
sf::Vertex(sf::Vector2f(300,300)),
sf::Vertex(sf::Vector2f(x1,y1)),
};
sf::Vertex pTwo[] =
{
sf::Vertex(sf::Vector2f(x1,y1)),
sf::Vertex(sf::Vector2f(x2,y2)),
};
window.clear();
window.draw(pOne, 2, sf::Lines);
window.draw(pTwo, 2, sf::Lines);
update();
checkForClose();
std::cout << std::sin(convDeg(a1)) << "\n";
}
}
}
List of problems:
convDeg: 180 and 0 degrees are not equivalent.
Angular variables: acceleration / velocity a1_a, a1_v etc are in radians, whereas your angle variables a1, a2 etc are in degrees. Every time the loop runs, your code wrongly converts degrees into radians. Do the conversion before the main loop.
(Speculation based on a previous answer - I could be wrong) The formulas on MyPhysicsLab seem to contradict those from other sources, e.g. here and here; a quick calculation using Lagrangian mechanics agrees with these two sources and not MPL.

Making a heart in c++

I am extremely interested in making a heart.
I am aware of the geometric primitive types.
http://www.opentk.com/doc/chapter/2/opengl/geometry/primitives
I am curious about how I would go about getting a curved line. Would I have to use the cmath library and connect it from two points somehow?
I have been looking at a lot of different sites about the math behind making hearts.
http://www16.ocn.ne.jp/~akiko-y/heart2/index_heart2_E.html
http://www.mathematische-basteleien.de/heart.htm
I'm struggling with porting this math to c++, not the actual math; I am just beginning to learn the language.
I would love it if someone could please provide me with some example code and an explanation as I am unable to find this on the internet. Also I am using the SFML framework for this project.
Thank you!
Here is an example of the current code.
#include <SFML/Graphics.hpp>
#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>
int main()
{
sf::RenderWindow Window;
Window.create(sf::VideoMode(800, 600), "My First Smfl Game");
Window.setKeyRepeatEnabled(false);
sf::Texture pTexture;
while(Window.isOpen())
{
sf::Event Event;
while(Window.pollEvent(Event))
{
switch(Event.type)
{
case sf::Event::Closed:
Window.close();
break;
}
}
sf::VertexArray vArray(sf::Lines, 20);
vArray[0].position = sf::Vector2f(82, 300);
vArray[1].position = sf::Vector2f(82, 84);
vArray[2].position = sf::Vector2f(82, 84);
vArray[3].position = sf::Vector2f(200, 84);
vArray[4].position = sf::Vector2f(200, 84);
vArray[5].position = sf::Vector2f(200, 100);
vArray[6].position = sf::Vector2f(200, 100);
vArray[7].position = sf::Vector2f(99, 100);
vArray[8].position = sf::Vector2f(99, 100);
vArray[9].position = sf::Vector2f(99, 284);
vArray[10].position = sf::Vector2f(99, 284);
vArray[11].position = sf::Vector2f(200, 284);
vArray[12].position = sf::Vector2f(200, 284);
vArray[13].position = sf::Vector2f(200, 300);
vArray[14].position = sf::Vector2f(200, 300);
vArray[15].position = sf::Vector2f(82, 300);
vArray[16].position = sf::Vector2f(250, 300);
vArray[17].position = sf::Vector2f(300, 82);
vArray[18].position = sf::Vector2f(380, 300);
vArray[19].position = sf::Vector2f(320, 82);
for(int k = 0; k < 20; k++)
{
int red = rand() % 255;
int green = rand() % 255;
int blue = rand() % 255;
vArray[k].color = sf::Color(red, green, blue);
}
Window.draw(vArray);
Window.display();
Window.clear();
}
}
Replace the hard-coded coordinates for your curve (all the vArray[.].position assignments) by code that generates the coordinates. To generate these coordinates, you simply have to sample one of the proposed curves from your references. What follows is a possible implementation of method 3 from your second link (it's the one with the four squares, which seemed simple enough to implement):
#include <vector>
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif // M_PI
// ...
int x0 = 800 / 2; // Coordinates of the center of the heart
int y0 = 600 / 2;
int size = 400; // Size of the heart
int r = size / 4; // Radius of the curves
int total_curve_vertex_count = 40; // Maximum number of vertices per curve
int total_vertex_count = 80; // Total number of vertices: 30 + 10 + 10 + 30
struct CurveInfo // Store information for each of the four square curves
{
int vertex_count;
double t0; // Angle origin
double s; // Angle sign: +1 or -1
int cx, cy; // (Relative) coordinates of the center of the curve
}
curve_infos[4] =
{
// Upper-left
{ 3 * total_curve_vertex_count / 4, 0.0, -1.0, -r, -r},
// Lower-left
{ total_curve_vertex_count / 4, 1.5 * M_PI, 1.0, -r, r},
// Lower-right
{ total_curve_vertex_count / 4, M_PI, 1.0, r, r},
// Upper-right
{ 3 * total_curve_vertex_count / 4, 0.5 * M_PI, -1.0, r, -r},
};
std::vector<sf::Vector2f> vertices(total_vertex_count);
int vertex_index = 0;
for(int i = 0; i < 4; i++)
{
CurveInfo& curve_info = curve_infos[i];
int vertex_count = curve_info.vertex_count;
double t0 = curve_info.t0;
double s = curve_info.s;
int cx = x0 + curve_info.cx;
int cy = y0 + curve_info.cy;
for(int j = 0; j < vertex_count; j++)
{
double dt = s * 2.0 * M_PI * j / (total_curve_vertex_count - 1);
int x = cx + r * cos(t0 + dt);
int y = cy + r * sin(t0 + dt);
vertices[vertex_index++] = sf::Vector2f(x, y);
}
}
// Generate the vertices of the lines primitives
int total_line_count = total_vertex_count - 1;
// Don't duplicate the first and last vertices
int line_vertex_count = 2 * total_vertex_count - 2;
sf::VertexArray vArray(sf::Lines, line_vertex_count);
int line_index = 0;
vertex_index = 0;
for(int k = 0; k < total_line_count; k++)
{
vArray[line_index++].position = vertices[vertex_index++];
vArray[line_index++].position = vertices[vertex_index];
}
for(int k = 0; k < line_vertex_count; k++)
{
int red = rand() % 255;
int green = rand() % 255;
int blue = rand() % 255;
vArray[k].color = sf::Color(red, green, blue);
}
// ...

Bezier curve using c++ opengl

I'm using this code to draw a Bézier curve by clicking a point. It works if I use the static formula that is written in drawBezier function, and it makes the right curve. But if I use the generalized formula written in drawBezierGeneralized, there's a problem with the last point.
What am I doing wrong?
#include <iostream>
#include <stdlib.h>
#include <GL/glut.h>
#include <math.h>
using namespace std;
//Point class for taking the points
class Point {
public:
float x, y;
void setxy(float x2, float y2)
{
x = x2; y = y2;
}
//operator overloading for '=' sign
const Point & operator=(const Point &rPoint)
{
x = rPoint.x;
y = rPoint.y;
return *this;
}
};
int factorial(int n)
{
if (n<=1)
return(1);
else
n=n*factorial(n-1);
return n;
}
float binomial_coff(float n,float k)
{
float ans;
ans = factorial(n) / (factorial(k)*factorial(n-k));
return ans;
}
Point abc[20];
int SCREEN_HEIGHT = 500;
int points = 0;
int clicks = 4;
void myInit() {
glClearColor(1.0,1.0,1.0,0.0);
glColor3f(0.0,0.0,0.0);
glPointSize(3);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,640.0,0.0,500.0);
}
void drawDot(int x, int y) {
glBegin(GL_POINTS);
glVertex2i(x,y);
glEnd();
glFlush();
}
void drawLine(Point p1, Point p2) {
glBegin(GL_LINES);
glVertex2f(p1.x, p1.y);
glVertex2f(p2.x, p2.y);
glEnd();
glFlush();
}
//Calculate the bezier point
Point drawBezier(Point PT[], double t) {
Point P;
P.x = pow((1 - t), 3) * PT[0].x + 3 * t * pow((1 -t), 2) * PT[1].x + 3 * (1-t) * pow(t, 2)* PT[2].x + pow (t, 3)* PT[3].x;
P.y = pow((1 - t), 3) * PT[0].y + 3 * t * pow((1 -t), 2) * PT[1].y + 3 * (1-t) * pow(t, 2)* PT[2].y + pow (t, 3)* PT[3].y;
return P;
}
//Calculate the bezier point [generalized]
Point drawBezierGeneralized(Point PT[], double t) {
Point P;
P.x = 0;P.y=0;
for(int i=0;i<clicks;i++)
{
P.x = P.x + binomial_coff((float)clicks,(float)i) * pow(t,(double)i) * pow((1-t),(clicks-i)) * PT[i].x;
P.y = P.y + binomial_coff((float)clicks,(float)i) * pow(t,(double)i) * pow((1-t),(clicks-i)) * PT[i].y;
}
//cout<<P.x<<endl<<P.y;
//cout<<endl<<endl;
return P;
}
void myMouse(int button, int state, int x, int y) {
// If left button was clicked
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
// Store where mouse was clicked, Y is backwards.
abc[points].setxy((float)x,(float)(SCREEN_HEIGHT - y));
points++;
// Draw the red dot.
drawDot(x, SCREEN_HEIGHT - y);
// If (click-amout) points are drawn do the curve.
if(points == clicks)
{
glColor3f(0.2,1.0,0.0);
// Drawing the control lines
for(int k=0;k<clicks-1;k++)
drawLine(abc[k], abc[k+1]);
Point p1 = abc[0];
/* Draw each segment of the curve.Make t increment in smaller amounts for a more detailed curve.*/
for(double t = 0.0;t <= 1.0; t += 0.02)
{
Point p2 = drawBezierGeneralized(abc,t);
cout<<p1.x<<" , "<<p1.y<<endl;
cout<<p2.x<<" , "<<p2.y<<endl;
cout<<endl;
drawLine(p1, p2);
p1 = p2;
}
glColor3f(0.0,0.0,0.0);
points = 0;
}
}
}
void myDisplay() {
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(640,500);
glutInitWindowPosition(100,150);
glutCreateWindow("Bezier Curve");
glutMouseFunc(myMouse);
glutDisplayFunc(myDisplay);
myInit();
glutMainLoop();
return 0;
}
I found what the problem was. Hope this is not too late.
Also, thanks for your code.
Point drawBezierGeneralized(Point PT[], double t) {
Point P;
P.x = 0; P.y = 0;
for (int i = 0; i<clicks; i++)
{
P.x = P.x + binomial_coff((float)(clicks - 1), (float)i) * pow(t, (double)i) * pow((1 - t), (clicks - 1 - i)) * PT[i].x;
P.y = P.y + binomial_coff((float)(clicks - 1), (float)i) * pow(t, (double)i) * pow((1 - t), (clicks - 1 - i)) * PT[i].y;
}
//cout<<P.x<<endl<<P.y;
//cout<<endl<<endl;
return P;
}
I think the problem is in the call to the primitive.
for(double t = 0.0;t <= 1.0; t += 0.02)
{
//Point p2 = drawBezierGeneralized(abc,t); -> here is the problem, you call the generalized
Point p2 = drawBezier(abc,t);
cout<<p1.x<<" , "<<p1.y<<endl;
cout<<p2.x<<" , "<<p2.y<<endl;
cout<<endl;
drawLine(p1, p2);
p1 = p2;
}