Image class is just array of palette indices converted from the rgb data of any image by using euclidian distance between palette rgb and pixel rgb. Works well.
579 lines
18 KiB
C++
579 lines
18 KiB
C++
//
|
|
// Created by Bobby Lucero on 4/20/24.
|
|
//
|
|
|
|
#include "Graphics.h"
|
|
#include "PycronImage.h"
|
|
#include "Font.h"
|
|
#include "../Utilities.h"
|
|
#include "../StateManager.h"
|
|
|
|
#include <fstream>
|
|
#include <raymath.h>
|
|
|
|
|
|
|
|
|
|
Graphics::Graphics(int screenWidth, int screenHeight, int startupScale) : m_screenWidth(screenWidth), m_screenHeight(screenHeight){
|
|
|
|
m_NormalFont = new PixelFont(5, 7, "resources/fonts/main.font");
|
|
m_currentFont = m_NormalFont;
|
|
|
|
m_startupScreenWidth = screenWidth * startupScale;
|
|
m_startupScreenHeight = screenHeight * startupScale;
|
|
m_windowWidth = m_startupScreenWidth;
|
|
m_windowHeight = m_startupScreenHeight;
|
|
|
|
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
|
InitWindow(m_startupScreenWidth, m_startupScreenHeight, "test");
|
|
SetTargetFPS(60);
|
|
|
|
m_virtualScreen = LoadRenderTexture(screenWidth, screenHeight);
|
|
m_origin = {0,0};
|
|
m_virtualScreenLocalBounds = {0.0f, 0.0f, (float)m_virtualScreen.texture.width, (float)m_virtualScreen.texture.height };
|
|
m_virtualScreenWindowBounds = {0.0f, 0.0f, (float)m_windowWidth, (float)m_windowHeight};
|
|
|
|
m_virtualScreenImageBuffer = GenImageColor(m_screenWidth, m_screenHeight, BLACK);
|
|
m_virtualScreenColorBuffer = {};
|
|
m_virtualScreenColorBuffer.resize(screenWidth * screenHeight);
|
|
|
|
calculateScreenPositionInWindow();
|
|
|
|
}
|
|
|
|
Graphics::~Graphics() {
|
|
delete m_NormalFont;
|
|
m_NormalFont = nullptr;
|
|
m_currentFont = nullptr;
|
|
}
|
|
|
|
void Graphics::draw(StateManager* stateManager) {
|
|
m_windowShouldClose = WindowShouldClose();
|
|
|
|
if (IsWindowResized()) {
|
|
m_windowWidth = GetScreenWidth();
|
|
m_windowHeight = GetScreenHeight();
|
|
calculateScreenPositionInWindow();
|
|
}
|
|
|
|
stateManager->Draw();
|
|
copyBufferToGPU();
|
|
renderVirtualScreen();
|
|
}
|
|
|
|
void Graphics::copyBufferToGPU() {
|
|
Color* pixel_data = LoadImageColors(m_virtualScreenImageBuffer);
|
|
for (int i = 0; i < m_screenWidth * m_screenHeight; ++i) {
|
|
pixel_data[i] = GetColor(m_paletteByID[m_virtualScreenColorBuffer[i]]);
|
|
}
|
|
UpdateTexture(m_virtualScreen.texture, pixel_data);
|
|
UnloadImageColors(pixel_data);
|
|
}
|
|
|
|
void Graphics::renderVirtualScreen() {
|
|
BeginDrawing();
|
|
ClearBackground(BLACK);
|
|
DrawTexturePro(m_virtualScreen.texture, m_virtualScreenLocalBounds, m_virtualScreenWindowBounds, m_origin, 0.0f, WHITE);
|
|
DrawText(std::to_string(GetFPS()).c_str(), 10, 10, 30, YELLOW);
|
|
|
|
EndDrawing();
|
|
}
|
|
|
|
void Graphics::loadPalette(std::string path) {
|
|
std::ifstream paletteFile(path);
|
|
std::string line;
|
|
|
|
if(paletteFile.is_open()){
|
|
int idx = 0;
|
|
while(getline(paletteFile, line)){
|
|
int color = stoi(line, nullptr, 16);
|
|
//Palette.push_back();
|
|
color = color << 8 | 0xFF;
|
|
m_paletteByID.insert({idx, color});
|
|
idx++;
|
|
}
|
|
paletteFile.close();
|
|
}
|
|
}
|
|
|
|
void Graphics::calculateScreenPositionInWindow() {
|
|
float virtualAspectRatio = (float)m_screenWidth / (float)m_screenHeight;
|
|
float windowAspectRatio = (float)m_windowWidth / (float)m_windowHeight;
|
|
|
|
if(windowAspectRatio > virtualAspectRatio) {
|
|
m_virtualScreenWindowBounds.height = (float)m_windowHeight;
|
|
m_virtualScreenWindowBounds.width = m_virtualScreenWindowBounds.height * virtualAspectRatio;
|
|
m_origin.x = -(m_windowWidth / 2.0f - (m_virtualScreenWindowBounds.width / 2.0f));
|
|
m_origin.y = 0;
|
|
}else {
|
|
m_virtualScreenWindowBounds.width = (float)m_windowWidth;
|
|
m_virtualScreenWindowBounds.height = m_virtualScreenWindowBounds.width / virtualAspectRatio;
|
|
m_origin.x = 0;
|
|
m_origin.y = -(m_windowHeight / 2.0f - (m_virtualScreenWindowBounds.height / 2.0f));
|
|
}
|
|
}
|
|
|
|
int Graphics::rgbToID(int r, int g, int b) {
|
|
r = Clamp(r, 0, 255);
|
|
g = Clamp(g, 0, 255);
|
|
b = Clamp(b, 0, 255);
|
|
uint8_t idx = 0;
|
|
Color c = GetColor(m_paletteByID[idx]);
|
|
double minDist = std::pow(r - c.r, 2) +
|
|
std::pow(g - c.g, 2) +
|
|
std::pow(b - c.b, 2);
|
|
|
|
for(const auto& paletteColor : m_paletteByID){
|
|
c = GetColor(paletteColor.second);
|
|
double dist = std::pow(r - c.r, 2) +
|
|
std::pow(g - c.g, 2) +
|
|
std::pow(b - c.b, 2);
|
|
if(dist < minDist){
|
|
minDist = dist;
|
|
idx = paletteColor.first;
|
|
}
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
|
|
int Graphics::mouseX() {
|
|
float x = GetMouseX();
|
|
float adjX = x + m_origin.x;
|
|
return (int)(adjX / m_virtualScreenWindowBounds.width * m_screenWidth);
|
|
}
|
|
|
|
int Graphics::mouseY() {
|
|
float y = GetMouseY();
|
|
float adjY = y + m_origin.y;
|
|
return (int)(adjY / m_virtualScreenWindowBounds.height * m_screenHeight);
|
|
}
|
|
|
|
void Graphics::toggleFullScreen() {
|
|
if (IsWindowFullscreen()) {
|
|
ToggleFullscreen();
|
|
SetWindowSize(m_startupScreenWidth, m_startupScreenHeight);
|
|
m_windowWidth = m_startupScreenWidth;
|
|
m_windowHeight = m_startupScreenHeight;
|
|
} else {
|
|
int monitor = GetCurrentMonitor();
|
|
m_windowWidth = GetMonitorWidth(monitor);
|
|
m_windowHeight = GetMonitorHeight(monitor);
|
|
SetWindowSize(m_windowWidth, m_windowHeight);
|
|
ToggleFullscreen();
|
|
|
|
}
|
|
calculateScreenPositionInWindow();
|
|
}
|
|
|
|
void Graphics::bindMethods(pkpy::VM *vm) {
|
|
vm->bind(vm->builtins, "clear(color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
|
|
int index = pkpy::py_cast<int>(vm, args[0]);
|
|
Clear(index);
|
|
return vm->None;
|
|
});
|
|
|
|
vm->bind(vm->builtins, "pixel(x: int, y: int, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
|
|
float x = pkpy::py_cast<float>(vm, args[0]);
|
|
float y = pkpy::py_cast<float>(vm, args[1]);
|
|
float paletteIndex = pkpy::py_cast<float>(vm, args[2]);
|
|
this->Pixel(x, y, paletteIndex);
|
|
return vm->None;
|
|
});
|
|
|
|
vm->bind(vm->builtins, "get_pixel(x: int, y: int) -> int", [this](pkpy::VM* vm, pkpy::ArgsView args){
|
|
float x = pkpy::py_cast<float>(vm, args[0]);
|
|
float y = pkpy::py_cast<float>(vm, args[1]);
|
|
|
|
return pkpy::py_var(vm, this->GetPixel(x, y));
|
|
});
|
|
|
|
vm->bind(vm->builtins, "circle(x: int, y: int, radius: float, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
|
|
float x = pkpy::py_cast<float>(vm, args[0]);
|
|
float y = pkpy::py_cast<float>(vm, args[1]);
|
|
float radius = pkpy::py_cast<float>(vm, args[2]);
|
|
float paletteIndex = pkpy::py_cast<float>(vm, args[3]);
|
|
this->Circle(x, y, radius, paletteIndex);
|
|
return vm->None;
|
|
});
|
|
|
|
vm->bind(vm->builtins, "rectangle(x: int, y: int, width: int, height: int, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
|
|
float x = pkpy::py_cast<float>(vm, args[0]);
|
|
float y = pkpy::py_cast<float>(vm, args[1]);
|
|
float width = pkpy::py_cast<float>(vm, args[2]);
|
|
float height = pkpy::py_cast<float>(vm, args[3]);
|
|
float paletteIndex = pkpy::py_cast<float>(vm, args[4]);
|
|
this->Rect(x, y, width, height, paletteIndex);
|
|
return vm->None;
|
|
});
|
|
|
|
vm->bind(vm->builtins, "triangle(x1: int, y1: int, x2: int, y2: int, x3: int, y3: int, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
|
|
float x1 = pkpy::py_cast<float>(vm, args[0]);
|
|
float y1 = pkpy::py_cast<float>(vm, args[1]);
|
|
float x2 = pkpy::py_cast<float>(vm, args[2]);
|
|
float y2 = pkpy::py_cast<float>(vm, args[3]);
|
|
float x3 = pkpy::py_cast<float>(vm, args[4]);
|
|
float y3 = pkpy::py_cast<float>(vm, args[5]);
|
|
float paletteIndex = pkpy::py_cast<float>(vm, args[6]);
|
|
this->Triangle(x1, y1, x2, y2, x3, y3, paletteIndex);
|
|
return vm->None;
|
|
});
|
|
|
|
vm->bind(vm->builtins, "text(t: string, x: int, y: int, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
|
|
pkpy::PyObject* func_str = vm->builtins->attr("str");
|
|
pkpy::PyObject* result = vm->call(func_str, args[0]);
|
|
std::string s = pkpy::py_cast<pkpy::Str&>(vm, result).str();
|
|
|
|
float x = pkpy::py_cast<float>(vm, args[1]);
|
|
float y = pkpy::py_cast<float>(vm, args[2]);
|
|
float paletteIndex = pkpy::py_cast<float>(vm, args[3]);
|
|
this->Text(s, x, y, paletteIndex);
|
|
return vm->None;
|
|
});
|
|
}
|
|
|
|
void Graphics::Clear(int paletteIndex) {
|
|
for (int y = 0; y < m_screenHeight; ++y) {
|
|
for (int x = 0; x < m_screenWidth; ++x) {
|
|
Pixel(x, y, paletteIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Graphics::Pixel(int x, int y, int paletteIndex) {
|
|
paletteIndex = Clamp(paletteIndex, 0, m_paletteByID.size() - 1);
|
|
if(x < 0 || y < 0 || x >= m_screenWidth || y >= m_screenHeight) return;
|
|
|
|
m_virtualScreenColorBuffer[y * m_screenWidth + x] = paletteIndex;
|
|
}
|
|
|
|
void Graphics::Circle(int x, int y, int radius, int paletteIndex) {
|
|
Ellipse(x, y, radius, radius, paletteIndex);
|
|
}
|
|
|
|
void Graphics::Ellipse(int x, int y, int w, int h, int paletteIndex){
|
|
|
|
int x0 = x - w;
|
|
int y0 = y - h;
|
|
int x1 = x + w;
|
|
int y1 = y + h;
|
|
|
|
if(x0 > x1 || y0 > y1)
|
|
return;
|
|
|
|
int a = abs(x1 - x0), b = abs(y1 - y0), b1 = b & 1;
|
|
int dx = 4 * (1 - a) * b * b, dy = 4 * (b1 + 1) * a * a;
|
|
int err = dx + dy + b1 * a * a, e2;
|
|
|
|
if (x0 > x1) { x0 = x1; x1 += a; }
|
|
if (y0 > y1) y0 = y1;
|
|
y0 += (b + 1) / 2; y1 = y0 - b1;
|
|
a *= 8 * a; b1 = 8 * b * b;
|
|
|
|
int prevY = y0;
|
|
do
|
|
{
|
|
Pixel( x1, y0, paletteIndex);
|
|
Pixel( x0, y0, paletteIndex);
|
|
Pixel( x0, y1, paletteIndex);
|
|
Pixel( x1, y1, paletteIndex);
|
|
if(y0 != prevY && (y0 - y) != h){
|
|
h_line(x1, y0, x - (x1 - x) + 1, paletteIndex);
|
|
h_line(x1, y - (y0 - y), x - (x1 - x) + 1, paletteIndex);
|
|
}
|
|
prevY = y0;
|
|
e2 = 2 * err;
|
|
if (e2 <= dy) { y0++; y1--; err += dy += a; } /* y step */
|
|
if (e2 >= dx || 2 * err > dy) { x0++; x1--; err += dx += b1; } /* x step */
|
|
} while (x0 <= x1);
|
|
|
|
while (y0-y1 < b)
|
|
{ /* too early stop of flat ellipses a=1 */
|
|
Pixel( x0 - 1, y0, paletteIndex); /* -> finish tip of ellipse */
|
|
Pixel( x1 + 1, y0++, paletteIndex);
|
|
Pixel( x0 - 1, y1, paletteIndex);
|
|
Pixel( x1 + 1, y1--, paletteIndex);
|
|
}
|
|
|
|
|
|
h_line(x - w, y, x + w, paletteIndex);
|
|
}
|
|
|
|
void Graphics::EllipseBorder(int x, int y, int w, int h, int paletteIndex){
|
|
|
|
int x0 = x - w;
|
|
int y0 = y - h;
|
|
int x1 = x + w;
|
|
int y1 = y + h;
|
|
|
|
if(x0 > x1 || y0 > y1)
|
|
return;
|
|
|
|
int a = abs(x1 - x0), b = abs(y1 - y0), b1 = b & 1;
|
|
int dx = 4 * (1 - a) * b * b, dy = 4 * (b1 + 1) * a * a;
|
|
int err = dx + dy + b1 * a * a, e2;
|
|
|
|
if (x0 > x1) { x0 = x1; x1 += a; }
|
|
if (y0 > y1) y0 = y1;
|
|
y0 += (b + 1) / 2; y1 = y0 - b1;
|
|
a *= 8 * a; b1 = 8 * b * b;
|
|
|
|
do
|
|
{
|
|
Pixel( x1, y0, paletteIndex);
|
|
Pixel( x0, y0, paletteIndex);
|
|
Pixel( x0, y1, paletteIndex);
|
|
Pixel( x1, y1, paletteIndex);
|
|
|
|
e2 = 2 * err;
|
|
if (e2 <= dy) { y0++; y1--; err += dy += a; } /* y step */
|
|
if (e2 >= dx || 2 * err > dy) { x0++; x1--; err += dx += b1; } /* x step */
|
|
} while (x0 <= x1);
|
|
|
|
while (y0-y1 < b)
|
|
{ /* too early stop of flat ellipses a=1 */
|
|
Pixel( x0 - 1, y0, paletteIndex); /* -> finish tip of ellipse */
|
|
Pixel( x1 + 1, y0++, paletteIndex);
|
|
Pixel( x0 - 1, y1, paletteIndex);
|
|
Pixel( x1 + 1, y1--, paletteIndex);
|
|
}
|
|
|
|
}
|
|
|
|
void Graphics::Rect(int x, int y, int width, int height, int paletteIndex) {
|
|
for (int i = 0; i < height; ++i) {
|
|
h_line(x, y + i, x + width - 1, paletteIndex);
|
|
}
|
|
}
|
|
|
|
void Graphics::RectBorder(int x, int y, int width, int height, int paletteIndex) {
|
|
h_line(x, y, x + width - 1, paletteIndex);
|
|
h_line(x, y + height - 1, x + width - 1, paletteIndex);
|
|
v_line(x, y + 1, y + height - 2, paletteIndex);
|
|
v_line(x + width - 1, y + 1, y + height - 2, paletteIndex);
|
|
}
|
|
|
|
void Graphics::Text(const std::string& s, int x, int y, int paletteIndex) {
|
|
|
|
for (int i = 0; i < s.size(); ++i) {
|
|
char c = s[i];
|
|
std::string bitData = m_currentFont->GetCharData((int)c);
|
|
|
|
//std::cout << c << ": " << (int)c << " = " << bitData << std::endl;
|
|
for (int j = 0; j < bitData.size(); ++j) {
|
|
if(bitData[j] == '1')
|
|
Pixel(x + (j % m_currentFont->GetWidth()) + ((m_currentFont->GetWidth() + 1) * i), y + (j / m_currentFont->GetWidth()), paletteIndex);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void Graphics::updateVMVars(pkpy::VM* vm) {
|
|
vm->builtins->attr().set("mouseX", pkpy::py_var(vm, mouseX()));
|
|
vm->builtins->attr().set("mouseY", pkpy::py_var(vm, mouseY()));
|
|
vm->builtins->attr().set("width", pkpy::py_var(vm, m_screenWidth));
|
|
vm->builtins->attr().set("height", pkpy::py_var(vm, m_screenHeight));
|
|
}
|
|
|
|
void Graphics::h_line(int x1, int y, int x2, int paletteIndex) {
|
|
if(y < 0 || y >= m_screenHeight) return;
|
|
int startX = x1;
|
|
int endX = x2;
|
|
if(x1 > x2){
|
|
startX = x2;
|
|
endX = x1;
|
|
}
|
|
for (int i = startX; i <= endX; ++i) {
|
|
Pixel(i, y, paletteIndex);
|
|
}
|
|
}
|
|
|
|
void Graphics::v_line(int x, int y1, int y2, int paletteIndex) {
|
|
if(x < 0 || x >= m_screenWidth) return;
|
|
int startY = y1;
|
|
int endY = y2;
|
|
if(y1 > y2){
|
|
startY = y2;
|
|
endY = y1;
|
|
}
|
|
for (int i = startY; i <= endY; ++i) {
|
|
Pixel(x, i, paletteIndex);
|
|
}
|
|
}
|
|
|
|
int Graphics::GetPixel(int x, int y) {
|
|
if(x < 0 || y < 0 || x >= m_screenWidth || y >= m_screenHeight) return 0;
|
|
|
|
return m_virtualScreenColorBuffer[y * m_screenWidth + x];
|
|
}
|
|
|
|
// https://github.com/OneLoneCoder/olcPixelGameEngine/blob/master/olcPixelGameEngine.h#L2456
|
|
void Graphics::Triangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, int paletteIndex)
|
|
{
|
|
auto drawline = [&](int sx, int ex, int ny) { for (int i = sx; i <= ex; i++) Pixel(i, ny, paletteIndex); };
|
|
|
|
int t1x, t2x, y, minx, maxx, t1xp, t2xp;
|
|
bool changed1 = false;
|
|
bool changed2 = false;
|
|
int signx1, signx2, dx1, dy1, dx2, dy2;
|
|
int e1, e2;
|
|
// Sort vertices
|
|
if (y1 > y2) { std::swap(y1, y2); std::swap(x1, x2); }
|
|
if (y1 > y3) { std::swap(y1, y3); std::swap(x1, x3); }
|
|
if (y2 > y3) { std::swap(y2, y3); std::swap(x2, x3); }
|
|
|
|
t1x = t2x = x1; y = y1; // Starting points
|
|
dx1 = (int)(x2 - x1);
|
|
if (dx1 < 0) { dx1 = -dx1; signx1 = -1; }
|
|
else signx1 = 1;
|
|
dy1 = (int)(y2 - y1);
|
|
|
|
dx2 = (int)(x3 - x1);
|
|
if (dx2 < 0) { dx2 = -dx2; signx2 = -1; }
|
|
else signx2 = 1;
|
|
dy2 = (int)(y3 - y1);
|
|
|
|
if (dy1 > dx1) { std::swap(dx1, dy1); changed1 = true; }
|
|
if (dy2 > dx2) { std::swap(dy2, dx2); changed2 = true; }
|
|
|
|
e2 = (int)(dx2 >> 1);
|
|
// Flat top, just process the second half
|
|
if (y1 == y2) goto next;
|
|
e1 = (int)(dx1 >> 1);
|
|
|
|
for (int i = 0; i < dx1;) {
|
|
t1xp = 0; t2xp = 0;
|
|
if (t1x < t2x) { minx = t1x; maxx = t2x; }
|
|
else { minx = t2x; maxx = t1x; }
|
|
// process first line until y value is about to change
|
|
while (i < dx1) {
|
|
i++;
|
|
e1 += dy1;
|
|
while (e1 >= dx1) {
|
|
e1 -= dx1;
|
|
if (changed1) t1xp = signx1;//t1x += signx1;
|
|
else goto next1;
|
|
}
|
|
if (changed1) break;
|
|
else t1x += signx1;
|
|
}
|
|
// Move line
|
|
next1:
|
|
// process second line until y value is about to change
|
|
while (1) {
|
|
e2 += dy2;
|
|
while (e2 >= dx2) {
|
|
e2 -= dx2;
|
|
if (changed2) t2xp = signx2;//t2x += signx2;
|
|
else goto next2;
|
|
}
|
|
if (changed2) break;
|
|
else t2x += signx2;
|
|
}
|
|
next2:
|
|
if (minx > t1x) minx = t1x;
|
|
if (minx > t2x) minx = t2x;
|
|
if (maxx < t1x) maxx = t1x;
|
|
if (maxx < t2x) maxx = t2x;
|
|
drawline(minx, maxx, y); // Draw line from min to max points found on the y
|
|
// Now increase y
|
|
if (!changed1) t1x += signx1;
|
|
t1x += t1xp;
|
|
if (!changed2) t2x += signx2;
|
|
t2x += t2xp;
|
|
y += 1;
|
|
if (y == y2) break;
|
|
}
|
|
next:
|
|
// Second half
|
|
dx1 = (int)(x3 - x2); if (dx1 < 0) { dx1 = -dx1; signx1 = -1; }
|
|
else signx1 = 1;
|
|
dy1 = (int)(y3 - y2);
|
|
t1x = x2;
|
|
|
|
if (dy1 > dx1) { // swap values
|
|
std::swap(dy1, dx1);
|
|
changed1 = true;
|
|
}
|
|
else changed1 = false;
|
|
|
|
e1 = (int)(dx1 >> 1);
|
|
|
|
for (int i = 0; i <= dx1; i++) {
|
|
t1xp = 0; t2xp = 0;
|
|
if (t1x < t2x) { minx = t1x; maxx = t2x; }
|
|
else { minx = t2x; maxx = t1x; }
|
|
// process first line until y value is about to change
|
|
while (i < dx1) {
|
|
e1 += dy1;
|
|
while (e1 >= dx1) {
|
|
e1 -= dx1;
|
|
if (changed1) { t1xp = signx1; break; }//t1x += signx1;
|
|
else goto next3;
|
|
}
|
|
if (changed1) break;
|
|
else t1x += signx1;
|
|
if (i < dx1) i++;
|
|
}
|
|
next3:
|
|
// process second line until y value is about to change
|
|
while (t2x != x3) {
|
|
e2 += dy2;
|
|
while (e2 >= dx2) {
|
|
e2 -= dx2;
|
|
if (changed2) t2xp = signx2;
|
|
else goto next4;
|
|
}
|
|
if (changed2) break;
|
|
else t2x += signx2;
|
|
}
|
|
next4:
|
|
|
|
if (minx > t1x) minx = t1x;
|
|
if (minx > t2x) minx = t2x;
|
|
if (maxx < t1x) maxx = t1x;
|
|
if (maxx < t2x) maxx = t2x;
|
|
drawline(minx, maxx, y);
|
|
if (!changed1) t1x += signx1;
|
|
t1x += t1xp;
|
|
if (!changed2) t2x += signx2;
|
|
t2x += t2xp;
|
|
y += 1;
|
|
if (y > y3) return;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
PycronImage* Graphics::loadImage(std::string path) {
|
|
Image img = LoadImage(path.c_str());
|
|
ImageRotateCW(&img);
|
|
ImageFlipHorizontal(&img);
|
|
if(img.width == 0 && img.height == 0) std::cerr << "Image at path " << path << " is empty\n";
|
|
Color* colors = LoadImageColors(img);
|
|
auto* idImg = new PycronImage(img.width, img.height);
|
|
for (int i = 0; i < idImg->data.size(); ++i) {
|
|
if(colors[i].a == 0){
|
|
idImg->data[i] = -1;
|
|
}else{
|
|
idImg->data[i] = (int8_t)rgbToID(colors[i].r, colors[i].g, colors[i].b);
|
|
}
|
|
}
|
|
return idImg;
|
|
}
|
|
|
|
void Graphics::Img(PycronImage* img, int x, int y) {
|
|
for (int i = 0; i < img->data.size(); ++i) {
|
|
if(img->data[i] == -1) continue;
|
|
Pixel(x + i / img->width, y + i % img->width, img->data[i]);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|