1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: draw.cpp
5 	Desc: contains all drawing 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 "draw.hpp"
14 #include "files.hpp"
15 #include "hash.hpp"
16 #include "entity.hpp"
17 #include "player.hpp"
18 #include "editor.hpp"
19 #include "items.hpp"
20 
21 /*-------------------------------------------------------------------------------
22 
23 	getPixel
24 
25 	gets the value of a pixel at the given x,y location in the given
26 	SDL_Surface
27 
28 -------------------------------------------------------------------------------*/
29 
getPixel(SDL_Surface * surface,int x,int y)30 Uint32 getPixel(SDL_Surface* surface, int x, int y)
31 {
32 	int bpp = surface->format->BytesPerPixel;
33 	// Here p is the address to the pixel we want to retrieve
34 	Uint8* p = (Uint8*)surface->pixels + y * surface->pitch + x * bpp;
35 
36 	switch (bpp)
37 	{
38 		case 1:
39 			return *p;
40 			break;
41 
42 		case 2:
43 			return *(Uint16*)p;
44 			break;
45 
46 		case 3:
47 			if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
48 			{
49 				return p[0] << 16 | p[1] << 8 | p[2];
50 			}
51 			else
52 			{
53 				return p[0] | p[1] << 8 | p[2] << 16;
54 			}
55 			break;
56 
57 		case 4:
58 			return *(Uint32*)p;
59 			break;
60 
61 		default:
62 			return 0;	   /* shouldn't happen, but avoids warnings */
63 	}
64 }
65 
66 /*-------------------------------------------------------------------------------
67 
68 	putPixel
69 
70 	sets the value of a pixel at the given x,y location in the given
71 	SDL_Surface
72 
73 -------------------------------------------------------------------------------*/
74 
putPixel(SDL_Surface * surface,int x,int y,Uint32 pixel)75 void putPixel(SDL_Surface* surface, int x, int y, Uint32 pixel)
76 {
77 	int bpp = surface->format->BytesPerPixel;
78 	// Here p is the address to the pixel we want to set
79 	Uint8* p = (Uint8*)surface->pixels + y * surface->pitch + x * bpp;
80 
81 	switch (bpp)
82 	{
83 		case 1:
84 			*p = pixel;
85 			break;
86 
87 		case 2:
88 			*(Uint16*)p = pixel;
89 			break;
90 
91 		case 3:
92 			if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
93 			{
94 				p[0] = (pixel >> 16) & 0xff;
95 				p[1] = (pixel >> 8) & 0xff;
96 				p[2] = pixel & 0xff;
97 			}
98 			else
99 			{
100 				p[0] = pixel & 0xff;
101 				p[1] = (pixel >> 8) & 0xff;
102 				p[2] = (pixel >> 16) & 0xff;
103 			}
104 			break;
105 
106 		case 4:
107 			*(Uint32*)p = pixel;
108 			break;
109 	}
110 }
111 
112 /*-------------------------------------------------------------------------------
113 
114 	flipSurface
115 
116 	flips the contents of an SDL_Surface horizontally, vertically, or both
117 
118 -------------------------------------------------------------------------------*/
119 
flipSurface(SDL_Surface * surface,int flags)120 SDL_Surface* flipSurface( SDL_Surface* surface, int flags )
121 {
122 	SDL_Surface* flipped = NULL;
123 	Uint32 pixel;
124 	int x, rx;
125 	int y, ry;
126 
127 	// prepare surface for flipping
128 	flipped = SDL_CreateRGBSurface( SDL_SWSURFACE, surface->w, surface->h, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask );
129 	if ( SDL_MUSTLOCK( surface ) )
130 	{
131 		SDL_LockSurface( surface );
132 	}
133 	if ( SDL_MUSTLOCK( flipped ) )
134 	{
135 		SDL_LockSurface( flipped );
136 	}
137 
138 	for ( x = 0, rx = flipped->w - 1; x < flipped->w; x++, rx-- )
139 	{
140 		for ( y = 0, ry = flipped->h - 1; y < flipped->h; y++, ry-- )
141 		{
142 			pixel = getPixel( surface, x, y );
143 
144 			// copy pixel
145 			if ( ( flags & FLIP_VERTICAL ) && ( flags & FLIP_HORIZONTAL ) )
146 			{
147 				putPixel( flipped, rx, ry, pixel );
148 			}
149 			else if ( flags & FLIP_HORIZONTAL )
150 			{
151 				putPixel( flipped, rx, y, pixel );
152 			}
153 			else if ( flags & FLIP_VERTICAL )
154 			{
155 				putPixel( flipped, x, ry, pixel );
156 			}
157 		}
158 	}
159 
160 	// restore image
161 	if ( SDL_MUSTLOCK( surface ) )
162 	{
163 		SDL_UnlockSurface( surface );
164 	}
165 	if ( SDL_MUSTLOCK( flipped ) )
166 	{
167 		SDL_UnlockSurface( flipped );
168 	}
169 
170 	return flipped;
171 }
172 
173 /*-------------------------------------------------------------------------------
174 
175 	drawCircle
176 
177 	draws a circle in either an opengl or SDL context
178 
179 -------------------------------------------------------------------------------*/
180 
drawCircle(int x,int y,real_t radius,Uint32 color,Uint8 alpha)181 void drawCircle( int x, int y, real_t radius, Uint32 color, Uint8 alpha )
182 {
183 	drawArc(x, y, radius, 0, 360, color, alpha);
184 }
185 
186 /*-------------------------------------------------------------------------------
187 
188 	drawArc
189 
190 	draws an arc in either an opengl or SDL context
191 
192 -------------------------------------------------------------------------------*/
193 
drawArc(int x,int y,real_t radius,real_t angle1,real_t angle2,Uint32 color,Uint8 alpha)194 void drawArc( int x, int y, real_t radius, real_t angle1, real_t angle2, Uint32 color, Uint8 alpha )
195 {
196 	int c;
197 
198 	// update projection
199 	glDisable(GL_DEPTH_TEST);
200 	glDisable(GL_LIGHTING);
201 	glMatrixMode(GL_PROJECTION);
202 	glViewport(0, 0, xres, yres);
203 	glLoadIdentity();
204 	glOrtho(0, xres, 0, yres, -1, 1);
205 	glMatrixMode(GL_MODELVIEW);
206 	glEnable(GL_BLEND);
207 
208 	// set line width
209 	GLint lineWidth;
210 	glGetIntegerv(GL_LINE_WIDTH, &lineWidth);
211 	glLineWidth(2);
212 
213 	// draw line
214 	glColor4f(((Uint8)(color >> mainsurface->format->Rshift)) / 255.f, ((Uint8)(color >> mainsurface->format->Gshift)) / 255.f, ((Uint8)(color >> mainsurface->format->Bshift)) / 255.f, alpha / 255.f);
215 	glBindTexture(GL_TEXTURE_2D, 0);
216 	glEnable(GL_LINE_SMOOTH);
217 	glBegin(GL_LINE_STRIP);
218 	for ( c = angle1; c <= angle2; c++)
219 	{
220 		float degInRad = c * PI / 180.f;
221 		glVertex2f(x + ceil(cos(degInRad)*radius) + 1, yres - (y + ceil(sin(degInRad)*radius)));
222 	}
223 	glEnd();
224 	glDisable(GL_LINE_SMOOTH);
225 
226 	// reset line width
227 	glLineWidth(lineWidth);
228 }
229 
230 /*-------------------------------------------------------------------------------
231 
232 drawArcInvertedY, reversing the angle of direction in the y coordinate.
233 
234 draws an arc in either an opengl or SDL context
235 
236 -------------------------------------------------------------------------------*/
237 
drawArcInvertedY(int x,int y,real_t radius,real_t angle1,real_t angle2,Uint32 color,Uint8 alpha)238 void drawArcInvertedY(int x, int y, real_t radius, real_t angle1, real_t angle2, Uint32 color, Uint8 alpha)
239 {
240 	int c;
241 
242 	// update projection
243 	glDisable(GL_DEPTH_TEST);
244 	glDisable(GL_LIGHTING);
245 	glMatrixMode(GL_PROJECTION);
246 	glViewport(0, 0, xres, yres);
247 	glLoadIdentity();
248 	glOrtho(0, xres, 0, yres, -1, 1);
249 	glMatrixMode(GL_MODELVIEW);
250 	glEnable(GL_BLEND);
251 
252 	// set line width
253 	GLint lineWidth;
254 	glGetIntegerv(GL_LINE_WIDTH, &lineWidth);
255 	glLineWidth(2);
256 
257 	// draw line
258 	glColor4f(((Uint8)(color >> mainsurface->format->Rshift)) / 255.f, ((Uint8)(color >> mainsurface->format->Gshift)) / 255.f, ((Uint8)(color >> mainsurface->format->Bshift)) / 255.f, alpha / 255.f);
259 	glBindTexture(GL_TEXTURE_2D, 0);
260 	glEnable(GL_LINE_SMOOTH);
261 	glBegin(GL_LINE_STRIP);
262 	for ( c = angle1; c <= angle2; c++ )
263 	{
264 		float degInRad = c * PI / 180.f;
265 		glVertex2f(x + ceil(cos(degInRad)*radius) + 1, yres - (y - ceil(sin(degInRad)*radius)));
266 	}
267 	glEnd();
268 	glDisable(GL_LINE_SMOOTH);
269 
270 	// reset line width
271 	glLineWidth(lineWidth);
272 }
273 
274 /*-------------------------------------------------------------------------------
275 
276 	drawLine
277 
278 	draws a line in either an opengl or SDL context
279 
280 -------------------------------------------------------------------------------*/
281 
drawLine(int x1,int y1,int x2,int y2,Uint32 color,Uint8 alpha)282 void drawLine( int x1, int y1, int x2, int y2, Uint32 color, Uint8 alpha )
283 {
284 	// update projection
285 	glDisable(GL_DEPTH_TEST);
286 	glDisable(GL_LIGHTING);
287 	glMatrixMode(GL_PROJECTION);
288 	glViewport(0, 0, xres, yres);
289 	glLoadIdentity();
290 	glOrtho(0, xres, 0, yres, -1, 1);
291 	glMatrixMode(GL_MODELVIEW);
292 	glEnable(GL_BLEND);
293 
294 	// set line width
295 	GLint lineWidth;
296 	glGetIntegerv(GL_LINE_WIDTH, &lineWidth);
297 	glLineWidth(2);
298 
299 	// draw line
300 	glColor4f(((Uint8)(color >> mainsurface->format->Rshift)) / 255.f, ((Uint8)(color >> mainsurface->format->Gshift)) / 255.f, ((Uint8)(color >> mainsurface->format->Bshift)) / 255.f, alpha / 255.f);
301 	glBindTexture(GL_TEXTURE_2D, 0);
302 	glEnable(GL_LINE_SMOOTH);
303 	glBegin(GL_LINES);
304 	glVertex2f(x1 + 1, yres - y1);
305 	glVertex2f(x2 + 1, yres - y2);
306 	glEnd();
307 	glDisable(GL_LINE_SMOOTH);
308 
309 	// reset line width
310 	glLineWidth(lineWidth);
311 }
312 
313 /*-------------------------------------------------------------------------------
314 
315 	drawRect
316 
317 	draws a rectangle in either an opengl or SDL context
318 
319 -------------------------------------------------------------------------------*/
320 
drawRect(SDL_Rect * src,Uint32 color,Uint8 alpha)321 int drawRect( SDL_Rect* src, Uint32 color, Uint8 alpha )
322 {
323 	SDL_Rect secondsrc;
324 
325 	// update projection
326 	glDisable(GL_DEPTH_TEST);
327 	glDisable(GL_LIGHTING);
328 	glMatrixMode(GL_PROJECTION);
329 	glViewport(0, 0, xres, yres);
330 	glLoadIdentity();
331 	glOrtho(0, xres, 0, yres, -1, 1);
332 	glMatrixMode(GL_MODELVIEW);
333 	glEnable(GL_BLEND);
334 
335 	// for the use of the whole screen
336 	if ( src == NULL )
337 	{
338 		secondsrc.x = 0;
339 		secondsrc.y = 0;
340 		secondsrc.w = xres;
341 		secondsrc.h = yres;
342 		src = &secondsrc;
343 	}
344 
345 	// draw quad
346 	glColor4f(((Uint8)(color >> mainsurface->format->Rshift)) / 255.f, ((Uint8)(color >> mainsurface->format->Gshift)) / 255.f, ((Uint8)(color >> mainsurface->format->Bshift)) / 255.f, alpha / 255.f);
347 	glBindTexture(GL_TEXTURE_2D, 0);
348 	glBegin(GL_QUADS);
349 	glVertex2f(src->x, yres - src->y);
350 	glVertex2f(src->x, yres - src->y - src->h);
351 	glVertex2f(src->x + src->w, yres - src->y - src->h);
352 	glVertex2f(src->x + src->w, yres - src->y);
353 	glEnd();
354 	return 0;
355 }
356 
357 
358 /*-------------------------------------------------------------------------------
359 
360 	drawBox
361 
362 	draws the border of a rectangle
363 
364 -------------------------------------------------------------------------------*/
drawBox(SDL_Rect * src,Uint32 color,Uint8 alpha)365 int drawBox(SDL_Rect* src, Uint32 color, Uint8 alpha)
366 {
367 	drawLine(src->x, src->y, src->x + src->w, src->y, color, alpha); //Top.
368 	drawLine(src->x, src->y, src->x, src->y + src->h, color, alpha); //Left.
369 	drawLine(src->x + src->w, src->y, src->x + src->w, src->y + src->h, color, alpha); //Right.
370 	drawLine(src->x, src->y + src->h, src->x + src->w, src->y + src->h, color, alpha); //Bottom.
371 	return 0;
372 }
373 
374 /*-------------------------------------------------------------------------------
375 
376 	drawGear
377 
378 	draws a gear (used for turning wheel splash)
379 
380 -------------------------------------------------------------------------------*/
381 
drawGear(Sint16 x,Sint16 y,real_t size,Sint32 rotation)382 void drawGear(Sint16 x, Sint16 y, real_t size, Sint32 rotation)
383 {
384 	Uint32 color;
385 	int c;
386 	Sint16 x1, y1, x2, y2;
387 
388 	color = SDL_MapRGB(mainsurface->format, 255, 127, 0);
389 	for ( c = 0; c < 6; c++ )
390 	{
391 		drawArc(x, y, size, 0 + c * 60 + rotation, 30 + c * 60 + rotation, color, 255);
392 		drawArc(x, y, (int)ceil(size * 1.33), 30 + c * 60 + 4 + rotation, 60 + c * 60 - 4 + rotation, color, 255);
393 		x1 = ceil(size * cos((30 + c * 60 + rotation) * (PI / 180))) + x;
394 		y1 = ceil(size * sin((30 + c * 60 + rotation) * (PI / 180))) + y;
395 		x2 = ceil(size * cos((30 + c * 60 + 4 + rotation) * (PI / 180)) * 1.33) + x;
396 		y2 = ceil(size * sin((30 + c * 60 + 4 + rotation) * (PI / 180)) * 1.33) + y;
397 		drawLine(x1, y1, x2, y2, color, 255);
398 		x1 = ceil(size * cos((60 + c * 60 + rotation) * (PI / 180))) + x;
399 		y1 = ceil(size * sin((60 + c * 60 + rotation) * (PI / 180))) + y;
400 		x2 = ceil(size * cos((60 + c * 60 - 4 + rotation) * (PI / 180)) * 1.33) + x;
401 		y2 = ceil(size * sin((60 + c * 60 - 4 + rotation) * (PI / 180)) * 1.33) + y;
402 		drawLine(x1, y1, x2, y2, color, 255);
403 	}
404 	color = SDL_MapRGBA(mainsurface->format, 191, 63, 0, 255);
405 	drawCircle(x, y, size * .66, color, 255);
406 	color = SDL_MapRGBA(mainsurface->format, 127, 0, 0, 255);
407 	drawCircle(x, y, size * .25, color, 255);
408 }
409 
410 /*-------------------------------------------------------------------------------
411 
412 	drawImageRotatedAlpha
413 
414 	blits an image in either an opengl or SDL context, rotating the image
415 	relative to the screen and taking an alpha value
416 
417 -------------------------------------------------------------------------------*/
418 
drawImageRotatedAlpha(SDL_Surface * image,SDL_Rect * src,SDL_Rect * pos,real_t angle,Uint8 alpha)419 void drawImageRotatedAlpha( SDL_Surface* image, SDL_Rect* src, SDL_Rect* pos, real_t angle, Uint8 alpha )
420 {
421 	SDL_Rect secondsrc;
422 
423 	// update projection
424 	glPushMatrix();
425 	glDisable(GL_DEPTH_TEST);
426 	glMatrixMode(GL_PROJECTION);
427 	glViewport(0, 0, xres, yres);
428 	glLoadIdentity();
429 	glOrtho(0, xres, 0, yres, -1, 1);
430 	glMatrixMode(GL_MODELVIEW);
431 	glEnable(GL_BLEND);
432 	glTranslatef(pos->x, yres - pos->y, 0);
433 	glRotatef(-angle * 180 / PI, 0.f, 0.f, 1.f);
434 
435 	// for the use of a whole image
436 	if ( src == NULL )
437 	{
438 		secondsrc.x = 0;
439 		secondsrc.y = 0;
440 		secondsrc.w = image->w;
441 		secondsrc.h = image->h;
442 		src = &secondsrc;
443 	}
444 
445 	// draw a textured quad
446 	glBindTexture(GL_TEXTURE_2D, texid[image->refcount]);
447 	glColor4f(1, 1, 1, alpha / 255.1);
448 	glBegin(GL_QUADS);
449 	glTexCoord2f(1.0 * ((real_t)src->x / image->w), 1.0 * ((real_t)src->y / image->h));
450 	glVertex2f(-src->w / 2, src->h / 2);
451 	glTexCoord2f(1.0 * ((real_t)src->x / image->w), 1.0 * (((real_t)src->y + src->h) / image->h));
452 	glVertex2f(-src->w / 2, -src->h / 2);
453 	glTexCoord2f(1.0 * (((real_t)src->x + src->w) / image->w), 1.0 * (((real_t)src->y + src->h) / image->h));
454 	glVertex2f(src->w / 2, -src->h / 2);
455 	glTexCoord2f(1.0 * (((real_t)src->x + src->w) / image->w), 1.0 * ((real_t)src->y / image->h));
456 	glVertex2f(src->w / 2, src->h / 2);
457 	glEnd();
458 	glPopMatrix();
459 	glEnable(GL_DEPTH_TEST);
460 }
461 
462 /*-------------------------------------------------------------------------------
463 
464 	drawImageColor
465 
466 	blits an image in either an opengl or SDL context while colorizing it
467 
468 -------------------------------------------------------------------------------*/
469 
drawImageColor(SDL_Surface * image,SDL_Rect * src,SDL_Rect * pos,Uint32 color)470 void drawImageColor( SDL_Surface* image, SDL_Rect* src, SDL_Rect* pos, Uint32 color )
471 {
472 	SDL_Rect secondsrc;
473 
474 	// update projection
475 	glPushMatrix();
476 	glDisable(GL_DEPTH_TEST);
477 	glMatrixMode(GL_PROJECTION);
478 	glViewport(0, 0, xres, yres);
479 	glLoadIdentity();
480 	glOrtho(0, xres, 0, yres, -1, 1);
481 	glMatrixMode(GL_MODELVIEW);
482 	glEnable(GL_BLEND);
483 
484 	// for the use of a whole image
485 	if ( src == NULL )
486 	{
487 		secondsrc.x = 0;
488 		secondsrc.y = 0;
489 		secondsrc.w = image->w;
490 		secondsrc.h = image->h;
491 		src = &secondsrc;
492 	}
493 
494 	// draw a textured quad
495 	glBindTexture(GL_TEXTURE_2D, texid[image->refcount]);
496 	real_t r = ((Uint8)(color >> mainsurface->format->Rshift)) / 255.f;
497 	real_t g = ((Uint8)(color >> mainsurface->format->Gshift)) / 255.f;
498 	real_t b = ((Uint8)(color >> mainsurface->format->Bshift)) / 255.f;
499 	real_t a = ((Uint8)(color >> mainsurface->format->Ashift)) / 255.f;
500 	glColor4f(r, g, b, a);
501 	glPushMatrix();
502 	glBegin(GL_QUADS);
503 	glTexCoord2f(1.0 * ((real_t)src->x / image->w), 1.0 * ((real_t)src->y / image->h));
504 	glVertex2f(pos->x, yres - pos->y);
505 	glTexCoord2f(1.0 * ((real_t)src->x / image->w), 1.0 * (((real_t)src->y + src->h) / image->h));
506 	glVertex2f(pos->x, yres - pos->y - src->h);
507 	glTexCoord2f(1.0 * (((real_t)src->x + src->w) / image->w), 1.0 * (((real_t)src->y + src->h) / image->h));
508 	glVertex2f(pos->x + src->w, yres - pos->y - src->h);
509 	glTexCoord2f(1.0 * (((real_t)src->x + src->w) / image->w), 1.0 * ((real_t)src->y / image->h));
510 	glVertex2f(pos->x + src->w, yres - pos->y);
511 	glEnd();
512 	glPopMatrix();
513 	glEnable(GL_DEPTH_TEST);
514 }
515 
516 /*-------------------------------------------------------------------------------
517 
518 	drawImageAlpha
519 
520 	blits an image in either an opengl or SDL context, taking an alpha value
521 
522 -------------------------------------------------------------------------------*/
523 
drawImageAlpha(SDL_Surface * image,SDL_Rect * src,SDL_Rect * pos,Uint8 alpha)524 void drawImageAlpha( SDL_Surface* image, SDL_Rect* src, SDL_Rect* pos, Uint8 alpha )
525 {
526 	SDL_Rect secondsrc;
527 
528 	// update projection
529 	glPushMatrix();
530 	glDisable(GL_DEPTH_TEST);
531 	glMatrixMode(GL_PROJECTION);
532 	glViewport(0, 0, xres, yres);
533 	glLoadIdentity();
534 	glOrtho(0, xres, 0, yres, -1, 1);
535 	glMatrixMode(GL_MODELVIEW);
536 	glEnable(GL_BLEND);
537 
538 	// for the use of a whole image
539 	if ( src == NULL )
540 	{
541 		secondsrc.x = 0;
542 		secondsrc.y = 0;
543 		secondsrc.w = image->w;
544 		secondsrc.h = image->h;
545 		src = &secondsrc;
546 	}
547 
548 	// draw a textured quad
549 	glBindTexture(GL_TEXTURE_2D, texid[image->refcount]);
550 	glColor4f(1, 1, 1, alpha / 255.1);
551 	glPushMatrix();
552 	glBegin(GL_QUADS);
553 	glTexCoord2f(1.0 * ((real_t)src->x / image->w), 1.0 * ((real_t)src->y / image->h));
554 	glVertex2f(pos->x, yres - pos->y);
555 	glTexCoord2f(1.0 * ((real_t)src->x / image->w), 1.0 * (((real_t)src->y + src->h) / image->h));
556 	glVertex2f(pos->x, yres - pos->y - src->h);
557 	glTexCoord2f(1.0 * (((real_t)src->x + src->w) / image->w), 1.0 * (((real_t)src->y + src->h) / image->h));
558 	glVertex2f(pos->x + src->w, yres - pos->y - src->h);
559 	glTexCoord2f(1.0 * (((real_t)src->x + src->w) / image->w), 1.0 * ((real_t)src->y / image->h));
560 	glVertex2f(pos->x + src->w, yres - pos->y);
561 	glEnd();
562 	glPopMatrix();
563 	glEnable(GL_DEPTH_TEST);
564 }
565 
566 /*-------------------------------------------------------------------------------
567 
568 	drawImage
569 
570 	blits an image in either an opengl or SDL context
571 
572 -------------------------------------------------------------------------------*/
573 
drawImage(SDL_Surface * image,SDL_Rect * src,SDL_Rect * pos)574 void drawImage( SDL_Surface* image, SDL_Rect* src, SDL_Rect* pos )
575 {
576 	SDL_Rect secondsrc;
577 
578 	// update projection
579 	glPushMatrix();
580 	glDisable(GL_DEPTH_TEST);
581 	glMatrixMode(GL_PROJECTION);
582 	glViewport(0, 0, xres, yres);
583 	glLoadIdentity();
584 	glOrtho(0, xres, 0, yres, -1, 1);
585 	glMatrixMode(GL_MODELVIEW);
586 	glEnable(GL_BLEND);
587 
588 	// for the use of a whole image
589 	if ( src == NULL )
590 	{
591 		secondsrc.x = 0;
592 		secondsrc.y = 0;
593 		secondsrc.w = image->w;
594 		secondsrc.h = image->h;
595 		src = &secondsrc;
596 	}
597 
598 	// draw a textured quad
599 	glBindTexture(GL_TEXTURE_2D, texid[image->refcount]);
600 	glColor4f(1, 1, 1, 1);
601 	glPushMatrix();
602 	glBegin(GL_QUADS);
603 	glTexCoord2f(1.0 * ((real_t)src->x / image->w), 1.0 * ((real_t)src->y / image->h));
604 	glVertex2f(pos->x, yres - pos->y);
605 	glTexCoord2f(1.0 * ((real_t)src->x / image->w), 1.0 * (((real_t)src->y + src->h) / image->h));
606 	glVertex2f(pos->x, yres - pos->y - src->h);
607 	glTexCoord2f(1.0 * (((real_t)src->x + src->w) / image->w), 1.0 * (((real_t)src->y + src->h) / image->h));
608 	glVertex2f(pos->x + src->w, yres - pos->y - src->h);
609 	glTexCoord2f(1.0 * (((real_t)src->x + src->w) / image->w), 1.0 * ((real_t)src->y / image->h));
610 	glVertex2f(pos->x + src->w, yres - pos->y);
611 	glEnd();
612 	glPopMatrix();
613 	glEnable(GL_DEPTH_TEST);
614 }
615 
616 /*-------------------------------------------------------------------------------
617 
618 drawImageRing
619 
620 blits an image in either an opengl or SDL context into a 2d ring.
621 
622 -------------------------------------------------------------------------------*/
623 
drawImageRing(SDL_Surface * image,SDL_Rect * src,int radius,int thickness,int segments,real_t angStart,real_t angEnd,Uint8 alpha)624 void drawImageRing(SDL_Surface* image, SDL_Rect* src, int radius, int thickness, int segments, real_t angStart, real_t angEnd, Uint8 alpha)
625 {
626 	SDL_Rect secondsrc;
627 
628 	// update projection
629 	glPushMatrix();
630 	glDisable(GL_DEPTH_TEST);
631 	glMatrixMode(GL_PROJECTION);
632 	glViewport(0, 0, xres, yres);
633 	glLoadIdentity();
634 	glOrtho(0, xres, 0, yres, -1, 1);
635 	glMatrixMode(GL_MODELVIEW);
636 	glEnable(GL_BLEND);
637 
638 	// for the use of a whole image
639 	if ( src == NULL )
640 	{
641 		secondsrc.x = 0;
642 		secondsrc.y = 0;
643 		secondsrc.w = image->w;
644 		secondsrc.h = image->h;
645 		src = &secondsrc;
646 	}
647 
648 	// draw a textured quad
649 	glBindTexture(GL_TEXTURE_2D, texid[image->refcount]);
650 	glColor4f(1, 1, 1, alpha / 255.f);
651 	glPushMatrix();
652 
653 	double s;
654 	real_t arcAngle = angStart;
655 	int first = segments / 2;
656 	real_t distance = std::round((angEnd - angStart) * segments / (2 * PI));
657 	for ( int i = 0; i < first; ++i )
658 	{
659 		glBegin(GL_QUAD_STRIP);
660 		for ( int j = 0; j <= static_cast<int>(distance); ++j )
661 		{
662 			s = i % first + 0.01;
663 			arcAngle = ((j % segments) * 2 * PI / segments) + angStart; // angle of the line.
664 
665 			real_t arcx1 = (radius + thickness * cos(s * 2 * PI / first)) * cos(arcAngle);
666 			real_t arcy1 = (radius + thickness * cos(s * 2 * PI / first)) * sin(arcAngle);
667 
668 			s = (i + 1) % first + 0.01;
669 			real_t arcx2 = (radius + thickness * cos(s * 2 * PI / first)) * cos(arcAngle);
670 			real_t arcy2 = (radius + thickness * cos(s * 2 * PI / first)) * sin(arcAngle);
671 			//glTexCoord2f(1.f, 0.f);
672 			glVertex2f(xres / 2 + arcx1, yres / 2 + arcy1);
673 			//glTexCoord2f(0.f, 1.f);
674 			glVertex2f(xres / 2 + arcx2, yres / 2 + arcy2);
675 			//s = i % first + 0.01;
676 			//arcAngle = (((j + 1) % segments) * 2 * PI / segments) + angStart; // angle of the line.
677 			//real_t arcx3 = (radius + thickness * cos(s * 2 * PI / first)) * cos(arcAngle);
678 			//real_t arcy3 = (radius + thickness * cos(s * 2 * PI / first)) * sin(arcAngle);
679 
680 			//s = (i + 1) % first + 0.01;
681 			//real_t arcx4 = (radius + thickness * cos(s * 2 * PI / first)) * cos(arcAngle);
682 			//real_t arcy4 = (radius + thickness * cos(s * 2 * PI / first)) * sin(arcAngle);
683 
684 			//std::vector<std::pair<real_t, real_t>> xycoords;
685 			//xycoords.push_back(std::make_pair(arcx1, arcy1));
686 			//xycoords.push_back(std::make_pair(arcx2, arcy2));
687 			//xycoords.push_back(std::make_pair(arcx3, arcy3));
688 			//xycoords.push_back(std::make_pair(arcx4, arcy4));
689 			//std::sort(xycoords.begin(), xycoords.end());
690 			//if ( xycoords.at(2).second < xycoords.at(3).second )
691 			//{
692 			//	glTexCoord2f(1.f, 0.f);
693 			//	glVertex2f(xres / 2 + xycoords.at(2).first, yres / 2 + xycoords.at(2).second); // lower right.
694 			//	glTexCoord2f(1.f, 1.f);
695 			//	glVertex2f(xres / 2 + xycoords.at(3).first, yres / 2 + xycoords.at(3).second); // upper right.
696 			//}
697 			//else
698 			//{
699 			//	glTexCoord2f(1.f, 0.f);
700 			//	glVertex2f(xres / 2 + xycoords.at(3).first, yres / 2 + xycoords.at(3).second); // lower right.
701 			//	glTexCoord2f(1.f, 1.f);
702 			//	glVertex2f(xres / 2 + xycoords.at(2).first, yres / 2 + xycoords.at(2).second); // upper right.
703 			//}
704 			//if ( xycoords.at(0).second < xycoords.at(1).second )
705 			//{
706 			//	glTexCoord2f(0.f, 0.f);
707 			//	glVertex2f(xres / 2 + xycoords.at(0).first, yres / 2 + xycoords.at(0).second); // lower left.
708 			//	glTexCoord2f(0.f, 1.f);
709 			//	glVertex2f(xres / 2 + xycoords.at(1).first, yres / 2 + xycoords.at(1).second); // upper left.
710 			//}
711 			//else
712 			//{
713 			//	glTexCoord2f(0.f, 0.f);
714 			//	glVertex2f(xres / 2 + xycoords.at(1).first, yres / 2 + xycoords.at(1).second); // lower left.
715 			//	glTexCoord2f(0.f, 1.f);
716 			//	glVertex2f(xres / 2 + xycoords.at(0).first, yres / 2 + xycoords.at(0).second); // upper left.
717 			//}
718 
719 
720 			//glVertex2f(xres / 2 + arcx3, yres / 2 + arcy3);
721 			//glVertex2f(xres / 2 + arcx4, yres / 2 + arcy4);
722 		}
723 		glEnd();
724 	}
725 	glPopMatrix();
726 	// debug lines
727 	/*real_t x1 = xres / 2 + 300 * cos(angStart);
728 	real_t y1 = yres / 2 - 300 * sin(angStart);
729 	real_t x2 = xres / 2 + 300 * cos(angEnd);
730 	real_t y2 = yres / 2 - 300 * sin(angEnd);
731 	drawLine(xres / 2, yres / 2, x1, y1, 0xFFFFFFFF, 255);
732 	drawLine(xres / 2, yres / 2, x2, y2, 0xFFFFFFFF, 255);*/
733 	glEnable(GL_DEPTH_TEST);
734 }
735 
736 /*-------------------------------------------------------------------------------
737 
738 	drawImageScaled
739 
740 	blits an image in either an opengl or SDL context, scaling it
741 
742 -------------------------------------------------------------------------------*/
743 
drawImageScaled(SDL_Surface * image,SDL_Rect * src,SDL_Rect * pos)744 void drawImageScaled( SDL_Surface* image, SDL_Rect* src, SDL_Rect* pos )
745 {
746 	SDL_Rect secondsrc;
747 
748 	if ( !image )
749 	{
750 		return;
751 	}
752 
753 	// update projection
754 	glPushMatrix();
755 	glDisable(GL_DEPTH_TEST);
756 	glMatrixMode(GL_PROJECTION);
757 	glViewport(0, 0, xres, yres);
758 	glLoadIdentity();
759 	glOrtho(0, xres, 0, yres, -1, 1);
760 	glMatrixMode(GL_MODELVIEW);
761 	glEnable(GL_BLEND);
762 
763 	// for the use of a whole image
764 	if ( src == NULL )
765 	{
766 		secondsrc.x = 0;
767 		secondsrc.y = 0;
768 		secondsrc.w = image->w;
769 		secondsrc.h = image->h;
770 		src = &secondsrc;
771 	}
772 
773 	// draw a textured quad
774 	glBindTexture(GL_TEXTURE_2D, texid[image->refcount]);
775 	glColor4f(1, 1, 1, 1);
776 	glPushMatrix();
777 	glBegin(GL_QUADS);
778 	glTexCoord2f(0.f, 0.f);
779 	glVertex2f(pos->x, yres - pos->y);
780 	glTexCoord2f(0.f, 1.f);
781 	glVertex2f(pos->x, yres - pos->y - pos->h);
782 	glTexCoord2f(1.f, 1.f);
783 	glVertex2f(pos->x + pos->w, yres - pos->y - pos->h);
784 	glTexCoord2f(1.f, 0.f);
785 	glVertex2f(pos->x + pos->w, yres - pos->y);
786 	glEnd();
787 	glPopMatrix();
788 	glEnable(GL_DEPTH_TEST);
789 }
790 
791 /*-------------------------------------------------------------------------------
792 
793 drawImageScaledPartial
794 
795 blits an image in either an opengl or SDL context, scaling it
796 
797 -------------------------------------------------------------------------------*/
798 
drawImageScaledPartial(SDL_Surface * image,SDL_Rect * src,SDL_Rect * pos,float percentY)799 void drawImageScaledPartial(SDL_Surface* image, SDL_Rect* src, SDL_Rect* pos, float percentY)
800 {
801 	SDL_Rect secondsrc;
802 
803 	if ( !image )
804 	{
805 		return;
806 	}
807 
808 	// update projection
809 	glPushMatrix();
810 	glDisable(GL_DEPTH_TEST);
811 	glMatrixMode(GL_PROJECTION);
812 	glViewport(0, 0, xres, yres);
813 	glLoadIdentity();
814 	glOrtho(0, xres, 0, yres, -1, 1);
815 	glMatrixMode(GL_MODELVIEW);
816 	glEnable(GL_BLEND);
817 
818 	// for the use of a whole image
819 	if ( src == NULL )
820 	{
821 		secondsrc.x = 0;
822 		secondsrc.y = 0;
823 		secondsrc.w = image->w;
824 		secondsrc.h = image->h;
825 		src = &secondsrc;
826 	}
827 
828 	// draw a textured quad
829 	glBindTexture(GL_TEXTURE_2D, texid[image->refcount]);
830 	glColor4f(1, 1, 1, 1);
831 	glPushMatrix();
832 	glBegin(GL_QUADS);
833 	glTexCoord2f(0.f, 1.f - 1.f * percentY); // top left.
834 	glVertex2f(pos->x, yres - pos->y - pos->h + pos->h * percentY);
835 
836 	glTexCoord2f(0.f, 1.f); // bottom left
837 	glVertex2f(pos->x, yres - pos->y - pos->h);
838 
839 	glTexCoord2f(1.f, 1.f); // bottom right
840 	glVertex2f(pos->x + pos->w, yres - pos->y - pos->h);
841 
842 	glTexCoord2f(1.f, 1.f - 1.f * percentY); // top right
843 	glVertex2f(pos->x + pos->w, yres - pos->y - pos->h + pos->h * percentY);
844 	glEnd();
845 	glPopMatrix();
846 	glEnable(GL_DEPTH_TEST);
847 
848 	// debug corners
849 	//Uint32 color = SDL_MapRGB(mainsurface->format, 64, 255, 64); // green
850 	//drawCircle(pos->x, pos->y + (pos->h - (pos->h * percentY)), 5, color, 255);
851 	//color = SDL_MapRGB(mainsurface->format, 204, 121, 167); // pink
852 	//drawCircle(pos->x, pos->y + pos->h, 5, color, 255);
853 	//color = SDL_MapRGB(mainsurface->format, 86, 180, 233); // sky blue
854 	//drawCircle(pos->x + pos->w, pos->y + pos->h, 5, color, 255);
855 	//color = SDL_MapRGB(mainsurface->format, 240, 228, 66); // yellow
856 	//drawCircle(pos->x + pos->w, pos->y + (pos->h - (pos->h * percentY)), 5, color, 255);
857 }
858 
859 /*-------------------------------------------------------------------------------
860 
861 drawImageScaledColor
862 
863 blits an image in either an opengl or SDL context while colorizing and scaling it
864 
865 -------------------------------------------------------------------------------*/
866 
drawImageScaledColor(SDL_Surface * image,SDL_Rect * src,SDL_Rect * pos,Uint32 color)867 void drawImageScaledColor(SDL_Surface* image, SDL_Rect* src, SDL_Rect* pos, Uint32 color)
868 {
869 	SDL_Rect secondsrc;
870 
871 	// update projection
872 	glPushMatrix();
873 	glDisable(GL_DEPTH_TEST);
874 	glMatrixMode(GL_PROJECTION);
875 	glViewport(0, 0, xres, yres);
876 	glLoadIdentity();
877 	glOrtho(0, xres, 0, yres, -1, 1);
878 	glMatrixMode(GL_MODELVIEW);
879 	glEnable(GL_BLEND);
880 
881 	// for the use of a whole image
882 	if ( src == NULL )
883 	{
884 		secondsrc.x = 0;
885 		secondsrc.y = 0;
886 		secondsrc.w = image->w;
887 		secondsrc.h = image->h;
888 		src = &secondsrc;
889 	}
890 
891 	// draw a textured quad
892 	glBindTexture(GL_TEXTURE_2D, texid[image->refcount]);
893 	real_t r = ((Uint8)(color >> mainsurface->format->Rshift)) / 255.f;
894 	real_t g = ((Uint8)(color >> mainsurface->format->Gshift)) / 255.f;
895 	real_t b = ((Uint8)(color >> mainsurface->format->Bshift)) / 255.f;
896 	real_t a = ((Uint8)(color >> mainsurface->format->Ashift)) / 255.f;
897 	glColor4f(r, g, b, a);
898 	glPushMatrix();
899 	glBegin(GL_QUADS);
900 	glTexCoord2f(0.f, 0.f);
901 	glVertex2f(pos->x, yres - pos->y);
902 	glTexCoord2f(0.f, 1.f);
903 	glVertex2f(pos->x, yres - pos->y - pos->h);
904 	glTexCoord2f(1.f, 1.f);
905 	glVertex2f(pos->x + pos->w, yres - pos->y - pos->h);
906 	glTexCoord2f(1.f, 0.f);
907 	glVertex2f(pos->x + pos->w, yres - pos->y);
908 	glEnd();
909 	glPopMatrix();
910 	glEnable(GL_DEPTH_TEST);
911 }
912 
913 /*-------------------------------------------------------------------------------
914 
915 	scaleSurface
916 
917 	Scales an SDL_Surface to the given width and height.
918 
919 -------------------------------------------------------------------------------*/
920 
scaleSurface(SDL_Surface * Surface,Uint16 Width,Uint16 Height)921 SDL_Surface* scaleSurface(SDL_Surface* Surface, Uint16 Width, Uint16 Height)
922 {
923 	Sint32 x, y, o_x, o_y;
924 
925 	if (!Surface || !Width || !Height)
926 	{
927 		return NULL;
928 	}
929 
930 	SDL_Surface* _ret = SDL_CreateRGBSurface(Surface->flags, Width, Height, Surface->format->BitsPerPixel, Surface->format->Rmask, Surface->format->Gmask, Surface->format->Bmask, Surface->format->Amask);
931 
932 	real_t _stretch_factor_x = (real_t)Width / (real_t)Surface->w;
933 	real_t _stretch_factor_y = (real_t)Height / (real_t)Surface->h;
934 
935 	for (y = 0; y < Surface->h; y++)
936 		for (x = 0; x < Surface->w; x++)
937 			for (o_y = 0; o_y < _stretch_factor_y; ++o_y)
938 				for (o_x = 0; o_x < _stretch_factor_x; ++o_x)
939 				{
940 					putPixel(_ret, (Sint32)(_stretch_factor_x * x) + o_x, (Sint32)(_stretch_factor_y * y) + o_y, getPixel(Surface, x, y));
941 				}
942 
943 	free(Surface);
944 	return _ret;
945 }
946 
947 /*-------------------------------------------------------------------------------
948 
949 	drawImageFancy
950 
951 	blits an image in either an opengl or SDL context, while coloring,
952 	rotating, and scaling it
953 
954 -------------------------------------------------------------------------------*/
955 
drawImageFancy(SDL_Surface * image,Uint32 color,real_t angle,SDL_Rect * src,SDL_Rect * pos)956 void drawImageFancy( SDL_Surface* image, Uint32 color, real_t angle, SDL_Rect* src, SDL_Rect* pos )
957 {
958 	SDL_Rect secondsrc;
959 
960 	if ( !image )
961 	{
962 		return;
963 	}
964 
965 	// update projection
966 	glPushMatrix();
967 	glDisable(GL_DEPTH_TEST);
968 	glMatrixMode(GL_PROJECTION);
969 	glViewport(0, 0, xres, yres);
970 	glLoadIdentity();
971 	glOrtho(0, xres, 0, yres, -1, 1);
972 	glMatrixMode(GL_MODELVIEW);
973 	glEnable(GL_BLEND);
974 	glTranslatef(pos->x, yres - pos->y, 0);
975 	glRotatef(-angle * 180 / PI, 0.f, 0.f, 1.f);
976 
977 	// for the use of a whole image
978 	if ( src == NULL )
979 	{
980 		secondsrc.x = 0;
981 		secondsrc.y = 0;
982 		secondsrc.w = image->w;
983 		secondsrc.h = image->h;
984 		src = &secondsrc;
985 	}
986 
987 	// draw a textured quad
988 	glBindTexture(GL_TEXTURE_2D, texid[image->refcount]);
989 	real_t r = ((Uint8)(color >> mainsurface->format->Rshift)) / 255.f;
990 	real_t g = ((Uint8)(color >> mainsurface->format->Gshift)) / 255.f;
991 	real_t b = ((Uint8)(color >> mainsurface->format->Bshift)) / 255.f;
992 	real_t a = ((Uint8)(color >> mainsurface->format->Ashift)) / 255.f;
993 	glColor4f(r, g, b, a);
994 	glPushMatrix();
995 	glBegin(GL_QUADS);
996 	glTexCoord2f(((real_t)src->x) / ((real_t)image->w), ((real_t)src->y) / ((real_t)image->h));
997 	glVertex2f(0, 0);
998 	glTexCoord2f(((real_t)src->x) / ((real_t)image->w), ((real_t)(src->y + src->h)) / ((real_t)image->h));
999 	glVertex2f(0, -pos->h);
1000 	glTexCoord2f(((real_t)(src->x + src->w)) / ((real_t)image->w), ((real_t)(src->y + src->h)) / ((real_t)image->h));
1001 	glVertex2f(pos->w, -pos->h);
1002 	glTexCoord2f(((real_t)(src->x + src->w)) / ((real_t)image->w), ((real_t)src->y) / ((real_t)image->h));
1003 	glVertex2f(pos->w, 0);
1004 	glEnd();
1005 	glPopMatrix();
1006 	glEnable(GL_DEPTH_TEST);
1007 }
1008 
1009 /*-------------------------------------------------------------------------------
1010 
1011 	drawSky3D
1012 
1013 	Draws the sky as an image whose position depends upon the given camera
1014 	position
1015 
1016 -------------------------------------------------------------------------------*/
1017 
drawSky3D(view_t * camera,SDL_Surface * tex)1018 void drawSky3D( view_t* camera, SDL_Surface* tex )
1019 {
1020 	real_t screenfactor;
1021 	int skyx, skyy;
1022 	SDL_Rect dest;
1023 	SDL_Rect src;
1024 
1025 	// move the images differently depending upon the screen size
1026 	screenfactor = xres / 320.0;
1027 
1028 	// bitmap offsets
1029 	skyx = -camera->ang * ((320 * screenfactor) / (PI / 2.0));
1030 	skyy = (-114 * screenfactor - camera->vang);
1031 
1032 	src.x = -skyx;
1033 	src.y = -skyy;
1034 	src.w = (-skyx) + xres; // clip to the screen width
1035 	src.h = (-skyy) + yres; // clip to the screen height
1036 	dest.x = 0;
1037 	dest.y = 0;
1038 	dest.w = xres;
1039 	dest.h = yres;
1040 
1041 	drawImage(tex, &src, &dest);
1042 
1043 	// draw the part of the last part of the sky (only appears when angle > 270 deg.)
1044 	if ( skyx < -960 * screenfactor )
1045 	{
1046 		dest.x = 1280 * screenfactor + skyx;
1047 		dest.y = 0;
1048 		dest.w = xres;
1049 		dest.h = yres;
1050 		src.x = 0;
1051 		src.y = -skyy;
1052 		src.w = xres - (-skyx - 1280 * screenfactor);
1053 		src.h = src.y + yres;
1054 		drawImage(tex, &src, &dest);
1055 	}
1056 }
1057 
1058 /*-------------------------------------------------------------------------------
1059 
1060 	drawLayer / drawBackground / drawForeground
1061 
1062 	Draws the world tiles that are viewable at the given camera coordinates
1063 
1064 -------------------------------------------------------------------------------*/
1065 
drawLayer(long camx,long camy,int z,map_t * map)1066 void drawLayer(long camx, long camy, int z, map_t* map)
1067 {
1068 	long x, y;
1069 	long minx, miny, maxx, maxy;
1070 	int index;
1071 	SDL_Rect pos;
1072 
1073 	minx = std::max<long int>(camx >> TEXTUREPOWER, 0);
1074 	maxx = std::min<long int>((camx >> TEXTUREPOWER) + xres / TEXTURESIZE + 2, map->width); //TODO: Why are long int and unsigned int being compared?
1075 	miny = std::max<long int>(camy >> TEXTUREPOWER, 0);
1076 	maxy = std::min<long int>((camy >> TEXTUREPOWER) + yres / TEXTURESIZE + 2, map->height); //TODO: Why are long int and unsigned int being compared?
1077 	for ( y = miny; y < maxy; y++ )
1078 	{
1079 		for ( x = minx; x < maxx; x++ )
1080 		{
1081 			index = map->tiles[z + y * MAPLAYERS + x * MAPLAYERS * map->height];
1082 			if ( index > 0)
1083 			{
1084 				pos.x = (x << TEXTUREPOWER) - camx;
1085 				pos.y = (y << TEXTUREPOWER) - camy;
1086 				pos.w = TEXTURESIZE;
1087 				pos.h = TEXTURESIZE;
1088 				if ( index >= 0 && index < numtiles )
1089 				{
1090 					if ( tiles[index] != NULL )
1091 					{
1092 						drawImageScaled(tiles[index], NULL, &pos);
1093 					}
1094 					else
1095 					{
1096 						drawImageScaled(sprites[0], NULL, &pos);
1097 					}
1098 				}
1099 				else
1100 				{
1101 					drawImageScaled(sprites[0], NULL, &pos);
1102 				}
1103 			}
1104 		}
1105 	}
1106 }
1107 
drawBackground(long camx,long camy)1108 void drawBackground(long camx, long camy)
1109 {
1110 	long z;
1111 	for ( z = 0; z < OBSTACLELAYER; z++ )
1112 	{
1113 		drawLayer(camx, camy, z, &map);
1114 	}
1115 }
1116 
drawForeground(long camx,long camy)1117 void drawForeground(long camx, long camy)
1118 {
1119 	long z;
1120 	for ( z = OBSTACLELAYER; z < MAPLAYERS; z++ )
1121 	{
1122 		drawLayer(camx, camy, z, &map);
1123 	}
1124 }
1125 
1126 /*-------------------------------------------------------------------------------
1127 
1128 	drawClearBuffers
1129 
1130 	clears the screen and resets zbuffer and vismap
1131 
1132 -------------------------------------------------------------------------------*/
1133 
drawClearBuffers()1134 void drawClearBuffers()
1135 {
1136 	// empty video and input buffers
1137 	if ( zbuffer != NULL )
1138 	{
1139 		memset( zbuffer, 0, xres * yres * sizeof(real_t) );
1140 	}
1141 	if ( clickmap != NULL )
1142 	{
1143 		memset( clickmap, 0, xres * yres * sizeof(Entity*) );
1144 	}
1145 	if ( vismap != NULL )
1146 	{
1147 		int c, i = map.width * map.height;
1148 		for ( c = 0; c < i; c++ )
1149 		{
1150 			vismap[c] = false;
1151 		}
1152 	}
1153 
1154 	// clear the screen
1155 	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
1156 	drawRect(NULL, 0, 255);
1157 }
1158 
1159 /*-------------------------------------------------------------------------------
1160 
1161 	raycast
1162 
1163 	Performs raycasting from the given camera's position through the
1164 	environment to update minimap and vismap
1165 
1166 -------------------------------------------------------------------------------*/
1167 
raycast(view_t * camera,int mode,bool updateVismap)1168 void raycast(view_t* camera, int mode, bool updateVismap)
1169 {
1170 	long posx, posy;
1171 	real_t fracx, fracy;
1172 	long inx, iny, inx2, iny2;
1173 	real_t rx, ry;
1174 	real_t d, dstart, dend;
1175 	long sx;
1176 	real_t arx, ary;
1177 	long dincx, dincy;
1178 	real_t dval0, dval1;
1179 
1180 	Uint8 light;
1181 	Sint32 z;
1182 	bool zhit[MAPLAYERS], wallhit;
1183 
1184 	posx = floor(camera->x);
1185 	posy = floor(camera->y); // integer coordinates
1186 	fracx = camera->x - posx;
1187 	fracy = camera->y - posy; // fraction coordinates
1188 
1189 	real_t wfov = (fov * camera->winw / camera->winh) * PI / 180.f;
1190 	dstart = CLIPNEAR / 16.0;
1191 
1192 	// ray vector
1193 	rx = cos(camera->ang - wfov / 2.f);
1194 	ry = sin(camera->ang - wfov / 2.f);
1195 
1196 	if ( updateVismap && posx >= 0 && posy >= 0 && posx < map.width && posy < map.height )
1197 	{
1198 		vismap[posy + posx * map.height] = true;
1199 	}
1200 	for ( sx = 0; sx < camera->winw; sx++ )   // for every column of the screen
1201 	{
1202 		inx = posx;
1203 		iny = posy;
1204 		inx2 = inx;
1205 		iny2 = iny;
1206 
1207 		arx = 0;
1208 		if (rx)
1209 		{
1210 			arx = 1.0 / fabs(rx);  // distance increments
1211 		}
1212 		ary = 0;
1213 		if (ry)
1214 		{
1215 			ary = 1.0 / fabs(ry);
1216 		}
1217 
1218 		// dval0=dend+1 is there to prevent infinite loops when ray is parallel to axis
1219 		dincx = 0;
1220 		dval0 = 1e32;
1221 		dincy = 0;
1222 		dval1 = 1e32;
1223 
1224 		// calculate integer coordinate increments
1225 		// x-axis:
1226 		if (rx < 0)
1227 		{
1228 			dincx = -1;
1229 			dval0 = fracx * arx;
1230 		}
1231 		else if (rx > 0)
1232 		{
1233 			dincx = 1;
1234 			dval0 = (1 - fracx) * arx;
1235 		}
1236 
1237 		// y-axis:
1238 		if (ry < 0)
1239 		{
1240 			dincy = -1;
1241 			dval1 = fracy * ary;
1242 		}
1243 		else if (ry > 0)
1244 		{
1245 			dincy = 1;
1246 			dval1 = (1 - fracy) * ary;
1247 		}
1248 
1249 		d = 0;
1250 		dend = CLIPFAR / 16;
1251 		do
1252 		{
1253 			inx2 = inx;
1254 			iny2 = iny;
1255 
1256 			// move the ray one square forward
1257 			if (dval1 > dval0)
1258 			{
1259 				inx += dincx;
1260 				d = dval0;
1261 				dval0 += arx;
1262 			}
1263 			else
1264 			{
1265 				iny += dincy;
1266 				d = dval1;
1267 				dval1 += ary;
1268 			}
1269 
1270 			if ( inx >= 0 && iny >= 0 && inx < map.width && iny < map.height )
1271 			{
1272 				if ( updateVismap )
1273 				{
1274 					vismap[iny + inx * map.height] = true;
1275 				}
1276 				for ( z = 0; z < MAPLAYERS; z++ )
1277 				{
1278 					zhit[z] = false;
1279 					if ( map.tiles[z + iny * MAPLAYERS + inx * MAPLAYERS * map.height] && d > dstart )   // hit something solid
1280 					{
1281 						zhit[z] = true;
1282 
1283 						// collect light information
1284 						if ( inx2 >= 0 && iny2 >= 0 && inx2 < map.width && iny2 < map.height )
1285 						{
1286 							if ( map.tiles[z + iny2 * MAPLAYERS + inx2 * MAPLAYERS * map.height] )
1287 							{
1288 								continue;
1289 							}
1290 							light = std::min(std::max(0, lightmap[iny2 + inx2 * map.height]), 255);
1291 						}
1292 						else
1293 						{
1294 							light = 128;
1295 						}
1296 
1297 						// update minimap
1298 						if ( mode == REALCOLORS )
1299 							if ( d < 16 && z == OBSTACLELAYER )
1300 								if ( light > 0 )
1301 								{
1302 									minimap[iny][inx] = 2;  // wall space
1303 								}
1304 					}
1305 					else if ( z == OBSTACLELAYER && mode == REALCOLORS )
1306 					{
1307 						// update minimap to show empty region
1308 						if ( inx >= 0 && iny >= 0 && inx < map.width && iny < map.height )
1309 						{
1310 							light = std::min(std::max(0, lightmap[iny + inx * map.height]), 255);
1311 						}
1312 						else
1313 						{
1314 							light = 128;
1315 						}
1316 						if ( d < 16 )
1317 						{
1318 							if ( light > 0 && map.tiles[iny * MAPLAYERS + inx * MAPLAYERS * map.height] )
1319 							{
1320 								minimap[iny][inx] = 1;  // walkable space
1321 							}
1322 							else if ( map.tiles[z + iny * MAPLAYERS + inx * MAPLAYERS * map.height] )
1323 							{
1324 								minimap[iny][inx] = 0;  // no floor
1325 							}
1326 						}
1327 					}
1328 				}
1329 				wallhit = true;
1330 				for ( z = 0; z < MAPLAYERS; z++ )
1331 					if ( zhit[z] == false )
1332 					{
1333 						wallhit = false;
1334 					}
1335 				if ( wallhit == true )
1336 				{
1337 					break;
1338 				}
1339 			}
1340 		}
1341 		while (d < dend);
1342 
1343 		// new ray vector for next column
1344 		rx = cos(camera->ang - wfov / 2.f + (wfov / camera->winw) * sx);
1345 		ry = sin(camera->ang - wfov / 2.f + (wfov / camera->winw) * sx);
1346 	}
1347 }
1348 
1349 /*-------------------------------------------------------------------------------
1350 
1351 	drawEntities3D
1352 
1353 	Draws all entities in the level as either voxel models or sprites
1354 
1355 -------------------------------------------------------------------------------*/
1356 
drawEntities3D(view_t * camera,int mode)1357 void drawEntities3D(view_t* camera, int mode)
1358 {
1359 	node_t* node;
1360 	Entity* entity;
1361 	long x, y;
1362 
1363 	if ( map.entities->first == nullptr )
1364 	{
1365 		return;
1366 	}
1367 
1368 	glEnable(GL_SCISSOR_TEST);
1369 	glScissor(camera->winx, yres - camera->winh - camera->winy, camera->winw, camera->winh);
1370 
1371 	for ( node = map.entities->first; node != nullptr; node = node->next )
1372 	{
1373 		entity = (Entity*)node->element;
1374 		if ( entity->flags[INVISIBLE] )
1375 		{
1376 			continue;
1377 		}
1378 		if ( entity->flags[UNCLICKABLE] && mode == ENTITYUIDS )
1379 		{
1380 			continue;
1381 		}
1382 		if ( entity->flags[GENIUS] )
1383 		{
1384 			// genius entities are not drawn when the camera is inside their bounding box
1385 			if ( camera->x >= (entity->x - entity->sizex) / 16 && camera->x <= (entity->x + entity->sizex) / 16 )
1386 				if ( camera->y >= (entity->y - entity->sizey) / 16 && camera->y <= (entity->y + entity->sizey) / 16 )
1387 				{
1388 					continue;
1389 				}
1390 		}
1391 		x = entity->x / 16;
1392 		y = entity->y / 16;
1393 		if ( x >= 0 && y >= 0 && x < map.width && y < map.height )
1394 		{
1395 			if ( vismap[y + x * map.height] || entity->flags[OVERDRAW] || entity->monsterEntityRenderAsTelepath == 1 )
1396 			{
1397 				if ( entity->flags[SPRITE] == false )
1398 				{
1399 					glDrawVoxel(camera, entity, mode);
1400 				}
1401 				else
1402 				{
1403 					if ( entity->behavior == &actSpriteNametag )
1404 					{
1405 						int playersTag = playerEntityMatchesUid(entity->parent);
1406 						if ( playersTag >= 0 )
1407 						{
1408 							glDrawSpriteFromImage(camera, entity, stats[playersTag]->name, mode);
1409 						}
1410 					}
1411 					else
1412 					{
1413 						glDrawSprite(camera, entity, mode);
1414 					}
1415 				}
1416 			}
1417 		}
1418 		else
1419 		{
1420 			if ( entity->flags[SPRITE] == false )
1421 			{
1422 				glDrawVoxel(camera, entity, mode);
1423 			}
1424 			else
1425 			{
1426 				glDrawSprite(camera, entity, mode);
1427 			}
1428 		}
1429 	}
1430 
1431 	glDisable(GL_SCISSOR_TEST);
1432 	glScissor(0, 0, xres, yres);
1433 }
1434 
1435 /*-------------------------------------------------------------------------------
1436 
1437 	drawEntities2D
1438 
1439 	Draws all entities in the level as sprites while accounting for the given
1440 	camera coordinates
1441 
1442 -------------------------------------------------------------------------------*/
1443 
drawEntities2D(long camx,long camy)1444 void drawEntities2D(long camx, long camy)
1445 {
1446 	node_t* node;
1447 	Entity* entity;
1448 	SDL_Rect pos, box;
1449 	int offsetx = 0;
1450 	int offsety = 0;
1451 
1452 	if ( map.entities->first == nullptr )
1453 	{
1454 		return;
1455 	}
1456 
1457 	// draw entities
1458 	for ( node = map.entities->first; node != nullptr; node = node->next )
1459 	{
1460 		entity = (Entity*)node->element;
1461 		if ( entity->flags[INVISIBLE] )
1462 		{
1463 			continue;
1464 		}
1465 		pos.x = entity->x * (TEXTURESIZE / 16) - camx;
1466 		pos.y = entity->y * (TEXTURESIZE / 16) - camy;
1467 		pos.w = TEXTURESIZE;
1468 		pos.h = TEXTURESIZE;
1469 		//ttfPrintText(ttf8, 100, 100, inputstr); debug any errant text input in editor
1470 
1471 		if ( entity->sprite >= 0 && entity->sprite < numsprites )
1472 		{
1473 			if ( sprites[entity->sprite] != nullptr )
1474 			{
1475 				if ( entity == selectedEntity )
1476 				{
1477 					// draws a box around the sprite
1478 					box.w = TEXTURESIZE;
1479 					box.h = TEXTURESIZE;
1480 					box.x = pos.x;
1481 					box.y = pos.y;
1482 					drawRect(&box, SDL_MapRGB(mainsurface->format, 255, 0, 0), 255);
1483 					box.w = TEXTURESIZE - 2;
1484 					box.h = TEXTURESIZE - 2;
1485 					box.x = pos.x + 1;
1486 					box.y = pos.y + 1;
1487 					drawRect(&box, SDL_MapRGB(mainsurface->format, 0, 0, 255), 255);
1488 				}
1489 
1490 				// if item sprite and the item index is not 0 (NULL), or 1 (RANDOM)
1491 				if ( entity->sprite == 8 && entity->skill[10] > 1 )
1492 				{
1493 					// draw the item sprite in the editor layout
1494 					Item* tmpItem = newItem(static_cast<ItemType>(entity->skill[10] - 2), static_cast<Status>(0), 0, 0, 0, 0, nullptr);
1495 					drawImageScaled(itemSprite(tmpItem), nullptr, &pos);
1496 					free(tmpItem);
1497 				}
1498 				else if ( entity->sprite == 133 )
1499 				{
1500 					pos.y += sprites[entity->sprite]->h / 2;
1501 					pos.x += sprites[entity->sprite]->w / 2;
1502 					switch ( entity->signalInputDirection )
1503 					{
1504 						case 0:
1505 							drawImageRotatedAlpha(sprites[entity->sprite], nullptr, &pos, 0.f, 255);
1506 							break;
1507 						case 1:
1508 							drawImageRotatedAlpha(sprites[entity->sprite], nullptr, &pos, 3 * PI / 2, 255);
1509 							break;
1510 						case 2:
1511 							drawImageRotatedAlpha(sprites[entity->sprite], nullptr, &pos, PI, 255);
1512 							break;
1513 						case 3:
1514 							drawImageRotatedAlpha(sprites[entity->sprite], nullptr, &pos, PI / 2, 255);
1515 							break;
1516 					}
1517 				}
1518 				else
1519 				{
1520 					// draw sprite normally from sprites list
1521 					drawImageScaled(sprites[entity->sprite], nullptr, &pos);
1522 				}
1523 			}
1524 			else
1525 			{
1526 				if ( entity == selectedEntity )
1527 				{
1528 					// draws a box around the sprite
1529 					box.w = TEXTURESIZE;
1530 					box.h = TEXTURESIZE;
1531 					box.x = pos.x;
1532 					box.y = pos.y;
1533 					drawRect(&box, SDL_MapRGB(mainsurface->format, 255, 0, 0), 255);
1534 					box.w = TEXTURESIZE - 2;
1535 					box.h = TEXTURESIZE - 2;
1536 					box.x = pos.x + 1;
1537 					box.y = pos.y + 1;
1538 					drawRect(&box, SDL_MapRGB(mainsurface->format, 0, 0, 255), 255);
1539 				}
1540 				drawImageScaled(sprites[0], nullptr, &pos);
1541 			}
1542 		}
1543 		else
1544 		{
1545 			if ( entity == selectedEntity )
1546 			{
1547 				// draws a box around the sprite
1548 				box.w = TEXTURESIZE;
1549 				box.h = TEXTURESIZE;
1550 				box.x = pos.x;
1551 				box.y = pos.y;
1552 				drawRect(&box, SDL_MapRGB(mainsurface->format, 255, 0, 0), 255);
1553 				box.w = TEXTURESIZE - 2;
1554 				box.h = TEXTURESIZE - 2;
1555 				box.x = pos.x + 1;
1556 				box.y = pos.y + 1;
1557 				drawRect(&box, SDL_MapRGB(mainsurface->format, 0, 0, 255), 255);
1558 			}
1559 			drawImageScaled(sprites[0], nullptr, &pos);
1560 		}
1561 	}
1562 
1563 	// draw hover text for entities over the top of sprites.
1564 	for ( node = map.entities->first; node != nullptr && (openwindow == 0 && savewindow == 0); node = node->next )
1565 	{
1566 		entity = (Entity*)node->element;
1567 		if ( entity->flags[INVISIBLE] )
1568 		{
1569 			continue;
1570 		}
1571 		pos.x = entity->x * (TEXTURESIZE / 16) - camx;
1572 		pos.y = entity->y * (TEXTURESIZE / 16) - camy;
1573 		pos.w = TEXTURESIZE;
1574 		pos.h = TEXTURESIZE;
1575 		//ttfPrintText(ttf8, 100, 100, inputstr); debug any errant text input in editor
1576 
1577 		if ( entity->sprite >= 0 && entity->sprite < numsprites )
1578 		{
1579 			if ( sprites[entity->sprite] != nullptr )
1580 			{
1581 				if ( entity == selectedEntity )
1582 				{
1583 					int spriteType = checkSpriteType(selectedEntity->sprite);
1584 					char tmpStr[1024] = "";
1585 					char tmpStr2[1024] = "";
1586 					int padx = pos.x + 10;
1587 					int pady = pos.y - 40;
1588 					Uint32 color = SDL_MapRGB(mainsurface->format, 255, 255, 255);
1589 					Uint32 colorWhite = SDL_MapRGB(mainsurface->format, 255, 255, 255);
1590 					switch ( spriteType )
1591 					{
1592 						case 1: //monsters
1593 							pady += 10;
1594 							if ( entity->getStats() != nullptr ) {
1595 								strcpy(tmpStr, spriteEditorNameStrings[selectedEntity->sprite]);
1596 								ttfPrintText(ttf8, padx, pady - 10, tmpStr);
1597 								snprintf(tmpStr, sizeof(entity->getStats()->name), "Name: %s", entity->getStats()->name);
1598 								ttfPrintText(ttf8, padx, pady, tmpStr);
1599 								snprintf(tmpStr, 10, "HP: %d", entity->getStats()->MAXHP);
1600 								ttfPrintText(ttf8, padx, pady + 10, tmpStr);
1601 								snprintf(tmpStr, 10, "Level: %d", entity->getStats()->LVL);
1602 								ttfPrintText(ttf8, padx, pady + 20, tmpStr);
1603 							}
1604 
1605 
1606 							break;
1607 						case 2: //chest
1608 							pady += 5;
1609 							strcpy(tmpStr, spriteEditorNameStrings[selectedEntity->sprite]);
1610 							ttfPrintText(ttf8, padx, pady, tmpStr);
1611 							switch ( (int)entity->yaw )
1612 							{
1613 								case 0:
1614 									strcpy(tmpStr, "Facing: EAST");
1615 									break;
1616 								case 1:
1617 									strcpy(tmpStr, "Facing: SOUTH");
1618 									break;
1619 								case 2:
1620 									strcpy(tmpStr, "Facing: WEST");
1621 									break;
1622 								case 3:
1623 									strcpy(tmpStr, "Facing: NORTH");
1624 									break;
1625 								default:
1626 									strcpy(tmpStr, "Facing: Invalid");
1627 									break;
1628 
1629 							}
1630 							ttfPrintText(ttf8, padx, pady + 10, tmpStr);
1631 
1632 							switch ( entity->skill[9] )
1633 							{
1634 								case 0:
1635 									strcpy(tmpStr, "Type: Random");
1636 									break;
1637 								case 1:
1638 									strcpy(tmpStr, "Type: Garbage");
1639 									break;
1640 								case 2:
1641 									strcpy(tmpStr, "Type: Food");
1642 									break;
1643 								case 3:
1644 									strcpy(tmpStr, "Type: Jewelry");
1645 									break;
1646 								case 4:
1647 									strcpy(tmpStr, "Type: Equipment");
1648 									break;
1649 								case 5:
1650 									strcpy(tmpStr, "Type: Tools");
1651 									break;
1652 								case 6:
1653 									strcpy(tmpStr, "Type: Magical");
1654 									break;
1655 								case 7:
1656 									strcpy(tmpStr, "Type: Potions");
1657 									break;
1658 								case 8:
1659 									strcpy(tmpStr, "Type: Empty");
1660 									break;
1661 								default:
1662 									strcpy(tmpStr, "Type: Random");
1663 									break;
1664 							}
1665 							ttfPrintText(ttf8, padx, pady + 20, tmpStr);
1666 							break;
1667 
1668 						case 3: //Items
1669 							pady += 5;
1670 							strcpy(tmpStr, itemNameStrings[selectedEntity->skill[10]]);
1671 							ttfPrintText(ttf8, padx, pady - 20, tmpStr);
1672 							color = SDL_MapRGB(mainsurface->format, 255, 255, 255);
1673 							pady += 2;
1674 
1675 							strcpy(tmpStr, "Status: ");
1676 							ttfPrintTextColor(ttf8, padx, pady - 10, colorWhite, 1, tmpStr);
1677 							switch ( (int)selectedEntity->skill[11] )
1678 							{
1679 								case 1:
1680 									strcpy(tmpStr, "Broken");
1681 									color = SDL_MapRGB(mainsurface->format, 255, 0, 0);
1682 									break;
1683 								case 2:
1684 									strcpy(tmpStr, "Decrepit");
1685 									color = SDL_MapRGB(mainsurface->format, 200, 128, 0);
1686 									break;
1687 								case 3:
1688 									strcpy(tmpStr, "Worn");
1689 									color = SDL_MapRGB(mainsurface->format, 255, 255, 0);
1690 									break;
1691 								case 4:
1692 									strcpy(tmpStr, "Servicable");
1693 									color = SDL_MapRGB(mainsurface->format, 128, 200, 0);
1694 									break;
1695 								case 5:
1696 									strcpy(tmpStr, "Excellent");
1697 									color = SDL_MapRGB(mainsurface->format, 0, 255, 0);
1698 									break;
1699 								default:
1700 									strcpy(tmpStr, "?");
1701 									color = SDL_MapRGB(mainsurface->format, 0, 168, 255);
1702 									break;
1703 							}
1704 							ttfPrintTextColor(ttf8, padx + 56, pady - 10, color, 1, tmpStr);
1705 
1706 							strcpy(tmpStr, "Bless: ");
1707 							ttfPrintTextColor(ttf8, padx, pady, colorWhite, 1, tmpStr);
1708 							if ( selectedEntity->skill[12] < 0 )
1709 							{
1710 								snprintf(tmpStr2, 10, "%d", selectedEntity->skill[12]);
1711 								color = SDL_MapRGB(mainsurface->format, 255, 0, 0);
1712 							}
1713 							else if ( selectedEntity->skill[12] == 0 )
1714 							{
1715 								snprintf(tmpStr2, 10, "%d", selectedEntity->skill[12]);
1716 								color = SDL_MapRGB(mainsurface->format, 255, 255, 255);
1717 							}
1718 							else if ( selectedEntity->skill[12] == 10 )
1719 							{
1720 								strcpy(tmpStr2, "?");
1721 								color = SDL_MapRGB(mainsurface->format, 0, 168, 255);
1722 							}
1723 							else
1724 							{
1725 								snprintf(tmpStr2, 10, "+%d", selectedEntity->skill[12]);
1726 								color = SDL_MapRGB(mainsurface->format, 0, 255, 0);
1727 							}
1728 							ttfPrintTextColor(ttf8, padx + 48, pady, color, 1, tmpStr2);
1729 
1730 							strcpy(tmpStr, "Qty: ");
1731 							ttfPrintTextColor(ttf8, padx, pady + 10, colorWhite, 1, tmpStr);
1732 							snprintf(tmpStr2, 10, "%d", selectedEntity->skill[13]);
1733 							ttfPrintTextColor(ttf8, padx + 32, pady + 10, colorWhite, 1, tmpStr2);
1734 
1735 							pady += 2;
1736 							strcpy(tmpStr, "Identified: ");
1737 							ttfPrintTextColor(ttf8, padx, pady + 20, colorWhite, 1, tmpStr);
1738 							if ( (int)selectedEntity->skill[15] == 0 )
1739 							{
1740 								strcpy(tmpStr2, "No");
1741 								color = SDL_MapRGB(mainsurface->format, 255, 255, 0);
1742 							}
1743 							else if ( (int)selectedEntity->skill[15] == 1 )
1744 							{
1745 								strcpy(tmpStr2, "Yes");
1746 								color = SDL_MapRGB(mainsurface->format, 0, 255, 0);
1747 							}
1748 							else
1749 							{
1750 								strcpy(tmpStr2, "?");
1751 								color = SDL_MapRGB(mainsurface->format, 0, 168, 255);
1752 							}
1753 							ttfPrintTextColor(ttf8, padx + 80, pady + 20, color, 1, tmpStr2);
1754 							break;
1755 						case 4: //summoning trap
1756 							pady += 5;
1757 							offsety = -40;
1758 							strcpy(tmpStr, spriteEditorNameStrings[selectedEntity->sprite]);
1759 							ttfPrintText(ttf8, padx, pady + offsety, tmpStr);
1760 
1761 							offsety += 10;
1762 							strcpy(tmpStr, "Type: ");
1763 							offsetx = strlen(tmpStr) * 8 - 8;
1764 							ttfPrintTextColor(ttf8, padx, pady + offsety, colorWhite, 1, tmpStr);
1765 							strcpy(tmpStr2, monsterEditorNameStrings[entity->skill[0]]);
1766 							ttfPrintText(ttf8, padx + offsetx, pady + offsety, tmpStr2);
1767 
1768 							offsety += 10;
1769 							strcpy(tmpStr, "Qty: ");
1770 							offsetx = strlen(tmpStr) * 8 - 8;
1771 							ttfPrintTextColor(ttf8, padx, pady + offsety, colorWhite, 1, tmpStr);
1772 							snprintf(tmpStr2, 10, "%d", selectedEntity->skill[1]);
1773 							ttfPrintText(ttf8, padx + offsetx, pady + offsety, tmpStr2);
1774 
1775 							offsety += 10;
1776 							strcpy(tmpStr, "Time: ");
1777 							offsetx = strlen(tmpStr) * 8 - 8;
1778 							ttfPrintTextColor(ttf8, padx, pady + offsety, colorWhite, 1, tmpStr);
1779 							snprintf(tmpStr2, 10, "%d", selectedEntity->skill[2]);
1780 							ttfPrintText(ttf8, padx + offsetx, pady + offsety, tmpStr2);
1781 
1782 							offsety += 10;
1783 							strcpy(tmpStr, "Amount: ");
1784 							offsetx = strlen(tmpStr) * 8 - 8;
1785 							ttfPrintTextColor(ttf8, padx, pady + offsety, colorWhite, 1, tmpStr);
1786 							snprintf(tmpStr2, 10, "%d", selectedEntity->skill[3]);
1787 							ttfPrintText(ttf8, padx + offsetx, pady + offsety, tmpStr2);
1788 
1789 							offsety += 10;
1790 							strcpy(tmpStr, "Power to: ");
1791 							offsetx = strlen(tmpStr) * 8 - 8;
1792 							ttfPrintTextColor(ttf8, padx, pady + offsety, colorWhite, 1, tmpStr);
1793 							if ( selectedEntity->skill[4] == 1 )
1794 							{
1795 								strcpy(tmpStr2, "Spawn");
1796 							}
1797 							else
1798 							{
1799 								strcpy(tmpStr2, "Disable");
1800 							}
1801 							ttfPrintText(ttf8, padx + offsetx, pady + offsety, tmpStr2);
1802 
1803 							offsety += 10;
1804 							strcpy(tmpStr, "Stop Chance: ");
1805 							offsetx = strlen(tmpStr) * 8 - 8;
1806 							ttfPrintTextColor(ttf8, padx, pady + offsety, colorWhite, 1, tmpStr);
1807 							snprintf(tmpStr2, 10, "%d", selectedEntity->skill[5]);
1808 							ttfPrintText(ttf8, padx + offsetx, pady + offsety, tmpStr2);
1809 							break;
1810 						case 5: //power crystal
1811 							pady += 5;
1812 							offsety = -20;
1813 							strcpy(tmpStr, spriteEditorNameStrings[selectedEntity->sprite]);
1814 							ttfPrintText(ttf8, padx, pady + offsety, tmpStr);
1815 
1816 							offsety += 10;
1817 							strcpy(tmpStr, "Facing: ");
1818 							ttfPrintText(ttf8, padx, pady + offsety, tmpStr);
1819 							offsetx = strlen(tmpStr) * 8 - 8;
1820 							switch ( (int)entity->yaw )
1821 							{
1822 								case 0:
1823 									strcpy(tmpStr2, "EAST");
1824 									break;
1825 								case 1:
1826 									strcpy(tmpStr2, "SOUTH");
1827 									break;
1828 								case 2:
1829 									strcpy(tmpStr2, "WEST");
1830 									break;
1831 								case 3:
1832 									strcpy(tmpStr2, "NORTH");
1833 									break;
1834 								default:
1835 									strcpy(tmpStr2, "Invalid");
1836 									break;
1837 
1838 							}
1839 							ttfPrintText(ttf8, padx + offsetx, pady + offsety, tmpStr2);
1840 
1841 							offsety += 10;
1842 							strcpy(tmpStr, "Nodes: ");
1843 							offsetx = strlen(tmpStr) * 8 - 8;
1844 							ttfPrintTextColor(ttf8, padx, pady + offsety, colorWhite, 1, tmpStr);
1845 							snprintf(tmpStr2, 10, "%d", selectedEntity->crystalNumElectricityNodes);
1846 							ttfPrintText(ttf8, padx + offsetx, pady + offsety, tmpStr2);
1847 
1848 							offsety += 10;
1849 							strcpy(tmpStr, "Rotation: ");
1850 							offsetx = strlen(tmpStr) * 8 - 8;
1851 							ttfPrintTextColor(ttf8, padx, pady + offsety, colorWhite, 1, tmpStr);
1852 							switch ( (int)entity->crystalTurnReverse )
1853 							{
1854 								case 0:
1855 									strcpy(tmpStr2, "Clockwise");
1856 									break;
1857 								case 1:
1858 									strcpy(tmpStr2, "Anti-Clockwise");
1859 									break;
1860 								default:
1861 									strcpy(tmpStr2, "Invalid");
1862 									break;
1863 
1864 							}
1865 							ttfPrintText(ttf8, padx + offsetx, pady + offsety, tmpStr2);
1866 
1867 							offsety += 10;
1868 							strcpy(tmpStr, "Spell to Activate: ");
1869 							offsetx = strlen(tmpStr) * 8 - 8;
1870 							ttfPrintTextColor(ttf8, padx, pady + offsety, colorWhite, 1, tmpStr);
1871 							switch ( (int)entity->crystalSpellToActivate )
1872 							{
1873 								case 0:
1874 									strcpy(tmpStr2, "No");
1875 									break;
1876 								case 1:
1877 									strcpy(tmpStr2, "Yes");
1878 									break;
1879 								default:
1880 									strcpy(tmpStr2, "Invalid");
1881 									break;
1882 
1883 							}
1884 							ttfPrintText(ttf8, padx + offsetx, pady + offsety, tmpStr2);
1885 							break;
1886 						case 16:
1887 						case 13:
1888 						{
1889 							char buf[256] = "";
1890 							int totalChars = 0;
1891 							for ( int i = (spriteType == 16 ? 4 : 8); i < 60; ++i )
1892 							{
1893 								if ( selectedEntity->skill[i] != 0 && i != 28 ) // skill[28] is circuit status.
1894 								{
1895 									for ( int c = 0; c < 4; ++c )
1896 									{
1897 										if ( static_cast<char>((selectedEntity->skill[i] >> (c * 8)) & 0xFF) == '\0'
1898 											&& i != 59 && selectedEntity->skill[i + 1] != 0 )
1899 										{
1900 											// don't add '\0' termination unless the next skill slot is empty as we have more data to read.
1901 										}
1902 										else
1903 										{
1904 											buf[totalChars] = static_cast<char>((selectedEntity->skill[i] >> (c * 8)) & 0xFF);
1905 											++totalChars;
1906 										}
1907 									}
1908 								}
1909 							}
1910 							if ( buf[totalChars] != '\0' )
1911 							{
1912 								buf[totalChars] = '\0';
1913 							}
1914 							int numLines = 0;
1915 							std::vector<std::string> lines;
1916 							lines.push_back(spriteEditorNameStrings[selectedEntity->sprite]);
1917 
1918 							strncpy(tmpStr, buf, 48);
1919 							if ( strcmp(tmpStr, "") )
1920 							{
1921 								lines.push_back(tmpStr);
1922 							}
1923 							strncpy(tmpStr, buf + 48, 48);
1924 							if ( strcmp(tmpStr, "") )
1925 							{
1926 								lines.push_back(tmpStr);
1927 							}
1928 							strncpy(tmpStr, buf + 96, 48);
1929 							if ( strcmp(tmpStr, "") )
1930 							{
1931 								lines.push_back(tmpStr);
1932 							}
1933 							strncpy(tmpStr, buf + 144, 48);
1934 							if ( strcmp(tmpStr, "") )
1935 							{
1936 								lines.push_back(tmpStr);
1937 							}
1938 							strncpy(tmpStr, buf + 192, 48);
1939 							if ( strcmp(tmpStr, "") )
1940 							{
1941 								lines.push_back(tmpStr);
1942 							}
1943 							if ( lines.size() > 3 )
1944 							{
1945 								offsety -= (lines.size() - 2) * 5;
1946 							}
1947 
1948 							size_t longestLine = 0;
1949 							for ( auto it : lines )
1950 							{
1951 								longestLine = std::max(longestLine, strlen(it.c_str()));
1952 							}
1953 
1954 							SDL_Rect tooltip;
1955 							tooltip.x = padx + offsetx - 4;
1956 							tooltip.w = TTF8_WIDTH * longestLine + 8;
1957 							tooltip.y = pady + offsety - 4;
1958 							tooltip.h = lines.size() * TTF8_HEIGHT + 8;
1959 							if ( lines.size() > 1 )
1960 							{
1961 								drawTooltip(&tooltip);
1962 							}
1963 							for ( auto it : lines )
1964 							{
1965 								ttfPrintText(ttf8, padx + offsetx, pady + offsety, it.c_str());
1966 								offsety += 10;
1967 							}
1968 						}
1969 							break;
1970 						default:
1971 							strcpy(tmpStr, spriteEditorNameStrings[selectedEntity->sprite]);
1972 							ttfPrintText(ttf8, padx, pady + 20, tmpStr);
1973 							break;
1974 
1975 					}
1976 				}
1977 				else if ( (omousex / TEXTURESIZE) * 32 == pos.x && (omousey / TEXTURESIZE) * 32 == pos.y &&
1978 					selectedEntity == NULL && hovertext )
1979 				{
1980 					// handle mouseover sprite name tooltip in main editor screen
1981 					int padx = pos.x + 10;
1982 					int pady = pos.y - 20;
1983 					int spriteType = checkSpriteType(entity->sprite);
1984 					//offsety = 0;
1985 					Stat* tmpStats = nullptr;
1986 					if ( spriteType == 1 )
1987 					{
1988 						tmpStats = entity->getStats();
1989 						if ( tmpStats != nullptr )
1990 						{
1991 							if ( strcmp(tmpStats->name, "") != 0 )
1992 							{
1993 								ttfPrintText(ttf8, padx, pady - offsety, tmpStats->name);
1994 								offsety += 10;
1995 							}
1996 							ttfPrintText(ttf8, padx, pady - offsety, spriteEditorNameStrings[entity->sprite]);
1997 							offsety += 10;
1998 						}
1999 					}
2000 					else if ( spriteType == 3 )
2001 					{
2002 						ttfPrintText(ttf8, padx, pady - offsety, itemNameStrings[entity->skill[10]]);
2003 						offsety += 10;
2004 					}
2005 					else
2006 					{
2007 						ttfPrintText(ttf8, padx, pady - offsety, spriteEditorNameStrings[entity->sprite]);
2008 						offsety += 10;
2009 					}
2010 				}
2011 			}
2012 		}
2013 	}
2014 }
2015 
2016 /*-------------------------------------------------------------------------------
2017 
2018 	drawGrid
2019 
2020 	Draws a white line grid for the tile map
2021 
2022 -------------------------------------------------------------------------------*/
2023 
drawGrid(long camx,long camy)2024 void drawGrid(long camx, long camy)
2025 {
2026 	long x, y;
2027 	Uint32 color;
2028 
2029 	color = SDL_MapRGB(mainsurface->format, 127, 127, 127);
2030 	drawLine(-camx, (map.height << TEXTUREPOWER) - camy, (map.width << TEXTUREPOWER) - camx, (map.height << TEXTUREPOWER) - camy, color, 255);
2031 	drawLine((map.width << TEXTUREPOWER) - camx, -camy, (map.width << TEXTUREPOWER) - camx, (map.height << TEXTUREPOWER) - camy, color, 255);
2032 	for ( y = 0; y < map.height; y++ )
2033 	{
2034 		for ( x = 0; x < map.width; x++ )
2035 		{
2036 			drawLine((x << TEXTUREPOWER) - camx, (y << TEXTUREPOWER) - camy, ((x + 1) << TEXTUREPOWER) - camx, (y << TEXTUREPOWER) - camy, color, 255);
2037 			drawLine((x << TEXTUREPOWER) - camx, (y << TEXTUREPOWER) - camy, (x << TEXTUREPOWER) - camx, ((y + 1) << TEXTUREPOWER) - camy, color, 255);
2038 		}
2039 	}
2040 }
2041 
2042 /*-------------------------------------------------------------------------------
2043 
2044 	drawEditormap
2045 
2046 	Draws a minimap in the upper right corner of the screen to represent
2047 	the screen's position relative to the rest of the level
2048 
2049 -------------------------------------------------------------------------------*/
2050 
drawEditormap(long camx,long camy)2051 void drawEditormap(long camx, long camy)
2052 {
2053 	SDL_Rect src, osrc;
2054 
2055 	src.x = xres - 120;
2056 	src.y = 24;
2057 	src.w = 112;
2058 	src.h = 112;
2059 	drawRect(&src, SDL_MapRGB(mainsurface->format, 0, 0, 0), 255);
2060 
2061 	// initial box dimensions
2062 	src.x = (xres - 120) + (((real_t)camx / TEXTURESIZE) * 112.0) / map.width;
2063 	src.y = 24 + (((real_t)camy / TEXTURESIZE) * 112.0) / map.height;
2064 	src.w = (112.0 / map.width) * ((real_t)xres / TEXTURESIZE);
2065 	src.h = (112.0 / map.height) * ((real_t)yres / TEXTURESIZE);
2066 
2067 	// clip at left edge
2068 	if ( src.x < xres - 120 )
2069 	{
2070 		src.w -= (xres - 120) - src.x;
2071 		src.x = xres - 120;
2072 	}
2073 
2074 	// clip at right edge
2075 	if ( src.x + src.w > xres - 8 )
2076 	{
2077 		src.w = xres - 8 - src.x;
2078 	}
2079 
2080 	// clip at top edge
2081 	if ( src.y < 24 )
2082 	{
2083 		src.h -= 24 - src.y;
2084 		src.y = 24;
2085 	}
2086 
2087 	// clip at bottom edge
2088 	if ( src.y + src.h > 136 )
2089 	{
2090 		src.h = 136 - src.y;
2091 	}
2092 
2093 	osrc.x = src.x + 1;
2094 	osrc.y = src.y + 1;
2095 	osrc.w = src.w - 2;
2096 	osrc.h = src.h - 2;
2097 	drawRect(&src, SDL_MapRGB(mainsurface->format, 255, 255, 255), 255);
2098 	drawRect(&osrc, SDL_MapRGB(mainsurface->format, 0, 0, 0), 255);
2099 }
2100 
2101 /*-------------------------------------------------------------------------------
2102 
2103 	drawWindow / drawDepressed
2104 
2105 	Draws a rectangular box that fills the area inside the given screen
2106 	coordinates
2107 
2108 -------------------------------------------------------------------------------*/
2109 
drawWindow(int x1,int y1,int x2,int y2)2110 void drawWindow(int x1, int y1, int x2, int y2)
2111 {
2112 	SDL_Rect src;
2113 
2114 	src.x = x1;
2115 	src.y = y1;
2116 	src.w = x2 - x1;
2117 	src.h = y2 - y1;
2118 	drawRect(&src, SDL_MapRGB(mainsurface->format, 160, 160, 192), 255);
2119 	src.x = x1 + 1;
2120 	src.y = y1 + 1;
2121 	src.w = x2 - x1 - 1;
2122 	src.h = y2 - y1 - 1;
2123 	drawRect(&src, SDL_MapRGB(mainsurface->format, 96, 96, 128), 255);
2124 	src.x = x1 + 1;
2125 	src.y = y1 + 1;
2126 	src.w = x2 - x1 - 2;
2127 	src.h = y2 - y1 - 2;
2128 	drawRect(&src, SDL_MapRGB(mainsurface->format, 128, 128, 160), 255);
2129 }
2130 
drawDepressed(int x1,int y1,int x2,int y2)2131 void drawDepressed(int x1, int y1, int x2, int y2)
2132 {
2133 	SDL_Rect src;
2134 
2135 	src.x = x1;
2136 	src.y = y1;
2137 	src.w = x2 - x1;
2138 	src.h = y2 - y1;
2139 	drawRect(&src, SDL_MapRGB(mainsurface->format, 96, 96, 128), 255);
2140 	src.x = x1 + 1;
2141 	src.y = y1 + 1;
2142 	src.w = x2 - x1 - 1;
2143 	src.h = y2 - y1 - 1;
2144 	drawRect(&src, SDL_MapRGB(mainsurface->format, 160, 160, 192), 255);
2145 	src.x = x1 + 1;
2146 	src.y = y1 + 1;
2147 	src.w = x2 - x1 - 2;
2148 	src.h = y2 - y1 - 2;
2149 	drawRect(&src, SDL_MapRGB(mainsurface->format, 128, 128, 160), 255);
2150 }
2151 
drawWindowFancy(int x1,int y1,int x2,int y2)2152 void drawWindowFancy(int x1, int y1, int x2, int y2)
2153 {
2154 	if (softwaremode)
2155 	{
2156 		// no fancy stuff in software mode
2157 		drawWindow(x1, y1, x2, y2);
2158 		return;
2159 	}
2160 
2161 	// update projection
2162 	glDisable(GL_DEPTH_TEST);
2163 	glDisable(GL_LIGHTING);
2164 	glMatrixMode(GL_PROJECTION);
2165 	glViewport(0, 0, xres, yres);
2166 	glLoadIdentity();
2167 	glOrtho(0, xres, 0, yres, -1, 1);
2168 	glMatrixMode(GL_MODELVIEW);
2169 	glEnable(GL_BLEND);
2170 
2171 	// draw quads
2172 	glColor3f(.25, .25, .25);
2173 	glBindTexture(GL_TEXTURE_2D, 0);
2174 	glBegin(GL_QUADS);
2175 	glVertex2f(x1, yres - y1);
2176 	glVertex2f(x1, yres - y2);
2177 	glVertex2f(x2, yres - y2);
2178 	glVertex2f(x2, yres - y1);
2179 	glEnd();
2180 	glColor3f(.5, .5, .5);
2181 	glBindTexture(GL_TEXTURE_2D, 0);
2182 	glBegin(GL_QUADS);
2183 	glVertex2f(x1 + 1, yres - y1 - 1);
2184 	glVertex2f(x1 + 1, yres - y2 + 1);
2185 	glVertex2f(x2 - 1, yres - y2 + 1);
2186 	glVertex2f(x2 - 1, yres - y1 - 1);
2187 	glEnd();
2188 	glColor3f(.75, .75, .75);
2189 	glBindTexture(GL_TEXTURE_2D, texid[fancyWindow_bmp->refcount]); // wood texture
2190 	glBegin(GL_QUADS);
2191 	glTexCoord2f(0, 0);
2192 	glVertex2f(x1 + 2, yres - y1 - 2);
2193 	glTexCoord2f(0, (y2 - y1 - 4) / (real_t)tiles[30]->h);
2194 	glVertex2f(x1 + 2, yres - y2 + 2);
2195 	glTexCoord2f((x2 - x1 - 4) / (real_t)tiles[30]->w, (y2 - y1 - 4) / (real_t)tiles[30]->h);
2196 	glVertex2f(x2 - 2, yres - y2 + 2);
2197 	glTexCoord2f((x2 - x1 - 4) / (real_t)tiles[30]->w, 0);
2198 	glVertex2f(x2 - 2, yres - y1 - 2);
2199 	glEnd();
2200 }
2201 
2202 /*-------------------------------------------------------------------------------
2203 
2204 	ttfPrintText / ttfPrintTextColor
2205 
2206 	Prints an unformatted utf8 string to the screen, returning the width of
2207 	the message surface in pixels. ttfPrintTextColor() also takes a 32-bit
2208 	color argument
2209 
2210 -------------------------------------------------------------------------------*/
2211 
2212 SDL_Rect errorRect = { 0 };
2213 
ttfPrintTextColor(TTF_Font * font,int x,int y,Uint32 color,bool outline,const char * str)2214 SDL_Rect ttfPrintTextColor( TTF_Font* font, int x, int y, Uint32 color, bool outline, const char* str )
2215 {
2216 	SDL_Rect pos = { x, y, 0, 0 };
2217 	SDL_Surface* surf;
2218 	int c;
2219 
2220 	if ( !str )
2221 	{
2222 		return errorRect;
2223 	}
2224 	char newStr[1024] = { 0 };
2225 	strcpy(newStr, str);
2226 
2227 	// tokenize string
2228 	for ( c = 0; c < strlen(newStr) + 1; c++ )
2229 	{
2230 		if ( newStr[c] == '\n' || newStr[c] == '\r' )
2231 		{
2232 			int offY = 0;
2233 			if ( newStr[c] == '\n' )
2234 			{
2235 				offY = TTF_FontHeight(font);
2236 			}
2237 			newStr[c] = 0;
2238 			ttfPrintTextColor(font, x, y + offY, color, outline, (char*)&newStr[c + 1]);
2239 			break;
2240 		}
2241 		else if ( newStr[c] == 0 )
2242 		{
2243 			break;
2244 		}
2245 	}
2246 
2247 	if ( imgref > ttfTextCacheLimit )
2248 	{
2249 		// time to flush the cache.
2250 		imgref -= 6144;
2251 		for ( int i = 0; i < HASH_SIZE; ++i )
2252 		{
2253 			list_FreeAll(&ttfTextHash[i]);
2254 		}
2255 		printlog("notice: stored hash limit exceeded, clearing ttfTextHash...");
2256 	}
2257 
2258 	// retrieve text surface
2259 	if ( (surf = ttfTextHashRetrieve(ttfTextHash, newStr, font, outline)) == NULL )
2260 	{
2261 		// create the text outline surface
2262 		if ( outline )
2263 		{
2264 			if ( font == ttf8 )
2265 			{
2266 				TTF_SetFontOutline(font, 1);
2267 			}
2268 			else
2269 			{
2270 				TTF_SetFontOutline(font, 2);
2271 			}
2272 			SDL_Color sdlColorBlack = { 0, 0, 0, 255 };
2273 			surf = TTF_RenderUTF8_Blended(font, newStr, sdlColorBlack);
2274 		}
2275 		else
2276 		{
2277 			int w, h;
2278 			TTF_SizeUTF8(font, newStr, &w, &h);
2279 			if ( font == ttf8 )
2280 			{
2281 				surf = SDL_CreateRGBSurface(0, w + 2, h + 2,
2282 				                            mainsurface->format->BitsPerPixel,
2283 				                            mainsurface->format->Rmask,
2284 				                            mainsurface->format->Gmask,
2285 				                            mainsurface->format->Bmask,
2286 				                            mainsurface->format->Amask
2287 				                           );
2288 			}
2289 			else
2290 			{
2291 				surf = SDL_CreateRGBSurface(0, w + 4, h + 4,
2292 				                            mainsurface->format->BitsPerPixel,
2293 				                            mainsurface->format->Rmask,
2294 				                            mainsurface->format->Gmask,
2295 				                            mainsurface->format->Bmask,
2296 				                            mainsurface->format->Amask
2297 				                           );
2298 			}
2299 		}
2300 
2301 		if (!surf)
2302 		{
2303 			printlog("warning: failed to create the surface\n");
2304 			return errorRect;
2305 		}
2306 		// create the text surface
2307 		TTF_SetFontOutline(font, 0);
2308 		SDL_Color sdlColorWhite = { 255, 255, 255, 255 };
2309 		SDL_Surface* textSurf = TTF_RenderUTF8_Blended(font, newStr, sdlColorWhite);
2310 
2311 		// combine the surfaces
2312 		if ( font == ttf8 )
2313 		{
2314 			pos.x = 1;
2315 			pos.y = 1;
2316 		}
2317 		else
2318 		{
2319 			pos.x = 2;
2320 			pos.y = 2;
2321 		}
2322 		SDL_BlitSurface(textSurf, NULL, surf, &pos);
2323 		// load the text outline surface as a GL texture
2324 		allsurfaces[imgref] = surf;
2325 		allsurfaces[imgref]->refcount = imgref;
2326 		glLoadTexture(allsurfaces[imgref], imgref);
2327 		imgref++;
2328 		// store the surface in the text surface cache
2329 		if ( !ttfTextHashStore(ttfTextHash, newStr, font, outline, surf) )
2330 		{
2331 			printlog("warning: failed to store text outline surface with imgref %d\n", imgref - 1);
2332 		}
2333 	}
2334 
2335 	// draw the text surface
2336 	if ( font == ttf8 )
2337 	{
2338 		pos.x = x;
2339 		pos.y = y - 3;
2340 	}
2341 	else
2342 	{
2343 		pos.x = x + 1;
2344 		pos.y = y - 4;
2345 	}
2346 	pos.w = surf->w;
2347 	pos.h = surf->h;
2348 	drawImageColor(surf, NULL, &pos, color);
2349 	pos.x = x;
2350 	pos.y = y;
2351 
2352 	return pos;
2353 }
2354 
ttfPrintText(TTF_Font * font,int x,int y,const char * str)2355 SDL_Rect ttfPrintText( TTF_Font* font, int x, int y, const char* str )
2356 {
2357 	if ( !str )
2358 	{
2359 		return errorRect;
2360 	}
2361 	return ttfPrintTextColor(font, x, y, 0xFFFFFFFF, true, str);
2362 }
2363 
2364 /*-------------------------------------------------------------------------------
2365 
2366 	ttfPrintTextFormatted / ttfPrintTextFormattedColor
2367 
2368 	Prints a formatted utf8 string to the screen using
2369 	ttfPrintText / ttfPrintTextColor
2370 
2371 -------------------------------------------------------------------------------*/
2372 
ttfPrintTextFormattedColor(TTF_Font * font,int x,int y,Uint32 color,char const * const fmt,...)2373 SDL_Rect ttfPrintTextFormattedColor( TTF_Font* font, int x, int y, Uint32 color, char const * const fmt, ... )
2374 {
2375 	char str[1024] = { 0 };
2376 
2377 	if ( !fmt )
2378 	{
2379 		return errorRect;
2380 	}
2381 
2382 	// format the string
2383 	va_list argptr;
2384 	va_start( argptr, fmt );
2385 	vsnprintf( str, 1023, fmt, argptr );
2386 	va_end( argptr );
2387 
2388 	// print the text
2389 	return ttfPrintTextColor(font, x, y, color, true, str);
2390 }
2391 
ttfPrintTextFormatted(TTF_Font * font,int x,int y,char const * const fmt,...)2392 SDL_Rect ttfPrintTextFormatted( TTF_Font* font, int x, int y, char const * const fmt, ... )
2393 {
2394 	char str[1024] = { 0 };
2395 
2396 	if ( !fmt )
2397 	{
2398 		return errorRect;
2399 	}
2400 
2401 	// format the string
2402 	va_list argptr;
2403 	va_start( argptr, fmt );
2404 	vsnprintf( str, 1023, fmt, argptr );
2405 	va_end( argptr );
2406 
2407 	// print the text
2408 	return ttfPrintTextColor(font, x, y, 0xFFFFFFFF, true, str);
2409 }
2410 
2411 /*-------------------------------------------------------------------------------
2412 
2413 	printText
2414 
2415 	Prints unformatted text to the screen using a font bitmap
2416 
2417 -------------------------------------------------------------------------------*/
2418 
printText(SDL_Surface * font_bmp,int x,int y,const char * str)2419 void printText( SDL_Surface* font_bmp, int x, int y, const char* str )
2420 {
2421 	int c;
2422 	int numbytes;
2423 	SDL_Rect src, dest, odest;
2424 
2425 	if ( strlen(str) > 2048 )
2426 	{
2427 		printlog("error: buffer overflow in printText\n");
2428 		return;
2429 	}
2430 
2431 	// format the string
2432 	numbytes = strlen(str);
2433 
2434 	// define font dimensions
2435 	dest.x = x;
2436 	dest.y = y;
2437 	dest.w = font_bmp->w / 16;
2438 	src.w = font_bmp->w / 16;
2439 	dest.h = font_bmp->h / 16;
2440 	src.h = font_bmp->h / 16;
2441 
2442 	// print the characters in the string
2443 	for ( c = 0; c < numbytes; c++ )
2444 	{
2445 		src.x = (str[c] * src.w) % font_bmp->w;
2446 		src.y = (int)((str[c] * src.w) / font_bmp->w) * src.h;
2447 		if ( str[c] != 10 && str[c] != 13 )   // LF/CR
2448 		{
2449 			odest.x = dest.x;
2450 			odest.y = dest.y;
2451 			drawImage( font_bmp, &src, &dest );
2452 			dest.x = odest.x + src.w;
2453 			dest.y = odest.y;
2454 		}
2455 		else if ( str[c] == 10 )
2456 		{
2457 			dest.x = x;
2458 			dest.y += src.h;
2459 		}
2460 	}
2461 }
2462 
2463 /*-------------------------------------------------------------------------------
2464 
2465 	printTextFormatted
2466 
2467 	Prints formatted text to the screen using a font bitmap
2468 
2469 -------------------------------------------------------------------------------*/
2470 
printTextFormatted(SDL_Surface * font_bmp,int x,int y,char const * const fmt,...)2471 void printTextFormatted( SDL_Surface* font_bmp, int x, int y, char const * const fmt, ... )
2472 {
2473 	int c;
2474 	int numbytes;
2475 	char str[1024] = { 0 };
2476 	va_list argptr;
2477 	SDL_Rect src, dest, odest;
2478 
2479 	// format the string
2480 	va_start( argptr, fmt );
2481 	numbytes = vsnprintf( str, 1023, fmt, argptr );
2482 	va_end( argptr );
2483 
2484 	// define font dimensions
2485 	dest.x = x;
2486 	dest.y = y;
2487 	dest.w = font_bmp->w / 16;
2488 	src.w = font_bmp->w / 16;
2489 	dest.h = font_bmp->h / 16;
2490 	src.h = font_bmp->h / 16;
2491 
2492 	// print the characters in the string
2493 	for ( c = 0; c < numbytes; c++ )
2494 	{
2495 		src.x = (str[c] * src.w) % font_bmp->w;
2496 		src.y = (int)((str[c] * src.w) / font_bmp->w) * src.h;
2497 		if ( str[c] != 10 && str[c] != 13 )   // LF/CR
2498 		{
2499 			odest.x = dest.x;
2500 			odest.y = dest.y;
2501 			drawImage( font_bmp, &src, &dest );
2502 			dest.x = odest.x + src.w;
2503 			dest.y = odest.y;
2504 		}
2505 		else if ( str[c] == 10 )
2506 		{
2507 			dest.x = x;
2508 			dest.y += src.h;
2509 		}
2510 	}
2511 }
2512 
2513 /*-------------------------------------------------------------------------------
2514 
2515 	printTextFormattedAlpha
2516 
2517 	Prints formatted text to the screen using a font bitmap and taking an
2518 	alpha value.
2519 
2520 -------------------------------------------------------------------------------*/
2521 
printTextFormattedAlpha(SDL_Surface * font_bmp,int x,int y,Uint8 alpha,char const * const fmt,...)2522 void printTextFormattedAlpha(SDL_Surface* font_bmp, int x, int y, Uint8 alpha, char const * const fmt, ...)
2523 {
2524 	int c;
2525 	int numbytes;
2526 	char str[1024] = { 0 };
2527 	va_list argptr;
2528 	SDL_Rect src, dest, odest;
2529 
2530 	// format the string
2531 	va_start( argptr, fmt );
2532 	numbytes = vsnprintf( str, 1023, fmt, argptr );
2533 	va_end( argptr );
2534 
2535 	// define font dimensions
2536 	dest.x = x;
2537 	dest.y = y;
2538 	dest.w = font_bmp->w / 16;
2539 	src.w = font_bmp->w / 16;
2540 	dest.h = font_bmp->h / 16;
2541 	src.h = font_bmp->h / 16;
2542 
2543 	// print the characters in the string
2544 	for ( c = 0; c < numbytes; c++ )
2545 	{
2546 		src.x = (str[c] * src.w) % font_bmp->w;
2547 		src.y = (int)((str[c] * src.w) / font_bmp->w) * src.h;
2548 		if ( str[c] != 10 && str[c] != 13 )   // LF/CR
2549 		{
2550 			odest.x = dest.x;
2551 			odest.y = dest.y;
2552 			drawImageAlpha( font_bmp, &src, &dest, alpha );
2553 			dest.x = odest.x + src.w;
2554 			dest.y = odest.y;
2555 		}
2556 		else if ( str[c] == 10 )
2557 		{
2558 			dest.x = x;
2559 			dest.y += src.h;
2560 		}
2561 	}
2562 }
2563 
2564 /*-------------------------------------------------------------------------------
2565 
2566 	printTextFormattedColor
2567 
2568 	Prints formatted text to the screen using a font bitmap and taking a
2569 	32-bit color value
2570 
2571 -------------------------------------------------------------------------------*/
2572 
printTextFormattedColor(SDL_Surface * font_bmp,int x,int y,Uint32 color,char const * const fmt,...)2573 void printTextFormattedColor(SDL_Surface* font_bmp, int x, int y, Uint32 color, char const * const fmt, ...)
2574 {
2575 	int c;
2576 	int numbytes;
2577 	char str[1024] = { 0 };
2578 	va_list argptr;
2579 	SDL_Rect src, dest, odest;
2580 
2581 	// format the string
2582 	va_start( argptr, fmt );
2583 	numbytes = vsnprintf( str, 1023, fmt, argptr );
2584 	va_end( argptr );
2585 
2586 	// define font dimensions
2587 	dest.x = x;
2588 	dest.y = y;
2589 	dest.w = font_bmp->w / 16;
2590 	src.w = font_bmp->w / 16;
2591 	dest.h = font_bmp->h / 16;
2592 	src.h = font_bmp->h / 16;
2593 
2594 	// print the characters in the string
2595 	for ( c = 0; c < numbytes; c++ )
2596 	{
2597 		src.x = (str[c] * src.w) % font_bmp->w;
2598 		src.y = (int)((str[c] * src.w) / font_bmp->w) * src.h;
2599 		if ( str[c] != 10 && str[c] != 13 )   // LF/CR
2600 		{
2601 			odest.x = dest.x;
2602 			odest.y = dest.y;
2603 			drawImageColor( font_bmp, &src, &dest, color );
2604 			dest.x = odest.x + src.w;
2605 			dest.y = odest.y;
2606 		}
2607 		else if ( str[c] == 10 )
2608 		{
2609 			dest.x = x;
2610 			dest.y += src.h;
2611 		}
2612 	}
2613 }
2614 
2615 /*-------------------------------------------------------------------------------
2616 
2617 	printTextFormattedColor
2618 
2619 	Prints formatted text to the screen using a font bitmap, while coloring,
2620 	rotating, and scaling it
2621 
2622 -------------------------------------------------------------------------------*/
2623 
printTextFormattedFancy(SDL_Surface * font_bmp,int x,int y,Uint32 color,real_t angle,real_t scale,char * fmt,...)2624 void printTextFormattedFancy(SDL_Surface* font_bmp, int x, int y, Uint32 color, real_t angle, real_t scale, char* fmt, ...)
2625 {
2626 	int c;
2627 	int numbytes;
2628 	char str[1024] = { 0 };
2629 	va_list argptr;
2630 	SDL_Rect src, dest;
2631 
2632 	// format the string
2633 	va_start( argptr, fmt );
2634 	numbytes = vsnprintf( str, 1023, fmt, argptr );
2635 	va_end( argptr );
2636 
2637 	// define font dimensions
2638 	real_t newX = x;
2639 	real_t newY = y;
2640 	dest.w = ((real_t)font_bmp->w / 16.f) * scale;
2641 	src.w = font_bmp->w / 16;
2642 	dest.h = ((real_t)font_bmp->h / 16.f) * scale;
2643 	src.h = font_bmp->h / 16;
2644 
2645 	// print the characters in the string
2646 	int line = 0;
2647 	for ( c = 0; c < numbytes; c++ )
2648 	{
2649 		src.x = (str[c] * src.w) % font_bmp->w;
2650 		src.y = (int)((str[c] * src.w) / font_bmp->w) * src.h;
2651 		if ( str[c] != 10 && str[c] != 13 )   // LF/CR
2652 		{
2653 			dest.x = newX;
2654 			dest.y = newY;
2655 			drawImageFancy( font_bmp, color, angle, &src, &dest );
2656 			newX += (real_t)dest.w * cos(angle);
2657 			newY += (real_t)dest.h * sin(angle);
2658 		}
2659 		else if ( str[c] == 10 )
2660 		{
2661 			line++;
2662 			dest.x = x + dest.h * cos(angle + PI / 2) * line;
2663 			dest.y = y + dest.h * sin(angle + PI / 2) * line;
2664 		}
2665 	}
2666 }
2667 
2668 /*-------------------------------------------------------------------------------
2669 
2670 	draws a tooltip
2671 
2672 	Draws a tooltip box
2673 
2674 -------------------------------------------------------------------------------*/
2675 
drawTooltip(SDL_Rect * src,Uint32 optionalColor)2676 void drawTooltip(SDL_Rect* src, Uint32 optionalColor)
2677 {
2678 	Uint32 color = SDL_MapRGB(mainsurface->format, 0, 192, 255);
2679 	if ( optionalColor == 0 )
2680 	{
2681 		drawRect(src, 0, 250);
2682 	}
2683 	else
2684 	{
2685 		color = optionalColor;
2686 	}
2687 	drawLine(src->x, src->y, src->x + src->w, src->y, color, 255);
2688 	drawLine(src->x, src->y + src->h, src->x + src->w, src->y + src->h, color, 255);
2689 	drawLine(src->x, src->y, src->x, src->y + src->h, color, 255);
2690 	drawLine(src->x + src->w, src->y, src->x + src->w, src->y + src->h, color, 255);
2691 }
2692