X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fglx%2Fcrumbler.c;h=8e783dbc0d7d242c7af652f1659c240afd3183be;hp=cf21a94e1cd5d0716001e89ca0fe9aa2a088b138;hb=refs%2Fheads%2Fmaster;hpb=78add6e627ee5f10e1fa6f3852602ea5066eee5a diff --git a/hacks/glx/crumbler.c b/hacks/glx/crumbler.c index cf21a94e..fccee8de 100644 --- a/hacks/glx/crumbler.c +++ b/hacks/glx/crumbler.c @@ -14,10 +14,7 @@ "*wireframe: False \n" \ "*suppressRotationAnimation: True\n" \ -# define free_crumbler 0 # define release_crumbler 0 -#undef countof -#define countof(x) (sizeof((x))/sizeof((*x))) #include "xlockmore.h" #include "colors.h" @@ -112,17 +109,29 @@ make_point_cloud (qh_vertex_t *verts, int nverts) } } +static void crumbler_oom (void) +{ +# ifdef HAVE_JWXYZ + jwxyz_abort ("%s: out of memory, try reducing 'density'", progname); +# else + fprintf (stderr, "%s: out of memory, try reducing 'density'\n", progname); + exit (1); +# endif +} + static chunk * make_chunk (void) { chunk *c = (chunk *) calloc (1, sizeof(*c)); + if (!c) crumbler_oom(); c->dlist = glGenLists (1); c->color_shift = 1 + (random() % 3) * RANDSIGN(); return c; } -static void +/* Return False if out of memory */ +static Bool render_chunk (ModeInfo *mi, chunk *c) { int wire = MI_IS_WIREFRAME(mi); @@ -130,15 +139,16 @@ render_chunk (ModeInfo *mi, chunk *c) qh_mesh_t m; GLfloat d; - c->polygon_count = 0; - c->min.x = c->min.y = c->min.z = 999999; - c->max.x = c->max.y = c->max.z = -999999; if (c->nverts <= 3) { fprintf (stderr, "%s: nverts %d\n", progname, c->nverts); abort(); } + c->polygon_count = 0; + c->min.x = c->min.y = c->min.z = 999999; + c->max.x = c->max.y = c->max.z = -999999; + for (i = 0; i < c->nverts; i++) { if (c->verts[i].x < c->min.x) c->min.x = c->verts[i].x; @@ -169,6 +179,12 @@ render_chunk (ModeInfo *mi, chunk *c) m = qh_quickhull3d (c->verts, c->nverts); + if (!m.vertices) /* out of memory */ + { + qh_free_mesh (m); + return False; + } + glNewList (c->dlist, GL_COMPILE); if (! wire) glBegin (GL_TRIANGLES); for (i = 0, j = 0; i < m.nindices; i += 3, j++) @@ -212,14 +228,16 @@ render_chunk (ModeInfo *mi, chunk *c) glEndList(); qh_free_mesh (m); + return True; } static void free_chunk (chunk *c) { + if (c->dlist) + glDeleteLists (c->dlist, 1); free (c->verts); - glDeleteLists (c->dlist, 1); free (c); } @@ -244,7 +262,7 @@ pad_chunk (chunk *c, int min) if (c->nverts >= min) return; if (c->nverts <= 3) abort(); verts = (qh_vertex_t *) calloc (min, sizeof(*verts)); - if (!verts) abort(); + if (!verts) crumbler_oom(); memcpy (verts, c->verts, c->nverts * sizeof(*verts)); i = c->nverts; while (i < min) @@ -311,6 +329,7 @@ pad_chunk (chunk *c, int min) #if 0 qh_vertex_t *verts2 = (qh_vertex_t *) calloc (n, sizeof(*verts2)); + if (!verts2) crumbler_oom(); memcpy (verts2, v, n * sizeof(*verts2)); free (c->verts); c->verts = verts2; @@ -334,15 +353,22 @@ split_chunk (ModeInfo *mi, chunk *c, int nchunks) render_chunk */ crumbler_configuration *bp = &bps[MI_SCREEN(mi)]; - chunk **chunks = (chunk **) calloc (nchunks, sizeof(*chunks)); - int *keys = (int *) calloc (nchunks, sizeof(*keys)); + chunk **chunks; + int *keys; int i, j; - chunk *c2; + int retries = 0; + + RETRY: + chunks = (chunk **) calloc (nchunks, sizeof(*chunks)); + if (!chunks) crumbler_oom(); + keys = (int *) calloc (nchunks, sizeof(*keys)); + if (!keys) crumbler_oom(); for (i = 0; i < nchunks; i++) { /* Fill keys with random numbers that are not duplicates. */ Bool ok = True; + chunk *c2 = 0; if (nchunks >= c->nverts) { fprintf (stderr, "%s: nverts %d nchunks %d\n", progname, @@ -351,21 +377,22 @@ split_chunk (ModeInfo *mi, chunk *c, int nchunks) } do { keys[i] = random() % c->nverts; + ok = True; for (j = 0; j < i; j++) if (keys[i] == keys[j]) { ok = False; break; } - ok = True; } while (!ok); c2 = make_chunk(); chunks[i] = c2; chunks[i]->nverts = 0; c2->verts = (qh_vertex_t *) calloc (c->nverts, sizeof(*c2->verts)); - c2->color = (c->color + (random() % (1 + (bp->ncolors / 3))) - % bp->ncolors); + if (!c2->verts) crumbler_oom(); + c2->color = (c->color + (random() % (1 + (bp->ncolors / 3)))) + % bp->ncolors; } /* Add the verts to the approprate chunks @@ -375,6 +402,8 @@ split_chunk (ModeInfo *mi, chunk *c, int nchunks) qh_vertex_t *v0 = &c->verts[i]; int target_chunk = -1; double target_d2 = 9999999; + chunk *c2 = 0; + for (j = 0; j < nchunks; j++) { qh_vertex_t *v1 = &c->verts[keys[j]]; @@ -392,17 +421,40 @@ split_chunk (ModeInfo *mi, chunk *c, int nchunks) c2 = chunks[target_chunk]; c2->verts[c2->nverts++] = *v0; + if (c2->nverts > c->nverts) abort(); } + free (keys); + keys = 0; + for (i = 0; i < nchunks; i++) { - c2 = chunks[i]; + chunk *c2 = chunks[i]; + + /* It is possible that the keys we have chosen have resulted in one or + more cells that have 3 or fewer points in them. If that's the case, + re-randomize. + */ + if (c2->nverts <= 3) + { + for (j = 0; j < nchunks; j++) + free_chunk (chunks[j]); + free (chunks); + chunks = 0; + if (retries++ > 100) + { + fprintf(stderr, "%s: unsplittable\n", progname); + abort(); + } + goto RETRY; + } + if (i == 0) /* The one we're gonna keep */ pad_chunk (c2, c->nverts); - render_chunk (mi, c2); + if (! render_chunk (mi, c2)) + crumbler_oom(); /* We are too far in to recover from this */ } - free (keys); return chunks; } @@ -453,7 +505,8 @@ tick_crumbler (ModeInfo *mi) /* Re-render it to move the verts in the display list too. This also recomputes min, max and mid. */ - render_chunk (mi, c); + if (! render_chunk (mi, c)) + crumbler_oom(); /* We are too far in to recover from this */ break; } @@ -500,7 +553,8 @@ tick_crumbler (ModeInfo *mi) /* Re-render it to move the verts in the display list too. This also recomputes min, max and mid (now 0). */ - render_chunk (mi, c); + if (! render_chunk (mi, c)) + crumbler_oom(); /* We are too far in to recover from this */ break; } @@ -554,13 +608,12 @@ reshape_crumbler (ModeInfo *mi, int width, int height) 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); -# ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */ { - int o = (int) current_device_rotation(); - if (o != 0 && o != 180 && o != -180) - glScalef (1/h, 1/h, 1/h); + GLfloat s = (MI_WIDTH(mi) < MI_HEIGHT(mi) + ? (MI_WIDTH(mi) / (GLfloat) MI_HEIGHT(mi)) + : 1); + glScalef (s, s, s); } -# endif glClear(GL_COLOR_BUFFER_BIT); } @@ -631,6 +684,7 @@ init_crumbler (ModeInfo *mi) bp->ncolors = 1024; bp->colors = (XColor *) calloc(bp->ncolors, sizeof(XColor)); + if (!bp->colors) crumbler_oom(); make_smooth_colormap (0, 0, 0, bp->colors, &bp->ncolors, False, 0, False); @@ -647,26 +701,55 @@ init_crumbler (ModeInfo *mi) } { + double d2 = density; chunk *c; + bp->nchunks = 1; bp->chunks = (chunk **) calloc (bp->nchunks, sizeof(*bp->chunks)); + if (! bp->chunks) crumbler_oom(); + c = make_chunk(); + if (! c) crumbler_oom(); + bp->chunks[0] = c; - c->nverts = 4500 * density; - c->verts = (qh_vertex_t *) calloc (c->nverts, sizeof(*c->verts)); - make_point_cloud (c->verts, c->nverts); - - /* Let's shrink it to a point then zoom in. */ - bp->state = ZOOM; - bp->tick = 0; - for (i = 0; i < c->nverts; i++) + + while (1) { - c->verts[i].x /= 500; - c->verts[i].y /= 500; - c->verts[i].z /= 500; + c->nverts = 4500 * d2; + c->verts = (qh_vertex_t *) calloc (c->nverts, sizeof(*c->verts)); + if (c->verts) + { + make_point_cloud (c->verts, c->nverts); + + /* Let's shrink it to a point then zoom in. */ + bp->state = ZOOM; + bp->tick = 0; + for (i = 0; i < c->nverts; i++) + { + c->verts[i].x /= 500; + c->verts[i].y /= 500; + c->verts[i].z /= 500; + } + + if (! render_chunk (mi, c)) + { + free (c->verts); + c->verts = 0; + } + } + + if (c->verts) + break; + + if (d2 < 0.1) + crumbler_oom(); + d2 *= 0.9; } - render_chunk (mi, c); + if (density != d2) + fprintf (stderr, + "%s: out of memory: reduced density from %.01f to %0.1f\n", + progname, density, d2); } } @@ -709,7 +792,7 @@ draw_crumbler (ModeInfo *mi) if (!bp->glx_context) return; - glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context)); + glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context); tick_crumbler (mi); @@ -817,6 +900,23 @@ draw_crumbler (ModeInfo *mi) glXSwapBuffers(dpy, window); } + +ENTRYPOINT void +free_crumbler (ModeInfo *mi) +{ + crumbler_configuration *bp = &bps[MI_SCREEN(mi)]; + int i; + if (!bp->glx_context) return; + glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context); + if (bp->trackball) gltrackball_free (bp->trackball); + if (bp->rot) free_rotator (bp->rot); + if (bp->colors) free (bp->colors); + for (i = 0; i < bp->nchunks; i++) + free_chunk (bp->chunks[i]); + if (bp->chunks) free (bp->chunks); +} + + XSCREENSAVER_MODULE ("Crumbler", crumbler) #endif /* USE_GL */