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 ---------------------*/
30 #include <extlib.h> /* we mainly use the blitting function and screen updating functions */
31 #include <ebuf.h> /* we mainly use the single item cleaning function Neuro_SCleanEBuf */
33 /*-------------------- Main Module Header --------------------------*/
38 /*-------------------- Other ----------------------------*/
40 NEURO_MODULE_CHANNEL("video/coredraw");
42 /*-------------------- Global Variables ----------------------------*/
44 /*-------------------- Static Variables ----------------------------*/
46 /*-------------------- Static Prototypes ---------------------------*/
50 /*-------------------- Static Functions ----------------------------*/
52 /* a function to resolve a bug that made the volatile objects
53 * mysteriously disapear. It was because the last element of the
54 * Dynamic object was not refreshed so if an element was just
55 * before the Dynamic object, it just made it disapear :).
57 * This function searches the element just before the input element
60 static INSTRUCTION_ENGINE
*
61 get_Previous_Object_To_Object(INSTRUCTION_ENGINE
*indep
)
63 INSTRUCTION_ENGINE
*cur
, *last
= NULL
;
65 cur
= Graphics_GetFirstElem();
78 /* Debug_Val(0, "found the previous elem 0x%x, (his next 0x%x)\n",
92 /* del_mask : 0 is don't clean any buffers (big memory leak)
93 * 1 is clean only the raw engine
94 * 2 is clean only the queue(instruction) engine
98 Core_clean_object(INSTRUCTION_ENGINE
*cur
, int dont_redraw_section
, u8 del_mask
)
101 INSTRUCTION_ENGINE
*last
= NULL
;
104 /* this functions needs to destroy an element
105 * from both the instruction buffer and the raw
108 * the first step we do is fill a special Rectan
109 * rectangle with the position and size of
110 * the image. Then, we draw this position and
111 * size black on screen. After that is done, we
112 * have to redraw previous objects (if theres any).
117 if (debug_track_fonts
)
119 if (cur
->current
->layer
>= 99999)
121 NEURO_TRACE("Destroying font", NULL
);
122 Debug_Val(0, "&0x%x\n", cur
);
126 /* Graphics_DebugQueueIntegrityCheck(); */
131 /* Debug_Val(0, "destroying element address 0x%x\n", cur); */
133 buf
.x
= cur
->current
->dx
;
134 buf
.y
= cur
->current
->dy
;
135 buf
.w
= cur
->current
->src
.w
;
136 buf
.h
= cur
->current
->src
.h
;
139 Lib_BlitObject(background, &buf, sclScreen2, &buf);
141 Lib_FillRect(sclScreen2, &buf, 0);
144 if (dont_redraw_section
== 0)
146 Lib_FillRect(Neuro_GetScreenBuffer(), &buf
, 0);
148 Graphics_RedrawSection(cur
);
151 if (debug_clean_instruction_buffer
)
153 Neuro_CreateEBuf(&verify_m
);
154 Graphics_DebugBufferQueue(verify_m
);
157 if (debug_clean_instruction_buffer
)
159 NEURO_TRACE("*initial values", NULL
);
160 Debug_Val(0, "Amount of elems %d\n", Neuro_GiveEBufCount(verify_m
) - 1);
161 Graphics_DebugPrintMissing(verify_m
);
164 /* only set the previous element (last) if the element we need to
165 * destroy isn't the first one
167 if (cur
!= Graphics_GetFirstElem())
168 last
= get_Previous_Object_To_Object(cur
);
171 /* Debug_Val(0, "changing last's(0x%x) next 0x%x to 0x%x\n", last,
172 last->next, cur->next);*/
174 last
->next
= cur
->next
;
177 /* check to see if the element cur is either first_element
178 * or last_element and if so, we will destituate it.
180 if (cur
== Graphics_GetFirstElem())
182 Graphics_SetFirstElem(cur
->next
);
185 if (cur
== Graphics_GetLastElem())
190 Graphics_SetLastElem(last
);
193 Graphics_SetLastElem(NULL
);
196 if (debug_clean_instruction_buffer
)
198 NEURO_TRACE("*before real destroy", NULL
);
199 Graphics_DebugPrintMissing(verify_m
);
202 /*if (use_memory_pool)
203 Push_Data_To_Pool(POOL_QUEUE, cur);
206 /* INSTRUCTION_ENGINE *temp; */
213 /* Debug_Val(0, "before queue total %d\n",
214 Neuro_GiveEBufCount(_Queue) + 1);*/
216 if (del_mask
== 1 || del_mask
== 3)
217 Neuro_SCleanEBuf(Graphics_GetRawBuffer(), cur
->current
);
218 /* Debug_Val(0, "-- element address 0x%x destroyed\n", cur); */
219 if (del_mask
== 2 || del_mask
== 3)
220 Neuro_SCleanEBuf(Graphics_GetQueueBuffer(), cur
);
222 /* Debug_Val(0, "after queue total %d\n",
223 Neuro_GiveEBufCount(_Queue) + 1); */
227 if (debug_clean_instruction_buffer
)
229 NEURO_TRACE("**After the destroy", NULL
);
230 /*Debug_Val(0, "Amount of elems in verify %d in queue %d\n",
231 Neuro_GiveEBufCount(verify_m) - 1,
232 Neuro_GiveEBufCount(_Queue) - 1);*/
233 NEURO_TRACE("**Full output", NULL
);
235 Graphics_DebugPrintQueue();
237 Graphics_DebugPrintMissing(verify_m
);
238 Neuro_CleanEBuf(&verify_m
);
241 /* Graphics_DebugQueueIntegrityCheck(); */
245 clean_object(INSTRUCTION_ENGINE
*cur
, int dont_redraw_section
)
247 Core_clean_object(cur
, dont_redraw_section
, 3);
250 /*-------------------- Global Functions ----------------------------*/
252 /* take note that we don't do any checks for valid pointers and such
253 * this function is supposed to be a backbone to an interface function
254 * which itself does the parity checks.
257 Graphics_DestroyElement(INSTRUCTION_ENGINE
*elem
)
262 /* we destroy only the queue buffer because we want to make
263 * the emplacement of the element into a more comfortable
264 * place for the algorithm to avoid glitches.
269 /* we clean only the queue element and keep the raw engine buffer */
270 Core_clean_object(elem
, 1, 2);
275 tmp
->type
= TDRAW_SDESTROY
;
277 /* we put the raw buffer back into the queue */
278 Graphics_PushRaw(tmp
);
282 Graphics_CoreDrawAll()
285 INSTRUCTION_ENGINE
*cur
, *last
= NULL
;
286 u32 safety
= 10000; /* safety decrementor to avoid death loop */
288 if (Neuro_EBufIsEmpty(Graphics_GetQueueBuffer()))
291 cur
= Graphics_GetFirstElem();
293 /* start the real drawing */
299 NEURO_ERROR("To avoid a death loop, had to bail out of the instruction loop after 1000 loops", NULL
);
300 break; /* safety break */
305 if (check_integrity_on_draw
)
307 NEURO_TRACE("Data integrity check before drawing", NULL
);
308 Graphics_DebugQueueIntegrityCheck();
311 memcpy(&isrc
, &cur
->current
->src
, sizeof(Rectan
));
313 idst
.x
= cur
->current
->dx
;
314 idst
.y
= cur
->current
->dy
;
316 if (debug_instruction_buffer
)
317 Debug_Val(0, "%s Flushing type %d layer %d\n", __FUNCTION__
, cur
->current
->type
, cur
->current
->layer
);
319 /* draw the surface_ptr to the screen buffer. */
320 switch (cur
->current
->type
)
325 /* Debug_Val(0, "static draw (%d,%d) %dx%d to (%d,%d)\n",
326 isrc.x, isrc.y, isrc.w, isrc.h,
332 Lib_BlitObject(cur
->current
->surface_ptr
, &isrc
, Neuro_GetScreenBuffer(),
335 cur
->current
->type
= TDRAW_SDRAWN
;
337 /* Graphics_RedrawSection(cur); */
339 /* Debug_Val(0, "drawn static\n"); */
341 if (debug_track_fonts
)
343 if (cur
->current
->layer
>= 99999)
345 NEURO_TRACE("Drawing font", NULL
);
346 Debug_Val(0, "Coord (%d,%d) &0x%x\n",
348 cur
->current
->dy
, cur
);
356 /* nothing needed for this type */
357 /* Debug_Val(0, "already drawn\n"); */
363 /* Debug_Val(0, "address of surface 0x%x\n", cur->current->surface_ptr); */
365 /* now we redraw the actual element */
366 Lib_BlitObject(cur
->current
->surface_ptr
, &isrc
, Neuro_GetScreenBuffer(),
369 /* we cleanly redrawn the static element so we
370 * set the element's flag to drawn
372 cur
->current
->type
= TDRAW_SDRAWN
;
374 /* then we redraw the stuff that could have been
375 * there and actually need to be visible(and are above
376 * our element, ie layers).
378 * broken for some reason
380 Graphics_RedrawSection(cur
);
382 /* Debug_Val(0, "Redrawn a static element\n"); */
388 INSTRUCTION_ENGINE
*tmp
;
390 if (cur->current->layer > 1000)
391 Debug_Print("Cleaned a static image");
398 clean_object(tmp
, 0);
400 /* we restart the loop completely since we need to draw
401 * the volatile types first before drawing the rest..
403 cur
= Graphics_GetFirstElem();
412 Lib_BlitObject(cur
->current
->surface_ptr
, &isrc
,
413 Neuro_GetScreenBuffer(), &idst
);
415 cur
->current
->type
= TDRAW_DYNAMIC_CLEAN
;
418 Debug_Val(0, "Dynamic : Tagging addr %x to clean\n", cur
);
419 /* Debug_Val(0, "drawn dynamic\n"); */
424 case TDRAW_DYNAMIC_CLEAN
:
426 /* Lib_BlitObject(cur->current->surface_ptr, &isrc,
427 sclScreen2, &idst);*/
429 /* clean_object(cur); */
436 /*Debug_Val(0, "Volatile draw (%d,%d) %dx%d to (%d,%d) image 0x%x\n",
437 isrc.x, isrc.y, isrc.w, isrc.h,
439 cur->current->surface_ptr);
442 Lib_BlitObject(cur
->current
->surface_ptr
, &isrc
,
443 Neuro_GetScreenBuffer(), &idst
);
445 /* NOTE that we CAN't USE clean_object() BECAUSE
446 * it actually makes the image all BLACK
447 * so it nullifies the action of this COMPLETELY.
450 last
->next
= cur
->next
;
452 /* check to see if the element cur is either first_element
453 * or last_element and if so, we will destituate it.
455 if (cur
== Graphics_GetFirstElem())
457 Graphics_SetFirstElem(cur
->next
);
460 if (cur
== Graphics_GetLastElem())
465 Graphics_SetLastElem(last
);
470 /*if (use_memory_pool)
471 Push_Data_To_Pool(POOL_QUEUE, cur);
474 INSTRUCTION_ENGINE
*temp
;
479 Neuro_SCleanEBuf(Graphics_GetRawBuffer(), temp
->current
);
480 Neuro_SCleanEBuf(Graphics_GetQueueBuffer(), temp
);
491 Debug_Val(0, "ERROR Draw unknown type %d\n", cur
->current
->type
);
499 if (cur
->next
== NULL
&& cur
!= Graphics_GetLastElem())
501 NEURO_ERROR("cur->next is NULL AND it isn't the last element, bad, very bad...", NULL
);
510 Graphics_SetDrawnLastCycle();
511 /* Lib_FillRect(sclScreen, &test_BoundFix, 0); */
515 Graphics_SetAllToRedraw()
517 INSTRUCTION_ENGINE
*cur
;
519 cur
= Graphics_GetFirstElem();
526 if (cur
->current
->type
== TDRAW_SDRAWN
)
527 cur
->current
->type
= TDRAW_STATIC
; /* TDRAW_SREDRAW seems to do a flaw */
532 if (debug_instruction_buffer
)
533 NEURO_TRACE("Just Set all the instructions to be redrawn", NULL
);
536 /* Graphics_CoreCleanAll might have cleaned objects
537 * that should be drawn so we will redraw those in this
539 * returns non zero if a volatile type was pushed
542 Graphics_RedrawSection(INSTRUCTION_ENGINE
*indep
)
544 Rectan buf
, indep_body
;
545 INSTRUCTION_ENGINE
*cur
;
550 indep_body
.x
= indep
->current
->dx
;
551 indep_body
.y
= indep
->current
->dy
;
552 indep_body
.w
= indep
->current
->src
.w
;
553 indep_body
.h
= indep
->current
->src
.h
;
555 cur
= Graphics_GetFirstElem();
571 Debug_Val(0, "BAD : the instruction 0x%x has an empty content!\n",
574 Debug_Val(0, "DEBUG data : indep 0x%x its next element 0x%x\n",
576 /* odd error, this ain't supposed to happen :L */
580 if (debug_track_fonts
)
582 if (cur
->current
->layer
>= 99999 && indep
->current
->layer
>= 99999)
584 NEURO_TRACE("INITIAL Redrawing font", NULL
);
586 Debug_Val(0, "Font type %d (%d,%d) &0x%x\n", cur
->current
->type
,
591 if (cur
->current
->type
== TDRAW_SDRAWN
)
594 buf
.x
= cur
->current
->dx
;
595 buf
.y
= cur
->current
->dy
;
596 buf
.w
= cur
->current
->src
.w
;
597 buf
.h
= cur
->current
->src
.h
;
599 bounds_ret
= Neuro_BoundsCheck(&indep_body
, &buf
);
600 /* bounds_ret = 2; */
602 if (debug_track_fonts
)
604 if (cur
->current
->layer
>= 99999 && indep
->current
->layer
>= 99999)
606 NEURO_TRACE("INITIAL 2 Redrawing font", NULL
);
607 Debug_Val(0, "bounds_ret %d current (%d,%d) indep (%d,%d)\n",
610 indep_body
.x
, indep_body
.y
);
618 bufa
.x
= cur
->current
->dx
;
619 bufa
.y
= cur
->current
->dy
;
623 Neuro_PushVolatileDraw(cur
->current
->layer
, &cur
->current
->src
,
624 &bufa
, cur
->current
->surface_ptr
);
626 /*Debug_Val(0, "dynamic is inside this object\n");*/
628 if (debug_track_fonts
)
630 if (cur
->current
->layer
>= 99999)
631 NEURO_TRACE("Redrawing font #0", NULL
);
641 memcpy(&isrc
, &cur
->current
->src
, sizeof(Rectan
));
643 idst
.x
= cur
->current
->dx
;
644 idst
.y
= cur
->current
->dy
;
648 Neuro_VerticalBoundCrop(&indep_body
, &isrc
, &idst
);
649 Neuro_HorizontalBoundCrop(&indep_body
, &isrc
, &idst
);
651 Neuro_PushVolatileDraw(cur
->current
->layer
,
652 &isrc
, &idst
, cur
->current
->surface_ptr
);
654 if (debug_track_fonts
)
656 if (cur
->current
->layer
>= 99999)
657 NEURO_TRACE("Redrawing font #2", NULL
);
665 Rectan isrc
, idst
, hack
;
667 memcpy(&isrc
, &cur
->current
->src
, sizeof(Rectan
));
669 idst
.x
= cur
->current
->dx
;
670 idst
.y
= cur
->current
->dy
;
675 if (indep_body
.x
> buf
.x
)
677 isrc
.x
+= indep_body
.x
- buf
.x
;
678 idst
.x
+= indep_body
.x
- buf
.x
;
680 /*isrc.y += buf.y - indep_body.y;
681 idst.y += buf.y - indep_body.y;*/
683 isrc
.w
-= buf
.w
- indep_body
.w
;
684 /* isrc.h += indep_body.h - buf.h; */
688 /*isrc.x += buf.x - indep_body.x;
689 idst.x += buf.x - indep_body.x;*/
691 isrc
.y
+= indep_body
.y
- buf
.y
;
692 idst
.y
+= indep_body
.y
- buf
.y
;
694 /* isrc.w += indep_body.w - buf.w; */
695 isrc
.h
-= buf
.h
- indep_body
.h
;
698 /* Neuro_PushVolatileDraw(cur->current->layer,
699 &isrc, &idst, cur->current->surface_ptr);*/
701 /* temporary hack that seems to work, we draw the whole
702 * static image... this needs testing and a better
706 hack
.x
= cur
->current
->dx
;
707 hack
.y
= cur
->current
->dy
;
711 Neuro_PushVolatileDraw(cur
->current
->layer
, &cur
->current
->src
,
712 &hack
, cur
->current
->surface_ptr
);
714 /*Debug_Val(0, "we have a case 3 situation!\n");*/
716 if (debug_track_fonts
)
718 if (cur
->current
->layer
>= 99999)
719 NEURO_TRACE("Redrawing font #3", NULL
);
725 /* indep is inside cur */
731 bufa
.x
= indep_body
.x
;
732 bufa
.y
= indep_body
.y
;
736 nsrc
.x
= indep_body
.x
- cur
->current
->dx
;
737 nsrc
.y
= indep_body
.y
- cur
->current
->dy
;
738 nsrc
.w
= indep_body
.w
;
739 nsrc
.h
= indep_body
.h
;
749 nsrc.w = cur->current->src.w;
750 nsrc.h = cur->current->src.h;
753 Neuro_PushVolatileDraw(cur
->current
->layer
, &nsrc
,
754 &bufa
, cur
->current
->surface_ptr
);
756 if (debug_track_fonts
)
758 if (cur
->current
->layer
>= 99999)
759 NEURO_TRACE("Redrawing font #4", NULL
);
765 /* Debug_Val(0, "Redraw Section debug #%d\n", bounds_ret); */
774 Graphics_CoreCleanAll()
776 INSTRUCTION_ENGINE
*cur
;
778 cur
= Graphics_GetFirstElem();
783 /* "reset" the emplacement of the last position of the image
784 * with the background if theres one or with the color black
789 clean_object(cur
, 1);
794 Graphics_ResetScreenDraw();
797 /* only clean those with the type TDRAW_DYNAMIC_CLEAN */
799 Graphics_CoreCleanDoneDynamics()
801 INSTRUCTION_ENGINE
*cur
;
803 cur
= Graphics_GetFirstElem();
808 /* "reset" the emplacement of the last position of the image
809 * with the background if theres one or with the color black
814 if (cur
->current
->type
== TDRAW_DYNAMIC_CLEAN
)
816 clean_object(cur
, 0);
824 Graphics_FreeVObject(v_object
*source
)
826 INSTRUCTION_ENGINE
*cur
, *tmp
;
828 /* this function was made to avoid the painter's algorithm
829 * to have an element contain an image surface that was
830 * freed before it was processed resulting in a segmentation
834 cur
= Graphics_GetFirstElem();
840 if (cur
->current
->surface_ptr
== source
)
842 /*if (cur->current->type == TDRAW_SDRAWN)
843 Neuro_DestroyDraw(cur);
845 Core_clean_object(cur
, 0, 3);
852 Lib_FreeVobject(source
);