-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
162 lines (146 loc) · 4.8 KB
/
main.cpp
File metadata and controls
162 lines (146 loc) · 4.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include <iostream>
#include <string>
#include <algorithm>
#include <thread>
#include <chrono>
#include <future>
#include <limits>
#include "stb_perlin.h"
//-------
// Il n'existe pas de façon standard d'interroger et de configurer le terminal.
// Ce programme ne fonctionne que sous Windows.
#include <Windows.h>
//-------
using namespace std;
//const string SYMBOLES_GRIS{ " .;-+oO0#$&%" };
const string SYMBOLES_GRIS{ " .;o0#&%" };
enum class Operation
{
Rien,
PlusGrand,
PlusPetit,
Quitter,
};
void afficherInstructions(void)
{
cout << "La touche Escape (ESC) pour quitter." << endl;
cout << "La touche + (plus) pour grandir l'échelle." << endl;
cout << "La touche - (moins) pour réduire l'échelle." << endl;
cout << "--- ENTRÉE pour débuter ---" << endl;
cin.get();
}
char generer(size_t x, size_t y, size_t tailleX, size_t tailleY, float echelle)
{
echelle = (echelle / 4); // Ajuster l'échelle
const float ECHELLE_X = 8.f;
const float ECHELLE_Y = 4.f;
const float unSurTailleX{ 1.f / tailleX };
const float unSurTailleY{ 1.f / tailleY };
// La fonction de perlin permet de produire du bruit cohérent.
// Un bruit cohérent est une fonction qui retourne des nombres aléatoires avec un contrôle sur la variation.
// La version que nous utilisons ici permet de générer du bruit 3D, mais nous l'utilisons en version 2D
// lorsque nous spécifions z = 0 (3D -> 2D).
//
// Perlin retourne une valeur entre [-1.0, 1.0] pour les floats x, y et z en entrée.
// Le wrap (l'enroulement) permet de garder le signal entre certaines valeurs,
// lors que nous spécifions 0, nous laissons le contrôle à Perlin et recevont dans l'intervale complet [-1.f, 1.f]
// [-1.f, 1.f] --> +1.f --> [0.f, 2.f ] --> *0.5f --> [0.f, 1.f] --> *255 + 0.5 -> [0.5, 255.5] -> transtypage(int - laisser tomber les décimales) -> [0, 255]
int _0_255 = static_cast< int >(((stb_perlin_noise3(x * unSurTailleX * ECHELLE_X * echelle,
y * unSurTailleY * ECHELLE_Y * echelle,
/*z*/ 0.f,
0, 0, 0) // wrap / enroulement
+ 1.f) * 0.5f * 255) + 0.5f);
_0_255 = min(max(0, _0_255), 255); // Restreindre à [0, 255]
const char carac = SYMBOLES_GRIS.at(static_cast< int >( _0_255 / 256.f * SYMBOLES_GRIS.length()));
return carac;
}
void ecrireLigne(size_t y, size_t tailleX, size_t tailleY, float echelle)
{
string line( tailleX, ' ' );
for (size_t x = 0; x < tailleX; x++)
{
line[x] = generer(x, y, tailleX, tailleY, echelle);
}
cout << line << endl;
cout.flush();
}
void obtenirTailleFenetre(size_t & largeur, size_t & hauteur)
{
const COORD tailleFenetre{ GetLargestConsoleWindowSize(GetStdHandle(STD_OUTPUT_HANDLE)) };
largeur = tailleFenetre.X;
hauteur = tailleFenetre.Y;
}
static auto derniereLecture{ std::chrono::system_clock::now() };
Operation interagir(void)
{
static const auto attenteLecture = chrono::milliseconds(500);
const auto maintenant{ std::chrono::system_clock::now() };
const bool okPeutLire = ((derniereLecture + attenteLecture) < maintenant);
while (okPeutLire)
{
if (GetAsyncKeyState(VK_ADD) & 0x8000)
{
derniereLecture = maintenant;
return Operation::PlusGrand;
}
else if (GetAsyncKeyState(VK_SUBTRACT) & 0x8000)
{
derniereLecture = maintenant;
return Operation::PlusPetit;
}
else if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)
{
derniereLecture = maintenant;
return Operation::Quitter;
}
}
return Operation::Rien;
}
void configurerConsole(size_t & largeur, size_t & hauteur)
{
::SendMessage(::GetConsoleWindow(), WM_SYSKEYDOWN, VK_RETURN, 0x20000000); // Plein écran
obtenirTailleFenetre(largeur, hauteur);
system(("mode " + to_string(largeur) + ',' + to_string(hauteur)).c_str()); // Taille MS-DOS
cout << endl;
}
int main(void)
{
setlocale(LC_ALL, "");
size_t tailleX{ 80 };
size_t tailleY{ 25 };
configurerConsole(tailleX, tailleY);
afficherInstructions();
std::future< Operation > future{ std::async(std::launch::async, interagir) };
const string separateur(tailleX, '-');
const auto attente{ chrono::milliseconds(15) };
size_t y{ 0 };
float echelle{ 4 };
bool fin{ false };
while (!fin)
{
obtenirTailleFenetre(tailleX, tailleY);
y++;
ecrireLigne(y, tailleX, tailleY, echelle);
this_thread::sleep_for(attente);
if (future.wait_for(chrono::milliseconds::zero()) == std::future_status::ready)
{
const Operation op{ future.get() };
future = std::async(std::launch::async, interagir);
switch (op)
{
case Operation::PlusPetit:
echelle = echelle / 1.2f;
cout << separateur << endl;
break;
case Operation::PlusGrand:
echelle = echelle * 1.2f;
cout << separateur << endl;
break;
case Operation::Quitter:
fin = true;
break;
}
}
}
return 0;
}