freg  0.3
Free-Roaming Elementary Game
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Lighting-inertia.cpp
Go to the documentation of this file.
1  /* freg, Free-Roaming Elementary Game with open and interactive world
2  * Copyright (C) 2012-2014 Alexander 'mmaulwurff' Kromm
3  * mmaulwurff@gmail.com
4  *
5  * This file is part of FREG.
6  *
7  * FREG is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * FREG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with FREG. If not, see <http://www.gnu.org/licenses/>. */
19 
20 /**\file Lighting-inertia.cpp
21  * \brief This file provides simple (also mad) lighting for freg.
22  *
23  * It has light inertia, meaning that block, enlightened by outer
24  * source, will remain enlightened when light source is removed.
25  * Light is divided to sunlight and other light. Sunlight is
26  * changing over the day.
27  *
28  * This lighting can be used to develop more intelligent one.
29  * Intended to be fast (and is!).
30  *
31  * LightMap is uchar:
32  * & 0xF0 bits are for non-sun light,
33  * & 0x0F bits for sun. */
34 
35 #include "World.h"
36 #include "Shred.h"
37 #include "blocks/Block.h"
38 #include "blocks/Active.h"
39 
40 const int FIRE_LIGHT_FACTOR = 4;
41 
42 /// Use Enlightened instead, which is smart wrapper of this.
43 int World::LightMap(const int x, const int y, const int z) const {
44  return GetShred(x, y)->
45  Lightmap(Shred::CoordInShred(x), Shred::CoordInShred(y), z);
46 }
47 
48 bool World::SetFireLightMap(const int level,
49  const int x, const int y, const int z)
50 {
51  return GetShred(x, y)->SetFireLight(
52  Shred::CoordInShred(x), Shred::CoordInShred(y), z, level);
53 }
54 
55 void World::AddFireLight(int, int, int, int) {}
56 void World::RemoveFireLight(int, int, int) {}
57 
58 /// Makes block emit shining.
59 /** Receives only non-sun light as level, from 1 to F. */
60 void World::Shine(const int x, const int y, const int z, int level) {
61  if ( SetFireLightMap(level << 4, x, y, z) ) {
62  const int transparent = GetBlock(x, y, z)->Transparent();
63  if ( INVISIBLE != transparent && not initial_lighting ) {
64  emit Updated(x, y, z);
65  }
66  if ( transparent != BLOCK_OPAQUE && level > 1 ) {
67  --level;
68  const int border = GetBound();
69  if ( x > 0 ) Shine(x-1, y, z, level);
70  if ( x < border ) Shine(x+1, y, z, level);
71  if ( y > 0 ) Shine(x, y-1, z, level);
72  if ( y < border ) Shine(x, y+1, z, level);
73  Shine(x, y, z-1, level);
74  Shine(x, y, z+1, level);
75  }
76  }
77 }
78 
79 void World::SunShineVertical(const int x, const int y, int z, int light_lev) {
80  /* 2 1 3
81  * * First, light goes down, then divides to 4 branches
82  * ^ | ^ to N-S-E-W, and goes up.
83  * | | |
84  * | | |
85  * |<v>|
86  * # */
87  Shred * const shred = GetShred(x, y);
88  const int x_in = Shred::CoordInShred(x);
89  const int y_in = Shred::CoordInShred(y);
90  shred->SetLightmap(x_in, y_in, HEIGHT-1, 0xFF);
91  for ( ; ; --z) {
92  shred->SetSunLight(x_in, y_in, z, light_lev);
93  switch ( shred->GetBlock(x_in, y_in, z)->Transparent() ) {
94  case BLOCK_OPAQUE: CrossUpShine(x, y, z); return;
95  case BLOCK_TRANSPARENT:
96  --light_lev;
97  if ( not initial_lighting ) {
98  emit Updated(x, y, z);
99  }
100  break;
101  case INVISIBLE: break;
102  }
103  }
104 }
105 
106 void World::CrossUpShine(const int x, const int y, const int z_bottom) {
107  const int bound = GetBound();
108  if ( initial_lighting ) {
109  if ( x > 0 ) UpShineInit(x-1, y, z_bottom);
110  if ( x < bound ) UpShineInit(x+1, y, z_bottom);
111  if ( y > 0 ) UpShineInit(x, y-1, z_bottom);
112  if ( y < bound ) UpShineInit(x, y+1, z_bottom);
113  } else {
114  if ( x > 0 ) UpShine(x-1, y, z_bottom);
115  if ( x < bound ) UpShine(x+1, y, z_bottom);
116  if ( y > 0 ) UpShine(x, y-1, z_bottom);
117  if ( y < bound ) UpShine(x, y+1, z_bottom);
118  emit Updated(x, y, z_bottom);
119  }
120 }
121 
122 void World::UpShineInit(int x, int y, int z_bottom) {
123  Shred * const shred = GetShred(x, y);
124  x = Shred::CoordInShred(x);
125  y = Shred::CoordInShred(y);
126  for ( ; shred->SetSunLight(x, y, z_bottom, 1) && z_bottom < HEIGHT-1;
127  ++z_bottom);
128 }
129 
130 void World::UpShine(const int x, const int y, int z_bottom) {
131  Shred * const shred = GetShred(x, y);
132  const int x_in = Shred::CoordInShred(x);
133  const int y_in = Shred::CoordInShred(y);
134  while (shred->SetSunLight(x_in, y_in, z_bottom, 1) && z_bottom<HEIGHT-1) {
135  emit Updated(x, y, z_bottom++);
136  }
137 }
138 
139 /// Called when one block is moved, built or destroyed.
140 void World::ReEnlighten(const int x, const int y, const int z) {
141  if ( not GetEvernight() ) {
142  SunShineVertical(x, y);
143  }
144  const int radius = GetBlock(x, y, z)->LightRadius();
145  if ( radius != 0 ) {
146  Shine(x, y, z, radius);
147  }
148 }
149 
151  for (int i=0; i<NumShreds()*NumShreds(); ++i) {
153  }
156  ReEnlightenAll();
157 }
158 
160  initial_lighting = true;
161  for (int i=0; i<NumShreds()*NumShreds(); ++i) {
162  shreds[i]->ShineAll();
163  }
164  initial_lighting = false;
165 }
166 
167 void World::ReEnlightenMove(const dirs dir) {
168  initial_lighting = true;
169  switch ( dir ) {
170  case NORTH:
171  for (int i=0; i<NumShreds(); ++i) {
172  shreds[i ]->ShineAll();
173  shreds[i+NumShreds()]->ShineAll();
174  }
175  break;
176  case SOUTH:
177  for (int i=0; i<NumShreds(); ++i) {
178  shreds[i+NumShreds()*(NumShreds()-1)]->ShineAll();
179  shreds[i+NumShreds()*(NumShreds()-2)]->ShineAll();
180  }
181  break;
182  case EAST:
183  for (int i=0; i<NumShreds(); ++i) {
184  shreds[NumShreds()*i+NumShreds()-1]->ShineAll();
185  shreds[NumShreds()*i+NumShreds()-2]->ShineAll();
186  }
187  break;
188  case WEST:
189  for (int i=0; i<NumShreds(); ++i) {
190  shreds[NumShreds()*i ]->ShineAll();
191  shreds[NumShreds()*i+1]->ShineAll();
192  }
193  break;
194  default: Q_UNREACHABLE(); break;
195  }
196  initial_lighting = false;
197 }
198 
199 int World::Enlightened(const int x, const int y, const int z) const {
200  const int light = LightMap(x, y, z);
201  return (light & 0x0F) * sunMoonFactor +
202  ( (light & 0xF0) >> 4 ) * FIRE_LIGHT_FACTOR;
203 }
204 
205 /// Provides lighting of block side, not all block.
206 int World::Enlightened(const int i, const int j, const int k, const dirs dir)
207 const {
208  int x, y, z;
209  Focus(i, j, k, &x, &y, &z, dir);
210  return qMin(Enlightened(i, j, k), Enlightened(x, y, z));
211 }
212 
213 int World::SunLight(const int i, const int j, const int k) const {
214  return (LightMap(i, j, k) & 0x0F) * sunMoonFactor;
215 }
216 
217 int World::FireLight(const int x, const int y, const int z) const {
218  return (LightMap(x, y, z) & 0xF0) * FIRE_LIGHT_FACTOR;
219 }
220 
221 // Shred methods
222 
223 int Shred::Lightmap(const int x, const int y, const int z) const {
224  return lightMap[x][y][z];
225 }
226 
227 int Shred::FireLight(const int x, const int y, const int z) const {
228  return ((lightMap[x][y][z] & 0xF0) >> 4) * FIRE_LIGHT_FACTOR;
229 }
230 
231 int Shred::SunLight(const int x, const int y, const int z) const {
232  return (lightMap[x][y][z] & 0x0F);
233 }
234 
235 bool Shred::SetSunLight(const int x, const int y, const int z, const int level)
236 {
237  if ( ( lightMap[x][y][z] & 0x0F ) < level ) {
238  ( lightMap[x][y][z] &= 0xF0 ) |= level;
239  return true;
240  } else {
241  return false;
242  }
243 }
244 
245 bool Shred::SetFireLight(const int x, const int y, const int z,
246  const int level)
247 {
248  if ( ( lightMap[x][y][z] & 0xF0 ) < level ) {
249  ( lightMap[x][y][z] &= 0x0F ) |= level;
250  return true;
251  } else {
252  return false;
253  }
254 }
255 
256 void Shred::SetLightmap(const int x, const int y, const int z, const int level)
257 {
258  lightMap[x][y][z] = level;
259 }
260 
261 void Shred::SetAllLightMapNull() { memset(lightMap, 0, sizeof(lightMap)); }
262 
263 /// Makes all shining blocks of shred shine.
265  for (auto i=ShiningBegin(); i!=ShiningEnd(); ++i) {
266  GetWorld()->Shine((*i)->X(), (*i)->Y(), (*i)->Z(),
267  (*i)->LightRadius());
268  }
269  if ( not GetWorld()->GetEvernight() ) {
270  for (int i=shredX*SHRED_WIDTH; i<SHRED_WIDTH*(shredX+1); ++i)
271  for (int j=shredY*SHRED_WIDTH; j<SHRED_WIDTH*(shredY+1); ++j) {
272  GetWorld()->SunShineVertical(i, j);
273  }
274  }
275 }
void ReEnlightenTime()
QLinkedList< Active *const >::const_iterator ShiningEnd() const
Definition: Shred.cpp:297
static int CoordInShred(const int x)
Get local coordinate.
Definition: Shred.h:100
3
Definition: header.h:90
QLinkedList< Active *const >::const_iterator ShiningBegin() const
Definition: Shred.cpp:293
bool SetFireLight(int x, int y, int z, int level)
const int FIRE_LIGHT_FACTOR
Shred ** shreds
Definition: World.h:231
void Updated(int, int, int)
uchar lightMap[SHRED_WIDTH][SHRED_WIDTH][HEIGHT]
Definition: Shred.h:169
int Transparent() const
Definition: Block.h:143
2
Definition: header.h:89
void UpShineInit(int x, int y, int z_bottom)
4
Definition: header.h:91
Definition: Shred.h:32
const int MOON_LIGHT_FACTOR
Definition: World.h:37
bool SetSunLight(int x, int y, int z, int level)
void AddFireLight(int x, int y, int z, int level)
const int HEIGHT
Definition: header.h:40
void ReEnlightenAll()
int LightMap(int x, int y, int z) const
Use Enlightened instead, which is smart wrapper of this.
virtual int LightRadius() const
Definition: Block.cpp:210
bool initial_lighting
Definition: World.h:250
void Shine(int x, int y, int z, int level)
If init is false, light will not spread from non-invisible blocks.
const int SUN_LIGHT_FACTOR
Definition: World.h:38
void ReEnlightenMove(dirs)
Called from ReloadShreds(int), enlightens only needed shreds.
Block * GetBlock(int x, int y, int z) const
Definition: World.cpp:204
int SunLight(int x, int y, int z) const
void SetAllLightMapNull()
bool GetEvernight() const
Definition: World.cpp:64
void ShineAll()
Makes all shining blocks of shred shine.
int SunLight(int x, int y, int z) const
void ReEnlighten(int x, int y, int z)
Called when block is moved.
void SetLightmap(int x, int y, int z, int level)
int GetBound() const
Definition: World.cpp:126
times_of_day PartOfDay() const
Definition: World.cpp:78
World * GetWorld() const
Definition: Shred.cpp:63
int FireLight(int x, int y, int z) const
int shredY
Definition: Shred.h:171
dirs
Definition: header.h:85
Shred * GetShred(int i, int j) const
Definition: World.cpp:40
int sunMoonFactor
Definition: World.h:247
Block * GetBlock(const int x, const int y, const int z) const
Definition: Shred.h:61
bool SetFireLightMap(int level, int x, int y, int z)
void RemoveFireLight(int x, int y, int z)
int NumShreds() const
Definition: World.cpp:58
int shredX
Definition: Shred.h:171
bool Focus(int x, int y, int z, int *x_targ, int *y_targ, int *z_targ, dirs dir) const
False on error, true if focus is received to _targ successfully.
Definition: World.cpp:491
int Lightmap(int x, int y, int z) const
const int SHRED_WIDTH
Definition: header.h:38
void CrossUpShine(int x, int y, int z_bottom)
void SunShineVertical(int x, int y, int z=HEIGHT-2, int level=MAX_LIGHT_RADIUS)
5
Definition: header.h:92
void UpShine(int x, int y, int z_bottom)
int FireLight(int x, int y, int z) const
Provides definition for class Block.
int Enlightened(int x, int y, int z) const