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:
Eduardo Bart 2012-11-29 19:38:39 -02:00
parent d7a45311ed
commit 6e154f6b2c
8 changed files with 123 additions and 44 deletions

View File

@ -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;

View File

@ -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)

View File

@ -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();
} }

View File

@ -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;

View File

@ -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();

View File

@ -96,6 +96,7 @@ struct MarketData {
}; };
struct Light { struct Light {
Light() { intensity = 0; color = 215; }
uint8 intensity; uint8 intensity;
uint8 color; uint8 color;
}; };

View File

@ -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;
}

View File

@ -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;