News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_ronaldo

#CPCtelera 1.4.2. release

Started by ronaldo, 11:59, 11 May 15

Previous topic - Next topic

0 Members and 2 Guests are viewing this topic.

FloppySoftware

Yes, of course, you are right.

But I wanted to point out that it's not a good practice to use unsigned ints as pointers because it' s not admited by the standard, even if it works on some compilers.

In fact, SDCC, should print a warning.
floppysoftware.es < NEW URL!!!
cpm-connections.blogspot.com.es

ronaldo

Quote from: FloppySoftware on 12:52, 14 July 15
In fact, SDCC, should print a warning.
It doesn't because the code makes an explicit cast previous to its use as pointer. Therefore, we are accessing memory using a proper u8*, which is initialized converting the value stored in the u16 variable. In fact, it doesn't work without the cast, as the compiler asks for a pointer to use the indirection operand * (which is normal, as it doesn't know what an unsigned int is supposed to be pointing to, as you were saying).

gerald

Quote from: ronaldo on 11:43, 14 July 15
@gerald: you are not using the same type. The program works well when using a byte pointer (char* or unsigned char*). The problem shows when using an unsigned int (u16) to store the address.

SDCC is 3.5.0, latest one.

Note that u8 and u16 are typedefs included with CPCtelera:

typedef unsigned char u8;
typedef unsigned int  u16;

Why not using standard type like uint8_t/uint16_t as define in stdint.h ?
It would make the code more generic, no ?

Quote from: FloppySoftware on 12:52, 14 July 15
But I wanted to point out that it's not a good practice to use unsigned ints as pointers because it' s not admited by the standard, even if it works on some compilers.
+1000  ;)

FloppySoftware

Ronaldo, IMHO, SDCC should print a warning due to that cast precisely.
floppysoftware.es < NEW URL!!!
cpm-connections.blogspot.com.es

ronaldo

Quote from: gerald on 13:16, 14 July 15
Why not using standard type like uint8_t/uint16_t as define in stdint.h ?
It would make the code more generic, no ?
The same reason not to use the basic type names (unsigned char, unsigned int, char, int...), just mere commodity. These types are provided, but not enforced. If anyone prefers to use uint8_t/uint16_t or the standard typenames, there is no problem.

Also, as said in previous posts, we are not making an argument in favor of using unsigned ints instead of pointers: we came here by chance, and just were analyzing the potential bug. We all agree that pointers should be used to point.

ronaldo

Quote from: FloppySoftware on 13:27, 14 July 15
Ronaldo, IMHO, SDCC should print a warning due to that cast precisely.
Why? Programmer is making something valid and doing it explicitly. I would understand a warning if no explicit cast was provided, to warn the programmer. But if the programmer does something valid explicitly, there is no reason for a warning.

mr_lou

Hm... ok, so as far as I can gather, I'm doing something wrong.
It works though, but as far as I can tell from this thread, I ought to be doing it differently.

Here's what I'm doing at the moment:

I have a 16bit array of screen addresses that contains the path of a sprite.

const u16 path[10] = {0xc058, 0xc858, 0xd058, 0xd858, 0xe058, 0xe858, 0xf058, 0xf858, 0xc0a8, 0xc8a8};


And then to draw my sprite, I type-cast it to a pointer:


cpct_drawSprite(mySprite, (u8*) path[position], TILEWIDTH, TILEHEIGHT);


This works fine. But I have an impression my array instead of being a 16bit array of screen addresses, ought to be an array of pointers, right?

So I have been trying hard to get the same results using an array of pointers, and failing miserably.


const u8* path[10] = {0xc058, 0xc858, 0xd058, 0xd858, 0xe058, 0xe858, 0xf058, 0xf858, 0xc0a8, 0xc8a8};
// or
const u8* path[10] = {(u8*)0xc058, (u8*)0xc858, (u8*)0xd058, (u8*)0xd858, (u8*)0xe058, (u8*)0xe858, (u8*)0xf058, (u8*)0xf858, (u8*)0xc0a8, (u8*)0xc8a8};
// and then
cpct_drawSprite(mySprite, path[position], TILEWIDTH, TILEHEIGHT);
// or
cpct_drawSprite(mySprite, *path[position], TILEWIDTH, TILEHEIGHT);
// or
cpct_drawSprite(mySprite, (u8*) path[position], TILEWIDTH, TILEHEIGHT);


But nothing is drawn.

So.....  any hints here?
Should I just continue using this 16bit array?

arnoldemu

Quote from: mr_lou on 17:54, 15 July 15

const u8* path[10] = {(u8*)0xc058, (u8*)0xc858, (u8*)0xd058, (u8*)0xd858, (u8*)0xe058, (u8*)0xe858, (u8*)0xf058, (u8*)0xf858, (u8*)0xc0a8, (u8*)0xc8a8};

// and then
cpct_drawSprite(mySprite, path[position], TILEWIDTH, TILEHEIGHT);



this combination should be correct.

My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

mr_lou

Quote from: arnoldemu on 17:58, 15 July 15
this combination should be correct.

Yea... that was the first one I tried too, but nothing is drawn....

Here is the assembler part in main.asm generated from the function.

    ld    de, (#(_path + 0x0170) + 0)
    ld    bc,#_mySprite
    ld    hl,#0x1004
    push    hl
    push    de
    push    bc
    call    _cpct_drawSprite
    ld    hl,#6
    add    hl,sp
    ld    sp,hl

ronaldo

Quote from: mr_lou on 17:54, 15 July 15
So I have been trying hard to get the same results using an array of pointers, and failing miserably.


const u8* path[10] = {0xc058, 0xc858, 0xd058, 0xd858, 0xe058, 0xe858, 0xf058, 0xf858, 0xc0a8, 0xc8a8};
// or
const u8* path[10] = {(u8*)0xc058, (u8*)0xc858, (u8*)0xd058, (u8*)0xd858, (u8*)0xe058, (u8*)0xe858, (u8*)0xf058, (u8*)0xf858, (u8*)0xc0a8, (u8*)0xc8a8};

The problem here is that you are creating an array of variable poiners to constants and, as the pointers are variables, they have the initialization problem we discussed previously. (You should read your definition as (const u8) * , which means you have a variable that points to a const u8 value, and that means that the constant value is what you are pointing, but not the pointer).

To solve this, you have to create constant pointers, that will be initializated as constants:

u8* const path[10] = {0xc058, 0xc858, 0xd058, 0xd858, 0xe058, 0xe858, 0xf058, 0xf858, 0xc0a8, 0xc8a8};

This means that you have 10 constant pointers, pointing to u8 values that might be changed. If you wanted constant pointers to constant values, you should use const 2 times.

mr_lou

Yes, it works now.

I'd never have figured that out. Would never have crossed my mind to switch "u8*" and "const". Can't do such nifty tricks in Java (where I'm coming from).

This works:

u8* const path[10] = {0xc058, 0xc858, 0xd058, 0xd858, 0xe058, 0xe858, 0xf058, 0xf858, 0xc0a8, 0xc8a8};


But this works too:

u8* const path[10] = {(u8*)0xc058, (u8*)0xc858, (u8*)0xd058, (u8*)0xd858, (u8*)0xe058, (u8*)0xe858, (u8*)0xf058, (u8*)0xf858, (u8*)0xc0a8, (u8*)0xc8a8};


Don't know if it's my imagination, but the first one seems to compile faster.

ronaldo

@mr_lou: both alternatives are equal, as the compiler does the casting implicitly. Both generate this code:

_path:
        .dw #0xC058
        .dw #0xC858
        .dw #0xD058
        .dw #0xD858
        .dw #0xE058
        .dw #0xE858
        .dw #0xF058
        .dw #0xF858
        .dw #0xC0A8
        .dw #0xC8A8

which is exactly what we use const for (instead of code initializers, for instance).

I don't think there is a perceivable performance difference. It might have been coincidence.

arnoldemu

for safety ;) :


const u8* const path[10] = {0xc058, 0xc858, 0xd058, 0xd858, 0xe058, 0xe858, 0xf058, 0xf858, 0xc0a8, 0xc8a8};



u8* path


this means a pointer that can be changed that points to modifyable data.


const u8 *path


means a pointer that can be changed but points to const/unchangeable data.


const u8 * const path

means an unchangeable pointer that points to unchangeable data ;)
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

mr_lou

Quote from: arnoldemu on 19:20, 15 July 15
for safety ;) :


const u8* const path[10] = {0xc058, 0xc858, 0xd058, 0xd858, 0xe058, 0xe858, 0xf058, 0xf858, 0xc0a8, 0xc8a8};


means an unchangeable pointer that points to unchangeable data ;)

But... doesn't that mean that I can't really use it for anything?
How can I draw a sprite there if the data is unchangeable?

arnoldemu

Quote from: mr_lou on 19:25, 15 July 15
But... doesn't that mean that I can't really use it for anything?
How can I draw a sprite there if the data is unchangeable?
You can use it for reading data.
True you want the other version.

I was being a bit pedantic, showing the difference between unchangeable data, and unchangeable pointers.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

mr_lou

Quote from: arnoldemu on 19:41, 15 July 15
You can use it for reading data.
True you want the other version.

I was being a bit pedantic, showing the difference between unchangeable data, and unchangeable pointers.

Well, I had to try it anyway, and it still draws the sprites fine....

lachlank

Just been working on a mode 1 game so got another useful c function for you guys to print a string without using firmware. I've ripped a few fonts from different mode 1 games, most of them store data in a monochrome 1bpp bitmap format (i.e. 8 bits = 8 pixels). I have found one exception (Deflektor) which stores the characters as raw sprites - this is much easier to draw but takes twice as much memory and you can't recolour dynamically. If you want to use these, see my Mode 0 drawing routine from earlier in this thread.


To draw any of the numerous 1bpp fonts, I create a local array[16] to store the intermediate "sprite" created from the monochrome data before drawing. This is pretty straightforward by leveraging the CPCTelera function cpct_px2byteM1(). There are options for the foreground and background pen so you can use any of the available colours in mode 1.


The font used in the below example is ripped from "Scooby Doo". I used this as it's one of the few I've ripped that is "full", i.e. every character from space up to Z is included. Most others have gaps or just include digits and A-Z. You will need to tweak the code if you want to use those to skip characters. I've attached the RGAS files containing all fonts I've ripped so far (hopefully the original authors/publishers won't mind by now!).


There are probably more efficient ways of doing this, but it works:




void printString(char *str, u8 forePen, u8 bgPen, u8 x, u8 y) {
u8 sprite[16]; // holds unpacked sprite to draw
u8* scrAddr = cpct_getScreenPtr ((void *) 0xC000, x, y); 
u8 *sprPtr;

while (*str > 0) {
u8 i;
u8 c = str[0];

c -= 32; // space is first in set
   
        // read the 8 bytes (each of 8 bits = one line)
sprPtr = G_Chars + c * 8;
for (i = 0; i < 8; i++) {
u8 b = sprPtr[0];
u8 leftPix = cpct_px2byteM1(b & 128 ? forePen : bgPen, b & 64 ? forePen : bgPen, b & 32 ? forePen : bgPen, b & 16 ? forePen : bgPen);
u8 rightPix = cpct_px2byteM1(b & 8 ? forePen : bgPen, b & 4 ? forePen : bgPen, b & 2 ? forePen : bgPen, b & 1 ? forePen : bgPen);

sprite[i * 2] = leftPix;
sprite[i * 2 + 1] = rightPix;
sprPtr++;
}

     
     
cpct_drawSprite(sprite, scrAddr, 2, 8);
     
str++;
scrAddr += 2;
     
        }   
}



const unsigned char G_Chars[504] = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x18,
0x18,
0x18,
0x18,
0x00,
0x18,
0x18,
0x00,
0x36,
0x36,
0x12,
0x24,
0x00,
0x00,
0x00,
0x00,
0x7E,
0xFC,
0x60,
0xF8,
0x0C,
0x7C,
0xF8,
0x00,
0x1C,
0x30,
0x3C,
0x6E,
0x66,
0x7E,
0x3C,
0x00,
0x7E,
0xFC,
0x0C,
0x18,
0x18,
0x30,
0x30,
0x00,
0x3C,
0x66,
0x72,
0x3C,
0x4E,
0x66,
0x3C,
0x00,
0x3C,
0x6E,
0x46,
0x66,
0x3C,
0x0C,
0x38,
0x00,
0x0C,
0x18,
0x18,
0x18,
0x18,
0x0C,
0x00,
0x00,
0x60,
0x30,
0x30,
0x30,
0x30,
0x60,
0x00,
0x00,
0x00,
0x14,
0x08,
0x3E,
0x08,
0x14,
0x00,
0x00,
0x00,
0x04,
0x0E,
0x04,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x18,
0x18,
0x08,
0x10,
0x00,
0x00,
0x00,
0x7E,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x18,
0x18,
0x00,
0x02,
0x02,
0x04,
0x08,
0x08,
0x00,
0x00,
0x00,
0x3C,
0x6E,
0xCE,
0xD6,
0xE6,
0xEC,
0x78,
0x00,
0x3C,
0x78,
0x18,
0x18,
0x18,
0x3C,
0x78,
0x00,
0x3C,
0x7E,
0x06,
0x0C,
0x10,
0x3E,
0x7C,
0x00,
0x3E,
0x7C,
0x08,
0x1C,
0x06,
0x7E,
0x3C,
0x00,
0x1E,
0x34,
0x64,
0x7E,
0x04,
0x0E,
0x1C,
0x00,
0x7E,
0xFC,
0x60,
0xF8,
0x0C,
0x7C,
0xF8,
0x00,
0x1C,
0x30,
0x3C,
0x6E,
0x66,
0x7E,
0x3C,
0x00,
0x7E,
0xFC,
0x0C,
0x18,
0x18,
0x30,
0x30,
0x00,
0x3C,
0x66,
0x72,
0x3C,
0x4E,
0x66,
0x3C,
0x00,
0x3C,
0x6E,
0x46,
0x66,
0x3C,
0x0C,
0x38,
0x00,
0x18,
0x18,
0x00,
0x18,
0x18,
0x00,
0x00,
0x00,
0x18,
0x18,
0x00,
0x18,
0x18,
0x08,
0x10,
0x00,
0x00,
0x02,
0x04,
0x02,
0x00,
0x00,
0x00,
0x00,
0x00,
0x7E,
0x00,
0x00,
0x7E,
0x00,
0x00,
0x00,
0x00,
0x04,
0x02,
0x04,
0x00,
0x00,
0x00,
0x00,
0x38,
0x7C,
0x18,
0x10,
0x00,
0x10,
0x30,
0x7C,
0xC6,
0xDE,
0xDE,
0xDE,
0xC0,
0x7C,
0x00,
0x00,
0x70,
0x38,
0x28,
0x4C,
0x7C,
0xC6,
0xC4,
0x00,
0x78,
0xFC,
0x24,
0x7E,
0x62,
0x7E,
0xFC,
0x00,
0x3C,
0x6E,
0xC4,
0xC0,
0xE0,
0x7C,
0x38,
0x00,
0x78,
0xFC,
0x26,
0x62,
0x46,
0x7C,
0xF8,
0x00,
0x7E,
0xFC,
0x20,
0x78,
0x40,
0x7E,
0xFC,
0x00,
0x7E,
0xFC,
0x20,
0x78,
0x40,
0x60,
0xC0,
0x00,
0x3C,
0x6E,
0xC4,
0xC0,
0xEE,
0x7C,
0x34,
0x00,
0x66,
0xEE,
0x66,
0x7E,
0x66,
0x66,
0xCC,
0x00,
0x1C,
0x38,
0x18,
0x18,
0x18,
0x1C,
0x38,
0x00,
0x1C,
0x38,
0x0C,
0x0C,
0x4C,
0x6C,
0x38,
0x00,
0x66,
0xEC,
0x78,
0x6C,
0x6C,
0x66,
0xC4,
0x00,
0x70,
0xE0,
0x60,
0x60,
0x60,
0x7E,
0xFC,
0x00,
0x42,
0xE6,
0x7E,
0x7A,
0x52,
0x42,
0xC6,
0x00,
0x42,
0xE6,
0x72,
0x7A,
0x5E,
0x4E,
0xC6,
0x00,
0x3C,
0x6C,
0xC6,
0xC6,
0xC6,
0x6C,
0x78,
0x00,
0x7C,
0xEE,
0x66,
0x7C,
0x60,
0x70,
0xE0,
0x00,
0x3C,
0x6C,
0xC6,
0xC6,
0xDE,
0x6C,
0x7A,
0x00,
0x7C,
0xEE,
0x66,
0x7C,
0x64,
0x76,
0xE6,
0x00,
0x38,
0x4E,
0x64,
0x18,
0x4C,
0xE4,
0x38,
0x00,
0x7E,
0xFC,
0x30,
0x30,
0x30,
0x38,
0x70,
0x00,
0x46,
0xCC,
0x64,
0x64,
0x64,
0x7E,
0x34,
0x00,
0x46,
0xCC,
0x64,
0x6C,
0x28,
0x38,
0x10,
0x00,
0x4A,
0xDA,
0x4A,
0x6A,
0x6A,
0x7E,
0x24,
0x00,
0x4E,
0xC4,
0x68,
0x10,
0x2C,
0x46,
0xE4,
0x00,
0x66,
0x62,
0x34,
0x1C,
0x48,
0x78,
0x30,
0x00,
0x7E,
0xFC,
0x08,
0x7C,
0x20,
0x7E,
0xFC,
0x3C,
0x30,
0x30,
0x30,
0x30,
0x30,
0x3C,
0x00,
0xC0,
0x60,
0x30,
0x18,
0x0C,
0x06,
0x02,
0x00,
0x3C,
0x0C,
0x0C,
0x0C,
0x0C,
0x0C,
0x3C,
0x00,
0x18,
0x3C,
0x7E,
0x18,
0x18,
0x18,
0x18,
0x00};








ronaldo

Nice one, @lachlank :).

I have bitmap font management added to the tasklist for future CPCtelera modules. Solutions like yours are very useful until a dedicated/optimized module is fully developed (which will take a lot of time/effort).

ervin

@ronaldo

Hi ronaldo.
I've installed the latest version of cpctelera, and I forgot about a previous post of yours in a different thread:

make -C cpctelera/ cleanall
./setup.sh


I'm now getting these warnings:

?ASlink-Warning-Definition of public symbol '_cpct_getScreenPtr' found more than once:
   Library: '/home/ErvinPajor/cpctelera/cpctelera/cpctelera.lib', Module: 'cpct_getScreenPtr.rel'
   Library: '/home/ErvinPajor/cpctelera/cpctelera/cpctelera.lib', Module: 'cpct_getScreenPtr_cbindings.rel'


No problems, I'll run the make/cleanall command and setup.sh again.
I'm just wondering though, can that make/cleanall command be built into setup.sh, in order to prevent errors like this happening?

ervin


mr_lou

Ok, time for another noob question from me.

I have finished my title-music track, and need to insert it now.

From what I've gathered, it's important that my STarKos track is located at the address I save it at.
I figure this might make it tricky or even impossible to include it the same way I include graphics.
Maybe I have to create this BASIC loader now that loads the music into a certain address first, and then loads my game-binary?
Or is there some clever way I can tell CPCtelera that certain data has to be at a certain address?

Addtionally (for the BASIC loader): Any clever way to not create a new DSK file every time, but rather just copy files to the existing DSK?

ronaldo

@ervin: Nice suggestion. There you go ;).

@mr_lou: There are easier ways to make SDCC put some data at a given place in memory. I think we discussed it in another thread, but I'm not sure... Anyways, you have it in the ArkosAudio example:


// Molusk song, created by Targhan / Arkos. Music is defined and
//   located at the desired location in memory in music.c
extern __at(0x1D4D) const u8 molusk_song[8883];


SDCC provides the prefix __at() to let you specify where you want some data to be located. This is a very convenient way of locating things into specific memory places, but you have to take some precautions when using it:

       
  • Put together in the same source code file all the things you want to be located at a specific absolute address. Otherwise, you can have them relocated by the linker. (Always check the .map file to be certain that things have been located where they should).
  • When adding something at a specific location, take into account that it will require the binary to have it statically inside. This means that a program starting at 0x40, with 256 bytes of code (0x40 to 0x140) and a 1K song located at 0x4000 (0x4000 to 0x4400) will produce a binary of almost 17K (from 0x40 to 0x4400). This is the only way to produce a binary that loads at 0x40 and statically places something at 0x4000: adding 0's from 0x140 to 0x4000. If you know this is the way it works, you can use it propperly to suit your needs.
  • Take into account that you can produce overlaps between loaded code and your specifically located data. If that happens, SDCC usually gives you warnings. Try to planify your locations in memory. For instance, if you know your song occupies 512 bytes, you may load it at 0x40, and you know it finishes at 0x240. Then you can change Z80CODELOC to 0x240 to load your code from there on.
I think this will be enough to suit most of your needs :).

ervin


mr_lou

I have problems regarding my titlemusic.

I use the STarKos tool GS to convert to binary, because I'm using Linux and don't like Mono.
The binary file is extracted from my DSK using ManageDsk without header.
Here is the first weird thing. ManageDsk say my entry point is 0x40, which is correct. That's the address I used.
It then says the length of the file is 5747 bytes. GS said that too, so all is still good.
But then ManageDsk says: Start address: 0x1d02
I don't get that. How can start address be an address much higher than the entry point + length?

Anyway, I then use cpct_bin2c to convert it into a byte array. And then create a titlemusic.h and titlemusic.c file.


//music.h
extern __at(0x40) const u8 music[5747];

//titlemusic.c
const u8 music[5747] = {0x53, 0x4b, 0x31, .... and so forth};


Then I changed Z80CODELOC to 0x16b3 because that where the music stops, as far as I can see.

Compiling gives error:

src/titlemusic.h:1: syntax error: token -> 'music' ; column 32

Tried changing Z80CODELOC to 0x26b3 suspecting it might be because of overlapping, but no. Same error.

What am I doing wrong?

mr_lou

Ok, the compile error was because I hadn't included #include <types.h>.... doh

So it compiles now, but gives me noise and other weird sounds.

Isn't STarKos supposed to be 100% compatible with Arkos Tracker?

Powered by SMFPacks Menu Editor Mod