- added WAD Archive Loader ( Quake2 (WAL2) and Halflife (WAL3) are supported )
- CFileList added Offset Parameter to SFileListEntry and removed the private array from the archive loaders. CFileList::addItem now uses automatic incremental id if id = 0 git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@3336 dfc29bdd-3216-0410-991c-e03cc46cb475master
parent
816d5655fc
commit
2a8461a4fe
|
@ -12,10 +12,10 @@ Changes in 1.7.1 (05.07.2010) TA
|
|||
allow to disable the bump/parallax on the earth like in the room ( with transparency )
|
||||
- added DDS Image files, DXT2, DXT3, DXT4, DXT5, based on code from nvidia and Randy Reddig
|
||||
|
||||
- added a Halflife 1 Model Loader. ( bases on code by Fabio Concas )
|
||||
- added a Halflife 1 Model Loader. ( bases on code by Fabio Concas ) Halflife 1.1.0.8, Counter-Strike 1.6 working
|
||||
-> Load all Textures ( can even optimize it to texture atlas ), all bone animation, all submodels.
|
||||
-> But to make use of the values ( named animation, mouth animation ) the Interface for IAnimatedMeshSceneNode
|
||||
has to be reonde. I don't want to blow up the Interface again...
|
||||
has to be redone. I don't want to blow up the Interface again...
|
||||
|
||||
TODO:
|
||||
->can handle float frames numbers, the interface for getMesh should be reworked
|
||||
|
@ -75,7 +75,10 @@ Changes in 1.7.1 (05.07.2010) TA
|
|||
Valve uses WAL archive types like quake2. textures are inside model files
|
||||
I reworked the existing ImageloaderWAL and added named Halflife textures to wal2 ( they have not extension )
|
||||
and an LMP (palette/texture) loader into the same file ( all using 32bit now )
|
||||
|
||||
- added WAD Archive Loader ( Quake2 (WAL2) and Halflife (WAL3) are supported )
|
||||
- CFileList
|
||||
added Offset Parameter to SFileListEntry and removed the private array from the archive loaders.
|
||||
CFileList::addItem now uses automatic incremental id if id = 0
|
||||
- coreutil.h
|
||||
added void splitFilenam, splits a path into components
|
||||
- irstring.h
|
||||
|
|
|
@ -38,7 +38,7 @@ int main()
|
|||
if (driverType==video::EDT_COUNT)
|
||||
return 1;
|
||||
*/
|
||||
video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D9; // video::EDT_BURNINGSVIDEO; // video::EDT_OPENGL; //video::EDT_BURNINGSVIDEO;
|
||||
video::E_DRIVER_TYPE driverType = video::EDT_BURNINGSVIDEO;// video::EDT_DIRECT3D9; // video::EDT_BURNINGSVIDEO; // video::EDT_OPENGL; //video::EDT_BURNINGSVIDEO;
|
||||
bool shadows = true;
|
||||
|
||||
/*
|
||||
|
|
|
@ -42,6 +42,9 @@ enum E_FILE_ARCHIVE_TYPE
|
|||
//! A Tape ARchive
|
||||
EFAT_TAR = MAKE_IRR_ID('T','A','R', 0),
|
||||
|
||||
//! A wad Archive, Quake2, Halflife
|
||||
EFAT_WAD = MAKE_IRR_ID('W','A','D', 0),
|
||||
|
||||
//! The type of this archive is unknown
|
||||
EFAT_UNKNOWN = MAKE_IRR_ID('u','n','k','n')
|
||||
};
|
||||
|
|
|
@ -42,6 +42,12 @@ public:
|
|||
\return The size of the file in bytes. */
|
||||
virtual u32 getFileSize(u32 index) const = 0;
|
||||
|
||||
//! Returns the file offset of a file in the file list, based on an index.
|
||||
/** \param index is the zero based index of the file which should be returned.
|
||||
The index must be less than the amount getFileCount() returns.
|
||||
\return The size of the file in bytes. */
|
||||
virtual u32 getFileOffset(u32 index) const = 0;
|
||||
|
||||
//! Returns the ID of a file in the file list, based on an index.
|
||||
/** This optional ID can be used to link the file list entry to information held
|
||||
elsewhere. For example this could be an index in an IFileArchive, linking the entry
|
||||
|
@ -71,9 +77,10 @@ public:
|
|||
//! Add as a file or folder to the list
|
||||
/** \param fullPath The file name including path, from the root of the file list.
|
||||
\param isDirectory True if this is a directory rather than a file.
|
||||
\param offset, The file offset inside an archive
|
||||
\param size The size of the file in bytes.
|
||||
\param id The ID of the file in the archive which owns it */
|
||||
virtual u32 addItem(const io::path& fullPath, u32 size, bool isDirectory, u32 id=0) = 0;
|
||||
virtual u32 addItem(const io::path& fullPath, u32 offset, u32 size, bool isDirectory, u32 id=0) = 0;
|
||||
|
||||
//! Sorts the file list. You should call this after adding any items to the file list
|
||||
virtual void sort() = 0;
|
||||
|
|
|
@ -381,6 +381,8 @@ currently only supports zip archives, though. */
|
|||
#define __IRR_COMPILE_WITH_NPK_ARCHIVE_LOADER_
|
||||
//! Define __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_ if you want to open TAR archives
|
||||
#define __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_
|
||||
//! Define __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_ if you want to open WAD archives
|
||||
#define __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_
|
||||
|
||||
//! Set FPU settings
|
||||
/** Irrlicht should use approximate float and integer fpu techniques
|
||||
|
|
|
@ -60,11 +60,12 @@ const io::path& CFileList::getFullFileName(u32 index) const
|
|||
}
|
||||
|
||||
//! adds a file or folder
|
||||
u32 CFileList::addItem(const io::path& fullPath, u32 size, bool isDirectory, u32 id)
|
||||
u32 CFileList::addItem(const io::path& fullPath, u32 offset, u32 size, bool isDirectory, u32 id)
|
||||
{
|
||||
SFileListEntry entry;
|
||||
entry.ID = id ? id : Files.size();
|
||||
entry.Offset = offset;
|
||||
entry.Size = size;
|
||||
entry.ID = id;
|
||||
entry.Name = fullPath;
|
||||
entry.Name.replace('\\', '/');
|
||||
entry.IsDirectory = isDirectory;
|
||||
|
@ -116,6 +117,12 @@ u32 CFileList::getFileSize(u32 index) const
|
|||
return index < Files.size() ? Files[index].Size : 0;
|
||||
}
|
||||
|
||||
//! Returns the size of a file
|
||||
u32 CFileList::getFileOffset(u32 index) const
|
||||
{
|
||||
return index < Files.size() ? Files[index].Offset : 0;
|
||||
}
|
||||
|
||||
|
||||
//! Searches for a file or folder within the list, returns the index
|
||||
s32 CFileList::findFile(const io::path& filename, bool isDirectory = false) const
|
||||
|
|
|
@ -36,6 +36,9 @@ struct SFileListEntry
|
|||
file in an archive, which can hold things like data offset and CRC. */
|
||||
u32 ID;
|
||||
|
||||
//! FileOffset inside an archive
|
||||
u32 Offset;
|
||||
|
||||
//! True if this is a folder, false if not.
|
||||
bool IsDirectory;
|
||||
|
||||
|
@ -76,9 +79,10 @@ public:
|
|||
//! Add as a file or folder to the list
|
||||
/** \param fullPath The file name including path, up to the root of the file list.
|
||||
\param isDirectory True if this is a directory rather than a file.
|
||||
\param offset The offset where the file is stored in an archive
|
||||
\param size The size of the file in bytes.
|
||||
\param id The ID of the file in the archive which owns it */
|
||||
virtual u32 addItem(const io::path& fullPath, u32 size, bool isDirectory, u32 id=0);
|
||||
virtual u32 addItem(const io::path& fullPath, u32 offset, u32 size, bool isDirectory, u32 id=0);
|
||||
|
||||
//! Sorts the file list. You should call this after adding any items to the file list
|
||||
virtual void sort();
|
||||
|
@ -101,6 +105,9 @@ public:
|
|||
//! Returns the size of a file
|
||||
virtual u32 getFileSize(u32 index) const;
|
||||
|
||||
//! Returns the offest of a file
|
||||
virtual u32 getFileOffset(u32 index) const;
|
||||
|
||||
//! Searches for a file or folder within the list, returns the index
|
||||
virtual s32 findFile(const io::path& filename, bool isFolder) const;
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "CPakReader.h"
|
||||
#include "CNPKReader.h"
|
||||
#include "CTarReader.h"
|
||||
#include "CWADReader.h"
|
||||
#include "CFileList.h"
|
||||
#include "CXMLReader.h"
|
||||
#include "CXMLWriter.h"
|
||||
|
@ -75,6 +76,11 @@ CFileSystem::CFileSystem()
|
|||
#ifdef __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_
|
||||
ArchiveLoader.push_back(new CArchiveLoaderTAR(this));
|
||||
#endif
|
||||
|
||||
#ifdef __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_
|
||||
ArchiveLoader.push_back(new CArchiveLoaderWAD(this));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -699,7 +705,7 @@ IFileList* CFileSystem::createFileList()
|
|||
{
|
||||
if (core::isInSameDirectory(Path, merge->getFullFileName(j)) == 0)
|
||||
{
|
||||
r->addItem(merge->getFullFileName(j), merge->getFileSize(j), merge->isDirectory(j), 0);
|
||||
r->addItem(merge->getFullFileName(j), merge->getFileOffset(j), merge->getFileSize(j), merge->isDirectory(j), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ void CMountPointReader::buildDirectory()
|
|||
|
||||
if (!list->isDirectory(i))
|
||||
{
|
||||
addItem(full, list->getFileSize(i), false, RealFileNames.size());
|
||||
addItem(full, list->getFileOffset(i), list->getFileSize(i), false, RealFileNames.size());
|
||||
RealFileNames.push_back(list->getFullFileName(i));
|
||||
}
|
||||
else
|
||||
|
@ -131,7 +131,7 @@ void CMountPointReader::buildDirectory()
|
|||
|
||||
if ( rel != "." && rel != ".." )
|
||||
{
|
||||
addItem(full, 0, true, 0);
|
||||
addItem(full, 0, 0, true, 0);
|
||||
Parent->changeWorkingDirectoryTo(pwd);
|
||||
buildDirectory();
|
||||
Parent->changeWorkingDirectoryTo("..");
|
||||
|
|
|
@ -222,8 +222,7 @@ bool CNPKReader::scanLocalHeader()
|
|||
#ifdef IRR_DEBUG_NPK_READER
|
||||
os::Printer::log("Name", entry.Name);
|
||||
#endif
|
||||
addItem((isDir?dirName:dirName+entry.Name), entry.Length, isDir, Offsets.size());
|
||||
Offsets.push_back(entry.Offset+header.Offset);
|
||||
addItem((isDir?dirName:dirName+entry.Name), entry.Offset+header.Offset, entry.Length, isDir);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -244,12 +243,11 @@ IReadFile* CNPKReader::createAndOpenFile(const io::path& filename)
|
|||
//! opens a file by index
|
||||
IReadFile* CNPKReader::createAndOpenFile(u32 index)
|
||||
{
|
||||
if (index < Files.size())
|
||||
{
|
||||
return createLimitReadFile(Files[index].FullName, File, Offsets[Files[index].ID], Files[index].Size);
|
||||
}
|
||||
else
|
||||
if (index >= Files.size() )
|
||||
return 0;
|
||||
|
||||
const SFileListEntry &entry = Files[index];
|
||||
return createLimitReadFile( entry.FullName, File, entry.Offset, entry.Size );
|
||||
}
|
||||
|
||||
void CNPKReader::readString(core::stringc& name)
|
||||
|
|
|
@ -117,9 +117,6 @@ namespace io
|
|||
void readString(core::stringc& name);
|
||||
|
||||
IReadFile* File;
|
||||
|
||||
//! Contains offsets of the files from the start of the archive file
|
||||
core::array<u32> Offsets;
|
||||
};
|
||||
|
||||
} // end namespace io
|
||||
|
|
|
@ -145,7 +145,6 @@ bool CPakReader::scanLocalHeader()
|
|||
|
||||
const int numberOfFiles = header.length / sizeof(SPAKFileEntry);
|
||||
|
||||
Offsets.reallocate(numberOfFiles);
|
||||
// Loop through each entry in the table of contents
|
||||
for(int i = 0; i < numberOfFiles; i++)
|
||||
{
|
||||
|
@ -162,8 +161,7 @@ bool CPakReader::scanLocalHeader()
|
|||
entry.length = os::Byteswap::byteswap(entry.length);
|
||||
#endif
|
||||
|
||||
addItem(io::path(entry.name), entry.length, false, Offsets.size());
|
||||
Offsets.push_back(entry.offset);
|
||||
addItem(io::path(entry.name), entry.offset, entry.length, false );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -184,12 +182,11 @@ IReadFile* CPakReader::createAndOpenFile(const io::path& filename)
|
|||
//! opens a file by index
|
||||
IReadFile* CPakReader::createAndOpenFile(u32 index)
|
||||
{
|
||||
if (index < Files.size())
|
||||
{
|
||||
return createLimitReadFile(Files[index].FullName, File, Offsets[Files[index].ID], Files[index].Size);
|
||||
}
|
||||
else
|
||||
if (index >= Files.size() )
|
||||
return 0;
|
||||
|
||||
const SFileListEntry &entry = Files[index];
|
||||
return createLimitReadFile( entry.FullName, File, entry.Offset, entry.Size );
|
||||
}
|
||||
|
||||
} // end namespace io
|
||||
|
|
|
@ -114,8 +114,6 @@ namespace io
|
|||
|
||||
IReadFile* File;
|
||||
|
||||
//! Contains offsets of the files from the start of the archive file
|
||||
core::array<u32> Offsets;
|
||||
};
|
||||
|
||||
} // end namespace io
|
||||
|
|
|
@ -385,6 +385,7 @@ CBurningVideoDriver::CBurningVideoDriver(const irr::SIrrlichtCreationParameters&
|
|||
BurningShader[ETR_TEXTURE_GOURAUD_ALPHA_NOZ] = createTRTextureGouraudAlphaNoZ( this );
|
||||
|
||||
BurningShader[ETR_NORMAL_MAP_SOLID] = createTRNormalMap ( this );
|
||||
BurningShader[ETR_STENCIL_SHADOW] = createTRStencilShadow ( this );
|
||||
BurningShader[ETR_TEXTURE_BLEND] = createTRTextureBlend( this );
|
||||
|
||||
BurningShader[ETR_REFERENCE] = createTriangleRendererReference ( this );
|
||||
|
@ -446,11 +447,12 @@ CBurningVideoDriver::~CBurningVideoDriver()
|
|||
// delete triangle renderers
|
||||
|
||||
for (s32 i=0; i<ETR2_COUNT; ++i)
|
||||
{
|
||||
if (BurningShader[i])
|
||||
BurningShader[i]->drop();
|
||||
}
|
||||
|
||||
// delete zbuffer
|
||||
|
||||
// delete Additional buffer
|
||||
if (StencilBuffer)
|
||||
StencilBuffer->drop();
|
||||
|
||||
|
@ -1727,6 +1729,7 @@ void CBurningVideoDriver::drawVertexPrimitiveList(const void* vertices, u32 vert
|
|||
dc_area = screenarea2 ( face );
|
||||
if ( Material.org.BackfaceCulling && F32_LOWER_EQUAL_0( dc_area ) )
|
||||
continue;
|
||||
else
|
||||
if ( Material.org.FrontfaceCulling && F32_GREATER_EQUAL_0( dc_area ) )
|
||||
continue;
|
||||
|
||||
|
@ -1844,6 +1847,7 @@ void CBurningVideoDriver::drawVertexPrimitiveList(const void* vertices, u32 vert
|
|||
dc_area = screenarea ( CurrentOut.data );
|
||||
if ( Material.org.BackfaceCulling && F32_LOWER_EQUAL_0 ( dc_area ) )
|
||||
continue;
|
||||
else
|
||||
if ( Material.org.FrontfaceCulling && F32_GREATER_EQUAL_0( dc_area ) )
|
||||
continue;
|
||||
|
||||
|
@ -2547,6 +2551,41 @@ u32 CBurningVideoDriver::getMaximalPrimitiveCount() const
|
|||
//! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow.
|
||||
void CBurningVideoDriver::drawStencilShadowVolume(const core::vector3df* triangles, s32 count, bool zfail)
|
||||
{
|
||||
if (!StencilBuffer || !count)
|
||||
return;
|
||||
|
||||
IBurningShader *shader = BurningShader [ ETR_STENCIL_SHADOW ];
|
||||
shader->setRenderTarget(RenderTargetSurface, ViewPort);
|
||||
|
||||
//glStencilMask(~0);
|
||||
//glStencilFunc(GL_ALWAYS, 0, ~0);
|
||||
|
||||
if (zfail)
|
||||
{
|
||||
Material.org.BackfaceCulling = false;
|
||||
Material.org.FrontfaceCulling = true;
|
||||
//glStencilOp(GL_KEEP, incr, GL_KEEP);
|
||||
//glDrawArrays(GL_TRIANGLES,0,count);
|
||||
|
||||
Material.org.BackfaceCulling = true;
|
||||
Material.org.FrontfaceCulling = false;
|
||||
//glStencilOp(GL_KEEP, decr, GL_KEEP);
|
||||
//glDrawArrays(GL_TRIANGLES,0,count);
|
||||
}
|
||||
else // zpass
|
||||
{
|
||||
Material.org.BackfaceCulling = true;
|
||||
Material.org.FrontfaceCulling = false;
|
||||
//glStencilOp(GL_KEEP, GL_KEEP, incr);
|
||||
//glDrawArrays(GL_TRIANGLES,0,count);
|
||||
|
||||
Material.org.BackfaceCulling = false;
|
||||
Material.org.FrontfaceCulling = true;
|
||||
//glStencilOp(GL_KEEP, GL_KEEP, decr);
|
||||
//glDrawArrays(GL_TRIANGLES,0,count);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
if (!StencilBuffer || !count)
|
||||
return;
|
||||
|
|
|
@ -78,19 +78,6 @@ namespace irr
|
|||
namespace video
|
||||
{
|
||||
|
||||
#define iter1(N) trial = root + (1 << (N)); if (n >= trial << (N)) { n -= trial << (N); root |= 2 << (N); }
|
||||
|
||||
tFixPoint fixsqrt (tFixPoint n)
|
||||
{
|
||||
tFixPoint root = 0, trial;
|
||||
iter1 (15); iter1 (14); iter1 (13); iter1 (12);
|
||||
iter1 (11); iter1 (10); iter1 ( 9); iter1 ( 8);
|
||||
iter1 ( 7); iter1 ( 6); iter1 ( 5); iter1 ( 4);
|
||||
iter1 ( 3); iter1 ( 2); iter1 ( 1); iter1 ( 0);
|
||||
return root >> 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class CTRNormalMap : public IBurningShader
|
||||
{
|
||||
|
@ -111,8 +98,6 @@ private:
|
|||
|
||||
};
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
//! constructor
|
||||
CTRNormalMap::CTRNormalMap(CBurningVideoDriver* driver)
|
||||
: IBurningShader(driver)
|
||||
|
@ -120,21 +105,6 @@ CTRNormalMap::CTRNormalMap(CBurningVideoDriver* driver)
|
|||
#ifdef _DEBUG
|
||||
setDebugName("CTRNormalMap");
|
||||
#endif
|
||||
/*
|
||||
char buf[256];
|
||||
f32 f = 0.f;
|
||||
tFixPoint a;
|
||||
tFixPoint b;
|
||||
for ( u32 i = 0; i < 100000; ++i )
|
||||
{
|
||||
f += 0.5f;
|
||||
f32 r = sqrtf ( f );
|
||||
a = tofix ( f );
|
||||
b = fixsqrt ( a );
|
||||
sprintf ( buf, "%.7f %.7f %.7f %.7f\n", f, r, a / FIX_POINT_F32_MUL, b / FIX_POINT_F32_MUL );
|
||||
OutputDebugStringA ( buf );
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,767 @@
|
|||
// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
#include "IBurningShader.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
|
||||
|
||||
// compile flag for this file
|
||||
#undef USE_ZBUFFER
|
||||
#undef USE_SBUFFER
|
||||
#undef IPOL_Z
|
||||
#undef CMP_Z
|
||||
#undef WRITE_Z
|
||||
|
||||
#undef IPOL_W
|
||||
#undef CMP_W
|
||||
#undef WRITE_W
|
||||
|
||||
#undef SUBTEXEL
|
||||
#undef INVERSE_W
|
||||
|
||||
#undef IPOL_C0
|
||||
#undef IPOL_T0
|
||||
#undef IPOL_T1
|
||||
#undef IPOL_T2
|
||||
#undef IPOL_L0
|
||||
|
||||
// define render case
|
||||
#define SUBTEXEL
|
||||
#define INVERSE_W
|
||||
|
||||
#define USE_ZBUFFER
|
||||
#define USE_SBUFFER
|
||||
#define IPOL_W
|
||||
#define CMP_W
|
||||
//#define WRITE_W
|
||||
|
||||
|
||||
// apply global override
|
||||
#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT
|
||||
#undef INVERSE_W
|
||||
#endif
|
||||
|
||||
#ifndef SOFTWARE_DRIVER_2_SUBTEXEL
|
||||
#undef SUBTEXEL
|
||||
#endif
|
||||
|
||||
#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR
|
||||
#undef IPOL_C0
|
||||
#endif
|
||||
|
||||
#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER )
|
||||
#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT
|
||||
#undef IPOL_W
|
||||
#endif
|
||||
#define IPOL_Z
|
||||
|
||||
#ifdef CMP_W
|
||||
#undef CMP_W
|
||||
#define CMP_Z
|
||||
#endif
|
||||
|
||||
#ifdef WRITE_W
|
||||
#undef WRITE_W
|
||||
#define WRITE_Z
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace irr
|
||||
{
|
||||
|
||||
namespace video
|
||||
{
|
||||
|
||||
class CTRStencilShadow : public IBurningShader
|
||||
{
|
||||
public:
|
||||
|
||||
//! constructor
|
||||
CTRStencilShadow(CBurningVideoDriver* driver);
|
||||
|
||||
//! draws an indexed triangle list
|
||||
virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c );
|
||||
|
||||
|
||||
private:
|
||||
void scanline ();
|
||||
|
||||
sScanConvertData scan;
|
||||
sScanLineData line;
|
||||
|
||||
};
|
||||
|
||||
//! constructor
|
||||
CTRStencilShadow::CTRStencilShadow(CBurningVideoDriver* driver)
|
||||
: IBurningShader(driver)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CTRStencilShadow");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
*/
|
||||
void CTRStencilShadow::scanline ()
|
||||
{
|
||||
tVideoSample *dst;
|
||||
|
||||
#ifdef USE_ZBUFFER
|
||||
fp24 *z;
|
||||
#endif
|
||||
|
||||
#ifdef USE_SBUFFER
|
||||
u32 *stencil;
|
||||
#endif
|
||||
|
||||
s32 xStart;
|
||||
s32 xEnd;
|
||||
s32 dx;
|
||||
|
||||
|
||||
#ifdef SUBTEXEL
|
||||
f32 subPixel;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_Z
|
||||
f32 slopeZ;
|
||||
#endif
|
||||
#ifdef IPOL_W
|
||||
fp24 slopeW;
|
||||
#endif
|
||||
#ifdef IPOL_C0
|
||||
sVec4 slopeC[MATERIAL_MAX_COLORS];
|
||||
#endif
|
||||
#ifdef IPOL_T0
|
||||
sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES];
|
||||
#endif
|
||||
#ifdef IPOL_L0
|
||||
sVec3 slopeL[BURNING_MATERIAL_MAX_TANGENT];
|
||||
#endif
|
||||
|
||||
// apply top-left fill-convention, left
|
||||
xStart = core::ceil32( line.x[0] );
|
||||
xEnd = core::ceil32( line.x[1] ) - 1;
|
||||
|
||||
dx = xEnd - xStart;
|
||||
|
||||
if ( dx < 0 )
|
||||
return;
|
||||
|
||||
// slopes
|
||||
const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] );
|
||||
|
||||
#ifdef IPOL_Z
|
||||
slopeZ = (line.z[1] - line.z[0]) * invDeltaX;
|
||||
#endif
|
||||
#ifdef IPOL_W
|
||||
slopeW = (line.w[1] - line.w[0]) * invDeltaX;
|
||||
#endif
|
||||
#ifdef IPOL_C0
|
||||
slopeC[0] = (line.c[0][1] - line.c[0][0]) * invDeltaX;
|
||||
#endif
|
||||
#ifdef IPOL_T0
|
||||
slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX;
|
||||
#endif
|
||||
#ifdef IPOL_T1
|
||||
slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX;
|
||||
#endif
|
||||
#ifdef IPOL_T2
|
||||
slopeT[2] = (line.t[2][1] - line.t[2][0]) * invDeltaX;
|
||||
#endif
|
||||
#ifdef IPOL_L0
|
||||
slopeL[0] = (line.l[0][1] - line.l[0][0]) * invDeltaX;
|
||||
#endif
|
||||
|
||||
#ifdef SUBTEXEL
|
||||
subPixel = ( (f32) xStart ) - line.x[0];
|
||||
#ifdef IPOL_Z
|
||||
line.z[0] += slopeZ * subPixel;
|
||||
#endif
|
||||
#ifdef IPOL_W
|
||||
line.w[0] += slopeW * subPixel;
|
||||
#endif
|
||||
#ifdef IPOL_C0
|
||||
line.c[0][0] += slopeC[0] * subPixel;
|
||||
#endif
|
||||
#ifdef IPOL_T0
|
||||
line.t[0][0] += slopeT[0] * subPixel;
|
||||
#endif
|
||||
#ifdef IPOL_T1
|
||||
line.t[1][0] += slopeT[1] * subPixel;
|
||||
#endif
|
||||
#ifdef IPOL_T2
|
||||
line.t[2][0] += slopeT[2] * subPixel;
|
||||
#endif
|
||||
#ifdef IPOL_L0
|
||||
line.l[0][0] += slopeL[0] * subPixel;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
dst = (tVideoSample*)RenderTarget->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart;
|
||||
|
||||
#ifdef USE_ZBUFFER
|
||||
z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart;
|
||||
#endif
|
||||
|
||||
#ifdef USE_SBUFFER
|
||||
stencil = (u32*) Stencil->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef INVERSE_W
|
||||
f32 inversew;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef IPOL_C0
|
||||
tFixPoint r3, g3, b3;
|
||||
#endif
|
||||
|
||||
for ( s32 i = 0; i <= dx; i++ )
|
||||
{
|
||||
#ifdef CMP_Z
|
||||
if ( line.z[0] < z[i] )
|
||||
#endif
|
||||
#ifdef CMP_W
|
||||
if ( line.w[0] >= z[i] )
|
||||
#endif
|
||||
{
|
||||
#ifdef INVERSE_W
|
||||
inversew = fix_inverse32 ( line.w[0] );
|
||||
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
dst[i] = 0xFFFFFFFF;
|
||||
|
||||
#ifdef WRITE_Z
|
||||
z[i] = line.z[0];
|
||||
#endif
|
||||
#ifdef WRITE_W
|
||||
z[i] = line.w[0];
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef IPOL_Z
|
||||
line.z[0] += slopeZ;
|
||||
#endif
|
||||
#ifdef IPOL_W
|
||||
line.w[0] += slopeW;
|
||||
#endif
|
||||
#ifdef IPOL_C0
|
||||
line.c[0][0] += slopeC[0];
|
||||
#endif
|
||||
#ifdef IPOL_T0
|
||||
line.t[0][0] += slopeT[0];
|
||||
#endif
|
||||
#ifdef IPOL_T1
|
||||
line.t[1][0] += slopeT[1];
|
||||
#endif
|
||||
#ifdef IPOL_T2
|
||||
line.t[2][0] += slopeT[2];
|
||||
#endif
|
||||
#ifdef IPOL_L0
|
||||
line.l[0][0] += slopeL[0];
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CTRStencilShadow::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c )
|
||||
{
|
||||
// sort on height, y
|
||||
if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b);
|
||||
if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c);
|
||||
if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b);
|
||||
|
||||
const f32 ca = c->Pos.y - a->Pos.y;
|
||||
const f32 ba = b->Pos.y - a->Pos.y;
|
||||
const f32 cb = c->Pos.y - b->Pos.y;
|
||||
// calculate delta y of the edges
|
||||
scan.invDeltaY[0] = core::reciprocal( ca );
|
||||
scan.invDeltaY[1] = core::reciprocal( ba );
|
||||
scan.invDeltaY[2] = core::reciprocal( cb );
|
||||
|
||||
if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) )
|
||||
return;
|
||||
|
||||
// find if the major edge is left or right aligned
|
||||
f32 temp[4];
|
||||
|
||||
temp[0] = a->Pos.x - c->Pos.x;
|
||||
temp[1] = -ca;
|
||||
temp[2] = b->Pos.x - a->Pos.x;
|
||||
temp[3] = ba;
|
||||
|
||||
scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1;
|
||||
scan.right = 1 - scan.left;
|
||||
|
||||
// calculate slopes for the major edge
|
||||
scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0];
|
||||
scan.x[0] = a->Pos.x;
|
||||
|
||||
#ifdef IPOL_Z
|
||||
scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0];
|
||||
scan.z[0] = a->Pos.z;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_W
|
||||
scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0];
|
||||
scan.w[0] = a->Pos.w;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_C0
|
||||
scan.slopeC[0][0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0];
|
||||
scan.c[0][0] = a->Color[0];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T0
|
||||
scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0];
|
||||
scan.t[0][0] = a->Tex[0];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T1
|
||||
scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0];
|
||||
scan.t[1][0] = a->Tex[1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T2
|
||||
scan.slopeT[2][0] = (c->Tex[2] - a->Tex[2]) * scan.invDeltaY[0];
|
||||
scan.t[2][0] = a->Tex[2];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_L0
|
||||
scan.slopeL[0][0] = (c->LightTangent[0] - a->LightTangent[0]) * scan.invDeltaY[0];
|
||||
scan.l[0][0] = a->LightTangent[0];
|
||||
#endif
|
||||
|
||||
// top left fill convention y run
|
||||
s32 yStart;
|
||||
s32 yEnd;
|
||||
|
||||
#ifdef SUBTEXEL
|
||||
f32 subPixel;
|
||||
#endif
|
||||
|
||||
|
||||
// rasterize upper sub-triangle
|
||||
//if ( (f32) 0.0 != scan.invDeltaY[1] )
|
||||
if ( F32_GREATER_0 ( scan.invDeltaY[1] ) )
|
||||
{
|
||||
// calculate slopes for top edge
|
||||
scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1];
|
||||
scan.x[1] = a->Pos.x;
|
||||
|
||||
#ifdef IPOL_Z
|
||||
scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1];
|
||||
scan.z[1] = a->Pos.z;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_W
|
||||
scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1];
|
||||
scan.w[1] = a->Pos.w;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_C0
|
||||
scan.slopeC[0][1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1];
|
||||
scan.c[0][1] = a->Color[0];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T0
|
||||
scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1];
|
||||
scan.t[0][1] = a->Tex[0];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T1
|
||||
scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1];
|
||||
scan.t[1][1] = a->Tex[1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T2
|
||||
scan.slopeT[2][1] = (b->Tex[2] - a->Tex[2]) * scan.invDeltaY[1];
|
||||
scan.t[2][1] = a->Tex[2];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_L0
|
||||
scan.slopeL[0][1] = (b->LightTangent[0] - a->LightTangent[0]) * scan.invDeltaY[1];
|
||||
scan.l[0][1] = a->LightTangent[0];
|
||||
#endif
|
||||
|
||||
// apply top-left fill convention, top part
|
||||
yStart = core::ceil32( a->Pos.y );
|
||||
yEnd = core::ceil32( b->Pos.y ) - 1;
|
||||
|
||||
#ifdef SUBTEXEL
|
||||
subPixel = ( (f32) yStart ) - a->Pos.y;
|
||||
|
||||
// correct to pixel center
|
||||
scan.x[0] += scan.slopeX[0] * subPixel;
|
||||
scan.x[1] += scan.slopeX[1] * subPixel;
|
||||
|
||||
#ifdef IPOL_Z
|
||||
scan.z[0] += scan.slopeZ[0] * subPixel;
|
||||
scan.z[1] += scan.slopeZ[1] * subPixel;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_W
|
||||
scan.w[0] += scan.slopeW[0] * subPixel;
|
||||
scan.w[1] += scan.slopeW[1] * subPixel;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_C0
|
||||
scan.c[0][0] += scan.slopeC[0][0] * subPixel;
|
||||
scan.c[0][1] += scan.slopeC[0][1] * subPixel;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T0
|
||||
scan.t[0][0] += scan.slopeT[0][0] * subPixel;
|
||||
scan.t[0][1] += scan.slopeT[0][1] * subPixel;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T1
|
||||
scan.t[1][0] += scan.slopeT[1][0] * subPixel;
|
||||
scan.t[1][1] += scan.slopeT[1][1] * subPixel;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T2
|
||||
scan.t[2][0] += scan.slopeT[2][0] * subPixel;
|
||||
scan.t[2][1] += scan.slopeT[2][1] * subPixel;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_L0
|
||||
scan.l[0][0] += scan.slopeL[0][0] * subPixel;
|
||||
scan.l[0][1] += scan.slopeL[0][1] * subPixel;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// rasterize the edge scanlines
|
||||
for( line.y = yStart; line.y <= yEnd; ++line.y)
|
||||
{
|
||||
line.x[scan.left] = scan.x[0];
|
||||
line.x[scan.right] = scan.x[1];
|
||||
|
||||
#ifdef IPOL_Z
|
||||
line.z[scan.left] = scan.z[0];
|
||||
line.z[scan.right] = scan.z[1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_W
|
||||
line.w[scan.left] = scan.w[0];
|
||||
line.w[scan.right] = scan.w[1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_C0
|
||||
line.c[0][scan.left] = scan.c[0][0];
|
||||
line.c[0][scan.right] = scan.c[0][1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T0
|
||||
line.t[0][scan.left] = scan.t[0][0];
|
||||
line.t[0][scan.right] = scan.t[0][1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T1
|
||||
line.t[1][scan.left] = scan.t[1][0];
|
||||
line.t[1][scan.right] = scan.t[1][1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T2
|
||||
line.t[2][scan.left] = scan.t[2][0];
|
||||
line.t[2][scan.right] = scan.t[2][1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_L0
|
||||
line.l[0][scan.left] = scan.l[0][0];
|
||||
line.l[0][scan.right] = scan.l[0][1];
|
||||
#endif
|
||||
|
||||
// render a scanline
|
||||
scanline ();
|
||||
|
||||
scan.x[0] += scan.slopeX[0];
|
||||
scan.x[1] += scan.slopeX[1];
|
||||
|
||||
#ifdef IPOL_Z
|
||||
scan.z[0] += scan.slopeZ[0];
|
||||
scan.z[1] += scan.slopeZ[1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_W
|
||||
scan.w[0] += scan.slopeW[0];
|
||||
scan.w[1] += scan.slopeW[1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_C0
|
||||
scan.c[0][0] += scan.slopeC[0][0];
|
||||
scan.c[0][1] += scan.slopeC[0][1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T0
|
||||
scan.t[0][0] += scan.slopeT[0][0];
|
||||
scan.t[0][1] += scan.slopeT[0][1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T1
|
||||
scan.t[1][0] += scan.slopeT[1][0];
|
||||
scan.t[1][1] += scan.slopeT[1][1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T2
|
||||
scan.t[2][0] += scan.slopeT[2][0];
|
||||
scan.t[2][1] += scan.slopeT[2][1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_L0
|
||||
scan.l[0][0] += scan.slopeL[0][0];
|
||||
scan.l[0][1] += scan.slopeL[0][1];
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// rasterize lower sub-triangle
|
||||
//if ( (f32) 0.0 != scan.invDeltaY[2] )
|
||||
if ( F32_GREATER_0 ( scan.invDeltaY[2] ) )
|
||||
{
|
||||
// advance to middle point
|
||||
//if( (f32) 0.0 != scan.invDeltaY[1] )
|
||||
if ( F32_GREATER_0 ( scan.invDeltaY[1] ) )
|
||||
{
|
||||
temp[0] = b->Pos.y - a->Pos.y; // dy
|
||||
|
||||
scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0];
|
||||
#ifdef IPOL_Z
|
||||
scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0];
|
||||
#endif
|
||||
#ifdef IPOL_W
|
||||
scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0];
|
||||
#endif
|
||||
#ifdef IPOL_C0
|
||||
scan.c[0][0] = a->Color[0] + scan.slopeC[0][0] * temp[0];
|
||||
#endif
|
||||
#ifdef IPOL_T0
|
||||
scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0];
|
||||
#endif
|
||||
#ifdef IPOL_T1
|
||||
scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0];
|
||||
#endif
|
||||
#ifdef IPOL_T2
|
||||
scan.t[2][0] = a->Tex[2] + scan.slopeT[2][0] * temp[0];
|
||||
#endif
|
||||
#ifdef IPOL_L0
|
||||
scan.l[0][0] = a->LightTangent[0] + scan.slopeL[0][0] * temp[0];
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// calculate slopes for bottom edge
|
||||
scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2];
|
||||
scan.x[1] = b->Pos.x;
|
||||
|
||||
#ifdef IPOL_Z
|
||||
scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2];
|
||||
scan.z[1] = b->Pos.z;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_W
|
||||
scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2];
|
||||
scan.w[1] = b->Pos.w;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_C0
|
||||
scan.slopeC[0][1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2];
|
||||
scan.c[0][1] = b->Color[0];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T0
|
||||
scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2];
|
||||
scan.t[0][1] = b->Tex[0];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T1
|
||||
scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2];
|
||||
scan.t[1][1] = b->Tex[1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T2
|
||||
scan.slopeT[2][1] = (c->Tex[2] - b->Tex[2]) * scan.invDeltaY[2];
|
||||
scan.t[2][1] = b->Tex[2];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_L0
|
||||
scan.slopeL[0][1] = (c->LightTangent[0] - b->LightTangent[0]) * scan.invDeltaY[2];
|
||||
scan.l[0][1] = b->LightTangent[0];
|
||||
#endif
|
||||
|
||||
// apply top-left fill convention, top part
|
||||
yStart = core::ceil32( b->Pos.y );
|
||||
yEnd = core::ceil32( c->Pos.y ) - 1;
|
||||
|
||||
#ifdef SUBTEXEL
|
||||
|
||||
subPixel = ( (f32) yStart ) - b->Pos.y;
|
||||
|
||||
// correct to pixel center
|
||||
scan.x[0] += scan.slopeX[0] * subPixel;
|
||||
scan.x[1] += scan.slopeX[1] * subPixel;
|
||||
|
||||
#ifdef IPOL_Z
|
||||
scan.z[0] += scan.slopeZ[0] * subPixel;
|
||||
scan.z[1] += scan.slopeZ[1] * subPixel;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_W
|
||||
scan.w[0] += scan.slopeW[0] * subPixel;
|
||||
scan.w[1] += scan.slopeW[1] * subPixel;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_C0
|
||||
scan.c[0][0] += scan.slopeC[0][0] * subPixel;
|
||||
scan.c[0][1] += scan.slopeC[0][1] * subPixel;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T0
|
||||
scan.t[0][0] += scan.slopeT[0][0] * subPixel;
|
||||
scan.t[0][1] += scan.slopeT[0][1] * subPixel;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T1
|
||||
scan.t[1][0] += scan.slopeT[1][0] * subPixel;
|
||||
scan.t[1][1] += scan.slopeT[1][1] * subPixel;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T2
|
||||
scan.t[2][0] += scan.slopeT[2][0] * subPixel;
|
||||
scan.t[2][1] += scan.slopeT[2][1] * subPixel;
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_L0
|
||||
scan.l[0][0] += scan.slopeL[0][0] * subPixel;
|
||||
scan.l[0][1] += scan.slopeL[0][1] * subPixel;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// rasterize the edge scanlines
|
||||
for( line.y = yStart; line.y <= yEnd; ++line.y)
|
||||
{
|
||||
line.x[scan.left] = scan.x[0];
|
||||
line.x[scan.right] = scan.x[1];
|
||||
|
||||
#ifdef IPOL_Z
|
||||
line.z[scan.left] = scan.z[0];
|
||||
line.z[scan.right] = scan.z[1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_W
|
||||
line.w[scan.left] = scan.w[0];
|
||||
line.w[scan.right] = scan.w[1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_C0
|
||||
line.c[0][scan.left] = scan.c[0][0];
|
||||
line.c[0][scan.right] = scan.c[0][1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T0
|
||||
line.t[0][scan.left] = scan.t[0][0];
|
||||
line.t[0][scan.right] = scan.t[0][1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T1
|
||||
line.t[1][scan.left] = scan.t[1][0];
|
||||
line.t[1][scan.right] = scan.t[1][1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T2
|
||||
line.t[2][scan.left] = scan.t[2][0];
|
||||
line.t[2][scan.right] = scan.t[2][1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_L0
|
||||
line.l[0][scan.left] = scan.l[0][0];
|
||||
line.l[0][scan.right] = scan.l[0][1];
|
||||
#endif
|
||||
|
||||
// render a scanline
|
||||
scanline ();
|
||||
|
||||
scan.x[0] += scan.slopeX[0];
|
||||
scan.x[1] += scan.slopeX[1];
|
||||
|
||||
#ifdef IPOL_Z
|
||||
scan.z[0] += scan.slopeZ[0];
|
||||
scan.z[1] += scan.slopeZ[1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_W
|
||||
scan.w[0] += scan.slopeW[0];
|
||||
scan.w[1] += scan.slopeW[1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_C0
|
||||
scan.c[0][0] += scan.slopeC[0][0];
|
||||
scan.c[0][1] += scan.slopeC[0][1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T0
|
||||
scan.t[0][0] += scan.slopeT[0][0];
|
||||
scan.t[0][1] += scan.slopeT[0][1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_T1
|
||||
scan.t[1][0] += scan.slopeT[1][0];
|
||||
scan.t[1][1] += scan.slopeT[1][1];
|
||||
#endif
|
||||
#ifdef IPOL_T2
|
||||
scan.t[2][0] += scan.slopeT[2][0];
|
||||
scan.t[2][1] += scan.slopeT[2][1];
|
||||
#endif
|
||||
|
||||
#ifdef IPOL_L0
|
||||
scan.l[0][0] += scan.slopeL[0][0];
|
||||
scan.l[0][1] += scan.slopeL[0][1];
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
|
||||
//! creates a triangle renderer
|
||||
IBurningShader* createTRStencilShadow(CBurningVideoDriver* driver)
|
||||
{
|
||||
#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
|
||||
return new CTRStencilShadow(driver);
|
||||
#else
|
||||
return 0;
|
||||
#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_
|
||||
}
|
||||
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
|
||||
|
|
@ -216,8 +216,7 @@ u32 CTarReader::populateFileList()
|
|||
pos = offset + (size / 512) * 512 + ((size % 512) ? 512 : 0);
|
||||
|
||||
// add file to list
|
||||
addItem(fullPath, size, false, Offsets.size());
|
||||
Offsets.push_back(offset);
|
||||
addItem(fullPath, offset, size, false );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -246,10 +245,11 @@ IReadFile* CTarReader::createAndOpenFile(const io::path& filename)
|
|||
//! opens a file by index
|
||||
IReadFile* CTarReader::createAndOpenFile(u32 index)
|
||||
{
|
||||
if (index < Files.size())
|
||||
return createLimitReadFile(Files[index].FullName, File, Offsets[Files[index].ID], Files[index].Size);
|
||||
else
|
||||
if (index >= Files.size() )
|
||||
return 0;
|
||||
|
||||
const SFileListEntry &entry = Files[index];
|
||||
return createLimitReadFile( entry.FullName, File, entry.Offset, entry.Size );
|
||||
}
|
||||
|
||||
} // end namespace io
|
||||
|
|
|
@ -135,9 +135,6 @@ namespace io
|
|||
u32 populateFileList();
|
||||
|
||||
IReadFile* File;
|
||||
|
||||
//! Contains offsets of the files from the start of the archive file
|
||||
core::array<u32> Offsets;
|
||||
};
|
||||
|
||||
} // end namespace io
|
||||
|
|
|
@ -0,0 +1,263 @@
|
|||
// Copyright (C) 2002-2009 Thomas Alten
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
// Code contributed by skreamz
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
|
||||
#ifdef __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_
|
||||
|
||||
#include "CWADReader.h"
|
||||
#include "os.h"
|
||||
#include "coreutil.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
//! Constructor
|
||||
CArchiveLoaderWAD::CArchiveLoaderWAD( io::IFileSystem* fs)
|
||||
: FileSystem(fs)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CArchiveLoaderWAD");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
bool CArchiveLoaderWAD::isALoadableFileFormat(const io::path& filename) const
|
||||
{
|
||||
return core::hasFileExtension ( filename, "wad" );
|
||||
}
|
||||
|
||||
|
||||
//! Creates an archive from the filename
|
||||
/** \param file File handle to check.
|
||||
\return Pointer to newly created archive, or 0 upon error. */
|
||||
IFileArchive* CArchiveLoaderWAD::createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const
|
||||
{
|
||||
IFileArchive *archive = 0;
|
||||
io::IReadFile* file = FileSystem->createAndOpenFile(filename);
|
||||
|
||||
if (file)
|
||||
{
|
||||
archive = createArchive ( file, ignoreCase, ignorePaths );
|
||||
file->drop ();
|
||||
}
|
||||
|
||||
return archive;
|
||||
}
|
||||
|
||||
//! creates/loads an archive from the file.
|
||||
//! \return Pointer to the created archive. Returns 0 if loading failed.
|
||||
IFileArchive* CArchiveLoaderWAD::createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const
|
||||
{
|
||||
IFileArchive *archive = 0;
|
||||
if ( file )
|
||||
{
|
||||
file->seek ( 0 );
|
||||
archive = new CWADReader(file, ignoreCase, ignorePaths);
|
||||
}
|
||||
return archive;
|
||||
}
|
||||
|
||||
|
||||
//! Check if the file might be loaded by this class
|
||||
/** Check might look into the file.
|
||||
\param file File handle to check.
|
||||
\return True if file seems to be loadable. */
|
||||
bool CArchiveLoaderWAD::isALoadableFileFormat(io::IReadFile* file) const
|
||||
{
|
||||
SWADFileHeader header;
|
||||
memset(&header, 0, sizeof(header));
|
||||
|
||||
file->read( &header.tag, 4 );
|
||||
|
||||
return !strncmp ( header.tag, "WAD2", 4 ) || !strncmp ( header.tag, "WAD3", 4 );
|
||||
}
|
||||
|
||||
//! Check to see if the loader can create archives of this type.
|
||||
bool CArchiveLoaderWAD::isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const
|
||||
{
|
||||
return fileType == EFAT_WAD;
|
||||
}
|
||||
|
||||
void createDir ( const c8 *full );
|
||||
|
||||
|
||||
/*!
|
||||
WAD Reader
|
||||
*/
|
||||
CWADReader::CWADReader(IReadFile* file, bool ignoreCase, bool ignorePaths)
|
||||
: CFileList((file ? file->getFileName() : io::path("")), ignoreCase, ignorePaths), File(file)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CWADReader");
|
||||
#endif
|
||||
|
||||
if (File)
|
||||
{
|
||||
File->grab();
|
||||
|
||||
Base = File->getFileName();
|
||||
Base.replace ( '\\', '/' );
|
||||
|
||||
// scan local headers
|
||||
scanLocalHeader();
|
||||
|
||||
sort();
|
||||
}
|
||||
|
||||
#if 0
|
||||
for ( u32 i = 0; i < FileList.size(); ++i )
|
||||
{
|
||||
SWADFileEntry &e = FileList[i];
|
||||
char buf[128];
|
||||
snprintf ( buf, 128, "c:\\h2\\%s", e.wadFileName.c_str() );
|
||||
|
||||
createDir ( buf );
|
||||
FILE * f = fopen ( buf, "wb" );
|
||||
if ( 0 == f )
|
||||
continue;
|
||||
|
||||
u8 * mem = new u8 [ e.header.disksize ];
|
||||
File->seek ( e.header.filepos );
|
||||
File->read ( mem, e.header.disksize );
|
||||
fwrite ( mem, e.header.disksize, 1, f );
|
||||
delete [] mem;
|
||||
fclose ( f );
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
CWADReader::~CWADReader()
|
||||
{
|
||||
if (File)
|
||||
File->drop();
|
||||
}
|
||||
|
||||
|
||||
//! return the id of the file Archive
|
||||
const io::path& CWADReader::getArchiveName () const
|
||||
{
|
||||
return Base;
|
||||
}
|
||||
|
||||
const IFileList* CWADReader::getFileList() const
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
//! scans for a local header, returns false if there is no more local file header.
|
||||
bool CWADReader::scanLocalHeader()
|
||||
{
|
||||
SWADFileEntryOriginal entry;
|
||||
SWADFileEntry save;
|
||||
|
||||
memset(&Header, 0, sizeof(SWADFileHeader));
|
||||
File->read(&Header, sizeof(SWADFileHeader));
|
||||
|
||||
if ( 0 == strncmp ( Header.tag, "WAD2", 4 ) )
|
||||
WadType = WAD_FORMAT_QUAKE2;
|
||||
else
|
||||
if ( 0 == strncmp ( Header.tag, "WAD3", 4 ) )
|
||||
WadType = WAD_FORMAT_HALFLIFE;
|
||||
else
|
||||
WadType = WAD_FORMAT_UNKNOWN;
|
||||
|
||||
if ( WadType == WAD_FORMAT_UNKNOWN )
|
||||
return false;
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
header.numlumps = os::Byteswap::byteswap(header.numlumps);
|
||||
header.infotableofs = os::Byteswap::byteswap(header.infotableofs);
|
||||
#endif
|
||||
|
||||
File->seek ( Header.infotableofs );
|
||||
|
||||
c8 buf[16];
|
||||
for ( u32 i = 0; i < Header.numlumps; ++i )
|
||||
{
|
||||
// read entry
|
||||
File->read(&entry, sizeof ( SWADFileEntryOriginal ));
|
||||
entry.name[ sizeof ( entry.name ) - 1 ] = 0;
|
||||
|
||||
save.header = entry;
|
||||
save.wadFileName = "/";
|
||||
save.wadFileName += entry.name;
|
||||
|
||||
if ( WadType == WAD_FORMAT_HALFLIFE )
|
||||
{
|
||||
// don't know about the types! i'm guessing
|
||||
switch ( entry.type )
|
||||
{
|
||||
case WAD_TYP_MIPTEX_HALFLIFE:
|
||||
save.wadFileName += ".wal2";
|
||||
break;
|
||||
default:
|
||||
snprintf ( buf, 16, ".%02d", entry.type );
|
||||
save.wadFileName += buf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
if ( WadType == WAD_FORMAT_QUAKE2 )
|
||||
{
|
||||
switch ( entry.type )
|
||||
{
|
||||
case WAD_TYP_MIPTEX: save.wadFileName += ".miptex"; break;
|
||||
case WAD_TYP_SOUND: save.wadFileName += ".sound"; break;
|
||||
case WAD_TYP_PALETTE: save.wadFileName += ".palette"; break;
|
||||
case WAD_TYP_QTEX: save.wadFileName += ".qtex"; break;
|
||||
case WAD_TYP_QPIC: save.wadFileName += ".qpic"; break;
|
||||
case WAD_TYP_FONT: save.wadFileName += ".font"; break;
|
||||
default:
|
||||
snprintf ( buf, 16, ".%02d", entry.type );
|
||||
save.wadFileName += buf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// add file to list
|
||||
addItem(save.wadFileName,save.header.filepos, save.header.disksize, false );
|
||||
//FileInfo.push_back(save);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//! opens a file by file name
|
||||
IReadFile* CWADReader::createAndOpenFile(const io::path& filename)
|
||||
{
|
||||
s32 index = findFile(filename, false);
|
||||
|
||||
if (index != -1)
|
||||
return createAndOpenFile(index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! opens a file by index
|
||||
IReadFile* CWADReader::createAndOpenFile(u32 index)
|
||||
{
|
||||
if (index >= Files.size() )
|
||||
return 0;
|
||||
|
||||
const SFileListEntry &entry = Files[index];
|
||||
return createLimitReadFile( entry.FullName, File, entry.Offset, entry.Size );
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace io
|
||||
} // end namespace irr
|
||||
|
||||
|
||||
#endif // __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
// Copyright (C) 2002-2009 Thomas Alten
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef __C_WAD_READER_H_INCLUDED__
|
||||
#define __C_WAD_READER_H_INCLUDED__
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
#ifdef __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_
|
||||
|
||||
#include "IReferenceCounted.h"
|
||||
#include "IReadFile.h"
|
||||
#include "irrArray.h"
|
||||
#include "irrString.h"
|
||||
#include "IFileSystem.h"
|
||||
#include "CFileList.h"
|
||||
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
|
||||
# pragma pack( push, packing )
|
||||
# pragma pack( 1 )
|
||||
# define PACK_STRUCT
|
||||
#elif defined( __GNUC__ )
|
||||
# define PACK_STRUCT __attribute__((packed))
|
||||
#else
|
||||
# error compiler not supported
|
||||
#endif
|
||||
|
||||
|
||||
enum eWADFileTypes
|
||||
{
|
||||
WAD_FORMAT_UNKNOWN = 0,
|
||||
WAD_FORMAT_QUAKE2 = 1,
|
||||
WAD_FORMAT_HALFLIFE = 2,
|
||||
|
||||
WAD_CMP_NONE = 0,
|
||||
WAD_CMP_LZSS = 1,
|
||||
|
||||
WAD_TYP_NONE = 0,
|
||||
WAD_TYP_LABEL = 1,
|
||||
|
||||
WAD_TYP_LUMPY = 64, // 64 + grab command number
|
||||
WAD_TYP_PALETTE = 64,
|
||||
WAD_TYP_QTEX = 65,
|
||||
WAD_TYP_QPIC = 66,
|
||||
WAD_TYP_SOUND = 67,
|
||||
WAD_TYP_MIPTEX = 68,
|
||||
WAD_TYP_MIPTEX_HALFLIFE = 67,
|
||||
WAD_TYP_FONT = 70,
|
||||
};
|
||||
|
||||
struct SWADFileHeader
|
||||
{
|
||||
c8 tag[4]; // type of WAD format WAD2 = quake2, WAD3 = halflife
|
||||
u32 numlumps;
|
||||
u32 infotableofs;
|
||||
} PACK_STRUCT;
|
||||
|
||||
struct SWADFileEntryOriginal
|
||||
{
|
||||
u32 filepos;
|
||||
u32 disksize;
|
||||
u32 size; // uncompressed
|
||||
u8 type;
|
||||
u8 compression;
|
||||
u8 pad[2];
|
||||
u8 name[16]; // must be null terminated
|
||||
} PACK_STRUCT;
|
||||
|
||||
// Default alignment
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
|
||||
# pragma pack( pop, packing )
|
||||
#endif
|
||||
|
||||
#undef PACK_STRUCT
|
||||
|
||||
struct SWADFileEntry
|
||||
{
|
||||
io::path simpleFileName;
|
||||
bool operator < (const SWADFileEntry& other) const
|
||||
{
|
||||
return simpleFileName < other.simpleFileName;
|
||||
}
|
||||
|
||||
io::path wadFileName;
|
||||
SWADFileEntryOriginal header;
|
||||
};
|
||||
|
||||
//! Archiveloader capable of loading WAD Archives
|
||||
class CArchiveLoaderWAD : public IArchiveLoader
|
||||
{
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
CArchiveLoaderWAD(io::IFileSystem* fs);
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".zip")
|
||||
virtual bool isALoadableFileFormat(const io::path& filename) const;
|
||||
|
||||
//! Check if the file might be loaded by this class
|
||||
/** Check might look into the file.
|
||||
\param file File handle to check.
|
||||
\return True if file seems to be loadable. */
|
||||
virtual bool isALoadableFileFormat(io::IReadFile* file) const;
|
||||
|
||||
//! Check to see if the loader can create archives of this type.
|
||||
/** Check based on the archive type.
|
||||
\param fileType The archive type to check.
|
||||
\return True if the archile loader supports this type, false if not */
|
||||
virtual bool isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const;
|
||||
|
||||
//! Creates an archive from the filename
|
||||
/** \param file File handle to check.
|
||||
\return Pointer to newly created archive, or 0 upon error. */
|
||||
virtual IFileArchive* createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const;
|
||||
|
||||
//! creates/loads an archive from the file.
|
||||
//! \return Pointer to the created archive. Returns 0 if loading failed.
|
||||
virtual io::IFileArchive* createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const;
|
||||
|
||||
private:
|
||||
io::IFileSystem* FileSystem;
|
||||
};
|
||||
|
||||
|
||||
//! reads from WAD
|
||||
class CWADReader : public IFileArchive, virtual CFileList
|
||||
{
|
||||
public:
|
||||
|
||||
CWADReader(IReadFile* file, bool ignoreCase, bool ignorePaths);
|
||||
virtual ~CWADReader();
|
||||
|
||||
// file archive methods
|
||||
|
||||
//! return the id of the file Archive
|
||||
virtual const io::path& getArchiveName() const;
|
||||
|
||||
//! opens a file by file name
|
||||
virtual IReadFile* createAndOpenFile(const io::path& filename);
|
||||
|
||||
//! opens a file by index
|
||||
virtual IReadFile* createAndOpenFile(u32 index);
|
||||
|
||||
//! returns the list of files
|
||||
virtual const IFileList* getFileList() const;
|
||||
|
||||
//! get the class Type
|
||||
virtual E_FILE_ARCHIVE_TYPE getType() const { return EFAT_WAD; }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
io::path Type;
|
||||
|
||||
//! scans for a local header, returns false if there is no more local file header.
|
||||
bool scanLocalHeader();
|
||||
|
||||
//! splits filename from zip file into useful filenames and paths
|
||||
void extractFilename(SWADFileEntry* entry);
|
||||
|
||||
|
||||
io::path Base;
|
||||
io::path MountPoint;
|
||||
|
||||
IReadFile* File;
|
||||
|
||||
eWADFileTypes WadType;
|
||||
SWADFileHeader Header;
|
||||
|
||||
//core::array<SWADFileEntry> FileInfo;
|
||||
|
||||
io::IFileSystem* FileSystem;
|
||||
};
|
||||
|
||||
} // end namespace io
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif // #ifdef __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_
|
||||
|
|
@ -363,7 +363,7 @@ bool CZipReader::scanGZipHeader()
|
|||
#endif
|
||||
|
||||
// now we've filled all the fields, this is just a standard deflate block
|
||||
addItem(ZipFileName, entry.header.DataDescriptor.UncompressedSize, false, 0);
|
||||
addItem(ZipFileName, entry.Offset, entry.header.DataDescriptor.UncompressedSize, false, 0);
|
||||
FileInfo.push_back(entry);
|
||||
}
|
||||
|
||||
|
@ -471,7 +471,7 @@ bool CZipReader::scanZipHeader()
|
|||
//os::Debuginfo::print("added file from archive", ZipFileName.c_str());
|
||||
#endif
|
||||
|
||||
addItem(ZipFileName, entry.header.DataDescriptor.UncompressedSize, false, FileInfo.size());
|
||||
addItem(ZipFileName, entry.Offset, entry.header.DataDescriptor.UncompressedSize, false, FileInfo.size());
|
||||
FileInfo.push_back(entry);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -112,6 +112,7 @@ namespace video
|
|||
ETR_TEXTURE_GOURAUD_ALPHA_NOZ,
|
||||
|
||||
ETR_NORMAL_MAP_SOLID,
|
||||
ETR_STENCIL_SHADOW,
|
||||
|
||||
ETR_TEXTURE_BLEND,
|
||||
ETR_REFERENCE,
|
||||
|
@ -187,6 +188,7 @@ namespace video
|
|||
IBurningShader* createTRTextureInverseAlphaBlend(CBurningVideoDriver* driver);
|
||||
|
||||
IBurningShader* createTRNormalMap(CBurningVideoDriver* driver);
|
||||
IBurningShader* createTRStencilShadow(CBurningVideoDriver* driver);
|
||||
|
||||
IBurningShader* createTriangleRendererReference(CBurningVideoDriver* driver);
|
||||
|
||||
|
|
|
@ -2531,6 +2531,10 @@
|
|||
RelativePath=".\CTRNormalMap.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CTRStencilShadow.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CTRTextureBlend.cpp"
|
||||
>
|
||||
|
@ -3316,6 +3320,14 @@
|
|||
RelativePath="CTarReader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CWADReader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CWADReader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CWriteFile.cpp"
|
||||
>
|
||||
|
|
Loading…
Reference in New Issue