diff --git a/demo/src/common.c b/demo/src/common.c index 9da766a..78071e5 100644 --- a/demo/src/common.c +++ b/demo/src/common.c @@ -8,6 +8,7 @@ static char buffer[4096] = {}; +static Sound beep; static void scanDirectoryRecursive(const char *path, char **outTextBegin, char *outTextEnd, int level) { @@ -61,12 +62,26 @@ static void scanDirectoryRecursive(const char *path, char **outTextBegin, char * void commonInit() { char *bufPtr = buffer; scanDirectoryRecursive("data", &bufPtr, bufPtr + sizeof(buffer) - 1, 0); + beep = createSound("data/sound/beep.ogg"); } void commonDraw() { + pushDrawingState(); + textFontDefault(); textSize(16); text(buffer, 16, 16); + + if (mouseWentDown("left")) + soundPlay(beep, FALSE); + + if (mouseWentDown("middle")) { + char text[1000]; + askTextEx("Test?", text, sizeof(text), TRUE, FALSE); + } + + if (mouseWentDown("right")) + messageBox("Test message box\nwith test message."); + + popDrawingState(); } - - diff --git a/demo/src/drawing.c b/demo/src/drawing.c index de2c855..48e50df 100644 --- a/demo/src/drawing.c +++ b/demo/src/drawing.c @@ -13,6 +13,8 @@ void drawingInit() { void drawingDraw() { + pushDrawingState(); + double x = 512; double y = 512 - 64; @@ -53,7 +55,6 @@ void drawingDraw() { lineTo(x, y + 48); lineTo(x + 24, y + 24); closePath(); - stroke("black"); -} - + popDrawingState(); +} diff --git a/demo/src/font.c b/demo/src/font.c index 0231bfe..a8326b3 100644 --- a/demo/src/font.c +++ b/demo/src/font.c @@ -16,6 +16,8 @@ void fontInit() { void fontDraw() { + pushDrawingState(); + double x = 512; double y = 256; @@ -26,8 +28,7 @@ void fontDraw() { textAlign(HALIGN_RIGHT, VALIGN_TOP); text("Here is the\nright aligned\ntext. VAW.", x, y); - textFontDefault(); - textAlign(HALIGN_LEFT, VALIGN_TOP); + popDrawingState(); } diff --git a/demo/src/phisics.c b/demo/src/phisics.c index fe7fa29..bd9f06f 100644 --- a/demo/src/phisics.c +++ b/demo/src/phisics.c @@ -8,7 +8,6 @@ static Sprite ball, brick1, brick2, brick3; static Group edges; static Group movement; - static Sound beep; @@ -43,7 +42,6 @@ void phisicsInit() { groupAdd(edges, brick1); groupAdd(edges, brick3); - beep = createSound("data/sound/beep.ogg"); } @@ -59,12 +57,6 @@ void phisicsDraw() { if (keyDown("up")) spriteSetVelocityY(ball, vy - accel*dt); if (keyDown("down")) spriteSetVelocityY(ball, vy + accel*dt); - if (mouseWentDown("left")) soundPlay(beep, FALSE); - if (mouseWentDown("middle")) { - char text[1000]; - askTextEx("Test?", text, sizeof(text), TRUE, FALSE); - } - int collision = FALSE; if (groupCollideBetween(movement, 1)) collision = TRUE; if (groupPushGroup(edges, movement, 0.9)) collision = TRUE; diff --git a/demo/src/sprites.c b/demo/src/sprites.c index cbac25e..4c746e9 100644 --- a/demo/src/sprites.c +++ b/demo/src/sprites.c @@ -89,6 +89,7 @@ void spritesInit() { x += 48/2 - w/2; s = createSpriteEx(x, y, w, h); spriteSetAnimation(s, "data/sprite/snake.png"); + spriteSetDebug(s, TRUE); groupAdd(pulse, s); } diff --git a/src/drawing.c b/src/drawing.c index 3b8deb9..62e0113 100644 --- a/src/drawing.c +++ b/src/drawing.c @@ -4,16 +4,23 @@ #include "drawing.h" -double heliDrawingColorStroke[4] = {0, 0, 0, 1}; - -#define colorStroke heliDrawingColorStroke static double colorBack[4] = {1, 1, 1, 1}; -static double colorFill[4] = {0.5, 0.5, 0.5, 1}; -static double lineWidth = 1; static double *path; static size_t pathSize; static size_t pathAllocated; +static HeliDrawingState statesStack[1024] = {{ + {0, 0, 0, 1}, // colorStroke + {0.5, 0.5, 0.5, 1}, // colorFill + 1, // lineWidth + HALIGN_LEFT, // horAlign + VALIGN_TOP, // vertAlign + NULL, // font + 24 // fontSize +}}; +static int statesStackIndex = 0; + + typedef struct _HeliStrokePoint { double x, y, dx, dy; @@ -25,8 +32,6 @@ typedef struct _HeliStroke { int allocatedCount; } HeliStroke; - - static void endPath(int close, int stroke, int fill, int fillSimple); static void closePathSimple() @@ -36,16 +41,16 @@ static void closePathSimple() void background(const char *color) { heliParseColor(color, colorBack); } void fill(const char *color) - { heliParseColor(color, colorFill); } + { heliParseColor(color, heliDrawingGetState()->colorFill); } void noFill() { fill("transparent"); } void stroke(const char *color) - { heliParseColor(color, colorStroke); } + { heliParseColor(color, heliDrawingGetState()->colorStroke); } void noStroke() { stroke("transparent"); } void strokeWeight(double weight) - { lineWidth = weight; } + { heliDrawingGetState()->lineWidth = weight; } const char* rgba(double r, double g, double b, double a) { static char buf[1024]; @@ -79,13 +84,12 @@ void ellipse(double x, double y, double width, double height) { } void point(double x, double y) { - double color[4]; - memcpy(color, colorFill, sizeof(color)); - memcpy(colorFill, colorStroke, sizeof(colorFill)); - colorStroke[3] = 0; - ellipse(x - lineWidth*0.5, y - lineWidth*0.5, lineWidth, lineWidth); - colorStroke[3] = colorFill[3]; - memcpy(colorFill, color, sizeof(colorFill)); + pushDrawingState(); + HeliDrawingState *s = heliDrawingGetState(); + memcpy(s->colorFill, s->colorStroke, sizeof(s->colorFill)); + s->colorStroke[3] = 0; + ellipse(x - s->lineWidth*0.5, y - s->lineWidth*0.5, s->lineWidth, s->lineWidth); + popDrawingState(); } void arcPath(double x, double y, double w, double h, double start, double stop) { @@ -136,10 +140,11 @@ void resetPath() { pathSize = 0; } static void drawFillSimple() { - if (colorFill[3] <= HELI_PRECISION) return; + HeliDrawingState *s = heliDrawingGetState(); + if (s->colorFill[3] <= HELI_PRECISION) return; if (pathSize < 6) return; - glColor4dv(colorFill); + glColor4dv(s->colorFill); glEnable(GL_MULTISAMPLE); glBegin(GL_TRIANGLE_FAN); for(int i = 0; i < pathSize; i += 2) @@ -150,7 +155,8 @@ static void drawFillSimple() { } static void drawFill() { - if (colorFill[3] <= HELI_PRECISION) return; + HeliDrawingState *s = heliDrawingGetState(); + if (s->colorFill[3] <= HELI_PRECISION) return; if (pathSize < 6) return; double l = path[0], r = l; @@ -167,7 +173,7 @@ static void drawFill() { t -= 1; b += 1; glEnable(GL_MULTISAMPLE); - glColor4dv(colorFill); + glColor4dv(s->colorFill); glEnable(GL_STENCIL_TEST); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); @@ -332,15 +338,16 @@ static void strokeDraw(HeliStroke *stroke, double w, double *color) { static void drawStroke(int close) { - if (colorStroke[3] <= HELI_PRECISION) return; - if (lineWidth < HELI_PRECISION) return; + HeliDrawingState *s = heliDrawingGetState(); + if (s->colorStroke[3] <= HELI_PRECISION) return; + if (s->lineWidth < HELI_PRECISION) return; if (pathSize < 4) return; HeliStroke stroke = {}; stroke.allocatedCount = pathSize; stroke.points = calloc(stroke.allocatedCount, sizeof(*stroke.points)); - double w = 0.5*lineWidth; + double w = 0.5*s->lineWidth; double precisionSqr = 1/(w*0.75); precisionSqr *= precisionSqr; @@ -361,7 +368,7 @@ static void drawStroke(int close) { stroke.points[0].y, stroke.points[0].dx, stroke.points[0].dy ); - strokeDraw(&stroke, w, colorStroke); + strokeDraw(&stroke, w, s->colorStroke); stroke.count = 0; @@ -381,7 +388,7 @@ static void drawStroke(int close) { stroke.points[0].y, stroke.points[0].dx, stroke.points[0].dy ); - strokeDraw(&stroke, w, colorStroke); + strokeDraw(&stroke, w, s->colorStroke); } else { double px = 0, py = 0, nx = 0, ny = 0; for(int i = 0; i < pathSize; i += 2) { @@ -402,7 +409,7 @@ static void drawStroke(int close) { strokeAddCorner(&stroke, px, py, x, y, nx, ny, precisionSqr); } memcpy(stroke.points + stroke.count - 1, stroke.points, sizeof(*stroke.points)); - strokeDraw(&stroke, w, colorStroke); + strokeDraw(&stroke, w, s->colorStroke); } free(stroke.points); @@ -461,6 +468,30 @@ void moveTo(double x, double y) { resetPath(); lineTo(x, y); } +HeliDrawingState *heliDrawingGetState() + { return statesStack + statesStackIndex; } + +HeliDrawingState *heliDrawingGetStateStack() + { return statesStack; } + +void pushDrawingState() { + if (statesStackIndex >= sizeof(statesStack)/sizeof(*statesStack) - 1) { + fprintf(stderr, "helianthus: drawing stack overflow\n"); + return; + } + ++statesStackIndex; + memcpy(statesStack + statesStackIndex, statesStack + statesStackIndex - 1, sizeof(*statesStack)); +} + +void popDrawingState() { + assert(statesStackIndex > 0); + if (statesStackIndex <= 0) { + fprintf(stderr, "helianthus: drawing stack underflow\n"); + return; + } + --statesStackIndex; +} + void heliDrawingClearFrame() { glClearColor(colorBack[0], colorBack[1], colorBack[2], colorBack[3]); glClear(GL_COLOR_BUFFER_BIT); @@ -468,6 +499,11 @@ void heliDrawingClearFrame() { void heliDrawingPrepareFrame() { resetPath(); + if (statesStackIndex > 0) { + //fprintf(stderr, "helianthus: drawing stack was not empty at end of frame\n"); + while(statesStackIndex > 0) popDrawingState(); + } + heliDrawingClearFrame(); glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); diff --git a/src/drawing.h b/src/drawing.h index a8fbe64..72d2fa0 100644 --- a/src/drawing.h +++ b/src/drawing.h @@ -6,13 +6,19 @@ void background(const char *color); + void fill(const char *color); void noFill(); void stroke(const char *color); void noStroke(); void strokeWeight(double weight); + +void pushDrawingState(); +void popDrawingState(); + const char* rgb(double r, double g, double b); const char* rgba(double r, double g, double b, double a); + void rect(double x, double y, double width, double height); void ellipse(double x, double y, double width, double height); void arc(double x, double y, double w, double h, double start, double stop); diff --git a/src/font.c b/src/font.c index 3b02ccd..2b8bd87 100644 --- a/src/font.c +++ b/src/font.c @@ -74,14 +74,7 @@ static HeliArray fontCache; static HeliFontMap *fontMapFirst, *fontMapLast; static HeliGlyph blankGlyph; static const char blankPath[] = ""; - -static HAlign horAlign = HALIGN_LEFT; -static VAlign vertAlign = VALIGN_TOP; -static Font font; -static Font defaultFont; -static double fontSize = 24; - - +static Font defaultFont = NULL; static HeliFontMap* createFontMap() { HeliFontMap *map = calloc(1, sizeof(*map)); @@ -227,13 +220,13 @@ static HeliFontInstance* loadFont(const char *path) { if (!ftInitialized) { if (FT_Init_FreeType(&ftLibrary)) - printf("Cannot initialize FreeType library"); + fprintf(stderr, "helianthus: cannot initialize FreeType library\n"); ftInitialized = TRUE; } if (ftLibrary) { if (path[0]) { if (FT_New_Face(ftLibrary, path, 0, &fi->face)) { - printf("Cannot load font from file: %s", path); + fprintf(stderr, "helianthus: cannot load font from file: %s\n", path); fi->face = NULL; } } else { @@ -242,7 +235,7 @@ static HeliFontInstance* loadFont(const char *path) { args.memory_base = (FT_Byte*)heliBlobDefaultFont; args.memory_size = heliBlobDefaultFontSize; if (FT_Open_Face(ftLibrary, &args, 0, &fi->face)) { - printf("Cannot initialize default font"); + fprintf(stderr, "helianthus: cannot initialize default font\n"); fi->face = NULL; } } @@ -289,31 +282,39 @@ Font createFont(const char *path) { void fontDestroy(Font f) { heliObjectUnregister(f); - if (font == f) font = NULL; + HeliDrawingState *ss = heliDrawingGetState(); + for(HeliDrawingState *s = heliDrawingGetStateStack(); s <= ss; ++s) + { if (ss->font == f) ss->font = NULL; } --f->instance->refcount; if (f->instance->refcount <= 0) heliStringmapRemove(&fontCache, f->instance->path); free(f); } -void textAlign(HAlign hor, VAlign vert) - { horAlign = hor; vertAlign = vert; } +void textAlign(HAlign hor, VAlign vert) { + HeliDrawingState *s = heliDrawingGetState(); + s->horAlign = hor; + s->vertAlign = vert; +} void textFontDefault() - { font = NULL; } + { heliDrawingGetState()->font = NULL; } void textFont(Font f) - { font = f; } + { heliDrawingGetState()->font = f; } void textSize(double size) - { fontSize = size; } + { heliDrawingGetState()->fontSize = size; } void text(const char *text, double x, double y) { resetPath(); - double fontScale = fontSize/FONT_BASE_SIZE; + HeliDrawingState *drawingState = heliDrawingGetState(); + + double fontScale = drawingState->fontSize/FONT_BASE_SIZE; if (fontScale < HELI_PRECISION) return; + if (drawingState->colorStroke[3] < HELI_PRECISION) return; if (!defaultFont) defaultFont = createFont(NULL); - HeliFontInstance *f = font ? font->instance : NULL; + HeliFontInstance *f = drawingState->font ? drawingState->font->instance : NULL; HeliFontInstance *ff = defaultFont ? defaultFont->instance : NULL; if (!f) f = ff; if (!ff) ff = f; @@ -417,14 +418,14 @@ void text(const char *text, double x, double y) { } // alignment - double dy = vertAlign == VALIGN_BOTTOM ? -b - : vertAlign == VALIGN_CENTER ? -0.5*(t + b) - : -t; + double dy = drawingState->vertAlign == VALIGN_BOTTOM ? -b + : drawingState->vertAlign == VALIGN_CENTER ? -0.5*(t + b) + : -t; for(int i = 0; i < linesCount; ++i) { HeliLineDesc *line = &lines[i]; - line->x = horAlign == HALIGN_RIGHT ? -line->r - : horAlign == HALIGN_CENTER ? -0.5*(line->l + line->r) - : -line->l; + line->x = drawingState->horAlign == HALIGN_RIGHT ? -line->r + : drawingState->horAlign == HALIGN_CENTER ? -0.5*(line->l + line->r) + : -line->l; line->y += dy; for(int j = line->begin; j < line->end; ++j) { HeliCharDesc *cc = &chars[j]; @@ -460,7 +461,7 @@ void text(const char *text, double x, double y) { glPushMatrix(); glTranslated(x, y, 0); glScaled(fontScale, fontScale, 1); - glColor4dv(heliDrawingColorStroke); + glColor4dv(drawingState->colorStroke); HeliFontMap *currentMap = NULL; glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); diff --git a/src/private.h b/src/private.h index 95d9ebf..8fd29c6 100644 --- a/src/private.h +++ b/src/private.h @@ -11,6 +11,7 @@ #include "common.h" #include "sprite.h" +#include "font.h" // globals @@ -134,7 +135,18 @@ void heliSpriteFinish(); // drawing -extern double heliDrawingColorStroke[4]; +typedef struct _HeliDrawingState { + double colorStroke[4]; + double colorFill[4]; + double lineWidth; + HAlign horAlign; + VAlign vertAlign; + Font font; + double fontSize; +} HeliDrawingState; + +HeliDrawingState *heliDrawingGetState(); +HeliDrawingState *heliDrawingGetStateStack(); void heliDrawingClearFrame(); void heliDrawingPrepareFrame(); void heliDrawingFinish(); diff --git a/src/sprite.c b/src/sprite.c index 5c63b32..64215c1 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -4,6 +4,7 @@ #include "sprite.h" #include "world.h" #include "group.h" +#include "drawing.h" struct _Sprite { @@ -360,42 +361,47 @@ Sprite worldGetSprite(int i) static void drawSpriteDebug(Sprite s) { - /* TODO:bw - cairo_save(cr); - cairo_set_line_width(cr, 0.5); - cairo_translate(cr, s->x, s->y); - cairo_rotate(cr, s->rotation*(PI/180)); - cairo_scale(cr, s->scale*s->mirrorX, s->scale*s->mirrorY); - - double hw = s->width*0.5; - double hh = s->height*0.5; - - cairo_set_source_rgba(cr, 0, 0, 0, 0.75); - cairo_move_to(cr, -hw, -hh); - cairo_line_to(cr, hw, -hh); - cairo_line_to(cr, hw, hh); - cairo_line_to(cr, -hw, hh); - cairo_close_path(cr); - cairo_stroke(cr); - - cairo_move_to(cr, -hw*0.25, 0); - cairo_line_to(cr, hw*0.25, 0); - cairo_move_to(cr, 0, -hh*0.25); - cairo_line_to(cr, 0, hh*0.25); - cairo_stroke(cr); + pushDrawingState(); + strokeWeight(0.5); + double a = s->rotation*(PI/180); + double sn = sin(a); + double cs = cos(a); + double hw = 0.5 * s->scale * s->mirrorX * s->width; + double hh = 0.5 * s->scale * s->mirrorX * s->height; + + double ltx = -hw*cs + hh*sn; + double lty = -hw*sn - hh*cs; + double rtx = hw*cs + hh*sn; + double rty = hw*sn - hh*cs; + + fill("transparent"); + stroke(rgba(0, 0, 0, 0.75)); + + // frame + moveTo(s->x + ltx, s->y + lty); + lineTo(s->x + rtx, s->y + rty); + lineTo(s->x - ltx, s->y - lty); + lineTo(s->x - rtx, s->y - rty); + closePath(); + + // center cross + line( s->x - cs*hw*0.25, s->y - sn*hw*0.25, + s->x + cs*hw*0.25, s->y + sn*hw*0.25 ); + line( s->x + sn*hh*0.25, s->y - cs*hh*0.25, + s->x - sn*hh*0.25, s->y + cs*hh*0.25 ); + + // depth + stroke(rgba(0, 0, 0, 0.75)); char buf[1024]; snprintf(buf, sizeof(buf)-1, "%lf", s->depth); - double s1 = hw*0.25; double s2 = hh*0.5; - cairo_set_font_size(cr, s1 < s2 ? s1 : s2); - - cairo_move_to(cr, -hw*0.9, -hh*0.5); - cairo_show_text(cr, buf); - - cairo_restore(cr); - */ + textSize(s1 < s2 ? s1 : s2); + textAlign(HALIGN_CENTER, VALIGN_CENTER); + text(buf, s->x, s->y); + + popDrawingState(); } static void drawSprite(Sprite s) { diff --git a/src/world.c b/src/world.c index 16dae1c..b2a886e 100644 --- a/src/world.c +++ b/src/world.c @@ -190,6 +190,15 @@ void cameraSetZoom(double x) { cameraZoom = x > HELI_PRECISION ? x : HELI_PRECISION; } +void messageBox(const char *message) { + SDL_ShowSimpleMessageBox( + SDL_MESSAGEBOX_INFORMATION, + title, + message, + window ); +} + + static void draw() { unsigned int currentFrameTimeMs = SDL_GetTicks(); unsigned long long deltaUs = frameCount == 0 ? 0 : (currentFrameTimeMs - prevFrameTimeMs)*1000ull; @@ -248,7 +257,7 @@ static void deinit() { static int init() { if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { - printf("SDL_Init failed\n"); + fprintf(stderr, "helianthus: SDL_Init failed\n"); deinit(); return FALSE; } @@ -274,7 +283,7 @@ static int init() { flags ); if (!window) { - printf("Cannot create window: %s\n", SDL_GetError()); + fprintf(stderr, "helianthus: cannot create window: %s\n", SDL_GetError()); SDL_ClearError(); deinit(); return FALSE; @@ -282,7 +291,7 @@ static int init() { context = SDL_GL_CreateContext(window); if (!context) { - printf("Cannot create OpenGL context: %s\n", SDL_GetError()); + fprintf(stderr, "helianthus: cannot create OpenGL context: %s\n", SDL_GetError()); SDL_ClearError(); deinit(); return FALSE; diff --git a/src/worldui.c b/src/worldui.c index 63ea577..2876efa 100644 --- a/src/worldui.c +++ b/src/worldui.c @@ -6,11 +6,6 @@ #include "world.h" -void messageBox(const char *message) { - // TODO:bw -} - - void askTextEx(const char *question, char *answer, int maxAnswerSize, int multiline, int password) { // TODO:bw }