Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve: lighting system replaced by that of the V8 #447

Merged
merged 4 commits into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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