| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | #define SG_BUILD_LIBRARY |
| 16 | #include <siege/graphics/atlas.h> |
| 17 | #include <siege/graphics/draw.h> |
| 18 | #include <siege/util/vector.h> |
| 19 | |
| 20 | #include <stdlib.h> |
| 21 | #include <stdio.h> |
| 22 | #include <math.h> |
| 23 | |
| 24 | static SGbool _sgAtlasNodeIsLeaf(SGAtlasNode* node) |
| 25 | { |
| 26 | return !node->child[0] && !node->child[1]; |
| 27 | } |
| 28 | static SGAtlasNode* _sgAtlasNodeCreate(SGushort x, SGushort y, SGushort w, SGushort h, size_t index) |
| 29 | { |
| 30 | SGAtlasNode* node = malloc(sizeof(SGAtlasNode)); |
| 31 | if(!node) return NULL((void*)0); |
| 32 | |
| 33 | node->child[0] = NULL((void*)0); |
| 34 | node->child[1] = NULL((void*)0); |
| 35 | |
| 36 | node->area.x = x; |
| 37 | node->area.y = y; |
| 38 | node->area.w = w; |
| 39 | node->area.h = h; |
| 40 | node->area.index = index; |
| 41 | |
| 42 | node->reserved = SG_FALSE0; |
| 43 | |
| 44 | return node; |
| 45 | } |
| 46 | static void _sgAtlasNodeDestroy(SGAtlasNode* node) |
| 47 | { |
| 48 | if(!node) return; |
| 49 | _sgAtlasNodeDestroy(node->child[0]); |
| 50 | _sgAtlasNodeDestroy(node->child[1]); |
| 51 | free(node); |
| 52 | } |
| 53 | static SGAtlasNode* _sgAtlasNodeInsert(SGAtlasNode* node, SGushort w, SGushort h, size_t index) |
| 54 | { |
| 55 | SGAtlasNode* nnode; |
| 56 | if(!_sgAtlasNodeIsLeaf(node)) |
| |
| |
| |
| |
| 57 | { |
| 58 | nnode = _sgAtlasNodeInsert(node->child[0], w, h, index); |
| 59 | if(nnode) return nnode; |
| 60 | |
| 61 | return _sgAtlasNodeInsert(node->child[1], w, h, index); |
| 62 | } |
| 63 | if(node->reserved) return NULL((void*)0); |
| |
| |
| |
| 26 | | Access to field 'reserved' results in a dereference of a null pointer (loaded from variable 'node') |
|
| 64 | if(node->area.w < w || node->area.h < h) return NULL((void*)0); |
| |
| |
| |
| 65 | if(node->area.w == w && node->area.h == h) |
| 66 | { |
| 67 | node->reserved = SG_TRUE1; |
| 68 | return node; |
| 69 | } |
| 70 | |
| 71 | SGushort dw = node->area.w - w; |
| 72 | SGushort dh = node->area.h - h; |
| 73 | |
| 74 | if(dw > dh) |
| |
| 15 | | Assuming 'dw' is <= 'dh' | |
|
| |
| 21 | | Assuming 'dw' is <= 'dh' | |
|
| |
| 75 | { |
| 76 | node->child[0] = _sgAtlasNodeCreate(node->area.x , node->area.y, w, node->area.h, index); |
| 77 | node->child[1] = _sgAtlasNodeCreate(node->area.x + w, node->area.y, dw, node->area.h, index); |
| 78 | } |
| 79 | else |
| 80 | { |
| 81 | node->child[0] = _sgAtlasNodeCreate(node->area.x, node->area.y , node->area.w, h, index); |
| 82 | node->child[1] = _sgAtlasNodeCreate(node->area.x, node->area.y + h, node->area.w, dh, index); |
| 83 | } |
| 84 | |
| 85 | return _sgAtlasNodeInsert(node->child[0], w, h, index); |
| 11 | | Calling '_sgAtlasNodeInsert' | |
|
| 17 | | Calling '_sgAtlasNodeInsert' | |
|
| 23 | | Passing null pointer value via 1st parameter 'node' | |
|
| 24 | | Calling '_sgAtlasNodeInsert' | |
|
| 86 | } |
| 87 | |
| 88 | static void SG_CALL__cdecl _sgAtlasNodeDrawDBG(SGAtlasNode* node, float x, float y) |
| 89 | { |
| 90 | if(!node) return; |
| 91 | _sgAtlasNodeDrawDBG(node->child[0], x, y); |
| 92 | _sgAtlasNodeDrawDBG(node->child[1], x, y); |
| 93 | |
| 94 | |
| 95 | |
| 96 | |
| 97 | |
| 98 | sgDrawRectangleWH(node->area.x + x, node->area.y + y, node->area.w, node->area.h, SG_FALSE0); |
| 99 | } |
| 100 | |
| 101 | static SGTexture* _sgAtlasAddTexture(SGAtlas* atlas, SGTexture* texture, SGbool owner) |
| 102 | { |
| 103 | if(!texture) return NULL((void*)0); |
| 104 | atlas->textures = realloc(atlas->textures, (atlas->numtextures + 1) * sizeof(SGAtlasTexture)); |
| 105 | atlas->textures[atlas->numtextures].texture = texture; |
| 106 | atlas->textures[atlas->numtextures].owner = owner; |
| 107 | atlas->textures[atlas->numtextures].root = _sgAtlasNodeCreate(0, 0, atlas->width, atlas->height, atlas->numtextures); |
| 108 | atlas->numtextures++; |
| 109 | return texture; |
| 110 | } |
| 111 | |
| 112 | SGAtlas* SG_CALL__cdecl sgAtlasCreate(size_t width, size_t height, SGenum bpp) |
| 113 | { |
| 114 | return sgAtlasCreateData(width, height, bpp, NULL((void*)0)); |
| 115 | } |
| 116 | SGAtlas* SG_CALL__cdecl sgAtlasCreateData(size_t width, size_t height, SGenum bpp, void* data) |
| 117 | { |
| 118 | SGAtlas* atlas = malloc(sizeof(SGAtlas)); |
| 119 | if(!atlas) return NULL((void*)0); |
| 120 | |
| 121 | atlas->width = width; |
| 122 | atlas->height = height; |
| 123 | atlas->bpp = bpp; |
| 124 | atlas->numtextures = 0; |
| 125 | atlas->textures = NULL((void*)0); |
| 126 | |
| 127 | _sgAtlasAddTexture(atlas, sgTextureCreateData(width, height, bpp, data), SG_TRUE1); |
| 128 | |
| 129 | return atlas; |
| 130 | } |
| 131 | SGAtlas* SG_CALL__cdecl sgAtlasCreateTexture(SGTexture* texture, SGbool owner) |
| 132 | { |
| 133 | SGAtlas* atlas = sgAtlasCreate(sgTextureGetWidth(texture), sgTextureGetHeight(texture), sgTextureGetBPP(texture)); |
| 134 | if(!atlas) return NULL((void*)0); |
| 135 | |
| 136 | _sgAtlasAddTexture(atlas, texture, owner); |
| 137 | |
| 138 | return atlas; |
| 139 | } |
| 140 | SGAtlas* SG_CALL__cdecl sgAtlasCreateFile(const char* fname) |
| 141 | { |
| 142 | return sgAtlasCreateTexture(sgTextureCreateFile(fname), SG_TRUE1); |
| 143 | } |
| 144 | void SG_CALL__cdecl sgAtlasDestroy(SGAtlas* atlas) |
| 145 | { |
| 146 | if(!atlas) |
| 147 | return; |
| 148 | |
| 149 | size_t i; |
| 150 | for(i = 0; i < atlas->numtextures; i++) |
| 151 | { |
| 152 | if(atlas->textures[i].owner) |
| 153 | sgTextureDestroy(atlas->textures[i].texture); |
| 154 | _sgAtlasNodeDestroy(atlas->textures[i].root); |
| 155 | } |
| 156 | free(atlas->textures); |
| 157 | free(atlas); |
| 158 | } |
| 159 | |
| 160 | SGAtlasArea* SG_CALL__cdecl sgAtlasAreaReserve(SGAtlas* atlas, size_t width, size_t height, SGbool overflow) |
| 161 | { |
| 162 | if(width > atlas->width || height > atlas->height) |
| |
| 163 | return NULL((void*)0); |
| 164 | |
| 165 | SGAtlasNode* node = _sgAtlasNodeInsert(atlas->textures[atlas->numtextures - 1].root, width, height, atlas->numtextures - 1); |
| 166 | if(node) return &node->area; |
| |
| |
| 167 | |
| 168 | |
| 169 | if(!overflow) return NULL((void*)0); |
| 4 | | Assuming 'overflow' is not equal to 0 | |
|
| |
| 170 | |
| 171 | _sgAtlasAddTexture(atlas, sgTextureCreateData(atlas->width, atlas->height, atlas->bpp, NULL((void*)0)), SG_TRUE1); |
| 172 | node = _sgAtlasNodeInsert(atlas->textures[atlas->numtextures - 1].root, width, height, atlas->numtextures - 1); |
| 6 | | Calling '_sgAtlasNodeInsert' | |
|
| 173 | if(node) return &node->area; |
| 174 | |
| 175 | return NULL((void*)0); |
| 176 | } |
| 177 | void SG_CALL__cdecl sgAtlasAreaSetData(SGAtlas* atlas, SGAtlasArea* area, size_t width, size_t height, SGenum bpp, void* data) |
| 178 | { |
| 179 | if(area->index >= atlas->numtextures) |
| 180 | return; |
| 181 | if(width > area->w || height > area->h) |
| 182 | return; |
| 183 | sgTextureSetSubData(atlas->textures[area->index].texture, area->x, area->y, width, height, bpp, data); |
| 184 | } |
| 185 | |
| 186 | void SG_CALL__cdecl sgAtlasAreaDrawRads3f2f2f1f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float z, float xscale, float yscale, float xoffset, float yoffset, float angle) |
| 187 | { |
| 188 | float s0, t0, s1, t1; |
| 189 | sgAtlasGetTexCoordsA(atlas, area, &s0, &t0, &s1, &t1); |
| 190 | |
| 191 | |
| 192 | SGVec2 pos = sgVec2f(x, y); |
| 193 | SGVec2 p0, p1, p2, p3; |
| 194 | p0 = sgVec2f(-xoffset , -yoffset ); |
| 195 | p1 = sgVec2f(-xoffset , -yoffset + area->h * yscale); |
| 196 | p2 = sgVec2f(-xoffset + area->w * xscale, -yoffset + area->h * yscale); |
| 197 | p3 = sgVec2f(-xoffset + area->w * xscale, -yoffset ); |
| 198 | |
| 199 | p0 = sgVec2RotateRads(p0, sgVec2AngleRads(p0) + angle); |
| 200 | p1 = sgVec2RotateRads(p1, sgVec2AngleRads(p1) + angle); |
| 201 | p2 = sgVec2RotateRads(p2, sgVec2AngleRads(p2) + angle); |
| 202 | p3 = sgVec2RotateRads(p3, sgVec2AngleRads(p3) + angle); |
| 203 | |
| 204 | p0 = sgVec2Add(p0, pos); |
| 205 | p1 = sgVec2Add(p1, pos); |
| 206 | p2 = sgVec2Add(p2, pos); |
| 207 | p3 = sgVec2Add(p3, pos); |
| 208 | |
| 209 | sgDrawBeginT(SG_QUADS0x0A, sgAtlasGetTextureA(atlas, area)); |
| 210 | sgDrawTexCoord2f(s0, t0); |
| 211 | sgDrawVertex3f(p0.x, p0.y, z); |
| 212 | sgDrawTexCoord2f(s0, t1); |
| 213 | sgDrawVertex3f(p1.x, p1.y, z); |
| 214 | sgDrawTexCoord2f(s1, t1); |
| 215 | sgDrawVertex3f(p2.x, p3.y, z); |
| 216 | sgDrawTexCoord2f(s1, t0); |
| 217 | sgDrawVertex3f(p2.x, p3.y, z); |
| 218 | sgDrawEnd(); |
| 219 | } |
| 220 | void SG_CALL__cdecl sgAtlasAreaDrawDegs3f2f2f1f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float z, float xscale, float yscale, float xoffset, float yoffset, float angle) |
| 221 | { |
| 222 | sgAtlasAreaDrawRads3f2f2f1f(atlas, area, x, y, z, xscale, yscale, xoffset, yoffset, angle * SG_PI3.14159265358979323846 / 180.0); |
| 223 | } |
| 224 | void SG_CALL__cdecl sgAtlasAreaDrawRads2f2f2f1f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float xscale, float yscale, float xoffset, float yoffset, float angle) |
| 225 | { |
| 226 | sgAtlasAreaDrawRads3f2f2f1f(atlas, area, x, y, 0.0, xscale, yscale, xoffset, yoffset, angle); |
| 227 | } |
| 228 | void SG_CALL__cdecl sgAtlasAreaDrawDegs2f2f2f1f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float xscale, float yscale, float xoffset, float yoffset, float angle) |
| 229 | { |
| 230 | sgAtlasAreaDrawDegs3f2f2f1f(atlas, area, x, y, 0.0, xscale, yscale, xoffset, yoffset, angle); |
| 231 | } |
| 232 | void SG_CALL__cdecl sgAtlasAreaDrawRads3f2f1f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float z, float xscale, float yscale, float angle) |
| 233 | { |
| 234 | sgAtlasAreaDrawRads3f2f2f1f(atlas, area, x, y, z, xscale, yscale, 0.0, 0.0, angle); |
| 235 | } |
| 236 | void SG_CALL__cdecl sgAtlasAreaDrawDegs3f2f1f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float z, float xscale, float yscale, float angle) |
| 237 | { |
| 238 | sgAtlasAreaDrawDegs3f2f2f1f(atlas, area, x, y, z, xscale, yscale, 0.0, 0.0, angle); |
| 239 | } |
| 240 | void SG_CALL__cdecl sgAtlasAreaDrawRads2f2f1f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float xscale, float yscale, float angle) |
| 241 | { |
| 242 | sgAtlasAreaDrawRads3f2f2f1f(atlas, area, x, y, 0.0, xscale, yscale, 0.0, 0.0, angle); |
| 243 | } |
| 244 | void SG_CALL__cdecl sgAtlasAreaDrawDegs2f2f1f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float xscale, float yscale, float angle) |
| 245 | { |
| 246 | sgAtlasAreaDrawDegs3f2f2f1f(atlas, area, x, y, 0.0, xscale, yscale, 0.0, 0.0, angle); |
| 247 | } |
| 248 | void SG_CALL__cdecl sgAtlasAreaDrawRads3f1f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float z, float angle) |
| 249 | { |
| 250 | sgAtlasAreaDrawRads3f2f2f1f(atlas, area, x, y, z, 1.0, 1.0, 0.0, 0.0, angle); |
| 251 | } |
| 252 | void SG_CALL__cdecl sgAtlasAreaDrawDegs3f1f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float z, float angle) |
| 253 | { |
| 254 | sgAtlasAreaDrawDegs3f2f2f1f(atlas, area, x, y, z, 1.0, 1.0, 0.0, 0.0, angle); |
| 255 | } |
| 256 | void SG_CALL__cdecl sgAtlasAreaDrawRads2f1f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float angle) |
| 257 | { |
| 258 | sgAtlasAreaDrawRads3f2f2f1f(atlas, area, x, y, 0.0, 1.0, 1.0, 0.0, 0.0, angle); |
| 259 | } |
| 260 | void SG_CALL__cdecl sgAtlasAreaDrawDegs2f1f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float angle) |
| 261 | { |
| 262 | sgAtlasAreaDrawDegs3f2f2f1f(atlas, area, x, y, 0.0, 1.0, 1.0, 0.0, 0.0, angle); |
| 263 | } |
| 264 | void SG_CALL__cdecl sgAtlasAreaDraw3f2f2f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float z, float xscale, float yscale, float xoffset, float yoffset) |
| 265 | { |
| 266 | sgAtlasAreaDrawRads3f2f2f1f(atlas, area, x, y, z, xscale, yscale, xoffset, yoffset, 0.0); |
| 267 | } |
| 268 | void SG_CALL__cdecl sgAtlasAreaDraw2f2f2f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float xscale, float yscale, float xoffset, float yoffset) |
| 269 | { |
| 270 | sgAtlasAreaDrawRads3f2f2f1f(atlas, area, x, y, 0.0, xscale, yscale, xoffset, yoffset, 0.0); |
| 271 | } |
| 272 | void SG_CALL__cdecl sgAtlasAreaDraw3f2f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float z, float xscale, float yscale) |
| 273 | { |
| 274 | sgAtlasAreaDrawRads3f2f2f1f(atlas, area, x, y, z, xscale, yscale, 0.0, 0.0, 0.0); |
| 275 | } |
| 276 | void SG_CALL__cdecl sgAtlasAreaDraw2f2f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float xscale, float yscale) |
| 277 | { |
| 278 | sgAtlasAreaDrawRads3f2f2f1f(atlas, area, x, y, 0.0, xscale, yscale, 0.0, 0.0, 0.0); |
| 279 | } |
| 280 | void SG_CALL__cdecl sgAtlasAreaDraw3f(SGAtlas* atlas, SGAtlasArea* area, float x, float y, float z) |
| 281 | { |
| 282 | sgAtlasAreaDrawRads3f2f2f1f(atlas, area, x, y, z, 1.0, 1.0, 0.0, 0.0, 0.0); |
| 283 | } |
| 284 | void SG_CALL__cdecl sgAtlasAreaDraw2f(SGAtlas* atlas, SGAtlasArea* area, float x, float y) |
| 285 | { |
| 286 | sgAtlasAreaDrawRads3f2f2f1f(atlas, area, x, y, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0); |
| 287 | } |
| 288 | void SG_CALL__cdecl sgAtlasAreaDraw(SGAtlas* atlas, SGAtlasArea* area) |
| 289 | { |
| 290 | sgAtlasAreaDrawRads3f2f2f1f(atlas, area, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0); |
| 291 | } |
| 292 | |
| 293 | void SG_CALL__cdecl sgAtlasGetTexCoords4i(SGAtlas* atlas, SGint x, SGint y, SGint w, SGint h, float* s0, float* t0, float* s1, float* t1) |
| 294 | { |
| 295 | *s0 = x / (float)atlas->width; |
| 296 | *t0 = y / (float)atlas->height; |
| 297 | *s1 = (x + w) / (float)atlas->width; |
| 298 | *t1 = (y + h) / (float)atlas->width; |
| 299 | } |
| 300 | void SG_CALL__cdecl sgAtlasGetTexCoordsA(SGAtlas* atlas, SGAtlasArea* area, float* s0, float* t0, float* s1, float* t1) |
| 301 | { |
| 302 | sgAtlasGetTexCoords4i(atlas, area->x, area->y, area->w, area->h, s0, t0, s1, t1); |
| 303 | } |
| 304 | |
| 305 | size_t SG_CALL__cdecl sgAtlasGetNumTextures(SGAtlas* atlas) |
| 306 | { |
| 307 | return atlas->numtextures; |
| 308 | } |
| 309 | SGTexture* SG_CALL__cdecl sgAtlasGetTexture(SGAtlas* atlas, size_t index) |
| 310 | { |
| 311 | if(index >= atlas->numtextures) |
| 312 | return NULL((void*)0); |
| 313 | return atlas->textures[index].texture; |
| 314 | } |
| 315 | SGTexture* SG_CALL__cdecl sgAtlasGetTextureA(SGAtlas* atlas, SGAtlasArea* area) |
| 316 | { |
| 317 | return sgAtlasGetTexture(atlas, area->index); |
| 318 | } |
| 319 | |
| 320 | void SG_CALL__cdecl sgAtlasGetSize(SGAtlas* atlas, size_t* width, size_t* height) |
| 321 | { |
| 322 | if(width) *width = atlas->width; |
| 323 | if(height) *height = atlas->height; |
| 324 | } |
| 325 | size_t SG_CALL__cdecl sgAtlasGetWidth(SGAtlas* atlas) |
| 326 | { |
| 327 | return atlas->width; |
| 328 | } |
| 329 | size_t SG_CALL__cdecl sgAtlasGetHeight(SGAtlas* atlas) |
| 330 | { |
| 331 | return atlas->height; |
| 332 | } |
| 333 | |
| 334 | void SG_CALL__cdecl sgAtlasDrawDBG(SGAtlas* atlas, float x, float y, size_t index, SGbool wires) |
| 335 | { |
| 336 | if(index > atlas->numtextures) |
| 337 | { |
| 338 | sgDrawRectangleWH(x, y, atlas->width, atlas->height, SG_FALSE0); |
| 339 | return; |
| 340 | } |
| 341 | if(wires) |
| 342 | _sgAtlasNodeDrawDBG(atlas->textures[index].root, x, y); |
| 343 | else |
| 344 | sgTextureDraw2f(atlas->textures[index].texture, x, y); |
| 345 | } |