/* * System Interface Library for games * Copyright (c) 2007-2020 Andrew Church * Released under the GNU GPL version 3 or later; NO WARRANTY is provided. * See the file COPYING.txt for details. * * src/debug.c: Debugging interface and utility functions. */ #ifdef DEBUG // To the end of the file. #include "src/base.h" #include "src/debug.h" #include "src/graphics.h" #include "src/input.h" #include "src/math.h" #include "src/memory.h" #include "src/sysdep.h" #include "src/texture.h" #include "src/time.h" /*************************************************************************/ /**************************** Debug font data ****************************/ /*************************************************************************/ /* Pixel data for debug text font (Sapir Sans, public domain). */ #define DEBUGFONT_TEXWIDTH 128 #define DEBUGFONT_TEXHEIGHT 128 #define DEBUGFONT_PIXELS_SIZE (DEBUGFONT_TEXWIDTH*DEBUGFONT_TEXHEIGHT) static const uint8_t font_pixels[DEBUGFONT_PIXELS_SIZE] = { 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,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,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,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, 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,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,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,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, 0,0,0,0,0,0,0,0,0,0,0,0,6,54,29,31,0,0,0,0,0,0,0,0,0,0,0,0,1,14,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,11,54,0,0,0,0,0,10,0,0,4,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,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,255,101,0,0,0,74,246,163,156,0,0,0,0,116,49,104,65,0,0,0,29,155,255,152,30,0,0,10,153,210,144,5,0,15,162,12,0,0,0,0,17,135,169,132,13,0,0,0,0,0,0,88,224,0,0,0,0,98,221,0,0,169,155,4,0,0,0,0,0,169,33,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,2,235,0,0,0,40,156,167,84,0,0,0,0,29,128,170,0,0, 0,0,0,0,0,0,0,255,101,0,0,0,62,225,153,134,0,0,0,0,221,39,191,62,0,0,0,217,206,255,175,59,0,0,126,198,44,238,104,0,155,133,0,0,0,0,0,154,227,120,155,8,0,0,0,0,0,0,79,202,0,0,0,59,248,50,0,0,24,229,133,0,0,0,72,154,253,159,110,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,67,205,0,0,11,230,172,159,254,70,0,0,17,238,209,255,0,0, 0,0,0,0,0,0,0,255,101,0,0,0,25,197,118,106,0,0,48,170,252,173,246,181,0,0,0,249,196,255,0,0,0,0,169,156,0,182,145,65,216,6,0,0,0,0,0,142,242,24,49,170,170,170,57,0,0,0,55,175,0,0,0,210,149,0,0,0,0,96,252,38,0,0,46,193,255,212,37,0,0,0,0,0,56,123,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,149,123,0,0,107,245,7,0,201,187,0,0,0,8,113,255,0,0, 0,0,0,0,0,0,0,255,99,0,0,0,0,78,53,26,0,0,45,178,241,163,250,147,0,0,0,131,255,255,17,0,0,0,149,189,0,218,110,219,113,162,150,23,0,0,0,46,251,199,94,202,254,160,14,0,0,0,12,71,0,0,44,255,58,0,0,0,0,7,244,123,0,0,1,229,150,242,18,0,0,0,0,0,85,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,231,41,0,0,165,212,0,0,153,245,0,0,0,0,113,255,0,0, 0,0,0,0,0,0,0,252,83,0,0,0,0,0,0,0,0,0,0,70,196,38,221,0,0,0,0,0,129,255,214,18,0,0,43,245,188,206,147,161,236,104,187,181,0,0,11,225,195,207,206,50,255,32,0,0,0,0,0,0,0,0,82,255,14,0,0,0,0,0,199,162,0,0,0,23,0,23,0,0,0,0,15,26,102,192,26,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,215,0,0,0,169,210,0,0,147,248,0,0,0,0,113,255,0,0, 0,0,0,0,0,0,0,240,62,0,0,0,0,0,0,0,0,0,145,254,254,254,255,195,0,0,0,0,84,230,250,140,0,0,0,33,74,59,223,86,255,6,86,248,0,0,77,255,78,14,190,218,250,14,0,0,0,0,0,0,0,0,84,254,8,0,0,0,0,0,186,162,0,0,0,0,0,0,0,0,0,0,189,255,255,255,255,237,0,0,0,0,0,0,0,0,159,247,247,93,0,0,0,0,0,0,0,0,0,141,133,0,0,0,155,237,1,0,164,211,0,0,0,0,113,255,0,0, 0,0,0,0,0,0,0,137,37,0,0,0,0,0,0,0,0,0,0,145,117,106,149,0,0,0,3,80,88,203,224,145,0,0,0,0,4,208,75,59,255,26,96,219,0,0,57,255,150,0,13,229,245,79,0,0,0,0,0,0,0,0,71,255,44,0,0,0,0,0,232,127,0,0,0,0,0,0,0,0,0,0,0,0,85,184,0,0,0,0,0,45,24,0,0,0,56,85,85,5,0,0,0,70,44,0,0,0,0,223,51,0,0,0,76,255,74,15,234,120,0,0,0,0,113,255,0,0, 0,0,0,0,0,0,14,255,138,0,0,0,0,0,0,0,0,0,0,173,79,152,112,0,0,0,39,243,251,254,218,26,0,0,0,0,122,165,0,3,212,188,219,96,0,0,0,166,255,221,235,152,179,252,44,0,0,0,0,0,0,0,9,243,128,0,0,0,0,57,254,47,0,0,0,0,0,0,0,0,0,0,0,0,85,184,0,0,0,0,15,244,109,0,0,0,0,0,0,0,0,0,0,250,158,0,0,0,50,223,0,0,0,0,0,173,249,238,182,4,0,0,0,0,113,255,0,0, 0,0,0,0,0,0,0,62,6,0,0,0,0,0,0,0,0,0,0,54,0,50,5,0,0,0,0,20,136,181,7,0,0,0,0,0,58,7,0,0,19,101,61,0,0,0,0,0,48,76,33,0,4,40,0,0,0,0,0,0,0,0,0,125,237,23,0,0,1,194,159,0,0,0,0,0,0,0,0,0,0,0,0,0,28,33,0,0,0,0,104,229,11,0,0,0,0,0,0,0,0,0,0,57,10,0,0,0,132,142,0,0,0,0,0,1,62,60,1,0,0,0,0,0,33,56,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,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,0,3,181,201,0,0,134,201,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,188,92,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,86,23,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,69,0,0,73,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,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,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,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,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,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,1,31,8,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,19,133,169,141,24,0,0,1,87,163,165,74,0,0,0,0,0,0,40,170,0,0,0,0,18,170,170,170,40,0,0,0,0,0,44,141,82,0,0,0,157,170,170,170,170,0,0,0,28,144,168,116,4,0,0,0,30,144,168,129,13,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,0,0,0,0,0,0,43,217,255,251,123,0,0,0,0,0,37,133,168,168,128,27,0,0,0,0,0,0,0,0,0,0, 0,0,0,196,176,139,245,199,0,0,2,181,122,187,253,42,0,0,0,0,15,217,255,0,0,0,0,92,238,126,111,4,0,0,0,0,123,244,150,28,0,0,0,115,126,126,205,223,0,0,0,214,157,116,253,116,0,0,21,234,183,120,232,181,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,0,0,0,0,0,0,56,89,12,193,242,0,0,0,0,103,245,150,92,107,193,238,50,0,0,0,0,0,0,0,0,0, 0,0,0,20,0,0,164,244,0,0,0,0,0,54,255,71,0,0,0,2,181,225,255,0,0,0,0,168,171,0,0,0,0,0,0,103,237,43,0,0,0,0,0,0,0,26,244,88,0,0,15,255,72,0,232,150,0,0,83,255,47,0,147,249,0,0,0,135,89,0,0,0,0,145,76,0,0,0,0,0,0,0,11,110,0,0,0,0,0,0,0,0,0,0,94,69,0,0,0,0,0,0,0,0,0,191,198,0,0,0,53,252,67,57,191,180,167,173,196,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,9,225,157,0,0,0,0,110,209,188,3,0,0,0,134,195,101,255,0,0,0,0,202,252,209,86,0,0,0,7,237,207,168,137,19,0,0,0,0,0,160,200,0,0,0,0,205,229,172,223,28,0,0,64,255,101,0,181,236,0,0,0,251,159,0,0,0,12,254,142,0,0,0,0,0,23,133,233,153,0,0,52,85,85,85,85,85,0,0,89,229,207,90,3,0,0,0,0,0,83,250,47,0,0,0,150,193,13,235,112,193,198,72,248,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,166,217,16,0,0,0,0,166,215,229,73,0,0,87,240,63,123,255,32,0,0,0,0,24,163,254,81,0,0,70,255,182,127,244,190,0,0,0,0,53,253,56,0,0,0,0,149,218,183,230,63,0,0,1,196,251,228,253,176,0,0,0,68,13,0,0,0,0,75,9,0,0,0,36,153,234,137,25,0,0,0,117,183,183,183,183,175,0,0,0,7,100,216,223,111,0,0,0,10,233,115,0,0,0,0,169,168,79,244,0,192,132,85,227,0,0,0,0,0,0,0,0,0, 0,0,0,0,142,226,29,0,0,0,0,0,0,1,191,222,0,0,229,255,255,255,255,211,0,0,0,0,0,3,243,162,0,0,84,255,45,0,157,249,0,0,0,0,197,167,0,0,0,0,60,255,46,0,142,232,0,0,0,7,72,93,246,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,253,112,5,0,0,0,0,11,24,24,24,24,23,0,0,0,0,0,30,206,246,0,0,0,64,225,4,0,0,0,0,142,218,77,253,166,254,131,199,117,0,0,0,0,0,0,0,0,0, 0,0,0,134,230,35,0,0,0,0,0,6,0,4,199,199,0,0,0,0,0,97,255,0,0,0,32,32,0,44,253,110,0,0,63,255,91,0,187,203,0,0,0,88,248,31,0,0,0,0,81,255,81,0,126,228,0,0,0,0,53,221,127,0,0,0,0,70,44,0,0,0,0,25,9,0,0,0,6,98,214,228,116,12,0,0,161,255,255,255,255,246,0,0,0,41,158,234,134,24,0,0,0,43,85,0,0,0,0,0,30,241,144,142,112,103,194,113,0,0,0,0,0,0,0,0,0,0, 0,0,93,255,242,232,232,226,0,0,0,228,227,234,227,43,0,0,0,0,0,97,255,0,0,0,143,251,218,249,163,2,0,0,1,180,251,225,229,42,0,0,1,222,134,0,0,0,0,0,12,206,252,224,239,74,0,0,0,192,236,101,0,0,0,0,0,250,158,0,0,0,15,240,102,0,0,0,0,0,1,78,195,239,0,0,0,0,0,0,0,0,0,0,128,225,115,12,0,0,0,0,0,165,238,5,0,0,0,0,0,58,226,225,169,179,228,44,0,0,0,0,0,0,0,0,0,0, 0,0,36,85,85,85,85,60,0,0,0,25,74,65,8,0,0,0,0,0,0,30,56,0,0,0,1,54,81,42,0,0,0,0,0,1,60,74,11,0,0,0,1,61,1,0,0,0,0,0,0,3,60,69,15,0,0,0,0,51,8,0,0,0,0,0,0,57,10,0,0,0,106,232,13,0,0,0,0,0,0,0,0,51,0,0,0,0,0,0,0,0,0,0,46,4,0,0,0,0,0,0,0,31,36,0,0,0,0,0,0,0,5,57,81,58,5,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,193,99,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,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,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,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,50,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,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,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,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,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,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,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,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,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,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,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,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,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,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,12,168,58,0,0,0,0,0,0,0,170,170,169,130,10,0,0,0,0,24,124,167,168,123,0,0,0,0,170,170,170,166,120,23,0,0,0,0,170,170,170,170,0,0,0,0,170,170,170,170,0,0,0,0,0,24,124,167,168,132,29,0,0,0,170,67,0,0,71,170,0,0,0,0,170,67,0,0,0,17,170,56,0,0,0,0,170,67,0,17,167,38,0,0,0,0,170,67,0,0,0,0,0,0,170,108,0,0,0,0,0,143,113,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,106,254,166,0,0,0,0,0,0,0,255,166,144,254,134,0,0,0,53,236,190,120,139,222,0,0,0,0,255,166,111,140,233,234,38,0,0,0,255,166,109,91,0,0,0,0,255,166,109,91,0,0,0,0,53,237,193,122,127,204,100,0,0,0,255,101,0,0,113,255,0,0,0,0,255,101,0,0,0,33,255,85,0,0,0,0,255,101,11,198,180,4,0,0,0,0,255,101,0,0,0,0,0,0,255,244,20,0,0,0,72,255,170,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,209,198,246,15,0,0,0,0,0,0,255,101,0,225,150,0,0,5,223,166,0,0,0,3,0,0,0,0,255,101,0,0,28,238,177,0,0,0,255,101,0,0,0,0,0,0,255,101,0,0,0,0,0,5,223,168,0,0,0,0,0,0,0,0,255,101,0,0,113,255,0,0,0,0,255,101,0,0,0,33,255,85,0,0,0,0,255,107,186,189,8,0,0,0,0,0,255,101,0,0,0,0,0,0,255,249,132,0,0,1,206,241,170,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,57,240,49,255,101,0,0,0,0,0,0,255,155,159,229,34,0,0,70,255,64,0,0,0,0,0,0,0,0,255,101,0,0,0,162,243,0,0,0,255,152,85,85,0,0,0,0,255,128,44,39,0,0,0,71,255,65,0,0,0,0,0,0,0,0,255,203,170,170,208,255,0,0,0,0,255,101,0,0,0,33,255,85,0,0,0,0,255,234,204,12,0,0,0,0,0,0,255,101,0,0,0,0,0,0,255,192,239,14,0,86,206,199,170,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,161,176,44,219,197,0,0,0,0,0,0,255,219,221,243,114,0,0,84,255,54,0,0,0,0,0,0,0,0,255,101,0,0,0,156,242,0,0,0,255,218,194,171,0,0,0,0,255,255,255,231,0,0,0,84,255,53,0,0,0,122,108,0,0,0,255,166,109,109,174,255,0,0,0,0,255,101,0,0,0,33,255,85,0,0,0,0,255,245,235,36,0,0,0,0,0,0,255,101,0,0,0,0,0,0,255,83,251,119,2,215,79,198,170,0,0,0,0,0,0,0,0,0,0, 0,0,0,18,248,255,255,255,254,37,0,0,0,0,0,255,101,0,145,254,0,0,54,255,119,0,0,0,0,0,0,0,0,255,101,0,0,0,199,187,0,0,0,255,101,0,0,0,0,0,0,255,101,0,0,0,0,0,55,255,116,0,0,0,198,170,0,0,0,255,101,0,0,113,255,0,0,0,0,255,101,0,0,0,33,255,85,0,0,0,0,255,124,225,217,18,0,0,0,0,0,255,101,0,0,0,0,0,0,255,53,161,229,101,207,0,198,170,0,0,0,0,0,0,0,0,0,0, 0,0,0,115,216,0,0,30,254,132,0,0,0,0,0,255,101,0,137,242,0,0,0,197,243,71,0,0,41,0,0,0,0,255,101,0,4,121,251,57,0,0,0,255,101,0,0,0,0,0,0,255,101,0,0,0,0,0,0,198,241,64,0,0,199,170,0,0,0,255,101,0,0,113,255,0,0,0,0,255,101,0,0,0,33,255,85,0,0,0,0,255,101,48,244,194,7,0,0,0,0,255,101,0,0,0,0,0,0,255,53,43,254,247,74,0,198,170,0,0,0,0,0,0,0,0,0,0, 0,0,0,217,127,0,0,0,198,225,2,0,0,0,0,255,230,229,242,83,0,0,0,26,198,255,226,222,241,0,0,0,0,255,230,218,245,224,71,0,0,0,0,255,230,214,214,0,0,0,0,255,101,0,0,0,0,0,0,27,201,254,223,223,252,121,0,0,0,255,101,0,0,113,255,0,0,0,0,255,101,0,0,0,33,255,85,0,0,0,0,255,101,0,83,254,133,0,0,0,0,255,230,214,214,0,0,0,0,255,53,0,173,198,0,0,198,170,0,0,0,0,0,0,0,0,0,0, 0,0,0,82,4,0,0,0,45,58,0,0,0,0,0,85,85,71,17,0,0,0,0,0,0,44,79,67,11,0,0,0,0,85,85,81,52,3,0,0,0,0,0,85,85,85,85,0,0,0,0,85,5,0,0,0,0,0,0,0,1,46,79,64,20,0,0,0,0,85,5,0,0,33,56,0,0,0,0,85,5,0,0,0,50,255,72,0,0,0,0,85,5,0,0,67,17,0,0,0,0,85,85,85,85,0,0,0,0,74,0,0,29,22,0,0,62,28,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,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,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,176,217,10,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,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,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,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,87,14,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,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,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,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,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,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0, 0,0,0,170,66,0,0,0,42,170,0,0,0,0,40,142,169,160,79,0,0,0,0,0,0,170,170,166,103,3,0,0,0,0,40,142,169,160,79,0,0,0,0,0,0,170,170,168,118,6,0,0,0,30,144,169,122,6,0,0,140,170,170,170,170,170,88,0,0,0,56,170,12,0,0,56,170,0,0,0,2,182,101,0,0,0,115,147,0,0,0,170,83,0,0,73,164,3,0,0,158,71,0,0,58,186,47,0,33,193,34,0,0,0,160,145,0,0,40,201,0,0,0,0,0,0,0,0, 0,0,0,255,238,39,0,0,73,255,0,0,0,81,248,163,117,159,252,157,0,0,0,0,0,255,168,159,255,121,0,0,0,81,248,163,117,159,252,158,0,0,0,0,0,255,166,149,255,122,0,0,0,217,192,128,202,34,0,0,87,109,157,255,117,109,29,0,0,0,85,255,18,0,0,84,255,0,0,0,0,200,208,0,0,1,226,110,0,0,0,210,175,0,0,176,255,59,0,20,253,40,0,0,22,234,203,3,174,177,0,0,0,0,147,253,45,0,177,162,0,0,0,0,0,0,0,0, 0,0,0,255,245,218,17,0,73,255,0,0,14,239,152,0,0,0,114,255,80,0,0,0,0,255,101,0,240,162,0,0,14,239,152,0,0,0,114,255,81,0,0,0,0,255,101,0,236,160,0,0,0,251,153,0,0,0,0,0,0,0,85,255,14,0,0,0,0,0,85,255,18,0,0,84,255,0,0,0,0,105,255,42,0,66,246,16,0,0,0,134,241,4,6,246,224,135,0,93,216,0,0,0,0,83,255,171,243,29,0,0,0,0,22,242,173,63,241,24,0,0,0,0,0,0,0,0, 0,0,0,255,109,248,187,4,73,255,0,0,78,255,61,0,0,0,5,249,155,0,0,0,0,255,101,43,253,93,0,0,78,255,61,0,0,0,5,249,155,0,0,0,0,255,129,99,254,86,0,0,0,148,255,147,5,0,0,0,0,0,85,255,14,0,0,0,0,0,85,255,18,0,0,84,255,0,0,0,0,16,249,130,0,159,161,0,0,0,0,58,255,61,73,212,146,211,0,168,137,0,0,0,0,0,165,255,123,0,0,0,0,0,0,125,254,217,113,0,0,0,0,0,0,0,0,0, 0,0,0,255,53,94,254,145,73,255,0,0,84,255,54,0,0,0,0,239,159,0,0,0,0,255,221,247,151,0,0,0,84,255,54,0,0,0,0,239,157,0,0,0,0,255,255,255,174,0,0,0,0,2,130,253,174,0,0,0,0,0,85,255,14,0,0,0,0,0,85,255,18,0,0,84,255,0,0,0,0,0,170,215,7,242,59,0,0,0,0,1,235,130,146,140,74,254,29,239,58,0,0,0,0,0,157,254,202,4,0,0,0,0,0,10,230,218,3,0,0,0,0,0,0,0,0,0, 0,0,0,255,53,0,134,255,168,255,0,0,52,255,119,0,0,0,35,254,105,0,0,0,0,255,150,41,0,0,0,0,59,255,119,0,0,0,35,254,104,0,0,0,0,255,101,150,235,16,0,0,0,0,0,115,255,59,0,0,0,0,85,255,14,0,0,0,0,0,84,255,36,0,0,101,245,0,0,0,0,0,75,255,126,212,0,0,0,0,0,0,160,197,218,66,7,248,155,232,2,0,0,0,0,59,250,106,254,122,0,0,0,0,0,0,170,186,0,0,0,0,0,0,0,0,0,0, 0,0,0,255,53,0,2,177,253,255,0,0,0,197,236,38,0,7,181,221,10,0,0,0,0,255,101,0,0,0,0,0,2,213,236,38,0,7,181,214,8,0,0,0,0,255,101,30,249,141,0,0,23,60,0,61,255,62,0,0,0,0,85,255,14,0,0,0,0,0,45,255,130,0,5,195,174,0,0,0,0,0,3,231,247,111,0,0,0,0,0,0,83,250,240,5,0,181,247,155,0,0,0,0,4,211,140,0,160,248,45,0,0,0,0,0,170,186,0,0,0,0,0,0,0,0,0,0, 0,0,0,255,53,0,0,12,208,255,0,0,0,27,202,252,220,242,208,34,0,0,0,0,0,255,101,0,0,0,0,0,0,38,213,252,220,242,223,25,0,0,0,0,0,255,101,0,150,247,0,0,86,253,222,245,155,0,0,0,0,0,85,255,14,0,0,0,0,0,0,151,255,222,233,212,25,0,0,0,0,0,0,140,247,17,0,0,0,0,0,0,11,250,168,0,0,105,255,75,0,0,0,0,112,233,15,0,19,234,200,0,0,0,0,0,170,186,0,0,0,0,0,0,0,0,0,0, 0,0,0,74,0,0,0,0,25,56,0,0,0,0,1,50,78,50,1,0,0,0,0,0,0,85,5,0,0,0,0,0,0,0,2,53,83,158,250,206,85,1,0,0,0,85,5,0,26,69,0,0,0,32,79,41,0,0,0,0,0,0,28,61,0,0,0,0,0,0,0,0,42,80,61,3,0,0,0,0,0,0,0,24,48,0,0,0,0,0,0,0,0,69,19,0,0,16,73,0,0,0,0,0,51,47,0,0,0,56,53,0,0,0,0,0,56,33,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,157,183,2,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,0,0,0,74,79,58,0,0,13,4,0,0,0,0,57,79,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,35,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,156,170,170,170,170,82,0,0,0,0,255,197,108,0,0,161,127,0,0,0,0,139,198,255,0,0,0,0,72,161,32,0,0,0,0,0,0,0,0,0,0,0,0,153,239,75,0,0,0,0,0,0,0,0,0,0,0,85,250,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,83,255,0,0,0,0,0,0,0,0,0,0,0,112,235,139,0,0,0,0,0,0,0,0,0,0,85,250,0,0,0,0,0,0,35,165,25,0,0,0,0,35,165,25,0,0, 0,0,0,83,94,94,189,233,20,0,0,0,0,255,82,0,0,0,88,210,0,0,0,0,0,84,255,0,0,0,78,227,172,225,35,0,0,0,0,0,0,0,0,0,0,0,0,86,134,0,0,0,0,0,0,0,0,0,0,0,85,250,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,84,255,0,0,0,0,0,0,0,0,0,0,0,250,107,10,0,0,0,0,0,0,0,0,0,0,85,250,0,0,0,0,0,0,36,127,7,0,0,0,0,36,127,7,0,0, 0,0,0,0,0,44,249,84,0,0,0,0,0,255,82,0,0,0,11,249,37,0,0,0,0,84,255,0,0,0,69,34,2,89,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,113,168,156,42,0,0,0,85,250,98,168,148,31,0,0,0,0,0,45,152,169,128,0,0,0,0,55,161,165,153,255,0,0,0,55,159,165,62,0,0,0,155,255,197,107,0,0,0,49,158,165,108,147,0,0,85,250,102,167,154,36,0,0,56,168,0,0,0,0,0,56,168,0,0,0, 0,0,0,0,5,206,170,0,0,0,0,0,0,255,82,0,0,0,0,179,119,0,0,0,0,84,255,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,39,165,90,207,217,0,0,0,85,254,186,108,219,221,7,0,0,0,36,243,164,107,113,0,0,0,43,246,135,124,246,255,0,0,64,249,121,161,241,14,0,0,130,255,179,62,0,0,39,243,136,125,247,255,0,0,85,255,175,111,225,204,0,0,85,252,0,0,0,0,0,85,252,0,0,0, 0,0,0,0,129,234,21,0,0,0,0,0,0,255,82,0,0,0,0,97,202,0,0,0,0,84,255,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,41,143,227,254,0,0,0,85,255,27,0,72,255,66,0,0,0,148,215,0,0,0,0,0,0,152,209,0,0,134,255,0,0,161,216,85,90,254,72,0,0,0,255,82,0,0,0,148,211,0,0,137,255,0,0,85,255,21,0,104,251,0,0,85,252,0,0,0,0,0,85,252,0,0,0, 0,0,0,50,251,86,0,0,0,0,0,0,0,255,82,0,0,0,0,18,251,30,0,0,0,84,255,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,78,236,98,114,255,0,0,0,85,254,4,0,40,255,74,0,0,0,169,200,0,0,0,0,0,0,168,197,0,0,97,255,0,0,169,234,166,166,166,28,0,0,0,255,82,0,0,0,169,195,0,0,95,255,0,0,85,255,12,0,84,255,0,0,85,252,0,0,0,0,0,85,252,0,0,0, 0,0,7,212,172,0,0,0,0,0,0,0,0,255,82,0,0,0,0,0,189,111,0,0,0,84,255,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,167,190,2,189,255,0,0,0,85,255,69,0,100,246,18,0,0,0,126,251,43,0,7,0,0,0,138,246,19,0,172,255,0,0,133,244,37,0,11,2,0,0,0,255,82,0,0,0,148,242,12,0,161,255,0,0,85,255,12,0,84,255,0,0,85,252,0,0,0,0,0,85,252,0,0,0, 0,0,127,255,202,185,185,185,119,0,0,0,0,255,82,0,0,0,0,0,106,193,0,0,0,84,255,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,127,254,232,212,255,0,0,0,85,253,239,171,241,99,0,0,0,0,15,206,246,204,230,0,0,0,29,238,213,183,227,255,0,0,20,212,245,198,231,29,0,0,0,255,82,0,0,0,43,246,195,159,235,255,0,0,85,255,12,0,84,255,0,0,85,252,0,0,0,0,0,85,252,0,0,0, 0,0,52,85,85,85,85,85,27,0,0,0,0,255,82,0,0,0,0,0,26,251,0,0,0,84,255,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,4,90,70,20,71,0,0,0,28,55,60,107,47,0,0,0,0,0,0,3,61,75,15,0,0,0,0,29,104,79,28,56,0,0,0,5,65,74,14,0,0,0,0,84,0,0,0,0,0,48,134,111,108,239,0,0,28,60,0,0,27,56,0,0,28,56,0,0,0,0,0,86,249,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,255,197,136,0,0,0,0,0,105,0,0,140,198,255,0,0,0,0,0,0,0,0,0,0,0,237,244,244,244,244,162,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,97,36,51,212,152,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,209,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,85,85,40,0,0,0,0,0,0,0,0,67,85,56,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,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,0,0,0,0,0,0,0,0,0,46,206,245,231,137,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,209,54,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,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,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,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,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,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,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,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,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,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,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,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,0,0,0, 0,0,85,252,0,0,0,0,0,0,85,252,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,85,252,0,0,0,0,0,0,85,252,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,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,227,80,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,85,252,0,57,125,0,0,0,85,252,0,0,44,145,110,169,138,45,146,167,86,0,0,0,44,145,101,167,154,36,0,0,0,42,151,169,124,12,0,0,44,146,95,168,149,33,0,0,0,0,0,57,162,165,111,147,0,0,44,143,139,139,2,0,0,0,0,106,168,133,0,0,136,255,198,129,0,0,0,0,56,166,0,0,112,113,0,0,126,81,0,0,115,0,0,0,131,74,0,18,148,10,0,91,113,0,0,0,24,127,13,0,119,36,0,0,0,119,89,0,0,104,88,0,0,0, 0,0,85,252,41,236,98,0,0,0,85,252,0,0,85,255,167,142,254,243,127,182,253,38,0,0,85,255,175,111,225,204,0,0,49,245,145,110,225,204,0,0,85,254,185,107,217,223,8,0,0,0,46,248,133,126,247,255,0,0,85,255,189,139,0,0,0,0,69,254,98,116,0,0,114,255,180,82,0,0,0,0,85,250,0,0,169,170,0,0,184,209,0,18,248,0,0,0,192,185,0,113,255,97,0,208,117,0,0,0,42,248,158,106,222,15,0,0,0,179,223,2,9,241,71,0,0,0, 0,0,85,253,226,119,0,0,0,0,85,252,0,0,85,255,11,0,195,176,0,20,255,83,0,0,85,255,21,0,104,251,0,0,156,211,0,0,75,255,0,0,85,255,27,0,70,255,68,0,0,0,154,207,0,0,142,255,0,0,85,255,10,0,0,0,0,0,55,253,176,20,0,0,0,255,84,0,0,0,0,0,85,250,0,0,169,170,0,0,76,255,52,110,203,0,0,0,104,250,18,213,230,198,33,253,30,0,0,0,0,105,255,242,49,0,0,0,0,77,255,69,99,213,0,0,0,0, 0,0,85,253,249,163,0,0,0,0,85,252,0,0,85,255,2,0,170,169,0,0,254,85,0,0,85,255,12,0,84,255,0,0,169,197,0,0,40,255,0,0,85,255,7,0,41,255,72,0,0,0,168,199,0,0,114,255,0,0,85,252,0,0,0,0,0,0,0,84,238,217,0,0,0,255,84,0,0,0,0,0,85,251,0,0,172,170,0,0,1,222,143,205,91,0,0,0,18,251,139,233,80,254,142,195,0,0,0,0,0,32,249,239,35,0,0,0,0,2,227,165,195,102,0,0,0,0, 0,0,85,252,107,255,115,0,0,0,85,252,0,0,85,255,2,0,170,169,0,0,254,85,0,0,85,255,12,0,84,255,0,0,126,248,34,0,117,240,0,0,85,255,85,0,112,240,14,0,0,0,131,249,28,1,192,255,0,0,85,252,0,0,0,0,0,0,11,18,49,255,0,0,0,254,95,0,0,0,0,0,82,255,47,13,229,170,0,0,0,118,235,230,5,0,0,0,0,181,246,139,3,229,252,106,0,0,0,0,8,204,150,221,206,8,0,0,0,0,128,244,234,8,0,0,0,0, 0,0,85,252,0,165,251,0,0,0,85,252,0,0,85,255,2,0,170,169,0,0,254,85,0,0,85,255,12,0,84,255,0,0,13,201,242,208,240,74,0,0,85,254,245,204,244,81,0,0,0,0,21,227,233,213,212,255,0,0,85,252,0,0,0,0,0,0,110,243,217,204,0,0,0,207,233,187,2,0,0,0,26,244,248,242,236,170,0,0,0,18,247,125,0,0,0,0,0,92,254,37,0,128,251,20,0,0,0,0,137,209,5,56,251,121,0,0,0,0,30,253,131,0,0,0,0,0, 0,0,28,56,0,11,63,0,0,0,28,56,0,0,28,57,0,0,56,28,0,0,84,0,0,0,28,60,0,0,27,56,0,0,0,3,61,74,16,0,0,0,85,252,34,78,25,0,0,0,0,0,0,13,75,49,84,255,0,0,28,56,0,0,0,0,0,0,1,57,68,4,0,0,0,15,76,30,0,0,0,0,0,38,103,51,55,28,0,0,0,0,62,2,0,0,0,0,0,9,57,0,0,18,52,0,0,0,0,0,36,25,0,0,61,10,0,0,0,0,16,241,25,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,252,0,0,0,0,0,0,0,0,0,0,0,0,84,255,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,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,18,166,142,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,214,0,0,0,0,0,0,0,0,0,0,0,0,79,216,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,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,26,248,158,6,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,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,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,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,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,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,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,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,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,9,54,0,0,0,0,0,0,0,0,35,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,44,0,0,0,0,0,0,2,0,0,0,1,59,1,51,6,0,0,0,0,0,2,0,3,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,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,0,0,0,0,0,0,13,220,157,0,0,0,255,13,0,0,0,118,249,70,0,0,0,27,156,145,71,88,83,0,0,71,82,82,82,82,71,0,0,89,248,24,0,0,0,0,148,177,0,0,0,25,255,84,244,123,0,0,0,0,151,174,111,214,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,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,0,0,0,0,0,0,78,254,4,0,0,0,255,13,0,0,0,0,193,158,0,0,0,172,114,133,227,216,35,0,0,189,198,198,198,198,156,0,0,26,245,110,0,0,0,9,246,96,0,0,0,0,203,177,162,216,0,0,0,11,247,93,218,133,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,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,48,170,170,170,167,0,0,0,0,84,254,0,0,0,0,255,13,0,0,0,0,169,170,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,173,0,0,0,85,208,2,0,0,0,0,61,234,35,243,0,0,0,87,206,50,233,13,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,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,45,161,161,245,140,0,0,0,0,87,243,0,0,0,0,255,13,0,0,0,0,169,173,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,17,0,0,0,36,34,0,0,0,0,0,0,27,0,28,0,0,0,37,33,21,48,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,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,110,210,6,0,0,0,10,184,144,0,0,0,0,255,13,0,0,0,0,111,235,45,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,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,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,0,0,0,0,0,0, 0,0,0,58,244,43,0,0,0,0,28,230,173,0,0,0,0,255,13,0,0,0,0,91,241,54,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,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,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,0,0,0,0,0,0, 0,0,22,228,112,0,0,0,0,0,0,101,246,0,0,0,0,255,13,0,0,0,0,167,176,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,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,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,0,0,0,0,0,0,0, 0,0,184,252,170,169,167,0,0,0,0,85,251,0,0,0,0,255,13,0,0,0,0,169,172,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,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,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,0,0,0,0,0,0,0, 0,0,76,85,85,85,60,0,0,0,0,82,253,12,0,0,0,61,0,0,0,0,0,183,154,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,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,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,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,25,239,178,0,0,0,0,0,0,0,0,101,241,49,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,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,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,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,27,48,0,0,0,0,0,0,0,0,44,25, }; /* Character boxes for debug text font. */ #define DEBUGFONT_HEIGHT 12 static const struct { int x, y, width, prekern, postkern; } debugfont_chars[] = { [' '] = {1, 2, 3, 0, 0}, ['!'] = {5, 2, 5, -1, -1}, ['"'] = {11, 2, 6, -1, -1}, ['#'] = {17, 2, 8, -1, -1}, ['$'] = {25, 2, 8, -1, -1}, ['%'] = {33, 2, 12, -1, -1}, ['&'] = {45, 2, 11, -1, -1}, ['\''] = {57, 2, 4, -1, -1}, ['('] = {61, 2, 6, -1, -1}, [')'] = {67, 2, 6, -1, -1}, ['*'] = {73, 2, 7, -1, -1}, ['+'] = {81, 2, 8, -1, -1}, [','] = {89, 2, 5, -1, -1}, ['-'] = {95, 2, 6, -1, -1}, ['.'] = {101, 2, 5, -1, -1}, ['/'] = {107, 2, 6, -1, -1}, ['0'] = {113, 2, 8, -1, -1}, ['1'] = {121, 2, 6, -1, 1}, ['2'] = {1, 16, 8, -1, -1}, ['3'] = {9, 16, 8, -1, -1}, ['4'] = {17, 16, 8, -1, -1}, ['5'] = {25, 16, 8, -1, -1}, ['6'] = {33, 16, 8, -1, -1}, ['7'] = {41, 16, 8, -1, -1}, ['8'] = {49, 16, 8, -1, -1}, ['9'] = {57, 16, 8, -1, -1}, [':'] = {65, 16, 5, -1, -1}, [';'] = {71, 16, 5, -1, -1}, ['<'] = {77, 16, 8, -1, -1}, ['='] = {85, 16, 8, -1, -1}, ['>'] = {93, 16, 8, -1, -1}, ['?'] = {101, 16, 7, -1, -1}, ['@'] = {109, 16, 11, -1, -1}, ['A'] = {1, 30, 11, -2, -2}, ['B'] = {13, 30, 8, -1, -1}, ['C'] = {21, 30, 9, -1, -1}, ['D'] = {31, 30, 10, -1, -1}, ['E'] = {41, 30, 7, -1, -1}, ['F'] = {49, 30, 7, -1, -1}, ['G'] = {57, 30, 10, -1, -1}, ['H'] = {67, 30, 9, -1, 0}, ['I'] = {77, 30, 5, -1, -1}, ['J'] = {83, 30, 5, -1, -1}, ['K'] = {89, 30, 9, -1, -1}, ['L'] = {99, 30, 7, -1, -1}, ['M'] = {107, 30, 12, -1, -1}, ['N'] = {1, 44, 10, -1, 0}, ['O'] = {11, 44, 11, -1, -1}, ['P'] = {23, 44, 8, -1, -1}, ['Q'] = {31, 44, 12, -1, -2}, ['R'] = {43, 44, 8, -1, -1}, ['S'] = {51, 44, 8, -1, -1}, ['T'] = {59, 44, 9, -1, -2}, ['U'] = {69, 44, 9, -1, 0}, ['V'] = {79, 44, 10, -2, -1}, ['W'] = {89, 44, 14, -2, -2}, ['X'] = {103, 44, 9, -1, -1}, ['Y'] = {113, 44, 8, -1, -1}, ['Z'] = {1, 58, 9, -1, -1}, ['['] = {11, 58, 6, -1, -1}, ['\\'] = {17, 58, 6, -1, -1}, [']'] = {23, 58, 5, -1, 0}, ['^'] = {29, 58, 7, -2, -1}, ['_'] = {37, 58, 8, -1, -2}, ['`'] = {45, 58, 5, -2, 0}, ['a'] = {51, 58, 7, -1, -1}, ['b'] = {59, 58, 9, -1, -1}, ['c'] = {69, 58, 7, -1, -1}, ['d'] = {77, 58, 8, -1, 0}, ['e'] = {85, 58, 8, -1, -1}, ['f'] = {93, 58, 6, -1, -2}, ['g'] = {99, 58, 8, -1, 0}, ['h'] = {107, 58, 8, -1, -1}, ['i'] = {115, 58, 5, -1, -1}, ['j'] = {121, 58, 6, -2, -1}, ['k'] = {1, 72, 7, -1, -1}, ['l'] = {9, 72, 4, -1, 0}, ['m'] = {13, 72, 12, -1, -1}, ['n'] = {25, 72, 8, -1, -1}, ['o'] = {33, 72, 8, -1, -1}, ['p'] = {41, 72, 9, -1, -1}, ['q'] = {51, 72, 8, -1, 0}, ['r'] = {59, 72, 7, -1, -2}, ['s'] = {67, 72, 6, -1, -1}, ['t'] = {73, 72, 7, -1, -2}, ['u'] = {81, 72, 8, -1, -1}, ['v'] = {89, 72, 7, -1, -1}, ['w'] = {97, 72, 11, -1, -1}, ['x'] = {109, 72, 8, -1, -1}, ['y'] = {117, 72, 9, -2, -2}, ['z'] = {1, 86, 7, -1, -1}, ['{'] = {9, 86, 6, -1, -1}, ['|'] = {15, 86, 5, -1, -1}, ['}'] = {21, 86, 6, -1, -1}, ['~'] = {27, 86, 8, -2, -1}, }; /* Texture coordinates for each debug font character (generated at runtime). */ static struct {float u0, v0, u1, v1;} debugfont_texcoords[lenof(debugfont_chars)]; /* Texture object for font (created in debug_init()). */ static int font_texture; /*************************************************************************/ /*************************** Other local data ****************************/ /*************************************************************************/ /* Debug UI buttons. */ typedef struct DebugButton DebugButton; struct DebugButton { const char * const id; // Arbitrary button ID for this button. const float cx, cy; // Center of button in touch coords (0.0-1.0). const float width, height; // Size of button in touch coords (0.0-1.0). const char *text; // Text to display in the button. uint8_t is_touched; // Is this button currently touched? float timer; // Touch timer (may also be reset by handler). }; static DebugButton debug_buttons[] = { {.id="CPU_DOWN", .cx=0.27f, .cy=0.93f, .width=0.06f, .height=0.08f, .text="-"}, {.id="CPU_UP", .cx=0.53f, .cy=0.93f, .width=0.06f, .height=0.08f, .text="+"}, {.id="MEM_TOGGLE", .cx=0.87f, .cy=0.84f, .width=0.06f, .height=0.08f, .text="Off"}, {.id="CPU_TOGGLE", .cx=0.87f, .cy=0.93f, .width=0.06f, .height=0.08f, .text="Off"}, }; /*-----------------------------------------------------------------------*/ /* Have we been initialized? */ static uint8_t initted; /* Should we enable the mouse/touch methods to activate the interface? */ static uint8_t auto_enabled; /* Current input state. */ static uint8_t mouse_left, mouse_middle, mouse_right; static struct { unsigned int id; uint8_t new_this_time; uint8_t seen_this_time; float x, y; } active_touches[INPUT_MAX_TOUCHES]; /* Is the debug interface active? */ static uint8_t debug_interface_on; /* Was the debug interface activated by touch? */ static uint8_t debug_interface_from_touch; /* Was the mouse pointer enabled when the debug interface was activated? */ static uint8_t mouse_pointer_was_on; /* CPU/memory display flags (toggled via debug input). */ static uint8_t do_display_cpu = 0, do_display_memory = 0; /* CPU usage logging flag (toggled via debug input). */ static uint8_t do_log_cpu = 0; /* Cached text and fill vertices. */ typedef struct TextVertex {float u,v; uint32_t color; float x,y;} TextVertex; typedef struct FillVertex {uint32_t color; int16_t x,y;} FillVertex; static TextVertex text_vertices[6*1000]; static FillVertex fill_vertices[6*100]; static int num_text_vertices, num_fill_vertices; /*-----------------------------------------------------------------------*/ /* Processing phases which we measure (corresponding to DEBUG_CPU_*, with * the addition of DEBUG). */ enum { CPUTIME_RENDER = 0, CPUTIME_DEBUG, // Time spent in debug interface processing. CPUTIME_PROCESS, CPUTIME_GPU_WAIT, CPUTIME__NUM }; /* CPU usage data, one entry per CPUTIME_* phase. */ static struct { double start, end; // Timestamps from debug_cpu_record_phase(). float time; // Time spent in this phase for the _last_ frame. float average; // Rolling average of time spent in this phase. } cpu_timing[CPUTIME__NUM]; /* CPU usage data (see update_cpu_usage()). */ static float usage_max; // Maximum usage during this averaging period. static int usage_displayed; // Usage (percent*10) currently displayed. static double usage_last_update; // Timestamp of last display update. /* CPU meter range (in frames). */ static int cpu_display_range; /* Frame period for the most recent frame. */ static float last_frame_time; /*-----------------------------------------------------------------------*/ #ifdef SIL_INCLUDE_TESTS /* Frame period override value (valid when nonzero). */ static float test_frame_period_override; /* Pending capture request, if any. */ static int test_capture_x; static int test_capture_y; static int test_capture_w; static int test_capture_h; static void *test_capture_pixels; #endif /*-----------------------------------------------------------------------*/ /* Local routine declarations. */ /** * Return the current display frame period, defaulting to 1/60 second * (60fps) if unknown. * * [Return value] * Display frame period. */ static float get_frame_period(void); /** * Perform per-frame processing for the debug interface. */ static void run_debug_interface(void); /** * update_cpu_usage: Update CPU usage information for the current frame. */ static void update_cpu_usage(void); /** * check_input: Check input state, and update debug interface state as * appropriate. */ static void check_input(void); /** * update_debug_buttons: Handle processing for all active debug buttons. */ static void update_debug_buttons(void); /** * display_debug_ui: Display the debug interface. */ static void display_debug_ui(void); /** * display_cpu_usage: Display CPU usage information. */ static void display_cpu_usage(void); /** * display_memory_usage: Display memory usage information. */ static void display_memory_usage(void); /** * debug_flush_render: Flush all pending debug render operations (filled * boxes and text, in that order) to the screen. Calls to this function * should be minimized, as each individual draw call is a significant hit * on performance. */ static void debug_flush_render(void); /** * debug_text_scale: Return the scale factor to use for drawing debug * text, based on the current display resolution. * * [Return value] * Scale factor for debug text size. */ static PURE_FUNCTION float debug_text_scale(void); /*************************************************************************/ /************************** Interface routines ***************************/ /*************************************************************************/ void debug_interface_activate(int on) { if (!initted) { return; } debug_interface_on = (on != 0); debug_interface_from_touch = 0; } /*-----------------------------------------------------------------------*/ void debug_interface_enable_auto(int enable) { auto_enabled = (enable != 0); } /*-----------------------------------------------------------------------*/ int debug_interface_is_active(void) { if (!initted) { return 0; } return debug_interface_on; } /*-----------------------------------------------------------------------*/ void debug_show_cpu_usage(int on) { if (!initted) { return; } do_display_cpu = (on != 0); do_log_cpu = 0; } /*-----------------------------------------------------------------------*/ int debug_cpu_usage_is_on(void) { if (!initted) { return 0; } return do_display_cpu; } /*-----------------------------------------------------------------------*/ void debug_show_memory_usage(int on) { if (!initted) { return; } do_display_memory = (on != 0); } /*-----------------------------------------------------------------------*/ int debug_memory_usage_is_on(void) { if (!initted) { return 0; } return do_display_memory; } /*-----------------------------------------------------------------------*/ int debug_draw_text(int x, int y, int alignment, const Vector4f *color, const char *format, ...) { if (!initted) { return 0; } char buf[1000]; va_list args; va_start(args, format); vstrformat(buf, sizeof(buf), format, args); va_end(args); int textwidth_raw = 0; for (int i = 0; buf[i] != 0; i++) { int ch = (unsigned char)buf[i]; if (ch >= lenof(debugfont_chars)) { continue; } textwidth_raw += debugfont_chars[ch].prekern + debugfont_chars[ch].width + debugfont_chars[ch].postkern; } int textwidth = iroundf(textwidth_raw * debug_text_scale()); if (alignment < 0) { x -= textwidth; } else if (alignment == 0) { x -= textwidth/2; } union {uint8_t b[4]; uint32_t i;} color_u = {.b = { iroundf(color->x*255), iroundf(color->y*255), iroundf(color->z*255), iroundf(color->w*255)}}; const uint32_t color32 = color_u.i; float cur_x = x; for (int i = 0; buf[i] != 0; i++) { int ch = (unsigned char)buf[i]; if (ch >= lenof(debugfont_chars)) { continue; } cur_x += debugfont_chars[ch].prekern * debug_text_scale(); if (debugfont_chars[ch].width > 0) { const float width = debugfont_chars[ch].width * debug_text_scale(); const float height = DEBUGFONT_HEIGHT * debug_text_scale(); const float u0 = debugfont_texcoords[ch].u0; const float v0 = debugfont_texcoords[ch].v0; const float u1 = debugfont_texcoords[ch].u1; const float v1 = debugfont_texcoords[ch].v1; if (num_text_vertices+6 > lenof(text_vertices)) { debug_flush_render(); } text_vertices[num_text_vertices+0].u = u0; text_vertices[num_text_vertices+0].v = v0; text_vertices[num_text_vertices+0].color = color32; text_vertices[num_text_vertices+0].x = cur_x; text_vertices[num_text_vertices+0].y = y; text_vertices[num_text_vertices+1].u = u1; text_vertices[num_text_vertices+1].v = v0; text_vertices[num_text_vertices+1].color = color32; text_vertices[num_text_vertices+1].x = cur_x + width; text_vertices[num_text_vertices+1].y = y; text_vertices[num_text_vertices+2].u = u0; text_vertices[num_text_vertices+2].v = v1; text_vertices[num_text_vertices+2].color = color32; text_vertices[num_text_vertices+2].x = cur_x; text_vertices[num_text_vertices+2].y = y + height; text_vertices[num_text_vertices+3] = text_vertices[num_text_vertices+2]; text_vertices[num_text_vertices+4] = text_vertices[num_text_vertices+1]; text_vertices[num_text_vertices+5].u = u1; text_vertices[num_text_vertices+5].v = v1; text_vertices[num_text_vertices+5].color = color32; text_vertices[num_text_vertices+5].x = cur_x + width; text_vertices[num_text_vertices+5].y = y + height; num_text_vertices += 6; cur_x += width; } cur_x += debugfont_chars[ch].postkern * debug_text_scale(); } return textwidth; } /*-----------------------------------------------------------------------*/ int debug_text_width(const char *text, int len) { if (!initted) { return 0; } if (len == 0) { len = strlen(text); } int textwidth_raw = 0; for (int i = 0; i < len; i++) { int ch = (unsigned char)text[i]; if (ch >= lenof(debugfont_chars)) { continue; } textwidth_raw += debugfont_chars[ch].prekern + debugfont_chars[ch].width + debugfont_chars[ch].postkern; } return iroundf(textwidth_raw * debug_text_scale()); } /*-----------------------------------------------------------------------*/ int debug_text_height(void) { return iroundf(DEBUGFONT_HEIGHT * debug_text_scale()); } /*-----------------------------------------------------------------------*/ void debug_fill_box(int x, int y, int w, int h, const Vector4f *color) { if (!initted) { return; } if (w == 0 || h == 0) { return; } const uint32_t color32 = iroundf(color->x*255) << 0 | iroundf(color->y*255) << 8 | iroundf(color->z*255) << 16 | iroundf(color->w*255) << 24; if (num_fill_vertices+6 > lenof(fill_vertices)) { debug_flush_render(); } fill_vertices[num_fill_vertices+0].color = color32; fill_vertices[num_fill_vertices+0].x = (int16_t)x; fill_vertices[num_fill_vertices+0].y = (int16_t)y; fill_vertices[num_fill_vertices+1].color = color32; fill_vertices[num_fill_vertices+1].x = (int16_t)(x+w); fill_vertices[num_fill_vertices+1].y = (int16_t)y; fill_vertices[num_fill_vertices+2].color = color32; fill_vertices[num_fill_vertices+2].x = (int16_t)x; fill_vertices[num_fill_vertices+2].y = (int16_t)(y+h); fill_vertices[num_fill_vertices+3] = fill_vertices[num_fill_vertices+2]; fill_vertices[num_fill_vertices+4] = fill_vertices[num_fill_vertices+1]; fill_vertices[num_fill_vertices+5].color = color32; fill_vertices[num_fill_vertices+5].x = (int16_t)(x+w); fill_vertices[num_fill_vertices+5].y = (int16_t)(y+h); num_fill_vertices += 6; } /*************************************************************************/ /************************* SIL-internal routines *************************/ /*************************************************************************/ void debug_init(void) { mouse_left = mouse_middle = mouse_right = 0; mem_clear(active_touches, sizeof(active_touches)); auto_enabled = 0; debug_interface_on = 0; debug_interface_from_touch = 0; mouse_pointer_was_on = 0; do_display_cpu = 0; do_display_memory = 0; do_log_cpu = 0; num_text_vertices = 0; num_fill_vertices = 0; mem_clear(cpu_timing, sizeof(cpu_timing)); usage_max = 0; usage_displayed = 0; usage_last_update = time_now() - 1; // Force an immediate update. cpu_display_range = 1; last_frame_time = 0; #ifdef SIL_INCLUDE_TESTS test_frame_period_override = 0; test_capture_pixels = NULL; #endif for (int i = 0; i < lenof(debugfont_chars); i++) { debugfont_texcoords[i].u0 = (float)debugfont_chars[i].x / DEBUGFONT_TEXWIDTH; debugfont_texcoords[i].v0 = (float)debugfont_chars[i].y / DEBUGFONT_TEXHEIGHT; debugfont_texcoords[i].u1 = debugfont_texcoords[i].u0 + (float)debugfont_chars[i].width / DEBUGFONT_TEXWIDTH; debugfont_texcoords[i].v1 = debugfont_texcoords[i].v0 + (float)DEBUGFONT_HEIGHT / DEBUGFONT_TEXHEIGHT; } initted = 1; } /*-----------------------------------------------------------------------*/ void debug_cleanup(void) { texture_destroy(font_texture); font_texture = 0; initted = 0; } /*-----------------------------------------------------------------------*/ void debug_record_cpu_phase(DebugCPUPhase phase) { if (!initted) { #ifdef SIL_INCLUDE_TESTS if (phase == DEBUG_CPU_RENDER_END && test_capture_pixels) { graphics_read_pixels(test_capture_x, test_capture_y, test_capture_w, test_capture_h, test_capture_pixels); test_capture_pixels = NULL; } #endif return; } const double now = time_now(); switch (phase) { case DEBUG_CPU_RENDER_START: /* Record time spent in each phase during the last frame (but only * if this isn't the first frame). */ if (cpu_timing[CPUTIME_RENDER].start > 0) { for (int i = 0; i < lenof(cpu_timing); i++) { cpu_timing[i].time = (float)(cpu_timing[i].end - cpu_timing[i].start); } last_frame_time = (float)(now - cpu_timing[CPUTIME_RENDER].start); } cpu_timing[CPUTIME_RENDER].start = now; break; case DEBUG_CPU_RENDER_END: cpu_timing[CPUTIME_RENDER].end = now; cpu_timing[CPUTIME_DEBUG].start = now; run_debug_interface(); cpu_timing[CPUTIME_DEBUG].end = time_now(); break; case DEBUG_CPU_PROCESS_START: cpu_timing[CPUTIME_PROCESS].start = now; break; case DEBUG_CPU_PROCESS_END: cpu_timing[CPUTIME_PROCESS].end = now; break; case DEBUG_CPU_GPU_WAIT_START: cpu_timing[CPUTIME_GPU_WAIT].start = now; break; case DEBUG_CPU_GPU_WAIT_END: cpu_timing[CPUTIME_GPU_WAIT].end = now; break; } } /*-----------------------------------------------------------------------*/ #ifdef SIL_INCLUDE_TESTS void TEST_debug_set_frame_period(float period) { test_frame_period_override = period; } void TEST_debug_capture_frame(int x, int y, int w, int h, void *pixels) { test_capture_x = x; test_capture_y = y; test_capture_w = w; test_capture_h = h; test_capture_pixels = pixels; } #endif // SIL_INCLUDE_TESTS /*************************************************************************/ /**************************** Local routines *****************************/ /*************************************************************************/ static float get_frame_period(void) { #ifdef SIL_INCLUDE_TESTS if (test_frame_period_override > 0) { return test_frame_period_override; } #endif const double frame_period = graphics_frame_period(); return (frame_period > 0 ? (float)frame_period : 1/60.0f); } /*-----------------------------------------------------------------------*/ static void run_debug_interface(void) { /* Update the rolling averages of CPU usage. */ update_cpu_usage(); /* Check input status for debug control. */ check_input(); /* If the debug interface is active, handle any button interactions * and display the debug interface. */ if (debug_interface_on) { update_debug_buttons(); display_debug_ui(); } /* Draw CPU usage information (if enabled). */ if (do_display_cpu && cpu_timing[CPUTIME_RENDER].start > 0) { display_cpu_usage(); } /* Get and draw information on used/available memory (if enabled). */ if (do_display_memory) { display_memory_usage(); } /* Flush out all debug display elements (if any). */ debug_flush_render(); #ifdef SIL_INCLUDE_TESTS /* Capture display data if requested. */ if (test_capture_pixels) { graphics_read_pixels(test_capture_x, test_capture_y, test_capture_w, test_capture_h, test_capture_pixels); test_capture_pixels = NULL; } #endif } /*-----------------------------------------------------------------------*/ static void update_cpu_usage(void) { const float frame_period = get_frame_period(); /* Update the average time for each phase of the frame, smoothing the * calculation to minimize the effect of transient spikes or similar * fluctuations. */ for (int i = 0; i < lenof(cpu_timing); i++) { const float this_time = cpu_timing[i].time; const float old_average = cpu_timing[i].average; /* Compute an exponentially smoothed average, reducing the weight * of each sample by 80% per second. However, give less weight to * values more than 50% greater than the average, on the assumption * that such values are transient spikes (from OS interference, for * example). */ float factor = 1 - powf(0.2f, last_frame_time>0 ? last_frame_time : frame_period); if (this_time > old_average * 1.5f) { factor *= lbound((old_average * 1.5f) / this_time, 0.5f); } cpu_timing[i].average = old_average*(1-factor) + this_time*factor; } /* Calculate CPU usage in frame time units. */ float usage[CPUTIME__NUM]; for (int i = 0; i < lenof(usage); i++) { usage[i] = cpu_timing[i].time / frame_period; } /* Sum the usage times and update the maximum usage if appropriate. */ float usage_total = 0; for (int i = 0; i < lenof(usage); i++) { usage_total += usage[i]; } if (usage_total > usage_max) { usage_max = usage_total; } /* Update the displayed CPU usage percentage twice a second, and log * the current usage if enabled. */ const double now = time_now(); if (now - usage_last_update >= 0.5) { usage_last_update = now; usage_displayed = iroundf(ubound(usage_max,10.0f) * 1000); usage_max = 0; if (do_log_cpu) { DLOG("[%.3f] Usage (%%): render=%.1f debug=%.1f process=%.1f" " GPU=%.1f total=%.1f", now, usage[0]*100, usage[1]*100, usage[2]*100, usage[3]*100, (usage[0]+usage[1]+usage[2]+usage[3])*100); } } } /*-----------------------------------------------------------------------*/ static void check_input(void) { int have_any_touch = 0, have_upper_left = 0, have_lower_left = 0; /* Look up all active touches and copy them into our local array. */ const int num_touches = input_touch_num_touches(); for (int i = 0; i < lenof(active_touches); i++) { active_touches[i].seen_this_time = 0; } for (int i = 0; i < num_touches; i++) { const unsigned int id = input_touch_id_for_index(i); ASSERT(input_touch_active(id), continue); float x, y; input_touch_get_position(id, &x, &y); have_any_touch = 1; if (x < 0.05f && y < 0.05f) { have_upper_left = 1; } else if (x < 0.05f && y > 0.95f) { have_lower_left = 1; } unsigned int j; for (j = 0; j < lenof(active_touches); j++) { if (active_touches[j].id == id) { active_touches[j].seen_this_time = 1; active_touches[j].x = x; active_touches[j].y = y; break; } } if (j >= lenof(active_touches)) { for (j = 0; j < lenof(active_touches); j++) { if (!active_touches[j].id) { active_touches[j].id = id; active_touches[j].seen_this_time = 1; active_touches[j].new_this_time = 1; active_touches[j].x = x; active_touches[j].y = y; break; } } if (j >= lenof(active_touches)) { DLOG("Touch array full, lost touch %u at %.2f,%.2f", id, x, y); } } } for (int i = 0; i < lenof(active_touches); i++) { if (!active_touches[i].seen_this_time) { active_touches[i].id = 0; } } const int lmb = input_mouse_left_button_state(); const int mmb = input_mouse_middle_button_state(); const int rmb = input_mouse_right_button_state(); const int have_3_buttons = lmb && mmb && rmb; const int had_3_buttons = mouse_left && mouse_middle && mouse_right; const int lmb_is_new = !mouse_left; mouse_left = lmb; mouse_middle = mmb; mouse_right = rmb; /* Update input and button state based on the currently active touches. */ if (auto_enabled) { if (!debug_interface_on && have_upper_left && have_lower_left) { debug_interface_on = 1; debug_interface_from_touch = 1; } else if (debug_interface_from_touch && !have_any_touch) { debug_interface_on = 0; debug_interface_from_touch = 0; } if (have_3_buttons && !had_3_buttons) { debug_interface_on = !debug_interface_on; debug_interface_from_touch = 0; if (debug_interface_on) { mouse_pointer_was_on = graphics_get_mouse_pointer_state(); graphics_show_mouse_pointer(1); } else { graphics_show_mouse_pointer(mouse_pointer_was_on); } } } for (int i = 0; i < lenof(debug_buttons); i++) { debug_buttons[i].is_touched = 0; } if (!debug_interface_on) { return; // Nothing else to update. } if (lmb) { float x, y; input_mouse_get_position(&x, &y); const int new_this_time = lmb_is_new; for (int j = 0; j < lenof(debug_buttons); j++) { if (fabsf(x - debug_buttons[j].cx) < debug_buttons[j].width/2 && fabsf(y - debug_buttons[j].cy) < debug_buttons[j].height/2) { debug_buttons[j].is_touched = 1; if (new_this_time) { debug_buttons[j].timer = 0; } } } } for (int i = 0; i < lenof(active_touches); i++) { if (active_touches[i].id) { const float x = active_touches[i].x, y = active_touches[i].y; const int new_this_time = active_touches[i].new_this_time; active_touches[i].new_this_time = 0; for (int j = 0; j < lenof(debug_buttons); j++) { if (fabsf(x - debug_buttons[j].cx) < debug_buttons[j].width/2 && fabsf(y - debug_buttons[j].cy) < debug_buttons[j].height/2) { debug_buttons[j].is_touched = 1; if (new_this_time) { debug_buttons[j].timer = 0; } } } } // if (active_touches[i].object) } } /*-----------------------------------------------------------------------*/ static void update_debug_buttons(void) { static double last_call = 0; const double now = time_now(); if (!last_call) { last_call = now; return; } const float dt = (float)(now - last_call); last_call = now; for (int i = 0; i < lenof(debug_buttons); i++) { if (debug_buttons[i].is_touched) { const float timer = debug_buttons[i].timer; debug_buttons[i].timer += dt; if (strcmp(debug_buttons[i].id, "CPU_DOWN") == 0) { if (timer == 0) { cpu_display_range = lbound(cpu_display_range-1, 1); } } else if (strcmp(debug_buttons[i].id, "CPU_UP") == 0) { if (timer == 0) { cpu_display_range = ubound(cpu_display_range+1, 10); } } else if (strcmp(debug_buttons[i].id, "MEM_TOGGLE") == 0) { if (timer == 0) { if (do_display_memory) { do_display_memory = 0; debug_buttons[i].text = "Off"; } else { do_display_memory = 1; debug_buttons[i].text = "On"; } } } else if (strcmp(debug_buttons[i].id, "CPU_TOGGLE") == 0) { if (timer == 0) { if (do_display_cpu) { do_display_cpu = 0; do_log_cpu = 1; debug_buttons[i].text = "Log"; } else if (do_log_cpu) { do_log_cpu = 0; debug_buttons[i].text = "Off"; } else { do_display_cpu = 1; debug_buttons[i].text = "On"; } } } else { DLOG("Unhandled debug button: %s", debug_buttons[i].id); // NOTREACHED } } } } /*-----------------------------------------------------------------------*/ static void display_debug_ui(void) { const int screen_w = graphics_display_width(); const int screen_h = graphics_display_height(); static const Vector4f color_screen_shade = {1, 0, 0, 0.333f}; static const Vector4f color_ui_background = {0, 0, 0, 0.75f}; static const Vector4f color_ui_text = {1, 1, 1, 1}; static const Vector4f color_button_inactive = {1, 1, 1, 1}; static const Vector4f color_button_active = {0.5f, 0.75f, 1, 1}; static const Vector4f color_button_text = {0, 0, 0, 1}; /* Indicate that the debug UI is active with a translucent red * rectangle over the screen. */ debug_fill_box(0, 0, screen_w, screen_h, &color_screen_shade); /* Draw a shaded background for the button area. */ const int ui_top = iroundf(0.79f*screen_h); const int ui_bottom = screen_h - (do_display_cpu ? debug_text_height()+4 : 0); debug_fill_box(0, ui_top, screen_w, ui_bottom - ui_top, &color_ui_background); /* Draw the CPU meter range. */ const int cpu_text_y = iroundf(0.93f*screen_h) - debug_text_height()/2; debug_draw_text(iroundf(0.15f*screen_w), cpu_text_y, -1, &color_ui_text, "CPU meter range:"); debug_draw_text(iroundf(0.40f*screen_w), cpu_text_y, 0, &color_ui_text, "%d frame%s (%d%% / %.3f sec)", cpu_display_range, cpu_display_range==1 ? "" : "s", cpu_display_range*100, cpu_display_range*get_frame_period()); /* Draw the memory/CPU toggle labels. */ const int memory_text_y = iroundf(0.84f*screen_h) - debug_text_height()/2; debug_draw_text(iroundf(0.82f*screen_w), memory_text_y, -1, &color_ui_text, "Memory meter toggle:"); debug_draw_text(iroundf(0.82f*screen_w), cpu_text_y, -1, &color_ui_text, "CPU meter toggle:"); /* Draw all debug buttons. */ for (int i = 0; i < lenof(debug_buttons); i++) { const int cx = iroundf(debug_buttons[i].cx * screen_w); const int cy = iroundf(debug_buttons[i].cy * screen_h); const int width = iroundf(debug_buttons[i].width * screen_w); const int height = iroundf(debug_buttons[i].height * screen_h); const Vector4f *color = (debug_buttons[i].is_touched ? &color_button_active : &color_button_inactive); debug_fill_box(cx - width/2, cy - height/2, width, height, color); debug_draw_text(cx, cy - debug_text_height()/2, 0, &color_button_text, "%s", debug_buttons[i].text); } } /*-----------------------------------------------------------------------*/ static void display_cpu_usage(void) { static const Vector4f color_background = {0, 0, 0, 0.75f}; static const Vector4f color_cpu_render = {1, 0, 0, 1}; static const Vector4f color_cpu_debug = {1, 1, 0, 1}; static const Vector4f color_cpu_process = {0, 1, 0, 1}; static const Vector4f color_cpu_gpu_wait = {0, 0, 1, 1}; static const Vector4f color_cpu_idle = {0.333f, 0.333f, 0.333f, 1}; static const Vector4f color_cpu_tickmark = {0, 0, 0, 1}; const int space = iroundf(2 * debug_text_scale()); const int x = iroundf(67 * debug_text_scale()) + 2*space; const int y = graphics_display_height() - (debug_text_height() + space); const int w = graphics_display_width() - x; /* Draw a shaded bar as a background for the debug information. */ debug_fill_box( 0, graphics_display_height() - (debug_text_height() + 2*space), graphics_display_width(), graphics_display_height(), &color_background); /* Draw the CPU usage percentage. */ debug_draw_text(space, y, 1, &(const Vector4f){1,1,1,1}, "CPU:"); char buf[7]; if (usage_displayed < 10000) { ASSERT(strformat_check(buf, sizeof(buf), "%3d.%d%%", usage_displayed/10, usage_displayed%10)); } else { ASSERT(strformat_check(buf, sizeof(buf), "---.-%%")); } debug_draw_text(x-space, y, -1, &(const Vector4f){1,1,1,1}, "%s", buf); /* Draw the CPU usage bar. The bar is divided into the following colors: * - Red: Rendering * - Yellow: Debug rendering * - Green: Non-render processing * - Blue: Time spent waiting for the GPU * and tick marks are drawn at 10% increments (~1.68ms for 60fps NTSC). * Note that we currently assume all phases are sequential. */ const float range = cpu_display_range * get_frame_period(); const float avg0 = cpu_timing[CPUTIME_RENDER].average; const float avg1 = avg0 + cpu_timing[CPUTIME_DEBUG].average; const float avg2 = avg1 + cpu_timing[CPUTIME_PROCESS].average; const float avg3 = avg2 + cpu_timing[CPUTIME_GPU_WAIT].average; const int bar0 = iroundf(ubound(avg0 / range, 1) * w); const int bar1 = iroundf(ubound(avg1 / range, 1) * w); const int bar2 = iroundf(ubound(avg2 / range, 1) * w); const int bar3 = iroundf(ubound(avg3 / range, 1) * w); debug_fill_box(x, y, bar0, debug_text_height(), &color_cpu_render); debug_fill_box(x+bar0, y, bar1-bar0, debug_text_height(), &color_cpu_debug); debug_fill_box(x+bar1, y, bar2-bar1, debug_text_height(), &color_cpu_process); debug_fill_box(x+bar2, y, bar3-bar2, debug_text_height(), &color_cpu_gpu_wait); debug_fill_box(x+bar3, y, w-bar3, debug_text_height(), &color_cpu_idle); for (int i = 1; i <= 9; i++) { const int thisx = x + (w*i+5)/10; debug_fill_box(thisx, y, 1, debug_text_height(), &color_cpu_tickmark); } } /*-----------------------------------------------------------------------*/ static void display_memory_usage(void) { static const Vector4f color_background = {0, 0, 0, 0.75f}; static const Vector4f color_text = {1, 1, 1, 1}; static const Vector4f color_sys = {0, 0, 0.8f, 1}; static const Vector4f color_self = {0.6f, 0.4f, 0, 1}; int64_t total = 0, self = 0, avail = 0; if (!sys_debug_get_memory_stats(&total, &self, &avail)) { return; } const int64_t sys = total - self - avail; const int total_width = graphics_display_width(); const int sys_width = iround(((double)sys/total) * total_width); const int self_width = iround(((double)self/total) * total_width); const int space = iroundf(2 * debug_text_scale()); debug_fill_box(0, 0, total_width, debug_text_height()+2*space, &color_background); debug_fill_box(0, space, sys_width, debug_text_height(), &color_sys); debug_fill_box(total_width - self_width, space, self_width, debug_text_height(), &color_self); if (sys > 0) { debug_draw_text(space, space, 1, &color_text, "System: %ldk", (long)(sys/1024)); debug_draw_text((sys_width + (total_width-self_width)) / 2, 2, 0, &color_text, "Free: %ldk", (long)(avail/1024)); } else { debug_draw_text(space, space, 1, &color_text, "Free: %ldk", (long)(avail/1024)); } debug_draw_text(total_width-space, space, -1, &color_text, "Used: %ldk", (long)(self/1024)); } /*-----------------------------------------------------------------------*/ static void debug_flush_render(void) { /* If there's nothing to render, skip out early. */ if (num_fill_vertices == 0 && num_text_vertices == 0) { return; } /* Set up rendering parameters for direct 2D drawing. */ graphics_set_parallel_projection( 0, graphics_display_width(), graphics_display_height(), 0, -1, 1); graphics_set_view_matrix(&mat4_identity); graphics_set_model_matrix(&mat4_identity); graphics_set_viewport( 0, 0, graphics_display_width(), graphics_display_height()); graphics_set_clip_region(0, 0, 0, 0); graphics_set_blend(GRAPHICS_BLEND_ADD, GRAPHICS_BLEND_SRC_ALPHA, GRAPHICS_BLEND_INV_SRC_ALPHA); graphics_enable_alpha_test(0); graphics_enable_depth_test(0); graphics_set_face_cull(GRAPHICS_FACE_CULL_NONE); graphics_set_fixed_color(&(Vector4f){1,1,1,1}); graphics_enable_fog(0); graphics_set_texture_offset(&(Vector2f){0, 0}); /* Draw all filled boxes. */ if (num_fill_vertices > 0) { texture_apply(0, 0); static const uint32_t vertex_format[] = { GRAPHICS_VERTEX_FORMAT(COLOR_4NUB, offsetof(FillVertex,color)), GRAPHICS_VERTEX_FORMAT(POSITION_2S, offsetof(FillVertex,x)), 0 }; graphics_draw_vertices( GRAPHICS_PRIMITIVE_TRIANGLES, fill_vertices, vertex_format, sizeof(*fill_vertices), num_fill_vertices); num_fill_vertices = 0; } /* Draw all text characters. */ if (num_text_vertices > 0) { if (!font_texture) { font_texture = texture_create_with_data( DEBUGFONT_TEXWIDTH, DEBUGFONT_TEXHEIGHT, font_pixels, TEX_FORMAT_A8, DEBUGFONT_TEXWIDTH, 0, 0); if (UNLIKELY(!font_texture)) { DLOG("Failed to create debug font texture"); } texture_set_repeat(font_texture, 0, 0); texture_set_antialias(font_texture, 1); } texture_apply(0, font_texture); static const uint32_t vertex_format[] = { GRAPHICS_VERTEX_FORMAT(TEXCOORD_2F, offsetof(TextVertex,u)), GRAPHICS_VERTEX_FORMAT(COLOR_4NUB, offsetof(TextVertex,color)), GRAPHICS_VERTEX_FORMAT(POSITION_2F, offsetof(TextVertex,x)), 0 }; graphics_draw_vertices( GRAPHICS_PRIMITIVE_TRIANGLES, text_vertices, vertex_format, sizeof(*text_vertices), num_text_vertices); texture_apply(0, 0); num_text_vertices = 0; } } /*-----------------------------------------------------------------------*/ static PURE_FUNCTION float debug_text_scale(void) { return lbound(graphics_display_height() / 720.0f, 0.75f); } /*************************************************************************/ /*************************************************************************/ #endif // DEBUG