commit 0bfdffdd282d1e9ea001ffa8da7cca3d31360eb9 Author: Sam Hocevar Date: Mon Jun 25 14:15:07 2012 +0000 build: move all games to a "games" subdirectory to clean up the root directory layout mess. diff --git a/neercs/.gitignore b/neercs/.gitignore new file mode 100644 index 0000000..c1e4abc --- /dev/null +++ b/neercs/.gitignore @@ -0,0 +1,2 @@ +# Our binaries +neercs diff --git a/neercs/Makefile.am b/neercs/Makefile.am new file mode 100644 index 0000000..cbcbc23 --- /dev/null +++ b/neercs/Makefile.am @@ -0,0 +1,36 @@ + +if USE_CACA +noinst_PROGRAMS = neercs +endif + +neercs_SOURCES = \ + neercs.cpp neercs.h \ + \ + video/render.cpp video/render.h \ + video/text-render.cpp video/text-render.h \ + video/blurh.lolfx video/blurv.lolfx video/glow.lolfx \ + video/postfx.lolfx video/radial.lolfx video/simple.lolfx \ + video/text.lolfx +neercs_CPPFLAGS = @LOL_CFLAGS@ @PIPI_CFLAGS@ @CACA_CFLAGS@ +neercs_LDADD = +neercs_LDFLAGS = $(top_builddir)/src/liblol.a \ + @LOL_LIBS@ @PIPI_LIBS@ @CACA_LIBS@ @UTIL_LIBS@ @PAM_LIBS@ +neercs_DEPENDENCIES = $(top_builddir)/src/liblol.a + +if USE_CACA +all-local: neercs$(EXEEXT) + test $(MAKE_FSELF) = no || make_fself neercs$(EXEEXT) neercs.self +endif + +CLEANFILES = $(noinst_PROGRAMS:%$(EXEEXT)=%.self) \ + $(noinst_PROGRAMS:%$(EXEEXT)=%.elf) \ + $(noinst_PROGRAMS:%$(EXEEXT)=%.exe) + +SUFFIXES = .lolfx +.lolfx.o: + (echo "char const *"; \ + echo "lolfx_$(notdir $(basename $(filter %.lolfx, $^))) ="; \ + $(SED) 's/"/\\"/g' $(filter %.lolfx, $^) | \ + $(SED) 's/\([^\r]*\).*/"\1\\n"/'; \ + echo ";") | $(CXXCOMPILE) -xc++ -c - -o $@ + diff --git a/neercs/neercs.cpp b/neercs/neercs.cpp new file mode 100644 index 0000000..df388db --- /dev/null +++ b/neercs/neercs.cpp @@ -0,0 +1,122 @@ +// +// Neercs +// +// Copyright: (c) 2012 Sam Hocevar +// + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#if defined _WIN32 +# include +#endif + +#if defined _XBOX +# define _USE_MATH_DEFINES /* for M_PI */ +# include +# undef near /* Fuck Microsoft */ +# undef far /* Fuck Microsoft again */ +#elif defined _WIN32 +# define _USE_MATH_DEFINES /* for M_PI */ +# define WIN32_LEAN_AND_MEAN +# include +# undef near /* Fuck Microsoft */ +# undef far /* Fuck Microsoft again */ +#else +# include +#endif + +#if USE_SDL && defined __APPLE__ +# include +#endif + +#include + +#include + +#include "core.h" +#include "loldebug.h" + +using namespace std; +using namespace lol; + +#include "neercs.h" +#include "video/render.h" + +Neercs::Neercs() + : m_ready(false), + m_caca(caca_create_canvas(47, 32)), + m_render(new Render(m_caca)), + m_time(0.f) +{ + Ticker::Ref(m_render); +} + +void Neercs::TickGame(float seconds) +{ + WorldEntity::TickGame(seconds); + + m_time += seconds; + + caca_set_color_ansi(m_caca, CACA_DEFAULT, CACA_DEFAULT); + caca_clear_canvas(m_caca); + + caca_fill_ellipse(m_caca, 20+10 * lol::cos(m_time * 1.f), 10+10 * lol::sin(m_time * 1.f), 16+8 * lol::sin(m_time * 6.f), 12+6 * lol::cos(m_time * 5.f), '|'); + caca_fill_ellipse(m_caca, 20+10 * lol::cos(m_time * 1.f), 10+10 * lol::sin(m_time * 1.f), 12+8 * lol::sin(m_time * 6.f), 8+6 * lol::cos(m_time * 5.f), ' '); + + caca_set_color_ansi(m_caca, 2, CACA_DEFAULT); + int x1 = 12 + 10 * lol::cos(m_time * 5.f); + int y1 = 6 + 5 * lol::sin(m_time * 5.f); + int x2 = 30 + 5 * lol::cos(m_time * 8.f); + int y2 = 8 + 5 * lol::sin(m_time * 8.f); + int y3 = 8 + 5 * lol::cos(m_time * 5.f); + caca_draw_thin_line(m_caca, x1, y1, x2, y2); + caca_draw_thin_line(m_caca, 40, y3, x2, y2); + caca_draw_thin_line(m_caca, x1, y1, 40, y3); + + int x3 = 13 + 7 * lol::cos(m_time * 3.f); + caca_set_color_ansi(m_caca, CACA_CYAN, CACA_BLUE); + caca_put_str(m_caca, x3, 3, " LOL WUT "); + + int x4 = 6 + 5 * lol::cos(m_time * 2.f); + caca_set_color_ansi(m_caca, CACA_YELLOW, CACA_RED); + caca_put_str(m_caca, x4, 25, "Le Caca C'Est Surpuissant \\:D/"); + + caca_put_str(m_caca, 0, 0, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + caca_put_str(m_caca, 0, 1, " !\"#$%&'()*+,-./0123456789"); + + if (Input::GetButtonState(27 /*SDLK_ESCAPE*/)) + Ticker::Shutdown(); + +} + +void Neercs::TickDraw(float seconds) +{ + WorldEntity::TickDraw(seconds); +} + +Neercs::~Neercs() +{ + Ticker::Unref(m_render); +} + +int main(int argc, char **argv) +{ + Application app("Neercs", ivec2(800, 600), 60.0f); + +#if defined _MSC_VER && !defined _XBOX + _chdir(".."); +#elif defined _WIN32 && !defined _XBOX + _chdir("../.."); +#endif + + new Neercs(); + new DebugFps(5, 5); + app.ShowPointer(false); + + app.Run(); + + return EXIT_SUCCESS; +} + diff --git a/neercs/neercs.h b/neercs/neercs.h new file mode 100644 index 0000000..f9b8947 --- /dev/null +++ b/neercs/neercs.h @@ -0,0 +1,34 @@ +// +// Neercs +// +// Copyright: (c) 2012 Sam Hocevar +// + +#if !defined __NEERCS_H__ +#define __NEERCS_H__ + +#include + +#include "video/render.h" + +class Neercs : public WorldEntity +{ +public: + Neercs(); + virtual ~Neercs(); + + char const *GetName() { return ""; } + +protected: + virtual void TickGame(float seconds); + virtual void TickDraw(float seconds); + +private: + bool m_ready; + caca_canvas_t *m_caca; + Render *m_render; + float m_time; +}; + +#endif // __NEERCS_H__ + diff --git a/neercs/neercs.vcxproj b/neercs/neercs.vcxproj new file mode 100644 index 0000000..8bbbea6 --- /dev/null +++ b/neercs/neercs.vcxproj @@ -0,0 +1,81 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Debug + Xbox 360 + + + Release + Win32 + + + Release + x64 + + + Release + Xbox 360 + + + + + + + + + + + + + + + {9e62f2fe-3408-4eae-8238-fd84238ceeda} + + + + + + + + + + + + + {587FCCE9-1D8D-4398-B8B6-E8F4E9A92233} + Application + Win32Proj + + + + + + + + + + + + + + $(CacaIncludes);%(AdditionalIncludeDirectories) + + + $(CacaDeps);%(AdditionalDependencies) + $(CacaLibs);%(AdditionalLibraryDirectories) + + + + + + + diff --git a/neercs/neercs.vcxproj.filters b/neercs/neercs.vcxproj.filters new file mode 100644 index 0000000..3019469 --- /dev/null +++ b/neercs/neercs.vcxproj.filters @@ -0,0 +1,49 @@ + + + + + + video + + + video + + + + + + video + + + video + + + + + {8598edd6-ce35-4250-b16e-4237b34ebd2a} + + + + + video + + + video + + + video + + + video + + + video + + + video + + + video + + + diff --git a/neercs/video/blurh.lolfx b/neercs/video/blurh.lolfx new file mode 100644 index 0000000..258530c --- /dev/null +++ b/neercs/video/blurh.lolfx @@ -0,0 +1,36 @@ +-- GLSL.Vert -- + +#version 120 + +void main() + { + gl_Position=gl_Vertex; + gl_TexCoord[0]=gl_MultiTexCoord0; + } + +-- GLSL.Frag -- + +#version 120 + +uniform sampler2D texture; +uniform vec2 screen_size; +uniform float time; +uniform float value; + +float blur=value; + +void main(void) + { + vec4 total=vec4(0.0); + vec2 p=gl_TexCoord[0].xy/screen_size; + total+=texture2D(texture,vec2(p.x-blur*4.0,p.y))*0.04; + total+=texture2D(texture,vec2(p.x-blur*3.0,p.y))*0.08; + total+=texture2D(texture,vec2(p.x-blur*2.0,p.y))*0.12; + total+=texture2D(texture,vec2(p.x-blur ,p.y))*0.16; + total+=texture2D(texture,vec2(p.x ,p.y))*0.20; + total+=texture2D(texture,vec2(p.x+blur ,p.y))*0.16; + total+=texture2D(texture,vec2(p.x+blur*2.0,p.y))*0.12; + total+=texture2D(texture,vec2(p.x+blur*3.0,p.y))*0.08; + total+=texture2D(texture,vec2(p.x+blur*4.0,p.y))*0.04; + gl_FragColor=total; + } diff --git a/neercs/video/blurv.lolfx b/neercs/video/blurv.lolfx new file mode 100644 index 0000000..f5189d0 --- /dev/null +++ b/neercs/video/blurv.lolfx @@ -0,0 +1,36 @@ +-- GLSL.Vert -- + +#version 120 + +void main() + { + gl_Position=gl_Vertex; + gl_TexCoord[0]=gl_MultiTexCoord0; + } + +-- GLSL.Frag -- + +#version 120 + +uniform sampler2D texture; +uniform vec2 screen_size; +uniform float time; +uniform float value; + +float blur=value; + +void main(void) + { + vec4 total=vec4(0.0); + vec2 p=gl_TexCoord[0].xy/screen_size; + total+=texture2D(texture,vec2(p.x,p.y-blur*4.0))*0.04; + total+=texture2D(texture,vec2(p.x,p.y-blur*3.0))*0.08; + total+=texture2D(texture,vec2(p.x,p.y-blur*2.0))*0.12; + total+=texture2D(texture,vec2(p.x,p.y-blur ))*0.16; + total+=texture2D(texture,vec2(p.x,p.y ))*0.20; + total+=texture2D(texture,vec2(p.x,p.y+blur ))*0.16; + total+=texture2D(texture,vec2(p.x,p.y+blur*2.0))*0.12; + total+=texture2D(texture,vec2(p.x,p.y+blur*3.0))*0.08; + total+=texture2D(texture,vec2(p.x,p.y+blur*4.0))*0.04; + gl_FragColor=total; + } diff --git a/neercs/video/glow.lolfx b/neercs/video/glow.lolfx new file mode 100644 index 0000000..d4f2d52 --- /dev/null +++ b/neercs/video/glow.lolfx @@ -0,0 +1,31 @@ +-- GLSL.Vert -- + +#version 120 + +void main() + { + gl_Position=gl_Vertex; + gl_TexCoord[0]=gl_MultiTexCoord0; + } + +-- GLSL.Frag -- + +#version 120 + +uniform sampler2D texture; +uniform sampler2D texture_prv; +uniform vec2 screen_size; +uniform float time; +uniform float step; +uniform float value1; +uniform float value2; + +void main(void) + { + vec2 p=gl_TexCoord[0].xy; + vec4 source=texture2D(texture_prv,p); + vec4 glow=texture2D(texture,p); + source=smoothstep(step,1.0,source); + vec4 color=glow*value1+source*value2; + gl_FragColor=color; + } diff --git a/neercs/video/postfx.lolfx b/neercs/video/postfx.lolfx new file mode 100644 index 0000000..105fac1 --- /dev/null +++ b/neercs/video/postfx.lolfx @@ -0,0 +1,90 @@ +-- GLSL.Vert -- + +#version 120 + +void main() + { + gl_Position=gl_Vertex; + gl_TexCoord[0]=gl_MultiTexCoord0; + } + +-- GLSL.Frag -- + +#version 120 + +uniform sampler2D texture; +uniform vec2 screen_size; +uniform float time; +uniform float flash; +uniform float value; +uniform float deform; +uniform bool scanline; +uniform float sync; + +const float PI=3.14159265358979323846; +float lens=PI/(deform+sync*0.0625); + +vec2 zoom(in vec2 p,in float radius) + { + float zoom=1.5-(radius*cos(p.x*PI/lens)+radius*cos(p.y*PI/lens)); + return vec2(p.x*zoom-0.5,p.y*zoom-0.5); + } + +vec3 get_color(in sampler2D tex,in vec2 p) + { + return (p.x<-1.0||p.x>0.0||p.y<-1.0||p.y>0.0)?vec3(0.0,0.0,0.0):texture2D(tex,p).xyz; + } + +float rand(in vec2 p) + { + return fract(sin(dot(p.xy,vec2(12.9898,78.233)))*43758.5453); + } + +void main(void) + { + vec2 q=gl_TexCoord[0].xy; + vec2 p=-1.0+2.0*gl_TexCoord[0].xy; + p.y+=0.025*sync; + vec2 z =zoom(p,0.5250); + vec2 z1=zoom(p,0.5225); + vec2 z2=zoom(p,0.5275); + float g=(2.0-cos(PI/lens/2.0+z.x*PI/lens)-cos(PI/lens/2.0+z.y*PI/lens))*32.0; + + float rnd1=rand(vec2(p.x+time,p.y-time)); + float rnd2=rand(vec2(p.x-time,p.y+time)); + float d1=rnd1*value/float(screen_size.x); + float d2=rnd2*value/float(screen_size.y); + + vec3 source;//=get_color(texture,z); + source.x=get_color(texture,vec2(z.x+d1,z.y)).x; + source.y=get_color(texture,vec2(z.x+d1,z.y)).y; + source.z=get_color(texture,vec2(z.x+d1,z.y)).z; + + vec3 glass1=get_color(texture,z1); + vec3 glass2=get_color(texture,z2); + + float v=value/float(screen_size.x)*g; + + vec3 noise; + noise.x=get_color(texture,vec2(z.x+d1-v,z.y+d2)).x; + noise.y=get_color(texture,vec2(z.x+d1 ,z.y-d2)).y; + noise.z=get_color(texture,vec2(z.x+d1+v,z.y-d2)).z; + + vec3 color=source+glass1*glass1*0.25+glass2*glass2*0.25+(scanline?noise:source); + + color+=flash; // flash + if(scanline) + { + color-=0.0125*mod(z.y*4.0+time*0.25,1.0); // electron beam + color-=(vec3(rnd1,rnd1,rnd1)-vec3(rnd2,rnd2,rnd2))*0.1; // noise + color*=0.75+0.25*sin(z.x*float(screen_size.x*2)); // scanline w + color*=0.90+0.10*cos(z.y*float(screen_size.y))*sin(0.5+z.x*float(screen_size.x)); // scanline h + } + else + { + color*=0.675; + } + color=vec3(color.x*0.875,color.y*1.0,color.z*0.625); + color*=q.x*(6.0-q.x*6.0)*q.y*(6.0-q.y*6.0); // vignetting + gl_FragColor=vec4(color,1.0); + } diff --git a/neercs/video/radial.lolfx b/neercs/video/radial.lolfx new file mode 100644 index 0000000..537fe4f --- /dev/null +++ b/neercs/video/radial.lolfx @@ -0,0 +1,54 @@ +-- GLSL.Vert -- + +#version 120 + +void main() + { + gl_Position=gl_Vertex; + gl_TexCoord[0]=gl_MultiTexCoord0; + } + +-- GLSL.Frag -- + +#version 120 + +uniform sampler2D texture; +uniform vec2 screen_size; +uniform float time; +uniform float value1; +uniform float value2; +uniform float color; + +float PI=3.14159265358979323846; + +vec3 deform(in vec2 p) + { + vec2 uv; + float zoom=0.5; + uv.x=p.x*zoom-0.5; + uv.y=p.y*zoom-0.5; + return texture2D(texture,uv).xyz; + } + +void main(void) + { + int n=32; + + vec2 p=-1.0+4.0*gl_TexCoord[0].xy; + vec2 s=p; + vec3 source=deform(s); + + vec3 total=vec3(0,1.0,1.0); + + vec2 d=-p/float(n*2); + float w=value1; + for(int i=0;i +#elif defined _WIN32 +# define _USE_MATH_DEFINES /* for M_PI */ +# define WIN32_LEAN_AND_MEAN +# include +#endif + +#include +#include +#include +#include +#include + +#include "core.h" +#include "lolgl.h" + +using namespace std; +using namespace lol; + +#include "../neercs.h" +#include "render.h" +#include "text-render.h" + +extern char const *lolfx_blurh; +extern char const *lolfx_blurv; +extern char const *lolfx_glow; +extern char const *lolfx_postfx; +extern char const *lolfx_radial; +extern char const *lolfx_simple; + +#define DEBUG 1 // debug flag //#if defined(_DEBUG) +#define PID M_PI/180.0f // pi ratio +#define CR 1.0f/256.0f // color ratio + +/* + * Various variables + */ + +int keys[256]; // keyboard array +int active = true; // window active flag +bool fullscreen = DEBUG?false:true; // fullscreen flag +bool paused = false; // pause flag +float nearplane = 0.1f; // nearplane +float farplane = 1000.0f; // farplane +bool polygon = true; // polygon mode +int polygon_fillmode = GL_FILL; // fill mode +/* window variable */ +ivec2 screen_size; // screen size +int window_color = 32; // color depth +vec3 screen_color = CR * vec3(48, 56, 64); // screen color +/* object variable */ +float main_angle = 0.0f; // main angle +float part_angle = 0.0f; // part angle +float fx_angle; // current angle +/* text variable */ +char const *name = "cacaShell"; +/* fs_quad variable */ +float fs_quad_vtx[] = {-1.0f, 1.0f, 0, 1.0f, -1.0f, -1.0f, 0, 1.0f, 1.0f, -1.0f, 0, 1.0f, 1.0f, 1.0f, 0, 1.0f}; +float fs_quad_tex[] = {0, 1.0f, 0, 0, 1.0f, 0, 1.0f, 1.0f}; +/* flash variable */ +bool flash_flag = false; // flag +float flash_angle = 0; // angle +float flash_value = 0; // value +float flash_speed = 1.5f; // speed +/* fade variable */ +bool fade_flag = false; // flag +float fade_angle = 0; // angle +float fade_value = 0; // value +float fade_speed = 0.2f; // speed +/* sync variable */ +bool sync_flag = false; // flag +float sync_angle = 0; // angle +float sync_value = 1.0f; // value +float sync_speed = 1.0f; // speed +/* beat variable */ +bool beat_flag = false; // flag +float beat_angle = 0; // angle +float beat_value = 0; // value +float beat_speed = 2.0f; // speed +/* corner variable */ +const int corner_n = 10; // polygon number +int corner_w = 24; // radius +int corner_vtx[corner_n*6];// vertex array +/* dos variable */ +bool dos_flag = true; // flag +int dos_m; // margin +vec3 dos_color = CR * vec3(48, 56, 64); // color value +int dos_vtx[8]; // vertex array +ivec2 ratio_2d(2,4); // 2d ratio +ivec2 map_size(256,256); // texture map size +ivec2 font_size(8,8); // font size +vec2 car_size(1.0f/map_size.x*font_size.x, 1.0f/map_size.y*font_size.y); +int shell_vtx[8]; // vertex array +float shell_tex[] = {1.0f, 0.96875f, 1.0f, 1.0f, 0.78125f, 1.0f, 0.78125f, 0.96875f}; +/* keyboard variable */ +int key_code = 0; // keyboard code +/* common variable */ +float value, angle, radius, scale, speed; +/* shader variable */ +bool shader_flag = true; +bool shader_blur_flag = true; +bool shader_glow_flag = true; +bool shader_effect_flag = true; +bool shader_postfx_flag = true; + +int glow_fbo_size = 2; // glow fbo size +float glow_smoothstep = 0.0f; // glow smoothstep value (try 0.025f) +float glow_mix_ratio1 = 0.5f; // glow mixing ratio +float glow_mix_ratio2 = 0.5f; // source mixing ratio + +float radial_value1 = 2.0f; +float radial_value2 = 0.8f; +float radial_color = 0; // color + +bool postfx_scanline = true; +float postfx_deform = 0.5f; // deformation ratio + +Shader *shader_simple, *shader_blur_h, *shader_blur_v; +Shader *shader_glow, *shader_radial, *shader_postfx; +// shader variables +ShaderUniform shader_simple_texture; +ShaderUniform shader_blur_h_texture, + shader_blur_h_screen_size, + shader_blur_h_time, + shader_blur_h_value; +ShaderUniform shader_blur_v_texture, + shader_blur_v_screen_size, + shader_blur_v_time, + shader_blur_v_value; +ShaderUniform shader_glow_texture, + shader_glow_texture_prv, + shader_glow_screen_size, + shader_glow_time, + shader_glow_step, + shader_glow_value1, + shader_glow_value2; +ShaderUniform shader_radial_texture, + shader_radial_screen_size, + shader_radial_time, + shader_radial_value1, + shader_radial_value2, + shader_radial_color; +ShaderUniform shader_postfx_texture, + shader_postfx_texture_2d, + shader_postfx_screen_size, + shader_postfx_time, + shader_postfx_flash, + shader_postfx_value, + shader_postfx_deform, + shader_postfx_scanline, + shader_postfx_sync; + +FrameBuffer *fbo_back, *fbo_front; +FrameBuffer *fbo_blur_h, *fbo_blur_v, *fbo_ping, *fbo_pong; + +TextRender *text_render; + +void fs_quad() +{ + glLoadIdentity(); + glDrawArrays(GL_QUADS, 0, 4); +} + +void draw_shader_simple(FrameBuffer *fbo_output, int n) +{ + shader_simple->Bind(); + shader_simple->SetTexture(shader_simple_texture, fbo_output->GetTexture(), n); + fs_quad(); + shader_simple->Unbind(); +} + +void rectangle(int x, int y, int w, int h) +{ + glLoadIdentity(); + glBegin(GL_QUADS); + glVertex2i(x+w, y ); + glVertex2i(x , y ); + glVertex2i(x , y+h); + glVertex2i(x+w, y+h); + glEnd(); +} + +void corner() +{ + float vertex[6+corner_n*2]; + vertex[0] = 0; + vertex[1] = 0; + for (int i = 1; i < corner_n + 1; i++) + { + int j = i*2; + float a = PID*90.0f/(corner_n-1)*(i-1); + vertex[j ] = corner_w-corner_w*cosf(a); + vertex[j+1] = corner_w-corner_w*sinf(a); + } + for (int i = 0; i < corner_n; i++) + { + int j = i*6; + int k = i*2; + corner_vtx[j ] = (int)vertex[0]; + corner_vtx[j+1] = (int)vertex[1]; + corner_vtx[j+2] = (int)vertex[2+k]; + corner_vtx[j+3] = (int)vertex[3+k]; + corner_vtx[j+4] = (int)vertex[4+k]; + corner_vtx[j+5] = (int)vertex[5+k]; + } +} + +int InitGL(void) +{ + glDepthMask(GL_TRUE); // do not write z-buffer + glEnable(GL_CULL_FACE); // disable cull face + glCullFace(GL_BACK); // don't draw front face + + if (shader_flag) + { + /* Initialise framebuffer objects */ + fbo_back = new FrameBuffer(screen_size); + fbo_front = new FrameBuffer(screen_size); + fbo_blur_h = new FrameBuffer(screen_size / glow_fbo_size); + fbo_blur_v = new FrameBuffer(screen_size / glow_fbo_size); + fbo_ping = new FrameBuffer(screen_size); + fbo_pong = new FrameBuffer(screen_size); + // shader simple + shader_simple = Shader::Create(lolfx_simple); + shader_simple_texture = shader_simple->GetUniformLocation("texture"); + // shader blur horizontal + shader_blur_h = Shader::Create(lolfx_blurh); + shader_blur_h_texture = shader_blur_h->GetUniformLocation("texture"); + shader_blur_h_screen_size = shader_blur_h->GetUniformLocation("screen_size"); + shader_blur_h_time = shader_blur_h->GetUniformLocation("time"); + shader_blur_h_value = shader_blur_h->GetUniformLocation("value"); + // shader blur vertical + shader_blur_v = Shader::Create(lolfx_blurv); + shader_blur_v_texture = shader_blur_v->GetUniformLocation("texture"); + shader_blur_v_screen_size = shader_blur_v->GetUniformLocation("screen_size"); + shader_blur_v_time = shader_blur_v->GetUniformLocation("time"); + shader_blur_v_value = shader_blur_v->GetUniformLocation("value"); + // shader glow + shader_glow = Shader::Create(lolfx_glow); + shader_glow_texture = shader_glow->GetUniformLocation("texture"); + shader_glow_texture_prv = shader_glow->GetUniformLocation("texture_prv"); + shader_glow_screen_size = shader_glow->GetUniformLocation("screen_size"); + shader_glow_time = shader_glow->GetUniformLocation("time"); + shader_glow_step = shader_glow->GetUniformLocation("step"); + shader_glow_value1 = shader_glow->GetUniformLocation("value1"); + shader_glow_value2 = shader_glow->GetUniformLocation("value2"); + // shader radial + shader_radial = Shader::Create(lolfx_radial); + shader_radial_texture = shader_radial->GetUniformLocation("texture"); + shader_radial_screen_size = shader_radial->GetUniformLocation("screen_size"); + shader_radial_time = shader_radial->GetUniformLocation("time"); + shader_radial_value1 = shader_radial->GetUniformLocation("value1"); + shader_radial_value2 = shader_radial->GetUniformLocation("value2"); + shader_radial_color = shader_radial->GetUniformLocation("color"); + // shader postfx + shader_postfx = Shader::Create(lolfx_postfx); + shader_postfx_texture = shader_postfx->GetUniformLocation("texture"); + shader_postfx_texture_2d = shader_postfx->GetUniformLocation("texture_2d"); + shader_postfx_screen_size = shader_postfx->GetUniformLocation("screen_size"); + shader_postfx_time = shader_postfx->GetUniformLocation("time"); + shader_postfx_flash = shader_postfx->GetUniformLocation("flash"); + shader_postfx_value = shader_postfx->GetUniformLocation("value"); + shader_postfx_deform = shader_postfx->GetUniformLocation("deform"); + shader_postfx_scanline = shader_postfx->GetUniformLocation("scanline"); + shader_postfx_sync = shader_postfx->GetUniformLocation("sync"); + } + + return true; +} + +int CreateGLWindow(char const *title) +{ + screen_size = Video::GetSize(); + corner_w = 16*ratio_2d.x; + corner(); + dos_m=12*ratio_2d.x; + dos_vtx[0]=font_size.x*ratio_2d.x/2.0f; + dos_vtx[1]=font_size.y*ratio_2d.y/2.0f; + dos_vtx[2]=font_size.x*ratio_2d.x/2.0f; + dos_vtx[3]=-font_size.y*ratio_2d.y/2.0f; + dos_vtx[4]=-font_size.x*ratio_2d.x/2.0f; + dos_vtx[5]=-font_size.y*ratio_2d.y/2.0f; + dos_vtx[6]=-font_size.x*ratio_2d.x/2.0f; + dos_vtx[7]=font_size.y*ratio_2d.y/2.0f; + shell_vtx[0]=dos_m+58*ratio_2d.x; + shell_vtx[1]=dos_m+(font_size.y+1)*ratio_2d.y; + shell_vtx[2]=dos_m+58*ratio_2d.x; + shell_vtx[3]=dos_m+ratio_2d.y; + shell_vtx[4]=dos_m+2*ratio_2d.x; + shell_vtx[5]=dos_m+ratio_2d.y; + shell_vtx[6]=dos_m+2*ratio_2d.x; + shell_vtx[7]=dos_m+(font_size.y+1)*ratio_2d.y; + InitGL(); + return true; +} + +Render::Render(caca_canvas_t *caca) + : m_caca(caca), + m_ready(false) +{ + text_render = new TextRender(m_caca, font_size); +} + +void Render::TickGame(float seconds) +{ + Entity::TickGame(seconds); +} + +void Render::TickDraw(float seconds) +{ + Entity::TickDraw(seconds); + + if (!m_ready) + { + CreateGLWindow("LOL"); + text_render->Init(); + + m_ready = true; + } + + // timer + if(!paused) + main_angle += seconds * 100.0f * PID; + if(sync_flag) + { + angle=(main_angle-sync_angle)*sync_speed; + sync_value=1.0f-sinf(angle); + if(angle>90.0f*PID) + { + sync_value=0; + sync_flag=false; + } + } + if(beat_flag) + { + angle=(main_angle-beat_angle)*beat_speed; + beat_value=1.0f-sinf(angle); + if(angle>90.0f*PID) + { + beat_value=0; + beat_flag=false; + } + } + if(flash_flag) + { + angle=(main_angle-flash_angle)*flash_speed; + flash_value=1.0f-sinf(angle); + if(angle>90.0f*PID) + { + flash_value=0; + flash_flag=false; + } + } + if(fade_flag) + { + angle=(main_angle-fade_angle)*fade_speed; + fade_value=1.0f-sinf(angle); + if(angle>90.0f*PID) + { + fade_value=0; + fade_flag=false; + } + } + + Draw2D(); + Draw3D(); +} + +void Render::Draw2D() +{ + /* Draw text in an offline buffer */ + text_render->Render(); + + if(shader_flag) + fbo_back->Bind(); + + glViewport(0, 0, screen_size.x, screen_size.y); + + /* Clear the back buffer */ + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_COLOR,GL_DST_ALPHA); + glClearColor(screen_color.r, screen_color.g, screen_color.b, 0.5f); + glClearDepth(1.0f); // set depth buffer + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + ivec2 border_top = ivec2(dos_m, dos_m + font_size.y * ratio_2d.y) + + ratio_2d * 2; + ivec2 border_bottom = ivec2(dos_m * 2, dos_m * 2 + font_size.y * ratio_2d.y) + + ratio_2d * 2; + text_render->Blit(border_top, screen_size - border_bottom); + + //if(polygon) glEnable(GL_LINE_SMOOTH); else glDisable(GL_LINE_SMOOTH); + glLineWidth((polygon)?2.0f:1.0f); + fx_angle=main_angle-part_angle; + if(polygon) glEnable(GL_TEXTURE_2D); + + glMatrixMode(GL_PROJECTION); + mat4 m = mat4::ortho(0, screen_size.x, screen_size.y, 0, -1.f, 1.f); + glLoadMatrixf(&m[0][0]); + glMatrixMode(GL_MODELVIEW); + // draw dos + if(dos_flag) + { + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + glColor3f(1.0f,1.0f,1.0f); + rectangle(dos_m,dos_m,screen_size.x-53*ratio_2d.x-dos_m*2,(font_size.y+2)*ratio_2d.y); + rectangle(screen_size.x-51*ratio_2d.x-dos_m,dos_m,22*ratio_2d.x,(font_size.y+2)*ratio_2d.y); + rectangle(screen_size.x-27*ratio_2d.x-dos_m,dos_m,22*ratio_2d.x,(font_size.y+2)*ratio_2d.y); + rectangle(screen_size.x-3*ratio_2d.x-dos_m,dos_m,3*ratio_2d.x,(font_size.y+2)*ratio_2d.y); + rectangle(dos_m,dos_m+(font_size.y+2)*ratio_2d.y,2*ratio_2d.x,screen_size.y-(font_size.y+2)*ratio_2d.y-dos_m*2); + rectangle(screen_size.x-2*ratio_2d.x-dos_m,dos_m+(font_size.y+2)*ratio_2d.y,2*ratio_2d.x,screen_size.y-(font_size.y+2)*ratio_2d.y-dos_m*2); + rectangle(dos_m+2*ratio_2d.x,screen_size.y-ratio_2d.y-dos_m,screen_size.x-4*ratio_2d.x-dos_m*2,ratio_2d.y); + glColor3f(dos_color.x,dos_color.y,dos_color.z); + rectangle(dos_m+2*ratio_2d.x,dos_m+ratio_2d.y,56*ratio_2d.x,font_size.y*ratio_2d.y); + rectangle(dos_m+60*ratio_2d.x,dos_m+2*ratio_2d.y,screen_size.x-115*ratio_2d.x-dos_m*2,2*ratio_2d.y); + rectangle(dos_m+60*ratio_2d.x,dos_m+6*ratio_2d.y,screen_size.x-115*ratio_2d.x-dos_m*2,2*ratio_2d.y); + rectangle(screen_size.x-49*ratio_2d.x-dos_m,dos_m+ratio_2d.y,14*ratio_2d.x,6*ratio_2d.y); + glColor3f(1.0f,1.0f,1.0f); + rectangle(screen_size.x-47*ratio_2d.x-dos_m,dos_m+2*ratio_2d.y,10*ratio_2d.x,4*ratio_2d.y); + glColor3f(0,0,0); + rectangle(screen_size.x-45*ratio_2d.x-dos_m,dos_m+3*ratio_2d.y,14*ratio_2d.x,6*ratio_2d.y); + rectangle(screen_size.x-25*ratio_2d.x-dos_m,dos_m+1*ratio_2d.y,14*ratio_2d.x,6*ratio_2d.y); + glColor3f(dos_color.x,dos_color.y,dos_color.z); + rectangle(screen_size.x-21*ratio_2d.x-dos_m,dos_m+2*ratio_2d.y,14*ratio_2d.x,7*ratio_2d.y); + glColor3f(1.0f,1.0f,1.0f); + rectangle(screen_size.x-19*ratio_2d.x-dos_m,dos_m+3*ratio_2d.y,10*ratio_2d.x,5*ratio_2d.y); + rectangle(screen_size.x-16*ratio_2d.x-dos_m,screen_size.y-9*ratio_2d.y-dos_m,14*ratio_2d.x,8*ratio_2d.y); + glColor3f(dos_color.x,dos_color.y,dos_color.z); + rectangle(screen_size.x-14*ratio_2d.x-dos_m,screen_size.y-8*ratio_2d.y-dos_m,12*ratio_2d.x,7*ratio_2d.y); + glColor3f(1.0f,1.0f,1.0f); + rectangle(screen_size.x-8*ratio_2d.x-dos_m,screen_size.y-8*ratio_2d.y-dos_m,8*ratio_2d.x,2*ratio_2d.y); + rectangle(screen_size.x-14*ratio_2d.x-dos_m,screen_size.y-5*ratio_2d.y-dos_m,4*ratio_2d.x,5*ratio_2d.y); + rectangle(screen_size.x-12*ratio_2d.x-dos_m,screen_size.y-7*ratio_2d.y-dos_m,2*ratio_2d.x,1*ratio_2d.y); + rectangle(screen_size.x-8*ratio_2d.x-dos_m,screen_size.y-5*ratio_2d.y-dos_m,4*ratio_2d.x,3*ratio_2d.y); + glEnable(GL_BLEND); + if(polygon) glEnable(GL_TEXTURE_2D); + glBlendFunc(GL_ONE, GL_ONE); + glVertexPointer(2, GL_INT, 0, shell_vtx); + glTexCoordPointer(2, GL_FLOAT, 0, shell_tex); + glDrawArrays(GL_QUADS, 0, 4); + } + // draw corner + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + glVertexPointer(2, GL_INT, 0, corner_vtx); + glLoadIdentity(); + glColor3f(0, 0, 0); + glDrawArrays(GL_TRIANGLES, 0, corner_n*3); + glTranslated(screen_size.x, 0, 0); + glRotated(90.0f, 0, 0, 1.0f); + glDrawArrays(GL_TRIANGLES, 0, corner_n*3); + glTranslated(screen_size.y, 0, 0); + glRotated(90.0f, 0, 0, 1.0f); + glDrawArrays(GL_TRIANGLES, 0, corner_n*3); + glTranslated(screen_size.x, 0, 0); + glRotated(90.0f, 0, 0, 1.0f); + glDrawArrays(GL_TRIANGLES, 0, corner_n*3); + glEnable(GL_BLEND); +} + +void Render::Draw3D() +{ + if (!shader_flag) + return; + + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(4, GL_FLOAT, 0, fs_quad_vtx); + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, fs_quad_tex); + + fbo_back->Unbind(); + if (shader_effect_flag && shader_blur_flag) + { + // shader blur horizontal + fbo_ping->Bind(); + shader_blur_h->Bind(); + shader_blur_h->SetTexture(shader_blur_h_texture, fbo_back->GetTexture(), 0); + shader_blur_h->SetUniform(shader_blur_h_screen_size, vec2(1.0f)); + shader_blur_h->SetUniform(shader_blur_h_time, fx_angle); + shader_blur_h->SetUniform(shader_blur_h_value, 0.5f/screen_size.x); + fs_quad(); + shader_blur_h->Unbind(); + fbo_ping->Unbind(); + // shader blur vertical + fbo_front->Bind(); + shader_blur_v->Bind(); + shader_blur_v->SetTexture(shader_blur_v_texture, fbo_ping->GetTexture(), 0); + shader_blur_v->SetUniform(shader_blur_v_screen_size, vec2(1.0f)); + shader_blur_v->SetUniform(shader_blur_v_time, fx_angle); + shader_blur_v->SetUniform(shader_blur_v_value, 0.5f/screen_size.y); + fs_quad(); + shader_blur_v->Unbind(); + } + else + { + // shader simple + fbo_front->Bind(); + draw_shader_simple(fbo_back, 0); + } + fbo_front->Unbind(); + // shader glow + if(shader_effect_flag && shader_glow_flag) + { + // shader blur horizontal + fbo_blur_h->Bind(); + shader_blur_h->Bind(); + shader_blur_h->SetTexture(shader_blur_h_texture, fbo_ping->GetTexture(), 0); + shader_blur_h->SetUniform(shader_blur_h_screen_size, vec2(1.0f / glow_fbo_size)); + shader_blur_h->SetUniform(shader_blur_h_time, fx_angle); + shader_blur_h->SetUniform(shader_blur_h_value, 2.5f/screen_size.x); + fs_quad(); + shader_blur_h->Unbind(); + fbo_blur_h->Unbind(); + // shader blur vertical + fbo_blur_v->Bind(); + shader_blur_v->Bind(); + shader_blur_v->SetTexture(shader_blur_v_texture, fbo_blur_h->GetTexture(), 0); + shader_blur_v->SetUniform(shader_blur_v_screen_size, vec2(1.0f / glow_fbo_size)); + shader_blur_v->SetUniform(shader_blur_v_time, fx_angle); + shader_blur_v->SetUniform(shader_blur_h_value, 2.5f/screen_size.y); + fs_quad(); + shader_blur_v->Unbind(); + fbo_blur_v->Unbind(); + // shader blur horizontal + fbo_blur_h->Bind(); + shader_blur_h->Bind(); + shader_blur_h->SetTexture(shader_blur_h_texture, fbo_blur_v->GetTexture(), 0); + shader_blur_h->SetUniform(shader_blur_h_screen_size, vec2(1.0f / glow_fbo_size)); + shader_blur_h->SetUniform(shader_blur_h_time, fx_angle); + shader_blur_h->SetUniform(shader_blur_h_value, 1.0f/screen_size.x); + fs_quad(); + shader_blur_h->Unbind(); + fbo_blur_h->Unbind(); + // shader blur vertical + fbo_blur_v->Bind(); + shader_blur_v->Bind(); + shader_blur_v->SetTexture(shader_blur_v_texture, fbo_blur_h->GetTexture(), 0); + shader_blur_v->SetUniform(shader_blur_v_screen_size, vec2(1.0f / glow_fbo_size)); + shader_blur_v->SetUniform(shader_blur_v_time, fx_angle); + shader_blur_v->SetUniform(shader_blur_h_value, 1.0f/screen_size.y); + fs_quad(); + shader_blur_v->Unbind(); + fbo_blur_v->Unbind(); + // shader glow + fbo_pong->Bind(); + shader_glow->Bind(); + shader_glow->SetTexture(shader_glow_texture, fbo_blur_v->GetTexture(), 0); + shader_glow->SetTexture(shader_glow_texture_prv, fbo_front->GetTexture(), 1); + shader_glow->SetUniform(shader_glow_screen_size, vec2(1.0f)); + shader_glow->SetUniform(shader_glow_time, fx_angle); + shader_glow->SetUniform(shader_glow_step, glow_smoothstep); + shader_glow->SetUniform(shader_glow_value1, glow_mix_ratio1); + shader_glow->SetUniform(shader_glow_value2, glow_mix_ratio2); + fs_quad(); + shader_glow->Unbind(); + } + if(!shader_effect_flag) + { + // shader simple + fbo_pong->Bind(); + draw_shader_simple(fbo_front, 0); + } + fbo_pong->Unbind(); + if(shader_postfx_flag) + { + // shader postfx + shader_postfx->Bind(); + shader_postfx->SetTexture(shader_postfx_texture, fbo_pong->GetTexture(), 0); + shader_postfx->SetUniform(shader_postfx_screen_size, (vec2)screen_size); + shader_postfx->SetUniform(shader_postfx_time, fx_angle); + shader_postfx->SetUniform(shader_postfx_flash, flash_value); + shader_postfx->SetUniform(shader_postfx_value, 4.0f); + shader_postfx->SetUniform(shader_postfx_deform, postfx_deform); + shader_postfx->SetUniform(shader_postfx_scanline, postfx_scanline); + shader_postfx->SetUniform(shader_postfx_sync, (float)fabs(beat_value*cosf((main_angle-beat_angle)*8.0f))); + fs_quad(); + shader_postfx->Unbind(); + } + else + { + // shader simple + draw_shader_simple(fbo_pong, 0); + } + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + +Render::~Render() +{ +} + diff --git a/neercs/video/render.h b/neercs/video/render.h new file mode 100644 index 0000000..6431150 --- /dev/null +++ b/neercs/video/render.h @@ -0,0 +1,28 @@ +// +// + +#if !defined __VIDEO_RENDER_H__ +#define __VIDEO_RENDER_H__ + +class Render : public WorldEntity +{ +public: + Render(caca_canvas_t *caca); + virtual ~Render(); + + char const *GetName() { return ""; } + +protected: + virtual void TickGame(float seconds); + virtual void TickDraw(float seconds); + + void Draw2D(); + void Draw3D(); + +private: + caca_canvas_t *m_caca; + bool m_ready; +}; + +#endif // __VIDEO_RENDER_H__ + diff --git a/neercs/video/resource/map.png b/neercs/video/resource/map.png new file mode 100644 index 0000000..e9d0f15 Binary files /dev/null and b/neercs/video/resource/map.png differ diff --git a/neercs/video/simple.lolfx b/neercs/video/simple.lolfx new file mode 100644 index 0000000..9e33b46 --- /dev/null +++ b/neercs/video/simple.lolfx @@ -0,0 +1,20 @@ +-- GLSL.Vert -- + +#version 120 + +void main() + { + gl_Position=gl_Vertex; + gl_TexCoord[0]=gl_MultiTexCoord0; + } + +-- GLSL.Frag -- + +#version 120 + +uniform sampler2D texture; + +void main(void) + { + gl_FragColor=vec4(texture2D(texture,gl_TexCoord[0].xy).xyz,1.0); + } diff --git a/neercs/video/text-render.cpp b/neercs/video/text-render.cpp new file mode 100644 index 0000000..8fd8448 --- /dev/null +++ b/neercs/video/text-render.cpp @@ -0,0 +1,151 @@ +// +// Neercs +// + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include <cmath> +#include <cstdio> +#include <cstdlib> +#include <ctime> +#include <string> + +#include "core.h" +#include "lolgl.h" + +using namespace std; +using namespace lol; + +#include "../neercs.h" +#include "render.h" +#include "text-render.h" + +extern char const *lolfx_text; + +/* + * Text rendering interface + */ + +TextRender::TextRender(caca_canvas_t *caca, ivec2 font_size) + : m_caca(caca), + m_font_size(font_size), + m_canvas_size(caca_get_canvas_width(m_caca), + caca_get_canvas_height(m_caca)), + m_fbo_size(m_font_size * m_canvas_size), + m_cells(m_canvas_size.x * m_canvas_size.y) +{ + for (int j = 0; j < m_canvas_size.y; j++) + for (int i = 0; i < m_canvas_size.x; i++) + m_vertices << vec2(i, j); +} + +void TextRender::Init() +{ + m_font = new TileSet("neercs/video/resource/map.png", + ivec2(256, 256), ivec2(1)); + + m_shader = Shader::Create(lolfx_text); + m_coord = m_shader->GetAttribLocation("in_Position", + VertexUsage::Position, 0); + m_color = m_shader->GetAttribLocation("in_Attr", + VertexUsage::Color, 0); + m_char = m_shader->GetAttribLocation("in_Char", + VertexUsage::Color, 1); + m_texture = m_shader->GetUniformLocation("in_Texture"); + m_transform = m_shader->GetUniformLocation("in_Transform"); + m_vdecl + = new VertexDeclaration(VertexStream<vec2>(VertexUsage::Position), + VertexStream<uint32_t>(VertexUsage::Color), + VertexStream<uint32_t>(VertexUsage::Color)); + + m_vbo1 = new VertexBuffer(m_vertices.Bytes()); + void *vertices = m_vbo1->Lock(0, 0); + memcpy(vertices, &m_vertices[0], m_vertices.Bytes()); + m_vbo1->Unlock(); + + m_vbo2 = new VertexBuffer(m_cells * sizeof(int32_t)); + m_vbo3 = new VertexBuffer(m_cells * sizeof(int32_t)); + + m_fbo = new FrameBuffer(m_fbo_size); +} + +void TextRender::Render() +{ + /* Transform matrix for the scene: + * - translate to the centre of the glyph + * - scale by 2.f * font_size / fbo_size + * - translate to the lower left corner */ + mat4 xform = mat4::translate(-1.f, -1.f + 2.0f * m_font_size.y + * m_canvas_size.y / m_fbo_size.y, 0.f) + * mat4::scale(vec3(2.f * m_font_size / m_fbo_size, 1.f) + * vec3(1.f, -1.f, 1.f)) + * mat4::translate(0.5f, 0.5f, 0.f); + + /* Upload libcaca canvas contents to the vertex buffers */ + uint32_t *colors = (uint32_t *)m_vbo2->Lock(0, 0); + for (int j = 0; j < m_canvas_size.y; j++) + for (int i = 0; i < m_canvas_size.x; i++) + { + uint32_t attr = caca_get_attr(m_caca, i, j); + uint16_t fg = caca_attr_to_rgb12_fg(attr); + uint16_t bg = caca_attr_to_rgb12_bg(attr); + caca_set_color_argb(m_caca, fg, bg); + attr = caca_get_attr(m_caca, -1, -1); + caca_put_attr(m_caca, i, j, attr); + } + memcpy(colors, caca_get_canvas_attrs(m_caca), + m_cells * sizeof(uint32_t)); + m_vbo2->Unlock(); + + uint32_t *chars = (uint32_t *)m_vbo3->Lock(0, 0); + memcpy(chars, caca_get_canvas_chars(m_caca), + m_cells * sizeof(uint32_t)); + m_vbo3->Unlock(); + + m_fbo->Bind(); + glViewport(0, 0, m_fbo_size.x, m_fbo_size.y); + glDisable(GL_DEPTH_TEST); + glEnable(GL_POINT_SPRITE); + //glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + glDisable(GL_POINT_SMOOTH); + glPointSize((float)max(m_font_size.x, m_font_size.y)); + m_shader->Bind(); + m_font->Bind(); + m_shader->SetUniform(m_texture, 0); + m_shader->SetUniform(m_transform, xform); + m_vdecl->SetStream(m_vbo1, m_coord); + m_vdecl->SetStream(m_vbo2, m_color); + m_vdecl->SetStream(m_vbo3, m_char); + m_vdecl->Bind(); + m_vdecl->DrawElements(MeshPrimitive::Points, 0, m_cells); + m_vdecl->Unbind(); + m_font->Unbind(); + m_shader->Unbind(); + glDisable(GL_POINT_SPRITE); + m_fbo->Unbind(); +} + +void TextRender::Blit(ivec2 pos, ivec2 size) +{ + glDisable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m_fbo->GetTexture()); + glColor3f(1.0f, 1.0f, 1.0f); + + vec2 tc = (vec2)m_canvas_size * m_font_size / m_fbo_size; + + glLoadIdentity(); + glBegin(GL_QUADS); + glTexCoord2f(tc.x, tc.y); + glVertex2i(pos.x + size.x, pos.y); + glTexCoord2f(0.0f, tc.y); + glVertex2i(pos.x, pos.y); + glTexCoord2f(0.0f, 0.0f); + glVertex2i(pos.x, pos.y + size.y); + glTexCoord2f(tc.x, 0.0f); + glVertex2i(pos.x + size.x, pos.y + size.y); + glEnd(); +} + diff --git a/neercs/video/text-render.h b/neercs/video/text-render.h new file mode 100644 index 0000000..2b2bdd2 --- /dev/null +++ b/neercs/video/text-render.h @@ -0,0 +1,31 @@ +// +// Neercs +// + +#if !defined __TEXT_RENDER_H__ +#define __TEXT_RENDER_H__ + +struct TextRender +{ + TextRender(caca_canvas_t *caca, ivec2 font_size); + void Init(); + void Render(); + void Blit(ivec2 pos, ivec2 size); + +private: + caca_canvas_t *m_caca; + ivec2 m_font_size, m_canvas_size, m_fbo_size; + int m_cells; + + Array<vec2> m_vertices; + TileSet *m_font; + Shader *m_shader; + ShaderAttrib m_coord, m_color, m_char; + ShaderUniform m_texture, m_transform; + VertexDeclaration *m_vdecl; + VertexBuffer *m_vbo1, *m_vbo2, *m_vbo3; + FrameBuffer *m_fbo; +}; + +#endif // __TEXT_RENDER_H__ + diff --git a/neercs/video/text.lolfx b/neercs/video/text.lolfx new file mode 100644 index 0000000..63b5a7b --- /dev/null +++ b/neercs/video/text.lolfx @@ -0,0 +1,55 @@ +-- GLSL.Vert -- + +#version 130 + +attribute vec2 in_Position; +attribute uint in_Char, in_Attr; + +varying vec4 pass_Foreground; +varying vec4 pass_Background; +varying vec2 pass_UV; + +uniform mat4 in_Transform; + +void main() +{ + float u = float(in_Char & 0xfu) / 32.0 + 0.0; + float v = float((in_Char >> 4u) & 0xfu) / 32.0 + 0.5; + pass_UV = vec2(u, v); + + float A = float(in_Attr >> 29u) / 7.0; + float B = float((in_Attr >> 25u) & 0xfu) / 15.0; + float C = float((in_Attr >> 21u) & 0xfu) / 15.0; + float D = float((in_Attr >> 18u) & 0x7u) / 7.0; + + float E = float((in_Attr >> 15u) & 0x7u) / 7.0; + float F = float((in_Attr >> 11u) & 0xfu) / 15.0; + float G = float((in_Attr >> 7u) & 0xfu) / 15.0; + float H = float((in_Attr >> 4u) & 0x7u) / 7.0; + + pass_Background = vec4(B, C, D, 1.0 - A); + pass_Foreground = vec4(F, G, H, 1.0 - E); + + // This only works with glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + //gl_PointSize = 40; + + gl_Position = in_Transform * vec4(in_Position, 0.0, 1.0); +} + +-- GLSL.Frag -- + +#version 130 + +varying vec4 pass_Foreground; +varying vec4 pass_Background; +varying vec2 pass_UV; + +uniform sampler2D in_Texture; + +void main(void) +{ + vec2 c = gl_PointCoord * (1.0 / 32.0) + pass_UV; + float t = texture2D(in_Texture, c).x; + gl_FragColor = mix(pass_Background, pass_Foreground, t); +} +