Image Manipulation

Discuss programming topics for the various GPL'd game engine sources.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: Image Manipulation

Post by Baker »

Sheesh. I'm drawing to draw a circle in Gimp and you'd think that'd be easy.

No.

I had to find a tutorial on it and it's mad hard for how easy it should be.

http://www.farcrydesign.com/tutorials/G ... orial.html
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
goldenboy
Posts: 924
Joined: Fri Sep 05, 2008 11:04 pm
Location: Kiel
Contact:

Re: Image Manipulation

Post by goldenboy »

To draw a circle in Gimp, you only need to create a circular selection of the right size, then "Stroke Selection".

To draw anything out of straight lines, I usually just use the paths tool and then "Stroke Path".

... If you need to use mainly straight lines etc for something, then a vector graphics application will perhaps be better suited, like Inkscape.

http://www.inkscape.org
leileilol
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Re: Image Manipulation

Post by leileilol »

why can't i just have a damn circle and line tool?

"submit a patch" - a developer

"FUCK YOU" - a typical frustrated end user
i should not be here
qbism
Posts: 1238
Joined: Thu Nov 04, 2004 5:51 am
Contact:

Re: Image Manipulation

Post by qbism »

Baker wrote:Sheesh. I'm drawing to draw a circle in Gimp and you'd think that'd be easy.

No.

I had to find a tutorial on it and it's mad hard for how easy it should be.

http://www.farcrydesign.com/tutorials/G ... orial.html
filters->render->gfig might be easier. Although the location of the tool is not so intuitive.
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Image Manipulation

Post by toneddu2000 »

I really suggest you, as goldenboy said, to use Inkscape for this kind of works
Meadow Fun!! - my first commercial game, made with FTEQW game engine
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: Image Manipulation

Post by Baker »

Inner mysteries to unravel:

1) Flood fill
2) Edge detection
3) Complex selection

In a way those aren't hard. In a way, they require a bit of efficiency. And they are all related.

Input: For instance, let's say there is an image with a solid white background color.
Output: Let's say you wish to change that background color to green.

In theory ...

1) Generate an alpha mask with alpha = black (not solid) for areas of the background color and ...
2) alpha = white (solid) for areas not touching any area next to the background color and ...
3) an alpha scale for areas bordered by either of the above in proportion to how many or 8 maximum neighboring pixels (top, right, bottom, left, top right, top left, bottom right, bottom left ... but edge of image pixels do not have all of these) are of each type.
4) Then again, some of the neighboring pixels may be other bordering pixels.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: Image Manipulation

Post by Baker »

Image

I'd used my "have C allocate and return an array list" code plus some geometry calculations and reuse of verts with triangle fans.

I'm using a single line to draw each polygon.

Code: Select all

		ScreenRect region= { {25, 25}, {225, 225} };
		GL_Draw_Polygon_Inscribed(region, 5, Color_RGBA_From_Bytes(255, 0, 0, 255));
Having a function return a list of vertices for such a polygon

Code: Select all

void GL_Draw_Polygon_Inscribed (ScreenRect location, int numSides, unsigned RGBAcolor)
{	 
	float		center_x		= ScreenRect_CenterXf		(location);
	float		center_y		= ScreenRect_CenterYf		(location);
	float		circumradius	= ScreenRect_CircumRadiusf  (location);
	
	Point2D**	pointsList		= Polygon_Vertices_ArrayListAlloc (numSides, center_x, center_y, circumradius);
	const int	numPointsList	= ArrayListCount (pointsList);

	color4_t RGBAColor4f;
	Color_RGBA_To_Color4f (RGBAcolor, RGBAColor4f);
	
	GL_Prepare_Colored_ListVerts (pointsList, numPointsList, GL_TRIANGLE_FAN, RGBAColor4f);
	glLineWidth(3);
	GL_Prepare_Colored_ListVerts (pointsList, numPointsList, GL_LINE_LOOP,    COLOR4F_WHITE);
	glLineWidth(1);
	
	glPointSize(8);
	GL_Prepare_Colored_ListVerts (pointsList, numPointsList, GL_POINTS,       COLOR4F_YELLOW);
	glPointSize(6);
	GL_Prepare_Colored_ListVerts (pointsList, numPointsList, GL_POINTS,       COLOR4F_LITERED);
	glPointSize(1);
	
	
	ArrayListFree (pointsList);
}
Using a function to calculate the polygon verts like this

Code: Select all

Point2D** Polygon_Vertices_ArrayListAlloc (int numSides, float center_x, float center_y, float circumradius)
{
	Point2D		myPolygons[numSides];

	const float	pieSlice = 360 / numSides;
	float		degrees = 90;
	
	for (int side = 0; side < numSides; degrees += pieSlice, side ++)
	{
		float x = -1, y = -1;
		Circle_Set_Point_With_Center_Radius_Degrees (&x, &y, 0, 0, circumradius, degrees);

		myPolygons[side].x = center_x + x;
		myPolygons[side].y = center_y - y;	// True geometry flips Y, we need descending Y or whatever
	}
	
	ReturnArray_Alloc (Point2D**, myPolygons);
}
Using my funny idea on how to return an array without making a new data type that goes like this

Code: Select all

void pArrayFree (void** arrayList)
{
	Memory_free (*arrayList);
	Memory_free (arrayList);
}

int pArrayCount (void** arrayList)
{
	int count;
	
	for (count = 0; arrayList[count]; count ++ )
		;
	
	return count;
}

void** pReturnArray (const void* sourceItems, const size_t numItems, const size_t itemSizeBytes)
{
	void*	myReturnData	= Memory_calloc (numItems + 0, itemSizeBytes, "Array data");	// Malloc return data block
	void** myReturnPointer	= Memory_calloc (numItems + 1, sizeof(myReturnData),  "Array of pointers");			// Malloc return pointer block
	
	myReturnPointer[numItems] = NULL;	// NULL terminate list
	
	for (int n = 0; n < numItems; n++)
	{
		size_t addy = n * itemSizeBytes;
		memcpy (&myReturnData[addy], &sourceItems[addy], itemSizeBytes);
		myReturnPointer[n] = &myReturnData[addy];
	}
	
	return myReturnPointer;
}

// Creation
void** pReturnArray (const void* sourceItems, const size_t numItems, const size_t itemSizeBytes);

// Utilization
int    pArrayCount  (void** arrayList);
#define ArrayListCount(arrayList) pArrayCount((void**)arrayList)	// Warning free

// Destruction
void   pArrayFree   (void** arrayList);
#define ArrayListFree(arrayList) pArrayFree((void**)arrayList)		// Warning free


#define ReturnArray_Alloc(type, array) {					\
const int sizeOfItem = sizeof(array[0]);					\
const size_t numItems = sizeof(array)/sizeOfItem;			\
return (type)pReturnArray(array, numItems, sizeOfItem );	\
}
Calculating the points like above using a set of geometry functions I wrote a week or 2 ago:

Code: Select all

void Circle_Set_Point_With_Center_Radius_Degrees (float *out_x, float *out_y, float center_x, float center_y, float radius, float degrees)
{
	const float radians	= DEGREES_TO_RADIANS(degrees);
	*out_x = cosf(radians) * radius + center_x;
	*out_y = sinf(radians) * radius + center_y;
}
Note: Above code reflects MH's philosophy about const over-kill. I just went crazy with const because DarkPlaces does, but thinking it through only pointers and weird datatypes should use const usually. Weird datatypes so a 3rd party can see that whatever this weird data type is, it isn't getting written. Well, arrays too.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: Image Manipulation

Post by Baker »

But there is another valid question. What good are platform neutral image manipulation functions without a platform neutral interface.

I think GTK looks ugly and all 1990s like Java's crappy looking interface. I think playing in some platform's "only me" sandbox is ... dumb ... even if you like the platform. The "my platform sandbox" where my platform might be Microsoft or Apple or X11 isn't the solution to the problem, it IS the problem.

But there are no solutions.

But I've been working on that one too. Dwelling on how "controls" and "forms" work on Windows and thinking about vb6 and such. And doing it possibly better.

Code: Select all

PROPERTY_LIST_START

PROPERTY_FIELD		(controltype,	controlType			);		// Intended location x1, y1 and x2, y2
PROPERTY_FIELD		(ScreenRect,	origin				);		// Intended location x1, y1 and x2, y2
PROPERTY_FIELD		(fbool,			hidden				);
PROPERTY_FIELD		(fbool,			notFocusable		);
PROPERTY_ARRAY		(char, 64,		name				);
PROPERTY_ARRAY		(char, 256,		text				);
PROPERTY_FIELD		(size_t,		textMaxBytes		);
PROPERTY_FIELD		(float,			value				);
PROPERTY_FIELD		(float,			valueMin			);
PROPERTY_FIELD		(float,			valueMax			);
PROPERTY_ARRAY		(char, 64,		bundleURL			);

PROPERTY_FIELD		(color4byte,	foregroundColor		);
PROPERTY_FIELD		(color4byte,	backgroundColor		);
PROPERTY_FIELD		(color4byte,	contentsForeColor	);
PROPERTY_FIELD		(color4byte,	contentsBackColor	);
PROPERTY_FIELD		(int,			borderWidth			);
PROPERTY_FIELD		(int,			tabIndex			);

PROPERTY_RUNTIME	(ScreenRect,	runtime_absOrigin				);	
PROPERTY_RUNTIME	(ScreenRect,	runtime_hotspot					);
PROPERTY_RUNTIME	(imageRGBA_t,	runtime_image					);	
PROPERTY_RUNTIME	(texture_t*,	runtime_textureBoss				);

PROPERTY_RUNTIME	(charset_t*,	runtime_charset					);	
PROPERTY_RUNTIME	(texture_t*,	runtime_textureBoss				);

PROPERTY_RUNTIME	(size_t,		runtime_textStrlength			);
PROPERTY_RUNTIME	(size_t,		runtime_textCursor				);
PROPERTY_RUNTIME	(size_t,		runtime_textSelectionStart		);
PROPERTY_RUNTIME	(size_t,		runtime_textSelectionLength		);
PROPERTY_RUNTIME	(size_t,		runtime_textFirstVisibleCol		);

PROPERTY_LIST_END
The above macros can be redefined 3 times recursively :D

Pass 1: Create struct ... goes like this ...

Code: Select all

#define PROPERTY_FIELD(datatype, propertyname)			datatype* propertyname; datatype _##propertyname
#define PROPERTY_ARRAY(datatype, size, propertyname)	datatype* propertyname; datatype _##propertyname[size]
#define PROPERTY_RUNTIME(datatype, propertyname)		datatype* propertyname; datatype _##propertyname
Pass 2: Actually generate property GET and SET. And READ and WRITE. If I have read and write, I can create controls via a "Quake console" with a command or write the "form" to file.

Code: Select all

#define PROPERTY_SYNTHESIZE(propertyname, datatype)									\
void Property_Set_##propertyname (exControl* myControl, datatype value);			\
																					\
void Property_Set_##propertyname (exControl* myControl, datatype value)				\
{																					\
	myControl->_##propertyname	= value;											\
	myControl->propertyname		= &myControl->_##propertyname;						\
}
Pass 3: Create a fixed array of values of string plus 2 functions. The 2 functions interpret a string based on datatype (one for read, one for write) and can check that the value makes any sense.

Then give each type of control a draw function, mouse/touch event function and key press function.

Let the "form" that holds all of these things know what field has "focus"

Code: Select all

// A collection of controls
typedef struct exForm_s
{
// Run time properties
	exControl			controls[256];		// A set of 256 max controls.  Form is control 0
	int					numControls;		// We might not use this for anything.
	
	exControl*			myself;				// This form as a control for others to inherit from where property isn't specified?
	exControl*			focus;				// NULL for none?
	exControl*			drawFirst;			// Linked list header.  Should we ever save to disk, save using this as the order.
} exForm;
And boom! At least for drawing: You have maybe 75% of vb6 form creation functionality, plus you can write it to file FAR better and even add controls in real time.

Mouse input: Going to have to plan that.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: Image Manipulation

Post by Baker »

I've got most of what vb6 does that matters written in about 5 files. More to do. Might take a few weeks for anything of interest to materialize from this due to lack of time.

But these 5 files are laughably short. Like "haha funny like a clown" short. A few functions of 10-12 lines here, a 6 line one there. And it can read/write properties into a nice and short text file that looks like this:

Code: Select all

controlType:Form
controlType:Rect origin:25,25,100,100 backgroundColor:#ffcc33
controlType:Rect origin:0,125,100,225 backgroundColor:#800000 foregroundColor:#ff0000
controlType:Rect origin:125,0,325,150 backgroundColor:#00ff00
Since this understands text, a new on-screen control could be created from, say, the console in Quake. And display the properties via a console command. The key was just writing 3 creative macros to reuse data: the macros automatically write property set/read/write functions based on data type, create a property name to property read/write function table lookup (so a text name can be associated with a text-input function).

Macros output stuff like

Code: Select all

typedef enum {DESIGN_TIME, RUN_TIME, } propavail;

typedef fbool (*property_read_t)(exControl*, const char*);
typedef fbool (*property_write_t)(exControl*, char*);

//	propertytable propertyTable [] = 
//	{
//	
//		{"controlType",	 Property_Read_controlType,	 Property_Write_controlType	 , DESIGN_TIME },	
//		{"origin",		 Property_Read_origin,		 Property_Write_origin		 , DESIGN_TIME },	
//		{"hidden",		 Property_Read_hidden,		 Property_Write_hidden		 , DESIGN_TIME },	
//		{"notFocusable", Property_Read_notFocusable, Property_Write_notFocusable , DESIGN_TIME },
but from a simple data source.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Post Reply