stb_truetype: oversampling, including oversampling demo appmaster
parent
b6f8358f47
commit
f03e352093
11 changed files with 1549 additions and 56 deletions
@ -0,0 +1,272 @@ |
|||||||
|
#pragma warning(disable:4244; disable:4305; disable:4018) |
||||||
|
#include <assert.h> |
||||||
|
#include <ctype.h> |
||||||
|
|
||||||
|
#define STB_DEFINE |
||||||
|
#define STB_WINMAIN |
||||||
|
#define STB_NO_REGISTRY |
||||||
|
#include "stb_wingraph.h" |
||||||
|
#include "stb.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 SIZE_X 1024 |
||||||
|
#define SIZE_Y 768 |
||||||
|
|
||||||
|
stbtt_packedchar chardata[3][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; |
||||||
|
|
||||||
|
void load_fonts(void) |
||||||
|
{ |
||||||
|
stbtt_pack_context pc; |
||||||
|
FILE *f = fopen("c:/windows/fonts/times.ttf", "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); |
||||||
|
stbtt_PackFontRange(&pc, ttf_buffer, 0, 24.0, 32, 95, chardata[0]+32); |
||||||
|
stbtt_PackSetOversampling(&pc, 2, 2); |
||||||
|
stbtt_PackFontRange(&pc, ttf_buffer, 0, 24.0, 32, 95, chardata[1]+32); |
||||||
|
stbtt_PackSetOversampling(&pc, 3, 1); |
||||||
|
stbtt_PackFontRange(&pc, ttf_buffer, 0, 24.0, 32, 95, chardata[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); |
||||||
|
} |
||||||
|
|
||||||
|
void draw_init(void) |
||||||
|
{ |
||||||
|
glDisable(GL_CULL_FACE); |
||||||
|
glDisable(GL_TEXTURE_2D); |
||||||
|
glDisable(GL_LIGHTING); |
||||||
|
glDisable(GL_DEPTH_TEST); |
||||||
|
|
||||||
|
glViewport(0,0,sx,sy); |
||||||
|
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=0; |
||||||
|
int translating; |
||||||
|
int rotating=0; |
||||||
|
float rotate_t, translate_t; |
||||||
|
int show_tex; |
||||||
|
|
||||||
|
void draw_world(void) |
||||||
|
{ |
||||||
|
float x = 20; |
||||||
|
glEnable(GL_BLEND); |
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
||||||
|
glColor3f(1,1,1); |
||||||
|
|
||||||
|
if (font==1) |
||||||
|
print(100, 50, font, "2x2 oversampled text at 1:1"); |
||||||
|
else if (font == 2) |
||||||
|
print(100, 50, font, "3x1 oversampled text at 1:1"); |
||||||
|
else if (integer_align) |
||||||
|
print(100, 50, font, "1:1 text, one texel = one pixel, snapped to integer coordinates"); |
||||||
|
else |
||||||
|
print(100, 50, font, "1:1 text, one texel = one pixel"); |
||||||
|
|
||||||
|
print(100, 80, font, "O: toggle oversampling"); |
||||||
|
print(100,105, font, "T: toggle translation"); |
||||||
|
print(100,130, font, "R: toggle rotation"); |
||||||
|
print(100,155, font, "P: toggle pixel-snap (only non-oversampled)"); |
||||||
|
print(100,180, font, "V: view font texture"); |
||||||
|
|
||||||
|
if (show_tex) { |
||||||
|
glBegin(GL_QUADS); |
||||||
|
drawBoxTC(200,200, 200+BITMAP_W,200+BITMAP_H, 0,0,1,1); |
||||||
|
glEnd(); |
||||||
|
} else { |
||||||
|
glMatrixMode(GL_MODELVIEW); |
||||||
|
glTranslatef(200,250,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; |
||||||
|
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 'v': case 'V': |
||||||
|
show_tex = !show_tex; |
||||||
|
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
|
||||||
|
} |
||||||
|
|
@ -0,0 +1,97 @@ |
|||||||
|
# Microsoft Developer Studio Project File - Name="oversample" - Package Owner=<4> |
||||||
|
# Microsoft Developer Studio Generated Build File, Format Version 6.00 |
||||||
|
# ** DO NOT EDIT ** |
||||||
|
|
||||||
|
# TARGTYPE "Win32 (x86) Application" 0x0101 |
||||||
|
|
||||||
|
CFG=oversample - Win32 Debug |
||||||
|
!MESSAGE This is not a valid makefile. To build this project using NMAKE, |
||||||
|
!MESSAGE use the Export Makefile command and run |
||||||
|
!MESSAGE |
||||||
|
!MESSAGE NMAKE /f "oversample.mak". |
||||||
|
!MESSAGE |
||||||
|
!MESSAGE You can specify a configuration when running NMAKE |
||||||
|
!MESSAGE by defining the macro CFG on the command line. For example: |
||||||
|
!MESSAGE |
||||||
|
!MESSAGE NMAKE /f "oversample.mak" CFG="oversample - Win32 Debug" |
||||||
|
!MESSAGE |
||||||
|
!MESSAGE Possible choices for configuration are: |
||||||
|
!MESSAGE |
||||||
|
!MESSAGE "oversample - Win32 Release" (based on "Win32 (x86) Application") |
||||||
|
!MESSAGE "oversample - Win32 Debug" (based on "Win32 (x86) Application") |
||||||
|
!MESSAGE |
||||||
|
|
||||||
|
# Begin Project |
||||||
|
# PROP AllowPerConfigDependencies 0 |
||||||
|
# PROP Scc_ProjName "" |
||||||
|
# PROP Scc_LocalPath "" |
||||||
|
CPP=cl.exe |
||||||
|
MTL=midl.exe |
||||||
|
RSC=rc.exe |
||||||
|
|
||||||
|
!IF "$(CFG)" == "oversample - Win32 Release" |
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0 |
||||||
|
# PROP BASE Use_Debug_Libraries 0 |
||||||
|
# PROP BASE Output_Dir "Release" |
||||||
|
# PROP BASE Intermediate_Dir "Release" |
||||||
|
# PROP BASE Target_Dir "" |
||||||
|
# PROP Use_MFC 0 |
||||||
|
# PROP Use_Debug_Libraries 0 |
||||||
|
# PROP Output_Dir "Release" |
||||||
|
# PROP Intermediate_Dir "Release" |
||||||
|
# PROP Ignore_Export_Lib 0 |
||||||
|
# PROP Target_Dir "" |
||||||
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c |
||||||
|
# ADD CPP /nologo /W3 /WX /GX /O2 /I "c:\sean\prj\stb" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c |
||||||
|
# SUBTRACT CPP /YX |
||||||
|
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 |
||||||
|
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 |
||||||
|
# ADD BASE RSC /l 0x409 /d "NDEBUG" |
||||||
|
# ADD RSC /l 0x409 /d "NDEBUG" |
||||||
|
BSC32=bscmake.exe |
||||||
|
# ADD BASE BSC32 /nologo |
||||||
|
# ADD BSC32 /nologo |
||||||
|
LINK32=link.exe |
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 |
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 |
||||||
|
# SUBTRACT LINK32 /map /debug |
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "oversample - Win32 Debug" |
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0 |
||||||
|
# PROP BASE Use_Debug_Libraries 1 |
||||||
|
# PROP BASE Output_Dir "Debug" |
||||||
|
# PROP BASE Intermediate_Dir "Debug" |
||||||
|
# PROP BASE Target_Dir "" |
||||||
|
# PROP Use_MFC 0 |
||||||
|
# PROP Use_Debug_Libraries 1 |
||||||
|
# PROP Output_Dir "Debug" |
||||||
|
# PROP Intermediate_Dir "Debug" |
||||||
|
# PROP Ignore_Export_Lib 0 |
||||||
|
# PROP Target_Dir "" |
||||||
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c |
||||||
|
# ADD CPP /nologo /W3 /WX /Gm /GX /Zi /Od /I "c:\sean\prj\stb" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c |
||||||
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 |
||||||
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 |
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG" |
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG" |
||||||
|
BSC32=bscmake.exe |
||||||
|
# ADD BASE BSC32 /nologo |
||||||
|
# ADD BSC32 /nologo |
||||||
|
LINK32=link.exe |
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept |
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib advapi32.lib winspool.lib comdlg32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:no /debug /machine:I386 /pdbtype:sept |
||||||
|
|
||||||
|
!ENDIF |
||||||
|
|
||||||
|
# Begin Target |
||||||
|
|
||||||
|
# Name "oversample - Win32 Release" |
||||||
|
# Name "oversample - Win32 Debug" |
||||||
|
# Begin Source File |
||||||
|
|
||||||
|
SOURCE=.\main.c |
||||||
|
# End Source File |
||||||
|
# End Target |
||||||
|
# End Project |
@ -0,0 +1,29 @@ |
|||||||
|
Microsoft Developer Studio Workspace File, Format Version 6.00 |
||||||
|
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! |
||||||
|
|
||||||
|
############################################################################### |
||||||
|
|
||||||
|
Project: "oversample"=.\oversample.dsp - Package Owner=<4> |
||||||
|
|
||||||
|
Package=<5> |
||||||
|
{{{ |
||||||
|
}}} |
||||||
|
|
||||||
|
Package=<4> |
||||||
|
{{{ |
||||||
|
}}} |
||||||
|
|
||||||
|
############################################################################### |
||||||
|
|
||||||
|
Global: |
||||||
|
|
||||||
|
Package=<5> |
||||||
|
{{{ |
||||||
|
}}} |
||||||
|
|
||||||
|
Package=<3> |
||||||
|
{{{ |
||||||
|
}}} |
||||||
|
|
||||||
|
############################################################################### |
||||||
|
|
@ -0,0 +1,824 @@ |
|||||||
|
// stb_wingraph.h v0.01 - public domain windows graphics programming
|
||||||
|
// wraps WinMain, ChoosePixelFormat, ChangeDisplayResolution, etc. for
|
||||||
|
// doing OpenGL graphics
|
||||||
|
//
|
||||||
|
// in ONE source file, put '#define STB_DEFINE' before including this
|
||||||
|
// OR put '#define STB_WINMAIN' to define a WinMain that calls stbwingraph_main(void)
|
||||||
|
//
|
||||||
|
// @TODO:
|
||||||
|
// 2d rendering interface (that can be done easily in software)
|
||||||
|
// STB_WINGRAPH_SOFTWARE -- 2d software rendering only
|
||||||
|
// STB_WINGRAPH_OPENGL -- OpenGL only
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef INCLUDE_STB_WINGRAPH_H |
||||||
|
#define INCLUDE_STB_WINGRAPH_H |
||||||
|
|
||||||
|
#ifdef STB_WINMAIN |
||||||
|
#ifndef STB_DEFINE |
||||||
|
#define STB_DEFINE |
||||||
|
#define STB_WINGRAPH_DISABLE_DEFINE_AT_END |
||||||
|
#endif |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef STB_DEFINE |
||||||
|
#pragma comment(lib, "opengl32.lib") |
||||||
|
#pragma comment(lib, "glu32.lib") |
||||||
|
#pragma comment(lib, "winmm.lib") |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
#define STB_EXTERN extern "C" |
||||||
|
#else |
||||||
|
#define STB_EXTERN |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef STB_DEFINE |
||||||
|
#ifndef _WINDOWS_ |
||||||
|
#ifdef APIENTRY |
||||||
|
#undef APIENTRY |
||||||
|
#endif |
||||||
|
#ifdef WINGDIAPI |
||||||
|
#undef WINGDIAPI |
||||||
|
#endif |
||||||
|
#define _WIN32_WINNT 0x0400 // WM_MOUSEWHEEL
|
||||||
|
#include <windows.h> |
||||||
|
#endif |
||||||
|
#include <stdio.h> |
||||||
|
#include <math.h> |
||||||
|
#include <time.h> |
||||||
|
#include <string.h> |
||||||
|
#include <assert.h> |
||||||
|
#endif |
||||||
|
|
||||||
|
typedef void * stbwingraph_hwnd; |
||||||
|
typedef void * stbwingraph_hinstance; |
||||||
|
|
||||||
|
enum |
||||||
|
{ |
||||||
|
STBWINGRAPH_unprocessed = -(1 << 24), |
||||||
|
STBWINGRAPH_do_not_show, |
||||||
|
STBWINGRAPH_winproc_exit, |
||||||
|
STBWINGRAPH_winproc_update, |
||||||
|
STBWINGRAPH_update_exit, |
||||||
|
STBWINGRAPH_update_pause, |
||||||
|
}; |
||||||
|
|
||||||
|
typedef enum |
||||||
|
{ |
||||||
|
STBWGE__none=0, |
||||||
|
|
||||||
|
STBWGE_create, |
||||||
|
STBWGE_create_postshow, |
||||||
|
STBWGE_draw, |
||||||
|
STBWGE_destroy, |
||||||
|
STBWGE_char, |
||||||
|
STBWGE_keydown, |
||||||
|
STBWGE_syskeydown, |
||||||
|
STBWGE_keyup, |
||||||
|
STBWGE_syskeyup, |
||||||
|
STBWGE_deactivate, |
||||||
|
STBWGE_activate, |
||||||
|
STBWGE_size, |
||||||
|
|
||||||
|
STBWGE_mousemove , |
||||||
|
STBWGE_leftdown , STBWGE_leftup , |
||||||
|
STBWGE_middledown, STBWGE_middleup, |
||||||
|
STBWGE_rightdown , STBWGE_rightup , |
||||||
|
STBWGE_mousewheel, |
||||||
|
} stbwingraph_event_type; |
||||||
|
|
||||||
|
typedef struct |
||||||
|
{ |
||||||
|
stbwingraph_event_type type; |
||||||
|
|
||||||
|
// for input events (mouse, keyboard)
|
||||||
|
int mx,my; // mouse x & y
|
||||||
|
int dx,dy; |
||||||
|
int shift, ctrl, alt; |
||||||
|
|
||||||
|
// for keyboard events
|
||||||
|
int key; |
||||||
|
|
||||||
|
// for STBWGE_size:
|
||||||
|
int width, height; |
||||||
|
|
||||||
|
// for STBWGE_crate
|
||||||
|
int did_share_lists; // if true, wglShareLists succeeded
|
||||||
|
|
||||||
|
void *handle; |
||||||
|
|
||||||
|
} stbwingraph_event; |
||||||
|
|
||||||
|
typedef int (*stbwingraph_window_proc)(void *data, stbwingraph_event *event); |
||||||
|
|
||||||
|
extern stbwingraph_hinstance stbwingraph_app; |
||||||
|
extern stbwingraph_hwnd stbwingraph_primary_window; |
||||||
|
extern int stbwingraph_request_fullscreen; |
||||||
|
extern int stbwingraph_request_windowed; |
||||||
|
|
||||||
|
STB_EXTERN void stbwingraph_ods(char *str, ...); |
||||||
|
STB_EXTERN int stbwingraph_MessageBox(stbwingraph_hwnd win, unsigned int type, |
||||||
|
char *caption, char *text, ...); |
||||||
|
STB_EXTERN int stbwingraph_ChangeResolution(unsigned int w, unsigned int h, |
||||||
|
unsigned int bits, int use_message_box); |
||||||
|
STB_EXTERN int stbwingraph_SetPixelFormat(stbwingraph_hwnd win, int color_bits, |
||||||
|
int alpha_bits, int depth_bits, int stencil_bits, int accum_bits); |
||||||
|
STB_EXTERN int stbwingraph_DefineClass(void *hinstance, char *iconname); |
||||||
|
STB_EXTERN void stbwingraph_SwapBuffers(void *win); |
||||||
|
STB_EXTERN void stbwingraph_Priority(int n); |
||||||
|
|
||||||
|
STB_EXTERN void stbwingraph_MakeFonts(void *window, int font_base); |
||||||
|
STB_EXTERN void stbwingraph_ShowWindow(void *window); |
||||||
|
STB_EXTERN void *stbwingraph_CreateWindow(int primary, stbwingraph_window_proc func, void *data, char *text, int width, int height, int fullscreen, int resizeable, int dest_alpha, int stencil); |
||||||
|
STB_EXTERN void *stbwingraph_CreateWindowSimple(stbwingraph_window_proc func, int width, int height); |
||||||
|
STB_EXTERN void *stbwingraph_CreateWindowSimpleFull(stbwingraph_window_proc func, int fullscreen, int ww, int wh, int fw, int fh); |
||||||
|
STB_EXTERN void stbwingraph_DestroyWindow(void *window); |
||||||
|
STB_EXTERN void stbwingraph_ShowCursor(void *window, int visible); |
||||||
|
STB_EXTERN float stbwingraph_GetTimestep(float minimum_time); |
||||||
|
STB_EXTERN void stbwingraph_SetGLWindow(void *win); |
||||||
|
typedef int (*stbwingraph_update)(float timestep, int real, int in_client); |
||||||
|
STB_EXTERN int stbwingraph_MainLoop(stbwingraph_update func, float mintime); |
||||||
|
|
||||||
|
#ifdef STB_DEFINE |
||||||
|
stbwingraph_hinstance stbwingraph_app; |
||||||
|
stbwingraph_hwnd stbwingraph_primary_window; |
||||||
|
int stbwingraph_request_fullscreen; |
||||||
|
int stbwingraph_request_windowed; |
||||||
|
|
||||||
|
void stbwingraph_ods(char *str, ...) |
||||||
|
{ |
||||||
|
char buffer[1024]; |
||||||
|
va_list v; |
||||||
|
va_start(v,str); |
||||||
|
vsprintf(buffer, str, v); |
||||||
|
va_end(v); |
||||||
|
OutputDebugString(buffer); |
||||||
|
} |
||||||
|
|
||||||
|
int stbwingraph_MessageBox(stbwingraph_hwnd win, unsigned int type, char *caption, char *text, ...) |
||||||
|
{ |
||||||
|
va_list v; |
||||||
|
char buffer[1024]; |
||||||
|
va_start(v, text); |
||||||
|
vsprintf(buffer, text, v); |
||||||
|
va_end(v); |
||||||
|
return MessageBox(win, buffer, caption, type); |
||||||
|
} |
||||||
|
|
||||||
|
void stbwingraph_Priority(int n) |
||||||
|
{ |
||||||
|
int p; |
||||||
|
switch (n) { |
||||||
|
case -1: p = THREAD_PRIORITY_BELOW_NORMAL; break; |
||||||
|
case 0: p = THREAD_PRIORITY_NORMAL; break; |
||||||
|
case 1: p = THREAD_PRIORITY_ABOVE_NORMAL; break; |
||||||
|
default: |
||||||
|
if (n < 0) p = THREAD_PRIORITY_LOWEST; |
||||||
|
else p = THREAD_PRIORITY_HIGHEST; |
||||||
|
} |
||||||
|
SetThreadPriority(GetCurrentThread(), p); |
||||||
|
} |
||||||
|
|
||||||
|
static void stbwingraph_ResetResolution(void) |
||||||
|
{ |
||||||
|
ChangeDisplaySettings(NULL, 0); |
||||||
|
} |
||||||
|
|
||||||
|
static void stbwingraph_RegisterResetResolution(void) |
||||||
|
{ |
||||||
|
static int done=0; |
||||||
|
if (!done) { |
||||||
|
done = 1; |
||||||
|
atexit(stbwingraph_ResetResolution); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int stbwingraph_ChangeResolution(unsigned int w, unsigned int h, unsigned int bits, int use_message_box) |
||||||
|
{ |
||||||
|
DEVMODE mode; |
||||||
|
int res; |
||||||
|
|
||||||
|
int i, tries=0; |
||||||
|
for (i=0; ; ++i) { |
||||||
|
int success = EnumDisplaySettings(NULL, i, &mode); |
||||||
|
if (!success) break; |
||||||
|
if (mode.dmBitsPerPel == bits && mode.dmPelsWidth == w && mode.dmPelsHeight == h) { |
||||||
|
++tries; |
||||||
|
success = ChangeDisplaySettings(&mode, CDS_FULLSCREEN);
|
||||||
|
if (success == DISP_CHANGE_SUCCESSFUL) { |
||||||
|
stbwingraph_RegisterResetResolution(); |
||||||
|
return TRUE; |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!tries) { |
||||||
|
if (use_message_box) |
||||||
|
stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "The resolution %d x %d x %d-bits is not supported.", w, h, bits); |
||||||
|
return FALSE; |
||||||
|
} |
||||||
|
|
||||||
|
// we tried but failed, so try explicitly doing it without specifying refresh rate
|
||||||
|
|
||||||
|
// Win95 support logic
|
||||||
|
mode.dmBitsPerPel = bits;
|
||||||
|
mode.dmPelsWidth = w;
|
||||||
|
mode.dmPelsHeight = h;
|
||||||
|
mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
|
||||||
|
|
||||||
|
res = ChangeDisplaySettings(&mode, CDS_FULLSCREEN); |
||||||
|
|
||||||
|
switch (res) { |
||||||
|
case DISP_CHANGE_SUCCESSFUL: |
||||||
|
stbwingraph_RegisterResetResolution(); |
||||||
|
return TRUE; |
||||||
|
|
||||||
|
case DISP_CHANGE_RESTART: |
||||||
|
if (use_message_box) |
||||||
|
stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "Please set your desktop to %d-bit color and then try again."); |
||||||
|
return FALSE; |
||||||
|
|
||||||
|
case DISP_CHANGE_FAILED: |
||||||
|
if (use_message_box) |
||||||
|
stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "The hardware failed to change modes."); |
||||||
|
return FALSE; |
||||||
|
|
||||||
|
case DISP_CHANGE_BADMODE: |
||||||
|
if (use_message_box) |
||||||
|
stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "The resolution %d x %d x %d-bits is not supported.", w, h, bits); |
||||||
|
return FALSE; |
||||||
|
|
||||||
|
default: |
||||||
|
if (use_message_box) |
||||||
|
stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "An unknown error prevented a change to a %d x %d x %d-bit display.", w, h, bits); |
||||||
|
return FALSE; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int stbwingraph_SetPixelFormat(stbwingraph_hwnd win, int color_bits, int alpha_bits, int depth_bits, int stencil_bits, int accum_bits) |
||||||
|
{ |
||||||
|
HDC dc = GetDC(win); |
||||||
|
PIXELFORMATDESCRIPTOR pfd = { sizeof(pfd) }; |
||||||
|
int pixel_format; |
||||||
|
|
||||||
|
pfd.nVersion = 1; |
||||||
|
pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER; |
||||||
|
pfd.dwLayerMask = PFD_MAIN_PLANE; |
||||||
|
pfd.iPixelType = PFD_TYPE_RGBA; |
||||||
|
pfd.cColorBits = color_bits; |
||||||
|
pfd.cAlphaBits = alpha_bits; |
||||||
|
pfd.cDepthBits = depth_bits; |
||||||
|
pfd.cStencilBits = stencil_bits; |
||||||
|
pfd.cAccumBits = accum_bits; |
||||||
|
|
||||||
|
pixel_format = ChoosePixelFormat(dc, &pfd); |
||||||
|
if (!pixel_format) return FALSE; |
||||||
|
|
||||||
|
if (!DescribePixelFormat(dc, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) |
||||||
|
return FALSE; |
||||||
|
SetPixelFormat(dc, pixel_format, &pfd); |
||||||
|
|
||||||
|
return TRUE; |
||||||
|
} |
||||||
|
|
||||||
|
typedef struct |
||||||
|
{ |
||||||
|
// app data
|
||||||
|
stbwingraph_window_proc func; |
||||||
|
void *data; |
||||||
|
// creation parameters
|
||||||
|
int color, alpha, depth, stencil, accum; |
||||||
|
HWND share_window; |
||||||
|
HWND window; |
||||||
|
// internal data
|
||||||
|
HGLRC rc; |
||||||
|
HDC dc; |
||||||
|
int hide_mouse; |
||||||
|
int in_client; |
||||||
|
int active; |
||||||
|
int did_share_lists; |
||||||
|
int mx,my; // last mouse positions
|
||||||
|
} stbwingraph__window; |
||||||
|
|
||||||
|
static void stbwingraph__inclient(stbwingraph__window *win, int state) |
||||||
|
{ |
||||||
|
if (state != win->in_client) { |
||||||
|
win->in_client = state; |
||||||
|
if (win->hide_mouse) |
||||||
|
ShowCursor(!state); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void stbwingraph__key(stbwingraph_event *e, int type, int key, stbwingraph__window *z) |
||||||
|
{ |
||||||
|
e->type = type; |
||||||
|
e->key = key; |
||||||
|
e->shift = (GetKeyState(VK_SHIFT) < 0); |
||||||
|
e->ctrl = (GetKeyState(VK_CONTROL) < 0); |
||||||
|
e->alt = (GetKeyState(VK_MENU) < 0); |
||||||
|
if (z) { |
||||||
|
e->mx = z->mx; |
||||||
|
e->my = z->my; |
||||||
|
} else { |
||||||
|
e->mx = e->my = 0; |
||||||
|
} |
||||||
|
e->dx = e->dy = 0; |
||||||
|
} |
||||||
|
|
||||||
|
static void stbwingraph__mouse(stbwingraph_event *e, int type, WPARAM wparam, LPARAM lparam, int capture, void *wnd, stbwingraph__window *z) |
||||||
|
{ |
||||||
|
static int captured = 0; |
||||||
|
e->type = type; |
||||||
|
e->mx = (short) LOWORD(lparam); |
||||||
|
e->my = (short) HIWORD(lparam); |
||||||
|
if (!z || z->mx == -(1 << 30)) { |
||||||
|
e->dx = e->dy = 0; |
||||||
|
} else { |
||||||
|
e->dx = e->mx - z->mx; |
||||||
|
e->dy = e->my - z->my; |
||||||
|
} |
||||||
|
e->shift = (wparam & MK_SHIFT) != 0; |
||||||
|
e->ctrl = (wparam & MK_CONTROL) != 0; |
||||||
|
e->alt = (wparam & MK_ALT) != 0; |
||||||
|
if (z) { |
||||||
|
z->mx = e->mx; |
||||||
|
z->my = e->my; |
||||||
|
} |
||||||
|
if (capture) { |
||||||
|
if (!captured && capture == 1) |
||||||
|
SetCapture(wnd); |
||||||
|
captured += capture; |
||||||
|
if (!captured && capture == -1) |
||||||
|
ReleaseCapture(); |
||||||
|
if (captured < 0) captured = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void stbwingraph__mousewheel(stbwingraph_event *e, int type, WPARAM wparam, LPARAM lparam, int capture, void *wnd, stbwingraph__window *z) |
||||||
|
{ |
||||||
|
// lparam seems bogus!
|
||||||
|
static int captured = 0; |
||||||
|
e->type = type; |
||||||
|
if (z) { |
||||||
|
e->mx = z->mx; |
||||||
|
e->my = z->my; |
||||||
|
} |
||||||
|
e->dx = e->dy = 0; |
||||||
|
e->shift = (wparam & MK_SHIFT) != 0; |
||||||
|
e->ctrl = (wparam & MK_CONTROL) != 0; |
||||||
|
e->alt = (GetKeyState(VK_MENU) < 0); |
||||||
|
e->key = ((int) wparam >> 16); |
||||||
|
} |
||||||
|
|
||||||
|
int stbwingraph_force_update; |
||||||
|
static int WINAPI stbwingraph_WinProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) |
||||||
|
{ |
||||||
|
int allow_default = TRUE; |
||||||
|
stbwingraph_event e = { STBWGE__none }; |
||||||
|
// the following line is wrong for 64-bit windows, but VC6 doesn't have GetWindowLongPtr
|
||||||
|
stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(wnd, GWL_USERDATA); |
||||||
|
|
||||||
|
switch (msg) { |
||||||
|
|
||||||
|
case WM_CREATE: |
||||||
|
{ |
||||||
|
LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lparam; |
||||||
|
assert(z == NULL); |
||||||
|
z = (stbwingraph__window *) lpcs->lpCreateParams; |
||||||
|
SetWindowLong(wnd, GWL_USERDATA, (LONG) z); |
||||||
|
z->dc = GetDC(wnd); |
||||||
|
if (stbwingraph_SetPixelFormat(wnd, z->color, z->alpha, z->depth, z->stencil, z->accum)) { |
||||||
|
z->rc = wglCreateContext(z->dc); |
||||||
|
if (z->rc) { |
||||||
|
e.type = STBWGE_create; |
||||||
|
z->did_share_lists = FALSE; |
||||||
|
if (z->share_window) { |
||||||
|
stbwingraph__window *y = (stbwingraph__window *) GetWindowLong(z->share_window, GWL_USERDATA); |
||||||
|
if (wglShareLists(z->rc, y->rc)) |
||||||
|
z->did_share_lists = TRUE; |
||||||
|
} |
||||||
|
wglMakeCurrent(z->dc, z->rc); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
case WM_PAINT: { |
||||||
|
PAINTSTRUCT ps; |
||||||
|
HDC hdc = BeginPaint(wnd, &ps); |
||||||
|
SelectObject(hdc, GetStockObject(NULL_BRUSH)); |
||||||
|
e.type = STBWGE_draw; |
||||||
|
e.handle = wnd; |
||||||
|
z->func(z->data, &e); |
||||||
|
EndPaint(wnd, &ps); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
case WM_DESTROY: |
||||||
|
e.type = STBWGE_destroy; |
||||||
|
e.handle = wnd; |
||||||
|
if (z && z->func) |
||||||
|
z->func(z->data, &e); |
||||||
|
wglMakeCurrent(NULL, NULL) ;
|
||||||
|
if (z) { |
||||||
|
if (z->rc) wglDeleteContext(z->rc); |
||||||
|
z->dc = 0; |
||||||
|
z->rc = 0; |
||||||
|
} |
||||||
|
if (wnd == stbwingraph_primary_window) |
||||||
|
PostQuitMessage (0); |
||||||
|
return 0; |
||||||
|
|
||||||
|
case WM_CHAR: stbwingraph__key(&e, STBWGE_char , wparam, z); break; |
||||||
|
case WM_KEYDOWN: stbwingraph__key(&e, STBWGE_keydown, wparam, z); break; |
||||||
|
case WM_KEYUP: stbwingraph__key(&e, STBWGE_keyup , wparam, z); break; |
||||||
|
|
||||||
|
case WM_NCMOUSEMOVE: stbwingraph__inclient(z,0); break; |
||||||
|
case WM_MOUSEMOVE: stbwingraph__inclient(z,1); stbwingraph__mouse(&e, STBWGE_mousemove, wparam, lparam,0,wnd, z); break; |
||||||
|
case WM_LBUTTONDOWN: stbwingraph__mouse(&e, STBWGE_leftdown, wparam, lparam,1,wnd, z); break; |
||||||
|
case WM_MBUTTONDOWN: stbwingraph__mouse(&e, STBWGE_middledown, wparam, lparam,1,wnd, z); break; |
||||||
|
case WM_RBUTTONDOWN: stbwingraph__mouse(&e, STBWGE_rightdown, wparam, lparam,1,wnd, z); break; |
||||||
|
case WM_LBUTTONUP: stbwingraph__mouse(&e, STBWGE_leftup, wparam, lparam,-1,wnd, z); break; |
||||||
|
case WM_MBUTTONUP: stbwingraph__mouse(&e, STBWGE_middleup, wparam, lparam,-1,wnd, z); break; |
||||||
|
case WM_RBUTTONUP: stbwingraph__mouse(&e, STBWGE_rightup, wparam, lparam,-1,wnd, z); break; |
||||||
|
case WM_MOUSEWHEEL: stbwingraph__mousewheel(&e, STBWGE_mousewheel, wparam, lparam,0,wnd, z); break; |
||||||
|
|
||||||
|
case WM_ACTIVATE: |
||||||
|
allow_default = FALSE; |
||||||
|
if (LOWORD(wparam)==WA_INACTIVE ) { |
||||||
|
wglMakeCurrent(z->dc, NULL); |
||||||
|
e.type = STBWGE_deactivate; |
||||||
|
z->active = FALSE; |
||||||
|
} else { |
||||||
|
wglMakeCurrent(z->dc, z->rc); |
||||||
|
e.type = STBWGE_activate; |
||||||
|
z->active = TRUE; |
||||||
|
} |
||||||
|
e.handle = wnd; |
||||||
|
z->func(z->data, &e); |
||||||
|
return 0; |
||||||
|
|
||||||
|
case WM_SIZE: { |
||||||
|
RECT rect; |
||||||
|
allow_default = FALSE; |
||||||
|
GetClientRect(wnd, &rect); |
||||||
|
e.type = STBWGE_size; |
||||||
|
e.width = rect.right; |
||||||
|
e.height = rect.bottom; |
||||||
|
e.handle = wnd; |
||||||
|
z->func(z->data, &e); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
default: |
||||||
|
return DefWindowProc (wnd, msg, wparam, lparam); |
||||||
|
} |
||||||
|
|
||||||
|
if (e.type != STBWGE__none) { |
||||||
|
int n; |
||||||
|
e.handle = wnd; |
||||||
|
n = z->func(z->data, &e); |
||||||
|
if (n == STBWINGRAPH_winproc_exit) { |
||||||
|
PostQuitMessage(0); |
||||||
|
n = 0; |
||||||
|
} |
||||||
|
if (n == STBWINGRAPH_winproc_update) { |
||||||
|
stbwingraph_force_update = TRUE; |
||||||
|
return 1; |
||||||
|
} |
||||||
|
if (n != STBWINGRAPH_unprocessed) |
||||||
|
return n; |
||||||
|
} |
||||||
|
return DefWindowProc (wnd, msg, wparam, lparam); |
||||||
|
} |
||||||
|
|
||||||
|
int stbwingraph_DefineClass(HINSTANCE hInstance, char *iconname) |
||||||
|
{ |
||||||
|
WNDCLASSEX wndclass; |
||||||
|
|
||||||
|
stbwingraph_app = hInstance; |
||||||
|
|
||||||
|
wndclass.cbSize = sizeof(wndclass); |
||||||
|
wndclass.style = CS_OWNDC; |
||||||
|
wndclass.lpfnWndProc = (WNDPROC) stbwingraph_WinProc; |
||||||
|
wndclass.cbClsExtra = 0; |
||||||
|
wndclass.cbWndExtra = 0; |
||||||
|
wndclass.hInstance = hInstance; |
||||||
|
wndclass.hIcon = LoadIcon(hInstance, iconname); |
||||||
|
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW); |
||||||
|
wndclass.hbrBackground = GetStockObject(NULL_BRUSH); |
||||||
|
wndclass.lpszMenuName = "zwingraph"; |
||||||
|
wndclass.lpszClassName = "zwingraph"; |
||||||
|
wndclass.hIconSm = NULL; |
||||||
|
|
||||||
|
if (!RegisterClassEx(&wndclass)) |
||||||
|
return FALSE; |
||||||
|
return TRUE; |
||||||
|
} |
||||||
|
|
||||||
|
void stbwingraph_ShowWindow(void *window) |
||||||
|
{ |
||||||
|
stbwingraph_event e = { STBWGE_create_postshow }; |
||||||
|
stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(window, GWL_USERDATA); |
||||||
|
ShowWindow(window, SW_SHOWNORMAL); |
||||||
|
InvalidateRect(window, NULL, TRUE); |
||||||
|
UpdateWindow(window); |
||||||
|
e.handle = window; |
||||||
|
z->func(z->data, &e); |
||||||
|
} |
||||||
|
|
||||||
|
void *stbwingraph_CreateWindow(int primary, stbwingraph_window_proc func, void *data, char *text, |
||||||
|
int width, int height, int fullscreen, int resizeable, int dest_alpha, int stencil) |
||||||
|
{ |
||||||
|
HWND win; |
||||||
|
DWORD dwstyle; |
||||||
|
stbwingraph__window *z = (stbwingraph__window *) malloc(sizeof(*z)); |
||||||
|
|
||||||
|
if (z == NULL) return NULL; |
||||||
|
memset(z, 0, sizeof(*z)); |
||||||
|
z->color = 24; |
||||||
|
z->depth = 24; |
||||||
|
z->alpha = dest_alpha; |
||||||
|
z->stencil = stencil; |
||||||
|
z->func = func; |
||||||
|
z->data = data; |
||||||
|
z->mx = -(1 << 30); |
||||||
|
z->my = 0; |
||||||
|
|
||||||
|
if (primary) { |
||||||
|
if (stbwingraph_request_windowed) |
||||||
|
fullscreen = FALSE; |
||||||
|
else if (stbwingraph_request_fullscreen) |
||||||
|
fullscreen = TRUE; |
||||||
|
} |
||||||
|
|
||||||
|
if (fullscreen) { |
||||||
|
#ifdef STB_SIMPLE |
||||||
|
stbwingraph_ChangeResolution(width, height, 32, 1); |
||||||
|
#else |
||||||
|
if (!stbwingraph_ChangeResolution(width, height, 32, 0)) |
||||||
|
return NULL; |
||||||
|
#endif |
||||||
|
dwstyle = WS_POPUP | WS_CLIPSIBLINGS; |
||||||
|
} else { |
||||||
|
RECT rect; |
||||||
|
dwstyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; |
||||||
|
if (resizeable) |
||||||
|
dwstyle |= WS_SIZEBOX | WS_MAXIMIZEBOX; |
||||||
|
rect.top = 0; |
||||||
|
rect.left = 0; |
||||||
|
rect.right = width; |
||||||
|
rect.bottom = height; |
||||||
|
AdjustWindowRect(&rect, dwstyle, FALSE); |
||||||
|
width = rect.right - rect.left; |
||||||
|
height = rect.bottom - rect.top; |
||||||
|
} |
||||||
|
|
||||||
|
win = CreateWindow("zwingraph", text ? text : "sample", dwstyle, |
||||||
|
CW_USEDEFAULT,0, width, height, |
||||||
|
NULL, NULL, stbwingraph_app, z); |
||||||
|
|
||||||
|
if (win == NULL) return win; |
||||||
|
|
||||||
|
if (primary) { |
||||||
|
if (stbwingraph_primary_window) |
||||||
|
stbwingraph_DestroyWindow(stbwingraph_primary_window); |
||||||
|
stbwingraph_primary_window = win; |
||||||
|
} |
||||||
|
|
||||||
|
{ |
||||||
|
stbwingraph_event e = { STBWGE_create }; |
||||||
|
stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(win, GWL_USERDATA); |
||||||
|
z->window = win; |
||||||
|
e.did_share_lists = z->did_share_lists; |
||||||
|
e.handle = win; |
||||||
|
if (z->func(z->data, &e) != STBWINGRAPH_do_not_show) |
||||||
|
stbwingraph_ShowWindow(win); |
||||||
|
} |
||||||
|
|
||||||
|
return win; |
||||||
|
} |
||||||
|
|
||||||
|
void *stbwingraph_CreateWindowSimple(stbwingraph_window_proc func, int width, int height) |
||||||
|
{ |
||||||
|
int fullscreen = 0; |
||||||
|
#ifndef _DEBUG |
||||||
|
if (width == 640 && height == 480) fullscreen = 1; |
||||||
|
if (width == 800 && height == 600) fullscreen = 1; |
||||||
|
if (width == 1024 && height == 768) fullscreen = 1; |
||||||
|
if (width == 1280 && height == 1024) fullscreen = 1; |
||||||
|
if (width == 1600 && height == 1200) fullscreen = 1; |
||||||
|
//@TODO: widescreen widths
|
||||||
|
#endif |
||||||
|
return stbwingraph_CreateWindow(1, func, NULL, NULL, width, height, fullscreen, 1, 0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
void *stbwingraph_CreateWindowSimpleFull(stbwingraph_window_proc func, int fullscreen, int ww, int wh, int fw, int fh) |
||||||
|
{ |
||||||
|
if (fullscreen == -1) { |
||||||
|
#ifdef _DEBUG |
||||||
|
fullscreen = 0; |
||||||
|
#else |
||||||
|
fullscreen = 1; |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
if (fullscreen) { |
||||||
|
if (fw) ww = fw; |
||||||
|
if (fh) wh = fh; |
||||||
|
} |
||||||
|
return stbwingraph_CreateWindow(1, func, NULL, NULL, ww, wh, fullscreen, 1, 0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
void stbwingraph_DestroyWindow(void *window) |
||||||
|
{ |
||||||
|
stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(window, GWL_USERDATA); |
||||||
|
DestroyWindow(window); |
||||||
|
free(z); |
||||||
|
if (stbwingraph_primary_window == window) |
||||||
|
stbwingraph_primary_window = NULL; |
||||||
|
} |
||||||
|
|
||||||
|
void stbwingraph_ShowCursor(void *window, int visible) |
||||||
|
{ |
||||||
|
int hide; |
||||||
|
stbwingraph__window *win; |
||||||
|
if (!window) |
||||||
|
window = stbwingraph_primary_window; |
||||||
|
win = (stbwingraph__window *) GetWindowLong((HWND) window, GWL_USERDATA); |
||||||
|
hide = !visible; |
||||||
|
if (hide != win->hide_mouse) { |
||||||
|
win->hide_mouse = hide; |
||||||
|
if (!hide) |
||||||
|
ShowCursor(TRUE); |
||||||
|
else if (win->in_client) |
||||||
|
ShowCursor(FALSE); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
float stbwingraph_GetTimestep(float minimum_time) |
||||||
|
{ |
||||||
|
float elapsedTime; |
||||||
|
double thisTime; |
||||||
|
static double lastTime = -1; |
||||||
|
|
||||||
|
if (lastTime == -1) |
||||||
|
lastTime = timeGetTime() / 1000.0 - minimum_time; |
||||||
|
|
||||||
|
for(;;) { |
||||||
|
thisTime = timeGetTime() / 1000.0; |
||||||
|
elapsedTime = (float) (thisTime - lastTime); |
||||||
|
if (elapsedTime >= minimum_time) { |
||||||
|
lastTime = thisTime;
|
||||||
|
return elapsedTime; |
||||||
|
} |
||||||
|
#if 1 |
||||||
|
Sleep(2); |
||||||
|
#endif |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void stbwingraph_SetGLWindow(void *win) |
||||||
|
{ |
||||||
|
stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(win, GWL_USERDATA); |
||||||
|
if (z) |
||||||
|
wglMakeCurrent(z->dc, z->rc); |
||||||
|
} |
||||||
|
|
||||||
|
void stbwingraph_MakeFonts(void *window, int font_base) |
||||||
|
{ |
||||||
|
wglUseFontBitmaps(GetDC(window ? window : stbwingraph_primary_window), 0, 256, font_base); |
||||||
|
} |
||||||
|
|
||||||
|
// returns 1 if WM_QUIT, 0 if 'func' returned 0
|
||||||
|
int stbwingraph_MainLoop(stbwingraph_update func, float mintime) |
||||||
|
{ |
||||||
|
int needs_drawing = FALSE; |
||||||
|
MSG msg; |
||||||
|
|
||||||
|
int is_animating = TRUE; |
||||||
|
if (mintime <= 0) mintime = 0.01f; |
||||||
|
|
||||||
|
for(;;) { |
||||||
|
int n; |
||||||
|
|
||||||
|
is_animating = TRUE; |
||||||
|
// wait for a message if: (a) we're animating and there's already a message
|
||||||
|
// or (b) we're not animating
|
||||||
|
if (!is_animating || PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { |
||||||
|
stbwingraph_force_update = FALSE; |
||||||
|
if (GetMessage(&msg, NULL, 0, 0)) { |
||||||
|
TranslateMessage(&msg); |
||||||
|
DispatchMessage(&msg); |
||||||
|
} else { |
||||||
|
return 1; // WM_QUIT
|
||||||
|
} |
||||||
|
|
||||||
|
// only force a draw for certain messages...
|
||||||
|
// if I don't do this, we peg at 50% for some reason... must
|
||||||
|
// be a bug somewhere, because we peg at 100% when rendering...
|
||||||
|
// very weird... looks like NVIDIA is pumping some messages
|
||||||
|
// through our pipeline? well, ok, I guess if we can get
|
||||||
|
// non-user-generated messages we have to do this
|
||||||
|
if (!stbwingraph_force_update) { |
||||||
|
switch (msg.message) { |
||||||
|
case WM_MOUSEMOVE: |
||||||
|
case WM_NCMOUSEMOVE: |
||||||
|
break; |
||||||
|
case WM_CHAR:
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
case WM_KEYUP:
|
||||||
|
case WM_LBUTTONDOWN:
|
||||||
|
case WM_MBUTTONDOWN:
|
||||||
|
case WM_RBUTTONDOWN:
|
||||||
|
case WM_LBUTTONUP:
|
||||||
|
case WM_MBUTTONUP:
|
||||||
|
case WM_RBUTTONUP:
|
||||||
|
case WM_TIMER: |
||||||
|
case WM_SIZE: |
||||||
|
case WM_ACTIVATE: |
||||||
|
needs_drawing = TRUE; |
||||||
|
break; |
||||||
|
} |
||||||
|
} else |
||||||
|
needs_drawing = TRUE; |
||||||
|
} |
||||||
|
|
||||||
|
// if another message, process that first
|
||||||
|
// @TODO: i don't think this is working, because I can't key ahead
|
||||||
|
// in the SVT demo app
|
||||||
|
if (PeekMessage(&msg, NULL, 0,0, PM_NOREMOVE)) |
||||||
|
continue; |
||||||
|
|
||||||
|
// and now call update
|
||||||
|
if (needs_drawing || is_animating) { |
||||||
|
int real=1, in_client=1; |
||||||
|
if (stbwingraph_primary_window) { |
||||||
|
stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(stbwingraph_primary_window, GWL_USERDATA); |
||||||
|
if (z && !z->active) { |
||||||
|
real = 0; |
||||||
|
} |
||||||
|
if (z) |
||||||
|
in_client = z->in_client; |
||||||
|
} |
||||||
|
|
||||||
|
if (stbwingraph_primary_window) |
||||||
|
stbwingraph_SetGLWindow(stbwingraph_primary_window); |
||||||
|
n = func(stbwingraph_GetTimestep(mintime), real, in_client); |
||||||
|
if (n == STBWINGRAPH_update_exit) |
||||||
|
return 0; // update_quit
|
||||||
|
|
||||||
|
is_animating = (n != STBWINGRAPH_update_pause); |
||||||
|
|
||||||
|
needs_drawing = FALSE; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void stbwingraph_SwapBuffers(void *win) |
||||||
|
{ |
||||||
|
stbwingraph__window *z; |
||||||
|
if (win == NULL) win = stbwingraph_primary_window; |
||||||
|
z = (stbwingraph__window *) GetWindowLong(win, GWL_USERDATA); |
||||||
|
if (z && z->dc) |
||||||
|
SwapBuffers(z->dc); |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef STB_WINMAIN |
||||||
|
void stbwingraph_main(void); |
||||||
|
|
||||||
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) |
||||||
|
{ |
||||||
|
{ |
||||||
|
char buffer[1024]; |
||||||
|
// add spaces to either side of the string
|
||||||
|
buffer[0] = ' '; |
||||||
|
strcpy(buffer+1, lpCmdLine); |
||||||
|
strcat(buffer, " "); |
||||||
|
if (strstr(buffer, " -reset ")) { |
||||||
|
ChangeDisplaySettings(NULL, 0);
|
||||||
|
exit(0); |
||||||
|
} |
||||||
|
if (strstr(buffer, " -window ") || strstr(buffer, " -windowed ")) |
||||||
|
stbwingraph_request_windowed = TRUE; |
||||||
|
else if (strstr(buffer, " -full ") || strstr(buffer, " -fullscreen ")) |
||||||
|
stbwingraph_request_fullscreen = TRUE; |
||||||
|
} |
||||||
|
|
||||||
|
stbwingraph_DefineClass(hInstance, "appicon"); |
||||||
|
stbwingraph_main(); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
#undef STB_EXTERN |
||||||
|
#ifdef STB_WINGRAPH_DISABLE_DEFINE_AT_END |
||||||
|
#undef STB_DEFINE |
||||||
|
#endif |
||||||
|
|
||||||
|
#endif // INCLUDE_STB_WINGRAPH_H
|
Loading…
Reference in New Issue