You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
		
		
		
		
		
			
		
			
				
					
					
						
							332 lines
						
					
					
						
							8.4 KiB
						
					
					
				
			
		
		
	
	
							332 lines
						
					
					
						
							8.4 KiB
						
					
					
				| #pragma warning(disable:4244; disable:4305; disable:4018) | |
| #include <assert.h> | |
| #include <ctype.h> | |
|  | |
| #define STB_WINMAIN | |
| #include "stb_wingraph.h" | |
|  | |
| #define STB_TRUETYPE_IMPLEMENTATION | |
| #define STB_RECT_PACK_IMPLEMENTATION | |
| #include "stb_rect_pack.h" | |
| #include "stb_truetype.h" | |
|  | |
| #ifndef WINGDIAPI | |
| #define CALLBACK    __stdcall | |
| #define WINGDIAPI   __declspec(dllimport) | |
| #define APIENTRY    __stdcall | |
| #endif | |
|  | |
| #include <gl/gl.h> | |
| #include <gl/glu.h> | |
|  | |
| #define GL_FRAMEBUFFER_SRGB_EXT           0x8DB9 | |
|  | |
| #define SIZE_X  1024 | |
| #define SIZE_Y  768 | |
|  | |
| stbtt_packedchar chardata[6][128]; | |
| 
 | |
| int sx=SIZE_X, sy=SIZE_Y; | |
| 
 | |
| #define BITMAP_W 512 | |
| #define BITMAP_H 512 | |
| unsigned char temp_bitmap[BITMAP_W][BITMAP_H]; | |
| unsigned char ttf_buffer[1 << 25]; | |
| GLuint font_tex; | |
| 
 | |
| float scale[2] = { 24.0f, 14.0f }; | |
| 
 | |
| int sf[6] = { 0,1,2, 0,1,2 }; | |
| 
 | |
| void load_fonts(void) | |
| { | |
|    stbtt_pack_context pc; | |
|    int i; | |
|    FILE *f; | |
|    char filename[256]; | |
|    char *win = getenv("windir"); | |
|    if (win == NULL) win = getenv("SystemRoot"); | |
| 
 | |
|    f = fopen(stb_wingraph_commandline, "rb"); | |
|    if (!f) { | |
|       if (win == NULL) | |
|          sprintf(filename, "arial.ttf", win); | |
|       else | |
|          sprintf(filename, "%s/fonts/arial.ttf", win); | |
|       f = fopen(filename, "rb"); | |
|       if (!f) exit(0); | |
|    } | |
| 
 | |
|    fread(ttf_buffer, 1, 1<<25, f); | |
| 
 | |
|    stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, 1, NULL); | |
|    for (i=0; i < 2; ++i) { | |
|       stbtt_PackSetOversampling(&pc, 1, 1); | |
|       stbtt_PackFontRange(&pc, ttf_buffer, 0, scale[i], 32, 95, chardata[i*3+0]+32); | |
|       stbtt_PackSetOversampling(&pc, 2, 2); | |
|       stbtt_PackFontRange(&pc, ttf_buffer, 0, scale[i], 32, 95, chardata[i*3+1]+32); | |
|       stbtt_PackSetOversampling(&pc, 3, 1); | |
|       stbtt_PackFontRange(&pc, ttf_buffer, 0, scale[i], 32, 95, chardata[i*3+2]+32); | |
|    } | |
|    stbtt_PackEnd(&pc); | |
| 
 | |
|    glGenTextures(1, &font_tex); | |
|    glBindTexture(GL_TEXTURE_2D, font_tex); | |
|    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, BITMAP_W, BITMAP_H, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); | |
|    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
|    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| } | |
| 
 | |
| int black_on_white; | |
| 
 | |
| void draw_init(void) | |
| { | |
|    glDisable(GL_CULL_FACE); | |
|    glDisable(GL_TEXTURE_2D); | |
|    glDisable(GL_LIGHTING); | |
|    glDisable(GL_DEPTH_TEST); | |
| 
 | |
|    glViewport(0,0,sx,sy); | |
|    if (black_on_white) | |
|       glClearColor(255,255,255,0); | |
|    else | |
|       glClearColor(0,0,0,0); | |
|    glClear(GL_COLOR_BUFFER_BIT); | |
| 
 | |
|    glMatrixMode(GL_PROJECTION); | |
|    glLoadIdentity(); | |
|    gluOrtho2D(0,sx,sy,0); | |
|    glMatrixMode(GL_MODELVIEW); | |
|    glLoadIdentity(); | |
| } | |
| 
 | |
| 
 | |
| void drawBoxTC(float x0, float y0, float x1, float y1, float s0, float t0, float s1, float t1) | |
| { | |
|    glTexCoord2f(s0,t0); glVertex2f(x0,y0); | |
|    glTexCoord2f(s1,t0); glVertex2f(x1,y0); | |
|    glTexCoord2f(s1,t1); glVertex2f(x1,y1); | |
|    glTexCoord2f(s0,t1); glVertex2f(x0,y1); | |
| } | |
| 
 | |
| int integer_align; | |
| 
 | |
| void print(float x, float y, int font, char *text) | |
| { | |
|    glEnable(GL_TEXTURE_2D); | |
|    glBindTexture(GL_TEXTURE_2D, font_tex); | |
|    glBegin(GL_QUADS); | |
|    while (*text) { | |
|       stbtt_aligned_quad q; | |
|       stbtt_GetPackedQuad(chardata[font], BITMAP_W, BITMAP_H, *text++, &x, &y, &q, font ? 0 : integer_align); | |
|       drawBoxTC(q.x0,q.y0,q.x1,q.y1, q.s0,q.t0,q.s1,q.t1); | |
|    } | |
|    glEnd(); | |
| } | |
| 
 | |
| int font=3; | |
| int translating; | |
| int rotating=0; | |
| int srgb=0; | |
| float rotate_t, translate_t; | |
| int show_tex; | |
| 
 | |
| void draw_world(void) | |
| { | |
|    int sfont = sf[font]; | |
|    float x = 20; | |
|    glEnable(GL_BLEND); | |
|    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 
 | |
|    if (black_on_white) | |
|       glColor3f(0,0,0); | |
|    else | |
|       glColor3f(1,1,1); | |
| 
 | |
| 
 | |
|    print(80, 30, sfont, "Controls:"); | |
|    print(100, 60, sfont, "S: toggle font size"); | |
|    print(100, 85, sfont, "O: toggle oversampling"); | |
|    print(100,110, sfont, "T: toggle translation"); | |
|    print(100,135, sfont, "R: toggle rotation"); | |
|    print(100,160, sfont, "P: toggle pixel-snap (only non-oversampled)"); | |
|    print(100,185, sfont, "G: toggle srgb gamma-correction"); | |
|    if (black_on_white) | |
|       print(100,210, sfont, "B: toggle to white-on-black"); | |
|    else | |
|       print(100,210, sfont, "B: toggle to black-on-white"); | |
|    print(100,235, sfont, "V: view font texture"); | |
| 
 | |
|    print(80, 300, sfont, "Current font:"); | |
| 
 | |
|    if (!show_tex) { | |
|       if (font < 3) | |
|          print(100, 350, sfont, "Font height: 24 pixels"); | |
|       else | |
|          print(100, 350, sfont, "Font height: 14 pixels"); | |
|    } | |
| 
 | |
|    if (font%3==1) | |
|       print(100, 325, sfont, "2x2 oversampled text at 1:1"); | |
|    else if (font%3 == 2) | |
|       print(100, 325, sfont, "3x1 oversampled text at 1:1"); | |
|    else if (integer_align) | |
|       print(100, 325, sfont, "1:1 text, one texel = one pixel, snapped to integer coordinates"); | |
|    else | |
|       print(100, 325, sfont, "1:1 text, one texel = one pixel"); | |
| 
 | |
|    if (show_tex) { | |
|       glBegin(GL_QUADS); | |
|       drawBoxTC(200,400, 200+BITMAP_W,300+BITMAP_H, 0,0,1,1); | |
|       glEnd(); | |
|    } else { | |
|       glMatrixMode(GL_MODELVIEW); | |
|       glTranslatef(200,350,0); | |
| 
 | |
|       if (translating) | |
|          x += fmod(translate_t*8,30); | |
| 
 | |
|       if (rotating) { | |
|          glTranslatef(100,150,0); | |
|          glRotatef(rotate_t*2,0,0,1); | |
|          glTranslatef(-100,-150,0); | |
|       } | |
|       print(x,100, font, "This is a test"); | |
|       print(x,130, font, "Now is the time for all good men to come to the aid of their country."); | |
|       print(x,160, font, "The quick brown fox jumps over the lazy dog."); | |
|       print(x,190, font, "0123456789"); | |
|    } | |
| } | |
| 
 | |
| void draw(void) | |
| { | |
|    draw_init(); | |
|    draw_world(); | |
|    stbwingraph_SwapBuffers(NULL); | |
| } | |
| 
 | |
| static int initialized=0; | |
| static float last_dt; | |
| 
 | |
| int move[4]; | |
| int raw_mouse_x, raw_mouse_y; | |
| 
 | |
| int loopmode(float dt, int real, int in_client) | |
| { | |
|    float actual_dt = dt; | |
| 
 | |
|    if (!initialized) return 0; | |
| 
 | |
|    rotate_t += dt; | |
|    translate_t += dt; | |
| 
 | |
| //   music_sim(); | |
|    if (!real) | |
|       return 0; | |
| 
 | |
|    if (dt > 0.25) dt = 0.25; | |
|    if (dt < 0.01) dt = 0.01; | |
| 
 | |
|    draw(); | |
| 
 | |
|    return 0; | |
| } | |
| 
 | |
| int winproc(void *data, stbwingraph_event *e) | |
| { | |
|    switch (e->type) { | |
|       case STBWGE_create: | |
|          break; | |
| 
 | |
|       case STBWGE_char: | |
|          switch(e->key) { | |
|             case 27: | |
|                stbwingraph_ShowCursor(NULL,1); | |
|                return STBWINGRAPH_winproc_exit; | |
|                break; | |
|             case 'o': case 'O': | |
|                font = (font+1) % 3 + (font/3)*3; | |
|                break; | |
|             case 's': case 'S': | |
|                font = (font+3) % 6; | |
|                break; | |
|             case 't': case 'T': | |
|                translating = !translating; | |
|                translate_t = 0; | |
|                break; | |
|             case 'r': case 'R': | |
|                rotating = !rotating; | |
|                rotate_t = 0; | |
|                break; | |
|             case 'p': case 'P': | |
|                integer_align = !integer_align; | |
|                break; | |
|             case 'g': case 'G': | |
|                srgb = !srgb; | |
|                if (srgb) | |
|                   glEnable(GL_FRAMEBUFFER_SRGB_EXT); | |
|                else | |
|                   glDisable(GL_FRAMEBUFFER_SRGB_EXT); | |
|                break; | |
|             case 'v': case 'V': | |
|                show_tex = !show_tex; | |
|                break; | |
|             case 'b': case 'B': | |
|                black_on_white = !black_on_white; | |
|                break; | |
|          } | |
|          break; | |
| 
 | |
|       case STBWGE_mousemove: | |
|          raw_mouse_x = e->mx; | |
|          raw_mouse_y = e->my; | |
|          break; | |
| 
 | |
| #if 0 | |
|       case STBWGE_mousewheel:  do_mouse(e,0,0); break; | |
|       case STBWGE_leftdown:    do_mouse(e, 1,0); break; | |
|       case STBWGE_leftup:      do_mouse(e,-1,0); break; | |
|       case STBWGE_rightdown:   do_mouse(e,0, 1); break; | |
|       case STBWGE_rightup:     do_mouse(e,0,-1); break; | |
| #endif | |
|  | |
|       case STBWGE_keydown: | |
|          if (e->key == VK_RIGHT) move[0] = 1; | |
|          if (e->key == VK_LEFT)  move[1] = 1; | |
|          if (e->key == VK_UP)    move[2] = 1; | |
|          if (e->key == VK_DOWN)  move[3] = 1; | |
|          break; | |
|       case STBWGE_keyup: | |
|          if (e->key == VK_RIGHT) move[0] = 0; | |
|          if (e->key == VK_LEFT)  move[1] = 0; | |
|          if (e->key == VK_UP)    move[2] = 0; | |
|          if (e->key == VK_DOWN)  move[3] = 0; | |
|          break; | |
| 
 | |
|       case STBWGE_size: | |
|          sx = e->width; | |
|          sy = e->height; | |
|          loopmode(0,1,0); | |
|          break; | |
| 
 | |
|       case STBWGE_draw: | |
|          if (initialized) | |
|             loopmode(0,1,0); | |
|          break; | |
| 
 | |
|       default: | |
|          return STBWINGRAPH_unprocessed; | |
|    } | |
|    return 0; | |
| } | |
| 
 | |
| void stbwingraph_main(void) | |
| { | |
|    stbwingraph_Priority(2); | |
|    stbwingraph_CreateWindow(1, winproc, NULL, "tt", SIZE_X,SIZE_Y, 0, 1, 0, 0); | |
|    stbwingraph_ShowCursor(NULL, 0); | |
|    load_fonts(); | |
|    initialized = 1; | |
|    stbwingraph_MainLoop(loopmode, 0.016f);   // 30 fps = 0.33 | |
| } | |
| 
 | |
| 
 |