#include <gp/coord.h>
#include <numbers>
#include "frame_buffer.h"
#include "hw01-misc.h"
template<class T>
class safe_vector : public vector<T> {
public:
T& operator [] ( size_t idx )
{
return vector<T>::at(idx);
}
};
struct HW01_Data {
HW01_Data():inited(false){};
bool inited;
bool tryout0, tryout1;
safe_vector<uint32_t> fb_area_dup;
bool opt_circle_hw01;
float gamma;
int mag_r;
};
void
circle_draw_hw01
( pFrame_Buffer& fb, HW01_Data& hw01_data,
int ctr_x, int ctr_y,
int r_outer, int r_inner, uint32_t co)
{
const int win_width [[maybe_unused]] = fb.width_get();
const int win_height [[maybe_unused]] = fb.height_get();
int r_o_sq = r_outer * r_outer;
int r_i_sq = r_inner * r_inner;
int idx_ctr = ctr_y * win_width + ctr_x;
for ( int ly = 0; ly <= r_outer; ly++ )
{
int lx0 = sqrtf( max( 0, r_i_sq - ly * ly ) );
int lx1 = sqrtf( max( 0, r_o_sq - ly * ly ) );
int ly_ww = ly * win_width;
for ( int lx = lx0; lx <= lx1; lx++ )
{
fb[ idx_ctr + ly_ww + lx ] = co;
fb[ idx_ctr + ly_ww - lx ] = co;
fb[ idx_ctr - ly_ww + lx ] = co;
fb[ idx_ctr - ly_ww - lx ] = co;
}
}
}
void
circle_draw_parametric
( pFrame_Buffer& fb, HW01_Data& hw01_data,
int ctr_x, int ctr_y,
int r_outer, int r_inner, uint32_t co)
{
const int win_width = fb.width_get();
float delta_theta = asinf(1.0f/r_outer);
for ( float theta = 0; theta < 2*numbers::pi; theta += delta_theta )
{
float cth = cosf(theta), sth = sinf(theta);
for ( int r = r_inner; r<=r_outer; r++ )
{
int x = ctr_x + r * cth, y = ctr_y + r * sth;
fb[ y * win_width + x ] = co;
}
}
}
void circle_draw
( pFrame_Buffer& fb, HW01_Data& hw01_data,
int ctr_x, int ctr_y,
int r_outer, int r_inner, uint32_t co)
{
if ( hw01_data.opt_circle_hw01 )
circle_draw_hw01(fb,hw01_data,ctr_x,ctr_y,r_outer, r_inner,co);
else
circle_draw_parametric(fb,hw01_data,ctr_x,ctr_y,r_outer, r_inner,co);
}
void
line_draw
( pFrame_Buffer& fb, iCoor p0, iCoor p1, uint32_t co)
{
int x0 = p0.x, y0 = p0.y;
int x1 = p1.x, y1 = p1.y;
const iVect delta = p1 - p0;
const int width = fb.width_get();
if ( abs( delta.x ) < abs( delta.y ) )
{
if ( y0 > y1 ) { swap(x0,x1); swap(y0,y1); }
float dxdy = float(delta.x) / delta.y;
float x = x0;
for ( int yi = y0; yi < y1; yi++ )
{
fb[ yi * width + x ] = co;
x += dxdy;
}
}
else
{
if ( x0 > x1 ) { swap(x0,x1); swap(y0,y1); }
float dydx = float(delta.y) / delta.x;
float y = y0;
for ( int xi = x0; xi < x1; xi++ )
{
fb[ int(y) * width + xi ] = co;
y += dydx;
}
}
}
void
parallel_lines_draw
( pFrame_Buffer& fb, iCoor p0, iCoor pb, iVect v, uint32_t co)
{
line_draw( fb, p0, p0 + v, co );
line_draw( fb, pb, pb + v, co );
}
void
parallelogram_draw
( pFrame_Buffer& fb, iCoor p00, iVect vx, iVect vy, uint32_t color )
{
parallel_lines_draw(fb, p00, p00+vy, vx, color);
parallel_lines_draw(fb, p00, p00+vx, vy, color);
}
void
aa_rectangle_draw
( pFrame_Buffer& fb, iCoor p00, int wd, int ht, uint32_t color )
{
const int win_width [[maybe_unused]] = fb.width_get();
const int win_height [[maybe_unused]] = fb.height_get();
iVect vx(wd,0);
iVect vy(0,ht);
iCoor p10 = p00 + vx;
iCoor p01 = p00 + vy;
iCoor p11 = p10 + vy;
line_draw( fb, p00, p01, color );
line_draw( fb, p10, p11, color );
line_draw( fb, p00, p10, color );
line_draw( fb, p01, p11, color );
}
void kbd_input_handle(pFrame_Buffer& fb, HW01_Data& hw01_data);
void
render_hw01(pFrame_Buffer& fb, HW01_Data& hw01_data)
{
const int win_width = fb.width_get();
const int win_height = fb.height_get();
kbd_input_handle(fb,hw01_data);
const int sq_slen = min(win_width,win_height) * .45;
const int sq_x0 = sq_slen * 0.1, sq_y0 = win_height - 150;
const int sq_x1 = sq_x0 + sq_slen, sq_y1 = sq_y0 - sq_slen;
const uint32_t color_red = 0xff0000;
const uint32_t color_blue = 0xff;
const uint32_t color_green = 0xff00;
int num_waves = 4;
float plot_ht = sq_slen/float(num_waves);
for ( float
yb = sq_y0 - plot_ht/2, freq = 4 * M_PI / ( win_width - 40 - sq_x1 );
yb > sq_y1;
yb -= plot_ht, freq *= 2 )
for ( int x = 20; x < win_width - 20; x++ )
{
int y = yb + sin( x * freq ) * plot_ht * .45;
fb[ y * win_width + x ] = 0xff00;
}
int n_rects = 24;
int n_pts = n_rects * 3;
float c_r1 = sq_slen/6; float c_r2 = sq_slen/2; pCoor c_ctr( c_r2 + 20, c_r2 + 20 ); float delta_theta = 2 * M_PI / n_pts;
vector<pVect> vecs;
circle_draw(fb, hw01_data, c_ctr.x, c_ctr.y, c_r2+9, c_r2+1, color_green);
circle_draw(fb, hw01_data, c_ctr.x, c_ctr.y, c_r1-1, c_r1-2, color_red);
for ( int i=0; i<n_pts; i++ )
vecs.push_back( pVect( cosf(i*delta_theta), sinf(i*delta_theta), 0 ) );
for ( int i=0; i<n_pts; i+=3 )
{
pVect v1 = vecs[i+1] * ( c_r2 - c_r1 );
pVect v2 = c_r1 * ( vecs[i+2] - vecs[i] );
pCoor p1 = c_ctr + c_r1 * vecs[i];
parallelogram_draw(fb, p1, v1, v2, 0xffffff );
}
fb.fb_stats_off();
const iCoor ctr(fb.mouse_x,fb.mouse_y);
const int mag_r = hw01_data.mag_r;
const float gamma [[maybe_unused]] = hw01_data.gamma;
auto& fb_dup [[maybe_unused]] = hw01_data.fb_area_dup;
circle_draw(fb, hw01_data, ctr.x, ctr.y, mag_r+2, mag_r+1, color_blue);
int idx_ctr = ctr.y * win_width + ctr.x;
int mag_r_sq = mag_r * mag_r;
int mag_2r = 2 * mag_r;
for ( int x = -mag_r; x < mag_r; x++ )
for ( int y = -mag_r; y < mag_r; y++ )
fb_dup[ ( y + mag_r ) * mag_2r + x + mag_r ]
= fb[ ( ctr.y + y ) * win_width + ctr.x + x ];
const float mag_r_inv = 1.0 / mag_r;
for ( int lx = 0; lx < mag_r; lx++ )
for ( int ly = 0; ly < mag_r; ly++ )
{
int len_sq = lx*lx + ly*ly;
if ( len_sq > mag_r_sq ) break;
float d = powf( len_sq, 0.5 );
float d_prime = powf( d * mag_r_inv, gamma ) * mag_r;
int lx_src = d ? lx * d_prime / d : 0;
int ly_src = d ? ly * d_prime / d : 0;
fb[ idx_ctr + ly * win_width + lx ] =
fb_dup[ (mag_r+ly_src) * mag_2r + lx_src + mag_r];
fb[ idx_ctr + ly * win_width - lx ] =
fb_dup[ (mag_r+ly_src) * mag_2r - lx_src + mag_r];
fb[ idx_ctr - ly * win_width - lx ] =
fb_dup[ (mag_r-ly_src) * mag_2r - lx_src + mag_r];
fb[ idx_ctr - ly * win_width + lx ] =
fb_dup[ (mag_r-ly_src) * mag_2r + lx_src + mag_r];
}
}
void
kbd_input_handle(pFrame_Buffer& fb, HW01_Data& hw01_data)
{
if ( !hw01_data.inited )
{
hw01_data.inited = true;
hw01_data.gamma = 1;
hw01_data.mag_r = 100;
hw01_data.opt_circle_hw01 = true;
int mag_2r = (hw01_data.mag_r+1) * 2;
hw01_data.tryout0 = false;
hw01_data.tryout1 = false;
hw01_data.fb_area_dup.resize( mag_2r * mag_2r );
}
switch ( fb.keyboard_key ) {
#if 0
case FB_KEY_RIGHT: case FB_KEY_LEFT:
{
const int inc = fb.keyboard_key == FB_KEY_LEFT ? -kbd_inc : kbd_inc;
break;
}
case FB_KEY_UP: case FB_KEY_DOWN:
{
const int inc = fb.keyboard_key == FB_KEY_DOWN ? -kbd_inc : kbd_inc;
break;
}
#endif
case 'c': case 'C':
hw01_data.opt_circle_hw01 = !hw01_data.opt_circle_hw01; break;
case 'u': hw01_data.gamma /= 1.1; break;
case 'U': hw01_data.gamma /= 1.5; break;
case 'z': hw01_data.gamma *= 1.1; break;
case 'Z': hw01_data.gamma *= 1.5; break;
case 'y':
hw01_data.tryout0 = !hw01_data.tryout0; break;
case 'Y':
hw01_data.tryout1 = !hw01_data.tryout1; break;
default:
break;
};
fb.fbprintf("Gamma: %.2f ('z','u') Circle Routine %s ('c') "
"Tryout 0,1: %s,%s ('y','Y')\n",
hw01_data.gamma,
hw01_data.opt_circle_hw01
? "circle_draw_hw01" : "circle_draw_parametric",
hw01_data.tryout0 ? "TRUE " : "FALSE",
hw01_data.tryout1 ? "TRUE " : "FALSE");
}
int
main(int argc, char **argv)
{
pFrame_Buffer demo_frame_buffer(argc,argv);
HW01_Data hw01_data;
demo_frame_buffer.show
( [&](pFrame_Buffer& fb){ render_hw01(fb,hw01_data); } );
return 0;
}