Merge branch 'master' of github.com:supertuxkart/stk-code
This commit is contained in:
commit
111b3f6361
@ -4,7 +4,7 @@ out vec4 FragColor;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
vec3 eyedir = gl_FragCoord.xyz / vec3(screen, 1.);
|
||||
vec3 eyedir = vec3(gl_FragCoord.xy / screen, 1.);
|
||||
eyedir = 2.0 * eyedir - 1.0;
|
||||
vec4 tmp = (InverseProjectionMatrix * vec4(eyedir, 1.));
|
||||
tmp /= tmp.w;
|
||||
|
10
data/shaders/sky.vert
Normal file
10
data/shaders/sky.vert
Normal file
@ -0,0 +1,10 @@
|
||||
#if __VERSION__ >= 330
|
||||
layout(location = 0) in vec3 Position;
|
||||
#else
|
||||
in vec3 Position;
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(Position, 1.);
|
||||
}
|
@ -6,6 +6,6 @@ vec3 SpecularIBL(vec3 normal, vec3 V, float roughness)
|
||||
sampleDirection = (InverseViewMatrix * vec4(sampleDirection, 0.)).xyz;
|
||||
|
||||
// Assume 8 level of lod (ie 256x256 texture)
|
||||
float lodval = 8. * (1. - roughness);
|
||||
return clamp( textureLod(probe, sampleDirection, lodval).rgb, 0., 1.);
|
||||
float lodval = 7. * (1. - roughness);
|
||||
return clamp(textureLod(probe, sampleDirection, lodval).rgb, 0., 1.);
|
||||
}
|
||||
|
@ -61,9 +61,7 @@ source/Irrlicht/CGUIFileOpenDialog.cpp
|
||||
source/Irrlicht/CGUISpriteBank.cpp
|
||||
source/Irrlicht/CParticleFadeOutAffector.cpp
|
||||
source/Irrlicht/CGUIMenu.cpp
|
||||
source/Irrlicht/CImageWriterPSD.cpp
|
||||
source/Irrlicht/CSphereSceneNode.cpp
|
||||
source/Irrlicht/CImageWriterTGA.cpp
|
||||
source/Irrlicht/CImageWriterPNG.cpp
|
||||
source/Irrlicht/CSceneNodeAnimatorFollowSpline.cpp
|
||||
source/Irrlicht/CGUIMessageBox.cpp
|
||||
@ -73,7 +71,6 @@ source/Irrlicht/CBoneSceneNode.cpp
|
||||
source/Irrlicht/CNPKReader.cpp
|
||||
source/Irrlicht/COpenGLSLMaterialRenderer.cpp
|
||||
source/Irrlicht/CParticleRotationAffector.cpp
|
||||
source/Irrlicht/CImageLoaderPSD.cpp
|
||||
source/Irrlicht/CTriangleBBSelector.cpp
|
||||
source/Irrlicht/CGUIComboBox.cpp
|
||||
source/Irrlicht/CSceneNodeAnimatorTexture.cpp
|
||||
@ -93,7 +90,6 @@ source/Irrlicht/CParticlePointEmitter.cpp
|
||||
source/Irrlicht/CTextSceneNode.cpp
|
||||
source/Irrlicht/CIrrDeviceLinux.cpp
|
||||
source/Irrlicht/CIrrDeviceStub.cpp
|
||||
source/Irrlicht/CImageWriterPCX.cpp
|
||||
source/Irrlicht/CGUIInOutFader.cpp
|
||||
source/Irrlicht/CGUITreeView.cpp
|
||||
source/Irrlicht/CAnimatedMeshSceneNode.cpp
|
||||
@ -105,7 +101,6 @@ source/Irrlicht/CColorConverter.cpp
|
||||
source/Irrlicht/CMeshCache.cpp
|
||||
source/Irrlicht/CIrrDeviceFB.cpp
|
||||
source/Irrlicht/CMemoryFile.cpp
|
||||
source/Irrlicht/CImageWriterPPM.cpp
|
||||
source/Irrlicht/CMountPointReader.cpp
|
||||
source/Irrlicht/CBillboardSceneNode.cpp
|
||||
source/Irrlicht/CGUIImageList.cpp
|
||||
@ -124,29 +119,23 @@ source/Irrlicht/CGUIEditBox.cpp
|
||||
source/Irrlicht/CLogger.cpp
|
||||
source/Irrlicht/CMeshManipulator.cpp
|
||||
source/Irrlicht/CLightSceneNode.cpp
|
||||
source/Irrlicht/CImageLoaderDDS.cpp
|
||||
source/Irrlicht/CSkyBoxSceneNode.cpp
|
||||
source/Irrlicht/CWriteFile.cpp
|
||||
source/Irrlicht/COctreeTriangleSelector.cpp
|
||||
source/Irrlicht/CFileList.cpp
|
||||
source/Irrlicht/CImageLoaderPCX.cpp
|
||||
source/Irrlicht/CIrrDeviceSDL.cpp
|
||||
source/Irrlicht/COSOperator.cpp
|
||||
source/Irrlicht/CImageLoaderJPG.cpp
|
||||
source/Irrlicht/COpenGLExtensionHandler.cpp
|
||||
source/Irrlicht/CImageLoaderWAL.cpp
|
||||
source/Irrlicht/CXMLWriter.cpp
|
||||
source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp
|
||||
source/Irrlicht/CImageLoaderPPM.cpp
|
||||
source/Irrlicht/CGUIColorSelectDialog.cpp
|
||||
source/Irrlicht/CSceneManager.cpp
|
||||
source/Irrlicht/Irrlicht.cpp
|
||||
source/Irrlicht/COpenGLShaderMaterialRenderer.cpp
|
||||
source/Irrlicht/CImageLoaderTGA.cpp
|
||||
source/Irrlicht/COpenGLDriver.cpp
|
||||
source/Irrlicht/CSceneNodeAnimatorFlyStraight.cpp
|
||||
source/Irrlicht/irrXML.cpp
|
||||
source/Irrlicht/CImageLoaderRGB.cpp
|
||||
source/Irrlicht/CSkinnedMesh.cpp
|
||||
source/Irrlicht/CXMLReader.cpp
|
||||
source/Irrlicht/CDummyTransformationSceneNode.cpp
|
||||
@ -159,7 +148,6 @@ source/Irrlicht/CGUISpinBox.cpp
|
||||
source/Irrlicht/CReadFile.cpp
|
||||
source/Irrlicht/CParticleRingEmitter.cpp
|
||||
source/Irrlicht/CMetaTriangleSelector.cpp
|
||||
source/Irrlicht/CShadowVolumeSceneNode.cpp
|
||||
source/Irrlicht/CDefaultSceneNodeFactory.cpp
|
||||
source/Irrlicht/CGUIImage.cpp
|
||||
source/Irrlicht/CGUIEnvironment.cpp
|
||||
@ -174,20 +162,17 @@ source/Irrlicht/CIrrDeviceLinux.h
|
||||
source/Irrlicht/CMeshCache.h
|
||||
source/Irrlicht/CAttributes.h
|
||||
source/Irrlicht/CParticleMeshEmitter.h
|
||||
source/Irrlicht/CImageWriterPPM.h
|
||||
source/Irrlicht/CParticlePointEmitter.h
|
||||
source/Irrlicht/CParticleRotationAffector.h
|
||||
source/Irrlicht/CMountPointReader.h
|
||||
source/Irrlicht/CIrrDeviceConsole.h
|
||||
source/Irrlicht/CTerrainSceneNode.h
|
||||
source/Irrlicht/CSceneNodeAnimatorCollisionResponse.h
|
||||
source/Irrlicht/CImageLoaderWAL.h
|
||||
source/Irrlicht/CImageLoaderBMP.h
|
||||
source/Irrlicht/CSkinnedMesh.h
|
||||
source/Irrlicht/COpenGLParallaxMapRenderer.h
|
||||
source/Irrlicht/CParticleRingEmitter.h
|
||||
source/Irrlicht/COpenGLShaderMaterialRenderer.h
|
||||
source/Irrlicht/CImageWriterTGA.h
|
||||
source/Irrlicht/CImageLoaderPNG.h
|
||||
source/Irrlicht/COctreeTriangleSelector.h
|
||||
source/Irrlicht/COpenGLTexture.h
|
||||
@ -229,7 +214,6 @@ source/Irrlicht/MacOSX/AppDelegate.h
|
||||
source/Irrlicht/MacOSX/CIrrDeviceMacOSX.h
|
||||
source/Irrlicht/MacOSX/OSXClipboard.h
|
||||
source/Irrlicht/CSceneManager.h
|
||||
source/Irrlicht/CImageLoaderPSD.h
|
||||
source/Irrlicht/COpenGLDriver.h
|
||||
source/Irrlicht/CGUIComboBox.h
|
||||
source/Irrlicht/CVolumeLightSceneNode.h
|
||||
@ -248,10 +232,8 @@ source/Irrlicht/CSphereSceneNode.h
|
||||
source/Irrlicht/CIrrDeviceStub.h
|
||||
source/Irrlicht/CDummyTransformationSceneNode.h
|
||||
source/Irrlicht/CParticleBoxEmitter.h
|
||||
source/Irrlicht/CShadowVolumeSceneNode.h
|
||||
source/Irrlicht/COctreeSceneNode.h
|
||||
source/Irrlicht/CReadFile.h
|
||||
source/Irrlicht/CImageLoaderDDS.h
|
||||
source/Irrlicht/COSOperator.h
|
||||
source/Irrlicht/CLightSceneNode.h
|
||||
source/Irrlicht/CParticleSphereEmitter.h
|
||||
@ -262,19 +244,15 @@ source/Irrlicht/CGUIEditBox.h
|
||||
source/Irrlicht/CGUISpriteBank.h
|
||||
source/Irrlicht/CSceneNodeAnimatorFlyStraight.h
|
||||
source/Irrlicht/COpenGLExtensionHandler.h
|
||||
source/Irrlicht/CImageWriterPSD.h
|
||||
source/Irrlicht/CGUIScrollBar.h
|
||||
source/Irrlicht/CImageLoaderPCX.h
|
||||
source/Irrlicht/CTriangleSelector.h
|
||||
source/Irrlicht/CParticleGravityAffector.h
|
||||
source/Irrlicht/CGUIModalScreen.h
|
||||
source/Irrlicht/CDefaultSceneNodeFactory.h
|
||||
source/Irrlicht/CImageLoaderPPM.h
|
||||
source/Irrlicht/CXMLReaderImpl.h
|
||||
source/Irrlicht/COpenGLMaterialRenderer.h
|
||||
source/Irrlicht/CVideoModeList.h
|
||||
source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.h
|
||||
source/Irrlicht/CImageLoaderTGA.h
|
||||
source/Irrlicht/CColorConverter.h
|
||||
source/Irrlicht/CWaterSurfaceSceneNode.h
|
||||
source/Irrlicht/SoftwareDriver2_compile_config.h
|
||||
@ -284,7 +262,6 @@ source/Irrlicht/CEmptySceneNode.h
|
||||
source/Irrlicht/CParticleSystemSceneNode.h
|
||||
source/Irrlicht/CImageWriterPNG.h
|
||||
source/Irrlicht/CParticleScaleAffector.h
|
||||
source/Irrlicht/CImageWriterPCX.h
|
||||
source/Irrlicht/CImageLoaderJPG.h
|
||||
source/Irrlicht/CBillboardSceneNode.h
|
||||
source/Irrlicht/CIrrDeviceSDL.h
|
||||
@ -304,7 +281,6 @@ source/Irrlicht/CGUIToolBar.h
|
||||
source/Irrlicht/CImageWriterJPG.h
|
||||
source/Irrlicht/IAttribute.h
|
||||
source/Irrlicht/CNullDriver.h
|
||||
source/Irrlicht/CImageLoaderRGB.h
|
||||
source/Irrlicht/CWriteFile.h
|
||||
source/Irrlicht/CSceneNodeAnimatorFollowSpline.h
|
||||
source/Irrlicht/glxext.h
|
||||
|
@ -94,27 +94,6 @@ namespace scene
|
||||
/** \return The importance of the animation: 1.f keeps the original animation, 0.f is no animation. */
|
||||
virtual f32 getAnimationStrength() const =0;
|
||||
|
||||
//! Creates shadow volume scene node as child of this node.
|
||||
/** The shadow can be rendered using the ZPass or the zfail
|
||||
method. ZPass is a little bit faster because the shadow volume
|
||||
creation is easier, but with this method there occur ugly
|
||||
looking artifacs when the camera is inside the shadow volume.
|
||||
These error do not occur with the ZFail method.
|
||||
\param shadowMesh: Optional custom mesh for shadow volume.
|
||||
\param id: Id of the shadow scene node. This id can be used to
|
||||
identify the node later.
|
||||
\param zfailmethod: If set to true, the shadow will use the
|
||||
zfail method, if not, zpass is used.
|
||||
\param infinity: Value used by the shadow volume algorithm to
|
||||
scale the shadow volume (for zfail shadow volume we support only
|
||||
finite shadows, so camera zfar must be larger than shadow back cap,
|
||||
which is depend on infinity parameter).
|
||||
\return Pointer to the created shadow scene node. This pointer
|
||||
should not be dropped. See IReferenceCounted::drop() for more
|
||||
information. */
|
||||
virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh=0,
|
||||
s32 id=-1, bool zfailmethod=true, f32 infinity=1000.0f) = 0;
|
||||
|
||||
|
||||
//! Get a pointer to a joint in the mesh (if the mesh is a bone based mesh).
|
||||
/** With this method it is possible to attach scene nodes to
|
||||
|
@ -38,27 +38,6 @@ public:
|
||||
/** \return Pointer to mesh which is displayed by this node. */
|
||||
virtual IMesh* getMesh(void) = 0;
|
||||
|
||||
//! Creates shadow volume scene node as child of this node.
|
||||
/** The shadow can be rendered using the ZPass or the zfail
|
||||
method. ZPass is a little bit faster because the shadow volume
|
||||
creation is easier, but with this method there occur ugly
|
||||
looking artifacs when the camera is inside the shadow volume.
|
||||
These error do not occur with the ZFail method.
|
||||
\param shadowMesh: Optional custom mesh for shadow volume.
|
||||
\param id: Id of the shadow scene node. This id can be used to
|
||||
identify the node later.
|
||||
\param zfailmethod: If set to true, the shadow will use the
|
||||
zfail method, if not, zpass is used.
|
||||
\param infinity: Value used by the shadow volume algorithm to
|
||||
scale the shadow volume (for zfail shadow volume we support only
|
||||
finite shadows, so camera zfar must be larger than shadow back cap,
|
||||
which is depend on infinity parameter).
|
||||
\return Pointer to the created shadow scene node. This pointer
|
||||
should not be dropped. See IReferenceCounted::drop() for more
|
||||
information. */
|
||||
virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh=0,
|
||||
s32 id=-1, bool zfailmethod=true, f32 infinity=1000.0f) = 0;
|
||||
|
||||
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
|
||||
/** In this way it is possible to change the materials of a mesh
|
||||
causing all mesh scene nodes referencing this mesh to change, too.
|
||||
|
@ -279,56 +279,11 @@ B3D, MS3D or X meshes */
|
||||
#ifdef NO_IRR_COMPILE_WITH_JPG_LOADER_
|
||||
#undef _IRR_COMPILE_WITH_JPG_LOADER_
|
||||
#endif
|
||||
//! Define _IRR_COMPILE_WITH_PCX_LOADER_ if you want to load .pcx files
|
||||
//#define _IRR_COMPILE_WITH_PCX_LOADER_
|
||||
#ifdef NO_IRR_COMPILE_WITH_PCX_LOADER_
|
||||
#undef _IRR_COMPILE_WITH_PCX_LOADER_
|
||||
#endif
|
||||
//! Define _IRR_COMPILE_WITH_PNG_LOADER_ if you want to load .png files
|
||||
#define _IRR_COMPILE_WITH_PNG_LOADER_
|
||||
#ifdef NO_IRR_COMPILE_WITH_PNG_LOADER_
|
||||
#undef _IRR_COMPILE_WITH_PNG_LOADER_
|
||||
#endif
|
||||
//! Define _IRR_COMPILE_WITH_PPM_LOADER_ if you want to load .ppm/.pgm/.pbm files
|
||||
//#define _IRR_COMPILE_WITH_PPM_LOADER_
|
||||
#ifdef NO_IRR_COMPILE_WITH_PPM_LOADER_
|
||||
#undef _IRR_COMPILE_WITH_PPM_LOADER_
|
||||
#endif
|
||||
//! Define _IRR_COMPILE_WITH_PSD_LOADER_ if you want to load .psd files
|
||||
//#define _IRR_COMPILE_WITH_PSD_LOADER_
|
||||
#ifdef NO_IRR_COMPILE_WITH_PSD_LOADER_
|
||||
#undef _IRR_COMPILE_WITH_PSD_LOADER_
|
||||
#endif
|
||||
//! Define _IRR_COMPILE_WITH_DDS_LOADER_ if you want to load .dds files
|
||||
// Outcommented because
|
||||
// a) it doesn't compile on 64-bit currently
|
||||
// b) anyone enabling it should be aware that S3TC compression algorithm which might be used in that loader
|
||||
// is patented in the US by S3 and they do collect license fees when it's used in applications.
|
||||
// So if you are unfortunate enough to develop applications for US market and their broken patent system be careful.
|
||||
// #define _IRR_COMPILE_WITH_DDS_LOADER_
|
||||
#ifdef NO_IRR_COMPILE_WITH_DDS_LOADER_
|
||||
#undef _IRR_COMPILE_WITH_DDS_LOADER_
|
||||
#endif
|
||||
//! Define _IRR_COMPILE_WITH_TGA_LOADER_ if you want to load .tga files
|
||||
#define _IRR_COMPILE_WITH_TGA_LOADER_
|
||||
#ifdef NO_IRR_COMPILE_WITH_TGA_LOADER_
|
||||
#undef _IRR_COMPILE_WITH_TGA_LOADER_
|
||||
#endif
|
||||
//! Define _IRR_COMPILE_WITH_WAL_LOADER_ if you want to load .wal files
|
||||
#define _IRR_COMPILE_WITH_WAL_LOADER_
|
||||
#ifdef NO_IRR_COMPILE_WITH_WAL_LOADER_
|
||||
#undef _IRR_COMPILE_WITH_WAL_LOADER_
|
||||
#endif
|
||||
//! Define _IRR_COMPILE_WITH_LMP_LOADER_ if you want to load .lmp files
|
||||
#define _IRR_COMPILE_WITH_LMP_LOADER_
|
||||
#ifdef NO_IRR_COMPILE_WITH_LMP_LOADER_
|
||||
#undef _IRR_COMPILE_WITH_LMP_LOADER_
|
||||
#endif
|
||||
//! Define _IRR_COMPILE_WITH_RGB_LOADER_ if you want to load Silicon Graphics .rgb/.rgba/.sgi/.int/.inta/.bw files
|
||||
#define _IRR_COMPILE_WITH_RGB_LOADER_
|
||||
#ifdef NO_IRR_COMPILE_WITH_RGB_LOADER_
|
||||
#undef _IRR_COMPILE_WITH_RGB_LOADER_
|
||||
#endif
|
||||
|
||||
//! Define _IRR_COMPILE_WITH_BMP_WRITER_ if you want to write .bmp files
|
||||
#define _IRR_COMPILE_WITH_BMP_WRITER_
|
||||
@ -340,31 +295,11 @@ B3D, MS3D or X meshes */
|
||||
#ifdef NO_IRR_COMPILE_WITH_JPG_WRITER_
|
||||
#undef _IRR_COMPILE_WITH_JPG_WRITER_
|
||||
#endif
|
||||
//! Define _IRR_COMPILE_WITH_PCX_WRITER_ if you want to write .pcx files
|
||||
//#define _IRR_COMPILE_WITH_PCX_WRITER_
|
||||
#ifdef NO_IRR_COMPILE_WITH_PCX_WRITER_
|
||||
#undef _IRR_COMPILE_WITH_PCX_WRITER_
|
||||
#endif
|
||||
//! Define _IRR_COMPILE_WITH_PNG_WRITER_ if you want to write .png files
|
||||
#define _IRR_COMPILE_WITH_PNG_WRITER_
|
||||
#ifdef NO_IRR_COMPILE_WITH_PNG_WRITER_
|
||||
#undef _IRR_COMPILE_WITH_PNG_WRITER_
|
||||
#endif
|
||||
//! Define _IRR_COMPILE_WITH_PPM_WRITER_ if you want to write .ppm files
|
||||
//#define _IRR_COMPILE_WITH_PPM_WRITER_
|
||||
#ifdef NO_IRR_COMPILE_WITH_PPM_WRITER_
|
||||
#undef _IRR_COMPILE_WITH_PPM_WRITER_
|
||||
#endif
|
||||
//! Define _IRR_COMPILE_WITH_PSD_WRITER_ if you want to write .psd files
|
||||
//#define _IRR_COMPILE_WITH_PSD_WRITER_
|
||||
#ifdef NO_IRR_COMPILE_WITH_PSD_WRITER_
|
||||
#undef _IRR_COMPILE_WITH_PSD_WRITER_
|
||||
#endif
|
||||
//! Define _IRR_COMPILE_WITH_TGA_WRITER_ if you want to write .tga files
|
||||
//#define _IRR_COMPILE_WITH_TGA_WRITER_
|
||||
#ifdef NO_IRR_COMPILE_WITH_TGA_WRITER_
|
||||
#undef _IRR_COMPILE_WITH_TGA_WRITER_
|
||||
#endif
|
||||
|
||||
//! Define __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_ if you want to open ZIP and GZIP archives
|
||||
/** ZIP reading has several more options below to configure. */
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "ISceneManager.h"
|
||||
#include "S3DVertex.h"
|
||||
#include "os.h"
|
||||
#include "CShadowVolumeSceneNode.h"
|
||||
#include "CSkinnedMesh.h"
|
||||
#include "IDummyTransformationSceneNode.h"
|
||||
#include "IBoneSceneNode.h"
|
||||
@ -37,7 +36,7 @@ CAnimatedMeshSceneNode::CAnimatedMeshSceneNode(IAnimatedMesh* mesh,
|
||||
TransitionTime(0), Transiting(0.f), TransitingBlend(0.f),
|
||||
JointMode(EJUOR_NONE), JointsUsed(false),
|
||||
Looping(true), ReadOnlyMaterials(false), RenderFromIdentity(false),
|
||||
LoopCallBack(0), PassCount(0), Shadow(0)
|
||||
LoopCallBack(0), PassCount(0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CAnimatedMeshSceneNode");
|
||||
@ -53,9 +52,6 @@ CAnimatedMeshSceneNode::~CAnimatedMeshSceneNode()
|
||||
if (Mesh)
|
||||
Mesh->drop();
|
||||
|
||||
if (Shadow)
|
||||
Shadow->drop();
|
||||
|
||||
if (LoopCallBack)
|
||||
LoopCallBack->drop();
|
||||
}
|
||||
@ -287,9 +283,6 @@ void CAnimatedMeshSceneNode::render()
|
||||
|
||||
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
|
||||
|
||||
if (Shadow && PassCount==1)
|
||||
Shadow->updateShadowVolumes();
|
||||
|
||||
// for debug purposes only:
|
||||
|
||||
bool renderMeshes = true;
|
||||
@ -523,23 +516,6 @@ u32 CAnimatedMeshSceneNode::getMaterialCount() const
|
||||
}
|
||||
|
||||
|
||||
//! Creates shadow volume scene node as child of this node
|
||||
//! and returns a pointer to it.
|
||||
IShadowVolumeSceneNode* CAnimatedMeshSceneNode::addShadowVolumeSceneNode(
|
||||
const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity)
|
||||
{
|
||||
if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER))
|
||||
return 0;
|
||||
|
||||
if (!shadowMesh)
|
||||
shadowMesh = Mesh; // if null is given, use the mesh of node
|
||||
|
||||
if (Shadow)
|
||||
Shadow->drop();
|
||||
|
||||
Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity);
|
||||
return Shadow;
|
||||
}
|
||||
|
||||
//! Returns a pointer to a child node, which has the same transformation as
|
||||
//! the corresponding joint, if the mesh in this scene node is a skinned mesh.
|
||||
@ -644,12 +620,6 @@ ISceneNode* CAnimatedMeshSceneNode::getXJointNode(const c8* jointName)
|
||||
//! or to remove attached childs.
|
||||
bool CAnimatedMeshSceneNode::removeChild(ISceneNode* child)
|
||||
{
|
||||
if (child && Shadow == child)
|
||||
{
|
||||
Shadow->drop();
|
||||
Shadow = 0;
|
||||
}
|
||||
|
||||
if (ISceneNode::removeChild(child))
|
||||
{
|
||||
if (JointsUsed) //stop weird bugs caused while changing parents as the joints are being created
|
||||
@ -1015,8 +985,6 @@ ISceneNode* CAnimatedMeshSceneNode::clone(ISceneNode* newParent, ISceneManager*
|
||||
newNode->ReadOnlyMaterials = ReadOnlyMaterials;
|
||||
newNode->LoopCallBack = LoopCallBack;
|
||||
newNode->PassCount = PassCount;
|
||||
newNode->Shadow = Shadow;
|
||||
newNode->Shadow->grab();
|
||||
newNode->JointChildSceneNodes = JointChildSceneNodes;
|
||||
newNode->PretransitingSave = PretransitingSave;
|
||||
newNode->RenderFromIdentity = RenderFromIdentity;
|
||||
|
@ -84,11 +84,6 @@ namespace scene
|
||||
//! returns amount of materials used by this scene node.
|
||||
virtual u32 getMaterialCount() const;
|
||||
|
||||
//! Creates shadow volume scene node as child of this node
|
||||
//! and returns a pointer to it.
|
||||
virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh,
|
||||
s32 id, bool zfailmethod=true, f32 infinity=1000.0f);
|
||||
|
||||
//! Returns a pointer to a child node, which has the same transformation as
|
||||
//! the corrsesponding joint, if the mesh in this scene node is a skinned mesh.
|
||||
virtual IBoneSceneNode* getJointNode(const c8* jointName);
|
||||
@ -199,8 +194,6 @@ namespace scene
|
||||
IAnimationEndCallBack* LoopCallBack;
|
||||
s32 PassCount;
|
||||
|
||||
IShadowVolumeSceneNode* Shadow;
|
||||
|
||||
core::array<IBoneSceneNode* > JointChildSceneNodes;
|
||||
core::array<core::matrix4> PretransitingSave;
|
||||
};
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "S3DVertex.h"
|
||||
#include "SMeshBuffer.h"
|
||||
#include "os.h"
|
||||
#include "CShadowVolumeSceneNode.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
@ -33,7 +32,7 @@ CCubeSceneNode::CCubeSceneNode(f32 size, ISceneNode* parent, ISceneManager* mgr,
|
||||
s32 id, const core::vector3df& position,
|
||||
const core::vector3df& rotation, const core::vector3df& scale)
|
||||
: IMeshSceneNode(parent, mgr, id, position, rotation, scale),
|
||||
Mesh(0), Shadow(0), Size(size)
|
||||
Mesh(0), Size(size)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CCubeSceneNode");
|
||||
@ -45,8 +44,6 @@ CCubeSceneNode::CCubeSceneNode(f32 size, ISceneNode* parent, ISceneManager* mgr,
|
||||
|
||||
CCubeSceneNode::~CCubeSceneNode()
|
||||
{
|
||||
if (Shadow)
|
||||
Shadow->drop();
|
||||
if (Mesh)
|
||||
Mesh->drop();
|
||||
}
|
||||
@ -66,9 +63,6 @@ void CCubeSceneNode::render()
|
||||
video::IVideoDriver* driver = SceneManager->getVideoDriver();
|
||||
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
|
||||
|
||||
if (Shadow)
|
||||
Shadow->updateShadowVolumes();
|
||||
|
||||
// for debug purposes only:
|
||||
video::SMaterial mat = Mesh->getMeshBuffer(0)->getMaterial();
|
||||
|
||||
@ -132,35 +126,10 @@ const core::aabbox3d<f32>& CCubeSceneNode::getBoundingBox() const
|
||||
//! or to remove attached childs.
|
||||
bool CCubeSceneNode::removeChild(ISceneNode* child)
|
||||
{
|
||||
if (child && Shadow == child)
|
||||
{
|
||||
Shadow->drop();
|
||||
Shadow = 0;
|
||||
}
|
||||
|
||||
return ISceneNode::removeChild(child);
|
||||
}
|
||||
|
||||
|
||||
//! Creates shadow volume scene node as child of this node
|
||||
//! and returns a pointer to it.
|
||||
IShadowVolumeSceneNode* CCubeSceneNode::addShadowVolumeSceneNode(
|
||||
const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity)
|
||||
{
|
||||
if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER))
|
||||
return 0;
|
||||
|
||||
if (!shadowMesh)
|
||||
shadowMesh = Mesh; // if null is given, use the mesh of node
|
||||
|
||||
if (Shadow)
|
||||
Shadow->drop();
|
||||
|
||||
Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity);
|
||||
return Shadow;
|
||||
}
|
||||
|
||||
|
||||
void CCubeSceneNode::OnRegisterSceneNode()
|
||||
{
|
||||
if (IsVisible)
|
||||
@ -220,8 +189,6 @@ ISceneNode* CCubeSceneNode::clone(ISceneNode* newParent, ISceneManager* newManag
|
||||
|
||||
nb->cloneMembers(this, newManager);
|
||||
nb->getMaterial(0) = getMaterial(0);
|
||||
nb->Shadow = Shadow;
|
||||
nb->Shadow->grab();
|
||||
|
||||
if ( newParent )
|
||||
nb->drop();
|
||||
|
@ -45,11 +45,6 @@ namespace scene
|
||||
//! Returns type of the scene node
|
||||
virtual ESCENE_NODE_TYPE getType() const { return ESNT_CUBE; }
|
||||
|
||||
//! Creates shadow volume scene node as child of this node
|
||||
//! and returns a pointer to it.
|
||||
virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh,
|
||||
s32 id, bool zfailmethod=true, f32 infinity=10000.0f);
|
||||
|
||||
//! Writes attributes of the scene node.
|
||||
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;
|
||||
|
||||
@ -82,7 +77,6 @@ namespace scene
|
||||
void setSize();
|
||||
|
||||
IMesh* Mesh;
|
||||
IShadowVolumeSceneNode* Shadow;
|
||||
f32 Size;
|
||||
};
|
||||
|
||||
|
@ -1,712 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Thomas Alten
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
/*
|
||||
Based on Code from Copyright (c) 2003 Randy Reddig
|
||||
Based on code from Nvidia's DDS example:
|
||||
http://www.nvidia.com/object/dxtc_decompression_code.html
|
||||
|
||||
mainly c to cpp
|
||||
*/
|
||||
|
||||
|
||||
#include "CImageLoaderDDS.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_DDS_LOADER_
|
||||
|
||||
#include "IReadFile.h"
|
||||
#include "os.h"
|
||||
#include "CColorConverter.h"
|
||||
#include "CImage.h"
|
||||
#include "irrString.h"
|
||||
|
||||
|
||||
namespace irr
|
||||
{
|
||||
|
||||
namespace video
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/*!
|
||||
DDSDecodePixelFormat()
|
||||
determines which pixel format the dds texture is in
|
||||
*/
|
||||
void DDSDecodePixelFormat( ddsBuffer *dds, eDDSPixelFormat *pf )
|
||||
{
|
||||
/* dummy check */
|
||||
if( dds == NULL || pf == NULL )
|
||||
return;
|
||||
|
||||
/* extract fourCC */
|
||||
const u32 fourCC = dds->pixelFormat.fourCC;
|
||||
|
||||
/* test it */
|
||||
if( fourCC == 0 )
|
||||
*pf = DDS_PF_ARGB8888;
|
||||
else if( fourCC == *((u32*) "DXT1") )
|
||||
*pf = DDS_PF_DXT1;
|
||||
else if( fourCC == *((u32*) "DXT2") )
|
||||
*pf = DDS_PF_DXT2;
|
||||
else if( fourCC == *((u32*) "DXT3") )
|
||||
*pf = DDS_PF_DXT3;
|
||||
else if( fourCC == *((u32*) "DXT4") )
|
||||
*pf = DDS_PF_DXT4;
|
||||
else if( fourCC == *((u32*) "DXT5") )
|
||||
*pf = DDS_PF_DXT5;
|
||||
else
|
||||
*pf = DDS_PF_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
DDSGetInfo()
|
||||
extracts relevant info from a dds texture, returns 0 on success
|
||||
*/
|
||||
s32 DDSGetInfo( ddsBuffer *dds, s32 *width, s32 *height, eDDSPixelFormat *pf )
|
||||
{
|
||||
/* dummy test */
|
||||
if( dds == NULL )
|
||||
return -1;
|
||||
|
||||
/* test dds header */
|
||||
if( *((s32*) dds->magic) != *((s32*) "DDS ") )
|
||||
return -1;
|
||||
if( DDSLittleLong( dds->size ) != 124 )
|
||||
return -1;
|
||||
|
||||
/* extract width and height */
|
||||
if( width != NULL )
|
||||
*width = DDSLittleLong( dds->width );
|
||||
if( height != NULL )
|
||||
*height = DDSLittleLong( dds->height );
|
||||
|
||||
/* get pixel format */
|
||||
DDSDecodePixelFormat( dds, pf );
|
||||
|
||||
/* return ok */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
DDSGetColorBlockColors()
|
||||
extracts colors from a dds color block
|
||||
*/
|
||||
void DDSGetColorBlockColors( ddsColorBlock *block, ddsColor colors[ 4 ] )
|
||||
{
|
||||
u16 word;
|
||||
|
||||
|
||||
/* color 0 */
|
||||
word = DDSLittleShort( block->colors[ 0 ] );
|
||||
colors[ 0 ].a = 0xff;
|
||||
|
||||
/* extract rgb bits */
|
||||
colors[ 0 ].b = (u8) word;
|
||||
colors[ 0 ].b <<= 3;
|
||||
colors[ 0 ].b |= (colors[ 0 ].b >> 5);
|
||||
word >>= 5;
|
||||
colors[ 0 ].g = (u8) word;
|
||||
colors[ 0 ].g <<= 2;
|
||||
colors[ 0 ].g |= (colors[ 0 ].g >> 5);
|
||||
word >>= 6;
|
||||
colors[ 0 ].r = (u8) word;
|
||||
colors[ 0 ].r <<= 3;
|
||||
colors[ 0 ].r |= (colors[ 0 ].r >> 5);
|
||||
|
||||
/* same for color 1 */
|
||||
word = DDSLittleShort( block->colors[ 1 ] );
|
||||
colors[ 1 ].a = 0xff;
|
||||
|
||||
/* extract rgb bits */
|
||||
colors[ 1 ].b = (u8) word;
|
||||
colors[ 1 ].b <<= 3;
|
||||
colors[ 1 ].b |= (colors[ 1 ].b >> 5);
|
||||
word >>= 5;
|
||||
colors[ 1 ].g = (u8) word;
|
||||
colors[ 1 ].g <<= 2;
|
||||
colors[ 1 ].g |= (colors[ 1 ].g >> 5);
|
||||
word >>= 6;
|
||||
colors[ 1 ].r = (u8) word;
|
||||
colors[ 1 ].r <<= 3;
|
||||
colors[ 1 ].r |= (colors[ 1 ].r >> 5);
|
||||
|
||||
/* use this for all but the super-freak math method */
|
||||
if( block->colors[ 0 ] > block->colors[ 1 ] )
|
||||
{
|
||||
/* four-color block: derive the other two colors.
|
||||
00 = color 0, 01 = color 1, 10 = color 2, 11 = color 3
|
||||
these two bit codes correspond to the 2-bit fields
|
||||
stored in the 64-bit block. */
|
||||
|
||||
word = ((u16) colors[ 0 ].r * 2 + (u16) colors[ 1 ].r ) / 3;
|
||||
/* no +1 for rounding */
|
||||
/* as bits have been shifted to 888 */
|
||||
colors[ 2 ].r = (u8) word;
|
||||
word = ((u16) colors[ 0 ].g * 2 + (u16) colors[ 1 ].g) / 3;
|
||||
colors[ 2 ].g = (u8) word;
|
||||
word = ((u16) colors[ 0 ].b * 2 + (u16) colors[ 1 ].b) / 3;
|
||||
colors[ 2 ].b = (u8) word;
|
||||
colors[ 2 ].a = 0xff;
|
||||
|
||||
word = ((u16) colors[ 0 ].r + (u16) colors[ 1 ].r * 2) / 3;
|
||||
colors[ 3 ].r = (u8) word;
|
||||
word = ((u16) colors[ 0 ].g + (u16) colors[ 1 ].g * 2) / 3;
|
||||
colors[ 3 ].g = (u8) word;
|
||||
word = ((u16) colors[ 0 ].b + (u16) colors[ 1 ].b * 2) / 3;
|
||||
colors[ 3 ].b = (u8) word;
|
||||
colors[ 3 ].a = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* three-color block: derive the other color.
|
||||
00 = color 0, 01 = color 1, 10 = color 2,
|
||||
11 = transparent.
|
||||
These two bit codes correspond to the 2-bit fields
|
||||
stored in the 64-bit block */
|
||||
|
||||
word = ((u16) colors[ 0 ].r + (u16) colors[ 1 ].r) / 2;
|
||||
colors[ 2 ].r = (u8) word;
|
||||
word = ((u16) colors[ 0 ].g + (u16) colors[ 1 ].g) / 2;
|
||||
colors[ 2 ].g = (u8) word;
|
||||
word = ((u16) colors[ 0 ].b + (u16) colors[ 1 ].b) / 2;
|
||||
colors[ 2 ].b = (u8) word;
|
||||
colors[ 2 ].a = 0xff;
|
||||
|
||||
/* random color to indicate alpha */
|
||||
colors[ 3 ].r = 0x00;
|
||||
colors[ 3 ].g = 0xff;
|
||||
colors[ 3 ].b = 0xff;
|
||||
colors[ 3 ].a = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DDSDecodeColorBlock()
|
||||
decodes a dds color block
|
||||
fixme: make endian-safe
|
||||
*/
|
||||
|
||||
void DDSDecodeColorBlock( u32 *pixel, ddsColorBlock *block, s32 width, u32 colors[ 4 ] )
|
||||
{
|
||||
s32 r, n;
|
||||
u32 bits;
|
||||
u32 masks[] = { 3, 12, 3 << 4, 3 << 6 }; /* bit masks = 00000011, 00001100, 00110000, 11000000 */
|
||||
s32 shift[] = { 0, 2, 4, 6 };
|
||||
|
||||
|
||||
/* r steps through lines in y */
|
||||
for( r = 0; r < 4; r++, pixel += (width - 4) ) /* no width * 4 as u32 ptr inc will * 4 */
|
||||
{
|
||||
/* width * 4 bytes per pixel per line, each j dxtc row is 4 lines of pixels */
|
||||
|
||||
/* n steps through pixels */
|
||||
for( n = 0; n < 4; n++ )
|
||||
{
|
||||
bits = block->row[ r ] & masks[ n ];
|
||||
bits >>= shift[ n ];
|
||||
|
||||
switch( bits )
|
||||
{
|
||||
case 0:
|
||||
*pixel = colors[ 0 ];
|
||||
pixel++;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
*pixel = colors[ 1 ];
|
||||
pixel++;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
*pixel = colors[ 2 ];
|
||||
pixel++;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
*pixel = colors[ 3 ];
|
||||
pixel++;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* invalid */
|
||||
pixel++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DDSDecodeAlphaExplicit()
|
||||
decodes a dds explicit alpha block
|
||||
*/
|
||||
void DDSDecodeAlphaExplicit( u32 *pixel, ddsAlphaBlockExplicit *alphaBlock, s32 width, u32 alphaZero )
|
||||
{
|
||||
s32 row, pix;
|
||||
u16 word;
|
||||
ddsColor color;
|
||||
|
||||
|
||||
/* clear color */
|
||||
color.r = 0;
|
||||
color.g = 0;
|
||||
color.b = 0;
|
||||
|
||||
/* walk rows */
|
||||
for( row = 0; row < 4; row++, pixel += (width - 4) )
|
||||
{
|
||||
word = DDSLittleShort( alphaBlock->row[ row ] );
|
||||
|
||||
/* walk pixels */
|
||||
for( pix = 0; pix < 4; pix++ )
|
||||
{
|
||||
/* zero the alpha bits of image pixel */
|
||||
*pixel &= alphaZero;
|
||||
color.a = word & 0x000F;
|
||||
color.a = color.a | (color.a << 4);
|
||||
*pixel |= *((u32*) &color);
|
||||
word >>= 4; /* move next bits to lowest 4 */
|
||||
pixel++; /* move to next pixel in the row */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
DDSDecodeAlpha3BitLinear()
|
||||
decodes interpolated alpha block
|
||||
*/
|
||||
void DDSDecodeAlpha3BitLinear( u32 *pixel, ddsAlphaBlock3BitLinear *alphaBlock, s32 width, u32 alphaZero )
|
||||
{
|
||||
|
||||
s32 row, pix;
|
||||
u32 stuff;
|
||||
u8 bits[ 4 ][ 4 ];
|
||||
u16 alphas[ 8 ];
|
||||
ddsColor aColors[ 4 ][ 4 ];
|
||||
|
||||
/* get initial alphas */
|
||||
alphas[ 0 ] = alphaBlock->alpha0;
|
||||
alphas[ 1 ] = alphaBlock->alpha1;
|
||||
|
||||
/* 8-alpha block */
|
||||
if( alphas[ 0 ] > alphas[ 1 ] )
|
||||
{
|
||||
/* 000 = alpha_0, 001 = alpha_1, others are interpolated */
|
||||
alphas[ 2 ] = ( 6 * alphas[ 0 ] + alphas[ 1 ]) / 7; /* bit code 010 */
|
||||
alphas[ 3 ] = ( 5 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 7; /* bit code 011 */
|
||||
alphas[ 4 ] = ( 4 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 7; /* bit code 100 */
|
||||
alphas[ 5 ] = ( 3 * alphas[ 0 ] + 4 * alphas[ 1 ]) / 7; /* bit code 101 */
|
||||
alphas[ 6 ] = ( 2 * alphas[ 0 ] + 5 * alphas[ 1 ]) / 7; /* bit code 110 */
|
||||
alphas[ 7 ] = ( alphas[ 0 ] + 6 * alphas[ 1 ]) / 7; /* bit code 111 */
|
||||
}
|
||||
|
||||
/* 6-alpha block */
|
||||
else
|
||||
{
|
||||
/* 000 = alpha_0, 001 = alpha_1, others are interpolated */
|
||||
alphas[ 2 ] = (4 * alphas[ 0 ] + alphas[ 1 ]) / 5; /* bit code 010 */
|
||||
alphas[ 3 ] = (3 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 5; /* bit code 011 */
|
||||
alphas[ 4 ] = (2 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 5; /* bit code 100 */
|
||||
alphas[ 5 ] = ( alphas[ 0 ] + 4 * alphas[ 1 ]) / 5; /* bit code 101 */
|
||||
alphas[ 6 ] = 0; /* bit code 110 */
|
||||
alphas[ 7 ] = 255; /* bit code 111 */
|
||||
}
|
||||
|
||||
/* decode 3-bit fields into array of 16 bytes with same value */
|
||||
|
||||
/* first two rows of 4 pixels each */
|
||||
stuff = *((u32*) &(alphaBlock->stuff[ 0 ]));
|
||||
|
||||
bits[ 0 ][ 0 ] = (u8) (stuff & 0x00000007);
|
||||
stuff >>= 3;
|
||||
bits[ 0 ][ 1 ] = (u8) (stuff & 0x00000007);
|
||||
stuff >>= 3;
|
||||
bits[ 0 ][ 2 ] = (u8) (stuff & 0x00000007);
|
||||
stuff >>= 3;
|
||||
bits[ 0 ][ 3 ] = (u8) (stuff & 0x00000007);
|
||||
stuff >>= 3;
|
||||
bits[ 1 ][ 0 ] = (u8) (stuff & 0x00000007);
|
||||
stuff >>= 3;
|
||||
bits[ 1 ][ 1 ] = (u8) (stuff & 0x00000007);
|
||||
stuff >>= 3;
|
||||
bits[ 1 ][ 2 ] = (u8) (stuff & 0x00000007);
|
||||
stuff >>= 3;
|
||||
bits[ 1 ][ 3 ] = (u8) (stuff & 0x00000007);
|
||||
|
||||
/* last two rows */
|
||||
stuff = *((u32*) &(alphaBlock->stuff[ 3 ])); /* last 3 bytes */
|
||||
|
||||
bits[ 2 ][ 0 ] = (u8) (stuff & 0x00000007);
|
||||
stuff >>= 3;
|
||||
bits[ 2 ][ 1 ] = (u8) (stuff & 0x00000007);
|
||||
stuff >>= 3;
|
||||
bits[ 2 ][ 2 ] = (u8) (stuff & 0x00000007);
|
||||
stuff >>= 3;
|
||||
bits[ 2 ][ 3 ] = (u8) (stuff & 0x00000007);
|
||||
stuff >>= 3;
|
||||
bits[ 3 ][ 0 ] = (u8) (stuff & 0x00000007);
|
||||
stuff >>= 3;
|
||||
bits[ 3 ][ 1 ] = (u8) (stuff & 0x00000007);
|
||||
stuff >>= 3;
|
||||
bits[ 3 ][ 2 ] = (u8) (stuff & 0x00000007);
|
||||
stuff >>= 3;
|
||||
bits[ 3 ][ 3 ] = (u8) (stuff & 0x00000007);
|
||||
|
||||
/* decode the codes into alpha values */
|
||||
for( row = 0; row < 4; row++ )
|
||||
{
|
||||
for( pix=0; pix < 4; pix++ )
|
||||
{
|
||||
aColors[ row ][ pix ].r = 0;
|
||||
aColors[ row ][ pix ].g = 0;
|
||||
aColors[ row ][ pix ].b = 0;
|
||||
aColors[ row ][ pix ].a = (u8) alphas[ bits[ row ][ pix ] ];
|
||||
}
|
||||
}
|
||||
|
||||
/* write out alpha values to the image bits */
|
||||
for( row = 0; row < 4; row++, pixel += width-4 )
|
||||
{
|
||||
for( pix = 0; pix < 4; pix++ )
|
||||
{
|
||||
/* zero the alpha bits of image pixel */
|
||||
*pixel &= alphaZero;
|
||||
|
||||
/* or the bits into the prev. nulled alpha */
|
||||
*pixel |= *((u32*) &(aColors[ row ][ pix ]));
|
||||
pixel++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DDSDecompressDXT1()
|
||||
decompresses a dxt1 format texture
|
||||
*/
|
||||
s32 DDSDecompressDXT1( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
|
||||
{
|
||||
s32 x, y, xBlocks, yBlocks;
|
||||
u32 *pixel;
|
||||
ddsColorBlock *block;
|
||||
ddsColor colors[ 4 ];
|
||||
|
||||
/* setup */
|
||||
xBlocks = width / 4;
|
||||
yBlocks = height / 4;
|
||||
|
||||
/* walk y */
|
||||
for( y = 0; y < yBlocks; y++ )
|
||||
{
|
||||
/* 8 bytes per block */
|
||||
block = (ddsColorBlock*) (dds->data + y * xBlocks * 8);
|
||||
|
||||
/* walk x */
|
||||
for( x = 0; x < xBlocks; x++, block++ )
|
||||
{
|
||||
DDSGetColorBlockColors( block, colors );
|
||||
pixel = (u32*) (pixels + x * 16 + (y * 4) * width * 4);
|
||||
DDSDecodeColorBlock( pixel, block, width, (u32*) colors );
|
||||
}
|
||||
}
|
||||
|
||||
/* return ok */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DDSDecompressDXT3()
|
||||
decompresses a dxt3 format texture
|
||||
*/
|
||||
|
||||
s32 DDSDecompressDXT3( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
|
||||
{
|
||||
s32 x, y, xBlocks, yBlocks;
|
||||
u32 *pixel, alphaZero;
|
||||
ddsColorBlock *block;
|
||||
ddsAlphaBlockExplicit *alphaBlock;
|
||||
ddsColor colors[ 4 ];
|
||||
|
||||
/* setup */
|
||||
xBlocks = width / 4;
|
||||
yBlocks = height / 4;
|
||||
|
||||
/* create zero alpha */
|
||||
colors[ 0 ].a = 0;
|
||||
colors[ 0 ].r = 0xFF;
|
||||
colors[ 0 ].g = 0xFF;
|
||||
colors[ 0 ].b = 0xFF;
|
||||
alphaZero = *((u32*) &colors[ 0 ]);
|
||||
|
||||
/* walk y */
|
||||
for( y = 0; y < yBlocks; y++ )
|
||||
{
|
||||
/* 8 bytes per block, 1 block for alpha, 1 block for color */
|
||||
block = (ddsColorBlock*) (dds->data + y * xBlocks * 16);
|
||||
|
||||
/* walk x */
|
||||
for( x = 0; x < xBlocks; x++, block++ )
|
||||
{
|
||||
/* get alpha block */
|
||||
alphaBlock = (ddsAlphaBlockExplicit*) block;
|
||||
|
||||
/* get color block */
|
||||
block++;
|
||||
DDSGetColorBlockColors( block, colors );
|
||||
|
||||
/* decode color block */
|
||||
pixel = (u32*) (pixels + x * 16 + (y * 4) * width * 4);
|
||||
DDSDecodeColorBlock( pixel, block, width, (u32*) colors );
|
||||
|
||||
/* overwrite alpha bits with alpha block */
|
||||
DDSDecodeAlphaExplicit( pixel, alphaBlock, width, alphaZero );
|
||||
}
|
||||
}
|
||||
|
||||
/* return ok */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DDSDecompressDXT5()
|
||||
decompresses a dxt5 format texture
|
||||
*/
|
||||
s32 DDSDecompressDXT5( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
|
||||
{
|
||||
s32 x, y, xBlocks, yBlocks;
|
||||
u32 *pixel, alphaZero;
|
||||
ddsColorBlock *block;
|
||||
ddsAlphaBlock3BitLinear *alphaBlock;
|
||||
ddsColor colors[ 4 ];
|
||||
|
||||
/* setup */
|
||||
xBlocks = width / 4;
|
||||
yBlocks = height / 4;
|
||||
|
||||
/* create zero alpha */
|
||||
colors[ 0 ].a = 0;
|
||||
colors[ 0 ].r = 0xFF;
|
||||
colors[ 0 ].g = 0xFF;
|
||||
colors[ 0 ].b = 0xFF;
|
||||
alphaZero = *((u32*) &colors[ 0 ]);
|
||||
|
||||
/* walk y */
|
||||
for( y = 0; y < yBlocks; y++ )
|
||||
{
|
||||
/* 8 bytes per block, 1 block for alpha, 1 block for color */
|
||||
block = (ddsColorBlock*) (dds->data + y * xBlocks * 16);
|
||||
|
||||
/* walk x */
|
||||
for( x = 0; x < xBlocks; x++, block++ )
|
||||
{
|
||||
/* get alpha block */
|
||||
alphaBlock = (ddsAlphaBlock3BitLinear*) block;
|
||||
|
||||
/* get color block */
|
||||
block++;
|
||||
DDSGetColorBlockColors( block, colors );
|
||||
|
||||
/* decode color block */
|
||||
pixel = (u32*) (pixels + x * 16 + (y * 4) * width * 4);
|
||||
DDSDecodeColorBlock( pixel, block, width, (u32*) colors );
|
||||
|
||||
/* overwrite alpha bits with alpha block */
|
||||
DDSDecodeAlpha3BitLinear( pixel, alphaBlock, width, alphaZero );
|
||||
}
|
||||
}
|
||||
|
||||
/* return ok */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DDSDecompressDXT2()
|
||||
decompresses a dxt2 format texture (fixme: un-premultiply alpha)
|
||||
*/
|
||||
s32 DDSDecompressDXT2( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
|
||||
{
|
||||
/* decompress dxt3 first */
|
||||
const s32 r = DDSDecompressDXT3( dds, width, height, pixels );
|
||||
|
||||
/* return to sender */
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DDSDecompressDXT4()
|
||||
decompresses a dxt4 format texture (fixme: un-premultiply alpha)
|
||||
*/
|
||||
s32 DDSDecompressDXT4( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
|
||||
{
|
||||
/* decompress dxt5 first */
|
||||
const s32 r = DDSDecompressDXT5( dds, width, height, pixels );
|
||||
|
||||
/* return to sender */
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DDSDecompressARGB8888()
|
||||
decompresses an argb 8888 format texture
|
||||
*/
|
||||
s32 DDSDecompressARGB8888( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
|
||||
{
|
||||
/* setup */
|
||||
u8* in = dds->data;
|
||||
u8* out = pixels;
|
||||
|
||||
/* walk y */
|
||||
for(s32 y = 0; y < height; y++)
|
||||
{
|
||||
/* walk x */
|
||||
for(s32 x = 0; x < width; x++)
|
||||
{
|
||||
*out++ = *in++;
|
||||
*out++ = *in++;
|
||||
*out++ = *in++;
|
||||
*out++ = *in++;
|
||||
}
|
||||
}
|
||||
|
||||
/* return ok */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DDSDecompress()
|
||||
decompresses a dds texture into an rgba image buffer, returns 0 on success
|
||||
*/
|
||||
s32 DDSDecompress( ddsBuffer *dds, u8 *pixels )
|
||||
{
|
||||
s32 width, height;
|
||||
eDDSPixelFormat pf;
|
||||
|
||||
/* get dds info */
|
||||
s32 r = DDSGetInfo( dds, &width, &height, &pf );
|
||||
if ( r )
|
||||
return r;
|
||||
|
||||
/* decompress */
|
||||
switch( pf )
|
||||
{
|
||||
case DDS_PF_ARGB8888:
|
||||
/* fixme: support other [a]rgb formats */
|
||||
r = DDSDecompressARGB8888( dds, width, height, pixels );
|
||||
break;
|
||||
|
||||
case DDS_PF_DXT1:
|
||||
r = DDSDecompressDXT1( dds, width, height, pixels );
|
||||
break;
|
||||
|
||||
case DDS_PF_DXT2:
|
||||
r = DDSDecompressDXT2( dds, width, height, pixels );
|
||||
break;
|
||||
|
||||
case DDS_PF_DXT3:
|
||||
r = DDSDecompressDXT3( dds, width, height, pixels );
|
||||
break;
|
||||
|
||||
case DDS_PF_DXT4:
|
||||
r = DDSDecompressDXT4( dds, width, height, pixels );
|
||||
break;
|
||||
|
||||
case DDS_PF_DXT5:
|
||||
r = DDSDecompressDXT5( dds, width, height, pixels );
|
||||
break;
|
||||
|
||||
default:
|
||||
case DDS_PF_UNKNOWN:
|
||||
memset( pixels, 0xFF, width * height * 4 );
|
||||
r = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* return to sender */
|
||||
return r;
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".tga")
|
||||
bool CImageLoaderDDS::isALoadableFileExtension(const io::path& filename) const
|
||||
{
|
||||
return core::hasFileExtension ( filename, "dds" );
|
||||
}
|
||||
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
bool CImageLoaderDDS::isALoadableFileFormat(io::IReadFile* file) const
|
||||
{
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
ddsBuffer header;
|
||||
file->read(&header, sizeof(header));
|
||||
|
||||
s32 width, height;
|
||||
eDDSPixelFormat pixelFormat;
|
||||
|
||||
return (0 == DDSGetInfo( &header, &width, &height, &pixelFormat));
|
||||
}
|
||||
|
||||
|
||||
//! creates a surface from the file
|
||||
IImage* CImageLoaderDDS::loadImage(io::IReadFile* file) const
|
||||
{
|
||||
u8 *memFile = new u8 [ file->getSize() ];
|
||||
file->read ( memFile, file->getSize() );
|
||||
|
||||
ddsBuffer *header = (ddsBuffer*) memFile;
|
||||
IImage* image = 0;
|
||||
s32 width, height;
|
||||
eDDSPixelFormat pixelFormat;
|
||||
|
||||
if ( 0 == DDSGetInfo( header, &width, &height, &pixelFormat) )
|
||||
{
|
||||
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height));
|
||||
|
||||
if ( DDSDecompress( header, (u8*) image->lock() ) == -1)
|
||||
{
|
||||
image->unlock();
|
||||
image->drop();
|
||||
image = 0;
|
||||
}
|
||||
}
|
||||
|
||||
delete [] memFile;
|
||||
if ( image )
|
||||
image->unlock();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
//! creates a loader which is able to load dds images
|
||||
IImageLoader* createImageLoaderDDS()
|
||||
{
|
||||
return new CImageLoaderDDS();
|
||||
}
|
||||
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
||||
|
@ -1,296 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Thomas Alten
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef __C_IMAGE_LOADER_DDS_H_INCLUDED__
|
||||
#define __C_IMAGE_LOADER_DDS_H_INCLUDED__
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_DDS_LOADER_)
|
||||
|
||||
#include "IImageLoader.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
/* dependencies */
|
||||
/* dds definition */
|
||||
enum eDDSPixelFormat
|
||||
{
|
||||
DDS_PF_ARGB8888,
|
||||
DDS_PF_DXT1,
|
||||
DDS_PF_DXT2,
|
||||
DDS_PF_DXT3,
|
||||
DDS_PF_DXT4,
|
||||
DDS_PF_DXT5,
|
||||
DDS_PF_UNKNOWN
|
||||
};
|
||||
|
||||
/* 16bpp stuff */
|
||||
#define DDS_LOW_5 0x001F;
|
||||
#define DDS_MID_6 0x07E0;
|
||||
#define DDS_HIGH_5 0xF800;
|
||||
#define DDS_MID_555 0x03E0;
|
||||
#define DDS_HI_555 0x7C00;
|
||||
|
||||
|
||||
// byte-align structures
|
||||
#include "irrpack.h"
|
||||
|
||||
/* structures */
|
||||
struct ddsColorKey
|
||||
{
|
||||
u32 colorSpaceLowValue;
|
||||
u32 colorSpaceHighValue;
|
||||
} PACK_STRUCT;
|
||||
|
||||
struct ddsCaps
|
||||
{
|
||||
u32 caps1;
|
||||
u32 caps2;
|
||||
u32 caps3;
|
||||
u32 caps4;
|
||||
} PACK_STRUCT;
|
||||
|
||||
struct ddsMultiSampleCaps
|
||||
{
|
||||
u16 flipMSTypes;
|
||||
u16 bltMSTypes;
|
||||
} PACK_STRUCT;
|
||||
|
||||
|
||||
struct ddsPixelFormat
|
||||
{
|
||||
u32 size;
|
||||
u32 flags;
|
||||
u32 fourCC;
|
||||
union
|
||||
{
|
||||
u32 rgbBitCount;
|
||||
u32 yuvBitCount;
|
||||
u32 zBufferBitDepth;
|
||||
u32 alphaBitDepth;
|
||||
u32 luminanceBitCount;
|
||||
u32 bumpBitCount;
|
||||
u32 privateFormatBitCount;
|
||||
};
|
||||
union
|
||||
{
|
||||
u32 rBitMask;
|
||||
u32 yBitMask;
|
||||
u32 stencilBitDepth;
|
||||
u32 luminanceBitMask;
|
||||
u32 bumpDuBitMask;
|
||||
u32 operations;
|
||||
};
|
||||
union
|
||||
{
|
||||
u32 gBitMask;
|
||||
u32 uBitMask;
|
||||
u32 zBitMask;
|
||||
u32 bumpDvBitMask;
|
||||
ddsMultiSampleCaps multiSampleCaps;
|
||||
};
|
||||
union
|
||||
{
|
||||
u32 bBitMask;
|
||||
u32 vBitMask;
|
||||
u32 stencilBitMask;
|
||||
u32 bumpLuminanceBitMask;
|
||||
};
|
||||
union
|
||||
{
|
||||
u32 rgbAlphaBitMask;
|
||||
u32 yuvAlphaBitMask;
|
||||
u32 luminanceAlphaBitMask;
|
||||
u32 rgbZBitMask;
|
||||
u32 yuvZBitMask;
|
||||
};
|
||||
} PACK_STRUCT;
|
||||
|
||||
|
||||
struct ddsBuffer
|
||||
{
|
||||
/* magic: 'dds ' */
|
||||
c8 magic[ 4 ];
|
||||
|
||||
/* directdraw surface */
|
||||
u32 size;
|
||||
u32 flags;
|
||||
u32 height;
|
||||
u32 width;
|
||||
union
|
||||
{
|
||||
s32 pitch;
|
||||
u32 linearSize;
|
||||
};
|
||||
u32 backBufferCount;
|
||||
union
|
||||
{
|
||||
u32 mipMapCount;
|
||||
u32 refreshRate;
|
||||
u32 srcVBHandle;
|
||||
};
|
||||
u32 alphaBitDepth;
|
||||
u32 reserved;
|
||||
void *surface;
|
||||
union
|
||||
{
|
||||
ddsColorKey ckDestOverlay;
|
||||
u32 emptyFaceColor;
|
||||
};
|
||||
ddsColorKey ckDestBlt;
|
||||
ddsColorKey ckSrcOverlay;
|
||||
ddsColorKey ckSrcBlt;
|
||||
union
|
||||
{
|
||||
ddsPixelFormat pixelFormat;
|
||||
u32 fvf;
|
||||
};
|
||||
ddsCaps caps;
|
||||
u32 textureStage;
|
||||
|
||||
/* data (Varying size) */
|
||||
u8 data[ 4 ];
|
||||
} PACK_STRUCT;
|
||||
|
||||
|
||||
struct ddsColorBlock
|
||||
{
|
||||
u16 colors[ 2 ];
|
||||
u8 row[ 4 ];
|
||||
} PACK_STRUCT;
|
||||
|
||||
|
||||
struct ddsAlphaBlockExplicit
|
||||
{
|
||||
u16 row[ 4 ];
|
||||
} PACK_STRUCT;
|
||||
|
||||
|
||||
struct ddsAlphaBlock3BitLinear
|
||||
{
|
||||
u8 alpha0;
|
||||
u8 alpha1;
|
||||
u8 stuff[ 6 ];
|
||||
} PACK_STRUCT;
|
||||
|
||||
|
||||
struct ddsColor
|
||||
{
|
||||
u8 r, g, b, a;
|
||||
} PACK_STRUCT;
|
||||
|
||||
// Default alignment
|
||||
#include "irrunpack.h"
|
||||
|
||||
|
||||
/* endian tomfoolery */
|
||||
typedef union
|
||||
{
|
||||
f32 f;
|
||||
c8 c[ 4 ];
|
||||
}
|
||||
floatSwapUnion;
|
||||
|
||||
|
||||
#ifndef __BIG_ENDIAN__
|
||||
#ifdef _SGI_SOURCE
|
||||
#define __BIG_ENDIAN__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
|
||||
s32 DDSBigLong( s32 src ) { return src; }
|
||||
s16 DDSBigShort( s16 src ) { return src; }
|
||||
f32 DDSBigFloat( f32 src ) { return src; }
|
||||
|
||||
s32 DDSLittleLong( s32 src )
|
||||
{
|
||||
return ((src & 0xFF000000) >> 24) |
|
||||
((src & 0x00FF0000) >> 8) |
|
||||
((src & 0x0000FF00) << 8) |
|
||||
((src & 0x000000FF) << 24);
|
||||
}
|
||||
|
||||
s16 DDSLittleShort( s16 src )
|
||||
{
|
||||
return ((src & 0xFF00) >> 8) |
|
||||
((src & 0x00FF) << 8);
|
||||
}
|
||||
|
||||
f32 DDSLittleFloat( f32 src )
|
||||
{
|
||||
floatSwapUnion in,out;
|
||||
in.f = src;
|
||||
out.c[ 0 ] = in.c[ 3 ];
|
||||
out.c[ 1 ] = in.c[ 2 ];
|
||||
out.c[ 2 ] = in.c[ 1 ];
|
||||
out.c[ 3 ] = in.c[ 0 ];
|
||||
return out.f;
|
||||
}
|
||||
|
||||
#else /*__BIG_ENDIAN__*/
|
||||
|
||||
s32 DDSLittleLong( s32 src ) { return src; }
|
||||
s16 DDSLittleShort( s16 src ) { return src; }
|
||||
f32 DDSLittleFloat( f32 src ) { return src; }
|
||||
|
||||
s32 DDSBigLong( s32 src )
|
||||
{
|
||||
return ((src & 0xFF000000) >> 24) |
|
||||
((src & 0x00FF0000) >> 8) |
|
||||
((src & 0x0000FF00) << 8) |
|
||||
((src & 0x000000FF) << 24);
|
||||
}
|
||||
|
||||
s16 DDSBigShort( s16 src )
|
||||
{
|
||||
return ((src & 0xFF00) >> 8) |
|
||||
((src & 0x00FF) << 8);
|
||||
}
|
||||
|
||||
f32 DDSBigFloat( f32 src )
|
||||
{
|
||||
floatSwapUnion in,out;
|
||||
in.f = src;
|
||||
out.c[ 0 ] = in.c[ 3 ];
|
||||
out.c[ 1 ] = in.c[ 2 ];
|
||||
out.c[ 2 ] = in.c[ 1 ];
|
||||
out.c[ 3 ] = in.c[ 0 ];
|
||||
return out.f;
|
||||
}
|
||||
|
||||
#endif /*__BIG_ENDIAN__*/
|
||||
|
||||
|
||||
/*!
|
||||
Surface Loader for DDS images
|
||||
*/
|
||||
class CImageLoaderDDS : public IImageLoader
|
||||
{
|
||||
public:
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".tga")
|
||||
virtual bool isALoadableFileExtension(const io::path& filename) const;
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
virtual bool isALoadableFileFormat(io::IReadFile* file) const;
|
||||
|
||||
//! creates a surface from the file
|
||||
virtual IImage* loadImage(io::IReadFile* file) const;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
#endif // compiled with DDS loader
|
||||
#endif
|
||||
|
@ -1,231 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "CImageLoaderPCX.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_PCX_LOADER_
|
||||
|
||||
#include "IReadFile.h"
|
||||
#include "SColor.h"
|
||||
#include "CColorConverter.h"
|
||||
#include "CImage.h"
|
||||
#include "os.h"
|
||||
#include "irrString.h"
|
||||
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
|
||||
//! constructor
|
||||
CImageLoaderPCX::CImageLoaderPCX()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CImageLoaderPCX");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".tga")
|
||||
bool CImageLoaderPCX::isALoadableFileExtension(const io::path& filename) const
|
||||
{
|
||||
return core::hasFileExtension ( filename, "pcx" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
bool CImageLoaderPCX::isALoadableFileFormat(io::IReadFile* file) const
|
||||
{
|
||||
u8 headerID;
|
||||
file->read(&headerID, sizeof(headerID));
|
||||
return headerID == 0x0a;
|
||||
}
|
||||
|
||||
|
||||
//! creates a image from the file
|
||||
IImage* CImageLoaderPCX::loadImage(io::IReadFile* file) const
|
||||
{
|
||||
SPCXHeader header;
|
||||
s32* paletteData = 0;
|
||||
|
||||
file->read(&header, sizeof(header));
|
||||
#ifdef __BIG_ENDIAN__
|
||||
header.XMin = os::Byteswap::byteswap(header.XMin);
|
||||
header.YMin = os::Byteswap::byteswap(header.YMin);
|
||||
header.XMax = os::Byteswap::byteswap(header.XMax);
|
||||
header.YMax = os::Byteswap::byteswap(header.YMax);
|
||||
header.HorizDPI = os::Byteswap::byteswap(header.HorizDPI);
|
||||
header.VertDPI = os::Byteswap::byteswap(header.VertDPI);
|
||||
header.BytesPerLine = os::Byteswap::byteswap(header.BytesPerLine);
|
||||
header.PaletteType = os::Byteswap::byteswap(header.PaletteType);
|
||||
header.HScrSize = os::Byteswap::byteswap(header.HScrSize);
|
||||
header.VScrSize = os::Byteswap::byteswap(header.VScrSize);
|
||||
#endif
|
||||
|
||||
//! return if the header is wrong
|
||||
if (header.Manufacturer != 0x0a && header.Encoding != 0x01)
|
||||
return 0;
|
||||
|
||||
// return if this isn't a supported type
|
||||
if ((header.BitsPerPixel != 8) && (header.BitsPerPixel != 4) && (header.BitsPerPixel != 1))
|
||||
{
|
||||
os::Printer::log("Unsupported bits per pixel in PCX file.",
|
||||
file->getFileName(), irr::ELL_WARNING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// read palette
|
||||
if( (header.BitsPerPixel == 8) && (header.Planes == 1) )
|
||||
{
|
||||
// the palette indicator (usually a 0x0c is found infront of the actual palette data)
|
||||
// is ignored because some exporters seem to forget to write it. This would result in
|
||||
// no image loaded before, now only wrong colors will be set.
|
||||
const long pos = file->getPos();
|
||||
file->seek( file->getSize()-256*3, false );
|
||||
|
||||
u8 *tempPalette = new u8[768];
|
||||
paletteData = new s32[256];
|
||||
file->read( tempPalette, 768 );
|
||||
|
||||
for( s32 i=0; i<256; i++ )
|
||||
{
|
||||
paletteData[i] = (0xff000000 |
|
||||
(tempPalette[i*3+0] << 16) |
|
||||
(tempPalette[i*3+1] << 8) |
|
||||
(tempPalette[i*3+2]));
|
||||
}
|
||||
|
||||
delete [] tempPalette;
|
||||
|
||||
file->seek(pos);
|
||||
}
|
||||
else if( header.BitsPerPixel == 4 )
|
||||
{
|
||||
paletteData = new s32[16];
|
||||
for( s32 i=0; i<16; i++ )
|
||||
{
|
||||
paletteData[i] = (0xff000000 |
|
||||
(header.Palette[i*3+0] << 16) |
|
||||
(header.Palette[i*3+1] << 8) |
|
||||
(header.Palette[i*3+2]));
|
||||
}
|
||||
}
|
||||
|
||||
// read image data
|
||||
const s32 width = header.XMax - header.XMin + 1;
|
||||
const s32 height = header.YMax - header.YMin + 1;
|
||||
const s32 imagebytes = header.BytesPerLine * header.Planes * header.BitsPerPixel * height / 8;
|
||||
u8* PCXData = new u8[imagebytes];
|
||||
|
||||
u8 cnt, value;
|
||||
s32 lineoffset=0, linestart=0, nextmode=1;
|
||||
for(s32 offset = 0; offset < imagebytes; offset += cnt)
|
||||
{
|
||||
file->read(&cnt, 1);
|
||||
if( !((cnt & 0xc0) == 0xc0) )
|
||||
{
|
||||
value = cnt;
|
||||
cnt = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
cnt &= 0x3f;
|
||||
file->read(&value, 1);
|
||||
}
|
||||
if (header.Planes==1)
|
||||
memset(PCXData+offset, value, cnt);
|
||||
else
|
||||
{
|
||||
for (u32 i=0; i<cnt; ++i)
|
||||
{
|
||||
PCXData[linestart+lineoffset]=value;
|
||||
lineoffset += 3;
|
||||
if (lineoffset>=3*header.BytesPerLine)
|
||||
{
|
||||
lineoffset=nextmode;
|
||||
if (++nextmode==3)
|
||||
nextmode=0;
|
||||
if (lineoffset==0)
|
||||
linestart += 3*header.BytesPerLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create image
|
||||
video::IImage* image = 0;
|
||||
s32 pad = (header.BytesPerLine - width * header.BitsPerPixel / 8) * header.Planes;
|
||||
|
||||
if (pad < 0)
|
||||
pad = -pad;
|
||||
|
||||
if (header.BitsPerPixel==8)
|
||||
{
|
||||
switch(header.Planes) // TODO: Other formats
|
||||
{
|
||||
case 1:
|
||||
image = new CImage(ECF_A1R5G5B5, core::dimension2d<u32>(width, height));
|
||||
if (image)
|
||||
CColorConverter::convert8BitTo16Bit(PCXData, (s16*)image->lock(), width, height, paletteData, pad);
|
||||
break;
|
||||
case 3:
|
||||
image = new CImage(ECF_R8G8B8, core::dimension2d<u32>(width, height));
|
||||
if (image)
|
||||
CColorConverter::convert24BitTo24Bit(PCXData, (u8*)image->lock(), width, height, pad);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (header.BitsPerPixel==4)
|
||||
{
|
||||
if (header.Planes==1)
|
||||
{
|
||||
image = new CImage(ECF_A1R5G5B5, core::dimension2d<u32>(width, height));
|
||||
if (image)
|
||||
CColorConverter::convert4BitTo16Bit(PCXData, (s16*)image->lock(), width, height, paletteData, pad);
|
||||
}
|
||||
}
|
||||
else if (header.BitsPerPixel==1)
|
||||
{
|
||||
if (header.Planes==4)
|
||||
{
|
||||
image = new CImage(ECF_A1R5G5B5, core::dimension2d<u32>(width, height));
|
||||
if (image)
|
||||
CColorConverter::convert4BitTo16Bit(PCXData, (s16*)image->lock(), width, height, paletteData, pad);
|
||||
}
|
||||
else if (header.Planes==1)
|
||||
{
|
||||
image = new CImage(ECF_A1R5G5B5, core::dimension2d<u32>(width, height));
|
||||
if (image)
|
||||
CColorConverter::convert1BitTo16Bit(PCXData, (s16*)image->lock(), width, height, pad);
|
||||
}
|
||||
}
|
||||
if (image)
|
||||
image->unlock();
|
||||
|
||||
// clean up
|
||||
|
||||
delete [] paletteData;
|
||||
delete [] PCXData;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
//! creates a loader which is able to load pcx images
|
||||
IImageLoader* createImageLoaderPCX()
|
||||
{
|
||||
return new CImageLoaderPCX();
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
||||
|
@ -1,82 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef __C_IMAGE_LOADER_PCX_H_INCLUDED__
|
||||
#define __C_IMAGE_LOADER_PCX_H_INCLUDED__
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
|
||||
#include "IImageLoader.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_PCX_LOADER_) || defined(_IRR_COMPILE_WITH_PCX_WRITER_)
|
||||
|
||||
// byte-align structures
|
||||
#include "irrpack.h"
|
||||
|
||||
struct SPCXHeader
|
||||
{
|
||||
u8 Manufacturer;
|
||||
u8 Version;
|
||||
u8 Encoding;
|
||||
u8 BitsPerPixel;
|
||||
u16 XMin;
|
||||
u16 YMin;
|
||||
u16 XMax;
|
||||
u16 YMax;
|
||||
u16 HorizDPI;
|
||||
u16 VertDPI;
|
||||
u8 Palette[48];
|
||||
u8 Reserved;
|
||||
u8 Planes;
|
||||
u16 BytesPerLine;
|
||||
u16 PaletteType;
|
||||
u16 HScrSize;
|
||||
u16 VScrSize;
|
||||
u8 Filler[54];
|
||||
} PACK_STRUCT;
|
||||
|
||||
|
||||
// Default alignment
|
||||
#include "irrunpack.h"
|
||||
|
||||
#endif // compile with loader or writer
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_PCX_LOADER_
|
||||
|
||||
/*!
|
||||
Image Loader for Windows PCX bitmaps.
|
||||
This loader was written and sent in by Dean P. Macri. I modified
|
||||
only some small bits of it.
|
||||
*/
|
||||
class CImageLoaderPCX : public IImageLoader
|
||||
{
|
||||
public:
|
||||
|
||||
//! constructor
|
||||
CImageLoaderPCX();
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".tga")
|
||||
virtual bool isALoadableFileExtension(const io::path& filename) const;
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
virtual bool isALoadableFileFormat(io::IReadFile* file) const;
|
||||
|
||||
//! creates a surface from the file
|
||||
virtual IImage* loadImage(io::IReadFile* file) const;
|
||||
|
||||
};
|
||||
|
||||
#endif // compile with loader
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
||||
|
@ -1,277 +0,0 @@
|
||||
// Copyright (C) 2007-2012 Christian Stehno
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "CImageLoaderPPM.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_PPM_LOADER_
|
||||
|
||||
#include "IReadFile.h"
|
||||
#include "CColorConverter.h"
|
||||
#include "CImage.h"
|
||||
#include "os.h"
|
||||
#include "fast_atof.h"
|
||||
#include "coreutil.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
|
||||
//! constructor
|
||||
CImageLoaderPPM::CImageLoaderPPM()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CImageLoaderPPM");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".tga")
|
||||
bool CImageLoaderPPM::isALoadableFileExtension(const io::path& filename) const
|
||||
{
|
||||
return core::hasFileExtension ( filename, "ppm", "pgm", "pbm" );
|
||||
}
|
||||
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
bool CImageLoaderPPM::isALoadableFileFormat(io::IReadFile* file) const
|
||||
{
|
||||
c8 id[2]={0};
|
||||
file->read(&id, 2);
|
||||
return (id[0]=='P' && id[1]>'0' && id[1]<'7');
|
||||
}
|
||||
|
||||
|
||||
//! creates a surface from the file
|
||||
IImage* CImageLoaderPPM::loadImage(io::IReadFile* file) const
|
||||
{
|
||||
IImage* image;
|
||||
|
||||
if (file->getSize() < 12)
|
||||
return 0;
|
||||
|
||||
c8 id[2];
|
||||
file->read(&id, 2);
|
||||
|
||||
if (id[0]!='P' || id[1]<'1' || id[1]>'6')
|
||||
return 0;
|
||||
|
||||
const u8 format = id[1] - '0';
|
||||
const bool binary = format>3;
|
||||
|
||||
core::stringc token;
|
||||
getNextToken(file, token);
|
||||
const u32 width = core::strtoul10(token.c_str());
|
||||
|
||||
getNextToken(file, token);
|
||||
const u32 height = core::strtoul10(token.c_str());
|
||||
|
||||
u8* data = 0;
|
||||
const u32 size = width*height;
|
||||
if (format==1 || format==4)
|
||||
{
|
||||
skipToNextToken(file); // go to start of data
|
||||
|
||||
const u32 bytesize = size/8+(size & 3)?1:0;
|
||||
if (binary)
|
||||
{
|
||||
if (file->getSize()-file->getPos() < (long)bytesize)
|
||||
return 0;
|
||||
data = new u8[bytesize];
|
||||
file->read(data, bytesize);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file->getSize()-file->getPos() < (long)(2*size)) // optimistic test
|
||||
return 0;
|
||||
data = new u8[bytesize];
|
||||
memset(data, 0, bytesize);
|
||||
u32 shift=0;
|
||||
for (u32 i=0; i<size; ++i)
|
||||
{
|
||||
getNextToken(file, token);
|
||||
if (token == "1")
|
||||
data[i/8] |= (0x01 << shift);
|
||||
if (++shift == 8)
|
||||
shift=0;
|
||||
}
|
||||
}
|
||||
image = new CImage(ECF_A1R5G5B5, core::dimension2d<u32>(width, height));
|
||||
if (image)
|
||||
CColorConverter::convert1BitTo16Bit(data, (s16*)image->lock(), width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
getNextToken(file, token);
|
||||
const u32 maxDepth = core::strtoul10(token.c_str());
|
||||
if (maxDepth > 255) // no double bytes yet
|
||||
return 0;
|
||||
|
||||
skipToNextToken(file); // go to start of data
|
||||
|
||||
if (format==2 || format==5)
|
||||
{
|
||||
if (binary)
|
||||
{
|
||||
if (file->getSize()-file->getPos() < (long)size)
|
||||
return 0;
|
||||
data = new u8[size];
|
||||
file->read(data, size);
|
||||
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height));
|
||||
if (image)
|
||||
{
|
||||
u8* ptr = (u8*)image->lock();
|
||||
for (u32 i=0; i<size; ++i)
|
||||
{
|
||||
*ptr++ = data[i];
|
||||
*ptr++ = data[i];
|
||||
*ptr++ = data[i];
|
||||
*ptr++ = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file->getSize()-file->getPos() < (long)(2*size)) // optimistic test
|
||||
return 0;
|
||||
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height));
|
||||
if (image)
|
||||
{
|
||||
u8* ptr = (u8*)image->lock();
|
||||
for (u32 i=0; i<size; ++i)
|
||||
{
|
||||
getNextToken(file, token);
|
||||
const u8 num = (u8)core::strtoul10(token.c_str());
|
||||
*ptr++ = num;
|
||||
*ptr++ = num;
|
||||
*ptr++ = num;
|
||||
*ptr++ = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const u32 bytesize = 3*size;
|
||||
if (binary)
|
||||
{
|
||||
if (file->getSize()-file->getPos() < (long)bytesize)
|
||||
return 0;
|
||||
data = new u8[bytesize];
|
||||
file->read(data, bytesize);
|
||||
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height));
|
||||
if (image)
|
||||
{
|
||||
u8* ptr = (u8*)image->lock();
|
||||
for (u32 i=0; i<size; ++i)
|
||||
{
|
||||
*ptr++ = data[3*i];
|
||||
*ptr++ = data[3*i+1];
|
||||
*ptr++ = data[3*i+2];
|
||||
*ptr++ = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file->getSize()-file->getPos() < (long)(2*bytesize)) // optimistic test
|
||||
return 0;
|
||||
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height));
|
||||
if (image)
|
||||
{
|
||||
u8* ptr = (u8*)image->lock();
|
||||
for (u32 i=0; i<size; ++i)
|
||||
{
|
||||
getNextToken(file, token);
|
||||
*ptr++ = (u8)core::strtoul10(token.c_str());
|
||||
getNextToken(file, token);
|
||||
*ptr++ = (u8)core::strtoul10(token.c_str());
|
||||
getNextToken(file, token);
|
||||
*ptr++ = (u8)core::strtoul10(token.c_str());
|
||||
*ptr++ = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (image)
|
||||
image->unlock();
|
||||
|
||||
delete [] data;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
//! read the next token from file
|
||||
void CImageLoaderPPM::getNextToken(io::IReadFile* file, core::stringc& token) const
|
||||
{
|
||||
token = "";
|
||||
c8 c;
|
||||
while(file->getPos()<file->getSize())
|
||||
{
|
||||
file->read(&c, 1);
|
||||
if (c=='#')
|
||||
{
|
||||
while (c!='\n' && c!='\r' && (file->getPos()<file->getSize()))
|
||||
file->read(&c, 1);
|
||||
}
|
||||
else if (!core::isspace(c))
|
||||
{
|
||||
token.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(file->getPos()<file->getSize())
|
||||
{
|
||||
file->read(&c, 1);
|
||||
if (c=='#')
|
||||
{
|
||||
while (c!='\n' && c!='\r' && (file->getPos()<file->getSize()))
|
||||
file->read(&c, 1);
|
||||
}
|
||||
else if (!core::isspace(c))
|
||||
token.append(c);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! skip to next token (skip whitespace)
|
||||
void CImageLoaderPPM::skipToNextToken(io::IReadFile* file) const
|
||||
{
|
||||
c8 c;
|
||||
while(file->getPos()<file->getSize())
|
||||
{
|
||||
file->read(&c, 1);
|
||||
if (c=='#')
|
||||
{
|
||||
while (c!='\n' && c!='\r' && (file->getPos()<file->getSize()))
|
||||
file->read(&c, 1);
|
||||
}
|
||||
else if (!core::isspace(c))
|
||||
{
|
||||
file->seek(-1, true); // put back
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! creates a loader which is able to load windows bitmaps
|
||||
IImageLoader* createImageLoaderPPM()
|
||||
{
|
||||
return new CImageLoaderPPM;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
||||
|
@ -1,55 +0,0 @@
|
||||
// Copyright (C) 2007-2012 Christian Stehno
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef __C_IMAGE_LOADER_PPM_H_INCLUDED__
|
||||
#define __C_IMAGE_LOADER_PPM_H_INCLUDED__
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_PPM_LOADER_
|
||||
|
||||
#include "IImageLoader.h"
|
||||
#include "irrString.h"
|
||||
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
|
||||
/*!
|
||||
Surface Loader for SUN Pixmaps
|
||||
*/
|
||||
class CImageLoaderPPM : public IImageLoader
|
||||
{
|
||||
public:
|
||||
|
||||
//! constructor
|
||||
CImageLoaderPPM();
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".tga")
|
||||
virtual bool isALoadableFileExtension(const io::path& filename) const;
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
virtual bool isALoadableFileFormat(io::IReadFile* file) const;
|
||||
|
||||
//! creates a surface from the file
|
||||
virtual IImage* loadImage(io::IReadFile* file) const;
|
||||
|
||||
private:
|
||||
//! read the next token from file
|
||||
void getNextToken(io::IReadFile* file, core::stringc& token) const;
|
||||
//! skip to next token (skip whitespace)
|
||||
void skipToNextToken(io::IReadFile* file) const;
|
||||
};
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -1,375 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "CImageLoaderPSD.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_PSD_LOADER_
|
||||
|
||||
#include "IReadFile.h"
|
||||
#include "os.h"
|
||||
#include "CImage.h"
|
||||
#include "irrString.h"
|
||||
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
|
||||
//! constructor
|
||||
CImageLoaderPSD::CImageLoaderPSD()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CImageLoaderPSD");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".tga")
|
||||
bool CImageLoaderPSD::isALoadableFileExtension(const io::path& filename) const
|
||||
{
|
||||
return core::hasFileExtension ( filename, "psd" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
bool CImageLoaderPSD::isALoadableFileFormat(io::IReadFile* file) const
|
||||
{
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
u8 type[3];
|
||||
file->read(&type, sizeof(u8)*3);
|
||||
return (type[2]==2); // we currently only handle tgas of type 2.
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! creates a surface from the file
|
||||
IImage* CImageLoaderPSD::loadImage(io::IReadFile* file) const
|
||||
{
|
||||
u32* imageData = 0;
|
||||
|
||||
PsdHeader header;
|
||||
file->read(&header, sizeof(PsdHeader));
|
||||
|
||||
#ifndef __BIG_ENDIAN__
|
||||
header.version = os::Byteswap::byteswap(header.version);
|
||||
header.channels = os::Byteswap::byteswap(header.channels);
|
||||
header.height = os::Byteswap::byteswap(header.height);
|
||||
header.width = os::Byteswap::byteswap(header.width);
|
||||
header.depth = os::Byteswap::byteswap(header.depth);
|
||||
header.mode = os::Byteswap::byteswap(header.mode);
|
||||
#endif
|
||||
|
||||
if (header.signature[0] != '8' ||
|
||||
header.signature[1] != 'B' ||
|
||||
header.signature[2] != 'P' ||
|
||||
header.signature[3] != 'S')
|
||||
return 0;
|
||||
|
||||
if (header.version != 1)
|
||||
{
|
||||
os::Printer::log("Unsupported PSD file version", file->getFileName(), ELL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (header.mode != 3 || header.depth != 8)
|
||||
{
|
||||
os::Printer::log("Unsupported PSD color mode or depth.\n", file->getFileName(), ELL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// skip color mode data
|
||||
|
||||
u32 l;
|
||||
file->read(&l, sizeof(u32));
|
||||
#ifndef __BIG_ENDIAN__
|
||||
l = os::Byteswap::byteswap(l);
|
||||
#endif
|
||||
if (!file->seek(l, true))
|
||||
{
|
||||
os::Printer::log("Error seeking file pos to image resources.\n", file->getFileName(), ELL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// skip image resources
|
||||
|
||||
file->read(&l, sizeof(u32));
|
||||
#ifndef __BIG_ENDIAN__
|
||||
l = os::Byteswap::byteswap(l);
|
||||
#endif
|
||||
if (!file->seek(l, true))
|
||||
{
|
||||
os::Printer::log("Error seeking file pos to layer and mask.\n", file->getFileName(), ELL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// skip layer & mask
|
||||
|
||||
file->read(&l, sizeof(u32));
|
||||
#ifndef __BIG_ENDIAN__
|
||||
l = os::Byteswap::byteswap(l);
|
||||
#endif
|
||||
if (!file->seek(l, true))
|
||||
{
|
||||
os::Printer::log("Error seeking file pos to image data section.\n", file->getFileName(), ELL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// read image data
|
||||
|
||||
u16 compressionType;
|
||||
file->read(&compressionType, sizeof(u16));
|
||||
#ifndef __BIG_ENDIAN__
|
||||
compressionType = os::Byteswap::byteswap(compressionType);
|
||||
#endif
|
||||
|
||||
if (compressionType != 1 && compressionType != 0)
|
||||
{
|
||||
os::Printer::log("Unsupported psd compression mode.\n", file->getFileName(), ELL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// create image data block
|
||||
|
||||
imageData = new u32[header.width * header.height];
|
||||
|
||||
bool res = false;
|
||||
|
||||
if (compressionType == 0)
|
||||
res = readRawImageData(file, header, imageData); // RAW image data
|
||||
else
|
||||
res = readRLEImageData(file, header, imageData); // RLE compressed data
|
||||
|
||||
video::IImage* image = 0;
|
||||
|
||||
if (res)
|
||||
{
|
||||
// create surface
|
||||
image = new CImage(ECF_A8R8G8B8,
|
||||
core::dimension2d<u32>(header.width, header.height), imageData);
|
||||
}
|
||||
|
||||
if (!image)
|
||||
delete [] imageData;
|
||||
imageData = 0;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
bool CImageLoaderPSD::readRawImageData(io::IReadFile* file, const PsdHeader& header, u32* imageData) const
|
||||
{
|
||||
u8* tmpData = new u8[header.width * header.height];
|
||||
|
||||
for (s32 channel=0; channel<header.channels && channel < 3; ++channel)
|
||||
{
|
||||
if (!file->read(tmpData, sizeof(c8) * header.width * header.height))
|
||||
{
|
||||
os::Printer::log("Error reading color channel\n", file->getFileName(), ELL_ERROR);
|
||||
break;
|
||||
}
|
||||
|
||||
s16 shift = getShiftFromChannel((c8)channel, header);
|
||||
if (shift != -1)
|
||||
{
|
||||
u32 mask = 0xff << shift;
|
||||
|
||||
for (u32 x=0; x<header.width; ++x)
|
||||
{
|
||||
for (u32 y=0; y<header.height; ++y)
|
||||
{
|
||||
s32 index = x + y*header.width;
|
||||
imageData[index] = ~(~imageData[index] | mask);
|
||||
imageData[index] |= tmpData[index] << shift;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delete [] tmpData;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CImageLoaderPSD::readRLEImageData(io::IReadFile* file, const PsdHeader& header, u32* imageData) const
|
||||
{
|
||||
/* If the compression code is 1, the image data
|
||||
starts with the byte counts for all the scan lines in the channel
|
||||
(LayerBottom LayerTop), with each count stored as a two
|
||||
byte value. The RLE compressed data follows, with each scan line
|
||||
compressed separately. The RLE compression is the same compres-sion
|
||||
algorithm used by the Macintosh ROM routine PackBits, and
|
||||
the TIFF standard.
|
||||
If the Layer's Size, and therefore the data, is odd, a pad byte will
|
||||
be inserted at the end of the row.
|
||||
*/
|
||||
|
||||
/*
|
||||
A pseudo code fragment to unpack might look like this:
|
||||
|
||||
Loop until you get the number of unpacked bytes you are expecting:
|
||||
Read the next source byte into n.
|
||||
If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
|
||||
Else if n is between -127 and -1 inclusive, copy the next byte -n+1
|
||||
times.
|
||||
Else if n is -128, noop.
|
||||
Endloop
|
||||
|
||||
In the inverse routine, it is best to encode a 2-byte repeat run as a replicate run
|
||||
except when preceded and followed by a literal run. In that case, it is best to merge
|
||||
the three runs into one literal run. Always encode 3-byte repeats as replicate runs.
|
||||
That is the essence of the algorithm. Here are some additional rules:
|
||||
- Pack each row separately. Do not compress across row boundaries.
|
||||
- The number of uncompressed bytes per row is defined to be (ImageWidth + 7)
|
||||
/ 8. If the uncompressed bitmap is required to have an even number of bytes per
|
||||
row, decompress into word-aligned buffers.
|
||||
- If a run is larger than 128 bytes, encode the remainder of the run as one or more
|
||||
additional replicate runs.
|
||||
When PackBits data is decompressed, the result should be interpreted as per com-pression
|
||||
type 1 (no compression).
|
||||
*/
|
||||
|
||||
u8* tmpData = new u8[header.width * header.height];
|
||||
u16 *rleCount= new u16 [header.height * header.channels];
|
||||
|
||||
s32 size=0;
|
||||
|
||||
for (u32 y=0; y<header.height * header.channels; ++y)
|
||||
{
|
||||
if (!file->read(&rleCount[y], sizeof(u16)))
|
||||
{
|
||||
delete [] tmpData;
|
||||
delete [] rleCount;
|
||||
os::Printer::log("Error reading rle rows\n", file->getFileName(), ELL_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef __BIG_ENDIAN__
|
||||
rleCount[y] = os::Byteswap::byteswap(rleCount[y]);
|
||||
#endif
|
||||
size += rleCount[y];
|
||||
}
|
||||
|
||||
s8 *buf = new s8[size];
|
||||
if (!file->read(buf, size))
|
||||
{
|
||||
delete [] rleCount;
|
||||
delete [] buf;
|
||||
delete [] tmpData;
|
||||
os::Printer::log("Error reading rle rows\n", file->getFileName(), ELL_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
u16 *rcount=rleCount;
|
||||
|
||||
s8 rh;
|
||||
u16 bytesRead;
|
||||
u8 *dest;
|
||||
s8 *pBuf = buf;
|
||||
|
||||
// decompress packbit rle
|
||||
|
||||
for (s32 channel=0; channel<header.channels; channel++)
|
||||
{
|
||||
for (u32 y=0; y<header.height; ++y, ++rcount)
|
||||
{
|
||||
bytesRead=0;
|
||||
dest = &tmpData[y*header.width];
|
||||
|
||||
while (bytesRead < *rcount)
|
||||
{
|
||||
rh = *pBuf++;
|
||||
++bytesRead;
|
||||
|
||||
if (rh >= 0)
|
||||
{
|
||||
++rh;
|
||||
|
||||
while (rh--)
|
||||
{
|
||||
*dest = *pBuf++;
|
||||
++bytesRead;
|
||||
++dest;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (rh > -128)
|
||||
{
|
||||
rh = -rh +1;
|
||||
|
||||
while (rh--)
|
||||
{
|
||||
*dest = *pBuf;
|
||||
++dest;
|
||||
}
|
||||
|
||||
++pBuf;
|
||||
++bytesRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s16 shift = getShiftFromChannel((c8)channel, header);
|
||||
|
||||
if (shift != -1)
|
||||
{
|
||||
u32 mask = 0xff << shift;
|
||||
|
||||
for (u32 x=0; x<header.width; ++x)
|
||||
for (u32 y=0; y<header.height; ++y)
|
||||
{
|
||||
s32 index = x + y*header.width;
|
||||
imageData[index] = ~(~imageData[index] | mask);
|
||||
imageData[index] |= tmpData[index] << shift;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete [] rleCount;
|
||||
delete [] buf;
|
||||
delete [] tmpData;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
s16 CImageLoaderPSD::getShiftFromChannel(c8 channelNr, const PsdHeader& header) const
|
||||
{
|
||||
switch(channelNr)
|
||||
{
|
||||
case 0:
|
||||
return 16; // red
|
||||
case 1:
|
||||
return 8; // green
|
||||
case 2:
|
||||
return 0; // blue
|
||||
case 3:
|
||||
return header.channels == 4 ? 24 : -1; // ?
|
||||
case 4:
|
||||
return 24; // alpha
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! creates a loader which is able to load tgas
|
||||
IImageLoader* createImageLoaderPSD()
|
||||
{
|
||||
return new CImageLoaderPSD();
|
||||
}
|
||||
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
||||
|
@ -1,72 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef __C_IMAGE_LOADER_PSD_H_INCLUDED__
|
||||
#define __C_IMAGE_LOADER_PSD_H_INCLUDED__
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_PSD_LOADER_
|
||||
|
||||
#include "IImageLoader.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
|
||||
// byte-align structures
|
||||
#include "irrpack.h"
|
||||
|
||||
struct PsdHeader
|
||||
{
|
||||
c8 signature [4]; // Always equal to 8BPS.
|
||||
u16 version; // Always equal to 1
|
||||
c8 reserved [6]; // Must be zero
|
||||
u16 channels; // Number of any channels inc. alphas
|
||||
u32 height; // Rows Height of image in pixel
|
||||
u32 width; // Colums Width of image in pixel
|
||||
u16 depth; // Bits/channel
|
||||
u16 mode; // Color mode of the file (Bitmap/Grayscale..)
|
||||
} PACK_STRUCT;
|
||||
|
||||
|
||||
// Default alignment
|
||||
#include "irrunpack.h"
|
||||
|
||||
/*!
|
||||
Surface Loader for psd images
|
||||
*/
|
||||
class CImageLoaderPSD : public IImageLoader
|
||||
{
|
||||
public:
|
||||
|
||||
//! constructor
|
||||
CImageLoaderPSD();
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".tga")
|
||||
virtual bool isALoadableFileExtension(const io::path& filename) const;
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
virtual bool isALoadableFileFormat(io::IReadFile* file) const;
|
||||
|
||||
//! creates a surface from the file
|
||||
virtual IImage* loadImage(io::IReadFile* file) const;
|
||||
|
||||
private:
|
||||
|
||||
bool readRawImageData(io::IReadFile* file, const PsdHeader& header, u32* imageData) const;
|
||||
bool readRLEImageData(io::IReadFile* file, const PsdHeader& header, u32* imageData) const;
|
||||
s16 getShiftFromChannel(c8 channelNr, const PsdHeader& header) const;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -1,654 +0,0 @@
|
||||
//! Copyright (C) 2009-2012 Gary Conway
|
||||
//! This file is part of the "Irrlicht Engine".
|
||||
//! For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
/*
|
||||
Author: Gary Conway (Viper) - co-author of the ZIP file format, Feb 1989,
|
||||
see the story at http://www.idcnet.us/ziphistory.html
|
||||
Website: http://idcnet.us
|
||||
Email: codeslinger@vipergc.com
|
||||
Created: March 1, 2009
|
||||
Version: 1.0
|
||||
Updated:
|
||||
|
||||
This module will load SGI .rgb files (along with the other extensions). The module complies
|
||||
with version 1.0 of the SGI Image File Format by Paul Haeberli of Silicon Graphics Computer Systems
|
||||
The module handles BW, RGB and RGBA images.
|
||||
|
||||
RGB images are stored with either 8 bits per COLOR VALUE, one each for red,green,blue (24bpp)
|
||||
or 16 bits per COLOR VALUE, again one each for red,green,blue (48 bpp), not including the alpha channel
|
||||
|
||||
|
||||
OPTIONS NOT SUPPORTED
|
||||
|
||||
1. 16 bit COLOR VALUES (48bpp modes)
|
||||
2. COLORMAP = DITHERED mode
|
||||
|
||||
|
||||
|
||||
For non- run length encoded files, this is the structure
|
||||
|
||||
The Header
|
||||
The Image Data
|
||||
|
||||
If the image is run length encoded, this is the structure:
|
||||
The Header
|
||||
The Offset Tables
|
||||
The Image Data
|
||||
|
||||
The Header consists of the following:
|
||||
|
||||
Size | Type | Name | Description
|
||||
|
||||
2 bytes | short | MAGIC | IRIS image file magic number
|
||||
1 byte | char | STORAGE | Storage format
|
||||
1 byte | char | BPC | Number of bytes per pixel channel
|
||||
2 bytes | ushort | DIMENSION | Number of dimensions
|
||||
2 bytes | ushort | XSIZE | X size in pixels
|
||||
2 bytes | ushort | YSIZE | Y size in pixels
|
||||
2 bytes | ushort | ZSIZE | Number of channels
|
||||
4 bytes | long | PIXMIN | Minimum pixel value
|
||||
4 bytes | long | PIXMAX | Maximum pixel value
|
||||
4 bytes | char | DUMMY | Ignored
|
||||
80 bytes | char | IMAGENAME | Image name
|
||||
4 bytes | long | COLORMAP | Colormap ID
|
||||
404 bytes | char | DUMMY | Ignored
|
||||
|
||||
Here is a description of each field in the image file Header:
|
||||
|
||||
MAGIC - This is the decimal value 474 saved as a short. This identifies the file as an SGI image file.
|
||||
|
||||
STORAGE - specifies whether the image is stored using run length encoding (RLE) or not (VERBATIM).
|
||||
If RLE is used, the value of this byte will be 1. Otherwise the value of this byte will
|
||||
be 0. The only allowed values for this field are 0 or 1.
|
||||
|
||||
BPC - describes the precision that is used to store each channel of an image. This is the number of
|
||||
bytes per pixel component. The majority of SGI image files use 1 byte per pixel component,
|
||||
giving 256 levels. Some SGI image files use 2 bytes per component. The only allowed values
|
||||
for this field are 1 or 2.
|
||||
|
||||
DIMENSION - described the number of dimensions in the data stored in the image file.
|
||||
The only allowed values are 1, 2, or 3. If this value is 1, the image file
|
||||
consists of only 1 channel and only 1 scanline (row). The length of this
|
||||
scanline is given by the value of XSIZE below. If this value is 2, the file
|
||||
consists of a single channel with a number of scanlines. The width and height
|
||||
of the image are given by the values of XSIZE and YSIZE below.
|
||||
If this value is 3, the file consists of a number of channels.
|
||||
The width and height of the image are given by the values of XSIZE and YSIZE below.
|
||||
The number of channels is given by the value of ZSIZE below.
|
||||
|
||||
XSIZE - The width of the image in pixels
|
||||
|
||||
YSIZE - The height of the image in pixels
|
||||
|
||||
ZSIZE - The number of channels in the image. B/W (greyscale) images are stored as 2 dimensional
|
||||
images with a ZSIZE of 1. RGB color images are stored as 3 dimensional images with a
|
||||
ZSIZE of 3. An RGB image with an ALPHA channel is stored as a 3 dimensional image with
|
||||
a ZSIZE of 4. There are no inherent limitations in the SGI image file format that would
|
||||
preclude the creation of image files with more than 4 channels.
|
||||
|
||||
PINMIN - The minimum pixel value in the image. The value of 0 may be used if no pixel has a value
|
||||
that is smaller than 0.
|
||||
|
||||
PINMAX - The maximum pixel value in the image. The value of 255 may be used if no pixel has a
|
||||
value that is greater than 255. This is the value that is considered to be full
|
||||
brightness in the image.
|
||||
|
||||
DUMMY - This 4 bytes of data should be set to 0.
|
||||
|
||||
IMAGENAME - An null terminated ascii string of up to 79 characters terminated by a null may be
|
||||
included here. This is not commonly used.
|
||||
|
||||
COLORMAP - This controls how the pixel values in the file should be interpreted. It can have one
|
||||
of these four values:
|
||||
|
||||
0: NORMAL - The data in the channels represent B/W values for images with 1 channel, RGB values
|
||||
for images with 3 channels, and RGBA values for images with 4 channels. Almost all
|
||||
the SGI image files are of this type.
|
||||
|
||||
1: DITHERED - The image will have only 1 channel of data. For each pixel, RGB data is packed
|
||||
into one 8 bit value. 3 bits are used for red and green, while blue uses 2 bits.
|
||||
Red data is found in bits[2..0], green data in bits[5..3], and blue data in
|
||||
bits[7..6]. This format is obsolete.
|
||||
|
||||
2: SCREEN - The image will have only 1 channel of data. This format was used to store
|
||||
color-indexed pixels. To convert the pixel values into RGB values a colormap
|
||||
must be used. The appropriate color map varies from image to image. This format is obsolete.
|
||||
|
||||
3: COLORMAP - The image is used to store a color map from an SGI machine. In this case the
|
||||
image is not displayable in the conventional sense.
|
||||
|
||||
DUMMY - This 404 bytes of data should be set to 0. This makes the Header exactly 512 bytes.
|
||||
*/
|
||||
|
||||
#include "CImageLoaderRGB.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_RGB_LOADER_
|
||||
|
||||
#include "IReadFile.h"
|
||||
#include "SColor.h"
|
||||
#include "CColorConverter.h"
|
||||
#include "CImage.h"
|
||||
#include "os.h"
|
||||
#include "irrString.h"
|
||||
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
//! constructor
|
||||
CImageLoaderRGB::CImageLoaderRGB()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CImageLoaderRGB");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extensions listed here
|
||||
bool CImageLoaderRGB::isALoadableFileExtension(const io::path& filename) const
|
||||
{
|
||||
return core::hasFileExtension( filename, "rgb", "rgba", "sgi" ) ||
|
||||
core::hasFileExtension( filename, "int", "inta", "bw" );
|
||||
}
|
||||
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
bool CImageLoaderRGB::isALoadableFileFormat(io::IReadFile* file) const
|
||||
{
|
||||
rgbStruct rgb;
|
||||
return checkFormat(file, rgb);
|
||||
}
|
||||
|
||||
|
||||
/** The main entry point, read and format the image file.
|
||||
\return Pointer to the image data on success
|
||||
null pointer on fail */
|
||||
IImage* CImageLoaderRGB::loadImage(io::IReadFile* file) const
|
||||
{
|
||||
IImage* image = 0;
|
||||
s32* paletteData = 0;
|
||||
|
||||
rgbStruct rgb; // construct our structure for holding data
|
||||
|
||||
// read Header information
|
||||
if (checkFormat(file, rgb))
|
||||
{
|
||||
// 16 bits per COLOR VALUE, not supported, this is 48bpp mode
|
||||
if (rgb.Header.BPC != 1)
|
||||
{
|
||||
os::Printer::log("Only one byte per pixel RGB files are supported", file->getFileName(), ELL_ERROR);
|
||||
}
|
||||
else if (rgb.Header.Colormap != 0)
|
||||
{
|
||||
os::Printer::log("Dithered, Screen and Colormap RGB files are not supported", file->getFileName(), ELL_ERROR);
|
||||
}
|
||||
else if (rgb.Header.Storage == 1 && !readOffsetTables(file, rgb))
|
||||
{
|
||||
os::Printer::log("Failed to read RLE table in RGB file", file->getFileName(), ELL_ERROR);
|
||||
}
|
||||
else if (!rgb.allocateTemps())
|
||||
{
|
||||
os::Printer::log("Out of memory in RGB file loader", file->getFileName(), ELL_ERROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
// read and process the file to rgbData
|
||||
processFile(file, rgb);
|
||||
|
||||
/*
|
||||
ZSIZE Description
|
||||
1 BW (grayscale) image
|
||||
3 RGB image
|
||||
4 RGBa image with one alpha channel
|
||||
|
||||
When the Alpha channel is present, I am not sure with RGB files if
|
||||
it's a precomputed RGB color or it needs to be completely calculated. My guess
|
||||
would be that it's not precomputed for two reasons.
|
||||
|
||||
1. the loss of precision when calculating the fraction, then storing the result as an int
|
||||
2. the loss of the original color data when the image might be composited with another. Yes
|
||||
the original color data could be computed, however, not without another loss in precision
|
||||
|
||||
Also, I don't know where to find the background color
|
||||
Pixmin and Pixmax are apparently the min and max alpha blend values (0-100%)
|
||||
|
||||
Complete Alpha blending computation
|
||||
The actual resulting merged color is computed this way:
|
||||
(image color ◊ alpha) + (background color ◊ (100% - alpha)).
|
||||
|
||||
Using precomputed blending
|
||||
(image color) + (background color ◊ (100% - alpha)).
|
||||
|
||||
Alternatively, the RGB files could use another blending technique entirely
|
||||
*/
|
||||
|
||||
switch (rgb.Header.Zsize)
|
||||
{
|
||||
case 1:
|
||||
// BW (grayscale) image
|
||||
paletteData = new s32[256];
|
||||
for (int n=0; n<256; n++)
|
||||
paletteData[n] = n;
|
||||
|
||||
image = new CImage(ECF_A1R5G5B5, core::dimension2d<u32>(rgb.Header.Xsize, rgb.Header.Ysize));
|
||||
if (image)
|
||||
CColorConverter::convert8BitTo16Bit(rgb.rgbData, (s16*)image->lock(), rgb.Header.Xsize, rgb.Header.Ysize, paletteData, 0, true);
|
||||
break;
|
||||
case 3:
|
||||
// RGB image
|
||||
// one byte per COLOR VALUE, eg, 24bpp
|
||||
image = new CImage(ECF_R8G8B8, core::dimension2d<u32>(rgb.Header.Xsize, rgb.Header.Ysize));
|
||||
if (image)
|
||||
CColorConverter::convert24BitTo24Bit(rgb.rgbData, (u8*)image->lock(), rgb.Header.Xsize, rgb.Header.Ysize, 0, true, false);
|
||||
break;
|
||||
case 4:
|
||||
// RGBa image with one alpha channel (32bpp)
|
||||
// image is stored in rgbData as RGBA
|
||||
|
||||
converttoARGB(reinterpret_cast<u32*>(rgb.rgbData), rgb.Header.Ysize * rgb.Header.Xsize);
|
||||
|
||||
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(rgb.Header.Xsize, rgb.Header.Ysize));
|
||||
if (image)
|
||||
CColorConverter::convert32BitTo32Bit((s32*)rgb.rgbData, (s32*)image->lock(), rgb.Header.Xsize, rgb.Header.Ysize, 0, true);
|
||||
|
||||
break;
|
||||
default:
|
||||
// Format unknown
|
||||
os::Printer::log("Unsupported pixel format in RGB file", file->getFileName(), ELL_ERROR);
|
||||
}
|
||||
|
||||
if (image)
|
||||
image->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// and tidy up allocated memory
|
||||
delete [] paletteData;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
// returns true on success
|
||||
bool CImageLoaderRGB::readHeader(io::IReadFile* file, rgbStruct& rgb) const
|
||||
{
|
||||
if ( file->read(&rgb.Header, sizeof(rgb.Header)) < s32(sizeof(rgb.Header)) )
|
||||
return false;
|
||||
|
||||
// test for INTEL or BIG ENDIAN processor
|
||||
// if INTEL, then swap the byte order on 16 bit INT's to make them BIG ENDIAN
|
||||
// because that is the native format for the .rgb file
|
||||
#ifndef __BIG_ENDIAN__
|
||||
rgb.Header.Magic = os::Byteswap::byteswap(rgb.Header.Magic);
|
||||
rgb.Header.Storage = os::Byteswap::byteswap(rgb.Header.Storage);
|
||||
rgb.Header.Dimension = os::Byteswap::byteswap(rgb.Header.Dimension);
|
||||
rgb.Header.Xsize = os::Byteswap::byteswap(rgb.Header.Xsize);
|
||||
rgb.Header.Ysize = os::Byteswap::byteswap(rgb.Header.Ysize);
|
||||
rgb.Header.Zsize = os::Byteswap::byteswap(rgb.Header.Zsize);
|
||||
rgb.Header.Pixmin = os::Byteswap::byteswap(rgb.Header.Pixmin);
|
||||
rgb.Header.Pixmax = os::Byteswap::byteswap(rgb.Header.Pixmax);
|
||||
rgb.Header.Colormap = os::Byteswap::byteswap(rgb.Header.Colormap);
|
||||
#endif
|
||||
|
||||
// calculate the size of the buffer needed: XSIZE * YSIZE * ZSIZE * BPC
|
||||
rgb.ImageSize = (rgb.Header.Xsize)*(rgb.Header.Ysize)*(rgb.Header.Zsize)*(rgb.Header.BPC);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CImageLoaderRGB::checkFormat(io::IReadFile* file, rgbStruct& rgb) const
|
||||
{
|
||||
if (!readHeader(file, rgb))
|
||||
return false;
|
||||
|
||||
return (rgb.Header.Magic == 0x1DA);
|
||||
}
|
||||
|
||||
/*
|
||||
If the image is stored using run length encoding, offset tables follow the Header that
|
||||
describe what the file offsets are to the RLE for each scanline. This information only
|
||||
applies if the value for STORAGE above is 1.
|
||||
|
||||
Size | Type | Name | Description
|
||||
|
||||
tablen longs | long | STARTTAB | Start table
|
||||
tablen longs | long | LENGTHTAB | Length table
|
||||
|
||||
One entry in each table is needed for each scanline of RLE data. The total number of scanlines in the image (tablen) is determined by the product of the YSIZE and ZSIZE. There are two tables of longs that are written. Each consists of tablen longs of data. The first table has the file offsets to the RLE data for each scanline in the image. In a file with more than 1 channel (ZSIZE > 1) this table first has all the offsets for the scanlines in the first channel, followed be offsets for the scanlines in the second channel, etc. The second table has the RLE data length for each scanline in the image. In a file with more than 1 channel (ZSIZE > 1) this table first has all the RLE data lengths for the scanlines in the first channel, followed be RLE data lengths for the scanlines in the second channel, etc.
|
||||
|
||||
To find the the file offset, and the number of bytes in the RLE data for a particular scanline, these
|
||||
two arrays may be read in and indexed as follows:
|
||||
|
||||
To read in the tables:
|
||||
|
||||
unsigned long *starttab, *lengthtab;
|
||||
|
||||
tablen = YSIZE*ZSIZE*sizeof(long);
|
||||
starttab = (unsigned long *)mymalloc(tablen);
|
||||
lengthtab = (unsigned long *)mymalloc(tablen);
|
||||
fseek(rgb->inf,512,SEEK_SET);
|
||||
readlongtab(rgb->inf,starttab);
|
||||
readlongtab(rgb->inf,lengthtab);
|
||||
|
||||
To find the file offset and RLE data length for a scanline:
|
||||
|
||||
rowno is an integer in the range 0 to YSIZE-1 channo is an integer in the range 0 to ZSIZE-1
|
||||
|
||||
rleoffset = starttab[rowno+channo*YSIZE]
|
||||
rlelength = lengthtab[rowno+channo*YSIZE]
|
||||
|
||||
It is possible for two identical rows (scanlines) to share compressed data. A completely
|
||||
white image could be written as a single compressed row and having all table entries point
|
||||
to that row. Another little hack that should work is if you are writing out a RGB RLE file,
|
||||
and a particular scanline is achromatic (greyscale), you could just make the r, g and b rows
|
||||
point to the same data!!
|
||||
|
||||
RETURNS: on success true, else returns false
|
||||
*/
|
||||
|
||||
bool CImageLoaderRGB::readOffsetTables(io::IReadFile* file, rgbStruct& rgb) const
|
||||
{
|
||||
rgb.TableLen = rgb.Header.Ysize * rgb.Header.Zsize ; // calc size of tables
|
||||
|
||||
// return error if unable to allocate tables
|
||||
rgb.StartTable = new u32[rgb.TableLen];
|
||||
if (!rgb.StartTable)
|
||||
return false;
|
||||
rgb.LengthTable = new u32[rgb.TableLen];
|
||||
if (!rgb.LengthTable)
|
||||
return false;
|
||||
|
||||
file->seek(512);
|
||||
file->read(rgb.StartTable, rgb.TableLen* sizeof(u32));
|
||||
file->read(rgb.LengthTable, rgb.TableLen* sizeof(u32));
|
||||
|
||||
// if we are on an INTEL platform, swap the bytes
|
||||
#ifndef __BIG_ENDIAN__
|
||||
const u32 length = rgb.TableLen;
|
||||
for (u32 i=0; i<length; ++i)
|
||||
{
|
||||
rgb.StartTable[i] = os::Byteswap::byteswap(rgb.StartTable[i]);
|
||||
rgb.LengthTable[i] = os::Byteswap::byteswap(rgb.LengthTable[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
The Header has already been read into rgb structure
|
||||
The Tables have been read if necessary
|
||||
Now process the actual data
|
||||
*/
|
||||
void CImageLoaderRGB::processFile(io::IReadFile* file, rgbStruct& rgb) const
|
||||
{
|
||||
u16 *tempShort;
|
||||
|
||||
// calculate the size of the buffer needed: XSIZE * YSIZE * ZSIZE * BPC
|
||||
rgb.rgbData = new u8 [(rgb.Header.Xsize)*(rgb.Header.Ysize)*(rgb.Header.Zsize)*(rgb.Header.BPC)];
|
||||
u8 *ptr = rgb.rgbData;
|
||||
|
||||
// cycle through all scanlines
|
||||
|
||||
#ifdef _IRR_RGB_FILE_INVERTED_IMAGE_
|
||||
// preserve the image as stored, eg, inverted
|
||||
for (u32 i = 0; i < rgb.Header.Ysize; ++i)
|
||||
#else
|
||||
// invert the image to make it upright
|
||||
for (s32 i = (s32)(rgb.Header.Ysize)-1; i>=0; --i)
|
||||
#endif
|
||||
{
|
||||
// check the number of channels and read a row of data
|
||||
if (rgb.Header.Zsize >= 1)
|
||||
readRGBrow( rgb.tmpR, i, 0, file, rgb);
|
||||
if (rgb.Header.Zsize >= 2)
|
||||
readRGBrow( rgb.tmpG, i, 1, file, rgb);
|
||||
if (rgb.Header.Zsize >= 3)
|
||||
readRGBrow( rgb.tmpB, i, 2, file, rgb);
|
||||
if (rgb.Header.Zsize >= 4)
|
||||
readRGBrow( rgb.tmpA, i, 3, file, rgb);
|
||||
|
||||
// cycle thru all values for this row
|
||||
for (u32 j = 0; j < rgb.Header.Xsize; ++j)
|
||||
{
|
||||
if(rgb.Header.BPC == 1)
|
||||
{
|
||||
// ONE byte per color
|
||||
if (rgb.Header.Zsize >= 1)
|
||||
*ptr++ = rgb.tmpR[j];
|
||||
if (rgb.Header.Zsize >= 2)
|
||||
*ptr++ = rgb.tmpG[j];
|
||||
if (rgb.Header.Zsize >= 3)
|
||||
*ptr++ = rgb.tmpB[j];
|
||||
if (rgb.Header.Zsize >= 4)
|
||||
*ptr++ = rgb.tmpA[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
// TWO bytes per color
|
||||
if( rgb.Header.Zsize >= 1 )
|
||||
{
|
||||
// two bytes of color data
|
||||
tempShort = (u16 *) (ptr);
|
||||
*tempShort = *( (u16 *) (rgb.tmpR) + j);
|
||||
tempShort++;
|
||||
ptr = ( u8 *)(tempShort);
|
||||
}
|
||||
if( rgb.Header.Zsize >= 2 )
|
||||
{
|
||||
tempShort = ( u16 *) (ptr);
|
||||
*tempShort = *( ( u16 *) (rgb.tmpG) + j);
|
||||
tempShort++;
|
||||
ptr = ( u8 *) (tempShort);
|
||||
}
|
||||
if( rgb.Header.Zsize >= 3 )
|
||||
{
|
||||
tempShort = ( u16 *) (ptr);
|
||||
*tempShort = *( ( u16 *) (rgb.tmpB) + j);
|
||||
tempShort++;
|
||||
ptr = ( u8 *)(tempShort);
|
||||
}
|
||||
if( rgb.Header.Zsize >= 4 )
|
||||
{
|
||||
tempShort = ( u16 *) (ptr);
|
||||
*tempShort = *( ( u16 *) (rgb.tmpA) + j);
|
||||
tempShort++;
|
||||
ptr = ( u8 *)(tempShort);
|
||||
}
|
||||
} // end if(rgb.Header.BPC == 1)
|
||||
} // end for
|
||||
} // end for
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This information only applies if the value for STORAGE is 1. If the image is
|
||||
stored using run length encoding, the image data follows the offset/length tables.
|
||||
The RLE data is not in any particular order. The offset tables are used to
|
||||
locate the rle data for any scanline.
|
||||
|
||||
The RLE data must be read in from the file and expanded into pixel data in the following manner:
|
||||
|
||||
If BPC is 1, then there is one byte per pixel. In this case the RLE data should be
|
||||
read into an array of chars. To expand data, the low order seven bits of the first
|
||||
byte: bits[6..0] are used to form a count. If the high order bit of the first byte
|
||||
is 1: bit[7], then the count is used to specify how many bytes to copy from the RLE
|
||||
data buffer to the destination. Otherwise, if the high order bit of the first byte
|
||||
is 0: bit[7], then the count is used to specify how many times to repeat the value
|
||||
of the following byte, in the destination. This process continues until a count
|
||||
of 0 is found. This should decompress exactly XSIZE pixels.
|
||||
|
||||
|
||||
One entry in each table is needed for each scanline of RLE data. The total number of
|
||||
scanlines in the image (tablen) is determined by the product of the YSIZE and ZSIZE.
|
||||
There are two tables of longs that are written. Each consists of tablen longs of data.
|
||||
The first table has the file offsets to the RLE data for each scanline in the image. In
|
||||
a file with more than 1 channel (ZSIZE > 1) this table first has all the offsets for the
|
||||
scanlines in the first channel, followed be offsets for the scanlines in the second
|
||||
channel, etc. The second table has the RLE data length for each scanline in the image.
|
||||
In a file with more than 1 channel (ZSIZE > 1) this table first has all the RLE data
|
||||
lengths for the scanlines in the first channel, followed be RLE data lengths for the
|
||||
scanlines in the second channel, etc.
|
||||
|
||||
Return a row of data, expanding RLE compression if necessary
|
||||
*/
|
||||
void CImageLoaderRGB::readRGBrow(u8 *buf, int y, int z, io::IReadFile* file, rgbStruct& rgb) const
|
||||
{
|
||||
if (rgb.Header.Storage != 1)
|
||||
{
|
||||
// stored VERBATIM
|
||||
|
||||
file->seek(512+(y*rgb.Header.Xsize * rgb.Header.BPC)+(z* rgb.Header.Xsize * rgb.Header.Ysize * rgb.Header.BPC));
|
||||
file->read(buf, rgb.Header.Xsize * rgb.Header.BPC);
|
||||
|
||||
#ifndef __BIG_ENDIAN__
|
||||
if (rgb.Header.BPC != 1)
|
||||
{
|
||||
u16* tmpbuf = reinterpret_cast<u16*>(buf);
|
||||
for (u32 i=0; i<rgb.Header.Xsize; ++i)
|
||||
tmpbuf[i] = os::Byteswap::byteswap(tmpbuf[i]);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// the file is stored as Run Length Encoding (RLE)
|
||||
// each sequence is stored as 0x80 NumRepeats ByteToRepeat
|
||||
|
||||
// get the file offset from StartTable and SEEK
|
||||
// then read the data
|
||||
|
||||
file->seek((long) rgb.StartTable[y+z * rgb.Header.Ysize]);
|
||||
file->read(rgb.tmp, rgb.LengthTable[y+z * rgb.Header.Ysize]);
|
||||
|
||||
// rgb.tmp has the data
|
||||
|
||||
u16 pixel;
|
||||
u16 *tempShort;
|
||||
u8* iPtr = rgb.tmp;
|
||||
u8* oPtr = buf;
|
||||
while (true)
|
||||
{
|
||||
// if BPC = 1, then one byte per pixel
|
||||
if (rgb.Header.BPC == 1)
|
||||
{
|
||||
pixel = *iPtr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// BPC = 2, so two bytes per pixel
|
||||
tempShort = (u16 *) iPtr;
|
||||
pixel = *tempShort;
|
||||
tempShort++;
|
||||
iPtr = (u8 *) tempShort;
|
||||
}
|
||||
|
||||
#ifndef __BIG_ENDIAN__
|
||||
if (rgb.Header.BPC != 1)
|
||||
pixel = os::Byteswap::byteswap(pixel);
|
||||
#endif
|
||||
|
||||
s32 count = (s32)(pixel & 0x7F);
|
||||
|
||||
// limit the count value to the remaining row size
|
||||
if (oPtr + count*rgb.Header.BPC > buf + rgb.Header.Xsize * rgb.Header.BPC)
|
||||
{
|
||||
count = ( (buf + rgb.Header.Xsize * rgb.Header.BPC) - oPtr ) / rgb.Header.BPC;
|
||||
}
|
||||
|
||||
if (count<=0)
|
||||
break;
|
||||
else if (pixel & 0x80)
|
||||
{
|
||||
// repeat the byte pointed to by iPtr, count times
|
||||
while (count--)
|
||||
{
|
||||
if(rgb.Header.BPC == 1)
|
||||
{
|
||||
*oPtr++ = *iPtr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// write pixel from iPtr to oPtr, move both two bytes ahead
|
||||
tempShort = (u16 *) (iPtr);
|
||||
pixel = *tempShort;
|
||||
tempShort++;
|
||||
iPtr = (u8 *) (tempShort);
|
||||
#ifndef __BIG_ENDIAN__
|
||||
pixel = os::Byteswap::byteswap(pixel);
|
||||
#endif
|
||||
tempShort = (u16 *) (oPtr);
|
||||
*tempShort = pixel;
|
||||
tempShort++;
|
||||
oPtr = (u8 *) (tempShort);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rgb.Header.BPC == 1)
|
||||
{
|
||||
pixel = *iPtr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempShort = (u16 *) (iPtr);
|
||||
pixel = *tempShort;
|
||||
tempShort++;
|
||||
iPtr = (u8 *) (tempShort);
|
||||
}
|
||||
|
||||
#ifndef __BIG_ENDIAN__
|
||||
if (rgb.Header.BPC != 1)
|
||||
pixel = os::Byteswap::byteswap(pixel);
|
||||
#endif
|
||||
|
||||
while (count--)
|
||||
{
|
||||
if(rgb.Header.BPC == 1)
|
||||
{
|
||||
*oPtr++ = (u8) pixel;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempShort = (u16 *) (oPtr);
|
||||
*tempShort = pixel;
|
||||
tempShort++;
|
||||
oPtr = (u8 *) (tempShort);
|
||||
}
|
||||
}
|
||||
} // else if (pixel & 0x80)
|
||||
} // while (true)
|
||||
}
|
||||
|
||||
|
||||
// we have 1 byte per COLOR VALUE, eg 24bpp and 1 alpha channel
|
||||
// color values are stored as RGBA, convert to ARGB
|
||||
// todo: replace with CColorConverter method
|
||||
void CImageLoaderRGB::converttoARGB(u32* in, const u32 size) const
|
||||
{
|
||||
for (u32 x=0; x < size; ++x)
|
||||
{
|
||||
*in=(*in>>8)|(*in<<24);
|
||||
++in;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! creates a loader which is able to load SGI RGB images
|
||||
IImageLoader* createImageLoaderRGB()
|
||||
{
|
||||
return new CImageLoaderRGB;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
||||
|
@ -1,165 +0,0 @@
|
||||
// Copyright (C) 2009-2012 Gary Conway
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
|
||||
/*
|
||||
Author: Gary Conway (Viper) - co-author of the ZIP file format, Feb 1989,
|
||||
see the story at http://www.idcnet.us/ziphistory.html
|
||||
Website: http://idcnet.us
|
||||
Email: codeslinger@vipergc.com
|
||||
Created: March 1, 2009
|
||||
Version: 1.0
|
||||
Updated:
|
||||
*/
|
||||
|
||||
#ifndef __C_IMAGE_LOADER_RGB_H_INCLUDED__
|
||||
#define __C_IMAGE_LOADER_RGB_H_INCLUDED__
|
||||
|
||||
// define _IRR_RGB_FILE_INVERTED_IMAGE_ to preserve the inverted format of the RGB file
|
||||
// commenting this out will invert the inverted image,resulting in the image being upright
|
||||
#define _IRR_RGB_FILE_INVERTED_IMAGE_
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_RGB_LOADER_
|
||||
|
||||
#include "IImageLoader.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
// byte-align structures
|
||||
#include "irrpack.h"
|
||||
|
||||
// the RGB image file header structure
|
||||
|
||||
struct SRGBHeader
|
||||
{
|
||||
u16 Magic; // IRIS image file magic number
|
||||
u8 Storage; // Storage format
|
||||
u8 BPC; // Number of bytes per pixel channel
|
||||
u16 Dimension; // Number of dimensions
|
||||
u16 Xsize; // X size in pixels
|
||||
u16 Ysize; // Y size in pixels
|
||||
u16 Zsize; // Z size in pixels
|
||||
u32 Pixmin; // Minimum pixel value
|
||||
u32 Pixmax; // Maximum pixel value
|
||||
u32 Dummy1; // ignored
|
||||
char Imagename[80];// Image name
|
||||
u32 Colormap; // Colormap ID
|
||||
// char Dummy2[404];// Ignored
|
||||
} PACK_STRUCT;
|
||||
|
||||
// Default alignment
|
||||
#include "irrunpack.h"
|
||||
|
||||
// this structure holds context specific data about the file being loaded.
|
||||
|
||||
typedef struct _RGBdata
|
||||
{
|
||||
u8 *tmp,
|
||||
*tmpR,
|
||||
*tmpG,
|
||||
*tmpB,
|
||||
*tmpA;
|
||||
|
||||
|
||||
u32 *StartTable; // compressed data table, holds file offsets
|
||||
u32 *LengthTable; // length for the above data, hold lengths for above
|
||||
u32 TableLen; // len of above tables
|
||||
|
||||
SRGBHeader Header; // define the .rgb file header
|
||||
u32 ImageSize;
|
||||
u8 *rgbData;
|
||||
|
||||
public:
|
||||
_RGBdata() : tmp(0), tmpR(0), tmpG(0), tmpB(0), tmpA(0),
|
||||
StartTable(0), LengthTable(0), TableLen(0), ImageSize(0), rgbData(0)
|
||||
{
|
||||
}
|
||||
|
||||
~_RGBdata()
|
||||
{
|
||||
delete [] tmp;
|
||||
delete [] tmpR;
|
||||
delete [] tmpG;
|
||||
delete [] tmpB;
|
||||
delete [] tmpA;
|
||||
delete [] StartTable;
|
||||
delete [] LengthTable;
|
||||
delete [] rgbData;
|
||||
}
|
||||
|
||||
bool allocateTemps()
|
||||
{
|
||||
tmp = tmpR = tmpG = tmpB = tmpA = 0;
|
||||
tmp = new u8 [Header.Xsize * 256 * Header.BPC];
|
||||
if (!tmp)
|
||||
return false;
|
||||
|
||||
if (Header.Zsize >= 1)
|
||||
{
|
||||
tmpR = new u8[Header.Xsize * Header.BPC];
|
||||
if (!tmpR)
|
||||
return false;
|
||||
}
|
||||
if (Header.Zsize >= 2)
|
||||
{
|
||||
tmpG = new u8[Header.Xsize * Header.BPC];
|
||||
if (!tmpG)
|
||||
return false;
|
||||
}
|
||||
if (Header.Zsize >= 3)
|
||||
{
|
||||
tmpB = new u8[Header.Xsize * Header.BPC];
|
||||
if (!tmpB)
|
||||
return false;
|
||||
}
|
||||
if (Header.Zsize >= 4)
|
||||
{
|
||||
tmpA = new u8[Header.Xsize * Header.BPC];
|
||||
if (!tmpA)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} rgbStruct;
|
||||
|
||||
|
||||
//! Surface Loader for Silicon Graphics RGB files
|
||||
class CImageLoaderRGB : public IImageLoader
|
||||
{
|
||||
public:
|
||||
|
||||
//! constructor
|
||||
CImageLoaderRGB();
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".tga")
|
||||
virtual bool isALoadableFileExtension(const io::path& filename) const;
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
virtual bool isALoadableFileFormat(io::IReadFile* file) const;
|
||||
|
||||
//! creates a surface from the file
|
||||
virtual IImage* loadImage(io::IReadFile* file) const;
|
||||
|
||||
private:
|
||||
|
||||
bool readHeader(io::IReadFile* file, rgbStruct& rgb) const;
|
||||
void readRGBrow(u8 *buf, int y, int z, io::IReadFile* file, rgbStruct& rgb) const;
|
||||
void processFile(io::IReadFile *file, rgbStruct& rgb) const;
|
||||
bool checkFormat(io::IReadFile *file, rgbStruct& rgb) const;
|
||||
bool readOffsetTables(io::IReadFile* file, rgbStruct& rgb) const;
|
||||
void converttoARGB(u32* in, const u32 size) const;
|
||||
};
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
#endif // _IRR_COMPILE_WITH_RGB_LOADER_
|
||||
#endif // __C_IMAGE_LOADER_RGB_H_INCLUDED__
|
||||
|
@ -1,239 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "CImageLoaderTGA.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_TGA_LOADER_
|
||||
|
||||
#include "IReadFile.h"
|
||||
#include "os.h"
|
||||
#include "CColorConverter.h"
|
||||
#include "CImage.h"
|
||||
#include "irrString.h"
|
||||
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".tga")
|
||||
bool CImageLoaderTGA::isALoadableFileExtension(const io::path& filename) const
|
||||
{
|
||||
return core::hasFileExtension ( filename, "tga" );
|
||||
}
|
||||
|
||||
|
||||
//! loads a compressed tga.
|
||||
u8 *CImageLoaderTGA::loadCompressedImage(io::IReadFile *file, const STGAHeader& header) const
|
||||
{
|
||||
// This was written and sent in by Jon Pry, thank you very much!
|
||||
// I only changed the formatting a little bit.
|
||||
|
||||
s32 bytesPerPixel = header.PixelDepth/8;
|
||||
s32 imageSize = header.ImageHeight * header.ImageWidth * bytesPerPixel;
|
||||
u8* data = new u8[imageSize];
|
||||
s32 currentByte = 0;
|
||||
|
||||
while(currentByte < imageSize)
|
||||
{
|
||||
u8 chunkheader = 0;
|
||||
file->read(&chunkheader, sizeof(u8)); // Read The Chunk's Header
|
||||
|
||||
if(chunkheader < 128) // If The Chunk Is A 'RAW' Chunk
|
||||
{
|
||||
chunkheader++; // Add 1 To The Value To Get Total Number Of Raw Pixels
|
||||
|
||||
file->read(&data[currentByte], bytesPerPixel * chunkheader);
|
||||
currentByte += bytesPerPixel * chunkheader;
|
||||
}
|
||||
else
|
||||
{
|
||||
// thnx to neojzs for some fixes with this code
|
||||
|
||||
// If It's An RLE Header
|
||||
chunkheader -= 127; // Subtract 127 To Get Rid Of The ID Bit
|
||||
|
||||
s32 dataOffset = currentByte;
|
||||
file->read(&data[dataOffset], bytesPerPixel);
|
||||
|
||||
currentByte += bytesPerPixel;
|
||||
|
||||
for(s32 counter = 1; counter < chunkheader; counter++)
|
||||
{
|
||||
for(s32 elementCounter=0; elementCounter < bytesPerPixel; elementCounter++)
|
||||
data[currentByte + elementCounter] = data[dataOffset + elementCounter];
|
||||
|
||||
currentByte += bytesPerPixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
bool CImageLoaderTGA::isALoadableFileFormat(io::IReadFile* file) const
|
||||
{
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
STGAFooter footer;
|
||||
memset(&footer, 0, sizeof(STGAFooter));
|
||||
file->seek(file->getSize()-sizeof(STGAFooter));
|
||||
file->read(&footer, sizeof(STGAFooter));
|
||||
return (!strcmp(footer.Signature,"TRUEVISION-XFILE.")); // very old tgas are refused.
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! creates a surface from the file
|
||||
IImage* CImageLoaderTGA::loadImage(io::IReadFile* file) const
|
||||
{
|
||||
STGAHeader header;
|
||||
u32 *palette = 0;
|
||||
|
||||
file->read(&header, sizeof(STGAHeader));
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
header.ColorMapLength = os::Byteswap::byteswap(header.ColorMapLength);
|
||||
header.ImageWidth = os::Byteswap::byteswap(header.ImageWidth);
|
||||
header.ImageHeight = os::Byteswap::byteswap(header.ImageHeight);
|
||||
#endif
|
||||
|
||||
// skip image identification field
|
||||
if (header.IdLength)
|
||||
file->seek(header.IdLength, true);
|
||||
|
||||
if (header.ColorMapType)
|
||||
{
|
||||
// create 32 bit palette
|
||||
palette = new u32[ header.ColorMapLength];
|
||||
|
||||
// read color map
|
||||
u8 * colorMap = new u8[header.ColorMapEntrySize/8 * header.ColorMapLength];
|
||||
file->read(colorMap,header.ColorMapEntrySize/8 * header.ColorMapLength);
|
||||
|
||||
// convert to 32-bit palette
|
||||
switch ( header.ColorMapEntrySize )
|
||||
{
|
||||
case 16:
|
||||
CColorConverter::convert_A1R5G5B5toA8R8G8B8(colorMap, header.ColorMapLength, palette);
|
||||
break;
|
||||
case 24:
|
||||
CColorConverter::convert_B8G8R8toA8R8G8B8(colorMap, header.ColorMapLength, palette);
|
||||
break;
|
||||
case 32:
|
||||
CColorConverter::convert_B8G8R8A8toA8R8G8B8(colorMap, header.ColorMapLength, palette);
|
||||
break;
|
||||
}
|
||||
delete [] colorMap;
|
||||
}
|
||||
|
||||
// read image
|
||||
|
||||
u8* data = 0;
|
||||
|
||||
if ( header.ImageType == 1 || // Uncompressed, color-mapped images.
|
||||
header.ImageType == 2 || // Uncompressed, RGB images
|
||||
header.ImageType == 3 // Uncompressed, black and white images
|
||||
)
|
||||
{
|
||||
const s32 imageSize = header.ImageHeight * header.ImageWidth * header.PixelDepth/8;
|
||||
data = new u8[imageSize];
|
||||
file->read(data, imageSize);
|
||||
}
|
||||
else
|
||||
if(header.ImageType == 10)
|
||||
{
|
||||
// Runlength encoded RGB images
|
||||
data = loadCompressedImage(file, header);
|
||||
}
|
||||
else
|
||||
{
|
||||
os::Printer::log("Unsupported TGA file type", file->getFileName(), ELL_ERROR);
|
||||
delete [] palette;
|
||||
return 0;
|
||||
}
|
||||
|
||||
IImage* image = 0;
|
||||
|
||||
switch(header.PixelDepth)
|
||||
{
|
||||
case 8:
|
||||
{
|
||||
if (header.ImageType==3) // grey image
|
||||
{
|
||||
image = new CImage(ECF_R8G8B8,
|
||||
core::dimension2d<u32>(header.ImageWidth, header.ImageHeight));
|
||||
if (image)
|
||||
CColorConverter::convert8BitTo24Bit((u8*)data,
|
||||
(u8*)image->lock(),
|
||||
header.ImageWidth,header.ImageHeight,
|
||||
0, 0, (header.ImageDescriptor&0x20)==0);
|
||||
}
|
||||
else
|
||||
{
|
||||
image = new CImage(ECF_A1R5G5B5,
|
||||
core::dimension2d<u32>(header.ImageWidth, header.ImageHeight));
|
||||
if (image)
|
||||
CColorConverter::convert8BitTo16Bit((u8*)data,
|
||||
(s16*)image->lock(),
|
||||
header.ImageWidth,header.ImageHeight,
|
||||
(s32*) palette, 0,
|
||||
(header.ImageDescriptor&0x20)==0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
image = new CImage(ECF_A1R5G5B5,
|
||||
core::dimension2d<u32>(header.ImageWidth, header.ImageHeight));
|
||||
if (image)
|
||||
CColorConverter::convert16BitTo16Bit((s16*)data,
|
||||
(s16*)image->lock(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0);
|
||||
break;
|
||||
case 24:
|
||||
image = new CImage(ECF_R8G8B8,
|
||||
core::dimension2d<u32>(header.ImageWidth, header.ImageHeight));
|
||||
if (image)
|
||||
CColorConverter::convert24BitTo24Bit(
|
||||
(u8*)data, (u8*)image->lock(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0, true);
|
||||
break;
|
||||
case 32:
|
||||
image = new CImage(ECF_A8R8G8B8,
|
||||
core::dimension2d<u32>(header.ImageWidth, header.ImageHeight));
|
||||
if (image)
|
||||
CColorConverter::convert32BitTo32Bit((s32*)data,
|
||||
(s32*)image->lock(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0);
|
||||
break;
|
||||
default:
|
||||
os::Printer::log("Unsupported TGA format", file->getFileName(), ELL_ERROR);
|
||||
break;
|
||||
}
|
||||
if (image)
|
||||
image->unlock();
|
||||
|
||||
delete [] data;
|
||||
delete [] palette;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
//! creates a loader which is able to load tgas
|
||||
IImageLoader* createImageLoaderTGA()
|
||||
{
|
||||
return new CImageLoaderTGA();
|
||||
}
|
||||
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
||||
|
@ -1,82 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef __C_IMAGE_LOADER_TGA_H_INCLUDED__
|
||||
#define __C_IMAGE_LOADER_TGA_H_INCLUDED__
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
|
||||
#include "IImageLoader.h"
|
||||
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_TGA_LOADER_) || defined(_IRR_COMPILE_WITH_TGA_WRITER_)
|
||||
|
||||
// byte-align structures
|
||||
#include "irrpack.h"
|
||||
|
||||
// these structs are also used in the TGA writer
|
||||
struct STGAHeader{
|
||||
u8 IdLength;
|
||||
u8 ColorMapType;
|
||||
u8 ImageType;
|
||||
u8 FirstEntryIndex[2];
|
||||
u16 ColorMapLength;
|
||||
u8 ColorMapEntrySize;
|
||||
u8 XOrigin[2];
|
||||
u8 YOrigin[2];
|
||||
u16 ImageWidth;
|
||||
u16 ImageHeight;
|
||||
u8 PixelDepth;
|
||||
u8 ImageDescriptor;
|
||||
} PACK_STRUCT;
|
||||
|
||||
struct STGAFooter
|
||||
{
|
||||
u32 ExtensionOffset;
|
||||
u32 DeveloperOffset;
|
||||
c8 Signature[18];
|
||||
} PACK_STRUCT;
|
||||
|
||||
// Default alignment
|
||||
#include "irrunpack.h"
|
||||
|
||||
#endif // compiled with loader or reader
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_TGA_LOADER_
|
||||
|
||||
/*!
|
||||
Surface Loader for targa images
|
||||
*/
|
||||
class CImageLoaderTGA : public IImageLoader
|
||||
{
|
||||
public:
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".tga")
|
||||
virtual bool isALoadableFileExtension(const io::path& filename) const;
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
virtual bool isALoadableFileFormat(io::IReadFile* file) const;
|
||||
|
||||
//! creates a surface from the file
|
||||
virtual IImage* loadImage(io::IReadFile* file) const;
|
||||
|
||||
private:
|
||||
|
||||
//! loads a compressed tga. Was written and sent in by Jon Pry, thank you very much!
|
||||
u8* loadCompressedImage(io::IReadFile *file, const STGAHeader& header) const;
|
||||
};
|
||||
|
||||
#endif // compiled with loader
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
||||
|
@ -1,285 +0,0 @@
|
||||
// Copyright (C) 2004 Murphy McCauley
|
||||
// Copyright (C) 2007-2012 Christian Stehno
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "CImageLoaderWAL.h"
|
||||
|
||||
#include "CColorConverter.h"
|
||||
#include "CImage.h"
|
||||
#include "os.h"
|
||||
#include "dimension2d.h"
|
||||
#include "IVideoDriver.h"
|
||||
#include "IFileSystem.h"
|
||||
#include "IReadFile.h"
|
||||
#include "irrString.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_LMP_LOADER_
|
||||
|
||||
// Palette quake2 colormap.h, 768 byte, last is transparent
|
||||
static const u32 colormap_h[256] = {
|
||||
0xFF000000,0xFF0F0F0F,0xFF1F1F1F,0xFF2F2F2F,0xFF3F3F3F,0xFF4B4B4B,0xFF5B5B5B,0xFF6B6B6B,
|
||||
0xFF7B7B7B,0xFF8B8B8B,0xFF9B9B9B,0xFFABABAB,0xFFBBBBBB,0xFFCBCBCB,0xFFDBDBDB,0xFFEBEBEB,
|
||||
0xFF0F0B07,0xFF170F0B,0xFF1F170B,0xFF271B0F,0xFF2F2313,0xFF372B17,0xFF3F2F17,0xFF4B371B,
|
||||
0xFF533B1B,0xFF5B431F,0xFF634B1F,0xFF6B531F,0xFF73571F,0xFF7B5F23,0xFF836723,0xFF8F6F23,
|
||||
0xFF0B0B0F,0xFF13131B,0xFF1B1B27,0xFF272733,0xFF2F2F3F,0xFF37374B,0xFF3F3F57,0xFF474767,
|
||||
0xFF4F4F73,0xFF5B5B7F,0xFF63638B,0xFF6B6B97,0xFF7373A3,0xFF7B7BAF,0xFF8383BB,0xFF8B8BCB,
|
||||
0xFF000000,0xFF070700,0xFF0B0B00,0xFF131300,0xFF1B1B00,0xFF232300,0xFF2B2B07,0xFF2F2F07,
|
||||
0xFF373707,0xFF3F3F07,0xFF474707,0xFF4B4B0B,0xFF53530B,0xFF5B5B0B,0xFF63630B,0xFF6B6B0F,
|
||||
0xFF070000,0xFF0F0000,0xFF170000,0xFF1F0000,0xFF270000,0xFF2F0000,0xFF370000,0xFF3F0000,
|
||||
0xFF470000,0xFF4F0000,0xFF570000,0xFF5F0000,0xFF670000,0xFF6F0000,0xFF770000,0xFF7F0000,
|
||||
0xFF131300,0xFF1B1B00,0xFF232300,0xFF2F2B00,0xFF372F00,0xFF433700,0xFF4B3B07,0xFF574307,
|
||||
0xFF5F4707,0xFF6B4B0B,0xFF77530F,0xFF835713,0xFF8B5B13,0xFF975F1B,0xFFA3631F,0xFFAF6723,
|
||||
0xFF231307,0xFF2F170B,0xFF3B1F0F,0xFF4B2313,0xFF572B17,0xFF632F1F,0xFF733723,0xFF7F3B2B,
|
||||
0xFF8F4333,0xFF9F4F33,0xFFAF632F,0xFFBF772F,0xFFCF8F2B,0xFFDFAB27,0xFFEFCB1F,0xFFFFF31B,
|
||||
0xFF0B0700,0xFF1B1300,0xFF2B230F,0xFF372B13,0xFF47331B,0xFF533723,0xFF633F2B,0xFF6F4733,
|
||||
0xFF7F533F,0xFF8B5F47,0xFF9B6B53,0xFFA77B5F,0xFFB7876B,0xFFC3937B,0xFFD3A38B,0xFFE3B397,
|
||||
0xFFAB8BA3,0xFF9F7F97,0xFF937387,0xFF8B677B,0xFF7F5B6F,0xFF775363,0xFF6B4B57,0xFF5F3F4B,
|
||||
0xFF573743,0xFF4B2F37,0xFF43272F,0xFF371F23,0xFF2B171B,0xFF231313,0xFF170B0B,0xFF0F0707,
|
||||
0xFFBB739F,0xFFAF6B8F,0xFFA35F83,0xFF975777,0xFF8B4F6B,0xFF7F4B5F,0xFF734353,0xFF6B3B4B,
|
||||
0xFF5F333F,0xFF532B37,0xFF47232B,0xFF3B1F23,0xFF2F171B,0xFF231313,0xFF170B0B,0xFF0F0707,
|
||||
0xFFDBC3BB,0xFFCBB3A7,0xFFBFA39B,0xFFAF978B,0xFFA3877B,0xFF977B6F,0xFF876F5F,0xFF7B6353,
|
||||
0xFF6B5747,0xFF5F4B3B,0xFF533F33,0xFF433327,0xFF372B1F,0xFF271F17,0xFF1B130F,0xFF0F0B07,
|
||||
0xFF6F837B,0xFF677B6F,0xFF5F7367,0xFF576B5F,0xFF4F6357,0xFF475B4F,0xFF3F5347,0xFF374B3F,
|
||||
0xFF2F4337,0xFF2B3B2F,0xFF233327,0xFF1F2B1F,0xFF172317,0xFF0F1B13,0xFF0B130B,0xFF070B07,
|
||||
0xFFFFF31B,0xFFEFDF17,0xFFDBCB13,0xFFCBB70F,0xFFBBA70F,0xFFAB970B,0xFF9B8307,0xFF8B7307,
|
||||
0xFF7B6307,0xFF6B5300,0xFF5B4700,0xFF4B3700,0xFF3B2B00,0xFF2B1F00,0xFF1B0F00,0xFF0B0700,
|
||||
0xFF0000FF,0xFF0B0BEF,0xFF1313DF,0xFF1B1BCF,0xFF2323BF,0xFF2B2BAF,0xFF2F2F9F,0xFF2F2F8F,
|
||||
0xFF2F2F7F,0xFF2F2F6F,0xFF2F2F5F,0xFF2B2B4F,0xFF23233F,0xFF1B1B2F,0xFF13131F,0xFF0B0B0F,
|
||||
0xFF2B0000,0xFF3B0000,0xFF4B0700,0xFF5F0700,0xFF6F0F00,0xFF7F1707,0xFF931F07,0xFFA3270B,
|
||||
0xFFB7330F,0xFFC34B1B,0xFFCF632B,0xFFDB7F3B,0xFFE3974F,0xFFE7AB5F,0xFFEFBF77,0xFFF7D38B,
|
||||
0xFFA77B3B,0xFFB79B37,0xFFC7C337,0xFFE7E357,0xFF7FBFFF,0xFFABE7FF,0xFFD7FFFF,0xFF670000,
|
||||
0xFF8B0000,0xFFB30000,0xFFD70000,0xFFFF0000,0xFFFFF393,0xFFFFF7C7,0xFFFFFFFF,0x009F5B53
|
||||
};
|
||||
|
||||
bool CImageLoaderLMP::isALoadableFileExtension(const io::path& filename) const
|
||||
{
|
||||
return core::hasFileExtension ( filename, "lmp" );
|
||||
}
|
||||
|
||||
|
||||
bool CImageLoaderLMP::isALoadableFileFormat(irr::io::IReadFile* file) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
Quake1, Quake2, Hallife lmp texture
|
||||
*/
|
||||
IImage* CImageLoaderLMP::loadImage(irr::io::IReadFile* file) const
|
||||
{
|
||||
SLMPHeader header;
|
||||
|
||||
file->seek(0);
|
||||
file->read(&header, sizeof(header));
|
||||
|
||||
// maybe palette file
|
||||
u32 rawtexsize = header.width * header.height;
|
||||
if ( rawtexsize + sizeof ( header ) != (u32)file->getSize() )
|
||||
return 0;
|
||||
|
||||
u8 *rawtex = new u8 [ rawtexsize ];
|
||||
|
||||
file->read(rawtex, rawtexsize);
|
||||
|
||||
IImage* image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(header.width, header.height));
|
||||
|
||||
CColorConverter::convert8BitTo32Bit(rawtex, (u8*)image->lock(), header.width, header.height, (u8*) colormap_h, 0, false);
|
||||
image->unlock();
|
||||
|
||||
delete [] rawtex;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
IImageLoader* createImageLoaderLMP()
|
||||
{
|
||||
return new irr::video::CImageLoaderLMP();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_WAL_LOADER_
|
||||
|
||||
// Palette quake2 demo pics/colormap.pcx, last is transparent
|
||||
static const u32 colormap_pcx[256] = {
|
||||
0xFF000000,0xFF0F0F0F,0xFF1F1F1F,0xFF2F2F2F,0xFF3F3F3F,0xFF4B4B4B,0xFF5B5B5B,0xFF6B6B6B,
|
||||
0xFF7B7B7B,0xFF8B8B8B,0xFF9B9B9B,0xFFABABAB,0xFFBBBBBB,0xFFCBCBCB,0xFFDBDBDB,0xFFEBEBEB,
|
||||
0xFF634B23,0xFF5B431F,0xFF533F1F,0xFF4F3B1B,0xFF47371B,0xFF3F2F17,0xFF3B2B17,0xFF332713,
|
||||
0xFF2F2313,0xFF2B1F13,0xFF271B0F,0xFF23170F,0xFF1B130B,0xFF170F0B,0xFF130F07,0xFF0F0B07,
|
||||
0xFF5F5F6F,0xFF5B5B67,0xFF5B535F,0xFF574F5B,0xFF534B53,0xFF4F474B,0xFF473F43,0xFF3F3B3B,
|
||||
0xFF3B3737,0xFF332F2F,0xFF2F2B2B,0xFF272727,0xFF232323,0xFF1B1B1B,0xFF171717,0xFF131313,
|
||||
0xFF8F7753,0xFF7B6343,0xFF735B3B,0xFF674F2F,0xFFCF974B,0xFFA77B3B,0xFF8B672F,0xFF6F5327,
|
||||
0xFFEB9F27,0xFFCB8B23,0xFFAF771F,0xFF93631B,0xFF774F17,0xFF5B3B0F,0xFF3F270B,0xFF231707,
|
||||
0xFFA73B2B,0xFF9F2F23,0xFF972B1B,0xFF8B2713,0xFF7F1F0F,0xFF73170B,0xFF671707,0xFF571300,
|
||||
0xFF4B0F00,0xFF430F00,0xFF3B0F00,0xFF330B00,0xFF2B0B00,0xFF230B00,0xFF1B0700,0xFF130700,
|
||||
0xFF7B5F4B,0xFF735743,0xFF6B533F,0xFF674F3B,0xFF5F4737,0xFF574333,0xFF533F2F,0xFF4B372B,
|
||||
0xFF433327,0xFF3F2F23,0xFF37271B,0xFF2F2317,0xFF271B13,0xFF1F170F,0xFF170F0B,0xFF0F0B07,
|
||||
0xFF6F3B17,0xFF5F3717,0xFF532F17,0xFF432B17,0xFF372313,0xFF271B0F,0xFF1B130B,0xFF0F0B07,
|
||||
0xFFB35B4F,0xFFBF7B6F,0xFFCB9B93,0xFFD7BBB7,0xFFCBD7DF,0xFFB3C7D3,0xFF9FB7C3,0xFF87A7B7,
|
||||
0xFF7397A7,0xFF5B879B,0xFF47778B,0xFF2F677F,0xFF17536F,0xFF134B67,0xFF0F435B,0xFF0B3F53,
|
||||
0xFF07374B,0xFF072F3F,0xFF072733,0xFF001F2B,0xFF00171F,0xFF000F13,0xFF00070B,0xFF000000,
|
||||
0xFF8B5757,0xFF834F4F,0xFF7B4747,0xFF734343,0xFF6B3B3B,0xFF633333,0xFF5B2F2F,0xFF572B2B,
|
||||
0xFF4B2323,0xFF3F1F1F,0xFF331B1B,0xFF2B1313,0xFF1F0F0F,0xFF130B0B,0xFF0B0707,0xFF000000,
|
||||
0xFF979F7B,0xFF8F9773,0xFF878B6B,0xFF7F8363,0xFF777B5F,0xFF737357,0xFF6B6B4F,0xFF636347,
|
||||
0xFF5B5B43,0xFF4F4F3B,0xFF434333,0xFF37372B,0xFF2F2F23,0xFF23231B,0xFF171713,0xFF0F0F0B,
|
||||
0xFF9F4B3F,0xFF934337,0xFF8B3B2F,0xFF7F3727,0xFF772F23,0xFF6B2B1B,0xFF632317,0xFF571F13,
|
||||
0xFF4F1B0F,0xFF43170B,0xFF37130B,0xFF2B0F07,0xFF1F0B07,0xFF170700,0xFF0B0000,0xFF000000,
|
||||
0xFF777BCF,0xFF6F73C3,0xFF676BB7,0xFF6363A7,0xFF5B5B9B,0xFF53578F,0xFF4B4F7F,0xFF474773,
|
||||
0xFF3F3F67,0xFF373757,0xFF2F2F4B,0xFF27273F,0xFF231F2F,0xFF1B1723,0xFF130F17,0xFF0B0707,
|
||||
0xFF9BAB7B,0xFF8F9F6F,0xFF879763,0xFF7B8B57,0xFF73834B,0xFF677743,0xFF5F6F3B,0xFF576733,
|
||||
0xFF4B5B27,0xFF3F4F1B,0xFF374313,0xFF2F3B0B,0xFF232F07,0xFF1B2300,0xFF131700,0xFF0B0F00,
|
||||
0xFF00FF00,0xFF23E70F,0xFF3FD31B,0xFF53BB27,0xFF5FA72F,0xFF5F8F33,0xFF5F7B33,0xFFFFFFFF,
|
||||
0xFFFFFFD3,0xFFFFFFA7,0xFFFFFF7F,0xFFFFFF53,0xFFFFFF27,0xFFFFEB1F,0xFFFFD717,0xFFFFBF0F,
|
||||
0xFFFFAB07,0xFFFF9300,0xFFEF7F00,0xFFE36B00,0xFFD35700,0xFFC74700,0xFFB73B00,0xFFAB2B00,
|
||||
0xFF9B1F00,0xFF8F1700,0xFF7F0F00,0xFF730700,0xFF5F0000,0xFF470000,0xFF2F0000,0xFF1B0000,
|
||||
0xFFEF0000,0xFF3737FF,0xFFFF0000,0xFF0000FF,0xFF2B2B23,0xFF1B1B17,0xFF13130F,0xFFEB977F,
|
||||
0xFFC37353,0xFF9F5733,0xFF7B3F1B,0xFFEBD3C7,0xFFC7AB9B,0xFFA78B77,0xFF876B57,0x009F5B53
|
||||
};
|
||||
|
||||
/*!
|
||||
Halflife
|
||||
*/
|
||||
bool CImageLoaderWAL2::isALoadableFileExtension(const io::path& filename) const
|
||||
{
|
||||
// embedded in Wad(WAD3 format). originally it has no extension
|
||||
return core::hasFileExtension ( filename, "wal2" );
|
||||
}
|
||||
|
||||
|
||||
bool CImageLoaderWAL2::isALoadableFileFormat(irr::io::IReadFile* file) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Halflite Texture WAD
|
||||
*/
|
||||
IImage* CImageLoaderWAL2::loadImage(irr::io::IReadFile* file) const
|
||||
{
|
||||
miptex_halflife header;
|
||||
|
||||
file->seek(0);
|
||||
file->read(&header, sizeof(header));
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
header.width = os::Byteswap::byteswap(header.width);
|
||||
header.height = os::Byteswap::byteswap(header.height);
|
||||
#endif
|
||||
|
||||
// palette
|
||||
//u32 paletteofs = header.mipmap[0] + ((rawtexsize * 85) >> 6) + 2;
|
||||
u32 *pal = new u32 [ 192 + 256 ];
|
||||
u8 *s = (u8*) pal;
|
||||
|
||||
file->seek ( file->getSize() - 768 - 2 );
|
||||
file->read ( s, 768 );
|
||||
u32 i;
|
||||
|
||||
for ( i = 0; i < 256; ++i, s+= 3 )
|
||||
{
|
||||
pal [ 192 + i ] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2];
|
||||
}
|
||||
|
||||
ECOLOR_FORMAT format = ECF_R8G8B8;
|
||||
|
||||
// transparency in filename;-) funny. rgb:0x0000FF is colorkey
|
||||
if ( file->getFileName().findFirst ( '{' ) >= 0 )
|
||||
{
|
||||
format = ECF_A8R8G8B8;
|
||||
pal [ 192 + 255 ] &= 0x00FFFFFF;
|
||||
}
|
||||
|
||||
u32 rawtexsize = header.width * header.height;
|
||||
|
||||
|
||||
u8 *rawtex = new u8 [ rawtexsize ];
|
||||
|
||||
file->seek ( header.mipmap[0] );
|
||||
file->read(rawtex, rawtexsize);
|
||||
|
||||
IImage* image = new CImage(format, core::dimension2d<u32>(header.width, header.height));
|
||||
|
||||
switch ( format )
|
||||
{
|
||||
case ECF_R8G8B8:
|
||||
CColorConverter::convert8BitTo24Bit(rawtex, (u8*)image->lock(), header.width, header.height, (u8*) pal + 768, 0, false);
|
||||
break;
|
||||
case ECF_A8R8G8B8:
|
||||
CColorConverter::convert8BitTo32Bit(rawtex, (u8*)image->lock(), header.width, header.height, (u8*) pal + 768, 0, false);
|
||||
break;
|
||||
}
|
||||
|
||||
image->unlock();
|
||||
|
||||
delete [] rawtex;
|
||||
delete [] pal;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
bool CImageLoaderWAL::isALoadableFileExtension(const io::path& filename) const
|
||||
{
|
||||
return core::hasFileExtension ( filename, "wal" );
|
||||
}
|
||||
|
||||
|
||||
bool CImageLoaderWAL::isALoadableFileFormat(irr::io::IReadFile* file) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
quake2
|
||||
*/
|
||||
IImage* CImageLoaderWAL::loadImage(irr::io::IReadFile* file) const
|
||||
{
|
||||
miptex_quake2 header;
|
||||
|
||||
file->seek(0);
|
||||
file->read(&header, sizeof(header));
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
header.width = os::Byteswap::byteswap(header.width);
|
||||
header.height = os::Byteswap::byteswap(header.height);
|
||||
#endif
|
||||
|
||||
u32 rawtexsize = header.width * header.height;
|
||||
|
||||
u8 *rawtex = new u8 [ rawtexsize ];
|
||||
|
||||
file->seek ( header.mipmap[0] );
|
||||
file->read(rawtex, rawtexsize);
|
||||
|
||||
IImage* image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(header.width, header.height));
|
||||
|
||||
CColorConverter::convert8BitTo32Bit(rawtex, (u8*)image->lock(), header.width, header.height, (u8*) colormap_pcx, 0, false);
|
||||
image->unlock();
|
||||
|
||||
delete [] rawtex;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
IImageLoader* createImageLoaderWAL()
|
||||
{
|
||||
return new irr::video::CImageLoaderWAL();
|
||||
}
|
||||
|
||||
IImageLoader* createImageLoaderHalfLife()
|
||||
{
|
||||
return new irr::video::CImageLoaderWAL2();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
@ -1,100 +0,0 @@
|
||||
// Copyright (C) 2004 Murphy McCauley
|
||||
// Copyright (C) 2007-2012 Christian Stehno
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
/*
|
||||
Thanks to:
|
||||
Max McGuire for his Flipcode article about WAL textures
|
||||
Nikolaus Gebhardt for the Irrlicht 3D engine
|
||||
*/
|
||||
|
||||
#ifndef __C_IMAGE_LOADER_WAL_H_INCLUDED__
|
||||
#define __C_IMAGE_LOADER_WAL_H_INCLUDED__
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
#include "IImageLoader.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_LMP_LOADER_
|
||||
|
||||
// byte-align structures
|
||||
#include "irrpack.h"
|
||||
|
||||
struct SLMPHeader {
|
||||
u32 width; // width
|
||||
u32 height; // height
|
||||
// variably sized
|
||||
} PACK_STRUCT;
|
||||
|
||||
// Default alignment
|
||||
#include "irrunpack.h"
|
||||
|
||||
//! An Irrlicht image loader for Quake1,2 engine lmp textures/palette
|
||||
class CImageLoaderLMP : public irr::video::IImageLoader
|
||||
{
|
||||
public:
|
||||
virtual bool isALoadableFileExtension(const io::path& filename) const;
|
||||
virtual bool isALoadableFileFormat(irr::io::IReadFile* file) const;
|
||||
virtual irr::video::IImage* loadImage(irr::io::IReadFile* file) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_WAL_LOADER_
|
||||
|
||||
//! An Irrlicht image loader for quake2 wal engine textures
|
||||
class CImageLoaderWAL : public irr::video::IImageLoader
|
||||
{
|
||||
public:
|
||||
virtual bool isALoadableFileExtension(const io::path& filename) const;
|
||||
virtual bool isALoadableFileFormat(irr::io::IReadFile* file) const;
|
||||
virtual irr::video::IImage* loadImage(irr::io::IReadFile* file) const;
|
||||
};
|
||||
|
||||
//! An Irrlicht image loader for Halflife 1 engine textures
|
||||
class CImageLoaderWAL2 : public irr::video::IImageLoader
|
||||
{
|
||||
public:
|
||||
virtual bool isALoadableFileExtension(const io::path& filename) const;
|
||||
virtual bool isALoadableFileFormat(irr::io::IReadFile* file) const;
|
||||
virtual irr::video::IImage* loadImage(irr::io::IReadFile* file) const;
|
||||
};
|
||||
|
||||
// byte-align structures
|
||||
#include "irrpack.h"
|
||||
|
||||
// Halfelife wad3 type 67 file
|
||||
struct miptex_halflife
|
||||
{
|
||||
c8 name[16];
|
||||
u32 width, height;
|
||||
u32 mipmap[4]; // four mip maps stored
|
||||
} PACK_STRUCT;
|
||||
|
||||
//quake2 texture
|
||||
struct miptex_quake2
|
||||
{
|
||||
c8 name[32];
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 mipmap[4]; // four mip maps stored
|
||||
c8 animname[32]; // next frame in animation chain
|
||||
s32 flags;
|
||||
s32 contents;
|
||||
s32 value;
|
||||
} PACK_STRUCT;
|
||||
|
||||
// Default alignment
|
||||
#include "irrunpack.h"
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,162 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "CImageWriterPCX.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_PCX_WRITER_
|
||||
|
||||
#include "CImageLoaderPCX.h"
|
||||
#include "IWriteFile.h"
|
||||
#include "os.h" // for logging
|
||||
#include "irrString.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
IImageWriter* createImageWriterPCX()
|
||||
{
|
||||
return new CImageWriterPCX;
|
||||
}
|
||||
|
||||
CImageWriterPCX::CImageWriterPCX()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CImageWriterPCX");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CImageWriterPCX::isAWriteableFileExtension(const io::path& filename) const
|
||||
{
|
||||
return core::hasFileExtension ( filename, "pcx" );
|
||||
}
|
||||
|
||||
bool CImageWriterPCX::writeImage(io::IWriteFile *file, IImage *image,u32 param) const
|
||||
{
|
||||
if (!file || !image)
|
||||
return false;
|
||||
|
||||
u8 d1;
|
||||
u16 d2;
|
||||
u32 i;
|
||||
|
||||
d1 = 10; // Manufacturer
|
||||
file->write(&d1, 1);
|
||||
d1 = 5; // Version
|
||||
file->write(&d1, 1);
|
||||
d1 = 1; // Encoding
|
||||
file->write(&d1, 1);
|
||||
d1 = 8; // Bits per Pixel
|
||||
file->write(&d1, 1);
|
||||
d2 = 0; // pixel origin
|
||||
file->write(&d2, 2);
|
||||
file->write(&d2, 2);
|
||||
d2 = image->getDimension().Width-1; // width
|
||||
#ifdef __BIG_ENDIAN__
|
||||
d2 = os::Byteswap::byteswap(d2);
|
||||
#endif
|
||||
file->write(&d2, 2);
|
||||
d2 = image->getDimension().Height-1; // height
|
||||
#ifdef __BIG_ENDIAN__
|
||||
d2 = os::Byteswap::byteswap(d2);
|
||||
#endif
|
||||
file->write(&d2, 2);
|
||||
d2 = 300; // dpi
|
||||
#ifdef __BIG_ENDIAN__
|
||||
d2 = os::Byteswap::byteswap(d2);
|
||||
#endif
|
||||
file->write(&d2, 2);
|
||||
file->write(&d2, 2);
|
||||
d2 = 0; // palette (not used)
|
||||
for (i=0; i<24; ++i)
|
||||
{
|
||||
file->write(&d2, 2);
|
||||
}
|
||||
d1 = 0; // reserved
|
||||
file->write(&d1, 1);
|
||||
d1 = 3; // planes
|
||||
file->write(&d1, 1);
|
||||
d2 = image->getDimension().Width; // pitch
|
||||
if (d2&0x0001) // must be even
|
||||
++d2;
|
||||
#ifdef __BIG_ENDIAN__
|
||||
d2 = os::Byteswap::byteswap(d2);
|
||||
#endif
|
||||
file->write(&d2, 2);
|
||||
d2 = 1; // color mode
|
||||
#ifdef __BIG_ENDIAN__
|
||||
d2 = os::Byteswap::byteswap(d2);
|
||||
#endif
|
||||
file->write(&d2, 2);
|
||||
d2 = 800; // screen width
|
||||
#ifdef __BIG_ENDIAN__
|
||||
d2 = os::Byteswap::byteswap(d2);
|
||||
#endif
|
||||
file->write(&d2, 2);
|
||||
d2 = 600; // screen height
|
||||
#ifdef __BIG_ENDIAN__
|
||||
d2 = os::Byteswap::byteswap(d2);
|
||||
#endif
|
||||
file->write(&d2, 2);
|
||||
d2 = 0; // filler (not used)
|
||||
for (i=0; i<27; ++i)
|
||||
{
|
||||
file->write(&d2, 2);
|
||||
}
|
||||
|
||||
u8 cnt, value;
|
||||
for (i=0; i<image->getDimension().Height; ++i)
|
||||
{
|
||||
cnt = 0;
|
||||
value = 0;
|
||||
for (u32 j=0; j<3; ++j) // color planes
|
||||
{
|
||||
for (u32 k=0; k<image->getDimension().Width; ++k)
|
||||
{
|
||||
const SColor pix = image->getPixel(k,i);
|
||||
if ((cnt!=0) && (cnt<63) &&
|
||||
(((j==0) && (value==pix.getRed())) ||
|
||||
((j==1) && (value==pix.getGreen())) ||
|
||||
((j==2) && (value==pix.getBlue()))))
|
||||
{
|
||||
++cnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cnt!=0)
|
||||
{
|
||||
if ((cnt>1) || ((value&0xc0)==0xc0))
|
||||
{
|
||||
cnt |= 0xc0;
|
||||
file->write(&cnt, 1);
|
||||
}
|
||||
file->write(&value, 1);
|
||||
}
|
||||
cnt=1;
|
||||
if (j==0)
|
||||
value=(u8)pix.getRed();
|
||||
else if (j==1)
|
||||
value=(u8)pix.getGreen();
|
||||
else if (j==2)
|
||||
value=(u8)pix.getBlue();
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((cnt>1) || ((value&0xc0)==0xc0))
|
||||
{
|
||||
cnt |= 0xc0;
|
||||
file->write(&cnt, 1);
|
||||
}
|
||||
file->write(&value, 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace video
|
||||
} // namespace irr
|
||||
|
||||
#endif
|
||||
|
@ -1,37 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef _C_IMAGE_WRITER_PCX_H_INCLUDED__
|
||||
#define _C_IMAGE_WRITER_PCX_H_INCLUDED__
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_PCX_WRITER_
|
||||
|
||||
#include "IImageWriter.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
class CImageWriterPCX : public IImageWriter
|
||||
{
|
||||
public:
|
||||
//! constructor
|
||||
CImageWriterPCX();
|
||||
|
||||
//! return true if this writer can write a file with the given extension
|
||||
virtual bool isAWriteableFileExtension(const io::path& filename) const;
|
||||
|
||||
//! write image to file
|
||||
virtual bool writeImage(io::IWriteFile *file, IImage *image, u32 param) const;
|
||||
};
|
||||
|
||||
} // namespace video
|
||||
} // namespace irr
|
||||
|
||||
#endif
|
||||
#endif // _C_IMAGE_WRITER_PCX_H_INCLUDED__
|
||||
|
@ -1,105 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "CImageWriterPPM.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_PPM_WRITER_
|
||||
|
||||
#include "IWriteFile.h"
|
||||
#include "IImage.h"
|
||||
#include "dimension2d.h"
|
||||
#include "irrString.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
|
||||
IImageWriter* createImageWriterPPM()
|
||||
{
|
||||
return new CImageWriterPPM;
|
||||
}
|
||||
|
||||
|
||||
CImageWriterPPM::CImageWriterPPM()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CImageWriterPPM");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool CImageWriterPPM::isAWriteableFileExtension(const io::path& filename) const
|
||||
{
|
||||
return core::hasFileExtension ( filename, "ppm" );
|
||||
}
|
||||
|
||||
|
||||
bool CImageWriterPPM::writeImage(io::IWriteFile *file, IImage *image, u32 param) const
|
||||
{
|
||||
char cache[70];
|
||||
int size;
|
||||
|
||||
const core::dimension2d<u32>& imageSize = image->getDimension();
|
||||
|
||||
const bool binary = false;
|
||||
|
||||
if (binary)
|
||||
size = snprintf(cache, 70, "P6\n");
|
||||
else
|
||||
size = snprintf(cache, 70, "P3\n");
|
||||
|
||||
if (file->write(cache, size) != size)
|
||||
return false;
|
||||
|
||||
size = snprintf(cache, 70, "%d %d\n", imageSize.Width, imageSize.Height);
|
||||
if (file->write(cache, size) != size)
|
||||
return false;
|
||||
|
||||
size = snprintf(cache, 70, "255\n");
|
||||
if (file->write(cache, size) != size)
|
||||
return false;
|
||||
|
||||
if (binary)
|
||||
{
|
||||
for (u32 h = 0; h < imageSize.Height; ++h)
|
||||
{
|
||||
for (u32 c = 0; c < imageSize.Width; ++c)
|
||||
{
|
||||
const video::SColor& pixel = image->getPixel(c, h);
|
||||
const u8 r = (u8)(pixel.getRed() & 0xff);
|
||||
const u8 g = (u8)(pixel.getGreen() & 0xff);
|
||||
const u8 b = (u8)(pixel.getBlue() & 0xff);
|
||||
file->write(&r, 1);
|
||||
file->write(&g, 1);
|
||||
file->write(&b, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s32 n = 0;
|
||||
|
||||
for (u32 h = 0; h < imageSize.Height; ++h)
|
||||
{
|
||||
for (u32 c = 0; c < imageSize.Width; ++c, ++n)
|
||||
{
|
||||
const video::SColor& pixel = image->getPixel(c, h);
|
||||
size = snprintf(cache, 70, "%.3u %.3u %.3u%s", pixel.getRed(), pixel.getGreen(), pixel.getBlue(), n % 5 == 4 ? "\n" : " ");
|
||||
if (file->write(cache, size) != size)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace video
|
||||
} // namespace irr
|
||||
|
||||
#endif
|
||||
|
@ -1,37 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef _C_IMAGE_WRITER_PPM_H_INCLUDED__
|
||||
#define _C_IMAGE_WRITER_PPM_H_INCLUDED__
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_PPM_WRITER_
|
||||
|
||||
#include "IImageWriter.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
class CImageWriterPPM : public IImageWriter
|
||||
{
|
||||
public:
|
||||
//! constructor
|
||||
CImageWriterPPM();
|
||||
|
||||
//! return true if this writer can write a file with the given extension
|
||||
virtual bool isAWriteableFileExtension(const io::path& filename) const;
|
||||
|
||||
//! write image to file
|
||||
virtual bool writeImage(io::IWriteFile *file, IImage *image, u32 param) const;
|
||||
};
|
||||
|
||||
} // namespace video
|
||||
} // namespace irr
|
||||
|
||||
#endif // _C_IMAGE_WRITER_PPM_H_INCLUDED__
|
||||
#endif
|
||||
|
@ -1,46 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "CImageWriterPSD.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_PSD_WRITER_
|
||||
|
||||
#include "CImageLoaderPSD.h"
|
||||
#include "IWriteFile.h"
|
||||
#include "os.h" // for logging
|
||||
#include "irrString.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
IImageWriter* createImageWriterPSD()
|
||||
{
|
||||
return new CImageWriterPSD;
|
||||
}
|
||||
|
||||
CImageWriterPSD::CImageWriterPSD()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CImageWriterPSD");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CImageWriterPSD::isAWriteableFileExtension(const io::path& filename) const
|
||||
{
|
||||
return core::hasFileExtension ( filename, "psd" );
|
||||
}
|
||||
|
||||
bool CImageWriterPSD::writeImage(io::IWriteFile *file, IImage *image,u32 param) const
|
||||
{
|
||||
os::Printer::log("PSD writer not yet implemented. Image not written.", ELL_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace video
|
||||
} // namespace irr
|
||||
|
||||
#endif
|
||||
|
@ -1,37 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef _C_IMAGE_WRITER_PSD_H_INCLUDED__
|
||||
#define _C_IMAGE_WRITER_PSD_H_INCLUDED__
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_PSD_WRITER_
|
||||
|
||||
#include "IImageWriter.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
class CImageWriterPSD : public IImageWriter
|
||||
{
|
||||
public:
|
||||
//! constructor
|
||||
CImageWriterPSD();
|
||||
|
||||
//! return true if this writer can write a file with the given extension
|
||||
virtual bool isAWriteableFileExtension(const io::path& filename) const;
|
||||
|
||||
//! write image to file
|
||||
virtual bool writeImage(io::IWriteFile *file, IImage *image,u32 param) const;
|
||||
};
|
||||
|
||||
} // namespace video
|
||||
} // namespace irr
|
||||
|
||||
#endif // _I_IMAGE_WRITER_PSD_H_INCLUDED__
|
||||
#endif
|
||||
|
@ -1,147 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "CImageWriterTGA.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_TGA_WRITER_
|
||||
|
||||
#include "CImageLoaderTGA.h"
|
||||
#include "IWriteFile.h"
|
||||
#include "CColorConverter.h"
|
||||
#include "irrString.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
IImageWriter* createImageWriterTGA()
|
||||
{
|
||||
return new CImageWriterTGA;
|
||||
}
|
||||
|
||||
CImageWriterTGA::CImageWriterTGA()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CImageWriterTGA");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CImageWriterTGA::isAWriteableFileExtension(const io::path& filename) const
|
||||
{
|
||||
return core::hasFileExtension ( filename, "tga" );
|
||||
}
|
||||
|
||||
bool CImageWriterTGA::writeImage(io::IWriteFile *file, IImage *image,u32 param) const
|
||||
{
|
||||
STGAHeader imageHeader;
|
||||
imageHeader.IdLength = 0;
|
||||
imageHeader.ColorMapType = 0;
|
||||
imageHeader.ImageType = 2;
|
||||
imageHeader.FirstEntryIndex[0] = 0;
|
||||
imageHeader.FirstEntryIndex[1] = 0;
|
||||
imageHeader.ColorMapLength = 0;
|
||||
imageHeader.ColorMapEntrySize = 0;
|
||||
imageHeader.XOrigin[0] = 0;
|
||||
imageHeader.XOrigin[1] = 0;
|
||||
imageHeader.YOrigin[0] = 0;
|
||||
imageHeader.YOrigin[1] = 0;
|
||||
imageHeader.ImageWidth = image->getDimension().Width;
|
||||
imageHeader.ImageHeight = image->getDimension().Height;
|
||||
|
||||
// top left of image is the top. the image loader needs to
|
||||
// be fixed to only swap/flip
|
||||
imageHeader.ImageDescriptor = (1 << 5);
|
||||
|
||||
// chances are good we'll need to swizzle data, so i'm going
|
||||
// to convert and write one scan line at a time. it's also
|
||||
// a bit cleaner this way
|
||||
void (*CColorConverter_convertFORMATtoFORMAT)(const void*, s32, void*) = 0;
|
||||
switch(image->getColorFormat())
|
||||
{
|
||||
case ECF_A8R8G8B8:
|
||||
CColorConverter_convertFORMATtoFORMAT
|
||||
= CColorConverter::convert_A8R8G8B8toA8R8G8B8;
|
||||
imageHeader.PixelDepth = 32;
|
||||
imageHeader.ImageDescriptor |= 8;
|
||||
break;
|
||||
case ECF_A1R5G5B5:
|
||||
CColorConverter_convertFORMATtoFORMAT
|
||||
= CColorConverter::convert_A1R5G5B5toA1R5G5B5;
|
||||
imageHeader.PixelDepth = 16;
|
||||
imageHeader.ImageDescriptor |= 1;
|
||||
break;
|
||||
case ECF_R5G6B5:
|
||||
CColorConverter_convertFORMATtoFORMAT
|
||||
= CColorConverter::convert_R5G6B5toA1R5G5B5;
|
||||
imageHeader.PixelDepth = 16;
|
||||
imageHeader.ImageDescriptor |= 1;
|
||||
break;
|
||||
case ECF_R8G8B8:
|
||||
CColorConverter_convertFORMATtoFORMAT
|
||||
= CColorConverter::convert_R8G8B8toR8G8B8;
|
||||
imageHeader.PixelDepth = 24;
|
||||
imageHeader.ImageDescriptor |= 0;
|
||||
break;
|
||||
#ifndef _DEBUG
|
||||
default:
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
// couldn't find a color converter
|
||||
if (!CColorConverter_convertFORMATtoFORMAT)
|
||||
return false;
|
||||
|
||||
if (file->write(&imageHeader, sizeof(imageHeader)) != sizeof(imageHeader))
|
||||
return false;
|
||||
|
||||
u8* scan_lines = (u8*)image->lock();
|
||||
if (!scan_lines)
|
||||
return false;
|
||||
|
||||
// size of one pixel in bytes
|
||||
u32 pixel_size = image->getBytesPerPixel();
|
||||
|
||||
// length of one row of the source image in bytes
|
||||
u32 row_stride = (pixel_size * imageHeader.ImageWidth);
|
||||
|
||||
// length of one output row in bytes
|
||||
s32 row_size = ((imageHeader.PixelDepth / 8) * imageHeader.ImageWidth);
|
||||
|
||||
// allocate a row do translate data into
|
||||
u8* row_pointer = new u8[row_size];
|
||||
|
||||
u32 y;
|
||||
for (y = 0; y < imageHeader.ImageHeight; ++y)
|
||||
{
|
||||
// source, length [pixels], destination
|
||||
if (image->getColorFormat()==ECF_R8G8B8)
|
||||
CColorConverter::convert24BitTo24Bit(&scan_lines[y * row_stride], row_pointer, imageHeader.ImageWidth, 1, 0, 0, true);
|
||||
else
|
||||
CColorConverter_convertFORMATtoFORMAT(&scan_lines[y * row_stride], imageHeader.ImageWidth, row_pointer);
|
||||
if (file->write(row_pointer, row_size) != row_size)
|
||||
break;
|
||||
}
|
||||
|
||||
delete [] row_pointer;
|
||||
|
||||
image->unlock();
|
||||
|
||||
STGAFooter imageFooter;
|
||||
imageFooter.ExtensionOffset = 0;
|
||||
imageFooter.DeveloperOffset = 0;
|
||||
strncpy(imageFooter.Signature, "TRUEVISION-XFILE.", 18);
|
||||
|
||||
if (file->write(&imageFooter, sizeof(imageFooter)) < (s32)sizeof(imageFooter))
|
||||
return false;
|
||||
|
||||
return imageHeader.ImageHeight <= y;
|
||||
}
|
||||
|
||||
} // namespace video
|
||||
} // namespace irr
|
||||
|
||||
#endif
|
||||
|
@ -1,37 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef _C_IMAGE_WRITER_TGA_H_INCLUDED__
|
||||
#define _C_IMAGE_WRITER_TGA_H_INCLUDED__
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_TGA_WRITER_
|
||||
|
||||
#include "IImageWriter.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
class CImageWriterTGA : public IImageWriter
|
||||
{
|
||||
public:
|
||||
//! constructor
|
||||
CImageWriterTGA();
|
||||
|
||||
//! return true if this writer can write a file with the given extension
|
||||
virtual bool isAWriteableFileExtension(const io::path& filename) const;
|
||||
|
||||
//! write image to file
|
||||
virtual bool writeImage(io::IWriteFile *file, IImage *image,u32 param) const;
|
||||
};
|
||||
|
||||
} // namespace video
|
||||
} // namespace irr
|
||||
|
||||
#endif // _C_IMAGE_WRITER_TGA_H_INCLUDED__
|
||||
#endif
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "IAnimatedMesh.h"
|
||||
#include "IMaterialRenderer.h"
|
||||
#include "IFileSystem.h"
|
||||
#include "CShadowVolumeSceneNode.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
@ -24,7 +23,7 @@ namespace scene
|
||||
CMeshSceneNode::CMeshSceneNode(IMesh* mesh, ISceneNode* parent, ISceneManager* mgr, s32 id,
|
||||
const core::vector3df& position, const core::vector3df& rotation,
|
||||
const core::vector3df& scale)
|
||||
: IMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0), Shadow(0),
|
||||
: IMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0),
|
||||
PassCount(0), ReadOnlyMaterials(false)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
@ -38,8 +37,6 @@ CMeshSceneNode::CMeshSceneNode(IMesh* mesh, ISceneNode* parent, ISceneManager* m
|
||||
//! destructor
|
||||
CMeshSceneNode::~CMeshSceneNode()
|
||||
{
|
||||
if (Shadow)
|
||||
Shadow->drop();
|
||||
if (Mesh)
|
||||
Mesh->drop();
|
||||
}
|
||||
@ -128,9 +125,6 @@ void CMeshSceneNode::render()
|
||||
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
|
||||
Box = Mesh->getBoundingBox();
|
||||
|
||||
if (Shadow && PassCount==1)
|
||||
Shadow->updateShadowVolumes();
|
||||
|
||||
// for debug purposes only:
|
||||
|
||||
bool renderMeshes = true;
|
||||
@ -232,12 +226,6 @@ void CMeshSceneNode::render()
|
||||
//! or to remove attached childs.
|
||||
bool CMeshSceneNode::removeChild(ISceneNode* child)
|
||||
{
|
||||
if (child && Shadow == child)
|
||||
{
|
||||
Shadow->drop();
|
||||
Shadow = 0;
|
||||
}
|
||||
|
||||
return ISceneNode::removeChild(child);
|
||||
}
|
||||
|
||||
@ -294,25 +282,6 @@ void CMeshSceneNode::setMesh(IMesh* mesh)
|
||||
}
|
||||
|
||||
|
||||
//! Creates shadow volume scene node as child of this node
|
||||
//! and returns a pointer to it.
|
||||
IShadowVolumeSceneNode* CMeshSceneNode::addShadowVolumeSceneNode(
|
||||
const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity)
|
||||
{
|
||||
if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER))
|
||||
return 0;
|
||||
|
||||
if (!shadowMesh)
|
||||
shadowMesh = Mesh; // if null is given, use the mesh of node
|
||||
|
||||
if (Shadow)
|
||||
Shadow->drop();
|
||||
|
||||
Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity);
|
||||
return Shadow;
|
||||
}
|
||||
|
||||
|
||||
void CMeshSceneNode::copyMaterials()
|
||||
{
|
||||
Materials.clear();
|
||||
@ -432,8 +401,6 @@ ISceneNode* CMeshSceneNode::clone(ISceneNode* newParent, ISceneManager* newManag
|
||||
nb->cloneMembers(this, newManager);
|
||||
nb->ReadOnlyMaterials = ReadOnlyMaterials;
|
||||
nb->Materials = Materials;
|
||||
nb->Shadow = Shadow;
|
||||
nb->Shadow->grab();
|
||||
|
||||
if (newParent)
|
||||
nb->drop();
|
||||
|
@ -60,11 +60,6 @@ namespace scene
|
||||
//! Returns the current mesh
|
||||
virtual IMesh* getMesh(void) { return Mesh; }
|
||||
|
||||
//! Creates shadow volume scene node as child of this node
|
||||
//! and returns a pointer to it.
|
||||
virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh,
|
||||
s32 id, bool zfailmethod=true, f32 infinity=10000.0f);
|
||||
|
||||
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
|
||||
/* In this way it is possible to change the materials a mesh causing all mesh scene nodes
|
||||
referencing this mesh to change too. */
|
||||
@ -90,7 +85,6 @@ namespace scene
|
||||
video::SMaterial ReadOnlyMaterial;
|
||||
|
||||
IMesh* Mesh;
|
||||
IShadowVolumeSceneNode* Shadow;
|
||||
|
||||
s32 PassCount;
|
||||
bool ReadOnlyMaterials;
|
||||
|
@ -121,33 +121,6 @@ CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& scre
|
||||
|
||||
// create surface loader
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_
|
||||
SurfaceLoader.push_back(video::createImageLoaderHalfLife());
|
||||
#endif
|
||||
#ifdef _IRR_COMPILE_WITH_WAL_LOADER_
|
||||
SurfaceLoader.push_back(video::createImageLoaderWAL());
|
||||
#endif
|
||||
#ifdef _IRR_COMPILE_WITH_LMP_LOADER_
|
||||
SurfaceLoader.push_back(video::createImageLoaderLMP());
|
||||
#endif
|
||||
#ifdef _IRR_COMPILE_WITH_PPM_LOADER_
|
||||
SurfaceLoader.push_back(video::createImageLoaderPPM());
|
||||
#endif
|
||||
#ifdef _IRR_COMPILE_WITH_RGB_LOADER_
|
||||
SurfaceLoader.push_back(video::createImageLoaderRGB());
|
||||
#endif
|
||||
#ifdef _IRR_COMPILE_WITH_PSD_LOADER_
|
||||
SurfaceLoader.push_back(video::createImageLoaderPSD());
|
||||
#endif
|
||||
#ifdef _IRR_COMPILE_WITH_DDS_LOADER_
|
||||
SurfaceLoader.push_back(video::createImageLoaderDDS());
|
||||
#endif
|
||||
#ifdef _IRR_COMPILE_WITH_PCX_LOADER_
|
||||
SurfaceLoader.push_back(video::createImageLoaderPCX());
|
||||
#endif
|
||||
#ifdef _IRR_COMPILE_WITH_TGA_LOADER_
|
||||
SurfaceLoader.push_back(video::createImageLoaderTGA());
|
||||
#endif
|
||||
#ifdef _IRR_COMPILE_WITH_PNG_LOADER_
|
||||
SurfaceLoader.push_back(video::createImageLoaderPNG());
|
||||
#endif
|
||||
@ -157,20 +130,6 @@ CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& scre
|
||||
#ifdef _IRR_COMPILE_WITH_BMP_LOADER_
|
||||
SurfaceLoader.push_back(video::createImageLoaderBMP());
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_PPM_WRITER_
|
||||
SurfaceWriter.push_back(video::createImageWriterPPM());
|
||||
#endif
|
||||
#ifdef _IRR_COMPILE_WITH_PCX_WRITER_
|
||||
SurfaceWriter.push_back(video::createImageWriterPCX());
|
||||
#endif
|
||||
#ifdef _IRR_COMPILE_WITH_PSD_WRITER_
|
||||
SurfaceWriter.push_back(video::createImageWriterPSD());
|
||||
#endif
|
||||
#ifdef _IRR_COMPILE_WITH_TGA_WRITER_
|
||||
SurfaceWriter.push_back(video::createImageWriterTGA());
|
||||
#endif
|
||||
#ifdef _IRR_COMPILE_WITH_JPG_WRITER_
|
||||
SurfaceWriter.push_back(video::createImageWriterJPG());
|
||||
#endif
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "IAnimatedMesh.h"
|
||||
#include "IMaterialRenderer.h"
|
||||
#include "os.h"
|
||||
#include "CShadowVolumeSceneNode.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
@ -24,7 +23,7 @@ COctreeSceneNode::COctreeSceneNode(ISceneNode* parent, ISceneManager* mgr,
|
||||
s32 id, s32 minimalPolysPerNode)
|
||||
: IMeshSceneNode(parent, mgr, id), StdOctree(0), LightMapOctree(0),
|
||||
TangentsOctree(0), VertexType((video::E_VERTEX_TYPE)-1),
|
||||
MinimalPolysPerNode(minimalPolysPerNode), Mesh(0), Shadow(0),
|
||||
MinimalPolysPerNode(minimalPolysPerNode), Mesh(0),
|
||||
UseVBOs(OCTREE_USE_HARDWARE), UseVisibilityAndVBOs(OCTREE_USE_VISIBILITY),
|
||||
BoxBased(OCTREE_BOX_BASED)
|
||||
{
|
||||
@ -37,8 +36,6 @@ COctreeSceneNode::COctreeSceneNode(ISceneNode* parent, ISceneManager* mgr,
|
||||
//! destructor
|
||||
COctreeSceneNode::~COctreeSceneNode()
|
||||
{
|
||||
if (Shadow)
|
||||
Shadow->drop();
|
||||
deleteTree();
|
||||
}
|
||||
|
||||
@ -104,9 +101,6 @@ void COctreeSceneNode::render()
|
||||
|
||||
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
|
||||
|
||||
if (Shadow)
|
||||
Shadow->updateShadowVolumes();
|
||||
|
||||
SViewFrustum frust = *camera->getViewFrustum();
|
||||
|
||||
//transform the frustum to the current absolute transformation
|
||||
@ -291,35 +285,10 @@ void COctreeSceneNode::render()
|
||||
//! or to remove attached childs.
|
||||
bool COctreeSceneNode::removeChild(ISceneNode* child)
|
||||
{
|
||||
if (child && Shadow == child)
|
||||
{
|
||||
Shadow->drop();
|
||||
Shadow = 0;
|
||||
}
|
||||
|
||||
return ISceneNode::removeChild(child);
|
||||
}
|
||||
|
||||
|
||||
//! Creates shadow volume scene node as child of this node
|
||||
//! and returns a pointer to it.
|
||||
IShadowVolumeSceneNode* COctreeSceneNode::addShadowVolumeSceneNode(
|
||||
const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity)
|
||||
{
|
||||
if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER))
|
||||
return 0;
|
||||
|
||||
if (!shadowMesh)
|
||||
shadowMesh = Mesh; // if null is given, use the mesh of node
|
||||
|
||||
if (Shadow)
|
||||
Shadow->drop();
|
||||
|
||||
Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity);
|
||||
return Shadow;
|
||||
}
|
||||
|
||||
|
||||
//! returns the axis aligned bounding box of this node
|
||||
const core::aabbox3d<f32>& COctreeSceneNode::getBoundingBox() const
|
||||
{
|
||||
|
@ -66,11 +66,6 @@ namespace scene
|
||||
//! Check if the scene node should not copy the materials of the mesh but use them in a read only style
|
||||
virtual bool isReadOnlyMaterials() const;
|
||||
|
||||
//! Creates shadow volume scene node as child of this node
|
||||
//! and returns a pointer to it.
|
||||
virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh,
|
||||
s32 id, bool zfailmethod=true, f32 infinity=10000.0f);
|
||||
|
||||
//! Removes a child from this scene node.
|
||||
//! Implemented here, to be able to remove the shadow properly, if there is one,
|
||||
//! or to remove attached childs.
|
||||
@ -99,7 +94,6 @@ namespace scene
|
||||
s32 PassCount;
|
||||
|
||||
IMesh * Mesh;
|
||||
IShadowVolumeSceneNode* Shadow;
|
||||
//! use VBOs for rendering where possible
|
||||
bool UseVBOs;
|
||||
//! use visibility information together with VBOs
|
||||
|
@ -1,419 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "CShadowVolumeSceneNode.h"
|
||||
#include "ISceneManager.h"
|
||||
#include "IMesh.h"
|
||||
#include "IVideoDriver.h"
|
||||
#include "ICameraSceneNode.h"
|
||||
#include "SViewFrustum.h"
|
||||
#include "SLight.h"
|
||||
#include "os.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene
|
||||
{
|
||||
|
||||
|
||||
//! constructor
|
||||
CShadowVolumeSceneNode::CShadowVolumeSceneNode(const IMesh* shadowMesh, ISceneNode* parent,
|
||||
ISceneManager* mgr, s32 id, bool zfailmethod, f32 infinity)
|
||||
: IShadowVolumeSceneNode(parent, mgr, id),
|
||||
ShadowMesh(0), IndexCount(0), VertexCount(0), ShadowVolumesUsed(0),
|
||||
Infinity(infinity), UseZFailMethod(zfailmethod)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CShadowVolumeSceneNode");
|
||||
#endif
|
||||
setShadowMesh(shadowMesh);
|
||||
setAutomaticCulling(scene::EAC_OFF);
|
||||
}
|
||||
|
||||
|
||||
//! destructor
|
||||
CShadowVolumeSceneNode::~CShadowVolumeSceneNode()
|
||||
{
|
||||
if (ShadowMesh)
|
||||
ShadowMesh->drop();
|
||||
}
|
||||
|
||||
|
||||
void CShadowVolumeSceneNode::createShadowVolume(const core::vector3df& light, bool isDirectional)
|
||||
{
|
||||
SShadowVolume* svp = 0;
|
||||
core::aabbox3d<f32>* bb = 0;
|
||||
|
||||
// builds the shadow volume and adds it to the shadow volume list.
|
||||
|
||||
if (ShadowVolumes.size() > ShadowVolumesUsed)
|
||||
{
|
||||
// get the next unused buffer
|
||||
|
||||
svp = &ShadowVolumes[ShadowVolumesUsed];
|
||||
svp->set_used(0);
|
||||
|
||||
bb = &ShadowBBox[ShadowVolumesUsed];
|
||||
}
|
||||
else
|
||||
{
|
||||
ShadowVolumes.push_back(SShadowVolume());
|
||||
svp = &ShadowVolumes.getLast();
|
||||
|
||||
ShadowBBox.push_back(core::aabbox3d<f32>());
|
||||
bb = &ShadowBBox.getLast();
|
||||
}
|
||||
svp->reallocate(IndexCount*5);
|
||||
++ShadowVolumesUsed;
|
||||
|
||||
// We use triangle lists
|
||||
Edges.set_used(IndexCount*2);
|
||||
u32 numEdges = 0;
|
||||
|
||||
numEdges=createEdgesAndCaps(light, svp, bb);
|
||||
|
||||
// for all edges add the near->far quads
|
||||
for (u32 i=0; i<numEdges; ++i)
|
||||
{
|
||||
const core::vector3df &v1 = Vertices[Edges[2*i+0]];
|
||||
const core::vector3df &v2 = Vertices[Edges[2*i+1]];
|
||||
const core::vector3df v3(v1+(v1 - light).normalize()*Infinity);
|
||||
const core::vector3df v4(v2+(v2 - light).normalize()*Infinity);
|
||||
|
||||
// Add a quad (two triangles) to the vertex list
|
||||
#ifdef _DEBUG
|
||||
if (svp->size() >= svp->allocated_size()-5)
|
||||
os::Printer::log("Allocation too small.", ELL_DEBUG);
|
||||
#endif
|
||||
svp->push_back(v1);
|
||||
svp->push_back(v2);
|
||||
svp->push_back(v3);
|
||||
|
||||
svp->push_back(v2);
|
||||
svp->push_back(v4);
|
||||
svp->push_back(v3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define IRR_USE_ADJACENCY
|
||||
#define IRR_USE_REVERSE_EXTRUDED
|
||||
|
||||
u32 CShadowVolumeSceneNode::createEdgesAndCaps(const core::vector3df& light,
|
||||
SShadowVolume* svp, core::aabbox3d<f32>* bb)
|
||||
{
|
||||
u32 numEdges=0;
|
||||
const u32 faceCount = IndexCount / 3;
|
||||
|
||||
if(faceCount >= 1)
|
||||
bb->reset(Vertices[Indices[0]]);
|
||||
else
|
||||
bb->reset(0,0,0);
|
||||
|
||||
// Check every face if it is front or back facing the light.
|
||||
for (u32 i=0; i<faceCount; ++i)
|
||||
{
|
||||
const core::vector3df v0 = Vertices[Indices[3*i+0]];
|
||||
const core::vector3df v1 = Vertices[Indices[3*i+1]];
|
||||
const core::vector3df v2 = Vertices[Indices[3*i+2]];
|
||||
|
||||
#ifdef IRR_USE_REVERSE_EXTRUDED
|
||||
FaceData[i]=core::triangle3df(v0,v1,v2).isFrontFacing(light);
|
||||
#else
|
||||
FaceData[i]=core::triangle3df(v2,v1,v0).isFrontFacing(light);
|
||||
#endif
|
||||
|
||||
if (UseZFailMethod && FaceData[i])
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (svp->size() >= svp->allocated_size()-5)
|
||||
os::Printer::log("Allocation too small.", ELL_DEBUG);
|
||||
#endif
|
||||
// add front cap from light-facing faces
|
||||
svp->push_back(v2);
|
||||
svp->push_back(v1);
|
||||
svp->push_back(v0);
|
||||
|
||||
// add back cap
|
||||
const core::vector3df i0 = v0+(v0-light).normalize()*Infinity;
|
||||
const core::vector3df i1 = v1+(v1-light).normalize()*Infinity;
|
||||
const core::vector3df i2 = v2+(v2-light).normalize()*Infinity;
|
||||
|
||||
svp->push_back(i0);
|
||||
svp->push_back(i1);
|
||||
svp->push_back(i2);
|
||||
|
||||
bb->addInternalPoint(i0);
|
||||
bb->addInternalPoint(i1);
|
||||
bb->addInternalPoint(i2);
|
||||
}
|
||||
}
|
||||
|
||||
// Create edges
|
||||
for (u32 i=0; i<faceCount; ++i)
|
||||
{
|
||||
// check all front facing faces
|
||||
if (FaceData[i] == true)
|
||||
{
|
||||
const u16 wFace0 = Indices[3*i+0];
|
||||
const u16 wFace1 = Indices[3*i+1];
|
||||
const u16 wFace2 = Indices[3*i+2];
|
||||
|
||||
const u16 adj0 = Adjacency[3*i+0];
|
||||
const u16 adj1 = Adjacency[3*i+1];
|
||||
const u16 adj2 = Adjacency[3*i+2];
|
||||
|
||||
// add edges if face is adjacent to back-facing face
|
||||
// or if no adjacent face was found
|
||||
#ifdef IRR_USE_ADJACENCY
|
||||
if (adj0 == i || FaceData[adj0] == false)
|
||||
#endif
|
||||
{
|
||||
// add edge v0-v1
|
||||
Edges[2*numEdges+0] = wFace0;
|
||||
Edges[2*numEdges+1] = wFace1;
|
||||
++numEdges;
|
||||
}
|
||||
|
||||
#ifdef IRR_USE_ADJACENCY
|
||||
if (adj1 == i || FaceData[adj1] == false)
|
||||
#endif
|
||||
{
|
||||
// add edge v1-v2
|
||||
Edges[2*numEdges+0] = wFace1;
|
||||
Edges[2*numEdges+1] = wFace2;
|
||||
++numEdges;
|
||||
}
|
||||
|
||||
#ifdef IRR_USE_ADJACENCY
|
||||
if (adj2 == i || FaceData[adj2] == false)
|
||||
#endif
|
||||
{
|
||||
// add edge v2-v0
|
||||
Edges[2*numEdges+0] = wFace2;
|
||||
Edges[2*numEdges+1] = wFace0;
|
||||
++numEdges;
|
||||
}
|
||||
}
|
||||
}
|
||||
return numEdges;
|
||||
}
|
||||
|
||||
|
||||
void CShadowVolumeSceneNode::setShadowMesh(const IMesh* mesh)
|
||||
{
|
||||
if (ShadowMesh == mesh)
|
||||
return;
|
||||
if (ShadowMesh)
|
||||
ShadowMesh->drop();
|
||||
ShadowMesh = mesh;
|
||||
if (ShadowMesh)
|
||||
{
|
||||
ShadowMesh->grab();
|
||||
Box = ShadowMesh->getBoundingBox();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CShadowVolumeSceneNode::updateShadowVolumes()
|
||||
{
|
||||
const u32 oldIndexCount = IndexCount;
|
||||
const u32 oldVertexCount = VertexCount;
|
||||
|
||||
const IMesh* const mesh = ShadowMesh;
|
||||
if (!mesh)
|
||||
return;
|
||||
|
||||
// create as much shadow volumes as there are lights but
|
||||
// do not ignore the max light settings.
|
||||
const u32 lightCount = SceneManager->getVideoDriver()->getDynamicLightCount();
|
||||
if (!lightCount)
|
||||
return;
|
||||
|
||||
// calculate total amount of vertices and indices
|
||||
|
||||
VertexCount = 0;
|
||||
IndexCount = 0;
|
||||
ShadowVolumesUsed = 0;
|
||||
|
||||
u32 i;
|
||||
u32 totalVertices = 0;
|
||||
u32 totalIndices = 0;
|
||||
const u32 bufcnt = mesh->getMeshBufferCount();
|
||||
|
||||
for (i=0; i<bufcnt; ++i)
|
||||
{
|
||||
const IMeshBuffer* buf = mesh->getMeshBuffer(i);
|
||||
totalIndices += buf->getIndexCount();
|
||||
totalVertices += buf->getVertexCount();
|
||||
}
|
||||
|
||||
// allocate memory if necessary
|
||||
|
||||
Vertices.set_used(totalVertices);
|
||||
Indices.set_used(totalIndices);
|
||||
FaceData.set_used(totalIndices / 3);
|
||||
|
||||
// copy mesh
|
||||
for (i=0; i<bufcnt; ++i)
|
||||
{
|
||||
const IMeshBuffer* buf = mesh->getMeshBuffer(i);
|
||||
|
||||
const u16* idxp = buf->getIndices();
|
||||
const u16* idxpend = idxp + buf->getIndexCount();
|
||||
for (; idxp!=idxpend; ++idxp)
|
||||
Indices[IndexCount++] = *idxp + VertexCount;
|
||||
|
||||
const u32 vtxcnt = buf->getVertexCount();
|
||||
for (u32 j=0; j<vtxcnt; ++j)
|
||||
Vertices[VertexCount++] = buf->getPosition(j);
|
||||
}
|
||||
|
||||
// recalculate adjacency if necessary
|
||||
if (oldVertexCount != VertexCount || oldIndexCount != IndexCount)
|
||||
calculateAdjacency();
|
||||
|
||||
core::matrix4 mat = Parent->getAbsoluteTransformation();
|
||||
mat.makeInverse();
|
||||
const core::vector3df parentpos = Parent->getAbsolutePosition();
|
||||
|
||||
// TODO: Only correct for point lights.
|
||||
for (i=0; i<lightCount; ++i)
|
||||
{
|
||||
const video::SLight& dl = SceneManager->getVideoDriver()->getDynamicLight(i);
|
||||
core::vector3df lpos = dl.Position;
|
||||
if (dl.CastShadows &&
|
||||
fabs((lpos - parentpos).getLengthSQ()) <= (dl.Radius*dl.Radius*4.0f))
|
||||
{
|
||||
mat.transformVect(lpos);
|
||||
createShadowVolume(lpos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! pre render method
|
||||
void CShadowVolumeSceneNode::OnRegisterSceneNode()
|
||||
{
|
||||
if (IsVisible)
|
||||
{
|
||||
SceneManager->registerNodeForRendering(this, scene::ESNRP_SHADOW);
|
||||
ISceneNode::OnRegisterSceneNode();
|
||||
}
|
||||
}
|
||||
|
||||
//! renders the node.
|
||||
void CShadowVolumeSceneNode::render()
|
||||
{
|
||||
video::IVideoDriver* driver = SceneManager->getVideoDriver();
|
||||
|
||||
if (!ShadowVolumesUsed || !driver)
|
||||
return;
|
||||
|
||||
driver->setTransform(video::ETS_WORLD, Parent->getAbsoluteTransformation());
|
||||
|
||||
for (u32 i=0; i<ShadowVolumesUsed; ++i)
|
||||
{
|
||||
bool drawShadow = true;
|
||||
|
||||
if (UseZFailMethod && SceneManager->getActiveCamera())
|
||||
{
|
||||
// Disable shadows drawing, when back cap is behind of ZFar plane.
|
||||
|
||||
SViewFrustum frust = *SceneManager->getActiveCamera()->getViewFrustum();
|
||||
|
||||
core::matrix4 invTrans(Parent->getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE);
|
||||
frust.transform(invTrans);
|
||||
|
||||
core::vector3df edges[8];
|
||||
ShadowBBox[i].getEdges(edges);
|
||||
|
||||
core::vector3df largestEdge = edges[0];
|
||||
f32 maxDistance = core::vector3df(SceneManager->getActiveCamera()->getPosition() - edges[0]).getLength();
|
||||
f32 curDistance = 0.f;
|
||||
|
||||
for(int j = 1; j < 8; ++j)
|
||||
{
|
||||
curDistance = core::vector3df(SceneManager->getActiveCamera()->getPosition() - edges[j]).getLength();
|
||||
|
||||
if(curDistance > maxDistance)
|
||||
{
|
||||
maxDistance = curDistance;
|
||||
largestEdge = edges[j];
|
||||
}
|
||||
}
|
||||
|
||||
if (!(frust.planes[scene::SViewFrustum::VF_FAR_PLANE].classifyPointRelation(largestEdge) != core::ISREL3D_FRONT))
|
||||
drawShadow = false;
|
||||
}
|
||||
|
||||
if(drawShadow)
|
||||
driver->drawStencilShadowVolume(ShadowVolumes[i], UseZFailMethod, DebugDataVisible);
|
||||
else
|
||||
{
|
||||
core::array<core::vector3df> triangles;
|
||||
driver->drawStencilShadowVolume(triangles, UseZFailMethod, DebugDataVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! returns the axis aligned bounding box of this node
|
||||
const core::aabbox3d<f32>& CShadowVolumeSceneNode::getBoundingBox() const
|
||||
{
|
||||
return Box;
|
||||
}
|
||||
|
||||
|
||||
//! Generates adjacency information based on mesh indices.
|
||||
void CShadowVolumeSceneNode::calculateAdjacency()
|
||||
{
|
||||
Adjacency.set_used(IndexCount);
|
||||
|
||||
// go through all faces and fetch their three neighbours
|
||||
for (u32 f=0; f<IndexCount; f+=3)
|
||||
{
|
||||
for (u32 edge = 0; edge<3; ++edge)
|
||||
{
|
||||
const core::vector3df& v1 = Vertices[Indices[f+edge]];
|
||||
const core::vector3df& v2 = Vertices[Indices[f+((edge+1)%3)]];
|
||||
|
||||
// now we search an_O_ther _F_ace with these two
|
||||
// vertices, which is not the current face.
|
||||
u32 of;
|
||||
|
||||
for (of=0; of<IndexCount; of+=3)
|
||||
{
|
||||
// only other faces
|
||||
if (of != f)
|
||||
{
|
||||
bool cnt1 = false;
|
||||
bool cnt2 = false;
|
||||
|
||||
for (s32 e=0; e<3; ++e)
|
||||
{
|
||||
if (v1.equals(Vertices[Indices[of+e]]))
|
||||
cnt1=true;
|
||||
|
||||
if (v2.equals(Vertices[Indices[of+e]]))
|
||||
cnt2=true;
|
||||
}
|
||||
// one match for each vertex, i.e. edge is the same
|
||||
if (cnt1 && cnt2)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// no adjacent edges -> store face number, else store adjacent face
|
||||
if (of >= IndexCount)
|
||||
Adjacency[f + edge] = f/3;
|
||||
else
|
||||
Adjacency[f + edge] = of/3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // end namespace scene
|
||||
} // end namespace irr
|
@ -1,87 +0,0 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef __C_SHADOW_VOLUME_SCENE_NODE_H_INCLUDED__
|
||||
#define __C_SHADOW_VOLUME_SCENE_NODE_H_INCLUDED__
|
||||
|
||||
#include "IShadowVolumeSceneNode.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene
|
||||
{
|
||||
|
||||
//! Scene node for rendering a shadow volume into a stencil buffer.
|
||||
class CShadowVolumeSceneNode : public IShadowVolumeSceneNode
|
||||
{
|
||||
public:
|
||||
|
||||
//! constructor
|
||||
CShadowVolumeSceneNode(const IMesh* shadowMesh, ISceneNode* parent, ISceneManager* mgr,
|
||||
s32 id, bool zfailmethod=true, f32 infinity=10000.0f);
|
||||
|
||||
//! destructor
|
||||
virtual ~CShadowVolumeSceneNode();
|
||||
|
||||
//! Sets the mesh from which the shadow volume should be generated.
|
||||
/** To optimize shadow rendering, use a simpler mesh for shadows.
|
||||
*/
|
||||
virtual void setShadowMesh(const IMesh* mesh);
|
||||
|
||||
//! Updates the shadow volumes for current light positions.
|
||||
/** Called each render cycle from Animated Mesh SceneNode render method. */
|
||||
virtual void updateShadowVolumes();
|
||||
|
||||
//! pre render method
|
||||
virtual void OnRegisterSceneNode();
|
||||
|
||||
//! renders the node.
|
||||
virtual void render();
|
||||
|
||||
//! returns the axis aligned bounding box of this node
|
||||
virtual const core::aabbox3d<f32>& getBoundingBox() const;
|
||||
|
||||
//! Returns type of the scene node
|
||||
virtual ESCENE_NODE_TYPE getType() const { return ESNT_SHADOW_VOLUME; }
|
||||
|
||||
private:
|
||||
|
||||
typedef core::array<core::vector3df> SShadowVolume;
|
||||
|
||||
void createShadowVolume(const core::vector3df& pos, bool isDirectional=false);
|
||||
u32 createEdgesAndCaps(const core::vector3df& light, SShadowVolume* svp, core::aabbox3d<f32>* bb);
|
||||
|
||||
//! Generates adjacency information based on mesh indices.
|
||||
void calculateAdjacency();
|
||||
|
||||
core::aabbox3d<f32> Box;
|
||||
|
||||
// a shadow volume for every light
|
||||
core::array<SShadowVolume> ShadowVolumes;
|
||||
|
||||
// a back cap bounding box for every light
|
||||
core::array<core::aabbox3d<f32> > ShadowBBox;
|
||||
|
||||
core::array<core::vector3df> Vertices;
|
||||
core::array<u16> Indices;
|
||||
core::array<u16> Adjacency;
|
||||
core::array<u16> Edges;
|
||||
// tells if face is front facing
|
||||
core::array<bool> FaceData;
|
||||
|
||||
const scene::IMesh* ShadowMesh;
|
||||
|
||||
u32 IndexCount;
|
||||
u32 VertexCount;
|
||||
u32 ShadowVolumesUsed;
|
||||
|
||||
f32 Infinity;
|
||||
|
||||
bool UseZFailMethod;
|
||||
};
|
||||
|
||||
} // end namespace scene
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
@ -7,7 +7,6 @@
|
||||
#include "ISceneManager.h"
|
||||
#include "S3DVertex.h"
|
||||
#include "os.h"
|
||||
#include "CShadowVolumeSceneNode.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
@ -17,7 +16,7 @@ namespace scene
|
||||
//! constructor
|
||||
CSphereSceneNode::CSphereSceneNode(f32 radius, u32 polyCountX, u32 polyCountY, ISceneNode* parent, ISceneManager* mgr, s32 id,
|
||||
const core::vector3df& position, const core::vector3df& rotation, const core::vector3df& scale)
|
||||
: IMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0), Shadow(0),
|
||||
: IMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0),
|
||||
Radius(radius), PolyCountX(polyCountX), PolyCountY(polyCountY)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
@ -32,8 +31,6 @@ CSphereSceneNode::CSphereSceneNode(f32 radius, u32 polyCountX, u32 polyCountY, I
|
||||
//! destructor
|
||||
CSphereSceneNode::~CSphereSceneNode()
|
||||
{
|
||||
if (Shadow)
|
||||
Shadow->drop();
|
||||
if (Mesh)
|
||||
Mesh->drop();
|
||||
}
|
||||
@ -48,8 +45,6 @@ void CSphereSceneNode::render()
|
||||
{
|
||||
driver->setMaterial(Mesh->getMeshBuffer(0)->getMaterial());
|
||||
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
|
||||
if (Shadow)
|
||||
Shadow->updateShadowVolumes();
|
||||
|
||||
driver->drawMeshBuffer(Mesh->getMeshBuffer(0));
|
||||
if ( DebugDataVisible & scene::EDS_BBOX )
|
||||
@ -68,35 +63,10 @@ void CSphereSceneNode::render()
|
||||
//! or to remove attached childs.
|
||||
bool CSphereSceneNode::removeChild(ISceneNode* child)
|
||||
{
|
||||
if (child && Shadow == child)
|
||||
{
|
||||
Shadow->drop();
|
||||
Shadow = 0;
|
||||
}
|
||||
|
||||
return ISceneNode::removeChild(child);
|
||||
}
|
||||
|
||||
|
||||
//! Creates shadow volume scene node as child of this node
|
||||
//! and returns a pointer to it.
|
||||
IShadowVolumeSceneNode* CSphereSceneNode::addShadowVolumeSceneNode(
|
||||
const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity)
|
||||
{
|
||||
if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER))
|
||||
return 0;
|
||||
|
||||
if (!shadowMesh)
|
||||
shadowMesh = Mesh; // if null is given, use the mesh of node
|
||||
|
||||
if (Shadow)
|
||||
Shadow->drop();
|
||||
|
||||
Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity);
|
||||
return Shadow;
|
||||
}
|
||||
|
||||
|
||||
//! returns the axis aligned bounding box of this node
|
||||
const core::aabbox3d<f32>& CSphereSceneNode::getBoundingBox() const
|
||||
{
|
||||
@ -185,8 +155,6 @@ ISceneNode* CSphereSceneNode::clone(ISceneNode* newParent, ISceneManager* newMan
|
||||
|
||||
nb->cloneMembers(this, newManager);
|
||||
nb->getMaterial(0) = Mesh->getMeshBuffer(0)->getMaterial();
|
||||
nb->Shadow = Shadow;
|
||||
nb->Shadow->grab();
|
||||
|
||||
if ( newParent )
|
||||
nb->drop();
|
||||
|
@ -69,11 +69,6 @@ namespace scene
|
||||
//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style
|
||||
virtual bool isReadOnlyMaterials() const { return false; }
|
||||
|
||||
//! Creates shadow volume scene node as child of this node
|
||||
//! and returns a pointer to it.
|
||||
virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh,
|
||||
s32 id, bool zfailmethod=true, f32 infinity=10000.0f);
|
||||
|
||||
//! Removes a child from this scene node.
|
||||
//! Implemented here, to be able to remove the shadow properly, if there is one,
|
||||
//! or to remove attached childs.
|
||||
@ -82,7 +77,6 @@ namespace scene
|
||||
private:
|
||||
|
||||
IMesh* Mesh;
|
||||
IShadowVolumeSceneNode* Shadow;
|
||||
core::aabbox3d<f32> Box;
|
||||
f32 Radius;
|
||||
u32 PolyCountX;
|
||||
|
@ -553,8 +553,15 @@ void Material::initCustomSFX(const XMLNode *sfx)
|
||||
sfx->get("max-pitch", &m_sfx_max_pitch); // 2.4 style
|
||||
sfx->get("max_pitch", &m_sfx_max_pitch); // 2.5 style
|
||||
|
||||
m_sfx_pitch_per_speed = (m_sfx_max_pitch - m_sfx_min_pitch)
|
||||
/ (m_sfx_max_speed - m_sfx_min_speed);
|
||||
if (m_sfx_max_speed == m_sfx_min_speed)
|
||||
{
|
||||
m_sfx_pitch_per_speed = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sfx_pitch_per_speed = (m_sfx_max_pitch - m_sfx_min_pitch)
|
||||
/ (m_sfx_max_speed - m_sfx_min_speed);
|
||||
}
|
||||
|
||||
if(!SFXManager::get()->soundExist(m_sfx_name))
|
||||
{
|
||||
@ -675,6 +682,8 @@ void Material::setSFXSpeed(SFXBase *sfx, float speed, bool should_be_paused) con
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!isnan(speed));
|
||||
|
||||
float f = m_sfx_pitch_per_speed*(speed-m_sfx_min_speed) + m_sfx_min_pitch;
|
||||
assert(!isnan(f));
|
||||
sfx->setSpeed(f);
|
||||
|
@ -380,27 +380,18 @@ void IrrDriver::renderSkybox(const scene::ICameraSceneNode *camera)
|
||||
{
|
||||
if (SkyboxTextures.empty())
|
||||
return;
|
||||
glBindVertexArray(MeshShader::SkyboxShader::getInstance()->cubevao);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
assert(SkyboxTextures.size() == 6);
|
||||
|
||||
core::matrix4 translate;
|
||||
translate.setTranslation(camera->getAbsolutePosition());
|
||||
|
||||
// Draw the sky box between the near and far clip plane
|
||||
const f32 viewDistance = (camera->getNearValue() + camera->getFarValue()) * 0.5f;
|
||||
core::matrix4 scale;
|
||||
scale.setScale(core::vector3df(viewDistance, viewDistance, viewDistance));
|
||||
core::matrix4 transform = translate * scale;
|
||||
core::matrix4 invtransform;
|
||||
transform.getInverse(invtransform);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glUseProgram(MeshShader::SkyboxShader::getInstance()->Program);
|
||||
MeshShader::SkyboxShader::getInstance()->setUniforms(transform);
|
||||
glBindVertexArray(MeshShader::SkyboxShader::getInstance()->vao);
|
||||
MeshShader::SkyboxShader::getInstance()->setUniforms();
|
||||
|
||||
MeshShader::SkyboxShader::getInstance()->SetTextureUnits(SkyboxCubeMap);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, 6 * 6, GL_UNSIGNED_INT, 0);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
@ -48,26 +48,6 @@ static GLuint generateRTT(const core::dimension2du &res, GLint internalFormat, G
|
||||
return result;
|
||||
}
|
||||
|
||||
static GLuint generateFBO(GLuint ColorAttachement)
|
||||
{
|
||||
GLuint fbo;
|
||||
glGenFramebuffers(1, &fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ColorAttachement, 0);
|
||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
assert(result == GL_FRAMEBUFFER_COMPLETE_EXT);
|
||||
return fbo;
|
||||
}
|
||||
|
||||
static GLuint generateFBO(GLuint ColorAttachement, GLuint DepthAttachement)
|
||||
{
|
||||
GLuint fbo = generateFBO(ColorAttachement);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, DepthAttachement, 0);
|
||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
assert(result == GL_FRAMEBUFFER_COMPLETE_EXT);
|
||||
return fbo;
|
||||
}
|
||||
|
||||
RTT::RTT(size_t width, size_t height)
|
||||
{
|
||||
m_width = width;
|
||||
|
@ -336,66 +336,19 @@ static void initBillboardVBO()
|
||||
glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), quad, GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
GLuint SharedObject::cubevbo = 0;
|
||||
GLuint SharedObject::cubeindexes = 0;
|
||||
GLuint SharedObject::skytrivbo = 0;
|
||||
|
||||
static void initCubeVBO()
|
||||
static void initSkyTriVBO()
|
||||
{
|
||||
// From CSkyBoxSceneNode
|
||||
float corners[] =
|
||||
{
|
||||
// top side
|
||||
1., 1., -1.,
|
||||
1., 1., 1.,
|
||||
-1., 1., 1.,
|
||||
-1., 1., -1.,
|
||||
const float tri_vertex[] = {
|
||||
-1., -1., 1.,
|
||||
-1., 3., 1.,
|
||||
3., -1., 1.,
|
||||
};
|
||||
|
||||
// Bottom side
|
||||
1., -1., 1.,
|
||||
1., -1., -1.,
|
||||
-1., -1., -1.,
|
||||
-1., -1., 1.,
|
||||
|
||||
// right side
|
||||
1., -1, -1,
|
||||
1., -1, 1,
|
||||
1., 1., 1.,
|
||||
1., 1., -1.,
|
||||
|
||||
// left side
|
||||
-1., -1., 1.,
|
||||
-1., -1., -1.,
|
||||
-1., 1., -1.,
|
||||
-1., 1., 1.,
|
||||
|
||||
// back side
|
||||
-1., -1., -1.,
|
||||
1., -1, -1.,
|
||||
1, 1, -1.,
|
||||
-1, 1, -1.,
|
||||
|
||||
// front side
|
||||
1., -1., 1.,
|
||||
-1., -1., 1.,
|
||||
-1, 1., 1.,
|
||||
1., 1., 1.,
|
||||
};
|
||||
int indices[] = {
|
||||
0, 1, 2, 2, 3, 0,
|
||||
4, 5, 6, 6, 7, 4,
|
||||
8, 9, 10, 10, 11, 8,
|
||||
12, 13, 14, 14, 15, 12,
|
||||
16, 17, 18, 18, 19, 16,
|
||||
20, 21, 22, 22, 23, 20
|
||||
};
|
||||
|
||||
glGenBuffers(1, &SharedObject::cubevbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, SharedObject::cubevbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, 6 * 4 * 3 * sizeof(float), corners, GL_STATIC_DRAW);
|
||||
|
||||
glGenBuffers(1, &SharedObject::cubeindexes);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, SharedObject::cubeindexes);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * 6 * sizeof(int), indices, GL_STATIC_DRAW);
|
||||
glGenBuffers(1, &SharedObject::skytrivbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, SharedObject::skytrivbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, 3 * 3 * sizeof(float), tri_vertex, GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
GLuint SharedObject::frustrumvbo = 0;
|
||||
@ -535,7 +488,7 @@ void Shaders::loadShaders()
|
||||
initQuadVBO();
|
||||
initQuadBuffer();
|
||||
initBillboardVBO();
|
||||
initCubeVBO();
|
||||
initSkyTriVBO();
|
||||
initFrustrumVBO();
|
||||
initShadowVPMUBO();
|
||||
initLightingDataUBO();
|
||||
@ -1417,17 +1370,16 @@ namespace MeshShader
|
||||
SkyboxShader::SkyboxShader()
|
||||
{
|
||||
Program = LoadProgram(OBJECT,
|
||||
GL_VERTEX_SHADER, file_manager->getAsset("shaders/object_pass.vert").c_str(),
|
||||
GL_VERTEX_SHADER, file_manager->getAsset("shaders/sky.vert").c_str(),
|
||||
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/sky.frag").c_str());
|
||||
AssignUniforms("ModelMatrix");
|
||||
AssignUniforms();
|
||||
AssignSamplerNames(Program, 0, "tex");
|
||||
|
||||
glGenVertexArrays(1, &cubevao);
|
||||
glBindVertexArray(cubevao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, SharedObject::cubevbo);
|
||||
glGenVertexArrays(1, &vao);
|
||||
glBindVertexArray(vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, SharedObject::skytrivbo);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, SharedObject::cubeindexes);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ class SharedObject
|
||||
{
|
||||
public:
|
||||
static GLuint billboardvbo;
|
||||
static GLuint cubevbo, cubeindexes, frustrumvbo, frustrumindexes, ParticleQuadVBO;
|
||||
static GLuint skytrivbo, frustrumvbo, frustrumindexes, ParticleQuadVBO;
|
||||
static GLuint ViewProjectionMatrixesUBO, LightingDataUBO;
|
||||
static GLuint FullScreenQuadVAO;
|
||||
static GLuint UIVAO;
|
||||
@ -281,11 +281,11 @@ public:
|
||||
DisplaceShader();
|
||||
};
|
||||
|
||||
class SkyboxShader : public ShaderHelperSingleton<SkyboxShader, core::matrix4>, public TextureRead<Trilinear_cubemap>
|
||||
class SkyboxShader : public ShaderHelperSingleton<SkyboxShader>, public TextureRead<Trilinear_cubemap>
|
||||
{
|
||||
public:
|
||||
SkyboxShader();
|
||||
GLuint cubevao;
|
||||
GLuint vao;
|
||||
};
|
||||
|
||||
class NormalVisualizer : public ShaderHelperSingleton<NormalVisualizer, video::SColor>
|
||||
|
@ -55,8 +55,6 @@ public:
|
||||
virtual scene::IMesh *getMesh() OVERRIDE { return m_mesh; }
|
||||
virtual void setReadOnlyMaterials(bool) OVERRIDE {}
|
||||
virtual bool isReadOnlyMaterials() const OVERRIDE { return false; }
|
||||
virtual scene::IShadowVolumeSceneNode* addShadowVolumeSceneNode
|
||||
(const scene::IMesh*, int, bool, f32) OVERRIDE { return NULL; }
|
||||
|
||||
protected:
|
||||
video::SMaterial m_mat;
|
||||
|
Loading…
Reference in New Issue
Block a user