!===============================================================================!
! SGW - a Simple Glulxe Wrapper
!===============================================================================!
! (by Alessandro Schillaci, Vincenzo Scarpa, Paolo Maroncelli)
!
! WeB   : http://slade.altervista.org
! @mail : silver.slade@tiscalinet.it
!
! Version 1.6.1 2006-03-11
!===============================================================================!
!
! WHAT IS THIS FOR ?
! ==================
! "sgw.h" (this file) is a simple and small glulxe wrapper, created for a novice
! inform programming level.
! With this library it's possible to visualize an image or simply to play a sound
! (or a music) by using a small set of functions that wrap the glulx functions.
! There are also text styles ready to be used.
!
! It's possible to convert a z-code adventure to a glulx adventure with
! multimedia support, in few steps.
!
! You can use 3 audio channels:
!
! - music : for the music channel
! - chan1 : channel 1 for audio (sound effects)
! - chan2 : channel 2 for audio (sound effects)
!
!===============================================================================!
!
! HOW TO USE
! ==========
!
! Just follow these points:
!
! 1) Put in your main file the directive
!    include "sgw.h";
!    before the Include "Parser"; directive
!
! 2) Use the initializeSGW(x) function in your initialize standard function.
!
!    Example:
!
!    initializeSGW(240);
!
!    This will set the main graphic window to have an height=240 pixels
!    but you can change this resolution as you like.
!
! 3) Now you can play a sound or visualize an image simply using these functions into your Inform
!    code: viewImageLeft (or viewImageCenter or viewImageRight) and playSound()
!
! 4) You can customize colors settings, by create these Globals
!    before you include the "sgw.h" library, to override them
!
!    Constant SCBACK $110101;
!    Constant SCTEXT $DDBB99;
!    Constant SCSOFT $665544;
!    Constant SCEMPH $FFFFDD;
!    Constant SCHEAD $EEDDAA;
!    Constant SCINPU $DDEEAA;
!
! 5) If you want to use ONLY the sounds (no graphics) you should define this constant
!
!    Constant NOGRAPHICS;
!
!    Before you Include the sgw.h library
!
! 6) If you want to use the text styles (examples):
!
!  with description [;
!             print "Text Style ", (s_emph) "Emphasized", "^";
!             print "Text Style ", (s_bold) "Bold", " (like Inform)^";
!             print "Text Style ", (s_pref) "Preformatted", "^";
!             print "Text Style ", (s_fixed) "Fixed", " (like Inform)^";
!             print "Text Style ", (s_head) "Header", "^";
!             print "Text Style ", (s_subhead) "Subheader", "^";
!             print "Text Style ", (s_alert) "Alert", "^";
!             print "Text Style ", (s_reverse) "Reverse", " (like Inform)^";
!             print "Text Style ", (s_note) "Note", "^";
!             print "Text Style ", (s_underline) "Underline/Italic", " (like Inform)^";
!             print "Text Style ", (s_block) "BlockQuote", "^";
!             print "Text Style ", (s_input) "Input", "^";
!       ],
!
!
!
! You can use these new simple functions in your game, also :
!
! GRAPHIC FUNCTIONS
! =================
! clearMainWindow()                     = clears the main window
! closeAllWindows()                     = closes all graphic windows
! initializeSGW(h)                      = graphic window dimension is set to h=height
! viewImageLeft(image)                  = shows the "image" in the graphic window on the Left
! viewImageCenter(image, image_width)   = shows the "image" in the graphic window (Centered)
! viewImageRight(image, image_width)    = shows the "image" in the graphic window on the Right
!
!
! AUDIO FUNCTIONS
! ===============
! playSound(channel,sound,lenght,volume)    = plays a sound/music
! silenceAll()                                = silences all audio channels
! silenceChannel(channel)                    = silences the audio "channel"
! setVolume(val, channel)                    = set "val" for volume of the channel
!
!
!
!===============================================================================!
! LICENSE
! =======
!
! This file is free software, it can be freely used, copied, distribuited and
! modified. Any modified or unmodified copy of this file distribuited as source
! code must acknoledge the original author and must be freely usable, copyable,
! distributable and modifiable.
! There's absolutely no condition or binding on the distribution as compiled
! binary file.
! This software is distribuited as-is, with NO WARRANTY. The author cannot be
! held as responsable for any damage due directly or indirectly to this file.
!
!===============================================================================!

message "Using the SGW 1.6.1 (Simple Glulxe Wrapper) library by Alessandro Schillaci";

#Ifdef NOGRAPHICS;
    message "[SGW] Using ONLY sounds";
#Endif;

Global music                    = 0;            ! Music Channel
Global chan1                    = 0;            ! Channel 1 sound effects
Global chan2                    = 0;            ! Channel 2 sound effects

Constant VOLUME_HIGH            5;
Constant VOLUME_NORMAL          3;
Constant VOLUME_LOW             2;

#IfDef TARGET_GLULX;
Global current_music            = 0;
Global gg_VolumeSupport            = false;        ! Change Volume supported?
Global gg_statuswin;
Global gg_mainwin;                                ! Text window
Global gg_bigwin;                                ! Image Location window
Global curr_pic;
Global curr_pic_pos;
Global curr_pic_width;

Constant GG_MUSICCHAN_ROCK          410;
Constant GG_MUSICCHANSOUND1_ROCK    411;
Constant GG_MUSICCHANSOUND2_ROCK    412;
Constant GG_BIGWIN_ROCK             210;        ! Image Location window

! Position constants - added by Paolo Maroncelli
Constant POS_GG_LEFT            1;
Constant POS_GG_CENTER            2;
Constant POS_GG_RIGHT            3;

! Colors constants - added by Vincenzo Scarpa
#Ifndef CLR_GG_AZURE;
    Constant CLR_GG_AZURE                 $30ffff;
#Endif;
#Ifndef CLR_GG_BLACK;
    Constant CLR_GG_BLACK                 $000000;
#Endif;
#Ifndef CLR_GG_BLUE;
    Constant CLR_GG_BLUE                  $0000a0;
#Endif;
#Ifndef CLR_GG_BROWN;
    Constant CLR_GG_BROWN                 $7f3f00;
#Endif;
#Ifndef CLR_GG_CYAN;
    Constant CLR_GG_CYAN                  $30ffff;
#Endif;
#Ifndef CLR_GG_GREEN;
    Constant CLR_GG_GREEN                 $30ff30;
#Endif;
#Ifndef CLR_GG_GREY;
    Constant CLR_GG_GREY                  $bfbfbf;
#Endif;
#Ifndef CLR_GG_MAGENTA;
    Constant CLR_GG_MAGENTA               $ff30ff;
#Endif;
#Ifndef CLR_GG_ORANGE;
    Constant CLR_GG_ORANGE                $ff7f00;
#Endif;
#Ifndef CLR_GG_PINK;
    Constant CLR_GG_PINK                  $ff7fff;
#Endif;
#Ifndef CLR_GG_PURPLE;
    Constant CLR_GG_PURPLE                $ff30ff;
#Endif;
#Ifndef CLR_GG_RED;
    Constant CLR_GG_RED                   $ff3030;
#Endif;
#Ifndef CLR_GG_YELLOW;
    Constant CLR_GG_YELLOW                $ffff30;
#Endif;
#Ifndef CLR_GG_WHITE;
    Constant CLR_GG_WHITE                 $ffffff;
#Endif;
#Ifndef CLR_GG_PERSBACK;
    Constant CLR_GG_PERSBACK              $110101;
#Endif;
#Ifndef CLR_GG_PERSTEXT;
    Constant CLR_GG_PERSTEXT              $DDBB99;
#Endif;
#Ifndef CLR_GG_PERSSOFT;
    Constant CLR_GG_PERSSOFT              $665544;
#Endif;
#Ifndef CLR_GG_PERSEMPH;
    Constant CLR_GG_PERSEMPH              $FFFFDD;
#Endif;
#Ifndef CLR_GG_PERSHEAD;
    Constant CLR_GG_PERSHEAD              $EEDDAA;
#Endif;
#Ifndef CLR_GG_PERSINPU;
    Constant CLR_GG_PERSINPU              $DDEEAA;
#Endif;

! Colors settings
#Ifndef SCBACK;
    Constant SCBACK                CLR_GG_PERSBACK;
#Endif;
#Ifndef SCTEXT;
    Constant SCTEXT                CLR_GG_PERSTEXT;
#Endif;
#Ifndef SCSOFT;
    Constant SCSOFT                CLR_GG_PERSSOFT;
#Endif;
#Ifndef SCEMPH;
    Constant SCEMPH                CLR_GG_PERSEMPH;
#Endif;
#Ifndef SCHEAD;
    Constant SCHEAD                CLR_GG_PERSHEAD;
#Endif;
#Ifndef SCINPU;
    Constant SCINPU                CLR_GG_PERSINPU;
#Endif;
#Endif;

[ initializeSGW h;
    #Ifdef TARGET_GLULX;
        if (music == 0) {music = glk_schannel_create(GG_MUSICCHAN_ROCK);            }
        if (chan1 == 0) {chan1 = glk_schannel_create(GG_MUSICCHANSOUND1_ROCK);    }
        if (chan2 == 0) {chan2 = glk_schannel_create(GG_MUSICCHANSOUND2_ROCK);    }
        testGlulx();        ! Test about Interpreter's performances
        closeAllWindows();  ! Closing all window
        silenceAll();       ! Silence all audio channels
        inizializeGlulx(h); ! Inizialize the glulx system
    #Endif;
];


! --- Texts functions - added by Vincenzo Scarpa -------------------------------------

! Text in Emphasized style
[ s_emph text;
   #Ifdef TARGET_GLULX;
       glk_set_style(style_Emphasized);
       print (string) text;
       glk_set_style(style_Normal);
   #endif;
];

! Text in Bold style (like Inform)
[ s_bold text;
   #Ifdef TARGET_GLULX;
       print (s_emph) text;
   #endif;
];

! Text in Preformatted style
[ s_pref text;
    #Ifdef TARGET_GLULX;
       glk_set_style(style_Preformatted);
       print (string) text;
       glk_set_style(style_Normal);
    #endif;
];

! Text in Fixed style (like Inform)
[ s_fixed text;
    #Ifdef TARGET_GLULX;
       print (s_pref) text;
    #endif;
];

! Text in Header style
[ s_head text;
    #Ifdef TARGET_GLULX;
       glk_set_style(style_Header);
       print (string) text;
       glk_set_style(style_Normal);
    #endif;
];

! Text in Subheader style
[ s_subhead text;
    #Ifdef TARGET_GLULX;
       glk_set_style(style_Subheader);
       print (string) text;
       glk_set_style(style_Normal);
    #endif;
];

! Text in Alert style
[ s_alert text;
    #Ifdef TARGET_GLULX;
       glk_set_style(style_Alert);
       print (string) text;
       glk_set_style(style_Normal);
    #endif;
];

! Text in Reverse style (like Inform)
[ s_reverse text;
    #Ifdef TARGET_GLULX;
       print (s_alert) text;
    #endif;
];

! Text in Note style
[ s_note text;
    #Ifdef TARGET_GLULX;
       glk_set_style(style_Note);
       print (string) text;
       glk_set_style(style_Normal);
    #endif;
];

! Text in Underline/Italic style (like Inform)
[ s_underline text;
    #Ifdef TARGET_GLULX;
       print (s_note) text;
    #endif;
];

! Text in BlockQuote style
[ s_block text;
    #Ifdef TARGET_GLULX;
       glk_set_style(style_BlockQuote);
       print (string) text;
       glk_set_style(style_Normal);
    #endif;
];

! Text in Input style
[ s_input text;
    #Ifdef TARGET_GLULX;
       glk_set_style(style_Input);
       print (string) text;
       glk_set_style(style_Normal);
    #endif;
];


! --- Graphics functions -------------------------------------------------------------

! Centralized visualization routine - added by Paolo Maroncelli
[ viewImageSGW finestra_larghezza x_pos;
    #Ifdef TARGET_GLULX;
        #Ifndef NOGRAPHICS;    
            glk_window_clear(gg_bigwin);
            glk_window_get_size(gg_bigwin, gg_arguments, gg_arguments+WORDSIZE);
            finestra_larghezza = gg_arguments-->0;
            switch (curr_pic_pos) {
                POS_GG_LEFT:    x_pos = 0;
                POS_GG_CENTER:    x_pos = (finestra_larghezza/2)-(curr_pic_width/2);
                POS_GG_RIGHT:    x_pos = (finestra_larghezza)-(curr_pic_width);
            }
            if (gg_bigwin && glk_gestalt(gestalt_Graphics, 0)) {
                glk_image_draw(gg_bigwin, curr_pic, x_pos, 0);
            }
        #endif;
    #endif;
];

! View an image on the left of the main graphic window
[ viewImageLeft image;
    #Ifdef TARGET_GLULX;
        curr_pic = image;
        curr_pic_pos = POS_GG_LEFT;
        curr_pic_width = 0;
        viewImageSGW();
    #endif;
];

! View an image on the center of the main graphic window
[ viewImageCenter image image_width;
    #Ifdef TARGET_GLULX;
        curr_pic = image;
        curr_pic_pos = POS_GG_CENTER;
        curr_pic_width = image_width;
        viewImageSGW();
    #endif;
];

! View an image on the right of the main graphic window
[ viewImageRight image image_width;
    #Ifdef TARGET_GLULX;
        curr_pic = image;
        curr_pic_pos = POS_GG_RIGHT;
        curr_pic_width = image_width;
        viewImageSGW();    
    #endif;
];

! Clean the main window
[ clearMainWindow;
    #Ifdef TARGET_GLULX;
        #Ifndef NOGRAPHICS;
            glk_window_set_background_color(gg_mainwin,SCBACK);
            glk_window_clear(gg_mainwin);
            glk_window_set_background_color(gg_bigwin,SCBACK);
            glk_window_clear(gg_bigwin);
        #endif;
    #endif;
];

! Close all windows
[ closeAllWindows;
    #Ifdef TARGET_GLULX;
        #Ifndef NOGRAPHICS;
            if (gg_bigwin) {
                glk_window_close(gg_bigwin,0);
                gg_bigwin = 0;
            }
        #endif;
    #endif;
];

! Redraws an image
[ MyRedrawGraphicsWindows ;
    viewImageSGW();
];

![ MyRedrawGraphicsWindows finestra_larghezza;
!    #Ifdef TARGET_GLULX;
!        #Ifndef NOGRAPHICS;
!            ! WIDTH for center image
!            glk_window_set_background_color(gg_bigwin,SCBACK);
!            #Ifdef SGW_WIDTH;
!                glk_window_get_size(gg_bigwin, gg_arguments, gg_arguments+WORDSIZE);
!                finestra_larghezza = gg_arguments-->0;
!                glk_window_clear(gg_bigwin);
!                if (gg_bigwin && glk_gestalt(gestalt_Graphics, 0)) {
!                    glk_image_draw(gg_bigwin, curr_pic, ((finestra_larghezza/2)-(SGW_WIDTH/2)), 0);
!                }
!            #Ifnot;
!                if (gg_bigwin && glk_gestalt(gestalt_Graphics, 0)) {
!                    glk_image_draw(gg_bigwin, curr_pic, 0, 0);
!                }
!            #endif;
!        #endif;
!    #endif;
!];

! --- Audio functions -------------------------------------------------------------

! Plays the sound "sound" for the channel "channel" , with "lenght" and "volume"
[ playSound channel sound lenght volume;
    #Ifdef TARGET_GLULX;
        if (channel) {
            current_music = sound;
            glk_schannel_stop(channel);
            SetVolume(volume,channel);
            glk_schannel_play_ext(channel, sound, lenght, 0);
        }
    #endif;
];

! Sileces all the audio channels
[ silenceAll;
    #Ifdef TARGET_GLULX;
        if (chan1) {    glk_schannel_stop(chan1); }
        if (chan2) {    glk_schannel_stop(chan2); }
        if (music) {    glk_schannel_stop(music); }
    #Endif;
];

! Silences the channel "channel"
[ silenceChannel channel;
    #Ifdef TARGET_GLULX;
        if (channel) {
            glk_schannel_stop(channel);
        }
    #endif;
];

! Reset all audio channels
[ resetMusicChannel;
    #Ifdef TARGET_GLULX;
        glk_schannel_stop(music);
        glk_schannel_stop(chan1);
        glk_schannel_stop(chan2);
    #endif;
];

! Set a volume for the channel
[ setVolume val chan;
    #Ifdef TARGET_GLULX;
        if (~~gg_VolumeSupport) return;
        if (val > 0) glk_schannel_set_volume(chan, val * 16384);
    #endif;
];



! --- GLULX functions ------------------------------------------------------------- !

#Ifdef TARGET_GLULX;

[ HandleGlkEvent event ;
    switch (event-->0) {
            evtype_Redraw, evtype_Arrange  :    MyRedrawGraphicsWindows();
                    evtype_SoundNotify:            glk_schannel_play_ext(music, current_music, 1, 1);
                    evtype_SoundNotify:            glk_schannel_play_ext(music, , 1, 1);

        4:                ! mouse
        1:                ! timer
        5, 6:            ! arrange/redraw
    }
];

! Glk window initialization entry point.
[ InitGlkWindow winrock;
    switch (winrock) {
         GG_MAINWIN_ROCK:
            glk_stylehint_set(wintype_AllTypes, style_Normal, stylehint_TextColor, SCTEXT);
            glk_stylehint_set(wintype_AllTypes, style_Normal, stylehint_BackColor, SCBACK);
            glk_stylehint_set(wintype_AllTypes, style_Normal, stylehint_Justification, stylehint_just_LeftRight);
            glk_stylehint_set(wintype_AllTypes, style_Emphasized, stylehint_TextColor, SCEMPH);
            glk_stylehint_set(wintype_AllTypes, style_Emphasized, stylehint_BackColor, SCBACK);
            glk_stylehint_set(wintype_AllTypes, style_Header, stylehint_TextColor, SCEMPH);
            glk_stylehint_set(wintype_AllTypes, style_Header, stylehint_BackColor, SCBACK);
            glk_stylehint_set(wintype_AllTypes, style_Subheader, stylehint_TextColor, SCHEAD);
            glk_stylehint_set(wintype_AllTypes, style_Subheader, stylehint_BackColor, SCBACK);
            glk_stylehint_set(wintype_AllTypes, style_Alert, stylehint_TextColor, SCBACK);
            glk_stylehint_set(wintype_AllTypes, style_Alert, stylehint_BackColor, SCTEXT);
            glk_stylehint_set(wintype_AllTypes, style_Note, stylehint_TextColor, SCINPU);
            glk_stylehint_set(wintype_AllTypes, style_Note, stylehint_BackColor, SCBACK);
            glk_stylehint_set(wintype_AllTypes, style_Blockquote, stylehint_TextColor, SCINPU);
            glk_stylehint_set(wintype_AllTypes, style_Blockquote, stylehint_BackColor, SCBACK);
            glk_stylehint_set(wintype_AllTypes, style_Input, stylehint_TextColor, SCINPU);
            glk_stylehint_set(wintype_AllTypes, style_Input, stylehint_BackColor, SCBACK);
            glk_stylehint_set(wintype_AllTypes, style_Preformatted, stylehint_TextColor, SCINPU);
            glk_stylehint_set(wintype_AllTypes, style_Preformatted, stylehint_BackColor, SCBACK);
            glk_stylehint_set(wintype_AllTypes, style_User1, stylehint_TextColor, SCSOFT);
            glk_stylehint_set(wintype_AllTypes, style_User1, stylehint_BackColor, SCBACK);
    }
    rfalse;
];


! Glk object identification entry point.
[ IdentifyGlkObject phase type ref rock id;

    switch (phase) {
    0:    ! start
        gg_bigwin            = 0;
        gg_statuswin            = 0;
        music                = 0;
        chan1                = 0;
        chan2                = 0;
        return;
    1:    ! pass ref
        switch (type) {
        0:    ! window ref
            switch (rock) {
                GG_BIGWIN_ROCK    :    gg_bigwin    = ref;
            }
        }
        return;
    2:  ! Update objects
         id = glk_schannel_iterate(0, gg_arguments);
         while (id) {
            switch (gg_arguments-->0) {
               GG_MUSICCHAN_ROCK        : music    = id;
               GG_MUSICCHANSOUND1_ROCK    : chan1    = id;
               GG_MUSICCHANSOUND2_ROCK    : chan2    = id;
           }
           id = glk_schannel_iterate(id, gg_arguments);
         }
         ResetMusicChannel();
         MyRedrawGraphicsWindows();
         return;
    }
    return;
];


! Test the Glulx Interpreter's performances
[ testGlulx;
    #Ifndef NOGRAPHICS;
        if (~~glk_gestalt(gestalt_Graphics, 0)) {
            print "^[This Interpreter doesn't support graphics.]^";
        }
    #Endif;

      if (~~glk_gestalt(gestalt_GraphicsTransparency, 0)) {
        print "^[This Interpreter doesn't support transparency.]^";
    }

      if (~~glk_gestalt(gestalt_Version, 0)) {
        print "^[This Interpreter doesn't support this version.]^";
    }

    if (~~glk_gestalt(gestalt_Sound, 0)) {
        print "^[This Interpreter doesn't support sound.]^";
    }

    if (~~glk_gestalt(gestalt_SoundVolume, 0)) {
        print "^[This Interpreter doesn't support sound volume.]^";
    }

      if (~~glk_gestalt(gestalt_SoundMusic, 0)) {
        print "^[This Interpreter doesn't support mod music.]^";
    }

      if (~~glk_gestalt(gestalt_SoundNotify, 0)) {
        print "^[This Interpreter doesn't support sound notify.]^";
    }

      if (~~glk_gestalt(gestalt_Timer, 0)) {
        print "^[This Interpreter doesn't support timer.]^";
    }

      if (~~glk_gestalt(gestalt_Hyperlinks, 0)) {
        print "^[This Interpreter doesn't support hyperlinks.]^";
    }
];


! Glulx Inizialize function
[ inizializeGlulx h;

    #Ifndef NOGRAPHICS;
        ! Graphics
        if (gg_statuswin == 0) {
            gg_statuswin = glk_window_open(gg_mainwin,(winmethod_Above+winmethod_Fixed), 2, wintype_TextGrid, GG_BIGWIN_ROCK);
        }

        if (gg_bigwin == 0) {
            gg_bigwin = glk_window_open(gg_mainwin,(winmethod_Above+winmethod_Fixed), h , wintype_Graphics, GG_BIGWIN_ROCK);
        }

        ! Set black as background colour for all windows
        glk_window_set_background_color(gg_bigwin,SCBACK);
        glk_window_clear(gg_bigwin);
        glk_window_set_background_color(gg_mainwin,SCBACK);
        glk_window_clear(gg_mainwin);
    #endif;
];

#Endif;
