PCS format

GFA, ASM, STOS, ...

Moderators: simonsunnyboy, Mug UK, Zorro 2, Moderator Team

User avatar
unseenmenace
Atari God
Atari God
Posts: 1965
Joined: Tue Sep 21, 2004 9:33 pm
Location: Margate, Kent, UK
Contact:

Re: PCS format

Post by unseenmenace »

Not quite as impressive but there is also a medium res fullscreen with plasma in Best Part Of Creation from Delta Forces Punish Your Machine
You do not have the required permissions to view the files attached to this post.
UNSEEN MENACE
Several STFM's, 4MB STE, 2MB TT with 1.2GB Hard Drive and 14MB Falcon with 540MB Hard Drive,
Lynx 2 and Jaguar with JagCD
Member of GamebaseST and AtariLegend team
Check out my website at http://unseenmenace.110mb.com
User avatar
Nyh
Atari God
Atari God
Posts: 1496
Joined: Tue Oct 12, 2004 2:25 pm
Location: Netherlands

Re: PCS format

Post by Nyh »

Cyprian_K wrote:
SoLo2 wrote:More than 4 colors in a medium resolution screen for Atari ST are found in the presentation logotype of
Asteroids by Sinister Developments,
for example.

I could count more than 8 colors!
and you can find much more colours in this production:

http://www.pouet.net/prod.php?which=12237
Nice one! I wrote a converter for the format.

Hans Wessels
You do not have the required permissions to view the files attached to this post.
earx
Captain Atari
Captain Atari
Posts: 353
Joined: Wed Aug 27, 2003 7:09 am

Re: PCS format

Post by earx »

nice one, ni! feel free to share this source with us :)))

ra's mode is much more suited to regions with edges and lines. and less to more smooth regions. as i could already see at outline2004 where it was released. hint: come to outline this year ;)
User avatar
Nyh
Atari God
Atari God
Posts: 1496
Joined: Tue Oct 12, 2004 2:25 pm
Location: Netherlands

Re: PCS format

Post by Nyh »

earx wrote:nice one, ni! feel free to share this source with us :)))

ra's mode is much more suited to regions with edges and lines. and less to more smooth regions. as i could already see at outline2004 where it was released. hint: come to outline this year ;)
I just dumped a lot of format information in the Atari Wiki. Now there is data on the following formats:
NEOchrome *.NEO
NEOchrome Animation *.ANI
DEGAS *.PI? ? = 1, 2, 3 (4, 5, 6)
DEGAS Elite *.PI? ? = 1, 2, 3
DEGAS Elite (Compressed) *.PC? ? = 1, 2, 3
DEGAS Elite block *.BL? ? = 1, 2, 3
DEGAS Elite icon *.ICN
CrackArt *.CA? ? = 1, 2, 3
ArtDirector *.ART
Tiny *.TN? ? = 1, 2, 3, Y, (4, 5, 6)
Spectrum 512 *.SPU
Spectrum 512 (Compressed) *.SPC
Spectrum 512 (Smooshed) *.SPS
Spectrum 512 Extended *.SPX
Photochrome *.PCS
QuantumPaint *.PBX
Art Director *.ART
C.O.L.R. Object Editor Mural *.MUR
Doodle *.DOO
Cyber Paint Sequence *.SEQ
Animatic Film *.FLM
Animaster Sprite Bank *.ASB
STOS *.MBK
GEM Bit Image *.IMG
STAD *.PAC
Imagic Film/Picture *.IC? ? = 1, 2, 3
IFF *.IFF
RGB Intermediate Format *.RGB
ComputerEyes Raw Data Format *.CE? ? = 1, 2
HighresMedium *.HRM
Overscan Interlaced *.PCI
Picture Packer *.PP1? ? = 1, 2, 3
MacPaint *.MAC
PackBits Compression Algorithm

But because you asked so nice about the HRM:

Code: Select all

int find_hrm_index(int x, int c)
{
  x+=80;
	if(c==0)
	{
	  return -1+4*(int)((x+0)/80);
	}
	else if(c==1)
	{
	  return 0+4*(int)((x-8)/80);
	}
	else if(c==2)
	{
	  return 1+4*(int)((x-40)/80);
	}
  return 2+4*(int)((x-48)/80);
}

HGLOBAL convert_hrm(unsigned char* gfx)
{
  HGLOBAL dst;
  unsigned char *data;
  dst=create_dip(&data, 640, 400, 24, 0, NULL);
  if(dst != NULL)
  {
    long y;
    unsigned char*p=data;
    for(y=0;y<400;y++)
    {
      unsigned char* q=gfx+(399-y)*160;
      unsigned char* cp=gfx+64000L+(399-y)*70;
      int x;
      for(x=0;x<40;x++)
      {
        unsigned int plane0;
        unsigned int plane1;
        int i;
        plane0=*q++;
        plane0<<=8;
        plane0+=*q++;
        plane1=*q++;
        plane1<<=8;
        plane1+=*q++;
        for(i=0;i<16;i++)
        {
          int color;
          color=(unsigned char)((plane1>>14)&2);
          color+=(unsigned char)((plane0>>15)&1);
          plane0<<=1;
          plane1<<=1;
          color=find_hrm_index(x*16+i, color);
          color=(cp[color*2]<<8)+cp[color*2+1];
          *p++=colortable[color&0xf]&0xff;
          *p++=colortable[(color>>4)&0xf]&0xff;
          *p++=colortable[(color>>8)&0xf]&0xff;
        }
      }
    }
    GlobalUnlock(dst);
  }
  return dst;
}

HGLOBAL hrm(char *fileName, char *errorText, char *compressionText)
{ /* medium res interlaced high color */
  FILE* f;
  long int len;
  unsigned char *file;
  HGLOBAL h=NULL;
  file=malloc(93000L);
  if(file==NULL)
  {
    sprintf(errorText, "Out of memory.");
    return h;
  }
  f=fopen(fileName, "rb");
  if(f==NULL)
  {
    sprintf(errorText, "Can not open file!");
  }
  else
  {
    len=packed_fread(file, 93000L, f);
    fclose(f);
    if(len!=92000L)
    {
      sprintf(errorText, "This is not a HRM file!");
    }
    else
    {
      h=convert_hrm(file);
      if(h==NULL)
      {
        sprintf(errorText, "Out of memory.");
      }
      else
      {
        sprintf(compressionText, "HRM picture");
      }
    }
  }
  free(file);
  return h;
}
I will do a full code release next week. I still have some testing to do because I did some heavy editing without testing in the source.

Hans Wessels
bjw66
Atari User
Atari User
Posts: 37
Joined: Fri Jan 18, 2008 2:02 am
Contact:

Re: PCS format

Post by bjw66 »

Nyh wrote:I just dumped a lot of format information in the Atari Wiki. Now there is data on the following formats:

Code: Select all

        ...
        IFF                                     *.IFF
Hans Wessels
Just some slight corrections on the ST version of DPaint which uses the VDAT SUB-chunks... . You didn't state in the Wiki that there may be several VDAT SUB-chunks within the BODY chunk (actually, there probably "always" are). The BODY chunk by itself is perfectly valid. But there are several VDAT SUB-chunks within it. Each with their own "VDAT" identifier and with their own size longs, one for each plane. But, most importantly, DPaint uses a compression type of 2, which indicates the use of VDAT sub-chunks. Until ST DPaint created that sub-format, "0" meant uncompressed, "1" meant compressed (which was always PackBits). ST DPaint added "2", meaning their own "vdat compression". Every file that is vdat-compressed has compression type 2.

Either way, feel free to use whatever information I sent you by email to add to this Wiki.
bjw66
Atari User
Atari User
Posts: 37
Joined: Fri Jan 18, 2008 2:02 am
Contact:

Re: PCS format

Post by bjw66 »

As for the information I sent you through email, regarding ST's IFF compression 2 format, and regarding the animated "4, 5, 6" extensions, you can use that information to add to the wiki without any restrictions. Common courtesy might require a mention of my contributions, but I really don't care. Use whatever information I sent you through private email. No need for acknowledgements. I got much more from your contributions than you got from mine. Thanks again, Hans. :)
xdelatour
Atarian
Atarian
Posts: 4
Joined: Sun Mar 02, 2008 11:14 pm

Re: PCS format

Post by xdelatour »

I found this source code to display PCS pictures. I hope it will help you.

Code: Select all

*-----------------------------------------------------------------------*
*		     		  'PCS' display module					*
*-----------------------------------------------------------------------*
*			      (C) 1992  Douglas Little 				*
*-----------------------------------------------------------------------*

	OPT	O+,W-

Devpac2_Pro		; if this option does not work, take it out!
			; (Devpac2 Pro's dcb.? command is back to front and
			; can cause problems. If the assembler jams up,
			; comment this option out and try again.

*-----------------------------------------------------------------------*
*	STANDARD HARDWARE EQUATES							*
*-----------------------------------------------------------------------*

LineADD		=	160
PHYS_MED		=	$FFFF8201
PHYS_TOP		=	$FFFF8203
COLOUR		=	$FFFF8240
FREQ			=	$FFFF820A

MFP			=	$FFFFFA00
ENABLE_A		=	MFP+$07		; int enable A
ENABLE_B		=	MFP+$09		; int enable B
PENDING_A		=	MFP+$0B		; int pending A
PENDING_B		=	MFP+$0D		; int pending B
IN_SERVICE_A	=	MFP+$0F		; int in-service A
IN_SERVICE_B	=	MFP+$11		; int in-service B
MASK_A		=	MFP+$13		; int mask A
MASK_B		=	MFP+$15		; int mask B
VECTOR		=	MFP+$17		; MFP vector base
CTRL_A		=	MFP+$19		; MFP timer A control
CTRL_B		=	MFP+$1B		; MFP timer B control
DATA_A		=	MFP+$1F		; timer A data
DATA_B		=	MFP+$21		; timer B data

HBI_VEC		=	$68			; Hblank timer
VBI_VEC		=	$70			; VBI
KBD_VEC		=	$118			; IKBD
TIMER_A		=	$134			; General timer
TIMER_B		=	$120			; Raster timer

BLIT			=	$FFFF8A00
halftone		=	BLIT+00	16*16 pattern mask
src_xinc		=	BLIT+32	increment of next source word (-128 -> +127)
src_yinc		=	BLIT+34	increment of next source line (-128 -> +127)
src_addr		=	BLIT+36	source data address
endmask1		=	BLIT+40	mask for first word in line (or only word)
endmask2		=	BLIT+42	mask for middle words in line
endmask3		=	BLIT+44	mask for last word in line
dst_xinc		=	BLIT+46	increment of next dest. word (-128 -> +127)
dst_yinc		=	BLIT+48	increment of next dest. line (-128 -> +127)
dst_addr		=	BLIT+50	destination screen address
x_size		=	BLIT+54	x-size	(number of words to go)
y_size		=	BLIT+56	y_size	(number of lines to go)
HOP			=	BLIT+58	halftone operation...
blit_op		=	BLIT+59	logic operations
blit_stat		=	BLIT+60	blitter chip status registers
skew			=	BLIT+61	offset bit shift (byte, 0 > +-15)

*-----------------------------------------------------------------------*
*	USEFUL MACROS									*
*-----------------------------------------------------------------------*

push	macro
	move.\0	\1,-(sp)
	endm
	
pop	macro
	move.\0	(sp)+,\1
	endm

pushall		macro
	movem.l	d0-d7/a0-a6,-(sp)
	endm
	
popall		macro
	movem.l	(sp)+,d0-d7/a0-a6
	endm

delay	macro					; wait for #n VBI's
	lea		TIMER(pc),a5
	move.w	#\1,(a5)
.wz\@	tst.w		(a5)
	bne.s		.wz\@
	endm

*-----------------------------------------------------------------------*

sync		macro				; clock-cycle timing macro
		IFEQ		NARG-1	; please don't read this, especially
		IFD		Devpac2_Pro
		dcb.w		\1,$4E71	; if you are a fan of high level
		ELSEIF
		dcb.w		$4E71,\1
		ENDC
		ELSEIF			; coding!
		IFLT		\1-3-3
		IFD		Devpac2_Pro
		dcb.w		\1,$4E71
		ELSEIF
		dcb.w		$4E71,\1
		ENDC
		ELSEIF
		move.w	#(\1-3)/3-1,\2
.wc\@		dbra		\2,.wc\@
Calc		set		(\1-3)-((\1-3)/3)*3
		IFGT		Calc
		IFD		Devpac2_Pro
		dcb.w		Calc,$4E71	; if you are a fan of high level
		ELSEIF
		dcb.w		$4E71,Calc	; if you are a fan of high level
		ENDC
		ENDC
		ENDC
		ENDC
		endm

*-----------------------------------------------------------------------*

CODE:			bra.s	START

VARIABLES:
TIME:			ds.w	1		; number of seconds to display picture
DATA:			ds.l	1		; source file
BIT1:			ds.l	1		; screen 1 address
PAL1:			ds.l	1		; palette 1 address
BIT2:			ds.l	1		; screen 2 address
PAL2:			ds.l	1		; palette 2 address

OLD_SCR		ds.l	1
TIMER:		ds.w	1
INTERLACE:		ds.b	1
HERZ:			ds.b	1

OLD_PAL		ds.w	16
VECTORS:		ds.b	40

*-----------------------------------------------------------------------*

START:lea		VARIABLES(pc),a6
	move.w	d0,(a6)+
	move.l	a0,(a6)+
	move.l	a1,(a6)+
	move.l	a2,(a6)+
	move.l	a3,(a6)+
	move.l	a4,(a6)+
	bsr		EMPTY_BUFFER			; clear keyboard buffer
	bsr		INIT_VECTORS			; store old vector setup
	bsr.s		DISPLAY_PCS				; show off fancy piccy
	bsr		RESET_VECTORS
	bsr		EMPTY_BUFFER
	rts
	
*-----------------------------------------------------------------------*
*	DISPLAY 'PCS' ROUTINES START HERE						*
*-----------------------------------------------------------------------*

DISPLAY_PCS:				; show one of my own snazzy 'PCS' pics.
	bsr		SAVE_SCREEN_SETUP	; init screen for piccy, saving old one
	move.l	DATA(pc),a0		; get address of file
	bsr		UNPACK_PCS		; unpack picture onto screen(s).
	delay		8			; wait for 10 vbi's (in case of 50/60Hz
	bsr		ENHANCED_DISPLAY	; switch). Turn on display interrupt.
	move.w	TIME(pc),d1
	mulu		#50,d1
	subq.l	#1,d1
.loop	cmp.b		#57,$FFFFFC02.w	; wait for 
	beq.s		.out
	lea		TIMER(pc),a6
	addq		#1,(a6)		; wait for 1 VBI
.wtv	tst.w		(a6)
	bne.s		.wtv
	subq.l	#1,d1			; decrement wait-counter.
	bpl.s		.loop
.out	bsr		STANDARD_DISPLAY	; when done, remove display interrupt.
	bsr		KILL_PALETTE
	bsr		REPLACE_SCREEN_SETUP
	rts

SAVE_SCREEN_SETUP:
	lea		COLOUR.w,a0		; store old colours
	lea		OLD_PAL(pc),a1
	moveq		#8-1,d0
.lp	move.l	(a0)+,(a1)+
	dbra		d0,.lp
	move.l	$FFFF8200.w,d0	; store old screen address
	lsl.w		#8,d0
	and.l		#$00FFFFFF,d0
	lea		OLD_SCR(pc),a0
	move.l	d0,(a0)
	bsr		KILL_PALETTE	; black screen
	move.l	BIT1(pc),a0		; clear screen 1
	bsr		CLS
	move.l	BIT2(pc),a0		; clear screen 2
	bsr		CLS	
	rts
	
REPLACE_SCREEN_SETUP:
	bsr		KILL_PALETTE	; black screen
	move.l	BIT1(pc),a0		; clear screen 1
	bsr		CLS
	move.l	BIT2(pc),a0		; clear screen 2
	bsr		CLS	
	move.l	OLD_SCR(pc),d0
	lsr.w		#8,d0
	move.l	d0,$FFFF8200.w
	lea		OLD_PAL(pc),a0
	lea		COLOUR.w,a1		; store old colours
	moveq		#8-1,d0
.lp	move.l	(a0)+,(a1)+
	dbra		d0,.lp
	rts

*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
*	UNPACK A 'PCS' PICTURE								*
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*

			rsreset
PCS_width		rs.w	1	; usually 320 for now
PCS_height		rs.w	1	; usually 200 for now
PCS_interlace	rs.b	1	; PCS-ST/E = 0 : SuperHam and Pchrome <> 0
PCS_ste		rs.b	1	; uses ste palette? 50/60Hz?
PCS_start		rs.b	0	; end of file header

;---------------------------------------------------------------------------
;		bit list... 	(PCS_interlace)
;		bit 0		:	if clear > XOR screen1 with screen2
;		bit 1		:	if clear > XOR palette1 with palette2
;		bit 2		:	if set   > interlace on, use bits 0+1,
;					otherwise ignore bits 0+1.
;
;	1.	if bit 2 is CLEAR then ignore bits 0+1.
;	2.	if bit 2 is SET and bit 0 is CLEAR then XOR
;		screen 1 with screen 2 after decompression. (delta-compression)
;	3.	if bit 2 is SET and bit 1 is CLEAR then XOR
;		palette 1 with palette 2 after decompression.
;---------------------------------------------------------------------------
;		bit list... 	(PCS_ste)
;		bit 0		:	if set > use 50Hz otherwise use 60Hz
;		bit 1		:	if set > then pic uses STE palette of 4096.
;
;	1.	if bit 0 is SET then the picture requires 50Hz,
;		otherwise set to 60Hz (STE or not)
;	2.	if bit 1 is SET, then piccy uses 4096 colour palette.
;---------------------------------------------------------------------------
;
;	There are 2 or 4 compressed chunks in each file - 1 bitmap and
;	1 palette for each screen, with 2 screens if it's interlaced.
;
;	The body of a chunk is a 2-byte value (not necessarily on a word
;	boundary) holding the number of control bytes in that compressed
;	chunk. This is followed by a big list of control bytes and data.
;
;	The bitmaps are horizontally byte-run compressed (like Degas)
;	but wrap around the screen instead of terminating on each scanline
;	(unlike Degas, more like Tiny). The screen planes are compressed
;	entirely separately, (the whole of plane 0 followed by the whole
;	of plane 1 etc.) without a break in the compression. It is just
;	one big string of data. If the screen was empty, the entire data
;	would consist of a control byte 0 (get a word), a control word
;	of 32000 (number of repeats), and a byte of 0 (byte to repeat).
;	The palette is compressed the same way, but using compressed words
;	instead of bytes.
;
;       For a given control byte, x: (as Tiny standard)
;
;
;     x < 0   Absolute value specifies the number of unique bytes/words to
;             fetch directly (from 1 to 127)
;
;     x = 0   1 word is taken which specifies the number of times to repeat
;     	  the next data byte/word fetched (from 128 to 32767)
;
;     x = 1   1 word is taken which specifies the number of unique
;     	  bytes/words to be fetched directly (from 128 - 32767)
;
;     x > 1   Specifies the number of times to repeat the next byte/word
;             fetched (from 2 to 127)

UNPACK_PCS:
	lea		INTERLACE(pc),a5
	sf		(a5)
	lea		PCS_start(a0),a1	; get past file header
	move.l	a0,a6			; keep for later
	lea		HERZ(pc),a5
	clr.b		(a5)			; set to 60Hz for now
	btst.b	#0,PCS_ste(a6)	; check real picture frequency,
	beq.s		.hz60			; if 60Hz, then leave as it is
.hz50	move.b	#2,(a5)		; otherwise must be 50Hz
.hz60	move.b	(a5),FREQ.w		; set up freq.
	move.l	BIT1(pc),a0		; get dest address of bitmap 1
	bsr.s		UNPACK_BITMAP	; unpack it onto screen
	move.l	PAL1(pc),a0		; same with palette
	bsr		UNPACK_PALETTE	; unpack it.
	tst.b		PCS_interlace(a6)	; check for interlaced mode
	beq.s		.done			; if not, skip past it
	lea		INTERLACE(pc),a5
	st		(a5)			; set INTERLACE to TRUE.
	move.l	BIT2(pc),a0		; now unpack second screen and
	bsr.s		UNPACK_BITMAP	; palette in the same way
	move.l	PAL2(pc),a0
	bsr		UNPACK_PALETTE
	bsr		XOR_BITMAP		; do delta-decompression if needed
	bsr		XOR_PALETTE		; on bitmap2 or palette2
.done	lea		PAL1(pc),a5
	add.l		#32,(a5)		; skip past first 16 colours
	lea		PAL2(pc),a5
	add.l		#32,(a5)		; in palette banks (used in top border)
	rts
	
UNPACK_BITMAP:				; decompress a bitmap.
	moveq		#0,d6
	move.w	#40,d2
	move.w	#200,d3
	moveq		#5,d4
	move.b	(a1)+,d7
	lsl.w		#8,d7
	move.b	(a1)+,d7
.Main	moveq		#0,d0
	subq		#1,d7
	bmi.s		.esc
	move.b	(a1)+,d0
	bmi.s		.B_block_copy
	beq.s		.W_run_length
	cmp.b		#1,d0
	beq.s		.W_block_copy
	bra.s		.B_run_length
.W_run_length
	move.b	(a1)+,d0
	lsl.w		#8,d0
	move.b	(a1)+,d0
.B_run_length
	subq		#1,d0
	move.b	(a1)+,d1
.run	move.b	d1,(a0,d6)
	addq		#1,d6
	and.w		#1,d6
	bne.s		.ok
	addq		#8,a0
.ok	subq		#1,d2				; drop 1 line
	bne.s		.fine
	moveq		#40,d2
	subq		#1,d3
	bne.s		.fine
	move.w	#200,d3
	lea		2-32000(a0),a0
	subq		#1,d4
	beq.s		.esc
.fine	dbra		d0,.run
	bra.s		.Main
.esc	rts
.B_block_copy
	neg.b		d0
	bra.s		.nw
.W_block_copy
	move.b	(a1)+,d0
	lsl.w		#8,d0
	move.b	(a1)+,d0
.nw	subq		#1,d0
.blk	move.b	(a1)+,d1
	move.b	d1,(a0,d6)
	addq		#1,d6
	and.w		#1,d6
	bne.s		.ok2
	addq		#8,a0
.ok2	subq		#1,d2				; drop 1 line
	bne.s		.fin2
	moveq		#40,d2
	subq		#1,d3
	bne.s		.fin2
	move.w	#200,d3
	lea		2-32000(a0),a0
	subq		#1,d4
	beq.s		.esc
.fin2	dbra		d0,.blk
	bra		.Main

UNPACK_PALETTE:				; decompress a palette
	move.b	(a1)+,d7
	lsl.w		#8,d7
	move.b	(a1)+,d7
.Main	moveq		#0,d0
	subq		#1,d7
	bmi.s		.esc
	move.b	(a1)+,d0
	bmi.s		.B_block_copy
	beq.s		.W_run_length
	cmp.b		#1,d0
	beq.s		.W_block_copy
	bra.s		.B_run_length
.W_run_length
	move.b	(a1)+,d0
	lsl.w		#8,d0
	move.b	(a1)+,d0
.B_run_length
	subq		#1,d0
	move.b	(a1)+,d1
	lsl.w		#8,d1
	move.b	(a1)+,d1
.run	move.w	d1,(a0)+
	dbra		d0,.run
	bra.s		.Main
.esc	rts
.B_block_copy
	neg.b		d0
	bra.s		.nw
.W_block_copy
	move.b	(a1)+,d0
	lsl.w		#8,d0
	move.b	(a1)+,d0
.nw	subq		#1,d0
.blk	move.b	(a1)+,d1
	lsl.w		#8,d1
	move.b	(a1)+,d1
	move.w	d1,(a0)+
	dbra		d0,.blk
	bra.s		.Main

XOR_BITMAP:						; delta decompression on bitmap.
	btst.b	#0,PCS_interlace(a6)
	bne.s		.nox
	pushall
	move.l	BIT1(pc),a0
	move.l	BIT2(pc),a1
	move.w	#32000/4-1,d0
.blop	move.l	(a0)+,d1
	eor.l		d1,(a1)+
	dbra		d0,.blop
	popall
.nox	rts

XOR_PALETTE:						; delta decompression on palette.
	btst.b	#1,PCS_interlace(a6)
	bne.s		.nox
	pushall
	move.l	PAL1(pc),a0
	move.l	PAL2(pc),a1
	move.w	#16*(3*199+1)-1,d0
.clop	move.w	(a0)+,d1
	eor.w		d1,(a1)+
	dbra		d0,.clop
	popall
.nox	rts

*-----------------------------------------------------------------------*
*	COLOUR SWITCHING ROUTINE							*
*-----------------------------------------------------------------------*
*	This is the actual screen-display interrupt and setup code		*
*-----------------------------------------------------------------------*

SCANLINE		=	$700
VIDEO_COUNTER	=	$FFFF8209

STE_HAM:
	btst		#1,FREQ.w
	bne.s		.hz50
	move.b	#32-10,SCANLINE.w
.hz60	pea		SCAN_COUNTER_60HZ(pc)
	bra.s		.done
.hz50	move.b	#62-10,SCANLINE.w
	pea		SCAN_COUNTER_50HZ(pc)
.done	pop.l		HBI_VEC.w
	move.w	#$2100,sr
	pushall
	move.l	PAL2(pc),a0
	lea		2*(1-16)(a0),a0
	lea		2+COLOUR.w,a1
	move.w	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
.wait	tst.b		SCANLINE.w
	bne.s		.wait
	move.w	#$2300,sr
.read	btst		#0,$FFFFFC00.w
	beq.s		.out
	move.b	$FFFFFC02.w,d0
	bra.s		.read
.out	lea		TIMER(pc),a0
	tst.w		(a0)
	ble.s		.rte
	subq		#1,(a0)
.rte	move.l	PAL1(pc),d0
	lea		INTERLACE(pc),a0
	tst.b		(a0)
	beq.s		.nin1
	lea		PAL1(pc),a0
	move.l	PAL2(pc),(a0)
.nin1	lea		PAL2(pc),a0
	move.l	d0,(a0)
	move.l	BIT1(pc),d0
	lea		INTERLACE(pc),a0
	tst.b		(a0)
	beq.s		.nin2
	lea		BIT1(pc),a0
	move.l	BIT2(pc),(a0)
.nin2	lea		BIT2(pc),a0
	move.l	d0,(a0)
.nint	lsr.w		#8,d0
	move.l	d0,$FFFF8200.w
.skip	popall
	rte

SCAN_COUNTER_50HZ:
	subq.b	#1,SCANLINE.w
	ble.s		SCREEN_RASTER_50HZ
	rte
	
SCREEN_RASTER_50HZ:
	move.w	#$2700,sr
	movem.l	d0-a6,-(sp)
	lea		(.ssp)+2(pc),a6
	move.l	a7,(a6)
	lea		VIDEO_COUNTER.w,a6
	moveq		#0,d0
	moveq		#64,d7
.wait	move.b	(a6),d0
	beq.s		.wait
	sub.w		d0,d7
	lsl.w		d7,d0
	sync		55,d0
	move.l	PAL2(pc),a7
	rept		199
	movem.l	(a7)+,d0-a6
	movem.l	d0-d7,COLOUR.w
	movem.l	a0-a6,COLOUR.w
	move.l	(a7)+,28+COLOUR.w
	lea		COLOUR.w,a0
	move.l	(a7)+,(a0)+
	move.l	(a7)+,(a0)+
	move.l	(a7)+,(a0)+
	move.l	(a7)+,(a0)+
	move.l	(a7)+,(a0)+
	move.l	(a7)+,(a0)+
	move.l	(a7)+,(a0)+
	move.w	#0,COLOUR.w
	move.l	(a7)+,(a0)+
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	endr
.ssp	move.l	#0,a7
	movem.l	(sp)+,d0-a6
	pea		ARTE(pc)
	pop.l		HBI_VEC.w	
	move.b	#$23,(sp)
ARTE:	rte

SCAN_COUNTER_60HZ:
	subq.b	#1,SCANLINE.w
	ble.s		SCREEN_RASTER_60HZ
	rte
	
SCREEN_RASTER_60HZ:
	move.w	#$2700,sr
	movem.l	d0-a6,-(sp)
	lea		(.ssp)+2(pc),a6
	move.l	a7,(a6)
	lea		VIDEO_COUNTER.w,a6
	moveq		#0,d0
	moveq		#64,d7
.wait	move.b	(a6),d0
	beq.s		.wait
	sub.w		d0,d7
	lsl.w		d7,d0
	sync		54,d0
	move.l	PAL2(pc),a7	
	rept		199
	movem.l	(a7)+,d0-a6
	movem.l	d0-d7,COLOUR.w
	movem.l	a0-a6,COLOUR.w
	move.l	(a7)+,28+COLOUR.w
	lea		COLOUR.w,a0
	move.l	(a7)+,(a0)+
	move.l	(a7)+,(a0)+
	move.l	(a7)+,(a0)+
	move.l	(a7)+,(a0)+
	move.l	(a7)+,(a0)+
	move.l	(a7)+,(a0)+
	move.l	(a7)+,(a0)+
	move.w	#0,COLOUR.w
	move.l	(a7)+,(a0)+
	nop
	nop
	nop
	nop
	nop
	nop
	endr
.ssp	move.l	#0,a7
	movem.l	(sp)+,d0-a6
	pea		ARTE(pc)
	pop.l		HBI_VEC.w	
	move.b	#$23,(sp)
	rte
	
*-----------------------------------------------------------------------*
*	INITIALISE PCS DISPLAY INTERRUPT						*
*-----------------------------------------------------------------------*

ENHANCED_DISPLAY:
	move.b	#$12,$FFFFFC02.w		; turn off the mouse 'cos it
	move.w	#$2700,sr
	pea		STE_HAM(pc)
	pop.l		VBI_VEC.w
	move.w	#$2300,sr
	rts

STANDARD_DISPLAY:
	move.w	#$2700,sr
	pea		NEW_VBI(pc)
	pop.l		VBI_VEC.w
	move.w	#$2300,sr
	move.b	#$8,$FFFFFC02.w		; turn off the mouse 'cos it
	rts

*-------------------------------------------------------------------------*

INIT_VECTORS:
	lea		VECTORS(pc),a0
	move.l	USP,a1
	move.l	a1,(a0)+
	move.l	HBI_VEC.w,(a0)+
	move.l	VBI_VEC.w,(a0)+
	move.l	KBD_VEC.w,(a0)+
	move.l	TIMER_A.w,(a0)+
	move.l	TIMER_B.w,(a0)+
	move.b	ENABLE_A.w,(a0)+
	move.b	ENABLE_B.w,(a0)+
	move.b	MASK_A.w,(a0)+
	move.b	MASK_B.w,(a0)+
	move.b	DATA_A.w,(a0)+
	move.b	DATA_B.w,(a0)+
	move.b	CTRL_A.w,(a0)+
	move.b	CTRL_B.w,(a0)+
	move.b	VECTOR.w,(a0)+
	move.b	FREQ.w,(a0)+
	move.w	#$2700,sr
	pea		NEW_VBI(pc)
	pop.l		VBI_VEC.w
	move.b	#0,ENABLE_A.w
	move.b	#1<<6,ENABLE_B.w	; leave IKBD alone
	move.w	#$2300,sr
	rts
	
RESET_VECTORS:
	move.w	#$2700,sr
	lea		VECTORS(pc),a0
	move.l	(a0)+,a1
	move.l	a1,USP
	move.l	(a0)+,HBI_VEC.w
	move.l	(a0)+,VBI_VEC.w
	move.l	(a0)+,KBD_VEC.w
	move.l	(a0)+,TIMER_A.w
	move.l	(a0)+,TIMER_B.w
	move.b	(a0)+,ENABLE_A.w
	move.b	(a0)+,ENABLE_B.w
	move.b	(a0)+,MASK_A.w
	move.b	(a0)+,MASK_B.w
	move.b	(a0)+,DATA_A.w
	move.b	(a0)+,DATA_B.w
	move.b	(a0)+,CTRL_A.w
	move.b	(a0)+,CTRL_B.w
	move.b	(a0)+,VECTOR.w
	move.b	(a0)+,FREQ.w
	move.w	#$2300,sr
	rts

NEW_VBI:
	push.l	a0
	lea		TIMER(pc),a0
	tst.w		(a0)
	ble.s		.rte
	subq		#1,(a0)
.rte	pop.l		a0
	rte

*-------------------------------------------------------------------------*

EMPTY_BUFFER:
	pushall
	bsr.s		FLUSH		; flush the IKBD properly (sorry, GEM!)
.bak	push.w	#11
	trap		#1
	addq		#2,sp
	tst.l		d0
	beq.s		.out
	push.w	#7
	trap		#1
	addq		#2,sp
	bra.s		.bak
.out	popall
	rts

FLUSH:push.w	d7
.read	btst		#0,$FFFFFC00.w	; empty hardware ikbd buffer
	beq.s		.out
	move.b	$FFFFFC02.w,d7
	bra.s		.read
.out	pop.w		d7
	rts

KILL_PALETTE:
	moveq		#8-1,d7
	lea		COLOUR.w,a0
.lp	clr.l		(a0)+
	dbra		d7,.lp		; empty out palette
	rts

CLS:	move.w	#32000/4-1,d0
.loop	clr.l		(a0)+
	dbra		d0,.loop
	rts
simonsunnyboy
Moderator
Moderator
Posts: 5239
Joined: Wed Oct 23, 2002 4:36 pm
Location: Friedrichshafen, Germany
Contact:

Re: PCS format

Post by simonsunnyboy »

Hmm, contains a lot of ugly Devpac specifics 8O
Anyone willing to INLINE for GFABASIC use? :D
I'd like to try to but it comes with few docs, not a defined calling interface and sofar I can't overlook whether it is already PC-relative code...
Simon Sunnyboy/Paradize - http://paradize.atari.org/

Stay cool, stay Atari!

1x2600jr, 1x1040STFm, 1x1040STE 4MB+TOS2.06+SatanDisk, 1xF030 14MB+FPU+NetUS-Bee
User avatar
Cyprian
10 GOTO 10
10 GOTO 10
Posts: 1964
Joined: Fri Oct 04, 2002 11:23 am
Location: Warsaw, Poland

Re: PCS format

Post by Cyprian »

Nyh wrote:But because you asked so nice about the HRM:
...
I will do a full code release next week. I still have some testing to do because I did some heavy editing without testing in the source.

Hans Wessels
great!
do you have any sources for HRM? I mean shower or converter e.g. BMP to HRM?
Portfolio / Lynx II / Jaguar / TT030 / Mega STe / 800 XL / 1040 STe / Falcon030 / 65 XE / 520 STm / SM124 / SC1435
SDrive / PAK68/3 / Lynx Multi Card / LDW Super 2000 / XCA12 / SkunkBoard / CosmosEx / SatanDisk / UltraSatan / USB Floppy Drive Emulator / Eiffel / SIO2PC / Crazy Dots / PAM Net
Hatari / Steem SSE / Aranym / Saint
http://260ste.appspot.com/
User avatar
prog99
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 122
Joined: Thu Jun 19, 2003 8:08 pm
Location: Edinburgh
Contact:

Re: PCS format

Post by prog99 »

SoLo2 wrote:Hello!


I saw a presentation screen by
Sinister Development, raytraced,
in red is the logotype, and was
very incredible because it showed
more than 16 colors, but in
medium resolution! 8)


Greetings,
SoLo2
Its been a long time but I'm pretty sure Asteroids is all running in low res.
All my real skills are undervalued
User avatar
bod/STAX
Atari Super Hero
Atari Super Hero
Posts: 508
Joined: Wed Nov 24, 2004 8:13 pm
Location: Halesowen, West Midlands, England

Re: PCS format

Post by bod/STAX »

I've just been looking through the above code on my ST and have a quick question.

I know this was written for use in another language such as STOS or GFA Basic and at the beginng of the routine is requires some 'VARIABLES' in some
of the registers. What I wan't to know is what are the correct offsets for each picture/palette to depack? The code only reads the screen/palette adresses
and doesn't define any.

I've just converted my own picture into Photochrome's 32000 colour format and want to test displaying it with this routine and try to see exacly what's going
on with this display mode.

**** EDIT ****

Forget it, every thing's clear to me now.
So let it be written, So let it be done. I'm sent here by the chosen one.
simonsunnyboy
Moderator
Moderator
Posts: 5239
Joined: Wed Oct 23, 2002 4:36 pm
Location: Friedrichshafen, Germany
Contact:

Re: PCS format

Post by simonsunnyboy »

It is? Then explain please ;)
Simon Sunnyboy/Paradize - http://paradize.atari.org/

Stay cool, stay Atari!

1x2600jr, 1x1040STFm, 1x1040STE 4MB+TOS2.06+SatanDisk, 1xF030 14MB+FPU+NetUS-Bee
User avatar
bod/STAX
Atari Super Hero
Atari Super Hero
Posts: 508
Joined: Wed Nov 24, 2004 8:13 pm
Location: Halesowen, West Midlands, England

Re: PCS format

Post by bod/STAX »

It is? Then explain please
Quite simple, you pass the number of seconds you want to display your picture in d0, the address of the picture in a0 and and four buffer addresses in a1-a4 two of those
are the addresses of your screens and the other two are the buffers for the palette data to be depacked, then you just call the assembled routine above.

I've just unravelled the above code and now I have my own display routine that makes it much easier to include 32768 colour pictures into demos and intros. I have one
piece of code that depacks a .PCS picture and saves both pictures and palettes out as raw data and then I have my display routine that uses this data to display the pictures.
It should now be easy to display a picture with no lower border where you could put a scroller and what not into the bottom border. I'll post the code here when I'm done
with it. It's much easier to read than the above code (although it does use the PCS depack routines from the code above).

One thing I did notice is that a PCS picture is not packed as well as it could be. My original picture was packed to 110K and when I repacked it with my display routine with
ICE packer it packed down to 77K.

**** EDIT ****

Ok, here it is. Included is the source code to depack and save a PCS picture into raw data files, a routine to display the raw data as a picture, the picture raw data files,
the PCS converted picture and the original Targa image I ported from the PC (Oh and an executable .PRG if you can't be bothered messing with an assembler).
Have fun with it. :D
You do not have the required permissions to view the files attached to this post.
So let it be written, So let it be done. I'm sent here by the chosen one.
User avatar
Nyh
Atari God
Atari God
Posts: 1496
Joined: Tue Oct 12, 2004 2:25 pm
Location: Netherlands

Re: PCS format

Post by Nyh »

bod/STAX wrote:Ok, here it is. Included is the source code to depack and save a PCS picture into raw data files, a routine to display the raw data as a picture, the picture raw data files.
Nice. Only I think it is a complete waste of memory space to expand the display loop the way you do. It makes the program far too big. You can also use a nice small loop. I also fixed the code so it will work in both 50 and 60 Hz. I included the ZIP file including the new display routine.

Code: Select all

hbl2:move    #$2700,SR
     movem.l D0-A6,-(SP)
     move.l  SP,save_stack
     lea     $FFFF8209.w,A6
     moveq   #0,D0
     moveq   #$40,D7
sync_wait:
     move.b  (A6),D0
     beq.s   sync_wait
     sub.w   D0,D7
     lsl.w   D7,D0
     move.w  #$0E,D0
wait_disp:
     dbra    D0,wait_disp     ; D0 = 0xffff at the end of the loop
     nop
     movea.l pal_pos2,SP
     move.w  D0,19104(SP)     ; -1
disp_loop:
fix_50_60:
     add.l   D0,D0            ; add.l d0,d0, 8 clocks, 50 Hz
; add.w d0,d0, 4 clocks, 60 Hz
     movem.l (SP)+,D0-A6
     movem.l D0-D7,$FFFF8240.w
     movem.l A0-A6,$FFFF8240.w
     move.l  (SP)+,$FFFF825C.w
     lea     $FFFF8240.w,A0
     move.l  (SP)+,(A0)+
     move.l  (SP)+,(A0)+
     move.l  (SP)+,(A0)+
     move.l  (SP)+,(A0)+
     move.l  (SP)+,(A0)+
     move.l  (SP)+,(A0)+
     move.l  (SP)+,(A0)+
     move.w  #0,$FFFF8240.w
     move.l  (SP)+,(A0)+
     tst.w   (SP)
     bge.s   disp_loop
     movea.l save_stack,SP
     movem.l (SP)+,D0-A6
     move.l  #rte_label,$68.w ; disable HBL
     move.w  #$2300,(SP)      ; disable HBL (SR fix)
rte_label:
     rte
Hans Wessels
You do not have the required permissions to view the files attached to this post.
User avatar
bod/STAX
Atari Super Hero
Atari Super Hero
Posts: 508
Joined: Wed Nov 24, 2004 8:13 pm
Location: Halesowen, West Midlands, England

Re: PCS format

Post by bod/STAX »

I agree it's a waste of memory, that's how the original displays the picture. I was toying with making it into a loop, but could'nt seem to get enough time within
the NOPS. I was going to try and do it like this:

Code: Select all

          move.w #199,loop_cnt     ; put this on vbl

.l3                                ; this is the picture display routine.
; display a line of picture here
          subq.w #1,loop_cnt
          cmp.w #0,loop_cnt
          bge.s .l3
I never thought about doing it the way you did (quite simple, really).
So let it be written, So let it be done. I'm sent here by the chosen one.
User avatar
MiggyMog
Atari Super Hero
Atari Super Hero
Posts: 909
Joined: Sun Oct 30, 2005 4:43 pm
Location: Scotland

Re: PCS format

Post by MiggyMog »

Good work guys.

A quicker program to make the PCS files from BMP/GIF/raw etc especiall in bulk would be good.

Photochrome is really slow?
('< o o o o |''| STM,2xSTFM,2xSTE+HD,C-Lab Falcon MK2+HD,Satandisk,Ultrasatandisk,Ethernat.
User avatar
ROWBEARTOE
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 123
Joined: Mon May 26, 2008 2:12 am
Contact:

Re: PCS format

Post by ROWBEARTOE »

Hey everyone- I just recently hooked up my Atari Mega ST4 and have been playing around with it. I've been a Spectrum 512 and occasional Quantum Paint user, but now that I've seen what Photochrome can do-WOW!! I would love to convert some of my PCS files I just made and view them on my PC. I've been converting a lot of my work (which is one of the reasons why I hooked up my Mega ST4) to the PC. Most picture files. Reccently I just made my favorite HAM6 killer using Spectrum 512. The picture plays to the strenghth of Spectrum 512 and since the colors are sperated by the color black, HAM6 has to smudge a lot. =)

http://i162.photobucket.com/albums/t268 ... Colors.jpg

Now I'm not a programmer, I just want to be able to convert my PCS files to something like PNG. Thanks for you help.
User avatar
Mug UK
Administrator
Administrator
Posts: 11539
Joined: Thu Apr 29, 2004 7:16 pm
Location: Stockport (UK)
Contact:

Re: PCS format

Post by Mug UK »

Didn't 'Speed Of Light' get a mention earlier on in this thread? Or did that not convert Photochrome?
My main site: http://www.mug-uk.co.uk - slowly digging up the bits from my past (and re-working a few): Atari ST, Sega 8-bit (game hacks) and NDS (Music ripping guide).

I develop a free Word (for Windows) add-in that's available for Word 2007 upwards. It's a fix-it toolbox that will allow power Word users to fix document errors. You can find it at: http://www.mikestoolbox.co.uk
simonsunnyboy
Moderator
Moderator
Posts: 5239
Joined: Wed Oct 23, 2002 4:36 pm
Location: Friedrichshafen, Germany
Contact:

Re: PCS format

Post by simonsunnyboy »

Speed Of Light does not convert PCS. PCS is an entire custom format.

PCS is not a file format in the common sense but a special format to be interpreted by a custom display routine which is tightly tied with the ST(e) Shifter and the ST interrupt system. So writing a converter back to other formats would require a lot of work.

Best solution would probably be to get the pictures in their original formats and convert them from there to PNG.
Simon Sunnyboy/Paradize - http://paradize.atari.org/

Stay cool, stay Atari!

1x2600jr, 1x1040STFm, 1x1040STE 4MB+TOS2.06+SatanDisk, 1xF030 14MB+FPU+NetUS-Bee
User avatar
Mug UK
Administrator
Administrator
Posts: 11539
Joined: Thu Apr 29, 2004 7:16 pm
Location: Stockport (UK)
Contact:

Re: PCS format

Post by Mug UK »

Ah right .. my mistake :(
My main site: http://www.mug-uk.co.uk - slowly digging up the bits from my past (and re-working a few): Atari ST, Sega 8-bit (game hacks) and NDS (Music ripping guide).

I develop a free Word (for Windows) add-in that's available for Word 2007 upwards. It's a fix-it toolbox that will allow power Word users to fix document errors. You can find it at: http://www.mikestoolbox.co.uk
User avatar
Nyh
Atari God
Atari God
Posts: 1496
Joined: Tue Oct 12, 2004 2:25 pm
Location: Netherlands

Re: PCS format

Post by Nyh »

ROWBEARTOE wrote:Now I'm not a programmer, I just want to be able to convert my PCS files to something like PNG. Thanks for you help.
This ST program will convert almost any ST graphics format:
** supported formats:
** DEGAS: .PI1, .PI2, .PI3, .PC1, .PC2, .PC3, ICN, BL1, BL2, BL3
** Neochrome: .NEO
** CrackArt: .CA1, .CA2, .CA3
** ArtDirector: .ART
** STadCad: .PAC
** Tiny: .TNY, .TN1, .TN2, .TN3, .TN4, .TN5, .TN6
** Doodle: .DOO
** Spectrum: .SPU, .SPC, .SPS, .SPX
** Photochrome: .PCS
** QuantumPaint: .PBX
** Overscan: .PCI
** HighresMedium: .HRM
** DeLuxePaint ST (only the special ST format): .IFF
** STOS memory bank: .MBK
** STOS character set: .CR0, .CR1, .CR2
** Animaster Sprite Bank: .ASB
** Picture Packer: .PP1, .PP2, .PP3
Into a standard .BMP file. Runs fine in 1 MB only bigger high color pictures need 4Mb memory

Hans Wessels
You do not have the required permissions to view the files attached to this post.
simonsunnyboy
Moderator
Moderator
Posts: 5239
Joined: Wed Oct 23, 2002 4:36 pm
Location: Friedrichshafen, Germany
Contact:

Re: PCS format

Post by simonsunnyboy »

simonsunnyboy wrote:Speed Of Light does not convert PCS. PCS is an entire custom format.

PCS is not a file format in the common sense but a special format to be interpreted by a custom display routine which is tightly tied with the ST(e) Shifter and the ST interrupt system. So writing a converter back to other formats would require a lot of work.

Best solution would probably be to get the pictures in their original formats and convert them from there to PNG.
Looks like Nyh did that tedious work :D

Nice :cheers:
Simon Sunnyboy/Paradize - http://paradize.atari.org/

Stay cool, stay Atari!

1x2600jr, 1x1040STFm, 1x1040STE 4MB+TOS2.06+SatanDisk, 1xF030 14MB+FPU+NetUS-Bee
User avatar
Mug UK
Administrator
Administrator
Posts: 11539
Joined: Thu Apr 29, 2004 7:16 pm
Location: Stockport (UK)
Contact:

Re: PCS format

Post by Mug UK »

Nice util .. one for the Wiki when I get 5 mins :)
My main site: http://www.mug-uk.co.uk - slowly digging up the bits from my past (and re-working a few): Atari ST, Sega 8-bit (game hacks) and NDS (Music ripping guide).

I develop a free Word (for Windows) add-in that's available for Word 2007 upwards. It's a fix-it toolbox that will allow power Word users to fix document errors. You can find it at: http://www.mikestoolbox.co.uk
User avatar
Nyh
Atari God
Atari God
Posts: 1496
Joined: Tue Oct 12, 2004 2:25 pm
Location: Netherlands

Re: PCS format

Post by Nyh »

muguk wrote:Nice util .. one for the Wiki when I get 5 mins :)
It think it lacks a front-end.
Hans Wessels
User avatar
Mug UK
Administrator
Administrator
Posts: 11539
Joined: Thu Apr 29, 2004 7:16 pm
Location: Stockport (UK)
Contact:

Re: PCS format

Post by Mug UK »

http://www.atari-forum.com/wiki/index.php/ST2BMP

Have mentioned it's a TTP file.
My main site: http://www.mug-uk.co.uk - slowly digging up the bits from my past (and re-working a few): Atari ST, Sega 8-bit (game hacks) and NDS (Music ripping guide).

I develop a free Word (for Windows) add-in that's available for Word 2007 upwards. It's a fix-it toolbox that will allow power Word users to fix document errors. You can find it at: http://www.mikestoolbox.co.uk
Post Reply

Return to “Coding”