Demo of low res colour vga video for stm32f3 discovery board

Dependencies:   STM32F3-Discovery-minimal

Fork of Space_Invaders_Demo by Martin Johnson

gdi.c

Committer:
MartinJohnson
Date:
2019-04-03
Revision:
17:833f1b69e11d
Parent:
14:3035b3271395

File content as of revision 17:833f1b69e11d:

/***************************************************************************
 * STM32 VGA demo
 * Copyright (C) 2012 Artekit Italy
 * http://www.artekit.eu
 * Written by Ruben H. Meleca
 
### gdi.c
 
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

***************************************************************************/

#include "gdi.h"
#include "mth.h"
#include "video.h"
#include "stm32f30x.h"

extern u8		*fb[VID_VSIZE];// *(VID_HSIZE+2)];
extern const u8 	gdiSystemFont[];
extern const u8 font6x8[];


#define CCM __attribute__ ((section (".ccmram")))
const u8			gdiCloseBm[] = 	{ 	0x7f, 0xC0,
										0x7f, 0xC0,
										0x7f, 0xC0,
										0x7f, 0xC0,
										0x40, 0x40,
										0x7f, 0xC0,
										0x7f, 0xC0,
										0x7f, 0xC0,
										0x7f, 0xC0 };

int colour=7;

u16	strLen(pu8 str) {

int		i = 0;

	while (*str != 0) {
		++i;
		++str;
	}
	return(i);
}

// *****************************************************************************
//	Function gdiCopyRect(PGDI_RECT rc1, PGDI_RECT rc2) 
//
//	Copy rectangle rc2 to rc1
//
//	parameters:
//		rc1			Destination rectangle
//		y			Source rectangle
//
//	return:			none
// *****************************************************************************
void gdiCopyRect(PGDI_RECT rc1, PGDI_RECT rc2) {

	rc1->x = rc2->x;
	rc1->y = rc2->y;
	rc1->w = rc2->w;
	rc1->h = rc2->h;
}

// *****************************************************************************
//	Function gdiBitBlt(PGDI_RECT prc, i16 x, i16 y, i16 w, i16 h, pu8 bm, u16 rop)
//
//	Bit Block Transfer funcion. This function uses the STM32 Bit-Banding mode
//	to simplify the complex BitBlt functionality.
//
//	From Cortex STM32F10x Reference Manual (RM0008):
//	A mapping formula shows how to reference each word in the alias region to a
//	corresponding bit in the bit-band region. The mapping formula is:
//	bit_word_addr = bit_band_base + (byte_offset x 32) + (bit_number � 4)
//	where:
//	bit_word_addr is the address of the word in the alias memory region that
//	maps to the targeted bit.
//	bit_band_base is the starting address of the alias region
//	byte_offset is the number of the byte in the bit-band region that contains
//	the targeted bit bit_number is the bit position (0-7) of the targeted bit.
//	Example:
//	The following example shows how to map bit 2 of the byte located at SRAM
//	address 0x20000300 in the alias region:
//	0x22006008 = 0x22000000 + (0x300*32) + (2*4).
//	Writing to address 0x22006008 has the same effect as a read-modify-write
//	operation on bit 2 of the byte at SRAM address 0x20000300.
//	Reading address 0x22006008 returns the value (0x01 or 0x00) of bit 2 of
//	the byte at SRAM address 0x20000300 (0x01: bit set; 0x00: bit reset).
//
//	For further reference see the Cortex M3 Technical Reference Manual
//
//	Parameters:
//
//		prc			Clipping rectangle. All X/Y coordinates are inside "prc"
//					If "prc" is NULL, the coordinates will be the entire display
//					area
//		x			Bitmap X start position
//		y			Bitmap Y start position
//		w			Bitmap width, in pixels
//		y			Bitmap height, in pixels
//		bm			Pointer to te bitmap start position
//		rop			Raster operation. See GDI_ROP_xxx defines
//
//	return			none
// ****************************************************************************

u8 leftmask[]={0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe};
u8 rightmask[]={0x0,0x1,0x3,0x7,0xf,0x1f,0x3f,0x7f};
CCM void gdiBitBlt(PGDI_RECT prc, i16 x, i16 y, i16 w, i16 h, pu8 bm, u16 rop) {

u16		i, xz, xb, xt;
u32		wb;					// Width in bytes
u32		r,rr;					// Start X position in bits (relative to x)
u32		k;
u32		d;
u32		offs;
u8		c;
pu8		fbPtr;				// Pointer to the Frame Buffer Bit-Band area
pu8		fbBak;
u8		fb1;
u32		fb2;
u32		rp;
pu8		bmPtr;				// Pointer to the bitmap bits

//	Calculate clipping region
	if (prc != NULL) {
		x = prc->x + x;
		y = prc->y + y;
	}

//	Get total bitmap width in bytes

	wb = (u32) (w+7) >> 3;
//	if ((wb << 3) < (u32) w) ++wb;

//	Get starting bit inside the first byte

	r=x&7;
	xb=x>>3;

	rr=7-((w+r)&7); // no of bits to mask at end of bitmap

//	Clip X

	if (prc == NULL) {
		if ((x + w) >= VID_PIXELS_X ) {
			xt =  VID_PIXELS_X - x;
		} else {
			xt = w;
		}
	} else {
		if ((x + w) >= (x + prc->w)) {
			xt = prc->w - x;
		} else {
			xt = w;
		}
	}

//	Draw bits
/*
	for (i = 0; i < h; i++) {
		u8 lst=0,d;
//	Clip Y
		bmPtr = bm + ((u32) i * wb);
		if ((i + y) > (VID_VSIZE - 1)) return;
		if(rop==GDI_ROP_COPY) {
			c = *bmPtr++;
			if((w+r)<8)
				fb[i+y][xb] = (fb[i+y][xb]&(leftmask[r]|rightmask[rr]))|(c>>r);
			else {
				fb[i+y][xb] = (fb[i+y][xb]&leftmask[r])|(c>>r);
				lst=(c<<(8-r));
				for(xz=1;xz<wb;xz++) {
					c = *bmPtr++;
					fb[i+y][xz+xb]=((c>>r)|lst);
					lst=(c<<(8-r));
				}
				fb[i+y][xb+wb] = (fb[i+y][xb+wb]&rightmask[rr])|lst;
			}
		}
		if(rop==GDI_ROP_XOR) {
                        for(xz=0;xz<wb;xz++) {
                                c = *bmPtr++;
                                fb[i+y][xz+xb]^=((c>>r)|lst);
                                lst=(c<<(8-r));
                        }
			if((w+r)>8)
				fb[i+y][xz+xb]^=lst;
                }
		if(rop==GDI_ROP_OR) {
                        for(xz=0;xz<wb;xz++) {
                                c = *bmPtr++;
                                fb[i+y][xz+xb]|=((c>>r)|lst);
                                lst=(c<<(8-r));
                        }
                        if((w+r)>8)
                                fb[i+y][xz+xb]|=lst;
                }

*/

//	Get offset to frame buffer in bit-banding mode
	for (i = 0; i < h; i++) {
		u8 lst=0,d;

/*
		offs = (((u32) x >> 3)) + ((u32) (y + i)  * VID_HSIZE_R);
		k = (u32) (&fb - 0x20000000);
		k += offs;
		fbPtr = (pu8) (0x22000000 + (k * 32) + ((7 - r) * 4));
		fbBak = (pu8) (0x22000000 + (k * 32) + 28);
	*/	
		
		fbPtr = fb[y+i]+x;
		if(fbPtr > fb[VID_VSIZE-1]) return;

//	Get offset to bitmap bits

		bmPtr = bm + ((u32) i * wb);
		xz = w;

		xb = 0;
		for (xz = 0; xz < xt; xz++) {
			//fb1 = ((u32) fbPtr) & 0x000000E0;
			if(x+xz > VID_HSIZE) break;
			if (xb++ == 0) {
				c = *bmPtr;
				++bmPtr;
			}
			xb &= 0x07;
			(c & 0x80) ? (rp = colour<<4) : (rp = 0);
			switch(rop) {
				case GDI_ROP_COPY:	*fbPtr |= rp;		break;
				case GDI_ROP_XOR:	*fbPtr ^= rp;		break;
				case GDI_ROP_AND:	*fbPtr &= rp;		break;
				case GDI_ROP_OR:	*fbPtr |= rp;		break;
			}
			fbPtr += 1;
			
			/*
			fb2 = ((u32) fbPtr) & 0x000000E0;
			if (fb1 != fb2) {
				fbPtr = fbBak + 32;
				fbBak = fbPtr;
			}
			*/
			c <<= 1;
		}

	}
}
void gdiSetColour(int c) {
	colour=c;
}
// *****************************************************************************
//	Function gdiPoint(PGDI_RECT rc, u16 x, u16 y)
//
//	Show a point in x/y position using the current graphical mode stored in 
//	grMode variable
//
//	parameters:
//		x			X position
//		y			Y position
//		rop			Raster operation. See GDI_ROP_xxx defines
//
//	return:			none
// *****************************************************************************
__attribute__ ((section ("ccmram"))) void gdiPoint(PGDI_RECT rc, u16 x, u16 y, u16 rop) {

u16		w, r;
u8		m;

//	Test for point outside display area

	if (x >= VID_PIXELS_X || y >= VID_PIXELS_Y) return;

	w = x;// >> 3;
	//r = x - (w << 3);

//	Prepare mask

	m = colour<<4;//(0x80 >> r);

	switch(rop) {
		case GDI_ROP_COPY:		fb[y][w] |= m;
								break;
		case GDI_ROP_XOR:		fb[y][w] ^= m;
								break;
		case GDI_ROP_AND:		fb[y][w] &= m;
								break;
	}
}

//*****************************************************************************
//	Function gdiLine(i16 x1, i16 y1, i16 x2, i16 y2, u16 rop)
//
//	Draw line using Bresenham algorithm 
//
//	This function was taken from the book:
//	Interactive Computer Graphics, A top-down approach with OpenGL
//	written by Emeritus Edward Angel
//
//	parameters:
//		prc			Clipping rectangle
//		x1			X start position
//		y1			Y start position
//		x2			X end position
//		y2			Y end position
//		rop			Raster operation. See GDI_ROP_xxx defines
//
//	return			none
//*****************************************************************************
void gdiLine(PGDI_RECT prc, i16 x1, i16 y1, i16 x2, i16 y2, u16 rop) {

i16		dx, dy, i, e;
i16		incx, incy, inc1, inc2;
i16		x, y;

	dx = x2 - x1;
	dy = y2 - y1;

	if(dx < 0) dx = -dx;
	if(dy < 0) dy = -dy;
	incx = 1;
	if(x2 < x1) incx = -1;
	incy = 1;
	if(y2 < y1) incy = -1;
	x=x1;
	y=y1;

	if (dx > dy) {
		gdiPoint(prc, x, y, rop);
		e = 2*dy - dx;
		inc1 = 2 * ( dy -dx);
		inc2 = 2 * dy;
		for (i = 0; i < dx; i++) {
			if (e >= 0) {
				y += incy;
				e += inc1;
			}
			else {
				e += inc2;
			}
			x += incx;
			gdiPoint(prc, x, y, rop);
		}
	} else {
		gdiPoint(prc, x, y, rop);
		e = 2 * dx - dy;
		inc1 = 2 * (dx - dy);
		inc2 = 2 * dx;
		for(i = 0; i < dy; i++) {
			if (e >= 0) {
				x += incx;
				e += inc1;
			} else {
				e += inc2;
			}
			y += incy;
			gdiPoint(prc, x, y, rop);
		}
	}
}

//*****************************************************************************
//	Function gdiRectangle(i16 x1, i16 y1, i16 x2, i16 y2, u16 rop)
//
//	Draw rectangle
//
//	parameters:
//		x1			X start position
//		y1			Y start position
//		x2			X end position
//		y2			Y end position
//		rop			Raster operation. See GDI_ROP_xxx defines
//
//	return			none
//*****************************************************************************
void	gdiRectangle(i16 x0, i16 y0, i16 x1, i16 y1, u16 rop) {
	
	gdiHLine(x0,y0,x1,rop);
	gdiHLine(x0,y1,x1,rop);
	gdiVLine(x0,y0,y1,rop);
	gdiVLine(x1,y0,y1,rop);
}

void gdiFilledRectangle(i16 x0, i16 y0, i16 x1, i16 y1, u16 rop) {
	
	for(int y=y0;y<y1;y++)
		gdiHLine(x0,y,x1,rop);
}

//*****************************************************************************
//	Function gdiRectangleEx(PGDI_RECT rc, u16 rop)
//
//	Draw rectangle
//
//	parameters:
//		rc			Struct containing the rectangle parameters
//		rop			Raster operation. See GDI_ROP_xxx defines
//
//	return			none
//*****************************************************************************
void	gdiRectangleEx(PGDI_RECT rc, u16 rop) {

	gdiRectangle(rc->x, rc->y, rc->x + rc->w, rc->y + rc->h,rop);
}

//*****************************************************************************
//	Function gdiCircle(i16 x, i16 y, i16 r, u16 rop)
//
//	Draw circle. This function uses the integer-precision math
//
//	parameters:
//		x			Circle center X position
//		y			Circle center Y position
//		r			Radius
//		rop			Raster operation. See GDI_ROP_xxx defines
//
//	return			none
//*****************************************************************************
void	gdiCircle(u16 x, u16 y, u16 r, u16 rop) {

i32		x1, y1;
u16		a;

	int div;
	div=360/(16*r);
	if(div==0) div=1;
	for (a = 0; a < 360; a+=div) {		
		x1 = r * mthCos(a);
		y1 = r * mthSin(a);
		gdiPoint(NULL, (x1 / 10000) + x,(y1 / 10000) + y,rop);
	}
}

void gdiHLine(u16 x, u16 y, u16 x1, u16 rop) {
//	printf("gdiHline %d %d %d\n",x,y,x1);
	if(x>=VID_HSIZE) x=VID_HSIZE-1;
	if(x1>=VID_HSIZE) x1=VID_HSIZE-1;
	if(y>=VID_VSIZE) y=VID_VSIZE-1;
	if(x>x1) {
		int t=x1;
		x1=x;
		x=t;
	}
	char *start=fb[y]+x;
	int n=x1-x+1;
	while(n--) {
		*start++|=(colour<<4);
	}
}


void gdiVLine(u16 x, u16 y, u16 y1, u16 rop) {
//	printf("gdiVline %d %d %d\n",x,y,y1);
	if(x>=VID_HSIZE) x=VID_HSIZE-1;
	if(y1>=VID_VSIZE) y1=VID_VSIZE-1;
	if(y>=VID_VSIZE) y=VID_VSIZE-1;
	if(y>y1) {
		u16 t=y1;
		y1=y;
		y=t;
	}
	char *start=fb[y]+x;
	int n=y1-y+1;
	while(n--) {
		*start|=(colour<<4);
		start+=HTOTAL;
	}
}

void	gdiFilledCircle(u16 x, u16 y, u16 r, u16 rop) {

i32		x1, y1;
u16		a;

	int div;
	div=360/(16*r);
	if(div==0) div=1;
	for (a = 0; a < 100; a+=div) {		
		x1 = r * mthCos(a);
		y1 = r * mthSin(a);
		gdiHLine( (x1 / 10000) + x,(y1 / 10000) + y,-(x1 / 10000) + x,rop);
		gdiHLine( (x1 / 10000) + x,-(y1 / 10000) + y,-(x1 / 10000) + x,rop);
//		gdiPoint(NULL, (x1 / 10000) + x,(y1 / 10000) + y,rop);
	}
}
//*****************************************************************************
//	Function gdiDrawText(PGDI_RECT prc, pu8 ptext, u16 style, u16 rop)
//
//	Draw text inside rectangle
//
//	parameters:
//		prc			Pointer to clipping rectangle
//		ptext		Pointer to text
//		style		Text style (see GDI_WINCAPTION_xx defines)
//		rop			Raster operation. See GDI_ROP_xxx defines
//
//	return			none
//*****************************************************************************
CCM void gdiDrawText(PGDI_RECT prc, pu8 ptext, u16 style, u16 rop) {

u16		l, i, pos, xp;
u8		c;
pu8		ptx;

	l = strLen(ptext) * GDI_SYSFONT_WIDTH;
	switch(style) {
		case GDI_WINCAPTION_RIGHT:		if (l < prc->w) {
											prc->x += (prc->w - l);
										}
										break;
		case GDI_WINCAPTION_CENTER:		if (l < prc->w) {
											prc->x += ((prc->w - l) / 2);
										}
										break;
	}
	l = strLen(ptext);
	xp = 1;//prc->x;
	for (i = 0; i < l; i++) {
		c = *(ptext++);
		if (c >= GDI_SYSFONT_OFFSET) {
			pos = (u16) (c - GDI_SYSFONT_OFFSET) * GDI_SYSFONT_BYTEWIDTH * GDI_SYSFONT_HEIGHT;
			ptx = ((pu8) gdiSystemFont) + pos;
			gdiBitBlt(prc, xp, 0, GDI_SYSFONT_WIDTH, GDI_SYSFONT_HEIGHT, ptx, rop);
			xp += GDI_SYSFONT_WIDTH;
			if (xp >= ((prc->x + prc->w) - GDI_SYSFONT_WIDTH)) return;
		}
	}
}

//*****************************************************************************
//	Function gdiDrawTextEx(i16 x, i16 y, pu8 ptext, u16 rop)
//
//	Draw text in X/Y position using system font.
//
//	parameters:
//		x			X start position
//		y			Y start position
//		ptext		Pointer to text
//		rop			Raster operation. See GDI_ROP_xxx defines
//
//	return			none
//*****************************************************************************
void gdiDrawTextEx(i16 x, i16 y, pu8 ptext, u16 rop) {

u16		l, i, pos, xp;
u8		c;
pu8		ptx;

	l = strLen(ptext);
	xp = x;
	for (i = 0; i < l; i++) {
		c = *(ptext++);
		if (c >= GDI_SYSFONT_OFFSET) {
			pos = (u16) (c - GDI_SYSFONT_OFFSET) * GDI_SYSFONT_BYTEWIDTH * GDI_SYSFONT_HEIGHT;
			ptx = ((pu8) gdiSystemFont) + pos;
			gdiBitBlt(NULL, xp, y, GDI_SYSFONT_WIDTH, GDI_SYSFONT_HEIGHT, ptx, rop);
			xp += GDI_SYSFONT_WIDTH;
			if (xp >= VID_PIXELS_X) return;
		}
	}
}
//*****************************************************************************
//	Function gdiDrawWindow(PGDI_WINDOW pwin)
//
//	Draw window
//
//	parameters:
//		pwin		Pointer to windows struct
//
//	return			none
//*****************************************************************************
void	gdiDrawWindow(PGDI_WINDOW pwin) {

i16			i;
GDI_RECT	rc, rt;

	gdiCopyRect(&rc,&pwin->rc);
	if (pwin->style & GDI_WINCAPTION) {
		gdiCopyRect(&rt,&pwin->rc);
		rt.h = rt.y + 11;
		rt.x += 2;
		rt.y += 1;
		rc.h += 10;
		for (i = 0; i < 11; i++) {
			gdiLine(NULL,rc.x, rc.y + i, rc.x + rc.w, rc.y + i, GDI_ROP_COPY);
		}
		if (pwin->style & GDI_WINCLOSEICON) {
			gdiBitBlt(&rc, rc.w - 9, 1, 10, 9, (pu8) gdiCloseBm, GDI_ROP_COPY);
			rt.w -= 11;
		} else {
			rt.w -= 1;
		}
		gdiDrawText(&rt,pwin->caption,pwin->style & GDI_WINCAPTION_MASK, GDI_ROP_XOR);
	}
	gdiRectangleEx(&rc,GDI_ROP_COPY);
}

int buttonstate=0;
int buttonPress() {
	int b=GPIOA->IDR&1;
	if(b!=buttonstate && b) {
		buttonstate=b;
		return 1;
	}
	buttonstate=b;
	return 0;
}