Skip to content

Commit

Permalink
improve: lighting system replaced by that of the OTClientV8
Browse files Browse the repository at this point in the history
  • Loading branch information
mehah authored Mar 2, 2023
1 parent 1d2faa6 commit 819ee76
Show file tree
Hide file tree
Showing 12 changed files with 152 additions and 59 deletions.
112 changes: 88 additions & 24 deletions src/client/lightview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,40 @@
#include "mapview.h"
#include "spritemanager.h"

LightView::LightView() : m_pool(g_drawPool.get<DrawPoolFramed>(DrawPoolType::LIGHT)) {}
LightView::LightView() : m_pool(g_drawPool.get<DrawPool>(DrawPoolType::LIGHT)) {}

void LightView::setSmooth(bool enabled) const { m_pool->setSmooth(enabled); }

void LightView::resize(const Size& size, const uint8_t tileSize) { m_pool->resize(size * (m_tileSize = tileSize)); }
void LightView::resize(const Size& size, const uint8_t tileSize) {
m_lightTexture = nullptr;
m_mapSize = size;
m_tiles.resize(size.area());
if (m_pixels.size() < 4u * m_mapSize.area())
m_pixels.resize(m_mapSize.area() * 4);
}

void LightView::addLightSource(const Point& pos, const Light& light)
{
if (!isDark()) return;

if (!m_sources.empty()) {
auto& prevLight = m_sources.back();
if (!m_lights.empty()) {
auto& prevLight = m_lights.back();
if (prevLight.pos == pos && prevLight.color == light.color) {
prevLight.intensity = std::max<uint16_t>(prevLight.intensity, light.intensity);
prevLight.intensity = std::max<uint8_t>(prevLight.intensity, light.intensity);
return;
}
}
m_lights.emplace_back(pos, light.intensity, light.color, g_drawPool.getOpacity());

stdext::hash_union(m_updatingHash, pos.hash());
stdext::hash_combine(m_updatingHash, light.intensity);
stdext::hash_combine(m_updatingHash, light.color);
stdext::hash_combine(m_updatingHash, g_drawPool.getOpacity());
}

m_sources.emplace_back(pos, light.color, light.intensity, g_drawPool.getOpacity());
void LightView::resetShade(const Point& pos)
{
size_t index = (pos.y / g_drawPool.getScaledSpriteSize()) * m_mapSize.width() + (pos.x / g_drawPool.getScaledSpriteSize());
if (index >= m_tiles.size()) return;
m_tiles[index] = m_lights.size();
}

void LightView::draw(const Rect& dest, const Rect& src)
Expand All @@ -53,27 +68,76 @@ void LightView::draw(const Rect& dest, const Rect& src)
m_pool->setEnable(isDark());
if (!isDark() || !m_pool->isValid()) return;

g_drawPool.use(m_pool->getType(), dest, src, m_globalLightColor);
updateCoords(dest, src);
g_drawPool.use(m_pool->getType());

g_drawPool.addAction([&, updatePixel = updatePixels()] {
if (!m_lightTexture) {
m_lightTexture = std::make_shared<Texture>(m_mapSize);
m_lightTexture->setSmooth(true);
}

if (updatePixel)
m_lightTexture->updatePixels(m_pixels.data());

const float size = m_tileSize * 3.3;
g_painter->resetColor();
g_painter->setCompositionMode(CompositionMode::MULTIPLY);
g_painter->setTexture(m_lightTexture.get());
g_painter->drawCoords(m_coords);
});

bool _clr = true;
for (const auto& light : m_sources) {
if (light.color) {
const auto& color = Color::from8bit(light.color, std::min<float>(light.opacity, light.intensity / 6.f));
const uint16_t radius = light.intensity * m_tileSize;
m_lights.clear();
m_tiles.assign(m_mapSize.area(), {});
}

void LightView::updateCoords(const Rect& dest, const Rect& src) {
if (m_dest != dest || m_src != src) {
m_dest = dest;
m_src = src;

Point offset = src.topLeft();
Size size = src.size();

m_coords.clear();
m_coords.addRect(RectF(dest.left(), dest.top(), dest.width(), dest.height()),
RectF((float)offset.x / g_drawPool.getScaledSpriteSize(), (float)offset.y / g_drawPool.getScaledSpriteSize(),
(float)size.width() / g_drawPool.getScaledSpriteSize(), (float)size.height() / g_drawPool.getScaledSpriteSize()));
}
}

g_drawPool.setBlendEquation(BlendEquation::MAX, true);
g_drawPool.addTexturedRect(Rect(light.pos - radius, Size(radius * 2)), g_sprites.getLightTexture(), color);
_clr = true;
} else {
// Empty the lightings references
if (_clr) { g_drawPool.flush(); _clr = false; }
bool LightView::updatePixels() {
bool updatePixel = m_updatingHash != m_hash;
if (updatePixel) {
for (int x = 0; x < m_mapSize.width(); ++x) {
for (int y = 0; y < m_mapSize.height(); ++y) {
const Point pos(x * g_drawPool.getScaledSpriteSize() + g_drawPool.getScaledSpriteSize() / 2, y * g_drawPool.getScaledSpriteSize() + g_drawPool.getScaledSpriteSize() / 2);

g_drawPool.setOpacity(light.opacity, true);
g_drawPool.addTexturedRect(Rect(light.pos - m_tileSize * 1.8, size, size), g_sprites.getShadeTexture(), m_globalLightColor);
int index = (y * m_mapSize.width() + x);

int colorIndex = index * 4;
m_pixels[colorIndex] = m_globalLightColor.r();
m_pixels[colorIndex + 1] = m_globalLightColor.g();
m_pixels[colorIndex + 2] = m_globalLightColor.b();
m_pixels[colorIndex + 3] = 255; // alpha channel
for (size_t i = m_tiles[index]; i < m_lights.size(); ++i) {
const auto& light = m_lights[i];
float distance = std::sqrt((pos.x - light.pos.x) * (pos.x - light.pos.x) +
(pos.y - light.pos.y) * (pos.y - light.pos.y));
distance /= g_drawPool.getScaledSpriteSize();
float intensity = (-distance + (light.intensity * light.brightness)) * 0.2f;
if (intensity < 0.01f) continue;
if (intensity > 1.0f) intensity = 1.0f;
Color lightColor = Color::from8bit(light.color) * intensity;
m_pixels[colorIndex] = std::max<int>(m_pixels[colorIndex], lightColor.r());
m_pixels[colorIndex + 1] = std::max<int>(m_pixels[colorIndex + 1], lightColor.g());
m_pixels[colorIndex + 2] = std::max<int>(m_pixels[colorIndex + 2], lightColor.b());
}
}
}

m_hash = m_updatingHash;
m_updatingHash = 0;
}

m_sources.clear();
return updatePixel;
}
31 changes: 18 additions & 13 deletions src/client/lightview.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class LightView : public LuaObject
void draw(const Rect& dest, const Rect& src);

void addLightSource(const Point& pos, const Light& light);
void addShade(const Point& pos, const float opacity) { m_sources.emplace_back(pos, opacity); }
void resetShade(const Point& pos);

void setGlobalLight(const Light& light)
{
Expand All @@ -45,29 +45,34 @@ class LightView : public LuaObject
m_pool->repaint();
}

void setSmooth(bool enabled) const;

const Light& getGlobalLight() const { return m_globalLight; }
bool isDark() const { return m_globalLight.intensity < 250; }

private:
struct Source
struct TileLight : public Light
{
Source(const Point& p, float o) : pos(p), opacity(o) {};
Source(const Point& p, uint8_t c, uint16_t i, float o) : pos(p), color(c), intensity(i), opacity(o) {};

Point pos;
uint8_t color{ 0 };
uint16_t intensity{ 0 };
float opacity{ 1.f };
float brightness{ 1.f };

TileLight(const Point& pos, uint8_t intensity, uint8_t color, float brightness) : Light(intensity, color), pos(pos), brightness(brightness) {}
};

uint8_t m_tileSize{ SPRITE_SIZE };
void updateCoords(const Rect& dest, const Rect& src);
bool updatePixels();

size_t m_hash{ 0 }, m_updatingHash{ 0 };

Light m_globalLight;
Color m_globalLightColor{ Color::white };

DrawPoolFramed* m_pool{ nullptr };
DrawPool* m_pool{ nullptr };

std::vector<TileLight> m_lights;
std::vector<uint8_t> m_tiles;
std::vector<uint8_t> m_pixels;

std::vector<Source> m_sources;
Size m_mapSize;
Rect m_dest, m_src;
CoordsBuffer m_coords;
TexturePtr m_lightTexture;
};
15 changes: 8 additions & 7 deletions src/client/mapview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,12 @@ void MapView::drawFloor()

const auto& map = m_cachedVisibleTiles[z];

if (isDrawingLights() && z < m_floorMax) {
if (m_lightView && (m_fadeType != FadeType::OUT$ || fadeLevel == 1.f)) {
for (const auto& tile : map.shades) {
if (alwaysTransparent && tile->getPosition().isInRange(_camera, TRANSPARENT_FLOOR_VIEW_RANGE, TRANSPARENT_FLOOR_VIEW_RANGE, true))
continue;

lightView->addShade(transformPositionTo2D(tile->getPosition(), cameraPosition), fadeLevel);
m_lightView->resetShade(transformPositionTo2D(tile->getPosition(), cameraPosition));
}
}

Expand Down Expand Up @@ -283,15 +283,18 @@ void MapView::updateVisibleTiles()

// Fading System by Kondra https://github.com/OTCv8/otclientv8
if (!m_lastCameraPosition.isValid() || m_lastCameraPosition.z != m_posInfo.camera.z || m_lastCameraPosition.distance(m_posInfo.camera) >= 3) {
m_fadeType = FadeType::NONE$;
for (int iz = m_cachedLastVisibleFloor; iz >= cachedFirstVisibleFloor; --iz) {
m_fadingFloorTimers[iz].restart(m_floorFading * 1000);
}
} else if (prevFirstVisibleFloor < m_cachedFirstVisibleFloor) { // hiding new floor
m_fadeType = FadeType::OUT$;
for (int iz = prevFirstVisibleFloor; iz < m_cachedFirstVisibleFloor; ++iz) {
const int shift = std::max<int>(0, m_floorFading - m_fadingFloorTimers[iz].elapsed_millis());
m_fadingFloorTimers[iz].restart(shift * 1000);
}
} else if (prevFirstVisibleFloor > m_cachedFirstVisibleFloor) { // showing floor
m_fadeType = FadeType::IN$;
m_lastFadeLevel = 0.f;
for (int iz = m_cachedFirstVisibleFloor; iz < prevFirstVisibleFloor; ++iz) {
const int shift = std::max<int>(0, m_floorFading - m_fadingFloorTimers[iz].elapsed_millis());
Expand Down Expand Up @@ -319,7 +322,7 @@ void MapView::updateVisibleTiles()
Position tilePos = m_posInfo.camera.translated(ix - m_virtualCenterOffset.x, iy - m_virtualCenterOffset.y);
// adjust tilePos to the wanted floor
tilePos.coveredUp(m_posInfo.camera.z - iz);
if (const TilePtr& tile = g_map.getTile(tilePos)) {
if (const auto& tile = g_map.getTile(tilePos)) {
// skip tiles that have nothing
if (!tile->isDrawable())
continue;
Expand All @@ -340,7 +343,7 @@ void MapView::updateVisibleTiles()
tile->onAddInMapView();
}

if (isDrawingLights() && tile->canShade(static_self_cast<MapView>()))
if (isDrawingLights() && tile->canShade())
floor.shades.emplace_back(tile);

if (addTile || !floor.shades.empty()) {
Expand Down Expand Up @@ -399,9 +402,9 @@ void MapView::updateGeometry(const Size& visibleDimension)
m_virtualCenterOffset = (drawDimension / 2 - Size(1)).toPoint();
m_rectDimension = { 0, 0, bufferSize };

if (m_lightView) m_lightView->resize(m_drawDimension, tileSize);
g_mainDispatcher.addEvent([=, this]() {
m_pool->resize(bufferSize);
if (m_lightView) m_lightView->resize(drawDimension, tileSize);
});

const uint8_t left = std::min<uint8_t>(g_map.getAwareRange().left, (m_drawDimension.width() / 2) - 1);
Expand Down Expand Up @@ -547,8 +550,6 @@ void MapView::setAntiAliasingMode(const AntialiasingMode mode)
g_drawPool.get<DrawPoolFramed>(DrawPoolType::MAP)
->setSmooth(mode != ANTIALIASING_DISABLED);

if (m_lightView) m_lightView->setSmooth(mode != ANTIALIASING_DISABLED);

updateGeometry(m_visibleDimension);
}

Expand Down
7 changes: 7 additions & 0 deletions src/client/mapview.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ class MapView : public LuaObject
friend class LightView;

private:
enum class FadeType
{
NONE$, IN$, OUT$
};

struct MapObject
{
std::vector<TilePtr> shades;
Expand Down Expand Up @@ -289,6 +294,8 @@ class MapView : public LuaObject
bool m_drawHighlightTarget{ false };
bool m_shiftPressed{ false };

FadeType m_fadeType{ FadeType::NONE$ };

AntialiasingMode m_antiAliasingMode{ AntialiasingMode::ANTIALIASING_DISABLED };

std::array<MapObject, MAX_Z + 1> m_cachedVisibleTiles;
Expand Down
13 changes: 0 additions & 13 deletions src/client/tile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -611,19 +611,6 @@ void Tile::onAddInMapView()
}
}

bool Tile::canShade(const MapViewPtr& mapView)
{
for (const auto dir : { Otc::North, Otc::NorthWest, Otc::West }) {
const auto& pos = m_position.translatedToDirection(dir);
const auto& tile = g_map.getTile(pos);

if ((!tile && mapView->isInRangeEx(pos, true)) || (tile && !tile->isFullyOpaque() && !tile->isFullGround() && !tile->hasTopGround(true)))
return false;
}

return isFullyOpaque() || hasTopGround(true) || isFullGround();
}

bool Tile::hasBlockingCreature() const
{
for (const auto& thing : m_things)
Expand Down
2 changes: 1 addition & 1 deletion src/client/tile.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ class Tile : public LuaObject

bool limitsFloorsView(bool isFreeView = false);

bool canShade(const MapViewPtr& mapView);
bool canShade() { return isFullyOpaque() || hasTopGround() || isFullGround(); }
bool canRender(uint32_t& flags, const Position& cameraPosition, AwareRange viewPort);
bool canErase()
{
Expand Down
7 changes: 7 additions & 0 deletions src/framework/graphics/coordsbuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ class CoordsBuffer
if (src.isValid())
m_textureCoordArray.addRect(src);
}

void addRect(const RectF& dest, const RectF& src)
{
m_vertexArray.addRect(dest);
m_textureCoordArray.addRect(src);
}

void addQuad(const Rect& dest, const Rect& src)
{
m_vertexArray.addQuad(dest);
Expand Down
2 changes: 1 addition & 1 deletion src/framework/graphics/drawpool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ FPS60 = 1000 / 60;
DrawPool* DrawPool::create(const DrawPoolType type)
{
DrawPool* pool;
if (type == DrawPoolType::MAP || type == DrawPoolType::LIGHT || type == DrawPoolType::FOREGROUND) {
if (type == DrawPoolType::MAP || type == DrawPoolType::FOREGROUND) {
pool = new DrawPoolFramed;

const auto& frameBuffer = pool->toPoolFramed()->m_framebuffer;
Expand Down
1 change: 1 addition & 0 deletions src/framework/graphics/drawpoolmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class DrawPoolManager

void setScaleFactor(float scale) const { getCurrentPool()->setScaleFactor(scale); }
inline float getScaleFactor() const { return getCurrentPool()->getScaleFactor(); }
inline uint16_t getScaledSpriteSize() const { return SPRITE_SIZE * getScaleFactor(); }

void flush() const { if (getCurrentPool()) getCurrentPool()->flush(); }

Expand Down
5 changes: 5 additions & 0 deletions src/framework/graphics/texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ Texture* Texture::create()
}

void Texture::updateImage(const ImagePtr& image) { m_image = image; setupSize(image->getSize()); }

void Texture::updatePixels(uint8_t* pixels, int level, int channels, bool compress) {
bind();
setupPixels(level, m_size, pixels, channels, compress);
}
void Texture::uploadPixels(const ImagePtr& image, bool buildMipmaps, bool compress)
{
if (!setupSize(image->getSize()))
Expand Down
1 change: 1 addition & 0 deletions src/framework/graphics/texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class Texture
Texture* create();
void uploadPixels(const ImagePtr& image, bool buildMipmaps = false, bool compress = false);
void updateImage(const ImagePtr& image);
void updatePixels(uint8_t* pixels, int level = 0, int channels = 4, bool compress = false);

virtual void buildHardwareMipmaps();

Expand Down
15 changes: 15 additions & 0 deletions src/framework/graphics/vertexarray.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,21 @@ class VertexArray
addVertex(right, bottom);
}

void addRect(const RectF& rect)
{
float top = rect.top();
float right = rect.right() + 1.f;
float bottom = rect.bottom() + 1.f;
float left = rect.left();

addVertex(left, top);
addVertex(right, top);
addVertex(left, bottom);
addVertex(left, bottom);
addVertex(right, top);
addVertex(right, bottom);
}

void addQuad(const Rect& rect)
{
const float top = rect.top();
Expand Down

0 comments on commit 819ee76

Please sign in to comment.