1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: light.cpp
5 	Desc: light spawning code
6 
7 	Copyright 2013-2016 (c) Turning Wheel LLC, all rights reserved.
8 	See LICENSE for details.
9 
10 -------------------------------------------------------------------------------*/
11 
12 #include "main.hpp"
13 #include "light.hpp"
14 
15 /*-------------------------------------------------------------------------------
16 
17 	lightSphereShadow
18 
19 	Adds a circle of light to the lightmap at x and y with the supplied
20 	radius and intensity; casts shadows against walls
21 
22 	intensity can be from -255 to 255
23 
24 -------------------------------------------------------------------------------*/
25 
lightSphereShadow(Sint32 x,Sint32 y,Sint32 radius,Sint32 intensity)26 light_t* lightSphereShadow(Sint32 x, Sint32 y, Sint32 radius, Sint32 intensity)
27 {
28 	light_t* light;
29 	Sint32 i;
30 	Sint32 u, v, u2, v2;
31 	double a, b;
32 	Sint32 dx, dy;
33 	Sint32 dxabs, dyabs;
34 	bool wallhit;
35 	int index, z;
36 
37 	if ( intensity == 0 )
38 	{
39 		return NULL;
40 	}
41 	light = newLight(x, y, radius, intensity);
42 	intensity = std::min(std::max(-255, intensity), 255);
43 
44 	for ( v = y - radius; v <= y + radius; v++ )
45 	{
46 		for ( u = x - radius; u <= x + radius; u++ )
47 		{
48 			if ( u >= 0 && v >= 0 && u < map.width && v < map.height )
49 			{
50 				dx = u - x;
51 				dy = v - y;
52 				dxabs = abs(dx);
53 				dyabs = abs(dy);
54 				a = dyabs * .5;
55 				b = dxabs * .5;
56 				u2 = u;
57 				v2 = v;
58 				wallhit = true;
59 				index = v * MAPLAYERS + u * MAPLAYERS * map.height;
60 				for ( z = 0; z < MAPLAYERS; z++ )
61 				{
62 					if ( !map.tiles[index + z] )
63 					{
64 						wallhit = false;
65 						break;
66 					}
67 				}
68 				if ( wallhit == true )
69 				{
70 					continue;
71 				}
72 				if ( dxabs >= dyabs )   // the line is more horizontal than vertical
73 				{
74 					for ( i = 0; i < dxabs; i++ )
75 					{
76 						u2 -= sgn(dx);
77 						b += dyabs;
78 						if ( b >= dxabs )
79 						{
80 							b -= dxabs;
81 							v2 -= sgn(dy);
82 						}
83 						if ( u2 >= 0 && u2 < map.width && v2 >= 0 && v2 < map.height )
84 						{
85 							if ( map.tiles[OBSTACLELAYER + v2 * MAPLAYERS + u2 * MAPLAYERS * map.height] )
86 							{
87 								wallhit = true;
88 								break;
89 							}
90 						}
91 					}
92 				}
93 				else     // the line is more vertical than horizontal
94 				{
95 					for ( i = 0; i < dyabs; i++ )
96 					{
97 						v2 -= sgn(dy);
98 						a += dxabs;
99 						if ( a >= dyabs )
100 						{
101 							a -= dyabs;
102 							u2 -= sgn(dx);
103 						}
104 						if ( u2 >= 0 && u2 < map.width && v2 >= 0 && v2 < map.height )
105 						{
106 							if ( map.tiles[OBSTACLELAYER + v2 * MAPLAYERS + u2 * MAPLAYERS * map.height] )
107 							{
108 								wallhit = true;
109 								break;
110 							}
111 						}
112 					}
113 				}
114 				if ( wallhit == false || (wallhit == true && u2 == u && v2 == v) )
115 				{
116 					light->tiles[(dy + radius) + (dx + radius) * (radius * 2 + 1)] = intensity - intensity * std::min<float>(sqrtf(dx * dx + dy * dy) / radius, 1.0f);
117 					lightmap[v + u * map.height] += light->tiles[(dy + radius) + (dx + radius) * (radius * 2 + 1)];
118 				}
119 			}
120 		}
121 	}
122 	return light;
123 }
124 
125 /*-------------------------------------------------------------------------------
126 
127 	lightSphere
128 
129 	Adds a circle of light to the lightmap at x and y with the supplied
130 	radius and intensity; casts no shadows
131 
132 	intensity can be from -255 to 255
133 
134 -------------------------------------------------------------------------------*/
135 
lightSphere(Sint32 x,Sint32 y,Sint32 radius,Sint32 intensity)136 light_t* lightSphere(Sint32 x, Sint32 y, Sint32 radius, Sint32 intensity)
137 {
138 	light_t* light;
139 	Sint32 u, v;
140 	Sint32 dx, dy;
141 
142 	if ( intensity == 0 )
143 	{
144 		return NULL;
145 	}
146 	light = newLight(x, y, radius, intensity);
147 	intensity = std::min(std::max(-255, intensity), 255);
148 
149 	for ( v = y - radius; v <= y + radius; v++ )
150 	{
151 		for ( u = x - radius; u <= x + radius; u++ )
152 		{
153 			if ( u >= 0 && v >= 0 && u < map.width && v < map.height )
154 			{
155 				dx = u - x;
156 				dy = v - y;
157 				light->tiles[(dy + radius) + (dx + radius) * (radius * 2 + 1)] = intensity - intensity * std::min<float>(sqrtf(dx * dx + dy * dy) / radius, 1.0f);
158 				lightmap[v + u * map.height] += light->tiles[(dy + radius) + (dx + radius) * (radius * 2 + 1)];
159 			}
160 		}
161 	}
162 	return light;
163 }
164