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
22 * the core drawing algorithm.
25 /*-------------------- Extern Headers Including --------------------*/
26 #include <string.h> /* memcpy */
28 /*-------------------- Local Headers Including ---------------------*/
29 #include <extlib.h> /* we mainly use the blitting function and screen updating functions */
30 #include <ebuf.h> /* we mainly use the single item cleaning function Neuro_SCleanEBuf */
32 /*-------------------- Main Module Header --------------------------*/
37 /*-------------------- Other ----------------------------*/
39 /*-------------------- Global Variables ----------------------------*/
41 /*-------------------- Static Variables ----------------------------*/
43 /*-------------------- Static Prototypes ---------------------------*/
47 /*-------------------- Static Functions ----------------------------*/
49 /* a function to resolve a bug that made the volatile objects
50 * mysteriously disapear. It was because the last element of the
51 * Dynamic object was not refreshed so if an element was just
52 * before the Dynamic object, it just made it disapear :).
54 * This function searches the element just before the input element
57 static INSTRUCTION_ENGINE
*
58 get_Previous_Object_To_Object(INSTRUCTION_ENGINE
*indep
)
60 INSTRUCTION_ENGINE
*cur
, *last
= NULL
;
62 cur
= Graphics_GetFirstElem();
75 /* Debug_Val(0, "found the previous elem 0x%x, (his next 0x%x)\n",
89 /* del_mask : 0 is don't clean any buffers (big memory leak)
90 * 1 is clean only the raw engine
91 * 2 is clean only the queue(instruction) engine
95 Core_clean_object(INSTRUCTION_ENGINE
*cur
, int dont_redraw_section
, u8 del_mask
)
98 INSTRUCTION_ENGINE
*last
= NULL
;
101 /* this functions needs to destroy an element
102 * from both the instruction buffer and the raw
105 * the first step we do is fill a special Rectan
106 * rectangle with the position and size of
107 * the image. Then, we draw this position and
108 * size black on screen. After that is done, we
109 * have to redraw previous objects (if theres any).
114 if (debug_track_fonts
)
116 if (cur
->current
->layer
>= 99999)
118 Debug_Print("Destroying font");
119 Debug_Val(0, "&0x%x\n", cur
);
123 /* Graphics_DebugQueueIntegrityCheck(); */
128 /* Debug_Val(0, "destroying element address 0x%x\n", cur); */
130 buf
.x
= cur
->current
->dx
;
131 buf
.y
= cur
->current
->dy
;
132 buf
.w
= cur
->current
->src
.w
;
133 buf
.h
= cur
->current
->src
.h
;
136 Lib_BlitObject(background, &buf, sclScreen2, &buf);
138 Lib_FillRect(sclScreen2, &buf, 0);
141 if (dont_redraw_section
== 0)
143 Lib_FillRect(Neuro_GetScreenBuffer(), &buf
, 0);
145 Graphics_RedrawSection(cur
);
148 if (debug_clean_instruction_buffer
)
150 Neuro_CreateEBuf(&verify_m
);
151 Graphics_DebugBufferQueue(verify_m
);
154 if (debug_clean_instruction_buffer
)
156 Debug_Print("*initial values");
157 Debug_Val(0, "Amount of elems %d\n", Neuro_GiveEBufCount(verify_m
) - 1);
158 Graphics_DebugPrintMissing(verify_m
);
161 /* only set the previous element (last) if the element we need to
162 * destroy isn't the first one
164 if (cur
!= Graphics_GetFirstElem())
165 last
= get_Previous_Object_To_Object(cur
);
168 /* Debug_Val(0, "changing last's(0x%x) next 0x%x to 0x%x\n", last,
169 last->next, cur->next);*/
171 last
->next
= cur
->next
;
174 /* check to see if the element cur is either first_element
175 * or last_element and if so, we will destituate it.
177 if (cur
== Graphics_GetFirstElem())
179 Graphics_SetFirstElem(cur
->next
);
182 if (cur
== Graphics_GetLastElem())
187 Graphics_SetLastElem(last
);
190 Graphics_SetLastElem(NULL
);
193 if (debug_clean_instruction_buffer
)
195 Debug_Print("*before real destroy");
196 Graphics_DebugPrintMissing(verify_m
);
199 /*if (use_memory_pool)
200 Push_Data_To_Pool(POOL_QUEUE, cur);
203 /* INSTRUCTION_ENGINE *temp; */
210 /* Debug_Val(0, "before queue total %d\n",
211 Neuro_GiveEBufCount(_Queue) + 1);*/
213 if (del_mask
== 1 || del_mask
== 3)
214 Neuro_SCleanEBuf(Graphics_GetRawBuffer(), cur
->current
);
215 /* Debug_Val(0, "-- element address 0x%x destroyed\n", cur); */
216 if (del_mask
== 2 || del_mask
== 3)
217 Neuro_SCleanEBuf(Graphics_GetQueueBuffer(), cur
);
219 /* Debug_Val(0, "after queue total %d\n",
220 Neuro_GiveEBufCount(_Queue) + 1); */
224 if (debug_clean_instruction_buffer
)
226 Debug_Print("**After the destroy");
227 /*Debug_Val(0, "Amount of elems in verify %d in queue %d\n",
228 Neuro_GiveEBufCount(verify_m) - 1,
229 Neuro_GiveEBufCount(_Queue) - 1);*/
230 Debug_Print("**Full output");
232 Graphics_DebugPrintQueue();
234 Graphics_DebugPrintMissing(verify_m
);
235 Neuro_CleanEBuf(&verify_m
);
238 /* Graphics_DebugQueueIntegrityCheck(); */
242 clean_object(INSTRUCTION_ENGINE
*cur
, int dont_redraw_section
)
244 Core_clean_object(cur
, dont_redraw_section
, 3);
247 /*-------------------- Global Functions ----------------------------*/
249 /* take note that we don't do any checks for valid pointers and such
250 * this function is supposed to be a backbone to an interface function
251 * which itself does the parity checks.
254 Graphics_DestroyElement(INSTRUCTION_ENGINE
*elem
)
259 /* we destroy only the queue buffer because we want to make
260 * the emplacement of the element into a more comfortable
261 * place for the algorithm to avoid glitches.
266 /* we clean only the queue element and keep the raw engine buffer */
267 Core_clean_object(elem
, 1, 2);
272 tmp
->type
= TDRAW_SDESTROY
;
274 /* we put the raw buffer back into the queue */
275 Graphics_PushRaw(tmp
);
279 Graphics_CoreDrawAll()
282 INSTRUCTION_ENGINE
*cur
, *last
= NULL
;
283 u32 safety
= 10000; /* safety decrementor to avoid death loop */
285 if (Neuro_EBufIsEmpty(Graphics_GetQueueBuffer()))
288 cur
= Graphics_GetFirstElem();
290 /* start the real drawing */
296 Error_Print("To avoid a death loop, had to bail out of the instruction loop after 1000 loops");
297 break; /* safety break */
302 if (check_integrity_on_draw
)
304 Debug_Print("Data integrity check before drawing");
305 Graphics_DebugQueueIntegrityCheck();
308 memcpy(&isrc
, &cur
->current
->src
, sizeof(Rectan
));
310 idst
.x
= cur
->current
->dx
;
311 idst
.y
= cur
->current
->dy
;
313 if (debug_instruction_buffer
)
314 Debug_Val(0, "%s Flushing type %d layer %d\n", __FUNCTION__
, cur
->current
->type
, cur
->current
->layer
);
316 /* draw the surface_ptr to the screen buffer. */
317 switch (cur
->current
->type
)
322 /* Debug_Val(0, "static draw (%d,%d) %dx%d to (%d,%d)\n",
323 isrc.x, isrc.y, isrc.w, isrc.h,
329 Lib_BlitObject(cur
->current
->surface_ptr
, &isrc
, Neuro_GetScreenBuffer(),
332 cur
->current
->type
= TDRAW_SDRAWN
;
334 /* Graphics_RedrawSection(cur); */
336 /* Debug_Val(0, "drawn static\n"); */
338 if (debug_track_fonts
)
340 if (cur
->current
->layer
>= 99999)
342 Debug_Print("Drawing font");
343 Debug_Val(0, "Coord (%d,%d) &0x%x\n",
345 cur
->current
->dy
, cur
);
353 /* nothing needed for this type */
354 /* Debug_Val(0, "already drawn\n"); */
360 /* Debug_Val(0, "address of surface 0x%x\n", cur->current->surface_ptr); */
362 /* now we redraw the actual element */
363 Lib_BlitObject(cur
->current
->surface_ptr
, &isrc
, Neuro_GetScreenBuffer(),
366 /* we cleanly redrawn the static element so we
367 * set the element's flag to drawn
369 cur
->current
->type
= TDRAW_SDRAWN
;
371 /* then we redraw the stuff that could have been
372 * there and actually need to be visible(and are above
373 * our element, ie layers).
375 * broken for some reason
377 Graphics_RedrawSection(cur
);
379 /* Debug_Val(0, "Redrawn a static element\n"); */
385 INSTRUCTION_ENGINE
*tmp
;
387 if (cur->current->layer > 1000)
388 Debug_Print("Cleaned a static image");
395 clean_object(tmp
, 0);
397 /* we restart the loop completely since we need to draw
398 * the volatile types first before drawing the rest..
400 cur
= Graphics_GetFirstElem();
409 Lib_BlitObject(cur
->current
->surface_ptr
, &isrc
,
410 Neuro_GetScreenBuffer(), &idst
);
412 cur
->current
->type
= TDRAW_DYNAMIC_CLEAN
;
415 Debug_Val(0, "Dynamic : Tagging addr %x to clean\n", cur
);
416 /* Debug_Val(0, "drawn dynamic\n"); */
421 case TDRAW_DYNAMIC_CLEAN
:
423 /* Lib_BlitObject(cur->current->surface_ptr, &isrc,
424 sclScreen2, &idst);*/
426 /* clean_object(cur); */
433 /*Debug_Val(0, "Volatile draw (%d,%d) %dx%d to (%d,%d) image 0x%x\n",
434 isrc.x, isrc.y, isrc.w, isrc.h,
436 cur->current->surface_ptr);
439 Lib_BlitObject(cur
->current
->surface_ptr
, &isrc
,
440 Neuro_GetScreenBuffer(), &idst
);
442 /* NOTE that we CAN't USE clean_object() BECAUSE
443 * it actually makes the image all BLACK
444 * so it nullifies the action of this COMPLETELY.
447 last
->next
= cur
->next
;
449 /* check to see if the element cur is either first_element
450 * or last_element and if so, we will destituate it.
452 if (cur
== Graphics_GetFirstElem())
454 Graphics_SetFirstElem(cur
->next
);
457 if (cur
== Graphics_GetLastElem())
462 Graphics_SetLastElem(last
);
467 /*if (use_memory_pool)
468 Push_Data_To_Pool(POOL_QUEUE, cur);
471 INSTRUCTION_ENGINE
*temp
;
476 Neuro_SCleanEBuf(Graphics_GetRawBuffer(), temp
->current
);
477 Neuro_SCleanEBuf(Graphics_GetQueueBuffer(), temp
);
488 Debug_Val(0, "ERROR Draw unknown type %d\n", cur
->current
->type
);
496 if (cur
->next
== NULL
&& cur
!= Graphics_GetLastElem())
498 Error_Print("cur->next is NULL AND it isn't the last element, bad, very bad...");
507 Graphics_SetDrawnLastCycle();
508 /* Lib_FillRect(sclScreen, &test_BoundFix, 0); */
512 Graphics_SetAllToRedraw()
514 INSTRUCTION_ENGINE
*cur
;
516 cur
= Graphics_GetFirstElem();
523 if (cur
->current
->type
== TDRAW_SDRAWN
)
524 cur
->current
->type
= TDRAW_STATIC
; /* TDRAW_SREDRAW seems to do a flaw */
529 if (debug_instruction_buffer
)
530 Debug_Print("Just Set all the instructions to be redrawn");
533 /* Graphics_CoreCleanAll might have cleaned objects
534 * that should be drawn so we will redraw those in this
536 * returns non zero if a volatile type was pushed
539 Graphics_RedrawSection(INSTRUCTION_ENGINE
*indep
)
541 Rectan buf
, indep_body
;
542 INSTRUCTION_ENGINE
*cur
;
547 indep_body
.x
= indep
->current
->dx
;
548 indep_body
.y
= indep
->current
->dy
;
549 indep_body
.w
= indep
->current
->src
.w
;
550 indep_body
.h
= indep
->current
->src
.h
;
552 cur
= Graphics_GetFirstElem();
568 Debug_Val(0, "BAD : the instruction 0x%x has an empty content!\n",
571 Debug_Val(0, "DEBUG data : indep 0x%x its next element 0x%x\n",
573 /* odd error, this ain't supposed to happen :L */
577 if (debug_track_fonts
)
579 if (cur
->current
->layer
>= 99999 && indep
->current
->layer
>= 99999)
581 Debug_Print("INITIAL Redrawing font");
583 Debug_Val(0, "Font type %d (%d,%d) &0x%x\n", cur
->current
->type
,
588 if (cur
->current
->type
== TDRAW_SDRAWN
)
591 buf
.x
= cur
->current
->dx
;
592 buf
.y
= cur
->current
->dy
;
593 buf
.w
= cur
->current
->src
.w
;
594 buf
.h
= cur
->current
->src
.h
;
596 bounds_ret
= Neuro_BoundsCheck(&indep_body
, &buf
);
597 /* bounds_ret = 2; */
599 if (debug_track_fonts
)
601 if (cur
->current
->layer
>= 99999 && indep
->current
->layer
>= 99999)
603 Debug_Print("INITIAL 2 Redrawing font");
604 Debug_Val(0, "bounds_ret %d current (%d,%d) indep (%d,%d)\n",
607 indep_body
.x
, indep_body
.y
);
615 bufa
.x
= cur
->current
->dx
;
616 bufa
.y
= cur
->current
->dy
;
620 Neuro_PushVolatileDraw(cur
->current
->layer
, &cur
->current
->src
,
621 &bufa
, cur
->current
->surface_ptr
);
623 /*Debug_Val(0, "dynamic is inside this object\n");*/
625 if (debug_track_fonts
)
627 if (cur
->current
->layer
>= 99999)
628 Debug_Print("Redrawing font #0");
638 memcpy(&isrc
, &cur
->current
->src
, sizeof(Rectan
));
640 idst
.x
= cur
->current
->dx
;
641 idst
.y
= cur
->current
->dy
;
645 Neuro_VerticalBoundCrop(&indep_body
, &isrc
, &idst
);
646 Neuro_HorizontalBoundCrop(&indep_body
, &isrc
, &idst
);
648 Neuro_PushVolatileDraw(cur
->current
->layer
,
649 &isrc
, &idst
, cur
->current
->surface_ptr
);
651 if (debug_track_fonts
)
653 if (cur
->current
->layer
>= 99999)
654 Debug_Print("Redrawing font #2");
662 Rectan isrc
, idst
, hack
;
664 memcpy(&isrc
, &cur
->current
->src
, sizeof(Rectan
));
666 idst
.x
= cur
->current
->dx
;
667 idst
.y
= cur
->current
->dy
;
672 if (indep_body
.x
> buf
.x
)
674 isrc
.x
+= indep_body
.x
- buf
.x
;
675 idst
.x
+= indep_body
.x
- buf
.x
;
677 /*isrc.y += buf.y - indep_body.y;
678 idst.y += buf.y - indep_body.y;*/
680 isrc
.w
-= buf
.w
- indep_body
.w
;
681 /* isrc.h += indep_body.h - buf.h; */
685 /*isrc.x += buf.x - indep_body.x;
686 idst.x += buf.x - indep_body.x;*/
688 isrc
.y
+= indep_body
.y
- buf
.y
;
689 idst
.y
+= indep_body
.y
- buf
.y
;
691 /* isrc.w += indep_body.w - buf.w; */
692 isrc
.h
-= buf
.h
- indep_body
.h
;
695 /* Neuro_PushVolatileDraw(cur->current->layer,
696 &isrc, &idst, cur->current->surface_ptr);*/
698 /* temporary hack that seems to work, we draw the whole
699 * static image... this needs testing and a better
703 hack
.x
= cur
->current
->dx
;
704 hack
.y
= cur
->current
->dy
;
708 Neuro_PushVolatileDraw(cur
->current
->layer
, &cur
->current
->src
,
709 &hack
, cur
->current
->surface_ptr
);
711 /*Debug_Val(0, "we have a case 3 situation!\n");*/
713 if (debug_track_fonts
)
715 if (cur
->current
->layer
>= 99999)
716 Debug_Print("Redrawing font #3");
722 /* indep is inside cur */
728 bufa
.x
= indep_body
.x
;
729 bufa
.y
= indep_body
.y
;
733 nsrc
.x
= indep_body
.x
- cur
->current
->dx
;
734 nsrc
.y
= indep_body
.y
- cur
->current
->dy
;
735 nsrc
.w
= indep_body
.w
;
736 nsrc
.h
= indep_body
.h
;
746 nsrc.w = cur->current->src.w;
747 nsrc.h = cur->current->src.h;
750 Neuro_PushVolatileDraw(cur
->current
->layer
, &nsrc
,
751 &bufa
, cur
->current
->surface_ptr
);
753 if (debug_track_fonts
)
755 if (cur
->current
->layer
>= 99999)
756 Debug_Print("Redrawing font #4");
762 /* Debug_Val(0, "Redraw Section debug #%d\n", bounds_ret); */
771 Graphics_CoreCleanAll()
773 INSTRUCTION_ENGINE
*cur
;
775 cur
= Graphics_GetFirstElem();
780 /* "reset" the emplacement of the last position of the image
781 * with the background if theres one or with the color black
786 clean_object(cur
, 1);
791 Graphics_ResetScreenDraw();
794 /* only clean those with the type TDRAW_DYNAMIC_CLEAN */
796 Graphics_CoreCleanDoneDynamics()
798 INSTRUCTION_ENGINE
*cur
;
800 cur
= Graphics_GetFirstElem();
805 /* "reset" the emplacement of the last position of the image
806 * with the background if theres one or with the color black
811 if (cur
->current
->type
== TDRAW_DYNAMIC_CLEAN
)
813 clean_object(cur
, 0);
821 Graphics_FreeVObject(v_object
*source
)
823 INSTRUCTION_ENGINE
*cur
, *tmp
;
825 /* this function was made to avoid the painter's algorithm
826 * to have an element contain an image surface that was
827 * freed before it was processed resulting in a segmentation
831 cur
= Graphics_GetFirstElem();
837 if (cur
->current
->surface_ptr
== source
)
839 /*if (cur->current->type == TDRAW_SDRAWN)
840 Neuro_DestroyDraw(cur);
842 Core_clean_object(cur
, 0, 3);
849 Lib_FreeVobject(source
);