1 //============================================================================
2 //
3 //   SSSS    tt          lll  lll
4 //  SS  SS   tt           ll   ll
5 //  SS     tttttt  eeee   ll   ll   aaaa
6 //   SSSS    tt   ee  ee  ll   ll      aa
7 //      SS   tt   eeeeee  ll   ll   aaaaa  --  "An Atari 2600 VCS Emulator"
8 //  SS  SS   tt   ee      ll   ll  aa  aa
9 //   SSSS     ttt  eeeee llll llll  aaaaa
10 //
11 // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony
12 // and the Stella Team
13 //
14 // See the file "License.txt" for information on usage and redistribution of
15 // this file, and for a DISCLAIMER OF ALL WARRANTIES.
16 //
17 // $Id: TrackBall.cxx 2838 2014-01-17 23:34:03Z stephena $
18 //============================================================================
19 
20 #include <cstdlib>
21 
22 #include "Event.hxx"
23 #include "System.hxx"
24 #include "TIA.hxx"
25 #include "TrackBall.hxx"
26 
27 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TrackBall(Jack jack,const Event & event,const System & system,Type type)28 TrackBall::TrackBall(Jack jack, const Event& event, const System& system,
29                      Type type)
30   : Controller(jack, event, system, type),
31     myHCounter(0),
32     myVCounter(0),
33     myMouseEnabled(false)
34 {
35   // This code in ::read() is set up to always return IOPortA values in
36   // the lower 4 bits data value
37   // As such, the jack type (left or right) isn't necessary here
38 
39   myTrakBallCountH = myTrakBallCountV = 0;
40   myTrakBallLinesH = myTrakBallLinesV = 1;
41 
42   myTrakBallLeft = myTrakBallDown = myScanCountV = myScanCountH =
43     myCountV = myCountH = 0;
44 
45   // Analog pins are never used by the trackball controller
46   myAnalogPinValue[Five] = myAnalogPinValue[Nine] = maximumResistance;
47 }
48 
49 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
~TrackBall()50 TrackBall::~TrackBall()
51 {
52 }
53 
54 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
read()55 uInt8 TrackBall::read()
56 {
57   int scanline = ((System&)mySystem).tia().scanlines();
58 
59   if(myScanCountV > scanline) myScanCountV = 0;
60   if(myScanCountH > scanline) myScanCountH = 0;
61   while((myScanCountV + myTrakBallLinesV) < scanline)
62   {
63     if(myTrakBallCountV)
64     {
65       if(myTrakBallDown) myCountV--;
66       else               myCountV++;
67       myTrakBallCountV--;
68     }
69     myScanCountV += myTrakBallLinesV;
70   }
71 
72   while((myScanCountH + myTrakBallLinesH) < scanline)
73   {
74     if(myTrakBallCountH)
75     {
76       if(myTrakBallLeft) myCountH--;
77       else               myCountH++;
78       myTrakBallCountH--;
79     }
80     myScanCountH += myTrakBallLinesH;
81   }
82 
83   myCountV &= 0x03;
84   myCountH &= 0x03;
85 
86   uInt8 IOPortA = 0x00;
87   switch(myType)
88   {
89     case Controller::TrackBall80:
90       IOPortA = IOPortA
91           | ourTrakBallTableST_V[myCountV]
92           | ourTrakBallTableST_H[myCountH];
93       break;
94     case Controller::TrackBall22:
95       IOPortA = IOPortA
96           | ourTrakBallTableTB_V[myCountV & 0x01][myTrakBallDown]
97           | ourTrakBallTableTB_H[myCountH & 0x01][myTrakBallLeft];
98       break;
99     case Controller::AmigaMouse:
100       IOPortA = IOPortA
101           | ourTrakBallTableAM_V[myCountV]
102           | ourTrakBallTableAM_H[myCountH];
103       break;
104     default:
105       break;
106   }
107 
108   myDigitalPinState[One]   = IOPortA & 0x10;
109   myDigitalPinState[Two]   = IOPortA & 0x20;
110   myDigitalPinState[Three] = IOPortA & 0x40;
111   myDigitalPinState[Four]  = IOPortA & 0x80;
112 
113   return (IOPortA >> 4);
114 }
115 
116 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
update()117 void TrackBall::update()
118 {
119   if(!myMouseEnabled)
120     return;
121 
122   // Get the current mouse position
123   myHCounter = myEvent.get(Event::MouseAxisXValue);
124   myVCounter = myEvent.get(Event::MouseAxisYValue);
125 
126   if(myVCounter < 0) myTrakBallLeft = 1;
127   else               myTrakBallLeft = 0;
128   if(myHCounter < 0) myTrakBallDown = 0;
129   else               myTrakBallDown = 1;
130   myTrakBallCountH = abs(myVCounter >> 1);
131   myTrakBallCountV = abs(myHCounter >> 1);
132   myTrakBallLinesH = 200 /*LinesInFrame*/ / (myTrakBallCountH + 1);
133   if(myTrakBallLinesH == 0) myTrakBallLinesH = 1;
134   myTrakBallLinesV = 200 /*LinesInFrame*/ / (myTrakBallCountV + 1);
135   if(myTrakBallLinesV == 0) myTrakBallLinesV = 1;
136 
137   // Get mouse button state
138   myDigitalPinState[Six] = (myEvent.get(Event::MouseButtonLeftValue) == 0) &&
139                            (myEvent.get(Event::MouseButtonRightValue) == 0);
140 }
141 
142 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
setMouseControl(Controller::Type xtype,int xid,Controller::Type ytype,int yid)143 bool TrackBall::setMouseControl(
144     Controller::Type xtype, int xid, Controller::Type ytype, int yid)
145 {
146   // Currently, the various trackball controllers take full control of the
147   // mouse, and use both mouse buttons for the single fire button
148   // As well, there's no separate setting for x and y axis, so any
149   // combination of Controller and id is valid
150   myMouseEnabled = (xtype == myType || ytype == myType) &&
151                    (xid != -1 || yid != -1);
152   return true;
153 }
154 
155 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
156 const uInt32 TrackBall::ourTrakBallTableTB_H[2][2] = {
157   { 0x40, 0x00 }, { 0xc0, 0x80 }
158 };
159 
160 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
161 const uInt32 TrackBall::ourTrakBallTableTB_V[2][2] = {
162   { 0x00, 0x10 }, { 0x20, 0x30 }
163 };
164 
165 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
166 const uInt32 TrackBall::ourTrakBallTableST_H[4] = {
167   0x00, 0x80, 0xc0, 0x40
168 };
169 
170 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
171 const uInt32 TrackBall::ourTrakBallTableST_V[4] = {
172   0x00, 0x10, 0x30, 0x20
173 };
174 
175 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
176 const uInt32 TrackBall::ourTrakBallTableAM_H[4] = {
177   0x00, 0x10, 0x50, 0x40
178 };
179 
180 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
181 const uInt32 TrackBall::ourTrakBallTableAM_V[4] = {
182   0x00, 0x80, 0xa0, 0x20
183 };
184