Exemple #1
0
static void create_texture_if_needed(int width, int height) {
    //g_frame_texture.video_version = g_fs_emu_video_version;
    if (g_frame_texture && g_frame_texture_width >= width &&
            g_frame_texture_height >= height) {
        return;
    }
    fs_gl_bind_texture(0);

    if (g_frame_texture) {
        glDeleteTextures(1, &g_frame_texture);
        CHECK_GL_ERROR();
    }
    g_frame_texture_width = 1;
    while (g_frame_texture_width < width) {
        g_frame_texture_width *= 2;
    }
    g_frame_texture_height = 1;
    while (g_frame_texture_height < height) {
        g_frame_texture_height *= 2;
    }
    glGenTextures(1, &g_frame_texture);
    CHECK_GL_ERROR();
    //g_frame_texture.opengl_context_stamp = g_fs_ml_opengl_context_stamp;
    //fs_emu_set_texture(&g_frame_texture);
    fs_gl_bind_texture(g_frame_texture);
    // with high quality borders, there should be no reason to initialize
    // the texture to black
    void *data = NULL;
    //void *data = g_malloc0(g_frame_texture_width * g_frame_texture_height * 4);
#ifndef HAVE_GLES
    fs_gl_unpack_row_length(0);
#endif
    glTexImage2D(GL_TEXTURE_2D, 0, fs_emu_get_texture_format(),
            g_frame_texture_width, g_frame_texture_height, 0,
            fs_emu_get_video_format(), GL_UNSIGNED_BYTE, data);
    CHECK_GL_ERROR();
    if (data) {
        g_free(data);
    }
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    CHECK_GL_ERROR();
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    CHECK_GL_ERROR();
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    CHECK_GL_ERROR();
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    CHECK_GL_ERROR();
}
Exemple #2
0
void load_texture(fs_emu_texture *texture) {
    fs_image *image = texture->image;
    //printf("loading texture from image %p\n", image);
    if (!image) {
        return;
    }
    unsigned int opengl_texture;
    glGenTextures(1, &opengl_texture);
    //texture->opengl_context_stamp = g_fs_ml_opengl_context_stamp;
    fs_gl_bind_texture(opengl_texture);
    fs_gl_unpack_row_length(0);
    int gl_buffer_format = GL_RGBA;
    if (fs_emu_get_video_format() == FS_EMU_VIDEO_FORMAT_BGRA) {
        gl_buffer_format = GL_BGRA;
    }
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->width, image->height,
            0, gl_buffer_format, GL_UNSIGNED_BYTE, image->data);
    CHECK_GL_ERROR();
    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
    //        GL_LINEAR_MIPMAP_LINEAR);
    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
    //        GL_LINEAR_MIPMAP_NEAREST);
    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();
    //glGenerateMipmapEXT(GL_TEXTURE_2D);
    texture->texture = opengl_texture;
}
Exemple #3
0
void fs_emu_set_texture(fs_emu_texture *texture) {
    fs_gl_texturing(1);
    /*
    if (texture && texture->opengl_context_stamp && \
            g_fs_ml_opengl_context_stamp != texture->opengl_context_stamp) {
        // OpenGL context has been recreated. load_texture also binds
        load_texture(texture);
    }
    */
    if (!texture) {
        fs_gl_bind_texture(0);
        return;
    }
    if (texture->texture) {
        fs_gl_bind_texture(texture->texture);
    }
    else {
        // texture was not loaded, perhaps due to context recreation
        load_texture(texture);
    }
}
Exemple #4
0
static void create_text_texture() {
    glGenTextures(1, &g_text_texture);
    fs_gl_bind_texture(g_text_texture);
    // want to clear data to color (0, 0, 0, 0), probably a better
    // way to to this...
    void *data = g_malloc0(TEXTURE_WIDTH * TEXTURE_HEIGHT * 4);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEXTURE_WIDTH, TEXTURE_HEIGHT,
            0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    g_free(data);
    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);
}
Exemple #5
0
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);
}
Exemple #6
0
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();
}
Exemple #7
0
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;
    }
}
Exemple #8
0
static void update_texture() {
    fs_emu_video_buffer *buffer = fs_emu_lock_video_buffer();
    // unlocked in fs_emu_video_after_update

    uint8_t *frame = buffer->data;
    if (frame == NULL) {
    	return;
    }
    int is_new_frame = 1;
    static int last_seq_no = -1;
    if (buffer->seq == last_seq_no + 1) {
        // normal
    }
    else if (buffer->seq == last_seq_no) {
        //fs_log("WARNING: repeated frame %d\n", info->seq_no);
        g_fs_emu_repeated_frames++;
        if (g_fs_emu_repeated_frames > 9999) {
            g_fs_emu_repeated_frames = 9999;
        }
        is_new_frame = 0;
    }
    else {
        int lost_frame_count = buffer->seq - last_seq_no - 1;
        g_fs_emu_lost_frames += lost_frame_count;
        //fs_log("lost %d frame(s)\n", lost_frame_count);
    }
    last_seq_no = buffer->seq;

    int width = buffer->width;
    int height = buffer->height;
    int bpp = buffer->bpp;

    if (g_fs_emu_screenshot) {
        static int count = 1;
        g_fs_emu_screenshot = 0;
        gchar *name, *path;
        time_t t = time(NULL);
        struct tm *tm_struct = localtime(&t);
        char strbuf[20];
        strftime(strbuf, 20, "%Y-%m-%d_%H-%M-%S", tm_struct);
        name = g_strdup_printf("%s_%d.png", strbuf, count);
        count += 1;
        path = g_build_filename(
                g_get_user_special_dir(G_USER_DIRECTORY_DESKTOP),
                name, NULL);
        fs_log("writing screenshot to %s\n", path);
        int len = width * height * bpp;
        uint8_t *out_data = malloc(width * height * 3);
        uint8_t *op = out_data;

        if (fs_emu_get_video_format() == FS_EMU_VIDEO_FORMAT_BGRA) {
            for (int x = 0; x < len; x += 4) {
                *op++ = frame[x + 2];
                *op++ = frame[x + 1];
                *op++ = frame[x + 0];
            }
        }
        else {
            for (int x = 0; x < len; x += 4) {
                *op++ = frame[x + 0];
                *op++ = frame[x + 1];
                *op++ = frame[x + 2];
            }
        }
        int result = fs_image_save_data(path, out_data, width, height, 3);
        if (result) {
            fs_log("saved screenshot\n");
        }
        else {
            fs_log("error saving screenshot\n");
        }
        g_free(name);
        g_free(path);
    }

    int format = 0;
    if (bpp == 3) {
        format = GL_RGB;
    }
    else if (bpp == 4) {
#if 0
        if (fs_emu_get_video_format() == GL_BGRA) {
            format = GL_BGRA;
        }
        else {
            format = GL_RGBA;
        }
#endif
        format = fs_emu_get_video_format();
    }
    else {
        //fs_log("na..\n");
        return;
        //fs_emu_fatal("bpp is neither 3 nor 4\n");
    }
    if (g_fs_emu_video_crop_mode) {
        g_crop = buffer->crop;
        if (g_crop.w == 0) {
            g_crop.w = width;
        }
        if (g_crop.h == 0) {
            g_crop.h = height;
        }
    }
    else {
        g_crop.x = 0;
        g_crop.y = 0;
        g_crop.w = buffer->width;
        g_crop.h = buffer->height;
    }

    int upload_x, upload_y, upload_w, upload_h;
    g_effective_viewport_mode = g_viewport_mode;
    if (buffer->flags & FS_EMU_FORCE_VIEWPORT_CROP_FLAG) {
        g_effective_viewport_mode = FS_EMU_VIEWPORT_MODE_CROP;
    }

    if (g_effective_viewport_mode == FS_EMU_VIEWPORT_MODE_CROP) {
        fix_border(buffer, &upload_x, &upload_y, &upload_w, &upload_h);
    }
    else {
        upload_x = 0;
        upload_y = 0;
        upload_w = buffer->width;
        upload_h = buffer->height;
    }

    if (g_fs_emu_scanlines &&
            (buffer->flags & FS_EMU_NO_SCANLINES_FLAG) == 0) {
        //printf("new frame? %d\n", is_new_frame);
        if (is_new_frame) {
            if (g_scanline_buffer_width != buffer->width ||
                    g_scanline_buffer_height != buffer->height) {
                if (g_scanline_buffer) {
                    free(g_scanline_buffer);
                }
                g_scanline_buffer = malloc(buffer->width * buffer->height * 4);
                g_scanline_buffer_width = buffer->width;
                g_scanline_buffer_height = buffer->height;
            }
            fs_emu_render_scanlines(g_scanline_buffer, buffer,
                    upload_x, upload_y, upload_w, upload_h,
                    g_fs_emu_scanlines_dark, g_fs_emu_scanlines_light);
        }
        if (g_scanline_buffer) {
            frame = g_scanline_buffer;
        }
    }

    //fs_log("%d %d %d %d %d %d %d\n", width, height, bpp,
    //        g_crop.x, g_crop.y, g_crop.w, g_crop.h);
    g_frame_width = width;
    g_frame_height = height;
    g_frame_aspect = buffer->aspect;

    create_texture_if_needed(width, height);
    fs_gl_bind_texture(g_frame_texture);

    uint8_t *data_start = frame + ((upload_y * width) + upload_x) * 4;
#ifndef HAVE_GLES
    fs_gl_unpack_row_length(width);
    glTexSubImage2D(GL_TEXTURE_2D, 0, upload_x, upload_y,
    		upload_w, upload_h, format,
            GL_UNSIGNED_BYTE, data_start);
#else
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, upload_w, upload_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data_start);

    for (int y = 0; y < upload_h; y++) {
        char *row = data_start + ((y + upload_y)*width + upload_x) * 4;
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, upload_y, upload_w, 1, GL_RGBA, GL_UNSIGNED_BYTE, row);
    }
#endif
    CHECK_GL_ERROR();

#if 1
    int hq_border = 2;
    if (hq_border >= 1) {
        if (upload_y > 0) {
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, upload_y - 1, width, 1,
                    format, GL_UNSIGNED_BYTE,
                    frame + (upload_y) * width * bpp);
            CHECK_GL_ERROR();
        }

        if (upload_y + upload_h < g_frame_texture_height) {
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, upload_y + upload_h,
                    width, 1, format, GL_UNSIGNED_BYTE,
                    frame + (upload_y + upload_h - 1) * width * bpp);
            CHECK_GL_ERROR();
        }

        if (upload_x > 0) {
            glTexSubImage2D(GL_TEXTURE_2D, 0, upload_x - 1, upload_y,
                    1, upload_h, format, GL_UNSIGNED_BYTE, frame +
                    ((upload_y) * width + upload_x) * bpp);
            CHECK_GL_ERROR();
        }

        if (upload_x + upload_w < g_frame_texture_width) {
            glTexSubImage2D(GL_TEXTURE_2D, 0, upload_x + upload_w,
                    upload_y, 1, upload_h, format,
                    GL_UNSIGNED_BYTE, frame +
                    ((upload_y) * width + upload_x + upload_w - 1) * bpp);
            CHECK_GL_ERROR();
        }
    }
#if 0
    if (hq_border >= 2) {
        if (upload_y + upload_h < g_frame_texture.height - 1) {
            //printf("1\n");
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, upload_y + upload_h + 1,
                    width, 1, format, GL_UNSIGNED_BYTE,
                    frame + (upload_y + upload_h - 1) * width * bpp);
                    //frame + (upload_y + upload_h - 2) * width * bpp);
        }

        if (upload_x + upload_w < g_frame_texture.width - 1) {
            glTexSubImage2D(GL_TEXTURE_2D, 0, upload_x + upload_w + 1,
                    upload_y, 1, upload_h, format,
                    GL_UNSIGNED_BYTE, frame +
                    ((upload_y) * width + upload_x + upload_w - 1) * bpp);
        }
    }
#endif
#endif
}
Exemple #9
0
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);
}
Exemple #10
0
static void render_pass(shader_pass *pass, int first, int last) {
    int output_w = -1;
    int output_h = -1;

    debug_printf("\n");

    // If the horizontal scale method is fixed, set the output width to
    // the horizontal scale value.

    if (pass->hor_scale_method == SCALING_FIXED) {
        output_w = pass->hor_scale_value;
    }

    // If the horizontal scale method is input, set the output width to the
    // horizontal component of the current input size, multiplied by
    // the horizontal scale value.

    else if (pass->hor_scale_method == SCALING_INPUT) {
        output_w = g_cur_input_w * pass->hor_scale_value;
    }

    // If the horizontal scale method is output, set the output width to the
    // horizontal component of the final output size, multiplied by the
    // horizontal scale value.

    else if (pass->hor_scale_method == SCALING_OUTPUT) {
        output_w = g_final_output_w * pass->hor_scale_value;
    }

    // If this is the first shader pass, and the output width is not yet set,
    // the host application may set the output width to an arbitrary value.

    else if (first && !last) {
        output_w = 1024;
        debug_printf("setting output width to arbitrary value %d\n",
                output_w);
    }

    // If this is the last shader pass:

    if (last) {

        // If the output width is already set, set requires implicit
        // pass to True.

        if (output_w > 0) {
            g_requires_implicit_pass = 1;
        }

        // If the output width is not yet set, set the output width to
        // the horizontal component of the final output size.

        else {
            output_w = g_final_output_w;
        }
    }

    // Otherwise, set the output width to the horizontal component of
    // the current input size.

    if (output_w < 0) {
        output_w = g_cur_input_w;
    }

    // If the vertical scale method is fixed, set the output height to the
    // vertical scale value.

    if (pass->ver_scale_method == SCALING_FIXED) {
        output_h = pass->ver_scale_value;
        debug_printf("pass->ver_scale_method == SCALING_FIXED, "
                "output_h = %d\n", output_h);
    }

    // If the vertical scale method is input, set the output height to the
    // vertical component of the current input size, multiplied by the
    // vertical scale value.

    else if (pass->ver_scale_method == SCALING_INPUT) {
        output_h = g_cur_input_h * pass->ver_scale_value;
        debug_printf("pass->ver_scale_method == SCALING_INPUT, "
                "output_h = %d\n", output_h);
    }

    // If the vertical scale method is output, set the output height to the
    // vertical component of the final output size, multiplied by the vertical
    // scale value.

    else if (pass->ver_scale_method == SCALING_OUTPUT) {
        output_h = g_final_output_h * pass->ver_scale_value;
        debug_printf("pass->ver_scale_method == SCALING_OUTPUT, "
                "output_h = %d\n", output_h);
    }

    // If this is the first shader pass, and the output height is not yet
    // set, the host application may set the output height to an arbitrary
    // value.

    else if (first && !last) {
        output_h = 1024;
        debug_printf("setting output height to arbitrary value %d\n",
                output_h);
    }

    // If this is the last shader pass:

    if (last) {

        // If the output height is already set, set requires implicit pass
        // to True.

        if (output_h > 0) {
            g_requires_implicit_pass = 1;
        }

        // If the output height is not yet set, set the output height to
        // the vertical component of the final output size.

        else {
            output_h = g_final_output_h;
        }
    }

    // Otherwise, set the output height to the vertical component of the
    // current input size.

    if (output_h < 0) {
        output_h = g_cur_input_h;
    }

    // Calculate the output size by combining the output width and
    // the output height.

    // If this is not the last shader pass, or this is the last shader pass
    // and requires implicit pass is True:

    GLuint frame_buffer = 0;
    GLuint output_texture = 0;
    int output_texture_w = 0;
    int output_texture_h = 0;

    //g_requires_implicit_pass = 1;

    if (!last || g_requires_implicit_pass) {

        // Construct the output texture with a suitable set of dimensions
        // larger than the output size.

        if (!pass->texture) {
            glGenTextures(1, &pass->texture);
            CHECK_GL_ERROR();
        }
        output_texture = pass->texture;

        output_texture_w = round_up_pow2(output_w);
        output_texture_h = round_up_pow2(output_h);

        // The following is a hack to fix compatibility with
        // CRT-interlaced-halation.shader which has a faulty assumption,
        // that rubyTextureSize and rubyOriginalTextureSize will be the
        // same in the final pass. The reason they may not be the same is
        // because of the crop / zoom function, so for example, FS-UAE may
        // allocate a 1024x1024 texture, but because of cropping, a
        // 1024x512 will be big enough for subsequent passes.

        if (output_texture_h < g_orig_texture_h) {
            output_texture_h = g_orig_texture_h;
        }
        if (output_texture_w < g_orig_texture_w) {
            output_texture_w = g_orig_texture_w;
        }

        fs_gl_bind_texture(output_texture);
        // using RGBA ensures that line size in bytes is a multiple of 4
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, output_texture_w,
                output_texture_h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
        CHECK_GL_ERROR();

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        fs_gl_bind_texture(0);

        // Construct a framebuffer object, and bind the output texture to it
        // as GL_COLOR_ATTACHMENT0.
        // Tell OpenGL to render to the frame-buffer object.

        if (!pass->frame_buffer) {
            //debug_printf("generating frame buffer\n");
            glGenFramebuffers(1, &pass->frame_buffer);
            CHECK_GL_ERROR();
        }
        frame_buffer = pass->frame_buffer;

        glPushMatrix();
        glLoadIdentity();
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();

        debug_printf("%d %d\n", output_w, output_h);
        glViewport(0, 0, output_w, output_h);

        glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer);
        CHECK_GL_ERROR();

        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                GL_TEXTURE_2D, output_texture, 0);
        CHECK_GL_ERROR();

        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) !=
                GL_FRAMEBUFFER_COMPLETE) {
            debug_printf("fbo is not complete!\n");
        }

        glClear(GL_COLOR_BUFFER_BIT);
    }

    // Set the GL_TEXTURE_MAG_FILTER and GL_TEXTURE_MIN_FILTER parameters
    // of the current texture according to the filter setting in the current
    // shader pass.
    //glBindTexture(GL_TEXTURE_2D, g_cur_texture);
    fs_gl_bind_texture(g_cur_texture);
    CHECK_GL_ERROR();

    if (pass->filtering == FILTERING_NEAREST) {
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    }
    else {
        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();

    // Tell OpenGL to use the shader program handle from the current shader
    // pass as the active shader program.

    glUseProgram(pass->program);
    CHECK_GL_ERROR();

    GLint rubyFrameCount = glGetUniformLocation(pass->program,
            "rubyFrameCount");
    if (rubyFrameCount >= 0) {
        glUniform1i(rubyFrameCount, g_frame_count);
    }
    CHECK_GL_ERROR();

    // Set the uniform rubyOrigTexture to the original texture.

    GLint rubyOrigTexture = glGetUniformLocation(pass->program,
            "rubyOrigTexture");
    if (rubyOrigTexture >= 0) {
        debug_printf("set rubyOrigTexture to %d\n", 1);
        glUniform1i(rubyOrigTexture, 1);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, g_orig_texture);
        glActiveTexture(GL_TEXTURE0);
    }
    CHECK_GL_ERROR();

    // Set the uniform rubyOrigTextureSize to the original texture size.

    GLint rubyOrigTextureSize = glGetUniformLocation(pass->program,
            "rubyOrigTextureSize");
    if (rubyOrigTextureSize >= 0) {
        debug_printf("set rubyOrigTextureSize to %dx%d\n",
                g_orig_texture_w, g_orig_texture_h);
        glUniform2f(rubyOrigTextureSize, g_orig_texture_w, g_orig_texture_h);
    }
    CHECK_GL_ERROR();

    // Set the uniform rubyOrigInputSize to the original input size.

    GLint rubyOrigInputSize = glGetUniformLocation(pass->program,
            "rubyOrigInputSize");
    if (rubyOrigInputSize >= 0) {
        debug_printf("set rubyOrigInputSize to %dx%d\n",
                g_orig_input_w, g_orig_input_h);
        glUniform2f(rubyOrigInputSize, g_orig_input_w, g_orig_input_h);
    }
    CHECK_GL_ERROR();

    // Set the uniform rubyTexture to the current texture.

    GLint rubyTexture = glGetUniformLocation(pass->program, "rubyTexture");
    if (rubyTexture >= 0) {
        debug_printf("set rubyTexture to %d\n", 0);
        glUniform1i(rubyTexture, 0);
    }
    CHECK_GL_ERROR();

    // Set the uniform rubyTextureSize to the current texture size.

    GLint rubyTextureSize = glGetUniformLocation(pass->program,
            "rubyTextureSize");
    if (rubyTextureSize >= 0) {
        debug_printf("set rubyTextureSize to %dx%d\n",
                g_cur_texture_w, g_cur_texture_h);
        glUniform2f(rubyTextureSize, g_cur_texture_w, g_cur_texture_h);
    }
    CHECK_GL_ERROR();

    // Set the uniform rubyInputSize to the current input size.

    GLint rubyInputSize = glGetUniformLocation(pass->program,
            "rubyInputSize");
    if (rubyInputSize >= 0) {
        debug_printf("set rubyInputSize to %dx%d\n",
                g_cur_input_w, g_cur_input_h);
        glUniform2f(rubyInputSize, g_cur_input_w, g_cur_input_h);
    }
    CHECK_GL_ERROR();

    // Set the uniform rubyOutputSize to the output size.

    GLint rubyOutputSize = glGetUniformLocation(pass->program,
            "rubyOutputSize");
    if (rubyOutputSize >= 0) {
        debug_printf("set rubyOutputSize to %dx%d\n", output_w, output_h);
        glUniform2f(rubyOutputSize, output_w, output_h);
    }
    CHECK_GL_ERROR();

    // Render a quad, textured with the current texture, with a vertex at
    // each corner of the 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, first, last && !g_requires_implicit_pass, first);
    CHECK_GL_ERROR();

    // Tell OpenGL not to use a shader program (i.e. glUseProgram(0)).

    glUseProgram(0);
    CHECK_GL_ERROR();

    // If this is not the last shader pass, or this is the last shader pass
    // and requires implicit pass is True:

    if (!last || g_requires_implicit_pass) {

        // Tell OpenGL not to use the frame-buffer object.
        debug_printf("unbind framebuffer\n");

        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        CHECK_GL_ERROR();

        glViewport(0, 0, fs_ml_video_width(), fs_ml_video_height());
        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
        glPopMatrix();
    }

    // Set the current input size to the current output size.

    g_cur_input_w = output_w;
    g_cur_input_h = output_h;

    // Set the current texture size to the size of the output texture.

    g_cur_texture_w = output_texture_w;
    g_cur_texture_h = output_texture_h;

    // Set the current texture to the output texture.

    g_cur_texture = output_texture;
}
Exemple #11
0
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;
}