Serious-Engine/Sources/Engine/Rendering/SelectOnRender.cpp
Ryan C. Gordon 24cb244d43 First attempt to hand-merge Ryan's Linux and Mac OS X port.
This was a _ton_ of changes, made 15 years ago, so there are probably some
problems to work out still.

Among others: Engine/Base/Stream.* was mostly abandoned and will need to be
re-ported.

Still, this is a pretty good start, and probably holds a world record for
lines of changes or something.  :)
2016-03-28 23:46:13 -04:00

284 lines
7.7 KiB
C++

/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */
#include "Engine/StdH.h"
#include <Engine/Brushes/Brush.h>
#include <Engine/Brushes/BrushTransformed.h>
#include <Engine/Rendering/Render.h>
#include <Engine/Rendering/Render_internal.h>
#include <Engine/Templates/Selection.cpp>
#include <Engine/Models/ModelObject.h>
static PIX _pixSizeI;
static PIX _pixSizeJ;
UBYTE *_pubLassoBuffer = NULL;
// init select-on-render functionality
void InitSelectOnRender(PIX pixSizeI, PIX pixSizeJ)
{
_pixSizeI = pixSizeI;
_pixSizeJ = pixSizeJ;
// if entity selecting not required
if (_pselenSelectOnRender==NULL)
{
// if vertex selecting not requred
if (_pselbvxtSelectOnRender==NULL) {
// do nothing
return;
}
// if not lasso and not alternative
else if (_pavpixSelectLasso==NULL && !_bSelectAlternative) {
// deselect all vertices
_pselbvxtSelectOnRender->Clear();
}
}
// if lasso selection is not on, or is invalid
if (_pavpixSelectLasso==NULL || _pavpixSelectLasso->Count()<3
|| pixSizeI<2 || pixSizeJ<2) {
// do nothing
return;
}
SLONG slMaxOffset = pixSizeI*pixSizeJ-1;
// allocate lasso buffer
_pubLassoBuffer = (UBYTE*)AllocMemory(_pixSizeI*_pixSizeJ);
// clear it
memset(_pubLassoBuffer, 0, _pixSizeI*_pixSizeJ);
// for each line in lasso
INDEX ctpt = _pavpixSelectLasso->Count();
for (INDEX ipt=0; ipt<ctpt; ipt++) {
// get its points
INDEX ipt0 = ipt;
INDEX ipt1 = (ipt+1)%ctpt;
// get their coordinates
PIX pixI0 = (*_pavpixSelectLasso)[ipt0](1);
PIX pixJ0 = (*_pavpixSelectLasso)[ipt0](2);
PIX pixI1 = (*_pavpixSelectLasso)[ipt1](1);
PIX pixJ1 = (*_pavpixSelectLasso)[ipt1](2);
// if any of the coordinates is outside of window
if (pixI0<0 || pixI0>=_pixSizeI || pixI1<0 || pixI1>=_pixSizeI ||
pixJ0<0 || pixJ0>=_pixSizeJ || pixJ1<0 || pixJ1>=_pixSizeJ) {
// skip this line
continue;
}
// if line is horizontal
if (pixJ0==pixJ1) {
// skip it
continue;
// if line goes upwards
} else if (pixJ0>pixJ1) {
// make it go downwards
Swap(pixI0, pixI1);
Swap(pixJ0, pixJ1);
}
// calculate step
FIX16_16 xStep = FIX16_16(FLOAT(pixI1-pixI0)/(pixJ1-pixJ0));
// start in first row
FIX16_16 xI = FIX16_16(pixI0);
// for each row
for(PIX pixJ = pixJ0; pixJ<pixJ1; pixJ++) {
// get offset
SLONG slOffset = pixJ*_pixSizeI+PIX(xI);
// if offset is valid
if (slOffset>=0 && slOffset<=slMaxOffset) {
// invert the pixel in that row
_pubLassoBuffer[slOffset] ^= 0xFF;
}
// step the line
xI+=xStep;
}
}
// for each row in lasso buffer
for(PIX pixJ = 0; pixJ<_pixSizeJ; pixJ++) {
// for each pixel in the row, except the last one
UBYTE *pub = _pubLassoBuffer+pixJ*_pixSizeI;
for(PIX pixI = 0; pixI<_pixSizeI-1; pixI++) {
// xor it to the next one
pub[1]^=pub[0];
pub++;
}
}
}
// end select-on-render functionality
void EndSelectOnRender(void)
{
// free lasso buffer
if (_pubLassoBuffer!=NULL) {
FreeMemory(_pubLassoBuffer);
_pubLassoBuffer = NULL;
}
}
// check if a vertex is influenced by current select-on-render selection
void SelectVertexOnRender(CBrushVertex &bvx, const PIX2D &vpix)
{
// if not selecting
if (_pselbvxtSelectOnRender==NULL) {
// do nothing
return;
}
// if the vertex is out of screen
if (vpix(1)<0 || vpix(1)>=_pixSizeI
|| vpix(2)<0 || vpix(2)>=_pixSizeJ) {
// do nothing
return;
}
// if selecting without lasso
if (_pubLassoBuffer==NULL) {
// if vertex is near point
if ((vpix-_vpixSelectNearPoint).Length()<_pixDeltaAroundVertex) {
// if selected
if (bvx.IsSelected(BVXF_SELECTED)) {
// deselect it
_pselbvxtSelectOnRender->Deselect(bvx);
// if not selected
} else {
// select it
_pselbvxtSelectOnRender->Select(bvx);
}
}
// if selecting with lasso
} else {
// if the vertex is set in lasso buffer
if (_pubLassoBuffer!=NULL
&&_pubLassoBuffer[vpix(2)*_pixSizeI+vpix(1)]) {
// if alternative
if (_bSelectAlternative) {
// deselect
if (bvx.IsSelected(BVXF_SELECTED)) {
_pselbvxtSelectOnRender->Deselect(bvx);
}
// if normal
} else {
// select
if (!bvx.IsSelected(BVXF_SELECTED)) {
_pselbvxtSelectOnRender->Select(bvx);
}
}
}
}
}
// check if given vertice is selected by lasso
BOOL IsVertexInLasso( CProjection3D &prProjection, const FLOAT3D &vtx, FLOATmatrix3D *pmR, FLOAT3D &vOffset)
{
// convert from relative to absolute space
FLOAT3D vAbsolute = vOffset+vtx*(*pmR);
FLOAT3D vtxProjected;
prProjection.ProjectCoordinate( vAbsolute, vtxProjected);
PIX2D vpix;
vpix(1) = (PIX) vtxProjected(1);
// convert coordinate into screen representation
vpix(2) = (PIX) (_pixSizeJ-vtxProjected(2));
// if the vertex is out of screen
if (vpix(1)<0 || vpix(1)>=_pixSizeI
|| vpix(2)<0 || vpix(2)>=_pixSizeJ) {
// no selecting
return FALSE;
}
// if the vertex is set in lasso buffer
if (_pubLassoBuffer!=NULL
&&_pubLassoBuffer[vpix(2)*_pixSizeI+vpix(1)])
{
return TRUE;
}
return FALSE;
}
// check if given bounding box is selected by lasso
BOOL IsBoundingBoxInLasso( CProjection3D &prProjection, const FLOATaabbox3D &box, FLOATmatrix3D *pmR, FLOAT3D &vOffset)
{
FLOAT3D vMin = box.Min();
FLOAT3D vMax = box.Max();
// test lasso influence for all of bounding box's vertices
if(
IsVertexInLasso( prProjection, FLOAT3D( vMin(1), vMin(2), vMin(3)), pmR, vOffset) &&
IsVertexInLasso( prProjection, FLOAT3D( vMax(1), vMin(2), vMin(3)), pmR, vOffset) &&
IsVertexInLasso( prProjection, FLOAT3D( vMin(1), vMax(2), vMin(3)), pmR, vOffset) &&
IsVertexInLasso( prProjection, FLOAT3D( vMax(1), vMax(2), vMin(3)), pmR, vOffset) &&
IsVertexInLasso( prProjection, FLOAT3D( vMin(1), vMin(2), vMax(3)), pmR, vOffset) &&
IsVertexInLasso( prProjection, FLOAT3D( vMax(1), vMin(2), vMax(3)), pmR, vOffset) &&
IsVertexInLasso( prProjection, FLOAT3D( vMin(1), vMax(2), vMax(3)), pmR, vOffset) &&
IsVertexInLasso( prProjection, FLOAT3D( vMax(1), vMax(2), vMax(3)), pmR, vOffset) )
{
return TRUE;
}
return FALSE;
}
// check if all of the corners of entity's bounding box are influenced by current select-on-render selection
void SelectEntityOnRender(CProjection3D &prProjection, CEntity &en)
{
FLOATaabbox3D bbox;
FLOATmatrix3D mOne = FLOATmatrix3D(0.0f);
mOne.Diagonal(1.0f);
FLOATmatrix3D *pmR;
FLOAT3D vOffset;
// if this entity is model
if (en.en_RenderType==CEntity::RT_MODEL || en.en_RenderType==CEntity::RT_EDITORMODEL)
{
// get bbox of current frame
CModelObject *pmo = en.GetModelObject();
pmo->GetCurrentFrameBBox( bbox);
pmR = &en.en_mRotation;
vOffset = en.GetPlacement().pl_PositionVector;
}
// if it is ska model
else if(en.en_RenderType==CEntity::RT_SKAMODEL || en.en_RenderType==CEntity::RT_SKAEDITORMODEL)
{
en.GetModelInstance()->GetCurrentColisionBox( bbox);
pmR = &en.en_mRotation;
vOffset = en.GetPlacement().pl_PositionVector;
}
// if it is brush
else
{
// get bbox of brush's first mip
CBrush3D *pbr = en.GetBrush();
CBrushMip *pbrmip = pbr->GetFirstMip();
bbox = pbrmip->bm_boxBoundingBox;
pmR = &mOne;
vOffset = FLOAT3D( 0.0f, 0.0f, 0.0f);
}
if( IsBoundingBoxInLasso( prProjection, bbox, pmR, vOffset))
{
if( _bSelectAlternative)
{
// deselect
if (en.IsSelected(ENF_SELECTED))
{
_pselenSelectOnRender->Deselect(en);
}
}
else
{
// select
if (!en.IsSelected(ENF_SELECTED))
{
_pselenSelectOnRender->Select(en);
}
}
}
}