Exemplo n.º 1
0
void BitmapUtilsT<PFsrc,PFdst>::Blit2x(uint8_t* dst_pixels, const uint8_t* src_pixels, int n) {
	for (int i = 0; i < n; i++) {
		copy_pixel(dst_pixels, src_pixels);
		dst_pixels += pf_dst.bytes;
		copy_pixel(dst_pixels, src_pixels);
		dst_pixels += pf_dst.bytes;
		src_pixels += pf_src.bytes;
	}
}
Exemplo n.º 2
0
void BitmapUtilsT<PFsrc,PFdst>::FlipH(uint8_t*& pixels_left, uint8_t*& pixels_right, int n) {
	for (int i = 0; i < n; i++) {
		if (pixels_left == pixels_right)
			continue;

		uint8_t tmp_buffer[4];
		copy_pixel(tmp_buffer, pixels_left);
		copy_pixel(pixels_left, pixels_right);
		copy_pixel(pixels_right, tmp_buffer);

		pixels_left += pf_dst.bytes;
		pixels_right -= pf_dst.bytes;
	}
}
Exemplo n.º 3
0
void BitmapUtilsT<PFsrc,PFdst>::FlipHV(uint8_t*& pixels_first, uint8_t*& pixels_last, int n) {
	for (int i = 0; i < n; i++) {
		if (pixels_first == pixels_last)
			break;

		uint8_t tmp_buffer[4];
		copy_pixel(tmp_buffer, pixels_first);
		copy_pixel(pixels_first, pixels_last);
		copy_pixel(pixels_last, tmp_buffer);

		pixels_first += pf_dst.bytes;
		pixels_last -= pf_dst.bytes;
	}
}
Exemplo n.º 4
0
	static inline void copy_pixels(BMU* bmu, uint8_t* dst_pixels, const uint8_t* src_pixels, int n) {
		for (int i = 0; i < n; i++) {
			copy_pixel(bmu, dst_pixels, src_pixels);
			src_pixels += bmu->pf_src.bytes;
			dst_pixels += bmu->pf_dst.bytes;
		}
	}
Exemplo n.º 5
0
void BitmapUtilsT<PFsrc,PFdst>::FlipHBlit(uint8* dst_pixels, const uint8* src_pixels, int n) {
	for (int i = 0; i < n; i++) {
		copy_pixel(dst_pixels, src_pixels);
		src_pixels -= pf_src.bytes;
		dst_pixels += pf_dst.bytes;
	}
}
Exemplo n.º 6
0
void BitmapUtilsT<PFsrc,PFdst>::CopyScaleBlit(uint8_t* dst_pixels, const uint8_t* src_pixels, int n, int x, int step) {
	for (int i = 0; i < n; i++) {
		const uint8_t* p = src_pixels + (x >> FRAC_BITS) * pf_src.bytes;
		copy_pixel(dst_pixels, p);
		dst_pixels += pf_dst.bytes;
		x += step;
	}
}
Exemplo n.º 7
0
void BitmapUtilsT<PFsrc,PFdst>::CopyTransformBlit(uint8_t* dst_pixels, const uint8_t* src_pixels, int src_pitch,
												  int x0, int x1, int y, const Rect& src_rect, const Matrix& inv) {
	const int sx0 = src_rect.x;
	const int sy0 = src_rect.y;
	const int sx1 = src_rect.x + src_rect.width;
	const int sy1 = src_rect.y + src_rect.height;

	for (int x = x0; x < x1; x++) {
		double fx, fy;
		inv.Transform(x + 0.5, y + 0.5, fx, fy);
		int xi = (int) floor(fx);
		int yi = (int) floor(fy);
		if (xi < sx0 || xi >= sx1 || yi < sy0 || yi >= sy1)
			;
		else
			copy_pixel(dst_pixels, &src_pixels[yi * src_pitch + xi * pf_src.bytes]);
		dst_pixels += pf_dst.bytes;
	}
}
Exemplo n.º 8
0
SDL_Surface* rotozoom(SDL_Surface *old, SDL_Rect *clip, Uint16 newW, Uint16 newH, char rotation) {
	#ifndef USE_GFX
	/* Doesn't work
	#ifdef PSP
	if(*access_int_global(access_resize) == resize_hardware) {
		SDL_Rect temp;
		if(clip == NULL) {
			temp.x = 0;
			temp.y = 0;
			temp.w = old->w;
			temp.h = old->h;   
			clip = &temp;
		}
		float x_ratio;
		float y_ratio;
		if(newW == 0) {
			if(newH == 0) {
				if((rotation % 4) == 0) return old;
				x_ratio = 1.0f;
				y_ratio = 1.0f;
			} else {
				x_ratio = y_ratio = ((float)newH)/old->h;
				newW = old->w * x_ratio;
			}
		} else if(newH == 0) {
			x_ratio = y_ratio = ((float)newW)/old->w;
			newH = old->h * y_ratio;
		} else if((newW == old->w) && (newH == old->h) && ((rotation % 4) == 0))
			return old;
		else {
			x_ratio = ((float)newW)/old->w;
			y_ratio = ((float)newH)/old->h;
		}
		device scr_acc = access_device(access_screen);
		SDL_Surface *ret = SDL_CreateRGBSurface(
			SDL_SWSURFACE, newW, newH,
			24, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
		if(!ret) return NULL;
		SDL_Surface *hw_buf = SDL_CreateRGBSurface(
			SDL_HWSURFACE, 256, 256,
			32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
		SDL_Surface *hw_draw_buf = SDL_CreateRGBSurface(
			SDL_HWSURFACE, 256, 256,
			32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
		if(!hw_buf || !hw_draw_buf) {
			if(hw_buf) SDL_FreeSurface(hw_buf);
			else SDL_FreeSurface(hw_draw_buf);
			SDL_FreeSurface(ret);
			return NULL;
		}
		void *display_list = memalign(16,262144);
		if(!display_list) {
			//TODO
		}
		void *draw_buf = (void*)((int)scr_acc.screen->pixels-0x4000000);
		sceKernelDcacheWritebackInvalidateAll();
		sceGuStart(GU_DIRECT,display_list);
		sceGuEnable(GU_TEXTURE_2D);
		//sceGuDrawBuffer(GU_PSM_8888,(void*)((int)hw_buf->pixels-0x4000000),256);
		sceGumMatrixMode(GU_PROJECTION);
		sceGumLoadIdentity();
		sceGumOrtho(0.0f,256.0f,256.0f,0.0f,-1.0f,1.0f);
		sceGumMatrixMode(GU_VIEW);
		sceGumLoadIdentity();
		sceGumMatrixMode(GU_MODEL);
		sceGumLoadIdentity();
		sceGuTexMode(GU_PSM_8888, 0, 0, GU_FALSE);	
		sceGuTexFunc(GU_TFX_DECAL, GU_TCC_RGB);
		sceGuTexFilter(GU_LINEAR, GU_LINEAR);
		sceGuTexWrap(GU_CLAMP,GU_CLAMP);
		sceGuTexScale(x_ratio, y_ratio);
		sceGuTexOffset(0.0f, 0.0f);
		sceGuTexImage(0,256,256,512,hw_buf->pixels);
		sceGuFinish();
		sceGuSync(0,0);
		int i;
		for(i = 0; i < clip->h; i+=256) {
			int j;
			for(j = 0; j < clip->w; j+=256) {
				SDL_Rect region = { .x = clip->x + j, .y = clip->y + i, .w = 256, .h = 256 };
				SDL_BlitSurface(old,NULL,hw_buf,NULL);
				SDL_LockSurface(hw_buf);
				SDL_LockSurface(scr_acc.screen);
				sceKernelDcacheWritebackInvalidateAll();
				sceGuStart(GU_DIRECT,display_list);
				sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT);
				sceGumDrawArray(GU_SPRITES, GU_TEXTURE_32BITF|GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_2D,2,NULL,rot0);
				sceGuFinish();
				sceGuSync(0,0);
				region.x = j*x_ratio;
				region.y = i*y_ratio;
				region.w *= x_ratio;
				region.h *= y_ratio;
				SDL_UnlockSurface(hw_buf);
				SDL_UnlockSurface(scr_acc.screen);
				SDL_BlitSurface(scr_acc.screen,NULL,ret,NULL);
				flip_screen();
			}
		}
		//sceGuDrawBuffer(GU_PSM_8888,draw_buf,512);
		SDL_FreeSurface(hw_buf);
		SDL_FreeSurface(hw_draw_buf);
		free(display_list);
		return ret;
	}
	#endif
	*/
	SDL_Rect src_rect;
	if(clip == NULL) {
		src_rect.x = 0;
		src_rect.y = 0;
		src_rect.w = old->w;
		src_rect.h = old->h;
	} else src_rect = *clip;
	if((newW == 0) && (newH != 0)) newW = (Uint16)(((float)newH/src_rect.h)*old->w);
	else if((newH == 0) && (newW != 0)) newH = (Uint16)(((float)newW/src_rect.w)*old->h);
	else if((newW == 0) && (newH == 0)) {
		newW = old->w;
		newH = old->h;
	}
	if((clip == NULL) && (newW == old->w) && (newH == old->h) && ((rotation % 4) == 0)) return old;
	int current_resize_method = *access_int_global(access_resize);
	scale_up_cpu();
	if((newW/old->w >= 2) && (newH/old->h >= 2)) current_resize_method = resize_nn;
	SDL_Surface *new_surf = SDL_CreateRGBSurface(
		SDL_SWSURFACE,
		(rotation % 2)?newH:newW, (rotation % 2)?newW:newH,
		((current_resize_method == resize_nn) || (old->format->BytesPerPixel >= 3)) ? old->format->BitsPerPixel :
		((old->format->BytesPerPixel == 1) && (old->flags & SDL_SRCCOLORKEY) && (current_resize_method == resample))? 32 : 24,
		(old->format->BytesPerPixel == 1)?0x00FF0000:old->format->Rmask,
		(old->format->BytesPerPixel == 1)?0x0000FF00:old->format->Gmask,
		(old->format->BytesPerPixel == 1)?0x000000FF:old->format->Bmask,
		(((old->format->BytesPerPixel == 1) && (old->flags & SDL_SRCCOLORKEY) && (current_resize_method == resample)) ||
		(old->format->BytesPerPixel == 4))?0xFF000000:0 //Not sure why it has to be done this way, but it does...
	);
	if(!new_surf) {
		scale_down_cpu();
		sdl_error();
		return NULL;
	}
	if((new_surf->format->BytesPerPixel == 1) &&
		  !(copy_palette(old, new_surf) == 1)) {
		SDL_FreeSurface(new_surf);
		scale_down_cpu();
		sdl_error();
		return NULL;
	}
	/* if(new_surf->format->BytesPerPixel == 4)
		SDL_SetAlpha(new_surf,SDL_SRCALPHA,SDL_ALPHA_TRANSPARENT); */
	SDL_LockSurface(old);
	SDL_LockSurface(new_surf);
	Uint32 i, j;
	Uint8 *new_pixel, *row_start;
	Uint32 new_pitch = new_surf->pitch;
	Uint8 bpp = new_surf->format->BytesPerPixel;
	Uint32 new_to_next_row = new_pitch-bpp*(newW - 1);
	Uint32 new_to_prev_column = new_pitch*newH - bpp;
	int oldW = old->w;
	int oldH = old->h;
	Uint32 old_pitch = new_surf->pitch;
	Uint32 old_to_next_row = old_pitch-old->format->BytesPerPixel*(old->w - 1);
	Uint32 old_to_next_column = -old_pitch*oldH + old->format->BytesPerPixel;
	Uint32 old_bpp = old->format->BytesPerPixel;
	if(rotation % 2) {
		newW = new_surf->w;
		newH = new_surf->h;
	}
	char amount = rotation % 4;
	if((newW == oldW) && (newH == oldH)) {
		//Old dims == new dims. Just rotate.
		Uint8 *old_pixel = old->pixels;
		switch(amount) {
			case 1:
			new_pixel = access_pixel(new_surf,i,newH);
			for(j = newH; j--;) {
				for(i = newW; i--;) {
					copy_pixel(old_pixel,new_pixel,bpp);
					old_pixel = (Uint8*)old_pixel - old_pitch;
					new_pixel = (Uint8*)new_pixel - bpp;
				}
				old_pixel = (Uint8*)old_pixel + old_bpp;
				new_pixel = (Uint8*)new_pixel - new_to_next_row;
			} break;

			case 2:
			new_pixel = access_pixel(new_surf,newW-1,newH-1);
			for(i = newW; i--;) {
				for(j = newH; j--;) {
					copy_pixel(old_pixel,new_pixel,bpp);
					old_pixel = (Uint8*)old_pixel + old_pitch;
					new_pixel = (Uint8*)new_pixel - new_pitch;
				}
				new_pixel = (Uint8*)new_pixel + new_to_prev_column;
				old_pixel = (Uint8*)old_pixel + old_to_next_column;
			} break;

			case 3:
			new_pixel = new_surf->pixels;
			for(i = newW; i--;) {
				for(j = newH; j--;) {
					copy_pixel(old_pixel,new_pixel,bpp);
					old_pixel = (Uint8*)old_pixel + bpp;
					new_pixel = (Uint8*)new_pixel - new_pitch;
				}
				old_pixel = (Uint8*)old_pixel + old_to_next_row;
				new_pixel = (Uint8*)new_pixel + new_to_next_row;
			} break;
		}
	} else {
		switch(current_resize_method) {
			case resize_nn: {
				Uint32 locationX, locationY;
				Uint8 *old_pixel;
				new_pixel = new_surf->pixels;
				for(i = newH; i--;) {
					row_start = new_pixel;
					for(j = 0; j < newW; ++j,new_pixel+=bpp) {
						switch(amount) {
							case 0:
							locationX = (j<<16)/newW*(src_rect.w-1) + (src_rect.x<<16);
							locationY = (src_rect.h<<16) - ((i<<16)/newH*(src_rect.h-1) + (src_rect.y<<16)) - 1;
							break;
							case 1:
							locationX = (src_rect.w<<16) - ((i<<16)/newH*(src_rect.w-1) + (src_rect.x<<16)) - 1;
							locationY = (src_rect.h<<16) - ((j<<16)/newW*(src_rect.h-1) + (src_rect.y<<16)) - 1;
							break;
							case 2:
							locationX = (src_rect.w<<16) - ((j<<16)/newW*(src_rect.w-1) + (src_rect.x<<16)) - 1;
							locationY = ((i<<16)/newH*(src_rect.h-1) + (src_rect.y<<16));
							break;
							case 3:
							locationX = (i<<16)/newH*(src_rect.w-1) + (src_rect.x<<16);
							locationY = (j<<16)/newW*(src_rect.h-1) + (src_rect.y<<16);
							break;
						}
						old_pixel = access_pixel(old,(Uint16)(locationX>>16),(Uint16)(locationY>>16));
						copy_pixel(old_pixel,new_pixel,bpp);
					}
					new_pixel = row_start + new_pitch;
				}
			} break;
			case resample: {
				Uint32 locationX, locationY;
				Uint16 cornerX0, cornerX1, cornerY0, cornerY1;
				Uint8 *old_pixel0, *old_pixel1;
				SDL_Surface *buffer = NULL;
				if(old->format->BytesPerPixel < 3) {
					buffer = old;
					old = SDL_CreateRGBSurface(
						SDL_SWSURFACE,
						buffer->w, buffer->h, 32,
						0x00FF0000, 0x0000FF00,
						0x000000FF, 0xFF000000
					);
					SDL_SetAlpha(old,SDL_SRCALPHA,SDL_ALPHA_TRANSPARENT);
					SDL_UnlockSurface(buffer);
					SDL_BlitSurface(buffer,NULL,old,NULL);
					SDL_UpdateRect(old,0,0,0,0);
					SDL_LockSurface(old);
				}
				Uint8 k = new_surf->format->BytesPerPixel;
				Uint16 val;
				new_pixel = access_pixel(new_surf,newW-1,newH-1);
				for(i = newH; i--;) {
					row_start = new_pixel;
					for(j = newW; j--; new_pixel -= k*2-1) {
						switch(amount) {
							case 0:
							locationX = (j<<16)/newW*(src_rect.w-1) + (src_rect.x<<16);
							locationY = (i<<16)/newH*(src_rect.h-1) + (src_rect.y<<16);
							break;
							case 1:
							locationX = (i<<16)/newH*(src_rect.w-1) + (src_rect.x<<16);
							locationY = (src_rect.h<<16) - ((j<<16)/newW*(src_rect.h-1) + (src_rect.y<<16)) - 1;
							break;
							case 2:
							locationX = (src_rect.w<<16) - ((j<<16)/newW*(src_rect.w-1) + (src_rect.x<<16)) - 1;
							locationY = (src_rect.h<<16) - ((i<<16)/newH*(src_rect.h-1) + (src_rect.y<<16)) - 1;
							break;
							case 3:
							locationX = (src_rect.w<<16) - ((i<<16)/newH*(src_rect.w-1) + (src_rect.x<<16)) - 1;
							locationY = (j<<16)/newW*(src_rect.h-1) + (src_rect.y<<16);
							break;
						}
						cornerX0 = (Uint16)(locationX>>16);
						cornerY0 = (Uint16)(locationY>>16);
						cornerX1 = cornerX0;
						cornerY1 = cornerY0;

						if(amount > 1) {
							if(locationX-(cornerX0<<16)) --cornerX1;
						}
						else {
							if(cornerX0+1<oldW) ++cornerX1;
						}

						if((amount < 3) && (amount > 0)) {
							if(locationY-(cornerY0<<16)) --cornerY1;
						}
						else {
							if(cornerY0+1<oldH) ++cornerY1;
						}

						old_pixel0 = access_pixel(old,cornerX0,cornerY0);
						old_pixel1 = access_pixel(old,cornerX1,cornerY1);
						//Basically, this averages two pixels' values and puts it
						//into the new image.
						val = ((Uint16)(*(old_pixel0))+
							(Uint16)(*(old_pixel1)))>>1;
						*((Uint8*)new_pixel) = (Uint8)val;
						//Do it up to four times, and also pre-increment the
						//variables so that the pointer is right immediately
						val = ((Uint16)(*(++old_pixel0))+
							(Uint16)(*(++old_pixel1)))>>1;
						*((Uint8*)++new_pixel) = (Uint8)val;
						val = ((Uint16)(*(++old_pixel0))+
							(Uint16)(*(++old_pixel1)))>>1;
						*((Uint8*)++new_pixel) = (Uint8)val;
						if(k == 4) {
							val = ((Uint16)(*(++old_pixel0))+
								(Uint16)(*(++old_pixel1)))>>1;
							*((Uint8*)++new_pixel) = (Uint8)val;
						}
					}
					new_pixel = row_start - new_pitch;
				}
				if(buffer) {
					SDL_FreeSurface(old);
					old = NULL;
				}
			} break;
		}
	}
Exemplo n.º 9
0
static void load_atlas_texture(fs_image *atlas_image,
        int texture_id, const char *name) {
    char *path = fs_emu_theme_get_resource(name);
    if (!path) {
        fs_emu_warning("Could not find resource %s\n", name);
        return;
    }

    fs_image *image = fs_image_new_from_file(path);
    if (!image) {
        fs_emu_warning("error loading texture \"%s\"\n", name);
        return;
    }
    fs_emu_log("loaded sub-texture from \"%s\"\n", path);

    // find needed number of cells
    int cw = (image->width + 7) / 8;
    int ch = (image->height + 7) / 8;
    // adding 1 to get some spacing between cells
    if (cw < 128) {
        cw++;
    }
    if (ch < 128) {
        ch++;
    }

    // try to find space for it in the texture atlas using a simple
    // brute-force search
    int cx = 0;
    int cy = 0;
    int ok = 0;
    for (cy = 0; cy <= 128 - ch; cy++) {
        for (cx = 0; cx <= 128 - cw; cx++) {
            if (check_placement(cx, cy, cw, ch)) {
                ok = 1;
                break;
            }
        }
        if (ok) {
            break;
        }
    }
    if (!ok) {
        fs_emu_warning("could not find space for \"%s\"\n", name);
        //printf("%d %d %d %d\n", cx * 8, cy * 8, cw * 8, ch * 8);
        return;
    }
    // mark cells as used
    for (int y = cy; y < cy + ch; y++) {
        for (int x = cx; x < cx + cw; x++) {
            g_cells[y][x] = 1;
        }
    }
    //printf("%d %d %d %d\n", cx * 8, cy * 8, cw * 8, ch * 8);

    // copy sub-texture into texture, also converting to pre-multiplied
    // alpha, and BGRA if needed. Also copy border pixels to pixels outside
    // border to fix unwanted bilinear filtering effects
    int dx = cx * 8;
    int dy = cy * 8;
    int ds = atlas_image->width * 4; // stride
    unsigned char *dst = atlas_image->data + \
            (dy * atlas_image->width + dx) * 4;
    unsigned char *sp = image->data;

    for (int y = 0; y < image->height; y++) {
#if 1
        if (y == 0 && dy > 0) {
            // repeat first line
            unsigned char *dp = dst - ds;
            for (int x = 0; x < image->width; x++) {
                copy_pixel(&dp, &sp);
            }
            sp -= image->width * 4;
        }
#endif
        unsigned char *dp = dst;
        for (int x = 0; x < image->width; x++) {
            copy_pixel(&dp, &sp);
        }
        dst += 1024 * 4; // stride
#if 1
        if (y == image->height - 1 && dy + y - 1 < atlas_image->height - 1) {
            // repeat last line
            sp -= image->width * 4;
            unsigned char *dp = dst;
            for (int x = 0; x < image->width; x++) {
                copy_pixel(&dp, &sp);
            }
        }
#endif
    }

    // repeat left and right borders
    uint32_t *idata = (uint32_t *) atlas_image->data;
    int iwidth = atlas_image->width;
    int y1 = dy;
    int y2 = dy + image->height - 1;
    if (y1 > 0) {
        y1 -= 1;
    }
    if (y2 < atlas_image->height - 1) {
        y2 += 1;
    }
    if (dx > 0) {
        for (int y = y1; y <= y2; y++) {
            idata[y * iwidth + dx - 1] = idata[y * iwidth + dx];
        }
    }
    if (dx + image->width - 1 < atlas_image->width - 1) {
        for (int y = y1; y <= y2; y++) {
            idata[y * iwidth + dx + image->width - 1 + 1] = \
                    idata[y * iwidth + dx + image->width - 1];
        }
    }

    // register texture coordinates
    g_entries[texture_id].x = cx * 8;
    g_entries[texture_id].y = cy * 8;
    g_entries[texture_id].w = image->width;
    g_entries[texture_id].h = image->height;

    // and finally free the sub-texture image
    fs_unref(image);
}
Exemplo n.º 10
0
void BitmapUtilsT<PFsrc,PFdst>::SetPixels(uint8_t* dst_pixels, const uint8_t* src_pixel, int n) {
	uint8_t tmp_pixel[4];
	copy_pixel(tmp_pixel, src_pixel);
	pf_dst.set_pixels(dst_pixels, tmp_pixel, n);
}
Exemplo n.º 11
0
/* TODO: consider using source.position and source.count (and possibly also phase) */
static int
read_mode10_bitmap_data(byte ** pdata, px_args_t * par, px_state_t * pxs,
			bool mode9031)
{
    px_vendor_state_t *v_state = pxs->vendor_state;
    mode10_state_t *mode10_state = &v_state->mode10_state;
    uint avail = min(par->source.available,
		     (v_state->tag.bytes_expected -
		      v_state->tag.bytes_so_far));
    const byte *pin = par->source.data;
    byte *pout;
    bool end_of_row = false;
    uint32_t pixel;
    int i;

    update_pout(pout);

    if ((v_state->state == vu_body)
	&& v_state->rowwritten == v_state->BlockHeight) {
	int code = pl_end_image(pxs->pgs, v_state->info, true);

	if (code < 0)
	    return code;

	v_state->state = vu_blank;
	v_state->rowwritten = 0;
	return 0;
    }

    /* initialize at begin of image */
    if (v_state->state == vu_tagged) {
	int code = vu_begin_image(pxs);

	if (code < 0)
	    return code;

	mode10_state->state = next_is_cmd;
	mode10_state->cursor = 0;
	v_state->rowwritten = 0;
	v_state->state = vu_body;
    }

    /* one byte at a time until end of input or end of row */
    while ((avail || mode10_state->state == process_rle)	/* process_rle does not consume */
	   &&(!end_of_row)) {
	switch (mode10_state->state) {
	    case next_is_cmd:{
		    mode10_state->cmd = *pin++;
		    --avail;
		    if_debug4('w',
			      "command:%02X row written:%d cursor:%d cached=%08X\n",
			      mode10_state->cmd,
			      v_state->rowwritten,
			      mode10_state->cursor,
			      mode10_state->cached_pixel);
		    mode10_state->offset = (mode10_state->cmd >> 3) & 0x03;
		    mode10_state->count = mode10_state->cmd & 0x07;
		    mode10_state->cursor += mode10_state->offset;	/* may be partial */
		    if ((mode10_state->offset < 3)
			&& (mode10_state->count < 7)
			&& (!srcNEW(mode10_state->cmd))
			) {
			/* completed command */
			if (mode10_state->cmd & eRLE) {
			    mode10_state->state = process_rle;
			} else {
			    /* literal, non-new */
			    update_pout(pout);
			    pixel =
				get_pixel(pout, &mode10_state->cached_pixel,
					  mode10_state->cmd,
					  v_state->color_space);

			    copy_pixel(pout, pixel);
			    mode10_state->cursor += 1;
			    if (mode10_state->count > 0) {
				mode10_state->count--;
				mode10_state->state = next_is_pixel;
			    } else
				mode10_state->state = next_is_cmd;
			}
		    } else if (mode10_state->offset == 3)
			mode10_state->state = partial_offset;
		    else if (srcNEW(mode10_state->cmd)) {
			if ((mode10_state->cmd & eRLE)
			    && (mode10_state->cursor >= v_state->SourceWidth)) {
			    /* special case */
			    if_debug0('w', "special\n");
			    mode10_state->cursor = 0;
			    end_of_row = 1;
			    mode10_state->state = next_is_cmd;
			} else
			    mode10_state->state = next_is_pixel;
		    } else if (mode10_state->count == 7)
			mode10_state->state = partial_count;
		    else
			mode10_state->state = next_is_cmd;	/* does not happen */
		    break;
		}

	    case partial_offset:{
		    uint offset = *pin++;

		    avail--;
		    mode10_state->offset += offset;
		    mode10_state->cursor += offset;
		    if (offset == 0xff)
			mode10_state->state = partial_offset;
		    else {
			/* completed offset */
			if_debug5('w',
				  "%02X row=%d offset=%d cursor=%d/%d\n",
				  mode10_state->cmd,
				  v_state->rowwritten,
				  mode10_state->offset, mode10_state->cursor,
				  v_state->SourceWidth);
			if (srcNEW(mode10_state->cmd)) {
			    if ((mode10_state->cmd & eRLE)
				&& (mode10_state->cursor >=
				    v_state->SourceWidth)) {
				/* special case */
				if_debug0('w', "special\n");
				mode10_state->cursor = 0;
				end_of_row = 1;
				mode10_state->state = next_is_cmd;
			    } else
				mode10_state->state = next_is_pixel;
			} else if (mode10_state->count == 7) {
			    mode10_state->state = partial_count;
			} else {
			    /* not new pixels, counts under 7, so we need to process there */
			    if (mode10_state->cmd & eRLE) {
				mode10_state->state = process_rle;
			    } else {
				/* literal non-new */
				update_pout(pout);
				pixel = get_pixel(pout,
						  &mode10_state->cached_pixel,
						  mode10_state->cmd,
						  v_state->color_space);
				copy_pixel(pout, pixel);
				mode10_state->cursor += 1;
				if (mode10_state->count > 0) {
				    mode10_state->count--;
				    mode10_state->state = next_is_pixel;
				} else
				    mode10_state->state = next_is_cmd;
			    }
			}
		    }
		    break;
		}

	    case partial_count:{
		    uint count = *pin++;

		    avail--;
		    mode10_state->count += count;
		    if (count == 0xff)
			mode10_state->state = partial_count;
		    else {
			/* finished count - partial count only happens on RLE */
			if_debug1('w', "count=%d\n", mode10_state->count);
			mode10_state->state = process_rle;
		    }
		    break;
		}

	    case next_is_pixel:{
		    if (!mode9031 && (avail < 3)) {
			/* get to outer loop to get more data */
			avail = 0;
			break;
		    }
		    if_debug3('w', "pixel:%02X%02X%02X\n", pin[0], pin[1],
			      pin[2]);
		    if (v_state->color_space == eGraySub) {
			/* bug in recent hpijs */
			mode10_state->cached_pixel =
			    (pin[0] << 16 | pin[0] << 8 | pin[0]) ^
			    0x00ffffff;
		    } else if (mode9031) {
			mode10_state->cached_pixel =
			    (pin[0] << 16 | pin[0] << 8 | pin[0]);
		    } else
			mode10_state->cached_pixel =
			    (pin[0] << 16 | pin[1] << 8 | pin[2]);
		    update_pout(pout);
		    update_advance_pixel(pout, pin, mode9031);
		    if (mode9031) {
			pin += 1;
			avail -= 1;
		    } else {
			pin += 3;
			avail -= 3;
		    }
		    mode10_state->cursor++;
		    if ((mode10_state->cmd & eRLE)
			&& (mode10_state->count == 7))
			mode10_state->state = partial_count;
		    else if (mode10_state->cmd & eRLE) {
			mode10_state->state = process_rle;
		    } else if (mode10_state->count > 0) {
			/* literal */
			mode10_state->count--;
			mode10_state->state = next_is_pixel;
		    } else
			mode10_state->state = next_is_cmd;
		    break;
		}

	    case process_rle:{
		    update_pout(pout);
		    pixel =
			get_pixel(pout, &mode10_state->cached_pixel,
				  mode10_state->cmd, v_state->color_space);

		    mode10_state->cursor += mode10_state->count + 2;
		    i = mode10_state->count + 2;

		    if (srcNEW(mode10_state->cmd)) {
			i--;	/* already moved cursor in the case of new pixel */
			mode10_state->cursor--;
		    }
		    while (i > 0) {
			copy_pixel(pout, pixel);
			i--;
		    }
		    mode10_state->state = next_is_cmd;
		    break;
		}

	}			/* end switch */

	/* conditional on state may not be necessary */
	if ((mode10_state->state == next_is_cmd) &&
	    (mode10_state->cursor >= v_state->SourceWidth)) {
	    mode10_state->cursor = 0;
	    end_of_row = 1;
	}
    }				/* end of while */

    par->source.available -= pin - par->source.data;	/* subtract compressed data used */
    par->source.position += pin - par->source.data;
    par->source.data = pin;	/* new compressed data position */

    if (end_of_row) {
	v_state->rowwritten++;
	return 1;
    }
    return pxNeedData;		/* not end of row so request more data */
}