aboutsummaryrefslogtreecommitdiff
path: root/src/libjin/Graphics
diff options
context:
space:
mode:
Diffstat (limited to 'src/libjin/Graphics')
-rw-r--r--src/libjin/Graphics/Canvas.cpp135
-rw-r--r--src/libjin/Graphics/Canvas.h40
-rw-r--r--src/libjin/Graphics/Color.h31
-rw-r--r--src/libjin/Graphics/Drawable.cpp77
-rw-r--r--src/libjin/Graphics/Drawable.h58
-rw-r--r--src/libjin/Graphics/Font.cpp194
-rw-r--r--src/libjin/Graphics/Font.h61
-rw-r--r--src/libjin/Graphics/Geometry.cpp122
-rw-r--r--src/libjin/Graphics/Geometry.h43
-rw-r--r--src/libjin/Graphics/Graphics.h15
-rw-r--r--src/libjin/Graphics/JSL.cpp159
-rw-r--r--src/libjin/Graphics/JSL.h74
-rw-r--r--src/libjin/Graphics/Texture.cpp100
-rw-r--r--src/libjin/Graphics/Texture.h40
-rw-r--r--src/libjin/Graphics/Window.cpp90
-rw-r--r--src/libjin/Graphics/Window.h60
16 files changed, 1299 insertions, 0 deletions
diff --git a/src/libjin/Graphics/Canvas.cpp b/src/libjin/Graphics/Canvas.cpp
new file mode 100644
index 0000000..dddc889
--- /dev/null
+++ b/src/libjin/Graphics/Canvas.cpp
@@ -0,0 +1,135 @@
+#include "../modules.h"
+#if JIN_MODULES_RENDER
+
+#include "../utils/macros.h"
+#include "canvas.h"
+#include "window.h"
+
+namespace jin
+{
+namespace graphics
+{
+
+ shared Canvas* Canvas::createCanvas(int w, int h)
+ {
+ return new Canvas(w, h);
+ }
+
+ Canvas::Canvas(int w, int h)
+ : Drawable(w, h)
+ {
+ init();
+ }
+
+ Canvas::~Canvas()
+ {
+ }
+
+ shared GLint Canvas::cur = -1;
+
+ bool Canvas::init()
+ {
+ setVertices(
+ new float [DRAWABLE_V_SIZE] {
+ 0, 0,
+ 0, (float)height,
+ (float)width, (float)height,
+ (float)width, 0,
+ },
+ new float [DRAWABLE_V_SIZE] {
+ 0, 1,
+ 0, 0,
+ 1, 0,
+ 1, 1
+ }
+ );
+
+ GLint current_fbo;
+ glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &current_fbo);
+
+ // generate a new render buffer object
+ glGenFramebuffers(1, &fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ // generate texture save target
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ // unbind framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+ return false;
+ return true;
+ }
+
+ bool Canvas::hasbind(GLint fbo)
+ {
+ return cur == fbo;
+ }
+
+ /**
+ * bind to canvas
+ */
+ void Canvas::bind()
+ {
+ if (hasbind(fbo)) return;
+
+ cur = fbo;
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glViewport(0, 0, width, height);
+ glOrtho(0, width, height, 0, -1, 1);
+
+ // Switch back to modelview matrix
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ }
+
+ /**
+ * bind to default screen render buffer.
+ */
+ shared void Canvas::unbind()
+ {
+ if (hasbind(0)) return;
+
+ cur = 0;
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ WindowSystem* wnd = WindowSystem::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
new file mode 100644
index 0000000..bccb3f6
--- /dev/null
+++ b/src/libjin/Graphics/Canvas.h
@@ -0,0 +1,40 @@
+#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);
+
+ private:
+
+ 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
new file mode 100644
index 0000000..a78234e
--- /dev/null
+++ b/src/libjin/Graphics/Color.h
@@ -0,0 +1,31 @@
+/**
+* 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
new file mode 100644
index 0000000..cab6c50
--- /dev/null
+++ b/src/libjin/Graphics/Drawable.cpp
@@ -0,0 +1,77 @@
+#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
new file mode 100644
index 0000000..c05d8a4
--- /dev/null
+++ b/src/libjin/Graphics/Drawable.h
@@ -0,0 +1,58 @@
+#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 Drawable::getWidth() const
+ {
+ return width;
+ }
+
+ inline int Drawable::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
new file mode 100644
index 0000000..a107613
--- /dev/null
+++ b/src/libjin/Graphics/Font.cpp
@@ -0,0 +1,194 @@
+#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
new file mode 100644
index 0000000..7fc96e2
--- /dev/null
+++ b/src/libjin/Graphics/Font.h
@@ -0,0 +1,61 @@
+#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/Geometry.cpp b/src/libjin/Graphics/Geometry.cpp
new file mode 100644
index 0000000..69e3596
--- /dev/null
+++ b/src/libjin/Graphics/Geometry.cpp
@@ -0,0 +1,122 @@
+#include "../modules.h"
+#if JIN_MODULES_RENDER
+
+#include "Geometry.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/Geometry.h b/src/libjin/Graphics/Geometry.h
new file mode 100644
index 0000000..afd4f7a
--- /dev/null
+++ b/src/libjin/Graphics/Geometry.h
@@ -0,0 +1,43 @@
+#ifndef __JIN_GEOMETRY_H
+#define __JIN_GEOMETRY_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/Graphics.h b/src/libjin/Graphics/Graphics.h
new file mode 100644
index 0000000..0823978
--- /dev/null
+++ b/src/libjin/Graphics/Graphics.h
@@ -0,0 +1,15 @@
+#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 "Geometry.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
new file mode 100644
index 0000000..b877e60
--- /dev/null
+++ b/src/libjin/Graphics/JSL.cpp
@@ -0,0 +1,159 @@
+#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";
+
+ shared 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
new file mode 100644
index 0000000..3872802
--- /dev/null
+++ b/src/libjin/Graphics/JSL.h
@@ -0,0 +1,74 @@
+#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);
+
+ ~JSLProgram();
+
+ inline void JSLProgram::use()
+ {
+ glUseProgram(pid);
+ currentJSLProgram = this;
+ }
+
+ static inline void JSLProgram::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;
+ }
+
+ private:
+
+ 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/Texture.cpp b/src/libjin/Graphics/Texture.cpp
new file mode 100644
index 0000000..7349c36
--- /dev/null
+++ b/src/libjin/Graphics/Texture.cpp
@@ -0,0 +1,100 @@
+#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
+{
+
+ 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
new file mode 100644
index 0000000..47f8d53
--- /dev/null
+++ b/src/libjin/Graphics/Texture.h
@@ -0,0 +1,40 @@
+#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);
+
+ ~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
new file mode 100644
index 0000000..2d0fa82
--- /dev/null
+++ b/src/libjin/Graphics/Window.cpp
@@ -0,0 +1,90 @@
+#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
+{
+
+ onlyonce bool WindowSystem::initSystem(const SettingBase* s)
+ {
+ Loghelper::log(Loglevel::LV_INFO, "Init window system");
+
+ if (SDL_Init(SDL_INIT_VIDEO) < 0)
+ return false;
+
+ const WindowSetting* setting = (WindowSetting*)s;
+
+ width = setting->width;
+ height = setting->height;
+ 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;
+
+ wnd = SDL_CreateWindow(title, wx, wy, width, height, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
+ 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;
+ }
+
+ onlyonce void WindowSystem::quitSystem()
+ {
+ SDL_DestroyWindow(wnd);
+ }
+
+ inline void WindowSystem::swapBuffers()
+ {
+ if (wnd)
+ SDL_GL_SwapWindow(wnd);
+ }
+
+}
+}
+
+#endif // JIN_MODULES_RENDER \ No newline at end of file
diff --git a/src/libjin/Graphics/Window.h b/src/libjin/Graphics/Window.h
new file mode 100644
index 0000000..893fdb8
--- /dev/null
+++ b/src/libjin/Graphics/Window.h
@@ -0,0 +1,60 @@
+#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.h"
+
+namespace jin
+{
+namespace graphics
+{
+
+ class WindowSystem : public Subsystem<WindowSystem>
+ {
+ public:
+
+ struct Setting : SettingBase
+ {
+ public:
+ int width, height; // ڴС
+ bool vsync; // ֱͬ
+ const char* title; //
+ };
+
+ inline int getW()
+ {
+ return width;
+ }
+
+ inline int getH()
+ {
+ return height;
+ }
+
+ inline void swapBuffers();
+
+ private:
+
+ WindowSystem() {};
+ virtual ~WindowSystem() {};
+
+ SINGLETON(WindowSystem);
+
+ SDL_Window* wnd;
+
+ int width, height;
+
+ onlyonce bool initSystem(const SettingBase* setting) override;
+ onlyonce void quitSystem() override;
+ };
+
+ typedef WindowSystem::Setting WindowSetting;
+
+} // render
+} // jin
+
+#endif // JIN_MODULES_RENDER
+#endif // __JIN_RENDER_WINDOW \ No newline at end of file