252 lines
5.8 KiB
C
252 lines
5.8 KiB
C
/*
|
|
* Kangaroo Punch MultiPlayer Game Server Mark II
|
|
* Copyright (C) 2020-2021 Scott Duensing
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
|
|
#include "surface.h"
|
|
#include "vesa.h"
|
|
|
|
|
|
static SurfaceT *_offScreenSurface;
|
|
static SurfaceT *_activeSurface;
|
|
|
|
|
|
static void surfacePutPixel8(uint16_t x, uint16_t y, ColorT color);
|
|
static void surfacePutPixel16(uint16_t x, uint16_t y, ColorT color);
|
|
static void surfacePutPixel32(uint16_t x, uint16_t y, ColorT color);
|
|
|
|
|
|
void (*surfacePutPixel)(uint16_t x, uint16_t y, ColorT color);
|
|
|
|
|
|
|
|
static void surfacePutPixel8(uint16_t x, uint16_t y, ColorT color) {
|
|
_activeSurface->buffer.bits8[y * _activeSurface->width + x] = (uint8_t)color;
|
|
}
|
|
|
|
|
|
static void surfacePutPixel16(uint16_t x, uint16_t y, ColorT color) {
|
|
_activeSurface->buffer.bits16[y * _activeSurface->width + x] = (uint16_t)color;
|
|
}
|
|
|
|
|
|
static void surfacePutPixel32(uint16_t x, uint16_t y, ColorT color) {
|
|
_activeSurface->buffer.bits32[y * _activeSurface->width + x] = color;
|
|
}
|
|
|
|
|
|
void surfaceBlit(SurfaceT *source, uint16_t x, uint16_t y) {
|
|
uint16_t y1;
|
|
size_t offsetTarget;
|
|
size_t offsetSource;
|
|
|
|
if (x == 0 && y == 0 && _activeSurface->width == source->width && _activeSurface->height == source->height) {
|
|
// Direct blit of entire surface.
|
|
memcpy(_activeSurface->buffer.bits8, source->buffer.bits8, source->bytes);
|
|
} else {
|
|
// Blit into larger surface.
|
|
offsetTarget = y * _activeSurface->scanline + x * vbeDisplayDepthBytesGet();
|
|
offsetSource = 0;
|
|
for (y1=y; y1<y+source->height; y1++) {
|
|
memcpy(&_activeSurface->buffer.bits8[offsetTarget], &source->buffer.bits8[offsetSource], source->scanline);
|
|
offsetTarget += _activeSurface->scanline;
|
|
offsetSource += source->scanline;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void surfaceClear(ColorT color) {
|
|
|
|
uint16_t x;
|
|
size_t offsetTarget;
|
|
|
|
// Draw the top line.
|
|
for (x=0; x<_activeSurface->width; x++) {
|
|
surfacePutPixel(x, 0, color);
|
|
}
|
|
|
|
// Copy it to the other lines.
|
|
offsetTarget = _activeSurface->scanline;
|
|
for (x=1; x<_activeSurface->height; x++) {
|
|
memcpy(&_activeSurface->buffer.bits8[offsetTarget], &_activeSurface->buffer.bits8[0], _activeSurface->scanline);
|
|
offsetTarget += _activeSurface->scanline;
|
|
}
|
|
}
|
|
|
|
|
|
SurfaceT *surfaceCreate(uint16_t width, uint16_t height) {
|
|
SurfaceT *surface = (SurfaceT *)malloc(sizeof(SurfaceT));
|
|
|
|
if (!surface) return NULL;
|
|
|
|
surface->width = width;
|
|
surface->height = height;
|
|
surface->scanline = width * vbeDisplayDepthBytesGet();
|
|
surface->bytes = surface->scanline * height;
|
|
|
|
surface->buffer.bits8 = malloc(surface->bytes);
|
|
if (!surface->buffer.bits8) {
|
|
free(surface);
|
|
return NULL;
|
|
}
|
|
|
|
memset(surface->buffer.bits8, 0, surface->bytes);
|
|
|
|
return surface;
|
|
}
|
|
|
|
|
|
void surfaceDestroy(SurfaceT **surface) {
|
|
SurfaceT *s = *surface;
|
|
|
|
free(s->buffer.bits8);
|
|
free(s);
|
|
s = NULL;
|
|
}
|
|
|
|
|
|
uint16_t surfaceHeightGet(void) {
|
|
return _activeSurface->height;
|
|
}
|
|
|
|
|
|
void surfaceHighlightFrameDraw(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, ColorT upperLeft, ColorT lowerRight) {
|
|
surfaceLineDraw(x1, y1, x2, y1, upperLeft);
|
|
surfaceLineDraw(x1, y1, x1, y2, upperLeft);
|
|
surfaceLineDraw(x1, y2, x2, y2, lowerRight);
|
|
surfaceLineDraw(x2, y1, x2, y2, lowerRight);
|
|
}
|
|
|
|
|
|
void surfaceLineDraw(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT color) {
|
|
int16_t x;
|
|
int16_t y;
|
|
int16_t dx;
|
|
int16_t dy;
|
|
int16_t incX;
|
|
int16_t incY;
|
|
int16_t balance;
|
|
|
|
if (x2 >= x1) {
|
|
dx = x2 - x1;
|
|
incX = 1;
|
|
} else {
|
|
dx = x1 - x2;
|
|
incX = -1;
|
|
}
|
|
|
|
if (y2 >= y1) {
|
|
dy = y2 - y1;
|
|
incY = 1;
|
|
} else {
|
|
dy = y1 - y2;
|
|
incY = -1;
|
|
}
|
|
|
|
x = x1;
|
|
y = y1;
|
|
|
|
if (dx >= dy) {
|
|
dy <<= 1;
|
|
balance = dy - dx;
|
|
dx <<= 1;
|
|
while (x != x2) {
|
|
surfacePutPixel(x, y, color);
|
|
if (balance >= 0) {
|
|
y += incY;
|
|
balance -= dx;
|
|
}
|
|
balance += dy;
|
|
x += incX;
|
|
}
|
|
surfacePutPixel(x, y, color);
|
|
} else {
|
|
dx <<= 1;
|
|
balance = dx - dy;
|
|
dy <<= 1;
|
|
while (y != y2) {
|
|
surfacePutPixel(x, y, color);
|
|
if (balance >= 0) {
|
|
x += incX;
|
|
balance -= dy;
|
|
}
|
|
balance += dx;
|
|
y += incY;
|
|
}
|
|
surfacePutPixel(x, y, color);
|
|
}
|
|
}
|
|
|
|
|
|
SurfaceT *surfaceOffScreenGet(void) {
|
|
return _offScreenSurface;
|
|
}
|
|
|
|
|
|
void surfaceRectangleDraw(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT color) {
|
|
surfaceLineDraw(x1, y1, x2, y1, color);
|
|
surfaceLineDraw(x2, y1, x2, y2, color);
|
|
surfaceLineDraw(x1, y2, x2, y2, color);
|
|
surfaceLineDraw(x1, y1, x1, y2, color);
|
|
}
|
|
|
|
|
|
void surfaceRectangleFilledDraw(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT color) {
|
|
uint16_t x;
|
|
uint16_t y;
|
|
|
|
// This could be optimized similar to surfaceClear
|
|
|
|
for (y=y1; y<=y2; y++) {
|
|
for (x=x1; x<=x2; x++) {
|
|
surfacePutPixel(x, y, color);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void surfaceSet(SurfaceT *surface) {
|
|
if (surface) {
|
|
_activeSurface = surface;
|
|
} else {
|
|
_activeSurface = _offScreenSurface;
|
|
}
|
|
}
|
|
|
|
|
|
void surfaceShutdown(void) {
|
|
surfaceDestroy(&_offScreenSurface);
|
|
}
|
|
|
|
|
|
uint8_t surfaceStartup(void) {
|
|
_offScreenSurface = surfaceCreate(vbeDisplayWidthGet(), vbeDisplayHeightGet());
|
|
|
|
if (vbeDisplayDepthBitsGet() == 8) surfacePutPixel = surfacePutPixel8;
|
|
if (vbeDisplayDepthBitsGet() == 16) surfacePutPixel = surfacePutPixel16;
|
|
if (vbeDisplayDepthBitsGet() == 15) surfacePutPixel = surfacePutPixel16;
|
|
if (vbeDisplayDepthBitsGet() == 32) surfacePutPixel = surfacePutPixel32;
|
|
|
|
return (_offScreenSurface == NULL ? 1 : 0);
|
|
}
|
|
|
|
|
|
uint16_t surfaceWidthGet(void) {
|
|
return _activeSurface->width;
|
|
}
|