|
|
@@ -38,78 +38,117 @@ public: |
|
|
|
m_size = size; |
|
|
|
m_pixels = new u8vec4[size.x * size.y]; |
|
|
|
m_frame = -1; |
|
|
|
m_center = 0; |
|
|
|
//m_target = f64cmplx(0.001643721971153, 0.822467633298876); |
|
|
|
m_target = f64cmplx(-1.207205434596, 0.315432814901); |
|
|
|
//m_target = f64cmplx(-0.79192956889854, -0.14632423080102); |
|
|
|
//m_target = f64cmplx(0.3245046418497685, 0.04855101129280834); |
|
|
|
//m_target = f64cmplx(0.28693186889504513, 0.014286693904085048); |
|
|
|
m_angle = 0.0; |
|
|
|
m_radius = 8.0; |
|
|
|
m_dirty = 8; |
|
|
|
m_center = -0.75; |
|
|
|
//f64cmplx(0.001643721971153, 0.822467633298876); |
|
|
|
//f64cmplx(-1.207205434596, 0.315432814901); |
|
|
|
//f64cmplx(-0.79192956889854, -0.14632423080102); |
|
|
|
//f64cmplx(0.3245046418497685, 0.04855101129280834); |
|
|
|
//f64cmplx(0.28693186889504513, 0.014286693904085048); |
|
|
|
m_radius = 1.5; |
|
|
|
m_screenradius = 0.5 * (m_size.x < m_size.y ? m_size.x : m_size.y); |
|
|
|
m_ready = false; |
|
|
|
|
|
|
|
m_centertext = new Text(NULL, "gfx/font/ascii.png"); |
|
|
|
m_centertext->SetPos(ivec3(5, m_size.y - 15, 1)); |
|
|
|
Ticker::Ref(m_centertext); |
|
|
|
|
|
|
|
m_mousetext = new Text(NULL, "gfx/font/ascii.png"); |
|
|
|
m_mousetext->SetPos(ivec3(5, m_size.y - 29, 1)); |
|
|
|
Ticker::Ref(m_mousetext); |
|
|
|
|
|
|
|
position = ivec3(0, 0, 0); |
|
|
|
bbox[0] = position; |
|
|
|
bbox[1] = ivec3(size, 0); |
|
|
|
Input::TrackMouse(this); |
|
|
|
} |
|
|
|
|
|
|
|
~Fractal() |
|
|
|
{ |
|
|
|
Input::UntrackMouse(this); |
|
|
|
Ticker::Unref(m_centertext); |
|
|
|
Ticker::Unref(m_mousetext); |
|
|
|
delete m_pixels; |
|
|
|
} |
|
|
|
|
|
|
|
inline f64cmplx ScreenToWorldOffset(ivec2 pixel) |
|
|
|
{ |
|
|
|
f64cmplx tmp = f64cmplx(pixel.x - m_size.x / 2, |
|
|
|
m_size.y / 2 - pixel.y); |
|
|
|
return tmp * (m_radius / m_screenradius); |
|
|
|
} |
|
|
|
|
|
|
|
virtual void TickGame(float deltams) |
|
|
|
{ |
|
|
|
WorldEntity::TickGame(deltams); |
|
|
|
|
|
|
|
m_frame = (m_frame + 1) % 4; |
|
|
|
|
|
|
|
double zoom = pow(2.0, -deltams * 0.0005); |
|
|
|
m_radius *= zoom; |
|
|
|
m_center = (m_center - m_target) * zoom * zoom + m_target; |
|
|
|
f64cmplx worldmouse = m_center + ScreenToWorldOffset(mousepos); |
|
|
|
|
|
|
|
double step = m_radius / (m_size.x > m_size.y ? m_size.x : m_size.y); |
|
|
|
// m_angle -= deltams * 0.00015; |
|
|
|
f64cmplx transform = step * f64cmplx(cos(m_angle), sin(m_angle)); |
|
|
|
ivec3 buttons = Input::GetMouseButtons(); |
|
|
|
if ((buttons[0] || buttons[2]) && mousepos.x != -1) |
|
|
|
{ |
|
|
|
double zoom = pow(2.0, (buttons[0] ? -deltams : deltams) * 0.0015); |
|
|
|
if (m_radius * zoom > 1.5) |
|
|
|
zoom = 1.0; |
|
|
|
m_radius *= zoom; |
|
|
|
m_center = (m_center - worldmouse) * zoom + worldmouse; |
|
|
|
worldmouse = m_center + ScreenToWorldOffset(mousepos); |
|
|
|
m_dirty = 8; |
|
|
|
} |
|
|
|
|
|
|
|
char buf[128]; |
|
|
|
sprintf(buf, "center: %+13.11f%+13.11fi", m_center.x, m_center.y); |
|
|
|
m_centertext->SetText(buf); |
|
|
|
sprintf(buf, " mouse: %+13.11f%+13.11fi", worldmouse.x, worldmouse.y); |
|
|
|
m_mousetext->SetText(buf); |
|
|
|
|
|
|
|
u8vec4 *m_pixelstart = m_pixels + m_size.x * m_size.y / 4 * m_frame; |
|
|
|
|
|
|
|
for (int j = ((m_frame + 1) % 4) / 2; j < m_size.y; j += 2) |
|
|
|
for (int i = m_frame % 2; i < m_size.x; i += 2) |
|
|
|
if (m_dirty) |
|
|
|
{ |
|
|
|
double const maxlen = 32; |
|
|
|
int const maxiter = 170; |
|
|
|
|
|
|
|
f64cmplx delta(i - m_size.x / 2, j - m_size.y / 2); |
|
|
|
|
|
|
|
f64cmplx z0 = m_center + transform * delta; |
|
|
|
f64cmplx r0 = z0; |
|
|
|
//f64cmplx r0(0.28693186889504513, 0.014286693904085048); |
|
|
|
//f64cmplx r0(0.001643721971153, 0.822467633298876); |
|
|
|
f64cmplx z; |
|
|
|
int iter = maxiter; |
|
|
|
for (z = z0; iter && z.sqlen() < maxlen * maxlen; z = z * z + r0) |
|
|
|
--iter; |
|
|
|
|
|
|
|
double f = iter; |
|
|
|
double n = z.sqlen(); |
|
|
|
|
|
|
|
double k = log(n) * 0.5f / log(maxlen); |
|
|
|
/* Approximate log2(k) in [1,2]. */ |
|
|
|
f += (- 0.344847817623168308695977510213252644185 * k |
|
|
|
+ 2.024664188044341212602376988171727038739) * k |
|
|
|
- 1.674876738008591047163498125918330313237; |
|
|
|
|
|
|
|
if (iter) |
|
|
|
{ |
|
|
|
double r = 0.5 * sin(f * 0.27 - 2.0) + 0.5; |
|
|
|
double g = 0.5 * sin(f * 0.13 + 1.0) + 0.5; |
|
|
|
double b = 0.5 * sin(f * 0.21) + 0.5; |
|
|
|
|
|
|
|
uint8_t red = r * 255.0f; |
|
|
|
uint8_t green = g * 255.0f; |
|
|
|
uint8_t blue = b * 255.0f; |
|
|
|
*m_pixelstart++ = u8vec4(red, green, blue, 0); |
|
|
|
} |
|
|
|
else |
|
|
|
m_dirty--; |
|
|
|
|
|
|
|
for (int j = ((m_frame + 1) % 4) / 2; j < m_size.y; j += 2) |
|
|
|
for (int i = m_frame % 2; i < m_size.x; i += 2) |
|
|
|
{ |
|
|
|
*m_pixelstart++ = u8vec4(0, 0, 0, 0); |
|
|
|
double const maxlen = 32; |
|
|
|
int const maxiter = 170; |
|
|
|
|
|
|
|
f64cmplx z0 = m_center + ScreenToWorldOffset(ivec2(i, j)); |
|
|
|
f64cmplx r0 = z0; |
|
|
|
//f64cmplx r0(0.28693186889504513, 0.014286693904085048); |
|
|
|
//f64cmplx r0(0.001643721971153, 0.822467633298876); |
|
|
|
f64cmplx z; |
|
|
|
int iter = maxiter; |
|
|
|
for (z = z0; iter && z.sqlen() < maxlen * maxlen; z = z * z + r0) |
|
|
|
--iter; |
|
|
|
|
|
|
|
double f = iter; |
|
|
|
double n = z.sqlen(); |
|
|
|
|
|
|
|
double k = log(n) * 0.5f / log(maxlen); |
|
|
|
/* Approximate log2(k) in [1,2]. */ |
|
|
|
f += (- 0.344847817623168308695977510213252644185 * k |
|
|
|
+ 2.024664188044341212602376988171727038739) * k |
|
|
|
- 1.674876738008591047163498125918330313237; |
|
|
|
|
|
|
|
if (iter) |
|
|
|
{ |
|
|
|
double r = 0.5 * sin(f * 0.27 - 1.5) + 0.5; |
|
|
|
double g = 0.5 * sin(f * 0.13 + 1.3) + 0.5; |
|
|
|
double b = 0.5 * sin(f * 0.21 + 0.4) + 0.5; |
|
|
|
|
|
|
|
uint8_t red = r * 255.0f; |
|
|
|
uint8_t green = g * 255.0f; |
|
|
|
uint8_t blue = b * 255.0f; |
|
|
|
*m_pixelstart++ = u8vec4(red, green, blue, 0); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
*m_pixelstart++ = u8vec4(0, 0, 0, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@@ -130,12 +169,12 @@ public: |
|
|
|
|
|
|
|
static float const texcoords[] = |
|
|
|
{ |
|
|
|
1.0f, 0.0f, |
|
|
|
0.0f, 0.0f, |
|
|
|
0.0f, 1.0f, |
|
|
|
0.0f, 1.0f, |
|
|
|
1.0f, 1.0f, |
|
|
|
0.0f, 1.0f, |
|
|
|
0.0f, 0.0f, |
|
|
|
0.0f, 0.0f, |
|
|
|
1.0f, 0.0f, |
|
|
|
1.0f, 1.0f, |
|
|
|
}; |
|
|
|
|
|
|
|
if (!m_ready) |
|
|
@@ -166,9 +205,11 @@ public: |
|
|
|
/* gl_FragCoord is centered inside the pixel, so we remove |
|
|
|
* 0.5 from gl_FragCoord.x. Also, (0,0) is at the bottom |
|
|
|
* left whereas our images have (0,0) at the top left, so we |
|
|
|
* _add_ 0.5 to gl_FragCoord.y. */ |
|
|
|
* _add_ 0.5 to gl_FragCoord.y. (XXX: this is no longer true |
|
|
|
* but will be again when mouse coordinates are back to |
|
|
|
* being top-left again). */ |
|
|
|
" float i = mod(gl_FragCoord.x - 0.5, 2.0);" |
|
|
|
" float j = mod(gl_FragCoord.y + 0.5 + i, 2.0);" |
|
|
|
" float j = mod(gl_FragCoord.y - 0.5 + i, 2.0);" |
|
|
|
" coord.y += i + j * 2;" |
|
|
|
" coord.y *= 0.25;" |
|
|
|
" vec4 p = texture2D(in_Texture, coord);" |
|
|
@@ -216,15 +257,21 @@ public: |
|
|
|
|
|
|
|
glEnable(GL_TEXTURE_2D); |
|
|
|
glBindTexture(GL_TEXTURE_2D, m_texid); |
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, |
|
|
|
0, m_frame * m_size.y / 2, m_size.x / 2, m_size.y / 2, |
|
|
|
|
|
|
|
if (m_dirty) |
|
|
|
{ |
|
|
|
m_dirty--; |
|
|
|
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, m_frame * m_size.y / 2, |
|
|
|
m_size.x / 2, m_size.y / 2, |
|
|
|
#if !defined __CELLOS_LV2__ |
|
|
|
GL_RGBA, GL_UNSIGNED_BYTE, |
|
|
|
GL_RGBA, GL_UNSIGNED_BYTE, |
|
|
|
#else |
|
|
|
/* The PS3 is big-endian */ |
|
|
|
GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, |
|
|
|
/* The PS3 is big-endian */ |
|
|
|
GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, |
|
|
|
#endif |
|
|
|
m_pixels + m_size.x * m_size.y / 4 * m_frame); |
|
|
|
m_pixels + m_size.x * m_size.y / 4 * m_frame); |
|
|
|
} |
|
|
|
|
|
|
|
m_shader->Bind(); |
|
|
|
#if !defined __CELLOS_LV2__ && !defined __ANDROID__ && !defined __APPLE__ |
|
|
@@ -272,11 +319,14 @@ private: |
|
|
|
GLuint m_tco; |
|
|
|
#endif |
|
|
|
int m_vertexattrib, m_texattrib; |
|
|
|
int m_frame; |
|
|
|
int m_frame, m_dirty; |
|
|
|
bool m_ready; |
|
|
|
|
|
|
|
f64cmplx m_center, m_target; |
|
|
|
double m_radius, m_angle; |
|
|
|
f64cmplx m_center; |
|
|
|
double m_radius, m_screenradius; |
|
|
|
|
|
|
|
/* Debug information */ |
|
|
|
Text *m_centertext, *m_mousetext; |
|
|
|
}; |
|
|
|
|
|
|
|
int main() |
|
|
|