1 /*---------------------------------------------------------------------------*
2 
3   Copyright 2010-2011 Nintendo.  All rights reserved.
4 
5   These coded instructions, statements, and computer programs contain
6   proprietary information of Nintendo of America Inc. and/or Nintendo
7   Company Ltd., and are protected by Federal copyright law.  They may
8   not be disclosed to third parties or copied or duplicated in any form,
9   in whole or in part, without the prior written consent of Nintendo.
10 
11  *---------------------------------------------------------------------------*/
12 #if !defined(_TC_PLUGINAPI_INCLUDED_)
13 #define _TC_PLUGINAPI_INCLUDED_
14 
15 /// @addtogroup GX2TexUtilGroup
16 /// @{
17 
18 #include <tchar.h>
19 #include <assert.h>
20 #include <stdlib.h>
21 #include "Texture.h"
22 
23 #if _MSC_VER > 1000
24 #pragma once
25 #endif // _MSC_VER > 1000
26 
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30 ///\def MAKEFOURCC(ch0, ch1, ch2, ch3)
31 /// Utility macro for defining a FourCC code.
32 #ifndef MAKEFOURCC
33 #define MAKEFOURCC(ch0, ch1, ch2, ch3)                              \
34 ((u32)(BYTE)(ch0) | ((u32)(BYTE)(ch1) << 8) |   \
35 ((u32)(BYTE)(ch2) << 16) | ((u32)(BYTE)(ch3) << 24 ))
36 #endif
37 
38 /// A structure for storing compression parameters specific to each codec.
39 typedef struct
40 {
41     void*          pPluginSpecific;  ///< Usually used as a pointer to a user-defined structure that can contain all the necessary file save options.
42     const TCHAR*   pszTextParams;    ///< A string containing the command line options for the file handler when the app is called from the command line.
43 } TC_FileSaveParams;
44 
45 #ifdef __cplusplus
46 };
47 #endif
48 
49 /// \brief Get number of mimpap levels.
50 ///
51 /// \donotcall \notthreadsafe \hostonly \enddonotcall
52 ///
GetNumMipLevels(int nWidth,int nHeight,int nDepth,int nMinMipSize)53 static GX2_INLINE int GetNumMipLevels(int nWidth, int nHeight, int nDepth, int nMinMipSize)
54 {
55     int mipLevels = 1;
56     ASSERT(nWidth > 0 && nHeight > 0 && nDepth > 0);
57 
58     while (nWidth > nMinMipSize || nHeight > nMinMipSize || nDepth > nMinMipSize)
59     {
60         mipLevels++;
61         //div by 2
62         nWidth  = nWidth > 1 ? nWidth >> 1 : 1;
63         nHeight = nHeight > 1 ? nHeight >> 1 : 1;
64         nDepth  = nDepth > 1 ? nDepth>>1 : 1;
65     }
66     return mipLevels;
67 }
68 
69 /// \brief Find the max number of faces or slices
70 ///
71 /// \donotcall \notthreadsafe \hostonly \enddonotcall
72 ///
MaxFacesOrSlices(const GX2Surface * pSurface,u32 nMipLevel)73 GX2_INLINE s32 MaxFacesOrSlices(const GX2Surface* pSurface, u32 nMipLevel)
74 {
75     if(!pSurface)
76     {
77         return 0;
78     }
79 
80     if(pSurface->depth < 1)
81     {
82         return 0;
83     }
84 
85     if(pSurface->dim == GX2_SURFACE_DIM_2D || pSurface->dim == GX2_SURFACE_DIM_CUBE)
86     {
87         return pSurface->depth;
88     }
89     else if(pSurface->dim == GX2_SURFACE_DIM_3D)
90     {
91         u32 count;
92         for(count = 0; count < pSurface->numMips + 1; count++)
93         {
94             int lvlDepth = pSurface->depth;
95             lvlDepth >>= count;
96             lvlDepth = (lvlDepth > 1) ? lvlDepth : 1;
97 
98             if(count == nMipLevel)
99                 return lvlDepth;
100         }
101     }
102 
103     return 0;
104 }
105 
106 /// \brief Get Mipmap Size of surface.
107 ///
108 /// \donotcall \notthreadsafe \hostonly \enddonotcall
109 ///
110 #ifdef __cplusplus
111 static GX2_INLINE u32 GetMipSize(const GX2Surface* pSurface, u32 nMipLevel, u32 nFaceOrSlice = 0)
112 #else
113 static GX2_INLINE u32 GetMipSize(const GX2Surface* pSurface, u32 nMipLevel, u32 nFaceOrSlice)
114 #endif
115 {
116     u32 depthShift;
117     u32 sliceCountThisLevel;
118 
119     if(!pSurface || (!pSurface->mipPtr && (pSurface->numMips > 1)))
120     {
121         ASSERT(pSurface || (!pSurface->mipPtr && (pSurface->numMips > 1)));
122         return 0;
123     }
124     if(nMipLevel >= pSurface->numMips)
125     {
126         ASSERT(nMipLevel < pSurface->numMips);
127         return 0;
128     }
129     if(nFaceOrSlice < 0)
130     {
131         return 0;    //not an error, indicates requested face doesn't exist
132     }
133 
134     depthShift = (pSurface->dim == GX2_SURFACE_DIM_3D) ? nMipLevel : 0;
135     sliceCountThisLevel = ((pSurface->depth >> depthShift) > 1) ? (pSurface->depth >> depthShift) : 1;
136 
137     ASSERT(nFaceOrSlice <= sliceCountThisLevel);
138 
139     if (!nMipLevel)
140     {
141         return pSurface->imageSize / sliceCountThisLevel;
142     }
143     else if ((pSurface->numMips == 2) && (nMipLevel == 1))
144     {
145         return pSurface->mipSize / sliceCountThisLevel;
146     }
147     else if (nMipLevel == (pSurface->numMips - 1))
148     {
149         return (pSurface->mipSize - pSurface->mipOffset[nMipLevel - 1]) / sliceCountThisLevel;
150     }
151     else if (nMipLevel == 1)
152     {
153         return pSurface->mipOffset[nMipLevel] / sliceCountThisLevel;
154     }
155 
156     return (pSurface->mipOffset[nMipLevel] - pSurface->mipOffset[nMipLevel - 1]) / sliceCountThisLevel;
157 }
158 
159 /// \brief Fill MipLevel data structure extracted from GX2Surface with specified nMipLevel and nFaceOrSlice flag
160 ///
161 /// \param pSurface surface data
162 /// \param nMipLevel user specified mipmap level
163 /// \param nFaceOrSlice flag if surface has n-faces or slices
164 /// \param pLevel output MipLevel data
165 ///
166 /// \donotcall \notthreadsafe \hostonly \enddonotcall
167 ///
GetMipLevel(GX2Surface * pSurface,u32 nMipLevel,u32 nFaceOrSlice,MipLevel * pLevel)168 static GX2_INLINE BOOL GetMipLevel(GX2Surface* pSurface, u32 nMipLevel, u32 nFaceOrSlice, MipLevel* pLevel)
169 {
170     u32 depthShift;
171     u32 sliceCountThisLevel;
172 
173     if(!pSurface || (!pSurface->mipPtr && (pSurface->numMips > 1)))
174     {
175         ASSERT(pSurface || (!pSurface->mipPtr && (pSurface->numMips > 1)));
176         return 0;
177     }
178     if(nMipLevel >= pSurface->numMips)
179     {
180         ASSERT(nMipLevel < pSurface->numMips);
181         return 0;
182     }
183     if(nFaceOrSlice < 0)
184     {
185         return 0;    //not an error, indicates requested face doesn't exist
186     }
187 
188     memset(pLevel, 0, sizeof(*pLevel));
189 
190     depthShift = (pSurface->dim == GX2_SURFACE_DIM_3D) ? nMipLevel : 0;
191     sliceCountThisLevel = ((pSurface->depth >> depthShift) > 1) ? (pSurface->depth >> depthShift) : 1;
192 
193     ASSERT(nFaceOrSlice <= sliceCountThisLevel);
194 
195     if (!nMipLevel)
196     {
197         pLevel->pData = (u8*)pSurface->imagePtr + ((pSurface->imageSize / sliceCountThisLevel) * nFaceOrSlice);
198         pLevel->byteSize = pSurface->imageSize / sliceCountThisLevel;
199     }
200     else if ((pSurface->numMips == 2) && (nMipLevel == 1))
201     {
202         pLevel->pData = (u8*)pSurface->mipPtr + ((pSurface->mipSize / sliceCountThisLevel) * nFaceOrSlice);
203         pLevel->byteSize = pSurface->mipSize / sliceCountThisLevel;
204     }
205     else if (nMipLevel == (pSurface->numMips - 1))
206     {
207         pLevel->pData = (u8*)pSurface->mipPtr + pSurface->mipOffset[nMipLevel - 1] + (((pSurface->mipSize - pSurface->mipOffset[nMipLevel - 1])/ sliceCountThisLevel) * nFaceOrSlice);
208         pLevel->byteSize = (pSurface->mipSize - pSurface->mipOffset[nMipLevel - 1]) / sliceCountThisLevel;
209     }
210     else if (nMipLevel == 1)
211     {
212         pLevel->pData = (u8*)pSurface->mipPtr + ((pSurface->mipOffset[nMipLevel] / sliceCountThisLevel) * nFaceOrSlice);
213         pLevel->byteSize = pSurface->mipOffset[nMipLevel] / sliceCountThisLevel;
214     }
215     else
216     {
217         pLevel->pData = (u8*)pSurface->mipPtr + pSurface->mipOffset[nMipLevel - 1] + (((pSurface->mipOffset[nMipLevel] - pSurface->mipOffset[nMipLevel - 1])/ sliceCountThisLevel) * nFaceOrSlice);
218         pLevel->byteSize = (pSurface->mipOffset[nMipLevel] - pSurface->mipOffset[nMipLevel - 1]) / sliceCountThisLevel;
219     }
220 
221     pLevel->width   = pSurface->width >> nMipLevel;
222     pLevel->height  = pSurface->height >> nMipLevel;
223 
224     if (pLevel->width < 1)
225     {
226         pLevel->width = 1;
227     }
228     if (pLevel->height < 1)
229     {
230         pLevel->height = 1;
231     }
232 
233     return TRUE;
234 }
235 
236 #include "Texture.h"
237 
238 /// @}
239 
240 #endif // !defined(_TC_PLUGINAPI_INCLUDED_)
241