can contain any number of stop-colors creating the gradient with values from 0 to 1.
every call to addColor sorts the new color within the color-array by its float value t, so the interpolation should speed up.
it can create images of any size.
Example gradient with 5 colors
Code: Select all
video::CLinearColorGradient Gradient;
Gradient.addColor( video::SColor(255,255,0,0), 1.0f );
Gradient.addColor( video::SColor(255,0,0,255), 0.0f);
Gradient.addColor( video::SColor(255,0,200,0), 0.35f );
Gradient.addColor( video::SColor(255,255,255,0), 0.75f );
Gradient.addColor( video::SColor(255,255,255,255), 0.5f );
video::IImage* tmp = Gradient.createImage( 512, 256, false);
if (tmp)
{
driver->writeImageToFile( tmp, "test_linear_color_gradient_h.png");
tmp->drop();
tmp = 0;
}
http://benjaminhampe.be.ohost.de/Irrlic ... nt.tar.bz2
CLinearColorGradient.h
Code: Select all
// Copyright (C) 2002-2013 BenjaminHampe@gmx.de
// This file intends to advance the caps of the "Irrlicht Engine"
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __IRR_C_LINEAR_COLOR_GRADIENT_H__
#define __IRR_C_LINEAR_COLOR_GRADIENT_H__
// #include <irrlicht.h>
#include <irrTypes.h>
#include <irrString.h>
#include <irrArray.h>
#include <SColor.h>
#include <EMaterialTypes.h>
#include <IImage.h>
#include <IVideoDriver.h>
namespace irr
{
namespace video
{
core::stringc toString( const SColor& color );
core::stringc toString( const SColorf& color );
////////////////////////////////////////////////////////////////////////////
/// class CLinearColorGradient
////////////////////////////////////////////////////////////////////////////
class CLinearColorGradient : public IReferenceCounted
{
public:
CLinearColorGradient(); // const SColor& startColor = SColor(0,0,0,0), const SColor& endColor = SColor(255,255,255,255) );
virtual ~CLinearColorGradient();
virtual core::stringc getName( ) const;
virtual CLinearColorGradient& setName( const core::stringc& name );
virtual SColor getColor( f32 t ) const;
virtual SColorf getColorf( f32 t ) const;
virtual u32 getColorCount() const;
virtual CLinearColorGradient& clear();
virtual CLinearColorGradient& addColor( const SColor& stopColor, f32 t = 0.5f );
virtual CLinearColorGradient& addColor( const SColorf& stopColor, f32 t = 0.5f );
virtual CLinearColorGradient& setColor( u32 index, const SColor& stopColor, f32 t = 0.5f );
virtual CLinearColorGradient& setColor( u32 index, const SColorf& stopColor, f32 t = 0.5f );
virtual bool isTransparent( ) const;
virtual E_MATERIAL_TYPE getMaterialType( ) const;
virtual ECOLOR_FORMAT getColorFormat( ) const;
virtual core::stringc toString( ) const;
virtual IImage* createImage( u32 w, u32 h, bool bVertical = false ) const;
private:
struct MyColorStruct
{
SColorf Color;
f32 Position; // in range 0..1
};
core::stringc Name;
core::array<MyColorStruct> Colors;
};
} // end namespace video
} // end namespace irr
#endif // __IRR_C_LINEAR_COLOR_GRADIENT_H__
Code: Select all
// Copyright (C) 2002-2013 BenjaminHampe@gmx.de
// This file intends to advance the caps of the "Irrlicht Engine"
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CLinearColorGradient.h"
//#include <irrlicht.h>
#include <irrTypes.h>
#include <irrString.h>
#include <irrArray.h>
#include <SColor.h>
#include <EMaterialTypes.h>
#include <IImage.h>
#include <IVideoDriver.h>
#include <../source/Irrlicht/os.h>
#include <../source/Irrlicht/CImage.h>
namespace irr
{
namespace video
{
core::stringc toString( const SColor& color )
{
core::stringc s("SColor(");
s += color.getAlpha();
s += ",";
s += color.getRed();
s += ",";
s += color.getGreen();
s += ",";
s += color.getBlue();
s += ")";
return s;
}
core::stringc toString( const SColorf& color )
{
core::stringc s("SColorf(");
s += color.getAlpha();
s += ",";
s += color.getRed();
s += ",";
s += color.getGreen();
s += ",";
s += color.getBlue();
s += ")";
return s;
}
CLinearColorGradient::CLinearColorGradient() // const SColor& startColor, const SColor& endColor)
: Name("")
{
#if _DEBUG
os::Printer::log( "CLinearColorGradient::ctr()", ELL_INFORMATION );
#endif // _DEBUG
// addColor( startColor, 0.0f );
// addColor( endColor, 1.0f );
}
CLinearColorGradient::~CLinearColorGradient()
{
#if _DEBUG
os::Printer::log( "CLinearColorGradient::dtr()", ELL_INFORMATION );
#endif // _DEBUG
clear();
}
CLinearColorGradient& CLinearColorGradient::clear()
{
Colors.clear();
}
CLinearColorGradient& CLinearColorGradient::addColor( const SColor& stopColor, f32 t )
{
return addColor( video::SColorf(stopColor), t);
}
CLinearColorGradient& CLinearColorGradient::addColor( const SColorf& stopColor, f32 t )
{
#if _DEBUG
os::Printer::log( "CLinearColorGradient::addColor()", ELL_INFORMATION );
#endif // _DEBUG
MyColorStruct entry;
entry.Color = stopColor;
entry.Position = core::clamp<f32>( t, 0.0f, 1.0f );
const u32 c = getColorCount();
if (c==0)
{
Colors.push_back( entry );
}
else // if (c>0)
{
bool found_greater_t = false;
u32 greater_t_index = 0;
for (u32 i=0; i<c; i++)
{
if ( core::equals(t, Colors[i].Position) )
{
return *this; // dont insert if any t does equal one of array-elements
}
else if ( Colors[i].Position > t )
{
found_greater_t = true;
greater_t_index = i;
break;
}
}
if (found_greater_t)
Colors.insert( entry, greater_t_index);
else
Colors.push_back( entry );
}
return *this;
}
CLinearColorGradient& CLinearColorGradient::setColor( u32 index, const SColor& stopColor, f32 t )
{
const u32 size0 = getColorCount();
if (index >= size0)
return *this;
Colors[index].Color = video::SColorf(stopColor);
Colors[index].Position = core::clamp<f32>( t, 0.0f, 1.0f );
return *this;
}
CLinearColorGradient& CLinearColorGradient::setColor( u32 index, const SColorf& stopColor, f32 t )
{
const u32 size0 = getColorCount();
if (index >= size0)
return *this;
Colors[index].Color = stopColor;
Colors[index].Position = core::clamp<f32>( t, 0.0f, 1.0f );
return *this;
}
SColor CLinearColorGradient::getColor( f32 t ) const
{
return getColorf(t).toSColor();
}
SColorf CLinearColorGradient::getColorf( f32 t ) const
{
// #if _DEBUG
// os::Printer::log( "CLinearColorGradient::getColor()", ELL_INFORMATION );
// #endif // _DEBUG
const u32 colorCount = getColorCount();
// find maximum and minimum neighbors
bool found_greater_t = false;
u32 greater_t_index = 0;
for (u32 i=0; i<colorCount; i++)
{
if ( core::equals(t, Colors[i].Position) )
{
return Colors[i].Color;
}
else if (Colors[i].Position > t)
{
found_greater_t = true;
greater_t_index = i;
break;
}
}
if (!found_greater_t)
{
return Colors[colorCount-1].Color;
}
// interpolate between prev and next neighbor color
const SColorf& A = Colors[greater_t_index-1].Color;
const SColorf& B = Colors[greater_t_index].Color;
const f32 min_t = Colors[greater_t_index-1].Position;
const f32 max_t = Colors[greater_t_index].Position;
const f32 dx = core::abs_<f32>( (t - min_t) / (max_t - min_t) );
const f32 fa = A.getAlpha() + dx*( B.getAlpha() - A.getAlpha() );
const f32 fr = A.getRed() + dx*( B.getRed() - A.getRed() );
const f32 fg = A.getGreen() + dx*( B.getGreen() - A.getGreen() );
const f32 fb = A.getBlue() + dx*( B.getBlue() - A.getBlue() );
return video::SColorf( fr,fg,fb,fa );
}
u32 CLinearColorGradient::getColorCount() const
{
return Colors.size();
}
core::stringc CLinearColorGradient::getName( ) const
{
return Name;
}
CLinearColorGradient& CLinearColorGradient::setName( const core::stringc& name )
{
Name = name;
return *this;
}
bool CLinearColorGradient::isTransparent( ) const
{
bool bTransparent = false;
u32 i=0;
u32 c=getColorCount();
while (i<c)
{
if (Colors[i].Color.getAlpha() < 1.0f) // not 255
{
bTransparent = true;
break;
}
i++; // dont ever forget again foo
}
return bTransparent;
}
E_MATERIAL_TYPE CLinearColorGradient::getMaterialType( ) const
{
if (isTransparent())
return EMT_TRANSPARENT_ALPHA_CHANNEL;
else
return EMT_SOLID;
}
ECOLOR_FORMAT CLinearColorGradient::getColorFormat( ) const
{
if (isTransparent())
return ECF_A8R8G8B8;
else
return ECF_R8G8B8;
}
// old
//IImage* CLinearColorGradient::createImage( IVideoDriver* driver, u32 w, u32 h, bool bVertical ) const
// new
IImage* CLinearColorGradient::createImage( u32 w, u32 h, bool bVertical ) const
{
#if _DEBUG
os::Printer::log( "CLinearColorGradient::createImage()", ELL_INFORMATION );
#endif // _DEBUG
if (w==0 || h==0)
{
os::Printer::log( "Can't create Image of size zero.", ELL_ERROR );
return 0;
}
// old
//IImage* tmp = driver->createImage( this->getColorFormat(), core::dimension2du(w,h) );
// new
IImage* tmp = (IImage*)new CImage( this->getColorFormat(), core::dimension2du(w,h) );
if (!tmp)
{
os::Printer::log( "Could not create CImage", ELL_ERROR );
return 0;
}
const core::dimension2du& ImageSize = tmp->getDimension();
// #if _DEBUG
// // os::Printer::log( core::sprintf("Created new CImage(%d,%d,%d)", ImageSize.Width, ImageSize.Height, tmp->getBitsPerPixel()).c_str(), ELL_INFORMATION );
// // os::Printer::log( "start filling", ELL_INFORMATION );
// #endif // _DEBUG
// vertical filling
if ( bVertical )
{
const f32 fy = 1.0f / (f32)h;
for (u32 y=0; y<ImageSize.Height; y++)
{
video::SColor color = getColor( fy*y );
for (u32 x=0; x<ImageSize.Width; x++)
{
tmp->setPixel( x,y,color );
}
}
}
// horizontal filling
else
{
const f32 fx = 1.0f / (f32)w ;
for (u32 x=0; x<ImageSize.Width; x++)
{
video::SColor color = getColor( fx*x );
for (u32 y=0; y<ImageSize.Height; y++)
{
tmp->setPixel( x,y,color );
}
}
}
// #if _DEBUG
// os::Printer::log( "finish image filling with CLinearColorGradient", ELL_INFORMATION );
// #endif // _DEBUG
return tmp;
}
core::stringc CLinearColorGradient::toString( ) const
{
core::stringc s("CLinearColorGradient[");
// print number of colors used
u32 c = getColorCount();
s += (s32)c;
// print name
if (Name.size()>0)
{
s += Name;
s += ", ";
}
// print
s += "] = {\n";
// print colors
for (u32 i=0; i<c; i++)
{
s += "\t{ ";
s += video::toString( Colors[i].Color.toSColor() );
s += ", ";
s += Colors[i].Position;
s += " }";
if (i<c)
{
s += ",";
}
s += "\n";
}
// print
s += "};\n";
return s;
}
//IImage* createImageFromLinearColorGradient( u32 w, u32 h, bool bVertical, CLinearColorGradient* gradient, bool deleteGradient)
//{
// if (!gradient)
// return 0;
//
// IImage* tmp = gradient->createImage( w,h,bVertical );
//
// if (deleteGradient)
// {
// delete gradient;
// }
//
// return tmp;
//}
} // end namespace video
} // end namespace irr
Code: Select all
/**
Example 099: tests new class CLinearColorGradient
Copyright (C) 2002-2013 BenjaminHampe@gmx.de
This file intends to advance the caps of the "Irrlicht Engine"
For conditions of distribution and use, see copyright notice in irrlicht.h
*/
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif
#include <irrlicht.h>
#include "CLinearColorGradient.h"
using namespace irr;
//! this draw a gradient with lines, very slow, better use the image creation, convert to texture, and draw textured quad or similar
inline void drawGradient(
video::IVideoDriver* driver, video::CLinearColorGradient* gradient, const core::recti& rectangle)
{
if (!driver)
return;
if (!gradient)
return;
const s32 x1 = rectangle.UpperLeftCorner.X;
const s32 y1 = rectangle.UpperLeftCorner.Y;
const s32 w = rectangle.getWidth();
const s32 h = rectangle.getHeight();
const f32 dt = 1.0f / (f32)h;
for (u32 y = 0; y<h; y++)
{
f32 t = 1.0f - dt*(f32)y;
driver->draw2DLine( core::position2di(x1,y1+y), core::position2di(x1+w,y1+y), gradient->getColor(t) );
}
}
//! main entry
int main()
{
SIrrlichtCreationParameters deviceParameter;
deviceParameter.LoggingLevel = ELL_INFORMATION;
deviceParameter.DriverType = video::EDT_OPENGL;
deviceParameter.Fullscreen = false;
deviceParameter.Doublebuffer = true;
deviceParameter.WindowSize = core::dimension2du(1024,768);
deviceParameter.Bits = 24;
deviceParameter.AntiAlias = video::EAAM_QUALITY;
deviceParameter.Vsync = false;
deviceParameter.HighPrecisionFPU = true;
// deviceParameter.Stencilbuffer = false;
// deviceParameter.WithAlphaChannel = false;
// deviceParameter.AntiAlias = video::EAAM_OFF;
// deviceParameter.ZBufferBits = 16;
IrrlichtDevice *device = createDeviceEx( deviceParameter );
if (device == 0)
return 1;
device->setWindowCaption(L"Irrlicht Example 99 - CLinearColorGradient");
ILogger* logger = device->getLogger();
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* env = device->getGUIEnvironment();
const core::dimension2du screen = driver->getScreenSize();
//driver->setTextureCreationFlag( video::ETCF_CREATE_MIP_MAPS, false);
//driver->setTextureCreationFlag( video::ETCF_ALWAYS_32_BIT, true);
//driver->setTextureCreationFlag( video::ETCF_ALLOW_NON_POWER_2, true);
smgr->getParameters()->setAttribute( scene::DEBUG_NORMAL_LENGTH, 0.3f );
smgr->getParameters()->setAttribute( scene::DEBUG_NORMAL_COLOR, video::SColor(255,255,0,0) );
// device->run(); // does not help
// TestColorGradient test0( device->getLogger(), driver );
logger->log( "Test CLinearColorGradient", ELL_INFORMATION );
logger->log( "" );
video::CLinearColorGradient Gradient;
logger->log( "add some colors to gradient", ELL_INFORMATION );
logger->log( "" );
Gradient.addColor( video::SColor(255,255,0,0), 1.0f );
Gradient.addColor( video::SColor(255,0,0,255), 0.0f);
Gradient.addColor( video::SColor(255,0,200,0), 0.35f );
Gradient.addColor( video::SColor(255,255,255,0), 0.75f );
Gradient.addColor( video::SColor(255,255,255,255), 0.5f );
logger->log( "Now let the gradient print its internal data", ELL_INFORMATION );
logger->log( "" );
logger->log( Gradient.toString().c_str(), ELL_INFORMATION);
logger->log( "Now test the getColor() function in the range from 0 to 1 and step-value 0.05", ELL_INFORMATION );
logger->log( "" );
const u32 count = 20;
const f32 step = core::reciprocal( (f32)count ); // 1:20 == 0.05
for (u32 i=0; i<=count; i++)
{
const f32 t = step*i;
core::stringc s( "CLinearColorGradient.getColor(" ); s+=t; s+=") = ";
s += video::toString( Gradient.getColor(t) );
logger->log( s.c_str(), ELL_INFORMATION);
}
logger->log( "" );
logger->log( "Now create two images, one with horizontal gradient, one with vertical gradient.", ELL_INFORMATION );
logger->log( "" );
video::IImage* tmp = 0;
// create vertical gradient image
tmp = Gradient.createImage( 512, 1024, true);
if (tmp)
{
driver->writeImageToFile( tmp, "test_linear_color_gradient_v.png");
tmp->drop();
tmp = 0;
}
// create horizontal gradient image
tmp = Gradient.createImage( 1024, 512, false);
if (tmp)
{
driver->writeImageToFile( tmp, "test_linear_color_gradient_h.png");
tmp->drop();
tmp = 0;
}
/*
create camera
*/
// SKeyMap KeyMapArray[6];
// KeyMapArray[0].Action = EKA_MOVE_FORWARD;
// KeyMapArray[1].Action = EKA_MOVE_BACKWARD;
// KeyMapArray[2].Action = EKA_STRAFE_LEFT;
// KeyMapArray[3].Action = EKA_STRAFE_RIGHT;
// KeyMapArray[4].Action = EKA_CROUCH;
// KeyMapArray[5].Action = EKA_JUMP_UP;
// KeyMapArray[0].KeyCode = KEY_KEY_W;
// KeyMapArray[1].KeyCode = KEY_KEY_S;
// KeyMapArray[2].KeyCode = KEY_KEY_A;
// KeyMapArray[3].KeyCode = KEY_KEY_D;
// KeyMapArray[4].KeyCode = KEY_KEY_C;
// KeyMapArray[5].KeyCode = KEY_SPACE;
//
// smgr->addCameraSceneNodeFPS(
// smgr->getRootSceneNode(), 100.0f, .1f, -1, KeyMapArray, 6, false, 1, false, true );
//
// scene::ICameraSceneNode* cam = smgr->getActiveCamera();
// if (cam)
// {
// cam->setNearValue( 1.0f );
// cam->setFarValue( 100000.0f );
// cam->setPosition( core::vector3df(35,12,-180) );
// cam->setTarget( core::vector3df(32,-9,2) );
// }
/*
main loop
*/
// scene::CAudioEQSceneNode eq( "../../media/audio/getout.ogg", smgr, smgr->getRootSceneNode(), -1,
// core::vector3df(0,0,0),core::vector3df(0,0,0),core::vector3df(1,1,1));
//
// eq.setScale( core::vector3df( 40,10,40) );
u32 frames=0;
while(device->run())
{
driver->beginScene(true, true, video::SColor(255,100,100,100));
smgr->drawAll();
env->drawAll();
// this draws the gradient
drawGradient( driver, &Gradient, core::recti(screen.Width/2, 0, screen.Width-1, screen.Height-1) );
driver->endScene();
if (++frames==100)
{
core::stringw str = L"GeometryCreator Example using Irrlicht Engine [";
str += driver->getName();
str += L"] FPS(";
str += (s32)driver->getFPS();
str += L"), Tris(";
str += (s32)driver->getPrimitiveCountDrawn();
str += L")";
irr::scene::ICameraSceneNode* camera = smgr->getActiveCamera();
if (camera)
{
str += L", Cam pos(";
str += irr::core::round32(camera->getPosition().X);
str += L", ";
str += irr::core::round32(camera->getPosition().Y);
str += L", ";
str += irr::core::round32(camera->getPosition().Z);
str += L"), eye(";
str += irr::core::round32(camera->getTarget().X);
str += L", ";
str += irr::core::round32(camera->getTarget().Y);
str += L", ";
str += irr::core::round32(camera->getTarget().Z);
str += L")";
}
device->setWindowCaption(str.c_str());
frames=0;
}
}
device->drop();
return 0;
}