Edit

kc3-lang/kc3/window/demo/toasters.c

Branch :

  • window/demo/toasters.c
  • /* kc3
     * Copyright from 2022 to 2025 kmx.io <contact@kmx.io>
     *
     * Permission is hereby granted to use this software granted the above
     * copyright notice and this permission paragraph are included in all
     * copies and substantial portions of this software.
     *
     * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
     * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
     * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
     * THIS SOFTWARE.
     */
    #include <math.h>
    #include "../../libkc3/kc3.h"
    #include "../../gl/gl.h"
    #include "toasters.h"
    #include "demo.h"
    
    #define TOASTERS_SCALE_TOAST   0.52
    #define TOASTERS_SCALE_TOASTER 0.4
    #define TOASTERS_SPACING \
      (g_sprite_toaster.pt_h * TOASTERS_SCALE_TOASTER * 2.0)
    
    static const f64 g_speed_x =  80.0;
    static const f64 g_speed_y = -40.0;
    s_gl_sprite    g_sprite_toast = {0};
    s_gl_sprite    g_sprite_toaster = {0};
    
    static u8 toasters_render_toasters (s_list **toasters,
                                        s_window *window,
                                        s_sequence *seq);
    static u8 toasters_render_toasts (s_list **toasts,
                                      s_window *window,
                                      s_sequence *seq);
    
    static s_tag * toast_init (s_tag *toast, f64 x, f64 y)
    {
      tag_init_map(toast, 2);
      tag_init_psym(toast->data.map.key   + 0, sym_1("x"));
      tag_init_f64(toast->data.map.value + 0, x);
      tag_init_psym(toast->data.map.key   + 1, sym_1("y"));
      tag_init_f64(toast->data.map.value + 1, y);
      return toast;
    }
    
    
    static void toast_render (s_tag *toast, s_window *window,
                              s_sequence *seq)
    {
      s_mat4 matrix;
      GLuint texture;
      f64 *x;
      f64 *y;
      if (toast->type == TAG_MAP) {
        x = &toast->data.map.value[0].data.f64;
        y = &toast->data.map.value[1].data.f64;
        *x -= seq->dt * g_speed_x;
        *y -= seq->dt * g_speed_y;
        if (*x < -100 || *y > window->h) {
          tag_clean(toast);
          toast->type = TAG_VOID;
          return;
        }
        matrix = g_ortho.model_matrix; {
          mat4_translate(&g_ortho.model_matrix, *x,
                                 *y + g_sprite_toast.pt_h, 0.0);
          mat4_scale(&g_ortho.model_matrix,
                             TOASTERS_SCALE_TOAST,
                             -TOASTERS_SCALE_TOAST, 1);
          gl_ortho_update_model_matrix(&g_ortho);
          texture = gl_sprite_texture(&g_sprite_toast, 0);
          gl_ortho_bind_texture(&g_ortho, texture);
          gl_ortho_rect(&g_ortho, 0, 0, g_sprite_toast.pt_w,
                        g_sprite_toast.pt_h);
        } g_ortho.model_matrix = matrix;
      }
    }
    
    static s_tag * toaster_init (s_tag *toaster, f64 y)
    {
      tag_init_map(toaster, 2);
      tag_init_psym(toaster->data.map.key + 0, sym_1("x"));
      tag_init_f64(toaster->data.map.value + 0, -150);
      tag_init_psym(toaster->data.map.key + 1, sym_1("y"));
      tag_init_f64(toaster->data.map.value + 1, y);
      return toaster;
    }
    
    static void toaster_render (s_tag *toaster, s_window *window,
                                s_sequence *seq)
    {
      s_mat4 matrix;
      GLuint texture;
      f64 *x;
      f64 *y;
      if (toaster->type == TAG_MAP) {
        x = &toaster->data.map.value[0].data.f64;
        y = &toaster->data.map.value[1].data.f64;
        *x += seq->dt * g_speed_x;
        *y += seq->dt * g_speed_y;
        if (*x > window->w || *y < -300) {
          tag_clean(toaster);
          toaster->type = TAG_VOID;
          return;
        }
        matrix = g_ortho.model_matrix;
        mat4_translate(&g_ortho.model_matrix, *x,
                               *y + g_sprite_toaster.pt_h, 0.0);
        mat4_scale(&g_ortho.model_matrix,
                           TOASTERS_SCALE_TOASTER,
                           -TOASTERS_SCALE_TOASTER, 1);
        gl_ortho_update_model_matrix(&g_ortho);
        texture = gl_sprite_texture(&g_sprite_toaster,
                                    fmod(seq->t *
                                         g_sprite_toaster.frame_count,
                                         g_sprite_toaster.frame_count));
        gl_ortho_bind_texture(&g_ortho, texture);
        gl_ortho_rect(&g_ortho, 0, 0, g_sprite_toaster.pt_w,
                      g_sprite_toaster.pt_h);
        g_ortho.model_matrix = matrix;
      }
    }
    
    u8 toasters_load (s_sequence *seq)
    {
      s_map *map;
      tag_map(&seq->tag, 2);
      map = &seq->tag.data.map;
      tag_init_psym(   map->key + 0, sym_1("toasters"));
      tag_init_plist(map->value + 0, NULL);
      tag_init_psym(   map->key + 1, sym_1("toasts"));
      tag_init_plist(map->value + 1, NULL);
      return true;
    }
    
    u8 toasters_render (s_sequence *seq)
    {
      s_list **toasters;
      s_list **toasts;
      s_window *window;
      assert(seq);
      window = seq->window;
      assert(window);
      glClearColor(0.7f, 0.95f, 1.0f, 1.0f);
      glClear(GL_COLOR_BUFFER_BIT);
      gl_ortho_render(&g_ortho);
      mat4_init_identity(&g_ortho.model_matrix);
      mat4_translate(&g_ortho.model_matrix, 0, window->h, 0);
      mat4_scale(&g_ortho.model_matrix, 1, -1, 1);
      /* io_inspect(&seq->tag); */
      if (seq->tag.type == TAG_MAP) {
        toasters = &seq->tag.data.map.value[0].data.plist;
        toasts   = &seq->tag.data.map.value[1].data.plist;
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                        GL_LINEAR_MIPMAP_LINEAR);
        toasters_render_toasts(toasts, window, seq);
        toasters_render_toasters(toasters, window, seq);
      }
      gl_ortho_render_end(&g_ortho);
      return true;
    }
    
    u8 toasters_render_toasts (s_list **toasts, s_window *window,
                                 s_sequence *seq)
    {
      s_list *i;
      s_list *j;
      s_map *map;
      s_list **t = NULL;
      f64 x;
      f64 y;
      assert(toasts);
      assert(window);
      assert(seq);
      y = window->w * g_speed_y / g_speed_x -
        TOASTERS_SPACING * 3.0 / 2.0 +
        50;
      if (*toasts && (*toasts)->tag.type == TAG_MAP) {
        t = &(*toasts)->tag.data.map.value[0].data.plist;
        y =  (*toasts)->tag.data.map.value[1].data.f64;
      }
      while (y < window->h - TOASTERS_SPACING / 2) {
        y += TOASTERS_SPACING;
        *toasts = list_new_map(2, *toasts);
        map = &(*toasts)->tag.data.map;
        tag_init_psym( map->key   + 0, sym_1("toasts"));
        tag_init_plist(map->value + 0, NULL);
        tag_init_psym( map->key   + 1, sym_1("y"));
        tag_init_f64(  map->value + 1, y);
      }
      i = *toasts;
      while (i) {
        if (i->tag.type == TAG_MAP) {
          t = &i->tag.data.map.value[0].data.plist;
          y =  i->tag.data.map.value[1].data.f64;
          x = 0.0;
          if (*t && (*t)->tag.type == TAG_MAP)
            x = (*t)->tag.data.map.value[0].data.f64;
          if (x < window->w - 160.0) {
            *t = list_new(*t);
            toast_init(&(*t)->tag, window->w, y);
          }
          plist_remove_void(t);
          j = *t;
          while (j) {
            toast_render(&j->tag, window, seq);
            j = list_next(j);
          }
        }
        i = list_next(i);
      }
      return true;
    }
    
    u8 toasters_render_toasters (s_list **toasters, s_window *window,
                                   s_sequence *seq)
    {
      s_list *i;
      s_list *j;
      s_map *map;
      s_list **t = NULL;
      f64 x;
      f64 y;
      assert(toasters);
      assert(window);
      assert(seq);
      /* io_inspect_list((const s_list **) toasters); */
      y = -TOASTERS_SPACING - 40;
      if (*toasters && (*toasters)->tag.type == TAG_MAP) {
        t = &(*toasters)->tag.data.map.value[0].data.plist;
        y =  (*toasters)->tag.data.map.value[1].data.f64;
      }
      while (y < window->h - window->w * g_speed_y / g_speed_x +
             TOASTERS_SPACING) {
        y += TOASTERS_SPACING;
        *toasters = list_new_map(2, *toasters);
        map = &(*toasters)->tag.data.map;
        tag_init_psym( map->key   + 0, sym_1("toasters"));
        tag_init_plist(map->value + 0, NULL);
        tag_init_psym( map->key   + 1, sym_1("y"));
        tag_init_f64(  map->value + 1, y);
      }
      i = *toasters;
      while (i) {
        if (i->tag.type == TAG_MAP) {
          t = &i->tag.data.map.value[0].data.plist;
          y =  i->tag.data.map.value[1].data.f64;
          x = 1000.0;
          if (*t && (*t)->tag.type == TAG_MAP)
            x = (*t)->tag.data.map.value[0].data.f64;
          if (x > 60.0) {
            *t = list_new(*t);
            toaster_init(&(*t)->tag, y);
          }
          plist_remove_void(t);
          j = *t;
          while (j) {
            toaster_render(&j->tag, window, seq);
            j = list_next(j);
          }
        }
        i = list_next(i);
      }
      return true;
    }
    
    u8 toasters_unload (s_sequence *seq)
    {
      (void) seq;
      return true;
    }