jueves, 29 de noviembre de 2012

Simple DirectMedia Layer

    1. ¿Qué es?
      • SDL es una API de desarrollo multimedia y multiplataforma libre
      • Usada para juegos
      • Usada para SDKs de juegos
      • Usada para emuladores
      • Usada para demos
      • Usada para applicaciones multimedia
    2. ¿Qué puede hacer?
      • Video
      • Eventos
      • Audio
      • CD-ROM de audio
      • Hilos
      • Temporizadores
      • Independencia del peso del sistema
  1. Video
    • Establecer un modo de vídeo de cualquier profundidad, con conversión opcional, si es que el modo de vídeo no está soportado por el hardware.
    • Escribir directamente a un búfer de marco gráfico.
    • Crear superficies con atributos de color clave o fundido alpha.
    • Los volcados de superficie son convertidos automáticamente al formato destino usando volcadores especializados, y están acelerados por hardware, cuando esto es posible. Volcados optimizados con MMX están disponibles para la arquitrectura x86.
    • Los volcados y rellenos son acelerados por hardware en el caso de que este lo soporte.
    Pista:
    Puedes establecer la barra de título de tu aplicación (si la tiene) y su icono usando las funciones SDL_WM_SetCaption() y SDL_WM_SetIcon() respectivamente.
    Eventos
    • Los eventos se facilitan para:
      • Cambiar la visibilidad de la aplicación
      • Entrada del teclado
      • Entrada del ratón
      • Salida solicitada por el usuario
    • Cada evento puede hablitarse o deshabilitarse con SDL_EventState().
    • Los eventos se pasan a una función de filtro especificada por el usuario antes de ser mandados a la cola interna de eventos.
    • Cola de eventos segura con hilos.
    Pista:
    Usa SDL_PeepEvents() para buscar un evento de un tipo determinado en la cola de eventos.
    Audio
    • Establecer la reproducción de sonido de 8 bits y 16 bits, mono o estéreo, con conversión opcional si el formato no está soportado por el hardware.
    • El sonido se ejecuta independientemente en un hilo separado, rellenándose mediante una función de retrollamada.
    • Diseñado para usar mezcladores software personalizados, pero el archivo de ejemplos contiene una librería completa de salida de sonido/música.
    Pista:
    Usa las funciones SDL_LockAudio() y SDL_UnlockAudio() para sincronizar el acceso a datos compartidos por la retrollamada de sonido y el resto del programa.
    CD-ROM audio
    • API completa de control de sonido de CD
    Pista:
    Si le pasas un manejador de CD-ROM NULL a las funciones de CD-ROM de la API, actuarán en el último CD-ROM que se abrió.
    Hilos
    • API de creación de hilos simple
    • Semáforos binarios simples para sincronización
    Pista:
    No utilices funciones de la librería de C como E/S y manejo de memoria desde hilos si puedes evitarlo - estas bloquean recursos utilizados por otros hilos.
    Temporizadores
    • Obtener el número de milisegundos transcurridos
    • Esperar un número especificado de milisegundos
    • Establecer un único temporizador con una resolución de 10ms
    Pista:
    Puedes reemplazar fácilmente la funcion de Win32 GetTickCount() con SDL_GetTicks()
    Independencia del peso del sistema
    • Detectar el peso del sistema del sistema actual
    • Rutinas para el intercambio rápido de valores de datos
    • Lectura y escritura de datos de un peso especificado

    1. ¿Sobre qué plataformas se ejecuta?
      • Linux
      • Win32
      • BeOS
      • Portes no oficiales, portes en desarrollo
     
    Linux
    • Usa las X11 para visualizar el vídeo, aprovechando las extensiones DGA de las XFree86 y la nueva aceleración MTRR para visualización a pantalla completa.
    • Usa la API de OSS para el sonido.
    • Los hilos se implementa usando bien la llamada al sistema clone() y IPC de SysV, o bien los pthreads de la glibc-2.1.
    Pista:
    Puedes obtener todas las porciones ocultas del interfaz del driver de SDL a través de la función SDL_GetWMInfo(). Esta te permite hacer cosas como eliminar las decoraciones de ventanas iconificar progamadamente la ventana.
    Win32
    • Dos versiones, una segura para todos los sistemas basados en la API de Win32, y una con mayor rendimientom basada en la API DirectX.
    • La versión segura usa GDI para la visualización de vídeo. La versión de alto rendimiento usa DirectDraw para la visualización de vídeo, aprovechando la aceleración hardware si está disponible.
    • La versión segura usa la API de waveOut para el sonido. La versión de alto rendimiento usa DirectSound para la reproducción de sonido.
    Pista:
    Debes de realizar llamadas a las funciones de eventos de SDL periódicamente desde el hilo principal para bombear la cola de mensajes de Windows y mantener la respuesta de tu aplicación.
    BeOS
    • Se usa BWindow para la visualización de video.
    • Se usa la API BSoundPlayer para el sonido.
    Pista:
    Linux y BeOS soportan el indicador SDL_INIT_EVENTTHREAD el cual, cuando es pasado a SDL_Init(), hace que la cola de eventos se ejecute asíncronamente en otro hilo. Esto es útil para los cursores de color que responden incluso cuando la aplicación está ocupada.
    Portes no oficiales, portes en desarrollo
    • Solaris, IRIX, FreeBSD
    • MacOS



  2. Usando la API de la Simple DirectMedia Layer
    1. Inicializando la librería
    Usa SDL_Init() para cargar dinámicamente e inicializar la librería. Esta función toma un conjunto de indicadores correspondientes a las porciones que deseas activar:
    SDL_INIT_AUDIO
    SDL_INIT_VIDEO
    SDL_INIT_CDROM
    SDL_INIT_TIMER
    Usa SDL_Quit() para limpiar la librería cuando hayas terminado con ella.
    Pista:
    SDL carga dinámicamente la librería SDL desde la localización estándar de las librerías del sistema. Usa la función SDL_SetLibraryPath() para usar una localización alternativa para las librerías dinámicas distribuidas con tu aplicación.
    Ejemplo:
    #include <stdlib.h>
    #include "SDL.h"
    
    main(int argc, char *argv[])
    {
        if ( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0 ) {
            fprintf(stderr, "No se puede iniciar SDL: %s\n", 
     SDL_GetError());
            exit(1);
        }
        atexit(SDL_Quit);
    
        ...
    }
    

    1. Video
      • Escogiendo y estableciendo módos de video (la manera fácil)
      • Pintando píxels en la pantalla
      • Cargando y mostrando imágenes
    • Eligiendo y estableciendo modos de vídeo (la manera fácil)
      Simplemente escoges tu modo de resolución y profundidad de color preferido y, ¡lo estableces!
    Pista #1:
    Puedes encontrar los modos de vídeo más rápidos soportados por el hardware con la función SDL_GetVideoInfo(). Pista #2:
    Puedes obtener una lista de resoluciones de vídeo soportadas para una determinada profundidad de color usando la función SDL_ListModes().
    Ejemplo:
    { SDL_Surface *screen;
    
        screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE);
        if ( screen == NULL ) 
        {
            fprintf(stderr, "No se puede establecer el modo \
                    de video 640x480: %s\n", SDL_GetError());
            exit(1);
        }
    }
    
    • Dibujando píxels en la pantalla
      Para dibujar en la pantalla debemos escribir directamente en el búfer de marco (framebuffer) gráfico, y llamar a la función de actualización de pantalla.
    Pista:
    Si sabes que vas a realizar mucho dibujo, es mejor cerrar la pantalla (si es necesario) una vez antes de pintar, dibujar mientras mantienes una lista de areas que necesitan ser actualizadas, y abrir la pantalla de nuevo antes de actualizar el dispositivo de visualización.
    Ejemplo: Dibujando un píxel en la pantalla de un formato arbitrario
    void DrawPixel(SDL_Surface *screen, Uint8 R, Uint8 G, Uint8 B)
    {
        Uint32 color = SDL_MapRGB(screen->format, R, G, B);
    
        if ( SDL_MUSTLOCK(screen) ) 
        {
            if ( SDL_LockSurface(screen) < 0 ) 
     {
                return;
            }
        }
        switch (screen->format->BytesPerPixel) 
        {    
            case 1: 
     { /* Asumimos 8-bpp */
                Uint8 *bufp;
    
                bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;
                *bufp = color;
            }
            break;
    
            case 2: 
     { /* Probablemente 15-bpp o 16-bpp */
                Uint16 *bufp;
    
                bufp = (Uint16 *)screen->pixels + \
                y*screen->pitch/2 + x;
                *bufp = color;
            }
            break;
    
            case 3: 
     { /* Modo lento 24-bpp, normalmente no usado */
                Uint8 *bufp;
    
                bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;
                *(bufp+screen->format->Rshift/8) = R;
                *(bufp+screen->format->Gshift/8) = G;
                *(bufp+screen->format->Bshift/8) = B;
            }
            break;
    
            case 4: 
     { /* Probablemente 32-bpp */
                Uint32 *bufp;
    
                bufp = (Uint32 *)screen->pixels + \ 
                       y*screen->pitch/4 + x;
                *bufp = color;
            }
            break;
        }
        if ( SDL_MUSTLOCK(screen) ) 
        {
            SDL_UnlockSurface(screen);
        }
        SDL_UpdateRect(screen, x, y, 1, 1);
    }
    
    • Cargar y mostrar imágenes
      SDL facilita una única rutina de carga de imágenes para tu conveniencia, SDL_LoadBMP(). Puedes encontrar una librería para la carga de imágenes en el archivo de demos SDL.
      Puedes mostrar imágenes usando SDL_BlitSurface() para volcarlas en búfer de marco gráfico. SDL_BlitSurface() recorta automáticamente el rectángulo volcado, que debería ser pasado a SDL_UpdateRects() para actualizar la porción de la pantalla que ha cambiado.
    Pista #1:
    Si estás cargando una imagen que se va a mostrar varias veces, puedes acelerar la velocidad de volcado convirtiéndola al formato de la pantalla. La función SDL_DisplayFormat() realiza esta conversión por tí. Pista #2:
    Muchas imágenes de sprite tienen un fondo transparente. Puedes habilitar volcados transparentes (volcados con color clave) mediante la función SDL_SetColorKey().
    Ejemplo:
    void ShowBMP(char *file, SDL_Surface *screen, int x, int y)
    {
        SDL_Surface *image;
        SDL_Rect dest;
    
        /* Cargamos el archivo BMP en la superficie */
        image = SDL_LoadBMP(file);
        if ( image == NULL ) {
            fprintf(stderr, "No pude cargar %s: %s\n", 
             file, SDL_GetError());
            return;
        }
    
        /* Volcamos en la superficie de pantalla.
           Las superficies no deberían estar bloqueadas 
           en este punto. */
        dest.x = x;
        dest.y = y;
        dest.w = image->w;
        dest.h = image->h;
        SDL_BlitSurface(image, NULL, screen, &dest);
    
        /* Actualizamos la porcion de pantalla que ha cambiado */
        SDL_UpdateRects(screen, 1, &dest);
    
        SDL_FreeSurface(image);
    }
    

    1. Eventos
      • Esperando eventos
      • Consultando eventos
      • Consultando el estado de eventos
    • Esperando eventos
    Esperando eventos usando la función SDL_WaitEvent().
    Pista:
    SDL tiene soporte de teclados internacionales, traducción de eventos de teclado y ubicación de los equivalentes UNICODE en event.key.keysym.unicode. Ya que esto conlleva cierta sobrecarga de proceso, debe habilitarse usando la función SDL_EnableUNICODE().
    Ejemplo:
    {
        SDL_Event event;
    
        SDL_WaitEvent(&event);
    
        switch (event.type) {
            case SDL_KEYDOWN:
                printf("¡Se pulsó la tecla %s!\n",
                       SDL_GetKeyName(event.key.keysym.sym));
                break;
            case SDL_QUIT:
                exit(0);
        }
    }
    
    • Consultando eventos
    Consultar eventos usando la función SDL_PollEvent().
    Pista:
    Puedes mirar los eventos de la cola de eventos sin necesidad de eliminarlos pasando la acción SDL_PEEKEVENT a la función SDL_PeepEvents().
    Ejemplo:
    {
        SDL_Event event;
    
        while ( SDL_PollEvent(&event) ) {
            switch (event.type) {
                case SDL_MOUSEMOTION:
                    printf("El ratón se movió \
             desde %d,%d hasta (%d,%d)\n", \
                           event.motion.xrel, event.motion.yrel, \
                           event.motion.x, event.motion.y);
                    break;
                case SDL_MOUSEBUTTONDOWN:
                    printf("Botón de ratón %d pulsado \
             en (%d,%d)\n",
                           event.button.button, event.button.x, 
             event.button.y);
                    break;
                case SDL_QUIT:
                    exit(0);
            }
        }
    }
    
    • Consultando el estado de evento
    Además de manejar los eventos directamente, cada tipo de evento tiene una función que te permite consultar el estado de evento de la aplicación. Si utilizas esto exclusivamente, deberías ignorar todos los eventos de la función SDL_EventState(), y llamar a SDL_PumpEvents() periódicamente para actualizar el estado de evento de la aplicación.
    Pista:
    Puedes ocultar o mostrar el cursor del ratón del sistema usando la función SDL_ShowCursor().
    Ejemplo:
    {
        SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
    }
    
    void CheckMouseHover(void)
    {
        int mouse_x, mouse_y;
    
        SDL_PumpEvents();
    
        SDL_GetMouseState(&mouse_x, &mouse_y);
        if ( (mouse_x < 32) && (mouse_y < 32) ) 
        {
            printf("¡Ratón en la esquina superior \
            izquierda!\n");
        }
    }
    

    1. Sonido
      • Abriendo el dispositivo de audio
      • Cargando y reproduciendo sonidos
    • Abriendo el dispositivo de sonido
    Necesitas tener una función de retrollamada que mezcle tus datos de sonido y lo coloque en el flujo de sonido. Tras esto, elije el formato de sonido que desees y la velocidad, y abre el dispositivo de sonido.
    El sonido no empezará realmente a reproducirse hasta que no hagas una llamada a SDL_PauseAudio(0), permitiéndote realizar las demás inicializaciones de audio que necesite antes de que tu función de retrollamada se ejecute. Tras terminar de usar la salida de audio, deberías cerrarla usando la función SDL_CloseAudio().
    Pista:
    Si tu aplicación puede manejar diferentes formatos de audio, pasa un segundo puntero SDL_AudioSpec a la función SDL_OpenAudio() para obtener el formato real de sonido del hardware. Si dejas el segundo puntero como NULL, los datos de sonido serán convertidos al formato de sonido del hardware en tiempo de ejecución.
    Ejemplo:
    #include "SDL.h"
    #include "SDL_audio.h"
    {
        extern void mixaudio(void *unused, Uint8 *stream, int len);
        SDL_AudioSpec fmt;
    
        /* Establece sonido estéreo de 16 bits a 22Khz */
        fmt.freq = 22050;
        fmt.format = AUDIO_S16;
        fmt.channels = 2;
        fmt.samples = 512;  /* Un buen valor para juegos */
        fmt.callback = mixaudio;
        fmt.userdata = NULL;
    
        /* ¡Abre el dispositivo de sonido y comienza a
           reproducir sonidos! */
        if ( SDL_OpenAudio(&fmt, NULL) < 0 ) {
            fprintf(stderr, "¡No puedo abrir el sonido!: %s\n",
             SDL_GetError());
            exit(1);
        }
        SDL_PauseAudio(0);
    
        ...
    
        SDL_CloseAudio();
    }
    
    • Cargando y reproduciendo sonidos
    SDL facilita para tu conveniencia, una rútina única para cargar sonido, SDL_LoadWAV(). Tra cargar tus sonidos, deberías convertirlos al formato de audio de salida usando SDL_ConvertAudio(), y así hacerlo disponible a tu función de mezcla.
    Pista:
    Las facilidades de sonido de SDL están diseñadas para un mezclador de sonido de software de bajo nivel. Una completa implementación de un mezclador de ejmplo está disponible bajo la licencia LGPL, y puede encontrarse en la sección de demos del archivo SDL.
    Ejemplo:
    #define NUM_SOUNDS 2
    struct sample {
        Uint8 *data;
        Uint32 dpos;
        Uint32 dlen;
    } sounds[NUM_SOUNDS];
    
    void mixaudio(void *unused, Uint8 *stream, int len)
    {
        int i;
        Uint32 amount;
    
        for ( i=0; i<NUM_SOUNDS; ++i ) 
            {
               amount = (sounds[i].dlen-sounds[i].dpos);
               if ( amount > len ) 
        {
                  amount = len;
               }
               SDL_MixAudio(stream, &sounds[i].data[sounds[i].dpos], 
                     amount, SDL_MIX_MAXVOLUME);
               sounds[i].dpos += amount;
            }
    }
    
    void PlaySound(char *file)
    {
        int index;
        SDL_AudioSpec wave;
        Uint8 *data;
        Uint32 dlen;
        SDL_AudioCVT cvt;
    
        /* Busca una ranura de sonido vacía(o finalizada) */
        for ( index=0; index<NUM_SOUNDS; ++index ) {
            if ( sounds[index].dpos == sounds[index].dlen ) 
     { 
                break;
            }
        }
        if ( index == NUM_SOUNDS )
            return;
    
        /* Carga el archivo de sonido y lo convierte a
           estéreo 16 bits a 22kHz */
        if ( SDL_LoadWAV(file, &wave, &data, &dlen) == NULL ) 
        {
            fprintf(stderr, "No pude cargar %s: %s\n", 
             file, SDL_GetError());
            return;
        }
        SDL_BuildAudioCVT(&cvt, wave.format, wave.channels, wave.freq,
                          AUDIO_S16, 2, 22050);
        cvt.buf = malloc(dlen*cvt.len_mult);
        memcpy(cvt.buf, data, dlen);
        cvt.len = dlen;
        SDL_ConvertAudio(&cvt);
        SDL_FreeWAV(data);
    
        /* Pone los datos de audio en la ranura (comienza
           la reproducción inmediatemente) */
        if ( sounds[index].data ) {
            free(sounds[index].data);
        }
        SDL_LockAudio();
        sounds[index].data = cvt.buf;
        sounds[index].dlen = cvt.len_cvt;
        sounds[index].dpos = 0;
        SDL_UnlockAudio();
    }
    

    1. CD-ROM de audio
      • Abriendo una unidad de CD-ROM para su uso
      • Reproduciendo el CD-ROM

     

    Ejemplo:
    {
        SDL_CD *cdrom;
    
        if ( SDL_CDNumDrives() > 0 ) {
            cdrom = SDL_CDOpen(0);
            if ( cdrom == NULL ) {
                fprintf(stderr, "No puedo abrir el CD-ROM \ 
                        por defecto: %s\n" SDL_GetError());
                return;
            }
    
            ...
    
            SDL_CDClose(cdrom);
        }
    }
    
    • Reproduciendo el CD-ROM
    Las unidades de CD-ROM especifican el tiempo bien en formato MSF (mins/segs/marcos), bien directamente en marcos. Un marco es una unidad estándar de tiempo en el CD, que se corresponde con 1/75 segundos. SDL usa marcos en lugar del formato MSF cuando especifica longitudes de pisat y desplazamientos, pero puedes convertir entre ambos formatos usando las macros FRAMES_TO_MSF() y MSF_TO_FRAMES().
    SDL no actualiza la información de pistas en la estructura SDL_CD hasta que realices una llamada a SDL_CDStatus(), así que deberías siempre hacer uso de SDL_CDStatus() para asegurarte de que hay un CD en la unidad y determinar qué pistas tienes disponibles antes de reproducir el CD. Notar que los índices para las pistas comienzan en 0 para la primera pista.
    SDL tiene dos funciones de reproducción de CD-ROM. Puedes reproducir pistas especificas del CD usando SDL_CDPlayTracks(), o puedes reproducir de una posición absoluta de marco usando SDL_CDPlay().
    SDL no facilita notificación automática de inserción de CD o de fin de reproducción. Para detectar estas condiciones, necesitarás consultar periódicamente el estado de la unidad con SDL_CDStatus(). Ya que esta llamada lee la tabla de contenido del CD, no debería ser llamada continuamente en un bucle corto.
    Pista:
    Puedes determinar qué pistas son de audio y cuales son de datos mirando en cdrom->tracks[track].type, y comparando su valor con SDL_AUDIO_TRACK y SDL_DATA_TRACK.
    Ejemplo:
    void PlayTrack(SDL_CD *cdrom, int track)
    {
        if ( CD_INDRIVE(SDL_CDStatus(cdrom)) ) {
            SDL_CDPlayTracks(cdrom, track, 0, track+1, 0);
        }
        while ( SDL_CDStatus(cdrom) == CD_PLAYING ) {
            SDL_Delay(1000);
        }
    }
    

    1. Hilos
      • Crear un hilo simple
      • Sincronizando el acceso a un recurso
    • Crea un hilo simple
    La creación de un hilo es realizada pasando una función a SDL_CreateThread(). Cuando la función retorna, si lo hace con éxito, tu función estará ahora ejcutándose concurrentemente con el resto de tu aplización, en su propio contexto (pila, registros, etc) y será capaz de acceder a la memoria y manejadores de archivo usados por el resto de la aplicación.
    Pista:
    El segundo argumento de SDL_CreateThread() se pasa como parámetro a la función del hilo. Puedes utilizar esto para pasarle valores en la pila, o simplemente un puntero a datos para que los use el hilo.
    Ejemplo:
    #include "SDL_thread.h"
    
    int global_data = 0;
    
    int thread_func(void *unused)
    {
        int last_value = 0;
    
        while ( global_data != -1 ) 
        {
            if ( global_data != last_value ) 
     {
                printf("Valores de datos cambiados a\n", global_data);
                last_value = global_data;
            }
            SDL_Delay(100);
        }
        printf("Saliendo del hilo\n");
        return(0);
    }
    
    {
        SDL_Thread *thread;
        int i;
    
        thread = SDL_CreateThread(thread_func, NULL);
        if ( thread == NULL ) 
        {
            fprintf(stderr, "No se puede crear el hilo: %s\n",
             SDL_GetError());
            return;
        }
    
        for ( i=0; i<5; ++i ) 
        {
            printf("Cambiando el valor a %d\n", i);
            global_data = i;
            SDL_Delay(1000);
        }
    
        printf("Indicando al hilo que finalice\n");
        global_data = -1;
        SDL_WaitThread(thread, NULL);
    }
    
    • Sincronizando el acceso a un recurso
    Puedes prevenir que un recurso sea accedido por más de un hilo creando un mutex y encerrando el acceso a el recurso llamadas de cierre (SDL_mutexP()) y apertura (SDL_mutexV()).
    Pista:
    Todos los datos que pueden ser accedidos por más de un hilo deberían protegerse con un mutex.
    Ejemplo:
    #include "SDL_thread.h"
    #include "SDL_mutex.h"
    
    int potty = 0;
    int gotta_go;
    
    int thread_func(void *data)
    {
        SDL_mutex *lock = (SDL_mutex *)data;
        int times_went;
    
        times_went = 0;
        while ( gotta_go ) 
        {
            SDL_mutexP(lock);  /* Cerramos el potty */
            ++potty;
            printf("Hilo %d usando el potty\n", SDL_ThreadID());
            if ( potty > 1 ) 
     {
                printf("¡Oh oh, alguien más está usando el potty!\n");
            }
            --potty;
            SDL_mutexV(lock);
            ++times_went;
        }
        printf("Yep\n");
        return(times_went);
    }
    
    {
        const int progeny = 5;
        SDL_Thread *kids[progeny];
        SDL_mutex  *lock;
        int i, lots;
    
        /* Creamos un cierre de sincronización */
        lock = SDL_CreateMutex();
    
        gotta_go = 1;
        for ( i=0; i<progeny; ++i ) {
            kids[i] = SDL_CreateThread(thread_func, lock);
        }
    
        SDL_Delay(5*1000);
        SDL_mutexP(lock);
        printf("¿Acabó todo el mundo?\n");
        gotta_go = 0;
        SDL_mutexV(lock);
    
        for ( i=0; i<progeny; ++i ) {
            SDL_WaitThread(kids[i], &lots);
            printf("El hilo %d uso el potty %d veces\n", i+1, lots);
        }
        SDL_DestroyMutex(lock);
    }
    

    1. Temporizadores
      • Obtener el tiempo actual, en milisegundos
      • Esperar un determinado número de milisegundo
    • Obtener el tiempo actual, en milisegundos
    SDL_GetTicks() te dice cuantos milisegundos han pasado desde un punto arbitrario del pasado.
    Pista:
    En general, cuando se implementa un juego, es mejor mover objetos en el juego basándose en el tiempo en lugar de la velocidad de marcos. Esto produce jugabilidad tanto en máquinas rápidas como en lentas.
    Ejemplo:
    #define TICK_INTERVAL    30
    
    Uint32 TimeLeft(void)
    {
        static Uint32 next_time = 0;
        Uint32 now;
    
        now = SDL_GetTicks();
        if ( next_time <= now ) 
        {
            next_time = now+TICK_INTERVAL;
            return(0);
        }
        return(next_time-now);
    }
    
    • Esperar un número determinado de milisegundos
    SDL_Delay() te permite esperar un número determinado de milisegundos.
    Dado que los sistemas operativos que soportados por SDL son multitares, no hay una manera de garantizar que tu aplicación se detendrá exactamente el tiempo solicitado. Debería ser usado más para parar por un momento más que para despertar en un momento determinado.
    Pista:
    La mayor parte de los sistemas operativos tiene una porción de tiempo del planificador de 10 ms. Puedes utilizar SDL_Delay(1) como una manera de liberar la CPU para la porción de tiempo actual, permitiendo la ejecución de otros hilos. Esto es importante si tienes un hilo ejecutando un bucle muy estrecho pero deseas que los demás hilos (como el del sonido) sigan ejecutándose.
    Ejemplo:
    {
        while ( game_running ) 
        {
            UpdateGameState();
            SDL_Delay(TimeLeft());
        }
    }
     

    1. Independencia del peso del sistema
    • Determinando el peso del sistema del sistema actual
    El preprocesador de C define el símbolo SDL_BYTEORDER como SDL_LIL_ENDIAN o SDL_BIG_ENDIAN, dependiendo del orden de los bytes del sistema actual.
    Un sistema de byte menos significativo primero(little endian) escribe datos a disco de la siguiente manera:
         [bytes bajos] [bytes altos]
    Un sistema de byte más significativo primero(big endian) escribe datos a disco de la siguiente manera:
         [bytes altos] [bytes bajos]
    Pista:
    Los sistemas x86 son de tipo byte menos significativo primero(little endian) y los sistemas PPC son de tipo byte más significativo primero(big endian).
    Ejemplo:
    #include "SDL_endian.h"
    
    #if SDL_BYTEORDER == SDL_LIL_ENDIAN
    #define SWAP16(X)    (X)
    #define SWAP32(X)    (X)
    #else#define SWAP16(X)    SDL_Swap16(X)
    #define SWAP32(X)    SDL_Swap32(X)
    #endif
    • Intercambiar datos entre sistemas de distinto peso
    SDL facilita un conjunto de macros en SDL_endian.h, SDL_Swap16() y SDL_Swap32(), los cuales intercambian el peso de los datos por tí. Esisten asimismo macros que intercambian datos de un peso en particular al peso del sistema local.
    Pista:
    Si simplemente necesitas conocer el orden de los byes, pero no usar todas las funciones de intercambio, incluye SDL_byteorder.h en lugar SDL_endian.h
    Ejemplo:
    #include "SDL_endian.h"
    
    void ReadScanline16(FILE *file, Uint16 *scanline, int length)
    {
        fread(scanline, length, sizeof(Uint16), file);
        if ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) {
            int i;
            for ( i=length-1; i >= 0; --i )
                scanline[i] = SDL_SwapLE16(scanline[i]);
        }
    }