1 /* GNU Robbo
2 * Copyright (C) 2002-2010 The GNU Robbo Team (see AUTHORS).
3 *
4 * GNU Robbo is free software - you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * GNU Robbo is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the impled warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with GNU CC; see the file COPYING. If not, write to the
16 * Free Software Foundation, 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 *
19 */
20
21 #include "game.h"
22
23 /* The GNU Robbo Rectangular Object Engine
24 =======================================
25
26 The purpose of this engine is to manage a GUI and widget set
27 capable of assisting in the development of a level designer.
28 It's a cut down version of ENG, a project I've been working on
29 and only recently (2009-03-22) published on Sourceforge.
30
31 The main differences between this and ENG are :-
32 * No objects will be loaded from a file, only created in code
33 * There is no image subsystem although ROB_FreeObject will free attached images
34 * There is no actions subsystem as it already exists within GNU Robbo in a simpler form
35 * No screen or viewport system objects, just a screen sized canvas
36 * The sorted id array is dispensed with because there won't be many objects
37 * Only GNU Robbo developers will be creating objects, not users
38 * Much of the idiot-proof error checking is no longer necessary :)
39
40 */
41
42 /* Defines */
43 /*
44 #define DEBUG_ROB_OBJECTS
45 #define DEBUG_ROB_OBJECT_ZORDER
46 #define DEBUG_ROB_OBJECTS_ALL_DRAGGABLE
47 #define DEBUG_ROB_GET_VISIBILITY
48 #define DEBUG_ROB_GET_ENABILITY
49 #define DEBUG_ROB_EVENTS
50 #define DEBUG_ROB_PROGRESS_DUMP
51 */
52
53 #define ROB_MAX_OBJECTS 1000
54 #define ROB_FILE_LENGTH 256
55 #define ROB_ERROR_LENGTH 256
56
57 #define ROB_DIR "rob"
58 #define ROB_SPRITES "robsprites.bmp"
59
60 #define ROB_SPRITES_POINTER_XOFFSET 0
61 #define ROB_SPRITES_POINTER_W 13
62 #define ROB_SPRITES_POINTER_H 19
63 #define ROB_SPRITES_POINTER_SHADOW_XOFFSET 13
64 #define ROB_SPRITES_POINTER_SHADOW_ALPHA 50
65 #define ROB_SPRITES_POINTER_SHADOW_X 4
66 #define ROB_SPRITES_POINTER_SHADOW_Y 4
67 #define ROB_SPRITES_POINTER_SHADOW_W 13
68 #define ROB_SPRITES_POINTER_SHADOW_H 19
69
70 /* Variables */
71 ROB_OpEnv rob_op_env;
72 SDL_Surface *rob_blend_screen = NULL;
73 SDL_Surface *rob_sprites = NULL;
74 ROB_Object *rob_objects[ROB_MAX_OBJECTS];
75 ROB_Object *rob_lyr_root = NULL;
76 ROB_Object *rob_lyr_canvas = NULL;
77 ROB_Object *rob_rec_pointer = NULL;
78 ROB_Object *rob_oup = NULL;
79 ROB_Object *rob_pressed_object = NULL;
80 int rob_object_count = 0;
81 char rob_last_error[ROB_ERROR_LENGTH];
82
83 /* Function prototypes */
84 int ROB_SetObjectZOrder(ROB_Object *rob_object, int position, ROB_Object *target);
85 void ROB_FreeAllObjects(void);
86 int ROB_FillRectA(SDL_Surface *surface, SDL_Rect *dstrect, Uint32 colour, Uint8 alpha);
87 int ROB_GetCanvasOffset(ROB_Object *rob_object, int *cx, int *cy);
88 int ROB_GetVisibility(ROB_Object *rob_object);
89 int ROB_GetEnability(ROB_Object *rob_object);
90 int ROB_GetAlpha(ROB_Object *rob_object);
91 ROB_Object *ROB_GetObjectUnderObject(ROB_Object *rob_object, int hitpoint);
92 int ROB_FindAncestor(ROB_Object *rob_object, ROB_Object *target);
93 void ROB_ManagePointerInput(int pxu, int pyu);
94 int ROB_SendEvent(ROB_Event *rob_event);
95
96
97 /***************************************************************************
98 * Initialise *
99 ***************************************************************************/
100 /* On entry: op_env points to the operating environment data which is copied locally */
101
ROB_Init(ROB_OpEnv * op_env)102 void ROB_Init(ROB_OpEnv *op_env) {
103 SDL_Surface *unconverted, *converted;
104 ROB_Object rob_object;
105 char filename[256];
106
107 #ifdef DEBUG_ROB_PROGRESS_DUMP
108 printf("%s: Initialising\n", __func__);
109 #endif
110
111 /* Create a local copy of the passed op_env */
112 rob_op_env = *op_env;
113
114 /* Initialise some defaults */
115 rob_lyr_pointer = NULL;
116 rob_last_error[0] = 0;
117
118 /* Duplicate the screen surface for making alpha rectangles only */
119 rob_blend_screen = SDL_CreateRGBSurface(screen->flags | SDL_SRCALPHA, screen->w, screen->h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
120 if (rob_blend_screen == NULL) {
121 fprintf(stdout, "%s: Cannot create blend surface: %s", __func__, SDL_GetError());
122 exit(1);
123 }
124
125 /* Load the ROB system images */
126 strcpy(filename, PACKAGE_DATA_DIR "/" ROB_DIR "/");
127 strcat(filename, ROB_SPRITES);
128 /* Load the bitmap */
129 if ((unconverted = SDL_LoadBMP(filename)) == NULL) {
130 fprintf(stdout, "Cannot load bitmap: %s\n", filename);
131 exit(1);
132 }
133 /* Set the transparent colour */
134 if (SDL_SetColorKey(unconverted, SDL_SRCCOLORKEY, SDL_MapRGB(unconverted->format, 0xff, 0x00, 0xff)) < 0) {
135 fprintf(stdout, "Cannot set surface colour key: %s\n", SDL_GetError());
136 exit(1);
137 }
138 /* Convert the loaded surface to the same pixel format as the screen for fast blitting */
139 converted = SDL_DisplayFormat(unconverted);
140 SDL_FreeSurface(unconverted);
141 if (converted == NULL) {
142 fprintf(stdout, "Cannot create surface: %s\n", SDL_GetError());
143 exit(1);
144 }
145 rob_sprites = converted;
146
147 /* Create the system objects */
148 /* Create a root object */
149 if (ROB_SetObjectDefaults(&rob_object)) printf("%s: %s\n", __func__, ROB_GetError());
150 rob_object.id = ROB_LYR_ROOT ;
151 rob_object.pid = ROB_LYR_ROOT;
152 rob_object.visible = TRUE;
153 rob_object.enabled = TRUE;
154 rob_object.alpha = 255;
155 if (ROB_CreateObject(&rob_object)) printf("%s: %s\n", __func__, ROB_GetError());
156 /* Create a canvas object */
157 if (ROB_SetObjectDefaults(&rob_object)) printf("%s: %s\n", __func__, ROB_GetError());
158 rob_object.id = ROB_LYR_CANVAS;
159 rob_object.pid = ROB_LYR_ROOT;
160 rob_object.visible = TRUE;
161 rob_object.enabled = TRUE;
162 rob_object.alpha = 255;
163 rob_object.w = screen->w;
164 rob_object.h = screen->h;
165 if (ROB_CreateObject(&rob_object)) printf("%s: %s\n", __func__, ROB_GetError());
166 /* Create a pointer shadow */
167 if (ROB_SetObjectDefaults(&rob_object)) printf("%s: %s\n", __func__, ROB_GetError());
168 rob_object.id = ROB_REC_POINTER;
169 rob_object.pid = ROB_LYR_POINTER;
170 rob_object.alpha = ROB_SPRITES_POINTER_SHADOW_ALPHA;
171 rob_object.x = ROB_SPRITES_POINTER_SHADOW_X;
172 rob_object.y = ROB_SPRITES_POINTER_SHADOW_Y;
173 rob_object.w = ROB_SPRITES_POINTER_SHADOW_W;
174 rob_object.h = ROB_SPRITES_POINTER_SHADOW_H;
175 rob_object.img_surface = rob_sprites;
176 rob_object.img_x = ROB_SPRITES_POINTER_SHADOW_XOFFSET;
177 rob_object.img_y = 0;
178 rob_object.img_w = rob_object.w;
179 rob_object.img_h = rob_object.h;
180 if (ROB_CreateObject(&rob_object)) printf("%s: %s\n", __func__, ROB_GetError());
181 /* Create a pointer */
182 if (ROB_SetObjectDefaults(&rob_object)) printf("%s: %s\n", __func__, ROB_GetError());
183 rob_object.id = ROB_LYR_POINTER;
184 rob_object.pid = ROB_LYR_CANVAS;
185 rob_object.visible = FALSE;
186 rob_object.enabled = TRUE;
187 rob_object.alpha = 255;
188 rob_object.x = screen->w / 2;
189 rob_object.y = screen->h / 2;
190 rob_object.w = ROB_SPRITES_POINTER_W;
191 rob_object.h = ROB_SPRITES_POINTER_H;
192 rob_object.img_surface = rob_sprites;
193 rob_object.img_x = ROB_SPRITES_POINTER_XOFFSET;
194 rob_object.img_y = 0;
195 rob_object.img_w = rob_object.w;
196 rob_object.img_h = rob_object.h;
197 if (ROB_CreateObject(&rob_object)) printf("%s: %s\n", __func__, ROB_GetError());
198 #ifdef DEBUG_ROB_OBJECTS
199 printf("%s: rob_lyr_root=%p\n", __func__, rob_lyr_root);
200 printf("%s: rob_lyr_canvas=%p\n", __func__, rob_lyr_canvas);
201 printf("%s: rob_rec_pointer=%p\n", __func__, rob_rec_pointer);
202 printf("%s: rob_lyr_pointer=%p\n", __func__, rob_lyr_pointer);
203 #endif
204
205 /* Process the operating environment */
206 ROB_SetOpEnvEventProcessor(rob_op_env.event_processor);
207 ROB_SetOpEnvSystemPointer(rob_op_env.systempointer);
208 ROB_SetOpEnvPointer(rob_op_env.pointer, rob_op_env.pointer_mode);
209 }
210
211 /***************************************************************************
212 * Set Object ZOrder *
213 ***************************************************************************/
214 /* User objects must be above ROB_LYR_CANVAS and below ROB_REC_POINTER to
215 be accessible via the pointer. This function does not place any restrictions
216 on the destinaton of any objects.
217
218 Positions :-
219
220 ROB_ZORDER_ABOVE_ALL
221 --------------------
222 The object will be moved above the target and above all other objects who's
223 pob is also the target.
224 If the object is or results in being the target then it is not moved.
225
226 ROB_ZORDER_ABOVE
227 ----------------
228 The object will be moved above the target.
229 If the object is the target then it is moved above itself.
230
231 ROB_ZORDER_BELOW
232 ----------------
233 The object will be moved below the target.
234 If the object is the target then it is moved below itself */
235
236 /* On entry: object is the object to move
237 position is one of the zorder positions detailed above
238 target is the target object of the move
239 On exit: returns ROB_ERROR_NONE on success else
240 any one of the error codes in ROB_engine.h */
241
ROB_SetObjectZOrder(ROB_Object * rob_object,int position,ROB_Object * target)242 int ROB_SetObjectZOrder(ROB_Object *rob_object, int position, ROB_Object *target) {
243 int count, retval = ROB_ERROR_NONE;
244 int index = rob_object->zorder, targetindex = ROB_UNDEFINED, direction = 0;
245 ROB_Object *swap_object;
246
247 if (rob_object == NULL || sizeof(*rob_object) != sizeof(ROB_Object)) {
248 sprintf(rob_last_error, "%s: object is invalid", __func__);
249 retval = ROB_ERROR_INVALID_OBJECT;
250 } else if (target == NULL || sizeof(*target) != sizeof(ROB_Object)) {
251 sprintf(rob_last_error, "%s: target is invalid", __func__);
252 retval = ROB_ERROR_INVALID_TARGET_OBJECT;
253 } else {
254 /* Set the target index */
255 if (position == ROB_ZORDER_ABOVE_ALL) {
256 /* Find the topmost object equal to target or its pob is equal to target */
257 for (count = 0; count < rob_object_count; count++) {
258 if (rob_objects[count] == target || rob_objects[count]->pob == target) targetindex = count;
259 }
260 /* Make some positional adjustments to the target index */
261 if (targetindex == ROB_UNDEFINED) {
262 targetindex = rob_object->zorder; /* No seg faults please :) */
263 } else if (rob_object->zorder > targetindex) {
264 targetindex++;
265 }
266 } else if (position == ROB_ZORDER_ABOVE) {
267 /* The target index is the zorder within the target */
268 targetindex = target->zorder;
269 /* Make some positional adjustments to the target index */
270 if (rob_object->zorder == targetindex && targetindex < rob_object_count - 1) {
271 targetindex++;
272 } else if (rob_object->zorder > targetindex) {
273 targetindex++;
274 }
275 } else if (position == ROB_ZORDER_BELOW) {
276 /* The target index is the zorder within the target */
277 targetindex = target->zorder;
278 /* Make some positional adjustments to the target index */
279 if (rob_object->zorder == targetindex && targetindex > 0) {
280 targetindex--;
281 } else if (rob_object->zorder < targetindex) {
282 targetindex--;
283 }
284 }
285 /* Set move direction */
286 if (index < targetindex) {
287 direction = 1;
288 } else if (rob_object->zorder > targetindex) {
289 direction = -1;
290 }
291 #ifdef DEBUG_ROB_OBJECT_ZORDER
292 printf("%s: Moving id=%i zorder=%i targetindex=%i (rob_object_count=%i)\n", __func__, rob_object->id, rob_object->zorder, targetindex, rob_object_count);
293 #endif
294 while (index != targetindex) {
295 #ifdef DEBUG_ROB_OBJECT_ZORDER
296 printf(" id=%i pob=%p zorder=%i <--> id=%i pob=%p zorder=%i\n", rob_objects[index]->id, rob_objects[index]->pob, rob_objects[index]->zorder, rob_objects[index + direction]->id, rob_objects[index + direction]->pob, rob_objects[index + direction]->zorder);
297 #endif
298 swap_object = rob_objects[index];
299 rob_objects[index] = rob_objects[index + direction];
300 rob_objects[index]->zorder -= direction;
301 index += direction;
302 rob_objects[index] = swap_object;
303 rob_objects[index]->zorder += direction;
304 }
305 }
306
307 return retval;
308 }
309
310 /***************************************************************************
311 * Get Object *
312 ***************************************************************************/
313 /* On entry: id is the object id
314 On exit: returns a pointer to the object on success else NULL */
315
ROB_GetObject(int id)316 ROB_Object *ROB_GetObject(int id) {
317 int count;
318
319 /* Linear search for id */
320 for (count = 0; count < rob_object_count; count++) {
321 if (rob_objects[count]->id == id) return rob_objects[count];
322 }
323
324 return NULL;
325 }
326
327 /***************************************************************************
328 * Create Object *
329 ***************************************************************************/
330 /* This will create the object.
331 There may be existing objects within rob_objects whose pob is NULL because
332 their parent was recently freed or hasn't been created yet. This function
333 will attempt to fix these NULL pobs on introduction of this new object */
334
335 /* On exit: returns ROB_ERROR_NONE on success else
336 any one of the error codes in ROB_engine.h */
337
ROB_CreateObject(ROB_Object * rob_object)338 int ROB_CreateObject(ROB_Object *rob_object) {
339 int retval = ROB_ERROR_NONE, count;
340 ROB_Object *newobject;
341
342 if (rob_object == NULL || sizeof(*rob_object) != sizeof(ROB_Object)) {
343 sprintf(rob_last_error, "%s: object is invalid", __func__);
344 retval = ROB_ERROR_INVALID_OBJECT;
345 } else if (rob_object_count >= ROB_MAX_OBJECTS) {
346 sprintf(rob_last_error, "%s: Too many objects (max %i)", __func__, ROB_MAX_OBJECTS);
347 retval = ROB_ERROR_TOO_MANY_OBJECTS;
348 } else {
349 /* Check uniqueness of id */
350 for (count = 0; count < rob_object_count; count++) {
351 if (rob_object->id == rob_objects[count]->id) {
352 sprintf(rob_last_error, "%s: Invalid duplicate id property", __func__);
353 retval = ROB_ERROR_INVALID_OBJECT_ID;
354 break;
355 }
356 }
357 if (!retval) {
358 /* Allocate memory for the new object */
359 newobject = (ROB_Object*) malloc(sizeof(ROB_Object));
360 *newobject = *rob_object;
361 #ifdef DEBUG_ROB_OBJECTS_ALL_DRAGGABLE
362 if (newobject->draggable == FALSE) newobject->draggable = ROB_DRAG_ANYWHERE;
363 #endif
364 #ifdef DEBUG_ROB_OBJECTS
365 printf("*** Start %s ***\n", __func__);
366 printf("%s: Creating %p (%i)\n", __func__, newobject, newobject->id);
367 #endif
368 /* Store the object pointer in the array */
369 rob_objects[rob_object_count] = newobject;
370 /* Set the zorder */
371 newobject->zorder = rob_object_count;
372 /* Update the array element count now */
373 rob_object_count++;
374 /* Store pointers to system objects */
375 if (newobject->id == ROB_LYR_ROOT) {
376 rob_lyr_root = newobject;
377 } else if (newobject->id == ROB_LYR_CANVAS) {
378 rob_lyr_canvas = newobject;
379 } else if (newobject->id == ROB_REC_POINTER) {
380 rob_rec_pointer = newobject;
381 } else if (newobject->id == ROB_LYR_POINTER) {
382 rob_lyr_pointer = newobject;
383 }
384 /* Iterate through rob_objects and fix the pob */
385 for (count = 0; count < rob_object_count; count++) {
386 if (rob_objects[count]->pob == NULL) {
387 /* This may still result in a NULL pob if the parent never exists */
388 rob_objects[count]->pob = ROB_GetObject(rob_objects[count]->pid);
389 }
390 }
391 /* Maintain the highest zorder for the pointer and shadow */
392 if (rob_lyr_pointer != NULL && rob_rec_pointer != NULL) {
393 ROB_SetObjectZOrder(rob_lyr_pointer, ROB_ZORDER_ABOVE, newobject);
394 ROB_SetObjectZOrder(rob_rec_pointer, ROB_ZORDER_BELOW, rob_lyr_pointer);
395 }
396 #ifdef DEBUG_ROB_OBJECTS
397 printf("newobject :-\n");
398 printf("id=%i\n", newobject->id);
399 printf("pid=%i\n", newobject->pid);
400 printf("visible=%i\n", newobject->visible);
401 printf("enabled=%i\n", newobject->enabled);
402 printf("alpha=%i\n", newobject->alpha);
403 printf("alpha_over=%i\n", newobject->alpha_over);
404 printf("alpha_press=%i\n", newobject->alpha_press);
405 printf("bgcolour=%03X\n", newobject->bgcolour);
406 printf("bgcolour_over=%03X\n", newobject->bgcolour_over);
407 printf("bgcolour_press=%03X\n", newobject->bgcolour_press);
408 printf("x=%i\n", newobject->x);
409 printf("y=%i\n", newobject->y);
410 printf("w=%i\n", newobject->w);
411 printf("h=%i\n", newobject->h);
412 printf("img_surface=%p\n", newobject->img_surface);
413 printf("img_x=%i\n", newobject->img_x);
414 printf("img_y=%i\n", newobject->img_y);
415 printf("img_w=%i\n", newobject->img_w);
416 printf("img_h=%i\n", newobject->img_h);
417 printf("img_over_surface=%p\n", newobject->img_over_surface);
418 printf("img_over_x=%i\n", newobject->img_over_x);
419 printf("img_over_y=%i\n", newobject->img_over_y);
420 printf("img_over_w=%i\n", newobject->img_over_w);
421 printf("img_over_h=%i\n", newobject->img_over_h);
422 printf("img_press_surface=%p\n", newobject->img_press_surface);
423 printf("img_press_x=%i\n", newobject->img_press_x);
424 printf("img_press_y=%i\n", newobject->img_press_y);
425 printf("img_press_w=%i\n", newobject->img_press_w);
426 printf("img_press_h=%i\n", newobject->img_press_h);
427 printf("draggable=%i\n", newobject->draggable);
428 printf("drag_point=%i\n", newobject->drag_point);
429 printf("drag_granularity=%i\n", newobject->drag_granularity);
430 printf("zorder=%i\n", newobject->zorder);
431 printf("pob=%p\n", newobject->pob);
432 printf("*** Stop %s ***\n", __func__);
433 #endif
434 }
435 }
436
437 return retval;
438 }
439
440 /***************************************************************************
441 * Set Object Defaults *
442 ***************************************************************************/
443 /* On exit: returns ROB_ERROR_NONE on success else
444 any one of the error codes in ROB_engine.h */
445
ROB_SetObjectDefaults(ROB_Object * rob_object)446 int ROB_SetObjectDefaults(ROB_Object *rob_object) {
447 int retval = ROB_ERROR_NONE;
448
449 if (rob_object == NULL || sizeof(*rob_object) != sizeof(ROB_Object)) {
450 sprintf(rob_last_error, "%s: object is invalid", __func__);
451 retval = ROB_ERROR_INVALID_OBJECT;
452 } else {
453 rob_object->id = ROB_UNDEFINED;
454 rob_object->pid = ROB_LYR_CANVAS;
455 rob_object->visible = ROB_INHERITED;
456 rob_object->enabled = ROB_INHERITED;
457 rob_object->alpha = ROB_INHERITED;
458 rob_object->alpha_over = ROB_UNDEFINED;
459 rob_object->alpha_press = ROB_UNDEFINED;
460 rob_object->bgcolour = ROB_UNDEFINED;
461 rob_object->bgcolour_over = ROB_UNDEFINED;
462 rob_object->bgcolour_press = ROB_UNDEFINED;
463 rob_object->x = 0;
464 rob_object->y = 0;
465 rob_object->w = 0;
466 rob_object->h = 0;
467 rob_object->img_surface = NULL;
468 rob_object->img_x = ROB_UNDEFINED;
469 rob_object->img_y = ROB_UNDEFINED;
470 rob_object->img_w = ROB_UNDEFINED;
471 rob_object->img_h = ROB_UNDEFINED;
472 rob_object->img_over_surface = NULL;
473 rob_object->img_over_x = ROB_UNDEFINED;
474 rob_object->img_over_y = ROB_UNDEFINED;
475 rob_object->img_over_w = ROB_UNDEFINED;
476 rob_object->img_over_h = ROB_UNDEFINED;
477 rob_object->img_press_surface = NULL;
478 rob_object->img_press_x = ROB_UNDEFINED;
479 rob_object->img_press_y = ROB_UNDEFINED;
480 rob_object->img_press_w = ROB_UNDEFINED;
481 rob_object->img_press_h = ROB_UNDEFINED;
482 rob_object->draggable = FALSE;
483 rob_object->drag_point = ROB_DRAG_POINT_ANYWHERE;
484 rob_object->drag_granularity = 1;
485 rob_object->zorder = ROB_UNDEFINED;
486 rob_object->pob = NULL;
487 }
488
489 return retval;
490 }
491
492 /***************************************************************************
493 * Get Error *
494 ***************************************************************************/
495 /* On exit: returns a pointer to a string containing the last internal
496 error plus the contents of SDL_GetError if relevant */
497
ROB_GetError(void)498 char *ROB_GetError(void) {
499 static char last_error[ROB_ERROR_LENGTH];
500
501 strcpy (last_error, rob_last_error);
502 strcpy (rob_last_error, "");
503
504 return last_error;
505 }
506
507 /***************************************************************************
508 * Quit (ROB) *
509 ***************************************************************************/
510 /* On exit: returns ROB_ERROR_NONE on success else
511 any one of the error codes in ROB_engine.h */
512
ROB_Quit(void)513 int ROB_Quit(void) {
514 int retval = ROB_ERROR_NONE;
515
516 #ifdef DEBUG_ROB_PROGRESS_DUMP
517 printf("%s: Quitting\n", __func__);
518 #endif
519 ROB_FreeAllObjects();
520 if (rob_sprites) SDL_FreeSurface(rob_sprites);
521 if (rob_blend_screen) SDL_FreeSurface(rob_blend_screen);
522
523 return retval;
524 }
525
526 /***************************************************************************
527 * Free All Objects *
528 ***************************************************************************/
529 /* This mops-up any remaining objects before shutting down */
530
ROB_FreeAllObjects(void)531 void ROB_FreeAllObjects(void) {
532 int count;
533
534 if (rob_object_count > 0) {
535 #ifdef DEBUG_ROB_PROGRESS_DUMP
536 printf("%s: Freeing %i objects\n", __func__, rob_object_count);
537 #endif
538 /* Free all remaining objects (ignoring errors) */
539 for (count = rob_object_count - 1; count >= 0; count--) {
540 ROB_FreeObject(rob_objects[count], FALSE);
541 }
542 }
543 }
544
545 /***************************************************************************
546 * Free All Child Objects *
547 ***************************************************************************/
548 /* This frees all child objects of a parent if any exist. This can be viewed
549 as a way of freeing a group of objects that share a common parent */
550
551 /* On entry: pob is a pointer to a parent object
552 free_pob = TRUE to free the parent object also */
553 /* On exit: returns ROB_ERROR_NONE on success else
554 any one of the error codes in ROB_engine.h */
555
ROB_FreeAllChildObjects(ROB_Object * pob,int free_pob)556 int ROB_FreeAllChildObjects(ROB_Object *pob, int free_pob) {
557 int retval = ROB_ERROR_NONE, count, free_count = 0;
558
559 if (pob == NULL || sizeof(*pob) != sizeof(ROB_Object)) {
560 sprintf(rob_last_error, "%s: pob is invalid", __func__);
561 retval = ROB_ERROR_INVALID_OBJECT;
562 } else if (rob_object_count > 0) {
563 for (count = rob_object_count - 1; count >= 0; count--) {
564 if (rob_objects[count]->pob == pob) {
565 ROB_FreeObject(rob_objects[count], FALSE);
566 free_count++;
567 }
568 }
569 #ifdef DEBUG_ROB_PROGRESS_DUMP
570 printf("%s: Freeing %i objects", __func__, free_count);
571 if (free_pob) printf(" and parent id=%i", pob->id);
572 printf("\n");
573 #endif
574 if (free_pob) {
575 ROB_FreeObject(pob, FALSE);
576 }
577 }
578
579 return retval;
580 }
581
582 /***************************************************************************
583 * Free All Descendant Objects *
584 ***************************************************************************/
585 /* This frees all descendant objects of an ancestor if any exist. This can be
586 viewed as a way of freeing a group of objects that share a common ancestor */
587
588 /* On entry: ancestor is a pointer to an ancestor object
589 free_ancestor = TRUE to free the ancestor object also */
590 /* On exit: returns ROB_ERROR_NONE on success else
591 any one of the error codes in ROB_engine.h */
592
ROB_FreeAllDescendantObjects(ROB_Object * ancestor,int free_ancestor)593 int ROB_FreeAllDescendantObjects(ROB_Object *ancestor, int free_ancestor) {
594 int retval = ROB_ERROR_NONE, count, free_count = 0;
595
596 if (ancestor == NULL || sizeof(*ancestor) != sizeof(ROB_Object)) {
597 sprintf(rob_last_error, "%s: ancestor is invalid", __func__);
598 retval = ROB_ERROR_INVALID_OBJECT;
599 } else if (rob_object_count > 0) {
600 for (count = rob_object_count - 1; count >= 0; count--) {
601 if (rob_objects[count] != ancestor && ROB_FindAncestor(rob_objects[count], ancestor)) {
602 ROB_FreeObject(rob_objects[count], FALSE);
603 free_count++;
604 }
605 }
606 #ifdef DEBUG_ROB_PROGRESS_DUMP
607 printf("%s: Freeing %i objects", __func__, free_count);
608 if (free_ancestor) printf(" and ancestor id=%i", ancestor->id);
609 printf("\n");
610 #endif
611 if (free_ancestor) {
612 ROB_FreeObject(ancestor, FALSE);
613 }
614 }
615
616 return retval;
617 }
618
619 /***************************************************************************
620 * Free Object *
621 ***************************************************************************/
622 /* When freeing a parent object, the child objects will have their pob
623 nullified up until the point when (or if) the parent is reinstated.
624 Images declared within the object are freed and any objects that are
625 also referencing these images through img_surface and img_over_surface
626 will have these properties nullified */
627
628 /* On entry: object is the object to free
629 free_images_only = TRUE to free ONLY any declared images */
630 /* On exit: returns ROB_ERROR_NONE on success else
631 any one of the error codes in ROB_engine.h */
632
ROB_FreeObject(ROB_Object * rob_object,int free_images_only)633 int ROB_FreeObject(ROB_Object *rob_object, int free_images_only) {
634 int retval = ROB_ERROR_NONE, count, count2;
635 SDL_Surface *img_surface;
636
637 if (rob_object_count <= 0) {
638 sprintf(rob_last_error, "%s: There is no object to free", __func__);
639 retval = ROB_ERROR_INVALID_OBJECT;
640 } else if (rob_object == NULL || sizeof(*rob_object) != sizeof(ROB_Object)) {
641 sprintf(rob_last_error, "%s: object is invalid", __func__);
642 retval = ROB_ERROR_INVALID_OBJECT;
643 } else {
644 #ifdef DEBUG_ROB_OBJECTS
645 printf("%s: Freeing %p (%i)\n", __func__, rob_object, rob_object->id);
646 #endif
647 /* Free img_surface and img_over_surface if either are declared */
648 for (count = 0; count < 2; count++) {
649 if (count == 0) {
650 img_surface = rob_object->img_surface;
651 } else {
652 img_surface = rob_object->img_over_surface;
653 }
654 if (img_surface != NULL) {
655 /* Nullify all surface pointers within rob_objects that reference this surface */
656 for (count2 = 0; count2 < rob_object_count; count2++) {
657 if (rob_objects[count2]->img_surface == img_surface) {
658 rob_objects[count2]->img_surface = NULL;
659 }
660 if (rob_objects[count2]->img_over_surface == img_surface) {
661 rob_objects[count2]->img_over_surface = NULL;
662 }
663 }
664 /* Free the SDL surface but not rob_sprites or GNU Robbo images */
665 if (img_surface != rob_sprites &&
666 img_surface != wm_icon &&
667 img_surface != icons &&
668 img_surface != ciphers &&
669 img_surface != alpha &&
670 img_surface != bgrnd &&
671 img_surface != k_icons) {
672 SDL_FreeSurface(img_surface);
673 }
674 }
675 }
676 if (!free_images_only) {
677 /* If the current object is the parent to other objects then nullify their pob */
678 for (count = 0; count < rob_object_count; count++) {
679 if (rob_objects[count]->pob == rob_object) rob_objects[count]->pob = NULL;
680 }
681 /* If anything is above the current object then move it down the array */
682 for (count = rob_object->zorder; count < rob_object_count - 1; count++) {
683 rob_objects[count] = rob_objects[count + 1];
684 rob_objects[count]->zorder--;
685 }
686 /* Nullify rob_oup if it's the same object */
687 if (rob_oup == rob_object) rob_oup = NULL;
688
689 /* Nullify rob_pressed_object if it's the same object */
690 if (rob_pressed_object == rob_object) rob_pressed_object = NULL;
691
692 /* Free the memory and update the array element count now */
693 free(rob_object);
694 rob_object_count--;
695 }
696 }
697
698 return retval;
699 }
700
701 /***************************************************************************
702 * Render Objects *
703 ***************************************************************************/
704 /* On exit: returns ROB_ERROR_NONE on success else
705 any one of the error codes in ROB_engine.h */
706
ROB_RenderObjects(void)707 int ROB_RenderObjects(void) {
708 int cx, cy, ix = 0, iy = 0, iw = 0, ih = 0, alpha;
709 int overeventfound, presseventfound, use_rleaccel = 0;
710 int count, retval = ROB_ERROR_NONE;
711 SDL_Surface *img_surface = NULL;
712 SDL_Rect srcrect, dstrect;
713 Uint32 bgcolour = 0;
714
715 /* Iterate through the objects */
716 for (count = 0; count < rob_object_count; count++) {
717 /* Get the object's visibility */
718 if (ROB_GetVisibility(rob_objects[count])) {
719
720 /* Is there an over event waiting for this object? */
721 overeventfound = presseventfound = FALSE;
722 if (rob_objects[count] == rob_oup && ROB_GetEnability(rob_objects[count])) {
723 overeventfound = TRUE;
724 /* Is there a press event waiting for this object? */
725 if (rob_objects[count] == rob_pressed_object) presseventfound = TRUE;
726 }
727
728 /* Get object's canvas offset */
729 ROB_GetCanvasOffset(rob_objects[count], &cx, &cy);
730
731 /* Get object's alpha and alpha_{over|press} */
732 alpha = ROB_GetAlpha(rob_objects[count]);
733 if (overeventfound && rob_objects[count]->alpha_over != ROB_UNDEFINED)
734 alpha = rob_objects[count]->alpha_over;
735 if (presseventfound && rob_objects[count]->alpha_press != ROB_UNDEFINED)
736 alpha = rob_objects[count]->alpha_press;
737
738 /* Get object's bgcolour and bgcolour_{over|press} */
739 bgcolour = rob_objects[count]->bgcolour;
740 if (overeventfound && rob_objects[count]->bgcolour_over != ROB_UNDEFINED)
741 bgcolour = rob_objects[count]->bgcolour_over;
742 if (presseventfound && rob_objects[count]->bgcolour_press != ROB_UNDEFINED)
743 bgcolour = rob_objects[count]->bgcolour_press;
744
745 /* Get object's img_{over_|press_}surface */
746 img_surface = rob_objects[count]->img_surface;
747 ix = rob_objects[count]->img_x; iy = rob_objects[count]->img_y;
748 iw = rob_objects[count]->img_w; ih = rob_objects[count]->img_h;
749 if (overeventfound && rob_objects[count]->img_over_surface != NULL) {
750 img_surface = rob_objects[count]->img_over_surface;
751 ix = rob_objects[count]->img_over_x; iy = rob_objects[count]->img_over_y;
752 iw = rob_objects[count]->img_over_w; ih = rob_objects[count]->img_over_h;
753 }
754 if (presseventfound && rob_objects[count]->img_press_surface != NULL) {
755 img_surface = rob_objects[count]->img_press_surface;
756 ix = rob_objects[count]->img_press_x; iy = rob_objects[count]->img_press_y;
757 iw = rob_objects[count]->img_press_w; ih = rob_objects[count]->img_press_h;
758 }
759
760 /** Is there a colour to fill? */
761 if (bgcolour != ROB_UNDEFINED) {
762 bgcolour = SDL_MapRGB(screen->format, bgcolour >> 16 & 0xff,
763 bgcolour >> 8 & 0xff, bgcolour & 0xff);
764 if (alpha == 255) {
765 /* Fill rectangle */
766 dstrect.x = cx; dstrect.y = cy;
767 dstrect.w = rob_objects[count]->w; dstrect.h = rob_objects[count]->h;
768 if ((SDL_FillRect(screen, &dstrect, bgcolour)) < 0) {
769 sprintf(rob_last_error, "%s: Cannot fill surface: %s", __func__, SDL_GetError());
770 retval = ROB_ERROR_CANNOT_FILL_SURFACE;
771 break;
772 }
773 } else {
774 /* Fill rectangle */
775 dstrect.x = cx; dstrect.y = cy;
776 dstrect.w = rob_objects[count]->w; dstrect.h = rob_objects[count]->h;
777 retval = ROB_FillRectA(screen, &dstrect, bgcolour, alpha);
778 if (retval) break;
779 }
780 }
781
782 /** Is there an image to attach? */
783 if (img_surface != NULL) {
784 /* If image region is unused then use entire image */
785 if (ix == ROB_UNDEFINED && iy == ROB_UNDEFINED &&
786 iw == ROB_UNDEFINED && ih == ROB_UNDEFINED) {
787 ix = 0; iy = 0; iw = img_surface->w; ih = img_surface->h;
788 }
789 if (alpha != 255) {
790 /* Record surface's use of SDL_RLEACCEL.
791 Because the surface is not compressed until the first blit,
792 SDL_RLEACCELOK must be checked for too, I imagine as compression is pending */
793 if (img_surface->flags & (SDL_RLEACCEL | SDL_RLEACCELOK)) use_rleaccel = SDL_RLEACCEL;
794 /* Set the image surface alpha. */
795 /* Note that this removes SDL_RLEACCEL because using it with alpha
796 is very very slow; it's restored at the end of the function */
797 if ((SDL_SetAlpha(img_surface, SDL_SRCALPHA, alpha)) < 0) {
798 sprintf(rob_last_error, "%s: Cannot set surface alpha: %s", __func__, SDL_GetError());
799 retval = ROB_ERROR_CANNOT_SET_SURFACE_ALPHA;
800 break;
801 }
802 }
803 srcrect.x = ix; srcrect.y = iy; srcrect.w = iw; srcrect.h = ih;
804 dstrect.x = cx; dstrect.y = cy; dstrect.w = rob_objects[count]->w; dstrect.h = rob_objects[count]->h;
805 /* Blit surface */
806 if ((SDL_BlitSurface(img_surface, &srcrect, screen, &dstrect)) < 0) {
807 sprintf(rob_last_error, "%s: Cannot blit surface: %s", __func__, SDL_GetError());
808 retval = ROB_ERROR_CANNOT_BLIT_SURFACE;
809 break;
810 }
811 if (alpha != 255) {
812 /* Disable the image surface alpha and restore SDL_RLEACCEL if set.
813 Note that officially NOT passing the SDL_SRCALPHA flag disables
814 alpha blits from this surface but then it's not possible to reenable
815 SDL_RLEACCEL, so I simply set the alpha value to SDL_ALPHA_OPAQUE
816 (255) which achieves the same result. */
817 if ((SDL_SetAlpha(img_surface, SDL_SRCALPHA | use_rleaccel, 255)) < 0) {
818 sprintf(rob_last_error, "%s: Cannot set surface alpha: %s", __func__, SDL_GetError());
819 retval = ROB_ERROR_CANNOT_SET_SURFACE_ALPHA;
820 break;
821 }
822 }
823 }
824 }
825 }
826
827 return retval;
828 }
829
830 /***************************************************************************
831 * FillRectA *
832 ***************************************************************************/
833 /* SDL_BlitSurface alpha blends, so an alpha rectangle first needs to become
834 a surface with per-surface-alpha set and then blitted to the screen */
835
836 /* On exit: returns ROB_ERROR_NONE on success else
837 any one of the error codes in ROB_engine.h */
838
ROB_FillRectA(SDL_Surface * surface,SDL_Rect * dstrect,Uint32 colour,Uint8 alpha)839 int ROB_FillRectA(SDL_Surface *surface, SDL_Rect *dstrect, Uint32 colour, Uint8 alpha) {
840 int retval = ROB_ERROR_NONE;
841
842 /* Set the blend surface alpha */
843 if ((SDL_SetAlpha(rob_blend_screen, SDL_SRCALPHA, alpha)) < 0) {
844 sprintf(rob_last_error, "%s: Cannot set surface alpha: %s", __func__, SDL_GetError());
845 retval = ROB_ERROR_CANNOT_SET_SURFACE_ALPHA;
846 }
847 if (!retval) {
848 /* Fill rectangle */
849 if ((SDL_FillRect(rob_blend_screen, dstrect, colour)) < 0) {
850 sprintf(rob_last_error, "%s: Cannot fill surface: %s", __func__, SDL_GetError());
851 retval = ROB_ERROR_CANNOT_FILL_SURFACE;
852 }
853 }
854 if (!retval) {
855 /* Blit surface */
856 if ((SDL_BlitSurface(rob_blend_screen, dstrect, surface, dstrect)) < 0) {
857 sprintf(rob_last_error, "%s: Cannot blit surface: %s", __func__, SDL_GetError());
858 retval = ROB_ERROR_CANNOT_BLIT_SURFACE;
859 }
860 }
861
862 return retval;
863 }
864
865 /***************************************************************************
866 * Get Canvas Offset *
867 ***************************************************************************/
868 /* This gets an object's canvas offset.
869 If a NULL pob is found then it will be interpreted as rob_lyr_canvas */
870
ROB_GetCanvasOffset(ROB_Object * rob_object,int * cx,int * cy)871 int ROB_GetCanvasOffset(ROB_Object *rob_object, int *cx, int *cy) {
872 int retval = ROB_ERROR_NONE;
873
874 if (rob_object == NULL || sizeof(*rob_object) != sizeof(ROB_Object)) {
875 sprintf(rob_last_error, "%s: object is invalid", __func__);
876 retval = ROB_ERROR_INVALID_OBJECT;
877 } else {
878 *cx = rob_object->x;
879 *cy = rob_object->y;
880 while (rob_object != rob_lyr_canvas && rob_object != rob_lyr_root) {
881 if (rob_object->pob == NULL) {
882 rob_object = rob_lyr_canvas;
883 } else {
884 rob_object = rob_object->pob;
885 }
886 *cx += rob_object->x;
887 *cy += rob_object->y;
888 }
889 }
890
891 return retval;
892 }
893
894 /***************************************************************************
895 * Get Visibility *
896 ***************************************************************************/
897 /* This gets an object's visibility.
898 If a NULL pob is found then it will be interpreted as rob_lyr_canvas */
899
900 /* On exit: returns TRUE or FALSE */
901
ROB_GetVisibility(ROB_Object * rob_object)902 int ROB_GetVisibility(ROB_Object *rob_object) {
903
904 if (rob_object == NULL || sizeof(*rob_object) != sizeof(ROB_Object)) {
905 sprintf(rob_last_error, "%s: object is invalid", __func__);
906 return TRUE; /* If NULL object this stops segfaults */
907 } else {
908 #ifdef DEBUG_ROB_GET_VISIBILITY
909 printf("\n%s: Visibility for object %i\n", __func__, rob_object->id);
910 printf("%s: id=%i pob=%p visible=%i\n", __func__, rob_object->id, rob_object->pob, rob_object->visible);
911 #endif
912 while (rob_object->visible == ROB_INHERITED) {
913 if (rob_object == rob_lyr_root || rob_object == rob_lyr_canvas) {
914 break;
915 } else {
916 if (rob_object->pob == NULL) {
917 rob_object = rob_lyr_canvas;
918 } else {
919 rob_object = rob_object->pob;
920 }
921 }
922 #ifdef DEBUG_ROB_GET_VISIBILITY
923 printf("%s: id=%i pob=%p visible=%i\n", __func__, rob_object->id, rob_object->pob, rob_object->visible);
924 #endif
925 }
926 }
927
928 /* Something valid must be returned and this may not be the
929 case if the user has been fiddling with the system objects */
930 if (rob_object->visible < 0 || rob_object->visible > 1) {
931 return TRUE;
932 } else {
933 return rob_object->visible;
934 }
935 }
936
937 /***************************************************************************
938 * Get Enability *
939 ***************************************************************************/
940 /* This gets an object's enability.
941 If a NULL pob is found then it will be interpreted as rob_lyr_canvas */
942
943 /* On exit: returns TRUE or FALSE */
944
ROB_GetEnability(ROB_Object * rob_object)945 int ROB_GetEnability(ROB_Object *rob_object) {
946
947 if (rob_object == NULL || sizeof(*rob_object) != sizeof(ROB_Object)) {
948 sprintf(rob_last_error, "%s: object is invalid", __func__);
949 return TRUE; /* If NULL object this stops segfaults */
950 } else {
951 #ifdef DEBUG_ROB_GET_ENABILITY
952 printf("\n%s: Enability for object %i\n", __func__, rob_object->id);
953 printf("%s: id=%i pob=%p enabled=%i\n", __func__, rob_object->id, rob_object->pob, rob_object->enabled);
954 #endif
955 while (rob_object->enabled == ROB_INHERITED) {
956 if (rob_object == rob_lyr_root || rob_object == rob_lyr_canvas) {
957 break;
958 } else {
959 if (rob_object->pob == NULL) {
960 rob_object = rob_lyr_canvas;
961 } else {
962 rob_object = rob_object->pob;
963 }
964 }
965 #ifdef DEBUG_ROB_GET_ENABILITY
966 printf("%s: id=%i pob=%p enabled=%i\n", __func__, rob_object->id, rob_object->pob, rob_object->enabled);
967 #endif
968 }
969 }
970
971 /* Something valid must be returned and this may not be the
972 case if the user has been fiddling with the system objects */
973 if (rob_object->enabled < 0 || rob_object->enabled > 1) {
974 return TRUE;
975 } else {
976 return rob_object->enabled;
977 }
978 }
979
980 /***************************************************************************
981 * Get Alpha *
982 ***************************************************************************/
983 /* This gets an object's alpha.
984 If a NULL pob is found then it will be interpreted as rob_lyr_canvas */
985
986 /* On exit: returns 0 to 255 */
987
ROB_GetAlpha(ROB_Object * rob_object)988 int ROB_GetAlpha(ROB_Object *rob_object) {
989
990 if (rob_object == NULL || sizeof(*rob_object) != sizeof(ROB_Object)) {
991 sprintf(rob_last_error, "%s: object is invalid", __func__);
992 return SDL_ALPHA_OPAQUE; /* If NULL object this stops segfaults */
993 } else {
994 while (rob_object->alpha == ROB_INHERITED) {
995 if (rob_object == rob_lyr_root || rob_object == rob_lyr_canvas) {
996 break;
997 } else {
998 if (rob_object->pob == NULL) {
999 rob_object = rob_lyr_canvas;
1000 } else {
1001 rob_object = rob_object->pob;
1002 }
1003 }
1004 }
1005 }
1006
1007 /* Something valid must be returned and this may not be the
1008 case if the user has been fiddling with the system objects */
1009 if (rob_object->alpha < 0 || rob_object->alpha > SDL_ALPHA_OPAQUE) {
1010 return SDL_ALPHA_OPAQUE;
1011 } else {
1012 return rob_object->alpha;
1013 }
1014 }
1015
1016 /***************************************************************************
1017 * Get Object Under Object *
1018 ***************************************************************************/
1019 /* On exit: returns a pointer to the visible object under object on success else NULL */
1020
ROB_GetObjectUnderObject(ROB_Object * rob_object,int hitpoint)1021 ROB_Object *ROB_GetObjectUnderObject(ROB_Object *rob_object, int hitpoint) {
1022 int count, cx, cy, cx2, cy2;
1023
1024 if (rob_object == NULL || sizeof(*rob_object) != sizeof(ROB_Object)) {
1025 sprintf(rob_last_error, "%s: object is invalid", __func__);
1026 } else if (hitpoint != ROB_HIT_POINT_TOP_LEFT && hitpoint != ROB_HIT_POINT_CENTRE) {
1027 sprintf(rob_last_error, "%s: hitpoint is invalid", __func__);
1028 } else {
1029 /* Get hit point of source object */
1030 ROB_GetCanvasOffset(rob_object, &cx, &cy);
1031 if (hitpoint == ROB_HIT_POINT_TOP_LEFT) {
1032 /* cx and cy are ok */
1033 } else if (hitpoint == ROB_HIT_POINT_CENTRE) {
1034 cx += rob_object->w / 2;
1035 cy += rob_object->h / 2;
1036 }
1037 for (count = rob_object_count - 1; count >= 0; count--) {
1038 if (ROB_GetVisibility(rob_objects[count]) && count < rob_object->zorder) {
1039 ROB_GetCanvasOffset(rob_objects[count], &cx2, &cy2);
1040 if (cx >= cx2 && cx < cx2 + rob_objects[count]->w && cy >= cy2 && cy < cy2 + rob_objects[count]->h) {
1041 return rob_objects[count];
1042 }
1043 }
1044 }
1045 }
1046
1047 return NULL;
1048 }
1049
1050 /***************************************************************************
1051 * Find Ancestor *
1052 ***************************************************************************/
1053 /* This traces back from (and including) an object looking for a
1054 particular ancestor.
1055 If a NULL pob is found then it will be interpreted as rob_lyr_canvas */
1056
1057 /* On exit: returns TRUE if found else FALSE */
1058
ROB_FindAncestor(ROB_Object * rob_object,ROB_Object * target)1059 int ROB_FindAncestor(ROB_Object *rob_object, ROB_Object *target) {
1060
1061 if (rob_object == NULL || sizeof(*rob_object) != sizeof(ROB_Object)) {
1062 sprintf(rob_last_error, "%s: object is invalid", __func__);
1063 } else if (target == NULL || sizeof(*target) != sizeof(ROB_Object)) {
1064 sprintf(rob_last_error, "%s: target is invalid", __func__);
1065 } else {
1066 #ifdef DEBUG_ROB_FIND_ANCESTOR
1067 printf("\n%s: Looking for object %i's ancestor %i\n", __func__, rob_object->id, target->id);
1068 printf("%s: id=%i pob=%p\n", __func__, rob_object->id, rob_object->pob);
1069 #endif
1070 while (rob_object != target) {
1071 if (rob_object == rob_lyr_root || rob_object == rob_lyr_canvas) {
1072 return FALSE;
1073 } else {
1074 if (rob_object->pob == NULL) {
1075 rob_object = rob_lyr_canvas;
1076 } else {
1077 rob_object = rob_object->pob;
1078 }
1079 }
1080 #ifdef DEBUG_ROB_FIND_ANCESTOR
1081 printf("%s: id=%i pob=%p\n", __func__, rob_object->id, rob_object->pob);
1082 #endif
1083 }
1084 }
1085
1086 return TRUE;
1087 }
1088
1089 /***************************************************************************
1090 * Generate Events *
1091 ***************************************************************************/
1092
ROB_GenerateEvents(int * actionid)1093 void ROB_GenerateEvents(int *actionid) {
1094 static int last_pointer_x = 0, last_pointer_y = 0;
1095 static int press_point_x = 0, press_point_y = 0;
1096 int mx, my, px, py, pxu = 0, pyu = 0;
1097 ROB_Object *new_oup, *pob;
1098 ROB_Event rob_event;
1099
1100 if (rob_op_env.pointer_mode == ROB_POINTER_MODE_OFF) {
1101 rob_oup = rob_lyr_root;
1102 } else {
1103 /* Get or set the object currently under the pointer. If an object is currently
1104 being pressed and it's enabled and draggable then it is attached to the pointer */
1105 if (rob_pressed_object != NULL && ROB_GetEnability(rob_pressed_object) && rob_pressed_object->draggable) {
1106 /* Force it as rob_oup to prevent dragging-off through latency */
1107 rob_oup = rob_pressed_object;
1108 ROB_GetCanvasOffset(rob_oup->pob, &px, &py);
1109 /* Attach the object to the pointer */
1110 ROB_GetCanvasOffset(rob_lyr_pointer, &mx, &my);
1111 rob_oup->x = mx - px - press_point_x;
1112 rob_oup->y = my - py - press_point_y;
1113 /* Adjust x/y for the granularity: n = n + (n % g) / (g / 2) * g - (n % g) */
1114 if (rob_oup->drag_granularity > 1) {
1115 rob_oup->x += rob_oup->x % rob_oup->drag_granularity / (rob_oup->drag_granularity / 2) * rob_oup->drag_granularity - rob_oup->x % rob_oup->drag_granularity;
1116 rob_oup->y += rob_oup->y % rob_oup->drag_granularity / (rob_oup->drag_granularity / 2) * rob_oup->drag_granularity - rob_oup->y % rob_oup->drag_granularity;
1117 }
1118 /* Is dragging restricted in any way? */
1119 if (rob_oup->draggable == ROB_DRAG_RESTRICT_TO_PARENT || rob_oup->draggable == ROB_DRAG_RESTRICT_TO_PARENT_ORIGIN) {
1120 pob = rob_oup->pob;
1121 if (rob_oup->draggable == ROB_DRAG_RESTRICT_TO_PARENT) {
1122 if (rob_oup->x + rob_oup->w > pob->w) rob_oup->x = pob->w - rob_oup->w;
1123 if (rob_oup->y + rob_oup->h > pob->h) rob_oup->y = pob->h - rob_oup->h;
1124 }
1125 if (rob_oup->x < 0) rob_oup->x = 0;
1126 if (rob_oup->y < 0) rob_oup->y = 0;
1127 }
1128 } else {
1129 new_oup = ROB_GetObjectUnderObject(rob_lyr_pointer, ROB_HIT_POINT_TOP_LEFT);
1130 /* rob_oup could be NULL here because it may have been a freed object but
1131 new_oup will most definitely contain at least a system object */
1132 if (rob_oup != new_oup) {
1133 /* Send one out event if the object is not NULL and enabled */
1134 if (rob_oup != NULL && ROB_GetEnability(rob_oup)) {
1135 rob_event.rob_object = rob_oup; rob_event.klasse = ROB_EVENT_OUT; ROB_SendEvent(&rob_event);
1136 }
1137 rob_oup = new_oup;
1138 /* Send one over event if the object is enabled */
1139 if (ROB_GetEnability(rob_oup)) {
1140 rob_event.rob_object = rob_oup; rob_event.klasse = ROB_EVENT_OVER; ROB_SendEvent(&rob_event);
1141 }
1142 }
1143 ROB_GetCanvasOffset(rob_oup->pob, &px, &py);
1144 }
1145 /* Detect dragging of the pointer across enabled objects */
1146 if (rob_pressed_object != NULL && rob_pressed_object == rob_oup && ROB_GetEnability(rob_oup)) {
1147 if (last_pointer_x != rob_lyr_pointer->x || last_pointer_y != rob_lyr_pointer->y) {
1148 rob_event.rob_object = rob_oup; rob_event.klasse = ROB_EVENT_DRAG; ROB_SendEvent(&rob_event);
1149 }
1150 }
1151 /* Record current pointer offsets for later comparison */
1152 last_pointer_x = rob_lyr_pointer->x;
1153 last_pointer_y = rob_lyr_pointer->y;
1154
1155 /* Process any reported action */
1156 if (*actionid != ROB_UNDEFINED) {
1157 switch (*actionid) {
1158 case ACTION_UP:
1159 if (rob_op_env.pointer_mode == ROB_POINTER_MODE_SIMULATED) {
1160 pyu = -1;
1161 }
1162 break;
1163 case ACTION_UP_RIGHT:
1164 if (rob_op_env.pointer_mode == ROB_POINTER_MODE_SIMULATED) {
1165 pyu = -1; pxu = 1;
1166 }
1167 break;
1168 case ACTION_RIGHT:
1169 if (rob_op_env.pointer_mode == ROB_POINTER_MODE_SIMULATED) {
1170 pxu = 1;
1171 }
1172 break;
1173 case ACTION_DOWN_RIGHT:
1174 if (rob_op_env.pointer_mode == ROB_POINTER_MODE_SIMULATED) {
1175 pyu = 1; pxu = 1;
1176 }
1177 break;
1178 case ACTION_DOWN:
1179 if (rob_op_env.pointer_mode == ROB_POINTER_MODE_SIMULATED) {
1180 pyu = 1;
1181 }
1182 break;
1183 case ACTION_DOWN_LEFT:
1184 if (rob_op_env.pointer_mode == ROB_POINTER_MODE_SIMULATED) {
1185 pyu = 1; pxu = -1;
1186 }
1187 break;
1188 case ACTION_LEFT:
1189 if (rob_op_env.pointer_mode == ROB_POINTER_MODE_SIMULATED) {
1190 pxu = -1;
1191 }
1192 break;
1193 case ACTION_UP_LEFT:
1194 if (rob_op_env.pointer_mode == ROB_POINTER_MODE_SIMULATED) {
1195 pyu = -1; pxu = -1;
1196 }
1197 break;
1198 case ACTION_SELECT:
1199 if (rob_op_env.pointer_mode == ROB_POINTER_MODE_PHYSICAL) break;
1200 case ACTION_PRIMARY_CLICK:
1201 if (rob_pressed_object == NULL) {
1202 rob_pressed_object = rob_oup;
1203 /* Only generate events for enabled objects */
1204 if (ROB_GetEnability(rob_oup)) {
1205 rob_event.rob_object = rob_oup; rob_event.klasse = ROB_EVENT_PRESS; ROB_SendEvent(&rob_event);
1206 rob_event.rob_object = rob_oup; rob_event.klasse = ROB_EVENT_SELECT; ROB_SendEvent(&rob_event);
1207 /* For draggable [enabled] objects, calculate the drag points */
1208 if (rob_oup->draggable) {
1209 /* Get the current pointer coordinates */
1210 ROB_GetCanvasOffset(rob_lyr_pointer, &mx, &my);
1211 if (rob_oup->drag_point == ROB_DRAG_POINT_ANYWHERE) {
1212 press_point_x = mx - px - rob_oup->x;
1213 press_point_y = my - py - rob_oup->y;
1214 } else if (rob_oup->drag_point == ROB_DRAG_POINT_MIDDLE) {
1215 press_point_x = rob_oup->w / 2;
1216 press_point_y = rob_oup->h / 2;
1217 }
1218 }
1219 }
1220 } else { /* Something is already being pressed */
1221 /* Only generate events for enabled objects */
1222 if (rob_pressed_object == rob_oup && ROB_GetEnability(rob_oup)) {
1223 rob_event.rob_object = rob_oup; rob_event.klasse = ROB_EVENT_SELECT; ROB_SendEvent(&rob_event);
1224 }
1225 }
1226 break;
1227 case ACTION_SELECT | 0x80:
1228 if (rob_op_env.pointer_mode == ROB_POINTER_MODE_PHYSICAL) break;
1229 case ACTION_PRIMARY_CLICK | 0x80:
1230 if (rob_pressed_object != NULL) {
1231 if (rob_pressed_object == rob_oup) {
1232 /* Only generate events for enabled objects */
1233 if (ROB_GetEnability(rob_oup)) {
1234 rob_event.rob_object = rob_oup; rob_event.klasse = ROB_EVENT_CLICK; ROB_SendEvent(&rob_event);
1235 }
1236 } else {
1237 /* Only generate events for enabled objects */
1238 if (ROB_GetEnability(rob_pressed_object)) {
1239 rob_event.rob_object = rob_oup; rob_event.klasse = ROB_EVENT_RELEASE; ROB_SendEvent(&rob_event);
1240 }
1241 }
1242 }
1243 rob_pressed_object = NULL;
1244 break;
1245 }
1246 /* Manage pointer input if required */
1247 if (rob_op_env.pointer_mode == ROB_POINTER_MODE_SIMULATED) ROB_ManagePointerInput(pxu, pyu);
1248 }
1249 }
1250
1251 }
1252
1253 /***************************************************************************
1254 * Manage Pointer Input *
1255 ***************************************************************************/
1256
ROB_ManagePointerInput(int pxu,int pyu)1257 void ROB_ManagePointerInput(int pxu, int pyu) {
1258 static int lastpxu = 0, lastpyu = 0, unitcount = 0;
1259 int xmov, ymov;
1260
1261 /* Is the x or y unit the same as last time? */
1262 if ((pxu != 0 && pxu == lastpxu) || (pyu != 0 && pyu == lastpyu)) {
1263 unitcount++;
1264 /* If the count reaches a threshold then change gear */
1265 if (unitcount < rob_op_env.pointer_move_unit_threshold) {
1266 xmov = pxu * rob_op_env.pointer_move_unit_low;
1267 ymov = pyu * rob_op_env.pointer_move_unit_low;
1268 } else {
1269 xmov = pxu * rob_op_env.pointer_move_unit_high;
1270 ymov = pyu * rob_op_env.pointer_move_unit_high;
1271 }
1272 } else {
1273 unitcount = 0;
1274 xmov = pxu * rob_op_env.pointer_move_unit_low;
1275 ymov = pyu * rob_op_env.pointer_move_unit_low;
1276 }
1277 lastpxu = pxu; lastpyu = pyu;
1278
1279 /* Now move the pointer */
1280 rob_lyr_pointer->x += xmov;
1281 rob_lyr_pointer->y += ymov;
1282
1283 /* Keep it within the bounds of the screen */
1284 if (rob_lyr_pointer->x < 0) {
1285 rob_lyr_pointer->x = 0;
1286 } else if (rob_lyr_pointer->x > screen->w - 1) {
1287 rob_lyr_pointer->x = screen->w - 1;
1288 }
1289 if (rob_lyr_pointer->y < 0) {
1290 rob_lyr_pointer->y = 0;
1291 } else if (rob_lyr_pointer->y > screen->h - 1) {
1292 rob_lyr_pointer->y = screen->h - 1;
1293 }
1294
1295 }
1296
1297 /***************************************************************************
1298 * Send Event *
1299 ***************************************************************************/
1300 /* On exit: returns ROB_ERROR_NONE on success else
1301 any one of the error codes in ROB_engine.h */
1302
ROB_SendEvent(ROB_Event * rob_event)1303 int ROB_SendEvent(ROB_Event *rob_event) {
1304 int retval = ROB_ERROR_NONE;
1305
1306 if (rob_event == NULL || sizeof(*rob_event) != sizeof(ROB_Event)) {
1307 sprintf(rob_last_error, "%s: event is invalid", __func__);
1308 retval = ROB_ERROR_INVALID_EVENT;
1309 } else {
1310 #ifdef DEBUG_ROB_EVENTS
1311 ROB_ShowEvent(rob_event, __func__);
1312 #endif
1313 rob_op_env.event_processor(rob_event);
1314 }
1315
1316 return retval;
1317 }
1318
1319 /***************************************************************************
1320 * Show Event *
1321 ***************************************************************************/
1322
ROB_ShowEvent(ROB_Event * rob_event,const char * func)1323 int ROB_ShowEvent(ROB_Event *rob_event, const char *func) {
1324 int retval = ROB_ERROR_NONE;
1325
1326 if (rob_event == NULL || sizeof(*rob_event) != sizeof(ROB_Event)) {
1327 sprintf(rob_last_error, "%s: event is invalid", func);
1328 retval = ROB_ERROR_INVALID_EVENT;
1329 } else {
1330 printf("%i: ", cycle_count);
1331 switch (rob_event->klasse) {
1332 case ROB_EVENT_OVER:
1333 printf("%s: ROB_EVENT_OVER", func);
1334 break;
1335 case ROB_EVENT_OUT:
1336 printf("%s: ROB_EVENT_OUT", func);
1337 break;
1338 case ROB_EVENT_PRESS:
1339 printf("%s: ROB_EVENT_PRESS", func);
1340 break;
1341 case ROB_EVENT_CLICK:
1342 printf("%s: ROB_EVENT_CLICK", func);
1343 break;
1344 case ROB_EVENT_RELEASE:
1345 printf("%s: ROB_EVENT_RELEASE", func);
1346 break;
1347 case ROB_EVENT_DRAG:
1348 printf("%s: ROB_EVENT_DRAG", func);
1349 break;
1350 case ROB_EVENT_SELECT:
1351 printf("%s: ROB_EVENT_SELECT", func);
1352 break;
1353 default:
1354 printf("%s: Unknown", func);
1355 break;
1356 }
1357 printf(" object=%p id=%i x=%i y=%i w=%i h=%i\n", rob_event->rob_object, rob_event->rob_object->id, rob_event->rob_object->x, rob_event->rob_object->y, rob_event->rob_object->w, rob_event->rob_object->h);
1358 }
1359
1360 return retval;
1361 }
1362
1363 /***************************************************************************
1364 * Set Operating Environment - System Pointer *
1365 ***************************************************************************/
1366 /* On entry: systempointer is true or false */
1367 /* On exit: returns ROB_ERROR_NONE on success else
1368 any one of the error codes in ROB_engine.h */
1369
ROB_SetOpEnvSystemPointer(int systempointer)1370 int ROB_SetOpEnvSystemPointer(int systempointer) {
1371 int retval = ROB_ERROR_NONE;
1372
1373 #ifdef DEBUG_ROB_PROGRESS_DUMP
1374 printf("%s: systempointer=%i\n", __func__, systempointer);
1375 #endif
1376 /* Store new value(s) */
1377 rob_op_env.systempointer = systempointer;
1378 SDL_ShowCursor(systempointer);
1379
1380 return retval;
1381 }
1382
1383 /***************************************************************************
1384 * Set Operating Environment - Pointer *
1385 ***************************************************************************/
1386 /* On entry: pointer's visibility is true or false
1387 pointer_mode is one of the modes as listed in ROB_engine.h */
1388 /* On exit: returns ROB_ERROR_NONE on success else
1389 any one of the error codes in ROB_engine.h */
1390
ROB_SetOpEnvPointer(int pointer,int pointer_mode)1391 int ROB_SetOpEnvPointer(int pointer, int pointer_mode) {
1392 int retval = ROB_ERROR_NONE;
1393 #ifdef DEBUG_ROB_PROGRESS_DUMP
1394 char *pointer_modes[] = {"off", "physical", "simulated"};
1395 #endif
1396
1397 #ifdef DEBUG_ROB_PROGRESS_DUMP
1398 printf("%s: pointer=%i pointer_mode=%s\n", __func__, pointer, pointer_modes[pointer_mode]);
1399 #endif
1400 /* Store new value(s) */
1401 rob_op_env.pointer = pointer;
1402 rob_op_env.pointer_mode = pointer_mode;
1403 if (rob_object_count > 0) rob_lyr_pointer->visible = pointer;
1404
1405 return retval;
1406 }
1407
1408 /***************************************************************************
1409 * Set Operating Environment - Event Processor *
1410 ***************************************************************************/
1411 /* On entry: event_processor is a pointer to a function that receives events */
1412 /* On exit: returns ROB_ERROR_NONE on success else
1413 any one of the error codes in ROB_engine.h */
1414
ROB_SetOpEnvEventProcessor(void (* event_processor)(ROB_Event * rob_event))1415 int ROB_SetOpEnvEventProcessor(void (*event_processor)(ROB_Event *rob_event)) {
1416 int retval = ROB_ERROR_NONE;
1417
1418 #ifdef DEBUG_ROB_PROGRESS_DUMP
1419 printf("%s: %p\n", __func__, event_processor);
1420 #endif
1421 /* Store new value(s) */
1422 rob_op_env.event_processor = event_processor;
1423
1424 return retval;
1425 }
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436