starting on hardware sprites
This commit is contained in:
parent
3e18d9cdb2
commit
23bc034f6f
18
arena.c
18
arena.c
|
@ -1,13 +1,14 @@
|
|||
#include "bmpload.h"
|
||||
#include "const.h"
|
||||
#include "arena.h"
|
||||
#include "system/vga.h"
|
||||
|
||||
char arenaLayout[10][10] = {
|
||||
{ 1, 1, 1, 1, 0, 0, 1, 1, 1, 1 },
|
||||
{ 1, 2, 2, 2, 0, 0, 2, 2, 2, 1 },
|
||||
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
{ 2, 0, 0, 0, 0, 0, 0, 0, 0, 2 },
|
||||
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
|
@ -37,9 +38,14 @@ void setupWallSprites(struct BMPImage *spritesheetImage) {
|
|||
);
|
||||
}
|
||||
|
||||
extern void renderFloorTile(byte *);
|
||||
// push items onto stack
|
||||
#pragma aux (__cdecl) renderFloorTile "renderFloorTile_"
|
||||
|
||||
void renderArenaTile(int x, int y) {
|
||||
char tile;
|
||||
struct SpriteRender *target;
|
||||
byte *drawBuffer;
|
||||
|
||||
tile = arenaLayout[y][x];
|
||||
|
||||
|
@ -58,7 +64,15 @@ void renderArenaTile(int x, int y) {
|
|||
target->x = x * TILE_SIZE;
|
||||
target->y = y * TILE_SIZE;
|
||||
|
||||
if (tile == 0) {
|
||||
drawBuffer = getDrawBuffer();
|
||||
|
||||
renderFloorTile(
|
||||
drawBuffer + target->x + target->y * VGA_DISPLAY_WIDTH
|
||||
);
|
||||
} else {
|
||||
drawSprite(target);
|
||||
}
|
||||
}
|
||||
|
||||
char arenaRedrawRequests[ARENA_HEIGHT_TILES][ARENA_WIDTH_TILES];
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'rmagick'
|
||||
require 'yaml'
|
||||
require 'erb'
|
||||
|
||||
data = YAML.load(File.read('spritesheet.yml'))
|
||||
|
||||
class Sprite
|
||||
def initialize(image:, sx:, sy:, width:, height:)
|
||||
@image = image
|
||||
@sx = sx
|
||||
@sy = sy
|
||||
@width = width
|
||||
@height = height
|
||||
end
|
||||
|
||||
def pixel_data
|
||||
@height.times.each_with_object([]) do |y, obj|
|
||||
obj << @width.times.map do |x|
|
||||
color = @image.pixel_color(x + @sx, y + @sy)
|
||||
|
||||
colormap.find_index { |c| c == color }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def colormap
|
||||
@colormap ||= @image.colors.times.map do |i|
|
||||
Magick::Pixel.from_color(@image.colormap(i))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
MovBytePtr = Data.define(:offset, :data)
|
||||
|
||||
ASM_TEMPLATE = <<~ASM
|
||||
<% sprites.each do |sprite| %>
|
||||
PUBLIC <%= sprite.exported_name %><% end %>
|
||||
|
||||
.386
|
||||
.model flat,c
|
||||
|
||||
.CODE
|
||||
|
||||
<% sprites.each do |sprite| %>
|
||||
<%= sprite.exported_name %>:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push ebx
|
||||
|
||||
mov eax, [ebp + 8]
|
||||
|
||||
<% sprite.bytes.each do |byte| %>
|
||||
mov BYTE PTR [eax + <%= byte.offset %>], <%= byte.data %><% end %>
|
||||
|
||||
pop ebx
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
<% end %>
|
||||
end
|
||||
ASM
|
||||
|
||||
C_TEMPLATE = <<~C
|
||||
<% sprites.each do |sprite| %>
|
||||
extern void <%= sprite.function_name %>(byte *);
|
||||
#pragma aux (__cdecl) <%= sprite.function_name %> "<%= sprite.exported_name %>"
|
||||
<% end %>
|
||||
C
|
||||
|
||||
class AssemblerSprite
|
||||
def initialize(
|
||||
name:,
|
||||
pixel_data:,
|
||||
screen_width:,
|
||||
transparent_color:,
|
||||
offset_x:,
|
||||
offset_y:,
|
||||
prefix:
|
||||
)
|
||||
@name = name
|
||||
@pixel_data = pixel_data
|
||||
@screen_width = screen_width
|
||||
@transparent_color = transparent_color
|
||||
@offset_x = offset_x
|
||||
@offset_y = offset_y
|
||||
@prefix = prefix
|
||||
end
|
||||
|
||||
def exported_name
|
||||
"#{function_name}_"
|
||||
end
|
||||
|
||||
def function_name
|
||||
"#{@prefix}_#{@name}"
|
||||
end
|
||||
|
||||
def bytes
|
||||
return @bytes if defined?(@bytes)
|
||||
|
||||
bytes = []
|
||||
|
||||
@pixel_data.each_with_index do |row, y|
|
||||
row.each_with_index do |column, x|
|
||||
next if @pixel_data[y][x] == @transparent_color
|
||||
|
||||
bytes << MovBytePtr.new(
|
||||
data: @pixel_data[y][x],
|
||||
offset: x - @offset_x + (y - @offset_y) * @screen_width
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
bytes
|
||||
end
|
||||
end
|
||||
|
||||
Screen = Data.define(:width, :transparent_color)
|
||||
SpriteData = Data.define(:image, :name, :position, :dimensions, :offset, :prefix)
|
||||
|
||||
screen = Screen.new(
|
||||
width: data["screen"]["width"],
|
||||
transparent_color: data["screen"]["transparentColor"]
|
||||
)
|
||||
|
||||
sprite_data = []
|
||||
|
||||
data["files"].each do |spritesheet|
|
||||
image = Magick::Image.read(spritesheet["file"]).first
|
||||
|
||||
spritesheet["sprites"].each do |name, details|
|
||||
sprite_data << SpriteData.new(
|
||||
image:,
|
||||
name:,
|
||||
prefix: spritesheet["prefix"],
|
||||
position: details["position"],
|
||||
dimensions: details["dimensions"],
|
||||
offset: details["offset"]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
sprites = sprite_data.map do |sd|
|
||||
sprite = Sprite.new(
|
||||
image: sd.image,
|
||||
sx: sd.position[0],
|
||||
sy: sd.position[1],
|
||||
width: sd.dimensions[0],
|
||||
height: sd.dimensions[1],
|
||||
)
|
||||
|
||||
AssemblerSprite.new(
|
||||
name: sd.name,
|
||||
prefix: sd.prefix,
|
||||
pixel_data: sprite.pixel_data,
|
||||
screen_width: screen.width,
|
||||
transparent_color: screen.transparent_color,
|
||||
offset_x: sd.offset[0],
|
||||
offset_y: sd.offset[1],
|
||||
)
|
||||
end
|
||||
|
||||
File.open('sprites.asm', 'w') do |fh|
|
||||
fh.puts ERB.new(ASM_TEMPLATE).result_with_hash(sprites:)
|
||||
end
|
||||
|
||||
File.open('sprites.h', 'w') do |fh|
|
||||
fh.puts ERB.new(C_TEMPLATE).result_with_hash(sprites:)
|
||||
end
|
||||
|
||||
puts "sprites.{asm,h} written"
|
7
game.c
7
game.c
|
@ -331,16 +331,11 @@ int currentSpeedCalc = 0;
|
|||
double averageSpeedCalc;
|
||||
clock_t startTime;
|
||||
|
||||
extern int doAThing(int);
|
||||
#pragma aux (__cdecl) doAThing "doAThing_"
|
||||
// non cdecl is put params into eax, ebx, and ecx
|
||||
|
||||
int main(void) {
|
||||
int keepRunning = 1;
|
||||
|
||||
fprintf(stderr, "%d\n", doAThing(1000));
|
||||
|
||||
return 0;
|
||||
|
||||
if (setupGame()) return 1;
|
||||
|
||||
maybeSpawnEnemy();
|
||||
|
|
3
makefile
3
makefile
|
@ -10,6 +10,9 @@ system/system.lib: .SYMBOLIC
|
|||
.c.o:
|
||||
wcc386 -q -bt=dos $<
|
||||
|
||||
.asm.o:
|
||||
wasm $<
|
||||
|
||||
game.exe: $(obj) system/system.lib
|
||||
wcl386 -q -bt=dos -l=dos4g $(obj) system/system.lib
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,22 @@
|
|||
|
||||
extern void sprite_arenaWallTop(byte *);
|
||||
#pragma aux (__cdecl) sprite_arenaWallTop "sprite_arenaWallTop_"
|
||||
|
||||
extern void sprite_arenaWallSide(byte *);
|
||||
#pragma aux (__cdecl) sprite_arenaWallSide "sprite_arenaWallSide_"
|
||||
|
||||
extern void sprite_arenaFloor(byte *);
|
||||
#pragma aux (__cdecl) sprite_arenaFloor "sprite_arenaFloor_"
|
||||
|
||||
extern void sprite_rabbit(byte *);
|
||||
#pragma aux (__cdecl) sprite_rabbit "sprite_rabbit_"
|
||||
|
||||
extern void sprite_mouse(byte *);
|
||||
#pragma aux (__cdecl) sprite_mouse "sprite_mouse_"
|
||||
|
||||
extern void sprite_bullet(byte *);
|
||||
#pragma aux (__cdecl) sprite_bullet "sprite_bullet_"
|
||||
|
||||
extern void sprite_enemy(byte *);
|
||||
#pragma aux (__cdecl) sprite_enemy "sprite_enemy_"
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
screen:
|
||||
width: 320
|
||||
transparentColor: 0
|
||||
files:
|
||||
- file: sprtsht.bmp
|
||||
prefix: "sprite"
|
||||
sprites:
|
||||
arenaWallTop:
|
||||
position: [0, 0]
|
||||
dimensions: [20, 20]
|
||||
offset: [10, 10]
|
||||
arenaWallSide:
|
||||
position: [20, 0]
|
||||
dimensions: [20, 20]
|
||||
offset: [0, 0]
|
||||
arenaFloor:
|
||||
position: [40, 0]
|
||||
dimensions: [20, 20]
|
||||
offset: [0, 0]
|
||||
rabbit:
|
||||
position: [0, 20]
|
||||
dimensions: [16, 16]
|
||||
offset: [8, 8]
|
||||
mouse:
|
||||
position: [16, 20]
|
||||
dimensions: [8, 8]
|
||||
offset: [4, 4]
|
||||
bullet:
|
||||
position: [16, 28]
|
||||
dimensions: [4, 4]
|
||||
offset: [1, 1]
|
||||
enemy:
|
||||
position: [0, 20]
|
||||
dimensions: [16, 16]
|
||||
offset: [8, 8]
|
|
@ -22,7 +22,7 @@ byte *initializeDrawBuffer() {
|
|||
}
|
||||
|
||||
void copyDrawBufferToDisplay() {
|
||||
memcpy(VGA, drawBuffer, 320 * 200);
|
||||
memcpy(VGA, drawBuffer, VGA_DISPLAY_WIDTH * VGA_DISPLAY_HEIGHT);
|
||||
}
|
||||
|
||||
void freeDrawBuffer() {
|
||||
|
|
56
test.asm
56
test.asm
|
@ -1,10 +1,11 @@
|
|||
PUBLIC doAThing_
|
||||
#PUBLIC doAThing_
|
||||
#PUBLIC renderTopTile_
|
||||
PUBLIC renderFloorTile_
|
||||
|
||||
.386
|
||||
.model flat,c
|
||||
|
||||
_TEXT segment byte public 'CODE'
|
||||
|
||||
.CODE
|
||||
doAThing_:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
@ -14,6 +15,53 @@ doAThing_:
|
|||
pop ebp
|
||||
ret
|
||||
|
||||
_TEXT ends
|
||||
renderTopTile_:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push ebx
|
||||
|
||||
mov eax, [ebp + 8]
|
||||
mov ebx, 20
|
||||
|
||||
_renderNextLine:
|
||||
mov DWORD PTR [eax], 02020202h
|
||||
mov DWORD PTR [eax + 4], 02020202h
|
||||
mov DWORD PTR [eax + 8], 02020202h
|
||||
mov DWORD PTR [eax + 12], 02020202h
|
||||
mov DWORD PTR [eax + 16], 02020202h
|
||||
|
||||
add eax, 320
|
||||
dec ebx
|
||||
cmp ebx, 0
|
||||
jne _renderNextLine
|
||||
|
||||
pop ebx
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
renderFloorTile_:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push ebx
|
||||
|
||||
mov eax, [ebp + 8]
|
||||
mov ebx, 20
|
||||
|
||||
_renderNextFloorLine:
|
||||
mov DWORD PTR [eax], 04040404h
|
||||
mov DWORD PTR [eax + 4], 04040404h
|
||||
mov DWORD PTR [eax + 8], 04040404h
|
||||
mov DWORD PTR [eax + 12], 04040404h
|
||||
mov DWORD PTR [eax + 16], 04040404h
|
||||
|
||||
add eax, 320
|
||||
dec ebx
|
||||
cmp ebx, 0
|
||||
jne _renderNextFloorLine
|
||||
|
||||
_done:
|
||||
pop ebx
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue