From 8bc1f1a865c08f54820134d3b8ae7802cf3ec39e Mon Sep 17 00:00:00 2001 From: Ivan Mahonin Date: Jul 26 2020 10:02:47 +0000 Subject: improve opengl integration --- diff --git a/demo/src/common.c b/demo/src/common.c index 2437030..6ce297c 100644 --- a/demo/src/common.c +++ b/demo/src/common.c @@ -1,5 +1,6 @@ #include +#include #include #include @@ -70,7 +71,11 @@ void commonDraw() { textFontDefault(); textSize(16); - text(buffer, 16, 16); + text(buffer, 16, 48); + + char fpsbuf[256] = {}; + sprintf(fpsbuf, "%6.2f", 1/worldGetFrameTime()); + text(fpsbuf, 16, 16); if (mouseWentDown("left")) soundPlay(beep, FALSE); diff --git a/demo/src/main.c b/demo/src/main.c index c8a5dd3..7d623f6 100644 --- a/demo/src/main.c +++ b/demo/src/main.c @@ -31,8 +31,12 @@ int main() { worldSetHeight(512); worldSetWidth(1024); worldSetResizable(TRUE); + worldSetFrameRateEx(1, 100); + worldSetInit(&init); worldSetDraw(&draw); + worldRun(); + return 0; } diff --git a/demo/src/phisics.c b/demo/src/phisics.c index bd9f06f..42074f5 100644 --- a/demo/src/phisics.c +++ b/demo/src/phisics.c @@ -47,7 +47,7 @@ void phisicsInit() { void phisicsDraw() { - double dt = worldGetTimeStep(); + double dt = worldGetFrameTime(); double accel = 100; double vx = spriteGetVelocityX(ball); diff --git a/src/SConstruct b/src/SConstruct index 527da0e..306d2ad 100644 --- a/src/SConstruct +++ b/src/SConstruct @@ -53,6 +53,7 @@ sources = [ 'common.c', 'drawing.c', 'font.c', + 'geometry.c', 'group.c', 'test.c', 'sound.c', diff --git a/src/drawing.c b/src/drawing.c index ee93d82..e994fc6 100644 --- a/src/drawing.c +++ b/src/drawing.c @@ -61,6 +61,30 @@ const char* rgba(double r, double g, double b, double a) { const char* rgb(double r, double g, double b) { return rgba(r, g, b, 1); } +void translate(double x, double y) + { glTranslated(x, y, 0); } +void rotate(double angle) + { glRotated(angle, 0, 0, 1); } +void scale(double x, double y) + { glScaled(x, y, 1); } +void zoom(double z) + { scale(z, z); } + +void cliprect(double x, double y, double width, double height) { + double eq[4][4] = { + { 1, 0, 0, -x }, + {-1, 0, 0, x+width }, + { 0, 1, 0, -y }, + { 0,-1, 0, y+height } }; + for(int i = 0; i < 4; ++i) { + glEnable(GL_CLIP_PLANE0 + i); + glClipPlane(GL_CLIP_PLANE0 + i, eq[i]); + } +} + +void noClip() + { for(int i = 0; i < 4; ++i) glDisable(GL_CLIP_PLANE0 + i); } + void rect(double x, double y, double width, double height) { resetPath(); moveTo(x, y); @@ -288,8 +312,8 @@ static void strokeAddCorner( } static void strokeDraw(HeliStroke *stroke, double w, double *color) { - const double aaBorder = 1; - if (aaBorder > 0) { + const double aaBorder = heliGLGetAAResolution(); + if (aaBorder > HELI_PRECISION) { double c0[4] = { color[0], color[1], color[2], 0 }; double c1[4] = { color[0], color[1], color[2], color[3] }; double w0 = w + 0.5*aaBorder; @@ -481,6 +505,7 @@ void pushDrawingState() { } ++statesStackIndex; memcpy(statesStack + statesStackIndex, statesStack + statesStackIndex - 1, sizeof(*statesStack)); + heliGLGetState(&statesStack[statesStackIndex].glState); } void popDrawingState() { @@ -489,6 +514,7 @@ void popDrawingState() { fprintf(stderr, "helianthus: drawing stack underflow\n"); return; } + heliGLSetState(&statesStack[statesStackIndex].glState); --statesStackIndex; } diff --git a/src/drawing.h b/src/drawing.h index 72d2fa0..ed89d36 100644 --- a/src/drawing.h +++ b/src/drawing.h @@ -13,6 +13,13 @@ void stroke(const char *color); void noStroke(); void strokeWeight(double weight); +void translate(double x, double y); +void rotate(double angle); +void zoom(double z); +void scale(double x, double y); +void cliprect(double x, double y, double width, double height); +void noClip(); + void pushDrawingState(); void popDrawingState(); diff --git a/src/font.c b/src/font.c index 2764026..d6a3bab 100644 --- a/src/font.c +++ b/src/font.c @@ -462,6 +462,7 @@ void text(const char *text, double x, double y) { const double texStep = 1.0/FONT_MAP_CNT; const double texOffset = -0.5*FONT_MAP_BORDERSIZE/FONT_MAP_TEXSIZE; + if (!heliGLIsIntegerClipping()) glEnable(GL_MULTISAMPLE); glPushMatrix(); glTranslated(x, y, 0); glScaled(fontScale, fontScale, 1); @@ -503,6 +504,7 @@ void text(const char *text, double x, double y) { glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); glPopMatrix(); + glDisable(GL_MULTISAMPLE); glColor4d(1, 1, 1, 1); } diff --git a/src/geometry.c b/src/geometry.c new file mode 100644 index 0000000..6dc5391 --- /dev/null +++ b/src/geometry.c @@ -0,0 +1,241 @@ + +#include "private.h" + + +// matrix + +void heliMatrix4Identity(double *r) { + r[ 0] = 1; r[ 1] = 0; r[ 2] = 0; r[ 3] = 0; + r[ 4] = 0; r[ 5] = 1; r[ 6] = 0; r[ 7] = 0; + r[ 8] = 0; r[ 9] = 0; r[10] = 1; r[11] = 0; + r[12] = 0; r[13] = 0; r[14] = 0; r[15] = 1; +} + +void heliMatrix4Translation(double *r, double x, double y, double z) { + r[ 0] = 1; r[ 1] = 0; r[ 2] = 0; r[ 3] = 0; + r[ 4] = 0; r[ 5] = 1; r[ 6] = 0; r[ 7] = 0; + r[ 8] = 0; r[ 9] = 0; r[10] = 1; r[11] = 0; + r[12] = x; r[13] = y; r[14] = z; r[15] = 1; +} + +void heliMatrix4Scale(double *r, double x, double y, double z) { + r[ 0] = x; r[ 1] = 0; r[ 2] = 0; r[ 3] = 0; + r[ 4] = 0; r[ 5] = y; r[ 6] = 0; r[ 7] = 0; + r[ 8] = 0; r[ 9] = 0; r[10] = z; r[11] = 0; + r[12] = 0; r[13] = 0; r[14] = 0; r[15] = 1; +} + +void heliMatrix4RotationZ(double *r, double a) { + double s = sin(a); + double c = cos(a); + r[ 0] = c; r[ 1] = s; r[ 2] = 0; r[ 3] = 0; + r[ 4] =-s; r[ 5] = c; r[ 6] = 0; r[ 7] = 0; + r[ 8] = 0; r[ 9] = 0; r[10] = 1; r[11] = 0; + r[12] = 0; r[13] = 0; r[14] = 0; r[15] = 1; +} + +void heliMatrix4MultVec(double *r, const double *m, const double *v) { + r[0] = v[0]*m[0] + v[1]*m[4] + v[2]*m[ 8] + v[3]*m[12]; + r[1] = v[0]*m[1] + v[1]*m[5] + v[2]*m[ 9] + v[3]*m[13]; + r[2] = v[0]*m[2] + v[1]*m[6] + v[2]*m[10] + v[3]*m[14]; + r[3] = v[0]*m[3] + v[1]*m[7] + v[2]*m[11] + v[3]*m[15]; +} + +void heliMatrix4Mult(double *r, const double *a, const double *b) { + heliMatrix4MultVec(r + 0, a, b + 0); + heliMatrix4MultVec(r + 4, a, b + 4); + heliMatrix4MultVec(r + 8, a, b + 8); + heliMatrix4MultVec(r + 12, a, b + 12); +} + +int heliMatrix4Invert(double *r, const double *m) { + r[ 0] = m[ 5]*(m[10]*m[15] - m[11]*m[14]) + m[ 6]*(m[11]*m[13] - m[ 9]*m[15]) + m[ 7]*(m[ 9]*m[14] - m[10]*m[13]); + r[ 4] = m[ 4]*(m[11]*m[14] - m[10]*m[15]) + m[ 6]*(m[ 8]*m[15] - m[11]*m[12]) + m[ 7]*(m[10]*m[12] - m[ 8]*m[14]); + r[ 8] = m[ 4]*(m[ 9]*m[15] - m[11]*m[13]) + m[ 5]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 7]*(m[ 8]*m[13] - m[ 9]*m[12]); + r[12] = m[ 4]*(m[10]*m[13] - m[ 9]*m[14]) + m[ 5]*(m[ 8]*m[14] - m[10]*m[12]) + m[ 6]*(m[ 9]*m[12] - m[ 8]*m[13]); + + double det = m[ 0]*r[0] + m[ 1]*r[4] + m[ 2]*r[8] + m[ 3]*r[12]; + if (fabs(det) <= HELI_PRECISION) { + memset(r, 0, sizeof(*r)*16); + return FALSE; + } + det = 1/det; + r[ 0] *= det; + r[ 4] *= det; + r[ 8] *= det; + r[12] *= det; + + r[ 1] = det*(m[ 1]*(m[11]*m[14] - m[10]*m[15]) + m[ 2]*(m[ 9]*m[15] - m[11]*m[13]) + m[ 3]*(m[10]*m[13] - m[ 9]*m[14])); + r[ 5] = det*(m[ 0]*(m[10]*m[15] - m[11]*m[14]) + m[ 2]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 3]*(m[ 8]*m[14] - m[10]*m[12])); + r[ 9] = det*(m[ 0]*(m[11]*m[13] - m[ 9]*m[15]) + m[ 1]*(m[ 8]*m[15] - m[11]*m[12]) + m[ 3]*(m[ 9]*m[12] - m[ 8]*m[13])); + r[13] = det*(m[ 0]*(m[ 9]*m[14] - m[10]*m[13]) + m[ 1]*(m[10]*m[12] - m[ 8]*m[14]) + m[ 2]*(m[ 8]*m[13] - m[ 9]*m[12])); + r[ 2] = det*(m[ 1]*(m[ 6]*m[15] - m[ 7]*m[14]) + m[ 2]*(m[ 7]*m[13] - m[ 5]*m[15]) + m[ 3]*(m[ 5]*m[14] - m[ 6]*m[13])); + r[ 6] = det*(m[ 0]*(m[ 7]*m[14] - m[ 6]*m[15]) + m[ 2]*(m[ 4]*m[15] - m[ 7]*m[12]) + m[ 3]*(m[ 6]*m[12] - m[ 4]*m[14])); + r[10] = det*(m[ 0]*(m[ 5]*m[15] - m[ 7]*m[13]) + m[ 1]*(m[ 7]*m[12] - m[ 4]*m[15]) + m[ 3]*(m[ 4]*m[13] - m[ 5]*m[12])); + r[14] = det*(m[ 0]*(m[ 6]*m[13] - m[ 5]*m[14]) + m[ 1]*(m[ 4]*m[14] - m[ 6]*m[12]) + m[ 2]*(m[ 5]*m[12] - m[ 4]*m[13])); + r[ 3] = det*(m[ 1]*(m[ 7]*m[10] - m[ 6]*m[11]) + m[ 2]*(m[ 5]*m[11] - m[ 7]*m[ 9]) + m[ 3]*(m[ 6]*m[ 9] - m[ 5]*m[10])); + r[ 7] = det*(m[ 0]*(m[ 6]*m[11] - m[ 7]*m[10]) + m[ 2]*(m[ 7]*m[ 8] - m[ 4]*m[11]) + m[ 3]*(m[ 4]*m[10] - m[ 6]*m[ 8])); + r[11] = det*(m[ 0]*(m[ 7]*m[ 9] - m[ 5]*m[11]) + m[ 1]*(m[ 4]*m[11] - m[ 7]*m[ 8]) + m[ 3]*(m[ 5]*m[ 8] - m[ 4]*m[ 9])); + r[15] = det*(m[ 0]*(m[ 5]*m[10] - m[ 6]*m[ 9]) + m[ 1]*(m[ 6]*m[ 8] - m[ 4]*m[10]) + m[ 2]*(m[ 4]*m[ 9] - m[ 5]*m[ 8])); + + 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[2]*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/private.h b/src/private.h index c6944ab..f98842d 100644 --- a/src/private.h +++ b/src/private.h @@ -83,6 +83,29 @@ HeliPair* heliStringmapAdd(HeliArray *a, const char *k, void *v, HeliFreeCallbac 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); +void heliMatrix4RotationZ(double *r, double a); +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); + +double heliGLGetAAResolution(); +int heliGLIsIntegerClipping(); +void heliGLGetState(HeliGLState *state); +void heliGLSetState(const HeliGLState *state); +int heliGLBackTransform(double *x, double *y); + + // all objects extern int heliInitialized; @@ -145,6 +168,7 @@ typedef struct _HeliDrawingState { VAlign vertAlign; Font font; double fontSize; + HeliGLState glState; } HeliDrawingState; HeliDrawingState *heliDrawingGetState(); diff --git a/src/sprite.c b/src/sprite.c index 64215c1..b703c65 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -404,9 +404,7 @@ static void drawSpriteDebug(Sprite s) { popDrawingState(); } -static void drawSprite(Sprite s) { - const double aaBorder = 1; - +static void drawSprite(Sprite s, double aaBorder) { unsigned int texid = s->animation ? (unsigned int)(size_t)heliArrayGetValue(&s->animation->frames, s->frame) : 0u; @@ -584,9 +582,10 @@ void drawSprites() { } // draw + const double aaBorder = heliGLGetAAResolution(); for(int i = 0; i < spritesSorted.count; ++i) { Sprite s = (Sprite)(spritesSorted.items[i].value); - if (s->visible) drawSprite(s); + if (s->visible) drawSprite(s, aaBorder); } // draw debug marks diff --git a/src/world.c b/src/world.c index d4081ef..1a81002 100644 --- a/src/world.c +++ b/src/world.c @@ -14,6 +14,7 @@ SDL_GLContext context; static int started; static int stopped; +static int firstFrame = TRUE; static unsigned long long frameCount; static unsigned long long elapsedTimeUs; static unsigned long long elapsedTimeSinceLastFrameUs; @@ -33,12 +34,9 @@ static int height = 512; static int resizable; static char title[1000]; static int titleSize = (int)(sizeof(title)/sizeof(*title)); -static double frameRate = 24; - -static int cameraEnabled; -static double cameraX; -static double cameraY; -static double cameraZoom = 1; +static double minFPS = 24; +static double maxFPS = 24; +static double frameTime = 1/24; static HeliArray keyEvents[6]; static int keyEventsCount = (int)(sizeof(keyEvents)/sizeof(*keyEvents)); @@ -95,6 +93,18 @@ double mouseX() double mouseY() { return _mouseY; } +double transformedMouseX() { + double x = mouseX(), y = mouseY(); + heliGLBackTransform(&x, &y); + return x; +} + +double transformedMouseY() { + double x = mouseX(), y = mouseY(); + heliGLBackTransform(&x, &y); + return y; +} + int mousePressedOver(Sprite sprite) { return keyEventGetCount(KEYEVENT_MOUSE_DOWN) && mouseIsOver(sprite); } @@ -108,7 +118,7 @@ static void resize(int w, int h) { SDL_SetWindowSize(window, width, height); } } - + int worldGetWidth() { return width; } void worldSetWidth(int w) @@ -141,16 +151,35 @@ void worldSetTitle(const char *t) { SDL_SetWindowTitle(window, title); } -double worldGetFrameRate() - { return frameRate; } -void worldSetFrameRate(double fps) { - if (!(fps > 1)) fps = 1; - if (!(fps < 100)) fps = 100; - frameRate = fps; +double worldGetMinFrameRate() + { return minFPS; } +double worldGetMaxFrameRate() + { return minFPS; } +void worldSetFrameRateEx(double minFrameRate, double maxFrameRate) { + if (!(minFrameRate > 1)) minFrameRate = 1; + if (!(minFrameRate < 100)) minFrameRate = 100; + if (!(maxFrameRate > 1)) maxFrameRate = 1; + if (!(maxFrameRate < 100)) maxFrameRate = 100; + if (minFrameRate > maxFrameRate) minFrameRate = maxFrameRate; + minFPS = minFrameRate; + maxFPS = maxFrameRate; } +void worldSetFrameRate(double frameRate) + { worldSetFrameRateEx(frameRate, frameRate); } + +double worldGetFrameTime() + { return frameTime; } + +double worldGetMinFrameRate(); +void worldSetMinFrameRate(double minFrameRate); + +double worldGetMaxFrameRate(); +void worldSetMaxFrameRate(double maxFrameRate); + +void worldSetFrameRate(double frameRate); + +double worldGetFrameTime(); -double worldGetTimeStep() - { return 1/frameRate; } int worldGetFrameCount() { return (int)frameCount; } @@ -167,34 +196,6 @@ void worldStop() { if (started) stopped = TRUE; } -void cameraOn() - { cameraEnabled = TRUE; } -void cameraOff() - { cameraEnabled = FALSE; } -int cameraIsActive() - { return cameraEnabled; } - -double cameraMouseX() - { return _mouseX/cameraZoom + cameraX; } -double cameraMouseY() - { return _mouseY/cameraZoom + cameraY; } - -double cameraGetX() - { return cameraX; } -void cameraSetX(double x) - { cameraX = x; } - -double cameraGetY() - { return cameraY; } -void cameraSetY(double y) - { cameraY = y; } - -double cameraGetZoom() - { return cameraZoom; } -void cameraSetZoom(double x) - { cameraZoom = x > HELI_PRECISION ? x : HELI_PRECISION; } - - void messageBox(const char *message) { SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_INFORMATION, @@ -219,12 +220,34 @@ static void resetEvents() { static void draw() { unsigned int currentFrameTimeMs = SDL_GetTicks(); - unsigned long long deltaUs = frameCount == 0 ? 0 : (currentFrameTimeMs - prevFrameTimeMs)*1000ull; + unsigned long long deltaUs = firstFrame ? 0 : (currentFrameTimeMs - prevFrameTimeMs)*1000ull; prevFrameTimeMs = currentFrameTimeMs; - if (dialog.shown) { + double actualMinFPS = minFPS, actualMaxFPS = maxFPS; + if (dialog.shown) { actualMinFPS = 1, actualMaxFPS = 100; } + + unsigned long long minTimeStepUs = (unsigned long long)round(1e6/actualMaxFPS); + unsigned long long maxTimeStepUs = (unsigned long long)round(1e6/actualMinFPS); + elapsedTimeSinceLastFrameUs += deltaUs; + if (elapsedTimeSinceLastFrameUs > 2000000) + elapsedTimeSinceLastFrameUs = 2000000; + if (firstFrame || elapsedTimeSinceLastFrameUs >= minTimeStepUs) { + unsigned long long encountedTimeUs = elapsedTimeSinceLastFrameUs; + if (encountedTimeUs > maxTimeStepUs) encountedTimeUs = maxTimeStepUs; + double dt = encountedTimeUs*1e-6; + + if (!firstFrame) elapsedTimeSinceLastFrameUs -= encountedTimeUs; + + if (!dialog.shown) { + elapsedTimeUs += encountedTimeUs; + ++frameCount; + frameTime = firstFrame ? 1/maxFPS : dt; + heliSpriteUpdate(dt); + } heliSoundUpdate(); + firstFrame = FALSE; + glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -232,44 +255,22 @@ static void draw() { glMatrixMode(GL_MODELVIEW); heliDrawingPrepareFrame(); - heliDialogDraw(&dialog); + if (dialog.shown) { + heliDialogDraw(&dialog); + } else { + if (drawCallback) + drawCallback(); + } resetEvents(); SDL_GL_SwapWindow(window); - SDL_Delay(20); - } else { - double dt = 1/frameRate; - unsigned long long timeStepUs = (unsigned long long)round(dt*1e6); - elapsedTimeSinceLastFrameUs += deltaUs; - if (elapsedTimeSinceLastFrameUs > 2000000) - elapsedTimeSinceLastFrameUs = 2000000; - if (frameCount == 0 || elapsedTimeSinceLastFrameUs >= timeStepUs) { - elapsedTimeUs += timeStepUs; - if (frameCount != 0) elapsedTimeSinceLastFrameUs -= timeStepUs; - ++frameCount; - - heliSpriteUpdate(dt); - heliSoundUpdate(); - - glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, width, height, 0, -1.0, 1.0); - glMatrixMode(GL_MODELVIEW); - - heliDrawingPrepareFrame(); - if (drawCallback) drawCallback(); - - resetEvents(); - SDL_GL_SwapWindow(window); - } - - unsigned long long addUs = elapsedTimeSinceLastFrameUs + (SDL_GetTicks() - prevFrameTimeMs)*1000ull; - if (addUs < timeStepUs) { - unsigned long long waitUs = timeStepUs - addUs; - if (waitUs > 2000) - SDL_Delay( (unsigned int)((waitUs + 500)/1000ull) ); - } + } + + unsigned long long addUs = elapsedTimeSinceLastFrameUs + (SDL_GetTicks() - prevFrameTimeMs)*1000ull; + if (addUs < minTimeStepUs) { + unsigned long long waitUs = minTimeStepUs - addUs; + if (waitUs > 2000) + SDL_Delay( (unsigned int)((waitUs + 500)/1000ull) ); } } @@ -463,6 +464,7 @@ void worldRun() { started = TRUE; stopped = FALSE; + firstFrame = TRUE; frameCount = 0; elapsedTimeUs = 0; elapsedTimeSinceLastFrameUs = 0; diff --git a/src/world.h b/src/world.h index a912a38..3dcf00e 100644 --- a/src/world.h +++ b/src/world.h @@ -39,6 +39,9 @@ int mouseWentUp(const char *code); double mouseX(); double mouseY(); +double transformedMouseX(); +double transformedMouseY(); + int mouseIsOver(Sprite sprite); int mousePressedOver(Sprite sprite); @@ -61,10 +64,11 @@ void worldSetResizable(int resizable); const char* worldGetTitle(); void worldSetTitle(const char *title); -double worldGetFrameRate(); +double worldGetMinFrameRate(); +double worldGetMaxFrameRate(); +void worldSetFrameRateEx(double minFrameRate, double maxFrameRate); void worldSetFrameRate(double frameRate); - -double worldGetTimeStep(); +double worldGetFrameTime(); int worldGetFrameCount(); double worldGetSeconds(); @@ -76,21 +80,4 @@ void worldRun(); void worldStop(); -void cameraOn(); -void cameraOff(); -int cameraIsActive(); - -double cameraMouseX(); -double cameraMouseY(); - -double cameraGetX(); -void cameraSetX(double x); - -double cameraGetY(); -void cameraSetY(double y); - -double cameraGetZoom(); -void cameraSetZoom(double zoom); - - #endif diff --git a/src/worldui.c b/src/worldui.c index 34c6579..945c9ea 100644 --- a/src/worldui.c +++ b/src/worldui.c @@ -146,15 +146,10 @@ static void draw(HeliDialog *dialog) { noFill(); stroke(strokeColor); + cliprect(l, t, r - l, b - t); textAlign(HALIGN_LEFT, VALIGN_TOP); text(dialog->answer, l + dialog->scrollX, t + dialog->scrollY); - - noStroke(); - fill(fillColor); - rect(0, 0, l, h); - rect(r, 0, w - r, h); - rect(0, 0, w, t); - rect(0, b, w, h - b); + noClip(); noFill(); stroke(strokeColor);