Citro3d
Loading...
Searching...
No Matches
tex3ds.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * Copyright (c) 2017
3 * Michael Theall (mtheall)
4 *
5 * This file is part of citro3d.
6 *
7 * This software is provided 'as-is', without any express or implied warranty.
8 * In no event will the authors be held liable for any damages arising from the
9 * use of this software.
10 *
11 * Permission is granted to anyone to use this software for any purpose,
12 * including commercial applications, and to alter it and redistribute it
13 * freely, subject to the following restrictions:
14 *
15 * 1. The origin of this software must not be misrepresented; you must not
16 * claim that you wrote the original software. If you use this software in
17 * a product, an acknowledgment in the product documentation would be
18 * appreciated but is not required.
19 * 2. Altered source versions must be plainly marked as such, and must not be
20 * misrepresented as being the original software.
21 * 3. This notice may not be removed or altered from any source distribution.
22 *----------------------------------------------------------------------------*/
26#include <tex3ds.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <unistd.h>
31
35{
37 u16 width;
38 u16 height;
39 u8 format;
41 Tex3DS_SubTexture subTextures[];
42};
43
44typedef struct __attribute__((packed))
45{
46 u16 numSubTextures;
47 u8 width_log2 : 3;
48 u8 height_log2 : 3;
49 u8 type : 1;
50 u8 format;
51 u8 mipmapLevels;
53
54typedef struct
55{
56 u16 width, height;
57 u16 left, top, right, bottom;
59
60static inline bool Tex3DSi_ReadData(decompressCallback callback, void** userdata, void* buffer, size_t size, size_t* insize)
61{
62 if (callback)
63 return callback(*userdata, buffer, size) == size;
64 if (size > *insize)
65 return false;
66
67 memcpy(buffer, *userdata, size);
68 *userdata = (u8*)*userdata + size;
69 *insize -= size;
70 return true;
71}
72
73static Tex3DS_Texture
74Tex3DSi_ImportCommon(C3D_Tex* tex, C3D_TexCube* texcube, bool vram, decompressCallback callback, void* userdata, size_t insize)
75{
76 // Read header
78 if (!Tex3DSi_ReadData(callback, &userdata, &hdr, sizeof(hdr), &insize))
79 return NULL;
80
81 // Allocate space for header + subtextures
82 Tex3DS_Texture texture = (Tex3DS_Texture)malloc(sizeof(struct Tex3DS_Texture_s) + hdr.numSubTextures*sizeof(Tex3DS_SubTexture));
83 if (!texture)
84 return NULL;
85
86 // Fill texture metadata structure
87 texture->numSubTextures = hdr.numSubTextures;
88 texture->width = 1 << (hdr.width_log2 + 3);
89 texture->height = 1 << (hdr.height_log2 + 3);
90 texture->format = hdr.format;
91 texture->mipmapLevels = hdr.mipmapLevels;
92
93 // Read subtexture info
94 for (size_t i = 0; i < hdr.numSubTextures; i ++)
95 {
96 Tex3DSi_SubTexture subtex;
97 if (!Tex3DSi_ReadData(callback, &userdata, &subtex, sizeof(Tex3DSi_SubTexture), &insize))
98 {
99 free(texture);
100 return NULL;
101 }
102 texture->subTextures[i].width = subtex.width;
103 texture->subTextures[i].height = subtex.height;
104 texture->subTextures[i].left = subtex.left / 1024.0f;
105 texture->subTextures[i].top = subtex.top / 1024.0f;
106 texture->subTextures[i].right = subtex.right / 1024.0f;
107 texture->subTextures[i].bottom = subtex.bottom / 1024.0f;
108 }
109
110 // Allocate texture memory
111 C3D_TexInitParams params;
112 params.width = texture->width;
113 params.height = texture->height;
114 params.maxLevel = texture->mipmapLevels;
115 params.format = texture->format;
116 params.type = (GPU_TEXTURE_MODE_PARAM)hdr.type;
117 params.onVram = vram;
118 if (!C3D_TexInitWithParams(tex, texcube, params))
119 {
120 free(texture);
121 return NULL;
122 }
123
124 // Get texture size, including mipmaps
125 size_t base_texsize = C3D_TexCalcTotalSize(tex->size, texture->mipmapLevels);
126 size_t texsize = base_texsize;
127
128 // If this is a cubemap/skybox, there are 6 textures
129 if (params.type == GPU_TEX_CUBE_MAP)
130 texsize *= 6;
131
132 if (vram)
133 {
134 // Allocate staging buffer in linear memory
135 void* texdata = linearAlloc(texsize);
136 if (!texdata)
137 {
138 C3D_TexDelete(tex);
139 free(texture);
140 return NULL;
141 }
142
143 // Decompress into staging buffer for VRAM upload
144 if (!decompress(texdata, texsize, callback, userdata, insize))
145 {
146 linearFree(texdata);
147 C3D_TexDelete(tex);
148 free(texture);
149 return NULL;
150 }
151
152 // Flush buffer to prepare DMA to VRAM
153 GSPGPU_FlushDataCache(texdata, texsize);
154
155 size_t texcount = 1;
156 if (params.type == GPU_TEX_CUBE_MAP)
157 texcount = 6;
158
159 // Upload texture(s) to VRAM
160 for (size_t i = 0; i < texcount; ++i)
161 C3D_TexLoadImage(tex, (u8*)texdata + i * base_texsize, i, -1);
162
163 linearFree(texdata);
164 } else if (params.type == GPU_TEX_CUBE_MAP)
165 {
166 decompressIOVec iov[6];
167
168 // Setup IO vectors
169 for (size_t i = 0; i < 6; ++i)
170 {
171 u32 size;
172 iov[i].data = C3D_TexCubeGetImagePtr(tex, i, -1, &size);
173 iov[i].size = size;
174 }
175
176 // Decompress into texture memory
177 if (!decompressV(iov, 6, callback, userdata, insize))
178 {
179 C3D_TexDelete(tex);
180 free(texture);
181 return NULL;
182 }
183 } else
184 {
185 u32 size;
186 void* data = C3D_Tex2DGetImagePtr(tex, -1, &size);
187
188 // Decompress into texture memory
189 if (!decompress(data, size, callback, userdata, insize))
190 {
191 C3D_TexDelete(tex);
192 free(texture);
193 return NULL;
194 }
195 }
196
197 return texture;
198}
199
200Tex3DS_Texture
201Tex3DS_TextureImport(const void* input, size_t insize, C3D_Tex* tex, C3D_TexCube* texcube, bool vram)
202{
203 return Tex3DSi_ImportCommon(tex, texcube, vram, NULL, (void*)input, insize);
204}
205
206Tex3DS_Texture
207Tex3DS_TextureImportCallback(C3D_Tex* tex, C3D_TexCube* texcube, bool vram, decompressCallback callback, void* userdata)
208{
209 return Tex3DSi_ImportCommon(tex, texcube, vram, callback, userdata, 0);
210}
211
212Tex3DS_Texture
213Tex3DS_TextureImportFD(int fd, C3D_Tex* tex, C3D_TexCube* texcube, bool vram)
214{
215 return Tex3DSi_ImportCommon(tex, texcube, vram, decompressCallback_FD, &fd, 0);
216}
217
218Tex3DS_Texture
219Tex3DS_TextureImportStdio(FILE* fp, C3D_Tex* tex, C3D_TexCube* texcube, bool vram)
220{
221 return Tex3DSi_ImportCommon(tex, texcube, vram, decompressCallback_Stdio, fp, 0);
222}
223
224size_t
225Tex3DS_GetNumSubTextures(const Tex3DS_Texture texture)
226{
227 return texture->numSubTextures;
228}
229
230const Tex3DS_SubTexture*
231Tex3DS_GetSubTexture(const Tex3DS_Texture texture, size_t index)
232{
233 if (index < texture->numSubTextures)
234 return &texture->subTextures[index];
235 return NULL;
236}
237
238void Tex3DS_TextureFree(Tex3DS_Texture texture)
239{
240 free(texture);
241}
Tex3DS texture.
Definition: tex3ds.c:35
u16 numSubTextures
Number of subtextures.
Definition: tex3ds.c:36
u16 width
Texture width.
Definition: tex3ds.c:37
u16 height
Texture height.
Definition: tex3ds.c:38
u8 mipmapLevels
Number of mipmaps.
Definition: tex3ds.c:40
u8 format
Texture format.
Definition: tex3ds.c:39
Tex3DS_SubTexture subTextures[]
Subtextures.
Definition: tex3ds.c:41
Tex3DS_Texture Tex3DS_TextureImportFD(int fd, C3D_Tex *tex, C3D_TexCube *texcube, bool vram)
Definition: tex3ds.c:213
Tex3DS_Texture Tex3DS_TextureImportStdio(FILE *fp, C3D_Tex *tex, C3D_TexCube *texcube, bool vram)
Definition: tex3ds.c:219
void Tex3DS_TextureFree(Tex3DS_Texture texture)
Definition: tex3ds.c:238
Tex3DS_Texture Tex3DS_TextureImportCallback(C3D_Tex *tex, C3D_TexCube *texcube, bool vram, decompressCallback callback, void *userdata)
Definition: tex3ds.c:207
Tex3DSi_Header
Definition: tex3ds.c:52
size_t Tex3DS_GetNumSubTextures(const Tex3DS_Texture texture)
Definition: tex3ds.c:225
struct __attribute__((packed))
Definition: tex3ds.c:44
const Tex3DS_SubTexture * Tex3DS_GetSubTexture(const Tex3DS_Texture texture, size_t index)
Definition: tex3ds.c:231
Tex3DS_Texture Tex3DS_TextureImport(const void *input, size_t insize, C3D_Tex *tex, C3D_TexCube *texcube, bool vram)
Definition: tex3ds.c:201
void C3D_TexLoadImage(C3D_Tex *tex, const void *data, GPU_TEXFACE face, int level)
Definition: texture.c:112
void C3D_TexDelete(C3D_Tex *tex)
Definition: texture.c:242
bool C3D_TexInitWithParams(C3D_Tex *tex, C3D_TexCube *cube, C3D_TexInitParams p)
Definition: texture.c:63
float24Uniform_s * data
Definition: uniforms.c:16