Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <random>
- #include <iostream>
- #include <iomanip>
- #include <fstream>
- #include <GL/gl.h>
- #include <GL/glut.h>
- // Rozmiar macierzy, musi być 2^n + 1
- const int size = 257;
- // Stopień definiujący zaokrąglanie obrazu
- // Większa wartość daje więcej punktów i "płynniejszy" obraz
- int range = 98;
- // Początkowy kąt kamery
- float angle = 0;
- // Skala obrazu
- const float scaling = 0.5f;
- // Funkcja określająca czas odświeżania widoku
- const int refreshMills = 16;
- // Macierz przechowująca obraz
- int map[size][size];
- // Funkcja zwracająca losowo wartość RGB
- int rnd(int min = 0, int max = 255)
- {
- return min + (rand() % static_cast<int>(max - min + 1));
- }
- // Inicjalizacja losowymi wartościami rogów
- void init()
- {
- map[0][0] = rnd();
- map[0][size - 1] = rnd();
- map[size - 1][0] = rnd();
- map[size - 1][size - 1] = rnd();
- }
- // Krok "Diamentowy" algorytmu Diamond-Square
- void diamond(int sideLength)
- {
- // Podział boku na pół
- int halfSide = sideLength / 2;
- // Podwójna pętla iterująca po kolejnych kwadratach powstałych na skutek podziału
- for (int y = 0; y < size / (sideLength-1); y++)
- {
- for (int x = 0; x < size / (sideLength-1); x++)
- {
- // Wyznaczenie środka aktualnego kwadratu
- int center_x = x*(sideLength-1) + halfSide;
- int center_y = y*(sideLength-1) + halfSide;
- //Uśrednienie wartości koloru na podstawie jego sąsiadów
- int avg = (map[x*(sideLength - 1)][y*(sideLength - 1)] +
- map[x*(sideLength - 1)][(y+1) * (sideLength - 1)] +
- map[(x + 1) * (sideLength - 1)][y*(sideLength - 1)] +
- map[(x + 1) * (sideLength - 1)][(y + 1) * (sideLength - 1)])
- / 4.0f;
- // Ustawienie koloru aktualnego kwadratu, bazując na kolorze uśrednionym
- map[center_x][center_y] = avg + rnd(-range, range);
- }
- }
- }
- // Funkcja uśredniająca, eliminuje przypadki
- // W których punkty nie są całkowite, bądź wykraczają poza macierz
- // Przypisuje do macierzy wartości ograniczone przez jej rozmiar
- void average(int x, int y, int sideLength)
- {
- // Zmienne pomocnicze
- float counter = 0;
- float accumulator = 0;
- int halfSide = sideLength / 2;
- // Jeżeli x nie posiada wartości
- if (x != 0)
- {
- counter += 1.0f;
- accumulator += map[y][x - halfSide];
- }
- // jeżeli y nie posiada wartości
- if (y != 0)
- {
- counter += 1.0f;
- accumulator += map[y - halfSide][x];
- }
- // Jeżeli x wykracza poza zakres
- if (x != size - 1)
- {
- counter += 1.0f;
- accumulator += map[y][x + halfSide];
- }
- // Jeżeli y wykracza poza zakres
- if (y != size - 1)
- {
- counter += 1.0f;
- accumulator += map[y + halfSide][x];
- }
- // Przypisanie poprawwionej wartości do macierzy
- map[y][x] = (accumulator / counter) + rnd(-range, range);
- }
- // Krok "Kwadratowy" algorytmu Diamond-Square
- void square(int sideLength)
- {
- // Podział boku na pół
- int halfLength = sideLength / 2;
- // Podwójna pętla iterująca po kolejnych kwadratach powstałych na skutek podziału
- for (int y = 0; y < size / (sideLength - 1); y++)
- {
- for (int x = 0; x < size / (sideLength - 1); x++)
- {
- // Góra kwadratu
- average(x*(sideLength - 1) + halfLength, y*(sideLength - 1), sideLength);
- // Prawo kwadratu
- average((x + 1)*(sideLength - 1), y*(sideLength - 1) + halfLength, sideLength);
- // Dół kwadratu
- average(x*(sideLength - 1) + halfLength, (y+1)*(sideLength - 1), sideLength);
- // Lewo kwadratu
- average(x*(sideLength - 1), y*(sideLength - 1) + halfLength, sideLength);
- }
- }
- }
- // Główna funkcja wywołujaca algorytm Diamond-Square
- // Wywołuje kolejne iteracje kroków "Diament" i "Kwadrat"
- void fractal()
- {
- // Startowe wywołanie algorytmu, podział macierzy na 4 części
- int sideLength = size/2;
- diamond(size);
- square(size);
- // Zmniejszenie zakresu o połowę
- range /= 2;
- // Pętla wykonująca kolejne iteracje
- // dopóki aktualny kwadrat ma rozmiar większy od piksela
- while (sideLength >= 2)
- {
- diamond(sideLength + 1);
- square(sideLength + 1);
- sideLength /= 2;
- range /= 2;
- }
- }
- // Pomocnicza funkcja zaorkąglająca wartości
- void clamp(int* val, int min, int max)
- {
- if (*val < min) *val = min;
- if (*val > max) *val = max;
- }
- // Pomocnicza funkcja zaorkąglająca wszystkie wartości w macierzy
- void clamp_map()
- {
- for (int i = 0; i < size; i++)
- {
- for (int j = 0; j < size; j++)
- {
- clamp(&map[i][j], 0, 255);
- }
- }
- }
- // Funkcja renderująca obraz z macierzy na ekran
- void render()
- {
- // Inicjalizacja zmiennej przechowującej kolor
- int color;
- // Wyczyszczenie ekranu
- glClear(GL_COLOR_BUFFER_BIT);
- // Ustalenie rozmiaru pojedyńczego punktu
- glPointSize(3);
- // Wypełnienie obrazu punktami z macierzy
- glBegin(GL_POINTS);
- for (int i = 0; i < size; i++)
- {
- for (int j = 0; j < size; j++)
- {
- // Przypisanie koloru z macierzy
- color = map[j][i];
- glColor3ub(color, color, color);
- // Narysowanie kwadratu o zadanym kolorze
- glVertex2f(i * 100.0f/size, j * 100.0f/size);
- }
- }
- // Zakończenie renderowania
- glEnd();
- glFlush();
- }
- // Parametry horizontal i vertical (szerokość i wysokość okna) są
- // przekazywane do funkcji za każdym razem, gdy zmieni się rozmiar okna
- void ChangeSize(GLsizei horizontal, GLsizei vertical)
- {
- // Deklaracja zmiennej AspectRatio określającej proporcję wymiarów okna
- GLfloat AspectRatio;
- // Zabezpieczenie przed dzieleniem przez 0
- if (vertical == 0) vertical = 1;
- // Ustawienie wielkościokna okna urządzenia (Viewport)
- // W tym przypadku od (0,0) do (horizontal, vertical)
- glViewport(0, 0, horizontal, vertical);
- // Określenie układu współrzędnych obserwatora
- glMatrixMode(GL_PROJECTION);
- // Określenie przestrzeni ograniczającej
- glLoadIdentity();
- // Wyznaczenie współczynnika proporcji okna
- AspectRatio = (GLfloat)horizontal / (GLfloat)vertical;
- // Gdy okno na ekranie nie jest kwadratem wymagane jest
- // określenie okna obserwatora.
- // Pozwala to zachować właściwe proporcje rysowanego obiektu
- // Do określenia okna obserwatora służy funkcja glOrtho(...)
- if (horizontal <= vertical) glOrtho(0, 100.0, 100.0 / AspectRatio, 0, 1.0, -1.0);
- else glOrtho(0, 100.0*AspectRatio, 100.0, 0, 1.0, -1.0);
- // Określenie układu współrzędnych
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- }
- // Zmiana zachowania przy pomocy klawiszy
- void handle_input(unsigned char key, int x, int y)
- {
- switch (key)
- {
- // Zamknięcie programu klawiszem ESC
- case 27:
- glutDestroyWindow(glutGetWindow());
- exit(0);
- break;
- // Generacja nowego obrazu klawiszem SPACE
- case 32:
- range = 196;
- init();
- fractal();
- clamp_map();
- glutPostRedisplay();
- break;
- // Zmiana shadingu klawiszami 1,2,3
- case '1':
- glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
- break;
- case '2':
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- break;
- case '3':
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- break;
- }
- }
- // Inicjalizacja OpenGL
- void initGL() {
- // Ustawienia koloru czarnego dla tła
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
- // Ustawienie głębokości renderowania na maksymalną
- glClearDepth(1.0f);
- // Uruchomienie i konfiguracja testów głębokości (z-culling)
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_LEQUAL);
- // Uruchomienie wygładzania
- glShadeModel(GL_SMOOTH);
- // Korekcja perspektywy
- glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
- }
- // Funkcja odświerzająca widok po upływie czasu
- void timer(int value) {
- glutPostRedisplay();
- glutTimerFunc(refreshMills, timer, 0);
- }
- // Funcja zwracająca losową wartość typu float
- float randomFloat()
- {
- float r3 = 0 + static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / (0.7f - 0)));
- return r3;
- }
- // Funkcja konwertująca kolor na jego czarno-biały odpowiednik
- void monoColor(float color)
- {
- glColor3ub(color, color, color);
- }
- // Funkcja wywoływana w momencie, kiedy wykonywany jest repaint okna
- void display() {
- // Czyszczenie koloru i głębokości
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- // Aktywacja widoku modelu dla macierzy
- glMatrixMode(GL_MODELVIEW);
- // Reset widoku modelu
- glLoadIdentity();
- // Przesunięcie w lewo i wokół osi
- glTranslatef(0, -0.3f, -1.5f);
- glRotatef(90, 0, 0, 1);
- glRotatef(60, 0, 1, 0);
- glRotatef(angle += 0.5f, 0, 0, 1);
- // Rysowanie piramidowych trójkątów
- glBegin(GL_TRIANGLES);
- for (int y = 0; y < size - 1; y++)
- {
- for (int x = 0; x < size - 1; x++)
- {
- // Uśrednienie wartości dla pośrednich punktów
- float midpoint_value = (map[y][x] + map[y][x + 1] + map[y + 1][x] + map[y + 1][x + 1])/4.0f;
- float midpoint_x = 1.0f / size * (x + 0.5f);
- float midpoint_y = 1.0f / size * (y + 0.5f);
- // Góra
- monoColor(map[y][x]);
- glVertex3f(1.0f / size*x - 0.5f, 1.0f / size*y - 0.5f, 1.0f / 256 * map[y][x]);
- monoColor(midpoint_value);
- glVertex3f(midpoint_x - 0.5f, midpoint_y - 0.5f, 1.0f / 256 * midpoint_value );
- monoColor(map[y][x + 1]);
- glVertex3f(1.0f / size*(x + 1) - 0.5f, 1.0f / size*y - 0.5f, 1.0f / 256 * map[y][x + 1]);
- // Lewo
- monoColor(map[y][x]);
- glVertex3f(1.0f / size*x - 0.5f, 1.0f / size*y - 0.5f, 1.0f / 256 * map[y][x]);
- monoColor(map[y + 1][x]);
- glVertex3f(1.0f / size*x - 0.5f, 1.0f / size*(y + 1) - 0.5f, 1.0f / 256 * map[y + 1][x]);
- monoColor(midpoint_value);
- glVertex3f(midpoint_x - 0.5f, midpoint_y - 0.5f, 1.0f / 256 * midpoint_value);
- // Dół
- monoColor(map[y + 1][x + 1]);
- glVertex3f(1.0f / size*(x+1) - 0.5f, 1.0f / size*(y+1) - 0.5f, 1.0f / 256 * map[y+1][x+1]);
- monoColor(map[y + 1][x]);
- glVertex3f(1.0f / size*x - 0.5f, 1.0f / size*(y + 1) - 0.5f, 1.0f / 256 * map[y+1][x]);
- monoColor(midpoint_value);
- glVertex3f(midpoint_x - 0.5f, midpoint_y - 0.5f, 1.0f / 256 * midpoint_value);
- // Prawo
- monoColor(map[y][x + 1]);
- glVertex3f(1.0f / size*(x + 1) - 0.5f, 1.0f / size*y - 0.5f, 1.0f / 256 * map[y][x + 1]);
- monoColor(midpoint_value);
- glVertex3f(midpoint_x - 0.5f, midpoint_y - 0.5f, 1.0f / 256 * midpoint_value);
- monoColor(map[y + 1][x + 1]);
- glVertex3f(1.0f / size*(x + 1) - 0.5f, 1.0f / size*(y + 1) - 0.5f, 1.0f / 256 * map[y+1][x+1]);
- }
- }
- // Zakończenie rysowania trójkątów
- glEnd();
- // Zmiana buforów klatek
- glutSwapBuffers();
- }
- // Funkcja obslugująca zmianę rozmiaru okna
- void reshape(GLsizei width, GLsizei height) {
- if (height == 0) height = 1;
- GLfloat aspect = (GLfloat)width / (GLfloat)height;
- glViewport(0, 0, width, height);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective(45.0f, aspect, 0.1f, 100.0f);
- }
- int main(int argc, char** argv) {
- init();
- fractal();
- clamp_map();
- glutInit(&argc, argv);
- glutInitDisplayMode(GLUT_DOUBLE);
- glutInitWindowSize(640, 480);
- glutInitWindowPosition(50, 50);
- glutCreateWindow("Fraktal Plazmowy 3-D");
- glutDisplayFunc(display);
- glutReshapeFunc(reshape);
- glutKeyboardFunc(handle_input);
- initGL();
- glutTimerFunc(0, timer, 0);
- glutMainLoop();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement