view src/dmlib.h @ 2395:e149fc273f2b

Remove the __USE_MINGW_ANSI_STDIO hack.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 09 Jan 2020 21:14:18 +0200
parents 147d40b708ea
children bcd33c77c605
line wrap: on
line source

/*
 * DMLib
 * -- Main header file
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2011-2020 Tecnic Software productions (TNSP)
 */
#ifndef DMLIB_H
#define DMLIB_H

#include <SDL_config.h>
#include <SDL_endian.h>
#include <SDL_types.h>
#include <SDL_mutex.h>
#include <SDL_thread.h>
#include <SDL_video.h>
#include <SDL_render.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
#include <inttypes.h>


#ifdef DM_USE_ASSERTS
#  include <assert.h>
#else
#  define assert(NEXPR) // stub
#endif


// Check for arch bitness
#if defined(__WIN64) || defined(_WIN64) || defined(_WIN32) || defined(__WIN32)
#  define DM_PLAT_WINDOWS 1
#else
#  define DM_PLAT_UNIX 1
#endif

// Check for arch bitness
#if !defined(DM_ARCH) && (defined(__WIN64) || defined(_WIN64))
#  define DM_ARCH 64
#endif

#if !defined(DM_ARCH) && (defined(__WIN32) || defined(_WIN32))
#  define DM_ARCH 32
#endif

#if !defined(DM_ARCH)
#  if UINTPTR_MAX == 0xffffffff
#    define DM_ARCH 32
#  elif UINTPTR_MAX == 0xffffffffffffffff
#    define DM_ARCH 64
#  endif
#endif


#if !defined(DM_ARCH)
#  if defined(__LP64__) || defined(_LP64)
#    define DM_ARCH 64
#  else
#    define DM_ARCH 32
#  endif
#endif


// Kludge, as MinGW64 cross-compiler does not like certain printf() format specifiers
#if defined(__MINGW64__)
#  define DM_ATTR_PRINTF_FMT(xstart, xend)
#else
#  define DM_ATTR_PRINTF_FMT(xstart, xend) __attribute__ ((__format__ (__printf__, (xstart), (xend))))
#endif


// Do we have a valid arch?
// If so, set some printf specifiers
#define DM_PRIu32              PRIu32
#define DM_PRId32              PRId32
#define DM_PRIx32              PRIx32
#define DM_PRIX32              PRIX32

#define DM_PRIu64              PRIu64
#define DM_PRId64              PRId64
#define DM_PRIx64              PRIx64
#define DM_PRIX64              PRIX64

#if DM_ARCH == 32
#    define DM_PRIu_SIZE_T     PRIu32
#    define DM_PRId_SSIZE_T    PRId32
#    define DM_PRIx_SIZE_T     PRIx32
#    define DM_PRIX_SIZE_T     PRIX32
#  ifdef DM_PLAT_WINDOWS
#    define DM_PRId_OFF_T      "ld"
#    define DM_PRIx_OFF_T      "lx"
#    define DM_PRIX_OFF_T      "lX"
#  else
#    define DM_PRId_OFF_T      PRId32
#    define DM_PRIx_OFF_T      PRIx32
#    define DM_PRIX_OFF_T      PRIX32
#  endif
#elif DM_ARCH == 64
#  ifdef DM_PLAT_WINDOWS // Unsure if this is MinGW64 only thing?
#    define DM_PRIu_SIZE_T     "I64u"
#    define DM_PRId_SSIZE_T    "I64d"
#    define DM_PRIx_SIZE_T     "I64x"
#    define DM_PRIX_SIZE_T     "I64X"
#    define DM_PRId_OFF_T      "I64d"
#    define DM_PRIx_OFF_T      "I64x"
#    define DM_PRIX_OFF_T      "I64X"
#  else
#    define DM_PRIu_SIZE_T     PRIu64
#    define DM_PRId_SSIZE_T    PRId64
#    define DM_PRIx_SIZE_T     PRIx64
#    define DM_PRIX_SIZE_T     PRIX64
#    define DM_PRId_OFF_T      PRId64
#    define DM_PRIx_OFF_T      PRIx64
#    define DM_PRIX_OFF_T      PRIX64
#  endif
#else
#  error Could not determine architecture (32/64bit), please define DM_ARCH=32 or 64
#endif


#ifdef __cplusplus
extern "C" {
#endif

// Defaults
#define DM_PROG_AUTHOR      "By Matti 'ccr' Hamalainen (C) Copyright 2020 TNSP"
#define DM_PROG_LICENSE     "Et all, see README / COPYING for more information."

/* Error codes
 */
enum {
    // General error codes
    DMERR_OK = 0,
    DMERR_PROGRESS,     // Status OK, but operation in progress

    DMERR_INTERNAL,
	
    DMERR_FOPEN,
    DMERR_FREAD,
    DMERR_FWRITE,
    DMERR_FSEEK,
    DMERR_NOT_FOUND,    // Resource/data not found

    DMERR_INVALID_DATA, // Some data was invalid
    DMERR_MALLOC,       // Memory allocation failure
    DMERR_ALREADY_INIT, // Resource has already been initialized
    DMERR_INIT_FAIL,    // General initialization failure
    DMERR_INVALID_ARGS,

    DMERR_NULLPTR,      // NULL pointer specified in critical argument
    DMERR_NOT_SUPPORTED,// Operation not supported
    DMERR_OUT_OF_DATA,
    DMERR_EXTRA_DATA,
    DMERR_BOUNDS,

    DMERR_DATA_ERROR,   // Data decoding/encoding/parsing error

    DMERR_VERSION,      // Unsupported data version

    // PACK-file subsystem
    DMERR_NOTPACK,
    DMERR_PACK_VERSION,
    DMERR_INVALID,
    DMERR_COMPRESSION,
};


// Directory/path separator stuff
#define DM_DIR_SEPARATOR     '/'


// Resource management defines
#define DMRES_NAME_LEN  32
#define DMRES_RES_FILE  "res.txt"   // Resource data file


/* Define a boolean type
 */
#if !defined(FALSE) && !defined(TRUE) && !defined(BOOL)
typedef enum { FALSE = 0, TRUE = 1 } BOOL;
#endif

#ifndef BOOL
#  ifdef bool
#    define BOOL bool
#  else
#    define BOOL int
#  endif
#endif


/* Math constants
 */
#define DM_PI   3.14159265358f
#define DM_PI2  6.28318530718f
#define DM_E    2.71828182846f


/* Fixed point math types
 */
typedef union
{
    Sint64 dw;
    Sint32 w[2];
} DMFixedPoint;


typedef union
{
    Sint32 dw;
    Sint16 w[2];
} DMFixedPoint32;


/* Macros for fixed point math
 */
#define FP_SET(a, k) a.dw = k ## ULL
#define FP_CONV(a, k) a.dw = (k)

#ifndef SDL_BYTEORDER
#  error Undefined byteorder!
#endif

#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
#  define FP_SETH(a, k) a.w[0] = (k)
#  define FP_SETL(a, k) a.w[1] = (k)
#  define FP_SETHL(a, h, l) { a.w[0] = (h); a.w[1] = (l); }
#  define FP_GETH32(a) a.w[0]
#  define FP_GETL32(a) a.w[1]
#  define FP_GETH16(a) a.w[0]
#  define FP_GETL16(a) a.w[1]
#elif (SDL_BYTEORDER == SDL_LIL_ENDIAN)
#  define FP_SETH(a, k) a.w[1] = (k)
#  define FP_SETL(a, k) a.w[0] = (k)
#  define FP_SETHL(a, h, l) { a.w[1] = (h); a.w[0] = (l); }
#  define FP_GETH32(a) a.w[1]
#  define FP_GETL32(a) a.w[0]
#  define FP_GETH16(a) a.w[1]
#  define FP_GETL16(a) a.w[0]
#else
#  error Unsupported byte order!
#endif

#define FP_PRINTF64(a) printf("%.8x:%.8x", FP_GETH32(a), FP_GETL32(a))
#define FP_PRINTF32(a) printf("%.4x:%.4x", FP_GETH16(a), FP_GETL16(a))

#define FP_ADD(a, b) a.dw += b.dw
#define FP_SUB(a, b) a.dw -= b.dw
#define FP_ADD_R(r, a, b) r.dw = a.dw + b.dw
#define FP_SUB_R(r, a, b) r.dw = a.dw - b.dw
#define FP_DIV(a, b) a.dw /= b.dw
#define FP_MUL(a, b) a.dw *= b.dw
#define FP_DIV_R(r, a, b) r.dw = (a.dw / b.dw)
#define FP_MUL_R(r, a, b) r.dw = (a.dw * b.dw)


/* Miscellaneous types
 */
typedef struct
{
#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
    Uint8 a,g,b,r;
#elif (SDL_BYTEORDER == SDL_LIL_ENDIAN)
    Uint8 r,g,b,a;
#endif
} DMColor;


typedef float DMFloat;


// Macro for swapping two lvalues of same type
#define DM_SWAP(T, A, B) { if ((B) < (A)) { T swtmp = (B); B = (A); A = swtmp; } }


/* Drawing modes used by blitting and some other functions.
 */
enum
{
    DMD_NONE        = 0x0000,
    DMD_TRANSPARENT = 0x0001,
    DMD_SATURATE    = 0x0002,

    DMD_ANTIALIAS   = 0x0004,

    DMD_NMODES      = 6
};


// Available bitdepths. Not all functions may support every one of these.
enum
{
    DMD_8BIT = 0,
    DMD_32BIT,

    DMD_NBITDEPTHS
};


static inline int dmBitsPerPixel2Index(int bpp)
{
    return (bpp == 8 ? 0 : (bpp == 32 ? 1 : -1));
}


static inline DMFloat dmClamp10(const DMFloat a)
{
    return (a < 0.0f ? 0.0f : (a > 1.0f ? 1.0f : a));
}


static inline int dmClamp(const int v, const int min, const int max)
{
    return (v < min ? min : (v > max ? max : v));
}


/* Arbitrary line drawing
 */
#ifdef DM_GFX_LINES
#define DM_HEADER
#include "dmlinefunc.h"

enum
{
    CLIP_TOP     = 1,
    CLIP_BOTTOM  = 2,
    CLIP_RIGHT   = 4,
    CLIP_LEFT    = 8
};

#define DM_CLIP_FUNC dmClipLineCoordsFloat
#define DM_COORD_TYPE DMFloat
#include "dmlineclip.h"

#undef DM_HEADER
#endif


/* Various blitting functions
 */
#ifdef DM_GFX_BLITS
typedef int (*DMScaledBlitFunc)(SDL_Surface *src, const int x0, const int y0, const int dwidth, const int dheight, SDL_Surface *dst);
DMScaledBlitFunc dmGetScaledBlitFunc(SDL_PixelFormat *src, SDL_PixelFormat *dst, int mode);
int dmScaledBlitSurfaceAny(SDL_Surface *src, const int x0, const int y0, const int dwidth, const int dheight, SDL_Surface *dst, int mode);

typedef int (*DMUnscaledBlitFunc)(SDL_Surface *src, const int x0, const int y0, SDL_Surface *dst);
DMUnscaledBlitFunc dmGetUnscaledBlitFunc(SDL_PixelFormat *src, SDL_PixelFormat *dst, int mode);
int dmUnscaledBlitSurfaceAny(SDL_Surface *src, const int x0, const int y0, SDL_Surface *dst, int mode);

SDL_Surface *dmConvertScaledSurface(SDL_Surface *src, SDL_PixelFormat *fmt, const int dwidth, const int dheight);


#define DM_HEADER
#include "dmblitfunc.h"
#undef DM_HEADER

#endif // DM_GFX_BLITS


static inline void dmClearSurface(SDL_Surface *screen, const Uint32 col)
{
    SDL_FillRect(screen, NULL, col);
}


static inline Uint32 dmMapRGB(SDL_Surface *screen, int r, int g, int b)
{
    return SDL_MapRGB(screen->format, r, g, b);
}


static inline Uint32 dmMapRGBA(SDL_Surface *screen, int r, int g, int b, int a)
{
    return SDL_MapRGBA(screen->format, r, g, b, a);
}


static inline int dmDirectBlitSurface(SDL_Surface *bmp, SDL_Surface *screen)
{
    return SDL_BlitSurface(bmp, NULL, screen, NULL);
}


static inline SDL_Surface *dmCopySurface(SDL_Surface *src)
{
    if (src != NULL)
        return SDL_ConvertSurface(src, src->format, src->flags);
    else
        return NULL;
}


/* Global variables
 */
extern char *dmProgName,
            *dmProgDesc,
            *dmProgVersion,
            *dmProgAuthor,
            *dmProgLicense;

extern int dmVerbosity;
void       dmInitProg(char *name, char *desc, char *version, char *author, char *license);
void       dmPrintBanner(FILE *outFile, const char *name, const char *usage);

void       dmMsgVA(int level, const char *fmt, va_list ap);
void       dmMsg(int level, const char *fmt, ...)
           DM_ATTR_PRINTF_FMT(2, 3);
void       dmPrintVA(int level, const char *fmt, va_list ap);
void       dmPrint(int level, const char *fmt, ...)
           DM_ATTR_PRINTF_FMT(2, 3);

int        dmErrorVA(const int error, const char *fmt, va_list);
int        dmError(const int error, const char *fmt, ...)
           DM_ATTR_PRINTF_FMT(2, 3);
void       dmErrorMsg(const char *fmt, ...)
           DM_ATTR_PRINTF_FMT(1, 2);
int        dmGetErrno();
const char *dmErrorStr(const int error);

#ifdef DM_DEBUG
#    define dmErrorDBG dmError
#    define dmErrorDBGMsg dmErrorMsg
#else
#    define dmErrorDBG(ecode, fmt, ...) (ecode) // Dummy
#    define dmErrorDBGMsg(fmt, ...)
#endif

void *     dmMalloc(size_t len);
void *     dmMalloc0(size_t len);
void *     dmRealloc(void *ptr, size_t len);
void *     dmCalloc(size_t n, size_t len);
void       dmFree(void *ptr);
void       dmFreeRReal(void **ptr);
#define    dmFreeR(ptr) dmFreeRReal((void **) ptr)

#if defined(DM_HAVE_MEMSET) || defined(DM_HAVE_STRING_H)
static inline void * dmMemset(void *ptr, const int c, size_t n)
{
    return memset(ptr, c, n);
}
#else
void *     dmMemset(void *ptr, const int c, size_t n);
#endif


/** String trimming option flags for dm_strdup_trim()
 */
enum
{
    DM_TRIM_START    = 1,
    DM_TRIM_END      = 2,
    DM_TRIM_BOTH     = 3
};



char *     dm_strdup(const char *str);
char *     dm_strndup(const char *str, const size_t n);
char *     dm_strdup_trim(const char *src, const int flags);
char *     dm_strndup_trim(const char *src, const size_t n, const int flags);
char *     dm_strdup_vprintf_len(const char *fmt, va_list args, int *len);
char *     dm_strdup_vprintf(const char *fmt, va_list args);
char *     dm_strdup_printf(const char *fmt, ...);

int        dm_strcasecmp(const char *haystack, const char *needle);
int        dm_strncasecmp(const char *haystack, const char *needle, size_t n);
char *     dm_strrcasecmp(char *str, const char *needle);

BOOL       dmGetIntVal(const char *str, unsigned int *value, BOOL *neg);


/* Mutexes
 */
#ifdef DM_MUTEX_DEBUG

typedef struct
{
    BOOL used;
    Uint32 id;
    int state;
} DMMutexLock;

typedef struct
{
    char *cr_file;
    int cr_line;
    SDL_mutex *m;
    DMMutexLock locks[8];
} DMMutex;

#define dmMutexLock(x) dmDOMutexLock(x, __FILE__, (int) __LINE__)
#define dmMutexUnlock(x) dmDOMutexUnlock(x, __FILE__, (int) __LINE__)
#define dmCreateMutex(x) dmDOCreateMutex(__FILE__, (int) __LINE__)

int        dmDOMutexLock(DMMutex *mutex, const char *file, const int line);
int        dmDOMutexUnlock(DMMutex *mutex, const char *file, const int line);
DMMutex *  dmDOCreateMutex(const char *file, const int line);
void       dmDestroyMutex(DMMutex *mutex);

#else
#define DMMutex SDL_mutex
#define dmCreateMutex() SDL_CreateMutex()
#define dmDestroyMutex(x) SDL_DestroyMutex(x)
#define dmMutexLock(x) SDL_mutexP(x)
#define dmMutexUnlock(x) SDL_mutexV(x)
#endif

/* Endianess swapping macros
 */
#define DM_SWAP_16_LE_BE(value) ((Uint16) ( \
    (Uint16) ((Uint16) (value) >> 8) |      \
    (Uint16) ((Uint16) (value) << 8)) )


#define DM_SWAP_32_LE_BE(value) ((Uint32) (             \
    (((Uint32) (value) & (Uint32) 0x000000ffU) << 24) | \
    (((Uint32) (value) & (Uint32) 0x0000ff00U) <<  8) | \
    (((Uint32) (value) & (Uint32) 0x00ff0000U) >>  8) | \
    (((Uint32) (value) & (Uint32) 0xff000000U) >> 24)))

#define DM_SWAP_64_LE_BE(value) ((Uint64) (                       \
    (((Uint64) (value) & (Uint64) 0x00000000000000ffULL) << 56) | \
    (((Uint64) (value) & (Uint64) 0x000000000000ff00ULL) << 40) | \
    (((Uint64) (value) & (Uint64) 0x0000000000ff0000ULL) << 24) | \
    (((Uint64) (value) & (Uint64) 0x00000000ff000000ULL) <<  8) | \
    (((Uint64) (value) & (Uint64) 0x000000ff00000000ULL) >>  8) | \
    (((Uint64) (value) & (Uint64) 0x0000ff0000000000ULL) >> 24) | \
    (((Uint64) (value) & (Uint64) 0x00ff000000000000ULL) >> 40) | \
    (((Uint64) (value) & (Uint64) 0xff00000000000000ULL) >> 56)))


/* Macros that swap only when needed ...
 */
#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
#  define DM_LE16_TO_NATIVE(value) DM_SWAP_16_LE_BE(value)
#  define DM_LE32_TO_NATIVE(value) DM_SWAP_32_LE_BE(value)
#  define DM_NATIVE_TO_LE16(value) DM_SWAP_16_LE_BE(value)
#  define DM_NATIVE_TO_LE32(value) DM_SWAP_32_LE_BE(value)

#  define DM_BE16_TO_NATIVE(value) ((Uint16) (value))
#  define DM_BE32_TO_NATIVE(value) ((Uint32) (value))
#  define DM_NATIVE_TO_BE16(value) ((Uint16) (value))
#  define DM_NATIVE_TO_BE32(value) ((Uint32) (value))

#  define DM_LE64_TO_NATIVE(value) DM_SWAP_64_LE_BE(value)
#  define DM_NATIVE_TO_LE64(value) DM_SWAP_64_LE_BE(value)
#  define DM_BE64_TO_NATIVE(value) ((Uint64) (value))
#  define DM_NATIVE_TO_BE64(value) ((Uint64) (value))

#elif (SDL_BYTEORDER == SDL_LIL_ENDIAN)

#  define DM_LE16_TO_NATIVE(value) ((Uint16) (value))
#  define DM_LE32_TO_NATIVE(value) ((Uint32) (value))
#  define DM_NATIVE_TO_LE16(value) ((Uint16) (value))
#  define DM_NATIVE_TO_LE32(value) ((Uint32) (value))

#  define DM_BE16_TO_NATIVE(value) DM_SWAP_16_LE_BE(value)
#  define DM_BE32_TO_NATIVE(value) DM_SWAP_32_LE_BE(value)
#  define DM_NATIVE_TO_BE16(value) DM_SWAP_16_LE_BE(value)
#  define DM_NATIVE_TO_BE32(value) DM_SWAP_32_LE_BE(value)

#  define DM_LE64_TO_NATIVE(value) ((Uint64) (value))
#  define DM_NATIVE_TO_LE64(value) ((Uint64) (value))
#  define DM_BE64_TO_NATIVE(value) DM_SWAP_64_LE_BE(value)
#  define DM_NATIVE_TO_BE64(value) DM_SWAP_64_LE_BE(value)
#endif


#ifdef __cplusplus
}
#endif

#endif // DMLIB_H