consolidate files into btgui/OpenGLWindow (from FontFiles/OpenGLTrueTypeFont)

consolidate stringify_linux/_osx into stringify.sh
This commit is contained in:
Erwin Coumans
2014-09-03 09:52:31 -07:00
parent d6c78426bd
commit 0125324bd6
30 changed files with 50 additions and 163 deletions

View File

@@ -4,13 +4,13 @@ INCLUDE_DIRECTORIES(
${BULLET_PHYSICS_SOURCE_DIR}/btgui
)
FILE(GLOB OpenGLWindow_HDRS "*.h" "../OpenGLTrueTypeFont/*.h")
FILE(GLOB OpenGLWindow_HDRS "*.h" )
FILE(GLOB OpenGLWindowMac_CPP "Mac*.mm")
FILE(GLOB OpenGLWindowWin32_CPP "Win32*.cpp")
FILE(GLOB OpenGLWindowLinux_CPP "X11*.cpp")
FILE(GLOB OpenGLWindowCommon_CPP "*.cpp" "../OpenGLTrueTypeFont/*.cpp" "../FontFiles/OpenSans.cpp" )
FILE(GLOB OpenGLWindowCommon_CPP "*.cpp" )
LIST(REMOVE_ITEM OpenGLWindowCommon_CPP ${OpenGLWindowMac_CPP} )
LIST(REMOVE_ITEM OpenGLWindowCommon_CPP ${OpenGLWindowWin32_CPP} )

View File

@@ -1245,7 +1245,7 @@ void GLInstancingRenderer::getMouseDirection(float* dir, int x, int y)
//#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "OpenGLTrueTypeFont/stb_image_write.h"
#include "stb_image_write.h"
void writeTextureToPng(int textureWidth, int textureHeight, const char* fileName, int numComponents)
{

View File

@@ -6,7 +6,7 @@
#include "Gwen/BaseRender.h"
#include "GLPrimitiveRenderer.h"
struct sth_stash;
#include "../OpenGLTrueTypeFont/fontstash.h"
#include "fontstash.h"
#include "Gwen/Texture.h"
#include "TwFonts.h"

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -21,11 +21,11 @@
#include "Bullet3Common/b3Vector3.h"
#include "Bullet3Common/b3Logging.h"
#include "OpenGLTrueTypeFont/fontstash.h"
#include "OpenGLWindow/fontstash.h"
#include "OpenGLWindow/TwFonts.h"
#include "OpenGLTrueTypeFont/opengl_fontstashcallbacks.h"
#include "OpenGLWindow/opengl_fontstashcallbacks.h"
#include <assert.h>
#include "GLRenderToTexture.h"
#include "OpenGLWindow/GLRenderToTexture.h"
#ifdef _WIN32
#define popen _popen
@@ -225,8 +225,6 @@ void SimpleOpenGL3App::drawText( const char* txt, int posX, int posY)
//r.w = g_DefaultNormalFont->m_CharWidth[c]+extraSpacing;
int endX = startX+g_DefaultNormalFont->m_CharWidth[c];
int endY = startY+g_DefaultNormalFont->m_CharHeight;
//Gwen::Rect rect = r;
//Translate( rect );
float currentColor[]={0.2f,0.2,0.2f,1.f};
@@ -425,7 +423,7 @@ SimpleOpenGL3App::~SimpleOpenGL3App()
}
//#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "OpenGLTrueTypeFont/stb_image_write.h"
#include "OpenGLWindow/stb_image_write.h"
static void writeTextureToFile(int textureWidth, int textureHeight, const char* fileName, FILE* ffmpegVideo)
{
int numComponents = 4;

View File

@@ -0,0 +1,818 @@
//
// Copyright (c) 2011 Andreas Krinke andreas.krinke@gmx.de
// Copyright (c) 2009 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#define STB_TRUETYPE_IMPLEMENTATION
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#endif
#include "fontstash.h"
#define BORDER_X_LEFT 2
#define BORDER_X_RIGHT 2
#define BORDER_Y_TOP 2
#define BORDER_Y_BOTTOM 2
#define ADDITIONAL_HEIGHT 2
#define STB_TRUETYPE_IMPLEMENTATION
#define STBTT_malloc(x,u) malloc(x)
#define STBTT_free(x,u) free(x)
#include "stb_truetype.h"
#define HASH_LUT_SIZE 256
#define TTFONT_FILE 1
#define TTFONT_MEM 2
#define BMFONT 3
static int idx = 1;
static float s_retinaScale = 1;
static unsigned int hashint(unsigned int a)
{
a += ~(a<<15);
a ^= (a>>10);
a += (a<<3);
a ^= (a>>6);
a += ~(a<<11);
a ^= (a>>16);
return a;
}
struct sth_font
{
int idx;
int type;
stbtt_fontinfo font;
unsigned char* data;
struct sth_glyph* glyphs;
int lut[HASH_LUT_SIZE];
int nglyphs;
float ascender;
float descender;
float lineh;
struct sth_font* next;
};
struct sth_stash
{
int tw,th;
float itw,ith;
struct sth_texture* textures;
struct sth_font* fonts;
int drawing;
RenderCallbacks* m_renderCallbacks;
};
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
#define UTF8_ACCEPT 0
#define UTF8_REJECT 1
static const unsigned char utf8d[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
};
static unsigned int decutf8(unsigned int* state, unsigned int* codep, unsigned int byte)
{
unsigned int type = utf8d[byte];
*codep = (*state != UTF8_ACCEPT) ?
(byte & 0x3fu) | (*codep << 6) :
(0xff >> type) & (byte);
*state = utf8d[256 + *state*16 + type];
return *state;
}
struct sth_stash* sth_create(int cachew, int cacheh, RenderCallbacks* renderCallbacks)
{
struct sth_stash* stash = NULL;
struct sth_texture* texture = NULL;
// Allocate memory for the font stash.
stash = (struct sth_stash*)malloc(sizeof(struct sth_stash));
if (stash == NULL)
{
assert(0);
return NULL;
}
memset(stash,0,sizeof(struct sth_stash));
stash->m_renderCallbacks = renderCallbacks;
// Allocate memory for the first texture
texture = (struct sth_texture*)malloc(sizeof(struct sth_texture));
if (texture == NULL)
{
assert(0);
free(stash);
}
memset(texture,0,sizeof(struct sth_texture));
// Create first texture for the cache.
stash->tw = cachew;
stash->th = cacheh;
stash->itw = 1.0f/cachew;
stash->ith = 1.0f/cacheh;
stash->textures = texture;
stash->m_renderCallbacks->updateTexture(texture, 0, stash->tw, stash->th);
return stash;
}
int sth_add_font_from_memory(struct sth_stash* stash, unsigned char* buffer)
{
int i, ascent, descent, fh, lineGap;
struct sth_font* fnt = NULL;
fnt = (struct sth_font*)malloc(sizeof(struct sth_font));
if (fnt == NULL) goto error;
memset(fnt,0,sizeof(struct sth_font));
// Init hash lookup.
for (i = 0; i < HASH_LUT_SIZE; ++i)
fnt->lut[i] = -1;
fnt->data = buffer;
// Init stb_truetype
if (!stbtt_InitFont(&fnt->font, fnt->data, 0))
goto error;
// Store normalized line height. The real line height is got
// by multiplying the lineh by font size.
stbtt_GetFontVMetrics(&fnt->font, &ascent, &descent, &lineGap);
fh = ascent - descent;
fnt->ascender = (float)ascent / (float)fh;
fnt->descender = (float)descent / (float)fh;
fnt->lineh = (float)(fh + lineGap) / (float)fh;
fnt->idx = idx;
fnt->type = TTFONT_MEM;
fnt->next = stash->fonts;
stash->fonts = fnt;
return idx++;
error:
if (fnt) {
if (fnt->glyphs) free(fnt->glyphs);
free(fnt);
}
return 0;
}
int sth_add_font(struct sth_stash* stash, const char* path)
{
FILE* fp = 0;
int datasize;
unsigned char* data = NULL;
int idx=0;
// Read in the font data.
fp = fopen(path, "rb");
if (!fp) goto error;
fseek(fp,0,SEEK_END);
datasize = (int)ftell(fp);
fseek(fp,0,SEEK_SET);
data = (unsigned char*)malloc(datasize);
if (data == NULL) goto error;
int bytesRead;
bytesRead = fread(data, 1, datasize, fp);
if (bytesRead)
{
idx = sth_add_font_from_memory(stash, data);
}
fclose(fp);
fp = 0;
// Modify type of the loaded font.
if (idx)
stash->fonts->type = TTFONT_FILE;
else
free(data);
return idx;
error:
if (data) free(data);
if (fp) fclose(fp);
return 0;
}
int sth_add_bitmap_font(struct sth_stash* stash, int ascent, int descent, int line_gap)
{
int i, fh;
struct sth_font* fnt = NULL;
fnt = (struct sth_font*)malloc(sizeof(struct sth_font));
if (fnt == NULL) goto error;
memset(fnt,0,sizeof(struct sth_font));
// Init hash lookup.
for (i = 0; i < HASH_LUT_SIZE; ++i) fnt->lut[i] = -1;
// Store normalized line height. The real line height is got
// by multiplying the lineh by font size.
fh = ascent - descent;
fnt->ascender = (float)ascent / (float)fh;
fnt->descender = (float)descent / (float)fh;
fnt->lineh = (float)(fh + line_gap) / (float)fh;
fnt->idx = idx;
fnt->type = BMFONT;
fnt->next = stash->fonts;
stash->fonts = fnt;
return idx++;
error:
if (fnt) free(fnt);
return 0;
}
/*void sth_add_glyph(struct sth_stash* stash,
int idx,
unsigned int id1,
const char* s,
short size, short base,
int x, int y, int w, int h,
float xoffset, float yoffset, float xadvance)
{
struct sth_texture* texture = NULL;
struct sth_font* fnt = NULL;
struct sth_glyph* glyph = NULL;
unsigned int codepoint;
unsigned int state = 0;
if (stash == NULL) return;
texture = stash->textures;
while (texture != NULL && texture->id != id)
texture = texture->next;
if (texture == NULL)
{
// Create new texture
texture = (struct sth_texture*)malloc(sizeof(struct sth_texture));
if (texture == NULL) return;
memset(texture, 0, sizeof(struct sth_texture));
texture->id = id;
texture->next = stash->textures;
stash->textures = texture;
}
fnt = stash->fonts;
while (fnt != NULL && fnt->idx != idx) fnt = fnt->next;
if (fnt == NULL) return;
if (fnt->type != BMFONT) return;
for (; *s; ++s)
{
if (!decutf8(&state, &codepoint, *(unsigned char*)s)) break;
}
if (state != UTF8_ACCEPT) return;
// Alloc space for new glyph.
fnt->nglyphs++;
fnt->glyphs = (sth_glyph*)realloc(fnt->glyphs, fnt->nglyphs*sizeof(struct sth_glyph));
if (!fnt->glyphs) return;
// Init glyph.
glyph = &fnt->glyphs[fnt->nglyphs-1];
memset(glyph, 0, sizeof(struct sth_glyph));
glyph->codepoint = codepoint;
glyph->size = size;
glyph->texture = texture;
glyph->x0_ = x;
glyph->y0 = y;
glyph->x1 = glyph->x0_+w;
glyph->y1 = glyph->y0+h;
glyph->xoff = xoffset;
glyph->yoff = yoffset - base;
glyph->xadv = xadvance;
// Find code point and size.
h = hashint(codepoint) & (HASH_LUT_SIZE-1);
// Insert char to hash lookup.
glyph->next = fnt->lut[h];
fnt->lut[h] = fnt->nglyphs-1;
}
*/
static struct sth_glyph* get_glyph(struct sth_stash* stash, struct sth_font* fnt, unsigned int codepoint, short isize)
{
int i,g,advance,lsb,x0,y0,x1,y1,gw,gh;
float scale;
struct sth_texture* texture = NULL;
struct sth_glyph* glyph = NULL;
unsigned int h;
float size = isize/10.0f;
int rh;
struct sth_row* br = NULL;
// Find code point and size.
h = hashint(codepoint) & (HASH_LUT_SIZE-1);
i = fnt->lut[h];
while (i != -1)
{
if (fnt->glyphs[i].codepoint == codepoint && (fnt->type == BMFONT || fnt->glyphs[i].size == isize))
return &fnt->glyphs[i];
i = fnt->glyphs[i].next;
}
// Could not find glyph.
// For bitmap fonts: ignore this glyph.
if (fnt->type == BMFONT) return 0;
// For truetype fonts: create this glyph.
scale = stbtt_ScaleForPixelHeight(&fnt->font, size);
g = stbtt_FindGlyphIndex(&fnt->font, codepoint);
stbtt_GetGlyphHMetrics(&fnt->font, g, &advance, &lsb);
stbtt_GetGlyphBitmapBox(&fnt->font, g, scale,scale, &x0,&y0,&x1,&y1);
gw = x1-x0;
gh = y1-y0;
// Check if glyph is larger than maximum texture size
if (gw >= stash->tw || gh >= stash->th)
return 0;
// Find texture and row where the glyph can be fit.
br = NULL;
rh = (gh+7) & ~7;
texture = stash->textures;
while(br == NULL)
{
for (i = 0; i < texture->nrows; ++i)
{
if (texture->rows[i].h >= rh && texture->rows[i].x+gw+1 <= stash->tw)
br = &texture->rows[i];
}
// If no row is found, there are 3 possibilities:
// - add new row
// - try next texture
// - create new texture
if (br == NULL)
{
short py = BORDER_Y_TOP;
// Check that there is enough space.
if (texture->nrows)
{
py = texture->rows[texture->nrows-1].y + texture->rows[texture->nrows-1].h+1;
if (py+rh > stash->th)
{
if (texture->next != NULL)
{
texture = texture->next;
}
else
{
// Create new texture
texture->next = (struct sth_texture*)malloc(sizeof(struct sth_texture));
texture = texture->next;
if (texture == NULL) goto error;
memset(texture,0,sizeof(struct sth_texture));
stash->m_renderCallbacks->updateTexture(texture,0,stash->tw,stash->th);
}
continue;
}
}
// Init and add row
br = &texture->rows[texture->nrows];
br->x = BORDER_X_LEFT;
br->y = py+BORDER_Y_BOTTOM;
br->h = rh+ADDITIONAL_HEIGHT;
texture->nrows++;
}
}
// Alloc space for new glyph.
fnt->nglyphs++;
fnt->glyphs = (sth_glyph*)realloc(fnt->glyphs, fnt->nglyphs*sizeof(struct sth_glyph));
if (!fnt->glyphs) return 0;
// Init glyph.
glyph = &fnt->glyphs[fnt->nglyphs-1];
memset(glyph, 0, sizeof(struct sth_glyph));
glyph->codepoint = codepoint;
glyph->size = isize;
glyph->texture = texture;
glyph->x0_ = br->x;
glyph->y0 = br->y;
glyph->x1 = glyph->x0_+gw;
glyph->y1 = glyph->y0+gh;
glyph->xadv = scale * advance;
glyph->xoff = (float)x0;
glyph->yoff = (float)y0;
glyph->next = 0;
// Advance row location.
br->x += gw+BORDER_X_RIGHT;
// Insert char to hash lookup.
glyph->next = fnt->lut[h];
fnt->lut[h] = fnt->nglyphs-1;
// Rasterize
{
unsigned char* ptr = texture->m_texels+glyph->x0_+glyph->y0*stash->tw;
stbtt_MakeGlyphBitmap(&fnt->font,ptr , gw,gh,stash->tw, scale,scale, g);
stash->m_renderCallbacks->updateTexture(texture,glyph, stash->tw, stash->th);
}
return glyph;
error:
if (texture)
free(texture);
return 0;
}
static int get_quad(struct sth_stash* stash, struct sth_font* fnt, struct sth_glyph* glyph, short isize, float* x, float* y, struct sth_quad* q)
{
float rx,ry;
float scale = 1.f/s_retinaScale;//1.0f;
if (fnt->type == BMFONT)
scale = isize/(glyph->size*10.0f);
rx = (*x + scale * float(glyph->xoff));
ry = (*y + scale * float(glyph->yoff));
q->x0 = rx;
q->y0 = ry + 1.5f*0.5f*float(isize)/10.f;
q->x1 = rx + scale * float(glyph->x1 - glyph->x0_);
q->y1 = ry + scale * float(glyph->y1 - glyph->y0)+ 1.5f*0.5f*float(isize)/10.f;
q->s0 = float(glyph->x0_) * stash->itw;
q->t0 = float(glyph->y0) * stash->ith;
q->s1 = float(glyph->x1) * stash->itw;
q->t1 = float(glyph->y1) * stash->ith;
*x += scale * glyph->xadv;
return 1;
}
static Vertex* setv(Vertex* v, float x, float y, float s, float t, float width, float height)
{
bool scale=true;
if (scale)
{
v->position.p[0] = (x*2-width)/(width);
v->position.p[1] = 1-(y)/(height/2);
} else
{
v->position.p[0] = (x-width)/(width);
v->position.p[1] = (height-y)/(height);
}
v->position.p[2] = 0.f;
v->position.p[3] = 1.f;
v->uv.p[0] = s;
v->uv.p[1] = t;
v->colour.p[0] = 0.1f;//1.f;
v->colour.p[1] = 0.1f;
v->colour.p[2] = 0.1f;
v->colour.p[3] = 1.f;
return v+1;
}
static void flush_draw(struct sth_stash* stash)
{
struct sth_texture* texture = stash->textures;
while (texture)
{
if (texture->nverts > 0)
{
stash->m_renderCallbacks->render(texture);
texture->nverts = 0;
}
texture = texture->next;
}
}
void sth_begin_draw(struct sth_stash* stash)
{
if (stash == NULL) return;
if (stash->drawing)
flush_draw(stash);
stash->drawing = 1;
}
void sth_end_draw(struct sth_stash* stash)
{
if (stash == NULL) return;
if (!stash->drawing) return;
/*
// Debug dump.
if (stash->nverts+6 < VERT_COUNT)
{
float x = 500, y = 100;
float* v = &stash->verts[stash->nverts*4];
v = setv(v, x, y, 0, 0);
v = setv(v, x+stash->tw, y, 1, 0);
v = setv(v, x+stash->tw, y+stash->th, 1, 1);
v = setv(v, x, y, 0, 0);
v = setv(v, x+stash->tw, y+stash->th, 1, 1);
v = setv(v, x, y+stash->th, 0, 1);
stash->nverts += 6;
}
*/
flush_draw(stash);
stash->drawing = 0;
}
void sth_draw_texture(struct sth_stash* stash,
int idx, float size,
float x, float y,
int screenwidth, int screenheight,
const char* s, float* dx)
{
int width = stash->tw;
int height=stash->th;
unsigned int codepoint;
struct sth_glyph* glyph = NULL;
struct sth_texture* texture = NULL;
unsigned int state = 0;
struct sth_quad q;
short isize = (short)(size*10.0f);
Vertex* v;
struct sth_font* fnt = NULL;
if (stash == NULL) return;
if (!stash->textures) return;
fnt = stash->fonts;
while(fnt != NULL && fnt->idx != idx) fnt = fnt->next;
if (fnt == NULL) return;
if (fnt->type != BMFONT && !fnt->data) return;
int once = true;
for (; once; ++s)
{
once=false;
if (decutf8(&state, &codepoint, *(unsigned char*)s))
continue;
glyph = get_glyph(stash, fnt, codepoint, isize);
if (!glyph)
continue;
texture = glyph->texture;
if (texture->nverts+6 >= VERT_COUNT)
flush_draw(stash);
if (!get_quad(stash, fnt, glyph, isize, &x, &y, &q))
continue;
v = &texture->newverts[texture->nverts];
q.x0 = 0;
q.y0 = 0;
q.x1 = q.x0+width;
q.y1 = q.y0+height;
v = setv(v, q.x0, q.y0, 0,0,(float)screenwidth,(float)screenheight);
v = setv(v, q.x1, q.y0, 1,0,(float)screenwidth,(float)screenheight);
v = setv(v, q.x1, q.y1, 1,1,(float)screenwidth,(float)screenheight);
v = setv(v, q.x0, q.y0, 0,0,(float)screenwidth,(float)screenheight);
v = setv(v, q.x1, q.y1, 1,1,(float)screenwidth,(float)screenheight);
v = setv(v, q.x0, q.y1, 0,1,(float)screenwidth,(float)screenheight);
texture->nverts += 6;
}
flush_draw(stash);
if (dx) *dx = x;
}
void sth_flush_draw(struct sth_stash* stash)
{
flush_draw(stash);
}
void sth_draw_text(struct sth_stash* stash,
int idx, float size,
float x, float y,
const char* s, float* dx, int screenwidth, int screenheight, int measureOnly, float retinaScale)
{
unsigned int codepoint;
struct sth_glyph* glyph = NULL;
struct sth_texture* texture = NULL;
unsigned int state = 0;
struct sth_quad q;
short isize = (short)(size*10.0f);
Vertex* v;
struct sth_font* fnt = NULL;
s_retinaScale = retinaScale;
if (stash == NULL) return;
if (!stash->textures) return;
fnt = stash->fonts;
while(fnt != NULL && fnt->idx != idx) fnt = fnt->next;
if (fnt == NULL) return;
if (fnt->type != BMFONT && !fnt->data) return;
for (; *s; ++s)
{
if (decutf8(&state, &codepoint, *(unsigned char*)s))
continue;
glyph = get_glyph(stash, fnt, codepoint, isize);
if (!glyph) continue;
texture = glyph->texture;
if (!measureOnly)
{
if (texture->nverts+6 >= VERT_COUNT)
flush_draw(stash);
}
if (!get_quad(stash, fnt, glyph, isize, &x, &y, &q)) continue;
if (!measureOnly)
{
v = &texture->newverts[texture->nverts];
v = setv(v, q.x0, q.y0, q.s0, q.t0,(float)screenwidth,(float)screenheight);
v = setv(v, q.x1, q.y0, q.s1, q.t0,(float)screenwidth,(float)screenheight);
v = setv(v, q.x1, q.y1, q.s1, q.t1,(float)screenwidth,(float)screenheight);
v = setv(v, q.x0, q.y0, q.s0, q.t0,(float)screenwidth,(float)screenheight);
v = setv(v, q.x1, q.y1, q.s1, q.t1,(float)screenwidth,(float)screenheight);
v = setv(v, q.x0, q.y1, q.s0, q.t1,(float)screenwidth,(float)screenheight);
texture->nverts += 6;
}
}
if (dx) *dx = x;
}
void sth_dim_text(struct sth_stash* stash,
int idx, float size,
const char* s,
float* minx, float* miny, float* maxx, float* maxy)
{
unsigned int codepoint;
struct sth_glyph* glyph = NULL;
unsigned int state = 0;
struct sth_quad q;
short isize = (short)(size*10.0f);
struct sth_font* fnt = NULL;
float x = 0, y = 0;
if (stash == NULL)
return;
if (!stash->textures)
return;
fnt = stash->fonts;
while(fnt != NULL && fnt->idx != idx) fnt = fnt->next;
if (fnt == NULL) return;
if (fnt->type != BMFONT && !fnt->data) return;
*minx = *maxx = x;
*miny = *maxy = y;
for (; *s; ++s)
{
if (decutf8(&state, &codepoint, *(unsigned char*)s)) continue;
glyph = get_glyph(stash, fnt, codepoint, isize);
if (!glyph) continue;
if (!get_quad(stash, fnt, glyph, isize, &x, &y, &q)) continue;
if (q.x0 < *minx) *minx = q.x0;
if (q.x1 > *maxx) *maxx = q.x1;
if (q.y1 < *miny) *miny = q.y1;
if (q.y0 > *maxy) *maxy = q.y0;
}
}
void sth_vmetrics(struct sth_stash* stash,
int idx, float size,
float* ascender, float* descender, float* lineh)
{
struct sth_font* fnt = NULL;
if (stash == NULL) return;
if (!stash->textures) return;
fnt = stash->fonts;
while(fnt != NULL && fnt->idx != idx) fnt = fnt->next;
if (fnt == NULL) return;
if (fnt->type != BMFONT && !fnt->data) return;
if (ascender)
*ascender = fnt->ascender*size;
if (descender)
*descender = fnt->descender*size;
if (lineh)
*lineh = fnt->lineh*size;
}
void sth_delete(struct sth_stash* stash)
{
struct sth_texture* tex = NULL;
struct sth_texture* curtex = NULL;
struct sth_font* fnt = NULL;
struct sth_font* curfnt = NULL;
if (!stash) return;
tex = stash->textures;
while(tex != NULL) {
curtex = tex;
delete tex->m_texels;
tex->m_texels=0;
tex = tex->next;
stash->m_renderCallbacks->updateTexture(curtex,0,0,0);
free(curtex);
}
fnt = stash->fonts;
while(fnt != NULL) {
curfnt = fnt;
fnt = fnt->next;
if (curfnt->glyphs)
{
free(curfnt->glyphs);
}
if (curfnt->type == TTFONT_FILE && curfnt->data)
{
free(curfnt->data);
}
free(curfnt);
}
free(stash);
}

View File

@@ -0,0 +1,145 @@
//
// Copyright (c) 2011 Andreas Krinke andreas.krinke@gmx.de
// Copyright (c) 2009 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#ifndef FONTSTASH_H
#define FONTSTASH_H
#define MAX_ROWS 128
#define VERT_COUNT (6*128)
#define INDEX_COUNT (VERT_COUNT*2)
struct vec2
{
vec2(float x, float y)
{
p[0] = x;
p[1] = y;
}
float p[2];
};
struct vec4
{
vec4(float x,float y, float z, float w)
{
p[0] = x;
p[1] = y;
p[2] = z;
p[3] = w;
}
float p[4];
};
typedef struct
{
vec4 position;
vec4 colour;
vec2 uv;
} Vertex;
struct sth_quad
{
float x0,y0,s0,t0;
float x1,y1,s1,t1;
};
struct sth_row
{
short x,y,h;
};
struct sth_glyph
{
unsigned int codepoint;
short size;
struct sth_texture* texture;
int x0_,y0,x1,y1;
float xadv,xoff,yoff;
int next;
};
struct sth_texture
{
union
{
void* m_userData;
int m_userId;
};
unsigned char* m_texels;
// TODO: replace rows with pointer
struct sth_row rows[MAX_ROWS];
int nrows;
int nverts;
Vertex newverts[VERT_COUNT];
struct sth_texture* next;
};
struct RenderCallbacks
{
virtual void updateTexture(sth_texture* texture, sth_glyph* glyph, int textureWidth, int textureHeight)=0;
virtual void render(sth_texture* texture)=0;
};
struct sth_stash* sth_create(int cachew, int cacheh, RenderCallbacks* callbacks);
int sth_add_font(struct sth_stash* stash, const char* path);
int sth_add_font_from_memory(struct sth_stash* stash, unsigned char* buffer);
int sth_add_bitmap_font(struct sth_stash* stash, int ascent, int descent, int line_gap);
/*void sth_add_glyph(struct sth_stash* stash, int idx, unsigned int uid, const char* s,
short size, short base, int x, int y, int w, int h,
float xoffset, float yoffset, float xadvance);
*/
void sth_begin_draw(struct sth_stash* stash);
void sth_end_draw(struct sth_stash* stash);
void sth_draw_texture(struct sth_stash* stash,
int idx, float size,
float x, float y,
int screenwidth, int screenheight,
const char* s, float* dx);
void sth_flush_draw(struct sth_stash* stash);
void sth_draw_text(struct sth_stash* stash,
int idx, float size,
float x, float y, const char* string, float* dx, int screenwidth, int screenheight, int measureOnly=0, float retinaScale=1);
void sth_dim_text(struct sth_stash* stash, int idx, float size, const char* string,
float* minx, float* miny, float* maxx, float* maxy);
void sth_vmetrics(struct sth_stash* stash,
int idx, float size,
float* ascender, float* descender, float * lineh);
void sth_delete(struct sth_stash* stash);
#endif // FONTSTASH_H

View File

@@ -0,0 +1,252 @@
#include "opengl_fontstashcallbacks.h"
#include "../OpenGLWindow/GLPrimitiveRenderer.h"
#include "../OpenGLWindow/GLPrimInternalData.h"
#include "fontstash.h"
#include "../OpenGLWindow/OpenGLInclude.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
static unsigned int s_indexData[INDEX_COUNT];
GLuint s_indexArrayObject, s_indexBuffer;
GLuint s_vertexArrayObject,s_vertexBuffer;
OpenGL2RenderCallbacks::OpenGL2RenderCallbacks(GLPrimitiveRenderer* primRender)
:m_primRender2(primRender)
{
}
OpenGL2RenderCallbacks::~OpenGL2RenderCallbacks()
{
}
PrimInternalData* OpenGL2RenderCallbacks::getData()
{
return m_primRender2->getData();
}
InternalOpenGL2RenderCallbacks::~InternalOpenGL2RenderCallbacks()
{
}
void InternalOpenGL2RenderCallbacks::display2()
{
assert(glGetError()==GL_NO_ERROR);
// glViewport(0,0,10,10);
//const float timeScale = 0.008f;
PrimInternalData* data = getData();
glUseProgram(data->m_shaderProg);
glBindBuffer(GL_ARRAY_BUFFER, s_vertexBuffer);
glBindVertexArray(s_vertexArrayObject);
assert(glGetError()==GL_NO_ERROR);
// glBindTexture(GL_TEXTURE_2D,m_texturehandle);
assert(glGetError()==GL_NO_ERROR);
vec2 p( 0.f,0.f);//?b?0.5f * sinf(timeValue), 0.5f * cosf(timeValue) );
glUniform2fv(data->m_positionUniform, 1, (const GLfloat *)&p);
assert(glGetError()==GL_NO_ERROR);
glEnableVertexAttribArray(data->m_positionAttribute);
assert(glGetError()==GL_NO_ERROR);
glEnableVertexAttribArray(data->m_colourAttribute);
assert(glGetError()==GL_NO_ERROR);
glEnableVertexAttribArray(data->m_textureAttribute);
glVertexAttribPointer(data->m_positionAttribute, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *)0);
glVertexAttribPointer(data->m_colourAttribute , 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *)sizeof(vec4));
glVertexAttribPointer(data->m_textureAttribute , 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *)(sizeof(vec4)+sizeof(vec4)));
assert(glGetError()==GL_NO_ERROR);
/*
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer);
//glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
int indexCount = 6;
err = glGetError();
assert(err==GL_NO_ERROR);
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
err = glGetError();
assert(err==GL_NO_ERROR);
*/
// glutSwapBuffers();
}
void InternalOpenGL2RenderCallbacks::updateTexture(sth_texture* texture, sth_glyph* glyph, int textureWidth, int textureHeight)
{
assert(glGetError()==GL_NO_ERROR);
if (glyph)
{
// Update texture (entire texture, could use glyph to update partial texture using glTexSubImage2D)
GLuint* gltexture = (GLuint*) texture->m_userData;
glBindTexture(GL_TEXTURE_2D, *gltexture);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
assert(glGetError()==GL_NO_ERROR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, textureWidth, textureHeight, 0, GL_RED, GL_UNSIGNED_BYTE, texture->m_texels);
assert(glGetError()==GL_NO_ERROR);
} else
{
if (textureWidth && textureHeight)
{
GLuint* texId = new GLuint;
texture->m_userData = texId;
//create new texture
glGenTextures(1, texId);
assert(glGetError()==GL_NO_ERROR);
glBindTexture(GL_TEXTURE_2D, *texId);
texture->m_texels = (unsigned char*)malloc(textureWidth*textureHeight);
memset(texture->m_texels,0,textureWidth*textureHeight);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, textureWidth, textureHeight, 0, GL_RED, GL_UNSIGNED_BYTE, texture->m_texels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
assert(glGetError()==GL_NO_ERROR);
////////////////////////////
//create the other data
{
glGenVertexArrays(1, &s_vertexArrayObject);
glBindVertexArray(s_vertexArrayObject);
glGenBuffers(1, &s_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, s_vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, VERT_COUNT * sizeof(Vertex), texture->newverts, GL_DYNAMIC_DRAW);
assert(glGetError()==GL_NO_ERROR);
for (int i=0;i<INDEX_COUNT;i++)
{
s_indexData[i] = i;
}
glGenBuffers(1, &s_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,INDEX_COUNT*sizeof(int), s_indexData,GL_STATIC_DRAW);
assert(glGetError()==GL_NO_ERROR);
}
} else
{
//delete texture
if (texture->m_userData)
{
GLuint* id = (GLuint*)texture->m_userData;
glDeleteTextures(1, id);
//delete id;
delete id;//texture->m_userData;
texture->m_userData = 0;
}
}
}
}
void InternalOpenGL2RenderCallbacks::render(sth_texture* texture)
{
display2();
GLuint* texId = (GLuint*) texture->m_userData;
assert(glGetError()==GL_NO_ERROR);
glActiveTexture(GL_TEXTURE0);
assert(glGetError()==GL_NO_ERROR);
glBindTexture(GL_TEXTURE_2D, *texId);
bool useFiltering = false;
if (useFiltering)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
assert(glGetError()==GL_NO_ERROR);
glBindBuffer(GL_ARRAY_BUFFER, s_vertexBuffer);
glBindVertexArray(s_vertexArrayObject);
glBufferData(GL_ARRAY_BUFFER, texture->nverts * sizeof(Vertex), &texture->newverts[0].position.p[0], GL_DYNAMIC_DRAW);
assert(glGetError()==GL_NO_ERROR);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_indexBuffer);
//glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
int indexCount = texture->nverts;
assert(glGetError()==GL_NO_ERROR);
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
assert(glGetError()==GL_NO_ERROR);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// glDisableVertexAttribArray(m_textureAttribute);
glUseProgram(0);
}
void dumpTextureToPng(int textureWidth, int textureHeight, const char* fileName)
{
glPixelStorei(GL_PACK_ALIGNMENT,1);
unsigned char* pixels = (unsigned char*)malloc(textureWidth*textureHeight);
glReadPixels(0,0,textureWidth, textureHeight, GL_RED, GL_UNSIGNED_BYTE, pixels);
//swap the pixels
unsigned char* tmp = (unsigned char*)malloc(textureWidth);
for (int j=0;j<textureHeight;j++)
{
pixels[j*textureWidth+j]=255;
}
if (0)
{
for (int j=0;j<textureHeight/2;j++)
{
for (int i=0;i<textureWidth;i++)
{
tmp[i] = pixels[j*textureWidth+i];
pixels[j*textureWidth+i]=pixels[(textureHeight-j-1)*textureWidth+i];
pixels[(textureHeight-j-1)*textureWidth+i] = tmp[i];
}
}
}
int comp=1;//1=Y
stbi_write_png(fileName, textureWidth,textureHeight, comp, pixels, textureWidth);
free(pixels);
}

View File

@@ -0,0 +1,55 @@
#ifndef _OPENGL_FONTSTASH_CALLBACKS_H
#define _OPENGL_FONTSTASH_CALLBACKS_H
#include "fontstash.h"
struct PrimInternalData;
class GLPrimitiveRenderer;
struct InternalOpenGL2RenderCallbacks : public RenderCallbacks
{
virtual PrimInternalData* getData()=0;
virtual ~InternalOpenGL2RenderCallbacks();
virtual void updateTexture(sth_texture* texture, sth_glyph* glyph, int textureWidth, int textureHeight);
virtual void render(sth_texture* texture);
void display2();
};
void dumpTextureToPng( int screenWidth, int screenHeight, const char* fileName);
struct SimpleOpenGL2RenderCallbacks : public InternalOpenGL2RenderCallbacks
{
PrimInternalData* m_data;
virtual PrimInternalData* getData()
{
return m_data;
}
SimpleOpenGL2RenderCallbacks(PrimInternalData* data)
:m_data(data)
{
}
virtual ~SimpleOpenGL2RenderCallbacks()
{
}
};
struct OpenGL2RenderCallbacks : public InternalOpenGL2RenderCallbacks
{
GLPrimitiveRenderer* m_primRender2;
virtual PrimInternalData* getData();
OpenGL2RenderCallbacks(GLPrimitiveRenderer* primRender);
virtual ~OpenGL2RenderCallbacks();
};
#endif//_OPENGL_FONTSTASH_CALLBACKS_H

View File

@@ -0,0 +1,511 @@
/* stbiw-0.92 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
no warranty implied; use at your own risk
Before including,
#define STB_IMAGE_WRITE_IMPLEMENTATION
in the file that you want to have the implementation.
ABOUT:
This header file is a library for writing images to C stdio. It could be
adapted to write to memory or a general streaming interface; let me know.
The PNG output is not optimal; it is 20-50% larger than the file
written by a decent optimizing implementation. This library is designed
for source code compactness and simplicitly, not optimal image file size
or run-time performance.
USAGE:
There are three functions, one for each image file format:
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
Each function returns 0 on failure and non-0 on success.
The functions create an image file defined by the parameters. The image
is a rectangle of pixels stored from left-to-right, top-to-bottom.
Each pixel contains 'comp' channels of data stored interleaved with 8-bits
per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
The *data pointer points to the first byte of the top-left-most pixel.
For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
a row of pixels to the first byte of the next row of pixels.
PNG creates output files with the same number of components as the input.
The BMP and TGA formats expand Y to RGB in the file format. BMP does not
output alpha.
PNG supports writing rectangles of data even when the bytes storing rows of
data are not consecutive in memory (e.g. sub-rectangles of a larger image),
by supplying the stride between the beginning of adjacent rows. The other
formats do not. (Thus you cannot write a native-format BMP through the BMP
writer, both because it is in BGR order and because it may have padding
at the end of the line.)
*/
#ifndef INCLUDE_STB_IMAGE_WRITE_H
#define INCLUDE_STB_IMAGE_WRITE_H
#ifdef __cplusplus
extern "C" {
#endif
extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
#ifdef __cplusplus
}
#endif
#endif//INCLUDE_STB_IMAGE_WRITE_H
#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
static void writefv(FILE *f, const char *fmt, va_list v)
{
while (*fmt) {
switch (*fmt++) {
case ' ': break;
case '1': { unsigned char x = (unsigned char) va_arg(v, int); fputc(x,f); break; }
case '2': { int x = va_arg(v,int); unsigned char b[2];
b[0] = (unsigned char) x; b[1] = (unsigned char) (x>>8);
fwrite(b,2,1,f); break; }
case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4];
b[0]=(unsigned char)x; b[1]=(unsigned char)(x>>8);
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
fwrite(b,4,1,f); break; }
default:
assert(0);
return;
}
}
}
static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
{
unsigned char arr[3];
arr[0] = a, arr[1] = b, arr[2] = c;
fwrite(arr, 3, 1, f);
}
static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad)
{
unsigned char bg[3] = { 255, 0, 255}, px[3];
stbiw_uint32 zero = 0;
int i,j,k, j_end;
if (y <= 0)
return;
if (vdir < 0)
j_end = -1, j = y-1;
else
j_end = y, j = 0;
for (; j != j_end; j += vdir) {
for (i=0; i < x; ++i) {
unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
if (write_alpha < 0)
fwrite(&d[comp-1], 1, 1, f);
switch (comp) {
case 1:
case 2: write3(f, d[0],d[0],d[0]);
break;
case 4:
if (!write_alpha) {
// composite against pink background
for (k=0; k < 3; ++k)
px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255;
write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]);
break;
}
/* FALLTHROUGH */
case 3:
write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]);
break;
}
if (write_alpha > 0)
fwrite(&d[comp-1], 1, 1, f);
}
fwrite(&zero,scanline_pad,1,f);
}
}
static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, void *data, int alpha, int pad, const char *fmt, ...)
{
FILE *f;
if (y < 0 || x < 0) return 0;
f = fopen(filename, "wb");
if (f) {
va_list v;
va_start(v, fmt);
writefv(f, fmt, v);
va_end(v);
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad);
fclose(f);
}
return f != NULL;
}
int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
{
int pad = (-x*3) & 3;
return outfile(filename,-1,-1,x,y,comp,(void *) data,0,pad,
"11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
}
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
{
int has_alpha = !(comp & 1);
return outfile(filename, -1,-1, x, y, comp, (void *) data, has_alpha, 0,
"111 221 2222 11", 0,0,2, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha);
}
// stretchy buffer; stbi__sbpush() == vector<>::push_back() -- stbi__sbcount() == vector<>::size()
#define stbi__sbraw(a) ((int *) (a) - 2)
#define stbi__sbm(a) stbi__sbraw(a)[0]
#define stbi__sbn(a) stbi__sbraw(a)[1]
#define stbi__sbneedgrow(a,n) ((a)==0 || stbi__sbn(a)+n >= stbi__sbm(a))
#define stbi__sbmaybegrow(a,n) (stbi__sbneedgrow(a,(n)) ? stbi__sbgrow(a,n) : 0)
#define stbi__sbgrow(a,n) stbi__sbgrowf((void **) &(a), (n), sizeof(*(a)))
#define stbi__sbpush(a, v) (stbi__sbmaybegrow(a,1), (a)[stbi__sbn(a)++] = (v))
#define stbi__sbcount(a) ((a) ? stbi__sbn(a) : 0)
#define stbi__sbfree(a) ((a) ? free(stbi__sbraw(a)),0 : 0)
static void *stbi__sbgrowf(void **arr, int increment, int itemsize)
{
int m = *arr ? 2*stbi__sbm(*arr)+increment : increment+1;
void *p = realloc(*arr ? stbi__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
assert(p);
if (p) {
if (!*arr) ((int *) p)[1] = 0;
*arr = (void *) ((int *) p + 2);
stbi__sbm(*arr) = m;
}
return *arr;
}
static unsigned char *stbi__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
{
while (*bitcount >= 8) {
stbi__sbpush(data, (unsigned char) *bitbuffer);
*bitbuffer >>= 8;
*bitcount -= 8;
}
return data;
}
static int stbi__zlib_bitrev(int code, int codebits)
{
int res=0;
while (codebits--) {
res = (res << 1) | (code & 1);
code >>= 1;
}
return res;
}
static unsigned int stbi__zlib_countm(unsigned char *a, unsigned char *b, int limit)
{
int i;
for (i=0; i < limit && i < 258; ++i)
if (a[i] != b[i]) break;
return i;
}
static unsigned int stbi__zhash(unsigned char *data)
{
stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
#define stbi__zlib_flush() (out = stbi__zlib_flushf(out, &bitbuf, &bitcount))
#define stbi__zlib_add(code,codebits) \
(bitbuf |= (code) << bitcount, bitcount += (codebits), stbi__zlib_flush())
#define stbi__zlib_huffa(b,c) stbi__zlib_add(stbi__zlib_bitrev(b,c),c)
// default huffman tables
#define stbi__zlib_huff1(n) stbi__zlib_huffa(0x30 + (n), 8)
#define stbi__zlib_huff2(n) stbi__zlib_huffa(0x190 + (n)-144, 9)
#define stbi__zlib_huff3(n) stbi__zlib_huffa(0 + (n)-256,7)
#define stbi__zlib_huff4(n) stbi__zlib_huffa(0xc0 + (n)-280,8)
#define stbi__zlib_huff(n) ((n) <= 143 ? stbi__zlib_huff1(n) : (n) <= 255 ? stbi__zlib_huff2(n) : (n) <= 279 ? stbi__zlib_huff3(n) : stbi__zlib_huff4(n))
#define stbi__zlib_huffb(n) ((n) <= 143 ? stbi__zlib_huff1(n) : stbi__zlib_huff2(n))
#define stbi__ZHASH 16384
unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
{
static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };
unsigned int bitbuf=0;
int i,j, bitcount=0;
unsigned char *out = NULL;
unsigned char **hash_table[stbi__ZHASH]; // 64KB on the stack!
if (quality < 5) quality = 5;
stbi__sbpush(out, 0x78); // DEFLATE 32K window
stbi__sbpush(out, 0x5e); // FLEVEL = 1
stbi__zlib_add(1,1); // BFINAL = 1
stbi__zlib_add(1,2); // B3YPE = 1 -- fixed huffman
for (i=0; i < stbi__ZHASH; ++i)
hash_table[i] = NULL;
i=0;
while (i < data_len-3) {
// hash next 3 bytes of data to be compressed
int h = stbi__zhash(data+i)&(stbi__ZHASH-1), best=3;
unsigned char *bestloc = 0;
unsigned char **hlist = hash_table[h];
int n = stbi__sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32768) { // if entry lies within window
int d = stbi__zlib_countm(hlist[j], data+i, data_len-i);
if (d >= best) best=d,bestloc=hlist[j];
}
}
// when hash table entry is too long, delete half the entries
if (hash_table[h] && stbi__sbn(hash_table[h]) == 2*quality) {
memcpy(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
stbi__sbn(hash_table[h]) = quality;
}
stbi__sbpush(hash_table[h],data+i);
if (bestloc) {
// "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
h = stbi__zhash(data+i+1)&(stbi__ZHASH-1);
hlist = hash_table[h];
n = stbi__sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32767) {
int e = stbi__zlib_countm(hlist[j], data+i+1, data_len-i-1);
if (e > best) { // if next match is better, bail on current match
bestloc = NULL;
break;
}
}
}
}
if (bestloc) {
int d = data+i - bestloc; // distance back
assert(d <= 32767 && best <= 258);
for (j=0; best > lengthc[j+1]-1; ++j);
stbi__zlib_huff(j+257);
if (lengtheb[j]) stbi__zlib_add(best - lengthc[j], lengtheb[j]);
for (j=0; d > distc[j+1]-1; ++j);
stbi__zlib_add(stbi__zlib_bitrev(j,5),5);
if (disteb[j]) stbi__zlib_add(d - distc[j], disteb[j]);
i += best;
} else {
stbi__zlib_huffb(data[i]);
++i;
}
}
// write out final bytes
for (;i < data_len; ++i)
stbi__zlib_huffb(data[i]);
stbi__zlib_huff(256); // end of block
// pad with 0 bits to byte boundary
while (bitcount)
stbi__zlib_add(0,1);
for (i=0; i < stbi__ZHASH; ++i)
(void) stbi__sbfree(hash_table[i]);
{
// compute adler32 on input
unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552;
int j=0;
while (j < data_len) {
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
s1 %= 65521, s2 %= 65521;
j += blocklen;
blocklen = 5552;
}
stbi__sbpush(out, (unsigned char) (s2 >> 8));
stbi__sbpush(out, (unsigned char) s2);
stbi__sbpush(out, (unsigned char) (s1 >> 8));
stbi__sbpush(out, (unsigned char) s1);
}
*out_len = stbi__sbn(out);
// make returned pointer freeable
memmove(stbi__sbraw(out), out, *out_len);
return (unsigned char *) stbi__sbraw(out);
}
unsigned int stbi__crc32(unsigned char *buffer, int len)
{
static unsigned int crc_table[256];
unsigned int crc = ~0u;
int i,j;
if (crc_table[1] == 0)
for(i=0; i < 256; i++)
for (crc_table[i]=i, j=0; j < 8; ++j)
crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
for (i=0; i < len; ++i)
crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
return ~crc;
}
#define stbi__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4)
#define stbi__wp32(data,v) stbi__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
#define stbi__wptag(data,s) stbi__wpng4(data, s[0],s[1],s[2],s[3])
static void stbi__wpcrc(unsigned char **data, int len)
{
unsigned int crc = stbi__crc32(*data - len - 4, len+4);
stbi__wp32(*data, crc);
}
static unsigned char stbi__paeth(int a, int b, int c)
{
int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
if (pa <= pb && pa <= pc) return (unsigned char) a;
if (pb <= pc) return (unsigned char) b;
return (unsigned char) c;
}
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
{
int ctype[5] = { -1, 0, 4, 2, 6 };
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
unsigned char *out,*o, *filt, *zlib;
signed char *line_buffer;
int i,j,k,p,zlen;
if (stride_bytes == 0)
stride_bytes = x * n;
filt = (unsigned char *) malloc((x*n+1) * y); if (!filt) return 0;
line_buffer = (signed char *) malloc(x * n); if (!line_buffer) { free(filt); return 0; }
for (j=0; j < y; ++j) {
static int mapping[] = { 0,1,2,3,4 };
static int firstmap[] = { 0,1,0,5,6 };
int *mymap = j ? mapping : firstmap;
int best = 0, bestval = 0x7fffffff;
for (p=0; p < 2; ++p) {
for (k= p?best:0; k < 5; ++k) {
int type = mymap[k],est=0;
unsigned char *z = pixels + stride_bytes*j;
for (i=0; i < n; ++i)
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
case 4: line_buffer[i] = (signed char) (z[i] - stbi__paeth(0,z[i-stride_bytes],0)); break;
case 5: line_buffer[i] = z[i]; break;
case 6: line_buffer[i] = z[i]; break;
}
for (i=n; i < x*n; ++i) {
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i] - z[i-n]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
case 4: line_buffer[i] = z[i] - stbi__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
case 6: line_buffer[i] = z[i] - stbi__paeth(z[i-n], 0,0); break;
}
}
if (p) break;
for (i=0; i < x*n; ++i)
est += abs((signed char) line_buffer[i]);
if (est < bestval) { bestval = est; best = k; }
}
}
// when we get here, best contains the filter type, and line_buffer contains the data
filt[j*(x*n+1)] = (unsigned char) best;
memcpy(filt+j*(x*n+1)+1, line_buffer, x*n);
}
free(line_buffer);
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
free(filt);
if (!zlib) return 0;
// each tag requires 12 bytes of overhead
out = (unsigned char *) malloc(8 + 12+13 + 12+zlen + 12);
if (!out) return 0;
*out_len = 8 + 12+13 + 12+zlen + 12;
o=out;
memcpy(o,sig,8); o+= 8;
stbi__wp32(o, 13); // header length
stbi__wptag(o, "IHDR");
stbi__wp32(o, x);
stbi__wp32(o, y);
*o++ = 8;
*o++ = (unsigned char) ctype[n];
*o++ = 0;
*o++ = 0;
*o++ = 0;
stbi__wpcrc(&o,13);
stbi__wp32(o, zlen);
stbi__wptag(o, "IDAT");
memcpy(o, zlib, zlen); o += zlen; free(zlib);
stbi__wpcrc(&o, zlen);
stbi__wp32(o,0);
stbi__wptag(o, "IEND");
stbi__wpcrc(&o,0);
assert(o == out + *out_len);
return out;
}
int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
{
FILE *f;
int len;
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
if (!png) return 0;
f = fopen(filename, "wb");
if (!f) { free(png); return 0; }
fwrite(png, 1, len, f);
fclose(f);
free(png);
return 1;
}
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history
0.92 (2010-08-01)
casts to unsigned char to fix warnings
0.91 (2010-07-17)
first public release
0.90 first internal release
*/

File diff suppressed because it is too large Load Diff