Initial commit.
This commit is contained in:
commit
d9db602f3d
11 changed files with 1412 additions and 0 deletions
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*.png filter=lfs diff=lfs merge=lfs -text
|
||||||
|
a2-3d/A2-3D2\#066000 filter=lfs diff=lfs merge=lfs -text
|
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
.builddir
|
||||||
|
backup/
|
||||||
|
*.iso
|
||||||
|
*~
|
||||||
|
*.pgz
|
||||||
|
apple2/
|
BIN
a2-3d/A2-3D2#066000
(Stored with Git LFS)
Normal file
BIN
a2-3d/A2-3D2#066000
(Stored with Git LFS)
Normal file
Binary file not shown.
73
build.sh
Executable file
73
build.sh
Executable file
|
@ -0,0 +1,73 @@
|
||||||
|
#!/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=shotel
|
||||||
|
|
||||||
|
F256=$(readlink -f $(pwd)/../f256)
|
||||||
|
LLVM=${F256}/llvm-mos
|
||||||
|
PATH=${LLVM}/bin:${PATH}
|
||||||
|
CLANG="mos-f256k-clang -I${F256} -I$(pwd)/src -Os"
|
||||||
|
|
||||||
|
|
||||||
|
# Update f256lib and tools.
|
||||||
|
pushd ${F256}
|
||||||
|
./build-f256lib.sh
|
||||||
|
./build-tools.sh
|
||||||
|
popd
|
||||||
|
|
||||||
|
|
||||||
|
[[ -d .builddir ]] && rm -rf .builddir
|
||||||
|
mkdir -p .builddir
|
||||||
|
|
||||||
|
# Do not use relative paths.
|
||||||
|
${F256}/overlay 5 $(pwd)/.builddir $(pwd)/src
|
||||||
|
|
||||||
|
pushd .builddir
|
||||||
|
|
||||||
|
cp ../a2-3d/A2-3D2#066000 a2-3d2.bin
|
||||||
|
truncate -s 8k a2-3d2.bin
|
||||||
|
|
||||||
|
cc -I../src -I${F256} ../tools/scene.c -o scene
|
||||||
|
./scene
|
||||||
|
|
||||||
|
cat a2-3d2.bin scene.3d > embedded.bin
|
||||||
|
|
||||||
|
${CLANG} -c main.c
|
||||||
|
${CLANG} -c a23d2.c
|
||||||
|
|
||||||
|
${CLANG} -T ../f256.ld \
|
||||||
|
-Wl,-Map=${PROJECT}.map \
|
||||||
|
-o ${PROJECT} \
|
||||||
|
main.o a23d2.o
|
||||||
|
|
||||||
|
mv ${PROJECT} ${PROJECT}.pgz
|
||||||
|
|
||||||
|
llvm-nm ${PROJECT}.elf > ${PROJECT}.sym
|
||||||
|
llvm-objdump --syms -d --print-imm-hex ${PROJECT}.elf > ${PROJECT}.lst
|
||||||
|
hexdump -C ${PROJECT}.pgz > ${PROJECT}.hex
|
||||||
|
python ${F256}/pgz-thunk.py ${PROJECT}.pgz
|
||||||
|
|
||||||
|
mv ${PROJECT}.pgz ../.
|
||||||
|
popd
|
116
f256.ld
Normal file
116
f256.ld
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/* fake C Stack */
|
||||||
|
PROVIDE(__stack = 0xA000);
|
||||||
|
/* entry point to my program */
|
||||||
|
PROVIDE(__f256_start = 0x300);
|
||||||
|
/* page size of a block of memory */
|
||||||
|
PROVIDE(__BLOCK_SIZE = 0x2000);
|
||||||
|
/* swappable block address */
|
||||||
|
PROVIDE(__SLOT_ADDR = 0xA000);
|
||||||
|
|
||||||
|
/* f256k uses first 16 bytes of ZP for mmu control? */
|
||||||
|
__rc0 = 0x10;
|
||||||
|
/* __rc0 = 0xc3; */
|
||||||
|
INCLUDE imag-regs.ld
|
||||||
|
/*
|
||||||
|
ASSERT(__rc0 == 0x10, "Inconsistent zero page map.")
|
||||||
|
ASSERT(__rc31 == 0x2f, "Inconsistent zero page map.")
|
||||||
|
*/
|
||||||
|
|
||||||
|
MEMORY {
|
||||||
|
/* kernel uses 0xf0-0xff for parameter passing */
|
||||||
|
/* A2-3D2 uses 0x60-0xc2 */
|
||||||
|
zp : ORIGIN = __rc31 + 1, LENGTH = 0xF0 - (__rc31 + 1)
|
||||||
|
/* zp : ORIGIN = 0x10, LENGTH = 80 */
|
||||||
|
ram (rw) : ORIGIN = __f256_start, LENGTH = __stack-__f256_start
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LMAs */
|
||||||
|
__block8_lma = ( 8<<24)|__SLOT_ADDR;
|
||||||
|
__block9_lma = ( 9<<24)|__SLOT_ADDR;
|
||||||
|
__block10_lma = (10<<24)|__SLOT_ADDR;
|
||||||
|
__block11_lma = (11<<24)|__SLOT_ADDR;
|
||||||
|
__block12_lma = (12<<24)|__SLOT_ADDR;
|
||||||
|
__block13_lma = (13<<24)|__SLOT_ADDR;
|
||||||
|
__block14_lma = (14<<24)|__SLOT_ADDR;
|
||||||
|
__block15_lma = (15<<24)|__SLOT_ADDR;
|
||||||
|
__block16_lma = (16<<24)|__SLOT_ADDR;
|
||||||
|
__block17_lma = (17<<24)|__SLOT_ADDR;
|
||||||
|
__block18_lma = (18<<24)|__SLOT_ADDR;
|
||||||
|
__block19_lma = (19<<24)|__SLOT_ADDR;
|
||||||
|
__block20_lma = (20<<24)|__SLOT_ADDR;
|
||||||
|
__block21_lma = (21<<24)|__SLOT_ADDR;
|
||||||
|
__block22_lma = (22<<24)|__SLOT_ADDR;
|
||||||
|
__block23_lma = (23<<24)|__SLOT_ADDR;
|
||||||
|
|
||||||
|
/* Stash preloaded binary data */
|
||||||
|
__binarydata_lma = 0x54000; /* Block 42 */
|
||||||
|
__BINARYDATA_SIZE = 0x2C000; /* Size of A2-3D2, 3D/2D data area, and 2 bitmaps. */
|
||||||
|
|
||||||
|
MEMORY {
|
||||||
|
block8 : ORIGIN = __block8_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
block9 : ORIGIN = __block9_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
block10 : ORIGIN = __block10_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
block11 : ORIGIN = __block11_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
block12 : ORIGIN = __block12_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
block13 : ORIGIN = __block13_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
block14 : ORIGIN = __block14_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
block15 : ORIGIN = __block15_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
block16 : ORIGIN = __block16_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
block17 : ORIGIN = __block17_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
block18 : ORIGIN = __block18_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
block19 : ORIGIN = __block19_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
block20 : ORIGIN = __block20_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
block21 : ORIGIN = __block21_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
block22 : ORIGIN = __block22_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
block23 : ORIGIN = __block23_lma, LENGTH = __BLOCK_SIZE
|
||||||
|
binarydata : ORIGIN = __binarydata_lma, LENGTH = __BINARYDATA_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
REGION_ALIAS("c_writeable", ram)
|
||||||
|
REGION_ALIAS("c_readonly", ram)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
INCLUDE c.ld
|
||||||
|
.block8 : { *(.block8 .block8.*) } >block8 end_block8 = .;
|
||||||
|
.block9 : { *(.block9 .block9.*) } >block9 end_block9 = .;
|
||||||
|
.block10 : { *(.block10 .block10.*) } >block10 end_block10 = .;
|
||||||
|
.block11 : { *(.block11 .block11.*) } >block11 end_block11 = .;
|
||||||
|
.block12 : { *(.block12 .block12.*) } >block12 end_block12 = .;
|
||||||
|
.block13 : { *(.block13 .block13.*) } >block13 end_block13 = .;
|
||||||
|
.block14 : { *(.block14 .block14.*) } >block14 end_block14 = .;
|
||||||
|
.block15 : { *(.block15 .block15.*) } >block15 end_block15 = .;
|
||||||
|
.block16 : { *(.block16 .block16.*) } >block16 end_block16 = .;
|
||||||
|
.block17 : { *(.block17 .block17.*) } >block17 end_block17 = .;
|
||||||
|
.block18 : { *(.block18 .block18.*) } >block18 end_block18 = .;
|
||||||
|
.block19 : { *(.block19 .block19.*) } >block19 end_block19 = .;
|
||||||
|
.block20 : { *(.block20 .block20.*) } >block20 end_block20 = .;
|
||||||
|
.block21 : { *(.block21 .block21.*) } >block21 end_block21 = .;
|
||||||
|
.block22 : { *(.block22 .block22.*) } >block22 end_block22 = .;
|
||||||
|
.block23 : { *(.block23 .block23.*) } >block23 end_block23 = .;
|
||||||
|
.binarydata : { *(.binarydata .binarydata.*) } >binarydata end_binarydata = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
OUTPUT_FORMAT {
|
||||||
|
BYTE(0x5A) /* pgZ */
|
||||||
|
|
||||||
|
/* RAM Segment */
|
||||||
|
SHORT(ORIGIN(ram)) /* where to load it, 24 bits */
|
||||||
|
BYTE(0x00)
|
||||||
|
SHORT(__bss_start-ORIGIN(ram)) /* size to load */
|
||||||
|
BYTE(0x00)
|
||||||
|
TRIM(ram)
|
||||||
|
|
||||||
|
/* Overlay Segments */
|
||||||
|
INCLUDE output.ld
|
||||||
|
|
||||||
|
/* Binary Data */
|
||||||
|
SHORT(ORIGIN(binarydata))
|
||||||
|
BYTE(ORIGIN(binarydata)>>16)
|
||||||
|
SHORT(end_binarydata - __binarydata_lma)
|
||||||
|
BYTE((end_binarydata - __binarydata_lma)>>16)
|
||||||
|
TRIM(binarydata)
|
||||||
|
|
||||||
|
/* Launch the program, at _start */
|
||||||
|
SHORT(_start)
|
||||||
|
LONG(0)
|
||||||
|
}
|
BIN
icon.png
(Stored with Git LFS)
Normal file
BIN
icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
26
run.sh
Executable file
26
run.sh
Executable 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 ../f256/FoenixMgr/FoenixMgr/fnxmgr.py --run-pgz shotel.pgz
|
201
src/a23d2.c
Normal file
201
src/a23d2.c
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
* 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 "a23d2.h"
|
||||||
|
|
||||||
|
#include <string.h> // For memcopy
|
||||||
|
|
||||||
|
|
||||||
|
cameraT *_camera = (cameraT *)0x200; // Simulation copy of camera.
|
||||||
|
cameraT *_cameraInDatabase;
|
||||||
|
|
||||||
|
uint16_t _drawlist;
|
||||||
|
uint16_t _drawlistInDatabase;
|
||||||
|
|
||||||
|
byte *_pointer;
|
||||||
|
uint16_t _bytes;
|
||||||
|
uint8_t _x1;
|
||||||
|
uint8_t _y1;
|
||||||
|
uint8_t _x2;
|
||||||
|
uint8_t _y2;
|
||||||
|
bool _useColor;
|
||||||
|
byte _mmu;
|
||||||
|
byte _ram;
|
||||||
|
float _trig;
|
||||||
|
|
||||||
|
|
||||||
|
#define SEGMENT_A23D2
|
||||||
|
|
||||||
|
|
||||||
|
// There's a lot of global use in here. We can't use the virtual stack.
|
||||||
|
|
||||||
|
|
||||||
|
void a23d2Cos(void) {
|
||||||
|
// Map 0-359 into 0-255.
|
||||||
|
_tdata = _tdata % 359;
|
||||||
|
_y1 = (360/256) * _tdata;
|
||||||
|
POKE(A23D2_TDATA, _y1);
|
||||||
|
asm("jsr %[addy]":: [addy] "i"(A23D2_COSEX));
|
||||||
|
_trig = (float)PEEKW(A23D2_TDATA) / 32768;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void a23d2Draw(void) {
|
||||||
|
|
||||||
|
_pointer = (byte *)_drawlist;
|
||||||
|
|
||||||
|
// Move our 3D/2D data buffer at 0x56000 into slot 4.
|
||||||
|
POKE(MMU_MEM_BANK_4, DATABASE_FAR_BLOCK);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
switch (*_pointer++) {
|
||||||
|
|
||||||
|
// Line.
|
||||||
|
case (byte)LIN2D:
|
||||||
|
_x1 = (uint8_t)((int8_t)(*_pointer++) + 128);
|
||||||
|
_y1 = 255 - (uint8_t)((int8_t)(*_pointer++) + 128);
|
||||||
|
_x2 = (uint8_t)((int8_t)(*_pointer++) + 128);
|
||||||
|
_y2 = 255 - (uint8_t)((int8_t)(*_pointer++) + 128);
|
||||||
|
bitmapLine(_x1, _y1, _x2, _y2);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Point.
|
||||||
|
case (byte)PNT2D:
|
||||||
|
_x1 = (uint8_t)((int8_t)(*_pointer++) + 128);
|
||||||
|
_y1 = 255 - (uint8_t)((int8_t)(*_pointer++) + 128);
|
||||||
|
bitmapPutPixel(_x1, _y1);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Set Color.
|
||||||
|
case (byte)STCOL:
|
||||||
|
_x1 = (int8_t)(*_pointer++);
|
||||||
|
if (_useColor) bitmapSetColor(_x1);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Set Resolution.
|
||||||
|
case (byte)SRES:
|
||||||
|
// Eat this byte. We don't need it.
|
||||||
|
_pointer++;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// End.
|
||||||
|
case (byte)END:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore memory map.
|
||||||
|
POKE(MMU_MEM_BANK_4, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void a23d2Init(void) {
|
||||||
|
// We need to manually page 0x54000 into 0x6000.
|
||||||
|
// This isn't actually large enough for A2-3D2 but what we should only
|
||||||
|
// lose Apple ][ stuff we're not using anyway.
|
||||||
|
POKE(MMU_MEM_BANK_3, A23D2_FAR_BLOCK);
|
||||||
|
|
||||||
|
// We're going to clobber from 0x80fb to 0x8101. Back it up.
|
||||||
|
memcpy((byte *)0x2f7, (byte *)A23D2_TEST_DATABASE, 0x06);
|
||||||
|
|
||||||
|
// Initialize A2-3D2 so we can use the "fast entry point" (NXTPT) when rendering.
|
||||||
|
_bytes = 0;
|
||||||
|
_pointer = (byte *)A23D2_TEST_DATABASE; // Standard location for test database in A2-3D2.
|
||||||
|
_pointer[_bytes++] = SCRSZ; // Screen size. 256x240. Center is 0,0.
|
||||||
|
_pointer[_bytes++] = 255;
|
||||||
|
_pointer[_bytes++] = 239;
|
||||||
|
_pointer[_bytes++] = 0;
|
||||||
|
_pointer[_bytes++] = 0;
|
||||||
|
_pointer[_bytes++] = END; // Setup complete!
|
||||||
|
|
||||||
|
asm("jsr %[addy]":: [addy] "i"(A23D2_ENTRYS)); // Call ENTRYS. This preserves the ZP for us.
|
||||||
|
// asm("jsr 0x606c"); // Call ENTRYS. This preserves the ZP for us.
|
||||||
|
|
||||||
|
// Put back the RAM we clobbered.
|
||||||
|
memcpy((byte *)A23D2_TEST_DATABASE, (byte *)0x2f7, 0x06);
|
||||||
|
|
||||||
|
// Move our 3D/2D data buffer at 0x56000 into slot 4.
|
||||||
|
POKE(MMU_MEM_BANK_4, DATABASE_FAR_BLOCK);
|
||||||
|
|
||||||
|
// Set up drawlists.
|
||||||
|
_drawlistInDatabase = DATABASE + 1; // First value after ARRAY in near memory.
|
||||||
|
POKE(DRAWLIST_P0, END);
|
||||||
|
POKE(DRAWLIST_P1, END);
|
||||||
|
|
||||||
|
// Set up camera.
|
||||||
|
_cameraInDatabase = (cameraT *)(DATABASE + 4); // First value after EYE in near memory.
|
||||||
|
_camera->x = _cameraInDatabase->x;
|
||||||
|
_camera->y = _cameraInDatabase->y;
|
||||||
|
_camera->z = _cameraInDatabase->z;
|
||||||
|
_camera->p = _cameraInDatabase->p;
|
||||||
|
_camera->b = _cameraInDatabase->b;
|
||||||
|
_camera->h = _cameraInDatabase->h;
|
||||||
|
|
||||||
|
// Restore memory map.
|
||||||
|
POKE(MMU_MEM_BANK_4, 4);
|
||||||
|
POKE(MMU_MEM_BANK_3, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void a23d2Render(void) {
|
||||||
|
// We need to manually page 0x54000 into 0x6000.
|
||||||
|
// This isn't actually large enough for A2-3D2 but what we should only
|
||||||
|
// lose Apple ][ stuff we're not using anyway.
|
||||||
|
POKE(MMU_MEM_BANK_3, A23D2_FAR_BLOCK);
|
||||||
|
|
||||||
|
// Move our 3D/2D data buffer at 0x56000 into slot 4.
|
||||||
|
POKE(MMU_MEM_BANK_4, DATABASE_FAR_BLOCK);
|
||||||
|
|
||||||
|
// Update drawlist.
|
||||||
|
POKEW(_drawlistInDatabase, _drawlist);
|
||||||
|
|
||||||
|
// Update camera position.
|
||||||
|
_cameraInDatabase->x = _camera->x;
|
||||||
|
_cameraInDatabase->y = _camera->y;
|
||||||
|
_cameraInDatabase->z = _camera->z;
|
||||||
|
_cameraInDatabase->p = _camera->p;
|
||||||
|
_cameraInDatabase->b = _camera->b;
|
||||||
|
_cameraInDatabase->h = _camera->h;
|
||||||
|
|
||||||
|
memcpy((byte *)0x29d, (byte *)A23D2_ZP_START, A23D2_ZP_LENGTH); // Save the ZP we're going to clobber.
|
||||||
|
POKEW(A23D2_IBP, DATABASE); // Set IBP.
|
||||||
|
__attribute__((leaf)) asm("jsr %[addy]":: [addy] "i"(A23D2_NXTPT) : "a","x","y","c","v"); // Call NXTPT.
|
||||||
|
// __attribute__((leaf)) asm("jsr 0x6118"::: "a","x","y","c","v"); // Call NXTPT.
|
||||||
|
memcpy((byte *)A23D2_ZP_START, (byte *)0x29d, A23D2_ZP_LENGTH); // Put the ZP back.
|
||||||
|
|
||||||
|
// Restore memory map.
|
||||||
|
POKE(MMU_MEM_BANK_4, 4);
|
||||||
|
POKE(MMU_MEM_BANK_3, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void a23d2Sin(void) {
|
||||||
|
// Map 0-359 into 0-255.
|
||||||
|
_tdata = _tdata % 359;
|
||||||
|
_y1 = (360/256) * _tdata;
|
||||||
|
POKE(A23D2_TDATA, _y1);
|
||||||
|
asm("jsr %[addy]":: [addy] "i"(A23D2_SINEX));
|
||||||
|
_trig = (float)PEEKW(A23D2_TDATA) / 32768;
|
||||||
|
}
|
127
src/a23d2.h
Normal file
127
src/a23d2.h
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __F256K__
|
||||||
|
#include "f256lib.h"
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
typedef uint8_t byte;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define A23D2_FAR_BLOCK 42
|
||||||
|
#define DATABASE_FAR_BLOCK 43
|
||||||
|
|
||||||
|
#define DATABASE_FAR 0x56000
|
||||||
|
#define DRAWLIST_P0_FAR 0x57000
|
||||||
|
#define DRAWLIST_P1_FAR 0x57800
|
||||||
|
|
||||||
|
#define DATABASE 0x8000
|
||||||
|
#define DRAWLIST_P0 0x9000
|
||||||
|
#define DRAWLIST_P1 0x9800
|
||||||
|
|
||||||
|
|
||||||
|
// A2-3D2 Function Addresses.
|
||||||
|
#define A23D2_ENTRYS 0x606c
|
||||||
|
#define A23D2_NXTPT 0x6118
|
||||||
|
#define A23D2_SINEX 0x61f6
|
||||||
|
#define A23D2_COSEX 0x620f
|
||||||
|
|
||||||
|
// A2-3D2 Data Addresses.
|
||||||
|
#define A23D2_TEST_DATABASE 0x80fb
|
||||||
|
#define A23D2_TDATA 0x613e
|
||||||
|
#define A23D2_IBP 0x9b
|
||||||
|
#define A23D2_ZP_START 0x60
|
||||||
|
#define A23D2_ZP_LENGTH 0x62
|
||||||
|
|
||||||
|
|
||||||
|
// A2-3D1 Commands. Commented out items are Apple ][ only.
|
||||||
|
#define PNT 0x00 // xLSB, xMSB, yLSB, yMSB, zLSB, zMSB - Define 3D Point
|
||||||
|
#define SPNT 0x01 // xLSB, xMSB, yLSB, yMSB, zLSB, zMSB - Define 3D Start Point
|
||||||
|
#define CPNT 0x02 // xLSB, xMSB, yLSB, yMSB, zLSB, zMSB - Define 3D Continue Point
|
||||||
|
#define RAY 0x03 // xLSB, xMSB, yLSB, yMSB, zLSB, zMSB - Define 3D Ray
|
||||||
|
#define CLPSW 0x04 // N - Define Clipper (0=off, 1=on)
|
||||||
|
#define EYE 0x05 // xLSB, xMSB, yLSB, yMSB, zLSB, zMSB, P, B, H - Define 3D Eye/Camera
|
||||||
|
#define LIN2D 0x06 // X1, Y1, X2, Y2 - Draw 2D Line
|
||||||
|
//#define DISP 0x07 // N - Display Select (50=set graphics, 51=set text, 52=clear mixed, 53=set mixed, 54=set page 1, 55=set page 2, 56=clear hi-res, 57=set hi-res)
|
||||||
|
//#define ERAS 0x08 // N - Erase Screen (0=erase page 1, 1=erase page 2, 2=fill page 1, 3=fill page 2)
|
||||||
|
//#define DRAW 0x09 // N - Select Draw Page (0=page 1, 1=page 2)
|
||||||
|
#define PNT2D 0x0a // X1, Y1 - Draw 2D Point
|
||||||
|
#define JMP 0x0b // LSB, MSB - Interpretive Jump
|
||||||
|
//#define LMODE 0x0c // N - Line Drawing Mode (0=solid, 1=xor)
|
||||||
|
#define ARRAY 0x0d // LSB, MSB - Enable Output Array
|
||||||
|
#define SCRSZ 0x0e // WIDTH, HEIGHT, xCENTER, yCENTER - Define Screen Size
|
||||||
|
#define FIELD 0x0f // xLSB, xMSB, yLSB, yMSB, zLSB, zMSB - Field of View Selection
|
||||||
|
#define INIT 0x10 // Easy Init
|
||||||
|
#define NOP 0x11 // No Operation
|
||||||
|
|
||||||
|
// A2-3D2 Commands. Commented out items are Apple ][ only.
|
||||||
|
#define STCOL 0x12 // COL - Set Color
|
||||||
|
#define ICALL 0x13 // STAT, LOC, ADDR - Independent Object Call
|
||||||
|
#define SRES 0x14 // RES - Set Resolution (0=140x192, 1=280x192)
|
||||||
|
//#define HLIN 0x15 // x1L, x1H, y1, x2L, x2H, y2 - Hi-Res (280x192) Line 2D
|
||||||
|
//#define SHRB 0x16 // xL, xH, y - Set Hi-Res Bias
|
||||||
|
//#define HLIN2 0x17 // x1, y1, x2, y2 - Hi-Res (x limited) Line 2D
|
||||||
|
//#define HPNT 0x18 // xL, xH, y - Hi-Res (280x192) Point 2D
|
||||||
|
//#define HPNT2 0x19 // x, y - Hi-Res (x limited) Point 2D
|
||||||
|
#define SKIP 0x1a // SIZE, STATUS - Skip Segment
|
||||||
|
//#define PAUS 0x1b // TIME - Pause for TIME/5ths of a Second
|
||||||
|
#define SET323 0x1c // LSB, MSB - Set 3D to 3D Array Address
|
||||||
|
#define GN323 0x1d // STATUS - Set 3D to 3D Status
|
||||||
|
#define END 0x79 // End of Database
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct cameraS {
|
||||||
|
int16_t x;
|
||||||
|
int16_t y;
|
||||||
|
int16_t z;
|
||||||
|
byte p;
|
||||||
|
byte b;
|
||||||
|
byte h;
|
||||||
|
} cameraT;
|
||||||
|
|
||||||
|
|
||||||
|
extern cameraT *_camera;
|
||||||
|
extern cameraT *_cameraInDatabase;
|
||||||
|
|
||||||
|
extern uint16_t _drawlist;
|
||||||
|
extern uint16_t _drawlistInDatabase;
|
||||||
|
|
||||||
|
extern byte *_pointer;
|
||||||
|
extern uint16_t _bytes;
|
||||||
|
extern uint8_t _x1;
|
||||||
|
#define _tdata _x1 // Alias.
|
||||||
|
extern uint8_t _y1;
|
||||||
|
extern uint8_t _x2;
|
||||||
|
extern uint8_t _y2;
|
||||||
|
extern bool _useColor;
|
||||||
|
extern byte _mmu;
|
||||||
|
extern byte _ram;
|
||||||
|
extern float _trig;
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE:
|
||||||
|
// There are no function prototypes in this header.
|
||||||
|
// This library lives in it's own overlay segment and the overlay tool
|
||||||
|
// will generate prototypes as well as trampoline macros for us.
|
681
src/main.c
Normal file
681
src/main.c
Normal file
|
@ -0,0 +1,681 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Memory Map:
|
||||||
|
*
|
||||||
|
* Far Heap (upper 448k):
|
||||||
|
*
|
||||||
|
* 0x7ffff - Top of far heap / End of bitmap page 1
|
||||||
|
* - Bitmap page is 0x14000 (81920 bytes)
|
||||||
|
* 0x6c000 - Start of bitmap page 1
|
||||||
|
* 0x6bfff - End of bitmap page 2
|
||||||
|
* - Bitmap page is 0x14000 (81920 bytes)
|
||||||
|
* 0x58000 - Start of bitmap page 2
|
||||||
|
* 0x57fff - End of A2-3D2 and data to be used in slots 3 and 2/4 below
|
||||||
|
* - ...
|
||||||
|
* 0x54000 - Start of A2-3D2 and data to be used in slots 3 and 2/4 below
|
||||||
|
* - 57344 bytes free
|
||||||
|
* 0x45fff - End of overlay code
|
||||||
|
* - ...
|
||||||
|
* 0x10000 - Bottom of far heap / Start of overlay code
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Near Heap (lower 64k):
|
||||||
|
*
|
||||||
|
* 0xffff - Top of near heap
|
||||||
|
* - ...
|
||||||
|
* 0xe000 - Microkernel
|
||||||
|
* - ...
|
||||||
|
* 0xc000 - I/O and microkernel
|
||||||
|
* - ...
|
||||||
|
* 0xa000 - Overlay code
|
||||||
|
* 0x9fff - Top of virtual stack
|
||||||
|
* - ...
|
||||||
|
* 0x8000 - Program code / 3D/2D data
|
||||||
|
* - ...
|
||||||
|
* 0x6000 - Program code / 3D library
|
||||||
|
* - ...
|
||||||
|
* 0x0300 - Start of program code
|
||||||
|
* 0x02ff - End of program arguments / data storage
|
||||||
|
* - ... (We're going to overwrite this!)
|
||||||
|
* 0x0200 - Start of program arguments / data storage
|
||||||
|
* 0x01ff - Top of CPU stack space
|
||||||
|
* - ...
|
||||||
|
* 0x0100 - Bottom of CPU stack space
|
||||||
|
* 0x00ff - End of microkernel use
|
||||||
|
* - ...
|
||||||
|
* 0x00f0 - Start of microkernel use
|
||||||
|
* - 46 bytes free
|
||||||
|
* 0x00c2 - End of A2-3D2 use
|
||||||
|
* - ...
|
||||||
|
* 0x0060 - Start of A2-3D2 use
|
||||||
|
* - 49 bytes free
|
||||||
|
* 0x002f - llvm virtual register 31
|
||||||
|
* - ...
|
||||||
|
* 0x0010 - llvm virtual register 0
|
||||||
|
* 0x000f - MMU_MEM_BANK_7
|
||||||
|
* - ...
|
||||||
|
* 0x0008 - MMU_MEM_BANK_0
|
||||||
|
* - 7 bytes free
|
||||||
|
* 0x0001 - MMU_IO_CTRL
|
||||||
|
* 0x0000 - MMU_MEM_CTRL
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Calling the 3D Renderer:
|
||||||
|
*
|
||||||
|
* The MMU splits the near heap into 8k "slots" that 8k "blocks" of far heap
|
||||||
|
* can be mapped into. f256lib, by default, sets the near heap up as
|
||||||
|
* follows:
|
||||||
|
*
|
||||||
|
* 0xe000 - Slot 7 - Microkernel
|
||||||
|
* 0xc000 - Slot 6 - I/O and Microkernel
|
||||||
|
* 0xa000 - Slot 5 - Code Overlay Region
|
||||||
|
* 0x8000 - Slot 4 - Program Code
|
||||||
|
* 0x6000 - Slot 3 - Program Code
|
||||||
|
* 0x4000 - Slot 2 - Program Code
|
||||||
|
* 0x2000 - Slot 1 - Program Code
|
||||||
|
* 0x0000 - Slot 0 - Zero Page & Program Code
|
||||||
|
*
|
||||||
|
* Our 3D library, subLOGIC's A2-3D2, was designed to be run on an Apple ][.
|
||||||
|
* The Apple ][ has two high-resolution video pages in the middle of the
|
||||||
|
* memory map and A2-3D2 loads at 0x6000 immediately after the second video
|
||||||
|
* page. This makes sense on the Apple. On the Foenix, it's in the way at
|
||||||
|
* slot 3. The library also needs a 3D scene database and outputs an array
|
||||||
|
* of 2D drawing instructions. Given the size of A2-3D2 this pushes our
|
||||||
|
* memory usage up into slot 4. This leaves slots 0 to 2 for the simulator.
|
||||||
|
* That's less than 24k. Not good.
|
||||||
|
*
|
||||||
|
* We're going to place the 3D library and related data in the far heap and
|
||||||
|
* manually swap them in using the MMU when we need to render the scene. To
|
||||||
|
* do this, we need to ensure we're not currently executing code from
|
||||||
|
* somewhere in the slot 2 to 4 range. To accomplish this, all the functions
|
||||||
|
* that deal with A2-3D2 are placed in an overlay. This ensures whatever
|
||||||
|
* code calls into slots 2 to 4 has a program counter between 0xa000 and
|
||||||
|
* 0xbfff - well out of the way of the 3D stuff.
|
||||||
|
*
|
||||||
|
* The last thing to worry about is data needed by both the simulator and
|
||||||
|
* A2-3D2. This is basically only the camera position and rotation. These
|
||||||
|
* 10 bytes will be stored directly into RAM from 0x200 to 0x20a overwriting
|
||||||
|
* any command line arguments that may have been in memory.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define WITHOUT_FILE
|
||||||
|
#define WITHOUT_SPRITE
|
||||||
|
#define WITHOUT_TILE
|
||||||
|
#define F256LIB_IMPLEMENTATION
|
||||||
|
#include "f256lib.h"
|
||||||
|
|
||||||
|
#include "a23d2.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct airplaneS {
|
||||||
|
int8_t aileron; // -15 to 15
|
||||||
|
int8_t elevator; // -15 to 15
|
||||||
|
int8_t rudder; // -15 to 15
|
||||||
|
int8_t throttle; // -15 to 15
|
||||||
|
bool ignition;
|
||||||
|
bool engine;
|
||||||
|
int16_t rpm;
|
||||||
|
float hSpeed;
|
||||||
|
float vSpeed;
|
||||||
|
float deltaZ;
|
||||||
|
float efAOF;
|
||||||
|
float climbRate;
|
||||||
|
bool airborne;
|
||||||
|
bool stall;
|
||||||
|
bool brake;
|
||||||
|
int16_t x;
|
||||||
|
int16_t y;
|
||||||
|
int16_t z;
|
||||||
|
double pitch; // 0 to 255
|
||||||
|
double yaw; // 0 to 255
|
||||||
|
double roll; // 0 to 255
|
||||||
|
} airplaneT;
|
||||||
|
|
||||||
|
|
||||||
|
airplaneT _plane;
|
||||||
|
byte _gamepad;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* embedded.bin is loaded at 0x54000:
|
||||||
|
*
|
||||||
|
* 8k a2-3d2.bin @ 0x54000
|
||||||
|
* 8k scene.3d @ 0x56000
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
EMBED(".binarydata.embedded", embedded, "embedded.bin");
|
||||||
|
|
||||||
|
|
||||||
|
#define SEGMENT_MATH
|
||||||
|
|
||||||
|
|
||||||
|
#define PI 3.1415926
|
||||||
|
|
||||||
|
//#define Rads(d) (((d) < 0 ? (d) + 360 : (d)) * (PI / 180))
|
||||||
|
#define Degs(r) ((r) * (180 / PI))
|
||||||
|
|
||||||
|
// https://www.reddit.com/r/programming/comments/3e7ghi/discrete_arctan_in_6502/
|
||||||
|
#define ATAN_SPLINE_C0 (double)(-0.14380550980765507115) /* 3pi/4 - 5/2 */
|
||||||
|
#define ATAN_SPLINE_C1 (double)(-0.07079632679489661923) /* 3/2 - pi/2 */
|
||||||
|
double atan(double x){
|
||||||
|
if (x >= 0) {
|
||||||
|
if ( x<= 1) {
|
||||||
|
return x + (ATAN_SPLINE_C0 + ATAN_SPLINE_C1 * x) * x * x;
|
||||||
|
} else {
|
||||||
|
x = 1 / x;
|
||||||
|
return PI / 2 - (x + (ATAN_SPLINE_C0 + ATAN_SPLINE_C1 * x) * x * x);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (x >= -1) {
|
||||||
|
return x - (ATAN_SPLINE_C0 - ATAN_SPLINE_C1 * x) * x * x;
|
||||||
|
} else {
|
||||||
|
x = -1 / x;
|
||||||
|
return (x + (ATAN_SPLINE_C0 + ATAN_SPLINE_C1 * x) * x * x) - PI / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float sin(float d) {
|
||||||
|
_tdata = d;
|
||||||
|
a23d2Sin();
|
||||||
|
return _trig;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float cos(float d) {
|
||||||
|
_tdata = d;
|
||||||
|
a23d2Cos();
|
||||||
|
return _trig;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define SEGMENT_INPUT
|
||||||
|
|
||||||
|
|
||||||
|
void getInput(void) {
|
||||||
|
static byte oneJoy = 0;
|
||||||
|
static byte twoJoy = 0;
|
||||||
|
static byte keyJoy = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
kernelCall(NextEvent);
|
||||||
|
|
||||||
|
// Read real joysticks.
|
||||||
|
if (kernelEventData.type == kernelEvent(GAME)) {
|
||||||
|
oneJoy = kernelEventData.game.game0;
|
||||||
|
twoJoy = kernelEventData.game.game1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//***TODO*** Add SNES/NES once I get some.
|
||||||
|
|
||||||
|
// Use keyboard as virtual joystick.
|
||||||
|
if (kernelEventData.type == 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (kernelEventData.type == 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (kernelGetPending() > 0);
|
||||||
|
|
||||||
|
// Merge inputs. Yes, this allows dumb things like LEFT and RIGHT at the same time.
|
||||||
|
_gamepad = oneJoy | twoJoy | keyJoy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define SEGMENT_FLIGHT_MODEL_1
|
||||||
|
|
||||||
|
|
||||||
|
// These didn't use to be global. Ugly.
|
||||||
|
float tmpX;
|
||||||
|
float tmpY;
|
||||||
|
float tmpZ;
|
||||||
|
float newX;
|
||||||
|
float newY;
|
||||||
|
float newZ;
|
||||||
|
float iSpeed;
|
||||||
|
float lSpeed;
|
||||||
|
float hAccel;
|
||||||
|
float lVeloc;
|
||||||
|
float gVeloc;
|
||||||
|
float deltaZ;
|
||||||
|
float AOA;
|
||||||
|
float torque;
|
||||||
|
float torque2;
|
||||||
|
|
||||||
|
uint16_t loopTime = 40;
|
||||||
|
|
||||||
|
static double dPitch = 0;
|
||||||
|
static double dYaw = 0;
|
||||||
|
static double dRoll = 0;
|
||||||
|
static float collectX = 0;
|
||||||
|
static float collectY = 0;
|
||||||
|
static float collectZ = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// This flight model is basically the one from "Build Your Own Flight Sim
|
||||||
|
// in C++" by Michael Radtke and Chris Lampton.
|
||||||
|
void lightPlane(void) {
|
||||||
|
// Flight model. Power Dynamics.
|
||||||
|
if (_plane.ignition) {
|
||||||
|
// Start engine.
|
||||||
|
if (!_plane.engine) _plane.engine = true;
|
||||||
|
// Adjust RPM.
|
||||||
|
if (_plane.rpm < (375 + (_plane.throttle * 117))) _plane.rpm += loopTime * 0.5; //***TODO*** T
|
||||||
|
if (_plane.rpm > (375 + (_plane.throttle * 117))) _plane.rpm -= loopTime * 0.5;
|
||||||
|
} else {
|
||||||
|
// Stop engine.
|
||||||
|
if (_plane.engine) _plane.engine = false;
|
||||||
|
// Run down engine.
|
||||||
|
if (_plane.rpm > 0) _plane.rpm -= (int16_t)(loopTime / 2); //***TODO*** This will never work.
|
||||||
|
if (_plane.rpm < 0) _plane.rpm = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flight model. Flight Dynamics.
|
||||||
|
// Calculate speed from RPM.
|
||||||
|
iSpeed = _plane.rpm / 17.5;
|
||||||
|
// Modify speed by pitch.
|
||||||
|
iSpeed += (_plane.pitch * 1.5);
|
||||||
|
// Horizontal acceleration - thrust.
|
||||||
|
hAccel = ((_plane.rpm * (iSpeed - _plane.hSpeed)) / 10000);
|
||||||
|
hAccel /= 1000;
|
||||||
|
hAccel *= loopTime;
|
||||||
|
if (_plane.brake && !_plane.airborne) {
|
||||||
|
// Handle brakes.
|
||||||
|
if (_plane.hSpeed > 0) {
|
||||||
|
_plane.hSpeed -= 1;
|
||||||
|
} else {
|
||||||
|
_plane.hSpeed = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Accelerate normally.
|
||||||
|
_plane.hSpeed += hAccel;
|
||||||
|
}
|
||||||
|
// Force speed to range -1..1.
|
||||||
|
lSpeed = (_plane.hSpeed / 65) - 1;
|
||||||
|
if (lSpeed > 1) lSpeed = 1;
|
||||||
|
// Lift curve.
|
||||||
|
lVeloc = Degs(atan(lSpeed));
|
||||||
|
// Force lift to range 0..90.
|
||||||
|
lVeloc += 45;
|
||||||
|
// Shift range to 0..-17.
|
||||||
|
lVeloc /= 5.29;
|
||||||
|
// Multiply by pitch modifier.
|
||||||
|
lVeloc *= (-(_plane.pitch * .157) + 1);
|
||||||
|
// Time slice.
|
||||||
|
lVeloc /= 1000;
|
||||||
|
lVeloc *= loopTime;
|
||||||
|
// Gravity.
|
||||||
|
gVeloc = loopTime * (-16.0 / 10000); // -16.0 is ft/sec for gravity.
|
||||||
|
// Sum vertical velocity.
|
||||||
|
_plane.vSpeed = gVeloc + lVeloc;
|
||||||
|
// No vertical speed if we're on the ground.
|
||||||
|
if (!_plane.airborne && (_plane.vSpeed < 0)) _plane.vSpeed = 0;
|
||||||
|
// Save climb rate in ft/min.
|
||||||
|
_plane.climbRate = _plane.vSpeed / loopTime;
|
||||||
|
_plane.climbRate *= 60000L;
|
||||||
|
// Expand to ft/hr.
|
||||||
|
deltaZ = _plane.hSpeed * 5280;
|
||||||
|
// Get ft/ms.
|
||||||
|
deltaZ /= 3600000L;
|
||||||
|
deltaZ *= loopTime;
|
||||||
|
// Find effective angle of flight.
|
||||||
|
if (deltaZ) {
|
||||||
|
_plane.efAOF = -(atan(_plane.vSpeed / deltaZ));
|
||||||
|
} else {
|
||||||
|
_plane.efAOF = -(atan(_plane.vSpeed));
|
||||||
|
}
|
||||||
|
// Convert to degrees.
|
||||||
|
AOA = Degs(_plane.efAOF);
|
||||||
|
// Handle stalling.
|
||||||
|
if (((_plane.pitch < AOA) && (AOA < 0)) && (_plane.hSpeed < 40)) {
|
||||||
|
if ((_plane.pitch - AOA) < -20) _plane.stall = true;
|
||||||
|
}
|
||||||
|
if (_plane.stall) {
|
||||||
|
if (_plane.pitch > 30) {
|
||||||
|
_plane.stall = false;
|
||||||
|
} else {
|
||||||
|
_plane.pitch++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define SEGMENT_FLIGHT_MODEL_2
|
||||||
|
|
||||||
|
|
||||||
|
void lightPlane2(void) {
|
||||||
|
// Flight model. Inertial Damping.
|
||||||
|
if (dPitch) {
|
||||||
|
dPitch -= dPitch / 10;
|
||||||
|
if (((dPitch > 0) && (dPitch < 0.01)) || ((dPitch < 0) && (dPitch > -0.01))) dPitch = 0;
|
||||||
|
}
|
||||||
|
if (dYaw) {
|
||||||
|
dYaw -= dYaw / 10;
|
||||||
|
if (((dYaw > 0) && (dYaw < 0.01)) || ((dYaw < 0) && (dYaw > -0.01))) dYaw = 0;
|
||||||
|
}
|
||||||
|
if (dRoll) {
|
||||||
|
dRoll -= dRoll / 10;
|
||||||
|
if (((dRoll > 0) && (dRoll < 0.01)) || ((dRoll < 0) && (dRoll > -0.01))) dRoll = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flight model. Rate of Change.
|
||||||
|
if (_plane.airborne) {
|
||||||
|
if (_plane.aileron != 0) {
|
||||||
|
torque = ((_plane.hSpeed * _plane.aileron) / 10000);
|
||||||
|
if (dRoll != (torque * loopTime)) dRoll += torque * 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_plane.elevator != 0) {
|
||||||
|
torque = ((_plane.hSpeed * _plane.elevator) / 10000);
|
||||||
|
if ((!_plane.airborne) && (torque > 0)) torque = 0; //***FIX*** This is dumb.
|
||||||
|
if (dPitch != (torque * loopTime)) dPitch += torque * 1.5;
|
||||||
|
}
|
||||||
|
if (_plane.hSpeed) {
|
||||||
|
torque = 0.0;
|
||||||
|
if (_plane.rudder != 0) torque -= ((_plane.hSpeed * _plane.rudder) / 10000);
|
||||||
|
torque2 = 0.0;
|
||||||
|
if ((_plane.roll > 0) && (_plane.roll <= 90)) { //***FIX*** This is dumb.
|
||||||
|
torque2 = _plane.roll * 0.00050;
|
||||||
|
} else {
|
||||||
|
if ((_plane.roll < 0) && (_plane.roll >= -90)) {
|
||||||
|
torque2 = _plane.roll * 0.00050;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
torque += torque2;
|
||||||
|
if (dYaw != (torque * loopTime)) dYaw += torque * 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flight model. Apply Rotations.
|
||||||
|
// Transform pitch into components of yaw and pitch based on roll.
|
||||||
|
_plane.roll += dRoll;
|
||||||
|
_plane.yaw += dYaw;
|
||||||
|
_plane.pitch += (dPitch * cos(_plane.roll));
|
||||||
|
_plane.yaw += -(dPitch * sin(_plane.roll));
|
||||||
|
if (_plane.roll > 180) {
|
||||||
|
_plane.roll = -180 + (_plane.roll - 180);
|
||||||
|
} else {
|
||||||
|
if (_plane.roll < -180) _plane.roll = 180 + (_plane.roll + 180);
|
||||||
|
}
|
||||||
|
if (_plane.yaw > 180) {
|
||||||
|
_plane.yaw = -180 + (_plane.yaw - 180);
|
||||||
|
} else {
|
||||||
|
if (_plane.yaw < -180) _plane.yaw = 180 + (_plane.yaw + 180);
|
||||||
|
}
|
||||||
|
// Handle special case when aircraft pitch passes vertical.
|
||||||
|
if ((_plane.pitch > 90) || (_plane.pitch < -90)) {
|
||||||
|
if (_plane.roll >= 0) {
|
||||||
|
_plane.roll -= 180;
|
||||||
|
} else {
|
||||||
|
if (_plane.roll < 0) _plane.roll += 180;
|
||||||
|
}
|
||||||
|
if (_plane.yaw >= 0) {
|
||||||
|
_plane.yaw -= 180;
|
||||||
|
} else {
|
||||||
|
if (_plane.yaw < 0) _plane.yaw += 180;
|
||||||
|
}
|
||||||
|
if (_plane.pitch > 0) {
|
||||||
|
_plane.pitch = (180 - _plane.pitch);
|
||||||
|
} else {
|
||||||
|
if (_plane.pitch < 0) _plane.pitch = (-180 - _plane.pitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Dampen everything out to 0 if they get close enough.
|
||||||
|
if ((_plane.pitch > -0.5) && (_plane.pitch < 0.5)) _plane.pitch = 0;
|
||||||
|
if ((_plane.roll > -0.5) && (_plane.roll < 0.5)) _plane.roll = 0;
|
||||||
|
if ((_plane.yaw > -0.5) && (_plane.yaw < 0.5)) _plane.yaw = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define SEGMENT_FLIGHT_MODEL_3
|
||||||
|
|
||||||
|
|
||||||
|
void moveAircraft(void) {
|
||||||
|
// Calculate new aircraft position. Each coordinate is 1 foot in 3D space.
|
||||||
|
tmpX = 0;
|
||||||
|
tmpY = 0;
|
||||||
|
tmpZ = deltaZ;
|
||||||
|
|
||||||
|
// Order of these points is significant.
|
||||||
|
// Rotate in Z.
|
||||||
|
newX = (tmpX * cos(_plane.roll)) - (tmpY * sin(_plane.roll));
|
||||||
|
newY = (tmpX * sin(_plane.roll)) + (tmpY * cos(_plane.roll));
|
||||||
|
tmpX = newX;
|
||||||
|
tmpY = newY;
|
||||||
|
// Rotate in X;
|
||||||
|
_plane.efAOF = Degs(_plane.efAOF);
|
||||||
|
newY = (tmpY * cos(_plane.efAOF)) - (tmpZ * sin(_plane.efAOF));
|
||||||
|
newZ = (tmpY * sin(_plane.efAOF)) + (tmpZ * cos(_plane.efAOF));
|
||||||
|
tmpY = newY;
|
||||||
|
tmpZ = newZ;
|
||||||
|
// Rotate in X;
|
||||||
|
newX = (tmpZ * sin(_plane.yaw)) + (tmpX * cos(_plane.yaw));
|
||||||
|
newZ = (tmpZ * cos(_plane.yaw)) - (tmpX * sin(_plane.yaw));
|
||||||
|
tmpX = newX;
|
||||||
|
tmpZ = newZ;
|
||||||
|
|
||||||
|
// Translate rotated point back to where it should be
|
||||||
|
// relative to it's last position.
|
||||||
|
collectX += newX;
|
||||||
|
if ((collectX > 1) || (collectX < -1)) {
|
||||||
|
_plane.x -= collectX;
|
||||||
|
collectX = 0;
|
||||||
|
}
|
||||||
|
collectY += newY;
|
||||||
|
if ((collectY > 1) || (collectY < -1)) {
|
||||||
|
_plane.y -= collectY;
|
||||||
|
collectY = 0;
|
||||||
|
}
|
||||||
|
collectZ += newZ;
|
||||||
|
if ((collectY > 1) || (collectY < -1)) {
|
||||||
|
_plane.z += collectZ;
|
||||||
|
collectZ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Are we flying?
|
||||||
|
if ((!_plane.airborne) && (-_plane.y)) _plane.airborne = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define SEGMENT_MAIN
|
||||||
|
|
||||||
|
|
||||||
|
void runSimulation(void) {
|
||||||
|
bool pageZero;
|
||||||
|
|
||||||
|
// Initialize airplane.
|
||||||
|
memset(&_plane, 0, sizeof(airplaneT));
|
||||||
|
|
||||||
|
// Which page is visible?
|
||||||
|
pageZero = true;
|
||||||
|
|
||||||
|
// Draw it!
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
// Flip pages.
|
||||||
|
if (pageZero) {
|
||||||
|
// Looking at bitmap 0.
|
||||||
|
pageZero = false;
|
||||||
|
bitmapSetActive(1);
|
||||||
|
bitmapSetVisible(0, true);
|
||||||
|
bitmapSetVisible(1, false);
|
||||||
|
_drawlist = DRAWLIST_P1;
|
||||||
|
} else {
|
||||||
|
// Looking at bitmap 1.
|
||||||
|
pageZero = true;
|
||||||
|
bitmapSetActive(0);
|
||||||
|
bitmapSetVisible(1, true);
|
||||||
|
bitmapSetVisible(0, false);
|
||||||
|
_drawlist = DRAWLIST_P0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erase old scene.
|
||||||
|
bitmapSetColor(0);
|
||||||
|
_useColor = false;
|
||||||
|
a23d2Draw();
|
||||||
|
|
||||||
|
// Draw new scene.
|
||||||
|
a23d2Render();
|
||||||
|
_useColor = true;
|
||||||
|
a23d2Draw();
|
||||||
|
|
||||||
|
// Update player input.
|
||||||
|
getInput();
|
||||||
|
|
||||||
|
// Update aircraft control state.
|
||||||
|
if ((_gamepad & JOY_BUTTON_1) || (_gamepad & JOY_BUTTON_2) || (_gamepad & JOY_BUTTON_3)) {
|
||||||
|
// Modified input with button down.
|
||||||
|
if ((_gamepad & JOY_UP) && (_plane.throttle > -15)) _plane.throttle++;
|
||||||
|
if ((_gamepad & JOY_DOWN) && (_plane.throttle < 15)) _plane.throttle--;
|
||||||
|
if (_gamepad & JOY_RIGHT) _plane.brake = !_plane.brake;
|
||||||
|
} else {
|
||||||
|
// No button pressed.
|
||||||
|
if ((_gamepad & JOY_UP) && (_plane.elevator > -15)) _plane.elevator--;
|
||||||
|
if ((_gamepad & JOY_DOWN) && (_plane.elevator < 15)) _plane.elevator++;
|
||||||
|
if ((_gamepad & JOY_LEFT) && (_plane.aileron > -15)) _plane.aileron--;
|
||||||
|
if ((_gamepad & JOY_RIGHT) && (_plane.aileron < 15)) _plane.aileron++;
|
||||||
|
}
|
||||||
|
// "Coordinated" flight.
|
||||||
|
_plane.rudder = _plane.aileron;
|
||||||
|
|
||||||
|
// Do the actual flying!
|
||||||
|
lightPlane();
|
||||||
|
lightPlane2();
|
||||||
|
moveAircraft();
|
||||||
|
|
||||||
|
// Move camera.
|
||||||
|
_camera->p += 1; // Change pitch angle.
|
||||||
|
_camera->b += 2; // Change bank angle.
|
||||||
|
_camera->h += 3; // Change heading angle.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
byte c;
|
||||||
|
byte ega[16][3] = {
|
||||||
|
{ 0x00, 0x00, 0x00 },
|
||||||
|
{ 0x00, 0x00, 0xaa },
|
||||||
|
{ 0x00, 0xaa, 0x00 },
|
||||||
|
{ 0x00, 0xaa, 0xaa },
|
||||||
|
{ 0xaa, 0x00, 0x00 },
|
||||||
|
{ 0xaa, 0x00, 0xaa },
|
||||||
|
{ 0xaa, 0x55, 0x00 },
|
||||||
|
{ 0xaa, 0xaa, 0xaa },
|
||||||
|
{ 0x55, 0x55, 0x55 },
|
||||||
|
{ 0x55, 0x55, 0xff },
|
||||||
|
{ 0x55, 0xff, 0x55 },
|
||||||
|
{ 0x55, 0xff, 0xff },
|
||||||
|
{ 0xff, 0x55, 0x55 },
|
||||||
|
{ 0xff, 0x55, 0xff },
|
||||||
|
{ 0xff, 0xff, 0x55 },
|
||||||
|
{ 0xff, 0xff, 0xff }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Load EGA palette into CLUT0.
|
||||||
|
for (c=0; c<16; c++) graphicsDefineColor(0, c, ega[c][0], ega[c][1], ega[c][2]);
|
||||||
|
|
||||||
|
a23d2Init();
|
||||||
|
|
||||||
|
// Set up bitmap planes.
|
||||||
|
for (c=0; c<2; c++) {
|
||||||
|
// Clear screen.
|
||||||
|
bitmapSetActive(c);
|
||||||
|
bitmapSetColor(0);
|
||||||
|
bitmapClear();
|
||||||
|
// 3D Viewport edge.
|
||||||
|
bitmapSetColor(14);
|
||||||
|
bitmapLine(256, 0, 256, 239);
|
||||||
|
}
|
||||||
|
bitmapSetVisible(0, true);
|
||||||
|
bitmapSetVisible(1, false);
|
||||||
|
|
||||||
|
runSimulation();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
174
tools/scene.c
Normal file
174
tools/scene.c
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
/*
|
||||||
|
* 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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "a23d2.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define LOW_BYTE(x) ((uint8_t)(x))
|
||||||
|
#define HIGH_BYTE(x) ((uint8_t)(((uint16_t)(x)) >> 8))
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t db[8192] = { 0 };
|
||||||
|
uint16_t bytes = 0;
|
||||||
|
|
||||||
|
|
||||||
|
void cube(void) {
|
||||||
|
int16_t i = 0;
|
||||||
|
uint8_t scene[] = {
|
||||||
|
STCOL, 0x04, // Red
|
||||||
|
SPNT, 0x00, 0xff, 0x00, 0xff, 0x00, 0x03, // Cube
|
||||||
|
CPNT, 0x00, 0x01, 0x00, 0xff, 0x00, 0x03,
|
||||||
|
CPNT, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03,
|
||||||
|
CPNT, 0x00, 0xff, 0x00, 0x01, 0x00, 0x03,
|
||||||
|
CPNT, 0x00, 0xff, 0x00, 0xff, 0x00, 0x03,
|
||||||
|
CPNT, 0x00, 0xff, 0x00, 0xff, 0x00, 0x05,
|
||||||
|
CPNT, 0x00, 0x01, 0x00, 0xff, 0x00, 0x05,
|
||||||
|
RAY, 0x00, 0x01, 0x00, 0xff, 0x00, 0x03,
|
||||||
|
CPNT, 0x00, 0x01, 0x00, 0x01, 0x00, 0x05,
|
||||||
|
RAY, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03,
|
||||||
|
CPNT, 0x00, 0xff, 0x00, 0x01, 0x00, 0x05,
|
||||||
|
RAY, 0x00, 0xff, 0x00, 0x01, 0x00, 0x03,
|
||||||
|
CPNT, 0x00, 0xff, 0x00, 0xff, 0x00, 0x05,
|
||||||
|
SPNT, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, // Edge Line
|
||||||
|
CPNT, 0x00, 0x00, 0x80, 0x00, 0x00, 0x03,
|
||||||
|
END
|
||||||
|
};
|
||||||
|
|
||||||
|
while (scene[i] != END) {
|
||||||
|
db[bytes++] = scene[i++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void landscape(void) {
|
||||||
|
int16_t i;
|
||||||
|
int16_t x;
|
||||||
|
int16_t y;
|
||||||
|
int16_t min = 0;
|
||||||
|
int16_t max = 10000;
|
||||||
|
|
||||||
|
db[bytes++] = STCOL;
|
||||||
|
db[bytes++] = 2; // Green
|
||||||
|
|
||||||
|
for (i=min; i<=max; i+=1000) {
|
||||||
|
db[bytes++] = SPNT;
|
||||||
|
db[bytes++] = LOW_BYTE(i); // X
|
||||||
|
db[bytes++] = HIGH_BYTE(i);
|
||||||
|
db[bytes++] = 0; // Y
|
||||||
|
db[bytes++] = 0;
|
||||||
|
db[bytes++] = LOW_BYTE(min); // Z
|
||||||
|
db[bytes++] = HIGH_BYTE(min);
|
||||||
|
|
||||||
|
db[bytes++] = CPNT;
|
||||||
|
db[bytes++] = LOW_BYTE(i); // X
|
||||||
|
db[bytes++] = HIGH_BYTE(i);
|
||||||
|
db[bytes++] = 0; // Y
|
||||||
|
db[bytes++] = 0;
|
||||||
|
db[bytes++] = LOW_BYTE(max); // Z
|
||||||
|
db[bytes++] = HIGH_BYTE(max);
|
||||||
|
|
||||||
|
db[bytes++] = SPNT;
|
||||||
|
db[bytes++] = LOW_BYTE(min); // X
|
||||||
|
db[bytes++] = HIGH_BYTE(min);
|
||||||
|
db[bytes++] = 0; // Y
|
||||||
|
db[bytes++] = 0;
|
||||||
|
db[bytes++] = LOW_BYTE(i); // Z
|
||||||
|
db[bytes++] = HIGH_BYTE(i);
|
||||||
|
|
||||||
|
db[bytes++] = CPNT;
|
||||||
|
db[bytes++] = LOW_BYTE(max); // X
|
||||||
|
db[bytes++] = HIGH_BYTE(max);
|
||||||
|
db[bytes++] = 0; // Y
|
||||||
|
db[bytes++] = 0;
|
||||||
|
db[bytes++] = LOW_BYTE(i); // Z
|
||||||
|
db[bytes++] = HIGH_BYTE(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runway - 3000' x 100'
|
||||||
|
min = 1500;
|
||||||
|
max = min + 300;
|
||||||
|
x = 1500;
|
||||||
|
db[bytes++] = STCOL;
|
||||||
|
db[bytes++] = 8; // Dark Grey
|
||||||
|
for (i=0; i<=10; i+=2) {
|
||||||
|
db[bytes++] = SPNT;
|
||||||
|
db[bytes++] = LOW_BYTE(x+i); // X
|
||||||
|
db[bytes++] = HIGH_BYTE(x+i);
|
||||||
|
db[bytes++] = 0; // Y
|
||||||
|
db[bytes++] = 0;
|
||||||
|
db[bytes++] = LOW_BYTE(min); // Z
|
||||||
|
db[bytes++] = HIGH_BYTE(min);
|
||||||
|
|
||||||
|
db[bytes++] = CPNT;
|
||||||
|
db[bytes++] = LOW_BYTE(x+i); // X
|
||||||
|
db[bytes++] = HIGH_BYTE(x+i);
|
||||||
|
db[bytes++] = 0; // Y
|
||||||
|
db[bytes++] = 0;
|
||||||
|
db[bytes++] = LOW_BYTE(max); // Z
|
||||||
|
db[bytes++] = HIGH_BYTE(max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
FILE *out;
|
||||||
|
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
// All scene databases need to begin with the ARRAY and EYE records.
|
||||||
|
// The CLPSW clipping setting is up to you. :-)
|
||||||
|
|
||||||
|
db[bytes++] = ARRAY; // Will be filled in by the program.
|
||||||
|
db[bytes++] = 0;
|
||||||
|
db[bytes++] = 0;
|
||||||
|
|
||||||
|
db[bytes++] = EYE; // Will be filled in by the program.
|
||||||
|
db[bytes++] = 0x00; // X
|
||||||
|
db[bytes++] = 0x00;
|
||||||
|
db[bytes++] = 0x00; // Y
|
||||||
|
db[bytes++] = 0x00;
|
||||||
|
db[bytes++] = 0x00; // Z
|
||||||
|
db[bytes++] = 0x00;
|
||||||
|
db[bytes++] = 0x00; // P
|
||||||
|
db[bytes++] = 0x00; // B
|
||||||
|
db[bytes++] = 0x00; // H
|
||||||
|
|
||||||
|
db[bytes++] = CLPSW;
|
||||||
|
db[bytes++] = 0x00;
|
||||||
|
|
||||||
|
//cube();
|
||||||
|
landscape();
|
||||||
|
|
||||||
|
db[bytes++] = END;
|
||||||
|
|
||||||
|
out = fopen("scene.3d", "wb");
|
||||||
|
if (out) {
|
||||||
|
fwrite(db, 1, 8192, out);
|
||||||
|
fclose(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue