starry_night_sky.cpp 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // based on: https://www.khanacademy.org/computer-programming/starry-night-sky-o_o/1545831539
  2. #include "common/sketchbook.hpp"
  3. int stars = 100;
  4. float hstart = 300.f; // left edge mountain height
  5. float hend = 300.f; // right edge mountain height
  6. float h = 1; //mountain roughness
  7. float r = 100; //mountain random range
  8. float moon_radius = 50;
  9. float2 moon_area = float2(1.f, 0.5f);
  10. rgb skyColorFrom (rgb24(0_u8, 0_u8, 51_u8)),
  11. skyColorTo (rgb24(51_u8, 51_u8, 51_u8));
  12. bool request_draw = false;
  13. void start(Program& program)
  14. {
  15. program.frametime = framerate<60>::frametime;
  16. if(program.argc > 2)
  17. {
  18. using support::ston;
  19. using seed_t = decltype(tiny_rand());
  20. tiny_rand.seed({ ston<seed_t>(program.argv[1]), ston<seed_t>(program.argv[2]) });
  21. }
  22. program.key_up = [&](scancode code, keycode)
  23. {
  24. switch(code)
  25. {
  26. case scancode::leftbracket:
  27. case scancode::c:
  28. if(pressed(scancode::rctrl) || pressed(scancode::lctrl))
  29. case scancode::escape:
  30. program.end();
  31. break;
  32. case scancode::space:
  33. request_draw = true;
  34. break;
  35. default: break;
  36. }
  37. };
  38. program.draw_loop = [&](auto frame, auto)
  39. {
  40. if(request_draw)
  41. {
  42. program.draw_once(std::move(frame));
  43. request_draw = false;
  44. }
  45. };
  46. program.draw_once = [](auto frame)
  47. {
  48. std::cout << "seed: " << std::hex << std::showbase << tiny_rand << '\n';
  49. frame.begin_sketch()
  50. .rectangle(rect{frame.size})
  51. .fill(rgb::white(0))
  52. ;
  53. //sky
  54. // TODO: use nanovg gradient
  55. for(float i = 0.f; i < frame.size.y(); ++i)
  56. {
  57. frame.begin_sketch()
  58. .line_width(2)
  59. .line({0.f,i},{frame.size.x(),i})
  60. .outline(lerp(skyColorFrom,skyColorTo,i/frame.size.y()))
  61. ;
  62. }
  63. //moon
  64. frame.begin_sketch()
  65. .ellipse(rect{float2::one(moon_radius), trand_float2() * moon_area * frame.size, float2::one(0.5f)})
  66. .fill(rgb::white());
  67. ;
  68. //stars
  69. for(int i=0; i < stars; ++i)
  70. {
  71. // TODO: find a better way to approximate points/stars of various sizes
  72. frame.begin_sketch()
  73. .rectangle(rect{
  74. trand_int({0,3}) * float2::one(),
  75. round(trand_float2() * frame.size)
  76. })
  77. .fill(rgb::white());
  78. }
  79. // generate mountains
  80. std::vector peaks = {hstart, hend};
  81. auto rng = r;
  82. while(peaks.size() < frame.size.x() + 113)
  83. {
  84. for(size_t i = 0; i < peaks.size(); i += 2)
  85. {
  86. const float variation = trand_float({-1.f, 1.f}) * rng;
  87. const float height = (peaks[i] + peaks[i+1])/2 + variation;
  88. peaks.insert(peaks.begin() + i + 1, height);
  89. }
  90. rng = rng * std::pow(2,-h);
  91. }
  92. // draw mountains
  93. { auto mountain_sketch = frame.begin_sketch();
  94. for(size_t i = 0; i < frame.size.x(); ++i)
  95. mountain_sketch.line(
  96. {float(i), peaks[i]},
  97. {float(i), frame.size.y()} );
  98. mountain_sketch
  99. .line_width(2)
  100. .outline(rgb::white(0));
  101. ;
  102. }
  103. };
  104. }