Skip to content

Commit 2d8eb88

Browse files
committed
Light sources are now visible in all layers
1 parent 304e61b commit 2d8eb88

File tree

8 files changed

+218
-49
lines changed

8 files changed

+218
-49
lines changed

docs/TODO.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@
4242
- [X] Fix low FPS when panning due to shadows being recalculated
4343
- [X] Make UI more intuitive (and pretty)
4444
- [X] Conditions, light sources, etc, applied to a token should remain highlighted in the right click menu
45-
- [ ] Scenes saved and later loaded should work on any screen resolution
45+
- [X] Scenes saved and later loaded should work on any screen resolution
46+
- [X] Light sources should be visible in all layers
4647
- [ ] Fix token images looking pixelated if zoom in is used
47-
- [ ] Light sources should be visible in all layers
4848
- [ ] Set maximum zoom and pan
4949
- [ ] Keep tokens inside grid when moving - larger tokens being moved to grid borders
5050
- [ ] Keep right click menu inside canvas - right click in tokens near the grid borders

dungeoneering/dungeoneering.pde

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,12 @@ void setup() {
6363

6464
initiative = new Initiative(initiativeCanvas);
6565

66-
playersLayer = new Layer(canvas, grid, obstacles, initiative, "Players Layer", Layers.players);
67-
dmLayer = new Layer(canvas, grid, obstacles, initiative, "DM Layer", Layers.dm);
68-
layerShown = Layers.players;
69-
7066
resources = new Resources(canvas, grid);
7167

68+
playersLayer = new Layer(canvas, grid, obstacles, resources, initiative, "Players Layer", Layers.players);
69+
dmLayer = new Layer(canvas, grid, obstacles, resources, initiative, "DM Layer", Layers.dm);
70+
layerShown = Layers.players;
71+
7272
userInterface = new UserInterface(canvas, cp5, map, grid, obstacles, playersLayer, dmLayer, resources, initiative);
7373

7474
backgroundColor = color(0);
@@ -108,19 +108,38 @@ void draw() {
108108
switch ( layerShown ) {
109109
case players:
110110

111-
if ( obstacles.getRecalculateShadows() )
112-
playersLayer.recalculateShadows();
111+
if ( obstacles.getRecalculateShadows() ) {
112+
// Gather light sources from all layers
113+
dmLayer.recalculateShadows(ShadowTypes.lightSources);
114+
playersLayer.recalculateShadows(ShadowTypes.lightSources);
115+
// Gather lines of sight of the layer being shown, to be used as a mask to hide/reveal light sources
116+
playersLayer.recalculateShadows(ShadowTypes.linesOfSight);
117+
// Gather sight types of the layer being shown
118+
playersLayer.recalculateShadows(ShadowTypes.sightTypes);
119+
// Compose final shadows with all of the above
120+
obstacles.blendShadows();
121+
}
113122

123+
// Draw layer not being shown first
114124
dmLayer.draw(layerShown);
125+
// Draw shadows to hide/reveal areas and tokens depending on the obstacles present
115126
obstacles.draw();
127+
// Draw layer being shown
116128
playersLayer.draw(layerShown);
117129

118130
break;
119131
case dm:
120132

121-
if ( obstacles.getRecalculateShadows() )
122-
dmLayer.recalculateShadows();
133+
if ( obstacles.getRecalculateShadows() ) {
134+
// Same as above, with opposite layer
135+
playersLayer.recalculateShadows(ShadowTypes.lightSources);
136+
dmLayer.recalculateShadows(ShadowTypes.lightSources);
137+
dmLayer.recalculateShadows(ShadowTypes.linesOfSight);
138+
dmLayer.recalculateShadows(ShadowTypes.sightTypes);
139+
obstacles.blendShadows();
140+
}
123141

142+
// Same as above, with opposite layer
124143
playersLayer.draw(layerShown);
125144
obstacles.draw();
126145
dmLayer.draw(layerShown);
@@ -130,11 +149,22 @@ void draw() {
130149
default:
131150

132151
if ( obstacles.getRecalculateShadows() ) {
133-
playersLayer.recalculateShadows();
134-
dmLayer.recalculateShadows();
152+
// Gather light sources from all layers
153+
playersLayer.recalculateShadows(ShadowTypes.lightSources);
154+
dmLayer.recalculateShadows(ShadowTypes.lightSources);
155+
// Gather lines of sight from all layers, to be used as a mask to reveal/hide light sources
156+
playersLayer.recalculateShadows(ShadowTypes.linesOfSight);
157+
dmLayer.recalculateShadows(ShadowTypes.linesOfSight);
158+
// Gather sight types from all layers
159+
playersLayer.recalculateShadows(ShadowTypes.sightTypes);
160+
dmLayer.recalculateShadows(ShadowTypes.sightTypes);
161+
// Compose final shadows with all of the above
162+
obstacles.blendShadows();
135163
}
136164

165+
// Draw shadows first, to hide/reveal areas depending on the obstacles present
137166
obstacles.draw();
167+
// Then draw all layers
138168
playersLayer.draw(layerShown);
139169
dmLayer.draw(layerShown);
140170

dungeoneering/enums.pde

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ enum Layers {
2020

2121
};
2222

23+
enum ShadowTypes {
24+
25+
lightSources,
26+
linesOfSight,
27+
sightTypes;
28+
29+
};
30+
2331
enum Illumination {
2432

2533
brightLight(255),

dungeoneering/layer.pde

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ class Layer {
88

99
Obstacles obstacles;
1010

11+
Resources resources;
12+
1113
Initiative initiative;
1214

1315
ArrayList<Token> tokens;
@@ -16,14 +18,16 @@ class Layer {
1618

1719
Layers thisLayer;
1820

19-
Layer(PGraphics _canvas, Grid _grid, Obstacles _obstacles, Initiative _initiative, String _name, Layers _thisLayer) {
21+
Layer(PGraphics _canvas, Grid _grid, Obstacles _obstacles, Resources _resources, Initiative _initiative, String _name, Layers _thisLayer) {
2022

2123
canvas = _canvas;
2224

2325
grid = _grid;
2426

2527
obstacles = _obstacles;
2628

29+
resources = _resources;
30+
2731
initiative = _initiative;
2832

2933
tokens = new ArrayList<Token>();
@@ -64,13 +68,12 @@ class Layer {
6468

6569
}
6670

67-
void recalculateShadows() {
71+
void recalculateShadows(ShadowTypes shadowsToRecalculate) {
6872

6973
logger.debug(name + ": recalculating shadows");
7074

7175
for ( Token token: tokens )
72-
token.recalculateShadows();
73-
obstacles.blurShadows();
76+
token.recalculateShadows(shadowsToRecalculate);
7477

7578
}
7679

@@ -85,7 +88,9 @@ class Layer {
8588
currentCell = grid.getCellAt(0, 0);
8689

8790
Token token = new Token(canvas, grid, obstacles);
88-
token.setup(tokenBaseName, tokenImageFile.getAbsolutePath(), grid.getCellWidth(), grid.getCellHeight(), resources.getSize("Medium"));
91+
Light lineOfSightTemplate = resources.getSightType("Line of Sight");
92+
Light lineOfSight = new Light(lineOfSightTemplate.getName(), lineOfSightTemplate.getBrightLightRadius(), lineOfSightTemplate.getDimLightRadius());
93+
token.setup(tokenBaseName, tokenImageFile.getAbsolutePath(), grid.getCellWidth(), grid.getCellHeight(), resources.getSize("Medium"), lineOfSight);
8994
token.setCell(currentCell);
9095
token.setBeingMoved(true);
9196
tokens.add(token);

dungeoneering/obstacles.pde

Lines changed: 124 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,16 @@ class Obstacles {
1313

1414
Illumination illumination;
1515

16+
// Accumulates all lights and shadows, serves as a mask to be applied over the entire scene
1617
PGraphics allShadows;
17-
PGraphics currentShadows;
18+
// Temporary canvas, used to draw shadows before they are blended into other canvases
19+
PGraphics temporaryShadows;
20+
// Accumulates light sources
21+
PGraphics lightSources;
22+
// Accumulates lines of sight, used as a mask to be applied over the light sources canvas
23+
PGraphics linesOfSight;
24+
// Accumulates sight types
25+
PGraphics sightTypes;
1826

1927
float currentPanX, currentPanY;
2028
float currentScale;
@@ -40,16 +48,34 @@ class Obstacles {
4048
illumination = Illumination.brightLight;
4149

4250
allShadows = createGraphics(canvas.width, canvas.height, P2D);
43-
allShadows.smooth();
51+
allShadows.noSmooth();
4452
allShadows.beginDraw();
4553
allShadows.background(illumination.getColor());
4654
allShadows.endDraw();
4755

48-
currentShadows = createGraphics(canvas.width, canvas.height, P2D);
49-
currentShadows.smooth();
50-
currentShadows.beginDraw();
51-
currentShadows.background(illumination.getColor());
52-
currentShadows.endDraw();
56+
temporaryShadows = createGraphics(canvas.width, canvas.height, P2D);
57+
temporaryShadows.noSmooth();
58+
temporaryShadows.beginDraw();
59+
temporaryShadows.background(illumination.getColor());
60+
temporaryShadows.endDraw();
61+
62+
lightSources = createGraphics(canvas.width, canvas.height, P2D);
63+
lightSources.noSmooth();
64+
lightSources.beginDraw();
65+
lightSources.background(0);
66+
lightSources.endDraw();
67+
68+
linesOfSight = createGraphics(canvas.width, canvas.height, P2D);
69+
linesOfSight.noSmooth();
70+
linesOfSight.beginDraw();
71+
linesOfSight.background(0);
72+
linesOfSight.endDraw();
73+
74+
sightTypes = createGraphics(canvas.width, canvas.height, P2D);
75+
sightTypes.noSmooth();
76+
sightTypes.beginDraw();
77+
sightTypes.background(0);
78+
sightTypes.endDraw();
5379

5480
currentPanX = 0;
5581
currentPanY = 0;
@@ -64,7 +90,9 @@ class Obstacles {
6490
if (canvas != null && allShadows != null)
6591
try {
6692
canvas.mask(allShadows);
67-
} catch(Exception e) {}
93+
} catch(Exception e) {
94+
logger.error("Obstacles: Error applying shadows mask");
95+
}
6896

6997
if ( drawObstacles ) {
7098

@@ -106,12 +134,73 @@ class Obstacles {
106134

107135
}
108136

137+
void blendLightSources() {
138+
139+
lightSources.beginDraw();
140+
lightSources.blendMode(LIGHTEST);
141+
lightSources.image(temporaryShadows, 0, 0);
142+
lightSources.blendMode(BLEND);
143+
lightSources.endDraw();
144+
145+
}
146+
147+
void blendSightTypes() {
148+
149+
sightTypes.beginDraw();
150+
sightTypes.blendMode(LIGHTEST);
151+
sightTypes.image(temporaryShadows, 0, 0);
152+
sightTypes.blendMode(BLEND);
153+
sightTypes.endDraw();
154+
155+
}
156+
157+
void blendLinesOfSight() {
158+
159+
linesOfSight.beginDraw();
160+
linesOfSight.blendMode(LIGHTEST);
161+
linesOfSight.image(temporaryShadows, 0, 0);
162+
linesOfSight.blendMode(BLEND);
163+
linesOfSight.endDraw();
164+
165+
}
166+
109167
void blendShadows() {
110168

111-
allShadows.beginDraw();
112-
allShadows.blendMode(LIGHTEST);
113-
allShadows.image(currentShadows, 0, 0);
114-
allShadows.endDraw();
169+
if ( illumination == Illumination.brightLight )
170+
return;
171+
172+
lightSources.beginDraw();
173+
lightSources.mask(linesOfSight);
174+
lightSources.endDraw();
175+
176+
switch ( illumination ) {
177+
case darkness:
178+
179+
allShadows.beginDraw();
180+
allShadows.image(lightSources, 0, 0);
181+
allShadows.blendMode(LIGHTEST);
182+
allShadows.image(sightTypes, 0, 0);
183+
allShadows.blendMode(BLEND);
184+
allShadows.endDraw();
185+
186+
break;
187+
case dimLight:
188+
189+
allShadows.beginDraw();
190+
allShadows.image(lightSources, 0, 0);
191+
allShadows.blendMode(LIGHTEST);
192+
allShadows.noStroke();
193+
allShadows.fill(illumination.getColor());
194+
allShadows.rect(0, 0, allShadows.width, allShadows.height);
195+
allShadows.blendMode(BLEND);
196+
allShadows.endDraw();
197+
198+
break;
199+
default:
200+
break;
201+
}
202+
203+
blurShadows();
115204

116205
}
117206

@@ -129,6 +218,26 @@ class Obstacles {
129218
allShadows.background(illumination.getColor());
130219
allShadows.endDraw();
131220

221+
temporaryShadows.beginDraw();
222+
temporaryShadows.background(0);
223+
temporaryShadows.endDraw();
224+
225+
lightSources.beginDraw();
226+
lightSources.background(0);
227+
lightSources.endDraw();
228+
229+
linesOfSight.beginDraw();
230+
linesOfSight.background(0);
231+
linesOfSight.endDraw();
232+
233+
sightTypes.beginDraw();
234+
sightTypes.background(0);
235+
sightTypes.endDraw();
236+
237+
// No need to recalculate shadows if environment lighting is bright light
238+
if ( illumination == Illumination.brightLight )
239+
recalculateShadows = false;
240+
132241
}
133242

134243
void clear() {
@@ -169,12 +278,8 @@ class Obstacles {
169278
return doorWidth;
170279
}
171280

172-
PGraphics getCurrentShadowsCanvas() {
173-
return currentShadows;
174-
}
175-
176-
PGraphics getAllShadowsCanvas() {
177-
return allShadows;
281+
PGraphics getTemporaryShadowsCanvas() {
282+
return temporaryShadows;
178283
}
179284

180285
void setCurrentPanX(float _currentPanX) {
@@ -209,7 +314,7 @@ class Obstacles {
209314

210315
recalculateShadows = _recalculateShadows;
211316

212-
if ( _recalculateShadows )
317+
if ( recalculateShadows )
213318
logger.debug("Obstacles: recalculating shadows");
214319

215320
}

dungeoneering/resources.pde

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class Resources {
6969
commonLightSources.put("Hooded Lantern", createLight("Hooded Lantern", 30, 60));
7070
commonLightSources.put("Lamp", createLight("Lamp", 15, 45));
7171
commonLightSources.put("Torch", createLight("Torch", 20, 40));
72-
commonLightSources.put("Daylight", createLight("Daylight", 150, 0));
72+
commonLightSources.put("Daylight", createLight("Daylight", 1000, 0));
7373

7474
}
7575

@@ -85,6 +85,7 @@ class Resources {
8585

8686
void setSightTypes() {
8787

88+
sightTypes.put("Line of Sight", createLight("Line of Sight", 1000, 0));
8889
sightTypes.put("Blindsight 30'", createLight("Blindsight 30'", 30, 0));
8990
sightTypes.put("Blindsight 60'", createLight("Blindsight 60'", 60, 0));
9091
sightTypes.put("Blindsight 120'", createLight("Blindsight 120'", 120, 0));

0 commit comments

Comments
 (0)