#include <thread>
#include <mutex>
#include <atomic>
#include <vector>
#include "./nvToolsExt.h"
#include "test.h"
#include <random>
#include <queue>
#include <unordered_set>
#include <cstdint>
#include <future>
// Just some hints on implementation
// You could remove all of them
struct PointStruct
{
std::atomic<float> _ax;
std::atomic<float> _ay;
bool _flag;
PointStruct()
:_ax(0), _ay(0), _flag(false)
{}
PointStruct(const std::atomic<float>& ax, const std::atomic<float>& ay, const bool flag)
{
_ax = ax.load();
_ay = ay.load();
_flag = flag;
}
PointStruct(const PointStruct& other)
{
_ax = other._ax.load();
_ay = other._ay.load();
_flag = other._flag;
}
PointStruct& operator=(const PointStruct& other)
{
_ax.store(other._ax.load());
_ay.store(other._ay.load());
_flag = other._flag;
}
};
static std::atomic_int globalTime;
static std::atomic_bool workerMustExit = false;
static std::atomic_bool counterMustExit = false;
static std::thread workerThread;
static std::thread counterThread;
std::vector<PointStruct> points(130880, {0,0,false});
std::vector<std::vector<float>> velocities(130880, { 0.0,0.0});
std::vector<std::vector<float>> alphaC(130880, { 0.0,0.0 });
std::vector<std::vector<int>> intData(64, { 0,0,0, false});
std::vector<float> V0(130880, 0.0);
static int startPointCount = 0;
//std::mutex mtx;
bool hitOnce = false;
bool flag = false;
const float g = 0.5;
int RandomGenerator( int num)
{
std::random_device rd; // a seed source for the random number engine
std::mt19937 gen(rd()); // mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<> distrib(1, num);
return distrib(gen);
}
void alpha()
{
for (int i = 0; i < alphaC.size(); ++i)
{
alphaC[i][0] = RandomGenerator(100) * 0.01;
alphaC[i][1] = pow(1 - (alphaC[i][0] * alphaC[i][0]),0.5);
}
/*for (int i = alphaC.size() / 2; i < alphaC.size(); ++i)
{
alphaC[i][0] = RandomGenerator(100) * (-0.01);
alphaC[i][1] = pow(1 - (alphaC[i][0] * alphaC[i][0]), 0.5);
}*/
}
void velo(int time)
{
float delta;
int j;
for (int i = 0; i < velocities.size(); ++i)
{
j = i / 64;
if (points[i]._flag && j<64)
{
delta = (time - intData[j][2]) * 0.01;
velocities[i][0] = V0[i] * alphaC[i][1];
velocities[i][1] = V0[i] * alphaC[i][0] - g * delta;
}
}
}
void position(int time)
{
//std::lock_guard<std::mutex> lock(mtx);
//float time = delta * 0.001;
float delta;
int j;
for (int i = 0; i < velocities.size(); ++i)
{
j = i / 64;
if (points[i]._flag && j < 64)
{
delta = (time - intData[j][2]) * 0.01;
points[i]._ax = intData[j][0] + velocities[i][0] * delta;
points[i]._ay = intData[j][1] + (V0[i] * 0.7 * delta - (g * delta * delta) / 2);
if (points[i]._ax > 1025 || points[i]._ay > 765)
points[i]._flag = false;
}
}
}
// some code
//видимо тут лежит логика на обновление картинки
void WorkerThread(void)
{
while (!workerMustExit)
{
nvtxRangePush(__FUNCTION__);
static int lastTime = 0;
const int time = globalTime.load();
const int delta = time - lastTime;
lastTime = time;
if (delta > 0 && flag)
{
//int t = time - t0;
/*velo(t);
position(t);*/
test::render();
}
static const int MIN_UPDATE_PERIOD_MS = 10;
if (delta < MIN_UPDATE_PERIOD_MS)
std::this_thread::sleep_for(std::chrono::milliseconds(MIN_UPDATE_PERIOD_MS - delta));
nvtxRangePop();
}
}
//инициализация нашего класса
void test::init(void)
{
// some code
std::random_device rd; // a seed source for the random number engine
std::mt19937 gen(rd()); // mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<> distrib(1, 20);
for (int i = 0; i < V0.size(); ++i)
{
V0[i] = RandomGenerator(5)* RandomGenerator(10);
}
alpha();
workerThread = std::thread(WorkerThread);
// some code
}
//тут завершаем работу
void test::term(void)
{
// some code
workerMustExit = true;
counterMustExit = true;
// some code
workerThread.join();
counterThread.join();
// some code
}
//рендерим картинку, ну то есть говорим что пока рисовать
void test::render(void)
{
// some code
if (flag)
{
for (int i = 0; i < points.size(); ++i)
{
if (points[i]._flag)
{
platform::drawPoint(points[i]._ax, points[i]._ay, 1, 1, 1, 1);
}
}
}
// platform::drawPoint(testPair.first, testPair.second, 1, 1, 1, 1);
// some code
}
//
void test::update(int dt)
{
// some code
// Atomically replaces the current value with the result of arithmetic addition of the value and arg
globalTime.fetch_add(dt);
// some code
}
//тут реагируем на клик
void test::on_click(int x, int y)
{
if (!flag)
{
//counterThread.detach();
intData[startPointCount][0] = x;
intData[startPointCount][1] = 765 - y;
intData[startPointCount][2] = globalTime.load();
intData[startPointCount][3] = true;
/*startX = x;
startY = y;
t0 = globalTime.load();*/
//points.assign(64, { (float)intData[startPointCount][0],(float)intData[startPointCount][1],true });
for (int i = 0; i < 64; ++i)
{
points[i]._ax = intData[startPointCount][0];
points[i]._ay = intData[startPointCount][1];
points[i]._flag = true;
}
//testPair = { (float)x,(float)y };
counterThread = std::thread(PointsThread);
flag = true;
}
}
int GenerateValidPosition( int range)
{
int i = 0;
do
{
i = RandomGenerator(range);
} while (!points[i]._flag);
return i;
}
void AssignNewPoints(std::vector<std::vector<int>> intData, int range)
{
for (int i = range; i < range + 64; ++i)
{
points[i]._ax = intData[startPointCount][0];
points[i]._ay = intData[startPointCount][1];
//points[i][2] = intData[startPointCount][2];
points[i]._flag = true;
}
}
void test::PointsThread(void)
{
while (!counterMustExit)
{
static int lastTime = 0;
const int time = globalTime.load();
const int delta = time - lastTime;
lastTime = time;
if (delta > 0 && flag)
{
//int t = time - t0;
velo(time);
position(time);
}
if (!hitOnce && time-intData[startPointCount][2] > 1500 ) //тут условие что я только один раз зайду сюда как только время жизни потока привысит 1500млс
{
hitOnce = true;
int destroyOrBlow = 63; // это колличество точек которые либо взорвутся либо погаснут
while (destroyOrBlow > 0)// это счетчик
{
int range = startPointCount + 64;//тут я высчитываю новый последний элемент
int position = GenerateValidPosition(range);//рандомно выбираю позицию
if (destroyOrBlow % 2)//тупо для выборки кому тухнуть а кому нет
{
startPointCount++;//увеличивается так как новый блок точек должен добавиться, счетчик партий точек
//сетим новые стартовые значения в вектор ноду(вектор начальных данных:координаты, начальное время, флаг)
intData[startPointCount][0] = points[position]._ax;
intData[startPointCount][1] = points[position]._ay;
intData[startPointCount][2] = globalTime.load();
intData[startPointCount][3] = true;
//загоняем новый блок точек в вектор точек
AssignNewPoints(intData, range);
}
else
points[destroyOrBlow]._flag = false;//уничтожаем точки, больше нам их показывать не надо
destroyOrBlow--;//уменьшаем счетчик
}
}
}
}