Original 1.0.5 code
(as received from Jonas Echterhoff)
This commit is contained in:
commit
02061d74c2
BIN
English.lproj/InfoPlist.strings
Normal file
BIN
English.lproj/InfoPlist.strings
Normal file
Binary file not shown.
245
HID_cookie_strings.plist
Executable file
245
HID_cookie_strings.plist
Executable 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
633
HID_device_usage_strings.plist
Executable 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
200
HID_usage_strings.plist
Executable 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
293
Info.plist
Normal 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
BIN
Next Track.scpt
Normal file
Binary file not shown.
BIN
PlayPause.scpt
Normal file
BIN
PlayPause.scpt
Normal file
Binary file not shown.
BIN
Plugin.icns
Normal file
BIN
Plugin.icns
Normal file
Binary file not shown.
BIN
Prev Track.scpt
Normal file
BIN
Prev Track.scpt
Normal file
Binary file not shown.
BIN
Redline.icns
Executable file
BIN
Redline.icns
Executable file
Binary file not shown.
BIN
Redline.rsrc
Normal file
BIN
Redline.rsrc
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
Status.scpt
Normal file
BIN
Status.scpt
Normal file
Binary file not shown.
BIN
build/game.build/game.pbxindex/categories.pbxbtree
Normal file
BIN
build/game.build/game.pbxindex/categories.pbxbtree
Normal file
Binary file not shown.
BIN
build/game.build/game.pbxindex/cdecls.pbxbtree
Normal file
BIN
build/game.build/game.pbxindex/cdecls.pbxbtree
Normal file
Binary file not shown.
BIN
build/game.build/game.pbxindex/decls.pbxbtree
Normal file
BIN
build/game.build/game.pbxindex/decls.pbxbtree
Normal file
Binary file not shown.
BIN
build/game.build/game.pbxindex/files.pbxbtree
Normal file
BIN
build/game.build/game.pbxindex/files.pbxbtree
Normal file
Binary file not shown.
BIN
build/game.build/game.pbxindex/imports.pbxbtree
Normal file
BIN
build/game.build/game.pbxindex/imports.pbxbtree
Normal file
Binary file not shown.
BIN
build/game.build/game.pbxindex/pbxindex.header
Normal file
BIN
build/game.build/game.pbxindex/pbxindex.header
Normal file
Binary file not shown.
BIN
build/game.build/game.pbxindex/protocols.pbxbtree
Normal file
BIN
build/game.build/game.pbxindex/protocols.pbxbtree
Normal file
Binary file not shown.
BIN
build/game.build/game.pbxindex/refs.pbxbtree
Normal file
BIN
build/game.build/game.pbxindex/refs.pbxbtree
Normal file
Binary file not shown.
BIN
build/game.build/game.pbxindex/strings.pbxstrings/control
Normal file
BIN
build/game.build/game.pbxindex/strings.pbxstrings/control
Normal file
Binary file not shown.
BIN
build/game.build/game.pbxindex/strings.pbxstrings/strings
Normal file
BIN
build/game.build/game.pbxindex/strings.pbxstrings/strings
Normal file
Binary file not shown.
BIN
build/game.build/game.pbxindex/subclasses.pbxbtree
Normal file
BIN
build/game.build/game.pbxindex/subclasses.pbxbtree
Normal file
Binary file not shown.
BIN
build/game.build/game.pbxindex/symbols0.pbxsymbols
Normal file
BIN
build/game.build/game.pbxindex/symbols0.pbxsymbols
Normal file
Binary file not shown.
1398
game.xcodeproj/jechter.mode1
Normal file
1398
game.xcodeproj/jechter.mode1
Normal file
File diff suppressed because it is too large
Load Diff
1386
game.xcodeproj/jechter.mode1v3
Normal file
1386
game.xcodeproj/jechter.mode1v3
Normal file
File diff suppressed because it is too large
Load Diff
1316
game.xcodeproj/jechter.pbxuser
Normal file
1316
game.xcodeproj/jechter.pbxuser
Normal file
File diff suppressed because it is too large
Load Diff
855
game.xcodeproj/project.pbxproj
Normal file
855
game.xcodeproj/project.pbxproj
Normal 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
6
game_Prefix.pch
Normal 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
BIN
iChat Status.scpt
Normal file
Binary file not shown.
BIN
source.zip
Normal file
BIN
source.zip
Normal file
Binary file not shown.
402
source/GetPID.c
Executable file
402
source/GetPID.c
Executable 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
169
source/GetPID.h
Executable 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
981
source/S3Decompression.cpp
Executable 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
8
source/S3Decompression.h
Executable 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
292
source/ai.cpp
Normal 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
1338
source/carphysics.cpp
Executable file
File diff suppressed because it is too large
Load Diff
214
source/carphysics.h
Executable file
214
source/carphysics.h
Executable 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
819
source/carselection.cpp
Normal 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
22
source/carselection.h
Normal 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
235
source/challenges.cpp
Normal 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
25
source/challenges.h
Normal 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
809
source/collision.cpp
Executable 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
15
source/collision.h
Normal 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
41
source/config.cpp
Normal 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
108
source/config.h
Normal 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
740
source/controls.cpp
Executable 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
100
source/controls.h
Executable 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
23
source/entities.cpp
Executable 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
117
source/entities.h
Executable 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
28
source/environment.cpp
Normal 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
36
source/environment.h
Normal 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
1
source/error.h
Normal 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
358
source/fileio.cpp
Executable 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
78
source/fileio.h
Executable 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
33
source/fpu_exc.c
Normal 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
4
source/fpu_exc.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
void EnableFPUExceptions();
|
||||||
|
}
|
846
source/gameframe.cpp
Executable file
846
source/gameframe.cpp
Executable 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
41
source/gameframe.h
Executable 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
772
source/gameinitexit.cpp
Executable 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
179
source/gameinitexit.h
Normal 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
13
source/gamemem.h
Executable 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
18
source/gamesound.h
Normal 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
22
source/gamesystem.h
Normal 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
9
source/gametime.h
Normal 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
1242
source/infodisplay.cpp
Normal file
File diff suppressed because it is too large
Load Diff
157
source/initexit.cpp
Executable file
157
source/initexit.cpp
Executable 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
13
source/initexit.h
Executable 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
555
source/interface.cpp
Normal 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
15
source/interface.h
Normal 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
|
2236
source/interfacemultiplayer.cpp
Normal file
2236
source/interfacemultiplayer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
20
source/interfacemultiplayer.h
Normal file
20
source/interfacemultiplayer.h
Normal 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
959
source/interfaceoptions.cpp
Normal 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
1206
source/interfaceutil.cpp
Normal file
File diff suppressed because it is too large
Load Diff
130
source/interfaceutil.h
Normal file
130
source/interfaceutil.h
Normal 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
235
source/lights.cpp
Normal 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
9
source/lights.h
Normal 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
15
source/localtracker.h
Normal 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
291
source/log.cpp
Normal 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
26
source/log.h
Normal 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
664
source/maccontrols.cpp
Executable 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
116
source/macerror.cpp
Normal 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
397
source/macfileio.cpp
Executable 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
490
source/maclocaltracker.cpp
Normal 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
346
source/macscreen.cpp
Normal 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
923
source/macsystem.cpp
Normal 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(¤tProc);
|
||||||
|
Boolean same;
|
||||||
|
SameProcess(¤tProc,&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;
|
||||||
|
}
|
107
source/mactexturesimport.cpp
Normal file
107
source/mactexturesimport.cpp
Normal 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
12
source/main.cpp
Executable 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
362
source/mapselection.cpp
Normal 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
14
source/mapselection.h
Normal 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
995
source/models.cpp
Executable 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
1
source/models.h
Executable 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
78
source/modeltypes.h
Normal 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
69
source/music.cpp
Normal 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
10
source/music.h
Normal 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
126
source/network.h
Normal 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
924
source/network_NT.cpp
Normal 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
952
source/networkphysics.cpp
Normal 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
42
source/networkphysics.h
Normal 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
81
source/notifications.mm
Normal 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
Loading…
Reference in New Issue
Block a user