From 5fc35fb36f6658dc486bf2c5e05510c575f3efec Mon Sep 17 00:00:00 2001 From: Ludovic Pouzenc Date: Thu, 5 Sep 2019 23:09:28 +0200 Subject: Unfinished integration of multi-process approach --- Makefile | 2 +- src/main.c | 362 ++++++++++++++++++++++++++++++++++++++++++---------------- src/main.h | 15 ++- src/scene00.c | 17 ++- src/scene00.h | 4 +- src/scene01.c | 248 +++++++++++++++++++++------------------- src/scene01.h | 4 +- src/scene02.c | 10 +- src/scene02.h | 4 +- 9 files changed, 445 insertions(+), 221 deletions(-) diff --git a/Makefile b/Makefile index 41a09e5..5b0297c 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ server: demoscene-eo demoscene-eo: src/main.c src/main.h $(wildcard src/scene*.[ch]) Makefile pkg-config --libs --cflags $(PKGLIBS) - gcc $(CFLAGS) `pkg-config --libs --cflags $(PKGLIBS)` src/main.c $(wildcard src/scene*.c) -o $@ + gcc $(CFLAGS) `pkg-config --libs --cflags $(PKGLIBS)` src/main.c $(wildcard src/scene*.c) -pthread -o $@ clean: rm -f demoscene-eo diff --git a/src/main.c b/src/main.c index 3f18052..94d6195 100644 --- a/src/main.c +++ b/src/main.c @@ -18,127 +18,178 @@ * along with demoscene-eo. If not, see */ #include "main.h" -#include "scene00.h" -#include "scene01.h" -#include "scene02.h" + +#include // calloc() +#include // bzero() +#include // mmap() +#include // sem_t, sem_init(), Link with -pthread +#include // fork() +#include // wait() +#include // errno +#include // uint32_t +#include // printf() + +#define TRACE(hint) printf("%s(): %s\n", __func__, hint) #define SCENE_COUNT 3 -#define SCENE_NEXT do { scene = (scene+1)%SCENE_COUNT; } while(0) +#define SCENE_NEXT do { shm->scene = (shm->scene+1)%SCENE_COUNT; } while(0) -#define EXPR_MIN_SIZE ( ge.w<80 || ge.h<25 ) +#define EXPR_MIN_SIZE ( shm->ge.w<80 || shm->ge.h<25 ) #define TEXT_MIN_SIZE "80x25" -int main(void) -{ - int done=0, lastscene=-1, scene=0, paused=0, res; - Uint32 sdl_win_flags = SDL_WINDOW_OPENGL; +#define SEM_POST(sem,errcode) \ + do { \ + printf("%s(): sem_post(%s,%i) call\n", __func__, #sem, errcode);\ + if ( sem_post(sem) == -1 ) { return errcode; } \ + printf("%s(): sem_post(%s,%i) done\n", __func__, #sem, errcode);\ + } while(0) + +#define SEM_WAIT(sem,errcode) \ + do { \ + printf("%s(): sem_wait(%s,%i) call\n", __func__, #sem, errcode);\ + while ( sem_wait(&shm->parent_can_read_result) == -1 ) { \ + switch(errno) { \ + case EINTR: \ + case EAGAIN: \ + break; \ + default: \ + return errcode; \ + } \ + } \ + printf("%s(): sem_wait(%s,%i) done\n", __func__, #sem, errcode);\ + } while(0) + +typedef struct { + sem_t worker_gl_can_render, worker_sdl_can_render, parent_can_read_result; + int scene, paused, done; graphical_env_t ge; scene00_env_t s00e; scene01_env_t s01e; scene02_env_t s02e; +} shm_t; - caca_event_t caca_ev; - SDL_RendererInfo renderer_info; - SDL_Event sdl_ev; +int do_fork1(); +int do_fork2(); +int parent(); +int worker_sdl(); +int worker_gl(); - // Initialize libcaca (http://caca.zoy.org/doxygen/libcaca/caca_8h.html) - ge.dp = caca_create_display(NULL); - if(!ge.dp) return 1; - caca_set_display_title(ge.dp, "demoscene-eo"); - caca_set_display_time(ge.dp, 16666); // 1e6µs/60 = 16666.66... It is ~60 fps - ge.cv = caca_get_canvas(ge.dp); +shm_t *shm; - ge.d = caca_create_dither(32, 256, 256, 256*4, 0x00ff0000, 0x0000ff00, 0x000000ff, 0); - if ( !ge.d ) return 2; - caca_set_dither_color(ge.d, "16"); +int main() { + TRACE("call"); + shm = mmap(NULL, sizeof(shm_t), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, 0, 0); + if ( shm == NULL ) return 1; + bzero(shm, sizeof(shm_t)); - // Initialize SDL (http://wiki.libsdl.org/SDL_CreateWindowAndRenderer) - // Useful snippet : https://gist.github.com/koute/7391344 - res = SDL_Init(SDL_INIT_VIDEO); - if ( res == -1) return 3; - SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); - SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 ); - SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 ); - SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 ); - SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 ); - SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 2 ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE ); + if (sem_init(&shm->worker_gl_can_render, 1, 0) < 0) return 2; + if (sem_init(&shm->worker_sdl_can_render, 1, 0) < 0) return 3; + if (sem_init(&shm->parent_can_read_result, 1, 0) < 0) return 4; - //XXX for final version, consider sdl_win_flags |= SDL_WINDOW_HIDDEN; - res = SDL_CreateWindowAndRenderer(256, 256, sdl_win_flags, &ge.sdl_win, &ge.sdl_rndr); - if ( res == -1) return 4; - SDL_SetWindowTitle(ge.sdl_win, "SDL/GL debug"); - res = SDL_GetRendererInfo(ge.sdl_rndr, &renderer_info); - if ( res < 0 ) return 5; - if ( !(renderer_info.flags & SDL_RENDERER_ACCELERATED)) return 6; - if ( !(renderer_info.flags & SDL_RENDERER_TARGETTEXTURE)) return 7; - ge.sdl_target = SDL_CreateTexture(ge.sdl_rndr, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 256, 256); - if ( ge.sdl_target == NULL ) return 9; - ge.raw_target = malloc(256*256*4); - if ( ge.raw_target == NULL ) return 10; + shm->ge.raw_target = calloc(FBUF_W*FBUF_H, sizeof(uint32_t)); + if ( shm->ge.raw_target == NULL ) return 5; - // Initialize OpenGL - ge.gl_ctx = SDL_GL_CreateContext(ge.sdl_win); - if ( ge.gl_ctx == NULL ) return 11; + return do_fork1(); +} - // Main libcaca loop for caca window (OpenGL could be used in sceneN_next()) - ge.framecount=0; +int do_fork1() { + TRACE("call"); + switch (fork()) { + case -1: return 4; break; + case 0: return worker_sdl(); break; + default: return do_fork2(); break; + } +} + +int do_fork2() { + TRACE("call"); + switch (fork()) { + case -1: return 5; break; + case 0: return worker_gl(); break; + default: return parent(); break; + } +} + +int parent() { + int lastscene=-1, res, child_status; + caca_event_t caca_ev; + + TRACE("call"); + + // Initialize libcaca (http://caca.zoy.org/doxygen/libcaca/caca_8h.html) + shm->ge.dp = caca_create_display(NULL); + if(!shm->ge.dp) return 1; + caca_set_display_title(shm->ge.dp, "demoscene-eo"); + caca_set_display_time(shm->ge.dp, 16666); // 1e6µs/60 = 16666.66... It is ~60 fps + shm->ge.cv = caca_get_canvas(shm->ge.dp); + + shm->ge.d = caca_create_dither(32, FBUF_W, FBUF_H, FBUF_W*4, 0x00ff0000, 0x0000ff00, 0x000000ff, 0); + if ( !shm->ge.d ) return 2; + caca_set_dither_color(shm->ge.d, "16"); + + // Main libcaca loop for caca window + shm->ge.framecount=0; do { // Check canvas size at every frame because of unreliable CACA_EVENT_RESIZE - ge.w = caca_get_canvas_width(ge.cv); - ge.h = caca_get_canvas_height(ge.cv); + shm->ge.w = caca_get_canvas_width(shm->ge.cv); + shm->ge.h = caca_get_canvas_height(shm->ge.cv); if ( EXPR_MIN_SIZE ) { - caca_set_color_ansi(ge.cv, CACA_BLACK, CACA_WHITE); - caca_put_str(ge.cv, 0, 0, "Need a minimum of " TEXT_MIN_SIZE " terminal"); - } else if (!paused) { + caca_set_color_ansi(shm->ge.cv, CACA_BLACK, CACA_WHITE); + caca_put_str(shm->ge.cv, 0, 0, "Need a minimum of " TEXT_MIN_SIZE " terminal"); + } else if (!shm->paused) { // init / free if scene transition - if ( lastscene != scene ) { + if ( lastscene != shm->scene ) { switch(lastscene) { - case 0: scene00_free(&ge, &s00e); break; - case 1: scene01_free(&ge, &s01e); break; - case 2: scene02_free(&ge, &s02e); break; + case 0: scene00_free(&shm->ge, &shm->s00e); break; + case 1: scene01_free(&shm->ge, &shm->s01e); break; + case 2: scene02_free(&shm->ge, &shm->s02e); break; } } - while ( lastscene != scene ) { - ge.sdl_ticks = SDL_GetTicks(); - ge.sc_framecount = 0; - switch(scene) { - case 0: res = scene00_init(&ge, &s00e); break; - case 1: res = scene01_init(&ge, &s01e); break; - case 2: res = scene02_init(&ge, &s02e); break; + while ( lastscene != shm->scene ) { + shm->ge.sdl_ticks = SDL_GetTicks(); + shm->ge.sc_framecount = 0; + switch(shm->scene) { + case 0: res = scene00_init(&shm->ge, &shm->s00e); break; + case 1: res = scene01_init(&shm->ge, &shm->s01e); break; + case 2: res = scene02_init(&shm->ge, &shm->s02e); break; } // If scene init fail, skip to the next one - if (res) SCENE_NEXT; else lastscene = scene; + if (res) SCENE_NEXT; else lastscene = shm->scene; } - // Compute current scene0 frame - ge.sdl_ticks = SDL_GetTicks(); // This value wraps if the program runs for more than ~49 days - switch(scene) { - case 0: res = scene00_next(&ge, &s00e); break; - case 1: res = scene01_next(&ge, &s01e); break; - case 2: res = scene02_next(&ge, &s02e); break; + shm->ge.sdl_ticks = SDL_GetTicks(); // This value wraps if the program runs for more than ~49 days + + SEM_POST(&shm->worker_gl_can_render,30); + SEM_WAIT(&shm->parent_can_read_result,31); + + SEM_POST(&shm->worker_sdl_can_render,32); + SEM_WAIT(&shm->parent_can_read_result,33); + + // Compute current scene frame (caca part) + switch(shm->scene) { + case 0: res = scene00_next_caca(&shm->ge, &shm->s00e); break; + case 1: res = scene01_next_caca(&shm->ge, &shm->s01e); break; + case 2: res = scene02_next_caca(&shm->ge, &shm->s02e); break; } if (res) SCENE_NEXT; - ge.framecount++; - ge.sc_framecount++; + shm->ge.framecount++; + shm->ge.sc_framecount++; } // Display it - caca_refresh_display(ge.dp); // Auto framerate limiting (see caca_set_display_time()) + caca_refresh_display(shm->ge.dp); // Auto framerate limiting (see caca_set_display_time()) // Event handling for the libcaca "window" (depending on CACA_DRIVER env variable) - if ( caca_get_event(ge.dp, CACA_EVENT_KEY_PRESS|CACA_EVENT_RESIZE|CACA_EVENT_QUIT, &caca_ev, 0) ) { + if ( caca_get_event(shm->ge.dp, CACA_EVENT_KEY_PRESS|CACA_EVENT_RESIZE|CACA_EVENT_QUIT, &caca_ev, 0) ) { switch(caca_get_event_type(&caca_ev)) { case CACA_EVENT_QUIT: - done = 1; + shm->done = 1; break; case CACA_EVENT_KEY_PRESS: switch(caca_get_event_key_ch(&caca_ev)) { - case 'q': done = 1; break; - case 'p': paused = !paused; break; + case 'q': shm->done = 1; break; + case 'p': shm->paused = !shm->paused; break; case CACA_KEY_ESCAPE: SCENE_NEXT; break; } break; - /* On Debian 10, no CACA_EVENT_RESIZE when using x11 CACA_DRIVER + /* On Debian 10, no CACA_EVENT_RESIZE fired when using x11 CACA_DRIVER case CACA_EVENT_RESIZE: w = caca_get_event_resize_width(&caca_ev); h = caca_get_event_resize_height(&caca_ev); @@ -149,16 +200,68 @@ int main(void) break; } } - // Event handling for the SDL/GL window (debug purposes) + } while(!shm->done); + + caca_free_dither(shm->ge.d); + caca_free_display(shm->ge.dp); + shm->ge.cv=NULL; + + // reap forked processes (order doesn't matter) + if ( wait(&child_status) != -1 ) { + if ( child_status > 0 ) return child_status; + } + if ( wait(&child_status) != -1 ) { + if ( child_status > 0 ) return child_status; + } + return 0; +} + +int worker_sdl() { + int res; + Uint32 sdl_win_flags = 0; //XXX for final version, consider sdl_win_flags = SDL_WINDOW_HIDDEN; + SDL_RendererInfo renderer_info; + SDL_Event sdl_ev; + + TRACE("call"); + + // Initialize SDL (http://wiki.libsdl.org/SDL_CreateWindowAndRenderer) + // Useful snippet : https://gist.github.com/koute/7391344 + res = SDL_Init(SDL_INIT_VIDEO); + if ( res == -1) return 3; + atexit(SDL_Quit); + + res = SDL_CreateWindowAndRenderer(FBUF_W, FBUF_H, sdl_win_flags, &shm->ge.sdl_win, &shm->ge.sdl_rndr); + if ( res == -1) return 4; + SDL_SetWindowTitle(shm->ge.sdl_win, "SDL debug"); + res = SDL_GetRendererInfo(shm->ge.sdl_rndr, &renderer_info); + if ( res < 0 ) return 5; + if ( !(renderer_info.flags & SDL_RENDERER_ACCELERATED)) return 6; + if ( !(renderer_info.flags & SDL_RENDERER_TARGETTEXTURE)) return 7; + shm->ge.sdl_target = SDL_CreateTexture(shm->ge.sdl_rndr, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, FBUF_W, FBUF_H); + if ( shm->ge.sdl_target == NULL ) return 9; + + while ( !shm->done ) { + //FIXME change for TRYWAIT for event handling (+delay) + SEM_WAIT(&shm->worker_sdl_can_render,20); + + // Compute current scene frame (sdl part) + switch(shm->scene) { + case 0: res = scene00_next_sdl(&shm->ge, &shm->s00e); break; + case 1: res = scene01_next_sdl(&shm->ge, &shm->s01e); break; + case 2: res = scene02_next_sdl(&shm->ge, &shm->s02e); break; + } + if (res) SCENE_NEXT; + + // Event handling for the SDL window (debug purposes) while(SDL_PollEvent(&sdl_ev)) { switch(sdl_ev.type) { case SDL_QUIT: - done = 1; + shm->done = 1; break; case SDL_KEYDOWN: switch(sdl_ev.key.keysym.sym) { - case SDLK_q: done = 1; break; - case SDLK_p: paused = !paused; break; + case SDLK_q: shm->done = 1; break; + case SDLK_p: shm->paused = !shm->paused; break; case SDLK_ESCAPE: SCENE_NEXT; break; } break; @@ -166,15 +269,82 @@ int main(void) break; } } - } while(!done); - - caca_free_dither(ge.d); - caca_free_display(ge.dp); - ge.cv=NULL; - SDL_GL_DeleteContext(ge.gl_ctx); - SDL_DestroyTexture(ge.sdl_target); - SDL_DestroyRenderer(ge.sdl_rndr); - SDL_DestroyWindow(ge.sdl_win); - SDL_Quit(); + + SEM_POST(&shm->parent_can_read_result, 21); + } + + SDL_DestroyRenderer(shm->ge.sdl_rndr); + SDL_DestroyTexture(shm->ge.sdl_target); + SDL_DestroyWindow(shm->ge.sdl_win); + + return 0; +} + +int worker_gl() { + int res; + //Uint32 sdl_win_flags = SDL_WINDOW_OPENGL; + SDL_Event gl_ev; + + TRACE("call"); + + // Initialize SDL (http://wiki.libsdl.org/SDL_CreateWindowAndRenderer) + // Useful snippet : https://gist.github.com/koute/7391344 + res = SDL_Init(SDL_INIT_VIDEO); + if ( res == -1) return 3; + atexit(SDL_Quit); + + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); + SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 ); + SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 ); + SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 ); + SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 ); + SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 2 ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE ); + + // Initialize OpenGL + shm->ge.gl_win = SDL_CreateWindow("GL Debug", 0, SDL_WINDOWPOS_CENTERED, FBUF_W, FBUF_H, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN ); + shm->ge.gl_ctx = SDL_GL_CreateContext(shm->ge.gl_win); + if ( shm->ge.gl_ctx == NULL ) return 11; + + while ( !shm->done ) { + //FIXME change for TRYWAIT for event handling (+delay) + SEM_WAIT(&shm->worker_gl_can_render,10); + + // Compute current scene frame (gl part) + switch(shm->scene) { + case 0: res = scene00_next_gl(&shm->ge, &shm->s00e); break; + case 1: res = scene01_next_gl(&shm->ge, &shm->s01e); break; + case 2: res = scene02_next_gl(&shm->ge, &shm->s02e); break; + } + if (res) SCENE_NEXT; + + + // Event handling for the GL window (debug purposes) + while(SDL_PollEvent(&gl_ev)) { + switch(gl_ev.type) { + case SDL_QUIT: + shm->done = 1; + break; + case SDL_KEYDOWN: + switch(gl_ev.key.keysym.sym) { + case SDLK_q: shm->done = 1; break; + case SDLK_p: shm->paused = !shm->paused; break; + case SDLK_ESCAPE: SCENE_NEXT; break; + } + break; + default: + break; + } + } + + SEM_POST(&shm->parent_can_read_result, 11); + } + + //SDL_DestroyTexture(shm->ge.gl_target); + SDL_GL_DeleteContext(shm->ge.gl_ctx); + SDL_DestroyWindow(shm->ge.gl_win); + return 0; } diff --git a/src/main.h b/src/main.h index 1ff41ec..907bc53 100644 --- a/src/main.h +++ b/src/main.h @@ -9,17 +9,30 @@ #include typedef struct { + // libcaca caca_display_t *dp; caca_canvas_t *cv; caca_dither_t *d; int w, h; // caca terminal size in characters + // SDL worker SDL_Window* sdl_win; SDL_Renderer *sdl_rndr; SDL_Texture *sdl_target; - void *raw_target; + // OpenGL worker + SDL_Window* gl_win; SDL_GLContext gl_ctx; + // framebuffer to inject OpenGL or SDL result in caca canvas + uint32_t *raw_target; + // Timing Uint32 sdl_ticks; Uint32 framecount; Uint32 sc_framecount; } graphical_env_t; + +#define FBUF_W 256 +#define FBUF_H 256 + +#include "scene00.h" +#include "scene01.h" +#include "scene02.h" #endif diff --git a/src/scene00.c b/src/scene00.c index 746db29..7bb1738 100644 --- a/src/scene00.c +++ b/src/scene00.c @@ -31,11 +31,14 @@ void scene00_free(graphical_env_t *ge, scene00_env_t *se) { SDL_DestroyTexture(se->eo1); se->eo1=NULL; } -int scene00_next(graphical_env_t *ge, scene00_env_t *se) { +int scene00_next_gl(graphical_env_t *ge, scene00_env_t *se) { + return 0; +} + +int scene00_next_sdl(graphical_env_t *ge, scene00_env_t *se) { // Shorthands caca_canvas_t *cv = ge->cv; int w = ge->w, h = ge->h; - Uint32 frame = ge->sc_framecount; SDL_Renderer *r = ge->sdl_rndr; // Local vars int res; @@ -54,11 +57,21 @@ int scene00_next(graphical_env_t *ge, scene00_env_t *se) { SDL_RenderPresent(r); // Download the rendered texture from videocard to main memory + SDL_SetRenderTarget(r, ge->sdl_target); res = SDL_RenderReadPixels(r, NULL, 0, ge->raw_target, 256*4); // "convert" the raw pixel stream to ASCII art on caca canevas if ( res == 0 ) caca_dither_bitmap(cv, 0, 0, w, h, ge->d, ge->raw_target); + return 0; +} + +int scene00_next_caca(graphical_env_t *ge, scene00_env_t *se) { + // Shorthands + caca_canvas_t *cv = ge->cv; + int w = ge->w, h = ge->h; + Uint32 frame = ge->sc_framecount; + // Add things on top of caca canvas caca_set_color_ansi(cv, CACA_BLACK, CACA_WHITE); caca_put_str(cv, (w-17)/2, h/2, "This is a message"); diff --git a/src/scene00.h b/src/scene00.h index b1c9d9d..ec6eb9a 100644 --- a/src/scene00.h +++ b/src/scene00.h @@ -8,5 +8,7 @@ typedef struct { int scene00_init(graphical_env_t *ge, scene00_env_t *se); void scene00_free(graphical_env_t *ge, scene00_env_t *se); -int scene00_next(graphical_env_t *ge, scene00_env_t *se); +int scene00_next_gl(graphical_env_t *ge, scene00_env_t *se); +int scene00_next_sdl(graphical_env_t *ge, scene00_env_t *se); +int scene00_next_caca(graphical_env_t *ge, scene00_env_t *se); #endif diff --git a/src/scene01.c b/src/scene01.c index 80cbae2..b817e71 100644 --- a/src/scene01.c +++ b/src/scene01.c @@ -24,130 +24,129 @@ typedef float t_mat4x4[16]; static inline void mat4x4_ortho( t_mat4x4 out, float left, float right, float bottom, float top, float znear, float zfar ) { - #define T(a, b) (a * 4 + b) + #define T(a, b) (a * 4 + b) - out[T(0,0)] = 2.0f / (right - left); - out[T(0,1)] = 0.0f; - out[T(0,2)] = 0.0f; - out[T(0,3)] = 0.0f; + out[T(0,0)] = 2.0f / (right - left); + out[T(0,1)] = 0.0f; + out[T(0,2)] = 0.0f; + out[T(0,3)] = 0.0f; - out[T(1,1)] = 2.0f / (top - bottom); - out[T(1,0)] = 0.0f; - out[T(1,2)] = 0.0f; - out[T(1,3)] = 0.0f; + out[T(1,1)] = 2.0f / (top - bottom); + out[T(1,0)] = 0.0f; + out[T(1,2)] = 0.0f; + out[T(1,3)] = 0.0f; - out[T(2,2)] = -2.0f / (zfar - znear); - out[T(2,0)] = 0.0f; - out[T(2,1)] = 0.0f; - out[T(2,3)] = 0.0f; + out[T(2,2)] = -2.0f / (zfar - znear); + out[T(2,0)] = 0.0f; + out[T(2,1)] = 0.0f; + out[T(2,3)] = 0.0f; - out[T(3,0)] = -(right + left) / (right - left); - out[T(3,1)] = -(top + bottom) / (top - bottom); - out[T(3,2)] = -(zfar + znear) / (zfar - znear); - out[T(3,3)] = 1.0f; + out[T(3,0)] = -(right + left) / (right - left); + out[T(3,1)] = -(top + bottom) / (top - bottom); + out[T(3,2)] = -(zfar + znear) / (zfar - znear); + out[T(3,3)] = 1.0f; - #undef T + #undef T } static const char * vertex_shader = - "#version 130\n" - "in vec2 i_position;\n" - "in vec4 i_color;\n" - "out vec4 v_color;\n" - "uniform mat4 u_projection_matrix;\n" - "void main() {\n" - " v_color = i_color;\n" - " gl_Position = u_projection_matrix * vec4( i_position, 0.0, 1.0 );\n" - "}\n"; + "#version 130\n" + "in vec2 i_position;\n" + "in vec4 i_color;\n" + "out vec4 v_color;\n" + "uniform mat4 u_projection_matrix;\n" + "void main() {\n" + " v_color = i_color;\n" + " gl_Position = u_projection_matrix * vec4( i_position, 0.0, 1.0 );\n" + "}\n"; static const char * fragment_shader = - "#version 130\n" - "in vec4 v_color;\n" - "out vec4 o_color;\n" - "void main() {\n" - " o_color = v_color;\n" - "}\n"; + "#version 130\n" + "in vec4 v_color;\n" + "out vec4 o_color;\n" + "void main() {\n" + " o_color = v_color;\n" + "}\n"; typedef enum t_attrib_id { - attrib_position, - attrib_color + attrib_position, + attrib_color } t_attrib_id; int scene01_init(graphical_env_t *ge, scene01_env_t *se) { - int width = 256, height = 256; - GLuint vs, fs, program; - - vs = glCreateShader( GL_VERTEX_SHADER ); - fs = glCreateShader( GL_FRAGMENT_SHADER ); - - int length = strlen( vertex_shader ); - glShaderSource( vs, 1, ( const GLchar ** )&vertex_shader, &length ); - glCompileShader( vs ); - - GLint status; - glGetShaderiv( vs, GL_COMPILE_STATUS, &status ); - if( status == GL_FALSE ) - { - fprintf( stderr, "vertex shader compilation failed\n" ); - return 1; - } - - length = strlen( fragment_shader ); - glShaderSource( fs, 1, ( const GLchar ** )&fragment_shader, &length ); - glCompileShader( fs ); - - glGetShaderiv( fs, GL_COMPILE_STATUS, &status ); - if( status == GL_FALSE ) - { - fprintf( stderr, "fragment shader compilation failed\n" ); - return 1; - } - - program = glCreateProgram(); - glAttachShader( program, vs ); - glAttachShader( program, fs ); - - glBindAttribLocation( program, attrib_position, "i_position" ); - glBindAttribLocation( program, attrib_color, "i_color" ); - glLinkProgram( program ); - - glUseProgram( program ); - - glDisable( GL_DEPTH_TEST ); - //glClearColor( 0.5, 0.0, 0.0, 0.0 ); - glClearColor( 0.5, 0.5, 0.0, 0.0 ); - glViewport( 0, 0, width, height ); - - GLuint vbo; - - glGenVertexArrays( 1, &(se->vao) ); - glGenBuffers( 1, &vbo ); - glBindVertexArray( se->vao ); - glBindBuffer( GL_ARRAY_BUFFER, vbo ); - - glEnableVertexAttribArray( attrib_position ); - glEnableVertexAttribArray( attrib_color ); - - glVertexAttribPointer( attrib_color, 4, GL_FLOAT, GL_FALSE, sizeof( float ) * 6, 0 ); - glVertexAttribPointer( attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof( float ) * 6, ( void * )(4 * sizeof(float)) ); - - const GLfloat g_vertex_buffer_data[] = { - /* R, G, B, A, X, Y */ - 1, 0, 0, 1, 0, 0, - 0, 1, 0, 1, width, 0, - 0, 0, 1, 1, width, height, - - 1, 0, 0, 1, 0, 0, - 0, 0, 1, 1, width, height, - 1, 1, 1, 1, 0, height - }; - - glBufferData( GL_ARRAY_BUFFER, sizeof( g_vertex_buffer_data ), g_vertex_buffer_data, GL_STATIC_DRAW ); - - t_mat4x4 projection_matrix; - mat4x4_ortho( projection_matrix, 0.0f, (float)width, (float)height, 0.0f, 0.0f, 100.0f ); - glUniformMatrix4fv( glGetUniformLocation( program, "u_projection_matrix" ), 1, GL_FALSE, projection_matrix ); + GLuint vs, fs, program; + + vs = glCreateShader( GL_VERTEX_SHADER ); + fs = glCreateShader( GL_FRAGMENT_SHADER ); + + int length = strlen( vertex_shader ); + glShaderSource( vs, 1, ( const GLchar ** )&vertex_shader, &length ); + glCompileShader( vs ); + + GLint status; + glGetShaderiv( vs, GL_COMPILE_STATUS, &status ); + if( status == GL_FALSE ) + { + fprintf( stderr, "vertex shader compilation failed\n" ); + return 1; + } + + length = strlen( fragment_shader ); + glShaderSource( fs, 1, ( const GLchar ** )&fragment_shader, &length ); + glCompileShader( fs ); + + glGetShaderiv( fs, GL_COMPILE_STATUS, &status ); + if( status == GL_FALSE ) + { + fprintf( stderr, "fragment shader compilation failed\n" ); + return 1; + } + + program = glCreateProgram(); + glAttachShader( program, vs ); + glAttachShader( program, fs ); + + glBindAttribLocation( program, attrib_position, "i_position" ); + glBindAttribLocation( program, attrib_color, "i_color" ); + glLinkProgram( program ); + + glUseProgram( program ); + + glDisable( GL_DEPTH_TEST ); + //glClearColor( 0.5, 0.0, 0.0, 0.0 ); + glClearColor( 0.5, 0.5, 0.0, 0.0 ); + glViewport( 0, 0, FBUF_W, FBUF_H ); + + GLuint vbo; + + glGenVertexArrays( 1, &(se->vao) ); + glGenBuffers( 1, &vbo ); + glBindVertexArray( se->vao ); + glBindBuffer( GL_ARRAY_BUFFER, vbo ); + + glEnableVertexAttribArray( attrib_position ); + glEnableVertexAttribArray( attrib_color ); + + glVertexAttribPointer( attrib_color, 4, GL_FLOAT, GL_FALSE, sizeof( float ) * 6, 0 ); + glVertexAttribPointer( attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof( float ) * 6, ( void * )(4 * sizeof(float)) ); + + const GLfloat g_vertex_buffer_data[] = { + /* R, G, B, A, X, Y */ + 1, 0, 0, 1, 0, 0, + 0, 1, 0, 1, FBUF_W, 0, + 0, 0, 1, 1, FBUF_W, FBUF_H, + + 1, 0, 0, 1, 0, 0, + 0, 0, 1, 1, FBUF_W, FBUF_H, + 1, 1, 1, 1, 0, FBUF_H + }; + + glBufferData( GL_ARRAY_BUFFER, sizeof( g_vertex_buffer_data ), g_vertex_buffer_data, GL_STATIC_DRAW ); + + t_mat4x4 projection_matrix; + mat4x4_ortho( projection_matrix, 0.0f, (float)FBUF_W, (float)FBUF_H, 0.0f, 0.0f, 100.0f ); + glUniformMatrix4fv( glGetUniformLocation( program, "u_projection_matrix" ), 1, GL_FALSE, projection_matrix ); return 0; } @@ -155,35 +154,50 @@ void scene01_free(graphical_env_t *ge, scene01_env_t *se) { //FIXME scene00 cannot be rendered coorectly after scene01_init done once } -int scene01_next(graphical_env_t *ge, scene01_env_t *se) { +int scene01_next_gl(graphical_env_t *ge, scene01_env_t *se) { // Shorthands caca_canvas_t *cv = ge->cv; int w = ge->w, h = ge->h; - Uint32 frame = ge->sc_framecount; SDL_Renderer *r = ge->sdl_rndr; - // Locals + // Local vars int res; + // https://gist.github.com/Twinklebear/8265888 + // https://forums.libsdl.org/viewtopic.php?p=51634 + // Render all the stuff on target texture - //SDL_SetRenderTarget(r, ge->sdl_target); + SDL_SetRenderTarget(r, ge->sdl_target); glClear( GL_COLOR_BUFFER_BIT ); glBindVertexArray( se->vao ); glDrawArrays( GL_TRIANGLES, 0, 6 ); - SDL_GL_SwapWindow( ge->sdl_win ); // Copy the SDL screen to SDL debug window (and display it, not mandatory) - //SDL_SetRenderTarget(r, NULL); - //SDL_RenderCopy(r, ge->sdl_target, NULL, NULL); - //SDL_RenderPresent(r); + SDL_SetRenderTarget(r, NULL); + SDL_RenderCopy(r, ge->sdl_target, NULL, NULL); + SDL_RenderPresent(r); // Download the rendered texture from videocard to main memory + SDL_SetRenderTarget(r, ge->sdl_target); res = SDL_RenderReadPixels(r, NULL, 0, ge->raw_target, 256*4); // "convert" the raw pixel stream to ASCII art on caca canevas - caca_set_dither_gamma(ge->d, (100-frame%100)/100.0); + caca_set_dither_gamma(ge->d, 1.0); if ( res == 0 ) caca_dither_bitmap(cv, 0, 0, w, h, ge->d, ge->raw_target); + return 0; +} + +int scene01_next_sdl(graphical_env_t *ge, scene01_env_t *se) { + return 0; +} + +int scene01_next_caca(graphical_env_t *ge, scene01_env_t *se) { + // Shorthands + caca_canvas_t *cv = ge->cv; + int w = ge->w, h = ge->h; + Uint32 frame = ge->sc_framecount; + caca_set_color_ansi(cv, CACA_WHITE, CACA_BLACK); caca_put_str(cv, (w-17)/2, h/2, "This is a message"); diff --git a/src/scene01.h b/src/scene01.h index ecad8df..f6544fb 100644 --- a/src/scene01.h +++ b/src/scene01.h @@ -8,5 +8,7 @@ typedef struct { int scene01_init(graphical_env_t *ge, scene01_env_t *se); void scene01_free(graphical_env_t *ge, scene01_env_t *se); -int scene01_next(graphical_env_t *ge, scene01_env_t *se); +int scene01_next_gl(graphical_env_t *ge, scene01_env_t *se); +int scene01_next_sdl(graphical_env_t *ge, scene01_env_t *se); +int scene01_next_caca(graphical_env_t *ge, scene01_env_t *se); #endif diff --git a/src/scene02.c b/src/scene02.c index 1989bf0..e8e7340 100644 --- a/src/scene02.c +++ b/src/scene02.c @@ -26,7 +26,15 @@ int scene02_init(graphical_env_t *ge, scene02_env_t *se) { void scene02_free(graphical_env_t *ge, scene02_env_t *se) { } -int scene02_next(graphical_env_t *ge, scene02_env_t *se) { +int scene02_next_gl(graphical_env_t *ge, scene02_env_t *se) { + return 0; +} + +int scene02_next_sdl(graphical_env_t *ge, scene02_env_t *se) { + return 0; +} + +int scene02_next_caca(graphical_env_t *ge, scene02_env_t *se) { // Shorthands caca_canvas_t *cv = ge->cv; //int w = ge->w, h = ge->h; diff --git a/src/scene02.h b/src/scene02.h index 49abbfb..7032d50 100644 --- a/src/scene02.h +++ b/src/scene02.h @@ -8,5 +8,7 @@ typedef struct { int scene02_init(graphical_env_t *ge, scene02_env_t *se); void scene02_free(graphical_env_t *ge, scene02_env_t *se); -int scene02_next(graphical_env_t *ge, scene02_env_t *se); +int scene02_next_gl(graphical_env_t *ge, scene02_env_t *se); +int scene02_next_sdl(graphical_env_t *ge, scene02_env_t *se); +int scene02_next_caca(graphical_env_t *ge, scene02_env_t *se); #endif -- cgit v1.2.3