void fs_emu_render_texture_with_size(fs_emu_texture *texture, int x, int y, int w, int h) { fs_emu_set_texture(texture); fs_gl_blending(1); //fs_emu_texturing(0); //return; //fs_log("%d %d %d %d\n", x, y, x + w , y + h); GLfloat tex[] = { 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0 }; GLfloat vert[] = { x, y, x + w, y, x + w, y + h, x, y + h }; glColor4f(1.0, 1.0, 1.0, 1.0); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vert); glTexCoordPointer(2, GL_FLOAT, 0, tex); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); CHECK_GL_ERROR(); }
static void render_gloss(double alpha) { //fs_emu_set_texture(g_tex_screen_gloss); fs_gl_blending(1); //fs_emu_blending(0); //fs_emu_texturing(0); fs_gl_color4f(alpha, alpha, alpha, alpha); //fs_ml_color4f(alpha, 0.0, 0.0, alpha); //glBegin(GL_QUADS); //glTexCoord2f(0.0, 1.0); glVertex2f(-1.0, -1.0); //glTexCoord2f(1.0, 1.0); glVertex2f( 1.0, -1.0); //glTexCoord2f(1.0, 0.0); glVertex2f( 1.0, 1.0); //glTexCoord2f(0.0, 0.0); glVertex2f(-1.0, 1.0); fs_emu_draw_texture_with_size(TEXTURE_GLOSS, -1.0, -1.0, 2.0, 2.0); //glEnd(); }
/** * This function is called at the end of the frame rendering function */ static void handle_quit_sequence() { int fade_time = 750 * 1000; int64_t dt = fs_emu_monotonic_time() - g_fs_emu_quit_time; if (dt > fade_time && g_fs_emu_emulation_thread_stopped) { fs_emu_log("calling fs_ml_stop because emu thread is done\n"); fs_ml_stop(); } else if (dt > 5 * 1000 * 1000) { // 5 seconds has passed after shutdown was requested fs_emu_log("calling fs_ml_stop because emu does not stop\n"); // FIXME: FORCE STOP fs_ml_stop(); fs_emu_log("force-closing the emulator\n"); exit(1); } // fade out over 750ms float fade = (1.0 * dt) / fade_time; if (fade > 1.0) { fade = 1.0; } // draw fading effect fs_gl_viewport(0, 0, fs_ml_video_width(), fs_ml_video_height()); fs_gl_ortho_hd(); fs_gl_blending(1); fs_gl_texturing(0); fs_gl_color4f(0.0, 0.0, 0.0, fade); GLfloat vert[] = { 0, 0, 1920, 0, 1920, 1080, 0, 1080 }; glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vert); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); CHECK_GL_ERROR(); }
int fs_emu_font_render(fs_emu_font *font, const char *text, float x, float y, float r, float g, float b, float alpha) { if (font->image == NULL) { return 0; } if (text == NULL || *text == '\0') { return 0 ; } if (!g_initialized) { initialize(); } /* if (g_fs_ml_opengl_context_stamp != g_video_version) { GList* list = g_cache; while (list) { cache_item *item = (cache_item *) list->data; g_free(item->text); g_free(item); list = list->next; } g_list_free(g_cache); g_cache = NULL; initialize_cache(); } */ // find cached text entry, if any //sanity_check(); GList* list = g_cache; while (list) { cache_item *item = (cache_item *) list->data; if (item->font == font && strcmp(item->text, text) == 0) { break; } list = list->next; } if (list) { cache_item *item = (cache_item *) list->data; g_cache = g_list_delete_link(g_cache, list); sanity_check(); fs_gl_blending(1); fs_gl_texturing(1); //fs_emu_ortho(); //fs_emu_set_texture(NULL); fs_gl_bind_texture(g_text_texture); //glColor4f(1.0, 1.0, 1.0, alpha); //printf("rendering %f %f %f %f...\n", item->x1, item->x2, item->y1, item->y2); fs_gl_color4f(r * alpha, g * alpha, b * alpha, alpha); //glColor4f(r * alpha, g * alpha, b * alpha, alpha); GLfloat tex[] = { item->x1, item->y2, item->x2, item->y2, item->x2, item->y1, item->x1, item->y1 }; GLfloat vert[] = { x, y, x + item->width, y, x + item->width, y + item->height, x, y + item->height }; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vert); glTexCoordPointer(2, GL_FLOAT, 0, tex); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); g_cache = g_list_prepend(g_cache, item); sanity_check(); return item->width; } // calculate size of text //printf(":: %s\n", text); int chars = 0; int required_width = 0; int required_height = font->h; unsigned char *cp = (unsigned char *) text; for(; *cp; cp++) { unsigned char c = *cp; //printf(" %p\n", font); //printf(" %d\n", c); //printf(" %d\n", font->w[c]); if (required_width + font->w[c] > TEXTURE_WIDTH) { break; } required_width += font->w[c]; chars++; } //fs_log("width: %d, height: %d\n", required_width, required_height); //float tw = font->texture->width; //float th = font->texture->height; // FIXME: clear g_buffer //int length = strlen(text); //for (int i = 0; i < length; i++) { cp = (unsigned char *) text; //glBegin(GL_QUADS); //glColor4f(1.0, 1.0, 1.0, 1.0); //int x2 = 0; int dx = 0; int dy = 0; for(int i = 0; i < chars; i++) { unsigned char c = *cp++; //unsigned char = (unsigned char) text[i]; int sx = font->x[c]; int sy = font->y[c]; int sw = font->w[c]; int sh = font->h; //printf("%d %d %d %d\n", sx, sy, sw, sh); // draw character int *sl = ((int *) font->image->data) + font->image->width * sy + sx; int ss = font->image->width; // source stride //int *sl = sp; int *dl = ((int *) g_buffer) + TEXTURE_WIDTH * dy + dx; int ds = TEXTURE_WIDTH; // destination stride //int *dl = dp; for (int y = 0; y < sh; y++) { //printf("%d\n", y); int *sp = sl; int *dp = dl; for (int x = 0; x < sw; x++) { //printf("%d %d\n", x, y); //*dp++ = 0xff0000ff; *dp++ = *sp++; //int a = *sp++; } sl += ss; dl += ds; } dx += sw; /* //fs_log("%d %d %d %d\n", font->x[c], font->y[c], w, h); float s1 = font->x[c] / tw; float s2 = (font->x[c] + w) / tw; //double t1 = 1.0 - (font->y[c]) / th; //double t2 = 1.0 - (font->y[c] + h) / th; float t1 = (font->y[c]) / th; float t2 = (font->y[c] + h) / th; //fs_log("%d %d %d %d\n", x, y, w, h); glTexCoord2f(s1, t2); //glVertex2f(x, y); glVertex2f(x2, 0); glTexCoord2f(s2, t2); //glVertex2f(x + w, y); glVertex2f(x2 + w, 0); glTexCoord2f(s2, t1); //glVertex2f(x + w, y + h); glVertex2f(x2 + w, h); glTexCoord2f(s1, t1); //glVertex2f(x, y + h); glVertex2f(x2, h); x2 += w; */ } //printf("...\n"); /* glEnd(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopAttrib(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glPopMatrix(); glDeleteFramebuffersEXT(1, &frame_buffer); //glDeleteRenderbuffersEXT(1, &depth_buffer); fs_emu_set_texture(NULL); if (mipmapping) { fs_gl_bind_texture(render_texture); glGenerateMipmapEXT(GL_TEXTURE_2D); fs_gl_bind_texture(0); } */ GList *last = g_list_last(g_cache); cache_item *last_item = (cache_item *) last->data; int position = last_item->position; fs_gl_bind_texture(g_text_texture); #ifndef HAVE_GLES fs_gl_unpack_row_length(TEXTURE_WIDTH); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, position * 32, required_width, required_height, fs_emu_get_video_format(), GL_UNSIGNED_BYTE, g_buffer); #else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, required_width, required_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, g_buffer); for (int y = 0; y < required_height; y++) { char *row = g_buffer + ((y + position * 32)*TEXTURE_WIDTH) * 4; glTexSubImage2D(GL_TEXTURE_2D, 0, 0, position * 32, required_width, 1, GL_RGBA, GL_UNSIGNED_BYTE, row); } #endif cache_item *item = g_malloc(sizeof(cache_item)); item->font = font; item->text = g_strdup(text); item->width = required_width; item->height = required_height; item->position = position; item->x1 = 0; item->x2 = required_width / (1.0 * TEXTURE_WIDTH); item->y1 = (item->position * 32) / (1.0 * TEXTURE_HEIGHT); item->y2 = (item->position * 32 + required_height) / (1.0 * TEXTURE_HEIGHT); //item->texture = render_texture; g_cache = g_list_prepend(g_cache, item); sanity_check(); if (last_item->text) { g_free(last_item->text); } /* if (last_item->texture) { glDeleteTextures(1, &last_item->texture); } */ g_free(last_item); g_cache = g_list_delete_link(g_cache, last); sanity_check(); // now the text is in the cache, so call function again return fs_emu_font_render(font, text, x, y, r, g, b, alpha); }
void fs_emu_video_render_function() { static int initialized_menu = 0; if (!initialized_menu) { // render menu once (without really showing it, so all menu // resources are initialized and loaded, -prevents flickering // when really opening the menu later fs_emu_render_menu(g_menu_transition); initialized_menu = 1; } if (g_fs_emu_video_debug) { int quarter_height = fs_ml_video_height() / 4; fs_gl_viewport(0, quarter_height, fs_ml_video_width(), fs_ml_video_height() - quarter_height); } else { fs_gl_viewport(0, 0, fs_ml_video_width(), fs_ml_video_height()); } // FIXME: can perhaps remove this soon.. fs_emu_video_render_mutex_lock(); int in_menu = fs_emu_menu_is_active(); if (in_menu && g_menu_transition_target < 1.0) { g_menu_transition_target = 1.0; } if (!in_menu && g_menu_transition_target > 0.0) { g_menu_transition_target = 0.0; } // FIXME: ideally, we would use time-based animation - for now, we use a // simple frame-based animation if (g_menu_transition < g_menu_transition_target) { if (g_menu_transition_target == 1.0) { g_menu_transition += 0.10; } } if (g_menu_transition > g_menu_transition_target) { if (g_menu_transition_target == 0.0) { g_menu_transition -= 0.10; } } if (g_menu_transition > 1.0) { g_menu_transition = 1.0; } else if (g_menu_transition < 0.0) { g_menu_transition = 0.0; } int matrix_pushed = 0; double t0_x = 0.0; double t0_y = 0.0; double t0_z = -2.42; double r0_a = 0.0; double t1_x = -0.31; //double t1_y = -0.04; double t1_y = 0.0; double t1_z = -3.7; double r1_a = 30.0; int perspective = 0; if (g_menu_transition == 0.0) { perspective = 0; fs_gl_ortho(); //glTranslated(1920.0 / 2.0, 1080.0 / 2.0, 0.0); //glScaled(1920.0 / 2.0, 1080.0 / 2.0, 1.0); } else { perspective = 1; glClearColor(0.1, 0.1, 0.1, 1.0); glClear(GL_DEPTH_BUFFER_BIT); CHECK_GL_ERROR(); fs_gl_ortho_hd(); // transition y-coordinate between floor and wall int splt = 361; fs_gl_blending(FALSE); fs_gl_texturing(FALSE); GLfloat color[] = { 39.0 / 255.0, 44.0 / 255.0, 51.0 / 255.0, 1.0, 39.0 / 255.0, 44.0 / 255.0, 51.0 / 255.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 20.0 / 255.0, 22.0 / 255.0, 26.0 / 255.0, 1.0, 20.0 / 255.0, 22.0 / 255.0, 26.0 / 255.0, 1.0 }; GLfloat vert[] = { 0, splt, -0.9, 1920, splt, -0.9, 1920, 1020, -0.9, 0, 1020, -0.9, 0, 1020, -0.9, 1920, 1020, -0.9, 1920, 1080, -0.9, 0, 1080, -0.9, 0, 0, -0.9, 1920, 0, -0.9, 1920, splt, -0.9, 0, splt, -0.9 }; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glColorPointer(4, GL_FLOAT, 0, color); glVertexPointer(3, GL_FLOAT, 0, vert); glDrawArrays(GL_TRIANGLE_FAN, 0, 12); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); CHECK_GL_ERROR(); fs_gl_perspective(); double t_x = t0_x + (t1_x - t0_x) * g_menu_transition; double t_y = t0_y + (t1_y - t0_y) * g_menu_transition; double t_z = t0_z + (t1_z - t0_z) * g_menu_transition; double r_a = r0_a + (r1_a - r0_a) * g_menu_transition; glPushMatrix(); matrix_pushed = 1; glScaled(16.0 / 9.0, 1.0, 1.0); glTranslated(t_x, t_y, t_z); glRotated(r_a, 0.0, 1.0, 0.0); CHECK_GL_ERROR(); } if (perspective) { render_glow(g_menu_transition); } if (perspective) { glPushMatrix(); glTranslatef(0.0, -2.0, 0.0); //glTranslatef(0.0, -1.0, 0.0); //glScalef(1.0, -1.0, 1.0); glScalef(1.0, -0.5, 1.0); glTranslatef(0.0, -1.0, 0.0); CHECK_GL_ERROR(); render_frame(0.33, perspective); CHECK_GL_ERROR(); render_gloss(g_menu_transition * 0.66); CHECK_GL_ERROR(); glPopMatrix(); CHECK_GL_ERROR(); } render_frame(1.0, perspective); if (perspective) { render_gloss(g_menu_transition); } /* if (fs_emu_is_paused()) { render_pause_fade(); } */ if (matrix_pushed) { glPopMatrix(); CHECK_GL_ERROR(); matrix_pushed = 0; } fs_emu_acquire_gui_lock(); fs_emu_render_chat(); //if (fs_emu_menu_is_active()) { if (g_menu_transition > 0.0) { fs_emu_render_menu(g_menu_transition); } fs_emu_render_dialog(); fs_emu_release_gui_lock(); if (g_fs_emu_hud_mode && fs_emu_netplay_enabled()) { fs_gl_ortho_hd(); fs_gl_texturing(0); fs_gl_blending(1); fs_gl_color4f(0.0, 0.0, 0.0, 0.5); GLfloat vert[] = { 0, 1030, 1920, 1030, 1920, 1080, 0, 1080 }; glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vert); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); CHECK_GL_ERROR(); #if 0 glBegin(GL_QUADS); glVertex2f(0, 1030); glVertex2f(1920, 1030); fs_gl_color4f(0.0, 0.0, 0.0, 0.0); glVertex2f(1920, 1030 - 50); glVertex2f(0, 1030 - 50); glEnd(); #endif fs_emu_font *menu_font = fs_emu_font_get_menu(); char *str; for (int i = 0; i < MAX_PLAYERS; i++) { fs_emu_player *player = g_fs_emu_players + i; int x = i * 1920 / 6 + 20; int y = 1038; int rendered_tag = 0; if (player->tag && player->tag[0]) { str = g_strdup_printf("%s", player->tag); fs_emu_font_render(menu_font, str, x, y, 1.0, 1.0, 1.0, 1.0); g_free(str); rendered_tag = 1; } if (rendered_tag || player->ping) { str = g_strdup_printf("%03d", player->ping); fs_emu_font_render(menu_font, str, x + 100, y, 1.0, 1.0, 1.0, 1.0); g_free(str); } if (rendered_tag || player->lag) { str = g_strdup_printf("%03d", player->lag); fs_emu_font_render(menu_font, str, x + 200, y, 1.0, 1.0, 1.0, 1.0); g_free(str); } } } if (g_fs_emu_video_debug) { int quarter_height = fs_ml_video_height() / 4; fs_gl_viewport(0, 0, fs_ml_video_width(), quarter_height); CHECK_GL_ERROR(); fs_emu_set_texture(NULL); CHECK_GL_ERROR(); static GLuint debug_texture = 0; static uint32_t *debug_texture_data = NULL; if (debug_texture == 0) { debug_texture_data = g_malloc0(256 * 256 * 4); glGenTextures(1, &debug_texture); CHECK_GL_ERROR(); fs_gl_bind_texture(debug_texture); #ifndef HAVE_GLES fs_gl_unpack_row_length(0); #endif glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); CHECK_GL_ERROR(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); CHECK_GL_ERROR(); } else { fs_gl_bind_texture(debug_texture); CHECK_GL_ERROR(); } memset(debug_texture_data, 0x00, 256 * 256 * 4); CHECK_GL_ERROR(); fs_emu_video_render_debug_info(debug_texture_data); CHECK_GL_ERROR(); fs_emu_audio_render_debug_info(debug_texture_data); CHECK_GL_ERROR(); #ifndef HAVE_GLES fs_gl_unpack_row_length(0); #endif CHECK_GL_ERROR(); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, debug_texture_data); CHECK_GL_ERROR(); fs_gl_ortho_hd(); fs_gl_texturing(1); fs_gl_blending(0); fs_gl_color4f(1.0, 1.0, 1.0, 1.0); GLfloat tex[] = { 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0 }; GLfloat vert[] = { 0, 0, 1920, 0, 1920, 1080, 0, 1080 }; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, 0, tex); glVertexPointer(2, GL_FLOAT, 0, vert); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); CHECK_GL_ERROR(); glPushMatrix(); glScalef(1.0, 4.0, 1.0); fs_emu_font *menu_font = fs_emu_font_get_menu(); char *str; /* str = g_strdup_printf("%d", fs_emu_get_audio_frequency()); fs_emu_font_render(menu_font, str, 1920 / 2 + 20, 3, 1.0, 1.0, 1.0, 1.0); g_free(str); */ str = g_strdup_printf("%0.1f", fs_emu_audio_get_measured_avg_buffer_fill(0) / 1000.0); fs_emu_font_render(menu_font, str, 1920 / 2 + 220, 3, 1.0, 1.0, 1.0, 1.0); g_free(str); str = g_strdup_printf("%d", g_fs_emu_audio_buffer_underruns); fs_emu_font_render(menu_font, str, 1920 / 2 + 420, 3, 1.0, 1.0, 1.0, 1.0); g_free(str); fs_emu_font_render(menu_font, "EMU", 20, 3, 1.0, 1.0, 1.0, 1.0); str = g_strdup_printf("%0.1f", fs_emu_get_average_emu_fps()); fs_emu_font_render(menu_font, str, 220, 3, 1.0, 1.0, 1.0, 1.0); g_free(str); str = g_strdup_printf("%d", g_fs_emu_lost_frames); fs_emu_font_render(menu_font, str, 420, 3, 1.0, 1.0, 1.0, 1.0); g_free(str); str = g_strdup_printf("%d", g_fs_emu_repeated_frames); fs_emu_font_render(menu_font, str, 620, 3, 1.0, 1.0, 1.0, 1.0); g_free(str); fs_emu_font_render(menu_font, "SYS", 20, 140, 1.0, 1.0, 1.0, 1.0); str = g_strdup_printf("%0.1f", fs_emu_get_average_sys_fps()); fs_emu_font_render(menu_font, str, 220, 140, 1.0, 1.0, 1.0, 1.0); g_free(str); str = g_strdup_printf("%d", g_fs_emu_lost_vblanks); fs_emu_font_render(menu_font, str, 420, 140, 1.0, 1.0, 1.0, 1.0); g_free(str); glPopMatrix(); CHECK_GL_ERROR(); } if (fs_emu_is_quitting()) { handle_quit_sequence(); } fs_emu_video_render_mutex_unlock(); }
static void render_glow(double opacity) { //printf("--- render glow ---\n"); float tx1, ty1, tx2, ty2; //const double dx = 0.1 * 9.0 / 16.0; const double dx = 0.15; const double dy = 0.15 * 16.0 / 9.0; const double z = 0.0; const double s = 0.65 * opacity; fs_gl_color4f(s, s, s, s); fs_gl_blending(1); //fs_emu_set_texture(g_tex_glow_top); fs_emu_prepare_texture(TEXTURE_GLOW_TOP, &tx1, &ty1, &tx2, &ty2); // render top edge GLfloat tex[] = { tx1, ty2, tx2, ty2, tx2, ty1, tx1, ty1 }; GLfloat vert[] = { -1.0 + dx, 1.0 - dy, z, 1.0 - dx, 1.0 - dy, z, 1.0 - dx, 1.0 + dy, z, -1.0 + dx, 1.0 + dy, z }; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(3, GL_FLOAT, 0, vert); glTexCoordPointer(2, GL_FLOAT, 0, tex); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); CHECK_GL_ERROR(); // render corners fs_emu_prepare_texture(TEXTURE_GLOW_TOP_LEFT, &tx1, &ty1, &tx2, &ty2); GLfloat tex2[] = { // top left corner tx1, ty2, tx2, ty2, tx2, ty1, tx1, ty1, // top right corner tx2, ty2, tx1, ty2, tx1, ty1, tx2, ty1 }; GLfloat vert2[] = { // top left corner -1.0 - dx, 1.0 - dy, z, -1.0 + dx, 1.0 - dy, z, -1.0 + dx, 1.0 + dy, z, -1.0 - dx, 1.0 + dy, z, // top right corner 1.0 - dx, 1.0 - dy, z, 1.0 + dx, 1.0 - dy, z, 1.0 + dx, 1.0 + dy, z, 1.0 - dx, 1.0 + dy, z }; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vert2); glTexCoordPointer(2, GL_FLOAT, 0, tex2); glDrawArrays(GL_TRIANGLE_FAN, 0, 8); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); CHECK_GL_ERROR(); // render left and right edge fs_emu_prepare_texture(TEXTURE_GLOW_LEFT, &tx1, &ty1, &tx2, &ty2); //fs_emu_set_texture(g_tex_glow_left); GLfloat color3[] = { // left edge s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, // right edge s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, // left edge bottom 0, 0, 0, 0, 0, 0, 0, 0, s, s, s, s, s, s, s, s, // right edge bottom 0, 0, 0, 0, 0, 0, 0, 0, s, s, s, s, s, s, s, s, }; GLfloat tex3[] = { // left edge tx1, ty2, tx2, ty2, tx2, ty1, tx1, ty1, // right edge tx2, ty2, tx1, ty2, tx1, ty1, tx2, ty1, // left edge bottom tx1, ty2, tx2, ty2, tx2, ty1, tx1, ty1, // right edge bottom tx2, ty2, tx1, ty2, tx1, ty1, tx2, ty1 }; GLfloat vert3[] = { // left edge -1.0 - dx, -0.5, z, -1.0 + dx, -0.5, z, -1.0 + dx, 1.0 - dy, z, -1.0 - dx, 1.0 - dy, z, // right edge 1.0 - dx, -0.5, z, 1.0 + dx, -0.5, z, 1.0 + dx, 1.0 - dy, z, 1.0 - dx, 1.0 - dy, z, // left edge bottom -1.0 - dx, -1.0, z, -1.0 + dx, -1.0, z, -1.0 + dx, -0.5, z, -1.0 - dx, -0.5, z, // right edge bottom 1.0 - dx, -1.0, z, 1.0 + dx, -1.0, z, 1.0 + dx, -0.5, z, 1.0 - dx, -0.5, z }; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glColorPointer(4, GL_FLOAT, 0, color3); glVertexPointer(3, GL_FLOAT, 0, vert3); glTexCoordPointer(2, GL_FLOAT, 0, tex3); glDrawArrays(GL_TRIANGLE_FAN, 0, 16); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); CHECK_GL_ERROR(); //printf("--- render glow done ---\n"); }
static void render_frame(double alpha, int perspective) { //printf("--- render frame ---\n"); //float t = g_snes_height / 512.0; //fs_log("%d %d %d %d\n", g_crop.x, g_crop.y, g_crop.w, g_crop.h); double s1; double s2; double t1; double t2; double emu_aspect; if (g_fs_emu_video_crop_mode) { //if (g_viewport_mode == FS_EMU_VIEWPORT_MODE_CROP) { s1 = (double) g_crop.x / g_frame_texture_width; s2 = (double) (g_crop.x + g_crop.w) / g_frame_texture_width; t1 = (double) g_crop.y / g_frame_texture_height; t2 = (double) (g_crop.y + g_crop.h) / g_frame_texture_height; emu_aspect = (double) g_crop.w / (double) g_crop.h; } else { s1 = 0.0; s2 = (double) g_frame_width / g_frame_texture_width; t1 = 0.0; t2 = (double) g_frame_height / g_frame_texture_height; emu_aspect = (double) g_frame_width / (double) g_frame_height; } emu_aspect *= g_frame_aspect; double x1 = -1.0; double x2 = 1.0; double y1 = -1.0; double y2 = 1.0; double repeat_right_border = 0; //int repeat_bottom_border = 0; if (fs_emu_video_get_aspect_correction()) { double screen_aspect = (double) fs_ml_video_width() / (double) fs_ml_video_height(); if (emu_aspect > screen_aspect) { // emu video is wider than screen double h = screen_aspect / emu_aspect; //double padding = (2.0 - 2.0 * h) / 2.0; double padding = 1.0 - h; if (g_effective_viewport_mode == FS_EMU_VIEWPORT_MODE_CROP) { y1 += padding; y2 -= padding; } else { // FS_EMU_VIEWPORT_MODE_CENTER t1 -= padding / 2.0; t2 += padding / 2.0; //y2 -= padding; } } else { double w = emu_aspect / screen_aspect; //double padding = (2.0 - 2.0 * w) / 2.0; double padding = 1.0 - w; if (g_effective_viewport_mode == FS_EMU_VIEWPORT_MODE_CROP) { x1 += padding; x2 -= padding; } else { // FS_EMU_VIEWPORT_MODE_CENTER //s1 -= padding / 4.0; // FIXME: THIS IS WRONG s1 -= padding / 2.0; //s2 += padding / 2.0; x2 -= padding; //repeat_right_border = x2; repeat_right_border = 1.0 - padding; } } } // if video is not stretched, we render black rectangles to cover // the rest of the screen if (x1 > -1.0 || x2 < 1.0 || y1 > -1.0 || y2 < 1.0) { fs_gl_texturing(0); if (alpha < 1.0) { fs_gl_blending(1); fs_gl_color4f(0.0, 0.0, 0.0, alpha); } else { fs_gl_blending(0); fs_gl_color4f(0.0, 0.0, 0.0, 1.0); } glEnableClientState(GL_VERTEX_ARRAY); if (x1 > -1.0) { GLfloat vert[] = { -1.0, y1, x1, y1, x1, y2, -1.0, y2 }; glVertexPointer(2, GL_FLOAT, 0, vert); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); CHECK_GL_ERROR(); } if (x2 < 1.0) { GLfloat vert[] = { x2, y1, 1.0, y1, 1.0, y2, x2, y2 }; glVertexPointer(2, GL_FLOAT, 0, vert); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); CHECK_GL_ERROR(); } if (y1 > -1.0) { GLfloat vert1[] = { x1, -1.0, x2, -1.0, x2, y1, x1, y1 }; GLfloat vert2[] = { -1.0, -1.0, -0.1, -1.0, -1.0, 0.0, -1.0, y1, 0.0, -1.0, y1, -0.1 }; glVertexPointer(2, GL_FLOAT, 0, vert1); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glVertexPointer(3, GL_FLOAT, 0, vert2); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); CHECK_GL_ERROR(); } if (y2 < 1.0) { GLfloat vert1[] = { x1, y2, x2, y2, x2, 1.0, x1, 1.0 }; GLfloat vert2[] = { -1.0, y2, -0.1, -1.0, y2, 0.0, -1.0, 1.0, 0.0, -1.0, 1.0, -0.1 }; glVertexPointer(2, GL_FLOAT, 0, vert1); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glVertexPointer(3, GL_FLOAT, 0, vert2); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); CHECK_GL_ERROR(); } glDisableClientState(GL_VERTEX_ARRAY); } //printf("--- render frame done ---\n"); if (perspective) { // render left side in 3d mode fs_gl_blending(0); if (x1 > -1.0) { // emu screen does not reach screen edge - side will be black fs_gl_texturing(0); fs_gl_color4f(0.0, 0.0, 0.0, alpha); } else { fs_gl_texturing(1); fs_gl_bind_texture(g_frame_texture); fs_gl_color4f(0.33 * alpha, 0.33 * alpha, 0.33 * alpha, alpha); } GLfloat tex[] = { s1, t2, s1, t2, s1, t1, // TODO: is s1 on this line a bug? s1, t1 }; GLfloat vert[] = { -1.0, y1, -0.1, -1.0, y1, 0.0, -1.0, y2, 0.0, -1.0, y2, -0.1 }; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(3, GL_FLOAT, 0, vert); glTexCoordPointer(2, GL_FLOAT, 0, tex); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); CHECK_GL_ERROR(); } float color = 1.0; if (g_frame_texture == 0) { // texture has not been created yet color = 0.0; fs_gl_texturing(0); } else { fs_gl_texturing(1); fs_gl_bind_texture(g_frame_texture); } if (alpha < 1.0) { fs_gl_blending(1); fs_gl_color4f(color * alpha, color * alpha, color * alpha, alpha); } else { fs_gl_blending(0); fs_gl_color4f(color, color, color, 1.0); } GLfloat tex[] = { s1, t2, s2, t2, s2, t1, s1, t1 }; GLfloat vert[] = { x1, y1, x2, y1, x2, y2, x1, y2 }; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vert); glTexCoordPointer(2, GL_FLOAT, 0, tex); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); CHECK_GL_ERROR(); //repeat_right_border = 0; if (repeat_right_border > 0.0) { s1 = s2 = (double) (g_frame_width - 1) / g_frame_texture_width; GLfloat tex[] = { s1, t2, s2, t2, s2, t1, s1, t1 }; GLfloat vert[] = { repeat_right_border, y1, 1.0, y1, 1.0, y2, repeat_right_border, y2 }; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vert); glTexCoordPointer(2, GL_FLOAT, 0, tex); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); CHECK_GL_ERROR(); // so the following code does not render black rectangle over // the right border x2 = 1.0; } }
void fs_emu_video_render_debug_info(uint32_t *texture) { //return; int x; //, y; int y1; GList *link; uint32_t color = 0x80404080; fs_gl_ortho_hd(); fs_gl_blending(TRUE); fs_gl_texturing(FALSE); // render debug triangles, these are for visually debugging vblank // synchronization y1 = 0; color = 0x80800080; static int start_add = 0; int add = start_add; for (int x = 0; x < 256; x++) { int y2 = add % 20; for (int y = y1; y < y2; y++) { *(texture + (((255 - y) * 256) + x)) = color; } add += 2; } start_add += 2; x = 127; y1 = 128; color = 0x80404080; link = g_queue_peek_head_link(g_fs_emu_sys_frame_times.queue); while (link) { int val = GPOINTER_TO_INT(link->data); //int x2 = x - 8; int y2 = y1 + val * VIDEO_DEBUG_SCALE_TIMES; if (y2 > 256) { y2 = 256; } for (int y = y1; y < y2; y++) { *(texture + ((y * 256) + x)) = color; } if (--x < 0) { break; } link = link->next; } x = 127; y1 = 0; color = 0x80205080; link = g_queue_peek_head_link(g_fs_emu_emu_frame_times.queue); while (link) { int val = GPOINTER_TO_INT(link->data); //int x2 = x - 8; int y2 = y1 + val * VIDEO_DEBUG_SCALE_TIMES; if (y2 > 256) { y2 = 256; } for (int y = y1; y < y2; y++) { *(texture + ((y * 256) + x)) = color; } if (--x < 0) { break; } link = link->next; } }
int fs_emu_font_render(fs_emu_font *font, const char *text, float x, float y, float r, float g, float b, float alpha) { if (font == NULL || font->image == NULL) { return 0; } if (text == NULL || *text == '\0') { return 0 ; } if (!g_initialized) { initialize(); } // find cached text entry, if any GList* list = g_cache; while (list) { cache_item *item = (cache_item *) list->data; if (item->font == font && strcmp(item->text, text) == 0) { break; } list = list->next; } if (list) { cache_item *item = (cache_item *) list->data; g_cache = g_list_delete_link(g_cache, list); sanity_check(); fs_gl_blending(1); fs_gl_texturing(1); //fs_emu_ortho(); //fs_emu_set_texture(NULL); fs_gl_bind_texture(g_text_texture); //glColor4f(1.0, 1.0, 1.0, alpha); //printf("rendering %f %f %f %f...\n", item->x1, item->x2, item->y1, item->y2); fs_gl_color4f(r, g, b, alpha); //glColor4f(r * alpha, g * alpha, b * alpha, alpha); #ifdef USE_GLES GLfloat tex[] = { item->x1, item->y2, item->x2, item->y2, item->x2, item->y1, item->x1, item->y1 }; GLfloat vert[] = { x, y, x + item->width, y, x + item->width, y + item->height, x, y + item->height }; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vert); glTexCoordPointer(2, GL_FLOAT, 0, tex); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); #else glBegin(GL_QUADS); glTexCoord2f(item->x1, item->y2); glVertex2f(x, y); glTexCoord2f(item->x2, item->y2); glVertex2f(x + item->width, y); glTexCoord2f(item->x2, item->y1); glVertex2f(x + item->width, y + item->height); glTexCoord2f(item->x1, item->y1); glVertex2f(x, y + item->height); glEnd(); #endif g_cache = g_list_prepend(g_cache, item); sanity_check(); return item->width; } // calculate size of text //printf(":: %s\n", text); int num_chars = 0; int required_width = 0; int required_height = font->h; //char *base_text = fs_utf8_strup(text, -1); const char *base_text = text; unsigned const char *c = (unsigned const char*) base_text; int continuations = 0; int cp = 0; while(*c) { //if ((*c & 0b10000000) == 0b00000000) { if ((*c & 0x80) == 0x0) { continuations = 0; //cp = *c & 0b01111111; cp = *c & 0x7f; } //else if ((*c & 0b11000000) == 0b10000000) { else if ((*c & 0xc0) == 0x80) { continuations--; cp = cp << 6; //cp = cp | (*c & 0b00111111); cp = cp | (*c & 0x3f); } //else if ((*c & 0b11111110) == 0b11111100) { // 1111110x else if ((*c & 0xfe) == 0xfc) { // 1111110x continuations = 5; //cp = *c & 0b00000001; cp = *c & 0x1; } //else if ((*c & 0b11111100) == 0b11111000) { // 111110xx else if ((*c & 0xfc) == 0xf8) { // 111110xx continuations = 4; //cp = *c & 0b00000011; cp = *c & 0x3; } //else if ((*c & 0b11111000) == 0b11110000) { // 11110xxx else if ((*c & 0xf8) == 0xf0) { // 11110xxx continuations = 3; //cp = *c & 0b00000111; cp = *c & 0x7; } //else if ((*c & 0b11110000) == 0b11100000) { // 1110xxxx else if ((*c & 0xf0) == 0xe0) { // 1110xxxx continuations = 2; //cp = *c & 0b00001111; cp = *c & 0xf; } //else if ((*c & 0b11100000) == 0b11000000) { // 110xxxxx else if ((*c & 0xe0) == 0xc0) { // 110xxxxx continuations = 1; //cp = *c & 0b00011111; cp = *c & 0x1f; } ++c; if (continuations) { continue; } cp = fix_char(font, cp); //printf("%d\n", cp); if (required_width + font->w[cp] > g_texture_width) { break; } required_width += font->w[cp]; num_chars++; } int dx = 0; int dy = 0; c = (unsigned const char*) base_text; //printf("base_text: %s\n", c); continuations = 0; cp = 0; int k = 0; while(*c) { //printf("%d\n", *c); //if ((*c & 0b10000000) == 0b00000000) { if ((*c & 0x80) == 0x0) { continuations = 0; //cp = *c & 0b01111111; cp = *c & 0x7f; } //else if ((*c & 0b11000000) == 0b10000000) { else if ((*c & 0xc0) == 0x80) { continuations--; cp = cp << 6; //cp = cp | (*c & 0b00111111); cp = cp | (*c & 0x3f); } //else if ((*c & 0b11111110) == 0b11111100) { // 1111110x else if ((*c & 0xfe) == 0xfc) { // 1111110x continuations = 5; //cp = *c & 0b00000001; cp = *c & 0x1; } //else if ((*c & 0b11111100) == 0b11111000) { // 111110xx else if ((*c & 0xfc) == 0xf8) { // 111110xx continuations = 4; //cp = *c & 0b00000011; cp = *c & 0x3; } //else if ((*c & 0b11111000) == 0b11110000) { // 11110xxx else if ((*c & 0xf8) == 0xf0) { // 11110xxx continuations = 3; //cp = *c & 0b00000111; cp = *c & 0x7; } //else if ((*c & 0b11110000) == 0b11100000) { // 1110xxxx else if ((*c & 0xf0) == 0xe0) { // 1110xxxx continuations = 2; //cp = *c & 0b00001111; cp = *c & 0xf; } //else if ((*c & 0b11100000) == 0b11000000) { // 110xxxxx else if ((*c & 0xe0) == 0xc0) { // 110xxxxx continuations = 1; //cp = *c & 0b00011111; cp = *c & 0x1f; } ++c; if (continuations) { continue; } if (++k > num_chars) { // there may be more chars left in the original string, // but there is no room for the next char in the texture break; } cp = fix_char(font, cp); int sx = font->x[cp]; int sy = font->y[cp]; int sw = font->w[cp]; int sh = font->h; //if (c > 256) { // printf("%d %d %d %d %d\n", c, sx, sy, sw, sh); //} // draw character //printf("-----------> %d\n", cp); int *sl = ((int *) font->image->data) + font->image->width * sy + sx; int ss = font->image->width; // source stride //int *sl = sp; int *dl = ((int *) g_buffer) + g_texture_width * dy + dx; int ds = g_texture_width; // destination stride //int *dl = dp; for (int y = 0; y < sh; y++) { //printf("%d\n", y); int *sp = sl; int *dp = dl; for (int x = 0; x < sw; x++) { //printf("%d %d\n", x, y); //*dp++ = 0xff0000ff; //*dp++ = *sp++; int a = *sp; sp++; *dp = a; dp++; //int a = *sp++; } sl += ss; dl += ds; } dx += sw; } //free(utext); //free(base_text); GList *last = g_list_last(g_cache); cache_item *last_item = (cache_item *) last->data; int position = last_item->position; fs_gl_bind_texture(g_text_texture); int gl_buffer_format = GL_RGBA; if (fs_emu_get_video_format() == FS_EMU_VIDEO_FORMAT_BGRA) { gl_buffer_format = GL_BGRA; } #ifdef USE_GLES /* GLES does not support unpack padding of buffer. we have to update line-wise (or create a new one) */ uint8_t *buf = g_buffer; for(int y=0;y<required_height;y++) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, position * 32 + y, required_width, 1, gl_buffer_format, GL_UNSIGNED_BYTE, buf); buf += g_texture_width * 4; } #else fs_gl_unpack_row_length(g_texture_width); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, position * 32, required_width, required_height, gl_buffer_format, GL_UNSIGNED_BYTE, g_buffer); #endif cache_item *item = malloc(sizeof(cache_item)); item->font = font; item->text = g_strdup(text); item->width = required_width; item->height = required_height; item->position = position; item->x1 = 0; item->x2 = required_width / (1.0 * g_texture_width); item->y1 = (item->position * 32) / (1.0 * g_texture_height); item->y2 = (item->position * 32 + required_height) / (1.0 * g_texture_height); //item->texture = render_texture; g_cache = g_list_prepend(g_cache, item); sanity_check(); if (last_item->text) { free(last_item->text); } /* if (last_item->texture) { glDeleteTextures(1, &last_item->texture); } */ free(last_item); g_cache = g_list_delete_link(g_cache, last); sanity_check(); // now the text is in the cache, so call function again return fs_emu_font_render(font, text, x, y, r, g, b, alpha); }
int fs_emu_xml_shader_render(int texture, int texture_width, int texture_height, int input_width, int input_height, int output_width, int output_height, float x1, float y1, float x2, float y2, int render_textured_side, float alpha) { if (!fs_emu_xml_shader_is_enabled()) { return 0; } g_x1 = x1; g_x2 = x2; g_y1 = y1; g_y2 = y2; g_alpha = alpha; g_render_textured_side = render_textured_side; fs_gl_blending(0); fs_gl_texturing(1); fs_gl_color4f(1.0, 1.0, 1.0, 1.0); // Let the current input size be the dimensions of the video-frame // generated by the host application. g_cur_input_w = input_width; g_cur_input_h = input_height; // Calculate the current texture size as a suitable set of dimensions // larger than the current input size. g_cur_texture_w = texture_width; g_cur_texture_h = texture_height; // Calculate the final output size as the dimensions of the region of the // back-buffer where the output will be displayed to the user, measured // in pixels. g_final_output_w = output_width; g_final_output_h = output_height; // Let requires implicit pass be False. g_requires_implicit_pass = 0; // Construct the current texture, whose dimensions are the current // texture size, and draw the video-frame generated by the host // application into it. g_cur_texture = texture; debug_printf("\n\n\n\n\n"); debug_printf("cur tex %d\n", g_cur_texture); g_orig_texture = g_cur_texture; g_orig_texture_w = g_cur_texture_w; g_orig_texture_h = g_cur_texture_h; g_orig_input_w = g_cur_input_w; g_orig_input_h = g_cur_input_h; debug_printf("final output: %d %d\n", g_final_output_w, g_final_output_h); debug_printf(" input: %d %d\n", g_cur_input_w, g_cur_input_h); debug_printf(" texture: %d %d\n", g_cur_texture_w, g_cur_texture_h); // For each shader pass in the list of shader passes... GList *link = g_active_shader->passes; int first = 1; while (link) { shader_pass *pass = link->data; render_pass(pass, first, link->next == NULL); first = 0; link = link->next; } // If requires implicit pass is True if (g_requires_implicit_pass) { debug_printf("implicit pass, cur tex %d %d %d\n", g_cur_texture, g_cur_texture_w, g_cur_texture_h); // Render a quad, textured with the current texture, with a vertex // at each corner of the final output size. float s2 = (float) g_cur_input_w / (float) g_cur_texture_w; float t2 = (float) g_cur_input_h / (float) g_cur_texture_h; fs_gl_bind_texture(g_cur_texture); render_quad(s2, 0.0, t2, 0, 1, 0); } CHECK_GL_ERROR(); g_frame_count++; glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); CHECK_GL_ERROR(); return 1; }
void fs_emu_render_dialog() { fs_emu_dialog *dialog = fs_emu_get_current_dialog(); if (!dialog) { return; } fs_gl_ortho_hd(); fs_gl_blending(1); fs_gl_texturing(0); fs_gl_color4f(0.0, 0.0, 0.0, 0.5); GLfloat vert[] = { 0, 0, 1920, 0, 1920, 1080, 0, 1080 }; glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vert); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); fs_gl_blending(0); int width = 1920 / 2; int height = 480; //1080 / 2; float x1 = (1920 - width) / 2; float x2 = x1 + width; float y1 = (1080 - height) / 2; float y2 = y1 + height; GLfloat color2[] = { 0.0, 0.4, 0.75, 1.0, 0.0, 0.4, 0.75, 1.0, 0.0, 0.2, 0.375, 1.0, 0.0, 0.2, 0.375, 1.0 }; GLfloat vert2[] = { x1, y1, x2, y1, x2, y2, x1, y2 }; glEnableClientState(GL_COLOR_ARRAY); glColorPointer(4, GL_FLOAT, 0, color2); glVertexPointer(2, GL_FLOAT, 0, vert2); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); fs_emu_font *font = fs_emu_font_get_menu(); int tx = x1 + 50; int ty = y2 - 80; if (dialog->title) { fs_emu_font_render(font, dialog->title, tx, ty, 1.0, 1.0, 1.0, 1.0); ty -= 50; } for (int i = 0; i < DIALOG_MAX_LINES; i++) { if (dialog->lines[i]) { fs_emu_font_render(font, dialog->lines[i], tx, ty, 1.0, 1.0, 1.0, 1.0); } ty -= 50; } tx = x2; ty = y1 - 50; int tw; if (dialog->affirmative) { fs_emu_font_measure(font, dialog->affirmative, &tw, NULL); tx -= tw; fs_emu_font_render(font, dialog->affirmative, tx, ty, 1.0, 1.0, 1.0, 1.0); tx -= 20; fs_emu_font_measure(font, "<OK>", &tw, NULL); tx -= tw; fs_emu_font_render(font, "<OK>", tx, ty, 1.0, 1.0, 1.0, 1.0); //tx -= 40; } tx = x1; if (dialog->negative) { //fs_emu_font_measure(font, dialog->negative, &tw, NULL); //tx -= tw; tx += fs_emu_font_render(font, "<BK>", tx, ty, 1.0, 1.0, 1.0, 1.0); tx += 20; fs_emu_font_render(font, dialog->negative, tx, ty, 1.0, 1.0, 1.0, 1.0); //fs_emu_font_measure(font, "<BK>", &tw, NULL); //tx -= tw; //tx -= 40; } }