Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Dreamcast
Framebuffer Tricks
Commits
e7d3f606
Commit
e7d3f606
authored
Jan 09, 2024
by
Donald Haase
Browse files
Initial commit
parents
Changes
4
Hide whitespace changes
Inline
Side-by-side
FB_tricks.c
0 → 100644
View file @
e7d3f606
/* KallistiOS ##version##
FB_tricks.c
Copyright (C) 2024 Donald Haase
*/
/*
This example loads a series of png images that are appropriately sized to
the display mode into frame buffers and cycles between them. By pressing
different buttons you can trigger different effects on that cycling.
These effects are achieved by manipulating PVR registers and should allow
significant time for parallel tasks.
*/
#include
<kos.h>
#include
<png/png.h>
#include
<kos/img.h>
/* Init just the basic necessaries */
KOS_INIT_FLAGS
(
INIT_IRQ
|
INIT_FS_ROMDISK
|
INIT_CONTROLLER
);
const
char
*
filenames
[]
=
{
"%s/PhillyGENSNL.png"
,
"%s/SteamBoat.png"
};
#define FILE_COUNT (sizeof(filenames)/sizeof(filenames[0]))
#define FILE_ROOT "/rd"
#define TIMEOUT_SECS 2
/* These might be something to add into video.c */
void
vid_disable
(
void
)
{
/* Blank screen and reset display enable (looks nicer) */
PVR_SET
(
PVR_VIDEO_CFG
,
PVR_GET
(
PVR_VIDEO_CFG
)
|
8
);
/* Blank */
PVR_SET
(
PVR_FB_CFG_1
,
PVR_GET
(
PVR_FB_CFG_1
)
&
~
1
);
/* Display disable */
}
void
vid_enable
(
void
)
{
/* Re-enable the display */
PVR_SET
(
PVR_VIDEO_CFG
,
PVR_GET
(
PVR_VIDEO_CFG
)
&
~
8
);
PVR_SET
(
PVR_FB_CFG_1
,
PVR_GET
(
PVR_FB_CFG_1
)
|
1
);
}
void
vid_shake
(
char
speed
)
{
uint32
bitmapy
=
vid_mode
->
bitmapy
;
int
i
,
j
;
int
shake_dist
=
24
;
int
shake_stride
=
2
;
printf
(
"Commence the shaking!
\n
"
);
for
(
i
=
0
;
i
<
5
;
i
++
)
{
for
(
j
=
(
shake_dist
*
-
1
);
j
<
shake_dist
;
j
+=
shake_stride
)
{
PVR_SET
(
PVR_BITMAP_Y
,
((
bitmapy
+
j
)
<<
16
)
|
(
bitmapy
+
j
));
thd_sleep
(
5
);
}
for
(
j
=
shake_dist
;
j
>
(
shake_dist
*
-
1
);
j
-=
shake_stride
)
{
PVR_SET
(
PVR_BITMAP_Y
,
((
bitmapy
+
j
)
<<
16
)
|
(
bitmapy
+
j
));
thd_sleep
(
5
);
}
}
/* Go back to start */
PVR_SET
(
PVR_BITMAP_Y
,
(
vid_mode
->
bitmapy
<<
16
)
|
vid_mode
->
bitmapy
);
printf
(
"Shaking completed.
\n
"
);
}
void
vid_rotate
(
int
rotations
)
{
/* If VID_MAX_FB exists, then we're in v2.1.0 and below multibuffer */
#ifdef VID_MAX_FB
uint32
old_base
=
(
fb_base
[
vid_mode
->
fb_curr
])
&
0x007FFFFF
;
#else
uint32
old_base
=
(
vid_mode
->
fb_size
*
vid_mode
->
fb_curr
)
&
0x007FFFFF
;
#endif
uint32
stride_div
=
8
;
uint32
stride
=
((
vid_mode
->
width
/
stride_div
)
*
vid_pmode_bpp
[
vid_mode
->
pm
]);
int32
i
,
dir
=
1
;
for
(;
rotations
>
0
;
rotations
--
)
{
for
(
i
=
0
;
i
<
stride_div
;
i
++
)
{
old_base
+=
(
stride
*
dir
);
/* Set vram base of current framebuffer */
PVR_SET
(
PVR_FB_ADDR
,
old_base
);
/* Set odd-field if interlaced. */
if
(
vid_mode
->
flags
&
VID_INTERLACE
)
PVR_SET
(
PVR_FB_IL_ADDR
,
old_base
+
(
vid_mode
->
width
*
vid_pmode_bpp
[
vid_mode
->
pm
]));
thd_sleep
(
16
*
stride_div
);
}
dir
*=
-
1
;
}
/* Set back to start value */
#ifdef VID_MAX_FB
old_base
=
(
fb_base
[
vid_mode
->
fb_curr
])
&
0x007FFFFF
;
#else
old_base
=
(
vid_mode
->
fb_size
*
vid_mode
->
fb_curr
)
&
0x007FFFFF
;
#endif
PVR_SET
(
PVR_FB_ADDR
,
old_base
);
/* Set odd-field if interlaced. */
if
(
vid_mode
->
flags
&
VID_INTERLACE
)
PVR_SET
(
PVR_FB_IL_ADDR
,
old_base
+
(
vid_mode
->
width
*
vid_pmode_bpp
[
vid_mode
->
pm
]));
}
/* This is a replacement for 'vid_flip' that scrolls the FB vertically into an adjascent one.
dir sets the direction for it to go 1 for forward -1 for backwards. Any other value will
default to forward. If asked to go in a direction with no more FBs, will go the other. */
/* 1 for forward, -1 for backwards, returns direction in case it has to bounce back or 0 on error */
char
vid_flip_fun
(
char
dir
,
char
stride_div
)
{
/* This requires the new MB concept to work right. */
#ifdef VID_MAX_FB
return
0
;
#else
uint32
old_base
=
(
vid_mode
->
fb_size
*
vid_mode
->
fb_curr
)
&
0x007FFFFF
;
uint32
new_base
;
uint32
stride
=
((
vid_mode
->
width
/
stride_div
)
*
vid_pmode_bpp
[
vid_mode
->
pm
]);
/* If we don't have multiple buffers set up, just kick back error */
if
(
vid_mode
->
fb_count
==
1
)
return
0
;
/* Lets default to 'forward' */
if
(
(
dir
!=
1
)
&&
(
dir
!=
-
1
)
)
dir
=
1
;
/* Check if we'd roll over in either direction, if so flip direction */
if
((
((
vid_mode
->
fb_curr
+
1
)
==
(
vid_mode
->
fb_count
))
&&
(
dir
==
1
)
)
||
(
(
vid_mode
->
fb_curr
==
0
)
&&
(
dir
==
-
1
)
))
dir
=
-
1
*
dir
;
/* Move the fb_curr in the desired direction */
vid_mode
->
fb_curr
+=
dir
;
/* Set the new base address for the fb */
new_base
=
(
vid_mode
->
fb_size
*
vid_mode
->
fb_curr
)
&
0x007FFFFF
;
for
(;
old_base
!=
new_base
;
old_base
+=
(
dir
*
stride
))
{
/* Set vram base of current framebuffer */
PVR_SET
(
PVR_FB_ADDR
,
old_base
);
/* Set odd-field if interlaced. */
if
(
vid_mode
->
flags
&
VID_INTERLACE
)
PVR_SET
(
PVR_FB_IL_ADDR
,
old_base
+
(
vid_mode
->
width
*
vid_pmode_bpp
[
vid_mode
->
pm
]));
thd_sleep
(
16
);
}
/* Set the vram_* pointers as expected */
new_base
=
vid_mode
->
fb_size
*
((
vid_mode
->
fb_curr
+
1
)
%
vid_mode
->
fb_count
);
vram_s
=
(
uint16
*
)(
PVR_RAM_BASE
|
new_base
);
vram_l
=
(
uint32
*
)(
PVR_RAM_BASE
|
new_base
);
return
dir
;
#endif
/* VID_MAX_FB */
}
/* Load a single png into the current writable FB */
int
fb_init
(
int
which
)
{
char
filename
[
80
];
kos_img_t
tmp_img
;
/* Compose the current filename */
snprintf
(
filename
,
sizeof
(
filename
),
filenames
[
which
],
FILE_ROOT
,
vid_mode
->
width
,
vid_mode
->
height
);
png_to_img
(
filename
,
PNG_NO_ALPHA
,
&
tmp_img
);
printf
(
"Loading png %i (%s)
\n
"
,
which
,
filename
);
memcpy
(
vram_s
,
tmp_img
.
data
,
tmp_img
.
byte_count
);
kos_img_free
(
&
tmp_img
,
0
);
return
0
;
}
int
main
(
int
argc
,
char
**
argv
)
{
uint32
done
,
start_secs
,
cur_secs
,
old_buttons
=
0
;
int
f
;
char
dir
=
1
;
/* Press all buttons to exit */
cont_btn_callback
(
0
,
CONT_START
|
CONT_A
|
CONT_B
|
CONT_X
|
CONT_Y
,
(
cont_btn_callback_t
)
arch_exit
);
/* First set the video mode */
vid_set_mode
(
DM_640x480
|
DM_MULTIBUFFER
,
PM_RGB565
);
/* Make sure we have enough FBs to hold the test images */
if
((
FILE_COUNT
)
>
vid_mode
->
fb_count
)
{
printf
(
"Not enough framebuffers to hold all the files, bailing.
\n
"
);
return
-
1
;
}
/* Now restrain the framebuffer cycling to the total we can load */
vid_mode
->
fb_count
=
FILE_COUNT
;
/* Blank the screen so we don't get rapid-fire of the FB's loading */
vid_disable
();
/* Load all the files */
for
(
f
=
0
;
f
<
FILE_COUNT
;
f
++
)
{
/* If we could load the file, move to the next FB */
if
(
fb_init
(
f
)
==
0
)
{
vid_flip
(
-
1
);
}
}
/* Now that all are loaded, lets reenable the screen */
vid_enable
();
/* Lets set a counter that we should rotate through each at least once */
done
=
FILE_COUNT
*
2
;
/* Get a timestamp so that we can flip without intervention.
any button press will disable this timed system until the next mode. */
timer_ms_gettime
(
&
start_secs
,
0
);
/* keep drawing frames until start is pressed */
while
(
done
)
{
/* Find the first controller and try to get it's state, if it's there */
cont_state_t
*
st
=
(
cont_state_t
*
)
maple_dev_status
(
maple_enum_type
(
0
,
MAPLE_FUNC_CONTROLLER
));
/* If there was a controller state and it is different from our last one, check it out */
if
((
st
!=
NULL
)
&&
(
st
->
buttons
!=
old_buttons
))
{
/* Update our last state, this prevents key repeat */
old_buttons
=
st
->
buttons
;
if
(
st
->
buttons
&
CONT_START
)
{
done
=
0
;
continue
;
}
else
if
(
st
->
buttons
&
CONT_A
)
{
vid_shake
(
-
1
);
start_secs
=
0
;
}
else
if
(
st
->
buttons
&
CONT_B
)
{
vid_rotate
(
5
);
start_secs
=
0
;
}
else
if
(
st
->
buttons
&
CONT_Y
)
{
dir
=
vid_flip_fun
(
dir
,
2
);
start_secs
=
0
;
}
}
/* If the timer is still active lets check it */
if
(
start_secs
)
{
timer_ms_gettime
(
&
cur_secs
,
0
);
if
(
cur_secs
>
(
start_secs
+
TIMEOUT_SECS
))
{
start_secs
=
cur_secs
;
//vid_flip(-1);
vid_squish
(
-
1
);
done
--
;
continue
;
}
}
}
return
0
;
}
Makefile
0 → 100644
View file @
e7d3f606
TARGET
=
FB_tricks.elf
OBJS
=
FB_tricks.o romdisk.o
KOS_ROMDISK_DIR
=
romdisk
all
:
rm-elf $(TARGET)
include
$(KOS_BASE)/Makefile.rules
clean
:
rm-elf
-
rm
-f
$(OBJS)
rm-elf
:
-
rm
-f
$(TARGET)
romdisk.
*
$(TARGET)
:
$(OBJS)
kos-cc
-o
$(TARGET)
$(OBJS)
-lkosutils
-lpng
-lz
-lm
run
:
$(TARGET)
$(KOS_LOADER)
$(TARGET)
dist
:
$(TARGET)
-
rm
-f
$(OBJS)
romdisk_boot.img
$(KOS_STRIP)
$(TARGET)
romdisk/PhillyGENSNL.png
0 → 100644
View file @
e7d3f606
330 KB
romdisk/SteamBoat.png
0 → 100644
View file @
e7d3f606
215 KB
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment