2022-04-07 18:46:57 +02:00

165 lines
4.9 KiB
C++

/*
Copyright (c) 2005-2020 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef FRACTAL_H_
#define FRACTAL_H_
#include <atomic>
#include "../../common/gui/video.h"
#include "../../common/utility/get_default_num_threads.h"
#include "tbb/task.h"
#include "tbb/task_arena.h"
#include "tbb/task_group.h"
//! Fractal class
class fractal {
//! Left corner of the fractal area
int off_x, off_y;
//! Size of the fractal area
int size_x, size_y;
//! Fractal properties
float cx, cy;
float magn;
float step;
unsigned int max_iterations;
//! Drawing memory object for rendering
const drawing_memory &dm;
//! One pixel calculation routine
color_t calc_one_pixel( int x, int y ) const;
//! Clears the fractal area
void clear();
//! Draws the border around the fractal area
void draw_border( bool is_active );
//! Renders the fractal
void render( tbb::task_group_context &context );
//! Check if the point is inside the fractal area
bool check_point( int x, int y ) const;
public:
//! Constructor
fractal( const drawing_memory &dm ) : step(0.2), dm(dm) {
#if _MSC_VER && _WIN64 && !__INTEL_COMPILER
// Workaround for MSVC x64 compiler issue
volatile int i=0;
#endif
}
//! Runs the fractal calculation
void run( tbb::task_group_context &context );
//! Renders the fractal rectangular area
void render_rect( int x0, int y0, int x1, int y1 ) const;
void move_up() { cy += step; }
void move_down() { cy -= step; }
void move_left() { cx += step; }
void move_right(){ cx -= step; }
void zoom_in() { magn *= 2.; step /= 2.; }
void zoom_out(){ magn /= 2.; step *= 2.; }
void quality_inc() { max_iterations += max_iterations/2; }
void quality_dec() { max_iterations -= max_iterations/2; }
friend class fractal_group;
};
//! The group of fractals
class fractal_group {
//! Fractals definition
fractal f0, f1;
//! Number of frames to calculate
std::atomic<int> num_frames[2];
//! Contexts, arenas and groups for concurrent computation
tbb::task_group_context context[2];
tbb::task_arena arenas[2];
tbb::task_group groups[2];
//! Border type enumeration
enum BORDER_TYPE {
BORDER_INACTIVE = 0,
BORDER_ACTIVE
};
//! The number of the threads
int num_threads;
//! The active (high priority) fractal number
int active;
//! Draws the borders around the fractals
void draw_borders();
//! Sets priorities for fractals calculations
void set_priorities();
public:
//! Constructor
fractal_group( const drawing_memory &_dm,
int num_threads = utility::get_default_num_threads(),
unsigned int max_iterations = 100000, int num_frames = 1 );
//! Run calculation
void run( bool create_second_fractal=true );
//! Mouse event handler
void mouse_click( int x, int y );
//! Fractal calculation routine
void calc_fractal( int num );
//! Get number of threads
int get_num_threads() const { return num_threads; }
//! Reset the number of frames to be not less than the given value
void set_num_frames_at_least( int n );
//! Switch active fractal
void switch_active( int new_active=-1 );
//! Get active fractal
fractal& get_active_fractal() { return active ? f1 : f0; }
void active_fractal_zoom_in() {
get_active_fractal().zoom_in();
context[active].cancel_group_execution();
}
void active_fractal_zoom_out() {
get_active_fractal().zoom_out();
context[active].cancel_group_execution();
}
void active_fractal_quality_inc() {
get_active_fractal().quality_inc();
context[active].cancel_group_execution();
}
void active_fractal_quality_dec() {
get_active_fractal().quality_dec();
context[active].cancel_group_execution();
}
void active_fractal_move_up() {
get_active_fractal().move_up();
context[active].cancel_group_execution();
}
void active_fractal_move_down() {
get_active_fractal().move_down();
context[active].cancel_group_execution();
}
void active_fractal_move_left() {
get_active_fractal().move_left();
context[active].cancel_group_execution();
}
void active_fractal_move_right() {
get_active_fractal().move_right();
context[active].cancel_group_execution();
}
};
#endif /* FRACTAL_H_ */