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