Descent3/2dlib/viewport.cpp

408 lines
11 KiB
C++
Raw Permalink Normal View History

/*
* Descent 3
* Copyright (C) 2024 Parallax Software
*
* 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 <http://www.gnu.org/licenses/>.
--- HISTORICAL COMMENTS FOLLOW ---
2024-04-16 03:43:29 +00:00
* $Logfile: /DescentIII/Main/2dlib/viewport.cpp $
* $Revision: 7 $
* $Date: 12/19/97 5:23p $
* $Author: Samir $
*
* this class manages a specific viewing region of either a screen or bitmap.
* functions such as font setting and bitmap bltting are supported
* under this class.
*
* this class also spawns a pen object which effectively locks the screen or
* bitmap associated with it.
*
* $Log: /DescentIII/Main/2dlib/viewport.cpp $
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 7 12/19/97 5:23p Samir
* Cleaned up a lot of code to call renderer code.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 6 12/19/97 12:32p Samir
* Support alpha for text. Stubbed out clipping support.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 5 11/18/97 12:32p Samir
* Took out useless lines.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 4 11/14/97 12:05p Samir
* don't free font, just init it.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 20 6/13/97 1:17p Samir
* Fucked up last checkin
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 19 6/13/97 1:00p Samir
* lock when called will always lock, so if the lock fails, then it's not
* viewport's job to fix it.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 18 6/12/97 6:29p Samir
* DDGR v2.0 Changes in 2d system implemented.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 17 6/06/97 12:18p Samir
* OpenGL HACKS to call renderer for some drawing functions. Must fix.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 16 5/15/97 3:47p Samir
* Fixed lock_clear.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 15 5/13/97 6:36p Samir
* added lock_clear functions.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 14 4/01/97 4:37p Samir
* Simply better circle functions using viewport line and pixel functions.
* made an hline function that clips and a setpixel function that clips.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 13 3/28/97 3:07p Samir
* Clear function now takes a color
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 12 3/28/97 2:50p Samir
* Fixed clip_rect fuckup.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 11 2/18/97 1:04p Samir
* Changed prototype for setpixel
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 10 2/18/97 11:38a Samir
* Added getpixel and setpixel to grViewport. NOTE: you must lock the
* viewport when doing these ops.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 9 2/04/97 4:56p Samir
* added 'hack' in viewport lock. see the function to see what I mean.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 8 2/04/97 12:50p Samir
* Viewports now lock on CLIP_LEFT, CLIP_TOP
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 7 2/04/97 11:14a Samir
* Improved clipping system by adding a separate clipport based off of the
2024-09-03 11:03:41 +00:00
* viewport's rectangle in its parent surface
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 6 2/03/97 7:56p Samir
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 5 1/31/97 11:02a Samir
* Adjusted clear function to use x,y,width,height parms.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 4 1/30/97 6:28p Samir
* Stupid me, left some dummy text causing errors.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 3 1/30/97 6:01p Samir
* The partition of memory and os surfaces as well as the change in
* ddgr_surface structure and all related changes.
*
* $NoKeywords: $
*/
2024-05-21 10:39:51 +00:00
#include <algorithm>
2024-04-16 03:43:29 +00:00
#include "gr.h"
#include "lib2d.h"
#include "renderer.h"
#include "pserror.h"
2024-04-16 18:56:40 +00:00
#define CLIP_LEFT (vp_InitLeft + vp_Left)
#define CLIP_TOP (vp_InitTop + vp_Top)
#define CLIP_RIGHT (vp_InitLeft + vp_Right)
#define CLIP_BOTTOM (vp_InitTop + vp_Bottom)
2024-04-16 03:43:29 +00:00
int grViewport::vp_Locked = 0;
grViewport *grViewport::vp_Current_VP = nullptr;
2024-04-16 03:43:29 +00:00
// ---------------------------------------------------------------------------
// grViewport constructor and destructor
// ---------------------------------------------------------------------------
2024-04-16 18:56:40 +00:00
grViewport::grViewport(grScreen *scr_parent) {
ASSERT(scr_parent != nullptr);
2024-04-16 18:56:40 +00:00
sf_Parent = scr_parent; // screen is a child of grSurface, so we
// can do this.
vp_InitLeft = vp_Left = 0; // define bounds = entire screen
vp_InitTop = vp_Top = 0;
vp_InitRight = vp_Right = sf_Parent->width() - 1;
vp_InitBottom = vp_Bottom = sf_Parent->height() - 1;
// initialize font object
// setup text settings.
char_Props.col[0] = GR_WHITE;
char_Props.col[1] = GR_WHITE;
char_Props.col[2] = GR_WHITE;
char_Props.col[3] = GR_WHITE;
char_Props.alpha = 255;
text_Spacing = 1;
text_Line_spacing = 1;
text_Font.init(DEFAULT_FONT);
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
grViewport::grViewport(grSurface *sf_parent) {
ASSERT(sf_parent != nullptr);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
sf_Parent = sf_parent;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
vp_InitLeft = vp_Left = 0; // define bounds = entire bitmap
vp_InitTop = vp_Top = 0;
vp_InitRight = vp_Right = sf_Parent->width() - 1;
vp_InitBottom = vp_Bottom = sf_Parent->height() - 1;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// initialize font object
// setup text settings.
char_Props.col[0] = GR_WHITE;
char_Props.col[1] = GR_WHITE;
char_Props.col[2] = GR_WHITE;
char_Props.col[3] = GR_WHITE;
char_Props.alpha = 255;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
text_Spacing = 1;
text_Line_spacing = 1;
text_Font.init(DEFAULT_FONT);
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
grViewport::~grViewport() {
ASSERT(!vp_Locked); // Viewport shouldn't be locked here!
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// text_Font.free();
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void grViewport::set_clipping_rect(int left, int top, int right, int bottom) {
ASSERT(!vp_Locked); // YOU CANT DO THIS WHILE LOCKED!
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// these are local to the viewport.
// vp_Left = left;
// vp_Top = top;
// vp_Right = right;
// vp_Bottom = bottom;
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
// these functions set and restore the state of the viewport (font, colors, etc.)
void grViewport::get_state(tVPState *state) {
state->font = text_Font;
state->text_spacing = text_Spacing;
state->text_line_spacing = text_Line_spacing;
get_char_properties(&state->chprops);
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void grViewport::set_state(const tVPState *state) {
set_char_properties(GR_VPCP_ALL, &state->chprops);
text_Font = state->font;
text_Spacing = state->text_spacing;
text_Line_spacing = state->text_line_spacing;
}
2024-04-16 03:43:29 +00:00
// ---------------------------------------------------------------------------
// font functions
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// bltting functions
// ---------------------------------------------------------------------------
2024-04-16 18:56:40 +00:00
void grViewport::clear(ddgr_color col) // clear with background color
2024-04-16 03:43:29 +00:00
{
2024-04-16 18:56:40 +00:00
sf_Parent->clear(CLIP_LEFT, CLIP_TOP, (vp_Right - vp_Left) + 1, (vp_Bottom - vp_Top) + 1, col);
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void grViewport::blt(int dx, int dy, grSurface *ssf) {
int x1, y1, x2, y2, sx, sy;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// perform rectangular clipping
x1 = global_x(dx);
y1 = global_y(dy);
x2 = x1 + ssf->width() - 1;
y2 = y1 + ssf->height() - 1;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
if (x1 < CLIP_LEFT)
sx = CLIP_LEFT - x1;
else
sx = 0;
if (y1 < CLIP_TOP)
sy = CLIP_TOP - y1;
else
sy = 0;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
if (clip_rect(x1, y1, x2, y2) == 2)
return;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
sf_Parent->blt(x1, y1, ssf, sx, sy, x2 - x1 + 1, y2 - y1 + 1);
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void grViewport::blt(int dx, int dy, grSurface *ssf, int sx, int sy, int sw, int sh) {
int x1, y1, x2, y2;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
x1 = global_x(dx);
y1 = global_y(dy);
x2 = x1 + sw - 1;
y2 = y1 + sh - 1;
if (clip_rect(x1, y1, x2, y2) == 2)
return;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
sf_Parent->blt(x1, y1, ssf, sx, sy, x2 - x1 + 1, y2 - y1 + 1);
}
2024-04-16 03:43:29 +00:00
// ---------------------------------------------------------------------------
// general lock creation functions
// ---------------------------------------------------------------------------
2024-04-16 18:56:40 +00:00
grSurface *grViewport::lock() {
int rowsize;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
ASSERT(!vp_Locked);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
sf_Parent->lock(CLIP_LEFT, CLIP_TOP, &rowsize);
vp_Locked = 1;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
if (vp_Locked) {
pen_Obj.sf = &sf_Parent->ddsfObj;
pen_Obj.rowsize = sf_Parent->rowsize();
pen_Obj.rgbcolor = GR_RGB(255, 255, 255);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// SUPERHACK. Pen functions don't use the adjusted pointer of grSurface, but use the
// base data pointer provided by locking the entire surface at (0,0). Pen functions
// use global coordinates, so they can calculate the adjusted pointer themselves. This
// makes global_x and global_y consisitent with the surface base pointer. This problem
// was caused by the clipping rect being a virtual viewport within a viewport to make
// the 3d system work better.
pen_Obj.data = sf_Parent->m_OrigDataPtr;
}
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
grViewport::vp_Current_VP = this;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
return sf_Parent;
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void grViewport::unlock() {
ASSERT(vp_Locked);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
sf_Parent->unlock();
vp_Locked = 0;
2024-04-16 03:43:29 +00:00
grViewport::vp_Current_VP = nullptr;
2024-04-16 03:43:29 +00:00
pen_Obj.data = nullptr;
2024-04-16 18:56:40 +00:00
pen_Obj.rowsize = 0;
pen_Obj.sf = nullptr;
2024-04-16 03:43:29 +00:00
}
// ---------------------------------------------------------------------------
// miscellaneous viewport functions
// ---------------------------------------------------------------------------
2024-04-16 18:56:40 +00:00
void grViewport::setpixel(ddgr_color col, int x, int y) {
ASSERT(vp_Locked);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
rend_SetPixel(col, x, y);
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void grViewport::setpixelc(ddgr_color col, int x, int y) {
ASSERT(vp_Locked);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
if (x < CLIP_LEFT || x > CLIP_RIGHT || y < CLIP_TOP || y > CLIP_BOTTOM)
return;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
rend_SetPixel(col, x, y);
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
ddgr_color grViewport::getpixel(int x, int y) {
ASSERT(vp_Locked);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
return rend_GetPixel(x, y);
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
ddgr_color grViewport::getpixelc(int x, int y) {
ASSERT(vp_Locked);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
if (x < CLIP_LEFT || x > CLIP_RIGHT || y < CLIP_TOP || y > CLIP_BOTTOM)
return 0;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
return rend_GetPixel(x, y);
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void grViewport::lock_clear(ddgr_color col) {
int l = CLIP_LEFT, t = CLIP_TOP, r = CLIP_RIGHT, b = CLIP_BOTTOM;
ddgr_surface *memsurf = sf_Parent->scratch_mem_surf;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
ASSERT(vp_Locked);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
if (sf_Parent->ddsfObj.flags & SURFFLAG_RENDERER) {
rend_FillRect(col, l, t, r, b);
} else {
memsurf->bpp = pen_Obj.sf->bpp;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
gr_mem_surf_Init(memsurf, pen_Obj.data, pen_Obj.rowsize);
gr_mem_surf_Clear(memsurf, col, l, t, r - l + 1, b - t + 1);
}
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void grViewport::lock_clear(ddgr_color col, int l, int t, int r, int b) {
ddgr_surface *memsurf = sf_Parent->scratch_mem_surf;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
ASSERT(vp_Locked);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
l = global_x(l);
t = global_y(t);
r = global_x(r);
b = global_y(b);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
clip_rect(l, t, r, b);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
if (sf_Parent->ddsfObj.flags & SURFFLAG_RENDERER) {
rend_FillRect(col, l, t, r, b);
} else {
memsurf->bpp = pen_Obj.sf->bpp;
gr_mem_surf_Init(memsurf, pen_Obj.data, pen_Obj.rowsize);
gr_mem_surf_Clear(memsurf, col, l, t, r - l + 1, b - t + 1);
}
2024-04-16 03:43:29 +00:00
}
// ---------------------------------------------------------------------------
// private functions
// ---------------------------------------------------------------------------
// grPen::clip_rect
// returns 2 if totally clipped
// returns 1 if partially clipped
// returns 0 if not clipped.
2024-04-16 18:56:40 +00:00
int grViewport::clip_rect(int &l, int &t, int &r, int &b) {
int clipped = 0;
if (l > r)
2024-05-21 10:39:51 +00:00
std::swap(l, r);
2024-04-16 18:56:40 +00:00
if (t > b)
2024-05-21 10:39:51 +00:00
std::swap(t, b);
2024-04-16 18:56:40 +00:00
if (l > CLIP_RIGHT || t > CLIP_BOTTOM || r < CLIP_LEFT || b < CLIP_TOP)
return 2;
if (l < CLIP_LEFT) {
l = CLIP_LEFT;
clipped = 1;
}
if (t < CLIP_TOP) {
t = CLIP_TOP;
clipped = 1;
}
if (r > CLIP_RIGHT) {
r = CLIP_RIGHT;
clipped = 1;
}
if (b > CLIP_BOTTOM) {
b = CLIP_BOTTOM;
clipped = 1;
}
return clipped;
2024-04-16 03:43:29 +00:00
}