Sprite example.

This commit is contained in:
Scott Duensing 2024-01-20 19:48:23 -06:00
parent 76ffdf3677
commit 1a2fc959c6
19 changed files with 493 additions and 15 deletions

2
.gitattributes vendored
View file

@ -1,3 +1,4 @@
*.xcf filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text *.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text *.jpg filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text *.gif filter=lfs diff=lfs merge=lfs -text
@ -8,3 +9,4 @@
*.map filter=lfs diff=lfs merge=lfs -text *.map filter=lfs diff=lfs merge=lfs -text
*.clut filter=lfs diff=lfs merge=lfs -text *.clut filter=lfs diff=lfs merge=lfs -text
*.indexed filter=lfs diff=lfs merge=lfs -text *.indexed filter=lfs diff=lfs merge=lfs -text
*.sprite filter=lfs diff=lfs merge=lfs -text

1
.gitignore vendored
View file

@ -40,6 +40,7 @@ intelFPGA_lite/
/header /header
/imageconvert /imageconvert
include/ include/
generated/
# Dumb QtCreator junk # Dumb QtCreator junk
build-*/ build-*/

View file

@ -152,7 +152,6 @@ int main(void) {
f256Init(); f256Init();
textSetCursor(0); // No cursor.
textSetColor(15, 0); textSetColor(15, 0);
// Clear two graphics pages. // Clear two graphics pages.
@ -204,8 +203,6 @@ int main(void) {
line[l][t].y2 = cubeProjY[edges[i + 1]]; line[l][t].y2 = cubeProjY[edges[i + 1]];
l++; l++;
} }
kernelUpdate();
} }
textClear(); textClear();

View file

@ -0,0 +1,52 @@
#
# Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# This is only to make my IDE happy.
# We can't actually build with it until I get llvm-mos integrated into
# toolchains. -- SCD
cmake_minimum_required(VERSION 3.22)
set(CMAKE_C_STANDARD 17)
project(helicopter)
set(F256DIR ${CMAKE_SOURCE_DIR}/../..)
set(DEFINES ${F256DIR}/include)
set(F256LIB ${F256DIR}/f256lib)
set(HELICOPTER_SOURCE
${F256LIB}/f256.h
${F256LIB}/f256.c
helicopter.c
)
add_executable(${CMAKE_PROJECT_NAME}
${HELICOPTER_SOURCE}
)
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC
${CMAKE_SOURCE_DIR}
${DEFINES}
${F256LIB}
)

BIN
examples/sprites/assets/apache-left-front.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/sprites/assets/apache-left.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/sprites/assets/apache-right-front.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/sprites/assets/apache-right.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/sprites/assets/apache.png (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

58
examples/sprites/build.sh Executable file
View file

@ -0,0 +1,58 @@
#!/bin/bash -ex
#
# Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
PROJECT=helicopter
START=0x200
F256=../..
LLVM=${F256}/llvm-mos
SETTINGS=${LLVM}/mos-platform/f256k/lib/settings.ld
PATH=${LLVM}/bin:${PATH}
echo "__f256_start = ${START};" > ${SETTINGS}
CLANG="mos-f256k-clang -I${F256}/include -I${F256}/f256lib -O3"
${CLANG} -c ${F256}/f256lib/f256.c
${CLANG} -c ${PROJECT}.c
${CLANG} -o ${PROJECT} ${PROJECT}.o f256.o
mv -f ${PROJECT} ${PROJECT}.bin
${F256}/header \
pgz 24 \
${PROJECT}.pgz \
${START} \
${PROJECT}.bin ${START} \
generated/apache-left.sprite 0x10000 \
generated/apache-left-front.sprite 0x12800 \
generated/apache-right-front.sprite 0x15000 \
generated/apache-right.sprite 0x17800 \
generated/apache-left.clut 0x1a000
llvm-nm ${PROJECT}.elf > ${PROJECT}.sym
llvm-objdump -d --print-imm-hex ${PROJECT}.elf > ${PROJECT}.lst
hexdump -C ${PROJECT}.pgz > ${PROJECT}.hex

View file

@ -0,0 +1,7 @@
[DEFAULT]
port=/dev/ttyUSB1
labels=sample.lbl
flash_address=380000
chunk_size=1024
cpu=65c02
data_rate=6000000

View file

@ -0,0 +1,271 @@
/*
* Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "f256.h"
#define SPRITE_COUNT 4
#define SPRITE_SIZE 32
#define SPRITE_WIDTH 5
#define SPRITE_HEIGHT 2
#define SPR_LEFT 0
#define SPR_LEFT_ADDR 0x10000
#define SPR_LEFT_FRONT 1
#define SPR_LEFT_FRONT_ADDR 0x12800
#define SPR_RIGHT_FRONT 2
#define SPR_RIGHT_FRONT_ADDR 0x15000
#define SPR_RIGHT 3
#define SPR_RIGHT_ADDR 0x17800
#define SPR_CLUT 0x1a000
#define SPR_CLUT_COLORS 32
#define TURN_SPEED 25
static byte sprites[SPRITE_COUNT] = { SPR_LEFT, SPR_LEFT_FRONT, SPR_RIGHT_FRONT, SPR_RIGHT };
static uint32_t spriteStartAddrs[SPRITE_COUNT] = { SPR_LEFT_ADDR, SPR_LEFT_FRONT_ADDR, SPR_RIGHT_FRONT_ADDR, SPR_RIGHT_ADDR };
static uint32_t spriteAddrs[SPRITE_COUNT][SPRITE_WIDTH][SPRITE_HEIGHT];
static byte spriteIds[SPRITE_COUNT][SPRITE_WIDTH][SPRITE_HEIGHT];
static byte anyJoy;
void drawHelicopter(void) {
static byte last = SPR_RIGHT; // Last frame used, can be anything other than "frame".
static byte frame = SPR_RIGHT_FRONT;
static byte lag = 0;
static uint16_t xSize = (SPRITE_WIDTH * SPRITE_SIZE);
static uint16_t ySize = (SPRITE_HEIGHT * SPRITE_SIZE);
static uint16_t xPos = 96; // (352 / 2) - (xSize / 2);
static uint16_t yPos = 104; // (272 / 2) - (ySize / 2);
byte i;
byte j;
// New frame?
if (last != frame) {
for (j=0; j<SPRITE_HEIGHT; j++) {
for (i=0; i<SPRITE_WIDTH; i++) {
spriteSetPosition(spriteIds[frame][i][j], mathUnsignedAddition(xPos, mathUnsignedMultiply(i, 32)), mathUnsignedAddition(yPos, mathUnsignedMultiply(j, 32)));
spriteSetVisible(spriteIds[frame][i][j], true);
spriteSetVisible(spriteIds[last][i][j], false);
}
}
last = frame;
}
// Move sprite.
if (anyJoy != 0) {
if (anyJoy & JOY_UP) {
if (yPos > 32) yPos--;
}
if (anyJoy & JOY_DOWN) {
if (yPos + ySize < 271) yPos++;
}
if (anyJoy & JOY_LEFT) {
if (xPos > 32) xPos--;
if (frame > SPR_LEFT) {
if (lag == 0) {
lag = TURN_SPEED;
} else {
lag--;
if (lag == 0) frame--;
}
}
}
if (anyJoy & JOY_RIGHT) {
if (xPos + xSize < 351) xPos++;
if (frame < SPR_RIGHT) {
if (lag == 0) {
lag = TURN_SPEED;
} else {
lag--;
if (lag == 0) frame++;
}
}
}
// Update sprite positions.
for (j=0; j<SPRITE_HEIGHT; j++) {
for (i=0; i<SPRITE_WIDTH; i++) {
spriteSetPosition(spriteIds[frame][i][j], mathUnsignedAddition(xPos, mathUnsignedMultiply(i, 32)), mathUnsignedAddition(yPos, mathUnsignedMultiply(j, 32)));
}
}
} // (anyJoy != 0)
}
void getInput(void) {
static byte oneJoy = 0;
static byte twoJoy = 0;
static byte keyJoy = 0;
kernelCall(NextEvent);
// Read real joysticks.
if (kernelEvent(JOYSTICK)) {
oneJoy = kernelEventData.joystick.joy0;
twoJoy = kernelEventData.joystick.joy1;
anyJoy = oneJoy | twoJoy | keyJoy;
}
// Use keyboard as virtual joystick.
// ***TODO*** This doesn't work worth a crap.
if (kernelEvent(key.PRESSED)) {
switch (kernelEventData.key.ascii) {
case 'w':
case 'W':
keyJoy |= JOY_UP;
break;
case 'a':
case 'A':
keyJoy |= JOY_LEFT;
break;
case 's':
case 'S':
keyJoy |= JOY_DOWN;
break;
case 'd':
case 'D':
keyJoy |= JOY_RIGHT;
break;
case 'j':
case 'J':
keyJoy |= JOY_BUTTON_1;
break;
case 'k':
case 'K':
keyJoy |= JOY_BUTTON_2;
break;
case 'l':
case 'L':
keyJoy |= JOY_BUTTON_3;
break;
}
anyJoy = oneJoy | twoJoy | keyJoy;
}
if (kernelEvent(key.RELEASED)) {
switch (kernelEventData.key.ascii) {
case 'w':
case 'W':
keyJoy &= JOY_UP;
break;
case 'a':
case 'A':
keyJoy &= JOY_LEFT;
break;
case 's':
case 'S':
keyJoy &= JOY_DOWN;
break;
case 'd':
case 'D':
keyJoy &= JOY_RIGHT;
break;
case 'j':
case 'J':
keyJoy &= JOY_BUTTON_1;
break;
case 'k':
case 'K':
keyJoy &= JOY_BUTTON_2;
break;
case 'l':
case 'L':
keyJoy &= JOY_BUTTON_3;
break;
anyJoy = oneJoy | twoJoy | keyJoy;
}
}
/*
textGotoXY(0, 0);
textPrintInt(oneJoy);
textPrint(" ");
textPrintInt(twoJoy);
textPrint(" ");
textPrintInt(keyJoy);
textPrint(" ");
textPrintInt(anyJoy);
textPrint(" ");
*/
}
void setup(void) {
byte i;
byte j;
byte s;
byte r;
byte g;
byte b;
uint32_t c;
// Set up CLUT0.
c = SPR_CLUT;
for (i=0; i<SPR_CLUT_COLORS; i++) {
b = FAR_PEEK(c++);
g = FAR_PEEK(c++);
r = FAR_PEEK(c++);
c++;
graphicsDefineColor(0, i, r, g, b);
}
// Sprite addresses and definitions.
r = 0;
for (s=0; s<SPRITE_COUNT; s++) {
c = spriteStartAddrs[s];
for (j=0; j<SPRITE_HEIGHT; j++) {
for (i=0; i<SPRITE_WIDTH; i++) {
spriteIds[s][i][j] = r++;
spriteAddrs[s][i][j] = c;
c = mathUnsignedAddition(c, mathUnsignedMultiply(SPRITE_SIZE, SPRITE_SIZE));
spriteDefine(spriteIds[s][i][j], spriteAddrs[s][i][j], SPRITE_SIZE, 0, 0);
spriteSetVisible(spriteIds[s][i][j], false);
}
}
}
}
int main(void) {
f256Init();
setup();
while (true) {
getInput();
drawHelicopter();
}
return 0;
}

View file

@ -0,0 +1,37 @@
#!/bin/bash
F256DIR=../..
IC=${F256DIR}/imageconvert
function makeSprite() {
local NAME=$1
${IC} sprite 32 assets/${NAME}.png
mkdir -p generated
mv assets/*.clut generated/.
mv assets/*.indexed generated/.
cat generated/${NAME}-1x1.indexed \
generated/${NAME}-2x1.indexed \
generated/${NAME}-3x1.indexed \
generated/${NAME}-4x1.indexed \
generated/${NAME}-5x1.indexed \
generated/${NAME}-1x2.indexed \
generated/${NAME}-2x2.indexed \
generated/${NAME}-3x2.indexed \
generated/${NAME}-4x2.indexed \
generated/${NAME}-5x2.indexed \
> generated/${NAME}.sprite
rm generated/*.indexed
}
makeSprite apache-left
makeSprite apache-left-front
makeSprite apache-right-front
makeSprite apache-right

26
examples/sprites/run.sh Executable file
View file

@ -0,0 +1,26 @@
#!/bin/bash
#
# Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
python ../../FoenixMgr/FoenixMgr/fnxmgr.py --run-pgz helicopter.pgz

View file

@ -85,7 +85,7 @@ void graphicsSetLayerBitmap(byte layer, byte which) {
POKE(VKY_LAYER_CTRL_0, (PEEK(VKY_LAYER_CTRL_0) & 0x0f) | (which << 4)); POKE(VKY_LAYER_CTRL_0, (PEEK(VKY_LAYER_CTRL_0) & 0x0f) | (which << 4));
break; break;
case 2: case 2:
POKE(VKY_LAYER_CTRL_1, which); POKE(VKY_LAYER_CTRL_1, which); //***TODO*** This doesn't work?
break; break;
} }
} }

View file

@ -167,14 +167,24 @@ void textPrint(char *message) {
void textPrintInt(int32_t value){ void textPrintInt(int32_t value){
char c[2];
if (value < 0) { if (value < 0) {
textPrint("-"); textPrint("-");
value = -value; value = -value;
} }
textPrintUInt(value);
}
if (value > 9) textPrintInt(mathUnsignedDivision(value, 10));
void textPrintUInt(uint32_t value){
char c[2];
if (value > 9) {
if (value > 65535) {
textPrintUInt(value / 10); // Can't use the coprocessor for uint32.
} else {
textPrintUInt(mathUnsignedDivision(value, 10));
}
}
c[0] = '0' + (value % 10); c[0] = '0' + (value % 10);
c[1] = 0; c[1] = 0;

View file

@ -65,6 +65,7 @@ void textGetXY(byte *x, byte *y);
void textGotoXY(byte x, byte y); void textGotoXY(byte x, byte y);
void textPrint(char *message); void textPrint(char *message);
void textPrintInt(int32_t value); void textPrintInt(int32_t value);
void textPrintUInt(uint32_t value);
void textReset(void); void textReset(void);
void textSetColor(byte f, byte b); void textSetColor(byte f, byte b);
void textSetCursor(byte c); void textSetCursor(byte c);

View file

@ -30,11 +30,11 @@
#include "../shared/util.h" #include "../shared/util.h"
int writeImage(byte *data, colorT *palette, int colors, char *filename, int xs, int ys, int width, int height) { int writeImage(byte *data, int imageWidth, colorT *palette, int colors, char *filename, int xs, int ys, int width, int height) {
int x; int x;
int y; int y;
int n; int n;
byte *p; int a;
colorT c; colorT c;
FILE *out; FILE *out;
@ -46,16 +46,17 @@ int writeImage(byte *data, colorT *palette, int colors, char *filename, int xs,
} }
for (y=ys; y<ys+height; y++) { for (y=ys; y<ys+height; y++) {
for (x=xs; x<xs+width; x++) { for (x=xs; x<xs+width; x++) {
p = &data[(y * width + x) * 3]; a = (y * imageWidth * 3) + (x * 3);
c.r = *p++; c.r = data[a++];
c.g = *p++; c.g = data[a++];
c.b = *p++; c.b = data[a++];
for (n=0; n<colors; n++) { for (n=0; n<colors; n++) {
if ((palette[n].r == c.r) && (palette[n].g == c.g) && (palette[n].b == c.b)) { if ((palette[n].r == c.r) && (palette[n].g == c.g) && (palette[n].b == c.b)) {
fputc(n, out); fputc(n, out);
break; break;
} }
} }
// This should never happen.
if (n == colors) { if (n == colors) {
printf("Color (%d, %d, %d) not found at %dx%d! Aborting.\n", c.r, c.g, c.b, x, y); printf("Color (%d, %d, %d) not found at %dx%d! Aborting.\n", c.r, c.g, c.b, x, y);
printf("Palette:\n"); printf("Palette:\n");
@ -199,7 +200,7 @@ int main(int argc, char *argv[]) {
if (spriteSize == 0) { if (spriteSize == 0) {
// Write out raw indexed image. // Write out raw indexed image.
filename = utilReplaceExtension(inputImage, ".indexed"); filename = utilReplaceExtension(inputImage, ".indexed");
n = writeImage(data, palette, colors, filename, 0, 0, w, h); n = writeImage(data, w, palette, colors, filename, 0, 0, w, h);
free(filename); free(filename);
if (n != 0) { if (n != 0) {
free(data); free(data);
@ -214,7 +215,7 @@ int main(int argc, char *argv[]) {
for (x=0; x<w; x+=spriteSize) { for (x=0; x<w; x+=spriteSize) {
filename = utilCreateString("%s-%dx%d.indexed", temp, i++, j); filename = utilCreateString("%s-%dx%d.indexed", temp, i++, j);
printf("Writing from %dx%d to %dx%d for %d bytes\n", x, y, x+spriteSize, y+spriteSize, spriteSize*spriteSize); printf("Writing from %dx%d to %dx%d for %d bytes\n", x, y, x+spriteSize, y+spriteSize, spriteSize*spriteSize);
n = writeImage(data, palette, colors, filename, x, y, spriteSize, spriteSize); n = writeImage(data, w, palette, colors, filename, x, y, spriteSize, spriteSize);
free(filename); free(filename);
if (n != 0) { if (n != 0) {
free(temp); free(temp);