Changeset 50:f68ae1d667f9

Show
Ignore:
Timestamp:
06/01/08 13:22:54 (7 months ago)
Author:
Diggory Hardy <diggory.hardy@gmail.com>
branch:
default
convert_revision:
067317582985d938db56d3b42613dff6eaea0485
Message:

Options: impl template & new OptionsFont? class.

Options: impl template to ease creating Options sub-classes.
New OptionsFont? class (currently only controls render mode and hinting).

committer: Diggory Hardy <diggory.hardy@gmail.com>

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • codeDoc/jobs.txt

    r49 r50  
    1010Also see todo.txt and FIXME/NOTE comment marks. 
    11115   mergetag crashes with no ending > on a tag and doesn't add header data when comments are included! 
     124   LCD filtering / fonts from Options. Get yMax for font not all glyphs on line? 
    12134   Not guaranteed to catch up-click ending callback! Appears not to be a problem... 
    13144   OutOfMemoryException is not currently checked for − it should be at least in critical places (use high-level catching of all errors?). 
     
    5253 
    5354Done (for git log message): 
    54 Enabled getting the size of a text block (before or after rendering). 
     55Options: impl template to ease creating Options sub-classes. 
     56New OptionsFont class (currently only controls render mode and hinting). 
  • data/conf/options.mtt

    r48 r50  
    66<int|logLevel=1> 
    77<double|pollInterval=0.01> 
     8 
     9{font} 
     10<int|lcdFilter=0> 
     11<int|hinting=0> 
    812 
    913{video} 
  • mde/Options.d

    r43 r50  
    4545* should be used for reading variables, and via the addOptionsClass() hook will be loaded from 
    4646* files during pre-init (init0 stage). Do not write changes directly to the subclasses or they will 
    47 * not be saved; use, for example, Options.setBool(...). 
     47* not be saved; use, for example, Options.setBool(...). Use an example like OptionsMisc as a 
     48* template for creating a new Options sub-class. 
    4849* 
    4950* Details: Options sub-classes hold associative arrays of pointers to all option variables, with a 
     
    225226     
    226227    //BEGIN Templates 
    227     template store(A...) { 
    228         alias A a; 
    229     } 
    230     template decRecurse(char[] A, B...) { 
    231         static if (B.length) const char[] decRecurse = A ~ ", " ~ decRecurse!(B); 
    232         else                 const char[] decRecurse = A; 
    233     } 
    234     template decBool(A...) { 
    235         const char[] decBool = "bool " ~ decRecurse!(A) ~ ";\n"; 
    236     } 
    237     template decInt(A...) { 
    238         const char[] decInt = "int " ~ decRecurse!(A) ~ ";\n"; 
    239     } 
    240     template decDouble(A...) { 
    241         const char[] decDouble = "double " ~ decRecurse!(A) ~ ";\n"; 
    242     } 
    243     template decCharA(A...) { 
    244         const char[] decCharA = "char[] " ~ decRecurse!(A) ~ ";\n"; 
    245     } 
    246     template aaRecurse(char[] A, B...) { 
    247         static if (B.length) const char[] aaRecurse = "\""~A~"\"[]:&"~A ~ ", " ~ aaRecurse!(B); 
    248         else                 const char[] aaRecurse = "\""~A~"\"[]:&"~A; 
    249     } 
    250     template aaBool(A...) { 
    251         const char[] aaBool = "optsBool = [" ~ aaRecurse!(A) ~ "];\n"; 
    252     } 
    253     template aaInt(A...) { 
    254         const char[] aaInt = "optsInt = [" ~ aaRecurse!(A) ~ "];\n"; 
    255     } 
    256     template aaDouble(A...) { 
    257         const char[] aaDouble = "optsDouble = [" ~ aaRecurse!(A) ~ "];\n"; 
    258     } 
    259     template aaCharA(A...) { 
    260         const char[] aaCharA = "optsCharA = [" ~ aaRecurse!(A) ~ "];\n"; 
    261     } 
     228    private { 
     229        // Return index of first comma, or halts if not found. 
     230        template cIndex(char[] A) { 
     231            static if (A.length == 0) 
     232                static assert (false, "Error in implementation"); 
     233            else static if (A[0] == ',') 
     234                const size_t cIndex = 0; 
     235            else 
     236                const size_t cIndex = 1 + cIndex!(A[1..$]); 
     237        } 
     238        // Return index of first semi-colon, or halts if not found. 
     239        template scIndex(char[] A) { 
     240            static if (A.length == 0) 
     241                static assert (false, "Error: no trailing semi-colon"); 
     242            else static if (A[0] == ';') 
     243                const size_t scIndex = 0; 
     244            else 
     245                const size_t scIndex = 1 + scIndex!(A[1..$]); 
     246        } 
     247        // Look for "type symbols;" in A and return symbols as a comma separated list of names 
     248        // (even if type is encountered more than once). Output may contain spaces and, if 
     249        // non-empty, will contain a trailing comma. Assumes scIndex always returns less than A.$. 
     250        template parseT(char[] type, char[] A) { 
     251            static if (A.length < type.length + 1)  // end of input, no match 
     252                const char[] parseT = ""; 
     253            else static if (A[0] == ' ')        // leading whitespace: skip 
     254                const char[] parseT = parseT!(type, A[1..$]); 
     255            else static if (A[0..type.length] == type && A[type.length] == ' ') // match 
     256                const char[] parseT = A[type.length+1 .. scIndex!(A)] ~ "," ~ 
     257                        parseT!(type, A[scIndex!(A)+1 .. $]); 
     258            else                    // no match 
     259                const char[] parseT = parseT!(type, A[scIndex!(A)+1 .. $]); 
     260        } 
     261        // May have a trailing comma. Assumes cIndex always returns less than A.$. 
     262        template aaVars(char[] A) { 
     263            static if (A.length == 0) 
     264                const char[] aaVars = ""; 
     265            else static if (A[0] == ' ') 
     266                const char[] aaVars = aaVars!(A[1..$]); 
     267            else 
     268                const char[] aaVars = "\""~A[0..cIndex!(A)]~"\"[]:&"~A[0..cIndex!(A)] ~ "," ~ 
     269                        aaVars!(A[cIndex!(A)+1..$]); 
     270        } 
     271        // strip Trailing Comma 
     272        template sTC(char[] A) { 
     273            static if (A.length && A[$-1] == ',') 
     274                const char[] sTC = A[0..$-1]; 
     275            else 
     276                const char[] sTC = A; 
     277        } 
     278        // if string is empty (other than space) return null, otherwise enclose: [A] 
     279        template listOrNull(char[] A) { 
     280            static if (A.length == 0) 
     281                const char[] listOrNull = "null"; 
     282            else static if (A[0] == ' ') 
     283                const char[] listOrNull = listOrNull!(A[1..$]); 
     284            else 
     285                const char[] listOrNull = "["~A~"]"; 
     286        } 
     287    } protected { 
     288        /** Produces the implementation code to go in the constuctor. */ 
     289        template aaDefs(char[] A) { 
     290            const char[] aaDefs = 
     291                    "optsBool = "  ~ listOrNull!(sTC!(aaVars!(parseT!("bool"  , A)))) ~ ";\n" ~ 
     292                    "optsInt = "   ~ listOrNull!(sTC!(aaVars!(parseT!("int"   , A)))) ~ ";\n" ~ 
     293                    "optsDouble = "~ listOrNull!(sTC!(aaVars!(parseT!("double", A)))) ~ ";\n" ~ 
     294                    "optsCharA = " ~ listOrNull!(sTC!(aaVars!(parseT!("char[]", A)))) ~ ";\n"; 
     295        } 
     296        /+/** Produces the implementation code to go in the static constuctor. */ 
     297        template optClassAdd(char[] symb) { 
     298            const char[] optClassAdd = symb ~ "=new "~classinfo(this).name~";\n";//Options.addOptionsClass("~symb~", );\n"; 
     299        }+/ 
     300        /** mixin impl("type symbol[, symbol[...]];[type symbol[...];][...]") 
     301         * 
     302         * E.g. 
     303         * --- 
     304         * mixin (impl ("bool a, b; int i;")); 
     305         * --- 
     306         * 
     307         * In case this() needs to be customized, mixin(impl!(A)) is equivalent to: 
     308         * --- 
     309         * mixin (A~"\nthis(){\n"~aaDefs!(A)~"}"); 
     310         * --- 
     311         * 
     312         * Notes: Only use space as whitespace (no new-lines or tabs). Make sure to add a trailing 
     313         * semi-colon (;) or you'll get told off! :D 
     314         * 
     315         * In general errors aren't reported well. Trial with pragma (msg, impl!(...)); if 
     316         * necessary. 
     317         * 
     318         * Extending: mixins could also be used for the static this() {...} or even the whole 
     319         * class, but doing would rather decrease readability of any implementation. */ 
     320        template impl(char[] A /+, char[] symb+/) { 
     321            const char[] impl = A~"\nthis(){\n"~aaDefs!(A)~"}"; 
     322            // ~"\nstatic this(){\n"~optClassAdd!(symb)~"}" 
     323        } 
     324    } 
     325    /+/** mixin impl("type symbol[, symbol[...]];[type symbol[...];][...]") 
     326     * 
     327     * E.g. 
     328     * --- 
     329     * mixin (impl ("bool a, b; int i;")); 
     330     * --- 
     331     * The parser isn't highly accurate. */ 
     332    // Try using templates instead? See std.metastrings 
     333    static char[] impl (char[] A) { 
     334        char[] bools; 
     335        char[] ints; 
     336         
     337        while (A.length) { 
     338            // Trim whitespace 
     339            { 
     340                size_t i = 0; 
     341                while (i < A.length && (A[i] == ' ' || (A[i] >= 9u && A[i] <= 0xD))) 
     342                    ++i; 
     343                A = A[i..$]; 
     344            } 
     345            if (A.length == 0) break; 
     346             
     347            char[] type; 
     348            for (size_t i = 0; i < A.length; ++i) { 
     349                if (A[i] == ' ' || (A[i] >= 9u && A[i] <= 0xD)) { 
     350                    type = A[0..i]; 
     351                    A = A[i+1..$]; 
     352                    break; 
     353                } 
     354            } 
     355             
     356            char[] symbols; 
     357            for (size_t i = 0; i < A.length; ++i) { 
     358                if (A[i] == ';') { 
     359                    symbols = A[0..i]; 
     360                    A = A[i+1..$]; 
     361                    break; 
     362                } 
     363            } 
     364             
     365            if (type == "bool") { 
     366                if (bools.length) 
     367                    bools = bools ~ "," ~ symbols; 
     368                else 
     369                    bools = symbols; 
     370            } 
     371            else if (type == "int") { 
     372                if (ints.length) 
     373                    ints = ints ~ "," ~ symbols; 
     374                else 
     375                    ints = symbols; 
     376            } 
     377            else { 
     378                // Unfortunately, we cannot output non-const strings (even though func is compile-time) 
     379                // We also cannot use pragma(msg) because the message gets printed even if the code isn't run. 
     380                //pragma(msg, "Warning: impl failed to parse whole input string"); 
     381                // Cannot use Cout / logger either. 
     382                break; 
     383            } 
     384        } 
     385         
     386        char[] ret; 
     387        if (bools.length) 
     388            ret = "bool "~bools~";\n"; 
     389        if (ints.length) 
     390            ret = ret ~ "int "~ints~";\n"; 
     391         
     392         
     393         
     394        return ret; 
     395    }+/ 
    262396    //END Templates 
    263397} 
     
    342476OptionsMisc miscOpts; 
    343477class OptionsMisc : Options { 
    344     alias store!("useThreads", "exitImmediately") BOOL; 
    345     alias store!("logLevel") INT; 
    346     alias store!("pollInterval") DOUBLE; 
    347     alias store!("L10n") CHARA; 
    348      
    349     mixin (decBool!(BOOL.a)); 
    350     mixin (decInt!(INT.a)); 
    351     mixin (decDouble!(DOUBLE.a)); 
    352     mixin (decCharA!(CHARA.a)); 
    353      
    354     this () { 
    355         mixin (aaBool!(BOOL.a)); 
    356         mixin (aaInt!(INT.a)); 
    357         mixin (aaDouble!(DOUBLE.a)); 
    358         mixin (aaCharA!(CHARA.a)); 
    359     } 
     478    mixin (impl!("bool useThreads, exitImmediately; int logLevel; double pollInterval; char[] L10n;")); 
    360479     
    361480    static this() { 
  • mde/resource/FontTexture.d

    r49 r50  
    1515 
    1616/** Font caching system. 
     17 * 
     18 * This module also serves as the internals to the font module and shouldn't be used except through 
     19 * the font module. The two modules could be combined, at a cost to readability. 
    1720 * 
    1821 * Three types of coordinates get used in the system: FreeType coordinates for each glyph, texture 
     
    2225module mde.resource.FontTexture; 
    2326 
     27import mde.Options; 
    2428import mde.resource.exception; 
    2529 
     
    3539} 
    3640 
    37 auto hinting = FT_LOAD_TARGET_NORMAL; //or FT_LOAD_TARGET_LCD (or others) 
    38 //FIXME: allow setting lcd filtering 
    39 auto lcdFilter = FT_LcdFilter.FT_LCD_FILTER_DEFAULT;    //altertives: NONE, LIGHT 
    4041static const int dimW = 256, dimH = 256;    // Texture size 
    4142const wFactor = 1f / dimW; 
     
    202203        auto g = face.glyph; 
    203204         
    204         if (FT_Load_Glyph (face, gi, FT_LOAD_RENDER | hinting)) 
     205        // Use renderMode from options, masking bits which are allowable: 
     206        if (FT_Load_Glyph (face, gi, FT_LOAD_RENDER | (fontOpts.renderMode & 0xF0000))) 
    205207            throw new fontGlyphException ("Unable to render glyph"); 
    206208         
     
    238240            format = GL_LUMINANCE; 
    239241        else if (b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_LCD || 
    240                  b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_LCD_V) 
    241             format = GL_RGB; 
    242         else 
     242                 b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_LCD_V) { 
     243            if (fontOpts.renderMode & RENDER_LCD_BGR) 
     244                format = GL_BGR; 
     245            else 
     246                format = GL_RGB; 
     247        } else 
    243248            throw new fontGlyphException ("Unsupported freetype bitmap format"); 
    244249         
     
    375380} 
    376381 
     382// this bit of renderMode, if set, means read glyph as BGR not RGB when using LCD rendering 
     383enum { RENDER_LCD_BGR = 1 << 30 } 
     384OptionsFont fontOpts; 
     385class OptionsFont : Options { 
     386    /* renderMode should be FT_LOAD_TARGET_NORMAL, FT_LOAD_TARGET_LIGHT, FT_LOAD_TARGET_LCD or 
     387     * FT_LOAD_TARGET_LCD_V, possibly with bit 31 set (see RENDER_LCD_BGR). 
     388     * FT_LOAD_TARGET_MONO is unsupported. 
     389     * 
     390     * lcdFilter should come from enum FT_LcdFilter: 
     391     * FT_LCD_FILTER_NONE, FT_LCD_FILTER_DEFAULT, FT_LCD_FILTER_LIGHT */ 
     392    mixin (impl!("int renderMode, lcdFilter;")); 
     393     
     394    static this() { 
     395        fontOpts = new OptionsFont; 
     396        Options.addOptionsClass (fontOpts, "font"); 
     397    } 
     398} 
     399 
    377400struct GlyphAttribs { 
    378401    int x, y;   // position within texture 
  • mde/resource/font.d

    r49 r50  
    1717module mde.resource.font; 
    1818 
     19import mde.Options; 
    1920import mde.resource.FontTexture; 
    2021import mde.resource.exception; 
     
    6970                char[128] tmp; 
    7071                logger.warn (logger.format (tmp, "Using an untested FreeType version: {}.{}.{}", maj, min, patch)); 
     72            } 
     73             
     74            // Set LCD filtering method 
     75            if (FT_Library_SetLcdFilter(library, cast(FT_LcdFilter)fontOpts.lcdFilter)) { 
     76                // If setting failed, leave at default (disabled status). Note: it is disabled by 
     77                // default because the code isn't compiled in by default, to avoid patents. 
     78                logger.warn ("Bad/unsupported LCD filter option; disabling."); 
     79                Options.setInt ("font", "lcdFilter", FT_LcdFilter.FT_LCD_FILTER_NONE); 
    7180            } 
    7281             
     
    261270    FT_Face face; 
    262271} 
     272 
     273/+class OptionsFont : Options { 
     274    alias store!(+/ 
  • mde/sdl.d

    r48 r50  
    180180OptionsVideo vidOpts; 
    181181class OptionsVideo : Options { 
    182     alias store!("fullscreen","hardware","resizable","noFrame") BOOL; 
    183     alias store!("screenW","screenH","windowW","windowH") INT; 
    184     //alias store!() CHARA; 
    185      
    186     mixin (decBool!(BOOL.a)); 
    187     mixin (decInt!(INT.a)); 
    188     //mixin (decCharA!(CHARA.a)); 
    189      
    190     this () { 
    191         mixin (aaBool!(BOOL.a)); 
    192         mixin (aaInt!(INT.a)); 
    193         //mixin (aaCharA!(CHARA.a)); 
    194     } 
     182    mixin (impl!("bool fullscreen,hardware,resizable,noFrame; int screenW,screenH,windowW,windowH;")); 
    195183     
    196184    static this() {