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); | ||||
|     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…
	
		Reference in New Issue
	
	 Eduardo Bart
						Eduardo Bart