WorldSim  inDev
2D tile-based sandbox RPG with procedurally generated fantasy world simulator 🌏
World_Viewer.hpp
Go to the documentation of this file.
1 #pragma once
2 #ifndef WORLDSIM_WORLD_VIEWER_HPP
3 #define WORLDSIM_WORLD_VIEWER_HPP
4 
5 /* WorldSim: WorldViewer
6  #include "World_Viewer.hpp"
7 
8  Code for rendering the player's view of the world. It is able to render the global (world map) view, and additionally
9  any local maps which have been loaded in.
10 
11  To do this it makes use of doubles. The main number tracks the global rendering coordinates, and the mantissa tracks
12  the local tile rendering coordinates. There's probably a better way of doing this but it's the only way I know and it
13  gets the job done.
14 
15  The World Viewer also takes mouse and keyboard input to control panning and zooming.
16 
17  It provides coordinates (both local and absolute) for the tile the mouse
18  is hovering over.
19 
20  It needs some cleanup and optimization. There are probably many things which could be done to improve performance,
21  this thing can be slow on older computers when zoomed out too far. Also a lot of calculations should be moved out of
22  the render function. It's worth noting that this is not a standard tile renderer. Most RPGs will render maybe a field
23  of 20x20 tiles and therefore optimisation is not a concern. This one in some cases needs to render more tiles than
24  there are screen pixels.
25 
26  This class could technically be moved into Wildcat but it's not likely to be used for much else so it's not a big
27  deal for now.
28 
29  We should be able to significantly improve render efficiency by building an array or vector of textures to draw.
30 
31  Then we draw each texture, only binding them once. Texture binding seems to be expensive so I think this will save
32  a lot of render time.
33 
34 */
35 
36 #include <Device/Display/DisplayInterface.hpp>
37 #include <Device/Mouse/MouseInterface.hpp>
38 #include <Graphics/Render/Renderer.hpp>
39 #include <Game/WorldGenerator/Biome.hpp> // For rendering biomes. Needs to be fixed
40 #include "WorldObjectGlobal.hpp"
41 #include "Creature.hpp"
42 #include "Tribe.hpp"
43 
45 
46 
47 class WorldViewer: public DisplayInterface, public MouseInterface
48 {
49  private:
50 
51  /* Rendering coordinates.
52  These should be updated to use the standard GUI panel system */
53  int mainViewX1, mainViewX2, mainViewY1, mainViewY2;
54  int mainViewNX, mainViewNY;
55 
56  double localTileMantissa;
57 
58  // Here is what we should really be drawing, rather than deciding during the render call.
59  // Ideally this should also be running in a thread, locking when render is called.
60  ArrayS2 <Vector <Texture* > > aScene;
61 
62  public:
63  //RAIN
65 
66  bool active;
67 
68  int tileSize; /* How big to render the tiles, in pixels. */
69 
70  /* The tile at the center of the screen.
71  Note that the mantissa is used to center on local tiles.
72  This must be a double due to the required level of precision.
73  */
75 
76  /* The first tile rendered, and the pixel coordinates where it is rendered */
77  /* We store this for other functions to use. */
79  unsigned long int firstTileAbsX, firstTileAbsY; /* (0,0) absolute of the above */
81 
82  // Temp: Local tile to render.
85 
86 
87  /* Store the last position of the mouse, so we can figure out which tile the mouse is on. */
88  short int lastMouseX, lastMouseY;
89 
92 
93  bool panning;
94  float panX, panY; /* Stores the last mouse position when panning. Needs to be a double. */
95 
97 
98  /* The current tile that the mouse is hovering over. Set to -1 if the mouse is not hovering over a tile. */
101  unsigned long int hoveredAbsoluteX, hoveredAbsoluteY;
103 
105 
109  bool landMode; // Show only landmasses
110 
111  // If true, game will randomly scroll around.
112  // In the future, the title screen will probably be scrolling around a map.
113  bool demoMode;
114  double demoScroll;
115 
117  {
118  tileSize=8;
119  tilesToSkip=0;
120  pixelsPerLocalTile = ((double)tileSize/LOCAL_MAP_SIZE);
121  localTileMantissa = (double)1/(double)LOCAL_MAP_SIZE;
122 
123  centerTileX=0; centerTileY=0;
124  world=0;
125  mainViewX1=0; mainViewX2=0;
126  mainViewY1=0; mainViewY2=0;
127  mainViewNX=0; mainViewNY=0;
128  active=false;
129 
130  panX=0; panY=0;
131 
132  panning=false;
133  alternateTile=0;
134 
135  lastMouseX=0;
136  lastMouseY=0;
137 
138  hoveredXTile=0;
139  hoveredYTile=0;
140  hoveredXTileLocal=0;
141  hoveredYTileLocal=0;
142  hoveredAbsoluteX=ABSOLUTE_COORDINATE_NULL;
143  hoveredAbsoluteY=ABSOLUTE_COORDINATE_NULL;
144 
145  showHoveredTile=false;
146 
147  centerLocalX=LOCAL_MAP_SIZE/2;
148  centerLocalY=LOCAL_MAP_SIZE/2;
149 
150  firstTileX=0;
151  firstTileY=0;
152  firstPixelX=0;
153  firstPixelY=0;
154  firstTileAbsX=0;
155  firstTileAbsY=0;
156 
157  territoryView = false;
158  tilesetMode = true;
159  landMode = false;
160  subterraneanMode = false;
161 
162  demoMode = false;
163  demoScroll = 0.1;
164 
165  rainManager.init(0,0,0,0,0);
166  }
167 
168  // Center the view on the middle of the world. Good for initializing.
169  void centerView()
170  {
171  if (world==0)
172  { return; }
173 
174  centerTileX = world->nX/2;
175  centerTileY = world->nY/2;
176 
177  centerTileX+=0.5;
178  centerTileY+=0.5;
179  }
180 
181  bool keyboardEvent( Keyboard* _keyboard )
182  {
183  //zoomIn();
184  //return false;
185  // Zoom the main map in by one step. (Can use either top row or numpad)
186  if(_keyboard->isPressed(Keyboard::EQUALS) || _keyboard->isPressed(Keyboard::PLUS))
187  {
188  if (_keyboard->keyWasPressed)
189  {
190  zoomIn();
191  }
192  }
193  /* Zoom the main map out by one step. */
194  if(_keyboard->isPressed(Keyboard::MINUS))
195  {
196  if (_keyboard->keyWasPressed)
197  {
198  zoomOut();
199  }
200  }
201 
202  return false;
203  }
204 
205  void zoomIn()
206  {
207  if ( tilesToSkip > 0 )
208  { --tilesToSkip; }
209  else
210  {
211  tileSize*=2;
212  if(tileSize>2000000)
213  { tileSize=2000000; }
214  }
215  pixelsPerLocalTile = ((double)tileSize/LOCAL_MAP_SIZE);
216  }
217 
218  void zoomOut()
219  {
220  tileSize/=2;
221 
222  if(tileSize<1)
223  { tileSize=1; ++tilesToSkip; }
224  pixelsPerLocalTile = ((double)tileSize/LOCAL_MAP_SIZE);
225  }
226 
227  void setTileSize(const int _tileSize)
228  {
229  tileSize=_tileSize;
230  tilesToSkip=0;
231  pixelsPerLocalTile = ((double)tileSize/LOCAL_MAP_SIZE);
232  }
233 
234  void switchTarget(World_Local* _worldLocal)
235  {
236  worldLocal=_worldLocal;
237  }
238 
239 
240  /* Keep the map visible on the screen so the player can't accidentally move it off screen and lose it. */
242  {
243  if ( centerTileX < 0 )
244  {
245  centerTileX=0;
246  }
247  if ( centerTileY < 0 )
248  {
249  centerTileY=0;
250  }
251  if ( centerTileX > world->nX )
252  {
253  centerTileX = world->nX;
254  }
255  if ( centerTileY > world->nY )
256  {
257  centerTileY = world->nY;
258  }
259  }
260 
261  bool mouseEvent ( Mouse* mouse )
262  {
263  if ( world==0 ) { return false; }
264 
265  lastMouseX=mouse->x;
266  lastMouseY=mouse->y;
267 
268  if(panning==true)
269  {
270  /* The view can be panned by holding down the middle mouse button
271  and moving the mouse to drag the map. */
272  centerTileX+=(panX-mouse->x)/((float)tileSize/(tilesToSkip+1));
273  centerTileY+=(panY-mouse->y)/((float)tileSize/(tilesToSkip+1));
274  panX=mouse->x;
275  panY=mouse->y;
276  }
277 
278  if(mouse->isMiddleClick==false)
279  {
280  panning=false;
281  }
282  if ( mouse->isMiddleClick)
283  {
284  panning=true;
285  /* Set initial pan coordinates. */
286  panX=mouse->x;
287  panY=mouse->y;
288  }
289 
290  if(mouse->isWheelDown)
291  {
292  zoomOut();
293  mouse->isWheelDown=false;
294  }
295  if(mouse->isWheelUp)
296  {
297  zoomIn();
298  mouse->isWheelUp=false;
299  }
300 
302 
303  if ( mouse->isLeftClick == true )
304  {
305  world->queryTile(hoveredXTile,hoveredYTile);
306  world->queryTileLocal(hoveredXTileLocal,hoveredYTileLocal);
307  }
308 
309  if (mouse->isRightClick)
310  {
311  world->generateLocal(hoveredXTile,hoveredYTile);
314  }
315  return false;
316  }
317 
318  void setPanel( const int _x1, const int _y1, const int _x2, const int _y2)
319  {
320  // Todo: Update class to use standard GUI panel system.
321  mainViewX1 = _x1;
322  mainViewY1 = _y1;
323  mainViewX2 = _x2;
324  mainViewY2 = _y2;
325 
326  mainViewNX = mainViewX2-mainViewX1;
327  mainViewNY = mainViewY2-mainViewY1;
328 
329  pixelsPerLocalTile = ((double)tileSize/LOCAL_MAP_SIZE);
330 
331  rainManager.init(_x1,_y1,_x2,_y2,world);
332  }
333 
334  inline void setCenterTile (const double _centerTileX, const double _centerTileY,
335  const int _subTileX=LOCAL_MAP_SIZE/2, const int _subTileY=LOCAL_MAP_SIZE/2)
336  {
337  centerTileX = _centerTileX;
338  centerTileY = _centerTileY;
339 
340  centerTileX += (_subTileX * localTileMantissa)+localTileMantissa/2;
341  centerTileY += (_subTileY * localTileMantissa)+localTileMantissa/2;
342  }
343 
344  /* Convert tile coordinates to screen (pixel) coordinates. */
345  void toScreenCoords(const int _tileX, const int _tileY, int * _pixelX, int * _pixelY)
346  {
347  float centerTileXDecimal = centerTileX - (int)centerTileX;
348  float centerTileYDecimal = centerTileY - (int)centerTileY;
349 
350  float centerTileXPixels = centerTileXDecimal*tileSize;
351  float centerTileYPixels = centerTileYDecimal*tileSize;
352 
353 
354  //double pixelOffsetX = tileSize*centerTileXDecimal;
355  //double pixelOffsetY = tileSize*centerTileYDecimal;
356 
357  const int iCenterTileX = centerTileX;
358 
359 
360  const int tilesToDrawX = (mainViewNX/tileSize) + 1;
361  const int tilesToDrawY = (mainViewNY/tileSize) + 1;
362 
363  int tileX=centerTileX;
364  int pixelTileX = mainViewX1+(mainViewNX/2) - centerTileXPixels;
365  while(pixelTileX>=mainViewX1)
366  {
367  --tileX;
368  tileX-=tilesToSkip;
369  pixelTileX-=tileSize;
370  }
371  const int revertTileX = tileX;
372 
373  int tileY=centerTileY;
374  int pixelTileY = mainViewY1 + (mainViewNY/2) - centerTileYPixels;
375  while(pixelTileY>=0)
376  {
377  --tileY;
378  tileY-=tilesToSkip;
379  pixelTileY-=tileSize;
380  }
381 
382 
383  int nExtraXTiles = _tileX - tileX;
384  int nExtraYTiles = _tileY - tileY;
385 
386  if ( nExtraXTiles>=0 && nExtraYTiles>=0 )
387  {
388  *_pixelX = pixelTileX + (tileSize * nExtraXTiles);
389  *_pixelY = pixelTileY + (tileSize * nExtraYTiles);
390  }
391  else
392  {
393  *_pixelX = -1000;
394  *_pixelY = -1000;
395  }
396  }
397 
398  // Take the given pixels and calculate what tile they are. This is in absolute coordinates.
399  // I need to add a version which can do relative coords.
400  void toTileCoords(int pixelX, int pixelY, unsigned long int * absX, unsigned long int * absY)
401  {
402  if (absX==0 || absY==0) {return;}
403 
404  if (pixelX<0 || pixelY<0 || pixelsPerLocalTile == 0)
405  {
408  }
409 
410  int pixelDistanceX = pixelX - firstPixelX;
411  int pixelDistanceY = pixelY - firstPixelY;
412 
413  if ( pixelDistanceX < 0 || pixelDistanceY < 0 )
414  {
415  *absX=0;
416  *absY=0;
417  return;
418  }
419 
420  *absX = firstTileAbsX + ((double)pixelDistanceX/pixelsPerLocalTile);
421  *absY = firstTileAbsY + ((double)pixelDistanceY/pixelsPerLocalTile);
422  }
423 
424  /* HERE I RENDER THE GRAPHICAL ICONS WHICH ARE PRESENT ON THE WORLD MAP, FOR EXAMPLE: CITIES AND ARMIES. */
425  /* ONLY A SMALL NUMBER OF WORLD TILES WILL HAVE AN ICON ON THEM, SO I WILL USE A DIFFERENT TECHNIQUE. */
427  {
428  if (active == false)
429  { return; }
430  if(world==0)
431  {
432  std::cout<<"ABORT: No world to render.\n";
433  return;
434  }
435 
436  // set viewport to panel
437  Renderer::saveViewPort();
438  Renderer::resizeViewPort(mainViewX1,mainViewY1,mainViewX2,mainViewY2);
439 
440  // some pixel coordinate calculations
441  // needs to be cleaned up
442 
443  float centerTileXDecimal = centerTileX - (int)centerTileX;
444  float centerTileYDecimal = centerTileY - (int)centerTileY;
445 
446  float pixelOffsetX = tileSize*centerTileXDecimal;
447  float pixelOffsetY = tileSize*centerTileYDecimal;
448 
449  const int iCenterTileX = centerTileX;
450 
451  const int tilesToDrawX = (mainViewNX/tileSize) + 1;
452  const int tilesToDrawY = (mainViewNY/tileSize) + 1;
453 
454  int tileX=centerTileX;
455  int pixelTile = mainViewNX/2;
456 
457  // this is bad but I'm too tired to figure out how to fix it rn
458  while(pixelTile>=0)
459  {
460  --tileX;
461  pixelTile-=tileSize;
462  }
463  const int revertTileX = tileX;
464 
465  int tileY=centerTileY;
466  pixelTile = mainViewNY/2;
467  while(pixelTile>=0)
468  {
469  --tileY;
470  pixelTile-=tileSize;
471  }
472 
473  Renderer::setTextureMode();
474 
475  // Draw global world objects
476  // Basically stuff like armies, fleets, tribes
477  for (int i=0;i<world->vWorldObjectGlobal.size();++i)
478  {
479  WorldObjectGlobal* wog = world->vWorldObjectGlobal(i);
480 
481  // Check if we're supposed to render a local map on this tile.
482  // If so, don't draw world icons over it.
483  if ( tileSize > 4 && world->isSafe(tileX,tileY) )
484  {
485  for ( int i2=0;i2<world->vWorldLocal.size();++i2)
486  {
487  if ( world->vWorldLocal(i2)->globalX == wog->worldX
488  && world->vWorldLocal(i2)->globalY == wog->worldY )
489  {
490  wog = 0;
491  break;
492  }
493  }
494  }
495 
496  if ( wog == 0 ) { continue; }
497 
498  int wogPixelX=-1;
499  int wogPixelY=-1;
500 
501  toScreenCoords(wog->worldX,wog->worldY,&wogPixelX,&wogPixelY);
502 
503  // I NEED TO DO A CHECK TO SEE IF THE OBJECT IS VISIBLE WITHIN THE CURRENT VIEW.
504  if ( wogPixelX != -1000 && wogPixelY != -1000 )
505  {
506  Renderer::placeTexture4(wogPixelX,wogPixelY,wogPixelX+tileSize,wogPixelY+tileSize
507  ,wog->currentTexture(),false);
508  }
509  }
510  /* RESTORE THE VIEWPORT TO THE PREVIOUS SETTING (PROBABLY THE WHOLE PANEL). */
511  Renderer::restoreViewPort();
512  }
513 
514  // This function should run in the background and basically constantly build and update the array of textures to render.
515  // We need code to build the world view, and code to build the local map view.
516  // We can start with just the global view because it's less complicated.
517  // The scene should not update more than once per frame. Otherwise we're going to be constantly loading and unloading
518  // arrays for nothing.
519  void updateScene()
520  {
521  }
522 
523  void render()
524  {
525  if (active == false || world==0)
526  { return; }
527 
528  if ( demoMode )
529  {
530  if ( centerTileX < 10 && demoScroll < 0 )
531  {
532  demoScroll = demoScroll * -1;
533  }
534  else if ( centerTileX > world->nX - 10 && demoScroll > 0 )
535  {
536  demoScroll = demoScroll * -1;
537  }
538  centerTileX += demoScroll;
539  }
540 
541  // I don't know why this has to be here but it do
542  pixelsPerLocalTile = ((double)tileSize/LOCAL_MAP_SIZE);
543 
544  hoveredAbsoluteX = ABSOLUTE_COORDINATE_NULL;
545  hoveredAbsoluteY = ABSOLUTE_COORDINATE_NULL;
546 
547  Renderer::saveViewPort();
548  Renderer::resizeViewPort(mainViewX1,mainViewY1,mainViewX2,mainViewY2);
549 
550  /* The World Viewer is passed centre coordinates because typically the camera needs to be centered on something.
551  However from this we must calculate what coordinates to start rendering from in the top-left.
552  Therefore we take the centre coordinates and work back to the top-left. This is done for both the tile (array)
553  coordinates, and the rendering (pixel) coordinates. */
554 
555  float centerTileXDecimal = centerTileX - (int)centerTileX;
556  float centerTileYDecimal = centerTileY - (int)centerTileY;
557  float centerTileXPixels = centerTileXDecimal*tileSize;
558  float centerTileYPixels = centerTileYDecimal*tileSize;
559 
560  const int iCenterTileX = centerTileX;
561 
562  const int tilesToDrawX = (mainViewNX/tileSize) + 1;
563  const int tilesToDrawY = (mainViewNY/tileSize) + 1;
564 
565  int tileX=centerTileX;
566  int pixelTileX = mainViewX1+(mainViewNX/2) - centerTileXPixels;
567  while(pixelTileX>=mainViewX1)
568  {
569  --tileX;
570  tileX-=tilesToSkip;
571  pixelTileX-=tileSize;
572  }
573  const int revertTileX = tileX;
574 
575  int tileY=centerTileY;
576  int pixelTileY = mainViewY1 + (mainViewNY/2) - centerTileYPixels;
577  while(pixelTileY>=0)
578  {
579  --tileY;
580  tileY-=tilesToSkip;
581  pixelTileY-=tileSize;
582  }
583  //We need to store the top-left coordinates for other functions to use.
584  firstTileX=tileX;
585  firstTileY=tileY;
586  if (world->isSafe(tileX,tileY))
587  {
588  firstTileAbsX=tileX*LOCAL_MAP_SIZE;
589  firstTileAbsY=tileY*LOCAL_MAP_SIZE;
590  }
591  else
592  {
593  firstTileAbsX=ABSOLUTE_COORDINATE_NULL;
594  firstTileAbsY=ABSOLUTE_COORDINATE_NULL;
595  }
596  firstPixelX=pixelTileX;
597  firstPixelY=pixelTileY;
598 
599  /* UPDATE HOVERED TILE COORDS. */
600  /* MAKE SURE MOUSE IS WITHIN THE RENDERING VIEW */
601  if (lastMouseX >= mainViewX1 && lastMouseX <= mainViewX2
602  && lastMouseY >= mainViewY1 && lastMouseY <= mainViewY2 )
603  {
604  const int startingPX = pixelTileX;
605  const int startingPY = pixelTileY;
606 
607  int diffX = (lastMouseX - startingPX)/tileSize;
608  int diffY = (lastMouseY - startingPY)/tileSize;
609 
610  /* UPDATE THE COORDS OF THE HOVERED TILE. */
611  hoveredXTile = tileX + diffX;
612  hoveredYTile = tileY + diffY;
613  }
614  else
615  {
616  hoveredXTile=-1;
617  hoveredYTile=-1;
618  }
619 
620  if ( tilesetMode == false )
621  {
622  renderColourMode(tileX,tileY,pixelTileX,pixelTileY);
623  }
624  else // Render in texture mode
625  {
626  renderTextureMode(tileX,tileY,pixelTileX,pixelTileY);
627  }
628  if(subterraneanMode==false)
629  {
630  rainManager.render();
631  }
632 
633  Renderer::restoreViewPort();
634  // Now render the icons on the world map.
637  }
638 
639  // Render the local map for this world tile. This is most likely because
640  // the player is active in this tile and looking at it.
641  void renderLocalMap(World_Local* localMap, int currentX, int currentY)
642  {
643  float currentSubY = currentY;
644  float nextSubY = currentY + pixelsPerLocalTile;
645 
646  int subTileSize = pixelsPerLocalTile;
647  if (subTileSize < 1) { subTileSize = 1; }
648 
649  const enumBiome localBaseBiome = localMap->baseBiome;
650 
651  // this needs to be fixed, we should simply be asking
652  // the local map and local tile what to draw.
653  for (int localYTile = 0; localYTile<LOCAL_MAP_SIZE;++localYTile)
654  {
655  if ( nextSubY>=mainViewY1 && currentSubY <= mainViewY2 && floor(currentSubY) != floor(nextSubY) )
656  {
657  float currentPixel = currentX;
658  float nextPixel = currentX+pixelsPerLocalTile;
659  for (int localXTile = 0; localXTile<LOCAL_MAP_SIZE;++localXTile)
660  {
661  if ( nextPixel>=mainViewX1 && currentPixel <= mainViewX2 && floor(currentPixel) != floor(nextPixel) )
662  {
663  // Render subterranean mode
664  if ( subterraneanMode && localMap->dataSubterranean)
665  {
666  // render order:
667  // terrain
668  // static
669  // objects
670  // fog
671  // overlay
672 
673  glColor4ub(255,255,255,255);
674  //Very basic player line of sight check here (only if we're in Adventure mode)
675  // Unseen tiles
677  && playerCharacter->hasSeen(localMap, localXTile,localYTile,true) == 0 )
678  {
679  }
680  //Previously seen tiles
682  && playerCharacter->hasSeen(localMap, localXTile,localYTile,true) == 1 )
683  {
684  //Draw tile very dark to symbolise fog of war
685  LocalTile* localTile = &localMap->dataSubterranean->aSubterranean(localXTile,localYTile);
686 
687  Vector <Texture*> * vText = localTile->currentTextures();
688  if ( vText != 0)
689  {
690  for (int i=0;i<vText->size();++i)
691  {
692  Renderer::placeTexture4(currentPixel, currentSubY, ceil(nextPixel), ceil(nextSubY),
693  (*vText)(i), false);
694  }
695  }
696  delete vText;
697  }
698  else /* DRAW VISIBLE TILES */
699  {
700  LocalTile* localTile = &localMap->dataSubterranean->aSubterranean(localXTile,localYTile);
701  Vector <Texture*> * vText = localTile->currentTextures();
702  if ( vText != 0)
703  {
704  for (int i=0;i<vText->size();++i)
705  {
706  Renderer::placeTexture4(currentPixel, currentSubY, ceil(nextPixel), ceil(nextSubY),
707  (*vText)(i), false);
708  }
709  }
710  for(int i=0;i<localMap->dataSubterranean->aSubterranean(localXTile,localYTile).vObject.size();++i)
711  {
712  Renderer::placeTexture4(currentPixel, currentSubY, ceil(nextPixel), ceil(nextSubY),
713  localMap->dataSubterranean->aSubterranean
714  (localXTile,localYTile).vObject(i)->currentTexture(), false);
715  }
716  delete vText;
717  }
718  }
719  // Render non-subterranean mode
720  else
721  {
722  //Very basic player line of sight check here (only if we're in Adventure mode)
723  // Render tiles we have never seen before (basically leave them black)
725  && playerCharacter->hasSeen(localMap, localXTile,localYTile) == 0 )
726  {
727  }
728  // Render tiles seen before but not currently seen.
730  && playerCharacter->hasSeen(localMap, localXTile,localYTile) == 1 )
731  {
732  //Draw tile very dark to symbolise fog of war
733  LocalTile* localTile = &localMap->data->aLocalTile(localXTile,localYTile);
734 
735  unsigned char lightValue = 80;
736  glColor3ub(lightValue,lightValue,lightValue);
737  //Renderer::placeTexture4(currentPixel, currentSubY, ceil(nextPixel), ceil(nextSubY), localTile->currentTexture(), false);
738 
739  Vector <Texture*> * vText = localTile->currentTextures();
740  if ( vText != 0)
741  {
742  for (int i=0;i<vText->size();++i)
743  {
744  Renderer::placeTexture4(currentPixel, currentSubY, ceil(nextPixel), ceil(nextSubY),
745  (*vText)(i), false);
746  }
747  }
748  delete vText;
749 
750  glColor3ub(255,255,255);
751  }
752  // Render tiles we can currently see
753  else
754  {
755  LocalTile* localTile = &localMap->data->aLocalTile(localXTile,localYTile);
756 
757  // this belongs in World.
758  // Due to increase in height levels we will remove the height shading and replace it with
759  // height shading relative to player's height. This obviously will only work when a player
760  // exists
761 
762  /* This is an absolute shading system. It allows for 127 shades of height, and then wraps back
763  down to the lowest. This seems to be a reasonably effective way of showing absolute heights
764  which exceed 127, as the player can simply count out how many "rings" of wrapping there are to
765  get a good idea of the elevation. */
766 
767  unsigned char lightValue = localTile->height+127;
768  if ( lightValue < 127 ) { lightValue += 127; }
769  //unsigned char lightValue = 255;
770 
771  int currentSecond = globalCalendar.second;
772  int sunsetCounter = currentSecond-50;
773 
774  int currentMinute = globalCalendar.minute;
775  int currentHour = globalCalendar.hour;
776 
777  // This is a bad implementation. We should overlay a colour over the whole playfield instead.
778  glColor3ub(lightValue,lightValue,lightValue);
779  // NIGHT
780  if (currentHour < 6 || currentHour > 19)
781  {
782  //glColor3ub(50+lightValue,50+lightValue,50+lightValue);
783  //glColor3ub(lightValue,lightValue,lightValue);
784  }
785  else if (currentHour == 6) // SUNRISE
786  {
787  //glColor3ub(110+lightValue,100+lightValue,120+lightValue);
788  }
789  else if (currentHour == 19) // SUNSET
790  {
791  //glColor3ub(130+lightValue,100+lightValue,100+lightValue);
792  }
793  else
794  {
795  //glColor3ub(180+lightValue,180+lightValue,180+lightValue);
796  //glColor3ub(80+(lightValue/2),80+(lightValue/2),80+(lightValue/2));
797  //if (currentSecond > 50 )
798  //{
799  //glColor3ub(80+(sunsetCounter*9)+(lightValue/2),80+(sunsetCounter*9)+(lightValue/2),
800  //80+(sunsetCounter*10)+(lightValue/2));
801  //}
802  }
803 
804  // draw all textures for this tile
805  // in future this should be copied to an array for later smart rendering, preferably outside of render function.
806  Vector <Texture*> * vText = localTile->currentTextures();
807  if ( vText != 0)
808  {
809  for (int i=0;i<vText->size();++i)
810  {
811  Renderer::placeTexture4
812  (currentPixel, currentSubY, ceil(nextPixel), ceil(nextSubY), (*vText)(i), false);
813  }
814  }
815  delete vText;
816 
817  glColor3ub(255,255,255);
818 
819  // Draw wall if necessary.
820  // Move this to static
821  // this is bad, needs to account for multiple blockers
822  if (localTile->bWall != 0 )
823  {
824  if ( (localTile->bWall & 0b10001000) == 0b10001000) // NORTH
825  {
826  Renderer::placeTexture4RotatedDegrees
827  (currentPixel, currentSubY, ceil(nextPixel), ceil(nextSubY),
829  }
830  if ( (localTile->bWall & 0b00010001) == 0b00010001) // WEST
831  {
832  Renderer::placeTexture4RotatedDegrees
833  (currentPixel, currentSubY, ceil(nextPixel), ceil(nextSubY),
835  }
836  if ( (localTile->bWall & 0b01000100) == 0b01000100) // EAST
837  {
838  Renderer::placeTexture4RotatedDegrees
839  (currentPixel, currentSubY, ceil(nextPixel), ceil(nextSubY),
841  }
842  if ( (localTile->bWall & 0b00100010) == 0b00100010) // SOUTH
843  {
844  Renderer::placeTexture4
845  (currentPixel, currentSubY, ceil(nextPixel), ceil(nextSubY),
846  &TEX_WALL_GREYBRICK_SOUTH, false);
847  }
848  // else if ( localTile->bWall == 0b01100110) // SE
849  // {
850  // Renderer::placeTexture4
851  // (currentPixel, currentSubY, ceil(nextPixel), ceil(nextSubY),
852  // &TEX_WALL_GREYBRICK_SE, false);
853  // }
854  // else if ( localTile->bWall == 0b00110011) // SW
855  // {
856  // Renderer::placeTexture4RotatedDegrees
857  // (currentPixel, currentSubY, ceil(nextPixel), ceil(nextSubY), &TEX_WALL_GREYBRICK_SE, 90);
858  // }
859  // else if ( localTile->bWall == 0b10011001) // NW
860  // {
861  // Renderer::placeTexture4RotatedDegrees
862  // (currentPixel, currentSubY, ceil(nextPixel), ceil(nextSubY), &TEX_WALL_GREYBRICK_SE, 180);
863  // }
864  // else if ( localTile->bWall == 0b11001100) // NE
865  // {
866  // Renderer::placeTexture4RotatedDegrees
867  // (currentPixel, currentSubY, ceil(nextPixel), ceil(nextSubY), &TEX_WALL_GREYBRICK_SE, 270);
868  // }
869  }
870  }
871  }
872 
873  // UPDATE LOCAL TILE HOVERED AND ABSOLUTE COORDS
874  // ALSO OPTIONALLY RENDER A SELECTION TEXTURE
875  if ( lastMouseX > currentPixel && lastMouseX < ceil(nextPixel) && lastMouseY > currentSubY && lastMouseY < ceil(nextSubY) )
876  {
877  hoveredXTileLocal = localXTile;
878  hoveredAbsoluteX = hoveredXTile * LOCAL_MAP_SIZE + localXTile;
879  hoveredYTileLocal = localYTile;
880  hoveredAbsoluteY = hoveredYTile * LOCAL_MAP_SIZE + localYTile;
881 
882  if ( showHoveredTile )
883  {
884  //The lines get overwritten if you don't -1. Do not add -1 anywhere else because it causes artifacts.
885  Renderer::placeBorder4(255,0,0,currentPixel, currentSubY, ceil(nextPixel)-1, ceil(nextSubY)-1);
886  Renderer::setTextureMode();
887  }
888  }
889  }
890  currentPixel=nextPixel;
891  nextPixel+=pixelsPerLocalTile;
892  }
893  }
894  currentSubY=nextSubY;
895  nextSubY+=pixelsPerLocalTile;
896  }
897  }
898 
899  // render the world using the texture system.
900  void renderTextureMode(int tileX, int tileY, float pixelTileX, float pixelTileY)
901  {
902  Renderer::setTextureMode();
903  const int revertTileX = tileX;
904 
905  for (int currentY = pixelTileY; currentY<mainViewNY; currentY+=tileSize)
906  {
907  //initial case
908  glColor3ub(255,255,255);
909 
910  for (int currentX = pixelTileX; currentX<mainViewNX+tileSize; currentX+=tileSize)
911  {
912  if (world->isSafe(tileX,tileY))
913  {
914 
915  // Check if we're supposed to render a local map on this tile.
916  World_Local * localMap = 0;
917  if ( tileSize >= 12 )
918  {
919  for ( int i=0;i<world->vWorldLocal.size();++i)
920  {
921  if ( world->vWorldLocal(i)->globalX == tileX && world->vWorldLocal(i)->globalY == tileY )
922  {
923  localMap = world->vWorldLocal(i);
924  break;
925  }
926  }
927  }
928 
929  // This tile needs to be rendered as a local map.
930  //if (tileSize > 4 && localX == tileX && localY == tileY && world->isSafe(tileX,tileY))
931  if ( localMap != 0 && localMap->data != 0 && localMap->initialized && tileSize > LOCAL_MAP_SIZE*2)
932  {
933  renderLocalMap(localMap,currentX,currentY);
934  }
935  else if (landMode)
936  {
937  // only render grassland and ocean tiles.
938  if(world->isLand(tileX,tileY)==false)
939  {
940  Renderer::placeTexture4(currentX, currentY, currentX+tileSize, currentY+tileSize,
942  }
943  else if(world->isLand(tileX,tileY)==true)
944  {
945  Renderer::placeTexture4(currentX, currentY, currentX+tileSize, currentY+tileSize,
947  }
948  }
949  // Render this tile as a world tile.
950  else
951  {
952  /* Textures are chosen here rather than from tile objects because it is highly dependent on
953  neighboring tiles. It would be possible to delegate texture handling to tile objects, but would take
954  too much memory maintaining pointers to neighbours. In future I should probably write a class
955  which returns joining textures based on neighbors. */
956 
957  // Todo:
958  // tile should just return vector of textures tbh
959 
960  // UPDATE: Textures should be assigned to World_Local at generation/modification, to save cycles on
961  // render time.
962  World_Local * tile = &(world->aWorldTile(tileX,tileY));
963  if (tile)
964  {
965  Renderer::placeTexture4(currentX, currentY, currentX+tileSize, currentY+tileSize,
966  tile->currentTexture(), false);
967  }
968 
969  // DRAW IMPROVEMENTS (FOREST, RIVER)
970  // Improvements can layer over base terrain, and each other.
971  // For example a tile may have a river and forest.
972  // This should be handled by the tile
973  if(world->isLand(tileX,tileY) && world->aWorldTile(tileX,tileY).baseBiome == FOREST)
974  {
975  Renderer::placeTexture4
976  (currentX, currentY, currentX+tileSize, currentY+tileSize,
978  }
979  else if(world->isLand(tileX,tileY) &&world->aWorldTile(tileX,tileY).baseBiome == JUNGLE)
980  {
981  Renderer::placeTexture4
982  (currentX, currentY, currentX+tileSize, currentY+tileSize, &TEX_WORLD_TERRAIN_JUNGLE, false);
983  }
984  if(world->isLand(tileX,tileY) && world->aWorldTile(tileX,tileY).baseBiome == MOUNTAIN &&
985  world->aWorldTile(tileX,tileY).active==false)
986  {
987  Renderer::placeTexture4
988  (currentX, currentY, currentX+tileSize, currentY+tileSize,
990  }
991  if(world->isLand(tileX,tileY) && world->aWorldTile(tileX,tileY).baseBiome == HILLY)
992  {
993  Renderer::placeTexture4
994  (currentX, currentY, currentX+tileSize, currentY+tileSize, &TEX_WORLD_TERRAIN_HILL, false);
995  }
996  if(world->isLand(tileX,tileY) && world->aRiverID(tileX,tileY) != -1)
997  {
998  Renderer::placeTexture4
999  (currentX, currentY, currentX+tileSize, currentY+tileSize, &TEX_WORLD_TERRAIN_RIVER_FULL, false);
1000  }
1001 
1002  // Render tribe territory colour if necessary
1003  if (territoryView)
1004  {
1005  //Renderer::setColourMode();
1006  // Get territory colour of dominant tribe on this tile and draw it as a transparent overlay
1007  const Tribe* dominantTribe = world->aWorldTile(tileX,tileY).getDominantInfluence();
1008  if (dominantTribe!=0)
1009  {
1010  Renderer::placeColour4a(dominantTribe->colourRed,dominantTribe->colourGreen,
1011  dominantTribe->colourBlue, 150, currentX, currentY, currentX+tileSize, currentY+tileSize);
1012  }
1013  //Renderer::setTextureMode();
1014  }
1015  }
1016  }
1017  ++tileX;
1018  tileX+=tilesToSkip;
1019  }
1020  tileX=revertTileX;
1021  ++tileY;
1022  tileY+=tilesToSkip;
1023  }
1024  }
1025 
1026  // render the world using the old colour system. Generally not used.
1027  void renderColourMode(int tileX, int tileY, float pixelTileX, float pixelTileY)
1028  {
1029  // Pixel coords for leftmost tile.
1030  Renderer::setColourMode();
1031 
1032  const int revertTileX = tileX;
1033 
1034  for (int currentY = pixelTileY; currentY<mainViewNY; currentY+=tileSize)
1035  {
1036  glBegin(GL_QUAD_STRIP);
1037 
1038  // initial case
1039  glColor3ub(0,0,0);
1040 
1041  for (int currentX = pixelTileX; currentX<mainViewNX+tileSize; currentX+=tileSize)
1042  {
1043  if(world->isSafe(tileX,tileY)==true)
1044  {
1045  glVertex2s(currentX,currentY);
1046  glVertex2s(currentX,currentY+tileSize);
1047 
1048  // Territory view
1049  if (territoryView)
1050  {
1051  const Tribe* dominantTribe = world->aWorldTile(tileX,tileY).getDominantInfluence();
1052  if (dominantTribe!=0)
1053  {
1054  glColor3ub(dominantTribe->colourRed,dominantTribe->colourGreen,dominantTribe->colourBlue);
1055  }
1056  else
1057  {
1058  glColor3ub(world->aTopoMap(tileX,tileY,0),world->aTopoMap(tileX,tileY,1),
1059  world->aTopoMap(tileX,tileY,2));
1060  }
1061  }
1062  else if (landMode)
1063  {
1064  // only draw land and ocean textures.
1065  if(world->isLand(tileX,tileY)==false)
1066  {
1067  glColor3ub(TEX_WORLD_TERRAIN_OCEAN_00.averageRed,TEX_WORLD_TERRAIN_OCEAN_00.averageGreen,
1068  TEX_WORLD_TERRAIN_OCEAN_00.averageBlue);
1069  }
1070  else if(world->isLand(tileX,tileY)==true)
1071  {
1072  glColor3ub(TEX_WORLD_TERRAIN_GRASS_00.averageRed,TEX_WORLD_TERRAIN_GRASS_00.averageGreen,
1073  TEX_WORLD_TERRAIN_GRASS_00.averageBlue);
1074  }
1075  }
1076  // draw normal colour mode
1077  else
1078  {
1079  // Cool feature where we keep track of the average colour of a texture and just draw that colour
1080  // in colour mode. Could also be adapted for distant rendering.
1081  // it allows for much smoother transition between texture and colur mode
1082  if(world->isSafe(tileX,tileY)==true && world->isLand(tileX,tileY)==false)
1083  {
1084  glColor3ub(TEX_WORLD_TERRAIN_OCEAN_00.averageRed,TEX_WORLD_TERRAIN_OCEAN_00.averageGreen,
1085  TEX_WORLD_TERRAIN_OCEAN_00.averageBlue);
1086  }
1087  else if(world->isSafe(tileX,tileY)==true && world->isLand(tileX,tileY)==true)
1088  {
1089  //glColor3ub(TEX_WORLD_TERRAIN_GRASS_00.averageRed,TEX_WORLD_TERRAIN_GRASS_00.averageGreen,
1090  //TEX_WORLD_TERRAIN_GRASS_00.averageBlue);
1091  Texture * tex = world->aWorldTile(tileX,tileY).currentTexture();
1092  if ( tex )
1093  {
1094  glColor3ub(tex->averageRed,tex->averageGreen,tex->averageBlue);
1095  }
1096  }
1097  else
1098  {
1099  //glColor3ub(world->aTopoMap(tileX,tileY,0),world->aTopoMap(tileX,tileY,1),
1100  //world->aTopoMap(tileX,tileY,2));
1101  }
1102  }
1103  }
1104 
1105  // final case
1106  else if(world->isSafe(tileX-1,tileY)==true)
1107  {
1108  glVertex2s(currentX,currentY);
1109  glVertex2s(currentX,currentY+tileSize);
1110  }
1111  ++tileX;
1112  tileX+=tilesToSkip;
1113  }
1114  glEnd();
1115 
1116  tileX=revertTileX;
1117  ++tileY;
1118  tileY+=tilesToSkip;
1119  }
1120  }
1121 
1122  // return the maximum number of tiles that fit on the current panel along X axis
1123  inline double getTilesNX()
1124  {
1125  return mainViewNX/tileSize;
1126  }
1127  // return the maximum number of tiles that fit on the current panel along Y axis
1128  inline double getTilesNY()
1129  {
1130  return mainViewNY/tileSize;
1131  }
1132 
1133 };
1134 
1135 #endif
Texture TEX_WORLD_TERRAIN_JUNGLE
Definition: Driver_TextureList.hpp:123
Definition: World_Viewer_Rain_Manager.hpp:28
World_Local * worldLocal
Definition: World_Viewer.hpp:91
unsigned char colourRed
Definition: Tribe.hpp:39
char hasSeen(World_Local *, int, int, bool isSubterranean=false)
Definition: Character.cpp:1106
virtual Vector< Texture * > * currentTextures()
Definition: LocalTile.cpp:247
int DEBUG_Y
Definition: Driver_Settings.cpp:268
Definition: World_Viewer.hpp:47
int firstPixelY
Definition: World_Viewer.hpp:80
int centerLocalX
Definition: World_Viewer.hpp:83
World * world
Definition: World_Viewer.hpp:90
short int lastMouseX
Definition: World_Viewer.hpp:88
unsigned long int firstTileAbsX
Definition: World_Viewer.hpp:79
const int LOCAL_MAP_SIZE
Definition: Driver_Settings.cpp:156
bool alternateTile
Definition: World_Viewer.hpp:96
WorldViewer()
Definition: World_Viewer.hpp:116
void toScreenCoords(const int _tileX, const int _tileY, int *_pixelX, int *_pixelY)
Definition: World_Viewer.hpp:345
unsigned long int hoveredAbsoluteX
Definition: World_Viewer.hpp:101
unsigned long int firstTileAbsY
Definition: World_Viewer.hpp:79
unsigned char bWall
Definition: LocalTile.hpp:55
Definition: World.hpp:50
int tileSize
Definition: World_Viewer.hpp:68
bool FOG_OF_WAR
Definition: Driver_Settings.cpp:116
double centerTileX
Definition: World_Viewer.hpp:74
void toTileCoords(int pixelX, int pixelY, unsigned long int *absX, unsigned long int *absY)
Definition: World_Viewer.hpp:400
Vector< WorldObjectGlobal * > vWorldObjectGlobal
Definition: World.hpp:110
int centerLocalY
Definition: World_Viewer.hpp:83
void setCenterTile(const double _centerTileX, const double _centerTileY, const int _subTileX=LOCAL_MAP_SIZE/2, const int _subTileY=LOCAL_MAP_SIZE/2)
Definition: World_Viewer.hpp:334
bool tilesetMode
Definition: World_Viewer.hpp:107
void render()
Definition: World_Viewer.hpp:523
Texture TEX_WORLD_TERRAIN_MOUNTAIN_00
Definition: Driver_TextureList.hpp:148
Definition: WorldObjectGlobal.hpp:17
void switchTarget(World_Local *_worldLocal)
Definition: World_Viewer.hpp:234
void setTileSize(const int _tileSize)
Definition: World_Viewer.hpp:227
ArrayS2< World_Local > aWorldTile
Definition: World.hpp:113
int hoveredXTile
Definition: World_Viewer.hpp:99
void queryTileLocal(int hoveredXTile, int hoveredYTile)
Definition: World.cpp:2127
int nY
Definition: World.hpp:75
ArrayS3< unsigned char > aTopoMap
Definition: World.hpp:107
int hoveredXTileLocal
Definition: World_Viewer.hpp:100
int DEBUG_X
Definition: Driver_Settings.cpp:267
RainManager rainManager
Definition: World_Viewer.hpp:64
int firstTileX
Definition: World_Viewer.hpp:78
int worldY
Definition: WorldObjectGlobal.hpp:22
Definition: World_Local.hpp:58
unsigned long int hoveredAbsoluteY
Definition: World_Viewer.hpp:101
void renderColourMode(int tileX, int tileY, float pixelTileX, float pixelTileY)
Definition: World_Viewer.hpp:1027
Texture TEX_WORLD_TERRAIN_GRASS_00
Definition: Driver_TextureList.hpp:74
Texture TEX_WORLD_TERRAIN_HILL
Definition: Driver_TextureList.hpp:151
void renderWorldIcons()
Definition: World_Viewer.hpp:426
int tilesToSkip
Definition: World_Viewer.hpp:104
Character * playerCharacter
Definition: Driver_Settings.cpp:107
unsigned char colourGreen
Definition: Tribe.hpp:40
int worldX
Definition: WorldObjectGlobal.hpp:22
#define ABSOLUTE_COORDINATE_NULL
Definition: Driver_Settings.cpp:247
double demoScroll
Definition: World_Viewer.hpp:114
short int lastMouseY
Definition: World_Viewer.hpp:88
int firstTileY
Definition: World_Viewer.hpp:78
bool panning
Definition: World_Viewer.hpp:93
bool landMode
Definition: World_Viewer.hpp:109
Calendar globalCalendar
Definition: Driver_GlobalObjects.hpp:28
bool showHoveredTile
Definition: World_Viewer.hpp:102
void renderLocalMap(World_Local *localMap, int currentX, int currentY)
Definition: World_Viewer.hpp:641
unsigned char colourBlue
Definition: Tribe.hpp:41
enumMenu activeMenu
Definition: Driver_Settings_Enums.hpp:29
void setPanel(const int _x1, const int _y1, const int _x2, const int _y2)
Definition: World_Viewer.hpp:318
float panY
Definition: World_Viewer.hpp:94
short int height
Definition: LocalTile.hpp:62
bool territoryView
Definition: World_Viewer.hpp:106
int nX
Definition: World.hpp:75
int firstPixelX
Definition: World_Viewer.hpp:80
double getTilesNX()
Definition: World_Viewer.hpp:1123
double pixelsPerLocalTile
Definition: World_Viewer.hpp:84
bool isSafe(int _x, int _y)
Definition: World.cpp:504
double getTilesNY()
Definition: World_Viewer.hpp:1128
bool mouseEvent(Mouse *mouse)
Definition: World_Viewer.hpp:261
Definition: Tribe.hpp:23
Definition: LocalTile.hpp:34
Data_Subterranean * dataSubterranean
Definition: World_Local.hpp:155
enumBiome baseBiome
Definition: World_Local.hpp:247
void updateScene()
Definition: World_Viewer.hpp:519
ArrayS2< int > aRiverID
Definition: World.hpp:119
std::atomic< bool > initialized
Definition: World_Local.hpp:176
Data * data
Definition: World_Local.hpp:154
void zoomOut()
Definition: World_Viewer.hpp:218
bool active
Definition: World_Viewer.hpp:66
float panX
Definition: World_Viewer.hpp:94
void render()
Definition: World_Viewer_Rain_Manager.cpp:66
bool isLand(int _x, int _y)
Definition: World.cpp:1296
Texture TEX_WALL_GREYBRICK_SOUTH
Definition: Driver_TextureList.hpp:224
int hoveredYTile
Definition: World_Viewer.hpp:99
Texture TEX_WORLD_TERRAIN_OCEAN_00
Definition: Driver_TextureList.hpp:103
Definition: Driver_Settings_Enums.hpp:25
bool keyboardEvent(Keyboard *_keyboard)
Definition: World_Viewer.hpp:181
int hoveredYTileLocal
Definition: World_Viewer.hpp:100
void normaliseCoordinates()
Definition: World_Viewer.hpp:241
void init(int _x1, int _y1, int _x2, int _y2, World *_world, int _maxRain=10000, double _rainPercentOfX=0.005)
Definition: World_Viewer_Rain_Manager.cpp:26
Texture TEX_WORLD_TERRAIN_RIVER_FULL
Definition: Driver_TextureList.hpp:92
bool subterraneanMode
Definition: World_Viewer.hpp:108
void renderTextureMode(int tileX, int tileY, float pixelTileX, float pixelTileY)
Definition: World_Viewer.hpp:900
virtual Texture * currentTexture()
Definition: World_Local.cpp:3159
Vector< World_Local * > vWorldLocal
Definition: World.hpp:115
double centerTileY
Definition: World_Viewer.hpp:74
Texture TEX_WORLD_TERRAIN_FOREST_TREES
Definition: Driver_TextureList.hpp:120
void queryTile(int hoveredXTile, int hoveredYTile)
Definition: World.cpp:2118
bool demoMode
Definition: World_Viewer.hpp:113
void centerView()
Definition: World_Viewer.hpp:169
void generateLocal(const int, const int)
Definition: World.cpp:1756
void zoomIn()
Definition: World_Viewer.hpp:205