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 INSTRUCTION_ENGINE
*first_element
;
78 static INSTRUCTION_ENGINE
*last_element
;
83 /* buffered screen size for fast consultation */
84 static Rectan screenSize
;
86 /* a rectangle meant to test the bound fix algorithm */
87 /* static Rectan test_BoundFix; */
89 /*-------------------- Static Prototypes ---------------------------*/
93 /*-------------------- Static Functions ----------------------------*/
95 /* A function that handles "fixes" needed on images
96 * to make them constrainted in the main screen.
97 * returns 0 if all is ok and 1 if the image needs
101 BoundFixChecker(Rectan
*indep
, Rectan
*isrc
, Rectan
*idst
)
107 bufa
.w
= isrc
->w
- 1;
108 bufa
.h
= isrc
->h
- 1;
110 switch (Neuro_BoundsCheck(indep
, &bufa
))
112 case 0: /* the v_object is inside the screen, all is ok */
115 case 1: /* the v_object is outside the screen, we need to drop this instruction */
117 /* Debug_Print("a drawing instruction was dropped because its destination is outbound"); */
122 /* here is the fun, the v_object is overlapping the screen
123 * and we got to only draw the part that is still inside
128 /* to do this, I'm thinking we could use 2 similar functions
129 * the 1st one would check and "correct" the parts of the
130 * v_object that is not inside the screen vertically and
131 * the 2nd one would do the same but horizontally.
132 * The only thing to do is to change the isrc(Rectan)'s
135 Neuro_VerticalBoundCrop(indep
, isrc
, idst
);
136 Neuro_HorizontalBoundCrop(indep
, isrc
, idst
);
137 /* Info_Print("Fixed the coordinates/size of the drawing instruction."); */
143 /* Debug_Print("a drawing instruction was dropped because its destination is outbound"); */
152 /* compute the instruction_engine buffer every
153 * time a new raw element is added.
155 static INSTRUCTION_ENGINE
*
156 computeRawEngine(RAW_ENGINE
*toadd
)
159 register INSTRUCTION_ENGINE
*buf
= NULL
, *cur
= NULL
, *last
= NULL
;
160 register u32 current
; /* current number of elements in instruction */
164 /*if (use_memory_pool)
165 buf = Pull_Data_From_Pool(POOL_QUEUE);*/
169 /* Debug_Val(0, "computeRawEngine buf is empty so we allocate for %d\n", toadd->layer); */
170 Neuro_AllocEBuf(tmp
, sizeof(INSTRUCTION_ENGINE
*), sizeof(INSTRUCTION_ENGINE
));
171 buf
= Neuro_GiveCurEBuf(tmp
);
174 Debug_Val(0, "computeRawEngine recycled an object! %d\n", toadd->layer);*/
177 current
= Neuro_GiveEBufCount(tmp
);
179 buf
->current
= toadd
;
183 /* this is the special case for a TDRAW_SDESTROY element
184 * every one of those elements will be put into the
187 if (buf
->current
->type
== TDRAW_SDESTROY
)
189 buf
->current
->layer
= 0;
193 * special case so volatile types always are put in the
194 * beginning of the queue. Both to make the process
195 * faster and to make the volatiles have precedence
196 * over everything to avoid conflicts.
198 if (buf
->current
->type
== TDRAW_VOLATILE
)
200 /* we make the type be of the layer 0 so it is
201 * always the first in the list.
203 * the layer 0 is reserved stricly for volatile
207 buf
->current
->layer
= 1;
210 if (debug_instruction_buffer
)
211 Debug_Val(0, "Push --> layer %d type %d\n", toadd
->layer
, toadd
->type
);
213 if (last_element
!= NULL
)
215 if (last_element
->current
== NULL
)
217 Debug_Val(0, "CAUGHT ERROR in last_element current == %d -- debug %d\nDropping this call\n",
219 (int)last_element
->current
);
223 if (last_element
->current
->layer
<= buf
->current
->layer
)
225 last_element
->next
= buf
;
227 /*Debug_Val(0, "proof layer %d real layer %d ptr %d\n",
228 (*buf)[current]->current->layer,
229 (*last_element)->current->layer,
230 (int)(*last_element)->current);*/
231 /* Debug_Val(0, "Placed the object at the end of the queue\n"); */
240 /* Debug_Val(0, "Just placed the frame as the first element, starting the queue\n"); */
245 /* cur = Neuro_GiveEBuf(tmp, first); */
248 /* Debug_Val(0, "looped cur %d buf %d\n", cur->current->layer, buf->current->layer); */
249 if (cur
->current
->layer
> buf
->current
->layer
)
251 /*printf("Event current layer %d > toadd layer %d\n",
256 /* to avoid death loops */
257 /*if (cur->next == buf)
260 if (cur
== first_element
)
263 /* switch **buf with the current position */
264 temp
= Neuro_GiveEBuf(tmp
, first
);
265 Neuro_SetEBuf(tmp
, Neuro_GiveEBufAddr(tmp
, first
), buf
);
266 Neuro_SetEBuf(tmp
, Neuro_GiveEBufAddr(tmp
, current
), temp
);
268 /*printf("Beginning LL change : cur %d, buf[0][0] %d\n",
272 if (cur
->current
== NULL
|| cur
->current
->surface_ptr
== NULL
)
273 cur
= Neuro_GiveEBuf(tmp
, first
);
274 if (Neuro_GiveEBuf(tmp
, first
) == buf
)
276 Error_Print("huge problem, it is going to put its next element as the same node as itself, creating a death loop!!\n");
282 /*Debug_Val(0, "New First element proclaimed %d\n",
283 buf->current->layer);*/
284 buf
->next
= first_element
;
297 /* Debug_Val(0, "nothing to be done\n"); */
302 /* printf("End of the looping process\n"); */
305 if (debug_instruction_buffer
)
307 Debug_Val(0, "BEGIN inside computeRawEngine debug print\n");
308 Graphics_DebugPrintQueue();
309 Debug_Val(0, "END inside computeRawEngine debug print\n");
316 /*-------------------- Global Functions ----------------------------*/
318 /* - layer is the priority by which it much be drawn.
319 * - src should be used to know which part of the
320 * surface has to be drawn(for sprites mostly).
321 * - dst is the destination X Y on the screen
322 * - surface is the pointer of the loaded image.
325 Graphics_AddDrawingInstruction(u32 layer
, u8 type
, Rectan
*isrc
, Rectan
*idst
, void *isurface
)
327 RAW_ENGINE
*buf
= NULL
;
330 if (isurface
== NULL
|| isrc
== NULL
|| idst
== NULL
)
333 memcpy(&tIsrc
, isrc
, sizeof(Rectan
));
334 memcpy(&tIdst
, idst
, sizeof(Rectan
));
336 if (BoundFixChecker(&screenSize
, &tIsrc
, &tIdst
) == 1)
338 /* Debug_Val(10, "a drawing instruction was dropped because its destination is outbound"); */
342 #if retain_image_inipos
350 #endif /* retain_image_inipos */
352 /* a square in the middle of the screen to test
353 * the bound fix checker on an object other than
356 /* BoundFixChecker(&test_BoundFix, &tIsrc, &tIdst); */
358 /*if (use_memory_pool)
359 buf = Pull_Data_From_Pool(POOL_RAWENGINE);*/
363 Neuro_AllocEBuf(Raw
, sizeof(RAW_ENGINE
*), sizeof(RAW_ENGINE
));
365 buf
= Neuro_GiveCurEBuf(Raw
);
368 /* we reserve the first 5 spots for our need
369 * we might reserve more than 5
370 * if the need comes out.
372 buf
->layer
= layer
+ 5;
374 memcpy(&buf
->src
, &tIsrc
, sizeof(Rectan
));
379 buf
->surface_ptr
= isurface
;
381 /* sets a flag to tell when changed things
382 * and I think the whole screen will be
385 Neuro_RedrawScreen();
387 /* if (buf->type == TDRAW_STATIC || buf->type == TDRAW_DYNAMIC)
388 Graphics_SetAllToRedraw();*/
390 return computeRawEngine((RAW_ENGINE
*)buf
);
394 Graphics_PushRaw(RAW_ENGINE
*raw
)
396 return computeRawEngine((RAW_ENGINE
*)raw
);
401 Graphics_GetFirstElem()
403 return first_element
;
407 Graphics_SetFirstElem(INSTRUCTION_ENGINE
*elem
)
409 first_element
= elem
;
413 Graphics_GetLastElem()
419 Graphics_SetLastElem(INSTRUCTION_ENGINE
*elem
)
425 Graphics_GetRawBuffer()
431 Graphics_GetQueueBuffer()
436 /*-------------------- Constructor Destructor ----------------------*/
439 Graphics_PainterInit()
441 i32 screenwidth
, screenheight
;
443 Neuro_CreateEBuf(&Raw
);
444 Neuro_CreateEBuf(&Queue
);
446 /* get the screen size from the "official" source */
447 Lib_GetScreenSize(&screenwidth
, &screenheight
);
449 /* populate a buffer variable that keeps the size of the screen for fast consultation. */
452 screenSize
.w
= screenwidth
;
453 screenSize
.h
= screenheight
;
459 Graphics_PainterReset()
461 Neuro_CleanEBuf(&Raw
);
462 Neuro_CleanEBuf(&Queue
);
464 Neuro_CreateEBuf(&Raw
);
465 Neuro_CreateEBuf(&Queue
);
467 first_element
= NULL
;
474 Graphics_PainterClean()
476 Debug_Val(0, "Raw total %d\n", Neuro_GiveEBufCount(Raw
));
477 Debug_Val(0, "Queue total %d\n", Neuro_GiveEBufCount(Queue
));
479 Neuro_CleanEBuf(&Raw
);
480 Neuro_CleanEBuf(&Queue
);
482 first_element
= NULL
;