Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3887208b8d | ||
|
|
4c837eff0a | ||
|
|
8f9a18d960 | ||
|
|
bc49540a95 | ||
|
|
d2605d9108 | ||
|
|
115cbbb7fa | ||
| ae1ca71a20 | |||
| c02273d29d | |||
| fec7e08c2b | |||
| 0f937e2e02 | |||
|
|
b855cff0e6 | ||
|
|
b768b27d49 |
@ -436,6 +436,10 @@ add_executable(space-game001
|
||||
OpenGlExtensions.h
|
||||
Utils.cpp
|
||||
Utils.h
|
||||
SparkEmitter.cpp
|
||||
SparkEmitter.h
|
||||
PlanetObject.cpp
|
||||
PlanetObject.h
|
||||
)
|
||||
|
||||
# Установка проекта по умолчанию для Visual Studio
|
||||
|
||||
@ -8,7 +8,7 @@ namespace ZL {
|
||||
int Environment::windowHeaderHeight = 0;
|
||||
int Environment::width = 0;
|
||||
int Environment::height = 0;
|
||||
float Environment::zoom = 6.f;
|
||||
float Environment::zoom = 14.f;
|
||||
|
||||
bool Environment::leftPressed = false;
|
||||
bool Environment::rightPressed = false;
|
||||
|
||||
904
Game.cpp
904
Game.cpp
@ -1,4 +1,4 @@
|
||||
#include "Game.h"
|
||||
#include "Game.h"
|
||||
#include "AnimatedModel.h"
|
||||
#include "BoneAnimatedModel.h"
|
||||
#include "Utils.h"
|
||||
@ -12,445 +12,615 @@
|
||||
namespace ZL
|
||||
{
|
||||
#ifdef EMSCRIPTEN
|
||||
const char* CONST_ZIP_FILE = "space-game001.zip";
|
||||
const char* CONST_ZIP_FILE = "space-game001.zip";
|
||||
#else
|
||||
const char* CONST_ZIP_FILE = "";
|
||||
const char* CONST_ZIP_FILE = "";
|
||||
#endif
|
||||
|
||||
Vector4f generateRandomQuaternion(std::mt19937& gen)
|
||||
{
|
||||
// Ðàñïðåäåëåíèå äëÿ ãåíåðàöèè ñëó÷àéíûõ êîîðäèíàò êâàòåðíèîíà
|
||||
std::normal_distribution<> distrib(0.0, 1.0);
|
||||
Vector4f generateRandomQuaternion(std::mt19937& gen)
|
||||
{
|
||||
// Ðàñïðåäåëåíèå äëÿ ãåíåðàöèè ñëó÷àéíûõ êîîðäèíàò êâàòåðíèîíà
|
||||
std::normal_distribution<> distrib(0.0, 1.0);
|
||||
|
||||
// Ãåíåðèðóåì ÷åòûðå ñëó÷àéíûõ ÷èñëà èç íîðìàëüíîãî ðàñïðåäåëåíèÿ N(0, 1).
|
||||
// Íîðìàëèçàöèÿ ýòîãî âåêòîðà äàåò ðàâíîìåðíîå ðàñïðåäåëåíèå ïî 4D-ñôåðå (ò.å. êâàòåðíèîí åäèíè÷íîé äëèíû).
|
||||
Vector4f randomQuat = {
|
||||
(float)distrib(gen),
|
||||
(float)distrib(gen),
|
||||
(float)distrib(gen),
|
||||
(float)distrib(gen)
|
||||
};
|
||||
// Ãåíåðèðóåì ÷åòûðå ñëó÷àéíûõ ÷èñëà èç íîðìàëüíîãî ðàñïðåäåëåíèÿ N(0, 1).
|
||||
// Íîðìàëèçàöèÿ ýòîãî âåêòîðà äàåò ðàâíîìåðíîå ðàñïðåäåëåíèå ïî 4D-ñôåðå (ò.å. êâàòåðíèîí åäèíè÷íîé äëèíû).
|
||||
Vector4f randomQuat = {
|
||||
(float)distrib(gen),
|
||||
(float)distrib(gen),
|
||||
(float)distrib(gen),
|
||||
(float)distrib(gen)
|
||||
};
|
||||
|
||||
return randomQuat.normalized();
|
||||
}
|
||||
return randomQuat.normalized();
|
||||
}
|
||||
|
||||
|
||||
// --- Îñíîâíàÿ ôóíêöèÿ ãåíåðàöèè ---
|
||||
std::vector<BoxCoords> generateRandomBoxCoords(int N)
|
||||
{
|
||||
// Êîíñòàíòû
|
||||
const float MIN_DISTANCE = 3.0f;
|
||||
const float MIN_DISTANCE_SQUARED = MIN_DISTANCE * MIN_DISTANCE; // Ðàáîòàåì ñ êâàäðàòîì ðàññòîÿíèÿ
|
||||
const float MIN_COORD = -100.0f;
|
||||
const float MAX_COORD = 100.0f;
|
||||
const int MAX_ATTEMPTS = 1000; // Îãðàíè÷åíèå íà êîëè÷åñòâî ïîïûòîê, ÷òîáû èçáåæàòü áåñêîíå÷íîãî öèêëà
|
||||
// --- Îñíîâíàÿ ôóíêöèÿ ãåíåðàöèè ---
|
||||
std::vector<BoxCoords> generateRandomBoxCoords(int N)
|
||||
{
|
||||
// Êîíñòàíòû
|
||||
const float MIN_DISTANCE = 3.0f;
|
||||
const float MIN_DISTANCE_SQUARED = MIN_DISTANCE * MIN_DISTANCE; // Ðàáîòàåì ñ êâàäðàòîì ðàññòîÿíèÿ
|
||||
const float MIN_COORD = -100.0f;
|
||||
const float MAX_COORD = 100.0f;
|
||||
const int MAX_ATTEMPTS = 1000; // Îãðàíè÷åíèå íà êîëè÷åñòâî ïîïûòîê, ÷òîáû èçáåæàòü áåñêîíå÷íîãî öèêëà
|
||||
|
||||
std::vector<BoxCoords> boxCoordsArr;
|
||||
boxCoordsArr.reserve(N); // Ðåçåðâèðóåì ïàìÿòü
|
||||
std::vector<BoxCoords> boxCoordsArr;
|
||||
boxCoordsArr.reserve(N); // Ðåçåðâèðóåì ïàìÿòü
|
||||
|
||||
// 1. Èíèöèàëèçàöèÿ ãåíåðàòîðà ïñåâäîñëó÷àéíûõ ÷èñåë
|
||||
// Èñïîëüçóåì Mersenne Twister (mt19937) êàê âûñîêîêà÷åñòâåííûé ãåíåðàòîð
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
// 1. Èíèöèàëèçàöèÿ ãåíåðàòîðà ïñåâäîñëó÷àéíûõ ÷èñåë
|
||||
// Èñïîëüçóåì Mersenne Twister (mt19937) êàê âûñîêîêà÷åñòâåííûé ãåíåðàòîð
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
|
||||
// 2. Îïðåäåëåíèå ðàâíîìåðíîãî ðàñïðåäåëåíèÿ äëÿ êîîðäèíàò [MIN_COORD, MAX_COORD]
|
||||
std::uniform_real_distribution<> distrib(MIN_COORD, MAX_COORD);
|
||||
// 2. Îïðåäåëåíèå ðàâíîìåðíîãî ðàñïðåäåëåíèÿ äëÿ êîîðäèíàò [MIN_COORD, MAX_COORD]
|
||||
std::uniform_real_distribution<> distrib(MIN_COORD, MAX_COORD);
|
||||
|
||||
int generatedCount = 0;
|
||||
int generatedCount = 0;
|
||||
|
||||
while (generatedCount < N)
|
||||
{
|
||||
bool accepted = false;
|
||||
int attempts = 0;
|
||||
while (generatedCount < N)
|
||||
{
|
||||
bool accepted = false;
|
||||
int attempts = 0;
|
||||
|
||||
// Ïîïûòêà íàéòè ïîäõîäÿùèå êîîðäèíàòû
|
||||
while (!accepted && attempts < MAX_ATTEMPTS)
|
||||
{
|
||||
// Ãåíåðèðóåì íîâûå ñëó÷àéíûå êîîðäèíàòû
|
||||
Vector3f newPos(
|
||||
(float)distrib(gen),
|
||||
(float)distrib(gen),
|
||||
(float)distrib(gen)
|
||||
);
|
||||
// Ïîïûòêà íàéòè ïîäõîäÿùèå êîîðäèíàòû
|
||||
while (!accepted && attempts < MAX_ATTEMPTS)
|
||||
{
|
||||
// Ãåíåðèðóåì íîâûå ñëó÷àéíûå êîîðäèíàòû
|
||||
Vector3f newPos(
|
||||
(float)distrib(gen),
|
||||
(float)distrib(gen),
|
||||
(float)distrib(gen)
|
||||
);
|
||||
|
||||
// Ïðîâåðêà ðàññòîÿíèÿ äî âñåõ óæå ñóùåñòâóþùèõ îáúåêòîâ
|
||||
accepted = true; // Ïðåäïîëàãàåì, ÷òî ïîäõîäèò, ïîêà íå äîêàçàíî îáðàòíîå
|
||||
for (const auto& existingBox : boxCoordsArr)
|
||||
{
|
||||
// Ðàñ÷åò âåêòîðà ðàçíîñòè
|
||||
Vector3f diff = newPos - existingBox.pos;
|
||||
// Ïðîâåðêà ðàññòîÿíèÿ äî âñåõ óæå ñóùåñòâóþùèõ îáúåêòîâ
|
||||
accepted = true; // Ïðåäïîëàãàåì, ÷òî ïîäõîäèò, ïîêà íå äîêàçàíî îáðàòíîå
|
||||
for (const auto& existingBox : boxCoordsArr)
|
||||
{
|
||||
// Ðàñ÷åò âåêòîðà ðàçíîñòè
|
||||
Vector3f diff = newPos - existingBox.pos;
|
||||
|
||||
// Ðàñ÷åò êâàäðàòà ðàññòîÿíèÿ
|
||||
float distanceSquared = diff.squaredNorm();
|
||||
// Ðàñ÷åò êâàäðàòà ðàññòîÿíèÿ
|
||||
float distanceSquared = diff.squaredNorm();
|
||||
|
||||
// Åñëè êâàäðàò ðàññòîÿíèÿ ìåíüøå êâàäðàòà ìèíèìàëüíîãî ðàññòîÿíèÿ
|
||||
if (distanceSquared < MIN_DISTANCE_SQUARED)
|
||||
{
|
||||
accepted = false; // Îòêëîíÿåì, ñëèøêîì áëèçêî
|
||||
break; // Íåò ñìûñëà ïðîâåðÿòü äàëüøå, åñëè îäíî íàðóøåíèå íàéäåíî
|
||||
}
|
||||
}
|
||||
// Åñëè êâàäðàò ðàññòîÿíèÿ ìåíüøå êâàäðàòà ìèíèìàëüíîãî ðàññòîÿíèÿ
|
||||
if (distanceSquared < MIN_DISTANCE_SQUARED)
|
||||
{
|
||||
accepted = false; // Îòêëîíÿåì, ñëèøêîì áëèçêî
|
||||
break; // Íåò ñìûñëà ïðîâåðÿòü äàëüøå, åñëè îäíî íàðóøåíèå íàéäåíî
|
||||
}
|
||||
}
|
||||
|
||||
if (accepted)
|
||||
{
|
||||
// 2. Ãåíåðèðóåì ñëó÷àéíûé êâàòåðíèîí
|
||||
Vector4f randomQuat = generateRandomQuaternion(gen);
|
||||
if (accepted)
|
||||
{
|
||||
// 2. Ãåíåðèðóåì ñëó÷àéíûé êâàòåðíèîí
|
||||
Vector4f randomQuat = generateRandomQuaternion(gen);
|
||||
|
||||
// 3. Ïðåîáðàçóåì åãî â ìàòðèöó âðàùåíèÿ
|
||||
Matrix3f randomMatrix = QuatToMatrix(randomQuat);
|
||||
// 3. Ïðåîáðàçóåì åãî â ìàòðèöó âðàùåíèÿ
|
||||
Matrix3f randomMatrix = QuatToMatrix(randomQuat);
|
||||
|
||||
// 4. Äîáàâëÿåì îáúåêò ñ íîâîé ñëó÷àéíîé ìàòðèöåé
|
||||
boxCoordsArr.emplace_back(BoxCoords{ newPos, randomMatrix });
|
||||
generatedCount++;
|
||||
}
|
||||
attempts++;
|
||||
}
|
||||
// 4. Äîáàâëÿåì îáúåêò ñ íîâîé ñëó÷àéíîé ìàòðèöåé
|
||||
boxCoordsArr.emplace_back(BoxCoords{ newPos, randomMatrix });
|
||||
generatedCount++;
|
||||
}
|
||||
attempts++;
|
||||
}
|
||||
|
||||
// Åñëè ïðåâûøåíî ìàêñèìàëüíîå êîëè÷åñòâî ïîïûòîê, âûõîäèì èç öèêëà,
|
||||
// ÷òîáû èçáåæàòü çàâèñàíèÿ, åñëè N ñëèøêîì âåëèêî èëè äèàïàçîí ñëèøêîì ìàë.
|
||||
if (!accepted) {
|
||||
std::cerr << "Ïðåäóïðåæäåíèå: Íå óäàëîñü ñãåíåðèðîâàòü " << N << " îáúåêòîâ. Ñãåíåðèðîâàíî: " << generatedCount << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Åñëè ïðåâûøåíî ìàêñèìàëüíîå êîëè÷åñòâî ïîïûòîê, âûõîäèì èç öèêëà,
|
||||
// ÷òîáû èçáåæàòü çàâèñàíèÿ, åñëè N ñëèøêîì âåëèêî èëè äèàïàçîí ñëèøêîì ìàë.
|
||||
if (!accepted) {
|
||||
std::cerr << "Ïðåäóïðåæäåíèå: Íå óäàëîñü ñãåíåðèðîâàòü " << N << " îáúåêòîâ. Ñãåíåðèðîâàíî: " << generatedCount << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return boxCoordsArr;
|
||||
}
|
||||
return boxCoordsArr;
|
||||
}
|
||||
|
||||
Game::Game()
|
||||
: window(nullptr)
|
||||
, glContext(nullptr)
|
||||
, newTickCount(0)
|
||||
, lastTickCount(0)
|
||||
{
|
||||
}
|
||||
Game::Game()
|
||||
: window(nullptr)
|
||||
, glContext(nullptr)
|
||||
, newTickCount(0)
|
||||
, lastTickCount(0)
|
||||
{
|
||||
std::vector<Vector3f> emissionPoints = {
|
||||
Vector3f{-2.1f, 0.9f, 5.0f},
|
||||
Vector3f{2.1f, 0.9f, 5.0f}
|
||||
};
|
||||
sparkEmitter = SparkEmitter(emissionPoints, 100.0f);
|
||||
}
|
||||
|
||||
Game::~Game() {
|
||||
if (glContext) {
|
||||
SDL_GL_DeleteContext(glContext);
|
||||
}
|
||||
if (window) {
|
||||
SDL_DestroyWindow(window);
|
||||
}
|
||||
SDL_Quit();
|
||||
}
|
||||
Game::~Game() {
|
||||
if (glContext) {
|
||||
SDL_GL_DeleteContext(glContext);
|
||||
}
|
||||
if (window) {
|
||||
SDL_DestroyWindow(window);
|
||||
}
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
void Game::setup() {
|
||||
glContext = SDL_GL_CreateContext(ZL::Environment::window);
|
||||
void Game::setup() {
|
||||
glContext = SDL_GL_CreateContext(ZL::Environment::window);
|
||||
|
||||
ZL::BindOpenGlFunctions();
|
||||
ZL::CheckGlError();
|
||||
ZL::BindOpenGlFunctions();
|
||||
ZL::CheckGlError();
|
||||
|
||||
// Initialize renderer
|
||||
// Initialize renderer
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_web.fragment", CONST_ZIP_FILE);
|
||||
|
||||
#else
|
||||
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_desktop.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_desktop.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_desktop.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_desktop.fragment", CONST_ZIP_FILE);
|
||||
|
||||
#endif
|
||||
|
||||
cubemapTexture = std::make_shared<Texture>(
|
||||
std::array<TextureDataStruct, 6>{
|
||||
CreateTextureDataFromBmp24("./resources/sky/space_rt.bmp", CONST_ZIP_FILE),
|
||||
CreateTextureDataFromBmp24("./resources/sky/space_lf.bmp", CONST_ZIP_FILE),
|
||||
CreateTextureDataFromBmp24("./resources/sky/space_up.bmp", CONST_ZIP_FILE),
|
||||
CreateTextureDataFromBmp24("./resources/sky/space_dn.bmp", CONST_ZIP_FILE),
|
||||
CreateTextureDataFromBmp24("./resources/sky/space_bk.bmp", CONST_ZIP_FILE),
|
||||
CreateTextureDataFromBmp24("./resources/sky/space_ft.bmp", CONST_ZIP_FILE)
|
||||
});
|
||||
|
||||
|
||||
cubemap.data = ZL::CreateCubemap(500);
|
||||
cubemap.RefreshVBO();
|
||||
|
||||
//Load texture
|
||||
spaceshipTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/DefaultMaterial_BaseColor.png", CONST_ZIP_FILE));
|
||||
spaceshipBase = LoadFromTextFile02("./resources/spaceship005.txt", CONST_ZIP_FILE);
|
||||
spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0)));
|
||||
//spaceshipBase.Move(Vector3f{ -0.52998, -13, 0 });
|
||||
spaceshipBase.Move(Vector3f{ -0.52998, -10, 10 });
|
||||
|
||||
spaceship.AssignFrom(spaceshipBase);
|
||||
spaceship.RefreshVBO();
|
||||
|
||||
//Boxes
|
||||
boxTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/box/box.png", CONST_ZIP_FILE));
|
||||
boxBase = LoadFromTextFile02("./resources/box/box.txt", CONST_ZIP_FILE);
|
||||
|
||||
boxCoordsArr = generateRandomBoxCoords(50);
|
||||
|
||||
boxRenderArr.resize(boxCoordsArr.size());
|
||||
|
||||
for (int i = 0; i < boxCoordsArr.size(); i++)
|
||||
{
|
||||
boxRenderArr[i].AssignFrom(boxBase);
|
||||
boxRenderArr[i].RefreshVBO();
|
||||
}
|
||||
|
||||
renderer.InitOpenGL();
|
||||
|
||||
}
|
||||
|
||||
void Game::drawCubemap()
|
||||
{
|
||||
static const std::string defaultShaderName = "default";
|
||||
static const std::string envShaderName = "env";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
|
||||
renderer.shaderManager.PushShader(envShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
1, 1000);
|
||||
renderer.PushMatrix();
|
||||
renderer.LoadIdentity();
|
||||
renderer.RotateMatrix(Environment::inverseShipMatrix);
|
||||
|
||||
CheckGlError();
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(cubemap);
|
||||
|
||||
CheckGlError();
|
||||
cubemapTexture = std::make_shared<Texture>(
|
||||
std::array<TextureDataStruct, 6>{
|
||||
CreateTextureDataFromBmp24("./resources/sky/space_rt.bmp", CONST_ZIP_FILE),
|
||||
CreateTextureDataFromBmp24("./resources/sky/space_lf.bmp", CONST_ZIP_FILE),
|
||||
CreateTextureDataFromBmp24("./resources/sky/space_up.bmp", CONST_ZIP_FILE),
|
||||
CreateTextureDataFromBmp24("./resources/sky/space_dn.bmp", CONST_ZIP_FILE),
|
||||
CreateTextureDataFromBmp24("./resources/sky/space_bk.bmp", CONST_ZIP_FILE),
|
||||
CreateTextureDataFromBmp24("./resources/sky/space_ft.bmp", CONST_ZIP_FILE)
|
||||
});
|
||||
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
cubemap.data = ZL::CreateCubemap(500);
|
||||
cubemap.RefreshVBO();
|
||||
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
}
|
||||
void Game::drawShip()
|
||||
{
|
||||
static const std::string defaultShaderName = "default";
|
||||
static const std::string envShaderName = "env";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
//Load texture
|
||||
spaceshipTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/DefaultMaterial_BaseColor.png", CONST_ZIP_FILE));
|
||||
spaceshipBase = LoadFromTextFile02("./resources/spaceship005.txt", CONST_ZIP_FILE);
|
||||
spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0)));
|
||||
//spaceshipBase.Move(Vector3f{ -0.52998, -13, 0 });
|
||||
spaceshipBase.Move(Vector3f{ -0.52998, -10, 10 });
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
spaceship.AssignFrom(spaceshipBase);
|
||||
spaceship.RefreshVBO();
|
||||
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
1, 1000);
|
||||
renderer.PushMatrix();
|
||||
//Boxes
|
||||
boxTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/box/box.png", CONST_ZIP_FILE));
|
||||
boxBase = LoadFromTextFile02("./resources/box/box.txt", CONST_ZIP_FILE);
|
||||
|
||||
renderer.LoadIdentity();
|
||||
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
|
||||
boxCoordsArr = generateRandomBoxCoords(50);
|
||||
|
||||
boxRenderArr.resize(boxCoordsArr.size());
|
||||
|
||||
for (int i = 0; i < boxCoordsArr.size(); i++)
|
||||
{
|
||||
boxRenderArr[i].AssignFrom(boxBase);
|
||||
boxRenderArr[i].RefreshVBO();
|
||||
}
|
||||
|
||||
sparkTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/spark.png", CONST_ZIP_FILE));
|
||||
|
||||
sparkEmitter.setTexture(sparkTexture);
|
||||
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(spaceship);
|
||||
buttonTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/button.png", CONST_ZIP_FILE));
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
button.data.PositionData.push_back({ 100, 100, 0 });
|
||||
button.data.PositionData.push_back({ 100, 150, 0 });
|
||||
button.data.PositionData.push_back({ 300, 150, 0 });
|
||||
button.data.PositionData.push_back({ 100, 100, 0 });
|
||||
button.data.PositionData.push_back({ 300, 150, 0 });
|
||||
button.data.PositionData.push_back({ 300, 100, 0 });
|
||||
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
}
|
||||
button.data.TexCoordData.push_back({ 0,0 });
|
||||
button.data.TexCoordData.push_back({ 0,1 });
|
||||
button.data.TexCoordData.push_back({ 1,1 });
|
||||
button.data.TexCoordData.push_back({ 0,0 });
|
||||
button.data.TexCoordData.push_back({ 1,1 });
|
||||
button.data.TexCoordData.push_back({ 1,0 });
|
||||
|
||||
void Game::drawBoxes()
|
||||
{
|
||||
static const std::string defaultShaderName = "default";
|
||||
static const std::string envShaderName = "env";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
button.RefreshVBO();
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
musicVolumeBarTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/musicVolumeBarTexture.png", CONST_ZIP_FILE));
|
||||
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
1, 1000);
|
||||
musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1190, 600, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1200, 100, 0 });
|
||||
|
||||
for (int i = 0; i < boxCoordsArr.size(); i++)
|
||||
{
|
||||
renderer.PushMatrix();
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 0,1 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 1,0 });
|
||||
|
||||
renderer.LoadIdentity();
|
||||
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
|
||||
renderer.RotateMatrix(Environment::inverseShipMatrix);
|
||||
renderer.TranslateMatrix(-Environment::shipPosition);
|
||||
renderer.TranslateMatrix(boxCoordsArr[i].pos);
|
||||
renderer.RotateMatrix(boxCoordsArr[i].m);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(boxRenderArr[i]);
|
||||
musicVolumeBar.RefreshVBO();
|
||||
|
||||
renderer.PopMatrix();
|
||||
}
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
}
|
||||
musicVolumeBarButtonTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/musicVolumeBarButton.png", CONST_ZIP_FILE));
|
||||
|
||||
void Game::drawScene() {
|
||||
static const std::string defaultShaderName = "default";
|
||||
static const std::string envShaderName = "env";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
float musicVolumeBarButtonButtonCenterY = 350.0f;
|
||||
|
||||
glClearColor(0.0f, 0.5f, 1.0f, 1.0f);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glViewport(0, 0, Environment::width, Environment::height);
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
|
||||
|
||||
CheckGlError();
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 0,1 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 1,0 });
|
||||
|
||||
drawCubemap();
|
||||
drawShip();
|
||||
drawBoxes();
|
||||
|
||||
CheckGlError();
|
||||
}
|
||||
musicVolumeBarButton.RefreshVBO();
|
||||
renderer.InitOpenGL();
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
void Game::processTickCount() {
|
||||
planetObject.init();
|
||||
|
||||
if (lastTickCount == 0) {
|
||||
lastTickCount = SDL_GetTicks64();
|
||||
return;
|
||||
}
|
||||
|
||||
newTickCount = SDL_GetTicks64();
|
||||
if (newTickCount - lastTickCount > CONST_TIMER_INTERVAL) {
|
||||
size_t delta = (newTickCount - lastTickCount > CONST_MAX_TIME_INTERVAL) ?
|
||||
CONST_MAX_TIME_INTERVAL : newTickCount - lastTickCount;
|
||||
|
||||
//gameObjects.updateScene(delta);
|
||||
}
|
||||
|
||||
if (Environment::tapDownHold) {
|
||||
void Game::drawCubemap()
|
||||
{
|
||||
static const std::string defaultShaderName = "default";
|
||||
static const std::string envShaderName = "env";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
|
||||
float diffx = Environment::tapDownCurrentPos.v[0] - Environment::tapDownStartPos.v[0];
|
||||
float diffy = Environment::tapDownCurrentPos.v[1] - Environment::tapDownStartPos.v[1];
|
||||
renderer.shaderManager.PushShader(envShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
1, 1000);
|
||||
renderer.PushMatrix();
|
||||
renderer.LoadIdentity();
|
||||
renderer.RotateMatrix(Environment::inverseShipMatrix);
|
||||
|
||||
|
||||
if (abs(diffy) > 5.0 || abs(diffx) > 5.0) //threshold
|
||||
{
|
||||
CheckGlError();
|
||||
|
||||
float rotationPower = sqrtf(diffx * diffx + diffy * diffy);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(cubemap);
|
||||
|
||||
//std::cout << rotationPower << std::endl;
|
||||
CheckGlError();
|
||||
|
||||
float deltaAlpha = rotationPower * delta * M_PI / 500000.f;
|
||||
|
||||
Vector3f rotationDirection = { diffy, diffx, 0 };
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
|
||||
rotationDirection = rotationDirection.normalized();
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
}
|
||||
|
||||
Vector4f rotateQuat = {
|
||||
rotationDirection.v[0] * sin(deltaAlpha * 0.5f),
|
||||
rotationDirection.v[1] * sin(deltaAlpha * 0.5f),
|
||||
rotationDirection.v[2] * sin(deltaAlpha * 0.5f),
|
||||
cos(deltaAlpha * 0.5f) };
|
||||
void Game::drawShip()
|
||||
{
|
||||
static const std::string defaultShaderName = "default";
|
||||
static const std::string envShaderName = "env";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
|
||||
Matrix3f rotateMat = QuatToMatrix(rotateQuat);
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
Environment::shipMatrix = MultMatrixMatrix(Environment::shipMatrix, rotateMat);
|
||||
Environment::inverseShipMatrix = InverseMatrix(Environment::shipMatrix);
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
1, 1000);
|
||||
renderer.PushMatrix();
|
||||
|
||||
}
|
||||
}
|
||||
renderer.LoadIdentity();
|
||||
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
|
||||
|
||||
if (fabs(Environment::shipVelocity) > 0.01f)
|
||||
{
|
||||
Vector3f velocityDirection = { 0,0, -Environment::shipVelocity*delta / 1000.f };
|
||||
Vector3f velocityDirectionAdjusted = MultMatrixVector(Environment::shipMatrix, velocityDirection);
|
||||
|
||||
Environment::shipPosition = Environment::shipPosition + velocityDirectionAdjusted;
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(spaceship);
|
||||
sparkEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
|
||||
|
||||
lastTickCount = newTickCount;
|
||||
}
|
||||
}
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
|
||||
void Game::render() {
|
||||
SDL_GL_MakeCurrent(ZL::Environment::window, glContext);
|
||||
ZL::CheckGlError();
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
}
|
||||
|
||||
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
drawScene();
|
||||
processTickCount();
|
||||
void Game::drawBoxes()
|
||||
{
|
||||
static const std::string defaultShaderName = "default";
|
||||
static const std::string envShaderName = "env";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
|
||||
SDL_GL_SwapWindow(ZL::Environment::window);
|
||||
}
|
||||
void Game::update() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
if (event.type == SDL_QUIT) {
|
||||
Environment::exitGameLoop = true;
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
}
|
||||
else if (event.type == SDL_MOUSEBUTTONDOWN) {
|
||||
// 1. Îáðàáîòêà íàæàòèÿ êíîïêè ìûøè
|
||||
Environment::tapDownHold = true;
|
||||
// Êîîðäèíàòû íà÷àëüíîãî íàæàòèÿ
|
||||
Environment::tapDownStartPos.v[0] = event.button.x;
|
||||
Environment::tapDownStartPos.v[1] = event.button.y;
|
||||
// Íà÷àëüíàÿ ïîçèöèÿ òàêæå ñòàíîâèòñÿ òåêóùåé
|
||||
Environment::tapDownCurrentPos.v[0] = event.button.x;
|
||||
Environment::tapDownCurrentPos.v[1] = event.button.y;
|
||||
}
|
||||
else if (event.type == SDL_MOUSEBUTTONUP) {
|
||||
// 2. Îáðàáîòêà îòïóñêàíèÿ êíîïêè ìûøè
|
||||
Environment::tapDownHold = false;
|
||||
}
|
||||
else if (event.type == SDL_MOUSEMOTION) {
|
||||
// 3. Îáðàáîòêà ïåðåìåùåíèÿ ìûøè
|
||||
if (Environment::tapDownHold) {
|
||||
// Îáíîâëåíèå òåêóùåé ïîçèöèè, åñëè êíîïêà óäåðæèâàåòñÿ
|
||||
Environment::tapDownCurrentPos.v[0] = event.motion.x;
|
||||
Environment::tapDownCurrentPos.v[1] = event.motion.y;
|
||||
}
|
||||
}
|
||||
else if (event.type == SDL_MOUSEWHEEL) {
|
||||
static const float zoomstep = 2.0f;
|
||||
if (event.wheel.y > 0) {
|
||||
Environment::zoom -= zoomstep;
|
||||
}
|
||||
else if (event.wheel.y < 0) {
|
||||
Environment::zoom += zoomstep;
|
||||
}
|
||||
if (Environment::zoom < zoomstep) {
|
||||
Environment::zoom = zoomstep;
|
||||
}
|
||||
}
|
||||
else if (event.type == SDL_KEYUP)
|
||||
{
|
||||
if (event.key.keysym.sym == SDLK_i)
|
||||
{
|
||||
Environment::shipVelocity += 1.f;
|
||||
}
|
||||
if (event.key.keysym.sym == SDLK_k)
|
||||
{
|
||||
Environment::shipVelocity -= 1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
render();
|
||||
}
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
1, 1000);
|
||||
|
||||
} // namespace ZL
|
||||
for (int i = 0; i < boxCoordsArr.size(); i++)
|
||||
{
|
||||
renderer.PushMatrix();
|
||||
|
||||
renderer.LoadIdentity();
|
||||
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
|
||||
renderer.RotateMatrix(Environment::inverseShipMatrix);
|
||||
renderer.TranslateMatrix(-Environment::shipPosition);
|
||||
renderer.TranslateMatrix(boxCoordsArr[i].pos);
|
||||
renderer.RotateMatrix(boxCoordsArr[i].m);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(boxRenderArr[i]);
|
||||
|
||||
renderer.PopMatrix();
|
||||
}
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
}
|
||||
void Game::UpdateVolumeKnob() {
|
||||
float musicVolumeBarButtonButtonCenterY = volumeBarMinY + musicVolume * (volumeBarMaxY - volumeBarMinY);
|
||||
|
||||
auto& pos = musicVolumeBarButton.data.PositionData;
|
||||
|
||||
pos[0] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 };
|
||||
pos[1] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 };
|
||||
pos[2] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 };
|
||||
pos[3] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 };
|
||||
pos[4] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 };
|
||||
pos[5] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 };
|
||||
|
||||
musicVolumeBarButton.RefreshVBO();
|
||||
|
||||
}
|
||||
|
||||
void Game::UpdateVolumeFromMouse(int mouseX, int mouseY) {
|
||||
|
||||
int uiX = mouseX;
|
||||
int uiY = Environment::height - mouseY;
|
||||
Environment::shipVelocity = (musicVolume) * (20.0);
|
||||
if (uiY < volumeBarMinY || uiY > volumeBarMaxY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float t = (uiY - volumeBarMinY) / (volumeBarMaxY - volumeBarMinY);
|
||||
if (t < 0.0f) t = 0.0f;
|
||||
if (t > 1.0f) t = 1.0f;
|
||||
musicVolume = t;
|
||||
UpdateVolumeKnob();
|
||||
}
|
||||
void Game::drawUI()
|
||||
{
|
||||
static const std::string defaultShaderName = "default";
|
||||
static const std::string envShaderName = "env";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
|
||||
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
renderer.PushProjectionMatrix(Environment::width, Environment::height, -1, 1);
|
||||
renderer.PushMatrix();
|
||||
|
||||
renderer.LoadIdentity();
|
||||
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, buttonTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(button);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, musicVolumeBarTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(musicVolumeBar);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, musicVolumeBarButtonTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(musicVolumeBarButton);
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
}
|
||||
|
||||
void Game::drawScene() {
|
||||
static const std::string defaultShaderName = "default";
|
||||
static const std::string envShaderName = "env";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
|
||||
glClearColor(0.0f, 0.5f, 1.0f, 1.0f);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glViewport(0, 0, Environment::width, Environment::height);
|
||||
|
||||
CheckGlError();
|
||||
|
||||
drawCubemap();
|
||||
drawShip();
|
||||
planetObject.draw(renderer);
|
||||
drawBoxes();
|
||||
|
||||
drawUI();
|
||||
|
||||
CheckGlError();
|
||||
}
|
||||
|
||||
void Game::processTickCount() {
|
||||
|
||||
if (lastTickCount == 0) {
|
||||
lastTickCount = SDL_GetTicks64();
|
||||
return;
|
||||
}
|
||||
|
||||
newTickCount = SDL_GetTicks64();
|
||||
if (newTickCount - lastTickCount > CONST_TIMER_INTERVAL) {
|
||||
size_t delta = (newTickCount - lastTickCount > CONST_MAX_TIME_INTERVAL) ?
|
||||
CONST_MAX_TIME_INTERVAL : newTickCount - lastTickCount;
|
||||
|
||||
//gameObjects.updateScene(delta);
|
||||
sparkEmitter.update(static_cast<float>(delta));
|
||||
|
||||
if (Environment::tapDownHold) {
|
||||
|
||||
float diffx = Environment::tapDownCurrentPos.v[0] - Environment::tapDownStartPos.v[0];
|
||||
float diffy = Environment::tapDownCurrentPos.v[1] - Environment::tapDownStartPos.v[1];
|
||||
|
||||
|
||||
if (abs(diffy) > 5.0 || abs(diffx) > 5.0) //threshold
|
||||
{
|
||||
|
||||
float rotationPower = sqrtf(diffx * diffx + diffy * diffy);
|
||||
|
||||
//std::cout << rotationPower << std::endl;
|
||||
|
||||
float deltaAlpha = rotationPower * delta * M_PI / 500000.f;
|
||||
|
||||
Vector3f rotationDirection = { diffy, diffx, 0 };
|
||||
|
||||
rotationDirection = rotationDirection.normalized();
|
||||
|
||||
Vector4f rotateQuat = {
|
||||
rotationDirection.v[0] * sin(deltaAlpha * 0.5f),
|
||||
rotationDirection.v[1] * sin(deltaAlpha * 0.5f),
|
||||
rotationDirection.v[2] * sin(deltaAlpha * 0.5f),
|
||||
cos(deltaAlpha * 0.5f) };
|
||||
|
||||
Matrix3f rotateMat = QuatToMatrix(rotateQuat);
|
||||
|
||||
Environment::shipMatrix = MultMatrixMatrix(Environment::shipMatrix, rotateMat);
|
||||
Environment::inverseShipMatrix = InverseMatrix(Environment::shipMatrix);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (fabs(Environment::shipVelocity) > 0.01f)
|
||||
{
|
||||
Vector3f velocityDirection = { 0,0, -Environment::shipVelocity * delta / 1000.f };
|
||||
Vector3f velocityDirectionAdjusted = MultMatrixVector(Environment::shipMatrix, velocityDirection);
|
||||
|
||||
Environment::shipPosition = Environment::shipPosition + velocityDirectionAdjusted;
|
||||
}
|
||||
|
||||
lastTickCount = newTickCount;
|
||||
}
|
||||
}
|
||||
|
||||
void Game::render() {
|
||||
SDL_GL_MakeCurrent(ZL::Environment::window, glContext);
|
||||
ZL::CheckGlError();
|
||||
|
||||
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
drawScene();
|
||||
processTickCount();
|
||||
|
||||
SDL_GL_SwapWindow(ZL::Environment::window);
|
||||
}
|
||||
void Game::update() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
if (event.type == SDL_QUIT) {
|
||||
Environment::exitGameLoop = true;
|
||||
|
||||
}
|
||||
else if (event.type == SDL_MOUSEBUTTONDOWN) {
|
||||
// 1. Îáðàáîòêà íàæàòèÿ êíîïêè ìûøè
|
||||
|
||||
int mx = event.button.x;
|
||||
int my = event.button.y;
|
||||
|
||||
std::cout << mx << " " << my << '\n';
|
||||
int uiX = mx;
|
||||
int uiY = Environment::height - my;
|
||||
if (uiX >= volumeBarMinX - 40 && uiX <= volumeBarMaxX + 40 &&
|
||||
uiY >= volumeBarMinY - 40 && uiY <= volumeBarMaxY + 40) {
|
||||
isDraggingVolume = true;
|
||||
UpdateVolumeFromMouse(mx, my);
|
||||
}
|
||||
else {
|
||||
Environment::tapDownHold = true;
|
||||
// Êîîðäèíàòû íà÷àëüíîãî íàæàòèÿ
|
||||
Environment::tapDownStartPos.v[0] = event.button.x;
|
||||
Environment::tapDownStartPos.v[1] = event.button.y;
|
||||
// Íà÷àëüíàÿ ïîçèöèÿ òàêæå ñòàíîâèòñÿ òåêóùåé
|
||||
Environment::tapDownCurrentPos.v[0] = event.button.x;
|
||||
Environment::tapDownCurrentPos.v[1] = event.button.y;
|
||||
}
|
||||
|
||||
}
|
||||
else if (event.type == SDL_MOUSEBUTTONUP) {
|
||||
// 2. Îáðàáîòêà îòïóñêàíèÿ êíîïêè ìûøè
|
||||
isDraggingVolume = false;
|
||||
Environment::tapDownHold = false;
|
||||
}
|
||||
else if (event.type == SDL_MOUSEMOTION) {
|
||||
// 3. Îáðàáîòêà ïåðåìåùåíèÿ ìûøè
|
||||
int mx = event.motion.x;
|
||||
int my = event.motion.y;
|
||||
|
||||
if (isDraggingVolume) {
|
||||
// Äâèãàåì ìûøü ïî ñëàéäåðó — ìåíÿåì ãðîìêîñòü è ïîçèöèþ êðóæêà
|
||||
UpdateVolumeFromMouse(mx, my);
|
||||
}
|
||||
if (Environment::tapDownHold) {
|
||||
// Îáíîâëåíèå òåêóùåé ïîçèöèè, åñëè êíîïêà óäåðæèâàåòñÿ
|
||||
Environment::tapDownCurrentPos.v[0] = event.motion.x;
|
||||
Environment::tapDownCurrentPos.v[1] = event.motion.y;
|
||||
}
|
||||
}
|
||||
else if (event.type == SDL_MOUSEWHEEL) {
|
||||
static const float zoomstep = 2.0f;
|
||||
if (event.wheel.y > 0) {
|
||||
Environment::zoom -= zoomstep;
|
||||
}
|
||||
else if (event.wheel.y < 0) {
|
||||
Environment::zoom += zoomstep;
|
||||
}
|
||||
if (Environment::zoom < zoomstep) {
|
||||
Environment::zoom = zoomstep;
|
||||
}
|
||||
}
|
||||
else if (event.type == SDL_KEYUP)
|
||||
{
|
||||
if (event.key.keysym.sym == SDLK_i)
|
||||
{
|
||||
Environment::shipVelocity += 1.f;
|
||||
}
|
||||
if (event.key.keysym.sym == SDLK_k)
|
||||
{
|
||||
Environment::shipVelocity -= 1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
} // namespace ZL
|
||||
|
||||
113
Game.h
113
Game.h
@ -1,61 +1,92 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "OpenGlExtensions.h"
|
||||
#include "Renderer.h"
|
||||
#include "Environment.h"
|
||||
#include "TextureManager.h"
|
||||
#include "SparkEmitter.h"
|
||||
#include "PlanetObject.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
|
||||
struct BoxCoords
|
||||
{
|
||||
Vector3f pos;
|
||||
Matrix3f m;
|
||||
};
|
||||
struct BoxCoords
|
||||
{
|
||||
Vector3f pos;
|
||||
Matrix3f m;
|
||||
};
|
||||
|
||||
|
||||
class Game {
|
||||
public:
|
||||
Game();
|
||||
~Game();
|
||||
|
||||
void setup();
|
||||
void update();
|
||||
void render();
|
||||
|
||||
bool shouldExit() const { return Environment::exitGameLoop; }
|
||||
class Game {
|
||||
public:
|
||||
Game();
|
||||
~Game();
|
||||
|
||||
private:
|
||||
void processTickCount();
|
||||
void drawScene();
|
||||
void drawCubemap();
|
||||
void drawShip();
|
||||
void drawBoxes();
|
||||
void setup();
|
||||
void update();
|
||||
void render();
|
||||
|
||||
SDL_Window* window;
|
||||
SDL_GLContext glContext;
|
||||
Renderer renderer;
|
||||
|
||||
size_t newTickCount;
|
||||
size_t lastTickCount;
|
||||
|
||||
static const size_t CONST_TIMER_INTERVAL = 10;
|
||||
static const size_t CONST_MAX_TIME_INTERVAL = 1000;
|
||||
|
||||
std::shared_ptr<Texture> spaceshipTexture;
|
||||
std::shared_ptr<Texture> cubemapTexture;
|
||||
VertexDataStruct spaceshipBase;
|
||||
VertexRenderStruct spaceship;
|
||||
bool shouldExit() const { return Environment::exitGameLoop; }
|
||||
|
||||
VertexRenderStruct cubemap;
|
||||
private:
|
||||
void processTickCount();
|
||||
void drawScene();
|
||||
void drawCubemap();
|
||||
void drawShip();
|
||||
void drawBoxes();
|
||||
void drawUI();
|
||||
|
||||
std::shared_ptr<Texture> boxTexture;
|
||||
VertexDataStruct boxBase;
|
||||
SDL_Window* window;
|
||||
SDL_GLContext glContext;
|
||||
Renderer renderer;
|
||||
|
||||
std::vector<BoxCoords> boxCoordsArr;
|
||||
std::vector<VertexRenderStruct> boxRenderArr;
|
||||
size_t newTickCount;
|
||||
size_t lastTickCount;
|
||||
|
||||
|
||||
std::vector<BoxCoords> boxCoordsArr;
|
||||
std::vector<VertexRenderStruct> boxRenderArr;
|
||||
|
||||
|
||||
std::shared_ptr<Texture> buttonTexture;
|
||||
VertexRenderStruct button;
|
||||
|
||||
std::shared_ptr<Texture> musicVolumeBarTexture;
|
||||
VertexRenderStruct musicVolumeBar;
|
||||
|
||||
std::shared_ptr<Texture> musicVolumeBarButtonTexture;
|
||||
VertexRenderStruct musicVolumeBarButton;
|
||||
|
||||
|
||||
bool isDraggingVolume = false;
|
||||
float musicVolume = 0.0f;
|
||||
float volumeBarMinX = 1190.0f;
|
||||
float volumeBarMaxX = 1200.0f;
|
||||
float volumeBarMinY = 100.0f;
|
||||
float volumeBarMaxY = 600.0f;
|
||||
float musicVolumeBarButtonButtonCenterX = 1195.0f;
|
||||
float musicVolumeBarButtonButtonRadius = 25.0f;
|
||||
void UpdateVolumeFromMouse(int mouseX, int mouseY);
|
||||
void UpdateVolumeKnob();
|
||||
|
||||
static const size_t CONST_TIMER_INTERVAL = 10;
|
||||
static const size_t CONST_MAX_TIME_INTERVAL = 1000;
|
||||
|
||||
std::shared_ptr<Texture> sparkTexture;
|
||||
std::shared_ptr<Texture> spaceshipTexture;
|
||||
std::shared_ptr<Texture> cubemapTexture;
|
||||
VertexDataStruct spaceshipBase;
|
||||
VertexRenderStruct spaceship;
|
||||
|
||||
VertexRenderStruct cubemap;
|
||||
|
||||
std::shared_ptr<Texture> boxTexture;
|
||||
VertexDataStruct boxBase;
|
||||
|
||||
SparkEmitter sparkEmitter;
|
||||
PlanetObject planetObject;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
} // namespace ZL
|
||||
292
PlanetObject.cpp
Normal file
292
PlanetObject.cpp
Normal file
@ -0,0 +1,292 @@
|
||||
#include "PlanetObject.h"
|
||||
#include <random>
|
||||
#include <cmath>
|
||||
#include "OpenGlExtensions.h"
|
||||
#include "Environment.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
struct Triangle
|
||||
{
|
||||
std::array<Vector3f, 3> data;
|
||||
|
||||
Triangle(Vector3f p1, Vector3f p2, Vector3f p3)
|
||||
: data{ p1, p2, p3 }
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<Triangle> subdivideTriangles(const std::vector<Triangle>& inputTriangles, PerlinNoise& perlin) {
|
||||
std::vector<Triangle> output;
|
||||
output.reserve(inputTriangles.size() * 4);
|
||||
|
||||
for (const auto& t : inputTriangles) {
|
||||
Vector3f a = t.data[0];
|
||||
Vector3f b = t.data[1];
|
||||
Vector3f c = t.data[2];
|
||||
|
||||
// 1. Вычисляем "сырые" середины
|
||||
Vector3f m_ab = (a + b) * 0.5f;
|
||||
Vector3f m_bc = (b + c) * 0.5f;
|
||||
Vector3f m_ac = (a + c) * 0.5f;
|
||||
|
||||
// 2. Нормализуем их (получаем идеальную сферу радиуса 1)
|
||||
m_ab = m_ab.normalized();
|
||||
m_bc = m_bc.normalized();
|
||||
m_ac = m_ac.normalized();
|
||||
|
||||
// 3. ПРИМЕНЯЕМ ШУМ: Смещаем точку по радиусу
|
||||
m_ab = m_ab * perlin.getSurfaceHeight(m_ab);
|
||||
m_bc = m_bc * perlin.getSurfaceHeight(m_bc);
|
||||
m_ac = m_ac * perlin.getSurfaceHeight(m_ac);
|
||||
|
||||
// 4. Формируем новые треугольники
|
||||
output.emplace_back(a, m_ab, m_ac);
|
||||
output.emplace_back(m_ab, b, m_bc);
|
||||
output.emplace_back(m_ac, m_bc, c);
|
||||
output.emplace_back(m_ab, m_bc, m_ac);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
Vector3f calculateSurfaceNormal(Vector3f p_sphere, PerlinNoise& perlin) {
|
||||
// p_sphere - это нормализованный вектор (точка на идеальной сфере)
|
||||
|
||||
float theta = 0.01f; // Шаг для "щупанья" соседей (epsilon)
|
||||
|
||||
// Нам нужно найти два вектора, касательных к сфере в точке p_sphere.
|
||||
// Для этого берем любой вектор (например UP), делаем Cross Product, чтобы получить касательную.
|
||||
// Если p_sphere совпадает с UP, берем RIGHT.
|
||||
Vector3f up = Vector3f(0.0f, 1.0f, 0.0f);
|
||||
if (abs(p_sphere.dot(up)) > 0.99f) {
|
||||
up = Vector3f(1.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
Vector3f tangentX = (up.cross(p_sphere)).normalized();
|
||||
Vector3f tangentY = (p_sphere.cross(tangentX)).normalized();
|
||||
|
||||
// Точки на идеальной сфере со смещением
|
||||
Vector3f p0_dir = p_sphere;
|
||||
Vector3f p1_dir = (p_sphere + tangentX * theta).normalized();
|
||||
Vector3f p2_dir = (p_sphere + tangentY * theta).normalized();
|
||||
|
||||
// Реальные точки на искаженной поверхности
|
||||
// p = dir * height(dir)
|
||||
Vector3f p0 = p0_dir * perlin.getSurfaceHeight(p0_dir);
|
||||
Vector3f p1 = p1_dir * perlin.getSurfaceHeight(p1_dir);
|
||||
Vector3f p2 = p2_dir * perlin.getSurfaceHeight(p2_dir);
|
||||
|
||||
// Вектора от центральной точки к соседям
|
||||
Vector3f v1 = p1 - p0;
|
||||
Vector3f v2 = p2 - p0;
|
||||
|
||||
// Нормаль - это перпендикуляр к этим двум векторам
|
||||
// Порядок (v2, v1) или (v1, v2) зависит от системы координат,
|
||||
// здесь подбираем так, чтобы нормаль смотрела наружу.
|
||||
return (-v2.cross(v1)).normalized();
|
||||
}
|
||||
|
||||
VertexDataStruct trianglesToVertices(const std::vector<Triangle>& triangles, PerlinNoise& perlin) {
|
||||
VertexDataStruct buffer;
|
||||
buffer.PositionData.reserve(triangles.size() * 3);
|
||||
buffer.NormalData.reserve(triangles.size() * 3);
|
||||
|
||||
for (const auto& t : triangles) {
|
||||
// Проходим по всем 3 вершинам треугольника
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// p_geometry - это уже точка на поверхности (с шумом)
|
||||
Vector3f p_geometry = t.data[i];
|
||||
|
||||
// Нам нужно восстановить направление от центра к этой точке,
|
||||
// чтобы передать его в функцию расчета нормали.
|
||||
// Так как (0,0,0) - центр, то normalize(p) даст нам направление.
|
||||
Vector3f p_dir = p_geometry.normalized();
|
||||
|
||||
// Считаем аналитическую нормаль для этой конкретной точки
|
||||
Vector3f normal = calculateSurfaceNormal(p_dir, perlin);
|
||||
|
||||
buffer.PositionData.push_back({ p_geometry });
|
||||
//buffer.NormalData.push_back({ normal });
|
||||
//buffer.TexCoordData.push_back({ 0.0f, 0.0f });
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Генерация геометрии октаэдра с дублированием вершин для Flat Shading
|
||||
VertexDataStruct generateOctahedron(PerlinNoise& perlin) {
|
||||
VertexDataStruct buffer;
|
||||
|
||||
std::vector<Triangle> v = {
|
||||
Triangle{
|
||||
{ 0.0f, 1.0f, 0.0f}, // Top
|
||||
{ 0.0f, 0.0f, 1.0f}, // Front
|
||||
{ 1.0f, 0.0f, 0.0f}, // Right
|
||||
},
|
||||
Triangle{
|
||||
{ 0.0f, 1.0f, 0.0f}, // Top
|
||||
{ 1.0f, 0.0f, 0.0f}, // Right
|
||||
{ 0.0f, 0.0f, -1.0f}, // Back
|
||||
},
|
||||
Triangle{
|
||||
{ 0.0f, 1.0f, 0.0f}, // Top
|
||||
{ 0.0f, 0.0f, -1.0f}, // Back
|
||||
{-1.0f, 0.0f, 0.0f}, // Left
|
||||
},
|
||||
Triangle{
|
||||
{ 0.0f, 1.0f, 0.0f}, // Top
|
||||
{-1.0f, 0.0f, 0.0f}, // Left
|
||||
{ 0.0f, 0.0f, 1.0f}, // Front
|
||||
},
|
||||
Triangle{
|
||||
{ 0.0f, -1.0f, 0.0f}, // Bottom
|
||||
{ 1.0f, 0.0f, 0.0f}, // Right
|
||||
{ 0.0f, 0.0f, 1.0f}, // Front
|
||||
},
|
||||
Triangle{
|
||||
{ 0.0f, -1.0f, 0.0f}, // Bottom
|
||||
{ 0.0f, 0.0f, 1.0f}, // Front
|
||||
{-1.0f, 0.0f, 0.0f}, // Left
|
||||
},
|
||||
Triangle{
|
||||
{ 0.0f, -1.0f, 0.0f}, // Bottom
|
||||
{-1.0f, 0.0f, 0.0f}, // Left
|
||||
{ 0.0f, 0.0f, -1.0f}, // Back
|
||||
},
|
||||
Triangle{
|
||||
{ 0.0f, -1.0f, 0.0f}, // Bottom
|
||||
{ 0.0f, 0.0f, -1.0f}, // Back
|
||||
{ 1.0f, 0.0f, 0.0f}, // Right
|
||||
}
|
||||
};
|
||||
|
||||
v = subdivideTriangles(v, perlin);
|
||||
v = subdivideTriangles(v, perlin);
|
||||
v = subdivideTriangles(v, perlin);
|
||||
v = subdivideTriangles(v, perlin);
|
||||
v = subdivideTriangles(v, perlin);
|
||||
|
||||
|
||||
for (int i = 0; i < v.size(); i++) {
|
||||
Vector3f p1 = v[i].data[0];
|
||||
Vector3f p2 = v[i].data[1];
|
||||
Vector3f p3 = v[i].data[2];
|
||||
|
||||
// Считаем нормаль грани через векторное произведение
|
||||
Vector3f edge1 = p2 - p1;
|
||||
Vector3f edge2 = p3 - p1;
|
||||
Vector3f normal = (edge1.cross(edge2)).normalized();
|
||||
|
||||
// Дублируем нормаль для всех трех вершин треугольника (Flat shading)
|
||||
buffer.PositionData.push_back({ p1 });
|
||||
buffer.PositionData.push_back({ p2 });
|
||||
buffer.PositionData.push_back({ p3 });
|
||||
/*buffer.NormalData.push_back({normal});
|
||||
buffer.NormalData.push_back({ normal });
|
||||
buffer.NormalData.push_back({ normal });
|
||||
buffer.TexCoordData.push_back({ 0.0f, 0.0f });
|
||||
buffer.TexCoordData.push_back({ 0.0f, 0.0f });
|
||||
buffer.TexCoordData.push_back({ 0.0f, 0.0f });*/
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
VertexDataStruct generateSphere(int subdivisions, PerlinNoise& perlin) {
|
||||
// 1. Исходный октаэдр
|
||||
std::vector<Triangle> geometry = {
|
||||
Triangle{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 1.0f, 0.0f, 0.0f}}, // Top-Front-Right
|
||||
Triangle{{ 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // Top-Right-Back
|
||||
Triangle{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}}, // Top-Back-Left
|
||||
Triangle{{ 0.0f, 1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // Top-Left-Front
|
||||
Triangle{{ 0.0f, -1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // Bottom-Right-Front
|
||||
Triangle{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}}, // Bottom-Front-Left
|
||||
Triangle{{ 0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // Bottom-Left-Back
|
||||
Triangle{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, { 1.0f, 0.0f, 0.0f}} // Bottom-Back-Right
|
||||
};
|
||||
|
||||
// 2. ПРИМЕНЯЕМ ШУМ К ИСХОДНЫМ ВЕРШИНАМ
|
||||
// Проходимся по всем треугольникам и всем вершинам в них
|
||||
for (auto& t : geometry) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// Нормализуем (на всякий случай, хотя у октаэдра они и так норм)
|
||||
Vector3f dir = t.data[i].normalized();
|
||||
// Применяем высоту
|
||||
t.data[i] = dir * perlin.getSurfaceHeight(dir);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Разбиваем N раз (новые вершины будут получать шум внутри функции)
|
||||
for (int i = 0; i < subdivisions; i++) {
|
||||
geometry = subdivideTriangles(geometry, perlin);
|
||||
}
|
||||
|
||||
// 4. Генерируем нормали
|
||||
// Благодаря тому, что мы реально сдвигали вершины, Flat Shading нормали
|
||||
// рассчитаются правильно относительно нового рельефа.
|
||||
return trianglesToVertices(geometry, perlin);
|
||||
}
|
||||
|
||||
PlanetObject::PlanetObject()
|
||||
{
|
||||
}
|
||||
|
||||
void PlanetObject::init() {
|
||||
|
||||
planetMesh = generateSphere(7, perlin);
|
||||
|
||||
planetMesh.Scale(100.f);
|
||||
planetMesh.Move({ 0,0,-200 });
|
||||
|
||||
planetRenderStruct.data = planetMesh;
|
||||
planetRenderStruct.RefreshVBO();
|
||||
|
||||
}
|
||||
|
||||
void PlanetObject::prepareDrawData() {
|
||||
if (!drawDataDirty) return;
|
||||
|
||||
drawDataDirty = false;
|
||||
}
|
||||
|
||||
void PlanetObject::draw(Renderer& renderer) {
|
||||
|
||||
prepareDrawData();
|
||||
|
||||
static const std::string defaultShaderName = "defaultColor";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
1, 1000);
|
||||
renderer.PushMatrix();
|
||||
renderer.LoadIdentity();
|
||||
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
|
||||
renderer.RotateMatrix(Environment::inverseShipMatrix);
|
||||
renderer.TranslateMatrix(-Environment::shipPosition);
|
||||
|
||||
|
||||
renderer.DrawVertexRenderStruct(planetRenderStruct);
|
||||
|
||||
CheckGlError();
|
||||
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
|
||||
|
||||
}
|
||||
|
||||
void PlanetObject::update(float deltaTimeMs) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace ZL
|
||||
100
PlanetObject.h
Normal file
100
PlanetObject.h
Normal file
@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#include "ZLMath.h"
|
||||
#include "Renderer.h"
|
||||
#include "TextureManager.h"
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
|
||||
namespace ZL {
|
||||
|
||||
class PerlinNoise {
|
||||
std::vector<int> p;
|
||||
public:
|
||||
PerlinNoise() {
|
||||
p.resize(256);
|
||||
std::iota(p.begin(), p.end(), 0);
|
||||
// Перемешиваем для случайности (можно задать seed)
|
||||
std::default_random_engine engine(12345);
|
||||
std::shuffle(p.begin(), p.end(), engine);
|
||||
p.insert(p.end(), p.begin(), p.end()); // Дублируем для переполнения
|
||||
}
|
||||
|
||||
float fade(float t) { return t * t * t * (t * (t * 6 - 15) + 10); }
|
||||
float lerp(float t, float a, float b) { return a + t * (b - a); }
|
||||
float grad(int hash, float x, float y, float z) {
|
||||
int h = hash & 15;
|
||||
float u = h < 8 ? x : y;
|
||||
float v = h < 4 ? y : (h == 12 || h == 14 ? x : z);
|
||||
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
||||
}
|
||||
|
||||
float noise(float x, float y, float z) {
|
||||
int X = (int)floor(x) & 255;
|
||||
int Y = (int)floor(y) & 255;
|
||||
int Z = (int)floor(z) & 255;
|
||||
|
||||
x -= floor(x);
|
||||
y -= floor(y);
|
||||
z -= floor(z);
|
||||
|
||||
float u = fade(x);
|
||||
float v = fade(y);
|
||||
float w = fade(z);
|
||||
|
||||
int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z;
|
||||
int B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z;
|
||||
|
||||
return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), grad(p[BA], x - 1, y, z)),
|
||||
lerp(u, grad(p[AB], x, y - 1, z), grad(p[BB], x - 1, y - 1, z))),
|
||||
lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), grad(p[BA + 1], x - 1, y, z - 1)),
|
||||
lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1))));
|
||||
}
|
||||
|
||||
float getSurfaceHeight(Vector3f pos) {
|
||||
// Частота шума (чем больше, тем больше "холмов")
|
||||
float frequency = 7.0f;
|
||||
|
||||
// Получаем значение шума (обычно от -1 до 1)
|
||||
float noiseValue = noise(pos.v[0] * frequency, pos.v[1] * frequency, pos.v[2] * frequency);
|
||||
|
||||
// Переводим из диапазона [-1, 1] в [0, 1]
|
||||
noiseValue = (noiseValue + 1.0f) * 0.5f;
|
||||
|
||||
// Масштабируем: хотим отклонение от 1.0 до 1.1
|
||||
// Значит амплитуда = 0.1
|
||||
float height = 1.0f + (noiseValue * 0.1f); // * 0.2 даст вариацию высоты
|
||||
|
||||
return height;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class PlanetObject {
|
||||
private:
|
||||
PerlinNoise perlin;
|
||||
void prepareDrawData();
|
||||
VertexDataStruct planetMesh;
|
||||
VertexRenderStruct planetRenderStruct;
|
||||
|
||||
public:
|
||||
PlanetObject();
|
||||
|
||||
void init();
|
||||
|
||||
void update(float deltaTimeMs);
|
||||
|
||||
void draw(Renderer& renderer);
|
||||
|
||||
|
||||
private:
|
||||
bool drawDataDirty = true;
|
||||
};
|
||||
|
||||
} // namespace ZL
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
download from https://cmake.org/download/
|
||||
|
||||
|
||||
Windows x64 Installer: cmake-4.2.0-windows-x86_64.msi
|
||||
|
||||
|
||||
@ -148,7 +149,7 @@ embuilder build sdl2 sdl2_ttf sdl2_image sdl2_image_jpg sdl2_image_png
|
||||
|
||||
|
||||
|
||||
emcc main.cpp Game.cpp Environment.cpp BoneAnimatedModel.cpp Math.cpp Renderer.cpp TextModel.cpp ShaderManager.cpp TextureManager.cpp Utils.cpp OpenGlExtensions.cpp -O2 -std=c++14 -pthread -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE=4 -sTOTAL_MEMORY=4294967296 -sINITIAL_MEMORY=3221225472 -sMAXIMUM_MEMORY=4294967296 -sALLOW_MEMORY_GROWTH=1 -I./thirdparty/libzip-1.11.3/build-emcmake/install/include -L./thirdparty/libzip-1.11.3/build-emcmake/install/lib -lzip -lz -sUSE_SDL_IMAGE=2 -sUSE_SDL=2 -sUSE_LIBPNG=1 --preload-file space-game001.zip -o space-game001.html
|
||||
emcc main.cpp Game.cpp Environment.cpp BoneAnimatedModel.cpp ZLMath.cpp Renderer.cpp TextModel.cpp ShaderManager.cpp TextureManager.cpp Utils.cpp OpenGlExtensions.cpp -O2 -std=c++14 -pthread -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE=4 -sTOTAL_MEMORY=4294967296 -sINITIAL_MEMORY=3221225472 -sMAXIMUM_MEMORY=4294967296 -sALLOW_MEMORY_GROWTH=1 -I./thirdparty/libzip-1.11.3/build-emcmake/install/include -L./thirdparty/libzip-1.11.3/build-emcmake/install/lib -lzip -lz -sUSE_SDL_IMAGE=2 -sUSE_SDL=2 -sUSE_LIBPNG=1 --preload-file space-game001.zip -o space-game001.html
|
||||
|
||||
emrun --no_browser --port 8080 .
|
||||
```
|
||||
|
||||
297
SparkEmitter.cpp
Normal file
297
SparkEmitter.cpp
Normal file
@ -0,0 +1,297 @@
|
||||
#include "SparkEmitter.h"
|
||||
#include <random>
|
||||
#include <cmath>
|
||||
#include "OpenGlExtensions.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
SparkEmitter::SparkEmitter()
|
||||
: emissionRate(100.0f), isActive(true), drawDataDirty(true), maxParticles(200) {
|
||||
particles.resize(maxParticles);
|
||||
drawPositions.reserve(maxParticles * 6);
|
||||
drawTexCoords.reserve(maxParticles * 6);
|
||||
lastEmissionTime = std::chrono::steady_clock::now();
|
||||
|
||||
sparkQuad.data = VertexDataStruct();
|
||||
}
|
||||
|
||||
SparkEmitter::SparkEmitter(const std::vector<Vector3f>& positions, float rate)
|
||||
: emissionPoints(positions), emissionRate(rate), isActive(true),
|
||||
drawDataDirty(true), maxParticles(positions.size() * 100) {
|
||||
particles.resize(maxParticles);
|
||||
drawPositions.reserve(maxParticles * 6);
|
||||
drawTexCoords.reserve(maxParticles * 6);
|
||||
lastEmissionTime = std::chrono::steady_clock::now();
|
||||
|
||||
sparkQuad.data = VertexDataStruct();
|
||||
}
|
||||
|
||||
SparkEmitter::SparkEmitter(const std::vector<Vector3f>& positions,
|
||||
std::shared_ptr<Texture> tex,
|
||||
float rate)
|
||||
: emissionPoints(positions), texture(tex), emissionRate(rate),
|
||||
isActive(true), drawDataDirty(true), maxParticles(positions.size() * 100) {
|
||||
particles.resize(maxParticles);
|
||||
drawPositions.reserve(maxParticles * 6);
|
||||
drawTexCoords.reserve(maxParticles * 6);
|
||||
lastEmissionTime = std::chrono::steady_clock::now();
|
||||
|
||||
sparkQuad.data = VertexDataStruct();
|
||||
}
|
||||
|
||||
void SparkEmitter::setTexture(std::shared_ptr<Texture> tex) {
|
||||
texture = tex;
|
||||
}
|
||||
|
||||
void SparkEmitter::prepareDrawData() {
|
||||
if (!drawDataDirty) return;
|
||||
|
||||
drawPositions.clear();
|
||||
drawTexCoords.clear();
|
||||
|
||||
if (getActiveParticleCount() == 0) {
|
||||
drawDataDirty = false;
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::pair<const SparkParticle*, float>> sortedParticles;
|
||||
sortedParticles.reserve(getActiveParticleCount());
|
||||
|
||||
for (const auto& particle : particles) {
|
||||
if (particle.active) {
|
||||
sortedParticles.push_back({ &particle, particle.position.v[2] });
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(sortedParticles.begin(), sortedParticles.end(),
|
||||
[](const auto& a, const auto& b) {
|
||||
return a.second > b.second;
|
||||
});
|
||||
|
||||
for (const auto& [particlePtr, depth] : sortedParticles) {
|
||||
const auto& particle = *particlePtr;
|
||||
Vector3f pos = particle.position;
|
||||
float size = 0.04f * particle.scale;
|
||||
|
||||
drawPositions.push_back({ pos.v[0] - size, pos.v[1] - size, pos.v[2] });
|
||||
drawTexCoords.push_back({ 0.0f, 0.0f });
|
||||
|
||||
drawPositions.push_back({ pos.v[0] - size, pos.v[1] + size, pos.v[2] });
|
||||
drawTexCoords.push_back({ 0.0f, 1.0f });
|
||||
|
||||
drawPositions.push_back({ pos.v[0] + size, pos.v[1] + size, pos.v[2] });
|
||||
drawTexCoords.push_back({ 1.0f, 1.0f });
|
||||
|
||||
drawPositions.push_back({ pos.v[0] - size, pos.v[1] - size, pos.v[2] });
|
||||
drawTexCoords.push_back({ 0.0f, 0.0f });
|
||||
|
||||
drawPositions.push_back({ pos.v[0] + size, pos.v[1] + size, pos.v[2] });
|
||||
drawTexCoords.push_back({ 1.0f, 1.0f });
|
||||
|
||||
drawPositions.push_back({ pos.v[0] + size, pos.v[1] - size, pos.v[2] });
|
||||
drawTexCoords.push_back({ 1.0f, 0.0f });
|
||||
}
|
||||
|
||||
drawDataDirty = false;
|
||||
}
|
||||
|
||||
void SparkEmitter::draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight) {
|
||||
if (getActiveParticleCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
prepareDrawData();
|
||||
|
||||
if (drawPositions.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
sparkQuad.data.PositionData = drawPositions;
|
||||
sparkQuad.data.TexCoordData = drawTexCoords;
|
||||
sparkQuad.RefreshVBO();
|
||||
|
||||
static const std::string defaultShaderName = "default";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
float aspectRatio = static_cast<float>(screenWidth) / static_cast<float>(screenHeight);
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, aspectRatio, 1, 1000);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);// Аддитивное смешивание для эффекта свечения
|
||||
|
||||
renderer.PushMatrix();
|
||||
renderer.LoadIdentity();
|
||||
renderer.TranslateMatrix({ 0, 0, -1.0f * zoom });
|
||||
|
||||
renderer.DrawVertexRenderStruct(sparkQuad);
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
renderer.shaderManager.PopShader();
|
||||
}
|
||||
|
||||
void SparkEmitter::update(float deltaTimeMs) {
|
||||
auto currentTime = std::chrono::steady_clock::now();
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
currentTime - lastEmissionTime).count();
|
||||
|
||||
if (isActive && elapsed >= emissionRate) {
|
||||
emit();
|
||||
lastEmissionTime = currentTime;
|
||||
drawDataDirty = true;
|
||||
}
|
||||
|
||||
bool anyChanged = false;
|
||||
for (auto& particle : particles) {
|
||||
if (particle.active) {
|
||||
Vector3f oldPosition = particle.position;
|
||||
float oldScale = particle.scale;
|
||||
|
||||
particle.position.v[0] += particle.velocity.v[0] * deltaTimeMs / 1000.0f;
|
||||
particle.position.v[1] += particle.velocity.v[1] * deltaTimeMs / 1000.0f;
|
||||
particle.position.v[2] += particle.velocity.v[2] * deltaTimeMs / 1000.0f;
|
||||
|
||||
particle.lifeTime += deltaTimeMs;
|
||||
|
||||
if (particle.lifeTime >= particle.maxLifeTime) {
|
||||
particle.active = false;
|
||||
anyChanged = true;
|
||||
}
|
||||
else {
|
||||
float lifeRatio = particle.lifeTime / particle.maxLifeTime;
|
||||
particle.scale = 1.0f - lifeRatio * 0.8f;
|
||||
|
||||
if (oldPosition.v[0] != particle.position.v[0] ||
|
||||
oldPosition.v[1] != particle.position.v[1] ||
|
||||
oldPosition.v[2] != particle.position.v[2] ||
|
||||
oldScale != particle.scale) {
|
||||
anyChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (anyChanged) {
|
||||
drawDataDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SparkEmitter::emit() {
|
||||
if (emissionPoints.empty()) return;
|
||||
bool emitted = false;
|
||||
|
||||
for (int i = 0; i < emissionPoints.size(); ++i) {
|
||||
bool particleFound = false;
|
||||
|
||||
for (auto& particle : particles) {
|
||||
if (!particle.active) {
|
||||
initParticle(particle, i);
|
||||
particle.active = true;
|
||||
particle.lifeTime = 0;
|
||||
particle.position = emissionPoints[i];
|
||||
particle.emitterIndex = i;
|
||||
particleFound = true;
|
||||
emitted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!particleFound && !particles.empty()) {
|
||||
size_t oldestIndex = 0;
|
||||
float maxLifeTime = 0;
|
||||
|
||||
for (size_t j = 0; j < particles.size(); ++j) {
|
||||
if (particles[j].lifeTime > maxLifeTime) {
|
||||
maxLifeTime = particles[j].lifeTime;
|
||||
oldestIndex = j;
|
||||
}
|
||||
}
|
||||
|
||||
initParticle(particles[oldestIndex], i);
|
||||
particles[oldestIndex].active = true;
|
||||
particles[oldestIndex].lifeTime = 0;
|
||||
particles[oldestIndex].position = emissionPoints[i];
|
||||
particles[oldestIndex].emitterIndex = i;
|
||||
emitted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (emitted) {
|
||||
drawDataDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SparkEmitter::setEmissionPoints(const std::vector<Vector3f>& positions) {
|
||||
emissionPoints = positions;
|
||||
maxParticles = positions.size() * 100;
|
||||
particles.resize(maxParticles);
|
||||
drawDataDirty = true;
|
||||
}
|
||||
|
||||
void SparkEmitter::initParticle(SparkParticle& particle, int emitterIndex) {
|
||||
particle.velocity = getRandomVelocity(emitterIndex);
|
||||
particle.scale = 1.0f;
|
||||
particle.maxLifeTime = 800.0f + (rand() % 400);
|
||||
particle.emitterIndex = emitterIndex;
|
||||
}
|
||||
|
||||
Vector3f SparkEmitter::getRandomVelocity(int emitterIndex) {
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen(rd());
|
||||
static std::uniform_real_distribution<> angleDist(0, 2 * M_PI);
|
||||
static std::uniform_real_distribution<> speedDist(0.5f, 2.0f);
|
||||
static std::uniform_real_distribution<> zSpeedDist(1.0f, 3.0f);
|
||||
|
||||
float angle = angleDist(gen);
|
||||
float speed = speedDist(gen);
|
||||
float zSpeed = zSpeedDist(gen);
|
||||
|
||||
if (emitterIndex == 0) {
|
||||
return Vector3f{
|
||||
cosf(angle) * speed - 0.3f,
|
||||
sinf(angle) * speed,
|
||||
zSpeed
|
||||
};
|
||||
}
|
||||
else {
|
||||
return Vector3f{
|
||||
cosf(angle) * speed + 0.3f,
|
||||
sinf(angle) * speed,
|
||||
zSpeed
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<SparkParticle>& SparkEmitter::getParticles() const {
|
||||
return particles;
|
||||
}
|
||||
|
||||
size_t SparkEmitter::getActiveParticleCount() const {
|
||||
size_t count = 0;
|
||||
for (const auto& particle : particles) {
|
||||
if (particle.active) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
} // namespace ZL
|
||||
66
SparkEmitter.h
Normal file
66
SparkEmitter.h
Normal file
@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
#include "ZLMath.h"
|
||||
#include "Renderer.h"
|
||||
#include "TextureManager.h"
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
namespace ZL {
|
||||
|
||||
struct SparkParticle {
|
||||
Vector3f position;
|
||||
Vector3f velocity;
|
||||
float scale;
|
||||
float lifeTime;
|
||||
float maxLifeTime;
|
||||
bool active;
|
||||
int emitterIndex;
|
||||
|
||||
SparkParticle() : position({ 0,0,0 }), velocity({ 0,0,0 }), scale(1.0f),
|
||||
lifeTime(0), maxLifeTime(1000.0f), active(false), emitterIndex(0) {
|
||||
}
|
||||
};
|
||||
|
||||
class SparkEmitter {
|
||||
private:
|
||||
std::vector<SparkParticle> particles;
|
||||
std::vector<Vector3f> emissionPoints;
|
||||
std::chrono::steady_clock::time_point lastEmissionTime;
|
||||
float emissionRate;
|
||||
bool isActive;
|
||||
|
||||
std::vector<Vector3f> drawPositions;
|
||||
std::vector<Vector2f> drawTexCoords;
|
||||
bool drawDataDirty;
|
||||
VertexRenderStruct sparkQuad;
|
||||
std::shared_ptr<Texture> texture;
|
||||
|
||||
int maxParticles;
|
||||
|
||||
void prepareDrawData();
|
||||
|
||||
public:
|
||||
SparkEmitter();
|
||||
SparkEmitter(const std::vector<Vector3f>& positions, float rate = 100.0f);
|
||||
SparkEmitter(const std::vector<Vector3f>& positions,
|
||||
std::shared_ptr<Texture> tex,
|
||||
float rate = 100.0f);
|
||||
|
||||
void setEmissionPoints(const std::vector<Vector3f>& positions);
|
||||
void setTexture(std::shared_ptr<Texture> tex);
|
||||
|
||||
void update(float deltaTimeMs);
|
||||
void emit();
|
||||
|
||||
void draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight);
|
||||
|
||||
const std::vector<SparkParticle>& getParticles() const;
|
||||
size_t getActiveParticleCount() const;
|
||||
|
||||
private:
|
||||
void initParticle(SparkParticle& particle, int emitterIndex);
|
||||
Vector3f getRandomVelocity(int emitterIndex);
|
||||
};
|
||||
|
||||
} // namespace ZL
|
||||
12
ZLMath.h
12
ZLMath.h
@ -56,6 +56,18 @@ namespace ZL {
|
||||
return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
|
||||
}
|
||||
|
||||
float dot(const Vector3f& other) const {
|
||||
return v[0] * other.v[0] + v[1] * other.v[1] + v[2] * other.v[2];
|
||||
}
|
||||
|
||||
Vector3f cross(const Vector3f& other) const {
|
||||
return Vector3f(
|
||||
v[1] * other.v[2] - v[2] * other.v[1],
|
||||
v[2] * other.v[0] - v[0] * other.v[2],
|
||||
v[0] * other.v[1] - v[1] * other.v[0]
|
||||
);
|
||||
}
|
||||
|
||||
// Îïåðàòîð âû÷èòàíèÿ
|
||||
/*Vector3f operator-(const Vector3f& other) const {
|
||||
return Vector3f(v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2]);
|
||||
|
||||
BIN
resources/button.png
(Stored with Git LFS)
Normal file
BIN
resources/button.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/musicVolumeBarButton.png
(Stored with Git LFS)
Normal file
BIN
resources/musicVolumeBarButton.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/musicVolumeBarTexture.png
(Stored with Git LFS)
Normal file
BIN
resources/musicVolumeBarTexture.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/spark.png
(Stored with Git LFS)
Normal file
BIN
resources/spark.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -5,8 +5,8 @@ varying vec2 texCoord;
|
||||
void main()
|
||||
{
|
||||
vec4 color = texture2D(Texture,texCoord).rgba;
|
||||
gl_FragColor = vec4(color.rgb*0.9 + vec3(0.1, 0.1, 0.1), 1.0);
|
||||
//gl_FragColor = vec4(color.rgb*0.9 + vec3(0.1, 0.1, 0.1), 1.0);
|
||||
|
||||
//gl_FragColor = color;
|
||||
gl_FragColor = color;
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user