Beispiel #1
0
static bool hapxi_play_effect(ALLEGRO_HAPTIC_EFFECT_ID *id, int loops)
{
   ALLEGRO_HAPTIC_XINPUT *hapxi = hapxi_device_for_id(id);
   ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi = hapxi_effect_for_id(id);

   if ((!hapxi) || (id->_id < 0) || (!effxi) || (loops < 1))
      return false;
   al_lock_mutex(hapxi_mutex);
   /* Simply set some flags. The polling thread will see this and start playing.
      after the effect's delay has passed. */
   effxi->state = ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_STARTING;
   effxi->start_time = al_get_time();
   effxi->stop_time = effxi->start_time + al_get_haptic_effect_duration(&effxi->effect) * loops;
   effxi->repeats = loops;
   effxi->play_repeated = 0;
   effxi->loop_start = effxi->start_time;

   id->_playing = true;
   id->_start_time = al_get_time();
   id->_start_time = effxi->start_time;
   id->_end_time = effxi->stop_time;
   al_unlock_mutex(hapxi_mutex);
   al_signal_cond(hapxi_cond);
   return true;
}
Beispiel #2
0
/* ljoy_exit_joystick: [primary thread]
 *  Shut down the joystick driver.
 */
static void ljoy_exit_joystick(void)
{
    int i;

#ifdef SUPPORT_HOTPLUG
    if (inotify_fd != -1) {
        _al_unix_stop_watching_fd(inotify_fd);
        close(inotify_fd);
        inotify_fd = -1;
    }
    hotplug_ended = true;
    al_signal_cond(hotplug_cond);
    al_join_thread(hotplug_thread, NULL);
#endif

    al_destroy_mutex(config_mutex);
    config_mutex = NULL;

    for (i = 0; i < (int)_al_vector_size(&joysticks); i++) {
        ALLEGRO_JOYSTICK_LINUX **slot = _al_vector_ref(&joysticks, i);
        inactivate_joy(*slot);
        al_free(*slot);
    }
    _al_vector_free(&joysticks);
    num_joysticks = 0;
}
Beispiel #3
0
static int packet_queue_put(PacketQueue * q, AVPacket * pkt)
{
   AVPacketList *pkt1;
   if (pkt != &flush_pkt && av_dup_packet(pkt) < 0) {
      return -1;
   }
   pkt1 = av_malloc(sizeof(AVPacketList));
   if (!pkt1)
      return -1;
   pkt1->pkt = *pkt;
   pkt1->next = NULL;

   al_lock_mutex(q->mutex);

   if (!q->last_pkt)
      q->first_pkt = pkt1;
   else
      q->last_pkt->next = pkt1;
   q->last_pkt = pkt1;
   q->nb_packets++;
   q->size += pkt1->pkt.size;
   al_signal_cond(q->cond);
   al_unlock_mutex(q->mutex);
   return 0;
}
Beispiel #4
0
/* [gtk thread] */
gboolean _al_gtk_release_args(gpointer data)
{
   ARGS_BASE *args = (ARGS_BASE *) data;

   args->done = true;
   al_signal_cond(args->cond);
   al_unlock_mutex(args->mutex);

   return FALSE;
}
Beispiel #5
0
/* [gtk thread] */
static gboolean release_args(gpointer data)
{
   ARGS *args = (ARGS *) data;
   
   args->done = true;
   al_signal_cond(args->cond);
   al_unlock_mutex(args->mutex);
   
   return FALSE;
}
/* This will only return when the text window is closed. */
static void *text_log_thread_proc(ALLEGRO_THREAD *thread, void *arg)
{
   ALLEGRO_NATIVE_DIALOG *textlog = arg;

   if (!_al_open_native_text_log(textlog)) {
      al_lock_mutex(textlog->tl_text_mutex);
      textlog->tl_init_error = true;
      al_signal_cond(textlog->tl_text_cond);
      al_unlock_mutex(textlog->tl_text_mutex);
   }

   return thread;
}
Beispiel #7
0
/* ljoy_config_dev_changed: [fdwatch thread]
 *  Called when the /dev hierarchy changes.
 */
static void ljoy_config_dev_changed(void *data)
{
    char buf[128];
    (void)data;

    /* Empty the event buffer. We only care that some inotify event was sent but it
     * doesn't matter what it is since we are going to do a full scan anyway once
     * the timer_fd fires.
     */
    while (read(inotify_fd, buf, sizeof(buf)) > 0) {
    }

    al_signal_cond(hotplug_cond);
}
Beispiel #8
0
static bool hapxi_stop_effect(ALLEGRO_HAPTIC_EFFECT_ID *id)
{
   ALLEGRO_HAPTIC_XINPUT *hapxi = hapxi_device_for_id(id);
   ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi = hapxi_effect_for_id(id);

   if ((!hapxi) || (id->_id < 0))
      return false;
   /* Simply set some flags. The polling thread will see this and stop playing.*/
   effxi = (ALLEGRO_HAPTIC_EFFECT_XINPUT *)id->_pointer;
   if (effxi->state <= ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_READY) return false;
   al_lock_mutex(hapxi_mutex);
   effxi->state = ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_STOPPING;
   id->_playing = false;
   al_unlock_mutex(hapxi_mutex);
   al_signal_cond(hapxi_cond);
   return true;
}
Beispiel #9
0
static void hapxi_exit_haptic(void)
{
   void *ret_value;
   ASSERT(hapxi_thread);
   ASSERT(hapxi_mutex);
   ASSERT(hapxi_cond);

   /* Request the event thread to shut down, signal the condition, then join the thread. */
   al_set_thread_should_stop(hapxi_thread);
   al_signal_cond(hapxi_cond);
   al_join_thread(hapxi_thread, &ret_value);

   /* clean it all up. */
   al_destroy_thread(hapxi_thread);
   al_destroy_cond(hapxi_cond);

   al_destroy_mutex(hapxi_mutex);
   hapxi_mutex = NULL;
}
Beispiel #10
0
static bool hapxi_is_effect_playing(ALLEGRO_HAPTIC_EFFECT_ID *id)
{
   ALLEGRO_HAPTIC_XINPUT *hapxi;
   ALLEGRO_HAPTIC_EFFECT_XINPUT *effxi;
   bool result;
   ASSERT(id);

   hapxi = hapxi_device_for_id(id);
   effxi = hapxi_effect_for_id(id);

   if ((!hapxi) || (id->_id < 0) || (!id->_playing))
      return false;
   al_lock_mutex(hapxi_mutex);
   ALLEGRO_DEBUG("Playing effect state: %d %p %lf %lf\n", effxi->state, effxi, al_get_time(), id->_end_time);

   result = (effxi->state > ALLEGRO_HAPTIC_EFFECT_XINPUT_STATE_READY);
   al_unlock_mutex(hapxi_mutex);
   al_signal_cond(hapxi_cond);

   return result;
}
Beispiel #11
0
/* Must be called from the user thread. */
static void retrieve_picture(VideoState *is)
{
   VideoPicture *vp;
   int dst_pix_fmt;
   AVPicture pict;
   static struct SwsContext *img_convert_ctx;
   AVFrame *pFrame;
   
   if (!is->got_picture) return;

   vp = &is->pictq[is->pictq_windex];
   
   pFrame = vp->frame;
   
   if (!vp->bmp ||
       vp->width != is->video_st->codec->width ||
       vp->height != is->video_st->codec->height) {
       alloc_picture(is);
   }
   
   /* YUV->RGB conversion. */
   if (vp->bmp) {
      /* Don't waste CPU on an outdated frame. */
      if (get_video_clock(is) >= get_external_clock(is) - 0.25) {
         ALLEGRO_LOCKED_REGION *lock;
         lock = al_lock_bitmap(vp->bmp, 0, ALLEGRO_LOCK_WRITEONLY);

         dst_pix_fmt = PIX_FMT_RGB24;

         pict.data[0] = lock->data;
         pict.linesize[0] = lock->pitch;

         if (img_convert_ctx == NULL) {
            int w = is->video_st->codec->width;
            int h = is->video_st->codec->height;
            img_convert_ctx = sws_getContext(w, h,
                                             is->video_st->codec->pix_fmt, w, h,
                                             dst_pix_fmt, SWS_BICUBIC, NULL, NULL,
                                             NULL);
            if (img_convert_ctx == NULL) {
               ALLEGRO_ERROR("Cannot initialize the conversion context!\n");
               return;
            }
         }
         sws_scale(img_convert_ctx, (uint8_t const *const*)pFrame->data, pFrame->linesize,
                   0, is->video_st->codec->height, pict.data, pict.linesize);

         al_unlock_bitmap(vp->bmp);
      }
      else {
         vp->dropped = true;
      }
      //printf("[%d] %f %f %f %s\n", is->pictq_windex,
      //   vp->pts, get_video_clock(is), get_external_clock(is), vp->dropped ? "dropped" : "shown");

      if (++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE) {
         is->pictq_windex = 0;
      }
   }

   al_lock_mutex(is->pictq_mutex);
   is->pictq_size++;
   is->got_picture--;
   vp->allocated = 1;
   al_signal_cond(is->pictq_cond);
   al_unlock_mutex(is->pictq_mutex);
}
Beispiel #12
0
static void video_refresh_timer(void *userdata)
{

   VideoState *is = (VideoState *) userdata;
   VideoPicture *vp;
   double actual_delay, delay, sync_threshold, ref_clock, diff;

   if (!is->first)
      return;
   if (!is->video_st)
      return;
   if (is->pictq_size == 0)
      return;
   if (is->paused) return;
   
   if (get_master_clock(is) < is->show_next) return;

   vp = &is->pictq[is->pictq_rindex];

   is->video_current_pts = vp->pts;
   is->video_current_pts_time = av_gettime();

   delay = vp->pts - is->frame_last_pts;        /* the pts from last time */
   if (delay <= 0 || delay >= 1.0) {
      /* if incorrect delay, use previous one */
      delay = is->frame_last_delay;
   }
   /* save for next time */
   is->frame_last_delay = delay;
   is->frame_last_pts = vp->pts;

   /* update delay to sync to audio if not master source */
   if (is->av_sync_type != AV_SYNC_VIDEO_MASTER) {
      ref_clock = get_master_clock(is);
      diff = vp->pts - ref_clock;

      /* Skip or repeat the frame. Take delay into account */
      sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD;
      if (fabs(diff) < AV_NOSYNC_THRESHOLD) {
         if (diff <= -sync_threshold) {
            delay = 0;
         }
         else if (diff >= sync_threshold) {
            delay = 2 * delay;
         }
      }
   }

   is->frame_timer += delay;
   /* computer the REAL delay */
   actual_delay = is->frame_timer - (av_gettime() / 1000000.0);

   if (!vp->dropped && vp->bmp) {
      is->video->current_frame = vp->bmp;
      
      /* Can be NULL or wrong size, will be (re-)allocated as needed. */
      vp->bmp = is->shown.bmp;
      /* That way it won't be overwritten. */
      is->shown.bmp = is->video->current_frame;

      is->video->position = get_master_clock(is);
      is->video->video_position = get_video_clock(is);
      is->video->audio_position = get_audio_clock(is);
      
      is->show_next = is->video->position + actual_delay;
      al_signal_cond(is->timer_cond);

      if (is->video_st->codec->sample_aspect_ratio.num == 0) {
         is->video->aspect_ratio = 0;
      }
      else {
         is->video->aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio) *
             is->video_st->codec->width / is->video_st->codec->height;
      }
      if (is->video->aspect_ratio <= 0.0) {
         is->video->aspect_ratio = (float)is->video_st->codec->width /
             (float)is->video_st->codec->height;
      }
   }
   else
      is->dropped_count++;
   
   //printf("[%d] %f %s\n", is->pictq_rindex,
   //   actual_delay, vp->dropped ? "dropped" : "shown");

   /* update queue for next picture! */
   if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) {
      is->pictq_rindex = 0;
   }
   
   al_lock_mutex(is->pictq_mutex);
   is->pictq_size--;
   al_signal_cond(is->pictq_cond);
   al_unlock_mutex(is->pictq_mutex);

   /* We skipped a frame... let's grab more until we catch up. */
   if (actual_delay < 0)
      video_refresh_timer(userdata);
}
Beispiel #13
0
static bool open_video(ALLEGRO_VIDEO *video)
{
   VideoState *is = av_mallocz(sizeof *is);
   int i;
   AVRational fps;

   is->video = video;
   
   init();
   
   video->data = is;
   strncpy(is->filename, al_path_cstr(video->filename, '/'),
      sizeof(is->filename));
   
   is->av_sync_type = DEFAULT_AV_SYNC_TYPE;

   // Open video file
   #ifdef FFMPEG_0_8
   if (avformat_open_input(&is->format_context, is->filename, NULL,
      NULL) != 0) { 	
   #else
   if (av_open_input_file(&is->format_context, is->filename, NULL, 0,
      NULL) != 0) {
   #endif
      av_free(is);
      return false;
   }

   if (av_find_stream_info(is->format_context) < 0) {
      av_free(is);
      return false;
   }

   is->video_index = -1;
   is->audio_index = -1;
   for (i = 0; i < (int)is->format_context->nb_streams; i++) {
      if (is->format_context->streams[i]->codec->codec_type
         == AVMEDIA_TYPE_VIDEO && is->video_index < 0)
      {
         is->video_index = i;
      }
      if (is->format_context->streams[i]->codec->codec_type
         == AVMEDIA_TYPE_AUDIO && is->audio_index < 0)
      {
         is->audio_index = i;
      }
   }
   
   fps = is->format_context->streams[is->video_index]->r_frame_rate;
   video->fps = (double)fps.num / fps.den;
   video->audio_rate = is->format_context->streams[is->audio_index]->
      codec->sample_rate;
   video->width = is->format_context->streams[is->video_index]->codec->width;
   video->height = is->format_context->streams[is->video_index]->codec->height;

   is->pictq_mutex = al_create_mutex();
   is->pictq_cond = al_create_cond();
   
   is->timer_mutex = al_create_mutex();
   is->timer_cond = al_create_cond();

   return true;
}

static bool close_video(ALLEGRO_VIDEO *video)
{
   VideoState *is = video->data;
   
   is->quit = true;
   
   if (is->timer_thread) {
   
      al_lock_mutex(is->timer_mutex);
      al_signal_cond(is->timer_cond);
      al_unlock_mutex(is->timer_mutex);
   
      al_join_thread(is->timer_thread, NULL);
   }
   
   if (is->parse_thread) {
      al_join_thread(is->parse_thread, NULL);
   }

   al_destroy_mutex(is->timer_mutex);
   al_destroy_cond(is->timer_cond);

   av_free(is);
   return true;
}
Beispiel #14
0
void gdp_game(){
    gdp_send2server_init();

    if(connecterro == 1){
        gdp_erro("Não foi possível conectar ao servidor! :/");
        return;
    }
    int i,a=-1,d=-1,x=-1,y=-1;

    thsend2server = al_create_thread(gdp_send2server, NULL);
    al_start_thread(thsend2server);

    threcv2server = al_create_thread(gdp_recv2server, NULL);
    al_start_thread(threcv2server);

    while(true){
        listchars[nlocchar]->idmap = opmap;

        al_wait_for_event(event_queue, &evento);

        if(gdp_readclose())
            break;

        if(listchars[nlocchar]->obj.lock == 0 && listchars[nlocchar]->obj.a !=4){
            gdp_readaction(&listchars[nlocchar]->obj,&scale);
            gdp_readdirection(&listchars[nlocchar]->obj);
        }

        for(i=0;i<ntotchars;i++){
            if(listchars[i]!=NULL)
                gdp_statuschar(listchars[i]);
        }

        if (gdp_readtime() && al_is_event_queue_empty(event_queue)) {
		    if (a != listchars[nlocchar]->obj.a || d != listchars[nlocchar]->obj.d2 ||
		    	x != listchars[nlocchar]->obj.x || y != listchars[nlocchar]->obj.y) {
		        al_lock_mutex(musend2server);
		        mudou = true;
		        al_signal_cond(condsend2server);
		        al_unlock_mutex(musend2server);
		    }
            gdp_clear();

            ALLEGRO_TRANSFORM camera;
            al_identity_transform(&camera);
            gdp_update_camera(listchars[nlocchar], height, wigth, scale);

            // imagem de fundo
            al_draw_scaled_bitmap(ambient->image,
                0, 0,
                ambient->w,
                ambient->h,
                0,
                0, //ambient->info->h
                ambient->wd,
                ambient->hd,
                0
            );

            //mostra portoes
            for (i=0;i<(ambient->qt_gates);i++)
            {
                 al_draw_filled_rectangle
                 (
                    (ambient->gates[i].x1),
                    (ambient->gates[i].y1),
                    (ambient->gates[i].x2),
                    (ambient->gates[i].y2),
                    al_map_rgba(255, 98, 100,0)
                  );
            }

            int size = CHARS + LIFELESS;
            LayeredObject *sorted = (LayeredObject*)calloc(size, sizeof(LayeredObject));
            memset(sorted, 0, size * sizeof(LayeredObject));

            for (i = 0; i < CHARS; i++) {
                if (listchars[i] && listchars[i]->idmap == opmap) {
                    sorted[i].type = OBJTYPE_ENEMY_OR_CHAR;
                    sorted[i].y = listchars[i]->obj.y + listchars[i]->obj.h;
                    sorted[i].arr_idx = i;
                }
            }

            for (i = CHARS; i < CHARS + LIFELESS; i++) {
                if (listlifeless[i - CHARS] && listlifeless[i - CHARS]->idmap == opmap) {
                    sorted[i].type = OBJTYPE_LIFELESS;
                    sorted[i].y = listlifeless[i - CHARS]->obj.y + listlifeless[i - CHARS]->obj.h;
                    sorted[i].arr_idx = i - CHARS;
                }
            }

            qsort(sorted, size, sizeof(LayeredObject), (void*)comparar_char);

            for (i = 0; i < size; i++) {
                if (sorted[i].type == OBJTYPE_NONE)
                    break;

                if (sorted[i].type == OBJTYPE_ENEMY_OR_CHAR) {
                    if(listchars[sorted[i].arr_idx] != NULL){
                        if(listchars[sorted[i].arr_idx]->dead==0){
                                gdp_drawchar(listchars[sorted[i].arr_idx]);
                        }
                    }
                    /*
                    if (listchars[sorted[i].arr_idx]->dead==1) {
                        free(listchars[sorted[i].arr_idx]);
                        listchars[sorted[i].arr_idx] = NULL;
                    }
                    */
                } else {
                    if(listlifeless[sorted[i].arr_idx] != NULL){
                        if(listlifeless[sorted[i].arr_idx]->dead==0){
                            gdp_drawlifeless(listlifeless[sorted[i].arr_idx]);
                        }
                    }
                    /*
                    if (listlifeless[sorted[i].arr_idx]->dead==1) {
                        free(listlifeless[sorted[i].arr_idx]);
                        listlifeless[sorted[i].arr_idx] = NULL;
                    }
                    */
                }
            }

            free(sorted);

            al_use_transform(&camera);
            gdp_drawinfo(ambient->info);
            al_flip_display();
        }
    }
}
Beispiel #15
0
bool _al_open_native_text_log(ALLEGRO_NATIVE_DIALOG *textlog)
{
   LPCSTR font_name;
   HWND hWnd;
   HWND hLog;
   WNDCLASSA text_log_class;
   RECT client_rect;
   HFONT hFont;
   MSG msg;
   BOOL ret;

   al_lock_mutex(textlog->tl_text_mutex);

   /* Prepare text log class info. */
   if (!wlog_class_registered) {
      memset(&text_log_class, 0, sizeof(text_log_class));
      text_log_class.hInstance      = (HINSTANCE)GetModuleHandle(NULL);
      text_log_class.lpszClassName  = "Allegro Text Log";
      text_log_class.lpfnWndProc    = wlog_text_log_callback;
      text_log_class.hIcon          = NULL;
      text_log_class.hCursor        = NULL;
      text_log_class.lpszMenuName   = NULL;
      text_log_class.hbrBackground  = (HBRUSH)GetStockObject(GRAY_BRUSH);

      if (RegisterClassA(&text_log_class) == 0) {
         /* Failure, window class is a basis and we do not have one. */
         al_unlock_mutex(textlog->tl_text_mutex);
         return false;
      }

      wlog_class_registered++;
   }

   /* Load RichEdit control. */
   if (!wlog_rich_edit_module) {
      if ((wlog_rich_edit_module = _al_open_library("msftedit.dll"))) {
         /* 4.1 and emulation of 3.0, 2.0, 1.0 */
         wlog_edit_control = L"RICHEDIT50W"; /*MSFTEDIT_CLASS*/
         wlog_unicode      = true;
      }
      else if ((wlog_rich_edit_module = _al_open_library("riched20.dll"))) {
         /* 3.0, 2.0 */
         wlog_edit_control = L"RichEdit20W"; /*RICHEDIT_CLASS*/
         wlog_unicode      = true;
      }
      else if ((wlog_rich_edit_module = _al_open_library("riched32.dll"))) {
         /* 1.0 */
         wlog_edit_control = L"RichEdit"; /*RICHEDIT_CLASS*/
         wlog_unicode      = false;
      }
      else {
         wlog_edit_control = L"EDIT";
         wlog_unicode      = false;
      }
   }

   /* Create text log window. */
   hWnd = CreateWindowA("Allegro Text Log", al_cstr(textlog->title),
      WS_CAPTION | WS_SIZEBOX | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU,
      CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL,
      (HINSTANCE)GetModuleHandle(NULL), textlog);
   if (!hWnd) {
      if (wlog_rich_edit_module) {
         _al_close_library(wlog_rich_edit_module);
         wlog_rich_edit_module = NULL;
      }
      UnregisterClassA("Allegro Text Log", (HINSTANCE)GetModuleHandle(NULL));
      al_unlock_mutex(textlog->tl_text_mutex);
      return false;
   }

   /* Get client area of the log window. */
   GetClientRect(hWnd, &client_rect);

   /* Create edit control. */
   hLog = CreateWindowW(wlog_edit_control, NULL,
      WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_WANTRETURN | ES_AUTOVSCROLL | ES_READONLY,
      client_rect.left, client_rect.top, client_rect.right - client_rect.left, client_rect.bottom - client_rect.top,
      hWnd, NULL, (HINSTANCE)GetModuleHandle(NULL), NULL);
   if (!hLog) {
      if (wlog_rich_edit_module) {
         _al_close_library(wlog_rich_edit_module);
         wlog_rich_edit_module = NULL;
      }
      DestroyWindow(hWnd);
      UnregisterClassA("Allegro Text Log", (HINSTANCE)GetModuleHandle(NULL));
      al_unlock_mutex(textlog->tl_text_mutex);
      return false;
   }

   /* Enable double-buffering. */
   SetWindowLong(hLog, GWL_EXSTYLE, GetWindowLong(hLog, GWL_EXSTYLE) | 0x02000000L/*WS_EX_COMPOSITED*/);

   /* Select font name. */
   if (textlog->flags & ALLEGRO_TEXTLOG_MONOSPACE)
      font_name = "Courier New";
   else
      font_name = "Arial";

   /* Create font and set font. */
   hFont = CreateFont(-11, 0, 0, 0, FW_LIGHT, 0, 0,
      0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
      FF_MODERN | FIXED_PITCH, font_name);

   /* Assign font to the text log. */
   if (hFont) {
      SendMessage(hLog, WM_SETFONT, (WPARAM)hFont, 0);
   }

   /* Set background color of RichEdit control. */
   if (wlog_rich_edit_module) {
      SendMessage(hLog, EM_SETBKGNDCOLOR, 0, (LPARAM)RGB(16, 16, 16));
   }

   /* We are ready to show our window. */
   ShowWindow(hWnd, SW_NORMAL);

   /* Save handles for future use. */
   textlog->window    = hWnd;
   textlog->tl_textview  = hLog;
   textlog->is_active = true;

   /* Now notify al_show_native_textlog that the text log is ready. */
   textlog->tl_done = true;
   al_signal_cond(textlog->tl_text_cond);
   al_unlock_mutex(textlog->tl_text_mutex);

   /* Process messages. */
   while ((ret = GetMessage(&msg, NULL, 0, 0)) != 0) {
      if (ret != -1 && msg.message != WM_QUIT) {
         /* Intercept child window key down messages. Needed to track
          * hit of ESCAPE key while text log have focus. */
         if (msg.hwnd != textlog->window && msg.message == WM_KEYDOWN) {
            PostMessage(textlog->window, WM_KEYDOWN, msg.wParam, msg.lParam);
         }
         TranslateMessage(&msg);
         DispatchMessage(&msg);
      }
      else
         break;
   }

   /* Close window. Should be already closed, this is just sanity. */
   if (IsWindow(textlog->window)) {
      DestroyWindow(textlog->window);
   }

   /* Release font. We don't want to leave any garbage. */
   DeleteObject(hFont);

   /* Release RichEdit module. */
   if (wlog_rich_edit_module) {
      _al_close_library(wlog_rich_edit_module);
      wlog_rich_edit_module = NULL;
   }

   /* Unregister window class. */
   if (--wlog_class_registered == 0) {
      UnregisterClassA("Allegro Text Log", (HINSTANCE)GetModuleHandle(NULL));
   }

   /* Notify everyone that we're gone. */
   al_lock_mutex(textlog->tl_text_mutex);
   textlog->tl_done = true;
   al_signal_cond(textlog->tl_text_cond);
   al_unlock_mutex(textlog->tl_text_mutex);

   return true;
}
Beispiel #16
0
static inline void HandleEvent(struct Game* game, ALLEGRO_EVENT* ev) {
	switch (ev->type) {
		case ALLEGRO_EVENT_DISPLAY_HALT_DRAWING:
			PauseExecution(game);
			al_acknowledge_drawing_halt(game->display);
			break;

		case ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING:
			al_acknowledge_drawing_resume(game->display);
			ReloadGamestates(game);
			ResumeExecution(game);
			break;

		case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT:
			if (game->config.autopause) {
				PrintConsole(game, "Focus lost, autopausing...");
				PauseExecution(game);
			}
			break;

		case ALLEGRO_EVENT_DISPLAY_SWITCH_IN:
			if (game->config.autopause) {
				if (game->config.debug.enabled && game->config.debug.livereload) {
					ReloadCode(game);
				}
				ResumeExecution(game);
			}
			break;

		case ALLEGRO_EVENT_DISPLAY_RESIZE:
			PrintConsole(game, "Resize event: %dx%d", ev->display.width, ev->display.height);

#ifdef LIBSUPERDERPY_IMGUI
			ImGui_ImplAllegro5_InvalidateDeviceObjects();
#endif
			al_acknowledge_resize(game->display);
#ifdef LIBSUPERDERPY_IMGUI
			ImGui_ImplAllegro5_CreateDeviceObjects();
#endif

			// SetupViewport can be expensive, so don't do it when the resize event is already outdated or doesn't change anything
			if (((ev->display.width != game->_priv.window_width) || (ev->display.height != game->_priv.window_height)) &&
				(ev->display.width == al_get_display_width(game->display)) && (ev->display.height == al_get_display_height(game->display))) {
				SetupViewport(game);
			}

			break;
		case ALLEGRO_EVENT_KEY_DOWN:
#ifdef ALLEGRO_ANDROID
			if ((ev->keyboard.keycode == ALLEGRO_KEY_MENU) || (ev->keyboard.keycode == ALLEGRO_KEY_TILDE) || (ev->keyboard.keycode == ALLEGRO_KEY_BACKQUOTE)) {
#else
			if ((ev->keyboard.keycode == ALLEGRO_KEY_TILDE) || (ev->keyboard.keycode == ALLEGRO_KEY_BACKQUOTE)) {
#endif
				game->_priv.showconsole = !game->_priv.showconsole;
				if ((ev->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) && (game->config.debug.enabled)) {
					game->_priv.showtimeline = game->_priv.showconsole;
				}
			}

			if (ev->keyboard.keycode == ALLEGRO_KEY_F12) {
				DrawGamestates(game);
				int flags = al_get_new_bitmap_flags();
				al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
				ALLEGRO_BITMAP* bitmap = al_create_bitmap(al_get_display_width(game->display), al_get_display_height(game->display));
				al_set_new_bitmap_flags(flags);
				ALLEGRO_BITMAP* target = al_get_target_bitmap();
				al_set_target_bitmap(bitmap);
				al_draw_bitmap(al_get_backbuffer(game->display), 0, 0, 0);
				al_set_target_bitmap(target);
				PrintConsole(game, "Screenshot made! Storing...");

				struct ScreenshotThreadData* data = malloc(sizeof(struct ScreenshotThreadData));
				data->game = game;
				data->bitmap = bitmap;
#ifndef LIBSUPERDERPY_SINGLE_THREAD
				al_run_detached_thread(ScreenshotThread, data);
#else
				ScreenshotThread(data);
#endif
			}

			break;
		default:
			break;
	}

#ifdef MAEMO5
	// on Maemo we get mouse events instead of touch ones, so we'll rewrite them by ourselves

	if ((ev->type == ALLEGRO_EVENT_MOUSE_AXES) || (ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) || (ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_UP)) {
		switch (ev->type) {
			case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
				ev->type = ALLEGRO_EVENT_TOUCH_BEGIN;
				break;
			case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
				ev->type = ALLEGRO_EVENT_TOUCH_END;
				break;
			case ALLEGRO_EVENT_MOUSE_AXES:
				ev->type = ALLEGRO_EVENT_TOUCH_MOVE;
				break;
			default:
				break;
		}
		ALLEGRO_DISPLAY* display = ev->mouse.display;
		float dx = ev->mouse.dx;
		float dy = ev->mouse.dy;
		float x = ev->mouse.x;
		float y = ev->mouse.y;
		double timestamp = ev->mouse.timestamp;

		ev->touch.display = display;
		ev->touch.dx = dx;
		ev->touch.dy = dy;
		ev->touch.id = 0;
		ev->touch.primary = true;
		ev->touch.source = (ALLEGRO_TOUCH_INPUT*)al_get_touch_input_event_source();
		ev->touch.timestamp = timestamp;
		ev->touch.x = x;
		ev->touch.y = y;
	}
#endif
}

static inline void HandleDebugEvent(struct Game* game, ALLEGRO_EVENT* ev) {
	switch (ev->type) {
		case ALLEGRO_EVENT_KEY_DOWN:
			switch (ev->keyboard.keycode) {
				case ALLEGRO_KEY_F1:
					if (!game->_priv.paused) {
						PauseExecution(game);
					} else {
						ReloadCode(game);
						ResumeExecution(game);
					}
					break;
				case ALLEGRO_KEY_F9:
					game->_priv.speed = ALLEGRO_BPS_TO_SECS(60.0);
					game->_priv.showconsole = true;
					PrintConsole(game, "DEBUG: Gameplay speed: 1.00x");
					break;
				case ALLEGRO_KEY_F10: {
					double speed = ALLEGRO_BPS_TO_SECS(game->_priv.speed); // inverting
					speed -= 10;
					if (speed < 10) { speed = 10; }
					game->_priv.speed = ALLEGRO_BPS_TO_SECS(speed);
					game->_priv.showconsole = true;
					PrintConsole(game, "DEBUG: Gameplay speed: %.2fx", speed / 60.0);
				} break;
				case ALLEGRO_KEY_F11: {
					double speed = ALLEGRO_BPS_TO_SECS(game->_priv.speed); // inverting
					speed += 10;
					if (speed > 600) { speed = 600; }
					game->_priv.speed = ALLEGRO_BPS_TO_SECS(speed);
					game->_priv.showconsole = true;
					PrintConsole(game, "DEBUG: Gameplay speed: %.2fx", speed / 60.0);
				} break;
			}

			break;
		default:
			break;
	}
}

static inline bool MainloopEvents(struct Game* game) {
	do {
		ALLEGRO_EVENT ev;

		if (game->_priv.paused && !IS_EMSCRIPTEN) {
			// there's no frame flipping when paused, so avoid pointless busylooping
			al_wait_for_event(game->_priv.event_queue, &ev);
		} else if (!al_get_next_event(game->_priv.event_queue, &ev)) {
			break;
		}

#ifdef LIBSUPERDERPY_IMGUI
		ImGui_ImplAllegro5_ProcessEvent(&ev);
		switch (ev.type) {
			case ALLEGRO_EVENT_KEY_CHAR:
			case ALLEGRO_EVENT_KEY_DOWN:
			case ALLEGRO_EVENT_KEY_UP:
				if (igGetIO()->WantCaptureKeyboard) {
					continue;
				}
				break;
			case ALLEGRO_EVENT_MOUSE_AXES:
			case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
			case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
			case ALLEGRO_EVENT_TOUCH_BEGIN:
			case ALLEGRO_EVENT_TOUCH_CANCEL:
			case ALLEGRO_EVENT_TOUCH_END:
			case ALLEGRO_EVENT_TOUCH_MOVE:
				if (igGetIO()->WantCaptureMouse) {
					continue;
				}
				break;
			default:
				break;
		}
#endif

		if (game->_priv.params.handlers.event) {
			if ((*game->_priv.params.handlers.event)(game, &ev)) {
				continue;
			}
		}

		if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
			EventGamestates(game, &ev);
			return false;
		}

		HandleEvent(game, &ev);

		if (game->config.debug.enabled) {
			HandleDebugEvent(game, &ev);
		}

		EventGamestates(game, &ev);

	} while (!al_is_event_queue_empty(game->_priv.event_queue));
	return true;
}

static inline bool MainloopTick(struct Game* game) {
	if (game->_priv.paused) {
		return true;
	}

	struct Gamestate* tmp = game->_priv.gamestates;

#ifdef __EMSCRIPTEN__
	emscripten_pause_main_loop();
#endif

	game->_priv.loading.to_load = 0;
	game->_priv.loading.loaded = 0;
	game->_priv.loading.lock = true;
	game->loading.progress = 0;

	// TODO: support gamestate dependences/ordering
	while (tmp) {
		if (tmp->pending_stop) {
			PrintConsole(game, "Stopping gamestate \"%s\"...", tmp->name);
			game->_priv.current_gamestate = tmp;
			(*tmp->api->stop)(game, tmp->data);
			tmp->started = false;
			tmp->pending_stop = false;
			PrintConsole(game, "Gamestate \"%s\" stopped successfully.", tmp->name);
		}

		if (tmp->pending_load) { game->_priv.loading.to_load++; }
		tmp = tmp->next;
	}

	tmp = game->_priv.gamestates;

	while (tmp) {
		if (tmp->pending_unload) {
#ifdef __EMSCRIPTEN__
			al_detach_voice(game->audio.v);
#endif
			PrintConsole(game, "Unloading gamestate \"%s\"...", tmp->name);
			tmp->loaded = false;
			tmp->pending_unload = false;
			game->_priv.current_gamestate = tmp;
			(*tmp->api->unload)(game, tmp->data);
			PrintConsole(game, "Gamestate \"%s\" unloaded successfully.", tmp->name);
#ifdef __EMSCRIPTEN__
			al_attach_mixer_to_voice(game->audio.mixer, game->audio.v);
#endif
		}
		if (tmp->pending_load) {
#ifdef __EMSCRIPTEN__
			al_detach_voice(game->audio.v);
#endif
			if (tmp->show_loading && game->_priv.loading.gamestate->open) {
				(*game->_priv.loading.gamestate->api->start)(game, game->_priv.loading.gamestate->data);
			}

			if (!tmp->api) {
				if (!OpenGamestate(game, tmp, true) || !LinkGamestate(game, tmp)) {
					tmp->pending_load = false;
					tmp->pending_start = false;
					continue;
				}
			}
			if (tmp->api) {
				PrintConsole(game, "Loading gamestate \"%s\"...", tmp->name);
				game->_priv.loading.progress = 0;

				game->_priv.loading.current = tmp;
				game->_priv.current_gamestate = tmp;

				struct GamestateLoadingThreadData data = {.game = game, .gamestate = tmp, .bitmap_flags = al_get_new_bitmap_flags()};
				game->_priv.loading.in_progress = true;
				double time = al_get_time();
				game->_priv.loading.time = time;

				CalculateProgress(game);
				if (tmp->show_loading) {
					game->loading.shown = true;
					DrawGamestates(game);
					DrawConsole(game);
					al_flip_display();
#ifdef __EMSCRIPTEN__
					emscripten_sleep(0);
#endif
				}
#ifndef LIBSUPERDERPY_SINGLE_THREAD
				al_run_detached_thread(GamestateLoadingThread, &data);
				while (game->_priv.loading.in_progress) {
					double delta = al_get_time() - game->_priv.loading.time;
					game->time += delta; // TODO: ability to disable passing time during loading
					game->_priv.loading.time += delta;
					if (game->loading.shown && game->_priv.loading.gamestate->open) {
						(*game->_priv.loading.gamestate->api->logic)(game, game->_priv.loading.gamestate->data, delta);
					}
					DrawGamestates(game);
					if (game->_priv.texture_sync) {
						al_convert_memory_bitmaps();
						game->_priv.texture_sync = false;
						al_signal_cond(game->_priv.texture_sync_cond);
						game->_priv.loading.time = al_get_time(); // TODO: rethink time management during loading
					}
					DrawConsole(game);
					al_flip_display();

					if (game->_priv.bsod_sync) {
						al_set_target_bitmap(NULL);
						game->_priv.bsod_sync = false;
						al_signal_cond(game->_priv.bsod_cond);
					}

					al_lock_mutex(game->_priv.bsod_mutex);
					while (game->_priv.in_bsod) {
						al_wait_cond(game->_priv.bsod_cond, game->_priv.bsod_mutex);
					}
					al_unlock_mutex(game->_priv.bsod_mutex);
				}
#else
				GamestateLoadingThread(&data);
				DrawGamestates(game);
				DrawConsole(game);
				al_flip_display();
#ifdef __EMSCRIPTEN__
				emscripten_sleep(0);
#endif
				al_convert_memory_bitmaps();
#endif

				al_set_new_bitmap_flags(data.bitmap_flags);

				ReloadShaders(game, false);

				if (tmp->api->post_load) {
					PrintConsole(game, "[%s] Post-loading...", tmp->name);
					tmp->api->post_load(game, tmp->data);
				}

				game->_priv.loading.progress++;
				CalculateProgress(game);
				PrintConsole(game, "Gamestate \"%s\" loaded successfully in %f seconds.", tmp->name, al_get_time() - time);
				game->_priv.loading.loaded++;

				DrawGamestates(game);
				DrawConsole(game);
				al_flip_display();
#ifdef __EMSCRIPTEN__
				emscripten_sleep(0);
#endif

				tmp->loaded = true;
				tmp->pending_load = false;
			}
			if (tmp->show_loading && game->_priv.loading.gamestate->open) {
				(*game->_priv.loading.gamestate->api->stop)(game, game->_priv.loading.gamestate->data);
			}
			tmp->show_loading = true;
			game->loading.shown = false;
			game->_priv.timestamp = al_get_time();
#ifdef __EMSCRIPTEN__
			al_attach_mixer_to_voice(game->audio.mixer, game->audio.v);
#endif
		}

		tmp = tmp->next;
	}