Ejemplo n.º 1
0
/* XImage allocation for normal client-side buffer */
void _ggi_x_freefb(struct ggi_visual *vis)
{
	ggi_x_priv *priv = GGIX_PRIV(vis);

	if (priv->slave) {
		struct gg_stem *stem = priv->slave->instance.stem;
		ggiClose(priv->slave->instance.stem);
		ggDelStem(stem);
		priv->slave = NULL;
	}

	if (priv->ximage) {
#ifndef HAVE_XINITIMAGE
		XFree(priv->ximage);
#else
		free(priv->ximage);
#endif
		priv->ximage = NULL;
	}

	if (priv->fb) {
		free(priv->fb);
		priv->fb = NULL;
	}

	LIB_ASSERT(priv->slave == NULL, "priv->slave: wild pointer\n");
	LIB_ASSERT(priv->ximage == NULL, "priv->ximage: wild pointer\n");
	LIB_ASSERT(priv->fb == NULL, "priv->fb: wild pointer\n");

	_ggi_free_dbs(vis);
}
Ejemplo n.º 2
0
Archivo: db.c Proyecto: antrik/libggi
/* _ggi_db_add_buffer
   Adds a buffer at the end of the list.
   Returns the position of the buffer (starting with 0).
*/
int _ggi_db_add_buffer(ggi_db_list *dbl, ggi_directbuffer *buf)
{
	LIB_ASSERT(dbl != NULL, "_ggi_db_add_buffer: list is NULL");
	LIB_ASSERT(buf != NULL, "_ggi_db_add_buffer: buffer is NULL");

	dbl->num++;
	dbl->bufs = _ggi_realloc(dbl->bufs, sizeof(ggi_directbuffer *) * dbl->num);
	dbl->bufs[dbl->num-1] = buf;

	return dbl->num-1;
}
Ejemplo n.º 3
0
Archivo: db.c Proyecto: antrik/libggi
/* _ggi_db_del_buffer
   Deletes the buffer at position idx from the list.
   Returns the number of buffers left in the list.
*/
int _ggi_db_del_buffer(ggi_db_list *dbl, int idx)
{
	LIB_ASSERT(dbl != NULL, "_ggi_db_del_buffer: list is NULL");
	LIB_ASSERT(dbl->num > 0, "_ggi_db_del_buffer: called for empty list");

	dbl->num--;
	memmove(dbl->bufs+idx, dbl->bufs+idx+1, (dbl->num-idx)*sizeof(ggi_directbuffer));
	if (dbl->num == 0) {
		free(dbl->bufs);
		dbl->bufs = NULL;
	} else {
		dbl->bufs = _ggi_realloc(dbl->bufs, sizeof(ggi_directbuffer *) * dbl->num);
	}
	
	return dbl->num;
}
Ejemplo n.º 4
0
Archivo: shm.c Proyecto: antrik/libggi
/* XImage allocation for normal client-side buffer */
static void _ggi_xshm_free_ximage(struct ggi_visual *vis)
{
	ggi_x_priv *priv;
	XShmSegmentInfo *myshminfo;

	priv = GGIX_PRIV(vis);
	myshminfo = priv->priv;
	if (myshminfo == NULL)
		return;

	if (priv->slave) {
		struct gg_stem *stem = priv->slave->instance.stem;
		ggiClose(priv->slave->instance.stem);
		ggDelStem(stem);
		priv->slave = NULL;
	}

	if (priv->ximage) {
		XShmDetach(priv->disp, myshminfo);
		/* Seems OK to destroy image before fb for SHM */
	  	XDestroyImage(priv->ximage);
	  	shmdt(myshminfo->shmaddr);
		/* shmid has already been removed, see below. */
		priv->ximage = NULL;
		priv->fb = NULL;
	}

	if (priv->fb) {
		free(priv->fb);
		priv->fb = NULL;
	}

	LIB_ASSERT(priv->slave == NULL, "priv->slave: wild pointer\n");
	LIB_ASSERT(priv->ximage == NULL, "priv->ximage: wild pointer\n");
	LIB_ASSERT(priv->fb == NULL, "priv->fb: wild pointer\n");

	free(myshminfo);
	priv->priv = NULL;

	_ggi_free_dbs(vis);
}
Ejemplo n.º 5
0
static int GGIclose(struct ggi_visual *vis, struct ggi_dlhandle *dlh)
{
  	suid_hook *priv = SUIDHOOK(vis);
	ggi_mode mode;
	int x;
	
	LIB_ASSERT(priv != NULL, "display-suidkgi: priv == NULL");

	if (priv->is_up) {
#if 1
		/* Not sure, if this is needed, but ... */
		mode.frames=1;
		mode.graphtype=GT_TEXT16;
		mode.visible.x=mode.virt.x=80;
		mode.visible.y=mode.virt.y=25;
		mode.dpp.x = 9;mode.dpp.y =14;
		x=GGI_suidkgi_checkmode(vis,&mode);
		DPRINT("TESTMODE1 says %d.\n",x);
		x=GGI_suidkgi_setmode(vis,&mode);
		DPRINT("SETMODE1 says %d.\n",x);
#endif
		
/*		suidkgi_cleanup_module(); */

		if (priv->vt_fd >= 0) {
			vtswitch_close(vis);
			priv->vt_fd = -1;
		}

		DPRINT("Cleanup went well.\n");
		close(priv->dev_mem);
		priv->is_up=0;
	}

	if (vis->input) {
		giiClose(vis->input);
		vis->input = NULL;
	}
	
	free(priv);

	return 0;
}
Ejemplo n.º 6
0
int
GGI_directx_DDChangePalette(struct ggi_visual *vis)
{
	directx_priv *priv = LIBGGI_PRIVATE(vis);
	int start       = LIBGGI_PAL(vis)->rw_start;
	int stop        = LIBGGI_PAL(vis)->rw_stop;
	ggi_color *clut = LIBGGI_PAL(vis)->clut.data;
	HRESULT hr;
	int x;
	static PALETTEENTRY pal[256];

	LIB_ASSERT(priv->lpddp, "No palette!\n");

	if (start >= stop)
		return 0;

	for (x = start; x < stop; x++) {
		pal[x].peFlags = PC_NOCOLLAPSE;
		pal[x].peRed   = clut[x].r >> 8;
		pal[x].peGreen = clut[x].g >> 8;
		pal[x].peBlue  = clut[x].b >> 8;
	}
	/*
	for (x = 0; x < 10; x++) {
		pal[x].peFlags  = pal[x+246].peFlags = PC_EXPLICIT;
		pal[x].peRed = x;
		pal[x+246].peRed = x+246;
		pal[x].peGreen = pal[x].peBlue = 0;
	}
	*/

	hr = IDirectDrawPalette_SetEntries(
	priv->lpddp, 0, start, stop - start, &pal[start]);

	if (hr != 0) {
		fprintf(stderr, "DDP_SetEntries Failed RC = %ld. Exiting\n",
		hr & 0xffff);
		exit(-1);
	}

	return 0;
}
Ejemplo n.º 7
0
int GIIdl_quartz(gii_input *inp, const char *args, void *argptr)
{
	int rc = 0;
	gii_inputquartz_arg *quartzarg = argptr;
	quartz_priv *priv;

	DPRINT_MISC("quartz input starting. (args=%s,argptr=%p)\n",
		args, argptr);

	priv = calloc(1, sizeof(quartz_priv));
	if (priv == NULL) {
		rc = GGI_ENOMEM;
		goto err0;
	}

	/* Attention: quartzarg->theWindow is invalid at this point.
	 * It becomes valid once a mode has been set up.
	 */
	priv->theWindow = quartzarg->theWindow;
#if 0
	LIB_ASSERT(priv->theWindow != NULL, "quartzarg->theWindow is NULL\n");
#endif

	if (0 == (priv->origin[QZ_DEV_KEY] =
		_giiRegisterDevice(inp, &key_devinfo, NULL)))
	{
		rc = GGI_ENODEVICE;
		goto err1;
	}	/* if */

	if (0 == (priv->origin[QZ_DEV_MOUSE] =
		_giiRegisterDevice(inp, &mouse_devinfo, NULL)))
	{
		rc = GGI_ENODEVICE;
		goto err1;
	}	/* if */


	if (GGI_OK != QuartzInit(priv)) {
		rc = GGI_ENODEVICE;
		goto err2;
	}

	inp->GIIsendevent    = GII_quartz_send_event;
	inp->GIIeventpoll    = GII_quartz_eventpoll;
#if 0
	inp->GIIseteventmask = GII_quartz_seteventmask;
	inp->GIIgeteventmask = GII_quartz_geteventmaks;
#endif
	inp->GIIclose        = GII_quartz_close;

	inp->targetcan = emKey | emPointer;
	inp->curreventmask = emKey | emPointer;

	inp->maxfd = 0; /* We poll from an event queue - ouch! */
	inp->flags |= GII_FLAGS_HASPOLLED;
	inp->priv = priv;

	inp->GIIseteventmask(inp, inp->targetcan);

	if (GGI_OK != QuartzFinishLaunch(inp)) {
		rc = GGI_ENODEVICE;
		goto err2;
	}

	send_devinfo(inp, QZ_DEV_KEY);
	send_devinfo(inp, QZ_DEV_MOUSE);

	DPRINT_MISC("quartz input fully up\n");

	return GGI_OK;

err2:
err1:
	GII_quartz_close(inp);
err0:
	return rc;
}	/* GIIdlinit */
Ejemplo n.º 8
0
Archivo: db.c Proyecto: antrik/libggi
/* _ggi_db_free
   Frees a ggi_directbuffer obtained from _ggi_db_get_new.
*/
void _ggi_db_free(ggi_directbuffer *db)
{
	LIB_ASSERT(db != NULL, "_ggi_db_free: db is NULL");
	
	free(db);
}
Ejemplo n.º 9
0
static int _ggi_clip2d(ggi_visual *vis,int *_x0, int *_y0, int *_x1, int *_y1,
		       int *clip_first, int *clip_last)
{
	int first,last, code;
	int x0,y0,x1,y1;
	int x,y;
	int dx,dy;
	unsigned int absdx, absdy;
	int xmajor;
	int slope;
	int i;

	*clip_first = first = 0;
	*clip_last = last = 0;
	outcode(first,*_x0,*_y0);
	outcode(last,*_x1,*_y1);

	if ((first | last) == 0) {
		return 1; /* Trivially accepted! */
	}
	if ((first & last) != 0) {
		return 0; /* Trivially rejected! */
	}

	x0=*_x0; y0=*_y0;
	x1=*_x1; y1=*_y1;

	dx = x1 - x0;
	dy = y1 - y0;

	absdx = x0 < x1 ? x1 - x0 : x0 - x1;
	absdy = y0 < y1 ? y1 - y0 : y0 - y1;
	xmajor = absdx > absdy;
	slope = ((x1>=x0) && (y1>=y0)) || ((x1<x0) && (y1<y0));

	if ((absdx > MAX_DIFF) || (absdy > MAX_DIFF)) {
		return _ggi_clip2d_3(vis, _x0, _y0, _x1, _y1,
			clip_first, clip_last);
	}

	for (i = 0; i < 4; i++) {
		code = first;
		if (first==0)
			code = last;

		if (code&OC_LEFT) {
			x = LIBGGI_GC(vis)->cliptl.x;
			if (xmajor) {
				y = *_y0 +  FloorDiv(dy*(x - *_x0)*2 + dx,
						      2*dx);
			} else {
				if (slope) {
					y = *_y0 + CeilDiv(dy*((x - *_x0)*2
							       - 1), 2*dx);
				} else {
					y = *_y0 + FloorDiv(dy*((x - *_x0)*2
								- 1), 2*dx);
				}
			}
		} else if (code&OC_RIGHT) {
			x = LIBGGI_GC(vis)->clipbr.x - 1;
			if (xmajor) {
				y = *_y0 +  FloorDiv(dy*(x - *_x0)*2 + dx, 2*dx);
			} else {
				if (slope) {
					y = *_y0 + CeilDiv(dy*((x - *_x0)*2
							       + 1), 2*dx)-1;
				} else {
					y = *_y0 + FloorDiv(dy*((x - *_x0)*2
								+ 1), 2*dx)+1;
				}
			}
		} else if (code&OC_TOP) {
			y = LIBGGI_GC(vis)->cliptl.y;
			if (xmajor) {
				if (slope) {
					x = *_x0 + CeilDiv(dx*((y - *_y0)*2
							       - 1), 2*dy);
				} else {
					x = *_x0 + FloorDiv(dx*((y - *_y0)*2
								- 1), 2*dy);
				}
			} else {
				x = *_x0 +  FloorDiv( dx*(y - *_y0)*2 + dy,
						      2*dy);
			}
		} else { /* OC_BOTTOM */
			LIB_ASSERT((code & OC_BOTTOM), "unknown outcode\n");
			y = LIBGGI_GC(vis)->clipbr.y - 1;
			if (xmajor) {
				if (slope) {
					x = *_x0 + CeilDiv(dx*((y - *_y0)*2
							       + 1), 2*dy)-1;
				} else {
					x = *_x0 + FloorDiv(dx*((y - *_y0)*2
								+ 1), 2*dy)+1;
				}
			} else {
				x = *_x0 +  FloorDiv(dx*(y - *_y0)*2 + dy,
						     2*dy);
			}
		}

		if (first!=0) {
			x0 = x;
			y0 = y;
			outcode(first,x0,y0);
			*clip_first = 1;
		} else {
			x1 = x;
			y1 = y;
			last = code;
			outcode(last,x1,y1);
			*clip_last = 1;
		}

		if ((first & last) != 0) {
			return 0; /* Trivially rejected! */
		}
		if ((first | last) == 0) {
			*_x0=x0; *_y0=y0;
			*_x1=x1; *_y1=y1;
			return 1; /* Trivially accepted! */
		}
	}
	return 0; /* Aieee! Failed to clip, clip whole line... */
}
Ejemplo n.º 10
0
static int _ggi_clip2d_3(ggi_visual *vis,
			     int *_x0, int *_y0,
			     int *_x1, int *_y1,
			     int *clip_first, int *clip_last)
{
	int first,last, code;
	int x0,y0,x1,y1;
	int x,y;
	unsigned dx[3], dy[3], tmp[3];
	unsigned int absdx, absdy;
	int xmajor;
	int slope;
	int i;

	*clip_first = first = 0;
	*clip_last = last = 0;
	outcode(first,*_x0,*_y0);
	outcode(last,*_x1,*_y1);

	if ((first | last) == 0) {
		return 1; /* Trivially accepted! */
	}
	if ((first & last) != 0) {
		return 0; /* Trivially rejected! */
	}

	x0=*_x0; y0=*_y0;
	x1=*_x1; y1=*_y1;
	
	assign_int_3(dx, x1);
	assign_int_3(tmp, x0);
	sub_3(dx, tmp);

	assign_int_3(dy, y1);
	assign_int_3(tmp, y0);
	sub_3(dy, tmp);

	absdx = x0 < x1 ? x1 - x0 : x0 - x1;
	absdy = y0 < y1 ? y1 - y0 : y0 - y1;
	xmajor = absdx > absdy;
	slope = ((x1>=x0) && (y1>=y0)) || ((x1<x0) && (y1<y0));

	for (i = 0; i < 4; i++) {
		code = first;
		if (first==0)
			code = last;

		if (code&OC_LEFT) {
			x = LIBGGI_GC(vis)->cliptl.x;
			if (xmajor) {
				/* y = *_y0 + FloorDiv(dy*(x - *_x0)*2 + dx,
							2*dx); */
				unsigned _x[3], res[3];
				assign_int_3(_x, x);
				assign_int_3(tmp, *_x0);
				sub_3(_x, tmp);
				lshift_3(_x, 1);
				mul_3(_x, dy);
				add_3(_x, dx);
				assign_3(tmp, dx);
				lshift_3(tmp, 1);
				FloorDiv_3(res, _x, tmp);
				assign_int_3(tmp, *_y0);
				add_3(res, tmp);
				y = res[0];
			} else if (slope) {
				/* y = *_y0 + CeilDiv(dy*((x - *_x0)*2 - 1),
							2*dx); */
				unsigned _x[3], res[3];
				assign_int_3(_x, x);
				assign_int_3(tmp, *_x0);
				sub_3(_x, tmp);
				lshift_3(_x, 1);
				dec_3(_x);
				mul_3(_x, dy);
				assign_3(tmp, dx);
				lshift_3(tmp, 1);
				CeilDiv_3(res, _x, tmp);
				assign_int_3(tmp, *_y0);
				add_3(res, tmp);
				y = res[0];
			} else {
				/* y = *_y0 + FloorDiv(dy*((x - *_x0)*2 - 1),
							2*dx); */
				unsigned _x[3], res[3];
				assign_int_3(_x, x);
				assign_int_3(tmp, *_x0);
				sub_3(_x, tmp);
				lshift_3(_x, 1);
				dec_3(_x);
				mul_3(_x, dy);
				assign_3(tmp, dx);
				lshift_3(tmp, 1);
				FloorDiv_3(res, _x, tmp);
				assign_int_3(tmp, *_y0);
				add_3(res, tmp);
				y = res[0];
			}
		} else if (code&OC_RIGHT) {
			x = LIBGGI_GC(vis)->clipbr.x - 1;
			if (xmajor) {
				/* y = *_y0 + FloorDiv(dy*(x - *_x0)*2 + dx,
							2*dx); */
				unsigned _x[3], res[3];
				assign_int_3(_x, x);
				assign_int_3(tmp, *_x0);
				sub_3(_x, tmp);
				lshift_3(_x, 1);
				mul_3(_x, dy);
				add_3(_x, dx);
				assign_3(tmp, dx);
				lshift_3(tmp, 1);
				FloorDiv_3(res, _x, tmp);
				assign_int_3(tmp, *_y0);
				add_3(res, tmp);
				y = res[0];
			} else if (slope) {
				/* y = *_y0 + CeilDiv(dy*((x - *_x0)*2 + 1),
							2*dx)-1; */
				unsigned _x[3], res[3];
				assign_int_3(_x, x);
				assign_int_3(tmp, *_x0);
				sub_3(_x, tmp);
				lshift_3(_x, 1);
				inc_3(_x);
				mul_3(_x, dy);
				assign_3(tmp, dx);
				lshift_3(tmp, 1);
				CeilDiv_3(res, _x, tmp);
				dec_3(res);
				assign_int_3(tmp, *_y0);
				add_3(res, tmp);
				y = res[0];
			} else {
				/* y = *_y0 + FloorDiv(dy*((x - *_x0)*2 + 1),
							2*dx)+1; */
				unsigned _x[3], res[3];
				assign_int_3(_x, x);
				assign_int_3(tmp, *_x0);
				sub_3(_x, tmp);
				lshift_3(_x, 1);
				inc_3(_x);
				mul_3(_x, dy);
				assign_3(tmp, dx);
				lshift_3(tmp, 1);
				FloorDiv_3(res, _x, tmp);
				inc_3(res);
				assign_int_3(tmp, *_y0);
				add_3(res, tmp);
				y = res[0];
			}
		} else if (code&OC_TOP) {
			y = LIBGGI_GC(vis)->cliptl.y;
			if (!xmajor) {
				/* x = *_x0 + FloorDiv(dx*(y - *_y0)*2 + dy,
							2*dy); */
				unsigned _y[3], res[3];
				assign_int_3(_y, y);
				assign_int_3(tmp, *_y0);
				sub_3(_y, tmp);
				lshift_3(_y, 1);
				mul_3(_y, dx);
				add_3(_y, dy);
				assign_3(tmp, dy);
				lshift_3(tmp, 1);
				FloorDiv_3(res, _y, tmp);
				assign_int_3(tmp, *_x0);
				add_3(res, tmp);
				x = res[0];
			} else if (slope) {
				/* x = *_x0 + CeilDiv(dx*((y - *_y0)*2 - 1),
							2*dy); */
				unsigned _y[3], res[3];
				assign_int_3(_y, y);
				assign_int_3(tmp, *_y0);
				sub_3(_y, tmp);
				lshift_3(_y, 1);
				dec_3(_y);
				mul_3(_y, dx);
				assign_3(tmp, dy);
				lshift_3(tmp, 1);
				CeilDiv_3(res, _y, tmp);
				assign_int_3(tmp, *_x0);
				add_3(res, tmp);
				x = res[0];
			} else {
				/* x = *_x0 + FloorDiv(dx*((y - *_y0)*2 - 1),
							2*dy); */
				unsigned _y[3], res[3];
				assign_int_3(_y, y);
				assign_int_3(tmp, *_y0);
				sub_3(_y, tmp);
				lshift_3(_y, 1);
				dec_3(_y);
				mul_3(_y, dx);
				assign_3(tmp, dy);
				lshift_3(tmp, 1);
				FloorDiv_3(res, _y, tmp);
				assign_int_3(tmp, *_x0);
				add_3(res, tmp);
				x = res[0];
			}
		} else { /* OC_BOTTOM */
			LIB_ASSERT((code & OC_BOTTOM), "unknown outcode\n");
			y = LIBGGI_GC(vis)->clipbr.y - 1;
			if (!xmajor) {
				/* x = *_x0 + FloorDiv(dx*(y - *_y0)*2 + dy,
							2*dy); */
				unsigned _y[3], res[3];
				assign_int_3(_y, y);
				assign_int_3(tmp, *_y0);
				sub_3(_y, tmp);
				lshift_3(_y, 1);
				mul_3(_y, dx);
				add_3(_y, dy);
				assign_3(tmp, dy);
				lshift_3(tmp, 1);
				FloorDiv_3(res, _y, tmp);
				assign_int_3(tmp, *_x0);
				add_3(res, tmp);
				x = res[0];
			} else if (slope) {
				/* x = *_x0 + CeilDiv(dx*((y - *_y0)*2 + 1),
							2*dy)-1; */
				unsigned _y[3], res[3];
				assign_int_3(_y, y);
				assign_int_3(tmp, *_y0);
				sub_3(_y, tmp);
				lshift_3(_y, 1);
				inc_3(_y);
				mul_3(_y, dx);
				assign_3(tmp, dy);
				lshift_3(tmp, 1);
				CeilDiv_3(res, _y, tmp);
				dec_3(res);
				assign_int_3(tmp, *_x0);
				add_3(res, tmp);
				x = res[0];
			} else {
				/* x = *_x0 + FloorDiv(dx*((y - *_y0)*2 + 1),
							2*dy)+1; */
				unsigned _y[3], res[3];
				assign_int_3(_y, y);
				assign_int_3(tmp, *_y0);
				sub_3(_y, tmp);
				lshift_3(_y, 1);
				inc_3(_y);
				mul_3(_y, dx);
				assign_3(tmp, dy);
				lshift_3(tmp, 1);
				FloorDiv_3(res, _y, tmp);
				inc_3(res);
				assign_int_3(tmp, *_x0);
				add_3(res, tmp);
				x = res[0];
			}
		}

		if (first!=0) {
			x0 = x;
			y0 = y;
			outcode(first,x0,y0);
			*clip_first = 1;
		} else {
			x1 = x;
			y1 = y;
			last = code;
			outcode(last,x1,y1);
			*clip_last = 1;
		}

		if ((first & last) != 0) {
			return 0; /* Trivially rejected! */
		}
		if ((first | last) == 0) {
			*_x0=x0; *_y0=y0;
			*_x1=x1; *_y1=y1;
			return 1; /* Trivially accepted! */
		}
	}
	return 0; /* Aieee! Failed to clip, clip whole line... */
}
Ejemplo n.º 11
0
void
World::think()
{
  auto world = Core_detail::world_index_get_world_data(m_impl->world_instance_id);
  LIB_ASSERT(world);

  /*
    Calculate Delta time.
  */
  {
    const lib::milliseconds now = lib::timer::get_current_time();
    const lib::milliseconds frame_time = lib::timer::get_delta(m_impl->dt_timer, now);
    m_impl->dt = lib::timer::to_seconds(frame_time);
    m_impl->dt_timer = now;
    
    m_impl->running_time += m_impl->dt;
  }

  /*
    Engine thing.
    Most of this can go I think, or at least be brought into here.
  */
  Engine::Tick_information tick_info;
  {
    auto resources = Data::get_context_data();
    LIB_ASSERT(resources);

    Engine::think(
      world,
      resources,
      m_impl->dt,
      m_impl->running_time,
      m_impl->context->get_width(),
      m_impl->context->get_height(),
      &tick_info);
  }
  
  /*
    Distro Collisions
  */
  {
    Data::Physics::Physics_data *phys = world->physics;
    LIB_ASSERT(phys);
    
    Data::Graph::Graph_data *graph = world->scene_graph;
    LIB_ASSERT(graph);
    
    const size_t coll_count(
      Data::Physics::world_get_number_of_colliding_items(phys)
    );
    
    const Data::Physics::Contact *contacts(
      Data::Physics::world_get_colliding_items(phys)
    );
    
    for(size_t i = 0; i < coll_count; ++i)
    {
      uintptr_t collision_callback = 0;
      uintptr_t user_data = 0;
      
      const uint32_t this_id = lib::bits::lower32(contacts[i].collision_a_b);
      
      Data::Graph::node_get_collision_callback(
        graph,
        this_id,
        &user_data,
        &collision_callback
      );

      if(collision_callback)
      {
        ((on_collision_callback_fn)collision_callback)(
          user_data,
          Entity_ref(this_id),
          to_core_collision(&contacts[i], 1)
        );
      }
    }
  }
  
  /*
    Debug Menu
    --
    Shows the debugging menu bar at the top of the screen.
  */
  #ifdef CORE_DEBUG_MENU
  {
    auto world = Core_detail::world_index_get_world_data(m_impl->world_instance_id);
  
    Debug_menu::display_global_data_menu(m_impl->context->get_context_data()->input_pool);
    Debug_menu::display_world_data_menu(
      world.get(),
      m_impl->dt,
      m_impl->dt_mul,
      12345,
      tick_info.number_of_draw_calls,
      tick_info.camera_runs
    );
  }
  #endif
}