aboutsummaryrefslogtreecommitdiff
path: root/src/libjin/Graphics
diff options
context:
space:
mode:
Diffstat (limited to 'src/libjin/Graphics')
-rw-r--r--src/libjin/Graphics/Canvas.cpp135
-rw-r--r--src/libjin/Graphics/Canvas.h40
-rw-r--r--src/libjin/Graphics/Color.h31
-rw-r--r--src/libjin/Graphics/Drawable.cpp77
-rw-r--r--src/libjin/Graphics/Drawable.h60
-rw-r--r--src/libjin/Graphics/Font.cpp194
-rw-r--r--src/libjin/Graphics/Font.h61
-rw-r--r--src/libjin/Graphics/Font/je_decoder.cpp93
-rw-r--r--src/libjin/Graphics/Font/je_decoder.h94
-rw-r--r--src/libjin/Graphics/Font/je_font.h100
-rw-r--r--src/libjin/Graphics/Font/je_page.h51
-rw-r--r--src/libjin/Graphics/Font/je_text.cpp154
-rw-r--r--src/libjin/Graphics/Font/je_text.h169
-rw-r--r--src/libjin/Graphics/Font/je_texture_font.cpp318
-rw-r--r--src/libjin/Graphics/Font/je_texture_font.h140
-rw-r--r--src/libjin/Graphics/Font/je_ttf.cpp463
-rw-r--r--src/libjin/Graphics/Font/je_ttf.h288
-rw-r--r--src/libjin/Graphics/Graphics.h15
-rw-r--r--src/libjin/Graphics/JSL.cpp159
-rw-r--r--src/libjin/Graphics/JSL.h74
-rw-r--r--src/libjin/Graphics/Shader/je_base.shader.h88
-rw-r--r--src/libjin/Graphics/Shader/je_default.shader.h21
-rw-r--r--src/libjin/Graphics/Shader/je_font.shader.h21
-rw-r--r--src/libjin/Graphics/Shader/je_jsl_compiler.cpp54
-rw-r--r--src/libjin/Graphics/Shader/je_jsl_compiler.h42
-rw-r--r--src/libjin/Graphics/Shader/je_shader.cpp278
-rw-r--r--src/libjin/Graphics/Shader/je_shader.h200
-rw-r--r--src/libjin/Graphics/Shader/je_texture.shader.h21
-rw-r--r--src/libjin/Graphics/Shapes.cpp122
-rw-r--r--src/libjin/Graphics/Shapes.h43
-rw-r--r--src/libjin/Graphics/Texture.cpp102
-rw-r--r--src/libjin/Graphics/Texture.h42
-rw-r--r--src/libjin/Graphics/Window.cpp97
-rw-r--r--src/libjin/Graphics/Window.h55
-rw-r--r--src/libjin/Graphics/animation/je_animation.cpp0
-rw-r--r--src/libjin/Graphics/animation/je_animation.h20
-rw-r--r--src/libjin/Graphics/animation/je_clip.cpp0
-rw-r--r--src/libjin/Graphics/animation/je_clip.h20
-rw-r--r--src/libjin/Graphics/je_bitmap.cpp162
-rw-r--r--src/libjin/Graphics/je_bitmap.h184
-rw-r--r--src/libjin/Graphics/je_canvas.cpp102
-rw-r--r--src/libjin/Graphics/je_canvas.h68
-rw-r--r--src/libjin/Graphics/je_color.cpp17
-rw-r--r--src/libjin/Graphics/je_color.h93
-rw-r--r--src/libjin/Graphics/je_gl.cpp12
-rw-r--r--src/libjin/Graphics/je_gl.h40
-rw-r--r--src/libjin/Graphics/je_graphic.cpp117
-rw-r--r--src/libjin/Graphics/je_graphic.h91
-rw-r--r--src/libjin/Graphics/je_graphics.h21
-rw-r--r--src/libjin/Graphics/je_image.cpp46
-rw-r--r--src/libjin/Graphics/je_image.h60
-rw-r--r--src/libjin/Graphics/je_mesh.cpp11
-rw-r--r--src/libjin/Graphics/je_mesh.h24
-rw-r--r--src/libjin/Graphics/je_shapes.cpp128
-rw-r--r--src/libjin/Graphics/je_shapes.h34
-rw-r--r--src/libjin/Graphics/je_sprite.cpp11
-rw-r--r--src/libjin/Graphics/je_sprite.h38
-rw-r--r--src/libjin/Graphics/je_sprite_batch.cpp0
-rw-r--r--src/libjin/Graphics/je_sprite_batch.h17
-rw-r--r--src/libjin/Graphics/je_texture.cpp44
-rw-r--r--src/libjin/Graphics/je_texture.h56
-rw-r--r--src/libjin/Graphics/je_window.cpp111
-rw-r--r--src/libjin/Graphics/je_window.h97
-rw-r--r--src/libjin/Graphics/particle/je_particle.cpp0
-rw-r--r--src/libjin/Graphics/particle/je_particle.h21
-rw-r--r--src/libjin/Graphics/particle/je_particle_batch.cpp0
-rw-r--r--src/libjin/Graphics/particle/je_particle_batch.h20
-rw-r--r--src/libjin/Graphics/particle/je_particle_emitter.cpp11
-rw-r--r--src/libjin/Graphics/particle/je_particle_emitter.h23
-rw-r--r--src/libjin/Graphics/particle/je_particle_system.cpp1
-rw-r--r--src/libjin/Graphics/particle/je_particle_system.h0
71 files changed, 4295 insertions, 1307 deletions
diff --git a/src/libjin/Graphics/Canvas.cpp b/src/libjin/Graphics/Canvas.cpp
deleted file mode 100644
index f5bd09f..0000000
--- a/src/libjin/Graphics/Canvas.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include "../utils/macros.h"
-#include "canvas.h"
-#include "window.h"
-
-namespace jin
-{
-namespace graphics
-{
-
- shared Canvas* Canvas::createCanvas(int w, int h)
- {
- return new Canvas(w, h);
- }
-
- Canvas::Canvas(int w, int h)
- : Drawable(w, h)
- {
- init();
- }
-
- Canvas::~Canvas()
- {
- }
-
- shared GLint Canvas::cur = -1;
-
- bool Canvas::init()
- {
- setVertices(
- new float [DRAWABLE_V_SIZE] {
- 0, 0,
- 0, (float)height,
- (float)width, (float)height,
- (float)width, 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, width, height, 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();
- }
-
-} // render
-} // jin
-
-#endif // JIN_MODULES_RENDER \ No newline at end of file
diff --git a/src/libjin/Graphics/Canvas.h b/src/libjin/Graphics/Canvas.h
deleted file mode 100644
index 0d5635e..0000000
--- a/src/libjin/Graphics/Canvas.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef __JIN_CANVAS_H
-#define __JIN_CANVAS_H
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include "drawable.h"
-namespace jin
-{
-namespace graphics
-{
- class Canvas: public Drawable
- {
- public:
-
- static Canvas* createCanvas(int w, int h);
-
- ~Canvas();
-
- void bind();
-
- static void unbind();
-
- static bool hasbind(GLint fbo);
-
- protected:
-
- Canvas(int w, int h);
-
- GLuint fbo;
-
- // current binded fbo
- static GLint cur;
-
- bool init();
- };
-} // render
-} // jin
-
-#endif // JIN_MODULES_RENDER
-#endif // __JIN_CANVAS_H \ No newline at end of file
diff --git a/src/libjin/Graphics/Color.h b/src/libjin/Graphics/Color.h
deleted file mode 100644
index a78234e..0000000
--- a/src/libjin/Graphics/Color.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
-* Some color operating here.
-*/
-#ifndef __JIN_COLOR_H
-#define __JIN_COLOR_H
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include "../utils/endian.h"
-
-namespace jin
-{
-namespace graphics
-{
-
- 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;
- };
-
-} // render
-} // jin
-
-#endif // JIN_MODULES_RENDER
-#endif // __JIN_COLOR_H \ No newline at end of file
diff --git a/src/libjin/Graphics/Drawable.cpp b/src/libjin/Graphics/Drawable.cpp
deleted file mode 100644
index cab6c50..0000000
--- a/src/libjin/Graphics/Drawable.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include "drawable.h"
-#include "../math/matrix.h"
-#include <stdlib.h>
-
-namespace jin
-{
-namespace graphics
-{
- Drawable::Drawable(int w, int h):texture(0), width(w), height(h), ancx(0), ancy(0), textCoord(0), vertCoord(0)
- {
- }
-
- Drawable::~Drawable()
- {
- glDeleteTextures(1, &texture);
- delete[] vertCoord;
- delete[] textCoord;
- }
-
- 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;
- }
-
- 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::math::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);
- }
-} // render
-} // jin
-
-#endif // JIN_MODULES_RENDER \ No newline at end of file
diff --git a/src/libjin/Graphics/Drawable.h b/src/libjin/Graphics/Drawable.h
deleted file mode 100644
index e04ac6b..0000000
--- a/src/libjin/Graphics/Drawable.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef __JIN_DRAWABLE
-#define __JIN_DRAWABLE
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include "../3rdparty/GLee/GLee.h"
-namespace jin
-{
-namespace graphics
-{
-
- class Drawable
- {
- public:
- Drawable(int w = 0, int h = 0);
- virtual ~Drawable();
-
- void setAnchor(int x, int y);
-
- void draw(int x, int y, float sx, float sy, float r);
-
- inline int getWidth() const
- {
- return width;
- }
-
- inline int getHeight() const
- {
- return height;
- }
-
- inline GLuint getTexture() const
- {
- return texture;
- };
-
- protected:
-
- const int 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;
-
- };
-
-} // render
-} // jin
-
-#endif // JIN_MODULES_RENDER
-#endif // __JIN_DRAWABLE \ No newline at end of file
diff --git a/src/libjin/Graphics/Font.cpp b/src/libjin/Graphics/Font.cpp
deleted file mode 100644
index a107613..0000000
--- a/src/libjin/Graphics/Font.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include "font.h"
-#include <stdio.h>
-#define STB_TRUETYPE_IMPLEMENTATION
-#include "../3rdparty/stb/stb_truetype.h"
-#include "color.h"
-
-namespace jin
-{
-namespace graphics
-{
-
- using namespace jin::math;
-
- const int BITMAP_WIDTH = 512;
- const int BITMAP_HEIGHT = 512;
- const int 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;
- }
-
-}
-}
-
-#endif // JIN_MODULES_RENDER \ No newline at end of file
diff --git a/src/libjin/Graphics/Font.h b/src/libjin/Graphics/Font.h
deleted file mode 100644
index 7fc96e2..0000000
--- a/src/libjin/Graphics/Font.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef __JIN_FONT_H
-#define __JIN_FONT_H
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include "drawable.h"
-#include "../3rdparty/stb/stb_truetype.h"
-#include "../math/quad.h"
-
-namespace jin
-{
-namespace graphics
-{
- /**
- * 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 // JIN_MODULES_RENDER
-#endif // __JIN_FONT_H \ No newline at end of file
diff --git a/src/libjin/Graphics/Font/je_decoder.cpp b/src/libjin/Graphics/Font/je_decoder.cpp
new file mode 100644
index 0000000..01e1990
--- /dev/null
+++ b/src/libjin/Graphics/Font/je_decoder.cpp
@@ -0,0 +1,93 @@
+#include <stdlib.h>
+#include <string.h>
+#include "je_decoder.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ /* utf8 byte string to unicode codepoint */
+ static const char *utf8toCodepoint(const char *p, unsigned *res) {
+ return nullptr;
+
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // decoders
+ /////////////////////////////////////////////////////////////////////////////
+
+ const void* Utf8::decode(const void* data, Codepoint* res) const
+ {
+ const char* p = (char*)data;
+ unsigned x, mask, shift;
+ switch (*p & 0xf0) {
+ case 0xf0: mask = 0x07; shift = 18; break;
+ case 0xe0: mask = 0x0f; shift = 12; break;
+ case 0xc0:
+ case 0xd0: mask = 0x1f; shift = 6; break;
+ default:
+ *res = *p;
+ return p + 1;
+ }
+ x = (*p & mask) << shift;
+ do {
+ if (*(++p) == '\0') {
+ *res = x;
+ return p;
+ }
+ shift -= 6;
+ x |= (*p & 0x3f) << shift;
+ } while (shift);
+ *res = x;
+ return p + 1;
+ }
+
+ const void* Utf8::next(const void* data) const
+ {
+ const char* p = (char*)data;
+ unsigned x, mask, shift;
+ switch (*p & 0xf0) {
+ case 0xf0: mask = 0x07; shift = 18; break;
+ case 0xe0: mask = 0x0f; shift = 12; break;
+ case 0xc0:
+ case 0xd0: mask = 0x1f; shift = 6; break;
+ default:
+ return p + 1;
+ }
+ x = (*p & mask) << shift;
+ do {
+ if (*(++p) == '\0') {
+ return p;
+ }
+ shift -= 6;
+ x |= (*p & 0x3f) << shift;
+ } while (shift);
+ return p + 1;
+ }
+ /*
+ const void* Utf16::decode(const void* data, Codepoint* res) const
+ {
+ return nullptr;
+ }
+
+ const void* Utf16::next(const void* data) const
+ {
+ return nullptr;
+ }
+ */
+ const void* Ascii::decode(const void* data, Codepoint* res) const
+ {
+ const char* p = (char*)data;
+ *res = *p;
+ return p + 1;
+ }
+
+ const void* Ascii::next(const void* data) const
+ {
+ const char* p = (char*)data;
+ return p + 1;
+ }
+
+ } // namespace Graphics
+} // namespace JinEngine \ No newline at end of file
diff --git a/src/libjin/Graphics/Font/je_decoder.h b/src/libjin/Graphics/Font/je_decoder.h
new file mode 100644
index 0000000..36cbda7
--- /dev/null
+++ b/src/libjin/Graphics/Font/je_decoder.h
@@ -0,0 +1,94 @@
+#ifndef __JE_UTF8_H
+#define __JE_UTF8_H
+
+#include <vector>
+
+#include "je_text.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ ///
+ /// Text decoder.
+ ///
+ class Decoder
+ {
+ public:
+
+ ///
+ /// Decode a code unit.
+ ///
+ /// @param data Code units.
+ /// @param codepoint Value of code point.
+ /// @return Next code unit location.
+ ///
+ virtual const void* decode(const void* data, Codepoint* codepoint) const = 0 ;
+
+ ///
+ /// Get next code unit location.
+ ///
+ /// @param data Code units.
+ /// @return Next code unit location.
+ ///
+ virtual const void* next(const void* data) const = 0;
+
+ };
+
+ ///
+ /// Utf-8 decoder.
+ ///
+ class Utf8 : public Decoder
+ {
+ public:
+
+ ///
+ /// Decode a code unit.
+ ///
+ /// @param data Code units.
+ /// @param codepoint Value of code point.
+ /// @return Next code unit location.
+ ///
+ const void* decode(const void* data, Codepoint* codepoint) const override;
+
+ ///
+ /// Get next code unit location.
+ ///
+ /// @param data Code units.
+ /// @return Next code unit location.
+ ///
+ const void* next(const void* data) const override;
+
+ };
+
+ ///
+ /// Ascii decoder.
+ ///
+ class Ascii : public Decoder
+ {
+ public:
+
+ ///
+ /// Decode a code unit.
+ ///
+ /// @param data Code units.
+ /// @param codepoint Value of code point.
+ /// @return Next code unit location.
+ ///
+ const void* decode(const void* data, Codepoint* codepoint) const override;
+
+ ///
+ /// Get next code unit location.
+ ///
+ /// @param data Code units.
+ /// @return Next code unit location.
+ ///
+ const void* next(const void* data) const override;
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif \ No newline at end of file
diff --git a/src/libjin/Graphics/Font/je_font.h b/src/libjin/Graphics/Font/je_font.h
new file mode 100644
index 0000000..4529902
--- /dev/null
+++ b/src/libjin/Graphics/Font/je_font.h
@@ -0,0 +1,100 @@
+#ifndef __JE_FONT_H
+#define __JE_FONT_H
+
+#include <vector>
+#include "je_text.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ struct Page;
+
+ ///
+ /// Base Font class.
+ ///
+ class Font
+ {
+ public:
+ ///
+ /// Font constructor.
+ ///
+ Font(unsigned fontsize)
+ : mFontSize(fontsize)
+ {
+ }
+
+ ///
+ /// Font destructor.
+ ///
+ virtual ~Font() {};
+
+ ///
+ /// Create page with given text.
+ ///
+ /// @param text Text to be typesetted.
+ /// @param lineheight Line height of text.
+ /// @param spacing Spacing between characters. 0 by default.
+ /// @return Page if created successfully, otherwise return null.
+ ///
+ virtual Page* typeset(const Text& text, int lineheight, int spacing = 0) = 0;
+
+ ///
+ /// Create page with given unicode codepoints.
+ ///
+ /// @param content Unicode codepoints to be typesetted.
+ /// @param lineheight Line height of text.
+ /// @param spacing Spacing between characters. 0 by default.
+ /// @return Page if created successfully, otherwise return null.
+ ///
+ virtual Page* typeset(const Content& content, int lineheight, int spacing = 0) = 0;
+
+ ///
+ /// Render page to given position.
+ ///
+ /// @param page Page to be rendered.
+ /// @param x X value of the position.
+ /// @param y Y value of the position.
+ ///
+ virtual void print(const Page* page, int x, int y) = 0;
+
+ ///
+ /// Render unicode codepoints to given position.
+ ///
+ /// @param content Unicode codepoints to be typesetted.
+ /// @param x X value of the position.
+ /// @param y Y value of the position.
+ /// @param lineheight Line height of the content.
+ /// @param spacing Spacing between characters.
+ ///
+ virtual void print(const Content& content, int x, int y, int lineheight, int spacing = 0) = 0;
+
+ ///
+ /// Render text to given position.
+ ///
+ /// @param text Text to be rendered.
+ /// @param x X value of the position.
+ /// @param y Y value of the position.
+ /// @param lineheight Line height of the text.
+ /// @param spacing Spacing between characters.
+ ///
+ virtual void print(const Text& text, int x, int y, int lineheight, int spacing = 0) = 0;
+
+ ///
+ /// Get font size.
+ ///
+ /// @return Font size.
+ ///
+ inline unsigned getFontSize() { return mFontSize; };
+
+ protected:
+
+ unsigned mFontSize;
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // __JE_FONT_H \ No newline at end of file
diff --git a/src/libjin/Graphics/Font/je_page.h b/src/libjin/Graphics/Font/je_page.h
new file mode 100644
index 0000000..fbc297e
--- /dev/null
+++ b/src/libjin/Graphics/Font/je_page.h
@@ -0,0 +1,51 @@
+#ifndef __JE_PAGE_H
+#define __JE_PAGE_H
+
+#include "../../math/je_vector2.hpp"
+
+#include "je_font.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ class Font;
+
+ ///
+ /// Glyphs data to be rendered.
+ ///
+ struct GlyphVertex
+ {
+ int x, y; ///< screen coordinates
+ float u, v; ///< normalized texture uv
+ };
+
+ ///
+ /// Glyphs info for reducing draw call.
+ ///
+ struct GlyphArrayDrawInfo
+ {
+ GLuint texture; ///< atlas
+ unsigned int start; ///< glyph vertex indecies
+ unsigned int count; ///< glyph vertex count
+ };
+
+ ///
+ /// Page to be rendered.
+ ///
+ /// A page is a pre-rendered text struct for reducing draw call. Each page
+ /// keeps a font pointer which should not be changed.
+ ///
+ struct Page
+ {
+ Font* font;
+ std::vector<GlyphArrayDrawInfo> glyphinfolist;
+ std::vector<GlyphVertex> glyphvertices;
+ Math::Vector2<int> size;
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // __JE_PAGE_H \ No newline at end of file
diff --git a/src/libjin/Graphics/Font/je_text.cpp b/src/libjin/Graphics/Font/je_text.cpp
new file mode 100644
index 0000000..75dfc7b
--- /dev/null
+++ b/src/libjin/Graphics/Font/je_text.cpp
@@ -0,0 +1,154 @@
+#include <cstring>
+
+#include "je_text.h"
+#include "je_decoder.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ /////////////////////////////////////////////////////////////////////////////
+ // iterator
+ /////////////////////////////////////////////////////////////////////////////
+
+ Text::Iterator::Iterator(const Iterator& itor)
+ : data(itor.data)
+ , p(itor.p)
+ , encode(itor.encode)
+ , length(itor.length)
+ {
+ switch (encode)
+ {
+ case Encode::UTF8: decoder = new Utf8(); break;
+ case Encode::ASCII: decoder = new Ascii(); break;
+ }
+ }
+
+ Text::Iterator::Iterator(const Encode& _encode, const void* _data, unsigned int _length)
+ : data(_data)
+ , p(_data)
+ , encode(_encode)
+ , length(_length)
+ {
+ switch (encode)
+ {
+ case Encode::UTF8: decoder = new Utf8(); break;
+ case Encode::ASCII: decoder = new Ascii(); break;
+ }
+ }
+
+ Text::Iterator::~Iterator()
+ {
+ delete decoder;
+ }
+
+ Codepoint Text::Iterator::get()
+ {
+ Codepoint codepoint;
+ decoder->decode(p, &codepoint);
+ return codepoint;
+ }
+
+ Codepoint Text::Iterator::operator*()
+ {
+ return get();
+ }
+ /*
+ Text::Iterator Text::Iterator::begin()
+ {
+ Iterator itor(encode, data, length);
+ itor.toBegin();
+ return itor;
+ }
+
+ Text::Iterator Text::Iterator::end()
+ {
+ Iterator itor(encode, data, length);
+ itor.toEnd();
+ return itor;
+ }
+ */
+ void Text::Iterator::toBegin()
+ {
+ p = (const unsigned char*)data;
+ }
+
+ void Text::Iterator::toEnd()
+ {
+ p = (const unsigned char*)data + length;
+ }
+
+ Text::Iterator& Text::Iterator::operator ++()
+ {
+ p = decoder->next(p);
+ return *this;
+ }
+
+ Text::Iterator Text::Iterator::operator ++(int)
+ {
+ p = decoder->next(p);
+ Iterator itor(encode, data, length);
+ itor.p = p;
+ return itor;
+ }
+
+ bool Text::Iterator::operator !=(const Iterator& itor)
+ {
+ return !(data == itor.data
+ && p == itor.p
+ && length == itor.length
+ && encode == itor.encode);
+ }
+
+ bool Text::Iterator::operator ==(const Iterator& itor)
+ {
+ return data == itor.data
+ && p == itor.p
+ && length == itor.length
+ && encode == itor.encode;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // text
+ /////////////////////////////////////////////////////////////////////////////
+
+ Text::Text(Encode encode, const void* data)
+ {
+ unsigned length = strlen((const char*)data);
+ Iterator end = Iterator(encode, data, length);
+ end.toEnd();
+ Iterator it = Iterator(encode, data, length);
+ for (; it != end; ++it)
+ {
+ content.push_back(*it);
+ }
+ }
+
+ Text::Text(Encode encode, const void* data, unsigned length)
+ {
+ Iterator end = Iterator(encode, data, length);
+ end.toEnd();
+ Iterator it = Iterator(encode, data, length);
+ for (; it != end; ++it)
+ {
+ content.push_back(*it);
+ }
+ }
+
+ Text::~Text()
+ {
+ }
+
+ const Content& Text::getContent() const
+ {
+ return content;
+ }
+
+ const Content& Text::operator*() const
+ {
+ return content;
+ }
+
+ } // namespace Graphics
+} // namespace JinEngine \ No newline at end of file
diff --git a/src/libjin/Graphics/Font/je_text.h b/src/libjin/Graphics/Font/je_text.h
new file mode 100644
index 0000000..7436875
--- /dev/null
+++ b/src/libjin/Graphics/Font/je_text.h
@@ -0,0 +1,169 @@
+#ifndef __JE_TEXT_H
+#define __JE_TEXT_H
+
+#include <vector>
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ typedef unsigned int Codepoint;
+
+ typedef std::vector<Codepoint> Content;
+
+ class Text;
+
+ class Decoder;
+
+ ///
+ /// Supported text encoding.
+ ///
+ enum Encode
+ {
+ UTF8, ///< utf-8
+ ASCII, ///< ASCII
+ };
+
+ ///
+ /// Decoded text. Saved as unicode codepoints.
+ ///
+ class Text
+ {
+ public:
+ ///
+ ///
+ ///
+ Text(Encode encode, const void* data);
+
+ ///
+ ///
+ ///
+ Text(Encode encode, const void* data, unsigned int length);
+
+ ///
+ ///
+ ///
+ ~Text();
+
+ ///
+ ///
+ ///
+ const Content& getContent() const;
+
+ ///
+ ///
+ ///
+ const Content& operator*() const;
+
+ private:
+ ///
+ ///
+ ///
+ class Iterator
+ {
+ public:
+
+ ///
+ ///
+ ///
+ Iterator(const Iterator& itor);
+
+ ///
+ ///
+ ///
+ Iterator(const Encode& encode, const void* data, unsigned int length);
+
+ ///
+ ///
+ ///
+ ~Iterator();
+
+ ///
+ ///
+ ///
+ Codepoint get();
+
+ //Iterator begin();
+ //Iterator end();
+
+ ///
+ ///
+ ///
+ void toBegin();
+
+ ///
+ ///
+ ///
+ void toEnd();
+
+ ///
+ ///
+ ///
+ Codepoint operator *();
+
+ ///
+ ///
+ ///
+ Iterator& operator ++();
+
+ ///
+ ///
+ ///
+ Iterator operator ++(int);
+
+ ///
+ ///
+ ///
+ bool operator !=(const Iterator& itor);
+
+ ///
+ ///
+ ///
+ bool operator ==(const Iterator& itor);
+
+ private:
+
+ ///
+ ///
+ ///
+ void operator = (const Iterator&);
+
+ ///
+ ///
+ ///
+ const Encode encode;
+
+ ///
+ ///
+ ///
+ const Decoder* decoder;
+
+ ///
+ ///
+ ///
+ const void* p;
+
+ ///
+ ///
+ ///
+ const void* const data;
+
+ ///
+ ///
+ ///
+ unsigned int length;
+
+ };
+
+ ///
+ ///
+ ///
+ Content content;
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif \ No newline at end of file
diff --git a/src/libjin/Graphics/Font/je_texture_font.cpp b/src/libjin/Graphics/Font/je_texture_font.cpp
new file mode 100644
index 0000000..9651c1a
--- /dev/null
+++ b/src/libjin/Graphics/Font/je_texture_font.cpp
@@ -0,0 +1,318 @@
+#include <vector>
+
+#include "../../math/je_vector2.hpp"
+
+#include "../shader/je_shader.h"
+
+#include "je_texture_font.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ using namespace std;
+ using namespace Math;
+
+ TextureFont * TextureFont::createTextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh)
+ {
+ TextureFont* tf = new TextureFont(bitmap, codepoints, cellw, cellh);
+ return tf;
+ }
+
+ TextureFont * TextureFont::createTextureFont(const Bitmap* bitmap, const Text& codepoints, int cellw, int cellh)
+ {
+ TextureFont* tf = new TextureFont(bitmap, *codepoints, cellw, cellh);
+ return tf;
+ }
+
+ TextureFont* TextureFont::createTextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh)
+ {
+ TextureFont* tf = new TextureFont(bitmap, codepoints, mask, cellh);
+ return tf;
+ }
+
+ TextureFont* TextureFont::createTextureFont(const Bitmap* bitmap, const Text& codepoints, Color mask, int cellh)
+ {
+ TextureFont* tf = new TextureFont(bitmap, *codepoints, mask, cellh);
+ return tf;
+ }
+
+ TextureFont::~TextureFont()
+ {
+ }
+
+ const TextureFont::TextureGlyph* TextureFont::findGlyph(Codepoint codepoint) const
+ {
+ auto it = glyphs.find(codepoint);
+ if (it != glyphs.end())
+ {
+ return &it->second;
+ }
+ else
+ return nullptr;
+ }
+
+ Page* TextureFont::typeset(const Content& text, int lineheight, int spacing)
+ {
+ Page* page = new Page();
+ page->font = this;
+ vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist;
+ vector<GlyphVertex>& glyphvertices = page->glyphvertices;
+ int texture = -1;
+ const TextureGlyph* glyph = nullptr;
+ GlyphVertex vertex;
+ Vector2<int> p(0, 0);
+ int i = 0;
+
+ #define glyphvertices_push(_x, _y, _u, _v) \
+ vertex.x = _x; vertex.y = _y;\
+ vertex.u = _u; vertex.v = _v;\
+ glyphvertices.push_back(vertex);\
+
+ for (Codepoint c : text)
+ {
+ // return
+ if (c == 0x0D) continue;
+ // newline
+ if (c == 0x0A)
+ {
+ p.y += lineheight;
+ p.x = 0;
+ continue;
+ }
+ if (c == 0x09)
+ {
+ // tab = 4*space
+ unsigned cw = getCharWidth(0x20);
+ p.x += cw * 4;
+ continue;
+ }
+ glyph = findGlyph(c);
+ if (glyph == nullptr) continue;
+ if (texture != mTexture)
+ {
+ texture = mTexture;
+ GlyphArrayDrawInfo info;
+ info.start = i;
+ info.count = 0;
+ info.texture = texture;
+ glyphinfolist.push_back(info);
+ }
+ glyphinfolist[glyphinfolist.size() - 1].count += 4;
+ // normalized
+ float w = getWidth(), h = getHeight();
+ float nx = glyph->x / w, ny = glyph->y / h;
+ float nw = glyph->w / w, nh = glyph->h / h;
+ glyphvertices_push(p.x, p.y, nx, ny);
+ glyphvertices_push(p.x, p.y + glyph->h, nx, ny + nh);
+ glyphvertices_push(p.x + glyph->w, p.y + glyph->h, nx + nw, ny + nh);
+ glyphvertices_push(p.x + glyph->w, p.y, nx + nw, ny);
+ p.x += glyph->w + spacing;
+ i += 4;
+ }
+ getTextBox(text, &page->size.w, &page->size.h, lineheight, spacing);
+ return page;
+ }
+
+ int TextureFont::getCharWidth(int c)
+ {
+ auto it = glyphs.find(c);
+ if (it != glyphs.end())
+ {
+ return it->second.w;
+ }
+ return 0;
+ }
+
+ int TextureFont::getCharHeight(int c)
+ {
+ auto it = glyphs.find(c);
+ if (it != glyphs.end())
+ {
+ return it->second.h;
+ }
+ return 0;
+ }
+
+ int TextureFont::getTextWidth(const Content& t, int spacing)
+ {
+ int res = 0;
+ int tmp = 0;
+ for (Codepoint c : t)
+ {
+ if (c == 0x0D)
+ continue;
+ if (c == 0x0A)
+ {
+ tmp = 0;
+ continue;
+ }
+ if (c == 0x09)
+ {
+ // tab = 4*space
+ unsigned cw = getCharWidth(0x20);
+ tmp += cw * 4;
+ if (tmp > res) res = tmp;
+ continue;
+ }
+ tmp += getCharWidth(c) + spacing;
+ if (tmp > res) res = tmp;
+ }
+ return res;
+ }
+
+ int TextureFont::getTextHeight(const Content& t, int lineheight)
+ {
+ int res = 0;
+ bool newline = true;
+ for (Codepoint c : t)
+ {
+ if (c == 0x0A)
+ newline = true;
+ else if (c == 0x0D);
+ else if (newline)
+ {
+ newline = false;
+ res += lineheight;
+ }
+ }
+ return res;
+ }
+
+ void TextureFont::getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing)
+ {
+ *w = 0;
+ *h = 0;
+ int tmp = 0;
+ bool newline = true;
+ for (Codepoint c : text)
+ {
+ if (c == 0x0D)
+ continue;
+ if (c == 0x0A)
+ {
+ tmp = 0;
+ newline = true;
+ continue;
+ }
+ else if (newline)
+ {
+ newline = false;
+ *h += lineheight;
+ }
+ tmp += getCharWidth(c) + spacing;
+ if (tmp > *w)
+ *w = tmp;
+ }
+ }
+
+ Page* TextureFont::typeset(const Text& text, int lineheight, int spacing)
+ {
+ return typeset(*text, lineheight, spacing);
+ }
+
+ void TextureFont::print(const Page* page, int x, int y)
+ {
+ Shader* shader = Shader::getCurrentShader();
+ const vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist;
+ const vector<GlyphVertex>& glyphvertices = page->glyphvertices;
+ gl.ModelMatrix.setTransformation(x, y, 0, 1, 1, 0, 0);
+ shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix);
+ shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix);
+ for (int i = 0; i < glyphinfolist.size(); ++i)
+ {
+ const GlyphArrayDrawInfo& info = glyphinfolist[i];
+ shader->bindVertexPointer(2, GL_INT, sizeof(GlyphVertex), &glyphvertices[info.start].x);
+ shader->bindUVPointer(2, GL_FLOAT, sizeof(GlyphVertex), &glyphvertices[info.start].u);
+ gl.bindTexture(info.texture);
+ gl.drawArrays(GL_QUADS, 0, info.count);
+ gl.bindTexture(0);
+ }
+ }
+
+ void TextureFont::print(const Content& text, int x, int y, int lineheight, int spacing)
+ {
+ Page* page = typeset(text, lineheight, spacing);
+ print(page, x, y);
+ delete page;
+ }
+
+ void TextureFont::print(const Text& text, int x, int y, int lineheight, int spacing)
+ {
+ Page* page = typeset(text, lineheight, spacing);
+ print(page, x, y);
+ delete page;
+ }
+
+ TextureFont::TextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh)
+ : Graphic(bitmap)
+ , Font(cellh)
+ {
+ TextureGlyph glyph;
+ Vector2<int> count(bitmap->getWidth() / cellw, bitmap->getHeight() / cellh);
+ glyph.w = cellw;
+ glyph.h = cellh;
+ for (int y = 0; y < count.row; ++y)
+ {
+ glyph.y = y * cellh;
+ for (int x = 0; x < count.colum; ++x)
+ {
+ glyph.x = x * cellw;
+ if (x + y * count.colum >= codepoints.size())
+ return;
+ glyphs.insert(std::pair<Codepoint, TextureGlyph>(codepoints[x + y * count.colum], glyph));
+ }
+ }
+ }
+
+ TextureFont::TextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh)
+ : Graphic(bitmap)
+ , Font(cellh)
+ {
+ TextureGlyph glyph;
+ glyph.h = cellh;
+ int w = bitmap->getWidth();
+ int h = bitmap->getHeight();
+ int i = 0;
+ for (int y = 0; y < h; y += cellh)
+ {
+ glyph.y = y;
+ bool newc = false;
+ for (int x = 0; x <= w; ++x)
+ {
+ if (x == w && newc)
+ {
+ glyph.w = x - glyph.x;
+ if (i >= codepoints.size())
+ return;
+ glyphs.insert(std::pair<Codepoint, TextureGlyph>(codepoints[i], glyph));
+ ++i;
+ newc = false;
+ break;
+ }
+ Color c = bitmap->getPixels()[x + y * w];
+ if (!newc && c != mask)
+ {
+ glyph.x = x;
+ newc = true;
+ }
+ else if (newc && c == mask)
+ {
+ glyph.w = x - glyph.x;
+ if (i >= codepoints.size())
+ return;
+ glyphs.insert(std::pair<Codepoint, TextureGlyph>(codepoints[i], glyph));
+ if (codepoints[i] == 't')
+ {
+ int a = 10;
+ }
+ ++i;
+ newc = false;
+ }
+ }
+ }
+ }
+
+ }
+} \ No newline at end of file
diff --git a/src/libjin/Graphics/Font/je_texture_font.h b/src/libjin/Graphics/Font/je_texture_font.h
new file mode 100644
index 0000000..6276350
--- /dev/null
+++ b/src/libjin/Graphics/Font/je_texture_font.h
@@ -0,0 +1,140 @@
+#ifndef __JE_TEXTURE_FONT_H
+#define __JE_TEXTURE_FONT_H
+
+#include <map>
+#include <vector>
+
+#include "../../math/je_vector4.hpp"
+
+#include "../je_graphic.h"
+#include "../je_bitmap.h"
+
+#include "je_page.h"
+#include "je_font.h"
+#include "je_text.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ ///
+ ///
+ ///
+ class TextureFont : public Font
+ , public Graphic
+ {
+ public:
+
+ ///
+ ///
+ ///
+ static TextureFont* createTextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh);
+
+ ///
+ ///
+ ///
+ static TextureFont* createTextureFont(const Bitmap* bitmap, const Text& text, int cellw, int cellh);
+
+ ///
+ ///
+ ///
+ static TextureFont* createTextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh);
+
+ ///
+ ///
+ ///
+ static TextureFont* createTextureFont(const Bitmap* bitmap, const Text& text, Color mask, int cellh);
+
+ ///
+ ///
+ ///
+ ~TextureFont();
+
+ ///
+ ///
+ ///
+ Page* typeset(const Text& text, int lineheight, int spacing = 0) override;
+
+ ///
+ ///
+ ///
+ Page* typeset(const Content& text, int lineheight, int spacing = 0) override ;
+
+ ///
+ ///
+ ///
+ void print(const Page* page, int x, int y) override;
+
+ ///
+ ///
+ ///
+ void print(const Content& text, int x, int y, int linehgiht, int spacing = 0) override;
+
+ ///
+ ///
+ ///
+ void print(const Text& text, int x, int y, int lineheight, int spacing = 0)override;
+
+ private:
+
+ ///
+ ///
+ ///
+ struct TextureGlyph
+ {
+ float x, y, w, h;
+ };
+
+ ///
+ ///
+ ///
+ TextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh);
+
+ ///
+ ///
+ ///
+ TextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh);
+
+ ///
+ ///
+ ///
+ int getCharWidth(int c);
+
+ ///
+ ///
+ ///
+ int getCharHeight(int c);
+
+ ///
+ ///
+ ///
+ int getTextWidth(const Content& text, int spacing = 0);
+
+ ///
+ ///
+ ///
+ int getTextHeight(const Content& text, int lineheight);
+
+ ///
+ ///
+ ///
+ void getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing = 0);
+
+ ///
+ ///
+ ///
+ const TextureGlyph* findGlyph(Codepoint codepoint) const;
+
+
+ ///
+ ///
+ ///
+ std::map<Codepoint, TextureGlyph> glyphs;
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif \ No newline at end of file
diff --git a/src/libjin/Graphics/Font/je_ttf.cpp b/src/libjin/Graphics/Font/je_ttf.cpp
new file mode 100644
index 0000000..a11efb0
--- /dev/null
+++ b/src/libjin/Graphics/Font/je_ttf.cpp
@@ -0,0 +1,463 @@
+#include "../../core/je_configuration.h"
+#if defined(jin_graphics)
+
+#include <stdio.h>
+
+#include "../../common/je_array.hpp"
+
+#include "../je_gl.h"
+#include "../je_color.h"
+#include "../shader/je_shader.h"
+
+#include "je_ttf.h"
+#include "je_page.h"
+
+#define STB_TRUETYPE_IMPLEMENTATION
+#include "../../3rdparty/stb/stb_truetype.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ /////////////////////////////////////////////////////////////////////////////
+ // TTFData
+ /////////////////////////////////////////////////////////////////////////////
+
+ TTFData* TTFData::createTTFData(const unsigned char* data, unsigned int size)
+ {
+ TTFData* ttf = nullptr;
+ try
+ {
+ ttf = new TTFData(data, size);
+ return ttf;
+ }
+ catch (...)
+ {
+ return nullptr;
+ }
+ }
+
+ TTFData::TTFData(const unsigned char* d, unsigned int s)
+ {
+ raw.size = s;
+ raw.data = (unsigned char*)malloc(s);
+ memcpy(raw.data, d, s);
+ if (!stbtt_InitFont(&info, (const unsigned char*)raw.data, 0))
+ {
+ delete raw.data;
+ throw 0;
+ }
+ /* push default fontsize */
+ pushTTFsize(FONT_SIZE);
+ }
+
+ TTFData::~TTFData()
+ {
+ free(raw.data);
+ }
+
+ TTF* TTFData::createTTF(unsigned fontSize)
+ {
+ TTF* ttf;
+ try
+ {
+ ttf = new TTF(this, fontSize);
+ }
+ catch (...)
+ {
+ return nullptr;
+ }
+ return ttf;
+ }
+
+ /*
+ * (0, 0)
+ * +--------------+ ascent
+ * | +--------+ |
+ * | | | |
+ * | | bitmap | |
+ * +--|--------|--+ baseline
+ * | +--------+ |
+ * +--|-----------+ decent
+ * | |
+ * leftSideBearing |
+ * advanceWidth
+ */
+ void TTFData::getVMetrics(int* baseline, int* descent)
+ {
+ float scale = scales.back();
+ int ascent;
+ stbtt_GetFontVMetrics(&info, &ascent, descent, 0);
+ *baseline = (int)(ascent*scale) + 1; // slight adjustment
+ *descent = *baseline - (int)(*descent*scale) + 1;
+ }
+
+ void TTFData::getHMetrics(unsigned int codepoint, int* advanceWidth, int* leftSideBearing)
+ {
+ float scale = scales.back();
+ int adw, lsb;
+ stbtt_GetCodepointHMetrics(&info, codepoint, &adw, &lsb);
+ *advanceWidth = (int)(adw*scale);
+ *leftSideBearing = (int)(lsb*scale);
+ }
+
+ void TTFData::pushTTFsize(unsigned int fs)
+ {
+ float sc = stbtt_ScaleForPixelHeight(&info, fs);
+ scales.push_back(sc);
+ }
+
+ void TTFData::popTTFsize()
+ {
+ /* always keep default ttf size on the bottom of stack */
+ if (scales.size() > 1)
+ scales.pop_back();
+ }
+
+ Channel* TTFData::getCodepointBitmapAlpha(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const
+ {
+ float scale = scales.back();
+ Channel* bitmap = stbtt_GetCodepointBitmap(&info, scale, scale, codepoint, width, height, xoff, yoff);
+ return bitmap;
+ }
+
+ Color* TTFData::getCodepointBitmap(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const
+ {
+ float scale = scales.back();
+ Channel* bitmap = stbtt_GetCodepointBitmap(&info, scale, scale, codepoint, width, height, xoff, yoff);
+ int w = *width, h = *height;
+ //int xo = *xoff, yo = *yoff;
+ Color* bitmap32 = new Color[w*h];
+ for (int y = 0; y < h; ++y)
+ {
+ for (int x = 0; x < w; ++x)
+ {
+ bitmap32[x + y * w].set(0xff, 0xff, 0xff, bitmap[x + y * w]);
+ }
+ }
+ free(bitmap);
+ return bitmap32;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // TTF
+ /////////////////////////////////////////////////////////////////////////////
+
+ #include "../shader/je_font.shader.h"
+
+ using namespace std;
+ using namespace JinEngine::Math;
+
+ const int TTF::TEXTURE_WIDTHS[] = { 128, 256, 256, 512, 512, 1024, 1024 };
+ const int TTF::TEXTURE_HEIGHTS[] = { 128, 128, 256, 256, 512, 512, 1024 };
+
+ /* little endian unicode */
+ static const char* unicodeLittleEndian(const char* p, unsigned* res)
+ {
+ }
+
+ ///*static*/ TTF* TTF::createTTF(TTFData* fontData, unsigned int fontSzie)
+ //{
+ // TTF* ttf;
+ // try
+ // {
+ // ttf = new TTF(fontData, fontSzie);
+ // }
+ // catch (...)
+ // {
+ // return nullptr;
+ // }
+ // return ttf;
+ //}
+
+ TTF::TTF(TTFData* f, unsigned int fontSize)
+ : Font(fontSize)
+ , cursor(0, 0)
+ , ttf(f)
+ {
+ ttf->pushTTFsize(fontSize);
+ ttf->getVMetrics(&baseline, &descent);
+ estimateSize();
+ ttf->popTTFsize();
+ /* create a default texture */
+ createAtlas();
+ }
+
+ /* estimate the size of atlas texture */
+ void TTF::estimateSize()
+ {
+ for (int level = 0; level <= TEXTURE_SIZE_LEVEL_MAX; ++level)
+ {
+ if (descent * (descent*0.8) * 96 <= TEXTURE_WIDTHS[level] * TEXTURE_HEIGHTS[level])
+ {
+ textureWidth = TEXTURE_WIDTHS[level];
+ textureHeight = TEXTURE_HEIGHTS[level];
+ break;
+ }
+ }
+ }
+
+ TTF::~TTF()
+ {
+ }
+
+ GLuint TTF::createAtlas()
+ {
+ GLuint t;
+ gl.flushError();
+ t = gl.genTexture();
+ gl.bindTexture(t);
+ gl.setTexParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl.setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl.setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ gl.setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ gl.texImage(GL_RGBA8, textureWidth, textureHeight, GL_RGBA, GL_UNSIGNED_BYTE);
+ if (glGetError() != GL_NO_ERROR)
+ {
+ glDeleteTextures(1, &t);
+ gl.bindTexture(0);
+ return 0;
+ }
+ atlases.push_back(t);
+ gl.bindTexture(0);
+ return t;
+ }
+
+ void TTF::print(const Content& t, int x, int y, int lineheight, int spacing)
+ {
+ Page* page = typeset(t, lineheight, spacing);
+ print(page, x, y);
+ delete page;
+ }
+
+ Page* TTF::typeset(const Content& text, int lineheight, int spacing)
+ {
+ Page* page = new Page();
+ page->font = this;
+ vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist;
+ vector<GlyphVertex>& glyphvertices = page->glyphvertices;
+ int texture = -1;
+ TTFGlyph* glyph = nullptr;
+ GlyphVertex vertex;
+ Vector2<int> p(0, 0);
+ int i = 0;
+
+ #define glyphvertices_push(_x, _y, _u, _v) \
+ vertex.x = _x; vertex.y = _y;\
+ vertex.u = _u; vertex.v = _v;\
+ glyphvertices.push_back(vertex);
+
+ #define glyphlize(c)\
+ do{\
+ glyph = &findGlyph(c); \
+ if (texture != glyph->atlas) \
+ { \
+ GlyphArrayDrawInfo info; \
+ info.start = i; \
+ info.count = 0; \
+ info.texture = glyph->atlas; \
+ texture = glyph->atlas; \
+ glyphinfolist.push_back(info); \
+ } \
+ glyphinfolist[glyphinfolist.size() - 1].count += 4; \
+ TTFGlyph::Bbox& bbox = glyph->bbox; \
+ glyphvertices_push(p.x, p.y, bbox.x, bbox.y); \
+ glyphvertices_push(p.x, p.y + glyph->height, bbox.x, bbox.y + bbox.h); \
+ glyphvertices_push(p.x + glyph->width, p.y + glyph->height, bbox.x + bbox.w, bbox.y + bbox.h); \
+ glyphvertices_push(p.x + glyph->width, p.y, bbox.x + bbox.w, bbox.y); \
+ }while(0)
+
+ for (Codepoint c : text)
+ {
+ if (c == 0x0D)
+ continue;
+ if (c == 0x0A)
+ {
+ /* new line */
+ p.y += lineheight;
+ p.x = 0;
+ continue;
+ }
+ if (c == 0x09)
+ {
+ // tab = 4*space
+ unsigned cw = getCharWidth(0x20);
+ p.x += cw * 4;
+ continue;
+ }
+ glyphlize(c);
+ p.x += glyph->width + spacing;
+ i += 4;
+ }
+ getTextBox(text, &page->size.w, &page->size.h, lineheight, spacing);
+ return page;
+ }
+
+ Page* TTF::typeset(const Text& text, int lineheight, int spacing)
+ {
+ return typeset(*text, lineheight, spacing);
+ }
+
+ void TTF::print(const Page* page, int x, int y)
+ {
+ Shader* shader = Shader::getCurrentShader();
+ const vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist;
+ const vector<GlyphVertex>& glyphvertices = page->glyphvertices;
+ gl.ModelMatrix.setTransformation(x, y, 0, 1, 1, 0, 0);
+ shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix);
+ shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix);
+ for (int i = 0; i < glyphinfolist.size(); ++i)
+ {
+ const GlyphArrayDrawInfo& info = glyphinfolist[i];
+ shader->bindVertexPointer(2, GL_INT, sizeof(GlyphVertex), &glyphvertices[info.start].x);
+ shader->bindUVPointer(2, GL_FLOAT, sizeof(GlyphVertex), &glyphvertices[info.start].u);
+ gl.bindTexture(info.texture);
+ gl.drawArrays(GL_QUADS, 0, info.count);
+ gl.bindTexture(0);
+ }
+ }
+
+ void TTF::print(const Text& text, int x, int y, int lineheight, int spacing /* = 0 */)
+ {
+ print(*text, x, y, lineheight, spacing);
+ }
+
+ int TTF::getCharWidth(int c)
+ {
+ int adw, lsb;
+ ttf->pushTTFsize(mFontSize);
+ ttf->getHMetrics(c, &adw, &lsb);
+ ttf->popTTFsize();
+ return adw;
+ }
+
+ int TTF::getCharHeight(int c)
+ {
+ return descent;
+ }
+
+ int TTF::getTextWidth(const Content& t, int spacing)
+ {
+ ttf->pushTTFsize(mFontSize);
+ int res = 0;
+ int tmp = 0;
+ for (Codepoint c : t)
+ {
+ if (c == 0x0D)
+ continue;
+ if (c == 0x0A)
+ {
+ tmp = 0;
+ continue;
+ }
+ tmp += getCharWidth(c) + spacing;
+ if (tmp > res)
+ res = tmp;
+ }
+ ttf->popTTFsize();
+ return res;
+ }
+
+ int TTF::getTextHeight(const Content& t, int lineheight)
+ {
+ ttf->pushTTFsize(mFontSize);
+ int res = 0;
+ bool newline = true;
+ for (Codepoint c : t)
+ {
+ if (c == 0x0A)
+ newline = true;
+ else if (c == 0x0D);
+ else if (newline)
+ {
+ newline = false;
+ res += lineheight;
+ }
+ }
+ ttf->popTTFsize();
+ return res;
+ }
+
+ void TTF::getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing)
+ {
+ ttf->pushTTFsize(mFontSize);
+ *w = 0;
+ *h = 0;
+ int tmp = 0;
+ bool newline = true;
+ for (Codepoint c : text)
+ {
+ if (c == 0x0D)
+ continue;
+ if (c == 0x0A)
+ {
+ tmp = 0;
+ newline = true;
+ continue;
+ }
+ else if (newline)
+ {
+ newline = false;
+ *h += lineheight;
+ }
+ tmp += getCharWidth(c) + spacing;
+ if (tmp > *w)
+ *w = tmp;
+ }
+ ttf->popTTFsize();
+ }
+
+ TTF::TTFGlyph& TTF::bakeGlyph(unsigned int character)
+ {
+ int w, h, xoff, yoff;
+ ttf->pushTTFsize(mFontSize);
+ GLuint atlas = atlases.back();
+ const Color* bitmap = ttf->getCodepointBitmap(character, &w, &h, &xoff, &yoff);
+ int adw, lsb;
+ {
+ /* bake glyph */
+ ttf->getHMetrics(character, &adw, &lsb);
+ ttf->popTTFsize();
+ if (cursor.x + adw > textureWidth )
+ {
+ cursor.x = 0;
+ cursor.y += descent;
+ if (cursor.y + descent * 2 > textureHeight)
+ {
+ /* create new atlas */
+ atlas = createAtlas();
+ cursor.y = 0;
+ }
+ }
+ gl.bindTexture(atlas);
+ gl.texSubImage(cursor.x + xoff, cursor.y + yoff + baseline, w, h, GL_RGBA, GL_UNSIGNED_BYTE, bitmap);
+ gl.bindTexture();
+ delete[] bitmap;
+ }
+ TTFGlyph glyph;
+ glyph.atlas = atlas;
+ glyph.bbox.x = cursor.x / (float)textureWidth;
+ glyph.bbox.y = cursor.y / (float)textureHeight;
+ glyph.bbox.w = adw / (float)textureWidth;
+ glyph.bbox.h = descent / (float)textureHeight;
+ glyph.width = adw;
+ glyph.height = descent;
+ glyphs.insert(std::pair<unsigned int, TTFGlyph>(character, glyph));
+ cursor.x += adw;
+ return glyphs[character];
+ }
+
+ TTF::TTFGlyph& TTF::findGlyph(unsigned int character)
+ {
+ map<unsigned int, TTFGlyph>::iterator it = glyphs.find(character);
+ if (it != glyphs.end())
+ return it->second;
+ else
+ return bakeGlyph(character);
+ }
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // defined(jin_graphics) \ No newline at end of file
diff --git a/src/libjin/Graphics/Font/je_ttf.h b/src/libjin/Graphics/Font/je_ttf.h
new file mode 100644
index 0000000..e3d63b2
--- /dev/null
+++ b/src/libjin/Graphics/Font/je_ttf.h
@@ -0,0 +1,288 @@
+#ifndef __JETTF_H
+#define __JE_TTF_H
+#include "../../core/je_configuration.h"
+#if defined(jin_graphics)
+
+#include <vector>
+#include <map>
+
+#include "../../3rdparty/stb/stb_truetype.h"
+#include "../../math/je_quad.h"
+
+#include "../je_color.h"
+#include "../je_graphic.h"
+
+#include "je_page.h"
+#include "je_font.h"
+#include "je_text.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ class TTF;
+
+ //
+ // TTFData
+ // |- TTF(14px)
+ // |- TTF(15px)
+ // .
+ // .
+ // .
+ //
+ class TTFData
+ {
+ public:
+
+ ///
+ ///
+ ///
+ static TTFData* createTTFData(const unsigned char* data, unsigned int size);
+
+ ///
+ ///
+ ///
+ ~TTFData();
+
+ ///
+ ///
+ ///
+ TTF* createTTF(unsigned ttfsize);
+
+ ///
+ ///
+ ///
+ void pushTTFsize(unsigned ttfsize);
+
+ ///
+ ///
+ ///
+ void popTTFsize();
+
+ ///
+ ///
+ ///
+ Channel* getCodepointBitmapAlpha(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const;
+
+ ///
+ ///
+ ///
+ Color* getCodepointBitmap(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const;
+
+ ///
+ ///
+ ///
+ void getVMetrics(int* baseline, int* descent);
+
+ ///
+ ///
+ ///
+ void getHMetrics(unsigned int codepoint, int* advanceWidth, int* leftSideBearing);
+
+ private:
+
+ ///
+ ///
+ ///
+ static const unsigned int FONT_SIZE = 12;
+
+ ///
+ ///
+ ///
+ TTFData(const unsigned char* data, unsigned int size);
+
+ ///
+ ///
+ ///
+ stbtt_fontinfo info;
+
+ ///
+ ///
+ ///
+ struct
+ {
+ unsigned char* data;
+ unsigned int size;
+ } raw;
+
+ ///
+ ///
+ ///
+ std::vector<float> scales;
+
+ };
+
+ class TTF : public Font
+ {
+ public:
+ //static TTF* createTTF(TTFData* ttfData, unsigned ttfSzie);
+
+ ///
+ ///
+ ///
+ Page* typeset(const Text& text, int lineheight, int spacing = 0) override;
+
+ ///
+ ///
+ ///
+ Page* typeset(const Content& text, int lineheight, int spacing = 0) override;
+
+ ///
+ ///
+ ///
+ void print(const Text& text, int x, int y, int lineheight, int spacing = 0) override;
+
+ ///
+ ///
+ ///
+ void print(const Content& text, int x, int y, int lineheight, int spacing = 0) override;
+
+ ///
+ ///
+ ///
+ void print(const Page* page, int x, int y) override;
+
+ ///
+ ///
+ ///
+ ~TTF();
+
+ private:
+
+ friend class TTFData;
+
+ ///
+ ///
+ ///
+ struct TTFGlyph
+ {
+ GLuint atlas;
+ // normalized coordinates
+ struct Bbox
+ {
+ float x, y;
+ float w, h;
+ } bbox;
+ // glyph size in pixel
+ unsigned int width, height;
+ };
+
+ ///
+ ///
+ ///
+ static const int TEXTURE_SIZE_LEVELS_COUNT = 7;
+
+ ///
+ ///
+ ///
+ static const int TEXTURE_SIZE_LEVEL_MAX = TEXTURE_SIZE_LEVELS_COUNT - 1;
+
+ ///
+ ///
+ ///
+ static const int TEXTURE_WIDTHS[TEXTURE_SIZE_LEVELS_COUNT];
+
+ ///
+ ///
+ ///
+ static const int TEXTURE_HEIGHTS[TEXTURE_SIZE_LEVELS_COUNT];
+
+ ///
+ ///
+ ///
+ TTF(TTFData* ttf, Codepoint ttfSize);
+
+ ///
+ ///
+ ///
+ void estimateSize();
+
+ ///
+ ///
+ ///
+ GLuint createAtlas();
+
+ ///
+ ///
+ ///
+ TTFGlyph& bakeGlyph(Codepoint character);
+
+ ///
+ ///
+ ///
+ TTFGlyph& findGlyph(Codepoint character);
+
+ ///
+ ///
+ ///
+ int getCharWidth(int c);
+
+ ///
+ ///
+ ///
+ int getCharHeight(int c);
+
+ ///
+ ///
+ ///
+ int getTextWidth(const Content& text, int spacing = 0);
+
+ ///
+ ///
+ ///
+ int getTextHeight(const Content& text, int lineheight);
+
+ ///
+ ///
+ ///
+ void getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing = 0);
+
+ ///
+ ///
+ ///
+ int textureWidth;
+
+ ///
+ ///
+ ///
+ int textureHeight;
+
+ ///
+ ///
+ ///
+ std::vector<GLuint> atlases;
+
+ ///
+ ///
+ ///
+ std::map<Codepoint, TTFGlyph> glyphs;
+
+ ///
+ ///
+ ///
+ TTFData* ttf;
+
+ ///
+ ///
+ ///
+ int baseline;
+
+ ///
+ ///
+ ///
+ int descent;
+
+ ///
+ ///
+ ///
+ Math::Vector2<float> cursor;
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // defined(jin_graphics)
+
+#endif // __JE_FONT_H \ No newline at end of file
diff --git a/src/libjin/Graphics/Graphics.h b/src/libjin/Graphics/Graphics.h
deleted file mode 100644
index 210dadf..0000000
--- a/src/libjin/Graphics/Graphics.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef __JIN_GRAPHICS_H
-#define __JIN_GRAPHICS_H
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include "canvas.h"
-#include "color.h"
-#include "font.h"
-#include "Shapes.h"
-#include "texture.h"
-#include "jsl.h"
-#include "window.h"
-
-#endif // JIN_MODULES_RENDER
-#endif // __JIN_GRAPHICS_H \ No newline at end of file
diff --git a/src/libjin/Graphics/JSL.cpp b/src/libjin/Graphics/JSL.cpp
deleted file mode 100644
index 2ab7ceb..0000000
--- a/src/libjin/Graphics/JSL.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include "../utils/macros.h"
-#include "jsl.h"
-namespace jin
-{
-namespace graphics
-{
- //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 Canvas sampler2D \n"
- "#define Color vec4 \n"
- "#define Texel texture2D \n"
- "#define extern uniform \n"
- "uniform Image _tex0_; \n"
- "%s \n"
- "void main(){ \n"
- " gl_FragColor = effect(gl_Color, _tex0_, gl_TexCoord[0].xy, gl_FragCoord.xy);\n"
- "}\0";
-
- /*static*/ JSLProgram* JSLProgram::currentJSLProgram = nullptr;
-
- JSLProgram* JSLProgram::createJSLProgram(const char* program)
- {
- return new JSLProgram(program);
- }
-
- JSLProgram::JSLProgram(const char* program)
- : currentTextureUnit(0)
- {
- initialize(program);
- }
-
- JSLProgram::~JSLProgram()
- {
- destroy();
- }
-
- inline void JSLProgram::destroy()
- {
- if (currentJSLProgram == this)
- unuse();
- }
-
- inline void JSLProgram::initialize(const char* program)
- {
- 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);
- }
-
- static inline GLint getMaxTextureUnits()
- {
- GLint maxTextureUnits = 0;
- glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
- return maxTextureUnits;
- }
-
- GLint JSLProgram::getTextureUnit(const std::string& name)
- {
- std::map<std::string, GLint>::iterator texture_unit = texturePool.find(name);
- if (texture_unit != texturePool.end())
- return texture_unit->second;
- static GLint maxTextureUnits = getMaxTextureUnits();
- if (++currentTextureUnit >= maxTextureUnits)
- return 0;
- texturePool[name] = currentTextureUnit;
- return currentTextureUnit;
- }
-
-#define checkJSL() if (currentJSLProgram != this) return
-
- void JSLProgram::sendFloat(const char* variable, float number)
- {
- checkJSL();
-
- int loc = glGetUniformLocation(pid, variable);
- glUniform1f(loc, number);
- }
-
- void JSLProgram::sendTexture(const char* variable, const Texture* tex)
- {
- checkJSL();
-
- GLint location = glGetUniformLocation(pid, variable);
- if (location == -1)
- return;
- GLint texture_unit = getTextureUnit(variable);
- glUniform1i(location, texture_unit);
- glActiveTexture(GL_TEXTURE0 + texture_unit);
- glBindTexture(GL_TEXTURE_2D, tex->getTexture());
- glActiveTexture(GL_TEXTURE0);
- }
-
- void JSLProgram::sendCanvas(const char* variable, const Canvas* canvas)
- {
- checkJSL();
-
- GLint location = glGetUniformLocation(pid, variable);
- if (location == -1)
- return;
- GLint texture_unit = getTextureUnit(variable);
- glUniform1i(location, texture_unit);
- glActiveTexture(GL_TEXTURE0 + texture_unit);
- glBindTexture(GL_TEXTURE_2D, canvas->getTexture());
- glActiveTexture(GL_TEXTURE0);
- }
-
- void JSLProgram::sendVec2(const char* name, float x, float y)
- {
- checkJSL();
-
- int loc = glGetUniformLocation(pid, name);
- glUniform2f(loc, x, y);
- }
-
- void JSLProgram::sendVec3(const char* name, float x, float y, float z)
- {
- checkJSL();
-
- int loc = glGetUniformLocation(pid, name);
- glUniform3f(loc, x, y, z);
- }
-
- void JSLProgram::sendVec4(const char* name, float x, float y, float z, float w)
- {
- checkJSL();
-
- int loc = glGetUniformLocation(pid, name);
- glUniform4f(loc, x, y, z, w);
- }
-
- void JSLProgram::sendColor(const char* name, const color* col)
- {
- checkJSL();
-
- int loc = glGetUniformLocation(pid, name);
- glUniform4f(loc,
- col->rgba.r / 255.f,
- col->rgba.g / 255.f,
- col->rgba.b / 255.f,
- col->rgba.a / 255.f
- );
- }
-
-}
-}
-
-#endif // JIN_MODULES_RENDER \ No newline at end of file
diff --git a/src/libjin/Graphics/JSL.h b/src/libjin/Graphics/JSL.h
deleted file mode 100644
index 8d4712b..0000000
--- a/src/libjin/Graphics/JSL.h
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef __JIN_JSL_H
-#define __JIN_JSL_H
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include <string>
-#include <map>
-#include "color.h"
-#include "texture.h"
-#include "canvas.h"
-#include "../3rdparty/GLee/GLee.h"
-
-namespace jin
-{
-namespace graphics
-{
-
- class JSLProgram
- {
-
- public:
-
- static JSLProgram* createJSLProgram(const char* program);
-
- virtual ~JSLProgram();
-
- inline void use()
- {
- glUseProgram(pid);
- currentJSLProgram = this;
- }
-
- static inline void unuse()
- {
- glUseProgram(0);
- currentJSLProgram = nullptr;
- }
-
- void sendFloat(const char* name, float number);
- void sendTexture(const char* name, const Texture* image);
- void sendVec2(const char* name, float x, float y);
- void sendVec3(const char* name, float x, float y, float z);
- void sendVec4(const char* name, float x, float y, float z, float w);
- void sendCanvas(const char* name, const Canvas* canvas);
- void sendColor(const char* name, const color* col);
-
- static inline JSLProgram* getCurrentJSL()
- {
- return currentJSLProgram;
- }
-
- protected:
-
- JSLProgram(const char* program);
-
- static JSLProgram* currentJSLProgram;
-
- GLuint pid;
-
- std::map<std::string, GLint> texturePool;
-
- GLint currentTextureUnit;
- GLint getTextureUnit(const std::string& name);
-
- inline void initialize(const char* program);
- inline void destroy();
-
- };
-
-}
-}
-
-#endif // JIN_MODULES_RENDER
-#endif // __JIN_JSL_H \ No newline at end of file
diff --git a/src/libjin/Graphics/Shader/je_base.shader.h b/src/libjin/Graphics/Shader/je_base.shader.h
new file mode 100644
index 0000000..d6f9d7b
--- /dev/null
+++ b/src/libjin/Graphics/Shader/je_base.shader.h
@@ -0,0 +1,88 @@
+#ifndef __JE_BASE_SHADER_H
+#define __JE_BASE_SHADER_H
+
+static const char* base_shared = R"(
+#define Number float
+#define Texture sampler2D
+#define Canvas sampler2D
+#define Color vec4
+#define Vec2 vec2
+#define Vec3 vec3
+#define Vec4 vec4
+
+#define texel texture2D
+
+struct Vertex
+{
+ vec2 xy;
+ vec2 uv;
+};
+
+)";
+
+static const int BASE_SHARED_SIZE = strlen(base_shared);
+
+static const char* base_vertex = R"(
+#version 130 core
+
+%s
+
+uniform mat4 jin_ProjectionMatrix;
+uniform mat4 jin_ModelMatrix;
+
+in vec2 jin_VertexCoords;
+in vec2 jin_TextureCoords;
+
+out vec4 jin_Color;
+out vec2 jin_XY;
+out vec2 jin_UV;
+
+%s
+
+void main()
+{
+ vec4 v = jin_ModelMatrix * vec4(jin_VertexCoords, 0, 1.0);
+ Vertex _v = vert(Vertex(v.xy, jin_TextureCoords));
+ gl_Position = jin_ProjectionMatrix * vec4(_v.xy, 0, 1.0f);
+ jin_Color = gl_Color;
+ jin_XY = _v.xy;
+ jin_UV = _v.uv;
+}
+)";
+
+static const int BASE_VERTEX_SHADER_SIZE = strlen(base_vertex) + BASE_SHARED_SIZE;
+
+#define formatVertexShader(buf, program) sprintf(buf,base_vertex, base_shared, program)
+
+static const char* base_fragment = R"(
+#version 130 core
+
+%s
+
+uniform Texture jin_MainTexture;
+
+in vec4 jin_Color;
+in vec2 jin_XY;
+in vec2 jin_UV;
+
+out vec4 jin_OutColor;
+
+%s
+
+void main()
+{
+ jin_OutColor = frag(jin_Color, jin_MainTexture, Vertex(jin_XY, jin_UV));
+}
+)";
+
+static const int BASE_FRAGMENT_SHADER_SIZE = strlen(base_fragment) + BASE_SHARED_SIZE;
+
+#define formatFragmentShader(buf, program) sprintf(buf, base_fragment, base_shared, program)
+
+static const char* SHADER_PROJECTION_MATRIX = "jin_ProjectionMatrix";
+static const char* SHADER_MODEL_MATRIX = "jin_ModelMatrix";
+static const char* SHADER_MAIN_TEXTURE = "jin_MainTexture";
+static const char* SHADER_VERTEX_COORDS = "jin_VertexCoords";
+static const char* SHADER_TEXTURE_COORDS = "jin_TextureCoords";
+
+#endif // __JE_BASE_SHADER_H \ No newline at end of file
diff --git a/src/libjin/Graphics/Shader/je_default.shader.h b/src/libjin/Graphics/Shader/je_default.shader.h
new file mode 100644
index 0000000..3f57c44
--- /dev/null
+++ b/src/libjin/Graphics/Shader/je_default.shader.h
@@ -0,0 +1,21 @@
+// Ĭshader
+static const char* default_shader = R"(
+
+#VERTEX_SHADER
+
+Vertex vert(Vertex v)
+{
+ return v;
+}
+
+#END_VERTEX_SHADER
+
+#FRAGMENT_SHADER
+
+Color frag(Color col, Texture tex, Vertex v)
+{
+ return col * texel(tex, v.uv);
+}
+
+#END_FRAGMENT_SHADER
+)"; \ No newline at end of file
diff --git a/src/libjin/Graphics/Shader/je_font.shader.h b/src/libjin/Graphics/Shader/je_font.shader.h
new file mode 100644
index 0000000..e04c225
--- /dev/null
+++ b/src/libjin/Graphics/Shader/je_font.shader.h
@@ -0,0 +1,21 @@
+// shader
+static const char* font_shader = R"(
+
+#VERTEX_SHADER
+
+Vertex vert(Vertex v)
+{
+ return v;
+}
+
+#END_VERTEX_SHADER
+
+#FRAGMENT_SHADER
+
+Color frag(Color col, Texture tex, Vertex v)
+{
+ return Color(col.rgb, texel(tex, v.uv).a);
+}
+
+#END_FRAGMENT_SHADER
+)"; \ No newline at end of file
diff --git a/src/libjin/Graphics/Shader/je_jsl_compiler.cpp b/src/libjin/Graphics/Shader/je_jsl_compiler.cpp
new file mode 100644
index 0000000..81b14e8
--- /dev/null
+++ b/src/libjin/Graphics/Shader/je_jsl_compiler.cpp
@@ -0,0 +1,54 @@
+#include "../../core/je_configuration.h"
+#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader)
+
+#include "../../Filesystem/je_buffer.h"
+
+#include "je_jsl_compiler.h"
+
+using namespace std;
+using namespace JinEngine::Filesystem;
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+#include "je_base.shader.h"
+
+ bool JSLCompiler::compile(const string& jsl, string* vertex_shader, string* fragment_shader)
+ {
+ // parse shader source, need some optimizations
+ int loc_VERTEX_SHADER = jsl.find("#VERTEX_SHADER");
+ int loc_END_VERTEX_SHADER = jsl.find("#END_VERTEX_SHADER");
+ int loc_FRAGMENT_SHADER = jsl.find("#FRAGMENT_SHADER");
+ int loc_END_FRAGMENT_SHADER = jsl.find("#END_FRAGMENT_SHADER");
+ if (loc_VERTEX_SHADER == string::npos
+ || loc_END_VERTEX_SHADER == string::npos
+ || loc_FRAGMENT_SHADER == string::npos
+ || loc_END_FRAGMENT_SHADER == string::npos
+ )
+ return false;
+ // Load vertex and fragment shader source into buffers.
+ {
+ // Compile JSL vertex program.
+ int start = loc_VERTEX_SHADER + strlen("#VERTEX_SHADER");
+ *vertex_shader = jsl.substr(start, loc_END_VERTEX_SHADER - start);
+ Buffer vbuffer = Buffer(vertex_shader->length() + BASE_VERTEX_SHADER_SIZE);
+ formatVertexShader((char*)&vbuffer, vertex_shader->c_str());
+ vertex_shader->assign((char*)&vbuffer);
+ }
+ {
+ // Compile JSL fragment program.
+ int start = loc_FRAGMENT_SHADER + strlen("#FRAGMENT_SHADER");
+ *fragment_shader = jsl.substr(start, loc_END_FRAGMENT_SHADER - start);
+ Buffer fbuffer = Buffer(fragment_shader->length() + BASE_FRAGMENT_SHADER_SIZE);
+ formatFragmentShader((char*)&fbuffer, fragment_shader->c_str());
+ fragment_shader->assign((char*)&fbuffer);
+ }
+ return true;
+ }
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader) \ No newline at end of file
diff --git a/src/libjin/Graphics/Shader/je_jsl_compiler.h b/src/libjin/Graphics/Shader/je_jsl_compiler.h
new file mode 100644
index 0000000..29129e1
--- /dev/null
+++ b/src/libjin/Graphics/Shader/je_jsl_compiler.h
@@ -0,0 +1,42 @@
+#ifndef __JE_JSL_COMPILER_H
+#define __JE_JSL_COMPILER_H
+
+#include "../../core/je_configuration.h"
+#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader)
+
+#include <string>
+
+#include "../../common/je_singleton.hpp"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ ///
+ /// Compile JSL into GLSL.
+ ///
+ class JSLCompiler : public Singleton<JSLCompiler>
+ {
+ public:
+ ///
+ /// Compile JSL shader source into GLSL.
+ ///
+ /// @param jsl JSL shader source.
+ /// @param glsl_vertex Output of vertex glsl shader source.
+ /// @param glsl_fragment Output of fragment glsl shader source.
+ /// @return True if compile successful, otherwise return false.
+ ///
+ bool compile(const std::string& jsl, std::string* glsl_vertex, std::string* glsl_fragment);
+
+ private:
+ singleton(JSLCompiler);
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader)
+
+#endif // __JE_JSL_COMPILER_H \ No newline at end of file
diff --git a/src/libjin/Graphics/Shader/je_shader.cpp b/src/libjin/Graphics/Shader/je_shader.cpp
new file mode 100644
index 0000000..b0e7506
--- /dev/null
+++ b/src/libjin/Graphics/Shader/je_shader.cpp
@@ -0,0 +1,278 @@
+#include "../../core/je_configuration.h"
+#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader)
+
+#include <iostream>
+
+#include "../../filesystem/je_buffer.h"
+#include "../../utils/je_macros.h"
+
+#include "je_jsl_compiler.h"
+#include "je_shader.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ using namespace std;
+ using namespace JinEngine::Filesystem;
+
+ //
+ // default_texture
+ // base_shader
+ // SHADER_FORMAT_SIZE
+ // formatShader
+ //
+ #include "je_default.shader.h"
+
+ //
+ // https://stackoverflow.com/questions/27941496/use-sampler-without-passing-through-value
+ // The default value of a sampler variable is 0. From the GLSL 3.30 spec,
+ // section "4.3.5 Uniforms":
+ //
+ // The link time initial value is either the value of the variable's
+ // initializer, if present, or 0 if no initializer is present.Sampler
+ // types cannot have initializers.
+ //
+ // Since a value of 0 means that it's sampling from texture unit 0, it will
+ // work without ever setting the value as long as you bind your textures to
+ // unit 0. This is well defined behavior.
+ //
+ // Since texture unit 0 is also the default until you call glActiveTexture()
+ // with a value other than GL_TEXTURE0, it's very common to always use unit
+ // 0 as long as shaders do not need more than one texture.Which means that
+ // often times, setting the sampler uniforms is redundant for simple
+ // applications.
+ //
+ // I would still prefer to always set the values.If nothing else, it makes
+ // it clear to anybody reading your code that you really mean to sample from
+ // texture unit 0, and did not just forget to set the value.
+ //
+ const int DEFAULT_TEXTURE_UNIT = 0;
+
+ /*static*/ Shader* Shader::CurrentShader = nullptr;
+
+ Shader* Shader::createShader(const string& program)
+ {
+ Shader* shader = nullptr;
+ try
+ {
+ shader = new Shader(program);
+ }
+ catch(...)
+ {
+ return nullptr;
+ }
+ return shader;
+ }
+
+ Shader::Shader(const string& program)
+ : mCurrentTextureUnit(DEFAULT_TEXTURE_UNIT)
+ {
+ if (!compile(program))
+ throw 0;
+ }
+
+ Shader::~Shader()
+ {
+ if (CurrentShader == this)
+ unuse();
+ // delete shader program
+ glDeleteShader(mPID);
+ }
+
+ bool Shader::compile(const string& program)
+ {
+ string vertex_shader, fragment_shader;
+ // Compile JSL shader source into GLSL shader source.
+ JSLCompiler* compiler = JSLCompiler::get();
+ if (!compiler->compile(program, &vertex_shader, &fragment_shader))
+ {
+ return false;
+ }
+#define glsl(SHADER_MODE, SHADER, SRC) \
+do{ \
+const GLchar* src = SRC.c_str(); \
+glShaderSource(SHADER, 1, &src, NULL); \
+glCompileShader(SHADER); \
+GLint success; \
+glGetShaderiv(SHADER, GL_COMPILE_STATUS, &success); \
+if (success == GL_FALSE) \
+ return false; \
+}while(0)
+ // Compile vertex shader.
+ GLuint vid = glCreateShader(GL_VERTEX_SHADER);
+ glsl(GL_VERTEX_SHADER, vid, vertex_shader);
+ // Compile fragment shader.
+ GLuint fid = glCreateShader(GL_FRAGMENT_SHADER);
+ glsl(GL_FRAGMENT_SHADER, fid, fragment_shader);
+#undef glsl
+ // Create OpenGL shader program.
+ mPID = glCreateProgram();
+ glAttachShader(mPID, vid);
+ glAttachShader(mPID, fid);
+ glLinkProgram(mPID);
+ GLint success;
+ glGetProgramiv(mPID, GL_LINK_STATUS, &success);
+ if (success == GL_FALSE)
+ return false;
+ }
+
+ static inline GLint getMaxTextureUnits()
+ {
+ GLint maxTextureUnits = 0;
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
+ return maxTextureUnits;
+ }
+
+ void Shader::use()
+ {
+ glUseProgram(mPID);
+ CurrentShader = this;
+ sendInt(SHADER_MAIN_TEXTURE, DEFAULT_TEXTURE_UNIT);
+ }
+
+ /*static*/ void Shader::unuse()
+ {
+ glUseProgram(0);
+ CurrentShader = nullptr;
+ }
+
+ GLint Shader::claimTextureUnit(const std::string& name)
+ {
+ std::map<std::string, GLint>::iterator unit = mTextureUnits.find(name);
+ if (unit != mTextureUnits.end())
+ return unit->second;
+ static GLint MAX_TEXTURE_UNITS = getMaxTextureUnits();
+ if (++mCurrentTextureUnit >= MAX_TEXTURE_UNITS)
+ return 0;
+ mTextureUnits[name] = mCurrentTextureUnit;
+ return mCurrentTextureUnit;
+ }
+
+ #define checkJSL() \
+ if (CurrentShader != this) \
+ return
+
+ void Shader::sendInt(const char* name, int value)
+ {
+ checkJSL();
+ int loc = glGetUniformLocation(mPID, name);
+ glUniform1i(loc, value);
+ }
+
+ void Shader::sendFloat(const char* variable, float number)
+ {
+ checkJSL();
+ int loc = glGetUniformLocation(mPID, variable);
+ glUniform1f(loc, number);
+ }
+
+ //
+ // https://www.douban.com/note/627332677/
+ // struct TextureUnit
+ // {
+ // GLuint targetTexture1D;
+ // GLuint targetTexture2D;
+ // GLuint targetTexture3D;
+ // GLuint targetTextureCube;
+ // ...
+ // };
+ //
+ // TextureUnit mTextureUnits[GL_MAX_TEXTURE_IMAGE_UNITS]
+ // GLuint mCurrentTextureUnit = 0;
+ //
+ void Shader::sendTexture(const char* variable, const Texture* tex)
+ {
+ checkJSL();
+ GLint location = glGetUniformLocation(mPID, variable);
+ if (location == -1)
+ return;
+ GLint unit = claimTextureUnit(variable);
+ if (unit == 0)
+ {
+ // TODO: 쳣󶨵
+ return;
+ }
+ gl.activeTexUnit(unit);
+ glUniform1i(location, unit);
+ gl.bindTexture(tex->getTexture());
+ gl.activeTexUnit(0);
+ }
+
+ void Shader::sendCanvas(const char* variable, const Canvas* canvas)
+ {
+ checkJSL();
+ GLint location = glGetUniformLocation(mPID, variable);
+ if (location == -1)
+ return;
+ GLint unit = claimTextureUnit(variable);
+ if (unit == 0)
+ {
+ // TODO: 쳣󶨵
+ return;
+ }
+ glUniform1i(location, unit);
+ glActiveTexture(GL_TEXTURE0 + unit);
+ gl.bindTexture(canvas->getTexture());
+
+ glActiveTexture(GL_TEXTURE0);
+ }
+
+ void Shader::sendVec2(const char* name, float x, float y)
+ {
+ checkJSL();
+ int loc = glGetUniformLocation(mPID, name);
+ glUniform2f(loc, x, y);
+ }
+
+ void Shader::sendVec3(const char* name, float x, float y, float z)
+ {
+ checkJSL();
+ int loc = glGetUniformLocation(mPID, name);
+ glUniform3f(loc, x, y, z);
+ }
+
+ void Shader::sendVec4(const char* name, float x, float y, float z, float w)
+ {
+ checkJSL();
+ int loc = glGetUniformLocation(mPID, name);
+ glUniform4f(loc, x, y, z, w);
+ }
+
+ void Shader::sendColor(const char* name, const Color* col)
+ {
+ checkJSL();
+ int loc = glGetUniformLocation(mPID, name);
+ glUniform4f(loc,
+ col->r / 255.f,
+ col->g / 255.f,
+ col->b / 255.f,
+ col->a / 255.f
+ );
+ }
+
+ void Shader::sendMatrix4(const char* name, const Math::Matrix* mat4)
+ {
+ int loc = glGetUniformLocation(mPID, name);
+ glUniformMatrix4fv(loc, 1, GL_FALSE, mat4->getElements());
+ }
+
+ void Shader::bindVertexPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers)
+ {
+ GLint loc = glGetAttribLocation(mPID, SHADER_VERTEX_COORDS);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(loc, n, type, GL_FALSE, stride, pointers);
+ }
+
+ void Shader::bindUVPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers)
+ {
+ GLint loc = glGetAttribLocation(mPID, SHADER_TEXTURE_COORDS);
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(loc, n, type, GL_FALSE, stride, pointers);
+ }
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader) \ No newline at end of file
diff --git a/src/libjin/Graphics/Shader/je_shader.h b/src/libjin/Graphics/Shader/je_shader.h
new file mode 100644
index 0000000..928fb0a
--- /dev/null
+++ b/src/libjin/Graphics/Shader/je_shader.h
@@ -0,0 +1,200 @@
+#ifndef __JE_SHADER_H
+#define __JE_SHADER_H
+
+#include "../../core/je_configuration.h"
+#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader)
+
+#include <string>
+#include <map>
+
+#include "../../3rdparty/GLee/GLee.h"
+
+#include "../je_color.h"
+#include "../je_texture.h"
+#include "../je_canvas.h"
+
+#include "je_base.shader.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ ///
+ /// Built in shader program.
+ ///
+ /// Built in shader program written with custom shading language called JSL (jin
+ /// shading language). A JSL program is compiled into glsl, so most glsl built in
+ /// functions and structs are available in JSL.
+ ///
+ class Shader
+ {
+ public:
+ ///
+ /// Create shader program from source code.
+ ///
+ /// @param source The shader source code.
+ ///
+ static Shader* createShader(const std::string& source);
+
+ ///
+ /// Get current shader.
+ ///
+ /// @return Current used shader program.
+ ///
+ static inline Shader* getCurrentShader() { return CurrentShader; }
+
+ ///
+ /// Unuse current shader.
+ ///
+ static void unuse();
+
+ ///
+ /// Destructor of shader.
+ ///
+ virtual ~Shader();
+
+ ///
+ /// Use specific shader.
+ ///
+ void use();
+
+ ///
+ /// Send float value to shader.
+ ///
+ /// @param name Name of the uniform variable to be assigned.
+ /// @param number Value of uniform variable to be sent.
+ ///
+ void sendFloat(const char* name, float number);
+
+ ///
+ /// Send texture to shader.
+ ///
+ /// @param name Name of the uniform variable to be assigned.
+ /// @param texture Texture to be sent.
+ ///
+ void sendTexture(const char* name, const Texture* texture);
+
+ ///
+ /// Send integer value to shader
+ ///
+ /// @param name Name of the uniform variable to be assigned.
+ /// @param value Value to be sent.
+ ///
+ void sendInt(const char* name, int value);
+
+ ///
+ /// Send 2D vector to shader.
+ ///
+ /// @param name Name of the uniform variable to be assigned.
+ /// @param x X value of the vector to be sent.
+ /// @param y Y value of the vector to be sent.
+ ///
+ void sendVec2(const char* name, float x, float y);
+
+ ///
+ /// Send 3D vector to shader.
+ ///
+ /// @param name Name of the uniform variable to be assigned.
+ /// @param x X value of the vector to be sent.
+ /// @param y Y value of the vector to be sent.
+ /// @param z Z value of the vector to be sent.
+ ///
+ void sendVec3(const char* name, float x, float y, float z);
+
+ ///
+ /// Send 4D vector to shader.
+ ///
+ /// @param name Name of the uniform variable to be assigned.
+ /// @param x X value of the vector to be sent.
+ /// @param y Y value of the vector to be sent.
+ /// @param z Z value of the vector to be sent.
+ /// @param w W value of the vector to be sent.
+ ///
+ void sendVec4(const char* name, float x, float y, float z, float w);
+
+ ///
+ /// Send canvas to shader.
+ ///
+ /// @param name Name of the uniform variable to be assigned.
+ /// @param canvas Canvas to be sent.
+ ///
+ void sendCanvas(const char* name, const Canvas* canvas);
+
+ ///
+ /// Send color to shader.
+ ///
+ /// @param name Name of the uniform variable to be assigned.
+ /// @param color Color to be sent.
+ ///
+ void sendColor(const char* name, const Color* color);
+
+ ///
+ /// Send 4 by 4 matrix to shader.
+ ///
+ /// @param name Name of the uniform variable to be assigned.
+ /// @param mat4 Matrix to be sent.
+ ///
+ void sendMatrix4(const char* name, const Math::Matrix* mat4);
+
+ ///
+ /// Set vertices value.
+ ///
+ /// @param n Number of vertices.
+ /// @param type Data type of each component in the array.
+ /// @param stride Byte offset between consecutive generic vertex attributes.
+ /// @param pointers Pointer to the first component of the first generic vertex
+ /// attribute in the array.
+ ///
+ void bindVertexPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers);
+
+ ///
+ /// Set texture UV coordinates.
+ ///
+ /// @param n Number of vertices.
+ /// @param type Data type of each component in the array.
+ /// @param stride Byte offset between consecutive generic vertex attributes.
+ /// @param pointers Pointer to the first component of the first generic vertex
+ /// attribute in the array.
+ ///
+ void bindUVPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers);
+
+ protected:
+ ///
+ /// Reference of current used shader.
+ ///
+ static Shader* CurrentShader;
+
+ ///
+ /// Get texture unit of the uniform texture. If not, assign one.
+ ///
+ /// @param name Name of the texture uniform variable.
+ /// @return Texture unit which texture variable be assigned.
+ ///
+ GLint claimTextureUnit(const std::string& name);
+
+ ///
+ /// Shader constructor.
+ ///
+ Shader(const std::string& program);
+
+ ///
+ /// Compile JSL program into GLSL source.
+ ///
+ /// @param program JSL source code.
+ /// @return Return true if compile successed, otherwise return false.
+ ///
+ bool compile(const std::string& program);
+
+ GLuint mPID;
+ GLint mCurrentTextureUnit;
+ std::map<std::string, GLint> mTextureUnits;
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader)
+
+#endif // __JE_SHADER_H \ No newline at end of file
diff --git a/src/libjin/Graphics/Shader/je_texture.shader.h b/src/libjin/Graphics/Shader/je_texture.shader.h
new file mode 100644
index 0000000..d1fc86f
--- /dev/null
+++ b/src/libjin/Graphics/Shader/je_texture.shader.h
@@ -0,0 +1,21 @@
+// ͼshader
+static const char* texture_shader = R"(
+
+#VERTEX_SHADER
+
+Vertex vert(Vertex v)
+{
+ return v;
+}
+
+#END_VERTEX_SHADER
+
+#FRAGMENT_SHADER
+
+Color frag(Color col, Texture tex, Vertex v)
+{
+ return col * texel(tex, v.uv);
+}
+
+#END_FRAGMENT_SHADER
+)"; \ No newline at end of file
diff --git a/src/libjin/Graphics/Shapes.cpp b/src/libjin/Graphics/Shapes.cpp
deleted file mode 100644
index 4b136a1..0000000
--- a/src/libjin/Graphics/Shapes.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include "Shapes.h"
-#include "../math/matrix.h"
-#include "../math/constant.h"
-#include <string>
-
-namespace jin
-{
-namespace graphics
-{
-
- 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);
- }
- }
-
-}
-}
-
-#endif // JIN_MODULES_RENDER \ No newline at end of file
diff --git a/src/libjin/Graphics/Shapes.h b/src/libjin/Graphics/Shapes.h
deleted file mode 100644
index 742345e..0000000
--- a/src/libjin/Graphics/Shapes.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef __JIN_GRAPHICS_SHAPES_H
-#define __JIN_GRAPHICS_SHAPES_H
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include "color.h"
-#include "canvas.h"
-#include "texture.h"
-
-namespace jin
-{
-namespace graphics
-{
-
- 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 // JIN_MODULES_RENDER
-#endif // __JIN_GEOMETRY_H \ No newline at end of file
diff --git a/src/libjin/Graphics/Texture.cpp b/src/libjin/Graphics/Texture.cpp
deleted file mode 100644
index 4c6707d..0000000
--- a/src/libjin/Graphics/Texture.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include <fstream>
-#include "texture.h"
-#include "../3rdparty/stb/stb_image.h"
-#include "../utils/utils.h"
-#include "../Math/Math.h"
-
-namespace jin
-{
-namespace graphics
-{
-
- using namespace jin::math;
-
- Texture* Texture::createTexture(const char* file)
- {
- std::ifstream fs;
- fs.open(file, std::ios::binary);
- Texture* tex = nullptr;
- if (fs.is_open())
- {
- fs.seekg(0, std::ios::end);
- int size = fs.tellg();
- fs.seekg(0, std::ios::beg);
- char* buffer = (char*)malloc(size);
- memset(buffer, 0, size);
- fs.read(buffer, size);
- tex = createTexture(buffer, size);
- free(buffer);
- }
- fs.close();
- return tex;
- }
-
- Texture* Texture::createTexture(const void* mem, size_t size)
- {
- Texture* tex = new Texture();
- if(!tex->loadb(mem, size))
- {
- delete tex;
- tex = nullptr;
- }
- return tex;
- }
-
- Texture::Texture()
- : Drawable(), pixels(0)
- {
- }
-
- Texture::~Texture()
- {
- stbi_image_free(pixels);
- }
-
- color Texture::getPixel(int x, int y)
- {
- if (without(x, 0, width) || without(y, 0, height))
- {
- return { 0 };
- }
- return pixels[x + y * width];
- }
-
- bool Texture::loadb(const void* b, size_t size)
- {
- // ʹstbi_load_from_memory
- unsigned char* textureData = stbi_load_from_memory((unsigned char *)b, size, &width, &height, NULL, STBI_rgb_alpha);
- if (textureData == 0) return false;
- pixels = (color*)textureData;
-
- 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, textureData);
-
- // 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;
- }
-}
-}
-
-#endif // JIN_MODULES_RENDER \ No newline at end of file
diff --git a/src/libjin/Graphics/Texture.h b/src/libjin/Graphics/Texture.h
deleted file mode 100644
index 1fdb50d..0000000
--- a/src/libjin/Graphics/Texture.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef __JIN_IMAGE_H
-#define __JIN_IMAGE_H
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include "../3rdparty/GLee/GLee.h"
-#include "color.h"
-#include "drawable.h"
-namespace jin
-{
-namespace graphics
-{
-
- class Texture: public Drawable
- {
-
- public:
-
- static Texture* createTexture(const char* file);
- static Texture* createTexture(const void* mem, size_t size);
-
- static void destroyTexture(Texture* tex);
-
- ~Texture();
-
- color getPixel(int x, int y);
-
- private:
-
- Texture();
-
- bool loadb(const void* buffer, size_t size);
-
- color* pixels;
-
- };
-
-}
-}
-
-#endif // JIN_MODULES_RENDER
-#endif // __JIN_IMAGE_H \ No newline at end of file
diff --git a/src/libjin/Graphics/Window.cpp b/src/libjin/Graphics/Window.cpp
deleted file mode 100644
index 708a30f..0000000
--- a/src/libjin/Graphics/Window.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include <iostream>
-#include "window.h"
-#include "../3rdparty/GLee/GLee.h"
-#include "canvas.h"
-#include "../utils/utils.h"
-#include "../audio/sdl/SDLAudio.h"
-#include "../utils/log.h"
-
-namespace jin
-{
-namespace graphics
-{
-
- bool Window::initSystem(const SettingBase* s)
- {
-#if JIN_DEBUG
- Loghelper::log(Loglevel::LV_INFO, "Init window system");
-#endif // JIN_DEBUG
-
- if (SDL_Init(SDL_INIT_VIDEO) < 0)
- return false;
-
- const Setting* setting = (Setting*)s;
- width = setting->width;
- height = setting->height;
- fps = setting->fps;
- bool vsync = setting->vsync;
- const char* title = setting->title;
-
- if (wnd)
- {
- SDL_DestroyWindow(wnd);
- SDL_FlushEvent(SDL_WINDOWEVENT);
- }
-
- SDL_GLContext ctx = NULL;
-
- 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);
- SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-
- int wx = SDL_WINDOWPOS_UNDEFINED,
- wy = SDL_WINDOWPOS_UNDEFINED;
-
- int flag = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL;
- if (setting->fullscreen) flag |= SDL_WINDOW_FULLSCREEN;
- if (setting->resizable) flag |= SDL_WINDOW_RESIZABLE;
-
- wnd = SDL_CreateWindow(title, wx, wy, width, height, flag);
- if (wnd == NULL)
- return false;
- ctx = SDL_GL_CreateContext(wnd);
- if (ctx == NULL)
- return false;
- SDL_GL_SetSwapInterval(vsync ? 1 : 0);
- SDL_GL_MakeCurrent(wnd, ctx);
- glClearColor(0.f, 0.f, 0.f, 1.f);
- glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
- glColor4f(1, 1, 1, 1);
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- Canvas::unbind();
- swapBuffers();
- return true;
- }
-
- void Window::quitSystem()
- {
- SDL_DestroyWindow(wnd);
- SDL_Quit();
- }
-
- inline void Window::swapBuffers()
- {
- if (wnd)
- SDL_GL_SwapWindow(wnd);
- }
-
-} // graphics
-} // jin
-
-#endif // JIN_MODULES_RENDER \ No newline at end of file
diff --git a/src/libjin/Graphics/Window.h b/src/libjin/Graphics/Window.h
deleted file mode 100644
index e09e9f9..0000000
--- a/src/libjin/Graphics/Window.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef __JIN_RENDER_WINDOW
-#define __JIN_RENDER_WINDOW
-#include "../modules.h"
-#if JIN_MODULES_RENDER
-
-#include "SDL2/SDL.h"
-#include "../utils/utils.h"
-#include "../common/Subsystem.hpp"
-
-namespace jin
-{
-namespace graphics
-{
-
- class Window : public Subsystem<Window>
- {
- public:
-
- struct Setting : SettingBase
- {
- public:
- const char* title; //
- bool fullscreen; // ȫ
- int width, height; // ڴС
- bool vsync; // ֱͬ
- int fps; // FPS
- bool resizable; // resize
- };
-
- inline int getW(){ return width; }
- inline int getH(){ return height; }
- inline int getFPS(){ return fps; }
- inline void swapBuffers();
-
- private:
-
- Window() {};
- virtual ~Window() {};
-
- SINGLETON(Window);
-
- SDL_Window* wnd;
-
- int width, height;
- int fps;
-
- onlyonce bool initSystem(const SettingBase* setting) override;
- onlyonce void quitSystem() override;
- };
-
-} // render
-} // jin
-
-#endif // JIN_MODULES_RENDER
-#endif // __JIN_RENDER_WINDOW \ No newline at end of file
diff --git a/src/libjin/Graphics/animation/je_animation.cpp b/src/libjin/Graphics/animation/je_animation.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/libjin/Graphics/animation/je_animation.cpp
diff --git a/src/libjin/Graphics/animation/je_animation.h b/src/libjin/Graphics/animation/je_animation.h
new file mode 100644
index 0000000..f330a0c
--- /dev/null
+++ b/src/libjin/Graphics/animation/je_animation.h
@@ -0,0 +1,20 @@
+#ifndef __JE_ANIMATION_H
+#define __JE_ANIMATION_H
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ ///
+ ///
+ ///
+ class Animation
+ {
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif \ No newline at end of file
diff --git a/src/libjin/Graphics/animation/je_clip.cpp b/src/libjin/Graphics/animation/je_clip.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/libjin/Graphics/animation/je_clip.cpp
diff --git a/src/libjin/Graphics/animation/je_clip.h b/src/libjin/Graphics/animation/je_clip.h
new file mode 100644
index 0000000..d6709dc
--- /dev/null
+++ b/src/libjin/Graphics/animation/je_clip.h
@@ -0,0 +1,20 @@
+#ifndef __JE_CLIP_H
+#define __JE_CLIP_H
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ ///
+ /// Animation clip with key.
+ ///
+ class Clip
+ {
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif \ No newline at end of file
diff --git a/src/libjin/Graphics/je_bitmap.cpp b/src/libjin/Graphics/je_bitmap.cpp
new file mode 100644
index 0000000..0747f0b
--- /dev/null
+++ b/src/libjin/Graphics/je_bitmap.cpp
@@ -0,0 +1,162 @@
+#define STB_IMAGE_IMPLEMENTATION
+#include "../3rdparty/stb/stb_image.h"
+
+#include "../filesystem/je_asset_database.h"
+#include "../math/je_math.h"
+
+#include "je_bitmap.h"
+
+using namespace JinEngine::Filesystem;
+using namespace JinEngine::Math;
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ Bitmap* Bitmap::createBitmap(const char* path)
+ {
+ AssetDatabase* ad = AssetDatabase::get();
+ Buffer buffer;
+ ad->read(path, buffer);
+ return createBitmap(&buffer, buffer.size());
+ }
+
+ /* pixelbitmap */
+ Bitmap* Bitmap::createBitmap(const void* pixel, unsigned width, unsigned height)
+ {
+ Bitmap* bitmap = new Bitmap(width, height);
+ memcpy(bitmap->pixels, pixel, width*height * sizeof(Color));
+ return bitmap;
+ }
+
+ /*static*/ Bitmap* Bitmap::createBitmap(const void* imgData, size_t size)
+ {
+ if (imgData == nullptr)
+ return nullptr;
+ int w, h;
+ void* data = stbi_load_from_memory((unsigned char *)imgData, size, &w, &h, NULL, STBI_rgb_alpha);
+ if (data == nullptr)
+ return nullptr;
+ Bitmap* bitmap = new Bitmap();
+ bitmap->pixels = (Color*)data;
+ bitmap->width = w;
+ bitmap->height = h;
+ return bitmap;
+ }
+
+ /*static*/ Bitmap* Bitmap::createBitmap(int w, int h, Color color)
+ {
+ Bitmap* bitmap = new Bitmap(w, h);
+ if (color != Color::BLACK)
+ bitmap->setPixels(color);
+ return bitmap;
+ }
+
+ /*static */ Bitmap* Bitmap::clone(const Bitmap* bitmap)
+ {
+ Bitmap* b = new Bitmap();
+ int w = bitmap->getWidth();
+ int h = bitmap->getHeight();
+ b->resetPixels(bitmap->getPixels(), w, h);
+ return b;
+ }
+
+ Bitmap::Bitmap()
+ : width(0)
+ , height(0)
+ , pixels(nullptr)
+ {
+ }
+
+ Bitmap::Bitmap(unsigned w, unsigned h)
+ {
+ width = w;
+ height = h;
+ pixels = new Color[w*h];
+ }
+
+ Bitmap::~Bitmap()
+ {
+ stbi_image_free(pixels);
+ }
+
+ void Bitmap::bind(Color* p, int w, int h)
+ {
+ if (pixels != nullptr)
+ delete[] pixels;
+ pixels = p;
+ width = w;
+ height = h;
+ }
+
+ void Bitmap::resetPixels(const Color* p, int w, int h)
+ {
+ if (pixels != nullptr)
+ delete[] pixels;
+ pixels = new Color[w*h];
+ size_t s = w * h * sizeof(Color);
+ memcpy(pixels, p, s);
+ width = w;
+ height = h;
+ }
+
+ void Bitmap::setPixel(const Color& c, int x, int y)
+ {
+ if (pixels == nullptr)
+ return;
+ if (without<int>(x, 0, width - 1) || without<int>(y, 0, height - 1))
+ return;
+ pixels[x + y * width] = c;
+ }
+
+ void Bitmap::resetPixels(const Color& c, int w, int h)
+ {
+ if (pixels != nullptr)
+ delete[] pixels;
+ pixels = new Color[w*h];
+ size_t s = w * h * sizeof(Color);
+ width = w;
+ height = h;
+ for (int x = 0; x < w; ++x)
+ {
+ for (int y = 0; y < h; ++y)
+ {
+ pixels[x + y * w] = c;
+ }
+ }
+ }
+
+ void Bitmap::setPixels(Color* p)
+ {
+ size_t s = width * height * sizeof(Color);
+ memcpy(pixels, p, s);
+ }
+
+ void Bitmap::setPixels(Color c)
+ {
+ for (int x = 0; x < width; ++x)
+ {
+ for (int y = 0; y < height; ++y)
+ {
+ pixels[x + y * width] = c;
+ }
+ }
+ }
+
+ Color Bitmap::getPixel(int x, int y)
+ {
+ if (pixels == nullptr)
+ return Color::BLACK;
+ if (without<int>(x, 0, width - 1) || without<int>(y, 0, height - 1))
+ return Color::BLACK;
+ return pixels[x + y * width];
+ }
+
+ const Color* Bitmap::getPixels() const
+ {
+ return pixels;
+ }
+
+ } // namespace Graphics
+} // namespace JinEngine \ No newline at end of file
diff --git a/src/libjin/Graphics/je_bitmap.h b/src/libjin/Graphics/je_bitmap.h
new file mode 100644
index 0000000..ae97d0d
--- /dev/null
+++ b/src/libjin/Graphics/je_bitmap.h
@@ -0,0 +1,184 @@
+#ifndef __JE_BITMAP_H
+#define __JE_BITMAP_H
+#include "../core/je_configuration.h"
+#if defined(jin_graphics)
+
+#include "../3rdparty/GLee/GLee.h"
+#include "../common/je_types.h"
+#include "../math/je_vector2.hpp"
+
+#include "je_color.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ ///
+ /// A RGBA32 bitmap.
+ ///
+ /// A bitmap keeps pixels and can't draw directly onto screen. To render bitmap, a texture is required.
+ ///
+ class Bitmap
+ {
+ public:
+ ///
+ /// Create bitmap from given file.
+ ///
+ /// @param path Path of image file.
+ /// @return Bitmap if create successful, otherwise retrun false.
+ ///
+ static Bitmap* createBitmap(const char* path);
+
+ ///
+ /// Create bitmap by pixels data.
+ ///
+ /// @param pixels Pixels data.
+ /// @param width Width of bitmap.
+ /// @param height Height of bitmap.
+ /// @return Return bitmap pointer if created, otherwise return null.
+ ///
+ static Bitmap* createBitmap(const void* pixels, unsigned width, unsigned height);
+
+ ///
+ /// Create bitmap from compressed image data.
+ ///
+ /// @param imgData Compressed image data.
+ /// @param size Size of image data.
+ /// @return Return bitmap pointer if created, otherwise return null.
+ ///
+ static Bitmap* createBitmap(const void* imgData, size_t size);
+
+ ///
+ /// Create bitmap with specific color and size.
+ ///
+ /// @param width Width of bitmap.
+ /// @param height Height of bitmap.
+ /// @param color Color of bitmap, black by default.
+ /// @return Return bitmap pointer if created, otherwise return null.
+ ///
+ static Bitmap* createBitmap(int width, int height, Color color = Color::BLACK);
+
+ ///
+ /// Create bitmap with another one.
+ ///
+ /// @param bitmap Bitmap be cloned.
+ /// @return Return bitmap pointer if created, otherwise return null.
+ ///
+ static Bitmap* clone(const Bitmap* bitmap);
+
+ ///
+ /// Destructor of bitmap
+ ///
+ virtual ~Bitmap();
+
+ ///
+ /// Directly bind pixels with given pixels data
+ ///
+ /// @param pixels Pixels to be binded.
+ /// @param width Width of bitmap
+ /// @param height Height of bitmap
+ ///
+ void bind(Color* pixels, int width, int height);
+
+ ///
+ /// Reset pixel data with given pixels data.
+ ///
+ /// @param pixels Pixels to be set.
+ /// @param width Width of bitmap
+ /// @param height Height of bitmap
+ ///
+ void resetPixels(const Color* pixels, int width, int height);
+
+ ///
+ /// Reset pixel data with given color.
+ ///
+ /// @param color Color to be set.
+ /// @param width Width of bitmap
+ /// @param height Height of bitmap
+ ///
+ void resetPixels(const Color& color, int width, int height);
+
+ ///
+ /// Set pixel with given color.
+ ///
+ /// @param color Color to be set.
+ /// @param x X value of pixel.
+ /// @param y Y value of pixel.
+ ///
+ void setPixel(const Color& color, int x, int y);
+
+ ///
+ /// Set pixels with given color.
+ ///
+ /// @param color Color to be set.
+ ///
+ void setPixels(Color color);
+
+ ///
+ /// Set pixels with given color data.
+ ///
+ /// @param colors New pixels' colors.
+ ///
+ void setPixels(Color* colors);
+
+ ///
+ /// Get pixel in given position.
+ ///
+ /// @param x X value of position.
+ /// @param y Y value of position.
+ ///
+ Color getPixel(int x, int y);
+
+ ///
+ /// Get pixels.
+ /// @return Colors of the bitmap.
+ ///
+ const Color* getPixels() const;
+
+ ///
+ /// Get bitmap width.
+ ///
+ /// @return Width of bitmap.
+ ///
+ inline int getWidth() const { return width; }
+
+ ///
+ /// Get bitmap height.
+ ///
+ /// @return Height of bitmap.
+ ///
+ inline int getHeight() const { return height; }
+
+ ///
+ /// Get bitmap size.
+ ///
+ /// @return Size of bitmap.
+ ///
+ inline Math::Vector2<int> getSize() const { return Math::Vector2<int>(width, height); }
+
+ protected:
+ ///
+ /// Constructor of bitmap.
+ ///
+ Bitmap();
+
+ ///
+ /// Constructor of bitmap.
+ ///
+ /// @param width Width of bitmap.
+ /// @param height Height of bitmap.
+ ///
+ Bitmap(unsigned w, unsigned h);
+
+ Color * pixels;
+ unsigned width, height;
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif
+
+#endif \ No newline at end of file
diff --git a/src/libjin/Graphics/je_canvas.cpp b/src/libjin/Graphics/je_canvas.cpp
new file mode 100644
index 0000000..7e0858b
--- /dev/null
+++ b/src/libjin/Graphics/je_canvas.cpp
@@ -0,0 +1,102 @@
+#include "../core/je_configuration.h"
+#if defined(jin_graphics)
+
+#include "../utils/je_macros.h"
+#include "je_canvas.h"
+#include "je_window.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ /*class member*/ const Canvas* Canvas::current = nullptr;
+ /*class member*/ const Canvas* const Canvas::DEFAULT_CANVAS = new Canvas(0);
+
+ /*class member*/ Canvas* Canvas::createCanvas(int w, int h)
+ {
+ return new Canvas(w, h);
+ }
+
+ Canvas::Canvas(GLuint n)
+ : fbo(n)
+ {
+ }
+
+ Canvas::Canvas(int w, int h)
+ : Graphic(w, h)
+ {
+ GLint current_fbo;
+ glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &current_fbo);
+
+ // Generate a new render buffer object
+ fbo = gl.genFrameBuffer();
+ gl.bindFrameBuffer(fbo);
+
+ // Generate texture save target
+ mTexture = gl.genTexture();
+ gl.bindTexture(mTexture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ gl.texImage(GL_RGBA8, w, h, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ gl.bindTexture(0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ // Unbind framebuffer
+ gl.bindFrameBuffer(current_fbo);
+ }
+
+ Canvas::~Canvas()
+ {
+ }
+
+ /*class member*/ bool Canvas::isBinded(const Canvas* cvs)
+ {
+ return current == cvs;
+ }
+
+ /**
+ * bind to canvas
+ */
+ /*class member*/ void Canvas::bind(Canvas* canvas)
+ {
+ if (isBinded(canvas)) return;
+ current = canvas;
+ gl.bindFrameBuffer(canvas->fbo);
+ int w = canvas->getWidth();
+ int h = canvas->getHeight();
+ // Set view port to canvas.
+ glViewport(0, 0, w, h);
+ gl.ProjectionMatrix.setOrtho(0, w, 0, h, -1, 1);
+ }
+
+ /**
+ * bind to default screen render buffer.
+ * do some coordinates transform work
+ * https://blog.csdn.net/liji_digital/article/details/79370841
+ * https://blog.csdn.net/lyx2007825/article/details/8792475
+ */
+ /*class member*/ void Canvas::unbind()
+ {
+ if (isBinded(DEFAULT_CANVAS)) return;
+ current = DEFAULT_CANVAS;
+ /* get window size as viewport */
+ Window* wnd = Window::get();
+ int w = wnd->getW();
+ int h = wnd->getH();
+
+ glBindFramebuffer(GL_FRAMEBUFFER, DEFAULT_CANVAS->fbo);
+
+ /* set viewport on screen */
+ glViewport(0, 0, w, h);
+
+ gl.ProjectionMatrix.setOrtho(0, w, h, 0, -1, 1);
+
+ }
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // defined(jin_graphics) \ No newline at end of file
diff --git a/src/libjin/Graphics/je_canvas.h b/src/libjin/Graphics/je_canvas.h
new file mode 100644
index 0000000..f39b0de
--- /dev/null
+++ b/src/libjin/Graphics/je_canvas.h
@@ -0,0 +1,68 @@
+#ifndef __JE_CANVAS_H
+#define __JE_CANVAS_H
+#include "../core/je_configuration.h"
+#if defined(jin_graphics)
+
+#include "je_graphic.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+ ///
+ /// Renderable canvas.
+ ///
+ /// A canvas is a rendering target.
+ ///
+ class Canvas: public Graphic
+ {
+ public:
+ ///
+ ///
+ ///
+ static Canvas* createCanvas(int w, int h);
+
+ ///
+ ///
+ ///
+ static void bind(Canvas*);
+
+ ///
+ ///
+ ///
+ static void unbind();
+
+ ///
+ ///
+ ///
+ static bool isBinded(const Canvas*);
+
+ ///
+ ///
+ ///
+ ~Canvas();
+
+ protected:
+ static const Canvas* const DEFAULT_CANVAS;
+ static const Canvas* current;
+
+ ///
+ ///
+ ///
+ Canvas(int w, int h);
+
+ ///
+ ///
+ ///
+ Canvas(GLuint n);
+
+ GLuint fbo;
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // defined(jin_graphics)
+
+#endif // __JE_CANVAS_H \ No newline at end of file
diff --git a/src/libjin/Graphics/je_color.cpp b/src/libjin/Graphics/je_color.cpp
new file mode 100644
index 0000000..da48162
--- /dev/null
+++ b/src/libjin/Graphics/je_color.cpp
@@ -0,0 +1,17 @@
+#include "je_color.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ const Color Color::WHITE = Color(255, 255, 255);
+ const Color Color::BLACK = Color(0, 0, 0);
+ const Color Color::RED = Color(255, 0, 0);
+ const Color Color::GREEN = Color(0, 255, 0);
+ const Color Color::BLUE = Color(0, 0, 255);
+ const Color Color::MAGENTA = Color(255, 0, 255);
+ const Color Color::YELLOW = Color(255, 255, 0);
+
+ }
+} \ No newline at end of file
diff --git a/src/libjin/Graphics/je_color.h b/src/libjin/Graphics/je_color.h
new file mode 100644
index 0000000..8fe7691
--- /dev/null
+++ b/src/libjin/Graphics/je_color.h
@@ -0,0 +1,93 @@
+/**
+* Some color operating here.
+*/
+#ifndef __JE_COLOR_H
+#define __JE_COLOR_H
+#include "../core/je_configuration.h"
+#if defined(jin_graphics)
+
+#include "../common/je_types.h"
+#include "../utils/je_endian.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ typedef uint8 Channel;
+
+ class Color
+ {
+ public:
+ // Built-in colors
+ static const Color WHITE;
+ static const Color BLACK;
+ static const Color RED;
+ static const Color GREEN;
+ static const Color BLUE;
+ static const Color MAGENTA;
+ static const Color YELLOW;
+
+ ///
+ ///
+ ///
+ Color() { r = g = b = a = 0; };
+
+ ///
+ ///
+ ///
+ Color(unsigned char _r
+ , unsigned char _g
+ , unsigned char _b
+ , unsigned char _a = 255)
+ {
+ r = _r;
+ g = _g;
+ b = _b;
+ a = _a;
+ }
+
+ Color(const Color& c)
+ {
+ r = c.r;
+ g = c.g;
+ b = c.b;
+ a = c.a;
+ }
+
+ void set(unsigned char _r, unsigned char _g, unsigned char _b, unsigned char _a)
+ {
+ r = _r;
+ g = _g;
+ b = _b;
+ a = _a;
+ }
+
+ void operator = (const Color& c)
+ {
+ r = c.r;
+ g = c.g;
+ b = c.b;
+ a = c.a;
+ }
+
+ bool operator == (const Color& c)
+ {
+ return r == c.r && g == c.g && b == c.b && a == c.a;
+ }
+
+ bool operator != (const Color& c)
+ {
+ return !(r == c.r && g == c.g && b == c.b && a == c.a);
+ }
+
+ Channel r, g, b, a;
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // jin_graphics
+
+#endif // __JE_COLOR_H \ No newline at end of file
diff --git a/src/libjin/Graphics/je_gl.cpp b/src/libjin/Graphics/je_gl.cpp
new file mode 100644
index 0000000..9ef1460
--- /dev/null
+++ b/src/libjin/Graphics/je_gl.cpp
@@ -0,0 +1,12 @@
+#define OGL2D_IMPLEMENT
+#include "je_gl.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ OpenGL gl;
+
+ } // namespace Graphics
+} // namespace JinEngine
diff --git a/src/libjin/Graphics/je_gl.h b/src/libjin/Graphics/je_gl.h
new file mode 100644
index 0000000..cda8bf9
--- /dev/null
+++ b/src/libjin/Graphics/je_gl.h
@@ -0,0 +1,40 @@
+#ifndef __JE_OPENGL_H
+#define __JE_OPENGL_H
+
+#include "../3rdparty/GLee/GLee.h"
+#include "../3rdparty/ogl/OpenGL.h"
+#include "../math/je_matrix.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ class OpenGL : public ogl2d::OpenGL
+ {
+ public:
+ ///
+ ///
+ ///
+ Math::Matrix ProjectionMatrix;
+
+ ///
+ ///
+ ///
+ Math::Matrix ModelMatrix;
+
+ ///
+ ///
+ ///
+ OpenGL() : ogl2d::OpenGL()
+ {
+ }
+
+ };
+
+ extern OpenGL gl;
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // __JE_OPENGL_H \ No newline at end of file
diff --git a/src/libjin/Graphics/je_graphic.cpp b/src/libjin/Graphics/je_graphic.cpp
new file mode 100644
index 0000000..831e409
--- /dev/null
+++ b/src/libjin/Graphics/je_graphic.cpp
@@ -0,0 +1,117 @@
+#include "../core/je_configuration.h"
+#if defined(jin_graphics)
+
+#include <stdlib.h>
+
+#include "../math/je_matrix.h"
+
+#include "shader/je_shader.h"
+#include "je_graphic.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ Graphic::Graphic(int w, int h)
+ : mTexture(0)
+ , mSize(w, h)
+ {
+ mVertexCoords[0] = 0; mVertexCoords[1] = 0;
+ mVertexCoords[2] = 0; mVertexCoords[3] = h;
+ mVertexCoords[4] = w; mVertexCoords[5] = h;
+ mVertexCoords[6] = w; mVertexCoords[7] = 0;
+
+ mTextureCoords[0] = 0; mTextureCoords[1] = 0;
+ mTextureCoords[2] = 0; mTextureCoords[3] = 1;
+ mTextureCoords[4] = 1; mTextureCoords[5] = 1;
+ mTextureCoords[6] = 1; mTextureCoords[7] = 0;
+ }
+
+ Graphic::Graphic(const Bitmap* bitmap)
+ : mTexture(0)
+ {
+ uint32 w = mSize.w = bitmap->getWidth();
+ uint32 h = mSize.h = bitmap->getHeight();
+
+ mVertexCoords[0] = 0; mVertexCoords[1] = 0;
+ mVertexCoords[2] = 0; mVertexCoords[3] = h;
+ mVertexCoords[4] = w; mVertexCoords[5] = h;
+ mVertexCoords[6] = w; mVertexCoords[7] = 0;
+
+ mTextureCoords[0] = 0; mTextureCoords[1] = 0;
+ mTextureCoords[2] = 0; mTextureCoords[3] = 1;
+ mTextureCoords[4] = 1; mTextureCoords[5] = 1;
+ mTextureCoords[6] = 1; mTextureCoords[7] = 0;
+
+ const Color* pixels = bitmap->getPixels();
+
+ mTexture = gl.genTexture();
+ gl.bindTexture(mTexture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ gl.texImage(GL_RGBA8, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+ gl.bindTexture(0);
+ }
+
+ Graphic::~Graphic()
+ {
+ glDeleteTextures(1, &mTexture);
+ }
+
+ void Graphic::draw(int x, int y, float sx, float sy, float r, float ox, float oy)
+ {
+ gl.ModelMatrix.setTransformation(x, y, r, sx, sy, ox, oy);
+
+ Shader* shader = Shader::getCurrentShader();
+ shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix);
+ shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix);
+ shader->bindVertexPointer(2, GL_FLOAT, 0, mVertexCoords);
+ shader->bindUVPointer(2, GL_FLOAT, 0, mTextureCoords);
+
+ gl.bindTexture(mTexture);
+ gl.drawArrays(GL_QUADS, 0, 4);
+ gl.bindTexture(0);
+ }
+
+ void Graphic::draw(const Math::Quad& slice, int x, int y, float sx, float sy, float r, float ax, float ay)
+ {
+ float vertCoords[8] = {
+ 0, 0,
+ 0, slice.h,
+ slice.w, slice.h,
+ slice.w, 0
+ };
+ float slx = slice.x / mSize.w;
+ float sly = slice.y / mSize.h;
+ float slw = slice.w / mSize.w;
+ float slh = slice.h / mSize.h;
+ float texCoords[8] = {
+ slx, sly,
+ slx, sly + slh,
+ slx + slw, sly + slh,
+ slx + slw, sly
+ };
+
+ gl.ModelMatrix.setTransformation(x, y, r, sx, sy, ax, ay);
+
+ Shader* shader = Shader::getCurrentShader();
+ shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix);
+ shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix);
+ shader->bindVertexPointer(2, GL_FLOAT, 0, vertCoords);
+ shader->bindUVPointer(2, GL_FLOAT, 0, texCoords);
+
+ gl.bindTexture(mTexture);
+ gl.drawArrays(GL_QUADS, 0, 4);
+ gl.bindTexture(0);
+ }
+
+ //void Graphic::setFilter(GLint min, GLint max)
+ //{
+ // glTexParameteri(GL_)
+ //}
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // defined(jin_graphics) \ No newline at end of file
diff --git a/src/libjin/Graphics/je_graphic.h b/src/libjin/Graphics/je_graphic.h
new file mode 100644
index 0000000..fb6b19e
--- /dev/null
+++ b/src/libjin/Graphics/je_graphic.h
@@ -0,0 +1,91 @@
+#ifndef __JE_GRAPHIC_H
+#define __JE_GRAPHIC_H
+#include "../core/je_configuration.h"
+#if defined(jin_graphics)
+
+#include "../math/je_quad.h"
+#include "../math/je_vector2.hpp"
+
+#include "je_gl.h"
+#include "je_bitmap.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ //
+ // Graphic
+ // |-Texture
+ // |-Canvas
+ //
+
+ ///
+ /// Class inherites Graphic doesn't keep any state such as origin, scale and other
+ /// properties.
+ ///
+ class Graphic
+ {
+ public:
+ ///
+ ///
+ ///
+ Graphic(int w = 0, int h = 0);
+
+ ///
+ ///
+ ///
+ Graphic(const Bitmap* bitmap);
+
+ ///
+ ///
+ ///
+ virtual ~Graphic();
+
+ ///
+ ///
+ ///
+ void draw(int x, int y, float sx = 1, float sy = 1, float r = 0, float ox = 0, float oy = 0);
+
+ ///
+ ///
+ ///
+ void draw(const Math::Quad& slice, int x, int y, float sx = 1, float sy = 1, float r = 0, float ax = 0, float ay = 0);
+
+ ///
+ ///
+ ///
+ inline int getWidth() const { return mSize.w; }
+
+ ///
+ ///
+ ///
+ inline int getHeight() const { return mSize.h; }
+
+ ///
+ ///
+ ///
+ inline GLuint getTexture() const { return mTexture; }
+
+ ///
+ ///
+ ///
+ void setFilter(GLint min, GLint max);
+
+ protected:
+ GLuint mTexture;
+
+ private:
+ JinEngine::Math::Vector2<uint> mSize;
+ // Screen coordinates and uv coordinates.
+ float mVertexCoords[8];
+ float mTextureCoords[8];
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // defined(jin_graphics)
+
+#endif // __JE_GRAPHIC_H \ No newline at end of file
diff --git a/src/libjin/Graphics/je_graphics.h b/src/libjin/Graphics/je_graphics.h
new file mode 100644
index 0000000..2ba003d
--- /dev/null
+++ b/src/libjin/Graphics/je_graphics.h
@@ -0,0 +1,21 @@
+#ifndef __JE_GRAPHICS_H
+#define __JE_GRAPHICS_H
+#include "../core/je_configuration.h"
+#if defined(jin_graphics)
+
+#include "je_canvas.h"
+#include "je_color.h"
+#include "je_shapes.h"
+#include "je_texture.h"
+#include "je_window.h"
+#include "je_bitmap.h"
+#include "je_image.h"
+
+#include "shader/je_shader.h"
+
+#include "font/je_ttf.h"
+#include "font/je_text.h"
+#include "font/je_texture_font.h"
+
+#endif // defined(jin_graphics)
+#endif // __JE_GRAPHICS_H \ No newline at end of file
diff --git a/src/libjin/Graphics/je_image.cpp b/src/libjin/Graphics/je_image.cpp
new file mode 100644
index 0000000..f800423
--- /dev/null
+++ b/src/libjin/Graphics/je_image.cpp
@@ -0,0 +1,46 @@
+#include "../3rdparty/stb/stb_image.h"
+#include "../filesystem/je_asset_database.h"
+
+#include "je_image.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ using namespace Filesystem;
+
+ /*static*/ Image* Image::createImage(const void* imgData, size_t size)
+ {
+ if (imgData == nullptr)
+ return nullptr;
+ int w, h;
+ void* data = stbi_load_from_memory((uint8*)imgData, size, &w, &h, NULL, STBI_rgb_alpha);
+ if (data == nullptr)
+ return nullptr;
+ Image* image = new Image();
+ image->pixels = (Color*)data;
+ image->width = w;
+ image->height = h;
+ return image;
+ }
+
+ Image* Image::createImage(const char* path)
+ {
+ AssetDatabase* fs = AssetDatabase::get();
+ Buffer buffer;
+ fs->read(path, buffer);
+ return createImage(&buffer, buffer.size());
+ }
+
+ Image::Image()
+ : Bitmap()
+ {
+ }
+
+ Image::~Image()
+ {
+ }
+
+ } // namespace Graphics
+} // namespace JinEngine \ No newline at end of file
diff --git a/src/libjin/Graphics/je_image.h b/src/libjin/Graphics/je_image.h
new file mode 100644
index 0000000..04ee4d2
--- /dev/null
+++ b/src/libjin/Graphics/je_image.h
@@ -0,0 +1,60 @@
+#ifndef __JE_IMAGE_H
+#define __JE_IMAGE_H
+
+#include "je_bitmap.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ ///
+ /// A readonly bitmap.
+ ///
+ /// Just like bitmap but only from image file. The pixels data is readonly.
+ ///
+ class Image : public Bitmap
+ {
+ public:
+ ///
+ /// Create image from image file.
+ ///
+ /// @param path Image path.
+ /// @return Image if created successfully, otherwise return null.
+ ///
+ static Image* createImage(const char* path);
+
+ ///
+ /// Create image from image data.
+ ///
+ /// @param imgData Image data to create image.
+ /// @param size Size of image data.
+ /// @return Image if created successfully, otherwise return null.
+ ///
+ static Image* createImage(const void* imgData, size_t size);
+
+ ///
+ /// Image destructor.
+ ///
+ ~Image();
+
+ private:
+ ///
+ /// Image constructor.
+ ///
+ Image();
+
+ // Disable setters inherited from Bitmap.
+ void bind(Color* pixels, int w, int h);
+ void resetPixels(const Color* pixels, int w, int h);
+ void resetPixels(const Color& pixels, int w, int h);
+ void setPixel(const Color& pixel, int x, int y);
+ void setPixels(Color pixels);
+ void setPixels(Color* pixels);
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif \ No newline at end of file
diff --git a/src/libjin/Graphics/je_mesh.cpp b/src/libjin/Graphics/je_mesh.cpp
new file mode 100644
index 0000000..dd2d61c
--- /dev/null
+++ b/src/libjin/Graphics/je_mesh.cpp
@@ -0,0 +1,11 @@
+#include "je_mesh.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+
+
+ } // namespace Graphics
+} // namespace JinEngine \ No newline at end of file
diff --git a/src/libjin/Graphics/je_mesh.h b/src/libjin/Graphics/je_mesh.h
new file mode 100644
index 0000000..ed22d91
--- /dev/null
+++ b/src/libjin/Graphics/je_mesh.h
@@ -0,0 +1,24 @@
+#ifndef __JE_MESH_H
+#define __JE_MESH_H
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ ///
+ ///
+ ///
+ class Mesh
+ {
+ public:
+
+ private:
+
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif \ No newline at end of file
diff --git a/src/libjin/Graphics/je_shapes.cpp b/src/libjin/Graphics/je_shapes.cpp
new file mode 100644
index 0000000..3146f31
--- /dev/null
+++ b/src/libjin/Graphics/je_shapes.cpp
@@ -0,0 +1,128 @@
+#include "../core/je_configuration.h"
+#if defined(jin_graphics)
+
+#include <string>
+
+#include "../math/je_matrix.h"
+#include "../math/je_constant.h"
+
+#include "shader/je_shader.h"
+#include "je_shapes.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ using namespace Math;
+
+ void point(int x, int y)
+ {
+ float verts[] = { x + 0.5f , y + 0.5f };
+
+ Shader* shader = Shader::getCurrentShader();
+ shader->bindVertexPointer(2, GL_FLOAT, 0, verts);
+ gl.ModelMatrix.setIdentity();
+ shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix);
+ shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix);
+
+ glDrawArrays(GL_POINTS, 0, 1);
+ }
+
+ void points(int n, GLshort* p)
+ {
+ Shader* shader = Shader::getCurrentShader();
+ shader->bindVertexPointer(2, GL_SHORT, 0, p);
+ gl.ModelMatrix.setIdentity();
+ shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix);
+ shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix);
+
+ glDrawArrays(GL_POINTS, 0, n);
+ }
+
+ void line(int x1, int y1, int x2, int y2)
+ {
+ float verts[] = {
+ x1, y1,
+ x2, y2
+ };
+
+ Shader* shader = Shader::getCurrentShader();
+ shader->bindVertexPointer(2, GL_FLOAT, 0, verts);
+ gl.ModelMatrix.setIdentity();
+ shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix);
+ shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix);
+
+ glDrawArrays(GL_LINES, 0, 2);
+ }
+
+ void circle(RenderMode 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(RenderMode 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(RenderMode 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)
+ {
+ Shader* shader = Shader::getCurrentShader();
+ gl.ModelMatrix.setIdentity();
+ shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix);
+ shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix);
+ shader->bindVertexPointer(2, GL_FLOAT, 0, p);
+
+ glDrawArrays(GL_LINE_LOOP, 0, count);
+ }
+
+ void polygon(RenderMode mode, float* p, int count)
+ {
+ if (mode == LINE)
+ {
+ polygon_line(p, count);
+ }
+ else if (mode == FILL)
+ {
+ Shader* shader = Shader::getCurrentShader();
+ gl.ModelMatrix.setIdentity();
+ shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix);
+ shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix);
+ shader->bindVertexPointer(2, GL_FLOAT, 0, p);
+
+ glDrawArrays(GL_POLYGON, 0, count);
+ }
+ }
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // defined(jin_graphics) \ No newline at end of file
diff --git a/src/libjin/Graphics/je_shapes.h b/src/libjin/Graphics/je_shapes.h
new file mode 100644
index 0000000..2221526
--- /dev/null
+++ b/src/libjin/Graphics/je_shapes.h
@@ -0,0 +1,34 @@
+#ifndef __JE_GEOMETRY_H
+#define __JE_GEOMETRY_H
+#include "../core/je_configuration.h"
+#if defined(jin_graphics)
+
+#include "je_color.h"
+#include "je_canvas.h"
+#include "je_texture.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ typedef enum {
+ NONE = 0,
+ FILL ,
+ LINE
+ }RenderMode;
+
+ extern void line(int x1, int y1, int x2, int y2);
+ extern void rect(RenderMode mode, int x, int y, int w, int h);
+ extern void triangle(RenderMode mode, int x1, int y1, int x2, int y2, int x3, int y3);
+ extern void circle(RenderMode 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(RenderMode mode, float* p, int count);
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // jin_graphics
+
+#endif // __JE_GEOMETRY_H \ No newline at end of file
diff --git a/src/libjin/Graphics/je_sprite.cpp b/src/libjin/Graphics/je_sprite.cpp
new file mode 100644
index 0000000..3ac976a
--- /dev/null
+++ b/src/libjin/Graphics/je_sprite.cpp
@@ -0,0 +1,11 @@
+#include "je_sprite.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+
+
+ } // namespace Graphics
+} // namespace JinEngine \ No newline at end of file
diff --git a/src/libjin/Graphics/je_sprite.h b/src/libjin/Graphics/je_sprite.h
new file mode 100644
index 0000000..3b96162
--- /dev/null
+++ b/src/libjin/Graphics/je_sprite.h
@@ -0,0 +1,38 @@
+#ifndef __JE_SPRITE_H
+#define __JE_SPRITE_H
+
+#include "../common/je_types.h"
+#include "../math/je_vector2.hpp"
+
+#include "shader/je_shader.h"
+#include "je_color.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+ ///
+ /// A sprite is unit of rendering, logic and events.
+ ///
+ class Sprite
+ {
+ public:
+ void setOrigin(float x, float y);
+ void setPosition(int x, int y);
+ void setScale(float x, float y);
+ void setColor(Color color);
+ void setShader(const Shader* shader);
+
+ private:
+ Math::Vector2<int> mPosition;
+ Math::Vector2<float> mOrigin;
+ Math::Vector2<float> mScale;
+ Color mColor;
+ const Shader* mShader;
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif \ No newline at end of file
diff --git a/src/libjin/Graphics/je_sprite_batch.cpp b/src/libjin/Graphics/je_sprite_batch.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/libjin/Graphics/je_sprite_batch.cpp
diff --git a/src/libjin/Graphics/je_sprite_batch.h b/src/libjin/Graphics/je_sprite_batch.h
new file mode 100644
index 0000000..85a7951
--- /dev/null
+++ b/src/libjin/Graphics/je_sprite_batch.h
@@ -0,0 +1,17 @@
+#ifndef __JE_SPRITE_BATCH_H
+#define __JE_SPRITE_BATCH_H
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ class SpriteBatch
+ {
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif \ No newline at end of file
diff --git a/src/libjin/Graphics/je_texture.cpp b/src/libjin/Graphics/je_texture.cpp
new file mode 100644
index 0000000..8aa3f9a
--- /dev/null
+++ b/src/libjin/Graphics/je_texture.cpp
@@ -0,0 +1,44 @@
+#include "../core/je_configuration.h"
+#if defined(jin_graphics)
+
+#include <fstream>
+
+#include "../utils/je_utils.h"
+#include "../math/je_math.h"
+
+#include "je_texture.h"
+
+using namespace JinEngine::Math;
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ Texture* Texture::createTexture(const char* path)
+ {
+ Bitmap* bitmap = Bitmap::createBitmap(path);
+ Texture* texture = createTexture(bitmap);
+ delete bitmap;
+ return texture;
+ }
+
+ /*static*/ Texture* Texture::createTexture(Bitmap* bitmap)
+ {
+ Texture* tex = new Texture(bitmap);
+ return tex;
+ }
+
+ Texture::Texture(const Bitmap* bitmap)
+ : Graphic(bitmap)
+ {
+ }
+
+ Texture::~Texture()
+ {
+ }
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // defined(jin_graphics) \ No newline at end of file
diff --git a/src/libjin/Graphics/je_texture.h b/src/libjin/Graphics/je_texture.h
new file mode 100644
index 0000000..ddc8cfc
--- /dev/null
+++ b/src/libjin/Graphics/je_texture.h
@@ -0,0 +1,56 @@
+#ifndef __JE_TEXTURE_H
+#define __JE_TEXTURE_H
+#include "../core/je_configuration.h"
+#if defined(jin_graphics)
+
+#include "../3rdparty/GLee/GLee.h"
+
+#include "je_color.h"
+#include "je_graphic.h"
+#include "je_bitmap.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ ///
+ ///
+ ///
+ class Texture: public Graphic
+ {
+ public:
+ ///
+ ///
+ ///
+ static Texture* createTexture(const char* path);
+
+ ///
+ ///
+ ///
+ static Texture* createTexture(Bitmap* bitmap);
+
+ ///
+ ///
+ ///
+ static Texture* createTexture();
+
+ ///
+ ///
+ ///
+ ~Texture();
+
+ private:
+ ///
+ ///
+ ///
+ Texture(const Bitmap* bitmap);
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // jin_graphics
+
+#endif // __JE_TEXTURE_H \ No newline at end of file
diff --git a/src/libjin/Graphics/je_window.cpp b/src/libjin/Graphics/je_window.cpp
new file mode 100644
index 0000000..f0b789e
--- /dev/null
+++ b/src/libjin/Graphics/je_window.cpp
@@ -0,0 +1,111 @@
+#include "../core/je_configuration.h"
+#if defined(jin_graphics)
+
+#include <iostream>
+
+#include "../utils/je_utils.h"
+#include "../audio/sdl/je_sdl_audio.h"
+#include "../utils/je_log.h"
+
+#include "shader/je_shader.h"
+#include "je_window.h"
+#include "je_gl.h"
+#include "je_canvas.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ bool Window::initSystem(const SettingBase* s)
+ {
+ #if defined(jin_debug)
+ Loghelper::log(Loglevel::LV_INFO, "Init window system");
+ #endif
+
+ if (SDL_Init(SDL_INIT_VIDEO) < 0)
+ return false;
+
+ const Setting* setting = (Setting*)s;
+ mSize.w = setting->width;
+ mSize.h = setting->height;
+ mFps = setting->fps;
+ bool vsync = setting->vsync;
+ const char* title = setting->title;
+
+ if (mWnd)
+ {
+ SDL_DestroyWindow(mWnd);
+ SDL_FlushEvent(SDL_WINDOWEVENT);
+ }
+
+ SDL_GLContext ctx = NULL;
+
+ 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);
+ SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ int wx = SDL_WINDOWPOS_UNDEFINED,
+ wy = SDL_WINDOWPOS_UNDEFINED;
+
+ int flag = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL;
+ if (setting->fullscreen) flag |= SDL_WINDOW_FULLSCREEN;
+ if (setting->resizable) flag |= SDL_WINDOW_RESIZABLE;
+
+ mWnd = SDL_CreateWindow(title, wx, wy, mSize.w, mSize.h, flag);
+ if (mWnd == NULL)
+ return false;
+ ctx = SDL_GL_CreateContext(mWnd);
+ if (ctx == NULL)
+ return false;
+ SDL_GL_SetSwapInterval(vsync ? 1 : 0);
+ SDL_GL_MakeCurrent(mWnd, ctx);
+ // default configuration
+ gl.setClearColor(0, 0, 0, 0xff);
+ gl.pushColor(0xff, 0xff, 0xff, 0xff);
+ gl.enable(GL_BLEND);
+ gl.enable(GL_TEXTURE_2D);
+ gl.setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ // avoid white screen blink on windows
+ swapBuffers();
+ // bind to default canvas
+ Canvas::unbind();
+ Shader::unuse();
+ return true;
+ }
+
+ void Window::quitSystem()
+ {
+ // disable opengl
+ gl.disable(GL_BLEND);
+ gl.disable(GL_TEXTURE_2D);
+ // close window
+ SDL_DestroyWindow(mWnd);
+ SDL_Quit();
+ }
+
+ void Window::swapBuffers()
+ {
+ if (mWnd)
+ SDL_GL_SwapWindow(mWnd);
+ }
+
+ void Window::setTitle(const char* title)
+ {
+ SDL_SetWindowTitle(mWnd, title);
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // defined(jin_graphics) \ No newline at end of file
diff --git a/src/libjin/Graphics/je_window.h b/src/libjin/Graphics/je_window.h
new file mode 100644
index 0000000..7ca1e5e
--- /dev/null
+++ b/src/libjin/Graphics/je_window.h
@@ -0,0 +1,97 @@
+#ifndef __JE_RENDER_WINDOW
+#define __JE_RENDER_WINDOW
+#include "../core/je_configuration.h"
+#if defined(jin_graphics)
+
+#include "SDL2/SDL.h"
+
+#include "../utils/je_utils.h"
+#include "../math/je_vector2.hpp"
+#include "../common/je_subsystem.hpp"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+ ///
+ ///
+ ///
+ class Window : public Subsystem<Window>
+ {
+ public:
+ ///
+ ///
+ ///
+ struct Setting : SettingBase
+ {
+ public:
+ const char* title; ///< window title
+ bool fullscreen; ///< full screen
+ int width, height; ///< window size
+ bool vsync; ///< vsync
+ int fps; ///< frame per second
+ bool resizable; ///< resizable
+ };
+
+ ///
+ ///
+ ///
+ void setTitle(const char* title);
+
+ ///
+ ///
+ ///
+ inline int getW(){ return mSize.w; }
+
+ ///
+ ///
+ ///
+ inline int getH(){ return mSize.h; }
+
+ ///
+ ///
+ ///
+ inline int getFPS(){ return mFps; }
+
+ ///
+ ///
+ ///
+ void swapBuffers();
+
+ private:
+
+ // declare a singleton
+ singleton(Window);
+
+ ///
+ ///
+ ///
+ Window() {};
+
+ ///
+ ///
+ ///
+ virtual ~Window() {};
+
+ ///
+ ///
+ ///
+ bool initSystem(const SettingBase* setting) override;
+
+ ///
+ ///
+ ///
+ void quitSystem() override;
+
+ SDL_Window* mWnd;
+ JinEngine::Math::Vector2<unsigned int> mSize;
+ int mFps;
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif // jin_graphics
+
+#endif // __JE_RENDER_WINDOW \ No newline at end of file
diff --git a/src/libjin/Graphics/particle/je_particle.cpp b/src/libjin/Graphics/particle/je_particle.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/libjin/Graphics/particle/je_particle.cpp
diff --git a/src/libjin/Graphics/particle/je_particle.h b/src/libjin/Graphics/particle/je_particle.h
new file mode 100644
index 0000000..2a5c54f
--- /dev/null
+++ b/src/libjin/Graphics/particle/je_particle.h
@@ -0,0 +1,21 @@
+#ifndef __JE_PARTICLE_H
+#define __JE_PARTICLE_H
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ ///
+ /// Single particle.
+ ///
+ class Particle
+ {
+
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif \ No newline at end of file
diff --git a/src/libjin/Graphics/particle/je_particle_batch.cpp b/src/libjin/Graphics/particle/je_particle_batch.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/libjin/Graphics/particle/je_particle_batch.cpp
diff --git a/src/libjin/Graphics/particle/je_particle_batch.h b/src/libjin/Graphics/particle/je_particle_batch.h
new file mode 100644
index 0000000..19f4ded
--- /dev/null
+++ b/src/libjin/Graphics/particle/je_particle_batch.h
@@ -0,0 +1,20 @@
+#ifndef __JE_PARTICLE_BATCH_H
+#define __JE_PARTICLE_BATCH_H
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ ///
+ ///
+ ///
+ class ParticleBatch
+ {
+
+ };
+
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif \ No newline at end of file
diff --git a/src/libjin/Graphics/particle/je_particle_emitter.cpp b/src/libjin/Graphics/particle/je_particle_emitter.cpp
new file mode 100644
index 0000000..d57d5ed
--- /dev/null
+++ b/src/libjin/Graphics/particle/je_particle_emitter.cpp
@@ -0,0 +1,11 @@
+#include "je_particle_emitter.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+
+
+ }
+}
diff --git a/src/libjin/Graphics/particle/je_particle_emitter.h b/src/libjin/Graphics/particle/je_particle_emitter.h
new file mode 100644
index 0000000..e191e36
--- /dev/null
+++ b/src/libjin/Graphics/particle/je_particle_emitter.h
@@ -0,0 +1,23 @@
+#ifndef __JE_PARTICLE_EMMITTER_H
+#define __JE_PARTICLE_EMMITTER_H
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+
+ ///
+ /// Particle emitter
+ ///
+ class ParticleEmitter
+ {
+ public:
+
+ private:
+
+ };
+
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/src/libjin/Graphics/particle/je_particle_system.cpp b/src/libjin/Graphics/particle/je_particle_system.cpp
new file mode 100644
index 0000000..6f70f09
--- /dev/null
+++ b/src/libjin/Graphics/particle/je_particle_system.cpp
@@ -0,0 +1 @@
+#pragma once
diff --git a/src/libjin/Graphics/particle/je_particle_system.h b/src/libjin/Graphics/particle/je_particle_system.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/libjin/Graphics/particle/je_particle_system.h