1 // LandCaster.c - Barebones raycasting renderer in C by Bret Logan
2 //Copyright (C) 2010 Bret Byron Logan (gnaural@sourceforge.net)
3 //
4 //      This program is free software; you can redistribute it and/or modify
5 //      it under the terms of the GNU General Public License as published by
6 //      the Free Software Foundation; either version 2 of the License, or
7 //      (at your option) any later version.
8 //
9 //      This program is distributed in the hope that it will be useful,
10 //      but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //      GNU General Public License for more details.
13 //
14 //      You should have received a copy of the GNU General Public License
15 //      along with this program; if not, write to the Free Software
16 //      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 //      MA 02110-1301, USA.
18 
19    //To use, just load-up LC_LandCaster_Initialize(), then call LC_LandscapeRollSkyFlyingObjects() and LC_DoMovement()
20    //until you are finished using it. Then call LC_LandCaster_Cleanup() when you are done. Do
21    //LC_SetRoll(LC_CircleRez>>1);
22    //at some pre-drawing point if image is inverted -- in which case, you should probably
23    //reverse "gravity" too:
24    //LC_Lift=-LC_Lift;
25 
26 #include <stdlib.h>
27 #include <math.h>
28 #include "LandCaster.h"
29 
30 //======================================
31 //Defines:
32 #define LC_SHIFT          10    //10 is normal - but don't change this without changing LC_DOUBLESHIFT!
33 #define LC_DOUBLESHIFT    20    //always must be double LC_SHIFT
34 #define LC_YSHIFT         19    //always one less than LC_DOUBLESHIFT
35 #define LC_SPEEDSHIFT     4     //4 works with LC_SHIFT of 10
36 #define LC_VISIBLE  1
37 #define LC_TARGET   1
38 #define LC_SKINNY    1
39 #define LC_SIDEWAYS   0
40 #define LC_FACING     2
41 #define LC_CHANCE     0
42 #define LC_LINEDUP    1
43 #define LC_MISSILE  0
44 #define LC_OBJECTHIT  2
45 #define LC_GROUND     3
46 #define LC_STARTING_RAYLENGTH 1024
47 
48 //======================================
49 //Global Variables:
50 //User MUST set these:
51 LC_BITMAP LC_BmpDest;
52 LC_BITMAP LC_BmpColors;         //address of first byte of color data bitmap
53 LC_BITMAP LC_BmpHeights;
54 LC_BITMAP LC_BmpSky;
55  //User doesn't have to set these:
56 int LC_SkyFlag;                 //if present, and there is a sky bitmap, will draw sky
57 int LC_MaxFrameWidth;
58 int *LC_Sin = NULL;
59 int *LC_Cos = NULL;
60 int *LC_Correction = NULL;
61 int *LC_DistanceScaling = NULL;
62 int *LC_TextureScaling = NULL;
63 typedef struct ROLLDATA_TYPE
64 {
65  int StartX;
66  int StartY;
67  unsigned short endpoints;
68 } ROLLDATA;
69 ROLLDATA *LC_RollData = NULL;
70 AUTOPILOTDATA LC_AP;
71 int LC_PositionY;               //X,Y Point on Map scaled by <<LC_SHIFT
72 int LC_PositionX;               //X,Y Point on Map scaled by <<LC_SHIFT
73 int LC_Roll = 0;                //never set less than zero or more than circlerez; use LC_SetRoll();
74 int LC_Tilt = 0;                //sets tilt of view
75 int LC_Altitude = 0;            //sets altitude of view
76 int LC_Direction = 0;           //set view direction based on full circle of LC_CircleRez
77 int LC_Turn;                    //sets rate of turn and direction of turn (+/-). 0 means no change
78 int LC_Lift;                    //sets climb or sink
79 int LC_Speed;                   //0 means no movement. can be negative
80 int LC_Eyelevel;                //height above ground at collision
81 int LC_CircleRez;               //sets the number of steps in everything circular
82 int LC_Raylength;               //determines how far to raycast
83 long LC_BmpColorsHeight_scaled;
84 long LC_BmpColorsWidth_scaled;
85 int LC_InitFlag;                //ensures I have Initted stuff before running Landscape()
86 int *LC_TextureStepX;           //array for LC_FlyingObject funcs
87 int *LC_TextureStepCountX;      //array for LC_FlyingObject funcs
88 int *LC_TextureStepCountY;      //array for LC_FlyingObject funcs
89 int *LC_StartDraw;              //array for LC_FlyingObject funcs
90 int *LC_StopDraw;               //array for LC_FlyingObject funcs
91 int **LC_TextureBitmapIndex;    //array for LC_FlyingObject funcs
92 unsigned short int *LC_BmpFlyingObjects;        //internal bitmap showing location of all objects MAX_NUMBER_OF_OBJECTS == 255
93 FLYINGOBJECT *LC_FlyingObject = NULL;
94 int LC_MaxRayDistance = 0;
95 int LC_WaterHeight = 0;         //determines height below which renderer blends sky pixels with ground
96 int LC_ResolutionInterval = 384;        //the distance at which resolution first gets reduced
97 int LC_FlyingObjectCount;       // max number of objects in landscape
98 int LC_TargetOrientation;
99 int LC_MissileControl;
100 int LC_UserData1;               //used to make certain data available when messages are sent
101 int LC_UserData2;               //used to make certain data available when messages are sent
102 void (*LC_pUserFunctionFast) (int message);     //fast, for sending messages in rendering loops
103 int LC_UserSky;
104 int LC_Seed;
105 int LC_BmpDestWidthCenter;
106 int LC_BmpDestHeightCenter;
107 int LC_DestLowerLeftStartPoint;
108 int LC_MaxLowerLeftStartPoint;
109 float LC_RadianToCircleRezFactor;
110 int LC_Scale;
111 int LC_Resolution;
112 int LC_TargetSpeed;
113 int LC_MissileSpeed;
114 int LC_TargetStartPos;
115 int LC_TargetSize;              //between 1 and 12. Default is 5
116 int LC_FacedTargetFlag;         //non-zero add directional mark on target
117 const double LC_SHIFTFACTOR = (1 << LC_SHIFT) * 1.0;
118 
119 //=========================================================================
120 
121 //START WITH THIS FUNCTION
122 /////////////////////////////////////////////////////////////////////
123 //void LC_LandCaster_Initialize(int *pLC_BmpDestTemp,
124 /////////////////////////////////////////////////////////////////////
LC_LandCaster_Initialize(int * pLC_BmpDestTemp,int LC_BmpDestWidthTemp,int LC_BmpDestHeightTemp,int * pLC_BmpHeightsTemp,int LC_BmpHeightsWidthTemp,int LC_BmpHeightsHeightTemp,int * pLC_BmpColorsTemp,int LC_BmpColorsWidthTemp,int LC_BmpColorsHeightTemp,int _FlyingObjectCount,int _SkySize,int seed)125 void LC_LandCaster_Initialize (int *pLC_BmpDestTemp,
126                                int LC_BmpDestWidthTemp,
127                                int LC_BmpDestHeightTemp,
128                                int *pLC_BmpHeightsTemp,
129                                int LC_BmpHeightsWidthTemp,
130                                int LC_BmpHeightsHeightTemp,
131                                int *pLC_BmpColorsTemp,
132                                int LC_BmpColorsWidthTemp,
133                                int LC_BmpColorsHeightTemp,
134                                int _FlyingObjectCount, int _SkySize, int seed)
135 {
136  LC_InitVars ();
137  LC_BmpDest.pixel = pLC_BmpDestTemp;
138  LC_BmpDest.w = LC_BmpDestWidthTemp;
139  LC_BmpDest.h = LC_BmpDestHeightTemp;
140  LC_BmpHeights.pixel = pLC_BmpHeightsTemp;
141  LC_BmpHeights.w = LC_BmpHeightsWidthTemp;
142  LC_BmpHeights.h = LC_BmpHeightsHeightTemp;
143  LC_BmpColors.pixel = pLC_BmpColorsTemp;
144  LC_BmpColors.w = LC_BmpColorsWidthTemp;
145  LC_BmpColors.h = LC_BmpColorsHeightTemp;
146  LC_Seed = seed;
147  LC_MakeSky (_SkySize);
148  LC_SetNumberOfFlyingObjects (_FlyingObjectCount);
149 
150  LC_InitLandscape ();
151 }
152 
153 /////////////////////////////////////////////////////////////////////
154 //int LC_InitLandscape()//must be called before using anything
155 /////////////////////////////////////////////////////////////////////
LC_InitLandscape()156 int LC_InitLandscape ()         //must be called before using anything
157 {
158  LC_InitFlag = 0;       //just in case LC_InitLandscape() exits early, set this low
159  //all of these must be set to do anything later:
160  if (LC_BmpColors.w < 1 || LC_BmpColors.h < 1 || LC_BmpHeights.w < 1
161      || LC_BmpHeights.h < 1 || LC_BmpDest.w < 1 || LC_BmpDest.h < 1)
162  {
163   return 0;     //user didn't initialize enough
164  }
165  LC_MaxFrameWidth =
166   (int) (sqrt
167          (LC_BmpDest.w * LC_BmpDest.w + LC_BmpDest.h * LC_BmpDest.h) + 3);
168  //if (!(LC_MaxFrameWidth%2)) ++LC_MaxFrameWidth;
169  //next line solves out of range subscript problems
170  if (LC_CircleRez < (LC_MaxFrameWidth << 1))
171   LC_CircleRez = (LC_MaxFrameWidth << 1);
172  if (LC_Direction >= LC_CircleRez)
173   LC_Direction = LC_CircleRez - (LC_CircleRez / 8);
174  LC_BmpColorsWidth_scaled = LC_BmpColors.w << LC_SHIFT;
175  LC_BmpColorsHeight_scaled = LC_BmpColors.h << LC_SHIFT;
176  LC_BmpDestWidthCenter = LC_BmpDest.w >> 1;
177  LC_BmpDestHeightCenter = LC_BmpDest.h >> 1;
178  LC_DestLowerLeftStartPoint = (LC_BmpDest.w * (LC_BmpDest.h - 1));
179  LC_MaxLowerLeftStartPoint = (LC_MaxFrameWidth * (LC_MaxFrameWidth - 1));
180  LC_RadianToCircleRezFactor =
181   (float) ((double) LC_CircleRez / 6.28318530717958647692528676655901);
182 
183  //now do allocations:
184  //since everything should equal NULL or something
185  //valid, no problem deleting... right?
186  if (LC_Sin != NULL)
187   free (LC_Sin);
188  if (LC_Cos != NULL)
189   free (LC_Cos);
190  if (LC_Correction != NULL)
191   free (LC_Correction);
192  if (LC_DistanceScaling != NULL)
193   free (LC_DistanceScaling);
194  if (LC_TextureScaling != NULL)
195   free (LC_TextureScaling);
196  if (LC_RollData != NULL)
197   free (LC_RollData);
198 
199  LC_Sin = (int *) calloc (LC_CircleRez, sizeof (int));
200  LC_Cos = (int *) calloc (LC_CircleRez, sizeof (int));
201  LC_Correction = (int *) calloc (LC_MaxFrameWidth, sizeof (int));
202  LC_DistanceScaling = (int *) calloc (LC_Raylength, sizeof (int));
203  LC_TextureScaling = (int *) calloc (LC_Raylength, sizeof (int));
204  LC_RollData = (ROLLDATA *) calloc (LC_CircleRez, sizeof (ROLLDATA));
205 
206  if (!LC_Sin || !LC_Cos || !LC_Correction || !LC_DistanceScaling
207      || !LC_TextureScaling || !LC_RollData)
208   return 0;
209 
210  if (!LC_InitTables ())
211   return 0;
212  LC_InitFlag = 1;       //did inits; set flag
213 
214  return 1;
215 }
216 
217 /////////////////////////////////////////////////////////////////////
218 // tables() - set up sin, cos, perspective, and correction tables
219 /////////////////////////////////////////////////////////////////////
LC_InitTables()220 int LC_InitTables ()
221 {
222  int i,
223   j,
224   limit = LC_CircleRez + LC_Raylength + LC_MaxFrameWidth;
225  double temp_angle;
226 
227  if (LC_CircleRez >= LC_Raylength && LC_CircleRez >= LC_MaxFrameWidth)
228   limit = LC_CircleRez;
229  if (LC_Raylength >= LC_CircleRez && LC_Raylength >= LC_MaxFrameWidth)
230   limit = LC_Raylength;
231  if (LC_MaxFrameWidth >= LC_Raylength && LC_MaxFrameWidth >= LC_CircleRez)
232   limit = LC_MaxFrameWidth;
233 
234  for (i = 0; i < limit; i++)
235  {
236   if (i < LC_CircleRez)
237   {     //start all less that LC_CircleRez
238    temp_angle = (2.0 * M_PI * (LC_CircleRez - i)) / LC_CircleRez;
239    //above makes LC_CircleRez equate with radians
240    LC_Cos[i] = (int) (LC_SHIFTFACTOR * cos (temp_angle));
241    LC_Sin[i] = (int) (LC_SHIFTFACTOR * sin (temp_angle));
242 
243    //Now I load the LC_Roll tables
244    //Cos is conventionally associated with X, Sin with Y. if LC_Roll = 0, then I want to do
245    //a straight (literally) x=0, y=1 copy of pMaxBitmap to LC_BmpDest. But Sin(0)=0, and
246    //Cos(0)=1, so trying to copy like this would have me moving across X on pMaxBitmap
247    //while making Y columns on LC_BmpDest. To correct this, I need to rotate the LC_Roll variable
248    //in my setup of the tables 1/4 turn so that when LC_Roll=0, Sin gives me 0 and Cos gives 1.
249    //also keep in mind that it is arbitrary that I use LC_CircleRez for LC_Roll.
250    LC_RollData[i].StartX =
251     (int) (((LC_BmpDest.w << (LC_SHIFT - 1)) -
252             (sin (temp_angle) * (LC_SHIFTFACTOR / 2.0) * LC_MaxFrameWidth)) +
253            (cos (temp_angle) * (LC_SHIFTFACTOR / 2.0) * LC_MaxFrameWidth));
254    LC_RollData[i].StartY =
255     (int) (((LC_BmpDest.h << (LC_SHIFT - 1)) -
256             (cos (temp_angle) * (LC_SHIFTFACTOR / 2.0) * LC_MaxFrameWidth)) -
257            (sin (temp_angle) * (LC_SHIFTFACTOR / 2.0) * LC_MaxFrameWidth));
258    //the following is simply an algebraic simplification of above. Not sure why it is right, incidentally
259    //int StartPointX=(int)((LC_BmpDest.h<<(LC_SHIFT-1))+(cos(temp_angle)-sin(temp_angle))*(LC_SHIFTFACTOR/2.0)*FrameSize*0.7);
260    //int StartPointY=(int)((LC_BmpDest.w <<(LC_SHIFT-1))-(sin(temp_angle)+cos(temp_angle))*(LC_SHIFTFACTOR/2.0)*FrameSize*0.7);
261 
262    //The following section gives a specific X start point for rendering
263    //according to how much LC_Roll  is present. Not required, just helps. Its sole reason for
264    //existing: to cut down on wasted (not used) rendering to the sides of MaxBitmap-
265    //stuff that would never get seen when transfered to LC_BmpDest.
266    //It works by comparing all four corners of the cookie-cut of the screen
267    //at the given LC_Roll i, and uses the one closest to the left for
268    //start point reference for that given LC_Roll.
269    j =
270     ((LC_MaxFrameWidth << (LC_SHIFT - 1)) -
271      (-LC_Sin[i] * LC_BmpDestHeightCenter)) -
272     (LC_Cos[i] * LC_BmpDestWidthCenter);
273 
274    if (j >
275        ((LC_MaxFrameWidth << (LC_SHIFT - 1)) -
276         (-LC_Sin[i] * LC_BmpDestHeightCenter)) +
277        (LC_Cos[i] * LC_BmpDestWidthCenter))
278     j =
279      ((LC_MaxFrameWidth << (LC_SHIFT - 1)) -
280       (-LC_Sin[i] * LC_BmpDestHeightCenter)) +
281      (LC_Cos[i] * LC_BmpDestWidthCenter);
282 
283    if (j >
284        ((LC_MaxFrameWidth << (LC_SHIFT - 1)) +
285         (-LC_Sin[i] * LC_BmpDestHeightCenter)) +
286        (LC_Cos[i] * LC_BmpDestWidthCenter))
287     j =
288      ((LC_MaxFrameWidth << (LC_SHIFT - 1)) +
289       (-LC_Sin[i] * LC_BmpDestHeightCenter)) +
290      (LC_Cos[i] * LC_BmpDestWidthCenter);
291 
292    if (j >
293        ((LC_MaxFrameWidth << (LC_SHIFT - 1)) +
294         (-LC_Sin[i] * LC_BmpDestHeightCenter)) -
295        (LC_Cos[i] * LC_BmpDestWidthCenter))
296     j =
297      ((LC_MaxFrameWidth << (LC_SHIFT - 1)) +
298       (-LC_Sin[i] * LC_BmpDestHeightCenter)) -
299      (LC_Cos[i] * LC_BmpDestWidthCenter);
300 
301    //   LC_RollData[i].endpoints=((j+511)>>LC_SHIFT);//added 511 to "round" it up. 011219
302    LC_RollData[i].endpoints = ((j + (int) ((LC_SHIFTFACTOR / 2.0) - 1)) >> LC_SHIFT);   //added 511 to "round" it up. 011219
303    //LC_RollData[i].endpoints=0;//for debugging
304 
305   }     //End all less that LC_CircleRez
306 
307   if (i < LC_Raylength)
308   {     //start all less than LC_Raylength
309    //   LC_DistanceScaling[i]=(int)((LC_SHIFTFACTOR/2.0)+(((1<<LC_SCALESHIFT)<<LC_SHIFT)/(i+1.0)));//64 used to be LC_Scale. Don't change.
310    //   int i_inv=LC_Raylength-i-1;
311    LC_DistanceScaling[i] = (int) (LC_Scale / (i + 1.0));
312    //   LC_DistanceScaling[i]=(int)(LC_Scale/(i_inv+1.0));
313    if (0 == LC_DistanceScaling[i])
314     LC_DistanceScaling[i] = 1;
315    LC_TextureScaling[i] = (1 << LC_DOUBLESHIFT) / LC_DistanceScaling[i];
316   }     //end all less than LC_Raylength
317  }      //end major loop
318 
319  //now do correction table:
320  LC_InitCorrectionTable ();
321  return 1;
322 }
323 
324 /////////////////////////////////////////////////////////////////////
325 // LC_InitCorrectionTable() - does 1/cos correction for LC_Roll scenario
326 /////////////////////////////////////////////////////////////////////
LC_InitCorrectionTable()327 int LC_InitCorrectionTable ()
328 {
329  int i;
330  for (i = 0; i < LC_MaxFrameWidth; i++)
331  {      //start fisheye-correction
332   //below:figure angles from half-screen_width left and right of my POV
333   LC_Correction[i] =
334    (int) (0.5 +
335           ((LC_Resolution << LC_SHIFT) /
336            cos (((2.0 * M_PI * i) / LC_CircleRez) -
337                 ((2.0 * M_PI * 0.5 * LC_MaxFrameWidth) / LC_CircleRez))));
338  }      //end fisheye correction
339  //next equation figures longest possible *distance* to throw ray
340  //with the available LC_Raylength number of *steps*. The shortest
341  //distance is what I want to know, so I don't go over the subscript
342  //range for it. Hence, I multiply the middle ray's step length by
343  //the number of steps my subscrript allows for (LC_Raylength-1).
344  LC_MaxRayDistance =
345   (int) ((LC_Raylength - 1) * LC_Correction[LC_MaxFrameWidth >> 1]);
346  LC_Tilt = LC_MaxFrameWidth >> 1;
347  return 1;
348 }
349 
350 /////////////////////////////////////////////////////////////////////
351 // LC_LandscapeRollSkyFlyingObjects() - 021024 - THE MAIN RENDERING ROUTINE
352 /////////////////////////////////////////////////////////////////////
LC_LandscapeRollSkyFlyingObjects()353 void LC_LandscapeRollSkyFlyingObjects ()
354 {
355  LC_DoFlyingObjectsMovement ();
356 
357  //debug lines:
358  //static int Bilbo = 0;
359  //LC_SetRoll (Bilbo += 100);
360  //if (Bilbo > 2559)
361  // Bilbo = 0;
362 
363  //FrameSize is the Width and Height to be false-rendered around LC_BmpDest
364  //if you make it LC_MaxFrameWidth, you can be sure it will correctly
365  //render every roll. it could be dynamic, changing each frame - but a major
366  //problem arises from a different effective "tilt" and sky placement for
367  //each setting.
368  //First prepare all the vars:
369  int HStepX = -LC_Cos[LC_Roll]; //0 degrees is now to the right
370  int HStepY = -LC_Sin[LC_Roll]; //0 degrees is now to the right
371  int VStepX = LC_Sin[LC_Roll];
372  int VStepY = -LC_Cos[LC_Roll];
373  int OldDrawPointY = 0;
374  int OldDrawPointX = 0;
375  //if (LC_Altitude<LC_WaterHeight) LC_Altitude=LC_WaterHeight;
376 
377  ////////////////
378  //now set up Dynamic X
379  int FrameSize = LC_MaxFrameWidth;
380  int xend = LC_RollData[LC_Roll].endpoints;     //variable startpoint for x, depending on roll
381  int x = FrameSize - xend;
382  //end Dynamic X
383 
384  //this next is used instead of a LC_Roll lookup entry:020119
385  //double temp_angle=(2.0*LC_PI*(LC_CircleRez-LC_Roll))/LC_CircleRez;
386  //int StartPointX=(int)(((LC_BmpDest.w <<(LC_SHIFT-1))-(sin(temp_angle)*(LC_SHIFTFACTOR/2.0)*FrameSize))+(cos(temp_angle)*(LC_SHIFTFACTOR/2.0)*FrameSize));
387  //int StartPointY=(int)(((LC_BmpDest.h<<(LC_SHIFT-1))-(cos(temp_angle)*(LC_SHIFTFACTOR/2.0)*FrameSize))-(sin(temp_angle)*(LC_SHIFTFACTOR/2.0)*FrameSize));
388  //the following is simply an algebraic simplification of above. Don't know why it is right, incidentally
389  // int StartPointX=(int)((LC_BmpDest.h<<(LC_SHIFT-1))+(cos(temp_angle)-sin(temp_angle))*(LC_SHIFTFACTOR/2.0)*FrameSize*0.7);
390  // int StartPointY=(int)((LC_BmpDest.w <<(LC_SHIFT-1))-(sin(temp_angle)+cos(temp_angle))*(LC_SHIFTFACTOR/2.0)*FrameSize*0.7);
391 
392  //this is simply an all-int version, for speed:
393  //int StartPointX=(int)((LC_BmpDest.w <<(LC_SHIFT-1))-(LC_Sin[LC_Roll]*FrameSize>>1)+(LC_Cos[LC_Roll]*FrameSize>>1));
394  //int StartPointY=(int)((LC_BmpDest.h<<(LC_SHIFT-1))-(LC_Cos[LC_Roll]*FrameSize>>1)-(LC_Sin[LC_Roll]*FrameSize>>1));
395  //the following is simply an algebraic simplification of above. Don't know why it is right, incidentally
396  //int StartPointY=(LC_BmpDest.w <<(LC_SHIFT-1))-(((LC_Sin[LC_Roll]+LC_Cos[LC_Roll])*FrameSize)>>1);
397  //int StartPointX=(LC_BmpDest.h<<(LC_SHIFT-1))+(((LC_Cos[LC_Roll]-LC_Sin[LC_Roll])*FrameSize)>>1);
398  //next one includes dynamic width:
399  //int StartPointY=((LC_BmpDest.w <<(LC_SHIFT-1))-(((LC_Sin[LC_Roll]+LC_Cos[LC_Roll])*FrameSize)>>1))-HStepY*xend;
400  //int StartPointX=((LC_BmpDest.h<<(LC_SHIFT-1))+(((LC_Cos[LC_Roll]-LC_Sin[LC_Roll])*FrameSize)>>1))+HStepX*xend;
401 
402  int StartPointX = LC_RollData[LC_Roll].StartX + HStepX * xend;
403  int StartPointY = LC_RollData[LC_Roll].StartY - HStepY * xend;
404 
405  //now determine draw slope:
406  int SLOPEY,
407   SLOPEX;
408  if (StartPointY < (StartPointY - VStepY))
409   SLOPEY = LC_BmpDest.w;
410  else
411   SLOPEY = -LC_BmpDest.w;
412  if (StartPointX < (StartPointX + VStepX))
413   SLOPEX = 1;
414  else
415   SLOPEX = -1;
416 
417  //initialize sky variables:
418  int *pSkyEnd = LC_BmpSky.pixel + LC_BmpSky.w * LC_BmpSky.h;
419  int SkyX = LC_Direction - xend;
420  //SkyX is now actually on Y axis of LC_BmpSky, for speed - 020119
421  if (SkyX >= LC_BmpSky.h)
422   do
423   {
424    SkyX -= LC_BmpSky.h;
425   }
426   while (SkyX >= LC_BmpSky.h);
427  int SkyTilt = LC_Tilt;
428  if (SkyTilt >= LC_BmpSky.w)
429   do
430    SkyTilt -= LC_BmpSky.w;
431   while (SkyTilt >= LC_BmpSky.w);
432  else if (SkyTilt < 0)
433   do
434    SkyTilt += LC_BmpSky.w;
435   while (SkyTilt < 0);
436  //end sky initialization
437 
438  int height;
439  int color;
440  int holemark;
441  int draw_length;
442  //object vars:
443  int tempcount;
444  int id;
445  //end object vars
446  int x_offset;
447  //******Start X******
448  do     // x is the number of rays I send
449  {
450   int y = 0;                    //needed for array indexing
451   int yinc = 1;
452   int y_distance = 0;
453   int y_distance_step = LC_Correction[x];
454   int y_origdiststep = y_distance_step;
455 
456   int top_height = FrameSize;
457   int DrawPointX = StartPointX; //go to bottom of screen to start line
458   int DrawPointY = StartPointY; //go to bottom of screen to start line
459   int *pScreenIndex = 0;
460   int DrawFlag = 0;             //every object pixel that gets hit advances this arrays-subscript
461   int DrawCount = 0;
462   int OldFlyingObjectPixel = -1;        //make sure I treat first pass freshly
463   //next line starts my first column on the left side of screen
464   if ((x_offset = LC_Direction - (FrameSize >> 1) + x) >= LC_CircleRez)
465    x_offset -= LC_CircleRez;
466   else if (x_offset < 0)
467    x_offset += LC_CircleRez;
468   int x_step = (LC_Cos[x_offset] * LC_Correction[x]) >> LC_DOUBLESHIFT;
469   int x_origstep = x_step;
470   int y_step = (LC_Sin[x_offset] * LC_Correction[x]) >> LC_DOUBLESHIFT;
471   int y_origstep = y_step;
472   int x_int = LC_PositionX;
473   int y_int = LC_PositionY;
474 
475   int *pSkyStart = LC_BmpSky.w * SkyX + LC_BmpSky.pixel + SkyTilt;
476   if (pSkyStart >= pSkyEnd)
477    do
478     pSkyStart -= LC_BmpSky.h;
479    while (pSkyStart >= pSkyEnd);
480   else if (pSkyStart < LC_BmpSky.pixel)
481    do
482     pSkyStart += LC_BmpSky.h;
483    while (pSkyStart < LC_BmpSky.pixel);
484   //////////////////////////////////////
485   //******Start Y********
486   do
487   {
488    if ((y_int += y_step) < 0)
489    {
490     y_int += LC_BmpColorsHeight_scaled;
491     OldFlyingObjectPixel = -1;
492    }
493    else if (y_int >= LC_BmpColorsHeight_scaled)
494    {
495     y_int -= LC_BmpColorsHeight_scaled;
496     OldFlyingObjectPixel = -1;  //necessary for doing multiple instances properly
497    }
498    if ((x_int += x_step) < 0)
499    {
500     x_int += LC_BmpColorsWidth_scaled;
501     OldFlyingObjectPixel = -1;
502    }
503    else if (x_int >= LC_BmpColorsWidth_scaled)
504    {
505     x_int -= LC_BmpColorsWidth_scaled;
506     OldFlyingObjectPixel = -1;
507    }
508 
509    //#########start PRE DRAW ########## Predraw loads drawing arrays.
510    //the point of this: Drawing objects is still about drawing landscape, but
511    //with the slight difference of checking the Start and Stop arrays
512    //to see if the point at which I am drawing on the screen should
513    //draw an object instead of land
514    //Note: color was just handy to use temporarily here to hold raw bitmap subscript:
515    //get bitmap position:
516    int data_index =
517     (y_int >> LC_SHIFT) * LC_BmpHeights.w + (x_int >> LC_SHIFT);
518    //make sure I'm not just hitting the same object pixel again and if not,
519    //get the column data (if any) from LC_BmpFlyingObjects and reference it to the texture:
520    if (data_index != OldFlyingObjectPixel &&
521        (LC_TextureStepCountY[DrawFlag] = LC_BmpFlyingObjects[data_index]))
522    {    //it wasn't the same pixel again, and there was data on that pixel, so:
523     //remember this subscript for next pass:
524     OldFlyingObjectPixel = data_index;
525     //    id=LC_TextureStepCountY[DrawFlag]>>6;//for int LC_BmpFlyingObjects (3 objects max)
526     id = LC_TextureStepCountY[DrawFlag] >> 8;   //for unsigned short int LC_BmpFlyingObjects
527     //get the column of the object's texture bmp:
528     //note- I subtract 1 from next because column data is coded +1 so column
529     //zero is discernable from background zeros.
530     //i.e., so I don't lose a column (column 1 is 0)
531     //    LC_TextureStepCountY[DrawFlag]=(LC_TextureStepCountY[DrawFlag]&63)-1;//for uchar bitmap
532     LC_TextureStepCountY[DrawFlag] = (LC_TextureStepCountY[DrawFlag] & 255) - 1;        //for short bitmap
533 
534     //get scaled step size for walking over the texture bmp:
535     LC_TextureStepX[DrawFlag] = LC_TextureScaling[y_distance >> LC_YSHIFT];
536 
537     //get the absolute screen height of the bottom of the object:
538     LC_StartDraw[DrawFlag] = FrameSize - LC_Tilt - (((LC_Altitude - LC_FlyingObject[id].Alt) * LC_DistanceScaling[y_distance >> LC_YSHIFT]) >> LC_SHIFT);       //020202
539     //now get the end screen height for the object column by adding scaled object sizeX:
540     LC_StopDraw[DrawFlag] = LC_StartDraw[DrawFlag] + ((LC_FlyingObject[id].SizeX * LC_DistanceScaling[y_distance >> LC_YSHIFT]) >> LC_SHIFT);   //020202
541 
542     //reset texture step to zero to get ready to begin walking the texture
543     LC_TextureStepCountX[DrawFlag] = 0;
544     //set my handy index pointer to the exact place in the texture bitmap
545     //that the object bitmap starts drawing from:
546     LC_TextureBitmapIndex[DrawFlag] = LC_FlyingObject[id].pTextureBitmap + (LC_TextureStepCountY[DrawFlag] * LC_FlyingObject[id].SizeX);        //don't forget this
547     ++DrawFlag;
548     //increment drawflag, to keep total count of object parts I need to draw
549     //in next part, and to get it ready to be subscript for next vars:
550     //     ++DrawFlag;
551    }
552    //#########end PRE DRAW ##########
553    //Theory of rendering is this: I don't scale anything at my altitude, but
554    //I do scale everything higher or lower than me by distince - that is, just
555    //by multiplying it by 1/distance. LC_Tilt is really screen height.
556    //In practice, the viewed height of a pixel is simply
557    //(LC_Altitude-PixelHeight)/RayStepCount, or in this program's
558    //language, height=(LC_Altitude-PixelHeight)/y
559    //here's a functional example, needing no lookup tables:
560    //height=LC_Tilt+((LC_Altitude-LC_BmpHeights.pixel[y_index*LC_BmpHeights.w+x_index])<<LC_SCALESHIFT)/++y;
561    //Now here's what I use with Lookup tables:
562    //height=LC_Tilt+((LC_Altitude-LC_BmpHeights.pixel[data_index])<<LC_SCALESHIFT)/(++y);
563    if ((height =
564         LC_Tilt +
565         (((LC_Altitude -
566            LC_BmpHeights.pixel[data_index]) *
567           LC_DistanceScaling[y_distance >> LC_YSHIFT]) >> LC_SHIFT)) < 0)
568    {
569     y_distance = LC_MaxRayDistance;
570     height = 0;
571    }
572 
573    //////////////////////////////////////
574    //start draw landscape
575    //***here's my blazing-fast drawing algorithm:
576    if ((draw_length = top_height - height) > 0)
577    {
578     //first see if this land is wet:
579     if (LC_BmpHeights.pixel[data_index] <= LC_WaterHeight)
580     {
581      //NOTE: user must do a LC_BmpHeights.pixel[data_index]=LC_WaterHeight, or else water looks weird.
582      int *pWaterIndex = pSkyStart - top_height;
583      if (pWaterIndex < LC_BmpSky.pixel)
584       do
585        pWaterIndex += LC_BmpSky.h;
586       while (pWaterIndex < LC_BmpSky.pixel);
587      //FAST Transparency (low precision) follow:
588      //50%-50% transparency:
589      color =
590       ((LC_BmpColors.pixel[data_index] & 0xfefefe) >> 1) +
591       ((*pWaterIndex & 0xfefefe) >> 1);
592      //50%+25% transparency:
593      //if (LC_BmpHeights.pixel[data_index]<=LC_WaterHeight) color=((LC_BmpColors[data_index]&0xfefefe)>>1)+((*pWaterIndex&0xfcfcfc)>>2);
594      //if (LC_BmpHeights.pixel[data_index]<=LC_WaterHeight) color=((LC_BmpColors[data_index]&0xfcfcfc)>>2)+((*pWaterIndex&0xfefefe)>>1);
595      //NO Transparency:
596      //if (LC_BmpHeights.pixel[data_index]<=LC_WaterHeight) color=*(pWaterIndex++);
597     }
598     else
599     {
600      color = LC_BmpColors.pixel[data_index];
601     }
602     top_height = height;        //not sure if this should be put here or above
603     do
604     {
605      if (DrawPointX > 0 && DrawPointY > 0 &&
606          (DrawPointX >> LC_SHIFT) < LC_BmpDest.w &&
607          (DrawPointY >> LC_SHIFT) < LC_BmpDest.h)
608      {
609       holemark = 2;     //holemark here for consistency with sky, where there had been a bug 020212
610       //see if first time entering drawing plane:
611       if (!pScreenIndex)
612       {
613        OldDrawPointY = (DrawPointY >> LC_SHIFT);
614        OldDrawPointX = (DrawPointX >> LC_SHIFT);
615        pScreenIndex =
616         LC_BmpDest.pixel + OldDrawPointY * LC_BmpDest.w + OldDrawPointX;
617       }
618       else
619       { //I am within drawing zone
620        //first of all, get pScreenIndex to the right position:
621        if (OldDrawPointY != (DrawPointY >> LC_SHIFT))
622        {
623         --holemark;
624         pScreenIndex += SLOPEY;
625         OldDrawPointY = (DrawPointY >> LC_SHIFT);
626        }
627        if (OldDrawPointX != (DrawPointX >> LC_SHIFT))
628        {
629         --holemark;
630         OldDrawPointX = (DrawPointX >> LC_SHIFT);
631         pScreenIndex += SLOPEX;
632        }
633        //pScreenIndex is now ready to be written to
634        //Now start test-for-object rendering section:
635        if (DrawFlag)
636        {        //Start Major If
637         tempcount = 0;
638         do
639         {
640          //Case 1:if within the window for an object, draw a pixel of the object:
641          if (DrawCount < LC_StopDraw[tempcount] &&
642              DrawCount >= LC_StartDraw[tempcount])
643          {      //it was within the window:
644           if (DrawCount > LC_StartDraw[tempcount])
645           {     //increment texture by how much gets skipped:
646            LC_TextureStepCountX[tempcount] += LC_TextureStepX[tempcount] * (((DrawCount - LC_StartDraw[tempcount])) - 1);       //011217
647            //increment LC_StartDraw one step beyond current screenindex:
648            LC_StartDraw[tempcount] = DrawCount + 1;     //011217
649           }     //StartDraw right at the bottom of window, so just move it up one
650           else
651            ++LC_StartDraw[tempcount];   //011217
652 
653           //now, assign color to destbmp and test transparency:
654           if ((*pScreenIndex =
655                *(LC_TextureBitmapIndex[tempcount] +
656                  (LC_TextureStepCountX[tempcount] >> LC_SHIFT))))
657           {     //not transparent, so advance to next texture pixel:
658            LC_TextureStepCountX[tempcount] += LC_TextureStepX[tempcount];
659            if (!holemark)
660             *(pScreenIndex - SLOPEX) = *pScreenIndex;
661            //this break is all-important, for many reasons. Most important:
662            //it makes sure this closer object doesn't get written on
663            //later by a more distant object on this ray.
664            break;       //!!!!!!!
665           }
666           else
667           {     //it is transparent, so re-assign pixel value:
668            //Next tempcount may draw here, in case another
669            //object is visible inside the closer (wow).
670            *pScreenIndex = color;       //too bad I must do this repeatedly...
671            if (!holemark)
672             *(pScreenIndex - SLOPEX) = *pScreenIndex;
673            LC_TextureStepCountX[tempcount] += LC_TextureStepX[tempcount];
674           }
675          }
676          else
677          {      //case 2: object here, but no pixels within screen start/stop, so just draw stuff
678           //below or above object, sort of like any other Landscape()
679           *pScreenIndex = color;
680           if (!holemark)
681            *(pScreenIndex - SLOPEX) = *pScreenIndex;
682          }      //got to check all objects every time! "break" above saves many cycles
683         }
684         while (++tempcount < DrawFlag);
685        }        //case 3: no object around, draw at will
686        //end test for object rendering section
687        else
688         //start normal landscape rendering section:
689        {
690         *pScreenIndex = color;
691         if (!holemark)
692          *(pScreenIndex - SLOPEX) = color;      //0xffff;
693        }
694        //end normal landscape rendering section
695       }
696      }
697      //next else works on principle that after entering window, exiting
698      //at any point means done with ray:
699      else if (pScreenIndex)
700      {
701       draw_length = 0;
702       top_height = 0;
703       y_distance = LC_MaxRayDistance;
704      }
705      DrawPointX += VStepX;
706      DrawPointY -= VStepY;
707      ++DrawCount;
708     }
709     while (--draw_length > 0);
710    }    //end draw_length if
711    //***end of new, fast drawing algorithm!
712    //end draw landscape
713    if ((y += yinc) > LC_ResolutionInterval)
714    {
715     y = 0;
716     yinc++;
717     x_step += x_origstep;
718     y_step += y_origstep;
719     y_distance_step += y_origdiststep;
720    }
721 
722    //////////////////////////////////////
723    //Decrement ray yardstick:
724   }
725   while ((y_distance += y_distance_step) < LC_MaxRayDistance);  //length I cast the ray
726   //********End Y**********
727   //////////////////////////////////////
728 
729   /////////////////////
730   //start sky
731   //   pSkyStart=LC_BmpSky.w*SkyX+LC_BmpSky.pixel+SkyTilt-top_height;
732   pSkyStart -= top_height;
733   //   if (pSkyStart>=pSkyEnd) do pSkyStart-=LC_BmpSky.h; while (pSkyStart>=pSkyEnd); else
734   //    if (pSkyStart<LC_BmpSky.pixel) do pSkyStart+=LC_BmpSky.h; while (pSkyStart<LC_BmpSky.pixel);
735   if (pSkyStart < LC_BmpSky.pixel)
736    do
737     pSkyStart += LC_BmpSky.h;
738    while (pSkyStart < LC_BmpSky.pixel);
739 
740   while (--top_height > 0)
741   {
742    if (DrawPointX > 0 && DrawPointY > 0 &&
743        (DrawPointX >> LC_SHIFT) < LC_BmpDest.w &&
744        (DrawPointY >> LC_SHIFT) < LC_BmpDest.h)
745    {
746     holemark = 2;       //putting holemark here solved bug - 020212
747     //see if first time entering drawing plane:
748     if (!pScreenIndex)
749     {
750      OldDrawPointY = (DrawPointY >> LC_SHIFT);
751      OldDrawPointX = (DrawPointX >> LC_SHIFT);
752      pScreenIndex =
753       LC_BmpDest.pixel + OldDrawPointY * LC_BmpDest.w + OldDrawPointX;
754     }
755     else
756     {
757      if (OldDrawPointY != (DrawPointY >> LC_SHIFT))
758      {
759       OldDrawPointY = (DrawPointY >> LC_SHIFT);
760       --holemark;
761       pScreenIndex += SLOPEY;
762      }
763      if (OldDrawPointX != (DrawPointX >> LC_SHIFT))
764      {
765       --holemark;
766       OldDrawPointX = (DrawPointX >> LC_SHIFT);
767       pScreenIndex += SLOPEX;
768      }
769     }
770     //Now start test-for-object rendering section:
771     if (DrawFlag)
772     {   //Start Major If
773      tempcount = 0;
774      do
775      {
776       //Case 1:if within the window for an object, draw a pixel of the object:
777       if (DrawCount < LC_StopDraw[tempcount] &&
778           DrawCount >= LC_StartDraw[tempcount])
779       { //it was within the window:
780        if (DrawCount > LC_StartDraw[tempcount])
781        {        //increment texture by how much gets skipped:
782         LC_TextureStepCountX[tempcount] += LC_TextureStepX[tempcount] * (((DrawCount - LC_StartDraw[tempcount])) - 1);  //011217
783         //increment LC_StartDraw one step beyond current screenindex:
784         LC_StartDraw[tempcount] = DrawCount + 1;        //011217
785        }        //StartDraw right at the bottom of window, so just move it up one
786        else
787         ++LC_StartDraw[tempcount];      //011217
788 
789        //now, assign color to destbmp and test transparency:
790        if ((*pScreenIndex =
791             *(LC_TextureBitmapIndex[tempcount] +
792               (LC_TextureStepCountX[tempcount] >> LC_SHIFT))))
793        {        //not transparent, so advance to next texture pixel:
794         LC_TextureStepCountX[tempcount] += LC_TextureStepX[tempcount];
795         if (!holemark)
796          *(pScreenIndex - SLOPEX) = *pScreenIndex;
797         //this break is all-important, for many reasons. Most important:
798         //it makes sure this closer object doesn't get written on
799         //later by a more distant object on this ray.
800         break;
801        }
802        else
803        {        //it is transparent, so re-assign pixel value:
804         //Next tempcount may draw here, in case another
805         //object is visible inside the closer (wow).
806         *pScreenIndex = *pSkyStart;     //too bad I must do this repeatedly...
807         if (!holemark)
808          *(pScreenIndex - SLOPEX) = *pScreenIndex;
809         LC_TextureStepCountX[tempcount] += LC_TextureStepX[tempcount];
810        }
811       }
812       else
813       { //case 2: object here, but no pixels within screen start/stop, so just draw stuff
814        //below or above object, sort of like any other Landscape()
815        *pScreenIndex = *pSkyStart;
816        if (!holemark)
817         *(pScreenIndex - SLOPEX) = *pScreenIndex;
818       } //got to check all objects every time! "break" above saves many cycles
819      }
820      while (++tempcount < DrawFlag);
821     }   //case 3: no object around, draw at will
822     //end test for object rendering section
823     else
824     {
825      *pScreenIndex = *pSkyStart;
826      if (!holemark)
827       *(pScreenIndex - SLOPEX) = *pSkyStart;
828     }
829    }
830    //following based on principle that after entering, exiting means done:
831    else if (pScreenIndex)
832     break;
833    DrawPointX += VStepX;
834    DrawPointY -= VStepY;
835    ++DrawCount;
836    if (++pSkyStart >= pSkyEnd)
837     pSkyStart -= LC_BmpSky.w;
838   }
839   if (--SkyX < 0)
840    SkyX += LC_BmpSky.h;
841   //end sky
842   ////////////////////////
843 
844   StartPointX += HStepX;
845   StartPointY -= HStepY;
846   // }while (--x>-1); // end x
847  }
848  while (--x > xend);    // end x
849  //*************end X**************
850 }       // end LC_LandscapeRollSkyFlyingObjects() - 021024
851 
852 ///////////////////////////////////////////////////////////////////////
853 
854 /////////////////////////////////////////////////////////////////////
855 // int LC_SetLC_Raylength(int length)
856 /////////////////////////////////////////////////////////////////////
LC_SetLC_Raylength(int length)857 int LC_SetLC_Raylength (int length)
858 {
859  static int old_length = LC_STARTING_RAYLENGTH;
860 
861  //next line is to deal with a discovery that
862  //bigger raylengths fail for some reason. need to figure out why.
863  if (LC_FlyingObjectCount && length > 4150)
864   length = 4140;
865 
866  //I have no data to suggest next line actually
867  //has a reference; but 40 does work.
868  if (length < 40)
869   length = 40;
870 
871  if (LC_Raylength == length)
872   return 1;     //keep this
873 
874  LC_Raylength = length;
875  if (!LC_InitLandscape ())
876  {
877   LC_Raylength = old_length;
878   LC_InitLandscape ();
879   return 0;
880  }
881  old_length = LC_Raylength;
882  return 1;
883 }
884 
885 /////////////////////////////////////////////////////////////////////
886 // int LC_SetNumberOfFlyingObjects(int number_of_objects)
887 /////////////////////////////////////////////////////////////////////
LC_SetNumberOfFlyingObjects(int number_of_objects)888 int LC_SetNumberOfFlyingObjects (int number_of_objects)
889 {
890  LC_DeleteFlyingObjectsResources ();    //redundant, but must do before I change LC_FlyingObjectCount()
891 
892  LC_FlyingObjectCount = number_of_objects;
893  if (LC_FlyingObjectCount < 1)
894   LC_FlyingObjectCount = 1;
895  if (LC_FlyingObjectCount > 254)
896   LC_FlyingObjectCount = 254;
897 
898  LC_SetLC_Raylength (LC_Raylength);     //to make sure it isn't too long or FlyingObjects
899  //I've rewritten so that I don't need to call initlandscape() with objects
900  // if (!LC_InitLandscape()) return 0;//LC_InitLandscape() calls LC_CreateFlyingObjectsResources(),
901  if (LC_FlyingObjectCount)
902  {
903   if (!LC_SkyFlag)
904    if (!LC_SetSkyFlag (1))
905     return 0;
906   if (!LC_CreateFlyingObjectsResources ())
907    return 0;
908  }
909  return 1;
910 }
911 
912 /////////////////////////////////////////////////////////////////////
913 // int LC_SetSkyFlag(int state)
914 /////////////////////////////////////////////////////////////////////
LC_SetSkyFlag(int state)915 int LC_SetSkyFlag (int state)
916 {
917  LC_SkyFlag = state;
918  if (LC_SkyFlag && !LC_BmpSky.pixel)
919  {
920   LC_MakeSky (8);
921   return 0;
922  }
923  return 1;
924 }
925 
926 /////////////////////////////////////////////////////////////////////
927 // int LC_CreateFlyingObjectsResources(void)
928 /////////////////////////////////////////////////////////////////////
929 //This is not called directly- LC_SetNumberOfFlyingObjects() must be called,
930 //which then calls LC_InitLandscape();
LC_CreateFlyingObjectsResources(void)931 int LC_CreateFlyingObjectsResources (void)
932 {
933  int i;
934 
935  LC_DeleteFlyingObjectsResources ();    //in case there were any
936  i = 1024;
937  //if (i<LC_Raylength) i=LC_Raylength;//you don't want to run under, but it almost never gets
938  //over 600.
939 
940  //next allot arrays:
941  //this is the landscape FlyingObjects trot along on:
942  LC_BmpFlyingObjects =
943   (unsigned short int *) calloc (LC_BmpHeights.w * LC_BmpHeights.h,
944                                  sizeof (unsigned short int));
945  //following 6 arrays are all part of CLandcaster's internal
946  //drawing machinery:
947  LC_TextureStepX = (int *) calloc (i, sizeof (int));
948  LC_TextureStepCountX = (int *) calloc (i, sizeof (int));
949  LC_TextureStepCountY = (int *) calloc (i, sizeof (int));
950  LC_StartDraw = (int *) calloc (i, sizeof (int));
951  LC_StopDraw = (int *) calloc (i, sizeof (int));
952  LC_TextureBitmapIndex = (int **) calloc (i, sizeof (int *));
953  //Biggie array follows - OBJECT it calls the constructors
954  //individually for all objects created:
955  LC_FlyingObject =
956   (FLYINGOBJECT *) calloc (LC_FlyingObjectCount, sizeof (FLYINGOBJECT));
957 
958  if (!LC_BmpFlyingObjects || !LC_TextureStepX || !LC_TextureStepCountX ||
959      !LC_TextureStepCountY || !LC_StartDraw || !LC_StopDraw
960      || !LC_TextureBitmapIndex || !LC_FlyingObject)
961  {
962   LC_DeleteFlyingObjectsResources ();
963   return 0;
964  }
965 
966  //Set FlyingObjects to some default values:
967  for (i = 0; i < LC_FlyingObjectCount; i++)
968   LC_FlyingObjectConstructor (&LC_FlyingObject[i]);
969 
970  //clear FlyingObjectBitmap array:
971  for (i = 0; i < (LC_BmpHeights.w * LC_BmpHeights.h); i++)
972  {
973   LC_BmpFlyingObjects[i] = 0;
974  }
975 
976  //Next line creates arbitrary objects, just so there is something in
977  //the arrays if User fails to provide their own object creation
978  if (LC_FlyingObjectCount)
979   LC_CreateSomeFlyingObjects ();
980  return 1;
981 }
982 
983 /////////////////////////////////////////////////////////////////////
984 //MUST CALL LC_SetNumberOfFlyingObjects FIRST!!
985 //makes default objects- one harpoon and LC_FlyingObjectCount-1 targets
986 //user can use LC_SetupFlyingObject() to modify default objects
987 //note- in default, user's harpoon is always at object[0]
988 /////////////////////////////////////////////////////////////////////
LC_CreateSomeFlyingObjects()989 int LC_CreateSomeFlyingObjects ()
990 {
991  int posx = 0,
992   posy = 0,
993   dir = 0,
994   i;
995 
996  for (i = 0; i < LC_FlyingObjectCount; i++)
997  {
998   if (i > 0)
999   {
1000    switch (LC_TargetStartPos)
1001    {
1002    case LC_CHANCE:
1003     posx = rand () % LC_BmpColors.w;
1004     posy = rand () % LC_BmpColors.h;
1005     dir = rand () % LC_CircleRez;
1006     if (posx < 0)
1007      posx += LC_BmpColors.w;
1008     else if (posx >= LC_BmpColors.w)
1009      posx -= LC_BmpColors.w;
1010     if (posy < 0)
1011      posy += LC_BmpColors.h;
1012     else if (posy >= LC_BmpColors.h)
1013      posy -= LC_BmpColors.h;
1014     if (dir < 0)
1015      dir += LC_CircleRez;
1016     else if (dir >= LC_CircleRez)
1017      dir -= LC_CircleRez;
1018     break;
1019 
1020    case LC_LINEDUP:
1021     switch (LC_TargetOrientation)
1022     {
1023     case LC_SKINNY:
1024      posx = posy = 0;
1025      //     dir=LC_CircleRez+((LC_FlyingObjectCount>>1)-i);
1026      dir = i;
1027      if (dir < 0)
1028       dir += LC_CircleRez;
1029      else if (dir >= LC_CircleRez)
1030       dir -= LC_CircleRez;
1031      break;
1032 
1033     case LC_SIDEWAYS:
1034      if ((posx -= 7) < 0)
1035       posx += LC_BmpColors.w;
1036      dir = 10;
1037      break;
1038 
1039     case LC_FACING:
1040      if ((posx -= 17) < 0)
1041       posx += LC_BmpColors.w;
1042      dir = 20;
1043      break;
1044 
1045     default:
1046      if ((posx -= 17) < 0)
1047       posx += LC_BmpColors.w;
1048      dir = 20;
1049      break;
1050     }
1051     break;
1052 
1053    default:
1054     posx = rand () % LC_BmpColors.w;
1055     posy = rand () % LC_BmpColors.h;
1056     dir = rand () % LC_CircleRez;
1057     if (posx < 0)
1058      posx += LC_BmpColors.w;
1059     else if (posx >= LC_BmpColors.w)
1060      posx -= LC_BmpColors.w;
1061     if (posy < 0)
1062      posy += LC_BmpColors.h;
1063     else if (posy >= LC_BmpColors.h)
1064      posy -= LC_BmpColors.h;
1065     if (dir < 0)
1066      dir += LC_CircleRez;
1067     else if (dir >= LC_CircleRez)
1068      dir -= LC_CircleRez;
1069     break;
1070    }
1071    LC_SetupFlyingObject (i, LC_TARGET, posx, posy, LC_TargetSpeed, 300, dir,
1072                          0, LC_VISIBLE, 0, 0, 0, NULL, 0, 0);
1073   }
1074   else
1075   {
1076    LC_SetupFlyingObject (i, LC_MISSILE, 0, 0, LC_MissileSpeed, 300, 0, 0,
1077                          LC_VISIBLE, 0, 0, 0, NULL, 0, 0);
1078   }
1079  }
1080  return 1;
1081 }
1082 
1083 /////////////////////////////////////////////////////////////////////
1084 // NOTE: LC_SetNumberOfFlyingObjects(int number_of_objects)
1085 //  must be called before anything!
1086 /////////////////////////////////////////////////////////////////////
LC_SetupFlyingObject(int id,int type,int x,int y,int altitude,int speed,int direction,int turn,int visible,unsigned char red,unsigned char green,unsigned char blue,int * pFlyingObjectBitmapTemp,int FlyingObjectBitmapWidthTemp,int FlyingObjectBitmapHeightTemp)1087 int LC_SetupFlyingObject (int id,       //the only required parameter
1088                           int type, int x, int y, int altitude, int speed, int direction, int turn, int visible, unsigned char red, unsigned char green, unsigned char blue, int *pFlyingObjectBitmapTemp,      //optional - can leave empty
1089                           int FlyingObjectBitmapWidthTemp,      // optional - can leave empty
1090                           int FlyingObjectBitmapHeightTemp)     // optional - can leave empty
1091 {
1092  int erasex;                    //041025 added to fix SizeY-erasure bug
1093  if (!(red + green + blue))
1094  {
1095   do
1096   {
1097    red = rand () % 256;
1098    green = rand () % 256;
1099    blue = rand () % 256;
1100   }
1101   while ((red + green + blue) < 200);
1102  }
1103  if (x == -1)
1104   LC_FlyingObject[id].PosX = ((rand () % LC_BmpHeights.w) << LC_SHIFT);
1105  else
1106   LC_FlyingObject[id].PosX = x << LC_SHIFT;
1107  if (y == -1)
1108   LC_FlyingObject[id].PosY = ((rand () % LC_BmpHeights.h) << LC_SHIFT);
1109  else
1110   LC_FlyingObject[id].PosY = y << LC_SHIFT;
1111  LC_FlyingObject[id].Alt = altitude;
1112  LC_FlyingObject[id].Speed = speed;
1113  LC_FlyingObject[id].Direction = direction;
1114  LC_FlyingObject[id].Type = type;
1115  LC_FlyingObject[id].Visible = visible;
1116  LC_FlyingObject[id].Turn = turn;
1117 
1118  if (pFlyingObjectBitmapTemp == NULL)
1119  {
1120   switch (type)
1121   {
1122   case LC_MISSILE:
1123    LC_MakeMissile (id, red, green, blue);
1124    break;
1125 
1126   case LC_TARGET:
1127    LC_MakeTarget (id, red, green, blue);
1128    break;
1129 
1130   default:
1131    break;
1132   }
1133   //041025 added to fix SizeY-erasure bug:
1134   erasex = LC_FlyingObject[id].SizeY;   //remember, texmaps are done sideways for speed
1135  }
1136  else   // It must be a User bitmap here, so do that:
1137  {
1138   //041025 added to fix SizeY-erasure bug:
1139   erasex = LC_FlyingObject[id].SizeY;   //remember, texmaps are done sideways for speed
1140   //if object was an *internal* bitmap before, erase it:
1141   if (LC_FlyingObject[id].bExternalBitmap == 0)
1142    free (LC_FlyingObject[id].pTextureBitmap);   // delete whatever had previously been there
1143   //definitely a user bitmap, so inform not to erase it:
1144   LC_FlyingObject[id].bExternalBitmap = 1;      //user gave me a bitmap
1145   LC_FlyingObject[id].Lift = -1;
1146   LC_FlyingObject[id].pTextureBitmap = pFlyingObjectBitmapTemp;
1147   LC_FlyingObject[id].SizeX = FlyingObjectBitmapWidthTemp;
1148   LC_FlyingObject[id].SizeY = FlyingObjectBitmapHeightTemp;
1149  }
1150  //done with determining type of object
1151  ////////////////////////////////////////////////////////
1152 
1153  //Now set up object's erasure arrays, regardless of User of Internal bmap:
1154  //First erase whatever previous object had written (if anything)
1155  if (LC_FlyingObject[id].pErase)
1156  {
1157   do
1158   {
1159    LC_BmpFlyingObjects[LC_FlyingObject[id].pErase[--erasex]] = 0;       //erase old positions
1160   }
1161   while (erasex);       //041025 bugfix
1162   //now that it is erased, I can delete it:
1163   free (LC_FlyingObject[id].pErase);    //in case one was already there
1164  }
1165 
1166  //now I allocate pErase according to SizeY:
1167  LC_FlyingObject[id].pErase = (int *) calloc (LC_FlyingObject[id].SizeY, sizeof (int)); //erasure array has been assigned!
1168  //now I zero the array:
1169  for (erasex = 0; erasex < LC_FlyingObject[id].SizeY; erasex++)
1170   LC_FlyingObject[id].pErase[erasex] = 0;
1171 
1172  return 1;
1173 }
1174 
1175 /////////////////////////////////////////////////////////////////////
1176 // int rand(int hi_limit)
1177 /////////////////////////////////////////////////////////////////////
LC_rand_hi(int hi_limit)1178 int LC_rand_hi (int hi_limit)
1179 {
1180  return rand () % (hi_limit + 1);
1181 }
1182 
1183 /////////////////////////////////////////////////////////////////////
1184 // MakeFacedTarget()
1185 /////////////////////////////////////////////////////////////////////
LC_MakeTarget(int id,unsigned char Red,unsigned char Green,unsigned char Blue)1186 int LC_MakeTarget (int id, unsigned char Red, unsigned char Green,
1187                    unsigned char Blue)
1188 {
1189  int x,
1190   y,
1191   Size = LC_TargetSize;
1192 
1193  int *Bitmap;
1194  if (Size > 12)
1195   Size = 12;    //keep factor 12 or less (for God's sake!)
1196  if (Size < 0)
1197   Size = LC_rand_hi (-Size) + 4;
1198  Size = (1 << (Size));
1199  //create bitmap, assign to globals:
1200  Bitmap = (int *) calloc (Size * Size, sizeof (int));
1201  int BitmapHeight = Size,
1202   BitmapWidth = Size;
1203  //start by making everything transparent (pixel 0)
1204  for (x = 0; x < BitmapWidth; x++)
1205  {
1206   // if (!UserFunction(x+1,BitmapWidth)) break;
1207   for (y = 0; y < BitmapHeight; y++)
1208   {
1209    Bitmap[y * BitmapWidth + x] = 0;
1210    // Bitmap[y*BitmapWidth+x]=ColorValue[id];
1211   }     //end y
1212  }      //end x
1213 
1214  int ColorValue = 0xff000000 | Red << 16 | Green << 8 | Blue;
1215  //for a small donut:
1216  LC_DumbCircle (Bitmap, BitmapWidth, BitmapWidth / 2, ColorValue,
1217                 BitmapWidth / 2 - 1, BitmapWidth / 2 - 1);
1218  LC_DumbCircle (Bitmap, BitmapWidth, BitmapWidth / 3, 0, BitmapWidth / 2 - 1,
1219                 BitmapWidth / 2 - 1);
1220  LC_DumbCircle (Bitmap, BitmapWidth, BitmapWidth / 8, ColorValue,
1221                 BitmapWidth / 2 - 1, BitmapWidth / 2 - 1);
1222  //to add a face:
1223  if (LC_FacedTargetFlag)
1224  {
1225   if (Red + Green + Blue < 640)
1226   {
1227    ColorValue = 0xffffffff;
1228   }
1229   LC_DumbCircle (Bitmap, BitmapWidth, BitmapWidth / 7, ColorValue,
1230                  BitmapWidth / 2 - 1, BitmapWidth - BitmapWidth / 8 - 1);
1231  }      //end face
1232  LC_Blur (Bitmap, BitmapWidth, BitmapHeight, 0);
1233  LC_ZeroContrast (Bitmap, BitmapWidth, BitmapHeight, 100);
1234 
1235  //done making missile, so assign bitmap and its parameters to object:
1236  LC_FlyingObject[id].pTextureBitmap = Bitmap;
1237  LC_FlyingObject[id].SizeX = Size;
1238  LC_FlyingObject[id].SizeY = Size;
1239  LC_FlyingObject[id].Type = LC_TARGET;
1240  LC_FlyingObject[id].Speed = LC_TargetSpeed;
1241  LC_FlyingObject[id].Lift = -1;
1242  return 1;      //bogus for now
1243 }
1244 
1245 /////////////////////////////////////////////////////////////////////
1246 // LC_ZeroContrast- just zero's any pixel summing under zero_thresh
1247 /////////////////////////////////////////////////////////////////////
LC_ZeroContrast(int * OrigBitmap,int width,int height,int zero_thresh)1248 void LC_ZeroContrast (int *OrigBitmap, int width, int height, int zero_thresh)
1249 {
1250  int color,
1251   y,
1252   x;
1253  for (x = 0; x < width; x++)
1254  {      //start x
1255   for (y = 0; y < height; y++)
1256   {     //start y
1257    color = LC_pixelget (OrigBitmap, x, y, width);
1258    color = ((color >> 16) & 0xff) + ((color >> 8) & 0xff) + (color & 0xff);
1259    if (color < zero_thresh)
1260     LC_pixelput (OrigBitmap, x, y, 0x00000000, width);
1261   }     //y end
1262  }      //x end
1263 }       //end LC_ZeroContrast()
1264 
1265 /////////////////////////////////////////////////////////////////////
1266 // void LC_DumbCircle()
1267 /////////////////////////////////////////////////////////////////////
1268 //pretty dumb circle drawer:
LC_DumbCircle(int * Bitmap,int BitmapWidth,int Radius,int color,int X,int Y)1269 void LC_DumbCircle (int *Bitmap, int BitmapWidth, int Radius, int color,
1270                     int X, int Y)
1271 {
1272  int Left,
1273   Bottom,
1274   PolarX,
1275   PolarY,
1276   x,
1277   y,
1278   ScaledRadius;
1279 
1280  while ((Y - Radius) < 0)
1281   Radius--;
1282  while ((Y + Radius) > BitmapWidth)
1283   Radius--;
1284  while ((X - Radius) < 0)
1285   Radius--;
1286  while ((X + Radius) > BitmapWidth)
1287   Radius--;
1288 
1289  if (!(Radius % 2))
1290   Radius--;
1291 
1292  Left = Bottom = -Radius;
1293  // ScaledRadius=(Radius-1)*(Radius-1);
1294  ScaledRadius = Radius * Radius;
1295  PolarX = Left;
1296  for (x = X - Radius; x < 1 + X + Radius; x++)
1297  {
1298   PolarY = Bottom;
1299   for (y = Y - Radius; y < 1 + Y + Radius; y++)
1300   {
1301    if (((PolarX * PolarX) + (PolarY * PolarY)) <= ScaledRadius)
1302     Bitmap[y * BitmapWidth + x] = color;
1303    PolarY++;
1304   }
1305   PolarX++;
1306  }
1307 }
1308 
1309 /////////////////////////////////////////////////////////////////////
1310 // skunk missile
1311 /////////////////////////////////////////////////////////////////////
LC_MakeMissile(int id,unsigned char Red,unsigned char Green,unsigned char Blue)1312 int LC_MakeMissile (int id, unsigned char Red, unsigned char Green,
1313                     unsigned char Blue)
1314 {
1315  int x,
1316   y;
1317  int BitmapWidth = 3;           //remember, LANDSCAPE will render it sideways
1318  int BitmapHeight = 32;
1319  //create bitmap, assign to globals:
1320  int *Bitmap = (int *) calloc (BitmapHeight * BitmapWidth, sizeof (int));
1321 
1322  for (y = 0; y < BitmapHeight; y++)
1323  {
1324   for (x = 0; x < BitmapWidth; x++)
1325   {
1326    if (x == 1)
1327     Bitmap[y * BitmapWidth + x] = 0xffffffff;
1328    else
1329     Bitmap[y * BitmapWidth + x] = 0xff000000;
1330   }
1331  }
1332 
1333  //now I have the bitmap, so assign it and all it's parameters to object:
1334  LC_FlyingObject[id].pTextureBitmap = Bitmap;
1335  LC_FlyingObject[id].Type = LC_MISSILE;
1336  LC_FlyingObject[id].SizeX = BitmapWidth;
1337  LC_FlyingObject[id].SizeY = BitmapHeight;
1338  LC_FlyingObject[id].Visible = 0;       //start not visible
1339  LC_FlyingObject[id].Speed = LC_MissileSpeed;
1340  LC_FlyingObject[id].Lift = 0;  //will be set at launch
1341  return 1;      //bogus
1342 }       //end makemissile()
1343 
1344 /////////////////////////////////////////////////////////////////////
1345 // void LC_MakeSky(int Size)
1346 /////////////////////////////////////////////////////////////////////
LC_MakeSky(int Size)1347 void LC_MakeSky (int Size)
1348 {
1349  int x,
1350   y;
1351  int *Bitmap;
1352  long old_seed = LC_Seed;
1353  if (Size > 12)
1354   Size = 12;    //keep factor 12 or less (for God's sake!)
1355  if (Size < 0)
1356   Size = 0;
1357  Size = (1 << (Size));
1358 
1359  //create bitmap, assign to globals:
1360  Bitmap = (int *) calloc (Size * Size, sizeof (int));
1361  //for (x=(Size*Size)-1;x>-1;x--){  Bitmap[x]=0xff000000; }
1362 
1363  //start find point and background colors:
1364  //start former globals in old code:
1365  int BitmapHeight = Size;
1366  int BitmapWidth = Size;
1367  //end of former globals in old code
1368  //first make a dark background:
1369  for (x = 0; x < BitmapWidth; x++)
1370  {      //put darks down
1371   // if (!UserFunction(x+1,BitmapWidth)) break;
1372   for (y = 0; y < BitmapHeight; y++)
1373   {
1374    Bitmap[y * BitmapWidth + x] =
1375     // 0xff000000|(rand()%20)<<16|(rand()%16)<<8|rand()%64;
1376     0xff000000 | (rand () % 16) << 16 | (rand () % 16) << 8 | rand () % 34;
1377   }     //end y
1378  }      //end x
1379  //LC_Blur(Bitmap,BitmapWidth,BitmapHeight,1);
1380  for (x = 0; x < BitmapWidth; x++)
1381  {      //put lights down
1382   for (y = 0; y < BitmapHeight; y++)
1383   {
1384    // if ((rand()%1024)<32)
1385    if ((rand () % 1024) < 12)
1386    {
1387     Bitmap[y * BitmapWidth + x] =
1388      0xff000000 | (230 + (rand () % 26)) << 16 | (230 +
1389                                                   (rand () %
1390                                                    26)) << 8 | (230 +
1391                                                                 rand () % 26);
1392    }
1393   }     //end y
1394  }      //end x
1395  LC_Blur (Bitmap, BitmapWidth, BitmapHeight, 2);
1396  int color;                     //highlight the whites:
1397  for (x = 0; x < BitmapWidth; x++)
1398  {      //start x
1399   for (y = 0; y < BitmapHeight; y++)
1400   {     //start y
1401    color = Bitmap[y * BitmapWidth + x];
1402    color = ((color >> 16) & 0xff) + ((color >> 8) & 0xff) + (color & 0xff);
1403    if (color > 375)
1404     Bitmap[y * BitmapWidth + x] = 0xFFFFFFFF;
1405   }     //y end
1406  }      //x end
1407  LC_Blur (Bitmap, BitmapWidth, BitmapHeight, 12);
1408  LC_Seed = old_seed;
1409  //don't delete Bitmap! it is LC_BmpSky
1410  if (LC_UserSky == 0)
1411   free (LC_BmpSky.pixel);
1412  LC_BmpSky.pixel = Bitmap;
1413  LC_BmpSky.w = Size;
1414  LC_BmpSky.h = Size;
1415  LC_UserSky = 0;
1416  LC_PlasmaSky ();
1417 }
1418 
1419 ////////////////////////////////////////////////////////////////////
1420 //int * PlasmaGenerator(int Size,int RandFactor,int Ceiling,int Floor) -
1421 //Size must represent a square bitmap with a width and height a clean power of 2
1422 //RandFactor is the highest random number than can be added to the plasma at the
1423 //start- complex relationship, so consider it carefully. For instance, making
1424 //it equal size means the last random additions to the landscape will be 0!
1425 //Double the Size is a good start. Ceiling and Floor
1426 //do a "hard limit" on the final bitmap values.
1427 ////////////////////////////////////////////////////////////////////
LC_Plasma(int * bitmap,int Size,int RandFactor,int floor,int ceiling)1428 void LC_Plasma (int *bitmap, int Size, int RandFactor, int floor, int ceiling)
1429 {
1430  int i,
1431   x,
1432   x_offset,
1433   y,
1434   y_offset,
1435   Step = Size;
1436  int ul,
1437   ur,
1438   lr,
1439   ll,
1440   MidT,
1441   MidB,
1442   MidR,
1443   MidL,
1444   Midpoint;
1445  //start mapmaking iterations:
1446  for (i = (Size >> 0); i > 1; i /= 2)
1447  {
1448   for (x = 0; x < Size; x += Step)
1449   {
1450    if ((x_offset = x + Step) >= Size)
1451     x_offset -= Size;
1452    for (y = 0; y < Size; y += Step)
1453    {
1454     if ((y_offset = y + Step) >= Size)
1455      y_offset -= Size;
1456     ul = bitmap[y * Size + x];
1457     ur = bitmap[y * Size + x_offset];
1458     ll = bitmap[y_offset * Size + x];
1459     lr = bitmap[y_offset * Size + x_offset];
1460     MidT =
1461      ((ul + ur) >> 1) + ((rand () % (RandFactor + 1)) - (RandFactor >> 1));
1462     MidB =
1463      ((ll + lr) >> 1) + ((rand () % (RandFactor + 1)) - (RandFactor >> 1));
1464     MidR =
1465      ((ur + lr) >> 1) + ((rand () % (RandFactor + 1)) - (RandFactor >> 1));
1466     MidL =
1467      ((ul + ll) >> 1) + ((rand () % (RandFactor + 1)) - (RandFactor >> 1));
1468     if (MidT < floor)
1469      MidT = floor;
1470     else if (MidT > ceiling)
1471      MidT = ceiling;
1472     if (MidB < floor)
1473      MidB = floor;
1474     else if (MidB > ceiling)
1475      MidB = ceiling;
1476     if (MidR < floor)
1477      MidR = floor;
1478     else if (MidR > ceiling)
1479      MidR = ceiling;
1480     if (MidL < floor)
1481      MidL = floor;
1482     else if (MidL > ceiling)
1483      MidL = ceiling;
1484     Midpoint =
1485      ((MidT + MidB + MidL + MidR) >> 2) + ((rand () % (RandFactor + 1)) -
1486                                            (RandFactor >> 1));
1487     if (Midpoint < floor)
1488      Midpoint = floor;
1489     else if (Midpoint > ceiling)
1490      Midpoint = ceiling;
1491     bitmap[y * Size + (x + (Step >> 1))] = MidT;
1492     bitmap[y_offset * Size + (x + (Step >> 1))] = MidB;
1493     bitmap[(y + (Step >> 1)) * Size + x] = MidL;
1494     bitmap[(y + (Step >> 1)) * Size + x_offset] = MidR;
1495     bitmap[(y + (Step >> 1)) * Size + (x + (Step >> 1))] = Midpoint;
1496    }    //end y
1497   }     //end x
1498   Step /= 2;
1499   if ((RandFactor /= 2) < 2)
1500    RandFactor = 2;
1501  }      //end i
1502 }       //end of LC_Plasma
1503 
1504 /////////////////////////////////////////////////////////////////////
1505 //void LC_ConvertIntBitmapToPixels() -- I think this was a Java required func
1506 /////////////////////////////////////////////////////////////////////
LC_ConvertIntBitmapToPixels(int * bitmap,int w,int h)1507 void LC_ConvertIntBitmapToPixels (int *bitmap, int w, int h)
1508 {
1509  int y,
1510   x;
1511  for (x = 0; x < w; x++)
1512   for (y = 0; y < h; y++)
1513    bitmap[y * w + x] |= 0xff000000;
1514 }
1515 
1516 /////////////////////////////////////////////////////////////////////
1517 // void LC_PlasmaSky() just throws some plasma over an existant sky, can only be called after LC_MakeSky(x) has been called
1518 /////////////////////////////////////////////////////////////////////
LC_PlasmaSky()1519 void LC_PlasmaSky ()
1520 {
1521  int w,
1522   h,
1523   j,
1524   i;
1525  long oldseed = LC_Seed;
1526  w = h = LC_BmpSky.w;
1527  int *bmp = (int *) calloc (w * h, sizeof (int));
1528  for (j = (w * h) - 1; j > -1; j--)
1529  {
1530   bmp[j] = 0;
1531  }
1532  LC_Plasma (bmp, LC_BmpSky.w, w, 0, 0xff);
1533  //this next weirdness simply adds, grays, and limits the
1534  //plasma with the original starmap, in the least
1535  //efficient way possible.
1536  //        for (int i=0;i<24;i+=8) {
1537  //         for (int y,x=0;x<w;x++) for (y=0;y<h;y++) {
1538  //          j=y*w+x;
1539  //          if ( (((LC_BmpSky[j]>>i)&0xff)+bmp[j])<256 )
1540  //           LC_BmpSky[j]+=(bmp[j]<<i);
1541  //          else LC_BmpSky[j]|=(0xff<<i);
1542  //         }
1543  //        }
1544 
1545  //I've written it a little more efficiently here, but
1546  //kept the above in case I do want to do a matrix-type
1547  //of operation (which often use the funny for config)
1548  for (j = (w * h) - 1; j > -1; j--)
1549  {
1550   for (i = 0; i < 24; i += 8)
1551   {
1552    if ((((LC_BmpSky.pixel[j] >> i) & 0xff) + bmp[j]) < 256)
1553     LC_BmpSky.pixel[j] += (bmp[j] << i);
1554    else
1555     LC_BmpSky.pixel[j] |= (0xff << i);
1556   }
1557  }
1558 
1559  LC_ConvertIntBitmapToPixels (LC_BmpSky.pixel, LC_BmpSky.w, LC_BmpSky.h);
1560  LC_Seed = oldseed;
1561  free (bmp);
1562 }       //end LC_PlasmaSky();
1563 
1564 /////////////////////////////////////////////////////////////////////
1565 //LC_SetRoll(int roll) - safely sets roll angle in LC_CircleRez units
1566 /////////////////////////////////////////////////////////////////////
LC_SetRoll(int roll)1567 void LC_SetRoll (int roll)
1568 {
1569  LC_Roll = roll;
1570  if (LC_Roll < 0)
1571   do
1572    LC_Roll += LC_CircleRez;
1573   while (LC_Roll < 0);
1574  else if (LC_Roll >= LC_CircleRez)
1575   do
1576    LC_Roll -= LC_CircleRez;
1577   while (LC_Roll >= LC_CircleRez);
1578 }
1579 
1580 /////////////////////////////////////////////////////////////////////
1581 // LC_DoMovement() - Increments position and direction on map
1582 /////////////////////////////////////////////////////////////////////
LC_DoMovement(int groundcollisionflag)1583 int LC_DoMovement (int groundcollisionflag)
1584 {
1585 
1586  if (!LC_InitFlag)
1587  {
1588   if (!LC_InitLandscape ())
1589    return 0;
1590  }
1591  //deal with turn:
1592  LC_Direction += LC_Turn;
1593  if (LC_Direction < 0)
1594   do
1595    LC_Direction += LC_CircleRez;
1596   while (LC_Direction < 0);
1597  else if (LC_Direction >= LC_CircleRez)
1598   do
1599    LC_Direction -= LC_CircleRez;
1600   while (LC_Direction >= LC_CircleRez);
1601 
1602  ///////////////
1603  //start motion
1604  LC_PositionX += ((LC_Cos[LC_Direction] * LC_Speed) >> LC_SPEEDSHIFT);  //the >>8 is only needed for g_framerate
1605  LC_PositionY += ((LC_Sin[LC_Direction] * LC_Speed) >> LC_SPEEDSHIFT);  //the >>8 is only needed for g_framerate
1606 
1607  //test bitmap limits- fast way:
1608  if (LC_PositionX < 0)
1609   LC_PositionX += LC_BmpColorsWidth_scaled;
1610  else if (LC_PositionX >= LC_BmpColorsWidth_scaled)
1611   LC_PositionX -= LC_BmpColorsWidth_scaled;
1612  if (LC_PositionY < 0)
1613   LC_PositionY += LC_BmpColorsHeight_scaled;
1614  else if (LC_PositionY >= LC_BmpColorsHeight_scaled)
1615   LC_PositionY -= LC_BmpColorsHeight_scaled;
1616 
1617  //test bitmap limits- careful way (for unlimited high LC_Speed values):
1618  //  if (LC_PositionX<0) do LC_PositionX+=LC_BmpColorsWidth_scaled; while (LC_PositionX<0);
1619  //  else if (LC_PositionX>LC_BmpColorsWidth_scaled) do LC_PositionX-=LC_BmpColorsWidth_scaled; while (LC_PositionX>LC_BmpColorsWidth_scaled);
1620  //  if (LC_PositionY<0) do LC_PositionY+=LC_BmpColorsHeight_scaled; while (LC_PositionY<0);
1621  // else if (LC_PositionY>LC_BmpColorsHeight_scaled) do LC_PositionY-=LC_BmpColorsHeight_scaled; while (LC_PositionY>LC_BmpColorsHeight_scaled);
1622 
1623  //things go haywire after 0x3FFF
1624  if ((LC_Altitude += LC_Lift) > 5362)
1625  {
1626   LC_Altitude = 5362;
1627  }
1628  else if (0 > LC_Altitude)
1629  {
1630   LC_Altitude = 0;
1631  }
1632 
1633  //////////////////////////////////
1634  //start ground collision detection
1635  //Do not call before LC_BmpHeights.pixel is available!
1636  //20110404: out of bounds in the array below, so made PosY\X check above >= instead of >
1637  if (0 != groundcollisionflag)
1638  {
1639   int ground =
1640    LC_Eyelevel +
1641    LC_BmpHeights.pixel[(LC_PositionY >> LC_SHIFT) * LC_BmpHeights.w +
1642                        (LC_PositionX >> LC_SHIFT)];
1643   //the scale-down factor (last number above) must relate to the calc in
1644   //tables() to scale pixels appropriately
1645   if (LC_Altitude < ground)
1646    LC_Altitude = ground;
1647  }
1648  //end ground collision detection
1649  //////////////////////////////////
1650  return 1;
1651 }       //end LC_DoMovement()
1652 
1653 /////////////////////////////////////////////////////////////////////
1654 // LC_DoFlyingObjectsMovement() - Increments all live views/objects
1655 /////////////////////////////////////////////////////////////////////
LC_DoFlyingObjectsMovement()1656 void LC_DoFlyingObjectsMovement ()
1657 {
1658  int tempint,
1659   id;
1660 
1661  id = LC_FlyingObjectCount - 1;
1662  do
1663  {      //start major do
1664   if (LC_FlyingObject[id].Visible)
1665    switch (LC_FlyingObject[id].Type)
1666    {    //start type switch
1667 
1668    case LC_TARGET:
1669     {
1670      //  if (LC_FlyingObject[id].Direction<0) LC_FlyingObject[id].Direction+=LC_CircleRez;
1671      //  else if (LC_FlyingObject[id].Direction>=LC_CircleRez) LC_FlyingObject[id].Direction-=LC_CircleRez;
1672 
1673      if ((LC_FlyingObject[id].Direction += LC_FlyingObject[id].Turn) < 0)
1674       LC_FlyingObject[id].Direction += LC_CircleRez;
1675      else if (LC_FlyingObject[id].Direction >= LC_CircleRez)
1676       LC_FlyingObject[id].Direction -= LC_CircleRez;
1677 
1678      LC_FlyingObject[id].PosX +=
1679       ((LC_Cos[LC_FlyingObject[id].Direction] *
1680         LC_FlyingObject[id].Speed) >> LC_SPEEDSHIFT);
1681      LC_FlyingObject[id].PosY +=
1682       ((LC_Sin[LC_FlyingObject[id].Direction] *
1683         LC_FlyingObject[id].Speed) >> LC_SPEEDSHIFT);
1684 
1685      //that mistake was below too: marked with //#
1686      //test bitmap limits- fast way:
1687      if (LC_FlyingObject[id].PosX < 0)
1688       LC_FlyingObject[id].PosX += LC_BmpColorsWidth_scaled;
1689      else if (LC_FlyingObject[id].PosX >= LC_BmpColorsWidth_scaled)
1690       LC_FlyingObject[id].PosX -= LC_BmpColorsWidth_scaled;     //#
1691      if (LC_FlyingObject[id].PosY < 0)
1692       LC_FlyingObject[id].PosY += LC_BmpColorsHeight_scaled;
1693      else if (LC_FlyingObject[id].PosY >= LC_BmpColorsHeight_scaled)
1694       LC_FlyingObject[id].PosY -= LC_BmpColorsHeight_scaled;    //#
1695 
1696      //now draw the object on the object map:
1697      int x_count = LC_FlyingObject[id].PosX,
1698       y_count = LC_FlyingObject[id].PosY,
1699       x_step,
1700       y_step,
1701       pos,
1702       id_code;
1703 
1704      switch (LC_TargetOrientation)
1705      {
1706       //decide how to face the targets:
1707      case LC_SKINNY:
1708       pos = LC_FlyingObject[id].Direction;
1709       break;
1710 
1711      case LC_SIDEWAYS:
1712       pos = LC_FlyingObject[id].Direction - (LC_CircleRez >> 2);
1713       if (pos < 0)
1714        pos += LC_CircleRez;
1715       else if (pos >= LC_CircleRez)
1716        pos -= LC_CircleRez;
1717       break;
1718 
1719      case LC_FACING:
1720       pos = LC_Direction - (LC_CircleRez >> 2);
1721       if (pos < 0)
1722        pos += LC_CircleRez;
1723       else if (pos >= LC_CircleRez)
1724        pos -= LC_CircleRez;
1725       break;
1726 
1727      default:
1728       pos = LC_FlyingObject[id].Direction - (LC_CircleRez >> 2);
1729       if (pos < 0)
1730        pos += LC_CircleRez;
1731       else if (pos >= LC_CircleRez)
1732        pos -= LC_CircleRez;
1733       break;
1734      }
1735 
1736      x_step = (LC_Cos[pos] >> 1);
1737      y_step = (LC_Sin[pos] >> 1);
1738 
1739      // id_code=((id<<6)+1);//for int LC_BmpFlyingObjects (3 objects max)
1740      id_code = ((id << 8) + 1); // for unsigned short int LC_BmpFlyingObjects (255 obj)
1741 
1742      //I have to do this first, unfortunately, and not in the main
1743      //placement loop because I discovered that the erasure loop
1744      //was erasing some NEW pixels if the object was going backward
1745      //(and other un-considered movements).
1746      //NOTE: crashes in following usually mean Erase hasn't been zeroed:
1747      pos = LC_FlyingObject[id].SizeY;   //remember, texmaps are done sideways for speed
1748      do
1749       LC_BmpFlyingObjects[LC_FlyingObject[id].pErase[--pos]] = 0;       //erase old positions
1750      while (pos);
1751 
1752      //Now do main placement loop:
1753      pos = LC_FlyingObject[id].SizeY;   //remember, texmaps are done sideways for speed
1754 
1755      //draw the lines:
1756      do
1757      {
1758       LC_FlyingObject[id].pErase[--pos] =
1759        (y_count >> LC_SHIFT) * LC_BmpColors.w + (x_count >> LC_SHIFT);
1760       LC_BmpFlyingObjects[LC_FlyingObject[id].pErase[pos]] = pos | id_code;
1761       if ((x_count -= x_step) < 0)
1762        x_count += LC_BmpColorsWidth_scaled;
1763       else if (x_count >= LC_BmpColorsWidth_scaled)
1764        x_count -= LC_BmpColorsWidth_scaled;
1765       if ((y_count -= y_step) < 0)
1766        y_count += LC_BmpColorsHeight_scaled;
1767       else if (y_count >= LC_BmpColorsHeight_scaled)
1768        y_count -= LC_BmpColorsHeight_scaled;
1769      }
1770      while (pos);
1771 
1772      /*
1773         //experimental
1774         unsigned short * pBmpIndex=LC_BmpFlyingObjects+(y_count>>LC_SHIFT)*LC_BmpColors.w+(x_count>>LC_SHIFT);
1775         //now determine draw slope:
1776         int SLOPEY,SLOPEX,holemark;
1777         int DrawPointX=x_count;
1778         int OldDrawPointX=DrawPointX>>10;
1779         int DrawPointY=y_count;
1780         int OldDrawPointY=DrawPointY>>10;
1781         if (DrawPointY<(DrawPointY-y_step)) SLOPEY=LC_BmpColors.w;
1782         else SLOPEY=-LC_BmpColors.w;
1783         if (DrawPointX<(DrawPointX-x_step)) SLOPEX=1;
1784         else SLOPEX=-1;
1785         do {
1786         *pBmpIndex=pos|id_code;
1787         LC_FlyingObject[id].pErase[pos]=pBmpIndex-LC_BmpFlyingObjects;
1788         DrawPointX-=x_step;
1789         DrawPointY-=y_step;
1790         if (DrawPointX<0) DrawPointX+=LC_BmpColorsWidth_scaled;
1791         else if (DrawPointX>=LC_BmpColorsWidth_scaled) DrawPointX-=LC_BmpColorsWidth_scaled;
1792         if (DrawPointY<0) DrawPointY+=LC_BmpColorsHeight_scaled;
1793         else if (DrawPointY>=LC_BmpColorsHeight_scaled) DrawPointY-=LC_BmpColorsHeight_scaled;
1794 
1795         holemark=2;
1796         if (OldDrawPointY!=(DrawPointY>>LC_SHIFT)) {
1797         --holemark;
1798         pBmpIndex+=SLOPEY;
1799         OldDrawPointY=(DrawPointY>>LC_SHIFT);
1800         }
1801         if (OldDrawPointX!=(DrawPointX>>LC_SHIFT)) {
1802         --holemark;
1803         OldDrawPointX=(DrawPointX>>LC_SHIFT);
1804         pBmpIndex+=SLOPEX;
1805         }
1806 
1807         //if (!holemark) *(pBmpIndex-SLOPEX)=2|id_code;//0xffff;
1808         } while (pos);
1809         //end experimental
1810       */
1811 
1812      LC_FlyingObject[id].Alt += LC_FlyingObject[id].Lift;
1813      if ((pos =
1814           10 +
1815           LC_BmpHeights.pixel[LC_FlyingObject[id].pErase
1816                               [LC_FlyingObject[id].SizeY >> 1]]) >
1817          LC_FlyingObject[id].Alt)
1818       //  if ((pos=10+LC_BmpHeights.pixel[LC_FlyingObject[id].pErase[LC_FlyingObject[id].SizeY>>1]])>--LC_FlyingObject[id].Alt)
1819      {
1820       LC_FlyingObject[id].Alt = pos;
1821      }
1822     }
1823     break;      //type LC_TARGET
1824 
1825    case LC_MISSILE:
1826     {   //start IsVisible
1827      int pos = LC_FlyingObject[id].SizeY;       //remember, texmaps are done sideways for speed
1828      //see if it is time to die:
1829      if (!(--LC_FlyingObject[id].Visible))      //missile too old; erase it
1830      {
1831       do
1832        LC_BmpFlyingObjects[LC_FlyingObject[id].pErase[--pos]] = 0;      //erase old positions
1833       while (pos);
1834       break;
1835      }
1836      if (LC_MissileControl)     //fly-by-wire: only works for solo user
1837      {
1838       LC_FlyingObject[id].Direction = LC_Direction + (LC_Turn << 2);    //direction==mine
1839       if (LC_FlyingObject[id].Direction < 0)
1840        LC_FlyingObject[id].Direction += LC_CircleRez;
1841       else if (LC_FlyingObject[id].Direction >= LC_CircleRez)
1842        LC_FlyingObject[id].Direction -= LC_CircleRez;
1843       LC_FlyingObject[id].Lift = LC_Lift;       //takes my sink or rise
1844      }
1845 
1846      LC_FlyingObject[id].PosX +=
1847       ((LC_Cos[LC_FlyingObject[id].Direction] *
1848         LC_FlyingObject[id].Speed) >> LC_SPEEDSHIFT);
1849      LC_FlyingObject[id].PosY +=
1850       ((LC_Sin[LC_FlyingObject[id].Direction] *
1851         LC_FlyingObject[id].Speed) >> LC_SPEEDSHIFT);
1852 
1853      //found my '>' insead of '>=" bug again - I will always mark with //#
1854      //test bitmap limits- fast way:
1855      if (LC_FlyingObject[id].PosX < 0)
1856       LC_FlyingObject[id].PosX += LC_BmpColorsWidth_scaled;
1857      else if (LC_FlyingObject[id].PosX >= LC_BmpColorsWidth_scaled)
1858       LC_FlyingObject[id].PosX -= LC_BmpColorsWidth_scaled;     //#
1859      if (LC_FlyingObject[id].PosY < 0)
1860       LC_FlyingObject[id].PosY += LC_BmpColorsHeight_scaled;
1861      else if (LC_FlyingObject[id].PosY >= LC_BmpColorsHeight_scaled)
1862       LC_FlyingObject[id].PosY -= LC_BmpColorsHeight_scaled;    //#
1863 
1864      //now draw the object on the object map:
1865      int x_step = (LC_Cos[LC_FlyingObject[id].Direction] >> 1),
1866       y_step = (LC_Sin[LC_FlyingObject[id].Direction] >> 1),
1867       x_count = LC_FlyingObject[id].PosX,
1868       y_count = LC_FlyingObject[id].PosY,
1869       id_code = ((id << 8) + 1);        // for unsigned short int LC_BmpFlyingObjects (255 obj)
1870      //try 1:
1871      do
1872      {  //first, test to see if missile has hit something
1873       if (LC_BmpFlyingObjects
1874           [tempint =
1875            (y_count >> LC_SHIFT) * LC_BmpColors.w + (x_count >> LC_SHIFT)])
1876       { //something is in that spot- now see if I really hit it
1877        //note- LC_UserData1 is intentional- used to give info to user ID of hit
1878        LC_UserData1 = LC_BmpFlyingObjects[tempint] >> 8;        //the ID of what got hit
1879        if (LC_UserData1 != id &&        //it is not itself
1880            LC_FlyingObject[id].Alt > LC_FlyingObject[LC_UserData1].Alt &&       //it's higher than its bottom
1881            LC_FlyingObject[id].Alt < (LC_FlyingObject[LC_UserData1].Alt + LC_FlyingObject[LC_UserData1].SizeX)) //lower than its top
1882        {        //I really hit it
1883         LC_UserData2 = id;      //also make ID of missile available
1884         LC_UserFunctionFast (LC_OBJECTHIT);     //tell user she hit something, get ID from LC_UserData1
1885         //     do LC_BmpFlyingObjects[LC_FlyingObject[id].pErase[--pos]]=0;  while (pos>0);
1886         break;  //keeps me from counting too many hits
1887        }
1888       }
1889       LC_BmpFlyingObjects[LC_FlyingObject[id].pErase[--pos]] = 0;       //erase old position
1890       LC_FlyingObject[id].pErase[pos] = tempint;
1891       LC_BmpFlyingObjects[LC_FlyingObject[id].pErase[pos]] = pos | id_code;
1892       x_count -= x_step;
1893       y_count -= y_step;
1894       if (x_count < 0)
1895        x_count += LC_BmpColorsWidth_scaled;
1896       else if (x_count >= LC_BmpColorsWidth_scaled)
1897        x_count -= LC_BmpColorsWidth_scaled;
1898       if (y_count < 0)
1899        y_count += LC_BmpColorsHeight_scaled;
1900       else if (y_count >= LC_BmpColorsHeight_scaled)
1901        y_count -= LC_BmpColorsHeight_scaled;
1902      }
1903      while (pos);
1904 
1905      LC_FlyingObject[id].Alt += LC_FlyingObject[id].Lift;       //do lift
1906      //now do ground testing:
1907      //    if (LC_BmpHeights.pixel[LC_FlyingObject[id].pErase[LC_FlyingObject[id].SizeY-1]]>LC_FlyingObject[id].Alt)
1908      if (LC_BmpHeights.pixel[tempint] > LC_FlyingObject[id].Alt)
1909      {
1910       LC_UserFunctionFast (LC_GROUND);  //tell user she hit something
1911       LC_FlyingObject[id].Visible = 0;  //stick it in a mountain (no erase)
1912       break;
1913      }
1914     }   //end IsVisible
1915     break;      //end LC_MISSILE
1916 
1917    default:
1918     break;      //default
1919    }    //end type switch
1920  }
1921  while (id--);  //end major do
1922 }
1923 
1924 ////////////////////////////////////////////////////////////////////////
1925 // void LC_UserFunctionFast(int message) - for fast uses (in rendering loop, etc)
1926 ////////////////////////////////////////////////////////////////////////
LC_UserFunctionFast(int message)1927 void LC_UserFunctionFast (int message)
1928 {
1929  if (!LC_pUserFunctionFast)
1930   return;
1931  LC_pUserFunctionFast (message);
1932  return;
1933 }
1934 
1935 /////////////////////////////////////////////////////////////////////
1936 // SetCallback - set what function I use to communicate with user's program
1937 /////////////////////////////////////////////////////////////////////
LC_SetCallbackFast(void (* CallbackFunction)(int message))1938 void LC_SetCallbackFast (void (*CallbackFunction) (int message))
1939 {
1940  LC_pUserFunctionFast = CallbackFunction;
1941 }
1942 
1943 /////////////////////////////////////////////////////////////////////
1944 // this is LandCaster's (not OBJECT's) way of deleting
1945 // what it allocated to objects
1946 /////////////////////////////////////////////////////////////////////
LC_DeleteFlyingObjectsResources(void)1947 int LC_DeleteFlyingObjectsResources (void)
1948 {
1949  if (LC_BmpFlyingObjects != NULL)
1950  {
1951   free (LC_BmpFlyingObjects);
1952   LC_BmpFlyingObjects = NULL;
1953  }
1954 
1955  if (LC_TextureStepX != NULL)
1956  {
1957   free (LC_TextureStepX);
1958   LC_TextureStepX = NULL;
1959  }
1960 
1961  if (LC_TextureStepCountX != NULL)
1962  {
1963   free (LC_TextureStepCountX);
1964   LC_TextureStepCountX = NULL;
1965  }
1966 
1967  if (LC_TextureStepCountY != NULL)
1968  {
1969   free (LC_TextureStepCountY);
1970   LC_TextureStepCountY = NULL;
1971  }
1972 
1973  if (LC_StartDraw != NULL)
1974  {
1975   free (LC_StartDraw);
1976   LC_StartDraw = NULL;
1977  }
1978 
1979  if (LC_StopDraw != NULL)
1980  {
1981   free (LC_StopDraw);
1982   LC_StopDraw = NULL;
1983  }
1984 
1985  if (LC_TextureBitmapIndex != NULL)
1986  {
1987   free (LC_TextureBitmapIndex);
1988   LC_TextureBitmapIndex = NULL;
1989  }
1990 
1991  if (LC_FlyingObject != NULL)
1992  {
1993   int i;
1994   for (i = 0; i < LC_FlyingObjectCount; i++)
1995    LC_FlyingObjectDestructor (&LC_FlyingObject[i]);
1996   free (LC_FlyingObject);
1997   LC_FlyingObject = NULL;
1998  }
1999  LC_BmpFlyingObjects = NULL;
2000  LC_TextureStepX = NULL;
2001  LC_TextureStepCountX = NULL;
2002  LC_TextureStepCountY = NULL;
2003  LC_StartDraw = NULL;
2004  LC_StopDraw = NULL;
2005  LC_TextureBitmapIndex = NULL;
2006  LC_FlyingObject = NULL;
2007  return 1;
2008 }
2009 
LC_InitVars()2010 void LC_InitVars ()
2011 {
2012  LC_AP.EyeLevel = 0;
2013  LC_AP.Lift = 0;
2014  LC_AP.Turn = 0;
2015  LC_AP.running = 1;
2016  LC_Eyelevel = 5;
2017  LC_WaterHeight = 0;
2018  LC_ResolutionInterval = 384;   //distance at which renderer starts taking longer ray steps
2019  LC_RadianToCircleRezFactor = 0;
2020  LC_UserSky = 0;        //not using a user's skybitmap is default
2021  LC_FacedTargetFlag = 1;
2022  LC_TargetOrientation = LC_SKINNY;
2023  LC_MissileControl = 0; //start with missile control off
2024  LC_MissileSpeed = 250;
2025  LC_TargetStartPos = LC_CHANCE;
2026  LC_TargetSpeed = 26;
2027  LC_TargetSize = 5;
2028 
2029  //pointers:
2030  LC_BmpDest.pixel = 0;
2031  LC_BmpColors.pixel = 0;
2032  LC_BmpHeights.pixel = 0;
2033  LC_BmpSky.pixel = 0;
2034  LC_Sin = 0;
2035  LC_Cos = 0;
2036  LC_Correction = 0;
2037  LC_DistanceScaling = 0;
2038  LC_TextureScaling = 0;
2039  LC_RollData = 0;
2040  LC_TextureStepX = 0;
2041  LC_TextureStepCountX = 0;
2042  LC_TextureStepCountY = 0;
2043  LC_StartDraw = 0;
2044  LC_StopDraw = 0;
2045  LC_TextureBitmapIndex = 0;
2046  LC_BmpFlyingObjects = 0;
2047  LC_StopDraw = 0;
2048  LC_TextureBitmapIndex = 0;
2049  LC_pUserFunctionFast = 0;
2050  LC_FlyingObject = 0;
2051  //endpointers
2052 
2053  //20101129: default datasize is 4 (int):
2054  LC_BmpDest.datasize = 4;
2055  LC_BmpColors.datasize = 4;
2056  LC_BmpHeights.datasize = 4;
2057  LC_BmpSky.datasize = 4;
2058 
2059  LC_FlyingObjectCount = 0;      //user turns this on using LC_SetNumberOfFlyingObjects()
2060  LC_Turn = 0;
2061  LC_Direction = 0;
2062  LC_Lift = 9;
2063  LC_InitFlag = 0;       //haven't run LC_InitLandscape yet.
2064  LC_Speed = 50;
2065  LC_CircleRez = 2560;
2066  LC_Resolution = 500;
2067  LC_Raylength = 1024;
2068  LC_Scale = 400000;     //400000;//change to suit hill scaling
2069  LC_Tilt = 200; //Screen altitude, really - should be about 1/2 MaxFramewidth
2070  LC_SkyFlag = 0;        //0 means don't draw fancy sky in Landscape
2071  LC_Altitude = 173;
2072  LC_PositionX = 0;
2073  LC_PositionY = 0;
2074  LC_Roll = 0;
2075  LC_MaxFrameWidth = 0;  //in case user replaces it.
2076  //set all bitmap info to 0, to be sure user sets them later
2077  LC_BmpColors.w = 0;
2078  LC_BmpColors.h = 0;
2079  LC_BmpHeights.w = 0;
2080  LC_BmpHeights.h = 0;
2081  LC_BmpDest.w = 0;
2082  LC_BmpDest.h = 0;
2083  LC_BmpSky.w = 0;
2084  LC_BmpSky.h = 0;
2085 }
2086 
2087 /////////////////////////////////////////////////////////////////////
2088 // void LC_pixelput() -- pretty dumb
2089 /////////////////////////////////////////////////////////////////////
LC_pixelput(int * pTempBitmap,int x_temp,int y_temp,int val,int width)2090 void LC_pixelput (int *pTempBitmap, int x_temp, int y_temp, int val,
2091                   int width)
2092 {
2093  pTempBitmap[y_temp * width + x_temp] = val;
2094 }
2095 
2096 /////////////////////////////////////////////////////////////////////
2097 // void LC_pixelget() -- similarly dumb
2098 /////////////////////////////////////////////////////////////////////
LC_pixelget(int * pTempBitmap,int x_temp,int y_temp,int width)2099 int LC_pixelget (int *pTempBitmap, int x_temp, int y_temp, int width)
2100 {
2101  return (pTempBitmap[y_temp * width + x_temp]);
2102 }
2103 
2104 /////////////////////////////////////////////////////////////////////
2105 // LC_Blur() - Higher blur_factor means less blur
2106 /////////////////////////////////////////////////////////////////////
LC_Blur(int * OrigBitmap,int width,int height,int blur_factor)2107 void LC_Blur (int *OrigBitmap, int width, int height, int blur_factor)
2108 {
2109  double divisor = 1.0 / (blur_factor + 9);
2110  int *TempBitmap;
2111  TempBitmap = (int *) calloc (width * height, sizeof (int));
2112  int x,
2113   y,
2114   x_step,
2115   y_step,
2116   x_temp,
2117   y_temp,
2118   sum_red,
2119   sum_green,
2120   sum_blue,
2121   image_width,
2122   image_height,
2123   color;
2124 
2125  image_height = height - 1;
2126  image_width = width - 1;
2127 
2128  LC_CopyBitmap (OrigBitmap, TempBitmap, 0, 0, 0, 0, width, height);
2129  for (x = 0; x < width; x++)
2130  {      //start x
2131   for (y = 0; y < height; y++)
2132   {     //start y
2133    sum_red = sum_green = sum_blue = 0;  //reset sums for new average
2134    //start with upper left pixel of the 3x3
2135    for (x_step = -1; x_step < 2; x_step++)
2136    {
2137     x_temp = x + x_step;
2138     if (x_temp < 0)
2139      x_temp += width;
2140     else if (x_temp > image_width)
2141      x_temp -= width;
2142     for (y_step = -1; y_step < 2; y_step++)
2143     {
2144      y_temp = y + y_step;
2145      if (y_temp < 0)
2146       y_temp += height;
2147      else if (y_temp > image_height)
2148       y_temp -= height;
2149      //now I take the rgb info from the designated pixel:
2150      color = LC_pixelget (TempBitmap, x_temp, y_temp, width);
2151      sum_red += ((color >> 16) & 0xff);
2152      sum_green += ((color >> 8) & 0xff);
2153      sum_blue += (color & 0xff);
2154      //now I emphasize the original pixel:
2155      if (x_step == 0 && y_step == 0 && blur_factor != 0)
2156      {
2157       sum_red += (((color >> 16) & 0xff) * blur_factor);
2158       sum_green += (((color >> 8) & 0xff) * blur_factor);
2159       sum_blue += ((color & 0xff) * blur_factor);
2160      }
2161     }   //y_temp end
2162    }    // x_temp end
2163    //now I get the average of all the sums- 9 + 1 pixels, so divide by 10:
2164    sum_red = (int) ((sum_red * divisor) + 0.5);
2165    sum_green = (int) ((sum_green * divisor) + 0.5);
2166    sum_blue = (int) ((sum_blue * divisor) + 0.5);
2167    if (sum_red > 255)
2168     sum_red = 255;
2169    else if (sum_red < 0)
2170     sum_red = 0;
2171    if (sum_green > 255)
2172     sum_green = 255;
2173    else if (sum_green < 0)
2174     sum_green = 0;
2175    if (sum_blue > 255)
2176     sum_blue = 255;
2177    else if (sum_blue < 0)
2178     sum_blue = 0;
2179    LC_pixelput (OrigBitmap, x, y,
2180                 ((0xff000000 | sum_red << 16 | sum_green << 8 | sum_blue)),
2181                 width);
2182   }     //y end
2183  }      //x end
2184  free (TempBitmap);
2185 }       //end LC_Blur
2186 
2187 ////////////////////////////////////////////////////////////////////////
2188 // void LC_CopyBitmap() - slow, unoptimized
2189 ////////////////////////////////////////////////////////////////////////
LC_CopyBitmap(int * pTempBitmapSource,int * pTempBitmapDest,int i,int j,int x,int y,int Width,int Height)2190 void LC_CopyBitmap (int *pTempBitmapSource, int *pTempBitmapDest, int i,
2191                     int j, int x, int y, int Width, int Height)
2192 {
2193  for (x = 0; x < Width; x++)
2194  {
2195   for (y = 0; y < Height; y++)
2196   {
2197    pTempBitmapDest[y * Width + x] = pTempBitmapSource[y * Width + x];
2198   }     //end y
2199  }      //end x
2200 }
2201 
2202 /////////////////////////////////////////////////////////////////////
2203 // void LC_FlyingObjectDestructor() -- taken from the C++ ver
2204 /////////////////////////////////////////////////////////////////////
LC_FlyingObjectDestructor(FLYINGOBJECT * tempFlyingObject)2205 void LC_FlyingObjectDestructor (FLYINGOBJECT * tempFlyingObject)
2206 {
2207  //if user isn't using an external bitmap, delete the bitmap:
2208  if (!tempFlyingObject->bExternalBitmap
2209      && NULL != tempFlyingObject->pTextureBitmap)
2210  {
2211   free (tempFlyingObject->pTextureBitmap);
2212   tempFlyingObject->pTextureBitmap = NULL;
2213  }
2214  //now delete erasure array:
2215  if (NULL != tempFlyingObject->pErase)
2216  {
2217   free (tempFlyingObject->pErase);      //in case one was already there
2218   tempFlyingObject->pErase = NULL;
2219  }
2220 }
2221 
2222 /////////////////////////////////////////////////////////////////////
2223 // void LC_FlyingObjectConstructor() -- taken from the C++ ver
2224 /////////////////////////////////////////////////////////////////////
LC_FlyingObjectConstructor(FLYINGOBJECT * tempFlyingObject)2225 void LC_FlyingObjectConstructor (FLYINGOBJECT * tempFlyingObject)
2226 {
2227  tempFlyingObject->bExternalBitmap = 0; //FLYINGOBJECT always creates NULL, or maybe a 1x1 pixel, bitmap
2228  tempFlyingObject->Type = LC_TARGET;    //arbitrary
2229  tempFlyingObject->Speed = 0;
2230  tempFlyingObject->Turn = 0;
2231  tempFlyingObject->Visible = LC_VISIBLE;
2232  tempFlyingObject->Alt = 100;
2233  tempFlyingObject->Direction = 0;
2234  tempFlyingObject->Lift = 0;
2235  tempFlyingObject->SizeX = 0;   //width of the texture bitmap
2236  tempFlyingObject->SizeY = 0;   //height of the texture bitmap
2237  tempFlyingObject->PosX = 0;    //scaled by <<LC_SHIFT
2238  tempFlyingObject->PosY = 0;    //scaled by <<LC_SHIFT
2239  tempFlyingObject->pErase = NULL;       //usually needs to be allotted to SizeY, unless a "3D" object
2240  tempFlyingObject->pTextureBitmap = NULL;       //address to first byte of texture bitmap
2241 }
2242 
2243 ////////////////////////////////////////////////////////////////////////
2244 // void LC_LandCaster_Cleanup()
2245 ////////////////////////////////////////////////////////////////////////
LC_LandCaster_Cleanup()2246 void LC_LandCaster_Cleanup ()
2247 {
2248  if (LC_Sin != NULL)
2249  {
2250   free (LC_Sin);
2251   LC_Sin = NULL;
2252  }
2253 
2254  if (LC_Cos != NULL)
2255  {
2256   free (LC_Cos);
2257   LC_Cos = NULL;
2258  }
2259 
2260  if (LC_Correction != NULL)
2261  {
2262   free (LC_Correction);
2263   LC_Correction = NULL;
2264  }
2265 
2266  if (LC_DistanceScaling != NULL)
2267  {
2268   free (LC_DistanceScaling);
2269   LC_DistanceScaling = NULL;
2270  }
2271 
2272  if (LC_TextureScaling != NULL)
2273  {
2274   free (LC_TextureScaling);
2275   LC_TextureScaling = NULL;
2276  }
2277 
2278  if (LC_RollData != NULL)
2279  {
2280   free (LC_RollData);
2281   LC_RollData = NULL;
2282  }
2283 
2284  if (!LC_UserSky && NULL != LC_BmpSky.pixel)
2285  {
2286   free (LC_BmpSky.pixel);       //already deleted if user gave sky
2287   LC_BmpSky.pixel = NULL;
2288  }
2289 
2290  LC_DeleteFlyingObjectsResources ();
2291 }
2292 
2293 /////////////////////////////////////////////////////////////////////
2294 // LC_PixelFly() - has sky and tilt, but no roll
2295 // SPECIAL NOTE: This function is Java-compatible (no pointers)
2296 /////////////////////////////////////////////////////////////////////
LC_PixelFly()2297 void LC_PixelFly ()
2298 {
2299  int SkySize = LC_BmpSky.w * LC_BmpSky.h;
2300  int SkyX = LC_Direction;
2301  if (SkyX >= LC_BmpSky.w)
2302   do
2303    SkyX -= LC_BmpSky.w;
2304   while (SkyX >= LC_BmpSky.w);
2305  int tiltFactor;
2306  int eyeLevel = (LC_BmpDest.h >> 1) - LC_Tilt;  //eyelevel set here
2307  int x = LC_BmpDest.w;
2308  int x_offset;
2309  int CenterWidth = LC_BmpDest.w >> 1;
2310  //******Start X******
2311  do     // x is the number of rays I send
2312  {
2313   //next line starts my first column on the left side of screen
2314   if ((x_offset = LC_Direction - CenterWidth + x) >= LC_CircleRez)
2315    x_offset -= LC_CircleRez;
2316   else if (x_offset < 0)
2317    x_offset += LC_CircleRez;
2318 
2319   //in the regular world (not DIB sections), window lower-left is this:
2320   int pScreenIndex = LC_DestLowerLeftStartPoint + --x;
2321 
2322   int x_step = (LC_Cos[x_offset] * LC_Correction[x]) >> 20;
2323   int y_step = (LC_Sin[x_offset] * LC_Correction[x]) >> 20;
2324   int y = LC_BmpDest.h;
2325   //////////////////////////////////////
2326   //******Start Y********
2327   do
2328   {
2329    //PFly2: the philosphy of rendering:
2330    //(TrueAltitude*EyeToScreenDistance)/RowsFromEyeLevelToCurentScreenRow
2331    //or the speed equivlent: (1/Drop)*(Alt<<eyedistance)
2332    if ((tiltFactor = y + eyeLevel) < 1)
2333     break;      //this does LC_Tilt
2334    int x_int = (x_step * LC_Altitude << 10) / tiltFactor + LC_PositionX;
2335    int y_int = (y_step * LC_Altitude << 10) / tiltFactor + LC_PositionY;
2336 
2337    //I must use the following cumbersome method of bounds checking because
2338    //when altitude increases in PFly, single steps can be even larger than
2339    //either image dimensions (010224)
2340    //if (y_int>=LC_BmpColorsHeight_scaled) do y_int-=LC_BmpColorsHeight_scaled; while (y_int>=LC_BmpColorsHeight_scaled);
2341    //else if(y_int<0) do y_int+=LC_BmpColorsHeight_scaled; while (y_int<0);
2342    //if (x_int>=LC_BmpColorsWidth_scaled) do x_int-=LC_BmpColorsWidth_scaled; while (x_int>=LC_BmpColorsWidth_scaled);
2343    //else if (x_int<0) do x_int+=LC_BmpColorsWidth_scaled; while (x_int<0);
2344    //the following actually is faster, since most of the time the
2345    //indexes are out of bounds:
2346    if (y_int < 0 || y_int >= LC_BmpColorsHeight_scaled)
2347    {
2348     y_int %= LC_BmpColorsHeight_scaled;
2349     if (y_int < 0)
2350      y_int += LC_BmpColorsHeight_scaled;
2351    }
2352    if (x_int < 0 || x_int >= LC_BmpColorsWidth_scaled)
2353    {
2354     x_int %= LC_BmpColorsWidth_scaled;
2355     if (x_int < 0)
2356      x_int += LC_BmpColorsWidth_scaled;
2357    }
2358    //////////////////////////////////////
2359    //start draw landscape
2360    LC_BmpDest.pixel[pScreenIndex] =
2361     LC_BmpColors.pixel[(y_int >> 10) * LC_BmpColors.w + (x_int >> 10)];
2362    pScreenIndex -= LC_BmpDest.w;
2363   }
2364   while (--y > 0);      //stop_ray); //length I cast the ray
2365   //********End Y**********
2366   //////////////////////////////////////
2367   //put the sky bitmap in the background:
2368   if (pScreenIndex > 0)
2369   {
2370    if (SkyX < 0)
2371     SkyX += LC_BmpSky.w;
2372    int SkyY = (pScreenIndex / LC_BmpDest.w) - LC_Tilt;
2373    if (SkyY >= LC_BmpSky.h)
2374     do
2375      SkyY -= LC_BmpSky.h;
2376     while (SkyY >= LC_BmpSky.h);
2377    else if (SkyY < 0)
2378     do
2379      SkyY += LC_BmpSky.h;
2380     while (SkyY < 0);
2381    SkyY = SkyY * LC_BmpSky.w + SkyX;
2382    //*** start sky draw ***
2383    do
2384    {
2385     LC_BmpDest.pixel[pScreenIndex] = LC_BmpSky.pixel[SkyY];
2386     if ((SkyY -= LC_BmpSky.w) < 0)
2387      SkyY += SkySize;
2388    }
2389    while ((pScreenIndex -= LC_BmpDest.w) > 0);
2390   }
2391   //*** end sky draw ***
2392   //##############END COLUMN OF SKY DRAWING#############
2393   --SkyX;
2394  }
2395  while (x > 0); // end x
2396  //*************end X**************
2397 }       //end PFly()
2398 
2399 /////////////////////////////////////////////////////////////////////
2400 // LC_AutoPilot() - 030223
2401 /////////////////////////////////////////////////////////////////////
LC_AutoAlt()2402 void LC_AutoAlt ()
2403 {
2404  static int ground_sum = 32 << 4;
2405  static int altitude_sum = 32 << 3;
2406  static const int distanceAlt = 20;     //distance feeler goes to determine altitude
2407 
2408  //alert: out of bounds error occurs in next line (fixed 11-30-00?)
2409  int x_start = LC_PositionX + LC_Cos[LC_Direction] * distanceAlt;
2410  int y_start = LC_PositionY + LC_Sin[LC_Direction] * distanceAlt;
2411  if (x_start < 0)
2412   do
2413    x_start += LC_BmpColorsWidth_scaled;
2414   while (x_start < 0);
2415  else if (x_start >= LC_BmpColorsWidth_scaled)
2416   do
2417    x_start -= LC_BmpColorsWidth_scaled;
2418   while (x_start > LC_BmpColorsWidth_scaled);
2419  if (y_start < 0)
2420   do
2421    y_start += LC_BmpColorsHeight_scaled;
2422   while (y_start < 0);
2423  else if (y_start >= LC_BmpColorsHeight_scaled)
2424   do
2425    y_start -= LC_BmpColorsHeight_scaled;
2426   while (y_start >= LC_BmpColorsHeight_scaled);
2427  altitude_sum += LC_Altitude;
2428  ground_sum +=
2429   LC_BmpHeights.pixel[(y_start >> LC_SHIFT) * LC_BmpHeights.w +
2430                       (x_start >> LC_SHIFT)] + LC_AP.EyeLevel;
2431  LC_AP.Lift = (ground_sum >> 4) - (altitude_sum >> 3);
2432  altitude_sum -= (altitude_sum >> 3);   //drain the running sum. Crucial
2433  ground_sum -= (ground_sum >> 4);       //drain the running sum. Crucial
2434 }
2435 
2436 /////////////////////////////////////////////////////////////////////
2437 // LC_AutoPilot() - 030223
2438 /////////////////////////////////////////////////////////////////////
LC_AutoPilot(int Seek,int ScanWidth)2439 void LC_AutoPilot (int Seek,    //Seek=1 seeks high ground; -1 = low
2440                    int ScanWidth)       //distance from first sample to third (last) sample taken
2441 {
2442  int HeightCount1,
2443   HeightCount2 = 0;
2444  static int AutoTurn = 0;
2445  int y,
2446   x_int,
2447   y_int,
2448   x_offset,
2449   x_step,
2450   y_step;
2451  int x = -ScanWidth;
2452 
2453  // ******Start X ******
2454  do     // x is the number of rays I send
2455  {
2456   y = 10;       //length of ray
2457   HeightCount1 = 0;
2458   //next line starts my first column on the left side of screen
2459   //CAUTION: theoretically x could push it beyond one LC_CircleRez
2460   if ((x_offset = LC_Direction + x) >= LC_CircleRez)
2461    x_offset -= LC_CircleRez;
2462   else if (x_offset < 0)
2463    x_offset += LC_CircleRez;
2464   x_step = LC_Cos[x_offset] << 2;
2465   y_step = LC_Sin[x_offset] << 2;
2466   x_int = LC_PositionX;
2467   y_int = LC_PositionY;
2468   //////////////////////////////////////
2469   // ******Start Y ********
2470   do
2471   {
2472    x_int += x_step;
2473    y_int += y_step;
2474    if (y_int >= LC_BmpColorsHeight_scaled)
2475     do
2476      y_int -= LC_BmpColorsHeight_scaled;
2477     while (y_int >= LC_BmpColorsHeight_scaled);
2478    else if (y_int < 0)
2479     do
2480      y_int += LC_BmpColorsHeight_scaled;
2481     while (y_int < 0);
2482    if (x_int >= LC_BmpColorsWidth_scaled)
2483     do
2484      x_int -= LC_BmpColorsWidth_scaled;
2485     while (x_int >= LC_BmpColorsWidth_scaled);
2486    else if (x_int < 0)
2487     do
2488      x_int += LC_BmpColorsWidth_scaled;
2489     while (x_int < 0);
2490 
2491    //the important part:
2492    HeightCount1 +=
2493     LC_BmpHeights.pixel[(y_int >> LC_SHIFT) * LC_BmpHeights.w +
2494                         (x_int >> LC_SHIFT)];
2495   }
2496   while (--y);  //this is tied to refheight, so don't casually change it
2497   // ********End Y **********
2498   //////////////////////////////////////
2499   //autopilot stuff:
2500   if (x < 0)
2501    HeightCount2 = HeightCount1;
2502  }
2503  while ((x += (ScanWidth << 1)) <= ScanWidth);  // end x
2504  // *************end X **************
2505 
2506  AutoTurn += Seek * (HeightCount1 - HeightCount2);      //make positive to seek high
2507  LC_AP.Turn = (AutoTurn -= (AutoTurn >> 3)) >> 2;
2508  if (LC_AP.Turn >= LC_CircleRez)
2509   LC_AP.Turn = LC_CircleRez - 1;
2510  else if (LC_AP.Turn <= -LC_CircleRez)
2511   LC_AP.Turn = -(LC_CircleRez - 1);
2512 
2513  //now I find out which way around circle is shortest to meet the new direction:
2514  if (abs (LC_AP.Turn) > (LC_CircleRez >> 1))
2515  {
2516   if (LC_AP.Turn < 0)
2517    LC_AP.Turn = LC_CircleRez + LC_AP.Turn;
2518   else
2519    LC_AP.Turn = -(LC_CircleRez - LC_AP.Turn);
2520  }
2521 
2522  LC_AutoAlt ();
2523 }       //end LC_AutoPilot()
2524 
2525 /////////////////////////////////////////////////////////////////////
2526 //uses a dot-product to turn object towards another object
LC_FlyingObjectSeekFlyingObject(int followerId,int targetID,int circle)2527 int LC_FlyingObjectSeekFlyingObject (int followerId, int targetID, int circle)
2528 {
2529  //subtract targeter's position from target's position
2530  int ax = (LC_FlyingObject[targetID].PosX - LC_FlyingObject[followerId].PosX);
2531  int ay = (LC_FlyingObject[targetID].PosY - LC_FlyingObject[followerId].PosY);
2532  int bx = LC_Cos[LC_FlyingObject[followerId].Direction];
2533  int by = LC_Sin[LC_FlyingObject[followerId].Direction];
2534 
2535  //regular dotproduct:
2536  //(this makes it circle object)
2537  //return ax*bx+ay*by;//>>LC_DOUBLESHIFT;
2538 
2539  //dotproduct turned 90 degrees: ya * xb - xa * yb
2540  //(this makes it follow object)
2541  if (!circle)
2542   return -(ay * bx - ax * by);
2543  return -(ax * bx + ay * by);
2544 }
2545 
2546 /////////////////////////////////////////////////////////////////////
2547 //uses a dot-product to turn object towards user position
LC_FlyingObjectSeekUser(int followerId,int circle)2548 int LC_FlyingObjectSeekUser (int followerId, int circle)
2549 {
2550  //subtract targeter's position from target's position
2551  int ax = (LC_PositionX - LC_FlyingObject[followerId].PosX);
2552  int ay = (LC_PositionY - LC_FlyingObject[followerId].PosY);
2553  int bx = LC_Cos[LC_FlyingObject[followerId].Direction];
2554  int by = LC_Sin[LC_FlyingObject[followerId].Direction];
2555 
2556  //regular dotproduct:
2557  //(this makes it circle object)
2558  //return ax*bx+ay*by;//>>LC_DOUBLESHIFT;
2559 
2560  //dotproduct turned 90 degrees: ya * xb - xa * yb
2561  //(this makes it follow object)
2562  if (!circle)
2563   return -(ay * bx - ax * by);
2564  return -(ax * bx + ay * by);
2565 }
2566 
2567 /////////////////////////////////////////////////////////////////////
2568 //uses a dot-product to turn object towards a position
LC_FlyingObjectSeekPosition(int ObjID,int PosX,int PosY,int circle)2569 int LC_FlyingObjectSeekPosition (int ObjID, int PosX, int PosY, int circle)
2570 {
2571  //subtract seeker's position from sought position
2572  int ax = (PosX - LC_FlyingObject[ObjID].PosX);
2573  int ay = (PosY - LC_FlyingObject[ObjID].PosY);
2574  int bx = LC_Cos[LC_FlyingObject[ObjID].Direction];
2575  int by = LC_Sin[LC_FlyingObject[ObjID].Direction];
2576 
2577  //regular dotproduct:
2578  //(this makes it circle object)
2579  //return ax*bx+ay*by;//>>LC_DOUBLESHIFT;
2580 
2581  //dotproduct turned 90 degrees: ya * xb - xa * yb
2582  //(this makes it follow object)
2583  if (!circle)
2584   return -(ay * bx - ax * by);
2585  return -(ax * bx + ay * by);
2586 }
2587 
2588 /////////////////////////////////////////////////////////////////////
2589 // LC_TargetFollowTheLeader() - 030223
LC_TargetFollowTheLeader()2590 void LC_TargetFollowTheLeader ()        //aka BlindFollowBlind
2591 {       //this searches for targets that are still live, and links them
2592  //in to a "followtheleader" endless loop. Interesting "chaos attractor"
2593  //results, seems
2594  int i = LC_FlyingObjectCount;
2595  if (i < 3)
2596   return;       //less that two targets existent
2597  //if (LiveTargetCount<2) return;//less than two targets left
2598  int j;
2599  int firstID = -1;
2600  int foundone;
2601  while (--i > 0)
2602  {      //since 0 is always a missile...
2603   if (LC_FlyingObject[i].Type == LC_TARGET && LC_FlyingObject[i].Visible)
2604   {
2605    if (firstID < 0)
2606     firstID = i;        //this will be what the last live target follows
2607    foundone = 0;
2608    j = i;
2609    while (--j > 0)
2610    {    //look for a live target to follow:
2611     if (LC_FlyingObject[j].Type == LC_TARGET && LC_FlyingObject[j].Visible)
2612     {
2613      foundone = 1;
2614      LC_FlyingObject[i].Turn = LC_FlyingObjectSeekFlyingObject (i, j, 0) >> LC_DOUBLESHIFT;     //may want to change shift depending on landsize
2615      break;
2616     }
2617    }    //end j
2618    if (!foundone)
2619    {    //nothing to follow beneath it, so follow first
2620     LC_FlyingObject[i].Turn = LC_FlyingObjectSeekFlyingObject (i, firstID, 0) >> LC_DOUBLESHIFT;        //shift can be changed
2621     return;     //if all is good (plenty of live targets), this is function exit
2622    }
2623   }     //end was target and visible
2624  }      //end i;
2625  //should never get here...
2626 }
2627 
2628 ///////////////////////////////////////////////////////////////////////
2629 // ShowColorsMap() - this was more complicated than I expected
2630 /////////////////////////////////////////////////////////////////////
LC_ShowColorsBitmap()2631 void LC_ShowColorsBitmap ()
2632 {
2633  int x,
2634   y;
2635  double xf,
2636   yf,
2637   Step;
2638 
2639  //clear DestBitmap
2640  for (x = 0; x < LC_BmpDest.w; x++)
2641  {
2642   for (y = 0; y < LC_BmpDest.h; y++)
2643    LC_BmpDest.pixel[y * LC_BmpDest.w + x] = 0;
2644  }      //end x
2645 
2646  //use whichever is the largest step for Step:
2647  if (((double) LC_BmpColors.w / LC_BmpDest.w) >
2648      ((double) LC_BmpColors.h / LC_BmpDest.h))
2649  {
2650   Step = ((double) LC_BmpColors.w / LC_BmpDest.w);
2651  }
2652  else
2653  {
2654   Step = ((double) LC_BmpColors.h / LC_BmpDest.h);
2655  }
2656 
2657  //start the ultra-safe transfer:
2658  for (xf = 0.0, x = 0; xf < LC_BmpColors.w && x < LC_BmpDest.w;
2659       xf += Step, x++)
2660  {
2661   for (yf = 0.0, y = 0; yf < LC_BmpColors.h && y < LC_BmpDest.h;
2662        yf += Step, y++)
2663   {
2664    LC_BmpDest.pixel[y * LC_BmpDest.w + x] =
2665     LC_BmpColors.pixel[((int) yf) * LC_BmpColors.w + ((int) xf)];
2666   }     //end y
2667  }      //end x
2668 }
2669