aboutsummaryrefslogtreecommitdiff
path: root/src/libjin
diff options
context:
space:
mode:
Diffstat (limited to 'src/libjin')
-rw-r--r--src/libjin/audio/audio.cpp11
-rw-r--r--src/libjin/audio/audio.h15
-rw-r--r--src/libjin/core/game.cpp14
-rw-r--r--src/libjin/core/game.h38
-rw-r--r--src/libjin/fs/buffer.h42
-rw-r--r--src/libjin/fs/dirent.h951
-rw-r--r--src/libjin/fs/filesystem.cpp68
-rw-r--r--src/libjin/fs/filesystem.h55
-rw-r--r--src/libjin/input/event.cpp7
-rw-r--r--src/libjin/input/event.h13
-rw-r--r--src/libjin/input/keyboard.cpp0
-rw-r--r--src/libjin/input/keyboard.h13
-rw-r--r--src/libjin/input/mouse.cpp0
-rw-r--r--src/libjin/input/mouse.h30
-rw-r--r--src/libjin/net/net.h6
-rw-r--r--src/libjin/render/canvas.cpp123
-rw-r--r--src/libjin/render/canvas.h33
-rw-r--r--src/libjin/render/color.h27
-rw-r--r--src/libjin/render/drawable.cpp92
-rw-r--r--src/libjin/render/drawable.h47
-rw-r--r--src/libjin/render/font.cpp189
-rw-r--r--src/libjin/render/font.h58
-rw-r--r--src/libjin/render/graphics.cpp115
-rw-r--r--src/libjin/render/graphics.h37
-rw-r--r--src/libjin/render/image.cpp97
-rw-r--r--src/libjin/render/image.h34
-rw-r--r--src/libjin/render/jsl.cpp84
-rw-r--r--src/libjin/render/jsl.h44
-rw-r--r--src/libjin/render/quad.h17
-rw-r--r--src/libjin/render/rect.h12
-rw-r--r--src/libjin/render/window.cpp83
-rw-r--r--src/libjin/render/window.h53
32 files changed, 2408 insertions, 0 deletions
diff --git a/src/libjin/audio/audio.cpp b/src/libjin/audio/audio.cpp
new file mode 100644
index 0000000..88fe52b
--- /dev/null
+++ b/src/libjin/audio/audio.cpp
@@ -0,0 +1,11 @@
+#include "audio.h"
+
+namespace jin
+{
+namespace audio
+{
+
+
+
+}
+} \ No newline at end of file
diff --git a/src/libjin/audio/audio.h b/src/libjin/audio/audio.h
new file mode 100644
index 0000000..652e7a8
--- /dev/null
+++ b/src/libjin/audio/audio.h
@@ -0,0 +1,15 @@
+#ifndef __JIN_AUDIO_H
+#define __JIN_AUDIO_H
+
+
+namespace jin
+{
+namespace audio
+{
+
+
+
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/libjin/core/game.cpp b/src/libjin/core/game.cpp
new file mode 100644
index 0000000..1c47d87
--- /dev/null
+++ b/src/libjin/core/game.cpp
@@ -0,0 +1,14 @@
+#include "game.h"
+
+namespace jin
+{
+namespace core
+{
+
+ Game* Game::g_game = 0;
+
+ Game::Game() :run(true) {};
+
+}
+}
+
diff --git a/src/libjin/core/game.h b/src/libjin/core/game.h
new file mode 100644
index 0000000..d56b249
--- /dev/null
+++ b/src/libjin/core/game.h
@@ -0,0 +1,38 @@
+#ifndef __JIN_CORE_GAME_H
+#define __JIN_CORE_GAME_H
+
+namespace jin
+{
+namespace core
+{
+ class Game
+ {
+ public:
+
+ static inline Game* get()
+ {
+ return g_game ? g_game : (g_game = new Game());
+ }
+
+ inline void quit()
+ {
+ run = false;
+ }
+
+ inline bool running()
+ {
+ return run;
+ }
+
+ private:
+
+ Game();
+
+ static Game* g_game;
+
+ bool run;
+ };
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/libjin/fs/buffer.h b/src/libjin/fs/buffer.h
new file mode 100644
index 0000000..d727d84
--- /dev/null
+++ b/src/libjin/fs/buffer.h
@@ -0,0 +1,42 @@
+#include <string.h>
+
+namespace jin
+{
+namespace fs
+{
+
+ /**
+ * A file data buffer.
+ */
+ class Buffer
+ {
+ public:
+
+ inline Buffer(): data(0), size(0)
+ {
+ }
+
+ inline ~Buffer()
+ {
+ size = 0;
+ delete[] data;
+ }
+
+ inline Buffer(void* d, int size)
+ {
+ data = new char(size);
+ memcpy(data, d, size);
+ }
+
+ public:
+
+ // data position in memory
+ void* data;
+
+ // data buffer size
+ unsigned int size;
+
+ };
+
+}
+} \ No newline at end of file
diff --git a/src/libjin/fs/dirent.h b/src/libjin/fs/dirent.h
new file mode 100644
index 0000000..832b164
--- /dev/null
+++ b/src/libjin/fs/dirent.h
@@ -0,0 +1,951 @@
+/*
+* Dirent interface for Microsoft Visual Studio
+* Version 1.21
+*
+* Copyright (C) 2006-2012 Toni Ronkko
+* This file is part of dirent. Dirent may be freely distributed
+* under the MIT license. For all details and documentation, see
+* https://github.com/tronkko/dirent
+*/
+#ifndef DIRENT_H
+#define DIRENT_H
+
+/*
+* Include windows.h without Windows Sockets 1.1 to prevent conflicts with
+* Windows Sockets 2.0.
+*/
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <wchar.h>
+#include <string.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+/* Indicates that d_type field is available in dirent structure */
+#define _DIRENT_HAVE_D_TYPE
+
+/* Indicates that d_namlen field is available in dirent structure */
+#define _DIRENT_HAVE_D_NAMLEN
+
+/* Entries missing from MSVC 6.0 */
+#if !defined(FILE_ATTRIBUTE_DEVICE)
+# define FILE_ATTRIBUTE_DEVICE 0x40
+#endif
+
+/* File type and permission flags for stat(), general mask */
+#if !defined(S_IFMT)
+# define S_IFMT _S_IFMT
+#endif
+
+/* Directory bit */
+#if !defined(S_IFDIR)
+# define S_IFDIR _S_IFDIR
+#endif
+
+/* Character device bit */
+#if !defined(S_IFCHR)
+# define S_IFCHR _S_IFCHR
+#endif
+
+/* Pipe bit */
+#if !defined(S_IFFIFO)
+# define S_IFFIFO _S_IFFIFO
+#endif
+
+/* Regular file bit */
+#if !defined(S_IFREG)
+# define S_IFREG _S_IFREG
+#endif
+
+/* Read permission */
+#if !defined(S_IREAD)
+# define S_IREAD _S_IREAD
+#endif
+
+/* Write permission */
+#if !defined(S_IWRITE)
+# define S_IWRITE _S_IWRITE
+#endif
+
+/* Execute permission */
+#if !defined(S_IEXEC)
+# define S_IEXEC _S_IEXEC
+#endif
+
+/* Pipe */
+#if !defined(S_IFIFO)
+# define S_IFIFO _S_IFIFO
+#endif
+
+/* Block device */
+#if !defined(S_IFBLK)
+# define S_IFBLK 0
+#endif
+
+/* Link */
+#if !defined(S_IFLNK)
+# define S_IFLNK 0
+#endif
+
+/* Socket */
+#if !defined(S_IFSOCK)
+# define S_IFSOCK 0
+#endif
+
+/* Read user permission */
+#if !defined(S_IRUSR)
+# define S_IRUSR S_IREAD
+#endif
+
+/* Write user permission */
+#if !defined(S_IWUSR)
+# define S_IWUSR S_IWRITE
+#endif
+
+/* Execute user permission */
+#if !defined(S_IXUSR)
+# define S_IXUSR 0
+#endif
+
+/* Read group permission */
+#if !defined(S_IRGRP)
+# define S_IRGRP 0
+#endif
+
+/* Write group permission */
+#if !defined(S_IWGRP)
+# define S_IWGRP 0
+#endif
+
+/* Execute group permission */
+#if !defined(S_IXGRP)
+# define S_IXGRP 0
+#endif
+
+/* Read others permission */
+#if !defined(S_IROTH)
+# define S_IROTH 0
+#endif
+
+/* Write others permission */
+#if !defined(S_IWOTH)
+# define S_IWOTH 0
+#endif
+
+/* Execute others permission */
+#if !defined(S_IXOTH)
+# define S_IXOTH 0
+#endif
+
+/* Maximum length of file name */
+#if !defined(PATH_MAX)
+# define PATH_MAX MAX_PATH
+#endif
+#if !defined(FILENAME_MAX)
+# define FILENAME_MAX MAX_PATH
+#endif
+#if !defined(NAME_MAX)
+# define NAME_MAX FILENAME_MAX
+#endif
+
+/* File type flags for d_type */
+#define DT_UNKNOWN 0
+#define DT_REG S_IFREG
+#define DT_DIR S_IFDIR
+#define DT_FIFO S_IFIFO
+#define DT_SOCK S_IFSOCK
+#define DT_CHR S_IFCHR
+#define DT_BLK S_IFBLK
+#define DT_LNK S_IFLNK
+
+/* Macros for converting between st_mode and d_type */
+#define IFTODT(mode) ((mode) & S_IFMT)
+#define DTTOIF(type) (type)
+
+/*
+* File type macros. Note that block devices, sockets and links cannot be
+* distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
+* only defined for compatibility. These macros should always return false
+* on Windows.
+*/
+#if !defined(S_ISFIFO)
+# define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISDIR)
+# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG)
+# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISLNK)
+# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK)
+# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISCHR)
+# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISBLK)
+# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
+#endif
+
+/* Return the exact length of d_namlen without zero terminator */
+#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
+
+/* Return number of bytes needed to store d_namlen */
+#define _D_ALLOC_NAMLEN(p) (PATH_MAX)
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+ /* Wide-character version */
+ struct _wdirent {
+ /* Always zero */
+ long d_ino;
+
+ /* Structure size */
+ unsigned short d_reclen;
+
+ /* Length of name without \0 */
+ size_t d_namlen;
+
+ /* File type */
+ int d_type;
+
+ /* File name */
+ wchar_t d_name[PATH_MAX];
+ };
+ typedef struct _wdirent _wdirent;
+
+ struct _WDIR {
+ /* Current directory entry */
+ struct _wdirent ent;
+
+ /* Private file data */
+ WIN32_FIND_DATAW data;
+
+ /* True if data is valid */
+ int cached;
+
+ /* Win32 search handle */
+ HANDLE handle;
+
+ /* Initial directory name */
+ wchar_t *patt;
+ };
+ typedef struct _WDIR _WDIR;
+
+ static _WDIR *_wopendir(const wchar_t *dirname);
+ static struct _wdirent *_wreaddir(_WDIR *dirp);
+ static int _wclosedir(_WDIR *dirp);
+ static void _wrewinddir(_WDIR* dirp);
+
+
+ /* For compatibility with Symbian */
+#define wdirent _wdirent
+#define WDIR _WDIR
+#define wopendir _wopendir
+#define wreaddir _wreaddir
+#define wclosedir _wclosedir
+#define wrewinddir _wrewinddir
+
+
+ /* Multi-byte character versions */
+ struct dirent {
+ /* Always zero */
+ long d_ino;
+
+ /* Structure size */
+ unsigned short d_reclen;
+
+ /* Length of name without \0 */
+ size_t d_namlen;
+
+ /* File type */
+ int d_type;
+
+ /* File name */
+ char d_name[PATH_MAX];
+ };
+ typedef struct dirent dirent;
+
+ struct DIR {
+ struct dirent ent;
+ struct _WDIR *wdirp;
+ };
+ typedef struct DIR DIR;
+
+ static DIR *opendir(const char *dirname);
+ static struct dirent *readdir(DIR *dirp);
+ static int closedir(DIR *dirp);
+ static void rewinddir(DIR* dirp);
+
+
+ /* Internal utility functions */
+ static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp);
+ static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp);
+
+ static int dirent_mbstowcs_s(
+ size_t *pReturnValue,
+ wchar_t *wcstr,
+ size_t sizeInWords,
+ const char *mbstr,
+ size_t count);
+
+ static int dirent_wcstombs_s(
+ size_t *pReturnValue,
+ char *mbstr,
+ size_t sizeInBytes,
+ const wchar_t *wcstr,
+ size_t count);
+
+ static void dirent_set_errno(int error);
+
+ /*
+ * Open directory stream DIRNAME for read and return a pointer to the
+ * internal working area that is used to retrieve individual directory
+ * entries.
+ */
+ static _WDIR*
+ _wopendir(
+ const wchar_t *dirname)
+ {
+ _WDIR *dirp = NULL;
+ int error;
+
+ /* Must have directory name */
+ if (dirname == NULL || dirname[0] == '\0') {
+ dirent_set_errno(ENOENT);
+ return NULL;
+ }
+
+ /* Allocate new _WDIR structure */
+ dirp = (_WDIR*)malloc(sizeof(struct _WDIR));
+ if (dirp != NULL) {
+ DWORD n;
+
+ /* Reset _WDIR structure */
+ dirp->handle = INVALID_HANDLE_VALUE;
+ dirp->patt = NULL;
+ dirp->cached = 0;
+
+ /* Compute the length of full path plus zero terminator
+ *
+ * Note that on WinRT there's no way to convert relative paths
+ * into absolute paths, so just assume its an absolute path.
+ */
+# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
+ n = wcslen(dirname);
+# else
+ n = GetFullPathNameW(dirname, 0, NULL, NULL);
+# endif
+
+ /* Allocate room for absolute directory name and search pattern */
+ dirp->patt = (wchar_t*)malloc(sizeof(wchar_t) * n + 16);
+ if (dirp->patt) {
+
+ /*
+ * Convert relative directory name to an absolute one. This
+ * allows rewinddir() to function correctly even when current
+ * working directory is changed between opendir() and rewinddir().
+ *
+ * Note that on WinRT there's no way to convert relative paths
+ * into absolute paths, so just assume its an absolute path.
+ */
+# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
+ wcsncpy_s(dirp->patt, n + 1, dirname, n);
+# else
+ n = GetFullPathNameW(dirname, n, dirp->patt, NULL);
+# endif
+ if (n > 0) {
+ wchar_t *p;
+
+ /* Append search pattern \* to the directory name */
+ p = dirp->patt + n;
+ if (dirp->patt < p) {
+ switch (p[-1]) {
+ case '\\':
+ case '/':
+ case ':':
+ /* Directory ends in path separator, e.g. c:\temp\ */
+ /*NOP*/;
+ break;
+
+ default:
+ /* Directory name doesn't end in path separator */
+ *p++ = '\\';
+ }
+ }
+ *p++ = '*';
+ *p = '\0';
+
+ /* Open directory stream and retrieve the first entry */
+ if (dirent_first(dirp)) {
+ /* Directory stream opened successfully */
+ error = 0;
+ }
+ else {
+ /* Cannot retrieve first entry */
+ error = 1;
+ dirent_set_errno(ENOENT);
+ }
+
+ }
+ else {
+ /* Cannot retrieve full path name */
+ dirent_set_errno(ENOENT);
+ error = 1;
+ }
+
+ }
+ else {
+ /* Cannot allocate memory for search pattern */
+ error = 1;
+ }
+
+ }
+ else {
+ /* Cannot allocate _WDIR structure */
+ error = 1;
+ }
+
+ /* Clean up in case of error */
+ if (error && dirp) {
+ _wclosedir(dirp);
+ dirp = NULL;
+ }
+
+ return dirp;
+ }
+
+ /*
+ * Read next directory entry. The directory entry is returned in dirent
+ * structure in the d_name field. Individual directory entries returned by
+ * this function include regular files, sub-directories, pseudo-directories
+ * "." and ".." as well as volume labels, hidden files and system files.
+ */
+ static struct _wdirent*
+ _wreaddir(
+ _WDIR *dirp)
+ {
+ WIN32_FIND_DATAW *datap;
+ struct _wdirent *entp;
+
+ /* Read next directory entry */
+ datap = dirent_next(dirp);
+ if (datap) {
+ size_t n;
+ DWORD attr;
+
+ /* Pointer to directory entry to return */
+ entp = &dirp->ent;
+
+ /*
+ * Copy file name as wide-character string. If the file name is too
+ * long to fit in to the destination buffer, then truncate file name
+ * to PATH_MAX characters and zero-terminate the buffer.
+ */
+ n = 0;
+ while (n + 1 < PATH_MAX && datap->cFileName[n] != 0) {
+ entp->d_name[n] = datap->cFileName[n];
+ n++;
+ }
+ dirp->ent.d_name[n] = 0;
+
+ /* Length of file name excluding zero terminator */
+ entp->d_namlen = n;
+
+ /* File type */
+ attr = datap->dwFileAttributes;
+ if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
+ entp->d_type = DT_CHR;
+ }
+ else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+ entp->d_type = DT_DIR;
+ }
+ else {
+ entp->d_type = DT_REG;
+ }
+
+ /* Reset dummy fields */
+ entp->d_ino = 0;
+ entp->d_reclen = sizeof(struct _wdirent);
+
+ }
+ else {
+
+ /* Last directory entry read */
+ entp = NULL;
+
+ }
+
+ return entp;
+ }
+
+ /*
+ * Close directory stream opened by opendir() function. This invalidates the
+ * DIR structure as well as any directory entry read previously by
+ * _wreaddir().
+ */
+ static int
+ _wclosedir(
+ _WDIR *dirp)
+ {
+ int ok;
+ if (dirp) {
+
+ /* Release search handle */
+ if (dirp->handle != INVALID_HANDLE_VALUE) {
+ FindClose(dirp->handle);
+ dirp->handle = INVALID_HANDLE_VALUE;
+ }
+
+ /* Release search pattern */
+ if (dirp->patt) {
+ free(dirp->patt);
+ dirp->patt = NULL;
+ }
+
+ /* Release directory structure */
+ free(dirp);
+ ok = /*success*/0;
+
+ }
+ else {
+ /* Invalid directory stream */
+ dirent_set_errno(EBADF);
+ ok = /*failure*/-1;
+ }
+ return ok;
+ }
+
+ /*
+ * Rewind directory stream such that _wreaddir() returns the very first
+ * file name again.
+ */
+ static void
+ _wrewinddir(
+ _WDIR* dirp)
+ {
+ if (dirp) {
+ /* Release existing search handle */
+ if (dirp->handle != INVALID_HANDLE_VALUE) {
+ FindClose(dirp->handle);
+ }
+
+ /* Open new search handle */
+ dirent_first(dirp);
+ }
+ }
+
+ /* Get first directory entry (internal) */
+ static WIN32_FIND_DATAW*
+ dirent_first(
+ _WDIR *dirp)
+ {
+ WIN32_FIND_DATAW *datap;
+
+ /* Open directory and retrieve the first entry */
+ dirp->handle = FindFirstFileExW(
+ dirp->patt, FindExInfoStandard, &dirp->data,
+ FindExSearchNameMatch, NULL, 0);
+ if (dirp->handle != INVALID_HANDLE_VALUE) {
+
+ /* a directory entry is now waiting in memory */
+ datap = &dirp->data;
+ dirp->cached = 1;
+
+ }
+ else {
+
+ /* Failed to re-open directory: no directory entry in memory */
+ dirp->cached = 0;
+ datap = NULL;
+
+ }
+ return datap;
+ }
+
+ /* Get next directory entry (internal) */
+ static WIN32_FIND_DATAW*
+ dirent_next(
+ _WDIR *dirp)
+ {
+ WIN32_FIND_DATAW *p;
+
+ /* Get next directory entry */
+ if (dirp->cached != 0) {
+
+ /* A valid directory entry already in memory */
+ p = &dirp->data;
+ dirp->cached = 0;
+
+ }
+ else if (dirp->handle != INVALID_HANDLE_VALUE) {
+
+ /* Get the next directory entry from stream */
+ if (FindNextFileW(dirp->handle, &dirp->data) != FALSE) {
+ /* Got a file */
+ p = &dirp->data;
+ }
+ else {
+ /* The very last entry has been processed or an error occured */
+ FindClose(dirp->handle);
+ dirp->handle = INVALID_HANDLE_VALUE;
+ p = NULL;
+ }
+
+ }
+ else {
+
+ /* End of directory stream reached */
+ p = NULL;
+
+ }
+
+ return p;
+ }
+
+ /*
+ * Open directory stream using plain old C-string.
+ */
+ static DIR*
+ opendir(
+ const char *dirname)
+ {
+ struct DIR *dirp;
+ int error;
+
+ /* Must have directory name */
+ if (dirname == NULL || dirname[0] == '\0') {
+ dirent_set_errno(ENOENT);
+ return NULL;
+ }
+
+ /* Allocate memory for DIR structure */
+ dirp = (DIR*)malloc(sizeof(struct DIR));
+ if (dirp) {
+ wchar_t wname[PATH_MAX];
+ size_t n;
+
+ /* Convert directory name to wide-character string */
+ error = dirent_mbstowcs_s(&n, wname, PATH_MAX, dirname, PATH_MAX);
+ if (!error) {
+
+ /* Open directory stream using wide-character name */
+ dirp->wdirp = _wopendir(wname);
+ if (dirp->wdirp) {
+ /* Directory stream opened */
+ error = 0;
+ }
+ else {
+ /* Failed to open directory stream */
+ error = 1;
+ }
+
+ }
+ else {
+ /*
+ * Cannot convert file name to wide-character string. This
+ * occurs if the string contains invalid multi-byte sequences or
+ * the output buffer is too small to contain the resulting
+ * string.
+ */
+ error = 1;
+ }
+
+ }
+ else {
+ /* Cannot allocate DIR structure */
+ error = 1;
+ }
+
+ /* Clean up in case of error */
+ if (error && dirp) {
+ free(dirp);
+ dirp = NULL;
+ }
+
+ return dirp;
+ }
+
+ /*
+ * Read next directory entry.
+ *
+ * When working with text consoles, please note that file names returned by
+ * readdir() are represented in the default ANSI code page while any output to
+ * console is typically formatted on another code page. Thus, non-ASCII
+ * characters in file names will not usually display correctly on console. The
+ * problem can be fixed in two ways: (1) change the character set of console
+ * to 1252 using chcp utility and use Lucida Console font, or (2) use
+ * _cprintf function when writing to console. The _cprinf() will re-encode
+ * ANSI strings to the console code page so many non-ASCII characters will
+ * display correcly.
+ */
+ static struct dirent*
+ readdir(
+ DIR *dirp)
+ {
+ WIN32_FIND_DATAW *datap;
+ struct dirent *entp;
+
+ /* Read next directory entry */
+ datap = dirent_next(dirp->wdirp);
+ if (datap) {
+ size_t n;
+ int error;
+
+ /* Attempt to convert file name to multi-byte string */
+ error = dirent_wcstombs_s(
+ &n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX);
+
+ /*
+ * If the file name cannot be represented by a multi-byte string,
+ * then attempt to use old 8+3 file name. This allows traditional
+ * Unix-code to access some file names despite of unicode
+ * characters, although file names may seem unfamiliar to the user.
+ *
+ * Be ware that the code below cannot come up with a short file
+ * name unless the file system provides one. At least
+ * VirtualBox shared folders fail to do this.
+ */
+ if (error && datap->cAlternateFileName[0] != '\0') {
+ error = dirent_wcstombs_s(
+ &n, dirp->ent.d_name, PATH_MAX,
+ datap->cAlternateFileName, PATH_MAX);
+ }
+
+ if (!error) {
+ DWORD attr;
+
+ /* Initialize directory entry for return */
+ entp = &dirp->ent;
+
+ /* Length of file name excluding zero terminator */
+ entp->d_namlen = n - 1;
+
+ /* File attributes */
+ attr = datap->dwFileAttributes;
+ if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
+ entp->d_type = DT_CHR;
+ }
+ else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+ entp->d_type = DT_DIR;
+ }
+ else {
+ entp->d_type = DT_REG;
+ }
+
+ /* Reset dummy fields */
+ entp->d_ino = 0;
+ entp->d_reclen = sizeof(struct dirent);
+
+ }
+ else {
+ /*
+ * Cannot convert file name to multi-byte string so construct
+ * an errornous directory entry and return that. Note that
+ * we cannot return NULL as that would stop the processing
+ * of directory entries completely.
+ */
+ entp = &dirp->ent;
+ entp->d_name[0] = '?';
+ entp->d_name[1] = '\0';
+ entp->d_namlen = 1;
+ entp->d_type = DT_UNKNOWN;
+ entp->d_ino = 0;
+ entp->d_reclen = 0;
+ }
+
+ }
+ else {
+ /* No more directory entries */
+ entp = NULL;
+ }
+
+ return entp;
+ }
+
+ /*
+ * Close directory stream.
+ */
+ static int
+ closedir(
+ DIR *dirp)
+ {
+ int ok;
+ if (dirp) {
+
+ /* Close wide-character directory stream */
+ ok = _wclosedir(dirp->wdirp);
+ dirp->wdirp = NULL;
+
+ /* Release multi-byte character version */
+ free(dirp);
+
+ }
+ else {
+
+ /* Invalid directory stream */
+ dirent_set_errno(EBADF);
+ ok = /*failure*/-1;
+
+ }
+ return ok;
+ }
+
+ /*
+ * Rewind directory stream to beginning.
+ */
+ static void
+ rewinddir(
+ DIR* dirp)
+ {
+ /* Rewind wide-character string directory stream */
+ _wrewinddir(dirp->wdirp);
+ }
+
+ /* Convert multi-byte string to wide character string */
+ static int
+ dirent_mbstowcs_s(
+ size_t *pReturnValue,
+ wchar_t *wcstr,
+ size_t sizeInWords,
+ const char *mbstr,
+ size_t count)
+ {
+ int error;
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+
+ /* Microsoft Visual Studio 2005 or later */
+ error = mbstowcs_s(pReturnValue, wcstr, sizeInWords, mbstr, count);
+
+#else
+
+ /* Older Visual Studio or non-Microsoft compiler */
+ size_t n;
+
+ /* Convert to wide-character string (or count characters) */
+ n = mbstowcs(wcstr, mbstr, sizeInWords);
+ if (!wcstr || n < count) {
+
+ /* Zero-terminate output buffer */
+ if (wcstr && sizeInWords) {
+ if (n >= sizeInWords) {
+ n = sizeInWords - 1;
+ }
+ wcstr[n] = 0;
+ }
+
+ /* Length of resuting multi-byte string WITH zero terminator */
+ if (pReturnValue) {
+ *pReturnValue = n + 1;
+ }
+
+ /* Success */
+ error = 0;
+
+ }
+ else {
+
+ /* Could not convert string */
+ error = 1;
+
+ }
+
+#endif
+
+ return error;
+ }
+
+ /* Convert wide-character string to multi-byte string */
+ static int
+ dirent_wcstombs_s(
+ size_t *pReturnValue,
+ char *mbstr,
+ size_t sizeInBytes, /* max size of mbstr */
+ const wchar_t *wcstr,
+ size_t count)
+ {
+ int error;
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+
+ /* Microsoft Visual Studio 2005 or later */
+ error = wcstombs_s(pReturnValue, mbstr, sizeInBytes, wcstr, count);
+
+#else
+
+ /* Older Visual Studio or non-Microsoft compiler */
+ size_t n;
+
+ /* Convert to multi-byte string (or count the number of bytes needed) */
+ n = wcstombs(mbstr, wcstr, sizeInBytes);
+ if (!mbstr || n < count) {
+
+ /* Zero-terminate output buffer */
+ if (mbstr && sizeInBytes) {
+ if (n >= sizeInBytes) {
+ n = sizeInBytes - 1;
+ }
+ mbstr[n] = '\0';
+ }
+
+ /* Length of resulting multi-bytes string WITH zero-terminator */
+ if (pReturnValue) {
+ *pReturnValue = n + 1;
+ }
+
+ /* Success */
+ error = 0;
+
+ }
+ else {
+
+ /* Cannot convert string */
+ error = 1;
+
+ }
+
+#endif
+
+ return error;
+ }
+
+ /* Set errno variable */
+ static void
+ dirent_set_errno(
+ int error)
+ {
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+
+ /* Microsoft Visual Studio 2005 and later */
+ _set_errno(error);
+
+#else
+
+ /* Non-Microsoft compiler or older Microsoft compiler */
+ errno = error;
+
+#endif
+ }
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*DIRENT_H*/
+
diff --git a/src/libjin/fs/filesystem.cpp b/src/libjin/fs/filesystem.cpp
new file mode 100644
index 0000000..72f1144
--- /dev/null
+++ b/src/libjin/fs/filesystem.cpp
@@ -0,0 +1,68 @@
+#include "filesystem.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h> /* defines FILENAME_MAX */
+
+namespace jin
+{
+namespace fs
+{
+
+ Filesystem* Filesystem::fs = 0;
+
+ Filesystem::Filesystem()
+ {
+ S = sm_newshared();
+ }
+
+ Filesystem* Filesystem::get()
+ {
+ return fs ? fs : (fs = new Filesystem());
+ }
+
+ /**
+ * r is relative path
+ */
+ void Filesystem::mount(const char * path)
+ {
+ int err = sm_mount(S, path);
+ if (err)
+ {
+ printf("%s mounted path %s", sm_errstr(err), path);
+ exit(1);
+ }
+ }
+
+ /**
+ *
+ */
+ int Filesystem::read(const char* path, Buffer* buffer)
+ {
+ buffer->data = sm_read(S, path, &buffer->size);
+ if (buffer->data == 0)
+ return 0;
+ return 1;
+ }
+
+ const char* Filesystem::getFull(const char* path)
+ {
+ return sm_fullpath(S, path);
+ }
+
+ bool Filesystem::isDir(const char* path)
+ {
+ return sm_isdir(S, path);
+ }
+
+ bool Filesystem::isFile(const char* path)
+ {
+ return sm_isreg(S, path);
+ }
+
+ bool Filesystem::exists(const char* path)
+ {
+ return sm_exists(S, path) == 0;
+ }
+
+}
+} \ No newline at end of file
diff --git a/src/libjin/fs/filesystem.h b/src/libjin/fs/filesystem.h
new file mode 100644
index 0000000..8c8ef04
--- /dev/null
+++ b/src/libjin/fs/filesystem.h
@@ -0,0 +1,55 @@
+#include "buffer.h"
+#include "3rdparty/smount/smount.h"
+
+namespace jin
+{
+namespace fs
+{
+
+ class Filesystem
+ {
+ public:
+
+ Filesystem();
+
+ static Filesystem* get();
+
+ /**
+ * is a path a directroy or a single file
+ */
+ bool isDir(const char* path);
+
+ /**
+ * is a path a directroy or a single file
+ */
+ bool isFile(const char* path);
+
+ /**
+ * is path a valid path
+ */
+ bool exists(const char* path);
+
+ /**
+ * read a file and return data buffer
+ */
+ int read(const char* path, Buffer* buffer);
+
+ /**
+ * set root directory, can only mount once.
+ */
+ void mount(const char* root);
+
+ /**
+ * convret relative path to absolute path
+ */
+ const char* getFull(const char* path);
+
+ private:
+
+ static Filesystem* fs;
+
+ sm_Shared* S;
+
+ };
+}
+} \ No newline at end of file
diff --git a/src/libjin/input/event.cpp b/src/libjin/input/event.cpp
new file mode 100644
index 0000000..8eb45e6
--- /dev/null
+++ b/src/libjin/input/event.cpp
@@ -0,0 +1,7 @@
+#include "event.h"
+#include "SDL2\SDL.h"
+
+namespace jin
+{
+
+} \ No newline at end of file
diff --git a/src/libjin/input/event.h b/src/libjin/input/event.h
new file mode 100644
index 0000000..e09f422
--- /dev/null
+++ b/src/libjin/input/event.h
@@ -0,0 +1,13 @@
+#ifndef __JIN_EVENT_H
+#define __JIN_EVENT_H
+namespace jin
+{
+namespace input
+{
+
+
+
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/libjin/input/keyboard.cpp b/src/libjin/input/keyboard.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/libjin/input/keyboard.cpp
diff --git a/src/libjin/input/keyboard.h b/src/libjin/input/keyboard.h
new file mode 100644
index 0000000..bbb6456
--- /dev/null
+++ b/src/libjin/input/keyboard.h
@@ -0,0 +1,13 @@
+#ifndef __JIN_KEYBOARD_H
+#define __JIN_KEYBOARD_H
+namespace jin
+{
+namespace input
+{
+ class Keyboard
+ {
+
+ };
+}
+}
+#endif \ No newline at end of file
diff --git a/src/libjin/input/mouse.cpp b/src/libjin/input/mouse.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/libjin/input/mouse.cpp
diff --git a/src/libjin/input/mouse.h b/src/libjin/input/mouse.h
new file mode 100644
index 0000000..55e3346
--- /dev/null
+++ b/src/libjin/input/mouse.h
@@ -0,0 +1,30 @@
+#ifndef __JIN_MOUSE_H
+#define __JIN_MOUSE_H
+namespace jin
+{
+namespace input
+{
+ class Mouse
+ {
+ public:
+
+ };
+
+ inline const char* buttonStr(int id) {
+ switch (id) {
+ case 1: return "left";
+ case 2: return "middle";
+ case 3: return "right";
+ case 4: return "wheelup";
+ case 5: return "wheeldown";
+ default: return "?";
+ }
+ }
+
+ inline const char* wheelStr(int dir)
+ {
+
+ }
+}
+}
+#endif \ No newline at end of file
diff --git a/src/libjin/net/net.h b/src/libjin/net/net.h
new file mode 100644
index 0000000..6b86a45
--- /dev/null
+++ b/src/libjin/net/net.h
@@ -0,0 +1,6 @@
+#ifndef __JIN_NET_H
+#define __JIN_NET_H
+
+
+
+#endif \ No newline at end of file
diff --git a/src/libjin/render/canvas.cpp b/src/libjin/render/canvas.cpp
new file mode 100644
index 0000000..494b0fa
--- /dev/null
+++ b/src/libjin/render/canvas.cpp
@@ -0,0 +1,123 @@
+#include "utils/macros.h"
+#include "canvas.h"
+#include "window.h"
+
+namespace jin
+{
+namespace render
+{
+ Canvas::Canvas() :Drawable()
+ {
+ }
+
+ Canvas::~Canvas()
+ {
+ }
+
+ // no canvas has binded
+ shared GLint Canvas::cur = -1;
+
+ bool Canvas::init(int w, int h)
+ {
+ Drawable::init(w, h);
+ Drawable::setVertices(
+ new float [DRAWABLE_V_SIZE] {
+ 0, 0,
+ 0, (float)h,
+ (float)w, (float)h,
+ (float)w, 0,
+ },
+ new float [DRAWABLE_V_SIZE] {
+ 0, 1,
+ 0, 0,
+ 1, 0,
+ 1, 1
+ }
+ );
+
+ GLint current_fbo;
+ glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &current_fbo);
+
+ // generate a new render buffer object
+ glGenFramebuffers(1, &fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ // generate texture save target
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ // unbind framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+ return false;
+ return true;
+ }
+
+ bool Canvas::hasbind(GLint fbo)
+ {
+ return cur == fbo;
+ }
+
+ /**
+ * bind to canvas
+ */
+ void Canvas::bind()
+ {
+ if (hasbind(fbo)) return;
+
+ cur = fbo;
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glViewport(0, 0, width, height);
+ glOrtho(0, width, height, 0, -1, 1);
+
+ // Switch back to modelview matrix
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ }
+
+ /**
+ * bind to default screen render buffer.
+ */
+ shared void Canvas::unbind()
+ {
+ if (hasbind(0)) return;
+
+ cur = 0;
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ Window* wnd = Window::get();
+ int ww = wnd->getW(),
+ wh = wnd->getH();
+
+ glViewport(0, 0, ww, wh);
+
+ // load back to normal
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ // set viewport matrix
+ glOrtho(0, ww, wh, 0, -1, 1);
+
+ // switch to model matrix
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ }
+}
+} \ No newline at end of file
diff --git a/src/libjin/render/canvas.h b/src/libjin/render/canvas.h
new file mode 100644
index 0000000..4600f8b
--- /dev/null
+++ b/src/libjin/render/canvas.h
@@ -0,0 +1,33 @@
+#ifndef __JIN_CANVAS_H
+#define __JIN_CANVAS_H
+#include "drawable.h"
+namespace jin
+{
+namespace render
+{
+ class Canvas: public Drawable
+ {
+ public:
+
+ Canvas();
+ ~Canvas();
+
+ bool init(int w, int h);
+
+ void bind();
+
+ static void unbind();
+
+ static bool hasbind(GLint fbo);
+
+ private:
+
+ GLuint fbo;
+
+ // current binded fbo
+ static GLint cur;
+ };
+}
+}// jin
+
+#endif
diff --git a/src/libjin/render/color.h b/src/libjin/render/color.h
new file mode 100644
index 0000000..dfb02e1
--- /dev/null
+++ b/src/libjin/render/color.h
@@ -0,0 +1,27 @@
+/**
+* Some color operating here.
+*/
+#ifndef __JIN_COLOR_H
+#define __JIN_COLOR_H
+#include "utils/endian.h"
+
+namespace jin
+{
+namespace render
+{
+
+ union color {
+ struct {
+#if JIN_BYTEORDER == JIN_BIG_ENDIAN
+ unsigned char r, g, b, a;
+#else
+ unsigned char a, b, g, r;
+#endif
+ }rgba;
+ int word;
+ };
+
+}
+}
+
+#endif
diff --git a/src/libjin/render/drawable.cpp b/src/libjin/render/drawable.cpp
new file mode 100644
index 0000000..45d6044
--- /dev/null
+++ b/src/libjin/render/drawable.cpp
@@ -0,0 +1,92 @@
+#include "drawable.h"
+#include "utils/matrix.h"
+#include <stdlib.h>
+namespace jin
+{
+namespace render
+{
+ Drawable::Drawable():texture(0), width(0), height(0), ancx(0), ancy(0), textCoord(0), vertCoord(0)
+ {
+ }
+
+ Drawable::~Drawable()
+ {
+ glDeleteTextures(1, &texture);
+ delete[] vertCoord;
+ delete[] textCoord;
+ }
+
+ void Drawable::init(int w, int h)
+ {
+ texture = 0;
+ width = w;
+ height = h;
+ ancx = 0;
+ ancy = 0;
+ textCoord = 0;
+ vertCoord = 0;
+ }
+
+ void Drawable::setVertices(float* v, float* t)
+ {
+ // render area
+ if (vertCoord)
+ delete[] vertCoord;
+ vertCoord = v;
+
+ // textrue
+ if (textCoord)
+ delete[] textCoord;
+ textCoord = t;
+ }
+
+ void Drawable::setAnchor(int x, int y)
+ {
+ ancx = x;
+ ancy = y;
+ }
+
+ int Drawable::getWidth()
+ {
+ return width;
+ }
+
+ int Drawable::getHeight()
+ {
+ return height;
+ }
+
+ void Drawable::draw(int x, int y, float sx, float sy, float r)
+ {
+ // Must set textCoord and vertCoord before renderring
+ if (! textCoord||! vertCoord) return;
+
+ static jin::util::Matrix t;
+ t.setTransformation(x, y, r, sx, sy, ancx, ancy);
+
+ glEnable(GL_TEXTURE_2D);
+
+ glBindTexture(GL_TEXTURE_2D, texture);
+
+ // push modle matrix
+ glPushMatrix();
+ glMultMatrixf((const GLfloat*)t.getElements());
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 0, textCoord);
+ glVertexPointer(2, GL_FLOAT, 0, vertCoord);
+ glDrawArrays(GL_QUADS, 0, 4);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ // pop the model matrix
+ glPopMatrix();
+
+ // bind texture to default screen
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ glDisable(GL_TEXTURE_2D);
+ }
+}
+}
diff --git a/src/libjin/render/drawable.h b/src/libjin/render/drawable.h
new file mode 100644
index 0000000..5eaf705
--- /dev/null
+++ b/src/libjin/render/drawable.h
@@ -0,0 +1,47 @@
+#ifndef __JIN_DRAWABLE
+#define __JIN_DRAWABLE
+#include "3rdparty/GLee/GLee.h"
+namespace jin
+{
+namespace render
+{
+ class Drawable
+ {
+ public:
+
+ Drawable();
+ virtual ~Drawable();
+
+ /* pseudo constructor*/
+ void init(int w = 0, int h = 0);
+
+ /* set anchor of texture, (0, 0) by default */
+ void setAnchor(int x, int y);
+
+ void draw(int x, int y, float sx, float sy, float r);
+
+ int getWidth();
+ int getHeight();
+
+ inline GLuint getTexture() const { return texture; };
+
+ protected:
+#define DRAWABLE_V_SIZE 8
+ void setVertices(float* v, float* t);
+
+ GLuint texture;
+
+ int width, height;
+
+ /* anchor point */
+ int ancx, ancy;
+
+ // render coords
+ float* textCoord;
+ float* vertCoord;
+
+ };
+}
+}// jin
+
+#endif
diff --git a/src/libjin/render/font.cpp b/src/libjin/render/font.cpp
new file mode 100644
index 0000000..287e0c0
--- /dev/null
+++ b/src/libjin/render/font.cpp
@@ -0,0 +1,189 @@
+#include "font.h"
+
+#include <stdio.h>
+
+#define STB_TRUETYPE_IMPLEMENTATION
+#include "3rdparty/stb/stb_truetype.h"
+#include "color.h"
+
+namespace jin
+{
+namespace render
+{
+
+#define BITMAP_WIDTH 512
+#define BITMAP_HEIGHT 512
+#define PIXEL_HEIGHT 32
+
+ Font::Font():Drawable()
+ {
+ }
+
+ // ttf file read buffer
+ static unsigned char ttf_buffer[1 << 20];
+
+ // bitmap for saving font data
+ static unsigned char temp_bitmap[BITMAP_WIDTH * BITMAP_HEIGHT];
+
+ void Font::loadf(const char* path)
+ {
+ fread(ttf_buffer, 1, 1 << 20, fopen(path, "rb"));
+
+ loadb(ttf_buffer);
+ }
+
+ /**
+ * load from memory
+ */
+ void Font::loadb(const unsigned char* data)
+ {
+ stbtt_BakeFontBitmap(data, 0, PIXEL_HEIGHT, temp_bitmap, BITMAP_WIDTH, BITMAP_HEIGHT, 32, 96, cdata);
+
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, BITMAP_WIDTH,
+ BITMAP_HEIGHT, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ /**
+ * get texture quad
+ */
+ static Quad getCharQuad(const stbtt_bakedchar* chardata, int pw, int ph, int char_index)
+ {
+ float ipw = 1.0f / pw, iph = 1.0f / ph;
+ const stbtt_bakedchar *b = chardata + char_index;
+ Quad q;
+ q.x = b->x0 * ipw;
+ q.y = b->y0 * iph;
+ q.w = b->x1 * ipw - b->x0 * ipw;
+ q.h = b->y1 * iph - b->y0 * iph;
+ return q;
+ }
+
+ /**
+ * render function draw mutiple times
+ * in loop
+ */
+ void Font::render(
+ const char* text, // rendered text
+ float x, float y, // render position
+ int fheight, // font height
+ int spacing, // font spacing
+ int lheight) // line height
+ {
+ float _x = x,
+ _y = y;
+
+ int len = strlen(text);
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, texture);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ // for saving clip quad
+ stbtt_aligned_quad q;
+
+ // render every given character
+ int xc = x;
+ int yc = y;
+
+ float factor = fheight / (float)PIXEL_HEIGHT;
+
+ for (int i = 0; i < len; ++i)
+ {
+ char c = text[i];
+ if (c == '\n')
+ {
+ xc = x;
+ yc += lheight;
+ continue;
+ }
+
+ // only support ASCII
+ Quad q = getCharQuad(cdata, 512, 512, c - 32);
+ float s0 = q.x,
+ s1 = q.x + q.w,
+ t0 = q.y,
+ t1 = q.y + q.h;
+
+ // texture quad
+ float tc[] = {
+ s0, t1,
+ s1, t1,
+ s1, t0,
+ s0, t0
+ };
+
+ // character bound box
+ stbtt_bakedchar box = cdata[c - 32];
+
+ float width = factor * (box.x1 - box.x0);
+ float height = factor * (box.y1 - box.y0);
+ float xoffset = factor * box.xoff;
+ // I don't know why add PIXEL_HEIGHT to box.yoff, but
+ // it works.
+ float yoffset = factor * (box.yoff + PIXEL_HEIGHT);
+ float xadvance = factor * box.xadvance;
+
+ // render quad
+ float vc[] = {
+ xc + xoffset, yc + height + yoffset,
+ xc + width + xoffset, yc + height + yoffset,
+ xc + width + xoffset, yc + yoffset,
+ xc + xoffset, yc + yoffset
+ };
+
+ // forward to next character
+ xc += xadvance + spacing;
+
+ glTexCoordPointer(2, GL_FLOAT, 0, tc);
+ glVertexPointer(2, GL_FLOAT, 0, vc);
+ glDrawArrays(GL_QUADS, 0, 4);
+ }
+
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_TEXTURE_2D);
+ }
+
+ void Font::box(const char* str, int fheight, int spacing, int lheight, int* w, int * h)
+ {
+ int len = strlen(str);
+
+ float xc = 0;
+ int yc = len ? lheight: 0;
+ int maxX = 0;
+
+ float factor = fheight / (float)PIXEL_HEIGHT;
+
+ for (int i = 0; i < len; ++i)
+ {
+ char c = str[i];
+ if (c == '\n')
+ {
+ yc += lheight;
+ xc = 0;
+ continue;
+ }
+ stbtt_bakedchar box = cdata[c - 32];
+
+ xc += factor * box.xadvance + spacing;
+ if (xc > maxX) maxX = xc;
+ }
+
+ *w = maxX;
+ *h = yc;
+ }
+
+}
+} \ No newline at end of file
diff --git a/src/libjin/render/font.h b/src/libjin/render/font.h
new file mode 100644
index 0000000..98a41b4
--- /dev/null
+++ b/src/libjin/render/font.h
@@ -0,0 +1,58 @@
+#ifndef __JIN_FONT_H
+#define __JIN_FONT_H
+
+#include "drawable.h"
+#include "3rdparty/stb/stb_truetype.h"
+#include "quad.h"
+
+namespace jin
+{
+namespace render
+{
+ /**
+ * Usage of stb_truetype.h here might be a little
+ * bit dummy. Implementation of Font is referring
+ * to stb_truetype.h L243~284. I basicly copy it:)
+ */
+ class Font: public Drawable
+ {
+ public:
+
+ Font();
+
+ /**
+ * load ttf font data from .ttf
+ */
+ void loadf(const char* file);
+
+ /**
+ * load ttf font data from memory
+ */
+ void loadb(const unsigned char* data);
+
+ /**
+ * render text to screen
+ */
+ void render(
+ const char* str, // rendered text
+ float x, float y, // render position
+ int fheight, // font size
+ int spacing, // font spacing
+ int lheight // line height
+ );
+
+ void box(const char* str, int fheight, int spacing, int lheight, int* w, int * h);
+
+ private:
+
+ /**
+ * ASCII 32(space)..126(~) is 95 glyphs
+ */
+ stbtt_bakedchar cdata[96];
+
+ };
+
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/libjin/render/graphics.cpp b/src/libjin/render/graphics.cpp
new file mode 100644
index 0000000..15d8a9c
--- /dev/null
+++ b/src/libjin/render/graphics.cpp
@@ -0,0 +1,115 @@
+#include "graphics.h"
+#include "utils/math.h"
+#include <string>
+namespace jin
+{
+namespace render
+{
+
+ void point(int x, int y)
+ {
+ float vers[] = { x + 0.5f , y + 0.5f };
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, (GLvoid*)vers);
+ glDrawArrays(GL_POINTS, 0, 1);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ }
+
+ void points(int n, GLshort* p)
+ {
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ glVertexPointer(2, GL_SHORT, 0, (GLvoid*)p);
+ glDrawArrays(GL_POINTS, 0, n);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ }
+
+ void line(int x1, int y1, int x2, int y2)
+ {
+ glDisable(GL_TEXTURE_2D);
+ float verts[] = {
+ x1, y1,
+ x2, y2
+ };
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, (GLvoid*)verts);
+ glDrawArrays(GL_LINES, 0, 2);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ }
+
+ void circle(RENDER_MODE mode, int x, int y, int r)
+ {
+ r = r < 0 ? 0 : r;
+
+ int points = 40;
+ float two_pi = static_cast<float>(PI * 2);
+ if (points <= 0) points = 1;
+ float angle_shift = (two_pi / points);
+ float phi = .0f;
+
+ float *coords = new float[2 * (points + 1)];
+ for (int i = 0; i < points; ++i, phi += angle_shift)
+ {
+ coords[2 * i] = x + r * cos(phi);
+ coords[2 * i + 1] = y + r * sin(phi);
+ }
+
+ coords[2 * points] = coords[0];
+ coords[2 * points + 1] = coords[1];
+
+ polygon(mode, coords, points);
+
+ delete[] coords;
+ }
+
+ void rect(RENDER_MODE mode, int x, int y, int w, int h)
+ {
+ float coords[] = { x, y, x + w, y, x + w, y + h, x, y + h };
+ polygon(mode, coords, 4);
+ }
+
+ void triangle(RENDER_MODE mode, int x1, int y1, int x2, int y2, int x3, int y3)
+ {
+ float coords[] = { x1, y1, x2, y2, x3, y3 };
+ polygon(mode, coords, 3);
+ }
+
+ void polygon_line(float* p, int count)
+ {
+ float* verts = new float[count * 4];
+ for (int i = 0; i < count; ++i)
+ {
+ // each line has two point n,n+1
+ verts[i * 4] = p[i * 2];
+ verts[i * 4 + 1] = p[i * 2 + 1];
+ verts[i * 4 + 2] = p[(i + 1) % count * 2];
+ verts[i * 4 + 3] = p[(i + 1) % count * 2 + 1];
+ }
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, (GLvoid*)verts);
+ glDrawArrays(GL_LINES, 0, count * 2);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ delete[] verts;
+ }
+
+ void polygon(RENDER_MODE mode, float* p, int count)
+ {
+ if (mode == LINE)
+ {
+ polygon_line(p, count);
+ }
+ else if (mode == FILL)
+ {
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, (const GLvoid*)p);
+ glDrawArrays(GL_POLYGON, 0, count);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ }
+ }
+
+}
+}
diff --git a/src/libjin/render/graphics.h b/src/libjin/render/graphics.h
new file mode 100644
index 0000000..242b19d
--- /dev/null
+++ b/src/libjin/render/graphics.h
@@ -0,0 +1,37 @@
+#ifndef __JIN_GRAPHICS_H
+#define __JIN_GRAPHICS_H
+
+#include "color.h"
+#include "canvas.h"
+#include "image.h"
+
+namespace jin
+{
+namespace render
+{
+ typedef enum {
+ NONE = 0,
+ FILL ,
+ LINE
+ }RENDER_MODE;
+
+ /**
+ * TODO:
+ * drawPixels(int n, points)
+ */
+ extern void line(int x1, int y1, int x2, int y2);
+
+ extern void rect(RENDER_MODE mode, int x, int y, int w, int h);
+
+ extern void triangle(RENDER_MODE mode, int x1, int y1, int x2, int y2, int x3, int y3);
+
+ extern void circle(RENDER_MODE mode, int x, int y, int r);
+
+ extern void point(int x, int y);
+
+ extern void points(int n, GLshort* p, GLubyte* c);
+
+ extern void polygon(RENDER_MODE mode, float* p, int count);
+}
+}
+#endif
diff --git a/src/libjin/render/image.cpp b/src/libjin/render/image.cpp
new file mode 100644
index 0000000..ac5947a
--- /dev/null
+++ b/src/libjin/render/image.cpp
@@ -0,0 +1,97 @@
+#include "image.h"
+#include "3rdparty/stb/stb_image.h"
+#include "utils/utils.h"
+namespace jin
+{
+namespace render
+{
+ Image::Image(): Drawable(), pixels(0)
+ {
+ }
+
+ Image::~Image()
+ {
+ stbi_image_free(pixels);
+ }
+
+ void Image::init()
+ {
+ Drawable::init();
+ pixels = 0;
+ }
+
+ color Image::getPixel(int x, int y)
+ {
+ if (without(x, 0, width) || without(y, 0, height))
+ {
+ return { 0 };
+ }
+ return pixels[x + y * width];
+ }
+
+ bool Image::loadf(const char* f)
+ {
+ unsigned char* imageData = stbi_load(f, &width, &height, NULL, STBI_rgb_alpha);
+ if (imageData == 0) return false;
+ pixels = (color*)imageData;
+
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width,
+ height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
+
+ // set render vertices
+ Drawable::setVertices(
+ new float [DRAWABLE_V_SIZE] {
+ 0, 0,
+ 0, (float)height,
+ (float)width, (float)height,
+ (float)width, 0,
+ },
+ new float [DRAWABLE_V_SIZE] {
+ 0, 0,
+ 0, 1,
+ 1, 1,
+ 1, 0
+ }
+ );
+
+ return true;
+ }
+
+ bool Image::loadb(const char* b, int size)
+ {
+ // ʹstbi_load_from_memory
+ unsigned char* imageData = stbi_load_from_memory((unsigned char *)b, size, &width, &height, NULL, STBI_rgb_alpha);
+ if (imageData == 0) return false;
+ pixels = (color*)imageData;
+
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width,
+ height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
+
+ // set render vertices
+ Drawable::setVertices(
+ new float [DRAWABLE_V_SIZE] {
+ 0, 0,
+ 0, (float)height,
+ (float)width, (float)height,
+ (float)width, 0,
+ },
+ new float [DRAWABLE_V_SIZE] {
+ 0, 0,
+ 0, 1,
+ 1, 1,
+ 1, 0
+ }
+ );
+
+ return true;
+ }
+}
+} \ No newline at end of file
diff --git a/src/libjin/render/image.h b/src/libjin/render/image.h
new file mode 100644
index 0000000..7375fc4
--- /dev/null
+++ b/src/libjin/render/image.h
@@ -0,0 +1,34 @@
+#ifndef __JIN_IMAGE_H
+#define __JIN_IMAGE_H
+#include "3rdparty/GLee/GLee.h"
+#include "color.h"
+#include "drawable.h"
+namespace jin
+{
+namespace render
+{
+ class Image: public Drawable
+ {
+ public:
+ Image();
+ ~Image();
+
+ // just like Image()
+ void init();
+
+ // load from file
+ bool loadf(const char* f);
+
+ // load from memory
+ bool loadb(const char* b, int size);
+
+ color getPixel(int x, int y);
+
+ private:
+
+ color* pixels;
+ };
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/libjin/render/jsl.cpp b/src/libjin/render/jsl.cpp
new file mode 100644
index 0000000..6fcee53
--- /dev/null
+++ b/src/libjin/render/jsl.cpp
@@ -0,0 +1,84 @@
+#include "utils/macros.h"
+#include "jsl.h"
+namespace jin
+{
+namespace render
+{
+ //vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords)
+ static const char* base_f = " "
+ "#version 120 \n"
+ "#define number float \n"
+ "#define Image sampler2D \n"
+ "#define Texel texture2D \n"
+ "#define extern uniform \n"
+ "uniform sampler2D _tex0_; \n"
+ "%s \n"
+ "void main(){ \n"
+ "gl_FragColor = effect(gl_Color, _tex0_, gl_TexCoord[0].xy, gl_FragCoord.xy);\n"
+ "}\0";
+
+ void JSLProgram::init(const char* program)
+ {
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &_max_texture_units);
+
+ char* fs = (char*)alloca(strlen(program) + strlen(base_f));
+ sprintf(fs, base_f, program);
+ GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fragmentShader, 1, (const GLchar**)&fs, NULL);
+ glCompileShader(fragmentShader);
+
+ pid = glCreateProgram();
+ glAttachShader(pid, fragmentShader);
+ glLinkProgram(pid);
+ }
+
+ shared std::map<std::string, GLint> JSLProgram::_texture_unit_pool;
+ shared GLint JSLProgram::_current_texture_unit = 0;
+ shared GLint JSLProgram::_max_texture_units = 0;
+
+ shared GLint JSLProgram::getTextureUnit(const std::string& name)
+ {
+ std::map<std::string, GLint>::const_iterator it = _texture_unit_pool.find(name);
+
+ if (it != _texture_unit_pool.end())
+ return it->second;
+
+ if (++_current_texture_unit >= _max_texture_units)
+ return 0;
+
+ _texture_unit_pool[name] = _current_texture_unit;
+ return _current_texture_unit;
+ }
+
+ void JSLProgram::use()
+ {
+ glUseProgram(pid);
+ }
+
+ shared void JSLProgram::unuse()
+ {
+ glUseProgram(0);
+ }
+
+ void JSLProgram::sendFloat(const char* variable, float number)
+ {
+ int loc = glGetUniformLocation(pid, variable);
+ glUniform1f(loc, number);
+ }
+
+ void JSLProgram::sendImage(const char* variable, const Image* image)
+ {
+ GLint texture_unit = getTextureUnit(variable);
+
+ GLint location = glGetUniformLocation(pid, variable);
+
+ glActiveTexture(GL_TEXTURE0 + texture_unit);
+ glBindTexture(GL_TEXTURE_2D, image->getTexture()); // guarantee it gets bound
+ glUniform1i(location, texture_unit);
+
+ // reset texture unit
+ glActiveTexture(GL_TEXTURE0);
+ }
+
+}
+}
diff --git a/src/libjin/render/jsl.h b/src/libjin/render/jsl.h
new file mode 100644
index 0000000..570235b
--- /dev/null
+++ b/src/libjin/render/jsl.h
@@ -0,0 +1,44 @@
+#ifndef __JIN_JSL_H
+#define __JIN_JSL_H
+#include <string>
+#include <map>
+#include "image.h"
+#include "3rdparty/GLee/GLee.h"
+namespace jin
+{
+namespace render
+{
+ /**
+ * A JSL program for shadering textures which is
+ * actually a glsl program.
+ */
+ class JSLProgram
+ {
+ public:
+
+ void init(const char* program);
+
+ void use();
+
+ static void unuse();
+
+ void sendFloat(const char* name, float number);
+ void sendImage(const char* name, const Image* image);
+ //void sendMatrix(const char* name, int size, const GLfloat* m, int count);
+ //void sendCanvas(const char* name, const Canvas& canvas);
+
+ private:
+ JSLProgram();
+
+ // only id for identify glsl program
+ GLuint pid;
+
+ static GLint _current_texture_unit;
+ static GLint _max_texture_units;
+ static std::map<std::string, GLint> _texture_unit_pool;
+ static GLint getTextureUnit(const std::string& name);
+ };
+}
+}
+
+#endif
diff --git a/src/libjin/render/quad.h b/src/libjin/render/quad.h
new file mode 100644
index 0000000..3ae4cc4
--- /dev/null
+++ b/src/libjin/render/quad.h
@@ -0,0 +1,17 @@
+#ifndef __JIN_QUAD_H
+#define __JIN_QUAD_H
+
+namespace jin
+{
+namespace render
+{
+
+ struct Quad
+ {
+ float x, y, w, h;
+ };
+
+}
+}
+
+#endif // !__JIN_RENDER_QUAD_H
diff --git a/src/libjin/render/rect.h b/src/libjin/render/rect.h
new file mode 100644
index 0000000..56b5bd1
--- /dev/null
+++ b/src/libjin/render/rect.h
@@ -0,0 +1,12 @@
+#ifndef __JIN_RECT_H
+#define __JIN_RECT_H
+
+namespace jin
+{
+class Rect
+{
+public:
+ int x, y, w, h;
+};
+}// jin
+#endif \ No newline at end of file
diff --git a/src/libjin/render/window.cpp b/src/libjin/render/window.cpp
new file mode 100644
index 0000000..20a6adc
--- /dev/null
+++ b/src/libjin/render/window.cpp
@@ -0,0 +1,83 @@
+#include "window.h"
+#include "3rdparty/GLee/GLee.h"
+#include "canvas.h"
+#include "utils/macros.h"
+namespace jin
+{
+namespace render
+{
+
+ shared Window* Window::g_wnd = 0;
+
+ Window::Window(): wnd(0), ctx(0)
+ {
+ }
+
+ Window::~Window()
+ {
+ }
+
+ void Window::init(int pw, int ph, const char* t)
+ {
+ w = pw;
+ h = ph;
+
+ if (wnd)
+ {
+ SDL_DestroyWindow(wnd);
+ SDL_FlushEvent(SDL_WINDOWEVENT);
+ }
+
+ if (ctx)
+ {
+ SDL_GL_DeleteContext(ctx);
+ }
+
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+
+ Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL ;
+
+ int wx = SDL_WINDOWPOS_UNDEFINED,
+ wy = SDL_WINDOWPOS_UNDEFINED;
+
+ /* Create window */
+ wnd = SDL_CreateWindow(t, wx, wy, w, h, flags);
+
+ // Create an opengl context
+ ctx = SDL_GL_CreateContext(wnd);
+ SDL_GL_MakeCurrent(wnd, ctx);
+
+ // Default clear color
+ glClearColor(0.f, 0.f, 0.f, 1.f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+ // Default render color
+ glColor4f(1, 1, 1, 1);
+
+ /**
+ * Set the viewport to top-left corner.
+ * Bind to the default render buffer.
+ */
+ Canvas::unbind();
+
+ // Swap window buffer
+ swapBuffers();
+ }
+
+ SDL_Window* Window::getWnd()
+ {
+ return wnd;
+ }
+
+ SDL_GLContext Window::getCtx()
+ {
+ return ctx;
+ }
+
+}
+} \ No newline at end of file
diff --git a/src/libjin/render/window.h b/src/libjin/render/window.h
new file mode 100644
index 0000000..f29c82d
--- /dev/null
+++ b/src/libjin/render/window.h
@@ -0,0 +1,53 @@
+#ifndef __JIN_RENDER_WINDOW
+#define __JIN_RENDER_WINDOW
+#include "SDL2/SDL.h"
+namespace jin
+{
+namespace render
+{
+ class Window
+ {
+ public:
+
+ void init(int w, int h, const char* t);
+
+ SDL_Window* getWnd();
+
+ SDL_GLContext getCtx();
+
+ static inline Window* get()
+ {
+ return (g_wnd ? g_wnd : (g_wnd = new Window()));
+ }
+
+ inline int Window::getW()
+ {
+ return w;
+ }
+
+ inline int Window::getH()
+ {
+ return h;
+ }
+
+ inline void Window::swapBuffers()
+ {
+ if (wnd)
+ SDL_GL_SwapWindow(wnd);
+ }
+ private:
+
+ Window();
+ ~Window();
+
+ static Window* g_wnd;
+
+ SDL_Window* wnd;
+
+ SDL_GLContext ctx;
+
+ int w, h;
+ };
+}
+}
+#endif \ No newline at end of file