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; }
/* 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; }
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; }
/* [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; }
/* [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; }
/* 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); }
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; }
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; }
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; }
/* 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); }
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); }
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; }
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(); } } }
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; }
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; }