-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Engine] * Break out texture atlas related code into a new module 'atlas.hpp'. * Remove unneeded 'close()' after 'dup2()' since the latter already does the prior. [Assets] * Rebuild API documentation.
- Loading branch information
Showing
14 changed files
with
445 additions
and
284 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,259 @@ | ||
/* == ATLAS.HPP ============================================================ ** | ||
** ######################################################################### ** | ||
** ## Mhatxotic Engine (c) Mhatxotic Design, All Rights Reserved ## ** | ||
** ######################################################################### ** | ||
** ## This module allows automatic and manual building of texture atlases ## ** | ||
** ######################################################################### ** | ||
** ========================================================================= */ | ||
#pragma once // Only one incursion allowed | ||
/* ------------------------------------------------------------------------- */ | ||
namespace IAtlas { // Start of private namespace | ||
/* -- Dependencies --------------------------------------------------------- */ | ||
using namespace IBin::P; using namespace ICollector::P; | ||
using namespace IDim; using namespace IError::P; | ||
using namespace IImageDef::P; using namespace ILog::P; | ||
using namespace ILuaLib::P; using namespace IMemory::P; | ||
using namespace IOgl::P; using namespace IStd::P; | ||
using namespace ISysUtil::P; using namespace ITexture::P; | ||
using namespace IUtil::P; using namespace Lib::OS::GlFW; | ||
/* ------------------------------------------------------------------------- */ | ||
namespace P { // Start of public namespace | ||
/* == Atlas collector class for collector data and custom variables ======== */ | ||
CTOR_BEGIN_NOBB(Atlases, Atlas, CLHelperUnsafe) | ||
/* == Atlas Variables Class ================================================ */ | ||
// Only put vars used in the Atlas class in here. This is an optimisation so | ||
// we do not have to initialise all these variables more than once as we have | ||
// more than one constructor in the main Atlas class. | ||
/* ------------------------------------------------------------------------- */ | ||
class AtlasBase : // Members initially private | ||
/* -- Base classes ------------------------------------------------------- */ | ||
public Texture // Texture class | ||
{ /* -- Protected typedefs -------------------------------------- */ protected: | ||
typedef Rectangle<GLfloat> RectFloat;// Rectangle of GLfloats | ||
/* -- Variables ---------------------------------------------------------- */ | ||
typedef Pack<GLint> IntPack; // Bin pack using GLint | ||
typedef IntPack::Rect IntPackRect; // Bin pack rectangle | ||
typedef Rectangle<GLuint> RectUint; // Reload glyph size | ||
/* --------------------------------------------------------------- */ public: | ||
OglFilterEnum ofeFilter; // Selected texture filter | ||
GLuint uiPadding; // Padding after each glyph | ||
IntPack ipData; // FT packed characters in image | ||
/* -- Reload texture parameters ------------------------------------------ */ | ||
enum RTCmd { RT_NONE, RT_FULL, RT_PARTIAL } rtCmd; // Reload texture command | ||
RectUint rRedraw; // Reload cordinates and dimensions | ||
/* -- Default constructor ------------------------------------------------ */ | ||
AtlasBase(void) : // No parameters | ||
/* --------------------------------------------------------------------- */ | ||
Texture{ true }, ofeFilter(OF_N_N), | ||
uiPadding(0), rtCmd(RT_NONE), | ||
rRedraw{ | ||
numeric_limits<GLuint>::max(), | ||
numeric_limits<GLuint>::max(), | ||
0, 0 } | ||
/* --------------------------------------------------------------------- */ | ||
{ } | ||
/* ----------------------------------------------------------------------- */ | ||
DELETECOPYCTORS(AtlasBase) // Suppress default functions for safety | ||
};/* ----------------------------------------------------------------------- */ | ||
/* == Atlas Class (which inherits a Texture) =============================== */ | ||
CTOR_MEM_BEGIN(Atlases, Atlas, ICHelperUnsafe, /* n/a */), | ||
/* -- Base classes ------------------------------------------------------- */ | ||
public AtlasBase // Atlas variables class | ||
{ /* -- Convert co-ordinates to absolute position -------------- */ protected: | ||
static size_t CoordsToAbsolute(const size_t stPosX, | ||
const size_t stPosY, | ||
const size_t stWidth, | ||
const size_t stBytesPerColumn=1) | ||
{ return ((stPosY * stWidth) + stPosX) * stBytesPerColumn; } | ||
/* -- Check if texture reload required ------------------------ */ protected: | ||
void AtlasCheckReloadTexture(void) | ||
{ // Check reload command | ||
switch(rtCmd) | ||
{ // No reload so just return | ||
case RT_NONE: return; | ||
// Full reload | ||
case RT_FULL: | ||
{ // Reset reload command incase of error | ||
rtCmd = RT_NONE; | ||
// Full reload of texture | ||
ReloadTexture(); | ||
// Log that we reuploaded the texture | ||
cLog->LogDebugExSafe("Atlas '$' full texture reload (S:$,$).", | ||
IdentGet(), DimGetWidth(), DimGetHeight()); | ||
// Done | ||
return; | ||
} // Partial reload | ||
case RT_PARTIAL: | ||
{ // Reset reload command incase of error | ||
rtCmd = RT_NONE; | ||
// Calculate position to read from in buffer | ||
const size_t stRTPos = CoordsToAbsolute(rRedraw.RectGetX1(), | ||
rRedraw.RectGetY1(), DimGetWidth(), 2); | ||
// Calculate position in buffer to read from | ||
const GLubyte*const ucpSrc = | ||
GetSlots().front().MemRead<GLubyte>(stRTPos, DimGetWidth()); | ||
// Update partial texture | ||
UpdateEx(GetSubName(), | ||
rRedraw.RectGetX1<GLint>(), rRedraw.RectGetY1<GLint>(), | ||
static_cast<GLsizei>(rRedraw.RectGetX2() - rRedraw.RectGetX1()), | ||
static_cast<GLsizei>(rRedraw.RectGetY2() - rRedraw.RectGetY1()), | ||
GetPixelType(), ucpSrc, DimGetWidth<GLsizei>()); | ||
// Log that we partially reuploaded the texture | ||
cLog->LogDebugExSafe("Atlas '$' partial re-upload (B:$,$,$,$;P:$).", | ||
IdentGet(), rRedraw.RectGetX1(), rRedraw.RectGetY1(), | ||
rRedraw.RectGetX2(), rRedraw.RectGetY2(), stRTPos); | ||
// Reset range parameters | ||
rRedraw.RectSetTopLeft(numeric_limits<GLuint>::max()); | ||
rRedraw.RectSetBottomRight(0); | ||
// Done | ||
return; | ||
} | ||
} | ||
} | ||
/* -- Copy procedures ---------------------------------------------------- */ | ||
struct AtlasCopy | ||
{ /* -- Copy gray alpha tile --------------------------------------------- */ | ||
struct GrayAlpha | ||
{ /* -- Constructor ------------------------------------------------------ */ | ||
GrayAlpha(const size_t stSrcWidth, | ||
const size_t stSrcHeight, | ||
const MemConst &mcSrc, | ||
const size_t stDstX, | ||
const size_t stDstY, | ||
const size_t stDstWidth, | ||
Memory &mDst) | ||
{ // For each pixel row of glyph image | ||
for(size_t stPixPosY = 0; stPixPosY < stSrcHeight; ++stPixPosY) | ||
{ // Calculate Y position co-ordinate in buffer. | ||
const size_t stPosY = stDstY + stPixPosY; | ||
// For each pixel column of glyph image | ||
for(size_t stPixPosX = 0; stPixPosX < stSrcWidth; ++stPixPosX) | ||
{ // Calculate X position co-ordinate in buffer. | ||
const size_t stPosX = stDstX + stPixPosX; | ||
// Set the character to write... | ||
// * Step 1: 0xNN (8-bit colour pixel value) converts to... | ||
// * Step 2: 0x00NN (16-bit integer) shift eight bits left... | ||
// * Step 3: 0xNN00 (16-bit integer) set all first eight bits... | ||
// * Step 4: 0xNNFF (16-bit colour alpha pixel value). | ||
// This will obviously need to be revised if compiling on Big-End. | ||
const size_t stSrcPos = | ||
CoordsToAbsolute(stPixPosX, stPixPosY, stSrcWidth); | ||
const uint16_t usPixel = static_cast<uint16_t>( | ||
static_cast<int>(mcSrc.MemReadInt<uint8_t>(stSrcPos)) << 8 | | ||
0xFF); | ||
// ...and the final offset position value | ||
const size_t stDstPos = | ||
CoordsToAbsolute(stPosX, stPosY, stDstWidth, sizeof(usPixel)); | ||
// If the paint position is in the tile bounds? | ||
// Copy pixels from source to destination. | ||
mDst.MemWriteInt<uint16_t>(stDstPos, usPixel); | ||
} | ||
} | ||
} | ||
}; | ||
}; | ||
/* -- Render texture data to memory -------------------------------------- */ | ||
template<class CopyType> | ||
void AtlasAddBitmap(const IntPackRect &iprRef, | ||
const size_t stSrcWidth, | ||
const size_t stSrcHeight, | ||
CoordData &cdRef, | ||
const void*const vpSrc, | ||
Memory &mDst) | ||
{ // Get source and destination sizes and return if they're different | ||
const size_t | ||
stDstWidth = iprRef.DimGetWidth<size_t>(), | ||
stDstHeight = iprRef.DimGetHeight<size_t>(); | ||
if(stSrcWidth != stDstWidth || stSrcHeight != stDstHeight) return; | ||
// Get destination X and Y position as size_t | ||
const size_t stDstX = iprRef.CoordGetX<size_t>(), | ||
stDstY = iprRef.CoordGetY<size_t>(); | ||
// Put glyph data and size in a managed class | ||
const MemConst mcSrc{ stSrcWidth * stSrcHeight, vpSrc }; | ||
// Run the requested copy procedure | ||
CopyType(stSrcWidth, stSrcHeight, mcSrc, | ||
stDstX, stDstY, DimGetWidth<size_t>(), mDst); | ||
// Calculate texture bounds | ||
const GLfloat | ||
fMinX = static_cast<GLfloat>(stDstX), | ||
fMinY = static_cast<GLfloat>(stDstY), | ||
fMaxX = fMinX + static_cast<GLfloat>(stSrcWidth), | ||
fMaxY = fMinY + static_cast<GLfloat>(stSrcHeight), | ||
fBW = DimGetWidth<GLfloat>(), | ||
fBH = DimGetHeight<GLfloat>(); | ||
// Get reference to first and second triangles | ||
TriCoordData &tcT1 = cdRef[0], &tcT2 = cdRef[1]; | ||
// Push opengl tile coords (keep .fW/.fH to zero which is already zero) | ||
tcT1[0] = tcT1[4] = tcT2[2] = fMinX / fBW; // Left | ||
tcT1[1] = tcT1[3] = tcT2[5] = fMinY / fBH; // Top | ||
tcT1[2] = tcT2[0] = tcT2[4] = fMaxX / fBW; // Right | ||
tcT1[5] = tcT2[1] = tcT2[3] = fMaxY / fBH; // Bottom | ||
} | ||
/* -- Initialise the atlas --------------------------------------- */ public: | ||
void AtlasInit(const string &strId, | ||
const GLuint uiTWidth, | ||
const GLuint uiTHeight, | ||
const GLuint uiISize, | ||
const GLuint _uiPadding, | ||
const OglFilterEnum _ofeFilter) | ||
{ // Make sure padding isn't negative. We use int because it is optimal for | ||
// use with the BinPack routines. | ||
if(UtilIntWillOverflow<int>(uiPadding)) | ||
XC("Atlas padding size overflows signed integer range!", | ||
"Identifier", strId, "Requested", _uiPadding); | ||
// Initialise base size, padding and opengl filter | ||
uiPadding = _uiPadding; | ||
ofeFilter = _ofeFilter; | ||
// Set initial tile size. This is just for the Texture class. | ||
duiTile.DimSet(uiTWidth, uiTHeight); | ||
// Set initial size of image. The image size starts here and can | ||
// automatically grow by the power of 2 if more space is needed. | ||
DimSet(uiISize ? uiISize : | ||
TextureGetMaxSizeFromBounds(0, 0, uiTWidth, uiTHeight, 1)); | ||
// Check if texture size is valid | ||
if(DimGetWidth() > cOgl->MaxTexSize() || uiTWidth > cOgl->MaxTexSize()) | ||
XC("Atlas dimensions for font not supported by graphics processor!", | ||
"Identifier", strId, "Requested", uiISize, | ||
"Width", DimGetWidth(), "Height", DimGetHeight(), | ||
"TileWidth", uiTWidth, "TileHeight", uiTHeight, | ||
"Maximum", cOgl->MaxTexSize()); | ||
// Estimate how many glyphs we're fitting in here to prevent unnecessary | ||
// alocations | ||
const size_t stGColumns = DimGetWidth() / uiTWidth, | ||
stGRows = DimGetHeight() / uiTHeight, | ||
stGTotal = UtilNearestPow2<size_t>(stGColumns * stGRows); | ||
// Init bin packer so we can tightly pack glyphs together. We're trying to | ||
// guess the size of the rlFree and rlUsed structs are too. | ||
ipData.Init(DimGetWidth(), DimGetHeight(), stGTotal, stGTotal); | ||
// Initialise texture image. Remember it needs to be cleared as the | ||
// parts that are padding will not be written to 'ever' and that would | ||
// cause display artifacts | ||
Memory mPixels{ DimGetWidth() * DimGetHeight() * 2 }; | ||
mPixels.MemFill<uint16_t>(0x00FF); | ||
InitRaw(strId, mPixels, DimGetWidth(), DimGetHeight(), BD_GRAYALPHA); | ||
// Initialise image in GL. This class is responsible for updating the | ||
// texture tile co-ords set. | ||
InitImage(*this, | ||
uiTWidth, uiTHeight, uiPadding, uiPadding, ofeFilter, false); | ||
} | ||
/* -- Constructor (Initialisation then registration) --------------------- */ | ||
Atlas(void) : // No parameters | ||
/* -- Initialisers ----------------------------------------------------- */ | ||
ICHelperAtlas{ cAtlases, this } // Initially registered | ||
/* --------------------------------------------------------------------- */ | ||
{ } // Do nothing else | ||
/* -- Constructor (without registration) --------------------------------- */ | ||
explicit Atlas(const bool) : // Dummy parameter | ||
/* -- Initialisers ----------------------------------------------------- */ | ||
ICHelperAtlas{ cAtlases } // Initially unregistered | ||
/* --------------------------------------------------------------------- */ | ||
{ } // Do nothing else | ||
/* ----------------------------------------------------------------------- */ | ||
DELETECOPYCTORS(Atlas) // Suppress default functions for safety | ||
};/* ----------------------------------------------------------------------- */ | ||
CTOR_END_NOINITS(Atlases, Atlas, ATLAS) // End of collector class | ||
/* ------------------------------------------------------------------------- */ | ||
} // End of public module namespace | ||
/* ------------------------------------------------------------------------- */ | ||
} // End of private module namespace | ||
/* == EoF =========================================================== EoF == */ |
Oops, something went wrong.