source: trunk/tools/neercs/video/render.cpp @ 1686

Last change on this file since 1686 was 1686, checked in by rez, 8 years ago

added delay to key repeat (float timer_key_repeat)

File size: 19.8 KB
Line 
1//
2// Neercs
3//
4
5#if defined HAVE_CONFIG_H
6#   include "config.h"
7#endif
8
9#if defined _XBOX
10#   define _USE_MATH_DEFINES /* for M_PI */
11#   include <xtl.h>
12#elif defined _WIN32
13#   define _USE_MATH_DEFINES /* for M_PI */
14#   define WIN32_LEAN_AND_MEAN
15#   include <windows.h>
16#endif
17
18#include <cmath>
19#include <cstdio>
20#include <cstdlib>
21#include <ctime>
22#include <string>
23
24#include "core.h"
25#include "lolgl.h"
26
27using namespace std;
28using namespace lol;
29
30#include "../neercs.h"
31#include "render.h"
32#include "text-render.h"
33
34extern char const *lolfx_blurh;
35extern char const *lolfx_blurv;
36extern char const *lolfx_remanency;
37extern char const *lolfx_glow;
38extern char const *lolfx_postfx;
39extern char const *lolfx_radial;
40extern char const *lolfx_simple;
41
42#define PID M_PI/180.0f    // pi ratio
43#define CR 1.0f/256.0f     // color ratio
44
45/*
46 * Various variables
47 */
48
49int active = true;         // window active flag
50float nearplane = 0.1f;    // nearplane
51float farplane = 1000.0f;  // farplane
52int polygon_fillmode = GL_FILL; // fill mode
53/* timer variable */
54float timer = 0;           // timer
55float timer_key = 0;       // key timer
56float timer_key_repeat = 0.25f;// key repeat delay
57/* window variable */
58ivec2 screen_size;         // screen size
59vec3 screen_color = CR * vec3(32, 32, 32); // screen color
60/* object variable */
61float main_angle = 0.0f;   // main angle
62float part_angle = 0.0f;   // part angle
63float fx_angle;            // current angle
64/* fs_quad variable */
65float fs_quad_vtx[] = {-1.0f, 1.0f, 0, 1.0f, -1.0f, -1.0f, 0, 1.0f, 1.0f, -1.0f, 0, 1.0f, 1.0f, 1.0f, 0, 1.0f};
66float fs_quad_tex[] = {0, 1.0f, 0, 0, 1.0f, 0, 1.0f, 1.0f};
67/* flash variable */
68bool flash_flag = false;   // flag
69float flash_angle = 0;     // angle
70float flash_value = 0;     // value
71float flash_speed = 1.5f;  // speed
72/* fade variable */
73bool fade_flag = false;    // flag
74float fade_angle = 0;      // angle
75float fade_value = 0;      // value
76float fade_speed = 0.2f;   // speed
77/* sync variable */
78bool sync_flag = false;    // flagsh
79float sync_angle = 0;      // angle
80float sync_value = 1.0f;   // value
81float sync_speed = 1.0f;   // speed
82/* beat variable */
83bool beat_flag = false;    // flag
84float beat_angle = 0;      // angle
85float beat_value = 0;      // value
86float beat_speed = 2.0f;   // speed
87/* window variable */
88ivec2 border;              // border width
89/* text variable */
90ivec2 ratio_2d(2,4);       // 2d ratio
91ivec2 map_size(256,256);   // texture map size
92ivec2 font_size(8,8);      // font size
93ivec2 canvas_char(0,0);    // canvas char number
94ivec2 canvas_size(0,0);    // caca size
95/* common variable */
96float value, angle, radius, scale, speed;
97/* shader variable */
98vec2 buffer(0.75f,0.25f);       // [new frame mix,old frame mix]
99vec2 remanency(0.25f,0.75f);    // remanency [source mix,buffer mix]
100vec2 blur(0.25f,0.75f);         // glow radius [normal,deform]
101vec2 glow_mix(0.5f,0.5f);       // glow mix [source mix,glow mix]
102vec2 glow_large(2.0f,2.0f);     // large glow radius [normal,deform]
103vec2 glow_small(1.0f,1.0f);     // small glow radius [normal,deform]
104//vec3 radial(2.0f,0.8f,0);     // radial [mix,strength,color mode]
105//---------------------------------[IDEAS] http://www.youtube.com/watch?v=d1qEP2vMe-I
106float postfx_deform = 0.625f;   // deformation ratio
107vec3 postfx_filter(0.875f,0.75f,1.0f);// color filter [red,green,blue]
108vec3 postfx_retrace(0.025f,2.0f,4.0f);// retrace [color,length,speed]
109vec2 postfx_offset(3.0f,3.0f);  // random line [horizontal,vertical]
110float postfx_noise = 0.125f;    // noise
111float postfx_aberration = 3.0f; // chromatic aberration
112bool postfx_moire = true;       // moire
113vec4 postfx_moire_h(0.75f,-0.25f,1.0f,2.0f);
114vec4 postfx_moire_v(0.75f,-0.25f,0.0f,1.0f);
115bool postfx_scanline = true;    // scanline
116vec4 postfx_scanline_h(0.75f,-0.25f,2.0f,0.0f);// vertical scanline [base,variable,repeat]
117vec4 postfx_scanline_v(0.75f, 0.25f,0.0f,2.0f);// horizontal scanline [base,variable,repeat]
118vec2 postfx_smoothstep(0.025f,0.625f);// smoothstep [lower,upper]
119
120Shader *shader_simple;
121Shader *shader_blur_h, *shader_blur_v;
122Shader *shader_remanency, *shader_glow, *shader_radial, *shader_postfx;
123// shader variables
124ShaderUniform shader_simple_texture;
125ShaderUniform shader_blur_h_texture,
126              shader_blur_h_radius,
127              shader_blur_v_texture,
128              shader_blur_v_radius;
129ShaderUniform shader_remanency_source,
130              shader_remanency_buffer,
131              shader_remanency_mix;
132ShaderUniform shader_glow_glow,
133              shader_glow_source,
134              shader_glow_mix;
135ShaderUniform shader_radial_texture,
136              shader_radial_screen_size,
137              shader_radial_time,
138              shader_radial_value1,
139              shader_radial_value2,
140              shader_radial_color;
141ShaderUniform shader_postfx_texture,
142              shader_postfx_texture_2d,
143              shader_postfx_screen_size,
144              shader_postfx_time,
145              shader_postfx_deform,
146              shader_postfx_filter,
147              shader_postfx_retrace,
148              shader_postfx_offset,
149              shader_postfx_noise,
150              shader_postfx_aberration,
151              shader_postfx_moire,
152              shader_postfx_moire_h,
153              shader_postfx_moire_v,
154              shader_postfx_scanline,
155              shader_postfx_scanline_h,
156              shader_postfx_scanline_v,
157              shader_postfx_smoothstep,
158              shader_postfx_flash,
159              shader_postfx_sync;
160
161FrameBuffer *fbo_back, *fbo_front, *fbo_buffer;
162FrameBuffer *fbo_blur_h, *fbo_blur_v, *fbo_ping, *fbo_pong;
163
164TextRender *text_render;
165
166void fs_quad()
167{
168    glLoadIdentity();
169    glDrawArrays(GL_QUADS, 0, 4);
170}
171
172void draw_shader_simple(FrameBuffer *fbo_output, int n)
173{
174    shader_simple->Bind();
175    shader_simple->SetTexture(shader_simple_texture, fbo_output->GetTexture(), n);
176    fs_quad();
177    shader_simple->Unbind();
178}
179
180void rectangle(int x, int y, int w, int h)
181{
182    glLoadIdentity();
183    glBegin(GL_QUADS);
184        glVertex2i(x+w, y  );
185        glVertex2i(x  , y  );
186        glVertex2i(x  , y+h);
187        glVertex2i(x+w, y+h);
188    glEnd();
189}
190
191int Render::InitDraw(void)
192{
193    glDepthMask(GL_TRUE);     // do not write z-buffer
194    glEnable(GL_CULL_FACE);   // disable cull face
195    glCullFace(GL_BACK);      // don't draw front face
196
197    /* Initialise framebuffer objects */
198    fbo_back = new FrameBuffer(screen_size);
199    fbo_front = new FrameBuffer(screen_size);
200    fbo_buffer = new FrameBuffer(screen_size);
201    fbo_blur_h = new FrameBuffer(screen_size);
202    fbo_blur_v = new FrameBuffer(screen_size);
203    fbo_ping = new FrameBuffer(screen_size);
204    fbo_pong = new FrameBuffer(screen_size);
205    // shader simple
206    shader_simple = Shader::Create(lolfx_simple);
207    shader_simple_texture = shader_simple->GetUniformLocation("texture");
208    // shader blur horizontal
209    shader_blur_h = Shader::Create(lolfx_blurh);
210    shader_blur_h_texture = shader_blur_h->GetUniformLocation("texture");
211    shader_blur_h_radius = shader_blur_h->GetUniformLocation("radius");
212    // shader blur vertical
213    shader_blur_v = Shader::Create(lolfx_blurv);
214    shader_blur_v_texture = shader_blur_v->GetUniformLocation("texture");
215    shader_blur_v_radius = shader_blur_v->GetUniformLocation("radius");
216    // shader remanency
217    shader_remanency = Shader::Create(lolfx_remanency);
218    shader_remanency_source = shader_remanency->GetUniformLocation("source");
219    shader_remanency_buffer = shader_remanency->GetUniformLocation("buffer");
220    shader_remanency_mix = shader_remanency->GetUniformLocation("mix");
221    // shader glow
222    shader_glow = Shader::Create(lolfx_glow);
223    shader_glow_glow = shader_glow->GetUniformLocation("glow");
224    shader_glow_source = shader_glow->GetUniformLocation("source");
225    shader_glow_mix = shader_glow->GetUniformLocation("mix");
226    // shader radial
227    shader_radial = Shader::Create(lolfx_radial);
228    shader_radial_texture = shader_radial->GetUniformLocation("texture");
229    shader_radial_screen_size = shader_radial->GetUniformLocation("screen_size");
230    shader_radial_time = shader_radial->GetUniformLocation("time");
231    shader_radial_value1 = shader_radial->GetUniformLocation("value1");
232    shader_radial_value2 = shader_radial->GetUniformLocation("value2");
233    shader_radial_color = shader_radial->GetUniformLocation("color");
234    // shader postfx
235    shader_postfx = Shader::Create(lolfx_postfx);
236    shader_postfx_texture = shader_postfx->GetUniformLocation("texture");
237    shader_postfx_texture_2d = shader_postfx->GetUniformLocation("texture_2d");
238    shader_postfx_screen_size = shader_postfx->GetUniformLocation("screen_size");
239    shader_postfx_time = shader_postfx->GetUniformLocation("time");
240    shader_postfx_deform = shader_postfx->GetUniformLocation("deform");
241    shader_postfx_filter = shader_postfx->GetUniformLocation("filter");
242    shader_postfx_retrace = shader_postfx->GetUniformLocation("retrace");
243    shader_postfx_offset = shader_postfx->GetUniformLocation("offset");
244    shader_postfx_noise = shader_postfx->GetUniformLocation("noise");
245    shader_postfx_aberration = shader_postfx->GetUniformLocation("aberration");
246    shader_postfx_moire = shader_postfx->GetUniformLocation("moire");
247    shader_postfx_moire_h = shader_postfx->GetUniformLocation("moire_h");
248    shader_postfx_moire_v = shader_postfx->GetUniformLocation("moire_v");
249    shader_postfx_scanline = shader_postfx->GetUniformLocation("scanline");
250    shader_postfx_scanline_h = shader_postfx->GetUniformLocation("scanline_h");
251    shader_postfx_scanline_v = shader_postfx->GetUniformLocation("scanline_v");
252    shader_postfx_smoothstep = shader_postfx->GetUniformLocation("smooth");
253    shader_postfx_flash = shader_postfx->GetUniformLocation("flash");
254    shader_postfx_sync = shader_postfx->GetUniformLocation("sync");
255
256    return true;
257}
258
259int Render::CreateGLWindow()
260{
261    screen_size = Video::GetSize();
262    border = 18 * ratio_2d;
263    border.y = border.x; // enabled to get same border everywhere
264    canvas_char = (screen_size - border * 2) / (font_size * ratio_2d);
265    canvas_size = canvas_char * font_size * ratio_2d;
266
267    border = (screen_size - canvas_size) / 2;
268
269    caca_set_canvas_size(m_caca, canvas_char.x, canvas_char.y);
270
271    InitDraw();
272    return true;
273}
274
275Render::Render(caca_canvas_t *caca)
276  : m_caca(caca),
277    m_ready(false),
278    m_pause(false),
279    m_polygon(true),
280    m_shader(true),
281    m_shader_remanency(true),
282    m_shader_glow(true),
283    m_shader_blur(true),
284    m_shader_fx(true),
285    m_shader_postfx(true),
286    m_border(false)
287{
288    text_render = new TextRender(m_caca, font_size);
289}
290
291void Render::TickGame(float seconds)
292{
293    Entity::TickGame(seconds);
294}
295
296void Render::Pause()
297{
298    m_pause=!m_pause;
299}
300
301void Render::TickDraw(float seconds)
302{
303    /* keyboard manager */
304    if (Input::GetButtonState(27/*SDLK_ESCAPE*/))
305        Ticker::Shutdown();
306    //if (Input::GetButtonState(282/*SDLK_F1*/))
307    //    LEAULE();
308    if (Input::GetButtonState(283/*SDLK_F2*/)&&(timer-timer_key>timer_key_repeat))
309        {
310        m_polygon = !m_polygon;
311        polygon_fillmode = (m_polygon)?GL_FILL:GL_LINE;
312        glPolygonMode(GL_FRONT, polygon_fillmode);
313        timer_key = timer;
314        }
315    if (Input::GetButtonState(284/*SDLK_F3*/)&&(timer-timer_key>timer_key_repeat))
316        {
317        m_shader = !m_shader;
318        timer_key = timer;
319        }
320    if (Input::GetButtonState(285/*SDLK_F4*/)&&(timer-timer_key>timer_key_repeat))
321        {
322        m_shader_postfx = !m_shader_postfx;
323        timer_key = timer;
324        }
325    if (Input::GetButtonState(286/*SDLK_F5*/)&&(timer-timer_key>timer_key_repeat))
326        {
327        Pause();
328        timer_key = timer;
329        }
330
331    Entity::TickDraw(seconds);
332
333    if (!m_ready)
334    {
335        CreateGLWindow();
336        text_render->Init();
337        m_ready = true;
338    }
339
340    // timer
341    if (!m_pause)
342    {
343        timer += seconds;
344        main_angle = timer * 100.0f * PID;
345    }
346    if (sync_flag)
347    {
348        angle=(main_angle-sync_angle)*sync_speed;
349        sync_value=1.0f-sinf(angle);
350        if (angle>90.0f*PID)
351        {
352            sync_value=0;
353            sync_flag=false;
354        }
355    }
356    if (beat_flag)
357    {
358        angle=(main_angle-beat_angle)*beat_speed;
359        beat_value=1.0f-sinf(angle);
360        if (angle>90.0f*PID)
361        {
362            beat_value=0;
363            beat_flag=false;
364        }
365    }
366    if (flash_flag)
367    {
368        angle=(main_angle-flash_angle)*flash_speed;
369        flash_value=1.0f-sinf(angle);
370        if (angle>90.0f*PID)
371        {
372            flash_value=0;
373            flash_flag=false;
374        }
375    }
376    if (fade_flag)
377    {
378        angle=(main_angle-fade_angle)*fade_speed;
379        fade_value=1.0f-sinf(angle);
380        if (angle>90.0f*PID)
381        {
382            fade_value=0;
383            fade_flag=false;
384        }
385    }
386
387    Draw2D();
388    Draw3D();
389}
390
391void Render::Draw2D()
392{
393    /* Draw text in an offline buffer */
394    text_render->Render();
395
396    if (m_shader)
397    {
398        fbo_back->Bind();
399    }
400
401    glViewport(0, 0, screen_size.x, screen_size.y);
402
403    /* Clear the back buffer */
404    glEnable(GL_BLEND);
405    glBlendFunc(GL_SRC_COLOR,GL_DST_ALPHA);
406    glClearColor(screen_color.r, screen_color.g, screen_color.b, 1.0f);
407    glClearDepth(1.0f); // set depth buffer
408    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
409
410    text_render->Blit(border, canvas_size);
411
412    //if (m_polygon) glEnable(GL_LINE_SMOOTH); else glDisable(GL_LINE_SMOOTH);
413    glLineWidth((m_polygon)?2.0f:1.0f);
414    fx_angle=main_angle-part_angle;
415    if (m_polygon)
416        glEnable(GL_TEXTURE_2D);
417
418    glMatrixMode(GL_PROJECTION);
419    mat4 m = mat4::ortho(0, screen_size.x, screen_size.y, 0, -1.f, 1.f);
420    glLoadMatrixf(&m[0][0]);
421    glMatrixMode(GL_MODELVIEW);
422    // draw border
423    if (m_border)
424    {
425        glDisable(GL_TEXTURE_2D);
426        glDisable(GL_BLEND);
427        glColor3f(1.0f, 1.0f, 1.0f);
428        rectangle(border.x - ratio_2d.x, border.y - ratio_2d.y, canvas_size.x + ratio_2d.x * 2, ratio_2d.y);
429        rectangle(border.x - ratio_2d.x, border.y, ratio_2d.x, canvas_size.y);
430        rectangle(border.x + canvas_size.x, border.y, ratio_2d.x, canvas_size.y);
431        rectangle(border.x - ratio_2d.x, border.y + canvas_size.y, canvas_size.x + ratio_2d.x * 2, ratio_2d.y);
432        glEnable(GL_BLEND);
433    }
434}
435
436void Render::Draw3D()
437{
438    if (!m_shader)
439        return;
440
441    glDisable(GL_DEPTH_TEST);
442    glDisable(GL_BLEND);
443
444    glEnableClientState(GL_VERTEX_ARRAY);
445    glVertexPointer(4, GL_FLOAT, 0, fs_quad_vtx);
446
447    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
448    glTexCoordPointer(2, GL_FLOAT, 0, fs_quad_tex);
449
450    if (m_shader_remanency)
451    {
452        // shader remanency
453        fbo_ping->Bind();
454        shader_remanency->Bind();
455        shader_remanency->SetTexture(shader_remanency_source, fbo_back->GetTexture(), 0);
456        shader_remanency->SetTexture(shader_remanency_buffer, fbo_buffer->GetTexture(), 1);
457        shader_remanency->SetUniform(shader_remanency_mix, remanency);
458        fs_quad();
459        shader_remanency->Unbind();
460        fbo_ping->Unbind();
461        // shader simple
462        fbo_back->Bind();
463        draw_shader_simple(fbo_ping, 0);
464        fbo_back->Unbind();
465        // save previous fbo
466        fbo_ping->Bind();
467        shader_remanency->Bind();
468        shader_remanency->SetTexture(shader_remanency_source, fbo_front->GetTexture(), 0);
469        shader_remanency->SetTexture(shader_remanency_buffer, fbo_buffer->GetTexture(), 1);
470        shader_remanency->SetUniform(shader_remanency_mix, buffer);
471        fs_quad();
472        shader_remanency->Unbind();
473        fbo_ping->Unbind();
474        // shader simple
475        fbo_buffer->Bind();
476        draw_shader_simple(fbo_ping, 0);
477        fbo_buffer->Unbind();
478    }
479
480    // shader glow
481    if (m_shader_fx && m_shader_glow)
482    {
483        // shader blur horizontal
484        fbo_blur_h->Bind();
485        shader_blur_h->Bind();
486        shader_blur_h->SetTexture(shader_blur_h_texture, fbo_back->GetTexture(), 0);
487        shader_blur_h->SetUniform(shader_blur_h_radius, glow_large / screen_size.x);
488        fs_quad();
489        shader_blur_h->Unbind();
490        fbo_blur_h->Unbind();
491        // shader blur vertical
492        fbo_blur_v->Bind();
493        shader_blur_v->Bind();
494        shader_blur_v->SetTexture(shader_blur_v_texture, fbo_blur_h->GetTexture(), 0);
495        shader_blur_v->SetUniform(shader_blur_v_radius, glow_large / screen_size.y);
496        fs_quad();
497        shader_blur_v->Unbind();
498        fbo_blur_v->Unbind();
499        // shader blur horizontal
500        fbo_blur_h->Bind();
501        shader_blur_h->Bind();
502        shader_blur_h->SetTexture(shader_blur_h_texture, fbo_blur_v->GetTexture(), 0);
503        shader_blur_h->SetUniform(shader_blur_h_radius, glow_small / screen_size.x);
504        fs_quad();
505        shader_blur_h->Unbind();
506        fbo_blur_h->Unbind();
507        // shader blur vertical
508        fbo_blur_v->Bind();
509        shader_blur_v->Bind();
510        shader_blur_v->SetTexture(shader_blur_v_texture, fbo_blur_h->GetTexture(), 0);
511        shader_blur_v->SetUniform(shader_blur_v_radius, glow_small / screen_size.y);
512        fs_quad();
513        shader_blur_v->Unbind();
514        fbo_blur_v->Unbind();
515        // shader glow
516        fbo_front->Bind();
517        shader_glow->Bind();
518        shader_glow->SetTexture(shader_glow_glow, fbo_blur_v->GetTexture(), 0);
519        shader_glow->SetTexture(shader_glow_source, fbo_back->GetTexture(), 1);
520        shader_glow->SetUniform(shader_glow_mix, glow_mix);
521        fs_quad();
522        shader_glow->Unbind();
523        fbo_front->Unbind();
524    }
525    else
526    {
527        // shader simple
528        fbo_front->Bind();
529        draw_shader_simple(fbo_back, 0);
530        fbo_front->Unbind();
531    }
532
533    if (m_shader_fx && m_shader_blur)
534    {
535        // shader blur horizontal
536        fbo_ping->Bind();
537        shader_blur_h->Bind();
538        shader_blur_h->SetTexture(shader_blur_h_texture, fbo_front->GetTexture(), 0);
539        shader_blur_h->SetUniform(shader_blur_h_radius, blur / screen_size.x);
540        fs_quad();
541        shader_blur_h->Unbind();
542        fbo_ping->Unbind();
543        // shader blur vertical
544        fbo_front->Bind();
545        shader_blur_v->Bind();
546        shader_blur_v->SetTexture(shader_blur_v_texture, fbo_ping->GetTexture(), 0);
547        shader_blur_v->SetUniform(shader_blur_v_radius, blur / screen_size.y);
548        fs_quad();
549        shader_blur_v->Unbind();
550        fbo_front->Unbind();
551    }
552
553    if (m_shader_postfx)
554    {
555        // shader postfx
556        shader_postfx->Bind();
557        shader_postfx->SetTexture(shader_postfx_texture, fbo_front->GetTexture(), 0);
558        shader_postfx->SetUniform(shader_postfx_screen_size, (vec2)screen_size);
559        shader_postfx->SetUniform(shader_postfx_time, fx_angle);
560        shader_postfx->SetUniform(shader_postfx_deform, postfx_deform);
561        shader_postfx->SetUniform(shader_postfx_filter, postfx_filter);
562        shader_postfx->SetUniform(shader_postfx_retrace, postfx_retrace);
563        shader_postfx->SetUniform(shader_postfx_offset, postfx_offset);
564        shader_postfx->SetUniform(shader_postfx_noise, postfx_noise);
565        shader_postfx->SetUniform(shader_postfx_aberration, postfx_aberration);
566        shader_postfx->SetUniform(shader_postfx_moire, postfx_moire);
567        shader_postfx->SetUniform(shader_postfx_moire_h, postfx_moire_h);
568        shader_postfx->SetUniform(shader_postfx_moire_v, postfx_moire_v);
569        shader_postfx->SetUniform(shader_postfx_scanline, postfx_scanline);
570        shader_postfx->SetUniform(shader_postfx_scanline_h, postfx_scanline_h);
571        shader_postfx->SetUniform(shader_postfx_scanline_v, postfx_scanline_v);
572        shader_postfx->SetUniform(shader_postfx_smoothstep, postfx_smoothstep);
573        shader_postfx->SetUniform(shader_postfx_flash, flash_value);
574        shader_postfx->SetUniform(shader_postfx_sync, (float)fabs(beat_value*cosf((main_angle-beat_angle)*8.0f)));
575        fs_quad();
576        shader_postfx->Unbind();
577    }
578    else
579    {
580        // shader simple
581        draw_shader_simple(fbo_front, 0);
582    }
583
584    glDisableClientState(GL_VERTEX_ARRAY);
585    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
586}
587
588Render::~Render()
589{
590}
Note: See TracBrowser for help on using the repository browser.