diff options
Diffstat (limited to 'src/libjin/Graphics')
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, ¤t_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, ¤t_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 |