Last active
November 18, 2017 03:12
-
-
Save hex007/fc4396de31e0c9e04a511869038d889c to your computer and use it in GitHub Desktop.
Program to test Pi's overscan, aspect ratio, and color settings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Raspberry Pi SDL2 image test with gradient and boundry. | |
- use keyboard buttons to change frames | |
- press F4 to exit | |
- in the boundaries frame, the entire boundry (white) should be visible and as outside as possible | |
to ensure overscan settings is optimal | |
- in the boundaries frame, the central rectangle should be a perfect square | |
- in the next frame, the circle should be perfect circle to ensure proper aspect ratio | |
To test: | |
wget -O tests.cpp "https://gist.githubusercontent.com/hex007/fc4396de31e0c9e04a511869038d889c/raw" | |
g++ -std=c++11 -lSDL2 -o tests tests.cpp | |
./tests | |
Changelog: | |
rev 1) initial commit | |
rev 2) Added documentation and instructions | |
rev 3) Added more gradients | |
rev 4) Removed abs ambiguity | |
*/ | |
#include <stdio.h> | |
#include <unistd.h> | |
#include <iostream> | |
#include <iomanip> | |
#include <SDL2/SDL.h> | |
using namespace std; | |
typedef void (*draw_func) (); | |
struct rgb { unsigned char R, G, B; }; | |
const int sq_percent = 50; // Should be < 100 | |
const int bytes = 3; | |
int func_c = 0; | |
int width = 0; | |
int height = 0; | |
unsigned char* frame; | |
SDL_Renderer *renderer; | |
SDL_Texture *texture; | |
SDL_Window *window; | |
void loadDisplayDimentions() | |
{ | |
SDL_DisplayMode dispMode; | |
SDL_GetDesktopDisplayMode(0, &dispMode); | |
width = dispMode.w; | |
height = dispMode.h; | |
printf("Width : %d, Height : %d\n", width, height); | |
} | |
void drawBoundry() | |
{ | |
int c = sq_percent * min(height, width) / 100; | |
int c_w = width / 2; | |
int c_h = height / 2; | |
for (int j = 0; j < height; j++) | |
{ | |
int d1 = j * width * bytes; // first column | |
int d2 = d1 + (width-1) * bytes; // last column | |
int d3 = (j * width + (width - c)/2) * bytes; | |
int d4 = (j * width + (width + c)/2) * bytes; | |
frame[d1 + 0] = frame[d1 + 1] = frame[d1 + 2] = 255; | |
frame[d2 + 0] = frame[d2 + 1] = frame[d2 + 2] = 255; | |
frame[d3 + 0] = frame[d3 + 1] = frame[d3 + 2] = 255; | |
frame[d4 + 0] = frame[d4 + 1] = frame[d4 + 2] = 255; | |
} | |
for (int i = 0; i < width; i++) | |
{ | |
int d1 = i * bytes; // first row | |
int d2 = d1 + width * (height-1) * bytes; // last row | |
int d3 = (width * (height - c)/2 + i) * bytes; | |
int d4 = (width * (height + c)/2 + i) * bytes; | |
frame[d1 + 0] = frame[d1 + 1] = frame[d1 + 2] = 255; | |
frame[d2 + 0] = frame[d2 + 1] = frame[d2 + 2] = 255; | |
frame[d3 + 0] = frame[d3 + 1] = frame[d3 + 2] = 255; | |
frame[d4 + 0] = frame[d4 + 1] = frame[d4 + 2] = 255; | |
} | |
} | |
void drawCircle() | |
{ | |
int thresh = 25 * min(height, width) / 100; // draw threshold | |
int r2 = pow(sq_percent * min(height, width) / 200, 2); | |
int c_w = width / 2; | |
int c_h = height / 2; | |
for (int j = 0; j < height; j++) | |
{ | |
for (int i = 0; i < width; i++) | |
{ | |
if (abs((int) (pow(i - c_w, 2) + pow(j - c_h, 2) - r2)) < thresh) | |
{ | |
int p = (j*width + i) * bytes; | |
frame[p + 0] = frame[p + 1] = frame[p + 2] = 255; | |
} | |
} | |
} | |
} | |
void drawGradient(rgb tl, rgb tr, rgb bl, rgb br, int w = width, int h = height, int v_offset = 0, int h_offset = 0) | |
{ | |
int p; | |
double l, m; | |
for (int j = 0; j < h; j++) | |
{ | |
for (int i = 0; i < w; i++) | |
{ | |
p = bytes * ((j + h_offset) * width + (i + v_offset)); | |
l = (double) i / w; | |
m = (double) j / h; | |
frame[p + 0] = (1-l)*(1-m)*tl.R + l*(1-m)*tr.R + (1-l)*m*bl.R + l*m*br.R; | |
frame[p + 1] = (1-l)*(1-m)*tl.G + l*(1-m)*tr.G + (1-l)*m*bl.G + l*m*br.G; | |
frame[p + 2] = (1-l)*(1-m)*tl.B + l*(1-m)*tr.B + (1-l)*m*bl.B + l*m*br.B; | |
} | |
} | |
} | |
void drawColor(unsigned char r, unsigned char g, unsigned char b) | |
{ | |
int total = width * height * bytes; | |
for (int i = 0; i < total; i = i+3) | |
{ | |
frame[i + 0] = r; | |
frame[i + 1] = g; | |
frame[i + 2] = b; | |
} | |
} | |
void drawR() { drawColor(255, 0 , 0 ); } | |
void drawG() { drawColor(0 , 255, 0 ); } | |
void drawB() { drawColor(0 , 0 , 255); } | |
void drawC() { drawColor(0 , 255, 255); } | |
void drawM() { drawColor(255, 0 , 255); } | |
void drawY() { drawColor(255, 255, 0 ); } | |
void drawK() { drawColor(0 , 0 , 0 ); } | |
void drawW() { drawColor(255, 255, 255); } | |
void drawRainPi() { drawGradient({255,0,0}, {255,255,0}, {0,0,255}, {0,255,255}); } | |
void drawRain00() { drawGradient({255,255,255}, {0,0,0}, {255,255,255}, {0,0,0}); } | |
void drawRain01() { drawGradient({255,255,255}, {255,255,255}, {0,0,0}, {0,0,0}); } | |
void drawRain02() { drawGradient({255,0,0}, {0,255,0}, {0,0,255}, {255,255,255}); } | |
void drawRain03() { drawGradient({255,255,0}, {0,255,255}, {255,0,255}, {0,0,0}); } | |
void drawRainHor() | |
{ | |
drawGradient({255,0,0}, {255,255,0}, {255,0,0}, {255,255,0}, width/6, height, 0 * width/6, 0); | |
drawGradient({255,255,0}, {0,255,0}, {255,255,0}, {0,255,0}, width/6, height, 1 * width/6, 0); | |
drawGradient({0,255,0}, {0,255,255}, {0,255,0}, {0,255,255}, width/6, height, 2 * width/6, 0); | |
drawGradient({0,255,255}, {0,0,255}, {0,255,255}, {0,0,255}, width/6, height, 3 * width/6, 0); | |
drawGradient({0,0,255}, {255,0,255}, {0,0,255}, {255,0,255}, width/6, height, 4 * width/6, 0); | |
drawGradient({255,0,255}, {255,0,0}, {255,0,255}, {255,0,0}, width/6, height, 5 * width/6, 0); | |
} | |
void drawRainVer() | |
{ | |
drawGradient({255,0,0}, {255,255,0}, {255,0,0}, {255,255,0}, width, height/6, 0, 0 * height/6); | |
drawGradient({255,255,0}, {0,255,0}, {255,255,0}, {0,255,0}, width, height/6, 0, 1 * height/6); | |
drawGradient({0,255,0}, {0,255,255}, {0,255,0}, {0,255,255}, width, height/6, 0, 2 * height/6); | |
drawGradient({0,255,255}, {0,0,255}, {0,255,255}, {0,0,255}, width, height/6, 0, 3 * height/6); | |
drawGradient({0,0,255}, {255,0,255}, {0,0,255}, {255,0,255}, width, height/6, 0, 4 * height/6); | |
drawGradient({255,0,255}, {255,0,0}, {255,0,255}, {255,0,0}, width, height/6, 0, 5 * height/6); | |
} | |
draw_func funcs[] = { | |
drawRainPi, drawRainHor, drawRainVer, | |
drawRain00, drawRain01, drawRain02, drawRain03, | |
drawR, drawG, drawB, drawW, drawC, drawY, drawM, drawK, | |
drawBoundry, drawCircle | |
}; | |
void drawFrame() | |
{ | |
funcs[func_c](); | |
func_c = (func_c + 1) % (sizeof(funcs)/sizeof(draw_func)); | |
SDL_RenderClear(renderer); | |
SDL_UpdateTexture(texture, NULL, frame, width * sizeof(char) * bytes); | |
SDL_RenderCopy(renderer, texture, NULL, NULL); | |
SDL_RenderPresent(renderer); | |
} | |
int main(int argc, char const *argv[]) { | |
if (SDL_Init(SDL_INIT_VIDEO) < 0 ) { | |
cerr << "Unable to initialize SDL" << endl; | |
exit(1); | |
} | |
loadDisplayDimentions(); | |
SDL_CreateWindowAndRenderer(0, 0, SDL_WINDOW_FULLSCREEN_DESKTOP, &window, &renderer); | |
SDL_ShowCursor(SDL_DISABLE); | |
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, width, height); | |
frame = new unsigned char[height * width * bytes]; | |
drawFrame(); | |
SDL_Event event; | |
while(SDL_WaitEvent(&event)) { | |
if (event.type == SDL_QUIT) | |
break; | |
if (event.type != SDL_KEYDOWN) | |
continue; | |
if (event.key.keysym.sym == SDLK_F4) | |
break; | |
drawFrame(); | |
} | |
SDL_Quit(); | |
delete[] frame; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment