Join us on Discord!
You can help CodeWalrus stay online by donating here.

Graphics and other system routines

Started by DarkestEx, October 19, 2015, 10:31:05 PM

Previous topic - Next topic

0 Members and 3 Guests are viewing this topic.

DarkestEx

Hello, in this topic you can suggest and vote for graphics and drawing routines that I we will use in he official API and system.

To start, I want to have some sprite routines, but I can't get them to work:
void oled_bdraws(int16_t x, int16_t y, uint8_t width, uint8_t height, const uint8_t bitmap[]) {
uint8_t ow = width;

if(width + x > BUFFER_WIDTH)
width -= width + x - BUFFER_WIDTH;
if(height + y > BUFFER_HEIGHT)
height -= height + y - BUFFER_HEIGHT;
if(width + x <= 0 || height + y <= 0)
return;

for(int yi = y; yi < (y + height); yi++) {
for(int xi = x; xi < (x + width); xi++) {
if((yi - y) < 0 || (xi - x) < 0)
continue;
if(bitmap[(yi - y) * ow + (xi - x)] > 0)
screen_buffer[yi * ow + xi] = bitmap[(yi - y) * ow + (xi - x)];
}
}
}


The language for all routines should be C, but many other languages can be ported pretty easily I guess.
There is one framebuffer called screen_buffer[128*128]. It is using a palette. If you want to make your own functions, just make them take inputs (coordiantes, colors, etc.) and let them write to screen_buffer. The color 0x00 is transparent when drawn.
  • Calculators owned: TI-84+, Casio 101-S, RPN-Calc, Hewlett-Packard 100LX, Hewlett-Packard 95LX
  • Consoles, mobile devices and vintage computers owned: Original Commodore 64C, C64 DTV, Nintendo GameBoy Color, Nintendo GameCube, Xbox 360, PlayStation 2

c4ooo

Here is an optimized circle drawing routine in java:

    public void drawCircle(int x, int y, int r) {
        double angle, x1, y1;
        for (angle = 0; angle < 90; angle += 0.1) {
            x1 = r * Math.cos(angle * Math.PI / 180);
            y1 = r * Math.sin(angle * Math.PI / 180);
            setPixel((int) (x + x1), (int) (y + y1)); //bottom left
            setPixel((int) (x + x1), (int) (y - y1)); //top left
            setPixel((int) (x - x1), (int) (y + y1)); //nottom right
            setPixel((int) (x - x1), (int) (y - y1)); // top right
        }
    }

I dont really know how you handle doubles/floats in c :P

setPixer is self explanatory:

    public void setPixel(int x, int y) {
        if (x >= 0 && x < width && y >= 0 && y < height) {
            pixels[x + width * y] = color;
        }
    }


Drawing filled circles is a bit more tricky:



    public void drawFillCircle(int x, int y, int r) {
        double angle, x1, y1;
        for (angle = 0; angle < 90; angle += 0.1) {
            x1 = r * Math.cos(angle * Math.PI / 180);
            y1 = r * Math.sin(angle * Math.PI / 180);
            setPixel((int) (x + x1), (int) (y + y1)); //bottom left
            setPixel((int) (x - x1), (int) (y + y1)); //nottom right
            for (double i = x - x1; i <= x + x1; i++) {
                setPixel((int) i, (int) (y + y1));
                setPixel((int) i, (int) (y - y1));
            }
        }
    }


Hope it helps you in some way ;)

semiprocoder

Since graphics has extensive trig, have an index of already done trig values so that you don't have to always do the trig. For more accuracy you would obiously need to use full trig, but I think you could do angle vals 1-90 or something without wasting too much ram, like have a 360 b devoted to trig index, and a bit more to arc values
  • Calculators owned: ti nspire, ti 84 plus se
My cemetech username is awesommee333.

c4ooo

There will be no accuracy increase from using 1-360, just a speed decrease. Basicly all i need to do is calculate a quarter slice of the circle, then flip the values over the center to get the rest. ;)

semiprocoder

#4
Yeah thats why I was saying 1-90 instead of 1-360  :P

The 360 was 90*4(for num bytes in a float)=360
  • Calculators owned: ti nspire, ti 84 plus se
My cemetech username is awesommee333.

DarkestEx

#5
Oh that's awesome :)
I can't wait implement them all.
I am glad for any help with the graphics functions. As you all obviously know, the quality and speed of them massively affect all games that come out for the platform ;)

I really hope that more functions will follow. Especially from the calculator community who managed writing well working and fast, integer based graphics functions.
  • Calculators owned: TI-84+, Casio 101-S, RPN-Calc, Hewlett-Packard 100LX, Hewlett-Packard 95LX
  • Consoles, mobile devices and vintage computers owned: Original Commodore 64C, C64 DTV, Nintendo GameBoy Color, Nintendo GameCube, Xbox 360, PlayStation 2

c4ooo

Quote from: semiprocoder on October 20, 2015, 01:57:32 AM
Yeah thats why I was saying 1-90 instead of 1-360  :P

The 360 was 90*4(for num bytes in a float)=360
Whoops i completely revered the meaning of your post :P 
*facepalm*

Any how, although they definatly work, they might be optimizable. It has been a long time since i looked at that code.

novenary

As DarkestEx said, integer routines will be favored as the hardware does not support floating point (which has to be emulated in software) so integer or fixed point math is going to be faster.

semiprocoder

#8
maybe then just have cos*100, estimated to an int, or something returned and ten you just manually divide later?


edit: maybe cos*128, so that to divide you just bit shift some places to the right(for any power of two, 128 may not be accurate enough, idk), which is faster.
  • Calculators owned: ti nspire, ti 84 plus se
My cemetech username is awesommee333.

Snektron

  • Calculators owned: TI-84+
Legends say if you spam more than DJ Omnimaga, you will become a walrus...


semiprocoder

Yay! Triangles are awesome! Unfortunately many simple graphics apis don't let you use them, like ti nspire lua. It would be amazing if the microcat api had triangles.

Also, I made a fast sin/cos/tan generating program. It doesnt give you the sin value, but forces you to input a value and have it multiplied by the sin, because otherwise it would be annoying to deal with. I have not tested my code yet and don't have time to right now, but here it is:

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
# define PI 3.14159265358979323846
void writeSines() {
FILE *myfile;
if ((myfile = fopen("C:\\Users\\Andrew\\vs\\sines\\sinesBYTE.txt", "w")) == NULL) {
printf("didnt open");
return;
}
unsigned char tempSin;
for (double i = 1.0; i <= 90.0; i += 1.0) {
tempSin = (unsigned char)(sin(i / 180.0*PI) * 256);
fprintf(myfile, "%d, ", tempSin);
double tempcheck = tempSin;
}
fclose(myfile);
}
//generated using writeSines(). doesnt include sin(90) because sin(90)*256=256>255, max for byte/unsigned char, so it wraps around to 0, which is pointless
unsigned char sinArray[90] = {0, 4, 8, 13, 17, 22, 26, 31, 35, 40, 44, 48, 53, 57, 61, 66, 70, 74, 79, 83, 87, 91, 95, 100, 104, 108, 112, 116, 120, 124, 127, 131, 135, 139, 143, 146, 150, 154, 157, 161, 164, 167, 171, 174, 177, 181, 184, 187, 190, 193, 196, 198, 201, 204, 207, 209, 212, 214, 217, 219, 221, 223, 226, 228, 230, 232, 233, 235, 237, 238, 240, 242, 243, 244, 246, 247, 248, 249, 250, 251, 252, 252, 253, 254, 254, 255, 255, 255, 255, 255};
void fastSinMult(int *val, int degree) {
if (degree == 90) {
return;
}
else if (degree < 90 && degree>=0) {
*val = (*val)*sinArray[degree+1];
(*val) = (*val) >> 8;
return;
}
else if (degree > 90 && degree <= 180) {
fastSinMult(val, 180 - degree);
return;
}
else if (degree > 180 && degree <= 360) {
fastSinMult(val, degree - 180);
(*val) *= -1;
return;
}
else if (degree > 360)//not allowing negative degrees for now
fastSinMult(val, degree % 360);
}
void fastCosMult(int *val, int degree) {
fastSinMult(val, degree - 90);
}
void fastTanMult(int *val, int angle) {
int val1 = *val;
int val2 = *val;
fastSinMult(&val1, angle);
fastCosMult(&val2, angle);
(*val) = val1 / val2;
}
  • Calculators owned: ti nspire, ti 84 plus se
My cemetech username is awesommee333.

DarkestEx

#11
Quote from: semiprocoder on October 20, 2015, 04:28:47 PM
Yay! Triangles are awesome! Unfortunately many simple graphics apis don't let you use them, like ti nspire lua. It would be amazing if the microcat api had triangles.

Also, I made a fast sin/cos/tan generating program. It doesnt give you the sin value, but forces you to input a value and have it multiplied by the sin, because otherwise it would be annoying to deal with. I have not tested my code yet and don't have time to right now, but here it is:

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
# define PI 3.14159265358979323846
void writeSines() {
FILE *myfile;
if ((myfile = fopen("C:\\Users\\Andrew\\vs\\sines\\sinesBYTE.txt", "w")) == NULL) {
printf("didnt open");
return;
}
unsigned char tempSin;
for (double i = 1.0; i <= 90.0; i += 1.0) {
tempSin = (unsigned char)(sin(i / 180.0*PI) * 256);
fprintf(myfile, "%d, ", tempSin);
double tempcheck = tempSin;
}
fclose(myfile);
}
//generated using writeSines(). doesnt include sin(90) because sin(90)*256=256>255, max for byte/unsigned char, so it wraps around to 0, which is pointless
unsigned char sinArray[90] = {0, 4, 8, 13, 17, 22, 26, 31, 35, 40, 44, 48, 53, 57, 61, 66, 70, 74, 79, 83, 87, 91, 95, 100, 104, 108, 112, 116, 120, 124, 127, 131, 135, 139, 143, 146, 150, 154, 157, 161, 164, 167, 171, 174, 177, 181, 184, 187, 190, 193, 196, 198, 201, 204, 207, 209, 212, 214, 217, 219, 221, 223, 226, 228, 230, 232, 233, 235, 237, 238, 240, 242, 243, 244, 246, 247, 248, 249, 250, 251, 252, 252, 253, 254, 254, 255, 255, 255, 255, 255};
void fastSinMult(int *val, int degree) {
if (degree == 90) {
return;
}
else if (degree < 90 && degree>=0) {
*val = (*val)*sinArray[degree+1];
(*val) = (*val) >> 8;
return;
}
else if (degree > 90 && degree <= 180) {
fastSinMult(val, 180 - degree);
return;
}
else if (degree > 180 && degree <= 360) {
fastSinMult(val, degree - 180);
(*val) *= -1;
return;
}
else if (degree > 360)//not allowing negative degrees for now
fastSinMult(val, degree % 360);
}
void fastCosMult(int *val, int degree) {
fastSinMult(val, degree - 90);
}
void fastTanMult(int *val, int angle) {
int val1 = *val;
int val2 = *val;
fastSinMult(&val1, angle);
fastCosMult(&val2, angle);
(*val) = val1 / val2;
}

Thank you :)
As you were so kind and provided the functions, I will absolutely implement them :)
Especially the Sin tables are pretty useful.

I'll add you all to the special thanks list obviously for all your great code :)
  • Calculators owned: TI-84+, Casio 101-S, RPN-Calc, Hewlett-Packard 100LX, Hewlett-Packard 95LX
  • Consoles, mobile devices and vintage computers owned: Original Commodore 64C, C64 DTV, Nintendo GameBoy Color, Nintendo GameCube, Xbox 360, PlayStation 2

Snektron

#12

public void circle(int cx, int cy, int r)
{
int f = 1-r;
int ddFx = 1;
int ddFy = -2*r;
int x = 0;
int y = r;

setPixel(cx, cy+r);
setPixel(cx, cy-r);
setPixel(cx+r, cy);
setPixel(cx-r, cy);

while (x < y)
{
if (f>=0)
{
y--;
ddFy += 2;
f += ddFy;
}

x++;
ddFx += 2;
f += ddFx;

setPixel(cx + x, cy + y);
setPixel(cx - x, cy + y);
setPixel(cx + x, cy - y);
setPixel(cx - x, cy - y);

setPixel(cx + y, cy + x);
setPixel(cx - y, cy + x);
setPixel(cx + y, cy - x);
setPixel(cx - y, cy - x);
}
}


Here's a sine/cosineless circle algoritm in java (midpoint circle/bresenham). Also you might want to thin about adding translations, since they;re really usefull.

EDIT: i've altered the circle algoritm for a filled circle

public void fcircle(int cx, int cy, int r)
{
int f = 1-r;
int ddFx = 1;
int ddFy = -2*r;
int x = 0;
int y = r;

for (int fr=r; fr>0; fr--)
{
setPixel(cx, cy+fr);
setPixel(cx, cy-fr);
setPixel(cx+fr, cy);
setPixel(cx-fr, cy);
}

setPixel(cx, cy);

while (x < y)
{
if (f >= 0)
{
y--;
ddFy += 2;
f += ddFy;
}

x++;
ddFx += 2;
f += ddFx;

for (int fx=x; fx>0; fx--)
{
setPixel(cx + fx, cy + y);
setPixel(cx - fx, cy + y);
setPixel(cx + fx, cy - y);
setPixel(cx - fx, cy - y);
}

for (int fy=y; fy>0; fy--)
{
setPixel(cx + fy, cy + x);
setPixel(cx - fy, cy + x);
setPixel(cx + fy, cy - x);
setPixel(cx - fy, cy - x);
}
}
}
  • Calculators owned: TI-84+
Legends say if you spam more than DJ Omnimaga, you will become a walrus...


DarkestEx

Quote from: Cumred_Snektron on October 20, 2015, 04:57:13 PM

public void circle(int cx, int cy, int r)
{
int f = 1-r;
int ddFx = 1;
int ddFy = -2*r;
int x = 0;
int y = r;

setPixel(cx, cy+r);
setPixel(cx, cy-r);
setPixel(cx+r, cy);
setPixel(cx-r, cy);

while (x < y)
{
if (f>=0)
{
y--;
ddFy += 2;
f += ddFy;
}

x++;
ddFx += 2;
f += ddFx;

setPixel(cx + x, cy + y);
setPixel(cx - x, cy + y);
setPixel(cx + x, cy - y);
setPixel(cx - x, cy - y);

setPixel(cx + y, cy + x);
setPixel(cx - y, cy + x);
setPixel(cx + y, cy - x);
setPixel(cx - y, cy - x);
}
}


Here's a sine/cosineless circle algoritm (midpoint circle/bresenham). Also you might want to thin about adding translations, since they;re really usefull.
Thats great, thank you! :)

Rounded rectangles would be useful too I guess. And if somebody has a lightweight raycaster or raytracer written in C or who could port one, I would absolutely love to have it in the graphics library. At 120MHz core speed, a raytracer or raycaster is feasible and would allow for more great games.
  • Calculators owned: TI-84+, Casio 101-S, RPN-Calc, Hewlett-Packard 100LX, Hewlett-Packard 95LX
  • Consoles, mobile devices and vintage computers owned: Original Commodore 64C, C64 DTV, Nintendo GameBoy Color, Nintendo GameCube, Xbox 360, PlayStation 2

semiprocoder

#14
Just wanted to point it out, I don't know any graphics so I won't be able to help you there.

Anyways, the trig functions, namely tan don't even give near the correct value, so here are the actual functions. I also updated sin to allow negative numbers, forgot to do that. Here is the new code, without any of the testing stuff that I had before that I was going to use:

unsigned char sinArray[90] = {0, 4, 8, 13, 17, 22, 26, 31, 35, 40, 44, 48, 53, 57, 61, 66, 70, 74, 79, 83, 87, 91, 95, 100, 104, 108, 112, 116, 120, 124, 127, 131, 135, 139, 143, 146, 150, 154, 157, 161, 164, 167, 171, 174, 177, 181, 184, 187, 190, 193, 196, 198, 201, 204, 207, 209, 212, 214, 217, 219, 221, 223, 226, 228, 230, 232, 233, 235, 237, 238, 240, 242, 243, 244, 246, 247, 248, 249, 250, 251, 252, 252, 253, 254, 254, 255, 255, 255, 255, 255};
void fastSinMult(int *val, int degree) {
if (degree == 90) {
return;
}
else if (degree < 90 && degree>=0) {
*val = (*val)*sinArray[degree-1];
(*val) = (*val) >> 8;
return;
}
else if (degree > 90 && degree <= 180) {
fastSinMult(val, 180 - degree);
return;
}
else if (degree > 180 && degree <= 360) {
fastSinMult(val, degree - 180);
(*val) *= -1;
return;
}
else if (degree > 360)
fastSinMult(val, degree % 360);
else {
fastSinMult(val, -degree);
(*val) = -(*val);
}
}
void fastCosMult(int *val, int degree) {
fastSinMult(val, 90-degree);
}
void fastTanMult(int *val, int degree) {
int val1 = *val;
int val2 = *val;
fastSinMult(&val1, degree);
fastCosMult(&val2, degree);
(*val) = ((*val) * val1) / val2;
}


Also I want to do arccos, arctan, and arcsin, but I am not sure how I would do that with ints. If you have any ideas about that tell me.
Furthermore, should I make a simple vector library, like magnitude, dot product, cross product, etc. or do you already have that without floats, cause I think it would be quite easy to do.
  • Calculators owned: ti nspire, ti 84 plus se
My cemetech username is awesommee333.

Powered by EzPortal