Esempio n. 1
0
//-----------------------------------------------------------------------------
// Export a view of the model as an image; we just take a screenshot, by
// rendering the view in the usual way and then copying the pixels.
//-----------------------------------------------------------------------------
void SolveSpace::ExportAsPngTo(char *filename) {
    int w = (int)SS.GW.width, h = (int)SS.GW.height;
    // No guarantee that the back buffer contains anything valid right now,
    // so repaint the scene. And hide the toolbar too.
    int prevShowToolbar = SS.showToolbar;
    SS.showToolbar = false;
    SS.GW.Paint();
    SS.showToolbar = prevShowToolbar;
    
    FILE *f = fopen(filename, "wb");
    if(!f) goto err;

    png_struct *png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
        NULL, NULL, NULL);
    if(!png_ptr) goto err;

    png_info *info_ptr = png_create_info_struct(png_ptr);
    if(!png_ptr) goto err;

    if(setjmp(png_jmpbuf(png_ptr))) goto err;

    png_init_io(png_ptr, f);

    // glReadPixels wants to align things on 4-boundaries, and there's 3
    // bytes per pixel. As long as the row width is divisible by 4, all
    // works out.
    w &= ~3; h &= ~3;

    png_set_IHDR(png_ptr, info_ptr, w, h,
        8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
    
    png_write_info(png_ptr, info_ptr);

    // Get the pixel data from the framebuffer
    BYTE *pixels = (BYTE *)AllocTemporary(3*w*h);
    BYTE **rowptrs = (BYTE **)AllocTemporary(h*sizeof(BYTE *));
    glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pixels);

    int y;
    for(y = 0; y < h; y++) {
        // gl puts the origin at lower left, but png puts it top left
        rowptrs[y] = pixels + ((h - 1) - y)*(3*w);
    }
    png_write_image(png_ptr, rowptrs);

    png_write_end(png_ptr, info_ptr);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    fclose(f);
    return;

err:    
    Error("Error writing PNG file '%s'", filename);
    if(f) fclose(f);
    return;
}
Esempio n. 2
0
SBsp3 *SBsp3::Alloc(void) { return (SBsp3 *)AllocTemporary(sizeof(SBsp3)); }
Esempio n. 3
0
SBsp2 *SBsp2::Alloc(void) { return (SBsp2 *)AllocTemporary(sizeof(SBsp2)); }
Esempio n. 4
0
SEdgeLl *SEdgeLl::Alloc(void) {
    return (SEdgeLl *)AllocTemporary(sizeof(SEdgeLl));
}
Esempio n. 5
0
//-----------------------------------------------------------------------------
// Make a kd-tree of edges. This is used for O(log(n)) implementations of stuff
// that would naively be O(n).
//-----------------------------------------------------------------------------
SKdNodeEdges *SKdNodeEdges::Alloc(void) {
    return (SKdNodeEdges *)AllocTemporary(sizeof(SKdNodeEdges));
}
Esempio n. 6
0
//-----------------------------------------------------------------------------
// Load a glyph from the .ttf file into memory. Assumes that the .ttf file
// is already seeked to the correct location, and writes the result to
// glyphs[index]
//-----------------------------------------------------------------------------
void TtfFont::LoadGlyph(int index) {
    if(index < 0 || index >= glyphs) return;

    int i;

    SWORD contours          = GetWORD();
    SWORD xMin              = GetWORD();
    SWORD yMin              = GetWORD();
    SWORD xMax              = GetWORD();
    SWORD yMax              = GetWORD();

    if(useGlyph['A'] == index) {
        scale = (1024*1024) / yMax;
    }

    if(contours > 0) {
        WORD *endPointsOfContours =
            (WORD *)AllocTemporary(contours*sizeof(WORD));

        for(i = 0; i < contours; i++) {
            endPointsOfContours[i] = GetWORD();
        }
        WORD totalPts = endPointsOfContours[i-1] + 1;

        WORD instructionLength = GetWORD();
        for(i = 0; i < instructionLength; i++) {
            // We can ignore the instructions, since we're doing vector
            // output.
            (void)GetBYTE();
        }

        BYTE  *flags = (BYTE *)AllocTemporary(totalPts*sizeof(BYTE));
        SWORD *x     = (SWORD *)AllocTemporary(totalPts*sizeof(SWORD));
        SWORD *y     = (SWORD *)AllocTemporary(totalPts*sizeof(SWORD));

        // Flags, that indicate format of the coordinates
#define FLAG_ON_CURVE           (1 << 0)
#define FLAG_DX_IS_BYTE         (1 << 1)
#define FLAG_DY_IS_BYTE         (1 << 2)
#define FLAG_REPEAT             (1 << 3)
#define FLAG_X_IS_SAME          (1 << 4)
#define FLAG_X_IS_POSITIVE      (1 << 4)
#define FLAG_Y_IS_SAME          (1 << 5)
#define FLAG_Y_IS_POSITIVE      (1 << 5)
        for(i = 0; i < totalPts; i++) {
            flags[i] = GetBYTE();
            if(flags[i] & FLAG_REPEAT) {
                int n = GetBYTE();
                BYTE f = flags[i];
                int j;
                for(j = 0; j < n; j++) {
                    i++;
                    if(i >= totalPts) {
                        throw "too many points in glyph";
                    }
                    flags[i] = f;
                }
            }
        }

        // x coordinates
        SWORD xa = 0;
        for(i = 0; i < totalPts; i++) {
            if(flags[i] & FLAG_DX_IS_BYTE) {
                BYTE v = GetBYTE();
                if(flags[i] & FLAG_X_IS_POSITIVE) {
                    xa += v;
                } else {
                    xa -= v;
                }
            } else {
                if(flags[i] & FLAG_X_IS_SAME) {
                    // no change
                } else {
                    SWORD d = GetWORD();
                    xa += d;
                }
            }
            x[i] = xa;
        }

        // y coordinates
        SWORD ya = 0;
        for(i = 0; i < totalPts; i++) {
            if(flags[i] & FLAG_DY_IS_BYTE) {
                BYTE v = GetBYTE();
                if(flags[i] & FLAG_Y_IS_POSITIVE) {
                    ya += v;
                } else {
                    ya -= v;
                }
            } else {
                if(flags[i] & FLAG_Y_IS_SAME) {
                    // no change
                } else {
                    SWORD d = GetWORD();
                    ya += d;
                }
            }
            y[i] = ya;
        }
   
        Glyph *g = &(glyph[index]);
        g->pt = (FontPoint *)MemAlloc(totalPts*sizeof(FontPoint));
        int contour = 0;
        for(i = 0; i < totalPts; i++) {
            g->pt[i].x = x[i];
            g->pt[i].y = y[i];
            g->pt[i].onCurve = (BYTE)(flags[i] & FLAG_ON_CURVE);

            if(i == endPointsOfContours[contour]) {
                g->pt[i].lastInContour = true;
                contour++;
            } else {
                g->pt[i].lastInContour = false;
            }
        }
        g->pts = totalPts;
        g->xMax = xMax;
        g->xMin = xMin;

    } else {
        // This is a composite glyph, TODO.
    }
}
Esempio n. 7
0
//-----------------------------------------------------------------------------
// Load a TrueType font into memory. We care about the curves that define
// the letter shapes, and about the mappings that determine which glyph goes
// with which character.
//-----------------------------------------------------------------------------
bool TtfFont::LoadFontFromFile(bool nameOnly) {
    if(loaded) return true;

    int i;
    
    fh = fopen(fontFile, "rb");
    if(!fh) {
        return false;
    }

    try {
        // First, load the Offset Table
        DWORD   version         = GetDWORD();
        WORD    numTables       = GetWORD();
        WORD    searchRange     = GetWORD();
        WORD    entrySelector   = GetWORD();
        WORD    rangeShift      = GetWORD();

        // Now load the Table Directory; our goal in doing this will be to
        // find the addresses of the tables that we will need.
        DWORD   glyfAddr = -1, glyfLen;
        DWORD   cmapAddr = -1, cmapLen;
        DWORD   headAddr = -1, headLen;
        DWORD   locaAddr = -1, locaLen;
        DWORD   maxpAddr = -1, maxpLen;
        DWORD   nameAddr = -1, nameLen;
        DWORD   hmtxAddr = -1, hmtxLen;
        DWORD   hheaAddr = -1, hheaLen;

        for(i = 0; i < numTables; i++) {
            char tag[5] = "xxxx";
            tag[0]              = GetBYTE();
            tag[1]              = GetBYTE();
            tag[2]              = GetBYTE();
            tag[3]              = GetBYTE();
            DWORD   checksum    = GetDWORD();
            DWORD   offset      = GetDWORD();
            DWORD   length      = GetDWORD();

            if(strcmp(tag, "glyf")==0) {
                glyfAddr = offset;
                glyfLen = length;
            } else if(strcmp(tag, "cmap")==0) {
                cmapAddr = offset;
                cmapLen = length;
            } else if(strcmp(tag, "head")==0) {
                headAddr = offset;
                headLen = length;
            } else if(strcmp(tag, "loca")==0) {
                locaAddr = offset;
                locaLen = length;
            } else if(strcmp(tag, "maxp")==0) {
                maxpAddr = offset;
                maxpLen = length;
            } else if(strcmp(tag, "name")==0) {
                nameAddr = offset;
                nameLen = length;
            } else if(strcmp(tag, "hhea")==0) {
                hheaAddr = offset;
                hheaLen = length;
            } else if(strcmp(tag, "hmtx")==0) {
                hmtxAddr = offset;
                hmtxLen = length;
            }
        }

        if(glyfAddr == -1 || cmapAddr == -1 || headAddr == -1 ||
           locaAddr == -1 || maxpAddr == -1 || hmtxAddr == -1 ||
           nameAddr == -1 || hheaAddr == -1)
        {
            throw "missing table addr";
        }

        // Load the name table. This gives us display names for the font, which
        // we need when we're giving the user a list to choose from.
        fseek(fh, nameAddr, SEEK_SET);

        WORD  nameFormat            = GetWORD();
        WORD  nameCount             = GetWORD();
        WORD  nameStringOffset      = GetWORD();
        // And now we're at the name records. Go through those till we find
        // one that we want.
        int displayNameOffset, displayNameLength;
        for(i = 0; i < nameCount; i++) {
            WORD    platformID      = GetWORD();
            WORD    encodingID      = GetWORD();
            WORD    languageID      = GetWORD();
            WORD    nameId          = GetWORD();
            WORD    length          = GetWORD();
            WORD    offset          = GetWORD();

            if(nameId == 4) {
                displayNameOffset = offset;
                displayNameLength = length;
                break;
            }
        }
        if(nameOnly && i >= nameCount) {
            throw "no name";
        }

        if(nameOnly) {
            // Find the display name, and store it in the provided buffer.
            fseek(fh, nameAddr+nameStringOffset+displayNameOffset, SEEK_SET);
            int c = 0;
            for(i = 0; i < displayNameLength; i++) {
                BYTE b = GetBYTE();
                if(b && c < (sizeof(name.str) - 2)) {
                    name.str[c++] = b;
                }
            }
            name.str[c++] = '\0';
         
            fclose(fh);
            return true;
        }


        // Load the head table; we need this to determine the format of the
        // loca table, 16- or 32-bit entries
        fseek(fh, headAddr, SEEK_SET);

        DWORD headVersion           = GetDWORD();
        DWORD headFontRevision      = GetDWORD();
        DWORD headCheckSumAdj       = GetDWORD();
        DWORD headMagicNumber       = GetDWORD();
        WORD  headFlags             = GetWORD();
        WORD  headUnitsPerEm        = GetWORD();
        (void)GetDWORD(); // created time
        (void)GetDWORD();
        (void)GetDWORD(); // modified time
        (void)GetDWORD();
        WORD  headXmin              = GetWORD();
        WORD  headYmin              = GetWORD();
        WORD  headXmax              = GetWORD();
        WORD  headYmax              = GetWORD();
        WORD  headMacStyle          = GetWORD();
        WORD  headLowestRecPPEM     = GetWORD();
        WORD  headFontDirectionHint = GetWORD();
        WORD  headIndexToLocFormat  = GetWORD();
        WORD  headGlyphDataFormat   = GetWORD();
        
        if(headMagicNumber != 0x5F0F3CF5) {
            throw "bad magic number";
        }

        // Load the hhea table, which contains the number of entries in the
        // horizontal metrics (hmtx) table.
        fseek(fh, hheaAddr, SEEK_SET);
        DWORD hheaVersion           = GetDWORD();
        WORD  hheaAscender          = GetWORD();
        WORD  hheaDescender         = GetWORD();
        WORD  hheaLineGap           = GetWORD();
        WORD  hheaAdvanceWidthMax   = GetWORD();
        WORD  hheaMinLsb            = GetWORD();
        WORD  hheaMinRsb            = GetWORD();
        WORD  hheaXMaxExtent        = GetWORD();
        WORD  hheaCaretSlopeRise    = GetWORD();
        WORD  hheaCaretSlopeRun     = GetWORD();
        WORD  hheaCaretOffset       = GetWORD();
        (void)GetWORD();
        (void)GetWORD();
        (void)GetWORD();
        (void)GetWORD();
        WORD  hheaMetricDataFormat  = GetWORD();
        WORD  hheaNumberOfMetrics   = GetWORD();

        // Load the maxp table, which determines (among other things) the number
        // of glyphs in the font
        fseek(fh, maxpAddr, SEEK_SET);

        DWORD maxpVersion               = GetDWORD();
        WORD  maxpNumGlyphs             = GetWORD();
        WORD  maxpMaxPoints             = GetWORD();
        WORD  maxpMaxContours           = GetWORD();
        WORD  maxpMaxComponentPoints    = GetWORD();
        WORD  maxpMaxComponentContours  = GetWORD();
        WORD  maxpMaxZones              = GetWORD();
        WORD  maxpMaxTwilightPoints     = GetWORD();
        WORD  maxpMaxStorage            = GetWORD();
        WORD  maxpMaxFunctionDefs       = GetWORD();
        WORD  maxpMaxInstructionDefs    = GetWORD();
        WORD  maxpMaxStackElements      = GetWORD();
        WORD  maxpMaxSizeOfInstructions = GetWORD();
        WORD  maxpMaxComponentElements  = GetWORD();
        WORD  maxpMaxComponentDepth     = GetWORD();

        glyphs = maxpNumGlyphs;
        glyph = (Glyph *)MemAlloc(glyphs*sizeof(glyph[0]));

        // Load the hmtx table, which gives the horizontal metrics (spacing
        // and advance width) of the font.
        fseek(fh, hmtxAddr, SEEK_SET);

        WORD  hmtxAdvanceWidth;
        SWORD hmtxLsb;
        for(i = 0; i < min(glyphs, hheaNumberOfMetrics); i++) {
            hmtxAdvanceWidth = GetWORD();
            hmtxLsb          = (SWORD)GetWORD();

            glyph[i].leftSideBearing = hmtxLsb;
            glyph[i].advanceWidth = hmtxAdvanceWidth;
        }
        // The last entry in the table applies to all subsequent glyphs also.
        for(; i < glyphs; i++) {
            glyph[i].leftSideBearing = hmtxLsb;
            glyph[i].advanceWidth = hmtxAdvanceWidth;
        }

        // Load the cmap table, which determines the mapping of characters to
        // glyphs.
        fseek(fh, cmapAddr, SEEK_SET);

        DWORD usedTableAddr = -1;

        WORD  cmapVersion        = GetWORD();
        WORD  cmapTableCount     = GetWORD();
        for(i = 0; i < cmapTableCount; i++) {
            WORD  platformId = GetWORD();
            WORD  encodingId = GetWORD();
            DWORD offset     = GetDWORD();

            if(platformId == 3 && encodingId == 1) {
                // The Windows Unicode mapping is our preference
                usedTableAddr = cmapAddr + offset;
            }
        }

        if(usedTableAddr == -1) {
            throw "no used table addr";
        }

        // So we can load the desired subtable; in this case, Windows Unicode,
        // which is us.
        fseek(fh, usedTableAddr, SEEK_SET);

        WORD  mapFormat             = GetWORD();
        WORD  mapLength             = GetWORD();
        WORD  mapVersion            = GetWORD();
        WORD  mapSegCountX2         = GetWORD();
        WORD  mapSearchRange        = GetWORD();
        WORD  mapEntrySelector      = GetWORD();
        WORD  mapRangeShift         = GetWORD();
        
        if(mapFormat != 4) {
            // Required to use format 4 per spec
            throw "not format 4";
        }

        int segCount = mapSegCountX2 / 2;
        WORD *endChar       = (WORD *)AllocTemporary(segCount*sizeof(WORD));
        WORD *startChar     = (WORD *)AllocTemporary(segCount*sizeof(WORD));
        WORD *idDelta       = (WORD *)AllocTemporary(segCount*sizeof(WORD));
        WORD *idRangeOffset = (WORD *)AllocTemporary(segCount*sizeof(WORD));

        DWORD *filePos = (DWORD *)AllocTemporary(segCount*sizeof(DWORD));

        for(i = 0; i < segCount; i++) {
            endChar[i] = GetWORD();
        }
        WORD  mapReservedPad        = GetWORD();
        for(i = 0; i < segCount; i++) {
            startChar[i] = GetWORD();
        }
        for(i = 0; i < segCount; i++) {
            idDelta[i] = GetWORD();
        }
        for(i = 0; i < segCount; i++) {
            filePos[i] = ftell(fh);
            idRangeOffset[i] = GetWORD();
        }

        // So first, null out the glyph table in our in-memory representation
        // of the font; any character for which cmap does not provide a glyph
        // corresponds to -1
        for(i = 0; i < arraylen(useGlyph); i++) {
            useGlyph[i] = 0;
        }

        for(i = 0; i < segCount; i++) {
            WORD v = idDelta[i];
            if(idRangeOffset[i] == 0) {
                int j;
                for(j = startChar[i]; j <= endChar[i]; j++) {
                    if(j > 0 && j < arraylen(useGlyph)) {
                        // Don't create a reference to a glyph that we won't
                        // store because it's bigger than the table.
                        if((WORD)(j + v) < glyphs) {
                            // Arithmetic is modulo 2^16
                            useGlyph[j] = (WORD)(j + v);
                        }
                    }
                }
            } else {
                int j;
                for(j = startChar[i]; j <= endChar[i]; j++) {
                    if(j > 0 && j < arraylen(useGlyph)) {
                        int fp = filePos[i];
                        fp += (j - startChar[i])*sizeof(WORD);
                        fp += idRangeOffset[i];
                        fseek(fh, fp, SEEK_SET);

                        useGlyph[j] = GetWORD();
                    }
                }
            }
        }

        // Load the loca table. This contains the offsets of each glyph,
        // relative to the beginning of the glyf table.
        fseek(fh, locaAddr, SEEK_SET);

        DWORD *glyphOffsets = (DWORD *)AllocTemporary(glyphs*sizeof(DWORD));

        for(i = 0; i < glyphs; i++) {
            if(headIndexToLocFormat == 1) {
                // long offsets, 32 bits
                glyphOffsets[i] = GetDWORD();
            } else if(headIndexToLocFormat == 0) {
                // short offsets, 16 bits but divided by 2
                glyphOffsets[i] = GetWORD()*2;
            } else {
                throw "bad headIndexToLocFormat";
            }
        }

        scale = 1024;
        // Load the glyf table. This contains the actual representations of the
        // letter forms, as piecewise linear or quadratic outlines.
        for(i = 0; i < glyphs; i++) {
            fseek(fh, glyfAddr + glyphOffsets[i], SEEK_SET);
            LoadGlyph(i);
        }
    } catch (char *s) {
        dbp("failed: '%s'", s);
        fclose(fh);
        return false;
    }

    fclose(fh);
    loaded = true;
    return true;
}