source: trunk/src/rocket/rocket_interface.cc @ 435

Last change on this file since 435 was 395, checked in by epyon, 10 years ago
  • bulk update copyright update include guards cleanup core/common.hh -> common.hh minor cleanups
File size: 16.8 KB
Line 
1// Copyright (C) 2015 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
6
7#include "nv/rocket/rocket_interface.hh"
8
9#include <nv/interface/context.hh>
10#include <nv/gl/gl_device.hh>
11#include <nv/core/time.hh>
12#include <Rocket/Core.h>
13#include <Rocket/Debugger/Debugger.h>
14
15
16class rocket_c_file_interface : public Rocket::Core::FileInterface
17{
18public:
19        rocket_c_file_interface( const Rocket::Core::String& root ) : root( root ) {}
20        virtual ~rocket_c_file_interface() {}
21        virtual Rocket::Core::FileHandle Open( const Rocket::Core::String& path );
22        virtual void Close( Rocket::Core::FileHandle file );
23        virtual size_t Read( void* buffer, size_t size, Rocket::Core::FileHandle file );
24        virtual bool Seek( Rocket::Core::FileHandle file, long offset, int origin );
25        virtual size_t Tell( Rocket::Core::FileHandle file );
26private:
27        Rocket::Core::String root;
28};
29
30class rocket_sdl2_system_interface : public Rocket::Core::SystemInterface
31{
32public:
33        float GetElapsedTime();
34        bool LogMessage( Rocket::Core::Log::Type type, const Rocket::Core::String& message );
35};
36
37class rocket_sdl2_render_interface : public Rocket::Core::RenderInterface
38{
39public:
40        rocket_sdl2_render_interface( nv::context* context );
41
42        /// Called by Rocket when it wants to render geometry that it does not wish to optimise.
43        virtual void RenderGeometry( Rocket::Core::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rocket::Core::TextureHandle texture, const Rocket::Core::Vector2f& translation );
44        /// Called by Rocket when it wants to enable or disable scissoring to clip content.
45        virtual void EnableScissorRegion( bool enable );
46        /// Called by Rocket when it wants to change the scissor region.
47        virtual void SetScissorRegion( int x, int y, int width, int height );
48
49        /// Called by Rocket when a texture is required by the library.
50        virtual bool LoadTexture( Rocket::Core::TextureHandle& texture_handle, Rocket::Core::Vector2i& texture_dimensions, const Rocket::Core::String& source );
51        /// Called by Rocket when a texture is required to be built from an internally-generated sequence of pixels.
52        virtual bool GenerateTexture( Rocket::Core::TextureHandle& texture_handle, const Rocket::Core::byte* source, const Rocket::Core::Vector2i& source_dimensions );
53        /// Called by Rocket when a loaded texture is no longer required.
54        virtual void ReleaseTexture( Rocket::Core::TextureHandle texture_handle );
55private:
56        nv::device*      m_device;
57        nv::context*     m_context;
58        nv::program      m_program;
59        nv::scene_state  m_state;
60        nv::render_state m_rstate;
61};
62
63
64static const char *rocket_vertex_shader = R"(
65#version 120
66attribute vec2 nv_position;
67attribute vec2 nv_texcoord;
68attribute vec4 nv_color;
69varying vec4 v_color;
70varying vec2 v_texcoord;
71uniform mat4 nv_m_projection;
72uniform mat4 nv_m_model;
73uniform vec2 texsize;
74void main(void)
75{
76        gl_Position = nv_m_projection * nv_m_model * vec4(nv_position.x, nv_position.y, 0.0, 1.0);
77        v_texcoord  = nv_texcoord; // / texsize;
78        v_color     = nv_color / 256;
79}
80)";
81
82static const char *rocket_fragment_shader = R"(
83#version 120
84varying vec4 v_color;
85varying vec2 v_texcoord;
86uniform sampler2D nv_t_diffuse;
87void main(void)
88{
89        vec4 tex_color = texture2D( nv_t_diffuse, v_texcoord );
90
91        gl_FragColor   = tex_color * v_color;
92}
93)";
94
95Rocket::Core::FileHandle rocket_c_file_interface::Open( const Rocket::Core::String& path )
96{
97        // Attempt to open the file relative to the application's root.
98        FILE* fp = fopen( ( root + path ).CString(), "rb" );
99        if ( fp != NULL )
100                return ( Rocket::Core::FileHandle ) fp;
101
102        // Attempt to open the file relative to the current working directory.
103        fp = fopen( path.CString(), "rb" );
104        return ( Rocket::Core::FileHandle ) fp;
105}
106
107void rocket_c_file_interface::Close( Rocket::Core::FileHandle file )
108{
109        fclose( (FILE*)file );
110}
111
112size_t rocket_c_file_interface::Read( void* buffer, size_t size, Rocket::Core::FileHandle file )
113{
114        return fread( buffer, 1, size, (FILE*)file );
115}
116
117bool rocket_c_file_interface::Seek( Rocket::Core::FileHandle file, long offset, int origin )
118{
119        return fseek( (FILE*)file, offset, origin ) == 0;
120}
121
122size_t rocket_c_file_interface::Tell( Rocket::Core::FileHandle file )
123{
124        return ftell( (FILE*)file );
125}
126
127float rocket_sdl2_system_interface::GetElapsedTime()
128{
129        return nv::get_ticks() / 1000;
130}
131
132bool rocket_sdl2_system_interface::LogMessage( Rocket::Core::Log::Type type, const Rocket::Core::String& message )
133{
134        switch ( type )
135        {
136        case Rocket::Core::Log::LT_ALWAYS: NV_LOG( nv::LOG_NOTICE, message.CString() ); break;
137        case Rocket::Core::Log::LT_ERROR: NV_LOG( nv::LOG_ERROR, message.CString() ); break;
138        case Rocket::Core::Log::LT_ASSERT: NV_LOG( nv::LOG_CRITICAL, message.CString() ); break;
139        case Rocket::Core::Log::LT_WARNING: NV_LOG( nv::LOG_WARNING, message.CString() ); break;
140        case Rocket::Core::Log::LT_INFO: NV_LOG( nv::LOG_INFO, message.CString() ); break;
141        case Rocket::Core::Log::LT_DEBUG: NV_LOG( nv::LOG_DEBUG, message.CString() ); break;
142        case Rocket::Core::Log::LT_MAX: break;
143        };
144
145        return true;
146}
147
148struct rocket_vertex
149{
150        nv::vec2   position;
151        nv::u8vec4 color;
152        nv::vec2   texcoord;
153};
154
155
156union texture_handle_convert
157{
158        Rocket::Core::TextureHandle th;
159        struct
160        {
161                nv::uint16 index;
162                nv::uint16 counter;
163        };
164};
165
166rocket_sdl2_render_interface::rocket_sdl2_render_interface( nv::context* context )
167{
168        m_context = context;
169        m_device = m_context->get_device();
170        m_rstate.depth_test.enabled = false;
171        m_rstate.culling.enabled = false;
172        m_rstate.blending.enabled = true;
173        m_rstate.blending.src_rgb_factor = nv::blending::SRC_ALPHA;
174        m_rstate.blending.dst_rgb_factor = nv::blending::ONE_MINUS_SRC_ALPHA;
175        m_rstate.blending.src_alpha_factor = nv::blending::SRC_ALPHA;
176        m_rstate.blending.dst_alpha_factor = nv::blending::ONE_MINUS_SRC_ALPHA;
177
178        m_program = m_device->create_program( rocket_vertex_shader, rocket_fragment_shader );
179
180        m_state.get_camera().set_ortho( 0.0f, float( 1024 ), float( 728 ), 0.0f );
181}
182
183void rocket_sdl2_render_interface::EnableScissorRegion( bool enable )
184{
185        m_rstate.scissor_test.enabled = enable;
186}
187
188void rocket_sdl2_render_interface::SetScissorRegion( int x, int y, int width, int height )
189{
190        m_rstate.scissor_test.pos.x = x;
191        m_rstate.scissor_test.pos.y = y;
192        m_rstate.scissor_test.dim.x = width;
193        m_rstate.scissor_test.pos.y = height;
194}
195
196bool rocket_sdl2_render_interface::LoadTexture( Rocket::Core::TextureHandle& texture_handle, Rocket::Core::Vector2i& texture_dimensions, const Rocket::Core::String& source )
197{
198        Rocket::Core::FileInterface* file_interface = Rocket::Core::GetFileInterface();
199        Rocket::Core::FileHandle file_handle = file_interface->Open( source );
200        if ( !file_handle )
201                return false;
202
203        file_interface->Seek( file_handle, 0, SEEK_END );
204        size_t buffer_size = file_interface->Tell( file_handle );
205        file_interface->Seek( file_handle, 0, SEEK_SET );
206
207        nv::uint8* buffer = new nv::uint8[buffer_size];
208        file_interface->Read( buffer, buffer_size, file_handle );
209        file_interface->Close( file_handle );
210
211        Rocket::Core::String ext = source.Substring( source.Length() - 3, 3 ).ToLower();
212
213        nv::sampler sampler( nv::sampler::LINEAR, nv::sampler::REPEAT );
214        nv::image_data* data = m_device->create_image_data( buffer, buffer_size );
215        nv::image_format iformat( nv::RGBA, nv::UBYTE );
216        if ( ext == "tga" ) iformat.format = nv::BGRA;
217
218        nv::texture tex = m_device->create_texture( data->get_size(), iformat, sampler, (void*)data->get_data() );
219        texture_dimensions.x = data->get_size().x;
220        texture_dimensions.y = data->get_size().y;
221        delete data;
222
223        typedef nv::handle_operator< nv::texture > op;
224        texture_handle_convert thc;
225        thc.index = op::get_index( tex );
226        thc.counter = op::get_counter( tex );
227        texture_handle = thc.th;
228        NV_LOG( nv::LOG_DEBUG, "load " << source.CString() << " as " << thc.index << "," << thc.counter );
229        return true;
230}
231
232bool rocket_sdl2_render_interface::GenerateTexture( Rocket::Core::TextureHandle& texture_handle, const Rocket::Core::byte* source, const Rocket::Core::Vector2i& source_dimensions )
233{
234        nv::sampler sampler( nv::sampler::LINEAR, nv::sampler::REPEAT );
235        nv::texture tex = m_device->create_texture( nv::ivec2( source_dimensions.x, source_dimensions.y ), nv::image_format( nv::RGBA, nv::UBYTE ), sampler, (void*)source );
236        typedef nv::handle_operator< nv::texture > op;
237        texture_handle_convert thc;
238        thc.index = op::get_index( tex );
239        thc.counter = op::get_counter( tex );
240        texture_handle = thc.th;
241        return true;
242}
243
244void rocket_sdl2_render_interface::ReleaseTexture( Rocket::Core::TextureHandle texture_handle )
245{
246        texture_handle_convert thc;
247        thc.th = texture_handle;
248        typedef nv::handle_operator< nv::texture > op;
249        m_device->release( op::create( thc.index, thc.counter ) );
250}
251
252
253void rocket_sdl2_render_interface::RenderGeometry( Rocket::Core::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rocket::Core::TextureHandle texture, const Rocket::Core::Vector2f& translation )
254{
255        const nv::texture_info* info = nullptr;
256        if ( texture != 0 )
257        {
258                texture_handle_convert thc;
259                thc.th = texture;
260                typedef nv::handle_operator< nv::texture > op;
261                nv::texture tex( op::create( thc.index, thc.counter ) );
262                m_context->bind( tex, nv::TEX_DIFFUSE );
263                info = m_device->get_texture_info( tex );
264        }
265        else
266        {
267                m_context->bind( nv::texture(), nv::TEX_DIFFUSE );
268                return;
269        }
270
271        rocket_vertex* rv = (rocket_vertex*)vertices;
272
273        nv::vertex_array m_va = m_context->create_vertex_array( rv, num_vertices, (unsigned*)indices, num_indices, nv::STATIC_DRAW );
274        //if ( info )   m_device->set_uniform( m_program, "texsize", nv::vec2( info->size ) );
275        m_state.set_model( glm::translate( glm::mat4(), nv::vec3( translation.x, translation.y, 0.0f ) ) );
276        m_context->draw( nv::TRIANGLES, m_rstate, m_state, m_program, m_va, num_indices );
277        m_context->release( m_va );
278
279}
280
281/*
282int RocketSDL2SystemInterface::TranslateMouseButton( Uint8 button )
283{
284        switch ( button )
285        {
286        case SDL_BUTTON_LEFT:
287                return 0;
288        case SDL_BUTTON_RIGHT:
289                return 1;
290        case SDL_BUTTON_MIDDLE:
291                return 2;
292        default:
293                return 3;
294        }
295}
296
297int RocketSDL2SystemInterface::GetKeyModifiers()
298{
299        SDL_Keymod sdlMods = SDL_GetModState();
300
301        int retval = 0;
302
303        if ( sdlMods & KMOD_CTRL )
304                retval |= Rocket::Core::Input::KM_CTRL;
305
306        if ( sdlMods & KMOD_SHIFT )
307                retval |= Rocket::Core::Input::KM_SHIFT;
308
309        if ( sdlMods & KMOD_ALT )
310                retval |= Rocket::Core::Input::KM_ALT;
311
312        return retval;
313}
314
315*/
316
317int rocket_get_key_modifiers()
318{
319        return 0;
320}
321
322int rocket_get_mouse_buttons( const nv::mouse_button_event& button )
323{
324        return 0;
325}
326
327Rocket::Core::Input::KeyIdentifier rocket_translate_key( const nv::key_event& key )
328{
329        using namespace Rocket::Core::Input;
330
331        switch ( key.code )
332        {
333        case nv::KEY_NONE  : return KI_UNKNOWN;
334        case nv::KEY_SPACE : return KI_SPACE;
335        case nv::KEY_0: return KI_0;
336        case nv::KEY_1: return KI_1;
337        case nv::KEY_2: return KI_2;
338        case nv::KEY_3: return KI_3;
339        case nv::KEY_4: return KI_4;
340        case nv::KEY_5: return KI_5;
341        case nv::KEY_6: return KI_6;
342        case nv::KEY_7: return KI_7;
343        case nv::KEY_8: return KI_8;
344        case nv::KEY_9: return KI_9;
345        case nv::KEY_A: return KI_A;
346        case nv::KEY_B: return KI_B;
347        case nv::KEY_C: return KI_C;
348        case nv::KEY_D: return KI_D;
349        case nv::KEY_E: return KI_E;
350        case nv::KEY_F: return KI_F;
351        case nv::KEY_G: return KI_G;
352        case nv::KEY_H: return KI_H;
353        case nv::KEY_I: return KI_I;
354        case nv::KEY_J: return KI_J;
355        case nv::KEY_K: return KI_K;
356        case nv::KEY_L: return KI_L;
357        case nv::KEY_M: return KI_M;
358        case nv::KEY_N: return KI_N;
359        case nv::KEY_O: return KI_O;
360        case nv::KEY_P: return KI_P;
361        case nv::KEY_Q: return KI_Q;
362        case nv::KEY_R: return KI_R;
363        case nv::KEY_S: return KI_S;
364        case nv::KEY_T: return KI_T;
365        case nv::KEY_U: return KI_U;
366        case nv::KEY_V: return KI_V;
367        case nv::KEY_W: return KI_W;
368        case nv::KEY_X: return KI_X;
369        case nv::KEY_Y: return KI_Y;
370        case nv::KEY_Z: return KI_Z;
371        case nv::KEY_SCOLON:return KI_OEM_1;
372//      case nv::KEY_PLUS:return KI_OEM_PLUS;
373        case nv::KEY_COMMA:return KI_OEM_COMMA;
374        case nv::KEY_MINUS:return KI_OEM_MINUS;
375        case nv::KEY_PERIOD:return KI_OEM_PERIOD;
376        case nv::KEY_SLASH:return KI_OEM_2;
377        case nv::KEY_BQUOTE:return KI_OEM_3;
378        case nv::KEY_LBRACKET:return KI_OEM_4;
379        case nv::KEY_BSLASH:return KI_OEM_5;
380        case nv::KEY_RBRACKET:return KI_OEM_6;
381//      case nv::KEY_QUOTEDBL:return KI_OEM_7;
382//      case nv::KEY_KP_0:return KI_NUMPAD0;
383//      case nv::KEY_KP_1:return KI_NUMPAD1;
384//      case nv::KEY_KP_2:return KI_NUMPAD2;
385//      case nv::KEY_KP_3:return KI_NUMPAD3;
386//      case nv::KEY_KP_4:return KI_NUMPAD4;
387//      case nv::KEY_KP_5:return KI_NUMPAD5;
388//      case nv::KEY_KP_6:return KI_NUMPAD6;
389//      case nv::KEY_KP_7:return KI_NUMPAD7;
390//      case nv::KEY_KP_8:return KI_NUMPAD8;
391//      case nv::KEY_KP_9:return KI_NUMPAD9;
392//      case nv::KEY_KP_ENTER:return KI_NUMPADENTER;
393//      case nv::KEY_KP_MULTIPLY:return KI_MULTIPLY;
394//      case nv::KEY_KP_PLUS:return KI_ADD;
395//      case nv::KEY_KP_MINUS: return KI_SUBTRACT;
396//      case nv::KEY_KP_PERIOD: return KI_DECIMAL;
397//      case nv::KEY_KP_DIVIDE: return KI_DIVIDE;
398//      case nv::KEY_KP_EQUALS: return KI_OEM_NEC_EQUAL;
399        case nv::KEY_BACK    : return KI_BACK;
400        case nv::KEY_TAB     : return KI_TAB;
401//      case nv::KEY_CLEAR   : return KI_CLEAR;
402        case nv::KEY_ENTER   : return KI_RETURN;
403//      case nv::KEY_PAUSE   : return KI_PAUSE;
404//      case nv::KEY_CAPSLOCK: return KI_CAPITAL;
405        case nv::KEY_PGUP  : return KI_PRIOR;
406        case nv::KEY_PGDOWN: return KI_NEXT;
407        case nv::KEY_END   : return KI_END;
408        case nv::KEY_HOME  : return KI_HOME;
409        case nv::KEY_LEFT  : return KI_LEFT;
410        case nv::KEY_UP    : return KI_UP;
411        case nv::KEY_RIGHT : return KI_RIGHT;
412        case nv::KEY_DOWN  : return KI_DOWN;
413        case nv::KEY_INSERT: return KI_INSERT;
414        case nv::KEY_DELETE: return KI_DELETE;
415        case nv::KEY_F1    : return KI_F1;
416        case nv::KEY_F2    : return KI_F2;
417        case nv::KEY_F3    : return KI_F3;
418        case nv::KEY_F4    : return KI_F4;
419        case nv::KEY_F5    : return KI_F5;
420        case nv::KEY_F6    : return KI_F6;
421        case nv::KEY_F7    : return KI_F7;
422        case nv::KEY_F8    : return KI_F8;
423        case nv::KEY_F9    : return KI_F9;
424        case nv::KEY_F10   : return KI_F10;
425        case nv::KEY_F11   : return KI_F11;
426        case nv::KEY_F12   : return KI_F12;
427//      case nv::KEY_F13 : return KI_F13;
428//      case nv::KEY_F14 : return KI_F14;
429//      case nv::KEY_F15 : return KI_F15;
430//      case nv::KEY_NUMLOCKCLEAR : return KI_NUMLOCK;
431//      case nv::KEY_SCROLLLOCK : return KI_SCROLL;
432//      case nv::KEY_LSHIFT  : return KI_LSHIFT;
433//      case nv::KEY_RSHIFT  : return KI_RSHIFT;
434//      case nv::KEY_LCTRL   : return KI_LCONTROL;
435//      case nv::KEY_RCTRL   : return KI_RCONTROL;
436//      case nv::KEY_LALT    : return KI_LMENU;
437//      case nv::KEY_RALT    : return KI_RMENU;
438//      case nv::KEY_LGUI    : return KI_LMETA;
439//      case nv::KEY_RGUI    : return KI_RMETA;
440//      case nv::KEY_LSUPER  : return KI_LWIN;
441//  case nv::KEY_RSUPER  : return KI_RWIN;
442        default: return KI_UNKNOWN;
443        }
444
445        return KI_UNKNOWN;
446}
447
448static rocket_sdl2_render_interface* s_render_interface = nullptr;
449static rocket_sdl2_system_interface* s_system_interface = nullptr;
450static rocket_c_file_interface*      s_file_interface   = nullptr;
451
452bool nv::rocket_event( void* context, nv::io_event& event )
453{
454        Rocket::Core::Context *Context = ( Rocket::Core::Context * )context;
455        switch ( event.type )
456        {
457        case nv::EV_MOUSE_MOVE :
458                Context->ProcessMouseMove( event.mmove.x, event.mmove.y, rocket_get_key_modifiers() );
459                break;
460        case nv::EV_MOUSE_BUTTON :
461                if ( event.mbutton.pressed )
462                        Context->ProcessMouseButtonDown( rocket_get_mouse_buttons( event.mbutton ), rocket_get_key_modifiers() );
463                else
464                        Context->ProcessMouseButtonUp( rocket_get_mouse_buttons( event.mbutton ), rocket_get_key_modifiers() );
465                break;
466        case nv::EV_MOUSE_WHEEL:
467                return Context->ProcessMouseWheel( event.mwheel.y, rocket_get_key_modifiers() );
468        case nv::EV_KEY:
469                if (event.key.pressed)
470                {
471                        if ( event.key.code == KEY_BQUOTE )
472                        {
473                                Rocket::Debugger::SetVisible( !Rocket::Debugger::IsVisible() );
474                                return true;
475                        }
476
477                        return Context->ProcessKeyDown( rocket_translate_key( event.key ) , rocket_get_key_modifiers() );
478                }
479                break;
480        default:
481                break;
482        }
483        return false;
484}
485
486bool nv::rocket_initialize( nv::window* w, const char* assets_root )
487{
488        s_render_interface = new rocket_sdl2_render_interface( w->get_context() );
489        s_system_interface = new rocket_sdl2_system_interface();
490        s_file_interface   = new rocket_c_file_interface( assets_root );
491
492        Rocket::Core::SetFileInterface( s_file_interface );
493        Rocket::Core::SetRenderInterface( s_render_interface );
494        Rocket::Core::SetSystemInterface( s_system_interface );
495
496        return Rocket::Core::Initialise();
497}
498
499void nv::rocket_shutdown()
500{
501        Rocket::Core::Shutdown();
502        delete s_render_interface;
503        delete s_system_interface;
504        delete s_file_interface;
505}
Note: See TracBrowser for help on using the repository browser.