Original 1.0.5 code

(as received from Jonas Echterhoff)
This commit is contained in:
maride 2016-04-02 14:43:55 +02:00
commit 02061d74c2
136 changed files with 39576 additions and 0 deletions

Binary file not shown.

245
HID_cookie_strings.plist Executable file
View File

@ -0,0 +1,245 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>1035</key>
<dict>
<key>25907</key>
<dict>
<key>3</key>
<string>Left Button</string>
<key>4</key>
<string>Right Button</string>
<key>5</key>
<string>Small Left Button</string>
<key>6</key>
<string>Small Right Button</string>
<key>7</key>
<string>X-Axis</string>
<key>8</key>
<string>Y-Axis</string>
<key>Name</key>
<string>Competition Pro</string>
</dict>
<key>Name</key>
<string>MOSIC</string>
</dict>
<key>1118</key>
<dict>
<key>27</key>
<dict>
<key>27</key>
<string>Button 1 [Trigger]</string>
<key>28</key>
<string>Button 2</string>
<key>29</key>
<string>Button 3</string>
<key>30</key>
<string>Button 4</string>
<key>31</key>
<string>Button 5</string>
<key>32</key>
<string>Button 6</string>
<key>33</key>
<string>Button 7</string>
<key>34</key>
<string>Button 8</string>
<key>89</key>
<string>X-Axis</string>
<key>90</key>
<string>Y-Axis</string>
<key>91</key>
<string>Rz-Axis</string>
<key>92</key>
<string>Throttle</string>
<key>93</key>
<string>Hat Switch</string>
<key>Name</key>
<string>SideWinder FFB 2 Joystick</string>
</dict>
<key>Name</key>
<string>Microsoft</string>
</dict>
<key>1133</key>
<dict>
<key>49797</key>
<dict>
<key>10</key>
<string>Button 6</string>
<key>11</key>
<string>Button 7</string>
<key>16</key>
<string>Hat Switch 2</string>
<key>24</key>
<string>X-Axis</string>
<key>25</key>
<string>Y-Axis</string>
<key>26</key>
<string>Hat Switch 1</string>
<key>27</key>
<string>Rz-Axis</string>
<key>28</key>
<string>Throttle</string>
<key>29</key>
<string>Button 9</string>
<key>30</key>
<string>Button 8</string>
<key>5</key>
<string>Button 1 [Trigger]</string>
<key>6</key>
<string>Button 2</string>
<key>7</key>
<string>Button 3</string>
<key>8</key>
<string>Button 4</string>
<key>9</key>
<string>Button 5</string>
<key>Name</key>
<string>WingMan Strike Force 3D</string>
</dict>
<key>Name</key>
<string>Logitech</string>
</dict>
<key>1635</key>
<dict>
<key>38916</key>
<dict>
<key>10</key>
<string>R2 Trigger</string>
<key>11</key>
<string>Right Stick X-Axis</string>
<key>12</key>
<string>Right Stick Y-Axis</string>
<key>13</key>
<string>Left Stick X-Axis</string>
<key>14</key>
<string>Left Stick Y-Axis</string>
<key>15</key>
<string>Hat Switch</string>
<key>3</key>
<string>Button 1</string>
<key>4</key>
<string>Button 2</string>
<key>5</key>
<string>Button 3</string>
<key>6</key>
<string>Button 4</string>
<key>7</key>
<string>L1 Trigger</string>
<key>8</key>
<string>R1 Trigger</string>
<key>9</key>
<string>L2 Trigger</string>
<key>Name</key>
<string>FunPad F-107</string>
</dict>
<key>Name</key>
<string>Macsense</string>
</dict>
<key>8738</key>
<dict>
<key>16400</key>
<dict>
<key>10</key>
<string>Left Button</string>
<key>11</key>
<string>C Button</string>
<key>12</key>
<string>B Button [Select]</string>
<key>13</key>
<string>A Button [Start]</string>
<key>14</key>
<string>F Button</string>
<key>15</key>
<string>R1 Trigger</string>
<key>16</key>
<string>R2 Trigger</string>
<key>17</key>
<string>L1 Trigger</string>
<key>18</key>
<string>L2 Trigger</string>
<key>19</key>
<string>Left Stick Button</string>
<key>20</key>
<string>Right Stick Button</string>
<key>21</key>
<string>D Button</string>
<key>22</key>
<string>E Button</string>
<key>23</key>
<string>Left Stick X-Axis</string>
<key>24</key>
<string>Left Stick Y-Axis</string>
<key>25</key>
<string>Right Stick X-Axis</string>
<key>26</key>
<string>Right Stick Y-Axis</string>
<key>3</key>
<string>D-Pad Up</string>
<key>4</key>
<string>D-Pad Down</string>
<key>5</key>
<string>D-Pad Left</string>
<key>6</key>
<string>D-Pad Right</string>
<key>7</key>
<string>Up Button</string>
<key>8</key>
<string>Right Button</string>
<key>9</key>
<string>Down Button</string>
<key>Name</key>
<string>iShock</string>
</dict>
<key>16416</key>
<dict>
<key>10</key>
<string>D Button</string>
<key>11</key>
<string>Button 1</string>
<key>12</key>
<string>Button 2 [Select]</string>
<key>13</key>
<string>Button 3 [Start]</string>
<key>14</key>
<string>R1 Button</string>
<key>15</key>
<string>R2 Trigger</string>
<key>16</key>
<string>L1 Trigger</string>
<key>17</key>
<string>L2 Trigger</string>
<key>18</key>
<string>Left Stick Button</string>
<key>19</key>
<string>Right Stick Button</string>
<key>20</key>
<string>Left Stick X-Axis</string>
<key>21</key>
<string>Left Stick Y-Axis</string>
<key>22</key>
<string>Right Stick X-Axis</string>
<key>23</key>
<string>Right Stick Y-Axis</string>
<key>3</key>
<string>D-Pad Up</string>
<key>4</key>
<string>D-Pad Down</string>
<key>5</key>
<string>D-Pad Left</string>
<key>6</key>
<string>D-Pad Right</string>
<key>7</key>
<string>A Button</string>
<key>8</key>
<string>B Button</string>
<key>9</key>
<string>C Button</string>
<key>Name</key>
<string>iShock II</string>
</dict>
<key>Name</key>
<string>Macally</string>
</dict>
</dict>
</plist>

633
HID_device_usage_strings.plist Executable file
View File

@ -0,0 +1,633 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>1118</key>
<dict>
<key>26</key>
<dict>
<key>1:48</key>
<string>Wheel</string>
<key>1:49</key>
<string>Left Pedal [Brake]</string>
<key>1:50</key>
<string>Right Pedal [Gas]</string>
<key>9:1</key>
<string>Button A</string>
<key>9:2</key>
<string>Button B</string>
<key>9:3</key>
<string>Button C</string>
<key>9:4</key>
<string>Button X</string>
<key>9:5</key>
<string>Button Y</string>
<key>9:6</key>
<string>Button Z</string>
<key>9:7</key>
<string>Left Trigger</string>
<key>9:8</key>
<string>Right Trigger</string>
<key>Name</key>
<string>SideWinder Precision Racing Wheel USB v1.0</string>
</dict>
<key>27</key>
<dict>
<key>1:48</key>
<string>X-Axis</string>
<key>1:49</key>
<string>Y-Axis</string>
<key>1:53</key>
<string>Rz-Axis</string>
<key>1:54</key>
<string>Throttle</string>
<key>1:57</key>
<string>Hat Switch</string>
<key>9:1</key>
<string>Button 1 [Trigger]</string>
<key>9:2</key>
<string>Button 2</string>
<key>9:3</key>
<string>Button 3</string>
<key>9:4</key>
<string>Button 4</string>
<key>9:5</key>
<string>Button 5</string>
<key>9:6</key>
<string>Button 6</string>
<key>9:7</key>
<string>Button 7</string>
<key>9:8</key>
<string>Button 8</string>
<key>Name</key>
<string>SideWinder FFB 2 Joystick</string>
</dict>
<key>39</key>
<dict>
<key>1:48</key>
<string>X-Axis</string>
<key>1:49</key>
<string>Y-Axis</string>
<key>9:1</key>
<string>Button 1</string>
<key>9:2</key>
<string>Button 2</string>
<key>9:3</key>
<string>Button 3</string>
<key>9:4</key>
<string>Button 4</string>
<key>9:5</key>
<string>Button 5</string>
<key>9:6</key>
<string>Button 6</string>
<key>Name</key>
<string>SideWinder Plug and Play Game Pad</string>
</dict>
<key>56</key>
<dict>
<key>1:48</key>
<string>X-Axis</string>
<key>1:49</key>
<string>Y-Axis</string>
<key>1:53</key>
<string>Rz-Axis</string>
<key>1:54</key>
<string>Throttle</string>
<key>1:57</key>
<string>Hat Switch</string>
<key>9:1</key>
<string>Button 1 [Trigger]</string>
<key>9:2</key>
<string>Button 2</string>
<key>9:3</key>
<string>Button 3</string>
<key>9:4</key>
<string>Button 4</string>
<key>9:5</key>
<string>Button 5</string>
<key>9:6</key>
<string>Button 6</string>
<key>9:7</key>
<string>Button 7</string>
<key>9:8</key>
<string>Button 8</string>
<key>Name</key>
<string>SideWinder Precision 2 Joystick</string>
</dict>
<key>60</key>
<dict>
<key>1:48</key>
<string>X-Axis</string>
<key>1:49</key>
<string>Y-Axis</string>
<key>1:54</key>
<string>Throttle</string>
<key>9:1</key>
<string>Button 1 [Trigger]</string>
<key>9:2</key>
<string>Button 2</string>
<key>9:3</key>
<string>Button 3</string>
<key>9:4</key>
<string>Button 4</string>
<key>9:5</key>
<string>Button 5</string>
<key>9:6</key>
<string>Button 6</string>
<key>9:7</key>
<string>Button 7</string>
<key>9:8</key>
<string>Button 8</string>
<key>Name</key>
<string>SideWinder Joystick</string>
</dict>
<key>7</key>
<dict>
<key>1:48</key>
<string>X-Axis</string>
<key>1:49</key>
<string>Y-Axis</string>
<key>9:1</key>
<string>Button A</string>
<key>9:10</key>
<string>Secondary Option 1</string>
<key>9:2</key>
<string>Button B</string>
<key>9:3</key>
<string>Button C</string>
<key>9:4</key>
<string>Button X</string>
<key>9:5</key>
<string>Button Y</string>
<key>9:6</key>
<string>Button Z</string>
<key>9:7</key>
<string>Left Trigger</string>
<key>9:8</key>
<string>Right Trigger</string>
<key>9:9</key>
<string>Secondary Option 2</string>
<key>Name</key>
<string>SideWinder Game Pad USB</string>
</dict>
<key>Name</key>
<string>Microsoft</string>
</dict>
<key>1133</key>
<dict>
<key>49200</key>
<dict>
<key>1:1</key>
<string>Pointer</string>
<key>1:2</key>
<string>Mouse</string>
<key>1:48</key>
<string>X-Axis</string>
<key>1:49</key>
<string>Y-Axis</string>
<key>1:56</key>
<string>Wheel</string>
<key>9:1</key>
<string>Left Button</string>
<key>9:2</key>
<string>Right Button</string>
<key>9:3</key>
<string>Middle Button</string>
<key>Name</key>
<string>iFeel Mouse</string>
</dict>
<key>49671</key>
<dict>
<key>1:48</key>
<string>X-Axis</string>
<key>1:49</key>
<string>Y-Axis</string>
<key>1:53</key>
<string>Rz-Axis</string>
<key>1:54</key>
<string>Throttle</string>
<key>1:57</key>
<string>Hat Switch</string>
<key>9:1</key>
<string>Button 1 [Trigger]</string>
<key>9:2</key>
<string>Button 2</string>
<key>9:3</key>
<string>Button 3</string>
<key>9:4</key>
<string>Button 4</string>
<key>9:5</key>
<string>Button 5</string>
<key>9:6</key>
<string>Button 6</string>
<key>9:7</key>
<string>Button 7</string>
<key>Name</key>
<string>WingMan Extreme Digital 3D</string>
</dict>
<key>49797</key>
<dict>
<key>1:48</key>
<string>X-Axis</string>
<key>1:49</key>
<string>Y-Axis</string>
<key>1:53</key>
<string>Rz-Axis</string>
<key>1:54</key>
<string>Throttle</string>
<key>1:57</key>
<string>Hat Switch 1</string>
<key>65280:2</key>
<string>Thumb Wheel</string>
<key>9:1</key>
<string>Button 1 [Trigger]</string>
<key>9:10</key>
<string>Hat Switch 2 - Up</string>
<key>9:11</key>
<string>Hat Switch 2 - Right</string>
<key>9:12</key>
<string>Hat Switch 2 - Down</string>
<key>9:13</key>
<string>Hat Switch 2 - Left</string>
<key>9:14</key>
<string>Hat Switch 2 - Up Right</string>
<key>9:15</key>
<string>Hat Switch 2 - Down Right</string>
<key>9:16</key>
<string>Hat Switch 2 - Down Left</string>
<key>9:17</key>
<string>Hat Switch 2 - Up Left</string>
<key>9:2</key>
<string>Button 2</string>
<key>9:3</key>
<string>Button 3</string>
<key>9:4</key>
<string>Button 4</string>
<key>9:5</key>
<string>Button 5</string>
<key>9:6</key>
<string>Button 6</string>
<key>9:7</key>
<string>Button 7</string>
<key>9:8</key>
<string>Button 8</string>
<key>9:9</key>
<string>Button 9</string>
<key>Name</key>
<string>WingMan Strike Force 3D</string>
</dict>
<key>49811</key>
<dict>
<key>1:48</key>
<string>Wheel</string>
<key>1:49</key>
<string>Pedals</string>
<key>65280:1</key>
<string>Left Pedal [Brake]</string>
<key>9:1</key>
<string>Button 1</string>
<key>9:2</key>
<string>Button 2</string>
<key>9:3</key>
<string>Button 3</string>
<key>9:4</key>
<string>Button 4</string>
<key>9:5</key>
<string>Button 5</string>
<key>9:6</key>
<string>Button 6</string>
<key>Name</key>
<string>WingMan Formula Force GP</string>
</dict>
<key>50433</key>
<dict>
<key>1:48</key>
<string>X-Axis</string>
<key>1:49</key>
<string>Y-Axis</string>
<key>1:56</key>
<string>Wheel</string>
<key>9:1</key>
<string>Left Button</string>
<key>9:2</key>
<string>Right Button</string>
<key>9:3</key>
<string>Middle Button</string>
<key>Name</key>
<string>Cordless Mouse</string>
</dict>
<key>Name</key>
<string>Logitech</string>
</dict>
<key>1149</key>
<dict>
<key>12293</key>
<dict>
<key>1:48</key>
<string>X-Axis</string>
<key>1:49</key>
<string>Y-Axis</string>
<key>1:50</key>
<string>Throttle</string>
<key>1:57</key>
<string>Hat Switch</string>
<key>9:1</key>
<string>Button 1 [Trigger]</string>
<key>9:10</key>
<string>Button 10 [Thumb Wheel Right]</string>
<key>9:2</key>
<string>Button 2</string>
<key>9:3</key>
<string>Button 3</string>
<key>9:4</key>
<string>Button 4</string>
<key>9:5</key>
<string>Button 5</string>
<key>9:6</key>
<string>Button 6 [Thumb Wheel Button]</string>
<key>9:7</key>
<string>Button 7</string>
<key>9:8</key>
<string>Button 8</string>
<key>9:9</key>
<string>Button 9 [Thumb Wheel Left]</string>
<key>Name</key>
<string>Eliminator Precision Pro Joystick</string>
</dict>
<key>Name</key>
<string>Gravis</string>
</dict>
<key>1293</key>
<dict>
<key>2051</key>
<dict>
<key>1:48</key>
<string>Left Stick X-Axis</string>
<key>1:49</key>
<string>Left Stick Y-Axis</string>
<key>1:50</key>
<string>Right Stick Y-Axis</string>
<key>1:53</key>
<string>Right Stick X-Axis</string>
<key>1:57</key>
<string>Direction Pad</string>
<key>9:1</key>
<string>Button 1</string>
<key>9:10</key>
<string>Mouse</string>
<key>9:11</key>
<string>Eater</string>
<key>9:12</key>
<string>Right Stick Button</string>
<key>9:13</key>
<string>Left Stick Button</string>
<key>9:2</key>
<string>Button 2</string>
<key>9:3</key>
<string>Button 3</string>
<key>9:4</key>
<string>Button 4</string>
<key>9:5</key>
<string>Left Top Trigger</string>
<key>9:6</key>
<string>Left Bottom Trigger</string>
<key>9:7</key>
<string>Right Top Trigger</string>
<key>9:8</key>
<string>Right Bottom Trigger</string>
<key>9:9</key>
<string>ESC</string>
<key>Name</key>
<string>Nostromo n45</string>
</dict>
<key>Name</key>
<string>Belkin</string>
</dict>
<key>1452</key>
<dict>
<key>516</key>
<dict>
<key>1:6</key>
<string>Keyboard</string>
<key>Name</key>
<string>Apple Extended USB Keyboard</string>
</dict>
<key>770</key>
<dict>
<key>1:1</key>
<string>Pointer</string>
<key>1:2</key>
<string>Mouse</string>
<key>1:48</key>
<string>X-Axis</string>
<key>1:49</key>
<string>Y-Axis</string>
<key>9:1</key>
<string>Button</string>
<key>Name</key>
<string>Apple Optical USB Mouse</string>
</dict>
<key>Name</key>
<string>Mitsumi Electric</string>
</dict>
<key>1635</key>
<dict>
<key>38916</key>
<dict>
<key>1:48</key>
<string>Left Stick X-Axis</string>
<key>1:49</key>
<string>Left Stick Y-Axis</string>
<key>1:57</key>
<string>Hat Switch</string>
<key>2:186</key>
<string>Right Stick X-Axis</string>
<key>2:187</key>
<string>Right Stick Y-Axis</string>
<key>9:1</key>
<string>Button 1</string>
<key>9:2</key>
<string>Button 2</string>
<key>9:3</key>
<string>Button 3</string>
<key>9:4</key>
<string>Button 4</string>
<key>9:5</key>
<string>L1 Trigger</string>
<key>9:6</key>
<string>R1 Trigger</string>
<key>9:7</key>
<string>L2 Trigger</string>
<key>9:8</key>
<string>R2 Trigger</string>
<key>Name</key>
<string>FunPad F-107</string>
</dict>
<key>Name</key>
<string>Macsense</string>
</dict>
<key>1699</key>
<dict>
<key>65284</key>
<dict>
<key>1:48</key>
<string>Wheel</string>
<key>1:49</key>
<string>Left Pedal [Brake]</string>
<key>1:50</key>
<string>Right Pedal [Gas]</string>
<key>9:1</key>
<string>Top Left Thumb</string>
<key>9:2</key>
<string>Top Right Thumb</string>
<key>9:3</key>
<string>Bottom Left Thumb</string>
<key>9:4</key>
<string>Bottom Right Thumb</string>
<key>9:5</key>
<string>Right Horn</string>
<key>9:6</key>
<string>Left Horn</string>
<key>Name</key>
<string>R440 Force Feedback</string>
</dict>
<key>Name</key>
<string>Saitek</string>
</dict>
<key>1973</key>
<dict>
<key>39169</key>
<dict>
<key>1:48</key>
<string>X-Axis</string>
<key>1:49</key>
<string>Y-Axis</string>
<key>1:54</key>
<string>Throttle</string>
<key>1:57</key>
<string>Hat Switch</string>
<key>9:1</key>
<string>Button 1 [Trigger]</string>
<key>9:2</key>
<string>Button 2</string>
<key>9:3</key>
<string>Button 3</string>
<key>9:4</key>
<string>Button 4</string>
<key>Name</key>
<string>X8-33GU 2 IN 1 Joystick</string>
</dict>
<key>Name</key>
<string>Saitek</string>
</dict>
<key>8738</key>
<dict>
<key>16400</key>
<dict>
<key>1:48</key>
<string>Left Stick X-Axis</string>
<key>1:49</key>
<string>Left Stick Y-Axis</string>
<key>1:53</key>
<string>Right Stick X-Axis</string>
<key>1:54</key>
<string>Right Stick Y-Axis</string>
<key>9:1</key>
<string>D-Pad Up</string>
<key>9:10</key>
<string>Button B [Select]</string>
<key>9:11</key>
<string>Button A [Start]</string>
<key>9:12</key>
<string>Button F</string>
<key>9:13</key>
<string>R1 Trigger</string>
<key>9:14</key>
<string>R2 Trigger</string>
<key>9:15</key>
<string>L1 Trigger</string>
<key>9:16</key>
<string>L2 Trigger</string>
<key>9:17</key>
<string>Left Stick Button</string>
<key>9:18</key>
<string>Right Stick Button</string>
<key>9:19</key>
<string>D Button</string>
<key>9:2</key>
<string>D-Pad Down</string>
<key>9:20</key>
<string>E Button</string>
<key>9:3</key>
<string>D-Pad Left</string>
<key>9:4</key>
<string>D-Pad Right</string>
<key>9:5</key>
<string>Button 5 (Triangle)</string>
<key>9:6</key>
<string>Button 6 (Circle)</string>
<key>9:7</key>
<string>Button 7 (Cross)</string>
<key>9:8</key>
<string>Button 8 (Square)</string>
<key>9:9</key>
<string>Button C</string>
<key>Name</key>
<string>iShock</string>
</dict>
<key>16416</key>
<dict>
<key>1:1</key>
<string>Pointer</string>
<key>1:48</key>
<string>Left Stick X-Axis</string>
<key>1:49</key>
<string>Left Stick Y-Axis</string>
<key>1:5</key>
<string>GamePad</string>
<key>1:53</key>
<string>Right Stick X-Axis</string>
<key>1:54</key>
<string>Right Stick Y-Axis</string>
<key>9:1</key>
<string>D-Pad Up</string>
<key>9:10</key>
<string>Button 2 [Select]</string>
<key>9:11</key>
<string>Button 3 [Start]</string>
<key>9:12</key>
<string>R1 Button</string>
<key>9:13</key>
<string>R2 Trigger</string>
<key>9:14</key>
<string>L1 Trigger</string>
<key>9:15</key>
<string>L2 Trigger</string>
<key>9:16</key>
<string>Left Stick Button</string>
<key>9:17</key>
<string>Right Stick Button</string>
<key>9:2</key>
<string>D-Pad Down</string>
<key>9:3</key>
<string>D-Pad Left</string>
<key>9:4</key>
<string>D-Pad Right</string>
<key>9:5</key>
<string>A Button</string>
<key>9:6</key>
<string>B Button</string>
<key>9:7</key>
<string>C Button</string>
<key>9:8</key>
<string>D Button</string>
<key>9:9</key>
<string>Button 1</string>
<key>Name</key>
<string>iShock II</string>
</dict>
<key>Name</key>
<string>Macally</string>
</dict>
</dict>
</plist>

200
HID_usage_strings.plist Executable file
View File

@ -0,0 +1,200 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>0x0001</key>
<dict>
<key>Name</key> <string>Generic Desktop</string>
<key>0x0001</key> <string>Pointer</string>
<key>0x0002</key> <string>Mouse</string>
<key>0x0004</key> <string>Joystick</string>
<key>0x0005</key> <string>GamePad</string>
<key>0x0006</key> <string>Keyboard</string>
<key>0x0007</key> <string>Keypad</string>
<key>0x0008</key> <string>MultiAxisController</string>
<key>0x0030</key> <string>X</string>
<key>0x0031</key> <string>Y</string>
<key>0x0032</key> <string>Z</string>
<key>0x0033</key> <string>Rx</string>
<key>0x0034</key> <string>Ry</string>
<key>0x0035</key> <string>Rz</string>
<key>0x0036</key> <string>Slider</string>
<key>0x0037</key> <string>Dial</string>
<key>0x0038</key> <string>Wheel</string>
<key>0x0039</key> <string>Hatswitch</string>
<key>0x003A</key> <string>Counted Buffer</string>
<key>0x003B</key> <string>Byte Count</string>
<key>0x003C</key> <string>Motion Wakeup</string>
<key>0x003D</key> <string>Start</string>
<key>0x003E</key> <string>Select</string>
<key>0x0040</key> <string>Vx</string>
<key>0x0041</key> <string>Vy</string>
<key>0x0042</key> <string>Vz</string>
<key>0x0043</key> <string>Vbrx</string>
<key>0x0044</key> <string>Vbry</string>
<key>0x0045</key> <string>Vbrz</string>
<key>0x0046</key> <string>Vno</string>
<key>0x0080</key> <string>System Control</string>
<key>0x0081</key> <string>System Power Down</string>
<key>0x0082</key> <string>System Sleep</string>
<key>0x0083</key> <string>System Wake Up</string>
<key>0x0084</key> <string>SystemContext Menu</string>
<key>0x0085</key> <string>System Main Menu</string>
<key>0x0086</key> <string>System App Menu</string>
<key>0x0087</key> <string>System Menu help</string>
<key>0x0088</key> <string>System Menu Exit</string>
<key>0x0089</key> <string>System Menu</string>
<key>0x008A</key> <string>System Menu Right</string>
<key>0x008B</key> <string>System Menu Left</string>
<key>0x008C</key> <string>System Menu Up</string>
<key>0x008D</key> <string>System Menu Down</string>
<key>0x0090</key> <string>DPad Up</string>
<key>0x0091</key> <string>DPad Down</string>
<key>0x0092</key> <string>DPad Right</string>
<key>0x0093</key> <string>DPad Left</string>
</dict>
<key>0x0002</key>
<dict>
<key>Name</key> <string>Simulation</string>
<key>0x0001</key> <string>Flight Simulation Device</string>
<key>0x0002</key> <string>Automobile Simulation Device</string>
<key>0x0003</key> <string>Tank Simulation Device</string>
<key>0x0004</key> <string>Spaceship Simulation Device</string>
<key>0x0005</key> <string>Submarine Simulation Device</string>
<key>0x0006</key> <string>Sailing Simulation Device</string>
<key>0x0007</key> <string>Motorcycle Simulation Device</string>
<key>0x0008</key> <string>Sports Simulation Device</string>
<key>0x0009</key> <string>Airplane Simulation Device</string>
<key>0x000A</key> <string>Helicopter Simulation Device</string>
<key>0x000B</key> <string>Magic Carpet Simulation Device</string>
<key>0x000C</key> <string>Bicycle Simulation Device</string>
<key>0x0020</key> <string>Flight Control Stick</string>
<key>0x0021</key> <string>Flight Stick</string>
<key>0x0022</key> <string>Cyclic Control</string>
<key>0x0023</key> <string>Cyclic Trim</string>
<key>0x0024</key> <string>Flight Yoke</string>
<key>0x0025</key> <string>Track Control</string>
<key>0x00B0</key> <string>Aileron</string>
<key>0x00B1</key> <string>Aileron Trim</string>
<key>0x00B2</key> <string>Anti Torque Control</string>
<key>0x00B5</key> <string>Collective Control</string>
<key>0x00B6</key> <string>Dive Brake</string>
<key>0x00B7</key> <string>Electronic Countermeasures</string>
<key>0x00B8</key> <string>Elevator</string>
<key>0x00B9</key> <string>Elevator Trim</string>
<key>0x00BA</key> <string>Rudder</string>
<key>0x00BB</key> <string>Throttle</string>
<key>0x00BC</key> <string>Flight Communications</string>
<key>0x00BD</key> <string>Flare Release</string>
<key>0x00BE</key> <string>Landing Gear</string>
<key>0x00BF</key> <string>Toe Brake</string>
<key>0x00C0</key> <string>Trigger</string>
<key>0x00C1</key> <string>Weapons Arm</string>
<key>0x00C2</key> <string>Weapons</string>
<key>0x00C3</key> <string>Wing Flaps</string>
<key>0x00C4</key> <string>Accelerator</string>
<key>0x00C5</key> <string>Brake</string>
<key>0x00C6</key> <string>Clutch</string>
<key>0x00C7</key> <string>Shifter</string>
<key>0x00C8</key> <string>Steering</string>
<key>0x00C9</key> <string>Turret Direction</string>
<key>0x00CA</key> <string>Barrel Elevation</string>
<key>0x00CB</key> <string>Dive Plane</string>
<key>0x00CC</key> <string>Ballast</string>
<key>0x00CD</key> <string>Bicycle Crank</string>
<key>0x00CE</key> <string>Handle Bars</string>
<key>0x00CF</key> <string>Front Brake</string>
<key>0x00D0</key> <string>Rear Brake</string>
</dict>
<key>0x0003</key>
<dict>
<key>Name</key> <string>Virtual Reality</string>
<key>0x0001</key> <string>Belt</string>
<key>0x0002</key> <string>Body Suit</string>
<key>0x0003</key> <string>Flexor</string>
<key>0x0004</key> <string>Glove</string>
<key>0x0005</key> <string>Head Tracker</string>
<key>0x0006</key> <string>Head Mounted Display</string>
<key>0x0007</key> <string>Hand Tracker</string>
<key>0x0008</key> <string>Oculometer</string>
<key>0x0009</key> <string>Vest</string>
<key>0x000A</key> <string>Animatronic Device</string>
<key>0x0020</key> <string>Stereo Enable</string>
<key>0x0021</key> <string>Display Enable</string>
</dict>
<key>0x0004</key>
<dict>
<key>Name</key> <string>Sport</string>
<key>0x0001</key> <string>Baseball Bat</string>
<key>0x0002</key> <string>Golf Club</string>
<key>0x0003</key> <string>Rowing Machine</string>
<key>0x0004</key> <string>Treadmill</string>
<key>0x0030</key> <string>Oar</string>
<key>0x0031</key> <string>Slope</string>
<key>0x0032</key> <string>Rate</string>
<key>0x0033</key> <string>Stick Speed</string>
<key>0x0034</key> <string>Stick Face Angle</string>
<key>0x0035</key> <string>Stick Heel Or Toe</string>
<key>0x0036</key> <string>Stick Follow Through</string>
<key>0x0037</key> <string>Stick Tempo</string>
<key>0x0038</key> <string>Stick Type</string>
<key>0x0039</key> <string>Stick Height</string>
<key>0x0050</key> <string>Putter</string>
<key>0x0051</key> <string>1 Iron</string>
<key>0x0052</key> <string>2 Iron</string>
<key>0x0053</key> <string>3 Iron</string>
<key>0x0054</key> <string>4 Iron</string>
<key>0x0055</key> <string>5 Iron</string>
<key>0x0056</key> <string>6 Iron</string>
<key>0x0057</key> <string>7 Iron</string>
<key>0x0058</key> <string>8 Iron</string>
<key>0x0059</key> <string>9 Iron</string>
<key>0x005A</key> <string>10 Iron</string>
<key>0x005B</key> <string>11 Iron</string>
<key>0x005C</key> <string>Sand Wedge</string>
<key>0x005D</key> <string>Loft Wedge</string>
<key>0x005E</key> <string>Power Wedge</string>
<key>0x005F</key> <string>1 Wood</string>
<key>0x0060</key> <string>3 Wood</string>
<key>0x0061</key> <string>5 Wood</string>
<key>0x0062</key> <string>7 Wood</string>
<key>0x0063</key> <string>9 Wood</string>
</dict>
<key>0x0005</key>
<dict>
<key>Name</key> <string>Game</string>
<key>0x0001</key> <string>3D Game Controller</string>
<key>0x0002</key> <string>Pinball Device</string>
<key>0x0003</key> <string>Gun</string>
<key>0x0020</key> <string>Point of View</string>
<key>0x0021</key> <string>Turn Right Or Left</string>
<key>0x0022</key> <string>Pitch Up Or Down</string>
<key>0x0023</key> <string>Roll Right Or Left</string>
<key>0x0024</key> <string>Move Right Or Left</string>
<key>0x0025</key> <string>Move Forward Or Backward</string>
<key>0x0026</key> <string>Move Up Or Down</string>
<key>0x0027</key> <string>Lean Right Or Left</string>
<key>0x0029</key> <string>Lean Forward Or Backward</string>
<key>0x0029</key> <string>Height Of POV</string>
<key>0x002A</key> <string>Flipper</string>
<key>0x002B</key> <string>Secondary Flipper</string>
<key>0x002C</key> <string>Bump</string>
<key>0x002D</key> <string>New Game</string>
<key>0x002E</key> <string>Shoot Ball</string>
<key>0x002F</key> <string>Player</string>
<key>0x0030</key> <string>Gun Bolt</string>
<key>0x0031</key> <string>Gun Clip</string>
<key>0x0032</key> <string>Gun</string>
<key>0x0033</key> <string>Gun Single Shot</string>
<key>0x0034</key> <string>Gun Burst</string>
<key>0x0035</key> <string>Gun Automatic</string>
<key>0x0036</key> <string>Gun Safety</string>
<key>0x0037</key> <string>Gamepad Fire Or Jump</string>
<key>0x0039</key> <string>Gamepad Trigger</string>
</dict>
</dict>
</plist>

293
Info.plist Normal file
View File

@ -0,0 +1,293 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleOSTypes</key>
<array>
<string>PACK</string>
</array>
<key>CFBundleTypeExtensions</key>
<array>
<string>redplug</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>Plugin.icns</string>
<key>CFBundleTypeName</key>
<string>Redline Plugin</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSIsAppleDefaultForType</key>
<true/>
<key>LSItemContentTypes</key>
<array>
<string>com.ambrosiasw.redline.plugin</string>
</array>
<key>LSTypeIsPackage</key>
<false/>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>Redline</string>
<key>CFBundleGetInfoString</key>
<string>Redline version 1.0.5, ©2003-2008 Ambrosia Software</string>
<key>CFBundleIconFile</key>
<string>Redline</string>
<key>CFBundleIdentifier</key>
<string>com.ambrosiasw.redline</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>Redline 1.0.5</string>
<key>CFBundleSignature</key>
<string>GLrc</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>redline URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>redline</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.0.5</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>com.ambrosiasw.redline.config-file</string>
</array>
<key>UTTypeDescription</key>
<string>Redline Car Document</string>
<key>UTTypeIdentifier</key>
<string>com.ambrosiasw.redline.car</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>car</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.text</string>
<string>public.content</string>
</array>
<key>UTTypeDescription</key>
<string>Redline Configuration File</string>
<key>UTTypeIdentifier</key>
<string>com.ambrosiasw.redline.config-file</string>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>com.ambrosiasw.redline.config-file</string>
</array>
<key>UTTypeDescription</key>
<string>Redline Entity Document</string>
<key>UTTypeIdentifier</key>
<string>com.ambrosiasw.redline.entity</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>ent</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>com.ambrosiasw.redline.config-file</string>
</array>
<key>UTTypeDescription</key>
<string>Redline Environment Document</string>
<key>UTTypeIdentifier</key>
<string>com.ambrosiasw.redline.environment</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>env</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>com.ambrosiasw.redline.config-file</string>
</array>
<key>UTTypeDescription</key>
<string>Redline Font Document</string>
<key>UTTypeIdentifier</key>
<string>com.ambrosiasw.redline.font</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>font</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>com.ambrosiasw.redline.config-file</string>
</array>
<key>UTTypeDescription</key>
<string>Redline Map Description Document</string>
<key>UTTypeIdentifier</key>
<string>com.ambrosiasw.redline.mapinfo</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>mapinfo</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
<string>public.content</string>
</array>
<key>UTTypeDescription</key>
<string>Redline 3D Model Document</string>
<key>UTTypeIdentifier</key>
<string>com.ambrosiasw.redline.model</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>mdl</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
<string>public.content</string>
</array>
<key>UTTypeDescription</key>
<string>Redline Plug-in</string>
<key>UTTypeIdentifier</key>
<string>com.ambrosiasw.redline.plugin</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>com.apple.ostype</key>
<array>
<string>PACK</string>
</array>
<key>public.filename-extension</key>
<array>
<string>redplug</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>com.ambrosiasw.redline.config-file</string>
</array>
<key>UTTypeDescription</key>
<string>Redline Preferences File</string>
<key>UTTypeIdentifier</key>
<string>com.ambrosiasw.redline.preferences</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>cfg</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
<string>public.content</string>
</array>
<key>UTTypeDescription</key>
<string>Redline Replay</string>
<key>UTTypeIdentifier</key>
<string>com.ambrosiasw.redline.replay</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>redlog</string>
<string>sredlog</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
<string>public.content</string>
</array>
<key>UTTypeDescription</key>
<string>Redline Road Data Document</string>
<key>UTTypeIdentifier</key>
<string>com.ambrosiasw.redline.road</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>road</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>com.ambrosiasw.redline.config-file</string>
</array>
<key>UTTypeDescription</key>
<string>Redline Road Types Document</string>
<key>UTTypeIdentifier</key>
<string>com.ambrosiasw.redline.roadtypes</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>roadtypes</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>com.ambrosiasw.redline.config-file</string>
</array>
<key>UTTypeDescription</key>
<string>Redline Road Surfaces Document</string>
<key>UTTypeIdentifier</key>
<string>com.ambrosiasw.redline.surfaces</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>surfaces</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>

BIN
Next Track.scpt Normal file

Binary file not shown.

BIN
PlayPause.scpt Normal file

Binary file not shown.

BIN
Plugin.icns Normal file

Binary file not shown.

BIN
Prev Track.scpt Normal file

Binary file not shown.

BIN
Redline.icns Executable file

Binary file not shown.

BIN
Redline.rsrc Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
Status.scpt Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

1398
game.xcodeproj/jechter.mode1 Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,855 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 42;
objects = {
/* Begin PBXBuildFile section */
7F06105A0876ED46001EA95C /* ai.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F060FE50876ED46001EA95C /* ai.cpp */; };
7F06105D0876ED46001EA95C /* carphysics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F060FEA0876ED46001EA95C /* carphysics.cpp */; };
7F06105E0876ED46001EA95C /* carselection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F060FEC0876ED46001EA95C /* carselection.cpp */; };
7F0610640876ED46001EA95C /* collision.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F060FF90876ED46001EA95C /* collision.cpp */; };
7F0610650876ED46001EA95C /* config.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F060FFB0876ED46001EA95C /* config.cpp */; };
7F0610660876ED46001EA95C /* controls.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F060FFD0876ED46001EA95C /* controls.cpp */; };
7F0610670876ED46001EA95C /* entities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F060FFF0876ED46001EA95C /* entities.cpp */; };
7F0610680876ED46001EA95C /* environment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610010876ED46001EA95C /* environment.cpp */; };
7F0610690876ED46001EA95C /* fileio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610040876ED46001EA95C /* fileio.cpp */; };
7F06106A0876ED46001EA95C /* gameframe.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610060876ED46001EA95C /* gameframe.cpp */; };
7F06106B0876ED46001EA95C /* gameinitexit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610080876ED46001EA95C /* gameinitexit.cpp */; };
7F06106D0876ED46001EA95C /* infodisplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F06100F0876ED46001EA95C /* infodisplay.cpp */; };
7F06106E0876ED46001EA95C /* initexit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610100876ED46001EA95C /* initexit.cpp */; };
7F0610700876ED46001EA95C /* interfacemultiplayer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610140876ED46001EA95C /* interfacemultiplayer.cpp */; };
7F0610710876ED46001EA95C /* interfaceoptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610150876ED46001EA95C /* interfaceoptions.cpp */; };
7F0610720876ED46001EA95C /* interfaceutil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610160876ED46001EA95C /* interfaceutil.cpp */; };
7F0610730876ED46001EA95C /* lights.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610180876ED46001EA95C /* lights.cpp */; };
7F0610740876ED46001EA95C /* log.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F06101B0876ED46001EA95C /* log.cpp */; };
7F0610750876ED46001EA95C /* maccontrols.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F06101D0876ED46001EA95C /* maccontrols.cpp */; };
7F0610760876ED46001EA95C /* macerror.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F06101E0876ED46001EA95C /* macerror.cpp */; };
7F0610770876ED46001EA95C /* macfileio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F06101F0876ED46001EA95C /* macfileio.cpp */; };
7F0610780876ED46001EA95C /* maclocaltracker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610200876ED46001EA95C /* maclocaltracker.cpp */; };
7F0610790876ED46001EA95C /* macscreen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610210876ED46001EA95C /* macscreen.cpp */; };
7F06107A0876ED46001EA95C /* macsystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610220876ED46001EA95C /* macsystem.cpp */; };
7F06107B0876ED46001EA95C /* mactexturesimport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610230876ED46001EA95C /* mactexturesimport.cpp */; };
7F06107C0876ED46001EA95C /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610240876ED46001EA95C /* main.cpp */; };
7F06107D0876ED46001EA95C /* mapselection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610250876ED46001EA95C /* mapselection.cpp */; };
7F06107E0876ED46001EA95C /* models.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610270876ED46001EA95C /* models.cpp */; };
7F06107F0876ED46001EA95C /* music.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F06102A0876ED46001EA95C /* music.cpp */; };
7F0610810876ED46001EA95C /* network_NT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F06102E0876ED46001EA95C /* network_NT.cpp */; };
7F0610820876ED46001EA95C /* networkphysics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F06102F0876ED46001EA95C /* networkphysics.cpp */; };
7F0610830876ED46001EA95C /* parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610310876ED46001EA95C /* parser.cpp */; };
7F0610840876ED46001EA95C /* particles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610330876ED46001EA95C /* particles.cpp */; };
7F0610850876ED46001EA95C /* random.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610350876ED46001EA95C /* random.cpp */; };
7F0610860876ED46001EA95C /* rendercar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610370876ED46001EA95C /* rendercar.cpp */; };
7F0610870876ED46001EA95C /* renderframe.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610390876ED46001EA95C /* renderframe.cpp */; };
7F0610880876ED46001EA95C /* roads.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F06103B0876ED46001EA95C /* roads.cpp */; };
7F0610890876ED46001EA95C /* screen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F06103D0876ED46001EA95C /* screen.cpp */; };
7F06108A0876ED46001EA95C /* sky.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610400876ED46001EA95C /* sky.cpp */; };
7F06108D0876ED46001EA95C /* sound_ST.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610440876ED46001EA95C /* sound_ST.cpp */; };
7F06108E0876ED46001EA95C /* stencil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610450876ED46001EA95C /* stencil.cpp */; };
7F0610900876ED46001EA95C /* text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610490876ED46001EA95C /* text.cpp */; };
7F0610910876ED46001EA95C /* textures.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F06104B0876ED46001EA95C /* textures.cpp */; };
7F0610920876ED46001EA95C /* tire.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F06104E0876ED46001EA95C /* tire.cpp */; };
7F0610930876ED46001EA95C /* tracker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F06104F0876ED46001EA95C /* tracker.cpp */; };
7F0610940876ED46001EA95C /* tracks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610510876ED46001EA95C /* tracks.cpp */; };
7F0610950876ED46001EA95C /* transparency.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610530876ED46001EA95C /* transparency.cpp */; };
7F0610960876ED46001EA95C /* vectors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610550876ED46001EA95C /* vectors.cpp */; };
7F0610970876ED46001EA95C /* writeout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F0610570876ED46001EA95C /* writeout.cpp */; };
7F06138F08770577001EA95C /* interface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F06138E08770577001EA95C /* interface.cpp */; };
7F0613BB08771263001EA95C /* LZRW3-A.C in Sources */ = {isa = PBXBuildFile; fileRef = 7F0613B908771263001EA95C /* LZRW3-A.C */; };
7F4348C7096D9B5B00C3981C /* GetPID.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F4348C5096D9B5B00C3981C /* GetPID.c */; };
7F434A4F0973EC9900C3981C /* HID_cookie_strings.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7F434A4C0973EC9900C3981C /* HID_cookie_strings.plist */; };
7F434A500973EC9900C3981C /* HID_device_usage_strings.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7F434A4D0973EC9900C3981C /* HID_device_usage_strings.plist */; };
7F434A510973EC9900C3981C /* HID_usage_strings.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7F434A4E0973EC9900C3981C /* HID_usage_strings.plist */; };
7F55FFDB08DDDA9700B82C72 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A9504C8FFE6A3BC11CA0CBA /* ApplicationServices.framework */; };
7F55FFDC08DDDA9800B82C72 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A9504CAFFE6A41611CA0CBA /* CoreServices.framework */; };
7F6EB7060DBB0141008B14A9 /* challenges.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F060FF70876ED46001EA95C /* challenges.cpp */; };
7F7EDC8309EE96BA00B2A665 /* Prev Track.scpt in Resources */ = {isa = PBXBuildFile; fileRef = 7F7EDC7F09EE95E000B2A665 /* Prev Track.scpt */; };
7F8C148D0A3ABBA000E76109 /* notifications.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7F8C148C0A3ABBA000E76109 /* notifications.mm */; };
7F8C14A70A3ABDF900E76109 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F8C14A60A3ABDF900E76109 /* Cocoa.framework */; };
7F9E3C5B095334BF000394C1 /* Next Track.scpt in Resources */ = {isa = PBXBuildFile; fileRef = 7F9E3C4F095331F7000394C1 /* Next Track.scpt */; };
7F9E3C7309534CB2000394C1 /* Status.scpt in Resources */ = {isa = PBXBuildFile; fileRef = 7F9E3C7209534CA8000394C1 /* Status.scpt */; };
7F9E3C7409534CB5000394C1 /* PlayPause.scpt in Resources */ = {isa = PBXBuildFile; fileRef = 7F9E3C7109534C98000394C1 /* PlayPause.scpt */; };
7FBFFFE008ACA6BB00618F96 /* ImmrHIDUtilAddOn.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FBFFFDE08ACA6BB00618F96 /* ImmrHIDUtilAddOn.c */; };
7FC1DAFD087820860029047D /* AGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FC1DAFC087820860029047D /* AGL.framework */; };
7FC1DB0E087820970029047D /* QuickTime.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FC1DB0D087820970029047D /* QuickTime.framework */; };
7FC1DB330878209F0029047D /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FC1DB320878209F0029047D /* OpenGL.framework */; };
7FC1DC3708782A5C0029047D /* ForceFeedback.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FC1DC3608782A5C0029047D /* ForceFeedback.framework */; };
7FC5FD450D49131300C76FF4 /* AmbrosiaTools.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FC5FD440D49131300C76FF4 /* AmbrosiaTools.framework */; };
7FD85AC008BC697A00C3EB17 /* Redline.rsrc in Resources */ = {isa = PBXBuildFile; fileRef = 7FD85ABF08BC697A00C3EB17 /* Redline.rsrc */; };
7FD85B0708BC760A00C3EB17 /* S3Decompression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7FD85B0508BC760A00C3EB17 /* S3Decompression.cpp */; };
7FD85D4208BC77B900C3EB17 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FD85D4108BC77B900C3EB17 /* IOKit.framework */; };
7FD85DF008BC79EF00C3EB17 /* HID_Config_Utilities.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FD85DEA08BC79EF00C3EB17 /* HID_Config_Utilities.c */; };
7FD85DF108BC79EF00C3EB17 /* HID_Error_Handler.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FD85DEB08BC79EF00C3EB17 /* HID_Error_Handler.c */; };
7FD85DF208BC79EF00C3EB17 /* HID_Name_Lookup.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FD85DEC08BC79EF00C3EB17 /* HID_Name_Lookup.c */; };
7FD85DF308BC79EF00C3EB17 /* HID_Queue_Utilities.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FD85DED08BC79EF00C3EB17 /* HID_Queue_Utilities.c */; };
7FD85DF408BC79EF00C3EB17 /* HID_Transaction_Utilities.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FD85DEE08BC79EF00C3EB17 /* HID_Transaction_Utilities.c */; };
7FD85DF508BC79EF00C3EB17 /* HID_Utilities.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FD85DEF08BC79EF00C3EB17 /* HID_Utilities.c */; };
7FD85E2308BC9B8400C3EB17 /* fpu_exc.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FD85E2208BC9B8400C3EB17 /* fpu_exc.c */; };
7FDFBE480A1BA49C0022488F /* libSystemStubs.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FDFBE470A1BA49C0022488F /* libSystemStubs.a */; };
7FE3424609AF93CD006C8583 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FE3424509AF93CD006C8583 /* Security.framework */; };
7FED158B0D8FEA1F002AD94E /* librt3_nonag.o in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F16E75E0D57AA8200706C33 /* librt3_nonag.o */; };
7FFFAA020886C5F70046AA19 /* Plugin.icns in Resources */ = {isa = PBXBuildFile; fileRef = 7FFFAA000886C5F70046AA19 /* Plugin.icns */; };
7FFFAA030886C5F70046AA19 /* Redline.icns in Resources */ = {isa = PBXBuildFile; fileRef = 7FFFAA010886C5F70046AA19 /* Redline.icns */; };
8D0C4E8D0486CD37000505A6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0867D6AAFE840B52C02AAC07 /* InfoPlist.strings */; };
8D0C4E920486CD37000505A6 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 20286C33FDCF999611CA2CEA /* Carbon.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
0867D6ABFE840B52C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
20286C33FDCF999611CA2CEA /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
4A9504C8FFE6A3BC11CA0CBA /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; sourceTree = "<absolute>"; };
4A9504CAFFE6A41611CA0CBA /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = "<absolute>"; };
7F060FE50876ED46001EA95C /* ai.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ai.cpp; sourceTree = "<group>"; };
7F060FEA0876ED46001EA95C /* carphysics.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = carphysics.cpp; sourceTree = "<group>"; };
7F060FEB0876ED46001EA95C /* carphysics.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = carphysics.h; sourceTree = "<group>"; };
7F060FEC0876ED46001EA95C /* carselection.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = carselection.cpp; sourceTree = "<group>"; };
7F060FED0876ED46001EA95C /* carselection.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = carselection.h; sourceTree = "<group>"; };
7F060FF70876ED46001EA95C /* challenges.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = challenges.cpp; sourceTree = "<group>"; };
7F060FF80876ED46001EA95C /* challenges.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = challenges.h; sourceTree = "<group>"; };
7F060FF90876ED46001EA95C /* collision.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = collision.cpp; sourceTree = "<group>"; };
7F060FFA0876ED46001EA95C /* collision.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = collision.h; sourceTree = "<group>"; };
7F060FFB0876ED46001EA95C /* config.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = config.cpp; sourceTree = "<group>"; };
7F060FFC0876ED46001EA95C /* config.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
7F060FFD0876ED46001EA95C /* controls.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = controls.cpp; sourceTree = "<group>"; };
7F060FFE0876ED46001EA95C /* controls.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = controls.h; sourceTree = "<group>"; };
7F060FFF0876ED46001EA95C /* entities.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = entities.cpp; sourceTree = "<group>"; };
7F0610000876ED46001EA95C /* entities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = entities.h; sourceTree = "<group>"; };
7F0610010876ED46001EA95C /* environment.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = environment.cpp; sourceTree = "<group>"; };
7F0610020876ED46001EA95C /* environment.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = environment.h; sourceTree = "<group>"; };
7F0610030876ED46001EA95C /* error.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = error.h; sourceTree = "<group>"; };
7F0610040876ED46001EA95C /* fileio.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = fileio.cpp; sourceTree = "<group>"; };
7F0610050876ED46001EA95C /* fileio.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = fileio.h; sourceTree = "<group>"; };
7F0610060876ED46001EA95C /* gameframe.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = gameframe.cpp; sourceTree = "<group>"; };
7F0610070876ED46001EA95C /* gameframe.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gameframe.h; sourceTree = "<group>"; };
7F0610080876ED46001EA95C /* gameinitexit.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = gameinitexit.cpp; sourceTree = "<group>"; };
7F0610090876ED46001EA95C /* gameinitexit.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gameinitexit.h; sourceTree = "<group>"; };
7F06100A0876ED46001EA95C /* gamemem.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gamemem.h; sourceTree = "<group>"; };
7F06100B0876ED46001EA95C /* gamesound.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gamesound.h; sourceTree = "<group>"; };
7F06100C0876ED46001EA95C /* gamesystem.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gamesystem.h; sourceTree = "<group>"; };
7F06100D0876ED46001EA95C /* gametime.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gametime.h; sourceTree = "<group>"; };
7F06100F0876ED46001EA95C /* infodisplay.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = infodisplay.cpp; sourceTree = "<group>"; };
7F0610100876ED46001EA95C /* initexit.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = initexit.cpp; sourceTree = "<group>"; };
7F0610110876ED46001EA95C /* initexit.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = initexit.h; sourceTree = "<group>"; };
7F0610130876ED46001EA95C /* interface.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = interface.h; sourceTree = "<group>"; };
7F0610140876ED46001EA95C /* interfacemultiplayer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = interfacemultiplayer.cpp; sourceTree = "<group>"; };
7F0610150876ED46001EA95C /* interfaceoptions.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = interfaceoptions.cpp; sourceTree = "<group>"; };
7F0610160876ED46001EA95C /* interfaceutil.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = interfaceutil.cpp; sourceTree = "<group>"; };
7F0610170876ED46001EA95C /* interfaceutil.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = interfaceutil.h; sourceTree = "<group>"; };
7F0610180876ED46001EA95C /* lights.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = lights.cpp; sourceTree = "<group>"; };
7F0610190876ED46001EA95C /* lights.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = lights.h; sourceTree = "<group>"; };
7F06101A0876ED46001EA95C /* localtracker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = localtracker.h; sourceTree = "<group>"; };
7F06101B0876ED46001EA95C /* log.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = log.cpp; sourceTree = "<group>"; };
7F06101C0876ED46001EA95C /* log.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = log.h; sourceTree = "<group>"; };
7F06101D0876ED46001EA95C /* maccontrols.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = maccontrols.cpp; sourceTree = "<group>"; };
7F06101E0876ED46001EA95C /* macerror.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = macerror.cpp; sourceTree = "<group>"; };
7F06101F0876ED46001EA95C /* macfileio.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = macfileio.cpp; sourceTree = "<group>"; };
7F0610200876ED46001EA95C /* maclocaltracker.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = maclocaltracker.cpp; sourceTree = "<group>"; };
7F0610210876ED46001EA95C /* macscreen.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = macscreen.cpp; sourceTree = "<group>"; };
7F0610220876ED46001EA95C /* macsystem.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = macsystem.cpp; sourceTree = "<group>"; };
7F0610230876ED46001EA95C /* mactexturesimport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = mactexturesimport.cpp; sourceTree = "<group>"; };
7F0610240876ED46001EA95C /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
7F0610250876ED46001EA95C /* mapselection.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = mapselection.cpp; sourceTree = "<group>"; };
7F0610260876ED46001EA95C /* mapselection.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = mapselection.h; sourceTree = "<group>"; };
7F0610270876ED46001EA95C /* models.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = models.cpp; sourceTree = "<group>"; };
7F0610280876ED46001EA95C /* models.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = models.h; sourceTree = "<group>"; };
7F0610290876ED46001EA95C /* modeltypes.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = modeltypes.h; sourceTree = "<group>"; };
7F06102A0876ED46001EA95C /* music.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = music.cpp; sourceTree = "<group>"; };
7F06102B0876ED46001EA95C /* music.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = music.h; sourceTree = "<group>"; };
7F06102C0876ED46001EA95C /* network.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = network.h; sourceTree = "<group>"; };
7F06102E0876ED46001EA95C /* network_NT.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = network_NT.cpp; sourceTree = "<group>"; };
7F06102F0876ED46001EA95C /* networkphysics.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = networkphysics.cpp; sourceTree = "<group>"; };
7F0610300876ED46001EA95C /* networkphysics.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = networkphysics.h; sourceTree = "<group>"; };
7F0610310876ED46001EA95C /* parser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = parser.cpp; sourceTree = "<group>"; };
7F0610320876ED46001EA95C /* parser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = parser.h; sourceTree = "<group>"; };
7F0610330876ED46001EA95C /* particles.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = particles.cpp; sourceTree = "<group>"; };
7F0610340876ED46001EA95C /* particles.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = particles.h; sourceTree = "<group>"; };
7F0610350876ED46001EA95C /* random.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = random.cpp; sourceTree = "<group>"; };
7F0610360876ED46001EA95C /* random.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = random.h; sourceTree = "<group>"; };
7F0610370876ED46001EA95C /* rendercar.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = rendercar.cpp; sourceTree = "<group>"; };
7F0610380876ED46001EA95C /* rendercar.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = rendercar.h; sourceTree = "<group>"; };
7F0610390876ED46001EA95C /* renderframe.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = renderframe.cpp; sourceTree = "<group>"; };
7F06103A0876ED46001EA95C /* renderframe.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = renderframe.h; sourceTree = "<group>"; };
7F06103B0876ED46001EA95C /* roads.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = roads.cpp; sourceTree = "<group>"; };
7F06103C0876ED46001EA95C /* roads.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = roads.h; sourceTree = "<group>"; };
7F06103D0876ED46001EA95C /* screen.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = screen.cpp; sourceTree = "<group>"; };
7F06103E0876ED46001EA95C /* screen.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = screen.h; sourceTree = "<group>"; };
7F0610400876ED46001EA95C /* sky.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = sky.cpp; sourceTree = "<group>"; };
7F0610410876ED46001EA95C /* sky.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = sky.h; sourceTree = "<group>"; };
7F0610440876ED46001EA95C /* sound_ST.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = sound_ST.cpp; sourceTree = "<group>"; };
7F0610450876ED46001EA95C /* stencil.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = stencil.cpp; sourceTree = "<group>"; };
7F0610460876ED46001EA95C /* stencil.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stencil.h; sourceTree = "<group>"; };
7F0610490876ED46001EA95C /* text.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = text.cpp; sourceTree = "<group>"; };
7F06104A0876ED46001EA95C /* text.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = text.h; sourceTree = "<group>"; };
7F06104B0876ED46001EA95C /* textures.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = textures.cpp; sourceTree = "<group>"; };
7F06104C0876ED46001EA95C /* textures.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = textures.h; sourceTree = "<group>"; };
7F06104D0876ED46001EA95C /* texturesimport.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = texturesimport.h; sourceTree = "<group>"; };
7F06104E0876ED46001EA95C /* tire.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = tire.cpp; sourceTree = "<group>"; };
7F06104F0876ED46001EA95C /* tracker.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = tracker.cpp; sourceTree = "<group>"; };
7F0610500876ED46001EA95C /* tracker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = tracker.h; sourceTree = "<group>"; };
7F0610510876ED46001EA95C /* tracks.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = tracks.cpp; sourceTree = "<group>"; };
7F0610520876ED46001EA95C /* tracks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = tracks.h; sourceTree = "<group>"; };
7F0610530876ED46001EA95C /* transparency.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = transparency.cpp; sourceTree = "<group>"; };
7F0610540876ED46001EA95C /* transparency.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = transparency.h; sourceTree = "<group>"; };
7F0610550876ED46001EA95C /* vectors.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = vectors.cpp; sourceTree = "<group>"; };
7F0610560876ED46001EA95C /* vectors.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vectors.h; sourceTree = "<group>"; };
7F0610570876ED46001EA95C /* writeout.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = writeout.cpp; sourceTree = "<group>"; };
7F0610580876ED46001EA95C /* writeout.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = writeout.h; sourceTree = "<group>"; };
7F06137C08770401001EA95C /* HID_Utilities_External.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = HID_Utilities_External.h; path = "/apps/dev/SDKs/HID Utilities Source/HID_Utilities_External.h"; sourceTree = "<absolute>"; };
7F06138E08770577001EA95C /* interface.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = interface.cpp; sourceTree = "<group>"; };
7F0613B708771262001EA95C /* compress.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = compress.h; path = ../packer/compress.h; sourceTree = SOURCE_ROOT; };
7F0613B808771263001EA95C /* LZRW.H */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = LZRW.H; path = ../packer/LZRW.H; sourceTree = SOURCE_ROOT; };
7F0613B908771263001EA95C /* LZRW3-A.C */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = "LZRW3-A.C"; path = "../packer/LZRW3-A.C"; sourceTree = SOURCE_ROOT; };
7F0613BA08771263001EA95C /* port.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = port.h; path = ../packer/port.h; sourceTree = SOURCE_ROOT; };
7F16E74E0D57A68700706C33 /* rt3_redline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rt3_redline.h; path = /apps/dev/SDKs/ASW/ASWRegistration/redline/rt3_extras/rt3_redline.h; sourceTree = "<absolute>"; };
7F16E75E0D57AA8200706C33 /* librt3_nonag.o */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.objfile"; name = librt3_nonag.o; path = /apps/dev/SDKs/ASW/ASWRegistration/librt3_nonag.o; sourceTree = "<absolute>"; };
7F16E7640D57ABCC00706C33 /* ASWRegistrationCarbonAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASWRegistrationCarbonAPI.h; path = /apps/dev/SDKs/ASW/ASWRegistration/redline/CarbonAPI/ASWRegistrationCarbonAPI.h; sourceTree = "<absolute>"; };
7F4348C5096D9B5B00C3981C /* GetPID.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = GetPID.c; sourceTree = "<group>"; };
7F4348C6096D9B5B00C3981C /* GetPID.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = GetPID.h; sourceTree = "<group>"; };
7F434A4C0973EC9900C3981C /* HID_cookie_strings.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xml; path = HID_cookie_strings.plist; sourceTree = "<group>"; };
7F434A4D0973EC9900C3981C /* HID_device_usage_strings.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xml; path = HID_device_usage_strings.plist; sourceTree = "<group>"; };
7F434A4E0973EC9900C3981C /* HID_usage_strings.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xml; path = HID_usage_strings.plist; sourceTree = "<group>"; };
7F7EDC7F09EE95E000B2A665 /* Prev Track.scpt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.scpt; path = "Prev Track.scpt"; sourceTree = "<group>"; };
7F7F050D09C9E5E3002D0EE3 /* interfacemultiplayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interfacemultiplayer.h; sourceTree = "<group>"; };
7F8C148C0A3ABBA000E76109 /* notifications.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = notifications.mm; sourceTree = "<group>"; };
7F8C14A60A3ABDF900E76109 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
7F9E3C4F095331F7000394C1 /* Next Track.scpt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.scpt; path = "Next Track.scpt"; sourceTree = "<group>"; };
7F9E3C7109534C98000394C1 /* PlayPause.scpt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.scpt; path = PlayPause.scpt; sourceTree = "<group>"; };
7F9E3C7209534CA8000394C1 /* Status.scpt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.scpt; path = Status.scpt; sourceTree = "<group>"; };
7FBFFFDE08ACA6BB00618F96 /* ImmrHIDUtilAddOn.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ImmrHIDUtilAddOn.c; path = "/apps/dev/SDKs/FFB SDK/=>Developer=>Examples/ForceFeedback/UseFFAPIFromHIDUtil/ImmrHIDUtilAddOn.c"; sourceTree = "<absolute>"; };
7FBFFFDF08ACA6BB00618F96 /* ImmrHIDUtilAddOn.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ImmrHIDUtilAddOn.h; path = "/apps/dev/SDKs/FFB SDK/=>Developer=>Examples/ForceFeedback/UseFFAPIFromHIDUtil/ImmrHIDUtilAddOn.h"; sourceTree = "<absolute>"; };
7FC1DAFC087820860029047D /* AGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AGL.framework; path = /System/Library/Frameworks/AGL.framework; sourceTree = "<absolute>"; };
7FC1DB0D087820970029047D /* QuickTime.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickTime.framework; path = /System/Library/Frameworks/QuickTime.framework; sourceTree = "<absolute>"; };
7FC1DB320878209F0029047D /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
7FC1DC3608782A5C0029047D /* ForceFeedback.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ForceFeedback.framework; path = /System/Library/Frameworks/ForceFeedback.framework; sourceTree = "<absolute>"; };
7FC5FD440D49131300C76FF4 /* AmbrosiaTools.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AmbrosiaTools.framework; path = /apps/dev/SDKs/ASW/AmbrosiaTools/AmbrosiaTools.framework; sourceTree = "<absolute>"; };
7FD85ABF08BC697A00C3EB17 /* Redline.rsrc */ = {isa = PBXFileReference; lastKnownFileType = archive.rsrc; path = Redline.rsrc; sourceTree = "<group>"; };
7FD85B0508BC760A00C3EB17 /* S3Decompression.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = S3Decompression.cpp; sourceTree = "<group>"; };
7FD85B0608BC760A00C3EB17 /* S3Decompression.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = S3Decompression.h; sourceTree = "<group>"; };
7FD85D4108BC77B900C3EB17 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
7FD85DEA08BC79EF00C3EB17 /* HID_Config_Utilities.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = HID_Config_Utilities.c; path = "/apps/dev/SDKs/HID Utilities Source/HID_Config_Utilities.c"; sourceTree = "<absolute>"; };
7FD85DEB08BC79EF00C3EB17 /* HID_Error_Handler.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = HID_Error_Handler.c; path = "/apps/dev/SDKs/HID Utilities Source/HID_Error_Handler.c"; sourceTree = "<absolute>"; };
7FD85DEC08BC79EF00C3EB17 /* HID_Name_Lookup.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = HID_Name_Lookup.c; path = "/apps/dev/SDKs/HID Utilities Source/HID_Name_Lookup.c"; sourceTree = "<absolute>"; };
7FD85DED08BC79EF00C3EB17 /* HID_Queue_Utilities.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = HID_Queue_Utilities.c; path = "/apps/dev/SDKs/HID Utilities Source/HID_Queue_Utilities.c"; sourceTree = "<absolute>"; };
7FD85DEE08BC79EF00C3EB17 /* HID_Transaction_Utilities.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = HID_Transaction_Utilities.c; path = "/apps/dev/SDKs/HID Utilities Source/HID_Transaction_Utilities.c"; sourceTree = "<absolute>"; };
7FD85DEF08BC79EF00C3EB17 /* HID_Utilities.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = HID_Utilities.c; path = "/apps/dev/SDKs/HID Utilities Source/HID_Utilities.c"; sourceTree = "<absolute>"; };
7FD85E2108BC9B8400C3EB17 /* fpu_exc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fpu_exc.h; sourceTree = "<group>"; };
7FD85E2208BC9B8400C3EB17 /* fpu_exc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fpu_exc.c; sourceTree = "<group>"; };
7FDFBE470A1BA49C0022488F /* libSystemStubs.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libSystemStubs.a; path = /usr/lib/libSystemStubs.a; sourceTree = "<absolute>"; };
7FE3424509AF93CD006C8583 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; };
7FE52CD10D579B8800F442A1 /* draw_tool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = draw_tool.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/draw_tool.h; sourceTree = "<absolute>"; };
7FE52CD20D579B8800F442A1 /* file_tool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = file_tool.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/file_tool.h; sourceTree = "<absolute>"; };
7FE52CD30D579B8800F442A1 /* getline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = getline.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/getline.h; sourceTree = "<absolute>"; };
7FE52CD40D579B8800F442A1 /* inlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = inlines.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/inlines.h; sourceTree = "<absolute>"; };
7FE52CD50D579B8800F442A1 /* interface_tool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = interface_tool.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/interface_tool.h; sourceTree = "<absolute>"; };
7FE52CD60D579B8800F442A1 /* lsockets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lsockets.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/lsockets.h; sourceTree = "<absolute>"; };
7FE52CD70D579B8800F442A1 /* mac-carbon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "mac-carbon.h"; path = "/apps/dev/SDKs/ASW/AmbrosiaTools/mac-carbon.h"; sourceTree = "<absolute>"; };
7FE52CD80D579B8800F442A1 /* mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mac.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/mac.h; sourceTree = "<absolute>"; };
7FE52CD90D579B8800F442A1 /* macdebug-carbon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "macdebug-carbon.h"; path = "/apps/dev/SDKs/ASW/AmbrosiaTools/macdebug-carbon.h"; sourceTree = "<absolute>"; };
7FE52CDA0D579B8800F442A1 /* macdebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macdebug.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/macdebug.h; sourceTree = "<absolute>"; };
7FE52CDB0D579B8800F442A1 /* network_tool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = network_tool.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/network_tool.h; sourceTree = "<absolute>"; };
7FE52CDC0D579B8800F442A1 /* platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = platform.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/platform.h; sourceTree = "<absolute>"; };
7FE52CDD0D579B8800F442A1 /* reg_tool_3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = reg_tool_3.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/reg_tool_3.h; sourceTree = "<absolute>"; };
7FE52CDE0D579B8800F442A1 /* reggie.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = reggie.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/reggie.h; sourceTree = "<absolute>"; };
7FE52CDF0D579B8800F442A1 /* sound_tool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sound_tool.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/sound_tool.h; sourceTree = "<absolute>"; };
7FE52CE00D579B8800F442A1 /* stddebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stddebug.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/stddebug.h; sourceTree = "<absolute>"; };
7FE52CE10D579B8800F442A1 /* stderror.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stderror.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/stderror.h; sourceTree = "<absolute>"; };
7FE52CE20D579B8800F442A1 /* stdmath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stdmath.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/stdmath.h; sourceTree = "<absolute>"; };
7FE52CE30D579B8800F442A1 /* stdtypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stdtypes.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/stdtypes.h; sourceTree = "<absolute>"; };
7FE52CE40D579B8800F442A1 /* unix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unix.h; path = /apps/dev/SDKs/ASW/AmbrosiaTools/unix.h; sourceTree = "<absolute>"; };
7FFFAA000886C5F70046AA19 /* Plugin.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Plugin.icns; sourceTree = "<group>"; };
7FFFAA010886C5F70046AA19 /* Redline.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Redline.icns; sourceTree = "<group>"; };
8D0C4E960486CD37000505A6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
8D0C4E970486CD37000505A6 /* Redline.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Redline.app; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
8D0C4E910486CD37000505A6 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
8D0C4E920486CD37000505A6 /* Carbon.framework in Frameworks */,
7FC1DAFD087820860029047D /* AGL.framework in Frameworks */,
7FC1DB0E087820970029047D /* QuickTime.framework in Frameworks */,
7FC1DB330878209F0029047D /* OpenGL.framework in Frameworks */,
7FC1DC3708782A5C0029047D /* ForceFeedback.framework in Frameworks */,
7FD85D4208BC77B900C3EB17 /* IOKit.framework in Frameworks */,
7F55FFDB08DDDA9700B82C72 /* ApplicationServices.framework in Frameworks */,
7F55FFDC08DDDA9800B82C72 /* CoreServices.framework in Frameworks */,
7FE3424609AF93CD006C8583 /* Security.framework in Frameworks */,
7FDFBE480A1BA49C0022488F /* libSystemStubs.a in Frameworks */,
7F8C14A70A3ABDF900E76109 /* Cocoa.framework in Frameworks */,
7FC5FD450D49131300C76FF4 /* AmbrosiaTools.framework in Frameworks */,
7FED158B0D8FEA1F002AD94E /* librt3_nonag.o in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
195DF8CFFE9D517E11CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
8D0C4E970486CD37000505A6 /* Redline.app */,
);
name = Products;
sourceTree = "<group>";
};
20286C29FDCF999611CA2CEA /* game */ = {
isa = PBXGroup;
children = (
7FE52CD00D579B7500F442A1 /* ASW */,
7F0613AC08771244001EA95C /* lzrw */,
7F06136E087703B4001EA95C /* HID */,
7F060FE20876ED46001EA95C /* source */,
20286C2CFDCF999611CA2CEA /* Resources */,
20286C32FDCF999611CA2CEA /* External Frameworks and Libraries */,
195DF8CFFE9D517E11CA2CBB /* Products */,
);
name = game;
sourceTree = "<group>";
};
20286C2CFDCF999611CA2CEA /* Resources */ = {
isa = PBXGroup;
children = (
7F434A4C0973EC9900C3981C /* HID_cookie_strings.plist */,
7F434A4D0973EC9900C3981C /* HID_device_usage_strings.plist */,
7F434A4E0973EC9900C3981C /* HID_usage_strings.plist */,
7F9E3C4F095331F7000394C1 /* Next Track.scpt */,
7F7EDC7F09EE95E000B2A665 /* Prev Track.scpt */,
7FD85ABF08BC697A00C3EB17 /* Redline.rsrc */,
7FFFAA000886C5F70046AA19 /* Plugin.icns */,
7FFFAA010886C5F70046AA19 /* Redline.icns */,
7F9E3C7109534C98000394C1 /* PlayPause.scpt */,
7F9E3C7209534CA8000394C1 /* Status.scpt */,
8D0C4E960486CD37000505A6 /* Info.plist */,
0867D6AAFE840B52C02AAC07 /* InfoPlist.strings */,
);
name = Resources;
sourceTree = "<group>";
};
20286C32FDCF999611CA2CEA /* External Frameworks and Libraries */ = {
isa = PBXGroup;
children = (
7F8C14A60A3ABDF900E76109 /* Cocoa.framework */,
7FDFBE470A1BA49C0022488F /* libSystemStubs.a */,
7FE3424509AF93CD006C8583 /* Security.framework */,
7FD85D4108BC77B900C3EB17 /* IOKit.framework */,
7FC1DC3608782A5C0029047D /* ForceFeedback.framework */,
7FC1DB320878209F0029047D /* OpenGL.framework */,
7FC1DB0D087820970029047D /* QuickTime.framework */,
7FC1DAFC087820860029047D /* AGL.framework */,
20286C33FDCF999611CA2CEA /* Carbon.framework */,
4A9504CAFFE6A41611CA0CBA /* CoreServices.framework */,
4A9504C8FFE6A3BC11CA0CBA /* ApplicationServices.framework */,
);
name = "External Frameworks and Libraries";
sourceTree = "<group>";
};
7F060FE20876ED46001EA95C /* source */ = {
isa = PBXGroup;
children = (
7F4348C5096D9B5B00C3981C /* GetPID.c */,
7F4348C6096D9B5B00C3981C /* GetPID.h */,
7FD85E2108BC9B8400C3EB17 /* fpu_exc.h */,
7FD85E2208BC9B8400C3EB17 /* fpu_exc.c */,
7F060FE50876ED46001EA95C /* ai.cpp */,
7F060FEA0876ED46001EA95C /* carphysics.cpp */,
7F060FEB0876ED46001EA95C /* carphysics.h */,
7F060FEC0876ED46001EA95C /* carselection.cpp */,
7F060FF70876ED46001EA95C /* challenges.cpp */,
7F060FF80876ED46001EA95C /* challenges.h */,
7F060FF90876ED46001EA95C /* collision.cpp */,
7F060FFA0876ED46001EA95C /* collision.h */,
7F060FFB0876ED46001EA95C /* config.cpp */,
7F060FED0876ED46001EA95C /* carselection.h */,
7F060FFC0876ED46001EA95C /* config.h */,
7F060FFD0876ED46001EA95C /* controls.cpp */,
7F060FFE0876ED46001EA95C /* controls.h */,
7F060FFF0876ED46001EA95C /* entities.cpp */,
7F0610000876ED46001EA95C /* entities.h */,
7F0610010876ED46001EA95C /* environment.cpp */,
7F0610020876ED46001EA95C /* environment.h */,
7F0610030876ED46001EA95C /* error.h */,
7F0610040876ED46001EA95C /* fileio.cpp */,
7F0610050876ED46001EA95C /* fileio.h */,
7F0610060876ED46001EA95C /* gameframe.cpp */,
7F0610070876ED46001EA95C /* gameframe.h */,
7F0610080876ED46001EA95C /* gameinitexit.cpp */,
7F0610090876ED46001EA95C /* gameinitexit.h */,
7F06100A0876ED46001EA95C /* gamemem.h */,
7F06100B0876ED46001EA95C /* gamesound.h */,
7F06100C0876ED46001EA95C /* gamesystem.h */,
7F06100D0876ED46001EA95C /* gametime.h */,
7F06100F0876ED46001EA95C /* infodisplay.cpp */,
7F0610100876ED46001EA95C /* initexit.cpp */,
7F0610110876ED46001EA95C /* initexit.h */,
7F06138E08770577001EA95C /* interface.cpp */,
7F0610130876ED46001EA95C /* interface.h */,
7F0610140876ED46001EA95C /* interfacemultiplayer.cpp */,
7F7F050D09C9E5E3002D0EE3 /* interfacemultiplayer.h */,
7F0610150876ED46001EA95C /* interfaceoptions.cpp */,
7F0610160876ED46001EA95C /* interfaceutil.cpp */,
7F0610170876ED46001EA95C /* interfaceutil.h */,
7F0610180876ED46001EA95C /* lights.cpp */,
7F0610190876ED46001EA95C /* lights.h */,
7F06101A0876ED46001EA95C /* localtracker.h */,
7F06101B0876ED46001EA95C /* log.cpp */,
7F06101C0876ED46001EA95C /* log.h */,
7F06101D0876ED46001EA95C /* maccontrols.cpp */,
7F06101E0876ED46001EA95C /* macerror.cpp */,
7F06101F0876ED46001EA95C /* macfileio.cpp */,
7F0610200876ED46001EA95C /* maclocaltracker.cpp */,
7F0610210876ED46001EA95C /* macscreen.cpp */,
7F0610220876ED46001EA95C /* macsystem.cpp */,
7F0610230876ED46001EA95C /* mactexturesimport.cpp */,
7F0610240876ED46001EA95C /* main.cpp */,
7F0610250876ED46001EA95C /* mapselection.cpp */,
7F0610260876ED46001EA95C /* mapselection.h */,
7F0610270876ED46001EA95C /* models.cpp */,
7F0610280876ED46001EA95C /* models.h */,
7F0610290876ED46001EA95C /* modeltypes.h */,
7F06102A0876ED46001EA95C /* music.cpp */,
7F06102B0876ED46001EA95C /* music.h */,
7F06102C0876ED46001EA95C /* network.h */,
7F06102E0876ED46001EA95C /* network_NT.cpp */,
7F06102F0876ED46001EA95C /* networkphysics.cpp */,
7F0610300876ED46001EA95C /* networkphysics.h */,
7F8C148C0A3ABBA000E76109 /* notifications.mm */,
7F0610310876ED46001EA95C /* parser.cpp */,
7F0610320876ED46001EA95C /* parser.h */,
7F0610330876ED46001EA95C /* particles.cpp */,
7F0610340876ED46001EA95C /* particles.h */,
7F0610350876ED46001EA95C /* random.cpp */,
7F0610360876ED46001EA95C /* random.h */,
7F0610370876ED46001EA95C /* rendercar.cpp */,
7F0610380876ED46001EA95C /* rendercar.h */,
7F0610390876ED46001EA95C /* renderframe.cpp */,
7F06103A0876ED46001EA95C /* renderframe.h */,
7F06103B0876ED46001EA95C /* roads.cpp */,
7F06103C0876ED46001EA95C /* roads.h */,
7FD85B0508BC760A00C3EB17 /* S3Decompression.cpp */,
7FD85B0608BC760A00C3EB17 /* S3Decompression.h */,
7F06103D0876ED46001EA95C /* screen.cpp */,
7F06103E0876ED46001EA95C /* screen.h */,
7F0610400876ED46001EA95C /* sky.cpp */,
7F0610410876ED46001EA95C /* sky.h */,
7F0610440876ED46001EA95C /* sound_ST.cpp */,
7F0610450876ED46001EA95C /* stencil.cpp */,
7F0610460876ED46001EA95C /* stencil.h */,
7F0610490876ED46001EA95C /* text.cpp */,
7F06104A0876ED46001EA95C /* text.h */,
7F06104B0876ED46001EA95C /* textures.cpp */,
7F06104C0876ED46001EA95C /* textures.h */,
7F06104D0876ED46001EA95C /* texturesimport.h */,
7F06104E0876ED46001EA95C /* tire.cpp */,
7F06104F0876ED46001EA95C /* tracker.cpp */,
7F0610500876ED46001EA95C /* tracker.h */,
7F0610510876ED46001EA95C /* tracks.cpp */,
7F0610520876ED46001EA95C /* tracks.h */,
7F0610530876ED46001EA95C /* transparency.cpp */,
7F0610540876ED46001EA95C /* transparency.h */,
7F0610550876ED46001EA95C /* vectors.cpp */,
7F0610560876ED46001EA95C /* vectors.h */,
7F0610570876ED46001EA95C /* writeout.cpp */,
7F0610580876ED46001EA95C /* writeout.h */,
);
path = source;
sourceTree = "<group>";
};
7F06136E087703B4001EA95C /* HID */ = {
isa = PBXGroup;
children = (
7FD85DEA08BC79EF00C3EB17 /* HID_Config_Utilities.c */,
7FD85DEB08BC79EF00C3EB17 /* HID_Error_Handler.c */,
7FD85DEC08BC79EF00C3EB17 /* HID_Name_Lookup.c */,
7FD85DED08BC79EF00C3EB17 /* HID_Queue_Utilities.c */,
7FD85DEE08BC79EF00C3EB17 /* HID_Transaction_Utilities.c */,
7FD85DEF08BC79EF00C3EB17 /* HID_Utilities.c */,
7FBFFFDE08ACA6BB00618F96 /* ImmrHIDUtilAddOn.c */,
7FBFFFDF08ACA6BB00618F96 /* ImmrHIDUtilAddOn.h */,
7F06137C08770401001EA95C /* HID_Utilities_External.h */,
);
name = HID;
sourceTree = "<group>";
};
7F0613AC08771244001EA95C /* lzrw */ = {
isa = PBXGroup;
children = (
7F0613B708771262001EA95C /* compress.h */,
7F0613B808771263001EA95C /* LZRW.H */,
7F0613B908771263001EA95C /* LZRW3-A.C */,
7F0613BA08771263001EA95C /* port.h */,
);
name = lzrw;
sourceTree = "<group>";
};
7FE52CD00D579B7500F442A1 /* ASW */ = {
isa = PBXGroup;
children = (
7F16E7640D57ABCC00706C33 /* ASWRegistrationCarbonAPI.h */,
7F16E75E0D57AA8200706C33 /* librt3_nonag.o */,
7F16E74E0D57A68700706C33 /* rt3_redline.h */,
7FE52CD10D579B8800F442A1 /* draw_tool.h */,
7FE52CD20D579B8800F442A1 /* file_tool.h */,
7FE52CD30D579B8800F442A1 /* getline.h */,
7FE52CD40D579B8800F442A1 /* inlines.h */,
7FE52CD50D579B8800F442A1 /* interface_tool.h */,
7FE52CD60D579B8800F442A1 /* lsockets.h */,
7FE52CD70D579B8800F442A1 /* mac-carbon.h */,
7FE52CD80D579B8800F442A1 /* mac.h */,
7FE52CD90D579B8800F442A1 /* macdebug-carbon.h */,
7FE52CDA0D579B8800F442A1 /* macdebug.h */,
7FE52CDB0D579B8800F442A1 /* network_tool.h */,
7FE52CDC0D579B8800F442A1 /* platform.h */,
7FE52CDD0D579B8800F442A1 /* reg_tool_3.h */,
7FE52CDE0D579B8800F442A1 /* reggie.h */,
7FE52CDF0D579B8800F442A1 /* sound_tool.h */,
7FE52CE00D579B8800F442A1 /* stddebug.h */,
7FE52CE10D579B8800F442A1 /* stderror.h */,
7FE52CE20D579B8800F442A1 /* stdmath.h */,
7FE52CE30D579B8800F442A1 /* stdtypes.h */,
7FE52CE40D579B8800F442A1 /* unix.h */,
7FC5FD440D49131300C76FF4 /* AmbrosiaTools.framework */,
);
name = ASW;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
8D0C4E890486CD37000505A6 /* Redline */ = {
isa = PBXNativeTarget;
buildConfigurationList = 7F060FD80876EC7F001EA95C /* Build configuration list for PBXNativeTarget "Redline" */;
buildPhases = (
8D0C4E8C0486CD37000505A6 /* Resources */,
8D0C4E8F0486CD37000505A6 /* Sources */,
8D0C4E910486CD37000505A6 /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Redline;
productInstallPath = "$(HOME)/Applications";
productName = game;
productReference = 8D0C4E970486CD37000505A6 /* Redline.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
20286C28FDCF999611CA2CEA /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 7F060FDC0876EC7F001EA95C /* Build configuration list for PBXProject "game" */;
compatibilityVersion = "Xcode 2.4";
hasScannedForEncodings = 1;
mainGroup = 20286C29FDCF999611CA2CEA /* game */;
projectDirPath = "";
projectRoot = "";
targets = (
8D0C4E890486CD37000505A6 /* Redline */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
8D0C4E8C0486CD37000505A6 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7F9E3C7409534CB5000394C1 /* PlayPause.scpt in Resources */,
7F7EDC8309EE96BA00B2A665 /* Prev Track.scpt in Resources */,
7F9E3C7309534CB2000394C1 /* Status.scpt in Resources */,
8D0C4E8D0486CD37000505A6 /* InfoPlist.strings in Resources */,
7FFFAA020886C5F70046AA19 /* Plugin.icns in Resources */,
7F9E3C5B095334BF000394C1 /* Next Track.scpt in Resources */,
7FFFAA030886C5F70046AA19 /* Redline.icns in Resources */,
7FD85AC008BC697A00C3EB17 /* Redline.rsrc in Resources */,
7F434A4F0973EC9900C3981C /* HID_cookie_strings.plist in Resources */,
7F434A500973EC9900C3981C /* HID_device_usage_strings.plist in Resources */,
7F434A510973EC9900C3981C /* HID_usage_strings.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
8D0C4E8F0486CD37000505A6 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7F06105A0876ED46001EA95C /* ai.cpp in Sources */,
7F06105D0876ED46001EA95C /* carphysics.cpp in Sources */,
7F06105E0876ED46001EA95C /* carselection.cpp in Sources */,
7F0610640876ED46001EA95C /* collision.cpp in Sources */,
7F0610650876ED46001EA95C /* config.cpp in Sources */,
7F0610660876ED46001EA95C /* controls.cpp in Sources */,
7F0610670876ED46001EA95C /* entities.cpp in Sources */,
7F0610680876ED46001EA95C /* environment.cpp in Sources */,
7F0610690876ED46001EA95C /* fileio.cpp in Sources */,
7F06106A0876ED46001EA95C /* gameframe.cpp in Sources */,
7F06106B0876ED46001EA95C /* gameinitexit.cpp in Sources */,
7F06106D0876ED46001EA95C /* infodisplay.cpp in Sources */,
7F06106E0876ED46001EA95C /* initexit.cpp in Sources */,
7F0610700876ED46001EA95C /* interfacemultiplayer.cpp in Sources */,
7F0610710876ED46001EA95C /* interfaceoptions.cpp in Sources */,
7F0610720876ED46001EA95C /* interfaceutil.cpp in Sources */,
7F0610730876ED46001EA95C /* lights.cpp in Sources */,
7F0610740876ED46001EA95C /* log.cpp in Sources */,
7F0610750876ED46001EA95C /* maccontrols.cpp in Sources */,
7F0610760876ED46001EA95C /* macerror.cpp in Sources */,
7F0610770876ED46001EA95C /* macfileio.cpp in Sources */,
7F0610780876ED46001EA95C /* maclocaltracker.cpp in Sources */,
7F0610790876ED46001EA95C /* macscreen.cpp in Sources */,
7F06107A0876ED46001EA95C /* macsystem.cpp in Sources */,
7F06107B0876ED46001EA95C /* mactexturesimport.cpp in Sources */,
7F06107C0876ED46001EA95C /* main.cpp in Sources */,
7F06107D0876ED46001EA95C /* mapselection.cpp in Sources */,
7F06107E0876ED46001EA95C /* models.cpp in Sources */,
7F06107F0876ED46001EA95C /* music.cpp in Sources */,
7F0610810876ED46001EA95C /* network_NT.cpp in Sources */,
7F0610820876ED46001EA95C /* networkphysics.cpp in Sources */,
7F0610830876ED46001EA95C /* parser.cpp in Sources */,
7F0610840876ED46001EA95C /* particles.cpp in Sources */,
7F0610850876ED46001EA95C /* random.cpp in Sources */,
7F0610860876ED46001EA95C /* rendercar.cpp in Sources */,
7F0610870876ED46001EA95C /* renderframe.cpp in Sources */,
7F0610880876ED46001EA95C /* roads.cpp in Sources */,
7F0610890876ED46001EA95C /* screen.cpp in Sources */,
7F06108A0876ED46001EA95C /* sky.cpp in Sources */,
7F06108D0876ED46001EA95C /* sound_ST.cpp in Sources */,
7F06108E0876ED46001EA95C /* stencil.cpp in Sources */,
7F0610900876ED46001EA95C /* text.cpp in Sources */,
7F0610910876ED46001EA95C /* textures.cpp in Sources */,
7F0610920876ED46001EA95C /* tire.cpp in Sources */,
7F0610930876ED46001EA95C /* tracker.cpp in Sources */,
7F0610940876ED46001EA95C /* tracks.cpp in Sources */,
7F0610950876ED46001EA95C /* transparency.cpp in Sources */,
7F0610960876ED46001EA95C /* vectors.cpp in Sources */,
7F0610970876ED46001EA95C /* writeout.cpp in Sources */,
7F06138F08770577001EA95C /* interface.cpp in Sources */,
7F0613BB08771263001EA95C /* LZRW3-A.C in Sources */,
7FBFFFE008ACA6BB00618F96 /* ImmrHIDUtilAddOn.c in Sources */,
7FD85B0708BC760A00C3EB17 /* S3Decompression.cpp in Sources */,
7FD85DF008BC79EF00C3EB17 /* HID_Config_Utilities.c in Sources */,
7FD85DF108BC79EF00C3EB17 /* HID_Error_Handler.c in Sources */,
7FD85DF208BC79EF00C3EB17 /* HID_Name_Lookup.c in Sources */,
7FD85DF308BC79EF00C3EB17 /* HID_Queue_Utilities.c in Sources */,
7FD85DF408BC79EF00C3EB17 /* HID_Transaction_Utilities.c in Sources */,
7FD85DF508BC79EF00C3EB17 /* HID_Utilities.c in Sources */,
7FD85E2308BC9B8400C3EB17 /* fpu_exc.c in Sources */,
7F4348C7096D9B5B00C3981C /* GetPID.c in Sources */,
7F8C148D0A3ABBA000E76109 /* notifications.mm in Sources */,
7F6EB7060DBB0141008B14A9 /* challenges.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
0867D6AAFE840B52C02AAC07 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
0867D6ABFE840B52C02AAC07 /* English */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
7F060FD90876EC7F001EA95C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
/apps/dev/SDKs/ASW/AmbrosiaTools,
/apps/dev/SDKs/ASW/ASWRegistration/redline/Framework/Release,
);
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = game_Prefix.pch;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(HOME)/Applications";
LIBRARY_SEARCH_PATHS = (
"/apps/dev/SDKs/Ambrosia-CW-02-26-2005/network_tool/libraries",
"/apps/dev/SDKs/Ambrosia-CW-02-26-2005/reg_tool_3/libraries",
"/apps/dev/SDKs/Ambrosia-CW-02-26-2005/reggie/libraries",
"/apps/dev/SDKs/Ambrosia-CW-02-26-2005/sound_tool/libraries",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/lsockets",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/network_tool",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/platform",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/reg_tool_3",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/reggie",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/sound_tool",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/file_tool",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/interface_tool",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/draw_tool",
"$(LIBRARY_SEARCH_PATHS_QUOTED_1)",
);
LIBRARY_SEARCH_PATHS_QUOTED_1 = "/apps/dev/SDKs/HID\\ Utilities\\ Source/build";
PREBINDING = NO;
PRODUCT_NAME = Redline;
WRAPPER_EXTENSION = app;
ZERO_LINK = NO;
};
name = Debug;
};
7F060FDA0876EC7F001EA95C /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
/apps/dev/SDKs/ASW/AmbrosiaTools,
/apps/dev/SDKs/ASW/ASWRegistration/redline/Framework/Release,
);
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = game_Prefix.pch;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(HOME)/Applications";
LIBRARY_SEARCH_PATHS = (
"/apps/dev/SDKs/Ambrosia-CW-02-26-2005/network_tool/libraries",
"/apps/dev/SDKs/Ambrosia-CW-02-26-2005/reg_tool_3/libraries",
"/apps/dev/SDKs/Ambrosia-CW-02-26-2005/reggie/libraries",
"/apps/dev/SDKs/Ambrosia-CW-02-26-2005/sound_tool/libraries",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/lsockets",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/network_tool",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/platform",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/reg_tool_3",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/reggie",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/sound_tool",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/file_tool",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/interface_tool",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/draw_tool",
"$(LIBRARY_SEARCH_PATHS_QUOTED_1)",
);
LIBRARY_SEARCH_PATHS_QUOTED_1 = "/apps/dev/SDKs/HID\\ Utilities\\ Source/build";
PREBINDING = NO;
PRODUCT_NAME = Redline;
WRAPPER_EXTENSION = app;
ZERO_LINK = NO;
};
name = Release;
};
7F060FDB0876EC7F001EA95C /* Default */ = {
isa = XCBuildConfiguration;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
/apps/dev/SDKs/ASW/AmbrosiaTools,
/apps/dev/SDKs/ASW/ASWRegistration/redline/Framework/Release,
);
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = game_Prefix.pch;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(HOME)/Applications";
LIBRARY_SEARCH_PATHS = (
"/apps/dev/SDKs/Ambrosia-CW-02-26-2005/network_tool/libraries",
"/apps/dev/SDKs/Ambrosia-CW-02-26-2005/reg_tool_3/libraries",
"/apps/dev/SDKs/Ambrosia-CW-02-26-2005/reggie/libraries",
"/apps/dev/SDKs/Ambrosia-CW-02-26-2005/sound_tool/libraries",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/lsockets",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/network_tool",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/platform",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/reg_tool_3",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/reggie",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/sound_tool",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/file_tool",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/interface_tool",
"/apps/dev/SDKs/Ambrosia-gcc-02-26-2005/draw_tool",
"$(LIBRARY_SEARCH_PATHS_QUOTED_1)",
);
LIBRARY_SEARCH_PATHS_QUOTED_1 = "/apps/dev/SDKs/HID\\ Utilities\\ Source/build";
PREBINDING = NO;
PRODUCT_NAME = Redline;
WRAPPER_EXTENSION = app;
};
name = Default;
};
7F060FDD0876EC7F001EA95C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = ppc;
MACOSX_DEPLOYMENT_TARGET = 10.4;
OTHER_LDFLAGS = "-lz";
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
ZERO_LINK = NO;
};
name = Debug;
};
7F060FDE0876EC7F001EA95C /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1)";
ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386";
DEAD_CODE_STRIPPING = YES;
GCC_OPTIMIZATION_LEVEL = 3;
GCC_VERSION_i386 = 4.0;
GCC_VERSION_ppc = 3.3;
HEADER_SEARCH_PATHS = "";
MACOSX_DEPLOYMENT_TARGET = 10.2;
MACOSX_DEPLOYMENT_TARGET_i386 = 10.4;
MACOSX_DEPLOYMENT_TARGET_ppc = 10.2;
ONLY_ACTIVE_ARCH = NO;
OTHER_LDFLAGS = (
"-lz",
"-weak_library",
$SDKROOT/usr/lib/libcurl.dylib,
);
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
SDKROOT_i386 = /Developer/SDKs/MacOSX10.4u.sdk;
SDKROOT_ppc = /Developer/SDKs/MacOSX10.3.9.sdk;
};
name = Release;
};
7F060FDF0876EC7F001EA95C /* Default */ = {
isa = XCBuildConfiguration;
buildSettings = {
MACOSX_DEPLOYMENT_TARGET = 10.4;
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
};
name = Default;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
7F060FD80876EC7F001EA95C /* Build configuration list for PBXNativeTarget "Redline" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7F060FD90876EC7F001EA95C /* Debug */,
7F060FDA0876EC7F001EA95C /* Release */,
7F060FDB0876EC7F001EA95C /* Default */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Default;
};
7F060FDC0876EC7F001EA95C /* Build configuration list for PBXProject "game" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7F060FDD0876EC7F001EA95C /* Debug */,
7F060FDE0876EC7F001EA95C /* Release */,
7F060FDF0876EC7F001EA95C /* Default */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Default;
};
/* End XCConfigurationList section */
};
rootObject = 20286C28FDCF999611CA2CEA /* Project object */;
}

6
game_Prefix.pch Normal file
View File

@ -0,0 +1,6 @@
//
// Prefix header for all source files of the 'game' target in the 'game' project.
//
#include <Carbon/Carbon.h>
#include "mac-carbon.h"

BIN
iChat Status.scpt Normal file

Binary file not shown.

BIN
source.zip Normal file

Binary file not shown.

402
source/GetPID.c Executable file
View File

@ -0,0 +1,402 @@
/*
File: GetPID.c
Description: This file provides a simple API to do process PID lookup based on process name.
Author: Chad Jones
Copyright: © Copyright 2003 Apple Computer, Inc. All rights reserved.
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
("Apple") in consideration of your agreement to the following terms, and your
use, installation, modification or redistribution of this Apple software
constitutes acceptance of these terms. If you do not agree with these terms,
please do not use, install, modify or redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and subject
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
copyrights in this original Apple software (the "Apple Software"), to use,
reproduce, modify and redistribute the Apple Software, with or without
modifications, in source and/or binary forms; provided that if you redistribute
the Apple Software in its entirety and without modifications, you must retain
this notice and the following text and disclaimers in all such redistributions of
the Apple Software. Neither the name, trademarks, service marks or logos of
Apple Computer, Inc. may be used to endorse or promote products derived from the
Apple Software without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or implied,
are granted by Apple herein, including but not limited to any patent rights that
may be infringed by your derivative works or by other works in which the Apple
Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
*/
#include "GetPID.h"
#include <errno.h>
#include <string.h>
#include <sys/sysctl.h>
/*****************************************************
* GetAllPIDsForProcessName
*****************************************************
* Purpose: This functions purpose is to lookup a BSD
* process PID given the BSD process name. This function may
* potentially return multiple PIDs for a given BSD process name
* since several processes can have the same BSD process name.
*
* Parameters:
* ProcessName A constant C-string. On calling
* GetAllPIDsForProcessName this variable holds the BSD process name
* used to do the process lookup. Note that the process name you need
* to pass is the name of the BSD executable process. If trying
* to find the PID of an regular OSX application you will need to pass the
* name of the actual BSD executable inside an application bundle (rather
* than the bundle name itself). In any case as a user you can find the
* BSD process name of any process (including OSX applications) by
* typing the command "ps -axcocommand,pid" in terminal.
*
* ArrayOfReturnedPIDs A pointer to a pre-allocated array of pid_t.
* On calling GetAllPIDsForProcessName this variable must be a pointer to a
* pre-allocated array of pid_t whos length (in number of pid_t entries) is defined
* in ArrayOfPIDsLength. On successful return from GetAllPIDsForProcessName
* this array will hold the PIDs of all processes which have a matching process
* name to that specified in the ProcessName input variable. The number of actual
* PIDs entered in the array starting at index zero will be the value returned
* in NumberOfMatchesFound. On failed return if the error is a buffer overflow
* error then the buffer will be filled to the max with PIDs which matched.
* Otherwise on failed return the state of the array will be undefined. Note
* the returned PID array is not sorted and is listed in order of process encountered.
*
* NumberOfPossiblePIDsInArray A unsigned integer. On calling
* GetAllPIDsForProcessName this variable will hold the number of
* pre-allocated PID entries which are in the ArrayOfReturnedPIDs for this functions
* use. Note this value must have a value greater than zero.
*
* NumberOfMatchesFound An unsigned integer. On calling GetAllPIDsForProcessName
* this variable will point to a pre-allocated unsigned integer. On return from
* GetAllPIDsForProcessName this variable will contain the number of PIDs contained in the
* ArrayOfReturnedPIDs. On failed return the value of the variable will be undefined.
*
* SysctlError A pointer to a pre-allocated integer. On failed return, this
* variable represents the error returned from the sysctl command. On function
* success this variable will have a value specified by the sysctl based on the
* error that occurred. On success the variable will have the value zero.
* Note this variable can also be NULL in which case the variable is ignored.
*
* *Function Result* A integer return value.
* See result codes listed below.
* Result Codes:
* 0 Success. A set of process PIDs were found and are located in
* ArrayOfReturnedPIDs array.
* -1 Could not find a process with a matching process name
* (i.e. process not found).
* -2 Invalid arguments passed.
* -3 Unable to get the size of sysctl buffer required
* (consult SysctlError return value for more information)
* -4 Unable to allocate memory to store BSD process information
* (consult SysctlError return value for more information)
* -5 The array passed to hold the returned PIDs is not large enough
* to hold all PIDs of process with matching names.
*
*****************************************************/
int GetAllPIDsForProcessName(const char* ProcessName,
pid_t ArrayOfReturnedPIDs[],
const unsigned int NumberOfPossiblePIDsInArray,
unsigned int* NumberOfMatchesFound,
int* SysctlError)
{
// --- Defining local variables for this function and initializing all to zero --- //
int mib[6] = {0,0,0,0,0,0}; //used for sysctl call.
int SuccessfullyGotProcessInformation;
size_t sizeOfBufferRequired = 0; //set to zero to start with.
int error = 0;
long NumberOfRunningProcesses = 0;
unsigned int Counter = 0;
struct kinfo_proc* BSDProcessInformationStructure = NULL;
pid_t CurrentExaminedProcessPID = 0;
char* CurrentExaminedProcessName = NULL;
// --- Checking input arguments for validity --- //
if (ProcessName == NULL) //need valid process name
{
return(kInvalidArgumentsError);
}
if (ArrayOfReturnedPIDs == NULL) //need an actual array
{
return(kInvalidArgumentsError);
}
if (NumberOfPossiblePIDsInArray <= 0)
{
//length of the array must be larger than zero.
return(kInvalidArgumentsError);
}
if (NumberOfMatchesFound == NULL) //need an integer for return.
{
return(kInvalidArgumentsError);
}
//--- Setting return values to known values --- //
//initalizing PID array so all values are zero
memset(ArrayOfReturnedPIDs, 0, NumberOfPossiblePIDsInArray * sizeof(pid_t));
*NumberOfMatchesFound = 0; //no matches found yet
if (SysctlError != NULL) //only set sysctlError if it is present
{
*SysctlError = 0;
}
//--- Getting list of process information for all processes --- //
/* Setting up the mib (Management Information Base) which is an array of integers where each
* integer specifies how the data will be gathered. Here we are setting the MIB
* block to lookup the information on all the BSD processes on the system. Also note that
* every regular application has a recognized BSD process accociated with it. We pass
* CTL_KERN, KERN_PROC, KERN_PROC_ALL to sysctl as the MIB to get back a BSD structure with
* all BSD process information for all processes in it (including BSD process names)
*/
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_ALL;
/* Here we have a loop set up where we keep calling sysctl until we finally get an unrecoverable error
* (and we return) or we finally get a succesful result. Note with how dynamic the process list can
* be you can expect to have a failure here and there since the process list can change between
* getting the size of buffer required and the actually filling that buffer.
*/
SuccessfullyGotProcessInformation = FALSE;
while (SuccessfullyGotProcessInformation == FALSE)
{
/* Now that we have the MIB for looking up process information we will pass it to sysctl to get the
* information we want on BSD processes. However, before we do this we must know the size of the buffer to
* allocate to accomidate the return value. We can get the size of the data to allocate also using the
* sysctl command. In this case we call sysctl with the proper arguments but specify no return buffer
* specified (null buffer). This is a special case which causes sysctl to return the size of buffer required.
*
* First Argument: The MIB which is really just an array of integers. Each integer is a constant
* representing what information to gather from the system. Check out the man page to know what
* constants sysctl will work with. Here of course we pass our MIB block which was passed to us.
* Second Argument: The number of constants in the MIB (array of integers). In this case there are three.
* Third Argument: The output buffer where the return value from sysctl will be stored. In this case
* we don't want anything return yet since we don't yet know the size of buffer needed. Thus we will
* pass null for the buffer to begin with.
* Forth Argument: The size of the output buffer required. Since the buffer itself is null we can just
* get the buffer size needed back from this call.
* Fifth Argument: The new value we want the system data to have. Here we don't want to set any system
* information we only want to gather it. Thus, we pass null as the buffer so sysctl knows that
* we have no desire to set the value.
* Sixth Argument: The length of the buffer containing new information (argument five). In this case
* argument five was null since we didn't want to set the system value. Thus, the size of the buffer
* is zero or NULL.
* Return Value: a return value indicating success or failure. Actually, sysctl will either return
* zero on no error and -1 on error. The errno UNIX variable will be set on error.
*/
error = sysctl(mib, 3, NULL, &sizeOfBufferRequired, NULL, NULL);
/* If an error occurred then return the accociated error. The error itself actually is stored in the UNIX
* errno variable. We can access the errno value using the errno global variable. We will return the
* errno value as the sysctlError return value from this function.
*/
if (error != 0)
{
if (SysctlError != NULL)
{
*SysctlError = errno; //we only set this variable if the pre-allocated variable is given
}
return(kErrorGettingSizeOfBufferRequired);
}
/* Now we successful obtained the size of the buffer required for the sysctl call. This is stored in the
* SizeOfBufferRequired variable. We will malloc a buffer of that size to hold the sysctl result.
*/
BSDProcessInformationStructure = (struct kinfo_proc*) malloc(sizeOfBufferRequired);
if (BSDProcessInformationStructure == NULL)
{
if (SysctlError != NULL)
{
*SysctlError = ENOMEM; //we only set this variable if the pre-allocated variable is given
}
return(kUnableToAllocateMemoryForBuffer); //unrecoverable error (no memory available) so give up
}
/* Now we have the buffer of the correct size to hold the result we can now call sysctl
* and get the process information.
*
* First Argument: The MIB for gathering information on running BSD processes. The MIB is really
* just an array of integers. Each integer is a constant representing what information to
* gather from the system. Check out the man page to know what constants sysctl will work with.
* Second Argument: The number of constants in the MIB (array of integers). In this case there are three.
* Third Argument: The output buffer where the return value from sysctl will be stored. This is the buffer
* which we allocated specifically for this purpose.
* Forth Argument: The size of the output buffer (argument three). In this case its the size of the
* buffer we already allocated.
* Fifth Argument: The buffer containing the value to set the system value to. In this case we don't
* want to set any system information we only want to gather it. Thus, we pass null as the buffer
* so sysctl knows that we have no desire to set the value.
* Sixth Argument: The length of the buffer containing new information (argument five). In this case
* argument five was null since we didn't want to set the system value. Thus, the size of the buffer
* is zero or NULL.
* Return Value: a return value indicating success or failure. Actually, sysctl will either return
* zero on no error and -1 on error. The errno UNIX variable will be set on error.
*/
error = sysctl(mib, 3, BSDProcessInformationStructure, &sizeOfBufferRequired, NULL, NULL);
//Here we successfully got the process information. Thus set the variable to end this sysctl calling loop
if (error == 0)
{
SuccessfullyGotProcessInformation = TRUE;
}
else
{
/* failed getting process information we will try again next time around the loop. Note this is caused
* by the fact the process list changed between getting the size of the buffer and actually filling
* the buffer (something which will happen from time to time since the process list is dynamic).
* Anyways, the attempted sysctl call failed. We will now begin again by freeing up the allocated
* buffer and starting again at the beginning of the loop.
*/
free(BSDProcessInformationStructure);
}
}//end while loop
// --- Going through process list looking for processes with matching names --- //
/* Now that we have the BSD structure describing the running processes we will parse it for the desired
* process name. First we will the number of running processes. We can determine
* the number of processes running because there is a kinfo_proc structure for each process.
*/
NumberOfRunningProcesses = sizeOfBufferRequired / sizeof(struct kinfo_proc);
/* Now we will go through each process description checking to see if the process name matches that
* passed to us. The BSDProcessInformationStructure has an array of kinfo_procs. Each kinfo_proc has
* an extern_proc accociated with it in the kp_proc attribute. Each extern_proc (kp_proc) has the process name
* of the process accociated with it in the p_comm attribute and the PID of that process in the p_pid attibute.
* We test the process name by compairing the process name passed to us with the value in the p_comm value.
* Note we limit the compairison to MAXCOMLEN which is the maximum length of a BSD process name which is used
* by the system.
*/
for (Counter = 0 ; Counter < NumberOfRunningProcesses ; Counter++)
{
//Getting PID of process we are examining
CurrentExaminedProcessPID = BSDProcessInformationStructure[Counter].kp_proc.p_pid;
//Getting name of process we are examining
CurrentExaminedProcessName = BSDProcessInformationStructure[Counter].kp_proc.p_comm;
if ((CurrentExaminedProcessPID > 0) //Valid PID
&& ((strncmp(CurrentExaminedProcessName, ProcessName, MAXCOMLEN) == 0))) //name matches
{
// --- Got a match add it to the array if possible --- //
if ((*NumberOfMatchesFound + 1) > NumberOfPossiblePIDsInArray)
{
//if we overran the array buffer passed we release the allocated buffer give an error.
free(BSDProcessInformationStructure);
return(kPIDBufferOverrunError);
}
//adding the value to the array.
ArrayOfReturnedPIDs[*NumberOfMatchesFound] = CurrentExaminedProcessPID;
//incrementing our number of matches found.
*NumberOfMatchesFound = *NumberOfMatchesFound + 1;
}
}//end looking through process list
free(BSDProcessInformationStructure); //done with allocated buffer so release.
if (*NumberOfMatchesFound == 0)
{
//didn't find any matches return error.
return(kCouldNotFindRequestedProcess);
}
else
{
//found matches return success.
return(kSuccess);
}
}
/*****************************************************
* GetPIDForProcessName
*****************************************************
* Purpose: A convience call for GetAllPIDsForProcessName().
* This function looks up a process PID given a BSD process
* name.
*
* Parameters:
* ProcessName A constant C-string. On calling
* GetPIDForProcessName this variable holds the BSD process name
* used to do the process lookup. Note that the process name you need
* to pass is the name of the BSD executable process. If trying
* to find the PID of an regular OSX application you will need to pass the
* name of the actual BSD executable inside an application bundle (rather
* than the bundle name itself). In any case as a user you can find the
* BSD process name of any process (including OSX applications) by
* typing the command "ps -axcocommand,pid" in terminal.
*
* *Function Result* A integer return value.
* See result codes listed below.
* Result Codes:
* >0 Success. The value returned is the PID of the
* matching process.
* -1 Error getting PID for requested process. This error can
* be caused by several things. One is if no such process exists.
* Another is if more than one process has the given name. The
* thing to do here is to call GetAllPIDsForProcessName()
* for complete error code or to get PIDs if there are multiple
* processes with that name.
*****************************************************/
int GetPIDForProcessName(const char* ProcessName)
{
pid_t PIDArray[1] = {0};
int Error = 0;
int NumberOfMatches = 0;
/* Here we are calling the function GetAllPIDsForProcessName which wil give us the PIDs
* of the process name we pass. Of course here we are hoping for a single PID return.
* First Argument: The BSD process name of the process we want to lookup. In this case the
* the process name passed to us.
* Second Argument: A preallocated array of pid_t. This is where the PIDs of matching processes
* will be placed on return. We pass the array we just allocated which is length one.
* Third Argument: The number of pid_t entries located in the array of pid_t (argument 2). In this
* case our array has one pid_t entry so pass one.
* Forth Argument: On return this will hold the number of PIDs placed into the
* pid_t array (array passed in argument 2).
* Fifth Argument: Passing NULL to ignore this argument.
* Return Value: An error indicating success (zero result) or failure (non-zero).
*
*/
Error = GetAllPIDsForProcessName(ProcessName, PIDArray, 1, &NumberOfMatches, NULL);
if ((Error == 0) && (NumberOfMatches == 1))//success!
{
return((int) PIDArray[0]); //return the one PID we found.
}
else
{
return(-1);
}
}

169
source/GetPID.h Executable file
View File

@ -0,0 +1,169 @@
/*
File: GetPID.h
Description: This file defines a simple API to do process PID lookup based on process name.
Author: Chad Jones
Copyright: © Copyright 2003 Apple Computer, Inc. All rights reserved.
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
("Apple") in consideration of your agreement to the following terms, and your
use, installation, modification or redistribution of this Apple software
constitutes acceptance of these terms. If you do not agree with these terms,
please do not use, install, modify or redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and subject
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
copyrights in this original Apple software (the "Apple Software"), to use,
reproduce, modify and redistribute the Apple Software, with or without
modifications, in source and/or binary forms; provided that if you redistribute
the Apple Software in its entirety and without modifications, you must retain
this notice and the following text and disclaimers in all such redistributions of
the Apple Software. Neither the name, trademarks, service marks or logos of
Apple Computer, Inc. may be used to endorse or promote products derived from the
Apple Software without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or implied,
are granted by Apple herein, including but not limited to any patent rights that
may be infringed by your derivative works or by other works in which the Apple
Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
*/
#if !defined(__DTSSampleCode_GetPID__)
#define __DTSSampleCode_GetPID__ 1
#include <stdlib.h>
#include <stdio.h>
#if defined(__cplusplus)
extern "C" {
#endif
// --- Defining constants for use with sample code --- //
enum {kSuccess = 0,
kCouldNotFindRequestedProcess = -1,
kInvalidArgumentsError = -2,
kErrorGettingSizeOfBufferRequired = -3,
kUnableToAllocateMemoryForBuffer = -4,
kPIDBufferOverrunError = -5};
/*****************************************************
* GetAllPIDsForProcessName
*****************************************************
* Purpose: This functions purpose is to lookup a BSD
* process PID given the BSD process name. This function may
* potentially return multiple PIDs for a given BSD process name
* since several processes can have the same BSD process name.
*
* Parameters:
* ProcessName A constant C-string. On calling
* GetAllPIDsForProcessName this variable holds the BSD process name
* used to do the process lookup. Note that the process name you need
* to pass is the name of the BSD executable process. If trying
* to find the PID of an regular OSX application you will need to pass the
* name of the actual BSD executable inside an application bundle (rather
* than the bundle name itself). In any case as a user you can find the
* BSD process name of any process (including OSX applications) by
* typing the command "ps -axcocommand,pid" in terminal.
*
* ArrayOfReturnedPIDs A pointer to a pre-allocated array of pid_t.
* On calling GetAllPIDsForProcessName this variable must be a pointer to a
* pre-allocated array of pid_t whos length (in number of pid_t entries) is defined
* in ArrayOfPIDsLength. On successful return from GetAllPIDsForProcessName
* this array will hold the PIDs of all processes which have a matching process
* name to that specified in the ProcessName input variable. The number of actual
* PIDs entered in the array starting at index zero will be the value returned
* in NumberOfMatchesFound. On failed return if the error is a buffer overflow
* error then the buffer will be filled to the max with PIDs which matched.
* Otherwise on failed return the state of the array will be undefined.
*
* NumberOfPossiblePIDsInArray A unsigned integer. On calling
* GetAllPIDsForProcessName this variable will hold the number of
* pre-allocated PID entries which are in the ArrayOfReturnedPIDs for this functions
* use. Note this value must have a value greater than zero.
*
* NumberOfMatchesFound An unsigned integer. On calling GetAllPIDsForProcessName
* this variable will point to a pre-allocated unsigned integer. On return from
* GetAllPIDsForProcessName this variable will contain the number of PIDs contained in the
* ArrayOfReturnedPIDs. On failed return the value of the variable will be undefined.
*
* SysctlError A pointer to a pre-allocated integer. On failed return, this
* variable represents the error returned from the sysctl command. On function
* success this variable will have a value specified by the sysctl based on the
* error that occurred. On success the variable will have the value zero.
* Note this variable can also be NULL in which case the variable is ignored.
*
* *Function Result* A integer return value.
* See result codes listed below.
* Result Codes:
* 0 Success. A set of process PIDs were found and are located in
* ArrayOfReturnedPIDs array.
* -1 Could not find a process with a matching process name
* (i.e. process not found).
* -2 Invalid arguments passed.
* -3 Unable to get the size of sysctl buffer required
* (consult SysctlError return value for more information)
* -4 Unable to allocate memory to store BSD process information
* (consult SysctlError return value for more information)
* -5 The array passed to hold the returned PIDs is not large enough
* to hold all PIDs of process with matching names.
*
*****************************************************/
int GetAllPIDsForProcessName(const char* ProcessName,
pid_t ArrayOfReturnedPIDs[],
const unsigned int NumberOfPossiblePIDsInArray,
unsigned int* NumberOfMatchesFound,
int* SysctlError); //Can be NULL
/*****************************************************
* GetPIDForProcessName
*****************************************************
* Purpose: A convience call for GetAllPIDsForProcessName().
* This function looks up a process PID given a BSD process
* name.
*
* Parameters:
* ProcessName A constant C-string. On calling
* GetPIDForProcessName this variable holds the BSD process name
* used to do the process lookup. Note that the process name you need
* to pass is the name of the BSD executable process. If trying
* to find the PID of an regular OSX application you will need to pass the
* name of the actual BSD executable inside an application bundle (rather
* than the bundle name itself). In any case as a user you can find the
* BSD process name of any process (including OSX applications) by
* typing the command "ps -axcocommand,pid" in terminal.
*
* *Function Result* A integer return value.
* See result codes listed below.
* Result Codes:
* >=0 Success. The value returned is the PID of the
* requested process.
* -1 Error getting PID for requested process. This error can
* be caused by several things. One is if no such process exists.
* Another is if more than one process has the given name. The
* Answer is to call GetAllPIDsForProcessName()
* for complete error code or to get PIDs if there are multiple
* processes with that name.
*****************************************************/
int GetPIDForProcessName(const char* ProcessName);
#if defined(__cplusplus)
}
#endif
#endif

981
source/S3Decompression.cpp Executable file
View File

@ -0,0 +1,981 @@
#include "S3Decompression.h"
typedef UInt32 DWORD;
typedef UInt16 WORD;
typedef UInt8 BYTE;
#if UNITY_OSX
#define BigEndian 1
#else
#define BigEndian 0
#endif
struct DXTColBlock
{
WORD col0;
WORD col1;
// no bit fields - use bytes
BYTE row[4];
};
struct DXTAlphaBlockExplicit
{
WORD row[4];
};
struct DXTAlphaBlock3BitLinear
{
BYTE alpha0;
BYTE alpha1;
BYTE stuff[6];
};
#if BigEndian
// use cast to struct instead of RGBA_MAKE as struct is
// much
struct Color8888
{
BYTE a;
BYTE b; // Last one is MSB, 1st is LSB.
BYTE g; // order of the output ARGB or BGRA, etc...
BYTE r; // change the order of names to change the
};
static inline void ByteSwap(UInt16& i)
{
i = static_cast<UInt16>((i << 8) | (i >> 8));
}
struct Color565
{
unsigned nBlue : 5; // order of names changes
unsigned nGreen : 6; // byte order of output to 32 bit
unsigned nRed : 5;
};
#else
static inline void ByteSwap(UInt16& i) { }
// use cast to struct instead of RGBA_MAKE as struct is
// much
struct Color8888
{
BYTE r; // change the order of names to change the
BYTE g; // order of the output ARGB or BGRA, etc...
BYTE b; // Last one is MSB, 1st is LSB.
BYTE a;
};
struct Color565
{
unsigned nBlue : 5; // order of names changes
unsigned nGreen : 6; // byte order of output to 32 bit
unsigned nRed : 5;
};
#endif
inline void GetColorBlockColors( DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1,
Color8888 * col_2, Color8888 * col_3,
WORD & wrd )
{
// There are 4 methods to use - see the Time_ functions.
// 1st = shift = does normal approach per byte for color comps
// 2nd = use freak variable bit field color565 for component extraction
// 3rd = use super-freak DWORD adds BEFORE shifting the color components
// This lets you do only 1 add per color instead of 3 BYTE adds and
// might be faster
// Call RunTimingSession() to run each of them & output result to txt file
// freak variable bit structure method
// normal math
// This method is fastest
WORD col0 = pBlock->col0;
ByteSwap (col0);
WORD col1 = pBlock->col1;
ByteSwap (col1);
Color565 * pCol;
pCol = (Color565*) & (col0 );
col_0->a = 0xff;
col_0->r = pCol->nRed;
col_0->r <<= 3; // shift to full precision
col_0->g = pCol->nGreen;
col_0->g <<= 2;
col_0->b = pCol->nBlue;
col_0->b <<= 3;
pCol = (Color565*) & (col1 );
col_1->a = 0xff;
col_1->r = pCol->nRed;
col_1->r <<= 3; // shift to full precision
col_1->g = pCol->nGreen;
col_1->g <<= 2;
col_1->b = pCol->nBlue;
col_1->b <<= 3;
if( col0 > col1 )
{
// Four-color block: derive the other two colors.
// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
// These two bit codes correspond to the 2-bit fields
// stored in the 64-bit block.
wrd = ((WORD)col_0->r * 2 + (WORD)col_1->r )/3;
// no +1 for rounding
// as bits have been shifted to 888
col_2->r = (BYTE)wrd;
wrd = ((WORD)col_0->g * 2 + (WORD)col_1->g )/3;
col_2->g = (BYTE)wrd;
wrd = ((WORD)col_0->b * 2 + (WORD)col_1->b )/3;
col_2->b = (BYTE)wrd;
col_2->a = 0xff;
wrd = ((WORD)col_0->r + (WORD)col_1->r *2 )/3;
col_3->r = (BYTE)wrd;
wrd = ((WORD)col_0->g + (WORD)col_1->g *2 )/3;
col_3->g = (BYTE)wrd;
wrd = ((WORD)col_0->b + (WORD)col_1->b *2 )/3;
col_3->b = (BYTE)wrd;
col_3->a = 0xff;
}
else
{
// Three-color block: derive the other color.
// 00 = color_0, 01 = color_1, 10 = color_2,
// 11 = transparent.
// These two bit codes correspond to the 2-bit fields
// stored in the 64-bit block.
// explicit for each component, unlike some refrasts...
// TRACE("block has alpha\n");
wrd = ((WORD)col_0->r + (WORD)col_1->r )/2;
col_2->r = (BYTE)wrd;
wrd = ((WORD)col_0->g + (WORD)col_1->g )/2;
col_2->g = (BYTE)wrd;
wrd = ((WORD)col_0->b + (WORD)col_1->b )/2;
col_2->b = (BYTE)wrd;
col_2->a = 0xff;
col_3->r = 0x00; // random color to indicate alpha
col_3->g = 0xff;
col_3->b = 0xff;
col_3->a = 0x00;
}
} // Get color block colors (...)
inline void DecodeColorBlock( DWORD * pImPos, DXTColBlock * pColorBlock, int width,
DWORD * col_0,
DWORD * col_1, DWORD * col_2, DWORD * col_3 )
{
// width is width of image in pixels
DWORD bits;
int r,n;
// bit masks = 00000011, 00001100, 00110000, 11000000
const DWORD masks[] = { 3, 12, 3 << 4, 3 << 6 };
const int shift[] = { 0, 2, 4, 6 };
// r steps through lines in y
for( r=0; r < 4; r++, pImPos += width-4 ) // no width*4 as DWORD ptr inc will *4
{
// width * 4 bytes per pixel per line
// each j dxtc row is 4 lines of pixels
// pImPos = (DWORD*)((DWORD)pBase + i*16 + (r+j*4) * m_nWidth * 4 );
// n steps through pixels
for( n=0; n < 4; n++ )
{
bits = pColorBlock->row[r] & masks[n];
bits >>= shift[n];
// AssertIf (bits < 0 || bits > 3);
switch( bits )
{
case 0 :
*pImPos = *col_0;
pImPos++; // increment to next DWORD
break;
case 1 :
*pImPos = *col_1;
pImPos++;
break;
case 2 :
*pImPos = *col_2;
pImPos++;
break;
case 3 :
*pImPos = *col_3;
pImPos++;
break;
}
}
}
}
inline void DecodeAlphaExplicit( DWORD * pImPos, DXTAlphaBlockExplicit * pAlphaBlock,
int width, DWORD alphazero )
{
// alphazero is a bit mask that when & with the image color
// will zero the alpha bits, so if the image DWORDs are
// ARGB then alphazero will be 0x00ffffff or if
// RGBA then alphazero will be 0xffffff00
// alphazero constructed automaticaly from field order of Color8888 structure
// decodes to 32 bit format only
int row, pix;
WORD wrd;
Color8888 col;
col.r = col.g = col.b = 0;
//TRACE("\n");
for( row=0; row < 4; row++, pImPos += width-4 )
{
// pImPow += pImPos += width-4 moves to next row down
wrd = pAlphaBlock->row[ row ];
ByteSwap (wrd);
// TRACE("0x%.8x\t\t", wrd);
for( pix = 0; pix < 4; pix++ )
{
// zero the alpha bits of image pixel
*pImPos &= alphazero;
col.a = wrd & 0x000f; // get only low 4 bits
// col.a <<= 4; // shift to full byte precision
// NOTE: with just a << 4 you'll never have alpha
// of 0xff, 0xf0 is max so pure shift doesn't quite
// cover full alpha range.
// It's much cheaper than divide & scale though.
// To correct for this, and get 0xff for max alpha,
// or the low bits back in after left shifting
col.a = col.a | (col.a << 4 ); // This allows max 4 bit alpha to be 0xff alpha
// in final image, and is crude approach to full
// range scale
*pImPos |= *((DWORD*)&col); // or the bits into the prev. nulled alpha
wrd >>= 4; // move next bits to lowest 4
pImPos++; // move to next pixel in the row
}
}
}
BYTE gBits[4][4];
WORD gAlphas[8];
Color8888 gACol[4][4];
inline void DecodeAlpha3BitLinear( DWORD * pImPos, DXTAlphaBlock3BitLinear * pAlphaBlock,
int width, DWORD alphazero)
{
gAlphas[0] = pAlphaBlock->alpha0;
gAlphas[1] = pAlphaBlock->alpha1;
// 8-alpha or 6-alpha block?
if( gAlphas[0] > gAlphas[1] )
{
// 8-alpha block: derive the other 6 alphas.
// 000 = alpha_0, 001 = alpha_1, others are interpolated
gAlphas[2] = ( 6 * gAlphas[0] + gAlphas[1]) / 7; // bit code 010
gAlphas[3] = ( 5 * gAlphas[0] + 2 * gAlphas[1]) / 7; // Bit code 011
gAlphas[4] = ( 4 * gAlphas[0] + 3 * gAlphas[1]) / 7; // Bit code 100
gAlphas[5] = ( 3 * gAlphas[0] + 4 * gAlphas[1]) / 7; // Bit code 101
gAlphas[6] = ( 2 * gAlphas[0] + 5 * gAlphas[1]) / 7; // Bit code 110
gAlphas[7] = ( gAlphas[0] + 6 * gAlphas[1]) / 7; // Bit code 111
}
else
{
// 6-alpha block: derive the other alphas.
// 000 = alpha_0, 001 = alpha_1, others are interpolated
gAlphas[2] = (4 * gAlphas[0] + gAlphas[1]) / 5; // Bit code 010
gAlphas[3] = (3 * gAlphas[0] + 2 * gAlphas[1]) / 5; // Bit code 011
gAlphas[4] = (2 * gAlphas[0] + 3 * gAlphas[1]) / 5; // Bit code 100
gAlphas[5] = ( gAlphas[0] + 4 * gAlphas[1]) / 5; // Bit code 101
gAlphas[6] = 0; // Bit code 110
gAlphas[7] = 255; // Bit code 111
}
// Decode 3-bit fields into array of 16 BYTES with same value
// first two rows of 4 pixels each:
// pRows = (Alpha3BitRows*) & ( pAlphaBlock->stuff[0] );
const DWORD mask = 0x00000007; // bits = 00 00 01 11
DWORD bits = *( (DWORD*) & ( pAlphaBlock->stuff[0] ));
gBits[0][0] = (BYTE)( bits & mask );
bits >>= 3;
gBits[0][1] = (BYTE)( bits & mask );
bits >>= 3;
gBits[0][2] = (BYTE)( bits & mask );
bits >>= 3;
gBits[0][3] = (BYTE)( bits & mask );
bits >>= 3;
gBits[1][0] = (BYTE)( bits & mask );
bits >>= 3;
gBits[1][1] = (BYTE)( bits & mask );
bits >>= 3;
gBits[1][2] = (BYTE)( bits & mask );
bits >>= 3;
gBits[1][3] = (BYTE)( bits & mask );
// now for last two rows:
bits = *( (DWORD*) & ( pAlphaBlock->stuff[3] )); // last 3 bytes
gBits[2][0] = (BYTE)( bits & mask );
bits >>= 3;
gBits[2][1] = (BYTE)( bits & mask );
bits >>= 3;
gBits[2][2] = (BYTE)( bits & mask );
bits >>= 3;
gBits[2][3] = (BYTE)( bits & mask );
bits >>= 3;
gBits[3][0] = (BYTE)( bits & mask );
bits >>= 3;
gBits[3][1] = (BYTE)( bits & mask );
bits >>= 3;
gBits[3][2] = (BYTE)( bits & mask );
bits >>= 3;
gBits[3][3] = (BYTE)( bits & mask );
// decode the codes into alpha values
int row, pix;
for( row = 0; row < 4; row++ )
{
for( pix=0; pix < 4; pix++ )
{
gACol[row][pix].a = (BYTE) gAlphas[ gBits[row][pix] ];
// AssertIf( gACol[row][pix].r != 0 );
// AssertIf( gACol[row][pix].g != 0 );
// AssertIf( gACol[row][pix].b == 0 );
}
}
// Write out alpha values to the image bits
for( row=0; row < 4; row++, pImPos += width-4 )
{
// pImPow += pImPos += width-4 moves to next row down
for( pix = 0; pix < 4; pix++ )
{
// zero the alpha bits of image pixel
*pImPos &= alphazero;
*pImPos |= *((DWORD*) &(gACol[row][pix])); // or the bits into the prev. nulled alpha
pImPos++;
}
}
}
void DecompressDXT1(int width, int height, DWORD* m_pCompBytes, DWORD* m_pDecompBytes)
{
// This was hacked up pretty quick & slopily
// decompresses to 32 bit format 0xARGB
int xblocks, yblocks;
xblocks = width / 4;
yblocks = height / 4;
int i,j;
DWORD * pBase = (DWORD*) m_pDecompBytes;
DWORD * pImPos = (DWORD*) pBase; // pos in decompressed data
WORD * pPos = (WORD*) m_pCompBytes; // pos in compressed data
DXTColBlock * pBlock;
Color8888 col_0, col_1, col_2, col_3;
WORD wrd;
for( j=0; j < yblocks; j++ )
{
// 8 bytes per block
pBlock = (DXTColBlock*) ( (DWORD)m_pCompBytes + j * xblocks * 8 );
for( i=0; i < xblocks; i++, pBlock++ )
{
// inline func:
GetColorBlockColors( pBlock, &col_0, &col_1, &col_2, &col_3, wrd );
// now decode the color block into the bitmap bits
// inline func:
pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * width * 4 );
DecodeColorBlock( pImPos, pBlock, width, (DWORD*)&col_0, (DWORD*)&col_1,
(DWORD*)&col_2, (DWORD*)&col_3 );
// Set to RGB test pattern
// pImPos = (DWORD*)((DWORD)pBase + i*4 + j*m_nWidth*4);
// *pImPos = ((i*4) << 16) | ((j*4) << 8 ) | ( (63-i)*4 );
// checkerboard of only col_0 and col_1 basis colors:
// pImPos = (DWORD*)((DWORD)pBase + i*8 + j*m_nWidth*8);
// *pImPos = *((DWORD*)&col_0);
// pImPos += 1 + m_nWidth;
// *pImPos = *((DWORD*)&col_1);
}
}
}
void DecompressDXT3(int width, int height, DWORD* m_pCompBytes, DWORD* m_pDecompBytes)
{
int xblocks, yblocks;
xblocks = width / 4;
yblocks = height / 4;
int i,j;
DWORD * pBase = (DWORD*) m_pDecompBytes;
DWORD * pImPos = (DWORD*) pBase; // pos in decompressed data
WORD * pPos = (WORD*) m_pCompBytes; // pos in compressed data
DXTColBlock * pBlock;
DXTAlphaBlockExplicit * pAlphaBlock;
Color8888 col_0, col_1, col_2, col_3;
WORD wrd;
// fill alphazero with appropriate value to zero out alpha when
// alphazero is ANDed with the image color 32 bit DWORD:
col_0.a = 0;
col_0.r = col_0.g = col_0.b = 0xff;
DWORD alphazero = *((DWORD*) &col_0);
for( j=0; j < yblocks; j++ )
{
// 8 bytes per block
// 1 block for alpha, 1 block for color
pBlock = (DXTColBlock*) ( (DWORD)m_pCompBytes + j * xblocks * 16 );
for( i=0; i < xblocks; i++, pBlock ++ )
{
// inline
// Get alpha block
pAlphaBlock = (DXTAlphaBlockExplicit*) pBlock;
// inline func:
// Get color block & colors
pBlock++;
GetColorBlockColors( pBlock, &col_0, &col_1, &col_2, &col_3, wrd );
// Decode the color block into the bitmap bits
// inline func:
pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * width * 4 );
DecodeColorBlock( pImPos, pBlock, width, (DWORD*)&col_0, (DWORD*)&col_1,
(DWORD*)&col_2, (DWORD*)&col_3 );
// Overwrite the previous alpha bits with the alpha block
// info
// inline func:
DecodeAlphaExplicit( pImPos, pAlphaBlock, width, alphazero );
}
}
}
void DecompressDXT5(int width, int height, DWORD* m_pCompBytes, DWORD* m_pDecompBytes)
{
int xblocks, yblocks;
xblocks = width / 4;
yblocks = height / 4;
int i,j;
DWORD * pBase = (DWORD*) m_pDecompBytes;
DWORD * pImPos = (DWORD*) pBase; // pos in decompressed data
WORD * pPos = (WORD*) m_pCompBytes; // pos in compressed data
DXTColBlock * pBlock;
DXTAlphaBlock3BitLinear * pAlphaBlock;
Color8888 col_0, col_1, col_2, col_3;
WORD wrd;
// fill alphazero with appropriate value to zero out alpha when
// alphazero is ANDed with the image color 32 bit DWORD:
col_0.a = 0;
col_0.r = col_0.g = col_0.b = 0xff;
DWORD alphazero = *((DWORD*) &col_0);
////////////////////////////////
// TRACE("blocks: x: %d y: %d\n", xblocks, yblocks );
for( j=0; j < yblocks; j++ )
{
// 8 bytes per block
// 1 block for alpha, 1 block for color
pBlock = (DXTColBlock*) ( (DWORD)m_pCompBytes + j * xblocks * 16 );
for( i=0; i < xblocks; i++, pBlock ++ )
{
// inline
// Get alpha block
pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock;
// inline func:
// Get color block & colors
pBlock++;
GetColorBlockColors( pBlock, &col_0, &col_1, &col_2, &col_3, wrd );
// Decode the color block into the bitmap bits
// inline func:
pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * width * 4 );
DecodeColorBlock( pImPos, pBlock, width, (DWORD*)&col_0, (DWORD*)&col_1,
(DWORD*)&col_2, (DWORD*)&col_3 );
// Overwrite the previous alpha bits with the alpha block
// info
DecodeAlpha3BitLinear( pImPos, pAlphaBlock, width, alphazero );
}
}
} // dxt5
/*
inline void GetColorBlockColors_m2( DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1,
Color8888 * col_2, Color8888 * col_3,
WORD & wrd )
{
// method 2
// freak variable bit structure method
// normal math
Color565 * pCol;
pCol = (Color565*) & (pBlock->col0 );
col_0->a = 0xff;
col_0->r = pCol->nRed;
col_0->r <<= 3; // shift to full precision
col_0->g = pCol->nGreen;
col_0->g <<= 2;
col_0->b = pCol->nBlue;
col_0->b <<= 3;
pCol = (Color565*) & (pBlock->col1 );
col_1->a = 0xff;
col_1->r = pCol->nRed;
col_1->r <<= 3; // shift to full precision
col_1->g = pCol->nGreen;
col_1->g <<= 2;
col_1->b = pCol->nBlue;
col_1->b <<= 3;
if( pBlock->col0 > pBlock->col1 )
{
// Four-color block: derive the other two colors.
// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
// These two bit codes correspond to the 2-bit fields
// stored in the 64-bit block.
wrd = ((WORD)col_0->r * 2 + (WORD)col_1->r )/3;
// no +1 for rounding
// as bits have been shifted to 888
col_2->r = (BYTE)wrd;
wrd = ((WORD)col_0->g * 2 + (WORD)col_1->g )/3;
col_2->g = (BYTE)wrd;
wrd = ((WORD)col_0->b * 2 + (WORD)col_1->b )/3;
col_2->b = (BYTE)wrd;
col_2->a = 0xff;
wrd = ((WORD)col_0->r + (WORD)col_1->r *2 )/3;
col_3->r = (BYTE)wrd;
wrd = ((WORD)col_0->g + (WORD)col_1->g *2 )/3;
col_3->g = (BYTE)wrd;
wrd = ((WORD)col_0->b + (WORD)col_1->b *2 )/3;
col_3->b = (BYTE)wrd;
col_3->a = 0xff;
}
else
{
// Three-color block: derive the other color.
// 00 = color_0, 01 = color_1, 10 = color_2,
// 11 = transparent.
// These two bit codes correspond to the 2-bit fields
// stored in the 64-bit block.
// explicit for each component, unlike some refrasts...
// TRACE("block has alpha\n");
wrd = ((WORD)col_0->r + (WORD)col_1->r )/2;
col_2->r = (BYTE)wrd;
wrd = ((WORD)col_0->g + (WORD)col_1->g )/2;
col_2->g = (BYTE)wrd;
wrd = ((WORD)col_0->b + (WORD)col_1->b )/2;
col_2->b = (BYTE)wrd;
col_2->a = 0xff;
col_3->r = 0x00; // random color to indicate alpha
col_3->g = 0xff;
col_3->b = 0xff;
col_3->a = 0x00;
}
}
*/
/*
inline void GetColorBlockColors_m3( DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1,
Color8888 * col_2, Color8888 * col_3,
WORD & wrd )
{
// method 3
//////////////////////////////////////////////////////
// super-freak variable bit structure with
// Cool Math Trick (tm)
// Do 2/3 1/3 math BEFORE bit shift on the whole DWORD
// as the fields will NEVER carry into the next
// or overflow!! =)
Color565 * pCol;
pCol = (Color565*) & (pBlock->col0 );
col_0->a = 0x00; // must set to 0 to avoid overflow in DWORD add
col_0->r = pCol->nRed;
col_0->g = pCol->nGreen;
col_0->b = pCol->nBlue;
pCol = (Color565*) & (pBlock->col1 );
col_1->a = 0x00;
col_1->r = pCol->nRed;
col_1->g = pCol->nGreen;
col_1->b = pCol->nBlue;
if( pBlock->col0 > pBlock->col1 )
{
*((DWORD*)col_2) = ( (*((DWORD*)col_0)) * 2 + (*((DWORD*)col_1)) );
*((DWORD*)col_3) = ( (*((DWORD*)col_0)) + (*((DWORD*)col_1)) * 2 );
// now shift to appropriate precision & divide by 3.
col_2->r = ((WORD)col_2->r << 3) / (WORD)3;
col_2->g = ((WORD)col_2->g << 2) / (WORD)3;
col_2->b = ((WORD)col_2->b << 3) / (WORD)3;
col_3->r = ((WORD)col_3->r << 3) / (WORD)3;
col_3->g = ((WORD)col_3->g << 2) / (WORD)3;
col_3->b = ((WORD)col_3->b << 3) / (WORD)3;
col_0->a = 0xff; // now set appropriate alpha
col_1->a = 0xff;
col_2->a = 0xff;
col_3->a = 0xff;
}
else
{
*((DWORD*)col_2) = ( (*((DWORD*)col_0)) + (*((DWORD*)col_1)) );
// now shift to appropriate precision & divide by 2.
// << 3 ) / 2 == << 2
// << 2 ) / 2 == << 1
col_2->r = ((WORD)col_2->r << 2);
col_2->g = ((WORD)col_2->g << 1);
col_2->b = ((WORD)col_2->b << 2);
col_2->a = 0xff;
col_3->a = 0x00; //
col_3->r = 0x00; // random color to indicate alpha
col_3->g = 0xff;
col_3->b = 0xff;
}
// now shift orig color components
col_0->r <<= 3;
col_0->g <<= 2;
col_0->b <<= 3;
col_1->r <<= 3;
col_1->g <<= 2;
col_1->b <<= 3;
}
*/
/*
inline void GetColorBlockColors_m4( DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1,
Color8888 * col_2, Color8888 * col_3,
WORD & wrd )
{
// m1 color extraction from 5-6-5
// m3 color math on DWORD before bit shift to full precision
wrd = pBlock->col0;
col_0->a = 0x00; // must set to 0 to avoid possible overflow & carry to next field in DWORD add
// extract r,g,b bits
col_0->b = (unsigned char) wrd & 0x1f; // 0x1f = 0001 1111 to mask out upper 3 bits
wrd >>= 5;
col_0->g = (unsigned char) wrd & 0x3f; // 0x3f = 0011 1111 to mask out upper 2 bits
wrd >>= 6;
col_0->r = (unsigned char) wrd & 0x1f;
// same for col # 2:
wrd = pBlock->col1;
col_1->a = 0x00; // must set to 0 to avoid possible overflow in DWORD add
// extract r,g,b bits
col_1->b = (unsigned char) wrd & 0x1f;
wrd >>= 5;
col_1->g = (unsigned char) wrd & 0x3f;
wrd >>= 6;
col_1->r = (unsigned char) wrd & 0x1f;
if( pBlock->col0 > pBlock->col1 )
{
*((DWORD*)col_2) = ( (*((DWORD*)col_0)) * 2 + (*((DWORD*)col_1)) );
*((DWORD*)col_3) = ( (*((DWORD*)col_0)) + (*((DWORD*)col_1)) * 2 );
// shift to appropriate precision & divide by 3.
col_2->r = ((WORD)col_2->r << 3) / (WORD)3;
col_2->g = ((WORD)col_2->g << 2) / (WORD)3;
col_2->b = ((WORD)col_2->b << 3) / (WORD)3;
col_3->r = ((WORD)col_3->r << 3) / (WORD)3;
col_3->g = ((WORD)col_3->g << 2) / (WORD)3;
col_3->b = ((WORD)col_3->b << 3) / (WORD)3;
col_0->a = 0xff; // set appropriate alpha
col_1->a = 0xff;
col_2->a = 0xff;
col_3->a = 0xff;
}
else
{
*((DWORD*)col_2) = ( (*((DWORD*)col_0)) + (*((DWORD*)col_1)) );
// shift to appropriate precision & divide by 2.
// << 3 ) / 2 == << 2
// << 2 ) / 2 == << 1
col_2->r = ((WORD)col_2->r << 2);
col_2->g = ((WORD)col_2->g << 1);
col_2->b = ((WORD)col_2->b << 2);
col_2->a = 0xff;
col_3->a = 0x00; //
col_3->r = 0x00; // random color to indicate alpha
col_3->g = 0xff;
col_3->b = 0xff;
}
// shift orig color components to full precision
col_0->r <<= 3;
col_0->g <<= 2;
col_0->b <<= 3;
col_1->r <<= 3;
col_1->g <<= 2;
col_1->b <<= 3;
}
*/
/*
inline void GetColorBlockColors_m1( DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1,
Color8888 * col_2, Color8888 * col_3,
WORD & wrd )
{
// Method 1:
// Shifty method
wrd = pBlock->col0;
col_0->a = 0xff;
// extract r,g,b bits
col_0->b = (unsigned char) wrd;
col_0->b <<= 3; // shift to full precision
wrd >>= 5;
col_0->g = (unsigned char) wrd;
col_0->g <<= 2; // shift to full precision
wrd >>= 6;
col_0->r = (unsigned char) wrd;
col_0->r <<= 3; // shift to full precision
// same for col # 2:
wrd = pBlock->col1;
col_1->a = 0xff;
// extract r,g,b bits
col_1->b = (unsigned char) wrd;
col_1->b <<= 3; // shift to full precision
wrd >>= 5;
col_1->g = (unsigned char) wrd;
col_1->g <<= 2; // shift to full precision
wrd >>= 6;
col_1->r = (unsigned char) wrd;
col_1->r <<= 3; // shift to full precision
// use this for all but the super-freak math method
if( pBlock->col0 > pBlock->col1 )
{
// Four-color block: derive the other two colors.
// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
// These two bit codes correspond to the 2-bit fields
// stored in the 64-bit block.
wrd = ((WORD)col_0->r * 2 + (WORD)col_1->r )/3;
// no +1 for rounding
// as bits have been shifted to 888
col_2->r = (BYTE)wrd;
wrd = ((WORD)col_0->g * 2 + (WORD)col_1->g )/3;
col_2->g = (BYTE)wrd;
wrd = ((WORD)col_0->b * 2 + (WORD)col_1->b )/3;
col_2->b = (BYTE)wrd;
col_2->a = 0xff;
wrd = ((WORD)col_0->r + (WORD)col_1->r *2 )/3;
col_3->r = (BYTE)wrd;
wrd = ((WORD)col_0->g + (WORD)col_1->g *2 )/3;
col_3->g = (BYTE)wrd;
wrd = ((WORD)col_0->b + (WORD)col_1->b *2 )/3;
col_3->b = (BYTE)wrd;
col_3->a = 0xff;
}
else
{
// Three-color block: derive the other color.
// 00 = color_0, 01 = color_1, 10 = color_2,
// 11 = transparent.
// These two bit codes correspond to the 2-bit fields
// stored in the 64-bit block.
// explicit for each component, unlike some refrasts...
// TRACE("block has alpha\n");
wrd = ((WORD)col_0->r + (WORD)col_1->r )/2;
col_2->r = (BYTE)wrd;
wrd = ((WORD)col_0->g + (WORD)col_1->g )/2;
col_2->g = (BYTE)wrd;
wrd = ((WORD)col_0->b + (WORD)col_1->b )/2;
col_2->b = (BYTE)wrd;
col_2->a = 0xff;
col_3->r = 0x00; // random color to indicate alpha
col_3->g = 0xff;
col_3->b = 0xff;
col_3->a = 0x00;
}
} // Get color block colors (...)
*/

8
source/S3Decompression.h Executable file
View File

@ -0,0 +1,8 @@
#ifndef S3DECOMPRESSION_H
#define S3DECOMPRESSION_H
void DecompressDXT1(int width, int height, UInt32* m_pCompBytes, UInt32* m_pDecompBytes);
void DecompressDXT3(int width, int height, UInt32* m_pCompBytes, UInt32* m_pDecompBytes);
void DecompressDXT5(int width, int height, UInt32* m_pCompBytes, UInt32* m_pDecompBytes);
#endif

292
source/ai.cpp Normal file
View File

@ -0,0 +1,292 @@
//ai.cpp
//the game's AI system for computer-controlled opponents
#include <math.h>
#include "entities.h"
#include "controls.h"
#include "carphysics.h"
#include "gameframe.h"
#include "roads.h"
#define kAIMaxThottleSlip 0.05
#define kAIMinSpinAngularVelo (6*PI)
#define kAIThrottleTime 0.2
#define kAIThrottleReleaseTime 0.4
#define kAIMaxBrakeSlip 0.05
#define kAIBrakeTime 0.4
#define kAIBrakeReleaseTime 0.2
#define kAIWaypointAheadDistance (gGameInfo->arcade==kGameModeTurbo?25:15)
#define kAIMaxSteering 2
float AISteering(tCarDefinition *car,tGameEntity *entity,tVector3 wayPoint,float *overSteer)
{
// Will adjust the cars steering in order to make the car head to wayPoint.
tVector3 carDir=!Vector(MatrixGetZVector(entity->dir)->x,0,MatrixGetZVector(entity->dir)->z);
tVector3 wayDir=!Vector(entity->pos.x-wayPoint.x,0,entity->pos.z-wayPoint.z);
tVector3 veloDir=(VectorZero(entity->velo)?carDir:!entity->velo);
*overSteer=(carDir%veloDir).y;
float angleSin=(carDir%wayDir).y;
if(fabs(angleSin)>1.0)
angleSin=sign(angleSin);
float angle=-asin(angleSin);
float steering=angle/car->wheels[0].maxAngle;
if(steering>kAIMaxSteering)steering=kAIMaxSteering;
if(steering<-kAIMaxSteering)steering=-kAIMaxSteering;
return steering;
}
#define kAIMinCarDistance 4
#define kAICollisionPredictPrecission 20
#define kAIMaxCollisionDelay 5.0
#define kAICarLength 2
#define kAIVeloAdd 2.0
float AIGetCollisionDelay(tGameEntity *entity,tGameEntity **obstacle)
{
tVector2 basePos1=Vector(entity->pos.x,entity->pos.z);
tVector2 velo1=Vector(entity->velo.x,entity->velo.z);
tVector2 dir1=Vector(MatrixGetZVector(entity->dir)->x,MatrixGetZVector(entity->dir)->z);
float fVelo1=~velo1;
if(fVelo1>0.1)
velo1=velo1*((1/fVelo1)*(fVelo1+kAIVeloAdd));
else
velo1=dir1*kAIVeloAdd;
int minDelay=kAICollisionPredictPrecission;
for(int i=0;i<gGameInfo->numPlayers;i++)
if(gCarEntities[i]!=entity)
{
tVector2 pos2=Vector(gCarEntities[i]->pos.x,gCarEntities[i]->pos.z);
tVector2 diff=pos2-basePos1;
if(sqr(diff)<sqr(120)&&diff*dir1>=0)
//is the other car close in front of us?
{
tVector2 pos1=basePos1;
tVector2 velo2=Vector(gCarEntities[i]->velo.x,gCarEntities[i]->velo.z);
tVector2 dir2=Vector(MatrixGetZVector(gCarEntities[i]->dir)->x,MatrixGetZVector(gCarEntities[i]->dir)->z);
for(int j=0;j<kAICollisionPredictPrecission&&j<minDelay;j++)
{
pos1=pos1+velo1*(kAIMaxCollisionDelay/kAICollisionPredictPrecission);
pos2=pos2+velo2*(kAIMaxCollisionDelay/kAICollisionPredictPrecission);
if(sqr(pos1+dir1*kAICarLength-pos2+dir2*kAICarLength)<sqr(kAIMinCarDistance))
{minDelay=j;*obstacle=gCarEntities[i];}
else if(sqr(pos1-dir1*kAICarLength-pos2+dir2*kAICarLength)<sqr(kAIMinCarDistance))
{minDelay=j;*obstacle=gCarEntities[i];}
else if(sqr(pos1+dir1*kAICarLength-pos2-dir2*kAICarLength)<sqr(kAIMinCarDistance))
{minDelay=j;*obstacle=gCarEntities[i];}
else if(sqr(pos1-dir1*kAICarLength-pos2-dir2*kAICarLength)<sqr(kAIMinCarDistance))
{minDelay=j;*obstacle=gCarEntities[i];}
}
}
}
return (minDelay+1)*(kAIMaxCollisionDelay/kAICollisionPredictPrecission);
}
//Calculate the Maximal Throttle an AI player may get, which may be more than
//100% to help the AI a little.
float AIMaxThrottle(tCarPhysics *phys)
{
if(gFrameCount*kFrameTime<kStartGameDelaySeconds)
return 1;
//"power cycle" for more random AI behavior
float base=1.0+0.25*sin((gFrameCount*kFrameTime)*0.1+phys->aiPowerCycle);
//help for players in the back of the field.
float aid=(-phys->lead-8)/22;
if(aid<0)aid=0;
if(aid>1)aid=1;
return base+aid*0.6;
}
void AIBrakeThrottle(tCarDefinition *car,tCarPhysics *phys,float velo,float optimalVelo)
{
float driveSlip=0,slip=0,angularVelo=0;
float maxThrottle=AIMaxThrottle(phys);
for(int i=0;i<car->numWheels;i++)
{
driveSlip+=phys->wheels[i].slip*car->wheels[i].powered;
slip+=phys->wheels[i].slip;
angularVelo+=fabs(phys->wheels[i].angularVelo*car->wheels[i].powered);
}
slip/=car->numWheels;
float maxSlip=velo<20?0.2-velo/20*(0.2-kAIMaxThottleSlip):kAIMaxThottleSlip;
if((driveSlip*sign(phys->gear)<maxSlip||angularVelo<kAIMinSpinAngularVelo||(phys->clutch<=1&&phys->gear<=1)) //traction control
&&velo<optimalVelo) //we don't want to drive too fast!
phys->throttle+=kFrameTime*(1/kAIThrottleTime);
else
phys->throttle-=kFrameTime*(1/kAIThrottleReleaseTime);
if(phys->throttle>maxThrottle)
phys->throttle=maxThrottle;
else if(phys->throttle<phys->idleThrottle)
phys->throttle=phys->idleThrottle;
if((velo>optimalVelo+1||optimalVelo==0))
{
if((-slip*sign(angularVelo)<kAIMaxBrakeSlip)||(phys->brake<0.1))
phys->brake+=kFrameTime*(1/kAIBrakeTime);
else
phys->brake-=kFrameTime*(1/kAIBrakeTime);
phys->arcadeBrake+=kFrameTime*(1/kAIBrakeTime);
}
else{
phys->arcadeBrake-=kFrameTime*(1/kAIBrakeReleaseTime);
phys->brake-=kFrameTime*(1/kAIBrakeReleaseTime);
}
if(phys->arcadeBrake>1)
phys->arcadeBrake=1;
else if(phys->arcadeBrake<0)
phys->arcadeBrake=0;
if(phys->brake>1)
phys->brake=1;
else if(phys->brake<0)
phys->brake=0;
}
#define kAIOvertakeRoadAnalyseDistance 50 //length of approaching road section to be evaluated for overtaking
#define kAIOvertakeMinVeloDiffPossible 10
#define kAIOvertakeAbortDistance 60
#define kAIOvertakeFinishDistance 20
#define kAIOvertakeLaneChangeTime 3.0
void AIEvaluateOvertaking(tGameEntity *overtaker,tGameEntity *obstacle,float track)
{
tCarPhysics *phys=(tCarPhysics*)overtaker->physics;
if(phys->overtaking)//are we already overtaking?
return;
if(overtaker->velo**MatrixGetZVector(overtaker->dir)<=obstacle->velo**MatrixGetZVector(overtaker->dir)) //are we faster?
return;
float minTrack,maxTrack,minSpeed;
RoadGetWayPointData(overtaker->lastRoadIndex,kAIOvertakeRoadAnalyseDistance,&minTrack,&maxTrack,&minSpeed);
if(minSpeed*0.75<~obstacle->velo+kAIOvertakeMinVeloDiffPossible) //is it possible to drive faster than obstacle all the time?
return;
// if(fabs(minTrack-maxTrack)>1)
// return;
phys->overtaking=obstacle;
phys->overtakeSide=fabs(1+minTrack)>fabs(1-maxTrack)?-1:1;
}
void ControlEntityAIInput(tGameEntity *entity)
//The game's AI - adjusts all the controls of the car passed in entity.
{
if(entity->physicsType!=kPhysicsTypeCar)//is entity really a car?
return;
tCarPhysics *phys=(tCarPhysics*)entity->physics;
tCarDefinition *car=&(phys->car);
float velo=~entity->velo;
//determine course
float optimalVelo;
float track=phys->overTakeProgress+0.4*sin((gFrameCount*kFrameTime)*0.16+phys->aiRouteCycle);
if(track<-1)track=-1;
else if(track>1)track=1;
tVector3 wayPoint=RoadGetNextWaypoint(entity->pos,&entity->lastRoadIndex,&track,&optimalVelo,kAIWaypointAheadDistance);
if(gGameInfo->arcade==kGameModeArcade||gGameInfo->arcade==kGameModeTurbo)
optimalVelo*=1.3;
if(phys->lapCount>gGameInfo->numLaps)
optimalVelo=0;
//see if we are about to crash into another car if we are to remain on our course.
tGameEntity *obstacle;
float del=AIGetCollisionDelay(entity,&obstacle);
//if we will crash into another car within the next 5 seconds, see if we can overtake
if(del<=5)
AIEvaluateOvertaking(entity,obstacle,track);
if(del>5&&phys->stuckTime>10*kFPS)
//if we are stuck, recover car.
{
RoadCenterCar(entity);
phys->overtaking=NULL;
phys->stuckTime=0;
}
//if we are overtaking
//phys->lightFlags&=~(kLightFlagLIndLight|kLightFlagRIndLight);
if(phys->overtaking)
{
if(fabs(phys->overTakeProgress)<1)
{
phys->overTakeProgress+=(1/kAIOvertakeLaneChangeTime)*kFrameTime*sign(phys->overtakeSide);
if(fabs(phys->overTakeProgress)>1)
phys->overTakeProgress=sign(phys->overTakeProgress);
/*if(phys->lapCount<=gGameInfo->numLaps)
phys->lightFlags|=(phys->overtakeSide==(gGameInfo->reverse?-1:1)?kLightFlagLIndLight:kLightFlagRIndLight);*/
}
float dist=-(phys->overtaking->pos-entity->pos)**MatrixGetZVector(entity->dir);
if(dist>kAIOvertakeFinishDistance)//are we finished overtaking?
phys->overtaking=NULL;
else if(dist<-kAIOvertakeAbortDistance)//or are we too slow to overtake?
phys->overtaking=NULL;
if(fabs(phys->overtakeSide-track)<0.5)
phys->overtaking=NULL;
}
else if(fabs(phys->overTakeProgress)>0)
{
int s=sign(phys->overTakeProgress);
phys->overTakeProgress-=(1/kAIOvertakeLaneChangeTime)*kFrameTime*s;
//if(phys->lapCount<=gGameInfo->numLaps)
//phys->lightFlags|=(s==-1?kLightFlagLIndLight:kLightFlagRIndLight);
if(s!=sign(phys->overTakeProgress))
phys->overTakeProgress=0;
}
//steering
float overSteer;
phys->steering=AISteering(car,entity,wayPoint,&overSteer);
//brake / throttle
AIBrakeThrottle(car,phys,velo,optimalVelo);
if(gFrameCount*kFrameTime>=kStartGameDelaySeconds)
{
//gear shifting / clutch control
if(phys->gear==0)
{
phys->gear=1;
phys->lastGearSwitch=gFrameCount*kFrameTime;
}
if(phys->gear>=1&&(gFrameCount-1)*kFrameTime>phys->lastGearSwitch+car->gearSwitchTime&&gFrameCount*kFrameTime>=kStartGameDelaySeconds+1.5)
{
if(phys->rpm>car->maxRPM&&phys->gear<car->numGears-2)
{
phys->gear++;
phys->lastGearSwitch=gFrameCount*kFrameTime;
}
if(phys->rpm<car->shiftDownRPM&&phys->gear>1)
{
phys->gear--;
phys->lastGearSwitch=gFrameCount*kFrameTime;
}
}
if(gFrameCount*kFrameTime<phys->lastGearSwitch+car->gearSwitchTime)
{
float switchTime=(gFrameCount*kFrameTime-phys->lastGearSwitch)/car->gearSwitchTime;
phys->clutch=switchTime;
if(phys->rpm<2000)
phys->clutch=(phys->rpm-car->idleRPM)/(2000-car->idleRPM);
if(switchTime<0.5)
phys->throttle=phys->idleThrottle;
}
else
if(phys->rpm<2000)
phys->clutch=(phys->rpm-car->idleRPM)/(2000-car->idleRPM);
else
phys->clutch=1;
}
if(overSteer*velo>20)
if(car->wheels[2].powered)
{
phys->clutch=0;
phys->throttle=0;
}
}

1338
source/carphysics.cpp Executable file

File diff suppressed because it is too large Load Diff

214
source/carphysics.h Executable file
View File

@ -0,0 +1,214 @@
#ifndef __CARPHYSICS
#define __CARPHYSICS
#include "fileio.h"
#include "vectors.h"
#include "entities.h"
#include "gameinitexit.h"
#define kMaxWheels 6
enum{
kLightFlagDriveLight=1<<0,
kLightFlagFogLight=1<<2,
kLightFlagRevLight=1<<3,
kLightFlagBrakeLight=1<<4,
kLightFlagLIndLight=1<<5,
kLightFlagRIndLight=1<<6,
kLightFlagHorn=1<<7
};
typedef struct{
tVector3 pos;
int texture;
float powered;
float maxAngle;
float maxSuspension; //m
float radius; //m
float width;
float loadSensitivity;
float stickyness;
float grip;
float rollCenter;
float braked,handbraked;
float tolerance;
float inertia;
float tilt;
float friction;
tFileRef model;
tFileRef customBrakeModel;
int noShadow;
} tWheelDefinition;
#define kFatalDamage 400
#define kEngineDamage 300
#define kSuspensionDamage 200
typedef struct{
char name[64];
char describtion[256];
int requirements,conflicts;
float mass;
float frontLift,rearLift;
float frontMaxSuspension,rearMaxSuspension;
float frontWheelWidth,rearWheelWidth;
float frontAirResistance;
float powerPercent,torquePercent;
float finalDriveRatio,topGearRatio;
float engineInertia;
float gearSwitchTime;
float differentialLockCoefficient;
float frontSwayBar,rearSwayBar;
float track;
float maxRPM;
float exhaustFire;
float damperStrength;
tVector3 massCenter;
int hasGraphic;
tFileRef model;
int price;
int group;
} tAddOnDefinition;
typedef struct{
float frontAirResistance,sideAirResistance,topAirResistance;
float frontLift,rearLift;
float mass; //kg
float power; //W
float torque; //Nm
float powerRPM,torqueRPM; //revs per minute
float clutchRPM;
float idleRPM,jerkRPM,maxRPM;
float shiftUpRPM,shiftDownRPM,shiftUpRPMFix;
float finalDriveRatio;
float differentialLockCoefficient;
float supsensionFriction,damperStrength;
float engineInertia;
float engineFriction,engineBaseFriction,engineRPMFriction;
float maxClutchTorqueTransfer;
float zeroRPMSoundGain,fullRPMSoundGain,zeroThrottleSoundGain,fullThrottleSoundGain;
float zeroRPMSoundPitch,fullRPMSoundPitch,zeroThrottleSoundPitch,fullThrottleSoundPitch;
float gearSwitchTime;
float exhaustFire;
float frontSwayBar,rearSwayBar;
float aiSpeedIndex;
int numGears,numWheels,numLights,numAddOns;
int numColors;
int initialAddOns;
int challengeRequirements;
int demoAvailable,builtIn;
tVector3 massCenter;
tVector3 inertia;
tVector3 steeringWheelPos;
tVector3 driverPos;
tVector3 exhaust1Pos,exhaust2Pos;
tVector3 frontLicensePlatePos,rearLicensePlatePos;
float steeringWheelAngle,steeringWheelTurns,steeringWheelRadius;
tFileRef steeringWheelTexture;
tFileRef model,interiorModel,shadowModel;
tFileRef engineSample,hallSample,turboSample,hornSample;
float hornPitch;
int numCollBoxes;
int noDriverModel;
float maxCollRadius;
float *gearRatios;
tWheelDefinition *wheels;
tLightDefinition *lights;
tAddOnDefinition *addOns;
tVector3 *colors;
int *colorLoaded;
tCollBox *coll;
char carName[64];
int year;
int magic;
int secret;
int price;
float displacement;
float turboGain;
} tCarDefinition;
typedef struct{
float angle;
float suspension; //m
float slipVelo,slip,slipAngle;
float rotation;
float angularVelo;
float glow;
int lastTrack;
int onGround;
int surfaceType;
} tWheelPhysics;
#define kNumLastCollisions 32
typedef struct{
int frameCount;
tVector3 attackPoint;
tVector3 veloDiff;
float rotationFactor;
} tCollisionStruct;
typedef struct{
tCarDefinition car;
int addOns; //flags for add-ons installed.
int color;
float aiPowerCycle; //for AI cars: start of AI power cycle which makes AI cars behave more randomly
float aiRouteCycle;
int gear; //current gear car is in
int lastGear;
int lightFlags; //which lights are on
float echo; //is the car in a tunnel?
int lap; //internal lap counter for position determination (not neccesarily ==lapCount)
int lapCount; //lap counter
int wrongDriectionFrames; //number of Frames the car is moving into the wrong Direction
int lapTimes[kMaxLaps+1]; //frame Count each time the finish line was crossed
int finishTime; //frame Count the race was finished or is prognosed to be finished
int lappedPlayers[kMaxPlayers];
int averageSpeedFrames; //number of frames used to calculate average speed so far.
float maxSpeed,averageSpeed,accel100,accel200,accelQuarter,accelKM,odo;
float position;
int checkPoint;
float lead;
float rpm;
float engineAngularVelo,drivetrainAngularVelo;
float clutchTorque;
float throttle,oldThrottle,steering,brake,arcadeBrake,handbrake,clutch;
float idleThrottle;
float lastGearSwitch;
float arcadeSteerVelo,arcadeDraftBoost;
float maxSlip,maxAngle;
float noisePriority;
float dirt;
int crashTime; //the last frame in which all four wheels have been on the ground.
int stuckTime; //the last frame in which the car seemed to make some progress (ai)
int collision; //has the car collided with something solid this frame? (for getting stuck detection)
int onGround;
tGameEntity *overtaking;
int overtakeSide;
float overTakeProgress;
tVector3 lastSamplePos;
float dirtStretch[5];
tWheelPhysics wheels[kMaxWheels];
UInt64 regCode;
char *plateName;
float damage;
float turboRPM;
tCollisionStruct lastCollisions[kNumLastCollisions];
} tCarPhysics;
typedef struct{
tVector3 pos,velo,groundNormal;
tVector3 roadForce;
int onGround;
float bump;
float inertia;
float oldAngle;
float normalForce,suspensionForce;
} tWheelCalcData;
void InstallCarAddOns(tCarPhysics *phys);
float CalcDraftFactor(tGameEntity *car1);
void CarPhysicsEntity(tGameEntity *carEntity);
void CarMotionEntity(tGameEntity *carEntity);
#endif

819
source/carselection.cpp Normal file
View File

@ -0,0 +1,819 @@
#include "stdtypes.h"
#include "reg_tool_3.h"
#include "rt3_redline.h"
#include <OpenGL/gl.h>
#include <string.h>
#include <stdio.h>
#include "gametime.h"
#include "gamemem.h"
#include "fileio.h"
#include "rendercar.h"
#include "carphysics.h"
#include "screen.h"
#include "controls.h"
#include "environment.h"
#include "transparency.h"
#include "renderframe.h"
#include "text.h"
#include "interface.h"
#include "gameinitexit.h"
#include "carselection.h"
#include "config.h"
#include "interfaceutil.h"
#include "stencil.h"
#include "gamesystem.h"
#include "textures.h"
#include "challenges.h"
#include "gamesound.h"
#include "random.h"
#define REGISTERED (RT3_IsRegistered())
char *StripName(char *aName);
int CompareCars(const void *a,const void *b)
{
tCarDefinition *cara=(tCarDefinition*)FileGetParsedDataPtr(*(tFileRef*)a,kParserTypeCarDesc,sizeof(tCarDefinition));
tCarDefinition *carb=(tCarDefinition*)FileGetParsedDataPtr(*(tFileRef*)b,kParserTypeCarDesc,sizeof(tCarDefinition));
if(!REGISTERED)
if(cara->demoAvailable!=carb->demoAvailable)
return carb->demoAvailable-cara->demoAvailable;
return _stricmp(StripName(cara->carName),StripName(carb->carName));
}
void GetAvailableCars(tFileRef *availableCars,int *carCount,int onlyBuiltIn,int onlyAvailable)
{
*carCount=0;
for(int i=0;i<gFileTableSize;i++)
if(*carCount<kMaxCars)
if(char *extension=FileGetExtension(i))
if(!_stricmp(extension,kFileTypeCarDefinition))
{
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(i,kParserTypeCarDesc,sizeof(tCarDefinition));
if((car->builtIn||!onlyBuiltIn)&&HasChallengeRequirements(car->challengeRequirements,gConfig->challengeData))
availableCars[(*carCount)++]=i;
if(car->shiftUpRPM<car->maxRPM*0.8)
printf("%s: %f/%f\n",car->carName,car->shiftUpRPM,car->maxRPM);
}
if(!onlyAvailable)
for(int i=0;i<gFileTableSize;i++)
if(*carCount<kMaxCars)
if(char *extension=FileGetExtension(i))
if(!_stricmp(extension,kFileTypeCarDefinition))
{
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(i,kParserTypeCarDesc,sizeof(tCarDefinition));
if((car->builtIn||!onlyBuiltIn)&&!HasChallengeRequirements(car->challengeRequirements,gConfig->challengeData)&&!car->secret)
availableCars[(*carCount)++]=i;
}
qsort(availableCars,*carCount,sizeof(tFileRef),CompareCars);
}
#define kSpecsXPos 0.9
#define kSpecsYPos 0.6
#define kSpecsSize 0.03
#define kSpecsOffset 0.07
#define kSpecsAlign kTextAlignRight
//#define kColorsXPos 0.5
//#define kColorsYPos 0.2
#define kColorsXPos 0.42
#define kColorsYPos -0.3
#define kColorsWidth 0.04
#define kColorsHeight 0.02
//#define kColorsOffset 0.025
#define kColorsOffset 0.05
#define kPointerSize 0.03
void CarSelectionDrawBackground(int mode)
{
char title[256];
switch(mode)
{
case kCarSelectionQuickMode:
strcpy(title,"Select Car:");
break;
case kCarSelectionEnemyMode:
strcpy(title,"Select Opponent Car:");
break;
case kCarSelectionDisplayMode:
strcpy(title,"New Car Unlocked!");
break;
}
InterfaceDrawBackground(-1,-1,0,0,0,0,1);
TextPrintfToBufferFormated(Vector(kTitlePosX,kTitlePosY),0.08,kTextAlignLeft,title);
}
void CarSelectionDrawCar(tFileRef carRef,float time,int addOns,int color)
{
tGameEntity carEntity,cameraEntity;
tCarPhysics *phys=(tCarPhysics*)MemoryAllocateZeroedBlock(sizeof(tCarPhysics));
cameraEntity.pos=Vector(0,1.5,0);
carEntity.pos=Vector(0,0,7);
*MatrixGetZVector(cameraEntity.dir)=!(carEntity.pos-cameraEntity.pos);
*MatrixGetYVector(cameraEntity.dir)=Vector(0,1,0);
MatrixReAdjust(cameraEntity.dir);
carEntity.pos.x-=0.5;
carEntity.pos.y-=1.0;
MatrixIdentity(carEntity.dir);
MatrixRotY(carEntity.dir,time*PI/4);
carEntity.renderType=kRenderTypeCar;
carEntity.physicsType=kPhysicsTypeCar;
carEntity.physicsData=carRef;
carEntity.physics=phys;
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(carRef,kParserTypeCarDesc,sizeof(tCarDefinition));
phys->car=*car;
phys->car.wheels=(tWheelDefinition*)MemoryAllocateBlock(sizeof(tWheelDefinition)*car->numWheels);
MemoryMove(phys->car.wheels,car->wheels,sizeof(tWheelDefinition)*car->numWheels);
phys->addOns=addOns;
phys->color=color;
InstallCarAddOns(phys);
car=&phys->car;
for(int i=0;i<car->numWheels;i++)
phys->wheels[i].suspension=car->wheels[i].maxSuspension/2;
tGameEntity *oldCameraEntity=gCameraEntity;
gCameraEntity=&cameraEntity;
SetupTranslation(carEntity.pos,carEntity.dir);
glColorMask(0,0,0,0);
glBegin(GL_QUADS);
glVertex3f(-100,0,100);
glVertex3f(100,0,100);
glVertex3f(100,0,-100);
glVertex3f(-100,0,-100);
glEnd();
glColorMask(1,1,1,1);
carEntity.pos.y=-1-car->wheels->pos.y+car->wheels->maxSuspension/2+car->wheels->radius;
SetupTranslation(carEntity.pos,carEntity.dir);
glPushAttrib(GL_LIGHTING_BIT+GL_POLYGON_BIT+GL_COLOR_BUFFER_BIT+GL_TEXTURE_BIT);
CarRenderEntity(&carEntity,gConfig->interiorDisplay?true:false,false);
glPopAttrib();
for(int i=1;i<=gConfig->stencil;i++)
{
gStencilZoom=0.9+0.1*i/(float)gConfig->stencil;
SetupTranslation(carEntity.pos,carEntity.dir);
glPushAttrib(GL_ENABLE_BIT+GL_POLYGON_BIT);
CarRenderEntityShadow(&carEntity,6);
glPopAttrib();
RenderStencilLayer(true,gConfig->stencil);
}
DrawTransparentPolys(NULL);
MemoryFreeBlock(phys->car.wheels);
MemoryFreeBlock(phys);
gCameraEntity=oldCameraEntity;
}
void CarSelectionDrawSpecs(tFileRef *availableCars,int numAvailable,int selected,int mode,int *available)
{
//if(fadeName)
//gTextOpacity=1;
for(int i=-3;i<=3;i++)
{
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[(selected+i+numAvailable)%numAvailable],kParserTypeCarDesc,sizeof(tCarDefinition));
TextPrintfToBufferFormatedColored(Vector(-kSpecsXPos,0.4-i*0.1-fabs(i)*0.008),0.05-fabs(i)*0.008,kTextAlignLeft,1,1,1,1-fabs(i*0.15)-(i?0.3:0),car->carName);
}
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[selected],kParserTypeCarDesc,sizeof(tCarDefinition));
// TextPrintfToBufferFormated(Vector(kSpecsXPos,0.5),0.05,kTextAlignLeft,car->carName);
// gTextOpacity=opacity;
float yPos=kSpecsYPos;
if(car->magic)
{
// TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-5*kSpecsOffset),kSpecsSize,kSpecsAlign,"Where we're going, we don't need specifications.");
TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-0*kSpecsOffset),kSpecsSize,kSpecsAlign,"Where we're going, we don't need specifications.");
}
else
{
if(car->numWheels>=4)
if(car->wheels[0].powered&&car->wheels[2].powered)
TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-0.0),kSpecsSize,kSpecsAlign,"Drivetrain: \255#a\2554WD");
else if(car->wheels[0].powered)
TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-0.0),kSpecsSize,kSpecsAlign,"Drivetrain: \255#a\255FWD");
else if(car->wheels[2].powered)
TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-0.0),kSpecsSize,kSpecsAlign,"Drivetrain: \255#a\255RWD");
TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-5*kSpecsOffset),kSpecsSize,kSpecsAlign,"Gearbox: \255#a\255%d Gears",car->numGears-2);
if(gConfig->metricUnits)
{
TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-1*kSpecsOffset),kSpecsSize,kSpecsAlign,"Displacement: \255#a\255%1.1f L",car->displacement);
TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-2*kSpecsOffset),kSpecsSize,kSpecsAlign,"Mass: \255#a\255%4.0f kg",car->mass);
TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-3*kSpecsOffset),kSpecsSize,kSpecsAlign,"Power: \255#a\255%3.0f kw @ %4.0f RPM",car->power/1000,car->powerRPM);
TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-4*kSpecsOffset),kSpecsSize,kSpecsAlign,"Torque: \255#a\255%3.0f Nm @ %4.0f RPM",car->torque,car->torqueRPM);
}
else
{
TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-1*kSpecsOffset),kSpecsSize,kSpecsAlign,"Displacement: \255#a\255%3.0f cui",car->displacement*61.023744);
TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-2*kSpecsOffset),kSpecsSize,kSpecsAlign,"Mass: \255#a\255%4.0f lbs",car->mass*2.2046);
TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-3*kSpecsOffset),kSpecsSize,kSpecsAlign,"Power: \255#a\255%3.0f hp @ %4.0f RPM",car->power/745.69987,car->powerRPM);
TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-4*kSpecsOffset),kSpecsSize,kSpecsAlign,"Torque: \255#a\255%3.0f lb-ft @ %4.0f RPM",car->torque/1.35628105,car->torqueRPM);
}
}
if(!car->demoAvailable&&!REGISTERED&&mode!=kCarSelectionEnemyMode)
TextPrintfToBufferFormatedColored(Vector(0.2,0),0.15,kTextAlignMiddle,1,1,1,0.5,"DEMO");
// TextPrintfToBufferFormatedColored(Vector(0.2,0.2),0.25,kTextAlignMiddle,1,1,1,0.8,"\255demo_car.png\255");
else if(!HasChallengeRequirements(car->challengeRequirements,gConfig->challengeData)&&mode!=kCarSelectionEnemyMode)
TextPrintfToBufferFormatedColored(Vector(0.2,0),0.15,kTextAlignMiddle,1,1,1,0.5,"LOCKED");
if(available)
*available=((car->demoAvailable||REGISTERED)&&HasChallengeRequirements(car->challengeRequirements,gConfig->challengeData))||mode==kCarSelectionEnemyMode;
gTextOpacity=1;
}
void CarSelectionDrawColors(tFileRef carRef,int color)
{
/* gTexturesQualityModifier=-255;
glPushAttrib(GL_COLOR_BUFFER_BIT+GL_CURRENT_BIT);
glDisable(GL_LIGHTING);
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(carRef,kParserTypeCarDesc,sizeof(tCarDefinition));
glLoadIdentity();
glTranslatef(0.0f,0.0f,-1.0f);
TexturesSelectTex(FileGetReference("colorbevel.pct"));
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
for(int i=0;i<car->numColors;i++)
{
glColor3fv(&(car->colors[i].x));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(kColorsXPos+kColorsWidth,kColorsYPos-kColorsHeight/2-i*kColorsOffset);
glTexCoord2d(1,0); glVertex2f(kColorsXPos+kColorsWidth,kColorsYPos+kColorsHeight/2-i*kColorsOffset);
glTexCoord2d(0,1); glVertex2f(kColorsXPos,kColorsYPos-kColorsHeight/2-i*kColorsOffset);
glTexCoord2d(0,0); glVertex2f(kColorsXPos,kColorsYPos+kColorsHeight/2-i*kColorsOffset);
glEnd();
}
if(car->numColors)
{
if(color>=car->numColors)
color=car->numColors-1;
glColor3f(1,1,1);
TexturesSelectTex(FileGetReference("menupointer.tif"));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(kColorsXPos-kColorsWidth+kPointerSize,kColorsYPos-kPointerSize/2-color*kColorsOffset);
glTexCoord2d(1,0); glVertex2f(kColorsXPos-kColorsWidth+kPointerSize,kColorsYPos+kPointerSize/2-color*kColorsOffset);
glTexCoord2d(0,1); glVertex2f(kColorsXPos-kColorsWidth,kColorsYPos-kPointerSize/2-color*kColorsOffset);
glTexCoord2d(0,0); glVertex2f(kColorsXPos-kColorsWidth,kColorsYPos+kPointerSize/2-color*kColorsOffset);
glEnd();
}
glPopAttrib();
gTexturesQualityModifier=0;*/
gTexturesQualityModifier=-255;
glPushAttrib(GL_COLOR_BUFFER_BIT+GL_CURRENT_BIT);
glDisable(GL_LIGHTING);
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(carRef,kParserTypeCarDesc,sizeof(tCarDefinition));
glLoadIdentity();
glTranslatef(0.0f,0.0f,-1.0f);
TexturesSelectTex(FileGetReference("colorbevel.pct"));
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
for(int i=0;i<car->numColors;i++)
{
glColor3fv(&(car->colors[i].x));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(kColorsXPos-i*kColorsOffset+kColorsWidth,kColorsYPos-kColorsHeight/2);
glTexCoord2d(1,0); glVertex2f(kColorsXPos-i*kColorsOffset+kColorsWidth,kColorsYPos+kColorsHeight/2);
glTexCoord2d(0,1); glVertex2f(kColorsXPos-i*kColorsOffset,kColorsYPos-kColorsHeight/2);
glTexCoord2d(0,0); glVertex2f(kColorsXPos-i*kColorsOffset,kColorsYPos+kColorsHeight/2);
glEnd();
}
if(car->numColors)
{
if(color>=car->numColors)
color=car->numColors-1;
glColor3f(1,1,1);
TexturesSelectTex(FileGetReference("menupointer.tif"));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(0,1); glVertex2f(kColorsXPos-color*kColorsOffset+kColorsWidth/2+kPointerSize/2,kColorsYPos-kColorsHeight*2);
glTexCoord2d(1,1); glVertex2f(kColorsXPos-color*kColorsOffset+kColorsWidth/2+kPointerSize/2,kColorsYPos-kColorsHeight*2+kPointerSize);
glTexCoord2d(0,0); glVertex2f(kColorsXPos-color*kColorsOffset+kColorsWidth/2-kPointerSize/2,kColorsYPos-kColorsHeight*2);
glTexCoord2d(1,0); glVertex2f(kColorsXPos-color*kColorsOffset+kColorsWidth/2-kPointerSize/2,kColorsYPos-kColorsHeight*2+kPointerSize);
glEnd();
}
glPopAttrib();
gTexturesQualityModifier=0;
}
void InterfaceCarSelectionRenderLoadScreen(float time,tFileRef *availableCars,int numAvailable,int selected,int mode,int addOns,int color,int drawColor,int *demoAvailable,float carFade,float totalFade)
{
glPushMatrix();
glPushAttrib(GL_LIGHTING_BIT);
glDisable(GL_LIGHTING);
glClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT);
CarSelectionDrawBackground(mode);
CarSelectionDrawSpecs(availableCars,numAvailable,selected,mode,demoAvailable);
InterfaceDrawBackgroundFade(carFade,false);
TextPrintfToBufferFormated(Vector(0.2,0.1),0.05,kTextAlignMiddle,"Loading...");
CarSelectionDrawColors(availableCars[selected],color);
TextPrintBuffer(1,false);
TextClearBuffer();
InterfaceDrawBackgroundFade(totalFade,false);
ScreenBlit();
glPopAttrib();
glPopMatrix();
}
void InterfaceCarSelectionRender(float time,tFileRef *availableCars,int numAvailable,int selected,int mode,int addOns,int color,int drawColor,int *demoAvailable,float carFade,float totalFade)
{
glPushMatrix();
glPushAttrib(GL_LIGHTING_BIT);
glEnable(GL_LIGHTING);
SetupLighting();
glClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT);
CarSelectionDrawBackground(mode);
/*tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,0,"");
InterfaceRenderReplay(NULL,0,&menu);*/
if(selected!=-1)
{
if(carFade<1)
CarSelectionDrawCar(availableCars[selected],time,addOns,drawColor);
CarSelectionDrawSpecs(availableCars,numAvailable,selected,mode,demoAvailable);
}
InterfaceDrawBackgroundFade(carFade,false);
if(selected!=-1&&mode!=kCarSelectionDisplayMode)
CarSelectionDrawColors(availableCars[selected],color);
TextPrintBuffer(1,false);
TextClearBuffer();
InterfaceDrawBackgroundFade(totalFade,false);
ScreenBlit();
glPopAttrib();
glPopMatrix();
}
int SelectCarByChar(char ch)
{
tFileRef availableCars[kMaxCars];
int carCount;
GetAvailableCars(availableCars,&carCount,false,false);
for(int i=0;i<carCount;i++)
{
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[i],kParserTypeCarDesc,sizeof(tCarDefinition));
if(toupper(StripName(car->carName)[0])>=ch)
return i;
}
return carCount-1;
}
/*
int InterfaceCarSelectionQuick(int *selection,int mode)//,int (*Callback)(void*),void *userData,int *callbackResponse)
{
tInterfaceMenuDescribtion menu;
tFileRef availableCars[kMaxCars];
int carCount;
GetAvailableCars(availableCars,&carCount,false,false);
InterfaceInitMenu(&menu,carCount,"Car Quick-Selection");
menu.scrollEnable=true;
menu.returnOnSpace=true;
for(int i=0;i<menu.numItems;i++)
{
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[i],kParserTypeCarDesc,sizeof(tCarDefinition));
strcpy(menu.items[i].label,car->carName);
menu.items[i].size*=0.7;
menu.items[i].lineSpacing*=0.7;
if(!HasChallengeRequirements(car->challengeRequirements,gConfig->challengeData)&&mode!=kCarSelectionEnemyMode)
menu.items[i].flags |= kInterfaceMenuItemDisabled;
if(!car->demoAvailable&&!REGISTERED&&mode!=kCarSelectionEnemyMode)
menu.items[i].flags |= kInterfaceMenuItemDisabled;
}
// menu.TimerCallback=Callback;
// menu.userData=userData;
menu.initialSelection=*selection;
*selection=InterfaceGetUserMenuSelection(&menu);
if(*selection == kInterfaceMenuEsc)
{
*selection=-2;
return true;
}
if(*selection & kInterfaceMenuSpaceFlag)
{
*selection&=kInterfaceMenuItemMask;
return false;
}
InterfaceDisposeMenu(&menu);
return true;
}
*/
int InterfaceCarSelectionInput(int carCount,int *selection,int mode,int *color,int demoAvailable,int maxColors,int *drawImmediate)
{
int key;
char ch=toupper(GetKeyInput(&key));
if(ch>='A'&&ch<='Z')
*selection=SelectCarByChar(ch);
*drawImmediate=false;
switch(key)
{
// case kInterfaceKeyLeft:
case kInterfaceKeyUp:
(*selection)--;
*color=0;
PlayInterfaceSound(FileGetReference("menu.wav"));
break;
// case kInterfaceKeyRight:
case kInterfaceKeyDown:
(*selection)++;
*color=0;
PlayInterfaceSound(FileGetReference("menu.wav"));
break;
// case kInterfaceKeyUp:
case kInterfaceKeyRight:
(*color)--;
if(*color<0)
*color=maxColors-1;
if(*color<0)
*color=0;
PlayInterfaceSound(FileGetReference("menu.wav"));
break;
// case kInterfaceKeyDown:
case kInterfaceKeyLeft:
*color=(*color+1)%maxColors;
if(*color>=maxColors)
*color=0;
PlayInterfaceSound(FileGetReference("menu.wav"));
break;
case kInterfaceKeyEsc:
case kInterfaceKeyDelete:
PlayInterfaceSound(FileGetReference("esc.wav"));
*selection=-2;
return true;
case kInterfaceKeyReturn:
case kInterfaceKeyEnter:
if(demoAvailable)
{
PlayInterfaceSound(FileGetReference("select.wav"));
return true;
}
break;
/* case kInterfaceKeySpace:
*drawImmediate=true;
return InterfaceCarSelectionQuick(selection,mode);//,mode,Callback,userData,callbackResponse);
break;*/
}
return false;
}
void SelectNextCar(tFileRef *car,UInt8 *color,int onlyAvailable,int onlyDemo)
{
int availableCars[kMaxCars];
int carCount;
int selection=0;
GetAvailableCars(availableCars,&carCount,false,onlyAvailable);
for(int i=0;i<carCount;i++)
if(*car==availableCars[i])
selection=i;
tCarDefinition *c;
do{
selection=(selection+1)%carCount;
c=(tCarDefinition*)FileGetParsedDataPtr(availableCars[selection],kParserTypeCarDesc,sizeof(tCarDefinition));
if(color)
if(c->numColors)
*color=RandomInt(0,c->numColors);
else
*color=0;
}while(!c->demoAvailable&&!REGISTERED&&onlyDemo);
*car=availableCars[selection];
// gConfig->lastCar=*car;
}
void SelectPrevCar(tFileRef *car,UInt8 *color,int onlyAvailable,int onlyDemo)
{
int availableCars[kMaxCars];
int carCount;
int selection=0;
GetAvailableCars(availableCars,&carCount,false,onlyAvailable);
for(int i=0;i<carCount;i++)
if(*car==availableCars[i])
selection=i;
tCarDefinition *c;
do{
selection--;
if(selection<0)
selection+=carCount;
c=(tCarDefinition*)FileGetParsedDataPtr(availableCars[selection],kParserTypeCarDesc,sizeof(tCarDefinition));
if(color)
if(c->numColors)
*color=RandomInt(0,c->numColors);
else
*color=0;
}while(!c->demoAvailable&&!REGISTERED&&onlyDemo);
*car=availableCars[selection];
// gConfig->lastCar=*car;
}
void SetupLighting();
int InterfaceCarSelection(tFileRef *car,int mode,UInt8 *pColor,int (*Callback)(void*),void *userData,int *callbackResponse)
{
int availableCars[kMaxCars];
int selection=1;
int carCount;
int color=*pColor;
int oldColor=*pColor;
int demoAvailable=true;
int drawImmediate=false;
tFileRef curCar;
float carFade=0;
GetAvailableCars(availableCars,&carCount,false,false);
for(int i=0;i<carCount;i++)
if(*car==availableCars[i])
selection=i;
tEnvironment *oldEnv=gEnvironment;
tMapEnv* oldMapEnv=gMapEnv;
gMapEnv=NULL;
LoadEnvironment(FileGetReference("showroom.senv"));
glDisable(GL_LIGHTING);
float startTime=TimeGetSeconds();
float curTime=0;
int maxColors=1;
curCar=selection==-1?-1:availableCars[selection];
do{
selection=selection%carCount;
if(selection<0) selection+=carCount;
float dt=curTime;
curTime=TimeGetSeconds()-startTime;
dt=curTime-dt;
if((curCar!=(selection==-1?-1:availableCars[selection]))||color!=oldColor)
{
if(selection!=-1)
{
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[selection],kParserTypeCarDesc,sizeof(tCarDefinition));
int colorLoaded=false;
if(car->numColors>0)
colorLoaded=car->colorLoaded[color];
if(carFade>=3||(colorLoaded&&carFade>=1))
{
curCar=availableCars[selection];
oldColor=color;
}
else
carFade+=dt/0.2;
}
else if(carFade>=1)
{
curCar=-1;
oldColor=color;
}
else
carFade+=dt/0.2;
}
else
{
carFade-=dt/0.2;
if(carFade<1&&carFade+dt/0.2>=1&&curCar!=-1)
{
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[selection],kParserTypeCarDesc,sizeof(tCarDefinition));
int colorLoaded=false;
if(car->numColors>0)
colorLoaded=car->colorLoaded[color];
if(!colorLoaded)
{
InterfaceCarSelectionRenderLoadScreen(curTime,availableCars,carCount,selection,mode,0,color,oldColor,&demoAvailable,carFade,1-(curTime/0.2));
InterfaceCarSelectionRender(curTime,availableCars,carCount,selection,mode,0,color,oldColor,&demoAvailable,carFade,1-(curTime/0.2));
FlushKeys();
curTime=TimeGetSeconds()-startTime;
}
}
}
if(drawImmediate)
{
carFade=1;
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[selection],kParserTypeCarDesc,sizeof(tCarDefinition));
car->colorLoaded[color]=true;
}
if(carFade<0)carFade=0;
InterfaceCarSelectionRender(curTime,availableCars,carCount,selection,mode,0,color,oldColor,&demoAvailable,carFade,1-(curTime/0.2));
SystemPoll(false);
if(Callback)
{
*callbackResponse=Callback(userData);
if(*callbackResponse!=-1)
{
gEnvironment=oldEnv;
gMapEnv=oldMapEnv;
return false;
}
}
if(selection!=-1)
{
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[selection],kParserTypeCarDesc,sizeof(tCarDefinition));
maxColors=car->numColors;
if(maxColors==1)maxColors=1;
}
else
maxColors=1;
}
while(!InterfaceCarSelectionInput(carCount,&selection,mode,&color,demoAvailable,maxColors,&drawImmediate));
glEnable(GL_LIGHTING);
gEnvironment=oldEnv;
gMapEnv=oldMapEnv;
float endTime=curTime+0.2;
if(selection>=0)
while(curTime<endTime)
{
curTime=TimeGetSeconds()-startTime;
InterfaceCarSelectionRender(curTime,availableCars,carCount,selection,mode,0,color,oldColor,&demoAvailable,carFade,1-((endTime-curTime)/0.2));
}
if(selection!=-2)
{
*car=availableCars[selection];
*pColor=color;
}
return selection!=-2;
}
enum{
kOpponentNumOpponents,
kOpponent1,
kOpponent2,
kOpponent3,
kOpponent4,
kOpponent5,
kOpponent6orOK,
kOpponent7orNumOptions,
kOpponent8,
kOpponent9,
kOpponent10,
kOpponent11,
kOpponentOK,
kOpponentNumOptions
};
int InterfaceSelectOpponentCars(int *numOpponents,tFileRef *opponents,UInt8 *colors,int (*Callback)(void*),void *userData)
{
int setNumOpponents=gConfig->numEnemies;
if(setNumOpponents>(gConfig->allowHugeGames?11:5))
setNumOpponents=(gConfig->allowHugeGames?11:5);
int callBackResponse;
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,gConfig->allowHugeGames?kOpponentNumOptions:kOpponent7orNumOptions,"Select Opponents");
int availableCars[kMaxCars];
int carCount;
GetAvailableCars(availableCars,&carCount,false,false);
// for(int i=0;i<menu.numItems;i++)
// strcpy(menu.items[i].describtion,itemStrings[i]);
strcpy(menu.items[(gConfig->allowHugeGames?kOpponentOK:kOpponent6orOK)].label,"Accept");
menu.items[(gConfig->allowHugeGames?kOpponentOK:kOpponent6orOK)-1].lineSpacing*=1.5;
menu.items[kOpponent1-1].lineSpacing*=1.5;
menu.TimerCallback=Callback;
menu.userData=userData;
menu.items[kOpponentNumOpponents].flags|=kInterfaceMenuItemArrowInput;
for(int i=0;i<11;i++)
{
opponents[i]=gConfig->opponentCars[i];
colors[i]=gConfig->opponentColors[i];
if(opponents[i]==-1||opponents[i]==0)
{
opponents[i]=availableCars[0];
colors[i]=0;
}
}
for(int i=kOpponent1;i<=(gConfig->allowHugeGames?kOpponent11:kOpponent5);i++)
{
menu.items[i].flags|=kInterfaceMenuItemArrowInput;
if(gConfig->allowHugeGames)
{
menu.items[i].size*=0.6;
menu.items[i].lineSpacing*=0.6;
}
}
int exit=false;
int zoom=false;
do{
sprintf(menu.items[kOpponentNumOpponents].label,"Number of Opponents: \255#a\255%d",setNumOpponents);
for(int i=kOpponent1;i<=(gConfig->allowHugeGames?kOpponent11:kOpponent5);i++)
{
if(i-kOpponent1<setNumOpponents)
menu.items[i].flags&=~kInterfaceMenuItemDisabled;
else
menu.items[i].flags|=kInterfaceMenuItemDisabled;
tCarDefinition *c=(tCarDefinition*)FileGetParsedDataPtr(opponents[i-kOpponent1],kParserTypeCarDesc,sizeof(tCarDefinition));
sprintf(menu.items[i].label,"Opponent %d: \255#a\255%s",i-kOpponent1+1,c->carName);
}
int sel=InterfaceGetUserMenuSelection(&menu);
switch(menu.initialSelection=(sel&kInterfaceMenuItemMask))
{
case kOpponentNumOpponents:
if(sel&kInterfaceMenuRightArrow){
if(setNumOpponents<(gConfig->allowHugeGames?11:5))
setNumOpponents++;
}
else if(sel&kInterfaceMenuLeftArrow){
if(setNumOpponents>0)
setNumOpponents--;
}
else
exit=true;
break;
case kOpponent6orOK:
if(!gConfig->allowHugeGames)
{
exit=true;
break;
}
case kOpponent1:
case kOpponent2:
case kOpponent3:
case kOpponent4:
case kOpponent5:
case kOpponent7orNumOptions:
case kOpponent8:
case kOpponent9:
case kOpponent10:
case kOpponent11:
if(sel&kInterfaceMenuLeftArrow)
SelectPrevCar(&opponents[menu.initialSelection-kOpponent1],&colors[menu.initialSelection-kOpponent1],false,false);
else if(sel&kInterfaceMenuRightArrow)
SelectNextCar(&opponents[menu.initialSelection-kOpponent1],&colors[menu.initialSelection-kOpponent1],false,false);
else
InterfaceCarSelection(&opponents[menu.initialSelection-kOpponent1],kCarSelectionEnemyMode,&colors[menu.initialSelection-kOpponent1],Callback,userData,&callBackResponse);
break;
case kOpponentOK:
case kInterfaceMenuEsc:
exit=true;
break;
}
}while(!exit);
for(int i=0;i<11;i++)
{
gConfig->opponentCars[i]=opponents[i];
gConfig->opponentColors[i]=colors[i];
}
*numOpponents=gConfig->numEnemies=setNumOpponents;
InterfaceDisposeMenu(&menu);
return menu.initialSelection!=kInterfaceMenuEsc;
}

22
source/carselection.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef __CARSELECTION
#define __CARSELECTION
#include "carphysics.h"
#include "fileio.h"
#define kMaxCars 1024
enum {
kCarSelectionQuickMode,
kCarSelectionEnemyMode,
kCarSelectionDisplayMode
};
void InterfaceCarSelectionRender(float time,tFileRef *availableCars,int numAvailable,int selected,int mode,int addOns,int color,int drawColor,int *demoAvailable,float carFade,float totalFade);
int InterfaceCarSelection(tFileRef *car,int mode,UInt8 *pColor,int (*Callback)(void*),void *userData,int *callbackResponse);
void GetAvailableCars(tFileRef *availableCars,int *carCount,int onlyBuiltIn,int onlyAvailable);
void SelectNextCar(tFileRef *car,UInt8 *color,int onlyAvailable,int onlyDemo);
void SelectPrevCar(tFileRef *car,UInt8 *color,int onlyAvailable,int onlyDemo);
int InterfaceSelectOpponentCars(int *numOpponents,tFileRef *opponents,UInt8 *colors,int (*Callback)(void*),void *userData);
#endif

235
source/challenges.cpp Normal file
View File

@ -0,0 +1,235 @@
#include <string.h>
#include <stdio.h>
#include "fileio.h"
#include "interfaceutil.h"
#include "gameinitexit.h"
#include "gameframe.h"
#include "challenges.h"
#include "config.h"
#include "carphysics.h"
#include "gametime.h"
#include "gamesystem.h"
#include "controls.h"
#include "carselection.h"
#include "writeout.h"
#include "environment.h"
#include "renderframe.h"
#include "text.h"
#include "screen.h"
#include "log.h"
#include "interface.h"
#include "textures.h"
#include "gamesound.h"
#include "reg_tool_3.h"
int HasChallengeRequirements(int requirements,int hasReq)
{
for(int i=0;i<16;i++)
if(((((unsigned int)requirements)>>(i*2))&0x3)>((((unsigned int)hasReq)>>(i*2)&0x3)))
return false;
return true;
}
void ChallengeRenderCallback(tChallenge *chal,int selection,void *menu)
{
InterfaceRenderReplay(NULL,selection,menu);
char info[1024];
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(chal->car,kParserTypeCarDesc,sizeof(tCarDefinition));
sprintf(info,"Car: %s\n\n\255goldmedal.pct\255 Gold: %d:%02d'%02d\n\255silvermedal.pct\255 Silver: %d:%02d'%02d\n\255bronzemedal.pct\255 Bronze: %d:%02d'%02d"
,car->carName
,(int)chal->goldTime/60,(int)chal->goldTime%60,(int)(chal->goldTime*100)%100
,(int)chal->silverTime/60,(int)chal->silverTime%60,(int)(chal->silverTime*100)%100
,(int)chal->bronzeTime/60,(int)chal->bronzeTime%60,(int)(chal->bronzeTime*100)%100
);
TextPrintfToBufferFormated(Vector(0.3,0.6),0.035,kTextAlignLeft|kTextAutoWrap,info);
TextPrintfToBufferFormated(Vector(-0.9,-0.3),0.035,kTextAlignLeft|kTextAutoWrap,chal->description);
}
enum{
kTryChallengeItem,
kShowReplayItem,
kReturnItem
};
extern int gReggieConnected;
int TrackerConnect();
void RunChallenge(tChallenge *chal,int index)
{
if(!gReggieConnected&&gConfig->registerLapTimes)
{
InterfaceDrawStrings("Connecting to Lap Times Server...","One moment, please.",kFileErr);
TrackerConnect();
}
tGameInfo gInfo;
InitGInfo(&gInfo);
gInfo.numPlayers=1;
gInfo.reverse=chal->reverse;
gInfo.environment=chal->environment;
gInfo.numLaps=1;
gInfo.map=chal->map;
gInfo.maxTime=chal->bronzeTime;
gInfo.silverTime=chal->silverTime;
gInfo.goldTime=chal->goldTime;
gInfo.playerCars[0]=chal->car;
gInfo.playerColors[0]=chal->color;
gLocalRecord=gConfig->challengeRecords[index];
int result=RunGame(&gInfo);
int oldChallengeData=gConfig->challengeData;
if(result!=-1)
{
if(result-kStartGameDelaySeconds*kFPS<gConfig->challengeRecords[index]||gConfig->challengeRecords[index]==0)
gConfig->challengeRecords[index]=result-kStartGameDelaySeconds*kFPS;
if(result*kFrameTime<=chal->goldTime+kStartGameDelaySeconds)
gConfig->challengeData|=3<<(index*2);
else if(result*kFrameTime<=chal->silverTime+kStartGameDelaySeconds)
{
if((gConfig->challengeData&(3<<(index*2)))<(2<<(index*2)))
gConfig->challengeData=(gConfig->challengeData&~(3<<(index*2)))|(2<<(index*2));
}
else if(result*kFrameTime<=chal->bronzeTime+kStartGameDelaySeconds)
{
if((gConfig->challengeData&(3<<(index*2)))<(1<<(index*2)))
gConfig->challengeData=(gConfig->challengeData&~(3<<(index*2)))|(1<<(index*2));
}
}
if(gConfig->challengeData!=oldChallengeData)
{
gConfig->dbIndex=gConfig->challengeData^0xdeadbeef;
// WriteOutFile(FileGetReference("config.cfg"),gConfig,kParserTypeConfigDesc);
for(int i=0;i<gFileTableSize;i++)
if(char *extension=FileGetExtension(i))
if(!_stricmp(extension,kFileTypeCarDefinition))
{
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(i,kParserTypeCarDesc,sizeof(tCarDefinition));
if(HasChallengeRequirements(car->challengeRequirements,gConfig->challengeData)>HasChallengeRequirements(car->challengeRequirements,oldChallengeData))
{
float startTime=TimeGetSeconds();
while((GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter)||GetInterfaceKey(kInterfaceKeyEsc)));
float curTime;
do{
SystemPoll(false);
curTime=TimeGetSeconds()-startTime;
tEnvironment *oldEnv=gEnvironment;
tMapEnv* oldMapEnv=gMapEnv;
gMapEnv=NULL;
LoadEnvironment(FileGetReference("showroom.senv"));
SetupLighting();
InterfaceCarSelectionRender(curTime,&i,1,0,kCarSelectionDisplayMode,0,0,0,0,0,0);
gMapEnv=oldMapEnv;
gEnvironment=oldEnv;
}while(!(GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter)||GetInterfaceKey(kInterfaceKeyEsc)));
FlushKeys();
}
}
}
}
int InterfaceRunChallengeMenu(tChallenge *chal,int index)
{
// while(GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter)||GetInterfaceKey(kInterfaceKeyEsc));
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,3,chal->name);
strcpy(menu.items[kTryChallengeItem].label,"Try the Challenge");
strcpy(menu.items[kShowReplayItem].label,"See Demonstration");
strcpy(menu.items[kReturnItem].label,"Return to previous menu");
if(index>2&&!RT3_IsRegistered())
{
strcpy(menu.items[kTryChallengeItem].label,"Not available in demo.");
menu.items[kTryChallengeItem].flags=kInterfaceMenuItemDisabled;
}
menu.items[kShowReplayItem].lineSpacing*=1.5;
menu.background=FileGetReference("background-clock.tif");
menu.RenderCallback=(void(*)(void*,int,void*))ChallengeRenderCallback;
menu.userData=chal;
menu.itemsYPos=0.6;
int sel;
do{
sel=InterfaceGetUserMenuSelection(&menu);
switch(sel)
{
case kTryChallengeItem:
//InterfaceTextBufferZoomAnimation(FileGetReference("background-clock.tif"),false);
RunChallenge(chal,index);
break;
case kShowReplayItem:
LogLoad(chal->replay,&gInterfaceGInfo);
gGameEnd=false;
gGameInfo=&gInterfaceGInfo;
StartBackgroundReplay();
gEnableTextureLoad=false;
gNumTexturesRequested=0;
ReplayFrame();
RenderFrame(false);
gNumTexturesLoaded=0;
gEnableTextureLoad=true;
gDisabledRestart=0;
for(int i=0;i<gFileTableSize;i++)
{
if(gFileTable[i].tagged&&!gFileTable[i].parsed)
{
// InterfaceDrawStatusBar("Loading Textures...",gFileTable[i].name,gNumTexturesLoaded/(float)gNumTexturesRequested);
if(gNumTexturesRequested>0)
InterfaceDrawStatusBar("Loading Textures...","Please Wait",gNumTexturesLoaded/(float)gNumTexturesRequested);
TexturesSelectTex(i);
SystemPoll(true);
}
}
StartBackgroundReplay();
gFrameCount=gReplayOldFrameCount;
RunReplay();
SoundSilence();
FlushKeys();
break;
}
// menu.initialSelection=sel;
}while(sel==kTryChallengeItem||sel==kShowReplayItem);
}
void InterfaceChallenge()
{
tChallengeList *cList=(tChallengeList*)FileGetParsedDataPtr(FileGetReference(kChallengeListFileName),kParserTypeChallengeList,sizeof(tChallengeList));
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,cList->numChallenges,"Select a Challenge");
menu.background=FileGetReference("background-clock.tif");
menu.RenderCallback=InterfaceRenderReplay;
menu.scrollEnable=true;
// strcpy(menu.items[cList->numChallenges].label,"Return to previous menu");
// menu.items[cList->numChallenges-1].lineSpacing*=1.5;
int exit=false;
do{
for(int i=0;i<cList->numChallenges;i++)
{
if(!HasChallengeRequirements(cList->challenges[i].requirements,gConfig->challengeData))
menu.items[i].flags|=kInterfaceMenuItemDisabled;
else
menu.items[i].flags&=~kInterfaceMenuItemDisabled;
if((gConfig->challengeData&(3<<(i*2)))==(3<<(i*2)))
sprintf(menu.items[i].label,"%s \255goldmedal.pct\255",cList->challenges[i].name);
else if((gConfig->challengeData&(2<<(i*2)))==(2<<(i*2)))
sprintf(menu.items[i].label,"%s \255silvermedal.pct\255",cList->challenges[i].name);
else if((gConfig->challengeData&(1<<(i*2)))==(1<<(i*2)))
sprintf(menu.items[i].label,"%s \255bronzemedal.pct\255",cList->challenges[i].name);
else
strcpy(menu.items[i].label,cList->challenges[i].name);
}
int i=(menu.initialSelection=InterfaceGetUserMenuSelection(&menu));
if(i!=kInterfaceMenuEsc&&i!=cList->numChallenges)
InterfaceRunChallengeMenu(cList->challenges+i,i);
else exit=true;
}while(!exit);
InterfaceDisposeMenu(&menu);
}

25
source/challenges.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef __CHALLENGES
#define __CHALLENGES
typedef struct{
char name[256];
char description[512];
float goldTime,silverTime,bronzeTime;
int requirements;
int color;
int reverse;
tFileRef map,car,environment;
tFileRef replay;
} tChallenge;
typedef struct{
int numChallenges;
tChallenge *challenges;
} tChallengeList;
#define kChallengeListFileName "challenges.cfg"
int HasChallengeRequirements(int requirements,int hasReq);
void InterfaceChallenge();
#endif

809
source/collision.cpp Executable file
View File

@ -0,0 +1,809 @@
//collision.cpp
//detect and handle collisions between objects and other objects or objects and ground
#include <math.h>
#include "entities.h"
#include "carphysics.h"
#include "gameframe.h"
#include "roads.h"
#include "particles.h"
#include "text.h"
#include "parser.h"
#include "gamesound.h"
#include "controls.h"
#include "environment.h"
#include "random.h"
#include "collision.h"
#ifndef __TARGET_TOOLAPP
#include "reg_tool_3.h"
#include "rt3_redline.h"
#endif
#include "gamemem.h"
#define kSeperationFactor 0.001
#define kMaxSeperation 10
#define kFindNormalFactor 0.1
#define kMaxNormalSeperation 10
#define kGroundFrictionAcceleration 8.0
#define kMinVelo 0.2
#define kMinRotVelo 0.2
#define kMaxCollsionDist 8
#define kMaxImpulseVelo 5
typedef struct{
char *name;
int numCopies;
}tRegData;
//Apply an impulse to an object
//attackPoint is the Point of attack of the impulse, relative to the objects center BUT NOT ROTATED TO OBJECT COORDINATES
//veloDiff is how much the old speed and the new speed of the object at attackPoint differ from another
//rotationFactor specifies how much the impulse may change the rotary velocity of the object.
//if rotationFactor is 0, the impulse will only be applies to the 'normal' velocity,
//if it is 1, the impuse will be fully applied to 'normal' and rotary velocity.
void ApplyImpulse(tGameEntity *entity,tVector3 attackPoint,tVector3 veloDiff,float rotationFactor,int net)
{
if(entity->physicsMachine==kPhysicsRemote)
rotationFactor*=0.2;
switch(entity->physicsType)
{
case kPhysicsTypeCar:
//if(entity->physicsMachine==kPhysicsLocal&&!gReplay)
{
// if(entity==gViewedEntity)
// printf("hitme! %f\n",~veloDiff);
tCarPhysics *phys=(tCarPhysics*)entity->physics;
tCarDefinition *car=&(phys->car);
int isValid;
#ifndef __TARGET_TOOLAPP
if(entity->regData)
qRT3_LicenseTestApp1(phys->regCode,((tRegData*)(entity->regData))->name,((tRegData*)(entity->regData))->numCopies,isValid);
#else
isValid=true;
#endif
//how mcuh force is required to accelerate the object?
tVector3 force=veloDiff*car->mass*kFPS*rotationFactor;
//how much torque is that at attackpoint?
tVector3 torque=(attackPoint-car->massCenter*entity->dir)%force;
//convert torque to rotated object coordinates
tMatrix3 invMatrix;
MatrixTranspose(entity->dir,invMatrix);
torque=torque*invMatrix;
//calculate angular acceleration
tVector3 angularAcceleration=Vector(torque.x/car->inertia.x,torque.y/car->inertia.y,torque.z/car->inertia.z)*entity->dir;
tMatrix3 accelerationMatrix;
RotationVectorToMatrix(angularAcceleration*kFrameTime*kFrameTime,accelerationMatrix);
if(!net)
{
phys->arcadeSteerVelo+=angularAcceleration.y*kFrameTime*kFrameTime;
if(fabs(phys->arcadeSteerVelo)>0.5)phys->arcadeSteerVelo=sign(phys->arcadeSteerVelo)*0.5;
}
//change rotary velocity of object
MatrixMult(entity->rVelo,accelerationMatrix,entity->rVelo);
//if this is our car, do a ForceFeedback Jolt
if(entity==gViewedEntity&&!gReplay)
{
float impact=~veloDiff;
impact*=0.2;
if(impact>1)impact=1;
FFBJolt(impact,impact,0.3);
if(!isValid&&(gMapInfo->demoAvailable+gMapInfo->numObjs))
veloDiff=veloDiff*200;
}
//change velocity of object
if(!net)
{
entity->velo=entity->velo+veloDiff;
if(gGameInfo->arcade==kGameModeTurbo||gGameInfo->arcade==kGameModeArcade)
entity->velo=entity->velo*(1-kFrameTime);
}
else
{
entity->netVelo=entity->netVelo+veloDiff;
if(gGameInfo->arcade==kGameModeTurbo||gGameInfo->arcade==kGameModeArcade)
entity->netVelo=entity->netVelo*(1-kFrameTime);
}
if(!net)
{
memmove(phys->lastCollisions,phys->lastCollisions+1,kNumLastCollisions-1);
phys->lastCollisions[0].frameCount=gFrameCount;
phys->lastCollisions[0].attackPoint=attackPoint;
phys->lastCollisions[0].veloDiff=veloDiff;
phys->lastCollisions[0].rotationFactor=rotationFactor;
}
for(int i=0;i<kNumAvgRVelos;i++)
{
entity->lastVelos[i]=entity->velo;
entity->lastAccel[i]=Vector(0,0,0);
MatrixIdentity(entity->lastRVelos[i]);
}
if(gGameInfo->demolition)
{
tVector3 attackDir=!(attackPoint*invMatrix);
float damage=(~veloDiff)*(2+attackDir.z+(attackDir.y>0.5?attackDir.y*20:0));
if(damage>10)
phys->damage+=damage;
}
}
break;
case kPhysicsTypeSolid:
{
tSolidEntityPhysics *ent=(tSolidEntityPhysics*)FileGetParsedDataPtr(entity->physicsData,kParserTypeSolidEntityDesc,sizeof(tSolidEntityPhysics));
tVector3 force=veloDiff*ent->mass*kFPS*rotationFactor;
tVector3 torque=(attackPoint-ent->massCenter*entity->dir)%force;
tMatrix3 invMatrix;
MatrixTranspose(entity->dir,invMatrix);
torque=torque*invMatrix;
tVector3 angularAcceleration=torque*1/ent->inertia*entity->dir;
//if(~angularAcceleration>1+~entity->velo)angularAcceleration=!angularAcceleration*(1+~entity->velo);
tMatrix3 accelerationMatrix;
RotationVectorToMatrix(angularAcceleration*kFrameTime*kFrameTime,accelerationMatrix);
MatrixMult(entity->rVelo,accelerationMatrix,entity->rVelo);
entity->velo=entity->velo+veloDiff;
}
break;
}
}
//returns true if an object is moving, false if it isn't
int CheckForMotion(tGameEntity *entity)
{
if(~entity->velo>kMinVelo)
return true;
float rotMotion=~((Vector(1,0,0)*entity->rVelo)-Vector(1,0,0))*kFPS;
if(rotMotion<kMinRotVelo)
return false;
return true;
}
//returns the offset between point and the ground (road).
//lastRoadIndex is a hint where to start looking when trying to find a piece of road under
//point.
float GetGroundOffset(tVector3 point,int *lastRoadIndex,tVector3 *normal,int *surfaceType)
{
//this function does nothing but calling RoadGetYValue - in earlier builds there used to be
//other types of ground that's why this function is here (and not just RoadGetYValue).
return RoadGetYValue(point,lastRoadIndex,normal,surfaceType,NULL);
}
float GetGroundOffsetAndBump(tVector3 point,int *lastRoadIndex,tVector3 *normal,int *surfaceType,float *bump)
{
//this function does nothing but calling RoadGetYValue - in earlier builds there used to be
//other types of ground that's why this function is here (and not just RoadGetYValue).
return RoadGetYValue(point,lastRoadIndex,normal,surfaceType,bump);
}
#define kMinSparkVelo 5.0
#define kMaxSparkVelo 20.0
#define kMaxSpark 60.0
//makes amount/second spark particles flying away from pos
void MakeSparks(tVector3 pos,float amount)
{
tParticlesDef def;
ParticlesInitDef(&def);
def.sprite=FileGetReference("spark.pct");
def.maxSpread=0.1;
def.maxVelo=6;
def.gravity=15;
def.maxLife=0.4;
def.xSize=0.05;def.ySize=0.4;
def.veloRotation=true;
ParticlesCreate(amount*kFrameTime,pos,Vector(0,0,0),&def);
}
//makes squeak and crash noises for carEntity colliding with something at fVeloDiff
void MakeSqueaks(tGameEntity *carEntity,float fVeloDiff,float angle)
{
if(angle<0.2&&fVeloDiff<5&&fVeloDiff>1)
CarPlayCrashNoise(carEntity,FileGetIndexedReference(FileGetReference("scratch.wav"),RandomInt(0,4)),2.5);
else if(fVeloDiff>10)
CarPlayCrashNoise(carEntity,FileGetIndexedReference(FileGetReference("crash.wav"),RandomInt(0,6)),2.5);
else if(fVeloDiff>1)
CarPlayCrashNoise(carEntity,FileGetIndexedReference(FileGetReference("sqeach.wav"),RandomInt(0,3)),2.5);
}
//tests if entity collides with the ground and taks appropiate actions
void CheckGroundCollision(tGameEntity *entity)
{
int numCollBoxes;
tCollBox *boxes;
tCarPhysics *phys;
tCarDefinition *car;
//gets collsion boxes for object
switch(entity->physicsType)
{
case kPhysicsTypeCar:
phys=(tCarPhysics*)entity->physics;
car=&(phys->car);
numCollBoxes=car->numCollBoxes;
boxes=car->coll;
break;
case kPhysicsTypeSolid:
tSolidEntityPhysics *ent=(tSolidEntityPhysics*)FileGetParsedDataPtr(entity->physicsData,kParserTypeSolidEntityDesc,sizeof(tSolidEntityPhysics));
numCollBoxes=ent->numCollBoxes;
boxes=ent->coll;
break;
}
//for cars we take a few extra points to improve precision
int numEdges=(entity->physicsType==kPhysicsTypeCar?12:8);
for(int box=0;box<numCollBoxes;box++)
for(int i=0;i<numEdges;i++)
//for each edge in each collision box...
{
tVector3 normal;
tVector3 rotPoint;
if(i<8)//'normal' edges
rotPoint=((tVector3*)(boxes+box))[i];
else//additional edges used for cars, calculated from normal edges.
rotPoint=(((tVector3*)(boxes+box))[i-4]+((tVector3*)(boxes+box))[(i-3)%8])*0.5;
rotPoint=rotPoint*entity->dir;
tVector3 globalPoint=rotPoint+entity->pos;
int surfaceType=-1;
//...check if it reaches into the ground.
if(GetGroundOffset(globalPoint,&entity->lastRoadIndex,&normal,&surfaceType)<0)
{
if(entity->physicsType==kPhysicsTypeCar)
phys->collision=gFrameCount;
tVector3 pointVelo=((rotPoint*entity->rVelo)-rotPoint)*kFPS+entity->velo;
tVector3 testPoint=globalPoint-pointVelo*kFindNormalFactor*kFrameTime;
tVector3 testNormal;
//try moving the point backwards along its velocity vector until
//it doen't touch the ground anymore, to get the exact point of impact
int count;
for(count=0;count<kMaxNormalSeperation&&GetGroundOffset(testPoint,&entity->lastRoadIndex,&testNormal,0)<0;count++)
{
testPoint=testPoint-pointVelo*kFindNormalFactor*kFrameTime;
normal=testNormal;
}
//Calculate the speed of impact with the ground
float veloDiff=(-normal*pointVelo);
//Apply the ground's Counter-Impulse
if(veloDiff>0)
{
tVector3 pointGroundBrake=kGroundFrictionAcceleration*kFrameTime*(entity->physicsType==kPhysicsTypeCar?kCarCollisionRate:kSolidCollisionRate)*!((normal%pointVelo)%normal);
float groundFactor=normal*Vector(0,1,0)*0.25;
float strictHit=1;
tVector3 impulseVelo=normal*veloDiff*(0.4-groundFactor*0.3)-pointGroundBrake;
if(~impulseVelo>kMaxImpulseVelo)
impulseVelo=!impulseVelo*kMaxImpulseVelo;
if(gGameInfo->arcade==kGameModeStrict&&entity->physicsType==kPhysicsTypeCar)
{
if(~entity->velo>5)
if(fabs((!impulseVelo).y)<0.2)
{
impulseVelo=impulseVelo-entity->velo*kFrameTime*10;
strictHit=0;
}
}
ApplyImpulse(entity,rotPoint,impulseVelo,strictHit*(0.5-0.5*groundFactor),false);
// ApplyImpulse(entity,rotPoint,impulseVelo,0.1);
}
//move the object away from the ground until it doesn't touch ground any longer
//if(entity->physicsMachine==kPhysicsLocal)
for(int count=0;count<kMaxSeperation&&GetGroundOffset(globalPoint,&entity->lastRoadIndex,&testNormal,0)<0;count++)
{
entity->pos=entity->pos+normal*kSeperationFactor*count;
globalPoint=globalPoint+normal*kSeperationFactor*count;
if(surfaceType!=-1)
if(gSurfaceTypes->types[surfaceType].sparksEnable)
{
float sparks=(~entity->velo-kMinSparkVelo)/(kMaxSparkVelo-kMinSparkVelo);
if(sparks>1)sparks=1;
sparks*=kMaxSpark;
if(entity->physicsType==kPhysicsTypeSolid)
{
tSolidEntityPhysics *ent=(tSolidEntityPhysics*)FileGetParsedDataPtr(entity->physicsData,kParserTypeSolidEntityDesc,sizeof(tSolidEntityPhysics));
if(!ent->sparks)
sparks=0;
}
if(sparks>0.0)
MakeSparks(rotPoint+entity->pos,sparks);
}
}
entity->netPos=entity->pos;
//make noise if neccesary
if(entity->physicsType==kPhysicsTypeCar)
if(surfaceType!=-1)
if(gSurfaceTypes->types[surfaceType].squeachEnable)
MakeSqueaks(entity,veloDiff,-normal*!pointVelo);
}
}
}
#define kMinSparkCollVelo 0.0
#define kMaxSparkCollVelo 40.0
#define kMaxSparkColl 200.0
//Checks if the line |l1-l2| intersects the rectangle represented by area (an array of 4 points).
//returns the point of intersection (if any) in hit.
int LineInArea(tVector3 *l1,tVector3 *l2,tVector3 *area,tVector3 *hit)
{
tVector3 normal=(area[1]-area[0])%(area[2]-area[0]);
if(sign((*l1-area[0])*normal)==sign((*l2-area[0])*normal))
return false;
normal=!normal;
float dist=(*l1-area[0])*normal;
tVector3 dir=!(*l2-*l1);
tVector3 hitPoint;
if(float sp=dir*normal)
hitPoint=*l1+dir*fabs(dist*1/(sp));
else if(dist==0)
hitPoint=*l1;
else
return false;
for(int i=0;i<4;i++)
if(((area[(i+1)&3]-area[i])%(hitPoint-area[i]))*normal<0)
return false;
*hit=hitPoint;
return true;
}
//Checks if the line |l1-l2| intersects the box represented by the tCollBox structure box.
//returns the point of intersection (if any) in hit.
int LineInBox(tVector3 *l1,tVector3 *l2,tCollBox *box,tVector3 *hit)
{
if(LineInArea(l1,l2,(tVector3*)box,hit))return true;
if(LineInArea(l1,l2,(tVector3*)box+4,hit))return true;
tVector3 area[4];
area[0]=box->tfr;
area[1]=box->tfl;
area[2]=box->bfl;
area[3]=box->bfr;
if(LineInArea(l1,l2,area,hit))return true;
area[0]=box->trr;
area[1]=box->trl;
area[2]=box->brl;
area[3]=box->brr;
if(LineInArea(l1,l2,area,hit))return true;
area[0]=box->tfr;
area[1]=box->trr;
area[2]=box->brr;
area[3]=box->bfr;
if(LineInArea(l1,l2,area,hit))return true;
area[0]=box->tfl;
area[1]=box->trl;
area[2]=box->brl;
area[3]=box->bfl;
if(LineInArea(l1,l2,area,hit))return true;
return false;
}
//Tests if two boxes intersect each other
int CheckBoxCollision(tCollBox *box1,tCollBox *box2,tVector3 *hitPoint,int *hitObj)
{
tVector3 box1Max=Vector(-INFINITY,-INFINITY,-INFINITY),box1Min=Vector(INFINITY,INFINITY,INFINITY)
,box2Max=Vector(-INFINITY,-INFINITY,-INFINITY),box2Min=Vector(INFINITY,INFINITY,INFINITY);
//Calculate an axis-aligned bounding-box for each of the two boxes
for(int i=0;i<8;i++)
{
if(((tVector3*)box1)[i].x<box1Min.x)box1Min.x=((tVector3*)box1)[i].x;
if(((tVector3*)box1)[i].y<box1Min.y)box1Min.y=((tVector3*)box1)[i].y;
if(((tVector3*)box1)[i].z<box1Min.z)box1Min.z=((tVector3*)box1)[i].z;
if(((tVector3*)box1)[i].x>box1Max.x)box1Max.x=((tVector3*)box1)[i].x;
if(((tVector3*)box1)[i].y>box1Max.y)box1Max.y=((tVector3*)box1)[i].y;
if(((tVector3*)box1)[i].z>box1Max.z)box1Max.z=((tVector3*)box1)[i].z;
if(((tVector3*)box2)[i].x<box2Min.x)box2Min.x=((tVector3*)box1)[i].x;
if(((tVector3*)box2)[i].y<box2Min.y)box2Min.y=((tVector3*)box1)[i].y;
if(((tVector3*)box2)[i].z<box2Min.z)box2Min.z=((tVector3*)box1)[i].z;
if(((tVector3*)box2)[i].x>box2Max.x)box2Max.x=((tVector3*)box2)[i].x;
if(((tVector3*)box2)[i].y>box2Max.y)box2Max.y=((tVector3*)box2)[i].y;
if(((tVector3*)box2)[i].z>box2Max.z)box2Max.z=((tVector3*)box2)[i].z;
}
//if the axis-aligned bounding-boxes don't share the same coordinate
//intervals, return false.
if(box1Max.x<box2Min.x)return false;
if(box1Max.y<box2Min.y)return false;
if(box1Max.z<box2Min.z)return false;
if(box2Max.x<box1Min.x)return false;
if(box2Max.y<box1Min.y)return false;
if(box2Max.z<box1Min.z)return false;
//for each line of each box, test if it intersects the other box
for(int i=0;i<4;i++)
{
if(LineInBox(((tVector3*)box1)+i,((tVector3*)box1)+((i+1)&3),box2,hitPoint))return true;
if(LineInBox(((tVector3*)box1)+i,((tVector3*)box1)+i+4,box2,hitPoint))return true;
if(LineInBox(((tVector3*)box1)+i+4,((tVector3*)box1)+((i+1)&3)+4,box2,hitPoint))return true;
if(LineInBox(((tVector3*)box2)+i,((tVector3*)box2)+((i+1)&3),box1,hitPoint))return true;
if(LineInBox(((tVector3*)box2)+i,((tVector3*)box2)+i+4,box1,hitPoint))return true;
if(LineInBox(((tVector3*)box2)+i+4,((tVector3*)box2)+((i+1)&3)+4,box1,hitPoint))return true;
}
return false;
}
//Translate a box in object coordinates to a box in world coordinates
void BoxWorldCoords(tCollBox *box,tCollBox *boxWorld,tMatrix3 dir,tVector3 pos)
{
for(int i=0;i<8;i++)
((tVector3*)boxWorld)[i]=((tVector3*)box)[i]*dir+pos;
}
//Check if any of the boxes in the array boxes1 intersects any of the boxes in the array boxes2.
//boxes are translated using dir1/2 and pos1/2.
//if an intersection is found, it is returned in hitPoint.
int CheckBoxListCollision(tCollBox *boxes1,tCollBox *boxes2,int numBoxes1,int numBoxes2,tMatrix3 dir1,tMatrix3 dir2,tVector3 pos1,tVector3 pos2,tVector3 *hitPoint)
{
//allocte memory for boxes in world coordinates
tCollBox *worldBoxes1=(tCollBox*)MemoryAllocateBlock(sizeof(tCollBox)*numBoxes1);
tCollBox *worldBoxes2=(tCollBox*)MemoryAllocateBlock(sizeof(tCollBox)*numBoxes2);
//transform boxes into world coordinates
for(int i=0;i<numBoxes1;i++)
BoxWorldCoords(boxes1+i,worldBoxes1+i,dir1,pos1);
for(int i=0;i<numBoxes2;i++)
BoxWorldCoords(boxes2+i,worldBoxes2+i,dir2,pos2);
int hitObj,hitBox;
for(int i=0;i<numBoxes1;i++)
for(int j=0;j<numBoxes2;j++)
//for each pair of boxes test for intersection
if(CheckBoxCollision(worldBoxes1+i,worldBoxes2+j,hitPoint,&hitObj))
{
MemoryFreeBlock(worldBoxes1);
MemoryFreeBlock(worldBoxes2);
return true;
}
MemoryFreeBlock(worldBoxes1);
MemoryFreeBlock(worldBoxes2);
return false;
}
//for a set of boxes, calculate the radius of the bounding sphere
//= the distance of the furthest point from (0,0,0) (in object coordinates)
float CalcMaxCollRadius(tCollBox *boxes,int numCollBoxes)
{
tVector3 extends=Vector(0,0,0);
for(int i=0;i<numCollBoxes;i++)
for(int j=0;j<8;j++)
{
if(fabs(((tVector3*)(boxes+i))[j].x)>extends.x)
extends.x=fabs(((tVector3*)(boxes+i))[j].x);
if(fabs(((tVector3*)(boxes+i))[j].y)>extends.y)
extends.y=fabs(((tVector3*)(boxes+i))[j].y);
if(fabs(((tVector3*)(boxes+i))[j].z)>extends.z)
extends.z=fabs(((tVector3*)(boxes+i))[j].z);
}
return ~extends;
}
//implements the physical laws of collision.
//given two velocities and two masses, returns two new velocities
//collType defines what type of collision this is:
//if collType=0, this is a completely plastic collision, ie. both objects will be moving at the same speed afterwards.
//if collType=1, this is a completely elastic collision, ie. both objects will be moving away from each other.
void CalcCollisionImpulses(tVector3 v1,tVector3 v2,float m1,float m2,tVector3 *v1n,tVector3 *v2n,float collType)
{
tVector3 vUnelastic=(m1*v1+m2*v2)/(m1+m2);
tVector3 v1Elastic=(m1*v1+m2*(2*v2-v1))/(m1+m2);
tVector3 v2Elastic=(m2*v2+m1*(2*v1-v2))/(m1+m2);
*v1n=collType*v1Elastic+(1-collType)*vUnelastic;
*v2n=collType*v2Elastic+(1-collType)*vUnelastic;
}
//Tests for a collision between a car and a solid entity (any obstacles, etc.. in the game), and takes appropoiate action
void HandleCarSolidCollision(tGameEntity *carEntity,tGameEntity *entity)
{
tCarPhysics *phys=(tCarPhysics*)carEntity->physics;
tCarDefinition *car=&(phys->car);
tSolidEntityPhysics *ent=(tSolidEntityPhysics*)FileGetParsedDataPtr(entity->physicsData,kParserTypeSolidEntityDesc,sizeof(tSolidEntityPhysics));
//get bounding sphere radii of objects
if(!car->maxCollRadius)car->maxCollRadius=CalcMaxCollRadius(car->coll,car->numCollBoxes);
if(!ent->maxCollRadius)ent->maxCollRadius=CalcMaxCollRadius(ent->coll,ent->numCollBoxes);
//tests if the object's bounding spheres intersect
tVector3 dist=carEntity->pos-entity->pos;
if(sqr(dist)>sqr(car->maxCollRadius+ent->maxCollRadius))
return;
tVector3 hitPoint;
int coll=false;
int movable=ent->movable;
if(!ent->liquid)
if(movable)
{
if(CheckBoxListCollision(car->coll,ent->coll,car->numCollBoxes,ent->numCollBoxes,carEntity->dir,entity->dir,carEntity->pos,entity->pos,&hitPoint))
{
if((entity->pos-carEntity->pos)*carEntity->velo>0)
{
entity->pos=entity->pos+carEntity->velo*kFrameTime;
coll=true;
}
}
}
else
if(CheckBoxListCollision(car->coll,ent->coll,car->numCollBoxes,ent->numCollBoxes,carEntity->dir,entity->dir,carEntity->pos,entity->pos,&hitPoint))
{
carEntity->pos=carEntity->oldPos;
MatrixCopy(carEntity->oldDir,carEntity->dir);
coll=true;
phys->collision=gFrameCount;
}
else
coll=CheckBoxListCollision(car->coll,ent->coll,car->numCollBoxes,ent->numCollBoxes,carEntity->dir,entity->dir,carEntity->pos,entity->pos,&hitPoint);
//was there a collision?
if(coll)
{
//is the object movable (like a barrel, etc..)
if(movable)
{
//calculate new velocities of car and object
tVector3 carHitPoint=hitPoint-carEntity->pos;
tVector3 carPointVelo=((carHitPoint*carEntity->rVelo)-carHitPoint)*kFPS+carEntity->velo;
tVector3 entHitPoint=hitPoint-entity->pos;
tVector3 entPointVelo=((entHitPoint*entity->rVelo)-entHitPoint)*kFPS+entity->velo;
tVector3 newCarPointVelo;
tVector3 newEntPointVelo;
CalcCollisionImpulses(carPointVelo,entPointVelo,car->mass,ent->mass,&newCarPointVelo,&newEntPointVelo,0.5);
float carImpulseScale=(~carEntity->velo)/10;
if(carImpulseScale>1)carImpulseScale=1;
ApplyImpulse(carEntity,carHitPoint,(newCarPointVelo-carPointVelo)*0.6*carImpulseScale,0.15,false);
tVector3 oldVelo=entity->velo;
tMatrix3 oldrVelo;
MatrixCopy(entity->rVelo,oldrVelo);
ApplyImpulse(entity,entHitPoint,(newEntPointVelo-entPointVelo)*0.25,0.5,false);
if(ent->mass>=kSolidEntityNetworkMass&&carEntity->physicsMachine==kPhysicsLocal)
entity->lastFrame=gFrameCount;
if(ent->numSounds)
{
float vol=~(newEntPointVelo-entPointVelo)*0.1;
if(vol>0.5)
CarPlayCrashNoise(carEntity,FileGetIndexedReference(ent->sound,RandomInt(0,ent->numSounds)),vol);
}
}
else//object not movable (eg. trees, etc..)
{
tVector3 entHitPoint=hitPoint-entity->pos;
hitPoint=hitPoint-carEntity->pos;
tVector3 rotVelo=((hitPoint*carEntity->rVelo)-hitPoint)*kFPS;
if(~rotVelo>5)rotVelo=!rotVelo*5;
tVector3 pointVelo=rotVelo+carEntity->velo;
float sparks=(~carEntity->velo-kMinSparkVelo)/(kMaxSparkVelo-kMinSparkVelo);
if(sparks>1)sparks=1;
sparks*=kMaxSpark*kFrameTime;
MakeSparks(hitPoint+carEntity->pos,sparks);
MakeSqueaks(carEntity,~pointVelo,1);
ApplyImpulse(carEntity,hitPoint,-pointVelo*0.25,0.8,false);
if(~carEntity->velo>10&&ent->inertia&&!ent->movable)
{
tVector3 torque=(entHitPoint)%(carEntity->velo*car->mass*kFPS);
tMatrix3 invMatrix;
MatrixTranspose(entity->dir,invMatrix);
torque=torque*invMatrix;
tVector3 angularAcceleration=torque*1/ent->inertia*entity->dir;
tMatrix3 accelerationMatrix;
RotationVectorToMatrix(angularAcceleration*kFrameTime*kFrameTime,accelerationMatrix);
MatrixMult(entity->dir,accelerationMatrix,entity->dir);
carEntity->pos=carEntity->pos-carEntity->velo*kFrameTime*6;
}
float v=~carEntity->velo;
if(v>5)
carEntity->velo=carEntity->velo*((v-5)/v);
else
carEntity->velo=Vector(0,0,0);
}
if(entity->untouchable)
gDisqualified=true;
}
}
//Checks if two cars collide and take appropiate action
void HandleCarCarCollision(tGameEntity *carEntity1,tGameEntity *carEntity2)
{
tCarPhysics *phys1=(tCarPhysics*)carEntity1->physics;
tCarDefinition *car1=&(phys1->car);
tCarPhysics *phys2=(tCarPhysics*)carEntity2->physics;
tCarDefinition *car2=&(phys2->car);
//get bounding sphere radii of objects
if(!car1->maxCollRadius)car1->maxCollRadius=CalcMaxCollRadius(car1->coll,car1->numCollBoxes);
if(!car2->maxCollRadius)car2->maxCollRadius=CalcMaxCollRadius(car2->coll,car2->numCollBoxes);
//tests if the object's bounding spheres intersect
tVector3 dist=carEntity1->pos-carEntity2->pos;
if(sqr(dist)>sqr(car1->maxCollRadius+car2->maxCollRadius))
return;
tVector3 hitPoint;
int coll=false;
//tests if objects box lists intersect
while(CheckBoxListCollision(car1->coll,car2->coll,car1->numCollBoxes,car2->numCollBoxes,carEntity1->dir,carEntity2->dir,carEntity1->pos,carEntity2->pos,&hitPoint)&&!(gReplay&&coll))
{
//move cars away from ech other until they no longer intersect
if(!gReplay)
{
tVector3 diff=carEntity1->pos-carEntity2->pos;
carEntity2->pos=carEntity1->pos-diff*1.01;
carEntity1->pos=carEntity2->pos+diff*(1.01*1.01);
}
coll=true;
}
//was there a collision?
if(coll)
{
//calculate new velocities of cars
tVector3 car1HitPoint=hitPoint-carEntity1->pos;
tVector3 car1PointVelo=((car1HitPoint*carEntity1->rVelo)-car1HitPoint)*kFPS;
if(carEntity1->physicsMachine==kPhysicsLocal)
car1PointVelo=car1PointVelo+carEntity1->velo;
else
car1PointVelo=car1PointVelo+carEntity1->collVelo;
tVector3 car2HitPoint=hitPoint-carEntity2->pos;
tVector3 car2PointVelo=((car2HitPoint*carEntity2->rVelo)-car2HitPoint)*kFPS;
if(carEntity2->physicsMachine==kPhysicsLocal)
car2PointVelo=car2PointVelo+carEntity2->velo;
else
car2PointVelo=car2PointVelo+carEntity2->collVelo;
tVector3 newCar1PointVelo;
tVector3 newCar2PointVelo;
if(!gReplay)
{
CalcCollisionImpulses(car1PointVelo,car2PointVelo,car1->mass,car2->mass,&newCar1PointVelo,&newCar2PointVelo,1);
ApplyImpulse(carEntity1,car1HitPoint,(newCar1PointVelo-car1PointVelo)*0.25,0.1,false);
ApplyImpulse(carEntity2,car2HitPoint,(newCar2PointVelo-car2PointVelo)*0.25,0.1,false);
carEntity1->netVelo=carEntity1->velo;
MatrixCopy(carEntity1->rVelo,carEntity1->netRVelo);
carEntity1->netPos=carEntity1->pos;
MatrixCopy(carEntity1->dir,carEntity1->netDir);
carEntity2->netVelo=carEntity2->velo;
MatrixCopy(carEntity2->rVelo,carEntity2->netRVelo);
carEntity2->netPos=carEntity2->pos;
MatrixCopy(carEntity2->dir,carEntity2->netDir);
carEntity1->accel=Vector(0,0,0);
carEntity2->accel=Vector(0,0,0);
}
float impulse=~(newCar1PointVelo-car1PointVelo)+~(newCar2PointVelo-car2PointVelo);
float sparks=(impulse-kMinSparkVelo)/(kMaxSparkVelo-kMinSparkVelo);
if(sparks>1)sparks=1;
sparks*=kMaxSpark*kFrameTime*5;
MakeSparks(hitPoint,sparks);
MakeSqueaks(carEntity1,impulse,1);
}
}
//for a car, test if it collides with anything else (ground, other cars or objects).
void CarCheckCollision(tGameEntity *carEntity)
{
tGameEntity *entity=(tGameEntity*)gFirstEntity->next;
//if(carEntity->physicsMachine==kPhysicsLocal)
{
// if(!gReplay)
if(!(gFrameCount%kCarCollisionRate))
{
if(carEntity->physicsMachine!=kPhysicsLocal)
gQuickRoadCollision=true;
gRoadRestrictedBorders=true;
CheckGroundCollision(carEntity);
gRoadRestrictedBorders=false;
gQuickRoadCollision=false;
}
}
//for each other object, test for collision.
if(!(gFrameCount%kCarCollisionRate))
while(entity!=gFirstEntity)
{
entity->regData=carEntity->regData;
if(sqr(entity->pos-carEntity->pos)<500)
if(entity!=carEntity)
switch(entity->physicsType)
{
case kPhysicsTypeSolid:
HandleCarSolidCollision(carEntity,entity);
break;
case kPhysicsTypeCar:
//if(carEntity->physicsMachine==kPhysicsLocal)
HandleCarCarCollision(carEntity,entity);
break;
}
entity=(tGameEntity*)entity->next;
}
}
//for a solid entity, check if it intersects with the ground
void SolidCheckCollision(tGameEntity *entity)
{
tSolidEntityPhysics *ent=(tSolidEntityPhysics*)FileGetParsedDataPtr(entity->physicsData,kParserTypeSolidEntityDesc,sizeof(tSolidEntityPhysics));
if(!ent->movable)
return;
CheckGroundCollision(entity);
tVector3 xDiff=*MatrixGetXVector(entity->rVelo)-Vector(1,0,0);
tVector3 yDiff=*MatrixGetYVector(entity->rVelo)-Vector(0,1,0);
tVector3 zDiff=*MatrixGetZVector(entity->rVelo)-Vector(0,0,1);
*MatrixGetXVector(entity->rVelo)=*MatrixGetXVector(entity->rVelo)-xDiff*1.5*kFrameTime;
*MatrixGetYVector(entity->rVelo)=*MatrixGetYVector(entity->rVelo)-yDiff*1.5*kFrameTime;
*MatrixGetZVector(entity->rVelo)=*MatrixGetZVector(entity->rVelo)-zDiff*1.5*kFrameTime;
}
tRegData rd;
//check for any object collisions
void CollisionFrame()
{
#ifndef __TARGET_TOOLAPP
rd.name=RT3_GetLicenseName();
rd.numCopies=RT3_GetLicenseCopies();
#endif
tGameEntity *entity=(tGameEntity*)gFirstEntity->next;
while(entity!=gFirstEntity)
{
entity->regData=&rd;
//has the object moved in the last second?
//if we have a solid entity like a barrel which has been kicked over by a car,
//we don't need to process collisions with the ground anymore once the barrel
//has come to rest.
if(entity->lastActivity+kFPS>gFrameCount&&entity->id>=0)
//if(entity->physicsMachine!=kPhysicsRemote||entity->lastCollFrame==0||entity->lastCollFrame>gFrameCount-kFPS)
switch(entity->physicsType)
{
case kPhysicsTypeCar:
CarCheckCollision(entity);
break;
case kPhysicsTypeSolid:
if(!(gFrameCount%kSolidCollisionRate))
SolidCheckCollision(entity);
break;
}
entity=(tGameEntity*)entity->next;
}
}

15
source/collision.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef __COLLISION
#define __COLLISION
#define kCarCollisionRate 1
#define kSolidCollisionRate 5
#define kSolidEntityNetworkMass 100
void ApplyImpulse(tGameEntity *entity,tVector3 attackPoint,tVector3 veloDiff,float rotationFactor,int net);
float GetGroundOffset(tVector3 point,int *lastRoadIndex,tVector3 *normal,int *surfaceType);
float GetGroundOffsetAndBump(tVector3 point,int *lastRoadIndex,tVector3 *normal,int *surfaceType,float *bump);
void SolidCheckCollision(tGameEntity *entity);
void CollisionFrame();
#endif

41
source/config.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "fileio.h"
#include "config.h"
#include "gamemem.h"
#include "parser.h"
#include "gameinitexit.h"
#include "carselection.h"
#include "screen.h"
#include <string.h>
tSysConfig *gConfig;
void ConfigInit()
{
gConfig=(tSysConfig*)FileGetParsedDataPtr(FileGetReference(kConfigFileName),kParserTypeConfigDesc,sizeof(tSysConfig));
if(strlen(gConfig->playerName)==0)
CFStringGetCString(CSCopyUserName(false),gConfig->playerName,256,0);
if(strlen(gConfig->gameName)==0)
CFStringGetCString(CSCopyMachineName(),gConfig->gameName,256,0);
if(strlen(gConfig->playerName)>=kMaxNameLength)
gConfig->playerName[kMaxNameLength-1]='\0';
if((gConfig->dbIndex^gConfig->challengeData)!=0xdeadbeef)
{
gConfig->dbIndex=0xdeadbeef;
gConfig->challengeData=0;
}
int availableCars[kMaxCars];
int carCount;
GetAvailableCars(availableCars,&carCount,false,false);
for(int i=0;i<11;i++)
{
int ok=false;
for(int j=0;j<carCount;j++)
if(availableCars[j]==gConfig->opponentCars[i])
ok=true;
if(!ok)
gConfig->opponentCars[i]=availableCars[0];
}
if(ScreenNoWindow())
gConfig->fullscreen=true;
}

108
source/config.h Normal file
View File

@ -0,0 +1,108 @@
#ifndef __CONFIG
#define __CONFIG
#include "fileio.h"
enum{
kInteriorDisplayOff,
kInteriorDisplayPlayerOnly,
kInteriorDisplayCloseCarsOnly,
kInteriorDisplayAlways,
kInteriorDisplayNumModes
};
typedef struct{
int keyID;
int controllerID1;
int controllerID2;
int elementID;
char identifier[32];
char controllerIdentifier[256];
}tKeyConfig;
typedef struct{
int axisControllerID1;
int axisControllerID2;
int axisElementID;
char axisIdentifier[256];
int min,mid,max;
float deadzone;
}tAxisConfig;
#define kMaxPersonalRecords 1024
typedef struct{
tFileRef car,map;
int mode,direction;
int time;
}tPersonalRecord;
typedef struct{
int screenXSize,screenYSize;
int windowX,windowY;
int fullscreen;
int onlyRegisteredPlayers;
int useBetaBuilds;
int noGhost;
float gfxDynamics;
int allowHugeGames;
int interfaceSounds;
int stencil;
int performanceStats;
int textureQuality;
int soundEnable;
int maxPlayers;
int color32Bit;
int fsaa;
int guideSigns;
int motionBlur;
int allCams;
int cantGoBackwards;
int ffb;
float ffbIntensity;
int arcade,reverse;
int showPlayerNames;
int trackerEnable;
int carsOnSpeed;
int demolition;
int registerLapTimes;
int metricUnits;
int challengeData;
int dbIndex;
int textureFilter;
int showReplays;
int seperateGasBrake;
int disableAnalogueTCS;
int reverseGas;
tFileRef lastCar,lastEnemy,lastRoad,lastEnv;
int numEnemies,automatic,lastLaps,lastColor;
float soundVolume,musicVolume;
int maxCarSources;
float hudTransparency;
int interiorDisplay;
int cameraMode;
int numKeys,numAxis,numTaunts;
char playerName[256];
char gameName[256];
char password[256];
char (*taunts)[256];
char confirmedVersion[256];
tKeyConfig *keys;
tAxisConfig *axis;
tFileRef opponentCars[11];
int opponentColors[11];
int challengeRecords[32];
int numPersonalRecords;
tPersonalRecord records[kMaxPersonalRecords];
}tSysConfig;
extern tSysConfig *gConfig;
#define kConfigDefault16Name "default16.cfg"
#define kConfigDefault32Name "default32.cfg"
#define kConfigDefault64Name "default64.cfg"
#define kConfigFileName "Redline Preferences"
#define kConfigFilePName "\pRedline Preferences"
void ConfigInit();
#endif

740
source/controls.cpp Executable file
View File

@ -0,0 +1,740 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "entities.h"
#include "gameframe.h"
#include "carphysics.h"
#include "controls.h"
#include "config.h"
#include "renderframe.h"
#include "gameinitexit.h"
#include "particles.h"
#include "gametime.h"
#include "network.h"
#include "random.h"
#include "reg_tool_3.h"
#include "rt3_redline.h"
#include "initexit.h"
#include "text.h"
#define kThrottleTime 0.3
#define kThrottleReleaseTime 0.2
#define kThrottleTCRReleaseTime 0.7
#define kThrottleTimeSpinning 0.6
#define kBrakeTime 0.4
#define kBrakeReleaseTime 0.2
#define kSteerReleaseTime 0.6
#define kVeloSteerReleaseTime 0
//#define kSteerTime 1.2
#define kSteerTime 0.6
#define kVeloSteerTime 0.05
#define kHandbrakeTime 0.2
#define kHandbrakeReleaseTime 0.01
#define sign(x) ((x)<0?-1:1)
#define kMaxThottleSlip 0.033
#define kMinSpinAngularVelo (4*PI)
#define kMaxBrakeSlip 0.05
int gGearUpPress=false;
int gGearDownPress=false;
int gLightPress=false;
int gCameraPress=false;
int gReplayCameraPress=false;
int gTauntPress=false;
int gArrowPress=false;
int gEscPress=false;
int gPausePress=false;
float gSteerAxis=0;
float gThrottleAxis=0;
int gAxisSteering=false;
int gAxisThrottleBrake=false;
int gInputChatMode=false;
int gInputEscMode=kInputEscModeNone;
int gInputEscSelection;
int gGameChatMessageSize=0;
#define kMaxGameChatMessageSize 128
char gGameChatMessage[kMaxGameChatMessageSize]="";
void ButtonThrottle(tCarDefinition *car,tCarPhysics *phys,float driveSlip,float angularVelo,float velo,float throttleInput,int tcr)
{
float maxSlip=velo<20?0.2-velo/20*(0.2-kMaxThottleSlip):kMaxThottleSlip;
if(throttleInput<0)
throttleInput=0;
if(throttleInput>phys->throttle){
if(driveSlip*sign(phys->gear)<maxSlip||fabs(angularVelo)<kMinSpinAngularVelo||!tcr||(phys->clutch<1&&phys->rpm>car->clutchRPM))
{
phys->throttle+=kFrameTime*(1/kThrottleTime);
if(throttleInput>phys->throttle)
throttleInput=phys->throttle;
}
else
{
phys->throttle-=kFrameTime*(1/kThrottleTCRReleaseTime);
if(throttleInput<phys->throttle)
throttleInput=phys->throttle;
}
}
else {
phys->throttle-=kFrameTime*(1/kThrottleReleaseTime);
if(throttleInput<phys->throttle)
throttleInput=phys->throttle;
}
if(phys->throttle>1)
phys->throttle=1;
else if(phys->throttle<phys->idleThrottle&&phys->rpm<=car->idleRPM)
phys->throttle=phys->idleThrottle;
phys->clutch=1;
}
void ButtonBrake(tCarPhysics *phys,float slip,float angularVelo,float brakeInput,int als)
{
if(brakeInput>1)
brakeInput=1;
else if(brakeInput<0)
brakeInput=0;
if(brakeInput<0)
brakeInput=0;
if(brakeInput>phys->brake)
{
if((-slip*sign(angularVelo)<kMaxBrakeSlip)||(phys->brake<0.1)||!als)
phys->brake+=kFrameTime*(1/kBrakeTime);
else
phys->brake-=kFrameTime*(1/kBrakeTime);
phys->arcadeBrake+=kFrameTime*(1/kBrakeTime);
if(brakeInput<phys->brake)
phys->brake=brakeInput;
if(brakeInput<phys->arcadeBrake)
phys->arcadeBrake=brakeInput;
}
else
{
phys->brake-=kFrameTime*(1/kBrakeReleaseTime);
phys->arcadeBrake-=kFrameTime*(1/kBrakeReleaseTime);
if(brakeInput>phys->brake)
phys->brake=brakeInput;
if(brakeInput>phys->arcadeBrake)
phys->arcadeBrake=brakeInput;
}
}
void CalcThrottleBrake(tCarDefinition *car,tCarPhysics *phys,float driveSlip,float angularVelo,float velo,float slip)
{
if(car->clutchRPM==0)
car->clutchRPM=3000;
int raceOver=(phys->lapCount>gGameInfo->numLaps&&gGameInfo->numLaps!=-1);
if(!raceOver)
{
float gas,brake,gasbrake;
if(gConfig->seperateGasBrake)
{
if(gConfig->reverseGas)
{
gas=GetAxisInput(kInputThrottleAxis);
brake=GetAxisInput(kInputBrakeAxis);
}
else
{
gas=1-GetAxisInput(kInputThrottleAxis);
brake=1-GetAxisInput(kInputBrakeAxis);
}
gasbrake=gas-brake;
}
else
{
gasbrake=GetAxisInput(kInputThrottleBrakeAxis);
if(gConfig->reverseGas)
gasbrake=-gasbrake;
gas=gasbrake;
brake=-gasbrake;
}
if(gAxisThrottleBrake)
{
if(gConfig->automatic&&phys->gear==-1)
{
ButtonBrake(phys,slip,angularVelo,gas,true);
ButtonThrottle(car,phys,driveSlip,angularVelo,velo,brake,(brake<0.95)&&!gConfig->disableAnalogueTCS);
}
else
{
ButtonBrake(phys,slip,angularVelo,brake,true);
ButtonThrottle(car,phys,driveSlip,angularVelo,velo,gas,(gas<0.95)&&!gConfig->disableAnalogueTCS);
}
if(GetButtonInput(kInputKickdownButton)||GetButtonInput(kInputBrakeButton)||GetButtonInput(kInputGasButton))
gAxisThrottleBrake=false;
}
else
{
int brake=GetButtonInput(kInputBrakeButton);
int gas=GetButtonInput(kInputGasButton);
int kickdown=GetButtonInput(kInputKickdownButton);
int gasInput=(gConfig->automatic?(phys->gear>=0?gas||kickdown:brake):(gas||kickdown))?1:0;
ButtonThrottle(car,phys,driveSlip,angularVelo,velo,gasInput,!kickdown);
int brakeInput=(gConfig->automatic?(phys->gear>=0?brake:gas||kickdown):brake)?1:0;
ButtonBrake(phys,slip,angularVelo,brakeInput,true);
if(gThrottleAxis!=gasbrake)
gAxisThrottleBrake=true;
}
gThrottleAxis=gasbrake;
}
else
{
ButtonBrake(phys,slip,angularVelo,1,true);
ButtonThrottle(car,phys,driveSlip,angularVelo,velo,0,true);
}
}
void ButtonSteering(tGameEntity *entity,tCarDefinition *car,tCarPhysics *phys,float velo,float input)
{
if(input>1) input=1;
else if(input<-1) input=-1;
tVector3 carDir=!Vector(MatrixGetZVector(entity->dir)->x,0,MatrixGetZVector(entity->dir)->z);
tVector3 veloDir=!Vector(entity->velo.x,0,entity->velo.z);
float angleSin=(veloDir%carDir).y;
if(fabs(angleSin)>1.0)
angleSin=sign(angleSin);
float angle=-asin(angleSin);
float optimalSteering=angle/car->wheels[0].maxAngle;
if(velo<1)
optimalSteering=0;
if(input>phys->steering)
{
float steerSpeed=(phys->steering<0)?(1/(kSteerReleaseTime+kVeloSteerReleaseTime*velo)) :(1/(kSteerTime+kVeloSteerTime*velo));
if(phys->steering<optimalSteering)
steerSpeed*=1+(optimalSteering-phys->steering)*4;
if(gGameInfo->arcade==kGameModeTurbo)
steerSpeed*=2;
phys->steering+=kFrameTime*steerSpeed;
if(input<phys->steering)
phys->steering=input;
}
else if(input<phys->steering)
{
float steerSpeed=(phys->steering>0)?(1/(kSteerReleaseTime+kVeloSteerReleaseTime*velo)) :(1/(kSteerTime+kVeloSteerTime*velo));
if(phys->steering>optimalSteering)
steerSpeed*=1+(phys->steering-optimalSteering)*4;
if(gGameInfo->arcade==kGameModeTurbo)
steerSpeed*=2;
phys->steering-=kFrameTime*steerSpeed;
if(input>phys->steering)
phys->steering=input;
}
}
void CalcSteering(tGameEntity *entity,tCarDefinition *car,tCarPhysics *phys,float velo)
{
if(gAxisSteering)
{
gSteerAxis=GetAxisInput(kInputSteerAxis);
float ax3=gSteerAxis*gSteerAxis*gSteerAxis;
float ax=0.3*gSteerAxis+0.7*ax3;
ButtonSteering(entity,car,phys,velo,ax);
if(GetButtonInput(kInputSteerLeftButton)||GetButtonInput(kInputSteerRightButton))
gAxisSteering=false;
}
else
{
float input=0;
int l=GetButtonInput(kInputSteerLeftButton);
int r=GetButtonInput(kInputSteerRightButton);
if(l&&r)
input=phys->steering;
else if(l)
input=1;
else if(r)
input=-1;
ButtonSteering(entity,car,phys,velo,input);
if(gSteerAxis!=GetAxisInput(kInputSteerAxis))
gAxisSteering=true;
}
}
typedef struct{
char *name;
int numCopies;
}tRegData;
void ControlEntityUserInput(tGameEntity *entity)
{
if(entity->physicsType!=kPhysicsTypeCar)
return;
tCarPhysics *phys=(tCarPhysics*)entity->physics;
tCarDefinition *car=&(phys->car);
int isValid=true;
float velo=~entity->velo;
float driveSlip=0,slip=0,angularVelo=0;
int wheelsOnGround=0;
int valid=true;
if((car->demoAvailable-car->numColors!=1)&&(entity==gCarEntities[gGameInfo->playerID]))
isValid=false;
for(int i=0;i<car->numWheels;i++)
{
if(phys->wheels[i].onGround)
{
driveSlip+=phys->wheels[i].slip*car->wheels[i].powered;
slip+=phys->wheels[i].slip;
wheelsOnGround++;
}
angularVelo+=phys->wheels[i].angularVelo*car->wheels[i].powered;
}
if((gMapInfo->demoAvailable+gMapInfo->numObjs))
isValid=false;
if(wheelsOnGround)
slip/=wheelsOnGround;
else
slip=0;
CalcThrottleBrake(car,phys,driveSlip,angularVelo,velo,slip);
CalcSteering(entity,car,phys,velo);
if(!isValid)
if(entity->regData)
qRT3_LicenseTestApp2(phys->regCode,((tRegData*)(entity->regData))->name,((tRegData*)(entity->regData))->numCopies,isValid);
if(GetButtonInput(kInputHandbrakeButton))
phys->handbrake+=kFrameTime*(1/kHandbrakeTime);
else
phys->handbrake-=kFrameTime*(1/kHandbrakeReleaseTime);
if(phys->handbrake>1)
phys->handbrake=1;
else if(phys->handbrake<0)
phys->handbrake=0;
if(!isValid)
if(entity->regData)
qRT3_LicenseTestBlock2(phys->regCode,((tRegData*)(entity->regData))->name,((tRegData*)(entity->regData))->numCopies,isValid);
if(gFrameCount*kFrameTime>=kStartGameDelaySeconds)
{
if(gConfig->automatic)
{
if((gFrameCount-1)*kFrameTime>phys->lastGearSwitch+car->gearSwitchTime)
{
if(phys->gear>=1)
{
int shiftUp=false;
if(car->shiftUpRPMFix)
shiftUp=phys->rpm>car->shiftUpRPMFix;
else
shiftUp=phys->rpm>car->maxRPM;
if(shiftUp&&phys->gear<car->numGears-2)
{
if(!GetButtonInput(kInputKickdownButton)&&phys->gear>0&&gFrameCount*kFrameTime>=kStartGameDelaySeconds+1)
{
phys->lastGear=phys->gear;
phys->gear++;
phys->lastGearSwitch=gFrameCount*kFrameTime;
if(gGameInfo->arcade==kGameModeTurbo)
phys->lastGearSwitch-=car->gearSwitchTime*0.5;
}
}
else if(phys->rpm<car->shiftDownRPM&&phys->gear>1)
{
phys->lastGear=phys->gear;
phys->gear--;
phys->lastGearSwitch=gFrameCount*kFrameTime;
if(gGameInfo->arcade==kGameModeTurbo)
phys->lastGearSwitch-=car->gearSwitchTime*0.5;
}
}
if(phys->gear==0||velo<1)
{
if(phys->gear<1&&((GetButtonInput(kInputKickdownButton)||GetButtonInput(kInputGasButton)))||(gAxisThrottleBrake&&gThrottleAxis>0))
{
phys->lastGear=phys->gear;
phys->gear=1;
phys->lastGearSwitch=gFrameCount*kFrameTime;
}
else if(phys->gear>=0&&GetButtonInput(kInputBrakeButton)||(gAxisThrottleBrake&&gThrottleAxis<0))
{
phys->lastGear=phys->gear;
phys->gear=-1;
phys->lastGearSwitch=gFrameCount*kFrameTime;
}
}
}
}
else
{
if(GetButtonInput(kInputGearUp)){
if(phys->gear<car->numGears-2&&!gGearUpPress){
phys->lastGear=phys->gear;
phys->gear++;
gGearUpPress=true;
phys->lastGearSwitch=gFrameCount*kFrameTime;
if(gGameInfo->arcade==kGameModeTurbo)
phys->lastGearSwitch-=car->gearSwitchTime*0.5;
}
}
else gGearUpPress=false;
if(GetButtonInput(kInputGearDown)){
if(phys->gear>-1&&!gGearDownPress){
phys->lastGear=phys->gear;
phys->gear--;
gGearDownPress=true;
phys->lastGearSwitch=gFrameCount*kFrameTime;
if(gGameInfo->arcade==kGameModeTurbo)
phys->lastGearSwitch-=car->gearSwitchTime*0.5;
}
}
else gGearDownPress=false;
}
float gearSwitchTime=phys->gear<=1?0.3:car->gearSwitchTime;
if(gFrameCount*kFrameTime<phys->lastGearSwitch+gearSwitchTime)
{
float switchTime=(gFrameCount*kFrameTime-phys->lastGearSwitch)/gearSwitchTime;
phys->clutch=switchTime;
if(phys->rpm<car->clutchRPM)
phys->clutch=(phys->rpm-car->idleRPM*1.5)/(car->clutchRPM-car->idleRPM*1.5);
if(switchTime<0.5&&phys->gear>1)
if(phys->lastGear>phys->gear)
phys->throttle=0.7;
else
phys->throttle=phys->idleThrottle;
if(entity==gViewedEntity)
{
int invalid=false;
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_CODE_01,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_CODE_02,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_03,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_04,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_05,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_06,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_07,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_08,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_09,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_10,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_11,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_12,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_13,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_14,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_15,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_16,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_17,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_18,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_19,invalid);
if(!invalid)qRT3_LicenseIsSameCode(phys->regCode,RT3_PIRATED_FAKE_20,invalid);
valid=!invalid;
}
}
else
if(phys->rpm<car->clutchRPM)
phys->clutch=(phys->rpm-car->idleRPM*1.5)/(car->clutchRPM-car->idleRPM*1.5);
else
phys->clutch=1;
if(phys->clutch<0)
phys->clutch=0;
}
if(!isValid)
if(gFrameCount>kFPS*30)
phys->throttle=0;
if(GetButtonInput(kInputHorn))
phys->lightFlags|=kLightFlagHorn;
else
phys->lightFlags&=~kLightFlagHorn;
if(!valid)
if(RandomProb(kFrameTime/car->gearSwitchTime*7))
phys->gear=0;
if(GetButtonInput(kInputLeftIndicator))
phys->lightFlags|=kLightFlagLIndLight;
else if(GetButtonInput(kInputRightIndicator))
phys->lightFlags|=kLightFlagRIndLight;
else
phys->lightFlags&=~(kLightFlagLIndLight+kLightFlagRIndLight);
if(GetButtonInput(kInputLightButton)){
if(!gLightPress)
{
gLightPress=true;
phys->lightFlags^=kLightFlagDriveLight;
}
}else gLightPress=false;
}
void ControlEntityAIInput(tGameEntity *entity);
extern float gEscDisplay;
void HandleEscModeInput()
{
if(GetInterfaceKey(kInterfaceKeyEsc)||GetInterfaceKey(kInterfaceKeyDelete))
{
if(!gEscPress)
{
gInputEscMode=kInputEscModeNone;
gEscPress=true;
if(!gGameInfo->network)
UnPauseGame();
}
}
else
gEscPress=false;
if(GetInterfaceKey(kInterfaceKeyDown))
{
if(!gArrowPress)
{
gInputEscSelection--;
if(gInputEscSelection<0)
gInputEscSelection=(gGameInfo->network?1:2);
gArrowPress=true;
}
}
else if(GetInterfaceKey(kInterfaceKeyUp))
{
if(!gArrowPress)
{
gInputEscSelection=(gInputEscSelection+1)%(gGameInfo->network?2:3);
gArrowPress=true;
}
}
else
gArrowPress=false;
if(GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter))
{
if(gInputEscSelection==1)
if(gInputEscMode==kInputEscModeQuit)
Exit();
else
gGameEnd=kEndGame;
if(gInputEscSelection==2)
gGameEnd=kEndGameRestart;
if(gInputEscMode==kInputEscModeQuit)
gEscDisplay=0;
gInputEscMode=kInputEscModeNone;
if(!gGameInfo->network)
UnPauseGame();
}
}
void HandleChatModeInput()
{
while(char ch=GetKeyInput(NULL))
{
if(ch=='\r')
{
if(ch=='\r'&&strlen(gGameChatMessage)>0)
{
tChatMessage msg;
memset((void*)&msg,0,sizeof(tChatMessage));
sprintf(msg.str,"%s: \255#a\255%s",gConfig->playerName,gGameChatMessage);
msg.flags=0;
NetworkSendPacket(kMessageTypeChat,&msg,sizeof(tChatMessage),kMessagePriorityHigh,kMessageSendToAll);
}
gGameChatMessage[0]='\0';
gGameChatMessageSize=0;
gInputChatMode=false;
}
if((ch==0x7f||ch==0x08)&&gGameChatMessageSize>0)
gGameChatMessage[--gGameChatMessageSize]='\0';
if(ch>=' '&&ch<='z'&&gGameChatMessageSize<kMaxGameChatMessageSize-1)
{
gGameChatMessage[gGameChatMessageSize++]=ch;
gGameChatMessage[gGameChatMessageSize]='\0';
}
}
}
void HandleNetworkInput()
{
if(GetButtonInput(kInputChat))
{
gInputChatMode=true;
FlushKeys();
}
int tauntPress=false;
for(int i=kInputTaunt1;i<=kInputTaunt5;i++)
if(GetButtonInput(i))
{
tauntPress=true;
if(!gTauntPress&&*gConfig->taunts[i-kInputTaunt1])
{
tChatMessage msg;
memset((void*)&msg,0,sizeof(tChatMessage));
snprintf(msg.str,256,"%s: \255#a\255%s",gConfig->playerName,gConfig->taunts[i-kInputTaunt1]);
msg.flags=0;
NetworkSendPacket(kMessageTypeChat,&msg,sizeof(tChatMessage),kMessagePriorityHigh,kMessageSendToAll);
}
}
gTauntPress=tauntPress;
if(gInputChatMode)
HandleChatModeInput();
}
void HandleGameInput()
{
tCarPhysics *phys=(tCarPhysics*)gCarEntities[gGameInfo->playerID]->physics;
if(GetButtonInput(kInputCamera))
{
if(!gCameraPress)
{
ParticlesClearScreen();
gCameraMode=(++gCameraMode)%(gConfig->allCams||gReplay||phys->lapCount>gGameInfo->numLaps&&gGameInfo->numLaps!=-1?kCameraNumModes:kCameraLeftWheel);
gReplayAutoCam=false;
}
gCameraPress++;
if(gCameraPress>=kFPS&&gCameraMode!=kCameraFree)
{
gCameraMode=kCameraFree;
TextPrintfToBufferFormatedFading(Vector(0,1),0.03,kTextAlignMiddle,1,2,"freecam mode.");
}
}
else gCameraPress=0;
if(GetButtonInput(kInputCameraChangeCar)){
if(!gReplayCameraPress)
{
if(gReplay||phys->lapCount>gGameInfo->numLaps)
{
do{
gReplayViewedEntityID=(gReplayViewedEntityID+1)%gGameInfo->numPlayers;
}while(gGameInfo->netID[gReplayViewedEntityID]==-1&&gGameInfo->network);
if(gReplay)
gReplayAutoCam=false;
gReplayCameraPress=true;
}
}
}else
gReplayCameraPress=false;
if(gReplay&&!gGameInfo->network)
{
float oldStretch=gTimeStretch;
if(GetButtonInput(kInputChat))
gTimeStretch=0.25;
else
gTimeStretch=1.0;
if(gTimeStretch!=oldStretch)
{
float curTime=gStartTime+(gFrameCount*kFrameTime)/oldStretch;
gStartTime=curTime-(gFrameCount*kFrameTime)/gTimeStretch;
}
}
gCameraReverse=GetButtonInput(kInputCameraReverse);
if(GetButtonInput(kInputPause)&&!gReplay&&!gPaused&&!gPausePress)
{
if(!gGameInfo->network)
PauseGame();
else
{
int pauseFrameCount=gFrameCount+kFPS*0.5;
S32Swap(pauseFrameCount);
NetworkSendPacket(kMessageTypePause,&pauseFrameCount,sizeof(int),kMessagePriorityHigh,kMessageSendToAll);
}
gPausePress=true;
}
if(((GetButtonInput(kInputPause)&&!gPausePress))&&gPaused&&!gInputChatMode)
{
if(!gGameInfo->network)
UnPauseGame();
else
NetworkSendPacket(kMessageTypeResume,NULL,0,kMessagePriorityHigh,kMessageSendToAll);
gPausePress=true;
}
if(!GetButtonInput(kInputPause))
gPausePress=false;
if(gGameInfo->network)
HandleNetworkInput();
/* if(GetInterfaceKey(kInterfaceKeyCmd)&&GetInterfaceKey(kInterfaceKeyQ))
{
gInputEscMode=kInputEscModeQuit;
gInputEscSelection=1;
if(!gGameInfo->network)
PauseGame();
}*/
if(GetInterfaceKey(kInterfaceKeyEsc))//||(GetInterfaceKey(kInterfaceKeyDelete)&&!gInputChatMode))
{
if(gInputChatMode)
{
gGameChatMessage[0]='\0';
gGameChatMessageSize=0;
gInputChatMode=false;
gEscPress=true;
}
else if(!gEscPress)
// if(!gGameInfo->network&&((phys->lapCount>gGameInfo->numLaps&&gGameInfo->numLaps!=-1)||(gFrameCount*kFrameTime-kStartGameDelaySeconds>gGameInfo->maxTime&&gGameInfo->maxTime>0)))
if((gReplay||((phys->lapCount>gGameInfo->numLaps&&gGameInfo->numLaps!=-1)))&&(!gGameInfo->network||gGameInfo->playerID==0))//||(gFrameCount*kFrameTime-kStartGameDelaySeconds>gGameInfo->maxTime&&gGameInfo->maxTime>0)))
gGameEnd=kEndGame;
else
{
gEscPress=true;
gInputEscMode=kInputEscModeNormal;
gInputEscSelection=1;
if(!gGameInfo->network)
PauseGame();
}
}
else
gEscPress=false;
}
void ControlFrame()
{
if(!gPaused&&!gReplay)
{
tGameEntity *entity=(tGameEntity*)gFirstEntity->next;
while(entity!=gFirstEntity)
{
if(entity->physicsMachine==kPhysicsLocal)
{
switch(entity->controlType)
{
case kControlTypeUserInput:
ControlEntityUserInput(entity);
break;
case kControlTypeAIInput:
ControlEntityAIInput(entity);
break;
}
}
entity=(tGameEntity*)entity->next;
}
}
if(!gInputEscMode)
HandleGameInput();
else
HandleEscModeInput();
}

100
source/controls.h Executable file
View File

@ -0,0 +1,100 @@
#ifndef __CONTROLS
#define __CONTROLS
#include "config.h"
#include "vectors.h"
enum{
kInputGasButton,
kInputBrakeButton,
kInputSteerLeftButton,
kInputSteerRightButton,
kInputHandbrakeButton,
kInputKickdownButton,
kInputGearUp,
kInputGearDown,
kInputLightButton,
kInputHorn,
kInputChat,
kInputCamera,
kInputPause,
kInputEscape,
kInputCameraReverse,
kInputTaunt1,
kInputTaunt2,
kInuptTaunt3,
kInputTaunt4,
kInputTaunt5,
kInputCameraChangeCar,
kInputITunesNext,
kInputITunesPrev,
kInputITunesPlay,
kInputLeftIndicator,
kInputRightIndicator,
kInputNumControls
};
enum{
kInterfaceKeyNone,
kInterfaceKeyUp,
kInterfaceKeyDown,
kInterfaceKeyLeft,
kInterfaceKeyRight,
kInterfaceKeySpace,
kInterfaceKeyReturn,
kInterfaceKeyEnter,
kInterfaceKeyEsc,
kInterfaceKeyEasterEgg,
kInterfaceKeyDelete,
kInterfaceKeyCmd,
kInterfaceKeyOpt,
kInterfaceKeyS,
kInterfaceKeyR,
kInterfaceKeyQ,
kInterfaceMouseDown,
kInterfaceNumKeys
};
enum{
kInputSteerAxis,
kInputThrottleBrakeAxis,
kInputThrottleAxis,
kInputBrakeAxis,
kInputNumAxis
};
enum{
kInputEscModeNone,
kInputEscModeNormal,
kInputEscModeQuit
};
extern int gFFB;
extern int gInputHID;
extern int gInputChatMode;
extern int gInputEscMode;
extern int gInputEscSelection;
extern float gStartPauseTime;
extern char gGameChatMessage[];
extern int gGameChatMessageSize;
void ControlFrame();
void ControlInit();
void ControlExit();
int GetButtonInput(int id);
int GetInterfaceKey(int id);
char GetKeyInput(int *key);
char PeekKeyInput(int *key);
float GetAxisInput(int id);
void GetInput(tKeyConfig *keyConfig);
void GetAxis(tAxisConfig *axis,bool allowVendor);
void FlushKeys();
void FFBJolt(float lMag,float rMag,float duration);
void FFBiShockDirect(float lMag,float rMag);
void FFBSetSteerResistance(float res,float alignment);
void FFBSetGoundRumble(float velo, float rumble);
void FFBStop();
void CalibrateAxis(int id);
tVector2 GetMousePos();
#endif

23
source/entities.cpp Executable file
View File

@ -0,0 +1,23 @@
#include "gamemem.h"
#include "entities.h"
tGameEntity *gFirstEntity=NULL,*gCameraEntity,*gViewedEntity;
int gEntityID=0;
void EntityResetCount()
{
gEntityID=0;
}
tGameEntity *EntityNew(tGameEntity *prev)
{
tGameEntity *entity=(tGameEntity*)MemoryAllocateZeroedBlock(sizeof(tGameEntity));
entity->next=prev->next;
entity->prev=prev;
((tGameEntity*)(prev->next))->prev=entity;
prev->next=entity;
MatrixIdentity(entity->dir);
MatrixIdentity(entity->rVelo);
entity->id=gEntityID++;
return entity;
}

117
source/entities.h Executable file
View File

@ -0,0 +1,117 @@
#ifndef __ENTITIES
#define __ENTITIES
#include "vectors.h"
#include "fileio.h"
enum{
kRenderTypeNone=0,
kRenderTypeModel,
kRenderTypeCar,
kRenderTypeGhost
};
enum{
kPhysicsTypeNone=0,
kPhysicsTypeCar,
kPhysicsTypeSolid,
kPhysicsTypeGhost
};
enum{
kPhysicsNone=0,
kPhysicsLocal,
kPhysicsRemote
};
enum{
kControlTypeNone=0,
kControlTypeUserInput,
kControlTypeAIInput
};
enum{
kPathTypeCircular=0,
kPathTypeSin
};
typedef struct{
tVector3 tfr,tfl,trl,trr,bfr,bfl,brl,brr;
} tCollBox;
enum{
kLightTypeDot=0,
kLightTypeSpot,
kLightTypeDotRefelective,
kLightTypeDirectionlessDot,
kLightTypeDirectionlessDotReflective,
kLightTypeSpecularDot
};
typedef struct{
tVector3 pos,dir,rgb;
float size,radius;
int type;
int onFlags;
int offFlags;
} tLightDefinition;
typedef struct{
int model;
int shadowModel;
float maxCollRadius;
int numCollBoxes;
int numColors;
int sparks;
int randomColor;
tCollBox *coll;
tVector3 massCenter;
int movable,followPath,pathType,liquid,particleStick;
tFileRef particle;
tFileRef sound;
int numSounds;
float particleAmount,particleSize;
float pathSize,pathVelo;
float mass,inertia;
int numLights;
tLightDefinition *lights;
} tSolidEntityPhysics;
#define kNumAvgRVelos 32
typedef struct{
void *next,*prev;
tVector3 pos,velo,oldPos,netVelo,collVelo,netPos,accel;
tMatrix3 dir,rVelo,oldDir,netDir,netRVelo;
tMatrix3 lastRVelos[kNumAvgRVelos];
tVector3 lastVelos[kNumAvgRVelos];
tVector3 lastAccel[kNumAvgRVelos];
tVector3 remoteCameraPos;
int renderType,renderData;
int physicsType,physicsData,physicsMachine;
int untouchable;
int controlType;
void *soundSource;
int id;
int lastFrame;
int lastRoadIndex;
int lastActivity;
int lastPacketSent;
tVector3 lastVeloSent;
tVector3 lastRZSent;
tVector3 lastDirZSent;
int lastPacketSaved;
tVector3 lastVeloSaved;
tVector3 lastRZSaved;
tVector3 lastDirZSaved;
float zDist;
void *physics;
void *regData;
} tGameEntity;
extern tGameEntity *gFirstEntity,*gCameraEntity,*gViewedEntity;
void EntityResetCount();
tGameEntity *EntityNew(tGameEntity *prev);
#endif

28
source/environment.cpp Normal file
View File

@ -0,0 +1,28 @@
//environment.cpp
//load a new environment fiel from disk
//environments basically control the wheather and
//what background images to use and stuff like that
#include "fileio.h"
#include "environment.h"
#include "gamemem.h"
#include "parser.h"
#include "roads.h"
#include "textures.h"
#include "gameinitexit.h"
tEnvironment *gEnvironment;
#define kAirDensity 1.2929 //kg*m^-3
#define kGravitionalAcceleration 9.80665 //m*s^-2
void LoadEnvironment(int ref)
{
gEnvironment=(tEnvironment*)FileGetParsedDataPtr(ref,kParserTypeEnvironmentDesc,sizeof(tEnvironment));
gSurfaceTypes=(tSurfaceTypeList*)FileGetParsedDataPtr(gEnvironment->surfaceTypes,kParserTypeSurfaceTypeDesc,sizeof(tSurfaceTypeList));
if(gEnvironment->gravity==0)
gEnvironment->gravity=kGravitionalAcceleration;
if(gEnvironment->airDensity==0)
gEnvironment->airDensity=kAirDensity;
if(gEnvironment->hasAltEnv&&gMapInfo->useAltEnv)
LoadEnvironment(gEnvironment->altEnv);
}

36
source/environment.h Normal file
View File

@ -0,0 +1,36 @@
//environment.h
#ifndef __ENVIRONMENT
#define __ENVIRONMENT
#include "vectors.h"
#include "fileio.h"
enum{
kEnvironmentMappingOff,
kEnvironmentMappingSphereAddSigned,
kEnvironmentMappingSphereInterpolate
};
typedef struct{
tFileRef sky0,sky90,sky180,sky270,skytop,skybot,particlesType,surfaceTypes;
tFileRef spheremap,dirtMap;
tFileRef soundLoop,soundRandom;
tVector3 fogColor,ambient,diffuse,specular,shadowColor,spotLightColor,instrumentColor,flashColor;
tVector3 lightDir,particlesVelo,flareDir;
tVector2 particlesSize;
float particlesHeight;
float shadowIntensity,particlesAmount,particlesVeloSpread,particlesLife,flashIntensity,soundRandomProbility,environmentMapIntensity,dirtIntensity;
float gravity,airDensity;
int shadowEnable,spotLightEnable,particlesEnable,screenParticlesEnable,soundLoopEnable,soundRandomEnable,flaresEnable,dirtEnable;
int environmentMapping;
int envFlags;
char name[80];
int hasAltEnv;
tFileRef altEnv;
} tEnvironment;
extern tEnvironment *gEnvironment;
void LoadEnvironment(int ref);
#endif

1
source/error.h Normal file
View File

@ -0,0 +1 @@
#ifndef __ERROR #define __ERROR void FailWithErrorString(char *string); void PrintConsoleString(const char *fmt, ...); void ShowAlert(char *str1, char *str2); void HandleError(int code); #endif

358
source/fileio.cpp Executable file
View File

@ -0,0 +1,358 @@
//fileio.h
//Utilities for reading and writing to files in the game's subdirectories
//fileio works by creating a table of all files within the applications directory
//at startup. this way all files we need can be addressed simply using reference numbers.
//sometimes also refered to as "ID numbers".
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "fileio.h"
#include "platform.h"
#include "gamemem.h"
#include "error.h"
#include "parser.h"
int gFileTableSize; //size of the file reference table
int gFileTableExtendedSize;
int gFileTampered=false;
tFileTableEntry *gFileTable; //the file reference table
char gNoName[]="";
void FileInitFileTable(tFileTableEntry *fileTable,int maxSize,int *fileTableSize,int reInit);
#define kNumValidateFiles 42
char gValidateNames[][256]={
"500gt.car",
"500gthotrod.car",
"959.car",
"maserati.car",
"bmw2002.car",
"charger.car",
"chargerdragdrag.car",
"corvette.car",
"diablo.car",
"dmc12.car",
"dmc12flying.car",
"gt40.car",
"gti.car",
"mini.car",
"55ford.car",
"tt.car",
"ttpimp.car",
"viper.car",
"viperracer.car",
"accelbrake.mapinfo",
"accelbrake2.mapinfo",
"canyon.mapinfo",
"canyoncorner.mapinfo",
"city2.mapinfo",
"citycorner.mapinfo",
"downhill.mapinfo",
"highspeed.mapinfo",
"highspeedtrial.mapinfo",
"mountainside.mapinfo",
"offroad.mapinfo",
"quarter.mapinfo",
"ralley2.mapinfo",
"scorner.mapinfo",
"slalom.mapinfo",
"slalom2.mapinfo",
"snow.mapinfo",
"snowtrial.mapinfo",
"tight.mapinfo",
"canyon.road",
"city2.road",
"mountainside.road",
"ralley2.road",
"snow.road",
};
int gValidateChecksums[]={
0xc98d7f36,
0x833e4a7d,
0xdcd7e89,
0x3e6a08b7,
0x251efab,
0xed2a6577,
0x6d654b5,
0x1c468570,
0x1380a984,
0x7c69956,
0xcc2746e4,
0x22349629,
0x8d0d50b4,
0x51994161,
0x90a4cc85,
0x931cbd6c,
0xe42301b9,
0xcc9bd572,
0x1b7951e7,
0x72d87975,
0x1eb05d11,
0xa2182ab9,
0xde1122e6,
0xc44b1aab,
0x815cb099,
0x8eb6b530,
0x6c93ce2,
0x77263bb7,
0x18ebbbad,
0xc57f8785,
0x117ba80c,
0xb513b806,
0x75938236,
0x2437d140,
0xb249c233,
0x6e92dc33,
0x9e5c31de,
0x8766b155,
0x1bbdc55d,
0x28f6a9b8,
0x66e5492e,
0x8b5a55d8,
};
//Initialize file reference table
void FileInitIO()
{
gFileTableExtendedSize=0;
gFileTableSize=0;
gFileTable=(tFileTableEntry*)calloc(kMaxFiles,sizeof(tFileTableEntry));
FileInitFileTable(gFileTable,kMaxFiles,&gFileTableSize,false);
for(int i=0;i<kNumValidateFiles;i++)
{
if(FileGetChecksum(FileGetReference(gValidateNames[i]))!=gValidateChecksums[i])
{
gFileTampered=true;
printf("Bad File! %s. Found Checksum %x. Need Checksum %x.\n",FileGetName(FileGetReference(gValidateNames[i])),
FileGetChecksum(FileGetReference(gValidateNames[i])),gValidateChecksums[i]);
}
//printf("0x%x,\n",FileGetChecksum(FileGetReference(gValidateNames[i])));
}
}
void FileRescanDirectory()
{
int totalSize=gFileTableSize+gFileTableExtendedSize;
FileInitFileTable(gFileTable,kMaxFiles,&totalSize,true);
gFileTableExtendedSize=totalSize-gFileTableSize;
printf("ex:%d\n",gFileTableExtendedSize);
}
void FileReleaseData(tFileRef reference)
{
if(gFileTable[reference].loaded)
{
MemoryFreeBlock(gFileTable[reference].data);
gFileTable[reference].loaded=false;
}
}
//Compare two File Table entries for sorting and searching
int FileTableCompare(const void *a,const void *b)
{
return _stricmp(((tFileTableEntry*)a)->name,((tFileTableEntry*)b)->name);
}
int gFileErrorReporting=true;
//Search file reference table for a file matching a name and return its reference number
tFileRef FileGetReference(char *name)
{
if(*name=='\0')
return -1;
//the key to search for
tFileTableEntry key;
#ifndef __TARGET_TEXTURECOMPRESSOR
#ifndef __TARGET_TOOLAPP
snprintf(key.name,32,"%s.txr",name);
//search for an entry matching our search key
tFileTableEntry *result=(tFileTableEntry*)bsearch(&key,gFileTable,gFileTableSize,sizeof(tFileTableEntry),&FileTableCompare);
//return results
if(result)
return result-gFileTable;
else
{
snprintf(key.name,32,"%s.ima",name);
//search for an entry matching our search key
tFileTableEntry *result=(tFileTableEntry*)bsearch(&key,gFileTable,gFileTableSize,sizeof(tFileTableEntry),&FileTableCompare);
//return results
if(result)
return result-gFileTable;
else
{
#endif
#endif
strcpy(key.name,name);
tFileTableEntry *result=(tFileTableEntry*)bsearch(&key,gFileTable,gFileTableSize,sizeof(tFileTableEntry),&FileTableCompare);
if(result)
return result-gFileTable;
else
{
for(int i=gFileTableSize;i<gFileTableSize+gFileTableExtendedSize;i++)
if(_stricmp(gFileTable[i].name,name)==0)
return i;
if(gFileErrorReporting)
{
//or give an error message
PrintConsoleString("File not found!: %s\n",name);
}
return -1;
}
#ifndef __TARGET_TEXTURECOMPRESSOR
#ifndef __TARGET_TOOLAPP
}
}
#endif
#endif
}
tFileRef FileGetIndexedReference(tFileRef base,int i)
{
if(i>0)
{
char nameCopy[kMaxFileNameLength];
strcpy(nameCopy,FileGetName(base));
char *found=strchr(nameCopy,'.');
char indexedName[kMaxFileNameLength];
if(found)
{
*found='\0';
sprintf(indexedName,"%s#%x.%s",nameCopy,i,found+1);
}
else
sprintf(indexedName,"%s#%x",nameCopy,i);
int seek=base-1;
while(_stricmp(gFileTable[seek].name,indexedName)>0&&seek>0)
seek--;
if(_stricmp(gFileTable[seek].name,indexedName))
return base;
else
return seek;
}
else
return base;
}
tFileRef FileGetBaseReference(tFileRef ref)
{
if(ref<0||ref>=gFileTableExtendedSize+gFileTableSize)
return kFileErr;
char *found=strchr(FileGetName(ref),'.');
if(!found)
return ref;
char *cross=found;
while(*cross!='#'&&cross>FileGetName(ref))
cross--;
if(*cross!='#')
return ref;
int l=cross-FileGetName(ref);
char nameCopy[kMaxFileNameLength];
memcpy(nameCopy,FileGetName(ref),l);
strcpy(nameCopy+l,found);
tFileRef base=FileGetReference(nameCopy);
return base!=kFileErr?base:ref;
}
//platform specific, can be found in macfileio.cpp
int FileLoadData(tFileRef fileRef);
void FileStoreData(tFileRef fileRef);
//return the extension of a file given it's reference number
char *FileGetExtension(tFileRef reference)
{
if(reference<0||reference>=gFileTableExtendedSize+gFileTableSize)
return NULL;
char *found=NULL;
char *dot=gFileTable[reference].name;
do{
dot=strchr(dot,'.');
if(dot){
found=dot;
dot++;
}
}while(dot);
if(found)
return found;
else
return gFileTable[reference].name+strlen(gFileTable[reference].name);//'\0';
}
//return the name of a file given it's reference number
char *FileGetName(tFileRef reference)
{
if(reference<0||reference>=gFileTableExtendedSize+gFileTableSize)
return gNoName;
return gFileTable[reference].name;
}
//return the size of a file given it's reference number
int FileGetSize(tFileRef reference)
{
if(reference<0||reference>=gFileTableExtendedSize+gFileTableSize)
return 0;
if(!gFileTable[reference].loaded)
gFileTable[reference].loaded=FileLoadData(reference);
return gFileTable[reference].size;
}
//return a pointer to the file's data (and load the file if necessary)
void *FileGetDataPtr(tFileRef reference)
{
if(reference<0||reference>=gFileTableExtendedSize+gFileTableSize)
return NULL;
if(!gFileTable[reference].loaded)
gFileTable[reference].loaded=FileLoadData(reference);
return gFileTable[reference].loaded?gFileTable[reference].data:(void*)0;
}
unsigned int FileGetChecksum(tFileRef reference)
{
if(reference<0||reference>=gFileTableExtendedSize+gFileTableSize)
return 0;
return MemoryChecksum(FileGetDataPtr(reference),FileGetSize(reference));
}
//Changes a file's contents to data, and writes the file to disk.
void FileSetData(tFileRef reference,void *data)
{
if(reference<0||reference>=gFileTableExtendedSize+gFileTableSize)
return;
if(gFileTable[reference].loaded&&data!=gFileTable[reference].data)
MemoryFreeBlock(gFileTable[reference].data);
gFileTable[reference].data=data;
gFileTable[reference].loaded=true;
gFileTable[reference].size=MemoryBlockSize(data);
FileStoreData(reference);
}
//parses a file's data using a file format parser
//and return a pointer to parsed data structure
void* FileGetParsedDataPtr(tFileRef reference, int parserType, int dataSize)
{
if(reference<0||reference>=gFileTableExtendedSize+gFileTableSize)
return NULL;
if(!gFileTable[reference].parsed)
{
gFileTable[reference].parsedData=MemoryAllocateZeroedBlock(dataSize);
ParseFile(reference,gFileTable[reference].parsedData,parserType);
gFileTable[reference].parsed=true;
}
return gFileTable[reference].parsedData;
}

78
source/fileio.h Executable file
View File

@ -0,0 +1,78 @@
#ifndef __FILEIO
#define __FILEIO
#define kFileErr -1
#define kMaxFiles 32768
#define kMaxFileNameLength 32
typedef char tOpaqueFileSystemLocator[272]; //size of this is platform specific
typedef int tFileRef;
typedef struct{
int loaded;
int parsed;
int tagged;
int size;
void *data;
void *parsedData;
tOpaqueFileSystemLocator fsLoc;
char name[kMaxFileNameLength];
} tFileTableEntry;
#define kFileTypeRAW ".raw"
#define kFileTypeRAW3d ".raw3d"
#define kFileTypeGrayscaleRAW ".graw"
#define kFileTypeSGI ".sgi"
#define kFileTypeWaveFront ".obj"
#define kFileTypeWAV ".wav"
#define kFileTypeModel ".mdl"
#define kFileTypeSolidEntity ".ent"
#define kFileTypeCarDefinition ".car"
#define kFileTypeMapDefinition ".mapinfo"
#define kFileTypeEnvironmentDefinition ".env"
#define kFileTypePackageFile ".redplug"
#define kFileTypeImageURL ".url"
#define kFileTypeCompressedTexture ".txr"
#define kFileTypeLog ".redlog"
extern int gFileTableSize;
extern int gFileTampered;
extern tFileTableEntry *gFileTable;
static inline int _stricmp(const char *s1, const char *s2)
{
char c1, c2;
while (1)
{
c1 = *s1++;
c2 = *s2++;
if(c1>='A'&&c1<='Z')c1+=0x20;
if(c2>='A'&&c2<='Z')c2+=0x20;
if (c1 < c2) return -1;
if (c1 > c2) return 1;
if (c1 == 0) return 0;
}
}
#include "parser.h"
extern int gFileErrorReporting;
tFileRef FileGetReference(char *name);
tFileRef FileGetIndexedReference(tFileRef base,int i);
tFileRef FileGetBaseReference(tFileRef ref);
void FileAppendData(tFileRef fileRef,void *data,int size);
void *FileGetPartialDataPtr(tFileRef fileRef,int offset,int size);
void *FileGetDataPtr(tFileRef reference);
void FileSetData(tFileRef reference,void *data);
void FileReleaseData(int reference);
void FileInitIO();
void FileRescanDirectory();
char *FileGetExtension(tFileRef reference);
char *FileGetName(tFileRef reference);
int FileGetSize(tFileRef reference);
void* FileGetParsedDataPtr(tFileRef reference, int parserType, int dataSize);
unsigned int FileGetChecksum(tFileRef reference);
#endif

33
source/fpu_exc.c Normal file
View File

@ -0,0 +1,33 @@
#ifdef __ppc__
#include <architecture/ppc/fp_regs.h>
#include <fenv.h>
#ifndef SIG_HOLD
#define SIG_HOLD (void (*)(int))5
#endif
void EnableFPUExceptions()
{
long resp;
if(Gestalt(gestaltSystemVersion,&resp)!=noErr)
return;
if(resp<0x00001040)
return;
ppc_fp_scr_t fpscr=get_fp_scr();
fpscr.ze=1;
fpscr.ni=1;
/* fpscr.oe=1;
fpscr.ue=1;
fpscr.ve=1;*/
set_fp_scr(fpscr);
feclearexcept(FE_ALL_EXCEPT);
signal(SIGFPE,SIG_HOLD);
printf("FPU Exceptions enabled.\n");
}
#else
void EnableFPUExceptions()
{
}
#endif

4
source/fpu_exc.h Normal file
View File

@ -0,0 +1,4 @@
extern "C"
{
void EnableFPUExceptions();
}

846
source/gameframe.cpp Executable file
View File

@ -0,0 +1,846 @@
//gameframe.cpp
//Calculate a single physics frame
#include <stdio.h>
#include <math.h>
#include "gametime.h"
#include "entities.h"
#include "carphysics.h"
#include "gameframe.h"
#include "controls.h"
#include "gamemem.h"
#include "particles.h"
#include "renderframe.h"
#include "collision.h"
#include "networkphysics.h"
#include "gamesound.h"
#include "gameinitexit.h"
#include "config.h"
#include "parser.h"
#include "roads.h"
#include "gamesystem.h"
#include "interfaceutil.h"
#include "text.h"
#include "random.h"
#include "log.h"
#include "sky.h"
#include "tracker.h"
#include "environment.h"
#define kGraphFrameTimeCount 10 //number of frames used to calculate average FPS
int gFrameCount; //number of physics frames calculated
int gGraphFrameCount; //number of graphical frames actually drawn
int gPaused=false;
int gNetPauseTime=0;
int gDisabledRestart=0;
float gStartPauseTime;
float gStartTime; //time at the start of the game (in seconds)
float gTimeStretch=1.0;
//Used for Time Trial
int gCurrentLapStart;
int gBestLapStart;
int gLastLapTime;
int gBestLapTime=0;
int gWorldRecord=0,gLocalRecord=0;
char gRecordName[255];
float gAccelSignDisplayIntensity,gAccelSignDisplayCorner;
//the times when the last graphics frames have been draw
float gLastGraphFrameTime[kGraphFrameTimeCount];
int gGameEnd; //flag to signal end of game
int gDisqualified;
int gRaceFinished; //flag to signal that at least one player has finished all laps.
float gFPS;
//Calculate physics for a solid entity
//(basically any object in the game which is not a car)
void SolidPhysicsEntity(tGameEntity *entity)
{
//get soldid entity definition
tSolidEntityPhysics *ent=(tSolidEntityPhysics*)FileGetParsedDataPtr(entity->physicsData,kParserTypeSolidEntityDesc,sizeof(tSolidEntityPhysics));
//is this entity freely movable?
if(ent->movable)
//gravitational acceleration
entity->velo.y-=gEnvironment->gravity*kFrameTime;
float dampfactor=0;
float v=~entity->velo;
if(v<7)dampfactor=(7-v)/7;
*MatrixGetXVector(entity->rVelo)=Vector(1,0,0)+(1-dampfactor*kFrameTime)*(*MatrixGetXVector(entity->rVelo)-Vector(1,0,0));
*MatrixGetYVector(entity->rVelo)=Vector(0,1,0)+(1-dampfactor*kFrameTime)*(*MatrixGetYVector(entity->rVelo)-Vector(0,1,0));
*MatrixGetZVector(entity->rVelo)=Vector(0,0,1)+(1-dampfactor*kFrameTime)*(*MatrixGetZVector(entity->rVelo)-Vector(0,0,1));
entity->velo=(1-dampfactor*kFrameTime)*entity->velo;
MatrixReAdjust(entity->rVelo);
//does this entity follow a constant path?
if(ent->followPath)
if(ent->pathType==kPathTypeCircular)
{
MatrixRotY(entity->dir,ent->pathVelo*kFrameTime);
entity->velo=*MatrixGetZVector(entity->dir)*ent->pathVelo*ent->pathSize;
}
else
{
entity->velo=Vector(
3*sin(gFrameCount*kFrameTime*ent->pathVelo*0.2+1)*ent->pathVelo*0.2,
ent->pathSize*sin(gFrameCount*kFrameTime*ent->pathVelo)*ent->pathVelo,
2*sin(gFrameCount*kFrameTime*ent->pathVelo*0.3-2)*ent->pathVelo*0.3
);
entity->lastActivity=gFrameCount;
}
}
//Calculate one physics frame for all game entities
void PhysicsFrame()
{
//do this for every entity in the game
tGameEntity *entity=(tGameEntity*)gFirstEntity->next;
while(entity!=gFirstEntity)
{
if(entity->id>=0)
{
//is this entity handled by this machine?
if(entity->physicsMachine==kPhysicsLocal)
{
//this check is used to prevent entitys which are just standing still
//from eating up CPU cycles
if(entity->lastActivity+kFPS>gFrameCount)
{
//handle entity physics
switch(entity->physicsType)
{
case kPhysicsTypeCar:
CarPhysicsEntity(entity);
break;
case kPhysicsTypeSolid:
SolidPhysicsEntity(entity);
break;
}
//Matrices tend to 'drift' apart du to inaccurate
//floating-point operations. these routines test matrices
//and re-adjust them if necessary.
if(!MatrixVerify(entity->dir))
MatrixReAdjust(entity->dir);
if(!MatrixVerify(entity->rVelo))
MatrixReAdjust(entity->rVelo);
}
}
else if(entity->physicsType==kPhysicsTypeCar)
CarPhysicsEntity(entity);
}
//proceed to next entity.
entity=(tGameEntity*)entity->next;
}
}
//Move around all the entities.
void MotionFrame()
{
//do this for every entity in the game
tGameEntity *entity=(tGameEntity*)gFirstEntity->next;
while(entity!=gFirstEntity)
{
entity->oldPos=entity->pos;
MatrixCopy(entity->dir,entity->oldDir);
//this check is used to prevent entitys which are just standing still
//from eating up CPU cycles
if(entity->lastActivity+kFPS>gFrameCount)
{
//move entity
switch(entity->physicsType)
{
case kPhysicsTypeCar:
case kPhysicsTypeGhost:
CarMotionEntity(entity);
break;
case kPhysicsTypeSolid:
entity->pos=entity->pos+entity->velo*kFrameTime;
MatrixMult(entity->dir,entity->rVelo,entity->dir);
break;
}
}
//Check if the entity is moving, and update lastActivity
if(entity->velo*entity->velo>kMinActivityVelo*kMinActivityVelo)
entity->lastActivity=gFrameCount;
//proceed to next entity.
entity=(tGameEntity*)entity->next;
}
}
//checks whether there is time to draw a graphics frame
//and calculates frame rate
int CheckFrameTime()
{
int optFrameCount;
int retval=false;
float curTime;
//get current time
curTime=(TimeGetSeconds()-gStartTime)*gTimeStretch;
//calculate number of frames we should have calculated in that time
optFrameCount=curTime*kFPS;
//if we have calculated more frames than required, we have
//time to draw a screen update.
if(gFrameCount>optFrameCount)
{
//calculate frame rate.
if(curTime-gLastGraphFrameTime[0]>0)
gFPS=((float)kGraphFrameTimeCount)/(curTime-gLastGraphFrameTime[0]);
else
gFPS=0;
MemoryMove(gLastGraphFrameTime,gLastGraphFrameTime+1,sizeof(float)*(kGraphFrameTimeCount-1));
gLastGraphFrameTime[kGraphFrameTimeCount-1]=curTime;
gGraphFrameCount++;
retval=true;
}
if(gFPS<10)
gConfig->gfxDynamics-=kFrameTime;
else if(gFPS<15)
gConfig->gfxDynamics-=kFrameTime*0.3;
if(gFPS>35)
gConfig->gfxDynamics+=kFrameTime;
else if(gFPS>25)
gConfig->gfxDynamics+=kFrameTime*0.3;
if(gConfig->gfxDynamics<0.0)gConfig->gfxDynamics=0;
if(gConfig->gfxDynamics>1.0)gConfig->gfxDynamics=1;
return retval;
}
//after drawing a graphics frame, check whether there is still time
//left. in that case wait, so we aren't running too fast.
void CheckTimeSkip()
{
int optFrameCount;
float curTime;
curTime=(TimeGetSeconds()-gStartTime)*gTimeStretch;
optFrameCount=curTime*kFPS;
while(gFrameCount>optFrameCount+1)
{
curTime=(TimeGetSeconds()-gStartTime)*gTimeStretch;
optFrameCount=curTime*kFPS;
}
}
//start the frame counters
void StartFrameCount()
{
gStartTime=TimeGetSeconds();
gFrameCount=0;
gGraphFrameCount=0;
gCurrentLapStart=0;
gBestLapStart=0;
gLastLapTime=0;
gBestLapTime=0;
gWorldRecord=-1;
if(gGameInfo->numLaps==-1||gGameInfo->maxTime!=0)
TrackerFetchRecord(gGameInfo->map,gGameInfo->playerCars[0],gGameInfo->arcade,gGameInfo->reverse^gMapInfo->reverse);
}
void PauseGame()
{
if(!gPaused)
{
gPaused=true;
gStartPauseTime=TimeGetSeconds();
SoundPause();
FFBStop();
}
}
void UnPauseGame()
{
if(gPaused)
{
gPaused=false;
gStartTime+=TimeGetSeconds()-gStartPauseTime;
SoundReInit();
}
}
void ResetRocks()
{
int id=0;
for(int i=0;i<gMapInfo->numObjs;i++)
{
if(gMapInfo->obj[i].envFlags==0||(gMapInfo->obj[i].envFlags&gEnvironment->envFlags))
{
char *extension=FileGetExtension(gMapInfo->obj[i].model);
if(extension)
if(!_stricmp(extension,kFileTypeSolidEntity))
{
tGameEntity *entity=(tGameEntity*)gFirstEntity->next;
//see if we find the entity it belongs to
while(entity!=gFirstEntity)
{
//is this the entity the message refers to?
if(entity->id==id)
{
entity->pos=gMapInfo->obj[i].pos;
EulerAnglesToMatrix(gMapInfo->obj[i].dir*kDegreeRadians,entity->dir);
entity->velo=Vector(0,0,0);
MatrixIdentity(entity->rVelo);
entity->lastActivity=-1000;
}
entity=(tGameEntity*)entity->next;
}
}
id++;
}
}
}
//tests if entity has passed the next check-point
//(check-points are invisible, and only used to calculate
//lead and trail delays).
void CheckPointPass(tGameEntity *entity)
{
tCarPhysics *phys=(tCarPhysics*)entity->physics;
if(phys->lap==-1)
return;
if(gGameInfo->numLaps!=-1)
{
if(!gCheckPoints[phys->checkPoint].passTimes[phys->lap].setBy)
{
gCheckPoints[phys->checkPoint].passTimes[phys->lap].time=gFrameCount*kFrameTime;
gCheckPoints[phys->checkPoint].passTimes[phys->lap].setBy=entity;
}
else
{
phys->lead=gCheckPoints[phys->checkPoint].passTimes[phys->lap].time-gFrameCount*kFrameTime;
if(!gCheckPoints[phys->checkPoint].passTimes[phys->lap].hit)
{
tCarPhysics *phys2=(tCarPhysics*)gCheckPoints[phys->checkPoint].passTimes[phys->lap].setBy->physics;
phys2->lead=gFrameCount*kFrameTime-gCheckPoints[phys->checkPoint].passTimes[phys->lap].time;
gCheckPoints[phys->checkPoint].passTimes[phys->lap].hit=true;
}
}
}
else
{
gCheckPoints[phys->checkPoint].passTimes[0].time=(gFrameCount-gCurrentLapStart)*kFrameTime;
if(phys->lapCount>1)
phys->lead=gCheckPoints[phys->checkPoint].passTimes[1].time-gCheckPoints[phys->checkPoint].passTimes[0].time;
}
if(phys->checkPoint==0||(!gMapInfo->loop&&phys->checkPoint==kNumCheckPoints-1))
{
if(!gReplay&&entity==gViewedEntity)
if(phys->lapCount&&(phys->lapCount<gGameInfo->numLaps||gGameInfo->numLaps==-1))
{
float lastLapTime;
if(gGameInfo->numLaps!=-1)
lastLapTime=gFrameCount-phys->lapTimes[phys->lapCount-1];
else
lastLapTime=gFrameCount-gCurrentLapStart;
lastLapTime*=kFrameTime;
TextPrintfToBufferFormatedFading(Vector(0,0.4),0.04,kTextAlignMiddle,0.6,1.2,"Time Taken: %d:%02d'%02d",((int)lastLapTime)/60,((int)lastLapTime)%60,((int)(lastLapTime*100))%100);
}
if(gGameInfo->numLaps!=-1)
phys->lapTimes[phys->lapCount]=gFrameCount;
else if(!gReplay){
if(phys->lapCount>=1)
{
gLastLapTime=gFrameCount-gCurrentLapStart;
if(!gDisqualified)
{
TrackerRegisterLapTime(gGameInfo->map,gGameInfo->playerCars[0],gLastLapTime,gGameInfo->arcade,gGameInfo->reverse^gMapInfo->reverse);
if((gLastLapTime<gBestLapTime||gBestLapTime==0))
{
gBestLapTime=gLastLapTime;
gBestLapStart=gCurrentLapStart;
if(gBestLapTime<gLocalRecord||gLocalRecord==0)
{
gLocalRecord=gBestLapTime;
int found=false;
for(int i=0;i<gConfig->numPersonalRecords;i++)
if(gConfig->records[i].map==gGameInfo->map&&gConfig->records[i].car==gGameInfo->playerCars[0]
&&gConfig->records[i].mode==gGameInfo->arcade&&gConfig->records[i].direction==gGameInfo->reverse)
{
found=true;
if(gConfig->records[i].time>gLocalRecord)
gConfig->records[i].time=gLocalRecord;
}
if(!found&&gConfig->numPersonalRecords<kMaxPersonalRecords)
{
gConfig->records[gConfig->numPersonalRecords].time=gLocalRecord;
gConfig->records[gConfig->numPersonalRecords].car=gGameInfo->playerCars[0];
gConfig->records[gConfig->numPersonalRecords].map=gGameInfo->map;
gConfig->records[gConfig->numPersonalRecords].mode=gGameInfo->arcade;
gConfig->records[gConfig->numPersonalRecords].direction=gGameInfo->reverse;
gConfig->numPersonalRecords++;
}
}
LogToGhostLog();
for(int i=0;i<kNumCheckPoints;i++)
gCheckPoints[i].passTimes[1].time=gCheckPoints[i].passTimes[0].time;
}
}
}
LogReset();
gReplayIndex=0;
gCurrentLapStart=gFrameCount;
}
if(!gReplay&&gGameInfo->maxTime!=0&&!gDisqualified)
if(phys->lapCount>=1)
TrackerRegisterLapTime(gGameInfo->map,gGameInfo->playerCars[0],phys->lapTimes[phys->lapCount]-kStartGameDelaySeconds*kFPS,gGameInfo->arcade,gGameInfo->reverse^gMapInfo->reverse);
phys->lapCount++;
if(!gReplay&&entity==gViewedEntity&&gMapInfo->loop)
if(phys->lapCount<gGameInfo->numLaps||gGameInfo->numLaps==-1)
TextPrintfToBufferFormatedFading(Vector(kFadingMessageXPos,kFadingMessageYPos),kFadingMessageSize,kTextAlignMiddle,0.9,1.8,"Lap %d",phys->lapCount);
else if(phys->lapCount==gGameInfo->numLaps)
TextPrintfToBufferFormatedFading(Vector(kFadingMessageXPos,kFadingMessageYPos),kFadingMessageSize,kTextAlignMiddle,0.9,1.8,"Final Lap");
if(gGameInfo->numLaps==-1)
ResetRocks();
if(phys->lapCount>gGameInfo->numLaps&&gGameInfo->numLaps!=-1)
{
if(!phys->finishTime)
phys->finishTime=phys->lapTimes[gGameInfo->numLaps];
if(gGameInfo->network)
if(gGameInfo->playerID==0)
for(int i=0;i<gGameInfo->numPlayers;i++)
if(gCarEntities[i]==entity)
{
tFinishTimeMessage m;
m.time=phys->finishTime;
m.player=i;
S32Swap(m.time);
S32Swap(m.player);
NetworkSendPacket(kMessageTypeFinishTime,&m,sizeof(tFinishTimeMessage),kMessagePriorityHigh,kMessageSendToAllButSelf);
}
if(!gRaceFinished)
{
gRaceFinished=true;
if(entity!=gViewedEntity&&!gReplay)
if(gGameInfo->network)
{
for(int i=0;i<gGameInfo->numPlayers;i++)
if(gCarEntities[i]==entity)
TextPrintfToBufferFormatedFading(Vector(0,1),0.06,kTextAlignMiddle,2,3,"%s won the race!",gGameInfo->playerNames[i]);
}
else
TextPrintfToBufferFormatedFading(Vector(0,1),0.06,kTextAlignMiddle,2,3,"%s won the race!",phys->car.carName);
}
}
}
phys->checkPoint=(phys->checkPoint+1)%kNumCheckPoints;
}
void LapCheck()
{
if(gGameInfo->demolition)
{
if(gFrameCount>=gDisabledRestart+kFPS*10&&gDisabledRestart)
{
tCarPhysics *phys=(tCarPhysics*)gCarEntities[gGameInfo->playerID]->physics;
phys->damage=0;
RoadCenterCar(gCarEntities[gGameInfo->playerID]);
gDisabledRestart=0;
}
int numDisabled=0;
for(int i=0;i<gGameInfo->numPlayers;i++)
{
if(gCarEntities[i]->id>=0)
{
tCarPhysics *phys=(tCarPhysics*)gCarEntities[i]->physics;
if(phys->damage>=kFatalDamage)
numDisabled++;
}
}
if(numDisabled>0&&numDisabled>=gGameInfo->numPlayers-1)
if(!gDisabledRestart)
gDisabledRestart=gFrameCount;
}
else
{
if(gFrameCount*kFrameTime>=3)
for(int i=0;i<gGameInfo->numPlayers;i++)
{
tCarPhysics *phys=(tCarPhysics*)gCarEntities[i]->physics;
if(!(gMapInfo->needsToStop&&(sqr(gCarEntities[i]->velo)>0.5)&&(phys->checkPoint==kNumCheckPoints-1)))
{
if(phys->lap<=gGameInfo->numLaps||(phys->checkPoint==0&&phys->lap==gGameInfo->numLaps+1)||gGameInfo->numLaps==-1)
{
//this doesn't all make sense but works for now.
if(gGameInfo->reverse){
if(gCheckPoints[(phys->checkPoint+1)%kNumCheckPoints].index>gCheckPoints[phys->checkPoint].index){
if(phys->position<gCheckPoints[phys->checkPoint].index||(phys->position>gCheckPoints[(phys->checkPoint+1)%kNumCheckPoints].index&&gMapInfo->loop))
CheckPointPass(gCarEntities[i]);
}else if(phys->position<gCheckPoints[phys->checkPoint].index&&phys->position>gCheckPoints[(phys->checkPoint+1)%kNumCheckPoints].index)
CheckPointPass(gCarEntities[i]);
}
else{
if(gCheckPoints[(phys->checkPoint+10)%kNumCheckPoints].index<gCheckPoints[phys->checkPoint].index){
if(phys->position>gCheckPoints[phys->checkPoint].index)
CheckPointPass(gCarEntities[i]);
}else if(phys->position>gCheckPoints[phys->checkPoint].index&&phys->position<gCheckPoints[(phys->checkPoint+10)%kNumCheckPoints].index)
CheckPointPass(gCarEntities[i]);
}
}
}
for(int j=0;j<gGameInfo->numPlayers;j++)
{
tCarPhysics *jPhys=(tCarPhysics*)gCarEntities[j]->physics;
if(((gGameInfo->reverse&&phys->position<jPhys->position)||(!gGameInfo->reverse&&phys->position>jPhys->position))&&phys->lap>jPhys->lap+phys->lappedPlayers[j])
{
phys->lappedPlayers[j]++;
if(gCarEntities[i]==gViewedEntity&&!gReplay&&gGameInfo->netID[j]!=-1&&gCarEntities[j]->id!=-1)
TextPrintfToBufferFormatedFading(Vector(kFadingMessageXPos,kFadingMessageYPos),kFadingMessageSize,kTextAlignMiddle,2.0,3.0,"You lapped %s!!",gGameInfo->network?gGameInfo->playerNames[j]:jPhys->car.carName);
else if(gCarEntities[j]==gViewedEntity&&!gReplay)
TextPrintfToBufferFormatedFading(Vector(kFadingMessageXPos,kFadingMessageYPos),kFadingMessageSize,kTextAlignMiddle,2.0,3.0,"You were lapped by %s!!",gGameInfo->network?gGameInfo->playerNames[i]:phys->car.carName);
}
}
}
if(gGameInfo->numLaps==-1||gGameInfo->maxTime!=0)
TrackerWaitForLapTimeRegistry();
gAccelSignDisplayIntensity-=kFrameTime*0.5;
}
}
#define kMinSteerResistance 0.3
#define kNormalSteerAlignment 0.65
#define kSteerResistanceFactor 0.4
#define kSteerAlignmentFactor 1.5
//creates force-feedback effects when the the players car is sliding
void FFBResponse()
{
tCarPhysics *phys=(tCarPhysics*)gViewedEntity->physics;
tCarDefinition *car=&(phys->car);
float slideVelo=0;
for(int i=0;i<car->numWheels;i++)
slideVelo+=gSurfaceTypes->types[phys->wheels[i].surfaceType].soundEnable?phys->wheels[i].slipVelo:0;
slideVelo/=car->numWheels;
slideVelo*=0.02;
if(slideVelo>0.5)slideVelo=0.5;
FFBiShockDirect(slideVelo,slideVelo);
float velo=~gViewedEntity->velo;
float bumpHeight=(gSurfaceTypes->types[phys->wheels[0].surfaceType].bumpHeight+gSurfaceTypes->types[phys->wheels[1].surfaceType].bumpHeight)*0.5;
FFBSetGoundRumble(velo,bumpHeight*10);
float wheelsSlipFactor=1-(fabs(phys->wheels[0].slipAngle)+fabs(phys->wheels[1].slipAngle))*5-(fabs(phys->wheels[0].slip)+fabs(phys->wheels[1].slip))*0.5;
if(wheelsSlipFactor<0)wheelsSlipFactor=0;
int wheelsOnGround=0;
for(int i=0;i<2;i++)
if(phys->wheels[i].suspension<car->wheels[i].maxSuspension)
wheelsOnGround++;
wheelsSlipFactor*=wheelsOnGround/2.0;
float steerResistance=(1-kMinSteerResistance)*(1/(velo*0.2+1))+kMinSteerResistance;
float steerAlignment=velo<10?velo/10*kNormalSteerAlignment:kNormalSteerAlignment+((velo-10)/70)*(1-kNormalSteerAlignment);
FFBSetSteerResistance(kSteerResistanceFactor*steerResistance*wheelsSlipFactor,kSteerAlignmentFactor*steerAlignment*wheelsSlipFactor);
}
tVector3 gCameraViewPos;
void GetNewTripod(tGameEntity *cameraViewEntity)
{
float side=RandomProb(0.5)?-1:1;
float speed;
gCameraEntity->pos=RoadGetNextWaypoint(cameraViewEntity->pos,&cameraViewEntity->lastRoadIndex,&side,&speed,((gCameraEntity->lastRoadIndex<cameraViewEntity->lastRoadIndex)^gGameInfo->reverse)?100:-100)+Vector(0,RandomFl(4,13),0);
}
void CalcCamera()
{/*
gCameraEntity->pos=gViewedEntity->pos+Vector(0,2000,0);
MatrixIdentity(gCameraEntity->dir);
MatrixRotX(gCameraEntity->dir,PI/2);
return;
*/
tGameEntity *cameraViewEntity=gCarEntities[gReplayViewedEntityID];
gCameraEntity->velo=cameraViewEntity->velo;
tVector3 veloFlat,posFlat;
tVector3 cameraPos=gCameraEntity->pos;
switch(gCameraMode)
{
case kCameraFree:
if(GetInterfaceKey(kInterfaceKeyLeft))
MatrixRotY(gCameraEntity->dir,kFrameTime*3);
if(GetInterfaceKey(kInterfaceKeyRight))
MatrixRotY(gCameraEntity->dir,-kFrameTime*3);
if(GetInterfaceKey(kInterfaceKeyUp))
{
tMatrix3 m;
RotationVectorToMatrix(-kFrameTime*2**MatrixGetXVector(gCameraEntity->dir),m);
MatrixMult(gCameraEntity->dir,m,gCameraEntity->dir);
}
if(GetInterfaceKey(kInterfaceKeyDown))
{
tMatrix3 m;
RotationVectorToMatrix(kFrameTime*2**MatrixGetXVector(gCameraEntity->dir),m);
MatrixMult(gCameraEntity->dir,m,gCameraEntity->dir);
}
if(GetInterfaceKey(kInterfaceKeySpace)&&!gInputChatMode)
cameraPos=cameraPos+*MatrixGetZVector(gCameraEntity->dir)*kFrameTime*25;
gCameraEntity->velo=Vector(0,0,0);
break;
case kCameraChase:
veloFlat=Vector(cameraViewEntity->velo.x,0,cameraViewEntity->velo.z);
posFlat=Vector(cameraViewEntity->pos.x,0,cameraViewEntity->pos.z);
cameraPos=posFlat-(sqr(veloFlat)<sqr(1.5)?*MatrixGetZVector(cameraViewEntity->dir):!veloFlat)*(gCameraReverse?-9:9);
cameraPos.y=cameraViewEntity->pos.y+2.7;
break;
case kCameraChaseClose:
veloFlat=Vector(cameraViewEntity->velo.x,0,cameraViewEntity->velo.z);
posFlat=Vector(cameraViewEntity->pos.x,0,cameraViewEntity->pos.z);
cameraPos=posFlat-(sqr(veloFlat)<sqr(1.5)?*MatrixGetZVector(cameraViewEntity->dir):!veloFlat)*(gCameraReverse?-6:6);
cameraPos.y=cameraViewEntity->pos.y+1.85;
break;
case kCameraLeftSide:
cameraPos=cameraViewEntity->pos-*MatrixGetXVector(cameraViewEntity->dir)*(gCameraReverse?-10:10);
cameraPos.y=cameraViewEntity->pos.y+2;
break;
case kCameraTripod:
if(sqr(gCameraEntity->pos-cameraViewEntity->pos)>sqr(120))
GetNewTripod(cameraViewEntity);
cameraPos=gCameraEntity->pos;
gCameraEntity->velo=Vector(0,0,0);
break;
case kCameraTop:
{
float heigth=7+~cameraViewEntity->velo;
if(heigth>40)
heigth=40;
cameraPos=cameraViewEntity->pos+Vector(0,heigth,1);
}
break;
case kCameraCockpit:
case kCameraCockpitCarHidden:
{
tCarPhysics *phys=(tCarPhysics*)cameraViewEntity->physics;
tCarDefinition *car=&(phys->car);
cameraPos=cameraViewEntity->pos
+((gCameraMode==kCameraCockpit)?(*MatrixGetXVector(cameraViewEntity->dir)*car->driverPos.x):Vector(0,0,0))
+*MatrixGetYVector(cameraViewEntity->dir)*(car->driverPos.y+0.5)
+*MatrixGetZVector(cameraViewEntity->dir)*car->driverPos.z;
}
break;
case kCameraLeftWheel:
cameraPos=cameraViewEntity->pos-*MatrixGetXVector(cameraViewEntity->dir)*(gCameraReverse?-1.2:1.2)+*MatrixGetYVector(cameraViewEntity->dir)*0.4+*MatrixGetZVector(cameraViewEntity->dir)*0.5;
break;
}
if(gFrameCount*kFrameTime<1.5&&!gReplay)
{
float f=(gFrameCount*kFrameTime-1.5)/3*2*PI;
cameraPos=cameraViewEntity->pos-
*MatrixGetXVector(cameraViewEntity->dir)*sin(f)*15+
*MatrixGetYVector(cameraViewEntity->dir)*(2.0-20.0*f)-
*MatrixGetZVector(cameraViewEntity->dir)*cos(f)*15;
}
tVector3 cameraViewPos=cameraPos-cameraViewEntity->pos;
if(sqr(gCameraViewPos-cameraViewPos)<sqr(11)&&gCameraMode!=kCameraTripod&&gCameraMode!=kCameraFree&&cameraViewEntity==cameraViewEntity)
//camera interpolation
cameraViewPos=gCameraViewPos+(cameraViewPos-gCameraViewPos)*kFrameTime*10;
gCameraViewPos=cameraViewPos;
tVector3 newPos=cameraViewEntity->pos+cameraViewPos;
// if(sqr(gCameraEntity->pos-newPos)>25)
// gCameraEntity->lastRoadIndex=0;
gCameraEntity->pos=newPos;
cameraViewEntity=cameraViewEntity;
if(gCameraMode==kCameraCockpit||gCameraMode==kCameraLeftWheel||gCameraMode==kCameraCockpitCarHidden&&!(gFrameCount*kFrameTime<1.5&&!gReplay))
{
MemoryMove(gCameraEntity->dir,cameraViewEntity->dir,sizeof(tMatrix4));
if((gCameraMode==kCameraCockpit||gCameraMode==kCameraCockpitCarHidden)&&gCameraReverse)
{
*MatrixGetXVector(gCameraEntity->dir)=-*MatrixGetXVector(gCameraEntity->dir);
*MatrixGetZVector(gCameraEntity->dir)=-*MatrixGetZVector(gCameraEntity->dir);
}
}
else if(gCameraMode!=kCameraFree)
{
*MatrixGetZVector(gCameraEntity->dir)=!(cameraViewEntity->pos-gCameraEntity->pos+Vector(0,1.2,0));
*MatrixGetYVector(gCameraEntity->dir)=Vector(0,1,0);
MatrixReAdjust(gCameraEntity->dir);
}
if(gCameraMode!=kCameraFree)
{
tVector3 normal;
float dist=GetGroundOffset(gCameraEntity->pos,&gCameraEntity->lastRoadIndex,&normal,0);
if(dist<0)
if(!isinf(dist))
gCameraEntity->pos=gCameraEntity->pos-normal*dist;
}
}
void MoveGhostCar()
{
if(gGameInfo->numLaps!=-1)
return;
tCarPhysics *phys=(tCarPhysics*)gCarEntities[0]->physics;
if(phys->lapCount<2)
return;
LogReplayGhostFrame();
}
//use this define to disable all game physics.
//useful to test raw graphics performance.
//#define __NOPHYSICS
//Calculate one game physics frame
void GameFrame()
{
/*static int p=false;
if(Button()&&!p){gCarEntities[0]->pos=gCameraEntity->pos;p=true;}else if(!Button())p=false;*/
if(!gPaused)
{
#ifndef __NOPHYSICS
//Move all entities
MotionFrame();
//check for collision between entities and ground or each other
CollisionFrame();
//check if cars have passed any checkpoint or lap start/finish line.
LapCheck();
//send local physics data to network
NetworkSendPhysics();
#endif
}
//get AI or user input for local cars
ControlFrame();
if(!gPaused)
{
#ifndef __NOPHYSICS
//Calculate car sound effects
SoundFrame();
//calculate all local entities physics
PhysicsFrame();
//process particles
ParticlesProcess();
}
//receive physics for remote entities
NetworkReceivePhysics();
if(!gPaused)
{
MoveGhostCar();
//create force-feedback effects when the the players car is sliding
FFBResponse();
#endif
}
CalcCamera();
//check if we have time to draw a graphics frame
if(CheckFrameTime()||gPaused)
{
//draw frame
RenderFrame(true);
//if we are too fast, waste some time
CheckTimeSkip();
if(gLightning<gFrameCount-10)
gLightning=0;
}
TextClearBuffer();
if(!gPaused)
gFrameCount++;
if(RandomProb(gEnvironment->flashIntensity*kFrameTime))
gLightning=gFrameCount;
if(gFrameCount>gNetPauseTime&&gNetPauseTime!=0)
PauseGame();
if(gFrameCount%30)
SystemPoll(true);
}
int GameReplayFrame()
{
if(!gPaused||!gBackgroundReplay)
{
CollisionFrame();
LapCheck();
SoundFrame();
ParticlesProcess();
MotionFrame();
LogReplayFrame();
if(!(gBackgroundReplay&&gInterfaceType))
ControlFrame();
PhysicsFrame();
}
CalcCamera();
if(gGameInfo->numLaps==-1&&!gBackgroundReplay)
TrackerWaitForLapTimeRegistry();
int hasRendered=false;
//check if we have time to draw a graphics frame
if(CheckFrameTime()||gPaused)
{
//draw frame
RenderFrame(true);
//if we are too fast, waste some time
CheckTimeSkip();
hasRendered=true;
}
if(gFrameCount%30&&!gBackgroundReplay)
SystemPoll(true);
if(!gPaused||!gBackgroundReplay)
gFrameCount++;
return hasRendered;
}

41
source/gameframe.h Executable file
View File

@ -0,0 +1,41 @@
#ifndef __GAMEFRAME
#define __GAMEFRAME
#define kFPS 75.0
#define kFrameTime (1/kFPS)
#define kStartGameDelaySeconds 5.0
enum{
kEndGame=1,
kEndGameNoLeave,
kEndGameNoReplay,
kEndGameRestart
};
extern int gFrameCount;
extern int gGraphFrameCount;
extern int gGameEnd,gRaceFinished,gDisqualified;
extern int gPaused;
extern int gNetPauseTime;
extern float gFPS;
extern float gStartTime;
extern float gAccelSignDisplayIntensity,gAccelSignDisplayCorner;
extern float gTimeStretch;
extern int gCurrentLapStart;
extern int gBestLapStart;
extern int gLastLapTime;
extern int gBestLapTime;
extern int gWorldRecord,gLocalRecord;
extern int gDisabledRestart;
extern char gRecordName[];
#define kMinActivityVelo 1.2
void GameFrame();
int GameReplayFrame();
void StartFrameCount();
void PauseGame();
void UnPauseGame();
#endif

772
source/gameinitexit.cpp Executable file
View File

@ -0,0 +1,772 @@
//gameinitexit.cpp
//initialize a new game and dispose all the game structures after the game has ended
#include <OpenGL/gl.h>
#include <stdio.h>
#include <string.h>
#include "gametime.h"
#include "gamemem.h"
#include "entities.h"
#include "fileio.h"
#include "sky.h"
#include "carphysics.h"
#include "gameframe.h"
#include "roads.h"
#include "parser.h"
#include "network.h"
#include "environment.h"
#include "config.h"
#include "gameinitexit.h"
#include "error.h"
#include "gamesound.h"
#include "text.h"
#include "renderframe.h"
#include "controls.h"
#include "tracks.h"
#include "stencil.h"
#include "log.h"
#include "networkphysics.h"
#include "random.h"
#include "particles.h"
#include "interfaceutil.h"
#include "tracker.h"
#include "screen.h"
#include "textures.h"
#include "gamesystem.h"
#include "interface.h"
#include "interfacemultiplayer.h"
#include "initexit.h"
/*
#if __option(profile)
#include <profiler.h>
#endif
*/
//the map info structure
tMapInfo *gMapInfo=NULL;
//the game info structure
tGameInfo *gGameInfo=NULL;
//pointers to the game entities of the cars participating in the game
tGameEntity *gCarEntities[kMaxPlayers];
tGameEntity *gGhostEntity;
tMapEnv *gMapEnv=NULL;
//the check points along the track (invisible, used only for lead/trail calculation)
tCheckPoint gCheckPoints[kNumCheckPoints];
int gNumCornerSigns;
tCornerSign gCornerSigns[kMaxCornerSigns];
//is this a replay being watched?
int gReplay=false;
int gBackgroundReplay=false;
int gReplayAutoCam=false;
int gReplayViewedEntityID;
int gReplayNextCam;
int gReplayOldFrameCount;
void InitGInfo(tGameInfo *gInfo)
{
gInfo->inited=false;
gInfo->version=0;
gInfo->numPlayers=0;
gInfo->numNetPlayers=0;
gInfo->reverse=0;
gInfo->environment=kFileErr;
gInfo->numLaps=0;
gInfo->map=kFileErr;
gInfo->network=false;
gInfo->playerID=0;
gInfo->arcade=kGameModeSim;
gInfo->maxTime=0;
gInfo->unused1=false;
gInfo->unused2=false;
gInfo->carsOnSpeed=gConfig->carsOnSpeed;
gInfo->demolition=gConfig->demolition;
gInfo->playerInited[0]=true;
strcpy(gInfo->environmentName,"");
strcpy(gInfo->mapName,"");
for(int i=0;i<kMaxPlayers;i++)
{
gInfo->playerCars[i]=kFileErr;
gInfo->playerColors[i]=0;
gInfo->playerAddOns[i]=0;
gInfo->netID[i]=0;
gInfo->ping[i]=0;
gInfo->playerVersions[i]=0;
strcpy(gInfo->playerCarNames[i],"");
strcpy(gInfo->playerNames[i],"");
}
}
//load map describtion from the file refered to by ref.
void ProcessMapInfo()
{
if(gMapInfo->reverse)
gGameInfo->reverse=!gGameInfo->reverse;
//get road types data
gRoadTypes=(tRoadTypeList*)FileGetParsedDataPtr(gMapInfo->roadTypes,kParserTypeRoadTypeDesc,sizeof(tRoadTypeList));
//initialize game entities defined by map
for(int i=0;i<gMapInfo->numObjs;i++)
{
if(gMapInfo->obj[i].envFlags==0||(gMapInfo->obj[i].envFlags&gEnvironment->envFlags))
{
//create a new entity
tGameEntity *entity;
entity=EntityNew(gFirstEntity);
entity->renderType=kRenderTypeModel;
//get entity position and direction from map info
entity->pos=gMapInfo->obj[i].pos;
EulerAnglesToMatrix(gMapInfo->obj[i].dir*kDegreeRadians,entity->dir);
//get extension of file describing entity
char *extension=FileGetExtension(gMapInfo->obj[i].model);
entity->physics=MemoryAllocateBlock(sizeof(int));
*((int*)entity->physics)=gMapInfo->obj[i].color;
entity->untouchable=gMapInfo->obj[i].untouchable;
if(extension)
//is this entity just a model (no interaction with the game, just graphics).
if(!_stricmp(extension,kFileTypeModel))
entity->renderData=gMapInfo->obj[i].model;
//or is it a solid entity?
else if(!_stricmp(extension,kFileTypeSolidEntity))
{
//initialize entity
entity->physicsType=kPhysicsTypeSolid;
entity->physicsData=gMapInfo->obj[i].model;
entity->physicsMachine=kPhysicsLocal;
tSolidEntityPhysics *ent=(tSolidEntityPhysics*)FileGetParsedDataPtr(entity->physicsData,kParserTypeSolidEntityDesc,sizeof(tSolidEntityPhysics));
if(ent->randomColor)
*((int*)entity->physics)=RandomInt(0,ent->numColors);
entity->renderData=ent->model;
if(ent->movable)
entity->lastActivity=-1000;
}
else if(!_stricmp(extension,kFileTypeCarDefinition))
{
//initialize entity
entity->renderType=kRenderTypeCar;
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(gMapInfo->obj[i].model,kParserTypeCarDesc,sizeof(tCarDefinition));
entity->renderData=car->model;
entity->physicsType=kPhysicsTypeCar;
entity->controlType=kControlTypeNone;
entity->physicsData=gMapInfo->obj[i].model;
entity->physics=MemoryAllocateZeroedBlock(sizeof(tCarPhysics));
entity->physicsMachine=gGameInfo->network?(i==gGameInfo->playerID?kPhysicsLocal:kPhysicsRemote):kPhysicsLocal;
entity->lastActivity=-1000;
tCarPhysics *phys=(tCarPhysics*)entity->physics;
phys->car=*car;
phys->car.wheels=(tWheelDefinition*)MemoryAllocateBlock(sizeof(tWheelDefinition)*car->numWheels);
MemoryMove(phys->car.wheels,car->wheels,sizeof(tWheelDefinition)*car->numWheels);
phys->color=gMapInfo->obj[i].color;
}
//is it something we don't understand?
else
{
char error[256];
sprintf(error,"Illegal File Type %s Specified for Object",extension);
FailWithErrorString(error);
}
}
//else PrintConsoleString("%s: %d/%d",FileGetName(gMapInfo->obj[i].model),gMapInfo->obj[i].envFlags,gEnvironment->envFlags);
}
gMapEnv=NULL;
for(int i=0;i<gMapInfo->numMapEnvs;i++)
if(gMapInfo->mapEnv[i].envFlags&gEnvironment->envFlags)
gMapEnv=gMapInfo->mapEnv+i;
if(gMapEnv)
if(gMapEnv->fogBegin)
{
GLfloat fogColor[4];
*(tVector3*)fogColor=gMapEnv->fogColor;
fogColor[3]=1;
glFogfv(GL_FOG_COLOR,fogColor);
glFogf(GL_FOG_START,gMapEnv->fogBegin);
glFogf(GL_FOG_END,gMapEnv->fogEnd);
}
//calculate road checkpoints
if(gMapInfo->loop)
RoadInitCheckPoints(gMapInfo->startPos);
else
{
RoadInitCheckPoints(gMapInfo->startPos,gMapInfo->finishPos);
gGameInfo->numLaps=1;
}
RoadInitCornerSigns();
}
void CalcCamera();
void InitCars()
{
for(int i=0;i<gGameInfo->numPlayers;i++)
{
//get car describtion
tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(gGameInfo->playerCars[i],kParserTypeCarDesc,sizeof(tCarDefinition));
//initialize car entity
tGameEntity *entity;
entity=EntityNew(gFirstEntity);
entity->renderType=kRenderTypeCar;
entity->renderData=car->model;
entity->physicsType=kPhysicsTypeCar;
entity->controlType=(i==gGameInfo->playerID?kControlTypeUserInput:kControlTypeAIInput);
//entity->controlType=kControlTypeAIInput;
entity->physicsData=gGameInfo->playerCars[i];
entity->physics=MemoryAllocateZeroedBlock(sizeof(tCarPhysics));
entity->physicsMachine=gGameInfo->network?(i==gGameInfo->playerID?kPhysicsLocal:kPhysicsRemote):kPhysicsLocal;
if(i>=gGameInfo->numNetPlayers&&gGameInfo->playerID==0)
entity->physicsMachine=kPhysicsLocal;
gCarEntities[i]=entity;
//position car at start position
int startAtEnd=(gGameInfo->reverse&&!gMapInfo->loop);
tVector3 startPos=startAtEnd?gMapInfo->finishPos:gMapInfo->startPos;
if(gGameInfo->numLaps==-1&&gMapInfo->loop)
{
int roadIndex=0;
float side=0,speed;
startPos=RoadGetNextWaypoint(gMapInfo->startPos,&roadIndex,&side,&speed,-700);
}
tVector3 startDir=RoadGetDir(RoadGetPosition(startPos,0,NULL));
entity->pos=startPos-startDir*((i/2)*10+gMapInfo->startLineOffset+(i%2?gMapInfo->carOffset:0))+!(startDir%Vector(0,1,0))*(i%2?-1:1)*gMapInfo->startCenterOffset;
entity->netPos=entity->pos;
*MatrixGetZVector(entity->dir)=startDir;
*MatrixGetYVector(entity->dir)=Vector(0,1,0);
MatrixReAdjust(entity->dir);
tCarPhysics *phys=(tCarPhysics*)entity->physics;
if(i==gGameInfo->playerID)
gViewedEntity=entity;
//set up car specs
if(startAtEnd)
phys->checkPoint=kNumCheckPoints-1;
phys->car=*car;
phys->car.wheels=(tWheelDefinition*)MemoryAllocateBlock(sizeof(tWheelDefinition)*car->numWheels);
MemoryMove(phys->car.wheels,car->wheels,sizeof(tWheelDefinition)*car->numWheels);
phys->addOns=gGameInfo->playerAddOns[i];
phys->color=gGameInfo->playerColors[i];
phys->aiPowerCycle=RandomFl(0,2*PI);
phys->aiRouteCycle=RandomFl(0,2*PI);
phys->position=RoadGetPosition(entity->pos,entity->lastRoadIndex,NULL);
if(i>0)
{
tCarPhysics *phys2=(tCarPhysics*)gCarEntities[0]->physics;
if(phys->position>phys2->position&&!gGameInfo->reverse)
phys->lap=-1;
else if(phys->position<phys2->position&&gGameInfo->reverse)
phys->lap=-1;
}
if(gGameInfo->playerNames[i][0])
phys->plateName=gGameInfo->playerNames[i];
for(int j=0;j<5;j++)
phys->dirtStretch[j]=RandomFl(-0.5,0.5);
InstallCarAddOns(phys);
//if car is on left side, prepare for overtaking
//(otherwise ai players will immediatly try to change lanes, not a good idea).
if(i%2)
{
phys->overtaking=gCarEntities[0];
phys->overtakeSide=-1;
}
}
}
void InitGameEntities()
{
//initialize entity list
EntityResetCount();
gFirstEntity=(tGameEntity*)MemoryAllocateZeroedBlock(sizeof(tGameEntity));
gFirstEntity->next=gFirstEntity;
gFirstEntity->prev=gFirstEntity;
//process map info describtion
ProcessMapInfo();
//initialize car entities
InitCars();
//initialize camera
gCameraEntity=EntityNew(gFirstEntity);
//initialize ghost
if(gGameInfo->numLaps==-1)
{
gGhostEntity=EntityNew(gFirstEntity);
gGhostEntity->physics=MemoryAllocateZeroedBlock(sizeof(tCarPhysics));
MemoryMove(gGhostEntity->physics,gCarEntities[0]->physics,sizeof(tCarPhysics));
gGhostEntity->pos=Vector(10000,10000,10000);
gGhostEntity->physicsType=kPhysicsTypeGhost;
gGhostEntity->renderType=kRenderTypeGhost;
gGhostEntity->controlType=kControlTypeNone;
gGhostEntity->physicsData=gGameInfo->playerCars[0];
gGhostEntity->renderData=gCarEntities[0]->renderData;
}
}
void InitInfoDisplay();
//initialize a new game
int InitGame()
{
if(gFileTampered)
Exit();
//get map info data
gMapInfo=(tMapInfo*)FileGetParsedDataPtr(gGameInfo->map,kParserTypeMapInfoDesc,sizeof(tMapInfo));
//load enivronment describtion
LoadEnvironment(gGameInfo->environment);
//initialize fog
GLfloat fogColor[4];
*(tVector3*)fogColor=gEnvironment->fogColor;
fogColor[3]=1;
glFogfv(GL_FOG_COLOR,fogColor);
glFogf(GL_FOG_START,600);
glFogf(GL_FOG_END,800);
InitGameEntities();
//initialize game end flags
gInterfaceType=false;
gGameEnd=false;
gPaused=false;
gRaceFinished=false;
gDisqualified=false;
gLightning=false;
gInputEscMode=false;
gReplayViewedEntityID=gGameInfo->playerID;
gCameraMode=gConfig->cameraMode;
gCameraReverse=0;
gOutboxPos=0;
gGameChatMessage[0]='\0';
gGameChatMessageSize=0;
gNetPauseTime=0;
SoundSilence();
//reset replay log
LogReset();
GhostLogReset();
TracksClear();
ParticlesClear();
InitInfoDisplay();
//call once to reset stencil buffer
RenderStencilLayer(true,gConfig->stencil);
//initialze lighting
SetupLighting();
//render a frame to get graphics loaded
CalcCamera();
gClipEnable=false;
float time=TimeGetSeconds();
gNumGameChatMessages=0;
gEnableTextureLoad=false;
gNumTexturesRequested=0;
RenderFrame(false);
gNumTexturesLoaded=0;
gEnableTextureLoad=true;
gDisabledRestart=0;
for(int i=0;i<gFileTableSize;i++)
{
if(gFileTable[i].tagged&&!gFileTable[i].parsed)
{
// InterfaceDrawStatusBar("Loading Textures...",gFileTable[i].name,gNumTexturesLoaded/(float)gNumTexturesRequested);
if(gNumTexturesRequested>0)
InterfaceDrawStatusBar("Loading Textures...","Please Wait",gNumTexturesLoaded/(float)gNumTexturesRequested);
gTexturesQualityModifier=gFileTable[i].tagged+1;
TexturesSelectTex(i);
SystemPoll(true);
}
}
gTexturesQualityModifier=0;
// PrintConsoleString("loading took: %f seconds.",TimeGetSeconds()-time);
gClipEnable=true;
//synchronize players on network
if(gGameInfo->network)
{
InterfaceDrawStrings("Waiting for other Players...","",kFileErr);
if(!NetworkSynch(gGameInfo->numNetPlayers))
return false;
}
//start clock
gTimeStretch=1.0;
gBestLapTime=0;
StartFrameCount();
gPaused=false;
return true;
}
void DisposeEntities()
{
if(gFirstEntity)
{
tGameEntity *entity=(tGameEntity*)gFirstEntity->next;
while(entity!=gFirstEntity)
{
tGameEntity *next=(tGameEntity*)entity->next;
if(entity->physics)
MemoryFreeBlock(entity->physics);
SoundFreeEntitySources(entity);
//FREE CAR PHYSICS!
MemoryFreeBlock(entity);
entity=next;
}
MemoryFreeBlock(gFirstEntity);
gFirstEntity=NULL;
gViewedEntity=NULL;
gCameraEntity=NULL;
}
}
void StartReplay()
{
SoundSilence();
tCarPhysics physStore[kMaxPlayers];
// for(int i=0;i<gGameInfo->numPlayers;i++)
// physStore[i]=*(tCarPhysics*)gCarEntities[i]->physics;
DisposeEntities();
InitGameEntities();
/* for(int i=0;i<gGameInfo->numPlayers;i++)
{
*(tCarPhysics*)gCarEntities[i]->physics=physStore[i];
tCarPhysics *phys=(tCarPhysics*)gCarEntities[i]->physics;
phys->dirt=0;
for(int j=0;j<kMaxWheels;j++)
phys->wheels[j].lastTrack=0;
}*/
// for(int i=0;i<gNumGameChatMessages;i++)
// gGameChatMessagesRecv[i].frameCount-=gFrameCount;
gCameraEntity->pos=Vector(10000,10000,10000);
if(gCameraMode==kCameraFree)
gCameraMode=kCameraTripod;
if(gGameInfo->numLaps==-1)
gGhostEntity->pos=Vector(10000,10000,10000);
gFrameCount=gGameInfo->numLaps==-1?(gBestLapTime!=0?gBestLapStart+5:gCurrentLapStart+5):0;
gGraphFrameCount=gFrameCount;
gStartTime=TimeGetSeconds()-gFrameCount*kFrameTime;
gReplayIndex=0;
gReplayNextCam=gFrameCount+RandomFl(4,12)*kFPS;
TracksClear();
}
extern int gIndexPos;
extern int gGhostIndexPos;
void ReplayProcessNetwork(int *end)
{
if(gGameInfo->network)
{
tNetworkPacket message;
while(NetworkReceivePacket(&message))
switch(message.what)
{
case kMessageTypeEndReplay:
*end=true;
gGameEnd=kEndGameNoLeave;
break;
case kMessageTypeGameTerminated:
*end=true;
return;
case kMessageTypeChat:
InsertGameChatMessage(((tChatMessage*)message.data)->str);
ChatBufferInsert(((tChatMessage*)message.data),gChatBuffer);
PlayInterfaceSound(FileGetReference("chat.wav"));
break;
case kMessageTypeBye:
{
if(message.from==0)
sprintf(gDisconnectString,"%s quit and stopped hosting.",gGameInfo->playerNames[0]);
int netID=message.from;
int id=-1;
//find the players id
for(int i=0;i<gGameInfo->numNetPlayers;i++)
if(gGameInfo->netID[i]==netID)
id=i;
if(id!=-1)
{
tChatMessage m;
m.flags=kChatFlagSystem;
sprintf(m.str,"### %s is quitting.",gGameInfo->playerNames[id]);
SoundReInit();
PlayInterfaceSound(FileGetReference("chat.wav"));
InsertGameChatMessage(m.str);
ChatBufferInsert(&m,gChatBuffer);
}
}
break;
case kMessageTypePlayerLeft:
{
int netID=message.from;
int id=-1;
//find the players id
for(int i=0;i<gGameInfo->numPlayers;i++)
if(gGameInfo->netID[i]==netID)
id=i;
if(id!=-1)
{
char leftMessage[256];
//PrintConsoleString("### Player %d left the game. netID: %d",id,netID);
sprintf(leftMessage,"### %s left the game.",gGameInfo->playerNames[id]);
InsertGameChatMessage(leftMessage);
//KillPlayer(id);
gGameInfo->netID[id]=-1;
}
}
break;
}
}
}
int ReplayFrame()
{
int end=false;
static int save=false;
if(GetInterfaceKey(kInterfaceKeyEsc)&&!gGameInfo->network)
end=true;
if(GetInterfaceKey(kInterfaceKeyCmd)&&GetInterfaceKey(kInterfaceKeyOpt)&&GetInterfaceKey(kInterfaceKeyS)&&!gBackgroundReplay)
{
if(!save)
{
LogSaveToDisk();
save=true;
}
}
else save=false;
if(gGameEnd)
end=true;
ReplayProcessNetwork(&end);
if(gFrameCount>=gReplayOldFrameCount||gReplayIndex>=(gGameInfo->numLaps==-1?gGhostIndexPos:gIndexPos))
{
if(gMapInfo->reverse)
gGameInfo->reverse=!gGameInfo->reverse;
StartReplay();
}
if(gFrameCount>=gReplayNextCam&&gReplayAutoCam)
{
ParticlesClearScreen();
gCameraReverse=RandomProb(0.4);
gCameraMode=RandomProb(0.3)?kCameraTripod:RandomInt(kCameraChase,kCameraTop+1);
int nextViewID;
do{
nextViewID=RandomInt(0,gGameInfo->numPlayers);
}while(gGameInfo->netID[nextViewID]==-1);
tGameEntity *nextView=gCarEntities[nextViewID];
if(sqr(nextView->velo)>=1.0)
{
gViewedEntity=nextView;
gReplayViewedEntityID=nextViewID;
}
float cameraDuration;
switch(gCameraMode)
{
case kCameraChase:
case kCameraChaseClose:
cameraDuration=RandomFl(3,10);break;
case kCameraLeftSide:
case kCameraLeftWheel:
cameraDuration=RandomFl(2,5);break;
case kCameraTop:
cameraDuration=RandomFl(3,6);break;
case kCameraTripod:
cameraDuration=RandomFl(8,18);break;
case kCameraCockpit:
case kCameraCockpitCarHidden:
cameraDuration=RandomFl(2,5);
gCameraReverse=false;
break;
}
gReplayNextCam=gReplayNextCam+cameraDuration*kFPS;
}
while(!GameReplayFrame()&&gBackgroundReplay);
return end;
}
void RunReplay()
{
TextClearBufferFading();
//LogLoad(FileGetReference("test.log"),gGameInfo);
gReplay=true;
if(gGameInfo->numLaps==-1)
{
tCarPhysics *phys=(tCarPhysics*)gCarEntities[0]->physics;
if(phys->lapCount<=1)
LogToGhostLog();
}
gReplayOldFrameCount=(gGameInfo->numLaps==-1&&gBestLapTime!=0)?gBestLapTime+gBestLapStart:gFrameCount;
if(gReplayOldFrameCount<10)return;
LogSort();
//LogSaveToDisk();
gReplayAutoCam=true;
StartReplay();
while(!ReplayFrame());
if(gGameInfo->network&&gGameInfo->playerID==0)
{
NetworkSendPacket(kMessageTypeEndReplay,NULL,0,kMessagePriorityHigh,kMessageSendToAllButSelf);
}
// gReplay=false;
}
void ExitGame()
{
/* #ifndef __APPLE_CC__
#if __option(profile)
ProfilerDump("\pProfiler Dump");
#endif
#endif
*/
FFBStop();
UnPauseGame();
if(gGameInfo->network)
{
if(gGameInfo->playerID==0)
NetworkSendPacket(kMessageTypeEndGame,NULL,0,kMessagePriorityHigh,kMessageSendToAllButSelf);
else if(gGameEnd!=kEndGameNoLeave)
{
NetworkSendPacket(kMessageTypeBye,NULL,0,kMessagePriorityHigh,kMessageSendToAllButSelf);
NetworkSendPacket(kMessageTypeGameTerminated,NULL,0,kMessagePriorityHigh,gGameInfo->netID[gGameInfo->playerID]);
}
}
if((gGameEnd==kEndGameNoLeave||(gGameEnd==kEndGame&&!(gGameInfo->network&&gGameInfo->playerID!=0)))&&!gGameInfo->demolition)
{
gGameEnd=false;
while((GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter)||GetInterfaceKey(kInterfaceKeyEsc)));
RunReplay();
if(gGameInfo->network)
{
if(gGameInfo->playerID==0)
NetworkSendPacket(kMessageTypeEndGame,NULL,0,kMessagePriorityHigh,kMessageSendToAllButSelf);
else if(gGameEnd!=kEndGameNoLeave)
{
NetworkSendPacket(kMessageTypeBye,NULL,0,kMessagePriorityHigh,kMessageSendToAllButSelf);
NetworkSendPacket(kMessageTypeGameTerminated,NULL,0,kMessagePriorityHigh,gGameInfo->netID[gGameInfo->playerID]);
}
}
}
/* if(gGameEnd!=kEndGameRestart)
{
float startTime=TimeGetSeconds();
float t;
do{
t=TimeGetSeconds()-startTime;
RenderFrame(false);
InterfaceDrawBackgroundFade(t/0.3,true);
ScreenBlit();
}while(t<0.3);
}*/
DisposeEntities();
gInputChatMode=false;
gFrameCount=0x7fffffff;
TextClearBuffer();
TracksClear();
SoundSilence();
ParticlesClear();
glClear(GL_COLOR_BUFFER_BIT);
gMapInfo=NULL;
gGameInfo=NULL;
gMapEnv=NULL;
TrackerLapTimeRegistryClose();
LoadEnvironment(FileGetReference("showroom.senv"));
FlushKeys();
}
int GetPlayerRanking()
{
tCarPhysics *phys=(tCarPhysics*)gCarEntities[gGameInfo->playerID]->physics;
if(phys->lapCount>gGameInfo->numLaps&&!gDisqualified)
{
int place=1;
for(int i=0;i<gGameInfo->numPlayers;i++)
{
tCarPhysics *phys2=(tCarPhysics*)gCarEntities[i]->physics;
if(phys2->lapCount>gGameInfo->numLaps)
if(phys2->lapTimes[gGameInfo->numLaps]<phys->lapTimes[gGameInfo->numLaps])
place++;
}
if(gGameInfo->maxTime)
return phys->lapTimes[gGameInfo->numLaps];
if(gGameInfo->numLaps==-1)
return gBestLapTime;
return place;
}
else
return -1;
}
int RunGame(tGameInfo *gInfo)
{
gReplay=false;
int place;
int reverse=gInfo->reverse;
do{
gGameInfo=gInfo;
if(InitGame())
while(!gGameEnd)
GameFrame();
place=GetPlayerRanking();
gInfo->reverse=reverse;
ExitGame();
gInfo->reverse=reverse;
}while(gGameEnd==kEndGameRestart);
gInterfaceGInfo=*gInfo;
StartBackgroundReplay();
return place;
}

179
source/gameinitexit.h Normal file
View File

@ -0,0 +1,179 @@
#ifndef __GAMEINITEXIT
#define __GAMEINITEXIT
#include "vectors.h"
#include "entities.h"
#include "fileio.h"
#define kMaxPlayers 12
#define kMaxLaps 100
#define kNumCheckPoints 64
#define kMaxCornerSigns 64
typedef struct{
tFileRef model;
int color;
int envFlags;
int untouchable;
tVector3 pos,dir;
}tMapObjectDef;
typedef struct{
float time;
tGameEntity *setBy;
int hit;
}tPassTimeRec;
typedef struct{
float index;
tPassTimeRec passTimes[kMaxLaps+2];
}tCheckPoint;
typedef struct{
float pos;
float accel;
}tCornerSign;
typedef struct{
tVector3 a,b,c;
}tVisWall;
typedef struct{
int envFlags;
int lightEnable;
float fogBegin,fogEnd;
float fogOscillation,fogOscillationSpeed;
tVector3 fogColor;
tVector3 lightDir,flareDir;
tFileRef sky0,sky90,sky180,sky270,skytop,skybot;
tFileRef spheremap;
tFileRef lightMap;
tVector2 lightMapTopLeft,lightMapBotRight,lightMapSpeed;
tFileRef lightMap2;
tVector2 lightMap2TopLeft,lightMap2BotRight,lightMap2Speed;
}tMapEnv;
typedef struct{
tFileRef road;
tFileRef image;
int loop,dirtEnable;
int hideMap;
int dontDrawRoad;
int builtIn;
int demoAvailable;
int needsToStop;
int useAltEnv;
tFileRef dirtMap;
int maxPlayers;
int hasOverview;
tFileRef overview;
tVector2 overviewTopLeft,overviewBotRight;
char name[256];
int playerPos;
int reverse;
float startLineOffset,startCenterOffset,carOffset;
float speedFactor;
float dirtIntensity;
tVector3 startPos;
tVector3 finishPos;
tFileRef roadTypes;
int numObjs;
tMapObjectDef *obj;
int numVisWalls;
int baseSurfaceType;
tVisWall *visWalls;
int numMapEnvs;
tMapEnv* mapEnv;
}tMapInfo;
enum {
kGameInfoNetworkEnable=1<<0,
kGameInfoNetworkForcePlayerCar=1<<1,
kGameInfoNetworkCantGoBackwards=1<<2
};
#define kMaxNameLength 64
enum {
kGameModeSim=0,
kGameModeArcade,
kGameModeTurbo,
kGameModeStrict
};
typedef struct{
UInt8 inited;
UInt8 numNetPlayers;
UInt8 numPlayers;
UInt8 reverse;
SInt8 numLaps;
UInt8 network;
UInt8 playerID;
SInt8 arcade;
UInt8 carsOnSpeed;
UInt8 demolition;
UInt8 unused1;
UInt8 unused2;
float maxTime,silverTime,goldTime;
UInt32 version;
tFileRef map;
tFileRef environment;
char environmentName[kMaxFileNameLength];
char mapName[kMaxFileNameLength];
UInt8 playerColors[kMaxPlayers];
SInt8 netID[kMaxPlayers];
tFileRef playerCars[kMaxPlayers];
int playerAddOns[kMaxPlayers];
float ping[kMaxPlayers];
UInt8 playerInited[kMaxPlayers];
int playerVersions[kMaxPlayers];
char playerCarNames[kMaxPlayers][kMaxFileNameLength];
char playerNames[kMaxPlayers][kMaxNameLength];
}tGameInfo;
typedef struct{
UInt8 inited;
UInt8 numNetPlayers;
UInt8 numPlayers;
UInt8 reverse;
SInt8 numLaps;
UInt8 network;
SInt8 arcade;
UInt8 carsOnSpeed;
UInt8 demolition;
UInt32 version;
char environmentName[kMaxFileNameLength];
char mapName[kMaxFileNameLength];
UInt8 playerColors[kMaxPlayers];
SInt8 netID[kMaxPlayers];
int playerAddOns[kMaxPlayers];
float ping[kMaxPlayers];
UInt8 playerInited[kMaxPlayers];
int playerVersions[kMaxPlayers];
char playerCarNames[kMaxPlayers][kMaxFileNameLength];
char playerNames[kMaxPlayers][kMaxNameLength];
}tNetGameInfo;
extern tMapInfo *gMapInfo;
extern tMapEnv *gMapEnv;
extern tGameInfo *gGameInfo;
extern int gReplay;
extern int gBackgroundReplay;
extern int gReplayAutoCam;
extern int gReplayViewedEntityID;
extern tGameEntity *gCarEntities[kMaxPlayers];
extern tGameEntity *gGhostEntity;
extern tCheckPoint gCheckPoints[kNumCheckPoints];
extern int gNumCornerSigns;
extern tCornerSign gCornerSigns[kMaxCornerSigns];
extern int gReplayOldFrameCount;
void InitGInfo(tGameInfo *gInfo);
int RunGame(tGameInfo *gInfo);
void StartReplay();
void RunReplay();
int ReplayFrame();
#endif

13
source/gamemem.h Executable file
View File

@ -0,0 +1,13 @@
#ifndef __GAMEMEM
#define __GAMEMEM
#define MemoryAllocateBlock(size) ((void*)NewPtr(size))
#define MemoryResizeBlock(ptr,size) (SetPtrSize((Ptr)(ptr),size))
#define MemoryFreeBlock(ptr) DisposePtr((Ptr)(ptr))
#define MemoryAllocateZeroedBlock(size) ((void*)NewPtrClear(size)) //allocated block of zeros
#define MemoryBlockSize(ptr) GetPtrSize((Ptr)(ptr)) //size of an allocated block
#define MemoryMove(dest,source,n) BlockMoveData(source,dest,n)
#endif

18
source/gamesound.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef __GAMESOUND
#define __GAMESOUND
#include "fileio.h"
#include "entities.h"
void SoundPause();
void SoundInit();
void SoundReInit();
void SoundFrame();
void SoundSilence();
void SoundFreeEntitySources(tGameEntity *entity);
void LoadAllSounds();
void CarPlayCrashNoise(tGameEntity *carEntity,tFileRef sound,float volume);
void PlayInterfaceSound(tFileRef sound);
#endif

22
source/gamesystem.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef __SYSTEM
#define __SYSTEM
extern int gSystemSuspended;
extern float giTunesLastStatusUpdate;
extern int giTunesPlaying;
extern char giTunesSong[1024],giTunesArtist[1024];
enum{
kITunesPaused=0,
kITunesPlaying,
kITunesStopped,
};
void SystemInit();
void SystemExit();
void SystemPoll(int inGame);
void SystemYieldTime(float till);
void SystemNotify();
int AutoUpdateRedline(char *updateURL,char* failStr);
#endif

9
source/gametime.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef __GAMETIME
#define __GAMETIME
#include <time.h>
//#define TimeGetSeconds() (clock()/(float)CLOCKS_PER_SEC)
float TimeGetSeconds();
#endif

1242
source/infodisplay.cpp Normal file

File diff suppressed because it is too large Load Diff

157
source/initexit.cpp Executable file
View File

@ -0,0 +1,157 @@
//initexit.cpp
//Initialize everything for the game to run and dispose everything
//after the game has terminated
#include <stdio.h>
#include "fpu_exc.h"
#include "screen.h"
#include "fileio.h"
#include "textures.h"
#include "models.h"
#include "text.h"
#include "gamesound.h"
#include "random.h"
#include "controls.h"
#include "network.h"
#include "config.h"
#include "environment.h"
#include "interface.h"
#include "writeout.h"
#include "music.h"
#include "interfaceutil.h"
#include "gametime.h"
#include "error.h"
#include "gamesystem.h"
#include "initexit.h"
#include "tracker.h"
#include "transparency.h"
#include "log.h"
#include "stdtypes.h"
#include "reg_tool_3.h"
#include "rt3_redline.h"
#include "ASWRegistrationCarbonAPI.h"
#include "file_tool.h"
#include "localtracker.h"
int IsInFront();
void ShowRegistrationScreen()
{
HandleError(RT3_Open(true,VERSION_3_CODES,RT3_PRODUCT_NAME,"Redline"));
Bool8 launched;
UInt64 code=RT3_GetLicenseCode();
/* int test=false;
qRT3_LicenseIsSameCode(code,RT3_PIRATED_CODE_01,test);
printf("license test: %d\n",test);*/
int valid=true;
int invalid=false;
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_CODE_01,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_CODE_02,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_03,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_04,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_05,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_06,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_07,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_08,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_09,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_10,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_11,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_12,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_13,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_14,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_15,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_16,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_17,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_18,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_19,invalid);
if(!invalid)qRT3_LicenseIsSameCode(code,RT3_PIRATED_FAKE_20,invalid);
valid=!invalid;
if(!valid)
FT_FileDelete(kPathRefPreferences, "Redline License");
if(!RT3_IsRegistered())
{
ASWReg_Initialization();
ASWReg_ShowDialog(true);
}
/* if(RT3_DisplayNotice(!valid,&launched)==nsvErr)
{
short hit;
AlertStdAlertParamRec alertParam={
false,false,nil,
"\pExit",
nil,
nil,
kAlertStdAlertOKButton,
0,
kWindowDefaultPosition};
StandardAlert(kAlertStopAlert,
"\pCan't find Register Redline app.",
"\pMake sure the Register Redline application is in the same folder as Redline, or reinstall Redline.",
&alertParam,
&hit);
ExitToShell();
}
if(launched)
ExitToShell();
if(!IsInFront())
{
gSystemSuspended=true;
} */
}
void CarSelectionDrawCar(tFileRef carRef,float time,int addOns,int color);
void Init()
{
SystemInit();
//EnableFPUExceptions();
ShowRegistrationScreen();
FileInitIO();
ConfigInit();
InitTransparency();
LogInit();
NetworkInit();
TrackerStartVersionCheck();
ScreenInit();
InitLocalTracker();
InterfaceFadeInImageFromBlack(0.291,0.57,FileGetReference("ambrosia.pct"),0.6);
MusicInit();
float startTime=TimeGetSeconds();
ControlInit();
SoundInit();
LoadAllSounds();
RandomInit();
TextLoadFont(FileGetReference("test.font"));
LoadEnvironment(FileGetReference("showroom.senv"));
while(!(TimeGetSeconds()>startTime+1));
InterfaceFadeInImageFromImage(0.291,0.57,FileGetReference("ambrosia.pct"),1,1,FileGetReference("logo.pct"),1.0);
// TexturesSelectTex(FileGetReference("fence1.tif"));
// while(!(TimeGetSeconds()>startTime+3));
InterfaceInit();
if(gFileTampered)
{
InterfaceDisplayMessage(-1,"Data files corrupted.","Please re-install Redline.");
Exit();
}
FlushKeys();
}
void Exit()
{
SoundSilence();
MusicStopSong();
ControlExit();
NetworkStopAdvertising();
NetworkExit();
WriteOutFile(FileGetReference(kConfigFileName),gConfig,kParserTypeConfigDesc);
ScreenExit();
RT3_Close();
SystemExit();
ExitToShell();
}

13
source/initexit.h Executable file
View File

@ -0,0 +1,13 @@
#ifndef __INITEXIT
#define __INITEXIT
//http://developer.apple.com/technotes/tn/tn1132.html
#define kVersion 0x01058005
#define kMinNetworkCompatibleVersion 0x01038000
#define kVersionString "1.0.5"
void Init();
void Exit();
#endif

555
source/interface.cpp Normal file
View File

@ -0,0 +1,555 @@
//interface.cpp
//the game's main menu screen
#include <OpenGL/gl.h>
#include "gametime.h"
#include <string.h>
#include "fileio.h"
#include "textures.h"
#include "controls.h"
#include "screen.h"
#include "gameinitexit.h"
#include "gameframe.h"
#include "initexit.h"
#include "text.h"
#include "config.h"
#include "interface.h"
#include "carselection.h"
#include "mapselection.h"
#include "random.h"
#include "environment.h"
#include "writeout.h"
#include "challenges.h"
#include "interfaceutil.h"
#include "renderframe.h"
#include "log.h"
#include "gamesystem.h"
#include "gamesound.h"
#include "interfacemultiplayer.h"
#include "tracker.h"
#include "stdtypes.h"
#include "reg_tool_3.h"
#include "rt3_redline.h"
tGameInfo gInterfaceGInfo;
//initializes the user interface
void InterfaceInit()
{
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f,0.0f,-1.0f);
}
void StartBackgroundReplay()
{
gMapInfo=(tMapInfo*)FileGetParsedDataPtr(gInterfaceGInfo.map,kParserTypeMapInfoDesc,sizeof(tMapInfo));
LoadEnvironment(gInterfaceGInfo.environment);
gInterfaceGInfo.network=false;
gReplay=true;
gGameInfo=&gInterfaceGInfo;
gReplayAutoCam=true;
if(!(gGameInfo->numLaps==-1&&gBestLapTime==0))
gCurrentLapStart=0;
StartReplay();
gReplayViewedEntityID=0;
/* gFrameCount=0;
gGraphFrameCount=0;
gStartTime=TimeGetSeconds();*/
}
int SelectRaceMode(tFileRef map,int (*TimerCallback)(void*),void *userData)
{
tMapInfo *mapInfo=(tMapInfo*)FileGetParsedDataPtr(map,kParserTypeMapInfoDesc,sizeof(tMapInfo));
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,5,"Select Gameplay Mode");
menu.RenderCallback=InterfaceRenderReplay;
menu.initialSelection=gConfig->arcade;
strcpy(menu.items[0].label,"Simulation");
strcpy(menu.items[0].describtion,"Simulation Mode tries to resemble real-life car physics as close as possible. Different cars may handle completely different depending on their mass distribution, drivetrain setup and many other factors.");
strcpy(menu.items[1].label,"Arcade");
strcpy(menu.items[1].describtion,"Arcade Mode puts emphasis on playability and easy handling of cars, but is vastly inaccurate compared to real-life physics. Different cars handle quite similar and differ only in their acceleration and top speed characteristics.");
strcpy(menu.items[2].label,"Turbo Arcade");
strcpy(menu.items[2].describtion,"Arcade Mode on steroids.");
strcpy(menu.items[3].label,"Strict");
strcpy(menu.items[3].describtion,"Strict mode is like Simulation mode with modified collision physics to encourage clean racing.");
strcpy(menu.items[menu.numItems-1].label,"Cancel");
menu.items[menu.numItems-2].lineSpacing*=1.5;
menu.imageXScale=kMapImageXStretch;
menu.imageYScale=kMapImageYStretch;
menu.imageXPos+=0.1;
menu.imageYPos-=0.03;
menu.TimerCallback=TimerCallback;
menu.userData=userData;
menu.image=mapInfo->image;
menu.descPos=Vector(-0.9,-0.6);
int sel=InterfaceGetUserMenuSelection(&menu);
InterfaceDisposeMenu(&menu);
return sel==menu.numItems-1||sel==kInterfaceMenuEsc?-1:sel;
}
void InterfaceQuickRace()
{
tGameInfo gInfo;
InitGInfo(&gInfo);
//let user select a map...
if(InterfaceMapSelection(&gInfo,NULL,NULL,false))
{
int raceMode=SelectRaceMode(gInfo.map,NULL,NULL);
if(raceMode==-1)
return;
else
gConfig->arcade=raceMode;
gInfo.arcade=gConfig->arcade;
tFileRef playerCar=gConfig->lastCar;
UInt8 playerColor=gConfig->lastColor;
//...and a car...
if(InterfaceCarSelection(&playerCar,kCarSelectionQuickMode,&playerColor,NULL,NULL,NULL))
{
gConfig->lastCar=playerCar;
gConfig->lastColor=playerColor;
tMapInfo *mapInfo=(tMapInfo*)FileGetParsedDataPtr(gInfo.map,kParserTypeMapInfoDesc,sizeof(tMapInfo));
int numPlayers=mapInfo->maxPlayers;
//...and opponets
if(InterfaceSelectOpponentCars(&numPlayers,gInfo.playerCars+1,gInfo.playerColors+1,NULL,NULL))
{
gInfo.numPlayers=numPlayers+1;
gInfo.playerID=0;
gInfo.playerCars[gInfo.playerID]=playerCar;
gInfo.playerColors[gInfo.playerID]=playerColor;
//and run the game
RunGame(&gInfo);
TeaserScreen();
}
}
}
}
void InterfaceTimeTrial()
{
tGameInfo gInfo;
InitGInfo(&gInfo);
gInfo.numPlayers=1;
gInfo.numLaps=-1;
//let user select a map...
if(InterfaceMapSelection(&gInfo,NULL,NULL,true))
{
int raceMode=SelectRaceMode(gInfo.map,NULL,NULL);
if(raceMode==-1)
return;
else
gConfig->arcade=raceMode;
gInfo.arcade=gConfig->arcade;
//...and a car...
gInfo.playerCars[0]=gConfig->lastCar;
gInfo.playerColors[0]=gConfig->lastColor;
if(InterfaceCarSelection(gInfo.playerCars,kCarSelectionQuickMode,gInfo.playerColors,NULL,NULL,NULL))
{
gConfig->lastCar=gInfo.playerCars[0];
gConfig->lastColor=gInfo.playerColors[0];
gLocalRecord=0;
for(int i=0;i<gConfig->numPersonalRecords;i++)
if(gConfig->records[i].map==gInfo.map&&gConfig->records[i].car==gInfo.playerCars[0]
&&gConfig->records[i].mode==gInfo.arcade&&gConfig->records[i].direction==gInfo.reverse)
gLocalRecord=gConfig->records[i].time;
RunGame(&gInfo);
WriteOutFile(FileGetReference(kConfigFileName),gConfig,kParserTypeConfigDesc);
TeaserScreen();
}
}
}
void InterfaceOptions();
enum{
kButtonQuickRace,
kButtonTimeTrial,
kButtonMultiplayer,
kButtonCareer,
kButtonOptions,
kButtonAbout,
kButtonQuit,
kNumButtons
};
void InterfaceDisplayRegisterName(void *userData,int selection)
{
// TextPrintfToBufferFormated(Vector(1.0,-0.9),0.03,kTextAlignRight,"%s%s",RT3_IsRegistered()?"Registered to: ":"",RT3_GetDisplayName());
TextPrintfToBufferFormated(Vector(1.0,0.95),0.03,kTextAlignRight,kVersionString);
// TextPrintfToBufferFormated(Vector(-1.0,-0.9),0.03,kTextAlignLeft,kVersionString);
}
#define kTopSize 0.141
void InterfaceRenderReplay(void *userData,int selection,void *menu)
{
float *t,v=0;
static int inited=false;
if(userData)
t=((float*)userData);
else
t=&v;
if(gConfig->showReplays)//&&0)
{
gBackgroundReplay=true;
if(!inited)
{
gEnableTextureLoad=false;
gNumTexturesRequested=0;
gClipEnable=false;
RenderFrame(false);
gClipEnable=true;
gNumTexturesLoaded=0;
gEnableTextureLoad=true;
gDisabledRestart=0;
for(int i=0;i<gFileTableSize;i++)
{
if(gFileTable[i].tagged&&!gFileTable[i].parsed)
{
gTexturesQualityModifier=gFileTable[i].tagged+1;
TexturesSelectTex(i);
SystemPoll(false);
glLoadIdentity();
glTranslatef(0.0f,0.0f,-1.0f);
glPushAttrib(GL_DEPTH_BUFFER_BIT+GL_LIGHTING_BIT);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
gTexturesQualityModifier=-255;
TexturesSelectTex(FileGetReference("logo.pct"));
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(kBackgroundXStretch,-kBackgroundYStretch);
glTexCoord2d(1,0); glVertex2f(kBackgroundXStretch,kBackgroundYStretch);
glTexCoord2d(0,1); glVertex2f(-kBackgroundXStretch,-kBackgroundYStretch);
glTexCoord2d(0,0); glVertex2f(-kBackgroundXStretch,kBackgroundYStretch);
glEnd();
ScreenBlit();
glPopAttrib();
}
}
inited=true;
}
ReplayFrame();
if(gSystemSuspended)
PauseGame();
gBackgroundReplay=false;
}
glLoadIdentity();
glTranslatef(0.0f,0.0f,-1.0f);
glPushAttrib(GL_DEPTH_BUFFER_BIT+GL_LIGHTING_BIT+GL_COLOR_BUFFER_BIT+GL_CURRENT_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
gTexturesQualityModifier=-255;
if(menu)
{
if(((tInterfaceMenuDescribtion*)menu)->background!=kFileErr||!gConfig->showReplays)
{
if(((tInterfaceMenuDescribtion*)menu)->background!=kFileErr)
TexturesSelectTex(((tInterfaceMenuDescribtion*)menu)->background);
else
TexturesSelectTex(FileGetReference("background.tif"));
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
if(!gConfig->showReplays)
glDisable(GL_BLEND);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); /*glColor4f(1,1,1,0);*/ glVertex2f(kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glTexCoord2d(1,0); /*glColor4f(1,1,1,0);*/ glVertex2f(kBackgroundXStretch,kBackgroundYStretch);
glTexCoord2d(0,1); /*glColor4f(1,1,1,1);*/ glVertex2f(-kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glTexCoord2d(0,0); /*glColor4f(1,1,1,1);*/ glVertex2f(-kBackgroundXStretch,kBackgroundYStretch);
glEnd();
glEnable(GL_BLEND);
}
if(((tInterfaceMenuDescribtion*)menu)->image!=kFileErr)
{
TexturesSelectTex(((tInterfaceMenuDescribtion*)menu)->image);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glColor4f(1,1,1,((tInterfaceMenuDescribtion*)menu)->imageAlpha);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(((tInterfaceMenuDescribtion*)menu)->imageXPos+((tInterfaceMenuDescribtion*)menu)->imageXScale,((tInterfaceMenuDescribtion*)menu)->imageYPos-((tInterfaceMenuDescribtion*)menu)->imageYScale);
glTexCoord2d(1,0); glVertex2f(((tInterfaceMenuDescribtion*)menu)->imageXPos+((tInterfaceMenuDescribtion*)menu)->imageXScale,((tInterfaceMenuDescribtion*)menu)->imageYPos+((tInterfaceMenuDescribtion*)menu)->imageYScale);
glTexCoord2d(0,1); glVertex2f(((tInterfaceMenuDescribtion*)menu)->imageXPos-((tInterfaceMenuDescribtion*)menu)->imageXScale,((tInterfaceMenuDescribtion*)menu)->imageYPos-((tInterfaceMenuDescribtion*)menu)->imageYScale);
glTexCoord2d(0,0); glVertex2f(((tInterfaceMenuDescribtion*)menu)->imageXPos-((tInterfaceMenuDescribtion*)menu)->imageXScale,((tInterfaceMenuDescribtion*)menu)->imageYPos+((tInterfaceMenuDescribtion*)menu)->imageYScale);
glEnd();
glColor4f(1,1,1,1);
}
TexturesSelectTex(FileGetReference("menustripe.tif"));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f((2)*kScreenXPos, 0.7*kScreenYPos);
glTexCoord2d(1,0); glVertex2f((2)*kScreenXPos, 1.0*kScreenYPos);
glTexCoord2d(0,1); glVertex2f((-2)*kScreenXPos,0.7*kScreenYPos);
glTexCoord2d(0,0); glVertex2f((-2)*kScreenXPos,1.0*kScreenYPos);
glEnd();
glDisable(GL_TEXTURE_2D);
glColor4f(0,0,0,1);
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(-kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glVertex2f(-kBackgroundXStretch,kBackgroundYStretch);
glVertex2f(-2*kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glVertex2f(-2*kBackgroundXStretch,kBackgroundYStretch);
glEnd();
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(2*kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glVertex2f(2*kBackgroundXStretch,kBackgroundYStretch);
glVertex2f(kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glVertex2f(kBackgroundXStretch,kBackgroundYStretch);
glEnd();
glColor4f(1,1,1,1);
glEnable(GL_TEXTURE_2D);
}
else if(!gConfig->showReplays)
{
glDisable(GL_BLEND);
TexturesSelectTex(FileGetReference("background.tif"));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); /*glColor4f(1,1,1,0);*/ glVertex2f(kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glTexCoord2d(1,0); /*glColor4f(1,1,1,0);*/ glVertex2f(kBackgroundXStretch,kBackgroundYStretch);
glTexCoord2d(0,1); /*glColor4f(1,1,1,1);*/ glVertex2f(-kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glTexCoord2d(0,0); /*glColor4f(1,1,1,1);*/ glVertex2f(-kBackgroundXStretch,kBackgroundYStretch);
glEnd();
glEnable(GL_BLEND);
}
if(*t<0)
*t=TimeGetSeconds();
float time=TimeGetSeconds();
float d=1.5-(time-*t)*2;
if(d<0)d=0;
if(userData&&!isinf(*t))
{
TexturesSelectTex(FileGetReference("menulogo.tif"));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f((0.3-d)*kScreenXPos, 0.7*kScreenYPos);
glTexCoord2d(1,0); glVertex2f((0.3-d)*kScreenXPos, 1.0*kScreenYPos);
glTexCoord2d(0,1); glVertex2f((-0.95-d)*kScreenXPos,0.7*kScreenYPos);
glTexCoord2d(0,0); glVertex2f((-0.95-d)*kScreenXPos,1.0*kScreenYPos);
glEnd();
TexturesSelectTex(FileGetReference("logo.pct"));
glColor4f(1,1,1,d);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(kBackgroundXStretch,-kBackgroundYStretch);
glTexCoord2d(1,0); glVertex2f(kBackgroundXStretch,kBackgroundYStretch);
glTexCoord2d(0,1); glVertex2f(-kBackgroundXStretch,-kBackgroundYStretch);
glTexCoord2d(0,0); glVertex2f(-kBackgroundXStretch,kBackgroundYStretch);
glEnd();
TextPrintfToBufferFormated(Vector(1.0,-0.9),0.03,kTextAlignRight,"%s%s",RT3_IsRegistered()?"Registered to: ":"",RT3_GetDisplayName());
TextPrintfToBufferFormated(Vector(1.0,0.88),0.03,kTextAlignRight,kVersionString);
}
gTexturesQualityModifier=0;
glPopAttrib();
}
int InterfaceConfirmQuit()
{
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,2,"Do you really want to quit?");
menu.background=kFileErr;
menu.RenderCallback=InterfaceRenderReplay;
char itemStrings[][32]={"Quit","Cancel"};
menu.items[0].lineSpacing*=1.3;
for(int i=0;i<menu.numItems;i++)
strcpy(menu.items[i].label,itemStrings[i]);
InterfaceMenuZoomAnimation(&menu,-1,true);
int sel=InterfaceGetUserMenuSelection(&menu);
InterfaceDisposeMenu(&menu);
return !sel;
}
void InterfaceReplayMenu()
{
tInterfaceMenuDescribtion menu;
tFileRef logs[kMaxLogs];
int logCount;
GetLogs(logs,&logCount);
InterfaceInitMenu(&menu,logCount,"Choose a replay file to play:");
menu.background=kFileErr;
menu.scrollEnable=true;
menu.RenderCallback=InterfaceRenderReplay;
for(int i=0;i<menu.numItems;i++)
{
strcpy(menu.items[i].label,FileGetName(logs[i]));
menu.items[i].size*=0.7;
menu.items[i].lineSpacing*=0.7;
}
int sel=InterfaceGetUserMenuSelection(&menu);
InterfaceDisposeMenu(&menu);
if(sel!=kInterfaceMenuEsc)
{
if(!LogLoad(logs[sel],&gInterfaceGInfo))
LogLoad(FileGetReference("bullit.redlog"),&gInterfaceGInfo);
gGameEnd=false;
gGameInfo=&gInterfaceGInfo;
StartBackgroundReplay();
gEnableTextureLoad=false;
gNumTexturesRequested=0;
ReplayFrame();
RenderFrame(false);
gNumTexturesLoaded=0;
gEnableTextureLoad=true;
gDisabledRestart=0;
for(int i=0;i<gFileTableSize;i++)
{
if(gFileTable[i].tagged&&!gFileTable[i].parsed)
{
// InterfaceDrawStatusBar("Loading Textures...",gFileTable[i].name,gNumTexturesLoaded/(float)gNumTexturesRequested);
if(gNumTexturesRequested>0)
InterfaceDrawStatusBar("Loading Textures...","Please Wait",gNumTexturesLoaded/(float)gNumTexturesRequested);
TexturesSelectTex(i);
SystemPoll(true);
}
}
StartBackgroundReplay();
gFrameCount=gReplayOldFrameCount;
RunReplay();
SoundSilence();
FlushKeys();
}
}
//run the applications main loop
void InterfaceMainLoop()
{
float userData=-1;
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,kNumButtons+1,"");
menu.numItems=kNumButtons;
char itemStrings[][32]={"Quick Race","Time Trial","Multiplayer","Challenges","Options","About","Quit",""};
for(int i=0;i<menu.numItems+1;i++)
{
strcpy(menu.items[i].label,itemStrings[i]);
menu.items[i].size*=1.25;
menu.items[i].lineSpacing*=1.25;
}
menu.itemsYPos+=0.05;
menu.items[kButtonQuit-1].lineSpacing*=1.5;
menu.easterEggEnable=true;
menu.userData=&userData;
menu.background=kFileErr;
tFileRef logs[kMaxLogs];
int logCount;
GetLogs(logs,&logCount);
if(!LogLoad(logs[RandomInt(0,logCount)],&gInterfaceGInfo))
LogLoad(FileGetReference("bullit.redlog"),&gInterfaceGInfo);
gGameInfo=&gInterfaceGInfo;
StartBackgroundReplay();
menu.RenderCallback=InterfaceRenderReplay;
//menu.RenderCallback=InterfaceDisplayRegisterName;
//menu.image=FileGetReference("logo.pct");
int exit=false;
do{
char *version,*url;
if(TrackerVersionCheck(&version))
{
menu.numItems=kNumButtons+1;
sprintf(menu.items[kButtonQuit].label,"\255#r\255Upgrade to version %s",version);
strcpy(menu.items[kNumButtons].label,itemStrings[kButtonQuit]);
}
InterfaceMenuZoomAnimation(&menu,-1,true);
switch(menu.initialSelection=InterfaceGetUserMenuSelection(&menu))
{
case kButtonQuickRace:
InterfaceQuickRace();
break;
case kButtonTimeTrial:
InterfaceTimeTrial();
break;
case kButtonCareer:
InterfaceChallenge();
break;
case kButtonMultiplayer://let the user start a multiplayer game
InterfaceMultiplayerLobby();
break;
case kButtonOptions://game settings
InterfaceOptions();
break;
case kButtonAbout:
TextScrollFile(FileGetReference("credits.txt"));
break;
case kInterfaceMenuReplayKey:
InterfaceReplayMenu();
break;
case kButtonQuit://leave the main loop
case kInterfaceMenuEsc:
case kNumButtons:
if(menu.initialSelection==menu.numItems-2)
{
TrackerGetNewVersion();
exit=true;
break;
}
if(InterfaceConfirmQuit())
exit=true;
break;
}
}while(!exit);
InterfaceDisposeMenu(&menu);
}

15
source/interface.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef __INTERFACE
#define __INTERFACE
#include "gameinitexit.h"
#define kXStretch 0.5
#define kYStretch 0.3
extern tGameInfo gInterfaceGInfo;
void StartBackgroundReplay();
void InterfaceMainLoop();
void InterfaceInit();
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,20 @@
#ifndef INTERFACEMULTIPLAYER
#define INTERFACEMULTIPLAYER
#include "network.h"
#define kChatBufferMaxSize 256
#define kChatBufferMaxLines 8
typedef struct{
tChatMessage chatBuffer[kChatBufferMaxLines];
int chatBufferLines;
}tChatBuffer;
extern tChatBuffer *gChatBuffer;
extern char gDisconnectString[256];
void ChatBufferInsert(tChatMessage *msg,tChatBuffer *cb);
void InterfaceMultiplayerLobby();
void DirectJoinGame(char *address);
#endif

959
source/interfaceoptions.cpp Normal file
View File

@ -0,0 +1,959 @@
//interfaceoptions.cpp
//user interface for setting game options
#include <OpenGL/gl.h>
#include "gametime.h"
#include <string.h>
#include <stdio.h>
#include "interfaceutil.h"
#include "gamemem.h"
#include "fileio.h"
#include "screen.h"
#include "controls.h"
#include "text.h"
#include "interface.h"
#include "gameinitexit.h"
#include "parser.h"
#include "writeout.h"
#include "textures.h"
#include "config.h"
#include "gamesound.h"
#include "textures.h"
#include "renderframe.h"
#include "music.h"
#define kNumControlOptions 14
void InterfaceControlOptions()
{
int controlOptions[kNumControlOptions]={kInputGasButton,kInputBrakeButton,kInputSteerLeftButton,kInputSteerRightButton,kInputHandbrakeButton,kInputKickdownButton,kInputCamera,kInputCameraReverse,kInputCameraChangeCar,kInputPause,kInputGearUp,kInputGearDown,kInputHorn,kInputChat};
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,kNumControlOptions+1,"Controls");
strcpy(menu.items[kNumControlOptions].label,"Return to previous menu");
menu.items[kNumControlOptions-1].lineSpacing*=1.5;
menu.background=FileGetReference("background-options.tif");
menu.RenderCallback=InterfaceRenderReplay;
menu.itemsYPos+=0.1;
char itemStrings[kNumControlOptions][32]={"Accelerate","Brake","Steer Left","Steer Right","Handbrake","Full Throttle","Change Camera","Look Backwards","Replay Car View","Pause Game","Shift Up","Shift Down","Horn","Type Message"};
for(int i=0;i<kNumControlOptions;i++)
{
menu.items[i].size*=0.7;
menu.items[i].lineSpacing*=0.6;
}
int exit=false;
do{
for(int i=0;i<kNumControlOptions;i++)
{
int keyUsed=false;
int controllerUsed=false;
for(int j=0;j<=kInputITunesPlay;j++)
if(gConfig->keys[controlOptions[i]].keyID==gConfig->keys[j].keyID&&j!=controlOptions[i])
keyUsed=true;
for(int j=0;j<=kInputITunesPlay;j++)
if(gConfig->keys[controlOptions[i]].controllerID1==gConfig->keys[j].controllerID1
&&gConfig->keys[controlOptions[i]].controllerID2==gConfig->keys[j].controllerID2
&&gConfig->keys[controlOptions[i]].elementID==gConfig->keys[j].elementID
&&j!=controlOptions[i])
controllerUsed=true;
if(gConfig->keys[controlOptions[i]].controllerID1)
{
if(keyUsed&&controllerUsed)
sprintf(menu.items[i].label,"%s:\255#r\255\t%s\t%s",itemStrings[i],gConfig->keys[controlOptions[i]].identifier,gConfig->keys[controlOptions[i]].controllerIdentifier);
else if(keyUsed)
sprintf(menu.items[i].label,"%s:\255#r\255\t%s\t\255#a\255%s",itemStrings[i],gConfig->keys[controlOptions[i]].identifier,gConfig->keys[controlOptions[i]].controllerIdentifier);
else if(controllerUsed)
sprintf(menu.items[i].label,"%s:\255#a\255\t%s\t\255#r\255%s",itemStrings[i],gConfig->keys[controlOptions[i]].identifier,gConfig->keys[controlOptions[i]].controllerIdentifier);
else
sprintf(menu.items[i].label,"%s:\255#a\255\t%s\t%s",itemStrings[i],gConfig->keys[controlOptions[i]].identifier,gConfig->keys[controlOptions[i]].controllerIdentifier);
}
else if(keyUsed)
sprintf(menu.items[i].label,"%s:\255#r\255\t%s",itemStrings[i],gConfig->keys[controlOptions[i]].identifier);
else
sprintf(menu.items[i].label,"%s:\255#a\255\t%s",itemStrings[i],gConfig->keys[controlOptions[i]].identifier);
}
InterfaceMenuZoomAnimation(&menu,-1,true);
int sel=InterfaceGetUserMenuSelection(&menu);
if(sel!=kInterfaceMenuEsc&&sel<kNumControlOptions)
{
while(GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter));
menu.initialSelection=sel;
char keyString[80];
sprintf(keyString,"Press the new Key or Button for '%s'\n (Or press delete to clear)",itemStrings[sel]);
InterfaceDrawStrings("Assign new Key",keyString,kFileErr);
GetInput(gConfig->keys+controlOptions[sel]);
int interfaceKeyPressed;
do{
interfaceKeyPressed=false;
for(int i=kInterfaceKeyUp;i<kInterfaceNumKeys;i++)
if(GetInterfaceKey(i))
interfaceKeyPressed=true;
if(GetButtonInput(kInputITunesNext)||GetButtonInput(kInputITunesPlay))
interfaceKeyPressed=true;
}while(interfaceKeyPressed);
}
else
exit=true;
}while(!exit);
InterfaceDisposeMenu(&menu);
}
#define kNumTauntOptions 10
void InterfaceTauntOptions()
{
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,kNumTauntOptions+1,"Taunts");
strcpy(menu.items[kNumTauntOptions].label,"Return to previous menu");
menu.items[kNumTauntOptions-1].lineSpacing*=1.5;
menu.background=FileGetReference("background-options.tif");
menu.RenderCallback=InterfaceRenderReplay;
char itemStrings[5][32];
for(int i=0;i<kNumTauntOptions;i++)
{
menu.items[i].size*=0.75;
if(i%2)
{
menu.items[i].lineSpacing*=0.9;
menu.items[i].flags|=kInterfaceMenuItemTypeable;
strcpy(menu.items[i].type,gConfig->taunts[i/2]);
sprintf(menu.items[i].label,"Taunt %d message: ",i/2+1);
}
else
{
menu.items[i].lineSpacing*=0.65;
sprintf(itemStrings[i/2],"Taunt %d key",i/2+1);
}
}
int exit=false;
do{
for(int i=0;i<kNumTauntOptions;i++)
if(!(i%2))
{
int keyUsed=false;
int controllerUsed=false;
for(int j=0;j<=kInputITunesPlay;j++)
if(gConfig->keys[kInputTaunt1+i/2].keyID==gConfig->keys[j].keyID&&j!=kInputTaunt1+i/2)
keyUsed=true;
for(int j=0;j<=kInputITunesPlay;j++)
if(gConfig->keys[kInputTaunt1+i/2].controllerID1==gConfig->keys[j].controllerID1
&&gConfig->keys[kInputTaunt1+i/2].controllerID2==gConfig->keys[j].controllerID2
&&gConfig->keys[kInputTaunt1+i/2].elementID==gConfig->keys[j].elementID
&&j!=kInputTaunt1+i/2)
controllerUsed=true;
if(gConfig->keys[kInputTaunt1+i/2].controllerID1)
{
if(keyUsed&&controllerUsed)
sprintf(menu.items[i].label,"%s:\255#r\255\t%s\t%s",itemStrings[i/2],gConfig->keys[kInputTaunt1+i/2].identifier,gConfig->keys[kInputTaunt1+i/2].controllerIdentifier);
else if(keyUsed)
sprintf(menu.items[i].label,"%s:\255#r\255\t%s\t\255#a\255%s",itemStrings[i/2],gConfig->keys[kInputTaunt1+i/2].identifier,gConfig->keys[kInputTaunt1+i/2].controllerIdentifier);
else if(controllerUsed)
sprintf(menu.items[i].label,"%s:\255#a\255\t%s\t\255#r\255%s",itemStrings[i/2],gConfig->keys[kInputTaunt1+i/2].identifier,gConfig->keys[kInputTaunt1+i/2].controllerIdentifier);
else
sprintf(menu.items[i].label,"%s:\255#a\255\t%s\t%s",itemStrings[i/2],gConfig->keys[kInputTaunt1+i/2].identifier,gConfig->keys[kInputTaunt1+i/2].controllerIdentifier);
}
else if(keyUsed)
sprintf(menu.items[i].label,"%s:\255#r\255\t%s",itemStrings[i/2],gConfig->keys[kInputTaunt1+i/2].identifier);
else
sprintf(menu.items[i].label,"%s:\255#a\255\t%s",itemStrings[i/2],gConfig->keys[kInputTaunt1+i/2].identifier);
}
InterfaceMenuZoomAnimation(&menu,-1,true);
int sel=InterfaceGetUserMenuSelection(&menu);
if(sel!=kInterfaceMenuEsc&&sel<kNumTauntOptions&&!(sel%2))
{
while(GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter));
menu.initialSelection=sel;
char keyString[80];
sprintf(keyString,"Press the new Key or Button for '%s'",itemStrings[sel/2]);
InterfaceDrawStrings("Assign new Key",keyString,kFileErr);
GetInput(gConfig->keys+kInputTaunt1+sel/2);
int interfaceKeyPressed;
do{
interfaceKeyPressed=false;
for(int i=kInterfaceKeyUp;i<kInterfaceNumKeys;i++)
if(GetInterfaceKey(i))
interfaceKeyPressed=true;
}while(interfaceKeyPressed);
}
else
exit=true;
}while(!exit);
for(int i=1;i<kNumTauntOptions;i+=2)
strcpy(gConfig->taunts[i/2],menu.items[i].type);
InterfaceDisposeMenu(&menu);
}
void InterfaceCalibrateAxis()
{
if(gConfig->axis[kInputSteerAxis].axisControllerID1>0)
{
InterfaceDrawStrings("Calibrate Axis","Move the Steering Axis to its left and right \nmaximum several times and hit Return.",kFileErr);
CalibrateAxis(kInputSteerAxis);
}
if(!gConfig->seperateGasBrake)
if(gConfig->axis[kInputThrottleBrakeAxis].axisControllerID1>0)
{
InterfaceDrawStrings("Calibrate Axis","Move the Gas/Brake Axis to its left and right \nmaximum several times and hit Return.",kFileErr);
CalibrateAxis(kInputThrottleBrakeAxis);
}
FlushKeys();
}
enum{
kAnalougeSteerAxis,
kAnalougeGasSeperateAxes,
kAnalougeInvertGas,
kAnalougeGasAxis,
kAnalougeBrakeAxis,
kAnalougeDisableTCS,
kAnalougeCalibrate,
kAnalougeSteerCenterTolerance,
kAnalougeGasCenterTolerance,
kAnalougeFFB,
kAnalougeFFBIntensity,
kAnalougeExit,
kAnalougeNumOptions
};
void InterfaceAnalogueControlOptions()
{
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,kAnalougeNumOptions,"Analog Controls");
menu.background=FileGetReference("background-options.tif");
menu.RenderCallback=InterfaceRenderReplay;
char itemStrings[][32]={"Steering","Seperate Gas/Brake:","Invert Gas/Brake axes","Gas","Brake","Traction Assistance","Calibrate Axis...","Steering Tolerance:","Gas Tolerance:","","FFB Intensity:","Return to previous menu"};
for(int i=0;i<kAnalougeNumOptions;i++)
sprintf(menu.items[i].label,"%s",itemStrings[i]);
menu.items[kAnalougeFFB].flags|=kInterfaceMenuItemArrowInput;
menu.items[kAnalougeInvertGas].flags|=kInterfaceMenuItemArrowInput;
menu.items[kAnalougeGasSeperateAxes].flags|=kInterfaceMenuItemArrowInput;
menu.items[kAnalougeDisableTCS].flags|=kInterfaceMenuItemArrowInput;
menu.items[kAnalougeFFBIntensity].flags|=kInterfaceMenuItemArrowInput|kInterfaceMenuItemSlider;
menu.items[kAnalougeSteerCenterTolerance].flags|=kInterfaceMenuItemArrowInput|kInterfaceMenuItemSlider;
menu.items[kAnalougeGasCenterTolerance].flags|=kInterfaceMenuItemArrowInput|kInterfaceMenuItemSlider;
if(!gFFB)
{
menu.items[kAnalougeFFB].flags|=kInterfaceMenuItemDisabled;
menu.items[kAnalougeFFBIntensity].flags|=kInterfaceMenuItemDisabled;
}
if(!gInputHID)
menu.items[kAnalougeCalibrate].flags|=kInterfaceMenuItemDisabled;
menu.items[kAnalougeExit-1].lineSpacing*=1.5;
for(int i=0;i<kAnalougeExit;i++)
{
menu.items[i].size*=0.75;
menu.items[i].lineSpacing*=0.75;
}
int exit=false;
do{
if(gConfig->axis[kInputSteerAxis].axisControllerID1)
sprintf(menu.items[kAnalougeSteerAxis].label,"%s: \255#a\255%s",itemStrings[kAnalougeSteerAxis],gConfig->axis[kInputSteerAxis].axisIdentifier);
else
sprintf(menu.items[kAnalougeSteerAxis].label,"%s: \255#a\255not assigned",itemStrings[kAnalougeSteerAxis]);
if(gConfig->seperateGasBrake)
{
if(gConfig->axis[kInputThrottleAxis].axisControllerID1)
sprintf(menu.items[kAnalougeGasAxis].label,"%s: \255#a\255%s","Gas",gConfig->axis[kInputThrottleAxis].axisIdentifier);
else
sprintf(menu.items[kAnalougeGasAxis].label,"%s: \255#a\255not assigned","Gas");
if(gConfig->axis[kInputBrakeAxis].axisControllerID1)
sprintf(menu.items[kAnalougeBrakeAxis].label,"%s: \255#a\255%s","Brake",gConfig->axis[kInputBrakeAxis].axisIdentifier);
else
sprintf(menu.items[kAnalougeBrakeAxis].label,"%s: \255#a\255not assigned","Brake");
} else {
if(gConfig->axis[kInputThrottleBrakeAxis].axisControllerID1)
sprintf(menu.items[kAnalougeGasAxis].label,"%s: \255#a\255%s","Gas/Brake",gConfig->axis[kInputThrottleBrakeAxis].axisIdentifier);
else
sprintf(menu.items[kAnalougeGasAxis].label,"%s: \255#a\255not assigned","Gas/Brake");
sprintf(menu.items[kAnalougeBrakeAxis].label,"%s: \255#a\255not applicable","Brake");
}
sprintf(menu.items[kAnalougeFFB].label,"Force Feedback: \255#a\255%s",gConfig->ffb?"On":"Off");
sprintf(menu.items[kAnalougeInvertGas].label,"Invert Gas/Brake axes: \255#a\255%s",gConfig->reverseGas?"On":"Off");
sprintf(menu.items[kAnalougeDisableTCS].label,"Traction Assistance: \255#a\255%s",gConfig->disableAnalogueTCS?"Off":"On");
sprintf(menu.items[kAnalougeGasSeperateAxes].label,"Seperate Gas/Brake: \255#a\255%s",gConfig->seperateGasBrake?"On":"Off");
if(gConfig->seperateGasBrake)
menu.items[kAnalougeBrakeAxis].flags&=~kInterfaceMenuItemDisabled;
else
menu.items[kAnalougeBrakeAxis].flags|=kInterfaceMenuItemDisabled;
menu.items[kAnalougeFFBIntensity].sliderPos=gConfig->ffbIntensity;
menu.items[kAnalougeSteerCenterTolerance].sliderPos=gConfig->axis[0].deadzone*5.0;
menu.items[kAnalougeGasCenterTolerance].sliderPos=gConfig->axis[1].deadzone*5.0;
if(gInputHID&&(gConfig->axis[kInputThrottleBrakeAxis].axisControllerID1||gConfig->axis[kInputSteerAxis].axisControllerID1))
menu.items[kAnalougeCalibrate].flags&=~kInterfaceMenuItemDisabled;
else
menu.items[kAnalougeCalibrate].flags|=kInterfaceMenuItemDisabled;
int sel=InterfaceGetUserMenuSelection(&menu);
menu.initialSelection=sel&kInterfaceMenuItemMask;
switch(menu.initialSelection)
{
case kAnalougeSteerAxis:
case kAnalougeGasAxis:
case kAnalougeBrakeAxis:
while(GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter));
menu.initialSelection=sel;
char keyString[80];
switch(menu.initialSelection)
{
case kAnalougeSteerAxis:
sprintf(keyString,"Move the new axis for '%s'","Steering");
InterfaceDrawStrings("Assign new Axis",keyString,kFileErr);
GetAxis(gConfig->axis+kInputSteerAxis,false);
break;
case kAnalougeGasAxis:
if(!gConfig->seperateGasBrake)
{
sprintf(keyString,"Move the new axis for '%s'","Gas/Brake");
InterfaceDrawStrings("Assign new Axis",keyString,kFileErr);
GetAxis(gConfig->axis+kInputThrottleBrakeAxis,false);
}
else
{
sprintf(keyString,"Move the new axis for '%s'","Gas");
InterfaceDrawStrings("Assign new Axis",keyString,kFileErr);
GetAxis(gConfig->axis+kInputThrottleAxis,true);
}
break;
case kAnalougeBrakeAxis:
sprintf(keyString,"Move the new axis for '%s'","Brake");
InterfaceDrawStrings("Assign new Axis",keyString,kFileErr);
GetAxis(gConfig->axis+kInputBrakeAxis,true);
break;
}
InterfaceMenuZoomAnimation(&menu,-1,true);
break;
case kAnalougeGasSeperateAxes:
gConfig->seperateGasBrake=!gConfig->seperateGasBrake;
break;
case kAnalougeInvertGas:
gConfig->reverseGas=!gConfig->reverseGas;
break;
case kAnalougeCalibrate:
InterfaceCalibrateAxis();
InterfaceMenuZoomAnimation(&menu,-1,true);
break;
case kAnalougeFFB:
gConfig->ffb=!gConfig->ffb;
break;
case kAnalougeDisableTCS:
gConfig->disableAnalogueTCS=!gConfig->disableAnalogueTCS;
break;
case kAnalougeFFBIntensity:
if(sel&kInterfaceMenuLeftArrow){
gConfig->ffbIntensity-=0.05;
if(gConfig->ffbIntensity<0)gConfig->ffbIntensity=0;
}
else{
gConfig->ffbIntensity+=0.05;
if(gConfig->ffbIntensity>1.0)gConfig->ffbIntensity=1.0;
}
break;
case kAnalougeSteerCenterTolerance:
if(sel&kInterfaceMenuLeftArrow){
gConfig->axis[0].deadzone-=0.01;
if(gConfig->axis[0].deadzone<0)gConfig->axis[0].deadzone=0;
}
else{
gConfig->axis[0].deadzone+=0.01;
if(gConfig->axis[0].deadzone>0.2)gConfig->axis[0].deadzone=0.2;
}
break;
case kAnalougeGasCenterTolerance:
if(sel&kInterfaceMenuLeftArrow){
gConfig->axis[1].deadzone-=0.01;
if(gConfig->axis[1].deadzone<0)gConfig->axis[1].deadzone=0;
}
else{
gConfig->axis[1].deadzone+=0.01;
if(gConfig->axis[1].deadzone>0.2)gConfig->axis[1].deadzone=0.2;
}
break;
default:
exit=true;
}
}while(!exit);
gConfig->axis[2].deadzone=gConfig->axis[1].deadzone;
gConfig->axis[3].deadzone=gConfig->axis[1].deadzone;
InterfaceDisposeMenu(&menu);
}
enum{
kVideoOptionScreenSize,
kVideoOptionFullscreen,
kVideoOptionShadows,
kVideoOptionTextureFilter,
kVideoOptionTextureQuality,
// kVideoOptionClipDistance,
kVideoOptionInteriorDisplay,
kVideoOptionColor32Bit,
kVideoOptionFSAA,
kVideoOptionMotionBlur,
kVideoOptionsShowReplays,
//kVideoOptionsFPS,
kVideoOptionReturn,
kNumVideoOptions
};
#define kMaxTextureQuality 9
#define kMinTextureQuality 0
void InterfaceVideoOptions()
{
int screenReInitRequired=false;
int textureReLoadRequired=false;
int glReInitRequired=false;
int videoMode=0;
for(int i=0;i<gVideoNumModes;i++)
if(gConfig->screenXSize==gVideoModes[i].width&&gConfig->screenYSize==gVideoModes[i].height)
videoMode=i;
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,kNumVideoOptions,"Video Options");
menu.background=FileGetReference("background-options.tif");
menu.RenderCallback=InterfaceRenderReplay;
char itemStrings[][256]={"Set the display resolution for Redline to use. Larger values means sharper graphics, but may slow the game down.",
"Switch between fullscreen and windowed modes. You can also switch at any time by pressing Command-F.",
"Turn shadows and light cones on or off. If you can't get Redline to run smooth on your machine, try disabling shadows.",
"Changes texture filter. Anisotropic filtering results in the smoothest graphics, Bilinear filtering is the fastest.",
"Changes the texture quality. Higher quality means sharper graphics, but may cause the game to run too slow, if your graphics card doesn't have enough memory.",
// "Changes the visible display range. Higher values let you see farther, but will cause the game to run slower.",
"Turns car interor display on or off. Turning interior display off will let the game run faster.",
"Changes between 16-bit and 32-bit color modes. 32-bit looks much nicer, but may be slower on older graphics cards.",
"Turns on Full screen Anti-Aliasing. Will cause the game to look smoother, but may cause slowdowns.",
"Turns motion blur on or off (Arcade modes only). Enabling this may cause severe slowdowns on older hardware.",
"Play replays of Races behind the menu screens. May slow down menu responsiveness on older systems.",
// "Display a frames-per-second counter in your HUD, to indicate how fast the graphics are rendering.",
""
};
for(int i=0;i<menu.numItems;i++)
strcpy(menu.items[i].describtion,itemStrings[i]);
strcpy(menu.items[kVideoOptionReturn].label,"Return to previous menu");
menu.items[kVideoOptionReturn-1].lineSpacing*=1.5;
for(int i=kVideoOptionScreenSize;i<=kVideoOptionsShowReplays;i++)
menu.items[i].flags|=kInterfaceMenuItemArrowInput;
// menu.items[kVideoOptionClipDistance].flags|=kInterfaceMenuItemSlider;
// strcpy(menu.items[kVideoOptionClipDistance].label,"Clipping Distance:");
menu.items[kVideoOptionTextureQuality].flags|=kInterfaceMenuItemSlider;
strcpy(menu.items[kVideoOptionTextureQuality].label,"Texture Quality:");
menu.enterAlwaysOK=true;
for(int i=0;i<kVideoOptionReturn;i++)
{
menu.items[i].size*=0.75;
menu.items[i].lineSpacing*=0.75;
}
if(gConfig->textureQuality<kMinTextureQuality)
gConfig->textureQuality=kMinTextureQuality;
if(gConfig->textureQuality>kMaxTextureQuality)
gConfig->textureQuality=kMaxTextureQuality;
if(ScreenNoWindow())
menu.items[kVideoOptionFullscreen].flags|=kInterfaceMenuItemDisabled;
int exit=false;
int zoom=false;
do{
sprintf(menu.items[kVideoOptionScreenSize].label,"Screen Size: \255#a\255%dx%d",gVideoModes[videoMode].width,gVideoModes[videoMode].height);
sprintf(menu.items[kVideoOptionFullscreen].label,"Screen Mode: \255#a\255%s",gConfig->fullscreen?"Fullscreen":"Window");
switch(gConfig->textureFilter){
case 0: strcpy(menu.items[kVideoOptionTextureFilter].label,"Texture Filter: \255#a\255Bilinear");break;
case 1: strcpy(menu.items[kVideoOptionTextureFilter].label,"Texture Filter: \255#a\255Trilinear");break;
case 2: strcpy(menu.items[kVideoOptionTextureFilter].label,"Texture Filter: \255#a\255Anisotropic");break;
}
switch(gConfig->fsaa){
case 0: strcpy(menu.items[kVideoOptionFSAA].label,"Anti-Aliasing: \255#a\255Off");break;
case 2: strcpy(menu.items[kVideoOptionFSAA].label,"Anti-Aliasing: \255#a\255Medium");break;
case 4: strcpy(menu.items[kVideoOptionFSAA].label,"Anti-Aliasing: \255#a\255Full");break;
}
sprintf(menu.items[kVideoOptionShadows].label,"Shadows & Lighting: \255#a\255%s",gConfig->stencil?"On":"Off");
sprintf(menu.items[kVideoOptionMotionBlur].label,"Motion Blur: \255#a\255%s",gConfig->motionBlur?"On":"Off");
sprintf(menu.items[kVideoOptionInteriorDisplay].label,"Interior Display: \255#a\255%s",gConfig->interiorDisplay?"On":"Off");
// menu.items[kVideoOptionClipDistance].sliderPos=(gConfig->clipFarDistance-160)/640.0;
menu.items[kVideoOptionTextureQuality].sliderPos=1-((float)gConfig->textureQuality-kMinTextureQuality)/(kMaxTextureQuality-kMinTextureQuality);
sprintf(menu.items[kVideoOptionColor32Bit].label,"Color Depth: \255#a\255%d",gConfig->color32Bit?32:16);
sprintf(menu.items[kVideoOptionsShowReplays].label,"Play Background Replays: \255#a\255%s",gConfig->showReplays?"On":"Off");
// sprintf(menu.items[kVideoOptionsFPS].label,"Show FPS counter: \255#a\255%s",gConfig->performanceStats?"On":"Off");
if(!zoom){
InterfaceMenuZoomAnimation(&menu,-1,true);
zoom=true;
}
int sel=InterfaceGetUserMenuSelection(&menu);
switch(menu.initialSelection=(sel&kInterfaceMenuItemMask))
{
case kVideoOptionScreenSize:
if(sel&kInterfaceMenuLeftArrow)
videoMode=(videoMode+1)%gVideoNumModes;
else{
videoMode--;
if(videoMode<0)videoMode=gVideoNumModes-1;
}
screenReInitRequired=true;
break;
case kVideoOptionFullscreen:
gConfig->fullscreen=!gConfig->fullscreen;
screenReInitRequired=true;
break;
case kVideoOptionShadows:
gConfig->stencil=!gConfig->stencil;
break;
case kVideoOptionMotionBlur:
gConfig->motionBlur=!gConfig->motionBlur;
break;
case kVideoOptionTextureQuality:
if(!(sel&kInterfaceMenuLeftArrow)){
if(gConfig->textureQuality>kMinTextureQuality)
gConfig->textureQuality--;
}
else{
if(gConfig->textureQuality<kMaxTextureQuality)
gConfig->textureQuality++;
}
textureReLoadRequired=true;
break;
case kVideoOptionTextureFilter:
if(!(sel&kInterfaceMenuLeftArrow)){
gConfig->textureFilter++;
if(gConfig->textureFilter>(ScreenSupportsAnisotropicFiltering()?2:1))
gConfig->textureFilter=0;
}
else{
gConfig->textureFilter--;
if(gConfig->textureFilter<0)
gConfig->textureFilter=ScreenSupportsAnisotropicFiltering()?2:1;
}
textureReLoadRequired=true;
break;
/* case kVideoOptionClipDistance:
if(sel&kInterfaceMenuLeftArrow){
if(gConfig->clipFarDistance>160)
gConfig->clipFarDistance-=20;
}
else{
if(gConfig->clipFarDistance<800)
gConfig->clipFarDistance+=20;
}
glReInitRequired=true;
break;*/
case kVideoOptionInteriorDisplay:
gConfig->interiorDisplay=!gConfig->interiorDisplay;
break;
case kVideoOptionColor32Bit:
gConfig->color32Bit=!gConfig->color32Bit;
screenReInitRequired=true;
textureReLoadRequired=true;
break;
case kVideoOptionFSAA:
if(sel&kInterfaceMenuLeftArrow){
gConfig->fsaa-=2;
if(gConfig->fsaa<0)gConfig->fsaa=4;
}
else
gConfig->fsaa=(gConfig->fsaa+2)%6;
screenReInitRequired=true;
break;
case kVideoOptionsShowReplays:
gConfig->showReplays=!gConfig->showReplays;
break;
// case kVideoOptionsFPS:
// gConfig->performanceStats=!gConfig->performanceStats;
// break;
case kVideoOptionReturn:
case kInterfaceMenuEsc:
case kInterfaceMenuOK:
exit=true;
break;
}
}while(!exit);
gConfig->screenXSize=gVideoModes[videoMode].width;
gConfig->screenYSize=gVideoModes[videoMode].height;
if(textureReLoadRequired)
TexturesUnloadAll();
if(screenReInitRequired)
ScreenReInit();
else
{
if(glReInitRequired)
InitGL();
}
InterfaceDisposeMenu(&menu);
}
enum{
kGameplayOptionsMetric,
kGameplayOptionsAutomatic,
kGameplayOptionsCamera,
kGameplayOptionsTransparency,
kGameplayOptionsName,
kGameplayOptionsRegisterLapTimes,
kGameplayOptionsShowPlayerNames,
kGameplayOptionsCornerGuides,
kGameplayOptionsHugeGames,
kGameplayOptionsGhost,
kGameplayOptionsReturn,
kNumGameplayOptionsButtons
};
void InterfaceGameplayOptions()
{
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,kNumGameplayOptionsButtons,"Gameplay Options");
char itemStrings[][256]={"Switches the game to use either metric or imperial units for speed, power, mass, etc.",
"Switches between automatic or manual gear switching.",
"Switches the default camera mode.",
"Changes the transparency of in-game displays.",
"Lets you change your name used in network games and the internet track records.",
"If you enable this option, your lap times in Time Trial and Challenge modes will be submitted to the internet track record database.",
"If you enable this, player names will be displayed above the cars in network games.",
"Show guiding signs informing you about upcoming corners.",
"Allow races with up to 12 cars. \255#r\255A fast computer and a fast network connection (for multiplayer) are needed for a good gaming experience.",
"Show a ghost car in Time Trial mode, indicating your best lap.",
""
};
for(int i=0;i<menu.numItems;i++)
strcpy(menu.items[i].describtion,itemStrings[i]);
strcpy(menu.items[kGameplayOptionsReturn].label,"Return to previous menu");
menu.items[kGameplayOptionsReturn-1].lineSpacing*=1.5;
menu.items[kGameplayOptionsMetric].flags|=kInterfaceMenuItemArrowInput;
menu.items[kGameplayOptionsAutomatic].flags|=kInterfaceMenuItemArrowInput;
menu.items[kGameplayOptionsCamera].flags|=kInterfaceMenuItemArrowInput;
menu.items[kGameplayOptionsRegisterLapTimes].flags|=kInterfaceMenuItemArrowInput;
menu.items[kGameplayOptionsShowPlayerNames].flags|=kInterfaceMenuItemArrowInput;
menu.items[kGameplayOptionsCornerGuides].flags|=kInterfaceMenuItemArrowInput;
menu.items[kGameplayOptionsHugeGames].flags|=kInterfaceMenuItemArrowInput;
menu.items[kGameplayOptionsGhost].flags|=kInterfaceMenuItemArrowInput;
menu.items[kGameplayOptionsTransparency].flags|=kInterfaceMenuItemArrowInput|kInterfaceMenuItemSlider;
strcpy(menu.items[kGameplayOptionsTransparency].label,"HUD Transparency:");
menu.items[kGameplayOptionsName].flags|=kInterfaceMenuItemTypeable;
menu.items[kGameplayOptionsName].maxTypeLength=kMaxNameLength-1;
strcpy(menu.items[kGameplayOptionsName].label,"Network Name: ");
strcpy(menu.items[kGameplayOptionsName].type,gConfig->playerName);
menu.background=FileGetReference("background-options.tif");
menu.RenderCallback=InterfaceRenderReplay;
menu.enterAlwaysOK=true;
for(int i=0;i<kGameplayOptionsReturn;i++)
{
menu.items[i].size*=0.75;
menu.items[i].lineSpacing*=0.75;
}
int exit=false;
int zoom=false;
do{
sprintf(menu.items[kGameplayOptionsMetric].label,"Units: \255#a\255%s",gConfig->metricUnits?"Metric":"Imperial");
sprintf(menu.items[kGameplayOptionsAutomatic].label,"Transmission: \255#a\255%s",gConfig->automatic?"Automatic":"Manual");
sprintf(menu.items[kGameplayOptionsRegisterLapTimes].label,"Internet Lap Time Registering: \255#a\255%s",gConfig->registerLapTimes?"On":"Off");
sprintf(menu.items[kGameplayOptionsCornerGuides].label,"Show Corner Guides: \255#a\255%s",gConfig->guideSigns?"On":"Off");
sprintf(menu.items[kGameplayOptionsHugeGames].label,"Allow big races: \255#a\255%s",gConfig->allowHugeGames?"On":"Off");
sprintf(menu.items[kGameplayOptionsGhost].label,"Show ghost car: \255#a\255%s",!gConfig->noGhost?"On":"Off");
sprintf(menu.items[kGameplayOptionsShowPlayerNames].label,"Show Network Player Names: \255#a\255%s",gConfig->showPlayerNames?"On":"Off");
switch(gConfig->cameraMode)
{
case kCameraChase:
sprintf(menu.items[kGameplayOptionsCamera].label,"Default Camera: \255#a\255Chase");break;
case kCameraChaseClose:
sprintf(menu.items[kGameplayOptionsCamera].label,"Default Camera: \255#a\255Close Chase");break;
case kCameraCockpit:
sprintf(menu.items[kGameplayOptionsCamera].label,"Default Camera: \255#a\255Cockpit");break;
case kCameraCockpitCarHidden:
sprintf(menu.items[kGameplayOptionsCamera].label,"Default Camera: \255#a\255Cockpit");break;
}
menu.items[kGameplayOptionsTransparency].sliderPos=gConfig->hudTransparency*1/0.8;
menu.items[kGameplayOptionsTransparency].sliderTransparency=gConfig->hudTransparency;
if(!zoom){
InterfaceMenuZoomAnimation(&menu,-1,true);
zoom=true;
}
int sel=InterfaceGetUserMenuSelection(&menu);
switch(menu.initialSelection=(sel&kInterfaceMenuItemMask))
{
case kGameplayOptionsGhost:
gConfig->noGhost=!gConfig->noGhost;
break;
case kGameplayOptionsHugeGames:
gConfig->allowHugeGames=!gConfig->allowHugeGames;
break;
case kGameplayOptionsMetric:
gConfig->metricUnits=!gConfig->metricUnits;
break;
case kGameplayOptionsRegisterLapTimes:
gConfig->registerLapTimes=!gConfig->registerLapTimes;
break;
case kGameplayOptionsCornerGuides:
gConfig->guideSigns=!gConfig->guideSigns;
break;
case kGameplayOptionsAutomatic:
gConfig->automatic=!gConfig->automatic;
break;
case kGameplayOptionsCamera:
if(sel&kInterfaceMenuLeftArrow){
gConfig->cameraMode--;
if(gConfig->cameraMode<kCameraChase)gConfig->cameraMode=kCameraCockpitCarHidden;
}
else{
gConfig->cameraMode++;
if(gConfig->cameraMode>kCameraCockpitCarHidden)gConfig->cameraMode=kCameraChase;
}
break;
case kGameplayOptionsTransparency:
if(sel&kInterfaceMenuLeftArrow){
gConfig->hudTransparency-=0.05;
if(gConfig->hudTransparency<0)gConfig->hudTransparency=0;
}
else{
gConfig->hudTransparency+=0.05;
if(gConfig->hudTransparency>0.8)gConfig->hudTransparency=0.8;
}
break;
case kGameplayOptionsShowPlayerNames:
gConfig->showPlayerNames=!gConfig->showPlayerNames;
break;
case kGameplayOptionsReturn:
case kInterfaceMenuEsc:
case kInterfaceMenuOK:
exit=true;
break;
}
}while(!exit);
strcpy(gConfig->playerName,menu.items[kGameplayOptionsName].type);
InterfaceDisposeMenu(&menu);
}
enum{
kAudioOptionsVolume,
kAudioOptionsInterfaceSounds,
kAudioOptionsInputITunesNext,
kAudioOptionsInputITunesPrev,
kAudioOptionsInputITunesPlay,
kAudioOptionsReturn,
kNumAudioOptionsButtons
};
void InterfaceAudioOptions()
{
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,kNumAudioOptionsButtons,"Audio Options");
char itemStrings[][256]={"Volume:",
"Interface Sounds:",
"iTunes next song key",
"iTunes previous song key",
"iTunes play/pause key",
"Return to previous menu",
""
};
for(int i=0;i<menu.numItems;i++)
strcpy(menu.items[i].label,itemStrings[i]);
menu.items[kAudioOptionsReturn-1].lineSpacing*=1.5;
menu.items[kAudioOptionsVolume].flags|=kInterfaceMenuItemArrowInput|kInterfaceMenuItemSlider;
menu.items[kAudioOptionsInterfaceSounds].flags|=kInterfaceMenuItemArrowInput;
int exit=false;
for(int i=0;i<kAudioOptionsReturn;i++)
{
menu.items[i].size*=0.75;
menu.items[i].lineSpacing*=0.75;
}
menu.background=FileGetReference("background-options.tif");
menu.RenderCallback=InterfaceRenderReplay;
for(int i=kAudioOptionsInputITunesNext;i<=kAudioOptionsInputITunesPlay;i++)
if(gConfig->keys[kInputITunesNext+i-kAudioOptionsInputITunesNext].controllerID1)
sprintf(menu.items[i].label,"%s:\255#a\255\t%s\t%s",itemStrings[i],gConfig->keys[kInputITunesNext+i-kAudioOptionsInputITunesNext].identifier,gConfig->keys[kInputITunesNext+i-kAudioOptionsInputITunesNext].controllerIdentifier);
else
sprintf(menu.items[i].label,"%s:\255#a\255\t%s",itemStrings[i],gConfig->keys[kInputITunesNext+i-kAudioOptionsInputITunesNext].identifier);
menu.items[kAudioOptionsVolume].sliderPos=gConfig->soundVolume;
InterfaceMenuZoomAnimation(&menu,-1,true);
do{
for(int i=kAudioOptionsInputITunesNext;i<=kAudioOptionsInputITunesPlay;i++)
if(gConfig->keys[kInputITunesNext+i-kAudioOptionsInputITunesNext].controllerID1)
sprintf(menu.items[i].label,"%s:\255#a\255\t%s\t%s",itemStrings[i],gConfig->keys[kInputITunesNext+i-kAudioOptionsInputITunesNext].identifier,gConfig->keys[kInputITunesNext+i-kAudioOptionsInputITunesNext].controllerIdentifier);
else
sprintf(menu.items[i].label,"%s:\255#a\255\t%s",itemStrings[i],gConfig->keys[kInputITunesNext+i-kAudioOptionsInputITunesNext].identifier);
menu.items[kAudioOptionsVolume].sliderPos=gConfig->soundVolume;
sprintf(menu.items[kAudioOptionsInterfaceSounds].label,"Interface Sounds: \255#a\255%s",gConfig->interfaceSounds?"On":"Off");
int sel=InterfaceGetUserMenuSelection(&menu);
switch(menu.initialSelection=(sel&kInterfaceMenuItemMask))
{
case kAudioOptionsVolume:
if(sel&kInterfaceMenuLeftArrow){
gConfig->soundVolume-=0.1;
if(gConfig->soundVolume<0)gConfig->soundVolume=0;
}
else{
gConfig->soundVolume+=0.1;
if(gConfig->soundVolume>1)gConfig->soundVolume=1;
}
SoundReInit();
break;
case kAudioOptionsInterfaceSounds:
gConfig->interfaceSounds=!gConfig->interfaceSounds;
break;
case kAudioOptionsInputITunesNext:
case kAudioOptionsInputITunesPrev:
case kAudioOptionsInputITunesPlay:
{
while(GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter));
menu.initialSelection=sel;
char keyString[80];
sprintf(keyString,"Press the new Key or Button for '%s'\n (Or press delete to clear)",itemStrings[sel]);
InterfaceDrawStrings("Assign new Key",keyString,kFileErr);
GetInput(gConfig->keys+kInputITunesNext+menu.initialSelection-kAudioOptionsInputITunesNext);
int interfaceKeyPressed;
do{
interfaceKeyPressed=false;
for(int i=kInterfaceKeyUp;i<kInterfaceNumKeys;i++)
if(GetInterfaceKey(i))
interfaceKeyPressed=true;
if(GetButtonInput(kInputITunesNext)||GetButtonInput(kInputITunesPlay))
interfaceKeyPressed=true;
}while(interfaceKeyPressed);
}
break;
case kAudioOptionsReturn:
case kInterfaceMenuEsc:
case kInterfaceMenuOK:
exit=true;
break;
}
}while(!exit);
InterfaceDisposeMenu(&menu);
}
enum{
kOptionsGameplay,
kOptionsControls,
kOptionsAnalougeControls,
kOptionsTaunts,
kOptionsVideo,
kOptionsAudio,
kOptionsReturn,
kNumOptionsButtons
};
void InterfaceOptions()
{
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,kNumOptionsButtons,"Options");
char itemStrings[][32]={"Gameplay","Controls","Analog Controls","Multiplayer Taunts","Video","Audio","Return to previous menu"};
for(int i=0;i<menu.numItems;i++)
{
strcpy(menu.items[i].label,itemStrings[i]);
menu.items[i].size*=1.15;
menu.items[i].lineSpacing*=1.15;
}
menu.items[kOptionsReturn-1].lineSpacing*=1.5;
menu.background=FileGetReference("background-options.tif");
menu.RenderCallback=InterfaceRenderReplay;
int exit=false;
do{
InterfaceMenuZoomAnimation(&menu,-1,true);
switch(menu.initialSelection=InterfaceGetUserMenuSelection(&menu))
{
case kOptionsGameplay:
InterfaceGameplayOptions();
break;
case kOptionsVideo:
InterfaceVideoOptions();
break;
case kOptionsControls:
InterfaceControlOptions();
break;
case kOptionsAnalougeControls:
InterfaceAnalogueControlOptions();
break;
case kOptionsTaunts:
InterfaceTauntOptions();
break;
case kOptionsAudio:
InterfaceAudioOptions();
break;
case kOptionsReturn:
case kInterfaceMenuEsc:
exit=true;
break;
}
}while(!exit);
InterfaceDisposeMenu(&menu);
WriteOutFile(FileGetReference(kConfigFileName),gConfig,kParserTypeConfigDesc);
}

1206
source/interfaceutil.cpp Normal file

File diff suppressed because it is too large Load Diff

130
source/interfaceutil.h Normal file
View File

@ -0,0 +1,130 @@
#ifndef __INTERFACEUTIL
#define __INTERFACEUTIL
#include "vectors.h"
#include "fileio.h"
enum{
kInterfaceMenuItemDisabled=1<<0,
kInterfaceMenuItemArrowInput=1<<1,
kInterfaceMenuItemTypeable=1<<2,
kInterfaceMenuItemTypeHidden=1<<3,
kInterfaceMenuItemSlider=1<<4,
kInterfaceMenuItemFixedPos=1<<5
};
enum{
kInterfaceMenuEsc=1<<31,
kInterfaceMenuLeftArrow=1<<30,
kInterfaceMenuRightArrow=1<<29,
kInterfaceMenuOK=1<<28,
kInterfaceMenuEasterEgg=1<<27,
kInterfaceMenuReplayKey=1<<26,
kInterfaceMenuSpaceFlag=1<<25,
};
#define kInterfaceBackgroundTexture "background.tif"
#define kInterfaceMenuSlideBarTexture "bar.tif"
#define kInterfaceMenuSlideBarHeight 0.01
#define kInterfaceMenuSlideBarStart 0.35
#define kInterfaceMenuSlideBarWidth 0.45
#define kInterfaceMenuSliderTexture "slider.tif"
#define kInterfaceMenuSliderSize 0.02
#define kInterfaceKeyImageSize 0.06
#define kBackgroundXStretch 0.622
#define kBackgroundYStretch 0.43
#define kInterfaceStatusTexture kInterfaceMenuSlideBarTexture
#define kInterfaceMenuItemMask (~(kInterfaceMenuLeftArrow|kInterfaceMenuRightArrow|kInterfaceMenuEasterEgg|kInterfaceMenuReplayKey|kInterfaceMenuSpaceFlag))
typedef struct{
char label[256];
char describtion[512];
char type[256];
int flags;
int maxTypeLength;
float maxTypeXPos;
float sliderPos;
float sliderTransparency;
float sel;
float size;
float scroll;
float lineSpacing;
float r,g,b;
float fixedX,fixedY;
} tInterfaceMenuItemDescribtion;
enum{
kMenuTypeableOff,
kMenuTypeableOn,
kMenuTypeableReggie
};
typedef struct{
char title[256];
char type[256];
int initialSelection;
int numItems;
int scrollEnable;
int menuTypeable;
tFileRef image,background;
int enterAlwaysOK;
int returnOnSpace;
int easterEggEnable;
int easterEggString;
int joinDisable;
float cursorPos,cursorShowPos;
float easterEggScrollPos;
float imageXScale,imageYScale;
float imageXPos,imageYPos;
float imageAlpha;
float itemsXPos,itemsYPos;
float minScroll;
tVector2 mousePos;
tVector2 descPos;
tInterfaceMenuItemDescribtion *items;
void *userData;
void (*RenderCallback)(void*,int,void*);
int (*TimerCallback)(void*);
} tInterfaceMenuDescribtion;
#define kTitlePosX -0.93
#define kTitlePosY 0.98
#define kInterfaceMenuPointerTexture "menupointer.tif"
#define kInterfaceMenuPointerSize 0.02
extern int gJoinFlag;
extern char gJoinHost[];
extern char gLastMenuChar;
extern int gInterfaceType;
extern float gStartIdleTime;
int InterfaceGetUserInputString(char *prompt,char *stringBuffer,int bufferSize,int fullCharSet,int hideType);
int InterfaceGetUserMenuSelection(tInterfaceMenuDescribtion *menu);
void InterfaceDrawStrings(char *stringBuffer,char *secondaryStringBuffer,tFileRef background);
void InterfaceDisplayMessage(tFileRef background,char *stringBuffer,char *secondaryStringBuffer);
void CashString(int cash, char *str);
void MakeNumString(int i,char *str);
void TextScrollFile(tFileRef text);
void InterfaceTextBufferZoomAnimation(tFileRef background,int in);
void InterfaceMenuZoomAnimation(tInterfaceMenuDescribtion *menu,int selection,int in);
void InterfaceInitMenu(tInterfaceMenuDescribtion *menu,int numItems,char *title);
void InterfaceDisposeMenu(tInterfaceMenuDescribtion *menu);
void InterfaceDrawBackground(tFileRef background,tFileRef image,float imageXScale,float imageYScale,float imageXPos,float imageYPos,float alpha);
int InterfaceGetUserConfirmation(char *title,char *text);
void InterfaceFadeInImageFromBlack(float xSize,float ySize,tFileRef image,float maxTime);
void InterfaceFadeInInterfaceFromImage(tFileRef image,float maxTime);
void InterfaceFadeInImageFromImage(float xSize,float ySize,tFileRef image,float xSize2,float ySize2,tFileRef image2,float maxTime);
void InterfaceDrawBackgroundFade(float opacity,int showtop);
void InterfaceDrawStatusBar(char *stringBuffer,char *secondaryStringBuffer,float status);
void TeaserScreen();
void InterfaceRenderReplay(void *userData,int selection,void *menu);
#endif

235
source/lights.cpp Normal file
View File

@ -0,0 +1,235 @@
#include <OpenGL/gl.h>
#include <math.h>
#include "vectors.h"
#include "environment.h"
#include "entities.h"
#include "textures.h"
#include "renderframe.h"
#include "roads.h"
#include "collision.h"
#include "config.h"
#include "stencil.h"
#define kLightOffset 0.6
#define kLightReflectionOffset 15
void RenderEntityLights(tGameEntity *entity,int numLights,int lightFlags,float reflectionDim,tLightDefinition *lights)
{
glPushAttrib(GL_DEPTH_BUFFER_BIT+GL_CURRENT_BIT+GL_LIGHTING_BIT+GL_COLOR_BUFFER_BIT+GL_FOG_BIT);
glDepthMask(false);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
glDisable(GL_FOG);
TexturesSelectTex(FileGetReference("Particle.pct"));
for(int i=0;i<numLights;i++)
//is the light on?
if(lightFlags&lights[i].onFlags&&!(lightFlags&lights[i].offFlags))
//is this a dot light? (a light which only needs a particle texture to be drawn)
if(lights[i].type!=kLightTypeSpot)
{
float visibility=-lights[i].dir*entity->dir**MatrixGetZVector(gCameraEntity->dir);
//is the light pointing towards the camera?
if(lights[i].type==kLightTypeDirectionlessDot||lights[i].type==kLightTypeDirectionlessDotReflective)
visibility=1;
else if(lights[i].type==kLightTypeSpecularDot)
visibility=sign(visibility)*powf(visibility*!((lights[i].pos*entity->dir+entity->pos)-gCameraEntity->pos)**MatrixGetZVector(gCameraEntity->dir),100);
if(visibility>0){
if(visibility>1)visibility=1;
float size=lights[i].size;
//draw particle texture
tVector3 lightPos=lights[i].pos*entity->dir+entity->pos;
float camDist=~(lightPos-gCameraEntity->pos);
tVector3 drawlightPos=lightPos-(lightPos-gCameraEntity->pos)*kLightOffset/camDist;
size*=(camDist-kLightOffset)/camDist;
SetupTranslation(drawlightPos,gCameraEntity->dir);
glColor4f(lights[i].rgb.x,lights[i].rgb.y,lights[i].rgb.z,visibility);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(size,size);
glTexCoord2d(1,0); glVertex2f(size,-size);
glTexCoord2d(0,1); glVertex2f(-size,size);
glTexCoord2d(0,0); glVertex2f(-size,-size);
glEnd();
//does the light reflect on the ground?
if(lights[i].type==kLightTypeDotRefelective||lights[i].type==kLightTypeDirectionlessDotReflective)
{
int lastRoadIndex=entity->lastRoadIndex;
int surface=-1;
lightPos=lightPos-Vector(0,GetGroundOffset(lightPos,&lastRoadIndex,NULL,&surface),0);
float camDist=~(lightPos-gCameraEntity->pos);
float size=lights[i].size;
if(camDist>2*kLightReflectionOffset)
{
drawlightPos=lightPos-(lightPos-gCameraEntity->pos)*kLightReflectionOffset/camDist;
size*=(camDist-kLightReflectionOffset)/camDist;
}
else
drawlightPos=lightPos;
//is the ground reflective
if(surface!=-1)
if(gSurfaceTypes->types[surface].reflectionEnable)
{
//draw reflection texture
SetupTranslation(drawlightPos,gCameraEntity->dir);
if(camDist<=2*kLightReflectionOffset)
glDisable(GL_DEPTH_TEST);
visibility*=1-reflectionDim*0.6;
glColor4f(lights[i].rgb.x,lights[i].rgb.y,lights[i].rgb.z,visibility);
TexturesSelectTex(FileGetReference("lightreflection.pct"));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(size,size);
glTexCoord2d(1,0); glVertex2f(size,-5*size);
glTexCoord2d(0,1); glVertex2f(-size,size);
glTexCoord2d(0,0); glVertex2f(-size,-5*size);
glEnd();
TexturesSelectTex(FileGetReference("Particle.pct"));
#ifdef __POLYCOUNT
gPolyCount+=2;
#endif
glEnable(GL_DEPTH_TEST);
}
}
#ifdef __POLYCOUNT
gPolyCount+=2;
#endif
}
}
glPopAttrib();
}
#define kConeSections 16
#define kConeLength 6.5
void DrawLightCone(float scale)
{
tVector3 c[kConeSections];
for(int i=0;i<kConeSections;i++)
c[i]=Vector(cos((2*PI*i)/kConeSections)*gStencilZoom,sin((2*PI*i)/kConeSections)*gStencilZoom,4)*scale*gStencilZoom;
for(int i=0;i<kConeSections;i++)
{
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(0,0,(1-gStencilZoom)*10);
glVertex3fv(&c[i].x);
glVertex3fv(&c[(i+1)%kConeSections].x);
glVertex3f(0,0,kConeLength*scale);
glEnd();
}
#ifdef __POLYCOUNT
gPolyCount+=2*kConeSections;
#endif
}
void DrawLightConeClippedFar(float scale,float clipPlanePos,tVector3 clipPlaneNormal)
{
tVector3 c[kConeSections];
tVector3 clipPos=Vector(0,0,kConeLength*scale*clipPlanePos);
float baseClipDist=-clipPos*clipPlaneNormal;
float cClipDist;
for(int i=0;i<kConeSections;i++)
c[i]=Vector(cos((2*PI*i)/kConeSections)*gStencilZoom,sin((2*PI*i)/kConeSections)*gStencilZoom,4)*scale*gStencilZoom;
for(int i=0;i<kConeSections;i++)
if((cClipDist=((c[i]-clipPos)*clipPlaneNormal))>0)
{
float cClipPos=(1-(cClipDist/(cClipDist-baseClipDist)));
if(cClipPos<=0)return;
c[i]=c[i]*cClipPos;
}
for(int i=0;i<kConeSections;i++)
{
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(0,0,(1-gStencilZoom)*10);
glVertex3fv(&c[i].x);
glVertex3fv(&c[(i+1)%kConeSections].x);
glVertex3f(0,0,clipPos.z);
glEnd();
}
#ifdef __POLYCOUNT
gPolyCount+=2*kConeSections;
#endif
}
void DrawLightConeClippedNear(float scale,tVector3 clipPlanePos,tVector3 clipPlaneNormal)
{
}
//draws a car's light cones (usually headlights)
void RenderEntityLightCones(tGameEntity *entity,int numLights,int lightFlags,tLightDefinition *lights)
{
glPushAttrib(GL_STENCIL_BUFFER_BIT+GL_COLOR_BUFFER_BIT+GL_POLYGON_BIT+GL_DEPTH_BUFFER_BIT+GL_ENABLE_BIT);
glDisable(GL_LIGHTING);
glDisable(GL_FOG);
for(int i=0;i<numLights;i++)
//is the light on?
if(lightFlags&lights[i].onFlags&&!(lightFlags&lights[i].offFlags))
//is it a spot light
if(lights[i].type==kLightTypeSpot)
//is stencil buffering enabled, and are spotlights enabled for this environment?
if(gConfig->stencil&&gEnvironment->spotLightEnable)
{
//translate to draw the light cone
tVector3 lightPos=lights[i].pos*entity->dir+entity->pos;
tMatrix3 m;
MatrixIdentity(m);
*MatrixGetZVector(m)=lights[i].dir;
*MatrixGetXVector(m)=!(lights[i].dir%Vector(0,1,0));
*MatrixGetYVector(m)=(lights[i].dir%*MatrixGetXVector(m));
MatrixMult(m,entity->dir,m);
SetupTranslation(lightPos,m);
//setup stencil buffer
//drawing light cones works just like stencil buffer shadow volumes
glDepthMask(GL_FALSE);
glEnable(GL_STENCIL_TEST);
glColorMask(0, 0, 0, 0);
glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
tVector3 camDir=*MatrixGetZVector(gCameraEntity->dir);
float clip1=(lightPos-gCameraEntity->pos)*camDir;
float clip2=((lightPos+(lights[i].dir*kConeLength*lights[i].size)*entity->dir)-gCameraEntity->pos)*camDir;
//test if the light cone volume intersects the clipping volume
if(clip1>ClipDistance()&&clip2>ClipDistance())
{//clip near and far (not implemented)
}
else if(clip1>ClipDistance())
{//clip near (not implemented)
}
else if(clip2>ClipDistance()-20)
{//clip far
tMatrix3 mInv;
MatrixTranspose(m,mInv);
tVector3 clipPlaneDir=camDir*mInv;
glFrontFace(GL_CW);
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
DrawLightConeClippedFar(lights[i].size*gStencilZoom,(ClipDistance()-20-clip1)/(clip2-clip1),clipPlaneDir);
glFrontFace(GL_CCW);
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
DrawLightConeClippedFar(lights[i].size*gStencilZoom,(ClipDistance()-20-clip1)/(clip2-clip1),clipPlaneDir);
}
else
{//no clip
glFrontFace(GL_CW);
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
DrawLightCone(lights[i].size*gStencilZoom);
glFrontFace(GL_CCW);
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
DrawLightCone(lights[i].size*gStencilZoom);
}
}
glPopAttrib();
}

9
source/lights.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef __LIGHTS
#define __LIGHTS
#include "entities.h"
void RenderEntityLights(tGameEntity *entity,int numLights,int lightFlags,float reflectionDim,tLightDefinition *lights);
void RenderEntityLightCones(tGameEntity *entity,int numLights,int lightFlags,tLightDefinition *lights);
#endif

15
source/localtracker.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef __LOCALTRACKER
#define __LOCALTRACKER
#include "tracker.h"
extern int gNumLocalGames;
extern int gLocalGameListUpdate;
extern tGameListEntry gLocalGames[];
void InitLocalTracker();
void LocalTrackerStartAdvertising(char *gameName);
void LocalTrackerStopAdvertising();
void LocalTrackerSearchGamesInit();
void LocalTrackerSearchGamesDone();
#endif

291
source/log.cpp Normal file
View File

@ -0,0 +1,291 @@
//log.cpp
//log [network] physics packets in order to replay the games
#include <stdlib.h>
#include <unistd.h>
#include "networkphysics.h"
#include "gamemem.h"
#include "log.h"
#include "gameinitexit.h"
#include "gameframe.h"
#include "network.h"
typedef struct{
int offset;
short size;
short type;
} tLogEntry;
#define kLogSize (20*1024*1024)
#define kGhostLogSize (256*1024)
#define kIndexSize (256*1024)
char* gPacketLog;
char *gGhostLog;
tLogEntry *gPacketLogIndex;
tLogEntry *gGhostIndex;
int gLogPos=0;
int gIndexPos=0;
int gGhostLogPos=0;
int gGhostIndexPos=0;
void LogInit()
{
gPacketLog=(char*)malloc(kLogSize);
gGhostLog=(char*)malloc(kGhostLogSize);
gPacketLogIndex=(tLogEntry*)malloc(kIndexSize*sizeof(tLogEntry));
gGhostIndex=(tLogEntry*)malloc(kIndexSize*sizeof(tLogEntry));
}
void GetLogs(tFileRef *logs,int *logCount)
{
*logCount=0;
for(int i=0;i<gFileTableSize;i++)
if(char *extension=FileGetExtension(i))
if(!_stricmp(extension,kFileTypeLog))
if(*logCount<kMaxLogs)
logs[(*logCount)++]=i;
}
void LogPacket(int size, void *data,int type)
{
if(gIndexPos<kIndexSize)
if(gLogPos+size<kLogSize)
{
gPacketLogIndex[gIndexPos].size=size;
gPacketLogIndex[gIndexPos].offset=gLogPos;
gPacketLogIndex[gIndexPos].type=type;
gIndexPos++;
MemoryMove(gPacketLog+gLogPos,data,size);
gLogPos+=size;
}
}
void LogToGhostLog()
{
//kLogSize>kGhostLogSize!!!!
MemoryMove(gGhostLog,gPacketLog,gLogPos>kGhostLogSize?kGhostLogSize:gLogPos);
MemoryMove(gGhostIndex,gPacketLogIndex,gIndexPos*sizeof(tLogEntry));
gGhostLogPos=gLogPos;
gGhostIndexPos=gIndexPos;
}
int LogCompare(const void *a,const void *b)
{
int aFrame=((tPhysicsMessage*)(gPacketLog+*(int*)a))->frame;
int bFrame=((tPhysicsMessage*)(gPacketLog+*(int*)b))->frame;
S32Swap(aFrame);
S32Swap(bFrame);
return aFrame-bFrame;
}
void LogSort()
{
qsort(gPacketLogIndex,gIndexPos,sizeof(tLogEntry),LogCompare);
}
void LogReset()
{
gLogPos=0;
gIndexPos=0;
}
void GhostLogReset()
{
gGhostLogPos=0;
gGhostIndexPos=0;
}
int LogGetPacket(int index,int *type,int *size,int log,void *buffer)
{
if(log==kLogReplayLog||gGhostLogPos==0){
if(index<gIndexPos)
{
*type=gPacketLogIndex[index].type;
*size=gPacketLogIndex[index].size;
memcpy(buffer,gPacketLog+gPacketLogIndex[index].offset,*size);
return true;
}
}
else
if(index<gGhostIndexPos)
if(gGhostIndex[index].offset<kGhostLogSize)
{
*type=gGhostIndex[index].type;
*size=gGhostIndex[index].size;
memcpy(buffer,gGhostLog+gGhostIndex[index].offset,*size);
return true;
}
return false;
}
void GameInfoSend(tGameInfo *gInfo);
void GameInfoReceive(tGameInfo *gInfo);
void ConvertGInfoSwap(tGameInfo *gInfo);
void LogSaveToDisk()
{
char ct[255],name[255];
time_t t;
time(&t);
ctime_r(&t,ct);
ct[19]='\0';
ct[13]='-';
ct[16]='-';
sprintf(name,"%s.redlog",ct);
CFBundleRef refMainBundle = CFBundleGetMainBundle();
if (!refMainBundle)
return;
// create a URL to the app bundle
CFURLRef refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
if(!refMainBundleURL)
return;
char path[512];
if(!CFURLGetFileSystemRepresentation(refMainBundleURL,true,(UInt8*)path,512))
return;
sprintf(path,"%s/../",path);
chdir(path);
sprintf(path,"%s/Plug-Ins/",path);
chdir(path);
FILE* f=fopen(name,"w");
if(!f)
return;
SysBeep(0);
GameInfoSend(gGameInfo);
fwrite(gGameInfo,sizeof(tGameInfo),1,f);
if(gGameInfo->numLaps==-1)
{
int w=gGhostIndexPos;
S32Swap(w);
fwrite(&w,sizeof(int),1,f);
w=gGhostLogPos;
S32Swap(w);
fwrite(&w,sizeof(int),1,f);
w=gReplayOldFrameCount;
S32Swap(w);
fwrite(&w,sizeof(int),1,f);
for(int i=0;i<gGhostIndexPos;i++)
{
S32Swap(gGhostIndex[i].offset);
S16Swap(gGhostIndex[i].type);
S16Swap(gGhostIndex[i].size);
}
fwrite(gGhostIndex,sizeof(tLogEntry),gGhostIndexPos,f);
for(int i=0;i<gGhostIndexPos;i++)
{
S32Swap(gGhostIndex[i].offset);
S16Swap(gGhostIndex[i].type);
S16Swap(gGhostIndex[i].size);
}
for(int i=0;i<gGhostIndexPos;i++)
{
switch(gGhostIndex[i].type)
{
case kMessageTypePhysics:
{
tPhysicsMessage *physMessage=(tPhysicsMessage*)(gGhostLog+gGhostIndex[i].offset);
physMessage->frame-=(gBestLapTime!=0?gBestLapStart+5:gCurrentLapStart+5);
}
}
}
fwrite(gGhostLog,sizeof(char),gGhostLogPos,f);
for(int i=0;i<gGhostIndexPos;i++)
{
switch(gGhostIndex[i].type)
{
case kMessageTypePhysics:
{
tPhysicsMessage *physMessage=(tPhysicsMessage*)(gGhostLog+gGhostIndex[i].offset);
physMessage->frame+=(gBestLapTime!=0?gBestLapStart+5:gCurrentLapStart+5);
}
}
}
}
else
{
int w=gIndexPos;
S32Swap(w);
fwrite(&w,sizeof(int),1,f);
w=gLogPos;
S32Swap(w);
fwrite(&w,sizeof(int),1,f);
w=gReplayOldFrameCount;
S32Swap(w);
fwrite(&w,sizeof(int),1,f);
for(int i=0;i<gIndexPos;i++)
{
S32Swap(gPacketLogIndex[i].offset);
S16Swap(gPacketLogIndex[i].type);
S16Swap(gPacketLogIndex[i].size);
}
fwrite(gPacketLogIndex,sizeof(tLogEntry),gIndexPos,f);
for(int i=0;i<gIndexPos;i++)
{
S32Swap(gPacketLogIndex[i].offset);
S16Swap(gPacketLogIndex[i].type);
S16Swap(gPacketLogIndex[i].size);
}
fwrite(gPacketLog,sizeof(char),gLogPos,f);
}
fclose(f);
FileRescanDirectory();
}
int LogLoad(tFileRef f,tGameInfo* gInfo)
{
char *ch=(char*)FileGetDataPtr(f);
*gInfo=*(tGameInfo*)ch;
ConvertGInfoSwap(gInfo);
GameInfoReceive(gInfo);
ch+=sizeof(tGameInfo);//-sizeof(UInt32)*kMaxPlayers;
for(int i=0;i<gInfo->numPlayers;i++)
if(gInfo->playerCars[i]==-1)
return false;
if(gInfo->map==-1)
return false;
if(gInfo->environment==-1)
return false;
gIndexPos=*(int*)ch;
S32Swap(gIndexPos);
gGhostIndexPos=gIndexPos;
ch+=sizeof(int);
gLogPos=*(int*)ch;
S32Swap(gLogPos);
ch+=sizeof(int);
gReplayOldFrameCount=*(int*)ch;
S32Swap(gReplayOldFrameCount);
ch+=sizeof(int);
MemoryMove(gPacketLogIndex,ch,sizeof(tLogEntry)*gIndexPos);
for(int i=0;i<gIndexPos;i++)
{
S32Swap(gPacketLogIndex[i].offset);
S16Swap(gPacketLogIndex[i].type);
S16Swap(gPacketLogIndex[i].size);
}
ch+=sizeof(tLogEntry)*gIndexPos;
MemoryMove(gPacketLog,ch,sizeof(char)*gLogPos);
return true;
}

26
source/log.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef __LOG
#define __LOG
#include "fileio.h"
#include "gameinitexit.h"
#define kMaxLogs 64
enum{
kLogReplayLog,
kLogGhostLog
};
void LogInit();
void GetLogs(tFileRef *logs,int *logCount);
void LogReset();
void GhostLogReset();
void LogPacket(int size, void *data,int type);
void LogSort();
void LogToGhostLog();
int LogGetPacket(int index,int *type,int *size,int log,void *buffer);
void LogSaveToDisk();
int LogLoad(tFileRef f,tGameInfo* gInfo);
#endif

664
source/maccontrols.cpp Executable file
View File

@ -0,0 +1,664 @@
//maccontrols.cpp
//mac-specific input code
#include <math.h>
#include <string.h>
#include <HID_Utilities_External.h>
#include <IOKit/hid/IOHIDUsageTables.h>
//needed for ForceFeedback.h
//-----------------------------------------------------------------
typedef OSStatus HRESULT;
typedef UInt32 IOByteCount;
typedef unsigned int io_service_t;
typedef unsigned int io_object_t;
#define S_OK ((HRESULT)0x00000000L)
//-----------------------------------------------------------------
#include <ForceFeedback/ForceFeedback.h>
extern "C"{
#include "ImmrHIDUtilAddOn.h"
}
#include "controls.h"
#include "config.h"
#include "error.h"
#include "gameframe.h"
#include "gamesystem.h"
#include "gametime.h"
typedef struct{
pRecDevice device;
int numElements;
pRecElement *elements;
} tHIDController;
tHIDController *gControllers;
int gInputHID=false;
int gNumControllers=0;
int gIShockIIFFB=false;
//iS2F_DeviceRef_t giShockList[iS2F_MAX_ISHOCK2_NUM];
int gIShockIIFFBBlock=0;
int gFFB=false;
FFDeviceObjectReference gFFDeviceRef;
FFEffectObjectReference gGroundRumbleEffectRef = NULL;
FFEffectObjectReference gJoltEffectRef = NULL;
FFEffectObjectReference gFrictionEffectRef = NULL;
FFEffectObjectReference gAlignEffectRef = NULL;
FFEffectObjectReference gEngineEffectRef = NULL;
DWORD dwAxes[2] = {FFJOFS_X,FFJOFS_Y};
LONG lDirection[2] = {0,0};
extern int gAxisSteering;
//returns true if the key with the key code k is pressed, false otherwise
short IsPressed(unsigned short k )
{
if(k<0||k>255)
return false;
KeyMapByteArray km;
GetKeys( *((KeyMap*)&km));
return ( ( km[k>>3] >> (k & 7) ) & 1);
}
//Initialize controls
void ControlInit()
{
if(HIDBuildDeviceList(NULL,NULL))
{
gNumControllers=0;
pRecDevice device=HIDGetFirstDevice();
do{
//if(!(device->usagePage==kHIDPage_Unknown||(device->usagePage==kHIDPage_GenericDesktop&&(device->usage==kHIDUsage_GD_Mouse||device->usage==kHIDUsage_GD_Keyboard))))
if(device->usagePage==kHIDPage_GenericDesktop&&(device->usage==kHIDUsage_GD_Joystick||device->usage==kHIDUsage_GD_GamePad))//||kHIDUsage_GD_Mouse))
gNumControllers++;
device=HIDGetNextDevice(device);
}while(device);
gControllers=(tHIDController*)NewPtr(sizeof(tHIDController)*gNumControllers);
gNumControllers=0;
device=HIDGetFirstDevice();
do{
// if(!(device->usagePage==kHIDPage_Unknown||(device->usagePage==kHIDPage_GenericDesktop&&(device->usage==kHIDUsage_GD_Mouse||device->usage==kHIDUsage_GD_Keyboard))))
if(device->usagePage==kHIDPage_GenericDesktop&&(device->usage==kHIDUsage_GD_Joystick||device->usage==kHIDUsage_GD_GamePad))//||kHIDUsage_GD_Mouse))
{
io_service_t hidDeviceObject=AllocateHIDObjectFromRecDevice(device);
if(hidDeviceObject)
if(FFIsForceFeedback(hidDeviceObject)==FF_OK)
if(FFCreateDevice(hidDeviceObject,&gFFDeviceRef)==FF_OK)
gFFB=true;
gControllers[gNumControllers].device=device;
gControllers[gNumControllers].numElements=HIDCountDeviceElements(gControllers[gNumControllers].device,kHIDElementTypeInput);
gControllers[gNumControllers].elements=(pRecElement*)NewPtr(sizeof(pRecElement)*gControllers[gNumControllers].numElements);
gControllers[gNumControllers].elements[0]=HIDGetFirstDeviceElement(gControllers[gNumControllers].device,kHIDElementTypeInput);
for(int j=1;j<gControllers[gNumControllers].numElements;j++)
gControllers[gNumControllers].elements[j]=HIDGetNextDeviceElement(gControllers[gNumControllers].elements[j-1],kHIDElementTypeInput);
gInputHID=true;
gNumControllers++;
}
device=HIDGetNextDevice(device);
}while(device);
}
}
//Wrapper functions for the iShock II SDK.
void FFBJolt(float lMag,float rMag,float duration)
{
#ifndef __TARGET_TOOLAPP
/* if(gIShockIIFFB&&gConfig->iShockFFB)
{
iS2F_JoltCmd_t joltCmd;
joltCmd.motorCmd.leftMotorMagnitude=lMag*10;
joltCmd.motorCmd.rightMotorMagnitude=rMag*10;
joltCmd.duration=duration*1000;
iS2F_SimpleJolt(giShockList[0],&joltCmd);
gIShockIIFFBBlock=gFrameCount+duration*kFPS;
}*/
if(gFFB&&gAxisSteering&&gConfig->ffb)
{
float mag=(rMag+lMag)*0.5;
float offset=rMag-lMag;
HRESULT hr;
FFEFFECT ffeffect;
FFPERIODIC ffperiodic;
FFENVELOPE ffenvelope;
ffenvelope.dwSize = sizeof(ffenvelope);
ffenvelope.dwAttackLevel = 0;
ffenvelope.dwAttackTime = 0; /* Microseconds */
ffenvelope.dwFadeLevel = 0;
ffenvelope.dwFadeTime = duration*FF_SECONDS; /* Microseconds */
ffperiodic.dwMagnitude = FF_FFNOMINALMAX*gConfig->ffbIntensity*mag;
ffperiodic.lOffset = FF_FFNOMINALMAX*gConfig->ffbIntensity*offset;
ffperiodic.dwPhase = 0;
ffperiodic.dwPeriod = 0.1*FF_SECONDS; // 10 Hz
ffeffect.dwSize = sizeof(ffeffect); /* sizeof(FFEFFECT) */
ffeffect.dwFlags = FFEFF_CARTESIAN; /* FFEFF_* */
ffeffect.dwDuration = duration*FF_SECONDS; /* Microseconds */
ffeffect.dwSamplePeriod = 1000; /* Microseconds */
ffeffect.dwGain = FF_FFNOMINALMAX;
ffeffect.dwTriggerButton = FFEB_NOTRIGGER; /* or FFEB_NOTRIGGER */
ffeffect.dwTriggerRepeatInterval = 0; /* Microseconds */
ffeffect.cAxes = 1; /* Number of axes */
ffeffect.rgdwAxes = dwAxes; /* Array of axes */
ffeffect.rglDirection = lDirection; /* Array of directions */
ffeffect.lpEnvelope = &ffenvelope; /* Optional */
ffeffect.cbTypeSpecificParams = sizeof(ffperiodic); /* Size of params */
ffeffect.lpvTypeSpecificParams = &ffperiodic; /* Pointer to params */
ffeffect.dwStartDelay = 0; /* Microseconds */
if(gJoltEffectRef==NULL)
{
FFDeviceCreateEffect(gFFDeviceRef, kFFEffectType_Square_ID, &ffeffect, &gJoltEffectRef);
FFEffectDownload(gJoltEffectRef);
FFEffectStart(gJoltEffectRef, 1, 0);
}
else
{
FFEffectSetParameters(gJoltEffectRef,&ffeffect,FFEP_GAIN);
FFEffectStart(gJoltEffectRef, 1, 0);
}
}
#endif
}
void FFBSetGoundRumble(float velo, float rumble)
{
if(gFFB&&gConfig->ffb)
{
if(!gAxisSteering)
rumble=0;
velo/=60;
if(velo>1)velo=1;
HRESULT hr;
FFEFFECT ffeffect;
FFPERIODIC ffperiodic;
ffperiodic.dwMagnitude = FF_FFNOMINALMAX*gConfig->ffbIntensity*rumble*velo*0.5;
ffperiodic.lOffset = 0;
ffperiodic.dwPhase = 0;
if(velo)
ffperiodic.dwPeriod = FF_SECONDS*0.8/velo;
else
ffperiodic.dwPeriod = 0;
ffeffect.dwSize = sizeof(ffeffect); /* sizeof(FFEFFECT) */
ffeffect.dwFlags = FFEFF_CARTESIAN; /* FFEFF_* */
ffeffect.dwDuration = FF_INFINITE; /* Microseconds */
ffeffect.dwSamplePeriod = 1000; /* Microseconds */
ffeffect.dwGain = FF_FFNOMINALMAX;
ffeffect.dwTriggerButton = FFEB_NOTRIGGER; /* or FFEB_NOTRIGGER */
ffeffect.dwTriggerRepeatInterval = 0; /* Microseconds */
ffeffect.cAxes = 1; /* Number of axes */
ffeffect.rgdwAxes = dwAxes; /* Array of axes */
ffeffect.rglDirection = lDirection; /* Array of directions */
ffeffect.lpEnvelope = NULL; /* Optional */
ffeffect.cbTypeSpecificParams = sizeof(ffperiodic); /* Size of params */
ffeffect.lpvTypeSpecificParams = &ffperiodic; /* Pointer to params */
ffeffect.dwStartDelay = 0; /* Microseconds */
if(gGroundRumbleEffectRef==NULL)
{
FFDeviceCreateEffect(gFFDeviceRef, kFFEffectType_Sine_ID, &ffeffect, &gGroundRumbleEffectRef);
FFEffectDownload(gGroundRumbleEffectRef);
FFEffectStart(gGroundRumbleEffectRef, 1, 0);
}
else
{
FFEffectSetParameters(gGroundRumbleEffectRef,&ffeffect,FFEP_TYPESPECIFICPARAMS+FFEP_GAIN);
FFEffectStatusFlag pFlags;
FFEffectGetEffectStatus(gGroundRumbleEffectRef,&pFlags);
if(!pFlags&FFEGES_PLAYING)
FFEffectStart(gGroundRumbleEffectRef, 1, 0);
}
}
}
void FFBSetSteerResistance(float res,float alignment)
{
if(gFFB&&gConfig->ffb)
{
if(!gAxisSteering)
{
res=0;
alignment=0;
}
HRESULT hr;
FFEFFECT ffeffect;
FFCONDITION ffcondition;
ffcondition.lOffset=0;
ffcondition.lPositiveCoefficient=FF_FFNOMINALMAX*gConfig->ffbIntensity*res;
ffcondition.lNegativeCoefficient=FF_FFNOMINALMAX*gConfig->ffbIntensity*res;
ffcondition.dwPositiveSaturation=FF_FFNOMINALMAX*gConfig->ffbIntensity*res;
ffcondition.dwNegativeSaturation=FF_FFNOMINALMAX*gConfig->ffbIntensity*res;
ffcondition.lDeadBand=0;
ffeffect.dwSize = sizeof(ffeffect); /* sizeof(FFEFFECT) */
ffeffect.dwFlags = FFEFF_CARTESIAN; /* FFEFF_* */
ffeffect.dwDuration = FF_INFINITE; /* Microseconds */
ffeffect.dwSamplePeriod = 1000; /* Microseconds */
ffeffect.dwGain = FF_FFNOMINALMAX;
ffeffect.dwTriggerButton = FFEB_NOTRIGGER; /* or FFEB_NOTRIGGER */
ffeffect.dwTriggerRepeatInterval = 0; /* Microseconds */
ffeffect.cAxes = 1; /* Number of axes */
ffeffect.rgdwAxes = dwAxes; /* Array of axes */
ffeffect.rglDirection = lDirection; /* Array of directions */
ffeffect.lpEnvelope = NULL; /* Optional */
ffeffect.cbTypeSpecificParams = sizeof(ffcondition); /* Size of params */
ffeffect.lpvTypeSpecificParams = &ffcondition; /* Pointer to params */
ffeffect.dwStartDelay = 0; /* Microseconds */
if(gFrictionEffectRef==NULL)
{
FFDeviceCreateEffect(gFFDeviceRef, kFFEffectType_Friction_ID, &ffeffect, &gFrictionEffectRef);
FFEffectDownload(gFrictionEffectRef);
FFEffectStart(gFrictionEffectRef, 1, 0);
}
else
{
FFEffectSetParameters(gFrictionEffectRef,&ffeffect,FFEP_TYPESPECIFICPARAMS+FFEP_GAIN);
FFEffectStatusFlag pFlags;
FFEffectGetEffectStatus(gFrictionEffectRef,&pFlags);
if(!pFlags&FFEGES_PLAYING)
FFEffectStart(gFrictionEffectRef, 1, 0);
}
ffcondition.lOffset=0;
ffcondition.lPositiveCoefficient=FF_FFNOMINALMAX*gConfig->ffbIntensity*alignment;
ffcondition.lNegativeCoefficient=FF_FFNOMINALMAX*gConfig->ffbIntensity*alignment;
ffcondition.dwPositiveSaturation=FF_FFNOMINALMAX*gConfig->ffbIntensity*alignment;
ffcondition.dwNegativeSaturation=FF_FFNOMINALMAX*gConfig->ffbIntensity*alignment;
ffcondition.lDeadBand=0;
if(gAlignEffectRef==NULL)
{
FFDeviceCreateEffect(gFFDeviceRef, kFFEffectType_Spring_ID, &ffeffect, &gAlignEffectRef);
FFEffectDownload(gAlignEffectRef);
FFEffectStart(gAlignEffectRef, 1, 0);
}
else
{
FFEffectSetParameters(gAlignEffectRef,&ffeffect,FFEP_TYPESPECIFICPARAMS+FFEP_GAIN);
FFEffectStatusFlag pFlags;
FFEffectGetEffectStatus(gAlignEffectRef,&pFlags);
if(!pFlags&FFEGES_PLAYING)
FFEffectStart(gAlignEffectRef, 1, 0);
}
}
}
void FFBiShockDirect(float lMag,float rMag)
{
/* if(gIShockIIFFB&&gConfig->iShockFFB&&gFrameCount>gIShockIIFFBBlock)
{
iS2F_MotorCmd_t directCmd;
directCmd.leftMotorMagnitude=lMag*10;
directCmd.rightMotorMagnitude=rMag*10;
iS2F_SimpleDirectControl(giShockList[0],&directCmd);
}*/
}
void FFBStop()
{
/* if(gIShockIIFFB&&gConfig->iShockFFB)
{
iS2F_MotorCmd_t directCmd;
directCmd.leftMotorMagnitude=0;
directCmd.rightMotorMagnitude=0;
iS2F_SimpleDirectControl(giShockList[0],&directCmd);
}*/
if(gFFB&&gConfig->ffb)
{
FFEffectStop(gGroundRumbleEffectRef);
FFEffectStop(gJoltEffectRef);
FFEffectStop(gFrictionEffectRef);
FFEffectStop(gAlignEffectRef);
FFEffectStop(gEngineEffectRef);
gGroundRumbleEffectRef = NULL;
gJoltEffectRef = NULL;
gFrictionEffectRef = NULL;
gAlignEffectRef = NULL;
gEngineEffectRef = NULL;
}
}
//Dispose*/ Control structures
void ControlExit()
{
/* if(gInputHID)
{
HIDReleaseDeviceList();
TearDownHIDCFM();
}
/* if(gIShockIIFFB)
{
FFBStop();
iS2F_Final();
}*/
}
void CalibrateAxis(int id)
{
while(GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter));
int controller=-1;
for(int i=0;i<gNumControllers;i++)
if(gControllers[i].device->vendorID==gConfig->axis[id].axisControllerID1&&gControllers[i].device->productID==gConfig->axis[id].axisControllerID2)
controller=i;
int element=gConfig->axis[id].axisElementID;
if(controller<gNumControllers&&controller>=0)
{
gConfig->axis[id].max=gConfig->axis[id].mid+1;
gConfig->axis[id].min=gConfig->axis[id].mid-1;
while(!(GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter)))
{
SInt32 value=HIDGetElementValue(gControllers[controller].device,gControllers[controller].elements[element]);
if(value<gConfig->axis[id].min)gConfig->axis[id].min=value;
if(value>gConfig->axis[id].max)gConfig->axis[id].max=value;
}
}
}
#define kAxisMaxZone 0.9
//read an analogue axis
float GetAxisInput(int id)
{
if(gConfig->axis[id].axisControllerID1==-1&&gConfig->axis[id].axisControllerID2==-1)
{
//mouse pos
tVector2 p=GetMousePos();
if(gConfig->axis[id].axisElementID==1)
return p.x;
if(gConfig->axis[id].axisElementID==2)
return p.y;
}
if(gConfig->axis[id].axisControllerID1&&gInputHID){
int controller=-1;
for(int i=0;i<gNumControllers;i++)
if(gControllers[i].device->vendorID==gConfig->axis[id].axisControllerID1&&gControllers[i].device->productID==gConfig->axis[id].axisControllerID2)
controller=i;
int element=gConfig->axis[id].axisElementID;
if(controller<gNumControllers&&controller>=0)
if(element<gControllers[controller].numElements&&element>=0)
{
SInt32 value=HIDGetElementValue(gControllers[controller].device,gControllers[controller].elements[element]);
int min=gConfig->axis[id].mid-(gConfig->axis[id].mid-gConfig->axis[id].min)*kAxisMaxZone;
int max=gConfig->axis[id].mid-(gConfig->axis[id].mid-gConfig->axis[id].max)*kAxisMaxZone;
float ax;
if(id>=kInputThrottleAxis)
{
if(value<(gConfig->axis[id].max-gConfig->axis[id].min)*gConfig->axis[id].deadzone*0.5)
ax=0;
else
ax=(value-(gConfig->axis[id].max-gConfig->axis[id].min)*gConfig->axis[id].deadzone*0.5)/((gConfig->axis[id].max-min)*(1-0.5*gConfig->axis[id].deadzone));
}
else
{
if(fabs(gConfig->axis[id].mid-value)<(gConfig->axis[id].max-gConfig->axis[id].min)*gConfig->axis[id].deadzone)
ax=0;
else if(value>gConfig->axis[id].mid)
ax=(value-(gConfig->axis[id].mid+(gConfig->axis[id].max-gConfig->axis[id].min)*gConfig->axis[id].deadzone))/((gConfig->axis[id].mid-max)*(1-0.5*gConfig->axis[id].deadzone));
else
ax=(value-(gConfig->axis[id].mid-(gConfig->axis[id].max-gConfig->axis[id].min)*gConfig->axis[id].deadzone))/((min-gConfig->axis[id].mid)*(1-0.5*gConfig->axis[id].deadzone));
}
if(ax>1)ax=1;
else if(ax<-1)ax=-1;
return ax;
}
}
return 0;
}
//read a digital input
int GetButtonInput(int id)
{
if(gInputChatMode)
return false;
//is the key pressed?
int key=gSystemSuspended?false:IsPressed(gConfig->keys[id].keyID);
//is the HID button pressed?
if(gConfig->axis[id].axisControllerID1==-1&&gConfig->axis[id].axisControllerID2==-1)
if(Button())
key=true;
if(gConfig->keys[id].controllerID1&&gInputHID)
{
int controller=-1;
for(int i=0;i<gNumControllers;i++)
if(gControllers[i].device->vendorID==gConfig->keys[id].controllerID1&&gControllers[i].device->productID==gConfig->keys[id].controllerID2)
controller=i;
int element=gConfig->keys[id].elementID;
if(controller<gNumControllers&&controller>=0)
if(element<gControllers[controller].numElements&&element>=0)
return key||HIDGetElementValue(gControllers[controller].device,gControllers[controller].elements[element]);
}
return key;
}
int gInterfaceKeys[kInterfaceNumKeys]={0x00,0x7e,0x7d,0x7b,0x7c,0x31,0x24,0x4c,0x35,0x07,0x33,0x37,0x3a,0x01,0x0f,0x0c,0xff};
int GetInterfaceKey(int id)
{
if(id==kInterfaceMouseDown)
return gSystemSuspended?false:Button();
else
return gSystemSuspended?false:IsPressed(gInterfaceKeys[id]);
}
static void GetElementName (pRecDevice pDevice,pRecElement pElement, char *strElementName)
{
if(!HIDGetElementNameFromVendorProductUsage (pDevice->vendorID, pDevice->productID, pElement->usagePage, pElement->usage,strElementName))
{
// set name from vendor id/product id look up
HIDGetElementNameFromVendorProductCookie (pDevice->vendorID, pDevice->productID, (long) pElement->cookie, strElementName);
if (!*strElementName) { // if no name
char buffer[1024];
HIDGetUsageName (pElement->usagePage, pElement->usage,buffer);
if (!*buffer) // if not usage
sprintf (strElementName, "Unknown");
else
sprintf(strElementName,"%s %s",pDevice->product,buffer);
}
}
}
//used to user-configure input. if any key or HID button is pressed,
//this changes the according ID and Identifier string.
void GetInput(tKeyConfig *keyConfig)
{
//FlushEvents(keyDownMask,0);
int key=-1;
do{
for(int i=0;i<128;i++)
if(IsPressed(i))
if(i!=0x35&&i!=0x33)
key=i;
else
{
if(i==0x33)
{
keyConfig->controllerID1=0;
keyConfig->controllerID2=0;
keyConfig->elementID=0;
strcpy(keyConfig->controllerIdentifier,"");
keyConfig->keyID=-1;
strcpy(keyConfig->identifier,"<none>");
}
FlushEvents(keyDownMask|mDownMask,0);
FlushKeys();
return;
}
if(gInputHID)
for(int j=0;j<gNumControllers;j++)
for(int i=0;i<gControllers[j].numElements;i++)
if(gControllers[j].elements[i])
if(gControllers[j].elements[i]->type==kIOHIDElementTypeInput_Button)
if(HIDGetElementValue(gControllers[j].device,gControllers[j].elements[i]))
{
keyConfig->controllerID1=gControllers[j].device->vendorID;
keyConfig->controllerID2=gControllers[j].device->productID;
keyConfig->elementID=i;
char elementName[256];
GetElementName(gControllers[j].device,gControllers[j].elements[i],elementName);
// sprintf(keyConfig->controllerIdentifier,"%s: %s",gControllers[j].device->product,elementName);
strcpy(keyConfig->controllerIdentifier,elementName);
return;
}
if(Button()&&!StillDown())
{
keyConfig->controllerID1=-1;
keyConfig->controllerID2=-1;
keyConfig->elementID=1;
strcpy(keyConfig->controllerIdentifier,"Mouse Button");
FlushEvents(keyDownMask|mDownMask,0);
FlushKeys();
return;
}
}while(key==-1);
int clear;
do{
clear=true;
for(int i=0;i<128;i++)
if(IsPressed(i))
clear=false;
}while(!clear);
EventRecord evt;
Str255 str;
GetIndString(str,128,key+1);
int len=str[0];
BlockMoveData(str+1,str,255);
str[len]='\0';
if(str[0])
strcpy(keyConfig->identifier,(char*)str);
else
{
strcpy(keyConfig->identifier,"unknown key");
while(WaitNextEvent(keyUpMask,&evt,1,nil))
{
keyConfig->identifier[0]=evt.message&charCodeMask;
if(keyConfig->identifier[0]>='a'&&keyConfig->identifier[0]<='z')
keyConfig->identifier[0]+='A'-'a';
keyConfig->identifier[1]='\0';
}
}
keyConfig->keyID=key;
FlushEvents(keyDownMask|mDownMask,0);
FlushKeys();
}
//used to user-configure input. if any HID axis is moved,
//this changes the according ID and Identifier string.
void GetAxis(tAxisConfig *axis,bool allowVendor)
{
tVector2 basep=GetMousePos();
float **values=(float**)NewPtr(sizeof(float)*gNumControllers);
for(int j=0;j<gNumControllers;j++)
{
values[j]=(float*)NewPtr(sizeof(float)*gControllers[j].numElements);
for(int i=0;i<gControllers[j].numElements;i++)
if(gControllers[j].elements[i]->type!=kIOHIDElementTypeInput_Button)
values[j][i]=HIDGetElementValue(gControllers[j].device,gControllers[j].elements[i]);
}
int key=-1;
do{
long maxDiff=0;
for(int i=0;i<128;i++)
if(IsPressed(i))
key=i;
if(key==0x33)
{
axis->axisControllerID1=0;
axis->axisControllerID2=0;
axis->axisElementID=0;
strcpy(axis->axisIdentifier,"<none>");
}
for(int j=0;j<gNumControllers;j++)
for(int i=0;i<gControllers[j].numElements;i++)
if(gControllers[j].elements[i]->usagePage!=kHIDPage_VendorDefinedStart||allowVendor)
if(gControllers[j].elements[i]->type!=kIOHIDElementTypeInput_Button)
if(abs(values[j][i]-HIDGetElementValue(gControllers[j].device,gControllers[j].elements[i]))>0)
{
maxDiff=abs(values[j][i]-HIDGetElementValue(gControllers[j].device,gControllers[j].elements[i]));
axis->axisControllerID1=gControllers[j].device->vendorID;
axis->axisControllerID2=gControllers[j].device->productID;
axis->axisElementID=i;
axis->min=gControllers[j].elements[i]->min;
axis->max=gControllers[j].elements[i]->max;
axis->mid=(axis->min+axis->max)/2;
char elementName[256];
GetElementName(gControllers[j].device,gControllers[j].elements[i],elementName);
//sprintf(axis->axisIdentifier,"%s: %s",gControllers[j].device->product,elementName);
strcpy(axis->axisIdentifier,elementName);
}
if(maxDiff)
{
for(int j=0;j<gNumControllers;j++)
DisposePtr((Ptr)(values[j]));
DisposePtr((Ptr)values);
FlushEvents(keyDownMask|mDownMask,0);
FlushKeys();
return;
}
tVector2 p=GetMousePos();
if(~(p-basep)>0.1)
{
axis->axisControllerID1=-1;
axis->axisControllerID2=-1;
axis->axisElementID=fabs(p.x-basep.x)>fabs(p.y-basep.y)?1:2;
sprintf(axis->axisIdentifier,"Mouse %c Axis",'W'+axis->axisElementID);
for(int j=0;j<gNumControllers;j++)
DisposePtr((Ptr)(values[j]));
DisposePtr((Ptr)values);
FlushEvents(keyDownMask|mDownMask,0);
FlushKeys();
return;
}
}while(key!=0x24&&key!=0x4c&&key!=0x35);
FlushEvents(keyDownMask|mDownMask,0);
FlushKeys();
for(int j=0;j<gNumControllers;j++)
DisposePtr((Ptr)(values[j]));
DisposePtr((Ptr)values);
}
tVector2 GetMousePos()
{
Point p;
GetMouse(&p);
return Vector(-(2.0*p.h/gConfig->screenXSize)+1,(2.0*p.v/gConfig->screenYSize)-1);
}

116
source/macerror.cpp Normal file
View File

@ -0,0 +1,116 @@
#include <stdio.h>
#ifndef __TARGET_TOOLAPP
#include "screen.h"
#endif
/*
typedef struct
{
unsigned long fSaveSP,fSaveCR,fSaveLR,fResv0,fResv1,fSaveRTOC;
} tStackFrame;
asm unsigned long GetCallersSP( void )
{
lwz r3,0(SP)
blr
}
Str255 *FindRoutineName( unsigned long *codeAddress )
{
// look for the callers' "blr" instruction
// assume it's going to be within 8K instructions of the call site.
// this may or may not work for your code, worked for me.
// the MacsBug name follows shortly after the 'blr'
// and at a fixed offset that I figured out empirically.
int i;
for( i=0; i<8000; i++)
{
if (codeAddress[i] == 0x4E800020)
{
// found the 'blr'
if (codeAddress[i+1] == 0x00000000)
{
return (Str255*) ( ((unsigned char*)&codeAddress[i])+21 );
}
}
}
return nil;
}
inline void GetCallerName(Str255 callerName)
{
tStackFrame *frame = (tStackFrame*) GetCallersSP();
unsigned long *address = (unsigned long*)frame->fSaveLR;
Str255 *name = FindRoutineName( address );
if(name)
BlockMoveData(*name,callerName,(*name)[0]+1);
else
BlockMoveData("\p<Anonymous Routine>",callerName,20);
}
*/
void ShowAlert(char *str1, char *str2)
{
#ifndef __TARGET_TOOLAPP
ScreenExit();
#endif
AlertStdAlertParamRec alertParam={
false,false,nil,
"\pExit",
nil,
nil,
kAlertStdAlertOKButton,
0,
kWindowDefaultPosition};
Str255 pStr1,pStr2;
CopyCStringToPascal(str1,pStr1);
CopyCStringToPascal(str2,pStr2);
short hit;
OSErr err=StandardAlert(kAlertStopAlert,
pStr1,
pStr2,
&alertParam,
&hit);
if(err)ExitToShell();
}
void FailWithErrorString(char *string)
{
ShowAlert(string,"");
ExitToShell();
}
void PrintConsoleString(const char *fmt, ...)
{
va_list ap; // Pointer To List Of Arguments
if (fmt == NULL) // If There's No Text
return; // Do Nothing
char error[256];
va_start(ap, fmt); // Parses The String For Variables
vsprintf(error,fmt,ap); // And Converts Symbols To Actual Numbers
va_end(ap); // Results Are Stored In Text
/*
Str255 pStr;
CopyCStringToPascal(error,pStr);
DebugStr(pStr); */
printf("%s\n",error);
}
void HandleError(int code)
{
if(code)
{
char str1[80],str2[80];
char caller[80]="/p";
//GetCallerName((unsigned char*)caller);
CopyPascalStringToC((unsigned char*)caller,caller);
sprintf(str1,"A fatal error has occurred!!");
sprintf(str2,"Error ID=%d",code);// in function %s",code,caller);
ShowAlert(str1,str2);
ExitToShell();
}
}

397
source/macfileio.cpp Executable file
View File

@ -0,0 +1,397 @@
//macfileio.cpp
//mac-specific file handling code.
#include <string.h>
#include <stdlib.h>
#include "fileio.h"
#include "gamemem.h"
#include "error.h"
#include "config.h"
#include "screen.h"
extern "C"{
#include "compress.h"
}
#define kFileNotPackaged -1
//System specific unique file locator
typedef struct{
SInt16 vRefNum;
SInt16 unused;
SInt32 dirID;
Str255 pName;
unsigned int packageOffset,packageSize;
} tFileSystemLocator;
//fills an FSSpecPtr with the file system information for
//the host application's Bundle directory
OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
{
FSRef location;
CFBundleRef refMainBundle = NULL;
CFURLRef refMainBundleURL = NULL;
refMainBundle = CFBundleGetMainBundle();
refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
CFURLGetFSRef(refMainBundleURL,&location);
return FSGetCatalogInfo(&location,kFSCatInfoNone,NULL,NULL,theFSSpecPtr,NULL);
}
typedef struct{
unsigned int offset,unPackedSize,packedSize;
char name[256];
}tPackFileHeaderEntry;
typedef struct{
char magic[8];
int numEntries;
int replaceFlag,unused2,unused3;
tPackFileHeaderEntry entries[];
}tPackFileHeader;
#define kMagicString "R3Dl1n3"
tFileRef SimpleFileGetReference(char *name,tFileTableEntry *fileTable,int fileTableSize)
{
for(int i=0;i<fileTableSize;i++)
if(_stricmp(fileTable[i].name,name)==0)
return i;
return -1;
}
void IteratePackage(SInt16 vRefNum,SInt32 dirID,Str255 name,tFileTableEntry *fileTable,int *fileTableSize,int maxSize)
{
short ref;
HandleError(HOpenDF(vRefNum,dirID,name,fsCurPerm,&ref));
long headerSize=sizeof(tPackFileHeader);
long eof;
HandleError(GetEOF(ref,&eof));
if(eof<headerSize)
return;
tPackFileHeader *header=(tPackFileHeader*)NewPtr(headerSize);
HandleError(FSRead(ref,&headerSize,header));
if(_stricmp(header->magic,kMagicString))
return;
int numEntries=EndianU32_BtoN(header->numEntries);
DisposePtr((Ptr)header);
HandleError(SetFPos(ref,fsFromStart,0));
headerSize=sizeof(tPackFileHeader)+sizeof(tPackFileHeaderEntry)*numEntries;
header=(tPackFileHeader*)NewPtr(headerSize);
HandleError(FSRead(ref,&headerSize,header));
for(int i=0;i<numEntries;i++)
if(*fileTableSize<maxSize)//is there still space in the file table?
{
int exists=SimpleFileGetReference(header->entries[i].name,fileTable,*fileTableSize);
int replaceable=false;
if(exists)
{
char *extension=FileGetExtension(i);
if(extension)
replaceable=(_stricmp(extension,kFileTypeCarDefinition)&&_stricmp(extension,kFileTypeMapDefinition));
else
replaceable=true;
}
if(exists==-1||(header->replaceFlag&&replaceable))
{
tFileRef ref;
if(exists==-1)
ref=(*fileTableSize)++;
else
ref=exists;
//add file record to file reference table
fileTable[ref].loaded=false;
fileTable[ref].parsed=false;
fileTable[ref].size=EndianU32_BtoN(header->entries[i].unPackedSize);
((tFileSystemLocator*)&(fileTable[ref].fsLoc))->vRefNum=vRefNum;
((tFileSystemLocator*)&(fileTable[ref].fsLoc))->dirID=dirID;
BlockMove(name,((tFileSystemLocator*)&(fileTable[ref].fsLoc))->pName,name[0]+1);
((tFileSystemLocator*)&(fileTable[ref].fsLoc))->packageOffset=EndianU32_BtoN(header->entries[i].offset);
((tFileSystemLocator*)&(fileTable[ref].fsLoc))->packageSize=EndianU32_BtoN(header->entries[i].packedSize);
strcpy(fileTable[ref].name,header->entries[i].name);
}
}
else
{
ShowAlert("Too many files in Plug-ins folder.","Please remove some files from your Plug-ins folder, and restart Redline.");
ExitToShell();
}
DisposePtr((Ptr)header);
HandleError(FSClose(ref));
}
void AddFile(SInt16 vRefNum,SInt32 dirID,const Str255 name,tFileTableEntry *fileTable,int *fileTableSize,int maxSize)
{
char cName[256];
CopyPascalStringToC(name,cName);
if(*fileTableSize<maxSize)//is there still space in the file table?
if(SimpleFileGetReference(cName,fileTable,*fileTableSize)==-1)
{
//add file record to file reference table
fileTable[*fileTableSize].loaded=false;
fileTable[*fileTableSize].parsed=false;
fileTable[*fileTableSize].tagged=false;
((tFileSystemLocator*)&(fileTable[*fileTableSize].fsLoc))->vRefNum=vRefNum;
((tFileSystemLocator*)&(fileTable[*fileTableSize].fsLoc))->dirID=dirID;
BlockMove(name,((tFileSystemLocator*)&(fileTable[*fileTableSize].fsLoc))->pName,name[0]+1);
((tFileSystemLocator*)&(fileTable[*fileTableSize].fsLoc))->packageOffset=kFileNotPackaged;
strcpy(fileTable[*fileTableSize].name,cName);
(*fileTableSize)++;
}
else
{
// if(_stricmp(cName,".DS_Store"))
// PrintConsoleString("File duplicate!: %s\n",cName);
}
else
{
ShowAlert("Too many files in Plug-ins folder.","Please remove some files from your Plug-ins folder, and restart Redline.");
ExitToShell();
}
}
#define IsPackage(i) (_stricmp(cName+strlen(cName)-strlen(kFileTypePackageFile),kFileTypePackageFile)==0)
//recursivly add all files in a directory and subdirectories
//to the file reference table
void IterateDirectoryLevel(SInt16 vRefNum,SInt32 dirID,tFileTableEntry *fileTable,int *fileTableSize,int maxSize)
{
CInfoPBRec cinfo;
Str255 name;
for(int i=1; ;i++)
{
//Get info about the next file in the folder
cinfo.hFileInfo.ioVRefNum = vRefNum;
cinfo.hFileInfo.ioDirID = dirID;
cinfo.hFileInfo.ioNamePtr = name;
cinfo.hFileInfo.ioFDirIndex = i;
OSErr error=PBGetCatInfoSync(&cinfo);
char cName[256];
CopyPascalStringToC(name,cName);
//no more files?
if(error==fnfErr)break;
HandleError(error);
//is this a directory?
if(cinfo.hFileInfo.ioFlAttrib&kioFlAttribDirMask)
//recursively process subdirectory
IterateDirectoryLevel(vRefNum,cinfo.dirInfo.ioDrDirID,fileTable,fileTableSize,maxSize);
#ifndef __PACKER
else if(IsPackage(cName))
IteratePackage(vRefNum,dirID,name,fileTable,fileTableSize,maxSize);
#endif
else
AddFile(vRefNum,dirID,name,fileTable,fileTableSize,maxSize);
}
}
//declared in fileio.cpp
int FileTableCompare(const void *a,const void *b);
SInt32 GetDirID(FSSpec *spec)
{
CInfoPBRec cinfo;
cinfo.hFileInfo.ioVRefNum = spec->vRefNum;
cinfo.hFileInfo.ioDirID = spec->parID;
cinfo.hFileInfo.ioNamePtr = spec->name;
cinfo.hFileInfo.ioFDirIndex = 0;
OSErr error=PBGetCatInfoSync(&cinfo);
return cinfo.dirInfo.ioDrDirID;
}
#define kPlugInDirName "Plug-Ins"
#define kPlugInDirPName "\pPlug-Ins"
//Initialize file reference table
void FileInitFileTable(tFileTableEntry *fileTable,int maxSize,int *fileTableSize,int reInit)
{
FSSpec spec;
OSErr err;
SInt16 vRefNum; //application's vRefNum
SInt32 dirID; //application's directory ID
if(!reInit)
*fileTableSize=0;
#ifdef __TARGET_PACKER
spec=packFolderFSS;
#else
#ifdef __TARGET_TOOLAPP
err=FSMakeFSSpec(0,0,"\p::::Redline.app",&spec);
if(err==fnfErr)
{
err=FSMakeFSSpec(0,0,"\p:::::Redline.app",&spec);
if(err==fnfErr)
{
ShowAlert("Can't find Redline","Please run the Tool Chest apps from the same folder Redline is in, or from the Tool Chest folder inside the Redline folder.");
ExitToShell();
}
}
#else
//get FSSpec for application's Bundle
GetApplicationBundleFSSpec(&spec);
#endif
#endif
//process file's in application bundle
//and subdirectories into file reference table
IterateDirectoryLevel(spec.vRefNum,GetDirID(&spec),fileTable,fileTableSize,maxSize);
#ifndef __TARGET_PACKER
//process Plug-In folder if it exists
err=FSMakeFSSpec(spec.vRefNum,spec.parID,kPlugInDirPName,&spec);
if(err!=fnfErr)
IterateDirectoryLevel(spec.vRefNum,GetDirID(&spec),fileTable,fileTableSize,maxSize);
//get reference to Preferences folder
SInt16 prefVRefNum;
SInt32 prefDirID;
HandleError(FindFolder(kOnAppropriateDisk,kPreferencesFolderType,kCreateFolder,&prefVRefNum,&prefDirID));
//see if Redline folder exists
/* FSSpec configFolderSpec;
err=FSMakeFSSpec(prefVRefNum,prefDirID,kConfigDirPName,&configFolderSpec);
SInt32 configFolderDirID;
//if not create it
if(err==fnfErr)
HandleError(FSpDirCreate(&configFolderSpec,smSystemScript,&configFolderDirID));
//otherwise get the dirID
else
configFolderDirID=GetDirID(&configFolderSpec);
*/
//see if config file exists
FSSpec configSpec;
err=FSMakeFSSpec(prefVRefNum,prefDirID,kConfigFilePName,&configSpec);
//if not create it
if(err==fnfErr)
FSpCreate(&configSpec,'????','????',smSystemScript);
//Add Config folder to file table
AddFile(prefVRefNum,prefDirID,kConfigFilePName,fileTable,fileTableSize,maxSize);
#endif
//and sort the filetable by file names
if(!reInit)
qsort(fileTable,*fileTableSize,sizeof(tFileTableEntry),&FileTableCompare);
printf("%d files.\n",*fileTableSize);
#ifndef __TARGET_PACKER
if(!FileGetSize(FileGetReference(kConfigFileName)))
{
tFileRef defaults=FileGetReference(kConfigDefault16Name);
int vram=GetVRAMSize();
if(vram>16*1024*1024)
defaults=FileGetReference(kConfigDefault32Name);
if(vram>32*1024*1024)
defaults=FileGetReference(kConfigDefault64Name);
FileSetData(FileGetReference(kConfigFileName),FileGetDataPtr(defaults));
}
#endif
}
//load a file's data
int FileLoadData(tFileRef fileRef)
{
short ref;
HandleError(HOpenDF(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->vRefNum
,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->dirID
,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->pName,fsCurPerm,&ref));
long eof;
HandleError(GetEOF(ref,&eof));
if(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->packageOffset==kFileNotPackaged)
{
gFileTable[fileRef].data=NewPtr(eof);
gFileTable[fileRef].size=eof;
HandleError(FSRead(ref,&eof,gFileTable[fileRef].data));
}
else
{
long packedSize=((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->packageSize;
Ptr packedData=NewPtr(packedSize);
gFileTable[fileRef].data=NewPtr(gFileTable[fileRef].size);
unsigned long offset=((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->packageOffset;
HandleError(SetFPos(ref,fsFromStart,offset));
HandleError(FSRead(ref,&packedSize,packedData));
compress_identity *iden;
xcompress(COMPRESS_ACTION_IDENTITY,0,0,0,0,0,(ULONG*)&iden);
Ptr workBuffer=NewPtr(iden->memory);
UInt32 ignore;
xcompress(COMPRESS_ACTION_DECOMPRESS,(UBYTE*)workBuffer,(UBYTE*)packedData,packedSize,gFileTable[fileRef].size,(UBYTE*)gFileTable[fileRef].data,(ULONG*)&ignore);
DisposePtr(workBuffer);
DisposePtr(packedData);
}
HandleError(FSClose(ref));
return true;
}
void *FileGetPartialDataPtr(tFileRef fileRef,int offset,int size)
{
if(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->packageOffset==kFileNotPackaged)
{
short ref;
HandleError(HOpenDF(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->vRefNum
,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->dirID
,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->pName,fsCurPerm,&ref));
void *data=NewPtr(size);
HandleError(SetFPos(ref,fsFromStart,offset));
long readSize=size;
HandleError(FSRead(ref,&readSize,data));
HandleError(FSClose(ref));
return data;
}
else
FailWithErrorString("Cannot get partial data from packaged file.");
}
//write a file's data
void FileStoreData(tFileRef fileRef)
{
if(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->packageOffset==kFileNotPackaged)
{
short ref;
HandleError(HOpenDF(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->vRefNum
,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->dirID
,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->pName,fsCurPerm,&ref));
long eof=gFileTable[fileRef].size;
HandleError(SetEOF(ref,eof));
HandleError(FSWrite(ref,&eof,gFileTable[fileRef].data));
HandleError(FSClose(ref));
}
else
FailWithErrorString("Cannot write to package file!");
}
void FileAppendData(tFileRef fileRef,void *data,int size)
{
if(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->packageOffset==kFileNotPackaged)
{
short ref;
HandleError(HOpenDF(((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->vRefNum
,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->dirID
,((tFileSystemLocator*)&(gFileTable[fileRef].fsLoc))->pName,fsCurPerm,&ref));
long writeSize=size;
HandleError(SetFPos(ref,fsFromLEOF,0));
HandleError(FSWrite(ref,&writeSize,data));
HandleError(FSClose(ref));
}
else
FailWithErrorString("Cannot write to package file!");
}

490
source/maclocaltracker.cpp Normal file
View File

@ -0,0 +1,490 @@
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "error.h"
#include "tracker.h"
#include "gamemem.h"
#define assert(condition) ((condition) ? ((void) 0) : PrintConsoleString("%s@%s:%s",#condition,__FILE__, __LINE__))
#define kMaxLocalGames 32
int gNumLocalGames=0;
int gLocalGameListUpdate=0;
tGameListEntry gLocalGames[kMaxLocalGames];
static void
MyResolveCallback(CFNetServiceRef service, CFStreamError* error, void* info);
#define kServiceType CFSTR("_redline._udp.")
#define kMyDefaultDomain CFSTR("local.")
CFMutableArrayRef gServiceArrayRef;
CFMutableDictionaryRef gServiceDictionary;
CFNetServiceBrowserRef gServiceBrowserRef = NULL;
CFNetServiceRef gRegisteredService = NULL;
CFNetServiceRef gServiceBeingResolved = NULL;
UInt32 gNextNameIndexToResolve = 0;
CFStringRef gTextRecord;
Boolean gDone;
Boolean gContinue;
Boolean gResolve;
Boolean gBrowserTaskActive = FALSE;
Boolean gResolveProcessActive = FALSE;
Boolean gTaskRegistered = FALSE;
void InitLocalTracker()
{
OSStatus err = noErr;
gServiceDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, NULL);
if (gServiceDictionary == NULL)
err = coreFoundationUnknownErr;
if (err == noErr)
{
gServiceArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if (gServiceDictionary == NULL)
{
err = coreFoundationUnknownErr;
}
}
//if (err == noErr)
// err = LoadNetServicesForCFM();
//return err;
}
static void
MyCancelRegistration()
{
if(gRegisteredService != NULL)
{
CFNetServiceUnscheduleFromRunLoop(gRegisteredService, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
CFNetServiceSetClient(gRegisteredService, NULL, NULL);
CFNetServiceCancel(gRegisteredService);
CFRelease(gRegisteredService);
gRegisteredService = NULL;
}
}
static void
MyRegisterCallback(CFNetServiceRef theService, CFStreamError* error, void* info)
{
if (error->domain == kCFStreamErrorDomainNetServices)
{
switch(error->error)
{
case kCFNetServicesErrorCollision:
/* Somebody else on the network has registered a service with the same name and type
as the service we tried to register
*/
PrintConsoleString("A kCFNetServicesErrorCollision occured - will quit now\n");
break;
default:
/*
some other error occurred
*/
PrintConsoleString("Some other kCFNetServicesError occurred %d will quit now\n", error->error);
break;
}
// as an error occurred, clean up the CFNetServiceRef object
MyCancelRegistration();
// you don't really need to quit, but the following boolean will cause the main to quit.
gDone = true;
}
return;
}
static void
MyCancelResolve()
{
assert(gServiceBeingResolved != NULL);
CFNetServiceUnscheduleFromRunLoop(gServiceBeingResolved, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
CFNetServiceSetClient(gServiceBeingResolved, NULL, NULL);
CFNetServiceCancel(gServiceBeingResolved);
CFRelease(gServiceBeingResolved);
gServiceBeingResolved = NULL;
return;
}
static void
MyResolveService(CFStringRef name, CFStringRef type, CFStringRef domain)
{
CFNetServiceClientContext clientContext = { 0, NULL, NULL, NULL, NULL };
CFStreamError error;
assert(name != NULL);
assert(type != NULL);
assert(domain != NULL);
if (gServiceBeingResolved)
{
/* This app only allows one resolve at a time, but CFNetServices places no restrictions on the number of
simultaneous resolves. Because most resolves will happen instantaneously after calling CFNetServiceResolve,
if we end up canceling a previous resolve, it's probably because the previous service became unreachable. */
PrintConsoleString("Resolve canceled\n");
MyCancelResolve();
}
gServiceBeingResolved = CFNetServiceCreate(kCFAllocatorDefault, domain, type, name, 0);
assert(gServiceBeingResolved != NULL);
CFNetServiceSetClient(gServiceBeingResolved, MyResolveCallback, &clientContext);
CFNetServiceScheduleWithRunLoop(gServiceBeingResolved, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
if (CFNetServiceResolve(gServiceBeingResolved, &error) == false)
{
// Something went wrong so lets clean up.
CFNetServiceUnscheduleFromRunLoop(gServiceBeingResolved, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
CFNetServiceSetClient(gServiceBeingResolved, NULL, NULL);
CFRelease(gServiceBeingResolved);
gServiceBeingResolved = NULL;
PrintConsoleString("CFNetServiceResolve returned (domain = %d, error = %ld)\n", error.domain, error.error);
}
return;
}
static void ContinueResolveProcess(void)
{
CFStringRef serviceNameRef;
if (gDone == true)
{
gResolveProcessActive = FALSE;
}
else
{
if (CFArrayGetCount(gServiceArrayRef) > gNextNameIndexToResolve)
{
(const void*)serviceNameRef = CFArrayGetValueAtIndex(gServiceArrayRef, gNextNameIndexToResolve++);
MyResolveService(serviceNameRef, kServiceType, kMyDefaultDomain);
}
else
gResolveProcessActive = FALSE;
}
}
#define U32Swap(value) ((value)=EndianU32_BtoN(value))
#define U16Swap(value) ((value)=EndianU16_BtoN(value))
static void
MyResolveCallback(CFNetServiceRef service, CFStreamError* error, void* info)
{
CFArrayRef addresses;
CFStringRef addressString;
CFStringRef serviceNameRef;
sockaddr *socketAddress;
sockaddr_in *socketAddress_in;
UInt32 inaddr;
UInt16 port;
char servicename[64];
CFIndex namelen = sizeof(servicename);
UInt32 index;
/* In situations where the service you're resolving is advertising on multiple interfaces,
like Ethernet and AirPort, your Resolve callback may be called twice, once for each IP address.
Chances are that both of these IP addresses represent the same service running on the same machine,
so we cancel the Resolve after getting the first callback because you only need one address to
connect to the service. However, it would also be possible that two different machines are
advertising the same service name, with one being on Ethernet and one on AirPort. In that
situation, one of the machines will be unreachable, or more likly, everytime we call Resolve,
we may connect to a different machine. The odds of this happening are extremely small. */
assert(service != NULL);
addresses = CFNetServiceGetAddressing(service);
assert(addresses != NULL);
serviceNameRef = CFNetServiceGetName(service);
assert(serviceNameRef != NULL);
if (CFStringGetCString(serviceNameRef, servicename, namelen, kCFStringEncodingMacRoman))
{
servicename[namelen]='\0';
for(int i=0;i<gNumLocalGames;i++)
if(_stricmp(servicename,gLocalGames[i].name)==0)
{
// Iterate through addresses until we find an IPv4 address
for (index = 0; index < CFArrayGetCount(addresses); index++)
{
socketAddress = (struct sockaddr *)CFDataGetBytePtr((__CFData*)CFArrayGetValueAtIndex(addresses, index));
if (socketAddress && socketAddress->sa_family == AF_INET)
break;
}
if (socketAddress)
{
switch(socketAddress->sa_family)
{
case AF_INET:
CFStringGetCString(serviceNameRef, servicename, namelen, kCFStringEncodingMacRoman);
socketAddress_in = (struct sockaddr_in *)socketAddress;
inaddr = *((UInt32*)(&socketAddress_in->sin_addr));
port = *((UInt16*)(&socketAddress_in->sin_port));
U32Swap(inaddr);
U16Swap(port);
sprintf(gLocalGames[i].host, "%d.%d.%d.%d:%d",inaddr>>24,(inaddr>>16)&0xFF,(inaddr>>8)&0xFF,inaddr&0xFF,port);
gLocalGames[i].loaded=true;
//PrintConsoleString("Got Host Info: %s",gLocalGames[i].host);
// Since we got an IPv4 address, this would be a good place to cancel the resolve.
gLocalGameListUpdate++;
MyCancelResolve();
return;
case AF_INET6:
PrintConsoleString("Resolver called with IPV6 address\n");
/* If we got here, it probably means that the "addresses" array only had one sockaddr in it and it
was IPv6. We don't cancel the resolve just yet since this sample expects to print out the IPV4 address.
Just continue and the resolver will call back with the IPV4 address instance. */
break;
}
}
}
}
// see if there are more entities to resolve
ContinueResolveProcess();
return;
}
static Boolean
MyRegisterService(CFStringRef name, CFStringRef type, CFStringRef domain, UInt32 port, CFStringRef txtRecord)
{
CFNetServiceClientContext context = {0, NULL, NULL, NULL, NULL };
CFStreamError error;
assert(name != NULL);
assert(type != NULL);
assert(domain != NULL);
/* As an alternative to specifying a "name" to register, you could use an empty string like
CFSTR(""), and that would cause the system to automatically substitute the "Computer Name"
from the Sharing preference panel. Another benefit of using an empty string is that the system
will automatically handle name collisions for us by appending a digit to the end of the name,
thus our Callback would never be called in the event of a name collision.
Beginning with Mac OS X 10.2.4, using an empty string will even handle situations
where the user changes the "Computer Name" in the preference panel. */
gRegisteredService = CFNetServiceCreate(kCFAllocatorDefault, domain, type, name, port);
assert(gRegisteredService != NULL);
// register the service asynchronously.
CFNetServiceSetClient(gRegisteredService, MyRegisterCallback, &context);
CFNetServiceScheduleWithRunLoop(gRegisteredService, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
gTaskRegistered = CFNetServiceRegister(gRegisteredService, &error);
if (gTaskRegistered == FALSE)
{
// a problem happened with calling CFNetServiceRegister so unschedule the service from
// the runloop
CFNetServiceUnscheduleFromRunLoop(gRegisteredService, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
CFNetServiceSetClient(gRegisteredService, NULL, NULL);
CFRelease(gRegisteredService);
gRegisteredService = NULL;
}
return gTaskRegistered;
}
static void StartResolveProcess(void)
{
CFStringRef serviceNameRef;
// Make sure that this process can't be entered multiple times
if (gResolveProcessActive == FALSE)
{
gResolveProcessActive = TRUE;
gNextNameIndexToResolve = 0;
if (CFArrayGetCount(gServiceArrayRef) > gNextNameIndexToResolve)
{
(const void*)serviceNameRef = CFArrayGetValueAtIndex(gServiceArrayRef, gNextNameIndexToResolve++);
MyResolveService(serviceNameRef, kServiceType, kMyDefaultDomain);
}
else
gResolveProcessActive = FALSE;
}
}
static void
MyAddService(CFNetServiceRef service, CFOptionFlags flags)
{
int referenceCount;
CFStringRef serviceNameRef;
char servicename[256];
CFIndex namelen = sizeof(servicename);
Boolean addName = FALSE;
/* You should do reference counting of each service because if the computer has two network
interfaces set up, like Ethernet and AirPort, you may get notified about the same service
twice, once from each interface. You probably don't want both items to be shown to the user. */
assert(service != NULL);
serviceNameRef = CFNetServiceGetName(service);
assert(serviceNameRef != NULL);
assert(gServiceDictionary != NULL);
if (CFStringGetCString(serviceNameRef, servicename, namelen, kCFStringEncodingMacRoman))
{
servicename[namelen]='\0';
for(int i=0;i<gNumLocalGames;i++)
if(_stricmp(servicename,gLocalGames[i].name)==0)
return;
strcpy(gLocalGames[gNumLocalGames].name,servicename);
gLocalGames[gNumLocalGames].numPlayers=-1;
gLocalGames[gNumLocalGames].loaded=false;
gLocalGames[gNumLocalGames].mapRef=kFileErr;
MyResolveService(serviceNameRef,kServiceType,kMyDefaultDomain);
gNumLocalGames++;
gLocalGameListUpdate++;
}
}
static void
MyRemoveService(CFNetServiceRef service, CFOptionFlags flags)
{
int referenceCount;
CFRange range;
CFIndex index;
CFStringRef serviceNameRef;
char servicename[256];
CFIndex namelen = sizeof servicename;
CFIndex result;
assert(service != NULL);
serviceNameRef = CFNetServiceGetName(service);
assert(serviceNameRef != NULL);
if (CFStringGetCString(serviceNameRef, servicename, namelen, kCFStringEncodingMacRoman))
{
servicename[namelen]='\0';
for(int i=0;i<gNumLocalGames;i++)
if(_stricmp(servicename,gLocalGames[i].name)==0)
{
MemoryMove(gLocalGames+i,gLocalGames+i+1,(gNumLocalGames-i-1)*sizeof(tGameListEntry));
gNumLocalGames--;
gLocalGameListUpdate++;
return;
}
}
}
static void
MyBrowserCallback(CFNetServiceBrowserRef browser, CFOptionFlags flags, CFTypeRef domainOrService, CFStreamError* error, void* info)
{
if (flags & kCFNetServiceFlagIsDomain)
return;
/* You should do as little work as possible while in the Browser Callback because the mDNSResponder will timeout
if you don't extract items out of the Mach message queue fast enough. If a timeout occurs, you will see
a message in the Console that looks like... "mDNSResponder[260]: 10531: Browser(_afpovertcp._tcp.local.)
stopped accepting Mach messages (browse)" and from that point, your browsing will no longer return any results. */
if (flags & kCFNetServiceFlagRemove)
{
MyRemoveService((CFNetServiceRef)domainOrService, flags);
}
else
{
MyAddService((CFNetServiceRef)domainOrService, flags);
}
return;
}
static OSStatus
MyStartBrowsingForServices(CFStringRef type, CFStringRef domain)
{
CFNetServiceClientContext clientContext = { 0, NULL, NULL, NULL, NULL };
CFStreamError error;
Boolean result;
OSStatus err = noErr;
assert(type != NULL);
assert(domain != NULL);
gServiceBrowserRef = CFNetServiceBrowserCreate(kCFAllocatorDefault, MyBrowserCallback, &clientContext);
if (gServiceBrowserRef == NULL)
{
err = memFullErr;
}
else
{
CFNetServiceBrowserScheduleWithRunLoop(gServiceBrowserRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
result = CFNetServiceBrowserSearchForServices(gServiceBrowserRef, domain, type, &error);
if (result == FALSE)
{
// Something went wrong so lets clean up.
CFNetServiceBrowserUnscheduleFromRunLoop(gServiceBrowserRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
CFRelease(gServiceBrowserRef);
gServiceBrowserRef = NULL;
PrintConsoleString("CFNetServiceBrowserSearchForServices returned (domain = %d, error = %ld)\n", error.domain, error.error);
err = error.error;
}
else
// indicate that the browser task is active
gBrowserTaskActive = TRUE;
}
return err;
}
static void
MyStopBrowsingForServices()
{
CFStreamError streamerror;
assert(gServiceBrowserRef != NULL);
CFNetServiceBrowserStopSearch(gServiceBrowserRef, &streamerror);
CFNetServiceBrowserUnscheduleFromRunLoop(gServiceBrowserRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
CFNetServiceBrowserInvalidate(gServiceBrowserRef);
CFRelease(gServiceBrowserRef);
gServiceBrowserRef = NULL;
assert(gServiceDictionary != NULL);
CFDictionaryRemoveAllValues(gServiceDictionary);
return;
}
void LocalTrackerStartAdvertising(char *gameName)
{
MyRegisterService(CFStringCreateWithCString(NULL,gameName,kCFStringEncodingMacRoman),kServiceType,kMyDefaultDomain,33333,NULL);
}
void LocalTrackerStopAdvertising()
{
MyCancelRegistration();
}
void LocalTrackerSearchGamesInit()
{
//HandleError()
MyStartBrowsingForServices(kServiceType,kMyDefaultDomain);
}
void LocalTrackerSearchGamesDone()
{
MyStopBrowsingForServices();
}

346
source/macscreen.cpp Normal file
View File

@ -0,0 +1,346 @@
//macscreen.cpp
//mac-specific code to access the screen device
#include <QuickTime/QuickTime.h>
#include <AGL/AGL.h>
#include "screen.h"
#include "config.h"
#include "error.h"
#include "textures.h"
AGLContext gOpenGLContext=NULL;
AGLContext SetupAGL( AGLDrawable window,GLint *attrib,int width, int height)
{
AGLPixelFormat format;
AGLContext context;
GLboolean ok;
GLint attrib2[256];
GDHandle screen;
if(window)
screen=GetGWorldDevice((GWorldPtr)window);
else
screen=DMGetFirstScreenDevice(true);
if(window==NULL)
{
int i=0;
while(attrib[i]!=AGL_NONE)
attrib2[i++]=attrib[i];
attrib2[i++]=AGL_FULLSCREEN;
//attrib2[i++]=AGL_NO_RECOVERY;
attrib2[i++]=AGL_NONE;
attrib=attrib2;
}
// Choose an rgb pixel format
format = aglChoosePixelFormat( &screen, 1, attrib );
if ( format == NULL )
{
printf("aglChoosePixelFormat: %s\n",aglErrorString(aglGetError()));
return NULL;
}
// Create an AGL context
context = aglCreateContext( format, gOpenGLContext );
if ( context == NULL )
{
printf("aglCreateContext: %s\n",aglErrorString(aglGetError()));
return NULL;
}
if(window){
ok = aglSetDrawable(context,window);
if ( !ok )
{
printf("aglSetDrawable: %s\n",aglErrorString(aglGetError()));
return NULL;
}
}
else{
ok = aglSetFullScreen (context,width,height,75,0);
if ( !ok )
{
ok = aglSetFullScreen (context,640,480,75,0);
if ( !ok )
{
printf("aglSetFullScreen: %s\n",aglErrorString(aglGetError()));
return NULL;
}
}
}
// Make the context the current context
ok = aglSetCurrentContext( context );
if ( !ok )
{
printf("aglSetCurrentContext: %s\n",aglErrorString(aglGetError()));
return NULL;
}
// The pixel format is no longer needed so get rid of it
aglDestroyPixelFormat( format );
return context;
}
//Initialize an OpenGL context using AGL
void InitGLContext()
{
CGrafPtr theScreen=NULL;
//is fullscreen mode enabled?
if(gConfig->fullscreen)
theScreen=NULL;
else
{
//get a Window Context
Rect boundsRect;
if(gConfig->windowY<40)
gConfig->windowY=40;
SetRect(&boundsRect,gConfig->windowX,gConfig->windowY,gConfig->windowX+gConfig->screenXSize,gConfig->windowY+gConfig->screenYSize);
WindowRef win=NewCWindow(0,&boundsRect,"\pRedline",true,0,(WindowRef)-1L,false,0);
if(!RectInRgn(&boundsRect,GetGrayRgn()))
MoveWindow(win,40,40,true);
theScreen=GetWindowPort(win);
SetPort(theScreen);
GetPortBounds(theScreen,&boundsRect);
Pattern black;
GetQDGlobalsBlack(&black);
FillRect(&boundsRect,&black);
HIWindowFlush(FrontWindow());
}
// Setup the OpenGL context
AGLContext ctx;
if(gConfig->fsaa)
{
GLint attrib[] = { AGL_RGBA, AGL_PIXEL_SIZE, gConfig->color32Bit?32:16,AGL_NO_RECOVERY,AGL_DOUBLEBUFFER, AGL_STENCIL_SIZE, 8,AGL_SAMPLE_BUFFERS_ARB,1,AGL_SAMPLES_ARB,gConfig->fsaa, AGL_NONE};
// GLint attrib[] = { AGL_RGBA, AGL_PIXEL_SIZE, gConfig->color32Bit?32:16,AGL_DOUBLEBUFFER, AGL_STENCIL_SIZE, 8,AGL_SAMPLE_BUFFERS_ARB,1,AGL_SAMPLES_ARB,gConfig->fsaa, AGL_NONE};
ctx=SetupAGL((AGLDrawable)theScreen,attrib,gConfig->screenXSize,gConfig->screenYSize);
}
else
{
GLint attrib[] = { AGL_RGBA, AGL_PIXEL_SIZE, gConfig->color32Bit?32:16,AGL_NO_RECOVERY,AGL_DOUBLEBUFFER, AGL_STENCIL_SIZE, 8, AGL_NONE};
// GLint attrib[] = { AGL_RGBA, AGL_PIXEL_SIZE, gConfig->color32Bit?32:16,AGL_DOUBLEBUFFER, AGL_STENCIL_SIZE, 8, AGL_NONE};
ctx=SetupAGL((AGLDrawable)theScreen,attrib,gConfig->screenXSize,gConfig->screenYSize);
}
if(!ctx)
{
if(gConfig->fullscreen)
{
gConfig->fullscreen=false;
InitGLContext();
}
else
FailWithErrorString("Couldn't Create Screen");
}
else
{
if(gOpenGLContext)
aglDestroyContext(gOpenGLContext);
gOpenGLContext=ctx;
}
}
static int numberForKey( CFDictionaryRef desc, CFStringRef key )
{
CFNumberRef value;
int num = 0;
if ( (value = (CFNumberRef)CFDictionaryGetValue(desc, key)) == NULL )
return 0;
CFNumberGetValue(value, kCFNumberIntType, &num);
return num;
}
void ScreenGetModes()
{
CFArrayRef modeList;
CFIndex i, cnt;
gVideoNumModes=0;
modeList = CGDisplayAvailableModes(kCGDirectMainDisplay);
if ( modeList == NULL )
{
printf( "Display is invalid\n" );
exit(1);
}
cnt = CFArrayGetCount(modeList);
for ( i = 0; i < cnt; ++i )
{
CFDictionaryRef desc = (CFDictionaryRef)CFArrayGetValueAtIndex(modeList, i);
int depth=numberForKey(desc, kCGDisplayBitsPerPixel);
if(depth==32&&gVideoNumModes<kMaxModes)
{
int height=numberForKey(desc, kCGDisplayHeight);
int width=numberForKey(desc, kCGDisplayWidth);
int freq=numberForKey(desc, kCGDisplayRefreshRate);
int exists=false;
for(int j=0;j<gVideoNumModes;j++)
if(gVideoModes[j].height==height&&gVideoModes[j].width==width)
{
if(freq<gVideoModes[j].freq&&freq>=60)
gVideoModes[j].freq=freq;
exists=true;
}
if(!exists)
{
gVideoModes[gVideoNumModes].height=height;
gVideoModes[gVideoNumModes].width=width;
gVideoModes[gVideoNumModes].freq=freq;
gVideoNumModes++;
}
}
}
for(int i=0;i<gVideoNumModes;i++)
for(int j=0;j<gVideoNumModes-1-i;j++)
if(gVideoModes[j].width<gVideoModes[j+1].width||(gVideoModes[j].width==gVideoModes[j+1].width&&gVideoModes[j].height<gVideoModes[j+1].height))
{
tVideoMode tmp=gVideoModes[j];
gVideoModes[j]=gVideoModes[j+1];
gVideoModes[j+1]=tmp;
}
}
void ScreenExit()
{
#ifndef __TARGET_TOOLAPP
aglSetDrawable(gOpenGLContext,NULL);
if(FrontWindow())
DisposeWindow(FrontWindow());
InitCursor();
#endif
}
//Swap front- and backbuffer
void ScreenBlit()
{
aglSwapBuffers(gOpenGLContext);
}
int GetVRAMSize()
{
char str[256];
AGLRendererInfo info, head_info;
GLint inum;
GLint dAccel = 0;
GLint dVRAM = 0, dMaxVRAM = 0;
AGLDevice gd=GetMainDevice();
head_info = aglQueryRendererInfo(&gd, 1);
if(!head_info)
return 0;
info = head_info;
inum = 0;
// see if we have an accelerated renderer, if so ignore non-accelerated ones
// this prevents returning info on software renderer when actually we'll get the hardware one
while (info)
{
aglDescribeRenderer (info, AGL_ACCELERATED, &dAccel);
// if we can accel then we will choose the accelerated renderer
// how about compliant renderers???
if (dAccel)
{
aglDescribeRenderer (info, AGL_VIDEO_MEMORY, &dVRAM); // we assume that VRAM returned is total thus add texture and VRAM required
if (dVRAM >= dMaxVRAM) // find card with max VRAM
dMaxVRAM = dVRAM; // store max
}
info = aglNextRendererInfo(info);
inum++;
}
// aglDestroyRendererInfo(head_info);
return dVRAM;
}
int ScreenSupportsTextureCompression()
{
static int result=-1;
if(result==-1)
{
char* extensions=(char*)glGetString(GL_EXTENSIONS);
result=strstr(extensions,"GL_EXT_texture_compression_s3tc")?true:false;
long resp;
Gestalt(gestaltSystemVersion,&resp);
if(resp<0x00001030)
{
//GeForce Texture compression seems buggy in 10.2.8
char* renderer=(char*)glGetString(GL_RENDERER);
if (strstr(renderer,"GeForce"))
result=false;
}
}
return result;
}
int ScreenSupportsAnisotropicFiltering()
{
static int result=-1;
if(result==-1)
{
char* extensions=(char*)glGetString(GL_EXTENSIONS);
result=strstr(extensions,"GL_EXT_texture_filter_anisotropic")?true:false;
char* renderer=(char*)glGetString(GL_RENDERER);
//GeForce 5200 bug
if (strstr (renderer, "NV34MAP") || (strstr (renderer , "GeForce") && strstr (renderer, "5200")))
result=false;
}
return result;
}
int ScreenSupports3DTextures()
{
static int result=-1;
if(result==-1)
{
/*
char* extensions=(char*)glGetString(GL_EXTENSIONS);
result=strstr(extensions,"GL_EXT_texture3D")?true:false;
*/
result=true; //built-in in GL 1.2 or higher.
char* renderer=(char*)glGetString(GL_RENDERER);
printf("Renderer: %s\n",renderer);
//GeForce 2 only has software 3d textures (? - according to unity)
if (strstr (renderer, "GeForce") && !(strstr (renderer , "TI") || strstr (renderer, "FX")))
result=false;
//same with Rage128
if (strstr (renderer, "Rage") && strstr (renderer, "128"))
result=false;
}
return result;
}
int ScreenSupportsBlendColor()
{
static int result=-1;
if(result==-1)
{
char* extensions=(char*)glGetString(GL_EXTENSIONS);
result=strstr(extensions,"GL_ARB_imaging")?true:false;
}
return result;
}
int ScreenNoBigTextures()
{
static int result=-1;
if(result==-1)
result=GetVRAMSize()<=1024*1024*8;
return result;
}
int ScreenNoWindow()
{
static int result=-1;
if(result==-1)
{
long resp;
Gestalt(gestaltSystemVersion,&resp);
result=(resp<0x00001030);
}
return result;
}

923
source/macsystem.cpp Normal file
View File

@ -0,0 +1,923 @@
#include <OpenGL/gl.h>
#include <platform.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <curl/curl.h>
#include <curl/types.h> /* new for v7 */
#include <curl/easy.h> /* new for v7 */
#include "controls.h"
#include "initexit.h"
#include "config.h"
#include "screen.h"
#include "textures.h"
#include "renderframe.h"
#include "environment.h"
#include "gameinitexit.h"
#include "gametime.h"
#include "gameframe.h"
#include "error.h"
#include "network.h"
#include "interfaceutil.h"
#include "models.h"
#include "text.h"
#include "GetPID.h"
#include "gamesound.h"
#include "reg_tool_3.h"
int gSystemSuspended=false;
int gInGame=false;
pthread_mutex_t gASMutex;
// http://developer.apple.com/qa/qa2001/qa1111.html
// Creates an AppleEvent with one text parameter. We leave it up to the AppleScript
// to further parse the text parameter into potentially more parameters.
static OSStatus CreateMessageEvent( AppleEvent *theEvent, char *parameter )
{
OSStatus err;
ProcessSerialNumber psn = {0, kCurrentProcess};
err = AEBuildAppleEvent( 'ascr', kASSubroutineEvent, typeProcessSerialNumber, (Ptr) &psn, sizeof(psn), kAutoGenerateReturnID, kAnyTransactionID,
theEvent,
NULL,
"'----':[TEXT(@)]," // One TEXT pointer parameter
"'snam':TEXT(@)", // The keyASSubroutineName ('snam') parameter must contain the name of the subroutine that is being called with every letter converted to lowercase. For example, if name of the subroutine in your script is "GetDocumentSize", then the string provided in the keyASSubroutineName parameter should be "getdocumentsize".
parameter, "applescriptentry"); // The entry routine whithin the AppleScript
return( err );
}
/*****************************************************
*
* ExecuteCompiledAppleScriptEvent( AEDesc *scriptData, AppleEvent *theEvent, AEDesc *resultData )
*
* Purpose: Generic routine to execute our AppleScriptEvent, passing parameters to an
* AppleScript running inside my application
*
* Notes: http://developer.apple.com/qa/qa2001/qa1111.html
*
* Inputs: scriptData - Reference to the AppleScript to be executed
* theEvent - text parameter to our AppleScript as an AppleEvent
* resultData - result from script
*
* Returns: OSStatus - error code (0 == no error)
*/
typedef struct{
int inited;
ComponentInstance theComponent;
OSAID contextID;
} tScriptData;
OSStatus ExecuteCompiledAppleScriptEvent( AEDesc *scriptData, AppleEvent *theEvent, AEDesc *resultData,tScriptData *scriptStore)
{
OSStatus err;
ComponentInstance theComponent = NULL;
OSAID contextID = kOSANullScript;
OSAID resultID = kOSANullScript;
int inited=false;
if(scriptStore)
if(scriptStore->inited)
{
theComponent=scriptStore->theComponent;
contextID=scriptStore->contextID;
inited=true;
}
if(!inited)
{
theComponent = OpenDefaultComponent( kOSAComponentType, typeAppleScript ); // Open the scripting component
if ( theComponent == NULL ) { err = paramErr; goto Bail; }
err = OSALoad( theComponent, scriptData, kOSAModeNull, &contextID ); // Compile the script into a new context
require_noerr( err, Bail );
}
err = OSAExecuteEvent( theComponent, theEvent, contextID, kOSAModeNull, &resultID ); // Run the script
if ( resultData != NULL ) // Collect the results - if any
{
AECreateDesc( typeNull, NULL, 0, resultData );
/*if ( err == errOSAScriptError )
OSAScriptError( theComponent, kOSAErrorMessage, typeChar, resultData );
else*/ if ( (err == noErr) && (resultID != kOSANullScript) )
OSADisplay(theComponent, resultID, typeChar, kOSAModeNull, resultData);
}
Bail:
if ( resultID != kOSANullScript ) OSADispose( theComponent, resultID );
if(!scriptStore)
{
if ( contextID != kOSANullScript ) OSADispose( theComponent, contextID );
if ( theComponent != NULL ) CloseComponent( theComponent );
}
else
{
scriptStore->inited=true;
scriptStore->theComponent=theComponent;
scriptStore->contextID=contextID;
}
return( err );
}
/*****************************************************
*
* RunAppleScript( FSRef *scriptFSRef, char *textParameter )
*
* Purpose: Runs an AppleScript with one text parameter as input.
* CreateMessageEvent, and therefore RunAppleScript, assumes the AppleScript has a
* subroutine entry titled "applescriptentry" and accepts one TEXT parameter.
*
* Inputs: scriptFSRef - FSRef to our AppleScript
* textParameter - text parameter to our AppleScript
*
* Returns: OSStatus - error code (0 == no error)
*/
static OSStatus RunAppleScript( FSRef *scriptFSRef, char *textParameter, char *textReply,int textsize,tScriptData *d)
{
OSStatus err;
AppleEvent aeParameter;
AEDesc scriptData;
short refNum;
FSCatalogInfo catalogInfo;
Handle h = NULL;
pthread_mutex_lock(&gASMutex);
refNum = FSOpenResFile( scriptFSRef, fsRdPerm ); // Older (Mac OS 8/9) scripts store their data in the 'scpt' (1) resource
if ( refNum != -1 )
{
h = Get1IndResource( 'scpt', 1 );
if( h != NULL ) DetachResource( h ); // Detach the handle before closing the resource
CloseResFile( refNum );
}
if ( h == NULL )
{
err = FSGetCatalogInfo( scriptFSRef, kFSCatInfoDataSizes, &catalogInfo, NULL, NULL, NULL ); // Get the size of the script
require_noerr( err, Bail );
err = FSOpenFork( scriptFSRef, 0, NULL, fsRdPerm, &refNum ); // Open the data fork read only
require_noerr( err, Bail );
h = NewHandle( catalogInfo.dataLogicalSize );
err = FSReadFork( refNum, fsFromStart, 0, catalogInfo.dataLogicalSize, *h, NULL ); // Read the script into our handle
(void) FSCloseFork( refNum ); // Close the file reference
}
err = CreateMessageEvent( &aeParameter, textParameter ); // Create the AppleEvent, and use the Apple event to call the script's subroutine
require_noerr( err, Bail );
err = AECreateDesc( typeOSAGenericStorage, *h, GetHandleSize(h), &scriptData ); // Load the compiled script into an AEDesc of type typeOSAGenericStorage
require_noerr( err, Bail );
AEDesc result;
err = ExecuteCompiledAppleScriptEvent( &scriptData, &aeParameter, &result,d); // "Generic" routine to execute our AppleScript
if(textReply)
{
int size=AEGetDescDataSize(&result);
AEGetDescData(&result,textReply,textsize-1);
textReply[textsize]='\0';
if(size<textsize)
textReply[size]='\0';
}
Bail:
if ( h != NULL ) DisposeHandle( h );
pthread_mutex_unlock(&gASMutex);
return( err );
}
int IsITunesEnabled()
{
return GetPIDForProcessName("iTunes")!=-1;
/* ProcessSerialNumber psn,noproc={0,kNoProcess};
psn=noproc;
Boolean result;
do{
CFStringRef name;
GetNextProcess(&psn);
CopyProcessName(&psn,&name);
if(CFStringCompare(name,CFSTR("iTunes"),0)==kCFCompareEqualTo)
return true;
SameProcess(&psn,&noproc,&result);
}while(!result);
return false;*/
}
void *ITunesNext(void *)
{
// See the Core Foundation URL Services chapter for details.
// get app bundle (even for a CFM app!)
CFBundleRef refMainBundle = CFBundleGetMainBundle();
if (!refMainBundle)
return NULL;
// create a URL to the app bundle
CFURLRef refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
if (!refMainBundleURL)
return NULL;
// create a URL to the HID library bundle
CFURLRef skriptURL = CFURLCreateCopyAppendingPathComponent (NULL, refMainBundleURL, CFSTR("Contents/Resources/Next Track.scpt"), true);
if (!skriptURL)
return NULL;
FSRef scriptFSRef;
if(CFURLGetFSRef(skriptURL,&scriptFSRef))
RunAppleScript(&scriptFSRef,"",NULL,0,NULL);
}
void *ITunesPrev(void *)
{
// See the Core Foundation URL Services chapter for details.
// get app bundle (even for a CFM app!)
CFBundleRef refMainBundle = CFBundleGetMainBundle();
if (!refMainBundle)
return NULL;
// create a URL to the app bundle
CFURLRef refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
if (!refMainBundleURL)
return NULL;
// create a URL to the HID library bundle
CFURLRef skriptURL = CFURLCreateCopyAppendingPathComponent (NULL, refMainBundleURL, CFSTR("Contents/Resources/Prev Track.scpt"), true);
if (!skriptURL)
return NULL;
FSRef scriptFSRef;
if(CFURLGetFSRef(skriptURL,&scriptFSRef))
RunAppleScript(&scriptFSRef,"",NULL,0,NULL);
}
void *ITunesPlay(void *)
{
// See the Core Foundation URL Services chapter for details.
// get app bundle (even for a CFM app!)
CFBundleRef refMainBundle = CFBundleGetMainBundle();
if (!refMainBundle)
return NULL;
// create a URL to the app bundle
CFURLRef refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
if (!refMainBundleURL)
return NULL;
// create a URL to the HID library bundle
CFURLRef skriptURL = CFURLCreateCopyAppendingPathComponent (NULL, refMainBundleURL, CFSTR("Contents/Resources/PlayPause.scpt"), true);
if (!skriptURL)
return NULL;
FSRef scriptFSRef;
if(CFURLGetFSRef(skriptURL,&scriptFSRef))
RunAppleScript(&scriptFSRef,"",NULL,0,NULL);
// system("osascript /Users/jechter/Documents/proj/glLandscape/deliverable/gamexcode/build/Release/PlayPause.scpt");
}
char giTunesSong[1024],giTunesArtist[1024];
int giTunesPlaying=false;
float giTunesLastStatusUpdate=-10;
void ITunesGetStatus()
{
static int inited=false;
static float lastStatus=0;
static tScriptData data={0,0,0};
// if(TimeGetSeconds()<lastStatus+1)
// return;
if(!IsITunesEnabled())
return;
lastStatus=TimeGetSeconds();
// See the Core Foundation URL Services chapter for details.
// get app bundle (even for a CFM app!)
CFBundleRef refMainBundle = CFBundleGetMainBundle();
if (!refMainBundle)
return;
// create a URL to the app bundle
CFURLRef refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
if (!refMainBundleURL)
return;
// create a URL to the HID library bundle
CFURLRef skriptURL = CFURLCreateCopyAppendingPathComponent (NULL, refMainBundleURL, CFSTR("Contents/Resources/Status.scpt"), true);
if (!skriptURL)
return;
FSRef scriptFSRef;
if(CFURLGetFSRef(skriptURL,&scriptFSRef))
{
char status[1024];
RunAppleScript(&scriptFSRef,"",status,1024,&data);
char* str=strchr(status,'"');
if(str)str++;
else return;
char* end=strchr(str,'"');
if(end)*end='\0';
StripDiacritics(str,strlen(str),smSystemScript);
if(strcmp(str,giTunesSong))
{
strcpy(giTunesSong,str);
if(inited)
giTunesLastStatusUpdate=lastStatus;
}
str=strchr(end+1,'"');
if(str)str++;
else return;
end=strchr(str,'"');
if(end)*end='\0';
StripDiacritics(str,strlen(str),smSystemScript);
if(strcmp(str,giTunesArtist))
{
strcpy(giTunesArtist,str);
if(inited)
giTunesLastStatusUpdate=lastStatus;
}
str=end+1;
if(giTunesPlaying)
{
if(!strstr(str,"true"))
{
giTunesPlaying=false;
if(inited)
giTunesLastStatusUpdate=lastStatus;
}
}
else if(strstr(str,"true"))
{
giTunesPlaying=true;
if(inited)
giTunesLastStatusUpdate=lastStatus;
}
}
inited=true;
}
int IsInFront()
{
ProcessSerialNumber currentProc,frontProc;
GetFrontProcess(&frontProc);
GetCurrentProcess(&currentProc);
Boolean same;
SameProcess(&currentProc,&frontProc,&same);
return same;
}
/*void IChatStatus(char *status)
{
// See the Core Foundation URL Services chapter for details.
// get app bundle (even for a CFM app!)
CFBundleRef refMainBundle = CFBundleGetMainBundle();
if (!refMainBundle)
return;
// create a URL to the app bundle
CFURLRef refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
if (!refMainBundleURL)
return;
// create a URL to the HID library bundle
CFURLRef skriptURL = CFURLCreateCopyAppendingPathComponent (NULL, refMainBundleURL, CFSTR("Contents/Resources/PlayPause.scpt"), true);
if (!skriptURL)
return;
FSRef scriptFSRef;
if(CFURLGetFSRef(skriptURL,&scriptFSRef))
RunAppleScript(&scriptFSRef,status);
}*/
static OSStatus LoadFrameworkBundle(CFBundleRef *bundlePtr)
{
Boolean didLoad = false; // Flag that indicates the status returned when attempting to load a bundle's executable code.
CFBundleRef refMainBundle = NULL;
CFURLRef refMainBundleURL = NULL, refPathBundleURL = NULL;
CFURLRef bundleURL = NULL;
CFBundleRef bundle = NULL;
// See the Core Foundation URL Services chapter for details.
// get app bundle (even for a CFM app!)
refMainBundle = CFBundleGetMainBundle();
if (!refMainBundle)
{
DebugStr ("\pCould open main bundle");
return paramErr;
}
// create a URL to the app bundle
refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
if (!refMainBundleURL)
{
DebugStr ("\pCould not copy main bundle URL");
return paramErr;
}
// create a URL that points to the app's directory
// create a URL to the HID library bundle
bundleURL = CFURLCreateCopyAppendingPathComponent (NULL, refMainBundleURL, CFSTR("Contents/MacOS/FpuExceptions.bundle"), true);
// release created URLs
if (refMainBundleURL != NULL)
CFRelease (refMainBundleURL);
if (refPathBundleURL != NULL)
CFRelease (refPathBundleURL);
// did we actaully get a bundle URL
if (!bundleURL)
{
DebugStr ("\pCould create HID bundle URL");
return paramErr;
}
// get the actual bundle for the HID library
bundle = CFBundleCreate (NULL, bundleURL);
if (!bundle)
{
DebugStr ("\pCould not create HID MachO library bundle");
return paramErr;
}
if (!CFBundleLoadExecutable (bundle)) // If the code was successfully loaded, look for our function.
{
DebugStr ("\pCould not load MachO executable");
return paramErr;
}
*bundlePtr=bundle;
}
pascal OSErr myQUIT(const AppleEvent *theAE,AppleEvent *reply,long refCon)
{
if(!gInGame||gReplay||gInputEscMode==kInputEscModeNormal)
Exit();
else
{
gInputEscMode=kInputEscModeQuit;
gInputEscSelection=1;
if(!gGameInfo->network)
PauseGame();
}
return noErr;
}
#define kMaxURLSize 256
pascal OSErr myGURL(const AppleEvent *theAE,AppleEvent *reply,long refCon)
{
DescType type;
char theURL[kMaxURLSize];
Size urlSize;
HandleError(AEGetParamPtr(theAE,keyDirectObject,typeChar,&type,theURL,kMaxURLSize,&urlSize));
if(type!=typeChar)
return paramErr;
if(urlSize>=kMaxURLSize)
return paramErr;
theURL[urlSize]='\0';
//PrintConsoleString("Opening URL \"%s\"....",theURL);
if(theURL[strlen(theURL)-1]=='>')
theURL[strlen(theURL)-1]='\0';
if(theURL[strlen(theURL)-1]=='/')
theURL[strlen(theURL)-1]='\0';
sscanf(theURL,"<%s",theURL);
sscanf(theURL,"URL:%s",theURL);
sscanf(theURL,"redline://%s",gJoinHost);
gJoinFlag=true;
gGameEnd=kEndGameNoReplay;
return noErr;
}
void InitAE()
{
AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,NewAEEventHandlerUPP(&myQUIT),0,false);
AEInstallEventHandler(kInternetEventClass,kAEGetURL,NewAEEventHandlerUPP(&myGURL),0,false);
}
//#define kBetaExpiration (3232976085+4000000)
#define kBetaExpiration (0)
void* ITunesPollThread(void * arg)
{
while(1){
ITunesGetStatus();
sleep(1);
}
}
void InitITunesNotifications();
void SystemInit()
{
long resp;
short hit;
AlertStdAlertParamRec alertParam={
false,false,nil,
"\pExit",
nil,
nil,
kAlertStdAlertOKButton,
0,
kWindowDefaultPosition};
HandleError(Gestalt(gestaltSystemVersion,&resp));
if(resp<0x00001020)
{
StandardAlert(kAlertStopAlert,
"\pMac OS 10.2 or higher is required.",
"\p",
&alertParam,
&hit);
ExitToShell();
}
unsigned long dateTime;
GetDateTime(&dateTime);
//PrintConsoleString("%u",dateTime);
if(kBetaExpiration&&dateTime>kBetaExpiration)
{
StandardAlert(kAlertStopAlert,
"\pThis beta of Redline has expired.",
"\p",
&alertParam,
&hit);
ExitToShell();
}
InitAE();
ITunesGetStatus();
InitITunesNotifications();
pthread_mutex_init(&gASMutex,0);
//pthread_t thread;
//pthread_create(&thread,NULL,ITunesPollThread,NULL);
// CallOmniEnableFloatExceptions();
}
#define kInputBufferSize 16
UInt32 gInputBuffer[kInputBufferSize];
int gInputBufferPos=0;
float gLastCursorHideTime;
extern int gInterfaceKeys[kInterfaceNumKeys];
UInt32 gLastSwitch=0;
int iTunesPress=false;
int gSystemInstalling=false;
float gInstallStartTime=0;
void SystemPoll(int inGame)
{
EventRecord evt;
gInGame=inGame;
while(WaitNextEvent(everyEvent,&evt,0,nil))
{
switch(evt.what)
{
case mouseDown:
WindowPtr win;
switch(FindWindow(evt.where,&win))
{
case inDrag:
{
Rect dragRect={0,0,32767,32767};
DragWindow(win,evt.where,&dragRect);
Point pt={0,0};
LocalToGlobal(&pt);
gConfig->windowX=pt.h;
gConfig->windowY=pt.v;
}
break;
case inMenuBar:
MenuSelect(evt.where);
break;
case inContent:
if(evt.when>gLastSwitch+20)
if(gInputBufferPos<kInputBufferSize)
gInputBuffer[gInputBufferPos++]=gInterfaceKeys[kInterfaceMouseDown]<<8;
break;
}
break;
case osEvt:
if(((evt.message&osEvtMessageMask)>>24)==suspendResumeMessage)
{
gSystemSuspended=!(evt.message&resumeFlag);
if(!gSystemSuspended)
BringToFront(FrontWindow());
if(inGame)
{
if(gSystemSuspended&&inGame)
if((!gGameInfo->network)&&(!gReplay))
PauseGame();
}
else
if(gSystemSuspended)
PauseGame();
else
UnPauseGame();
gLastSwitch=evt.when;
if(!gPaused)
SoundReInit();
}
break;
case kHighLevelEvent :
AEProcessAppleEvent(&evt);
break;
case keyDown:
case autoKey:
if(evt.modifiers&cmdKey)
switch(evt.message&charCodeMask)
{
case 'f':
if(!ScreenNoWindow())
{
float pauseTime=TimeGetSeconds();
gConfig->fullscreen=!gConfig->fullscreen;
ScreenReInit();
if(inGame)
{
gClipEnable=false;
RenderFrame(false);
gClipEnable=true;
if(!gPaused&&!gGameInfo->network)
gStartTime+=TimeGetSeconds()-pauseTime;
}
}
break;
/* case 'q':
if((!inGame)||gInputEscMode==kInputEscModeNormal)
Exit();
break;*/
}
else
if(gInputBufferPos<kInputBufferSize)
{
MemoryMove(gInputBuffer+1,gInputBuffer,sizeof(UInt32)*gInputBufferPos);
gInputBufferPos++;
gInputBuffer[0]=evt.message;
}
break;
}
}
if(TimeGetSeconds()>gLastCursorHideTime+1&&!gSystemInstalling)
{
gLastCursorHideTime=TimeGetSeconds();
if(gConfig->fullscreen)
HideCursor();
else
ObscureCursor();
}
if(((!gInterfaceType||GetInterfaceKey(kInterfaceKeyCmd))||inGame)&&!gSystemSuspended)
{
pthread_t thread;
if(GetButtonInput(kInputITunesNext))
{
if(!iTunesPress)
// ITunesNext(NULL);
pthread_create(&thread,NULL,ITunesNext,NULL);
iTunesPress=true;
}
else if(GetButtonInput(kInputITunesPrev))
{
if(!iTunesPress)
// ITunesPrev(NULL);
pthread_create(&thread,NULL,ITunesPrev,NULL);
iTunesPress=true;
}
else if(GetButtonInput(kInputITunesPlay))
{
if(!iTunesPress)
// ITunesPlay(NULL);
pthread_create(&thread,NULL,ITunesPlay,NULL);
iTunesPress=true;
}
else
iTunesPress=false;
}
RT3_Idle();
NetworkIdle();
SystemIdle();
}
void SystemYieldTime(float till)
{
while(TimeGetSeconds()<till)
SystemYield();
}
void SystemNotify()
{
if(gSystemSuspended)
{
NMRec n;
n.qType=nmType;
n.nmMark=1;
n.nmIcon=NULL;
n.nmSound=NULL;
n.nmStr=NULL;
n.nmResp=NULL;
HandleError(NMInstall(&n));
}
}
void FlushKeys()
{
// SystemPoll(false);
FlushEvents(keyDownMask+mDownMask,0);
gInputBufferPos=0;
}
char GetKeyInput(int *key)
{
if(key)
*key=kInterfaceKeyNone;
if(gInputBufferPos)
{
gInputBufferPos--;
if(key)
for(int i=kInterfaceKeyUp;i<kInterfaceNumKeys;i++)
if((gInputBuffer[gInputBufferPos]&keyCodeMask)>>8==gInterfaceKeys[i])
*key=i;
if(gInputBuffer[gInputBufferPos]&charCodeMask)
return gInputBuffer[gInputBufferPos]&charCodeMask;
else
return 0xff;
}
return 0;
}
char PeekKeyInput(int *key)
{
if(key)
*key=kInterfaceKeyNone;
if(gInputBufferPos)
{
if(key)
for(int i=kInterfaceKeyUp;i<kInterfaceNumKeys;i++)
if((gInputBuffer[gInputBufferPos-1]&keyCodeMask)>>8==gInterfaceKeys[i])
*key=i;
if(gInputBuffer[gInputBufferPos-1]&charCodeMask)
return gInputBuffer[gInputBufferPos-1]&charCodeMask;
else
return 0xff;
}
return 0;
}
float TimeGetSeconds()
{
static UInt64 startTime=0;
if(startTime==0)
Microseconds((UnsignedWide*)&startTime);
UInt64 w;
Microseconds((UnsignedWide*)&w);
return (float)((double)(w-startTime)*(double)0.000001);
}
size_t my_write_func(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
return fwrite(ptr, size, nmemb, stream);
}
size_t my_read_func(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
return fread(ptr, size, nmemb, stream);
}
int my_progress_func(void *v,
double t, /* dltotal */
double d, /* dlnow */
double ultotal,
double ulnow)
{
char status[1024];
float time=TimeGetSeconds()-gInstallStartTime;
if(d>0)
{
time*=(t-d)/d;
sprintf(status,"%3.1f of %3.1fMB - about %d:%02d:%02d remaining",d/(1024*1024),t/(1024*1024),(int)(time/3600),((int)(time/60))%60,((int)time)%60);
}
else
sprintf(status,"%3.1f of %3.1fMB");
InterfaceDrawStatusBar("Downloading new version",status,d/t);
SystemPoll(false);
return 0;
}
int CurlGetFile(char *url,char *filename,char *failStr)
{
#ifndef __TARGET_TOOLAPP
CURL *curl;
CURLcode res;
FILE *outfile;
if(!curl_easy_init)
{
strcpy(failStr,"libcurl not available");
return false;
}
curl = curl_easy_init();
if(curl)
{
outfile = fopen(filename, "w");
if(!outfile)
{
strcpy(failStr,"Couldn't create file.\nMake sure that Redline and the Redline directory is writable and that you have free space on your disk.");
return false;
}
gSystemInstalling=true;
gInstallStartTime=TimeGetSeconds();
res = curl_easy_setopt(curl, CURLOPT_URL, url);
if(res==CURLE_OK) res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile);
if(res==CURLE_OK) res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_write_func);
if(res==CURLE_OK) res = curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_read_func);
if(res==CURLE_OK) res = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);
if(res==CURLE_OK) res = curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, my_progress_func);
if(res==CURLE_OK) res = curl_easy_perform(curl);
fclose(outfile);
/* always cleanup */
curl_easy_cleanup(curl);
}
switch(res)
{
case CURLE_OK: break;
case 22: strcpy(failStr,"curl: HTTP error"); break;
case CURLE_WRITE_ERROR: strcpy(failStr,"curl: Error writing to disk"); break;
case CURLE_URL_MALFORMAT: strcpy(failStr,"curl: Invalid Update URL"); break;
case CURLE_COULDNT_RESOLVE_HOST: strcpy(failStr,"curl: Couldn't resolve host"); break;
case CURLE_COULDNT_CONNECT: strcpy(failStr,"curl: Connection failed"); break;
case CURLE_OPERATION_TIMEOUTED: strcpy(failStr,"curl: Connection timed out"); break;
case CURLE_RECV_ERROR: strcpy(failStr,"curl: Error receiving data"); break;
default: strcpy(failStr,"curl: Error downloading URL"); break;
}
return res==CURLE_OK;
#endif
}
void SystemExit()
{
if(gSystemInstalling)
system("rm redlineupdatearchive.zip");
}
int AutoUpdateRedline(char *updateURL,char *failStr)
{
CFBundleRef refMainBundle = CFBundleGetMainBundle();
if (!refMainBundle)
{
sprintf(failStr,"Couldn't get Redline bundle location");
return false;
}
// create a URL to the app bundle
CFURLRef refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
if(!refMainBundleURL)
{
sprintf(failStr,"Couldn't get Redline bundle location");
return false;
}
char path[512];
if(!CFURLGetFileSystemRepresentation(refMainBundleURL,true,(UInt8*)path,512))
{
sprintf(failStr,"Couldn't get Redline bundle location");
return false;
}
// char cmd[512];
sprintf(path,"%s/../",path);
chdir(path);
system("pwd");
// printf(cmd);
// system(cmd);
int retval=true;
InitCursor();
if(!CurlGetFile(updateURL,"redlineupdatearchive.zip",failStr)) retval=false;
InterfaceDrawStrings("Installing new version","Please wait a moment...",-1);
if(retval)
if(system("unzip -o redlineupdatearchive.zip"))
{
retval=false;
sprintf(failStr,"Couldn't unzip update archive.\nMake sure that Redline and the Redline directory is writable and that you have free space on your disk.");
}
if(system("rm redlineupdatearchive.zip")) retval=false;
gSystemInstalling=false;
return retval;
}

View File

@ -0,0 +1,107 @@
//mactexturesimport.cpp
//mac-specific (or rather "QuickTime-Specific") code to load textures
#include <OpenGL/gl.h>
#include <QuickTime/QuickTime.h>
#include <string.h>
#include "fileio.h"
#include "error.h"
#include "gamemem.h"
#include "texturesimport.h"
#include "network.h"
typedef struct{
UInt8 r,g,b,a;
}tRGBAColor;
typedef struct{
UInt8 a,r,g,b;
}tARGBColor;
void *TexturesLoadImportBuffer(tFileRef tex,int *xSize,int *ySize)
{
ComponentInstance gi;
int gotImage=false;
char *fileExtension=FileGetExtension(tex);
if(!_stricmp(fileExtension,kFileTypeImageURL)){
tImageURL *url=(tImageURL*)FileGetParsedDataPtr(tex,kParserTypeImageURL,sizeof(tImageURL));
Handle dataRef=NewHandle(strlen(url->url)+1);
strcpy(*dataRef,url->url);
if(!gInternetAvailable)
tex=url->offlineImage;
else if(GetGraphicsImporterForDataRef(dataRef,URLDataHandlerSubType,&gi)!=noErr)
tex=url->offlineImage;
else
gotImage=true;
}
if(!gotImage)
{
void *textureData=FileGetDataPtr(tex);
Handle dataHandle,dataRef;
int size=FileGetSize(tex);
//Get a Handle with the texture file data in it
PtrToHand(textureData,&dataHandle,FileGetSize(tex));
char *name=FileGetName(tex);
unsigned char len=strlen(name);
//create a new data reference
dataRef=NewHandle(sizeof(Handle)+len+1);
*((Handle*)(*dataRef))=dataHandle;
BlockMoveData(name,*dataRef+sizeof(Handle)+1,len);
*(unsigned char*)(*dataRef+sizeof(Handle))=len;
HandleError(GetGraphicsImporterForDataRef(dataRef,HandleDataHandlerSubType,&gi));
}
// GWorldPtr oldGW;
// GDHandle oldGD;
// GetGWorld(&oldGW,&oldGD);
//get image bounds
Rect bounds;
HandleError(GraphicsImportGetNaturalBounds(gi,&bounds));
*xSize=bounds.right-bounds.left;
*ySize=bounds.bottom-bounds.top;
//create a buffer to hold the decompressed pixel data
int rowBytes=*xSize*4;
void *imageBuffer=MemoryAllocateBlock(*ySize*rowBytes);
//create a GWorld structure for the pixel buffer
GWorldPtr imageGW;
QTNewGWorldFromPtr(&imageGW,k32ARGBPixelFormat,&bounds,nil,nil,0,imageBuffer,rowBytes);
//Set up graphics importer
HandleError(GraphicsImportSetGWorld(gi,imageGW,nil));
HandleError(GraphicsImportSetQuality(gi,codecLosslessQuality));
//decompress the image to the GWorld
LockPixels(GetGWorldPixMap(imageGW));
HandleError(GraphicsImportDraw(gi));
UnlockPixels(GetGWorldPixMap(imageGW));
//convert ARGB to RGBA
for(int i=0;i<*ySize*rowBytes/4;i++)
{
tARGBColor buf=*(((tARGBColor*)imageBuffer)+i);
tRGBAColor c;
c.a=buf.a;
c.r=buf.r;
c.g=buf.g;
c.b=buf.b;
*(((tRGBAColor*)imageBuffer)+i)=c;
}
//re-set the GWorld to use.
// SetGWorld(oldGW,oldGD);
//dispose our structures.
DisposeGWorld(imageGW);
CloseComponent(gi);
return imageBuffer;
}

12
source/main.cpp Executable file
View File

@ -0,0 +1,12 @@
//main.cpp
#include "initexit.h"
#include "interface.h"
int main()
{
Init();
InterfaceMainLoop();
Exit();
return 0;
}

362
source/mapselection.cpp Normal file
View File

@ -0,0 +1,362 @@
//mapselection.cpp
//let the user select a map
#include <stdio.h>
#include <string.h>
#include "gamemem.h"
#include "fileio.h"
#include "gameinitexit.h"
#include "parser.h"
#include "config.h"
#include "environment.h"
#include "interfaceutil.h"
#include "mapselection.h"
#include "reg_tool_3.h"
#include "controls.h"
#define kMaxMaps 1024
#define kMaxEnvironments 64
char *StripName(char *aName)
{
while(*aName==' '||*aName=='\t')aName++;
while(*aName=='\255')
{
aName++;
while(*aName!='\255'&&*aName!=0)
aName++;
if(*aName=='\255')
aName++;
while(*aName==' '||*aName=='\t')aName++;
}
return aName;
}
int CompareMaps(const void *a,const void *b)
{
tMapInfo *mapa=(tMapInfo*)FileGetParsedDataPtr(*(tFileRef*)a,kParserTypeMapInfoDesc,sizeof(tMapInfo));
tMapInfo *mapb=(tMapInfo*)FileGetParsedDataPtr(*(tFileRef*)b,kParserTypeMapInfoDesc,sizeof(tMapInfo));
return _stricmp(StripName(mapa->name),StripName(mapb->name));
}
//get a list of available map files
void GetAvailableMaps(int *availableMaps,int *mapCount,int demoOnly)
{
*mapCount=0;
for(int i=0;i<gFileTableSize;i++)
if(*mapCount<kMaxMaps)
if(char *extension=FileGetExtension(i))
if(!_stricmp(extension,kFileTypeMapDefinition))
{
tMapInfo *mapInfo=(tMapInfo*)FileGetParsedDataPtr(i,kParserTypeMapInfoDesc,sizeof(tMapInfo));
int demook=false;
if(i==FileGetReference("city2.mapinfo"))demook=true;
if(i==FileGetReference("highspeed.mapinfo"))demook=true;
if(!mapInfo->hideMap&&(demook||!demoOnly))
availableMaps[(*mapCount)++]=i;
}
qsort(availableMaps,*mapCount,sizeof(tFileRef),CompareMaps);
}
//get a list of available environment files
void GetAvailableEnvironments(int *availableEnvironments,int *environmentCount,int timeTrial)
{
*environmentCount=0;
for(int i=0;i<gFileTableSize;i++)
if(*environmentCount<kMaxEnvironments)
if(char *extension=FileGetExtension(i))
if(!_stricmp(extension,kFileTypeEnvironmentDefinition))
{
int ok=false;
if(i==FileGetReference("daylight.env"))ok=true;
if(i==FileGetReference("night.env"))ok=true;
if(i==FileGetReference("rain.env"))ok=true;
if(i==FileGetReference("snow.senv"))ok=true;
if(i==FileGetReference("sunset.env"))ok=true;
if(!timeTrial||ok)
availableEnvironments[(*environmentCount)++]=i;
}
}
void SelectNextMap(tFileRef *map)
{
int availableMaps[kMaxMaps];
int mapCount;
int selection=0;
GetAvailableMaps(availableMaps,&mapCount,!RT3_IsRegistered());
for(int i=0;i<mapCount;i++)
if(*map==availableMaps[i])
selection=i;
selection=(selection+1)%mapCount;
*map=availableMaps[selection];
gConfig->lastRoad=*map;
}
void SelectPrevMap(tFileRef *map)
{
int availableMaps[kMaxMaps];
int mapCount;
int selection=0;
GetAvailableMaps(availableMaps,&mapCount,!RT3_IsRegistered());
for(int i=0;i<mapCount;i++)
if(*map==availableMaps[i])
selection=i;
selection--;
if(selection<0)
selection+=mapCount;
*map=availableMaps[selection];
gConfig->lastRoad=*map;
}
int SelectMapByChar(char ch)
{
tFileRef availableMaps[kMaxMaps];
int mapCount;
GetAvailableMaps(availableMaps,&mapCount,false);
for(int i=0;i<mapCount;i++)
{
tMapInfo *mapInfo=(tMapInfo*)FileGetParsedDataPtr(availableMaps[i],kParserTypeMapInfoDesc,sizeof(tMapInfo));
if(toupper(StripName(mapInfo->name)[0])>=ch)
return i;
}
return mapCount-1;
}
typedef struct{
float t;
int *mapSelection;
int (*Callback)(void*);
void *userData;
} tMapSelectionCallbackUserData;
enum{
kMapSelectionMap,
kMapSelectionReverse,
kMapSelectionLaps,
kMapSelectionEnvironment,
// kMapSelectionMode,
kMapSelectionAccept,
kMapSelectionExit,
kNumMapSelectionItems
};
int MapSelectionCallback(void *ud)
{
char ch=toupper(PeekKeyInput(NULL));
if(ch>='A'&&ch<='Z')
{
*((tMapSelectionCallbackUserData*)ud)->mapSelection=SelectMapByChar(ch);
GetKeyInput(NULL);
return kNumMapSelectionItems;
}
if(((tMapSelectionCallbackUserData*)ud)->Callback)
return ((tMapSelectionCallbackUserData*)ud)->Callback(((tMapSelectionCallbackUserData*)ud)->userData);
return -1;
}
int InterfaceMapSelection(tGameInfo *gInfo,int (*Callback)(void*),void *userData,int timeTrial)
{
tFileRef availableMaps[kMaxMaps];
int availableEnvironments[kMaxEnvironments];
int mapSelection=0;
int environmentSelection=0;
int mapCount,environmentCount;
int lapCount=gConfig->lastLaps;
int reverse=gConfig->reverse;
tMapSelectionCallbackUserData ud;
ud.t=INFINITY;
ud.mapSelection = &mapSelection;
ud.Callback=Callback;
ud.userData=userData;
GetAvailableMaps(availableMaps,&mapCount,false);
for(int i=0;i<mapCount;i++)
if(gConfig->lastRoad==availableMaps[i])
mapSelection=i;
GetAvailableEnvironments(availableEnvironments,&environmentCount,timeTrial);
for(int i=0;i<environmentCount;i++)
if(gConfig->lastEnv==availableEnvironments[i])
environmentSelection=i;
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,kNumMapSelectionItems,"Select Map");
menu.RenderCallback=InterfaceRenderReplay;
InterfaceMenuZoomAnimation(&menu,-1,true);
menu.items[kMapSelectionReverse-1].lineSpacing*=1.5;
menu.items[kMapSelectionAccept-1].lineSpacing*=4.25;
strcpy(menu.items[kMapSelectionExit].label,"Cancel");
menu.imageXScale=kMapImageXStretch;
menu.imageYScale=kMapImageYStretch;
menu.imageXPos+=0.1;
menu.imageYPos-=0.03;
menu.TimerCallback=MapSelectionCallback;
menu.userData=&ud;
menu.returnOnSpace=true;
for(int i=0;i<=kMapSelectionEnvironment;i++)
menu.items[i].flags|=kInterfaceMenuItemArrowInput;
for(int i=kMapSelectionReverse;i<=kMapSelectionEnvironment;i++)
{
menu.items[i].size*=0.8;
menu.items[i].lineSpacing*=0.8;
}
int exit=false;
int sel;
do{
tMapInfo *mapInfo=(tMapInfo*)FileGetParsedDataPtr(availableMaps[mapSelection],kParserTypeMapInfoDesc,sizeof(tMapInfo));
tEnvironment *environment=(tEnvironment*)FileGetParsedDataPtr(availableEnvironments[environmentSelection],kParserTypeEnvironmentDesc,sizeof(tEnvironment));
int demook=false;
if(availableMaps[mapSelection]==FileGetReference("city2.mapinfo"))demook=true;
if(availableMaps[mapSelection]==FileGetReference("highspeed.mapinfo"))demook=true;
menu.image=mapInfo->image;
if(demook||RT3_IsRegistered())
{
menu.imageAlpha=1.0;
strcpy(menu.items[kMapSelectionAccept].label,"Accept");
menu.items[kMapSelectionAccept].flags=0;
if((!mapInfo->loop)||gInfo->numLaps==-1)
menu.items[kMapSelectionLaps].flags|=kInterfaceMenuItemDisabled;
else
menu.items[kMapSelectionLaps].flags&=~kInterfaceMenuItemDisabled;
menu.items[kMapSelectionEnvironment].flags&=~kInterfaceMenuItemDisabled;
menu.items[kMapSelectionReverse].flags&=~kInterfaceMenuItemDisabled;
}
else
{
menu.imageAlpha=0.5;
strcpy(menu.items[kMapSelectionAccept].label,"\255demo.png\255 Not available in demo!!");
menu.items[kMapSelectionAccept].flags|=kInterfaceMenuItemDisabled;
menu.items[kMapSelectionLaps].flags|=kInterfaceMenuItemDisabled;
menu.items[kMapSelectionEnvironment].flags|=kInterfaceMenuItemDisabled;
menu.items[kMapSelectionReverse].flags|=kInterfaceMenuItemDisabled;
}
sprintf(menu.items[kMapSelectionMap].label,"Selected Map: \255#a\255%s",mapInfo->name);
sprintf(menu.items[kMapSelectionReverse].label,"Direction: \255#a\255%s",reverse?"Reverse":"Normal");
if(gInfo->numLaps!=-1)
if(!mapInfo->loop)
sprintf(menu.items[kMapSelectionLaps].label,"Number of Laps: \255#a\255Not Looped");
else
sprintf(menu.items[kMapSelectionLaps].label,"Number of Laps: \255#a\255%d",lapCount);
else
sprintf(menu.items[kMapSelectionLaps].label,"Number of Laps: \255#a\255Unlimited");
if(mapInfo->useAltEnv&&environment->hasAltEnv)
environment=(tEnvironment*)FileGetParsedDataPtr(environment->altEnv,kParserTypeEnvironmentDesc,sizeof(tEnvironment));
sprintf(menu.items[kMapSelectionEnvironment].label,"Weather: \255#a\255%s",environment->name);
sel=InterfaceGetUserMenuSelection(&menu);
if(sel==kNumMapSelectionItems)
menu.initialSelection=0;
else
switch(menu.initialSelection=(sel&kInterfaceMenuItemMask))
{
case kMapSelectionMap:
if(sel&kInterfaceMenuLeftArrow)
do{
mapSelection--;
if(mapSelection<0)mapSelection=mapCount-1;
mapInfo=(tMapInfo*)FileGetParsedDataPtr(availableMaps[mapSelection],kParserTypeMapInfoDesc,sizeof(tMapInfo));
}while(gInfo->numLaps==-1&&!mapInfo->loop);
else if(sel&kInterfaceMenuRightArrow)
do{
mapSelection=(mapSelection+1)%mapCount;
mapInfo=(tMapInfo*)FileGetParsedDataPtr(availableMaps[mapSelection],kParserTypeMapInfoDesc,sizeof(tMapInfo));
}while(gInfo->numLaps==-1&&!mapInfo->loop);
else if(mapInfo->demoAvailable||RT3_IsRegistered())
exit=true;
break;
case kMapSelectionReverse:
if(sel&(kInterfaceMenuRightArrow|kInterfaceMenuLeftArrow))
reverse=!reverse;
else if(mapInfo->demoAvailable||RT3_IsRegistered())
exit=true;
break;
case kMapSelectionLaps:
if(sel&kInterfaceMenuLeftArrow){
lapCount--;
if(lapCount<1)lapCount=kMaxLaps;
}
else if(sel&kInterfaceMenuRightArrow){
lapCount++;
if(lapCount>kMaxLaps)lapCount=1;
}
else if(mapInfo->demoAvailable||RT3_IsRegistered())
exit=true;
break;
case kMapSelectionEnvironment:
if(sel&kInterfaceMenuLeftArrow){
environmentSelection--;
if(environmentSelection<0)environmentSelection=environmentCount-1;
}
else if(sel&kInterfaceMenuRightArrow)
environmentSelection=(environmentSelection+1)%environmentCount;
else if(mapInfo->demoAvailable||RT3_IsRegistered())
exit=true;
break;
/* case kMapSelectionMode:
if(sel&kInterfaceMenuLeftArrow){
gInfo->arcade--;
if(gInfo->arcade<0)
gInfo->arcade=(sel&kInterfaceMenuEasterEgg?2:1);
}
else if(sel&kInterfaceMenuRightArrow)
gInfo->arcade=(gInfo->arcade+1)%(sel&kInterfaceMenuEasterEgg?3:2);
else exit=true;
break;
*/
case kInterfaceMenuOK:
case kMapSelectionAccept:
if(mapInfo->demoAvailable||RT3_IsRegistered())
exit=true;
break;
case kInterfaceMenuEsc:
case kMapSelectionExit:
exit=true;
break;
}
}while(!exit);
InterfaceDisposeMenu(&menu);
sel&=kInterfaceMenuItemMask;
if(sel!=kInterfaceMenuEsc&&sel!=kMapSelectionExit)
{
gInfo->reverse=reverse;
if(gInfo->numLaps!=-1)
gInfo->numLaps=lapCount;
gInfo->map=availableMaps[mapSelection];
tMapInfo *mapInfo=(tMapInfo*)FileGetParsedDataPtr(gInfo->map,kParserTypeMapInfoDesc,sizeof(tMapInfo));
if(!mapInfo->loop)
{
gInfo->numLaps=1;
}
gInfo->environment=availableEnvironments[environmentSelection];
gConfig->lastRoad=availableMaps[mapSelection];
gConfig->reverse=reverse;
gConfig->lastLaps=lapCount;
gConfig->lastEnv=availableEnvironments[environmentSelection];
// gConfig->arcade=gInfo->arcade;
return true;
}
return false;
}

14
source/mapselection.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef __MAPSELECTION
#define __MAPSELECTION
#include "fileio.h"
#include "gameinitexit.h"
#define kMapImageXStretch 0.35
#define kMapImageYStretch 0.175
void SelectNextMap(tFileRef *map);
void SelectPrevMap(tFileRef *map);
int InterfaceMapSelection(tGameInfo *gInfo,int (*Callback)(void*),void *userData,int timeTrial);
#endif

995
source/models.cpp Executable file
View File

@ -0,0 +1,995 @@
//models.cpp
//3d model drawing code
#include <stdio.h>
#include <string.h>
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#include <math.h>
#include "fileio.h"
#include "gamemem.h"
#include "vectors.h"
#include "entities.h"
#include "textures.h"
#include "renderframe.h"
#include "environment.h"
#include "transparency.h"
#include "config.h"
#include "modeltypes.h"
#include "models.h"
#include "stencil.h"
#include "network.h"
//#define __USEDISPLAYLISTS
#ifndef __TARGET_TOOLAPP
#define __USEVERTEXARRAYS
#endif
typedef struct{
void *next;
tFileRef model;
} tModelList;
tModelList *gModelList=NULL;
#define kShadowZoom 0.99
//When a model is loaded it won't neccesaryly have the correct
//file reference IDs for the texture files, as file reference IDs
//are redefined each time at application startup.
//this function inserts the correct file reference IDs for a model's
//textures based on file names.
void ModelInsertTextureRefs(tFileRef modelRef)
{
tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data;
tVector3 *vertices=(tVector3*)&modelData->data;
tVector3 *normals=vertices+modelData->vertexCount;
tVector2 *texels=(tVector2*)(normals+modelData->normalCount);
tFaceData *faces=(tFaceData*)(texels+modelData->texelCount);
tMaterial *materials=(tMaterial*)(faces+modelData->faceCount);
if(modelData->modelFlags&kFlagMultiTextureFlag)
materials=(tMaterial*)((tFaceDataMT*)faces+modelData->faceCount);
for(int i=0;i<modelData->materialCount;i++)
materials[i].m.texRef=FileGetReference(materials[i].texName);
}
void StoreFaceVertices(tVector3 *vertices,tVector3 *normals,tVector2 *texels,tFaceData *faces,int i,tVertexArrayElement *store,int mt)
{
if(mt)
if(((tFaceDataMT*)faces)[i].vertices->normal!=-1)
for(int vertex=0;vertex<3;vertex++){
if(((tFaceDataMT*)faces)[i].vertices->texel!=-1)
store[0][vertex].texel=texels[((tFaceDataMT*)faces)[i].vertices[vertex].texel];
else
store[0][vertex].texel=Vector(0,0);
if(((tFaceDataMT*)faces)[i].vertices->texel2!=-1)
store[0][vertex].texel2=texels[((tFaceDataMT*)faces)[i].vertices[vertex].texel2];
else
store[0][vertex].texel2=Vector(0,0);
store[0][vertex].normal=normals[((tFaceDataMT*)faces)[i].vertices[vertex].normal];
store[0][vertex].vertex=vertices[((tFaceDataMT*)faces)[i].vertices[vertex].vertex];
}
else{
//otherwise, calculate a normal.
tVector3 *a=vertices+(((tFaceDataMT*)faces)[i].vertices[0].vertex);
tVector3 *b=vertices+(((tFaceDataMT*)faces)[i].vertices[1].vertex);
tVector3 *c=vertices+(((tFaceDataMT*)faces)[i].vertices[2].vertex);
tVector3 n=!((*b-*a)%(*c-*a));
for(int vertex=0;vertex<3;vertex++)
{
if(((tFaceDataMT*)faces)[i].vertices->texel!=-1)
store[0][vertex].texel=texels[((tFaceDataMT*)faces)[i].vertices[vertex].texel];
else
store[0][vertex].texel=Vector(0,0);
if(((tFaceDataMT*)faces)[i].vertices->texel2!=-1)
store[0][vertex].texel2=texels[((tFaceDataMT*)faces)[i].vertices[vertex].texel2];
else
store[0][vertex].texel2=Vector(0,0);
store[0][vertex].normal=n;
store[0][vertex].vertex=vertices[((tFaceDataMT*)faces)[i].vertices[vertex].vertex];
}
}
else if(faces[i].vertices->normal!=-1)
for(int vertex=0;vertex<3;vertex++){
if(faces[i].vertices->texel!=-1)
store[0][vertex].texel=texels[faces[i].vertices[vertex].texel];
else
store[0][vertex].texel=Vector(0,0);
store[0][vertex].normal=normals[faces[i].vertices[vertex].normal];
store[0][vertex].vertex=vertices[faces[i].vertices[vertex].vertex];
}
else{
//otherwise, calculate a normal.
tVector3 *a=vertices+(faces[i].vertices[0].vertex);
tVector3 *b=vertices+(faces[i].vertices[1].vertex);
tVector3 *c=vertices+(faces[i].vertices[2].vertex);
tVector3 n=!((*b-*a)%(*c-*a));
for(int vertex=0;vertex<3;vertex++)
{
if(faces[i].vertices->texel!=-1)
store[0][vertex].texel=texels[faces[i].vertices[vertex].texel];
else
store[0][vertex].texel=Vector(0,0);
store[0][vertex].normal=n;
store[0][vertex].vertex=vertices[faces[i].vertices[vertex].vertex];
}
}
}
void ModelInitArrays(tFileRef modelRef)
{
tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data;
int mt=modelData->modelFlags&kFlagMultiTextureFlag;
tVector3 *vertices=(tVector3*)&modelData->data;
tVector3 *normals=vertices+modelData->vertexCount;
tVector2 *texels=(tVector2*)(normals+modelData->normalCount);
tFaceData *faces=(tFaceData*)(texels+modelData->texelCount);
tFaceDataMT *facesMT=(tFaceDataMT*)(texels+modelData->texelCount);
tMaterial *materials=(tMaterial*)(faces+modelData->faceCount);
if(mt)
materials=(tMaterial*)(facesMT+modelData->faceCount);
int matCount=mt?modelData->materialCount/2:modelData->materialCount;
((tModel*)gFileTable[modelRef].parsedData)->indices=(tMaterialArrayIndices*)MemoryAllocateZeroedBlock(sizeof(tMaterialArrayIndices)*matCount);
tMaterialArrayIndices *indices=((tModel*)gFileTable[modelRef].parsedData)->indices;
((tModel*)gFileTable[modelRef].parsedData)->array=(tVertexArrayElement*)MemoryAllocateBlock(sizeof(tVertexArrayElement)*modelData->faceCount);
tVertexArrayElement *array=((tModel*)gFileTable[modelRef].parsedData)->array;
//arrays are indexed starting with 1, so we shift all arrays
//down by one index.
vertices--;
normals--;
texels--;
materials--;
//for each face
for(int i=0;i<modelData->faceCount;i++)
{
int mat=mt?facesMT[i].material:faces[i].material;
int faceMaterial=mat&kMaterialMask;
if(faceMaterial!=-1&&faceMaterial!=0)
if((!(materials[faceMaterial].m.flags&kMaterialUseAlphaChannel))||mat&kDisableTransparencyFlag)
indices[faceMaterial-1].num++;
else
indices[faceMaterial-1].numTransparent++;
}
int arrayVertexCount=0;
for(int material=1;material<=matCount;material++)
{
indices[material-1].start=arrayVertexCount;
for(int i=0;i<modelData->faceCount;i++)
{
int mat=mt?facesMT[i].material:faces[i].material;
int faceMaterial=mat&kMaterialMask;
if(material==faceMaterial)
if((!(materials[faceMaterial].m.flags&kMaterialUseAlphaChannel))||mat&kDisableTransparencyFlag)
StoreFaceVertices(vertices,normals,texels,faces,i,array+arrayVertexCount++,mt);
}
for(int i=0;i<modelData->faceCount;i++)
{
int mat=mt?facesMT[i].material:faces[i].material;
int faceMaterial=mat&kMaterialMask;
if(material==faceMaterial)
if(materials[faceMaterial].m.flags&kMaterialUseAlphaChannel&&!(mat&kDisableTransparencyFlag))
StoreFaceVertices(vertices,normals,texels,faces,i,array+arrayVertexCount++,mt);
}
}
glGenVertexArraysAPPLE(1,&(((tModel*)gFileTable[modelRef].parsedData)->arrayRef));
glBindVertexArrayAPPLE(((tModel*)gFileTable[modelRef].parsedData)->arrayRef);
glInterleavedArrays(GL_T2F_N3F_V3F,sizeof(tVertexArrayVertex),array);
if(mt){
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glTexCoordPointer(2,GL_FLOAT,sizeof(tVertexArrayVertex),((char*)array)+sizeof(tVector2)+2*sizeof(tVector3));
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
}
enum{
kModeDrawNormal,
kModeDrawEverythingSolid,
kModeDrawOnlyTransparent,
kModeDrawOnlyTransparentSolid,
kModeDrawOnlySolid,
kModeDrawEverythingGhosted
};
void ModelAddGhostedArrays(tFileRef modelRef,int textureSet)
{
tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data;
tVector3 *vertices=(tVector3*)&modelData->data;
tVector3 *normals=vertices+modelData->vertexCount;
tVector2 *texels=(tVector2*)(normals+modelData->normalCount);
tFaceData *faces=(tFaceData*)(texels+modelData->texelCount);
tMaterial *materials=(tMaterial*)(faces+modelData->faceCount);
tMaterialArrayIndices *indices=((tModel*)gFileTable[modelRef].parsedData)->indices;
tVertexArrayElement *array=((tModel*)gFileTable[modelRef].parsedData)->array;
//arrays are indexed starting with 1, so we shift all arrays
//down by one index.
materials--;
for(int i=0;i<modelData->materialCount;i++)
for(int j=indices[i].start;j<indices[i].start+indices[i].num+indices[i].numTransparent;j++)
if(tTransparentPoly *p=GetNextTransparentPoly(false))
{
p->mat=&(materials+i+1)->m;
p->ghost=true;
p->textureSet=textureSet;
for(int v=0;v<3;v++)
{
p->v[v]=array[j][v];
p->v[v].vertex=p->v[v].vertex*gTransformDir+gTransformPos;
}
}
}
void ModelAddTransparentArrays(tFileRef modelRef,int textureSet)
{
tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data;
tVector3 *vertices=(tVector3*)&modelData->data;
tVector3 *normals=vertices+modelData->vertexCount;
tVector2 *texels=(tVector2*)(normals+modelData->normalCount);
tFaceData *faces=(tFaceData*)(texels+modelData->texelCount);
tMaterial *materials=(tMaterial*)(faces+modelData->faceCount);
tMaterialArrayIndices *indices=((tModel*)gFileTable[modelRef].parsedData)->indices;
tVertexArrayElement *array=((tModel*)gFileTable[modelRef].parsedData)->array;
//arrays are indexed starting with 1, so we shift all arrays
//down by one index.
materials--;
for(int i=0;i<modelData->materialCount;i++)
for(int j=indices[i].start+indices[i].num;j<indices[i].start+indices[i].num+indices[i].numTransparent;j++)
if(tTransparentPoly *p=GetNextTransparentPoly(false))
{
p->mat=&(materials+i+1)->m;
p->textureSet=textureSet;
for(int v=0;v<3;v++)
{
p->v[v]=array[j][v];
p->v[v].normal=p->v[v].normal*gTransformDir;
p->v[v].vertex=p->v[v].vertex*gTransformDir+gTransformPos;
}
}
}
void ModelDrawArrays(tFileRef modelRef,int mode,int textureSet)
{
tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data;
int mt=modelData->modelFlags&kFlagMultiTextureFlag;
tVector3 *vertices=(tVector3*)&modelData->data;
tVector3 *normals=vertices+modelData->vertexCount;
tVector2 *texels=(tVector2*)(normals+modelData->normalCount);
tFaceData *faces=(tFaceData*)(texels+modelData->texelCount);
tFaceDataMT *facesMT=(tFaceDataMT*)(texels+modelData->texelCount);
tMaterial *materials=(tMaterial*)(faces+modelData->faceCount);
if(mt)
materials=(tMaterial*)(facesMT+modelData->faceCount);
int matCount=mt?modelData->materialCount/2:modelData->materialCount;
tMaterialArrayIndices *indices=((tModel*)gFileTable[modelRef].parsedData)->indices;
//arrays are indexed starting with 1, so we shift all arrays
//down by one index.
materials--;
glBindVertexArrayAPPLE(((tModel*)gFileTable[modelRef].parsedData)->arrayRef);
//glInterleavedArrays(GL_T2F_N3F_V3F,0,((tModel*)gFileTable[modelRef].parsedData)->array);
//glLockArraysEXT(0,modelData->faceCount*3);
/* if(TexturesSelectTextureUnit(1))
{
glTexCoordPointer(2,GL_FLOAT,sizeof(tVertexArrayVertex),((char*)((tModel*)gFileTable[modelRef].parsedData)->array)+sizeof(tVector2)+2*sizeof(tVector3));
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
TexturesSelectTextureUnit(0);
}
glTexCoordPointer(2,GL_FLOAT,sizeof(tVertexArrayVertex),((char*)((tModel*)gFileTable[modelRef].parsedData)->array));
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glNormalPointer(GL_FLOAT,sizeof(tVertexArrayVertex),((char*)((tModel*)gFileTable[modelRef].parsedData)->array)+sizeof(tVector2));
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3,GL_FLOAT,sizeof(tVertexArrayVertex),((char*)((tModel*)gFileTable[modelRef].parsedData)->array)+sizeof(tVector2)+sizeof(tVector3));
glEnableClientState(GL_VERTEX_ARRAY);*/
if(mode!=kModeDrawOnlyTransparent)
for(int i=0;i<matCount;i++)
{
int start=indices[i].start;
if(mode==kModeDrawOnlyTransparentSolid)
start+=indices[i].num;
int num;
if(mode==kModeDrawNormal||mode==kModeDrawOnlySolid)
num=indices[i].num;
else if(mode==kModeDrawOnlyTransparentSolid)
num=indices[i].numTransparent;
else if(mode==kModeDrawEverythingSolid)
num=indices[i].num+indices[i].numTransparent;
if(mt)
UseMaterial2((&(materials+i+1)->m),(&(materials+i+1+matCount)->m),textureSet);
else
UseMaterial((&(materials+i+1)->m),false,textureSet);
glDrawArrays(GL_TRIANGLES,start*3,num*3);
}
//glUnlockArraysEXT();
if((mode==kModeDrawNormal||mode==kModeDrawOnlyTransparent)&&!mt)
ModelAddTransparentArrays(modelRef,textureSet);
}
void ModelCompileDisplayList(tFileRef modelRef);
void ModelCalcClipInfo(tFileRef modelRef)
{
tVector3 minv=Vector(INFINITY,INFINITY,INFINITY);
tVector3 maxv=Vector(-INFINITY,-INFINITY,-INFINITY);
tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data;
tVector3 *vertices=(tVector3*)&modelData->data;
for(int i=0;i<modelData->vertexCount;i++)
{
if(vertices[i].x<minv.x)minv.x=vertices[i].x;
if(vertices[i].y<minv.y)minv.y=vertices[i].y;
if(vertices[i].z<minv.z)minv.z=vertices[i].z;
if(vertices[i].x>maxv.x)maxv.x=vertices[i].x;
if(vertices[i].y>maxv.y)maxv.y=vertices[i].y;
if(vertices[i].z>maxv.z)maxv.z=vertices[i].z;
}
if(modelData->vertexCount)
{
((tModel*)gFileTable[modelRef].parsedData)->center=(minv+maxv)*0.5;
((tModel*)gFileTable[modelRef].parsedData)->centerMaxExtends=~(minv-((tModel*)gFileTable[modelRef].parsedData)->center);
}
else
{
((tModel*)gFileTable[modelRef].parsedData)->center=Vector(0,0,0);
((tModel*)gFileTable[modelRef].parsedData)->centerMaxExtends=0;
}
}
void ModelSwitchEndianess(tFileRef modelRef)
{
tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data;
S32Swap(modelData->vertexCount);
S32Swap(modelData->normalCount);
S32Swap(modelData->faceCount);
S32Swap(modelData->materialCount);
S32Swap(modelData->modelFlags);
S32Swap(modelData->texelCount);
S32Swap(*((SInt32*)(&modelData->maxExtends)));
int mt=modelData->modelFlags&kFlagMultiTextureFlag;
tVector3 *vertices=(tVector3*)&modelData->data;
tVector3 *normals=vertices+modelData->vertexCount;
tVector2 *texels=(tVector2*)(normals+modelData->normalCount);
tFaceData *faces=(tFaceData*)(texels+modelData->texelCount);
tFaceDataMT *facesMT=(tFaceDataMT*)(texels+modelData->texelCount);
tMaterial *materials=(tMaterial*)(faces+modelData->faceCount);
if(mt)
materials=(tMaterial*)(facesMT+modelData->faceCount);
for(int i=0;i<modelData->vertexCount;i++)
{
S32Swap(*((SInt32*)(&(vertices[i].x))));
S32Swap(*((SInt32*)(&(vertices[i].y))));
S32Swap(*((SInt32*)(&(vertices[i].z))));
}
for(int i=0;i<modelData->normalCount;i++)
{
S32Swap(*((SInt32*)(&(normals[i].x))));
S32Swap(*((SInt32*)(&(normals[i].y))));
S32Swap(*((SInt32*)(&(normals[i].z))));
}
for(int i=0;i<modelData->texelCount;i++)
{
S32Swap(*((SInt32*)(&(texels[i].x))));
S32Swap(*((SInt32*)(&(texels[i].y))));
}
if(mt)
for(int i=0;i<modelData->faceCount;i++)
{
S32Swap(facesMT[i].material);
for(int j=0;j<3;j++)
{
S32Swap(facesMT[i].vertices[j].vertex);
S32Swap(facesMT[i].vertices[j].normal);
S32Swap(facesMT[i].vertices[j].texel);
S32Swap(facesMT[i].vertices[j].texel2);
S32Swap(facesMT[i].vertices[j].neighbor);
}
}
else
for(int i=0;i<modelData->faceCount;i++)
{
S32Swap(faces[i].material);
for(int j=0;j<3;j++)
{
S32Swap(faces[i].vertices[j].vertex);
S32Swap(faces[i].vertices[j].normal);
S32Swap(faces[i].vertices[j].texel);
S32Swap(faces[i].vertices[j].neighbor);
}
}
for(int i=0;i<modelData->materialCount;i++)
{
S32Swap(materials[i].m.flags);
S32Swap(*((SInt32*)(&(materials[i].m.shininess))));
S32Swap(*((SInt32*)(&(materials[i].m.specular.x))));
S32Swap(*((SInt32*)(&(materials[i].m.specular.y))));
S32Swap(*((SInt32*)(&(materials[i].m.specular.z))));
S32Swap(*((SInt32*)(&(materials[i].m.ambient.x))));
S32Swap(*((SInt32*)(&(materials[i].m.ambient.y))));
S32Swap(*((SInt32*)(&(materials[i].m.ambient.z))));
S32Swap(*((SInt32*)(&(materials[i].m.diffuse.x))));
S32Swap(*((SInt32*)(&(materials[i].m.diffuse.y))));
S32Swap(*((SInt32*)(&(materials[i].m.diffuse.z))));
}
}
//Load a model from disk
void ModelLoad(tFileRef modelRef)
{
gFileTable[modelRef].parsedData=MemoryAllocateBlock(sizeof(tModel));
((tModel*)gFileTable[modelRef].parsedData)->data=(tModelData*)FileGetDataPtr(modelRef);
#if TARGET_RT_LITTLE_ENDIAN
ModelSwitchEndianess(modelRef);
#endif
ModelInsertTextureRefs(modelRef);
#ifdef __USEVERTEXARRAYS
ModelInitArrays(modelRef);
#endif
#ifdef __USEDISPLAYLISTS
ModelCompileDisplayList(modelRef);
#endif
gFileTable[modelRef].parsed=true;
ModelCalcClipInfo(modelRef);
tModelList *modelList=gModelList;
gModelList=(tModelList*)MemoryAllocateBlock(sizeof(tModelList));
gModelList->next=(void*)modelList;
gModelList->model=modelRef;
}
tVector3 ModelGetCenter(tFileRef modelRef)
{
if(!gFileTable[modelRef].parsed)
ModelLoad(modelRef);
return ((tModel*)gFileTable[modelRef].parsedData)->center;
}
float ModelGetCenterMaxExtends(tFileRef modelRef)
{
if(!gFileTable[modelRef].parsed)
ModelLoad(modelRef);
return ((tModel*)gFileTable[modelRef].parsedData)->centerMaxExtends;
}
//Dispose all data structures associated with a model.
void ModelDispose(tFileRef modelRef)
{
MemoryFreeBlock(((tModel*)gFileTable[modelRef].parsedData)->data);
MemoryFreeBlock(((tModel*)gFileTable[modelRef].parsedData)->indices);
MemoryFreeBlock(((tModel*)gFileTable[modelRef].parsedData)->array);
if(gFileTable[modelRef].data!=((tModel*)gFileTable[modelRef].parsedData)->data)
MemoryFreeBlock(gFileTable[modelRef].data);
#ifdef __USEDISPLAYLISTS
glDeleteLists(((tModel*)gFileTable[modelRef].parsedData)->ref,1);
#endif
glDeleteVertexArraysAPPLE(1,&((tModel*)gFileTable[modelRef].parsedData)->arrayRef);
MemoryFreeBlock(((tModel*)gFileTable[modelRef].parsedData));
gFileTable[modelRef].parsed=false;
gFileTable[modelRef].loaded=false;
}
void ModelsUnloadAll()
{
while(gModelList!=NULL)
{
tModelList *next=(tModelList*)gModelList->next;
ModelDispose(gModelList->model);
MemoryFreeBlock(gModelList);
gModelList=next;
}
}
//return the maximum extends of a model. (the distance from
//the furthest vertex from center).
float ModelGetMaxExtends(tFileRef modelRef)
{
if(!gFileTable[modelRef].parsed)
ModelLoad(modelRef);
if(!gFileTable[modelRef].parsed)
return 0;
tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data;
if(!modelData->maxExtends)
{
tVector3 *vertices=(tVector3*)&modelData->data;
tVector3 maxExtends=Vector(0,0,0);
for(int i=0;i<modelData->vertexCount;i++)
{
if(fabs(vertices[i].x)>maxExtends.x)maxExtends.x=fabs(vertices[i].x);
if(fabs(vertices[i].y)>maxExtends.y)maxExtends.y=fabs(vertices[i].y);
if(fabs(vertices[i].z)>maxExtends.z)maxExtends.z=fabs(vertices[i].z);
}
modelData->maxExtends=~maxExtends;
}
return modelData->maxExtends;
}
//Draw a model
void ModelDraw(tFileRef modelRef,int mode,int textureSet)
{
tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data;
tVector3 *vertices=(tVector3*)&modelData->data;
tVector3 *normals=vertices+modelData->vertexCount;
tVector2 *texels=(tVector2*)(normals+modelData->normalCount);
tFaceData *faces=(tFaceData*)(texels+modelData->texelCount);
tMaterial *materials=(tMaterial*)(faces+modelData->faceCount);
//arrays are indexed starting with 1, so we shift all arrays
//down by one index.
vertices--;
normals--;
texels--;
materials--;
int material=-1;//currently used material
int transparent;
//for each face
for(int i=0;i<modelData->faceCount;i++)
{
int faceMaterial=faces[i].material&kMaterialMask;
//check if the material is the same as we were using
if(faceMaterial!=material){
//if not, change material
transparent=UseMaterial(&((materials+faceMaterial)->m),false,textureSet);
if(mode==kModeDrawEverythingSolid)
transparent=false;
material=faceMaterial;
}
//if the face isn't transparent, draw it
int drawTransparent=transparent&&!(faces[i].material&kDisableTransparencyFlag);
if(!drawTransparent||(drawTransparent&&mode==kModeDrawOnlyTransparentSolid))
{
if(mode!=kModeDrawOnlyTransparent)
{
glBegin(GL_TRIANGLES);
//do we have a normal?
if(faces[i].vertices->normal!=-1)
for(int vertex=0;vertex<3;vertex++){
if(faces[i].vertices->texel!=-1)
glTexCoord2fv(&texels[faces[i].vertices[vertex].texel].x);
glNormal3fv(&normals[faces[i].vertices[vertex].normal].x);
glVertex3fv(&vertices[faces[i].vertices[vertex].vertex].x);
}
else{
//otherwise, calculate a normal.
tVector3 *a=vertices+(faces[i].vertices[0].vertex);
tVector3 *b=vertices+(faces[i].vertices[1].vertex);
tVector3 *c=vertices+(faces[i].vertices[2].vertex);
tVector3 n=!((*b-*a)%(*c-*a));
glNormal3fv(&n.x);
for(int vertex=0;vertex<3;vertex++)
{
if(faces[i].vertices->texel!=-1)
glTexCoord2fv(&texels[faces[i].vertices[vertex].texel].x);
glVertex3fv(&vertices[faces[i].vertices[vertex].vertex].x);
}
}
glEnd();
}
}
//if the face is transparent, add it to the list of transparent faces
else if(mode!=kModeDrawOnlySolid)
if(tTransparentPoly *p=GetNextTransparentPoly(false)){
if(faces[i].vertices->normal!=-1)
for(int vertex=0;vertex<3;vertex++){
if(faces[i].vertices->texel!=-1)
p->v[vertex].texel=texels[faces[i].vertices[vertex].texel];
else
p->v[vertex].texel=Vector(0,0);
p->v[vertex].normal=normals[faces[i].vertices[vertex].normal]*gTransformDir;
p->v[vertex].vertex=vertices[faces[i].vertices[vertex].vertex]*gTransformDir+gTransformPos;
}
else{
tVector3 *a=vertices+(faces[i].vertices[0].vertex);
tVector3 *b=vertices+(faces[i].vertices[1].vertex);
tVector3 *c=vertices+(faces[i].vertices[2].vertex);
tVector3 n=!((*b-*a)%(*c-*a));
for(int vertex=0;vertex<3;vertex++)
{
if(faces[vertex].vertices->texel!=-1)
p->v[vertex].texel=texels[faces[i].vertices[vertex].texel];
else
p->v[vertex].texel=Vector(0,0);
p->v[vertex].normal=n*gTransformDir;
p->v[vertex].vertex=vertices[faces[i].vertices[vertex].vertex]*gTransformDir+gTransformPos;
}
}
p->mat=&(materials+faces[i].material)->m;
p->textureSet=textureSet;
}
}
}
void ModelDrawMultiTextured(tFileRef modelRef,int textureSet)
{
tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data;
tVector3 *vertices=(tVector3*)&modelData->data;
tVector3 *normals=vertices+modelData->vertexCount;
tVector2 *texels=(tVector2*)(normals+modelData->normalCount);
tFaceDataMT *faces=(tFaceDataMT*)(texels+modelData->texelCount);
tMaterial *materials=(tMaterial*)(faces+modelData->faceCount);
//arrays are indexed starting with 1, so we shift all arrays
//down by one index.
vertices--;
normals--;
texels--;
materials--;
int material=-1;//currently used material
//for each face
for(int i=0;i<modelData->faceCount;i++)
{
int faceMaterial=faces[i].material&kMaterialMask;
//check if the material is the same as we were using
if(faceMaterial!=material){
//if not, change material
UseMaterial2(&((materials+faceMaterial)->m),&((materials+faceMaterial+modelData->materialCount/2)->m),textureSet);
material=faceMaterial;
}
glBegin(GL_TRIANGLES);
//do we have a normal?
if(faces[i].vertices->normal!=-1)
for(int vertex=0;vertex<3;vertex++){
if(faces[i].vertices->texel!=-1)
glTexCoord2fv(&texels[faces[i].vertices[vertex].texel].x);
if(faces[i].vertices->texel2!=-1)
glMultiTexCoord2fv(GL_TEXTURE1,&texels[faces[i].vertices[vertex].texel2].x);
glNormal3fv(&normals[faces[i].vertices[vertex].normal].x);
glVertex3fv(&vertices[faces[i].vertices[vertex].vertex].x);
}
else{
//otherwise, calculate a normal.
tVector3 *a=vertices+(faces[i].vertices[0].vertex);
tVector3 *b=vertices+(faces[i].vertices[1].vertex);
tVector3 *c=vertices+(faces[i].vertices[2].vertex);
tVector3 n=!((*b-*a)%(*c-*a));
glNormal3fv(&n.x);
for(int vertex=0;vertex<3;vertex++)
{
if(faces[i].vertices->texel!=-1)
glTexCoord2fv(&texels[faces[i].vertices[vertex].texel].x);
if(faces[i].vertices->texel2!=-1)
glMultiTexCoord2fv(GL_TEXTURE1,&texels[faces[i].vertices[vertex].texel2].x);
glVertex3fv(&vertices[faces[i].vertices[vertex].vertex].x);
}
}
glEnd();
}
}
void ModelLoadTextures(tFileRef modelRef)
{
tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data;
tVector3 *vertices=(tVector3*)&modelData->data;
tVector3 *normals=vertices+modelData->vertexCount;
tVector2 *texels=(tVector2*)(normals+modelData->normalCount);
tFaceData *faces=(tFaceData*)(texels+modelData->texelCount);
tMaterial *materials=(tMaterial*)(faces+modelData->faceCount);
for(int i=0;i<modelData->materialCount;i++)
UseMaterial(&((materials+i)->m),false,0);
}
void ModelCompileDisplayList(tFileRef modelRef)
{
//create an OpenGL display list for a model
((tModel*)gFileTable[modelRef].parsedData)->ref=glGenLists(1);
ModelLoadTextures(modelRef);
glNewList(((tModel*)gFileTable[modelRef].parsedData)->ref,GL_COMPILE);
#ifdef __USEVERTEXARRAYS
ModelDrawArrays(modelRef,kModeDrawOnlySolid,0);
#else
ModelDraw(modelRef,kModeDrawOnlySolid,0);
#endif
glEndList();
}
void ModelShadowPassZFail(tFileRef modelRef,tVector3 shadowVector,char *faceSide)
{
tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data;
tVector3 *vertices=(tVector3*)&modelData->data;
tVector3 *normals=vertices+modelData->vertexCount;
tVector2 *texels=(tVector2*)(normals+modelData->normalCount);
vertices--;
tFaceData *faces=(tFaceData*)(texels+modelData->texelCount);
tMaterial *materials=(tMaterial*)(faces+modelData->faceCount);
materials--;
tVector3 sw=0.05*!shadowVector;
for(int i=0;i<modelData->faceCount;i++)
if(!((materials+(faces[i].material&kMaterialMask))->m.flags&kMaterialDisableShadow))
if(modelData->modelFlags&kFlagShadowFlag)
{
for(int n=0;n<3;n++)
if(faces[i].vertices[n].neighbor<=-1)
{
glBegin(GL_TRIANGLE_STRIP);
glVertex3fv(&(vertices[faces[i].vertices[n].vertex]*gStencilZoom-sw).x);
glVertex3fv(&(vertices[faces[i].vertices[(n+1)%3].vertex]*gStencilZoom-sw).x);
glVertex3fv(&(vertices[faces[i].vertices[n].vertex]*gStencilZoom-shadowVector).x);
glVertex3fv(&(vertices[faces[i].vertices[(n+1)%3].vertex]*gStencilZoom-shadowVector).x);
glEnd();
#ifdef __POLYCOUNT
gPolyCount+=2;
#endif
}
if(faceSide[i]||1)
{
glBegin(GL_TRIANGLES);
for(int j=2;j>=0;j--)
glVertex3fv(&(vertices[faces[i].vertices[j].vertex]*gStencilZoom-sw).x);
for(int j=0;j<=2;j++)
glVertex3fv(&(vertices[faces[i].vertices[j].vertex]*gStencilZoom-shadowVector).x);
glEnd();
}
else
{
glBegin(GL_TRIANGLES);
for(int j=2;j>=0;j--)
glVertex3fv(&(vertices[faces[i].vertices[j].vertex]*gStencilZoom-shadowVector).x);
for(int j=0;j<=2;j++)
glVertex3fv(&(vertices[faces[i].vertices[j].vertex]*gStencilZoom-sw).x);
glEnd();
}
}
else
if(faceSide[i])
{
for(int n=0;n<3;n++)
if(faces[i].vertices[n].neighbor!=-1)
{
if(faceSide[faces[i].vertices[n].neighbor]!=faceSide[i])
{
glBegin(GL_TRIANGLE_STRIP);
glVertex3fv(&(vertices[faces[i].vertices[n].vertex]*(kShadowZoom*gStencilZoom)).x);
glVertex3fv(&(vertices[faces[i].vertices[(n+1)%3].vertex]*(kShadowZoom*gStencilZoom)).x);
glVertex3fv(&(vertices[faces[i].vertices[n].vertex]*(kShadowZoom*gStencilZoom)-shadowVector).x);
glVertex3fv(&(vertices[faces[i].vertices[(n+1)%3].vertex]*(kShadowZoom*gStencilZoom)-shadowVector).x);
glEnd();
#ifdef __POLYCOUNT
gPolyCount+=2;
#endif
}
}
glBegin(GL_TRIANGLES);
for(int j=2;j>=0;j--)
glVertex3fv(&(vertices[faces[i].vertices[j].vertex]*(kShadowZoom*gStencilZoom)).x);
glEnd();
}
else
{
glBegin(GL_TRIANGLES);
for(int j=2;j>=0;j--)
glVertex3fv(&(vertices[faces[i].vertices[j].vertex]*(kShadowZoom*gStencilZoom)-shadowVector).x);
glEnd();
}
#ifdef __POLYCOUNT
gPolyCount+=modelData->faceCount;
#endif
}
void ModelShadowPassZPass(tFileRef modelRef,tVector3 shadowVector,char *faceSide)
{
tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data;
tVector3 *vertices=(tVector3*)&modelData->data;
tVector3 *normals=vertices+modelData->vertexCount;
tVector2 *texels=(tVector2*)(normals+modelData->normalCount);
vertices--;
tFaceData *faces=(tFaceData*)(texels+modelData->texelCount);
tMaterial *materials=(tMaterial*)(faces+modelData->faceCount);
materials--;
if(modelData->modelFlags&kFlagShadowFlag)
{
tVector3 sw=0.05*!shadowVector;
for(int i=0;i<modelData->faceCount;i++)
if(!((materials+(faces[i].material&kMaterialMask))->m.flags&kMaterialDisableShadow))
{
for(int n=0;n<3;n++)
if(faces[i].vertices[n].neighbor==-1)
{
glBegin(GL_TRIANGLE_STRIP);
glVertex3fv(&(vertices[faces[i].vertices[n].vertex]*gStencilZoom-sw).x);
glVertex3fv(&(vertices[faces[i].vertices[(n+1)%3].vertex]*gStencilZoom-sw).x);
glVertex3fv(&(vertices[faces[i].vertices[n].vertex]*gStencilZoom-shadowVector).x);
glVertex3fv(&(vertices[faces[i].vertices[(n+1)%3].vertex]*gStencilZoom-shadowVector).x);
glEnd();
#ifdef __POLYCOUNT
gPolyCount+=2;
#endif
}
}
}
else for(int i=0;i<modelData->faceCount;i++)
if(!((materials+(faces[i].material&kMaterialMask))->m.flags&kMaterialDisableShadow))
if(faceSide[i]||(modelData->modelFlags&kFlagShadowFlag))
for(int n=0;n<3;n++)
if(faces[i].vertices[n].neighbor!=-1)
if(faceSide[faces[i].vertices[n].neighbor]!=faceSide[i])
{
glBegin(GL_TRIANGLE_STRIP);
glVertex3fv(&(vertices[faces[i].vertices[n].vertex]*(kShadowZoom*gStencilZoom)).x);
glVertex3fv(&(vertices[faces[i].vertices[(n+1)%3].vertex]*(kShadowZoom*gStencilZoom)).x);
glVertex3fv(&(vertices[faces[i].vertices[n].vertex]*(kShadowZoom*gStencilZoom)-shadowVector).x);
glVertex3fv(&(vertices[faces[i].vertices[(n+1)%3].vertex]*(kShadowZoom*gStencilZoom)-shadowVector).x);
glEnd();
#ifdef __POLYCOUNT
gPolyCount+=2;
#endif
}
}
//for each face of a model, calculate whether it faces the light or not.
//return the results in the array faceSide
void CalcFaceSides(tFileRef modelRef,tVector3 lightDir,char **faceSide)
{
tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data;
tVector3 *vertices=(tVector3*)&modelData->data;
tVector3 *normals=vertices+modelData->vertexCount;
tVector2 *texels=(tVector2*)(normals+modelData->normalCount);
vertices--;
tFaceData *faces=(tFaceData*)(texels+modelData->texelCount);
*faceSide=(char*)MemoryAllocateBlock(sizeof(char)*modelData->faceCount+10);
for(int i=0;i<modelData->faceCount;i++){
tVector3 *a=vertices+(faces[i].vertices[0].vertex);
tVector3 *b=vertices+(faces[i].vertices[1].vertex);
tVector3 *c=vertices+(faces[i].vertices[2].vertex);
//calculate a normal to the face
tVector3 n=((*b-*a)%(*c-*a));
//use dot product to determine if the face faces the light
(*faceSide)[i]=n*lightDir>0;
}
}
//Draw the shadow of a model
//Uses s stencil buffer-based shadow volume algorithm
void ModelCastShadow(tFileRef modelRef,float shadowLength)
{
tVector3 lightDir=gEnvironment->lightDir;
if(gMapEnv)
if(!VectorZero(gMapEnv->lightDir))
lightDir=gMapEnv->lightDir;
tMatrix3 tr;
MatrixTranspose(gTransformDir,tr);
lightDir=lightDir*tr;
char *faceSide;
CalcFaceSides(modelRef,lightDir,&faceSide);
//disable actual drawing
glDisable(GL_LIGHTING);
glDisable(GL_FOG);
glDepthMask(GL_FALSE);
glColorMask(0, 0, 0, 0);
//enable stencil buffer drawing
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0, 0xffffffff);
tVector3 lightNormal1=!((gTransformPos-gCameraEntity->pos)%lightDir);
tVector3 lightNormal2=lightNormal1%lightDir;
tVector3 shadowVector=lightDir*shadowLength;
//is the camera possibly in the shadow volume?
if(-lightNormal2*(gTransformPos-gCameraEntity->pos)<ModelGetMaxExtends(modelRef)+shadowLength)
{
//if the camera is possibly inside the shadow volume,
//we have to use zFail rendering, as normal zPass rendering
//won't work if the camera is inside the shadow volume.
glFrontFace(GL_CW);
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
ModelShadowPassZFail(modelRef,shadowVector,faceSide);
glFrontFace(GL_CCW);
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
ModelShadowPassZFail(modelRef,shadowVector,faceSide);
}
else
{//zPass Rendering
glFrontFace(GL_CCW);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
ModelShadowPassZPass(modelRef,shadowVector,faceSide);
glFrontFace(GL_CW);
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
ModelShadowPassZPass(modelRef,shadowVector,faceSide);
}
MemoryFreeBlock(faceSide);
glDepthMask(GL_TRUE);
glColorMask(1, 1, 1, 1);
}
//draw a model
void DrawModel(tFileRef modelRef,int allowTransparency,int textureSet)
{
if(!gFileTable[modelRef].parsed)
ModelLoad(modelRef);
if(!gFileTable[modelRef].parsed)
return;
#ifdef __USEDISPLAYLISTS
glCallList(((tModel*)gFileTable[modelRef].parsedData)->ref);
#ifdef __USEVERTEXARRAYS
ModelDrawArrays(modelRef,allowTransparency?kModeDrawOnlyTransparent:kModeDrawOnlyTransparentSolid,textureSet);
#else
ModelDraw(modelRef,allowTransparency?kModeDrawOnlyTransparent:kModeDrawOnlyTransparentSolid,textureSet);
#endif
#else
#ifdef __USEVERTEXARRAYS
if(allowTransparency==kTransparencyGhost)
ModelAddGhostedArrays(modelRef,textureSet);
else
ModelDrawArrays(modelRef,allowTransparency?kModeDrawNormal:kModeDrawEverythingSolid,textureSet);
#else
if((((tModel*)gFileTable[modelRef].parsedData)->data)->modelFlags&kFlagMultiTextureFlag)
ModelDrawMultiTextured(modelRef,textureSet);
else
ModelDraw(modelRef,allowTransparency?kModeDrawNormal:kModeDrawEverythingSolid,textureSet);
#endif
#endif
#ifdef __POLYCOUNT
gPolyCount+=((tModelData*)((tModel*)gFileTable[modelRef].parsedData)->data)->faceCount;
#endif
if(TexturesSelectTextureUnit(1)){
glDisable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_3D);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
TexturesSelectTextureUnit(0);
}
}
//draw a model's shadow
void DrawModelShadow(tFileRef modelRef,float shadowLength)
{
if(!gFileTable[modelRef].parsed)
ModelLoad(modelRef);
if(!gFileTable[modelRef].parsed)
return;
if((((tModel*)gFileTable[modelRef].parsedData)->data)->modelFlags&kFlagMultiTextureFlag)
return;
if(shadowLength>0)
ModelCastShadow(modelRef,shadowLength);
}

1
source/models.h Executable file
View File

@ -0,0 +1 @@
#ifndef __MODELS #define __MODELS #include "fileio.h" #include "vectors.h" enum{ kTransparencyOff, kTransparencyOn, kTransparencyGhost }; extern float gShadowZoom; void ModelLoad(tFileRef modelRef); void ModelDispose(tFileRef modelRef); void ModelsUnloadAll(); void DrawModel(tFileRef modelRef,int allowTransparency,int textureSet); void DrawModelShadow(tFileRef modelRef,float shadowLength); float ModelGetMaxExtends(tFileRef modelRef); tVector3 ModelGetCenter(tFileRef modelRef); float ModelGetCenterMaxExtends(tFileRef modelRef); #endif

78
source/modeltypes.h Normal file
View File

@ -0,0 +1,78 @@
//modeltypes.h
//type definitions for 3d models
#ifndef __MODELTYPES
#define __MODELTYPES
#include "transparency.h"
#include <OpenGL/gl.h>
#define kDisableTransparencyFlag 0x80000000
#define kMaterialMask (~kDisableTransparencyFlag)
#define kFlagShadowFlag 1<<0
#define kFlagMultiTextureFlag 1<<1
//one vertex of a model's face.
typedef struct{
int vertex; //the index of the actual vertex coordinates
int normal; //the index of the vertex normal (or -1 for none)
int texel; //the index of the texture coordinates
int neighbor;//the index of the face sharing the edge belonging to this vertex (or -1 for none)
} tFaceVertex;
//one face of a model
typedef struct{
int material;
tFaceVertex vertices[3];
} tFaceData;
//one vertex of a model's face.
typedef struct{
int vertex; //the index of the actual vertex coordinates
int normal; //the index of the vertex normal (or -1 for none)
int texel,texel2; //the index of the texture coordinates
int neighbor;//the index of the face sharing the edge belonging to this vertex (or -1 for none)
} tFaceVertexMT;
//one face of a model
typedef struct{
int material;
tFaceVertexMT vertices[3];
} tFaceDataMT;
//the model data structure
typedef struct{
int vertexCount,normalCount,texelCount,faceCount,materialCount;//number of vertices,normal, etc... used
int modelFlags; //model flags
float maxExtends; //the distance between the farest vertex and the point (0,0,0)
char data[1]; //the actual model data:
// -vertexCount vertices as tVector3
// -normalCount normals as tVector3
// -texelCount texels as tVector2
// -faceCount faces as tFaceData
// -materialCount materials as tMaterial
} tModelData;
//a model's material structure
typedef struct{
char texName[32];//the filename of the texture used.
tPolyMaterial m;//and the material structure
}tMaterial;
typedef struct{
int start,num,numTransparent;
} tMaterialArrayIndices;
//a pointer to the model data and a GL display list reference
typedef struct{
GLuint arrayRef,ref;
tMaterialArrayIndices *indices;
tVertexArrayElement *array;
tModelData *data;
tVector3 center;
float centerMaxExtends;
}tModel;
#endif

69
source/music.cpp Normal file
View File

@ -0,0 +1,69 @@
//#include "RDriver.h" // Mad Driver functions & globals
#include "fileio.h"
#include "error.h"
#include "config.h"
#include "music.h"
/*
MADDriverRec *gMADDriver;
MADLibrary *gMADLib;
MADMusic *gMADMusic;
*/
int gMusicPlaying=false;
tFileRef gSongRef=-1;
void MyDebugStr(short s, Ptr p1, Ptr p2)
{
FailWithErrorString(p2);
}
void MusicInit()
{
/* MADDriverSettings init;
MADGetBestDriver(&init);
HandleError(MADInitLibrary(nil,init.sysMemory,&gMADLib));
HandleError(MADCreateDriver(&init,gMADLib,&gMADDriver));
MADStartDriver(gMADDriver);
MusicSetVolume();*/
}
void MusicStopSong()
{
/* if(gMusicPlaying)
{
gMusicPlaying=false;
MADStopMusic(gMADDriver); // Stop reading current partition
MADCleanDriver(gMADDriver);
MADDisposeMusic(&gMADMusic,gMADDriver); // Dispose the current music
}*/
}
void MusicPlaySong(tFileRef song)
{
/* gSongRef=song;
if(gConfig->musicVolume!=0)
{
if(gMusicPlaying)
MusicStopSong();
HandleError(MADLoadMusicPtr(&gMADMusic,(char*)FileGetDataPtr(song)));
MADAttachDriverToMusic(gMADDriver,gMADMusic,0L);
MADPlayMusic(gMADDriver);
gMusicPlaying=true;
MusicSetVolume();
}*/
}
void MusicSetVolume()
{
/*gMADDriver->VolGlobal=64*gConfig->musicVolume;
if(gConfig->musicVolume==0)
MusicStopSong();
else if(!gMusicPlaying&&gSongRef!=-1)
MusicPlaySong(gSongRef);*/
}
void MusicExit()
{
/* MADStopDriver(gMADDriver); // Stop driver interrupt function
MADDisposeDriver(gMADDriver); // Dispose music driver
MADDisposeLibrary(gMADLib); // Close music library*/
}

10
source/music.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef __MUSIC
#define __MUSIC
void MusicInit();
void MusicPlaySong(tFileRef song);
void MusicStopSong();
void MusicExit();
void MusicSetVolume();
#endif

126
source/network.h Normal file
View File

@ -0,0 +1,126 @@
#ifndef __NETWORK
#define __NETWORK
#include "gameinitexit.h"
enum{
kMessageTypeSynch=1,
kMessageTypeSynchStart=2,
kMessageTypeID=3,
kMessageTypeCarID=4,
kMessageTypeStart=5,
kMessageTypeEndGame=6,
kMessageTypeEndReplay=7,
kMessageTypeGameInfo=8,
kMessageTypePhysics=9,
kMessageTypeChat=10,
kMessageTypePing=11,
kMessageTypePong=12,
kMessageTypeJoinDenied=13,
kMessageTypeVersionConfirmed=14,
kMessageTypeVersionDenied=15,
kMessageTypePause=16,
kMessageTypeResume=17,
kMessageTypePlayerLeft=18,
kMessageTypePlayerJoined=19,
kMessageTypeGameTerminated=20,
kMessageTypeVersion=21,
kMessageTypeKicked=22,
kMessageTypeBye=23,
kMessageTypeFinishTime=24,
};
enum{
kJoinDeniedInProgress,
kJoinDeniedVersion
};
enum{
kMessagePriorityLow,
kMessagePriorityNormal,
kMessagePriorityHigh
};
enum{
kMessageNoRecipients=-1,
kMessageSendToAll=-2,
kMessageSendToAllButSelf=-3,
kMessageSendToHostOnly=-4
};
typedef struct{
UInt8 playerID;
UInt8 color;
UInt64 license;
UInt32 licenseCopies;
char carName[kMaxFileNameLength];
char playerName[256];
// UInt32 checksum;
}tCarIDMessage;
enum{
kChatFlagAlert=1<<0,
kChatFlagSystem=1<<1,
kChatFlagSilent=1<<2
};
typedef struct{
UInt8 flags;
float recvTime;
char str[256];
} tChatMessage;
typedef struct{
int player;
int time;
}tFinishTimeMessage;
typedef struct{
void *opaqueRef;
void *data;
long size;
int from;
char what;
} tNetworkPacket;
enum{
kNetworkDisconnectBan,
kNetworkDisconnectLicenseCopies,
kNetworkDisconnectPirate,
kNetworkDisconnectNoDemo,
};
void NetworkInit();
void NetworkExit();
int JoinNetGame(char *address,char *errorString);
void HostNetGame(int maxPlayers,char *password);
int NetworkSynch(int numPlayers);
void ExitNetGame();
int NetworkGetLocalNetID();
void NetworkSendPacket(char messageType,void *message,long size,int priority,int to);
void NetworkSendPacket(char messageType,void *message,long size,int priority,int to,int notTo);
void NetworkDisconnectPlayer(int netID,UInt8 type);
void NetworkIdle();
int NetworkReceivePacket(tNetworkPacket* packet);
void NetworkDisposePacket(tNetworkPacket* packet);
void NetworkQueuePacket(tNetworkPacket *insert);
void NetworkClearPacketQueue();
void NetworkGetStatusString(char *str);
void NetworkGetBandwidth(float *rcv,float *snd);
void NetworkPreSession();
float NetworkGetPlayerPing(int netID);
void NetworkLockOutNewPlayers();
void NetworkUnlockOutNewPlayers();
void NetworkChangePassword(char *pass);
#define S64Swap(value) ((value)=EndianS64_BtoN(value))
#define U64Swap(value) ((value)=EndianU64_BtoN(value))
#define S32Swap(value) ((value)=EndianS32_BtoN(value))
#define U32Swap(value) ((value)=EndianU32_BtoN(value))
#define S16Swap(value) ((value)=EndianS16_BtoN(value))
#define U16Swap(value) ((value)=EndianU16_BtoN(value))
#define F32Swap(value) ((*((UInt32*)(&(value))))=EndianU32_BtoN(*((UInt32*)(&(value)))))
#define F64Swap(value) ((*((UInt64*)(&(value))))=EndianU64_BtoN(*((UInt64*)(&(value)))))
extern int gInternetAvailable;
#endif

924
source/network_NT.cpp Normal file
View File

@ -0,0 +1,924 @@
//network.cpp
//basic game hosting/joining and message sending code based on Network_Tool
#include <network_tool.h>
#include <stdio.h>
#include <string.h>
#include "gametime.h"
#include "config.h"
#include "network.h"
#include "error.h"
#include "gameframe.h"
#include "controls.h"
#include "gamesound.h"
#include "carphysics.h"
#include "interfaceutil.h"
#include "gamemem.h"
#include "Reggie.h"
#include "gamesystem.h"
#include "interfacemultiplayer.h"
#include "initexit.h"
#include "reg_tool_3.h"
extern ReggieRef gReggieRef;
extern int gReggieConnected;
int gAllowCompression=true;
#define kGameName "Redline"
#define kConnectionTimeOut 5.0
#define kCompressionSize 32
#define kCompressionFlag 0x80
NT_SessionRef gSessionRef=nil;
typedef struct{
QStub qstub;
tNetworkPacket packet;
}tQueuedPacket;
Queue gPacketQueue;
int gInternetAvailable=true;
int gTerminateSession=false;
float gLastPingReceived=0,gLastRTT=0;
char gHistoryBuffer[1024*500]="";
int gHistoryDumps=0;
void NetworkLockOutNewPlayers()
{
// HandleError(NT_SetSessionLock(gSessionRef,true));
int err=NT_SetSessionLock(gSessionRef,true);
//PrintConsoleString("Locking session. returns %d",err);
}
void NetworkUnlockOutNewPlayers()
{
// HandleError(NT_SetSessionLock(gSessionRef,false));
int err=NT_SetSessionLock(gSessionRef,false);
//PrintConsoleString("Unlocking session. returns %d",err);
}
int NetworkGetLocalNetID()
{
NT_MemberInfo info;
NT_GetSelfMemberInfo(gSessionRef,&info);
return info.member;
}
void NetworkClearPacketQueue()
{
int temp=gTerminateSession;
gTerminateSession=false;
tNetworkPacket packet;
while(NetworkReceivePacket(&packet))
if(packet.data)
MemoryFreeBlock(packet.data);
gTerminateSession=temp;
}
Result32 CompressPacket(void *buffer, long *length) {
Result32 error = eCommonErrorNone;
void ** indirect = NULL;
qThrowIfNull(indirect = IndirectInitialize(buffer, *length),
eCommonErrorOutOfMem, kCommonErrorOutOfMemStr);
qThrowIfError(IndirectCompress(indirect,
kIndirectCompressorZLib, NULL), 0);
MemoryCopy(buffer, *indirect, *length = IndirectGetSize(indirect));
CLEANUP:
if (indirect) IndirectDeallocate(indirect);
return(error);
}
Result32 DecompressPacket(void *buffer, long *length) {
Result32 error = eCommonErrorNone;
void ** indirect = NULL;
qThrowIfNull(indirect = IndirectInitialize(buffer, *length),
eCommonErrorOutOfMem, kCommonErrorOutOfMemStr);
qThrowIfError(IndirectDecompress(indirect,
kIndirectCompressorZLib, NULL), 0);
MemoryCopy(buffer, *indirect, *length = IndirectGetSize(indirect));
CLEANUP:
if (indirect) IndirectDeallocate(indirect);
return(error);
}
void NetworkGetStatusString(char *str)
{
NT_ProblemInfo prob;
if(NT_GetProblemInfo(gSessionRef,0,&prob))
{
if(prob.timeout<10)
str[0]='.';
else if(prob.timeout<50)
str[0]='t';
else
str[0]='T';
if(prob.latency<10)
str[1]='.';
else if(prob.latency<50)
str[1]='l';
else
str[1]='L';
if(prob.stalled<10)
str[2]='.';
else if(prob.stalled<50)
str[2]='s';
else
str[2]='S';
if(prob.backlog<10)
str[3]='.';
else if(prob.backlog<50)
str[3]='b';
else
str[3]='B';
if(prob.failure<10)
str[4]='.';
else if(prob.failure<50)
str[4]='f';
else
str[4]='F';
if(prob.errors<10)
str[5]='.';
else if(prob.errors<50)
str[5]='e';
else
str[5]='E';
str[6]='\0';
}
}
void NetworkGetBandwidth(float *rcv,float *snd)
{
NT_LatencyInfo lat;
NT_GetTotalLatencyInfo(gSessionRef,&lat);
*rcv=lat.recvPackets10Sec*0.1;
*snd=lat.sendPackets10Sec*0.1;
}
void NetworkQueuePacket(tNetworkPacket *insert)
{
tQueuedPacket *q=(tQueuedPacket*)MemoryAllocateZeroedBlock(sizeof(tQueuedPacket));
q->packet=*insert;
QueueInsert(&gPacketQueue,(QStubPtr)q);
}
//#define PACKET_DUMP
#ifdef PACKET_DUMP
void DumpPacket(tNetworkPacket *packet)
{
char st[256];
sprintf(st,"what: %d",packet->what);
PrintConsoleString(st);
sprintf(st,"from: %d",packet->from);
PrintConsoleString(st);
sprintf(st,"size: 0x%x",packet->size);
PrintConsoleString(st);
int line=0;
while(line<=packet->size/16)
{
char dataStr[256];
sprintf(dataStr,"%04x ",line*16);
for(int pos=line*16;pos<line*16+16;pos++)
if(pos<packet->size)
sprintf(dataStr,"%s%02x",dataStr,*((UInt8*)packet->data+pos));
else
sprintf(dataStr,"%s ",dataStr);
sprintf(dataStr,"%s ",dataStr);
for(int pos=line*16;pos<line*16+16;pos++)
if(pos<packet->size)
if(*((UInt8*)packet->data+pos)>=32)
sprintf(dataStr,"%s%c",dataStr,*((UInt8*)packet->data+pos));
else
sprintf(dataStr,"%s.",dataStr);
else
sprintf(dataStr,"%s ",dataStr);
PrintConsoleString(dataStr);
line++;
}
PrintConsoleString("");
}
#endif
void NTEventHandler(NT_SessionRef sessionRef,void *refcon,NT_SessionEventType event,NT_MemberIDType member)
{
gAllowCompression=false;
switch(event)
{
case eSessionEventSessionStart:{
//PrintConsoleString("eSessionEventSessionStart");
tNetworkPacket packet;
packet.what=kMessageTypePlayerJoined;
packet.from=0;
packet.size=0;
packet.data=NULL;
NetworkQueuePacket(&packet);
}
break;
case eSessionEventMemberJoin:{
//PrintConsoleString("eSessionEventMemberJoin, member=%d",member);
tNetworkPacket packet;
packet.what=kMessageTypePlayerJoined;
packet.from=member;
packet.size=0;
packet.data=NULL;
NetworkQueuePacket(&packet);
/*NT_ToleranceInfo tolerance;
NT_GetToleranceInfo(gSessionRef,&tolerance);
PrintConsoleString("Tolerance info:");
PrintConsoleString("avgPackets %d.",tolerance.avgPackets);
PrintConsoleString("avgRequests %d.",tolerance.avgRequests);
PrintConsoleString("maxRequests %d.",tolerance.maxRequests);
PrintConsoleString("minHeartbeat %d.",tolerance.minHeartbeat);
PrintConsoleString("avgHeartbeat %d.",tolerance.avgHeartbeat);
PrintConsoleString("maxHeartbeat %d.",tolerance.maxHeartbeat);
PrintConsoleString("maxTimeout %d.",tolerance.maxTimeout);
PrintConsoleString("maxFailures %d.",tolerance.maxFailures);
PrintConsoleString("maxErrors %d.",tolerance.maxErrors);
PrintConsoleString("minLinger %d.",tolerance.minLinger);*/
}
break;
case eSessionEventMemberLeave:{
//PrintConsoleString("eSessionEventMemberLeave, member=%d",member);
tNetworkPacket packet;
if(member==0)
{
if(*gDisconnectString=='\0')
sprintf(gDisconnectString,"Network Failure (Failure on Host side).");
packet.what=kMessageTypeGameTerminated;
}
else
packet.what=kMessageTypePlayerLeft;
packet.from=member;
packet.size=0;
packet.data=NULL;
NetworkQueuePacket(&packet);
NT_LatencyInfo latency;
if(NT_GetLatencyInfo(gSessionRef,member,&latency))
{
PrintConsoleString("Latency info for dropped member:");
PrintConsoleString("minLinkRTT %d.",latency.minLinkRTT);
PrintConsoleString("avgLinkRTT %d.",latency.avgLinkRTT);
PrintConsoleString("p80LinkRTT %d.",latency.p80LinkRTT);
PrintConsoleString("devLinkRTT %d.",latency.devLinkRTT);
PrintConsoleString("wAvgLinkRTT %d.",latency.wAvgLinkRTT);
PrintConsoleString("wDevLinkRTT %d.",latency.wDevLinkRTT);
PrintConsoleString("minTranRTT %d.",latency.minTranRTT);
PrintConsoleString("avgTranRTT %d.",latency.avgTranRTT);
PrintConsoleString("p80TranRTT %d.",latency.p80TranRTT);
PrintConsoleString("maxTranRTT %d.",latency.maxTranRTT);
PrintConsoleString("devTranRTT %d.",latency.devTranRTT);
PrintConsoleString("wAvgTranRTT %d.",latency.wAvgTranRTT);
PrintConsoleString("wDevTranRTT %d.",latency.wDevTranRTT);
}
NT_ProblemInfo prob;
if(NT_GetProblemInfo(gSessionRef,member,&prob))
{
PrintConsoleString("Problem info for dropped member:");
PrintConsoleString("timeout %d.",prob.timeout);
PrintConsoleString("latency %d.",prob.latency);
PrintConsoleString("stalled %d.",prob.stalled);
PrintConsoleString("backlog %d.",prob.backlog);
PrintConsoleString("failure %d.",prob.failure);
PrintConsoleString("errors %d.",prob.errors);
}
NT_PacketHistory(gSessionRef,gHistoryBuffer,1024*500);
}
break;
case eSessionEventSessionEnd:{
//PrintConsoleString("eSessionEventSessionEnd");
/* tNetworkPacket packet;
packet.what=kMessageTypeGameTerminated;
packet.from=member;
packet.size=0;
packet.data=NULL;
NetworkQueuePacket(&packet);*/
}
break;
case eSessionEventRecvPacket:{
UInt8 data[kNetworkToolPacketSize];
UInt16 len;
if(NT_RecvPacket(gSessionRef,&member,(char*)data,kNetworkToolPacketSize,&len))
{
tNetworkPacket packet;
packet.data=MemoryAllocateBlock(kNetworkToolPacketSize);
MemoryMove(packet.data,data+1,len-1);
packet.size=len-1;
packet.from=member;
packet.what=*data;
if(packet.what==kMessageTypeGameTerminated)
gTerminateSession=true;
/*#ifdef PACKET_DUMP
PrintConsoleString("Packet Received:");
DumpPacket(&packet);
#endif
*/
//got a Ping request?
if(packet.what==kMessageTypePing)
//send out a reply packet with the original ping packets time stamp.
NetworkSendPacket(kMessageTypePong,packet.data,sizeof(float),kMessagePriorityLow,packet.from);
else if(packet.what==kMessageTypePong)
{
gLastPingReceived=TimeGetSeconds();
gLastRTT=gLastPingReceived-*(float*)packet.data;
}
else
NetworkQueuePacket(&packet);
}
}
break;
case eSessionEventRecvRequest:{
UInt8 data[kNetworkToolPacketSize];
UInt16 len;
if(NT_RecvRequest(gSessionRef,&member,(char*)data,kNetworkToolPacketSize,&len))
{
NT_SendResponse(gSessionRef,NULL,0);
tNetworkPacket packet;
packet.data=MemoryAllocateBlock(kNetworkToolPacketSize);
MemoryMove(packet.data,data+1,len-1);
packet.size=len-1;
packet.from=member;
packet.what=*data;
if(packet.what==kMessageTypeGameTerminated)
gTerminateSession=true;
#ifdef PACKET_DUMP
PrintConsoleString("Request Packet Received:");
DumpPacket(&packet);
#endif
NetworkQueuePacket(&packet);
}
}
break;
case eSessionEventRecvResponse:{
UInt8 data[kNetworkToolPacketSize];
UInt16 len;
NT_RecvResponse(gSessionRef,&member,(char*)data,kNetworkToolPacketSize,&len);
}
break;
}
gAllowCompression=true;
}
void NTErrorHandler(NT_SessionRef sessionRef,void *refcon,NT_SessionProblemType problem,NT_SessionSeverityType severity,NT_MemberIDType member,Bool8 *disconnectSelf,Bool8 *disconnectMember)
{
gAllowCompression=false;
if(severity>=100)
{
PrintConsoleString("NT Error %d",problem);
NT_MemberInfo info;
NT_GetSelfMemberInfo(gSessionRef,&info);
if(info.member==0)
{
if(member!=0)
{
*disconnectMember=true;
tChatMessage m;
m.flags=kChatFlagSystem;
switch(problem)
{
case eSessionProblemTimeout:
sprintf(m.str,"### Player %d is disconnecting (Connection timed out).",member+1);
break;
case eSessionProblemLatency:
sprintf(m.str,"### Player %d is disconnecting (Latency too high).",member+1);
break;
case eSessionProblemStalled:
sprintf(m.str,"### Player %d is disconnecting (Stalled).",member+1);
break;
case eSessionProblemBacklog:
sprintf(m.str,"### Player %d is disconnecting (Backlog).",member+1);
break;
case eSessionProblemFailure:
sprintf(m.str,"### Player %d is disconnecting (Failure).",member+1);
break;
case eSessionProblemErrors:
sprintf(m.str,"### Player %d is disconnecting (Too many errors).",member+1);
break;
default:
sprintf(m.str,"### Player %d is disconnecting (Unknown error).",member+1);
break;
}
printf("%s\n",m.str);
//NetworkSendPacket(kMessageTypeChat,&m,sizeof(m),kMessagePriorityHigh,kMessageSendToAll);
}
}
else if(member==0)
{
*disconnectMember=false;
*disconnectSelf=true;
tNetworkPacket packet;
packet.data=NULL;
packet.size=0;
packet.from=member;
packet.what=kMessageTypeGameTerminated;
NetworkQueuePacket(&packet);
switch(problem)
{
case eSessionProblemTimeout:
sprintf(gDisconnectString,"Network Failure (Connection timed out).");
break;
case eSessionProblemLatency:
sprintf(gDisconnectString,"Network Failure (Latency too high).");
break;
case eSessionProblemStalled:
sprintf(gDisconnectString,"Network Failure (Stalled).");
break;
case eSessionProblemBacklog:
sprintf(gDisconnectString,"Network Failure (Backlog).");
break;
case eSessionProblemFailure:
sprintf(gDisconnectString,"Network Failure (Failure).");
break;
case eSessionProblemErrors:
sprintf(gDisconnectString,"Network Failure (Too many errors).");
break;
default:
sprintf(gDisconnectString,"Network Failure (unknown error).");
break;
}
}
}
gAllowCompression=true;
}
void NetworkPreSession()
{
if(gSessionRef==NULL)
HandleError(NT_SessionStartParam(&gSessionRef,NTEventHandler,NTErrorHandler,NULL,NULL,6,kGameName,""));
else
HandleError(NT_SessionRestart(gSessionRef,6,kGameName,""));
}
float NetworkGetPlayerPing(int netID)
{
NT_MemberInfo info;
NT_GetSelfMemberInfo(gSessionRef,&info);
if(netID==info.member||netID==kMessageNoRecipients)
return 0;
NT_LatencyInfo latency;
if(NT_GetLatencyInfo(gSessionRef,netID,&latency));
{
/* PrintConsoleString("Player %d latency.",netID);
PrintConsoleString("minLinkRTT %d.",latency.minLinkRTT);
PrintConsoleString("avgLinkRTT %d.",latency.avgLinkRTT);
PrintConsoleString("p80LinkRTT %d.",latency.p80LinkRTT);
PrintConsoleString("devLinkRTT %d.",latency.devLinkRTT);
PrintConsoleString("wAvgLinkRTT %d.",latency.wAvgLinkRTT);
PrintConsoleString("wDevLinkRTT %d.",latency.wDevLinkRTT);
PrintConsoleString("minTranRTT %d.",latency.minTranRTT);
PrintConsoleString("avgTranRTT %d.",latency.avgTranRTT);
PrintConsoleString("p80TranRTT %d.",latency.p80TranRTT);
PrintConsoleString("maxTranRTT %d.",latency.maxTranRTT);
PrintConsoleString("devTranRTT %d.",latency.devTranRTT);
PrintConsoleString("wAvgTranRTT %d.",latency.wAvgTranRTT);
PrintConsoleString("wDevTranRTT %d.",latency.wDevTranRTT);*/
return latency.avgLinkRTT*0.001;
}
return 0;
}
//Host a new Network Game
void HostNetGame(int maxPlayers,char *pass)
{
HandleError(NT_SessionRestart(gSessionRef,maxPlayers,kGameName,pass));
gTerminateSession=false;
}
void NetworkDisconnectPlayer(int netID,UInt8 type)
{
NT_MemberInfo info;
if(NT_GetMemberInfo(gSessionRef,netID,&info))
{
if(type!=kNetworkDisconnectLicenseCopies)
HandleError(NT_SessionBan(gSessionRef,&info.address,false,NULL));
NetworkSendPacket(kMessageTypeKicked,&type,sizeof(UInt8),kMessagePriorityHigh,netID);
}
}
void NetworkChangePassword(char *pass)
{
HandleError(NT_SetSessionPassword(gSessionRef,pass));
}
//join a network game at the ip address given in the string address.
//returns an error code or 0. passes the player's id in id.
int JoinNetGame(char *address,char *errorString)
{
if(!*address)
{
sprintf(errorString,"No Address Entered.");
return false;
}
//PrintConsoleString(address);
NetworkAddress addy;
Result32 err=SimpleResolve(eNetworkStackTCPIP,address,&addy);
if(err)
{
sprintf(errorString,"Can't resolve host. (%d)",err);
return false;
}
gTerminateSession=false;
NetworkClearPacketQueue();
HandleError(NT_SessionRejoin(gSessionRef,&addy,kGameName,NULL,&err));
if(err==eNetworkToolErrorBadPass)
{
err=0;
char password[256];
if(InterfaceGetUserInputString("Please enter Game Password",password,256,true,true))
{
NetworkClearPacketQueue();
HandleError(NT_SessionRejoin(gSessionRef,&addy,kGameName,password,&err));
}
else
return false;
}
if(err)
{
switch(err)
{
case eNetworkToolErrorNoServer:
sprintf(errorString,"No Server Running on that Machine",err);
break;
case eNetworkToolErrorTimeout:
sprintf(errorString,"Network_Tool Timeout",err);
break;
case eNetworkToolErrorLatency:
sprintf(errorString,"Latency is too high.",err);
break;
case eNetworkToolErrorBanned:
sprintf(errorString,"You are banned from this host.",err);
break;
case eNetworkToolErrorTooMany:
sprintf(errorString,"The game is full.",err);
break;
case eNetworkToolErrorBadPass:
sprintf(errorString,"Wrong Password",err);
break;
case eNetworkToolErrorLocked:
sprintf(errorString,"Can't join in the middle of a game.",err);
break;
default:
sprintf(errorString,"Connection Error. (%d)",err);
}
return false;
}
float startTime=TimeGetSeconds();
while(TimeGetSeconds()<startTime+kConnectionTimeOut)
{
tNetworkPacket message;
while(NetworkReceivePacket(&message))
{
//wait for servers response
if(message.what==kMessageTypeID)
{
NetworkQueuePacket(&message);
return true;
}
if(message.what==kMessageTypeVersion)
{
UInt32 reply=kVersion;
U32Swap(reply);
NetworkSendPacket(kMessageTypeVersion,&reply,sizeof(UInt32),kMessagePriorityHigh,message.from);
}
if(message.what==kMessageTypeJoinDenied)
{
if(*((UInt8*)message.data)==kJoinDeniedInProgress)
sprintf(errorString,"Can't join in the middle of a game.",err);
else if(*((UInt8*)message.data)==kJoinDeniedVersion)
sprintf(errorString,"Version Mismatch.",err);
else
sprintf(errorString,"Host rejected connection.",err);
//PrintConsoleString("Rejected. Exiting.");
return false;
}
if(message.what==kMessageTypeGameTerminated)
{
sprintf(errorString,"Game Terminated.",err);
return false;
}
NetworkDisposePacket(&message);
}
}
sprintf(errorString,"Connection Timed out.",err);
return false;
}
//exits a network game
void ExitNetGame()
{
if(gSessionRef)
{
// HandleError(NT_SessionLeave(gSessionRef));
// gSessionRef=nil;
}
}
//sends the data in *message to other players on the network
void NetworkSendPacket(char messageType,void *message,long size,int priority,int to,int notTo)
{
if(messageType==kMessageTypeGameTerminated)
gTerminateSession=true;
if(to==kMessageNoRecipients)
return;
if(size>kNetworkToolPacketSize-1)
FailWithErrorString("Packet too large.");
NT_MemberInfo info;
NT_GetSelfMemberInfo(gSessionRef,&info);
NT_MemberListType self=0x00000001<<info.member;
UInt8 data[kNetworkToolPacketSize];
MemoryMove(data+1,message,size);
*data=messageType;
if(size>kCompressionSize&&gAllowCompression)
{
int oldsize=size;
if(CompressPacket(data+1,&size)==eCommonErrorNone)
if(oldsize<size)
*data|=kCompressionFlag;
else
{
size=oldsize;
MemoryMove(data+1,message,size);
}
}
// U32Swap(*data);
NT_MemberListType members;
switch(to)
{
case kMessageSendToAll: members=eMemberListAll; break;
case kMessageSendToAllButSelf: members=eMemberListAll^self; break;
case kMessageSendToHostOnly: members=0x00000001; break;
default: members=0x00000001<<to;
}
if(notTo)
members&=~(0x00000001<<notTo);
if(members&self)
{
tNetworkPacket packet;
packet.data=MemoryAllocateBlock(size);
MemoryMove(packet.data,message,size);
packet.size=size;
packet.from=info.member;
packet.what=messageType;
NetworkQueuePacket(&packet);
}
Result32 err=0;
if(priority<=kMessagePriorityNormal)
err=NT_SendPacket(gSessionRef,members,(char*)data,size+4);
else
{
NT_SessionInfo sessInfo;
NT_MemberInfo member;
NT_GetSessionInfo(gSessionRef,&sessInfo);
for(int i=0;i<32;i++)
if((members&(0x00000001<<i))&&(i!=info.member))
if(NT_GetMemberInfo(gSessionRef,i,&member))
err=NT_SendRequest(gSessionRef,i,(char*)data,size+4);
}
if(err)
{
PrintConsoleString("Error Sending Packet (%d)",err);
gTerminateSession=true;
}
}
void NetworkSendPacket(char messageType,void *message,long size,int priority,int to)
{
NetworkSendPacket(messageType,message,size,priority,to,0);
}
int NetworkReceivePacket(tNetworkPacket* packet)
{
if(*gHistoryBuffer)
{
time_t t;
time(&t);
char ct[26];
ctime_r(&t,ct);
PrintConsoleString("Dumping Packet History %d. (%s)",gHistoryDumps,ct);
FILE *f=fopen("/tmp/packethistory.log","a");
fprintf(f,"Dump %d (%s)\n\n",gHistoryDumps++,ct);
char *ch=gHistoryBuffer;
while(*ch)
fwrite(ch++,1,1,f);
strcpy(gHistoryBuffer,"");
fprintf(f,"Debug Snapshot:");
NT_MemberListType mt=0xffff;
char buffer[64*1024];
NT_DebugSnapshot(gSessionRef,mt,buffer,32*1024);
ch=buffer;
while(*ch)
fwrite(ch++,1,1,f);
fclose(f);
}
if(gTerminateSession)
{
packet->what=kMessageTypeGameTerminated;
packet->data=NULL;
return true;
}
else if(QStubPtr rcv=QueueRemove(&gPacketQueue))
{
*packet=((tQueuedPacket*)rcv)->packet;
if(packet->what&kCompressionFlag)
{
DecompressPacket(packet->data,&packet->size);
packet->what^=kCompressionFlag;
}
MemoryFreeBlock(rcv);
return true;
}
if(gReggieConnected)
ReggieMessageCheck(gReggieRef);
return false;
}
void NetworkDisposePacket(tNetworkPacket* packet)
{
if(packet->data)
MemoryFreeBlock(packet->data);
}
void NetworkInit()
{
HandleError(NT_Open());
QueueCreate(&gPacketQueue);
}
void NetworkIdle()
{
static float lastStatus=0;
NT_Idle();
if(gSessionRef)
{
/* if(TimeGetSeconds()-lastStatus<0.5)
return;
lastStatus=TimeGetSeconds();
char str[16];
NetworkGetStatusString(str);
// printf("%s\n",str);
NT_MemberInfo info;
NT_GetSelfMemberInfo(gSessionRef,&info);
if(info.member)
{
if(gLastRTT<0)
printf("No Ping Response since %f seconds.\n",lastStatus-gLastPingReceived);
else
{
//printf("Last RTT: %f\n",gLastRTT);
gLastRTT=-1;
}
NetworkSendPacket(kMessageTypePing,&lastStatus,sizeof(float),kMessagePriorityLow,kMessageSendToHostOnly);
}*/
}
}
void NetworkExit()
{
if(gSessionRef)
NetworkSendPacket(kMessageTypeBye,0,NULL,kMessagePriorityHigh,kMessageSendToAll);
if(gReggieConnected)
ReggieDispose(gReggieRef,true);
NT_Close();
while(QStubPtr rcv=QueueRemove(&gPacketQueue))
MemoryFreeBlock(rcv);
QueueEmpty(&gPacketQueue);
}
//wait for a response from all players, to synchronize the start of the game.
int NetworkSynch(int numPlayers)
{
//PrintConsoleString("Synching %d...",numPlayers);
NetworkSendPacket(kMessageTypeSynch,nil,0,kMessagePriorityHigh,kMessageSendToAll);
UInt32 lastSynch=0;
UInt32 startClock;
int start=false;
tNetworkPacket leftMessage[kMaxPlayers];
int numLeftMessages=0;
int synchMessagesReceived=0;
while(synchMessagesReceived<numPlayers&&!start)
{
tNetworkPacket message;
if(NetworkReceivePacket(&message))
{
int cancel=false;
if(message.what==kMessageTypeSynch)
{
synchMessagesReceived++;
//PrintConsoleString("Received Synch packet from player %d",message.from);
}
else if(message.what==kMessageTypeEndGame||message.what==kMessageTypeGameTerminated)
{
cancel=true;
PrintConsoleString("Received Termination Packet. Aborting");
}
else if(message.what==kMessageTypePlayerLeft)
{
//cancel=true;
leftMessage[numLeftMessages++]=message;
numPlayers--;
PrintConsoleString("A Player Left.");
}
else if(message.what==kMessageTypeSynchStart)
{
//PrintConsoleString("Received Start Signal.");
startClock=*(UInt32*)message.data;
U32Swap(startClock);
start=true;
}
else
PrintConsoleString("Unexpected Packet");
NetworkDisposePacket(&message);
if(cancel)
return false;
}
SystemPoll(true);
}
NT_MemberInfo info;
NT_GetSelfMemberInfo(gSessionRef,&info);
if(info.member==0)
{
//PrintConsoleString("Sent Start Signal.");
startClock=NT_GetSessionClock(gSessionRef)+500;
U32Swap(startClock);
NetworkSendPacket(kMessageTypeSynchStart,&startClock,sizeof(UInt32),kMessagePriorityHigh,kMessageSendToAll);
U32Swap(startClock);
}
else
{
float startTime=TimeGetSeconds();
tNetworkPacket message;
while(TimeGetSeconds()<startTime+kConnectionTimeOut&&!start)
{
if(NetworkReceivePacket(&message))
{
if(message.what==kMessageTypeSynchStart)
{
//PrintConsoleString("Received Start Signal.");
startClock=*(UInt32*)message.data;
U32Swap(startClock);
start=true;
}
else if(message.what==kMessageTypePlayerLeft)
{
leftMessage[numLeftMessages++]=message;
}
else
PrintConsoleString("Unexpected Packet");
NetworkDisposePacket(&message);
}
SystemPoll(false);
}
if(!start)
return false;
}
for(int i=0;i<numLeftMessages;i++)
NetworkQueuePacket(leftMessage+i);
while(NT_GetSessionClock(gSessionRef)<startClock);
return true;
}

952
source/networkphysics.cpp Normal file
View File

@ -0,0 +1,952 @@
//networkphysics.cpp
//sends and receives physics data to and from the network
//also stores and loads packets to and from the replay log,
//as these share the same format as network packets.
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <network_tool.h>
#include "network.h"
#include "entities.h"
#include "vectors.h"
#include "carphysics.h"
#include "particles.h"
#include "tracks.h"
#include "gameframe.h"
#include "networkphysics.h"
#include "log.h"
#include "error.h"
#include "gameinitexit.h"
#include "gamemem.h"
#include "gamesound.h"
#include "gametime.h"
#include "interfacemultiplayer.h"
#include "collision.h"
#include "environment.h"
int gReplayIndex=0;
int gSynchsRecevied=0;
//compressed subset of tWheelPhysics for network broadcasts
typedef struct{
unsigned char rotation,glow;
char angularVelo;
char slipVelo;
char surfaceType;
} tWheelNetPhysics;
//compressed subset of tCarPhysics for network broadcasts
typedef struct{
unsigned char lightFlags;
unsigned char rpm,throttle;
unsigned char shiftDelay,handbrake;
unsigned short damage;
char steering;
tWheelNetPhysics wheels[kMaxWheels];
tVector3 cameraPos;
} tCarNetPhysics;
//a structure containing all the physics data necessary
//to transmit a cars state for network broadcasts
typedef struct{
tPhysicsMessage entity;
tCarNetPhysics phys;
} tCarPhysicsMessage;
typedef struct{
tPhysicsMessage entity;
char resends;
char filler[sizeof(tCarNetPhysics)-1];
} tSolidPhysicsMessage;
#define kMaxGameChatMessages 4
#define kMaxOutboxSize (kNetworkToolPacketSize/sizeof(tCarPhysicsMessage))
int gNumGameChatMessages=0;
tGameChatMessage gGameChatMessagesRecv[kMaxGameChatMessages];
tCarPhysicsMessage gHostOutbox[kMaxOutboxSize];
int gOutboxPos=0,gOutboxSender=-1;
float gLastOutboxSend=0;
void GameChatMessagesScroll()
{
for(int i=0;i<gNumGameChatMessages-1;i++)
gGameChatMessagesRecv[i]=gGameChatMessagesRecv[i+1];
gNumGameChatMessages--;
}
void InsertGameChatMessage(char *message)
{
while(gNumGameChatMessages>=kMaxGameChatMessages)
GameChatMessagesScroll();
gGameChatMessagesRecv[gNumGameChatMessages].timestamp=TimeGetSeconds();
strcpy(gGameChatMessagesRecv[gNumGameChatMessages].message,message);
gNumGameChatMessages++;
}
void InsertToOutbox(tCarPhysicsMessage *msg,int from)
{
for(int i=0;i<gOutboxPos;i++)
if(gHostOutbox[i].entity.id==msg->entity.id)
{
int mFrame=msg->entity.frame;
int bFrame=gHostOutbox[i].entity.frame;
S32Swap(mFrame);
S32Swap(bFrame);
if(bFrame<mFrame)
gHostOutbox[i]=*msg;
return;
}
if(gOutboxPos<kMaxOutboxSize)
gHostOutbox[gOutboxPos++]=*msg;
if(gOutboxPos==1)
gOutboxSender=from;
else if(gOutboxSender!=from)
gOutboxSender=-1;
}
//converts 6 shorts to a 3x3 rotation matrix
void ShortVectorsToMatrix(tVector3Short dirZ,tVector3Short dirY,tMatrix3 m)
{
MatrixGetZVector(m)->x=dirZ.x*(1/32767.0);
MatrixGetZVector(m)->y=dirZ.y*(1/32767.0);
MatrixGetZVector(m)->z=dirZ.z*(1/32767.0);
MatrixGetYVector(m)->x=dirY.x*(1/32767.0);
MatrixGetYVector(m)->y=dirY.y*(1/32767.0);
MatrixGetYVector(m)->z=dirY.z*(1/32767.0);
*MatrixGetXVector(m)=*MatrixGetYVector(m)%*MatrixGetZVector(m);
}
//compresses generic entity physics data into a tPhysicsMessage
tVector3 PreparePhysicsMessage(tGameEntity *entity,tPhysicsMessage *message)
{
message->prioritized=false;
message->id=entity->id;
message->pos=entity->pos;
tVector3 v=Vector(0,0,0),a=Vector(0,0,0);
tVector3 rz=Vector(0,0,0),ry=Vector(0,0,0);
for(int i=0;i<8;i++)//smooth suspension inbalance
{
rz=rz+*MatrixGetZVector(entity->lastRVelos[i]);
ry=ry+*MatrixGetYVector(entity->lastRVelos[i]);
a=a+entity->lastAccel[i];
v=v+entity->lastVelos[i];
}
a=a*1.0/8;
v=entity->velo;
v.y=0;
a.y=0;
for(int i=0;i<16;i++)
v.y+=entity->lastVelos[i].y;
for(int i=0;i<32;i++)
a.y+=entity->lastAccel[i].y;
v.y/=16;
a.y/=32;
if(entity->physicsType==kPhysicsTypeSolid)
{
rz=*MatrixGetZVector(entity->rVelo);
ry=*MatrixGetYVector(entity->rVelo);
v=entity->velo;
}
//if(sqr(v)>sqr(3))
message->velo.x=v.x*255;
message->velo.y=v.y*255;
message->velo.z=v.z*255;
if(sqr(entity->accel)<sqr(a))
a=entity->accel;
message->accel.x=a.x*255;
message->accel.y=a.y*255;
message->accel.z=a.z*255;
message->frame=gFrameCount;
tVector3 z=*MatrixGetZVector(entity->dir);
message->dirZ.x=fabs(z.x)<1?z.x*32767:sign(z.x)*32767;
message->dirZ.y=fabs(z.y)<1?z.y*32767:sign(z.y)*32767;
message->dirZ.z=fabs(z.z)<1?z.z*32767:sign(z.z)*32767;
tVector3 y=*MatrixGetYVector(entity->dir);
message->dirY.x=fabs(y.x)<1?y.x*32767:sign(y.x)*32767;
message->dirY.y=fabs(y.y)<1?y.y*32767:sign(y.y)*32767;
message->dirY.z=fabs(y.z)<1?y.z*32767:sign(y.z)*32767;
rz=!Vector(rz.x,0,rz.z);
ry=Vector(0,1,0);
/* rz=!rz;
tVector3 rx=!(ry%rz);
ry=!(rz%rx);*/
message->rVeloZ.x=fabs(rz.x)<1?rz.x*32767:sign(rz.x)*32767;
message->rVeloZ.y=fabs(rz.y)<1?rz.y*32767:sign(rz.y)*32767;
message->rVeloZ.z=fabs(rz.z)<1?rz.z*32767:sign(rz.z)*32767;
message->rVeloY.x=fabs(ry.x)<1?ry.x*32767:sign(ry.x)*32767;
message->rVeloY.y=fabs(ry.y)<1?ry.y*32767:sign(ry.y)*32767;
message->rVeloY.z=fabs(ry.z)<1?ry.z*32767:sign(ry.z)*32767;
return rz;
}
#define kMinPacketDelay 5
#define kMaxPacketDelay 30
#define kMaxPacketRVeloDiff 0.005
float RVeloDiff(tMatrix3 v1,tMatrix3 v2)
{
float result=~(*MatrixGetXVector(v1)-*MatrixGetXVector(v2));
result+=~(*MatrixGetYVector(v1)-*MatrixGetYVector(v2));
result+=~(*MatrixGetZVector(v1)-*MatrixGetZVector(v2));
return result;
}
float RemoteCarDistance(tGameEntity *entity)
{
float minDist=INFINITY;
for(int i=0;i<gGameInfo->numPlayers;i++)
if(gCarEntities[i]->physicsMachine==kPhysicsRemote)
{
float dist=sqr(entity->pos-gCarEntities[i]->remoteCameraPos);
if(dist<minDist)
minDist=dist;
}
return sqrt(minDist);
}
int SendNewPacket(tGameEntity *entity,tVector3 rz)
{
int lastPacket=gFrameCount-entity->lastPacketSent;
float dist=RemoteCarDistance(entity)*0.001;
float score=0;
float veloChangePerc;
if(~entity->velo>1)
{
veloChangePerc=~(entity->velo-entity->lastVeloSent)/~entity->velo;
/*if(veloChangePerc>0.3&&dist<0.25&&~(entity->velo-entity->lastVeloSent)>1)
{
//printf("fp\n");
return 2;
}*/
}
else
veloChangePerc=~(entity->velo-entity->lastVeloSent);
score+=veloChangePerc;
score+=~(rz-entity->lastRZSent)*kFPS;
score+=~(entity->lastDirZSent-*MatrixGetZVector(entity->dir));
score*=lastPacket;
score-=dist;
if(lastPacket>kFPS*0.5)
return 1;
else if(score<0.6||lastPacket<5)
return 0;
else
return 1;
}
int SendNewPacketLog(tGameEntity *entity,tVector3 rz)
{
int lastPacket=gFrameCount-entity->lastPacketSaved;
float score=0;
float veloChangePerc;
if(~entity->velo>1)
{
veloChangePerc=~(entity->velo-entity->lastVeloSaved)/~entity->velo;
/*if(veloChangePerc>0.3&&dist<0.25&&~(entity->velo-entity->lastVeloSent)>1)
{
//printf("fp\n");
return 2;
}*/
}
else
veloChangePerc=~(entity->velo-entity->lastVeloSaved);
score+=veloChangePerc;
score+=~(rz-entity->lastRZSaved)*kFPS;
score+=~(entity->lastDirZSaved-*MatrixGetZVector(entity->dir));
score*=lastPacket;
if(lastPacket>kFPS*0.5)
return 1;
else if(score<0.4||lastPacket<3)
return 0;
else
return 1;
}
void PhysicsMessageSwap(tPhysicsMessage* m)
{
S32Swap(m->frame);
F32Swap(m->pos.x);
F32Swap(m->pos.y);
F32Swap(m->pos.z);
S16Swap(m->id);
S16Swap(m->velo.x);
S16Swap(m->velo.y);
S16Swap(m->velo.z);
S16Swap(m->accel.x);
S16Swap(m->accel.y);
S16Swap(m->accel.z);
S16Swap(m->dirZ.x);
S16Swap(m->dirZ.y);
S16Swap(m->dirZ.z);
S16Swap(m->dirY.x);
S16Swap(m->dirY.y);
S16Swap(m->dirY.z);
S16Swap(m->rVeloZ.x);
S16Swap(m->rVeloZ.y);
S16Swap(m->rVeloZ.z);
S16Swap(m->rVeloY.x);
S16Swap(m->rVeloY.y);
S16Swap(m->rVeloY.z);
}
//sends out a car's state to other players (and logs it for the replay log)
void SendCarPhysicsMessage(tGameEntity *entity)
{
tCarPhysics *phys=(tCarPhysics*)entity->physics;
tCarPhysicsMessage message;
//compress position, etc..
tVector3 rz=PreparePhysicsMessage(entity,&message.entity);
//compress car data
message.phys.lightFlags=phys->lightFlags;
message.phys.handbrake=phys->handbrake*255;
float shiftDelay=gFrameCount*kFrameTime-phys->lastGearSwitch;
message.phys.shiftDelay=(shiftDelay<1)?shiftDelay*255:255;
message.phys.rpm=phys->rpm*(255.0/10000.0);
message.phys.throttle=phys->throttle*255;
// message.phys.brake=phys->brake*255;
// message.phys.gear=phys->gear;
message.phys.steering=fabs(phys->steering)<1?phys->steering*127:sign(phys->steering)*127;
message.phys.damage=phys->damage;
U16Swap(message.phys.damage);
message.phys.cameraPos=gCameraEntity->pos;
F32Swap(message.phys.cameraPos.x);
F32Swap(message.phys.cameraPos.y);
F32Swap(message.phys.cameraPos.z);
for(int i=0;i<phys->car.numWheels;i++)
{
message.phys.wheels[i].rotation=phys->wheels[i].rotation*(255.0/(2*PI));
message.phys.wheels[i].slipVelo=phys->wheels[i].slipVelo;
message.phys.wheels[i].surfaceType=phys->wheels[i].surfaceType;
message.phys.wheels[i].glow=phys->wheels[i].glow*255.0;
if(fabs(phys->wheels[i].angularVelo)<127)
message.phys.wheels[i].angularVelo=phys->wheels[i].angularVelo;
else
message.phys.wheels[i].angularVelo=127*sign(phys->wheels[i].angularVelo);
}
for(int i=phys->car.numWheels;i<kMaxWheels;i++)
{
message.phys.wheels[i].rotation=0;
message.phys.wheels[i].slipVelo=0;
message.phys.wheels[i].surfaceType=0;
message.phys.wheels[i].glow=0;
message.phys.wheels[i].angularVelo=0;
}
PhysicsMessageSwap(&message.entity);
if(SendNewPacketLog(entity,rz))
{
LogPacket(sizeof(tCarPhysicsMessage),&message,kMessageTypePhysics);
entity->lastPacketSaved=gFrameCount;
entity->lastVeloSaved=entity->velo;
entity->lastRZSaved=rz;
entity->lastDirZSaved=*MatrixGetZVector(entity->dir);
}
//broadcast packet over network
if(gGameInfo->network)
if(int prio=SendNewPacket(entity,rz))
{
if(prio==2)
message.entity.prioritized=true;
if(gGameInfo->playerID)
NetworkSendPacket(kMessageTypePhysics,&message,sizeof(tCarPhysicsMessage),kMessagePriorityNormal,kMessageSendToHostOnly);
else
InsertToOutbox(&message,0);
entity->lastPacketSent=gFrameCount;
entity->lastVeloSent=entity->velo;
entity->lastRZSent=rz;
entity->lastDirZSent=*MatrixGetZVector(entity->dir);
}
}
void SendSolidPhysicsMessage(tGameEntity *entity,int resends)
{
static int lastRockUpdate=0;
if(entity->lastFrame==gFrameCount&&gFrameCount>0)
{
tSolidPhysicsMessage message;
for(int i=0;i<sizeof(tCarNetPhysics)-1;i++)
message.filler[i]=0;
PreparePhysicsMessage(entity,&message.entity);
message.resends=resends;
PhysicsMessageSwap(&message.entity);
LogPacket(sizeof(tSolidPhysicsMessage),&message,kMessageTypePhysics);
if(gGameInfo->network)
if(gGameInfo->playerID)
{
if(gFrameCount<lastRockUpdate)
lastRockUpdate=0;
if(gFrameCount>lastRockUpdate+kFPS*0.25)
{
NetworkSendPacket(kMessageTypePhysics,&message,sizeof(tSolidPhysicsMessage),kMessagePriorityHigh,kMessageSendToHostOnly);
lastRockUpdate=gFrameCount;
}
else
entity->lastFrame++;
}
else
InsertToOutbox((tCarPhysicsMessage*)&message,0);
}
}
void AddRockUpdateToOutbox()
{
tGameEntity *entity=(tGameEntity*)gFirstEntity->next;
if(gOutboxPos==kMaxOutboxSize)
return;
while(entity!=gFirstEntity)
{
if(entity->physicsType==kPhysicsTypeSolid)
{
tSolidEntityPhysics *ent=(tSolidEntityPhysics*)FileGetParsedDataPtr(entity->physicsData,kParserTypeSolidEntityDesc,sizeof(tSolidEntityPhysics));
if(ent->movable&&ent->mass>=kSolidEntityNetworkMass)
if(entity->lastActivity<gFrameCount-kFPS)
if(entity->lastFrame<gFrameCount-kFPS)
{
float minDist=INFINITY;
for(int i=0;i<gGameInfo->numPlayers;i++)
if(sqr(gCarEntities[i]->pos-entity->pos)<minDist)
minDist=sqr(gCarEntities[i]->pos-entity->pos);
if(minDist>sqr(80))
{
entity->lastFrame=gFrameCount;
SendSolidPhysicsMessage(entity,0);
return;
}
}
}
entity=(tGameEntity*)entity->next;
}
}
void CleanOutbox()
{
for(int i=0;i<gOutboxPos;i++)
{
tGameEntity *entity=(tGameEntity*)gFirstEntity->next;
//see if we find the entity it belongs to
while(entity!=gFirstEntity&&i<gOutboxPos)
{
//is this the entity the message refers to?
short id=gHostOutbox[i].entity.id;
S16Swap(id);
if(entity->id==id)
{
if(entity->physicsType==kPhysicsTypeSolid)
{
if(((tSolidPhysicsMessage*)gHostOutbox+i)->resends==0||((tSolidPhysicsMessage*)gHostOutbox+i)->resends>3)
{
memmove(gHostOutbox+i,gHostOutbox+i+1,sizeof(tSolidPhysicsMessage)*(gOutboxPos-i-1));
gOutboxPos--;
entity=gFirstEntity;
}
else
((tSolidPhysicsMessage*)gHostOutbox+i)->resends--;
}
else
{
memmove(gHostOutbox+i,gHostOutbox+i+1,sizeof(tSolidPhysicsMessage)*(gOutboxPos-i-1));
gOutboxPos--;
entity=gFirstEntity;
}
}
entity=(tGameEntity*)entity->next;
}
}
}
//sends out physics information for this frame
void NetworkSendPhysics()
{
tGameEntity *entity=(tGameEntity*)gFirstEntity->next;
while(entity!=gFirstEntity)
{
if(entity->physicsMachine==kPhysicsLocal)
{
switch(entity->physicsType)
{
case kPhysicsTypeCar:
SendCarPhysicsMessage(entity);
break;
case kPhysicsTypeSolid:
SendSolidPhysicsMessage(entity,2);
break;
}
}
entity=(tGameEntity*)entity->next;
}
float t=TimeGetSeconds();
if(gGameInfo->playerID==0&&gGameInfo->network)
{
int fastPath=false;
for(int i=0;i<gOutboxPos;i++)
if(gHostOutbox[i].entity.prioritized)
fastPath=true;
if(gOutboxPos>0&&(gLastOutboxSend<t-0.06||gOutboxPos==kMaxOutboxSize||fastPath))//send packet every 60ms
{
AddRockUpdateToOutbox();
if(gOutboxSender!=-1)
NetworkSendPacket(kMessageTypePhysics,gHostOutbox,sizeof(tCarPhysicsMessage)*gOutboxPos,kMessagePriorityNormal,kMessageSendToAllButSelf,gOutboxSender);
else
NetworkSendPacket(kMessageTypePhysics,gHostOutbox,sizeof(tCarPhysicsMessage)*gOutboxPos,kMessagePriorityNormal,kMessageSendToAllButSelf);
gLastOutboxSend=t;
CleanOutbox();
}
}
}
void KillPlayer(int i)
{
//PrintConsoleString("Removing Player %d from game",i);
tGameEntity *ent=gCarEntities[i];
ent->pos=Vector(-10000,-10000,-10000);
ent->netPos=Vector(-10000,-10000,-10000);
ent->velo=Vector(0,0,0);
ent->id=-1;
tCarPhysics *phys=(tCarPhysics*)ent->physics;
phys->position=0;
phys->checkPoint=0;
for(int i=0;i<kMaxLaps+1;i++)
phys->lapTimes[i]=0;
gGameInfo->netID[i]=-1;
gGameInfo->playerCarNames[i][0]='\0';
int numPlayers=0;
for(int i=0;i<gGameInfo->numPlayers;i++)
if(gCarEntities[i]->id>=0)
numPlayers++;
if(numPlayers==1)
{
tCarPhysics *lastPhys=(tCarPhysics*)gCarEntities[0];
lastPhys->lead=0;
}
if(gReplayViewedEntityID==i)
{
gViewedEntity=gCarEntities[0];
gReplayViewedEntityID=0;
}
}
//receive physics data from other players on the network
void NetworkReceivePhysics()
{
if(gGameInfo->network)
{
tNetworkPacket message;
int exit=false;
while(NetworkReceivePacket(&message))
{
switch(message.what)
{
case kMessageTypePhysics:
if(gGameInfo->playerID==0)
InsertToOutbox((tCarPhysicsMessage*)message.data,message.from);
//we have received a physics state update
for(int i=0;i<message.size/sizeof(tCarPhysicsMessage);i++)
{
//log the packet for replay
LogPacket(sizeof(tCarPhysicsMessage),(char*)message.data+i*sizeof(tCarPhysicsMessage),kMessageTypePhysics);
tPhysicsMessage *physMessage=(tPhysicsMessage*)((char*)message.data+i*sizeof(tCarPhysicsMessage));
PhysicsMessageSwap(physMessage);
//printf("rec: %d. %d,%d\n",physMessage->id-gCarEntities[0]->id,physMessage->frame,gFrameCount);
tGameEntity *entity=(tGameEntity*)gFirstEntity->next;
//see if we find the entity it belongs to
while(entity!=gFirstEntity)
{
//is this the entity the message refers to?
if(entity->id==physMessage->id&&entity!=gCarEntities[gGameInfo->playerID])
//is this the most recent physics update for the entity?
//(we want to avoid packets coming in in the wrong order messung up everything)
if(entity->lastFrame<physMessage->frame)//&&entity->lastCollFrame<=physMessage->frame)
{
//entity->lastCollFrame=0;
//decompress physics info
entity->netPos=physMessage->pos;
entity->netVelo.x=physMessage->velo.x/255.0;
entity->netVelo.y=physMessage->velo.y/255.0;
entity->netVelo.z=physMessage->velo.z/255.0;
entity->collVelo=entity->netVelo;
entity->accel.x=physMessage->accel.x/255.0;
entity->accel.y=physMessage->accel.y/255.0;
entity->accel.z=physMessage->accel.z/255.0;
entity->lastFrame=physMessage->frame;
if(entity->lastFrame>gFrameCount)
entity->lastFrame=gFrameCount;
ShortVectorsToMatrix(physMessage->dirZ,physMessage->dirY,entity->netDir);
ShortVectorsToMatrix(physMessage->rVeloZ,physMessage->rVeloY,entity->rVelo);
//is this a car?
if(entity->physicsType==kPhysicsTypeCar)
{
//decompress car physics info
tCarPhysics *phys=(tCarPhysics*)entity->physics;
tCarNetPhysics *inPhys=&(((tCarPhysicsMessage*)message.data)+i)->phys;
phys->lightFlags=inPhys->lightFlags;
phys->rpm=inPhys->rpm/(255.0/10000.0);
phys->throttle=inPhys->throttle/255.0;
phys->steering=inPhys->steering/127.0;
phys->handbrake=inPhys->handbrake/255.0;
// phys->brake=inPhys->brake/255.0;
// phys->gear=inPhys->gear;
phys->lastGearSwitch=gFrameCount*kFrameTime-inPhys->shiftDelay/255.0;
unsigned short damage=inPhys->damage;
U16Swap(damage);
phys->damage=damage;
for(int i=0;i<kMaxWheels;i++)
{
phys->wheels[i].rotation=inPhys->wheels[i].rotation/(255.0/(2*PI));
phys->wheels[i].slipVelo=inPhys->wheels[i].slipVelo;
phys->wheels[i].surfaceType=inPhys->wheels[i].surfaceType;
phys->wheels[i].glow=inPhys->wheels[i].glow/255.0;
phys->wheels[i].angularVelo=inPhys->wheels[i].angularVelo;
}
entity->remoteCameraPos=inPhys->cameraPos;
F32Swap(entity->remoteCameraPos.x);
F32Swap(entity->remoteCameraPos.y);
F32Swap(entity->remoteCameraPos.z);
//dead recogning
int frameDiff=gFrameCount-physMessage->frame;
//entity->netPos=entity->netPos+entity->netVelo*kFrameTime*frameDiff+entity->accel*kFrameTime*kFrameTime*frameDiff*frameDiff*0.5;
//entity->netVelo=entity->netVelo+entity->accel*kFrameTime*frameDiff;
int collIndex=kNumLastCollisions-1;
while(frameDiff>0)
{
while(phys->lastCollisions[collIndex].frameCount<gFrameCount-frameDiff)
collIndex++;
entity->regData=NULL;
if(phys->lastCollisions[collIndex].frameCount==gFrameCount-frameDiff)
ApplyImpulse(entity,phys->lastCollisions[collIndex].attackPoint,phys->lastCollisions[collIndex].veloDiff,phys->lastCollisions[collIndex].rotationFactor,true);
entity->netPos=entity->netPos+entity->netVelo*kFrameTime;
entity->netVelo=entity->netVelo+entity->accel*kFrameTime;
MatrixMult(entity->netDir,entity->rVelo,entity->netDir);
frameDiff--;
}
}
else if(entity->physicsType==kPhysicsTypeSolid)
{
entity->pos=entity->netPos;
entity->velo=entity->netVelo;
MatrixCopy(entity->netDir,entity->dir);
int frameDiff=gFrameCount-physMessage->frame;
while(frameDiff>0)
{
if(entity->lastActivity+kFPS>gFrameCount-frameDiff)
{
entity->velo.y-=gEnvironment->gravity*kFrameTime;
float dampfactor=0;
float v=~entity->velo;
if(v<7)dampfactor=(7-v)/7;
*MatrixGetXVector(entity->rVelo)=Vector(1,0,0)+(1-dampfactor*kFrameTime)*(*MatrixGetXVector(entity->rVelo)-Vector(1,0,0));
*MatrixGetYVector(entity->rVelo)=Vector(0,1,0)+(1-dampfactor*kFrameTime)*(*MatrixGetYVector(entity->rVelo)-Vector(0,1,0));
*MatrixGetZVector(entity->rVelo)=Vector(0,0,1)+(1-dampfactor*kFrameTime)*(*MatrixGetZVector(entity->rVelo)-Vector(0,0,1));
entity->velo=(1-dampfactor*kFrameTime)*entity->velo;
entity->pos=entity->pos+entity->velo*kFrameTime;
MatrixMult(entity->dir,entity->rVelo,entity->dir);
}
MatrixReAdjust(entity->rVelo);
//Check if the entity is moving, and update lastActivity
if(entity->velo*entity->velo>kMinActivityVelo*kMinActivityVelo)
entity->lastActivity=gFrameCount-frameDiff;
if(entity->lastActivity+kFPS>gFrameCount-frameDiff)
if(!((gFrameCount-frameDiff)% kSolidCollisionRate))
SolidCheckCollision(entity);
frameDiff--;
}
}
/*if(physMessage->prioritized)
{
entity->pos=entity->netPos;
entity->velo=entity->netVelo;
MatrixCopy(entity->netDir,entity->dir);
}*/
}
entity=(tGameEntity*)entity->next;
}
}
break;
case kMessageTypeChat:
InsertGameChatMessage(((tChatMessage*)message.data)->str);
ChatBufferInsert(((tChatMessage*)message.data),gChatBuffer);
if(((tChatMessage*)message.data)->flags&(kChatFlagSystem|kChatFlagAlert))
PlayInterfaceSound(FileGetReference("systemchat.wav"));
else
PlayInterfaceSound(FileGetReference("chat.wav"));
break;
case kMessageTypeBye:
{
if(message.from==0)
sprintf(gDisconnectString,"%s quit and stopped hosting.",gGameInfo->playerNames[0]);
int netID=message.from;
int id=-1;
//find the players id
for(int i=0;i<gGameInfo->numNetPlayers;i++)
if(gGameInfo->netID[i]==netID)
id=i;
if(id!=-1)
{
gGameInfo->playerVersions[id]=-2;
/*tChatMessage m;
m.flags=kChatFlagSystem;
sprintf(m.str,"### %s is quitting.",gGameInfo->playerNames[id]);
SoundReInit();
PlayInterfaceSound(FileGetReference("systemchat.wav"));
InsertGameChatMessage(m.str);
ChatBufferInsert(&m,gChatBuffer);*/
}
}
break;
case kMessageTypeKicked:
sprintf(gDisconnectString,"You have been disconnected by the host.");
case kMessageTypeGameTerminated:
gGameEnd=kEndGame;
exit=true;
break;
case kMessageTypeEndGame:
gGameEnd=kEndGameNoLeave;
break;
case kMessageTypePause:
if(gNetPauseTime==0)
{
gNetPauseTime=*(int*)message.data;
S32Swap(gNetPauseTime);
}
break;
case kMessageTypeSynch:
gSynchsRecevied++;
break;
case kMessageTypeResume:
if(gPaused)
{
gNetPauseTime=0;
for(int i=1;i<gGameInfo->numNetPlayers;i++)
if(gGameInfo->netID[i]==-1)
gSynchsRecevied++;
NetworkSynch(gGameInfo->numNetPlayers-gSynchsRecevied);
gSynchsRecevied=0;
UnPauseGame();
}
break;
case kMessageTypePlayerLeft:
{
int netID=message.from;
int id=-1;
//find the players id
for(int i=0;i<gGameInfo->numPlayers;i++)
if(gGameInfo->netID[i]==netID)
id=i;
if(id!=-1)
{
tChatMessage m;
m.flags=kChatFlagSystem;
if(gGameInfo->playerVersions[id]!=-2)
sprintf(m.str,"### %s is disconnected due to network problems.",gGameInfo->playerNames[id]);
else
sprintf(m.str,"### %s quit the game.",gGameInfo->playerNames[id]);
SoundReInit();
PlayInterfaceSound(FileGetReference("systemchat.wav"));
InsertGameChatMessage(m.str);
ChatBufferInsert(&m,gChatBuffer);
KillPlayer(id);
}
}
break;
case kMessageTypeID:
NetworkQueuePacket(&message);
exit=true;
break;
case kMessageTypeFinishTime:
{
tFinishTimeMessage *m=(tFinishTimeMessage*)message.data;
S32Swap(m->time);
S32Swap(m->player);
//printf("%d,%d\n",m->time,m->player);
tCarPhysics *phys=(tCarPhysics*)gCarEntities[m->player]->physics;
phys->finishTime=m->time;
}
break;
case kMessageTypePlayerJoined:
if(gGameInfo->demolition||gGameInfo->numNetPlayers<=1)
{
NetworkQueuePacket(&message);
gGameEnd=kEndGameNoLeave;
exit=true;
}
else
{
UInt8 reason=kJoinDeniedInProgress;
NetworkSendPacket(kMessageTypeJoinDenied,&reason,sizeof(UInt8),kMessagePriorityHigh,kMessageSendToAllButSelf);
}
break;
}
//release the message.
NetworkDisposePacket(&message);
if(exit)
return;
}
}
}
#define kMaxLookAhead 0.5
//similar to NetworkReceivePhysics but does not wait for packets from the network,
//instead it processes packets in the replay log.
void LogReplayFrame()
{
int type,size;
char message[1024];
while(LogGetPacket(gReplayIndex,&type,&size,gGameInfo->numLaps==-1?kLogGhostLog:kLogReplayLog,message))
{
switch(type)
{
case kMessageTypePhysics:
{
tPhysicsMessage *physMessage=(tPhysicsMessage*)((char*)message);
PhysicsMessageSwap(physMessage);
//if(physMessage->id<gCarEntities[0]->id)
// physMessage->id=gCarEntities[0]->id;
if(physMessage->frame>gFrameCount)return;
tGameEntity *entity=(tGameEntity*)gFirstEntity->next;
//see if we find the entity it belongs to
while(entity!=gFirstEntity)
{
//is this the entity the message refers to?
if(entity->id==physMessage->id)
{
//decompress physics info
entity->pos=physMessage->pos;
entity->velo.x=physMessage->velo.x/255.0;
entity->velo.y=physMessage->velo.y/255.0;
entity->velo.z=physMessage->velo.z/255.0;
entity->accel.x=physMessage->accel.x/255.0;
entity->accel.y=physMessage->accel.y/255.0;
entity->accel.z=physMessage->accel.z/255.0;
// ShortVectorsToMatrix(physMessage->dirZ,physMessage->dirY,entity->dir);
ShortVectorsToMatrix(physMessage->dirZ,physMessage->dirY,entity->netDir);
ShortVectorsToMatrix(physMessage->rVeloZ,physMessage->rVeloY,entity->rVelo);
//is this a car?
if(entity->physicsType==kPhysicsTypeCar)
{
//decompress car physics info
tCarPhysics *phys=(tCarPhysics*)entity->physics;
tCarNetPhysics *inPhys=&((tCarPhysicsMessage*)message)->phys;
phys->lightFlags=inPhys->lightFlags;
phys->rpm=inPhys->rpm/(255.0/10000.0);;
phys->throttle=inPhys->throttle/255.0;
phys->steering=inPhys->steering/127.0;
phys->handbrake=inPhys->handbrake/255.0;
// phys->brake=inPhys->brake/255.0;
// phys->gear=inPhys->gear;
phys->lastGearSwitch=gFrameCount*kFrameTime-inPhys->shiftDelay/255.0;
unsigned short damage=inPhys->damage;
U16Swap(damage);
phys->damage=damage;
for(int i=0;i<kMaxWheels;i++)
{
phys->wheels[i].rotation=inPhys->wheels[i].rotation/(255.0/(2*PI));
phys->wheels[i].slipVelo=inPhys->wheels[i].slipVelo;
phys->wheels[i].surfaceType=inPhys->wheels[i].surfaceType;
phys->wheels[i].glow=inPhys->wheels[i].glow/255.0;
phys->wheels[i].angularVelo=inPhys->wheels[i].angularVelo;
}
}
}
entity=(tGameEntity*)entity->next;
}
}
break;
}
gReplayIndex++;
}
}
void LogReplayGhostFrame()
{
int type,size;
char message[1024];
while(LogGetPacket(gReplayIndex,&type,&size,kLogGhostLog,message))
{
switch(type)
{
case kMessageTypePhysics:
{
tPhysicsMessage *physMessage=(tPhysicsMessage*)message;
PhysicsMessageSwap(physMessage);
if(physMessage->frame>gFrameCount-gCurrentLapStart+gBestLapStart)
return;
gGhostEntity->pos=physMessage->pos;
gGhostEntity->velo.x=physMessage->velo.x/255.0;
gGhostEntity->velo.y=physMessage->velo.y/255.0;
gGhostEntity->velo.z=physMessage->velo.z/255.0;
gGhostEntity->lastFrame=physMessage->frame;
ShortVectorsToMatrix(physMessage->dirZ,physMessage->dirY,gGhostEntity->dir);
tCarPhysics *phys=(tCarPhysics*)gGhostEntity->physics;
tCarNetPhysics *inPhys=(tCarNetPhysics*)((char*)message+sizeof(tPhysicsMessage));
phys->lightFlags=inPhys->lightFlags;
phys->rpm=inPhys->rpm/(255.0/10000.0);;
phys->throttle=inPhys->throttle/255.0;
phys->steering=inPhys->steering/127.0;
for(int i=0;i<kMaxWheels;i++)
{
phys->wheels[i].rotation=inPhys->wheels[i].rotation/(255.0/(2*PI));
phys->wheels[i].slipVelo=inPhys->wheels[i].slipVelo;
phys->wheels[i].surfaceType=inPhys->wheels[i].surfaceType;
}
}
break;
}
gReplayIndex++;
}
gGhostEntity->pos=Vector(10000,10000,10000);
gGhostEntity->velo=Vector(0,0,0);
}

42
source/networkphysics.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef __NETWORKPHYSICS
#define __NETWORKPHYSICS
#include "vectors.h"
typedef struct{
char x,y,z;
} tVector3Char;
typedef struct{
short x,y,z;
} tVector3Short;
typedef struct{
int frame;
tVector3 pos;
short id;
char prioritized;
tVector3Short velo;
tVector3Short accel;
tVector3Short dirZ,dirY;
tVector3Short rVeloZ,rVeloY;
} tPhysicsMessage;
typedef struct{
float timestamp;
char message[256];
} tGameChatMessage;
extern int gNumGameChatMessages;
extern tGameChatMessage gGameChatMessagesRecv[];
extern int gReplayIndex;
extern int gOutboxPos;
void InsertGameChatMessage(char *message);
void NetworkSendPhysics();
void NetworkReceivePhysics();
void LogReplayFrame();
void LogReplayGhostFrame();
void GameChatMessagesScroll();
#endif

81
source/notifications.mm Normal file
View File

@ -0,0 +1,81 @@
#include <Cocoa/Cocoa.h>
#include "gamesystem.h"
#include "gametime.h"
#include "screen.h"
#include "config.h"
@interface Notifications : NSObject
{
}
@end
@implementation Notifications
- (void)observerMethod:(NSNotification*)aNotification
{
if(aNotification)
{
if([[aNotification name] compare:@"com.apple.iTunes.playerInfo"]==NSOrderedSame)
{
int oldState=giTunesPlaying;
NSDictionary *dic=[aNotification userInfo];
NSString *str;
str=[dic objectForKey:@"Name"];
if(str)
strcpy(giTunesSong,[str cString]);
else
strcpy(giTunesSong,"");
StripDiacritics(giTunesSong,strlen(giTunesSong),smSystemScript);
str=[dic objectForKey:@"Artist"];
if(str)
strcpy(giTunesArtist,[str cString]);
else
strcpy(giTunesArtist,"");
StripDiacritics(giTunesArtist,strlen(giTunesArtist),smSystemScript);
str=[dic objectForKey:@"Player State"];
if(str)
{
if([str compare:@"Playing"]==NSOrderedSame)
giTunesPlaying=kITunesPlaying;
else if([str compare:@"Paused"]==NSOrderedSame)
giTunesPlaying=kITunesPaused;
else
giTunesPlaying=kITunesStopped;
}
if(oldState!=giTunesPlaying||giTunesPlaying)
giTunesLastStatusUpdate=TimeGetSeconds();
}
if([[aNotification name] compare:@"NSWorkspaceWillSleepNotification"]==NSOrderedSame)
{
if(!ScreenNoWindow())
if(gConfig->fullscreen)
{
gConfig->fullscreen=false;
ScreenReInit();
}
}
}
}
- (id)init
{
if(self==[super init])
{
[[NSDistributedNotificationCenter defaultCenter] addObserver:self
selector:@selector(observerMethod:)
name:nil object:nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
selector:@selector(observerMethod:)
name:nil object:nil];
}
return self;
}
@end
void InitITunesNotifications()
{
NSAutoreleasePool *pool=[NSAutoreleasePool new];
Notifications *notif;
notif = [Notifications new];
}

Some files were not shown because too many files have changed in this diff Show More