1 /***************************************************************************
2                      minimap.cpp  -  The ingame minimap
3                              -------------------
4     begin                : Thu Jan 29 2004
5     copyright            : (C) 2004 by Daroth-U
6     email                : daroth-u@ifrance.com
7 ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "common/constants.h"
19 #include "minimap.h"
20 #include "render/renderlib.h"
21 #include "sdlhandler.h"
22 #include "dungeongenerator.h"
23 #include "scourge.h"
24 #include "math.h"
25 #include "gui/canvas.h"
26 #include "item.h"
27 #include "creature.h"
28 #include "shapepalette.h"
29 #include "rpg/rpglib.h"
30 
31 using namespace std;
32 
33 #define DEBUG_MINIMAP 0
34 #define MINI_MAP_OFFSET_X 30
35 #define MINI_MAP_OFFSET_Y 50
36 #define MINI_MAP_SIZE 60
37 #define MINI_MAP_BLOCK 4
38 
MiniMap(Scourge * scourge)39 MiniMap :: MiniMap( Scourge *scourge ) {
40 	this->scourge = scourge;
41 	showMiniMap = true;
42 	textureSizeH = textureSizeW = 512;
43 }
44 
~MiniMap()45 MiniMap :: ~MiniMap() {
46 }
47 
drawMap()48 void MiniMap::drawMap() {
49 	if ( !showMiniMap ) return;
50 
51 	bool useStencil =
52 	  ( scourge->getPreferences()->getStencilbuf() &&
53 	    scourge->getPreferences()->getStencilBufInitialized() );
54 
55 	int sx = scourge->getSession()->getMap()->getX() + 75 - 30 - ( MINI_MAP_SIZE / 2 );
56 	if ( sx < MAP_OFFSET ) sx = MAP_OFFSET;
57 	int sy = scourge->getSession()->getMap()->getY() + 75 - 30 - ( MINI_MAP_SIZE / 2 );
58 	if ( sy < MAP_OFFSET ) sy = MAP_OFFSET;
59 	int ex = sx + MINI_MAP_SIZE;
60 	if ( ex > textureSizeW ) ex = textureSizeW;
61 	int ey = sy + MINI_MAP_SIZE;
62 	if ( ey > textureSizeH ) ey = textureSizeW;
63 
64 	glDisable( GL_CULL_FACE );
65 	glDisable( GL_DEPTH_TEST );
66 	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
67 
68 	// Set rotation/translation for all following drawing operations.
69 	glPushMatrix();
70 	glLoadIdentity();
71 	glTranslatef( MINI_MAP_OFFSET_X, MINI_MAP_OFFSET_Y, 0 );
72 	glTranslatef( MINI_MAP_SIZE * MINI_MAP_BLOCK / 2, MINI_MAP_SIZE * MINI_MAP_BLOCK / 2, 0 );
73 	glRotatef( scourge->getSession()->getMap()->getZRot(), 0, 0, 1 );
74 	glTranslatef( -MINI_MAP_SIZE * MINI_MAP_BLOCK / 2, -MINI_MAP_SIZE * MINI_MAP_BLOCK / 2, 0 );
75 
76 	// Create the stencil from the minimap mask texture.
77 	if ( useStencil ) {
78 		glClear( GL_STENCIL_BUFFER_BIT );
79 		glColorMask( 0, 0, 0, 0 );
80 		glEnable( GL_STENCIL_TEST );
81 		glStencilOp( GL_REPLACE, GL_REPLACE, GL_REPLACE );
82 		glStencilFunc( GL_ALWAYS, 1, 0xffffffff );
83 
84 		glPushMatrix();
85 		glDisable( GL_BLEND );
86 		glEnable( GL_ALPHA_TEST );
87 		//glAlphaFunc( GL_EQUAL, 0xff );
88 		glAlphaFunc( GL_NOTEQUAL, 0 );
89 		glEnable( GL_TEXTURE_2D );
90 		scourge->getShapePalette()->getMinimapMaskTexture().glBind();
91 		glColor4f( 1, 1, 1, 1 );
92 		glBegin( GL_TRIANGLE_STRIP );
93 		glTexCoord2f( 0, 0 );
94 		glVertex2d( 0, 0 );
95 		glTexCoord2f( 1, 0 );
96 		glVertex2d( MINI_MAP_SIZE * MINI_MAP_BLOCK, 0 );
97 		glTexCoord2f( 0, 1 );
98 		glVertex2d( 0, MINI_MAP_SIZE * MINI_MAP_BLOCK );
99 		glTexCoord2f( 1, 1 );
100 		glVertex2d( MINI_MAP_SIZE * MINI_MAP_BLOCK, MINI_MAP_SIZE * MINI_MAP_BLOCK );
101 		glEnd();
102 		glDisable( GL_TEXTURE_2D );
103 		glDisable( GL_ALPHA_TEST );
104 		glPopMatrix();
105 
106 		glColorMask( 1, 1, 1, 1 );
107 		glStencilFunc( GL_EQUAL, 1, 0xffffffff );
108 		glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
109 		glDepthMask( GL_FALSE );
110 
111 		// Draw the transparent background.
112 		glPushMatrix();
113 		glEnable( GL_BLEND );
114 		glEnable( GL_TEXTURE_2D );
115 		scourge->getShapePalette()->getMinimapMaskTexture().glBind();
116 		glColor4f( 0, 0, 0, 0.5f );
117 		glBegin( GL_TRIANGLE_STRIP );
118 		glTexCoord2f( 0, 0 );
119 		glVertex2d( 0, 0 );
120 		glTexCoord2f( 1, 0 );
121 		glVertex2d( MINI_MAP_SIZE * MINI_MAP_BLOCK, 0 );
122 		glTexCoord2f( 0, 1 );
123 		glVertex2d( 0, MINI_MAP_SIZE * MINI_MAP_BLOCK );
124 		glTexCoord2f( 1, 1 );
125 		glVertex2d( MINI_MAP_SIZE * MINI_MAP_BLOCK, MINI_MAP_SIZE * MINI_MAP_BLOCK );
126 		glEnd();
127 		glDisable( GL_TEXTURE_2D );
128 		glPopMatrix();
129 	} else {
130 		// Draw north marker and outline for the "simple" non-stencil version.
131 		glEnable( GL_BLEND );
132 
133 		glColor4f( 0.5f, 0.5f, 0.5f, 0.5f );
134 		glBegin( GL_TRIANGLES );
135 		glVertex2f( 0, 0 );
136 		glVertex2f( 30, 0 );
137 		glVertex2f( 0, 30 );
138 		glEnd();
139 		glPushMatrix();
140 		glRotatef( -45, 0, 0, 1 );
141 		glTranslatef( -7, 20, 0 );
142 		glScalef( 1.5f, 1.5f, 1.5f );
143 		glColor4f( 1, 1, 1, 0.5f );
144 		scourge->getSDLHandler()->texPrint( 0, 0, "N" );
145 		glScalef( 1, 1, 1 );
146 		glPopMatrix();
147 
148 		// outline
149 		glColor4f( 0.5f, 0.5f, 0.5f, 0.5f );
150 		glBegin( GL_LINE_LOOP );
151 		glVertex2f( 0, 0 );
152 		glVertex2f( 0, MINI_MAP_SIZE * MINI_MAP_BLOCK );
153 		glVertex2f( MINI_MAP_SIZE * MINI_MAP_BLOCK, MINI_MAP_SIZE * MINI_MAP_BLOCK );
154 		glVertex2f( MINI_MAP_SIZE * MINI_MAP_BLOCK, 0 );
155 		glEnd();
156 	}
157 
158 	// Draw the surrounding objects into the map. Naive method: draw each block.
159 	for ( int x = sx; x < ex; x++ ) {
160 		if ( x < 0 || x >= MAP_WIDTH ) continue;
161 		for ( int y = sy; y < ey; y++ ) {
162 			if ( y < 0 || y >= MAP_DEPTH ) continue;
163 			Location *pos = scourge->getSession()->getMap()->getLocation( x, y, 0 );
164 
165 			if ( pos ) {
166 
167 				if ( pos->shape ) {
168 
169 					if ( !pos->creature ) {
170 
171 						if ( pos->item ) {
172 							glColor4f( 0, 0, 1, 0.5f );
173 						} else {
174 							if ( !pos->shape->isInteractive() ) {
175 								glColor4f( 1, 1, 1, 0.5f );
176 							} else {
177 								glColor4f( 1, 0.7f, 0, 0.5f );
178 							}
179 						}
180 
181 						float xp = ( x - sx ) * MINI_MAP_BLOCK;
182 						float yp = ( y - sy ) * MINI_MAP_BLOCK;
183 
184 						glBegin( GL_TRIANGLE_STRIP );
185 						glVertex2f( xp, yp );
186 						glVertex2f( xp + MINI_MAP_BLOCK, yp );
187 						glVertex2f( xp, yp + MINI_MAP_BLOCK );
188 						glVertex2f( xp + MINI_MAP_BLOCK, yp + MINI_MAP_BLOCK );
189 						glEnd();
190 
191 					} else {
192 
193 						if ( pos->creature->isMonster() ) {
194 							glColor4f( 1, 0, 0, 0.5f );
195 						} else if ( pos->creature->isNpc() ) {
196 							glColor4f( 0.8f, 0.8f, 0, 0.5f );
197 						} else {
198 							if ( pos->creature == scourge->getSession()->getParty()->getPlayer() ) {
199 								glColor4f( 0, 1, 0, 0.5f );
200 							} else {
201 								glColor4f( 0, 0.8f, 0.8f, 0.5f );
202 								for ( int c = 0; c < scourge->getParty()->getPartySize(); c++ ) {
203 									if ( pos->creature == scourge->getSession()->getParty()->getParty( c ) ) {
204 										glColor4f( 0, 0.8f, 0, 0.5f );
205 										break;
206 									}
207 								}
208 							}
209 						}
210 
211 						float width = pos->creature->getShape()->getWidth() / 2.0f * MINI_MAP_BLOCK;
212 						float cx =  ( pos->creature->getX() - sx ) * MINI_MAP_BLOCK + width;
213 						float cy = ( pos->creature->getY() - sy ) * MINI_MAP_BLOCK - width;
214 
215 						glPushMatrix();
216 						glTranslatef( cx, cy, 0 );
217 						glRotatef( ( ( AnimatedShape* )pos->creature->getShape() )->getAngle(), 0, 0, 1 );
218 						glBegin( GL_TRIANGLES );
219 						glVertex2f( width, width );
220 						glVertex2f( -width, width );
221 						glVertex2f( 0, -width );
222 						glEnd();
223 						glPopMatrix();
224 
225 					}
226 
227 				}
228 
229 			}
230 
231 		}
232 	}
233 
234 	// Draw the minimap frame.
235 	if ( useStencil ) {
236 		glDepthMask( GL_TRUE );
237 		glDisable( GL_STENCIL_TEST );
238 
239 		glPushMatrix();
240 		glEnable( GL_ALPHA_TEST );
241 		glAlphaFunc( GL_ALWAYS, 0 );
242 		glEnable( GL_TEXTURE_2D );
243 		scourge->getShapePalette()->getMinimapTexture().glBind();
244 		glColor4f( 1, 1, 1, 1 );
245 		glBegin( GL_TRIANGLE_STRIP );
246 		glTexCoord2f( 0, 0 );
247 		glVertex2d( 0, 0 );
248 		glTexCoord2f( 1, 0 );
249 		glVertex2d( MINI_MAP_SIZE * MINI_MAP_BLOCK, 0 );
250 		glTexCoord2f( 0, 1 );
251 		glVertex2d( 0, MINI_MAP_SIZE * MINI_MAP_BLOCK );
252 		glTexCoord2f( 1, 1 );
253 		glVertex2d( MINI_MAP_SIZE * MINI_MAP_BLOCK, MINI_MAP_SIZE * MINI_MAP_BLOCK );
254 		glEnd();
255 		glDisable( GL_TEXTURE_2D );
256 		glDisable( GL_ALPHA_TEST );
257 		glPopMatrix();
258 
259 		// draw pointers for gates and teleporters
260 		if ( scourge->getParty() && scourge->getParty()->getPartySize() ) {
261 			drawPointers( scourge->getSession()->getMap()->getGates(), Color( 1, 0, 0, 1 ) );
262 			drawPointers( scourge->getSession()->getMap()->getTeleporters(), Color( 0, 0, 1, 1 ) );
263 		}
264 	}
265 
266 	glPopMatrix();
267 	glDisable( GL_BLEND );
268 	glEnable( GL_CULL_FACE );
269 	glEnable( GL_DEPTH_TEST );
270 	glEnable( GL_TEXTURE_2D );
271 }
272 
drawPointers(std::set<Location * > * p,Color color)273 void MiniMap::drawPointers( std::set<Location*> *p, Color color ) {
274 	// player's pos
275 	float px = scourge->getParty()->getPlayer()->getX();
276 	float py = scourge->getParty()->getPlayer()->getY();
277 
278 	// center coord. of minimap
279 	float r = MINI_MAP_SIZE * MINI_MAP_BLOCK / 2;
280 
281 	for ( set<Location*>::iterator e = p->begin(); e != p->end(); ++e ) {
282 		Location *pos = *e;
283 		float angle = Util::getAngle( px, py, 0, 0, ( float )pos->x, ( float )pos->y, 0, 0 );
284 		float nx = r + ( r - 10 ) * Constants::cosFromAngle( angle ) - 5;
285 		float ny = r + ( r - 10 ) * Constants::sinFromAngle( angle );
286 		glColor4f( color.r, color.g, color.b, color.a );
287 		glBegin( GL_TRIANGLE_STRIP );
288 		glVertex2d( nx, ny );
289 		glVertex2d( nx + 4, ny );
290 		glVertex2d( nx, ny + 4 );
291 		glVertex2d( nx + 4, ny + 4 );
292 		glEnd();
293 		glColor4f( 0, 0, 0, 1 );
294 		glBegin( GL_LINE_LOOP );
295 		glVertex2d( nx - 1, ny + 6 );
296 		glVertex2d( nx + 6, ny + 6 );
297 		glVertex2d( nx + 6, ny - 1 );
298 		glVertex2d( nx - 1, ny - 1 );
299 		glEnd();
300 	}
301 	glColor4f( 1, 1, 1, 1 );
302 }
303