pretty much all code that's commented out were either failed tests or debug code. You can just ignore those parts. The part after the first header sorts the points based on their Y-coordinate (from smallest to biggest) The secound part sets up flags and variables, and it calculates some numbers. For example dx is the fixed-point number that needs to be added in every scanline to adjust the X and make the line meet at the next point. The part after that calculates some values for the scanline (drawloop is the loop in wich scanlines are drawn, 1 cycle=1scanline). The first part does vertical clipping, then it checks the start and the end and when nessicary it switches them so the scanline can always be drawn from left to right. Then GetPixel is called and saved so it only has to be called once per scanline. The rest of that part is texture interpolation.
PlotLoop is the loop in which the pixels are plotted. 1 cycle = 1 pixel. It basically just reads the pixel of the texture at coordinates calculated in the part before this one, and plots that pixel. Then it shifts the texture coordinates and adjusts the results of the getPixel to plot the next pixel.
After that, the values for the scanlines are calculated again to update the x coordinates and texture coordinates. after the end of pizel plotting code comment, the variables are updated to draw the bottom half of the triangle. After repeating the loop, the triangle is complete and it returns.
The getPixel routine bihind that was just as documentation, so you could see which one I'm using and what exactely that it does. I doubt that that can be optimized.
I have to optimize this code, But I haven't really optimized before and whatever I try to do, I can't get it to work faster. Can anyone give me some tips?
Also: I'm optimizing for speed, not for size. The code can be quite big.
;--------------------------------------------------------------- ;This part sorts the points so that Y1 <= Y2 <= Y3 so ;we can just draw each scanline below the last one. ;---------------------------------------------------------------
;---------------------------------------------------------- ;Here, some variables are initialized. The delta ;variables (the variables which start with a 'd') ;contain the values that need to be added to ;the variables which start with a 't'. Variables ;with a 't' and a '1' are used for the start of ;the scanline. Those with a 't' and a '2' are used ;for the end of the scanline. ;----------------------------------------------------------
res 0, (IY);if this bit is 0, the routine is drawing the top half of the triangle. if it's 1, it's drawing the bottom half. res 1, (IY);This bit is used to store if the deltas for the texture coordinates inside scanlines are already calculated. They are constants, so they only need to be calculated once per half.
ld hl, (y2) ld de, (y1) subFP;This routine is for substracting fixed-point values, but here it's used to substract integer values. ld h, l ld l, 0 push hl ld hl, (x2) ld de, (x1) subFP ld h, l ld l, 0 pop de call DivFP ld (dx1), hl ld hl, (y3) ld de, (y2) subFP ld h, l ld l, 0 push hl ld hl, (x3) ld de, (x2) subFP ld h, l ld l, 0 pop de call DivFP ld (dx2), hl ld hl, (y3) ld de, (y1) subFP ld h, l ld l, 0 push hl ld hl, (x3) ld de, (x1) subFP ld h, l ld l, 0 pop de call DivFP ld (dx3), hl
ld hl, (y2) ld de, (y1) subFP ld h, l ld l, 0 push hl ld a, (u2) ld h, a ld l, 0 ld a, (u1) ld d, a ld e, 0 subFP ;ld h, l ;ld l, 0 pop de call DivFP ld (du1), hl ld hl, (y3) ld de, (y2) subFP ld h, l ld l, 0 push hl ld a, (u3) ld h, a ld l, 0 ld a, (u2) ld d, a ld e, 0 subFP ;ld h, l ;ld l, 0 pop de call DivFP ld (du2), hl ld hl, (y3) ld de, (y1) subFP ld h, l ld l, 0 push hl ld a, (u3) ld h, a ld l, 0 ld a, (u1) ld d, a ld e, 0 subFP ;ld h, l ;ld l, 0 pop de call DivFP ld (du3), hl
ld hl, (y2) ld de, (y1) subFP ld h, l ld l, 0 push hl ld a, (v2) ld h, a ld l, 0 ld a, (v1) ld d, a ld l, 0 subFP ;ld h, l ;ld l, 0 pop de call DivFP ld (dv1), hl ld hl, (y3) ld de, (y2) subFP ld h, l ld l, 0 push hl ld a, (v3) ld h, a ld l, 0 ld a, (v2) ld d, a ld e, 0 subFP ;ld h, l ;ld l, 0 pop de call DivFP ld (dv2), hl ld hl, (y3) ld de, (y1) subFP ld h, l ld l, 0 push hl ld a, (v3) ld h, a ld l, 0 ld a, (v1) ld d, a ld e, 0 subFP ;ld h, l ;ld l, 0 pop de call DivFP ld (dv3), hl
ld hl, (x1) bit 7, h jr z, TPos1 ld (tx1+1),hl \ ld a, $FF \ ld (tx1),a ld (tx2+1),hl \ ld a, $FF \ ld (tx2),a jr TEnd1 TPos1: ld (tx1+1),hl \ xor a \ ld (tx1),a ;store the 16bit integer at hl into 16.8 fixed point number tx1 ld (tx2+1),hl \ xor a \ ld (tx2),a TEnd1: ld hl, (y1) ld (_ty), hl
ld a, (u1) ld h, a ld l, 0 ld (tu1), hl ld (tu2), hl ld a, (v1) ld h, a ld l, 0 ld (tv1), hl ld (tv2), hl
;if Y1 == Y2, then we don't need to draw the first half. ld hl, (Y1) ld de, (y2) cpHLDE jp z, __TEndLoop
;+++++ End of initializing code +++++
;------------------------------------------------------------ ;This is the loop in which the triangle is drawn. ;In each interval of the loop, a single scanline is ;drawn. When this loop finished, one half of the ;triangle is drawn. ;------------------------------------------------------------
TDrawLoop: ld a, (_ty) ld d, a ;if the Y of the scanline is negative, then go to the next one. bit 7, a jp nz, Clip ld a, (_ty) ;If it reaches the bottom of the screen, then stop drawing the triangle. cp 64 ret nc
;Initialize variables for the scanline ld hl, (tu1) ld (tmpu), hl ld hl, (tv1) ld (tmpv), hl ld hl, (tu2) ld (temp2), hl ld hl, (tv2) ld (temp3), hl ld a, (tx2+1) ld (temp+1), a add a, 128 ld b, a ld a, (tx1+1) ld (temp), a add a, 128 cp b jr c, TOrdered ;jp po, TOrdered ld hl, (tu2) ld (tmpu), hl ld hl, (tv2) ld (tmpv), hl ld hl, (tu1) ld (temp2), hl ld hl, (tv1) ld (temp3), hl ld a, (tx2+1) ld (temp), a ld a, (tx1+1) ld (temp+1), a TOrdered: ld l, d ld a, (temp) ;folowing line was for the test to see if the sign was the problem ;sub 100 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; bit 7, a jr z, TGetPixel xor a TGetPixel: call GetPixel ld (mask), a ld (pointer), hl
;If the deltas for the texture coordinates inside a scanline are already ;calculated, then calculating them again is a wast of cycles. bit 1, (IY) jr nz, TPlotLoop ld hl, (tx1) ld de, (tx2) cpHLDE jr z, TPlotLoop ld a, (temp) ld h, a ld l, 0 ld a, (temp+1) ld d, a ld e, 0 subFP push hl ld hl, (tmpu) ld de, (temp2) subFP pop de call DivFP ld (tmpdu), hl ld a, (temp) ld h, a ld l, 0 ld a, (temp+1) ld d, a ld e, 0 subFP push hl ld hl, (tmpv) ld de, (temp3) subFP pop de call DivFP ld (tmpdv), hl set 1, (IY)
;--------------------------------------------------------------------- ;In this loop, the scanline is drawn. One interval here ;draws one pixel. When the loop ends, one scanline is drawn. ;---------------------------------------------------------------------
TPlotLoop: ;If the x coordinate of the pixel is negative, then go to the next pixel. ld a, (temp) bit 7, a jr nz, TNoCarry
;if the pixel goes of the right side of the screen, then go to the next scanline cp 96 jp nc, Clip
;Everything with 4 ;'s behind it are for 16x16 textures. Remove those and the ;textures will be 8x8.
ld a, (tmpv+1) add a, a;;;; ld hl, texture add a, l ld l, a
ld a, (tmpu+1) bit 3, a;;;; jr z, TFirstByte;;;; res 3, a;;;; inc hl;;;; TFirstByte:;;;; ld b, a inc b ld a, (hl) TshiftLoop: rla djnz TshiftLoop
ld a, (mask) ld hl, (pointer) jr c, TSetPixel
TResPixel: ;ld a, b cpl and (hl) ld (hl), a jr TEndPlot
ld hl, (tmpu) ld de, (tmpdu) add hl, de ld (tmpu), hl ld hl, (tmpv) ld de, (tmpdv) add hl, de ld (tmpv), hl
ld a, (temp+1) ld b, a ld a, (temp) ld hl, temp inc (hl) cp b jp nz, TPlotLoop
;+++++ End of pixel plotting code +++++
;If it's drawing the secound half, then make it recalculate the thexture deltas ;for inside the scanlines. This was to solve a bug in the texture mapping. bit 0, (IY) jr nz, aaaa;I suddenly ran out of inspiration for label names ; res 1, (IY) aaaa:
Clip: ld hl,(tx1) ld de, (dx1) ld a, d rla sbc a, a ld b, a add hl, de ld (tx1), hl ld a, (tx1+2) adc a, b ld (tx1+2), a
ld hl,(tx2) ld de, (dx3) ld a, d rla sbc a, a ld b, a add hl, de ld (tx2), hl ld a, (tx2+2) adc a, b ld (tx2+2), a
ld hl, (tu1) ld de, (du1) add hl, de ld (tu1), hl ld hl, (tu2) ld de, (du3) add hl, de ld (tu2), hl
ld hl, (tv1) ld de, (dv1) add hl, de ld (tv1), hl ld hl, (tv2) ld de, (dv3) add hl, de ld (tv2), hl
progress went slowly because the OS ate my source files a few times, but here's a small update: the world generation now generates a hilly landscape instaed of the flat landscape with a few block at higher and lower coordinates, the bug that made trees sometimes spawn next to eachother and overlap has been solved, and large narrow veins of iron ore are generated. The long narrow shape isn't intended, the blocks are placed randomly, but somehow they often group together in veins. That's it. I hope you enjoy.
Only one wire can be controlled manually, but both can be read. If you need to recieve information too, it will be much more complicated, because you can't send and recieve bytes at the same time. But in many cases 1 way communication is enough. In my case, the calc is used as a controle panel for a scoreboard: the calc sends the values as binary numbers to the arduino, which relays the information as decimal numbers to a 7-segment display driver
If you need any help on getting it to work, just ask. I can even help you in Dutch if you want.
also: what's TI-Nterface and is it fot the 84+? (name makes me think it's for the nspire).
void loop(){ digitalWrite(Dp, HIGH); //clock = 1 so we'll read a bit if(Recieving == 0){ //if nothing is being sent, we have to check for a 1 if(digitalRead(Dm) == HIGH){ //1 was send, so we'll have to recieve a byte Recieving = 1; RecievedBit = 0; RecievedByte = 0; } } else { //save the received bit if(digitalRead(Dm) == HIGH){ bitSet(RecievedByte, RecievedBit); } else{ bitClear(RecievedByte, RecievedBit); } RecievedBit++; if(RecievedBit == 8){ //if all 8 bits are sent, the byte is complete. Recieving = 0; Recieved = 1; } } delay(Delay); digitalWrite(Dp, LOW); if(Recieved){ if(RecievedByte == 50){ if(ledOn == 0){ digitalWrite(13, HIGH); ledOn = 1; } else { digitalWrite(13, LOW); ledOn = 0; } RecievedByte = 0; } Recieved = 0; } delay(Delay); }
HOW TO USE THE EXAMPLE PROGRAMS: - BACKUP YOUR PROGRAMS AND OTHER IMPORTANT DATA ON YOUR CALC - compile the z80 program (I used SPASM) and send it to your calc. - send the programs to the arduino and the calc. - if the arduino hasn't got an on-board LED, connect one (and a resistor!) to pin 13. - cut a USB mini male end of a USB cable (make sure the wire attached to it is long enough, works with both A-type and B-type (both have been tested)). - connect the white wire of the USB to pin 6, the green wire to pin 5 and the black wire to the GND. - make sure the arduino is powered and insert the USB cable into the calc's USB port. - run the assembly program with Asm( on the calc
When you run the program, press a key. The led should now turn on. When you run it and press a key again, the led should turn off. If your calc freezes, make sure the arduino is powered, the black wire is connected to the GND, runs the correct software and is connected to your calc.
What this does is: when you press a key on the calc, it sends a byte with a value of 50 to the arduino. The arduino notices a byte is send and checks if it's 50. If it's 50, pin 13 will toggle.
It may be very unoptimized (especially the arduino part, I learned the language two days ago), but it works. I hope this code can be usefull to anyone.
Also: thank you, Thepenguin77. Without your help, I wouldn't be able to control the USB port.
That's because when you reach the edges of the screen, the blocks in the edit buffer (the blocks that you see) are copied to the world and the blocks which are on an other location are loaded. this makes the part of the world that you can see shift by 8 pixels, and to make sure the player won't be stuck in blocks, the player moves 8 blocks as well. This causes the bad scrolling. I will probably once implement smooth scrolling, but I don't really know how to do that yet. I'm already glad the tilemap fully works and has collision checking and scrolling.
Since you all wanted it:
I hope you like it. It was hard to get it to work.
What are all the kinds of blocks you have in this game?
solid naturally generated can't be used to build unbreakable currently unused
from id 0 to id 15: air,wood, bedrock, leaves, planks, dirt, stone, cobblestone, iron ore, sand(can fall), ladder, water, lava, TNT(doesn't work yet), solid object, fluid object
What about a 256x64 world instead of 128x128? I don't remember if Minecraft needs this much depth and it would leave more space to build stuff. Or maybe 192x96?
128 is what the old minecraft used (now it's 256), so that should deffinately give you enough height. And the program itself doesn't use much RAM so right now a world of the size 128*300 blocks can fit in RAM, together with the program. So what fits in RAM isn't the problem right now. And too see if 128 is a good limit, then you must be able to fully play it, and for that it is in a too early state. What I mean with that is: I'm going to make this game fully functional first, so I'll imediately know if the world size is good or not.
By the way what is the max world size you plan to have in future versions?
Also, stevon8ter, If it still doesn't work, tell it, then I'll post a version that will work with asm( .
the current world size is 128*128, and that might stay like that because generating a new world now already takes 8 seconds. If that doesn't turn out big enough, then I'll have to make code something in to only generate parts ('chunks') of the world. If that happens, The max world size might be whatever fits into the memory.
I'm building one, too, but in Grammer! Did you use a sprite for your player? Seems a bit stalky...
Xeda already told me you were working on one. Apparently the controls are almost identical. And yes, I'm using a sprite for the player. It looks so bad because I'm not good at drawing sprites.
EDIT: A part of the world generation now works (Thank you Runer for your seeded pseudo random number generator routine). The world is now made of dirt (on top), stone (usually below ground) and trees a maximum of 20 trees (which spawn on the first dirt block of a collum). There are also still the bedrock borders.
The main source isn't changed, so you can just recompile with the previous minesrc3 program, and download the new genwrld program here. minecr_exe is the new executable. When you run it, don't worry, your calc isn't frozen. World generation takes 8 secounds
I also included an example world which can be loaded by the previous version (the one that supports appvars) (MCworld)
[12:35:53] <+Runer112> I'm about to make one of my hackiest optimizations ever [12:35:59] <+aeTIos> Oh [12:36:04] <+Runer112> a good favorite [12:36:08] <+Runer112> executing data as code [12:36:12] <+aeTIos> let's celebrate it before TI ruins it [12:36:13] <+OmnomIRC> (O)<hellninjas> :O [12:36:24] <+OmnomIRC> (O)<hellninjas> RUNER NO!! [12:36:31] <+OmnomIRC> (O)<hellninjas> YOU'LL BREAK TEH WORLDZ [12:36:41] <+aeTIos> heh [12:37:16] <+OmnomIRC> (O)<leafy> lolwat [12:37:53] <+OmnomIRC> (O)<hellninjas> idk [12:38:00] <+Runer112> wait shit [12:38:04] <+OmnomIRC> (O)<hellninjas> RACIST [12:38:12] <+Runer112> balls messed that up [12:38:24] <+OmnomIRC> (O)<hellninjas> your balls messed up your program? [12:38:26] <+OmnomIRC> (O)* hellninjas runs [12:38:53] <+OmnomIRC> (O)* ben_g was thinking abouth that too [12:39:00] <+OmnomIRC> (O)<hellninjas> lol [12:39:02] * +New post by DJ_O in How we can improve Omnimaga? http://omniurl.tk/10502/239609 [12:39:11] <+Runer112> oh crap [12:39:13] <+Runer112> that was even worse [12:39:22] <+OmnomIRC> (O)<hellninjas> DJ_O [12:40:11] <+Runer112> .z80 a9 [12:40:23] <+Runer112> man this is getting crazily hack [12:40:24] <+Runer112> y [12:40:25] <+OmnomIRC> (O)<DJ_O> nom [12:40:42] <+OmnomIRC> (O)<leafy> his massive testicles clogged up the z80