Пример #1
0
void CGameObject::OnRender			()
{
	if (!ai().get_level_graph())
		return;

	CDebugRenderer					&renderer = Level().debug_renderer();
	if (/**bDebug && /**/Visual()) {
		float						half_cell_size = 1.f*ai().level_graph().header().cell_size()*.5f;
		Fvector						additional = Fvector().set(half_cell_size,half_cell_size,half_cell_size);

		render_box					(Visual(),XFORM(),Fvector().set(0.f,0.f,0.f),true,color_rgba(0,0,255,255));
		render_box					(Visual(),XFORM(),additional,false,color_rgba(0,255,0,255));
	}

	if (0) {
		Fvector						bc,bd; 
		Visual()->getVisData().box.get_CD	(bc,bd);
		Fmatrix						M = Fidentity;
		float						half_cell_size = ai().level_graph().header().cell_size()*.5f;
		bd.add						(Fvector().set(half_cell_size,half_cell_size,half_cell_size));
		M.scale						(bd);
		Fmatrix						T = XFORM();
		T.c.add						(bc);
		renderer.draw_obb			(T,bd,color_rgba(255,255,255,255));
	}
}
Пример #2
0
void wf_view_transformer_t::render_with_damage(uint32_t src_tex, wlr_box src_box,
            const wf_region& damage, const wf_framebuffer& target_fb)
{
    for (const auto& rect : damage)
    {
        auto box = target_fb.framebuffer_box_from_damage_box(
            wlr_box_from_pixman_box(rect));
        render_box(src_tex, src_box, box, target_fb);
    }
}
Пример #3
0
static int tool_laser_iter(goxel_t *goxel, const inputs_t *inputs, int state,
                           const vec2_t *view_size, bool inside)
{
    vec3_t pos, normal;
    box_t box;
    painter_t painter = goxel->painter;
    mesh_t *mesh = goxel->image->active_layer->mesh;
    const bool down = inputs->mouse_down[0];
    // XXX: would be nice if we got the vec4_t view instead of view_size,
    // and why input->pos is not already in win pos?
    vec4_t view = vec4(0, 0, view_size->x, view_size->y);
    vec2_t win = inputs->mouse_pos;
    win.y = view_size->y - win.y;

    painter.op = OP_SUB;
    painter.shape = &shape_cylinder;
    // Create the tool box from the camera along the visible ray.
    camera_get_ray(&goxel->camera, &win, &view, &pos, &normal);
    box.mat = mat4_identity;
    box.w = mat4_mul_vec(mat4_inverted(goxel->camera.view_mat),
                     vec4(1, 0, 0, 0)).xyz;
    box.h = mat4_mul_vec(mat4_inverted(goxel->camera.view_mat),
                     vec4(0, 1, 0, 0)).xyz;
    box.d = mat4_mul_vec(mat4_inverted(goxel->camera.view_mat),
                     vec4(0, 0, 1, 0)).xyz;
    box.d = vec3_neg(normal);
    box.p = pos;
    // Just a large value for the size of the laser box.
    mat4_itranslate(&box.mat, 0, 0, -1024);
    mat4_iscale(&box.mat, goxel->tool_radius, goxel->tool_radius, 1024);
    render_box(&goxel->rend, &box, false, NULL, false);
    if (state == STATE_IDLE) {
        if (down) {
            state = STATE_PAINT;
            image_history_push(goxel->image);
        }
    }
    if (state == STATE_PAINT) {
        if (!down) {
            return STATE_IDLE;
        }
        mesh_op(mesh, &painter, &box);
        goxel_update_meshes(goxel, -1);
    }
    return state;
}
Пример #4
0
static int tool_procedural_iter(goxel_t *goxel, const inputs_t *inputs,
                                int state, const vec2_t *view_size,
                                bool inside)
{
    int snaped = 0;
    vec3_t pos, normal;
    box_t box;
    gox_proc_t *proc = &goxel->proc;
    const bool down = inputs->mouse_down[0];

    if (proc->state == PROC_PARSE_ERROR) return 0;

    // XXX: duplicate code with tool_brush_iter.
    if (inside)
        snaped = goxel_unproject(
                goxel, view_size, &inputs->mouse_pos,
                goxel->painter.op == OP_ADD && !goxel->snap_offset,
                &pos, &normal);
    if (snaped) {
        if (goxel->tool == TOOL_BRUSH && goxel->snap_offset)
            vec3_iaddk(&pos, normal, goxel->snap_offset * goxel->tool_radius);
        pos.x = round(pos.x - 0.5) + 0.5;
        pos.y = round(pos.y - 0.5) + 0.5;
        pos.z = round(pos.z - 0.5) + 0.5;
        box = bbox_from_extents(pos, 0.5, 0.5, 0.5);
        render_box(&goxel->rend, &box, false, NULL, false);
    }
    if (state == STATE_IDLE) {
        if (snaped) state = STATE_SNAPED;
    }
    if (state == STATE_SNAPED) {
        if (!snaped) return STATE_IDLE;
        if (down) {
            image_history_push(goxel->image);
            proc_stop(proc);
            proc_start(proc, &box);
            state = STATE_PAINT;
        }
    }
    if (state == STATE_PAINT) {
        if (!down) state = STATE_IDLE;
    }
    return state;
}
Пример #5
0
static int tool_laser_iter(goxel_t *goxel, const inputs_t *inputs, int state,
                           const vec2_t *view_size, bool inside)
{
    vec3_t pos, normal;
    box_t box;
    painter_t painter = goxel->painter;
    mesh_t *mesh = goxel->image->active_layer->mesh;
    const bool down = inputs->mouse_down[0];

    painter.op = OP_SUB;
    painter.shape = &shape_cylinder;
    // Create the laser box with an inifinity width.
    goxel_unproject_on_screen(goxel, view_size, &inputs->mouse_pos,
                              &pos, &normal);
    box.mat = mat4_identity;
    box.w = mat4_mul_vec(mat4_inverted(goxel->camera.view_mat),
                     vec4(1, 0, 0, 0)).xyz;
    box.h = mat4_mul_vec(mat4_inverted(goxel->camera.view_mat),
                     vec4(0, 1, 0, 0)).xyz;
    box.d = mat4_mul_vec(mat4_inverted(goxel->camera.view_mat),
                     vec4(0, 0, 1, 0)).xyz;
    box.p = pos;
    mat4_itranslate(&box.mat, 0, 0, -128);
    mat4_iscale(&box.mat, goxel->tool_radius, goxel->tool_radius, 128);
    render_box(&goxel->rend, &box, false, NULL, false);
    if (state == STATE_IDLE) {
        if (down) state = STATE_PAINT;
    }
    if (state == STATE_PAINT) {
        if (!down) {
            image_history_push(goxel->image);
            return STATE_IDLE;
        }
        mesh_op(mesh, &painter, &box);
        goxel_update_meshes(goxel, false);
    }
    return state;
}
Пример #6
0
void render(void)
{
	render_begin();

	const PfxVector3 colorWhite(1.0f);
	const PfxVector3 colorGray(0.7f);

	for(int i=0;i<physics_get_num_rigidbodies();i++) {
		const PfxRigidState &state = physics_get_state(i);
		const PfxCollidable &coll = physics_get_collidable(i);

		PfxVector3 color = state.isAsleep()?colorGray:colorWhite;

		PfxTransform3 rbT(state.getOrientation(), state.getPosition());

		PfxShapeIterator itrShape(coll);
		for(PfxUInt32 j=0;j<coll.getNumShapes();j++,++itrShape) {
			const PfxShape &shape = *itrShape;
			PfxTransform3 offsetT = shape.getOffsetTransform();
			PfxTransform3 worldT = rbT * offsetT;

			switch(shape.getType()) {
				case kPfxShapeSphere:
				render_sphere(
					worldT,
					color,
					PfxFloatInVec(shape.getSphere().m_radius));
				break;

				case kPfxShapeBox:
				render_box(
					worldT,
					color,
					shape.getBox().m_half);
				break;

				case kPfxShapeCapsule:
				render_capsule(
					worldT,
					color,
					PfxFloatInVec(shape.getCapsule().m_radius),
					PfxFloatInVec(shape.getCapsule().m_halfLen));
				break;

				case kPfxShapeCylinder:
				render_cylinder(
					worldT,
					color,
					PfxFloatInVec(shape.getCylinder().m_radius),
					PfxFloatInVec(shape.getCylinder().m_halfLen));
				break;

				case kPfxShapeConvexMesh:
				render_mesh(
					worldT,
					color,
					convexMeshId);
				break;

				case kPfxShapeLargeTriMesh:
				render_mesh(
					worldT,
					color,
					landscapeMeshId);
				break;

				default:
				break;
			}
		}
	}

	render_debug_begin();
	
	#ifdef ENABLE_DEBUG_DRAW_CONTACT
	for(int i=0;i<physics_get_num_contacts();i++) {
		const PfxContactManifold &contact = physics_get_contact(i);
		const PfxRigidState &stateA = physics_get_state(contact.getRigidBodyIdA());
		const PfxRigidState &stateB = physics_get_state(contact.getRigidBodyIdB());

		for(int j=0;j<contact.getNumContacts();j++) {
			const PfxContactPoint &cp = contact.getContactPoint(j);
			PfxVector3 pA = stateA.getPosition()+rotate(stateA.getOrientation(),pfxReadVector3(cp.m_localPointA));

			const float w = 0.05f;

			render_debug_line(pA+PfxVector3(-w,0.0f,0.0f),pA+PfxVector3(w,0.0f,0.0f),PfxVector3(0,0,1));
			render_debug_line(pA+PfxVector3(0.0f,-w,0.0f),pA+PfxVector3(0.0f,w,0.0f),PfxVector3(0,0,1));
			render_debug_line(pA+PfxVector3(0.0f,0.0f,-w),pA+PfxVector3(0.0f,0.0f,w),PfxVector3(0,0,1));
		}
	}
	#endif
	
	#ifdef ENABLE_DEBUG_DRAW_AABB
	for(int i=0;i<physics_get_num_rigidbodies();i++) {
		const PfxRigidState &state = physics_get_state(i);
		const PfxCollidable &coll = physics_get_collidable(i);

		PfxVector3 center = state.getPosition() + coll.getCenter();
		PfxVector3 half = absPerElem(PfxMatrix3(state.getOrientation())) * coll.getHalf();
		
		render_debug_box(center,half,PfxVector3(1,0,0));
	}
	#endif

	#ifdef ENABLE_DEBUG_DRAW_ISLAND
	const PfxIsland *island = physics_get_islands();
	if(island) {
		for(PfxUInt32 i=0;i<pfxGetNumIslands(island);i++) {
			PfxIslandUnit *islandUnit = pfxGetFirstUnitInIsland(island,i);
			PfxVector3 aabbMin(SCE_PFX_FLT_MAX);
			PfxVector3 aabbMax(-SCE_PFX_FLT_MAX);
			for(;islandUnit!=NULL;islandUnit=pfxGetNextUnitInIsland(islandUnit)) {
				const PfxRigidState &state = physics_get_state(pfxGetUnitId(islandUnit));
				const PfxCollidable &coll = physics_get_collidable(pfxGetUnitId(islandUnit));
				PfxVector3 center = state.getPosition() + coll.getCenter();
				PfxVector3 half = absPerElem(PfxMatrix3(state.getOrientation())) * coll.getHalf();
				aabbMin = minPerElem(aabbMin,center-half);
				aabbMax = maxPerElem(aabbMax,center+half);
			}
			render_debug_box((aabbMax+aabbMin)*0.5f,(aabbMax-aabbMin)*0.5f,PfxVector3(0,1,0));
		}
	}
	#endif
	
	for(int i=0;i<physics_get_num_rays();i++) {
		const PfxRayInput& rayInput = physics_get_rayinput(i);
		const PfxRayOutput& rayOutput = physics_get_rayoutput(i);
		if(rayOutput.m_contactFlag) {
			render_debug_line(
				rayInput.m_startPosition,
				rayOutput.m_contactPoint,
				PfxVector3(1.0f,0.0f,1.0f));
			render_debug_line(
				rayOutput.m_contactPoint,
				rayOutput.m_contactPoint+rayOutput.m_contactNormal,
				PfxVector3(1.0f,0.0f,1.0f));
		}
		else {
			render_debug_line(rayInput.m_startPosition,
				rayInput.m_startPosition+rayInput.m_direction,
				PfxVector3(0.5f,0.0f,0.5f));
		}
	}

	extern bool doAreaRaycast;
	extern PfxVector3 areaCenter;
	extern PfxVector3 areaExtent;

	if(doAreaRaycast) {
		render_debug_box(areaCenter,areaExtent,PfxVector3(0,0,1));
	}

	render_debug_end();

	render_end();
}
Пример #7
0
void render(void)
{
	render_begin();
	
	for(int i=0;i<physics_get_num_rigidbodies();i++) {
		const PfxRigidState &state = physics_get_state(i);
		const PfxCollidable &coll = physics_get_collidable(i);

		PfxTransform3 rbT(state.getOrientation(), state.getPosition());

		PfxShapeIterator itrShape(coll);
		for(int j=0;j<coll.getNumShapes();j++,++itrShape) {
			const PfxShape &shape = *itrShape;
			PfxTransform3 offsetT = shape.getOffsetTransform();
			PfxTransform3 worldT = rbT * offsetT;

			switch(shape.getType()) {
				case kPfxShapeSphere:
				render_sphere(
					worldT,
					PfxVector3(1,1,1),
					PfxFloatInVec(shape.getSphere().m_radius));
				break;

				case kPfxShapeBox:
				render_box(
					worldT,
					PfxVector3(1,1,1),
					shape.getBox().m_half);
				break;

				case kPfxShapeCapsule:
				render_capsule(
					worldT,
					PfxVector3(1,1,1),
					PfxFloatInVec(shape.getCapsule().m_radius),
					PfxFloatInVec(shape.getCapsule().m_halfLen));
				break;

				case kPfxShapeCylinder:
				render_cylinder(
					worldT,
					PfxVector3(1,1,1),
					PfxFloatInVec(shape.getCylinder().m_radius),
					PfxFloatInVec(shape.getCylinder().m_halfLen));
				break;

				case kPfxShapeConvexMesh:
				render_mesh(
					worldT,
					PfxVector3(1,1,1),
					convexMeshId);
				break;

				case kPfxShapeLargeTriMesh:
				render_mesh(
					worldT,
					PfxVector3(1,1,1),
					landscapeMeshId);
				break;

				default:
				break;
			}
		}
	}

	render_end();
}
Пример #8
0
static int tool_cube_iter(goxel_t *goxel, const inputs_t *inputs, int state,
                          const vec2_t *view_size, bool inside)
{
    const bool down = inputs->mouse_down[0];
    const bool up = !down;
    int snaped = 0;
    vec3_t pos, normal;
    box_t box;
    uvec4b_t box_color = HEXCOLOR(0xffff00ff);
    mesh_t *mesh = goxel->image->active_layer->mesh;

    if (inside)
        snaped = goxel_unproject(goxel, view_size, &inputs->mouse_pos,
                                 &pos, &normal);
    if (snaped) {
        if (    snaped == SNAP_MESH && goxel->painter.op == OP_ADD &&
                !goxel->snap_offset)
            vec3_iadd(&pos, normal);
        pos.x = round(pos.x - 0.5) + 0.5;
        pos.y = round(pos.y - 0.5) + 0.5;
        pos.z = round(pos.z - 0.5) + 0.5;
    }
    if (state == STATE_IDLE) {
        goxel->tool_t = 0;
        if (snaped) state = STATE_SNAPED;
    }
    if (state == STATE_SNAPED) {
        if (goxel->tool_t == 0) {
            goxel->tool_t = 1;
            mesh_set(&goxel->tool_origin_mesh, mesh);
        }
        if (!snaped) return STATE_CANCEL;
        goxel_set_help_text(goxel, "Click and drag to draw.");
        goxel->tool_start_pos = pos;
        box = get_box(&goxel->tool_start_pos, &pos, &normal, 0,
                      &goxel->plane);
        mesh_set(&mesh, goxel->tool_origin_mesh);
        mesh_op(mesh, &goxel->painter, &box);
        render_box(&goxel->rend, &box, false, &box_color, false);
        if (down) {
            state = STATE_PAINT;
            goxel->painting = true;
        }
    }
    if (state == STATE_PAINT) {
        goxel_set_help_text(goxel, "Drag.");
        box = get_box(&goxel->tool_start_pos, &pos, &normal, 0, &goxel->plane);
        render_box(&goxel->rend, &box, false, &box_color, false);
        mesh_set(&mesh, goxel->tool_origin_mesh);
        mesh_op(mesh, &goxel->painter, &box);
        goxel_update_meshes(goxel, false);
        if (up) {
            state = STATE_PAINT2;
            goxel->tool_plane = plane_from_normal(pos, goxel->plane.u);
        }
    }
    if (state == STATE_PAINT2) {
        goxel_set_help_text(goxel, "Adjust height.");
        render_plane(&goxel->rend, &goxel->tool_plane, &goxel->grid_color);
        pos = vec3_add(goxel->tool_plane.p,
                    vec3_project(vec3_sub(pos, goxel->tool_plane.p),
                                 goxel->plane.n));
        box = get_box(&goxel->tool_start_pos, &pos, &normal, 0,
                      &goxel->plane);
        render_box(&goxel->rend, &box, false, &box_color, false);
        mesh_set(&mesh, goxel->tool_origin_mesh);
        mesh_op(mesh, &goxel->painter, &box);
        goxel_update_meshes(goxel, false);
        if (down) {
            mesh_set(&mesh, goxel->tool_origin_mesh);
            mesh_op(mesh, &goxel->painter, &box);
            goxel_update_meshes(goxel, true);
            goxel->painting = false;
            image_history_push(goxel->image);
            return STATE_WAIT_UP;
        }
    }
    if (state == STATE_WAIT_UP) {
        goxel->tool_plane = plane_null;
        if (up) state = STATE_IDLE;
    }
    return state;
}
Пример #9
0
// XXX: this is very close to tool_cube_iter.
static int tool_selection_iter(goxel_t *goxel, const inputs_t *inputs,
                               int state, const vec2_t *view_size,
                               bool inside)
{
    extern const mat4_t FACES_MATS[6];
    const bool down = inputs->mouse_down[0];
    const bool up = !down;
    int snaped = 0;
    int face = -1;
    vec3_t pos, normal;
    plane_t face_plane;
    box_t box;
    uvec4b_t box_color = HEXCOLOR(0xffff00ff);

    // See if we can snap on a selection face.
    if (inside && !box_is_null(goxel->selection) &&
            IS_IN(state, STATE_IDLE, STATE_SNAPED, STATE_SNAPED_FACE)) {
        goxel->tool_snape_face = -1;
        if (goxel_unproject_on_box(goxel, view_size, &inputs->mouse_pos,
                               &goxel->selection, &pos, &normal, &face)) {
            goxel->tool_snape_face = face;
            state = STATE_SNAPED_FACE;
        }
    }
    if (!box_is_null(goxel->selection) && goxel->tool_snape_face != -1)
        face_plane.mat = mat4_mul(goxel->selection.mat,
                                  FACES_MATS[goxel->tool_snape_face]);

    if (inside && face == -1)
        snaped = goxel_unproject(goxel, view_size, &inputs->mouse_pos,
                                 &pos, &normal);
    if (snaped) {
        pos.x = round(pos.x - 0.5) + 0.5;
        pos.y = round(pos.y - 0.5) + 0.5;
        pos.z = round(pos.z - 0.5) + 0.5;
    }

    if (state == STATE_IDLE) {
        goxel->tool_t = 0;
        goxel->tool_snape_face = -1;
        if (snaped) state = STATE_SNAPED;
    }
    if (state == STATE_SNAPED) {
        if (!snaped) return STATE_CANCEL;
        goxel_set_help_text(goxel, "Click and drag to set selection.");
        goxel->tool_start_pos = pos;
        box = get_box(&goxel->tool_start_pos, &pos, &normal, 0,
                      &goxel->plane);
        render_box(&goxel->rend, &box, false, &box_color, false);
        if (down) {
            state = STATE_PAINT;
            goxel->painting = true;
        }
    }
    if (state == STATE_PAINT) {
        goxel_set_help_text(goxel, "Drag.");
        goxel->selection = get_box(&goxel->tool_start_pos, &pos, &normal, 0,
                                   &goxel->plane);
        if (up) {
            state = STATE_PAINT2;
            goxel->tool_plane = plane_from_normal(pos, goxel->plane.u);
        }
    }
    if (state == STATE_PAINT2) {
        goxel_set_help_text(goxel, "Adjust height.");
        render_plane(&goxel->rend, &goxel->tool_plane, &goxel->grid_color);
        pos = vec3_add(goxel->tool_plane.p,
                    vec3_project(vec3_sub(pos, goxel->tool_plane.p),
                                 goxel->plane.n));
        goxel->selection = get_box(&goxel->tool_start_pos, &pos, &normal, 0,
                                   &goxel->plane);
        if (down) {
            goxel->painting = false;
            return STATE_WAIT_UP;
        }
    }
    if (state == STATE_WAIT_UP) {
        goxel->tool_plane = plane_null;
        goxel->selection = box_get_bbox(goxel->selection);
        return up ? STATE_IDLE : STATE_WAIT_UP;
    }
    if (IS_IN(state, STATE_SNAPED_FACE, STATE_MOVE_FACE))
        goxel_set_help_text(goxel, "Drag to move face");
    if (state == STATE_SNAPED_FACE) {
        if (face == -1) return STATE_IDLE;
        render_img(&goxel->rend, NULL, &face_plane.mat);
        if (down) {
            state = STATE_MOVE_FACE;
            goxel->tool_plane = plane(pos, normal,
                                      vec3_normalized(face_plane.u));
        }
    }
    if (state == STATE_MOVE_FACE) {
        if (up) return STATE_IDLE;
        goxel_unproject_on_plane(goxel, view_size, &inputs->mouse_pos,
                                 &goxel->tool_plane, &pos, &normal);
        pos = vec3_add(goxel->tool_plane.p,
                    vec3_project(vec3_sub(pos, goxel->tool_plane.p),
                                 vec3_normalized(face_plane.n)));
        pos.x = round(pos.x);
        pos.y = round(pos.y);
        pos.z = round(pos.z);
        goxel->selection = box_move_face(goxel->selection,
                                         goxel->tool_snape_face, pos);
    }
    return state;
}
Пример #10
0
Файл: main.c Проект: scoopr/ngi
void draw_tachometer() {
    

    const unsigned char col1[] = { 180,180,255,255};
    const unsigned char colbg[] = { 16,16,20,255};


    float innerRadius = tachoBox.width * .3f;
    float outerRadius = tachoBox.width * .35f;
    float centerx = tachoBox.left + tachoBox.width/2;
    float centery = tachoBox.bottom + tachoBox.height/2;

//    double spf = 1.0/60.0;
//    double spf = 1.0/51.56 ;
//    double spf = 1.0/10.0;
//    double spf = 1.0/60.0;
    double spf = get_spf();


    
    double offset = frametimes[last_frametime] ; //fmod(,spf);
//    double offset = frametimes[last_frametime]  - fmod(frametimes[last_frametime],spf);

    const int tachoframes = 6;
    double max_age = frametimes[last_frametime] - spf * (tachoframes-1);

	int i;

	render_box(rend, &tachoBox, colbg);

	for(i = 0; i < tachoframes; ++i)
    {
        float angle = -i * 3.14159f * 2.0f / tachoframes ;
        float ax = cosf(angle);
        float ay = sinf(angle);
        render_line(rend, centerx + ax * innerRadius, centery + ay * innerRadius,
                          centerx + ax * outerRadius, centery + ay * outerRadius, 2, col1);
    }


    for(i = 0; i < max_frametimes; ++i)
    {
        int j = (i + cur_frametime) % max_frametimes;
        double t = frametimes[ j ] - offset;

        int lum = i*255/max_frametimes;
        unsigned char col[]= { lum, lum>>1, lum>>1, 255};
        float r = -(1.0f-(i/(float)max_frametimes)) * 15 + 5;
//        if( j <= last_frametime && j > (last_frametime-tachoframes+max_frametimes)%max_frametimes) {
        float angle = (float)(-fmod(t, spf * tachoframes ) / (spf*tachoframes) * 3.14159 * 2.0);
        float ax = cosf(angle);
        float ay = sinf(angle);

        if( frametimes[j] > max_age ) {
            r=15.0f;
        } else {
            lum = lum >>1;
        }
        if(j == last_frametime) memcpy(col, white ,4);;


        render_line(rend, centerx + ax * (outerRadius+r), centery + ay * (outerRadius+r),
                          centerx + ax * (outerRadius+5+r), centery + ay * (outerRadius+5+r), 3, col);
        
    }




    
}
Пример #11
0
WPaper *make_image(Fl_Color bg_color,
                     Fl_Image *im,
                     int w, int h,
                     int mode,
                     uchar opacity=255)
{
    // secret box render function from Fl_Image :)
    extern uint8 *render_box(int w, int h, int bitspp, uint color, Fl_Colormap *pal, uint8 *buffer);

    Fl_PixelFormat *fmt = Fl_Renderer::system_format();
    WPaper *bg_image = new WPaper(w, h, Fl_Renderer::system_format());

    int iw=im->width(), ih=im->height();
    int ix=0, iy=0;
    int xoff=0, yoff=0;
    Fl_Image *newim = im;

    switch(mode) {
    //CENTER
    case 0: {
        ix=(w/2)-(iw/2);
        iy=(h/2)-(ih/2);
        if(ix<0) xoff=-ix; if(iy<0) yoff=-iy;
        if(ix<0) ix=0; if(iy<0) iy=0;
    }
    break;

    //STRECH
    case 1: {
        ix=0, iy=0, iw=w, ih=h;
        if(w!=im->width()||h!=im->height()) {
            newim = im->scale(w,h);
        }
    }
    break;

    //STRETCH ASPECT
    case 2: {
        int pbw = w, pbh = h;
        iw = pbw;
        ih = iw * im->height() / im->width();
        if(ih > pbh) {
            ih = pbh;
            iw = ih * im->width() / im->height();
        }
        ix=(w/2)-(iw/2), iy=(h/2)-(ih/2);
        if(ix<0) ix=0; if(iy<0) iy=0;
        if(iw>w) iw=w; if(ih>h) ih=h;
        if(iw!=im->width()||ih!=im->height()) {
            newim = im->scale(iw,ih);
        }
    }
    break;
    }

    // This could be an option, opacity
    newim->format()->alpha = opacity;

    if( (iw<w || ih<h) || newim->format()->alpha!=255) {
        // If image doesnt fill the whole screen, or opacity < 255
        // fill image first with bg color.
        render_box(w, h, fmt->bitspp, bg_color, fmt->palette, bg_image->data());
    }

    if(iw>w) iw=w; if(ih>h) ih=h;
    Fl_Rect r(xoff, yoff, iw, ih);
    Fl_Rect r2(ix,iy, iw, ih);

    if(newim->format()->alpha>0) {
        // Blit image data to our bg_image
        bg_image->check_map(newim->format());
        Fl_Renderer::alpha_blit(newim->data(), &r, newim->format(), newim->pitch(),
                                bg_image->data(), &r2, bg_image->format(), bg_image->pitch(),
                                0);
    }

    if(newim!=im)
        delete newim;

    return bg_image;
}