There's no such thing as a "half empty glass"

Retina, 56 bytes

T%` l`!`^.*?#|[^#]+$
O` |\w
*`!
 
T`#!¶
*M` \w
+` \w

 +

Try it online!

The output encoding is 0\n0 for full, 0\n1 for empty, 1\n0 for mostly full and 1\n1 for mostly empty (in other words, the first bit indicates "mostly" and the second bit indicates "empty").

Explanation

T%` l`!`^.*?#|[^#]+$

We start by turning all spaces and letters outside the glass into !. This is done by matching either a line-beginning up to the first # or by matching a line-ending that doesn't contain a # and transliterating all spaces and letters in those matches.

O` |\w

Sort all spaces and letters. Since letters have higher code points than spaces, this sorts all the letters to the end, which means to the bottom of the glass. This also happens to sort the letters among themselves, but the order of the letters in the result is irrelevant.

*`!
 

Dry run: print the result of replacing all ! with spaces, but don't actually apply this change to the working string. This prints the nice glass.

T`#!¶

Discard all #, ! and linefeeds, so that we're only left with the spaces and letters inside the glass (still sorted).

*M` \w

Dry run: print the number of matches of a space followed by a letter. This will find at most one match, and that only if the there were both spaces and letters inside the glass, i.e. the glass is mostly (full/empty).

+` \w

Repeatedly remove a space followed by a letter. This "cancels" letters and spaces, so that we end up with only that type of character which appears more often inside the glass.

 +

Count the number of matches of this regex, which gives 1 if there are any spaces left (i.e. the glass was [mostly] empty) and 0 if there are non left (i.e. the glass was at exactly 50% or more and therefore [mostly] full).


C, 190 bytes

Thanks to @l4m2 for saving 17 bytes!

i,k,t,s;f(char*g){char*p=g,l[strlen(g)];for(s=t=0;*p;*p>35&&(t?l[i++]=*p:1)?*p=32:0,~*p++&t&&++s)t^=*p==35;for(k=i;i;t&*p==32?*p=l[--i]:0)t^=*--p==35;printf("%s\n%d",g,k?k-s?k*2<s?1:2:3:0);}

Outputs 0 for empty glass, 1 for mostly empty, 2 for mostly full, and 3 for full.

First loops through the input string counting the space inside the glass, marking down letters that are inside the glass, and changing all letters to spaces. Then loops through the string backwards placing all the letters that were in the glass at the bottom of the glass.

Try it online!

Unrolled:

i,k,t,s;
f(char*g)
{
    char l[strlen(g)], *p=g;
    for (s=t=0; *p; *p>35&&(t?l[i++]=*p:1)?*p=32:0, ~*p++&t&&++s)
        t ^= *p==35;
    for (k=i; i; t&*p==32?*p=l[--i]:0)
        t ^= *--p==35;
    printf("%s\n%d", g, k?k-s?k*2<s?1:2:3:0);
}