diff --git a/Makefile b/Makefile index 848befb0..58b0b43f 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,14 @@ .PHONY : mingw ej2d linux undefined -CFLAGS = -g -Wall -Ilib -Ilua -D EJOY2D_OS=$(OS) +CFLAGS = -g -Wall -Ilib -Ilib/render -Ilua -D EJOY2D_OS=$(OS) LDFLAGS := -SRC := \ +RENDER := \ +lib/render/render.c \ +lib/render/carray.c \ +lib/render/log.c + +EJOY2D := \ lib/shader.c \ lib/lshader.c \ lib/ejoy2dgame.c \ @@ -24,6 +29,8 @@ lib/scissor.c \ lib/renderbuffer.c \ lib/lrenderbuffer.c +SRC := $(EJOY2D) $(RENDER) + LUASRC := \ lua/lapi.c \ lua/lauxlib.c \ diff --git a/ejoy2d/init.lua b/ejoy2d/init.lua index 855230dc..57368b97 100644 --- a/ejoy2d/init.lua +++ b/ejoy2d/init.lua @@ -2,9 +2,11 @@ local shader = require "ejoy2d.shader" local fw = require "ejoy2d.framework" function fw.EJOY2D_INIT() - shader.init() +-- shader.init() end +shader.init() + local ejoy2d = {} local touch = { @@ -43,4 +45,8 @@ function ejoy2d.clear(color) return shader.clear(color) end +function ejoy2d.define_shader(args) + return shader.define(args) +end + return ejoy2d diff --git a/ejoy2d/shader.lua b/ejoy2d/shader.lua index 7e940fb6..62ced23b 100644 --- a/ejoy2d/shader.lua +++ b/ejoy2d/shader.lua @@ -202,6 +202,8 @@ local shader_name = { BLEND = 6, } +local shader_material = {} + function shader.init() s.load(shader_name.NORMAL, PRECISION .. sprite_fs, PRECISION .. sprite_vs) s.load(shader_name.TEXT, PRECISION .. text_fs, PRECISION .. sprite_vs) @@ -210,15 +212,104 @@ function shader.init() s.load(shader_name.COLOR, PRECISION .. color_fs, PRECISION .. sprite_vs) s.load(shader_name.BLEND, PRECISION .. blend_fs, PRECISION .. blend_vs) s.load(shader_name.RENDERBUFFER, PRECISION .. renderbuffer_fs, PRECISION_HIGH .. renderbuffer_vs) + s.uniform_bind(shader_name.RENDERBUFFER, { { name = "st", type = 4} }) -- st must the first uniform (the type is float4/4) end shader.draw = s.draw shader.blend = s.blend shader.clear = s.clear +shader.texture = s.shader_texture function shader.id(name) local id = assert(shader_name[name] , "Invalid shader name " .. name) return id end +-- user defined shader (or replace default shader) + +local MAX_PROGRAM = 16 +local USER_PROGRAM = 7 + +local uniform_format = { + float = 1, + float2 = 2, + float3 = 3, + float4 = 4, + matrix33 = 5, + matrix44 = 6, +} + +local uniform_set = s.uniform_set + +local function create_shader(id, uniform) + if uniform then + local s = {} + for index , u in ipairs(uniform) do + local loc = index-1 + local format = u.type + s[u.name] = function(...) + uniform_set(id, loc, format, ...) + end + end + return s + end +end + +local material_setuniform = s.material_setuniform +local material_settexture = s.material_settexture + +local function material_meta(id, arg) + local uniform = arg.uniform + local meta + if uniform then + local index_table = {} + meta = { __index = index_table } + for index , u in ipairs(uniform) do + local loc = index-1 + index_table[u.name] = function(self, ...) + material_setuniform(self.__obj, loc, ...) + end + end + if arg.texture then + index_table.texture = function(self, ...) + material_settexture(self.__obj, ...) + end + end + end + shader_material[id] = meta +end + +function shader.define( arg ) + local name = assert(arg.name) + local id = shader_name[name] + if id == nil then + assert(USER_PROGRAM < MAX_PROGRAM) + id = USER_PROGRAM + USER_PROGRAM = id + 1 + end + + local vs = PRECISION .. (arg.vs or sprite_vs) + local fs = PRECISION_HIGH .. (arg.fs or sprite_fs) + + s.load(id, fs, vs, arg.texture) + + local uniform = arg.uniform + if uniform then + for _,v in ipairs(uniform) do + v.type = assert(uniform_format[v.type]) + end + s.uniform_bind(id, uniform) + end + + local r = create_shader(id, uniform) + shader_name[name] = id + + material_meta(id, arg) + return r +end + +function shader.material_meta(prog) + return shader_material[prog] +end + return shader diff --git a/ejoy2d/sprite.lua b/ejoy2d/sprite.lua index ebc6e57b..f202cb29 100644 --- a/ejoy2d/sprite.lua +++ b/ejoy2d/sprite.lua @@ -4,6 +4,7 @@ local pack = require "ejoy2d.spritepack" local shader = require "ejoy2d.shader" local richtext = require "ejoy2d.richtext" +local setmetatable = setmetatable local method = c.method local method_fetch = method.fetch local method_test = method.test @@ -14,6 +15,22 @@ local test local get = c.get local set = c.set +local get_material = get.material +function get:material() + local m = get_material(self) + if m == nil then + local prog + m, prog = c.new_material(self) + if m == nil then + return + end + local meta = shader.material_meta(prog) + setmetatable(m, meta) + end + + return m +end + local set_program = set.program function set:program(prog) if prog == nil then diff --git a/examples/ex07.lua b/examples/ex07.lua index a60e0f96..c909d846 100644 --- a/examples/ex07.lua +++ b/examples/ex07.lua @@ -28,9 +28,12 @@ function game.update() p=p+1 end +bird:ps(200,0) + function game.drawframe() ej.clear() rb:draw(p,p) + bird:draw(screencoord) end function game.touch(what, x, y) diff --git a/examples/ex08.lua b/examples/ex08.lua new file mode 100644 index 00000000..8d4f94fb --- /dev/null +++ b/examples/ex08.lua @@ -0,0 +1,86 @@ +-- This example show how user defined shader works + +local ej = require "ejoy2d" +local fw = require "ejoy2d.framework" +local pack = require "ejoy2d.simplepackage" + +pack.load { + pattern = fw.WorkDir..[[examples/asset/?]], + "sample", +} + + +-- define a shader +local s = ej.define_shader { + name = "EXAMPLE", + fs = [[ +varying vec2 v_texcoord; +uniform vec4 color; +uniform sampler2D texture0; + +void main() { + vec4 tmp = texture2D(texture0, v_texcoord); + gl_FragColor = color + tmp; +} + ]], + uniform = { + { + name = "color", + type = "float4", + } + }, + texture = { + "texture0", + } +} + +s.color(1,0,0,1) -- set shader color + + +local obj = ej.sprite("sample","cannon") +obj:ps(100,100) +obj.program = "EXAMPLE" +obj.turret.program = "EXAMPLE" +obj.turret.material:color(0,0,1,1) + + +local obj2 = ej.sprite("sample","cannon") +obj2:ps(200,100) + +obj2.turret.program = "EXAMPLE" +obj2.turret.material:color(0,1,0,1) -- uniform can be set in material + + +local obj3 = ej.sprite("sample","cannon") +obj3:ps(300,100) +obj3.program = "EXAMPLE" + +local game = {} + +function game.update() +end + +function game.drawframe() + ej.clear(0xff808080) -- clear (0.5,0.5,0.5,1) gray + obj:draw() + obj2:draw() + obj3:draw() +end + +function game.touch(what, x, y) +end + +function game.message(...) +end + +function game.handle_error(...) +end + +function game.on_resume() +end + +function game.on_pause() +end + +ej.start(game) + diff --git a/ios/example/example.xcodeproj/project.pbxproj b/ios/example/example.xcodeproj/project.pbxproj index 62edac59..578484c9 100644 --- a/ios/example/example.xcodeproj/project.pbxproj +++ b/ios/example/example.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 5E344A8B1A011ADA00FC33BD /* carray.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E344A851A011ADA00FC33BD /* carray.c */; }; + 5E344A8C1A011ADA00FC33BD /* log.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E344A871A011ADA00FC33BD /* log.c */; }; + 5E344A8D1A011ADA00FC33BD /* render.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E344A891A011ADA00FC33BD /* render.c */; }; AE7789AF19C161E300AFCC14 /* lrenderbuffer.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7789AD19C161E300AFCC14 /* lrenderbuffer.c */; }; AE7789B019C161E300AFCC14 /* renderbuffer.c in Sources */ = {isa = PBXBuildFile; fileRef = AE7789AE19C161E300AFCC14 /* renderbuffer.c */; }; E675687F18756D8B00466F0C /* scissor.c in Sources */ = {isa = PBXBuildFile; fileRef = E675687D18756D8B00466F0C /* scissor.c */; }; @@ -90,6 +93,18 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 5E344A7C1A0119F800FC33BD /* array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = array.h; path = ../../lib/array.h; sourceTree = ""; }; + 5E344A7D1A0119F800FC33BD /* lrenderbuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lrenderbuffer.h; path = ../../lib/lrenderbuffer.h; sourceTree = ""; }; + 5E344A7E1A0119F800FC33BD /* platform_print.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = platform_print.h; path = ../../lib/platform_print.h; sourceTree = ""; }; + 5E344A801A0119F800FC33BD /* renderbuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = renderbuffer.h; path = ../../lib/renderbuffer.h; sourceTree = ""; }; + 5E344A831A011ADA00FC33BD /* blendmode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blendmode.h; sourceTree = ""; }; + 5E344A841A011ADA00FC33BD /* block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = block.h; sourceTree = ""; }; + 5E344A851A011ADA00FC33BD /* carray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = carray.c; sourceTree = ""; }; + 5E344A861A011ADA00FC33BD /* carray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = carray.h; sourceTree = ""; }; + 5E344A871A011ADA00FC33BD /* log.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = log.c; sourceTree = ""; }; + 5E344A881A011ADA00FC33BD /* log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = log.h; sourceTree = ""; }; + 5E344A891A011ADA00FC33BD /* render.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render.c; sourceTree = ""; }; + 5E344A8A1A011ADA00FC33BD /* render.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render.h; sourceTree = ""; }; AE7789AD19C161E300AFCC14 /* lrenderbuffer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lrenderbuffer.c; path = ../../lib/lrenderbuffer.c; sourceTree = ""; }; AE7789AE19C161E300AFCC14 /* renderbuffer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = renderbuffer.c; path = ../../lib/renderbuffer.c; sourceTree = ""; }; E675687D18756D8B00466F0C /* scissor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = scissor.c; path = ../../lib/scissor.c; sourceTree = ""; }; @@ -147,7 +162,6 @@ E6C2640F1872AD44008035E3 /* sprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sprite.h; path = ../../lib/sprite.h; sourceTree = ""; }; E6C264101872AD44008035E3 /* spritepack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = spritepack.h; path = ../../lib/spritepack.h; sourceTree = ""; }; E6C264111872AD44008035E3 /* texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = texture.h; path = ../../lib/texture.h; sourceTree = ""; }; - E6C264121872B266008035E3 /* font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = font.h; sourceTree = ""; }; E6C264131872B266008035E3 /* font.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = font.m; sourceTree = ""; }; E6C2642C1872CD4D008035E3 /* ejoy2d */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ejoy2d; path = ../../ejoy2d; sourceTree = ""; }; E6C264311872E451008035E3 /* examples */ = {isa = PBXFileReference; lastKnownFileType = folder; name = examples; path = ../../examples; sourceTree = ""; }; @@ -236,6 +250,22 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 5E344A821A011ADA00FC33BD /* render */ = { + isa = PBXGroup; + children = ( + 5E344A831A011ADA00FC33BD /* blendmode.h */, + 5E344A841A011ADA00FC33BD /* block.h */, + 5E344A851A011ADA00FC33BD /* carray.c */, + 5E344A861A011ADA00FC33BD /* carray.h */, + 5E344A871A011ADA00FC33BD /* log.c */, + 5E344A881A011ADA00FC33BD /* log.h */, + 5E344A891A011ADA00FC33BD /* render.c */, + 5E344A8A1A011ADA00FC33BD /* render.h */, + ); + name = render; + path = ../../lib/render; + sourceTree = ""; + }; E6C2314F187275D10029D57B = { isa = PBXGroup; children = ( @@ -276,7 +306,6 @@ E6C23161187275D10029D57B /* example */ = { isa = PBXGroup; children = ( - E6C264121872B266008035E3 /* font.h */, E6C264131872B266008035E3 /* font.m */, E6C262E41872A91B008035E3 /* winfw.c */, E6C2319018728E7C0029D57B /* winfw.h */, @@ -322,6 +351,11 @@ E6C264021872AD22008035E3 /* lib */ = { isa = PBXGroup; children = ( + 5E344A821A011ADA00FC33BD /* render */, + 5E344A7C1A0119F800FC33BD /* array.h */, + 5E344A7D1A0119F800FC33BD /* lrenderbuffer.h */, + 5E344A7E1A0119F800FC33BD /* platform_print.h */, + 5E344A801A0119F800FC33BD /* renderbuffer.h */, AE7789AD19C161E300AFCC14 /* lrenderbuffer.c */, AE7789AE19C161E300AFCC14 /* renderbuffer.c */, E675687D18756D8B00466F0C /* scissor.c */, @@ -541,6 +575,7 @@ E6EF880418D2CE0800F01E49 /* lbaselib.c in Sources */, E6EF881318D2CE0800F01E49 /* lmem.c in Sources */, E6EF881418D2CE0800F01E49 /* loadlib.c in Sources */, + 5E344A8D1A011ADA00FC33BD /* render.c in Sources */, E6EF881E18D2CE0800F01E49 /* ltm.c in Sources */, E6EF881618D2CE0800F01E49 /* lopcodes.c in Sources */, E6EF881918D2CE0800F01E49 /* lstate.c in Sources */, @@ -557,6 +592,7 @@ E6EF880318D2CE0800F01E49 /* lauxlib.c in Sources */, E6C263FB1872ACEC008035E3 /* ppm.c in Sources */, AE7789B019C161E300AFCC14 /* renderbuffer.c in Sources */, + 5E344A8C1A011ADA00FC33BD /* log.c in Sources */, E6C263FC1872ACEC008035E3 /* screen.c in Sources */, E6C263FD1872ACEC008035E3 /* shader.c in Sources */, E6C263FE1872ACEC008035E3 /* sprite.c in Sources */, @@ -570,6 +606,7 @@ E6C2318E187288C50029D57B /* EJViewController.m in Sources */, E6EF880E18D2CE0800F01E49 /* lgc.c in Sources */, E6EF881118D2CE0800F01E49 /* llex.c in Sources */, + 5E344A8B1A011ADA00FC33BD /* carray.c in Sources */, E6C262E51872A91B008035E3 /* winfw.c in Sources */, E6EF880918D2CE0800F01E49 /* ldblib.c in Sources */, E6C23168187275D10029D57B /* main.m in Sources */, @@ -697,9 +734,10 @@ E6C23185187275D20029D57B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; + ALWAYS_SEARCH_USER_PATHS = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CODE_SIGN_IDENTITY = "iPhone Developer"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "example/example-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -710,6 +748,7 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, ../../lib, + ../../lib/render, ../../lua, ); INFOPLIST_FILE = "example/example-Info.plist"; @@ -722,9 +761,10 @@ E6C23186187275D20029D57B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; + ALWAYS_SEARCH_USER_PATHS = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CODE_SIGN_IDENTITY = "iPhone Developer"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "example/example-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = "EJOY2D_OS=IOS"; @@ -732,6 +772,7 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, ../../lib, + ../../lib/render, ../../lua, ); INFOPLIST_FILE = "example/example-Info.plist"; diff --git a/lib/label.c b/lib/label.c index 33100e9b..f7473118 100644 --- a/lib/label.c +++ b/lib/label.c @@ -1,12 +1,13 @@ #include "label.h" #include "dfont.h" #include "shader.h" -#include "opengl.h" #include "matrix.h" #include "spritepack.h" #include "screen.h" #include "array.h" +#include "render.h" + #include #include #include @@ -14,35 +15,31 @@ #define TEX_HEIGHT 1024 #define TEX_WIDTH 1024 #define FONT_SIZE 31 -#define TEX_FMT GL_ALPHA +#define TEX_FMT TEXTURE_A8 -static GLuint Tex; +static RID Tex; static struct dfont * Dfont = NULL; static int Outline = 1; +static struct render *R = NULL; + +void +label_initrender(struct render *r) { + R = r; +} void label_load() { if (Dfont) return; Dfont = dfont_create(TEX_WIDTH, TEX_HEIGHT); - glPixelStorei(GL_UNPACK_ALIGNMENT,1); - - glGenTextures(1, &(Tex)); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, Tex); - - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - glTexImage2D(GL_TEXTURE_2D, 0, TEX_FMT, (GLsizei)TEX_WIDTH, (GLsizei)TEX_HEIGHT, 0, TEX_FMT, GL_UNSIGNED_BYTE, NULL); + Tex = render_texture_create(R, TEX_WIDTH, TEX_HEIGHT, TEX_FMT, TEXTURE_2D, 0); + render_texture_update(R, Tex, TEX_WIDTH, TEX_HEIGHT ,NULL, 0, 0); } void label_unload() { - glDeleteTextures(1,&Tex); + render_release(R, TEXTURE, Tex); dfont_release(Dfont); Dfont = NULL; } @@ -191,8 +188,7 @@ gen_char(int unicode, const char * utf8, int size, int outline) { // write_pgm(unicode, ctx.w, ctx.h, buffer); font_release(&ctx); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexSubImage2D(GL_TEXTURE_2D, 0, rect->x, rect->y, rect->w, rect->h, TEX_FMT, GL_UNSIGNED_BYTE, buffer); + render_texture_subupdate(R, Tex, buffer, rect->x, rect->y, rect->w, rect->h); return rect; } @@ -453,13 +449,13 @@ label_get_color(struct pack_label * l, const struct sprite_trans *arg) { void label_draw(const struct rich_text *rich, struct pack_label * l, struct srt *srt, const struct sprite_trans *arg) { - shader_texture(Tex); + shader_texture(Tex, 0); uint32_t color = label_get_color(l, arg); - const char *str = rich->text; + const char *str = rich->text; char utf8[7]; int i; - int ch = 0, w = 0, cy = 0, pre = 0, char_cnt = 0; + int ch = 0, w = 0, cy = 0, pre = 0, char_cnt = 0; for (i=0; str && str[i];) { int unicode; uint8_t c = (uint8_t)str[i]; diff --git a/lib/label.h b/lib/label.h index e90027e2..1a51f080 100644 --- a/lib/label.h +++ b/lib/label.h @@ -20,6 +20,8 @@ struct rich_text { struct label_field *fields; }; +struct render; +void label_initrender(struct render *R); void label_load(); void label_unload(); void label_flush(); diff --git a/lib/lshader.c b/lib/lshader.c index 23187025..dda58a18 100644 --- a/lib/lshader.c +++ b/lib/lshader.c @@ -1,18 +1,33 @@ #include #include +#include #include "shader.h" #include "screen.h" #include "texture.h" #include "array.h" #include "spritepack.h" +#include "render.h" +#include "material.h" static int lload(lua_State *L) { int prog = (int)luaL_checkinteger(L,1); const char *fs = luaL_checkstring(L, 2); const char *vs = luaL_checkstring(L, 3); - shader_load(prog, fs, vs); + if (lua_istable(L, 4)) { + int texture_number = lua_rawlen(L, 4); + ARRAY(const char *, name, texture_number); + luaL_checkstack(L, texture_number + 1, NULL); + int i; + for (i=0;i> 24) & 0xff ) / 255.0; - float r = ((c >> 16) & 0xff ) / 255.0; - float g = ((c >> 8) & 0xff ) / 255.0; - float b = ((c >> 0) & 0xff ) / 255.0; - glClearColor(r,g,b,a); - glClear(GL_COLOR_BUFFER_BIT); + shader_clear(c); + + return 0; +} +static int +luniform_bind(lua_State *L) { + int prog = luaL_checkinteger(L, 1); + luaL_checktype(L, 2, LUA_TTABLE); + int n = lua_rawlen(L, 2); + int i; + for (i=0;i sizeof(v)/sizeof(v[0])+2) + return luaL_error(L, "too many agrument"); + int n = top-2; + int i; + for (i=0;i #include @@ -37,6 +38,7 @@ newlabel(lua_State *L, struct pack_label *label) { s->total_frame = 0; s->frame = 0; s->data.rich_text = NULL; + s->material = NULL; return s; } @@ -175,6 +177,7 @@ newanchor(lua_State *L) { s->data.anchor->ps = NULL; s->data.anchor->pic = NULL; s->s.mat = &s->data.anchor->mat; + s->material = NULL; matrix_identity(s->s.mat); return s; @@ -244,6 +247,17 @@ self(lua_State *L) { return s; } +static void +get_reftable(lua_State *L, int index) { + lua_getuservalue(L, index); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + lua_createtable(L, 0, 1); + lua_pushvalue(L, -1); + lua_setuservalue(L, index); + } +} + static int lgetframe(lua_State *L) { struct sprite * s = self(L); @@ -374,6 +388,12 @@ lsetprogram(lua_State *L) { } else { s->t.program = (int)luaL_checkinteger(L,2); } + if (s->material) { + s->material = NULL; + get_reftable(L, 1); + lua_pushnil(L); + lua_setfield(L, -2, "material"); + } return 0; } @@ -387,24 +407,6 @@ lsetscissor(lua_State *L) { return 0; } -static int -lsetpicmask(lua_State *L) { - struct sprite *s = self(L); - if (s->type != TYPE_PICTURE) { - return luaL_error(L, "Only picture can set mask"); - } - struct sprite *mask = (struct sprite*) lua_touserdata(L, 2); - if (mask && mask->type != TYPE_PICTURE) { - return luaL_error(L, "Mask must be picture"); - } - struct pack_picture *m = NULL; - if (mask) { - m = mask->s.pic; - } - s->data.mask = m; - return 0; -} - static int lgetname(lua_State *L) { struct sprite *s = self(L); @@ -601,9 +603,20 @@ lgetparent(lua_State *L) { static int lgetprogram(lua_State *L) { - struct sprite *s = self(L); - lua_pushinteger(L, s->t.program); - return 1; + struct sprite *s = self(L); + lua_pushinteger(L, s->t.program); + return 1; +} + +static int +lgetmaterial(lua_State *L) { + struct sprite *s = self(L); + if (s->material) { + get_reftable(L,1); + lua_getfield(L, -1, "material"); + return 1; + } + return 0; } static void @@ -624,7 +637,8 @@ lgetter(lua_State *L) { {"parent_name", lgetparentname }, // todo: maybe unused , use parent instead {"has_parent", lhasparent }, // todo: maybe unused , use parent instead {"parent", lgetparent }, - {"program", lgetprogram }, + {"program", lgetprogram }, + {"material", lgetmaterial }, {NULL, NULL}, }; luaL_newlib(L,l); @@ -644,23 +658,11 @@ lsetter(lua_State *L) { {"message", lsetmessage }, {"program", lsetprogram }, {"scissor", lsetscissor }, - {"picture_mask", lsetpicmask }, {NULL, NULL}, }; luaL_newlib(L,l); } -static void -get_reftable(lua_State *L, int index) { - lua_getuservalue(L, index); - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - lua_createtable(L, 0, 1); - lua_pushvalue(L, -1); - lua_setuservalue(L, index); - } -} - static void ref_parent(lua_State *L, int index, int parent) { get_reftable(L, index); @@ -1259,18 +1261,41 @@ lnewproxy(lua_State *L) { s->start_frame = 0; s->total_frame = 0; s->frame = 0; + s->material = NULL; s->data.children[0] = NULL; sprite_action(s, NULL); return 1; } +static int +lnewmaterial(lua_State *L) { + struct sprite *s = self(L); + int sz = sprite_material_size(s); + if (sz == 0) + return luaL_error(L, "The program has not material"); + get_reftable(L, 1); + + lua_createtable(L, 0, 1); + void * m = lua_newuserdata(L, sz); // sprite, uservalue, table, matertial + s->material = m; + material_init(m, sz, s->t.program); + lua_setfield(L, -2, "__obj"); + + lua_pushvalue(L, -1); // sprite, uservalue, table, table + lua_setfield(L, -3, "material"); + lua_pushinteger(L, s->t.program); + + return 2; // return table, program +} + int ejoy2d_sprite(lua_State *L) { luaL_Reg l[] ={ { "new", lnew }, { "label", lnewlabel }, { "proxy", lnewproxy }, + { "new_material", lnewmaterial }, { "label_gen_outline", lgenoutline }, { "enable_visible_test", lenable_visible_test }, { NULL, NULL }, diff --git a/lib/material.h b/lib/material.h new file mode 100644 index 00000000..101d6505 --- /dev/null +++ b/lib/material.h @@ -0,0 +1,16 @@ +#ifndef ejoy2d_material_h +#define ejoy2d_material_h + +// the implemention is in shader.c + +struct material; +struct render; + +int material_size(int prog); +struct material * material_init(void *self, int size, int prog); +void material_apply(int prog, struct material *); +int material_setuniform(struct material *, int index, int n, const float *v); +int material_settexture(struct material *, int channel, int texture); +// todo: change alpha blender mode, change attrib layout, etc. + +#endif diff --git a/lib/opengl.h b/lib/opengl.h index 6a84f69e..9b06952f 100644 --- a/lib/opengl.h +++ b/lib/opengl.h @@ -5,7 +5,7 @@ #define OPENGLES 2 #include -#import +#import #elif defined(linux) || defined(__linux) || defined(__linux__) diff --git a/lib/ppm.c b/lib/ppm.c index 9894b63c..a4391c71 100644 --- a/lib/ppm.c +++ b/lib/ppm.c @@ -1,6 +1,7 @@ #include "ppm.h" #include "texture.h" #include "array.h" +#include "render.h" #include #include @@ -257,15 +258,15 @@ loadtexture(lua_State *L) { int type = 0; if (ppm.depth == 255) { if (ppm.step == 4) { - type = Texture2DPixelFormat_RGBA8888; + type = TEXTURE_RGBA8; } else if (ppm.step == 3) { - type = Texture2DPixelFormat_RGB888; + type = TEXTURE_RGB; } else { - type = Texture2DPixelFormat_A8; + type = TEXTURE_A8; } } else { if (ppm.step == 4) { - type = Texture2DPixelFormat_RGBA4444; + type = TEXTURE_RGBA8; uint16_t * tmp = (uint16_t * )malloc(ppm.width * ppm.height * sizeof(uint16_t)); int i; for (i=0;ibuffer = buffer; + B->sz = sz; +} + +static inline void * +block_slice(struct block * B, int sz) { + if (B->sz < sz) { + return NULL; + } + void * ret = B->buffer; + B->buffer += sz; + B->sz -= sz; + return ret; +} + +#endif diff --git a/lib/render/carray.c b/lib/render/carray.c new file mode 100644 index 00000000..7bc34103 --- /dev/null +++ b/lib/render/carray.c @@ -0,0 +1,96 @@ +#include "carray.h" + +#include +#include +#include + +// align to qword +#define ALIGN(n) (((n) + 7) & ~7) + +struct array_node { + struct array_node * next; +}; + +int +array_size(int n, int sz) { + sz = ALIGN(sz); + return n * sz; +} + +void +array_init(struct array *p, void * buffer, int n, int nsz) { + int sz = ALIGN(nsz); + char * ptr = buffer; + int i; + for (i=0;inext = node_next; + } + struct array_node * node = (struct array_node *)(ptr + (n-1)*sz); + node->next = NULL; + p->n = n; + p->sz = sz; + p->buffer = buffer; + p->freelist = buffer; +} + +void * +array_alloc(struct array *p) { + struct array_node * node = p->freelist; + if (node == NULL) { + return NULL; + } + p->freelist = node->next; + memset(node, 0, p->sz); + return node; +} + +void +array_free(struct array *p, void *v) { + struct array_node * node = v; + if (node) { + node->next = p->freelist; + p->freelist = node; + } +} + +int +array_id(struct array *p, void *v) { + if (v == NULL) + return 0; + int idx = ((char *)v - p->buffer) / p->sz; + assert(idx >= 0 && idx < p->n); + + return idx + 1; +} + +void * +array_ref(struct array *p, int id) { + if (id == 0) + return NULL; + --id; + assert(id >= 0 && id < p->n); + void * ptr = p->buffer + p->sz * id; + return ptr; +} + +void +array_exit(struct array *p, void (*close)(void *p, void *ud), void *ud) { + char flag[p->n]; + memset(flag, 0, p->n); + struct array_node * n = p->freelist; + while (n) { + int idx = array_id(p, n) - 1; + flag[idx] = 1; + n = n->next; + } + int i; + for (i=0;in;i++) { + if (flag[i] == 0) { + struct array_node * n = array_ref(p, i+1); + close(n, ud); + } + } +} + diff --git a/lib/render/carray.h b/lib/render/carray.h new file mode 100644 index 00000000..12a40c30 --- /dev/null +++ b/lib/render/carray.h @@ -0,0 +1,22 @@ +#ifndef ejoy3d_array_h +#define ejoy3d_array_h + +struct array_node; + +struct array { + int n; + int sz; + char * buffer; + struct array_node * freelist; +}; + +int array_size(int n, int sz); +void array_init(struct array *p, void * buffer, int n, int sz); +void * array_alloc(struct array *p); +void array_free(struct array *p, void *v); +void array_exit(struct array *p, void (*close)(void *p, void *ud), void *ud); + +int array_id(struct array *p, void *); +void * array_ref(struct array *p, int id); + +#endif diff --git a/lib/render/log.c b/lib/render/log.c new file mode 100644 index 00000000..7e16763a --- /dev/null +++ b/lib/render/log.c @@ -0,0 +1,39 @@ +#include "log.h" +#include + +void +log_init(struct log *log, FILE *f) { + log->f = f; +} + +/* +void +log_printf(struct log *log, const char * format, ...) { + va_list ap; + va_start(ap, format); + vfprintf(log->f, format, ap); + va_end(ap); + fflush(log->f); +} +*/ + +// for ejoy2d compatibility + +#include +#include "platform_print.h" + +void +log_printf(struct log *log,const char * format, ...) { + if (format[0] == '!') { + va_list ap; + va_start(ap, format); + pf_vprint(format+1, ap); + va_end(ap); + } else { + va_list ap; + va_start(ap, format); + pf_vprint(format, ap); + va_end(ap); + exit(1); + } +} diff --git a/lib/render/log.h b/lib/render/log.h new file mode 100644 index 00000000..bb2d6969 --- /dev/null +++ b/lib/render/log.h @@ -0,0 +1,13 @@ +#ifndef ejoy3d_log_h +#define ejoy3d_log_h + +#include + +struct log { + FILE *f; +}; + +void log_init(struct log *log, FILE *f); +void log_printf(struct log *log, const char * format, ...); + +#endif diff --git a/lib/render/render.c b/lib/render/render.c new file mode 100644 index 00000000..a29074c8 --- /dev/null +++ b/lib/render/render.c @@ -0,0 +1,1031 @@ +#include "render.h" +#include "opengl.h" +#include "carray.h" +#include "block.h" +#include "log.h" + +#include +#include +#include +#include +#include + +#define MAX_VB_SLOT 8 +#define MAX_ATTRIB 16 +#define MAX_TEXTURE 8 +#define CHANGE_INDEXBUFFER 0x1 +#define CHANGE_VERTEXBUFFER 0x2 +#define CHANGE_TEXTURE 0x4 +#define CHANGE_BLEND 0x8 +#define CHANGE_DEPTH 0x10 +#define CHANGE_CULL 0x20 +#define CHANGE_TARGET 0x40 +#define CHANGE_SCISSOR 0x80 + +//#define CHECK_GL_ERROR +//#define CHECK_GL_ERROR assert(check_opengl_error()); +#define CHECK_GL_ERROR check_opengl_error_debug(R, __FILE__, __LINE__); + +struct buffer { + GLuint glid; + GLenum gltype; + int n; + int stride; +}; + +struct attrib { + int n; + struct vertex_attrib a[MAX_ATTRIB]; +}; + +struct target { + GLuint glid; + RID tex; +}; + +struct texture { + GLuint glid; + int width; + int height; + int mipmap; + enum TEXTURE_FORMAT format; + enum TEXTURE_TYPE type; + int memsize; +}; + +struct attrib_layout { + int vbslot; + GLint size; + GLenum type; + GLboolean normalized; + int offset; +}; + +struct shader { + GLuint glid; + int n; + struct attrib_layout a[MAX_ATTRIB]; + int texture_n; + int texture_uniform[MAX_TEXTURE]; +}; + +struct rstate { + RID indexbuffer; + RID target; + enum BLEND_FORMAT blend_src; + enum BLEND_FORMAT blend_dst; + enum DEPTH_FORMAT depth; + enum CULL_MODE cull; + int depthmask; + int scissor; + RID texture[MAX_TEXTURE]; +}; + +struct render { + uint32_t changeflag; + RID attrib_layout; + RID vbslot[MAX_VB_SLOT]; + RID program; + GLint default_framebuffer; + struct rstate current; + struct rstate last; + struct log log; + struct array buffer; + struct array attrib; + struct array target; + struct array texture; + struct array shader; +}; + +static void +check_opengl_error_debug(struct render *R, const char *filename, int line) { + GLenum error = glGetError(); + if (error != GL_NO_ERROR +// && error != GL_INVALID_ENUM +// && error != GL_INVALID_VALUE +// && error != GL_INVALID_OPERATION +// && error != GL_OUT_OF_MEMORY +// && error != GL_STACK_OVERFLOW +// && error != GL_STACK_UNDERFLOW + ) { + log_printf(&R->log, "GL_ERROR (0x%x) @ %s : %d\n", error, filename, line); + exit(1); + } +} + +// what should be VERTEXBUFFER or INDEXBUFFER +RID +render_buffer_create(struct render *R, enum RENDER_OBJ what, const void *data, int n, int stride) { + GLenum gltype; + switch(what) { + case VERTEXBUFFER: + gltype = GL_ARRAY_BUFFER; + break; + case INDEXBUFFER: + gltype = GL_ELEMENT_ARRAY_BUFFER; + break; + default: + return 0; + } + struct buffer * buf = array_alloc(&R->buffer); + if (buf == NULL) + return 0; + glGenBuffers(1, &buf->glid); + glBindBuffer(gltype, buf->glid); + if (data) { + glBufferData(gltype, n * stride, data, GL_STATIC_DRAW); + buf->n = n; + } else { + buf->n = 0; + } + buf->gltype = gltype; + buf->stride = stride; + + CHECK_GL_ERROR + + return array_id(&R->buffer, buf); +} + +void +render_buffer_update(struct render *R, RID id, const void * data, int n) { + struct buffer * buf = array_ref(&R->buffer, id); + glBindBuffer(buf->gltype, buf->glid); + buf->n = n; + glBufferData(buf->gltype, n * buf->stride, data, GL_DYNAMIC_DRAW); + CHECK_GL_ERROR +} + +static void +close_buffer(void *p, void *R) { + struct buffer * buf = p; + glDeleteBuffers(1,&buf->glid); + + CHECK_GL_ERROR +} + +RID +render_register_vertexlayout(struct render *R, int n, struct vertex_attrib * attrib) { + assert(n <= MAX_ATTRIB); + struct attrib * a = array_alloc(&R->attrib); + if (a == NULL) + return 0; + + a->n = n; + memcpy(a->a, attrib, n * sizeof(struct vertex_attrib)); + + RID id = array_id(&R->attrib, a); + + R->attrib_layout = id; + + return id; +} + +static GLuint +compile(struct render *R, const char * source, int type) { + GLint status; + + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &source, NULL); + glCompileShader(shader); + + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + + if (status == GL_FALSE) { + char buf[1024]; + GLint len; + glGetShaderInfoLog(shader, 1024, &len, buf); + + log_printf(&R->log, "compile failed:%s\n" + "source:\n %s\n", + buf, source); + glDeleteShader(shader); + return 0; + } + + CHECK_GL_ERROR + + return shader; +} + +static int +link(struct render *R, GLuint prog) { + GLint status; + glLinkProgram(prog); + + glGetProgramiv(prog, GL_LINK_STATUS, &status); + if (status == 0) { + char buf[1024]; + GLint len; + glGetProgramInfoLog(prog, 1024, &len, buf); + + log_printf(&R->log, "link failed:%s\n", buf); + + return 0; + } + + CHECK_GL_ERROR + + return 1; +} + +static int +compile_link(struct render *R, struct shader *s, const char * VS, const char *FS) { + GLuint fs = compile(R, FS, GL_FRAGMENT_SHADER); + if (fs == 0) { + log_printf(&R->log, "Can't compile fragment shader"); + return 0; + } else { + glAttachShader(s->glid, fs); + } + + GLuint vs = compile(R, VS, GL_VERTEX_SHADER); + if (vs == 0) { + log_printf(&R->log, "Can't compile vertex shader"); + return 0; + } else { + glAttachShader(s->glid, vs); + } + + if (R->attrib_layout == 0) + return 0; + + struct attrib * a = array_ref(&R->attrib, R->attrib_layout); + s->n = a->n; + int i; + for (i=0;in;i++) { + struct vertex_attrib *va = &a->a[i]; + struct attrib_layout *al = &s->a[i]; + glBindAttribLocation(s->glid, i, va->name); + al->vbslot = va->vbslot; + al->offset = va->offset; + al->size = va->n; + switch (va->size) { + case 1: + al->type = GL_UNSIGNED_BYTE; + al->normalized = GL_TRUE; + break; + case 2: + al->type = GL_UNSIGNED_SHORT; + al->normalized = GL_TRUE; + break; + case 4: + al->type = GL_FLOAT; + al->normalized = GL_FALSE; + break; + default: + return 0; + } + } + + return link(R, s->glid); +} + +RID +render_shader_create(struct render *R, struct shader_init_args *args) { + struct shader * s = array_alloc(&R->shader); + if (s == NULL) { + return 0; + } + s->glid = glCreateProgram(); + if (!compile_link(R, s, args->vs, args->fs)) { + glDeleteProgram(s->glid); + array_free(&R->shader, s); + return 0; + } + + s->texture_n = args->texture; + int i; + for (i=0;itexture_n;i++) { + s->texture_uniform[i] = glGetUniformLocation(s->glid, args->texture_uniform[i]); + } + + CHECK_GL_ERROR + + return array_id(&R->shader, s); +} + +static void +close_shader(void *p, void *R) { + struct shader * shader = p; + glDeleteProgram(shader->glid); + + CHECK_GL_ERROR +} + +static void +close_texture(void *p, void *R) { + struct texture * tex = p; + glDeleteTextures(1,&tex->glid); + + CHECK_GL_ERROR +} + +static void +close_target(void *p, void *R) { + struct target * tar = p; + glDeleteFramebuffers(1, &tar->glid); + + CHECK_GL_ERROR +} + +void +render_release(struct render *R, enum RENDER_OBJ what, RID id) { + switch (what) { + case VERTEXBUFFER: + case INDEXBUFFER: { + struct buffer * buf = array_ref(&R->buffer, id); + if (buf) { + close_buffer(buf, R); + array_free(&R->buffer, buf); + } + break; + } + case SHADER: { + struct shader * shader = array_ref(&R->shader, id); + if (shader) { + close_shader(shader, R); + array_free(&R->shader, shader); + } + break; + } + case TEXTURE : { + struct texture * tex = array_ref(&R->texture, id); + if (tex) { + close_texture(tex, R); + array_free(&R->texture, tex); + } + break; + } + case TARGET : { + struct target * tar = array_ref(&R->target, id); + if (tar) { + close_target(tar, R); + array_free(&R->target, tar); + } + break; + } + default: + assert(0); + break; + } +} + +void +render_set(struct render *R, enum RENDER_OBJ what, RID id, int slot) { + switch (what) { + case VERTEXBUFFER: + assert(slot >= 0 && slot < MAX_VB_SLOT); + R->vbslot[slot] = id; + R->changeflag |= CHANGE_VERTEXBUFFER; + break; + case INDEXBUFFER: + R->current.indexbuffer = id; + R->changeflag |= CHANGE_INDEXBUFFER; + break; + case VERTEXLAYOUT: + R->attrib_layout = id; + break; + case TEXTURE: + assert(slot >= 0 && slot < MAX_TEXTURE); + R->current.texture[slot] = id; + R->changeflag |= CHANGE_TEXTURE; + break; + case TARGET: + R->current.target = id; + R->changeflag |= CHANGE_TARGET; + break; + default: + assert(0); + break; + } +} + +static void +apply_texture_uniform(struct shader *s) { + int i; + for (i=0;itexture_n;i++) { + int loc = s->texture_uniform[i]; + if (loc >= 0) { + glUniform1i(loc, i); + } + } +} + +void +render_shader_bind(struct render *R, RID id) { + R->program = id; + R->changeflag |= CHANGE_VERTEXBUFFER; + struct shader * s = array_ref(&R->shader, id); + if (s) { + glUseProgram(s->glid); + apply_texture_uniform(s); + } else { + glUseProgram(0); + } + + CHECK_GL_ERROR +} + +int +render_size(struct render_init_args *args) { + return sizeof(struct render) + + array_size(args->max_buffer, sizeof(struct buffer)) + + array_size(args->max_layout, sizeof(struct attrib)) + + array_size(args->max_target, sizeof(struct target)) + + array_size(args->max_texture, sizeof(struct texture)) + + array_size(args->max_shader, sizeof(struct shader)); +} + +static void +new_array(struct block *B, struct array *A, int n, int sz) { + int s = array_size(n, sz); + void * buffer = block_slice(B, s); + array_init(A, buffer, n, sz); +} + +struct render * +render_init(struct render_init_args *args, void * buffer, int sz) { + struct block B; + block_init(&B, buffer, sz); + struct render * R = block_slice(&B, sizeof(struct render)); + memset(R, 0, sizeof(*R)); + log_init(&R->log, stderr); + new_array(&B, &R->buffer, args->max_buffer, sizeof(struct buffer)); + new_array(&B, &R->attrib, args->max_layout, sizeof(struct attrib)); + new_array(&B, &R->target, args->max_target, sizeof(struct target)); + new_array(&B, &R->texture, args->max_texture, sizeof(struct texture)); + new_array(&B, &R->shader, args->max_shader, sizeof(struct shader)); + + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &R->default_framebuffer); + + CHECK_GL_ERROR + + return R; +} + +void +render_exit(struct render * R) { + array_exit(&R->buffer, close_buffer, R); + array_exit(&R->shader, close_shader, R); + array_exit(&R->texture, close_texture, R); + array_exit(&R->target, close_target, R); +} + +void +render_setviewport(struct render *R, int x, int y, int width, int height) { + glViewport(x, y, width, height); +} + +void +render_setscissor(struct render *R, int x, int y, int width, int height ) { + glScissor(x,y,width,height); +} + +static void +apply_vb(struct render *R) { + RID prog = R->program; + struct shader * s = array_ref(&R->shader, prog); + if (s) { + int i; + RID last_vb = 0; + int stride = 0; + for (i=0;in;i++) { + struct attrib_layout *al = &s->a[i]; + int vbidx = al->vbslot; + RID vb = R->vbslot[vbidx]; + if (last_vb != vb) { + struct buffer * buf = array_ref(&R->buffer, vb); + if (buf == NULL) { + continue; + } + glBindBuffer(GL_ARRAY_BUFFER, buf->glid); + last_vb = vb; + stride = buf->stride; + } + glEnableVertexAttribArray(i); + glVertexAttribPointer(i, al->size, al->type, al->normalized, stride, (void *)(al->offset)); + } + } + + CHECK_GL_ERROR +} + +// texture + +static int +calc_texture_size(enum TEXTURE_FORMAT format, int width, int height) { + switch( format ) { + case TEXTURE_RGBA8 : + return width * height * 4; + case TEXTURE_RGB565: + case TEXTURE_RGBA4 : + return width * height * 2; + case TEXTURE_RGB: + return width * height * 3; + case TEXTURE_A8 : + case TEXTURE_DEPTH : + return width * height; + case TEXTURE_PVR2 : + return width * height / 4; + case TEXTURE_PVR4 : + case TEXTURE_ETC1 : + return width * height / 2; + default: + return 0; + } +} + +RID +render_texture_create(struct render *R, int width, int height, enum TEXTURE_FORMAT format, enum TEXTURE_TYPE type, int mipmap) { + struct texture * tex = array_alloc(&R->texture); + if (tex == NULL) + return 0; + glGenTextures(1, &tex->glid); + tex->width = width; + tex->height = height; + tex->format = format; + tex->type = type; + assert(type == TEXTURE_2D || type == TEXTURE_CUBE); + tex->mipmap = mipmap; + int size = calc_texture_size(format, width, height); + if (mipmap) { + size += size / 3; + } + if (type == TEXTURE_CUBE) { + size *= 6; + } + tex->memsize = size; + + CHECK_GL_ERROR + return array_id(&R->texture, tex); +} + +static void +bind_texture(struct render *R, struct texture * tex, int slice, GLenum *type, int *target) { + if (tex->type == TEXTURE_2D) { + *type = GL_TEXTURE_2D; + *target = GL_TEXTURE_2D; + } else { + assert(tex->type == TEXTURE_CUBE); + *type = GL_TEXTURE_CUBE_MAP; + *target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice; + } + glActiveTexture( GL_TEXTURE7 ); + R->changeflag |= CHANGE_TEXTURE; + R->last.texture[7] = 0; // use last texture slot + glBindTexture( *type, tex->glid); +} + +// return compressed +static int +texture_format(struct texture * tex, GLint *pf, GLenum *pt) { + GLuint format = 0; + GLenum itype = 0; + int compressed = 0; + switch(tex->format) { + case TEXTURE_RGBA8 : + format = GL_RGBA; + itype = GL_UNSIGNED_BYTE; + break; + case TEXTURE_RGB : + format = GL_RGB; + itype = GL_UNSIGNED_BYTE; + break; + case TEXTURE_RGBA4 : + format = GL_RGBA; + itype = GL_UNSIGNED_SHORT_4_4_4_4; + break; + case TEXTURE_RGB565: + format = GL_RGB; + itype = GL_UNSIGNED_SHORT_5_6_5; + break; + case TEXTURE_A8 : + case TEXTURE_DEPTH : + format = GL_ALPHA; + itype = GL_UNSIGNED_BYTE; + break; +#ifdef GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG + case TEXTURE_PVR2 : + format = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + compressed = 1; + break; +#endif +#ifdef GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG + case TEXTURE_PVR4 : + format = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + compressed = 1; + break; +#endif +#ifdef GL_ETC1_RGB8_OES + case TEXTURE_ETC1 : + format = GL_ETC1_RGB8_OES; + compressed = 1; + break; +#endif + default: + assert(0); + return -1; + } + *pf = format; + *pt = itype; + return compressed; +} + +void +render_texture_update(struct render *R, RID id, int width, int height, const void *pixels, int slice, int miplevel) { + struct texture * tex = array_ref(&R->texture, id); + if (tex == NULL) + return; + + GLenum type; + int target; + bind_texture(R, tex, slice, &type, &target); + + if (tex->mipmap) { + glTexParameteri( type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); + } else { + glTexParameteri( type, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + } + glTexParameteri( type, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameteri( type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + + glPixelStorei(GL_UNPACK_ALIGNMENT,1); + GLint format = 0; + GLenum itype = 0; + int compressed = texture_format(tex, &format, &itype); + if (compressed) { + glCompressedTexImage2D(target, miplevel, format, + (GLsizei)tex->width, (GLsizei)tex->height, 0, + calc_texture_size(tex->format, width, height), pixels); + } else { + glTexImage2D(target, miplevel, format, (GLsizei)width, (GLsizei)height, 0, format, itype, pixels); + } + + CHECK_GL_ERROR +} + +void +render_texture_subupdate(struct render *R, RID id, const void *pixels, int x, int y, int w, int h) { + struct texture * tex = array_ref(&R->texture, id); + if (tex == NULL) + return; + + GLenum type; + int target; + bind_texture(R, tex, 0, &type, &target); + + glPixelStorei(GL_UNPACK_ALIGNMENT,1); + GLint format = 0; + GLenum itype = 0; + int compressed = texture_format(tex, &format, &itype); + if (compressed) { + glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, + x, y, w, h, format, + calc_texture_size(tex->format, w, h), pixels); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, format, itype, pixels); + } + + CHECK_GL_ERROR +} + +// blend mode +void +render_setblend(struct render *R, enum BLEND_FORMAT src, enum BLEND_FORMAT dst) { + R->current.blend_src = src; + R->current.blend_dst = dst; + R->changeflag |= CHANGE_BLEND; +} + +// depth +void +render_enabledepthmask(struct render *R, int enable) { + R->current.depthmask = enable; + R->changeflag |= CHANGE_DEPTH; +} + +// depth +void +render_enablescissor(struct render *R, int enable) { + R->current.scissor = enable; + R->changeflag |= CHANGE_SCISSOR; +} + +void +render_setdepth(struct render *R, enum DEPTH_FORMAT d) { + R->current.depth = d; + R->changeflag |= CHANGE_DEPTH; +} + +// cull +void +render_setcull(struct render *R, enum CULL_MODE c) { + R->current.cull = c; + R->changeflag |= CHANGE_CULL; +} + +// render target +static RID +create_rt(struct render *R, RID texid) { + struct target *tar = array_alloc(&R->target); + if (tar == NULL) + return 0; + tar->tex = texid; + struct texture * tex = array_ref(&R->texture, texid); + if (tex == NULL) + return 0; + glGenFramebuffers(1, &tar->glid); + glBindFramebuffer(GL_FRAMEBUFFER, tar->glid); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex->glid, 0); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + close_target(tar, R); + return 0; + } + CHECK_GL_ERROR + + return array_id(&R->target, tar); +} + +RID +render_target_create(struct render *R, int width, int height, enum TEXTURE_FORMAT format) { + RID tex = render_texture_create(R, width, height, format, TEXTURE_2D, 0); + if (tex == 0) + return 0; + render_texture_update(R, tex, width, height, NULL, 0, 0); + RID rt = create_rt(R, tex); + glBindFramebuffer(GL_FRAMEBUFFER, R->default_framebuffer); + R->last.target = 0; + R->changeflag |= CHANGE_TARGET; + + if (rt == 0) { + render_release(R, TEXTURE, tex); + } + CHECK_GL_ERROR + return rt; +} + +RID +render_target_texture(struct render *R, RID rt) { + struct target *tar = array_ref(&R->target, rt); + if (tar) { + return tar->tex; + } else { + return 0; + } +} + +// render state + +static void +render_state_commit(struct render *R) { + if (R->changeflag & CHANGE_INDEXBUFFER) { + RID ib = R->current.indexbuffer; + if (ib != R->last.indexbuffer) { + R->last.indexbuffer = ib; + struct buffer * b = array_ref(&R->buffer, ib); + if (b) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, b->glid); + CHECK_GL_ERROR + } + } + } + + if (R->changeflag & CHANGE_VERTEXBUFFER) { + apply_vb(R); + } + + if (R->changeflag & CHANGE_TEXTURE) { + static GLenum mode[] = { + GL_TEXTURE_2D, + GL_TEXTURE_CUBE_MAP, + }; + int i; + for (i=0;icurrent.texture[i]; + RID lastid = R->last.texture[i]; + if (id != lastid) { + R->last.texture[i] = id; + struct texture * tex = array_ref(&R->texture, id); + if (tex) { + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(mode[tex->type], tex->glid); + } + } + } + CHECK_GL_ERROR + } + + if (R->changeflag & CHANGE_TARGET) { + RID crt = R->current.target; + if (R->last.target != crt) { + GLuint rt = R->default_framebuffer; + if (crt != 0) { + struct target * tar = array_ref(&R->target, crt); + if (tar) { + rt = tar->glid; + } else { + crt = 0; + } + } + glBindFramebuffer(GL_FRAMEBUFFER, rt); + R->last.target = crt; + CHECK_GL_ERROR + } + } + + if (R->changeflag & CHANGE_BLEND) { + if (R->last.blend_src != R->current.blend_src || R->last.blend_dst != R->current.blend_dst) { + if (R->current.blend_src == BLEND_DISABLE) { + glDisable(GL_BLEND); + } else if (R->last.blend_src == BLEND_DISABLE) { + glEnable(GL_BLEND); + } + static GLenum blend[] = { + 0, + GL_ZERO, + GL_ONE, + GL_SRC_COLOR, + GL_ONE_MINUS_SRC_COLOR, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_DST_ALPHA, + GL_ONE_MINUS_DST_ALPHA, + GL_DST_COLOR, + GL_ONE_MINUS_DST_COLOR, + GL_SRC_ALPHA_SATURATE, + }; + + enum BLEND_FORMAT src = R->current.blend_src; + enum BLEND_FORMAT dst = R->current.blend_dst; + glBlendFunc(blend[src], blend[dst]); + + R->last.blend_src = src; + R->last.blend_dst = dst; + } + } + + if (R->changeflag & CHANGE_DEPTH) { + if (R->last.depth != R->current.depth) { + if (R->last.depth == DEPTH_DISABLE) { + glEnable( GL_DEPTH_TEST); + } + if (R->current.depth == DEPTH_DISABLE) { + glDisable( GL_DEPTH_TEST); + } else { + static GLenum depth[] = { + 0, + GL_LEQUAL, + GL_LESS, + GL_EQUAL, + GL_GREATER, + GL_GEQUAL, + GL_ALWAYS, + }; + glDepthFunc( depth[R->current.depth] ); + } + R->last.depth = R->current.depth; + } + if (R->last.depthmask != R->current.depthmask) { + glDepthMask(R->current.depthmask ? GL_TRUE : GL_FALSE); + R->last.depthmask = R->current.depthmask; + } + } + + if (R->changeflag & CHANGE_CULL) { + if (R->last.cull != R->current.cull) { + if (R->last.cull == CULL_DISABLE) { + glEnable(GL_CULL_FACE); + } + if (R->current.cull == CULL_DISABLE) { + glDisable(GL_CULL_FACE); + } else { + glCullFace(R->current.cull == CULL_FRONT ? GL_FRONT : GL_BACK); + } + R->last.cull = R->current.cull; + } + } + + if (R->changeflag & CHANGE_SCISSOR) { + if (R->last.scissor != R->current.scissor) { + if (R->current.scissor) { + glEnable(GL_SCISSOR_TEST); + } else { + glDisable(GL_SCISSOR_TEST); + } + R->last.scissor = R->current.scissor; + } + } + + R->changeflag = 0; + + CHECK_GL_ERROR +} + +void +render_state_reset(struct render *R) { + R->changeflag = ~0; + memset(&R->last, 0 , sizeof(R->last)); + glDisable(GL_BLEND); + glDisable(GL_SCISSOR_TEST); + glDepthMask(GL_FALSE); + glDisable( GL_DEPTH_TEST ); + glDisable( GL_CULL_FACE ); + glBindFramebuffer(GL_FRAMEBUFFER, R->default_framebuffer); + + CHECK_GL_ERROR +} + +// draw +void +render_draw(struct render *R, enum DRAW_MODE mode, int fromidx, int ni) { + static int draw_mode[] = { + GL_TRIANGLES, + GL_LINES, + }; + assert(mode < sizeof(draw_mode)/sizeof(int)); + render_state_commit(R); + RID ib = R->current.indexbuffer; + struct buffer * buf = array_ref(&R->buffer, ib); + if (buf) { + assert(fromidx + ni <= buf->n); + int offset = fromidx; + GLenum type = GL_UNSIGNED_SHORT; + if (buf->stride == 1) { + type = GL_UNSIGNED_BYTE; + } else { + offset *= sizeof(short); + } + glDrawElements(draw_mode[mode], ni, type, (char *)0 + offset); + CHECK_GL_ERROR + } +} + +void +render_clear(struct render *R, enum CLEAR_MASK mask, unsigned long c) { + GLbitfield m = 0; + if (mask & MASKC) { + m |= GL_COLOR_BUFFER_BIT; + float a = ((c >> 24) & 0xff ) / 255.0; + float r = ((c >> 16) & 0xff ) / 255.0; + float g = ((c >> 8) & 0xff ) / 255.0; + float b = ((c >> 0) & 0xff ) / 255.0; + glClearColor(r,g,b,a); + } + if (mask & MASKD) { + m |= GL_DEPTH_BUFFER_BIT; + } + if (mask & MASKS) { + m |= GL_STENCIL_BUFFER_BIT; + } + render_state_commit(R); + glClear(m); + + CHECK_GL_ERROR +} + +// uniform +int +render_shader_locuniform(struct render *R, const char * name) { + struct shader * s = array_ref(&R->shader, R->program); + if (s) { + int loc = glGetUniformLocation( s->glid, name); + CHECK_GL_ERROR + return loc; + } else { + return -1; + } +} + +void +render_shader_setuniform(struct render *R, int loc, enum UNIFORM_FORMAT format, const float *v) { + switch(format) { + case UNIFORM_FLOAT1: + glUniform1f(loc, v[0]); + break; + case UNIFORM_FLOAT2: + glUniform2f(loc, v[0], v[1]); + break; + case UNIFORM_FLOAT3: + glUniform3f(loc, v[0], v[1], v[2]); + break; + case UNIFORM_FLOAT4: + glUniform4f(loc, v[0], v[1], v[2], v[3]); + break; + case UNIFORM_FLOAT33: + glUniformMatrix3fv(loc, 1, GL_FALSE, v); + break; + case UNIFORM_FLOAT44: + glUniformMatrix4fv(loc, 1, GL_FALSE, v); + break; + default: + assert(0); + return; + } + CHECK_GL_ERROR +} + +int +render_version(struct render *R) { + return OPENGLES; +} diff --git a/lib/render/render.h b/lib/render/render.h new file mode 100644 index 00000000..8b16c11b --- /dev/null +++ b/lib/render/render.h @@ -0,0 +1,155 @@ +#ifndef ejoy3d_render_h +#define ejoy3d_render_h + +#include + +typedef unsigned int RID; + +struct render; + +struct render_init_args { + int max_buffer; + int max_layout; + int max_target; + int max_texture; + int max_shader; +}; + +struct vertex_attrib { + const char * name; + int vbslot; + int n; + int size; + int offset; +}; + +struct shader_init_args { + const char * vs; + const char * fs; + int texture; + const char **texture_uniform; +}; + +enum RENDER_OBJ { + INVALID = 0, + VERTEXLAYOUT = 1, + VERTEXBUFFER = 2, + INDEXBUFFER = 3, + TEXTURE = 4, + TARGET = 5, + SHADER = 6, +}; + +enum TEXTURE_TYPE { + TEXTURE_2D = 0, + TEXTURE_CUBE, +}; + +enum TEXTURE_FORMAT { + TEXTURE_INVALID = 0, + TEXTURE_RGBA8, + TEXTURE_RGBA4, + TEXTURE_RGB, + TEXTURE_RGB565, + TEXTURE_A8, + TEXTURE_DEPTH, // use for render target + TEXTURE_PVR2, + TEXTURE_PVR4, + TEXTURE_ETC1, +}; + +enum BLEND_FORMAT { + BLEND_DISABLE = 0, + BLEND_ZERO, + BLEND_ONE, + BLEND_SRC_COLOR, + BLEND_ONE_MINUS_SRC_COLOR, + BLEND_SRC_ALPHA, + BLEND_ONE_MINUS_SRC_ALPHA, + BLEND_DST_ALPHA, + BLEND_ONE_MINUS_DST_ALPHA, + BLEND_DST_COLOR, + BLEND_ONE_MINUS_DST_COLOR, + BLEND_SRC_ALPHA_SATURATE, +}; + +enum DEPTH_FORMAT { + DEPTH_DISABLE = 0, + DEPTH_LESS_EQUAL, + DEPTH_LESS, + DEPTH_EQUAL, + DEPTH_GREATER, + DEPTH_GREATER_EQUAL, + DEPTH_ALWAYS, +}; + +enum CLEAR_MASK { + MASKC = 0x1, + MASKD = 0x2, + MASKS = 0x4, +}; + +enum UNIFORM_FORMAT { + UNIFORM_INVALID = 0, + UNIFORM_FLOAT1, + UNIFORM_FLOAT2, + UNIFORM_FLOAT3, + UNIFORM_FLOAT4, + UNIFORM_FLOAT33, + UNIFORM_FLOAT44, +}; + +enum DRAW_MODE { + DRAW_TRIANGLE = 0, + DRAW_LINE, +}; + +enum CULL_MODE { + CULL_DISABLE = 0, + CULL_FRONT, + CULL_BACK, +}; + +int render_version(struct render *R); +int render_size(struct render_init_args *args); +struct render * render_init(struct render_init_args *args, void * buffer, int sz); +void render_exit(struct render * R); + +void render_set(struct render *R, enum RENDER_OBJ what, RID id, int slot); +void render_release(struct render *R, enum RENDER_OBJ what, RID id); + +RID render_register_vertexlayout(struct render *R, int n, struct vertex_attrib * attrib); + +// what should be VERTEXBUFFER or INDEXBUFFER +RID render_buffer_create(struct render *R, enum RENDER_OBJ what, const void *data, int n, int stride); +void render_buffer_update(struct render *R, RID id, const void * data, int n); + +RID render_texture_create(struct render *R, int width, int height, enum TEXTURE_FORMAT format, enum TEXTURE_TYPE type, int mipmap); +void render_texture_update(struct render *R, RID id, int width, int height, const void *pixels, int slice, int miplevel); +// subupdate only support slice 0, miplevel 0 +void render_texture_subupdate(struct render *R, RID id, const void *pixels, int x, int y, int w, int h); + +RID render_target_create(struct render *R, int width, int height, enum TEXTURE_FORMAT format); +// render_release TARGET would not release the texture attachment +RID render_target_texture(struct render *R, RID rt); + +RID render_shader_create(struct render *R, struct shader_init_args *args); +void render_shader_bind(struct render *R, RID id); +int render_shader_locuniform(struct render *R, const char * name); +void render_shader_setuniform(struct render *R, int loc, enum UNIFORM_FORMAT format, const float *v); + +void render_setviewport(struct render *R, int x, int y, int width, int height ); +void render_setscissor(struct render *R, int x, int y, int width, int height ); + +void render_setblend(struct render *R, enum BLEND_FORMAT src, enum BLEND_FORMAT dst); +void render_setdepth(struct render *R, enum DEPTH_FORMAT d); +void render_setcull(struct render *R, enum CULL_MODE c); +void render_enabledepthmask(struct render *R, int enable); +void render_enablescissor(struct render *R, int enable); + +void render_state_reset(struct render *R); + +void render_clear(struct render *R, enum CLEAR_MASK mask, unsigned long argb); +void render_draw(struct render *R, enum DRAW_MODE mode, int fromidx, int ni); + +#endif diff --git a/lib/renderbuffer.c b/lib/renderbuffer.c index c1371b28..4cfdadf6 100644 --- a/lib/renderbuffer.c +++ b/lib/renderbuffer.c @@ -4,11 +4,17 @@ #include "screen.h" #include "texture.h" #include "array.h" -#include "opengl.h" #include #include +static struct render *R = NULL; + +void +renderbuffer_initrender(struct render *r) { + R = r; +} + int renderbuffer_add(struct render_buffer *rb, const struct vertex_pack vb[4], uint32_t color, uint32_t additive) { if (rb->object >= MAX_COMMBINE) { @@ -221,21 +227,16 @@ renderbuffer_drawsprite(struct render_buffer *rb, struct sprite *s) { void renderbuffer_upload(struct render_buffer *rb) { if (rb->vbid == 0) { - GLuint id = 0; - glGenBuffers(1, &id); - rb->vbid = (unsigned int)id; + rb->vbid = render_buffer_create(R, VERTEXBUFFER, rb->vb, rb->object * 4, sizeof(struct vertex)); + } else { + render_buffer_update(R, rb->vbid, rb->vb, rb->object * 4); } - - GLuint id = rb->vbid; - glBindBuffer(GL_ARRAY_BUFFER, id); - glBufferData(GL_ARRAY_BUFFER, sizeof(struct quad) * rb->object, rb->vb, GL_STATIC_DRAW); } void renderbuffer_unload(struct render_buffer *rb) { if (rb->vbid) { - GLuint id = rb->vbid; - glDeleteBuffers(1,&id); + render_release(R, VERTEXBUFFER, rb->vbid); rb->vbid = 0; } } diff --git a/lib/renderbuffer.h b/lib/renderbuffer.h index 5df08798..2423662c 100644 --- a/lib/renderbuffer.h +++ b/lib/renderbuffer.h @@ -2,6 +2,7 @@ #define ejoy2d_renderbuffer_h #include +#include "render.h" #define MAX_COMMBINE 1024 @@ -25,10 +26,12 @@ struct quad { struct render_buffer { int object; int texid; - unsigned int vbid; + RID vbid; struct quad vb[MAX_COMMBINE]; }; + +void renderbuffer_initrender(struct render *R); void renderbuffer_init(struct render_buffer *rb); void renderbuffer_upload(struct render_buffer *rb); void renderbuffer_unload(struct render_buffer *rb); diff --git a/lib/scissor.c b/lib/scissor.c index 42ae3d17..51666fd6 100644 --- a/lib/scissor.c +++ b/lib/scissor.c @@ -1,5 +1,4 @@ #include "scissor.h" -#include "opengl.h" #include "screen.h" #include "shader.h" @@ -44,7 +43,7 @@ scissor_push(int x, int y, int w, int h) { assert(S.depth < SCISSOR_MAX); shader_flush(); if (S.depth == 0) { - glEnable(GL_SCISSOR_TEST); + shader_scissortest(1); } if (S.depth >= 1) { @@ -65,7 +64,7 @@ scissor_pop() { shader_flush(); --S.depth; if (S.depth == 0) { - glDisable(GL_SCISSOR_TEST); + shader_scissortest(0); return; } struct box * s = &S.s[S.depth-1]; diff --git a/lib/screen.c b/lib/screen.c index 2aa69ddb..1bdd0607 100644 --- a/lib/screen.c +++ b/lib/screen.c @@ -1,5 +1,5 @@ #include "screen.h" -#include "opengl.h" +#include "render.h" #include "spritepack.h" struct screen { @@ -11,6 +11,14 @@ struct screen { }; static struct screen SCREEN; +static struct render *R = NULL; + +void +screen_initrender(struct render *r) { + R = r; + // for ejoy2d compatibility, ejoy2d may call screen_init before screen_initrender + screen_init(SCREEN.width, SCREEN.height, SCREEN.scale); +} void screen_init(float w, float h, float scale) { @@ -19,7 +27,9 @@ screen_init(float w, float h, float scale) { SCREEN.scale = scale; SCREEN.invw = 2.0f / SCREEN_SCALE / w; SCREEN.invh = -2.0f / SCREEN_SCALE / h; - glViewport(0,0,w * scale,h * scale); + if (R) { + render_setviewport(R, 0, 0, w * scale, h * scale ); + } } void @@ -54,7 +64,7 @@ screen_scissor(int x, int y, int w, int h) { w *= SCREEN.scale; h *= SCREEN.scale; - glScissor(x,y,w,h); + render_setscissor(R,x,y,w,h); } bool screen_is_visible(float x,float y) diff --git a/lib/screen.h b/lib/screen.h index 77237a32..c6439840 100644 --- a/lib/screen.h +++ b/lib/screen.h @@ -2,6 +2,9 @@ #define ejoy_2d_screen_h #include +struct render; + +void screen_initrender(struct render *R); void screen_init(float w, float h, float scale); void screen_trans(float *x, float *y); void screen_scissor(int x, int y, int w, int h); diff --git a/lib/shader.c b/lib/shader.c index a60b1c2a..816683b5 100644 --- a/lib/shader.c +++ b/lib/shader.c @@ -1,5 +1,5 @@ #include "shader.h" -#include "opengl.h" +#include "material.h" #include "fault.h" #include "array.h" #include "renderbuffer.h" @@ -7,38 +7,51 @@ #include "matrix.h" #include "spritepack.h" #include "screen.h" +#include "label.h" + +#include "render.h" +#include "blendmode.h" #include #include #include #include +#include + +#define MAX_PROGRAM 16 -#define MAX_PROGRAM 9 +#define BUFFER_OFFSET(f) ((int)&(((struct vertex *)NULL)->f)) -#define ATTRIB_VERTEX 0 -#define ATTRIB_TEXTCOORD 1 -#define ATTRIB_COLOR 2 -#define ATTRIB_ADDITIVE 3 +#define MAX_UNIFORM 16 +#define MAX_TEXTURE_CHANNEL 8 -#define BUFFER_OFFSET(f) ((void *)&(((struct vertex *)NULL)->f)) +struct uniform { + int loc; + int offset; + enum UNIFORM_FORMAT type; +}; struct program { - GLuint prog; - - GLint mask; - GLint st; - float arg_mask_x; - float arg_mask_y; + RID prog; + struct material * material; + int texture_number; + int uniform_number; + struct uniform uniform[MAX_UNIFORM]; + bool reset_uniform; + bool uniform_change[MAX_UNIFORM]; + float uniform_value[MAX_UNIFORM * 16]; }; struct render_state { + struct render * R; int current_program; struct program program[MAX_PROGRAM]; - int tex; + RID tex[MAX_TEXTURE_CHANNEL]; int blendchange; int drawcall; - GLuint vertex_buffer; - GLuint index_buffer; + RID vertex_buffer; + RID index_buffer; + RID layout; struct render_buffer vb; }; @@ -50,14 +63,28 @@ shader_init() { struct render_state * rs = (struct render_state *) malloc(sizeof(*rs)); memset(rs, 0 , sizeof(*rs)); + + struct render_init_args RA; + // todo: config these args + RA.max_buffer = 128; + RA.max_layout = 4; + RA.max_target = 128; + RA.max_texture = 256; + RA.max_shader = MAX_PROGRAM; + + int rsz = render_size(&RA); + rs->R = (struct render *)malloc(rsz); + rs->R = render_init(&RA, rs->R, rsz); + texture_initrender(rs->R); + screen_initrender(rs->R); + label_initrender(rs->R); + renderbuffer_initrender(rs->R); + rs->current_program = -1; rs->blendchange = 0; - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + render_setblend(rs->R, BLEND_ONE, BLEND_ONE_MINUS_SRC_ALPHA); - glGenBuffers(1, &rs->index_buffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rs->index_buffer); - - GLushort idxs[6 * MAX_COMMBINE]; + uint16_t idxs[6 * MAX_COMMBINE]; int i; for (i=0;ivertex_buffer); - glBindBuffer(GL_ARRAY_BUFFER, rs->vertex_buffer); - - glEnable(GL_BLEND); + rs->index_buffer = render_buffer_create(rs->R, INDEXBUFFER, idxs, 6 * MAX_COMMBINE, sizeof(uint16_t)); + rs->vertex_buffer = render_buffer_create(rs->R, VERTEXBUFFER, NULL, 4 * MAX_COMMBINE, sizeof(struct vertex)); + + struct vertex_attrib va[4] = { + { "position", 0, 2, sizeof(float), BUFFER_OFFSET(vp.vx) }, + { "texcoord", 0, 2, sizeof(uint16_t), BUFFER_OFFSET(vp.tx) }, + { "color", 0, 4, sizeof(uint8_t), BUFFER_OFFSET(rgba) }, + { "additive", 0, 4, sizeof(uint8_t), BUFFER_OFFSET(add) }, + }; + rs->layout = render_register_vertexlayout(rs->R, sizeof(va)/sizeof(va[0]), va); + render_set(rs->R, VERTEXLAYOUT, rs->layout, 0); + render_set(rs->R, INDEXBUFFER, rs->index_buffer, 0); + render_set(rs->R, VERTEXBUFFER, rs->vertex_buffer, 0); RS = rs; } -void -shader_reset() -{ - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - - if (RS->current_program != -1) - { - glUseProgram(RS->program[RS->current_program].prog); - } - - glBindTexture(GL_TEXTURE_2D, RS->tex); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, RS->index_buffer); - glBindBuffer(GL_ARRAY_BUFFER, RS->vertex_buffer); -} - -static GLuint -compile(const char * source, int type) { - GLint status; - - GLuint shader = glCreateShader(type); - glShaderSource(shader, 1, &source, NULL); - glCompileShader(shader); - - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - - if (status == GL_FALSE) { - char buf[1024]; - GLint len; - glGetShaderInfoLog(shader, 1024, &len, buf); - - fault("compile failed:%s\n" - "source:\n %s\n", - buf, source); - glDeleteShader(shader); - return 0; - } - return shader; -} - -static void -link(struct program *p) { - GLint status; - glLinkProgram(p->prog); - - glGetProgramiv(p->prog, GL_LINK_STATUS, &status); - if (status == 0) { - char buf[1024]; - GLint len; - glGetProgramInfoLog(p->prog, 1024, &len, buf); - fault("link failed:%s\n", buf); +void +shader_reset() { + struct render_state *rs = RS; + render_state_reset(rs->R); + render_setblend(rs->R, BLEND_ONE, BLEND_ONE_MINUS_SRC_ALPHA); + if (RS->current_program != -1) { + render_shader_bind(rs->R, RS->program[RS->current_program].prog); } + render_set(rs->R, VERTEXLAYOUT, rs->layout, 0); + render_set(rs->R, TEXTURE, RS->tex[0], 0); + render_set(rs->R, INDEXBUFFER, RS->index_buffer,0); + render_set(rs->R, VERTEXBUFFER, RS->vertex_buffer,0); } static void -program_init(struct program * p, const char *FS, const char *VS) { - // Create shader program. - p->prog = glCreateProgram(); - - GLuint fs = compile(FS, GL_FRAGMENT_SHADER); - if (fs == 0) { - fault("Can't compile fragment shader"); - } else { - glAttachShader(p->prog, fs); - } - - GLuint vs = compile(VS, GL_VERTEX_SHADER); - if (vs == 0) { - fault("Can't compile vertex shader"); - } else { - glAttachShader(p->prog, vs); - } - - glBindAttribLocation(p->prog, ATTRIB_VERTEX, "position"); - glBindAttribLocation(p->prog, ATTRIB_TEXTCOORD, "texcoord"); - glBindAttribLocation(p->prog, ATTRIB_COLOR, "color"); - glBindAttribLocation(p->prog, ATTRIB_ADDITIVE, "additive"); - - link(p); - - p->mask = glGetUniformLocation(p->prog, "mask"); - p->arg_mask_x = 0.0f; - p->arg_mask_y = 0.0f; - if (p->mask != -1) { - glUniform2f(p->mask, 0.0f, 0.0f); - } - p->st = glGetUniformLocation(p->prog, "st"); - - glDetachShader(p->prog, fs); - glDeleteShader(fs); - glDetachShader(p->prog, vs); - glDeleteShader(vs); +program_init(struct program * p, const char *FS, const char *VS, int texture, const char ** texture_uniform_name) { + struct render *R = RS->R; + memset(p, 0, sizeof(*p)); + struct shader_init_args args; + args.vs = VS; + args.fs = FS; + args.texture = texture; + args.texture_uniform = texture_uniform_name; + p->prog = render_shader_create(R, &args); + render_shader_bind(R, p->prog); + render_shader_bind(R, 0); } void -shader_load(int prog, const char *fs, const char *vs) { +shader_load(int prog, const char *fs, const char *vs, int texture, const char ** texture_uniform_name) { struct render_state *rs = RS; assert(prog >=0 && prog < MAX_PROGRAM); struct program * p = &rs->program[prog]; - assert(p->prog == 0); - program_init(p, fs, vs); + if (p->prog) { + render_release(RS->R, SHADER, p->prog); + p->prog = 0; + } + program_init(p, fs, vs, texture, texture_uniform_name); + p->texture_number = texture; + RS->current_program = -1; } void @@ -186,17 +159,14 @@ shader_unload() { if (RS == NULL) { return; } - int i; - - for (i=0;iprogram[i]; - if (p->prog) { - glDeleteProgram(p->prog); - } - } - - glDeleteBuffers(1,&RS->vertex_buffer); - glDeleteBuffers(1,&RS->index_buffer); + struct render *R = RS->R; + texture_initrender(NULL); + screen_initrender(NULL); + label_initrender(NULL); + renderbuffer_initrender(NULL); + + render_exit(R); + free(R); free(RS); RS = NULL; } @@ -219,15 +189,8 @@ drawcall_count() { static void renderbuffer_commit(struct render_buffer * rb) { - glEnableVertexAttribArray(ATTRIB_VERTEX); - glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), BUFFER_OFFSET(vp.vx)); - glEnableVertexAttribArray(ATTRIB_TEXTCOORD); - glVertexAttribPointer(ATTRIB_TEXTCOORD, 2, GL_UNSIGNED_SHORT, GL_TRUE, sizeof(struct vertex), BUFFER_OFFSET(vp.tx)); - glEnableVertexAttribArray(ATTRIB_COLOR); - glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(struct vertex), BUFFER_OFFSET(rgba)); - glEnableVertexAttribArray(ATTRIB_ADDITIVE); - glVertexAttribPointer(ATTRIB_ADDITIVE, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(struct vertex), BUFFER_OFFSET(add)); - glDrawElements(GL_TRIANGLES, 6 * rb->object, GL_UNSIGNED_SHORT, 0); + struct render *R = RS->R; + render_draw(R, DRAW_TRIANGLE, 0, 6 * rb->object); } static void @@ -236,9 +199,8 @@ rs_commit() { if (rb->object == 0) return; RS->drawcall++; - glBindBuffer(GL_ARRAY_BUFFER, RS->vertex_buffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(struct quad) * rb->object, rb->vb, GL_DYNAMIC_DRAW); - + struct render *R = RS->R; + render_buffer_update(R, RS->vertex_buffer, rb->vb, 4 * rb->object); renderbuffer_commit(rb); rb->object = 0; @@ -247,65 +209,70 @@ rs_commit() { void shader_drawbuffer(struct render_buffer * rb, float tx, float ty, float scale) { rs_commit(); - int glid = texture_glid(rb->texid); + + RID glid = texture_glid(rb->texid); if (glid == 0) return; - shader_texture(glid); - shader_program(PROGRAM_RENDERBUFFER); - RS->drawcall++; - glBindBuffer(GL_ARRAY_BUFFER, rb->vbid); + shader_texture(glid, 0); + render_set(RS->R, VERTEXBUFFER, rb->vbid, 0); float sx = scale; float sy = scale; screen_trans(&sx, &sy); screen_trans(&tx, &ty); - struct program *p = &RS->program[RS->current_program]; - glUniform4f(p->st, sx, sy, tx, ty); + float v[4] = { sx, sy, tx, ty }; + + // we should call shader_adduniform to add "st" uniform first + shader_setuniform(PROGRAM_RENDERBUFFER, 0, UNIFORM_FLOAT4, v); + + shader_program(PROGRAM_RENDERBUFFER, NULL); + RS->drawcall++; renderbuffer_commit(rb); -} -void -shader_texture(int id) { - if (RS->tex != id) { - rs_commit(); - RS->tex = (GLuint)id; - glBindTexture(GL_TEXTURE_2D, id); - } + render_set(RS->R, VERTEXBUFFER, RS->vertex_buffer, 0); } void -shader_program(int n) { - if (RS->current_program != n) { +shader_texture(int id, int channel) { + assert(channel < MAX_TEXTURE_CHANNEL); + if (RS->tex[channel] != id) { rs_commit(); - RS->current_program = n; - glUseProgram(RS->program[n].prog); + RS->tex[channel] = id; + render_set(RS->R, TEXTURE, id, channel); } } -void -shader_mask(float x, float y) { - struct program *p = &RS->program[RS->current_program]; - if (!p || p->mask == -1) - return; - if (p->arg_mask_x == x && p->arg_mask_y == y) - return; - p->arg_mask_x = x; - p->arg_mask_y = y; -// rs_commit(); - glUniform2f(p->mask, x, y); +static void +apply_uniform(struct program *p) { + struct render *R = RS->R; + int i; + for (i=0;iuniform_number;i++) { + if (p->uniform_change[i]) { + struct uniform * u = &p->uniform[i]; + render_shader_setuniform(R, u->loc, u->type, p->uniform_value + u->offset); + } + } + p->reset_uniform = false; } void -shader_st(int prog, float x, float y, float scale) { - rs_commit(); - shader_program(prog); - struct program *p = &RS->program[prog]; - - if (!p || p->st == -1) - return; - - glUniform4f(p->st, scale, scale, x, y); +shader_program(int n, struct material *m) { + struct program *p = &RS->program[n]; + if (RS->current_program != n || p->reset_uniform || m) { + rs_commit(); + } + if (RS->current_program != n) { + RS->current_program = n; + render_shader_bind(RS->R, p->prog); + p->material = NULL; + apply_uniform(p); + } else if (p->reset_uniform) { + apply_uniform(p); + } + if (m) { + material_apply(n, m); + } } void @@ -348,15 +315,185 @@ shader_defaultblend() { if (RS->blendchange) { rs_commit(); RS->blendchange = 0; - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + render_setblend(RS->R, BLEND_ONE, BLEND_ONE_MINUS_SRC_ALPHA); } } void shader_blend(int m1, int m2) { - if (m1 != GL_ONE || m2 != GL_ONE_MINUS_SRC_ALPHA) { + if (m1 != BLEND_GL_ONE || m2 != BLEND_GL_ONE_MINUS_SRC_ALPHA) { rs_commit(); RS->blendchange = 1; - glBlendFunc(m1,m2); + enum BLEND_FORMAT src = blend_mode(m1); + enum BLEND_FORMAT dst = blend_mode(m2); + render_setblend(RS->R, src, dst); + } +} + +void +shader_clear(unsigned long argb) { + render_clear(RS->R, MASKC, argb); +} + +int +shader_version() { + return render_version(RS->R); +} + +void +shader_scissortest(int enable) { + render_enablescissor(RS->R, enable); +} + +int +shader_uniformsize(enum UNIFORM_FORMAT t) { + int n = 0; + switch(t) { + case UNIFORM_INVALID: + n = 0; + break; + case UNIFORM_FLOAT1: + n = 1; + break; + case UNIFORM_FLOAT2: + n = 2; + break; + case UNIFORM_FLOAT3: + n = 3; + break; + case UNIFORM_FLOAT4: + n = 4; + break; + case UNIFORM_FLOAT33: + n = 9; + break; + case UNIFORM_FLOAT44: + n = 16; + break; + } + return n; +} + +void +shader_setuniform(int prog, int index, enum UNIFORM_FORMAT t, float *v) { + rs_commit(); + struct program * p = &RS->program[prog]; + assert(index >= 0 && index < p->uniform_number); + struct uniform *u = &p->uniform[index]; + assert(t == u->type); + int n = shader_uniformsize(t); + memcpy(p->uniform_value + u->offset, v, n * sizeof(float)); + p->reset_uniform = true; + p->uniform_change[index] = true; +} + +int +shader_adduniform(int prog, const char * name, enum UNIFORM_FORMAT t) { + // reset current_program + assert(prog >=0 && prog < MAX_PROGRAM); + shader_program(prog, NULL); + struct program * p = &RS->program[prog]; + assert(p->uniform_number < MAX_UNIFORM); + int loc = render_shader_locuniform(RS->R, name); + if (loc < 0) + return -1; + int index = p->uniform_number++; + struct uniform * u = &p->uniform[index]; + u->loc = loc; + u->type = t; + if (index == 0) { + u->offset = 0; + } else { + struct uniform * lu = &p->uniform[index-1]; + u->offset = lu->offset + shader_uniformsize(lu->type); + } + return index; +} + +// material system + +struct material { + struct program *p; + int texture[MAX_TEXTURE_CHANNEL]; + bool uniform_enable[MAX_UNIFORM]; + float uniform[1]; +}; + +int +material_size(int prog) { + if (prog < 0 || prog >= MAX_PROGRAM) + return 0; + struct program *p = &RS->program[prog]; + if (p->uniform_number == 0 && p->texture_number == 0) { + return 0; + } + struct uniform * lu = &p->uniform[p->uniform_number-1]; + int total = lu->offset + shader_uniformsize(lu->type); + return sizeof(struct material) + (total-1) * sizeof(float); +} + +struct material * +material_init(void *self, int size, int prog) { + int rsz = material_size(prog); + struct program *p = &RS->program[prog]; + assert(size >= rsz); + memset(self, 0, rsz); + struct material * m = self; + m->p = p; + int i; + for (i=0;itexture[i] = -1; + } + + return m; +} + +int +material_setuniform(struct material *m, int index, int n, const float *v) { + struct program * p = m->p; + assert(index >= 0 && index < p->uniform_number); + struct uniform * u = &p->uniform[index]; + if (shader_uniformsize(u->type) != n) { + return 1; + } + memcpy(m->uniform + u->offset, v, n * sizeof(float)); + m->uniform_enable[index] = true; + return 0; +} + +void +material_apply(int prog, struct material *m) { + struct program * p = m->p; + if (p != &RS->program[prog]) + return; + if (p->material == m) { + return; + } + p->material = m; + p->reset_uniform = true; + int i; + for (i=0;iuniform_number;i++) { + if (m->uniform_enable[i]) { + struct uniform * u = &p->uniform[i]; + render_shader_setuniform(RS->R, u->loc, u->type, m->uniform + u->offset); + } + } + for (i=0;itexture_number;i++) { + int tex = m->texture[i]; + if (tex >= 0) { + RID glid = texture_glid(tex); + if (glid) { + shader_texture(glid, i); + } + } + } +} + +int +material_settexture(struct material *m, int channel, int texture) { + if (channel >= MAX_TEXTURE_CHANNEL) { + return 1; } + m->texture[channel] = texture; + return 0; } diff --git a/lib/shader.h b/lib/shader.h index 31ed6e0c..a81a47f8 100644 --- a/lib/shader.h +++ b/lib/shader.h @@ -2,6 +2,7 @@ #define EJOY_2D_SHADER_H #include "renderbuffer.h" +#include "render.h" #include #include @@ -12,28 +13,34 @@ #define PROGRAM_TEXT 2 #define PROGRAM_TEXT_EDGE 3 +struct material; + void shader_init(); -void shader_load(int prog, const char *fs, const char *vs); +void shader_load(int prog, const char *fs, const char *vs, int texture, const char ** texture_uniform_name); void shader_unload(); void shader_blend(int m1,int m2); void shader_defaultblend(); -void shader_texture(int id); -void shader_mask(float x, float y); -void shader_st(int prog, float x, float y, float s); +void shader_texture(int id, int channel); void shader_draw(const struct vertex_pack vb[4],uint32_t color,uint32_t additive); void shader_drawpolygon(int n, const struct vertex_pack *vb, uint32_t color, uint32_t additive); -void shader_program(int n); +void shader_program(int n, struct material *); void shader_flush(); - -// 还原当前的环境,比如rt渲染之后 -void shader_reset(); +void shader_clear(unsigned long argb); +int shader_version(); +void shader_scissortest(int enable); int ejoy2d_shader(lua_State *L); +void shader_drawbuffer(struct render_buffer * rb, float x, float y, float s); + +int shader_adduniform(int prog, const char * name, enum UNIFORM_FORMAT t); +void shader_setuniform(int prog, int index, enum UNIFORM_FORMAT t, float *v); +int shader_uniformsize(enum UNIFORM_FORMAT t); +// these api may deprecated later +void shader_reset(); +void shader_mask(float x, float y); void reset_drawcall_count(); int drawcall_count(); -void shader_drawbuffer(struct render_buffer * rb, float x, float y, float s); - #endif diff --git a/lib/sprite.c b/lib/sprite.c index 77fb475c..3b5d2717 100644 --- a/lib/sprite.c +++ b/lib/sprite.c @@ -8,6 +8,7 @@ #include "scissor.h" #include "array.h" #include "particle.h" +#include "material.h" #include #include @@ -15,7 +16,7 @@ #include void -sprite_drawquad(struct pack_picture *picture, struct pack_picture *mask, const struct srt *srt, const struct sprite_trans *arg) { +sprite_drawquad(struct pack_picture *picture, const struct srt *srt, const struct sprite_trans *arg) { struct matrix tmp; struct vertex_pack vb[4]; int i,j; @@ -31,7 +32,7 @@ sprite_drawquad(struct pack_picture *picture, struct pack_picture *mask, const s int glid = texture_glid(q->texid); if (glid == 0) continue; - shader_texture(glid); + shader_texture(glid, 0); for (j=0;j<4;j++) { int xx = q->screen_coord[j*2+0]; int yy = q->screen_coord[j*2+1]; @@ -46,13 +47,6 @@ sprite_drawquad(struct pack_picture *picture, struct pack_picture *mask, const s vb[j].tx = tx; vb[j].ty = ty; } - if (mask != NULL) { - float tx = mask->rect[0].texture_coord[0]; - float ty = mask->rect[0].texture_coord[1]; - float delta_tx = (tx - vb[0].tx) * (1.0f / 65535.0f); - float delta_ty = (ty - vb[0].ty) * (1.0f / 65535.0f); - shader_mask(delta_tx, delta_ty); - } shader_draw(vb, arg->color, arg->additive); } } @@ -73,7 +67,7 @@ sprite_drawpolygon(struct pack_polygon *poly, const struct srt *srt, const struc int glid = texture_glid(p->texid); if (glid == 0) continue; - shader_texture(glid); + shader_texture(glid, 0); int pn = p->n; ARRAY(struct vertex_pack, vb, pn); @@ -156,6 +150,7 @@ sprite_init(struct sprite * s, struct sprite_pack * pack, int id, int sz) { s->name = NULL; s->id = id; s->type = pack->type[id]; + s->material = NULL; if (s->type == TYPE_ANIMATION) { struct pack_animation * ani = (struct pack_animation *)pack->data[id]; s->s.ani = ani; @@ -343,12 +338,12 @@ mat_mul(struct matrix *a, struct matrix *b, struct matrix *tmp) { } static void -switch_program(struct sprite_trans *t, int def) { +switch_program(struct sprite_trans *t, int def, struct material *m) { int prog = t->program; if (prog == PROGRAM_DEFAULT) { prog = def; } - shader_program(prog); + shader_program(prog, m); } static void @@ -449,7 +444,7 @@ drawparticle(struct sprite *s, struct particle_system *ps, struct pack_picture * s->t.mat = mat; s->t.color = color; - sprite_drawquad(pic, NULL, NULL, &s->t); + sprite_drawquad(pic, NULL, &s->t); } shader_defaultblend(); @@ -458,29 +453,32 @@ drawparticle(struct sprite *s, struct particle_system *ps, struct pack_picture * } static int -draw_child(struct sprite *s, struct srt *srt, struct sprite_trans * ts) { +draw_child(struct sprite *s, struct srt *srt, struct sprite_trans * ts, struct material * material) { struct sprite_trans temp; struct matrix temp_matrix; struct sprite_trans *t = sprite_trans_mul(&s->t, ts, &temp, &temp_matrix); + if (s->material) { + material = s->material; + } switch (s->type) { case TYPE_PICTURE: - switch_program(t, PROGRAM_PICTURE); - sprite_drawquad(s->s.pic, s->data.mask, srt, t); + switch_program(t, PROGRAM_PICTURE, material); + sprite_drawquad(s->s.pic, srt, t); return 0; case TYPE_POLYGON: - switch_program(t, PROGRAM_PICTURE); + switch_program(t, PROGRAM_PICTURE, material); sprite_drawpolygon(s->s.poly, srt, t); return 0; case TYPE_LABEL: if (s->data.rich_text) { t->program = PROGRAM_DEFAULT; // label never set user defined program - switch_program(t, s->s.label->edge ? PROGRAM_TEXT_EDGE : PROGRAM_TEXT); + switch_program(t, s->s.label->edge ? PROGRAM_TEXT_EDGE : PROGRAM_TEXT, material); label_draw(s->data.rich_text, s->s.label, srt, t); } return 0; case TYPE_ANCHOR: if (s->data.anchor->ps){ - switch_program(t, PROGRAM_PICTURE); + switch_program(t, PROGRAM_PICTURE, material); drawparticle(s, s->data.anchor->ps, s->data.anchor->pic, srt); } anchor_update(s, srt, t); @@ -515,7 +513,7 @@ draw_child(struct sprite *s, struct srt *srt, struct sprite_trans * ts) { struct sprite_trans temp2; struct matrix temp_matrix2; struct sprite_trans *ct = sprite_trans_mul(&pp->t, t, &temp2, &temp_matrix2); - scissor += draw_child(child, srt, ct); + scissor += draw_child(child, srt, ct, material); } for (i=0;ivisible) { - draw_child(s, srt, NULL); + draw_child(s, srt, NULL, NULL); } } @@ -555,7 +553,7 @@ sprite_draw_as_child(struct sprite *s, struct srt *srt, struct matrix *mat, uint st.color = color; st.additive = 0; st.program = PROGRAM_DEFAULT; - draw_child(s, srt, &st); + draw_child(s, srt, &st, NULL); } } @@ -1009,3 +1007,9 @@ sprite_setframe(struct sprite *s, int frame, bool force_child) { } return total_frame; } + +int +sprite_material_size(struct sprite *s) { + return material_size(s->t.program); +} + diff --git a/lib/sprite.h b/lib/sprite.h index 9deb608d..8672e9f7 100644 --- a/lib/sprite.h +++ b/lib/sprite.h @@ -8,6 +8,8 @@ #include #include +struct material; + struct anchor_data { struct particle_system *ps; struct pack_picture *pic; @@ -35,17 +37,17 @@ struct sprite { bool message; bool multimount; const char *name; // name for parent + struct material *material; union { struct sprite * children[1]; struct rich_text * rich_text; int scissor; - struct pack_picture *mask; //for picture only struct anchor_data *anchor; } data; }; struct sprite_trans * sprite_trans_mul(struct sprite_trans *a, struct sprite_trans *b, struct sprite_trans *t, struct matrix *tmp_matrix); -void sprite_drawquad(struct pack_picture *picture, struct pack_picture *mask, const struct srt *srt, const struct sprite_trans *arg); +void sprite_drawquad(struct pack_picture *picture, const struct srt *srt, const struct sprite_trans *arg); void sprite_drawpolygon(struct pack_polygon *poly, const struct srt *srt, const struct sprite_trans *arg); // sprite_size must be call before sprite_init @@ -74,6 +76,7 @@ int sprite_pos(struct sprite *s, struct srt *srt, struct matrix *m, int pos[2]); void sprite_matrix(struct sprite *s, struct matrix *mat); bool sprite_child_visible(struct sprite *s, const char * childname); +int sprite_material_size(struct sprite *s); int ejoy2d_sprite(lua_State *L); diff --git a/lib/texture.c b/lib/texture.c index 697ba889..12a688fa 100644 --- a/lib/texture.c +++ b/lib/texture.c @@ -2,15 +2,14 @@ #include "shader.h" #define MAX_TEXTURE 128 -#define IS_POT(x) (((x) & ((x) -1)) == 0) struct texture { int width; int height; float invw; float invh; - GLuint id; - GLuint fb; /// rt 's frame buffer + RID id; + RID fb; /// rt 's frame buffer }; struct texture_pool { @@ -19,9 +18,56 @@ struct texture_pool { }; static struct texture_pool POOL; +static struct render *R = NULL; + +void +texture_initrender(struct render *r) { + R = r; +} + +static inline uint32_t +average4(uint32_t c[4]) { + int i; + uint32_t hi = 0; + uint32_t low = 0; + for (i=0;i<4;i++) { + uint32_t v = c[i]; + low += v & 0x00ff00ff; + hi += (v & 0xff00ff00) >> 8; + } + hi = (hi/4) & 0x00ff00ff; + low = (low/4) & 0x00ff00ff; + + return hi << 8 | low; +} + +static void +texture_reduce(enum TEXTURE_FORMAT type, int *width, int *height, void *buffer) { + int w = *width; + int h = *height; + if (w%2 == 1 || h%2 == 1) + return; + // only support RGBA8888 now + if (type != TEXTURE_RGBA8) { + return; + } + uint32_t *src = buffer; + uint32_t *dst = buffer; + int i,j; + for (i=0;i= MAX_TEXTURE) { return "Too many texture"; } @@ -35,64 +81,23 @@ texture_load(int id, int pixel_format, int pixel_width, int pixel_height, void * tex->invw = 1.0f / (float)pixel_width; tex->invh = 1.0f / (float)pixel_height; if (tex->id == 0) { - glGenTextures(1, &tex->id); + tex->id = render_texture_create(R, pixel_width, pixel_height, pixel_format, TEXTURE_2D, 0); } if (data == NULL) { // empty texture return NULL; } - if ((pixel_format == Texture2DPixelFormat_RGBA8888) || - ( IS_POT(pixel_width) && IS_POT(pixel_height))) { - glPixelStorei(GL_UNPACK_ALIGNMENT,4); - } else { - glPixelStorei(GL_UNPACK_ALIGNMENT,1); - } - glActiveTexture(GL_TEXTURE0); - shader_texture(tex->id); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - switch(pixel_format) { - case Texture2DPixelFormat_RGBA8888: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixel_width, (GLsizei)pixel_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - break; - case Texture2DPixelFormat_RGB888: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)pixel_width, (GLsizei)pixel_height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); - break; - case Texture2DPixelFormat_RGBA4444: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixel_width, (GLsizei)pixel_height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); - break; - case Texture2DPixelFormat_RGB565: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)pixel_width, (GLsizei)pixel_height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); - break; - case Texture2DPixelFormat_A8: - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, (GLsizei)pixel_width, (GLsizei)pixel_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data); - break; -#if GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG - case Texture2DPixelFormat_PVRTC4: - { - int size = pixel_width * pixel_height * 4 / 8; - uint8_t* p = data+4; - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, - (GLsizei)pixel_width, (GLsizei)pixel_height, 0, size, p); - - } - break; -#endif - default: - glDeleteTextures(1,&tex->id); - tex->id = 0; - return "Invalid pixel format"; + if (reduce) { + texture_reduce(pixel_format, &pixel_width, &pixel_height, data); } + render_texture_update(R, tex->id, pixel_width, pixel_height, data, 0, 0); return NULL; } const char* texture_new_rt(int id, int w, int h){ - if (id >= MAX_TEXTURE) { return "Too many texture"; } @@ -107,35 +112,10 @@ texture_new_rt(int id, int w, int h){ tex->invw = 1.0f / (float) w; tex->invh = 1.0f / (float) h; if (tex->id == 0) { - glGenTextures(1, &tex->id); - glGenFramebuffers(1, &tex->fb); + tex->fb = render_target_create(R, w, h, TEXTURE_RGBA8); + tex->id = render_target_texture(R, tex->fb); } - - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, tex->id); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei) w, (GLsizei) h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - - glBindFramebuffer(GL_FRAMEBUFFER, tex->fb); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex->id, 0); - - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - { - return "frame buffer is not complete"; - } - - glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - return NULL; } @@ -145,7 +125,7 @@ texture_active_rt(int id) { return "Invalid rt id"; struct texture *tex = &POOL.tex[id]; - glBindFramebuffer(GL_FRAMEBUFFER, tex->fb); + render_set(R, TARGET, tex->fb, 0); return NULL; } @@ -189,14 +169,14 @@ texture_unload(int id) { struct texture *tex = &POOL.tex[id]; if (tex->id == 0) return; - glDeleteTextures(1,&tex->id); + render_release(R, TEXTURE, tex->id); if (tex->fb != 0) - glDeleteFramebuffers(1, &tex->fb); + render_release(R, TARGET, tex->fb); tex->id = 0; - tex->fb = 0; + tex->fb = 0; } -GLuint +RID texture_glid(int id) { if (id < 0 || id >= POOL.count) return 0; @@ -258,7 +238,7 @@ texture_delete_framebuffer(int id) { struct texture *tex = &POOL.tex[id]; if (tex->fb != 0) { - glDeleteFramebuffers(1, &tex->fb); + render_release(R, TARGET, tex->fb); tex->fb = 0; } } diff --git a/lib/texture.h b/lib/texture.h index ce2336eb..b307ac2d 100644 --- a/lib/texture.h +++ b/lib/texture.h @@ -1,20 +1,13 @@ #ifndef EJOY_2D_TEXTURE_H #define EJOY_2D_TEXTURE_H -#include "opengl.h" +#include "render.h" #include -#define Texture2DPixelFormat_RGBA8888 1 -#define Texture2DPixelFormat_RGBA4444 2 -#define Texture2DPixelFormat_PVRTC4 3 -#define Texture2DPixelFormat_PVRTC2 4 -#define Texture2DPixelFormat_RGB888 5 -#define Texture2DPixelFormat_RGB565 6 -#define Texture2DPixelFormat_A8 7 - -const char * texture_load(int id, int type, int width, int height, void *buffer); +void texture_initrender(struct render *R); +const char * texture_load(int id, enum TEXTURE_FORMAT type, int width, int height, void *buffer, int reduce); void texture_unload(int id); -GLuint texture_glid(int id); +RID texture_glid(int id); int texture_coord(int id, float x, float y, uint16_t *u, uint16_t *v); void texture_clearall(); void texture_exit();