reorganize files and add btgui

This commit is contained in:
erwin coumans
2013-03-12 23:52:31 -07:00
parent 9612c2cd3d
commit e4a7b6f487
262 changed files with 46553 additions and 14753 deletions

View File

@@ -0,0 +1,812 @@
//
// 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;
// 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;
fread(data, 1, datasize, fp);
fclose(fp);
fp = 0;
idx = sth_add_font_from_memory(stash, data);
// 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 char* bmp = 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.5*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.5*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,screenwidth,screenheight);
v = setv(v, q.x1, q.y0, 1,0,screenwidth,screenheight);
v = setv(v, q.x1, q.y1, 1,1,screenwidth,screenheight);
v = setv(v, q.x0, q.y0, 0,0,screenwidth,screenheight);
v = setv(v, q.x1, q.y1, 1,1,screenwidth,screenheight);
v = setv(v, q.x0, q.y1, 0,1,screenwidth,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,screenwidth,screenheight);
v = setv(v, q.x1, q.y0, q.s1, q.t0,screenwidth,screenheight);
v = setv(v, q.x1, q.y1, q.s1, q.t1,screenwidth,screenheight);
v = setv(v, q.x0, q.y0, q.s0, q.t0,screenwidth,screenheight);
v = setv(v, q.x1, q.y1, q.s1, q.t1,screenwidth,screenheight);
v = setv(v, q.x0, q.y1, q.s0, q.t1,screenwidth,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;
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,680 @@
/*
Copyright (c) 2012 Advanced Micro Devices, Inc.
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.
*/
//Originally written by Erwin Coumans
//
//#include "vld.h"
#ifndef __APPLE__
#include <GL/glew.h>
#endif
#include <string.h>//memset
#ifdef __APPLE__
#include "OpenGLWindow/MacOpenGLWindow.h"
#elif defined (_WIN32)
#include "OpenGLWindow/Win32OpenGLWindow.h"
#elif defined (__linux)
#include "OpenGLWindow/X11OpenGLWindow.h"
#endif
#include "fontstash.h"
#include "opengl_fontstashcallbacks.h"
#include "BulletCommon/btQuickprof.h"
#include "BulletCommon/btQuaternion.h"
#include "BulletCommon/CommandLineArgs.h"
#include "../OpenGLWindow/LoadShader.h"
extern char OpenSansData[];
bool printStats = false;
bool pauseSimulation = false;
bool shootObject = false;
int m_glutScreenWidth;
int m_glutScreenHeight;
bool useInterop = false;
#include "../OpenGLWindow/GLPrimInternalData.h"
static PrimInternalData sData;
/*GLuint sData.m_texturehandle;
GLuint sData.m_shaderProg;
GLint m_positionUniform;
GLint m_colourAttribute, m_positionAttribute,m_textureAttribute;
GLuint m_vertexArrayObject,m_vertexBuffer;
GLuint m_indexBuffer;
*/
void loadShader();
unsigned int indexData[6] = {0,1,2,0,2,3};
void loadBufferData(){
Vertex vertexDataOrg[4] = {
{ vec4(-0.5, -0.5, 0.0, 1.0 ), vec4( 1.0, 0.0, 0.0, 1.0 ) ,vec2(0,0)},
{ vec4(-0.5, 0.5, 0.0, 1.0 ), vec4( 1.0, 1.0, 1.0, 1.0 ) ,vec2(0,1)},
{ vec4( 0.5, 0.5, 0.0, 1.0 ), vec4( 1.0, 1.0, 1.0, 1.0 ) ,vec2(1,1)},
{ vec4( 0.5, -0.5, 0.0, 1.0 ), vec4( 1.0, 1.0, 1.0, 1.0 ) ,vec2(1,0)}
};
Vertex vertexData[4] = {
{ vec4(-0.5, -0.5, 0.0, 1.0 ), vec4( 1.0, 1.0, 1.0, 1.0 ) ,vec2(0.0078125,0.015625)},
{ vec4(-0.5, 0.5, 0.0, 1.0 ), vec4( 1.0, 1.0, 1.0, 1.0 ) ,vec2(0.101562,0.015625)},
{ vec4( 0.5, 0.5, 0.0, 1.0 ), vec4( 1.0, 1.0, 1.0, 1.0 ) ,vec2(0.101562,0.105469)},
{ vec4( 0.5, -0.5, 0.0, 1.0 ), vec4( 1.0, 1.0, 1.0, 1.0 ) ,vec2(0.0078125,0.105469)}
};
Vertex vertexData2[4] = {
{ vec4(0, 0.901042, 0.0, 1.0 ), vec4( 1.0, 1.0, 1.0, 1.0 ) ,vec2(0.0078125,0.015625)},
{ vec4(0.0234375, 0.901042, 0.0, 1.0 ), vec4( 1.0, 1.0, 1.0, 1.0 ) ,vec2(0.101562,0.015625)},
{ vec4( 0.0234375, 0.871094, 0.0, 1.0 ), vec4( 1.0, 1.0, 1.0, 1.0 ) ,vec2(0.101562,0.105469)},
{ vec4( 0., 0.871094, 0.0, 1.0 ), vec4( 1.0, 1.0, 1.0, 1.0 ) ,vec2(0.0078125,0.105469)}
};
glGenVertexArrays(1, &sData.m_vertexArrayObject);
glBindVertexArray(sData.m_vertexArrayObject);
glGenBuffers(1, &sData.m_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, sData.m_vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(Vertex), vertexData, GL_STATIC_DRAW);
GLuint err = glGetError();
btAssert(err==GL_NO_ERROR);
glGenBuffers(1, &sData.m_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sData.m_indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,6*sizeof(int), indexData,GL_STATIC_DRAW);
glEnableVertexAttribArray(sData.m_positionAttribute);
glEnableVertexAttribArray(sData.m_colourAttribute);
err = glGetError();
btAssert(err==GL_NO_ERROR);
glEnableVertexAttribArray(sData.m_textureAttribute);
glVertexAttribPointer(sData.m_positionAttribute, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *)0);
glVertexAttribPointer(sData.m_colourAttribute , 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *)sizeof(vec4));
glVertexAttribPointer(sData.m_textureAttribute , 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *)(sizeof(vec4)+sizeof(vec4)));
err = glGetError();
btAssert(err==GL_NO_ERROR);
}
void initTestTexture()
{
// glEnable(GL_TEXTURE_2D);
glGenTextures(1,(GLuint*)&sData.m_texturehandle);
GLint err = glGetError();
btAssert(err==GL_NO_ERROR);
glBindTexture(GL_TEXTURE_2D,sData.m_texturehandle);
err = glGetError();
btAssert(err==GL_NO_ERROR);
err = glGetError();
btAssert(err==GL_NO_ERROR);
int width=256;
int height=256;
unsigned char* image = (unsigned char*)malloc(width*height);
memset(image,0,width*height);
for (int i=0;i<width;i++)
{
for (int j=0;j<height;j++)
{
if (i==j)
image[i+width*j]=0;
else
image[i+width*j]=255;
}
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width,height,0,GL_RED,GL_UNSIGNED_BYTE,image);
err = glGetError();
btAssert(err==GL_NO_ERROR);
glGenerateMipmap(GL_TEXTURE_2D);
err = glGetError();
btAssert(err==GL_NO_ERROR);
free(image);
}
static const char* vertexShader= \
"#version 150 \n"
"\n"
"uniform vec2 p;\n"
"\n"
"in vec4 position;\n"
"in vec4 colour;\n"
"out vec4 colourV;\n"
"\n"
"in vec2 texuv;\n"
"out vec2 texuvV;\n"
"\n"
"\n"
"void main (void)\n"
"{\n"
" colourV = colour;\n"
" gl_Position = vec4(p.x+position.x, p.y+position.y,0.f,1.f);\n"
" texuvV=texuv;\n"
"}\n";
static const char* fragmentShader= \
"#version 150\n"
"\n"
"in vec4 colourV;\n"
"out vec4 fragColour;\n"
"in vec2 texuvV;\n"
"\n"
"uniform sampler2D Diffuse;\n"
"\n"
"void main(void)\n"
"{\n"
" vec4 texcolorred = texture(Diffuse,texuvV);\n"
"// vec4 texcolor = vec4(texcolorred.x,texcolorred.x,texcolorred.x,texcolorred.x);\n"
" vec4 texcolor = vec4(1,1,1,texcolorred.x);\n"
"\n"
" fragColour = colourV*texcolor;\n"
"}\n";
void loadShader(){
sData.m_shaderProg= gltLoadShaderPair(vertexShader,fragmentShader);
sData.m_positionUniform = glGetUniformLocation(sData.m_shaderProg, "p");
if (sData.m_positionUniform < 0) {
btAssert(0);
}
sData.m_colourAttribute = glGetAttribLocation(sData.m_shaderProg, "colour");
if (sData.m_colourAttribute < 0) {
btAssert(0);
}
sData.m_positionAttribute = glGetAttribLocation(sData.m_shaderProg, "position");
if (sData.m_positionAttribute < 0) {
btAssert(0);
}
sData.m_textureAttribute = glGetAttribLocation(sData.m_shaderProg,"texuv");
if (sData.m_textureAttribute < 0) {
btAssert(0);
}
}
void display() {
GLint err = glGetError();
btAssert(err==GL_NO_ERROR);
const float timeScale = 0.008f;
glUseProgram(sData.m_shaderProg);
glBindBuffer(GL_ARRAY_BUFFER, sData.m_vertexBuffer);
glBindVertexArray(sData.m_vertexArrayObject);
err = glGetError();
btAssert(err==GL_NO_ERROR);
// glBindTexture(GL_TEXTURE_2D,sData.m_texturehandle);
err = glGetError();
btAssert(err==GL_NO_ERROR);
vec2 p( 0.f,0.f);//?b?0.5f * sinf(timeValue), 0.5f * cosf(timeValue) );
glUniform2fv(sData.m_positionUniform, 1, (const GLfloat *)&p);
err = glGetError();
btAssert(err==GL_NO_ERROR);
err = glGetError();
btAssert(err==GL_NO_ERROR);
glEnableVertexAttribArray(sData.m_positionAttribute);
err = glGetError();
btAssert(err==GL_NO_ERROR);
glEnableVertexAttribArray(sData.m_colourAttribute);
err = glGetError();
btAssert(err==GL_NO_ERROR);
glEnableVertexAttribArray(sData.m_textureAttribute);
glVertexAttribPointer(sData.m_positionAttribute, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *)0);
glVertexAttribPointer(sData.m_colourAttribute , 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *)sizeof(vec4));
glVertexAttribPointer(sData.m_textureAttribute , 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *)(sizeof(vec4)+sizeof(vec4)));
err = glGetError();
btAssert(err==GL_NO_ERROR);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sData.m_indexBuffer);
//glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
int indexCount = 6;
err = glGetError();
btAssert(err==GL_NO_ERROR);
// glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
err = glGetError();
btAssert(err==GL_NO_ERROR);
// glutSwapBuffers();
}
const char* fileName="../../bin/1000 stack.bullet";
void Usage()
{
printf("\nprogram.exe [--pause_simulation=<0 or 1>] [--load_bulletfile=test.bullet] [--enable_interop=<0 or 1>] [--enable_gpusap=<0 or 1>] [--enable_convexheightfield=<0 or 1>] [--enable_static=<0 or 1>] [--x_dim=<int>] [--y_dim=<num>] [--z_dim=<int>] [--x_gap=<float>] [--y_gap=<float>] [--z_gap=<float>]\n");
};
int main(int argc, char* argv[])
{
GLint err;
CommandLineArgs args(argc,argv);
if (args.CheckCmdLineFlag("help"))
{
Usage();
return 0;
}
args.GetCmdLineArgument("enable_interop", useInterop);
printf("useInterop=%d\n",useInterop);
args.GetCmdLineArgument("pause_simulation", pauseSimulation);
printf("pause_simulation=%d\n",pauseSimulation);
char* tmpfile = 0;
args.GetCmdLineArgument("load_bulletfile", tmpfile );
if (tmpfile)
fileName = tmpfile;
printf("load_bulletfile=%s\n",fileName);
int width = 700;
int height= 512;
printf("\n");
btgDefaultOpenGLWindow* window = new btgDefaultOpenGLWindow();
window->createWindow(btgWindowConstructionInfo(width,height));
window->setWindowTitle("font test");
#ifndef __APPLE__
err = glewInit();
#endif
window->runMainLoop();
loadShader();
loadBufferData();
initTestTexture();
window->startRendering();
window->endRendering();
err = glGetError();
btAssert(err==GL_NO_ERROR);
// render.InitShaders();
// render.writeTransforms();
window->runMainLoop();
// window->setMouseCallback(btDefaultMouseCallback);
// window->setKeyboardCallback(btDefaultKeyboardCallback);
// window->setWheelCallback(btDefaultWheelCallback);
err = glGetError();
btAssert(err==GL_NO_ERROR);
int done;
struct sth_stash* stash = 0;
FILE* fp = 0;
int datasize;
float sx,sy,dx,dy,lh;
int droidRegular;//, droidItalic, droidBold, droidJapanese, dejavu;
GLuint texture;
int fontTextureWidth = 512;
int fontTextureHeight = 512;
SimpleOpenGL2RenderCallbacks* renderCallbacks = new SimpleOpenGL2RenderCallbacks(&sData);
stash = sth_create(fontTextureWidth,fontTextureHeight,renderCallbacks);
err = glGetError();
btAssert(err==GL_NO_ERROR);
if (!stash)
{
fprintf(stderr, "Could not create stash.\n");
return -1;
}
// Load the first truetype font from memory (just because we can).
#ifdef _WIN32
const char* fontPath = "../../bin/";
#else
const char* fontPath = "./";
#endif
char fullFontFileName[1024];
sprintf(fullFontFileName,"%s%s",fontPath,"DroidSerif-Regular.ttf");//cour.ttf");//times.ttf");//DroidSerif-Regular.ttf");
//sprintf(fullFontFileName,"%s%s",fontPath,"arial.ttf");//cour.ttf");//times.ttf");//DroidSerif-Regular.ttf");
fp = fopen(fullFontFileName, "rb");
#ifdef LOAD_FONT_FROM_FILE
unsigned char* data;
err = glGetError();
btAssert(err==GL_NO_ERROR);
btAssert(fp);
if (fp)
{
fseek(fp, 0, SEEK_END);
datasize = (int)ftell(fp);
fseek(fp, 0, SEEK_SET);
data = (unsigned char*)malloc(datasize);
if (data == NULL)
{
btAssert(0);
return -1;
}
else
fread(data, 1, datasize, fp);
fclose(fp);
fp = 0;
}
if (!(droidRegular = sth_add_font_from_memory(stash, data)))
{
btAssert(0);
return -1;
}
err = glGetError();
btAssert(err==GL_NO_ERROR);
// Load the remaining truetype fonts directly.
sprintf(fullFontFileName,"%s%s",fontPath,"DroidSerif-Italic.ttf");
if (!(droidItalic = sth_add_font(stash,fullFontFileName)))
{
btAssert(0);
return -1;
}
sprintf(fullFontFileName,"%s%s",fontPath,"DroidSerif-Bold.ttf");
if (!(droidBold = sth_add_font(stash,fullFontFileName)))
{
btAssert(0);
return -1;
}
err = glGetError();
btAssert(err==GL_NO_ERROR);
sprintf(fullFontFileName,"%s%s",fontPath,"DroidSansJapanese.ttf");
if (!(droidJapanese = sth_add_font(stash,fullFontFileName)))
{
btAssert(0);
return -1;
}
err = glGetError();
btAssert(err==GL_NO_ERROR);
#else//LOAD_FONT_FROM_FILE
char* data2 = OpenSansData;
unsigned char* data = (unsigned char*) data2;
if (!(droidRegular = sth_add_font_from_memory(stash, data)))
{
printf("error!\n");
}
#endif//LOAD_FONT_FROM_FILE
while (!window->requestedExit())
{
CProfileManager::Reset();
GLint err = glGetError();
btAssert(err==GL_NO_ERROR);
// glClearColor(0.5f,0.5f,0.5f,1.f);
err = glGetError();
btAssert(err==GL_NO_ERROR);
window->startRendering();
err = glGetError();
btAssert(err==GL_NO_ERROR);
glClearColor(1,1,1,1);//.4, .4, 0.4, 1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//display();
err = glGetError();
btAssert(err==GL_NO_ERROR);
if (1)
{
BT_PROFILE("font stash rendering");
// Update and render
glEnable(GL_BLEND);
err = glGetError();
btAssert(err==GL_NO_ERROR);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
err = glGetError();
btAssert(err==GL_NO_ERROR);
err = glGetError();
btAssert(err==GL_NO_ERROR);
glDisable(GL_DEPTH_TEST);
err = glGetError();
btAssert(err==GL_NO_ERROR);
//glColor4ub(255,0,0,255);
err = glGetError();
btAssert(err==GL_NO_ERROR);
glEnable(GL_BLEND);
err = glGetError();
btAssert(err==GL_NO_ERROR);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
err = glGetError();
btAssert(err==GL_NO_ERROR);
sx = 0; sy = height;
sth_begin_draw(stash);
display();
dx = sx; dy = sy;
static int once=0;
//sth_draw_text(stash, droidRegular,12.f, dx, dy-50, "How does this OpenGL True Type font look? ", &dx,width,height);
int spacing = 512;
if (1)
for (int i=20;i<=110;i+=12)
{
char txt[512];
sprintf(txt,"%d. The quick brown fox jumped over the lazy dog. 1234567890",i);
sth_draw_text(stash, droidRegular,i, 10, dy-spacing, txt, &dx,width,height);
spacing-=i;
}
err = glGetError();
btAssert(err==GL_NO_ERROR);
if (0)
for (int i=0;i<1;i++)
{
dx = sx;
if (once!=1)
{
//need to save this file as UTF-8 without signature, codepage 650001 in Visual Studio
err = glGetError();
btAssert(err==GL_NO_ERROR);
//sth_draw_text(stash, droidJapanese,16.f, dx, dy-36, (const char*) "\xE7\xA7\x81\xE3\x81\xAF\xE3\x82\xAC\xE3\x83\xA9\xE3\x82\xB9\xE3\x82\x92\xE9\xA3\x9F\xE3\x81\xB9\xE3\x82\x89\xE3\x82\x8C\xE3\x81\xBE\xE3\x81\x99\xE3\x80\x82",&dx,
// width,height);//はabcdefghijlkmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_-+=?/\][{}.,<>`~@#$%^", &dx);
// sth_draw_text(stash, droidJapanese,32.f, dx, dy, (const char*) "私はガラスを食べられます。それは私を傷つけません。",&dx);//はabcdefghijlkmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_-+=?/\][{}.,<>`~@#$%^", &dx);
dx = sx;
err = glGetError();
btAssert(err==GL_NO_ERROR);
sth_flush_draw(stash);
dx=0;
sth_draw_text(stash, droidRegular,14.f, dx, dy-80, "How does this OpenGL True Type font look? ", &dx,width,height);
dx=0;
dy-=30;
//sth_draw_text(stash, droidRegular,16.f, dx, dy-80, "Profile How does this OpenGL True Type font look? ", &dx,width,height);
dx=0;
dy-=30;
sth_draw_text(stash, droidRegular,16.f, dx, dy-80, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", &dx,width,height);
dx=0;
dy-=30;
sth_draw_text(stash, droidRegular,16.f, dx, dy-80, "!@#$%^abcdefghijklmnopqrstuvwxyz", &dx,width,height);
dx=0;
// sth_draw_text(stash, droidRegular,16.f, dx, dy-42, "aph OpenGL Profile aCABCabdabcdefghijlkmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^", &dx,width,height);
//sth_draw_text(stash, droidRegular,16.f, dx, dy-42, "aph OpenGL Profile aCABCabdabcdefghijlkmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^", &dx,width,height);
sth_flush_draw(stash);
err = glGetError();
btAssert(err==GL_NO_ERROR);
} else
{
dx = sx;
dy = height;
err = glGetError();
btAssert(err==GL_NO_ERROR);
sth_draw_texture(stash, droidRegular, 16.f, 0, 0,width,height, "a", &dx);
err = glGetError();
btAssert(err==GL_NO_ERROR);
dumpTextureToPng(fontTextureWidth, fontTextureHeight,"newPic.png");
}
once++;
}
err = glGetError();
btAssert(err==GL_NO_ERROR);
sth_end_draw(stash);
glEnable(GL_DEPTH_TEST);
err = glGetError();
btAssert(err==GL_NO_ERROR);
//glFinish();
}
err = glGetError();
btAssert(err==GL_NO_ERROR);
window->endRendering();
err = glGetError();
btAssert(err==GL_NO_ERROR);
{
BT_PROFILE("glFinish");
glFinish();
}
CProfileManager::Increment_Frame_Counter();
static bool printStats = true;
if (printStats && !pauseSimulation)
{
static int count = 0;
count--;
if (count<0)
{
count = 100;
// CProfileManager::dumpAll();
//printStats = false;
} else
{
// printf(".");
}
}
err = glGetError();
btAssert(err==GL_NO_ERROR);
}
#ifdef _WIN32
sth_delete(stash);
#ifdef LOAD_FONT_FROM_FILE
free(data);
#endif //LOAD_FONT_FROM_FILE
#endif
// render.CleanupShaders();
window->closeWindow();
delete window;
return 0;
}

View File

@@ -0,0 +1,275 @@
#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()
{
GLint err = glGetError();
assert(err==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);
err = glGetError();
assert(err==GL_NO_ERROR);
// glBindTexture(GL_TEXTURE_2D,m_texturehandle);
err = glGetError();
assert(err==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);
err = glGetError();
assert(err==GL_NO_ERROR);
err = glGetError();
assert(err==GL_NO_ERROR);
glEnableVertexAttribArray(data->m_positionAttribute);
err = glGetError();
assert(err==GL_NO_ERROR);
glEnableVertexAttribArray(data->m_colourAttribute);
err = glGetError();
assert(err==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)));
err = glGetError();
assert(err==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)
{
GLint err;
err = glGetError();
assert(err==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);
err = glGetError();
assert(err==GL_NO_ERROR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, textureWidth, textureHeight, 0, GL_RED, GL_UNSIGNED_BYTE, texture->m_texels);
GLenum err = glGetError();
assert(err==GL_NO_ERROR);
} else
{
if (textureWidth && textureHeight)
{
GLuint* texId = new GLuint;
texture->m_userData = texId;
//create new texture
glGenTextures(1, texId);
GLenum err = glGetError();
assert(err==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);
err = glGetError();
assert(err==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);
GLuint err = glGetError();
assert(err==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);
err = glGetError();
assert(err==GL_NO_ERROR);
}
} else
{
//delete texture
if (texture->m_userData)
{
GLuint* id = (GLuint*)texture->m_userData;
glDeleteTextures(1, id);
//delete id;
texture->m_userData = 0;
}
}
}
}
void InternalOpenGL2RenderCallbacks::render(sth_texture* texture)
{
display2();
GLuint* texId = (GLuint*) texture->m_userData;
GLint err;
err = glGetError();
assert(err==GL_NO_ERROR);
glActiveTexture(GL_TEXTURE0);
err = glGetError();
assert(err==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);
}
err = glGetError();
assert(err==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);
err = glGetError();
assert(err==GL_NO_ERROR);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_indexBuffer);
//glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
int indexCount = texture->nverts;
err = glGetError();
assert(err==GL_NO_ERROR);
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
err = glGetError();
assert(err==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,54 @@
#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,61 @@
project "OpenGL_TrueTypeFont"
language "C++"
kind "ConsoleApp"
targetdir "../../bin"
initOpenGL()
initGlew()
includedirs {
"../../src",
".."
}
files {
"main.cpp",
"../FontFiles/OpenSans.cpp",
"../OpenGLWindow/LoadShader.cpp",
"../OpenGLWindow/LoadShader.h",
"../../src/BulletCommon/btAlignedAllocator.cpp",
"../../src/BulletCommon/btQuickprof.cpp",
"../../src/BulletCommon/btQuickprof.h" ,
"fontstash.cpp",
"fontstash.h",
"opengl_fontstashcallbacks.cpp",
"opengl_fontstashcallbacks.h",
"stb_image_write.h",
"stb_truetype.h",
}
if os.is("Windows") then
files{
"../OpenGLWindow/Win32OpenGLWindow.cpp",
"../OpenGLWindow/Win32OpenGLWindow.h",
"../OpenGLWindow/Win32Window.cpp",
"../OpenGLWindow/Win32Window.h",
}
end
if os.is("Linux") then
files{
"../OpenGLWindow/X11OpenGLWindow.h",
"../OpenGLWindow/X11OpenGLWindow.cpp"
}
if os.is("MacOSX") then
links {"BulletFileLoader"}
links { "Cocoa.framework" }
files{
"../OpenGLWindow/MacOpenGLWindow.h",
"../OpenGLWindow/MacOpenGLWindow.mm",
}
end
end

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); // BTYPE = 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