#+TITLE: sdl2 org src
#+AUTHOR: screwtape
* Rich media sdl2 C applications
(skip past window settings in your reading; they are just better at the top)
** Various updates
   Now has odd inline
   | SDL_HasIntersection(SDL_Rect *, SDL_Rect *)                             |
   | SDL_IntersectRectAndLine(SDL_Rect *, int *x0, int *y0, int *x1, int *y1 |
   | Array of SDL_Rect rocks being used somehow                              |
   Note that SDL_IntersectRectAndLine clobbers intersected endpoint int *s.
   both intersections should be compared with SDL_TRUE / SDL_FALSE.
** Window settings
#+NAME: w-sizing
#+HEADER: :includes "/usr/local/include/SDL2/SDL.h"
#+begin_src C
SDL_WINDOW_RESIZABLE
#+end_src

#+NAME: w-height
#+begin_src C
768
#+end_src

#+NAME: w-width
#+begin_src C
1280
#+end_src

** template
#+BEGIN_EXAMPLE
  This template does seem a little bit  goto cleanup rather than some clunky
  long, but that is because it handles  quit flag;  but then,  it was easier
  keyboard  and mouse events and mouse  to goto quit which gotos cleanup. At
  position  in the general case.  I do  least the loop isn't goto based!
#+END_EXAMPLE
includes and libs might need to be customized. I found that  my  sdl2-config
flags on arm64 openbsd didn't actually work!
#+name: template
#+HEADER: :includes "/usr/local/include/SDL2/SDL.h" <stdlib.h>
#+HEADER: :libs "-L/usr/local/lib -lSDL2"
#+HEADER: :exports code
#+HEADER: :results none
#+HEADER: :noweb yes
#+begin_src C

  <<hero-init>>

  /* random */
  int ra, rb;
  time_t rt;
  srand((unsigned)time(&rt));
  /* /rand */

  /* Some rocks */
  int NROCKS = 2;
  int r;

  struct SDL_Rect rocks[NROCKS];
  rocks[0].x = 100; rocks[0].y = 120;
  rocks[0].w = 50; rocks[0].h = 40;

  rocks[1].x = 200; rocks[1].y = 220;
  rocks[1].w = 50; rocks[1].h = 40;



  /* Sort of clock */
  int cycle_limit = 10000;
  int cycle_now = 0;


  /* spinning animation */
  int ticks = 0;
  int tox, toy, centerx, centery;
  float xoff=0.0, yoff=0.0, l;

  int hitx, hity, hitcx, hitcy;

  centerx = 635; centery = 384; l = 100.0;
  /*/spinning animation */

  <<sdlstart>>

  for(;;){
    while(SDL_PollEvent(&e))
      if (e.type == SDL_QUIT)
      quit:
	goto cleanup;
      else if (e.type == SDL_MOUSEBUTTONDOWN)
	switch (1){
	default:
	  break;
	}
      else if (e.type == SDL_MOUSEBUTTONUP)
	switch (1){
	default:
	  break;
	}
      else if (e.type == SDL_KEYDOWN)
	switch (e.key.keysym.sym){
	case SDLK_UP:
	  if (hero.alive == 1)
	    hero.rect.y -= 10;
	  for (r=0;r<NROCKS; r++)
	    if (SDL_TRUE == SDL_HasIntersection(&(hero.rect),&(rocks[r])))
	      hero.rect.y += 10;
	  break;
	case SDLK_RIGHT:
	  if (hero.alive == 1)
	    hero.rect.x += 10;
	  break;
	case SDLK_DOWN:
	  if (hero.alive == 1)
	    hero.rect.y += 10;
	  break;  
	case SDLK_LEFT:
	  if (hero.alive == 1)
	    hero.rect.x -= 10;
	  break;
	case SDLK_r:
	  hero.rect.x = rand() % 1000;
	  hero.rect.y = rand() % 500;
	  hero.alive = 1;
	  break;
	case SDLK_q:
	  goto quit;
	default:
	  break;
	}
      else if (e.type == SDL_KEYUP)
	switch (1){
	default:
	  break;
	}

    mdown = SDL_GetMouseState(&mx, &my);

    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);      
    SDL_RenderClear(renderer);

    <<hero-update>>

	SDL_SetRenderDrawColor(renderer, 100, 200, 200, 255);


    /* spinning animation */
    ticks++;

    xoff= l * SDL_sin((float)ticks / (2.0 * M_PI));
    tox = centerx + (int)xoff;
    yoff= l * SDL_cos((float)ticks / (2.0 * M_PI));
    toy = centery + (int)yoff;

    SDL_RenderDrawLine(renderer, centerx, centery, tox, toy);
    /*/spinning animation */

    /* Potentially kill hero */
    hitcx = centerx; hitcy = centery;
    hitx = tox; hity = toy;
    if (hero.alive== 1 &&
	SDL_IntersectRectAndLine(&(hero.rect),
				 &hitcx, &hitcy,
				 &hitx, &hity)
	== SDL_TRUE)
      hero.alive=0;
    /* Potentially killed hero */

  /* Draw rocks */
    SDL_SetRenderDrawColor(renderer, 50, 50, 50, 255);
  for (r=0; r<NROCKS; r++)
    SDL_RenderFillRect(renderer, &rocks[r]);
  /* Drawn rocks */


    SDL_RenderPresent(renderer);
    SDL_Delay(25);

    if ((cycle_now+=25) < cycle_limit) {
      if (cycle_now < (cycle_limit / 2)) centerx--;
      else centerx++;
    } else {
      cycle_now = 0;
    }
   }
  cleanup:
  <<sdlcleanup>>
#+end_src

** My macros
*** Hero
**** Hero init
#+name: hero-init
#+begin_src C
  struct hero{
    int xpos, ypos, width, height, r, g, b, a, speed, alive;
    SDL_Rect rect;
  } hero;

    SDL_Event e;
    int mx, my;
    Uint32 mdown;

  hero.alive = 1;
  hero.rect.x=100; hero.rect.y=200; hero.rect.w=50; hero.rect.h=60;

  hero.r = 30; hero.g = 60; hero.b = 90; hero.a = 255;
  hero.speed = 10;
#+end_src

**** Hero update
#+name: hero-update
#+begin_src C
  if(hero.alive == 1)
    SDL_SetRenderDrawColor(renderer, hero.r, hero.g, hero.b, hero.a);
   else
     SDL_SetRenderDrawColor(renderer, 255, 0, 0, hero.a);
  SDL_RenderFillRect(renderer, &(hero.rect));
#+end_src


** Simple SDL2, window, renderer init
#+NAME: sdlstart
#+HEADER: :noweb yes
#+begin_src C
  SDL_Window *window;
  SDL_Renderer *renderer;

  if (SDL_Init(SDL_INIT_VIDEO) < 0){
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to init SDL: %s",
		 SDL_GetError());
    return 3;
   }

  if (SDL_CreateWindowAndRenderer(<<w-width>>, <<w-height>>,
				  <<w-sizing>>, &window, &renderer)){
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create renderer and window: %s",
		 SDL_GetError());
    return 3;
   }
#+end_src

** Simple SDL2 cleanup
#+NAME: sdlcleanup
#+begin_src C
  SDL_DestroyRenderer(renderer);
  SDL_DestroyWindow(window);
  SDL_Quit();
  return 0;
#+end_src