1//////////////////////////////////////////////////////////////////////
2// This file is part of Remere's Map Editor
3//////////////////////////////////////////////////////////////////////
4// Remere's Map Editor is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Remere's Map Editor is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16//////////////////////////////////////////////////////////////////////
17
18#include "main.h"
19#include "light_drawer.h"
20
21LightDrawer::LightDrawer() {
22 texture = 0;
23 global_color = wxColor(50, 50, 50, 255);
24}
25
26LightDrawer::~LightDrawer() {
27 unloadGLTexture();
28
29 lights.clear();
30}
31
32void LightDrawer::draw(int map_x, int map_y, int end_x, int end_y, int scroll_x, int scroll_y, bool fog) {
33 if (texture == 0) {
34 createGLTexture();
35 }
36
37 int w = end_x - map_x;
38 int h = end_y - map_y;
39
40 buffer.resize(static_cast<size_t>(w * h * PixelFormatRGBA));
41
42 for (int x = 0; x < w; ++x) {
43 for (int y = 0; y < h; ++y) {
44 int mx = (map_x + x);
45 int my = (map_y + y);
46 int index = (y * w + x);
47 int color_index = index * PixelFormatRGBA;
48
49 buffer[color_index] = global_color.Red();
50 buffer[color_index + 1] = global_color.Green();
51 buffer[color_index + 2] = global_color.Blue();
52 buffer[color_index + 3] = 140; // global_color.Alpha();
53
54 for (auto& light : lights) {
55 float intensity = calculateIntensity(mx, my, light);
56 if (intensity == 0.f) {
57 continue;
58 }
59 wxColor light_color = colorFromEightBit(light.color);
60 uint8_t red = static_cast<uint8_t>(light_color.Red() * intensity);
61 uint8_t green = static_cast<uint8_t>(light_color.Green() * intensity);
62 uint8_t blue = static_cast<uint8_t>(light_color.Blue() * intensity);
63 buffer[color_index] = std::max(buffer[color_index], red);
64 buffer[color_index + 1] = std::max(buffer[color_index + 1], green);
65 buffer[color_index + 2] = std::max(buffer[color_index + 2], blue);
66 }
67 }
68 }
69
70 const int draw_x = map_x * TileSize - scroll_x;
71 const int draw_y = map_y * TileSize - scroll_y;
72 int draw_width = w * TileSize;
73 int draw_height = h * TileSize;
74
75 glBindTexture(GL_TEXTURE_2D, texture);
76
77 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
78 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
79 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 0x812F);
80 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 0x812F);
81 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
82
83 if (!fog) {
84 glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
85 }
86
87 glColor4ub(255, 255, 255, 255); // reset color
88 glEnable(GL_TEXTURE_2D);
89 glBegin(GL_QUADS);
90 glTexCoord2f(0.f, 0.f);
91 glVertex2f(draw_x, draw_y);
92 glTexCoord2f(1.f, 0.f);
93 glVertex2f(draw_x + draw_width, draw_y);
94 glTexCoord2f(1.f, 1.f);
95 glVertex2f(draw_x + draw_width, draw_y + draw_height);
96 glTexCoord2f(0.f, 1.f);
97 glVertex2f(draw_x, draw_y + draw_height);
98 glEnd();
99 glDisable(GL_TEXTURE_2D);
100
101 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
102
103 if (fog) {
104 glColor4ub(10, 10, 10, 80);
105 glBegin(GL_QUADS);
106 glVertex2f(draw_x, draw_y);
107 glVertex2f(draw_x + draw_width, draw_y);
108 glVertex2f(draw_x + draw_width, draw_y + draw_height);
109 glVertex2f(draw_x, draw_y + draw_height);
110 glEnd();
111 }
112}
113
114void LightDrawer::setGlobalLightColor(uint8_t color) {
115 global_color = colorFromEightBit(color);
116}
117
118void LightDrawer::addLight(int map_x, int map_y, int map_z, const SpriteLight& light) {
119 if (map_z <= GROUND_LAYER) {
120 map_x -= (GROUND_LAYER - map_z);
121 map_y -= (GROUND_LAYER - map_z);
122 }
123
124 if (map_x <= 0 || map_x >= MAP_MAX_WIDTH || map_y <= 0 || map_y >= MAP_MAX_HEIGHT) {
125 return;
126 }
127
128 uint8_t intensity = std::min(light.intensity, static_cast<uint8_t>(MaxLightIntensity));
129
130 if (!lights.empty()) {
131 Light& previous = lights.back();
132 if (previous.map_x == map_x && previous.map_y == map_y && previous.color == light.color) {
133 previous.intensity = std::max(previous.intensity, intensity);
134 return;
135 }
136 }
137
138 lights.push_back(Light { static_cast<uint16_t>(map_x), static_cast<uint16_t>(map_y), light.color, intensity });
139}
140
141void LightDrawer::clear() noexcept {
142 lights.clear();
143}
144
145void LightDrawer::createGLTexture() {
146 glGenTextures(1, &texture);
147 ASSERT(texture == 0);
148}
149
150void LightDrawer::unloadGLTexture() {
151 if (texture != 0) {
152 glDeleteTextures(1, &texture);
153 }
154}
155