1 : ////////////////////////////////////////////////////////////////// 2 : // Bristle 3 : // 4 : // Bristly hair screen saver animation 5 : // Flying Pig 6 : // 1.00 (29 Aug 2006) 7 : ////////////////////////////////////////////////////////////////// 8 : 9 : ////////////////////////////////////////////////////////////////// 10 : // Includes 11 : 12 : #include "oslib/wimp.h" 13 : #include "oslib/dragasprite.h" 14 : #include "oslib/colourtrans.h" 15 : 16 : #include "ScrSave.h" 17 : #include "Choices.h" 18 : #include "Bristle.h" 19 : 20 : #include 21 : #include 22 : #include 23 : #include 24 : #include 25 : #include 26 : #include 27 : 28 : ////////////////////////////////////////////////////////////////// 29 : // Defines 30 : 31 : #define RANGE(var,min,max) if ((var) < (min)) var = min; \ 32 : if ((var) > (max)) var = max; 33 : #define HAIR_X_DEF (20) 34 : #define HAIR_Y_DEF (20) 35 : #define HAIR_X_MAX (50) 36 : #define HAIR_Y_MAX (50) 37 : #define HAIR_MAX (HAIR_X_MAX * HAIR_Y_MAX) 38 : #define HAIR_ROT_MAX (0.5f / M_PI) 39 : #define HAIR_MIN_LEN (20.0f) 40 : #define HAIR_START_LEN (0.5f) 41 : #define HAIR_END_LEN (70.0f) 42 : #define HAIR_COL_MAX (50.0f) 43 : #define ANIM_STEP_MAX (6.0f) 44 : 45 : ////////////////////////////////////////////////////////////////// 46 : // Structures 47 : 48 : ////////////////////////////////////////////////////////////////// 49 : // Global variables 50 : 51 : // Amount 52 : static int gnHairXMax = HAIR_X_DEF; 53 : static int gnHairYMax = HAIR_Y_DEF; 54 : static int gnHairs = (HAIR_X_DEF * HAIR_Y_DEF); 55 : 56 : // Hairs 57 : static float gfHairRotMax = HAIR_ROT_MAX; 58 : static float gfAngleAdd = 0.0f * M_PI; 59 : static float gfAttraction = 20000.0f; 60 : static float gfLenMin = HAIR_MIN_LEN; 61 : static float gfLenStart = HAIR_START_LEN; 62 : static float gfLenEnd = HAIR_END_LEN; 63 : 64 : // Movement 65 : static float gfParam1 = 31.0f; 66 : static float gfParam2 = 29.0f; 67 : static float gfParam3 = 26.4f; 68 : static float gfScale1 = 1.0f; 69 : static float gfScale2 = 1.5f; 70 : static float gfScale3 = 1.0f; 71 : static float gfScale4 = 1.3f; 72 : 73 : // Colour 74 : static float gfColCycle = 1000.0f; 75 : static float gfRed1Param = M_PI / 200.0f; 76 : static float gfBlue1Param = M_PI / 123.0f; 77 : static float gfGreen1Param = M_PI / 91.0f; 78 : static float gfRed2Param = M_PI / 71.0f; 79 : static float gfGreen2Param = M_PI / 211.0f; 80 : static float gfBlue2Param = M_PI / 183.0f; 81 : 82 : // General 83 : static int gnScreenWidth; 84 : static int gnScreenHeight; 85 : 86 : static float gfAngle1 = 0.0f; 87 : static float gfAngle2 = 0.0f; 88 : static float gfAngle3 = 0.0f; 89 : 90 : static float gfXPos[HAIR_MAX]; 91 : static float gfYPos[HAIR_MAX]; 92 : static float gfAngle[HAIR_MAX]; 93 : static float gfLength[HAIR_MAX]; 94 : 95 : static float gfPXPos[HAIR_MAX]; 96 : static float gfPYPos[HAIR_MAX]; 97 : static float gfPAngle[HAIR_MAX]; 98 : static float gfPLength[HAIR_MAX]; 99 : 100 : static float gfRed1 = 1.0f; 101 : static float gfGreen1 = 0.0f; 102 : static float gfBlue1 = 0.0f; 103 : static float gfRed2 = 1.0f; 104 : static float gfGreen2 = 1.0f; 105 : static float gfBlue2 = 0.0f; 106 : 107 : static float gfColourDelay = 0.0f; 108 : static float gfColourDelayCycle = 0.0f;; 109 : 110 : static float gfRed1Count = 0.0f; 111 : static float gfGreen1Count = 0.0f; 112 : static float gfBlue1Count = 0.0f; 113 : static float gfRed2Count = 0.0f; 114 : static float gfGreen2Count = 0.0f; 115 : static float gfBlue2Count = 0.0f; 116 : 117 : 118 : ////////////////////////////////////////////////////////////////// 119 : // Local function prototypes 120 : 121 : float AngleMod (float fAngle); 122 : 123 : ////////////////////////////////////////////////////////////////// 124 : // Main application 125 : 126 : ////////////////////////////////////////////////////////////////// 127 : // Update window 128 : void UpdateScreenSaver (wimp_draw * psRedraw) { 129 : bool boMore = TRUE; 130 : 131 : wimp_update_window (psRedraw); 132 : 133 : while (boMore) { 134 : // Redraw the screen saver, updating as we go along 135 : DrawScreenSaver (psRedraw, ANIMDRAW_UPDATE); 136 : boMore = wimp_get_rectangle (psRedraw); 137 : } 138 : } 139 : 140 : ////////////////////////////////////////////////////////////////// 141 : // Draw screen saver area 142 : void DrawScreenSaver (wimp_draw * psDraw, ANIMDRAW eDrawType) { 143 : int nRedMinX = psDraw->clip.x0; 144 : int nRedMinY = psDraw->clip.y0; 145 : int nRedMaxX = psDraw->clip.x1; 146 : int nRedMaxY = psDraw->clip.y1; 147 : int nCount; 148 : float fXHair; 149 : float fYHair; 150 : unsigned char cRed = 255; 151 : unsigned char cGreen = 0; 152 : unsigned char cBlue = 0; 153 : float fDistance; 154 : float fColour; 155 : 156 : if (eDrawType == ANIMDRAW_CLEAR) { 157 : // Clear using the background colour first 158 : xcolourtrans_set_gcol (os_COLOUR_BLACK, 0, os_ACTION_OVERWRITE, 159 : NULL, NULL); 160 : xos_plot (os_PLOT_POINT | os_MOVE_TO, nRedMinX, nRedMinY); 161 : xos_plot (os_PLOT_RECTANGLE | os_PLOT_TO, nRedMaxX, nRedMaxY); 162 : } 163 : 164 : // Draw the hairs 165 : for (nCount = 0; nCount < gnHairs; nCount++) { 166 : if (eDrawType == ANIMDRAW_UPDATE) { 167 : // Remove the previous picture 168 : xcolourtrans_set_gcol (os_COLOUR_BLACK, 0, os_ACTION_OVERWRITE, 169 : NULL, NULL); 170 : fXHair = (gfLenMin + gfPLength[nCount]) 171 : * cos (gfPAngle[nCount] + gfAngleAdd); 172 : fYHair = (gfLenMin + gfPLength[nCount]) 173 : * sin (gfPAngle[nCount] + gfAngleAdd); 174 : xos_plot (os_PLOT_POINT | os_MOVE_TO, 175 : (int)(gfPXPos[nCount] + (fXHair * gfLenStart)), 176 : (int)(gfPYPos[nCount] + (fYHair * gfLenStart))); 177 : xos_plot (os_PLOT_SOLID | os_PLOT_BY, (int)fXHair, (int)fYHair); 178 : } 179 : 180 : fDistance = (gfLength[nCount] / HAIR_COL_MAX); 181 : 182 : fColour = 255.0f * (gfRed2 + ((gfRed1 - gfRed2) * fDistance)); 183 : RANGE (fColour, 0.0f, 255.0f) 184 : cRed = (unsigned char)(fColour); 185 : 186 : fColour = 255.0f * (gfGreen2 + ((gfGreen1 - gfGreen2) * fDistance)); 187 : RANGE (fColour, 0.0f, 255.0f) 188 : cGreen = (unsigned char)(fColour); 189 : 190 : fColour = 255.0f * (gfBlue2 + ((gfBlue1 - gfBlue2) * fDistance)); 191 : RANGE (fColour, 0.0f, 255.0f) 192 : cBlue = (unsigned char)(fColour); 193 : 194 : xcolourtrans_set_gcol ((cBlue << 24) + (cGreen << 16) + (cRed << 8), 195 : colourtrans_USE_ECFS, os_ACTION_OVERWRITE, NULL, NULL); 196 : 197 : fXHair = (gfLenMin + gfLength[nCount]) 198 : * cos (gfAngle[nCount] + gfAngleAdd); 199 : fYHair = (gfLenMin + gfLength[nCount]) 200 : * sin (gfAngle[nCount] + gfAngleAdd); 201 : xos_plot (os_PLOT_POINT | os_MOVE_TO, 202 : (int)(gfXPos[nCount] + (fXHair * gfLenStart)), 203 : (int)(gfYPos[nCount] + (fYHair * gfLenStart))); 204 : xos_plot (os_PLOT_SOLID | os_PLOT_BY, (int)fXHair, (int)fYHair); 205 : } 206 : } 207 : 208 : ////////////////////////////////////////////////////////////////// 209 : // Animate the screen saver 210 : void AnimateScreenSaver (float fChange, wimp_draw * psRedraw) { 211 : int nCount; 212 : float fXPos; 213 : float fYPos; 214 : float fXDif; 215 : float fYDif; 216 : float fAngle; 217 : float fDistancePow; 218 : float fDistance; 219 : float fMaxRot; 220 : 221 : if (fChange > ANIM_STEP_MAX) fChange = ANIM_STEP_MAX; 222 : 223 : if (fChange > 0.0f) { 224 : // Deal with the colours 225 : if (gfColourDelay < 0.0f) { 226 : // Reset the colour counter with a new delay 227 : gfColourDelayCycle += 2.0f; 228 : if (gfColourDelayCycle > (2 * M_PI)) gfColourDelayCycle -= (2 * M_PI); 229 : gfColourDelay = (2.0f + sin (gfColourDelayCycle)) * gfColCycle; 230 : } 231 : else { 232 : gfColourDelay -= fChange; 233 : } 234 : 235 : if (gfColourDelay < 100.0f) { 236 : // Time to update the colours 237 : gfRed1 = (1.5f + cos (gfRed1Count)) / 2.5f; 238 : gfGreen1 = (1.0f - cos (gfGreen1Count)) / 2.0f; 239 : gfBlue1 = (1.0f - cos (gfBlue1Count)) / 2.0f; 240 : 241 : gfRed2 = (1.5f + cos (gfRed2Count)) / 2.5f; 242 : gfGreen2 = (1.3f + cos (gfGreen2Count)) / 2.3f; 243 : gfBlue2 = (1.0f - cos (gfBlue2Count)) / 2.0f; 244 : 245 : gfRed1Count += gfRed1Param; 246 : gfGreen1Count += gfBlue1Param; 247 : gfBlue1Count += gfGreen1Param; 248 : 249 : gfRed2Count += gfRed2Param; 250 : gfGreen2Count += gfGreen2Param; 251 : gfBlue2Count += gfBlue2Param; 252 : 253 : if (gfRed1Count > (2 * M_PI)) gfRed1Count -= (2 * M_PI); 254 : if (gfGreen1Count > (2 * M_PI)) gfGreen1Count -= (2 * M_PI); 255 : if (gfBlue1Count > (2 * M_PI)) gfBlue1Count -= (2 * M_PI); 256 : if (gfRed2Count > (2 * M_PI)) gfRed2Count -= (2 * M_PI); 257 : if (gfGreen2Count > (2 * M_PI)) gfGreen2Count -= (2 * M_PI); 258 : if (gfBlue2Count > (2 * M_PI)) gfBlue2Count -= (2 * M_PI); 259 : } 260 : 261 : // Update the animation 262 : gfAngle1 += fChange / (gfParam1 * M_PI); 263 : gfAngle2 += fChange / (gfParam2 * M_PI); 264 : gfAngle3 += fChange / (gfParam3 * M_PI); 265 : 266 : if (gfAngle1 > (2.0f * M_PI)) gfAngle1 -= 2.0f * M_PI; 267 : if (gfAngle2 > (2.0f * M_PI)) gfAngle2 -= 2.0f * M_PI; 268 : if (gfAngle3 > (2.0f * M_PI)) gfAngle3 -= 2.0f * M_PI; 269 : 270 : fXPos = (float)(gnScreenWidth / 2) 271 : + ((float)(gnScreenWidth / 4) * ((gfScale1 * cos (gfAngle1)) 272 : + (gfScale2 * sin (gfAngle2)))); 273 : fYPos = (float)(gnScreenHeight / 2) 274 : + ((float)(gnScreenHeight / 4) * ((gfScale3 * sin (gfAngle1)) 275 : + (gfScale4 * sin (gfAngle3)))); 276 : 277 : // Move each hair towards the moving point 278 : for (nCount = 0; nCount < gnHairs; nCount++) { 279 : fXDif = fXPos - gfXPos[nCount]; 280 : fYDif = fYPos - gfYPos[nCount]; 281 : 282 : fDistancePow = (pow (fXDif, 2.0f) + pow (fYDif, 2.0f)); 283 : fDistance = sqrt (fDistancePow); 284 : fDistancePow /= gfAttraction; 285 : fMaxRot = (gfHairRotMax * fChange); 286 : 287 : fAngle = AngleMod (atan2 (fYDif, fXDif) - gfAngle[nCount]); 288 : if (fDistancePow > 1.0f) fMaxRot /= fDistancePow; 289 : if (fAngle < -fMaxRot) fAngle = -fMaxRot; 290 : if (fAngle > fMaxRot) fAngle = fMaxRot; 291 : 292 : gfAngle[nCount] += fAngle; 293 : gfLength[nCount] = gfLenEnd * fDistance / (float)gnScreenWidth; 294 : } 295 : 296 : // Redraw the display 297 : UpdateScreenSaver (psRedraw); 298 : 299 : // Take a copy of all current positions 300 : for (nCount = 0; nCount < gnHairs; nCount++) { 301 : gfPXPos[nCount] = gfXPos[nCount]; 302 : gfPYPos[nCount] = gfYPos[nCount]; 303 : gfPAngle[nCount] = gfAngle[nCount]; 304 : gfPLength[nCount] = gfLength[nCount]; 305 : } 306 : } 307 : } 308 : 309 : ////////////////////////////////////////////////////////////////// 310 : // Initialise the animation 311 : void InitAnimation (int nWidth, int nHeight) { 312 : int nCount; 313 : FILE *pfhChoices; 314 : int nSection; 315 : int nValue; 316 : 317 : gnScreenWidth = nWidth; 318 : gnScreenHeight = nHeight; 319 : 320 : // Load details from the configuration file 321 : pfhChoices = fopen (CHOICES, "r"); 322 : if (pfhChoices) { 323 : nSection = FindSection (pfhChoices, "Screen"); 324 : FindInt (pfhChoices, nSection, "Rows", & gnHairYMax); 325 : FindInt (pfhChoices, nSection, "Columns", & gnHairXMax); 326 : nValue = 2; 327 : FindInt (pfhChoices, nSection, "Update", & nValue); 328 : SetAnimationDelay (nValue); 329 : 330 : nSection = FindSection (pfhChoices, "Hairs"); 331 : FindFloat (pfhChoices, nSection, "RotateMax", & gfHairRotMax); 332 : FindFloat (pfhChoices, nSection, "AngleAdd", & gfAngleAdd); 333 : FindFloat (pfhChoices, nSection, "Attraction", & gfAttraction); 334 : if (gfAttraction <= 1.0f) gfAttraction = 1.0f; 335 : FindFloat (pfhChoices, nSection, "Distortion", & gfLenStart); 336 : FindFloat (pfhChoices, nSection, "Length", & gfLenEnd); 337 : FindFloat (pfhChoices, nSection, "LengthMin", & gfLenMin); 338 : 339 : nSection = FindSection (pfhChoices, "Movement"); 340 : FindFloat (pfhChoices, nSection, "Param1", & gfParam1); 341 : FindFloat (pfhChoices, nSection, "Param2", & gfParam2); 342 : FindFloat (pfhChoices, nSection, "Param3", & gfParam3); 343 : FindFloat (pfhChoices, nSection, "Scale1", & gfScale1); 344 : FindFloat (pfhChoices, nSection, "Scale2", & gfScale2); 345 : FindFloat (pfhChoices, nSection, "Scale3", & gfScale3); 346 : FindFloat (pfhChoices, nSection, "Scale4", & gfScale4); 347 : 348 : nSection = FindSection (pfhChoices, "Colour"); 349 : FindFloat (pfhChoices, nSection, "Cycle", & gfColCycle); 350 : FindFloat (pfhChoices, nSection, "Red1", & gfRed1Param); 351 : FindFloat (pfhChoices, nSection, "Green1", & gfGreen1Param); 352 : FindFloat (pfhChoices, nSection, "Blue1", & gfBlue1Param); 353 : FindFloat (pfhChoices, nSection, "Red2", & gfRed2Param); 354 : FindFloat (pfhChoices, nSection, "Green2", & gfGreen2Param); 355 : FindFloat (pfhChoices, nSection, "Blue2", & gfBlue2Param); 356 : 357 : fclose (pfhChoices); 358 : } 359 : 360 : if (gnHairXMax > HAIR_X_MAX) gnHairXMax = HAIR_X_MAX; 361 : if (gnHairYMax > HAIR_Y_MAX) gnHairYMax = HAIR_Y_MAX; 362 : gnHairs = gnHairXMax * gnHairYMax; 363 : if (gnHairs > HAIR_MAX) gnHairs = HAIR_MAX; 364 : 365 : for (nCount = 0; nCount < gnHairs; nCount++) { 366 : gfXPos[nCount] = ((float)gnScreenWidth / (float)gnHairXMax) 367 : * ((nCount % gnHairXMax) + 0.5f); 368 : gfYPos[nCount] = ((float)gnScreenHeight / (float)gnHairYMax) 369 : * ((nCount / gnHairXMax) + 0.5f); 370 : gfAngle[nCount] = 0.0f; 371 : gfLength[nCount] = 40.0f; 372 : 373 : gfPXPos[nCount] = gfXPos[nCount]; 374 : gfPYPos[nCount] = gfYPos[nCount]; 375 : gfPAngle[nCount] = gfAngle[nCount]; 376 : gfPLength[nCount] = gfLength[nCount]; 377 : } 378 : } 379 : 380 : ////////////////////////////////////////////////////////////////// 381 : // Fix an angle so it lies between -PI and +PI 382 : float AngleMod (float fAngle) { 383 : fAngle -= (2.0f * M_PI) * (int)(fAngle / (2 * M_PI)); 384 : if (fAngle < - M_PI) fAngle += (2 * M_PI); 385 : if (fAngle > M_PI) fAngle -= (2 * M_PI); 386 : 387 : return fAngle; 388 : } 389 :