diff --git a/demo/src/SConstruct b/demo/src/SConstruct index 269edf8..69ea914 100644 --- a/demo/src/SConstruct +++ b/demo/src/SConstruct @@ -8,7 +8,7 @@ env['ENV']['PKG_CONFIG_PATH'] = os.environ.get('PKG_CONFIG_PATH') # config libs = ['helianthus'] -flags = ' -O0 -g -lm -Wall -fmessage-length=0 ' +flags = ' -O0 -g -lm -Wall -fmessage-length=0 -fdebug-prefix-map=src=demo/src ' # files diff --git a/demo/src/common.c b/demo/src/common.c index b29c50a..8a05859 100644 --- a/demo/src/common.c +++ b/demo/src/common.c @@ -67,7 +67,7 @@ void commonInit() { } void commonDraw() { - pushDrawingState(); + saveState(); int shift = keyDown("left shift") || keyDown("right shift"); int ctrl = keyDown("left ctrl") || keyDown("right ctrl"); @@ -90,5 +90,5 @@ void commonDraw() { if (mouseWentDown("right")) messageBox("Test message box\nwith test message."); - popDrawingState(); + restoreState(); } diff --git a/demo/src/drawing.c b/demo/src/drawing.c index 48e50df..0cea3d0 100644 --- a/demo/src/drawing.c +++ b/demo/src/drawing.c @@ -6,19 +6,22 @@ #include "drawing.h" +static Animation texture; + void drawingInit() { background("yellow"); + texture = createAnimationEx("data/sprite/bricks-tile.png", TRUE, TRUE); } void drawingDraw() { - pushDrawingState(); + saveState(); double x = 512; double y = 512 - 64; - strokeWeight(20); + strokeWidth(20); fill("red"); stroke("blue"); rect(x, y, 48*2, 48); @@ -48,7 +51,9 @@ void drawingDraw() { strokePath(); x += 64; - fill("blue"); stroke("transparent"); + fill("red"); + fillTexture(texture, 0, 0, 32, 32, FALSE); + stroke("transparent"); moveTo(x, y + 24); arcPath(x, y, 48, 48, 180, 360); lineTo(x + 48, y + 48); @@ -56,5 +61,5 @@ void drawingDraw() { lineTo(x + 24, y + 24); closePath(); - popDrawingState(); + restoreState(); } diff --git a/demo/src/font.c b/demo/src/font.c index c109d22..c4b8673 100644 --- a/demo/src/font.c +++ b/demo/src/font.c @@ -16,7 +16,7 @@ void fontInit() { void fontDraw() { - pushDrawingState(); + saveState(); double x = 512; double y = 256; @@ -30,7 +30,7 @@ void fontDraw() { textAlign(HALIGN_RIGHT, VALIGN_TOP); text("Here is the\nright aligned\ntext. VAW.", x, y); - popDrawingState(); + restoreState(); } diff --git a/demo/src/main.c b/demo/src/main.c index f83d315..46d8df4 100644 --- a/demo/src/main.c +++ b/demo/src/main.c @@ -24,11 +24,11 @@ void draw() { fontDraw(); drawSprites(); - pushDrawingState(); + saveState(); stroke("red"); - strokeWeight(20); + strokeWidth(20); point(mouseX(), mouseY()); - popDrawingState(); + restoreState(); } int main() { diff --git a/src/SConstruct b/src/SConstruct index f69b2a6..eeb54da 100644 --- a/src/SConstruct +++ b/src/SConstruct @@ -55,6 +55,7 @@ sources = [ 'drawing.c', 'font.c', 'geometry.c', + 'gl.c', 'group.c', 'test.c', 'sound.c', diff --git a/src/animation.h b/src/animation.h index 009b420..883beeb 100644 --- a/src/animation.h +++ b/src/animation.h @@ -45,5 +45,6 @@ int animationGetFrame(Animation animation); void animationSetFrame(Animation animation, int frame); void animationNextFrame(Animation animation); + #endif diff --git a/src/drawing.c b/src/drawing.c index 7c46833..e9d94ab 100644 --- a/src/drawing.c +++ b/src/drawing.c @@ -10,13 +10,13 @@ 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 + 0, // flags + {0.5, 0.5, 0.5, 1}, // fillColor + {0, 0, 0, 1}, // strokeColor + 1, // lineWidth + HALIGN_LEFT, // horAlign + VALIGN_TOP, // vertAlign + 24 // fontSize }}; static int statesStackIndex = 0; @@ -38,19 +38,72 @@ static void closePathSimple() { endPath(TRUE, TRUE, FALSE, TRUE); } +void heliDrawingApplyTexture(double *color, HeliTextureState *state) { + glColor4dv(color); + unsigned int texid = state->animation ? animationGetGLTexId(state->animation) : 0; + if (texid) { + unsigned int mode = state->fixed ? GL_EYE_LINEAR : GL_OBJECT_LINEAR; + unsigned int param = state->fixed ? GL_EYE_PLANE : GL_OBJECT_PLANE; + + double kx = fabs(state->width) > HELI_PRECISION ? 1/state->width + : state->width < 0 ? -HELI_PRECISION : HELI_PRECISION; + double ky = fabs(state->height) > HELI_PRECISION ? 1/state->height + : state->height < 0 ? -HELI_PRECISION : HELI_PRECISION; + double x[4] = { kx, 0, 0, -state->x*kx }; + double y[4] = { 0, ky, 0, -state->y*ky }; + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texid); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, mode); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, mode); + glTexGendv(GL_S, param, x); + glTexGendv(GL_T, param, y); + } +} + +void heliDrawingResetTexture() { + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + glDisable(GL_TEXTURE_2D); + glColor4d(1, 1, 1, 1); +} + + void background(const char *color) { heliParseColor(color, colorBack); } void fill(const char *color) - { heliParseColor(color, heliDrawingGetState()->colorFill); } + { heliParseColor(color, heliDrawingGetState()->fillColor); } void noFill() { fill("transparent"); } +void fillTexture(Animation animation, double x, double y, double width, double height, int fixed) { + HeliTextureState *s = &heliDrawingGetState()->fillTexture; + s->animation = animation; + s->x = x; + s->y = y; + s->width = width; + s->height = height; + s->fixed = fixed != 0; +} + void stroke(const char *color) - { heliParseColor(color, heliDrawingGetState()->colorStroke); } + { heliParseColor(color, heliDrawingGetState()->strokeColor); } void noStroke() { stroke("transparent"); } +void strokeTexture(Animation animation, double x, double y, double width, double height, int fixed) { + HeliTextureState *s = &heliDrawingGetState()->strokeTexture; + s->animation = animation; + s->x = x; + s->y = y; + s->width = width; + s->height = height; + s->fixed = fixed != 0; +} -void strokeWeight(double weight) - { heliDrawingGetState()->lineWidth = weight; } +void strokeWidth(double width) + { heliDrawingGetState()->strokeWidth = width; } const char* rgba(double r, double g, double b, double a) { static char buf[1024]; @@ -87,11 +140,12 @@ void noClip() void rect(double x, double y, double width, double height) { resetPath(); + heliFillRectSimple(x, y, x+width, y+height, heliGLGetAAResolution()); moveTo(x, y); lineTo(x + width, y); lineTo(x + width, y + height); lineTo(x, y + height); - closePathSimple(); + endPath(TRUE, TRUE, FALSE, FALSE); } void line(double x1, double y1, double x2, double y2) { @@ -103,17 +157,25 @@ void line(double x1, double y1, double x2, double y2) { void ellipse(double x, double y, double width, double height) { resetPath(); - arcPath(x, y, width, height, 0, 360); - closePathSimple(); + if (fabs(fabs(width) - fabs(height)) <= HELI_PRECISION) { + heliFillCircleSimple(x + 0.5*width, y + 0.5*height, 0.5*width, heliGLGetAAResolution()); + arcPath(x, y, width, height, 0, 360); + endPath(TRUE, TRUE, FALSE, FALSE); + } else { + arcPath(x, y, width, height, 0, 360); + closePathSimple(); + } } void point(double x, double y) { - pushDrawingState(); + saveStateEx(STATE_FILL | STATE_STROKE); 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(); + memcpy(&s->fillColor, &s->strokeColor, sizeof(s->fillColor)); + memcpy(&s->fillTexture, &s->strokeTexture, sizeof(s->fillTexture)); + noStroke(); + if (s->strokeWidth > HELI_PRECISION) + ellipse(x - s->strokeWidth*0.5, y - s->strokeWidth*0.5, s->strokeWidth, s->strokeWidth); + restoreState(); } void arcPath(double x, double y, double w, double h, double start, double stop) { @@ -163,24 +225,144 @@ void regularPolygon(double x, double y, int sides, double size) { void resetPath() { pathSize = 0; } + +void heliFillCircleSimple(double x, double y, double r, double aaBorder) { + r = fabs(r); + if (r < HELI_PRECISION) return; + + HeliDrawingState *s = heliDrawingGetState(); + if (s->fillColor[3] <= HELI_PRECISION) return; + + heliDrawingApplyTexture(s->fillColor, &s->fillTexture); + + double step = 1/r; + if (step > PI/180) step = PI/180; + if (aaBorder < HELI_PRECISION) { + glEnable(GL_MULTISAMPLE); + glBegin(GL_TRIANGLE_FAN); + for(double a = 0; a < 2*PI; a += step) glVertex2d(x + cos(a)*r, y + sin(a)*r); + glEnd(); + glDisable(GL_MULTISAMPLE); + } else { + double color[4] = { s->fillColor[0], s->fillColor[1], s->fillColor[2], s->fillColor[3] }; + double sideColor[4] = { color[0], color[1], color[2], 0 }; + double r1 = r + 0.5*aaBorder; + double r0 = r - 0.5*aaBorder; + if (r0 > HELI_PRECISION) { + glBegin(GL_TRIANGLE_FAN); + for(double a = 0; a < 2*PI; a += step) glVertex2d(x + cos(a)*r0, y + sin(a)*r0); + glEnd(); + } else { + color[3] *= r/aaBorder; + r0 = 0; + } + glBegin(GL_TRIANGLE_STRIP); + for(double a = step; a < 2*PI; a += step) { + double s = sin(a), c = cos(a); + glColor4dv(color); + glVertex2d(x + c*r0, y + s*r0); + glColor4dv(sideColor); + glVertex2d(x + c*r1, y + s*r1); + } + glEnd(); + } +} + + +void heliFillRectSimple(double x0, double y0, double x1, double y1, double aaBorder) { + if (fabs(x1 - x0) < HELI_PRECISION || fabs(y1 - y0) < HELI_PRECISION) return; + + HeliDrawingState *s = heliDrawingGetState(); + if (s->fillColor[3] <= HELI_PRECISION) return; + + heliDrawingApplyTexture(s->fillColor, &s->fillTexture); + if (aaBorder <= HELI_PRECISION) { + glEnable(GL_MULTISAMPLE); + glBegin(GL_QUADS); + glVertex2d(x0, y0); + glVertex2d(x1, y0); + glVertex2d(x1, y1); + glVertex2d(x0, y1); + glEnd(); + glDisable(GL_MULTISAMPLE); + } else { + double color[4] = { s->fillColor[0], s->fillColor[1], s->fillColor[2], s->fillColor[3] }; + double sideColor[4] = { color[0], color[1], color[2], 0 }; + + if (x1 < x0) { double x = x0; x0 = x1; x1 = x; } + if (y1 < y0) { double y = y0; y0 = y1; y1 = y; } + double x = (x1 + x0)*0.5; + double y = (y1 + y0)*0.5; + double hw = (x1 - x0)*0.5; + double hh = (y1 - y0)*0.5; + + double w0 = hw - 0.5*aaBorder; + double w1 = hw + 0.5*aaBorder; + if (w0 < HELI_PRECISION) w0 = 0; + double h0 = hh - 0.5*aaBorder; + double h1 = hh + 0.5*aaBorder; + if (h0 < HELI_PRECISION) h0 = 0; + + const double k = (w1 < aaBorder ? w1/aaBorder : 1) + * (h1 < aaBorder ? h1/aaBorder : 1); + color[3] *= k; + + const int vcnt = 14; + + const double vertices[][2] = { + { -w1, -h1 }, { -w0, -h0 }, + { w1, -h1 }, { w0, -h0 }, + { w1, h1 }, { w0, h0 }, + { -w1, h1 }, { -w0, h0 }, + { -w1, -h1 }, { -w0, -h0 }, + { -w0, -h0 }, + { w0, -h0 }, + { -w0, h0 }, + { w0, h0 } }; + + const double *colors[] = { + sideColor, color, + sideColor, color, + sideColor, color, + sideColor, color, + sideColor, color, + color, + color, + color, + color }; + + glPushMatrix(); + glTranslated(x, y, 0); + glBegin(GL_TRIANGLE_STRIP); + for(int i = 0; i < vcnt; ++i) { + glColor4dv(colors[i]); + glVertex2dv(vertices[i]); + } + glEnd(); + glPopMatrix(); + } + heliDrawingResetTexture(); +} + + static void drawFillSimple() { HeliDrawingState *s = heliDrawingGetState(); - if (s->colorFill[3] <= HELI_PRECISION) return; + if (s->fillColor[3] <= HELI_PRECISION) return; if (pathSize < 6) return; - glColor4dv(s->colorFill); + heliDrawingApplyTexture(s->fillColor, &s->fillTexture); glEnable(GL_MULTISAMPLE); glBegin(GL_TRIANGLE_FAN); for(int i = 0; i < pathSize; i += 2) glVertex2dv(&path[i]); glEnd(); glDisable(GL_MULTISAMPLE); - glColor4d(1, 1, 1, 1); + heliDrawingResetTexture(); } static void drawFill() { HeliDrawingState *s = heliDrawingGetState(); - if (s->colorFill[3] <= HELI_PRECISION) return; + if (s->fillColor[3] <= HELI_PRECISION) return; if (pathSize < 6) return; double l = path[0], r = l; @@ -197,7 +379,6 @@ static void drawFill() { t -= 1; b += 1; glEnable(GL_MULTISAMPLE); - glColor4dv(s->colorFill); glEnable(GL_STENCIL_TEST); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); @@ -239,17 +420,19 @@ static void drawFill() { glStencilFunc(GL_NOTEQUAL, 0, -1u); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + heliDrawingApplyTexture(s->fillColor, &s->fillTexture); glBegin(GL_QUADS); glVertex2d(l, t); glVertex2d(r, t); glVertex2d(r, b); glVertex2d(l, b); glEnd(); + heliDrawingResetTexture(); glStencilFunc(GL_ALWAYS, 0, -1u); glDisable(GL_STENCIL_TEST); glDisable(GL_MULTISAMPLE); - glColor4d(1, 1, 1, 1); } static void strokeAddPoint(HeliStroke *stroke, double x, double y, double dx, double dy) { @@ -383,18 +566,20 @@ static void strokeDraw(HeliStroke *stroke, double w, double *color) { static void drawStroke(int close) { HeliDrawingState *s = heliDrawingGetState(); - if (s->colorStroke[3] <= HELI_PRECISION) return; - if (s->lineWidth < HELI_PRECISION) return; + if (s->strokeColor[3] <= HELI_PRECISION) return; + if (s->strokeWidth < HELI_PRECISION) return; if (pathSize < 4) return; HeliStroke stroke = {}; stroke.allocatedCount = pathSize; stroke.points = calloc(stroke.allocatedCount, sizeof(*stroke.points)); - double w = 0.5*s->lineWidth; + double w = 0.5*s->strokeWidth; double precisionSqr = 1/(w*0.75); precisionSqr *= precisionSqr; + heliDrawingApplyTexture(s->strokeColor, &s->strokeTexture); + if (close) { for(int i = 0; i < pathSize; i += 2) { int p = i > 0 ? i - 2 : pathSize - 2; @@ -412,7 +597,7 @@ static void drawStroke(int close) { stroke.points[0].y, stroke.points[0].dx, stroke.points[0].dy ); - strokeDraw(&stroke, w, s->colorStroke); + strokeDraw(&stroke, w, s->strokeColor); stroke.count = 0; @@ -432,7 +617,7 @@ static void drawStroke(int close) { stroke.points[0].y, stroke.points[0].dx, stroke.points[0].dy ); - strokeDraw(&stroke, w, s->colorStroke); + strokeDraw(&stroke, w, s->strokeColor); } else { double px = 0, py = 0, nx = 0, ny = 0; for(int i = 0; i < pathSize; i += 2) { @@ -453,9 +638,10 @@ 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, s->colorStroke); + strokeDraw(&stroke, w, s->strokeColor); } + heliDrawingResetTexture(); free(stroke.points); } @@ -518,24 +704,49 @@ HeliDrawingState *heliDrawingGetState() HeliDrawingState *heliDrawingGetStateStack() { return statesStack; } -void pushDrawingState() { +void saveState(unsigned int flags) + { saveStateEx(STATE_ALL); } + +void saveStateEx(unsigned int flags) { if (statesStackIndex >= sizeof(statesStack)/sizeof(*statesStack) - 1) { fprintf(stderr, "helianthus: drawing stack overflow\n"); return; } ++statesStackIndex; memcpy(statesStack + statesStackIndex, statesStack + statesStackIndex - 1, sizeof(*statesStack)); - heliGLGetState(&statesStack[statesStackIndex].glState); + statesStack[statesStackIndex].flags = flags; + heliGLGetCommonState(&statesStack[statesStackIndex].glState, flags); } -void popDrawingState() { +void restoreState() { assert(statesStackIndex > 0); if (statesStackIndex <= 0) { fprintf(stderr, "helianthus: drawing stack underflow\n"); return; } - heliGLSetState(&statesStack[statesStackIndex].glState); + + HeliDrawingState *prev = &statesStack[statesStackIndex]; + heliGLSetCommonState(&prev->glState); --statesStackIndex; + HeliDrawingState *curr = &statesStack[statesStackIndex]; + + unsigned int flags = ~prev->flags; + if (flags & STATE_FILL_COLOR) + memcpy(curr->fillColor, prev->fillColor, sizeof(curr->fillColor)); + if (flags & STATE_FILL_TEXTURE) + memcpy(&curr->fillTexture, &prev->fillTexture, sizeof(curr->fillTexture)); + if (flags & STATE_STROKE_COLOR) + memcpy(curr->strokeColor, prev->strokeColor, sizeof(curr->strokeColor)); + if (flags & STATE_STROKE_TEXTURE) + memcpy(&curr->strokeTexture, &prev->strokeTexture, sizeof(curr->strokeTexture)); + if (flags & STATE_STROKE_WIDTH) + curr->strokeWidth = prev->strokeWidth; + if (flags & STATE_TEXT_ALIGN) + { curr->horAlign = prev->horAlign; curr->vertAlign = prev->vertAlign; } + if (flags & STATE_TEXT_SIZE) + curr->fontSize = prev->fontSize; + if (flags & STATE_TEXT_FONT) + curr->font = prev->font; } void heliDrawingClearFrame() { diff --git a/src/drawing.h b/src/drawing.h index ed89d36..70be85b 100644 --- a/src/drawing.h +++ b/src/drawing.h @@ -3,15 +3,51 @@ #include "common.h" +#include "animation.h" + + +typedef enum _StateFlags { + STATE_FILL_COLOR = 1 << 0, + STATE_FILL_TEXTURE = 1 << 1, + + STATE_STROKE_COLOR = 1 << 2, + STATE_STROKE_TEXTURE = 1 << 3, + STATE_STROKE_WIDTH = 1 << 4, + + STATE_TEXT_ALIGN = 1 << 5, + STATE_TEXT_SIZE = 1 << 6, + STATE_TEXT_FONT = 1 << 7, + + STATE_TRANSFORM = 1 << 8, + STATE_CLIP = 1 << 9, + + + STATE_FILL = STATE_FILL_COLOR + | STATE_FILL_TEXTURE, + STATE_STROKE = STATE_STROKE_COLOR + | STATE_STROKE_TEXTURE + | STATE_STROKE_WIDTH, + STATE_TEXT = STATE_TEXT_ALIGN + | STATE_TEXT_SIZE + | STATE_TEXT_FONT, + + STATE_ALL = STATE_FILL + | STATE_STROKE + | STATE_TEXT + | STATE_TRANSFORM + | STATE_CLIP, +} StateFlags; void background(const char *color); void fill(const char *color); +void fillTexture(Animation animation, double x, double y, double width, double height, int fixed); void noFill(); void stroke(const char *color); +void strokeTexture(Animation animation, double x, double y, double width, double height, int fixed); void noStroke(); -void strokeWeight(double weight); +void strokeWidth(double width); void translate(double x, double y); void rotate(double angle); @@ -20,8 +56,9 @@ void scale(double x, double y); void cliprect(double x, double y, double width, double height); void noClip(); -void pushDrawingState(); -void popDrawingState(); +void saveState(); +void saveStateEx(unsigned int flags); +void restoreState(); const char* rgb(double r, double g, double b); const char* rgba(double r, double g, double b, double a); diff --git a/src/font.c b/src/font.c index e04c0fa..dcb89c8 100644 --- a/src/font.c +++ b/src/font.c @@ -516,8 +516,8 @@ void textLayoutDrawSubstr(TextLayout layout, double x, double y, int start, int double fontScale = drawingState->fontSize/FONT_BASE_SIZE; if (fontScale <= HELI_PRECISION) return; - if ( drawingState->colorStroke[3] <= HELI_PRECISION - && drawingState->colorFill[3] <= HELI_PRECISION ) return; + if ( drawingState->strokeColor[3] <= HELI_PRECISION + && drawingState->fillColor[3] <= HELI_PRECISION ) return; const double borderK = 0.5*FONT_MAP_BORDERSIZE/FONT_MAP_GLYPHWORKSIZE; const double texStep = 1.0/FONT_MAP_CNT; @@ -528,9 +528,9 @@ void textLayoutDrawSubstr(TextLayout layout, double x, double y, int start, int glTranslated(x, y, 0); glScaled(fontScale, fontScale, 1); - if (drawingState->colorFill[3] > HELI_PRECISION) { - double strokeAlpha = drawingState->colorStroke[3]; - drawingState->colorStroke[3] = 0; + if (drawingState->fillColor[3] > HELI_PRECISION) { + double strokeAlpha = drawingState->strokeColor[3]; + drawingState->strokeColor[3] = 0; for(int i = 0; i < layout->linesCount; ++i) { HeliLineDesc *line = layout->lines + i; int found = FALSE; @@ -548,11 +548,11 @@ void textLayoutDrawSubstr(TextLayout layout, double x, double y, int start, int if (found) rect(l, line->t + line->y, r-l, line->b - line->t); } - drawingState->colorStroke[3] = strokeAlpha; + drawingState->strokeColor[3] = strokeAlpha; } - if (drawingState->colorStroke[3] > HELI_PRECISION) { - glColor4dv(drawingState->colorStroke); + if (drawingState->strokeColor[3] > HELI_PRECISION) { + glColor4dv(drawingState->strokeColor); HeliFontMap *currentMap = NULL; glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); @@ -611,8 +611,8 @@ void text(const char *text, double x, double y) { HeliDrawingState *drawingState = heliDrawingGetState(); double fontScale = drawingState->fontSize/FONT_BASE_SIZE; if (fontScale < HELI_PRECISION) return; - if ( drawingState->colorStroke[3] < HELI_PRECISION - && drawingState->colorFill[3] < HELI_PRECISION ) return; + if ( drawingState->strokeColor[3] < HELI_PRECISION + && drawingState->fillColor[3] < HELI_PRECISION ) return; TextLayout layout = createTextLayout(text); textLayoutDraw(layout, x, y); diff --git a/src/geometry.c b/src/geometry.c index eb2c291..26b61fe 100644 --- a/src/geometry.c +++ b/src/geometry.c @@ -81,161 +81,3 @@ int heliMatrix4Invert(double *r, const double *m) { return TRUE; } - -// opengl - -double heliGLGetAAResolution() { - if (!heliGLIsIntegerClipping()) return 0; - - double proj[16] = {}; - double model[16] = {}; - glGetDoublev(GL_PROJECTION_MATRIX, proj); - glGetDoublev(GL_MODELVIEW_MATRIX, model); - - double full[16] = {}; - double fullinv[16] = {}; - heliMatrix4Mult(full, proj, model); - - full[8] = 0, full[9] = 0, full[10] = 1, full[11] = 0; // assume z is zero - if (!heliMatrix4Invert(fullinv, full)) return 0; - - if (fabs(fullinv[15]) < HELI_PRECISION_SQR) return 0; // bad perspective - double k = 1/fullinv[15]; - - if ( fabs(fullinv[3]*k) > 1e-5 - || fabs(fullinv[7]*k) > 1e-5 ) return 0; // perspective distortion - - int rect[4] = {}; // x, y, w, h - glGetIntegerv(GL_VIEWPORT, rect); - double w = rect[2], h = rect[3]; - - double m00 = fullinv[0]*k*2/w, m01 = fullinv[1]*k*2/w, - m10 = fullinv[4]*k*2/h, m11 = fullinv[5]*k*2/h; - double l0 = sqrt(m00*m00 + m01*m01); - double l1 = sqrt(m10*m10 + m11*m11); - if (l0 > l1) { double l = l0; l0 = l1; l1 = l; } - if (l0 < HELI_PRECISION || l1 < HELI_PRECISION) return 0; - if (l0/l1 < 0.75) return 0; // to big aspect ratio - - return sqrt(l0*l1); -} - - -static int isInteger(double x) - { return fabs(floor(x + 0.5) - x) > 0.01; } - -int heliGLIsIntegerClipping() { - double proj[16] = {}; - double model[16] = {}; - double viewproj[16] = {}; - double viewmodel[16] = {}; - - int rect[4] = {}; // x, y, w, h - glGetIntegerv(GL_VIEWPORT, rect); - double hw = 0.5*rect[2], hh = 0.5*rect[3]; - double view[16] = { - hw, 0, 0, 0, - 0,-hh, 0, 0, - 0, 0, 1, 0, - hw, hh, 0, 1 }; - - glGetDoublev(GL_PROJECTION_MATRIX, proj); - glGetDoublev(GL_MODELVIEW_MATRIX, model); - heliMatrix4Mult(viewproj, view, proj); - heliMatrix4Mult(viewmodel, viewproj, model); - - int badMatrix = FALSE; - if (fabs(viewmodel[15]) < HELI_PRECISION_SQR) badMatrix = TRUE; // bad perspective - double k = badMatrix ? 0 : 1/viewmodel[15]; - if ( fabs(viewmodel[3]*k) > 1e-5 - || fabs(viewmodel[7]*k) > 1e-5 ) badMatrix = TRUE; // perspective distortion - - HeliGLState s; - const int clipCount = (int)(sizeof(s.clipEnabled)/sizeof(*s.clipEnabled)); - //glGetIntegerv(GL_MAX_CLIP_PLANES, &clipCount); - double eq[4] = {}, eqv[4] = {}; - for(int i = 0; i < clipCount; ++i) { - if (!glIsEnabled(GL_CLIP_PLANE0 + i)) continue; - if (badMatrix) return FALSE; - - glGetClipPlane(GL_CLIP_PLANE0 + i, eq); - heliMatrix4MultVec(eqv, viewproj, eq); - double a = (eqv[0] + eqv[2]*viewmodel[2])*k; - double b = (eqv[1] + eqv[2]*viewmodel[6])*k; - double c = eqv[2]*viewmodel[14]*k + 1; - - if (fabs(a) > 1e-5 && fabs(b) > 1e-5) return FALSE; - if (fabs(a) > 1e-5 && !isInteger(c/a)) return FALSE; - if (fabs(b) > 1e-5 && !isInteger(b/a)) return FALSE; - } - - return TRUE; -} - -int heliGLBackTransform(double *x, double *y) { - double proj[16] = {}; - double model[16] = {}; - double viewproj[16] = {}; - double viewmodel[16] = {}; - double inv[16] = {}; - - double v[2][4] = { - { *x, *y, 0, 1 }, - { *x, *y, 1, 1 } }; - double vv[2][4] = {}; - *x = 0; *y = 0; - - int rect[4] = {}; // x, y, w, h - glGetIntegerv(GL_VIEWPORT, rect); - double hw = 0.5*rect[2], hh = 0.5*rect[3]; - double view[16] = { - hw, 0, 0, 0, - 0,-hh, 0, 0, - 0, 0, 1, 0, - hw, hh, 0, 1 }; - - glGetDoublev(GL_PROJECTION_MATRIX, proj); - glGetDoublev(GL_MODELVIEW_MATRIX, model); - heliMatrix4Mult(viewproj, view, proj); - heliMatrix4Mult(viewmodel, viewproj, model); - - if (!heliMatrix4Invert(inv, viewmodel)) return FALSE; - heliMatrix4MultVec(vv[0], inv, v[0]); - heliMatrix4MultVec(vv[1], inv, v[1]); - - double l = vv[0][2] - vv[1][2]; - if (fabs(l) <= HELI_PRECISION) return FALSE; - l = vv[0][2]/l; - - double kw = vv[0][3] + (vv[1][3] - vv[0][3])*l; - if (fabs(kw) <= HELI_PRECISION) return FALSE; - kw = 1/kw; - - *x = (vv[0][0] + (vv[1][0] - vv[0][0])*l)*kw; - *y = (vv[0][1] + (vv[1][1] - vv[0][1])*l)*kw; - return TRUE; -} - - -void heliGLGetState(HeliGLState *state) { - const int clipCount = (int)(sizeof(state->clipEnabled)/sizeof(*state->clipEnabled)); - glGetDoublev(GL_MODELVIEW_MATRIX, state->modelviewMatrix); - for(int i = 0; i < clipCount; ++i) { - state->clipEnabled[i] = glIsEnabled(GL_CLIP_PLANE0 + i) != 0; - glGetClipPlane(GL_CLIP_PLANE0 + i, state->clipEquations[i]); - } -} - -void heliGLSetState(const HeliGLState *state) { - const int clipCount = (int)(sizeof(state->clipEnabled)/sizeof(*state->clipEnabled)); - unsigned int mode; - glGetIntegerv(GL_MATRIX_MODE, (int*)&mode); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - for(int i = 0; i < clipCount; ++i) { - if (state->clipEnabled[i]) glEnable(GL_CLIP_PLANE0+i); else glDisable(GL_CLIP_PLANE0+i); - glClipPlane(GL_CLIP_PLANE0+i, state->clipEquations[i]); - } - glLoadMatrixd(state->modelviewMatrix); - glMatrixMode(mode); -} diff --git a/src/gl.c b/src/gl.c new file mode 100644 index 0000000..20af865 --- /dev/null +++ b/src/gl.c @@ -0,0 +1,181 @@ + +#include "private.h" +#include "drawing.h" + + +double heliGLGetAAResolution() { + if (!heliGLIsIntegerClipping()) return 0; + + double proj[16] = {}; + double model[16] = {}; + glGetDoublev(GL_PROJECTION_MATRIX, proj); + glGetDoublev(GL_MODELVIEW_MATRIX, model); + + double full[16] = {}; + double fullinv[16] = {}; + heliMatrix4Mult(full, proj, model); + + full[8] = 0, full[9] = 0, full[10] = 1, full[11] = 0; // assume z is zero + if (!heliMatrix4Invert(fullinv, full)) return 0; + + if (fabs(fullinv[15]) < HELI_PRECISION_SQR) return 0; // bad perspective + double k = 1/fullinv[15]; + + if ( fabs(fullinv[3]*k) > 1e-5 + || fabs(fullinv[7]*k) > 1e-5 ) return 0; // perspective distortion + + int rect[4] = {}; // x, y, w, h + glGetIntegerv(GL_VIEWPORT, rect); + double w = rect[2], h = rect[3]; + + double m00 = fullinv[0]*k*2/w, m01 = fullinv[1]*k*2/w, + m10 = fullinv[4]*k*2/h, m11 = fullinv[5]*k*2/h; + double l0 = sqrt(m00*m00 + m01*m01); + double l1 = sqrt(m10*m10 + m11*m11); + if (l0 > l1) { double l = l0; l0 = l1; l1 = l; } + if (l0 < HELI_PRECISION || l1 < HELI_PRECISION) return 0; + if (l0/l1 < 0.75) return 0; // to big aspect ratio + + return sqrt(l0*l1); +} + + +static int isInteger(double x) + { return fabs(floor(x + 0.5) - x) > 0.01; } + +int heliGLIsIntegerClipping() { + double proj[16] = {}; + double model[16] = {}; + double viewproj[16] = {}; + double viewmodel[16] = {}; + + int rect[4] = {}; // x, y, w, h + glGetIntegerv(GL_VIEWPORT, rect); + double hw = 0.5*rect[2], hh = 0.5*rect[3]; + double view[16] = { + hw, 0, 0, 0, + 0,-hh, 0, 0, + 0, 0, 1, 0, + hw, hh, 0, 1 }; + + glGetDoublev(GL_PROJECTION_MATRIX, proj); + glGetDoublev(GL_MODELVIEW_MATRIX, model); + heliMatrix4Mult(viewproj, view, proj); + heliMatrix4Mult(viewmodel, viewproj, model); + + int badMatrix = FALSE; + if (fabs(viewmodel[15]) < HELI_PRECISION_SQR) badMatrix = TRUE; // bad perspective + double k = badMatrix ? 0 : 1/viewmodel[15]; + if ( fabs(viewmodel[3]*k) > 1e-5 + || fabs(viewmodel[7]*k) > 1e-5 ) badMatrix = TRUE; // perspective distortion + + HeliGLCommonState s; + const int clipCount = (int)(sizeof(s.clipPlanes)/sizeof(*s.clipPlanes)); + //glGetIntegerv(GL_MAX_CLIP_PLANES, &clipCount); + double eq[4] = {}, eqv[4] = {}; + for(int i = 0; i < clipCount; ++i) { + if (!glIsEnabled(GL_CLIP_PLANE0 + i)) continue; + if (badMatrix) return FALSE; + + glGetClipPlane(GL_CLIP_PLANE0 + i, eq); + heliMatrix4MultVec(eqv, viewproj, eq); + double a = (eqv[0] + eqv[2]*viewmodel[2])*k; + double b = (eqv[1] + eqv[2]*viewmodel[6])*k; + double c = eqv[2]*viewmodel[14]*k + 1; + + if (fabs(a) > 1e-5 && fabs(b) > 1e-5) return FALSE; + if (fabs(a) > 1e-5 && !isInteger(c/a)) return FALSE; + if (fabs(b) > 1e-5 && !isInteger(b/a)) return FALSE; + } + + return TRUE; +} + +int heliGLBackTransform(double *x, double *y) { + double proj[16] = {}; + double model[16] = {}; + double viewproj[16] = {}; + double viewmodel[16] = {}; + double inv[16] = {}; + + double v[2][4] = { + { *x, *y, 0, 1 }, + { *x, *y, 1, 1 } }; + double vv[2][4] = {}; + *x = 0; *y = 0; + + int rect[4] = {}; // x, y, w, h + glGetIntegerv(GL_VIEWPORT, rect); + double hw = 0.5*rect[2], hh = 0.5*rect[3]; + double view[16] = { + hw, 0, 0, 0, + 0,-hh, 0, 0, + 0, 0, 1, 0, + hw, hh, 0, 1 }; + + glGetDoublev(GL_PROJECTION_MATRIX, proj); + glGetDoublev(GL_MODELVIEW_MATRIX, model); + heliMatrix4Mult(viewproj, view, proj); + heliMatrix4Mult(viewmodel, viewproj, model); + + if (!heliMatrix4Invert(inv, viewmodel)) return FALSE; + heliMatrix4MultVec(vv[0], inv, v[0]); + heliMatrix4MultVec(vv[1], inv, v[1]); + + double l = vv[0][2] - vv[1][2]; + if (fabs(l) <= HELI_PRECISION) return FALSE; + l = vv[0][2]/l; + + double kw = vv[0][3] + (vv[1][3] - vv[0][3])*l; + if (fabs(kw) <= HELI_PRECISION) return FALSE; + kw = 1/kw; + + *x = (vv[0][0] + (vv[1][0] - vv[0][0])*l)*kw; + *y = (vv[0][1] + (vv[1][1] - vv[0][1])*l)*kw; + return TRUE; +} + + +void heliGLGetCommonState(HeliGLCommonState *state, unsigned int flags) { + memset(state, 0, sizeof(*state)); + state->flags = flags; + + if (state->flags & STATE_TRANSFORM) + glGetDoublev(GL_MODELVIEW_MATRIX, state->modelviewMatrix); + + if (state->flags & STATE_CLIP) { + const int clipCount = (int)(sizeof(state->clipPlanes)/sizeof(*state->clipPlanes)); + for(int i = 0; i < clipCount; ++i) { + state->clipPlanes[i].enabled = glIsEnabled(GL_CLIP_PLANE0 + i) != 0; + glGetClipPlane(GL_CLIP_PLANE0 + i, state->clipPlanes[i].equation); + } + } +} + + +void heliGLSetCommonState(const HeliGLCommonState *state) { + int loadClip = state->flags & STATE_CLIP; + int loadTransform = state->flags & STATE_CLIP; + if (loadClip) { + unsigned int mode; + glGetIntegerv(GL_MATRIX_MODE, (int*)&mode); + glMatrixMode(GL_MODELVIEW); + if (!loadTransform) glPushMatrix(); + const int clipCount = (int)(sizeof(state->clipPlanes)/sizeof(*state->clipPlanes)); + for(int i = 0; i < clipCount; ++i) { + if (state->clipPlanes[i].enabled) glEnable(GL_CLIP_PLANE0+i); + else glDisable(GL_CLIP_PLANE0+i); + glClipPlane(GL_CLIP_PLANE0+i, state->clipPlanes[i].equation); + } + if (!loadTransform) glPopMatrix(); else glLoadMatrixd(state->modelviewMatrix); + glMatrixMode(mode); + } else + if (loadTransform) { + unsigned int mode; + glGetIntegerv(GL_MATRIX_MODE, (int*)&mode); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixd(state->modelviewMatrix); + glMatrixMode(mode); + } +} + diff --git a/src/private.h b/src/private.h index 4f530e1..64b3842 100644 --- a/src/private.h +++ b/src/private.h @@ -90,12 +90,6 @@ int heliStringmapRemove(HeliArray *a, const char *k); // geometry -typedef struct _HeliGLState { - double modelviewMatrix[16]; - double clipEnabled[4]; - double clipEquations[4][4]; -} HeliGLState; - void heliMatrix4Identity(double *r); void heliMatrix4Translation(double *r, double x, double y, double z); void heliMatrix4Scale(double *r, double x, double y, double z); @@ -104,11 +98,25 @@ void heliMatrix4MultVec(double *r, const double *m, const double *v); void heliMatrix4Mult(double *r, const double *a, const double *b); int heliMatrix4Invert(double *r, const double *m); + +// gl + +typedef struct _HeliGLClipPlaneState { + int enabled; + double equation[4]; +} HeliGLClipPlaneState; + +typedef struct _HeliGLCommonState { + unsigned int flags; + double modelviewMatrix[16]; + HeliGLClipPlaneState clipPlanes[4]; +} HeliGLCommonState; + double heliGLGetAAResolution(); int heliGLIsIntegerClipping(); -void heliGLGetState(HeliGLState *state); -void heliGLSetState(const HeliGLState *state); int heliGLBackTransform(double *x, double *y); +void heliGLGetCommonState(HeliGLCommonState *state, unsigned int flags); +void heliGLSetCommonState(const HeliGLCommonState *state); // all objects @@ -119,6 +127,48 @@ void heliObjectRegister(void *o, HeliFreeCallback fo); void heliObjectUnregister(void *o); +// drawing + +typedef struct _HeliTextureState { + double color[4]; + Animation animation; + int fixed; + double x, y, width, height; +} HeliTextureState; + +typedef struct _HeliDrawingState { + unsigned int flags; + double fillColor[4]; + double strokeColor[4]; + double strokeWidth; + HAlign horAlign; + VAlign vertAlign; + double fontSize; + Font font; + HeliTextureState fillTexture; + HeliTextureState strokeTexture; + HeliGLCommonState glState; +} HeliDrawingState; + +typedef void (APIENTRY *HeliGlStencilOpSeparatePtr)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +extern HeliGlStencilOpSeparatePtr heliGlStencilOpSeparatePtr; + +HeliDrawingState *heliDrawingGetState(); +HeliDrawingState *heliDrawingGetStateStack(); +void heliDrawingApplyTexture(double *color, HeliTextureState *state); +void heliDrawingResetTexture(); +void heliFillRectSimple(double x0, double y0, double x1, double y1, double aaBorder); +void heliFillCircleSimple(double x, double y, double r, double aaBorder); +void heliDrawingClearFrame(); +void heliDrawingPrepareFrame(); +void heliDrawingFinish(); + + +// font + +void heliFontFinish(); + + // animation void heliAnimationUpdate(double dt); @@ -156,34 +206,6 @@ void heliSpriteUpdate(double dt); void heliSpriteFinish(); -// drawing - -typedef struct _HeliDrawingState { - double colorStroke[4]; - double colorFill[4]; - double lineWidth; - HAlign horAlign; - VAlign vertAlign; - Font font; - double fontSize; - HeliGLState glState; -} HeliDrawingState; - -typedef void (APIENTRY *HeliGlStencilOpSeparatePtr)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -extern HeliGlStencilOpSeparatePtr heliGlStencilOpSeparatePtr; - -HeliDrawingState *heliDrawingGetState(); -HeliDrawingState *heliDrawingGetStateStack(); -void heliDrawingClearFrame(); -void heliDrawingPrepareFrame(); -void heliDrawingFinish(); - - -// font - -void heliFontFinish(); - - // sound void heliSoundUpdate(); diff --git a/src/sprite.c b/src/sprite.c index c181568..bd14b2f 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -345,35 +345,24 @@ Sprite worldGetSprite(int i) static void drawSpriteDebug(Sprite s) { - pushDrawingState(); - strokeWeight(0.5); + saveState(); + translate(s->x, s->y); + rotate(s->rotation); - 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; + strokeWidth(0.5); - double ltx = -hw*cs + hh*sn; - double lty = -hw*sn - hh*cs; - double rtx = hw*cs + hh*sn; - double rty = hw*sn - hh*cs; + double hw = 0.5 * s->scale * s->width; + double hh = 0.5 * s->scale * s->height; 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(); + rect(-hw, -hh, 2*hw, 2*hh); // 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 ); + line(-hw/4, 0, hw/4, 0); + line(0, -hh/4, 0, hh/4); // depth stroke(rgba(0, 0, 0, 0.75)); @@ -381,156 +370,37 @@ static void drawSpriteDebug(Sprite s) { snprintf(buf, sizeof(buf)-1, "%lf", s->depth); double s1 = hw*0.25; double s2 = hh*0.5; - textSize(s1 < s2 ? s1 : s2); - textAlign(HALIGN_CENTER, VALIGN_CENTER); - text(buf, s->x, s->y); + double ss = s1 < s2 ? s1 : s2; + textSize(ss); + textAlign(HALIGN_LEFT, VALIGN_BOTTOM); + text(buf, 0.1*ss - hw, hh - 0.1*ss); - popDrawingState(); + restoreState(); } static void drawSprite(Sprite s, double aaBorder) { - unsigned int texid = s->animation ? animationGetGLTexId(s->animation) : 0u; + double w = 0.5*s->scale*s->width; + double h = 0.5*s->scale*s->height; + if (w < HELI_PRECISION || h < HELI_PRECISION) return; + w *= s->mirrorX; + h *= s->mirrorY; + unsigned int texid = s->animation ? animationGetGLTexId(s->animation) : 0u; double color[4] = { (texid ? 1.0 : s->shapeColor[0])*s->tintColor[0], (texid ? 1.0 : s->shapeColor[1])*s->tintColor[1], (texid ? 1.0 : s->shapeColor[2])*s->tintColor[2], (texid ? 1.0 : s->shapeColor[3])*s->tintColor[3] }; - if (color[3] < HELI_PRECISION) return; - - double w = 0.5*s->scale*s->width; - double h = 0.5*s->scale*s->height; - if (w < HELI_PRECISION || h < HELI_PRECISION) return; - - glPushMatrix(); - glTranslated(s->x, s->y, 0); - glRotated(s->rotation, 0, 0, 1); - - if (aaBorder <= HELI_PRECISION) { - // use OpenGL multisample antialiasing - - glEnable(GL_MULTISAMPLE); - - const int vcnt = 4; - const double vertices[][2] = { - { -w, -h }, - { w, -h }, - { -w, h }, - { w, h } }; - glColor4dv(color); - if (texid) { - const double texCoords[][2] = { - {0, 0}, - {1, 0}, - {0, 1}, - {1, 1} }; - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, texid); - - glBegin(GL_TRIANGLE_STRIP); - for(int i = 0; i < vcnt; ++i) { - glTexCoord2dv(texCoords[i]); - glVertex2dv(vertices[i]); - } - glEnd(); - - glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); - } else { - glBegin(GL_TRIANGLE_STRIP); - for(int i = 0; i < vcnt; ++i) - glVertex2dv(vertices[i]); - glEnd(); - } - - glDisable(GL_MULTISAMPLE); - } else { - // make antialiased borde manually - - double sideColor[4] = { color[0], color[1], color[2], 0 }; - - double w0 = w - 0.5*aaBorder; - double w1 = w + 0.5*aaBorder; - if (w0 < HELI_PRECISION) w0 = 0; - double h0 = h - 0.5*aaBorder; - double h1 = h + 0.5*aaBorder; - if (h0 < HELI_PRECISION) h0 = 0; - - const double k = (w1 < aaBorder ? w1/aaBorder : 1) - * (h1 < aaBorder ? h1/aaBorder : 1); - color[3] *= k; - - w0 *= s->mirrorX; - w1 *= s->mirrorX; - h0 *= s->mirrorY; - h1 *= s->mirrorY; - - const int vcnt = 14; - - const double vertices[][2] = { - { -w1, -h1 }, { -w0, -h0 }, - { w1, -h1 }, { w0, -h0 }, - { w1, h1 }, { w0, h0 }, - { -w1, h1 }, { -w0, h0 }, - { -w1, -h1 }, { -w0, -h0 }, - { -w0, -h0 }, - { w0, -h0 }, - { -w0, h0 }, - { w0, h0 } }; - - const double *colors[] = { - sideColor, color, - sideColor, color, - sideColor, color, - sideColor, color, - sideColor, color, - color, - color, - color, - color }; - - if (texid) { - const double tw0 = fabs(w0/w)*0.5 - 0.5; - const double tw1 = fabs(w1/w)*0.5 - 0.5; - const double th0 = fabs(h0/h)*0.5 - 0.5; - const double th1 = fabs(h1/h)*0.5 - 0.5; - const double texCoords[][2] = { - { -tw1, -th1 }, { -tw0, -th0 }, - { 1 + tw1, -th1 }, { 1 + tw0, -th0 }, - { 1 + tw1, 1 + th1 }, { 1 + tw0, 1 + th0 }, - { -tw1, 1 + th1 }, { -tw0, 1 + th0 }, - { -tw1, -th1 }, { -tw0, -th0 }, - { -tw0, -th0 }, - { 1 + tw0, -th0 }, - { -tw0, 1 + th0 }, - { 1 + tw0, 1 + th0 } }; - - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, texid); - - glBegin(GL_TRIANGLE_STRIP); - for(int i = 0; i < vcnt; ++i) { - glColor4dv(colors[i]); - glTexCoord2dv(texCoords[i]); - glVertex2dv(vertices[i]); - } - glEnd(); - - glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); - } else { - glBegin(GL_TRIANGLE_STRIP); - for(int i = 0; i < vcnt; ++i) { - glColor4dv(colors[i]); - glVertex2dv(vertices[i]); - } - glEnd(); - } - } - - glColor4d(1, 1, 1, 1); - glPopMatrix(); + + saveState(); + translate(s->x, s->y); + rotate(s->rotation); + noStroke(); + fill(rgba(color[0], color[1], color[2], color[3])); + fillTexture(s->animation, -w, -h, 2*w, 2*h, FALSE); + rect(-w, -h, 2*w, 2*h); + restoreState(); } void drawSprites() { diff --git a/src/worldui.c b/src/worldui.c index 5d45acb..ea7a443 100644 --- a/src/worldui.c +++ b/src/worldui.c @@ -137,7 +137,7 @@ static void paste(HeliDialog *dialog) { static void draw(HeliDialog *dialog) { - pushDrawingState(); + saveState(); const double time = SDL_GetTicks()*1e-3; @@ -174,7 +174,7 @@ static void draw(HeliDialog *dialog) { const char *fillColor = "0.3 0.3 0.3"; const char *selTextColor = "black"; const char *selFillColor = "white"; - strokeWeight(1); + strokeWidth(1); textFontDefault(); textSize(16); @@ -271,7 +271,7 @@ static void draw(HeliDialog *dialog) { } } - popDrawingState(); + restoreState(); }