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
master
Eduardo Bart 12 years ago
parent d7a45311ed
commit 6e154f6b2c

@ -39,6 +39,8 @@ public:
void paste(const ImagePtr& other);
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; }
uint8* getPixelData() { return &m_pixels[0]; }
int getPixelCount() { return m_size.area(); }
@ -46,7 +48,7 @@ public:
int getWidth() { return m_size.width(); }
int getHeight() { return m_size.height(); }
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:
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);
m_footStepDrawn = true;
if(lightView && m_light.intensity > 0)
lightView->addLightSource(dest + (animationOffset + Point(16,16)) * scaleFactor, scaleFactor, m_light);
if(lightView) {
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)

@ -36,29 +36,25 @@ LightView::LightView()
void LightView::generateLightBuble()
{
const int size = 256;
uint8_t dest[size*size*4];
m_lightRadius = 128;
int circleDiameter = m_lightRadius * 2;
ImagePtr lightImage = ImagePtr(new Image(Size(circleDiameter, circleDiameter)));
for(int x = 0; x < size; x++){
for(int y = 0; y < size; y++){
int norm = std::sqrt((size/2 - x)*(size/2 - x) + (size/2 - y)*(size/2 - y));
float p = 128*norm/(size/2);
for(int x = 0; x < circleDiameter; x++) {
for(int y = 0; y < circleDiameter; y++) {
float radius = std::sqrt((m_lightRadius - x)*(m_lightRadius - x) + (m_lightRadius - y)*(m_lightRadius - y));
float intensity = std::max((m_lightRadius-radius)/(float)m_lightRadius, 0.0f);
float color = (p <= 128 ? 255 * (128-p)*(128-p)/(128*128) : 0);
if(color < 0)
color = 0;
// light intensity varies inversely with the square of the distance
intensity = intensity * intensity;
uint8_t colorByte = intensity * 255;
int line = y;
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;
uint8_t pixel[4] = {colorByte,colorByte,colorByte,255};
lightImage->setPixel(x, y, pixel);
}
}
ImagePtr light = ImagePtr(new Image(Size(size,size), 4, dest));
m_lightTexture = TexturePtr(new Texture(light, false));
m_lightTexture = TexturePtr(new Texture(lightImage, 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)
{
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;
source.center = center;
source.color = Color::from8bit(light.color);
source.color = color;
source.radius = radius;
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);
float factor = light.intensity / 256.0f;
color.setRed(color.rF() * factor);
color.setGreen(color.gF() * factor);
color.setBlue(color.bF() * factor);
color.setAlpha(1.0f);
float brightness = light.intensity / 256.0f;
color.setRed(color.rF() * brightness);
color.setGreen(color.gF() * brightness);
color.setBlue(color.bF() * brightness);
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)
{
Rect dest = Rect(center - Point(radius, radius), Size(radius*2,radius*2));
g_painter->setColor(color);
g_painter->setCompositionMode(Painter::CompositionMode_Add);
g_painter->drawTexturedRect(dest, m_lightTexture);
// 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);
}
void LightView::draw(const Rect& dest, const Rect& src)
{
g_painter->saveAndResetState();
m_lightbuffer->bind();
drawGlobalLight(m_globalLight, size);
g_painter->setCompositionMode(Painter::CompositionMode_Replace);
drawGlobalLight(m_globalLight);
g_painter->setCompositionMode(Painter::CompositionMode_Add);
for(const LightSource& source : m_lightMap)
drawLightSource(source.center, source.color, source.radius);
m_lightbuffer->release();
g_painter->setCompositionMode(Painter::CompositionMode_Light);
m_lightbuffer->draw();
g_painter->setCompositionMode(Painter::CompositionMode_Normal);
m_lightbuffer->draw(dest, src);
g_painter->restoreSavedState();
}

@ -41,14 +41,16 @@ public:
void reset();
void setGlobalLight(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:
void drawGlobalLight(const Light& light, const Size& size);
void drawGlobalLight(const Light& light);
void drawLightSource(const Point& center, const Color& color, int radius);
void generateLightBuble();
TexturePtr m_lightTexture;
int m_lightRadius;
FrameBufferPtr m_lightbuffer;
MapView* m_mapView;
Light m_globalLight;

@ -100,13 +100,14 @@ void MapView::draw(const Rect& rect)
if(m_drawLights) {
m_lightView->reset();
m_lightView->resize(m_framebuffer->getSize());
if(cameraPosition.z <= 7)
m_lightView->setGlobalLight(g_map.getLight());
else {
Light undergroundLight;
undergroundLight.color = 0;
undergroundLight.intensity = 0;
undergroundLight.color = 215;
undergroundLight.intensity = 16;
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();
// 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);
}
}
// 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()) {
Position pos = staticText->getPosition();

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

@ -28,6 +28,7 @@
#include "localplayer.h"
#include "effect.h"
#include "protocolgame.h"
#include "lightview.h"
#include <framework/graphics/fontmanager.h>
Tile::Tile(const Position& position) :
@ -92,7 +93,7 @@ void Tile::draw(const Point& dest, float scaleFactor, int drawFlags, LightView *
continue;
const TilePtr& tile = g_map.getTile(m_position.translated(x,y));
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()
@ -213,6 +221,9 @@ void Tile::addThing(const ThingPtr& thing, int stackPos)
thing->setPosition(m_position);
thing->onAppear();
if(thing->isTranslucent())
checkTranslucentLight();
}
bool Tile::removeThing(ThingPtr thing)
@ -239,6 +250,9 @@ bool Tile::removeThing(ThingPtr thing)
thing->onDisappear();
if(thing->isTranslucent())
checkTranslucentLight();
return removed;
}
@ -567,7 +581,7 @@ bool Tile::limitsFloorsView()
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)
@ -578,3 +592,30 @@ bool Tile::hasElevation(int elevation)
count++;
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_TRASHHOLDER = 1 << 20,
TILESTATE_BED = 1 << 21,
TILESTATE_DEPOT = 1 << 22
TILESTATE_DEPOT = 1 << 22,
TILESTATE_TRANSLUECENT_LIGHT = 1 << 23
};
#pragma pack(push,1) // disable memory alignment
@ -101,6 +102,7 @@ public:
bool isClickable();
bool isEmpty();
bool isDrawable();
bool hasTranslucentLight() { return m_flags & TILESTATE_TRANSLUECENT_LIGHT; }
bool mustHookSouth();
bool mustHookEast();
bool hasCreature();
@ -118,6 +120,8 @@ public:
TilePtr asTile() { return static_self_cast<Tile>(); }
private:
void checkTranslucentLight();
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<ThingPtr> m_things;

Loading…
Cancel
Save