home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Hacks / Hacks '96 / Sharks' Spark Hack / DesktopView.cpp next >
Encoding:
C/C++ Source or Header  |  1996-06-21  |  6.8 KB  |  289 lines  |  [TEXT/MMCC]

  1. #ifndef DESK_VIEW_H
  2. #include "DesktopView.h"
  3. #endif
  4. #include <stdio.h>
  5. #include "Sparks.h"
  6.  
  7. // The high-speed timer thread.
  8. long MyThread( void * );
  9.  
  10. // Used to kill the nasty thread when the program exits
  11. thread_id ThreadId;
  12.  
  13. // An arbitrary number of sparks.
  14. const int kSparkCount = 500;
  15.  
  16. // Artificial gravity strength
  17. const float kNormalGravity = 1.3;                // Sparks fall over time
  18. const float kNoGravity = 0.0;                    // Sparks go straight out
  19. const float kNegativeGravity = -1.3;            // Sparks float up 
  20.  
  21. // How long should the little buggers live?
  22. const int kLifeLength = 25;
  23.  
  24. // Are they wide and fast? ( SCSI? )
  25. const float kMaximumHorizontal = 15.0;
  26. const float kMaximumVertical   = 15.0;
  27.  
  28. // How often should the drawing function be called?
  29. const int kTimeTwixtCalls    = 75;
  30.  
  31. // Scale the pixel toss.
  32. const float kScalingFactor = 0.30;
  33.  
  34. // Used to send messages from the timer thread to the view.
  35. static DesktopView *pView = NULL;
  36.  
  37. DesktopView::DesktopView(BRect rect, char *name)
  38.               : BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW )
  39. {
  40.     m_pBitmap = NULL;
  41.     m_pView   = NULL;
  42.     m_ScreenRect = Bounds();
  43.  
  44.     m_pSparks = new BSpark[ kSparkCount ];
  45.  
  46.     // Kill those pesky sparks.
  47.     for( int Loop = 0; Loop < kSparkCount; Loop++ )
  48.         m_pSparks[ Loop ].Life = -1;
  49.  
  50.     // Default to normal mode
  51.     m_bMissionMode = FALSE;
  52.     m_Gravity = kNormalGravity;
  53.         
  54.     // Keep a black handy for erasing the sparks.
  55.     rgb_color Black;
  56.     
  57.     Black.red   = 0x00;
  58.     Black.blue  = 0x00;
  59.     Black.green = 0x00;
  60.     m_Black = index_for_color( Black );
  61. }
  62.  
  63. DesktopView::~DesktopView()
  64. {
  65.     kill_thread( ThreadId );
  66.     
  67.     if( m_pSparks )
  68.         delete[] m_pSparks;
  69. }
  70.  
  71. void DesktopView::AttachedToWindow()
  72. {
  73.     srand( ( int ) __get_time() );
  74.  
  75.     m_pBitmap = new BBitmap( m_ScreenRect, B_COLOR_8_BIT, TRUE );
  76.     m_pView   = new BView( m_ScreenRect, "", 0, B_WILL_DRAW );
  77.     
  78.     m_pBitmap->Lock();
  79.     m_pBitmap->AddChild( m_pView );
  80.  
  81.     // Erase the screen to black first.
  82.     m_pView->SetHighColor( 0, 0, 0, 0 );
  83.     m_pView->FillRect( m_ScreenRect );
  84.     DrawBitmap( m_pBitmap, BPoint( 0, 0 ) );
  85.         
  86.     // draw it
  87.     DrawOffscreen();
  88.  
  89.     m_pBitmap->Unlock();
  90.     
  91.     // We need to use this to call from the timer thread to this view
  92.     pView = this;
  93.  
  94.     // We're gonna need an original mouse position.
  95.     ulong TrashPoint;
  96.     GetMouse( &m_OldMouse, &TrashPoint );
  97.     
  98.     ThreadId = spawn_thread( MyThread, "Timer Thread", B_DISPLAY_PRIORITY, NULL );
  99.     resume_thread( ThreadId );
  100. }
  101.  
  102. void    DesktopView::Plot(long x, long y, char c)
  103. {
  104.     char    *p;
  105.     long    rowbyte;
  106.         
  107.     rowbyte = m_pBitmap->BytesPerRow();
  108.  
  109.     p = ( char * )m_pBitmap->Bits();
  110.     if( y >= m_ScreenRect.top && x >= m_ScreenRect.left && x <= m_ScreenRect.right && y <= m_ScreenRect.bottom  )
  111.     {
  112.         p += (y*rowbyte + x);
  113.        *p = c;
  114.     }    
  115. }
  116.  
  117. void DesktopView::Draw(BRect /*updateRect*/)
  118. {
  119.     Window()->Lock();
  120.     DrawBitmap(m_pBitmap, BPoint(0,0));
  121.     Window()->Unlock();
  122. }
  123.  
  124.  
  125. void DesktopView::DrawOffscreen( )
  126. {
  127.  
  128.     Window()->Lock();
  129.  
  130.     m_pBitmap->Lock();
  131.     
  132.     // Used to find the bounding rectange of the sparks.
  133.     int   MinX = 16384;
  134.     int   MaxX = -1;
  135.     int   MinY = 16384;
  136.     int   MaxY = -1;
  137.       
  138.     int   Loop;
  139.     BPoint    Point;
  140.     ulong     Button;
  141.     
  142.     GetMouse( &Point, &Button );
  143.  
  144.     if( m_bMissionMode )
  145.     {
  146.         Plot( m_MissionX,     m_MissionY,     m_Black );
  147.         Plot( m_MissionX + 1, m_MissionY,     m_Black );
  148.         Plot( m_MissionX,     m_MissionY + 1, m_Black );
  149.         Plot( m_MissionX + 1, m_MissionY + 1, m_Black );
  150.             
  151.         m_MissionX++;
  152.         
  153.         if( m_MissionX >= m_ScreenRect.right )
  154.         {
  155.             m_bMissionMode = FALSE;
  156.             m_Gravity = kNormalGravity;
  157.         }
  158.     }
  159.  
  160.     for( Loop = 0; Loop < kSparkCount; Loop++ )
  161.     {
  162.         // Check the bounding box....
  163.         if( m_pSparks[ Loop ].x < MinX )
  164.             MinX = m_pSparks[ Loop ].x;
  165.         if( m_pSparks[ Loop ].x > MaxX )
  166.             MaxX = m_pSparks[ Loop ].x;
  167.         if( m_pSparks[ Loop ].y < MinY )
  168.             MinY = m_pSparks[ Loop ].y;
  169.         if( m_pSparks[ Loop ].y > MaxY )
  170.             MaxY = m_pSparks[ Loop ].y;
  171.  
  172.         if( m_pSparks[ Loop ].Life > 0 )    // If the spark is currently alive, move it.....
  173.         {
  174.             // One day closer to death.
  175.             m_pSparks[ Loop ].Life--;    
  176.             
  177.             // Erase the previous dot
  178.              Plot( m_pSparks[ Loop ].x, m_pSparks[ Loop ].y, m_Black );
  179.  
  180.             // Watch as the amazing gravity pulls upon our partical.
  181.             m_pSparks[ Loop ].VerticalSpeed += m_Gravity;                                        
  182.  
  183. //    Uncomment this to cause the sparks to bounce upon reaching the bottom of the screen.
  184. //            if (m_pSparks[Loop].y + m_pSparks[Loop].VerticalSpeed > m_ScreenRect.bottom)
  185. //                m_pSparks[Loop].VerticalSpeed = -m_pSparks[Loop].VerticalSpeed;
  186.  
  187.             // Update the sparks' position.
  188.             m_pSparks[ Loop ].x += m_pSparks[ Loop ].HorizontalSpeed;
  189.             m_pSparks[ Loop ].y += m_pSparks[ Loop ].VerticalSpeed;
  190.  
  191.             // Let's see it.
  192.             Plot( m_pSparks[ Loop ].x, m_pSparks[ Loop ].y, m_pSparks[ Loop ].Color );
  193.         }
  194.         else                        // otherwise create a new one.
  195.         {
  196.             // Erase the last living incarnation of the spark
  197.              Plot( m_pSparks[ Loop ].x, m_pSparks[ Loop ].y, m_Black );
  198.     
  199.             if( !m_bMissionMode )
  200.             {
  201.                 // The cursor is my guide....
  202.                 m_pSparks[ Loop ].x = Point.x;
  203.                 m_pSparks[ Loop ].y = Point.y;
  204.             }
  205.             else
  206.             {
  207.                 m_pSparks[ Loop ].x = m_MissionX;
  208.                 m_pSparks[ Loop ].y = m_MissionY;
  209.             }
  210.                         
  211.             // Gimme some random values to move this bad-boy along.
  212.             m_pSparks[ Loop ].HorizontalSpeed = (rand()/32767.0)*kMaximumHorizontal-( kMaximumHorizontal/2.0 );
  213.             m_pSparks[ Loop ].VerticalSpeed = -fabs( rand()/32768.0*kMaximumVertical );
  214.             
  215.             // Add the inertia factor...
  216.             m_pSparks[ Loop ].HorizontalSpeed -= ( ( m_OldMouse.x - Point.x ) * kScalingFactor );
  217.             m_pSparks[ Loop ].VerticalSpeed -= ( ( m_OldMouse.y - Point.y ) * kScalingFactor );
  218.  
  219.             m_pSparks[ Loop ].Life = abs( rand() % kLifeLength );
  220.             m_pSparks[ Loop ].Color = rand() % 0xFF;
  221.             
  222.         }    
  223.     }
  224.     
  225.     m_pBitmap->Unlock();
  226.  
  227.     m_OldMouse = Point;
  228.     
  229.     // We only need to blit the maximum area changed,
  230.     // with a generous fudge factor ( naturally ).
  231.     m_BoundingRect.left = MinX - 2;
  232.     m_BoundingRect.right = MaxX + 2;
  233.     m_BoundingRect.top = MinY - 2;
  234.     m_BoundingRect.bottom = MaxY + 2;
  235.     
  236.     DrawBitmap(m_pBitmap, m_BoundingRect, m_BoundingRect );
  237.     Window()->Unlock();
  238. }
  239.  
  240. void DesktopView::MouseDown( BPoint )
  241. {
  242.     // Don't try it if we are already in "Impossible" mode.
  243.     if( m_bMissionMode )
  244.         return;
  245.     
  246.     BRect  Rect;
  247.                 
  248.     m_bMissionMode = TRUE;
  249.     m_Gravity = kNoGravity;
  250.     
  251.     Window()->Lock();
  252.     m_pBitmap->Lock();
  253.     
  254.     m_MissionX = m_ScreenRect.left;
  255.     m_MissionY = ( m_ScreenRect.bottom - m_ScreenRect.top ) / 2.0;        // Center the fuse
  256.     
  257.     // Erase all the old sparks before starting the fuse.
  258.     m_pView->SetHighColor( 0, 0, 0, 0 );
  259.     m_pView->FillRect( m_BoundingRect );
  260.     
  261.     m_pView->SetHighColor( 0xff, 0xff, 0xff );
  262.     Rect.left = m_ScreenRect.left;
  263.     Rect.top = m_MissionY;
  264.     Rect.right = m_ScreenRect.right;
  265.     Rect.bottom = m_MissionY;
  266.     m_pView->FillRect( Rect );
  267.                 
  268.     m_pView->Sync();
  269.     m_pBitmap->Unlock();
  270.     
  271.     DrawBitmap( m_pBitmap, Rect, Rect );
  272.     
  273.     Window()->Unlock();    
  274.     
  275. }
  276.  
  277. long MyThread( void * )
  278. {
  279.     int Delay = 0;
  280.     
  281.     while( 1 )
  282.     {
  283.         snooze(20*1000.0);
  284.         pView->DrawOffscreen();
  285.     }
  286.  
  287.     return 0;
  288. }
  289.