Lights now are looking really good
* Draw lights beneath holes * Improve light particle * Light intensityvaries inversely with the square of the distance * Local player always have a minimum light in complete darkness * Creature names are behind lights now
This commit is contained in:
parent
d7a45311ed
commit
6e154f6b2c
|
@ -39,6 +39,8 @@ public:
|
||||||
void paste(const ImagePtr& other);
|
void paste(const ImagePtr& other);
|
||||||
bool nextMipmap();
|
bool nextMipmap();
|
||||||
|
|
||||||
|
void setPixel(int x, int y, uint8 *pixel) { memcpy(&m_pixels[(y * m_size.width() + x) * m_bpp], pixel, m_bpp);}
|
||||||
|
|
||||||
std::vector<uint8>& getPixels() { return m_pixels; }
|
std::vector<uint8>& getPixels() { return m_pixels; }
|
||||||
uint8* getPixelData() { return &m_pixels[0]; }
|
uint8* getPixelData() { return &m_pixels[0]; }
|
||||||
int getPixelCount() { return m_size.area(); }
|
int getPixelCount() { return m_size.area(); }
|
||||||
|
@ -46,7 +48,7 @@ public:
|
||||||
int getWidth() { return m_size.width(); }
|
int getWidth() { return m_size.width(); }
|
||||||
int getHeight() { return m_size.height(); }
|
int getHeight() { return m_size.height(); }
|
||||||
int getBpp() { return m_bpp; }
|
int getBpp() { return m_bpp; }
|
||||||
uint8* getPixel(int x, int y) { return &m_pixels[(y * m_size.width() + x) * 4]; }
|
uint8* getPixel(int x, int y) { return &m_pixels[(y * m_size.width() + x) * m_bpp]; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<uint8> m_pixels;
|
std::vector<uint8> m_pixels;
|
||||||
|
|
|
@ -81,8 +81,19 @@ void Creature::draw(const Point& dest, float scaleFactor, bool animate, LightVie
|
||||||
internalDrawOutfit(dest + animationOffset * scaleFactor, scaleFactor, animate, animate, m_direction);
|
internalDrawOutfit(dest + animationOffset * scaleFactor, scaleFactor, animate, animate, m_direction);
|
||||||
m_footStepDrawn = true;
|
m_footStepDrawn = true;
|
||||||
|
|
||||||
if(lightView && m_light.intensity > 0)
|
if(lightView) {
|
||||||
lightView->addLightSource(dest + (animationOffset + Point(16,16)) * scaleFactor, scaleFactor, m_light);
|
Light light = m_light;
|
||||||
|
|
||||||
|
// local player always have a minimum light in complete darkness
|
||||||
|
if(isLocalPlayer() && (g_map.getLight().intensity < 40 || m_position.z > Otc::SEA_FLOOR)) {
|
||||||
|
light.intensity = std::max<uint8>(light.intensity, 2);
|
||||||
|
if(light.color == 0 || light.color > 215)
|
||||||
|
light.color = 215;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(light.intensity > 0)
|
||||||
|
lightView->addLightSource(dest + (animationOffset + Point(16,16)) * scaleFactor, scaleFactor, light);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Creature::internalDrawOutfit(Point dest, float scaleFactor, bool animateWalk, bool animateIdle, Otc::Direction direction, LightView *lightView)
|
void Creature::internalDrawOutfit(Point dest, float scaleFactor, bool animateWalk, bool animateIdle, Otc::Direction direction, LightView *lightView)
|
||||||
|
|
|
@ -36,29 +36,25 @@ LightView::LightView()
|
||||||
|
|
||||||
void LightView::generateLightBuble()
|
void LightView::generateLightBuble()
|
||||||
{
|
{
|
||||||
const int size = 256;
|
m_lightRadius = 128;
|
||||||
uint8_t dest[size*size*4];
|
int circleDiameter = m_lightRadius * 2;
|
||||||
|
ImagePtr lightImage = ImagePtr(new Image(Size(circleDiameter, circleDiameter)));
|
||||||
|
|
||||||
for(int x = 0; x < size; x++){
|
for(int x = 0; x < circleDiameter; x++) {
|
||||||
for(int y = 0; y < size; y++){
|
for(int y = 0; y < circleDiameter; y++) {
|
||||||
int norm = std::sqrt((size/2 - x)*(size/2 - x) + (size/2 - y)*(size/2 - y));
|
float radius = std::sqrt((m_lightRadius - x)*(m_lightRadius - x) + (m_lightRadius - y)*(m_lightRadius - y));
|
||||||
float p = 128*norm/(size/2);
|
float intensity = std::max((m_lightRadius-radius)/(float)m_lightRadius, 0.0f);
|
||||||
|
|
||||||
float color = (p <= 128 ? 255 * (128-p)*(128-p)/(128*128) : 0);
|
// light intensity varies inversely with the square of the distance
|
||||||
if(color < 0)
|
intensity = intensity * intensity;
|
||||||
color = 0;
|
uint8_t colorByte = intensity * 255;
|
||||||
|
|
||||||
int line = y;
|
uint8_t pixel[4] = {colorByte,colorByte,colorByte,255};
|
||||||
|
lightImage->setPixel(x, y, pixel);
|
||||||
dest[4*x + 4*size*line] = (uint8_t)color;
|
|
||||||
dest[4*x + 4*size*line + 1] = (uint8_t)color;
|
|
||||||
dest[4*x + 4*size*line + 2] = (uint8_t)color;
|
|
||||||
dest[4*x + 4*size*line + 3] = 255;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagePtr light = ImagePtr(new Image(Size(size,size), 4, dest));
|
m_lightTexture = TexturePtr(new Texture(lightImage, true));
|
||||||
m_lightTexture = TexturePtr(new Texture(light, false));
|
|
||||||
m_lightTexture->setSmooth(true);
|
m_lightTexture->setSmooth(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,48 +70,66 @@ void LightView::setGlobalLight(const Light& light)
|
||||||
|
|
||||||
void LightView::addLightSource(const Point& center, float scaleFactor, const Light& light)
|
void LightView::addLightSource(const Point& center, float scaleFactor, const Light& light)
|
||||||
{
|
{
|
||||||
int radius = light.intensity * 64 * scaleFactor;
|
int radius = light.intensity * m_lightRadius * scaleFactor * 0.25f;
|
||||||
|
|
||||||
|
Color color = Color::from8bit(light.color);
|
||||||
|
float brightness = 0.8f + (light.intensity/8.0f)*0.2f;
|
||||||
|
|
||||||
|
color.setRed(color.rF() * brightness);
|
||||||
|
color.setGreen(color.gF() * brightness);
|
||||||
|
color.setBlue(color.bF() * brightness);
|
||||||
|
|
||||||
LightSource source;
|
LightSource source;
|
||||||
source.center = center;
|
source.center = center;
|
||||||
source.color = Color::from8bit(light.color);
|
source.color = color;
|
||||||
source.radius = radius;
|
source.radius = radius;
|
||||||
m_lightMap.push_back(source);
|
m_lightMap.push_back(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightView::drawGlobalLight(const Light& light, const Size& size)
|
void LightView::drawGlobalLight(const Light& light)
|
||||||
{
|
{
|
||||||
Color color = Color::from8bit(light.color);
|
Color color = Color::from8bit(light.color);
|
||||||
float factor = light.intensity / 256.0f;
|
float brightness = light.intensity / 256.0f;
|
||||||
color.setRed(color.rF() * factor);
|
color.setRed(color.rF() * brightness);
|
||||||
color.setGreen(color.gF() * factor);
|
color.setGreen(color.gF() * brightness);
|
||||||
color.setBlue(color.bF() * factor);
|
color.setBlue(color.bF() * brightness);
|
||||||
color.setAlpha(1.0f);
|
|
||||||
g_painter->setColor(color);
|
g_painter->setColor(color);
|
||||||
g_painter->drawFilledRect(Rect(0,0,size));
|
g_painter->drawFilledRect(Rect(0,0,m_lightbuffer->getSize()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightView::drawLightSource(const Point& center, const Color& color, int radius)
|
void LightView::drawLightSource(const Point& center, const Color& color, int radius)
|
||||||
{
|
{
|
||||||
Rect dest = Rect(center - Point(radius, radius), Size(radius*2,radius*2));
|
Rect dest = Rect(center - Point(radius, radius), Size(radius*2,radius*2));
|
||||||
g_painter->setColor(color);
|
g_painter->setColor(color);
|
||||||
|
g_painter->setCompositionMode(Painter::CompositionMode_Add);
|
||||||
g_painter->drawTexturedRect(dest, m_lightTexture);
|
g_painter->drawTexturedRect(dest, m_lightTexture);
|
||||||
|
|
||||||
// debug draw
|
// debug draw
|
||||||
//g_painter->drawBoundingRect(dest);
|
/*
|
||||||
|
radius = 8;
|
||||||
|
g_painter->setColor(Color::black);
|
||||||
|
g_painter->setCompositionMode(Painter::CompositionMode_Replace);
|
||||||
|
g_painter->drawBoundingRect(Rect(center - Point(radius, radius), Size(radius*2,radius*2)), 4);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightView::draw(Size size)
|
void LightView::resize(const Size& size)
|
||||||
{
|
{
|
||||||
m_lightbuffer->resize(size);
|
m_lightbuffer->resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightView::draw(const Rect& dest, const Rect& src)
|
||||||
|
{
|
||||||
|
g_painter->saveAndResetState();
|
||||||
m_lightbuffer->bind();
|
m_lightbuffer->bind();
|
||||||
drawGlobalLight(m_globalLight, size);
|
g_painter->setCompositionMode(Painter::CompositionMode_Replace);
|
||||||
|
drawGlobalLight(m_globalLight);
|
||||||
g_painter->setCompositionMode(Painter::CompositionMode_Add);
|
g_painter->setCompositionMode(Painter::CompositionMode_Add);
|
||||||
for(const LightSource& source : m_lightMap)
|
for(const LightSource& source : m_lightMap)
|
||||||
drawLightSource(source.center, source.color, source.radius);
|
drawLightSource(source.center, source.color, source.radius);
|
||||||
m_lightbuffer->release();
|
m_lightbuffer->release();
|
||||||
|
|
||||||
g_painter->setCompositionMode(Painter::CompositionMode_Light);
|
g_painter->setCompositionMode(Painter::CompositionMode_Light);
|
||||||
m_lightbuffer->draw();
|
m_lightbuffer->draw(dest, src);
|
||||||
g_painter->setCompositionMode(Painter::CompositionMode_Normal);
|
g_painter->restoreSavedState();
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,14 +41,16 @@ public:
|
||||||
void reset();
|
void reset();
|
||||||
void setGlobalLight(const Light& light);
|
void setGlobalLight(const Light& light);
|
||||||
void addLightSource(const Point& center, float scaleFactor, const Light& light);
|
void addLightSource(const Point& center, float scaleFactor, const Light& light);
|
||||||
void draw(Size size);
|
void resize(const Size& size);
|
||||||
|
void draw(const Rect& dest, const Rect& src);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void drawGlobalLight(const Light& light, const Size& size);
|
void drawGlobalLight(const Light& light);
|
||||||
void drawLightSource(const Point& center, const Color& color, int radius);
|
void drawLightSource(const Point& center, const Color& color, int radius);
|
||||||
void generateLightBuble();
|
void generateLightBuble();
|
||||||
|
|
||||||
TexturePtr m_lightTexture;
|
TexturePtr m_lightTexture;
|
||||||
|
int m_lightRadius;
|
||||||
FrameBufferPtr m_lightbuffer;
|
FrameBufferPtr m_lightbuffer;
|
||||||
MapView* m_mapView;
|
MapView* m_mapView;
|
||||||
Light m_globalLight;
|
Light m_globalLight;
|
||||||
|
|
|
@ -100,13 +100,14 @@ void MapView::draw(const Rect& rect)
|
||||||
|
|
||||||
if(m_drawLights) {
|
if(m_drawLights) {
|
||||||
m_lightView->reset();
|
m_lightView->reset();
|
||||||
|
m_lightView->resize(m_framebuffer->getSize());
|
||||||
|
|
||||||
if(cameraPosition.z <= 7)
|
if(cameraPosition.z <= 7)
|
||||||
m_lightView->setGlobalLight(g_map.getLight());
|
m_lightView->setGlobalLight(g_map.getLight());
|
||||||
else {
|
else {
|
||||||
Light undergroundLight;
|
Light undergroundLight;
|
||||||
undergroundLight.color = 0;
|
undergroundLight.color = 215;
|
||||||
undergroundLight.intensity = 0;
|
undergroundLight.intensity = 16;
|
||||||
m_lightView->setGlobalLight(undergroundLight);
|
m_lightView->setGlobalLight(undergroundLight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,9 +145,6 @@ void MapView::draw(const Rect& rect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_drawLights && m_updateTilesPos == 0)
|
|
||||||
m_lightView->draw(m_framebuffer->getSize());
|
|
||||||
|
|
||||||
m_framebuffer->release();
|
m_framebuffer->release();
|
||||||
|
|
||||||
// generating mipmaps each frame can be slow in older cards
|
// generating mipmaps each frame can be slow in older cards
|
||||||
|
@ -208,7 +206,13 @@ void MapView::draw(const Rect& rect)
|
||||||
|
|
||||||
creature->drawInformation(p, g_map.isCovered(pos, m_cachedFirstVisibleFloor), rect);
|
creature->drawInformation(p, g_map.isCovered(pos, m_cachedFirstVisibleFloor), rect);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lights are drawn after names and before texts
|
||||||
|
if(m_drawLights)
|
||||||
|
m_lightView->draw(rect, srcRect);
|
||||||
|
|
||||||
|
if(m_viewMode == NEAR_VIEW && m_drawTexts) {
|
||||||
for(const StaticTextPtr& staticText : g_map.getStaticTexts()) {
|
for(const StaticTextPtr& staticText : g_map.getStaticTexts()) {
|
||||||
Position pos = staticText->getPosition();
|
Position pos = staticText->getPosition();
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,7 @@ struct MarketData {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Light {
|
struct Light {
|
||||||
|
Light() { intensity = 0; color = 215; }
|
||||||
uint8 intensity;
|
uint8 intensity;
|
||||||
uint8 color;
|
uint8 color;
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "localplayer.h"
|
#include "localplayer.h"
|
||||||
#include "effect.h"
|
#include "effect.h"
|
||||||
#include "protocolgame.h"
|
#include "protocolgame.h"
|
||||||
|
#include "lightview.h"
|
||||||
#include <framework/graphics/fontmanager.h>
|
#include <framework/graphics/fontmanager.h>
|
||||||
|
|
||||||
Tile::Tile(const Position& position) :
|
Tile::Tile(const Position& position) :
|
||||||
|
@ -92,7 +93,7 @@ void Tile::draw(const Point& dest, float scaleFactor, int drawFlags, LightView *
|
||||||
continue;
|
continue;
|
||||||
const TilePtr& tile = g_map.getTile(m_position.translated(x,y));
|
const TilePtr& tile = g_map.getTile(m_position.translated(x,y));
|
||||||
if(tile)
|
if(tile)
|
||||||
tile->draw(dest + Point(x*Otc::TILE_PIXELS, y*Otc::TILE_PIXELS)*scaleFactor, scaleFactor, topRedrawFlags, lightView);
|
tile->draw(dest + Point(x*Otc::TILE_PIXELS, y*Otc::TILE_PIXELS)*scaleFactor, scaleFactor, topRedrawFlags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,6 +134,13 @@ void Tile::draw(const Point& dest, float scaleFactor, int drawFlags, LightView *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// draw translucent light (for tiles beneath holes)
|
||||||
|
if(hasTranslucentLight() && lightView) {
|
||||||
|
Light light;
|
||||||
|
light.intensity = 2;
|
||||||
|
lightView->addLightSource(dest + Point(16,16) * scaleFactor, scaleFactor, light);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tile::clean()
|
void Tile::clean()
|
||||||
|
@ -213,6 +221,9 @@ void Tile::addThing(const ThingPtr& thing, int stackPos)
|
||||||
|
|
||||||
thing->setPosition(m_position);
|
thing->setPosition(m_position);
|
||||||
thing->onAppear();
|
thing->onAppear();
|
||||||
|
|
||||||
|
if(thing->isTranslucent())
|
||||||
|
checkTranslucentLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Tile::removeThing(ThingPtr thing)
|
bool Tile::removeThing(ThingPtr thing)
|
||||||
|
@ -239,6 +250,9 @@ bool Tile::removeThing(ThingPtr thing)
|
||||||
|
|
||||||
thing->onDisappear();
|
thing->onDisappear();
|
||||||
|
|
||||||
|
if(thing->isTranslucent())
|
||||||
|
checkTranslucentLight();
|
||||||
|
|
||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,7 +581,7 @@ bool Tile::limitsFloorsView()
|
||||||
|
|
||||||
bool Tile::canErase()
|
bool Tile::canErase()
|
||||||
{
|
{
|
||||||
return m_walkingCreatures.empty() && m_effects.empty() && m_things.empty();
|
return m_walkingCreatures.empty() && m_effects.empty() && m_things.empty() && m_flags == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Tile::hasElevation(int elevation)
|
bool Tile::hasElevation(int elevation)
|
||||||
|
@ -578,3 +592,30 @@ bool Tile::hasElevation(int elevation)
|
||||||
count++;
|
count++;
|
||||||
return count >= elevation;
|
return count >= elevation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Tile::checkTranslucentLight()
|
||||||
|
{
|
||||||
|
if(m_position.z < Otc::SEA_FLOOR)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Position downPos = m_position;
|
||||||
|
if(!downPos.down())
|
||||||
|
return;
|
||||||
|
|
||||||
|
TilePtr tile = g_map.getOrCreateTile(downPos);
|
||||||
|
if(!tile)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool translucent = false;
|
||||||
|
for(const ThingPtr& thing : m_things) {
|
||||||
|
if(thing->isTranslucent() || thing->hasLensHelp()) {
|
||||||
|
translucent = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(translucent)
|
||||||
|
tile->m_flags = tile->m_flags | TILESTATE_TRANSLUECENT_LIGHT;
|
||||||
|
else
|
||||||
|
tile->m_flags = tile->m_flags & ~TILESTATE_TRANSLUECENT_LIGHT;
|
||||||
|
}
|
||||||
|
|
|
@ -47,7 +47,8 @@ enum tileflags_t
|
||||||
TILESTATE_MAILBOX = 1 << 19,
|
TILESTATE_MAILBOX = 1 << 19,
|
||||||
TILESTATE_TRASHHOLDER = 1 << 20,
|
TILESTATE_TRASHHOLDER = 1 << 20,
|
||||||
TILESTATE_BED = 1 << 21,
|
TILESTATE_BED = 1 << 21,
|
||||||
TILESTATE_DEPOT = 1 << 22
|
TILESTATE_DEPOT = 1 << 22,
|
||||||
|
TILESTATE_TRANSLUECENT_LIGHT = 1 << 23
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(push,1) // disable memory alignment
|
#pragma pack(push,1) // disable memory alignment
|
||||||
|
@ -101,6 +102,7 @@ public:
|
||||||
bool isClickable();
|
bool isClickable();
|
||||||
bool isEmpty();
|
bool isEmpty();
|
||||||
bool isDrawable();
|
bool isDrawable();
|
||||||
|
bool hasTranslucentLight() { return m_flags & TILESTATE_TRANSLUECENT_LIGHT; }
|
||||||
bool mustHookSouth();
|
bool mustHookSouth();
|
||||||
bool mustHookEast();
|
bool mustHookEast();
|
||||||
bool hasCreature();
|
bool hasCreature();
|
||||||
|
@ -118,6 +120,8 @@ public:
|
||||||
TilePtr asTile() { return static_self_cast<Tile>(); }
|
TilePtr asTile() { return static_self_cast<Tile>(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void checkTranslucentLight();
|
||||||
|
|
||||||
stdext::packed_vector<CreaturePtr> m_walkingCreatures;
|
stdext::packed_vector<CreaturePtr> m_walkingCreatures;
|
||||||
stdext::packed_vector<EffectPtr> m_effects; // leave this outside m_things because it has no stackpos.
|
stdext::packed_vector<EffectPtr> m_effects; // leave this outside m_things because it has no stackpos.
|
||||||
stdext::packed_vector<ThingPtr> m_things;
|
stdext::packed_vector<ThingPtr> m_things;
|
||||||
|
|
Loading…
Reference in New Issue