Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions rts/Game/UI/MouseHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,12 @@ bool CMouseHandler::ReplaceMouseCursor(

CMouseCursor newCursor = CMouseCursor(newName, hotSpot);

// a replacement that loaded no frames draws nothing, so this silently turns
// a working cursor invisible. Whether the engine should refuse it is a
// behaviour question, since content may rely on it to hide the cursor.
if (!newCursor.IsValid())
LOG_L(L_WARNING, "[MouseHandler::%s] replacement \"%s\" for \"%s\" has no frames, the cursor will draw nothing", __func__, newName.c_str(), oldName.c_str());

// replace here so SetCursor() operates with new CMouseCursor() object
// hold on the destruction of old CMouseCursor() in this place. Otherwise bad things will happen.
std::swap(loadedCursors.at(fileIt->second), newCursor);
Expand Down
159 changes: 145 additions & 14 deletions rts/Rendering/Textures/nv_dds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@
//
// Description:
//
// Loads DDS images (DXTC1, DXTC3, DXTC5, RGB (888, 888X), and RGBA (8888) are
// supported) for use in OpenGL. Image is flipped when its loaded as DX images
// are stored with different coordinate system. If file has mipmaps and/or
// cubemaps then these are loaded as well. Volume textures can be loaded as
// well but they must be uncompressed.
// Loads DDS images for use in OpenGL. DXT1, DXT3, DXT5, BC4, BC5, BC7,
// RGB (888, 888X), and RGBA (8888) are supported. Images are flipped to match
// OpenGL coordinates, except BC7. Volume textures must be uncompressed.
//
// When multiple textures are loaded (i.e a volume or cubemap texture),
// additional faces can be accessed using the array operator.
Expand Down Expand Up @@ -349,6 +347,24 @@ bool CDDSImage::load(string filename, bool flipImage)
file.Read(&ddsh.dwCaps2, tmp);
file.Read(&ddsh.dwReserved2, tmp*3);

const bool hasDX10Header = ((swabDWord(ddsh.ddspf.dwFlags) & DDSF_FOURCC) && swabDWord(ddsh.ddspf.dwFourCC) == FOURCC_DX10);
DDS_HEADER_DXT10 ddsh10 = {0, 0, 0, 1, 0};
if (hasDX10Header)
{
if (file.Read(&ddsh10.dxgiFormat, tmp) != tmp ||
file.Read(&ddsh10.resourceDimension, tmp) != tmp ||
file.Read(&ddsh10.miscFlag, tmp) != tmp ||
file.Read(&ddsh10.arraySize, tmp) != tmp ||
file.Read(&ddsh10.miscFlags2, tmp) != tmp)
return false;

ddsh10.dxgiFormat = swabDWord(ddsh10.dxgiFormat);
ddsh10.resourceDimension = swabDWord(ddsh10.resourceDimension);
ddsh10.miscFlag = swabDWord(ddsh10.miscFlag);
ddsh10.arraySize = swabDWord(ddsh10.arraySize);
ddsh10.miscFlags2 = swabDWord(ddsh10.miscFlags2);
}

// if in VFS, read post-header data directly from buffer
if (file.IsBuffered()) {
fileBuf = std::move(file.GetBuffer());
Expand All @@ -374,16 +390,29 @@ bool CDDSImage::load(string filename, bool flipImage)
ddsh.dwCaps1 = swabDWord(ddsh.dwCaps1);
ddsh.dwCaps2 = swabDWord(ddsh.dwCaps2);

if (hasDX10Header &&
(ddsh10.arraySize != 1 ||
(ddsh10.resourceDimension != DX10_DIMENSION_TEXTURE2D && ddsh10.resourceDimension != DX10_DIMENSION_TEXTURE3D) ||
((ddsh10.miscFlag & DX10_MISC_TEXTURECUBE) && ddsh10.resourceDimension != DX10_DIMENSION_TEXTURE2D)))
return false;

// default to flat texture type (1D, 2D, or rectangle)
m_type = TextureFlat;

// check if image is a cubemap
if (ddsh.dwCaps2 & DDSF_CUBEMAP)
m_type = TextureCubemap;

// check if image is a volume texture
if ((ddsh.dwCaps2 & DDSF_VOLUME) && (ddsh.dwDepth > 0))
m_type = Texture3D;
if (hasDX10Header) {
if (ddsh10.miscFlag & DX10_MISC_TEXTURECUBE)
m_type = TextureCubemap;
else if (ddsh10.resourceDimension == DX10_DIMENSION_TEXTURE3D)
m_type = Texture3D;
} else {
// check if image is a cubemap
if (ddsh.dwCaps2 & DDSF_CUBEMAP)
m_type = TextureCubemap;

// check if image is a volume texture
if ((ddsh.dwCaps2 & DDSF_VOLUME) && (ddsh.dwDepth > 0))
m_type = Texture3D;
}

// figure out what the image format is
if (ddsh.ddspf.dwFlags & DDSF_FOURCC)
Expand All @@ -402,6 +431,51 @@ bool CDDSImage::load(string filename, bool flipImage)
m_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
m_components = 4;
break;
case FOURCC_ATI1:
case FOURCC_BC4U:
m_format = GL_COMPRESSED_RED_RGTC1;
m_components = 1;
break;
case FOURCC_ATI2:
case FOURCC_BC5U:
m_format = GL_COMPRESSED_RG_RGTC2;
m_components = 2;
break;
case FOURCC_DX10:
switch (ddsh10.dxgiFormat)
{
case DXGI_FORMAT_BC1_UNORM:
m_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
m_components = 3;
break;
case DXGI_FORMAT_BC2_UNORM:
m_format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
m_components = 4;
break;
case DXGI_FORMAT_BC3_UNORM:
m_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
m_components = 4;
break;
case DXGI_FORMAT_BC4_UNORM:
m_format = GL_COMPRESSED_RED_RGTC1;
m_components = 1;
break;
case DXGI_FORMAT_BC5_UNORM:
m_format = GL_COMPRESSED_RG_RGTC2;
m_components = 2;
break;
case DXGI_FORMAT_BC7_UNORM:
m_format = GL_COMPRESSED_RGBA_BPTC_UNORM;
m_components = 4;
break;
case DXGI_FORMAT_BC7_UNORM_SRGB:
m_format = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
m_components = 4;
break;
default:
return false;
}
break;
default:
//fclose(fp);
return false;
Expand Down Expand Up @@ -435,6 +509,11 @@ bool CDDSImage::load(string filename, bool flipImage)
return false;
}

if (flipImage && (m_format == GL_COMPRESSED_RGBA_BPTC_UNORM || m_format == GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM)) {
LOG_L(L_WARNING, "[nv_dds] cannot vertically flip BC7 image \"%s\", author it pre-flipped", filename.c_str());
flipImage = false;
}

// store primary surface width/height/depth
unsigned int width = ddsh.dwWidth;
unsigned int height = ddsh.dwHeight;
Expand Down Expand Up @@ -578,6 +657,12 @@ bool CDDSImage::save(std::string filename, bool flipImage) const
assert(m_valid);
assert(m_type != TextureNone);

if (is_compressed() &&
m_format != GL_COMPRESSED_RGBA_S3TC_DXT1_EXT &&
m_format != GL_COMPRESSED_RGBA_S3TC_DXT3_EXT &&
m_format != GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
return false;

DDS_HEADER ddsh;
unsigned int headerSize = sizeof(DDS_HEADER);
memset(&ddsh, 0, headerSize);
Expand Down Expand Up @@ -727,7 +812,11 @@ bool CDDSImage::is_compressed() const
RECOIL_DETAILED_TRACY_ZONE;
return ((m_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ||
(m_format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) ||
(m_format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT));
(m_format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) ||
(m_format == GL_COMPRESSED_RED_RGTC1) ||
(m_format == GL_COMPRESSED_RG_RGTC2) ||
(m_format == GL_COMPRESSED_RGBA_BPTC_UNORM) ||
(m_format == GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM));
}

#ifndef HEADLESS
Expand Down Expand Up @@ -969,7 +1058,7 @@ inline unsigned int CDDSImage::size_dxtc(unsigned int width, unsigned int height
{
RECOIL_DETAILED_TRACY_ZONE;
return ((width+3)/4)*((height+3)/4)*
(m_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16);
((m_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || m_format == GL_COMPRESSED_RED_RGTC1) ? 8 : 16);
}

///////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -1030,6 +1119,14 @@ void CDDSImage::flip(CSurface &surface) const
blocksize = 16;
flipblocks = &CDDSImage::flip_blocks_dxtc5;
break;
case GL_COMPRESSED_RED_RGTC1:
blocksize = 8;
flipblocks = &CDDSImage::flip_blocks_bc4;
break;
case GL_COMPRESSED_RG_RGTC2:
blocksize = 16;
flipblocks = &CDDSImage::flip_blocks_bc5;
break;
default:
return;
}
Expand Down Expand Up @@ -1219,6 +1316,40 @@ void CDDSImage::flip_blocks_dxtc5(DXTColBlock *line, unsigned int numBlocks) con
}
}

///////////////////////////////////////////////////////////////////////////////
// flip a line of BC4 blocks
void CDDSImage::flip_blocks_bc4(DXTColBlock *line, unsigned int numBlocks) const
{
RECOIL_DETAILED_TRACY_ZONE;
DXT5AlphaBlock *curblock = reinterpret_cast<DXT5AlphaBlock*>(line);

for (unsigned int i = 0; i < numBlocks; i++)
{
flip_dxt5_alpha(curblock);

curblock++;
}
}

///////////////////////////////////////////////////////////////////////////////
// flip a line of BC5 blocks
void CDDSImage::flip_blocks_bc5(DXTColBlock *line, unsigned int numBlocks) const
{
RECOIL_DETAILED_TRACY_ZONE;
DXT5AlphaBlock *curblock = reinterpret_cast<DXT5AlphaBlock*>(line);

for (unsigned int i = 0; i < numBlocks; i++)
{
flip_dxt5_alpha(curblock);

curblock++;

flip_dxt5_alpha(curblock);

curblock++;
}
}

///////////////////////////////////////////////////////////////////////////////
// CTexture implementation
///////////////////////////////////////////////////////////////////////////////
Expand Down
30 changes: 30 additions & 0 deletions rts/Rendering/Textures/nv_dds.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,25 @@ namespace nv_dds
const unsigned int FOURCC_DXT1 = 0x31545844; //(MAKEFOURCC('D','X','T','1'))
const unsigned int FOURCC_DXT3 = 0x33545844; //(MAKEFOURCC('D','X','T','3'))
const unsigned int FOURCC_DXT5 = 0x35545844; //(MAKEFOURCC('D','X','T','5'))
const unsigned int FOURCC_ATI1 = 0x31495441; //(MAKEFOURCC('A','T','I','1')), BC4
const unsigned int FOURCC_BC4U = 0x55344342; //(MAKEFOURCC('B','C','4','U'))
const unsigned int FOURCC_ATI2 = 0x32495441; //(MAKEFOURCC('A','T','I','2')), BC5
const unsigned int FOURCC_BC5U = 0x55354342; //(MAKEFOURCC('B','C','5','U'))
const unsigned int FOURCC_DX10 = 0x30315844; //(MAKEFOURCC('D','X','1','0'))

// Supported DXGI formats
const unsigned int DXGI_FORMAT_BC1_UNORM = 71;
const unsigned int DXGI_FORMAT_BC2_UNORM = 74;
const unsigned int DXGI_FORMAT_BC3_UNORM = 77;
const unsigned int DXGI_FORMAT_BC4_UNORM = 80;
const unsigned int DXGI_FORMAT_BC5_UNORM = 83;
const unsigned int DXGI_FORMAT_BC7_UNORM = 98;
const unsigned int DXGI_FORMAT_BC7_UNORM_SRGB = 99;

// DDS_HEADER_DXT10 values
const unsigned int DX10_DIMENSION_TEXTURE2D = 3;
const unsigned int DX10_DIMENSION_TEXTURE3D = 4;
const unsigned int DX10_MISC_TEXTURECUBE = 0x00000004;

struct DXTColBlock
{
Expand Down Expand Up @@ -85,6 +104,15 @@ namespace nv_dds
unsigned int dwABitMask;
};

struct DDS_HEADER_DXT10
{
unsigned int dxgiFormat;
unsigned int resourceDimension;
unsigned int miscFlag;
unsigned int arraySize;
unsigned int miscFlags2;
};

struct DDS_HEADER
{
unsigned int dwSize;
Expand Down Expand Up @@ -333,6 +361,8 @@ namespace nv_dds
void flip_blocks_dxtc1(DXTColBlock *line, unsigned int numBlocks) const;
void flip_blocks_dxtc3(DXTColBlock *line, unsigned int numBlocks) const;
void flip_blocks_dxtc5(DXTColBlock *line, unsigned int numBlocks) const;
void flip_blocks_bc4(DXTColBlock *line, unsigned int numBlocks) const;
void flip_blocks_bc5(DXTColBlock *line, unsigned int numBlocks) const;
void flip_dxt5_alpha(DXT5AlphaBlock *block) const;

bool write_texture(const CTexture &texture, FILE *fp) const;
Expand Down
21 changes: 6 additions & 15 deletions rts/Sim/Path/QTPFS/Path.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,24 +295,15 @@ namespace QTPFS {
points.clear();
points.resize(n);
}
void CopyPoints(const IPath& p) {
AllocPoints(p.NumPoints());

for (unsigned int n = 0; n < p.NumPoints(); n++) {
points[n] = p.GetPoint(n);
}
}
void CopyPoints(const IPath& p) { points = p.points; }

void AllocNodes(unsigned int n) {
nodes.clear();
nodes.resize(n);
}
void CopyNodes(const IPath& p) {
AllocNodes(p.nodes.size());

for (unsigned int n = 0; n < p.nodes.size(); n++) {
nodes[n] = p.GetNode(n);
}
}
void CopyNodes(const IPath& p) { nodes = p.nodes; }

// Function is for debugging and logging purposes only
uint32_t CalculateHash() const {
Expand Down Expand Up @@ -345,15 +336,15 @@ namespace QTPFS {
spring_time GetSearchTime() const { return searchTime; }

// Incomplete paths need to be rebuilt from time to time as the owner makes progress.
unsigned int GetRepathTriggerIndex() const { return repathAtPointIndex; }
uint32_t GetRepathTriggerIndex() const { return repathAtPointIndex; }
void SetRepathTriggerIndex(unsigned int index) { repathAtPointIndex = index; }

void ClearGetRepathTriggerIndex() { repathAtPointIndex = 0; }

float3 GetGoalPosition() const { return goalPosition; }
const float3& GetGoalPosition() const { return goalPosition; }
void SetGoalPosition(float3 point) { goalPosition = point; }

unsigned int GetFirstNodeIdOfCleanPath() const { return firstNodeIdOfCleanPath; }
uint32_t GetFirstNodeIdOfCleanPath() const { return firstNodeIdOfCleanPath; }
void SetFirstNodeIdOfCleanPath(int nodeId) { firstNodeIdOfCleanPath = nodeId; }

bool IsRawPath() const { return isRawPath; }
Expand Down
3 changes: 1 addition & 2 deletions rts/Sim/Path/QTPFS/PathCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@ static void GetRectangleCollisionVolume(const SRectangle& r, CollisionVolume& v,
rm.z = ((r.z1 + r.z2) * SQUARE_SIZE) >> 1;
rm.y = 0.0f;

#define CV CollisionVolume
using CV = CollisionVolume;
v.InitShape(vScales, ZeroVector, CV::COLVOL_TYPE_BOX, CV::COLVOL_HITTEST_CONT, CV::COLVOL_AXIS_Y);
#undef CV
}

bool QTPFS::PathCache::MarkDeadPaths(const SRectangle& r, const NodeLayer& nodeLayer) {
Expand Down
2 changes: 1 addition & 1 deletion rts/Sim/Path/QTPFS/PathSearch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ void QTPFS::PathSearch::InitializeThread(SearchThreadData* threadData, IPath* pa
// auto *pathToRepair = ( tryPathRepair && registry.valid(QTPFS::entity(searchID)) )
// ? registry.try_get<IPath>(QTPFS::entity(searchID)) : nullptr; // FIXME: race condition

// Path repairs need only search to the point of finding the beginning of the renaming clean part of the old path.
// Path repairs need only search to the point of finding the beginning of the remaining clean part of the old path.
// Such searches are also restricted in the area they can search to avoid creating poor paths that would be better
// off being recreated from scratch.
doPathRepair = tryPathRepair
Expand Down
6 changes: 6 additions & 0 deletions rts/Sim/Weapons/Weapon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,12 @@ void CWeapon::HoldIfTargetInvalid()
return;

if (!TryTarget(currentTarget)) {
// BombDroppers must retain ground targets until their active salvo ends.
// Dropping one after the aircraft passes the target prevents the CAI from
// associating the completed salvo with its current attack command.
if (noAutoTarget && HavePosTarget() && salvoLeft > 0)
return;

DropCurrentTarget();
return;
}
Expand Down
5 changes: 4 additions & 1 deletion rts/System/Threading/ThreadPool.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,10 @@ class ITaskGroup
}

uint32_t GetId() const { return id; }
uint64_t GetDeltaTime(const spring_time t) const { return (std::max(ts.load(), uint64_t(t.toNanoSecsi())) - ts); }
uint64_t GetDeltaTime(const spring_time t0) const {
const uint64_t t1 = ts.load();
return (std::max(t1, uint64_t(t0.toNanoSecsi())) - t1);
}

void UpdateId() { id = lastId.fetch_add(1); }
void SetTimeStamp(const spring_time t) { ts = t.toNanoSecsi(); }
Expand Down