2 * libneuro, a light weight abstraction of high or lower libraries
3 * and toolkit for applications.
4 * Copyright (C) 2005-2006 Nicholas Niro, Robert Lemay
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 * The core painter's algorithm module.
28 * this code is my own version of the painter's algorithm.
29 * It is thus used to draw images in an order you have to
30 * input when "pushing" an image, called layers.
31 * This module also requires 3 other variables which contain
32 * the size of the image, a pointer to the image and the
33 * destination of the image.
35 * To make the painter's algorithm, I used 2 types of data.
36 * I use raw data which contains exactly what the external
37 * process gives us and then theres the instruction data which
38 * contains a pointer to a single raw data and a pointer
39 * to the next instruction data.
41 * The instruction datas order are changed every time a new
42 * image is pushed. It is organized in a growing order,
43 * the smallest layers are the first ones and the biggest
44 * are the last instructions drawn.
46 * Now, you see, the major advantage of this is we can also
47 * redraw images that were below another one which would for
48 * example be deleted. But for this, we have do an expansive
49 * bounds search for images which have to be redrawn.
51 * Also note that raw datas have different types that trigger
52 * behaviors. Static and dynamic are the two most important
53 * types, then theres the temporary type and the rest
54 * are pretty much sub types for those that I mentioned earlier.
58 /*-------------------- Extern Headers Including --------------------*/
59 #include <string.h> /* memcpy */
61 /*-------------------- Local Headers Including ---------------------*/
62 #include <extlib.h> /* we only use Lib_GetScreenSize */
63 #include <ebuf.h> /* we use all the "normal" allocation function from this */
64 #include <other.h> /* we call all the bounding check functions from it
65 and also the bound fix ones */
67 /*-------------------- Main Module Header --------------------------*/
71 /*-------------------- Other ----------------------------*/
73 /*-------------------- Global Variables ----------------------------*/
75 /*-------------------- Static Variables ----------------------------*/
77 static v_object
*background
; /* the background image */
79 static INSTRUCTION_ENGINE
*first_element
;
80 static INSTRUCTION_ENGINE
*last_element
;
85 /* buffered screen size for fast consultation */
86 static Rectan screenSize
;
88 /* a rectangle meant to test the bound fix algorithm */
89 static Rectan test_BoundFix
;
91 /*-------------------- Static Prototypes ---------------------------*/
95 /*-------------------- Static Functions ----------------------------*/
97 /* A function that handles "fixes" needed on images
98 * to make them constrainted in the main screen.
99 * returns 0 if all is ok and 1 if the image needs
103 BoundFixChecker(Rectan
*indep
, Rectan
*isrc
, Rectan
*idst
)
109 bufa
.w
= isrc
->w
- 1;
110 bufa
.h
= isrc
->h
- 1;
112 switch (Neuro_BoundsCheck(indep
, &bufa
))
114 case 0: /* the v_object is inside the screen, all is ok */
117 case 1: /* the v_object is outside the screen, we need to drop this instruction */
119 /* Debug_Print("a drawing instruction was dropped because its destination is outbound"); */
124 /* here is the fun, the v_object is overlapping the screen
125 * and we got to only draw the part that is still inside
130 /* to do this, I'm thinking we could use 2 similar functions
131 * the 1st one would check and "correct" the parts of the
132 * v_object that is not inside the screen vertically and
133 * the 2nd one would do the same but horizontally.
134 * The only thing to do is to change the isrc(Rectan)'s
137 Neuro_VerticalBoundFix(indep
, isrc
, idst
);
138 Neuro_HorizontalBoundFix(indep
, isrc
, idst
);
139 /* Info_Print("Fixed the coordinates/size of the drawing instruction."); */
145 /* Debug_Print("a drawing instruction was dropped because its destination is outbound"); */
154 /* compute the instruction_engine buffer every
155 * time a new raw element is added.
157 static INSTRUCTION_ENGINE
*
158 computeRawEngine(RAW_ENGINE
*toadd
)
161 register INSTRUCTION_ENGINE
*buf
= NULL
, *cur
= NULL
, *last
= NULL
;
162 register u32 current
; /* current number of elements in instruction */
166 /*if (use_memory_pool)
167 buf = Pull_Data_From_Pool(POOL_QUEUE);*/
171 /* Debug_Val(0, "computeRawEngine buf is empty so we allocate for %d\n", toadd->layer); */
172 Neuro_AllocEBuf(tmp
, sizeof(INSTRUCTION_ENGINE
*), sizeof(INSTRUCTION_ENGINE
));
173 buf
= Neuro_GiveCurEBuf(tmp
);
176 Debug_Val(0, "computeRawEngine recycled an object! %d\n", toadd->layer);*/
179 current
= Neuro_GiveEBufCount(tmp
);
181 buf
->current
= toadd
;
184 if (debug_instruction_buffer
)
185 Debug_Val(0, "Push --> %d\n", toadd
->layer
);
187 if (last_element
!= NULL
)
189 if (last_element
->current
== NULL
)
191 Debug_Val(0, "CAUGHT ERROR in last_element current == %d -- debug %d\nDropping this call\n",
193 (int)last_element
->current
);
197 if (last_element
->current
->layer
<= buf
->current
->layer
)
199 last_element
->next
= buf
;
201 /*Debug_Val(0, "proof layer %d real layer %d ptr %d\n",
202 (*buf)[current]->current->layer,
203 (*last_element)->current->layer,
204 (int)(*last_element)->current);*/
205 /* Debug_Val(0, "Placed the object at the end of the queue\n"); */
214 /* Debug_Val(0, "Just placed the frame as the first element, starting the queue\n"); */
218 /* TODO TODO TODO TODO
219 * special case so volatile types always are put in the
220 * beginning of the queue. Both to make the process
221 * faster and to make the volatiles have precedence
222 * over everything to avoid conflicts.
224 if (buf
->current
->type
= TDRAW_VOLATILE
)
226 /* we make the type be of the layer 0 so it is
227 * always the first in the list.
229 * the layer 0 is reserved stricly for volatile
233 buf
->current
->layer
= 0;
238 /* cur = Neuro_GiveEBuf(tmp, first); */
241 /* Debug_Val(0, "looped cur %d buf %d\n", cur->current->layer, buf->current->layer); */
242 if (cur
->current
->layer
> buf
->current
->layer
)
244 /*printf("Event current layer %d > toadd layer %d\n",
249 /* to avoid death loops */
250 /*if (cur->next == buf)
253 if (cur
== first_element
)
256 /* switch **buf with the current position */
257 temp
= Neuro_GiveEBuf(tmp
, first
);
258 Neuro_SetEBuf(tmp
, Neuro_GiveEBufAddr(tmp
, first
), buf
);
259 Neuro_SetEBuf(tmp
, Neuro_GiveEBufAddr(tmp
, current
), temp
);
261 /*printf("Beginning LL change : cur %d, buf[0][0] %d\n",
265 if (cur
->current
== NULL
|| cur
->current
->surface_ptr
== NULL
)
266 cur
= Neuro_GiveEBuf(tmp
, first
);
267 if (Neuro_GiveEBuf(tmp
, first
) == buf
)
269 Error_Print("huge problem, it is going to put its next element as the same node as itself, creating a death loop!!\n");
275 /*Debug_Val(0, "New First element proclaimed %d\n",
276 buf->current->layer);*/
277 buf
->next
= first_element
;
290 /* Debug_Val(0, "nothing to be done\n"); */
295 /* printf("End of the looping process\n"); */
298 if (debug_instruction_buffer
)
300 Debug_Val(0, "BEGIN inside computeRawEngine debug print\n");
301 Graphics_DebugPrintQueue();
302 Debug_Val(0, "END inside computeRawEngine debug print\n");
309 /*-------------------- Global Functions ----------------------------*/
311 /* - layer is the priority by which it much be drawn.
312 * - src should be used to know which part of the
313 * surface has to be drawn(for sprites mostly).
314 * - dst is the destination X Y on the screen
315 * - surface is the pointer of the loaded image.
318 Graphics_AddDrawingInstruction(u32 layer
, u8 type
, Rectan
*isrc
, Rectan
*idst
, void *isurface
)
320 RAW_ENGINE
*buf
= NULL
;
323 if (isurface
== NULL
|| isrc
== NULL
|| idst
== NULL
)
326 memcpy(&tIsrc
, isrc
, sizeof(Rectan
));
327 memcpy(&tIdst
, idst
, sizeof(Rectan
));
329 if (BoundFixChecker(&screenSize
, &tIsrc
, &tIdst
) == 1)
331 /* Debug_Val(10, "a drawing instruction was dropped because its destination is outbound"); */
335 #if retain_image_inipos
343 #endif /* retain_image_inipos */
345 /* a square in the middle of the screen to test
346 * the bound fix checker on an object other than
349 /* BoundFixChecker(&test_BoundFix, &tIsrc, &tIdst); */
351 /*if (use_memory_pool)
352 buf = Pull_Data_From_Pool(POOL_RAWENGINE);*/
356 Neuro_AllocEBuf(Raw
, sizeof(RAW_ENGINE
*), sizeof(RAW_ENGINE
));
358 buf
= Neuro_GiveCurEBuf(Raw
);
361 /* we reserve the 0 spot for out need
362 * we might reserve more than just one
363 * if the need comes out.
365 buf
->layer
= layer
+ 1;
367 memcpy(&buf
->src
, &tIsrc
, sizeof(Rectan
));
372 buf
->surface_ptr
= isurface
;
374 /* sets a flag to tell when changed things
375 * and I think the whole screen will be
378 Neuro_RedrawScreen();
380 return computeRawEngine((RAW_ENGINE
*)buf
);
384 Graphics_GetFirstElem()
386 return first_element
;
390 Graphics_SetFirstElem(INSTRUCTION_ENGINE
*elem
)
392 first_element
= elem
;
396 Graphics_GetLastElem()
402 Graphics_SetLastElem(INSTRUCTION_ENGINE
*elem
)
408 Graphics_GetRawBuffer()
414 Graphics_GetQueueBuffer()
419 /*-------------------- Constructor Destructor ----------------------*/
422 Graphics_PainterInit()
424 u32 screenwidth
, screenheight
;
426 Neuro_CreateEBuf(&Raw
);
427 Neuro_CreateEBuf(&Queue
);
429 /* get the screen size from the "official" source */
430 Lib_GetScreenSize(&screenwidth
, &screenheight
);
432 /* populate a buffer variable that keeps the size of the screen for fast consultation. */
435 screenSize
.w
= screenwidth
;
436 screenSize
.h
= screenheight
;
442 Graphics_PainterReset()
444 Neuro_CleanEBuf(&Raw
);
445 Neuro_CleanEBuf(&Queue
);
447 Neuro_CreateEBuf(&Raw
);
448 Neuro_CreateEBuf(&Queue
);
450 first_element
= NULL
;
457 Graphics_PainterClean()
459 Debug_Val(0, "Raw total %d\n", Neuro_GiveEBufCount(Raw
));
460 Debug_Val(0, "Queue total %d\n", Neuro_GiveEBufCount(Queue
));
462 Neuro_CleanEBuf(&Raw
);
463 Neuro_CleanEBuf(&Queue
);
465 first_element
= NULL
;