mirror of
https://github.com/leozide/leocad
synced 2025-02-01 07:57:14 +01:00
Copied 0.75 branch as the new trunk.
This commit is contained in:
commit
1f9a1761c0
443 changed files with 94172 additions and 0 deletions
11
CREDITS.txt
Normal file
11
CREDITS.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
The following people have contributed to LeoCAD:
|
||||
|
||||
Author, Original Design:
|
||||
Leonardo Zide <leo@gerf.org>
|
||||
|
||||
Contributions:
|
||||
Christian Höltje <docwhat@gerf.org>
|
||||
Renaud Breard <renaud@islande.net>
|
||||
|
||||
Linux man page and Debian packages:
|
||||
Pat Mahoney <pat7@gmx.net>
|
152
Makefile
Normal file
152
Makefile
Normal file
|
@ -0,0 +1,152 @@
|
|||
### ALL CONFIGURATION SHOULD BE IN CONFIG.MK, NOT HERE
|
||||
include config.mk
|
||||
|
||||
### Module directories
|
||||
MODULES := $(OSDIR) common
|
||||
|
||||
### look for include files in
|
||||
### each of the modules
|
||||
CPPFLAGS += $(patsubst %,-I%,$(MODULES)) $(OS)
|
||||
CPPFLAGS += -g
|
||||
|
||||
### extra libraries if required
|
||||
LIBS :=
|
||||
|
||||
### each module will add to this
|
||||
SRC :=
|
||||
|
||||
BIN := bin/leocad
|
||||
|
||||
-include $(OSDIR)/config.mk
|
||||
|
||||
### include the description for
|
||||
### each module
|
||||
include $(patsubst %,%/module.mk,$(MODULES))
|
||||
|
||||
### determine the object files
|
||||
OBJ := \
|
||||
$(patsubst %.c,%.o,$(filter %.c,$(SRC))) \
|
||||
$(patsubst %.cpp,%.o,$(filter %.cpp,$(SRC)))
|
||||
|
||||
### link the program
|
||||
.PHONY: all static
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
static: bin/leocad.static
|
||||
|
||||
bin/leocad: $(OBJ) bin
|
||||
$(CXX) -o $@ $(OBJ) $(LIBS) $(LDFLAGS)
|
||||
|
||||
bin/leocad.static: $(OBJ) bin
|
||||
$(CXX) -static -o $@ $(OBJ) $(LIBS) $(LDFLAGS)
|
||||
|
||||
bin:
|
||||
mkdir bin
|
||||
|
||||
### include the C/C++ include
|
||||
### dependencies
|
||||
ifeq ($(findstring $(MAKECMDGOALS), help config-help config clean veryclean spotless), )
|
||||
-include $(OBJ:.o=.d)
|
||||
endif
|
||||
|
||||
### calculate C/C++ include
|
||||
### dependencies
|
||||
%.d: %.c
|
||||
@[ -s $(OSDIR)/config.h ] || $(MAKE) config
|
||||
@$(CC) -MM -MT '$(patsubst %.d,%.o, $@)' $(CFLAGS) $(CPPFLAGS) -w $< > $@
|
||||
@[ -s $@ ] || rm -f $@
|
||||
|
||||
%.d: %.cpp
|
||||
@[ -s $(OSDIR)/config.h ] || $(MAKE) config
|
||||
@$(CXX) -MM -MT '$(patsubst %.d,%.o, $@)' $(CXXFLAGS) $(CPPFLAGS) -w $< > $@
|
||||
@[ -s $@ ] || rm -f $@
|
||||
|
||||
### Various cleaning functions
|
||||
.PHONY: clean veryclean spotless all
|
||||
|
||||
clean:
|
||||
find $(MODULES) -name \*.o | xargs rm -f
|
||||
|
||||
veryclean: clean
|
||||
find $(MODULES) -name \*.d | xargs rm -f
|
||||
rm -rf bin
|
||||
|
||||
spotless: veryclean
|
||||
rm -rf arch $(OSDIR)/config.mk $(OSDIR)/config.h
|
||||
|
||||
|
||||
### dependency stuff is done automatically, so these do nothing.
|
||||
.PHONY: dep depend
|
||||
|
||||
|
||||
### Help function
|
||||
.PHONY: help
|
||||
|
||||
help:
|
||||
@echo 'Possible Targets are:'
|
||||
@echo ' help (this is it)'
|
||||
@echo ' all'
|
||||
@echo ' install'
|
||||
@echo ' binary'
|
||||
@echo ' source'
|
||||
@echo ' (binary and source can be called as'
|
||||
@echo ' a -zip or -tgz variants)'
|
||||
@echo ' clean'
|
||||
@echo ' veryclean'
|
||||
@echo ' spotless'
|
||||
@echo
|
||||
|
||||
### Rules to make various packaging
|
||||
.PHONY: binary binary-tgz source-zip source-tgz source install
|
||||
|
||||
arch:
|
||||
mkdir arch
|
||||
|
||||
install: $(BIN)
|
||||
install -d $(DESTDIR)$(PREFIX)/bin
|
||||
install -d $(DESTDIR)$(PREFIX)/share/man/man1
|
||||
install -c -m 0755 $(BIN) $(DESTDIR)$(PREFIX)/bin/
|
||||
install -c -m 0644 docs/leocad.1 $(DESTDIR)$(PREFIX)/share/man/man1/
|
||||
|
||||
binary: binary-zip binary-tgz
|
||||
|
||||
binary-zip: arch/leocad-$(VERSION)-linux.zip
|
||||
|
||||
binary-tgz: arch/leocad-$(VERSION)-linux.tgz
|
||||
|
||||
source: source-tgz source-zip
|
||||
|
||||
source-tgz: arch/leocad-$(VERSION)-src.tgz
|
||||
|
||||
source-zip: arch/leocad-$(VERSION)-src.zip
|
||||
|
||||
### Create a directory with the files needed for a binary package
|
||||
package-dir: arch all
|
||||
mkdir leocad-$(VERSION)
|
||||
cp bin/leocad leocad-$(VERSION)
|
||||
cp CREDITS.txt leocad-$(VERSION)/CREDITS
|
||||
cp README.txt leocad-$(VERSION)/README
|
||||
cp docs/INSTALL.txt leocad-$(VERSION)/INSTALL
|
||||
cp docs/LINUX.txt leocad-$(VERSION)/LINUX
|
||||
cp docs/leocad.1 leocad-$(VERSION)
|
||||
|
||||
arch/leocad-$(VERSION)-linux.zip: package-dir
|
||||
rm -f $@
|
||||
zip -r $@ leocad-$(VERSION)
|
||||
rm -rf leocad-$(VERSION)
|
||||
|
||||
arch/leocad-$(VERSION)-linux.tgz: package-dir
|
||||
rm -f $@
|
||||
tar -cvzf $@ leocad-$(VERSION)
|
||||
rm -rf leocad-$(VERSION)
|
||||
|
||||
arch/leocad-$(VERSION)-src.tgz: arch veryclean
|
||||
rm -f $@
|
||||
( cd .. ; tar --exclude=leocad/arch/\* --exclude=CVS \
|
||||
-cvzf leocad/$@ leocad )
|
||||
|
||||
arch/leocad-$(VERSION)-src.zip: arch veryclean
|
||||
rm -f $@
|
||||
( cd .. ; zip -r leocad/$@ leocad -x '*/arch/*' -x '*/CVS/*' -x '*~' -x '*/core' -x '*/.#*')
|
||||
|
61
README.txt
Normal file
61
README.txt
Normal file
|
@ -0,0 +1,61 @@
|
|||
About LeoCAD
|
||||
------------
|
||||
|
||||
LeoCAD is a CAD program that allows people to build virtual models using
|
||||
bricks similar to those found in LEGO toys. It's available for free under
|
||||
the GNU Public License v2, and works on the Windows and Linux Operating
|
||||
Systems.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
You can download the latest version of LeoCAD and its Pieces Library from
|
||||
the main website at http://www.leocad.org
|
||||
|
||||
It's recommended that you install the latest drivers for your video card,
|
||||
since LeoCAD can take advantage of hardware acceleration for rendering by
|
||||
using OpenGL.
|
||||
|
||||
- LeoCAD for Windows:
|
||||
|
||||
Download LeoCAD-0.75.2-4351.exe to your computer, double click on the
|
||||
icon to launch the installer and follow the intructions.
|
||||
|
||||
- LeoCAD for Linux:
|
||||
|
||||
You can either download the source from Subversion or use the i386 rpm
|
||||
binaries. If you decide to compile it yourself you will also need to
|
||||
download the Pieces Library separately, extract it to any directory of
|
||||
your choice and point the LEOCAD_LIB environment variable to it. More
|
||||
information is available at http://www.leocad.org
|
||||
|
||||
New users should take a look at the online tutorial located at
|
||||
http://www.leocad.org/trac/wiki/BasicTutorial/ to learn how to use LeoCAD.
|
||||
|
||||
|
||||
Online Resources
|
||||
----------------
|
||||
|
||||
- Website:
|
||||
http://www.leocad.org/
|
||||
|
||||
- Mailing lists:
|
||||
http://gerf.org/mailman/listinfo
|
||||
|
||||
- LUGNET Newsgroup:
|
||||
http://news.lugnet.com/cad/leocad/
|
||||
news://lugnet.com/lugnet.cad.leocad
|
||||
|
||||
- Subversion access:
|
||||
http://svn.leocad.org/
|
||||
|
||||
- Bug database:
|
||||
http://www.leocad.org/trac/report
|
||||
|
||||
|
||||
Legal Disclaimer
|
||||
----------------
|
||||
|
||||
LEGO is a trademark of the LEGO Group of companies which does not sponsor,
|
||||
authorize or endorse this software.
|
1
common/Makefile
Normal file
1
common/Makefile
Normal file
|
@ -0,0 +1 @@
|
|||
include ../generic.mk
|
433
common/algebra.cpp
Normal file
433
common/algebra.cpp
Normal file
|
@ -0,0 +1,433 @@
|
|||
//
|
||||
// Math and Linear Algebra stuff.
|
||||
//
|
||||
|
||||
#include "defines.h"
|
||||
#include "algebra.h"
|
||||
|
||||
// ============================================================================
|
||||
// 4x4 Matrix class.
|
||||
|
||||
void Matrix44::CreateLookAt(const Vector3& Eye, const Vector3& Target, const Vector3& Up)
|
||||
{
|
||||
Vector3 x, y, z;
|
||||
|
||||
// Z = Eye - Target
|
||||
z = Eye - Target;
|
||||
|
||||
// X = Y Cross Z
|
||||
x = Cross3(Up, z);
|
||||
|
||||
// Y = Z Cross X
|
||||
y = Cross3(z, x);
|
||||
|
||||
// Normalize everything.
|
||||
x.Normalize();
|
||||
y.Normalize();
|
||||
z.Normalize();
|
||||
|
||||
m_Rows[0] = Vector4(x[0], y[0], z[0], 0.0f);
|
||||
m_Rows[1] = Vector4(x[1], y[1], z[1], 0.0f);
|
||||
m_Rows[2] = Vector4(x[2], y[2], z[2], 0.0f);
|
||||
m_Rows[3] = m_Rows[0]*-Eye[0] + m_Rows[1]*-Eye[1] + m_Rows[2]*-Eye[2];
|
||||
m_Rows[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
void Matrix44::CreatePerspective(float FoVy, float Aspect, float Near, float Far)
|
||||
{
|
||||
float Left, Right, Bottom, Top;
|
||||
|
||||
Top = Near * (float)tan(FoVy * LC_PI / 360.0f);
|
||||
Bottom = -Top;
|
||||
|
||||
Left = Bottom * Aspect;
|
||||
Right = Top * Aspect;
|
||||
|
||||
if ((Near <= 0.0f) || (Far <= 0.0f) || (Near == Far) || (Left == Right) || (Top == Bottom))
|
||||
return;
|
||||
|
||||
float x, y, a, b, c, d;
|
||||
|
||||
x = (2.0f * Near) / (Right - Left);
|
||||
y = (2.0f * Near) / (Top - Bottom);
|
||||
a = (Right + Left) / (Right - Left);
|
||||
b = (Top + Bottom) / (Top - Bottom);
|
||||
c = -(Far + Near) / (Far - Near);
|
||||
d = -(2.0f * Far * Near) / (Far - Near);
|
||||
|
||||
m_Rows[0] = Vector4(x, 0, 0, 0);
|
||||
m_Rows[1] = Vector4(0, y, 0, 0);
|
||||
m_Rows[2] = Vector4(a, b, c, -1);
|
||||
m_Rows[3] = Vector4(0, 0, d, 0);
|
||||
}
|
||||
|
||||
// Inverse code from the GLU library.
|
||||
Matrix44 Inverse(const Matrix44& m)
|
||||
{
|
||||
#define SWAP_ROWS(a, b) { float *_tmp = a; (a)=(b); (b)=_tmp; }
|
||||
#define MAT(m,c,r) m.m_Rows[r][c]
|
||||
|
||||
float wtmp[4][8];
|
||||
float m0, m1, m2, m3, s;
|
||||
float *r0, *r1, *r2, *r3;
|
||||
|
||||
r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
|
||||
|
||||
r0[0] = MAT(m,0,0), r0[1] = MAT(m,0,1),
|
||||
r0[2] = MAT(m,0,2), r0[3] = MAT(m,0,3),
|
||||
r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0,
|
||||
|
||||
r1[0] = MAT(m,1,0), r1[1] = MAT(m,1,1),
|
||||
r1[2] = MAT(m,1,2), r1[3] = MAT(m,1,3),
|
||||
r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0,
|
||||
|
||||
r2[0] = MAT(m,2,0), r2[1] = MAT(m,2,1),
|
||||
r2[2] = MAT(m,2,2), r2[3] = MAT(m,2,3),
|
||||
r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0,
|
||||
|
||||
r3[0] = MAT(m,3,0), r3[1] = MAT(m,3,1),
|
||||
r3[2] = MAT(m,3,2), r3[3] = MAT(m,3,3),
|
||||
r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0;
|
||||
|
||||
// choose pivot - or die
|
||||
if (fabs(r3[0])>fabs(r2[0])) SWAP_ROWS(r3, r2);
|
||||
if (fabs(r2[0])>fabs(r1[0])) SWAP_ROWS(r2, r1);
|
||||
if (fabs(r1[0])>fabs(r0[0])) SWAP_ROWS(r1, r0);
|
||||
// if (0.0 == r0[0]) return GL_FALSE;
|
||||
|
||||
// eliminate first variable
|
||||
m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0];
|
||||
s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s;
|
||||
s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s;
|
||||
s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s;
|
||||
s = r0[4];
|
||||
if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; }
|
||||
s = r0[5];
|
||||
if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; }
|
||||
s = r0[6];
|
||||
if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; }
|
||||
s = r0[7];
|
||||
if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; }
|
||||
|
||||
// choose pivot - or die
|
||||
if (fabs(r3[1])>fabs(r2[1])) SWAP_ROWS(r3, r2);
|
||||
if (fabs(r2[1])>fabs(r1[1])) SWAP_ROWS(r2, r1);
|
||||
// if (0.0 == r1[1]) return GL_FALSE;
|
||||
|
||||
// eliminate second variable
|
||||
m2 = r2[1]/r1[1]; m3 = r3[1]/r1[1];
|
||||
r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2];
|
||||
r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3];
|
||||
s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; }
|
||||
s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; }
|
||||
s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; }
|
||||
s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; }
|
||||
|
||||
// choose pivot - or die
|
||||
if (fabs(r3[2])>fabs(r2[2])) SWAP_ROWS(r3, r2);
|
||||
// if (0.0 == r2[2]) return GL_FALSE;
|
||||
|
||||
// eliminate third variable
|
||||
m3 = r3[2]/r2[2];
|
||||
r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
|
||||
r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6],
|
||||
r3[7] -= m3 * r2[7];
|
||||
|
||||
// last check
|
||||
// if (0.0 == r3[3]) return GL_FALSE;
|
||||
|
||||
s = 1.0f/r3[3]; // now back substitute row 3
|
||||
r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s;
|
||||
|
||||
m2 = r2[3]; // now back substitute row 2
|
||||
s = 1.0f/r2[2];
|
||||
r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
|
||||
r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
|
||||
m1 = r1[3];
|
||||
r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
|
||||
r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
|
||||
m0 = r0[3];
|
||||
r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
|
||||
r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
|
||||
|
||||
m1 = r1[2]; // now back substitute row 1
|
||||
s = 1.0f/r1[1];
|
||||
r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
|
||||
r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
|
||||
m0 = r0[2];
|
||||
r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
|
||||
r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
|
||||
|
||||
m0 = r0[1]; // now back substitute row 0
|
||||
s = 1.0f/r0[0];
|
||||
r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
|
||||
r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
|
||||
|
||||
Vector4 Row0(r0[4], r1[4], r2[4], r3[4]);
|
||||
Vector4 Row1(r0[5], r1[5], r2[5], r3[5]);
|
||||
Vector4 Row2(r0[6], r1[6], r2[6], r3[6]);
|
||||
Vector4 Row3(r0[7], r1[7], r2[7], r3[7]);
|
||||
|
||||
Matrix44 out(Row0, Row1, Row2, Row3);
|
||||
|
||||
return out;
|
||||
|
||||
#undef MAT
|
||||
#undef SWAP_ROWS
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Project/Unproject a point.
|
||||
|
||||
// Convert world coordinates to screen coordinates.
|
||||
Vector3 ProjectPoint(const Vector3& Pt, const Matrix44& ModelView, const Matrix44& Projection, const int Viewport[4])
|
||||
{
|
||||
Vector4 Tmp;
|
||||
|
||||
Tmp = Mul4(Vector4(Pt[0], Pt[1], Pt[2], 1.0f), ModelView);
|
||||
Tmp = Mul4(Tmp, Projection);
|
||||
|
||||
// Normalize.
|
||||
Tmp /= Tmp[3];
|
||||
|
||||
// Screen coordinates.
|
||||
return Vector3(Viewport[0]+(1+Tmp[0])*Viewport[2]/2, Viewport[1]+(1+Tmp[1])*Viewport[3]/2, (1+Tmp[2])/2);
|
||||
}
|
||||
|
||||
void ProjectPoints(Vector3* Points, int NumPoints, const Matrix44& ModelView, const Matrix44& Projection, const int Viewport[4])
|
||||
{
|
||||
for (int i = 0; i < NumPoints; i++)
|
||||
{
|
||||
Vector4 Tmp;
|
||||
|
||||
Tmp = Mul4(Vector4(Points[i][0], Points[i][1], Points[i][2], 1.0f), ModelView);
|
||||
Tmp = Mul4(Tmp, Projection);
|
||||
|
||||
// Normalize.
|
||||
Tmp /= Tmp[3];
|
||||
|
||||
// Screen coordinates.
|
||||
Points[i] = Vector3(Viewport[0]+(1+Tmp[0])*Viewport[2]/2, Viewport[1]+(1+Tmp[1])*Viewport[3]/2, (1+Tmp[2])/2);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert screen coordinates to world coordinates.
|
||||
Vector3 UnprojectPoint(const Vector3& Point, const Matrix44& ModelView, const Matrix44& Projection, const int Viewport[4])
|
||||
{
|
||||
Vector3 Tmp = Point;
|
||||
UnprojectPoints(&Tmp, 1, ModelView, Projection, Viewport);
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
void UnprojectPoints(Vector3* Points, int NumPoints, const Matrix44& ModelView, const Matrix44& Projection, const int Viewport[4])
|
||||
{
|
||||
// Calculate the screen to model transform.
|
||||
Matrix44 Transform = Inverse(Mul(ModelView, Projection));
|
||||
|
||||
for (int i = 0; i < NumPoints; i++)
|
||||
{
|
||||
Vector4 Tmp;
|
||||
|
||||
// Convert the point to homogeneous coordinates.
|
||||
Tmp[0] = (Points[i][0] - Viewport[0]) * 2.0f / Viewport[2] - 1.0f;
|
||||
Tmp[1] = (Points[i][1] - Viewport[1]) * 2.0f / Viewport[3] - 1.0f;
|
||||
Tmp[2] = Points[i][2] * 2.0f - 1.0f;
|
||||
Tmp[3] = 1.0f;
|
||||
|
||||
Tmp = Mul4(Tmp, Transform);
|
||||
|
||||
if (Tmp[3] != 0.0f)
|
||||
Tmp /= Tmp[3];
|
||||
|
||||
Points[i] = Vector3(Tmp[0], Tmp[1], Tmp[2]);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Geometry functions.
|
||||
|
||||
// Sutherland-Hodgman method of clipping a polygon to a plane.
|
||||
void PolygonPlaneClip(Vector3* InPoints, int NumInPoints, Vector3* OutPoints, int* NumOutPoints, const Vector4& Plane)
|
||||
{
|
||||
Vector3 *s, *p, i;
|
||||
|
||||
*NumOutPoints = 0;
|
||||
s = &InPoints[NumInPoints-1];
|
||||
|
||||
for (int j = 0; j < NumInPoints; j++)
|
||||
{
|
||||
p = &InPoints[j];
|
||||
|
||||
if (Dot3(*p, Plane) + Plane[3] <= 0)
|
||||
{
|
||||
if (Dot3(*s, Plane) + Plane[3] <= 0)
|
||||
{
|
||||
// Both points inside.
|
||||
OutPoints[*NumOutPoints] = *p;
|
||||
*NumOutPoints = *NumOutPoints + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Outside, inside.
|
||||
LinePlaneIntersection(i, *s, *p, Plane);
|
||||
|
||||
OutPoints[*NumOutPoints] = i;
|
||||
*NumOutPoints = *NumOutPoints + 1;
|
||||
OutPoints[*NumOutPoints] = *p;
|
||||
*NumOutPoints = *NumOutPoints + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Dot3(*s, Plane) + Plane[3] <= 0)
|
||||
{
|
||||
// Inside, outside.
|
||||
LinePlaneIntersection(i, *s, *p, Plane);
|
||||
|
||||
OutPoints[*NumOutPoints] = i;
|
||||
*NumOutPoints = *NumOutPoints + 1;
|
||||
}
|
||||
}
|
||||
|
||||
s = p;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the intersection of a line segment and a plane and returns false
|
||||
// if they are parallel or the intersection is outside the line segment.
|
||||
bool LinePlaneIntersection(Vector3& Intersection, const Vector3& Start, const Vector3& End, const Vector4& Plane)
|
||||
{
|
||||
Vector3 Dir = End - Start;
|
||||
|
||||
float t1 = Dot3(Plane, Start) + Plane[3];
|
||||
float t2 = Dot3(Plane, Dir);
|
||||
|
||||
if (t2 == 0.0f)
|
||||
return false;
|
||||
|
||||
float t = -t1 / t2;
|
||||
|
||||
Intersection = Start + t * Dir;
|
||||
|
||||
if ((t < 0.0f) || (t > 1.0f))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LineTriangleMinIntersection(const Vector3& p1, const Vector3& p2, const Vector3& p3, const Vector3& Start, const Vector3& End, float& MinDist, Vector3& Intersection)
|
||||
{
|
||||
// Calculate the polygon plane.
|
||||
Vector4 Plane;
|
||||
Plane = Cross3(p1 - p2, p3 - p2);
|
||||
Plane[3] = -Dot3(Plane, p1);
|
||||
|
||||
// Check if the line is parallel to the plane.
|
||||
Vector3 Dir = End - Start;
|
||||
|
||||
float t1 = Dot3(Plane, Start) + Plane[3];
|
||||
float t2 = Dot3(Plane, Dir);
|
||||
|
||||
if (t2 == 0)
|
||||
return false;
|
||||
|
||||
float t = -(t1 / t2);
|
||||
|
||||
if (t < 0)
|
||||
return false;
|
||||
|
||||
// Intersection of the plane and line segment.
|
||||
Intersection = Start - (t1 / t2) * Dir;
|
||||
|
||||
float Dist = (Start - Intersection).Length();
|
||||
|
||||
if (Dist > MinDist)
|
||||
return false;
|
||||
|
||||
// Check if we're inside the triangle.
|
||||
Vector3 pa1, pa2, pa3;
|
||||
pa1 = (p1 - Intersection).Normalize();
|
||||
pa2 = (p2 - Intersection).Normalize();
|
||||
pa3 = (p3 - Intersection).Normalize();
|
||||
|
||||
float a1, a2, a3;
|
||||
a1 = Dot3(pa1, pa2);
|
||||
a2 = Dot3(pa2, pa3);
|
||||
a3 = Dot3(pa3, pa1);
|
||||
|
||||
float total = (acosf(a1) + acosf(a2) + acosf(a3)) * RTOD;
|
||||
|
||||
if (fabs(total - 360) <= 0.001f)
|
||||
{
|
||||
MinDist = Dist;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LineQuadMinIntersection(const Vector3& p1, const Vector3& p2, const Vector3& p3, const Vector3& p4, const Vector3& Start, const Vector3& End, float& MinDist, Vector3& Intersection)
|
||||
{
|
||||
// Calculate the polygon plane.
|
||||
Vector4 Plane;
|
||||
Plane = Cross3(p1 - p2, p3 - p2);
|
||||
Plane[3] = -Dot3(Plane, p1);
|
||||
|
||||
// Check if the line is parallel to the plane.
|
||||
Vector3 Dir = End - Start;
|
||||
|
||||
float t1 = Dot3(Plane, Start) + Plane[3];
|
||||
float t2 = Dot3(Plane, Dir);
|
||||
|
||||
if (t2 == 0)
|
||||
return false;
|
||||
|
||||
float t = -(t1 / t2);
|
||||
|
||||
if (t < 0)
|
||||
return false;
|
||||
|
||||
// Intersection of the plane and line segment.
|
||||
Intersection = Start - (t1 / t2) * Dir;
|
||||
|
||||
float Dist = (Start - Intersection).Length();
|
||||
|
||||
if (Dist > MinDist)
|
||||
return false;
|
||||
|
||||
// Check if we're inside the triangle.
|
||||
Vector3 pa1, pa2, pa3;
|
||||
pa1 = (p1 - Intersection).Normalize();
|
||||
pa2 = (p2 - Intersection).Normalize();
|
||||
pa3 = (p3 - Intersection).Normalize();
|
||||
|
||||
float a1, a2, a3;
|
||||
a1 = Dot3(pa1, pa2);
|
||||
a2 = Dot3(pa2, pa3);
|
||||
a3 = Dot3(pa3, pa1);
|
||||
|
||||
float total = (acosf(a1) + acosf(a2) + acosf(a3)) * RTOD;
|
||||
|
||||
if (fabs(total - 360) <= 0.001f)
|
||||
{
|
||||
MinDist = Dist;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if we're inside the second triangle.
|
||||
pa2 = (p4 - Intersection).Normalize();
|
||||
|
||||
a1 = Dot3(pa1, pa2);
|
||||
a2 = Dot3(pa2, pa3);
|
||||
a3 = Dot3(pa3, pa1);
|
||||
|
||||
total = (acosf(a1) + acosf(a2) + acosf(a3)) * RTOD;
|
||||
|
||||
if (fabs(total - 360) <= 0.001f)
|
||||
{
|
||||
MinDist = Dist;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
707
common/algebra.h
Normal file
707
common/algebra.h
Normal file
|
@ -0,0 +1,707 @@
|
|||
#ifndef _ALGEBRA_H_
|
||||
#define _ALGEBRA_H_
|
||||
|
||||
#include <math.h>
|
||||
|
||||
//
|
||||
// Simple math library and linear algebra functions.
|
||||
//
|
||||
// Everything is based on the Vector4 class, so changing that class should be enough
|
||||
// to add support for compiler specific math intrinsics.
|
||||
//
|
||||
// Functions that end with 34 mean that they don't care what happens to the 4th
|
||||
// component, it can either be affected or not.
|
||||
//
|
||||
// Matrices are represented as row-major, so we pre-multiply instead of post-multiplying
|
||||
// like you would in a column major notation.
|
||||
//
|
||||
// OpenGL only expects a matrix to be an array of 16 floats so it doesn't matter what
|
||||
// notation we use.
|
||||
//
|
||||
// v[0] v[1] v[2] v[3] <- x, y, z, w
|
||||
//
|
||||
// m[0] m[1] m[2] m[3] <- x axis
|
||||
// m[4] m[5] m[6] m[7] <- y axis
|
||||
// m[8] m[9] m[10] m[11] <- z axis
|
||||
// m[12] m[13] m[14] m[15] <- translation
|
||||
//
|
||||
|
||||
// TODO: Move this define to config.h
|
||||
#define LC_MATH_FLOAT
|
||||
//#define LC_MATH_SSE
|
||||
|
||||
// Classes defined in this file:
|
||||
class Vector3;
|
||||
class Vector4;
|
||||
class Quaternion;
|
||||
class Matrix44;
|
||||
|
||||
// ============================================================================
|
||||
// Vector4 class (float version).
|
||||
|
||||
#ifdef LC_MATH_FLOAT
|
||||
|
||||
class Vector4
|
||||
{
|
||||
public:
|
||||
// Constructors.
|
||||
inline Vector4() { }
|
||||
inline explicit Vector4(const float _x, const float _y, const float _z)
|
||||
: x(_x), y(_y), z(_z) { }
|
||||
inline explicit Vector4(const float _x, const float _y, const float _z, const float _w)
|
||||
: x(_x), y(_y), z(_z), w(_w) { }
|
||||
|
||||
inline operator const float*() const { return (const float*)this; }
|
||||
inline float& operator[](int i) const { return ((float*)this)[i]; }
|
||||
|
||||
// Comparison.
|
||||
friend inline bool operator==(const Vector4& a, const Vector4& b)
|
||||
{ return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); }
|
||||
|
||||
friend inline bool Compare3(const Vector4& a, const Vector4& b)
|
||||
{ return (a.x == b.x) && (a.y == b.y) && (a.z == b.z); }
|
||||
|
||||
// Math operations for 4 components.
|
||||
friend inline Vector4 operator+(const Vector4& a, const Vector4& b)
|
||||
{ return Vector4(a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w); }
|
||||
|
||||
friend inline Vector4 operator-(const Vector4& a, const Vector4& b)
|
||||
{ return Vector4(a.x-b.x, a.y-b.y, a.z-b.z, a.w-b.w); }
|
||||
|
||||
friend inline Vector4 operator*(const Vector4& a, float f)
|
||||
{ return Vector4(a.x*f, a.y*f, a.z*f, a.w*f); }
|
||||
|
||||
friend inline Vector4 operator*(const Vector4& a, const Vector4& b)
|
||||
{ return Vector4(a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w); }
|
||||
|
||||
friend inline Vector4 operator/(const Vector4& a, float f)
|
||||
{ return Vector4(a.x/f, a.y/f, a.z/f, a.w/f); }
|
||||
|
||||
friend inline Vector4 operator/=(Vector4& a, float f)
|
||||
{ a = Vector4(a.x/f, a.y/f, a.z/f, a.w/f); return a; }
|
||||
|
||||
friend inline Vector4 operator-(const Vector4& a)
|
||||
{ return Vector4(-a.x, -a.y, -a.z, -a.w); }
|
||||
|
||||
// Math operations ignoring the 4th component.
|
||||
friend inline Vector4 Add34(const Vector4& a, const Vector4& b)
|
||||
{ return Vector4(a.x+b.x, a.y+b.y, a.z+b.z); }
|
||||
|
||||
friend inline Vector4 Subtract34(const Vector4& a, const Vector4& b)
|
||||
{ return Vector4(a.x-b.x, a.y-b.y, a.z-b.z); }
|
||||
|
||||
friend inline Vector4 Multiply34(const Vector4& a, float f)
|
||||
{ return Vector4(a.x*f, a.y*f, a.z*f); }
|
||||
|
||||
friend inline Vector4 Multiply34(const Vector4& a, const Vector4& b)
|
||||
{ return Vector4(a.x*b.x, a.y*b.y, a.z*b.z); }
|
||||
|
||||
friend inline Vector4 Divide34(const Vector4& a, float f)
|
||||
{ return Vector4(a.x/f, a.y/f, a.z/f); }
|
||||
|
||||
friend inline Vector4 Negate34(const Vector4& a)
|
||||
{ return Vector4(-a.x, -a.y, -a.z, -a.w); }
|
||||
|
||||
// Dot product.
|
||||
friend inline float Dot3(const Vector4& a, const Vector4& b)
|
||||
{ return a.x*b.x + a.y*b.y + a.z*b.z; }
|
||||
|
||||
friend inline float Dot4(const Vector4& a, const Vector4& b)
|
||||
{ return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; }
|
||||
|
||||
// Cross product.
|
||||
friend inline Vector4 Cross3(const Vector4& a, const Vector4& b)
|
||||
{ return Vector4(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x); }
|
||||
|
||||
// Other functions.
|
||||
inline float Length3() const
|
||||
{ return sqrtf(x*x + y*y + z*z); }
|
||||
|
||||
inline void Normalize34()
|
||||
{
|
||||
float len = 1.0f / sqrtf(x*x + y*y + z*z);
|
||||
|
||||
x *= len;
|
||||
y *= len;
|
||||
z *= len;
|
||||
}
|
||||
|
||||
inline void Abs34()
|
||||
{
|
||||
if (x < 0.0f) x = -x;
|
||||
if (y < 0.0f) y = -y;
|
||||
if (z < 0.0f) z = -z;
|
||||
}
|
||||
|
||||
inline void Abs()
|
||||
{
|
||||
if (x < 0.0f) x = -x;
|
||||
if (y < 0.0f) y = -y;
|
||||
if (z < 0.0f) z = -z;
|
||||
if (w < 0.0f) w = -w;
|
||||
}
|
||||
|
||||
protected:
|
||||
float x, y, z, w;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// Vector4 class (SSE version).
|
||||
|
||||
#ifdef LC_MATH_SSE
|
||||
|
||||
// If you can't find this file you need to install the VS6 Processor Pack.
|
||||
#include <xmmintrin.h>
|
||||
|
||||
class __declspec(align(16)) Vector4
|
||||
{
|
||||
public:
|
||||
// Constructors.
|
||||
inline Vector4() { }
|
||||
inline explicit Vector4(const __m128& _xyzw)
|
||||
: xyzw(_xyzw) { }
|
||||
inline explicit Vector4(const float _x, const float _y, const float _z)
|
||||
: xyzw(_mm_setr_ps(_x, _y, _z, _z)) { }
|
||||
inline explicit Vector4(const float _x, const float _y, const float _z, const float _w)
|
||||
: xyzw(_mm_setr_ps(_x, _y, _z, _w)) { }
|
||||
|
||||
inline float& operator[](int i) const { return ((const float*)this)[i]; }
|
||||
|
||||
// Comparison.
|
||||
friend inline bool operator==(const Vector4& a, const Vector4& b)
|
||||
{ return !_mm_movemask_ps(_mm_cmpneq_ps(a.xyzw, b.xyzw)); }
|
||||
|
||||
friend inline bool Compare3(const Vector4& a, const Vector4& b)
|
||||
{ return (_mm_movemask_ps(_mm_cmpeq_ps(a.xyzw, b.xyzw)) & 0x7) == 0x7; }
|
||||
|
||||
// Math operations for 4 components.
|
||||
friend inline Vector4 operator+(const Vector4& a, const Vector4& b)
|
||||
{ return Vector4(_mm_add_ps(a.xyzw, b.xyzw)); }
|
||||
|
||||
friend inline Vector4 operator-(const Vector4& a, const Vector4& b)
|
||||
{ return Vector4(_mm_sub_ps(a.xyzw, b.xyzw)); }
|
||||
|
||||
friend inline Vector4 operator*(const Vector4& a, float f)
|
||||
{ return Vector4(_mm_mul_ps(a.xyzw, _mm_load_ps1(&f))); }
|
||||
|
||||
friend inline Vector4 operator*(const Vector4& a, const Vector4& b)
|
||||
{ return Vector4(_mm_mul_ps(a.xyzw, b.xyzw)); }
|
||||
|
||||
friend inline Vector4 operator/(const Vector4& a, float f)
|
||||
{ return Vector4(_mm_div_ps(a.xyzw, _mm_load_ps1(&f))); }
|
||||
|
||||
friend inline Vector4 operator-(const Vector4& a)
|
||||
{
|
||||
static const __declspec(align(16)) unsigned int Mask[4] = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
|
||||
return Vector4(_mm_xor_ps(xyzw, *(__m128*)&Mask));
|
||||
}
|
||||
|
||||
// Math operations ignoring the 4th component.
|
||||
friend inline Vector4 Add34(const Vector4& a, const Vector4& b)
|
||||
{ return a*b }
|
||||
|
||||
friend inline Vector4 Subtract34(const Vector4& a, const Vector4& b)
|
||||
{ return a-b; }
|
||||
|
||||
friend inline Vector4 Multiply34(const Vector4& a, float f)
|
||||
{ return a*f; }
|
||||
|
||||
friend inline Vector4 Multiply34(const Vector4& a, const Vector4& b)
|
||||
{ return a*b; }
|
||||
|
||||
friend inline Vector4 Divide34(const Vector4& a, float f)
|
||||
{ return a/f; }
|
||||
|
||||
friend inline Vector4 Negate34(const Vector4& a)
|
||||
{ return -a; }
|
||||
|
||||
// Dot product.
|
||||
friend inline float Dot3(const Vector4& a, const Vector4& b)
|
||||
{
|
||||
__m128 tmp = _mm_mul_ps(a.xyzw, b.xyzw);
|
||||
__m128 yz = _mm_add_ss(_mm_shuffle_ps(tmp, tmp, _MM_SHUFFLE(1, 1, 1, 1)), _mm_shuffle_ps(tmp, tmp, _MM_SHUFFLE(2, 2, 2, 2)));
|
||||
tmp = _mm_add_ss(tmp, yz);
|
||||
|
||||
return *(const float*)&tmp;
|
||||
}
|
||||
|
||||
// Cross product.
|
||||
friend inline Vector4 Cross3(const Vector4& a, const Vector4& b)
|
||||
{
|
||||
// a(yzx)*b(zxy)-a(zxy)*b(yzx)
|
||||
__m128 r1 = _mm_mul_ps(_mm_shuffle_ps(a.xyzw, a.xyzw, _MM_SHUFFLE(0, 0, 2, 1)), _mm_shuffle_ps(b.xyzw, b.xyzw, _MM_SHUFFLE(0, 1, 0, 2)));
|
||||
__m128 r2 = _mm_mul_ps(_mm_shuffle_ps(a.xyzw, a.xyzw, _MM_SHUFFLE(0, 1, 0, 2)), _mm_shuffle_ps(b.xyzw, b.xyzw, _MM_SHUFFLE(0, 0, 2, 1)));
|
||||
|
||||
return Vector4(_mm_sub_ps(r1, r2));
|
||||
}
|
||||
|
||||
// Other functions.
|
||||
inline float Length3() const
|
||||
{
|
||||
__m128 tmp = _mm_mul_ps(xyzw, xyzw);
|
||||
__m128 yz = _mm_add_ss(_mm_shuffle_ps(tmp, tmp, _MM_SHUFFLE(1, 1, 1, 1)), _mm_shuffle_ps(tmp, tmp, _MM_SHUFFLE(2, 2, 2, 2)));
|
||||
tmp = _mm_add_ss(tmp, yz);
|
||||
tmp = _mm_sqrt_ss(tmp);
|
||||
|
||||
return *(const float*)&tmp;
|
||||
}
|
||||
|
||||
inline void Normalize34()
|
||||
{
|
||||
__m128 tmp = _mm_mul_ps(xyzw, xyzw);
|
||||
__m128 yz = _mm_add_ss(_mm_shuffle_ps(tmp, tmp, _MM_SHUFFLE(1, 1, 1, 1)), _mm_shuffle_ps(tmp, tmp, _MM_SHUFFLE(2, 2, 2, 2)));
|
||||
tmp = _mm_add_ss(tmp, yz);
|
||||
tmp = _mm_rsqrt_ss(tmp);
|
||||
tmp = _mm_shuffle_ps(tmp, tmp, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
xyzw = _mm_mul_ps(xyzw, tmp);
|
||||
}
|
||||
|
||||
inline void Abs()
|
||||
{
|
||||
static const __declspec(align(16)) unsigned int Mask[4] = { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff }
|
||||
xyzw = _mm_and_ps(xyzw, *(__m128*)&Mask);
|
||||
}
|
||||
|
||||
protected:
|
||||
__m128 xyzw;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// 3D Vector class.
|
||||
|
||||
class Vector3
|
||||
{
|
||||
public:
|
||||
// Constructors.
|
||||
inline Vector3()
|
||||
{ }
|
||||
inline explicit Vector3(const Vector4& _v)
|
||||
: m_Value(_v) { }
|
||||
inline explicit Vector3(const float _x, const float _y, const float _z)
|
||||
: m_Value(_x, _y, _z) { }
|
||||
|
||||
inline operator const float*() const { return (const float*)this; }
|
||||
inline operator float*() { return (float*)this; }
|
||||
inline const Vector4& GetValue() const { return m_Value; }
|
||||
inline operator const Vector4() const
|
||||
{ return Vector4(m_Value[0], m_Value[1], m_Value[2], 0.0f); }
|
||||
|
||||
inline float& operator[](int i) const { return m_Value[i]; }
|
||||
|
||||
// Math operations.
|
||||
friend inline Vector3 operator+=(Vector3& a, const Vector3& b)
|
||||
{ a.m_Value = a.m_Value + b.m_Value; return a; }
|
||||
|
||||
friend inline Vector3 operator*=(Vector3& a, float b)
|
||||
{ a.m_Value = a.m_Value * b; return a; }
|
||||
|
||||
friend inline Vector3 operator/=(Vector3& a, float b)
|
||||
{ a.m_Value = a.m_Value / b; return a; }
|
||||
|
||||
// Other functions.
|
||||
inline float Length() const
|
||||
{ return m_Value.Length3(); }
|
||||
|
||||
inline float LengthSquared() const
|
||||
{ return Dot3(m_Value, m_Value); }
|
||||
|
||||
inline const Vector3& Normalize()
|
||||
{ m_Value.Normalize34(); return *this; }
|
||||
|
||||
inline void Abs()
|
||||
{ m_Value.Abs34(); }
|
||||
|
||||
protected:
|
||||
Vector4 m_Value;
|
||||
};
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Operators.
|
||||
|
||||
// Comparison.
|
||||
inline bool operator==(const Vector3& a, const Vector3& b)
|
||||
{ return Compare3(a.GetValue(), b.GetValue()); }
|
||||
|
||||
// Multiply by a scalar.
|
||||
inline Vector3 operator*(const Vector3& a, float f)
|
||||
{ return Vector3(Multiply34(a.GetValue(), f)); }
|
||||
|
||||
inline Vector3 operator*(float f, const Vector3& a)
|
||||
{ return Vector3(Multiply34(a.GetValue(), f)); }
|
||||
|
||||
// Divide by a scalar.
|
||||
inline Vector3 operator/(const Vector3& a, float f)
|
||||
{ return Vector3(Divide34(a.GetValue(), f)); }
|
||||
|
||||
inline Vector3 operator/(float f, const Vector3& a)
|
||||
{ return Vector3(Divide34(a.GetValue(), f)); }
|
||||
|
||||
// Add vectors.
|
||||
inline Vector3 operator+(const Vector3& a, const Vector3& b)
|
||||
{ return Vector3(Add34(a.GetValue(), b.GetValue())); }
|
||||
|
||||
// Subtract vectors.
|
||||
inline Vector3 operator-(const Vector3& a, const Vector3& b)
|
||||
{ return Vector3(Subtract34(a.GetValue(), b.GetValue())); }
|
||||
|
||||
// Negate.
|
||||
inline Vector3 operator-(const Vector3& a)
|
||||
{ return Vector3(Negate34(a.GetValue())); }
|
||||
|
||||
// Dot product.
|
||||
inline float Dot3(const Vector3& a, const Vector3& b)
|
||||
{ return Dot3(a.GetValue(), b.GetValue()); }
|
||||
|
||||
// Cross product.
|
||||
inline Vector3 Cross3(const Vector3& a, const Vector3& b)
|
||||
{ return Vector3(Cross3(a.GetValue(), b.GetValue())); }
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Quaternion class.
|
||||
|
||||
class Quaternion
|
||||
{
|
||||
public:
|
||||
// Constructors.
|
||||
inline Quaternion()
|
||||
{ }
|
||||
inline explicit Quaternion(const Vector4& _v)
|
||||
: m_Value(_v) { }
|
||||
inline explicit Quaternion(const float _x, const float _y, const float _z, const float _w)
|
||||
: m_Value(_x, _y, _z, _w) { }
|
||||
|
||||
// Get/Set functions.
|
||||
inline const float operator[](int i) const { return m_Value[i]; }
|
||||
|
||||
// Conversions.
|
||||
inline void FromAxisAngle(const Vector4& AxisAngle)
|
||||
{
|
||||
float s = sinf(AxisAngle[3] / 2.0f);
|
||||
m_Value = Vector4(AxisAngle[0] * s, AxisAngle[1] * s, AxisAngle[2] * s, cosf(AxisAngle[3] / 2.0f));
|
||||
}
|
||||
|
||||
inline void CreateRotationX(float Radians)
|
||||
{
|
||||
m_Value = Vector4(sinf(Radians / 2.0f), 0, 0, cosf(Radians / 2.0f));
|
||||
}
|
||||
|
||||
inline void CreateRotationY(float Radians)
|
||||
{
|
||||
m_Value = Vector4(0, sinf(Radians / 2.0f), 0, cosf(Radians / 2.0f));
|
||||
}
|
||||
|
||||
inline void CreateRotationZ(float Radians)
|
||||
{
|
||||
m_Value = Vector4(0, 0, sinf(Radians / 2.0f), cosf(Radians / 2.0f));
|
||||
}
|
||||
|
||||
inline void ToAxisAngle(Vector4& AxisAngle) const
|
||||
{
|
||||
float Len = m_Value[0]*m_Value[0] + m_Value[1]*m_Value[1] + m_Value[2]*m_Value[2];
|
||||
|
||||
if (Len > 0.0001f)
|
||||
{
|
||||
float f = 1.0f / sqrtf(Len);
|
||||
AxisAngle = Vector4(m_Value[0] * f, m_Value[1] * f, m_Value[2] * f, acosf(m_Value[3]) * 2.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
AxisAngle = Vector4(0, 0, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Operators.
|
||||
friend inline Quaternion Mul(const Quaternion& a, const Quaternion& b)
|
||||
{
|
||||
float x = a.m_Value[0] * b.m_Value[3] + a.m_Value[1] * b.m_Value[2] - a.m_Value[2] * b.m_Value[1] + a.m_Value[3] * b.m_Value[0];
|
||||
float y = -a.m_Value[0] * b.m_Value[2] + a.m_Value[1] * b.m_Value[3] + a.m_Value[2] * b.m_Value[0] + a.m_Value[3] * b.m_Value[1];
|
||||
float z = a.m_Value[0] * b.m_Value[1] - a.m_Value[1] * b.m_Value[0] + a.m_Value[2] * b.m_Value[3] + a.m_Value[3] * b.m_Value[2];
|
||||
float w = -a.m_Value[0] * b.m_Value[0] - a.m_Value[1] * b.m_Value[1] - a.m_Value[2] * b.m_Value[2] + a.m_Value[3] * b.m_Value[3];
|
||||
|
||||
return Quaternion(x, y, z, w);
|
||||
}
|
||||
|
||||
friend inline Vector3 Mul(const Vector3& a, const Quaternion& b)
|
||||
{
|
||||
// Faster to transform to a matrix and multiply.
|
||||
float Tx = 2.0f*b[0];
|
||||
float Ty = 2.0f*b[1];
|
||||
float Tz = 2.0f*b[2];
|
||||
float Twx = Tx*b[3];
|
||||
float Twy = Ty*b[3];
|
||||
float Twz = Tz*b[3];
|
||||
float Txx = Tx*b[0];
|
||||
float Txy = Ty*b[0];
|
||||
float Txz = Tz*b[0];
|
||||
float Tyy = Ty*b[1];
|
||||
float Tyz = Tz*b[1];
|
||||
float Tzz = Tz*b[2];
|
||||
|
||||
Vector3 Rows[3];
|
||||
Rows[0] = Vector3(1.0f-(Tyy+Tzz), Txy+Twz, Txz-Twy);
|
||||
Rows[1] = Vector3(Txy-Twz, 1.0f-(Txx+Tzz), Tyz+Twx);
|
||||
Rows[2] = Vector3(Txz+Twy, Tyz-Twx, 1.0f-(Txx+Tyy));
|
||||
|
||||
return Vector3(Rows[0].GetValue()*a[0] + Rows[1].GetValue()*a[1] + Rows[2].GetValue()*a[2]);
|
||||
}
|
||||
|
||||
protected:
|
||||
Vector4 m_Value;
|
||||
};
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// 3x3 Matrix class.
|
||||
|
||||
class Matrix33
|
||||
{
|
||||
public:
|
||||
// Constructors.
|
||||
inline Matrix33()
|
||||
{ }
|
||||
inline Matrix33(const Vector3& Row0, const Vector3& Row1, const Vector3& Row2)
|
||||
{ m_Rows[0] = Row0; m_Rows[1] = Row1; m_Rows[2] = Row2; }
|
||||
|
||||
inline void LoadIdentity()
|
||||
{
|
||||
m_Rows[0] = Vector3(1.0f, 0.0f, 0.0f);
|
||||
m_Rows[1] = Vector3(0.0f, 1.0f, 0.0f);
|
||||
m_Rows[2] = Vector3(0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
inline void CreateFromAxisAngle(const Vector3& Axis, const float Radians)
|
||||
{
|
||||
float s, c, mag, xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c;
|
||||
|
||||
s = sinf(Radians);
|
||||
c = cosf(Radians);
|
||||
mag = Axis.Length();
|
||||
|
||||
if (mag == 0.0f)
|
||||
{
|
||||
LoadIdentity();
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 Normal = Axis * (1.0f / mag);
|
||||
|
||||
xx = Normal[0] * Normal[0];
|
||||
yy = Normal[1] * Normal[1];
|
||||
zz = Normal[2] * Normal[2];
|
||||
xy = Normal[0] * Normal[1];
|
||||
yz = Normal[1] * Normal[2];
|
||||
zx = Normal[2] * Normal[0];
|
||||
xs = Normal[0] * s;
|
||||
ys = Normal[1] * s;
|
||||
zs = Normal[2] * s;
|
||||
one_c = 1.0f - c;
|
||||
|
||||
m_Rows[0] = Vector3((one_c * xx) + c, (one_c * xy) + zs, (one_c * zx) - ys);
|
||||
m_Rows[1] = Vector3((one_c * xy) - zs, (one_c * yy) + c, (one_c * yz) + xs);
|
||||
m_Rows[2] = Vector3((one_c * zx) + ys, (one_c * yz) - xs, (one_c * zz) + c);
|
||||
}
|
||||
|
||||
friend inline Vector3 Mul(const Vector3& a, const Matrix33& b)
|
||||
{ return Vector3(b.m_Rows[0]*a[0] + b.m_Rows[1]*a[1] + b.m_Rows[2]*a[2]); }
|
||||
|
||||
protected:
|
||||
Vector3 m_Rows[3];
|
||||
|
||||
friend class Matrix44;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 4x4 Matrix class.
|
||||
|
||||
class Matrix44
|
||||
{
|
||||
public:
|
||||
inline Matrix44()
|
||||
{ }
|
||||
inline Matrix44(const Vector4& Row0, const Vector4& Row1, const Vector4& Row2, const Vector4& Row3)
|
||||
{ m_Rows[0] = Row0; m_Rows[1] = Row1; m_Rows[2] = Row2; m_Rows[3] = Row3; }
|
||||
|
||||
inline operator const float*() const { return (const float*)this; }
|
||||
inline Vector4& operator[](int i) { return m_Rows[i]; }
|
||||
|
||||
inline void LoadIdentity()
|
||||
{
|
||||
m_Rows[0] = Vector4(1.0f, 0.0f, 0.0f, 0.0f);
|
||||
m_Rows[1] = Vector4(0.0f, 1.0f, 0.0f, 0.0f);
|
||||
m_Rows[2] = Vector4(0.0f, 0.0f, 1.0f, 0.0f);
|
||||
m_Rows[3] = Vector4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
// Math operations.
|
||||
friend inline Vector3 Mul31(const Vector3& a, const Matrix44& b)
|
||||
{ return Vector3(b.m_Rows[0]*a[0] + b.m_Rows[1]*a[1] + b.m_Rows[2]*a[2] + b.m_Rows[3]); }
|
||||
|
||||
friend inline Vector3 Mul30(const Vector3& a, const Matrix44& b)
|
||||
{ return Vector3(b.m_Rows[0]*a[0] + b.m_Rows[1]*a[1] + b.m_Rows[2]*a[2]); }
|
||||
|
||||
friend inline Vector4 Mul4(const Vector4& a, const Matrix44& b)
|
||||
{ return Vector4(b.m_Rows[0]*a[0] + b.m_Rows[1]*a[1] + b.m_Rows[2]*a[2] + b.m_Rows[3]*a[3]); }
|
||||
|
||||
friend inline Matrix44 Mul(const Matrix44& a, const Matrix44& b)
|
||||
{
|
||||
Vector4 Col0(b.m_Rows[0][0], b.m_Rows[1][0], b.m_Rows[2][0], b.m_Rows[3][0]);
|
||||
Vector4 Col1(b.m_Rows[0][1], b.m_Rows[1][1], b.m_Rows[2][1], b.m_Rows[3][1]);
|
||||
Vector4 Col2(b.m_Rows[0][2], b.m_Rows[1][2], b.m_Rows[2][2], b.m_Rows[3][2]);
|
||||
Vector4 Col3(b.m_Rows[0][3], b.m_Rows[1][3], b.m_Rows[2][3], b.m_Rows[3][3]);
|
||||
|
||||
Vector4 Ret0(Dot4(a.m_Rows[0], Col0), Dot4(a.m_Rows[0], Col1), Dot4(a.m_Rows[0], Col2), Dot4(a.m_Rows[0], Col3));
|
||||
Vector4 Ret1(Dot4(a.m_Rows[1], Col0), Dot4(a.m_Rows[1], Col1), Dot4(a.m_Rows[1], Col2), Dot4(a.m_Rows[1], Col3));
|
||||
Vector4 Ret2(Dot4(a.m_Rows[2], Col0), Dot4(a.m_Rows[2], Col1), Dot4(a.m_Rows[2], Col2), Dot4(a.m_Rows[2], Col3));
|
||||
Vector4 Ret3(Dot4(a.m_Rows[3], Col0), Dot4(a.m_Rows[3], Col1), Dot4(a.m_Rows[3], Col2), Dot4(a.m_Rows[3], Col3));
|
||||
|
||||
return Matrix44(Ret0, Ret1, Ret2, Ret3);
|
||||
}
|
||||
|
||||
inline Matrix44& operator=(const Matrix33& a)
|
||||
{
|
||||
m_Rows[0] = Vector4(a.m_Rows[0][0], a.m_Rows[0][1], a.m_Rows[0][2], 0.0f);
|
||||
m_Rows[1] = Vector4(a.m_Rows[1][0], a.m_Rows[1][1], a.m_Rows[1][2], 0.0f);
|
||||
m_Rows[2] = Vector4(a.m_Rows[2][0], a.m_Rows[2][1], a.m_Rows[2][2], 0.0f);
|
||||
m_Rows[3] = Vector4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void Transpose3()
|
||||
{
|
||||
Vector4 a = m_Rows[0], b = m_Rows[1], c = m_Rows[2];
|
||||
m_Rows[0] = Vector4(a[0], b[0], c[0], a[3]);
|
||||
m_Rows[1] = Vector4(a[1], b[1], c[1], b[3]);
|
||||
m_Rows[2] = Vector4(a[2], b[2], c[2], c[3]);
|
||||
}
|
||||
|
||||
inline void SetTranslation(const Vector3& a)
|
||||
{ m_Rows[3] = Vector4(a[0], a[1], a[2], 1.0f); }
|
||||
|
||||
friend Matrix44 Inverse(const Matrix44& m);
|
||||
void CreateLookAt(const Vector3& Eye, const Vector3& Target, const Vector3& Up);
|
||||
void CreatePerspective(float FoVy, float Aspect, float Near, float Far);
|
||||
|
||||
void CreateFromAxisAngle(const Vector3& Axis, float Radians)
|
||||
{
|
||||
Matrix33 Mat;
|
||||
Mat.CreateFromAxisAngle(Axis, Radians);
|
||||
*this = Mat;
|
||||
}
|
||||
|
||||
Vector4 ToAxisAngle()
|
||||
{
|
||||
Matrix33 tmp(Vector3(m_Rows[0]).Normalize(), Vector3(m_Rows[1]).Normalize(), Vector3(m_Rows[2]).Normalize());
|
||||
|
||||
// Determinant should be 1 for rotation matrices.
|
||||
float Determinant = tmp.m_Rows[0][0] * tmp.m_Rows[1][1] * tmp.m_Rows[2][2] + tmp.m_Rows[0][1] * tmp.m_Rows[1][2] * tmp.m_Rows[2][0] +
|
||||
tmp.m_Rows[0][2] * tmp.m_Rows[1][0] * tmp.m_Rows[2][1] - tmp.m_Rows[0][0] * tmp.m_Rows[1][2] * tmp.m_Rows[2][1] -
|
||||
tmp.m_Rows[0][1] * tmp.m_Rows[1][0] * tmp.m_Rows[2][2] - tmp.m_Rows[0][2] * tmp.m_Rows[1][1] * tmp.m_Rows[2][0];
|
||||
|
||||
if (Determinant < 0.0f)
|
||||
tmp.m_Rows[0] *= -1.0f;
|
||||
|
||||
float Trace = tmp.m_Rows[0][0] + tmp.m_Rows[1][1] + tmp.m_Rows[2][2];
|
||||
float Cos = 0.5f * (Trace - 1.0f);
|
||||
Vector4 rot;
|
||||
|
||||
if (Cos < -1.0f)
|
||||
Cos = -1.0f;
|
||||
else if (Cos > 1.0f)
|
||||
Cos = 1.0f;
|
||||
rot[3] = acosf(Cos); // in [0,PI]
|
||||
|
||||
if (rot[3] > 0.01f)
|
||||
{
|
||||
if (fabsf(3.141592f - rot[3]) > 0.01f)
|
||||
{
|
||||
rot[0] = tmp.m_Rows[1][2] - tmp.m_Rows[2][1];
|
||||
rot[1] = tmp.m_Rows[2][0] - tmp.m_Rows[0][2];
|
||||
rot[2] = tmp.m_Rows[0][1] - tmp.m_Rows[1][0];
|
||||
|
||||
float inv = 1.0f / sqrtf(rot[0]*rot[0] + rot[1]*rot[1] + rot[2]*rot[2]);
|
||||
|
||||
rot[0] *= inv;
|
||||
rot[1] *= inv;
|
||||
rot[2] *= inv;
|
||||
}
|
||||
else
|
||||
{
|
||||
// angle is PI
|
||||
float HalfInverse;
|
||||
if (tmp.m_Rows[0][0] >= tmp.m_Rows[1][1])
|
||||
{
|
||||
// r00 >= r11
|
||||
if (tmp.m_Rows[0][0] >= tmp.m_Rows[2][2])
|
||||
{
|
||||
// r00 is maximum diagonal term
|
||||
rot[0] = 0.5f * sqrtf(tmp.m_Rows[0][0] - tmp.m_Rows[1][1] - tmp.m_Rows[2][2] + 1.0f);
|
||||
HalfInverse = 0.5f / rot[0];
|
||||
rot[1] = HalfInverse * tmp.m_Rows[1][0];
|
||||
rot[2] = HalfInverse * tmp.m_Rows[2][0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// r22 is maximum diagonal term
|
||||
rot[2] = 0.5f * sqrtf(tmp.m_Rows[2][2] - tmp.m_Rows[0][0] - tmp.m_Rows[1][1] + 1.0f);
|
||||
HalfInverse = 0.5f / rot[2];
|
||||
rot[0] = HalfInverse * tmp.m_Rows[2][0];
|
||||
rot[1] = HalfInverse * tmp.m_Rows[2][1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// r11 > r00
|
||||
if (tmp.m_Rows[1][1] >= tmp.m_Rows[2][2])
|
||||
{
|
||||
// r11 is maximum diagonal term
|
||||
rot[1] = 0.5f * sqrtf(tmp.m_Rows[1][1] - tmp.m_Rows[0][0] - tmp.m_Rows[2][2] + 1.0f);
|
||||
HalfInverse = 0.5f / rot[1];
|
||||
rot[0] = HalfInverse * tmp.m_Rows[1][0];
|
||||
rot[2] = HalfInverse * tmp.m_Rows[2][1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// r22 is maximum diagonal term
|
||||
rot[2] = 0.5f * sqrtf(tmp.m_Rows[2][2] - tmp.m_Rows[0][0] - tmp.m_Rows[1][1] + 1.0f);
|
||||
HalfInverse = 0.5f / rot[2];
|
||||
rot[0] = HalfInverse * tmp.m_Rows[2][0];
|
||||
rot[1] = HalfInverse * tmp.m_Rows[2][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The angle is 0 and the matrix is the identity.
|
||||
rot[0] = 0.0f;
|
||||
rot[1] = 0.0f;
|
||||
rot[2] = 1.0f;
|
||||
}
|
||||
|
||||
return rot;
|
||||
}
|
||||
|
||||
protected:
|
||||
Vector4 m_Rows[4];
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Other Functions.
|
||||
|
||||
Vector3 ProjectPoint(const Vector3& Point, const Matrix44& ModelView, const Matrix44& Projection, const int Viewport[4]);
|
||||
void ProjectPoints(Vector3* Points, int NumPoints, const Matrix44& ModelView, const Matrix44& Projection, const int Viewport[4]);
|
||||
Vector3 UnprojectPoint(const Vector3& Point, const Matrix44& ModelView, const Matrix44& Projection, const int Viewport[4]);
|
||||
void UnprojectPoints(Vector3* Points, int NumPoints, const Matrix44& ModelView, const Matrix44& Projection, const int Viewport[4]);
|
||||
|
||||
void PolygonPlaneClip(Vector3* InPoints, int NumInPoints, Vector3* OutPoints, int* NumOutPoints, const Vector4& Plane);
|
||||
bool LinePlaneIntersection(Vector3& Intersection, const Vector3& Start, const Vector3& End, const Vector4& Plane);
|
||||
bool LineTriangleMinIntersection(const Vector3& p1, const Vector3& p2, const Vector3& p3, const Vector3& Start, const Vector3& End, float& MinDist, Vector3& Intersection);
|
||||
bool LineQuadMinIntersection(const Vector3& p1, const Vector3& p2, const Vector3& p3, const Vector3& p4, const Vector3& Start, const Vector3& End, float& MinDist, Vector3& Intersection);
|
||||
|
||||
#endif
|
341
common/array.cpp
Executable file
341
common/array.cpp
Executable file
|
@ -0,0 +1,341 @@
|
|||
//
|
||||
// Simple array classes
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
template <class T>
|
||||
PtrArray<T>::PtrArray(int nSize)
|
||||
{
|
||||
m_pData = NULL;
|
||||
m_nLength = 0;
|
||||
m_nAlloc = 0;
|
||||
|
||||
if(nSize != 0)
|
||||
Expand(nSize);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
PtrArray<T>::~PtrArray()
|
||||
{
|
||||
free(m_pData);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void PtrArray<T>::Expand(int nGrow)
|
||||
{
|
||||
if((m_nLength + nGrow) > m_nAlloc)
|
||||
{
|
||||
m_pData =(T**)realloc(m_pData,(m_nLength + nGrow) * sizeof(T*));
|
||||
memset(m_pData + m_nLength, 0, nGrow * sizeof(T*));
|
||||
m_nAlloc = m_nLength + nGrow;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void PtrArray<T>::RemoveAll()
|
||||
{
|
||||
m_nLength = 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T* PtrArray<T>::RemoveIndex(int nIndex)
|
||||
{
|
||||
T* ret = NULL;
|
||||
|
||||
if(nIndex < m_nLength)
|
||||
{
|
||||
ret = m_pData[nIndex];
|
||||
|
||||
if(nIndex != m_nLength - 1)
|
||||
memmove(m_pData + nIndex, m_pData + nIndex + 1, sizeof(T*) *(m_nLength - nIndex - 1));
|
||||
|
||||
m_nLength--;
|
||||
m_pData[m_nLength] = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T* PtrArray<T>::RemovePointer(T* pObj)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < m_nLength; i++)
|
||||
if(m_pData[i] == pObj)
|
||||
return RemoveIndex(i);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void PtrArray<T>::Add(T* pObj)
|
||||
{
|
||||
Expand(1);
|
||||
m_pData[m_nLength] = pObj;
|
||||
m_nLength++;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void PtrArray<T>::AddSorted(T* pObj, LC_PTRARRAY_COMPARE_FUNC pFunc, void* pData)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < GetSize(); i++)
|
||||
{
|
||||
if(pFunc(pObj, m_pData[i], pData) < 0)
|
||||
{
|
||||
InsertAt(i, pObj);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Add(pObj);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void PtrArray<T>::InsertAt(int nIndex, T* pObj)
|
||||
{
|
||||
if(nIndex >= m_nLength)
|
||||
Expand(nIndex - m_nLength + 1);
|
||||
else
|
||||
Expand(1);
|
||||
|
||||
m_nLength++;
|
||||
for(int i = m_nLength - 1; i > nIndex; i--)
|
||||
m_pData[i] = m_pData[i-1];
|
||||
|
||||
m_pData[nIndex] = pObj;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int PtrArray<T>::FindIndex(T* Obj) const
|
||||
{
|
||||
for (int i = 0; i < m_nLength; i++)
|
||||
if (m_pData[i] == Obj)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void PtrArray<T>::Sort(LC_PTRARRAY_COMPARE_FUNC SortFunc, void* SortData)
|
||||
{
|
||||
int Count = GetSize();
|
||||
|
||||
if (Count <= 1)
|
||||
return;
|
||||
|
||||
int i = 1;
|
||||
bool Flipped;
|
||||
|
||||
do
|
||||
{
|
||||
Flipped = false;
|
||||
|
||||
for (int j = Count - 1; j >= i; --j)
|
||||
{
|
||||
T* a = m_pData[j];
|
||||
T* b = m_pData[j-1];
|
||||
|
||||
if (SortFunc(b, a, SortData) > 0)
|
||||
{
|
||||
m_pData[j - 1] = a;
|
||||
m_pData[j] = b;
|
||||
Flipped = true;
|
||||
}
|
||||
}
|
||||
} while ((++i < Count) && Flipped);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
PtrArray<T>& PtrArray<T>::operator=(const PtrArray<T>& Array)
|
||||
{
|
||||
m_nLength = Array.m_nLength;
|
||||
m_nAlloc = Array.m_nAlloc;
|
||||
m_pData =(T**)realloc(m_pData, (m_nAlloc) * sizeof(T*));
|
||||
memcpy(m_pData, Array.m_pData, (m_nAlloc) * sizeof(T*));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
PtrArray<T>& PtrArray<T>::operator+=(const PtrArray<T>& Array)
|
||||
{
|
||||
Expand(Array.m_nLength);
|
||||
memcpy(m_pData + m_nLength, Array.m_pData, Array.m_nLength * sizeof(T*));
|
||||
m_nLength += Array.m_nLength;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
template <class T>
|
||||
ObjArray<T>::ObjArray(int Size, int Grow)
|
||||
{
|
||||
m_Data = NULL;
|
||||
m_Length = 0;
|
||||
m_Alloc = 0;
|
||||
m_Grow = Grow;
|
||||
|
||||
if (Size != 0)
|
||||
Expand(Size);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
ObjArray<T>::~ObjArray ()
|
||||
{
|
||||
delete[] m_Data;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ObjArray<T>::Expand(int Grow)
|
||||
{
|
||||
if ((m_Length + Grow) > m_Alloc)
|
||||
{
|
||||
int NewSize = ((m_Length + Grow) / m_Grow + 1) * m_Grow;
|
||||
|
||||
T* NewData = new T[NewSize];
|
||||
|
||||
for (int i = 0; i < m_Length; i++)
|
||||
NewData[i] = m_Data[i];
|
||||
|
||||
delete[] m_Data;
|
||||
m_Data = NewData;
|
||||
m_Alloc = NewSize;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ObjArray<T>::RemoveAll()
|
||||
{
|
||||
m_Length = 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ObjArray<T>::RemoveIndex(int Index)
|
||||
{
|
||||
m_Length--;
|
||||
|
||||
for (int i = Index; i < m_Length; i++)
|
||||
m_Data[i] = m_Data[i+1];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ObjArray<T>::Add(const T& Obj)
|
||||
{
|
||||
Expand(1);
|
||||
m_Data[m_Length++] = Obj;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ObjArray<T>::AddSorted (const T& Obj, LC_OBJARRAY_COMPARE_FUNC Func, void* SortData)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < GetSize(); i++)
|
||||
{
|
||||
if (Func(Obj, m_Data[i], SortData) < 0)
|
||||
{
|
||||
InsertAt (i, Obj);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Add(Obj);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ObjArray<T>::InsertAt(int Index, const T& Obj)
|
||||
{
|
||||
if (Index >= m_Length)
|
||||
Expand(Index - m_Length + 1);
|
||||
else
|
||||
Expand(1);
|
||||
|
||||
m_Length++;
|
||||
for (int i = m_Length - 1; i > Index; i--)
|
||||
m_Data[i] = m_Data[i-1];
|
||||
|
||||
m_Data[Index] = Obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
// ============================================================================
|
||||
// ObjectArray class
|
||||
|
||||
ObjectArray::ObjectArray (unsigned long nSize)
|
||||
{
|
||||
m_pData = NULL;
|
||||
m_nLength = 0;
|
||||
m_nAlloc = 0;
|
||||
|
||||
if (nSize != 0)
|
||||
Expand (nSize);
|
||||
}
|
||||
|
||||
ObjectArray::~ObjectArray ()
|
||||
{
|
||||
free (m_pData);
|
||||
}
|
||||
|
||||
void ObjectArray::Expand (unsigned long nGrow)
|
||||
{
|
||||
if ((m_nLength + nGrow) > m_nAlloc)
|
||||
{
|
||||
m_pData = (Object**)realloc (m_pData, (m_nLength + nGrow) * sizeof (Object*));
|
||||
memset (m_pData + m_nLength, 0, nGrow * sizeof (Object*));
|
||||
m_nAlloc = m_nLength + nGrow;
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectArray::SetSize (unsigned long nSize)
|
||||
{
|
||||
if (nSize > m_nLength)
|
||||
Expand (nSize - m_nLength);
|
||||
|
||||
m_nLength = nSize;
|
||||
}
|
||||
|
||||
Object* ObjectArray::RemoveIndex (unsigned long nIndex)
|
||||
{
|
||||
Object* ret = NULL;
|
||||
|
||||
if (nIndex < m_nLength)
|
||||
{
|
||||
ret = m_pData[nIndex];
|
||||
|
||||
if (nIndex != m_nLength - 1)
|
||||
memmove (m_pData + nIndex, m_pData + nIndex + 1,
|
||||
sizeof (Object*) * (m_nLength - nIndex - 1));
|
||||
|
||||
m_nLength--;
|
||||
m_pData[m_nLength] = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Object* ObjectArray::RemovePointer (Object* pObj)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < m_nLength; i++)
|
||||
if (m_pData[i] == pObj)
|
||||
return RemoveIndex (i);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ObjectArray::Add (Object* pObj)
|
||||
{
|
||||
Expand (1);
|
||||
m_pData[m_nLength++] = pObj;
|
||||
}
|
||||
*/
|
70
common/array.h
Executable file
70
common/array.h
Executable file
|
@ -0,0 +1,70 @@
|
|||
#ifndef _ARRAY_H_
|
||||
#define _ARRAY_H_
|
||||
|
||||
template <class T>
|
||||
class PtrArray
|
||||
{
|
||||
public:
|
||||
PtrArray(int nSize = 0);
|
||||
~PtrArray();
|
||||
|
||||
typedef int (*LC_PTRARRAY_COMPARE_FUNC)(const T* a, const T* b, void* data);
|
||||
|
||||
int GetSize() const
|
||||
{ return m_nLength; }
|
||||
|
||||
T* RemoveIndex(int nIndex);
|
||||
T* RemovePointer(T* pObj);
|
||||
void RemoveAll();
|
||||
void Add(T* pObj);
|
||||
void AddSorted(T* pObj, LC_PTRARRAY_COMPARE_FUNC pFunc, void* pData);
|
||||
void InsertAt(int nIndex, T* pObj);
|
||||
int FindIndex(T* Obj) const;
|
||||
void Sort(LC_PTRARRAY_COMPARE_FUNC SortFunc, void* SortData);
|
||||
|
||||
PtrArray<T>& operator=(const PtrArray<T>& Array);
|
||||
PtrArray<T>& operator+=(const PtrArray<T>& Array);
|
||||
T* operator [](int nIndex) const
|
||||
{ return m_pData[nIndex]; }
|
||||
|
||||
protected:
|
||||
void Expand(int nGrow);
|
||||
|
||||
T** m_pData;
|
||||
int m_nLength;
|
||||
int m_nAlloc;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ObjArray
|
||||
{
|
||||
public:
|
||||
ObjArray(int Size = 0, int Grow = 16);
|
||||
~ObjArray();
|
||||
|
||||
typedef int (*LC_OBJARRAY_COMPARE_FUNC)(const T& A, const T& B, void* SortData);
|
||||
|
||||
int GetSize() const
|
||||
{ return m_Length; }
|
||||
|
||||
void RemoveIndex(int Index);
|
||||
void RemoveAll();
|
||||
void Add(const T& Obj);
|
||||
void AddSorted(const T& Obj, LC_OBJARRAY_COMPARE_FUNC Func, void* SortData);
|
||||
void InsertAt(int Index, const T& Obj);
|
||||
|
||||
T& operator [](int Index) const
|
||||
{ return m_Data[Index]; }
|
||||
|
||||
protected:
|
||||
void Expand(int Grow);
|
||||
|
||||
T* m_Data;
|
||||
int m_Length;
|
||||
int m_Alloc;
|
||||
int m_Grow;
|
||||
};
|
||||
|
||||
#include "array.cpp"
|
||||
|
||||
#endif // _ARRAY_H_
|
102
common/basewnd.h
Normal file
102
common/basewnd.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
#ifndef _BASEWND_H_
|
||||
#define _BASEWND_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// FIXME: move this to another place
|
||||
#ifdef WIN32
|
||||
#include "stdafx.h"
|
||||
typedef CWnd* BaseWndXID;
|
||||
typedef struct
|
||||
{
|
||||
CWnd* wnd;
|
||||
int index;
|
||||
UINT command;
|
||||
} BaseMenuItem;
|
||||
#endif
|
||||
|
||||
#ifdef LC_LINUX
|
||||
#include <gtk/gtk.h>
|
||||
typedef GtkWidget* BaseWndXID;
|
||||
typedef struct
|
||||
{
|
||||
GtkWidget* widget;
|
||||
GtkAccelGroup* accel;
|
||||
} BaseMenuItem;
|
||||
#endif
|
||||
|
||||
#ifdef LC_MACOSX
|
||||
typedef void* BaseWndXID;
|
||||
typedef struct
|
||||
{
|
||||
void* Dummy;
|
||||
} BaseMenuItem;
|
||||
#endif
|
||||
|
||||
// =============================================================================
|
||||
// Message Box constants
|
||||
|
||||
#define LC_OK 1
|
||||
#define LC_CANCEL 2
|
||||
#define LC_ABORT 3
|
||||
#define LC_RETRY 4
|
||||
#define LC_IGNORE 5
|
||||
#define LC_YES 6
|
||||
#define LC_NO 7
|
||||
|
||||
#define LC_MB_OK 0x000
|
||||
#define LC_MB_OKCANCEL 0x001
|
||||
//#define LC_MB_ABORTRETRYIGNORE 0x002
|
||||
#define LC_MB_YESNOCANCEL 0x003
|
||||
#define LC_MB_YESNO 0x004
|
||||
//#define LC_MB_RETRYCANCEL 0x005
|
||||
|
||||
#define LC_MB_ICONERROR 0x010
|
||||
#define LC_MB_ICONQUESTION 0x020
|
||||
#define LC_MB_ICONWARNING 0x030
|
||||
#define LC_MB_ICONINFORMATION 0x040
|
||||
|
||||
#define LC_MB_TYPEMASK 0x00F
|
||||
#define LC_MB_ICONMASK 0x0F0
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class BaseWnd
|
||||
{
|
||||
public:
|
||||
BaseWnd (BaseWnd *parent, int menu_count);
|
||||
virtual ~BaseWnd ();
|
||||
|
||||
int MessageBox (const char* text, const char* caption="LeoCAD", int flags=LC_MB_OK|LC_MB_ICONINFORMATION);
|
||||
void BeginWait ();
|
||||
void EndWait ();
|
||||
void SetTitle (const char *title);
|
||||
|
||||
void ShowMenuItem (int id, bool show);
|
||||
void EnableMenuItem (int id, bool enable);
|
||||
void CheckMenuItem (int id, bool check);
|
||||
void SetMenuItemText (int id, const char *text);
|
||||
|
||||
BaseWndXID GetXID () const
|
||||
{ return m_pXID; }
|
||||
void SetXID (BaseWndXID id)
|
||||
{ m_pXID = id; }
|
||||
|
||||
#ifdef LC_LINUX
|
||||
// FIXME: remove
|
||||
operator GtkWidget* () const
|
||||
{ return m_pXID; }
|
||||
#endif
|
||||
|
||||
BaseMenuItem* GetMenuItem (int id) const
|
||||
{ return &m_pMenuItems[id]; }
|
||||
void SetMenuItem (int id, BaseMenuItem* item)
|
||||
{ memcpy (&m_pMenuItems[id], item, sizeof (BaseMenuItem)); }
|
||||
|
||||
protected:
|
||||
BaseWnd* m_pParent;
|
||||
BaseWndXID m_pXID;
|
||||
BaseMenuItem* m_pMenuItems;
|
||||
};
|
||||
|
||||
#endif // _BASEWND_H_
|
852
common/camera.cpp
Normal file
852
common/camera.cpp
Normal file
|
@ -0,0 +1,852 @@
|
|||
// Camera object.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "opengl.h"
|
||||
#include "globals.h"
|
||||
#include "defines.h"
|
||||
#include "vector.h"
|
||||
#include "matrix.h"
|
||||
#include "file.h"
|
||||
#include "camera.h"
|
||||
#include "tr.h"
|
||||
|
||||
#define LC_CAMERA_SAVE_VERSION 6 // LeoCAD 0.73
|
||||
|
||||
GLuint Camera::m_nTargetList = 0;
|
||||
|
||||
static LC_OBJECT_KEY_INFO camera_key_info[LC_CK_COUNT] =
|
||||
{
|
||||
{ "Camera Position", 3, LC_CK_EYE },
|
||||
{ "Camera Target", 3, LC_CK_TARGET },
|
||||
{ "Camera Up Vector", 3, LC_CK_UP }
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// CameraTarget class
|
||||
|
||||
CameraTarget::CameraTarget (Camera *pParent)
|
||||
: Object (LC_OBJECT_CAMERA_TARGET)
|
||||
{
|
||||
m_pParent = pParent;
|
||||
/*
|
||||
strcpy (m_strName, pParent->GetName ());
|
||||
m_strName[LC_OBJECT_NAME_LEN-8] = '\0';
|
||||
strcat (m_strName, ".Target");
|
||||
*/
|
||||
}
|
||||
|
||||
CameraTarget::~CameraTarget ()
|
||||
{
|
||||
}
|
||||
|
||||
void CameraTarget::MinIntersectDist (LC_CLICKLINE* pLine)
|
||||
{
|
||||
float dist = (float)BoundingBoxIntersectDist (pLine);
|
||||
|
||||
if (dist < pLine->mindist)
|
||||
{
|
||||
pLine->mindist = dist;
|
||||
pLine->pClosest = this;
|
||||
}
|
||||
}
|
||||
|
||||
void CameraTarget::Select (bool bSelecting, bool bFocus, bool bMultiple)
|
||||
{
|
||||
m_pParent->SelectTarget (bSelecting, bFocus, bMultiple);
|
||||
}
|
||||
|
||||
const char* CameraTarget::GetName() const
|
||||
{
|
||||
return m_pParent->GetName();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Camera construction/destruction
|
||||
|
||||
Camera::Camera ()
|
||||
: Object (LC_OBJECT_CAMERA)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
// Start with a standard camera.
|
||||
Camera::Camera (unsigned char nType, Camera* pPrev)
|
||||
: Object (LC_OBJECT_CAMERA)
|
||||
{
|
||||
if (nType > 7)
|
||||
nType = 8;
|
||||
|
||||
char names[8][7] = { "Front", "Back", "Top", "Under", "Left", "Right", "Main", "User" };
|
||||
float eyes[8][3] = { { 50,0,0 }, { -50,0,0 }, { 0,0,50 }, { 0,0,-50 },
|
||||
{ 0,50,0 }, { 0,-50,0 }, { -10,-10,5}, { 0,5,0 } };
|
||||
float ups [8][3] = { { 0,0,1 }, { 0,0,1 }, { 1,0,0 }, { -1,0,0 }, { 0,0,1 },
|
||||
{ 0,0,1 }, {-0.2357f, -0.2357f, 0.94281f }, { 0,0,1 } };
|
||||
|
||||
Initialize();
|
||||
|
||||
ChangeKey (1, false, true, eyes[nType], LC_CK_EYE);
|
||||
ChangeKey (1, false, true, ups[nType], LC_CK_UP);
|
||||
ChangeKey (1, true, true, eyes[nType], LC_CK_EYE);
|
||||
ChangeKey (1, true, true, ups[nType], LC_CK_UP);
|
||||
|
||||
strcpy (m_strName, names[nType]);
|
||||
if (nType != 8)
|
||||
m_nState = LC_CAMERA_HIDDEN;
|
||||
m_nType = nType;
|
||||
|
||||
if (pPrev)
|
||||
pPrev->m_pNext = this;
|
||||
|
||||
UpdatePosition(1, false);
|
||||
}
|
||||
|
||||
// From OnMouseMove(), case LC_ACTION_ROTATE_VIEW
|
||||
Camera::Camera (const float *eye, const float *target, const float *up, Camera* pCamera)
|
||||
: Object (LC_OBJECT_CAMERA)
|
||||
{
|
||||
// Fix the up vector
|
||||
Vector upvec(up), frontvec(eye[0]-target[0], eye[1]-target[1], eye[2]-target[2]), sidevec;
|
||||
frontvec.Normalize();
|
||||
sidevec.Cross(frontvec, upvec);
|
||||
upvec.Cross(sidevec, frontvec);
|
||||
upvec.Normalize();
|
||||
|
||||
Initialize();
|
||||
|
||||
ChangeKey (1, false, true, eye, LC_CK_EYE);
|
||||
ChangeKey (1, false, true, target, LC_CK_TARGET);
|
||||
ChangeKey (1, false, true, upvec, LC_CK_UP);
|
||||
ChangeKey (1, true, true, eye, LC_CK_EYE);
|
||||
ChangeKey (1, true, true, target, LC_CK_TARGET);
|
||||
ChangeKey (1, true, true, upvec, LC_CK_UP);
|
||||
|
||||
int i, max = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (strncmp (pCamera->m_strName, "Camera ", 7) == 0)
|
||||
if (sscanf(pCamera->m_strName, "Camera %d", &i) == 1)
|
||||
if (i > max)
|
||||
max = i;
|
||||
|
||||
if (pCamera->m_pNext == NULL)
|
||||
{
|
||||
sprintf(m_strName, "Camera %d", max+1);
|
||||
pCamera->m_pNext = this;
|
||||
break;
|
||||
}
|
||||
else
|
||||
pCamera = pCamera->m_pNext;
|
||||
}
|
||||
|
||||
UpdatePosition (1, false);
|
||||
}
|
||||
|
||||
// From LC_ACTION_CAMERA
|
||||
Camera::Camera (float ex, float ey, float ez, float tx, float ty, float tz, Camera* pCamera)
|
||||
: Object (LC_OBJECT_CAMERA)
|
||||
{
|
||||
// Fix the up vector
|
||||
Vector upvec(0,0,1), frontvec(ex-tx, ey-ty, ez-tz), sidevec;
|
||||
frontvec.Normalize();
|
||||
if (frontvec == upvec)
|
||||
sidevec = Vector(1,0,0);
|
||||
else
|
||||
sidevec.Cross(frontvec, upvec);
|
||||
upvec.Cross(sidevec, frontvec);
|
||||
upvec.Normalize();
|
||||
|
||||
Initialize();
|
||||
|
||||
float eye[3] = { ex, ey, ez }, target[3] = { tx, ty, tz };
|
||||
|
||||
ChangeKey (1, false, true, eye, LC_CK_EYE);
|
||||
ChangeKey (1, false, true, target, LC_CK_TARGET);
|
||||
ChangeKey (1, false, true, upvec, LC_CK_UP);
|
||||
ChangeKey (1, true, true, eye, LC_CK_EYE);
|
||||
ChangeKey (1, true, true, target, LC_CK_TARGET);
|
||||
ChangeKey (1, true, true, upvec, LC_CK_UP);
|
||||
|
||||
int i, max = 0;
|
||||
|
||||
if (pCamera)
|
||||
for (;;)
|
||||
{
|
||||
if (strncmp (pCamera->m_strName, "Camera ", 7) == 0)
|
||||
if (sscanf(pCamera->m_strName, "Camera %d", &i) == 1)
|
||||
if (i > max)
|
||||
max = i;
|
||||
|
||||
if (pCamera->m_pNext == NULL)
|
||||
{
|
||||
sprintf(m_strName, "Camera %d", max+1);
|
||||
pCamera->m_pNext = this;
|
||||
break;
|
||||
}
|
||||
else
|
||||
pCamera = pCamera->m_pNext;
|
||||
}
|
||||
|
||||
UpdatePosition (1, false);
|
||||
}
|
||||
|
||||
Camera::~Camera()
|
||||
{
|
||||
if (m_nList != 0)
|
||||
glDeleteLists (m_nList, 1);
|
||||
|
||||
delete m_pTarget;
|
||||
}
|
||||
|
||||
void Camera::Initialize()
|
||||
{
|
||||
m_fovy = 30;
|
||||
m_zNear = 1;
|
||||
m_zFar = 500;
|
||||
|
||||
m_pNext = NULL;
|
||||
m_nState = 0;
|
||||
m_nList = 0;
|
||||
m_nType = LC_CAMERA_USER;
|
||||
m_nList = 0;
|
||||
|
||||
m_pTR = NULL;
|
||||
for (unsigned char i = 0 ; i < sizeof(m_strName) ; i++ )
|
||||
m_strName[i] = 0;
|
||||
|
||||
float *values[] = { m_fEye, m_fTarget, m_fUp };
|
||||
RegisterKeys (values, camera_key_info, LC_CK_COUNT);
|
||||
|
||||
m_pTarget = new CameraTarget (this);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Camera save/load
|
||||
|
||||
bool Camera::FileLoad (File& file)
|
||||
{
|
||||
unsigned char version, ch;
|
||||
|
||||
file.ReadByte (&version, 1);
|
||||
|
||||
if (version > LC_CAMERA_SAVE_VERSION)
|
||||
return false;
|
||||
|
||||
if (version > 5)
|
||||
if (!Object::FileLoad (file))
|
||||
return false;
|
||||
|
||||
if (version == 4)
|
||||
{
|
||||
file.Read(m_strName, 80);
|
||||
m_strName[80] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
file.Read(&ch, 1);
|
||||
if (ch == 0xFF)
|
||||
return false; // don't read CString
|
||||
file.Read(m_strName, ch);
|
||||
m_strName[ch] = 0;
|
||||
}
|
||||
|
||||
if (version < 3)
|
||||
{
|
||||
double d[3];
|
||||
float f[3];
|
||||
|
||||
file.ReadDouble (d, 3);
|
||||
f[0] = (float)d[0];
|
||||
f[1] = (float)d[1];
|
||||
f[2] = (float)d[2];
|
||||
ChangeKey (1, false, true, f, LC_CK_EYE);
|
||||
ChangeKey (1, true, true, f, LC_CK_EYE);
|
||||
|
||||
file.ReadDouble (d, 3);
|
||||
f[0] = (float)d[0];
|
||||
f[1] = (float)d[1];
|
||||
f[2] = (float)d[2];
|
||||
ChangeKey (1, false, true, f, LC_CK_TARGET);
|
||||
ChangeKey (1, true, true, f, LC_CK_TARGET);
|
||||
|
||||
file.ReadDouble (d, 3);
|
||||
f[0] = (float)d[0];
|
||||
f[1] = (float)d[1];
|
||||
f[2] = (float)d[2];
|
||||
ChangeKey (1, false, true, f, LC_CK_UP);
|
||||
ChangeKey (1, true, true, f, LC_CK_UP);
|
||||
}
|
||||
|
||||
if (version == 3)
|
||||
{
|
||||
file.Read(&ch, 1);
|
||||
|
||||
while (ch--)
|
||||
{
|
||||
unsigned char step;
|
||||
double eye[3], target[3], up[3];
|
||||
float f[3];
|
||||
|
||||
file.ReadDouble (eye, 3);
|
||||
file.ReadDouble (target, 3);
|
||||
file.ReadDouble (up, 3);
|
||||
file.ReadByte (&step, 1);
|
||||
|
||||
if (up[0] == 0 && up[1] == 0 && up[2] == 0)
|
||||
up[2] = 1;
|
||||
|
||||
f[0] = (float)eye[0];
|
||||
f[1] = (float)eye[1];
|
||||
f[2] = (float)eye[2];
|
||||
ChangeKey (step, false, true, f, LC_CK_EYE);
|
||||
ChangeKey (step, true, true, f, LC_CK_EYE);
|
||||
|
||||
f[0] = (float)target[0];
|
||||
f[1] = (float)target[1];
|
||||
f[2] = (float)target[2];
|
||||
ChangeKey (step, false, true, f, LC_CK_TARGET);
|
||||
ChangeKey (step, true, true, f, LC_CK_TARGET);
|
||||
|
||||
f[0] = (float)up[0];
|
||||
f[1] = (float)up[1];
|
||||
f[2] = (float)up[2];
|
||||
ChangeKey (step, false, true, f, LC_CK_UP);
|
||||
ChangeKey (step, true, true, f, LC_CK_UP);
|
||||
|
||||
int snapshot; // BOOL under Windows
|
||||
int cam;
|
||||
file.ReadLong (&snapshot, 1);
|
||||
file.ReadLong (&cam, 1);
|
||||
// if (cam == -1)
|
||||
// node->pCam = NULL;
|
||||
// else
|
||||
// node->pCam = pDoc->GetCamera(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (version < 4)
|
||||
{
|
||||
double d;
|
||||
file.ReadDouble (&d, 1); m_fovy = (float)d;
|
||||
file.ReadDouble (&d, 1); m_zFar = (float)d;
|
||||
file.ReadDouble (&d, 1); m_zNear= (float)d;
|
||||
}
|
||||
else
|
||||
{
|
||||
int n;
|
||||
|
||||
if (version < 6)
|
||||
{
|
||||
unsigned short time;
|
||||
float param[4];
|
||||
unsigned char type;
|
||||
|
||||
file.ReadLong (&n, 1);
|
||||
while (n--)
|
||||
{
|
||||
file.ReadShort (&time, 1);
|
||||
file.ReadFloat (param, 3);
|
||||
file.ReadByte (&type, 1);
|
||||
|
||||
ChangeKey (time, false, true, param, type);
|
||||
}
|
||||
|
||||
file.ReadLong (&n, 1);
|
||||
while (n--)
|
||||
{
|
||||
file.ReadShort (&time, 1);
|
||||
file.ReadFloat (param, 3);
|
||||
file.ReadByte (&type, 1);
|
||||
|
||||
ChangeKey (time, true, true, param, type);
|
||||
}
|
||||
}
|
||||
|
||||
file.ReadFloat (&m_fovy, 1);
|
||||
file.ReadFloat (&m_zFar, 1);
|
||||
file.ReadFloat (&m_zNear, 1);
|
||||
|
||||
if (version < 5)
|
||||
{
|
||||
file.ReadLong (&n, 1);
|
||||
if (n != 0)
|
||||
m_nState |= LC_CAMERA_HIDDEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
file.ReadByte (&m_nState, 1);
|
||||
file.ReadByte (&m_nType, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if ((version > 1) && (version < 4))
|
||||
{
|
||||
unsigned long show;
|
||||
int user;
|
||||
|
||||
file.ReadLong (&show, 1);
|
||||
// if (version > 2)
|
||||
file.ReadLong (&user, 1);
|
||||
if (show == 0)
|
||||
m_nState |= LC_CAMERA_HIDDEN;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Camera::FileSave (File& file) const
|
||||
{
|
||||
unsigned char ch = LC_CAMERA_SAVE_VERSION;
|
||||
|
||||
file.WriteByte (&ch, 1);
|
||||
|
||||
Object::FileSave (file);
|
||||
|
||||
ch = (unsigned char)strlen(m_strName);
|
||||
file.Write (&ch, 1);
|
||||
file.Write (m_strName, ch);
|
||||
|
||||
file.WriteFloat (&m_fovy, 1);
|
||||
file.WriteFloat (&m_zFar, 1);
|
||||
file.WriteFloat (&m_zNear, 1);
|
||||
// version 5
|
||||
file.WriteByte (&m_nState, 1);
|
||||
file.WriteByte (&m_nType, 1);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Camera operations
|
||||
|
||||
void Camera::Move (unsigned short nTime, bool bAnimation, bool bAddKey, float dx, float dy, float dz)
|
||||
{
|
||||
if (IsSide())
|
||||
{
|
||||
m_fEye[0] += dx;
|
||||
m_fEye[1] += dy;
|
||||
m_fEye[2] += dz;
|
||||
m_fTarget[0] += dx;
|
||||
m_fTarget[1] += dy;
|
||||
m_fTarget[2] += dz;
|
||||
|
||||
ChangeKey(nTime, bAnimation, bAddKey, m_fEye, LC_CK_EYE);
|
||||
ChangeKey(nTime, bAnimation, bAddKey, m_fTarget, LC_CK_TARGET);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsEyeSelected())
|
||||
{
|
||||
m_fEye[0] += dx;
|
||||
m_fEye[1] += dy;
|
||||
m_fEye[2] += dz;
|
||||
|
||||
ChangeKey(nTime, bAnimation, bAddKey, m_fEye, LC_CK_EYE);
|
||||
}
|
||||
|
||||
if (IsTargetSelected())
|
||||
{
|
||||
m_fTarget[0] += dx;
|
||||
m_fTarget[1] += dy;
|
||||
m_fTarget[2] += dz;
|
||||
|
||||
ChangeKey(nTime, bAnimation, bAddKey, m_fTarget, LC_CK_TARGET);
|
||||
}
|
||||
|
||||
// Fix the up vector
|
||||
Vector upvec(m_fUp), sidevec;
|
||||
Vector frontvec(m_fTarget[0]-m_fEye[0], m_fTarget[1]-m_fEye[1], m_fTarget[2]-m_fEye[2]);
|
||||
sidevec.Cross(frontvec, upvec);
|
||||
upvec.Cross(sidevec, frontvec);
|
||||
upvec.Normalize();
|
||||
upvec.ToFloat(m_fUp);
|
||||
|
||||
ChangeKey(nTime, bAnimation, bAddKey, m_fUp, LC_CK_UP);
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::Select (bool bSelecting, bool bFocus, bool bMultiple)
|
||||
{
|
||||
if (bSelecting == true)
|
||||
{
|
||||
if (bFocus == true)
|
||||
{
|
||||
m_nState |= (LC_CAMERA_FOCUSED|LC_CAMERA_SELECTED);
|
||||
|
||||
m_pTarget->Select (false, true, bMultiple);
|
||||
}
|
||||
else
|
||||
m_nState |= LC_CAMERA_SELECTED;
|
||||
|
||||
if (bMultiple == false)
|
||||
m_pTarget->Select (false, false, bMultiple);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bFocus == true)
|
||||
m_nState &= ~(LC_CAMERA_FOCUSED);
|
||||
else
|
||||
m_nState &= ~(LC_CAMERA_SELECTED|LC_CAMERA_FOCUSED);
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::SelectTarget (bool bSelecting, bool bFocus, bool bMultiple)
|
||||
{
|
||||
// FIXME: the target should handle this
|
||||
|
||||
if (bSelecting == true)
|
||||
{
|
||||
if (bFocus == true)
|
||||
{
|
||||
m_nState |= (LC_CAMERA_TARGET_FOCUSED|LC_CAMERA_TARGET_SELECTED);
|
||||
|
||||
Select (false, true, bMultiple);
|
||||
}
|
||||
else
|
||||
m_nState |= LC_CAMERA_TARGET_SELECTED;
|
||||
|
||||
if (bMultiple == false)
|
||||
Select (false, false, bMultiple);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bFocus == true)
|
||||
m_nState &= ~(LC_CAMERA_TARGET_FOCUSED);
|
||||
else
|
||||
m_nState &= ~(LC_CAMERA_TARGET_SELECTED|LC_CAMERA_TARGET_FOCUSED);
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::UpdatePosition(unsigned short nTime, bool bAnimation)
|
||||
{
|
||||
CalculateKeys(nTime, bAnimation);
|
||||
|
||||
UpdateBoundingBox();
|
||||
}
|
||||
|
||||
void Camera::UpdateBoundingBox()
|
||||
{
|
||||
// Fix the up vector
|
||||
Vector frontvec(m_fEye[0]-m_fTarget[0], m_fEye[1]-m_fTarget[1], m_fEye[2]-m_fTarget[2]);
|
||||
Vector upvec(m_fUp), sidevec;
|
||||
|
||||
sidevec.Cross(frontvec, upvec);
|
||||
upvec.Cross(sidevec, frontvec);
|
||||
upvec.Normalize();
|
||||
upvec.ToFloat(m_fUp);
|
||||
|
||||
float len = frontvec.Length();
|
||||
|
||||
Matrix mat;
|
||||
mat.CreateLookat (m_fEye, m_fTarget, m_fUp);
|
||||
mat.Invert ();
|
||||
|
||||
mat.SetTranslation (m_fEye[0], m_fEye[1], m_fEye[2]);
|
||||
BoundingBoxCalculate (&mat);
|
||||
mat.SetTranslation (m_fTarget[0], m_fTarget[1], m_fTarget[2]);
|
||||
m_pTarget->BoundingBoxCalculate (&mat);
|
||||
mat.SetTranslation (0, 0, 0);
|
||||
|
||||
if (!m_nList)
|
||||
return;
|
||||
|
||||
glNewList(m_nList, GL_COMPILE);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(m_fEye[0], m_fEye[1], m_fEye[2]);
|
||||
glMultMatrixf(mat.m);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
float verts[34][3] = {
|
||||
{ 0.3f, 0.3f, 0.3f }, { -0.3f, 0.3f, 0.3f },
|
||||
{ -0.3f, 0.3f, 0.3f }, { -0.3f, -0.3f, 0.3f },
|
||||
{ -0.3f, -0.3f, 0.3f }, { 0.3f, -0.3f, 0.3f },
|
||||
{ 0.3f, -0.3f, 0.3f }, { 0.3f, 0.3f, 0.3f },
|
||||
{ 0.3f, 0.3f, -0.3f }, { -0.3f, 0.3f, -0.3f },
|
||||
{ -0.3f, 0.3f, -0.3f }, { -0.3f, -0.3f, -0.3f },
|
||||
{ -0.3f, -0.3f, -0.3f }, { 0.3f, -0.3f, -0.3f },
|
||||
{ 0.3f, -0.3f, -0.3f }, { 0.3f, 0.3f, -0.3f },
|
||||
{ 0.3f, 0.3f, 0.3f }, { 0.3f, 0.3f, -0.3f },
|
||||
{ -0.3f, 0.3f, 0.3f }, { -0.3f, 0.3f, -0.3f },
|
||||
{ -0.3f, -0.3f, 0.3f }, { -0.3f, -0.3f, -0.3f },
|
||||
{ 0.3f, -0.3f, 0.3f }, { 0.3f, -0.3f, -0.3f },
|
||||
{ -0.3f, -0.3f, -0.6f }, { -0.3f, 0.3f, -0.6f },
|
||||
{ 0.0f, 0.0f, -0.3f }, { -0.3f, -0.3f, -0.6f },
|
||||
{ 0.3f, -0.3f, -0.6f }, { 0.0f, 0.0f, -0.3f },
|
||||
{ 0.3f, 0.3f, -0.6f }, { 0.3f, -0.3f, -0.6f },
|
||||
{ 0.3f, 0.3f, -0.6f }, { -0.3f, 0.3f, -0.6f } };
|
||||
glVertexPointer (3, GL_FLOAT, 0, verts);
|
||||
glDrawArrays(GL_LINES, 0, 24);
|
||||
glDrawArrays(GL_LINE_STRIP, 24, 10);
|
||||
|
||||
// glBegin(GL_LINES);
|
||||
// glVertex3f(0,0,0);
|
||||
// glVertex3f(0,0,len);
|
||||
// glEnd();
|
||||
|
||||
glTranslatef(0, 0, -len);
|
||||
|
||||
glEndList();
|
||||
|
||||
if (m_nTargetList == 0)
|
||||
{
|
||||
m_nTargetList = glGenLists(1);
|
||||
glNewList (m_nTargetList, GL_COMPILE);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
float box[24][3] = {
|
||||
{ 0.2f, 0.2f, 0.2f }, { -0.2f, 0.2f, 0.2f },
|
||||
{ -0.2f, 0.2f, 0.2f }, { -0.2f, -0.2f, 0.2f },
|
||||
{ -0.2f, -0.2f, 0.2f }, { 0.2f, -0.2f, 0.2f },
|
||||
{ 0.2f, -0.2f, 0.2f }, { 0.2f, 0.2f, 0.2f },
|
||||
{ 0.2f, 0.2f, -0.2f }, { -0.2f, 0.2f, -0.2f },
|
||||
{ -0.2f, 0.2f, -0.2f }, { -0.2f, -0.2f, -0.2f },
|
||||
{ -0.2f, -0.2f, -0.2f }, { 0.2f, -0.2f, -0.2f },
|
||||
{ 0.2f, -0.2f, -0.2f }, { 0.2f, 0.2f, -0.2f },
|
||||
{ 0.2f, 0.2f, 0.2f }, { 0.2f, 0.2f, -0.2f },
|
||||
{ -0.2f, 0.2f, 0.2f }, { -0.2f, 0.2f, -0.2f },
|
||||
{ -0.2f, -0.2f, 0.2f }, { -0.2f, -0.2f, -0.2f },
|
||||
{ 0.2f, -0.2f, 0.2f }, { 0.2f, -0.2f, -0.2f } };
|
||||
glVertexPointer (3, GL_FLOAT, 0, box);
|
||||
glDrawArrays(GL_LINES, 0, 24);
|
||||
glPopMatrix();
|
||||
glEndList();
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::Render(float fLineWidth)
|
||||
{
|
||||
// Create the display lists if this is the first time we're rendered.
|
||||
if (!m_nList)
|
||||
{
|
||||
m_nList = glGenLists(1);
|
||||
UpdateBoundingBox();
|
||||
}
|
||||
|
||||
if (IsEyeSelected())
|
||||
{
|
||||
glLineWidth(fLineWidth*2);
|
||||
glColor3ubv(FlatColorArray[(m_nState & LC_CAMERA_FOCUSED) != 0 ? LC_COL_FOCUSED : LC_COL_SELECTED]);
|
||||
glCallList(m_nList);
|
||||
glLineWidth(fLineWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
glColor3f(0.5f, 0.8f, 0.5f);
|
||||
glCallList(m_nList);
|
||||
}
|
||||
|
||||
if (IsTargetSelected())
|
||||
{
|
||||
glLineWidth(fLineWidth*2);
|
||||
glColor3ubv(FlatColorArray[(m_nState & LC_CAMERA_TARGET_FOCUSED) != 0 ? LC_COL_FOCUSED : LC_COL_SELECTED]);
|
||||
glCallList(m_nTargetList);
|
||||
glLineWidth(fLineWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
glColor3f(0.5f, 0.8f, 0.5f);
|
||||
glCallList(m_nTargetList);
|
||||
}
|
||||
|
||||
glColor3f(0.5f, 0.8f, 0.5f);
|
||||
glBegin(GL_LINES);
|
||||
glVertex3fv(m_fEye);
|
||||
glVertex3fv(m_fTarget);
|
||||
glEnd();
|
||||
|
||||
if (IsSelected())
|
||||
{
|
||||
Matrix projection, modelview;
|
||||
Vector frontvec(m_fTarget[0]-m_fEye[0], m_fTarget[1]-m_fEye[1], m_fTarget[2]-m_fEye[2]);
|
||||
float len = frontvec.Length();
|
||||
|
||||
glPushMatrix ();
|
||||
|
||||
modelview.CreateLookat (m_fEye, m_fTarget, m_fUp);
|
||||
modelview.Invert ();
|
||||
glMultMatrixf (modelview.m);
|
||||
|
||||
projection.CreatePerspective (m_fovy, 1.33f, 0.01f, len);
|
||||
projection.Invert ();
|
||||
glMultMatrixf (projection.m);
|
||||
|
||||
// draw the viewing frustum
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex3i(1, 1, 1);
|
||||
glVertex3i(-1, 1, 1);
|
||||
glVertex3i(-1, -1, 1);
|
||||
glVertex3i(1, -1, 1);
|
||||
glEnd();
|
||||
|
||||
glBegin(GL_LINES);
|
||||
glVertex3i(1, 1, -1);
|
||||
glVertex3i(1, 1, 1);
|
||||
glVertex3i(-1, 1, -1);
|
||||
glVertex3i(-1, 1, 1);
|
||||
glVertex3i(-1, -1, -1);
|
||||
glVertex3i(-1, -1, 1);
|
||||
glVertex3i(1, -1, -1);
|
||||
glVertex3i(1, -1, 1);
|
||||
glEnd();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::MinIntersectDist(LC_CLICKLINE* pLine)
|
||||
{
|
||||
float dist;
|
||||
|
||||
if (m_nState & LC_CAMERA_HIDDEN)
|
||||
return;
|
||||
|
||||
dist = (float)BoundingBoxIntersectDist (pLine);
|
||||
if (dist < pLine->mindist)
|
||||
{
|
||||
pLine->mindist = dist;
|
||||
pLine->pClosest = this;
|
||||
}
|
||||
|
||||
m_pTarget->MinIntersectDist (pLine);
|
||||
}
|
||||
|
||||
void Camera::LoadProjection(float fAspect)
|
||||
{
|
||||
if (m_pTR != NULL)
|
||||
m_pTR->BeginTile();
|
||||
else
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(m_fovy, fAspect, m_zNear, m_zFar);
|
||||
/*
|
||||
ymax = 10;//(m_zFar-m_zNear)*tan(DTOR*m_fovy)/3;
|
||||
ymin = -ymax;
|
||||
xmin = ymin * fAspect;
|
||||
xmax = ymax * fAspect;
|
||||
znear = -60;
|
||||
zfar = 60;
|
||||
glOrtho(xmin, xmax, ymin, ymax, znear, zfar);
|
||||
*/
|
||||
}
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
gluLookAt(m_fEye[0], m_fEye[1], m_fEye[2], m_fTarget[0], m_fTarget[1], m_fTarget[2], m_fUp[0], m_fUp[1], m_fUp[2]);
|
||||
}
|
||||
|
||||
void Camera::DoZoom(int dy, int mouse, unsigned short nTime, bool bAnimation, bool bAddKey)
|
||||
{
|
||||
Vector frontvec(m_fEye[0]-m_fTarget[0], m_fEye[1]-m_fTarget[1], m_fEye[2]-m_fTarget[2]);
|
||||
frontvec.Normalize();
|
||||
frontvec *= 2.0f*dy/(21-mouse);
|
||||
|
||||
// TODO: option to move eye, target or both
|
||||
m_fEye[0] += frontvec[0];
|
||||
m_fEye[1] += frontvec[1];
|
||||
m_fEye[2] += frontvec[2];
|
||||
m_fTarget[0] += frontvec[0];
|
||||
m_fTarget[1] += frontvec[1];
|
||||
m_fTarget[2] += frontvec[2];
|
||||
|
||||
ChangeKey(nTime, bAnimation, bAddKey, m_fEye, LC_CK_EYE);
|
||||
ChangeKey(nTime, bAnimation, bAddKey, m_fTarget, LC_CK_TARGET);
|
||||
UpdatePosition(nTime, bAnimation);
|
||||
}
|
||||
|
||||
void Camera::DoPan(int dx, int dy, int mouse, unsigned short nTime, bool bAnimation, bool bAddKey)
|
||||
{
|
||||
Vector upvec(m_fUp), frontvec(m_fEye[0]-m_fTarget[0], m_fEye[1]-m_fTarget[1], m_fEye[2]-m_fTarget[2]), sidevec;
|
||||
sidevec.Cross(frontvec, upvec);
|
||||
sidevec.Normalize();
|
||||
sidevec *= 2.0f*dx/(21-mouse);
|
||||
upvec.Normalize();
|
||||
upvec *= -2.0f*dy/(21-mouse);
|
||||
|
||||
m_fEye[0] += upvec[0] + sidevec[0];
|
||||
m_fEye[1] += upvec[1] + sidevec[1];
|
||||
m_fEye[2] += upvec[2] + sidevec[2];
|
||||
m_fTarget[0] += upvec[0] + sidevec[0];
|
||||
m_fTarget[1] += upvec[1] + sidevec[1];
|
||||
m_fTarget[2] += upvec[2] + sidevec[2];
|
||||
|
||||
ChangeKey(nTime, bAnimation, bAddKey, m_fEye, LC_CK_EYE);
|
||||
ChangeKey(nTime, bAnimation, bAddKey, m_fTarget, LC_CK_TARGET);
|
||||
UpdatePosition(nTime, bAnimation);
|
||||
}
|
||||
|
||||
void Camera::DoRotate(int dx, int dy, int mouse, unsigned short nTime, bool bAnimation, bool bAddKey, float* /*center*/)
|
||||
{
|
||||
Vector upvec(m_fUp), frontvec(m_fEye[0]-m_fTarget[0], m_fEye[1]-m_fTarget[1], m_fEye[2]-m_fTarget[2]), sidevec;
|
||||
sidevec.Cross(frontvec, upvec);
|
||||
sidevec.Normalize();
|
||||
sidevec *= 2.0f*dx/(21-mouse);
|
||||
upvec.Normalize();
|
||||
upvec *= -2.0f*dy/(21-mouse);
|
||||
|
||||
// TODO: option to move eye or target
|
||||
float len = frontvec.Length();
|
||||
frontvec += Vector(upvec[0] + sidevec[0], upvec[1] + sidevec[1], upvec[2] + sidevec[2]);
|
||||
frontvec.Normalize();
|
||||
frontvec *= len;
|
||||
frontvec += Vector(m_fTarget);
|
||||
frontvec.ToFloat(m_fEye);
|
||||
|
||||
// Calculate new up
|
||||
upvec = Vector(m_fUp[0], m_fUp[1], m_fUp[2]);
|
||||
frontvec = Vector(m_fEye[0]-m_fTarget[0], m_fEye[1]-m_fTarget[1], m_fEye[2]-m_fTarget[2]);
|
||||
sidevec.Cross(frontvec, upvec);
|
||||
upvec.Cross(sidevec, frontvec);
|
||||
upvec.Normalize();
|
||||
upvec.ToFloat(m_fUp);
|
||||
|
||||
ChangeKey(nTime, bAnimation, bAddKey, m_fEye, LC_CK_EYE);
|
||||
ChangeKey(nTime, bAnimation, bAddKey, m_fUp, LC_CK_UP);
|
||||
UpdatePosition(nTime, bAnimation);
|
||||
}
|
||||
|
||||
void Camera::DoRoll(int dx, int mouse, unsigned short nTime, bool bAnimation, bool bAddKey)
|
||||
{
|
||||
Matrix mat;
|
||||
float front[3] = { m_fEye[0]-m_fTarget[0], m_fEye[1]-m_fTarget[1], m_fEye[2]-m_fTarget[2] };
|
||||
|
||||
mat.FromAxisAngle(front, 2.0f*dx/(21-mouse));
|
||||
mat.TransformPoints(m_fUp, 1);
|
||||
|
||||
ChangeKey(nTime, bAnimation, bAddKey, m_fUp, LC_CK_UP);
|
||||
UpdatePosition(nTime, bAnimation);
|
||||
}
|
||||
|
||||
void Camera::StartTiledRendering(int tw, int th, int iw, int ih, float fAspect)
|
||||
{
|
||||
m_pTR = new TiledRender();
|
||||
m_pTR->TileSize(tw, th, 0);
|
||||
m_pTR->ImageSize(iw, ih);
|
||||
m_pTR->Perspective(m_fovy, fAspect, m_zNear, m_zFar);
|
||||
}
|
||||
|
||||
void Camera::GetTileInfo(int* row, int* col, int* width, int* height)
|
||||
{
|
||||
if (m_pTR != NULL)
|
||||
{
|
||||
*row = m_pTR->m_Rows - m_pTR->m_CurrentRow - 1;
|
||||
*col = m_pTR->m_CurrentColumn;
|
||||
*width = m_pTR->m_CurrentTileWidth;
|
||||
*height = m_pTR->m_CurrentTileHeight;
|
||||
}
|
||||
}
|
||||
|
||||
bool Camera::EndTile()
|
||||
{
|
||||
if (m_pTR != NULL)
|
||||
{
|
||||
if (m_pTR->EndTile())
|
||||
return true;
|
||||
|
||||
delete m_pTR;
|
||||
m_pTR = NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
195
common/camera.h
Normal file
195
common/camera.h
Normal file
|
@ -0,0 +1,195 @@
|
|||
#ifndef _CAMERA_H_
|
||||
#define _CAMERA_H_
|
||||
|
||||
#include "opengl.h"
|
||||
#include "object.h"
|
||||
#include "algebra.h"
|
||||
|
||||
#define LC_CAMERA_HIDDEN 0x01
|
||||
#define LC_CAMERA_SELECTED 0x02
|
||||
#define LC_CAMERA_FOCUSED 0x04
|
||||
#define LC_CAMERA_TARGET_SELECTED 0x08
|
||||
#define LC_CAMERA_TARGET_FOCUSED 0x10
|
||||
|
||||
class Camera;
|
||||
class CameraTarget;
|
||||
class File;
|
||||
class TiledRender;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_CAMERA_FRONT,LC_CAMERA_BACK,
|
||||
LC_CAMERA_TOP, LC_CAMERA_UNDER,
|
||||
LC_CAMERA_LEFT, LC_CAMERA_RIGHT,
|
||||
LC_CAMERA_MAIN, LC_CAMERA_USER
|
||||
} LC_CAMERA_TYPES;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_CK_EYE,
|
||||
LC_CK_TARGET,
|
||||
LC_CK_UP,
|
||||
LC_CK_COUNT
|
||||
} LC_CK_TYPES;
|
||||
|
||||
class CameraTarget : public Object
|
||||
{
|
||||
public:
|
||||
CameraTarget (Camera *pParent);
|
||||
virtual ~CameraTarget ();
|
||||
|
||||
public:
|
||||
void MinIntersectDist (LC_CLICKLINE* pLine);
|
||||
bool IntersectsVolume(const Vector4* Planes, int NumPlanes)
|
||||
{ return false; }
|
||||
void Select (bool bSelecting, bool bFocus, bool bMultiple);
|
||||
void Move (unsigned short nTime, bool bAnimation, bool bAddKey, float x, float y, float z)
|
||||
{
|
||||
// FIXME: move the position handling to the camera target
|
||||
}
|
||||
|
||||
const char* GetName() const;
|
||||
|
||||
Camera* GetParent () const
|
||||
{ return m_pParent; }
|
||||
|
||||
protected:
|
||||
Camera* m_pParent;
|
||||
|
||||
friend class Camera; // FIXME: needed for BoundingBoxCalculate ()
|
||||
// remove and use UpdatePosition instead
|
||||
};
|
||||
|
||||
class Camera : public Object
|
||||
{
|
||||
public:
|
||||
Camera ();
|
||||
Camera (unsigned char nType, Camera* pPrev);
|
||||
Camera (float ex, float ey, float ez, float tx, float ty, float tz, Camera* pCamera);
|
||||
Camera (const float *eye, const float *target, const float *up, Camera* pCamera);
|
||||
virtual ~Camera ();
|
||||
|
||||
// Query functions.
|
||||
inline Vector3 GetEyePosition() const
|
||||
{ return Vector3(m_fEye[0], m_fEye[1], m_fEye[2]); };
|
||||
inline Vector3 GetTargetPosition() const
|
||||
{ return Vector3(m_fTarget[0], m_fTarget[1], m_fTarget[2]); };
|
||||
inline Vector3 GetUpVector() const
|
||||
{ return Vector3(m_fUp[0], m_fUp[1], m_fUp[2]); };
|
||||
|
||||
const char* GetName() const
|
||||
{ return m_strName; };
|
||||
|
||||
CameraTarget* GetTarget () const
|
||||
{ return m_pTarget; }
|
||||
|
||||
|
||||
// Deprecated functions:
|
||||
const float* GetEyePos () const
|
||||
{ return m_fEye; };
|
||||
void GetEyePos (float* eye) const
|
||||
{ memcpy(eye, m_fEye, sizeof(m_fEye)); };
|
||||
const float* GetTargetPos () const
|
||||
{ return m_fTarget; };
|
||||
void GetTargetPos (float* target) const
|
||||
{ memcpy(target, m_fTarget, sizeof(m_fTarget)); };
|
||||
const float* GetUpVec () const
|
||||
{ return m_fUp; };
|
||||
void GetUpVec (float* up) const
|
||||
{ memcpy(up, m_fUp, sizeof(m_fUp)); };
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public:
|
||||
Camera* m_pNext;
|
||||
void Hide()
|
||||
{ m_nState = LC_CAMERA_HIDDEN; }
|
||||
void UnHide()
|
||||
{ m_nState &= ~LC_CAMERA_HIDDEN; }
|
||||
char* GetName()
|
||||
{ return m_strName; }
|
||||
bool IsSide()
|
||||
{ return m_nType < LC_CAMERA_MAIN; }
|
||||
bool IsUser()
|
||||
{ return m_nType == LC_CAMERA_USER; }
|
||||
bool IsVisible()
|
||||
{ return (m_nState & LC_CAMERA_HIDDEN) == 0; }
|
||||
bool IsSelected()
|
||||
{ return (m_nState & (LC_CAMERA_SELECTED|LC_CAMERA_TARGET_SELECTED)) != 0; }
|
||||
bool IsEyeSelected()
|
||||
{ return (m_nState & LC_CAMERA_SELECTED) != 0; }
|
||||
bool IsTargetSelected()
|
||||
{ return (m_nState & LC_CAMERA_TARGET_SELECTED) != 0; }
|
||||
bool IsEyeFocused()
|
||||
{ return (m_nState & LC_CAMERA_FOCUSED) != 0; }
|
||||
bool IsTargetFocused()
|
||||
{ return (m_nState & LC_CAMERA_TARGET_FOCUSED) != 0; }
|
||||
|
||||
/*
|
||||
void Select()
|
||||
{ m_nState |= (LC_CAMERA_SELECTED|LC_CAMERA_TARGET_SELECTED); }
|
||||
void UnSelect()
|
||||
{ m_nState &= ~(LC_CAMERA_SELECTED|LC_CAMERA_FOCUSED|LC_CAMERA_TARGET_SELECTED|LC_CAMERA_TARGET_FOCUSED); }
|
||||
void UnFocus()
|
||||
{ m_nState &= ~(LC_CAMERA_FOCUSED|LC_CAMERA_TARGET_FOCUSED); }
|
||||
void FocusEye()
|
||||
{ m_nState |= (LC_CAMERA_FOCUSED|LC_CAMERA_SELECTED); }
|
||||
void FocusTarget()
|
||||
{ m_nState |= (LC_CAMERA_TARGET_FOCUSED|LC_CAMERA_TARGET_SELECTED); }
|
||||
*/
|
||||
|
||||
void SelectTarget (bool bSelecting, bool bFocus, bool bMultiple);
|
||||
|
||||
public:
|
||||
bool FileLoad (File& file);
|
||||
void FileSave (File& file) const;
|
||||
void MinIntersectDist (LC_CLICKLINE* pLine);
|
||||
void Select (bool bSelecting, bool bFocus, bool bMultiple);
|
||||
bool IntersectsVolume(const Vector4* Planes, int NumPlanes)
|
||||
{ return false; }
|
||||
|
||||
|
||||
void UpdatePosition(unsigned short nTime, bool bAnimation);
|
||||
void Render(float fLineWidth);
|
||||
void LoadProjection(float fAspect);
|
||||
|
||||
void DoZoom(int dy, int mouse, unsigned short nTime, bool bAnimation, bool bAddKey);
|
||||
void DoPan(int dx, int dy, int mouse, unsigned short nTime, bool bAnimation, bool bAddKey);
|
||||
void DoRotate(int dx, int dy, int mouse, unsigned short nTime, bool bAnimation, bool bAddKey, float* center);
|
||||
void DoRoll(int dx, int mouse, unsigned short nTime, bool bAnimation, bool bAddKey);
|
||||
void Move(unsigned short nTime, bool bAnimation, bool bAddKey, float x, float y, float z);
|
||||
|
||||
void StartTiledRendering(int tw, int th, int iw, int ih, float fAspect);
|
||||
void GetTileInfo(int* row, int* col, int* width, int* height);
|
||||
bool EndTile();
|
||||
|
||||
float m_fovy;
|
||||
float m_zNear;
|
||||
float m_zFar;
|
||||
|
||||
protected:
|
||||
void Initialize();
|
||||
void UpdateBoundingBox();
|
||||
|
||||
// Camera target
|
||||
CameraTarget* m_pTarget;
|
||||
|
||||
// Attributes
|
||||
char m_strName[81];
|
||||
unsigned char m_nState;
|
||||
unsigned char m_nType;
|
||||
GLuint m_nList;
|
||||
static GLuint m_nTargetList;
|
||||
|
||||
// Current position and orientation.
|
||||
float m_fEye[3];
|
||||
float m_fTarget[3];
|
||||
float m_fUp[3];
|
||||
|
||||
TiledRender* m_pTR;
|
||||
};
|
||||
|
||||
#endif // _CAMERA_H_
|
93
common/console.cpp
Normal file
93
common/console.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
//
|
||||
// Debug Console
|
||||
//
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "console.h"
|
||||
|
||||
Console console;
|
||||
|
||||
// ============================================================================
|
||||
|
||||
Console::Console ()
|
||||
{
|
||||
m_pWindowFunc = NULL;
|
||||
}
|
||||
|
||||
Console::~Console ()
|
||||
{
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
void Console::Print (LC_CONSOLE_LEVEL level, const char* format, ...)
|
||||
{
|
||||
char text[512];
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
vsprintf (text, format, args);
|
||||
va_end (args);
|
||||
|
||||
InternalPrint (level, text);
|
||||
}
|
||||
|
||||
void Console::PrintMisc (const char* format, ...)
|
||||
{
|
||||
char text[512];
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
vsprintf (text, format, args);
|
||||
va_end (args);
|
||||
|
||||
InternalPrint (LC_CONSOLE_MISC, text);
|
||||
}
|
||||
|
||||
void Console::PrintDebug (const char* format, ...)
|
||||
{
|
||||
char text[512];
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
vsprintf (text, format, args);
|
||||
va_end (args);
|
||||
|
||||
InternalPrint (LC_CONSOLE_DEBUG, text);
|
||||
}
|
||||
|
||||
void Console::PrintWarning (const char* format, ...)
|
||||
{
|
||||
char text[512];
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
vsprintf (text, format, args);
|
||||
va_end (args);
|
||||
|
||||
InternalPrint (LC_CONSOLE_WARNING, text);
|
||||
}
|
||||
|
||||
void Console::PrintError (const char* format, ...)
|
||||
{
|
||||
char text[512];
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
vsprintf (text, format, args);
|
||||
va_end (args);
|
||||
|
||||
InternalPrint (LC_CONSOLE_ERROR, text);
|
||||
}
|
||||
|
||||
void Console::InternalPrint (LC_CONSOLE_LEVEL level, const char* text)
|
||||
{
|
||||
#ifndef LC_DEBUG
|
||||
if (level == LC_CONSOLE_DEBUG)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (m_pWindowFunc)
|
||||
(*m_pWindowFunc) (level, text, m_pWindowFuncData);
|
||||
}
|
42
common/console.h
Normal file
42
common/console.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef _CONSOLE_H_
|
||||
#define _CONSOLE_H_
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_CONSOLE_ERROR,
|
||||
LC_CONSOLE_WARNING,
|
||||
LC_CONSOLE_DEBUG,
|
||||
LC_CONSOLE_MISC
|
||||
} LC_CONSOLE_LEVEL;
|
||||
|
||||
typedef void (*CONSOLECALLBACK) (LC_CONSOLE_LEVEL level, const char* text, void* user_data);
|
||||
|
||||
class Console
|
||||
{
|
||||
public:
|
||||
Console ();
|
||||
virtual ~Console ();
|
||||
|
||||
void Print (LC_CONSOLE_LEVEL level, const char* format, ...);
|
||||
void PrintMisc (const char* format, ...);
|
||||
void PrintDebug (const char* format, ...);
|
||||
void PrintWarning (const char* format, ...);
|
||||
void PrintError (const char* format, ...);
|
||||
|
||||
void SetWindowCallback (CONSOLECALLBACK func, void* data)
|
||||
{ m_pWindowFunc = func; m_pWindowFuncData = data; };
|
||||
|
||||
protected:
|
||||
void InternalPrint (LC_CONSOLE_LEVEL level, const char* text);
|
||||
|
||||
CONSOLECALLBACK m_pWindowFunc;
|
||||
void* m_pWindowFuncData;
|
||||
|
||||
// variables
|
||||
bool use_tty;
|
||||
bool use_file;
|
||||
};
|
||||
|
||||
extern Console console;
|
||||
|
||||
#endif // _CONSOLE_H_
|
872
common/curve.cpp
Executable file
872
common/curve.cpp
Executable file
|
@ -0,0 +1,872 @@
|
|||
// Curve class, used to represent all flexible objects
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "globals.h"
|
||||
#include "curve.h"
|
||||
#include "opengl.h"
|
||||
#include "matrix.h"
|
||||
#include "vector.h"
|
||||
|
||||
#define LC_CURVE_SAVE_VERSION 1 // LeoCAD 0.73
|
||||
#define LC_CURVE_POINT_SAVE_VERSION 1 // LeoCAD 0.73
|
||||
|
||||
GLuint CurvePoint::m_nArrowList = 0;
|
||||
GLuint CurvePoint::m_nSphereList = 0;
|
||||
|
||||
static LC_OBJECT_KEY_INFO curve_point_key_info[LC_CURVE_POINT_KEY_COUNT] =
|
||||
{
|
||||
{ "Control Point Position", 3, LC_CURVE_POINT_KEY_POSITION },
|
||||
{ "Control Point Direction 1", 3, LC_CURVE_POINT_KEY_DIRECTION1 },
|
||||
{ "Control Point Direction 2", 3, LC_CURVE_POINT_KEY_DIRECTION2 },
|
||||
{ "Control Point Angle", 1, LC_CURVE_POINT_KEY_ANGLE }
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// CurvePoint class
|
||||
|
||||
CurvePoint::CurvePoint (Curve *pParent)
|
||||
: Object (LC_OBJECT_CURVE_POINT)
|
||||
{
|
||||
m_pParent = pParent;
|
||||
|
||||
/*
|
||||
FIXME
|
||||
strcpy (m_strName, pParent->GetName ());
|
||||
m_strName[LC_OBJECT_NAME_LEN-8] = '\0';
|
||||
strcat (m_strName, ".Target");
|
||||
*/
|
||||
|
||||
Initialize ();
|
||||
}
|
||||
|
||||
CurvePoint::CurvePoint (Curve *pParent, const float *pos, const float *dir)
|
||||
: Object (LC_OBJECT_CURVE_POINT)
|
||||
{
|
||||
m_pParent = pParent;
|
||||
|
||||
/*
|
||||
FIXME
|
||||
strcpy (m_strName, pParent->GetName ());
|
||||
m_strName[LC_OBJECT_NAME_LEN-8] = '\0';
|
||||
strcat (m_strName, ".Target");
|
||||
*/
|
||||
|
||||
Initialize ();
|
||||
|
||||
float angle[1] = { 0 };
|
||||
|
||||
ChangeKey (1, false, true, pos, LC_CURVE_POINT_KEY_POSITION);
|
||||
ChangeKey (1, false, true, dir, LC_CURVE_POINT_KEY_DIRECTION1);
|
||||
ChangeKey (1, false, true, dir, LC_CURVE_POINT_KEY_DIRECTION2);
|
||||
ChangeKey (1, false, true, angle, LC_CURVE_POINT_KEY_ANGLE);
|
||||
ChangeKey (1, true, true, pos, LC_CURVE_POINT_KEY_POSITION);
|
||||
ChangeKey (1, true, true, dir, LC_CURVE_POINT_KEY_DIRECTION1);
|
||||
ChangeKey (1, true, true, dir, LC_CURVE_POINT_KEY_DIRECTION2);
|
||||
ChangeKey (1, true, true, angle, LC_CURVE_POINT_KEY_ANGLE);
|
||||
|
||||
UpdatePosition (1, false);
|
||||
}
|
||||
|
||||
void CurvePoint::Initialize ()
|
||||
{
|
||||
if (m_nSphereList == 0)
|
||||
{
|
||||
m_nSphereList = glGenLists (1);
|
||||
glNewList (m_nSphereList, GL_COMPILE);
|
||||
|
||||
float radius = 0.2f;
|
||||
int slices = 6, stacks = 6;
|
||||
float rho, drho, theta, dtheta;
|
||||
float x, y, z;
|
||||
int i, j, imin, imax;
|
||||
drho = 3.1415926536f/(float)stacks;
|
||||
dtheta = 2.0f*3.1415926536f/(float)slices;
|
||||
|
||||
// draw +Z end as a triangle fan
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
glVertex3f(0.0, 0.0, radius);
|
||||
for (j = 0; j <= slices; j++)
|
||||
{
|
||||
theta = (j == slices) ? 0.0f : j * dtheta;
|
||||
x = (float)(-sin(theta) * sin(drho));
|
||||
y = (float)(cos(theta) * sin(drho));
|
||||
z = (float)(cos(drho));
|
||||
glVertex3f(x*radius, y*radius, z*radius);
|
||||
}
|
||||
glEnd();
|
||||
|
||||
imin = 1;
|
||||
imax = stacks-1;
|
||||
|
||||
for (i = imin; i < imax; i++)
|
||||
{
|
||||
rho = i * drho;
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for (j = 0; j <= slices; j++)
|
||||
{
|
||||
theta = (j == slices) ? 0.0f : j * dtheta;
|
||||
x = (float)(-sin(theta) * sin(rho));
|
||||
y = (float)(cos(theta) * sin(rho));
|
||||
z = (float)(cos(rho));
|
||||
glVertex3f(x*radius, y*radius, z*radius);
|
||||
x = (float)(-sin(theta) * sin(rho+drho));
|
||||
y = (float)(cos(theta) * sin(rho+drho));
|
||||
z = (float)(cos(rho+drho));
|
||||
glVertex3f(x*radius, y*radius, z*radius);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
// draw -Z end as a triangle fan
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
glVertex3f(0.0, 0.0, -radius);
|
||||
rho = 3.1415926536f - drho;
|
||||
for (j = slices; j >= 0; j--)
|
||||
{
|
||||
theta = (j==slices) ? 0.0f : j * dtheta;
|
||||
x = (float)(-sin(theta) * sin(rho));
|
||||
y = (float)(cos(theta) * sin(rho));
|
||||
z = (float)(cos(rho));
|
||||
glVertex3f(x*radius, y*radius, z*radius);
|
||||
}
|
||||
glEnd();
|
||||
glEndList();
|
||||
}
|
||||
|
||||
m_nState = LC_CURVE_POINT_CONTINUOUS;
|
||||
|
||||
float *values[] = { m_fPos, m_fDir1, m_fDir2, &m_fAngle };
|
||||
RegisterKeys (values, curve_point_key_info, LC_CURVE_POINT_KEY_COUNT);
|
||||
}
|
||||
|
||||
CurvePoint::~CurvePoint ()
|
||||
{
|
||||
}
|
||||
|
||||
void CurvePoint::MinIntersectDist (LC_CLICKLINE* pLine)
|
||||
{
|
||||
float dist = (float)BoundingBoxIntersectDist (pLine);
|
||||
|
||||
if (dist < pLine->mindist)
|
||||
{
|
||||
pLine->mindist = dist;
|
||||
pLine->pClosest = this;
|
||||
|
||||
m_nLastHit = 1;
|
||||
}
|
||||
|
||||
m_nLastHit = 0;
|
||||
// FIXME: check arrows
|
||||
}
|
||||
|
||||
void CurvePoint::UpdatePosition (unsigned short nTime, bool bAnimation)
|
||||
{
|
||||
CalculateKeys (nTime, bAnimation);
|
||||
}
|
||||
|
||||
bool CurvePoint::FileLoad (File& file)
|
||||
{
|
||||
// FIXME
|
||||
return true;
|
||||
}
|
||||
|
||||
void CurvePoint::FileSave (File& file) const
|
||||
{
|
||||
// FIXME
|
||||
}
|
||||
|
||||
void CurvePoint::Move (unsigned short nTime, bool bAnimation, bool bAddKey, float dx, float dy, float dz)
|
||||
{
|
||||
/*
|
||||
if (m_nState & LC_CURVE_POINT_ARROW1_FOCUS)
|
||||
if (m_nState & LC_CURVE_POINT_ARROW2_FOCUS)
|
||||
if (m_nState & LC_CURVE_POINT_CONTINUOUS)
|
||||
;
|
||||
*/
|
||||
}
|
||||
|
||||
void CurvePoint::Select (bool bSelecting, bool bFocus, bool bMultiple)
|
||||
{
|
||||
// FIXME: select arrows, use m_nLastHit
|
||||
|
||||
if (bSelecting == true)
|
||||
{
|
||||
m_nState |= LC_CURVE_POINT_SELECTED;
|
||||
|
||||
if (bFocus == true)
|
||||
{
|
||||
m_nState |= LC_CURVE_POINT_FOCUSED;
|
||||
|
||||
m_pParent->DeselectOtherPoints (this, bMultiple);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bFocus == true)
|
||||
m_nState &= ~(LC_CURVE_POINT_SELECTED|LC_CURVE_POINT_FOCUSED);
|
||||
else
|
||||
m_nState &= ~(LC_CURVE_POINT_SELECTED);
|
||||
}
|
||||
}
|
||||
|
||||
void CurvePoint::Render (LC_RENDER_INFO* pInfo)
|
||||
{
|
||||
if (m_nState & LC_CURVE_POINT_FOCUSED)
|
||||
glColor3ubv (FlatColorArray[LC_COL_FOCUSED]);
|
||||
else if (m_nState & LC_CURVE_POINT_SELECTED)
|
||||
glColor3ubv (FlatColorArray[LC_COL_SELECTED]);
|
||||
else
|
||||
glColor3f(0.5f, 0.8f, 0.5f); // FIXME: same as camera color, add to FlatColorArray
|
||||
// glColor3ub (0, 0, 0); // FIXME: inverse of background
|
||||
// FIXME: add a new color to the array and change the names from LC_COL to LC_COLOR ?
|
||||
|
||||
glPushMatrix ();
|
||||
glTranslatef (m_fPos[0], m_fPos[1], m_fPos[2]);
|
||||
glCallList (m_nSphereList);
|
||||
|
||||
// FIXME: create and use arrow display list
|
||||
// if (m_pPoints[i].m_nFlags & LC_CURVE_POINT_FOCUSED)
|
||||
{
|
||||
glBegin (GL_LINES);
|
||||
glVertex3f ( m_fDir1[0]/5, m_fDir1[1]/5, m_fDir1[2]/5);
|
||||
glVertex3f (-m_fDir2[0]/5, -m_fDir2[1]/5, -m_fDir2[2]/5);
|
||||
glEnd ();
|
||||
}
|
||||
|
||||
glPopMatrix ();
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Curve class
|
||||
|
||||
Curve::Curve ()
|
||||
: Object (LC_OBJECT_CURVE)
|
||||
{
|
||||
Initialize ();
|
||||
}
|
||||
|
||||
Curve::Curve (PieceInfo *pInfo, const float *pos, unsigned char color)
|
||||
: Object (LC_OBJECT_CURVE)
|
||||
{
|
||||
/*
|
||||
Initialize ();
|
||||
|
||||
// FIXME: set the curve type and length based on the PieceInfo
|
||||
m_fLength = 5;
|
||||
|
||||
m_nCurveType = LC_CURVE_TYPE_HOSE;
|
||||
m_nColor = color;
|
||||
|
||||
float dir[3] = { 0, 20, 0 }, pos2[3] = { pos[0] + m_fLength, pos[1], pos[2] };
|
||||
|
||||
m_fUp0[0] = 0;
|
||||
m_fUp0[1] = 0;
|
||||
m_fUp0[2] = 1;
|
||||
|
||||
CurvePoint *pt;
|
||||
pt = new CurvePoint (this, pos, dir);
|
||||
m_Points.Add (pt);
|
||||
|
||||
dir[1] = 0;
|
||||
dir[2] = -5;
|
||||
|
||||
pt = new CurvePoint (this, pos2, dir);
|
||||
m_Points.Add (pt);
|
||||
|
||||
pos2[0] += 5;
|
||||
dir[2] = 5;
|
||||
|
||||
pt = new CurvePoint (this, pos2, dir);
|
||||
m_Points.Add (pt);
|
||||
|
||||
UpdatePosition (1, false);
|
||||
*/
|
||||
}
|
||||
|
||||
Curve::~Curve ()
|
||||
{
|
||||
/*
|
||||
for (int i = 0; i < m_Points.GetSize (); i++)
|
||||
delete m_Points[i];
|
||||
glDeleteLists (m_nDisplayList, 1);
|
||||
*/
|
||||
}
|
||||
|
||||
void Curve::Initialize ()
|
||||
{
|
||||
m_nCurveType = (LC_CURVE_TYPE)0;
|
||||
m_nState = 0;
|
||||
m_nColor = 0;
|
||||
m_nDisplayList = glGenLists (1);
|
||||
}
|
||||
|
||||
bool Curve::FileLoad (File& file)
|
||||
{
|
||||
// FIXME
|
||||
return true;
|
||||
}
|
||||
|
||||
void Curve::FileSave (File& file) const
|
||||
{
|
||||
// FIXME
|
||||
}
|
||||
|
||||
void Curve::MinIntersectDist (LC_CLICKLINE* pLine)
|
||||
{
|
||||
// FIXME
|
||||
}
|
||||
|
||||
void Curve::UpdatePosition (unsigned short nTime, bool bAnimation)
|
||||
{
|
||||
for (int i = 0; i < m_Points.GetSize (); i++)
|
||||
m_Points[i]->UpdatePosition (nTime, bAnimation);
|
||||
|
||||
glNewList (m_nDisplayList, GL_COMPILE);
|
||||
|
||||
switch (m_nCurveType)
|
||||
{
|
||||
case LC_CURVE_TYPE_HOSE:
|
||||
TesselateHose ();
|
||||
break;
|
||||
}
|
||||
|
||||
glEndList ();
|
||||
}
|
||||
|
||||
void Curve::Move (unsigned short nTime, bool bAnimation, bool bAddKey, float dx, float dy, float dz)
|
||||
{
|
||||
for (int i = 0; i < m_Points.GetSize (); i++)
|
||||
m_Points[i]->Move (nTime, bAnimation, bAddKey, dx, dy, dz);
|
||||
}
|
||||
|
||||
void Curve::Select (bool bSelecting, bool bFocus, bool bMultiple)
|
||||
{
|
||||
if (bSelecting == true)
|
||||
{
|
||||
if (bFocus == true)
|
||||
{
|
||||
m_nState |= (LC_CURVE_SELECTED|LC_CURVE_FOCUSED);
|
||||
|
||||
for (int i = 0; i < m_Points.GetSize (); i++)
|
||||
m_Points[i]->Select (false, true, bMultiple);
|
||||
}
|
||||
else
|
||||
m_nState |= LC_CURVE_SELECTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bFocus == true)
|
||||
m_nState &= ~(LC_CURVE_SELECTED|LC_CURVE_FOCUSED);
|
||||
else
|
||||
m_nState &= ~(LC_CURVE_SELECTED);
|
||||
|
||||
for (int i = 0; i < m_Points.GetSize (); i++)
|
||||
m_Points[i]->Select (false, bFocus, bMultiple);
|
||||
}
|
||||
}
|
||||
|
||||
void Curve::DeselectOtherPoints (CurvePoint *pSender, bool bFocusOnly)
|
||||
{
|
||||
CurvePoint *pt;
|
||||
|
||||
for (int i = 0; i < m_Points.GetSize (); i++)
|
||||
{
|
||||
pt = m_Points[i];
|
||||
if (pt != pSender)
|
||||
pt->Select (false, bFocusOnly, true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void Curve::TesselateHose ()
|
||||
{
|
||||
float x, y, z, t, t2, t3, cx[4], cy[4], cz[4];
|
||||
const float *p1, *p2, *r1, *r2, *u1, *u2;
|
||||
|
||||
glEnableClientState (GL_VERTEX_ARRAY);
|
||||
|
||||
for (unsigned int i = 0; i < m_Points.GetSize () - 1; i++)
|
||||
{
|
||||
p1 = m_Points[i]->GetPosition ();
|
||||
p2 = m_Points[i+1]->GetPosition ();
|
||||
r1 = m_Points[i]->GetDirection1 ();
|
||||
r2 = m_Points[i+1]->GetDirection2 ();
|
||||
u1 = m_Points[i]->GetUpVector ();
|
||||
u2 = m_Points[i+1]->GetUpVector ();
|
||||
|
||||
cx[0] = 2*p1[0] - 2*p2[0] + r1[0] + r2[0];
|
||||
cx[1] = -3*p1[0] + 3*p2[0] - 2*r1[0] - r2[0];
|
||||
cx[2] = r1[0];
|
||||
cx[3] = p1[0];
|
||||
|
||||
cy[0] = 2*p1[1] - 2*p2[1] + r1[1] + r2[1];
|
||||
cy[1] = -3*p1[1] + 3*p2[1] - 2*r1[1] - r2[1];
|
||||
cy[2] = r1[1];
|
||||
cy[3] = p1[1];
|
||||
|
||||
cz[0] = 2*p1[2] - 2*p2[2] + r1[2] + r2[2];
|
||||
cz[1] = -3*p1[2] + 3*p2[2] - 2*r1[2] - r2[2];
|
||||
cz[2] = r1[2];
|
||||
cz[3] = p1[2];
|
||||
|
||||
int steps1 = 16, steps2 = 6, j, k;
|
||||
float* verts = (float*)malloc ((steps1+1) * steps2 * 3 * sizeof (float));
|
||||
float a, b, c;
|
||||
float ux, uy, uz;
|
||||
|
||||
for (t = 0, j = 0; j <= steps1; j++, t += 1.0f/steps1)
|
||||
{
|
||||
t2 = t*t;
|
||||
t3 = t2*t;
|
||||
|
||||
// position
|
||||
x = cx[0]*t3 + cx[1]*t2 + cx[2]*t + cx[3];
|
||||
y = cy[0]*t3 + cy[1]*t2 + cy[2]*t + cy[3];
|
||||
z = cz[0]*t3 + cz[1]*t2 + cz[2]*t + cz[3];
|
||||
|
||||
// tangent
|
||||
a = 3*cx[0]*t2 + 2*cx[1]*t + cx[2];
|
||||
b = 3*cy[0]*t2 + 2*cy[1]*t + cy[2];
|
||||
c = 3*cz[0]*t2 + 2*cz[1]*t + cz[2];
|
||||
|
||||
// gradient
|
||||
ux = 6*cx[0]*t + 2*cx[1];
|
||||
uy = 6*cy[0]*t + 2*cy[1];
|
||||
uz = 6*cz[0]*t + 2*cz[1];
|
||||
|
||||
Vector side, front (a, b, c);
|
||||
Vector up (ux, uy, uz);
|
||||
side.Cross (front, up);
|
||||
up.Cross (side, front);
|
||||
up.Normalize ();
|
||||
front.Normalize ();
|
||||
side.Normalize ();
|
||||
|
||||
float f[16];
|
||||
#define M(row,col) f[col*4+row]
|
||||
M(0,0) = side[0]; M(0,1) = up[0]; M(0,2) = front[0]; M(0,3) = x;
|
||||
M(1,0) = side[1]; M(1,1) = up[1]; M(1,2) = front[1]; M(1,3) = y;
|
||||
M(2,0) = side[2]; M(2,1) = up[2]; M(2,2) = front[2]; M(2,3) = z;
|
||||
M(3,0) = 0.0; M(3,1) = 0.0; M(3,2) = 0.0; M(3,3) = 1.0;
|
||||
#undef M
|
||||
|
||||
float v[3];
|
||||
Matrix m;
|
||||
m.FromFloat (f);
|
||||
|
||||
for (int k = 0; k < steps2; k++)
|
||||
{
|
||||
float *o = &verts[(j*steps2+k)*3];
|
||||
v[0] = cos (2.0 * M_PI * k / steps2) * 0.15f;
|
||||
v[1] = sin (2.0 * M_PI * k / steps2) * 0.15f;
|
||||
v[2] = 0;
|
||||
m.TransformPoint (o, v);
|
||||
glVertex3fv (o);
|
||||
}
|
||||
}
|
||||
|
||||
GLuint *index = (GLuint*)malloc (2 * (steps2+1) * sizeof (GLuint));
|
||||
glVertexPointer (3, GL_FLOAT, 0, verts);
|
||||
for (j = 0; j < steps1; j++)
|
||||
{
|
||||
for (k = 0; k < steps2; k++)
|
||||
{
|
||||
index[k*2] = j*steps2+k;
|
||||
index[k*2+1] = (j+1)*steps2+k;
|
||||
}
|
||||
index[k*2] = index[0];
|
||||
index[k*2+1] = index[1];
|
||||
glDrawElements (GL_TRIANGLE_STRIP, 2*(steps2+1), GL_UNSIGNED_INT, index);
|
||||
}
|
||||
|
||||
free (index);
|
||||
free (verts);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void Curve::TesselateHose ()
|
||||
{
|
||||
float x, y, z, t, t2, t3, cx[4], cy[4], cz[4];
|
||||
const float *p1, *p2, *r1, *r2;
|
||||
|
||||
float u[3] = { m_fUp0[0], m_fUp0[1], m_fUp0[2] };
|
||||
int steps1 = 16, steps2 = 6, j, k;
|
||||
float* verts = (float*)malloc ((steps1+1) * steps2 * 3 * sizeof (float));
|
||||
float a, b, c;
|
||||
|
||||
glEnableClientState (GL_VERTEX_ARRAY);
|
||||
glVertexPointer (3, GL_FLOAT, 0, verts);
|
||||
|
||||
for (int i = 0; i < m_Points.GetSize () - 1; i++)
|
||||
{
|
||||
float a1, a2, angle_step; // axial rotation
|
||||
|
||||
p1 = m_Points[i]->GetPosition ();
|
||||
p2 = m_Points[i+1]->GetPosition ();
|
||||
r1 = m_Points[i]->GetDirection1 ();
|
||||
r2 = m_Points[i+1]->GetDirection2 ();
|
||||
a1 = m_Points[i]->GetAngle ();
|
||||
a2 = m_Points[i+1]->GetAngle ();
|
||||
|
||||
angle_step = (a2 - a1) / steps1;
|
||||
if (fabs (angle_step) < 0.01f)
|
||||
angle_step = 0;
|
||||
|
||||
cx[0] = 2*p1[0] - 2*p2[0] + r1[0] + r2[0];
|
||||
cx[1] = -3*p1[0] + 3*p2[0] - 2*r1[0] - r2[0];
|
||||
cx[2] = r1[0];
|
||||
cx[3] = p1[0];
|
||||
|
||||
cy[0] = 2*p1[1] - 2*p2[1] + r1[1] + r2[1];
|
||||
cy[1] = -3*p1[1] + 3*p2[1] - 2*r1[1] - r2[1];
|
||||
cy[2] = r1[1];
|
||||
cy[3] = p1[1];
|
||||
|
||||
cz[0] = 2*p1[2] - 2*p2[2] + r1[2] + r2[2];
|
||||
cz[1] = -3*p1[2] + 3*p2[2] - 2*r1[2] - r2[2];
|
||||
cz[2] = r1[2];
|
||||
cz[3] = p1[2];
|
||||
|
||||
for (t = 0, j = 0; j <= steps1; j++, t += 1.0f/steps1)
|
||||
{
|
||||
t2 = t*t;
|
||||
t3 = t2*t;
|
||||
|
||||
// position
|
||||
x = cx[0]*t3 + cx[1]*t2 + cx[2]*t + cx[3];
|
||||
y = cy[0]*t3 + cy[1]*t2 + cy[2]*t + cy[3];
|
||||
z = cz[0]*t3 + cz[1]*t2 + cz[2]*t + cz[3];
|
||||
|
||||
// tangent
|
||||
a = 3*cx[0]*t2 + 2*cx[1]*t + cx[2];
|
||||
b = 3*cy[0]*t2 + 2*cy[1]*t + cy[2];
|
||||
c = 3*cz[0]*t2 + 2*cz[1]*t + cz[2];
|
||||
|
||||
Vector side, front (a, b, c);
|
||||
Vector up (u);
|
||||
side.Cross (front, up);
|
||||
up.Cross (side, front);
|
||||
up.Normalize ();
|
||||
front.Normalize ();
|
||||
side.Normalize ();
|
||||
|
||||
if (angle_step != 0)
|
||||
{
|
||||
Matrix rot;
|
||||
rot.FromAxisAngle (front, angle_step);
|
||||
rot.TransformPoint (u, up);
|
||||
}
|
||||
else
|
||||
up.ToFloat (u);
|
||||
|
||||
float f[16];
|
||||
#define M(row,col) f[col*4+row]
|
||||
M(0,0) = side[0]; M(0,1) = up[0]; M(0,2) = front[0]; M(0,3) = x;
|
||||
M(1,0) = side[1]; M(1,1) = up[1]; M(1,2) = front[1]; M(1,3) = y;
|
||||
M(2,0) = side[2]; M(2,1) = up[2]; M(2,2) = front[2]; M(2,3) = z;
|
||||
M(3,0) = 0.0; M(3,1) = 0.0; M(3,2) = 0.0; M(3,3) = 1.0;
|
||||
#undef M
|
||||
|
||||
float v[3];
|
||||
Matrix m;
|
||||
m.FromFloat (f);
|
||||
|
||||
for (int k = 0; k < steps2; k++)
|
||||
{
|
||||
float *o = &verts[(j*steps2+k)*3];
|
||||
v[0] = (float)(cos (2.0 * M_PI * k / steps2) * 0.15);
|
||||
v[1] = (float)(sin (2.0 * M_PI * k / steps2) * 0.15);
|
||||
v[2] = 0;
|
||||
m.TransformPoint (o, v);
|
||||
}
|
||||
}
|
||||
|
||||
GLuint *index = (GLuint*)malloc (2 * (steps2+1) * sizeof (GLuint));
|
||||
for (j = 0; j < steps1; j++)
|
||||
{
|
||||
for (k = 0; k < steps2; k++)
|
||||
{
|
||||
index[k*2] = j*steps2+k;
|
||||
index[k*2+1] = (j+1)*steps2+k;
|
||||
}
|
||||
index[k*2] = index[0];
|
||||
index[k*2+1] = index[1];
|
||||
glDrawElements (GL_TRIANGLE_STRIP, 2*(steps2+1), GL_UNSIGNED_INT, index);
|
||||
}
|
||||
|
||||
free (index);
|
||||
}
|
||||
free (verts);
|
||||
}
|
||||
|
||||
void Curve::Render (LC_RENDER_INFO* pInfo)
|
||||
{
|
||||
if ((m_nState & LC_CURVE_HIDDEN) != 0)
|
||||
return;
|
||||
|
||||
// FIXME: create a "set color" function in LC_RENDER_INFO
|
||||
if (pInfo->lighting)
|
||||
glColor4ubv (ColorArray[m_nColor]);
|
||||
else
|
||||
glColor3ubv (FlatColorArray[m_nColor]);
|
||||
|
||||
if (m_nColor > 13 && m_nColor < 22) // FIXME: use a #define
|
||||
{
|
||||
if (!pInfo->transparent)
|
||||
{
|
||||
pInfo->transparent = true;
|
||||
glEnable (GL_BLEND);
|
||||
glDepthMask (GL_FALSE);
|
||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pInfo->transparent)
|
||||
{
|
||||
pInfo->transparent = false;
|
||||
glDepthMask (GL_TRUE);
|
||||
glDisable (GL_BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
// glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
|
||||
glCallList (m_nDisplayList);
|
||||
|
||||
// if (m_nState & LC_CURVE_SELECTED)
|
||||
{
|
||||
// turn off transparency to draw the control points
|
||||
if (pInfo->transparent)
|
||||
{
|
||||
pInfo->transparent = false;
|
||||
if (pInfo->transparent)
|
||||
{
|
||||
glDepthMask (GL_TRUE);
|
||||
glDisable (GL_BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_Points.GetSize (); i++)
|
||||
m_Points[i]->Render (pInfo);
|
||||
}
|
||||
|
||||
/*
|
||||
if (IsSelected ())
|
||||
{
|
||||
|
||||
for (int i = 0; i < m_nNumPoints; i++)
|
||||
{
|
||||
if (m_pPoints[i].m_nFlags & LC_CURVE_POINT_FOCUSED)
|
||||
glColor3ubv (FlatColorArray[LC_COL_FOCUSED]);
|
||||
else if (m_pPoints[i].m_nFlags & LC_CURVE_POINT_SELECTED)
|
||||
glColor3ubv (FlatColorArray[LC_COL_SELECTED]);
|
||||
else
|
||||
glColor3f(0.5f, 0.8f, 0.5f); // FIXME: same as camera color, add to FlatColorArray
|
||||
// glColor3ub (0, 0, 0); // FIXME: inverse of background
|
||||
// FIXME: add a new color to the array and change the names from LC_COL to LC_COLOR ?
|
||||
|
||||
glPushMatrix ();
|
||||
// RenderSegment (m_pPoints[i].m_fPos, m_pPoints[i+1].m_fPos, m_pSegments[i].m_fR1, m_pSegments[i].m_fR2);
|
||||
glTranslatef (m_pPoints[i].m_fPos[0], m_pPoints[i].m_fPos[1], m_pPoints[i].m_fPos[2]);
|
||||
glCallList (m_nSphereList);
|
||||
|
||||
if (m_pPoints[i].m_nFlags & LC_CURVE_POINT_FOCUSED)
|
||||
{
|
||||
glBegin (GL_LINES);
|
||||
if (i < m_nNumSegments)
|
||||
{
|
||||
glVertex3fv (m_pSegments[i].m_fR1);
|
||||
glVertex3f (0, 0, 0);
|
||||
}
|
||||
else if (i > 0)
|
||||
{
|
||||
glVertex3f (-m_pSegments[i-1].m_fR2[0], -m_pSegments[i-1].m_fR2[1], -m_pSegments[i-1].m_fR2[2]);
|
||||
glVertex3f (0, 0, 0);
|
||||
}
|
||||
glEnd ();
|
||||
}
|
||||
|
||||
glPopMatrix ();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
if (m_nFlags & LC_CURVE_LOOP)
|
||||
{
|
||||
i = m_nNumPoints - 1;
|
||||
RenderSegment (m_pPoints[0].pos, m_pPoints[i].pos, m_pPoints[0].normal, m_pPoints[i].normal);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
#define LC_CURVE_POINT_RADIUS 0.2f
|
||||
|
||||
// =============================================================================
|
||||
// Static functions
|
||||
|
||||
#include <math.h>
|
||||
/*
|
||||
// TODO: optimize
|
||||
static void RenderSegment (float p1[3], float p2[3], float r1[3], float r2[3])
|
||||
{
|
||||
float x, y, z, t, t2, t3, cx[4], cy[4], cz[4];
|
||||
int i;
|
||||
|
||||
cx[0] = 2*p1[0] - 2*p2[0] + r1[0] + r2[0];
|
||||
cx[1] = -3*p1[0] + 3*p2[0] - 2*r1[0] - r2[0];
|
||||
cx[2] = r1[0];
|
||||
cx[3] = p1[0];
|
||||
|
||||
cy[0] = 2*p1[1] - 2*p2[1] + r1[1] + r2[1];
|
||||
cy[1] = -3*p1[1] + 3*p2[1] - 2*r1[1] - r2[1];
|
||||
cy[2] = r1[1];
|
||||
cy[3] = p1[1];
|
||||
|
||||
cz[0] = 2*p1[2] - 2*p2[2] + r1[2] + r2[2];
|
||||
cz[1] = -3*p1[2] + 3*p2[2] - 2*r1[2] - r2[2];
|
||||
cz[2] = r1[2];
|
||||
cz[3] = p1[2];
|
||||
|
||||
glColor3f (1,0,0);
|
||||
|
||||
glBegin (GL_LINE_STRIP);
|
||||
glVertex3f (cx[3], cy[3], cz[3]);
|
||||
|
||||
for (t = 0, i = 0; i < 10; i++)
|
||||
{
|
||||
t += 0.1f;
|
||||
t2 = t*t;
|
||||
t3 = t2*t;
|
||||
|
||||
x = cx[0]*t3 + cx[1]*t2 + cx[2]*t + cx[3];
|
||||
y = cy[0]*t3 + cy[1]*t2 + cy[2]*t + cy[3];
|
||||
z = cz[0]*t3 + cz[1]*t2 + cz[2]*t + cz[3];
|
||||
glVertex3f (x, y, z);
|
||||
}
|
||||
|
||||
glEnd ();
|
||||
|
||||
|
||||
glColor3f (0,0,0);
|
||||
|
||||
float a, b, c;
|
||||
for (t = 0, i = 0; i <= 10; i++, t += 0.1f)
|
||||
{
|
||||
t2 = t*t;
|
||||
t3 = t2*t;
|
||||
|
||||
x = cx[0]*t3 + cx[1]*t2 + cx[2]*t + cx[3];
|
||||
y = cy[0]*t3 + cy[1]*t2 + cy[2]*t + cy[3];
|
||||
z = cz[0]*t3 + cz[1]*t2 + cz[2]*t + cz[3];
|
||||
|
||||
a = 3*cx[0]*t2 + 2*cx[1]*t + cx[2];
|
||||
b = 3*cy[0]*t2 + 2*cy[1]*t + cy[2];
|
||||
c = 3*cz[0]*t2 + 2*cz[1]*t + cz[2];
|
||||
|
||||
Vector v1 (0, 0, 1);
|
||||
Vector v2 (a, b, c);
|
||||
Vector v3;
|
||||
v3.Cross (v1, v2);
|
||||
a = v1.Angle (v2);
|
||||
float v[3];
|
||||
v3.ToFloat (v);
|
||||
Matrix m;
|
||||
m.FromAxisAngle (v, a);
|
||||
|
||||
glBegin (GL_LINE_LOOP);
|
||||
for (int j = 0; j < 16; j++)
|
||||
{
|
||||
float o[3];
|
||||
v[0] = cos (2.0 * M_PI * j / 16) * 0.15f;
|
||||
v[1] = sin (2.0 * M_PI * j / 16) * 0.15f;
|
||||
v[2] = 0;
|
||||
m.TransformPoint (o, v);
|
||||
glVertex3f (o[0]+x, o[1]+y, o[2]+z);
|
||||
}
|
||||
|
||||
glEnd ();
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
// =============================================================================
|
||||
// Curve class
|
||||
|
||||
void Curve::MinIntersectDist (LC_CLICKLINE* pLine)
|
||||
{
|
||||
// FIXME: Curve segments and tangent arrows
|
||||
|
||||
for (int i = 0; i < m_nNumPoints; i++)
|
||||
{
|
||||
double dist = pLine->PointDistance (m_pPoints[i].m_fPos);
|
||||
|
||||
if ((dist < pLine->mindist) && (dist < LC_CURVE_POINT_RADIUS))
|
||||
{
|
||||
pLine->mindist = dist;
|
||||
pLine->pClosest = this;
|
||||
pLine->pParam = &m_pPoints[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Curve::SetSelection (bool bSelect, void *pParam)
|
||||
{
|
||||
Object::SetSelection (bSelect, pParam);
|
||||
|
||||
if (pParam != NULL)
|
||||
{
|
||||
for (int i = 0; i < m_nNumPoints; i++)
|
||||
if (&m_pPoints[i] == pParam)
|
||||
{
|
||||
if (bSelect)
|
||||
m_pPoints[i].m_nState |= LC_CURVE_POINT_SELECTED;
|
||||
else
|
||||
m_pPoints[i].m_nState &= ~(LC_CURVE_POINT_SELECTED | LC_CURVE_POINT_FOCUSED);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < m_nNumPoints; i++)
|
||||
if (bSelect)
|
||||
m_pPoints[i].m_nState |= LC_CURVE_POINT_SELECTED;
|
||||
else
|
||||
m_pPoints[i].m_nState &= ~(LC_CURVE_POINT_SELECTED | LC_CURVE_POINT_FOCUSED);
|
||||
}
|
||||
}
|
||||
|
||||
void Curve::SetFocus (bool bFocus, void *pParam)
|
||||
{
|
||||
Object::SetFocus (bFocus, pParam);
|
||||
|
||||
if (pParam != NULL)
|
||||
{
|
||||
for (int i = 0; i < m_nNumPoints; i++)
|
||||
if (&m_pPoints[i] == pParam)
|
||||
{
|
||||
if (bFocus)
|
||||
m_pPoints[i].m_nState |= (LC_CURVE_POINT_SELECTED | LC_CURVE_POINT_FOCUSED);
|
||||
else
|
||||
m_pPoints[i].m_nState &= ~LC_CURVE_POINT_FOCUSED;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPoints[i].m_nState &= ~LC_CURVE_POINT_FOCUSED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
127
common/curve.h
Executable file
127
common/curve.h
Executable file
|
@ -0,0 +1,127 @@
|
|||
#ifndef _CURVE_H_
|
||||
#define _CURVE_H_
|
||||
|
||||
#include "object.h"
|
||||
#include "opengl.h"
|
||||
#include "array.h"
|
||||
|
||||
class Curve;
|
||||
class CurvePoint;
|
||||
class PieceInfo;
|
||||
|
||||
//#define LC_CURVE_POINT_HIDDEN 0x01
|
||||
#define LC_CURVE_POINT_SELECTED 0x02
|
||||
#define LC_CURVE_POINT_FOCUSED 0x04
|
||||
#define LC_CURVE_POINT_ARROW1_FOCUSED 0x08
|
||||
#define LC_CURVE_POINT_ARROW2_FOCUSED 0x10
|
||||
#define LC_CURVE_POINT_CONTINUOUS 0x20
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_CURVE_POINT_KEY_POSITION,
|
||||
LC_CURVE_POINT_KEY_DIRECTION1,
|
||||
LC_CURVE_POINT_KEY_DIRECTION2,
|
||||
LC_CURVE_POINT_KEY_ANGLE,
|
||||
LC_CURVE_POINT_KEY_COUNT
|
||||
} LC_CURVE_POINT_KEY_TYPES;
|
||||
|
||||
class CurvePoint : public Object
|
||||
{
|
||||
public:
|
||||
// constructors / destructor
|
||||
CurvePoint (Curve *pParent);
|
||||
CurvePoint (Curve *pParent, const float *pos, const float *dir);
|
||||
virtual ~CurvePoint ();
|
||||
|
||||
// object functions
|
||||
bool FileLoad (File& file);
|
||||
void FileSave (File& file) const;
|
||||
void MinIntersectDist (LC_CLICKLINE* pLine);
|
||||
bool IntersectsVolume(const Vector4* Planes, int NumPlanes)
|
||||
{ return false; }
|
||||
void UpdatePosition (unsigned short nTime, bool bAnimation);
|
||||
void Move (unsigned short nTime, bool bAnimation, bool bAddKey, float dx, float dy, float dz);
|
||||
void Render (LC_RENDER_INFO* pInfo);
|
||||
void Select (bool bSelecting, bool bFocus, bool bMultiple);
|
||||
|
||||
// query functions
|
||||
Curve* GetParent () const
|
||||
{ return m_pParent; }
|
||||
const float* GetPosition () const
|
||||
{ return m_fPos; }
|
||||
const float* GetDirection1 () const
|
||||
{ return m_fDir1; }
|
||||
const float* GetDirection2 () const
|
||||
{ return m_fDir2; }
|
||||
float GetAngle () const
|
||||
{ return m_fAngle; }
|
||||
|
||||
protected:
|
||||
void Initialize ();
|
||||
|
||||
Curve* m_pParent;
|
||||
static GLuint m_nArrowList;
|
||||
static GLuint m_nSphereList;
|
||||
|
||||
unsigned char m_nState;
|
||||
|
||||
// temporary
|
||||
float m_fPos[3];
|
||||
float m_fDir1[3];
|
||||
float m_fDir2[3];
|
||||
float m_fAngle;
|
||||
|
||||
unsigned char m_nLastHit; // FIXME: create arrow objects, ugly hack for now
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
|
||||
#define LC_CURVE_HIDDEN 0x01
|
||||
#define LC_CURVE_SELECTED 0x02
|
||||
#define LC_CURVE_FOCUSED 0x04
|
||||
#define LC_CURVE_LOOP 0x10
|
||||
#define LC_CURVE_FIXED_SIZE 0x20
|
||||
|
||||
// all the different types of curved objects
|
||||
typedef enum
|
||||
{
|
||||
LC_CURVE_TYPE_HOSE
|
||||
} LC_CURVE_TYPE;
|
||||
|
||||
class Curve : public Object
|
||||
{
|
||||
public:
|
||||
// constructors / destructor
|
||||
Curve ();
|
||||
Curve (PieceInfo *pInfo, const float *pos, unsigned char color);
|
||||
virtual ~Curve ();
|
||||
|
||||
// object functions
|
||||
bool FileLoad (File& file);
|
||||
void FileSave (File& file) const;
|
||||
void MinIntersectDist (LC_CLICKLINE* pLine);
|
||||
void UpdatePosition (unsigned short nTime, bool bAnimation);
|
||||
void Move (unsigned short nTime, bool bAnimation, bool bAddKey, float dx, float dy, float dz);
|
||||
void Render (LC_RENDER_INFO* pInfo);
|
||||
void Select (bool bSelecting, bool bFocus, bool bMultiple);
|
||||
|
||||
// implementation
|
||||
void DeselectOtherPoints (CurvePoint *pSender, bool bFocusOnly);
|
||||
|
||||
protected:
|
||||
void Initialize ();
|
||||
void TesselateHose ();
|
||||
|
||||
LC_CURVE_TYPE m_nCurveType;
|
||||
unsigned char m_nState;
|
||||
unsigned char m_nColor;
|
||||
float m_fLength;
|
||||
|
||||
float m_fUp0[3];
|
||||
|
||||
GLuint m_nDisplayList;
|
||||
|
||||
PtrArray<CurvePoint> m_Points;
|
||||
};
|
||||
|
||||
#endif // _CURVE_H_
|
100
common/debug.cpp
Normal file
100
common/debug.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
#include "opengl.h"
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef LC_DEBUG
|
||||
|
||||
#define LC_MAX_DEBUG_LINES 100
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Vector3 pt1;
|
||||
Vector3 pt2;
|
||||
Vector3 color;
|
||||
} LC_DEBUG_LINE;
|
||||
|
||||
static LC_DEBUG_LINE DebugLines[LC_MAX_DEBUG_LINES];
|
||||
static int NumDebugLines;
|
||||
|
||||
void ClearDebugLines()
|
||||
{
|
||||
NumDebugLines = 0;
|
||||
}
|
||||
|
||||
void AddDebugLine(const Vector3& pt1, const Vector3& pt2, const Vector3& Color)
|
||||
{
|
||||
if (NumDebugLines == LC_MAX_DEBUG_LINES-1)
|
||||
return;
|
||||
|
||||
DebugLines[NumDebugLines].pt1 = pt1;
|
||||
DebugLines[NumDebugLines].pt2 = pt2;
|
||||
DebugLines[NumDebugLines].color = Color;
|
||||
NumDebugLines++;
|
||||
}
|
||||
|
||||
#define LC_MAX_DEBUG_QUADS 100
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Vector3 pt1;
|
||||
Vector3 pt2;
|
||||
Vector3 pt3;
|
||||
Vector3 pt4;
|
||||
Vector4 color;
|
||||
} LC_DEBUG_QUAD;
|
||||
|
||||
static LC_DEBUG_QUAD DebugQuads[LC_MAX_DEBUG_QUADS];
|
||||
static int NumDebugQuads;
|
||||
|
||||
void ClearDebugQuads()
|
||||
{
|
||||
NumDebugQuads = 0;
|
||||
}
|
||||
|
||||
void AddDebugQuad(const Vector3& pt1, const Vector3& pt2, const Vector3& pt3, const Vector3& pt4, const Vector4& Color)
|
||||
{
|
||||
if (NumDebugQuads == LC_MAX_DEBUG_QUADS-1)
|
||||
return;
|
||||
|
||||
DebugQuads[NumDebugQuads].pt1 = pt1;
|
||||
DebugQuads[NumDebugQuads].pt2 = pt2;
|
||||
DebugQuads[NumDebugQuads].pt3 = pt3;
|
||||
DebugQuads[NumDebugQuads].pt4 = pt4;
|
||||
DebugQuads[NumDebugQuads].color = Color;
|
||||
NumDebugQuads++;
|
||||
}
|
||||
|
||||
void RenderDebugPrimitives()
|
||||
{
|
||||
glBegin(GL_LINES);
|
||||
|
||||
for (int i = 0; i < NumDebugLines; i++)
|
||||
{
|
||||
glColor3fv((float*)&DebugLines[i].color);
|
||||
glVertex3fv((float*)&DebugLines[i].pt1);
|
||||
glVertex3fv((float*)&DebugLines[i].pt2);
|
||||
}
|
||||
|
||||
glEnd();
|
||||
|
||||
glDepthMask(GL_FALSE);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
for (int i = 0; i < NumDebugQuads; i++)
|
||||
{
|
||||
glColor4fv((float*)&DebugQuads[i].color);
|
||||
glVertex3fv((float*)&DebugQuads[i].pt1);
|
||||
glVertex3fv((float*)&DebugQuads[i].pt2);
|
||||
glVertex3fv((float*)&DebugQuads[i].pt3);
|
||||
glVertex3fv((float*)&DebugQuads[i].pt4);
|
||||
}
|
||||
|
||||
glEnd();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
#endif // LC_DEBUG
|
17
common/debug.h
Normal file
17
common/debug.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef _DEBUG_H_
|
||||
#define _DEBUG_H_
|
||||
#ifdef LC_DEBUG
|
||||
|
||||
#include "algebra.h"
|
||||
|
||||
void RenderDebugPrimitives();
|
||||
|
||||
void AddDebugLine(const Vector3& pt1, const Vector3& pt2, const Vector3& Color);
|
||||
void ClearDebugLines();
|
||||
|
||||
void AddDebugQuad(const Vector3& pt1, const Vector3& pt2, const Vector3& pt3, const Vector3& pt4, const Vector4& Color);
|
||||
void ClearDebugQuads();
|
||||
|
||||
|
||||
#endif // LC_DEBUG
|
||||
#endif // _DEBUG_H_
|
218
common/defines.h
Normal file
218
common/defines.h
Normal file
|
@ -0,0 +1,218 @@
|
|||
// Constant definitions.
|
||||
//
|
||||
|
||||
#ifndef _DEFINES_H_
|
||||
#define _DEFINES_H_
|
||||
|
||||
// Check for supported platforms.
|
||||
#if !(defined(LC_WINDOWS) || defined(LC_LINUX) || defined(LC_MACOSX))
|
||||
#error YOU NEED TO DEFINE YOUR OS
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// Old defines (mostly deprecated).
|
||||
|
||||
#ifdef LC_WINDOWS
|
||||
#define LC_MAXPATH 260 //_MAX_PATH
|
||||
#define KEY_SHIFT VK_SHIFT
|
||||
#define KEY_CONTROL VK_CONTROL
|
||||
#define KEY_ESCAPE VK_ESCAPE
|
||||
#define KEY_TAB VK_TAB
|
||||
#define KEY_INSERT VK_INSERT
|
||||
#define KEY_DELETE VK_DELETE
|
||||
#define KEY_UP VK_UP
|
||||
#define KEY_DOWN VK_DOWN
|
||||
#define KEY_LEFT VK_LEFT
|
||||
#define KEY_RIGHT VK_RIGHT
|
||||
#define KEY_PRIOR VK_PRIOR
|
||||
#define KEY_NEXT VK_NEXT
|
||||
#define KEY_PLUS VK_ADD
|
||||
#define KEY_MINUS VK_SUBTRACT
|
||||
#endif
|
||||
|
||||
#ifdef LC_LINUX
|
||||
#define LC_MAXPATH 1024 //FILENAME_MAX
|
||||
#define KEY_SHIFT 0x01
|
||||
#define KEY_CONTROL 0x02
|
||||
#define KEY_ESCAPE 0x03
|
||||
#define KEY_TAB 0x04
|
||||
#define KEY_INSERT 0x05
|
||||
#define KEY_DELETE 0x06
|
||||
#define KEY_UP 0x07
|
||||
#define KEY_DOWN 0x08
|
||||
#define KEY_LEFT 0x09
|
||||
#define KEY_RIGHT 0x0A
|
||||
#define KEY_PRIOR 0x0B
|
||||
#define KEY_NEXT 0x0C
|
||||
#define KEY_PLUS '+'
|
||||
#define KEY_MINUS '-'
|
||||
|
||||
char* strupr(char* string);
|
||||
char* strlwr(char* string);
|
||||
int stricmp(const char* str1, const char* str2);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef LC_MACOSX
|
||||
#include <sys/param.h>
|
||||
#define LC_MAXPATH MAXPATHLEN //FILENAME_MAX
|
||||
|
||||
#define KEY_SHIFT 0x01
|
||||
#define KEY_CONTROL 0x02
|
||||
#define KEY_ESCAPE 0x03
|
||||
#define KEY_TAB 0x04
|
||||
#define KEY_INSERT 0x05
|
||||
#define KEY_DELETE 0x06
|
||||
#define KEY_UP 0x07
|
||||
#define KEY_DOWN 0x08
|
||||
#define KEY_LEFT 0x09
|
||||
#define KEY_RIGHT 0x0A
|
||||
#define KEY_PRIOR 0x0B
|
||||
#define KEY_NEXT 0x0C
|
||||
#define KEY_PLUS '+'
|
||||
#define KEY_MINUS '-'
|
||||
|
||||
char* strupr(char* string);
|
||||
char* strlwr(char* string);
|
||||
int stricmp(const char* str1, const char* str2);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// LeoCAD constants
|
||||
|
||||
// Math numbers.
|
||||
#define LC_DTOR 0.017453f
|
||||
#define LC_RTOD 57.29578f
|
||||
#define LC_PI 3.141592f
|
||||
#define LC_2PI 6.283185f
|
||||
|
||||
|
||||
#define DTOR 0.017453f
|
||||
#define RTOD 57.29578f
|
||||
#define PI 3.14159265
|
||||
#define PI2 6.28318530
|
||||
|
||||
#ifndef min
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef ABS
|
||||
#define ABS(a) (((a) > 0) ? (a) : -(a))
|
||||
#endif
|
||||
|
||||
#ifndef LC_WINDOWS
|
||||
#define RGB(r, g, b) ((unsigned long)(((unsigned char) (r) | ((unsigned short) (g) << 8))|(((unsigned long) (unsigned char) (b)) << 16)))
|
||||
#endif
|
||||
|
||||
#define FLOATRGB(f) RGB(f[0]*255, f[1]*255, f[2]*255)
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265
|
||||
#endif
|
||||
|
||||
#define LC_FOURCC(ch0, ch1, ch2, ch3) (lcuint32)((lcuint32)(lcuint8)(ch0) | ((lcuint32)(lcuint8)(ch1) << 8) | \
|
||||
((lcuint32)(lcuint8)(ch2) << 16) | ((lcuint32)(lcuint8)(ch3) << 24 ))
|
||||
|
||||
#define LC_FILE_ID LC_FOURCC('L','C','D', 0)
|
||||
|
||||
#define LC_CONNECTIONS 2 // Different piece connections
|
||||
#define LC_STR_VERSION "LeoCAD 0.7 Project\0\0" // char[20]
|
||||
|
||||
#define LC_MAXCOLORS 28 // Number of colors supported
|
||||
#define LC_COL_EDGES 28 // Piece edges
|
||||
#define LC_COL_SELECTED 29 // Selected object
|
||||
#define LC_COL_FOCUSED 30 // Focused object
|
||||
#define LC_COL_DEFAULT 31 // Default piece color
|
||||
|
||||
|
||||
// #define DET_BACKFACES 0x00001 // Draw backfaces
|
||||
// #define DET_DEPTH 0x00002 // Enable depth test
|
||||
// #define DET_CLEAR 0x00004 // Use clear colors
|
||||
#define LC_DET_LIGHTING 0x00008 // Lighting
|
||||
#define LC_DET_SMOOTH 0x00010 // Smooth shading
|
||||
// #define DET_STUDS 0x00020 // Draw studs
|
||||
// #define DET_WIREFRAME 0x00040 // Wireframe
|
||||
#define LC_DET_ANTIALIAS 0x00080 // Turn on anti-aliasing
|
||||
#define LC_DET_BRICKEDGES 0x00100 // Draw lines
|
||||
#define LC_DET_DITHER 0x00200 // Enable dithering
|
||||
#define LC_DET_BOX_FILL 0x00400 // Filled boxes
|
||||
#define LC_DET_HIDDEN_LINE 0x00800 // Remove hidden lines
|
||||
// #define DET_STUDS_BOX 0x01000 // Draw studs as boxes
|
||||
#define LC_DET_LINEAR 0x02000 // Linear filtering
|
||||
#define LC_DET_FAST 0x04000 // Fast rendering (boxes)
|
||||
#define LC_DET_BACKGROUND 0x08000 // Background rendering
|
||||
//#define LC_DET_SCREENDOOR 0x10000 // No alpha blending
|
||||
|
||||
#define LC_DRAW_AXIS 0x0001 // Orientation icon
|
||||
#define LC_DRAW_GRID 0x0002 // Grid
|
||||
#define LC_DRAW_SNAP_A 0x0004 // Snap Angle
|
||||
#define LC_DRAW_SNAP_X 0x0008 // Snap X
|
||||
#define LC_DRAW_SNAP_Y 0x0010 // Snap Y
|
||||
#define LC_DRAW_SNAP_Z 0x0020 // Snap Z
|
||||
#define LC_DRAW_SNAP_XYZ (LC_DRAW_SNAP_X | LC_DRAW_SNAP_Y | LC_DRAW_SNAP_Z)
|
||||
#define LC_DRAW_GLOBAL_SNAP 0x0040 // Don't allow relative snap.
|
||||
#define LC_DRAW_MOVE 0x0080 // Switch to move after insert
|
||||
#define LC_DRAW_LOCK_X 0x0100 // Lock X
|
||||
#define LC_DRAW_LOCK_Y 0x0200 // Lock Y
|
||||
#define LC_DRAW_LOCK_Z 0x0400 // Lock Z
|
||||
#define LC_DRAW_LOCK_XYZ (LC_DRAW_LOCK_X | LC_DRAW_LOCK_Y | LC_DRAW_LOCK_Z)
|
||||
#define LC_DRAW_MOVEAXIS 0x0800 // Move on fixed axis
|
||||
//#define LC_DRAW_PREVIEW 0x1000 // Show piece position
|
||||
#define LC_DRAW_CM_UNITS 0x2000 // Use centimeters
|
||||
//#define LC_DRAW_3DMOUSE 0x4000 // Mouse moves in all directions
|
||||
|
||||
// #define RENDER_FAST 0x001
|
||||
// #define RENDER_BACKGROUND 0x002
|
||||
#define LC_SCENE_FOG 0x004 // Enable fog
|
||||
// #define RENDER_FOG_BG 0x008 // Use bg color for fog
|
||||
#define LC_SCENE_BG 0x010 // Draw bg image
|
||||
// #define RENDER_BG_FAST 0x020
|
||||
#define LC_SCENE_BG_TILE 0x040 // Tile bg image
|
||||
#define LC_SCENE_FLOOR 0x080 // Render floor
|
||||
#define LC_SCENE_GRADIENT 0x100 // Draw gradient
|
||||
|
||||
#define LC_TERRAIN_FLAT 0x01 // Flat terrain
|
||||
#define LC_TERRAIN_TEXTURE 0x02 // Use texture
|
||||
#define LC_TERRAIN_SMOOTH 0x04 // Smooth shading
|
||||
|
||||
#define LC_AUTOSAVE_FLAG 0x100000 // Enable auto-saving
|
||||
|
||||
#define LC_SEL_NO_PIECES 0x001 // No pieces in the project
|
||||
#define LC_SEL_PIECE 0x002 // piece selected
|
||||
#define LC_SEL_CAMERA 0x004 // camera selected
|
||||
#define LC_SEL_LIGHT 0x010 // light selected
|
||||
#define LC_SEL_MULTIPLE 0x020 // multiple pieces selected
|
||||
#define LC_SEL_UNSELECTED 0x040 // at least 1 piece unselected
|
||||
#define LC_SEL_HIDDEN 0x080 // at least one piece hidden
|
||||
#define LC_SEL_GROUP 0x100 // at least one piece selected is grouped
|
||||
#define LC_SEL_FOCUSGROUP 0x200 // focused piece is grouped
|
||||
#define LC_SEL_CANGROUP 0x400 // can make a new group
|
||||
|
||||
// Image Options
|
||||
#define LC_IMAGE_PROGRESSIVE 0x1000
|
||||
#define LC_IMAGE_TRANSPARENT 0x2000
|
||||
#define LC_IMAGE_HIGHCOLOR 0x4000
|
||||
#define LC_IMAGE_MASK 0x7000
|
||||
|
||||
// HTML export options
|
||||
#define LC_HTML_SINGLEPAGE 0x01
|
||||
#define LC_HTML_INDEX 0x02
|
||||
#define LC_HTML_IMAGES 0x04
|
||||
#define LC_HTML_LISTEND 0x08
|
||||
#define LC_HTML_LISTSTEP 0x10
|
||||
#define LC_HTML_HIGHLIGHT 0x20
|
||||
#define LC_HTML_HTMLEXT 0x40
|
||||
|
||||
// Piece library update
|
||||
#define LC_UPDATE_DELETE 0x00
|
||||
#define LC_UPDATE_DESCRIPTION 0x01
|
||||
#define LC_UPDATE_DRAWINFO 0x02
|
||||
#define LC_UPDATE_NEWPIECE 0x04
|
||||
|
||||
#endif // _DEFINES_H_
|
571
common/file.cpp
Normal file
571
common/file.cpp
Normal file
|
@ -0,0 +1,571 @@
|
|||
// File class, can be a memory file or in the disk.
|
||||
// Needed to work with the clipboard and undo/redo easily.
|
||||
// NOTE: Because of endianess issues, all I/O must be done from a File class.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "file.h"
|
||||
#include "defines.h"
|
||||
#include "config.h"
|
||||
#include "str.h"
|
||||
|
||||
// =============================================================================
|
||||
// File construction/destruction
|
||||
|
||||
File::File ()
|
||||
{
|
||||
strcpy(FileName, "");
|
||||
}
|
||||
|
||||
File::~File ()
|
||||
{
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Endian-safe functions
|
||||
|
||||
// reads 1-byte integers
|
||||
unsigned long File::ReadByte (void* pBuf, unsigned long nCount)
|
||||
{
|
||||
return Read (pBuf, nCount);
|
||||
}
|
||||
|
||||
// reads 2-byte integers
|
||||
unsigned long File::ReadShort (void* pBuf, unsigned long nCount)
|
||||
{
|
||||
unsigned long read;
|
||||
|
||||
read = Read (pBuf, nCount*2)/2;
|
||||
|
||||
#ifdef LC_BIG_ENDIAN
|
||||
unsigned long i;
|
||||
lcuint16* val = (lcuint16*)pBuf, x;
|
||||
|
||||
for (i = 0; i < read; i++)
|
||||
{
|
||||
x = *val;
|
||||
*val = ((x>>8) | (x<<8));
|
||||
val++;
|
||||
}
|
||||
#endif
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
// reads 4-byte integers
|
||||
unsigned long File::ReadLong (void* pBuf, unsigned long nCount)
|
||||
{
|
||||
unsigned long read;
|
||||
|
||||
read = Read (pBuf, nCount*4)/4;
|
||||
|
||||
#ifdef LC_BIG_ENDIAN
|
||||
unsigned long i;
|
||||
lcuint32* val = (lcuint32*)pBuf, x;
|
||||
|
||||
for (i = 0; i < read; i++)
|
||||
{
|
||||
x = *val;
|
||||
*val = ((x>>24) | ((x>>8) & 0xff00) | ((x<<8) & 0xff0000) | (x<<24));
|
||||
val++;
|
||||
}
|
||||
#endif
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
// reads 4-byte floats
|
||||
unsigned long File::ReadFloat (void* pBuf, unsigned long nCount)
|
||||
{
|
||||
unsigned long read;
|
||||
|
||||
read = Read (pBuf, nCount*4)/4;
|
||||
|
||||
#ifdef LC_BIG_ENDIAN
|
||||
unsigned long i;
|
||||
float* val = (float*)pBuf;
|
||||
union { unsigned char b[4]; float f; } in, out;
|
||||
|
||||
for (i = 0; i < read; i++)
|
||||
{
|
||||
in.f = *val;
|
||||
|
||||
out.b[0] = in.b[3];
|
||||
out.b[1] = in.b[2];
|
||||
out.b[2] = in.b[1];
|
||||
out.b[3] = in.b[0];
|
||||
|
||||
*val = out.f;
|
||||
val++;
|
||||
}
|
||||
#endif
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
// reads 8-byte floats
|
||||
unsigned long File::ReadDouble (void* pBuf, unsigned long nCount)
|
||||
{
|
||||
unsigned long read;
|
||||
|
||||
read = Read (pBuf, nCount*8)/8;
|
||||
|
||||
#ifdef LC_BIG_ENDIAN
|
||||
unsigned long i;
|
||||
double* val = (double*)pBuf;
|
||||
union { unsigned char b[8]; double d; } in, out;
|
||||
|
||||
for (i = 0; i < read; i++)
|
||||
{
|
||||
in.d = *val;
|
||||
|
||||
out.b[0] = in.b[7];
|
||||
out.b[1] = in.b[6];
|
||||
out.b[2] = in.b[5];
|
||||
out.b[3] = in.b[4];
|
||||
out.b[4] = in.b[3];
|
||||
out.b[5] = in.b[2];
|
||||
out.b[6] = in.b[1];
|
||||
out.b[7] = in.b[0];
|
||||
|
||||
*val = out.d;
|
||||
val++;
|
||||
}
|
||||
#endif
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
// writes 1-byte integers
|
||||
unsigned long File::WriteByte (const void* pBuf, unsigned long nCount)
|
||||
{
|
||||
return Write (pBuf, nCount);
|
||||
}
|
||||
|
||||
// writes 2-byte integers
|
||||
unsigned long File::WriteShort (const void* pBuf, unsigned long nCount)
|
||||
{
|
||||
#ifdef LC_BIG_ENDIAN
|
||||
unsigned long wrote = 0, i;
|
||||
lcuint16* val = (lcuint16*)pBuf, x;
|
||||
|
||||
for (i = 0; i < nCount; i++)
|
||||
{
|
||||
x = (((*val)>>8) | ((*val)<<8));
|
||||
val++;
|
||||
wrote += Write (&x, 2)/2;
|
||||
}
|
||||
|
||||
return wrote;
|
||||
#else
|
||||
return Write(pBuf, nCount*2)/2;
|
||||
#endif
|
||||
}
|
||||
|
||||
// writes 4-byte integers
|
||||
unsigned long File::WriteLong (const void* pBuf, unsigned long nCount)
|
||||
{
|
||||
#ifdef LC_BIG_ENDIAN
|
||||
unsigned long wrote = 0, i;
|
||||
lcuint32* val = (lcuint32*)pBuf, x;
|
||||
|
||||
for (i = 0; i < nCount; i++)
|
||||
{
|
||||
x = (((*val)>>24) | (((*val)>>8) & 0xff00) | (((*val)<<8) & 0xff0000) | ((*val)<<24));
|
||||
val++;
|
||||
wrote += Write (&x, 4)/4;
|
||||
}
|
||||
|
||||
return wrote;
|
||||
#else
|
||||
return Write (pBuf, nCount*4)/4;
|
||||
#endif
|
||||
}
|
||||
|
||||
// writes 4-byte floats
|
||||
unsigned long File::WriteFloat (const void* pBuf, unsigned long nCount)
|
||||
{
|
||||
#ifdef LC_BIG_ENDIAN
|
||||
unsigned long wrote = 0, i;
|
||||
float* val = (float*)pBuf, x;
|
||||
union { unsigned char b[4]; float f; } in, out;
|
||||
|
||||
for (i = 0; i < nCount; i++)
|
||||
{
|
||||
in.f = *val;
|
||||
val++;
|
||||
|
||||
out.b[0] = in.b[3];
|
||||
out.b[1] = in.b[2];
|
||||
out.b[2] = in.b[1];
|
||||
out.b[3] = in.b[0];
|
||||
x = out.f;
|
||||
|
||||
wrote += Write (&x, 4)/4;
|
||||
}
|
||||
|
||||
return wrote;
|
||||
#else
|
||||
return Write (pBuf, nCount*4)/4;
|
||||
#endif
|
||||
}
|
||||
|
||||
// writes 8-byte floats
|
||||
unsigned long File::WriteDouble (const void* pBuf, unsigned long nCount)
|
||||
{
|
||||
#ifdef LC_BIG_ENDIAN
|
||||
unsigned long wrote = 0, i;
|
||||
double* val = (double*)pBuf, x;
|
||||
union { unsigned char b[8]; double d; } in, out;
|
||||
|
||||
for (i = 0; i < nCount; i++)
|
||||
{
|
||||
in.d = *val;
|
||||
val++;
|
||||
|
||||
out.b[0] = in.b[7];
|
||||
out.b[1] = in.b[6];
|
||||
out.b[2] = in.b[5];
|
||||
out.b[3] = in.b[4];
|
||||
out.b[4] = in.b[3];
|
||||
out.b[5] = in.b[2];
|
||||
out.b[6] = in.b[1];
|
||||
out.b[7] = in.b[0];
|
||||
x = out.d;
|
||||
|
||||
wrote += Write (&x, 8)/8;
|
||||
}
|
||||
|
||||
return wrote;
|
||||
#else
|
||||
return Write (pBuf, nCount*8)/8;
|
||||
#endif
|
||||
}
|
||||
|
||||
void File::ReadString(String& Value)
|
||||
{
|
||||
lcuint32 l;
|
||||
ReadInt(&l);
|
||||
Read(Value.GetBuffer(l+1), l);
|
||||
((char*)Value)[l] = 0;
|
||||
}
|
||||
|
||||
void File::WriteString(const String& Value)
|
||||
{
|
||||
WriteInt(Value.GetLength());
|
||||
Write((const char*)Value, Value.GetLength());
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
FileMem::FileMem()
|
||||
{
|
||||
m_nGrowBytes = 1024;
|
||||
m_nPosition = 0;
|
||||
m_nBufferSize = 0;
|
||||
m_nFileSize = 0;
|
||||
m_pBuffer = NULL;
|
||||
m_bAutoDelete = true;
|
||||
}
|
||||
|
||||
FileDisk::FileDisk()
|
||||
{
|
||||
m_hFile = NULL;
|
||||
m_bCloseOnDelete = false;
|
||||
}
|
||||
|
||||
FileMem::~FileMem()
|
||||
{
|
||||
if (m_pBuffer)
|
||||
Close();
|
||||
|
||||
m_nGrowBytes = 0;
|
||||
m_nPosition = 0;
|
||||
m_nBufferSize = 0;
|
||||
m_nFileSize = 0;
|
||||
}
|
||||
|
||||
FileDisk::~FileDisk()
|
||||
{
|
||||
if (m_hFile != NULL && m_bCloseOnDelete)
|
||||
Close();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// File operations
|
||||
|
||||
char* FileMem::ReadLine(char* pBuf, unsigned long nMax)
|
||||
{
|
||||
int nRead = 0;
|
||||
unsigned char ch;
|
||||
|
||||
if (nMax <= 0)
|
||||
return NULL;
|
||||
if (m_nPosition >= m_nFileSize)
|
||||
return NULL;
|
||||
|
||||
while ((--nMax))
|
||||
{
|
||||
if (m_nPosition == m_nFileSize)
|
||||
break;
|
||||
|
||||
ch = m_pBuffer[m_nPosition];
|
||||
m_nPosition++;
|
||||
pBuf[nRead++] = ch;
|
||||
|
||||
if (ch == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
pBuf[nRead] = '\0';
|
||||
return pBuf;
|
||||
}
|
||||
|
||||
char* FileDisk::ReadLine(char* pBuf, unsigned long nMax)
|
||||
{
|
||||
return fgets(pBuf, nMax, m_hFile);
|
||||
}
|
||||
|
||||
unsigned long FileMem::Read(void* pBuf, unsigned long nCount)
|
||||
{
|
||||
if (nCount == 0)
|
||||
return 0;
|
||||
|
||||
if (m_nPosition > m_nFileSize)
|
||||
return 0;
|
||||
|
||||
unsigned long nRead;
|
||||
if (m_nPosition + nCount > m_nFileSize)
|
||||
nRead = (unsigned long)(m_nFileSize - m_nPosition);
|
||||
else
|
||||
nRead = nCount;
|
||||
|
||||
memcpy((unsigned char*)pBuf, (unsigned char*)m_pBuffer + m_nPosition, nRead);
|
||||
m_nPosition += nRead;
|
||||
|
||||
return nRead;
|
||||
}
|
||||
|
||||
unsigned long FileDisk::Read(void* pBuf, unsigned long nCount)
|
||||
{
|
||||
return fread(pBuf, 1, nCount, m_hFile);
|
||||
}
|
||||
|
||||
int FileMem::GetChar()
|
||||
{
|
||||
if (m_nPosition > m_nFileSize)
|
||||
return EOF;
|
||||
|
||||
unsigned char* ret = (unsigned char*)m_pBuffer + m_nPosition;
|
||||
m_nPosition++;
|
||||
|
||||
return *ret;
|
||||
}
|
||||
|
||||
int FileDisk::GetChar()
|
||||
{
|
||||
return fgetc(m_hFile);
|
||||
}
|
||||
|
||||
unsigned long FileMem::Write(const void* pBuf, unsigned long nCount)
|
||||
{
|
||||
if (nCount == 0)
|
||||
return 0;
|
||||
|
||||
if (m_nPosition + nCount > m_nBufferSize)
|
||||
GrowFile(m_nPosition + nCount);
|
||||
|
||||
memcpy((unsigned char*)m_pBuffer + m_nPosition, (unsigned char*)pBuf, nCount);
|
||||
|
||||
m_nPosition += nCount;
|
||||
|
||||
if (m_nPosition > m_nFileSize)
|
||||
m_nFileSize = m_nPosition;
|
||||
|
||||
return nCount;
|
||||
}
|
||||
|
||||
unsigned long FileDisk::Write(const void* pBuf, unsigned long nCount)
|
||||
{
|
||||
return fwrite(pBuf, 1, nCount, m_hFile);
|
||||
}
|
||||
|
||||
int FileMem::PutChar(int c)
|
||||
{
|
||||
if (m_nPosition + 1 > m_nBufferSize)
|
||||
GrowFile(m_nPosition + 1);
|
||||
|
||||
unsigned char* bt = (unsigned char*)m_pBuffer + m_nPosition;
|
||||
*bt = c;
|
||||
|
||||
m_nPosition++;
|
||||
|
||||
if (m_nPosition > m_nFileSize)
|
||||
m_nFileSize = m_nPosition;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FileDisk::PutChar(int c)
|
||||
{
|
||||
return fputc(c, m_hFile);
|
||||
}
|
||||
|
||||
bool FileDisk::Open(const char *filename, const char *mode)
|
||||
{
|
||||
if (*filename == 0)
|
||||
return false;
|
||||
|
||||
strcpy(FileName, filename);
|
||||
|
||||
m_hFile = fopen(filename, mode);
|
||||
m_bCloseOnDelete = true;
|
||||
|
||||
return (m_hFile != NULL);
|
||||
}
|
||||
|
||||
void FileMem::Close()
|
||||
{
|
||||
m_nGrowBytes = 0;
|
||||
m_nPosition = 0;
|
||||
m_nBufferSize = 0;
|
||||
m_nFileSize = 0;
|
||||
if (m_pBuffer && m_bAutoDelete)
|
||||
free(m_pBuffer);
|
||||
m_pBuffer = NULL;
|
||||
strcpy(FileName, "");
|
||||
}
|
||||
|
||||
void FileDisk::Close()
|
||||
{
|
||||
if (m_hFile != NULL)
|
||||
fclose(m_hFile);
|
||||
|
||||
m_hFile = NULL;
|
||||
m_bCloseOnDelete = false;
|
||||
strcpy(FileName, "");
|
||||
}
|
||||
|
||||
unsigned long FileMem::Seek(long lOff, int nFrom)
|
||||
{
|
||||
unsigned long lNewPos = m_nPosition;
|
||||
|
||||
if (nFrom == SEEK_SET)
|
||||
lNewPos = lOff;
|
||||
else if (nFrom == SEEK_CUR)
|
||||
lNewPos += lOff;
|
||||
else if (nFrom == SEEK_END)
|
||||
lNewPos = m_nFileSize + lOff;
|
||||
else
|
||||
return (unsigned long)-1;
|
||||
|
||||
m_nPosition = lNewPos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long FileDisk::Seek(long lOff, int nFrom)
|
||||
{
|
||||
fseek (m_hFile, lOff, nFrom);
|
||||
|
||||
return ftell(m_hFile);
|
||||
}
|
||||
|
||||
unsigned long FileMem::GetPosition() const
|
||||
{
|
||||
return m_nPosition;
|
||||
}
|
||||
|
||||
unsigned long FileDisk::GetPosition() const
|
||||
{
|
||||
return ftell(m_hFile);
|
||||
}
|
||||
|
||||
void FileMem::GrowFile(unsigned long nNewLen)
|
||||
{
|
||||
if (nNewLen > m_nBufferSize)
|
||||
{
|
||||
// grow the buffer
|
||||
unsigned long nNewBufferSize = m_nBufferSize;
|
||||
|
||||
// determine new buffer size
|
||||
while (nNewBufferSize < nNewLen)
|
||||
nNewBufferSize += m_nGrowBytes;
|
||||
|
||||
// allocate new buffer
|
||||
unsigned char* lpNew;
|
||||
if (m_pBuffer == NULL)
|
||||
lpNew = (unsigned char*)malloc(nNewBufferSize);
|
||||
else
|
||||
lpNew = (unsigned char*)realloc(m_pBuffer, nNewBufferSize);
|
||||
|
||||
m_pBuffer = lpNew;
|
||||
m_nBufferSize = nNewBufferSize;
|
||||
}
|
||||
}
|
||||
|
||||
void FileMem::Flush()
|
||||
{
|
||||
// Nothing to be done
|
||||
}
|
||||
|
||||
void FileDisk::Flush()
|
||||
{
|
||||
if (m_hFile == NULL)
|
||||
return;
|
||||
|
||||
fflush(m_hFile);
|
||||
}
|
||||
|
||||
void FileMem::Abort()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void FileDisk::Abort()
|
||||
{
|
||||
if (m_hFile != NULL)
|
||||
{
|
||||
// close but ignore errors
|
||||
if (m_bCloseOnDelete)
|
||||
fclose(m_hFile);
|
||||
m_hFile = NULL;
|
||||
m_bCloseOnDelete = false;
|
||||
}
|
||||
}
|
||||
|
||||
void FileMem::SetLength(unsigned long nNewLen)
|
||||
{
|
||||
if (nNewLen > m_nBufferSize)
|
||||
GrowFile(nNewLen);
|
||||
|
||||
if (nNewLen < m_nPosition)
|
||||
m_nPosition = nNewLen;
|
||||
|
||||
m_nFileSize = nNewLen;
|
||||
}
|
||||
|
||||
void FileDisk::SetLength(unsigned long nNewLen)
|
||||
{
|
||||
fseek(m_hFile, nNewLen, SEEK_SET);
|
||||
}
|
||||
|
||||
unsigned long FileMem::GetLength() const
|
||||
{
|
||||
return m_nFileSize;
|
||||
}
|
||||
|
||||
unsigned long FileDisk::GetLength() const
|
||||
{
|
||||
unsigned long nLen, nCur;
|
||||
|
||||
// Seek is a non const operation
|
||||
nCur = ftell(m_hFile);
|
||||
fseek(m_hFile, 0, SEEK_END);
|
||||
nLen = ftell(m_hFile);
|
||||
fseek(m_hFile, nCur, SEEK_SET);
|
||||
|
||||
return nLen;
|
||||
}
|
140
common/file.h
Normal file
140
common/file.h
Normal file
|
@ -0,0 +1,140 @@
|
|||
#ifndef _FILE_H_
|
||||
#define _FILE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "defines.h"
|
||||
#include "config.h"
|
||||
|
||||
class String;
|
||||
|
||||
class File
|
||||
{
|
||||
public:
|
||||
// Constructors
|
||||
File();
|
||||
virtual ~File();
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
virtual unsigned long GetPosition() const = 0;
|
||||
virtual unsigned long Seek(long lOff, int nFrom) = 0;
|
||||
virtual void SetLength(unsigned long nNewLen) = 0;
|
||||
virtual unsigned long GetLength() const = 0;
|
||||
|
||||
virtual char* ReadLine(char* pBuf, unsigned long nMax)=0;
|
||||
virtual unsigned long Read(void* pBuf, unsigned long nCount)=0;
|
||||
virtual unsigned long Write(const void* pBuf, unsigned long nCount)=0;
|
||||
virtual int GetChar()=0;
|
||||
virtual int PutChar(int c)=0;
|
||||
|
||||
unsigned long ReadByte(void* pBuf, unsigned long nCount);
|
||||
unsigned long ReadShort(void* pBuf, unsigned long nCount);
|
||||
unsigned long ReadLong(void* pBuf, unsigned long nCount);
|
||||
unsigned long ReadFloat(void* pBuf, unsigned long nCount);
|
||||
unsigned long ReadDouble(void* pBuf, unsigned long nCount);
|
||||
unsigned long WriteByte(const void* pBuf, unsigned long nCount);
|
||||
unsigned long WriteShort(const void* pBuf, unsigned long nCount);
|
||||
unsigned long WriteLong(const void* pBuf, unsigned long nCount);
|
||||
unsigned long WriteFloat(const void* pBuf, unsigned long nCount);
|
||||
unsigned long WriteDouble(const void* pBuf, unsigned long nCount);
|
||||
|
||||
void ReadString(String& Value);
|
||||
void ReadInt(lcint32* Value)
|
||||
{ ReadLong(Value, 1); }
|
||||
void ReadInt(lcuint32* Value)
|
||||
{ ReadLong(Value, 1); }
|
||||
|
||||
void WriteString(const String& Value);
|
||||
void WriteInt(lcint32 Value)
|
||||
{ WriteLong(&Value, 1); }
|
||||
void WriteInt(lcuint32 Value)
|
||||
{ WriteLong(&Value, 1); }
|
||||
|
||||
virtual void Abort()=0;
|
||||
virtual void Flush()=0;
|
||||
virtual void Close()=0;
|
||||
|
||||
const char* GetFileName() const
|
||||
{ return FileName; }
|
||||
|
||||
void SetFileName(const char* Name)
|
||||
{ strncpy(FileName, Name, LC_MAXPATH); }
|
||||
|
||||
protected:
|
||||
char FileName[LC_MAXPATH];
|
||||
};
|
||||
|
||||
class FileMem : public File
|
||||
{
|
||||
public:
|
||||
// Constructors
|
||||
FileMem();
|
||||
~FileMem();
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
unsigned long GetPosition() const;
|
||||
unsigned long Seek(long lOff, int nFrom);
|
||||
void SetLength(unsigned long nNewLen);
|
||||
unsigned long GetLength() const;
|
||||
|
||||
char* ReadLine(char* pBuf, unsigned long nMax);
|
||||
unsigned long Read(void* pBuf, unsigned long nCount);
|
||||
unsigned long Write(const void* pBuf, unsigned long nCount);
|
||||
int GetChar();
|
||||
int PutChar(int c);
|
||||
|
||||
void Abort();
|
||||
void Flush();
|
||||
void Close();
|
||||
bool Open(const char *filename, const char *mode);
|
||||
|
||||
void* GetBuffer() const
|
||||
{
|
||||
return m_pBuffer;
|
||||
}
|
||||
|
||||
protected:
|
||||
// MemFile specific:
|
||||
unsigned long m_nGrowBytes;
|
||||
unsigned long m_nPosition;
|
||||
unsigned long m_nBufferSize;
|
||||
unsigned long m_nFileSize;
|
||||
unsigned char* m_pBuffer;
|
||||
bool m_bAutoDelete;
|
||||
void GrowFile(unsigned long nNewLen);
|
||||
};
|
||||
|
||||
class FileDisk : public File
|
||||
{
|
||||
public:
|
||||
// Constructors
|
||||
FileDisk();
|
||||
~FileDisk();
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
unsigned long GetPosition() const;
|
||||
unsigned long Seek(long lOff, int nFrom);
|
||||
void SetLength(unsigned long nNewLen);
|
||||
unsigned long GetLength() const;
|
||||
|
||||
char* ReadLine(char* pBuf, unsigned long nMax);
|
||||
unsigned long Read(void* pBuf, unsigned long nCount);
|
||||
unsigned long Write(const void* pBuf, unsigned long nCount);
|
||||
int GetChar();
|
||||
int PutChar(int c);
|
||||
|
||||
void Abort();
|
||||
void Flush();
|
||||
void Close();
|
||||
bool Open(const char *filename, const char *mode);
|
||||
|
||||
protected:
|
||||
// DiscFile specific:
|
||||
FILE* m_hFile;
|
||||
bool m_bCloseOnDelete;
|
||||
};
|
||||
|
||||
#endif // _FILE_H_
|
89
common/globals.cpp
Normal file
89
common/globals.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
//
|
||||
// Global variables common to all platforms.
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "globals.h"
|
||||
|
||||
Messenger* messenger;
|
||||
MainWnd* main_window;
|
||||
|
||||
const char* colornames[LC_MAXCOLORS] = { "Red", "Orange", "Green",
|
||||
"Light Green", "Blue", "Light Blue", "Yellow", "White",
|
||||
"Dark Gray", "Black", "Brown", "Pink", "Purple", "Gold",
|
||||
"Clear Red", "Clear Orange", "Clear Green", "Clear Light Green",
|
||||
"Clear Blue", "Clear Light Blue", "Clear Yellow", "Clear White",
|
||||
"Light Gray", "Tan", "Light Brown", "Light Pink", "Turquoise", "Silver" };
|
||||
|
||||
const char* altcolornames[LC_MAXCOLORS] = { "Red", "Orange", "Green",
|
||||
"LightGreen", "Blue", "LightBlue", "Yellow", "White",
|
||||
"DarkGray", "Black", "Brown", "Pink", "Purple", "Gold",
|
||||
"ClearRed", "ClearOrange", "ClearGreen", "ClearLightGreen",
|
||||
"ClearBlue", "ClearLightBlue", "ClearYellow", "ClearWhite",
|
||||
"LightGray", "Tan", "LightBrown", "LightPink", "Turquoise", "Silver" };
|
||||
|
||||
unsigned char FlatColorArray[31][3] = {
|
||||
{ 166, 25, 25 }, // 0 - Red
|
||||
{ 255, 127, 51 }, // 1 - Orange
|
||||
{ 25, 102, 25 }, // 2 - Green
|
||||
{ 76, 153, 76 }, // 3 - Light Green
|
||||
{ 0, 51, 178 }, // 4 - Blue
|
||||
{ 51, 102, 229 }, // 5 - Light Blue
|
||||
{ 204, 204, 0 }, // 6 - Yellow
|
||||
{ 242, 242, 242 }, // 7 - White
|
||||
{ 84, 76, 76 }, // 8 - Dark Gray
|
||||
{ 51, 51, 51 }, // 9 - Black
|
||||
{ 102, 51, 51 }, //10 - Brown
|
||||
{ 178, 76, 153 }, //11 - Pink
|
||||
{ 153, 51, 153 }, //12 - Purple
|
||||
{ 229, 178, 51 }, //13 - Gold
|
||||
{ 153, 25, 25 }, //14 - Clear Red
|
||||
{ 255, 153, 76 }, //15 - Clear Orange
|
||||
{ 25, 102, 25 }, //16 - Clear Green
|
||||
{ 153, 178, 76 }, //17 - Clear Light Green
|
||||
{ 0, 0, 127 }, //18 - Clear Blue
|
||||
{ 51, 102, 229 }, //19 - Clear Light Blue
|
||||
{ 229, 229, 0 }, //20 - Clear Yellow
|
||||
{ 229, 229, 229 }, //21 - Clear White
|
||||
{ 140, 140, 140 }, //22 - Light Gray
|
||||
{ 204, 204, 178 }, //23 - Tan
|
||||
{ 153, 102, 102 }, //24 - Light Brown
|
||||
{ 229, 178, 229 }, //25 - Light Pink
|
||||
{ 25, 178, 204 }, //26 - Turquoise
|
||||
{ 204, 204, 204 }, //27 - Silver
|
||||
{ 0, 0, 0 }, //28 - Edges
|
||||
{ 229, 76, 102 }, //29 - Selected
|
||||
{ 102, 76, 229 }}; //30 - Focused
|
||||
|
||||
unsigned char ColorArray[31][4] = {
|
||||
{ 166, 25, 25, 255 }, // 0 - Red
|
||||
{ 255, 127, 51, 255 }, // 1 - Orange
|
||||
{ 25, 102, 25, 255 }, // 2 - Green
|
||||
{ 76, 153, 76, 255 }, // 3 - Light Green
|
||||
{ 0, 51, 178, 255 }, // 4 - Blue
|
||||
{ 51, 102, 229, 255 }, // 5 - Light Blue
|
||||
{ 204, 204, 0, 255 }, // 6 - Yellow
|
||||
{ 242, 242, 242, 255 }, // 7 - White
|
||||
{ 76, 76, 76, 255 }, // 8 - Dark Gray
|
||||
{ 25, 25, 25, 255 }, // 9 - Black
|
||||
{ 102, 51, 51, 255 }, //10 - Brown
|
||||
{ 178, 76, 153, 255 }, //11 - Pink
|
||||
{ 153, 51, 153, 255 }, //12 - Purple
|
||||
{ 229, 178, 51, 255 }, //13 - Gold
|
||||
{ 153, 25, 25, 153 }, //14 - Clear Red
|
||||
{ 255, 153, 76, 153 }, //15 - Clear Orange
|
||||
{ 25, 102, 25, 153 }, //16 - Clear Green
|
||||
{ 153, 178, 76, 153 }, //17 - Clear Light Green
|
||||
{ 0, 0, 127, 153 }, //18 - Clear Blue
|
||||
{ 51, 102, 229, 153 }, //19 - Clear Light Blue
|
||||
{ 229, 229, 0, 153 }, //20 - Clear Yellow
|
||||
{ 229, 229, 229, 153 }, //21 - Clear White
|
||||
{ 127, 127, 127, 255 }, //22 - Light Gray
|
||||
{ 204, 204, 178, 255 }, //23 - Tan
|
||||
{ 153, 102, 102, 255 }, //24 - Light Brown
|
||||
{ 229, 178, 229, 255 }, //25 - Light Pink
|
||||
{ 25, 178, 204, 255 }, //26 - Turquoise
|
||||
{ 204, 204, 204, 255 }, //27 - Silver
|
||||
{ 51, 51, 51, 255 }, //28 - Edges
|
||||
{ 229, 76, 102, 255 }, //29 - Selected
|
||||
{ 102, 76, 229, 255 }}; //30 - Focused
|
19
common/globals.h
Normal file
19
common/globals.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef _GLOBALS_H_
|
||||
#define _GLOBALS_H_
|
||||
|
||||
#include "defines.h"
|
||||
#include "typedefs.h"
|
||||
#include "console.h"
|
||||
|
||||
class Messenger;
|
||||
extern Messenger* messenger;
|
||||
|
||||
class MainWnd;
|
||||
extern MainWnd* main_window;
|
||||
|
||||
extern unsigned char FlatColorArray[31][3];
|
||||
extern unsigned char ColorArray[31][4];
|
||||
extern const char* colornames[LC_MAXCOLORS];
|
||||
extern const char* altcolornames[LC_MAXCOLORS];
|
||||
|
||||
#endif // _GLOBALS_H_
|
52
common/glwindow.h
Normal file
52
common/glwindow.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
#ifndef _GLWINDOW_H_
|
||||
#define _GLWINDOW_H_
|
||||
|
||||
class GLWindow
|
||||
{
|
||||
public:
|
||||
GLWindow(GLWindow *share);
|
||||
virtual ~GLWindow();
|
||||
|
||||
void IncRef()
|
||||
{ m_nRef++; }
|
||||
void DecRef()
|
||||
{ m_nRef--; if (m_nRef == 0) delete this; }
|
||||
|
||||
bool Create(void* data);
|
||||
void DestroyContext();
|
||||
|
||||
bool MakeCurrent();
|
||||
void SwapBuffers();
|
||||
void Redraw();
|
||||
void CaptureMouse();
|
||||
void ReleaseMouse();
|
||||
|
||||
int GetWidth() const
|
||||
{ return m_nWidth; }
|
||||
int GetHeight() const
|
||||
{ return m_nHeight; }
|
||||
void* GetData() const
|
||||
{ return m_pData; }
|
||||
|
||||
virtual void OnDraw() { };
|
||||
virtual void OnSize(int cx, int cy)
|
||||
{ m_nWidth = cx; m_nHeight = cy; };
|
||||
virtual void OnInitialUpdate();
|
||||
virtual void OnLeftButtonDown(int x, int y, bool bControl, bool bShift) { };
|
||||
virtual void OnLeftButtonUp(int x, int y, bool bControl, bool bShift) { };
|
||||
virtual void OnLeftButtonDoubleClick(int x, int y, bool bControl, bool bShift) { };
|
||||
virtual void OnRightButtonDown(int x, int y, bool bControl, bool bShift) { };
|
||||
virtual void OnRightButtonUp(int x, int y, bool bControl, bool bShift) { };
|
||||
virtual void OnMouseMove(int x, int y, bool bControl, bool bShift) { };
|
||||
|
||||
protected:
|
||||
int m_nWidth;
|
||||
int m_nHeight;
|
||||
|
||||
private:
|
||||
void *m_pData;
|
||||
GLWindow *m_pShare;
|
||||
int m_nRef;
|
||||
};
|
||||
|
||||
#endif // _GLWINDOW_H_
|
79
common/group.cpp
Normal file
79
common/group.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
// Piece group
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "group.h"
|
||||
#include "file.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Group construction/destruction
|
||||
|
||||
Group::Group()
|
||||
{
|
||||
m_pGroup = NULL;
|
||||
m_pNext = NULL;
|
||||
}
|
||||
|
||||
Group::~Group()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Group* Group::GetTopGroup()
|
||||
{
|
||||
return m_pGroup ? m_pGroup->GetTopGroup() : this;
|
||||
}
|
||||
|
||||
void Group::SetGroup(Group* pGroup)
|
||||
{
|
||||
if (pGroup == this)
|
||||
return;
|
||||
|
||||
if (m_pGroup != NULL && m_pGroup != (Group*)-1)
|
||||
m_pGroup->SetGroup(pGroup);
|
||||
else
|
||||
m_pGroup = pGroup;
|
||||
}
|
||||
|
||||
void Group::UnGroup(Group* pGroup)
|
||||
{
|
||||
if (m_pGroup == pGroup)
|
||||
m_pGroup = NULL;
|
||||
else
|
||||
if (m_pGroup != NULL)
|
||||
m_pGroup->UnGroup(pGroup);
|
||||
}
|
||||
|
||||
void Group::FileLoad(File* file)
|
||||
{
|
||||
unsigned char version;
|
||||
int i;
|
||||
|
||||
file->Read(&version, 1);
|
||||
file->Read(m_strName, 65);
|
||||
file->Read(m_fCenter, 12);
|
||||
file->ReadLong(&i, 1);
|
||||
m_pGroup = (Group*)i;
|
||||
}
|
||||
|
||||
void Group::FileSave(File* file, Group* pGroups)
|
||||
{
|
||||
unsigned char version = 1; // LeoCAD 0.60
|
||||
|
||||
file->Write(&version, 1);
|
||||
file->Write(m_strName, 65);
|
||||
file->Write(m_fCenter, 12);
|
||||
|
||||
int i = 0;
|
||||
if (m_pGroup == NULL)
|
||||
i = -1;
|
||||
else
|
||||
{
|
||||
for (; pGroups; pGroups = pGroups->m_pNext)
|
||||
if (pGroups == m_pGroup)
|
||||
break;
|
||||
else
|
||||
i++;
|
||||
}
|
||||
file->WriteLong(&i, 1);
|
||||
}
|
31
common/group.h
Normal file
31
common/group.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// group.h
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _GROUP_H
|
||||
#define _GROUP_H
|
||||
|
||||
class File;
|
||||
|
||||
class Group
|
||||
{
|
||||
public:
|
||||
// void DoSaveLoad(CArchive& ar, CCADDoc* pDoc);
|
||||
Group();
|
||||
~Group();
|
||||
|
||||
void SetGroup(Group* pGroup);
|
||||
void UnGroup(Group* pGroup);
|
||||
Group* GetTopGroup();
|
||||
|
||||
Group* m_pNext;
|
||||
Group* m_pGroup;
|
||||
|
||||
void FileLoad(File* file);
|
||||
void FileSave(File* file, Group* pGroups);
|
||||
|
||||
char m_strName[65];
|
||||
float m_fCenter[3];
|
||||
};
|
||||
|
||||
#endif // _GROUP_H
|
492
common/im_bmp.cpp
Executable file
492
common/im_bmp.cpp
Executable file
|
@ -0,0 +1,492 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "config.h"
|
||||
#include "quant.h"
|
||||
#include "image.h"
|
||||
#include "file.h"
|
||||
|
||||
// ========================================================
|
||||
|
||||
bool Image::LoadBMP (File& file)
|
||||
{
|
||||
lcint32 bmWidth, bmHeight;
|
||||
lcuint8 bmPlanes, bmBitsPixel, m1, m2;
|
||||
typedef struct {
|
||||
unsigned char rgbBlue;
|
||||
unsigned char rgbGreen;
|
||||
unsigned char rgbRed;
|
||||
unsigned char rgbReserved;
|
||||
} RGBQUAD;
|
||||
lcint16 res1,res2;
|
||||
lcint32 filesize, pixoff;
|
||||
lcint32 bmisize, compression;
|
||||
lcint32 xscale, yscale;
|
||||
lcint32 colors, impcol, rc;
|
||||
lcuint32 sizeimage, m_bytesRead = 0;
|
||||
|
||||
FreeData ();
|
||||
|
||||
if (file.Read (&m1, 1) != 1)
|
||||
return false;
|
||||
m_bytesRead++;
|
||||
|
||||
if (file.Read (&m2, 1) != 1)
|
||||
return false;
|
||||
m_bytesRead++;
|
||||
|
||||
if ((m1 != 'B') || (m2 != 'M'))
|
||||
return false;
|
||||
|
||||
rc = file.ReadLong ((long*)&(filesize), 1); m_bytesRead+=4;
|
||||
if (rc != 1) { return false; }
|
||||
|
||||
rc = file.ReadShort ((int*)&(res1), 1); m_bytesRead+=2;
|
||||
if (rc != 1) { return false; }
|
||||
|
||||
rc = file.ReadShort ((int*)&(res2), 1); m_bytesRead+=2;
|
||||
if (rc != 1) { return false; }
|
||||
|
||||
rc = file.ReadLong ((long*)&(pixoff), 1); m_bytesRead+=4;
|
||||
if (rc != 1) { return false; }
|
||||
|
||||
rc = file.ReadLong ((long*)&(bmisize), 1); m_bytesRead+=4;
|
||||
if (rc != 1) { return false; }
|
||||
|
||||
rc = file.ReadLong ((long*)&(bmWidth), 1); m_bytesRead+=4;
|
||||
if (rc != 1) { return false; }
|
||||
|
||||
rc = file.ReadLong ((long*)&(bmHeight), 1); m_bytesRead+=4;
|
||||
if (rc != 1) { return false; }
|
||||
|
||||
rc = file.ReadShort ((int*)&(bmPlanes), 1); m_bytesRead+=2;
|
||||
if (rc != 1) { return false; }
|
||||
|
||||
rc = file.ReadShort ((int*)&(bmBitsPixel), 1); m_bytesRead+=2;
|
||||
if (rc != 1) { return false; }
|
||||
|
||||
rc = file.ReadLong ((long*)&(compression), 1); m_bytesRead+=4;
|
||||
if (rc != 1) { return false; }
|
||||
|
||||
rc = file.ReadLong ((long*)&(sizeimage), 1); m_bytesRead+=4;
|
||||
if (rc != 1) {return false; }
|
||||
|
||||
rc = file.ReadLong ((long*)&(xscale), 1); m_bytesRead+=4;
|
||||
if (rc != 1) { return false; }
|
||||
|
||||
rc = file.ReadLong ((long*)&(yscale), 1); m_bytesRead+=4;
|
||||
if (rc != 1) { return false; }
|
||||
|
||||
rc = file.ReadLong ((long*)&(colors), 1); m_bytesRead+=4;
|
||||
if (rc != 1) { return false; }
|
||||
|
||||
rc = file.ReadLong ((long*)&(impcol), 1); m_bytesRead+=4;
|
||||
if (rc != 1) { return false; }
|
||||
|
||||
if (colors == 0)
|
||||
colors = 1 << bmBitsPixel;
|
||||
|
||||
RGBQUAD *colormap = NULL;
|
||||
|
||||
if (bmBitsPixel != 24)
|
||||
{
|
||||
colormap = new RGBQUAD[colors];
|
||||
if (colormap == NULL)
|
||||
return false;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < colors; i++)
|
||||
{
|
||||
unsigned char r ,g, b, dummy;
|
||||
|
||||
rc = file.Read (&b, 1);
|
||||
m_bytesRead++;
|
||||
if (rc!=1)
|
||||
{
|
||||
delete [] colormap;
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = file.Read (&g, 1);
|
||||
m_bytesRead++;
|
||||
if (rc!=1)
|
||||
{
|
||||
delete [] colormap;
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = file.Read (&r, 1);
|
||||
m_bytesRead++;
|
||||
if (rc != 1)
|
||||
{
|
||||
delete [] colormap;
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = file.Read (&dummy, 1);
|
||||
m_bytesRead++;
|
||||
if (rc != 1)
|
||||
{
|
||||
delete [] colormap;
|
||||
return false;
|
||||
}
|
||||
|
||||
colormap[i].rgbRed = r;
|
||||
colormap[i].rgbGreen = g;
|
||||
colormap[i].rgbBlue = b;
|
||||
}
|
||||
}
|
||||
|
||||
if ((long)m_bytesRead > pixoff)
|
||||
{
|
||||
delete [] colormap;
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((long)m_bytesRead < pixoff)
|
||||
{
|
||||
char dummy;
|
||||
file.Read (&dummy, 1);
|
||||
m_bytesRead++;
|
||||
}
|
||||
|
||||
int w = bmWidth;
|
||||
int h = bmHeight;
|
||||
|
||||
// set the output params
|
||||
m_pData = (unsigned char*)malloc (w*h*3);
|
||||
long row_size = w * 3;
|
||||
|
||||
if (m_pData != NULL)
|
||||
{
|
||||
m_nWidth = w;
|
||||
m_nHeight = h;
|
||||
m_bAlpha = false;
|
||||
unsigned char* outbuf = m_pData;
|
||||
long row = 0;
|
||||
long rowOffset = 0;
|
||||
|
||||
if (compression == 0) // BI_RGB
|
||||
{
|
||||
// read rows in reverse order
|
||||
for (row=bmHeight-1;row>=0;row--)
|
||||
{
|
||||
// which row are we working on?
|
||||
rowOffset = (long unsigned)row*row_size;
|
||||
|
||||
if (bmBitsPixel == 24)
|
||||
{
|
||||
for (int col=0;col<w;col++)
|
||||
{
|
||||
long offset = col * 3;
|
||||
char pixel[3];
|
||||
|
||||
if (file.Read (pixel, 3) ==3)
|
||||
{
|
||||
// we swap red and blue here
|
||||
*(outbuf + rowOffset + offset + 0) = pixel[2]; // r
|
||||
*(outbuf + rowOffset + offset + 1) = pixel[1]; // g
|
||||
*(outbuf + rowOffset + offset + 2) = pixel[0]; // b
|
||||
}
|
||||
}
|
||||
m_bytesRead += row_size;
|
||||
|
||||
// read DWORD padding
|
||||
while ((m_bytesRead-pixoff)&3)
|
||||
{
|
||||
char dummy;
|
||||
if (file.Read (&dummy, 1) != 1)
|
||||
{
|
||||
FreeData ();
|
||||
return false;
|
||||
}
|
||||
m_bytesRead++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// pixels are packed as 1 , 4 or 8 bit vals. need to unpack them
|
||||
int bit_count = 0;
|
||||
unsigned long mask = (1 << bmBitsPixel) - 1;
|
||||
unsigned char inbyte = 0;
|
||||
|
||||
for (int col=0;col<w;col++)
|
||||
{
|
||||
int pix = 0;
|
||||
|
||||
// if we need another byte
|
||||
if (bit_count <= 0)
|
||||
{
|
||||
bit_count = 8;
|
||||
if (file.Read (&inbyte, 1) != 1)
|
||||
{
|
||||
FreeData ();
|
||||
delete [] colormap;
|
||||
return false;
|
||||
}
|
||||
m_bytesRead++;
|
||||
}
|
||||
|
||||
// keep track of where we are in the bytes
|
||||
bit_count -= bmBitsPixel;
|
||||
pix = ( inbyte >> bit_count) & mask;
|
||||
|
||||
// lookup the color from the colormap - stuff it in our buffer
|
||||
// swap red and blue
|
||||
*(outbuf + rowOffset + col * 3 + 2) = colormap[pix].rgbBlue;
|
||||
*(outbuf + rowOffset + col * 3 + 1) = colormap[pix].rgbGreen;
|
||||
*(outbuf + rowOffset + col * 3 + 0) = colormap[pix].rgbRed;
|
||||
}
|
||||
|
||||
// read DWORD padding
|
||||
while ((m_bytesRead-pixoff)&3)
|
||||
{
|
||||
char dummy;
|
||||
if (file.Read (&dummy, 1) != 1)
|
||||
{
|
||||
FreeData ();
|
||||
if (colormap)
|
||||
delete [] colormap;
|
||||
return false;
|
||||
}
|
||||
m_bytesRead++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, x = 0;
|
||||
unsigned char c, c1 = 0, *pp;
|
||||
row = 0;
|
||||
pp = outbuf + (bmHeight-1)*bmWidth*3;
|
||||
|
||||
if (bmBitsPixel == 8)
|
||||
{
|
||||
while (row < bmHeight)
|
||||
{
|
||||
c = file.GetChar ();
|
||||
|
||||
if (c)
|
||||
{
|
||||
// encoded mode
|
||||
c1 = file.GetChar ();
|
||||
for (i = 0; i < c; x++, i++)
|
||||
{
|
||||
*pp = colormap[c1].rgbRed; pp++;
|
||||
*pp = colormap[c1].rgbGreen; pp++;
|
||||
*pp = colormap[c1].rgbBlue; pp++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// c==0x00, escape codes
|
||||
c = file.GetChar ();
|
||||
|
||||
if (c == 0x00) // end of line
|
||||
{
|
||||
row++;
|
||||
x = 0;
|
||||
pp = outbuf + (bmHeight-row-1)*bmWidth*3;
|
||||
}
|
||||
else if (c == 0x01)
|
||||
break; // end of pic
|
||||
else if (c == 0x02) // delta
|
||||
{
|
||||
c = file.GetChar ();
|
||||
x += c;
|
||||
c = file.GetChar ();
|
||||
row += c;
|
||||
pp = outbuf + x*3 + (bmHeight-row-1)*bmWidth*3;
|
||||
}
|
||||
else // absolute mode
|
||||
{
|
||||
for (i = 0; i < c; x++, i++)
|
||||
{
|
||||
c1 = file.GetChar ();
|
||||
*pp = colormap[c1].rgbRed; pp++;
|
||||
*pp = colormap[c1].rgbGreen; pp++;
|
||||
*pp = colormap[c1].rgbBlue; pp++;
|
||||
}
|
||||
|
||||
if (c & 1)
|
||||
file.GetChar (); // odd length run: read an extra pad byte
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bmBitsPixel == 4)
|
||||
{
|
||||
while (row < bmHeight)
|
||||
{
|
||||
c = file.GetChar ();
|
||||
|
||||
if (c)
|
||||
{
|
||||
// encoded mode
|
||||
c1 = file.GetChar ();
|
||||
for (i = 0; i < c; x++, i++)
|
||||
{
|
||||
*pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbRed; pp++;
|
||||
*pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbGreen; pp++;
|
||||
*pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbBlue; pp++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// c==0x00, escape codes
|
||||
c = file.GetChar ();
|
||||
|
||||
if (c == 0x00) // end of line
|
||||
{
|
||||
row++;
|
||||
x = 0;
|
||||
pp = outbuf + (bmHeight-row-1)*bmWidth*3;
|
||||
}
|
||||
else if (c == 0x01)
|
||||
break; // end of pic
|
||||
else if (c == 0x02) // delta
|
||||
{
|
||||
c = file.GetChar ();
|
||||
x += c;
|
||||
c = file.GetChar ();
|
||||
row += c;
|
||||
pp = outbuf + x*3 + (bmHeight-row-1)*bmWidth*3;
|
||||
}
|
||||
else // absolute mode
|
||||
{
|
||||
for (i = 0; i < c; x++, i++)
|
||||
{
|
||||
if ((i&1) == 0)
|
||||
c1 = file.GetChar ();
|
||||
*pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbRed; pp++;
|
||||
*pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbGreen; pp++;
|
||||
*pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbBlue; pp++;
|
||||
}
|
||||
|
||||
if (((c&3) == 1) || ((c&3) == 2))
|
||||
file.GetChar (); // odd length run: read an extra pad byte
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (colormap)
|
||||
delete [] colormap;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========================================================
|
||||
|
||||
bool Image::SaveBMP (File& file, bool quantize) const
|
||||
{
|
||||
unsigned short bits;
|
||||
unsigned long cmap, bfSize;
|
||||
unsigned char pal[3][256], *colormappedbuffer = NULL;
|
||||
|
||||
if (quantize)
|
||||
{
|
||||
colormappedbuffer = (unsigned char*)malloc(m_nWidth*m_nHeight);
|
||||
dl1quant (m_pData, colormappedbuffer, m_nWidth, m_nHeight, 256, true, pal);
|
||||
bits = 8;
|
||||
cmap = 256;
|
||||
bfSize = 1078 + m_nWidth*m_nHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
bits = 24;
|
||||
cmap = 0;
|
||||
bfSize = 54 + m_nWidth*m_nHeight*3;
|
||||
}
|
||||
|
||||
long byteswritten = 0;
|
||||
long pixoff = 54 + cmap*4;
|
||||
short res = 0;
|
||||
char m1 ='B', m2 ='M';
|
||||
file.WriteByte (&m1, 1); byteswritten++; // B
|
||||
file.WriteByte (&m2, 1); byteswritten++; // M
|
||||
file.WriteLong (&bfSize, 1); byteswritten+=4;// bfSize
|
||||
file.WriteShort (&res, 1); byteswritten+=2;// bfReserved1
|
||||
file.WriteShort (&res, 1); byteswritten+=2;// bfReserved2
|
||||
file.WriteLong (&pixoff, 1); byteswritten+=4;// bfOffBits
|
||||
|
||||
lcuint32 biSize = 40, compress = 0, size = 0;
|
||||
lcint32 width = m_nWidth, height = m_nHeight, pixels = 0;
|
||||
lcuint16 planes = 1;
|
||||
file.WriteLong (&biSize, 1); byteswritten+=4;// biSize
|
||||
file.WriteLong (&width, 1); byteswritten+=4;// biWidth
|
||||
file.WriteLong (&height, 1); byteswritten+=4;// biHeight
|
||||
file.WriteShort (&planes, 1); byteswritten+=2;// biPlanes
|
||||
file.WriteShort (&bits, 1); byteswritten+=2;// biBitCount
|
||||
file.WriteLong (&compress, 1); byteswritten+=4;// biCompression
|
||||
file.WriteLong (&size, 1); byteswritten+=4;// biSizeImage
|
||||
file.WriteLong (&pixels, 1); byteswritten+=4;// biXPelsPerMeter
|
||||
file.WriteLong (&pixels, 1); byteswritten+=4;// biYPelsPerMeter
|
||||
file.WriteLong (&cmap, 1); byteswritten+=4;// biClrUsed
|
||||
file.WriteLong (&cmap, 1); byteswritten+=4;// biClrImportant
|
||||
|
||||
if (quantize)
|
||||
{
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
file.PutChar (pal[2][i]);
|
||||
file.PutChar (pal[1][i]);
|
||||
file.PutChar (pal[0][i]);
|
||||
file.PutChar (0); // dummy
|
||||
}
|
||||
|
||||
for (int row = 0; row < m_nHeight; row++)
|
||||
{
|
||||
int pixbuf = 0;
|
||||
|
||||
for (int col = 0; col < m_nWidth; col++)
|
||||
{
|
||||
int offset = (m_nHeight-row-1) * width + col; // offset into our color-mapped RGB buffer
|
||||
unsigned char pval = *(colormappedbuffer + offset);
|
||||
|
||||
pixbuf = (pixbuf << 8) | pval;
|
||||
|
||||
file.PutChar (pixbuf);
|
||||
pixbuf = 0;
|
||||
byteswritten++;
|
||||
}
|
||||
|
||||
// DWORD align
|
||||
while ((byteswritten - pixoff) & 3)
|
||||
{
|
||||
file.PutChar (0);
|
||||
byteswritten++;
|
||||
}
|
||||
}
|
||||
|
||||
free(colormappedbuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned long widthDW = (((m_nWidth*24) + 31) / 32 * 4);
|
||||
long row, row_size = m_nWidth*3;
|
||||
for (row = 0; row < m_nHeight; row++)
|
||||
{
|
||||
unsigned char* buf = m_pData+(m_nHeight-row-1)*row_size;
|
||||
|
||||
// write a row
|
||||
for (int col = 0; col < row_size; col += 3)
|
||||
{
|
||||
file.PutChar (buf[col+2]);
|
||||
file.PutChar (buf[col+1]);
|
||||
file.PutChar (buf[col]);
|
||||
}
|
||||
byteswritten += row_size;
|
||||
|
||||
for (unsigned long count = row_size; count < widthDW; count++)
|
||||
{
|
||||
file.PutChar (0); // dummy
|
||||
byteswritten++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
699
common/im_gif.cpp
Normal file
699
common/im_gif.cpp
Normal file
|
@ -0,0 +1,699 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "image.h"
|
||||
#include "quant.h"
|
||||
#include "file.h"
|
||||
#include "config.h"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char colormap[3][256];
|
||||
|
||||
// State for GetCode and LZWReadByte
|
||||
char code_buf[256+4];
|
||||
int last_byte; // # of bytes in code_buf
|
||||
int last_bit; // # of bits in code_buf
|
||||
int cur_bit; // next bit index to read
|
||||
bool out_of_blocks; // true if hit terminator data block
|
||||
|
||||
int input_code_size; // codesize given in GIF file
|
||||
int clear_code,end_code;// values for Clear and End codes
|
||||
|
||||
int code_size; // current actual code size
|
||||
int limit_code; // 2^code_size
|
||||
int max_code; // first unused code value
|
||||
bool first_time; // flags first call to LZWReadByte
|
||||
|
||||
// Private state for LZWReadByte
|
||||
int oldcode; // previous LZW symbol
|
||||
int firstcode; // first byte of oldcode's expansion
|
||||
|
||||
// LZW symbol table and expansion stack
|
||||
lcuint16 *symbol_head; // => table of prefix symbols
|
||||
lcuint8 *symbol_tail; // => table of suffix bytes
|
||||
lcuint8 *symbol_stack; // => stack for symbol expansions
|
||||
lcuint8 *sp; // stack pointer
|
||||
|
||||
// State for interlaced image processing
|
||||
bool is_interlaced; // true if have interlaced image
|
||||
// jvirt_sarray_ptr interlaced_image; // full image in interlaced order
|
||||
unsigned char* interlaced_image;
|
||||
lcuint32 cur_row_number; // need to know actual row number
|
||||
lcuint32 pass2_offset; // # of pixel rows in pass 1
|
||||
lcuint32 pass3_offset; // # of pixel rows in passes 1&2
|
||||
lcuint32 pass4_offset; // # of pixel rows in passes 1,2,3
|
||||
|
||||
File* input_file;
|
||||
bool first_interlace;
|
||||
unsigned char* buffer;//JSAMPARRAY buffer;
|
||||
unsigned int width, height;
|
||||
} gif_source_struct;
|
||||
|
||||
typedef gif_source_struct *gif_source_ptr;
|
||||
|
||||
// Macros for extracting header data --- note we assume chars may be signed
|
||||
#define LM_to_uint(a,b) ((((b)&0xFF) << 8) | ((a)&0xFF))
|
||||
#define BitSet(byte, bit) ((byte) & (bit))
|
||||
#define INTERLACE 0x40 // mask for bit signifying interlaced image
|
||||
#define COLORMAPFLAG 0x80 // mask for bit signifying colormap presence
|
||||
|
||||
#undef LZW_TABLE_SIZE
|
||||
#define MAX_LZW_BITS 12 // maximum LZW code size
|
||||
#define LZW_TABLE_SIZE (1<<MAX_LZW_BITS) // # of possible LZW symbols
|
||||
|
||||
static int GetDataBlock (gif_source_ptr sinfo, char *buf)
|
||||
{
|
||||
int count = sinfo->input_file->GetChar();
|
||||
if (count > 0)
|
||||
sinfo->input_file->Read(buf, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int GetCode (gif_source_ptr sinfo)
|
||||
{
|
||||
register lcint32 accum;
|
||||
int offs, ret, count;
|
||||
|
||||
while ((sinfo->cur_bit + sinfo->code_size) > sinfo->last_bit)
|
||||
{
|
||||
if (sinfo->out_of_blocks)
|
||||
return sinfo->end_code; // fake something useful
|
||||
sinfo->code_buf[0] = sinfo->code_buf[sinfo->last_byte-2];
|
||||
sinfo->code_buf[1] = sinfo->code_buf[sinfo->last_byte-1];
|
||||
if ((count = GetDataBlock(sinfo, &sinfo->code_buf[2])) == 0)
|
||||
{
|
||||
sinfo->out_of_blocks = true;
|
||||
return sinfo->end_code; // fake something useful
|
||||
}
|
||||
sinfo->cur_bit = (sinfo->cur_bit - sinfo->last_bit) + 16;
|
||||
sinfo->last_byte = 2 + count;
|
||||
sinfo->last_bit = sinfo->last_byte * 8;
|
||||
}
|
||||
|
||||
offs = sinfo->cur_bit >> 3; // byte containing cur_bit
|
||||
accum = sinfo->code_buf[offs+2] & 0xFF;
|
||||
accum <<= 8;
|
||||
accum |= sinfo->code_buf[offs+1] & 0xFF;
|
||||
accum <<= 8;
|
||||
accum |= sinfo->code_buf[offs] & 0xFF;
|
||||
accum >>= (sinfo->cur_bit & 7);
|
||||
ret = ((int) accum) & ((1 << sinfo->code_size) - 1);
|
||||
|
||||
sinfo->cur_bit += sinfo->code_size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int LZWReadByte (gif_source_ptr sinfo)
|
||||
{
|
||||
register int code; // current working code
|
||||
int incode; // saves actual input code
|
||||
|
||||
// First time, just eat the expected Clear code(s) and return next code,
|
||||
// which is expected to be a raw byte.
|
||||
if (sinfo->first_time)
|
||||
{
|
||||
sinfo->first_time = false;
|
||||
code = sinfo->clear_code; // enables sharing code with Clear case
|
||||
}
|
||||
else
|
||||
{
|
||||
// If any codes are stacked from a previously read symbol, return them
|
||||
if (sinfo->sp > sinfo->symbol_stack)
|
||||
return (int) *(-- sinfo->sp);
|
||||
|
||||
// Time to read a new symbol
|
||||
code = GetCode(sinfo);
|
||||
}
|
||||
|
||||
if (code == sinfo->clear_code)
|
||||
{
|
||||
sinfo->code_size = sinfo->input_code_size + 1;
|
||||
sinfo->limit_code = sinfo->clear_code << 1; // 2^code_size
|
||||
sinfo->max_code = sinfo->clear_code + 2; // first unused code value
|
||||
sinfo->sp = sinfo->symbol_stack; // init stack to empty
|
||||
do
|
||||
{
|
||||
code = GetCode(sinfo);
|
||||
} while (code == sinfo->clear_code);
|
||||
|
||||
if (code > sinfo->clear_code)
|
||||
code = 0; // use something valid
|
||||
sinfo->firstcode = sinfo->oldcode = code;
|
||||
return code;
|
||||
}
|
||||
|
||||
if (code == sinfo->end_code)
|
||||
{
|
||||
if (!sinfo->out_of_blocks)
|
||||
{
|
||||
char buf[256];
|
||||
while (GetDataBlock(sinfo, buf) > 0)
|
||||
; // skip
|
||||
sinfo->out_of_blocks = true;
|
||||
}
|
||||
return 0; // fake something usable
|
||||
}
|
||||
|
||||
incode = code; // save for a moment
|
||||
|
||||
if (code >= sinfo->max_code)
|
||||
{
|
||||
// special case for not-yet-defined symbol
|
||||
// code == max_code is OK; anything bigger is bad data
|
||||
if (code > sinfo->max_code)
|
||||
incode = 0; // prevent creation of loops in symbol table
|
||||
// this symbol will be defined as oldcode/firstcode
|
||||
*(sinfo->sp++) = (lcuint8) sinfo->firstcode;
|
||||
code = sinfo->oldcode;
|
||||
}
|
||||
|
||||
while (code >= sinfo->clear_code)
|
||||
{
|
||||
*(sinfo->sp++) = sinfo->symbol_tail[code]; // tail is a byte value
|
||||
code = sinfo->symbol_head[code]; // head is another LZW symbol
|
||||
}
|
||||
sinfo->firstcode = code; // save for possible future use
|
||||
|
||||
if ((code = sinfo->max_code) < LZW_TABLE_SIZE)
|
||||
{
|
||||
sinfo->symbol_head[code] = sinfo->oldcode;
|
||||
sinfo->symbol_tail[code] = (lcuint8) sinfo->firstcode;
|
||||
sinfo->max_code++;
|
||||
if ((sinfo->max_code >= sinfo->limit_code) &&
|
||||
(sinfo->code_size < MAX_LZW_BITS))
|
||||
{
|
||||
sinfo->code_size++;
|
||||
sinfo->limit_code <<= 1; // keep equal to 2^code_size
|
||||
}
|
||||
}
|
||||
|
||||
sinfo->oldcode = incode; // save last input symbol for future use
|
||||
return sinfo->firstcode; // return first byte of symbol's expansion
|
||||
}
|
||||
|
||||
bool Image::LoadGIF (File& file)
|
||||
{
|
||||
gif_source_ptr source;
|
||||
source = (gif_source_ptr)malloc (sizeof(gif_source_struct));
|
||||
source->input_file = &file;
|
||||
|
||||
char hdrbuf[10];
|
||||
unsigned int width, height;
|
||||
int colormaplen, aspectRatio;
|
||||
int c;
|
||||
|
||||
FreeData ();
|
||||
|
||||
source->input_file->Read(hdrbuf, 6);
|
||||
if ((hdrbuf[0] != 'G' || hdrbuf[1] != 'I' || hdrbuf[2] != 'F') ||
|
||||
((hdrbuf[3] != '8' || hdrbuf[4] != '7' || hdrbuf[5] != 'a') &&
|
||||
(hdrbuf[3] != '8' || hdrbuf[4] != '9' || hdrbuf[5] != 'a')))
|
||||
return false;
|
||||
|
||||
source->input_file->Read(hdrbuf, 7);
|
||||
width = LM_to_uint(hdrbuf[0],hdrbuf[1]);
|
||||
height = LM_to_uint(hdrbuf[2],hdrbuf[3]);
|
||||
source->height = height;
|
||||
source->width = width;
|
||||
colormaplen = 2 << (hdrbuf[4] & 0x07);
|
||||
aspectRatio = hdrbuf[6] & 0xFF;
|
||||
|
||||
if (BitSet(hdrbuf[4], COLORMAPFLAG))
|
||||
for (int i = 0; i < colormaplen; i++)
|
||||
{
|
||||
source->colormap[0][i] = source->input_file->GetChar();
|
||||
source->colormap[1][i] = source->input_file->GetChar();
|
||||
source->colormap[2][i] = source->input_file->GetChar();
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
c = source->input_file->GetChar();
|
||||
|
||||
// if (c == ';')
|
||||
// ERREXIT(cinfo, JERR_GIF_IMAGENOTFOUND);
|
||||
|
||||
if (c == '!')
|
||||
{
|
||||
int extlabel;
|
||||
char buf[256];
|
||||
|
||||
extlabel = source->input_file->GetChar();
|
||||
while (GetDataBlock(source, buf) > 0)
|
||||
; // skip
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c != ',')
|
||||
continue;
|
||||
|
||||
source->input_file->Read(hdrbuf, 9);
|
||||
width = LM_to_uint(hdrbuf[4],hdrbuf[5]);
|
||||
height = LM_to_uint(hdrbuf[6],hdrbuf[7]);
|
||||
source->is_interlaced = (hdrbuf[8] & INTERLACE) != 0;
|
||||
|
||||
if (BitSet(hdrbuf[8], COLORMAPFLAG))
|
||||
{
|
||||
colormaplen = 2 << (hdrbuf[8] & 0x07);
|
||||
for (int i = 0; i < colormaplen; i++)
|
||||
{
|
||||
source->colormap[0][i] = source->input_file->GetChar();
|
||||
source->colormap[1][i] = source->input_file->GetChar();
|
||||
source->colormap[2][i] = source->input_file->GetChar();
|
||||
}
|
||||
}
|
||||
|
||||
source->input_code_size = source->input_file->GetChar();
|
||||
// if (source->input_code_size < 2 || source->input_code_size >= MAX_LZW_BITS)
|
||||
// ERREXIT1(cinfo, JERR_GIF_CODESIZE, source->input_code_size);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
source->symbol_head = (lcuint16*) malloc(LZW_TABLE_SIZE * sizeof(lcuint16));
|
||||
source->symbol_tail = (lcuint8*) malloc (LZW_TABLE_SIZE * sizeof(lcuint8));
|
||||
source->symbol_stack = (lcuint8*) malloc (LZW_TABLE_SIZE * sizeof(lcuint8));
|
||||
source->last_byte = 2; // make safe to "recopy last two bytes"
|
||||
source->last_bit = 0; // nothing in the buffer
|
||||
source->cur_bit = 0; // force buffer load on first call
|
||||
source->out_of_blocks = false;
|
||||
source->clear_code = 1 << source->input_code_size;
|
||||
source->end_code = source->clear_code + 1;
|
||||
source->first_time = true;
|
||||
source->code_size = source->input_code_size + 1;
|
||||
source->limit_code = source->clear_code << 1; // 2^code_size
|
||||
source->max_code = source->clear_code + 2; // first unused code value
|
||||
source->sp = source->symbol_stack; // init stack to empty
|
||||
|
||||
if (source->is_interlaced)
|
||||
{
|
||||
source->first_interlace = true;
|
||||
source->interlaced_image = (unsigned char*)malloc(width*height);
|
||||
}
|
||||
else
|
||||
source->first_interlace = false;
|
||||
|
||||
source->buffer = (unsigned char*)malloc(width*3);
|
||||
m_pData = (unsigned char*)malloc(width*height*3);
|
||||
m_nWidth = width;
|
||||
m_nHeight = height;
|
||||
m_bAlpha = false; // FIXME: create the alpha channel for transparent files
|
||||
unsigned char* buf = m_pData;
|
||||
|
||||
for (unsigned long scanline = 0; scanline < height; scanline++)
|
||||
{
|
||||
if (source->is_interlaced)
|
||||
{
|
||||
if (source->first_interlace)
|
||||
{
|
||||
register lcuint8 *sptr;
|
||||
register lcuint32 col;
|
||||
lcuint32 row;
|
||||
|
||||
for (row = 0; row < source->height; row++)
|
||||
{
|
||||
sptr = &source->interlaced_image[row*source->width];
|
||||
for (col = source->width; col > 0; col--)
|
||||
*sptr++ = (lcuint8) LZWReadByte(source);
|
||||
}
|
||||
|
||||
source->first_interlace = false;
|
||||
source->cur_row_number = 0;
|
||||
source->pass2_offset = (source->height + 7) / 8;
|
||||
source->pass3_offset = source->pass2_offset + (source->height + 3) / 8;
|
||||
source->pass4_offset = source->pass3_offset + (source->height + 1) / 4;
|
||||
}
|
||||
|
||||
register int c;
|
||||
register lcuint8 *sptr, *ptr;
|
||||
register lcuint32 col;
|
||||
lcuint32 irow;
|
||||
|
||||
// Figure out which row of interlaced image is needed, and access it.
|
||||
switch ((int) (source->cur_row_number & 7))
|
||||
{
|
||||
case 0: // first-pass row
|
||||
irow = source->cur_row_number >> 3;
|
||||
break;
|
||||
case 4: // second-pass row
|
||||
irow = (source->cur_row_number >> 3) + source->pass2_offset;
|
||||
break;
|
||||
case 2: // third-pass row
|
||||
case 6:
|
||||
irow = (source->cur_row_number >> 2) + source->pass3_offset;
|
||||
break;
|
||||
default: // fourth-pass row
|
||||
irow = (source->cur_row_number >> 1) + source->pass4_offset;
|
||||
break;
|
||||
}
|
||||
sptr = &source->interlaced_image[irow*source->width];
|
||||
ptr = source->buffer;
|
||||
for (col = source->width; col > 0; col--)
|
||||
{
|
||||
c = *sptr++;
|
||||
*ptr++ = source->colormap[0][c];
|
||||
*ptr++ = source->colormap[1][c];
|
||||
*ptr++ = source->colormap[2][c];
|
||||
}
|
||||
source->cur_row_number++; // for next time
|
||||
}
|
||||
else
|
||||
{
|
||||
register int c;
|
||||
register lcuint8 *ptr;
|
||||
register lcuint32 col;
|
||||
|
||||
ptr = source->buffer;
|
||||
for (col = source->width; col > 0; col--)
|
||||
{
|
||||
c = LZWReadByte(source);
|
||||
*ptr++ = source->colormap[0][c];
|
||||
*ptr++ = source->colormap[1][c];
|
||||
*ptr++ = source->colormap[2][c];
|
||||
}
|
||||
}
|
||||
|
||||
memcpy (buf+(width*scanline*3), source->buffer, 3*width);
|
||||
}
|
||||
|
||||
if (source->is_interlaced)
|
||||
free(source->interlaced_image);
|
||||
free(source->buffer);
|
||||
free(source->symbol_head);
|
||||
free(source->symbol_tail);
|
||||
free(source->symbol_stack);
|
||||
free(source);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
#undef LZW_TABLE_SIZE
|
||||
#define MAX_LZW_BITS 12
|
||||
typedef lcint16 code_int;
|
||||
#define LZW_TABLE_SIZE ((code_int) 1 << MAX_LZW_BITS)
|
||||
#define HSIZE 5003
|
||||
typedef int hash_int;
|
||||
#define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1)
|
||||
typedef lcint32 hash_entry;
|
||||
#define HASH_ENTRY(prefix,suffix) ((((hash_entry) (prefix)) << 8) | (suffix))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int n_bits;
|
||||
code_int maxcode;
|
||||
int init_bits;
|
||||
lcint32 cur_accum;
|
||||
int cur_bits;
|
||||
code_int waiting_code;
|
||||
bool first_byte;
|
||||
code_int ClearCode;
|
||||
code_int EOFCode;
|
||||
code_int free_code;
|
||||
code_int *hash_code;
|
||||
hash_entry *hash_value;
|
||||
int bytesinpkt;
|
||||
char packetbuf[256];
|
||||
File* output_file;
|
||||
void* buffer;//JSAMPARRAY buffer;
|
||||
} gif_dest_struct;
|
||||
|
||||
typedef gif_dest_struct* gif_dest_ptr;
|
||||
|
||||
// Emit a 16-bit word, LSB first
|
||||
static void put_word(File& output_file, unsigned int w)
|
||||
{
|
||||
output_file.PutChar(w & 0xFF);
|
||||
output_file.PutChar((w >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
static void flush_packet(gif_dest_ptr dinfo)
|
||||
{
|
||||
if (dinfo->bytesinpkt > 0)
|
||||
{
|
||||
dinfo->packetbuf[0] = (char) dinfo->bytesinpkt++;
|
||||
dinfo->output_file->Write(dinfo->packetbuf, dinfo->bytesinpkt);
|
||||
dinfo->bytesinpkt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void output(gif_dest_ptr dinfo, code_int code)
|
||||
{
|
||||
dinfo->cur_accum |= ((lcint32) code) << dinfo->cur_bits;
|
||||
dinfo->cur_bits += dinfo->n_bits;
|
||||
|
||||
while (dinfo->cur_bits >= 8)
|
||||
{
|
||||
(dinfo)->packetbuf[++(dinfo)->bytesinpkt] = (char) (dinfo->cur_accum & 0xFF);
|
||||
if ((dinfo)->bytesinpkt >= 255)
|
||||
flush_packet(dinfo);
|
||||
|
||||
dinfo->cur_accum >>= 8;
|
||||
dinfo->cur_bits -= 8;
|
||||
}
|
||||
|
||||
if (dinfo->free_code > dinfo->maxcode)
|
||||
{
|
||||
dinfo->n_bits++;
|
||||
if (dinfo->n_bits == MAX_LZW_BITS)
|
||||
dinfo->maxcode = LZW_TABLE_SIZE;
|
||||
else
|
||||
dinfo->maxcode = MAXCODE(dinfo->n_bits);
|
||||
}
|
||||
}
|
||||
|
||||
// Accept and compress one 8-bit byte
|
||||
static void compress_byte (gif_dest_ptr dinfo, int c)
|
||||
{
|
||||
register hash_int i;
|
||||
register hash_int disp;
|
||||
register hash_entry probe_value;
|
||||
|
||||
if (dinfo->first_byte)
|
||||
{
|
||||
dinfo->waiting_code = c;
|
||||
dinfo->first_byte = false;
|
||||
return;
|
||||
}
|
||||
|
||||
i = ((hash_int) c << (MAX_LZW_BITS-8)) + dinfo->waiting_code;
|
||||
if (i >= HSIZE)
|
||||
i -= HSIZE;
|
||||
|
||||
probe_value = HASH_ENTRY(dinfo->waiting_code, c);
|
||||
|
||||
if (dinfo->hash_code[i] != 0)
|
||||
{
|
||||
if (dinfo->hash_value[i] == probe_value)
|
||||
{
|
||||
dinfo->waiting_code = dinfo->hash_code[i];
|
||||
return;
|
||||
}
|
||||
if (i == 0)
|
||||
disp = 1;
|
||||
else
|
||||
disp = HSIZE - i;
|
||||
for (;;)
|
||||
{
|
||||
i -= disp;
|
||||
if (i < 0)
|
||||
i += HSIZE;
|
||||
if (dinfo->hash_code[i] == 0)
|
||||
break;
|
||||
if (dinfo->hash_value[i] == probe_value)
|
||||
{
|
||||
dinfo->waiting_code = dinfo->hash_code[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output(dinfo, dinfo->waiting_code);
|
||||
if (dinfo->free_code < LZW_TABLE_SIZE)
|
||||
{
|
||||
dinfo->hash_code[i] = dinfo->free_code++;
|
||||
dinfo->hash_value[i] = probe_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(dinfo->hash_code, 0, HSIZE * sizeof(code_int));
|
||||
dinfo->free_code = dinfo->ClearCode + 2;
|
||||
output(dinfo, dinfo->ClearCode);
|
||||
dinfo->n_bits = dinfo->init_bits;
|
||||
dinfo->maxcode = MAXCODE(dinfo->n_bits);
|
||||
}
|
||||
dinfo->waiting_code = c;
|
||||
}
|
||||
|
||||
bool Image::SaveGIF (File& file, bool transparent, bool interlaced, unsigned char* background) const
|
||||
{
|
||||
int InitCodeSize, FlagByte, i;
|
||||
unsigned char pal[3][256];
|
||||
unsigned char* colormappedbuffer = (unsigned char*)malloc (m_nWidth*m_nHeight);
|
||||
dl1quant (m_pData, colormappedbuffer, m_nWidth, m_nHeight, 256, true, pal);
|
||||
|
||||
gif_dest_ptr dinfo;
|
||||
dinfo = (gif_dest_ptr) malloc (sizeof(gif_dest_struct));
|
||||
dinfo->output_file = &file;
|
||||
dinfo->buffer = malloc(m_nWidth*sizeof(lcuint32));
|
||||
dinfo->hash_code = (code_int*) malloc(HSIZE * sizeof(code_int));
|
||||
dinfo->hash_value = (hash_entry*)malloc(HSIZE*sizeof(hash_entry));
|
||||
|
||||
InitCodeSize = 8;
|
||||
// Write the GIF header.
|
||||
file.PutChar('G');
|
||||
file.PutChar('I');
|
||||
file.PutChar('F');
|
||||
file.PutChar('8');
|
||||
file.PutChar(transparent ? '9' : '7');
|
||||
file.PutChar('a');
|
||||
// Write the Logical Screen Descriptor
|
||||
put_word(file, (unsigned int)m_nWidth);
|
||||
put_word(file, (unsigned int)m_nHeight);
|
||||
FlagByte = 0x80;
|
||||
FlagByte |= (7) << 4; // color resolution
|
||||
FlagByte |= (7); // size of global color table
|
||||
file.PutChar(FlagByte);
|
||||
file.PutChar(0); // Background color index
|
||||
file.PutChar(0); // Reserved (aspect ratio in GIF89)
|
||||
// Write the Global Color Map
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
file.PutChar(pal[0][i]);
|
||||
file.PutChar(pal[1][i]);
|
||||
file.PutChar(pal[2][i]);
|
||||
}
|
||||
|
||||
// Write out extension for transparent colour index, if necessary.
|
||||
if (transparent)
|
||||
{
|
||||
unsigned char index = 0;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
if (background[0] == pal[0][i] &&
|
||||
background[1] == pal[1][i] &&
|
||||
background[2] == pal[2][i])
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
|
||||
file.PutChar('!');
|
||||
file.PutChar(0xf9);
|
||||
file.PutChar(4);
|
||||
file.PutChar(1);
|
||||
file.PutChar(0);
|
||||
file.PutChar(0);
|
||||
file.PutChar(index);
|
||||
file.PutChar(0);
|
||||
}
|
||||
|
||||
// Write image separator and Image Descriptor
|
||||
file.PutChar(',');
|
||||
put_word(file, 0);
|
||||
put_word(file, 0);
|
||||
put_word(file, (unsigned int)m_nWidth);
|
||||
put_word(file, (unsigned int)m_nHeight);
|
||||
// flag byte: interlaced
|
||||
if (interlaced)
|
||||
file.PutChar(0x40);
|
||||
else
|
||||
file.PutChar(0x00);
|
||||
file.PutChar(InitCodeSize);// Write Initial Code Size byte
|
||||
|
||||
// Initialize for LZW compression of image data
|
||||
dinfo->n_bits = dinfo->init_bits = InitCodeSize+1;
|
||||
dinfo->maxcode = MAXCODE(dinfo->n_bits);
|
||||
dinfo->ClearCode = ((code_int) 1 << (InitCodeSize));
|
||||
dinfo->EOFCode = dinfo->ClearCode + 1;
|
||||
dinfo->free_code = dinfo->ClearCode + 2;
|
||||
dinfo->first_byte = true;
|
||||
dinfo->bytesinpkt = 0;
|
||||
dinfo->cur_accum = 0;
|
||||
dinfo->cur_bits = 0;
|
||||
memset(dinfo->hash_code, 0, HSIZE * sizeof(code_int));
|
||||
output(dinfo, dinfo->ClearCode);
|
||||
|
||||
int scanline = 0;
|
||||
int pass = 0;
|
||||
while (scanline < m_nHeight)
|
||||
{
|
||||
memcpy(dinfo->buffer, colormappedbuffer+(scanline*m_nWidth), m_nWidth);
|
||||
|
||||
register lcuint8 *ptr;
|
||||
register lcuint32 col;
|
||||
|
||||
ptr = (unsigned char*)dinfo->buffer;
|
||||
for (col = m_nWidth; col > 0; col--)
|
||||
compress_byte(dinfo, *ptr++);
|
||||
|
||||
if (interlaced)
|
||||
{
|
||||
switch (pass)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
scanline += 8;
|
||||
if (scanline >= m_nHeight)
|
||||
{
|
||||
pass++;
|
||||
scanline = 4;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
scanline += 8;
|
||||
if (scanline >= m_nHeight)
|
||||
{
|
||||
pass++;
|
||||
scanline = 2;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
scanline += 4;
|
||||
if (scanline >= m_nHeight)
|
||||
{
|
||||
pass++;
|
||||
scanline = 1;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
scanline += 2;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
else
|
||||
scanline++;
|
||||
}
|
||||
|
||||
// Finish up at the end of the file.
|
||||
if (!dinfo->first_byte)
|
||||
output(dinfo, dinfo->waiting_code);
|
||||
output(dinfo, dinfo->EOFCode);
|
||||
if (dinfo->cur_bits > 0)
|
||||
{
|
||||
(dinfo)->packetbuf[++(dinfo)->bytesinpkt] = (char) (dinfo->cur_accum & 0xFF);
|
||||
if ((dinfo)->bytesinpkt >= 255)
|
||||
flush_packet(dinfo);
|
||||
}
|
||||
|
||||
flush_packet(dinfo);
|
||||
file.PutChar(0);
|
||||
file.PutChar(';');
|
||||
file.Flush();
|
||||
|
||||
free(dinfo->buffer);
|
||||
free(dinfo->hash_code);
|
||||
free(dinfo->hash_value);
|
||||
free(dinfo);
|
||||
free(colormappedbuffer);
|
||||
return true;
|
||||
}
|
401
common/im_jpg.cpp
Normal file
401
common/im_jpg.cpp
Normal file
|
@ -0,0 +1,401 @@
|
|||
#include <setjmp.h>
|
||||
#include <stdlib.h>
|
||||
#include "config.h"
|
||||
#include "image.h"
|
||||
#include "file.h"
|
||||
|
||||
#ifdef LC_HAVE_JPEGLIB
|
||||
|
||||
extern "C" {
|
||||
#include <jpeglib.h>
|
||||
}
|
||||
|
||||
typedef struct bt_jpeg_error_mgr
|
||||
{
|
||||
struct jpeg_error_mgr pub; // "public" fields
|
||||
jmp_buf setjmp_buffer; // for return to caller
|
||||
} bt_jpeg_error_mgr;
|
||||
|
||||
static void bt_jpeg_error_exit (j_common_ptr cinfo)
|
||||
{
|
||||
bt_jpeg_error_mgr* myerr = (bt_jpeg_error_mgr*) cinfo->err;
|
||||
char buffer[JMSG_LENGTH_MAX];
|
||||
(*cinfo->err->format_message) (cinfo, buffer);
|
||||
// MessageBox(NULL, buffer, "JPEG Fatal Error", MB_ICONSTOP);
|
||||
longjmp(myerr->setjmp_buffer, 1);
|
||||
}
|
||||
|
||||
// stash a scanline
|
||||
static void j_putRGBScanline(unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row)
|
||||
{
|
||||
int offset = row * widthPix * 3;
|
||||
int count;
|
||||
for (count = 0; count < widthPix; count++)
|
||||
{
|
||||
unsigned char iRed, iBlu, iGrn;
|
||||
unsigned char *oRed, *oBlu, *oGrn;
|
||||
|
||||
iRed = *(jpegline + count * 3 + 0);
|
||||
iGrn = *(jpegline + count * 3 + 1);
|
||||
iBlu = *(jpegline + count * 3 + 2);
|
||||
|
||||
oRed = outBuf + offset + count * 3 + 0;
|
||||
oGrn = outBuf + offset + count * 3 + 1;
|
||||
oBlu = outBuf + offset + count * 3 + 2;
|
||||
|
||||
*oRed = iRed;
|
||||
*oGrn = iGrn;
|
||||
*oBlu = iBlu;
|
||||
}
|
||||
}
|
||||
|
||||
// stash a gray scanline
|
||||
static void j_putGrayScanlineToRGB(unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row)
|
||||
{
|
||||
int offset = row * widthPix * 3;
|
||||
int count;
|
||||
for (count = 0; count < widthPix; count++)
|
||||
{
|
||||
unsigned char iGray;
|
||||
unsigned char *oRed, *oBlu, *oGrn;
|
||||
|
||||
// get our grayscale value
|
||||
iGray = *(jpegline + count);
|
||||
|
||||
oRed = outBuf + offset + count * 3;
|
||||
oGrn = outBuf + offset + count * 3 + 1;
|
||||
oBlu = outBuf + offset + count * 3 + 2;
|
||||
|
||||
*oRed = iGray;
|
||||
*oGrn = iGray;
|
||||
*oBlu = iGray;
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// JPEG data source
|
||||
|
||||
// Expanded data source object for input using the File class
|
||||
typedef struct
|
||||
{
|
||||
struct jpeg_source_mgr pub; // public fields
|
||||
|
||||
File * infile; // source stream
|
||||
JOCTET * buffer; // start of buffer
|
||||
boolean start_of_file; // have we gotten any data yet?
|
||||
} my_source_mgr;
|
||||
|
||||
typedef my_source_mgr * my_src_ptr;
|
||||
|
||||
#define INPUT_BUF_SIZE 4096 // choose an efficiently fread'able size
|
||||
|
||||
// Initialize source --- called by jpeg_read_header
|
||||
// before any data is actually read.
|
||||
static void init_source (j_decompress_ptr cinfo)
|
||||
{
|
||||
my_src_ptr src = (my_src_ptr) cinfo->src;
|
||||
|
||||
// We reset the empty-input-file flag for each image,
|
||||
// but we don't clear the input buffer.
|
||||
// This is correct behavior for reading a series of images from one source.
|
||||
src->start_of_file = TRUE;
|
||||
}
|
||||
|
||||
// Fill the input buffer --- called whenever buffer is emptied.
|
||||
static boolean fill_input_buffer (j_decompress_ptr cinfo)
|
||||
{
|
||||
my_src_ptr src = (my_src_ptr) cinfo->src;
|
||||
size_t nbytes;
|
||||
|
||||
nbytes = src->infile->Read (src->buffer, INPUT_BUF_SIZE);
|
||||
|
||||
if (nbytes <= 0)
|
||||
{
|
||||
// if (src->start_of_file) // Treat empty input file as fatal error
|
||||
// ERREXIT(cinfo, JERR_INPUT_EMPTY);
|
||||
// WARNMS(cinfo, JWRN_JPEG_EOF);
|
||||
|
||||
// Insert a fake EOI marker
|
||||
src->buffer[0] = (JOCTET) 0xFF;
|
||||
src->buffer[1] = (JOCTET) JPEG_EOI;
|
||||
nbytes = 2;
|
||||
}
|
||||
|
||||
src->pub.next_input_byte = src->buffer;
|
||||
src->pub.bytes_in_buffer = nbytes;
|
||||
src->start_of_file = FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Skip data --- used to skip over a potentially large amount of
|
||||
// uninteresting data (such as an APPn marker).
|
||||
|
||||
static void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
|
||||
{
|
||||
my_src_ptr src = (my_src_ptr) cinfo->src;
|
||||
|
||||
// Just a dumb implementation for now. Could use Seek() except
|
||||
// it doesn't work on pipes. Not clear that being smart is worth
|
||||
// any trouble anyway --- large skips are infrequent.
|
||||
if (num_bytes > 0)
|
||||
{
|
||||
while (num_bytes > (long) src->pub.bytes_in_buffer)
|
||||
{
|
||||
num_bytes -= (long) src->pub.bytes_in_buffer;
|
||||
(void) fill_input_buffer(cinfo);
|
||||
// note we assume that fill_input_buffer will never return FALSE,
|
||||
// so suspension need not be handled.
|
||||
}
|
||||
src->pub.next_input_byte += (size_t) num_bytes;
|
||||
src->pub.bytes_in_buffer -= (size_t) num_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
// Terminate source --- called by jpeg_finish_decompress
|
||||
// after all data has been read. Often a no-op.
|
||||
static void term_source (j_decompress_ptr cinfo)
|
||||
{
|
||||
// no work necessary here
|
||||
}
|
||||
|
||||
// Prepare for input from a File object.
|
||||
static void jpeg_file_src (j_decompress_ptr cinfo, File& infile)
|
||||
{
|
||||
my_src_ptr src;
|
||||
|
||||
// The source object and input buffer are made permanent so that a series
|
||||
// of JPEG images can be read from the same file by calling jpeg_stdio_src
|
||||
// only before the first one. (If we discarded the buffer at the end of
|
||||
// one image, we'd likely lose the start of the next one.)
|
||||
// This makes it unsafe to use this manager and a different source
|
||||
// manager serially with the same JPEG object. Caveat programmer.
|
||||
if (cinfo->src == NULL)
|
||||
{
|
||||
// first time for this JPEG object?
|
||||
cinfo->src = (struct jpeg_source_mgr *)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||
sizeof (my_source_mgr));
|
||||
src = (my_src_ptr) cinfo->src;
|
||||
src->buffer = (JOCTET *)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||
INPUT_BUF_SIZE * sizeof(JOCTET));
|
||||
}
|
||||
|
||||
src = (my_src_ptr) cinfo->src;
|
||||
src->pub.init_source = init_source;
|
||||
src->pub.fill_input_buffer = fill_input_buffer;
|
||||
src->pub.skip_input_data = skip_input_data;
|
||||
src->pub.resync_to_restart = jpeg_resync_to_restart; // use default method
|
||||
src->pub.term_source = term_source;
|
||||
src->infile = &infile;
|
||||
src->pub.bytes_in_buffer = 0; // forces fill_input_buffer on first read
|
||||
src->pub.next_input_byte = NULL; // until buffer loaded
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
bool Image::LoadJPG (File& file)
|
||||
{
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
struct bt_jpeg_error_mgr jerr;
|
||||
JSAMPARRAY buffer; // Output row buffer
|
||||
int row_stride; // physical row width in output buffer
|
||||
|
||||
FreeData ();
|
||||
|
||||
cinfo.err = jpeg_std_error(&jerr.pub);
|
||||
jerr.pub.error_exit = bt_jpeg_error_exit;
|
||||
|
||||
if (setjmp(jerr.setjmp_buffer))
|
||||
{
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
jpeg_create_decompress(&cinfo);
|
||||
jpeg_file_src(&cinfo, file);
|
||||
jpeg_read_header(&cinfo, TRUE);
|
||||
jpeg_start_decompress(&cinfo);
|
||||
|
||||
// get our buffer set to hold data
|
||||
m_pData = (unsigned char*)malloc(cinfo.output_width*cinfo.output_height*3);
|
||||
|
||||
if (m_pData == NULL)
|
||||
{
|
||||
// MessageBox(NULL, "Error", "Cannot allocate memory", MB_ICONSTOP);
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_nWidth = cinfo.output_width;
|
||||
m_nHeight = cinfo.output_height;
|
||||
m_bAlpha = false;
|
||||
|
||||
row_stride = cinfo.output_width * cinfo.output_components;
|
||||
buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
|
||||
|
||||
while (cinfo.output_scanline < cinfo.output_height)
|
||||
{
|
||||
jpeg_read_scanlines(&cinfo, buffer, 1);
|
||||
|
||||
if (cinfo.out_color_components == 3)
|
||||
j_putRGBScanline(buffer[0], m_nWidth, m_pData, cinfo.output_scanline-1);
|
||||
else if (cinfo.out_color_components == 1)
|
||||
j_putGrayScanlineToRGB(buffer[0], m_nWidth, m_pData, cinfo.output_scanline-1);
|
||||
}
|
||||
|
||||
jpeg_finish_decompress(&cinfo);
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// JPEG data destination
|
||||
|
||||
// Expanded data destination object for output using the File class
|
||||
typedef struct
|
||||
{
|
||||
struct jpeg_destination_mgr pub; // public fields
|
||||
|
||||
File * outfile; // target stream
|
||||
JOCTET * buffer; // start of buffer
|
||||
} my_destination_mgr;
|
||||
|
||||
typedef my_destination_mgr * my_dest_ptr;
|
||||
|
||||
#define OUTPUT_BUF_SIZE 4096 // choose an efficiently fwrite'able size
|
||||
|
||||
// Initialize destination --- called by jpeg_start_compress
|
||||
// before any data is actually written.
|
||||
static void init_destination (j_compress_ptr cinfo)
|
||||
{
|
||||
my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
|
||||
|
||||
/* Allocate the output buffer --- it will be released when done with image */
|
||||
dest->buffer = (JOCTET *)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
||||
OUTPUT_BUF_SIZE * sizeof(JOCTET));
|
||||
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
|
||||
}
|
||||
|
||||
// Empty the output buffer --- called whenever buffer fills up.
|
||||
//
|
||||
// In typical applications, this should write the entire output buffer
|
||||
// (ignoring the current state of next_output_byte & free_in_buffer),
|
||||
// reset the pointer & count to the start of the buffer, and return TRUE
|
||||
// indicating that the buffer has been dumped.
|
||||
static boolean empty_output_buffer (j_compress_ptr cinfo)
|
||||
{
|
||||
my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
|
||||
|
||||
dest->outfile->Write (dest->buffer, OUTPUT_BUF_SIZE);
|
||||
// if (dest->outfile.Write (dest->buffer, OUTPUT_BUF_SIZE) != (size_t) OUTPUT_BUF_SIZE)
|
||||
// ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Terminate destination --- called by jpeg_finish_compress
|
||||
// after all data has been written. Usually needs to flush buffer.
|
||||
static void term_destination (j_compress_ptr cinfo)
|
||||
{
|
||||
my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
|
||||
size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
|
||||
|
||||
// Write any data remaining in the buffer
|
||||
if (datacount > 0)
|
||||
{
|
||||
dest->outfile->Write (dest->buffer, datacount);
|
||||
// if (dest->outfile.Write (dest->buffer, datacount) != datacount)
|
||||
// ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
}
|
||||
dest->outfile->Flush ();
|
||||
|
||||
// Make sure we wrote the output file OK
|
||||
// if (ferror(dest->outfile))
|
||||
// ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
}
|
||||
|
||||
// Prepare for output to a File object.
|
||||
static void jpeg_file_dest (j_compress_ptr cinfo, File& outfile)
|
||||
{
|
||||
my_dest_ptr dest;
|
||||
|
||||
// The destination object is made permanent so that multiple JPEG images
|
||||
// can be written to the same file without re-executing jpeg_stdio_dest.
|
||||
// This makes it dangerous to use this manager and a different destination
|
||||
// manager serially with the same JPEG object, because their private object
|
||||
// sizes may be different. Caveat programmer.
|
||||
if (cinfo->dest == NULL)
|
||||
{
|
||||
// first time for this JPEG object?
|
||||
cinfo->dest = (struct jpeg_destination_mgr *)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||
sizeof (my_destination_mgr));
|
||||
}
|
||||
|
||||
dest = (my_dest_ptr) cinfo->dest;
|
||||
dest->pub.init_destination = init_destination;
|
||||
dest->pub.empty_output_buffer = empty_output_buffer;
|
||||
dest->pub.term_destination = term_destination;
|
||||
dest->outfile = &outfile;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
bool Image::SaveJPG (File& file, int quality, bool progressive) const
|
||||
{
|
||||
struct jpeg_compress_struct cinfo;
|
||||
struct bt_jpeg_error_mgr jerr;
|
||||
int row_stride; // physical row widthPix in image buffer
|
||||
|
||||
// allocate and initialize JPEG compression object
|
||||
cinfo.err = jpeg_std_error(&jerr.pub);
|
||||
jerr.pub.error_exit = bt_jpeg_error_exit;
|
||||
|
||||
if (setjmp(jerr.setjmp_buffer))
|
||||
{
|
||||
// jpeg_destroy_compress(&cinfo);
|
||||
// if (outfile != NULL)
|
||||
// fclose(outfile);
|
||||
return false;
|
||||
}
|
||||
|
||||
jpeg_create_compress(&cinfo);
|
||||
|
||||
jpeg_file_dest(&cinfo, file);
|
||||
|
||||
cinfo.image_width = m_nWidth;
|
||||
cinfo.image_height = m_nHeight;
|
||||
cinfo.input_components = 3;
|
||||
cinfo.in_color_space = JCS_RGB;
|
||||
|
||||
jpeg_set_defaults (&cinfo);
|
||||
jpeg_set_quality (&cinfo, quality, TRUE);
|
||||
|
||||
if (progressive)
|
||||
jpeg_simple_progression(&cinfo);
|
||||
|
||||
jpeg_start_compress (&cinfo, TRUE);
|
||||
row_stride = m_nWidth * 3;
|
||||
|
||||
while (cinfo.next_scanline < cinfo.image_height)
|
||||
{
|
||||
unsigned char* outRow = m_pData + (cinfo.next_scanline * m_nWidth * 3);
|
||||
jpeg_write_scanlines(&cinfo, &outRow, 1);
|
||||
}
|
||||
|
||||
jpeg_finish_compress(&cinfo);
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // LC_HAVE_JPEGLIB
|
375
common/im_png.cpp
Executable file
375
common/im_png.cpp
Executable file
|
@ -0,0 +1,375 @@
|
|||
#include <stdlib.h>
|
||||
#include "config.h"
|
||||
#include "image.h"
|
||||
#include "file.h"
|
||||
|
||||
#ifdef LC_HAVE_PNGLIB
|
||||
|
||||
#include <png.h>
|
||||
|
||||
#define alpha_composite(composite, fg, alpha, bg) { \
|
||||
unsigned short temp = ((unsigned short)(fg)*(unsigned short)(alpha) + \
|
||||
(unsigned short)(bg)*(unsigned short)(255 - (unsigned short)(alpha)) + (unsigned short)128); \
|
||||
(composite) = (unsigned char)((temp + (temp >> 8)) >> 8); \
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
static void user_read_fn (png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
{
|
||||
png_size_t check;
|
||||
|
||||
// Read() returns 0 on error, so it is OK to store this in a png_size_t
|
||||
// instead of an int, which is what Read() actually returns.
|
||||
check = (png_size_t)((File*)png_ptr->io_ptr)->Read (data, length);
|
||||
|
||||
if (check != length)
|
||||
png_error(png_ptr, "Read Error");
|
||||
}
|
||||
|
||||
bool Image::LoadPNG (File& file)
|
||||
{
|
||||
unsigned char sig[8], red, green, blue;
|
||||
unsigned char *image_data = NULL;
|
||||
unsigned char *src, *dest;
|
||||
unsigned char r, g, b, a;
|
||||
unsigned long i, row;
|
||||
unsigned long image_rowbytes;
|
||||
png_color_16p pBackground;
|
||||
png_structp png_ptr = NULL;
|
||||
png_infop info_ptr = NULL;
|
||||
png_uint_32 width, height;
|
||||
png_bytepp row_pointers = NULL;
|
||||
int bit_depth, color_type;
|
||||
int image_channels;
|
||||
double gamma;
|
||||
|
||||
FreeData ();
|
||||
|
||||
file.Read (sig, 8);
|
||||
if (!png_check_sig(sig, 8))
|
||||
return false; // bad signature
|
||||
|
||||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!png_ptr)
|
||||
return false; // out of memory
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr)
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, NULL, NULL);
|
||||
return false; // out of memory
|
||||
}
|
||||
|
||||
if (setjmp(png_ptr->jmpbuf))
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_set_read_fn(png_ptr, (void *)&file, user_read_fn);
|
||||
// png_init_io(png_ptr, f);
|
||||
png_set_sig_bytes(png_ptr, 8); // we already read the 8 signature bytes
|
||||
|
||||
png_read_info(png_ptr, info_ptr); // read all PNG info up to image data
|
||||
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (setjmp(png_ptr->jmpbuf))
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD))
|
||||
{
|
||||
png_get_bKGD(png_ptr, info_ptr, &pBackground);
|
||||
|
||||
if (setjmp (png_ptr->jmpbuf))
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
// however, it always returns the raw bKGD data, regardless of any
|
||||
// bit-depth transformations, so check depth and adjust if necessary
|
||||
if (bit_depth == 16)
|
||||
{
|
||||
red = pBackground->red >> 8;
|
||||
green = pBackground->green >> 8;
|
||||
blue = pBackground->blue >> 8;
|
||||
}
|
||||
else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
||||
{
|
||||
if (bit_depth == 1)
|
||||
red = green = blue = pBackground->gray? 255 : 0;
|
||||
else if (bit_depth == 2)
|
||||
red = green = blue = (255/3) * pBackground->gray;
|
||||
else // bit_depth == 4
|
||||
red = green = blue = (255/15) * pBackground->gray;
|
||||
}
|
||||
else
|
||||
{
|
||||
red = (unsigned char)pBackground->red;
|
||||
green = (unsigned char)pBackground->green;
|
||||
blue = (unsigned char)pBackground->blue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (setjmp (png_ptr->jmpbuf))
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
red = green = blue = 0;
|
||||
}
|
||||
|
||||
// expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
|
||||
// transparency chunks to full alpha channel; strip 16-bit-per-sample
|
||||
// images to 8 bits per sample; and convert grayscale to RGB[A]
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
png_set_expand(png_ptr);
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
||||
png_set_expand(png_ptr);
|
||||
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
|
||||
png_set_expand(png_ptr);
|
||||
if (bit_depth == 16)
|
||||
png_set_strip_16(png_ptr);
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY ||
|
||||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||
png_set_gray_to_rgb(png_ptr);
|
||||
|
||||
if (png_get_gAMA(png_ptr, info_ptr, &gamma))
|
||||
png_set_gamma(png_ptr, 2.2, gamma);
|
||||
|
||||
// all transformations have been registered; now update info_ptr data,
|
||||
// get rowbytes and channels, and allocate image memory
|
||||
png_read_update_info(png_ptr, info_ptr);
|
||||
|
||||
image_rowbytes = png_get_rowbytes(png_ptr, info_ptr);
|
||||
image_channels = (int)png_get_channels(png_ptr, info_ptr);
|
||||
|
||||
if ((image_data = (unsigned char*)malloc(image_rowbytes*height)) == NULL)
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL)
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
free(image_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
// set the individual row_pointers to point at the correct offsets
|
||||
for (i = 0; i < height; ++i)
|
||||
row_pointers[i] = image_data + i*image_rowbytes;
|
||||
|
||||
// now we can go ahead and just read the whole image
|
||||
png_read_image(png_ptr, row_pointers);
|
||||
|
||||
// and we're done! (png_read_end() can be omitted if no processing of
|
||||
// post-IDAT text/time/etc. is desired)
|
||||
free(row_pointers);
|
||||
row_pointers = NULL;
|
||||
|
||||
png_read_end(png_ptr, NULL);
|
||||
|
||||
// done with PNG file, so clean up to minimize memory usage
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
|
||||
if (!image_data)
|
||||
return false;
|
||||
|
||||
// get our buffer set to hold data
|
||||
m_pData = (unsigned char*)malloc(width*height*image_channels);
|
||||
|
||||
if (m_pData == NULL)
|
||||
{
|
||||
free (image_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_nWidth = width;
|
||||
m_nHeight = height;
|
||||
if (image_channels == 3)
|
||||
m_bAlpha = false;
|
||||
else
|
||||
m_bAlpha = true;
|
||||
|
||||
for (row = 0; row < height; row++)
|
||||
{
|
||||
src = image_data + row*image_rowbytes;
|
||||
dest = m_pData + row*image_channels*width;
|
||||
|
||||
if (image_channels == 3)
|
||||
{
|
||||
for (i = width; i > 0; i--)
|
||||
{
|
||||
r = *src++;
|
||||
g = *src++;
|
||||
b = *src++;
|
||||
*dest++ = r;
|
||||
*dest++ = g;
|
||||
*dest++ = b;
|
||||
}
|
||||
}
|
||||
else // if (image_channels == 4)
|
||||
{
|
||||
for (i = width; i > 0; i--)
|
||||
{
|
||||
r = *src++;
|
||||
g = *src++;
|
||||
b = *src++;
|
||||
a = *src++;
|
||||
|
||||
if (a == 255)
|
||||
{
|
||||
*dest++ = r;
|
||||
*dest++ = g;
|
||||
*dest++ = b;
|
||||
}
|
||||
else if (a == 0)
|
||||
{
|
||||
*dest++ = red;
|
||||
*dest++ = green;
|
||||
*dest++ = blue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this macro (copied from png.h) composites the
|
||||
// foreground and background values and puts the
|
||||
// result into the first argument; there are no
|
||||
// side effects with the first argument
|
||||
alpha_composite(*dest++, r, a, red);
|
||||
alpha_composite(*dest++, g, a, green);
|
||||
alpha_composite(*dest++, b, a, blue);
|
||||
}
|
||||
*dest++ = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(image_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
static void user_write_fn (png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
{
|
||||
png_uint_32 check;
|
||||
|
||||
check = ((File*)png_ptr->io_ptr)->Write (data, length);
|
||||
if (check != length)
|
||||
{
|
||||
png_error(png_ptr, "Write Error");
|
||||
}
|
||||
}
|
||||
|
||||
static void user_flush_fn (png_structp png_ptr)
|
||||
{
|
||||
((File*)png_ptr->io_ptr)->Flush ();
|
||||
}
|
||||
|
||||
bool Image::SavePNG (File& file, bool transparent, bool interlaced, unsigned char* background) const
|
||||
{
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
png_bytepp row_pointers = NULL;
|
||||
png_color_8 sig_bit;
|
||||
png_color_16 bg;
|
||||
int i;
|
||||
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!png_ptr)
|
||||
return false;
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr)
|
||||
{
|
||||
png_destroy_write_struct(&png_ptr, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setjmp(png_ptr->jmpbuf))
|
||||
{
|
||||
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
// png_init_io(png_ptr, fp);
|
||||
png_set_write_fn (png_ptr, &file, user_write_fn, user_flush_fn);
|
||||
|
||||
png_set_IHDR (png_ptr, info_ptr, m_nWidth, m_nHeight, 8,
|
||||
transparent ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
|
||||
interlaced ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
bg.red = background[0];
|
||||
bg.green = background[1];
|
||||
bg.blue = background[2];
|
||||
png_set_bKGD(png_ptr, info_ptr, &bg);
|
||||
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
// Set the true bit depth of the image data
|
||||
sig_bit.red = 8;
|
||||
sig_bit.green = 8;
|
||||
sig_bit.blue = 8;
|
||||
sig_bit.alpha = 8;
|
||||
|
||||
png_set_sBIT(png_ptr, info_ptr, &sig_bit);
|
||||
|
||||
if ((row_pointers = (png_bytepp)malloc(m_nHeight*sizeof(png_bytep))) == NULL)
|
||||
{
|
||||
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
// set the individual row_pointers to point at the correct offsets
|
||||
if (transparent)
|
||||
{
|
||||
unsigned char *buf, *src, *dst, alpha;
|
||||
dst = buf = (unsigned char*)malloc (m_nWidth*m_nHeight*4);
|
||||
src = m_pData;
|
||||
|
||||
for (i = 0; i < m_nWidth*m_nHeight; i++)
|
||||
{
|
||||
if ((src[0] == background[0]) &&
|
||||
(src[1] == background[1]) &&
|
||||
(src[2] == background[2]))
|
||||
alpha = 0;
|
||||
else
|
||||
alpha = 255;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = alpha;
|
||||
}
|
||||
|
||||
for (i = 0; i < m_nHeight; i++)
|
||||
row_pointers[i] = buf + i*m_nWidth*4;
|
||||
png_write_image(png_ptr, row_pointers);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < m_nHeight; i++)
|
||||
row_pointers[i] = m_pData + i*m_nWidth*3;
|
||||
png_write_image(png_ptr, row_pointers);
|
||||
}
|
||||
|
||||
free(row_pointers);
|
||||
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // LC_HAVE_PNGLIB
|
512
common/image.cpp
Normal file
512
common/image.cpp
Normal file
|
@ -0,0 +1,512 @@
|
|||
// Image I/O routines
|
||||
//
|
||||
|
||||
#include "opengl.h"
|
||||
#ifdef LC_WINDOWS
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
//#include <mmsystem.h>
|
||||
#include <vfw.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "config.h"
|
||||
#include "image.h"
|
||||
#include "file.h"
|
||||
|
||||
// =============================================================================
|
||||
// Image functions
|
||||
|
||||
Image::Image ()
|
||||
{
|
||||
m_nWidth = 0;
|
||||
m_nHeight = 0;
|
||||
m_bAlpha = false;
|
||||
m_pData = NULL;
|
||||
}
|
||||
|
||||
Image::~Image ()
|
||||
{
|
||||
free (m_pData);
|
||||
}
|
||||
|
||||
void Image::FreeData ()
|
||||
{
|
||||
m_nWidth = 0;
|
||||
m_nHeight = 0;
|
||||
m_bAlpha = false;
|
||||
free (m_pData);
|
||||
m_pData = NULL;
|
||||
}
|
||||
|
||||
void Image::Allocate (int width, int height, bool alpha)
|
||||
{
|
||||
FreeData ();
|
||||
|
||||
m_nWidth = width;
|
||||
m_nHeight = height;
|
||||
m_bAlpha = alpha;
|
||||
|
||||
if (m_bAlpha)
|
||||
m_pData = (unsigned char*)malloc (width * height * 4);
|
||||
else
|
||||
m_pData = (unsigned char*)malloc (width * height * 3);
|
||||
}
|
||||
|
||||
void Image::ResizePow2 ()
|
||||
{
|
||||
int i, shifted_x, shifted_y;
|
||||
|
||||
shifted_x = m_nWidth;
|
||||
for (i = 0; ((i < 16) && (shifted_x != 0)); i++)
|
||||
shifted_x = shifted_x >> 1;
|
||||
shifted_x = (i != 0) ? 1 << (i-1) : 1;
|
||||
|
||||
shifted_y = m_nHeight;
|
||||
for (i = 0; ((i < 16) && (shifted_y != 0)); i++)
|
||||
shifted_y = shifted_y >> 1;
|
||||
shifted_y = (i != 0) ? 1 << (i-1) : 1;
|
||||
|
||||
if ((shifted_x != m_nWidth) || (shifted_y != m_nHeight))
|
||||
Resize (shifted_x, shifted_y);
|
||||
}
|
||||
|
||||
void Image::Resize (int width, int height)
|
||||
{
|
||||
int i, j, k, components, stx, sty;
|
||||
float accumx, accumy;
|
||||
unsigned char* bits;
|
||||
|
||||
if (m_bAlpha)
|
||||
components = 4;
|
||||
else
|
||||
components = 3;
|
||||
|
||||
bits = (unsigned char*)malloc (width * height * components);
|
||||
|
||||
for (j = 0; j < m_nHeight; j++)
|
||||
{
|
||||
accumy = (float)height*j/(float)m_nHeight;
|
||||
sty = (int)floor(accumy);
|
||||
|
||||
for (i = 0; i < m_nWidth; i++)
|
||||
{
|
||||
accumx = (float)width*i/(float)m_nWidth;
|
||||
stx = (int)floor(accumx);
|
||||
|
||||
for (k = 0; k < components; k++)
|
||||
bits[(stx+sty*width)*components+k] = m_pData[(i+j*m_nWidth)*components+k];
|
||||
}
|
||||
}
|
||||
|
||||
free (m_pData);
|
||||
m_pData = bits;
|
||||
m_nWidth = width;
|
||||
m_nHeight = height;
|
||||
}
|
||||
|
||||
void Image::FromOpenGL (int width, int height)
|
||||
{
|
||||
unsigned char *buf;
|
||||
buf = (unsigned char*)malloc (width*height*3);
|
||||
|
||||
FreeData ();
|
||||
|
||||
m_pData = (unsigned char*)malloc (width*height*3);
|
||||
m_nWidth = width;
|
||||
m_nHeight = height;
|
||||
m_bAlpha = false;
|
||||
|
||||
glPixelStorei (GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels (0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buf);
|
||||
|
||||
for (int row = 0; row < height; row++)
|
||||
memcpy (m_pData + (row*width*3), buf + ((height-row-1)*width*3), width*3);
|
||||
|
||||
free (buf);
|
||||
}
|
||||
|
||||
bool Image::FileLoad (File& file)
|
||||
{
|
||||
unsigned char buf[8];
|
||||
|
||||
// Read a few bytes
|
||||
if (file.Read (buf, 8) != 8)
|
||||
return false;
|
||||
file.Seek (-8, SEEK_CUR);
|
||||
|
||||
// Check for the BMP header
|
||||
if ((buf[0] == 'B') && (buf[1] == 'M'))
|
||||
{
|
||||
if (!LoadBMP (file))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef LC_HAVE_JPEGLIB
|
||||
if ((buf[0] == 0xFF) && (buf[1] == 0xD8))
|
||||
{
|
||||
if (!LoadJPG (file))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LC_HAVE_PNGLIB
|
||||
const unsigned char png_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
|
||||
|
||||
// Check for the PNG header
|
||||
if (memcmp (buf, png_signature, 8) == 0)
|
||||
{
|
||||
if (!LoadPNG (file))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check for the GIF header
|
||||
if ((buf[0] == 'G') && (buf[1] == 'I') && (buf[2] == 'F') &&
|
||||
(buf[3] == '8') && ((buf[4] == '7') || (buf[4] == '9')) &&
|
||||
(buf[5] == 'a'))
|
||||
{
|
||||
if (!LoadGIF (file))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// MessageBox (NULL, "Unknown File Format", "Error", MB_ICONSTOP);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Image::FileLoad (const char* filename)
|
||||
{
|
||||
FileDisk file;
|
||||
|
||||
if (!file.Open (filename, "rb"))
|
||||
return false;
|
||||
|
||||
return FileLoad (file);
|
||||
}
|
||||
|
||||
bool Image::FileSave (File& file, LC_IMAGE_OPTS* opts) const
|
||||
{
|
||||
switch (opts->format)
|
||||
{
|
||||
#ifdef LC_HAVE_JPEGLIB
|
||||
case LC_IMAGE_JPG:
|
||||
return SaveJPG (file, opts->quality, opts->interlaced);
|
||||
#endif
|
||||
|
||||
case LC_IMAGE_GIF:
|
||||
return SaveGIF (file, opts->transparent, opts->interlaced, opts->background);
|
||||
|
||||
case LC_IMAGE_BMP:
|
||||
return SaveBMP (file, opts->truecolor == false);
|
||||
|
||||
#ifdef LC_HAVE_PNGLIB
|
||||
case LC_IMAGE_PNG:
|
||||
return SavePNG (file, opts->transparent, opts->interlaced, opts->background);
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// MessageBox (NULL, "Could not save file", "Error", MB_ICONSTOP);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Image::FileSave (const char* filename, LC_IMAGE_OPTS* opts) const
|
||||
{
|
||||
char name[LC_MAXPATH], ext[5], *p;
|
||||
FileDisk file;
|
||||
bool needext = false;
|
||||
|
||||
strcpy (name, filename);
|
||||
p = name + strlen (name) - 1;
|
||||
|
||||
while ((p > name) && (*p != '/') && (*p != '\\') && (*p != '.'))
|
||||
p--;
|
||||
|
||||
if (*p != '.')
|
||||
needext = true;
|
||||
else
|
||||
{
|
||||
if (strlen (p) > 5)
|
||||
needext = true;
|
||||
else
|
||||
{
|
||||
strcpy (ext, p+1);
|
||||
strlwr (ext);
|
||||
|
||||
if (strcmp (ext, "bmp") == 0)
|
||||
opts->format = LC_IMAGE_BMP;
|
||||
else if (strcmp (ext, "gif") == 0)
|
||||
opts->format = LC_IMAGE_GIF;
|
||||
#ifdef LC_HAVE_JPEGLIB
|
||||
else if (strcmp (ext, "jpg") == 0)
|
||||
opts->format = LC_IMAGE_JPG;
|
||||
else if (strcmp (ext, "jpeg") == 0)
|
||||
opts->format = LC_IMAGE_JPG;
|
||||
#endif
|
||||
#ifdef LC_HAVE_PNGLIB
|
||||
else if (strcmp (ext, "png") == 0)
|
||||
opts->format = LC_IMAGE_PNG;
|
||||
#endif
|
||||
else
|
||||
needext = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needext)
|
||||
{
|
||||
// no extension, add from the options
|
||||
switch (opts->format)
|
||||
{
|
||||
case LC_IMAGE_BMP:
|
||||
strcat (name, ".bmp");
|
||||
break;
|
||||
case LC_IMAGE_GIF:
|
||||
strcat (name, ".gif");
|
||||
break;
|
||||
#ifdef LC_HAVE_JPEGLIB
|
||||
case LC_IMAGE_JPG:
|
||||
strcat (name, ".jpg");
|
||||
break;
|
||||
#endif
|
||||
#ifdef LC_HAVE_PNGLIB
|
||||
case LC_IMAGE_PNG:
|
||||
strcat (name, ".png");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!file.Open (name, "wb"))
|
||||
return false;
|
||||
|
||||
return FileSave (file, opts);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// Global functions
|
||||
|
||||
#ifdef LC_WINDOWS
|
||||
#include "system.h"
|
||||
|
||||
#define AVIIF_KEYFRAME 0x00000010L // this frame is a key frame.
|
||||
#define LPLPBI LPBITMAPINFOHEADER *
|
||||
|
||||
static HANDLE MakeDib (HBITMAP hbitmap, Image& image)
|
||||
{
|
||||
HANDLE hdib ;
|
||||
HDC hdc ;
|
||||
BITMAP bitmap ;
|
||||
UINT wLineLen ;
|
||||
DWORD dwSize ;
|
||||
DWORD wColSize ;
|
||||
LPBITMAPINFOHEADER lpbi ;
|
||||
LPBYTE lpBits ;
|
||||
UINT bits = 24;
|
||||
int i, j;
|
||||
|
||||
GetObject(hbitmap,sizeof(BITMAP),&bitmap) ;
|
||||
|
||||
// DWORD align the width of the DIB
|
||||
// Figure out the size of the colour table
|
||||
// Calculate the size of the DIB
|
||||
wLineLen = (bitmap.bmWidth*bits+31)/32 * 4;
|
||||
wColSize = sizeof(RGBQUAD)*((bits <= 8) ? 1<<bits : 0);
|
||||
dwSize = sizeof(BITMAPINFOHEADER) + wColSize +
|
||||
(DWORD)(UINT)wLineLen*(DWORD)(UINT)bitmap.bmHeight;
|
||||
|
||||
// Allocate room for a DIB and set the LPBI fields
|
||||
hdib = GlobalAlloc(GHND,dwSize);
|
||||
if (!hdib)
|
||||
return hdib ;
|
||||
|
||||
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib) ;
|
||||
|
||||
lpbi->biSize = sizeof(BITMAPINFOHEADER) ;
|
||||
lpbi->biWidth = bitmap.bmWidth ;
|
||||
lpbi->biHeight = bitmap.bmHeight ;
|
||||
lpbi->biPlanes = 1 ;
|
||||
lpbi->biBitCount = (WORD) bits ;
|
||||
lpbi->biCompression = BI_RGB ;
|
||||
lpbi->biSizeImage = dwSize - sizeof(BITMAPINFOHEADER) - wColSize ;
|
||||
lpbi->biXPelsPerMeter = 0 ;
|
||||
lpbi->biYPelsPerMeter = 0 ;
|
||||
lpbi->biClrUsed = (bits <= 8) ? 1<<bits : 0;
|
||||
lpbi->biClrImportant = 0 ;
|
||||
|
||||
// Get the bits from the bitmap and stuff them after the LPBI
|
||||
lpBits = (LPBYTE)(lpbi+1)+wColSize ;
|
||||
|
||||
hdc = CreateCompatibleDC(NULL) ;
|
||||
|
||||
GetDIBits(hdc,hbitmap,0,bitmap.bmHeight,lpBits,(LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
|
||||
|
||||
for (i = 0; i < lpbi->biHeight; i++)
|
||||
{
|
||||
unsigned char *src = image.GetData() + i * image.Width() * 3;
|
||||
unsigned char *dst = lpBits + (lpbi->biHeight - i - 1) * wLineLen;
|
||||
|
||||
for (j = 0; j < lpbi->biWidth; j++)
|
||||
{
|
||||
dst[0] = src[2];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[0];
|
||||
|
||||
src += 3;
|
||||
dst += 3;
|
||||
}
|
||||
}
|
||||
|
||||
// Fix this if GetDIBits messed it up....
|
||||
lpbi->biClrUsed = (bits <= 8) ? 1<<bits : 0;
|
||||
|
||||
DeleteDC(hdc) ;
|
||||
GlobalUnlock(hdib);
|
||||
|
||||
return hdib ;
|
||||
}
|
||||
|
||||
// Walk through our array of LPBI's and free them
|
||||
static void FreeFrames(LPLPBI alpbi, int frames)
|
||||
{
|
||||
int w;
|
||||
|
||||
if (!alpbi[0])
|
||||
return;
|
||||
|
||||
// Don't free a frame if it's a duplicate of the previous one
|
||||
for (w=0; w < frames; w++)
|
||||
if (alpbi[w] && alpbi[w] != alpbi[w-1])
|
||||
GlobalFreePtr(alpbi[w]);
|
||||
|
||||
for (w=0; w < frames; w++)
|
||||
alpbi[w] = NULL;
|
||||
}
|
||||
|
||||
// Fill an array of LPBI's with the frames for this movie
|
||||
static void MakeFrames (LPLPBI alpbi, Image *images, int frames)
|
||||
{
|
||||
HBITMAP hbitmap, hbitmapOld;
|
||||
HDC hdc, hdcMem;
|
||||
int i;
|
||||
RECT rc;
|
||||
|
||||
hdc = GetDC (NULL);
|
||||
hdcMem = CreateCompatibleDC (NULL);
|
||||
|
||||
hbitmap = CreateCompatibleBitmap (hdc, images[0].Width (), images[0].Height ());
|
||||
|
||||
// Now walk through and make all the frames
|
||||
for ( i=0; i < frames; i++ )
|
||||
{
|
||||
hbitmapOld = SelectBitmap(hdcMem, hbitmap);
|
||||
|
||||
// Fill the whole frame with white
|
||||
SetRect(&rc,0,0,images[0].Width (), images[0].Height ());
|
||||
FillRect(hdcMem,&rc,GetStockBrush(WHITE_BRUSH));
|
||||
|
||||
SelectBitmap(hdcMem, hbitmapOld);
|
||||
|
||||
// Make this into a DIB and stuff it into the array
|
||||
alpbi[i] = (LPBITMAPINFOHEADER)GlobalLock(MakeDib(hbitmap, images[i]));
|
||||
|
||||
// For an error, just duplicate the last frame if we can
|
||||
if (alpbi[i] == NULL && i )
|
||||
alpbi[i] = alpbi[i-1] ;
|
||||
}
|
||||
|
||||
// Select all the old objects back and delete resources
|
||||
DeleteBitmap(hbitmap) ;
|
||||
DeleteObject(hdcMem) ;
|
||||
ReleaseDC(NULL,hdc) ;
|
||||
}
|
||||
|
||||
void SaveVideo(char* filename, Image *images, int count, float fps)
|
||||
{
|
||||
AVISTREAMINFO strhdr;
|
||||
PAVIFILE pfile = NULL;
|
||||
PAVISTREAM ps = NULL, psCompressed = NULL;
|
||||
AVICOMPRESSOPTIONS opts;
|
||||
AVICOMPRESSOPTIONS FAR * aopts[1] = { &opts };
|
||||
LPBITMAPINFOHEADER *plpbi;
|
||||
_fmemset(&opts, 0, sizeof(opts));
|
||||
|
||||
// first let's make sure we are running on 1.1
|
||||
WORD wVer = HIWORD(VideoForWindowsVersion());
|
||||
if (wVer < 0x010a)
|
||||
{
|
||||
SystemDoMessageBox("Video for Windows 1.1 or later required", MB_OK|MB_ICONSTOP);
|
||||
return;
|
||||
}
|
||||
|
||||
AVIFileInit();
|
||||
|
||||
plpbi = (LPBITMAPINFOHEADER*) malloc (count*sizeof (LPBITMAPINFOHEADER));
|
||||
MakeFrames (plpbi, images, count);
|
||||
|
||||
if (AVIFileOpen(&pfile, filename, OF_WRITE | OF_CREATE, NULL) == AVIERR_OK)
|
||||
{
|
||||
// Fill in the header for the video stream.
|
||||
_fmemset(&strhdr, 0, sizeof(strhdr));
|
||||
strhdr.fccType = streamtypeVIDEO;
|
||||
strhdr.fccHandler = 0;
|
||||
strhdr.dwScale = 1;
|
||||
/////////////// set FPS
|
||||
strhdr.dwRate = 15; // 15 fps
|
||||
strhdr.dwSuggestedBufferSize = plpbi[0]->biSizeImage;
|
||||
SetRect(&strhdr.rcFrame, 0, 0, (int) plpbi[0]->biWidth, (int) plpbi[0]->biHeight);
|
||||
|
||||
// And create the stream.
|
||||
if (AVIFileCreateStream(pfile, &ps, &strhdr) == AVIERR_OK)
|
||||
if (AVISaveOptions(NULL, 0, 1, &ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts))
|
||||
// if (AVISaveOptions(AfxGetMainWnd()->m_hWnd, 0, 1, &ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts))
|
||||
if (AVIMakeCompressedStream(&psCompressed, ps, &opts, NULL) == AVIERR_OK)
|
||||
if (AVIStreamSetFormat(psCompressed, 0, plpbi[0], plpbi[0]->biSize + plpbi[0]->biClrUsed * sizeof(RGBQUAD)) == AVIERR_OK)
|
||||
{
|
||||
float fPause = (float)Sys_ProfileLoadInt("Default", "AVI Pause", 100)/100;
|
||||
int time = (int)(fPause * 15);
|
||||
///////////// set FPS
|
||||
time = 1;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (AVIStreamWrite(psCompressed, i * time, 1,
|
||||
(LPBYTE) plpbi[i] + plpbi[i]->biSize + plpbi[i]->biClrUsed * sizeof(RGBQUAD),
|
||||
plpbi[i]->biSizeImage, i%5 ? 0 : AVIIF_KEYFRAME, NULL, NULL) != AVIERR_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FreeFrames (plpbi, count);
|
||||
|
||||
// Now close the file
|
||||
if (ps) AVIStreamClose(ps);
|
||||
if (psCompressed) AVIStreamClose(psCompressed);
|
||||
if (pfile) AVIFileClose(pfile);
|
||||
AVIFileExit();
|
||||
}
|
||||
#else
|
||||
void SaveVideo(char* filename, Image *images, int count, float fps)
|
||||
{
|
||||
// SystemDoMessageBox("Format not supported under this platform.", LC_MB_OK|LC_MB_ERROR);
|
||||
}
|
||||
#endif
|
54
common/image.h
Normal file
54
common/image.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
#ifndef _IMAGE_H_
|
||||
#define _IMAGE_H_
|
||||
|
||||
class File;
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
class Image
|
||||
{
|
||||
public:
|
||||
Image ();
|
||||
virtual ~Image ();
|
||||
|
||||
bool FileSave (File& file, LC_IMAGE_OPTS* opts) const;
|
||||
bool FileSave (const char* filename, LC_IMAGE_OPTS* opts) const;
|
||||
bool FileLoad (File& file);
|
||||
bool FileLoad (const char* filename);
|
||||
|
||||
void Resize (int width, int height);
|
||||
void ResizePow2 ();
|
||||
void FromOpenGL (int width, int height);
|
||||
void Allocate (int width, int height, bool alpha);
|
||||
|
||||
int Width () const
|
||||
{ return m_nWidth; }
|
||||
int Height () const
|
||||
{ return m_nHeight; }
|
||||
int Alpha () const
|
||||
{ return m_bAlpha; }
|
||||
unsigned char* GetData () const
|
||||
{ return m_pData; }
|
||||
|
||||
protected:
|
||||
void FreeData ();
|
||||
|
||||
bool LoadJPG (File& file);
|
||||
bool LoadBMP (File& file);
|
||||
bool LoadPNG (File& file);
|
||||
bool LoadGIF (File& file);
|
||||
|
||||
bool SaveJPG (File& file, int quality, bool progressive) const;
|
||||
bool SaveBMP (File& file, bool quantize) const;
|
||||
bool SavePNG (File& file, bool transparent, bool interlaced, unsigned char* background) const;
|
||||
bool SaveGIF (File& file, bool transparent, bool interlaced, unsigned char* background) const;
|
||||
|
||||
int m_nWidth;
|
||||
int m_nHeight;
|
||||
bool m_bAlpha;
|
||||
unsigned char* m_pData;
|
||||
};
|
||||
|
||||
void SaveVideo(char* filename, Image *images, int count, float fps);
|
||||
|
||||
#endif // _IMAGE_H_
|
433
common/keyboard.cpp
Normal file
433
common/keyboard.cpp
Normal file
|
@ -0,0 +1,433 @@
|
|||
//
|
||||
// Code to handle user-defined keyboard shortcuts.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include "system.h"
|
||||
#include "keyboard.h"
|
||||
#include "file.h"
|
||||
#include "str.h"
|
||||
|
||||
// ============================================================================
|
||||
// Globals.
|
||||
|
||||
LC_KEYBOARD_COMMAND DefaultKeyboardShortcuts[] =
|
||||
{
|
||||
{ LC_FILE_NEW, "New Project", LC_KEYMOD1_CONTROL, LC_KEY_N, 0 },
|
||||
{ LC_FILE_OPEN, "Open Project", LC_KEYMOD1_CONTROL, LC_KEY_O, 0 },
|
||||
{ LC_FILE_MERGE, "Merge Project", 0, 0, 0 },
|
||||
{ LC_FILE_SAVE, "Save Project", LC_KEYMOD1_CONTROL, LC_KEY_S, 0 },
|
||||
{ LC_FILE_SAVEAS, "Save Project As", 0, 0, 0 },
|
||||
{ LC_FILE_PICTURE, "Save Picture", 0, 0, 0 },
|
||||
{ LC_FILE_3DS, "Export 3D Studio", 0, 0, 0 },
|
||||
{ LC_FILE_HTML, "Export HTML", 0, 0, 0 },
|
||||
{ LC_FILE_POVRAY, "Export POV-Ray", 0, 0, 0 },
|
||||
{ LC_FILE_WAVEFRONT, "Export Wavefront", 0, 0, 0 },
|
||||
{ LC_FILE_PROPERTIES, "Project Properties", 0, 0, 0 },
|
||||
// { LC_FILE_TERRAIN, "Terrain Editor", 0, 0, 0 },
|
||||
{ LC_FILE_LIBRARY, "Piece Library Manager", 0, 0, 0 },
|
||||
// { LC_FILE_RECENT, "Open Recent File", 0, 0, 0 },
|
||||
{ LC_EDIT_UNDO, "Undo", LC_KEYMOD1_CONTROL, LC_KEY_Z, 0 },
|
||||
{ LC_EDIT_REDO, "Redo", LC_KEYMOD1_CONTROL, LC_KEY_Y, 0 },
|
||||
{ LC_EDIT_CUT, "Cut", LC_KEYMOD1_CONTROL, LC_KEY_X, 0 },
|
||||
{ LC_EDIT_COPY, "Copy", LC_KEYMOD1_CONTROL, LC_KEY_C, 0 },
|
||||
{ LC_EDIT_PASTE, "Paste", LC_KEYMOD1_CONTROL, LC_KEY_V, 0 },
|
||||
{ LC_EDIT_SELECT_ALL, "Select All", LC_KEYMOD1_CONTROL, LC_KEY_A, 0 },
|
||||
{ LC_EDIT_SELECT_NONE, "Select None", 0, 0, 0 },
|
||||
{ LC_EDIT_SELECT_INVERT, "Select Invert", 0, 0, 0 },
|
||||
{ LC_EDIT_SELECT_BYNAME, "Select By Name", 0, 0, 0 },
|
||||
{ LC_PIECE_INSERT, "Piece Insert", 0, LC_KEY_INSERT, 0 },
|
||||
{ LC_PIECE_DELETE, "Piece Delete", 0, LC_KEY_DELETE, 0 },
|
||||
// { LC_PIECE_MINIFIG, "Minifig Wizard", 0, 0, 0 },
|
||||
{ LC_PIECE_ARRAY, "Piece Array", 0, 0, 0 },
|
||||
// { LC_PIECE_COPYKEYS, "", 0, 0, 0 },
|
||||
{ LC_PIECE_GROUP, "Piece Group", LC_KEYMOD1_CONTROL, LC_KEY_G, 0 },
|
||||
{ LC_PIECE_UNGROUP, "Piece Ungroup", LC_KEYMOD1_CONTROL, LC_KEY_U, 0 },
|
||||
{ LC_PIECE_GROUP_ADD, "Group Add Piece", 0, 0, 0 },
|
||||
{ LC_PIECE_GROUP_REMOVE, "Group Remove Piece", 0, 0, 0 },
|
||||
{ LC_PIECE_GROUP_EDIT, "Group Edit", 0, 0, 0 },
|
||||
{ LC_PIECE_HIDE_SELECTED, "Hide Selection", LC_KEYMOD1_CONTROL, LC_KEY_H, 0 },
|
||||
{ LC_PIECE_HIDE_UNSELECTED, "Unhide Selection", 0, 0, 0 },
|
||||
{ LC_PIECE_UNHIDE_ALL, "Unhide All", 0, 0, 0 },
|
||||
{ LC_PIECE_PREVIOUS, "Piece Previous Step", 0, 0, 0 },
|
||||
{ LC_PIECE_NEXT, "Piece Next Step", 0, 0, 0 },
|
||||
{ LC_VIEW_PREFERENCES, "Preferences", 0, 0, 0 },
|
||||
// { LC_VIEW_ZOOM, "", 0, 0, 0 },
|
||||
{ LC_VIEW_ZOOMIN, "Zoom In", 0, 0, 0 },
|
||||
{ LC_VIEW_ZOOMOUT, "Zoom Out", 0, 0, 0 },
|
||||
{ LC_VIEW_ZOOMEXTENTS, "Zoom Extents", 0, 0, 0 },
|
||||
// { LC_VIEW_VIEWPORTS, "", 0, 0, 0 },
|
||||
{ LC_VIEW_STEP_NEXT, "Step Next", 0, 0, 0 },
|
||||
{ LC_VIEW_STEP_PREVIOUS, "Step Previous", 0, 0, 0 },
|
||||
{ LC_VIEW_STEP_FIRST, "Step First", 0, 0, 0 },
|
||||
{ LC_VIEW_STEP_LAST, "Step Last", 0, 0, 0 },
|
||||
// { LC_VIEW_STEP_CHOOSE, "", 0, 0, 0 },
|
||||
// { LC_VIEW_STEP_SET, "", 0, 0, 0 },
|
||||
// { LC_VIEW_STOP, "", 0, 0, 0 },
|
||||
// { LC_VIEW_PLAY, "", 0, 0, 0 },
|
||||
{ LC_VIEW_CAMERA_FRONT, "Camera Front", LC_KEYMOD_VIEWONLY, LC_KEY_F, 0 },
|
||||
{ LC_VIEW_CAMERA_BACK, "Camera Back", LC_KEYMOD_VIEWONLY, LC_KEY_B, 0 },
|
||||
{ LC_VIEW_CAMERA_TOP, "Camera Top", LC_KEYMOD_VIEWONLY, LC_KEY_T, 0 },
|
||||
{ LC_VIEW_CAMERA_BOTTOM, "Camera Bottom", LC_KEYMOD_VIEWONLY, LC_KEY_U, 0 },
|
||||
{ LC_VIEW_CAMERA_LEFT, "Camera Left", LC_KEYMOD_VIEWONLY, LC_KEY_L, 0 },
|
||||
{ LC_VIEW_CAMERA_RIGHT, "Camera Right", LC_KEYMOD_VIEWONLY, LC_KEY_R, 0 },
|
||||
{ LC_VIEW_CAMERA_MAIN, "Camera Main", LC_KEYMOD_VIEWONLY, LC_KEY_M, 0 },
|
||||
// { LC_VIEW_CAMERA_MENU, "", 0, 0, 0 },
|
||||
// { LC_VIEW_CAMERA_RESET, "", 0, 0, 0 },
|
||||
// { LC_VIEW_AUTOPAN, "", 0, 0, 0 },
|
||||
// { LC_HELP_ABOUT, "", 0, 0, 0 },
|
||||
// { LC_TOOLBAR_ANIMATION, "", 0, 0, 0 },
|
||||
// { LC_TOOLBAR_ADDKEYS, "", 0, 0, 0 },
|
||||
// { LC_TOOLBAR_SNAPMENU, "", 0, 0, 0 },
|
||||
// { LC_TOOLBAR_LOCKMENU, "", 0, 0, 0 },
|
||||
// { LC_TOOLBAR_FASTRENDER, "", 0, 0, 0 },
|
||||
// { LC_TOOLBAR_BACKGROUND, "", 0, 0, 0 },
|
||||
{ LC_VIEW_STEP_INSERT, "Step Insert", 0, 0, 0 },
|
||||
{ LC_VIEW_STEP_DELETE, "Step Delete", 0, 0, 0 },
|
||||
{ LC_EDIT_MOVEXY_SNAP_0, "Move XY Snap 0", 0, LC_KEY_0, 0 },
|
||||
{ LC_EDIT_MOVEXY_SNAP_1, "Move XY Snap 1", 0, LC_KEY_1, 0 },
|
||||
{ LC_EDIT_MOVEXY_SNAP_2, "Move XY Snap 2", 0, LC_KEY_2, 0 },
|
||||
{ LC_EDIT_MOVEXY_SNAP_3, "Move XY Snap 3", 0, LC_KEY_3, 0 },
|
||||
{ LC_EDIT_MOVEXY_SNAP_4, "Move XY Snap 4", 0, LC_KEY_4, 0 },
|
||||
{ LC_EDIT_MOVEXY_SNAP_5, "Move XY Snap 5", 0, LC_KEY_5, 0 },
|
||||
{ LC_EDIT_MOVEXY_SNAP_6, "Move XY Snap 6", 0, LC_KEY_6, 0 },
|
||||
{ LC_EDIT_MOVEXY_SNAP_7, "Move XY Snap 7", 0, LC_KEY_7, 0 },
|
||||
{ LC_EDIT_MOVEXY_SNAP_8, "Move XY Snap 8", 0, LC_KEY_8, 0 },
|
||||
{ LC_EDIT_MOVEXY_SNAP_9, "Move XY Snap 9", 0, LC_KEY_9, 0 },
|
||||
{ LC_EDIT_MOVEZ_SNAP_0, "Move Z Snap 0", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_0, 0 },
|
||||
{ LC_EDIT_MOVEZ_SNAP_1, "Move Z Snap 1", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_1, 0 },
|
||||
{ LC_EDIT_MOVEZ_SNAP_2, "Move Z Snap 2", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_2, 0 },
|
||||
{ LC_EDIT_MOVEZ_SNAP_3, "Move Z Snap 3", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_3, 0 },
|
||||
{ LC_EDIT_MOVEZ_SNAP_4, "Move Z Snap 4", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_4, 0 },
|
||||
{ LC_EDIT_MOVEZ_SNAP_5, "Move Z Snap 5", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_5, 0 },
|
||||
{ LC_EDIT_MOVEZ_SNAP_6, "Move Z Snap 6", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_6, 0 },
|
||||
{ LC_EDIT_MOVEZ_SNAP_7, "Move Z Snap 7", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_7, 0 },
|
||||
{ LC_EDIT_MOVEZ_SNAP_8, "Move Z Snap 8", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_8, 0 },
|
||||
{ LC_EDIT_MOVEZ_SNAP_9, "Move Z Snap 9", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_9, 0 },
|
||||
{ LC_EDIT_ANGLE_SNAP_0, "Angle Snap 1", LC_KEYMOD1_SHIFT, LC_KEY_0, 0 },
|
||||
{ LC_EDIT_ANGLE_SNAP_1, "Angle Snap 5", LC_KEYMOD1_SHIFT, LC_KEY_1, 0 },
|
||||
{ LC_EDIT_ANGLE_SNAP_2, "Angle Snap 10", LC_KEYMOD1_SHIFT, LC_KEY_2, 0 },
|
||||
{ LC_EDIT_ANGLE_SNAP_3, "Angle Snap 15", LC_KEYMOD1_SHIFT, LC_KEY_3, 0 },
|
||||
{ LC_EDIT_ANGLE_SNAP_4, "Angle Snap 30", LC_KEYMOD1_SHIFT, LC_KEY_4, 0 },
|
||||
{ LC_EDIT_ANGLE_SNAP_5, "Angle Snap 45", LC_KEYMOD1_SHIFT, LC_KEY_5, 0 },
|
||||
{ LC_EDIT_ANGLE_SNAP_6, "Angle Snap 60", LC_KEYMOD1_SHIFT, LC_KEY_6, 0 },
|
||||
{ LC_EDIT_ANGLE_SNAP_7, "Angle Snap 90", LC_KEYMOD1_SHIFT, LC_KEY_7, 0 },
|
||||
{ LC_EDIT_ANGLE_SNAP_8, "Angle Snap 180", LC_KEYMOD1_SHIFT, LC_KEY_8, 0 },
|
||||
{ LC_EDIT_ACTION_SELECT, "Select Mode", 0, 0, 0 },
|
||||
{ LC_EDIT_ACTION_INSERT, "Insert Mode", 0, 0, 0 },
|
||||
{ LC_EDIT_ACTION_LIGHT, "Light Mode", 0, 0, 0 },
|
||||
{ LC_EDIT_ACTION_SPOTLIGHT, "Spotlight Mode", 0, 0, 0 },
|
||||
{ LC_EDIT_ACTION_CAMERA, "Camera Mode", 0, 0, 0 },
|
||||
{ LC_EDIT_ACTION_MOVE, "Move Mode", LC_KEYMOD1_SHIFT, LC_KEY_M, 0 },
|
||||
{ LC_EDIT_ACTION_ROTATE, "Rotate Mode", LC_KEYMOD1_SHIFT, LC_KEY_R, 0 },
|
||||
{ LC_EDIT_ACTION_ERASER, "Eraser Mode", LC_KEYMOD1_SHIFT, LC_KEY_E, 0 },
|
||||
{ LC_EDIT_ACTION_PAINT, "Paint Mode", LC_KEYMOD1_SHIFT, LC_KEY_N, 0 },
|
||||
{ LC_EDIT_ACTION_ZOOM, "Zoom Mode", LC_KEYMOD1_SHIFT, LC_KEY_Z, 0 },
|
||||
{ LC_EDIT_ACTION_ZOOM_REGION, "Zoom Region Mode", 0, 0, 0 },
|
||||
{ LC_EDIT_ACTION_PAN, "Pan Mode", LC_KEYMOD1_SHIFT, LC_KEY_P, 0 },
|
||||
{ LC_EDIT_ACTION_ROTATE_VIEW, "Rotate View Mode", LC_KEYMOD1_SHIFT, LC_KEY_T, 0 },
|
||||
{ LC_EDIT_ACTION_ROLL, "Roll Camera Mode", LC_KEYMOD1_SHIFT, LC_KEY_L, 0 },
|
||||
};
|
||||
|
||||
const int KeyboardShortcutsCount = sizeof(DefaultKeyboardShortcuts)/sizeof(KeyboardShortcuts[0]);
|
||||
|
||||
LC_KEYBOARD_COMMAND KeyboardShortcuts[KeyboardShortcutsCount];
|
||||
|
||||
// ============================================================================
|
||||
// Functions
|
||||
|
||||
bool SaveKeyboardShortcuts(const char* FileName)
|
||||
{
|
||||
FileDisk f;
|
||||
|
||||
if (!f.Open(FileName, "wt"))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < KeyboardShortcutsCount; i++)
|
||||
{
|
||||
LC_KEYBOARD_COMMAND& Cmd = KeyboardShortcuts[i];
|
||||
String str;
|
||||
|
||||
str = Cmd.Description;
|
||||
str += "=";
|
||||
|
||||
if (Cmd.Key1)
|
||||
{
|
||||
if (Cmd.Flags & LC_KEYMOD1_SHIFT)
|
||||
str += "Shift+";
|
||||
|
||||
if (Cmd.Flags & LC_KEYMOD1_CONTROL)
|
||||
str += "Ctrl+";
|
||||
|
||||
str += "\"";
|
||||
str += GetKeyName(Cmd.Key1);
|
||||
str += "\"";
|
||||
}
|
||||
|
||||
if (Cmd.Key2)
|
||||
{
|
||||
str += ",";
|
||||
|
||||
if (Cmd.Flags & LC_KEYMOD2_SHIFT)
|
||||
str += "Shift+";
|
||||
|
||||
if (Cmd.Flags & LC_KEYMOD2_CONTROL)
|
||||
str += "Ctrl+";
|
||||
|
||||
str += "\"";
|
||||
str += GetKeyName(Cmd.Key2);
|
||||
str += "\"";
|
||||
}
|
||||
|
||||
str += "\n";
|
||||
|
||||
f.Write((const char*)str, str.GetLength());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadKeyboardShortcuts(const char* FileName)
|
||||
{
|
||||
FileDisk f;
|
||||
int i;
|
||||
|
||||
if (!f.Open(FileName, "rt"))
|
||||
return false;
|
||||
|
||||
// Remove all existing shortcuts
|
||||
for (i = 0; i < KeyboardShortcutsCount; i++)
|
||||
{
|
||||
LC_KEYBOARD_COMMAND& Cmd = KeyboardShortcuts[i];
|
||||
|
||||
Cmd.Key1 = 0;
|
||||
Cmd.Key2 = 0;
|
||||
Cmd.Flags = DefaultKeyboardShortcuts[i].Flags & ~LC_KEYMOD_MASK;
|
||||
}
|
||||
|
||||
char Line[1024];
|
||||
while (f.ReadLine(Line, 1024))
|
||||
{
|
||||
char* ptr = strchr(Line, '=');
|
||||
|
||||
if (ptr == NULL)
|
||||
continue;
|
||||
|
||||
*ptr = 0;
|
||||
ptr++;
|
||||
|
||||
|
||||
for (i = 0; i < KeyboardShortcutsCount; i++)
|
||||
{
|
||||
LC_KEYBOARD_COMMAND& Cmd = KeyboardShortcuts[i];
|
||||
|
||||
if (strcmp(Line, Cmd.Description))
|
||||
continue;
|
||||
|
||||
if (!strncmp(ptr, "Shift+", 6))
|
||||
{
|
||||
Cmd.Flags |= LC_KEYMOD1_SHIFT;
|
||||
ptr += 6;
|
||||
}
|
||||
|
||||
if (!strncmp(ptr, "Ctrl+", 5))
|
||||
{
|
||||
Cmd.Flags |= LC_KEYMOD1_CONTROL;
|
||||
ptr += 5;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
char* ptr2 = strchr(ptr, '\"');
|
||||
|
||||
if (ptr2 == NULL)
|
||||
{
|
||||
Cmd.Flags &= ~(LC_KEYMOD1_SHIFT | LC_KEYMOD1_CONTROL);
|
||||
break;
|
||||
}
|
||||
|
||||
*ptr2 = 0;
|
||||
Cmd.Key1 = GetKeyFromName(ptr);
|
||||
|
||||
ptr = ptr2 + 1;
|
||||
|
||||
if (*ptr != ',')
|
||||
break;
|
||||
ptr++;
|
||||
|
||||
if (!strncmp(ptr, "Shift+", 6))
|
||||
{
|
||||
Cmd.Flags |= LC_KEYMOD2_SHIFT;
|
||||
ptr += 6;
|
||||
}
|
||||
|
||||
if (!strncmp(ptr, "Ctrl+", 5))
|
||||
{
|
||||
Cmd.Flags |= LC_KEYMOD2_CONTROL;
|
||||
ptr += 5;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
ptr2 = strchr(ptr, '\"');
|
||||
|
||||
if (ptr2 == NULL)
|
||||
{
|
||||
Cmd.Flags &= ~(LC_KEYMOD2_SHIFT | LC_KEYMOD2_CONTROL);
|
||||
break;
|
||||
}
|
||||
|
||||
*ptr2 = 0;
|
||||
Cmd.Key2 = GetKeyFromName(ptr);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResetKeyboardShortcuts()
|
||||
{
|
||||
memcpy(KeyboardShortcuts, DefaultKeyboardShortcuts, sizeof(KeyboardShortcuts));
|
||||
}
|
||||
|
||||
void InitKeyboardShortcuts()
|
||||
{
|
||||
const char* FileName = Sys_ProfileLoadString("Settings", "Keyboard", "");
|
||||
|
||||
ResetKeyboardShortcuts();
|
||||
LoadKeyboardShortcuts(FileName);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int Key;
|
||||
const char* Name;
|
||||
|
||||
} LC_KEYNAME_ENTRY;
|
||||
|
||||
static LC_KEYNAME_ENTRY KeyNames[] =
|
||||
{
|
||||
{ LC_KEY_BACK, "Backspace" },
|
||||
{ LC_KEY_TAB, "Tab" },
|
||||
{ LC_KEY_RETURN, "Return" },
|
||||
{ LC_KEY_PAUSE, "Pause" },
|
||||
{ LC_KEY_CAPITAL, "Caps" },
|
||||
{ LC_KEY_ESCAPE, "Escape" },
|
||||
{ LC_KEY_SPACE, "Space" },
|
||||
{ LC_KEY_PRIOR, "Page Up" },
|
||||
{ LC_KEY_NEXT, "Page Down" },
|
||||
{ LC_KEY_END, "End" },
|
||||
{ LC_KEY_HOME, "Home" },
|
||||
{ LC_KEY_LEFT, "Left" },
|
||||
{ LC_KEY_UP, "Up" },
|
||||
{ LC_KEY_RIGHT, "Right" },
|
||||
{ LC_KEY_DOWN, "Down" },
|
||||
{ LC_KEY_SELECT, "Select" },
|
||||
{ LC_KEY_PRINT, "Print" },
|
||||
{ LC_KEY_INSERT, "Insert" },
|
||||
{ LC_KEY_DELETE, "Delete" },
|
||||
{ LC_KEY_0, "0" },
|
||||
{ LC_KEY_1, "1" },
|
||||
{ LC_KEY_2, "2" },
|
||||
{ LC_KEY_3, "3" },
|
||||
{ LC_KEY_4, "4" },
|
||||
{ LC_KEY_5, "5" },
|
||||
{ LC_KEY_6, "6" },
|
||||
{ LC_KEY_7, "7" },
|
||||
{ LC_KEY_8, "8" },
|
||||
{ LC_KEY_9, "9" },
|
||||
{ LC_KEY_A, "A" },
|
||||
{ LC_KEY_B, "B" },
|
||||
{ LC_KEY_C, "C" },
|
||||
{ LC_KEY_D, "D" },
|
||||
{ LC_KEY_E, "E" },
|
||||
{ LC_KEY_F, "F" },
|
||||
{ LC_KEY_G, "G" },
|
||||
{ LC_KEY_H, "H" },
|
||||
{ LC_KEY_I, "I" },
|
||||
{ LC_KEY_J, "J" },
|
||||
{ LC_KEY_K, "K" },
|
||||
{ LC_KEY_L, "L" },
|
||||
{ LC_KEY_M, "M" },
|
||||
{ LC_KEY_N, "N" },
|
||||
{ LC_KEY_O, "O" },
|
||||
{ LC_KEY_P, "P" },
|
||||
{ LC_KEY_Q, "Q" },
|
||||
{ LC_KEY_R, "R" },
|
||||
{ LC_KEY_S, "S" },
|
||||
{ LC_KEY_T, "T" },
|
||||
{ LC_KEY_U, "U" },
|
||||
{ LC_KEY_V, "V" },
|
||||
{ LC_KEY_W, "W" },
|
||||
{ LC_KEY_X, "X" },
|
||||
{ LC_KEY_Y, "Y" },
|
||||
{ LC_KEY_Z, "Z" },
|
||||
{ LC_KEY_NUMPAD0, "Numpad 0" },
|
||||
{ LC_KEY_NUMPAD1, "Numpad 1" },
|
||||
{ LC_KEY_NUMPAD2, "Numpad 2" },
|
||||
{ LC_KEY_NUMPAD3, "Numpad 3" },
|
||||
{ LC_KEY_NUMPAD4, "Numpad 4" },
|
||||
{ LC_KEY_NUMPAD5, "Numpad 5" },
|
||||
{ LC_KEY_NUMPAD6, "Numpad 6" },
|
||||
{ LC_KEY_NUMPAD7, "Numpad 7" },
|
||||
{ LC_KEY_NUMPAD8, "Numpad 8" },
|
||||
{ LC_KEY_NUMPAD9, "Numpad 9" },
|
||||
{ LC_KEY_MULTIPLY, "Numpad *" },
|
||||
{ LC_KEY_ADD, "Numpad +" },
|
||||
{ LC_KEY_SUBTRACT, "Numpad -" },
|
||||
{ LC_KEY_DECIMAL, "Numpad ." },
|
||||
{ LC_KEY_DIVIDE, "Numpad /" },
|
||||
{ LC_KEY_F1, "F1" },
|
||||
{ LC_KEY_F2, "F2" },
|
||||
{ LC_KEY_F3, "F3" },
|
||||
{ LC_KEY_F4, "F4" },
|
||||
{ LC_KEY_F5, "F5" },
|
||||
{ LC_KEY_F6, "F6" },
|
||||
{ LC_KEY_F7, "F7" },
|
||||
{ LC_KEY_F8, "F8" },
|
||||
{ LC_KEY_F9, "F9" },
|
||||
{ LC_KEY_F10, "F10" },
|
||||
{ LC_KEY_F11, "F11" },
|
||||
{ LC_KEY_F12, "F12" },
|
||||
{ LC_KEY_F13, "F13" },
|
||||
{ LC_KEY_F14, "F14" },
|
||||
{ LC_KEY_F15, "F15" },
|
||||
{ LC_KEY_F16, "F16" },
|
||||
{ LC_KEY_F17, "F17" },
|
||||
{ LC_KEY_F18, "F18" },
|
||||
{ LC_KEY_F19, "F19" },
|
||||
{ LC_KEY_F20, "F20" },
|
||||
{ LC_KEY_F21, "F21" },
|
||||
{ LC_KEY_F22, "F22" },
|
||||
{ LC_KEY_F23, "F23" },
|
||||
{ LC_KEY_F24, "F24" },
|
||||
{ LC_KEY_NUMLOCK, "Num Lock" },
|
||||
{ LC_KEY_SCROLL, "Scroll" }
|
||||
};
|
||||
|
||||
// Returns a string with the name of the key.
|
||||
const char* GetKeyName(char Key)
|
||||
{
|
||||
int Count = sizeof(KeyNames)/sizeof(KeyNames[0]);
|
||||
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
if (Key == KeyNames[i].Key)
|
||||
return KeyNames[i].Name;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char GetKeyFromName(const char* Name)
|
||||
{
|
||||
int Count = sizeof(KeyNames)/sizeof(KeyNames[0]);
|
||||
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
if (!strcmp(Name, KeyNames[i].Name))
|
||||
return KeyNames[i].Key;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
151
common/keyboard.h
Normal file
151
common/keyboard.h
Normal file
|
@ -0,0 +1,151 @@
|
|||
#ifndef _KEYBOARD_H_
|
||||
#define _KEYBOARD_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
// ============================================================================
|
||||
// Keyboard keys.
|
||||
|
||||
#define LC_KEY_BACK 0x08
|
||||
#define LC_KEY_TAB 0x09
|
||||
|
||||
#define LC_KEY_RETURN 0x0D
|
||||
|
||||
#define LC_KEY_PAUSE 0x13
|
||||
#define LC_KEY_CAPITAL 0x14
|
||||
|
||||
#define LC_KEY_ESCAPE 0x1B
|
||||
|
||||
#define LC_KEY_SPACE 0x20
|
||||
#define LC_KEY_PRIOR 0x21
|
||||
#define LC_KEY_NEXT 0x22
|
||||
#define LC_KEY_END 0x23
|
||||
#define LC_KEY_HOME 0x24
|
||||
#define LC_KEY_LEFT 0x25
|
||||
#define LC_KEY_UP 0x26
|
||||
#define LC_KEY_RIGHT 0x27
|
||||
#define LC_KEY_DOWN 0x28
|
||||
#define LC_KEY_SELECT 0x29
|
||||
#define LC_KEY_PRINT 0x2A
|
||||
#define LC_KEY_INSERT 0x2D
|
||||
#define LC_KEY_DELETE 0x2E
|
||||
|
||||
#define LC_KEY_0 0x30
|
||||
#define LC_KEY_1 0x31
|
||||
#define LC_KEY_2 0x32
|
||||
#define LC_KEY_3 0x33
|
||||
#define LC_KEY_4 0x34
|
||||
#define LC_KEY_5 0x35
|
||||
#define LC_KEY_6 0x36
|
||||
#define LC_KEY_7 0x37
|
||||
#define LC_KEY_8 0x38
|
||||
#define LC_KEY_9 0x39
|
||||
|
||||
#define LC_KEY_A 0x41
|
||||
#define LC_KEY_B 0x42
|
||||
#define LC_KEY_C 0x43
|
||||
#define LC_KEY_D 0x44
|
||||
#define LC_KEY_E 0x45
|
||||
#define LC_KEY_F 0x46
|
||||
#define LC_KEY_G 0x47
|
||||
#define LC_KEY_H 0x48
|
||||
#define LC_KEY_I 0x49
|
||||
#define LC_KEY_J 0x4A
|
||||
#define LC_KEY_K 0x4B
|
||||
#define LC_KEY_L 0x4C
|
||||
#define LC_KEY_M 0x4D
|
||||
#define LC_KEY_N 0x4E
|
||||
#define LC_KEY_O 0x4F
|
||||
#define LC_KEY_P 0x50
|
||||
#define LC_KEY_Q 0x51
|
||||
#define LC_KEY_R 0x52
|
||||
#define LC_KEY_S 0x53
|
||||
#define LC_KEY_T 0x54
|
||||
#define LC_KEY_U 0x55
|
||||
#define LC_KEY_V 0x56
|
||||
#define LC_KEY_W 0x57
|
||||
#define LC_KEY_X 0x58
|
||||
#define LC_KEY_Y 0x59
|
||||
#define LC_KEY_Z 0x5A
|
||||
|
||||
#define LC_KEY_NUMPAD0 0x60
|
||||
#define LC_KEY_NUMPAD1 0x61
|
||||
#define LC_KEY_NUMPAD2 0x62
|
||||
#define LC_KEY_NUMPAD3 0x63
|
||||
#define LC_KEY_NUMPAD4 0x64
|
||||
#define LC_KEY_NUMPAD5 0x65
|
||||
#define LC_KEY_NUMPAD6 0x66
|
||||
#define LC_KEY_NUMPAD7 0x67
|
||||
#define LC_KEY_NUMPAD8 0x68
|
||||
#define LC_KEY_NUMPAD9 0x69
|
||||
#define LC_KEY_MULTIPLY 0x6A
|
||||
#define LC_KEY_ADD 0x6B
|
||||
//#define LC_KEY_SEPARATOR 0x6C
|
||||
#define LC_KEY_SUBTRACT 0x6D
|
||||
#define LC_KEY_DECIMAL 0x6E
|
||||
#define LC_KEY_DIVIDE 0x6F
|
||||
#define LC_KEY_F1 0x70
|
||||
#define LC_KEY_F2 0x71
|
||||
#define LC_KEY_F3 0x72
|
||||
#define LC_KEY_F4 0x73
|
||||
#define LC_KEY_F5 0x74
|
||||
#define LC_KEY_F6 0x75
|
||||
#define LC_KEY_F7 0x76
|
||||
#define LC_KEY_F8 0x77
|
||||
#define LC_KEY_F9 0x78
|
||||
#define LC_KEY_F10 0x79
|
||||
#define LC_KEY_F11 0x7A
|
||||
#define LC_KEY_F12 0x7B
|
||||
#define LC_KEY_F13 0x7C
|
||||
#define LC_KEY_F14 0x7D
|
||||
#define LC_KEY_F15 0x7E
|
||||
#define LC_KEY_F16 0x7F
|
||||
#define LC_KEY_F17 0x80
|
||||
#define LC_KEY_F18 0x81
|
||||
#define LC_KEY_F19 0x82
|
||||
#define LC_KEY_F20 0x83
|
||||
#define LC_KEY_F21 0x84
|
||||
#define LC_KEY_F22 0x85
|
||||
#define LC_KEY_F23 0x86
|
||||
#define LC_KEY_F24 0x87
|
||||
|
||||
#define LC_KEY_NUMLOCK 0x90
|
||||
#define LC_KEY_SCROLL 0x91
|
||||
|
||||
// ============================================================================
|
||||
// Functions.
|
||||
|
||||
#define LC_KEYMOD1_SHIFT 0x01
|
||||
#define LC_KEYMOD1_CONTROL 0x02
|
||||
#define LC_KEYMOD2_SHIFT 0x04
|
||||
#define LC_KEYMOD2_CONTROL 0x08
|
||||
#define LC_KEYMOD_VIEWONLY 0x10
|
||||
|
||||
#define LC_KEYMOD1_MASK (LC_KEYMOD1_SHIFT | LC_KEYMOD1_CONTROL)
|
||||
#define LC_KEYMOD2_MASK (LC_KEYMOD2_SHIFT | LC_KEYMOD2_CONTROL)
|
||||
#define LC_KEYMOD_MASK (LC_KEYMOD1_MASK | LC_KEYMOD2_MASK)
|
||||
|
||||
#define LC_KEYMOD_1TO2(a) ((a & ~LC_KEYMOD_MASK) | ((a & LC_KEYMOD1_MASK) << 2))
|
||||
#define LC_KEYMOD_2TO1(a) ((a & ~LC_KEYMOD_MASK) | ((a & LC_KEYMOD2_MASK) >> 2))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LC_COMMANDS ID;
|
||||
const char* Description;
|
||||
unsigned char Flags;
|
||||
unsigned char Key1;
|
||||
unsigned char Key2;
|
||||
} LC_KEYBOARD_COMMAND;
|
||||
|
||||
extern LC_KEYBOARD_COMMAND KeyboardShortcuts[];
|
||||
extern const int KeyboardShortcutsCount;
|
||||
|
||||
const char* GetKeyName(char Key);
|
||||
char GetKeyFromName(const char* Name);
|
||||
|
||||
void InitKeyboardShortcuts();
|
||||
void ResetKeyboardShortcuts();
|
||||
bool SaveKeyboardShortcuts(const char* FileName);
|
||||
bool LoadKeyboardShortcuts(const char* FileName);
|
||||
|
||||
#endif // _KEYBOARD_H_
|
407
common/lc_application.cpp
Normal file
407
common/lc_application.cpp
Normal file
|
@ -0,0 +1,407 @@
|
|||
#include <stdio.h>
|
||||
#include "lc_application.h"
|
||||
#include "library.h"
|
||||
#include "system.h"
|
||||
#include "console.h"
|
||||
#include "config.h"
|
||||
#include "opengl.h"
|
||||
#include "project.h"
|
||||
#include "image.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Global functions.
|
||||
|
||||
lcApplication* g_App;
|
||||
|
||||
PiecesLibrary* lcGetPiecesLibrary()
|
||||
{
|
||||
LC_ASSERT(g_App, "g_App not initialized.");
|
||||
return g_App->GetPiecesLibrary();
|
||||
}
|
||||
|
||||
Project* lcGetActiveProject()
|
||||
{
|
||||
LC_ASSERT(g_App, "g_App not initialized.");
|
||||
return g_App->GetActiveProject();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// lcApplication class.
|
||||
|
||||
lcApplication::lcApplication()
|
||||
{
|
||||
m_ActiveProject = NULL;
|
||||
m_Library = NULL;
|
||||
}
|
||||
|
||||
lcApplication::~lcApplication()
|
||||
{
|
||||
}
|
||||
|
||||
void lcApplication::AddProject(Project* project)
|
||||
{
|
||||
m_Projects.Add(project);
|
||||
|
||||
if (m_ActiveProject == NULL)
|
||||
m_ActiveProject = project;
|
||||
}
|
||||
|
||||
bool lcApplication::LoadPiecesLibrary(const char* LibPath, const char* SysLibPath)
|
||||
{
|
||||
// Create an empty library.
|
||||
if (m_Library == NULL)
|
||||
m_Library = new PiecesLibrary();
|
||||
else
|
||||
m_Library->Unload();
|
||||
|
||||
// Check if the user specified a library path in the command line.
|
||||
if (LibPath != NULL)
|
||||
if (m_Library->Load(LibPath))
|
||||
return true;
|
||||
|
||||
// Check for the LEOCAD_LIB environment variable.
|
||||
char* EnvPath = getenv("LEOCAD_LIB");
|
||||
|
||||
if (EnvPath != NULL)
|
||||
if (m_Library->Load(EnvPath))
|
||||
return true;
|
||||
|
||||
// Try the executable install path last.
|
||||
if (SysLibPath != NULL)
|
||||
if (m_Library->Load(SysLibPath))
|
||||
return true;
|
||||
|
||||
#ifdef LC_WINDOWS
|
||||
SystemDoMessageBox("Cannot load pieces library.\n"
|
||||
"Make sure that you have the PIECES.IDX file in the same "
|
||||
"folder where you installed the program.", LC_MB_OK|LC_MB_ICONERROR);
|
||||
#else
|
||||
printf("Error: Cannot load pieces library.\n");
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void lcApplication::ParseIntegerArgument(int* CurArg, int argc, char* argv[], int* Value)
|
||||
{
|
||||
if (argc > (*CurArg + 1))
|
||||
{
|
||||
(*CurArg)++;
|
||||
int val;
|
||||
|
||||
if ((sscanf(argv[(*CurArg)], "%d", &val) == 1) && (val > 0))
|
||||
*Value = val;
|
||||
else
|
||||
console.PrintWarning("Invalid value specified for the %s argument.", argv[(*CurArg) - 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
console.PrintWarning("Not enough parameters for the %s argument.", argv[(*CurArg) - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
void lcApplication::ParseStringArgument(int* CurArg, int argc, char* argv[], char** Value)
|
||||
{
|
||||
if (argc > (*CurArg + 1))
|
||||
{
|
||||
(*CurArg)++;
|
||||
*Value = argv[(*CurArg)];
|
||||
}
|
||||
else
|
||||
{
|
||||
console.PrintWarning("No path specified after the %s argument.", argv[(*CurArg) - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
bool lcApplication::Initialize(int argc, char* argv[], const char* SysLibPath)
|
||||
{
|
||||
// System setup parameters.
|
||||
char* LibPath = NULL;
|
||||
char* GLPath = NULL;
|
||||
|
||||
// Image output options.
|
||||
bool SaveImage = false;
|
||||
bool ImageAnimation = false;
|
||||
bool ImageInstructions = false;
|
||||
bool ImageHighlight = false;
|
||||
int ImageWidth = Sys_ProfileLoadInt("Default", "Image Width", 640);
|
||||
int ImageHeight = Sys_ProfileLoadInt("Default", "Image Height", 480);
|
||||
int ImageStart = 0;
|
||||
int ImageEnd = 0;
|
||||
char* ImageName = NULL;
|
||||
|
||||
// File to open.
|
||||
char* ProjectName = NULL;
|
||||
|
||||
// Parse the command line arguments.
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
char* Param = argv[i];
|
||||
|
||||
if (Param[0] == '-')
|
||||
{
|
||||
if (strcmp(Param, "--libgl") == 0)
|
||||
{
|
||||
ParseStringArgument(&i, argc, argv, &GLPath);
|
||||
}
|
||||
else if ((strcmp(Param, "-l") == 0) || (strcmp(Param, "--libpath") == 0))
|
||||
{
|
||||
ParseStringArgument(&i, argc, argv, &LibPath);
|
||||
}
|
||||
else if ((strcmp(Param, "-i") == 0) || (strcmp(Param, "--image") == 0))
|
||||
{
|
||||
SaveImage = true;
|
||||
|
||||
if ((argc > (i+1)) && (argv[i+1][0] != '-'))
|
||||
{
|
||||
i++;
|
||||
ImageName = argv[i];
|
||||
}
|
||||
}
|
||||
else if ((strcmp(Param, "-w") == 0) || (strcmp(Param, "--width") == 0))
|
||||
{
|
||||
ParseIntegerArgument(&i, argc, argv, &ImageWidth);
|
||||
}
|
||||
else if ((strcmp(Param, "-h") == 0) || (strcmp(Param, "--height") == 0))
|
||||
{
|
||||
ParseIntegerArgument(&i, argc, argv, &ImageHeight);
|
||||
}
|
||||
else if ((strcmp(Param, "-f") == 0) || (strcmp(Param, "--from") == 0))
|
||||
{
|
||||
ParseIntegerArgument(&i, argc, argv, &ImageStart);
|
||||
}
|
||||
else if ((strcmp(Param, "-t") == 0) || (strcmp(Param, "--to") == 0))
|
||||
{
|
||||
ParseIntegerArgument(&i, argc, argv, &ImageEnd);
|
||||
}
|
||||
else if (strcmp(Param, "--animation") == 0)
|
||||
ImageAnimation = true;
|
||||
else if (strcmp(Param, "--instructions") == 0)
|
||||
ImageInstructions = true;
|
||||
else if (strcmp(Param, "--highlight") == 0)
|
||||
ImageHighlight = true;
|
||||
else if ((strcmp(Param, "-v") == 0) || (strcmp(Param, "--version") == 0))
|
||||
{
|
||||
printf("LeoCAD version " LC_VERSION_TEXT LC_VERSION_TAG " for "LC_VERSION_OSNAME"\n");
|
||||
printf("Copyright (c) 1996-2006, BT Software\n");
|
||||
printf("Compiled "__DATE__"\n");
|
||||
|
||||
#ifdef LC_HAVE_JPEGLIB
|
||||
printf("With JPEG support\n");
|
||||
#else
|
||||
printf("Without JPEG support\n");
|
||||
#endif
|
||||
|
||||
#ifdef LC_HAVE_PNGLIB
|
||||
printf("With PNG support\n");
|
||||
#else
|
||||
printf("Without PNG support\n");
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
else if ((strcmp(Param, "-?") == 0) || (strcmp(Param, "--help") == 0))
|
||||
{
|
||||
printf("Usage: leocad [options] [file]\n");
|
||||
printf(" [options] can be:\n");
|
||||
printf(" --libgl <path>: Searches for OpenGL libraries in path.\n");
|
||||
printf(" --libpath <path>: Loads the Pieces library from path.\n");
|
||||
printf(" -i, --image <outfile.ext>: Saves a picture in the format specified by ext.\n");
|
||||
printf(" -w, --width <width>: Sets the picture width.\n");
|
||||
printf(" -h, --height <height>: Sets the picture height.\n");
|
||||
printf(" -f, --from <time>: Sets the first frame or step to save pictures.\n");
|
||||
printf(" -t, --to <time>: Sets the last frame or step to save pictures.\n");
|
||||
printf(" --animation: Saves animations frames.\n");
|
||||
printf(" --instructions: Saves instructions steps.\n");
|
||||
printf(" --highlight: Highlight pieces in the steps they appear.\n");
|
||||
printf(" \n");
|
||||
}
|
||||
else
|
||||
console.PrintWarning("Unknown parameter: %s\n", Param);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProjectName = Param;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize other systems.
|
||||
if (!GL_Initialize(GLPath))
|
||||
return false;
|
||||
|
||||
if (!LoadPiecesLibrary(LibPath, SysLibPath))
|
||||
return false;
|
||||
|
||||
SystemInit();
|
||||
|
||||
// Create a new project.
|
||||
Project* project = new Project();
|
||||
AddProject(project);
|
||||
|
||||
// Load project.
|
||||
if (ProjectName && project->OpenProject(ProjectName))
|
||||
{
|
||||
if (!SaveImage)
|
||||
return true;
|
||||
|
||||
// Check if there's a file name and it has an extension.
|
||||
bool NeedExt = true;
|
||||
String FileName;
|
||||
|
||||
if (!ImageName)
|
||||
{
|
||||
FileName = ProjectName;
|
||||
|
||||
int i = FileName.ReverseFind('.');
|
||||
if (i != -1)
|
||||
FileName[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
FileName = ImageName;
|
||||
|
||||
int i = FileName.ReverseFind('.');
|
||||
String Ext;
|
||||
|
||||
if (i != -1)
|
||||
{
|
||||
Ext = FileName.Right(FileName.GetLength() - i);
|
||||
Ext.MakeLower();
|
||||
}
|
||||
|
||||
if ((Ext == "bmp") || (Ext == "gif"))
|
||||
NeedExt = false;
|
||||
#ifdef LC_HAVE_JPEGLIB
|
||||
else if ((Ext == "jpg") || (Ext == "jpeg"))
|
||||
NeedExt = false;
|
||||
#endif
|
||||
#ifdef LC_HAVE_PNGLIB
|
||||
else if (Ext == "png")
|
||||
NeedExt = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Setup default options.
|
||||
LC_IMAGE_OPTS ImageOptions;
|
||||
unsigned long image = Sys_ProfileLoadInt ("Default", "Image Options", 1|LC_IMAGE_TRANSPARENT);
|
||||
ImageOptions.quality = Sys_ProfileLoadInt ("Default", "JPEG Quality", 70);
|
||||
ImageOptions.interlaced = (image & LC_IMAGE_PROGRESSIVE) != 0;
|
||||
ImageOptions.transparent = (image & LC_IMAGE_TRANSPARENT) != 0;
|
||||
ImageOptions.truecolor = (image & LC_IMAGE_HIGHCOLOR) != 0;
|
||||
ImageOptions.format = image & ~(LC_IMAGE_MASK);
|
||||
ImageOptions.background[0] = (unsigned char)(project->GetBackgroundColor()[0]*255);
|
||||
ImageOptions.background[1] = (unsigned char)(project->GetBackgroundColor()[1]*255);
|
||||
ImageOptions.background[2] = (unsigned char)(project->GetBackgroundColor()[2]*255);
|
||||
|
||||
// Append file extension if needed.
|
||||
if (NeedExt)
|
||||
{
|
||||
switch (ImageOptions.format)
|
||||
{
|
||||
default:
|
||||
case LC_IMAGE_BMP:
|
||||
FileName += ".bmp";
|
||||
break;
|
||||
case LC_IMAGE_GIF:
|
||||
FileName += ".gif";
|
||||
break;
|
||||
case LC_IMAGE_JPG:
|
||||
FileName += ".jpg";
|
||||
break;
|
||||
case LC_IMAGE_PNG:
|
||||
FileName += ".png";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImageInstructions)
|
||||
project->SetAnimation(false);
|
||||
else if (ImageAnimation)
|
||||
project->SetAnimation(true);
|
||||
|
||||
if (ImageEnd < ImageStart)
|
||||
ImageEnd = ImageStart;
|
||||
else if (ImageStart > ImageEnd)
|
||||
ImageStart = ImageEnd;
|
||||
|
||||
if ((ImageStart == 0) && (ImageEnd == 0))
|
||||
{
|
||||
ImageStart = ImageEnd = project->GetCurrentTime();
|
||||
}
|
||||
else if ((ImageStart == 0) && (ImageEnd != 0))
|
||||
{
|
||||
ImageStart = ImageEnd;
|
||||
}
|
||||
else if ((ImageStart != 0) && (ImageEnd == 0))
|
||||
{
|
||||
ImageEnd = ImageStart;
|
||||
}
|
||||
|
||||
if (project->IsAnimation())
|
||||
{
|
||||
if (ImageStart > project->GetTotalFrames())
|
||||
ImageStart = project->GetTotalFrames();
|
||||
|
||||
if (ImageEnd > project->GetTotalFrames())
|
||||
ImageEnd = project->GetTotalFrames();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ImageStart > 255)
|
||||
ImageStart = 255;
|
||||
|
||||
if (ImageEnd > 255)
|
||||
ImageEnd = 255;
|
||||
}
|
||||
|
||||
Image* images = new Image[ImageEnd - ImageStart + 1];
|
||||
project->CreateImages(images, ImageWidth, ImageHeight, ImageStart, ImageEnd, ImageHighlight);
|
||||
|
||||
for (int i = 0; i <= ImageEnd - ImageStart; i++)
|
||||
{
|
||||
char idx[256];
|
||||
String Frame;
|
||||
|
||||
if (ImageStart != ImageEnd)
|
||||
{
|
||||
sprintf(idx, "%02d", i+1);
|
||||
int Ext = FileName.ReverseFind('.');
|
||||
|
||||
Frame = FileName.Left(Ext) + idx + FileName.Right(FileName.GetLength() - Ext);
|
||||
}
|
||||
else
|
||||
Frame = FileName;
|
||||
|
||||
images[i].FileSave(Frame, &ImageOptions);
|
||||
}
|
||||
|
||||
delete []images;
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SaveImage)
|
||||
return false;
|
||||
else
|
||||
project->OnNewDocument();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void lcApplication::Shutdown()
|
||||
{
|
||||
for (int i = 0; i < m_Projects.GetSize(); i++)
|
||||
{
|
||||
Project* project = m_Projects[i];
|
||||
|
||||
project->HandleNotify(LC_ACTIVATE, 0);
|
||||
delete project;
|
||||
}
|
||||
|
||||
delete m_Library;
|
||||
m_Library = NULL;
|
||||
|
||||
GL_Shutdown();
|
||||
}
|
51
common/lc_application.h
Normal file
51
common/lc_application.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
#ifndef _LC_APPLICATION_H_
|
||||
#define _LC_APPLICATION_H_
|
||||
|
||||
#include "array.h"
|
||||
|
||||
class Project;
|
||||
class PiecesLibrary;
|
||||
|
||||
class lcApplication
|
||||
{
|
||||
public:
|
||||
lcApplication();
|
||||
~lcApplication();
|
||||
|
||||
bool Initialize(int argc, char *argv[], const char* SysLibPath);
|
||||
void Shutdown();
|
||||
|
||||
// Pieces library.
|
||||
bool LoadPiecesLibrary(const char* LibPath, const char* SysLibPath);
|
||||
PiecesLibrary* GetPiecesLibrary() const
|
||||
{
|
||||
return m_Library;
|
||||
}
|
||||
|
||||
// Projects.
|
||||
void AddProject(Project* project);
|
||||
|
||||
Project* GetActiveProject() const
|
||||
{
|
||||
return m_ActiveProject;
|
||||
}
|
||||
|
||||
void SetActiveProject(Project* project)
|
||||
{
|
||||
m_ActiveProject = project;
|
||||
}
|
||||
|
||||
protected:
|
||||
void ParseIntegerArgument(int* CurArg, int argc, char* argv[], int* Value);
|
||||
void ParseStringArgument(int* CurArg, int argc, char* argv[], char** Value);
|
||||
|
||||
Project* m_ActiveProject;
|
||||
PtrArray<Project> m_Projects;
|
||||
PiecesLibrary* m_Library;
|
||||
};
|
||||
|
||||
extern lcApplication* g_App;
|
||||
PiecesLibrary* lcGetPiecesLibrary();
|
||||
Project* lcGetActiveProject();
|
||||
|
||||
#endif // _LC_APPLICATION_H_
|
2749
common/library.cpp
Executable file
2749
common/library.cpp
Executable file
File diff suppressed because it is too large
Load diff
168
common/library.h
Executable file
168
common/library.h
Executable file
|
@ -0,0 +1,168 @@
|
|||
#ifndef _LIBRARY_H_
|
||||
#define _LIBRARY_H_
|
||||
|
||||
#include "defines.h"
|
||||
#include "str.h"
|
||||
#include "array.h"
|
||||
|
||||
class File;
|
||||
class FileDisk;
|
||||
class Texture;
|
||||
class PieceInfo;
|
||||
|
||||
#define LC_CATEGORY_FILE_ID LC_FOURCC('C', 'A', 'T', 0)
|
||||
#define LC_CATEGORY_FILE_VERSION 0x0100
|
||||
|
||||
typedef struct
|
||||
{
|
||||
String Name;
|
||||
String Keywords;
|
||||
} PiecesLibraryCategory;
|
||||
|
||||
class PiecesLibrary
|
||||
{
|
||||
public:
|
||||
PiecesLibrary();
|
||||
~PiecesLibrary();
|
||||
|
||||
const char* GetLibraryPath() const
|
||||
{ return m_LibraryPath; }
|
||||
int GetPieceCount () const
|
||||
{ return m_nPieceCount; }
|
||||
int GetTextureCount () const
|
||||
{ return m_nTextureCount; }
|
||||
|
||||
// Categories.
|
||||
bool PieceInCategory(PieceInfo* Info, const String& CategoryKeywords) const;
|
||||
int GetFirstCategory(PieceInfo* Info) const;
|
||||
void GetCategoryEntries(int CategoryIndex, bool GroupPieces, PtrArray<PieceInfo>& SinglePieces, PtrArray<PieceInfo>& GroupedPieces) const;
|
||||
void GetPatternedPieces(PieceInfo* Parent, PtrArray<PieceInfo>& Pieces) const;
|
||||
void SetCategory(int Index, const String& Name, const String& Keywords);
|
||||
void AddCategory(const String& Name, const String& Keywords);
|
||||
void RemoveCategory(int Index);
|
||||
void ResetCategories();
|
||||
bool SaveCategories();
|
||||
bool DoSaveCategories(bool AskName);
|
||||
bool LoadCategories(const char* FileName);
|
||||
|
||||
const String& GetCategoryName(int Index) const
|
||||
{ return m_Categories[Index].Name; }
|
||||
|
||||
const String& GetCategoryKeywords(int Index) const
|
||||
{ return m_Categories[Index].Keywords; }
|
||||
|
||||
int GetNumCategories() const
|
||||
{ return m_Categories.GetSize(); }
|
||||
|
||||
int FindCategoryIndex(const String& CategoryName) const
|
||||
{
|
||||
for (int i = 0; i < m_Categories.GetSize(); i++)
|
||||
if (m_Categories[i].Name == CategoryName)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool Load(const char* libpath);
|
||||
void Unload();
|
||||
|
||||
// Search for pieces.
|
||||
PieceInfo* FindPieceInfo(const char* name) const;
|
||||
PieceInfo* GetPieceInfo(int index) const;
|
||||
int GetPieceIndex(PieceInfo *pInfo) const;
|
||||
Texture* FindTexture(const char* name) const;
|
||||
Texture* GetTexture(int index) const;
|
||||
|
||||
// File operations.
|
||||
bool DeletePieces(PtrArray<PieceInfo>& Pieces);
|
||||
bool LoadUpdate(const char* update);
|
||||
bool DeleteTextures(char** Names, int NumTextures);
|
||||
bool ImportTexture(const char* Name);
|
||||
bool ImportLDrawPiece(const char* Filename);
|
||||
|
||||
// Set when pieces are added/removed from the library.
|
||||
bool m_Modified;
|
||||
|
||||
protected:
|
||||
char m_LibraryPath[LC_MAXPATH]; // path to the library files
|
||||
|
||||
int m_nMovedCount; // number of moved pieces
|
||||
char* m_pMovedReference; // moved pieces list
|
||||
int m_nPieceCount; // number of pieces
|
||||
PieceInfo* m_pPieceIdx; // pieces array
|
||||
int m_nTextureCount; // number of textures
|
||||
Texture* m_pTextures; // textures array
|
||||
|
||||
// Categories.
|
||||
ObjArray<PiecesLibraryCategory> m_Categories;
|
||||
|
||||
bool m_CategoriesModified;
|
||||
char m_CategoriesFile[LC_MAXPATH];
|
||||
|
||||
bool ValidatePiecesFile(FileDisk& IdxFile, FileDisk& BinFile) const;
|
||||
bool ValidateTexturesFile(File& IdxFile, File& BinFile) const;
|
||||
|
||||
// File headers
|
||||
static const char PiecesBinHeader[32];
|
||||
static const char PiecesIdxHeader[32];
|
||||
static const int PiecesFileVersion;
|
||||
static const char TexturesBinHeader[32];
|
||||
static const char TexturesIdxHeader[32];
|
||||
static const int TexturesFileVersion;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// This should be cleaned and moved to the PiecesLibrary class
|
||||
typedef struct connection_s
|
||||
{
|
||||
unsigned char type;
|
||||
float pos[3];
|
||||
float up[3];
|
||||
connection_s* next;
|
||||
} connection_t;
|
||||
|
||||
typedef struct group_s
|
||||
{
|
||||
connection_t* connections[5];
|
||||
void* drawinfo;
|
||||
unsigned long infosize;
|
||||
group_s* next;
|
||||
} group_t;
|
||||
|
||||
typedef struct lineinfo_s
|
||||
{
|
||||
unsigned char type;
|
||||
unsigned char color;
|
||||
float points[12];
|
||||
lineinfo_s* next;
|
||||
} lineinfo_t;
|
||||
|
||||
typedef struct texture_s
|
||||
{
|
||||
float points[20];
|
||||
unsigned char color;
|
||||
char name[9];
|
||||
texture_s* next;
|
||||
} texture_t;
|
||||
|
||||
struct LC_LDRAW_PIECE
|
||||
{
|
||||
float* verts;
|
||||
unsigned int verts_count;
|
||||
bool long_info;
|
||||
connection_t* connections;
|
||||
group_t* groups;
|
||||
texture_t* textures;
|
||||
char name[LC_MAXPATH];
|
||||
char description[65];
|
||||
};
|
||||
|
||||
bool ReadLDrawPiece(const char* filename, LC_LDRAW_PIECE* piece);
|
||||
bool SaveLDrawPiece(LC_LDRAW_PIECE* piece);
|
||||
void FreeLDrawPiece(LC_LDRAW_PIECE* piece);
|
||||
|
||||
#endif // _LIBRARY_H_
|
573
common/light.cpp
Normal file
573
common/light.cpp
Normal file
|
@ -0,0 +1,573 @@
|
|||
// Light object.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "light.h"
|
||||
#include "defines.h"
|
||||
#include "globals.h"
|
||||
#include "vector.h"
|
||||
#include "matrix.h"
|
||||
|
||||
GLuint Light::m_nSphereList = 0;
|
||||
GLuint Light::m_nTargetList = 0;
|
||||
|
||||
static LC_OBJECT_KEY_INFO light_key_info[LC_LK_COUNT] =
|
||||
{
|
||||
{ "Light Position", 3, LC_LK_POSITION },
|
||||
{ "Light Target", 3, LC_LK_TARGET },
|
||||
{ "Ambient Color", 3, LC_LK_AMBIENT },
|
||||
{ "Diffuse Color", 3, LC_LK_DIFFUSE },
|
||||
{ "Specular Color", 3, LC_LK_SPECULAR },
|
||||
{ "Constant Attenuation", 1, LC_LK_CONSTANT },
|
||||
{ "Linear Attenuation", 1, LC_LK_LINEAR },
|
||||
{ "Quadratic Attenuation", 1, LC_LK_QUADRATIC },
|
||||
{ "Spot Cutoff", 1, LC_LK_CUTOFF },
|
||||
{ "Spot Exponent", 1, LC_LK_EXPONENT }
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// CameraTarget class
|
||||
|
||||
LightTarget::LightTarget (Light *pParent)
|
||||
: Object (LC_OBJECT_LIGHT_TARGET)
|
||||
{
|
||||
m_pParent = pParent;
|
||||
/*
|
||||
strcpy (m_strName, pParent->GetName ());
|
||||
m_strName[LC_OBJECT_NAME_LEN-8] = '\0';
|
||||
strcat (m_strName, ".Target");
|
||||
*/
|
||||
}
|
||||
|
||||
LightTarget::~LightTarget ()
|
||||
{
|
||||
}
|
||||
|
||||
void LightTarget::MinIntersectDist (LC_CLICKLINE* pLine)
|
||||
{
|
||||
float dist = (float)BoundingBoxIntersectDist (pLine);
|
||||
|
||||
if (dist < pLine->mindist)
|
||||
{
|
||||
pLine->mindist = dist;
|
||||
pLine->pClosest = this;
|
||||
}
|
||||
}
|
||||
|
||||
void LightTarget::Select (bool bSelecting, bool bFocus, bool bMultiple)
|
||||
{
|
||||
m_pParent->SelectTarget (bSelecting, bFocus, bMultiple);
|
||||
}
|
||||
|
||||
const char* LightTarget::GetName() const
|
||||
{
|
||||
return m_pParent->GetName();
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Light class
|
||||
|
||||
// New positional light
|
||||
Light::Light (float px, float py, float pz)
|
||||
: Object (LC_OBJECT_LIGHT)
|
||||
{
|
||||
Initialize ();
|
||||
|
||||
float pos[] = { px, py, pz }, target[] = { 0, 0, 0 };
|
||||
|
||||
ChangeKey (1, false, true, pos, LC_LK_POSITION);
|
||||
ChangeKey (1, false, true, target, LC_LK_TARGET);
|
||||
ChangeKey (1, true, true, pos, LC_LK_POSITION);
|
||||
ChangeKey (1, true, true, target, LC_LK_TARGET);
|
||||
|
||||
m_fPos[3] = 0.0f;
|
||||
|
||||
UpdatePosition (1, false);
|
||||
}
|
||||
|
||||
// New directional light
|
||||
Light::Light (float px, float py, float pz, float tx, float ty, float tz)
|
||||
: Object (LC_OBJECT_LIGHT)
|
||||
{
|
||||
Initialize ();
|
||||
|
||||
float pos[] = { px, py, pz }, target[] = { tx, ty, tz };
|
||||
|
||||
ChangeKey (1, false, true, pos, LC_LK_POSITION);
|
||||
ChangeKey (1, false, true, target, LC_LK_TARGET);
|
||||
ChangeKey (1, true, true, pos, LC_LK_POSITION);
|
||||
ChangeKey (1, true, true, target, LC_LK_TARGET);
|
||||
|
||||
m_pTarget = new LightTarget (this);
|
||||
m_fPos[3] = 1.0f;
|
||||
|
||||
UpdatePosition (1, false);
|
||||
}
|
||||
|
||||
void Light::Initialize ()
|
||||
{
|
||||
m_bEnabled = true;
|
||||
m_pNext = NULL;
|
||||
m_nState = 0;
|
||||
m_pTarget = NULL;
|
||||
m_nList = 0;
|
||||
memset (m_strName, 0, sizeof (m_strName));
|
||||
|
||||
m_fAmbient[3] = 1.0f;
|
||||
m_fDiffuse[3] = 1.0f;
|
||||
m_fSpecular[3] = 1.0f;
|
||||
|
||||
float *values[] = { m_fPos, m_fTarget, m_fAmbient, m_fDiffuse, m_fSpecular,
|
||||
&m_fConstant, &m_fLinear, &m_fQuadratic, &m_fCutoff, &m_fExponent };
|
||||
RegisterKeys (values, light_key_info, LC_LK_COUNT);
|
||||
|
||||
// set the default values
|
||||
float ambient[] = { 0, 0, 0 }, diffuse[] = { 0.8f, 0.8f, 0.8f }, specular[] = { 1, 1, 1 };
|
||||
float constant = 1, linear = 0, quadratic = 0, cutoff = 30, exponent = 0;
|
||||
|
||||
ChangeKey (1, false, true, ambient, LC_LK_AMBIENT);
|
||||
ChangeKey (1, false, true, diffuse, LC_LK_DIFFUSE);
|
||||
ChangeKey (1, false, true, specular, LC_LK_SPECULAR);
|
||||
ChangeKey (1, false, true, &constant, LC_LK_CONSTANT);
|
||||
ChangeKey (1, false, true, &linear, LC_LK_LINEAR);
|
||||
ChangeKey (1, false, true, &quadratic, LC_LK_QUADRATIC);
|
||||
ChangeKey (1, false, true, &cutoff, LC_LK_CUTOFF);
|
||||
ChangeKey (1, false, true, &exponent, LC_LK_EXPONENT);
|
||||
ChangeKey (1, true, true, ambient, LC_LK_AMBIENT);
|
||||
ChangeKey (1, true, true, diffuse, LC_LK_DIFFUSE);
|
||||
ChangeKey (1, true, true, specular, LC_LK_SPECULAR);
|
||||
ChangeKey (1, true, true, &constant, LC_LK_CONSTANT);
|
||||
ChangeKey (1, true, true, &linear, LC_LK_LINEAR);
|
||||
ChangeKey (1, true, true, &quadratic, LC_LK_QUADRATIC);
|
||||
ChangeKey (1, true, true, &cutoff, LC_LK_CUTOFF);
|
||||
ChangeKey (1, true, true, &exponent, LC_LK_EXPONENT);
|
||||
}
|
||||
|
||||
Light::~Light ()
|
||||
{
|
||||
if (m_nList != 0)
|
||||
glDeleteLists (m_nList, 1);
|
||||
|
||||
delete m_pTarget;
|
||||
}
|
||||
|
||||
void Light::CreateName(const Light* pLight)
|
||||
{
|
||||
int i, max = 0;
|
||||
|
||||
for (; pLight; pLight = pLight->m_pNext)
|
||||
{
|
||||
if (strncmp (pLight->m_strName, "Light ", 6) == 0)
|
||||
{
|
||||
if (sscanf(pLight->m_strName + 6, " #%d", &i) == 1)
|
||||
{
|
||||
if (i > max)
|
||||
max = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sprintf (m_strName, "Light #%.2d", max+1);
|
||||
}
|
||||
|
||||
void Light::Select (bool bSelecting, bool bFocus, bool bMultiple)
|
||||
{
|
||||
if (bSelecting == true)
|
||||
{
|
||||
if (bFocus == true)
|
||||
{
|
||||
m_nState |= (LC_LIGHT_FOCUSED|LC_LIGHT_SELECTED);
|
||||
|
||||
if (m_pTarget != NULL)
|
||||
m_pTarget->Select (false, true, bMultiple);
|
||||
}
|
||||
else
|
||||
m_nState |= LC_LIGHT_SELECTED;
|
||||
|
||||
if (bMultiple == false)
|
||||
if (m_pTarget != NULL)
|
||||
m_pTarget->Select (false, false, bMultiple);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bFocus == true)
|
||||
m_nState &= ~(LC_LIGHT_FOCUSED);
|
||||
else
|
||||
m_nState &= ~(LC_LIGHT_SELECTED|LC_LIGHT_FOCUSED);
|
||||
}
|
||||
}
|
||||
|
||||
void Light::SelectTarget (bool bSelecting, bool bFocus, bool bMultiple)
|
||||
{
|
||||
// FIXME: the target should handle this
|
||||
|
||||
if (bSelecting == true)
|
||||
{
|
||||
if (bFocus == true)
|
||||
{
|
||||
m_nState |= (LC_LIGHT_TARGET_FOCUSED|LC_LIGHT_TARGET_SELECTED);
|
||||
|
||||
Select (false, true, bMultiple);
|
||||
}
|
||||
else
|
||||
m_nState |= LC_LIGHT_TARGET_SELECTED;
|
||||
|
||||
if (bMultiple == false)
|
||||
Select (false, false, bMultiple);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bFocus == true)
|
||||
m_nState &= ~(LC_LIGHT_TARGET_FOCUSED);
|
||||
else
|
||||
m_nState &= ~(LC_LIGHT_TARGET_SELECTED|LC_LIGHT_TARGET_FOCUSED);
|
||||
}
|
||||
}
|
||||
|
||||
void Light::MinIntersectDist (LC_CLICKLINE* pLine)
|
||||
{
|
||||
float dist;
|
||||
|
||||
if (m_nState & LC_LIGHT_HIDDEN)
|
||||
return;
|
||||
|
||||
dist = (float)BoundingBoxIntersectDist (pLine);
|
||||
if (dist < pLine->mindist)
|
||||
{
|
||||
pLine->mindist = dist;
|
||||
pLine->pClosest = this;
|
||||
}
|
||||
|
||||
if (m_pTarget != NULL)
|
||||
m_pTarget->MinIntersectDist (pLine);
|
||||
}
|
||||
|
||||
void Light::Move (unsigned short nTime, bool bAnimation, bool bAddKey, float dx, float dy, float dz)
|
||||
{
|
||||
if (IsEyeSelected())
|
||||
{
|
||||
m_fPos[0] += dx;
|
||||
m_fPos[1] += dy;
|
||||
m_fPos[2] += dz;
|
||||
|
||||
ChangeKey (nTime, bAnimation, bAddKey, m_fPos, LC_LK_POSITION);
|
||||
}
|
||||
|
||||
if (IsTargetSelected())
|
||||
{
|
||||
m_fTarget[0] += dx;
|
||||
m_fTarget[1] += dy;
|
||||
m_fTarget[2] += dz;
|
||||
|
||||
ChangeKey (nTime, bAnimation, bAddKey, m_fTarget, LC_LK_TARGET);
|
||||
}
|
||||
}
|
||||
|
||||
void Light::UpdatePosition (unsigned short nTime, bool bAnimation)
|
||||
{
|
||||
CalculateKeys (nTime, bAnimation);
|
||||
BoundingBoxCalculate (m_fPos);
|
||||
|
||||
if (m_pTarget != NULL)
|
||||
{
|
||||
m_pTarget->BoundingBoxCalculate (m_fTarget);
|
||||
|
||||
if (m_nList == 0)
|
||||
m_nList = glGenLists(1);
|
||||
|
||||
glNewList (m_nList, GL_COMPILE);
|
||||
|
||||
glPushMatrix ();
|
||||
glTranslatef (m_fPos[0], m_fPos[1], m_fPos[2]);
|
||||
|
||||
Vector frontvec (m_fTarget[0]-m_fPos[0], m_fTarget[1]-m_fPos[1], m_fTarget[2]-m_fPos[2]);
|
||||
float len = frontvec.Length (), up[3] = { 1, 1, 1 };
|
||||
|
||||
if (fabs (frontvec[0]) < fabs (frontvec[1]))
|
||||
{
|
||||
if (fabs (frontvec[0]) < fabs (frontvec[2]))
|
||||
up[0] = -(up[1]*frontvec[1] + up[2]*frontvec[2]);
|
||||
else
|
||||
up[2] = -(up[0]*frontvec[0] + up[1]*frontvec[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fabs (frontvec[1]) < fabs (frontvec[2]))
|
||||
up[1] = -(up[0]*frontvec[0] + up[2]*frontvec[2]);
|
||||
else
|
||||
up[2] = -(up[0]*frontvec[0] + up[1]*frontvec[1]);
|
||||
}
|
||||
|
||||
Matrix mat;
|
||||
mat.CreateLookat (m_fPos, m_fTarget, up);
|
||||
mat.Invert ();
|
||||
mat.SetTranslation (0, 0, 0);
|
||||
|
||||
glMultMatrixf (mat.m);
|
||||
|
||||
glEnableClientState (GL_VERTEX_ARRAY);
|
||||
float verts[16*3];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
verts[i*6] = verts[i*6+3] = (float)cos ((float)i/4 * PI) * 0.3f;
|
||||
verts[i*6+1] = verts[i*6+4] = (float)sin ((float)i/4 * PI) * 0.3f;
|
||||
verts[i*6+2] = 0.3f;
|
||||
verts[i*6+5] = -0.3f;
|
||||
}
|
||||
glVertexPointer (3, GL_FLOAT, 0, verts);
|
||||
glDrawArrays (GL_LINES, 0, 16);
|
||||
glVertexPointer (3, GL_FLOAT, 6*sizeof(float), verts);
|
||||
glDrawArrays (GL_LINE_LOOP, 0, 8);
|
||||
glVertexPointer (3, GL_FLOAT, 6*sizeof(float), &verts[3]);
|
||||
glDrawArrays (GL_LINE_LOOP, 0, 8);
|
||||
|
||||
glBegin (GL_LINE_LOOP);
|
||||
glVertex3f (-0.5f, -0.5f, -0.3f);
|
||||
glVertex3f ( 0.5f, -0.5f, -0.3f);
|
||||
glVertex3f ( 0.5f, 0.5f, -0.3f);
|
||||
glVertex3f (-0.5f, 0.5f, -0.3f);
|
||||
glEnd ();
|
||||
|
||||
glTranslatef(0, 0, -len);
|
||||
glEndList();
|
||||
|
||||
if (m_nTargetList == 0)
|
||||
{
|
||||
m_nTargetList = glGenLists (1);
|
||||
glNewList (m_nTargetList, GL_COMPILE);
|
||||
|
||||
glEnableClientState (GL_VERTEX_ARRAY);
|
||||
float box[24][3] = {
|
||||
{ 0.2f, 0.2f, 0.2f }, { -0.2f, 0.2f, 0.2f },
|
||||
{ -0.2f, 0.2f, 0.2f }, { -0.2f, -0.2f, 0.2f },
|
||||
{ -0.2f, -0.2f, 0.2f }, { 0.2f, -0.2f, 0.2f },
|
||||
{ 0.2f, -0.2f, 0.2f }, { 0.2f, 0.2f, 0.2f },
|
||||
{ 0.2f, 0.2f, -0.2f }, { -0.2f, 0.2f, -0.2f },
|
||||
{ -0.2f, 0.2f, -0.2f }, { -0.2f, -0.2f, -0.2f },
|
||||
{ -0.2f, -0.2f, -0.2f }, { 0.2f, -0.2f, -0.2f },
|
||||
{ 0.2f, -0.2f, -0.2f }, { 0.2f, 0.2f, -0.2f },
|
||||
{ 0.2f, 0.2f, 0.2f }, { 0.2f, 0.2f, -0.2f },
|
||||
{ -0.2f, 0.2f, 0.2f }, { -0.2f, 0.2f, -0.2f },
|
||||
{ -0.2f, -0.2f, 0.2f }, { -0.2f, -0.2f, -0.2f },
|
||||
{ 0.2f, -0.2f, 0.2f }, { 0.2f, -0.2f, -0.2f } };
|
||||
glVertexPointer (3, GL_FLOAT, 0, box);
|
||||
glDrawArrays (GL_LINES, 0, 24);
|
||||
glPopMatrix ();
|
||||
glEndList ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_nSphereList == 0)
|
||||
m_nSphereList = glGenLists (1);
|
||||
glNewList (m_nSphereList, GL_COMPILE);
|
||||
|
||||
const float radius = 0.2f;
|
||||
const int slices = 6, stacks = 6;
|
||||
float rho, drho, theta, dtheta;
|
||||
float x, y, z;
|
||||
int i, j, imin, imax;
|
||||
drho = 3.1415926536f/(float)stacks;
|
||||
dtheta = 2.0f*3.1415926536f/(float)slices;
|
||||
|
||||
// draw +Z end as a triangle fan
|
||||
glBegin (GL_TRIANGLE_FAN);
|
||||
glVertex3f (0.0, 0.0, radius);
|
||||
for (j = 0; j <= slices; j++)
|
||||
{
|
||||
theta = (j == slices) ? 0.0f : j * dtheta;
|
||||
x = (float)(-sin(theta) * sin(drho));
|
||||
y = (float)(cos(theta) * sin(drho));
|
||||
z = (float)(cos(drho));
|
||||
glVertex3f (x*radius, y*radius, z*radius);
|
||||
}
|
||||
glEnd ();
|
||||
|
||||
imin = 1;
|
||||
imax = stacks-1;
|
||||
|
||||
for (i = imin; i < imax; i++)
|
||||
{
|
||||
rho = i * drho;
|
||||
glBegin (GL_QUAD_STRIP);
|
||||
for (j = 0; j <= slices; j++)
|
||||
{
|
||||
theta = (j == slices) ? 0.0f : j * dtheta;
|
||||
x = (float)(-sin(theta) * sin(rho));
|
||||
y = (float)(cos(theta) * sin(rho));
|
||||
z = (float)(cos(rho));
|
||||
glVertex3f (x*radius, y*radius, z*radius);
|
||||
x = (float)(-sin(theta) * sin(rho+drho));
|
||||
y = (float)(cos(theta) * sin(rho+drho));
|
||||
z = (float)(cos(rho+drho));
|
||||
glVertex3f (x*radius, y*radius, z*radius);
|
||||
}
|
||||
glEnd ();
|
||||
}
|
||||
|
||||
// draw -Z end as a triangle fan
|
||||
glBegin (GL_TRIANGLE_FAN);
|
||||
glVertex3f(0.0, 0.0, -radius);
|
||||
rho = 3.1415926536f - drho;
|
||||
for (j = slices; j >= 0; j--)
|
||||
{
|
||||
theta = (j==slices) ? 0.0f : j * dtheta;
|
||||
x = (float)(-sin(theta) * sin(rho));
|
||||
y = (float)(cos(theta) * sin(rho));
|
||||
z = (float)(cos(rho));
|
||||
glVertex3f (x*radius, y*radius, z*radius);
|
||||
}
|
||||
glEnd ();
|
||||
|
||||
glEndList ();
|
||||
}
|
||||
}
|
||||
|
||||
void Light::Render (float fLineWidth)
|
||||
{
|
||||
if (m_pTarget != NULL)
|
||||
{
|
||||
if (IsEyeSelected())
|
||||
{
|
||||
glLineWidth(fLineWidth*2);
|
||||
glColor3ubv(FlatColorArray[(m_nState & LC_LIGHT_FOCUSED) != 0 ? LC_COL_FOCUSED : LC_COL_SELECTED]);
|
||||
glCallList(m_nList);
|
||||
glLineWidth(fLineWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
glColor3f(0.5f, 0.8f, 0.5f);
|
||||
glCallList(m_nList);
|
||||
}
|
||||
|
||||
if (IsTargetSelected())
|
||||
{
|
||||
glLineWidth(fLineWidth*2);
|
||||
glColor3ubv(FlatColorArray[(m_nState & LC_LIGHT_TARGET_FOCUSED) != 0 ? LC_COL_FOCUSED : LC_COL_SELECTED]);
|
||||
glCallList(m_nTargetList);
|
||||
glLineWidth(fLineWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
glColor3f(0.5f, 0.8f, 0.5f);
|
||||
glCallList(m_nTargetList);
|
||||
}
|
||||
|
||||
glColor3f(0.5f, 0.8f, 0.5f);
|
||||
glBegin(GL_LINES);
|
||||
glVertex3fv(m_fPos);
|
||||
glVertex3fv(m_fTarget);
|
||||
glEnd();
|
||||
|
||||
if (IsSelected())
|
||||
{
|
||||
Matrix projection, modelview;
|
||||
Vector frontvec(m_fTarget[0]-m_fPos[0], m_fTarget[1]-m_fPos[1], m_fTarget[2]-m_fPos[2]);
|
||||
float len = frontvec.Length (), up[3] = { 1, 1, 1 };
|
||||
|
||||
if (fabs (frontvec[0]) < fabs (frontvec[1]))
|
||||
{
|
||||
if (fabs (frontvec[0]) < fabs (frontvec[2]))
|
||||
up[0] = -(up[1]*frontvec[1] + up[2]*frontvec[2]);
|
||||
else
|
||||
up[2] = -(up[0]*frontvec[0] + up[1]*frontvec[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fabs (frontvec[1]) < fabs (frontvec[2]))
|
||||
up[1] = -(up[0]*frontvec[0] + up[2]*frontvec[2]);
|
||||
else
|
||||
up[2] = -(up[0]*frontvec[0] + up[1]*frontvec[1]);
|
||||
}
|
||||
|
||||
glPushMatrix ();
|
||||
|
||||
modelview.CreateLookat (m_fPos, m_fTarget, up);
|
||||
modelview.Invert ();
|
||||
glMultMatrixf (modelview.m);
|
||||
|
||||
projection.CreatePerspective (2*m_fCutoff, 1.0f, 0.01f, len);
|
||||
projection.Invert ();
|
||||
glMultMatrixf (projection.m);
|
||||
|
||||
// draw the viewing frustum
|
||||
glBegin (GL_LINE_LOOP);
|
||||
glVertex3f ( 0.5f, 1.0f, 1.0f);
|
||||
glVertex3f ( 1.0f, 0.5f, 1.0f);
|
||||
glVertex3f ( 1.0f, -0.5f, 1.0f);
|
||||
glVertex3f ( 0.5f, -1.0f, 1.0f);
|
||||
glVertex3f (-0.5f, -1.0f, 1.0f);
|
||||
glVertex3f (-1.0f, -0.5f, 1.0f);
|
||||
glVertex3f (-1.0f, 0.5f, 1.0f);
|
||||
glVertex3f (-0.5f, 1.0f, 1.0f);
|
||||
glEnd ();
|
||||
|
||||
glBegin (GL_LINES);
|
||||
glVertex3f (1, 1, -1);
|
||||
glVertex3f (0.75f, 0.75f, 1);
|
||||
glVertex3f (-1, 1, -1);
|
||||
glVertex3f (-0.75f, 0.75f, 1);
|
||||
glVertex3f (-1, -1, -1);
|
||||
glVertex3f (-0.75f, -0.75f, 1);
|
||||
glVertex3f (1, -1, -1);
|
||||
glVertex3f (0.75f, -0.75f, 1);
|
||||
glEnd ();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
glPushMatrix ();
|
||||
glTranslatef (m_fPos[0], m_fPos[1], m_fPos[2]);
|
||||
|
||||
if (IsEyeSelected ())
|
||||
{
|
||||
glLineWidth (fLineWidth*2);
|
||||
glColor3ubv (FlatColorArray[(m_nState & LC_LIGHT_FOCUSED) != 0 ? LC_COL_FOCUSED : LC_COL_SELECTED]);
|
||||
glCallList (m_nSphereList);
|
||||
glLineWidth (fLineWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
glColor3f (0.5f, 0.8f, 0.5f);
|
||||
glCallList (m_nSphereList);
|
||||
}
|
||||
|
||||
glPopMatrix ();
|
||||
}
|
||||
}
|
||||
|
||||
void Light::Setup (int index)
|
||||
{
|
||||
GLenum light = (GLenum)(GL_LIGHT0+index);
|
||||
|
||||
if (!m_bEnabled)
|
||||
{
|
||||
glDisable (light);
|
||||
return;
|
||||
}
|
||||
|
||||
glEnable (light);
|
||||
glLightfv (light, GL_POSITION, m_fPos);
|
||||
|
||||
glLightfv (light, GL_AMBIENT, m_fAmbient);
|
||||
glLightfv (light, GL_DIFFUSE, m_fDiffuse);
|
||||
glLightfv (light, GL_SPECULAR, m_fSpecular);
|
||||
|
||||
glLightf (light, GL_CONSTANT_ATTENUATION, m_fConstant);
|
||||
glLightf (light, GL_LINEAR_ATTENUATION, m_fLinear);
|
||||
glLightf (light, GL_QUADRATIC_ATTENUATION, m_fQuadratic);
|
||||
|
||||
if (m_pTarget != NULL)
|
||||
{
|
||||
Vector dir (m_fTarget[0]-m_fPos[0], m_fTarget[1]-m_fPos[1], m_fTarget[2]-m_fPos[2]);
|
||||
dir.Normalize ();
|
||||
|
||||
glLightf (light, GL_SPOT_CUTOFF, m_fCutoff);
|
||||
glLightf (light, GL_SPOT_EXPONENT, m_fExponent);
|
||||
glLightfv (light, GL_SPOT_DIRECTION, dir);
|
||||
}
|
||||
}
|
138
common/light.h
Normal file
138
common/light.h
Normal file
|
@ -0,0 +1,138 @@
|
|||
#ifndef _LIGHT_H_
|
||||
#define _LIGHT_H_
|
||||
|
||||
#include "opengl.h"
|
||||
#include "object.h"
|
||||
|
||||
#define LC_LIGHT_HIDDEN 0x01
|
||||
#define LC_LIGHT_SELECTED 0x02
|
||||
#define LC_LIGHT_FOCUSED 0x04
|
||||
#define LC_LIGHT_TARGET_SELECTED 0x08
|
||||
#define LC_LIGHT_TARGET_FOCUSED 0x10
|
||||
#define LC_LIGHT_ENABLED 0x20
|
||||
|
||||
class Light;
|
||||
class LightTarget;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_LK_POSITION, LC_LK_TARGET, // position
|
||||
LC_LK_AMBIENT, LC_LK_DIFFUSE, LC_LK_SPECULAR, // color
|
||||
LC_LK_CONSTANT, LC_LK_LINEAR, LC_LK_QUADRATIC, // attenuation
|
||||
LC_LK_CUTOFF, LC_LK_EXPONENT, // spot
|
||||
LC_LK_COUNT
|
||||
} LC_LK_TYPES;
|
||||
|
||||
class LightTarget : public Object
|
||||
{
|
||||
public:
|
||||
LightTarget (Light *pParent);
|
||||
~LightTarget ();
|
||||
|
||||
public:
|
||||
void MinIntersectDist (LC_CLICKLINE* pLine);
|
||||
bool IntersectsVolume(const Vector4* Planes, int NumPlanes)
|
||||
{ return false; }
|
||||
void Select (bool bSelecting, bool bFocus, bool bMultiple);
|
||||
void Move (unsigned short nTime, bool bAnimation, bool bAddKey, float x, float y, float z)
|
||||
{
|
||||
// FIXME: move the position handling to the light target
|
||||
}
|
||||
|
||||
const char* GetName() const;
|
||||
|
||||
Light* GetParent () const
|
||||
{ return m_pParent; }
|
||||
|
||||
protected:
|
||||
Light* m_pParent;
|
||||
|
||||
friend class Light; // FIXME: needed for BoundingBoxCalculate ()
|
||||
// remove and use UpdatePosition instead
|
||||
};
|
||||
|
||||
class Light : public Object
|
||||
{
|
||||
public:
|
||||
Light (float px, float py, float pz);
|
||||
Light (float px, float py, float pz, float tx, float ty, float tz);
|
||||
virtual ~Light ();
|
||||
|
||||
void Select (bool bSelecting, bool bFocus, bool bMultiple);
|
||||
void SelectTarget (bool bSelecting, bool bFocus, bool bMultiple);
|
||||
|
||||
public:
|
||||
Light* m_pNext;
|
||||
|
||||
bool IsVisible()
|
||||
{ return (m_nState & LC_LIGHT_HIDDEN) == 0; }
|
||||
bool IsSelected()
|
||||
{ return (m_nState & (LC_LIGHT_SELECTED|LC_LIGHT_TARGET_SELECTED)) != 0; }
|
||||
bool IsEyeSelected()
|
||||
{ return (m_nState & LC_LIGHT_SELECTED) != 0; }
|
||||
bool IsTargetSelected()
|
||||
{ return (m_nState & LC_LIGHT_TARGET_SELECTED) != 0; }
|
||||
bool IsEyeFocused()
|
||||
{ return (m_nState & LC_LIGHT_FOCUSED) != 0; }
|
||||
bool IsTargetFocused()
|
||||
{ return (m_nState & LC_LIGHT_TARGET_FOCUSED) != 0; }
|
||||
|
||||
void Select()
|
||||
{ m_nState |= (LC_LIGHT_SELECTED|LC_LIGHT_TARGET_SELECTED); }
|
||||
void UnSelect()
|
||||
{ m_nState &= ~(LC_LIGHT_SELECTED|LC_LIGHT_FOCUSED|LC_LIGHT_TARGET_SELECTED|LC_LIGHT_TARGET_FOCUSED); }
|
||||
void UnFocus()
|
||||
{ m_nState &= ~(LC_LIGHT_FOCUSED|LC_LIGHT_TARGET_FOCUSED); }
|
||||
void FocusEye()
|
||||
{ m_nState |= (LC_LIGHT_FOCUSED|LC_LIGHT_SELECTED); }
|
||||
void FocusTarget()
|
||||
{ m_nState |= (LC_LIGHT_TARGET_FOCUSED|LC_LIGHT_TARGET_SELECTED); }
|
||||
const char* GetName()
|
||||
{ return m_strName; }
|
||||
void GetTargetPos (float *pos) const
|
||||
{ memcpy (pos, m_fTarget, sizeof (float[3])); }
|
||||
LightTarget* GetTarget () const
|
||||
{ return m_pTarget; }
|
||||
|
||||
const char* GetName() const
|
||||
{ return m_strName; };
|
||||
|
||||
void Render (float fLineWidth);
|
||||
void MinIntersectDist (LC_CLICKLINE* Line);
|
||||
bool IntersectsVolume(const Vector4* Planes, int NumPlanes)
|
||||
{ return false; }
|
||||
void UpdatePosition (unsigned short nTime, bool bAnimation);
|
||||
void Move (unsigned short nTime, bool bAnimation, bool bAddKey, float dx, float dy, float dz);
|
||||
void Setup (int index);
|
||||
void CreateName(const Light* pLight);
|
||||
|
||||
protected:
|
||||
void Initialize ();
|
||||
|
||||
// Camera target
|
||||
LightTarget* m_pTarget;
|
||||
|
||||
// Attributes
|
||||
float m_fCone;
|
||||
unsigned char m_nState;
|
||||
char m_strName[81];
|
||||
bool m_bEnabled;
|
||||
|
||||
GLuint m_nList;
|
||||
static GLuint m_nSphereList;
|
||||
static GLuint m_nTargetList;
|
||||
|
||||
// Temporary parameters
|
||||
float m_fPos[4];
|
||||
float m_fTarget[3];
|
||||
float m_fAmbient[4];
|
||||
float m_fDiffuse[4];
|
||||
float m_fSpecular[4];
|
||||
float m_fConstant;
|
||||
float m_fLinear;
|
||||
float m_fQuadratic;
|
||||
float m_fCutoff;
|
||||
float m_fExponent;
|
||||
};
|
||||
|
||||
#endif // _LIGHT_H_
|
101
common/mainwnd.cpp
Normal file
101
common/mainwnd.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
//
|
||||
// Main LeoCAD window
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include "mainwnd.h"
|
||||
#include "system.h"
|
||||
|
||||
MainWnd::MainWnd ()
|
||||
: BaseWnd (NULL, LC_MAINWND_NUM_COMMANDS)
|
||||
{
|
||||
char entry[8];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LC_MRU_MAX; i++)
|
||||
{
|
||||
sprintf (entry, "File%d", i+1);
|
||||
m_strMRU[i] = Sys_ProfileLoadString ("RecentFiles", entry, "");
|
||||
}
|
||||
}
|
||||
|
||||
MainWnd::~MainWnd ()
|
||||
{
|
||||
char entry[8];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LC_MRU_MAX; i++)
|
||||
{
|
||||
sprintf (entry, "File%d", i+1);
|
||||
Sys_ProfileSaveString ("RecentFiles", entry, m_strMRU[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// recently used files
|
||||
|
||||
void MainWnd::UpdateMRU ()
|
||||
{
|
||||
#ifdef LC_WINDOWS
|
||||
// FIXME !!
|
||||
void SystemUpdateRecentMenu(char names[4][LC_MAXPATH]);
|
||||
char names[4][LC_MAXPATH];
|
||||
|
||||
for (int i = 0; i < LC_MRU_MAX; i++)
|
||||
strcpy (names[i], m_strMRU[i]);
|
||||
|
||||
SystemUpdateRecentMenu(names);
|
||||
#else
|
||||
for (int i = 0; i < LC_MRU_MAX; i++)
|
||||
{
|
||||
if (m_strMRU[i].IsEmpty ())
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
SetMenuItemText (LC_MAINWND_RECENT1, "Recent Files");
|
||||
EnableMenuItem (LC_MAINWND_RECENT1, false);
|
||||
}
|
||||
else
|
||||
ShowMenuItem (LC_MAINWND_RECENT1+i, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
char text[LC_MAXPATH+8];
|
||||
sprintf (text, "&%d- %s", i+1, (char*)m_strMRU[i]);
|
||||
|
||||
ShowMenuItem (LC_MAINWND_RECENT1+i, true);
|
||||
EnableMenuItem (LC_MAINWND_RECENT1+i, true);
|
||||
SetMenuItemText (LC_MAINWND_RECENT1+i, text);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWnd::AddToMRU(const char* Filename)
|
||||
{
|
||||
// Make a copy of the string in case we're loading a file from the MRU menu.
|
||||
String str = Filename;
|
||||
int i;
|
||||
|
||||
// Search for Filename in the MRU list.
|
||||
for (i = 0; i < (LC_MRU_MAX - 1); i++)
|
||||
if (m_strMRU[i] == Filename)
|
||||
break;
|
||||
|
||||
// Move MRU strings before this one down.
|
||||
for (; i > 0; i--)
|
||||
m_strMRU[i] = m_strMRU[i-1];
|
||||
|
||||
m_strMRU[0] = str;
|
||||
|
||||
UpdateMRU();
|
||||
}
|
||||
|
||||
void MainWnd::RemoveFromMRU(int index)
|
||||
{
|
||||
for (int i = index; i < (LC_MRU_MAX - 1); i++)
|
||||
m_strMRU[i] = m_strMRU[i+1];
|
||||
m_strMRU[LC_MRU_MAX - 1].Empty ();
|
||||
|
||||
UpdateMRU ();
|
||||
}
|
34
common/mainwnd.h
Normal file
34
common/mainwnd.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef _MAINWND_H_
|
||||
#define _MAINWND_H_
|
||||
|
||||
#include "str.h"
|
||||
#include "basewnd.h"
|
||||
|
||||
#define LC_MRU_MAX 4
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_MAINWND_RECENT1,
|
||||
LC_MAINWND_RECENT2,
|
||||
LC_MAINWND_RECENT3,
|
||||
LC_MAINWND_RECENT4,
|
||||
LC_MAINWND_NUM_COMMANDS
|
||||
} LC_MAINWND_COMMANDS;
|
||||
|
||||
class MainWnd : public BaseWnd
|
||||
{
|
||||
public:
|
||||
MainWnd ();
|
||||
virtual ~MainWnd ();
|
||||
|
||||
void UpdateMRU ();
|
||||
void AddToMRU (const char *filename);
|
||||
void RemoveFromMRU (int index);
|
||||
const char* GetMRU (int index) const
|
||||
{ return m_strMRU[index]; }
|
||||
|
||||
protected:
|
||||
String m_strMRU[LC_MRU_MAX];
|
||||
};
|
||||
|
||||
#endif // _MAINWND_H_
|
688
common/matrix.cpp
Normal file
688
common/matrix.cpp
Normal file
|
@ -0,0 +1,688 @@
|
|||
//
|
||||
// 4x4 Matrix class
|
||||
//
|
||||
|
||||
#include <memory.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "matrix.h"
|
||||
#include "defines.h"
|
||||
|
||||
// =============================================================================
|
||||
// static functions
|
||||
|
||||
static float Identity[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
|
||||
|
||||
// Perform a 4x4 matrix multiplication (product = a x b).
|
||||
// WARNING: (product != b) assumed
|
||||
static void matmul (float *product, const float *a, const float *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
#define A(row,col) a[(col<<2)+row]
|
||||
#define B(row,col) b[(col<<2)+row]
|
||||
#define P(row,col) product[(col<<2)+row]
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
float ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3);
|
||||
P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0);
|
||||
P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1);
|
||||
P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2);
|
||||
P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3);
|
||||
}
|
||||
|
||||
#undef A
|
||||
#undef B
|
||||
#undef P
|
||||
}
|
||||
|
||||
// Generate a 4x4 transformation matrix from rotation parameters.
|
||||
static void rotation_matrix (double angle, float x, float y, float z, float m[] )
|
||||
{
|
||||
float s, c, mag, xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c;
|
||||
|
||||
s = (float)sin (angle * DTOR);
|
||||
c = (float)cos (angle * DTOR);
|
||||
mag = (float)sqrt(x*x + y*y + z*z);
|
||||
|
||||
if (mag == 0)
|
||||
{
|
||||
// generate an identity matrix and return
|
||||
memcpy (m, Identity, sizeof(float[16]));
|
||||
return;
|
||||
}
|
||||
|
||||
x /= mag;
|
||||
y /= mag;
|
||||
z /= mag;
|
||||
|
||||
xx = x * x;
|
||||
yy = y * y;
|
||||
zz = z * z;
|
||||
xy = x * y;
|
||||
yz = y * z;
|
||||
zx = z * x;
|
||||
xs = x * s;
|
||||
ys = y * s;
|
||||
zs = z * s;
|
||||
one_c = 1.0f - c;
|
||||
|
||||
m[0] = (one_c * xx) + c;
|
||||
m[4] = (one_c * xy) - zs;
|
||||
m[8] = (one_c * zx) + ys;
|
||||
m[12]= 0;
|
||||
|
||||
m[1] = (one_c * xy) + zs;
|
||||
m[5] = (one_c * yy) + c;
|
||||
m[9] = (one_c * yz) - xs;
|
||||
m[13]= 0;
|
||||
|
||||
m[2] = (one_c * zx) - ys;
|
||||
m[6] = (one_c * yz) + xs;
|
||||
m[10]= (one_c * zz) + c;
|
||||
m[14]= 0;
|
||||
|
||||
m[3] = 0;
|
||||
m[7] = 0;
|
||||
m[11]= 0;
|
||||
m[15]= 1;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Matrix class
|
||||
|
||||
Matrix::Matrix ()
|
||||
{
|
||||
LoadIdentity();
|
||||
}
|
||||
|
||||
Matrix::Matrix (const float* mat)
|
||||
{
|
||||
memcpy (&m[0], mat, sizeof(float[16]));
|
||||
}
|
||||
|
||||
// Create a matrix from axis-angle and a point
|
||||
Matrix::Matrix (const float *rot, const float *pos)
|
||||
{
|
||||
float tmp[4] = { rot[0], rot[1], rot[2], rot[3]*DTOR };
|
||||
float q[4];
|
||||
float length, cosA, sinA;
|
||||
length = (float)sqrt(tmp[0]*tmp[0] + tmp[1]*tmp[1] + tmp[2]*tmp[2]);
|
||||
|
||||
// if zero vector passed in, just return identity quaternion
|
||||
if (length < 1E-5)
|
||||
{
|
||||
q[0] = 0;
|
||||
q[1] = 0;
|
||||
q[2] = 0;
|
||||
q[3] = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
tmp[0] /= length;
|
||||
tmp[1] /= length;
|
||||
tmp[2] /= length;
|
||||
|
||||
cosA = (float)cos(tmp[3] / 2.0f);
|
||||
sinA = (float)sin(tmp[3] / 2.0f);
|
||||
|
||||
q[3] = cosA;
|
||||
q[0] = sinA * tmp[0];
|
||||
q[1] = sinA * tmp[1];
|
||||
q[2] = sinA * tmp[2];
|
||||
|
||||
// Now calculate the matrix
|
||||
float s,xs,ys,zs,wx,wy,wz,xx,xy,xz,yy,yz,zz;
|
||||
|
||||
s = 2.0f / (q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
|
||||
|
||||
xs = q[0] * s; ys = q[1] * s; zs = q[2] * s;
|
||||
wx = q[3] * xs; wy = q[3] * ys; wz = q[3] * zs;
|
||||
xx = q[0] * xs; xy = q[0] * ys; xz = q[0] * zs;
|
||||
yy = q[1] * ys; yz = q[1] * zs; zz = q[2] * zs;
|
||||
|
||||
m[0] = 1.0f - (yy + zz);
|
||||
m[4] = xy - wz;
|
||||
m[8] = xz + wy;
|
||||
m[12]= pos[0];
|
||||
|
||||
m[1] = xy + wz;
|
||||
m[5] = 1.0f - (xx + zz);
|
||||
m[9] = yz - wx;
|
||||
m[13]= pos[1];
|
||||
|
||||
m[2] = xz - wy;
|
||||
m[6] = yz + wx;
|
||||
m[10]= 1.0f - (xx + yy);
|
||||
m[14]= pos[2];
|
||||
|
||||
m[3] = 0.0f;
|
||||
m[7] = 0.0f;
|
||||
m[11] = 0.0f;
|
||||
m[15] = 1.0f;
|
||||
}
|
||||
|
||||
// Expand from the .bin file
|
||||
void Matrix::FromPacked (const float *mat)
|
||||
{
|
||||
m[0] = mat[0];
|
||||
m[1] = mat[1];
|
||||
m[2] = mat[2];
|
||||
m[3] = 0.0f;
|
||||
m[4] = mat[3];
|
||||
m[5] = mat[4];
|
||||
m[6] = mat[5];
|
||||
m[7] = 0.0f;
|
||||
m[8] = mat[6];
|
||||
m[9] = mat[7];
|
||||
m[10] = mat[8];
|
||||
m[11] = 0.0f;
|
||||
m[12] = mat[9];
|
||||
m[13] = mat[10];
|
||||
m[14] = mat[11];
|
||||
m[15] = 0.0f;
|
||||
}
|
||||
|
||||
void Matrix::FromFloat (const float* mat)
|
||||
{
|
||||
memcpy (&m[0], mat, sizeof(float[16]));
|
||||
}
|
||||
|
||||
void Matrix::LoadIdentity ()
|
||||
{
|
||||
memcpy (&m[0], &Identity, sizeof(float[16]));
|
||||
}
|
||||
|
||||
float Matrix::Determinant() const
|
||||
{
|
||||
return m[0]*m[5]*m[10] + m[1]*m[6]*m[8] + m[2]*m[4]*m[9] - m[0]*m[6]*m[9] - m[1]*m[4]*m[10] - m[2]*m[5]*m[8];
|
||||
}
|
||||
|
||||
void Matrix::Multiply(const Matrix& m1, const Matrix& m2)
|
||||
{
|
||||
matmul(m, m1.m, m2.m);
|
||||
}
|
||||
|
||||
void Matrix::Rotate (float angle, float x, float y, float z)
|
||||
{
|
||||
float rm[16];
|
||||
|
||||
if (angle == 0.0)
|
||||
return;
|
||||
|
||||
rotation_matrix(angle, x, y, z, rm);
|
||||
matmul(rm, rm, m);
|
||||
memcpy (&m[0], &rm[0], sizeof(rm));
|
||||
}
|
||||
|
||||
void Matrix::RotateCenter (float angle, float x, float y, float z, float px, float py, float pz)
|
||||
{
|
||||
m[12] -= px;
|
||||
m[13] -= py;
|
||||
m[14] -= pz;
|
||||
|
||||
Rotate (angle, x, y, z);
|
||||
|
||||
m[12] += px;
|
||||
m[13] += py;
|
||||
m[14] += pz;
|
||||
}
|
||||
|
||||
void Matrix::Translate (float x, float y, float z)
|
||||
{
|
||||
m[12] = m[0] * x + m[4] * y + m[8] * z + m[12];
|
||||
m[13] = m[1] * x + m[5] * y + m[9] * z + m[13];
|
||||
m[14] = m[2] * x + m[6] * y + m[10] * z + m[14];
|
||||
m[15] = m[3] * x + m[7] * y + m[11] * z + m[15];
|
||||
}
|
||||
|
||||
void Matrix::SetTranslation (float x, float y, float z)
|
||||
{
|
||||
m[12] = x;
|
||||
m[13] = y;
|
||||
m[14] = z;
|
||||
m[15] = 1;
|
||||
}
|
||||
|
||||
void Matrix::GetTranslation (float* x, float* y, float* z)
|
||||
{
|
||||
*x = m[12];
|
||||
*y = m[13];
|
||||
*z = m[14];
|
||||
}
|
||||
|
||||
void Matrix::GetTranslation (float pos[3])
|
||||
{
|
||||
pos[0] = m[12];
|
||||
pos[1] = m[13];
|
||||
pos[2] = m[14];
|
||||
}
|
||||
|
||||
void Matrix::SetTranslation (float pos[3])
|
||||
{
|
||||
m[12] = pos[0];
|
||||
m[13] = pos[1];
|
||||
m[14] = pos[2];
|
||||
m[15] = 1;
|
||||
}
|
||||
|
||||
void Matrix::CreateOld(float mx, float my, float mz, float rx, float ry, float rz)
|
||||
{
|
||||
LoadIdentity();
|
||||
Translate(mx, my, mz);
|
||||
|
||||
float rm[16];
|
||||
rotation_matrix(rx, 1, 0, 0, rm);
|
||||
matmul(m, m, rm);
|
||||
rotation_matrix(ry, 0, 1, 0, rm);
|
||||
matmul(m, m, rm);
|
||||
rotation_matrix(rz, 0, 0, 1, rm);
|
||||
matmul(m, m, rm);
|
||||
}
|
||||
|
||||
// Transform a point by a 4x4 matrix. out = m * in
|
||||
void Matrix::TransformPoint(float out[], const float in[3])
|
||||
{
|
||||
out[0] = m[0]*in[0] + m[4]*in[1] + m[8]*in[2] + m[12];
|
||||
out[1] = m[1]*in[0] + m[5]*in[1] + m[9]*in[2] + m[13];
|
||||
out[2] = m[2]*in[0] + m[6]*in[1] + m[10]*in[2] + m[14];
|
||||
}
|
||||
|
||||
void Matrix::TransformPoints (float p[], int n)
|
||||
{
|
||||
for (int i = 0; i < n*3; i += 3)
|
||||
{
|
||||
float tmp[3] = { p[i], p[i+1], p[i+2] };
|
||||
TransformPoint (&p[i], tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void Matrix::FromLDraw (const float *f)
|
||||
{
|
||||
float trans[16] = { 1,0,0,0, 0,0,-1,0, 0,1,0,0, 0,0,0,1 };
|
||||
float t[16] = { 1,0,0,0, 0,0,1,0, 0,-1,0,0, 0,0,0,1 };
|
||||
|
||||
m[0] = f[3]; m[1] = f[6]; m[2] = f[9]; m[3] = 0.0f;
|
||||
m[4] = f[4]; m[5] = f[7]; m[6] = f[10]; m[7] = 0.0f;
|
||||
m[8] = f[5]; m[9] = f[8]; m[10]= f[11]; m[11] = 0.0f;
|
||||
m[12]= f[0]/25; m[13]= f[1]/25; m[14]= f[2]/25; m[15] = 1.0f;
|
||||
|
||||
matmul (m, m, t);
|
||||
matmul (trans, trans, m);
|
||||
memcpy (&m[0], &trans[0], sizeof(m));
|
||||
}
|
||||
|
||||
void Matrix::ToLDraw (float *f) const
|
||||
{
|
||||
float trans[16] = { 1,0,0,0, 0,0,-1,0, 0,1,0,0, 0,0,0,1 };
|
||||
float tmp[16] = { 1,0,0,0, 0,0,1,0, 0,-1,0,0, 0,0,0,1 };
|
||||
|
||||
matmul(tmp, tmp, m);
|
||||
matmul (tmp, tmp, trans);
|
||||
|
||||
f[0] = m[12]*25; f[1] = -m[14]*25; f[2] = m[13]*25;
|
||||
f[3] = tmp[0]; f[4] = tmp[4]; f[5] = tmp[8];
|
||||
f[6] = tmp[1]; f[7] = tmp[5]; f[8] = tmp[9];
|
||||
f[9] = tmp[2]; f[10]= tmp[6]; f[11]= tmp[10];
|
||||
}
|
||||
|
||||
void Matrix::ToEulerAngles (float *rot) const
|
||||
{
|
||||
double sinPitch, cosPitch, sinRoll, cosRoll, sinYaw, cosYaw;
|
||||
float colMatrix[4][4];
|
||||
|
||||
colMatrix[0][0] = m[0];
|
||||
colMatrix[0][1] = m[4];
|
||||
colMatrix[0][2] = m[8];
|
||||
colMatrix[0][3] = m[12];
|
||||
|
||||
colMatrix[1][0] = m[1];
|
||||
colMatrix[1][1] = m[5];
|
||||
colMatrix[1][2] = m[9];
|
||||
colMatrix[1][3] = m[13];
|
||||
|
||||
colMatrix[2][0] = m[2];
|
||||
colMatrix[2][1] = m[6];
|
||||
colMatrix[2][2] = m[10];
|
||||
colMatrix[2][3] = m[14];
|
||||
|
||||
colMatrix[3][0] = 0.0f;
|
||||
colMatrix[3][1] = 0.0f;
|
||||
colMatrix[3][2] = 0.0f;
|
||||
colMatrix[3][3] = 1.0f;
|
||||
|
||||
sinPitch = -colMatrix[2][0];
|
||||
cosPitch = sqrt(1 - sinPitch*sinPitch);
|
||||
|
||||
if (fabs(cosPitch) > 0.0005)
|
||||
{
|
||||
sinRoll = colMatrix[2][1] / cosPitch;
|
||||
cosRoll = colMatrix[2][2] / cosPitch;
|
||||
sinYaw = colMatrix[1][0] / cosPitch;
|
||||
cosYaw = colMatrix[0][0] / cosPitch;
|
||||
}
|
||||
else
|
||||
{
|
||||
sinRoll = -colMatrix[1][2];
|
||||
cosRoll = colMatrix[1][1];
|
||||
sinYaw = 0;
|
||||
cosYaw = 1;
|
||||
}
|
||||
|
||||
rot[2] = (float)(RTOD*atan2 (sinYaw, cosYaw));
|
||||
rot[1] = (float)(RTOD*atan2 (sinPitch, cosPitch));
|
||||
rot[0] = (float)(RTOD*atan2 (sinRoll, cosRoll));
|
||||
|
||||
if (rot[2] < 0) rot[2] += 360;
|
||||
if (rot[1] < 0) rot[1] += 360;
|
||||
if (rot[0] < 0) rot[0] += 360;
|
||||
}
|
||||
|
||||
void Matrix::ToAxisAngle(float *rot) const
|
||||
{
|
||||
Matrix tmp(*this);
|
||||
|
||||
// Normalize.
|
||||
float inv;
|
||||
inv = 1.0f / sqrtf(tmp.m[0]*tmp.m[0] + tmp.m[1]*tmp.m[1] + tmp.m[2]*tmp.m[2]);
|
||||
tmp.m[0] *= inv; tmp.m[1] *= inv; tmp.m[2] *= inv;
|
||||
inv = 1.0f / sqrtf(tmp.m[4]*tmp.m[4] + tmp.m[5]*tmp.m[5] + tmp.m[6]*tmp.m[6]);
|
||||
tmp.m[4] *= inv; tmp.m[5] *= inv; tmp.m[6] *= inv;
|
||||
inv = 1.0f / sqrtf(tmp.m[8]*tmp.m[8] + tmp.m[9]*tmp.m[9] + tmp.m[10]*tmp.m[10]);
|
||||
tmp.m[8] *= inv; tmp.m[9] *= inv; tmp.m[10] *= inv;
|
||||
|
||||
// Determinant should be 1 for rotation matrices.
|
||||
if (tmp.Determinant() < 0.0f)
|
||||
{
|
||||
tmp.m[0] *= -1.0f;
|
||||
tmp.m[1] *= -1.0f;
|
||||
tmp.m[2] *= -1.0f;
|
||||
}
|
||||
|
||||
float fTrace = tmp.m[0] + tmp.m[5] + tmp.m[10];
|
||||
float fCos = 0.5f * (fTrace - 1.0f);
|
||||
|
||||
rot[3] = acosf(fCos); // in [0,PI]
|
||||
|
||||
if (rot[3] > 0.01f)
|
||||
{
|
||||
if (fabs (M_PI - rot[3]) > 0.01f)
|
||||
{
|
||||
rot[0] = tmp.m[6] - tmp.m[9];
|
||||
rot[1] = tmp.m[8] - tmp.m[2];
|
||||
rot[2] = tmp.m[1] - tmp.m[4];
|
||||
|
||||
inv = 1.0f / sqrtf(rot[0]*rot[0] + rot[1]*rot[1] + rot[2]*rot[2]);
|
||||
|
||||
rot[0] *= inv;
|
||||
rot[1] *= inv;
|
||||
rot[2] *= inv;
|
||||
}
|
||||
else
|
||||
{
|
||||
// angle is PI
|
||||
float fHalfInverse;
|
||||
if (tmp.m[0] >= tmp.m[5])
|
||||
{
|
||||
// r00 >= r11
|
||||
if (tmp.m[0] >= tmp.m[10])
|
||||
{
|
||||
// r00 is maximum diagonal term
|
||||
rot[0] = 0.5f * sqrtf(tmp.m[0] - tmp.m[5] - tmp.m[10] + 1.0f);
|
||||
fHalfInverse = 0.5f / rot[0];
|
||||
rot[1] = fHalfInverse * tmp.m[4];
|
||||
rot[2] = fHalfInverse * tmp.m[8];
|
||||
}
|
||||
else
|
||||
{
|
||||
// r22 is maximum diagonal term
|
||||
rot[2] = 0.5f * sqrtf(tmp.m[10] - tmp.m[0] - tmp.m[5] + 1.0f);
|
||||
fHalfInverse = 0.5f / rot[2];
|
||||
rot[0] = fHalfInverse * tmp.m[8];
|
||||
rot[1] = fHalfInverse * tmp.m[9];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// r11 > r00
|
||||
if (tmp.m[5] >= tmp.m[10])
|
||||
{
|
||||
// r11 is maximum diagonal term
|
||||
rot[1] = 0.5f * sqrtf(tmp.m[5] - tmp.m[0] - tmp.m[10] + 1.0f);
|
||||
fHalfInverse = 0.5f / rot[1];
|
||||
rot[0] = fHalfInverse * tmp.m[4];
|
||||
rot[2] = fHalfInverse * tmp.m[9];
|
||||
}
|
||||
else
|
||||
{
|
||||
// r22 is maximum diagonal term
|
||||
rot[2] = 0.5f * sqrtf(tmp.m[10] - tmp.m[0] - tmp.m[5] + 1.0f);
|
||||
fHalfInverse = 0.5f / rot[2];
|
||||
rot[0] = fHalfInverse * tmp.m[8];
|
||||
rot[1] = fHalfInverse * tmp.m[9];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The angle is 0 and the matrix is the identity. Any axis will
|
||||
// work, so just use the z-axis.
|
||||
rot[0] = 0.0f;
|
||||
rot[1] = 0.0f;
|
||||
rot[2] = 1.0f;
|
||||
}
|
||||
|
||||
rot[3] *= RTOD;
|
||||
}
|
||||
|
||||
void Matrix::FromEulerAngles (float roll, float pitch, float yaw)
|
||||
{
|
||||
float cosYaw, sinYaw, cosPitch, sinPitch, cosRoll, sinRoll;
|
||||
|
||||
cosYaw = (float)cos(yaw*DTOR);
|
||||
sinYaw = (float)sin(yaw*DTOR);
|
||||
cosPitch = (float)cos(pitch*DTOR);
|
||||
sinPitch = (float)sin(pitch*DTOR);
|
||||
cosRoll = (float)cos(roll*DTOR);
|
||||
sinRoll = (float)sin(roll*DTOR);
|
||||
|
||||
m[0] = cosYaw * cosPitch;
|
||||
m[4] = cosYaw * sinPitch * sinRoll - sinYaw * cosRoll;
|
||||
m[8] = cosYaw * sinPitch * cosRoll + sinYaw * sinRoll;
|
||||
m[12] = 0.0f;
|
||||
|
||||
m[1] = sinYaw * cosPitch;
|
||||
m[5] = cosYaw * cosRoll + sinYaw * sinPitch * sinRoll;
|
||||
m[9] = sinYaw * sinPitch * cosRoll - cosYaw * sinRoll;
|
||||
m[13] = 0.0f;
|
||||
|
||||
m[2] = -sinPitch;
|
||||
m[6] = cosPitch * sinRoll;
|
||||
m[10] = cosPitch * cosRoll;
|
||||
m[14] = 0.0f;
|
||||
|
||||
m[3] = 0.0f;
|
||||
m[7] = 0.0f;
|
||||
m[11] = 0.0f;
|
||||
m[15] = 1.0f;
|
||||
}
|
||||
|
||||
// Create a rotation matrix (angle is in degrees)
|
||||
void Matrix::FromAxisAngle (const float *axis, float angle)
|
||||
{
|
||||
if (angle == 0.0f)
|
||||
return;
|
||||
rotation_matrix (angle, axis[0], axis[1], axis[2], m);
|
||||
}
|
||||
|
||||
void Matrix::Transpose3()
|
||||
{
|
||||
float tmp;
|
||||
|
||||
tmp = m[1]; m[1] = m[4]; m[4] = tmp;
|
||||
tmp = m[2]; m[2] = m[8]; m[8] = tmp;
|
||||
tmp = m[6]; m[6] = m[9]; m[9] = tmp;
|
||||
}
|
||||
|
||||
bool Matrix::Invert ()
|
||||
{
|
||||
double t, inverse[16];
|
||||
int i, j, k, swap;
|
||||
double tmp[4][4];
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
inverse[i] = 0.0;
|
||||
inverse[0] = inverse[5] = inverse[10] = inverse[15] = 1.0;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
for (j = 0; j < 4; j++)
|
||||
tmp[i][j] = m[i*4+j];
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
// look for largest element in column.
|
||||
swap = i;
|
||||
for (j = i + 1; j < 4; j++)
|
||||
if (fabs(tmp[j][i]) > fabs(tmp[i][i]))
|
||||
swap = j;
|
||||
|
||||
if (swap != i)
|
||||
{
|
||||
// swap rows.
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
t = tmp[i][k];
|
||||
tmp[i][k] = tmp[swap][k];
|
||||
tmp[swap][k] = t;
|
||||
|
||||
t = inverse[i*4+k];
|
||||
inverse[i*4+k] = inverse[swap*4+k];
|
||||
inverse[swap*4+k] = t;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp[i][i] == 0)
|
||||
{
|
||||
// The matrix is singular, which shouldn't happen.
|
||||
return false;
|
||||
}
|
||||
|
||||
t = tmp[i][i];
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
tmp[i][k] /= t;
|
||||
inverse[i*4+k] /= t;
|
||||
}
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
if (j != i)
|
||||
{
|
||||
t = tmp[j][i];
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
tmp[j][k] -= tmp[i][k]*t;
|
||||
inverse[j*4+k] -= inverse[i*4+k]*t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
m[i] = (float)inverse[i];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Matrix::CreatePerspective (float fovy, float aspect, float nearval, float farval)
|
||||
{
|
||||
float left, right, bottom, top;
|
||||
float x, y, a, b, c, d;
|
||||
|
||||
LoadIdentity ();
|
||||
|
||||
top = nearval * (float)tan (fovy * M_PI / 360.0);
|
||||
bottom = -top;
|
||||
|
||||
left = bottom * aspect;
|
||||
right = top * aspect;
|
||||
|
||||
if ((nearval<=0.0 || farval<=0.0) || (nearval == farval) || (left == right) || (top == bottom))
|
||||
return;
|
||||
|
||||
x = (2.0f*nearval) / (right-left);
|
||||
y = (2.0f*nearval) / (top-bottom);
|
||||
a = (right+left) / (right-left);
|
||||
b = (top+bottom) / (top-bottom);
|
||||
c = -(farval+nearval) / ( farval-nearval);
|
||||
d = -(2.0f*farval*nearval) / (farval-nearval);
|
||||
|
||||
#define M(row,col) m[col*4+row]
|
||||
M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
|
||||
M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
|
||||
M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
|
||||
M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
|
||||
#undef M
|
||||
}
|
||||
|
||||
void Matrix::CreateLookat (const float *eye, const float *target, const float *up)
|
||||
{
|
||||
float x[3], y[3], z[3];
|
||||
float mag;
|
||||
|
||||
z[0] = eye[0] - target[0];
|
||||
z[1] = eye[1] - target[1];
|
||||
z[2] = eye[2] - target[2];
|
||||
mag = (float)sqrt (z[0]*z[0] + z[1]*z[1] + z[2]*z[2]);
|
||||
if (mag)
|
||||
{
|
||||
z[0] /= mag;
|
||||
z[1] /= mag;
|
||||
z[2] /= mag;
|
||||
}
|
||||
|
||||
y[0] = up[0];
|
||||
y[1] = up[1];
|
||||
y[2] = up[2];
|
||||
|
||||
// X vector = Y cross Z
|
||||
x[0] = y[1]*z[2] - y[2]*z[1];
|
||||
x[1] = -y[0]*z[2] + y[2]*z[0];
|
||||
x[2] = y[0]*z[1] - y[1]*z[0];
|
||||
|
||||
// Recompute Y = Z cross X
|
||||
y[0] = z[1]*x[2] - z[2]*x[1];
|
||||
y[1] = -z[0]*x[2] + z[2]*x[0];
|
||||
y[2] = z[0]*x[1] - z[1]*x[0];
|
||||
|
||||
mag = (float)sqrt (x[0]*x[0] + x[1]*x[1] + x[2]*x[2]);
|
||||
if (mag)
|
||||
{
|
||||
x[0] /= mag;
|
||||
x[1] /= mag;
|
||||
x[2] /= mag;
|
||||
}
|
||||
|
||||
mag = (float)sqrt (y[0]*y[0] + y[1]*y[1] + y[2]*y[2]);
|
||||
if (mag)
|
||||
{
|
||||
y[0] /= mag;
|
||||
y[1] /= mag;
|
||||
y[2] /= mag;
|
||||
}
|
||||
|
||||
#define M(row,col) m[col*4+row]
|
||||
M(0,0) = x[0]; M(0,1) = x[1]; M(0,2) = x[2]; M(0,3) = 0.0;
|
||||
M(1,0) = y[0]; M(1,1) = y[1]; M(1,2) = y[2]; M(1,3) = 0.0;
|
||||
M(2,0) = z[0]; M(2,1) = z[1]; M(2,2) = z[2]; M(2,3) = 0.0;
|
||||
M(3,0) = 0.0; M(3,1) = 0.0; M(3,2) = 0.0; M(3,3) = 1.0;
|
||||
#undef M
|
||||
|
||||
// Translate Eye to Origin
|
||||
m[12] = m[0] * -eye[0] + m[4] * -eye[1] + m[8] * -eye[2] + m[12];
|
||||
m[13] = m[1] * -eye[0] + m[5] * -eye[1] + m[9] * -eye[2] + m[13];
|
||||
m[14] = m[2] * -eye[0] + m[6] * -eye[1] + m[10] * -eye[2] + m[14];
|
||||
m[15] = m[3] * -eye[0] + m[7] * -eye[1] + m[11] * -eye[2] + m[15];
|
||||
}
|
49
common/matrix.h
Normal file
49
common/matrix.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
// Matrix class
|
||||
//
|
||||
|
||||
#ifndef _MATRIX_H_
|
||||
#define _MATRIX_H_
|
||||
|
||||
class Matrix
|
||||
{
|
||||
public:
|
||||
Matrix();
|
||||
Matrix(const float *mat);
|
||||
Matrix(const float *rot, const float *pos);
|
||||
~Matrix() { };
|
||||
|
||||
void FromPacked(const float *mat);
|
||||
void FromFloat(const float* mat);
|
||||
void FromLDraw(const float *f);
|
||||
void FromEulerAngles(float yaw, float pitch, float roll);
|
||||
void FromAxisAngle(const float *axis, float angle);
|
||||
|
||||
void ToLDraw(float *f) const;
|
||||
void ToEulerAngles(float *rot) const;
|
||||
void ToAxisAngle(float *rot) const;
|
||||
|
||||
void LoadIdentity();
|
||||
void Translate(float x, float y, float z);
|
||||
void Multiply(const Matrix& m1, const Matrix& m2);
|
||||
bool Invert();
|
||||
void Transpose3();
|
||||
float Determinant() const;
|
||||
|
||||
void GetTranslation(float *x, float *y, float *z);
|
||||
void SetTranslation(float x, float y, float z);
|
||||
void GetTranslation(float pos[3]);
|
||||
void SetTranslation(float pos[3]);
|
||||
|
||||
void TransformPoint(float out[], const float in[3]);
|
||||
void TransformPoints(float p[], int n);
|
||||
void CreateOld(float mx, float my, float mz, float rx, float ry, float rz);
|
||||
void Rotate(float angle, float x, float y, float z);
|
||||
void RotateCenter(float angle, float x, float y, float z, float px, float py, float pz);
|
||||
void CreatePerspective(float fovy, float aspect, float nearval, float farval);
|
||||
void CreateLookat(const float *eye, const float *target, const float *up);
|
||||
|
||||
public:
|
||||
float m[16];
|
||||
};
|
||||
|
||||
#endif //_MATRIX_H_
|
32
common/message.cpp
Normal file
32
common/message.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// LeoCAD messaging system
|
||||
//
|
||||
|
||||
#include "message.h"
|
||||
|
||||
Messenger::Messenger ()
|
||||
{
|
||||
m_nRef = 0;
|
||||
}
|
||||
|
||||
Messenger::~Messenger ()
|
||||
{
|
||||
for (int i = 0; i < m_Listeners.GetSize (); i++)
|
||||
delete m_Listeners[i];
|
||||
}
|
||||
|
||||
void Messenger::Dispatch (int message, void *data)
|
||||
{
|
||||
for (int i = 0; i < m_Listeners.GetSize (); i++)
|
||||
m_Listeners[i]->func (message, data, m_Listeners[i]->user);
|
||||
}
|
||||
|
||||
void Messenger::Listen (LC_MSG_CALLBACK func, void *user)
|
||||
{
|
||||
LC_MSG_STRUCT *s = new LC_MSG_STRUCT;
|
||||
|
||||
s->func = func;
|
||||
s->user = user;
|
||||
|
||||
m_Listeners.Add (s);
|
||||
}
|
40
common/message.h
Normal file
40
common/message.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#ifndef _MESSAGE_H_
|
||||
#define _MESSAGE_H_
|
||||
|
||||
#include "array.h"
|
||||
|
||||
typedef void (*LC_MSG_CALLBACK) (int message, void *data, void *user);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_MSG_FOCUS_CHANGED,
|
||||
// LC_MSG_SELECTION_CHANGED,
|
||||
LC_MSG_COUNT
|
||||
} LC_MSG_TYPES;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LC_MSG_CALLBACK func;
|
||||
void *user;
|
||||
} LC_MSG_STRUCT;
|
||||
|
||||
class Messenger
|
||||
{
|
||||
public:
|
||||
Messenger ();
|
||||
~Messenger ();
|
||||
|
||||
void AddRef ()
|
||||
{ m_nRef++; };
|
||||
void DecRef ()
|
||||
{ m_nRef--; if (m_nRef == 0) delete this; };
|
||||
|
||||
void Dispatch (int message, void *data);
|
||||
void Listen (LC_MSG_CALLBACK func, void *user);
|
||||
|
||||
protected:
|
||||
int m_nRef;
|
||||
PtrArray<LC_MSG_STRUCT> m_Listeners;
|
||||
};
|
||||
|
||||
#endif // _MESSAGE_H_
|
1369
common/minifig.cpp
Normal file
1369
common/minifig.cpp
Normal file
File diff suppressed because it is too large
Load diff
73
common/minifig.h
Normal file
73
common/minifig.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
#ifndef _MINIFIG_H_
|
||||
#define _MINIFIG_H_
|
||||
|
||||
#include "glwindow.h"
|
||||
#include "file.h"
|
||||
#include "algebra.h"
|
||||
#include "array.h"
|
||||
|
||||
class PieceInfo;
|
||||
|
||||
enum LC_MFW_TYPES
|
||||
{
|
||||
LC_MFW_HAT,
|
||||
LC_MFW_HEAD,
|
||||
LC_MFW_TORSO,
|
||||
LC_MFW_NECK,
|
||||
LC_MFW_LEFT_ARM,
|
||||
LC_MFW_RIGHT_ARM,
|
||||
LC_MFW_LEFT_HAND,
|
||||
LC_MFW_RIGHT_HAND,
|
||||
LC_MFW_LEFT_TOOL,
|
||||
LC_MFW_RIGHT_TOOL,
|
||||
LC_MFW_HIPS,
|
||||
LC_MFW_LEFT_LEG,
|
||||
LC_MFW_RIGHT_LEG,
|
||||
LC_MFW_LEFT_SHOE,
|
||||
LC_MFW_RIGHT_SHOE,
|
||||
LC_MFW_NUMITEMS
|
||||
};
|
||||
|
||||
struct lcMinifigPieceInfo
|
||||
{
|
||||
char Description[80];
|
||||
PieceInfo* Info;
|
||||
Matrix44 Offset;
|
||||
};
|
||||
|
||||
class MinifigWizard : public GLWindow
|
||||
{
|
||||
public:
|
||||
MinifigWizard (GLWindow *share);
|
||||
~MinifigWizard ();
|
||||
|
||||
void OnDraw ();
|
||||
|
||||
void Calculate();
|
||||
int GetSelectionIndex(int Type) const;
|
||||
void SetSelectionIndex(int Type, int Index);
|
||||
void SetColor(int Type, int Color);
|
||||
void SetAngle(int Type, float Angle);
|
||||
|
||||
void GetMinifigNames (char ***names, int *count);
|
||||
void SaveMinifig (const char* name);
|
||||
bool LoadMinifig (const char* name);
|
||||
void DeleteMinifig (const char* name);
|
||||
|
||||
void ParseSettings(File& Settings);
|
||||
|
||||
ObjArray<lcMinifigPieceInfo> mSettings[LC_MFW_NUMITEMS];
|
||||
|
||||
PieceInfo* m_Info[LC_MFW_NUMITEMS];
|
||||
int m_Colors[LC_MFW_NUMITEMS];
|
||||
float m_Angles[LC_MFW_NUMITEMS];
|
||||
Matrix44 m_Matrices[LC_MFW_NUMITEMS];
|
||||
|
||||
protected:
|
||||
// saved minifig templates
|
||||
int m_MinifigCount;
|
||||
char **m_MinifigNames;
|
||||
char **m_MinifigTemplates;
|
||||
};
|
||||
|
||||
#endif // _MINIFIG_H_
|
22
common/module.mk
Normal file
22
common/module.mk
Normal file
|
@ -0,0 +1,22 @@
|
|||
SRC += common/algebra.cpp common/camera.cpp common/console.cpp common/curve.cpp common/file.cpp \
|
||||
common/globals.cpp common/group.cpp common/image.cpp common/im_bmp.cpp common/im_gif.cpp \
|
||||
common/lc_application.cpp common/library.cpp common/light.cpp common/mainwnd.cpp \
|
||||
common/matrix.cpp common/message.cpp common/minifig.cpp common/object.cpp common/opengl.cpp \
|
||||
common/piece.cpp common/pieceinf.cpp common/preview.cpp common/project.cpp common/quant.cpp \
|
||||
common/str.cpp common/terrain.cpp common/texfont.cpp common/texture.cpp common/tr.cpp \
|
||||
common/vector.cpp common/view.cpp
|
||||
|
||||
ifeq ($(HAVE_JPEGLIB), yes)
|
||||
LIBS += -ljpeg
|
||||
SRC += common/im_jpg.cpp
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_ZLIB), yes)
|
||||
ifeq ($(HAVE_PNGLIB), yes)
|
||||
LIBS += -lpng -lz
|
||||
SRC += common/im_png.cpp
|
||||
endif
|
||||
endif
|
||||
|
||||
LIBS += -lm
|
||||
|
568
common/object.cpp
Executable file
568
common/object.cpp
Executable file
|
@ -0,0 +1,568 @@
|
|||
// Base class for all drawable objects
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include "globals.h"
|
||||
#include "project.h"
|
||||
#include "object.h"
|
||||
#include "matrix.h"
|
||||
#include "vector.h"
|
||||
#include "file.h"
|
||||
#include "lc_application.h"
|
||||
|
||||
#define LC_KEY_SAVE_VERSION 1 // LeoCAD 0.73
|
||||
|
||||
// =============================================================================
|
||||
// Static functions
|
||||
|
||||
// Returns in (A,B,C,D) the coefficientes of the plane with the three
|
||||
// succesive (in counterclockwise order) vertices p1,p2,p3.
|
||||
static void GetPolyCoeffs (float x1, float y1, float z1, float x2, float y2, float z2,
|
||||
float x3, float y3, float z3, float *A, float *B, float *C, float *D)
|
||||
{
|
||||
*A = ((y1-y2)*(z3-z2)) - ((z1-z2)*(y3-y2));
|
||||
*B = ((z1-z2)*(x3-x2)) - ((x1-x2)*(z3-z2));
|
||||
*C = ((x1-x2)*(y3-y2)) - ((y1-y2)*(x3-x2));
|
||||
*D = - ((*A)*x1) - ((*B)*y1) - ((*C)*z1);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// ClickLine structure
|
||||
|
||||
double LC_CLICKLINE::PointDistance (float *point)
|
||||
{
|
||||
Vector op ((float)(point[0] - a1), (float)(point[1] - b1), (float)(point[2] - c1));
|
||||
Vector d ((float)a2, (float)b2, (float)c2);
|
||||
float len = d.Length ();
|
||||
d.Normalize ();
|
||||
float t = op.Dot (d);
|
||||
|
||||
if (t > 0)
|
||||
{
|
||||
if (t >= len)
|
||||
t = 1;
|
||||
else
|
||||
t /= len;
|
||||
|
||||
d *= (t*len);
|
||||
op -= d;
|
||||
}
|
||||
|
||||
return op.Length ();
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Object class
|
||||
|
||||
Object::Object (LC_OBJECT_TYPE nType)
|
||||
{
|
||||
// m_nState = 0;
|
||||
// m_strName[0] = '\0';
|
||||
|
||||
m_pAnimationKeys = NULL;
|
||||
m_pInstructionKeys = NULL;
|
||||
|
||||
m_nObjectType = nType;
|
||||
m_pKeyValues = NULL;
|
||||
|
||||
// m_pParent = NULL;
|
||||
// m_pNext = NULL;
|
||||
// m_pNextRender = NULL;
|
||||
}
|
||||
|
||||
Object::~Object ()
|
||||
{
|
||||
delete []m_pKeyValues;
|
||||
RemoveKeys ();
|
||||
}
|
||||
|
||||
bool Object::FileLoad (File& file)
|
||||
{
|
||||
lcuint8 version;
|
||||
|
||||
file.ReadByte (&version, 1);
|
||||
if (version > LC_KEY_SAVE_VERSION)
|
||||
return false;
|
||||
|
||||
lcuint16 time;
|
||||
float param[4];
|
||||
lcuint8 type;
|
||||
lcuint32 n;
|
||||
|
||||
file.ReadLong (&n, 1);
|
||||
while (n--)
|
||||
{
|
||||
file.ReadShort (&time, 1);
|
||||
file.ReadFloat (param, 4);
|
||||
file.ReadByte (&type, 1);
|
||||
|
||||
ChangeKey (time, false, true, param, type);
|
||||
}
|
||||
|
||||
file.ReadLong (&n, 1);
|
||||
while (n--)
|
||||
{
|
||||
file.ReadShort (&time, 1);
|
||||
file.ReadFloat (param, 4);
|
||||
file.ReadByte (&type, 1);
|
||||
|
||||
ChangeKey (time, true, true, param, type);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Object::FileSave (File& file) const
|
||||
{
|
||||
lcuint8 version = LC_KEY_SAVE_VERSION;
|
||||
LC_OBJECT_KEY *node;
|
||||
lcuint32 n;
|
||||
|
||||
file.WriteByte (&version, 1);
|
||||
|
||||
for (n = 0, node = m_pInstructionKeys; node; node = node->next)
|
||||
n++;
|
||||
file.WriteLong (&n, 1);
|
||||
|
||||
for (node = m_pInstructionKeys; node; node = node->next)
|
||||
{
|
||||
file.WriteShort (&node->time, 1);
|
||||
file.WriteFloat (node->param, 4);
|
||||
file.WriteByte (&node->type, 1);
|
||||
}
|
||||
|
||||
for (n = 0, node = m_pAnimationKeys; node; node = node->next)
|
||||
n++;
|
||||
file.WriteLong (&n, 1);
|
||||
|
||||
for (node = m_pAnimationKeys; node; node = node->next)
|
||||
{
|
||||
file.WriteShort (&node->time, 1);
|
||||
file.WriteFloat (node->param, 4);
|
||||
file.WriteByte (&node->type, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Key handling
|
||||
|
||||
static LC_OBJECT_KEY* AddNode (LC_OBJECT_KEY *node, unsigned short nTime, unsigned char nType)
|
||||
{
|
||||
LC_OBJECT_KEY* newnode = (LC_OBJECT_KEY*)malloc (sizeof (LC_OBJECT_KEY));
|
||||
|
||||
if (node)
|
||||
{
|
||||
newnode->next = node->next;
|
||||
node->next = newnode;
|
||||
}
|
||||
else
|
||||
newnode->next = NULL;
|
||||
|
||||
newnode->type = nType;
|
||||
newnode->time = nTime;
|
||||
newnode->param[0] = newnode->param[1] = newnode->param[2] = newnode->param[3] = 0;
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
void Object::RegisterKeys (float *values[], LC_OBJECT_KEY_INFO* info, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
m_pKeyValues = new float* [count];
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
m_pKeyValues[i] = values[i];
|
||||
|
||||
m_pAnimationKeys = AddNode (NULL, 1, 0);
|
||||
m_pInstructionKeys = AddNode (NULL, 1, 0);
|
||||
|
||||
for (i = count-1; i > 0; i--)
|
||||
{
|
||||
AddNode (m_pAnimationKeys, 1, i);
|
||||
AddNode (m_pInstructionKeys, 1, i);
|
||||
}
|
||||
|
||||
m_pKeyInfo = info;
|
||||
m_nKeyInfoCount = count;
|
||||
}
|
||||
|
||||
void Object::RemoveKeys ()
|
||||
{
|
||||
LC_OBJECT_KEY *node, *prev;
|
||||
|
||||
for (node = m_pInstructionKeys; node;)
|
||||
{
|
||||
prev = node;
|
||||
node = node->next;
|
||||
free (prev);
|
||||
}
|
||||
|
||||
for (node = m_pAnimationKeys; node;)
|
||||
{
|
||||
prev = node;
|
||||
node = node->next;
|
||||
free (prev);
|
||||
}
|
||||
}
|
||||
|
||||
void Object::ChangeKey (unsigned short nTime, bool bAnimation, bool bAddKey, const float *param, unsigned char nKeyType)
|
||||
{
|
||||
LC_OBJECT_KEY *node, *poskey = NULL, *newpos = NULL;
|
||||
if (bAnimation)
|
||||
node = m_pAnimationKeys;
|
||||
else
|
||||
node = m_pInstructionKeys;
|
||||
|
||||
while (node)
|
||||
{
|
||||
if ((node->time <= nTime) &&
|
||||
(node->type == nKeyType))
|
||||
poskey = node;
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
if (bAddKey)
|
||||
{
|
||||
if (poskey)
|
||||
{
|
||||
if (poskey->time != nTime)
|
||||
newpos = AddNode(poskey, nTime, nKeyType);
|
||||
}
|
||||
else
|
||||
newpos = AddNode(poskey, nTime, nKeyType);
|
||||
}
|
||||
|
||||
if (newpos == NULL)
|
||||
newpos = poskey;
|
||||
|
||||
for (int i = 0; i < m_pKeyInfo[nKeyType].size; i++)
|
||||
newpos->param[i] = param[i];
|
||||
}
|
||||
|
||||
void Object::CalculateKeys (unsigned short nTime, bool bAnimation)
|
||||
{
|
||||
// LC_OBJECT_KEY *next[m_nKeyInfoCount], *prev[m_nKeyInfoCount], *node;
|
||||
LC_OBJECT_KEY *next[32], *prev[32], *node;
|
||||
int i, empty = m_nKeyInfoCount;
|
||||
|
||||
for (i = 0; i < m_nKeyInfoCount; i++)
|
||||
next[i] = NULL;
|
||||
|
||||
if (bAnimation)
|
||||
node = m_pAnimationKeys;
|
||||
else
|
||||
node = m_pInstructionKeys;
|
||||
|
||||
// Get the previous and next keys for each variable
|
||||
while (node && empty)
|
||||
{
|
||||
if (node->time <= nTime)
|
||||
{
|
||||
prev[node->type] = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (next[node->type] == NULL)
|
||||
{
|
||||
next[node->type] = node;
|
||||
empty--;
|
||||
}
|
||||
}
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
// TODO: USE KEY IN/OUT WEIGHTS
|
||||
for (i = 0; i < m_nKeyInfoCount; i++)
|
||||
{
|
||||
LC_OBJECT_KEY *n = next[i], *p = prev[i];
|
||||
|
||||
if (bAnimation && (n != NULL) && (p->time != nTime))
|
||||
{
|
||||
float t = (float)(nTime - p->time)/(n->time - p->time);
|
||||
|
||||
for (int j = 0; j < m_pKeyInfo[i].size; j++)
|
||||
m_pKeyValues[i][j] = p->param[j] + (n->param[j] - p->param[j])*t;
|
||||
}
|
||||
else
|
||||
for (int j = 0; j < m_pKeyInfo[i].size; j++)
|
||||
m_pKeyValues[i][j] = p->param[j];
|
||||
}
|
||||
}
|
||||
|
||||
void Object::CalculateSingleKey (unsigned short nTime, bool bAnimation, int keytype, float *value) const
|
||||
{
|
||||
LC_OBJECT_KEY *next = NULL, *prev = NULL, *node;
|
||||
|
||||
if (bAnimation)
|
||||
node = m_pAnimationKeys;
|
||||
else
|
||||
node = m_pInstructionKeys;
|
||||
|
||||
while (node)
|
||||
{
|
||||
if (node->type == keytype)
|
||||
{
|
||||
if (node->time <= nTime)
|
||||
prev = node;
|
||||
else
|
||||
{
|
||||
if (next == NULL)
|
||||
{
|
||||
next = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
// TODO: USE KEY IN/OUT WEIGHTS
|
||||
if (bAnimation && (next != NULL) && (prev->time != nTime))
|
||||
{
|
||||
float t = (float)(nTime - prev->time)/(next->time - prev->time);
|
||||
|
||||
for (int j = 0; j < m_pKeyInfo[keytype].size; j++)
|
||||
value[j] = prev->param[j] + (next->param[j] - prev->param[j])*t;
|
||||
}
|
||||
else
|
||||
for (int j = 0; j < m_pKeyInfo[keytype].size; j++)
|
||||
value[j] = prev->param[j];
|
||||
}
|
||||
|
||||
void Object::InsertTime (unsigned short start, bool animation, unsigned short time)
|
||||
{
|
||||
LC_OBJECT_KEY *node, *prev = NULL;
|
||||
unsigned short last;
|
||||
bool end[32];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < m_nKeyInfoCount; i++)
|
||||
end[i] = false;
|
||||
|
||||
if (animation)
|
||||
{
|
||||
node = m_pAnimationKeys;
|
||||
last = lcGetActiveProject()->GetTotalFrames ();
|
||||
}
|
||||
else
|
||||
{
|
||||
node = m_pInstructionKeys;
|
||||
last = 255;
|
||||
}
|
||||
|
||||
for (; node != NULL; prev = node, node = node->next)
|
||||
{
|
||||
// skip everything before the start time
|
||||
if ((node->time < start) || (node->time == 1))
|
||||
continue;
|
||||
|
||||
// there's already a key at the end, delete this one
|
||||
if (end[node->type])
|
||||
{
|
||||
prev->next = node->next;
|
||||
free (node);
|
||||
node = prev;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
node->time += time;
|
||||
if (node->time >= last)
|
||||
{
|
||||
node->time = last;
|
||||
end[node->type] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Object::RemoveTime (unsigned short start, bool animation, unsigned short time)
|
||||
{
|
||||
LC_OBJECT_KEY *node, *prev = NULL;
|
||||
|
||||
if (animation)
|
||||
node = m_pAnimationKeys;
|
||||
else
|
||||
node = m_pInstructionKeys;
|
||||
|
||||
for (; node != NULL; prev = node, node = node->next)
|
||||
{
|
||||
// skip everything before the start time
|
||||
if ((node->time < start) || (node->time == 1))
|
||||
continue;
|
||||
|
||||
if (node->time < (start + time))
|
||||
{
|
||||
// delete this key
|
||||
prev->next = node->next;
|
||||
free (node);
|
||||
node = prev;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
node->time -= time;
|
||||
if (node->time < 1)
|
||||
node->time = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// BoundingBox stuff
|
||||
|
||||
// Find the distance from the object to the beginning of the "click line".
|
||||
double Object::BoundingBoxIntersectDist (LC_CLICKLINE* pLine) const
|
||||
{
|
||||
double x, y, z;
|
||||
|
||||
if (BoundingBoxIntersectionbyLine (pLine->a1, pLine->b1, pLine->c1, pLine->a2, pLine->b2, pLine->c2, &x, &y, &z))
|
||||
return (float)sqrt ((pLine->a1-x)*(pLine->a1-x)+(pLine->b1-y)*(pLine->b1-y)+(pLine->c1-z)*(pLine->c1-z));
|
||||
|
||||
return DBL_MAX;
|
||||
}
|
||||
|
||||
// Returns TRUE if the specified point is inside the bounding box of this object.
|
||||
bool Object::BoundingBoxPointInside(double x, double y, double z) const
|
||||
{
|
||||
int i = 0;
|
||||
while (i < 6 && ((m_fBoxPlanes[0][i]*x + m_fBoxPlanes[1][i]*y +
|
||||
m_fBoxPlanes[2][i]*z + m_fBoxPlanes[3][i]) <= 0.001))
|
||||
i++;
|
||||
return (i == 6);
|
||||
}
|
||||
|
||||
// Returns TRUE if the line is intersecting any of the planes of the bounding
|
||||
// box and if this point is also inside this bounding box.
|
||||
bool Object::BoundingBoxIntersectionbyLine (double a1, double b1, double c1, double a2, double b2,
|
||||
double c2, double *x, double *y, double *z) const
|
||||
{
|
||||
double curr_t = DBL_MAX;
|
||||
double t, t1, t2;
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
t1 = (m_fBoxPlanes[0][i]*a1 + m_fBoxPlanes[1][i]*b1 + m_fBoxPlanes[2][i]*c1 + m_fBoxPlanes[3][i]);
|
||||
t2 = (m_fBoxPlanes[0][i]*a2 + m_fBoxPlanes[1][i]*b2 + m_fBoxPlanes[2][i]*c2);
|
||||
|
||||
if (t1!=0 && t2!=0)
|
||||
{
|
||||
t = -( t1 / t2 );
|
||||
if (t>=0)
|
||||
{
|
||||
*x=a1+a2*t;
|
||||
*y=b1+b2*t;
|
||||
*z=c1+c2*t;
|
||||
|
||||
if (BoundingBoxPointInside(*x,*y,*z))
|
||||
if (t < curr_t)
|
||||
curr_t = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (curr_t != DBL_MAX)
|
||||
{
|
||||
*x=a1+a2*curr_t;
|
||||
*y=b1+b2*curr_t;
|
||||
*z=c1+c2*curr_t;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// For pieces
|
||||
void Object::BoundingBoxCalculate (Matrix *mat, float Dimensions[6])
|
||||
{
|
||||
// BASE TOP
|
||||
// 1------3 .------4 ^ X
|
||||
// | | | | |
|
||||
// | | | | | Y
|
||||
// 0------. 2------5 .--->
|
||||
|
||||
float pts[18] = {
|
||||
Dimensions[0], Dimensions[1], Dimensions[5],
|
||||
Dimensions[3], Dimensions[1], Dimensions[5],
|
||||
Dimensions[0], Dimensions[1], Dimensions[2],
|
||||
Dimensions[3], Dimensions[4], Dimensions[5],
|
||||
Dimensions[3], Dimensions[4], Dimensions[2],
|
||||
Dimensions[0], Dimensions[4], Dimensions[2] };
|
||||
|
||||
mat->TransformPoints(pts, 6);
|
||||
|
||||
GetPolyCoeffs (pts[3], pts[4], pts[5], pts[0], pts[1], pts[2], pts[6], pts[7], pts[8],
|
||||
&m_fBoxPlanes[0][0], &m_fBoxPlanes[1][0], &m_fBoxPlanes[2][0], &m_fBoxPlanes[3][0]); //1,0,2
|
||||
GetPolyCoeffs (pts[9], pts[10],pts[11], pts[12],pts[13],pts[14], pts[15],pts[16],pts[17],
|
||||
&m_fBoxPlanes[0][1], &m_fBoxPlanes[1][1], &m_fBoxPlanes[2][1], &m_fBoxPlanes[3][1]); //3,4,5
|
||||
GetPolyCoeffs (pts[15],pts[16],pts[17], pts[6], pts[7], pts[8], pts[0], pts[1], pts[2],
|
||||
&m_fBoxPlanes[0][2], &m_fBoxPlanes[1][2], &m_fBoxPlanes[2][2], &m_fBoxPlanes[3][2]); //5,2,0
|
||||
GetPolyCoeffs (pts[12],pts[13],pts[14], pts[9], pts[10],pts[11], pts[3], pts[4], pts[5],
|
||||
&m_fBoxPlanes[0][3], &m_fBoxPlanes[1][3], &m_fBoxPlanes[2][3], &m_fBoxPlanes[3][3]); //4,3,1
|
||||
GetPolyCoeffs (pts[6], pts[7], pts[8], pts[15],pts[16],pts[17], pts[12],pts[13],pts[14],
|
||||
&m_fBoxPlanes[0][4], &m_fBoxPlanes[1][4], &m_fBoxPlanes[2][4], &m_fBoxPlanes[3][4]); //2,5,4
|
||||
GetPolyCoeffs (pts[0], pts[1], pts[2], pts[3], pts[4], pts[5], pts[9], pts[10],pts[11],
|
||||
&m_fBoxPlanes[0][5], &m_fBoxPlanes[1][5], &m_fBoxPlanes[2][5], &m_fBoxPlanes[3][5]); //0,1,3
|
||||
}
|
||||
|
||||
// Cameras
|
||||
void Object::BoundingBoxCalculate (Matrix *mat)
|
||||
{
|
||||
float normals[6][3] = {
|
||||
{ 1,0,0 }, { 0,1,0 }, { 0,0,1 },
|
||||
{ -1,0,0 }, { 0,-1,0 }, { 0,0,-1 } };
|
||||
float x,y,z,dist;
|
||||
|
||||
if (IsCamera ())
|
||||
dist = 0.3f;
|
||||
else
|
||||
dist = 0.2f;
|
||||
|
||||
mat->GetTranslation(&x,&y,&z);
|
||||
mat->SetTranslation(0,0,0);
|
||||
mat->TransformPoints(&normals[0][0], 6);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_fBoxPlanes[0][i] = normals[i][0];
|
||||
m_fBoxPlanes[1][i] = normals[i][1];
|
||||
m_fBoxPlanes[2][i] = normals[i][2];
|
||||
|
||||
float pt[3];
|
||||
pt[0] = dist*normals[i][0] + x;
|
||||
pt[1] = dist*normals[i][1] + y;
|
||||
pt[2] = dist*normals[i][2] + z;
|
||||
|
||||
m_fBoxPlanes[3][i] = -(pt[0]*normals[i][0]+pt[1]*normals[i][1]+pt[2]*normals[i][2]);
|
||||
}
|
||||
}
|
||||
|
||||
// Light
|
||||
void Object::BoundingBoxCalculate (float pos[3])
|
||||
{
|
||||
float pts[18] = {
|
||||
0.3f+pos[0], 0.3f+pos[1], -0.3f+pos[2],
|
||||
-0.3f+pos[0], 0.3f+pos[1], -0.3f+pos[2],
|
||||
0.3f+pos[0], 0.3f+pos[1], 0.3f+pos[2],
|
||||
-0.3f+pos[0], -0.3f+pos[1], -0.3f+pos[2],
|
||||
-0.3f+pos[0], -0.3f+pos[1], 0.3f+pos[2],
|
||||
0.3f+pos[0], -0.3f+pos[1], 0.3f+pos[2] };
|
||||
|
||||
GetPolyCoeffs (pts[3], pts[4], pts[5], pts[0], pts[1], pts[2], pts[6], pts[7], pts[8],
|
||||
&m_fBoxPlanes[0][0], &m_fBoxPlanes[1][0], &m_fBoxPlanes[2][0], &m_fBoxPlanes[3][0]); //1,0,2
|
||||
GetPolyCoeffs (pts[9], pts[10],pts[11], pts[12],pts[13],pts[14], pts[15],pts[16],pts[17],
|
||||
&m_fBoxPlanes[0][1], &m_fBoxPlanes[1][1], &m_fBoxPlanes[2][1], &m_fBoxPlanes[3][1]); //3,4,5
|
||||
GetPolyCoeffs (pts[15],pts[16],pts[17], pts[6], pts[7], pts[8], pts[0], pts[1], pts[2],
|
||||
&m_fBoxPlanes[0][2], &m_fBoxPlanes[1][2], &m_fBoxPlanes[2][2], &m_fBoxPlanes[3][2]); //5,2,0
|
||||
GetPolyCoeffs (pts[12],pts[13],pts[14], pts[9], pts[10],pts[11], pts[3], pts[4], pts[5],
|
||||
&m_fBoxPlanes[0][3], &m_fBoxPlanes[1][3], &m_fBoxPlanes[2][3], &m_fBoxPlanes[3][3]); //4,3,1
|
||||
GetPolyCoeffs (pts[6], pts[7], pts[8], pts[15],pts[16],pts[17], pts[12],pts[13],pts[14],
|
||||
&m_fBoxPlanes[0][4], &m_fBoxPlanes[1][4], &m_fBoxPlanes[2][4], &m_fBoxPlanes[3][4]); //2,5,4
|
||||
GetPolyCoeffs (pts[0], pts[1], pts[2], pts[3], pts[4], pts[5], pts[9], pts[10],pts[11],
|
||||
&m_fBoxPlanes[0][5], &m_fBoxPlanes[1][5], &m_fBoxPlanes[2][5], &m_fBoxPlanes[3][5]); //0,1,3
|
||||
}
|
||||
|
213
common/object.h
Executable file
213
common/object.h
Executable file
|
@ -0,0 +1,213 @@
|
|||
#ifndef _OBJECT_H_
|
||||
#define _OBJECT_H_
|
||||
|
||||
class File;
|
||||
class Matrix;
|
||||
class Object;
|
||||
/*
|
||||
#define LC_OBJECT_NAME_LEN 80
|
||||
#define LC_OBJECT_HIDDEN 0x01
|
||||
#define LC_OBJECT_SELECTED 0x02
|
||||
#define LC_OBJECT_FOCUSED 0x04
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_OBJECT_PIECE,
|
||||
LC_OBJECT_CAMERA,
|
||||
LC_OBJECT_CAMERA_TARGET,
|
||||
LC_OBJECT_LIGHT,
|
||||
LC_OBJECT_LIGHT_TARGET,
|
||||
LC_OBJECT_CURVE,
|
||||
LC_OBJECT_CURVE_POINT,
|
||||
// LC_OBJECT_GROUP,
|
||||
// LC_OBJECT_GROUP_PIVOT,
|
||||
} LC_OBJECT_TYPE;
|
||||
|
||||
// key handling
|
||||
typedef struct LC_OBJECT_KEY
|
||||
{
|
||||
unsigned short time;
|
||||
float param[4];
|
||||
unsigned char type;
|
||||
LC_OBJECT_KEY* next;
|
||||
} LC_OBJECT_KEY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *description;
|
||||
unsigned char size; // number of floats
|
||||
unsigned char type;
|
||||
} LC_OBJECT_KEY_INFO;
|
||||
|
||||
// rendering parameters
|
||||
typedef struct
|
||||
{
|
||||
bool lighting;
|
||||
bool edges;
|
||||
float fLineWidth;
|
||||
|
||||
unsigned char lastcolor;
|
||||
bool transparent;
|
||||
} LC_RENDER_INFO;
|
||||
|
||||
// Callback "closure" struct, used to make the necessary parameters known to
|
||||
// the callback function.
|
||||
typedef struct LC_CLICKLINE
|
||||
{
|
||||
float a1, b1, c1;
|
||||
float a2, b2, c2;
|
||||
float mindist;
|
||||
Object *pClosest;
|
||||
|
||||
double PointDistance (float *point);
|
||||
|
||||
} LC_CLICKLINE;
|
||||
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
Object (LC_OBJECT_TYPE nType);
|
||||
virtual ~Object ();
|
||||
|
||||
public:
|
||||
// Move the object.
|
||||
virtual void Move(unsigned short nTime, bool bAnimation, bool bAddKey, float dx, float dy, float dz) = 0;
|
||||
|
||||
// Check if the object intersects the ray.
|
||||
virtual void MinIntersectDist(LC_CLICKLINE* pLine) = 0;
|
||||
|
||||
// bSelecting is the action (add/remove), bFocus means "add focus if selecting"
|
||||
// or "remove focus only if deselecting", bMultiple = Ctrl key is down
|
||||
virtual void Select(bool bSelecting, bool bFocus, bool bMultiple) = 0;
|
||||
|
||||
// Check if the object intersects the volume specified by a given set of planes.
|
||||
virtual bool IntersectsVolume(const class Vector4* Planes, int NumPlanes) = 0;
|
||||
|
||||
|
||||
/*
|
||||
virtual void UpdatePosition (unsigned short nTime, bool bAnimation) = 0;
|
||||
virtual void CompareBoundingBox (float *box) { };
|
||||
virtual void Render (LC_RENDER_INFO* pInfo) = 0;
|
||||
|
||||
// Query functions
|
||||
virtual bool IsSelected () const
|
||||
{ return (m_nState & LC_OBJECT_SELECTED) != 0; };
|
||||
virtual bool IsFocused () const
|
||||
{ return (m_nState & LC_OBJECT_FOCUSED) != 0; };
|
||||
virtual bool IsVisible (unsigned short nTime, bool bAnimation) const
|
||||
{ return (m_nState & LC_OBJECT_HIDDEN) == 0; }
|
||||
const char* GetName() const
|
||||
{ return m_strName; }
|
||||
|
||||
|
||||
// State change, most classes will have to replace these functions
|
||||
virtual void SetSelection (bool bSelect, void *pParam = NULL)
|
||||
{
|
||||
if (bSelect)
|
||||
m_nState |= LC_OBJECT_SELECTED;
|
||||
else
|
||||
m_nState &= ~(LC_OBJECT_SELECTED | LC_OBJECT_FOCUSED);
|
||||
};
|
||||
virtual void SetFocus (bool bFocus, void *pParam = NULL)
|
||||
{
|
||||
if (bFocus)
|
||||
m_nState |= (LC_OBJECT_SELECTED | LC_OBJECT_FOCUSED);
|
||||
else
|
||||
m_nState &= ~LC_OBJECT_FOCUSED;
|
||||
};
|
||||
virtual void SetVisible (bool bVisible)
|
||||
{
|
||||
if (bVisible)
|
||||
m_nState &= ~LC_OBJECT_HIDDEN;
|
||||
else
|
||||
{
|
||||
m_nState |= LC_OBJECT_HIDDEN;
|
||||
SetSelection (false, NULL);
|
||||
}
|
||||
}
|
||||
virtual bool SetColor (int nColor)
|
||||
{ return false; };
|
||||
*/
|
||||
|
||||
// determine the object type
|
||||
bool IsPiece () const
|
||||
{ return m_nObjectType == LC_OBJECT_PIECE; }
|
||||
bool IsCamera () const
|
||||
{ return m_nObjectType == LC_OBJECT_CAMERA; }
|
||||
bool IsLight () const
|
||||
{ return m_nObjectType == LC_OBJECT_LIGHT; }
|
||||
bool IsCurve () const
|
||||
{ return m_nObjectType == LC_OBJECT_CURVE; }
|
||||
|
||||
LC_OBJECT_TYPE GetType () const
|
||||
{ return m_nObjectType; }
|
||||
|
||||
virtual const char* GetName() const = 0;
|
||||
/*
|
||||
// For linked lists
|
||||
Object* m_pNext;
|
||||
Object* m_pNextRender;
|
||||
Object* m_pParent;
|
||||
|
||||
Object* GetTopAncestor () const
|
||||
{ return m_pParent ? m_pParent->GetTopAncestor () : this; }
|
||||
*/
|
||||
|
||||
protected:
|
||||
// Str m_strName;
|
||||
// unsigned char m_nState;
|
||||
|
||||
virtual bool FileLoad (File& file);
|
||||
virtual void FileSave (File& file) const;
|
||||
|
||||
|
||||
// Key handling stuff
|
||||
public:
|
||||
void CalculateSingleKey (unsigned short nTime, bool bAnimation, int keytype, float *value) const;
|
||||
void ChangeKey (unsigned short time, bool animation, bool addkey, const float *param, unsigned char keytype);
|
||||
virtual void InsertTime (unsigned short start, bool animation, unsigned short time);
|
||||
virtual void RemoveTime (unsigned short start, bool animation, unsigned short time);
|
||||
|
||||
int GetKeyTypeCount () const
|
||||
{ return m_nKeyInfoCount; }
|
||||
const LC_OBJECT_KEY_INFO* GetKeyTypeInfo (int index) const
|
||||
{ return &m_pKeyInfo[index]; };
|
||||
const float* GetKeyTypeValue (int index) const
|
||||
{ return m_pKeyValues[index]; };
|
||||
|
||||
protected:
|
||||
void RegisterKeys (float *values[], LC_OBJECT_KEY_INFO* info, int count);
|
||||
void CalculateKeys (unsigned short nTime, bool bAnimation);
|
||||
|
||||
private:
|
||||
void RemoveKeys ();
|
||||
|
||||
LC_OBJECT_KEY* m_pAnimationKeys;
|
||||
LC_OBJECT_KEY* m_pInstructionKeys;
|
||||
float **m_pKeyValues;
|
||||
|
||||
LC_OBJECT_KEY_INFO *m_pKeyInfo;
|
||||
int m_nKeyInfoCount;
|
||||
|
||||
|
||||
// Bounding box stuff
|
||||
protected:
|
||||
double BoundingBoxIntersectDist (LC_CLICKLINE* pLine) const;
|
||||
void BoundingBoxCalculate (float pos[3]);
|
||||
void BoundingBoxCalculate (Matrix *mat);
|
||||
void BoundingBoxCalculate (Matrix *mat, float Dimensions[6]);
|
||||
|
||||
private:
|
||||
bool BoundingBoxIntersectionbyLine (double a1, double b1, double c1, double a2, double b2, double c2,
|
||||
double *x, double *y, double *z) const;
|
||||
bool BoundingBoxPointInside (double x, double y, double z) const;
|
||||
float m_fBoxPlanes[4][6];
|
||||
|
||||
|
||||
// Object type
|
||||
private:
|
||||
LC_OBJECT_TYPE m_nObjectType;
|
||||
};
|
||||
|
||||
#endif
|
1549
common/opengl.cpp
Executable file
1549
common/opengl.cpp
Executable file
File diff suppressed because it is too large
Load diff
1274
common/opengl.h
Executable file
1274
common/opengl.h
Executable file
File diff suppressed because it is too large
Load diff
1883
common/piece.cpp
Normal file
1883
common/piece.cpp
Normal file
File diff suppressed because it is too large
Load diff
155
common/piece.h
Normal file
155
common/piece.h
Normal file
|
@ -0,0 +1,155 @@
|
|||
#ifndef _PIECE_H_
|
||||
#define _PIECE_H_
|
||||
|
||||
class File;
|
||||
class Piece;
|
||||
class Group;
|
||||
class PieceInfo;
|
||||
|
||||
#include "object.h"
|
||||
#include "globals.h"
|
||||
#include "typedefs.h"
|
||||
#include "defines.h"
|
||||
|
||||
#define LC_PIECE_HIDDEN 0x01
|
||||
#define LC_PIECE_SELECTED 0x02
|
||||
#define LC_PIECE_FOCUSED 0x04
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_PK_POSITION,
|
||||
LC_PK_ROTATION,
|
||||
LC_PK_COUNT
|
||||
} LC_PK_TYPES;
|
||||
|
||||
class Piece : public Object
|
||||
{
|
||||
public:
|
||||
Piece (PieceInfo* pPieceInfo);
|
||||
~Piece ();
|
||||
|
||||
void Select (bool bSelecting, bool bFocus, bool bMultiple);
|
||||
virtual void InsertTime (unsigned short start, bool animation, unsigned short time);
|
||||
virtual void RemoveTime (unsigned short start, bool animation, unsigned short time);
|
||||
virtual bool IntersectsVolume(const Vector4* Planes, int NumPlanes);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Piece* m_pNext;
|
||||
Piece* m_pLink;
|
||||
|
||||
void Hide()
|
||||
{ m_nState = LC_PIECE_HIDDEN; }
|
||||
void UnHide()
|
||||
{ m_nState &= ~LC_PIECE_HIDDEN; }
|
||||
bool IsHidden()
|
||||
{ return (m_nState & LC_PIECE_HIDDEN) != 0; }
|
||||
bool IsSelected()
|
||||
{ return (m_nState & LC_PIECE_SELECTED) != 0; }
|
||||
bool IsFocused()
|
||||
{ return (m_nState & LC_PIECE_FOCUSED) != 0; }
|
||||
|
||||
const char* GetName() const
|
||||
{ return m_strName; };
|
||||
|
||||
void MinIntersectDist(LC_CLICKLINE* pLine);
|
||||
bool IsVisible(unsigned short nTime, bool bAnimation);
|
||||
void Initialize(float x, float y, float z, unsigned char nStep, unsigned short nFrame, unsigned char nColor);
|
||||
void CreateName(Piece* pPiece);
|
||||
void AddConnections(CONNECTION_TYPE* pConnections);
|
||||
void RemoveConnections(CONNECTION_TYPE* pConnections);
|
||||
void CompareBoundingBox(float box[6]);
|
||||
void SetPieceInfo(PieceInfo* pPieceInfo);
|
||||
bool FileLoad(File& file, char* name);
|
||||
void FileSave(File& file, Group* pGroups);
|
||||
|
||||
void CalculateConnections(CONNECTION_TYPE* pConnections, unsigned short nTime, bool bAnimation, bool bForceRebuild, bool bFixOthers);
|
||||
void UpdatePosition(unsigned short nTime, bool bAnimation);
|
||||
void Move(unsigned short nTime, bool bAnimation, bool bAddKey, float dx, float dy, float dz);
|
||||
|
||||
void DoGroup(Group* pGroup);
|
||||
void UnGroup(Group* pGroup);
|
||||
Group* GetTopGroup();
|
||||
void SetGroup(Group* pGroup)
|
||||
{ m_pGroup = pGroup; }
|
||||
Group* GetGroup()
|
||||
{ return m_pGroup; }
|
||||
void SetName(char* name)
|
||||
{ strcpy(m_strName, name); }
|
||||
const char* GetName()
|
||||
{ return m_strName; }
|
||||
const unsigned char GetColor()
|
||||
{ return m_nColor; }
|
||||
void SetColor(unsigned char color)
|
||||
{ m_nColor = color; }
|
||||
PieceInfo* GetPieceInfo()
|
||||
{ return m_pPieceInfo; }
|
||||
void SetStepShow(unsigned char step)
|
||||
{ m_nStepShow = step; }
|
||||
const unsigned char GetStepShow()
|
||||
{ return m_nStepShow; }
|
||||
void SetStepHide(unsigned char step)
|
||||
{ m_nStepHide = step; }
|
||||
const unsigned char GetStepHide()
|
||||
{ return m_nStepHide; }
|
||||
void SetFrameShow(unsigned short frame)
|
||||
{ m_nFrameShow = frame; }
|
||||
const unsigned short GetFrameShow()
|
||||
{ return m_nFrameShow; }
|
||||
void SetFrameHide(unsigned short frame)
|
||||
{ m_nFrameHide = frame; }
|
||||
const unsigned short GetFrameHide()
|
||||
{ return m_nFrameHide; }
|
||||
const float* GetConstPosition()
|
||||
{ return m_fPosition; }
|
||||
inline Vector3 GetPosition() const
|
||||
{ return Vector3(m_fPosition[0], m_fPosition[1], m_fPosition[2]); }
|
||||
void GetPosition (float* position)
|
||||
{ memcpy(position, m_fPosition, sizeof(m_fPosition)); }
|
||||
void GetRotation (float* rotation)
|
||||
{ memcpy(rotation, m_fRotation, sizeof(m_fRotation)); }
|
||||
|
||||
void Render(bool bLighting, bool bEdges, unsigned char* nLastColor, bool* bTrans);
|
||||
void RenderBox(bool bHilite, float fLineWidth);
|
||||
|
||||
inline bool IsTransparent()
|
||||
{
|
||||
if (m_nColor < 14) return false;
|
||||
if (m_nColor > 21) return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
inline void UseTransform()
|
||||
{
|
||||
glTranslatef(m_fPosition[0], m_fPosition[1], m_fPosition[2]);
|
||||
glRotatef(m_fRotation[3], m_fRotation[0], m_fRotation[1], m_fRotation[2]);
|
||||
}
|
||||
*/
|
||||
protected:
|
||||
void BuildDrawInfo();
|
||||
|
||||
// Atributes
|
||||
PieceInfo* m_pPieceInfo;
|
||||
Group* m_pGroup;
|
||||
|
||||
unsigned short m_nFrameShow;
|
||||
unsigned short m_nFrameHide;
|
||||
unsigned char m_nStepShow;
|
||||
unsigned char m_nStepHide;
|
||||
|
||||
unsigned char m_nColor;
|
||||
unsigned char m_nState;
|
||||
char m_strName[81];
|
||||
|
||||
// Temporary variables
|
||||
float m_fPosition[3];
|
||||
float m_fRotation[4];
|
||||
CONNECTION* m_pConnections;
|
||||
void* m_pDrawInfo;
|
||||
};
|
||||
|
||||
|
||||
#endif // _PIECE_H
|
1946
common/pieceinf.cpp
Normal file
1946
common/pieceinf.cpp
Normal file
File diff suppressed because it is too large
Load diff
130
common/pieceinf.h
Normal file
130
common/pieceinf.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
//
|
||||
// pieceinf.h
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _PIECEINF_H_
|
||||
#define _PIECEINF_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#ifndef GLuint
|
||||
#include "opengl.h"
|
||||
#endif
|
||||
#include "algebra.h"
|
||||
|
||||
#define LC_PIECE_COUNT 0x01 // Count this piece in the totals ?
|
||||
#define LC_PIECE_LONGDATA 0x02 // unsigned long/short index
|
||||
#define LC_PIECE_CCW 0x04 // Use back-face culling
|
||||
#define LC_PIECE_SMALL 0x10 // scale = 10000
|
||||
#define LC_PIECE_MEDIUM 0x20 // scale = 1000 (otherwise = 100)
|
||||
#define LC_PIECE_LONGDATA_RUNTIME 0x40 // If the original data is 16 bits but we expanded to 32 bits
|
||||
|
||||
#define LC_PIECE_NAME_LEN 256
|
||||
|
||||
class File;
|
||||
class Texture;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char type;
|
||||
float center[3];
|
||||
float normal[3];
|
||||
} CONNECTIONINFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short connections[6];
|
||||
void* drawinfo;
|
||||
} DRAWGROUP;
|
||||
|
||||
typedef struct TEXTURE
|
||||
{
|
||||
Texture* texture;
|
||||
unsigned char color;
|
||||
float vertex[4][3];
|
||||
float coords[4][2];
|
||||
} TEXTURE;
|
||||
|
||||
unsigned char ConvertColor(int c);
|
||||
|
||||
class PieceInfo
|
||||
{
|
||||
public:
|
||||
PieceInfo ();
|
||||
~PieceInfo ();
|
||||
|
||||
bool IsPatterned() const
|
||||
{
|
||||
const char* Name = m_strName;
|
||||
|
||||
while (*Name)
|
||||
{
|
||||
if (*Name < '0' || *Name > '9')
|
||||
break;
|
||||
|
||||
Name++;
|
||||
}
|
||||
|
||||
if (*Name == 'P')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsSubPiece() const
|
||||
{
|
||||
return (m_strDescription[0] == '~');
|
||||
}
|
||||
|
||||
Vector3 GetCenter() const
|
||||
{
|
||||
return Vector3((m_fDimensions[0] + m_fDimensions[3]) * 0.5f,
|
||||
(m_fDimensions[1] + m_fDimensions[4]) * 0.5f,
|
||||
(m_fDimensions[2] + m_fDimensions[5]) * 0.5f);
|
||||
}
|
||||
|
||||
// Operations
|
||||
void ZoomExtents(float Fov, float Aspect, float* EyePos = NULL) const;
|
||||
void RenderOnce(int nColor);
|
||||
void RenderPiece(int nColor);
|
||||
void WriteWavefront(FILE* file, unsigned char color, unsigned long* start);
|
||||
|
||||
// Implementation
|
||||
GLuint GetBoxDisplayList()
|
||||
{
|
||||
if (!m_nBoxList)
|
||||
CreateBoxDisplayList();
|
||||
return m_nBoxList;
|
||||
};
|
||||
void LoadIndex(File& file);
|
||||
void AddRef();
|
||||
void DeRef();
|
||||
|
||||
public:
|
||||
// Attributes
|
||||
char m_strName[LC_PIECE_NAME_LEN];
|
||||
char m_strDescription[65];
|
||||
float m_fDimensions[6];
|
||||
unsigned long m_nOffset;
|
||||
unsigned long m_nSize;
|
||||
|
||||
// Nobody should change these
|
||||
unsigned char m_nFlags;
|
||||
unsigned long m_nVertexCount;
|
||||
float* m_fVertexArray;
|
||||
unsigned short m_nConnectionCount;
|
||||
CONNECTIONINFO* m_pConnections;
|
||||
unsigned short m_nGroupCount;
|
||||
DRAWGROUP* m_pGroups;
|
||||
unsigned char m_nTextureCount;
|
||||
TEXTURE* m_pTextures;
|
||||
|
||||
protected:
|
||||
int m_nRef;
|
||||
GLuint m_nBoxList;
|
||||
|
||||
void LoadInformation();
|
||||
void FreeInformation();
|
||||
void CreateBoxDisplayList();
|
||||
};
|
||||
|
||||
#endif // _PIECEINF_H_
|
185
common/preview.cpp
Normal file
185
common/preview.cpp
Normal file
|
@ -0,0 +1,185 @@
|
|||
//
|
||||
// Piece Preview window
|
||||
//
|
||||
|
||||
#include "preview.h"
|
||||
#include "globals.h"
|
||||
#include "project.h"
|
||||
#include "pieceinf.h"
|
||||
#include "system.h"
|
||||
#include "lc_application.h"
|
||||
|
||||
PiecePreview::PiecePreview(GLWindow *share)
|
||||
: GLWindow(share)
|
||||
{
|
||||
m_PieceInfo = NULL;
|
||||
m_RotateX = 60.0f;
|
||||
m_RotateZ = 225.0f;
|
||||
m_Distance = 10.0f;
|
||||
m_AutoZoom = true;
|
||||
m_Tracking = LC_TRACK_NONE;
|
||||
}
|
||||
|
||||
PiecePreview::~PiecePreview()
|
||||
{
|
||||
}
|
||||
|
||||
void PiecePreview::OnDraw()
|
||||
{
|
||||
if (m_PieceInfo == NULL)
|
||||
return;
|
||||
|
||||
if (!MakeCurrent())
|
||||
return;
|
||||
|
||||
glEnable(GL_LIGHT0);
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(0.5f, 0.1f);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
glDisable(GL_DITHER);
|
||||
glShadeModel(GL_FLAT);
|
||||
|
||||
float aspect = (float)m_nWidth/(float)m_nHeight;
|
||||
glViewport(0, 0, m_nWidth, m_nHeight);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(30.0f, aspect, 1.0f, 100.0f);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
Vector3 Eye(0, 0, 1.0f);
|
||||
Matrix33 Rot;
|
||||
|
||||
Rot.CreateFromAxisAngle(Vector3(1, 0, 0), -m_RotateX * LC_DTOR);
|
||||
Eye = Mul(Eye, Rot);
|
||||
|
||||
Rot.CreateFromAxisAngle(Vector3(0, 0, 1), -m_RotateZ * LC_DTOR);
|
||||
Eye = Mul(Eye, Rot);
|
||||
|
||||
if (m_AutoZoom)
|
||||
{
|
||||
Eye = Eye * 100.0f;
|
||||
m_PieceInfo->ZoomExtents(30.0f, aspect, Eye);
|
||||
|
||||
// Update the new camera distance.
|
||||
Vector3 d = Eye - m_PieceInfo->GetCenter();
|
||||
m_Distance = d.Length();
|
||||
}
|
||||
else
|
||||
{
|
||||
Matrix44 WorldToView;
|
||||
WorldToView.CreateLookAt(Eye * m_Distance, m_PieceInfo->GetCenter(), Vector3(0, 0, 1));
|
||||
glLoadMatrixf(WorldToView);
|
||||
}
|
||||
|
||||
float pos[4] = { 0, 0, 10, 0 }, *bg = lcGetActiveProject()->GetBackgroundColor ();
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, pos);
|
||||
glClearColor(bg[0], bg[1], bg[2], bg[3]);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
m_PieceInfo->RenderPiece(lcGetActiveProject()->GetCurrentColor());
|
||||
|
||||
glFinish();
|
||||
SwapBuffers();
|
||||
}
|
||||
|
||||
void PiecePreview::SetCurrentPiece(PieceInfo *pInfo)
|
||||
{
|
||||
MakeCurrent();
|
||||
|
||||
if (m_PieceInfo != NULL)
|
||||
m_PieceInfo->DeRef();
|
||||
|
||||
m_PieceInfo = pInfo;
|
||||
|
||||
if (m_PieceInfo != NULL)
|
||||
{
|
||||
m_PieceInfo->AddRef();
|
||||
lcGetActiveProject()->SetCurrentPiece(m_PieceInfo);
|
||||
Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
void PiecePreview::OnLeftButtonDown(int x, int y, bool Control, bool Shift)
|
||||
{
|
||||
if (m_Tracking == LC_TRACK_NONE)
|
||||
{
|
||||
m_DownX = x;
|
||||
m_DownY = y;
|
||||
m_Tracking = LC_TRACK_LEFT;
|
||||
CaptureMouse();
|
||||
}
|
||||
}
|
||||
|
||||
void PiecePreview::OnLeftButtonUp(int x, int y, bool Control, bool Shift)
|
||||
{
|
||||
if (m_Tracking == LC_TRACK_LEFT)
|
||||
{
|
||||
m_Tracking = LC_TRACK_NONE;
|
||||
ReleaseMouse();
|
||||
}
|
||||
}
|
||||
|
||||
void PiecePreview::OnLeftButtonDoubleClick(int x, int y, bool Control, bool Shift)
|
||||
{
|
||||
m_AutoZoom = true;
|
||||
Redraw();
|
||||
}
|
||||
|
||||
void PiecePreview::OnRightButtonDown(int x, int y, bool Control, bool Shift)
|
||||
{
|
||||
if (m_Tracking == LC_TRACK_NONE)
|
||||
{
|
||||
m_DownX = x;
|
||||
m_DownY = y;
|
||||
m_Tracking = LC_TRACK_RIGHT;
|
||||
CaptureMouse();
|
||||
}
|
||||
}
|
||||
|
||||
void PiecePreview::OnRightButtonUp(int x, int y, bool Control, bool Shift)
|
||||
{
|
||||
if (m_Tracking == LC_TRACK_RIGHT)
|
||||
{
|
||||
m_Tracking = LC_TRACK_NONE;
|
||||
ReleaseMouse();
|
||||
}
|
||||
}
|
||||
|
||||
void PiecePreview::OnMouseMove(int x, int y, bool Control, bool Shift)
|
||||
{
|
||||
if (m_Tracking == LC_TRACK_LEFT)
|
||||
{
|
||||
// Rotate.
|
||||
m_RotateZ += x - m_DownX;
|
||||
m_RotateX += y - m_DownY;
|
||||
|
||||
if (m_RotateX > 179.5f)
|
||||
m_RotateX = 179.5f;
|
||||
else if (m_RotateX < 0.5f)
|
||||
m_RotateX = 0.5f;
|
||||
|
||||
m_DownX = x;
|
||||
m_DownY = y;
|
||||
|
||||
Redraw();
|
||||
}
|
||||
else if (m_Tracking == LC_TRACK_RIGHT)
|
||||
{
|
||||
// Zoom.
|
||||
m_Distance += (float)(y - m_DownY) * 0.2f;
|
||||
m_AutoZoom = false;
|
||||
|
||||
if (m_Distance < 0.5f)
|
||||
m_Distance = 0.5f;
|
||||
|
||||
m_DownX = x;
|
||||
m_DownY = y;
|
||||
|
||||
Redraw();
|
||||
}
|
||||
}
|
42
common/preview.h
Normal file
42
common/preview.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef _PREVIEW_H_
|
||||
#define _PREVIEW_H_
|
||||
|
||||
#include "glwindow.h"
|
||||
|
||||
class PieceInfo;
|
||||
|
||||
class PiecePreview : public GLWindow
|
||||
{
|
||||
public:
|
||||
PiecePreview(GLWindow *share);
|
||||
virtual ~PiecePreview();
|
||||
|
||||
void OnDraw();
|
||||
void OnLeftButtonDown(int x, int y, bool Control, bool Shift);
|
||||
void OnLeftButtonUp(int x, int y, bool Control, bool Shift);
|
||||
void OnLeftButtonDoubleClick(int x, int y, bool Control, bool Shift);
|
||||
void OnRightButtonDown(int x, int y, bool Control, bool Shift);
|
||||
void OnRightButtonUp(int x, int y, bool Control, bool Shift);
|
||||
void OnMouseMove(int x, int y, bool Control, bool Shift);
|
||||
|
||||
PieceInfo* GetCurrentPiece() const
|
||||
{ return m_PieceInfo; }
|
||||
void SetCurrentPiece(PieceInfo* Info);
|
||||
|
||||
protected:
|
||||
PieceInfo* m_PieceInfo;
|
||||
|
||||
// Mouse tracking.
|
||||
int m_Tracking;
|
||||
int m_DownX;
|
||||
int m_DownY;
|
||||
|
||||
// Current camera settings.
|
||||
float m_Distance;
|
||||
float m_RotateX;
|
||||
float m_RotateZ;
|
||||
bool m_AutoZoom;
|
||||
};
|
||||
|
||||
#endif // _PREVIEW_H_
|
||||
|
9338
common/project.cpp
Normal file
9338
common/project.cpp
Normal file
File diff suppressed because it is too large
Load diff
313
common/project.h
Normal file
313
common/project.h
Normal file
|
@ -0,0 +1,313 @@
|
|||
#ifndef _PROJECT_H_
|
||||
#define _PROJECT_H_
|
||||
|
||||
#include "object.h"
|
||||
#include "defines.h"
|
||||
#include "typedefs.h"
|
||||
#include "opengl.h"
|
||||
#include "array.h"
|
||||
#include "algebra.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_TRACK_NONE, LC_TRACK_START_LEFT, LC_TRACK_LEFT,
|
||||
LC_TRACK_START_RIGHT, LC_TRACK_RIGHT
|
||||
} LC_MOUSE_TRACK;
|
||||
|
||||
// Mouse control overlays.
|
||||
typedef enum
|
||||
{
|
||||
LC_OVERLAY_XYZ,
|
||||
LC_OVERLAY_X,
|
||||
LC_OVERLAY_Y,
|
||||
LC_OVERLAY_Z,
|
||||
LC_OVERLAY_XY,
|
||||
LC_OVERLAY_XZ,
|
||||
LC_OVERLAY_YZ
|
||||
} LC_OVERLAY_MODES;
|
||||
|
||||
class Piece;
|
||||
class Camera;
|
||||
class Light;
|
||||
class Group;
|
||||
class Texture;
|
||||
class Terrain;
|
||||
class PieceInfo;
|
||||
class Matrix;
|
||||
class View;
|
||||
class Image;
|
||||
class PiecesLibrary;
|
||||
class TexFont;
|
||||
|
||||
// Undo support
|
||||
|
||||
#include "file.h"
|
||||
|
||||
typedef struct LC_UNDOINFO
|
||||
{
|
||||
FileMem file;
|
||||
char strText[21];
|
||||
LC_UNDOINFO* pNext;
|
||||
LC_UNDOINFO() { pNext = NULL; };
|
||||
} LC_UNDOINFO;
|
||||
|
||||
class Project
|
||||
{
|
||||
public:
|
||||
// Constructors
|
||||
Project();
|
||||
~Project();
|
||||
|
||||
// Attributes
|
||||
public:
|
||||
bool IsModified()
|
||||
{ return m_bModified; }
|
||||
void SetModifiedFlag(bool bModified)
|
||||
{ m_bModified = bModified; }
|
||||
|
||||
// Access to protected members
|
||||
unsigned char GetLastStep();
|
||||
bool IsAnimation()
|
||||
{ return m_bAnimation; }
|
||||
void SetAnimation(bool Anim)
|
||||
{ m_bAnimation = Anim; } // only to be called from lcApplication::Initialize()
|
||||
unsigned short GetCurrentTime ()
|
||||
{ return m_bAnimation ? m_nCurFrame : m_nCurStep; }
|
||||
void SetCurrentPiece(PieceInfo* pInfo)
|
||||
{ m_pCurPiece = pInfo; }
|
||||
int GetCurrentColor () const
|
||||
{ return m_nCurColor; }
|
||||
float* GetBackgroundColor()
|
||||
{ return m_fBackground; }
|
||||
unsigned char GetAction() const
|
||||
{ return m_nCurAction; }
|
||||
int GetOverlayMode() const
|
||||
{ return m_OverlayMode; }
|
||||
void GetSnapIndex(int* SnapXY, int* SnapZ) const;
|
||||
void GetSnapDistance(float* SnapXY, float* SnapZ) const;
|
||||
void GetSnapDistanceText(char* SnapXY, char* SnapZ) const;
|
||||
Camera* GetCamera(int i);
|
||||
void GetTimeRange(int* from, int* to)
|
||||
{
|
||||
*from = m_bAnimation ? m_nCurFrame : m_nCurStep;
|
||||
*to = m_bAnimation ? m_nTotalFrames : 255;
|
||||
}
|
||||
unsigned short GetTotalFrames () const
|
||||
{ return m_nTotalFrames; }
|
||||
|
||||
void ConvertToUserUnits(Vector3& Value) const;
|
||||
void ConvertFromUserUnits(Vector3& Value) const;
|
||||
void GetArrays(Piece** ppPiece, Camera** ppCamera, Light** ppLight)
|
||||
{
|
||||
*ppPiece = m_pPieces;
|
||||
*ppCamera = m_pCameras;
|
||||
*ppLight = m_pLights;
|
||||
}
|
||||
|
||||
void UpdateInterface();
|
||||
void SetPathName (const char* lpszPathName, bool bAddToMRU);
|
||||
void SetTitle (const char* lpszTitle);
|
||||
|
||||
public:
|
||||
// Special notifications
|
||||
void DeleteContents(bool bUndo); // delete doc items etc
|
||||
void LoadDefaults(bool cameras);
|
||||
void BeginPieceDrop(PieceInfo* Info);
|
||||
|
||||
void CreateImages(Image* images, int width, int height, unsigned short from, unsigned short to, bool hilite);
|
||||
void Render(bool bToMemory);
|
||||
void SetViewSize(int cx, int cy);
|
||||
void CheckAutoSave();
|
||||
bool GetSelectionCenter(Vector3& Center) const;
|
||||
bool GetFocusPosition(Vector3& Position) const;
|
||||
Object* GetFocusObject() const;
|
||||
Group* AddGroup (const char* name, Group* pParent, float x, float y, float z);
|
||||
|
||||
void AddView (View* pView);
|
||||
void RemoveView (View* pView);
|
||||
void UpdateAllViews (View* pSender = NULL);
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
// default implementation
|
||||
char m_strTitle[LC_MAXPATH];
|
||||
char m_strPathName[LC_MAXPATH];
|
||||
bool m_bModified; // changed since last saved
|
||||
|
||||
PtrArray<View> m_ViewList;
|
||||
|
||||
char m_strAuthor[101];
|
||||
char m_strDescription[101];
|
||||
char m_strComments[256];
|
||||
|
||||
// Piece library
|
||||
TexFont* m_pScreenFont;
|
||||
|
||||
// Undo support
|
||||
LC_UNDOINFO* m_pUndoList;
|
||||
LC_UNDOINFO* m_pRedoList;
|
||||
bool m_bUndoOriginal;
|
||||
void CheckPoint (const char* text);
|
||||
|
||||
// Objects
|
||||
Piece* m_pPieces;
|
||||
Camera* m_pCameras;
|
||||
Light* m_pLights;
|
||||
Group* m_pGroups;
|
||||
Camera* m_pViewCameras[4];
|
||||
Terrain* m_pTerrain;
|
||||
File* m_pClipboard[10];
|
||||
unsigned char m_nCurClipboard;
|
||||
|
||||
CONNECTION_TYPE m_pConnections[LC_CONNECTIONS];
|
||||
|
||||
void AddPiece(Piece* pPiece);
|
||||
void RemovePiece(Piece* pPiece);
|
||||
bool RemoveSelectedObjects();
|
||||
void GetPieceInsertPosition(Piece* OffsetPiece, Vector3& Position, Vector4& Rotation);
|
||||
void GetPieceInsertPosition(int MouseX, int MouseY, Vector3& Position, Vector4& Orientation);
|
||||
void FindObjectFromPoint(int x, int y, LC_CLICKLINE* pLine, bool PiecesOnly = false);
|
||||
void FindObjectsInBox(float x1, float y1, float x2, float y2, PtrArray<Object>& Objects);
|
||||
void SelectAndFocusNone(bool bFocusOnly);
|
||||
void GetActiveViewportMatrices(Matrix44& ModelView, Matrix44& Projection, int Viewport[4]);
|
||||
void CalculateStep();
|
||||
|
||||
// Movement.
|
||||
bool MoveSelectedObjects(Vector3& Move, Vector3& Remainder, bool Snap);
|
||||
bool RotateSelectedObjects(Vector3& Delta, Vector3& Remainder);
|
||||
void SnapVector(Vector3& Delta) const
|
||||
{
|
||||
Vector3 Dummy;
|
||||
SnapVector(Delta, Dummy);
|
||||
}
|
||||
void SnapVector(Vector3& Delta, Vector3& Leftover) const;
|
||||
void SnapRotationVector(Vector3& Delta, Vector3& Leftover) const;
|
||||
|
||||
// Rendering
|
||||
void RenderScene(bool bShaded, bool bDrawViewports);
|
||||
void RenderViewports(bool bBackground, bool bLines);
|
||||
void RenderOverlays(int Viewport);
|
||||
void RenderBoxes(bool bHilite);
|
||||
void RenderInitialize();
|
||||
void CreateHTMLPieceList(FILE* f, int nStep, bool bImages, const char* ext);
|
||||
|
||||
inline bool IsDrawing()
|
||||
{
|
||||
if (m_bRendering)
|
||||
m_bStopRender = true;
|
||||
return m_bRendering;
|
||||
}
|
||||
|
||||
bool m_bRendering;
|
||||
bool m_bStopRender;
|
||||
File* m_pTrackFile;
|
||||
bool m_bTrackCancel;
|
||||
int m_nTracking;
|
||||
int m_nDownX;
|
||||
int m_nDownY;
|
||||
float m_fTrack[3];
|
||||
int m_nMouse;
|
||||
Vector3 m_MouseSnapLeftover;
|
||||
Vector3 m_MouseTotalDelta;
|
||||
|
||||
int m_OverlayMode;
|
||||
bool m_OverlayActive;
|
||||
float m_OverlayScale[4];
|
||||
Vector3 m_OverlayCenter;
|
||||
Vector3 m_OverlayTrackStart;
|
||||
Vector3 m_OverlayDelta;
|
||||
void MouseUpdateOverlays(int x, int y);
|
||||
void ActivateOverlay();
|
||||
void UpdateOverlayScale();
|
||||
|
||||
void LoadViewportProjection(int Viewport);
|
||||
bool SetActiveViewport(int x, int y);
|
||||
bool StopTracking(bool bAccept);
|
||||
void StartTracking(int mode);
|
||||
void UpdateSelection();
|
||||
void RemoveEmptyGroups();
|
||||
|
||||
public:
|
||||
// Call this functions from each OS
|
||||
void OnLeftButtonDown(int x, int y, bool bControl, bool bShift);
|
||||
void OnLeftButtonUp(int x, int y, bool bControl, bool bShift);
|
||||
void OnLeftButtonDoubleClick(int x, int y, bool bControl, bool bShift);
|
||||
void OnRightButtonDown(int x, int y, bool bControl, bool bShift);
|
||||
void OnRightButtonUp(int x, int y, bool bControl, bool bShift);
|
||||
void OnMouseMove(int x, int y, bool bControl, bool bShift);
|
||||
bool OnKeyDown(char nKey, bool bControl, bool bShift);
|
||||
|
||||
void SetAction(int nAction);
|
||||
void HandleNotify(LC_NOTIFY id, unsigned long param);
|
||||
void HandleCommand(LC_COMMANDS id, unsigned long nParam);
|
||||
void HandleMessage(int Message, void* Data);
|
||||
|
||||
protected:
|
||||
// State variables
|
||||
unsigned char m_nViewportMode;
|
||||
unsigned char m_nActiveViewport;
|
||||
int m_nViewX;
|
||||
int m_nViewY;
|
||||
PieceInfo* m_pCurPiece;
|
||||
PieceInfo* m_PreviousPiece;
|
||||
unsigned char m_nCurColor;
|
||||
unsigned char m_nCurAction;
|
||||
unsigned char m_PreviousAction;
|
||||
bool m_bAnimation;
|
||||
bool m_bAddKeys;
|
||||
unsigned char m_nFPS;
|
||||
unsigned char m_nCurStep;
|
||||
unsigned short m_nCurFrame;
|
||||
unsigned short m_nTotalFrames;
|
||||
|
||||
unsigned long m_nScene;
|
||||
unsigned long m_nDetail;
|
||||
unsigned long m_nSnap;
|
||||
unsigned short m_nMoveSnap;
|
||||
unsigned short m_nAngleSnap;
|
||||
unsigned short m_nGridSize;
|
||||
float m_fLineWidth;
|
||||
float m_fFogDensity;
|
||||
float m_fFogColor[4];
|
||||
float m_fAmbient[4];
|
||||
float m_fBackground[4];
|
||||
float m_fGradient1[3];
|
||||
float m_fGradient2[3];
|
||||
char m_strFooter[256];
|
||||
char m_strHeader[256];
|
||||
|
||||
GLuint m_nGridList;
|
||||
unsigned long m_nAutosave;
|
||||
unsigned long m_nSaveTimer;
|
||||
char m_strModelsPath[LC_MAXPATH];
|
||||
char m_strBackground[LC_MAXPATH];
|
||||
Texture* m_pBackground;
|
||||
|
||||
protected:
|
||||
// File load/save implementation.
|
||||
bool DoSave(char* lpszPathName, bool bReplace);
|
||||
bool DoFileSave();
|
||||
bool FileLoad(File* file, bool bUndo, bool bMerge);
|
||||
void FileSave(File* file, bool bUndo);
|
||||
void FileReadLDraw(File* file, Matrix* prevmat, int* nOk, int DefColor, int* nStep, PtrArray<File>& FileArray);
|
||||
void FileReadMPD(File& MPD, PtrArray<File>& FileArray) const;
|
||||
|
||||
public:
|
||||
// File helpers
|
||||
bool OnNewDocument();
|
||||
bool OnOpenDocument(const char* FileName);
|
||||
bool OpenProject(const char* FileName);
|
||||
bool SaveModified();
|
||||
|
||||
protected:
|
||||
// mail enabling
|
||||
// void OnFileSendMail();
|
||||
// void OnUpdateFileSendMail(CCmdUI* pCmdUI);
|
||||
|
||||
// TODO: Fix ! This is a hack to make things work now
|
||||
friend class CCADView;
|
||||
friend void PrintPiecesThread(void* pv);
|
||||
friend void Export3DStudio();
|
||||
};
|
||||
|
||||
#endif // _PROJECT_H_
|
640
common/quant.cpp
Normal file
640
common/quant.cpp
Normal file
|
@ -0,0 +1,640 @@
|
|||
///////////////////////////////////////
|
||||
// DL1 Quantization
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include "quant.h"
|
||||
|
||||
//#define FAST // improves speed but uses a lot of memory
|
||||
#define QUAL1 // slightly improves quality
|
||||
//#define QUAL2 // slightly improves quality
|
||||
|
||||
//#define DITHER1 // 1-val error diffusion dither
|
||||
#define DITHER2 // 2-val error diffusion dither
|
||||
//#define DITHER4 // 4-val error diffusion dither (Floyd-Steinberg)
|
||||
|
||||
#define DITHER_MAX 20
|
||||
|
||||
static void dlq_finish();
|
||||
static int build_table(unsigned char *image, unsigned long pixels);
|
||||
static void fixheap(unsigned long id);
|
||||
static void reduce_table(int num_colors);
|
||||
static void set_palette(int index, int level);
|
||||
static void closest_color(int index, int level);
|
||||
static int quantize_image(unsigned char *in, unsigned char *out, int width, int height, int dither);
|
||||
static int bestcolor(int r, int g, int b);
|
||||
|
||||
static unsigned char palette[3][256];
|
||||
static CUBE *rgb_table[6];
|
||||
static unsigned short r_offset[256], g_offset[256], b_offset[256];
|
||||
static CLOSEST_INFO c_info;
|
||||
static int tot_colors, pal_index;
|
||||
static unsigned long *squares;
|
||||
static FCUBE *heap = NULL;
|
||||
static short *dl_image = NULL;
|
||||
|
||||
bool dl1quant(unsigned char *inbuf, unsigned char *outbuf, int width, int height, int quant_to, int dither, unsigned char userpal[3][256])
|
||||
{
|
||||
int i;
|
||||
|
||||
// dlq_init
|
||||
for (i = 0; i < 6; i++)
|
||||
rgb_table[i]=NULL;
|
||||
|
||||
tot_colors=0;
|
||||
pal_index=0;
|
||||
|
||||
heap = NULL;
|
||||
dl_image = NULL;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
r_offset[i] = (i & 128) << 7 | (i & 64) << 5 | (i & 32) << 3 |
|
||||
(i & 16) << 1 | (i & 8) >> 1;
|
||||
g_offset[i] = (i & 128) << 6 | (i & 64) << 4 | (i & 32) << 2 |
|
||||
(i & 16) << 0 | (i & 8) >> 2;
|
||||
b_offset[i] = (i & 128) << 5 | (i & 64) << 3 | (i & 32) << 1 |
|
||||
(i & 16) >> 1 | (i & 8) >> 3;
|
||||
}
|
||||
|
||||
c_info.palette_index=0;
|
||||
c_info.red=0;
|
||||
c_info.green=0;
|
||||
c_info.blue=0;
|
||||
c_info.distance=0;
|
||||
|
||||
for (i = (-255); i <= 255; i++)
|
||||
c_info.squares[i+255] = i*i;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
palette[0][i] = 0;
|
||||
palette[1][i] = 0;
|
||||
palette[2][i] = 0;
|
||||
}
|
||||
|
||||
squares = c_info.squares + 255;
|
||||
|
||||
// dlq_start
|
||||
rgb_table[0] = (CUBE*)calloc(sizeof(CUBE), 1);
|
||||
rgb_table[1] = (CUBE*)calloc(sizeof(CUBE), 8);
|
||||
rgb_table[2] = (CUBE*)calloc(sizeof(CUBE), 64);
|
||||
rgb_table[3] = (CUBE*)calloc(sizeof(CUBE), 512);
|
||||
rgb_table[4] = (CUBE*)calloc(sizeof(CUBE), 4096);
|
||||
rgb_table[5] = (CUBE*)calloc(sizeof(CUBE), 32768);
|
||||
|
||||
for (i = 0; i <= 5; i++)
|
||||
if (rgb_table[i] == NULL)
|
||||
{
|
||||
dlq_finish();
|
||||
return false;
|
||||
}
|
||||
|
||||
pal_index = 0;
|
||||
|
||||
if (build_table(inbuf, width*height) == 0)
|
||||
{
|
||||
dlq_finish();
|
||||
return false;
|
||||
}
|
||||
|
||||
reduce_table(quant_to);
|
||||
set_palette(0, 0);
|
||||
|
||||
if (quantize_image(inbuf, outbuf, width, height, dither) == 0)
|
||||
{
|
||||
dlq_finish();
|
||||
return false;
|
||||
}
|
||||
|
||||
dlq_finish();
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
userpal[0][i] = palette[0][i];
|
||||
userpal[1][i] = palette[1][i];
|
||||
userpal[2][i] = palette[2][i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dlq_finish(void)
|
||||
{
|
||||
for (int i = 0;i < 6;i++)
|
||||
{
|
||||
if (rgb_table[i] != NULL)
|
||||
{
|
||||
free(rgb_table[i]);
|
||||
rgb_table[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (heap != NULL)
|
||||
{
|
||||
free(heap);
|
||||
heap = NULL;
|
||||
}
|
||||
|
||||
if (dl_image != NULL)
|
||||
{
|
||||
free(dl_image);
|
||||
dl_image = NULL;
|
||||
}
|
||||
|
||||
memset(&c_info, 0, sizeof(CLOSEST_INFO));
|
||||
|
||||
tot_colors=pal_index=0;
|
||||
}
|
||||
|
||||
// returns 1 on success, 0 on failure
|
||||
static int build_table(unsigned char *image, unsigned long pixels)
|
||||
{
|
||||
unsigned long i = 0, index = 0, cur_count = 0, head = 0, tail = 0;
|
||||
long j = 0;
|
||||
|
||||
heap = (FCUBE *) malloc(sizeof(FCUBE) * 32769);
|
||||
if (heap == NULL)
|
||||
return 0;
|
||||
|
||||
#ifdef FAST
|
||||
dl_image = malloc(sizeof(short) * pixels);
|
||||
if (dl_image == NULL)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < pixels; i++)
|
||||
{
|
||||
#ifdef FAST
|
||||
dl_image[i] = index = r_offset[image[0]] + g_offset[image[1]] + b_offset[image[2]];
|
||||
#else
|
||||
index = r_offset[image[0]] + g_offset[image[1]] + b_offset[image[2]];
|
||||
#endif
|
||||
#ifdef QUAL1
|
||||
rgb_table[5][index].r += image[0];
|
||||
rgb_table[5][index].g += image[1];
|
||||
rgb_table[5][index].b += image[2];
|
||||
#endif
|
||||
rgb_table[5][index].pixel_count++;
|
||||
image += 3;
|
||||
}
|
||||
|
||||
tot_colors = 0;
|
||||
for (i = 0; i < 32768; i++)
|
||||
{
|
||||
cur_count = rgb_table[5][i].pixel_count;
|
||||
if (cur_count)
|
||||
{
|
||||
heap[++tot_colors].level = 5;
|
||||
heap[tot_colors].index = (unsigned short)i;
|
||||
rgb_table[5][i].pixels_in_cube = cur_count;
|
||||
#ifndef QUAL1
|
||||
rgb_table[5][i].r = cur_count * (((i & 0x4000) >> 7 |
|
||||
(i & 0x0800) >> 5 | (i & 0x0100) >> 3 |
|
||||
(i & 0x0020) >> 1 | (i & 0x0004) << 1) + 4);
|
||||
rgb_table[5][i].g = cur_count * (((i & 0x2000) >> 6 |
|
||||
(i & 0x0400) >> 4 | (i & 0x0080) >> 2 |
|
||||
(i & 0x0010) >> 0 | (i & 0x0002) << 2) + 4);
|
||||
rgb_table[5][i].b = cur_count * (((i & 0x1000) >> 5 |
|
||||
(i & 0x0200) >> 3 | (i & 0x0040) >> 1 |
|
||||
(i & 0x0008) << 1 | (i & 0x0001) << 3) + 4);
|
||||
#endif
|
||||
head = i;
|
||||
for (j = 4; j >= 0; j--)
|
||||
{
|
||||
tail = head & 0x7;
|
||||
head >>= 3;
|
||||
rgb_table[j][head].pixels_in_cube += cur_count;
|
||||
rgb_table[j][head].children |= 1 << tail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = tot_colors; i > 0; i--)
|
||||
fixheap(i);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void fixheap(unsigned long id)
|
||||
{
|
||||
unsigned char thres_level = heap[id].level;
|
||||
unsigned long thres_index = heap[id].index, index = 0;
|
||||
unsigned long half_totc = tot_colors >> 1;
|
||||
unsigned long thres_val = rgb_table[thres_level][thres_index].pixels_in_cube;
|
||||
|
||||
while (id <= half_totc)
|
||||
{
|
||||
index = id << 1;
|
||||
|
||||
if (index < (unsigned long)tot_colors)
|
||||
if (rgb_table[heap[index].level][heap[index].index].pixels_in_cube
|
||||
> rgb_table[heap[index+1].level][heap[index+1].index].pixels_in_cube)
|
||||
index++;
|
||||
|
||||
if (thres_val <= rgb_table[heap[index].level][heap[index].index].pixels_in_cube)
|
||||
break;
|
||||
else {
|
||||
heap[id] = heap[index];
|
||||
id = index;
|
||||
}
|
||||
}
|
||||
heap[id].level = thres_level;
|
||||
heap[id].index = (unsigned short)thres_index;
|
||||
}
|
||||
|
||||
static void reduce_table(int num_colors)
|
||||
{
|
||||
while (tot_colors > num_colors)
|
||||
{
|
||||
unsigned char tmp_level = heap[1].level, t_level = (tmp_level - 1) > 0 ? (tmp_level - 1) : 0;
|
||||
unsigned long tmp_index = heap[1].index, t_index = tmp_index >> 3;
|
||||
|
||||
if (rgb_table[t_level][t_index].pixel_count)
|
||||
heap[1] = heap[tot_colors--];
|
||||
else
|
||||
{
|
||||
heap[1].level = t_level;
|
||||
heap[1].index = (unsigned short)t_index;
|
||||
}
|
||||
|
||||
rgb_table[t_level][t_index].pixel_count += rgb_table[tmp_level][tmp_index].pixel_count;
|
||||
rgb_table[t_level][t_index].r += rgb_table[tmp_level][tmp_index].r;
|
||||
rgb_table[t_level][t_index].g += rgb_table[tmp_level][tmp_index].g;
|
||||
rgb_table[t_level][t_index].b += rgb_table[tmp_level][tmp_index].b;
|
||||
rgb_table[t_level][t_index].children &= ~(1 << (tmp_index & 0x7));
|
||||
|
||||
fixheap(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_palette(int index, int level)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (rgb_table[level][index].children)
|
||||
for (i = 7; i >= 0; i--)
|
||||
if (rgb_table[level][index].children & (1 << i))
|
||||
set_palette((index << 3) + i, level + 1);
|
||||
|
||||
if (rgb_table[level][index].pixel_count)
|
||||
{
|
||||
unsigned long r_sum, g_sum, b_sum, sum;
|
||||
|
||||
rgb_table[level][index].palette_index = pal_index;
|
||||
|
||||
r_sum = rgb_table[level][index].r;
|
||||
g_sum = rgb_table[level][index].g;
|
||||
b_sum = rgb_table[level][index].b;
|
||||
|
||||
sum = rgb_table[level][index].pixel_count;
|
||||
|
||||
palette[0][pal_index] = (unsigned char)((r_sum + (sum >> 1)) / sum);
|
||||
palette[1][pal_index] = (unsigned char)((g_sum + (sum >> 1)) / sum);
|
||||
palette[2][pal_index] = (unsigned char)((b_sum + (sum >> 1)) / sum);
|
||||
|
||||
pal_index++;
|
||||
}
|
||||
}
|
||||
|
||||
static void closest_color(int index, int level)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (rgb_table[level][index].children)
|
||||
for (i = 7; i >= 0; i--)
|
||||
if (rgb_table[level][index].children & (1 << i))
|
||||
closest_color((index << 3) + i, level + 1);
|
||||
|
||||
if (rgb_table[level][index].pixel_count)
|
||||
{
|
||||
long dist, r_dist, g_dist, b_dist;
|
||||
unsigned char pal_num = rgb_table[level][index].palette_index;
|
||||
|
||||
// Determine if this color is "closest".
|
||||
r_dist = palette[0][pal_num] - c_info.red;
|
||||
g_dist = palette[1][pal_num] - c_info.green;
|
||||
b_dist = palette[2][pal_num] - c_info.blue;
|
||||
|
||||
dist = squares[r_dist] + squares[g_dist] + squares[b_dist];
|
||||
|
||||
if (dist < (long)c_info.distance)
|
||||
{
|
||||
c_info.distance = dist;
|
||||
c_info.palette_index = pal_num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns 1 on success, 0 on failure
|
||||
static int quantize_image(unsigned char *in, unsigned char *out, int width, int height, int dither)
|
||||
{
|
||||
if (!dither)
|
||||
{
|
||||
unsigned long i = 0, pixels = width * height;
|
||||
unsigned short level = 0, index = 0;
|
||||
unsigned char tmp_r = 0, tmp_g = 0, tmp_b = 0, cube = 0;
|
||||
unsigned char *lookup = NULL;
|
||||
|
||||
lookup = (unsigned char*)malloc(sizeof(char) * 32768);
|
||||
if (lookup == NULL)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < 32768; i++)
|
||||
if (rgb_table[5][i].pixel_count)
|
||||
{
|
||||
tmp_r = (unsigned char)((i & 0x4000) >> 7 | (i & 0x0800) >> 5 |
|
||||
(i & 0x0100) >> 3 | (i & 0x0020) >> 1 |
|
||||
(i & 0x0004) << 1);
|
||||
tmp_g = (unsigned char)((i & 0x2000) >> 6 | (i & 0x0400) >> 4 |
|
||||
(i & 0x0080) >> 2 | (i & 0x0010) >> 0 |
|
||||
(i & 0x0002) << 2);
|
||||
tmp_b = (unsigned char)((i & 0x1000) >> 5 | (i & 0x0200) >> 3 |
|
||||
(i & 0x0040) >> 1 | (i & 0x0008) << 1 |
|
||||
(i & 0x0001) << 3);
|
||||
#ifdef QUAL2
|
||||
lookup[i] = bestcolor(tmp_r, tmp_g, tmp_b);
|
||||
#else
|
||||
c_info.red = tmp_r + 4;
|
||||
c_info.green = tmp_g + 4;
|
||||
c_info.blue = tmp_b + 4;
|
||||
level = 0;
|
||||
index = 0;
|
||||
for (;;) {
|
||||
cube = (tmp_r&128) >> 5 | (tmp_g&128) >> 6 | (tmp_b&128) >> 7;
|
||||
if ((rgb_table[level][index].children & (1 << cube)) == 0) {
|
||||
c_info.distance = (unsigned long)~0L;
|
||||
closest_color(index, level);
|
||||
lookup[i] = c_info.palette_index;
|
||||
break;
|
||||
}
|
||||
level++;
|
||||
index = (index << 3) + cube;
|
||||
tmp_r <<= 1;
|
||||
tmp_g <<= 1;
|
||||
tmp_b <<= 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for (i = 0; i < pixels; i++)
|
||||
{
|
||||
#ifdef FAST
|
||||
out[i] = lookup[dl_image[i]];
|
||||
#else
|
||||
out[i] = lookup[r_offset[in[0]] + g_offset[in[1]] + b_offset[in[2]]];
|
||||
in += 3;
|
||||
#endif
|
||||
}
|
||||
|
||||
free(lookup);
|
||||
|
||||
}
|
||||
else // dither
|
||||
{
|
||||
#if defined(DITHER2) || defined(DITHER4)
|
||||
long i = 0, j = 0;
|
||||
long r_pix = 0, g_pix = 0, b_pix = 0;
|
||||
long offset = 0, dir = 0;
|
||||
long odd_scanline = 0;
|
||||
long err_len = (width + 2) * 3;
|
||||
unsigned char *range_tbl = NULL, *range = NULL;
|
||||
short *lookup = NULL, *erowerr = NULL, *orowerr = NULL;
|
||||
short *thisrowerr = NULL, *nextrowerr = NULL;
|
||||
char *dith_max_tbl = NULL, *dith_max = NULL;
|
||||
|
||||
lookup = (short*)malloc(sizeof(short) * 32768);
|
||||
erowerr = (short*)malloc(sizeof(short) * err_len);
|
||||
orowerr = (short*)malloc(sizeof(short) * err_len);
|
||||
range_tbl = (unsigned char*)malloc(3 * 256);
|
||||
range = range_tbl + 256;
|
||||
dith_max_tbl= (char*)malloc(512);
|
||||
dith_max = dith_max_tbl + 256;
|
||||
|
||||
if (range_tbl == NULL || lookup == NULL || erowerr == NULL || orowerr == NULL || dith_max_tbl == NULL)
|
||||
{
|
||||
if (range_tbl != NULL)
|
||||
{
|
||||
free(range_tbl);
|
||||
range_tbl=NULL;
|
||||
}
|
||||
if (lookup != NULL)
|
||||
{
|
||||
free(lookup);
|
||||
lookup=NULL;
|
||||
}
|
||||
if (erowerr != NULL)
|
||||
{
|
||||
free(erowerr);
|
||||
erowerr=NULL;
|
||||
}
|
||||
if (orowerr != NULL)
|
||||
{
|
||||
free(orowerr);
|
||||
orowerr=NULL;
|
||||
}
|
||||
if (dith_max_tbl != NULL)
|
||||
{
|
||||
free(dith_max_tbl);
|
||||
dith_max_tbl=NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < err_len; i++)
|
||||
erowerr[i] = 0;
|
||||
|
||||
for (i = 0; i < 32768; i++)
|
||||
lookup[i] = -1;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
range_tbl[i] = 0;
|
||||
range_tbl[i + 256] = (unsigned char) i;
|
||||
range_tbl[i + 512] = 255;
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
dith_max_tbl[i] = -DITHER_MAX;
|
||||
dith_max_tbl[i + 256] = DITHER_MAX;
|
||||
}
|
||||
for (i = -DITHER_MAX; i <= DITHER_MAX; i++)
|
||||
dith_max_tbl[i + 256] = (char)i;
|
||||
|
||||
for (i = 0 ; i < height; i++)
|
||||
{
|
||||
if (odd_scanline)
|
||||
{
|
||||
dir = -1;
|
||||
in += (width - 1) * 3;
|
||||
out += (width - 1);
|
||||
thisrowerr = orowerr + 3;
|
||||
nextrowerr = erowerr + width * 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = 1;
|
||||
thisrowerr = erowerr + 3;
|
||||
nextrowerr = orowerr + width * 3;
|
||||
}
|
||||
|
||||
nextrowerr[0] = nextrowerr[1] = nextrowerr[2] = 0;
|
||||
|
||||
for (j = 0; j < width; j++)
|
||||
{
|
||||
#ifdef DITHER2
|
||||
r_pix = range[(thisrowerr[0] >> 1) + in[0]];
|
||||
g_pix = range[(thisrowerr[1] >> 1) + in[1]];
|
||||
b_pix = range[(thisrowerr[2] >> 1) + in[2]];
|
||||
#else
|
||||
r_pix = range[((thisrowerr[0] + 8) >> 4) + in[0]];
|
||||
g_pix = range[((thisrowerr[1] + 8) >> 4) + in[1]];
|
||||
b_pix = range[((thisrowerr[2] + 8) >> 4) + in[2]];
|
||||
#endif
|
||||
offset = (r_pix&248) << 7 | (g_pix&248) << 2 | b_pix >> 3;
|
||||
if (lookup[offset] < 0)
|
||||
lookup[offset] = bestcolor(r_pix, g_pix, b_pix);
|
||||
*out = (unsigned char)lookup[offset];
|
||||
r_pix = dith_max[r_pix - palette[0][lookup[offset]]];
|
||||
g_pix = dith_max[g_pix - palette[1][lookup[offset]]];
|
||||
b_pix = dith_max[b_pix - palette[2][lookup[offset]]];
|
||||
|
||||
#ifdef DITHER2
|
||||
nextrowerr[0 ] = (short)r_pix;
|
||||
thisrowerr[0+3] += (short)r_pix;
|
||||
nextrowerr[1 ] = (short)g_pix;
|
||||
thisrowerr[1+3] += (short)g_pix;
|
||||
nextrowerr[2 ] = (short)b_pix;
|
||||
thisrowerr[2+3] += (short)b_pix;
|
||||
#else
|
||||
two_val = r_pix * 2;
|
||||
nextrowerr[0-3] = r_pix;
|
||||
r_pix += two_val;
|
||||
nextrowerr[0+3] += r_pix;
|
||||
r_pix += two_val;
|
||||
nextrowerr[0 ] += r_pix;
|
||||
r_pix += two_val;
|
||||
thisrowerr[0+3] += r_pix;
|
||||
two_val = g_pix * 2;
|
||||
nextrowerr[1-3] = g_pix;
|
||||
g_pix += two_val;
|
||||
nextrowerr[1+3] += g_pix;
|
||||
g_pix += two_val;
|
||||
nextrowerr[1 ] += g_pix;
|
||||
g_pix += two_val;
|
||||
thisrowerr[1+3] += g_pix;
|
||||
two_val = b_pix * 2;
|
||||
nextrowerr[2-3] = b_pix;
|
||||
b_pix += two_val;
|
||||
nextrowerr[2+3] += b_pix;
|
||||
b_pix += two_val;
|
||||
nextrowerr[2 ] += b_pix;
|
||||
b_pix += two_val;
|
||||
thisrowerr[2+3] += b_pix;
|
||||
#endif
|
||||
thisrowerr += 3;
|
||||
nextrowerr -= 3;
|
||||
in += dir * 3;
|
||||
out += dir;
|
||||
}
|
||||
|
||||
if ((i % 2) == 1)
|
||||
{
|
||||
in += (width + 1) * 3;
|
||||
out += (width + 1);
|
||||
}
|
||||
|
||||
odd_scanline = !odd_scanline;
|
||||
}
|
||||
|
||||
free(range_tbl);
|
||||
free(lookup);
|
||||
free(erowerr);
|
||||
free(orowerr);
|
||||
free(dith_max_tbl);
|
||||
#else
|
||||
long i = 0, j = 0;
|
||||
long r_pix = 0, g_pix = 0, b_pix=0;
|
||||
long r_err = 0, g_err = 0, b_err=0;
|
||||
long offset = 0;
|
||||
BYTE *range_tbl = (BYTE*)malloc(3 * 256), *range = range_tbl + 256;
|
||||
short *lookup = (sshort *)malloc(sizeof(short) * 32768);
|
||||
|
||||
if (range_tbl == NULL || lookup == NULL)
|
||||
{
|
||||
if (range_tbl != NULL)
|
||||
free(range_tbl);
|
||||
if (lookup != NULL)
|
||||
free(lookup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 32768; i++)
|
||||
lookup[i] = -1;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
range_tbl[i] = 0;
|
||||
range_tbl[i + 256] = (BYTE) i;
|
||||
range_tbl[i + 512] = 255;
|
||||
}
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
r_err = g_err = b_err = 0;
|
||||
for (j = width - 1; j >= 0; j--)
|
||||
{
|
||||
r_pix = range[(r_err >> 1) + in[0]];
|
||||
g_pix = range[(g_err >> 1) + in[1]];
|
||||
b_pix = range[(b_err >> 1) + in[2]];
|
||||
|
||||
offset = (r_pix&248) << 7 | (g_pix&248) << 2 | b_pix >> 3;
|
||||
|
||||
if (lookup[offset] < 0)
|
||||
lookup[offset] = bestcolor(r_pix, g_pix, b_pix);
|
||||
|
||||
*out++ = (unsigned char)lookup[offset];
|
||||
|
||||
r_err = r_pix - palette[0][lookup[offset]];
|
||||
g_err = g_pix - palette[1][lookup[offset]];
|
||||
b_err = b_pix - palette[2][lookup[offset]];
|
||||
|
||||
in += 3;
|
||||
}
|
||||
}
|
||||
|
||||
free(range_tbl);
|
||||
free(lookup);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bestcolor(int r, int g, int b)
|
||||
{
|
||||
unsigned long i = 0, bestcolor = 0, curdist = 0, mindist = 0;
|
||||
long rdist = 0, gdist = 0, bdist = 0;
|
||||
|
||||
r = (r & 248) + 4;
|
||||
g = (g & 248) + 4;
|
||||
b = (b & 248) + 4;
|
||||
mindist = 200000;
|
||||
|
||||
for (i = 0; i < (unsigned long)tot_colors; i++)
|
||||
{
|
||||
rdist = palette[0][i] - r;
|
||||
gdist = palette[1][i] - g;
|
||||
bdist = palette[2][i] - b;
|
||||
curdist = squares[rdist] + squares[gdist] + squares[bdist];
|
||||
|
||||
if (curdist < mindist)
|
||||
{
|
||||
mindist = curdist;
|
||||
bestcolor = i;
|
||||
}
|
||||
}
|
||||
return bestcolor;
|
||||
}
|
31
common/quant.h
Normal file
31
common/quant.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
///////////////////////////////////////
|
||||
// DL1 Quantization
|
||||
|
||||
#ifndef _QUANT_H_
|
||||
#define _QUANT_H_
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned long r, g, b;
|
||||
unsigned long pixel_count;
|
||||
unsigned long pixels_in_cube;
|
||||
unsigned char children;
|
||||
unsigned char palette_index;
|
||||
} CUBE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char level;
|
||||
unsigned short index;
|
||||
} FCUBE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char palette_index, red, green, blue;
|
||||
unsigned long distance;
|
||||
unsigned long squares[255+255+1];
|
||||
} CLOSEST_INFO;
|
||||
|
||||
bool dl1quant(unsigned char *inbuf, unsigned char *outbuf, int width, int height, int quant_to, int dither, unsigned char userpal[3][256]);
|
||||
|
||||
#endif // _QUANT_H_
|
402
common/str.cpp
Normal file
402
common/str.cpp
Normal file
|
@ -0,0 +1,402 @@
|
|||
//
|
||||
// General purpose string class
|
||||
//
|
||||
|
||||
#include <ctype.h>
|
||||
#include "str.h"
|
||||
|
||||
static String aux;
|
||||
|
||||
// =============================================================================
|
||||
// Construction / Destruction
|
||||
|
||||
String::String ()
|
||||
{
|
||||
m_pData = new char[1];
|
||||
m_pData[0] = '\0';
|
||||
}
|
||||
|
||||
String::~String ()
|
||||
{
|
||||
delete []m_pData;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Operators
|
||||
|
||||
const String& String::operator= (const String& src)
|
||||
{
|
||||
delete []m_pData;
|
||||
m_pData = new char[src.GetLength () + 1];
|
||||
strcpy (m_pData, src.m_pData);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const String& String::operator= (char ch)
|
||||
{
|
||||
delete []m_pData;
|
||||
m_pData = new char[2];
|
||||
m_pData[0] = ch;
|
||||
m_pData[1] = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
const String& String::operator= (const char *src)
|
||||
{
|
||||
delete []m_pData;
|
||||
m_pData = new char[strlen (src) + 1];
|
||||
strcpy (m_pData, src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const String& String::operator+= (const String& src)
|
||||
{
|
||||
char *tmp = new char[GetLength () + src.GetLength () + 1];
|
||||
strcpy (tmp, m_pData);
|
||||
strcat (tmp, src.m_pData);
|
||||
delete []m_pData;
|
||||
m_pData = tmp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const String& String::operator+= (char ch)
|
||||
{
|
||||
int len = GetLength ();
|
||||
char *tmp = new char[len + 1 + 1];
|
||||
strcpy (tmp, m_pData);
|
||||
tmp[len] = ch;
|
||||
tmp[len+1] = '\0';
|
||||
delete []m_pData;
|
||||
m_pData = tmp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const String& String::operator+= (const char *src)
|
||||
{
|
||||
char *tmp = new char[GetLength () + strlen (src) + 1];
|
||||
strcpy (tmp, m_pData);
|
||||
strcat (tmp, src);
|
||||
delete []m_pData;
|
||||
m_pData = tmp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Non-member operators
|
||||
|
||||
String& operator+ (const String& string1, const String& string2)
|
||||
{
|
||||
String s;
|
||||
s = string1;
|
||||
s += string2;
|
||||
aux = s;
|
||||
return aux;
|
||||
}
|
||||
|
||||
String& operator+ (const String& string, char ch)
|
||||
{
|
||||
String s;
|
||||
s = string;
|
||||
s += ch;
|
||||
aux = s;
|
||||
return aux;
|
||||
}
|
||||
|
||||
String& operator+ (char ch, const String& string)
|
||||
{
|
||||
String s;
|
||||
s = ch;
|
||||
s += string;
|
||||
aux = s;
|
||||
return aux;
|
||||
}
|
||||
|
||||
String& operator+ (const String& string1, const char *string2)
|
||||
{
|
||||
String s;
|
||||
s = string1;
|
||||
s += string2;
|
||||
aux = s;
|
||||
return aux;
|
||||
}
|
||||
|
||||
String& operator+ (const char *string1, const String& string2)
|
||||
{
|
||||
String s;
|
||||
s = string1;
|
||||
s += string2;
|
||||
aux = s;
|
||||
return aux;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Sub-string extraction
|
||||
|
||||
String& String::Mid (int first, int count) const
|
||||
{
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
else if (count > GetLength ())
|
||||
count = GetLength ();
|
||||
|
||||
String s;
|
||||
strncpy (s.GetBuffer (count+1), m_pData + first, count);
|
||||
s.m_pData[count] = '\0';
|
||||
aux = s;
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
String& String::Left (int count) const
|
||||
{
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
else if (count > GetLength ())
|
||||
count = GetLength ();
|
||||
|
||||
String s;
|
||||
strncpy (s.GetBuffer (count+1), m_pData, count);
|
||||
s.m_pData[count] = '\0';
|
||||
aux = s;
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
String& String::Right (int count) const
|
||||
{
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
else if (count > GetLength ())
|
||||
count = GetLength ();
|
||||
|
||||
String s;
|
||||
strncpy (s.GetBuffer (count+1), m_pData + GetLength () - count, count);
|
||||
s.m_pData[count] = '\0';
|
||||
aux = s;
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Other functions
|
||||
|
||||
// Evaluates the contents of the string against a boolean expression.
|
||||
// For example: (^Car | %Animal) & !Parrot
|
||||
// Will return true for any strings that have the Car word or
|
||||
// begin with Animal and do not have the word Parrot.
|
||||
bool String::Match(const String& Expression) const
|
||||
{
|
||||
// Check if we need to split the test expression.
|
||||
const char* p = Expression;
|
||||
|
||||
while (*p)
|
||||
{
|
||||
if (*p == '!')
|
||||
{
|
||||
return !Match(String(p + 1));
|
||||
}
|
||||
else if (*p == '(')
|
||||
{
|
||||
const char* Start = p;
|
||||
int c = 0;
|
||||
|
||||
// Skip what's inside the parenthesis.
|
||||
do
|
||||
{
|
||||
if (*p == '(')
|
||||
c++;
|
||||
else if (*p == ')')
|
||||
c--;
|
||||
else if (*p == 0)
|
||||
return false; // Mismatched parenthesis.
|
||||
|
||||
p++;
|
||||
}
|
||||
while (c);
|
||||
|
||||
if (*p == 0)
|
||||
break;
|
||||
}
|
||||
else if ((*p == '|') || (*p == '&'))
|
||||
{
|
||||
String Left, Right;
|
||||
|
||||
Left = Expression.Left((p - Expression) - 1);
|
||||
Right = Expression.Right(Expression.GetLength() - (p - Expression) - 1);
|
||||
|
||||
if (*p == '|')
|
||||
return Match(Left) || Match(Right);
|
||||
else
|
||||
return Match(Left) && Match(Right);
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
if (Expression.Find('(') != -1)
|
||||
{
|
||||
p = Expression;
|
||||
while (*p)
|
||||
{
|
||||
if (*p == '(')
|
||||
{
|
||||
const char* Start = p;
|
||||
int c = 0;
|
||||
|
||||
// Extract what's inside the parenthesis.
|
||||
do
|
||||
{
|
||||
if (*p == '(')
|
||||
c++;
|
||||
else if (*p == ')')
|
||||
c--;
|
||||
else if (*p == 0)
|
||||
return false; // Mismatched parenthesis.
|
||||
|
||||
p++;
|
||||
}
|
||||
while (c);
|
||||
|
||||
String Expr = Expression.Mid(Start - Expression + 1, p - Start - 2);
|
||||
return Match(Expr);
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
// Testing a simple case.
|
||||
String Search = Expression;
|
||||
Search.TrimRight();
|
||||
Search.TrimLeft();
|
||||
|
||||
const char* Word = Search;
|
||||
|
||||
// Check for modifiers.
|
||||
bool WholeWord = 0;
|
||||
bool Begin = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (Word[0] == '^')
|
||||
WholeWord = true;
|
||||
else if (Word[0] == '%')
|
||||
Begin = true;
|
||||
else
|
||||
break;
|
||||
|
||||
Word++;
|
||||
}
|
||||
|
||||
int Result = Find(Word);
|
||||
|
||||
if (Result == -1)
|
||||
return false;
|
||||
|
||||
if (Begin && (Result != 0))
|
||||
{
|
||||
if ((Result != 1) || ((GetAt(Result-1) != '_') && (GetAt(Result-1) != '~')))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (WholeWord)
|
||||
{
|
||||
char End = GetAt(Result + strlen(Word));
|
||||
|
||||
if ((End != 0) && (End != ' '))
|
||||
return false;
|
||||
|
||||
if ((Result != 0) && ((GetAt(Result-1) == '_') || (GetAt(Result-1) == '~')))
|
||||
Result--;
|
||||
|
||||
if ((Result != 0) && (GetAt(Result-1) != ' '))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int String::CompareNoCase (const char *string) const
|
||||
{
|
||||
char c1, c2, *ch = m_pData;
|
||||
while (*ch && *string)
|
||||
{
|
||||
c1 = tolower (*ch);
|
||||
c2 = tolower (*string);
|
||||
if (c1 != c2)
|
||||
return (c1 - c2);
|
||||
ch++; string++;
|
||||
}
|
||||
return (((int)*ch) - ((int)*string));
|
||||
}
|
||||
|
||||
int String::CompareNoCase(const char *string, int count) const
|
||||
{
|
||||
char c1, c2, *ch = m_pData;
|
||||
|
||||
while (*ch && *string)
|
||||
{
|
||||
c1 = tolower (*ch);
|
||||
c2 = tolower (*string);
|
||||
|
||||
if (c1 != c2)
|
||||
return (c1 - c2);
|
||||
|
||||
ch++;
|
||||
string++;
|
||||
count--;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (((int)*ch) - ((int)*string));
|
||||
}
|
||||
|
||||
void String::MakeUpper ()
|
||||
{
|
||||
for (char *cp = m_pData; *cp; ++cp)
|
||||
if ('a' <= *cp && *cp <= 'z')
|
||||
*cp += 'A' - 'a';
|
||||
}
|
||||
|
||||
void String::MakeLower ()
|
||||
{
|
||||
for (char *cp = m_pData; *cp; ++cp)
|
||||
if ('A' <= *cp && *cp <= 'Z')
|
||||
*cp += 'a' - 'A';
|
||||
}
|
||||
|
||||
void String::MakeReverse ()
|
||||
{
|
||||
register char *h, *t;
|
||||
|
||||
h = m_pData;
|
||||
t = m_pData + strlen (m_pData) - 1;
|
||||
|
||||
while (h < t)
|
||||
{
|
||||
register char c;
|
||||
|
||||
c = *h;
|
||||
*h = *t;
|
||||
h++;
|
||||
*t = c;
|
||||
t--;
|
||||
}
|
||||
}
|
||||
|
||||
void String::TrimRight ()
|
||||
{
|
||||
for (char *s = m_pData + strlen (m_pData) - 1; s >= m_pData && isspace (*s); s--)
|
||||
*s = '\0';
|
||||
}
|
||||
|
||||
void String::TrimLeft ()
|
||||
{
|
||||
char *ch;
|
||||
ch = m_pData;
|
||||
while (isspace (*ch))
|
||||
ch++;
|
||||
memmove (m_pData, ch, strlen (ch)+1);
|
||||
}
|
157
common/str.h
Normal file
157
common/str.h
Normal file
|
@ -0,0 +1,157 @@
|
|||
#ifndef _STR_H_
|
||||
#define _STR_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
class String
|
||||
{
|
||||
public:
|
||||
String();
|
||||
String(const String& src)
|
||||
{ m_pData = NULL; *this = src; }
|
||||
String(const char* str)
|
||||
{ m_pData = NULL; *this = str; }
|
||||
~String();
|
||||
|
||||
int GetLength() const
|
||||
{ return strlen(m_pData); }
|
||||
bool IsEmpty() const
|
||||
{ return m_pData[0] == '\0'; }
|
||||
void Empty()
|
||||
{ m_pData[0] = '\0'; }
|
||||
|
||||
char GetAt(int index) const
|
||||
{ return m_pData[index]; }
|
||||
char& operator[](int index) const
|
||||
{ return m_pData[index]; }
|
||||
void SetAt(int index, char ch)
|
||||
{ m_pData[index] = ch; }
|
||||
operator char*() const
|
||||
{ return m_pData; }
|
||||
operator const char*() const
|
||||
{ return m_pData; }
|
||||
|
||||
// Operators
|
||||
const String& operator=(const String& src);
|
||||
const String& operator=(char ch);
|
||||
const String& operator=(const char *src);
|
||||
const String& operator+=(const String& string);
|
||||
const String& operator+=(char ch);
|
||||
const String& operator+=(const char *src);
|
||||
|
||||
// Comparison
|
||||
int Compare(const char *string) const
|
||||
{ return strcmp(m_pData, string); }
|
||||
int CompareNoCase(const char *string) const;
|
||||
int CompareNoCase(const char *string, int count) const;
|
||||
bool Match(const String& Expression) const;
|
||||
|
||||
// simple sub-string extraction
|
||||
String& Mid(int first, int count) const;
|
||||
String& Mid(int first) const
|
||||
{ return Mid(first, GetLength() - first); }
|
||||
String& Left(int count) const;
|
||||
String& Right(int count) const;
|
||||
|
||||
// upper/lower/reverse conversion
|
||||
void MakeUpper();
|
||||
void MakeLower();
|
||||
void MakeReverse();
|
||||
|
||||
// trimming whitespace (either side)
|
||||
void TrimRight();
|
||||
void TrimLeft();
|
||||
|
||||
// searching (return starting index, or -1 if not found)
|
||||
// look for a single character match
|
||||
int Find(char ch) const
|
||||
{
|
||||
char *pf = strchr(m_pData, ch);
|
||||
return (pf) ? (pf - m_pData) : -1;
|
||||
}
|
||||
int ReverseFind(char ch) const
|
||||
{
|
||||
char *pf = strrchr(m_pData, ch);
|
||||
return (pf) ? (pf - m_pData) : -1;
|
||||
}
|
||||
int FindOneOf(const char *set) const
|
||||
{
|
||||
char *pf = strpbrk(m_pData, set);
|
||||
return (pf) ? (pf - m_pData) : -1;
|
||||
}
|
||||
|
||||
// look for a specific sub-string
|
||||
int Find(const char *str) const
|
||||
{
|
||||
char *pf = strstr(m_pData, str);
|
||||
return (pf) ? (pf - m_pData) : -1;
|
||||
}
|
||||
|
||||
char* GetBuffer(int len)
|
||||
{
|
||||
if (len > (int)strlen(m_pData))
|
||||
{
|
||||
char *tmp = new char[len+1];
|
||||
strcpy(tmp, m_pData);
|
||||
delete []m_pData;
|
||||
m_pData = tmp;
|
||||
}
|
||||
return m_pData;
|
||||
}
|
||||
void ReleaseBuffer(int len = -1)
|
||||
{
|
||||
if (len == -1)
|
||||
len = strlen(m_pData);
|
||||
m_pData[len] = '\0';
|
||||
}
|
||||
|
||||
protected:
|
||||
char* m_pData;
|
||||
};
|
||||
|
||||
// Concatenation operators
|
||||
String& operator+(const String& string1, const String& string2);
|
||||
String& operator+(const String& string, char ch);
|
||||
String& operator+(char ch, const String& string);
|
||||
String& operator+(const String& string1, const char *string2);
|
||||
String& operator+(const char *string1, const String& string2);
|
||||
|
||||
// Comparison operators
|
||||
inline bool operator==(const String& s1, const String& s2)
|
||||
{ return s1.Compare(s2) == 0; }
|
||||
inline bool operator==(const String& s1, const char *s2)
|
||||
{ return s1.Compare(s2) == 0; }
|
||||
inline bool operator==(const char *s1, const String& s2)
|
||||
{ return s2.Compare(s1) == 0; }
|
||||
inline bool operator!=(const String& s1, const String& s2)
|
||||
{ return s1.Compare(s2) != 0; }
|
||||
inline bool operator!=(const String& s1, const char *s2)
|
||||
{ return s1.Compare(s2) != 0; }
|
||||
inline bool operator!=(const char *s1, const String& s2)
|
||||
{ return s2.Compare(s1) != 0; }
|
||||
inline bool operator<(const String& s1, const String& s2)
|
||||
{ return s1.Compare(s2) < 0; }
|
||||
inline bool operator<(const String& s1, const char *s2)
|
||||
{ return s1.Compare(s2) < 0; }
|
||||
inline bool operator<(const char *s1, const String& s2)
|
||||
{ return s2.Compare(s1) > 0; }
|
||||
inline bool operator>(const String& s1, const String& s2)
|
||||
{ return s1.Compare(s2) > 0; }
|
||||
inline bool operator>(const String& s1, const char *s2)
|
||||
{ return s1.Compare(s2) > 0; }
|
||||
inline bool operator>(const char *s1, const String& s2)
|
||||
{ return s2.Compare(s1) < 0; }
|
||||
inline bool operator<=(const String& s1, const String& s2)
|
||||
{ return s1.Compare(s2) <= 0; }
|
||||
inline bool operator<=(const String& s1, const char *s2)
|
||||
{ return s1.Compare(s2) <= 0; }
|
||||
inline bool operator<=(const char *s1, const String& s2)
|
||||
{ return s2.Compare(s1) >= 0; }
|
||||
inline bool operator>=(const String& s1, const String& s2)
|
||||
{ return s1.Compare(s2) >= 0; }
|
||||
inline bool operator>=(const String& s1, const char *s2)
|
||||
{ return s1.Compare(s2) >= 0; }
|
||||
inline bool operator>=(const char *s1, const String& s2)
|
||||
{ return s2.Compare(s1) <= 0; }
|
||||
|
||||
#endif // _STR_H_
|
122
common/system.h
Executable file
122
common/system.h
Executable file
|
@ -0,0 +1,122 @@
|
|||
#ifndef _SYSTEM_H_
|
||||
#define _SYSTEM_H_
|
||||
|
||||
#include "defines.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
// Assert macros.
|
||||
#ifdef LC_DEBUG
|
||||
|
||||
extern bool lcAssert(const char* FileName, int Line, const char* Expression, const char* Description);
|
||||
|
||||
#define LC_ASSERT(Expr, Desc) \
|
||||
do \
|
||||
{ \
|
||||
static bool Ignore = false; \
|
||||
if (!Expr && !Ignore) \
|
||||
Ignore = lcAssert(__FILE__, __LINE__, #Expr, Desc); \
|
||||
} while (0)
|
||||
|
||||
#define LC_ASSERT_FALSE(Desc) LC_ASSERT(0, Desc)
|
||||
|
||||
#else
|
||||
|
||||
#define LC_ASSERT(expr, desc) do { } while(0)
|
||||
|
||||
#define LC_ASSERT_FALSE(Desc) LC_ASSERT(0, Desc)
|
||||
|
||||
#endif
|
||||
|
||||
// Profile functions
|
||||
bool Sys_ProfileSaveInt (const char *section, const char *key, int value);
|
||||
bool Sys_ProfileSaveString (const char *section, const char *key, const char *value);
|
||||
int Sys_ProfileLoadInt (const char *section, const char *key, int default_value);
|
||||
char* Sys_ProfileLoadString (const char *section, const char *key, const char *default_value);
|
||||
|
||||
// Memory render
|
||||
void* Sys_StartMemoryRender (int width, int height);
|
||||
void Sys_FinishMemoryRender (void* param);
|
||||
|
||||
// FIXME: moved to basewnd, remove
|
||||
|
||||
// Message Box
|
||||
#define LC_OK 1
|
||||
#define LC_CANCEL 2
|
||||
#define LC_ABORT 3
|
||||
#define LC_RETRY 4
|
||||
#define LC_IGNORE 5
|
||||
#define LC_YES 6
|
||||
#define LC_NO 7
|
||||
|
||||
#define LC_MB_OK 0x000
|
||||
#define LC_MB_OKCANCEL 0x001
|
||||
//#define LC_MB_ABORTRETRYIGNORE 0x002
|
||||
#define LC_MB_YESNOCANCEL 0x003
|
||||
#define LC_MB_YESNO 0x004
|
||||
//#define LC_MB_RETRYCANCEL 0x005
|
||||
|
||||
#define LC_MB_ICONERROR 0x010
|
||||
#define LC_MB_ICONQUESTION 0x020
|
||||
#define LC_MB_ICONWARNING 0x030
|
||||
#define LC_MB_ICONINFORMATION 0x040
|
||||
|
||||
#define LC_MB_TYPEMASK 0x00F
|
||||
#define LC_MB_ICONMASK 0x0F0
|
||||
|
||||
int Sys_MessageBox (const char* text, const char* caption="LeoCAD", int type=LC_MB_OK|LC_MB_ICONINFORMATION);
|
||||
|
||||
// FIXME end
|
||||
|
||||
// Misc stuff
|
||||
bool Sys_KeyDown (int key);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class File;
|
||||
class Camera;
|
||||
class PieceInfo;
|
||||
|
||||
// User Interface
|
||||
void SystemUpdateViewport(int nNew, int nOld);
|
||||
void SystemUpdateAction(int nNew, int nOld);
|
||||
void SystemUpdateColorList(int nNew);
|
||||
void SystemUpdateRenderingMode(bool bBackground, bool bFast);
|
||||
void SystemUpdateUndoRedo(char* undo, char* redo);
|
||||
void SystemUpdateSnap(const unsigned long nSnap);
|
||||
void SystemUpdateCurrentCamera(Camera* pOld, Camera* pNew, Camera* pCamera);
|
||||
void SystemUpdateCameraMenu(Camera* pCamera);
|
||||
void SystemUpdateTime(bool bAnimation, int nTime, int nTotal);
|
||||
void SystemUpdateAnimation(bool bAnimation, bool bAddKeys);
|
||||
void SystemUpdateSnap(unsigned short MoveSnap, unsigned short RotateSnap);
|
||||
void SystemUpdateSelected(unsigned long flags, int SelectedCount, class Object* Focus);
|
||||
void SystemUpdatePaste(bool enable);
|
||||
void SystemUpdatePlay(bool play, bool stop);
|
||||
void SystemUpdateCategories(bool SearchOnly);
|
||||
|
||||
void SystemInit();
|
||||
void SystemFinish();
|
||||
int SystemDoMessageBox(const char* prompt, int nMode);
|
||||
bool SystemDoDialog(int nMode, void* param);
|
||||
void SystemDoPopupMenu(int nMenu, int x, int y);
|
||||
void SystemDoWaitCursor(int nCode);
|
||||
|
||||
void SystemSetWindowCaption(char* caption);
|
||||
void SystemPieceComboAdd(char* name);
|
||||
|
||||
void SystemCaptureMouse();
|
||||
void SystemReleaseMouse();
|
||||
|
||||
void SystemExportClipboard(File* clip);
|
||||
File* SystemImportClipboard();
|
||||
|
||||
void SystemPumpMessages();
|
||||
long SystemGetTicks();
|
||||
|
||||
void SystemStartProgressBar(int nLower, int nUpper, int nStep, const char* Text);
|
||||
void SytemEndProgressBar();
|
||||
void SytemStepProgressBar();
|
||||
|
||||
#endif // _SYSTEM_H_
|
861
common/terrain.cpp
Normal file
861
common/terrain.cpp
Normal file
|
@ -0,0 +1,861 @@
|
|||
// Terrain: a Bezier surface.
|
||||
//
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include "opengl.h"
|
||||
#include "defines.h"
|
||||
#include "terrain.h"
|
||||
#include "file.h"
|
||||
#include "camera.h"
|
||||
#include "matrix.h"
|
||||
#include "system.h"
|
||||
#include "texture.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Static functions
|
||||
|
||||
// Cubic Bezier patch matrix:
|
||||
// 1 0 0 0
|
||||
// -3 3 0 0
|
||||
// 3 -6 3 0
|
||||
// -1 3 -3 1
|
||||
static float SolveBase(int i, float t)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: return (((-t)+3)*t-3)*t+1;
|
||||
case 1: return (((3*t)-6)*t+3)*t;
|
||||
case 2: return ((-3*t)+3)*t*t;
|
||||
case 3: return t*t*t;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static float SolveDiff(int i, float t)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: return ((-3*t)+6)*t-3;
|
||||
case 1: return ((9*t)-12)*t+3;
|
||||
case 2: return ((-9*t)+6)*t;
|
||||
case 3: return 3*t*t;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// TerrainPatch functions
|
||||
|
||||
TerrainPatch::TerrainPatch ()
|
||||
{
|
||||
vertex = NULL;
|
||||
normals = NULL;
|
||||
coords = NULL;
|
||||
index = NULL;
|
||||
steps = 10;
|
||||
visible = true;
|
||||
}
|
||||
|
||||
TerrainPatch::~TerrainPatch ()
|
||||
{
|
||||
FreeMemory ();
|
||||
}
|
||||
|
||||
void TerrainPatch::InitBox(float minX, float maxX, float minY, float maxY, float minZ, float maxZ)
|
||||
{
|
||||
// Now make each corner point for convenient culling.
|
||||
corners[0][0] = minX;
|
||||
corners[1][0] = minX;
|
||||
corners[2][0] = minX;
|
||||
corners[3][0] = minX;
|
||||
corners[4][0] = maxX;
|
||||
corners[5][0] = maxX;
|
||||
corners[6][0] = maxX;
|
||||
corners[7][0] = maxX;
|
||||
|
||||
corners[0][1] = minY;
|
||||
corners[1][1] = minY;
|
||||
corners[2][1] = maxY;
|
||||
corners[3][1] = maxY;
|
||||
corners[4][1] = minY;
|
||||
corners[5][1] = minY;
|
||||
corners[6][1] = maxY;
|
||||
corners[7][1] = maxY;
|
||||
|
||||
corners[0][2] = minZ;
|
||||
corners[1][2] = maxZ;
|
||||
corners[2][2] = minZ;
|
||||
corners[3][2] = maxZ;
|
||||
corners[4][2] = minZ;
|
||||
corners[5][2] = maxZ;
|
||||
corners[6][2] = minZ;
|
||||
corners[7][2] = maxZ;
|
||||
}
|
||||
|
||||
bool TerrainPatch::BoxIsOutside(const float plane[4]) const
|
||||
{
|
||||
float planeEqVal;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
planeEqVal = plane[0] * corners[i][0] + plane[1] * corners[i][1] + plane[2] * corners[i][2] + plane[3];
|
||||
|
||||
if (planeEqVal > 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define controlsX(b, a) control[(a*4+b)*3]
|
||||
#define controlsY(b, a) control[(a*4+b)*3+1]
|
||||
#define controlsZ(b, a) control[(a*4+b)*3+2]
|
||||
|
||||
void TerrainPatch::Tesselate(bool bNormals)
|
||||
{
|
||||
FreeMemory();
|
||||
|
||||
vertex = new float[steps*steps*3];
|
||||
if (bNormals)
|
||||
normals = new float[steps*steps*3];
|
||||
|
||||
coords = new float[steps*steps*2];
|
||||
|
||||
float invTotalSteps = 1.0f / (steps - 1);
|
||||
|
||||
for (int stepU = 0; stepU < steps; stepU++)
|
||||
{
|
||||
// Generate the parameter for this step of the curve.
|
||||
float u = stepU * invTotalSteps;
|
||||
|
||||
for (int stepV = 0; stepV < steps; stepV++)
|
||||
{
|
||||
// Generate the parameter for this step of the curve.
|
||||
float v = stepV * invTotalSteps;
|
||||
|
||||
// This holds the point we're working on as we add control points' contributions to it.
|
||||
float curPt[3] = { 0, 0, 0 };
|
||||
float curNorm[3] = { 0, 0, 0 };
|
||||
float curUTan[3] = { 0, 0, 0 };
|
||||
float curVTan[3] = { 0, 0, 0 };
|
||||
|
||||
// Generate a point on the curve for this step.
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
// Get a few basis function values and products thereof that we'll need.
|
||||
float bu = SolveBase(i, u);
|
||||
float bv = SolveBase(j, v);
|
||||
float dbu = SolveDiff(i, u);
|
||||
float dbv = SolveDiff(j, v);
|
||||
float bu_bv = bu * bv;
|
||||
float bu_dbv = bu * dbv;
|
||||
float dbu_bv = dbu * bv;
|
||||
|
||||
// Add this control point's contribution onto the current point.
|
||||
curPt[0] += controlsX(i, j) * bu_bv;
|
||||
curPt[1] += controlsY(i, j) * bu_bv;
|
||||
curPt[2] += controlsZ(i, j) * bu_bv;
|
||||
|
||||
// Add this point's contribution to our u-tangent.
|
||||
curUTan[0] += controlsX(i, j) * dbu_bv;
|
||||
curUTan[1] += controlsY(i, j) * dbu_bv;
|
||||
curUTan[2] += controlsZ(i, j) * dbu_bv;
|
||||
|
||||
// Add this point's contribution to our v-tangent.
|
||||
curVTan[0] += controlsX(i, j) * bu_dbv;
|
||||
curVTan[1] += controlsY(i, j) * bu_dbv;
|
||||
curVTan[2] += controlsZ(i, j) * bu_dbv;
|
||||
}
|
||||
|
||||
// Now get our normal as the cross-product of the u and v tangents.
|
||||
curNorm[0] = curVTan[1] * curUTan[2] - curVTan[2] * curUTan[1];
|
||||
curNorm[1] = curVTan[2] * curUTan[0] - curVTan[0] * curUTan[2];
|
||||
curNorm[2] = curVTan[0] * curUTan[1] - curVTan[1] * curUTan[0];
|
||||
|
||||
// Normalize our normal (ouch!)
|
||||
float rInv = 1.0f / (float)sqrt(curNorm[0]*curNorm[0] + curNorm[1]*curNorm[1] + curNorm[2]*curNorm[2]);
|
||||
curNorm[0] *= rInv;
|
||||
curNorm[1] *= rInv;
|
||||
curNorm[2] *= rInv;
|
||||
|
||||
// Store these.
|
||||
memcpy(&vertex[(stepU+(stepV*steps))*3], curPt, 3*sizeof(float));
|
||||
if (bNormals)
|
||||
memcpy(&normals[(stepU+(stepV*steps))*3], curNorm, 3*sizeof(float));
|
||||
|
||||
coords[(stepU+(stepV*steps))*2] = u;
|
||||
coords[(stepU+(stepV*steps))*2+1] = v;
|
||||
}
|
||||
}
|
||||
|
||||
index = new unsigned short[(steps-1)*(steps-1)*6];
|
||||
|
||||
for (unsigned short i = 0; i < steps-1; i++)
|
||||
for (unsigned short j = 0; j < steps-1; j++)
|
||||
{
|
||||
index[(i*(steps-1)+j)*6] = i*steps+j;
|
||||
index[(i*(steps-1)+j)*6+1] = (i+1)*steps+j;
|
||||
index[(i*(steps-1)+j)*6+2] = i*steps+j+1;
|
||||
index[(i*(steps-1)+j)*6+3] = (i+1)*steps+j;
|
||||
index[(i*(steps-1)+j)*6+4] = (i+1)*steps+j+1;
|
||||
index[(i*(steps-1)+j)*6+5] = i*steps+j+1;
|
||||
}
|
||||
}
|
||||
|
||||
#undef controlsX
|
||||
#undef controlsY
|
||||
#undef controlsZ
|
||||
|
||||
void TerrainPatch::FreeMemory()
|
||||
{
|
||||
if (vertex)
|
||||
{
|
||||
delete[] vertex;
|
||||
vertex = NULL;
|
||||
}
|
||||
|
||||
if (normals)
|
||||
{
|
||||
delete[] normals;
|
||||
normals = NULL;
|
||||
}
|
||||
|
||||
if (coords)
|
||||
{
|
||||
delete[] coords;
|
||||
coords = NULL;
|
||||
}
|
||||
|
||||
if (index)
|
||||
{
|
||||
delete[] index;
|
||||
index = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Terrain construction/destruction
|
||||
|
||||
Terrain::Terrain()
|
||||
{
|
||||
m_uPatches = 0;
|
||||
m_vPatches = 0;
|
||||
m_uSize = 50;
|
||||
m_vSize = 50;
|
||||
m_Patches = NULL;
|
||||
m_pControl = NULL;
|
||||
m_nOptions = 0;
|
||||
m_pTexture = new Texture();
|
||||
}
|
||||
|
||||
Terrain::~Terrain()
|
||||
{
|
||||
FreeMemory();
|
||||
delete m_pTexture;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Terrain functions
|
||||
|
||||
void Terrain::FileLoad(File* file)
|
||||
{
|
||||
unsigned char ch;
|
||||
unsigned short sh;
|
||||
int i, j;
|
||||
|
||||
file->ReadByte (&ch, 1);
|
||||
file->ReadLong (&i, 1);
|
||||
file->ReadLong (&j, 1);
|
||||
file->ReadFloat (&m_uSize, 1);
|
||||
file->ReadFloat (&m_vSize, 1);
|
||||
file->ReadLong (&m_nOptions, 1);
|
||||
file->ReadFloat (&m_fColor, 3);
|
||||
|
||||
if (ch == 1)
|
||||
{
|
||||
file->Read(&ch, 1);
|
||||
sh = ch;
|
||||
}
|
||||
else
|
||||
file->ReadShort (&sh, 1);
|
||||
|
||||
if (sh > LC_MAXPATH)
|
||||
file->Seek (sh, SEEK_CUR);
|
||||
else
|
||||
file->Read (&m_strTexture, sh);
|
||||
|
||||
SetPatchCount(i, j);
|
||||
for (i = 0; i < GetCountU(); i++)
|
||||
for (j = 0; j < GetCountV(); j++)
|
||||
file->ReadFloat (&m_pControl[i][j*3+2], 1);
|
||||
}
|
||||
|
||||
void Terrain::FileSave(File* file)
|
||||
{
|
||||
unsigned char version = 2; // LeoCAD 0.70
|
||||
unsigned short sh;
|
||||
|
||||
file->WriteByte (&version, 1);
|
||||
file->WriteLong (&m_uPatches, 1);
|
||||
file->WriteLong (&m_vPatches, 1);
|
||||
file->WriteFloat (&m_uSize, 1);
|
||||
file->WriteFloat (&m_vSize, 1);
|
||||
file->WriteLong (&m_nOptions, 1);
|
||||
file->WriteFloat (&m_fColor, 3);
|
||||
|
||||
sh = strlen (m_strTexture);
|
||||
file->WriteShort (&sh, 1);
|
||||
file->Write (m_strTexture, sh);
|
||||
|
||||
for (int i = 0; i < GetCountU(); i++)
|
||||
for (int j = 0; j < GetCountV(); j++)
|
||||
file->WriteFloat (&m_pControl[i][j*3+2], 1);
|
||||
}
|
||||
|
||||
void Terrain::FreeMemory()
|
||||
{
|
||||
int i;
|
||||
|
||||
if (m_Patches)
|
||||
{
|
||||
for (i = 0; i < m_uPatches; i++)
|
||||
delete[] m_Patches[i];
|
||||
|
||||
delete[] m_Patches;
|
||||
m_Patches = NULL;
|
||||
}
|
||||
|
||||
if (m_pControl)
|
||||
{
|
||||
for (i = 0; i < (m_uPatches*3)+1; i++)
|
||||
delete[] m_pControl[i];
|
||||
|
||||
delete[] m_pControl;
|
||||
m_pControl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy terrain info
|
||||
Terrain& Terrain::operator= (const Terrain& source)
|
||||
{
|
||||
FreeMemory();
|
||||
int i;
|
||||
|
||||
m_nOptions = source.m_nOptions;
|
||||
strcpy(m_strTexture, source.m_strTexture);
|
||||
memcpy(m_fColor, source.m_fColor, sizeof(m_fColor));
|
||||
m_uPatches = source.m_uPatches;
|
||||
m_vPatches = source.m_vPatches;
|
||||
|
||||
m_Patches = new TerrainPatch*[m_uPatches];
|
||||
for (i = 0; i < m_uPatches; i++)
|
||||
m_Patches[i] = new TerrainPatch[m_vPatches];
|
||||
|
||||
int uCount = GetCountU(), vCount = GetCountV();
|
||||
|
||||
m_pControl = new float*[uCount];
|
||||
for (i = 0; i < uCount; i++)
|
||||
{
|
||||
m_pControl[i] = new float[vCount*3];
|
||||
memcpy(m_pControl[i], source.m_pControl[i], vCount*3*sizeof(float));
|
||||
}
|
||||
|
||||
m_uSize = source.m_uSize;
|
||||
m_vSize = source.m_vSize;
|
||||
|
||||
SetControlPoints();
|
||||
Tesselate();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Terrain::GetSize(float *uSize, float *vSize)
|
||||
{
|
||||
*uSize = m_uSize;
|
||||
*vSize = m_vSize;
|
||||
}
|
||||
|
||||
void Terrain::SetSize(float uSize, float vSize)
|
||||
{
|
||||
m_uSize = uSize;
|
||||
m_vSize = vSize;
|
||||
|
||||
int i, j, uCount = GetCountU(), vCount = GetCountV();
|
||||
|
||||
for (i = 0; i < uCount; i++)
|
||||
for (j = 0; j < vCount; j++)
|
||||
{
|
||||
m_pControl[i][j*3] = m_uSize * ((float)i/(uCount-1)-0.5f);
|
||||
m_pControl[i][j*3+1] = m_vSize * ((float)j/(vCount-1)-0.5f);
|
||||
}
|
||||
|
||||
SetControlPoints();
|
||||
Tesselate();
|
||||
}
|
||||
|
||||
void Terrain::GetPatchCount(int *uCount, int *vCount)
|
||||
{
|
||||
*uCount = m_uPatches;
|
||||
*vCount = m_vPatches;
|
||||
}
|
||||
|
||||
void Terrain::SetPatchCount(int uPatches, int vPatches)
|
||||
{
|
||||
if (uPatches == m_uPatches && vPatches == m_vPatches)
|
||||
return;
|
||||
|
||||
float** oldControl = m_pControl;
|
||||
int i, j, uCount = uPatches*3+1, vCount = vPatches*3+1;
|
||||
int uCountOld = m_uPatches != 0 ? m_uPatches*3+1 : 0, vCountOld = m_vPatches != 0 ? m_vPatches*3+1 : 0;
|
||||
|
||||
// allocate new arrays
|
||||
// if (uPatches != m_uPatches)
|
||||
m_pControl = new float*[uCount];
|
||||
|
||||
if (m_vPatches != vPatches)
|
||||
{
|
||||
for (i = 0; i < uCount; i++)
|
||||
m_pControl[i] = new float[vCount*3];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; (i < uCount) && (i < uCountOld); i++)
|
||||
m_pControl[i] = oldControl[i];
|
||||
for (i = uCountOld; i < uCount; i++)
|
||||
m_pControl[i] = new float[vCount*3];
|
||||
}
|
||||
|
||||
// set the points
|
||||
for (i = 0; i < uCount; i++)
|
||||
{
|
||||
for (j = 0; j < vCount; j++)
|
||||
{
|
||||
m_pControl[i][j*3] = m_uSize * ((float)i/(uCount-1)-0.5f);
|
||||
m_pControl[i][j*3+1] = m_vSize * ((float)j/(vCount-1)-0.5f);
|
||||
|
||||
if (i < uCountOld && j < vCountOld)
|
||||
m_pControl[i][j*3+2] = oldControl[i][j*3+2];
|
||||
else
|
||||
m_pControl[i][j*3+2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_vPatches != vPatches)
|
||||
{
|
||||
for (i = 0; i < uCountOld; i++)
|
||||
delete[] oldControl[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = uCount; i < uCountOld; i++)
|
||||
delete[] oldControl[i];
|
||||
}
|
||||
|
||||
// if ((uPatches != m_uPatches) && (oldControl != NULL))
|
||||
delete[] oldControl;
|
||||
|
||||
if (m_Patches)
|
||||
{
|
||||
for (i = 0; i < m_uPatches; i++)
|
||||
{
|
||||
for (j = 0; j < m_vPatches; j++)
|
||||
m_Patches[i][j].FreeMemory();
|
||||
|
||||
delete[] m_Patches[i];
|
||||
}
|
||||
|
||||
delete[] m_Patches;
|
||||
}
|
||||
|
||||
m_uPatches = uPatches;
|
||||
m_vPatches = vPatches;
|
||||
|
||||
m_Patches = new TerrainPatch*[m_uPatches];
|
||||
for (i = 0; i < m_uPatches; i++)
|
||||
m_Patches[i] = new TerrainPatch[m_vPatches];
|
||||
|
||||
SetControlPoints();
|
||||
Tesselate();
|
||||
}
|
||||
|
||||
// Set the control points for each patch
|
||||
void Terrain::SetControlPoints()
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < m_uPatches; i++)
|
||||
for (j = 0; j < m_vPatches; j++)
|
||||
{
|
||||
///////////
|
||||
m_Patches[i][j].FreeMemory();
|
||||
|
||||
float minX = 9999999, maxX = -9999999, minY = 9999999, maxY = -9999999, minZ = 9999999, maxZ = -9999999;
|
||||
|
||||
for (int a = 0; a < 4; a++)
|
||||
for (int b = 0; b < 4; b++)
|
||||
{
|
||||
m_Patches[i][j].control[(a*4+b)*3] = m_pControl[i*(4-1)+a][(j*(4-1)+b)*3];
|
||||
m_Patches[i][j].control[(a*4+b)*3+1] = m_pControl[i*(4-1)+a][(j*(4-1)+b)*3+1];
|
||||
m_Patches[i][j].control[(a*4+b)*3+2] = m_pControl[i*(4-1)+a][(j*(4-1)+b)*3+2];
|
||||
|
||||
minX = min(minX, m_Patches[i][j].control[(a*4+b)*3]);
|
||||
maxX = max(maxX, m_Patches[i][j].control[(a*4+b)*3]);
|
||||
minY = min(minY, m_Patches[i][j].control[(a*4+b)*3+1]);
|
||||
maxY = max(maxY, m_Patches[i][j].control[(a*4+b)*3+1]);
|
||||
minZ = min(minZ, m_Patches[i][j].control[(a*4+b)*3+2]);
|
||||
maxZ = max(maxZ, m_Patches[i][j].control[(a*4+b)*3+2]);
|
||||
}
|
||||
m_Patches[i][j].InitBox(minX, maxX, minY, maxY, minZ, maxZ);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate mesh and store for later use.
|
||||
void Terrain::Tesselate()
|
||||
{
|
||||
int i, j, a, steps = 10;
|
||||
float x, y, z, inv;
|
||||
|
||||
for (i = 0; i < m_uPatches; i++)
|
||||
for (j = 0; j < m_vPatches; j++)
|
||||
m_Patches[i][j].Tesselate((m_nOptions & LC_TERRAIN_SMOOTH) != 0);
|
||||
|
||||
if ((m_nOptions & LC_TERRAIN_SMOOTH) != 0)
|
||||
{
|
||||
// fix normals at +u
|
||||
for (i = 0; i < m_uPatches-1; i++)
|
||||
for (j = 0; j < m_vPatches; j++)
|
||||
for (a = 0; a < steps; a++)
|
||||
{
|
||||
x = m_Patches[i][j].normals[((steps-1)*steps+a)*3] + m_Patches[i+1][j].normals[a*3];
|
||||
y = m_Patches[i][j].normals[((steps-1)*steps+a)*3+1] + m_Patches[i+1][j].normals[a*3+1];
|
||||
z = m_Patches[i][j].normals[((steps-1)*steps+a)*3+2] + m_Patches[i+1][j].normals[a*3+2];
|
||||
|
||||
inv = 1.0f / (float)sqrt(x*x + y*y + z*z);
|
||||
x *= inv;
|
||||
y *= inv;
|
||||
z *= inv;
|
||||
|
||||
m_Patches[i][j].normals[((steps-1)*steps+a)*3] = x;
|
||||
m_Patches[i][j].normals[((steps-1)*steps+a)*3+1] = y;
|
||||
m_Patches[i][j].normals[((steps-1)*steps+a)*3+2] = z;
|
||||
m_Patches[i+1][j].normals[a*3] = x;
|
||||
m_Patches[i+1][j].normals[a*3+1] = y;
|
||||
m_Patches[i+1][j].normals[a*3+2] = z;
|
||||
}
|
||||
|
||||
// and at +v
|
||||
for (i = 0; i < m_uPatches; i++)
|
||||
for (j = 0; j < m_vPatches-1; j++)
|
||||
for (a = 0; a < steps; a++)
|
||||
{
|
||||
x = m_Patches[i][j].normals[((steps-1)+a*steps)*3] + m_Patches[i][j+1].normals[(a*steps)*3];
|
||||
y = m_Patches[i][j].normals[((steps-1)+a*steps)*3+1] + m_Patches[i][j+1].normals[(a*steps)*3+1];
|
||||
z = m_Patches[i][j].normals[((steps-1)+a*steps)*3+2] + m_Patches[i][j+1].normals[(a*steps)*3+2];
|
||||
|
||||
inv = 1.0f / (float)sqrt(x*x + y*y + z*z);
|
||||
x *= inv;
|
||||
y *= inv;
|
||||
z *= inv;
|
||||
|
||||
m_Patches[i][j].normals[((steps-1)+a*steps)*3] = x;
|
||||
m_Patches[i][j].normals[((steps-1)+a*steps)*3+1] = y;
|
||||
m_Patches[i][j].normals[((steps-1)+a*steps)*3+2] = z;
|
||||
m_Patches[i][j+1].normals[(a*steps)*3] = x;
|
||||
m_Patches[i][j+1].normals[(a*steps)*3+1] = y;
|
||||
m_Patches[i][j+1].normals[(a*steps)*3+2] = z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Terrain::Render(Camera* pCam, float aspect)
|
||||
{
|
||||
if (m_nOptions & LC_TERRAIN_FLAT)
|
||||
{
|
||||
float eye[3];
|
||||
pCam->GetEyePos(eye);
|
||||
glPushMatrix();
|
||||
glTranslatef(eye[0], eye[1], 0);
|
||||
glScalef(pCam->m_zFar, pCam->m_zFar, 1);
|
||||
|
||||
if (m_nOptions & LC_TERRAIN_TEXTURE)
|
||||
{
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
m_pTexture->MakeCurrent();
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
float tw = 15.0f, th = 15.0f;
|
||||
// tw = 2*pCam->m_zFar/m_nBackgroundSize;
|
||||
// th = 2*pCam->m_zFar/m_nBackgroundSize;
|
||||
|
||||
float tx, ty;
|
||||
tx = (tw*eye[0])/(2*pCam->m_zFar);
|
||||
ty = (th*eye[1])/(2*pCam->m_zFar);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(tx, ty);
|
||||
glVertex2f(-1, -1);
|
||||
glTexCoord2f(tx+tw, ty);
|
||||
glVertex2f(1, -1);
|
||||
glTexCoord2f(tx+tw, ty+th);
|
||||
glVertex2f(1, 1);
|
||||
glTexCoord2f(tx, ty+th);
|
||||
glVertex2f(-1, 1);
|
||||
glEnd();
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
else
|
||||
{
|
||||
glColor3fv(m_fColor);
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2f(-1, -1);
|
||||
glVertex2f(1, -1);
|
||||
glVertex2f(1, 1);
|
||||
glVertex2f(-1, 1);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
else
|
||||
{
|
||||
FindVisiblePatches(pCam, aspect);
|
||||
|
||||
int i, j;
|
||||
glColor3fv(m_fColor);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (m_nOptions & LC_TERRAIN_TEXTURE)
|
||||
{
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
m_pTexture->MakeCurrent();
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
if (m_nOptions & LC_TERRAIN_SMOOTH)
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
for (i = 0; i < m_uPatches; i++)
|
||||
for (j = 0; j < m_vPatches; j++)
|
||||
if (m_Patches[i][j].visible)
|
||||
{
|
||||
glVertexPointer(3, GL_FLOAT, 0, m_Patches[i][j].vertex);
|
||||
|
||||
if (m_nOptions & LC_TERRAIN_SMOOTH)
|
||||
glNormalPointer(GL_FLOAT, 0, m_Patches[i][j].normals);
|
||||
|
||||
if (m_nOptions & LC_TERRAIN_TEXTURE)
|
||||
glTexCoordPointer(2, GL_FLOAT, 0, m_Patches[i][j].coords);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, (m_Patches[i][j].steps-1)*(m_Patches[i][j].steps-1)*6, GL_UNSIGNED_SHORT, m_Patches[i][j].index);
|
||||
}
|
||||
|
||||
if (m_nOptions & LC_TERRAIN_SMOOTH)
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
if (m_nOptions & LC_TERRAIN_TEXTURE)
|
||||
{
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Terrain::FindVisiblePatches(Camera* pCam, float aspect)
|
||||
{
|
||||
// Get camera position information.
|
||||
float eye[3];
|
||||
pCam->GetEyePos(eye);
|
||||
|
||||
// Get perspective information.
|
||||
float alpha = pCam->m_fovy / 2.0f;
|
||||
float halfFovY = pCam->m_fovy / 2.0f;
|
||||
halfFovY = halfFovY * 3.1415f / 180.0f;
|
||||
float halfFovX = (float)atan(tan(halfFovY) * aspect);
|
||||
halfFovX = halfFovX * 180.0f / 3.1415f;
|
||||
float beta = 2.0f * halfFovX;
|
||||
|
||||
// Get vector stuff from the position.
|
||||
float nonOrthoTop[3], target[3];
|
||||
pCam->GetUpVec(nonOrthoTop);
|
||||
pCam->GetTargetPos(target);
|
||||
float front[3] = { target[0] - eye[0], target[1] - eye[1], target[2] - eye[2]};
|
||||
float side[3];
|
||||
side[0] = nonOrthoTop[1]*front[2] - nonOrthoTop[2]*front[1];
|
||||
side[1] = nonOrthoTop[2]*front[0] - nonOrthoTop[0]*front[2];
|
||||
side[2] = nonOrthoTop[0]*front[1] - nonOrthoTop[1]*front[0];
|
||||
|
||||
// Make sure our up vector is orthogonal.
|
||||
float top[3];
|
||||
top[0] = front[1]*side[2] - front[2]*side[1];
|
||||
top[1] = front[2]*side[0] - front[0]*side[2];
|
||||
top[2] = front[0]*side[1] - front[1]*side[0];
|
||||
|
||||
// Get our plane normals.
|
||||
Matrix mat;
|
||||
float topNormal[3] = { -top[0], -top[1], -top[2] };
|
||||
mat.FromAxisAngle(side, -alpha);
|
||||
mat.TransformPoints(topNormal, 1);
|
||||
|
||||
float bottomNormal[3] = { top[0], top[1], top[2] };
|
||||
mat.FromAxisAngle(side, alpha);
|
||||
mat.TransformPoints(bottomNormal, 1);
|
||||
|
||||
float rightNormal[3] = { side[0], side[1], side[2] };
|
||||
mat.FromAxisAngle(top, -beta);
|
||||
mat.TransformPoints(rightNormal, 1);
|
||||
|
||||
float leftNormal[3] = { -side[0], -side[1], -side[2] };
|
||||
mat.FromAxisAngle(top, beta);
|
||||
mat.TransformPoints(leftNormal, 1);
|
||||
|
||||
float nearNormal[3] = { front[0], front[1], front[2] };
|
||||
|
||||
// Now calculate our plane offsets from the normals and the eye position.
|
||||
float topD = eye[0]*-topNormal[0] + eye[1]*-topNormal[1] + eye[2]*-topNormal[2];
|
||||
float bottomD = eye[0]*-bottomNormal[0] + eye[1]*-bottomNormal[1] + eye[2]*-bottomNormal[2];
|
||||
float leftD = eye[0]*-leftNormal[0] + eye[1]*-leftNormal[1] + eye[2]*-leftNormal[2];
|
||||
float rightD = eye[0]*-rightNormal[0] + eye[1]*-rightNormal[1] + eye[2]*-rightNormal[2];
|
||||
float nearD = eye[0]*-nearNormal[0] + eye[1]*-nearNormal[1] + eye[2]*-nearNormal[2];
|
||||
|
||||
// For the far plane, find the point farDist away from the eye along the front vector.
|
||||
float farDist = pCam->m_zFar;
|
||||
float farPt[3] = { front[0], front[1], front[2] };
|
||||
float invR = farDist/(float)sqrt(farPt[0]*farPt[0]+farPt[1]*farPt[1]+farPt[2]*farPt[2]);
|
||||
farPt[0] = farPt[0]*invR;
|
||||
farPt[1] = farPt[1]*invR;
|
||||
farPt[2] = farPt[2]*invR;
|
||||
farPt[0] += eye[0];
|
||||
farPt[1] += eye[1];
|
||||
farPt[2] += eye[2];
|
||||
float farD = farPt[0]*nearNormal[0] + farPt[1]*nearNormal[1] + farPt[2]*nearNormal[2];
|
||||
|
||||
// Now generate the planes
|
||||
invR = 1.0f/(float)sqrt(topNormal[0]*topNormal[0]+topNormal[1]*topNormal[1]+topNormal[2]*topNormal[2]);
|
||||
float topPlane[4] = { topNormal[0]*invR, topNormal[1]*invR, topNormal[2]*invR, topD*invR };
|
||||
invR = 1.0f/(float)sqrt(bottomNormal[0]*bottomNormal[0]+bottomNormal[1]*bottomNormal[1]+bottomNormal[2]*bottomNormal[2]);
|
||||
float bottomPlane[4] = { bottomNormal[0]*invR, bottomNormal[1]*invR, bottomNormal[2]*invR, bottomD*invR };
|
||||
invR = 1.0f/(float)sqrt(leftNormal[0]*leftNormal[0]+leftNormal[1]*leftNormal[1]+leftNormal[2]*leftNormal[2]);
|
||||
float leftPlane[4] = { leftNormal[0]*invR, leftNormal[1]*invR, leftNormal[2]*invR, leftD*invR };
|
||||
invR = 1.0f/(float)sqrt(rightNormal[0]*rightNormal[0]+rightNormal[1]*rightNormal[1]+rightNormal[2]*rightNormal[2]);
|
||||
float rightPlane[4] = { rightNormal[0]*invR, rightNormal[1]*invR, rightNormal[2]*invR, rightD*invR };
|
||||
invR = 1.0f/(float)sqrt(nearNormal[0]*nearNormal[0]+nearNormal[1]*nearNormal[1]+nearNormal[2]*nearNormal[2]);
|
||||
float nearPlane[4] = { nearNormal[0]*invR, nearNormal[1]*invR, nearNormal[2]*invR, nearD*invR };
|
||||
invR = 1.0f/(float)sqrt(-nearNormal[0]*-nearNormal[0]+-nearNormal[1]*-nearNormal[1]+-nearNormal[2]*-nearNormal[2]);
|
||||
float farPlane[4] = { -nearNormal[0]*invR, -nearNormal[1]*invR, -nearNormal[2]*invR, farD*invR };
|
||||
|
||||
for (int i = 0; i < m_uPatches; i++)
|
||||
{
|
||||
for (int j = 0; j < m_vPatches; j++)
|
||||
{
|
||||
m_Patches[i][j].visible = true;
|
||||
|
||||
if (m_Patches[i][j].BoxIsOutside(leftPlane))
|
||||
{
|
||||
m_Patches[i][j].visible = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_Patches[i][j].BoxIsOutside(rightPlane))
|
||||
{
|
||||
m_Patches[i][j].visible = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_Patches[i][j].BoxIsOutside(nearPlane))
|
||||
{
|
||||
m_Patches[i][j].visible = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_Patches[i][j].BoxIsOutside(farPlane))
|
||||
{
|
||||
m_Patches[i][j].visible = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_Patches[i][j].BoxIsOutside(bottomPlane))
|
||||
{
|
||||
m_Patches[i][j].visible = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_Patches[i][j].BoxIsOutside(topPlane))
|
||||
{
|
||||
m_Patches[i][j].visible = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Terrain::LoadDefaults(bool bLinear)
|
||||
{
|
||||
unsigned long rgb = Sys_ProfileLoadInt ("Default", "Floor", RGB (0,191,0));
|
||||
m_fColor[0] = (float)((unsigned char) (rgb))/255;
|
||||
m_fColor[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255;
|
||||
m_fColor[2] = (float)((unsigned char) ((rgb) >> 16))/255;
|
||||
|
||||
m_uSize = 50;
|
||||
m_vSize = 50;
|
||||
|
||||
strcpy (m_strTexture, Sys_ProfileLoadString ("Default", "FloorBMP", ""));
|
||||
m_pTexture->Unload();
|
||||
|
||||
m_nOptions = LC_TERRAIN_FLAT;
|
||||
if (strlen(m_strTexture))
|
||||
{
|
||||
m_nOptions |= LC_TERRAIN_TEXTURE;
|
||||
LoadTexture(bLinear);
|
||||
}
|
||||
|
||||
SetPatchCount(4, 4);
|
||||
|
||||
for (int i = 0; i < 13; i++)
|
||||
for (int j = 0; j < 13; j++)
|
||||
{
|
||||
m_pControl[i][j*3] = m_uSize * ((float)i/12-0.5f);
|
||||
m_pControl[i][j*3+1] = m_vSize * ((float)j/12-0.5f);
|
||||
m_pControl[i][j*3+2] = 0;
|
||||
}
|
||||
|
||||
SetControlPoints();
|
||||
Tesselate();
|
||||
}
|
||||
|
||||
void Terrain::LoadTexture(bool bLinear)
|
||||
{
|
||||
m_pTexture->Unload();
|
||||
|
||||
if ((m_nOptions & LC_TERRAIN_TEXTURE) == 0)
|
||||
return;
|
||||
|
||||
if (m_pTexture->LoadFromFile(m_strTexture, bLinear) == false)
|
||||
{
|
||||
// AfxMessageBox("Could not load terrain texture.", MB_OK|MB_ICONEXCLAMATION);
|
||||
m_nOptions &= ~LC_TERRAIN_TEXTURE;
|
||||
}
|
||||
}
|
||||
|
||||
void Terrain::GenerateRandom()
|
||||
{
|
||||
srand((unsigned)time(NULL));
|
||||
|
||||
int uCount = (m_uPatches*3)+1, vCount = (m_vPatches*3)+1;
|
||||
|
||||
for (int i = 0; i < uCount; i++)
|
||||
for (int j = 0; j < vCount; j++)
|
||||
{
|
||||
m_pControl[i][j*3] = m_uSize * ((float)i/(uCount-1)-0.5f);
|
||||
m_pControl[i][j*3+1] = m_vSize * ((float)j/(vCount-1)-0.5f);
|
||||
m_pControl[i][j*3+2] = (((float)rand()/(float)RAND_MAX) - 0.5f) * 8;
|
||||
}
|
||||
|
||||
SetControlPoints();
|
||||
Tesselate();
|
||||
}
|
83
common/terrain.h
Normal file
83
common/terrain.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// terrain.h
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _TERRAIN_H_
|
||||
#define _TERRAIN_H_
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
class File;
|
||||
class Camera;
|
||||
class Texture;
|
||||
|
||||
class TerrainPatch
|
||||
{
|
||||
public:
|
||||
TerrainPatch ();
|
||||
~TerrainPatch ();
|
||||
|
||||
float control[48]; // 4x4 grid
|
||||
unsigned short steps;
|
||||
|
||||
float* vertex;
|
||||
float* normals;
|
||||
float* coords;
|
||||
unsigned short* index;
|
||||
|
||||
bool visible;
|
||||
|
||||
void InitBox(float minX, float maxX, float minY, float maxY, float minZ, float maxZ);
|
||||
bool BoxIsOutside(const float plane[4]) const;
|
||||
void Tesselate(bool bNormals);
|
||||
void FreeMemory();
|
||||
|
||||
protected:
|
||||
float corners[8][3];
|
||||
};
|
||||
|
||||
class Terrain
|
||||
{
|
||||
public:
|
||||
Terrain();
|
||||
~Terrain();
|
||||
Terrain& operator=(const Terrain& source);
|
||||
|
||||
void LoadTexture(bool bLinear);
|
||||
void Render(Camera* pCam, float aspect);
|
||||
void LoadDefaults(bool bLinear);
|
||||
void SetSize(float uSize, float vSize);
|
||||
void GetSize(float *uSize, float *vSize);
|
||||
void FileLoad(File* file);
|
||||
void FileSave(File* file);
|
||||
void Tesselate();
|
||||
void SetControlPoints();
|
||||
void GenerateRandom();
|
||||
|
||||
void SetPatchCount(int uPatches, int vPatches);
|
||||
void GetPatchCount(int *uCount, int *vCount);
|
||||
int GetCountU()
|
||||
{ return m_uPatches != 0 ? m_uPatches*3 + 1 : 0; }
|
||||
int GetCountV()
|
||||
{ return m_vPatches != 0 ? m_vPatches*3 + 1 : 0; }
|
||||
float** GetControlPoints()
|
||||
{ return m_pControl; }
|
||||
|
||||
unsigned long m_nOptions;
|
||||
char m_strTexture[LC_MAXPATH];
|
||||
float m_fColor[3];
|
||||
|
||||
protected:
|
||||
void FreeMemory();
|
||||
void FindVisiblePatches(Camera* pCam, float aspect);
|
||||
|
||||
float** m_pControl;
|
||||
TerrainPatch** m_Patches;
|
||||
int m_uPatches;
|
||||
int m_vPatches;
|
||||
float m_uSize;
|
||||
float m_vSize;
|
||||
Texture* m_pTexture;
|
||||
};
|
||||
|
||||
#endif // _TERRAIN_H_
|
160
common/texfont.cpp
Normal file
160
common/texfont.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
//
|
||||
// Texture Font
|
||||
//
|
||||
|
||||
#include "globals.h"
|
||||
#include "project.h"
|
||||
#include "texfont.h"
|
||||
#include "texture.h"
|
||||
#include "library.h"
|
||||
#include "file.h"
|
||||
#include "lc_application.h"
|
||||
|
||||
#define LC_TEXFONT_FILE_VERSION 1 // LeoCAD 0.74
|
||||
#define LC_TEXFONT_FILE_HEADER "LeoCAD Texture Font\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
|
||||
// ============================================================================
|
||||
|
||||
TexFont::TexFont ()
|
||||
{
|
||||
m_bLoaded = false;
|
||||
m_pTexture = NULL;
|
||||
|
||||
memset (&m_Glyphs, 0, sizeof (m_Glyphs));
|
||||
}
|
||||
|
||||
TexFont::~TexFont ()
|
||||
{
|
||||
if (m_pTexture != NULL)
|
||||
m_pTexture->DeRef ();
|
||||
}
|
||||
|
||||
bool TexFont::FileLoad (File& file)
|
||||
{
|
||||
unsigned char version;
|
||||
char buf[64];
|
||||
|
||||
if (m_bLoaded)
|
||||
{
|
||||
console.PrintError ("Texture font already loaded.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
file.Read (buf, 32);
|
||||
if (strncmp (buf, LC_TEXFONT_FILE_HEADER, 32) != 0)
|
||||
{
|
||||
console.PrintError ("Texture font file header mismatch.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
file.ReadByte (&version, 1);
|
||||
if (version > LC_TEXFONT_FILE_VERSION)
|
||||
{
|
||||
console.PrintError ("Wrong version of texture font file.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
memset (buf, 0, 32);
|
||||
file.Read (buf, 8);
|
||||
|
||||
m_pTexture = lcGetPiecesLibrary()->FindTexture (buf);
|
||||
if (m_pTexture == NULL)
|
||||
{
|
||||
console.PrintError ("Cannot find texture for font %s.\n", buf);
|
||||
return false;
|
||||
}
|
||||
m_pTexture->AddRef (false);
|
||||
|
||||
file.ReadByte (&m_nFontHeight, 1);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
unsigned char glyph;
|
||||
|
||||
file.ReadByte (&glyph, 1);
|
||||
|
||||
if (glyph == 0)
|
||||
break;
|
||||
|
||||
file.ReadByte (&m_Glyphs[glyph].width, 1);
|
||||
file.ReadFloat (&m_Glyphs[glyph].left, 1);
|
||||
file.ReadFloat (&m_Glyphs[glyph].right, 1);
|
||||
file.ReadFloat (&m_Glyphs[glyph].top, 1);
|
||||
file.ReadFloat (&m_Glyphs[glyph].bottom, 1);
|
||||
|
||||
m_Glyphs[glyph].left /= m_pTexture->m_nWidth;
|
||||
m_Glyphs[glyph].right /= m_pTexture->m_nWidth;
|
||||
m_Glyphs[glyph].top /= m_pTexture->m_nHeight;
|
||||
m_Glyphs[glyph].bottom /= m_pTexture->m_nHeight;
|
||||
}
|
||||
|
||||
m_bLoaded = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TexFont::GetStringDimensions(int* cx, int* cy, const char* Text) const
|
||||
{
|
||||
*cx = 0;
|
||||
*cy = m_nFontHeight;
|
||||
|
||||
while (*Text != 0)
|
||||
{
|
||||
*cx += m_Glyphs[(int)(*Text)].width;
|
||||
Text++;
|
||||
}
|
||||
}
|
||||
|
||||
void TexFont::PrintText(float Left, float Top, float ScaleX, float ScaleY, const char* Text) const
|
||||
{
|
||||
float Height = m_nFontHeight * ScaleY;
|
||||
|
||||
while (*Text != 0)
|
||||
{
|
||||
int ch = *Text;
|
||||
glTexCoord2f(m_Glyphs[ch].left, m_Glyphs[ch].top);
|
||||
glVertex2f(Left, Top);
|
||||
glTexCoord2f(m_Glyphs[ch].left, m_Glyphs[ch].bottom);
|
||||
glVertex2f(Left, Top - Height);
|
||||
glTexCoord2f(m_Glyphs[ch].right, m_Glyphs[ch].bottom);
|
||||
glVertex2f(Left + m_Glyphs[ch].width * ScaleX, Top - Height);
|
||||
glTexCoord2f(m_Glyphs[ch].right, m_Glyphs[ch].top);
|
||||
glVertex2f(Left + m_Glyphs[ch].width * ScaleX, Top);
|
||||
|
||||
Left += m_Glyphs[ch].width * ScaleX;
|
||||
Text++;
|
||||
}
|
||||
}
|
||||
|
||||
// Old function, should probably be removed.
|
||||
void TexFont::PrintText(float Left, float Top, float Z, const char* Text) const
|
||||
{
|
||||
while (*Text != 0)
|
||||
{
|
||||
int ch = *Text;
|
||||
glTexCoord2f(m_Glyphs[ch].left, m_Glyphs[ch].top);
|
||||
glVertex3f(Left, Top, Z);
|
||||
glTexCoord2f(m_Glyphs[ch].left, m_Glyphs[ch].bottom);
|
||||
glVertex3f(Left, Top - m_nFontHeight, Z);
|
||||
glTexCoord2f(m_Glyphs[ch].right, m_Glyphs[ch].bottom);
|
||||
glVertex3f(Left + m_Glyphs[ch].width, Top - m_nFontHeight, Z);
|
||||
glTexCoord2f(m_Glyphs[ch].right, m_Glyphs[ch].top);
|
||||
glVertex3f(Left + m_Glyphs[ch].width, Top, Z);
|
||||
|
||||
Left += m_Glyphs[ch].width;
|
||||
Text++;
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary function to draw the axis icon text
|
||||
void TexFont::PrintCharScaled (float scale, int ch) const
|
||||
{
|
||||
glTexCoord2f (m_Glyphs[ch].left, m_Glyphs[ch].top);
|
||||
glVertex2f (-scale * m_Glyphs[ch].width, scale * m_nFontHeight);
|
||||
glTexCoord2f (m_Glyphs[ch].left, m_Glyphs[ch].bottom);
|
||||
glVertex2f (-scale * m_Glyphs[ch].width, -scale * m_nFontHeight);
|
||||
glTexCoord2f (m_Glyphs[ch].right, m_Glyphs[ch].bottom);
|
||||
glVertex2f (scale * m_Glyphs[ch].width, -scale * m_nFontHeight);
|
||||
glTexCoord2f (m_Glyphs[ch].right, m_Glyphs[ch].top);
|
||||
glVertex2f (scale * m_Glyphs[ch].width, scale * m_nFontHeight);
|
||||
}
|
38
common/texfont.h
Normal file
38
common/texfont.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#ifndef _TEXFONT_H_
|
||||
#define _TEXFONT_H_
|
||||
|
||||
class File;
|
||||
class Texture;
|
||||
|
||||
#include "texture.h"
|
||||
|
||||
class TexFont
|
||||
{
|
||||
public:
|
||||
TexFont ();
|
||||
~TexFont ();
|
||||
|
||||
bool IsLoaded () const
|
||||
{ return m_bLoaded; }
|
||||
void MakeCurrent ()
|
||||
{ if (m_bLoaded) m_pTexture->MakeCurrent (); }
|
||||
|
||||
bool FileLoad(File& file);
|
||||
void PrintText(float left, float top, float z, const char* text) const;
|
||||
void PrintText(float Left, float Top, float ScaleX, float ScaleY, const char* Text) const;
|
||||
void PrintCharScaled(float scale, int ch) const;
|
||||
void GetStringDimensions(int* cx, int* cy, const char* Text) const;
|
||||
|
||||
protected:
|
||||
struct
|
||||
{
|
||||
unsigned char width;
|
||||
float left, right, top, bottom;
|
||||
} m_Glyphs[256];
|
||||
|
||||
Texture* m_pTexture;
|
||||
unsigned char m_nFontHeight;
|
||||
bool m_bLoaded;
|
||||
};
|
||||
|
||||
#endif // _TEXFONT_H_
|
271
common/texture.cpp
Normal file
271
common/texture.cpp
Normal file
|
@ -0,0 +1,271 @@
|
|||
// Texture object.
|
||||
//
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "opengl.h"
|
||||
#include "file.h"
|
||||
#include "texture.h"
|
||||
#include "project.h"
|
||||
#include "globals.h"
|
||||
#include "image.h"
|
||||
#include "library.h"
|
||||
#include "lc_application.h"
|
||||
|
||||
// =============================================================================
|
||||
// Static functions
|
||||
|
||||
static void* ResizeImage (GLubyte* old_image, int components, int srcw, int srch, int destw, int desth)
|
||||
{
|
||||
int i, j, k;
|
||||
float sx, sy;
|
||||
GLubyte* new_image;
|
||||
|
||||
new_image = (GLubyte*)malloc (destw*desth*components*sizeof(GLubyte));
|
||||
if (new_image == NULL)
|
||||
return NULL;
|
||||
|
||||
if (destw > 1)
|
||||
sx = (GLfloat) (srcw-1) / (GLfloat) (destw-1);
|
||||
else
|
||||
sx = (GLfloat) (srcw-1);
|
||||
if (desth > 1)
|
||||
sy = (GLfloat) (srch-1) / (GLfloat) (desth-1);
|
||||
else
|
||||
sy = (GLfloat) (srch-1);
|
||||
|
||||
for (i = 0; i < desth; i++)
|
||||
{
|
||||
GLint ii = (GLint)(i * sy);
|
||||
for (j = 0; j < destw; j++)
|
||||
{
|
||||
GLint jj = (GLint)(j * sx);
|
||||
GLubyte *src = old_image + (ii * srcw + jj) * components;
|
||||
GLubyte *dst = new_image + (i * destw + j) * components;
|
||||
|
||||
for (k = 0; k < components; k++)
|
||||
*dst++ = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
return new_image;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Texture construction/destruction
|
||||
|
||||
// Only called for the background image, use LoadIndex()
|
||||
Texture::Texture()
|
||||
{
|
||||
m_nRef = 1;
|
||||
m_nID = 0;
|
||||
}
|
||||
|
||||
Texture::~Texture()
|
||||
{
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Texture attributes
|
||||
|
||||
void Texture::AddRef(bool bFilter)
|
||||
{
|
||||
if (m_nRef == 0)
|
||||
Load(bFilter);
|
||||
|
||||
m_nRef++;
|
||||
}
|
||||
|
||||
void Texture::DeRef()
|
||||
{
|
||||
m_nRef--;
|
||||
if (m_nRef == 0)
|
||||
Unload();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Load methods
|
||||
|
||||
void Texture::LoadIndex(File* idx)
|
||||
{
|
||||
unsigned char bt;
|
||||
|
||||
// TODO: don't change ref. if reloading
|
||||
m_nRef = 0;
|
||||
m_nID = 0;
|
||||
|
||||
idx->Read(m_strName, 8);
|
||||
idx->ReadShort(&m_nWidth, 1);
|
||||
idx->ReadShort(&m_nHeight, 1);
|
||||
idx->ReadByte(&bt, 1);
|
||||
|
||||
switch (bt)
|
||||
{
|
||||
case LC_INTENSITY:
|
||||
m_nFormat = GL_LUMINANCE_ALPHA;
|
||||
m_nFileSize = m_nWidth*m_nHeight;
|
||||
break;
|
||||
case LC_RGB:
|
||||
m_nFormat = GL_RGB;
|
||||
m_nFileSize = m_nWidth*m_nHeight*3;
|
||||
break;
|
||||
case LC_RGBA:
|
||||
m_nFormat = GL_RGBA;
|
||||
m_nFileSize = m_nWidth*m_nHeight*4;
|
||||
break;
|
||||
}
|
||||
|
||||
idx->ReadLong(&m_nOffset, 1);
|
||||
}
|
||||
|
||||
void Texture::Unload()
|
||||
{
|
||||
if (m_nID != 0)
|
||||
glDeleteTextures(1, &m_nID);
|
||||
m_nID = 0;
|
||||
}
|
||||
|
||||
// Load from textures.bin file
|
||||
void Texture::Load(bool bFilter)
|
||||
{
|
||||
char filename[LC_MAXPATH];
|
||||
FileDisk bin;
|
||||
void* bits;
|
||||
|
||||
strcpy(filename, lcGetPiecesLibrary()->GetLibraryPath());
|
||||
strcat(filename, "textures.bin");
|
||||
if (!bin.Open(filename, "rb"))
|
||||
return;
|
||||
|
||||
if (m_nFormat == GL_LUMINANCE_ALPHA)
|
||||
bits = malloc (m_nFileSize*2);
|
||||
else
|
||||
bits = malloc (m_nFileSize);
|
||||
|
||||
bin.Seek (m_nOffset, SEEK_SET);
|
||||
bin.Read (bits, m_nFileSize);
|
||||
bin.Close ();
|
||||
|
||||
FinishLoadImage (bFilter, bits);
|
||||
|
||||
free(bits);
|
||||
}
|
||||
|
||||
bool Texture::LoadFromFile (char* strFilename, bool bFilter)
|
||||
{
|
||||
Image image;
|
||||
|
||||
if (image.FileLoad (strFilename))
|
||||
{
|
||||
image.ResizePow2 ();
|
||||
|
||||
m_nWidth = image.Width ();
|
||||
m_nHeight = image.Height ();
|
||||
|
||||
if (image.Alpha ())
|
||||
m_nFormat = GL_RGBA;
|
||||
else
|
||||
m_nFormat = GL_RGB;
|
||||
|
||||
if (FinishLoadImage (bFilter, image.GetData ()) == true)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_nID != 0)
|
||||
{
|
||||
glDeleteTextures(1, &m_nID);
|
||||
m_nID = 0;
|
||||
}
|
||||
|
||||
m_nWidth = 0;
|
||||
m_nHeight = 0;
|
||||
m_nFileSize = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Texture::FinishLoadImage (bool bFilter, void *data)
|
||||
{
|
||||
GLint w, h, level, maxsize;
|
||||
GLint i, j, k, pow2;
|
||||
GLint components;
|
||||
|
||||
if (data == NULL || m_nWidth < 1 || m_nHeight < 1)
|
||||
return false;
|
||||
|
||||
if (m_nID == 0)
|
||||
glGenTextures(1, &m_nID);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, m_nID);
|
||||
glDisable(GL_TEXTURE_GEN_S);
|
||||
glDisable(GL_TEXTURE_GEN_T);
|
||||
// glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, bFilter ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, bFilter ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
switch (m_nFormat)
|
||||
{
|
||||
case GL_LUMINANCE_ALPHA: components = 2; break;
|
||||
case GL_RGB: components = 3; break;
|
||||
case GL_RGBA: components = 4; break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
// create an alpha channel for the texture
|
||||
if (m_nFormat == GL_LUMINANCE_ALPHA)
|
||||
for (i = m_nWidth*m_nHeight-1; i >= 0; i--)
|
||||
((GLubyte*)data)[i*2+1] = ((GLubyte*)data)[i*2] = ((GLubyte*)data)[i];
|
||||
|
||||
glGetIntegerv (GL_MAX_TEXTURE_SIZE, &maxsize);
|
||||
|
||||
for (pow2 = 1; pow2 < m_nWidth; pow2 = pow2 << 1);
|
||||
w = (pow2 == m_nWidth) ? m_nWidth : (pow2 << 1);
|
||||
|
||||
for (pow2 = 1; pow2 < m_nHeight; pow2 = pow2 << 1);
|
||||
h = (pow2 == m_nHeight) ? m_nHeight : (pow2 << 1);
|
||||
|
||||
if (w > maxsize) w = maxsize;
|
||||
if (h > maxsize) h = maxsize;
|
||||
|
||||
if (w != m_nWidth || h != m_nHeight)
|
||||
{
|
||||
data = ResizeImage ((GLubyte*)data, components, m_nWidth, m_nHeight, w, h);
|
||||
m_nWidth = w;
|
||||
m_nHeight = h;
|
||||
if (data == NULL)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
void *tmp = malloc (w*h*components);
|
||||
memcpy (tmp, data, w*h*components);
|
||||
data = tmp;
|
||||
}
|
||||
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, components, w, h, 0, m_nFormat, GL_UNSIGNED_BYTE, data);
|
||||
|
||||
if (bFilter)
|
||||
for (level = 1; ((w != 1) || (h != 1)); level++)
|
||||
{
|
||||
GLubyte *out, *in;
|
||||
int row;
|
||||
|
||||
row = w * components;
|
||||
if (w != 1) w >>= 1;
|
||||
if (h != 1) h >>= 1;
|
||||
in = out = (GLubyte*)data;
|
||||
|
||||
for (i = 0; i < h; i++, in+=row)
|
||||
for (j = 0; j < w; j++, out+=components, in+=2*components)
|
||||
for (k = 0; k < components; k++)
|
||||
out[k] = (in[k] + in[k+components] + in[row] + in[row+k+components])>>2;
|
||||
|
||||
glTexImage2D (GL_TEXTURE_2D, level, components, w, h, 0, m_nFormat, GL_UNSIGNED_BYTE, data);
|
||||
}
|
||||
|
||||
free (data);
|
||||
return true;
|
||||
}
|
53
common/texture.h
Normal file
53
common/texture.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// texture.h
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _TEXTURE_H
|
||||
#define _TEXTURE_H
|
||||
|
||||
class File;
|
||||
|
||||
#include "opengl.h"
|
||||
#include "config.h"
|
||||
|
||||
typedef enum { LC_INTENSITY, LC_RGB, LC_RGBA } LC_TEXTURE_TYPES;
|
||||
|
||||
class Texture
|
||||
{
|
||||
public:
|
||||
Texture();
|
||||
~Texture();
|
||||
|
||||
void MakeCurrent()
|
||||
{
|
||||
if (m_nID != 0)
|
||||
glBindTexture(GL_TEXTURE_2D, m_nID);
|
||||
}
|
||||
|
||||
bool IsLoaded()
|
||||
{ return ((m_nID != 0) && (glIsTexture(m_nID) == GL_TRUE)); }
|
||||
void Load(bool bFilter);
|
||||
bool LoadFromFile(char* strFilename, bool bFilter);
|
||||
void Unload();
|
||||
|
||||
void LoadIndex(File* idx);
|
||||
void AddRef(bool bFilter);
|
||||
void DeRef();
|
||||
|
||||
// Read-only
|
||||
char m_strName[9];
|
||||
lcuint16 m_nWidth;
|
||||
lcuint16 m_nHeight;
|
||||
|
||||
protected:
|
||||
bool FinishLoadImage (bool bFilter, void *data);
|
||||
|
||||
int m_nRef;
|
||||
GLuint m_nID;
|
||||
GLenum m_nFormat;
|
||||
lcuint32 m_nOffset;
|
||||
lcuint32 m_nFileSize;
|
||||
};
|
||||
|
||||
|
||||
#endif // _TEXTURE_H
|
325
common/tr.cpp
Normal file
325
common/tr.cpp
Normal file
|
@ -0,0 +1,325 @@
|
|||
// TR.cpp: implementation of the TiledRender class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <math.h>
|
||||
#include "opengl.h"
|
||||
#include "tr.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
TiledRender::TiledRender()
|
||||
{
|
||||
m_TileWidth = 256;
|
||||
m_TileHeight = 256;
|
||||
m_TileBorder = 0;
|
||||
m_RowOrder = TR_BOTTOM_TO_TOP;
|
||||
m_CurrentTile = -1;
|
||||
m_ImageBuffer = 0;
|
||||
m_TileBuffer = 0;
|
||||
}
|
||||
|
||||
TiledRender::~TiledRender()
|
||||
{
|
||||
}
|
||||
|
||||
void TiledRender::TileSize(int width, int height, int border)
|
||||
{
|
||||
m_TileBorder = border;
|
||||
m_TileWidth = width;
|
||||
m_TileHeight = height;
|
||||
m_TileWidthNB = width - 2 * border;
|
||||
m_TileHeightNB = height - 2 * border;
|
||||
}
|
||||
|
||||
void TiledRender::TileBuffer(TRenum format, TRenum type, void *image)
|
||||
{
|
||||
m_TileFormat = format;
|
||||
m_TileType = type;
|
||||
m_TileBuffer = image;
|
||||
}
|
||||
|
||||
void TiledRender::ImageSize(int width, int height)
|
||||
{
|
||||
m_ImageWidth = width;
|
||||
m_ImageHeight = height;
|
||||
}
|
||||
|
||||
void TiledRender::ImageBuffer(TRenum format, TRenum type, void *image)
|
||||
{
|
||||
m_ImageFormat = format;
|
||||
m_ImageType = type;
|
||||
m_ImageBuffer = image;
|
||||
}
|
||||
|
||||
void TiledRender::RowOrder(TRenum order)
|
||||
{
|
||||
if (order == TR_TOP_TO_BOTTOM || order == TR_BOTTOM_TO_TOP)
|
||||
m_RowOrder = order;
|
||||
}
|
||||
|
||||
int TiledRender::Get(TRenum param)
|
||||
{
|
||||
switch (param)
|
||||
{
|
||||
case TR_TILE_WIDTH:
|
||||
return m_TileWidth;
|
||||
case TR_TILE_HEIGHT:
|
||||
return m_TileHeight;
|
||||
case TR_TILE_BORDER:
|
||||
return m_TileBorder;
|
||||
case TR_IMAGE_WIDTH:
|
||||
return m_ImageWidth;
|
||||
case TR_IMAGE_HEIGHT:
|
||||
return m_ImageHeight;
|
||||
case TR_ROWS:
|
||||
return m_Rows;
|
||||
case TR_COLUMNS:
|
||||
return m_Columns;
|
||||
case TR_CURRENT_ROW:
|
||||
if (m_CurrentTile < 0)
|
||||
return -1;
|
||||
else
|
||||
return m_CurrentRow;
|
||||
case TR_CURRENT_COLUMN:
|
||||
if (m_CurrentTile < 0)
|
||||
return -1;
|
||||
else
|
||||
return m_CurrentColumn;
|
||||
case TR_CURRENT_TILE_WIDTH:
|
||||
return m_CurrentTileWidth;
|
||||
case TR_CURRENT_TILE_HEIGHT:
|
||||
return m_CurrentTileHeight;
|
||||
case TR_ROW_ORDER:
|
||||
return (int) m_RowOrder;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TiledRender::Ortho(double left, double right, double bottom, double top, double zNear, double zFar)
|
||||
{
|
||||
if (m_CurrentTile < 0)
|
||||
{
|
||||
m_Perspective = false;
|
||||
m_Left = left;
|
||||
m_Right = right;
|
||||
m_Bottom = bottom;
|
||||
m_Top = top;
|
||||
m_Near = zNear;
|
||||
m_Far = zFar;
|
||||
}
|
||||
}
|
||||
|
||||
void TiledRender::Frustum(double left, double right, double bottom, double top, double zNear, double zFar)
|
||||
{
|
||||
if (m_CurrentTile < 0)
|
||||
{
|
||||
m_Perspective = true;
|
||||
m_Left = left;
|
||||
m_Right = right;
|
||||
m_Bottom = bottom;
|
||||
m_Top = top;
|
||||
m_Near = zNear;
|
||||
m_Far = zFar;
|
||||
}
|
||||
}
|
||||
|
||||
void TiledRender::Perspective(double fovy, double aspect, double zNear, double zFar )
|
||||
{
|
||||
double xmin, xmax, ymin, ymax;
|
||||
ymax = zNear * tan(fovy * 3.14159265 / 360.0);
|
||||
ymin = -ymax;
|
||||
xmin = ymin * aspect;
|
||||
xmax = ymax * aspect;
|
||||
Frustum(xmin, xmax, ymin, ymax, zNear, zFar);
|
||||
}
|
||||
|
||||
void TiledRender::BeginTile()
|
||||
{
|
||||
GLint matrixMode;
|
||||
int tileWidth, tileHeight, tileWidthNB, tileHeightNB, border;
|
||||
double left, right, bottom, top;
|
||||
|
||||
if (m_CurrentTile <= 0)
|
||||
{
|
||||
m_Columns = (m_ImageWidth + m_TileWidthNB - 1) / m_TileWidthNB;
|
||||
m_Rows = (m_ImageHeight + m_TileHeightNB - 1) / m_TileHeightNB;
|
||||
m_CurrentTile = 0;
|
||||
|
||||
// Save user's viewport, will be restored after last tile rendered
|
||||
glGetIntegerv(GL_VIEWPORT, m_ViewportSave);
|
||||
}
|
||||
|
||||
// which tile (by row and column) we're about to render
|
||||
if (m_RowOrder == TR_BOTTOM_TO_TOP)
|
||||
{
|
||||
m_CurrentRow = m_CurrentTile / m_Columns;
|
||||
m_CurrentColumn = m_CurrentTile % m_Columns;
|
||||
}
|
||||
else if (m_RowOrder==TR_TOP_TO_BOTTOM)
|
||||
{
|
||||
m_CurrentRow = m_Rows - (m_CurrentTile / m_Columns) - 1;
|
||||
m_CurrentColumn = m_CurrentTile % m_Columns;
|
||||
}
|
||||
|
||||
border = m_TileBorder;
|
||||
|
||||
// Compute actual size of this tile with border
|
||||
if (m_CurrentRow < m_Rows-1)
|
||||
tileHeight = m_TileHeight;
|
||||
else
|
||||
tileHeight = m_ImageHeight - (m_Rows-1) * (m_TileHeightNB) + 2 * border;
|
||||
|
||||
if (m_CurrentColumn < m_Columns-1)
|
||||
tileWidth = m_TileWidth;
|
||||
else
|
||||
tileWidth = m_ImageWidth - (m_Columns-1) * (m_TileWidthNB) + 2 * border;
|
||||
|
||||
// tile size with No Border
|
||||
tileWidthNB = tileWidth - 2 * border;
|
||||
tileHeightNB = tileHeight - 2 * border;
|
||||
|
||||
// Save tile size, with border
|
||||
m_CurrentTileWidth = tileWidth;
|
||||
m_CurrentTileHeight = tileHeight;
|
||||
|
||||
glViewport(0, 0, tileWidth, tileHeight); // tile size including border
|
||||
|
||||
// save current matrix mode
|
||||
glGetIntegerv(GL_MATRIX_MODE, &matrixMode);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
// compute projection parameters
|
||||
left = m_Left + (m_Right - m_Left)
|
||||
* (m_CurrentColumn * m_TileWidthNB - border) / m_ImageWidth;
|
||||
right = left + (m_Right - m_Left) * tileWidth / m_ImageWidth;
|
||||
bottom = m_Bottom + (m_Top - m_Bottom)
|
||||
* (m_CurrentRow * m_TileHeightNB - border) / m_ImageHeight;
|
||||
top = bottom + (m_Top - m_Bottom) * tileHeight / m_ImageHeight;
|
||||
|
||||
if (m_Perspective)
|
||||
glFrustum(left, right, bottom, top, m_Near, m_Far);
|
||||
else
|
||||
glOrtho(left, right, bottom, top, m_Near, m_Far);
|
||||
|
||||
// restore user's matrix mode
|
||||
glMatrixMode((GLenum)matrixMode);
|
||||
}
|
||||
|
||||
int TiledRender::EndTile()
|
||||
{
|
||||
GLint prevRowLength, prevSkipRows, prevSkipPixels;
|
||||
|
||||
// be sure OpenGL rendering is finished
|
||||
glFlush();
|
||||
|
||||
// save current glPixelStore values
|
||||
glGetIntegerv(GL_PACK_ROW_LENGTH, &prevRowLength);
|
||||
glGetIntegerv(GL_PACK_SKIP_ROWS, &prevSkipRows);
|
||||
glGetIntegerv(GL_PACK_SKIP_PIXELS, &prevSkipPixels);
|
||||
|
||||
if (m_TileBuffer)
|
||||
{
|
||||
int srcX = m_TileBorder;
|
||||
int srcY = m_TileBorder;
|
||||
int srcWidth = m_TileWidthNB;
|
||||
int srcHeight = m_TileHeightNB;
|
||||
glReadPixels(srcX, srcY, srcWidth, srcHeight,
|
||||
(GLenum)m_TileFormat, (GLenum)m_TileType, m_TileBuffer);
|
||||
}
|
||||
|
||||
if (m_ImageBuffer)
|
||||
{
|
||||
int srcX = m_TileBorder;
|
||||
int srcY = m_TileBorder;
|
||||
int srcWidth = m_CurrentTileWidth - 2 * m_TileBorder;
|
||||
int srcHeight = m_CurrentTileHeight - 2 * m_TileBorder;
|
||||
int destX = m_TileWidthNB * m_CurrentColumn;
|
||||
int destY = m_TileHeightNB * m_CurrentRow;
|
||||
|
||||
// setup pixel store for glReadPixels
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, m_ImageWidth);
|
||||
glPixelStorei(GL_PACK_SKIP_ROWS, destY);
|
||||
glPixelStorei(GL_PACK_SKIP_PIXELS, destX);
|
||||
|
||||
// read the tile into the final image
|
||||
glReadPixels(srcX, srcY, srcWidth, srcHeight,
|
||||
(GLenum)m_ImageFormat, (GLenum)m_ImageType, m_ImageBuffer);
|
||||
}
|
||||
|
||||
// restore previous glPixelStore values
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, prevRowLength);
|
||||
glPixelStorei(GL_PACK_SKIP_ROWS, prevSkipRows);
|
||||
glPixelStorei(GL_PACK_SKIP_PIXELS, prevSkipPixels);
|
||||
|
||||
// increment tile counter, return 1 if more tiles left to render
|
||||
m_CurrentTile++;
|
||||
if (m_CurrentTile >= m_Rows * m_Columns)
|
||||
{
|
||||
// restore user's viewport
|
||||
glViewport(m_ViewportSave[0], m_ViewportSave[1],
|
||||
m_ViewportSave[2], m_ViewportSave[3]);
|
||||
m_CurrentTile = -1; // all done
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
void TiledRender::RasterPos3f(float x, float y, float z)
|
||||
{
|
||||
if (m_CurrentTile < 0)
|
||||
{
|
||||
// not doing tile rendering right now. Let OpenGL do this.
|
||||
glRasterPos3f(x, y, z);
|
||||
}
|
||||
else
|
||||
{
|
||||
GLdouble modelview[16], proj[16];
|
||||
GLint viewport[4];
|
||||
GLdouble winX, winY, winZ;
|
||||
|
||||
// Get modelview, projection and viewport
|
||||
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
|
||||
glGetDoublev(GL_PROJECTION_MATRIX, proj);
|
||||
viewport[0] = 0;
|
||||
viewport[1] = 0;
|
||||
viewport[2] = m_CurrentTileWidth;
|
||||
viewport[3] = m_CurrentTileHeight;
|
||||
|
||||
// Project object coord to window coordinate
|
||||
if (gluProject(x, y, z, modelview, proj, viewport, &winX, &winY, &winZ))
|
||||
{
|
||||
// set raster pos to window coord (0,0)
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho(0.0, m_CurrentTileWidth,
|
||||
0.0, m_CurrentTileHeight, 0.0, 1.0);
|
||||
glRasterPos3f(0.0, 0.0, (float)-winZ);
|
||||
|
||||
// Now use empty bitmap to adjust raster position to (winX,winY)
|
||||
{
|
||||
GLubyte bitmap[1] = {0};
|
||||
glBitmap(1, 1, 0.0, 0.0, (float)winX, (float)winY, bitmap);
|
||||
}
|
||||
|
||||
// restore original matrices
|
||||
glPopMatrix(); // proj
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
75
common/tr.h
Normal file
75
common/tr.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
// TR.h: interface for the TiledRender class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _TR_H_
|
||||
#define _TR_H_
|
||||
|
||||
typedef enum {
|
||||
TR_TILE_WIDTH = 100,
|
||||
TR_TILE_HEIGHT,
|
||||
TR_TILE_BORDER,
|
||||
TR_IMAGE_WIDTH,
|
||||
TR_IMAGE_HEIGHT,
|
||||
TR_ROWS,
|
||||
TR_COLUMNS,
|
||||
TR_CURRENT_ROW,
|
||||
TR_CURRENT_COLUMN,
|
||||
TR_CURRENT_TILE_WIDTH,
|
||||
TR_CURRENT_TILE_HEIGHT,
|
||||
TR_ROW_ORDER,
|
||||
TR_TOP_TO_BOTTOM,
|
||||
TR_BOTTOM_TO_TOP
|
||||
} TRenum;
|
||||
|
||||
class TiledRender
|
||||
{
|
||||
public:
|
||||
TiledRender();
|
||||
virtual ~TiledRender();
|
||||
|
||||
void TileSize(int width, int height, int border);
|
||||
void TileBuffer(TRenum format, TRenum type, void *image);
|
||||
void ImageSize(int width, int height);
|
||||
void ImageBuffer(TRenum format, TRenum type, void *image);
|
||||
void RowOrder(TRenum order);
|
||||
void Ortho(double left, double right, double bottom, double top, double zNear, double zFar);
|
||||
void Frustum(double left, double right, double bottom, double top, double zNear, double zFar);
|
||||
void Perspective(double fovy, double aspect, double zNear, double zFar );
|
||||
void RasterPos3f(float x, float y, float z);
|
||||
int Get(TRenum param);
|
||||
int EndTile();
|
||||
void BeginTile();
|
||||
|
||||
// Final image parameters
|
||||
int m_ImageWidth, m_ImageHeight;
|
||||
TRenum m_ImageFormat, m_ImageType;
|
||||
void *m_ImageBuffer;
|
||||
|
||||
// Tile parameters
|
||||
int m_TileWidth, m_TileHeight;
|
||||
int m_TileWidthNB, m_TileHeightNB;
|
||||
int m_TileBorder;
|
||||
TRenum m_TileFormat, m_TileType;
|
||||
void *m_TileBuffer;
|
||||
|
||||
// Projection parameters
|
||||
bool m_Perspective;
|
||||
double m_Left;
|
||||
double m_Right;
|
||||
double m_Bottom;
|
||||
double m_Top;
|
||||
double m_Near;
|
||||
double m_Far;
|
||||
|
||||
// Misc
|
||||
TRenum m_RowOrder;
|
||||
int m_Rows, m_Columns;
|
||||
int m_CurrentTile;
|
||||
int m_CurrentTileWidth, m_CurrentTileHeight;
|
||||
int m_CurrentRow, m_CurrentColumn;
|
||||
|
||||
GLint m_ViewportSave[4];
|
||||
};
|
||||
|
||||
#endif // _TR_H_
|
420
common/typedefs.h
Normal file
420
common/typedefs.h
Normal file
|
@ -0,0 +1,420 @@
|
|||
// Typedefs.
|
||||
//
|
||||
|
||||
#ifndef _TYPEDEF_H_
|
||||
#define _TYPEDEF_H_
|
||||
|
||||
class Group;
|
||||
class Piece;
|
||||
class PieceInfo;
|
||||
class Camera;
|
||||
|
||||
#include "defines.h"
|
||||
#include "str.h"
|
||||
#include "algebra.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_COLOR_CHANGED,
|
||||
LC_CAPTURE_LOST,
|
||||
LC_ACTIVATE,
|
||||
LC_PIECE_MODIFIED,
|
||||
LC_CAMERA_MODIFIED,
|
||||
LC_LIGHT_MODIFIED
|
||||
} LC_NOTIFY;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_FILE_NEW,
|
||||
LC_FILE_OPEN,
|
||||
LC_FILE_MERGE,
|
||||
LC_FILE_SAVE,
|
||||
LC_FILE_SAVEAS,
|
||||
LC_FILE_PICTURE,
|
||||
LC_FILE_3DS,
|
||||
LC_FILE_HTML,
|
||||
LC_FILE_POVRAY,
|
||||
LC_FILE_WAVEFRONT,
|
||||
LC_FILE_PROPERTIES,
|
||||
LC_FILE_TERRAIN,
|
||||
LC_FILE_LIBRARY,
|
||||
LC_FILE_RECENT,
|
||||
LC_EDIT_UNDO,
|
||||
LC_EDIT_REDO,
|
||||
LC_EDIT_CUT,
|
||||
LC_EDIT_COPY,
|
||||
LC_EDIT_PASTE,
|
||||
LC_EDIT_SELECT_ALL,
|
||||
LC_EDIT_SELECT_NONE,
|
||||
LC_EDIT_SELECT_INVERT,
|
||||
LC_EDIT_SELECT_BYNAME,
|
||||
LC_PIECE_INSERT,
|
||||
LC_PIECE_DELETE,
|
||||
LC_PIECE_MINIFIG,
|
||||
LC_PIECE_ARRAY,
|
||||
LC_PIECE_COPYKEYS,
|
||||
LC_PIECE_GROUP,
|
||||
LC_PIECE_UNGROUP,
|
||||
LC_PIECE_GROUP_ADD,
|
||||
LC_PIECE_GROUP_REMOVE,
|
||||
LC_PIECE_GROUP_EDIT,
|
||||
LC_PIECE_HIDE_SELECTED,
|
||||
LC_PIECE_HIDE_UNSELECTED,
|
||||
LC_PIECE_UNHIDE_ALL,
|
||||
LC_PIECE_PREVIOUS,
|
||||
LC_PIECE_NEXT,
|
||||
LC_VIEW_PREFERENCES,
|
||||
LC_VIEW_ZOOM,
|
||||
LC_VIEW_ZOOMIN,
|
||||
LC_VIEW_ZOOMOUT,
|
||||
LC_VIEW_ZOOMEXTENTS,
|
||||
LC_VIEW_VIEWPORTS,
|
||||
LC_VIEW_STEP_NEXT,
|
||||
LC_VIEW_STEP_PREVIOUS,
|
||||
LC_VIEW_STEP_FIRST,
|
||||
LC_VIEW_STEP_LAST,
|
||||
LC_VIEW_STEP_CHOOSE,
|
||||
LC_VIEW_STEP_SET,
|
||||
LC_VIEW_STEP_INSERT,
|
||||
LC_VIEW_STEP_DELETE,
|
||||
LC_VIEW_STOP,
|
||||
LC_VIEW_PLAY,
|
||||
LC_VIEW_CAMERA_FRONT,
|
||||
LC_VIEW_CAMERA_BACK,
|
||||
LC_VIEW_CAMERA_TOP,
|
||||
LC_VIEW_CAMERA_BOTTOM,
|
||||
LC_VIEW_CAMERA_LEFT,
|
||||
LC_VIEW_CAMERA_RIGHT,
|
||||
LC_VIEW_CAMERA_MAIN,
|
||||
LC_VIEW_CAMERA_MENU,
|
||||
LC_VIEW_CAMERA_RESET,
|
||||
LC_VIEW_AUTOPAN,
|
||||
LC_HELP_ABOUT,
|
||||
LC_TOOLBAR_ANIMATION,
|
||||
LC_TOOLBAR_ADDKEYS,
|
||||
LC_TOOLBAR_SNAPMENU,
|
||||
LC_TOOLBAR_LOCKMENU,
|
||||
LC_TOOLBAR_FASTRENDER,
|
||||
LC_TOOLBAR_BACKGROUND,
|
||||
LC_EDIT_MOVEXY_SNAP_0,
|
||||
LC_EDIT_MOVEXY_SNAP_1,
|
||||
LC_EDIT_MOVEXY_SNAP_2,
|
||||
LC_EDIT_MOVEXY_SNAP_3,
|
||||
LC_EDIT_MOVEXY_SNAP_4,
|
||||
LC_EDIT_MOVEXY_SNAP_5,
|
||||
LC_EDIT_MOVEXY_SNAP_6,
|
||||
LC_EDIT_MOVEXY_SNAP_7,
|
||||
LC_EDIT_MOVEXY_SNAP_8,
|
||||
LC_EDIT_MOVEXY_SNAP_9,
|
||||
LC_EDIT_MOVEZ_SNAP_0,
|
||||
LC_EDIT_MOVEZ_SNAP_1,
|
||||
LC_EDIT_MOVEZ_SNAP_2,
|
||||
LC_EDIT_MOVEZ_SNAP_3,
|
||||
LC_EDIT_MOVEZ_SNAP_4,
|
||||
LC_EDIT_MOVEZ_SNAP_5,
|
||||
LC_EDIT_MOVEZ_SNAP_6,
|
||||
LC_EDIT_MOVEZ_SNAP_7,
|
||||
LC_EDIT_MOVEZ_SNAP_8,
|
||||
LC_EDIT_MOVEZ_SNAP_9,
|
||||
LC_EDIT_ANGLE_SNAP_0,
|
||||
LC_EDIT_ANGLE_SNAP_1,
|
||||
LC_EDIT_ANGLE_SNAP_2,
|
||||
LC_EDIT_ANGLE_SNAP_3,
|
||||
LC_EDIT_ANGLE_SNAP_4,
|
||||
LC_EDIT_ANGLE_SNAP_5,
|
||||
LC_EDIT_ANGLE_SNAP_6,
|
||||
LC_EDIT_ANGLE_SNAP_7,
|
||||
LC_EDIT_ANGLE_SNAP_8,
|
||||
LC_EDIT_ACTION_SELECT,
|
||||
LC_EDIT_ACTION_INSERT,
|
||||
LC_EDIT_ACTION_LIGHT,
|
||||
LC_EDIT_ACTION_SPOTLIGHT,
|
||||
LC_EDIT_ACTION_CAMERA,
|
||||
LC_EDIT_ACTION_MOVE,
|
||||
LC_EDIT_ACTION_ROTATE,
|
||||
LC_EDIT_ACTION_ERASER,
|
||||
LC_EDIT_ACTION_PAINT,
|
||||
LC_EDIT_ACTION_ZOOM,
|
||||
LC_EDIT_ACTION_ZOOM_REGION,
|
||||
LC_EDIT_ACTION_PAN,
|
||||
LC_EDIT_ACTION_ROTATE_VIEW,
|
||||
LC_EDIT_ACTION_ROLL,
|
||||
} LC_COMMANDS;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_ACTION_SELECT,
|
||||
LC_ACTION_INSERT,
|
||||
LC_ACTION_LIGHT,
|
||||
LC_ACTION_SPOTLIGHT,
|
||||
LC_ACTION_CAMERA,
|
||||
LC_ACTION_MOVE,
|
||||
LC_ACTION_ROTATE,
|
||||
LC_ACTION_ERASER,
|
||||
LC_ACTION_PAINT,
|
||||
LC_ACTION_ZOOM,
|
||||
LC_ACTION_ZOOM_REGION,
|
||||
LC_ACTION_PAN,
|
||||
LC_ACTION_ROTATE_VIEW,
|
||||
LC_ACTION_ROLL,
|
||||
LC_ACTION_CURVE
|
||||
} LC_ACTIONS;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_CURSOR_NONE,
|
||||
LC_CURSOR_BRICK,
|
||||
LC_CURSOR_LIGHT,
|
||||
LC_CURSOR_SPOTLIGHT,
|
||||
LC_CURSOR_CAMERA,
|
||||
LC_CURSOR_SELECT,
|
||||
LC_CURSOR_SELECT_GROUP,
|
||||
LC_CURSOR_MOVE,
|
||||
LC_CURSOR_ROTATE,
|
||||
LC_CURSOR_ROTATEX,
|
||||
LC_CURSOR_ROTATEY,
|
||||
LC_CURSOR_DELETE,
|
||||
LC_CURSOR_PAINT,
|
||||
LC_CURSOR_ZOOM,
|
||||
LC_CURSOR_ZOOM_REGION,
|
||||
LC_CURSOR_PAN,
|
||||
LC_CURSOR_ROLL,
|
||||
LC_CURSOR_ROTATE_VIEW,
|
||||
LC_CURSOR_COUNT
|
||||
} LC_CURSOR_TYPE;
|
||||
|
||||
// Piece connections (complicated and wastes memory but fast).
|
||||
|
||||
typedef struct CONNECTION
|
||||
{
|
||||
unsigned char type;
|
||||
float center[3];
|
||||
float normal[3];
|
||||
CONNECTION* link;
|
||||
Piece* owner;
|
||||
} CONNECTION;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Piece* owner;
|
||||
CONNECTION** cons; // pointers to the structures in each piece
|
||||
unsigned short numcons;
|
||||
} CONNECTION_ENTRY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CONNECTION_ENTRY* entries;
|
||||
unsigned short numentries;
|
||||
} CONNECTION_TYPE;
|
||||
|
||||
// Select by Name dialog data
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_SELDLG_PIECE,
|
||||
LC_SELDLG_CAMERA,
|
||||
LC_SELDLG_LIGHT,
|
||||
LC_SELDLG_GROUP
|
||||
} LC_SEL_DATA_TYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
unsigned char type;
|
||||
bool selected;
|
||||
void* pointer;
|
||||
} LC_SEL_DATA;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Piece* piece;
|
||||
Vector3 Position;
|
||||
Vector3 Rotation;
|
||||
char name[81];
|
||||
int from;
|
||||
int to;
|
||||
bool hidden;
|
||||
int color;
|
||||
} LC_PIECE_MODIFY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Camera* camera;
|
||||
Vector3 Eye;
|
||||
Vector3 Target;
|
||||
Vector3 Up;
|
||||
char name[81];
|
||||
float fovy;
|
||||
float znear;
|
||||
float zfar;
|
||||
bool hidden;
|
||||
} LC_CAMERA_MODIFY;
|
||||
|
||||
// Image
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_IMAGE_BMP,
|
||||
LC_IMAGE_GIF,
|
||||
LC_IMAGE_JPG,
|
||||
LC_IMAGE_PNG,
|
||||
LC_IMAGE_AVI
|
||||
} LC_IMAGE_FORMATS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char quality;
|
||||
bool interlaced;
|
||||
bool transparent;
|
||||
bool truecolor;
|
||||
unsigned char background[3];
|
||||
float pause;
|
||||
unsigned int format;
|
||||
} LC_IMAGE_OPTS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char filename[LC_MAXPATH];
|
||||
unsigned short from;
|
||||
unsigned short to;
|
||||
bool multiple;
|
||||
unsigned short width;
|
||||
unsigned short height;
|
||||
LC_IMAGE_OPTS imopts;
|
||||
} LC_IMAGEDLG_OPTS;
|
||||
|
||||
typedef enum {
|
||||
LC_DLG_FILE_OPEN_PROJECT,
|
||||
LC_DLG_FILE_SAVE_PROJECT,
|
||||
LC_DLG_FILE_MERGE_PROJECT,
|
||||
LC_DLG_FILE_OPEN,
|
||||
LC_DLG_FILE_SAVE,
|
||||
LC_DLG_PICTURE_SAVE,
|
||||
LC_DLG_HTML,
|
||||
LC_DLG_POVRAY,
|
||||
LC_DLG_WAVEFRONT,
|
||||
LC_DLG_MINIFIG,
|
||||
LC_DLG_ARRAY,
|
||||
LC_DLG_PREFERENCES,
|
||||
LC_DLG_PROPERTIES,
|
||||
LC_DLG_TERRAIN,
|
||||
LC_DLG_LIBRARY,
|
||||
LC_DLG_SELECTBYNAME,
|
||||
LC_DLG_STEPCHOOSE,
|
||||
LC_DLG_EDITGROUPS,
|
||||
LC_DLG_GROUP,
|
||||
LC_DLG_EDITCATEGORY,
|
||||
LC_DLG_ABOUT
|
||||
} LC_DIALOGS;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_FILEOPENDLG_DAT,
|
||||
LC_FILEOPENDLG_LCF,
|
||||
LC_FILEOPENDLG_LUP
|
||||
} LC_FILEOPENDLG_TYPES;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int type;
|
||||
char path[LC_MAXPATH];
|
||||
int numfiles;
|
||||
char** filenames;
|
||||
} LC_FILEOPENDLG_OPTS;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LC_FILESAVEDLG_LCF,
|
||||
} LC_FILESAVEDLG_TYPES;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int type;
|
||||
char path[LC_MAXPATH];
|
||||
} LC_FILESAVEDLG_OPTS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool render;
|
||||
char povpath[LC_MAXPATH];
|
||||
char outpath[LC_MAXPATH];
|
||||
char libpath[LC_MAXPATH];
|
||||
} LC_POVRAYDLG_OPTS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char path[LC_MAXPATH];
|
||||
bool singlepage;
|
||||
bool index;
|
||||
bool images;
|
||||
bool listend;
|
||||
bool liststep;
|
||||
bool highlight;
|
||||
bool htmlext;
|
||||
LC_IMAGEDLG_OPTS imdlg;
|
||||
} LC_HTMLDLG_OPTS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short n1DCount;
|
||||
unsigned short n2DCount;
|
||||
unsigned short n3DCount;
|
||||
unsigned char nArrayDimension;
|
||||
float f2D[3];
|
||||
float f3D[3];
|
||||
float fMove[3];
|
||||
float fRotate[3];
|
||||
} LC_ARRAYDLG_OPTS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char strAuthor[101];
|
||||
char strDescription[101];
|
||||
char strComments[256];
|
||||
char* strTitle;
|
||||
char* strFilename;
|
||||
char** names;
|
||||
unsigned short* count;
|
||||
int lines;
|
||||
} LC_PROPERTIESDLG_OPTS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int piececount;
|
||||
Piece** pieces;
|
||||
Group** piecesgroups;
|
||||
int groupcount;
|
||||
Group** groups;
|
||||
Group** groupsgroups;
|
||||
} LC_GROUPEDITDLG_OPTS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int nMouse;
|
||||
int nSaveInterval;
|
||||
char strUser[101];
|
||||
char strPath[LC_MAXPATH];
|
||||
unsigned long nDetail;
|
||||
float fLineWidth;
|
||||
unsigned long nSnap;
|
||||
unsigned short nAngleSnap;
|
||||
unsigned short nGridSize;
|
||||
unsigned long nScene;
|
||||
float fDensity;
|
||||
char strBackground[LC_MAXPATH];
|
||||
float fBackground[4];
|
||||
float fFog[4];
|
||||
float fAmbient[4];
|
||||
float fGrad1[3];
|
||||
float fGrad2[3];
|
||||
char strFooter[256];
|
||||
char strHeader[256];
|
||||
} LC_PREFERENCESDLG_OPTS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
String Name;
|
||||
String Keywords;
|
||||
} LC_CATEGORYDLG_OPTS;
|
||||
|
||||
#endif
|
105
common/vector.cpp
Normal file
105
common/vector.cpp
Normal file
|
@ -0,0 +1,105 @@
|
|||
#include <math.h>
|
||||
#include "vector.h"
|
||||
#include "defines.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
|
||||
Vector::Vector()
|
||||
{
|
||||
m_fPoint[0] = 0;
|
||||
m_fPoint[1] = 0;
|
||||
m_fPoint[2] = 0;
|
||||
}
|
||||
|
||||
Vector::Vector(float x, float y, float z)
|
||||
{
|
||||
m_fPoint[0] = x;
|
||||
m_fPoint[1] = y;
|
||||
m_fPoint[2] = z;
|
||||
}
|
||||
|
||||
Vector::Vector(const float *point)
|
||||
{
|
||||
m_fPoint[0] = point[0];
|
||||
m_fPoint[1] = point[1];
|
||||
m_fPoint[2] = point[2];
|
||||
}
|
||||
|
||||
Vector::Vector(const float *p1, const float *p2)
|
||||
{
|
||||
m_fPoint[0] = p2[0] - p1[0];
|
||||
m_fPoint[1] = p2[1] - p1[1];
|
||||
m_fPoint[2] = p2[2] - p1[2];
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Operations
|
||||
|
||||
Vector& Vector::operator*=(float scalar)
|
||||
{
|
||||
m_fPoint[0] *= scalar;
|
||||
m_fPoint[1] *= scalar;
|
||||
m_fPoint[2] *= scalar;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector& Vector::operator+=(const Vector& add)
|
||||
{
|
||||
m_fPoint[0] += add.m_fPoint[0];
|
||||
m_fPoint[1] += add.m_fPoint[1];
|
||||
m_fPoint[2] += add.m_fPoint[2];
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector& Vector::operator-=(const Vector& sub)
|
||||
{
|
||||
m_fPoint[0] -= sub.m_fPoint[0];
|
||||
m_fPoint[1] -= sub.m_fPoint[1];
|
||||
m_fPoint[2] -= sub.m_fPoint[2];
|
||||
return *this;
|
||||
}
|
||||
|
||||
float Vector::Length()
|
||||
{
|
||||
return (float)sqrt(m_fPoint[0]*m_fPoint[0] + m_fPoint[1]*m_fPoint[1] + m_fPoint[2]*m_fPoint[2]);
|
||||
}
|
||||
|
||||
void Vector::Normalize()
|
||||
{
|
||||
float inv = 1.0f / Length();
|
||||
m_fPoint[0] *= inv;
|
||||
m_fPoint[1] *= inv;
|
||||
m_fPoint[2] *= inv;
|
||||
}
|
||||
|
||||
Vector& Vector::Cross(const Vector& v1, const Vector& v2)
|
||||
{
|
||||
m_fPoint[0] = v1.m_fPoint[1]*v2.m_fPoint[2] - v1.m_fPoint[2]*v2.m_fPoint[1];
|
||||
m_fPoint[1] = v1.m_fPoint[2]*v2.m_fPoint[0] - v1.m_fPoint[0]*v2.m_fPoint[2];
|
||||
m_fPoint[2] = v1.m_fPoint[0]*v2.m_fPoint[1] - v1.m_fPoint[1]*v2.m_fPoint[0];
|
||||
return *this;
|
||||
}
|
||||
|
||||
float Vector::Angle(const Vector& vec)
|
||||
{
|
||||
double d, m1, m2;
|
||||
|
||||
d = m_fPoint[0]*vec.m_fPoint[0]+m_fPoint[1]*vec.m_fPoint[1]+m_fPoint[2]*vec.m_fPoint[2];
|
||||
m1 = sqrt(m_fPoint[0]*m_fPoint[0]+m_fPoint[1]*m_fPoint[1]+m_fPoint[2]*m_fPoint[2]);
|
||||
m2 = sqrt(vec.m_fPoint[0]*vec.m_fPoint[0]+vec.m_fPoint[1]*vec.m_fPoint[1]+vec.m_fPoint[2]*vec.m_fPoint[2]);
|
||||
|
||||
return (float)(RTOD * acos(d / (m1*m2)));
|
||||
}
|
||||
|
||||
float Vector::Dot(const Vector& vec)
|
||||
{
|
||||
return m_fPoint[0]*vec.m_fPoint[0]+m_fPoint[1]*vec.m_fPoint[1]+m_fPoint[2]*vec.m_fPoint[2];
|
||||
}
|
||||
|
||||
void Vector::ToFloat(float *point)
|
||||
{
|
||||
point[0] = m_fPoint[0];
|
||||
point[1] = m_fPoint[1];
|
||||
point[2] = m_fPoint[2];
|
||||
}
|
30
common/vector.h
Normal file
30
common/vector.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef _VECTOR_H_
|
||||
#define _VECTOR_H_
|
||||
|
||||
class Vector
|
||||
{
|
||||
public:
|
||||
Vector();
|
||||
Vector(float x, float y, float z);
|
||||
Vector(const float *point);
|
||||
Vector(const float *p1, const float *p2);
|
||||
~Vector() { };
|
||||
|
||||
float Dot(const Vector& vec);
|
||||
float Angle(const Vector& vec);
|
||||
Vector& Cross(const Vector& v1, const Vector& v2);
|
||||
Vector& operator+=(const Vector& add);
|
||||
Vector& operator-=(const Vector& sub);
|
||||
Vector& operator*=(float scalar);
|
||||
|
||||
operator const float*() const
|
||||
{ return m_fPoint; }
|
||||
void ToFloat(float *point);
|
||||
float Length();
|
||||
void Normalize();
|
||||
|
||||
protected:
|
||||
float m_fPoint[3];
|
||||
};
|
||||
|
||||
#endif // _VECTOR_H_
|
139
common/view.cpp
Normal file
139
common/view.cpp
Normal file
|
@ -0,0 +1,139 @@
|
|||
//
|
||||
// View the project contents
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "project.h"
|
||||
#include "view.h"
|
||||
#include "system.h"
|
||||
|
||||
View::View(Project *pProject, GLWindow *share)
|
||||
: GLWindow(share)
|
||||
{
|
||||
m_Project = pProject;
|
||||
}
|
||||
|
||||
View::~View()
|
||||
{
|
||||
if (m_Project != NULL)
|
||||
m_Project->RemoveView(this);
|
||||
}
|
||||
|
||||
LC_CURSOR_TYPE View::GetCursor(int Ptx, int Pty) const
|
||||
{
|
||||
// TODO: check if we're the focused window and return just the default arrow if we aren't.
|
||||
|
||||
switch (m_Project->GetAction())
|
||||
{
|
||||
case LC_ACTION_SELECT:
|
||||
if (Sys_KeyDown(KEY_CONTROL))
|
||||
return LC_CURSOR_SELECT_GROUP;
|
||||
else
|
||||
return LC_CURSOR_SELECT;
|
||||
|
||||
case LC_ACTION_INSERT:
|
||||
return LC_CURSOR_BRICK;
|
||||
|
||||
case LC_ACTION_LIGHT:
|
||||
return LC_CURSOR_LIGHT;
|
||||
|
||||
case LC_ACTION_SPOTLIGHT:
|
||||
return LC_CURSOR_SPOTLIGHT;
|
||||
|
||||
case LC_ACTION_CAMERA:
|
||||
return LC_CURSOR_CAMERA;
|
||||
|
||||
case LC_ACTION_MOVE:
|
||||
return LC_CURSOR_MOVE;
|
||||
|
||||
case LC_ACTION_ROTATE:
|
||||
return LC_CURSOR_ROTATE;
|
||||
|
||||
case LC_ACTION_ERASER:
|
||||
return LC_CURSOR_DELETE;
|
||||
|
||||
case LC_ACTION_PAINT:
|
||||
return LC_CURSOR_PAINT;
|
||||
|
||||
case LC_ACTION_ZOOM:
|
||||
return LC_CURSOR_ZOOM;
|
||||
|
||||
case LC_ACTION_ZOOM_REGION:
|
||||
return LC_CURSOR_ZOOM_REGION;
|
||||
|
||||
case LC_ACTION_PAN:
|
||||
return LC_CURSOR_PAN;
|
||||
|
||||
case LC_ACTION_ROTATE_VIEW:
|
||||
switch (m_Project->GetOverlayMode())
|
||||
{
|
||||
case LC_OVERLAY_X: return LC_CURSOR_ROTATEX;
|
||||
case LC_OVERLAY_Y: return LC_CURSOR_ROTATEY;
|
||||
case LC_OVERLAY_Z: return LC_CURSOR_ROLL;
|
||||
case LC_OVERLAY_XYZ: return LC_CURSOR_ROTATE_VIEW;
|
||||
default:
|
||||
LC_ASSERT_FALSE("Unknown cursor type.");
|
||||
return LC_CURSOR_NONE;
|
||||
}
|
||||
|
||||
case LC_ACTION_ROLL:
|
||||
return LC_CURSOR_ROLL;
|
||||
|
||||
case LC_ACTION_CURVE:
|
||||
default:
|
||||
LC_ASSERT_FALSE("Unknown cursor type.");
|
||||
return LC_CURSOR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void View::OnDraw()
|
||||
{
|
||||
MakeCurrent();
|
||||
|
||||
m_Project->SetViewSize(m_nWidth, m_nHeight);
|
||||
m_Project->Render(false);
|
||||
|
||||
SwapBuffers();
|
||||
}
|
||||
|
||||
void View::OnInitialUpdate()
|
||||
{
|
||||
GLWindow::OnInitialUpdate();
|
||||
m_Project->AddView(this);
|
||||
}
|
||||
|
||||
void View::OnLeftButtonDown(int x, int y, bool bControl, bool bShift)
|
||||
{
|
||||
m_Project->SetViewSize(m_nWidth, m_nHeight);
|
||||
m_Project->OnLeftButtonDown(x, y, bControl, bShift);
|
||||
}
|
||||
|
||||
void View::OnLeftButtonUp(int x, int y, bool bControl, bool bShift)
|
||||
{
|
||||
m_Project->SetViewSize(m_nWidth, m_nHeight);
|
||||
m_Project->OnLeftButtonUp(x, y, bControl, bShift);
|
||||
}
|
||||
|
||||
void View::OnLeftButtonDoubleClick(int x, int y, bool bControl, bool bShift)
|
||||
{
|
||||
m_Project->SetViewSize(m_nWidth, m_nHeight);
|
||||
m_Project->OnLeftButtonDoubleClick(x, y, bControl, bShift);
|
||||
}
|
||||
|
||||
void View::OnRightButtonDown(int x, int y, bool bControl, bool bShift)
|
||||
{
|
||||
m_Project->SetViewSize(m_nWidth, m_nHeight);
|
||||
m_Project->OnRightButtonDown(x, y, bControl, bShift);
|
||||
}
|
||||
|
||||
void View::OnRightButtonUp(int x, int y, bool bControl, bool bShift)
|
||||
{
|
||||
m_Project->SetViewSize(m_nWidth, m_nHeight);
|
||||
m_Project->OnRightButtonUp(x, y, bControl, bShift);
|
||||
}
|
||||
|
||||
void View::OnMouseMove(int x, int y, bool bControl, bool bShift)
|
||||
{
|
||||
m_Project->SetViewSize(m_nWidth, m_nHeight);
|
||||
m_Project->OnMouseMove(x, y, bControl, bShift);
|
||||
}
|
33
common/view.h
Normal file
33
common/view.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef _VIEW_H_
|
||||
#define _VIEW_H_
|
||||
|
||||
#include "glwindow.h"
|
||||
|
||||
class Project;
|
||||
|
||||
class View : public GLWindow
|
||||
{
|
||||
public:
|
||||
View (Project *pProject, GLWindow *share);
|
||||
virtual ~View ();
|
||||
|
||||
void OnDraw ();
|
||||
void OnInitialUpdate ();
|
||||
void OnLeftButtonDown (int x, int y, bool bControl, bool bShift);
|
||||
void OnLeftButtonUp (int x, int y, bool bControl, bool bShift);
|
||||
void OnLeftButtonDoubleClick (int x, int y, bool bControl, bool bShift);
|
||||
void OnRightButtonDown (int x, int y, bool bControl, bool bShift);
|
||||
void OnRightButtonUp (int x, int y, bool bControl, bool bShift);
|
||||
void OnMouseMove (int x, int y, bool bControl, bool bShift);
|
||||
|
||||
LC_CURSOR_TYPE GetCursor(int x, int y) const;
|
||||
Project* GetProject () const
|
||||
{ return m_Project; }
|
||||
|
||||
protected:
|
||||
Project* m_Project;
|
||||
|
||||
// virtual void OnInitialUpdate (); // called first time after construct
|
||||
};
|
||||
|
||||
#endif // _VIEW_H_
|
385
config.mk
Normal file
385
config.mk
Normal file
|
@ -0,0 +1,385 @@
|
|||
# LeoCAD configuration file
|
||||
#
|
||||
include version.mk
|
||||
|
||||
ERROR_SETTING=2> /dev/null
|
||||
|
||||
default: all
|
||||
|
||||
CC := gcc
|
||||
CXX := g++
|
||||
|
||||
# (Add a -g for debugging)
|
||||
CPPFLAGS += -O2 -Wall
|
||||
|
||||
# Add compile options, such as -I option to include jpeglib's headers
|
||||
# CPPFLAGS += -I/home/fred/jpeglib
|
||||
|
||||
# Add linker options, such as -L option to include jpeglib's libraries
|
||||
# LDFLAGS += -L/home/fred/jpeglib
|
||||
|
||||
### Linux configuration
|
||||
|
||||
ifeq ($(shell uname), Linux)
|
||||
|
||||
OS := -DLC_LINUX
|
||||
OSDIR := linux
|
||||
TEST_GTK := 1
|
||||
|
||||
endif
|
||||
|
||||
### FreeBSD configuration
|
||||
|
||||
ifeq ($(shell uname), FreeBSD)
|
||||
|
||||
OS := -DLC_LINUX
|
||||
OSDIR := linux
|
||||
TEST_GTK := 1
|
||||
CPPFLAGS += -L/usr/local/lib
|
||||
|
||||
endif
|
||||
|
||||
### Macintosh configuration
|
||||
|
||||
ifeq ($(shell uname), Darwin)
|
||||
|
||||
OS := -DLC_MACOSX
|
||||
OSDIR := macosx
|
||||
TEST_GTK := 0
|
||||
CPPFLAGS += -funsigned-char -I/Developer/Headers/FlatCarbon/
|
||||
LDFLAGS += -framework AGL -framework Carbon
|
||||
|
||||
# The directory tree for the generated bundle
|
||||
BUNDLEDIR = bin/LeoCAD.app
|
||||
CONTDIR = $(BUNDLEDIR)/Contents
|
||||
BINDIR = $(CONTDIR)/MacOS
|
||||
RSRCDIR = $(CONTDIR)/Resources
|
||||
EN_RSRCDIR = $(RSRCDIR)/English.lproj
|
||||
|
||||
NIBS = main.nib
|
||||
|
||||
all: bundletree exec bnibs pkginfo infoplist infopliststr
|
||||
|
||||
bundletree: $(BINDIR) $(BUNDLEDIR) $(CONTDIR) $(RSRCDIR) $(EN_RSRCDIR)
|
||||
|
||||
$(BUNDLEDIR):
|
||||
mkdir bin
|
||||
mkdir $(BUNDLEDIR)
|
||||
|
||||
$(CONTDIR): $(BUNDLEDIR)
|
||||
mkdir $(CONTDIR)
|
||||
|
||||
$(BINDIR): $(CONTDIR)
|
||||
mkdir $(BINDIR)
|
||||
|
||||
$(RSRCDIR): $(CONTDIR)
|
||||
mkdir $(RSRCDIR)
|
||||
|
||||
$(EN_RSRCDIR): $(RSRCDIR)
|
||||
mkdir $(EN_RSRCDIR)
|
||||
|
||||
# The binary executable
|
||||
exec: $(BINDIR)/leocad
|
||||
|
||||
$(BINDIR)/leocad: bin/leocad
|
||||
cp bin/leocad $(BINDIR)
|
||||
|
||||
# The nib's
|
||||
BNIBS = $(NIBS:%=$(EN_RSRCDIR)/%)
|
||||
|
||||
bnibs: $(BNIBS)
|
||||
|
||||
$(BNIBS) : $(EN_RSRCDIR)/%: macosx/English.lproj/%
|
||||
rm -rf $@
|
||||
cp -R $< $@
|
||||
touch $@
|
||||
|
||||
# Info.plist
|
||||
infoplist : $(CONTDIR)/Info.plist
|
||||
|
||||
$(CONTDIR)/Info.plist : macosx/Info.plist
|
||||
cp macosx/Info.plist $@
|
||||
|
||||
# PkgInfo
|
||||
pkginfo : $(CONTDIR)/PkgInfo
|
||||
|
||||
$(CONTDIR)/PkgInfo : macosx/PkgInfo
|
||||
cp macosx/PkgInfo $@
|
||||
|
||||
# InfoPlist.strings - this goes inside English.lproj
|
||||
infopliststr : $(EN_RSRCDIR)/InfoPlist.strings
|
||||
|
||||
$(EN_RSRCDIR)/InfoPlist.strings: macosx/English.lproj/InfoPlist.strings
|
||||
cp $< $@
|
||||
|
||||
endif
|
||||
|
||||
### Default directory
|
||||
|
||||
ifeq ($(PREFIX), )
|
||||
PREFIX := /usr/local
|
||||
endif
|
||||
|
||||
.PHONY: config config-help
|
||||
|
||||
config-help:
|
||||
@echo "This target attempts to detect your system settings,"
|
||||
@echo "it will create $(OSDIR)/config.mk and $(OSDIR)/config.h"
|
||||
@echo "Valid parameters and their default values are:"
|
||||
@echo " PREFIX=/usr/local"
|
||||
@echo " DESTDIR="
|
||||
|
||||
### Automatic configuration
|
||||
|
||||
#USE this with printf and a primitive type - printf "WIDTHTEST" "char" >conftest.c
|
||||
CONFTEST="\#include <stdio.h>\nint main() { FILE *f=fopen(\"conftestval\", \"w\");\n\
|
||||
if (!f) return 1; fprintf(f, \"%%d\\\n\", (int)sizeof(%s)); return 0; }\n"
|
||||
|
||||
config:
|
||||
@echo "Automatic configuration"
|
||||
|
||||
@echo "### LeoCAD configuration" > $(OSDIR)/config.mk
|
||||
@echo "### Auto-generated file, DO NOT EDIT" >> $(OSDIR)/config.mk
|
||||
@echo "" >> $(OSDIR)/config.mk
|
||||
@echo "PREFIX := $(PREFIX)" >> $(OSDIR)/config.mk;
|
||||
@echo "DESTDIR := $(DESTDIR)" >> $(OSDIR)/config.mk;
|
||||
@echo "" >> $(OSDIR)/config.mk
|
||||
|
||||
@echo "//" > $(OSDIR)/config.h
|
||||
@echo "// LeoCAD configuration" >> $(OSDIR)/config.h
|
||||
@echo "//" >> $(OSDIR)/config.h
|
||||
@echo "// Auto-generated file, DO NOT EDIT" >> $(OSDIR)/config.h
|
||||
@echo "//" >> $(OSDIR)/config.h
|
||||
@echo "" >> $(OSDIR)/config.h
|
||||
@echo "#ifndef _CONFIG_H_" >> $(OSDIR)/config.h
|
||||
@echo "#define _CONFIG_H_" >> $(OSDIR)/config.h
|
||||
@echo "" >> $(OSDIR)/config.h
|
||||
|
||||
### Version information
|
||||
@echo "#define LC_VERSION_MAJOR $(MAJOR)" >> $(OSDIR)/config.h
|
||||
@echo "#define LC_VERSION_MINOR $(MINOR)" >> $(OSDIR)/config.h
|
||||
@echo "#define LC_VERSION_PATCH $(PATCHLVL)" >> $(OSDIR)/config.h
|
||||
@echo "#define LC_VERSION_OSNAME \"$(shell uname)\"" >> $(OSDIR)/config.h
|
||||
@echo "#define LC_VERSION_TEXT \"$(MAJOR).$(MINOR).$(PATCHLVL)\"" >> $(OSDIR)/config.h
|
||||
@echo "#define LC_VERSION_TAG \"$(VERSIONTAG)\"" >> $(OSDIR)/config.h
|
||||
@echo "#define LC_INSTALL_PREFIX \"$(PREFIX)\"" >> $(OSDIR)/config.h
|
||||
@echo "" >> $(OSDIR)/config.h
|
||||
|
||||
### Determine variable sizes
|
||||
@echo -n "checking size of char... "; \
|
||||
printf ${CONFTEST} "char" > conftest.c; \
|
||||
if { (eval $(CC) conftest.c -o conftest); } && \
|
||||
(test -s conftest && (./conftest; exit)); then \
|
||||
ac_cv_sizeof_char=`cat conftestval`; \
|
||||
echo "$$ac_cv_sizeof_char"; \
|
||||
else \
|
||||
echo "failed to get size of char"; \
|
||||
ac_cv_sizeof_char=0; \
|
||||
fi; \
|
||||
echo "#define LC_SIZEOF_CHAR $$ac_cv_sizeof_char" >> $(OSDIR)/config.h; \
|
||||
rm -f conftest.c conftest conftestval; \
|
||||
\
|
||||
echo -n "checking size of short... "; \
|
||||
printf ${CONFTEST} "short" > conftest.c; \
|
||||
if { (eval $(CC) conftest.c -o conftest); } && \
|
||||
(test -s conftest && (./conftest; exit)); then \
|
||||
ac_cv_sizeof_short=`cat conftestval`; \
|
||||
echo "$$ac_cv_sizeof_short"; \
|
||||
else \
|
||||
echo "failed to get size of short"; \
|
||||
ac_cv_sizeof_short=0; \
|
||||
fi; \
|
||||
echo "#define LC_SIZEOF_SHORT $$ac_cv_sizeof_short" >> $(OSDIR)/config.h; \
|
||||
rm -f conftest.c conftest conftestval; \
|
||||
\
|
||||
echo -n "checking size of long... "; \
|
||||
printf ${CONFTEST} "long" > conftest.c; \
|
||||
if { (eval $(CC) conftest.c -o conftest); } && \
|
||||
(test -s conftest && (./conftest; exit)); then \
|
||||
ac_cv_sizeof_long=`cat conftestval`; \
|
||||
echo "$$ac_cv_sizeof_long"; \
|
||||
else \
|
||||
echo "failed to get size of long"; \
|
||||
ac_cv_sizeof_long=0; \
|
||||
fi; \
|
||||
echo "#define LC_SIZEOF_LONG $$ac_cv_sizeof_long" >> $(OSDIR)/config.h; \
|
||||
rm -f conftest.c conftest conftestval; \
|
||||
\
|
||||
echo -n "checking size of int... "; \
|
||||
printf ${CONFTEST} "int" > conftest.c; \
|
||||
if { (eval $(CC) conftest.c -o conftest); } && \
|
||||
(test -s conftest && (./conftest; exit)); then \
|
||||
ac_cv_sizeof_int=`cat conftestval`; \
|
||||
echo "$$ac_cv_sizeof_int"; \
|
||||
else \
|
||||
echo "failed to get size of int"; \
|
||||
ac_cv_sizeof_int=0; \
|
||||
fi; \
|
||||
echo "#define LC_SIZEOF_INT $$ac_cv_sizeof_int" >> $(OSDIR)/config.h; \
|
||||
rm -f conftest.c conftest conftestval; \
|
||||
\
|
||||
echo -n "checking size of void *... "; \
|
||||
printf ${CONFTEST} "void *" > conftest.c; \
|
||||
if { (eval $(CC) conftest.c -o conftest); } && \
|
||||
(test -s conftest && (./conftest; exit)); then \
|
||||
ac_cv_sizeof_void_p=`cat conftestval`; \
|
||||
echo "$$ac_cv_sizeof_void_p"; \
|
||||
else \
|
||||
echo "failed to get size of void *"; \
|
||||
ac_cv_sizeof_void_p=0; \
|
||||
fi; \
|
||||
echo "#define LC_SIZEOF_VOID_P $$ac_cv_sizeof_void_p" >> $(OSDIR)/config.h; \
|
||||
if test "$$ac_cv_sizeof_void_p" -eq "8"; then \
|
||||
echo "#define LC_POINTER_TO_INT(p) ((lcint32)(lcint64)(p))" >> $(OSDIR)/config.h; \
|
||||
else \
|
||||
echo "#define LC_POINTER_TO_INT(p) ((lcint32)(p))" >> $(OSDIR)/config.h; \
|
||||
fi; \
|
||||
rm -f conftest.c conftest conftestval; \
|
||||
\
|
||||
echo -n "checking size of long long... "; \
|
||||
printf ${CONFTEST} "long long" > conftest.c; \
|
||||
if { (eval $(CC) conftest.c -o conftest); } && \
|
||||
(test -s conftest && (./conftest; exit)); then \
|
||||
ac_cv_sizeof_long_long=`cat conftestval`; \
|
||||
echo "$$ac_cv_sizeof_long_long"; \
|
||||
else \
|
||||
echo "failed to get size of long long"; \
|
||||
ac_cv_sizeof_long_long=0; \
|
||||
fi; \
|
||||
echo "#define LC_SIZEOF_LONG_LONG $$ac_cv_sizeof_long_long" >> $(OSDIR)/config.h; \
|
||||
rm -f conftest.c conftest conftestval; \
|
||||
case 2 in \
|
||||
$$ac_cv_sizeof_short) lcint16=short;; \
|
||||
$$ac_cv_sizeof_int) lcint16=int;; \
|
||||
esac; \
|
||||
case 4 in \
|
||||
$$ac_cv_sizeof_short) lcint32=short;; \
|
||||
$$ac_cv_sizeof_int) lcint32=int;; \
|
||||
$$ac_cv_sizeof_long) lcint32=long;; \
|
||||
esac; \
|
||||
case 8 in \
|
||||
$$ac_cv_sizeof_long_long) lcint64="long long";; \
|
||||
esac; \
|
||||
echo "" >> $(OSDIR)/config.h; \
|
||||
echo "typedef signed char lcint8;" >> $(OSDIR)/config.h; \
|
||||
echo "typedef unsigned char lcuint8;" >> $(OSDIR)/config.h; \
|
||||
if test -n "$$lcint16"; then \
|
||||
echo "typedef signed $$lcint16 lcint16;" >> $(OSDIR)/config.h; \
|
||||
echo "typedef unsigned $$lcint16 lcuint16;" >> $(OSDIR)/config.h; \
|
||||
else \
|
||||
echo "#error need to define lcint16 and lcuint16" >> $(OSDIR)/config.h; \
|
||||
fi; \
|
||||
if test -n "$$lcint32"; then \
|
||||
echo "typedef signed $$lcint32 lcint32;" >> $(OSDIR)/config.h; \
|
||||
echo "typedef unsigned $$lcint32 lcuint32;" >> $(OSDIR)/config.h; \
|
||||
else \
|
||||
echo "#error need to define lcint32 and lcuint32" >> $(OSDIR)/config.h; \
|
||||
fi; \
|
||||
if test -n "$$lcint64"; then \
|
||||
echo "typedef signed $$lcint64 lcint64;" >> $(OSDIR)/config.h; \
|
||||
echo "typedef unsigned $$lcint64 lcuint64;" >> $(OSDIR)/config.h; \
|
||||
else \
|
||||
echo "#error need to define lcint64 and lcuint64" >> $(OSDIR)/config.h; \
|
||||
fi; \
|
||||
echo "" >> $(OSDIR)/config.h
|
||||
|
||||
### Check if machine is little or big endian
|
||||
@echo -n "Determining endianess... "
|
||||
@echo "int main () { union { long l; char c[sizeof (long)]; } u;" > endiantest.c
|
||||
@echo "u.l = 1; return (u.c[sizeof (long) - 1] == 1); }" >> endiantest.c
|
||||
@if { (eval $(CC) endiantest.c -o endiantest); } && \
|
||||
(test -s endiantest && (./endiantest; exit)); then \
|
||||
echo "little endian"; \
|
||||
echo "#define LC_LITTLE_ENDIAN" >> $(OSDIR)/config.h; \
|
||||
echo "#define LCUINT16(val) val" >> $(OSDIR)/config.h; \
|
||||
echo "#define LCUINT32(val) val" >> $(OSDIR)/config.h; \
|
||||
echo "#define LCINT16(val) val" >> $(OSDIR)/config.h; \
|
||||
echo "#define LCINT32(val) val" >> $(OSDIR)/config.h; \
|
||||
echo "#define LCFLOAT(val) val" >> $(OSDIR)/config.h; \
|
||||
else \
|
||||
echo "big endian"; \
|
||||
echo "#define LC_BIG_ENDIAN" >> $(OSDIR)/config.h; \
|
||||
echo "#define LCUINT16(val) ((lcuint16) ( \\" >> $(OSDIR)/config.h; \
|
||||
echo " (((lcuint16) (val) & (lcuint16) 0x00ffU) << 8) | \\" >> $(OSDIR)/config.h; \
|
||||
echo " (((lcuint16) (val) & (lcuint16) 0xff00U) >> 8)))" >> $(OSDIR)/config.h; \
|
||||
echo "#define LCUINT32(val) ((lcuint32) ( \\" >> $(OSDIR)/config.h; \
|
||||
echo " (((lcuint32) (val) & (lcuint32) 0x000000ffU) << 24) | \\" >> $(OSDIR)/config.h; \
|
||||
echo " (((lcuint32) (val) & (lcuint32) 0x0000ff00U) << 8) | \\" >> $(OSDIR)/config.h; \
|
||||
echo " (((lcuint32) (val) & (lcuint32) 0x00ff0000U) >> 8) | \\" >> $(OSDIR)/config.h; \
|
||||
echo " (((lcuint32) (val) & (lcuint32) 0xff000000U) >> 24)))" >> $(OSDIR)/config.h; \
|
||||
echo "#define LCINT16(val) ((lcint16)LCUINT16(val))" >> $(OSDIR)/config.h; \
|
||||
echo "#define LCINT32(val) ((lcint32)LCUINT32(val))" >> $(OSDIR)/config.h; \
|
||||
echo -e "inline float LCFLOAT (float l)\n{" >> $(OSDIR)/config.h; \
|
||||
echo -e " union { unsigned char b[4]; float f; } in, out;\n" >> $(OSDIR)/config.h; \
|
||||
echo -e " in.f = l;\n out.b[0] = in.b[3];\n out.b[1] = in.b[2];" >> $(OSDIR)/config.h; \
|
||||
echo -e " out.b[2] = in.b[1];\n out.b[3] = in.b[0];\n" >> $(OSDIR)/config.h; \
|
||||
echo -e " return out.f;\n}" >> $(OSDIR)/config.h; \
|
||||
fi; \
|
||||
echo "" >> $(OSDIR)/config.h
|
||||
@rm -f endiantest.c endiantest
|
||||
|
||||
#### Check if the user has GTK+ and GLIB installed.
|
||||
ifeq ($(TEST_GTK), 1)
|
||||
@echo -n "Checking if GLIB and GTK+ are installed... "
|
||||
@if (pkg-config --atleast-version=2.0.0 glib-2.0) && (pkg-config --atleast-version=2.0.0 gtk+-2.0); then \
|
||||
echo "ok"; \
|
||||
echo "CFLAGS += \$$(shell pkg-config gtk+-2.0 --cflags)" >> $(OSDIR)/config.mk; \
|
||||
echo "CXXFLAGS += \$$(shell pkg-config gtk+-2.0 --cflags)" >> $(OSDIR)/config.mk; \
|
||||
echo "LIBS += \$$(shell pkg-config gtk+-2.0 --libs)" >> $(OSDIR)/config.mk; \
|
||||
else \
|
||||
echo "failed"; \
|
||||
rm -rf $(OSDIR)/config.mk $(OSDIR)/config.h; \
|
||||
exit 1; \
|
||||
fi
|
||||
endif
|
||||
|
||||
## Check if the user has libjpeg installed
|
||||
@echo -n "Checking for jpeg support... "
|
||||
@echo "char jpeg_read_header();" > jpegtest.c
|
||||
@echo "int main() { jpeg_read_header(); return 0; }" >> jpegtest.c
|
||||
@if { (eval $(CC) jpegtest.c -ljpeg -o jpegtest $(CPPFLAGS) $(LDFLAGS)); } && \
|
||||
(test -s jpegtest); then \
|
||||
echo "ok"; \
|
||||
echo "HAVE_JPEGLIB = yes" >> $(OSDIR)/config.mk; \
|
||||
echo "#define LC_HAVE_JPEGLIB" >> $(OSDIR)/config.h; \
|
||||
else \
|
||||
echo "no (libjpeg optional)"; \
|
||||
echo "HAVE_JPEGLIB = no" >> $(OSDIR)/config.mk; \
|
||||
echo "#undef LC_HAVE_JPEGLIB" >> $(OSDIR)/config.h; \
|
||||
fi
|
||||
@rm -f jpegtest.c jpegtest
|
||||
|
||||
### Check if the user has zlib installed
|
||||
@echo -n "Checking for zlib support... "
|
||||
@echo "char gzread();" > ztest.c
|
||||
@echo "int main() { gzread(); return 0; }" >> ztest.c
|
||||
@if { (eval $(CC) ztest.c -lz -o ztest $(CPPFLAGS) $(LDFLAGS)); } && \
|
||||
(test -s ztest); then \
|
||||
echo "ok"; \
|
||||
echo "HAVE_ZLIB = yes" >> $(OSDIR)/config.mk; \
|
||||
echo "#define LC_HAVE_ZLIB" >> $(OSDIR)/config.h; \
|
||||
else \
|
||||
echo "no (zlib optional)"; \
|
||||
echo "HAVE_ZLIB = no" >> $(OSDIR)/config.mk; \
|
||||
echo "#undef LC_HAVE_ZLIB" >> $(OSDIR)/config.h; \
|
||||
fi
|
||||
@rm -f ztest.c ztest
|
||||
|
||||
### Check if the user has libpng installed
|
||||
@echo -n "Checking for png support... "
|
||||
@echo "char png_read_info();" > pngtest.c
|
||||
@echo "int main() { png_read_info(); return 0; }" >> pngtest.c
|
||||
@if { (eval $(CC) pngtest.c -lm -lz -lpng -o pngtest $(CPPFLAGS) $(LDFLAGS)); } && \
|
||||
(test -s pngtest); then \
|
||||
echo "ok"; \
|
||||
echo "HAVE_PNGLIB = yes" >> $(OSDIR)/config.mk; \
|
||||
echo "#define LC_HAVE_PNGLIB" >> $(OSDIR)/config.h; \
|
||||
else \
|
||||
echo "no (libpng optional)"; \
|
||||
echo "HAVE_PNGLIB = no" >> $(OSDIR)/config.mk; \
|
||||
echo "#undef LC_HAVE_PNGLIB" >> $(OSDIR)/config.h; \
|
||||
fi
|
||||
@rm -f pngtest.c pngtest
|
||||
|
||||
@echo "" >> $(OSDIR)/config.h
|
||||
@echo "#endif // _CONFIG_H_" >> $(OSDIR)/config.h
|
5
description-pak
Normal file
5
description-pak
Normal file
|
@ -0,0 +1,5 @@
|
|||
LeoCAD is a CAD program that allows people to build virtual models using
|
||||
bricks similar to those found in LEGO toys. It's available for free under
|
||||
the GNU Public License, and works on the Windows and Linux Operating
|
||||
Systems.
|
||||
|
206
docs/CHANGES.txt
Normal file
206
docs/CHANGES.txt
Normal file
|
@ -0,0 +1,206 @@
|
|||
This is a changelog for developers only, not for regular users.
|
||||
|
||||
30/07/2003
|
||||
- Added MPD support.
|
||||
|
||||
17/10/2002
|
||||
- Fixed several bugs with the 3DS exporter.
|
||||
|
||||
10/10/2002
|
||||
- Added a dialog to handle the textures in the library.
|
||||
|
||||
26/08/2002
|
||||
- Added an option to print the total pages on the header (&O).
|
||||
- Fixed a bug with the step numbers when printing.
|
||||
|
||||
09/03/2002
|
||||
- Moved the texture font to a class to allow support for multiple fonts.
|
||||
|
||||
08/03/2002
|
||||
- Fixed a crash in the Edit Groups Dialog.
|
||||
|
||||
03/12/2001
|
||||
- Added a console window for text messages.
|
||||
|
||||
30/07/2001
|
||||
- Fixed a small memory leak and improved the default mouse sensitivity.
|
||||
|
||||
16/05/2001
|
||||
- Fixed the way pieces are moved/rotated with the side cameras.
|
||||
|
||||
26/03/2001
|
||||
- Reorganized the Image I/O functions, created a new Image class.
|
||||
- Fixed the return value of FileMem::Seek.
|
||||
|
||||
23/03/2001
|
||||
- Update object keys when adding/removing steps.
|
||||
- Added an option to save HTML files with .html extension instead of .htm.
|
||||
|
||||
21/03/2001
|
||||
- Improved Linux About dialog.
|
||||
|
||||
15/03/2001
|
||||
- Fixed drawing area border not being drawn correctly.
|
||||
|
||||
13/03/2001
|
||||
- Fixed texture font not visible on some video cards.
|
||||
|
||||
21/02/2001
|
||||
- New shortcuts: Home/End keys will change the Pieces List selection (win32).
|
||||
- Fixed the creation and destruction of the MainWnd under win32.
|
||||
|
||||
19/02/2001
|
||||
- The "Mouse moves in 3D" option now applies to rotations too.
|
||||
|
||||
04/02/2001
|
||||
- When multiple pieces are selected, rotate around the piece that has focus.
|
||||
- Clicking on a piece with focus now deselects it.
|
||||
- Only define LC_HAVE_PNGLIB if zlib is available.
|
||||
- Don't compile jpeg or png support if libraries are not present.
|
||||
|
||||
02/02/2001
|
||||
- HTML dialog now correctly remembers the last settings
|
||||
- Added step add/remove commands
|
||||
|
||||
01/02/2001
|
||||
- Fixed a crash deselecting point lights
|
||||
|
||||
07/01/2001
|
||||
- Added a new command to create floating views of the project
|
||||
|
||||
05/01/2001
|
||||
- Added a new cross platform class for handling OpenGL windows
|
||||
- Added a new base window class for handling top level windows
|
||||
|
||||
02/01/2001
|
||||
- Linux PPC fixes - LeoCAD now works on big endian computers !
|
||||
Thanks to Lon Shapiro for allowing me to use his Mac for debugging.
|
||||
|
||||
30/12/2000
|
||||
- Added Step Insert and Step Delete commands.
|
||||
|
||||
29/12/2000
|
||||
- Capture mouse events while dragging the cursor under linux.
|
||||
- HTML Dialog improvements under linux.
|
||||
|
||||
28/12/2000
|
||||
- Click on "Last Step" goes to the last used step instead of step 255.
|
||||
- Save HTML dialog options.
|
||||
|
||||
24/12/2000
|
||||
- Fixed piece combo under linux.
|
||||
|
||||
20/12/2000
|
||||
- Fixed crash when saving pictures of multiple steps.
|
||||
|
||||
================================================================================
|
||||
Version 0.73
|
||||
================================================================================
|
||||
|
||||
18/12/2000
|
||||
- Fixed win32 help file.
|
||||
|
||||
17/12/2000
|
||||
- Fixed win2k startup crash.
|
||||
|
||||
16/12/2000
|
||||
- Fixed AVI saving.
|
||||
- Fixed rotation bug.
|
||||
|
||||
15/12/2000
|
||||
- Fixed small bug in the texture font.
|
||||
|
||||
03/12/2000
|
||||
- Added Save Picture dialog to the linux version.
|
||||
- Added an overwrite prompt when saving a project under linux.
|
||||
|
||||
02/12/2000
|
||||
- Added project loading preview to the linux version.
|
||||
|
||||
24/11/2000
|
||||
- Renamed several functions from the Matrix class.
|
||||
- Added const to several functions.
|
||||
|
||||
23/11/2000
|
||||
- Now all object classes have a Select () function.
|
||||
|
||||
18/11/2000
|
||||
- Fixed animation playback under linux.
|
||||
- Fixed Z buffer bug in the piece preview.
|
||||
- Fixed blending in piece preview.
|
||||
|
||||
12/11/2000
|
||||
- Added the PtrArray class.
|
||||
- Started adding the internal messaging system.
|
||||
- Link with g++ instead of gcc.
|
||||
- Moved all keyframer functions to the Object class.
|
||||
|
||||
09/11/2000
|
||||
- First implementation of the light classes.
|
||||
- Added a const float* operator to the Vector class.
|
||||
- Added functions to create transformation matrixes.
|
||||
- Faster rendering of the camera objects.
|
||||
- Added new minifig pieces.
|
||||
|
||||
01/10/2000
|
||||
- Added an option to save custom minifigs to the Minifig Wizard.
|
||||
|
||||
30/09/2000
|
||||
- Enabled the "Make Default" button of the preferences dialog (Linux).
|
||||
|
||||
24/09/2000
|
||||
- Finished adding the new minifig rotation options.
|
||||
|
||||
20/09/2000
|
||||
- Fixed the numeric keypad under Linux, thanks to Renaud Breard.
|
||||
- Updated the Array dialog.
|
||||
|
||||
18/09/2000
|
||||
- Added new menu shortcuts.
|
||||
- Fixed endianess bugs when loading piece information.
|
||||
- Fixed piece preview mirrored image.
|
||||
- Fixed some warning messages in FreeBSD.
|
||||
- Added endian test to auto-configuration.
|
||||
- Fixed gtk-config problem under FreeBSD.
|
||||
|
||||
16/09/2000
|
||||
- Added man page, thanks to Patrick Mahoney.
|
||||
- Moved gif and jpg functions from image.cpp to separate files.
|
||||
- Modified the Makefile to automatically check for libjpeg, zlib and
|
||||
libpng. It also creates a config.h file with the options.
|
||||
|
||||
15/09/2000
|
||||
- Fixed problem with "focus follow mouse" in X, thanks to Renaud Breard.
|
||||
|
||||
13/09/2000
|
||||
- Fixed bug that caused image files to be saved upside down.
|
||||
|
||||
12/09/2000
|
||||
- Fixed bug when exporting POV-Ray files using LGEO.
|
||||
- Changed GL library name under Linux from 'libGL.so.1' to 'libGL.so'.
|
||||
|
||||
27/08/2000
|
||||
- Save window position and size under Linux.
|
||||
|
||||
25/08/2000
|
||||
- Changes to the Linux version:
|
||||
- The Pieces toolbar can now be resized when docked or detached from
|
||||
the main window.
|
||||
- The toolbar menu now has the checkboxes correct.
|
||||
- Remember toolbar state between sessions.
|
||||
|
||||
24/08/2000
|
||||
- Updated the Windows version with the new Minifig Wizard.
|
||||
- Fixed OpenGL problems on the Windows version.
|
||||
|
||||
21/08/2000
|
||||
- New options for the Minifig Wizard, now each piece can be rotated.
|
||||
|
||||
19/08/2000
|
||||
- Fixed a bug when you insert a piece after a rotated piece wouldn't
|
||||
show the new piece correctly.
|
||||
- Added a new parameter to Project::Initialize to search the program
|
||||
directory for the piece library. Useful if a Linux user wants to
|
||||
install everything in the same directory and keeps compatibility
|
||||
with installations in /usr/local/share/leocad.
|
||||
- Initial attempt of a BeOS port.
|
340
docs/COPYING.txt
Normal file
340
docs/COPYING.txt
Normal file
|
@ -0,0 +1,340 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
26
docs/INSTALL.txt
Normal file
26
docs/INSTALL.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
|
||||
================
|
||||
COMPILING LeoCAD
|
||||
================
|
||||
|
||||
Linux/GNU platforms
|
||||
-------------------
|
||||
|
||||
All your config options go into config.mk
|
||||
|
||||
You will need jpeglib. Install compile/install it and add it's header
|
||||
directory as a -I to CPPFLAGS and -L to LDFLAGS. This isn't required if
|
||||
it is installed to "standard" locations, like /usr/include and /usr/lib
|
||||
|
||||
Then just type MAKE
|
||||
|
||||
|
||||
MS Windows
|
||||
----------
|
||||
|
||||
- Extract LIBJPEG 6.0 to the win/libjpeg directory
|
||||
- Extract ZLIB to win/zlib
|
||||
- Extract LIBPNG to win/libpng
|
||||
- Extract the 3DSFTK to win/3dsftk (use -d to keep directory names)
|
||||
- Open VC++ and do a 'Make All'
|
||||
|
89
docs/LINUX.txt
Normal file
89
docs/LINUX.txt
Normal file
|
@ -0,0 +1,89 @@
|
|||
|
||||
LeoCAD for Linux
|
||||
----------------
|
||||
|
||||
This is the only documentation you will find for the Linux
|
||||
version, I'll start writing some help files in HTML format soon but
|
||||
it's going to take a while (I really prefer to code and my english
|
||||
is not perfect). I strongly advise you to follow the online tutorial
|
||||
from my web page, it will at least get you started with the basic
|
||||
editing commands.
|
||||
|
||||
I still have to finish some dialogs, the printing routines
|
||||
and a few GUI items but all the rest should work fine. I'd also
|
||||
like to warn you that this is my first Linux program so if you
|
||||
find anything that doesn't behave as you expect, a bug or just
|
||||
have some suggestions, feel free to email me at
|
||||
leonardo@centroin.com.br
|
||||
|
||||
I hope you enjoy using LeoCAD as much as I enjoyed writing it,
|
||||
|
||||
Leonardo
|
||||
|
||||
|
||||
HOW TO GET HELP
|
||||
---------------
|
||||
|
||||
The best source of help is the LeoCAD mailing list at
|
||||
leocad@gerf.org
|
||||
|
||||
You can subscribe/unsubscribe at
|
||||
http://gerf.org/mailman/listinfo/leocad
|
||||
|
||||
|
||||
INSTALLATION
|
||||
------------
|
||||
|
||||
Instalation should be very simple for most systems, first you need
|
||||
get the executable and the pieces library from my homepage (if you
|
||||
already have the library for the MS Windows version, you don't
|
||||
need to download it again).
|
||||
|
||||
Now you should unzip the files to a temporary directory (you
|
||||
probably already did that) and move the file 'leocad' to
|
||||
/usr/local/bin/ and the 4 files from the pieces library to
|
||||
/usr/local/share/leocad/. If you wish to have the library files
|
||||
installed in another place, set the environment variable LEOCAD_LIB
|
||||
to that directory or start the program with the -l <path> option.
|
||||
|
||||
You need to have an OpenGL library, you can download Mesa 3D
|
||||
from www.mesa3d.org if you don't have one already and you will also
|
||||
need GTK+ 1.2, it's available from www.gtk.org
|
||||
|
||||
If you're using the precompiled version, then you will also need
|
||||
libjpeg, zlib and libpng. If you're compiling from the sources, the
|
||||
configuration utility will detect what libraries you have installed
|
||||
and only support those file formats.
|
||||
|
||||
Current versions used are:
|
||||
GTK+ 1.2 http://www.gtk.org/
|
||||
MESA 3D 3.4 http://www.mesa3d.org/
|
||||
LIBJPEG 6.0 ftp://ftp.uu.net/graphics/jpeg/
|
||||
LIBPNG 1.0 http://www.libpng.org/pub/png/libpng.html
|
||||
ZLIB 1.1 http://www.info-zip.org/pub/infozip/zlib/
|
||||
|
||||
|
||||
COMMAND LINE OPTIONS
|
||||
--------------------
|
||||
|
||||
The man (1) page has a more complete description of all command line
|
||||
parameters available. This is just a list of the most used ones:
|
||||
|
||||
[filename]: Loads a file
|
||||
|
||||
-l <path>: Tells the program to use the piece library located in the directory
|
||||
pointed by <path>
|
||||
|
||||
-i [filename]: Saves a picture and exit
|
||||
|
||||
-w <x>: Use this width for the picture
|
||||
|
||||
-h <y>: Use this height for the picture
|
||||
|
||||
Example:
|
||||
|
||||
leocad car.lcd -i car.gif -w 640 -h 480 -l /mnt/c/leocad/
|
||||
|
||||
This will start LeoCAD, load the file "car.lcd", create a GIF file
|
||||
called "car.gif" with a resolution of 640 x 480 using the pieces
|
||||
library in /mnt/c/leocad/ and exit when done.
|
24
docs/TODO.txt
Normal file
24
docs/TODO.txt
Normal file
|
@ -0,0 +1,24 @@
|
|||
IDEAS:
|
||||
|
||||
- Add arrows & text objects
|
||||
- Technic style Instructions (picture with new pcs.)
|
||||
- Add lighting
|
||||
- Collision detection (fix)
|
||||
- Orthographic projections
|
||||
- Choose rotation centers
|
||||
- Flyby and explode (like Lego Creator)
|
||||
- Clouds/stars/waves
|
||||
- Network building
|
||||
- Create HTML catalog of pieces
|
||||
- OLE (probably not)
|
||||
|
||||
KNOWN BUGS:
|
||||
- WIN: color lb tooltip bug (after calling a dialog)
|
||||
- save piece list m_nLast in projects ?
|
||||
- create backups
|
||||
|
||||
NEW (since 0.71.1)
|
||||
- POV export bug
|
||||
- paste step
|
||||
- piecelist sort bug (linux)
|
||||
- CS_OWNDC (win)
|
118
docs/leocad.1
Normal file
118
docs/leocad.1
Normal file
|
@ -0,0 +1,118 @@
|
|||
.TH LEOCAD 1 "20 July 2000"
|
||||
.\" NAME should be all caps, SECTION should be 1-8, maybe w/ subsection
|
||||
.\" other parms are allowed: see man(7), man(1)
|
||||
.SH NAME
|
||||
LeoCAD \- CAD program using plastic bricks.
|
||||
.SH SYNOPSIS
|
||||
\fIleocad \fR[\fI infile \fR[ -i \fR[\fI outfile.ext \fR]\fI \fR[\fI-w x\fR]\fI \fR[\fI-h y\fR] ] \fR] [\fI\-l path\fR]
|
||||
.SH "DESCRIPTION"
|
||||
This manual page documents briefly the \fILeoCAD \fRprogram.
|
||||
It was written for the Debian GNU/Linux distribution
|
||||
because the original program does not have a manual page. The information
|
||||
in this manual page came from docs/LINUX.txt in the source archive.
|
||||
|
||||
.PP
|
||||
\fILeoCAD \fR is a CAD program that uses plastic bricks similar to those found
|
||||
in many toys (but not any particular brand). It supports animation
|
||||
as well as exportation to various file formats including POV-Ray.
|
||||
|
||||
.SH OPTIONS
|
||||
Below is a summary of all of the options that \fILeoCAD\fR
|
||||
accepts. Most options have two equivalent names, one of
|
||||
which is a single letter preceded by -, and the other of
|
||||
which is a long name preceded by --. Brackets ([ and ])
|
||||
indicate that an option takes an optional argument.
|
||||
|
||||
.TP
|
||||
.B infile
|
||||
Loads the project file \fIinfile\fR
|
||||
|
||||
.TP
|
||||
.BI "\-i [" outfile.ext ]
|
||||
.ns
|
||||
.TP
|
||||
.BI "\-\-image [" outfile.ext ]
|
||||
Saves a picture to \fIoutfile.ext \fR in the image format specified
|
||||
by \fIext\fR and exits. If outfile is not given then the program will
|
||||
use a name based on \fIinfile\fR. The file format is selected by \fIext\fR
|
||||
and can be gif, bmp, png or jpg (if \fIext\fR is not present then the
|
||||
default preferences format will be used).
|
||||
|
||||
.TP
|
||||
.BI "\-w "width
|
||||
.ns
|
||||
.TP
|
||||
.BI "\-\-width "width
|
||||
Sets the width of the picture to \fIwidth\fR.
|
||||
|
||||
.TP
|
||||
.BI "\-h "height
|
||||
.ns
|
||||
.TP
|
||||
.BI "\-\-height "height
|
||||
Sets the height of the picture to \fIheight\fR.
|
||||
|
||||
.TP
|
||||
.BI "\-f "time
|
||||
.ns
|
||||
.TP
|
||||
.BI "\-\-from "time
|
||||
Start saving pictures at the step or frame \fItime\fR.
|
||||
|
||||
.TP
|
||||
.BI "\-t "time
|
||||
.ns
|
||||
.TP
|
||||
.BI "\-\-to "time
|
||||
Save pictures until the step or frame \fItime\fR.
|
||||
|
||||
.TP
|
||||
.B \-\-animation
|
||||
Tells the program to save animations instead of instructions.
|
||||
|
||||
.TP
|
||||
.B \-\-instructions
|
||||
Tells the program to save instructions instead of animations (default).
|
||||
|
||||
.TP
|
||||
.B \-\-highlight
|
||||
Adds a border around the pieces in the step or frame they appear when saving pictures.
|
||||
|
||||
.TP
|
||||
.BI "\-l "path
|
||||
.ns
|
||||
.TP
|
||||
.BI "\-\-libpath "path
|
||||
Use alternate pieces library found in \fIpath \fR. The Debian version
|
||||
of \fILeoCAD \fRuses /usr/share/leocad/ as the default.
|
||||
|
||||
.TP
|
||||
.BI "\-\-libgl "library
|
||||
Sets the name of the OpenGL dynamic library used by the program to \fIlibrary\fR.
|
||||
The default library names searched are libGL.so and libMesaGL.so.
|
||||
|
||||
.SH ENVIRONMENT
|
||||
``LEOCAD_LIB'' may be set to the path of the pieces library.
|
||||
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
$ leocad car.lcd -i car.png -w 640 -h 480
|
||||
.PP
|
||||
This will start LeoCAD, load the file "car.lcd," create a png called
|
||||
"car.png" with a resolution of 640x480 and exit when done.
|
||||
|
||||
.SH FILES
|
||||
.TP
|
||||
.I ~/.leocad
|
||||
User preferences file
|
||||
|
||||
.SH BUGS
|
||||
If you find any bugs please report them at http://trac.gerf.org/leocad/
|
||||
|
||||
.SH AUTHOR
|
||||
\fILeoCAD \fRis written by Leonardo Zide <leo@gerf.org>.
|
||||
You can visit the LeoCAD homepage at http://www.leocad.org/
|
||||
|
||||
This manual page was written by Patrick Mahoney <pat7@gmx.net>,
|
||||
for the Debian GNU/Linux system (but may be used by others).
|
||||
|
21
fixwin.sh
Executable file
21
fixwin.sh
Executable file
|
@ -0,0 +1,21 @@
|
|||
#!/bin/sh
|
||||
# script to rename all files to lowercase and remove ^M from them
|
||||
|
||||
for j in linux common ; do
|
||||
for i in $j/*.cpp $j/*.c $j/*.h $j/*.mk ; do
|
||||
if [ -f $i ]; then
|
||||
echo $i | awk \
|
||||
'{
|
||||
if (tolower($1) != $1)
|
||||
{
|
||||
system ("mv "$1" "$1".lower")
|
||||
system ("mv "$1".lower "tolower($1))
|
||||
print $i
|
||||
}
|
||||
}'
|
||||
grep -ls
|
||||
$i | perl -pi -e 's/
|
||||
$//g'
|
||||
fi
|
||||
done
|
||||
done
|
11
generic.mk
Normal file
11
generic.mk
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
all:
|
||||
$(MAKE) -C .. $@
|
||||
|
||||
clean:
|
||||
$(MAKE) -C .. $@
|
||||
|
||||
veryclean:
|
||||
$(MAKE) -C .. $@
|
||||
|
||||
.PHONY: all clean veryclean
|
1
linux/Makefile
Normal file
1
linux/Makefile
Normal file
|
@ -0,0 +1 @@
|
|||
include ../generic.mk
|
247
linux/basewnd.cpp
Normal file
247
linux/basewnd.cpp
Normal file
|
@ -0,0 +1,247 @@
|
|||
//
|
||||
// BaseWnd class implementation for Linux
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include "basewnd.h"
|
||||
#include "dialogs.h"
|
||||
#include "main.h"
|
||||
|
||||
BaseWnd::BaseWnd (BaseWnd *parent, int menu_count)
|
||||
{
|
||||
m_pMenuItems = new BaseMenuItem[menu_count];
|
||||
memset(m_pMenuItems, 0, sizeof(BaseMenuItem[menu_count]));
|
||||
m_pParent = parent;
|
||||
|
||||
m_pXID = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
if (parent != NULL)
|
||||
gtk_window_set_transient_for (GTK_WINDOW (m_pXID), GTK_WINDOW (parent->GetXID ()));
|
||||
}
|
||||
|
||||
BaseWnd::~BaseWnd ()
|
||||
{
|
||||
delete [] m_pMenuItems;
|
||||
m_pMenuItems = NULL;
|
||||
}
|
||||
|
||||
void BaseWnd::BeginWait ()
|
||||
{
|
||||
GdkCursor *cursor = gdk_cursor_new (GDK_WATCH);
|
||||
gdk_window_set_cursor (m_pXID->window, cursor);
|
||||
gdk_cursor_destroy (cursor);
|
||||
}
|
||||
|
||||
void BaseWnd::EndWait ()
|
||||
{
|
||||
gdk_window_set_cursor (m_pXID->window, NULL);
|
||||
}
|
||||
|
||||
int BaseWnd::MessageBox (const char* text, const char* caption, int flags)
|
||||
{
|
||||
GtkWidget *window, *w, *vbox, *hbox;
|
||||
GtkAccelGroup *group;
|
||||
int mode = (flags & LC_MB_TYPEMASK), ret, loop = 1;
|
||||
guint tmp_key;
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_signal_connect (GTK_OBJECT (window), "delete_event",
|
||||
GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);
|
||||
// gtk_signal_connect (GTK_OBJECT (window), "destroy",
|
||||
// GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);
|
||||
gtk_window_set_title (GTK_WINDOW (window), caption);
|
||||
gtk_container_border_width (GTK_CONTAINER (window), 10);
|
||||
gtk_object_set_data (GTK_OBJECT (window), "loop", &loop);
|
||||
gtk_object_set_data (GTK_OBJECT (window), "ret", &ret);
|
||||
|
||||
if (m_pXID != NULL)
|
||||
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (m_pXID));
|
||||
// gtk_widget_realize (window);
|
||||
|
||||
group = gtk_accel_group_new ();
|
||||
gtk_window_add_accel_group (GTK_WINDOW (window), group);
|
||||
|
||||
vbox = gtk_vbox_new (FALSE, 10);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
gtk_widget_show (vbox);
|
||||
|
||||
w = gtk_label_new (text);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);
|
||||
gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT);
|
||||
gtk_widget_show (w);
|
||||
|
||||
w = gtk_hseparator_new ();
|
||||
gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);
|
||||
gtk_widget_show (w);
|
||||
|
||||
hbox = gtk_hbox_new (FALSE, 10);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2);
|
||||
gtk_widget_show (hbox);
|
||||
|
||||
if (mode == LC_MB_OK)
|
||||
{
|
||||
w = gtk_button_new_with_label ("Ok");
|
||||
gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
|
||||
gtk_signal_connect (GTK_OBJECT (w), "clicked",
|
||||
GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (LC_OK));
|
||||
GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
|
||||
gtk_widget_grab_default (w);
|
||||
gtk_widget_show (w);
|
||||
ret = LC_OK;
|
||||
}
|
||||
else if (mode == LC_MB_OKCANCEL)
|
||||
{
|
||||
w = gtk_button_new_with_label ("Ok");
|
||||
gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
|
||||
gtk_signal_connect (GTK_OBJECT (w), "clicked",
|
||||
GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (LC_OK));
|
||||
GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
|
||||
gtk_widget_grab_default (w);
|
||||
gtk_widget_show (w);
|
||||
|
||||
w = gtk_button_new_with_label ("Cancel");
|
||||
gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
|
||||
gtk_signal_connect (GTK_OBJECT (w), "clicked",
|
||||
GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (LC_CANCEL));
|
||||
gtk_widget_show (w);
|
||||
ret = LC_CANCEL;
|
||||
}
|
||||
else if (mode == LC_MB_YESNOCANCEL)
|
||||
{
|
||||
w = gtk_button_new_with_label ("");
|
||||
tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (w)->child), "_Yes");
|
||||
gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
|
||||
gtk_signal_connect (GTK_OBJECT (w), "clicked",
|
||||
GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (LC_YES));
|
||||
gtk_widget_add_accelerator (w, "clicked", group, tmp_key, (GdkModifierType)0, (GtkAccelFlags)0);
|
||||
GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
|
||||
gtk_widget_grab_default (w);
|
||||
gtk_widget_show (w);
|
||||
gtk_window_set_focus (GTK_WINDOW (window), w);
|
||||
|
||||
w = gtk_button_new_with_label ("");
|
||||
tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (w)->child), "_No");
|
||||
gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
|
||||
gtk_signal_connect (GTK_OBJECT (w), "clicked",
|
||||
GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (LC_NO));
|
||||
gtk_widget_add_accelerator (w, "clicked", group, tmp_key, (GdkModifierType)0, (GtkAccelFlags)0);
|
||||
gtk_widget_show (w);
|
||||
|
||||
w = gtk_button_new_with_label ("");
|
||||
tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (w)->child), "_Cancel");
|
||||
gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
|
||||
gtk_signal_connect (GTK_OBJECT (w), "clicked",
|
||||
GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (LC_CANCEL));
|
||||
gtk_widget_add_accelerator (w, "clicked", group, tmp_key, (GdkModifierType)0, (GtkAccelFlags)0);
|
||||
gtk_widget_add_accelerator (w, "clicked", group, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
|
||||
gtk_widget_show (w);
|
||||
ret = LC_CANCEL;
|
||||
}
|
||||
else /* if (mode == LC_MB_YESNO) */
|
||||
{
|
||||
w = gtk_button_new_with_label ("Yes");
|
||||
gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
|
||||
gtk_signal_connect (GTK_OBJECT (w), "clicked",
|
||||
GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (LC_YES));
|
||||
GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
|
||||
gtk_widget_grab_default (w);
|
||||
gtk_widget_show (w);
|
||||
|
||||
w = gtk_button_new_with_label ("No");
|
||||
gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
|
||||
gtk_signal_connect (GTK_OBJECT (w), "clicked",
|
||||
GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (LC_NO));
|
||||
gtk_widget_show (w);
|
||||
ret = LC_NO;
|
||||
}
|
||||
|
||||
gtk_widget_show (window);
|
||||
gtk_grab_add (window);
|
||||
|
||||
while (loop)
|
||||
gtk_main_iteration ();
|
||||
|
||||
gtk_grab_remove (window);
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BaseWnd::ShowMenuItem (int id, bool show)
|
||||
{
|
||||
if (!m_pMenuItems[id].widget)
|
||||
return;
|
||||
|
||||
if (show)
|
||||
gtk_widget_show (m_pMenuItems[id].widget);
|
||||
else
|
||||
gtk_widget_hide (m_pMenuItems[id].widget);
|
||||
}
|
||||
|
||||
void BaseWnd::EnableMenuItem (int id, bool enable)
|
||||
{
|
||||
if (!m_pMenuItems[id].widget)
|
||||
return;
|
||||
|
||||
gtk_widget_set_sensitive (m_pMenuItems[id].widget, enable);
|
||||
}
|
||||
|
||||
void BaseWnd::CheckMenuItem (int id, bool check)
|
||||
{
|
||||
if (!m_pMenuItems[id].widget)
|
||||
return;
|
||||
|
||||
ignore_commands = true;
|
||||
gtk_check_menu_item_set_state (GTK_CHECK_MENU_ITEM (m_pMenuItems[id].widget), check);
|
||||
ignore_commands = false;
|
||||
}
|
||||
#include <stdio.h>
|
||||
|
||||
void BaseWnd::SetMenuItemText (int id, const char *text)
|
||||
{
|
||||
gboolean underscore;
|
||||
gchar *r;
|
||||
const char *p;
|
||||
gchar *pattern;
|
||||
gint length;
|
||||
|
||||
if (!m_pMenuItems[id].widget)
|
||||
return;
|
||||
|
||||
length = strlen (text);
|
||||
pattern = g_new (gchar, length+1);
|
||||
|
||||
underscore = FALSE;
|
||||
|
||||
p = text;
|
||||
r = pattern;
|
||||
|
||||
while (*p)
|
||||
{
|
||||
if (underscore)
|
||||
{
|
||||
if (*p == '&')
|
||||
*r++ = *p;
|
||||
else
|
||||
{
|
||||
*r++ = '_';
|
||||
*r++ = *p;
|
||||
}
|
||||
|
||||
underscore = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*p == '&')
|
||||
underscore = TRUE;
|
||||
else
|
||||
*r++ = *p;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
*r = 0;
|
||||
|
||||
gtk_label_set_text_with_mnemonic(GTK_LABEL(GTK_BIN(m_pMenuItems[id].widget)->child), pattern);
|
||||
g_free (pattern);
|
||||
}
|
||||
|
3193
linux/dialogs.cpp
Normal file
3193
linux/dialogs.cpp
Normal file
File diff suppressed because it is too large
Load diff
40
linux/dialogs.h
Normal file
40
linux/dialogs.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#ifndef _DIALOGS_H_
|
||||
#define _DIALOGS_H_
|
||||
|
||||
// Dialog support functions
|
||||
void dialog_button_callback (GtkWidget *widget, gpointer data);
|
||||
gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data);
|
||||
|
||||
// obsolete
|
||||
int dlg_domodal (GtkWidget* dlg, int def);
|
||||
void dlg_end (int ret);
|
||||
gint dlg_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data);
|
||||
void dlg_default_callback(GtkWidget *widget, gpointer data);
|
||||
|
||||
void modifydlg_toggle ();
|
||||
|
||||
// All dialogs
|
||||
int openprojectdlg_execute (char* filename);
|
||||
int saveprojectdlg_execute (char* filename);
|
||||
int savepicturedlg_execute (void* param);
|
||||
int msgbox_execute (const char* text, const char *caption, int flags);
|
||||
int filedlg_execute(const char* caption, char* filename);
|
||||
int arraydlg_execute(void* param);
|
||||
int aboutdlg_execute(void* param);
|
||||
int htmldlg_execute(void* param);
|
||||
int imageoptsdlg_execute(void* param, bool from_htmldlg);
|
||||
int povraydlg_execute(void* param);
|
||||
int preferencesdlg_execute(void* param);
|
||||
int propertiesdlg_execute(void* param);
|
||||
int groupeditdlg_execute(void* param);
|
||||
int groupdlg_execute(void* param);
|
||||
int minifigdlg_execute(void* param);
|
||||
int librarydlg_execute(void* param);
|
||||
|
||||
#endif // _DIALOGS_H_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
345
linux/dlgfile.cpp
Executable file
345
linux/dlgfile.cpp
Executable file
|
@ -0,0 +1,345 @@
|
|||
//
|
||||
// This file holds all the dialogs that are called
|
||||
// from the 'File' submenu:
|
||||
//
|
||||
// - File Open Dialog
|
||||
// - File Save Dialog
|
||||
// - Save Picture Dialog
|
||||
// - Piece Library Manager
|
||||
//
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "system.h"
|
||||
#include "dialogs.h"
|
||||
#include "file.h"
|
||||
#include "image.h"
|
||||
#include "main.h"
|
||||
|
||||
// =============================================================================
|
||||
// Open Project Dialog
|
||||
|
||||
static void openprojectdlg_select (GtkCList *clist, gint row, gint col, GdkEvent *event, GtkPreview *preview)
|
||||
{
|
||||
GtkWidget *parent = gtk_widget_get_toplevel (GTK_WIDGET (clist));
|
||||
const char *filename, *p;
|
||||
bool loaded = false;
|
||||
Image image;
|
||||
|
||||
filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (parent));
|
||||
|
||||
p = strrchr (filename, '.');
|
||||
if ((p != NULL) && (g_strcasecmp (p+1, "lcd") == 0))
|
||||
{
|
||||
float fv;
|
||||
char id[32];
|
||||
FileDisk file;
|
||||
file.Open (filename, "rb");
|
||||
file.Read (id, 32);
|
||||
sscanf (strchr(id, ' '), "%f", &fv);
|
||||
|
||||
if (fv > 0.4f)
|
||||
{
|
||||
file.Read(&fv, 4);
|
||||
|
||||
if (fv > 0.7f)
|
||||
{
|
||||
unsigned long dwPosition;
|
||||
file.Seek (-4, SEEK_END);
|
||||
file.Read (&dwPosition, 4);
|
||||
file.Seek (dwPosition, SEEK_SET);
|
||||
|
||||
if (dwPosition != 0)
|
||||
{
|
||||
if (fv < 1.0f)
|
||||
{
|
||||
file.Seek (54, SEEK_CUR);
|
||||
|
||||
image.Allocate (120, 100, false);
|
||||
file.Read (image.GetData (), 36000);
|
||||
|
||||
for (int y = 0; y < 50; y++)
|
||||
for (int x = 0; x < 120; x++)
|
||||
{
|
||||
unsigned char *from = image.GetData() + x*3 + y*360;
|
||||
unsigned char *to = image.GetData() + x*3 + (100-y-1)*360;
|
||||
unsigned char tmp[3] = { from[0], from[1], from[2] };
|
||||
|
||||
from[0] = to[2];
|
||||
from[1] = to[1];
|
||||
from[2] = to[0];
|
||||
to[0] = tmp[2];
|
||||
to[1] = tmp[1];
|
||||
to[2] = tmp[0];
|
||||
}
|
||||
loaded = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
loaded = image.FileLoad (file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
file.Close();
|
||||
}
|
||||
|
||||
if (loaded == false)
|
||||
{
|
||||
GtkWidget *w = GTK_WIDGET (preview);
|
||||
guchar row[360];
|
||||
|
||||
for (int x = 0; x < 120; x++)
|
||||
{
|
||||
row[x*3] = w->style->bg[0].red/0xFF;
|
||||
row[x*3+1] = w->style->bg[0].green/0xFF;
|
||||
row[x*3+2] = w->style->bg[0].blue/0xFF;
|
||||
}
|
||||
|
||||
for (int y = 0; y < 100; y++)
|
||||
gtk_preview_draw_row (preview, row, 0, y, 120);
|
||||
gtk_widget_draw (w, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < 100; y++)
|
||||
gtk_preview_draw_row (preview, image.GetData ()+y*360, 0, y, 120);
|
||||
gtk_widget_draw (GTK_WIDGET (preview), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int openprojectdlg_execute (char* filename)
|
||||
{
|
||||
GtkWidget *dlg, *preview, *vbox, *frame, *frame2, *hbox;
|
||||
int ret = LC_CANCEL, loop = 1, len;
|
||||
|
||||
dlg = gtk_file_selection_new ("Open Project");
|
||||
gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (((GtkWidget*)(*main_window))));
|
||||
gtk_signal_connect (GTK_OBJECT (dlg), "delete_event",
|
||||
GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);
|
||||
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
|
||||
GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);
|
||||
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (dlg)->ok_button), "clicked",
|
||||
GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (LC_OK));
|
||||
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (dlg)->cancel_button), "clicked",
|
||||
GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (LC_CANCEL));
|
||||
gtk_object_set_data (GTK_OBJECT (dlg), "loop", &loop);
|
||||
gtk_object_set_data (GTK_OBJECT (dlg), "ret", &ret);
|
||||
|
||||
// add preview support
|
||||
hbox = GTK_FILE_SELECTION (dlg)->file_list->parent->parent;
|
||||
|
||||
vbox = gtk_vbox_new (FALSE, 0);
|
||||
gtk_widget_show (vbox);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, TRUE, 0);
|
||||
|
||||
frame = gtk_frame_new ("Preview");
|
||||
gtk_widget_show (frame);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, FALSE, 0);
|
||||
|
||||
frame2 = gtk_frame_new (NULL);
|
||||
gtk_widget_show (frame2);
|
||||
gtk_container_add (GTK_CONTAINER (frame), frame2);
|
||||
gtk_container_border_width (GTK_CONTAINER (frame2), 5);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (frame2), GTK_SHADOW_NONE);
|
||||
|
||||
preview = gtk_preview_new (GTK_PREVIEW_COLOR);
|
||||
gtk_container_add (GTK_CONTAINER (frame2), preview);
|
||||
gtk_preview_size (GTK_PREVIEW (preview), 120, 100);
|
||||
gtk_widget_show (preview);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (dlg)->file_list), "select_row",
|
||||
GTK_SIGNAL_FUNC (openprojectdlg_select), preview);
|
||||
|
||||
len = strlen (filename);
|
||||
if (len != 0)
|
||||
{
|
||||
if (filename[len-1] != '/')
|
||||
strcat (filename, "/");
|
||||
gtk_file_selection_set_filename (GTK_FILE_SELECTION (dlg), filename);
|
||||
}
|
||||
|
||||
gtk_widget_show (dlg);
|
||||
gtk_grab_add (dlg);
|
||||
|
||||
while (loop)
|
||||
gtk_main_iteration ();
|
||||
|
||||
if (ret == LC_OK)
|
||||
strcpy (filename, gtk_file_selection_get_filename (GTK_FILE_SELECTION (dlg)));
|
||||
|
||||
gtk_grab_remove (dlg);
|
||||
gtk_widget_destroy (dlg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Save Project Dialog
|
||||
|
||||
static void saveprojectdlg_preview (GtkToggleButton *button, gpointer data)
|
||||
{
|
||||
Sys_ProfileSaveInt ("Default", "Save Preview", gtk_toggle_button_get_active (button));
|
||||
}
|
||||
|
||||
// used by the save project and save picture dialogs
|
||||
static void savefiledlg_ok (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
GtkWidget *parent;
|
||||
int *loop, *ret;
|
||||
|
||||
parent = gtk_widget_get_toplevel (widget);
|
||||
loop = (int*)gtk_object_get_data (GTK_OBJECT (parent), "loop");
|
||||
ret = (int*)gtk_object_get_data (GTK_OBJECT (parent), "ret");
|
||||
|
||||
if ((GPOINTER_TO_INT (data) == LC_OK) &&
|
||||
(access (gtk_file_selection_get_filename (GTK_FILE_SELECTION (parent)), R_OK) == 0))
|
||||
if (Sys_MessageBox ("File already exists, overwrite ?", "LeoCAD", LC_MB_YESNO) == LC_NO)
|
||||
return;
|
||||
|
||||
*loop = 0;
|
||||
*ret = GPOINTER_TO_INT (data);
|
||||
}
|
||||
|
||||
int saveprojectdlg_execute (char* filename)
|
||||
{
|
||||
GtkWidget *dlg, *check;
|
||||
int ret = LC_CANCEL, loop = 1;
|
||||
|
||||
dlg = gtk_file_selection_new ("Save Project");
|
||||
gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (((GtkWidget*)(*main_window))));
|
||||
gtk_signal_connect (GTK_OBJECT (dlg), "delete_event",
|
||||
GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);
|
||||
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
|
||||
GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);
|
||||
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (dlg)->ok_button), "clicked",
|
||||
GTK_SIGNAL_FUNC (savefiledlg_ok), GINT_TO_POINTER (LC_OK));
|
||||
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (dlg)->cancel_button), "clicked",
|
||||
GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (LC_CANCEL));
|
||||
gtk_object_set_data (GTK_OBJECT (dlg), "loop", &loop);
|
||||
gtk_object_set_data (GTK_OBJECT (dlg), "ret", &ret);
|
||||
|
||||
// add preview checkbox
|
||||
check = gtk_check_button_new_with_label ("Save Preview");
|
||||
gtk_widget_show (check);
|
||||
gtk_box_pack_start (GTK_BOX (GTK_FILE_SELECTION (dlg)->main_vbox), check, FALSE, FALSE, 0);
|
||||
|
||||
int i = Sys_ProfileLoadInt ("Default", "Save Preview", 0);
|
||||
if (i != 0)
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE);
|
||||
gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (saveprojectdlg_preview), NULL);
|
||||
|
||||
gtk_file_selection_set_filename (GTK_FILE_SELECTION (dlg), filename);
|
||||
|
||||
gtk_widget_show (dlg);
|
||||
gtk_grab_add (dlg);
|
||||
|
||||
while (loop)
|
||||
gtk_main_iteration ();
|
||||
|
||||
if (ret == LC_OK)
|
||||
strcpy (filename, gtk_file_selection_get_filename (GTK_FILE_SELECTION (dlg)));
|
||||
|
||||
gtk_grab_remove (dlg);
|
||||
gtk_widget_destroy (dlg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Save Picture Dialog
|
||||
|
||||
static void savepicturedlg_options (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
imageoptsdlg_execute (data, false);
|
||||
}
|
||||
|
||||
int savepicturedlg_execute (void* param)
|
||||
{
|
||||
GtkWidget *dlg, *button;
|
||||
int ret = LC_CANCEL, loop = 1;
|
||||
|
||||
unsigned long image = Sys_ProfileLoadInt ("Default", "Image Options", 1|LC_IMAGE_TRANSPARENT);
|
||||
LC_IMAGEDLG_OPTS* opts = (LC_IMAGEDLG_OPTS*)param;
|
||||
opts->width = Sys_ProfileLoadInt ("Default", "Image Width", gdk_screen_width ());
|
||||
opts->height = Sys_ProfileLoadInt ("Default", "Image Height", gdk_screen_height ());
|
||||
opts->imopts.quality = Sys_ProfileLoadInt ("Default", "JPEG Quality", 70);
|
||||
opts->imopts.interlaced = (image & LC_IMAGE_PROGRESSIVE) != 0;
|
||||
opts->imopts.transparent = (image & LC_IMAGE_TRANSPARENT) != 0;
|
||||
opts->imopts.truecolor = (image & LC_IMAGE_HIGHCOLOR) != 0;
|
||||
opts->imopts.pause = (float)Sys_ProfileLoadInt ("Default", "AVI Pause", 100)/100;
|
||||
opts->imopts.format = (unsigned char)(image & ~(LC_IMAGE_MASK));
|
||||
|
||||
dlg = gtk_file_selection_new ("Save Picture");
|
||||
gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (((GtkWidget*)(*main_window))));
|
||||
gtk_signal_connect (GTK_OBJECT (dlg), "delete_event",
|
||||
GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);
|
||||
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
|
||||
GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);
|
||||
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (dlg)->ok_button), "clicked",
|
||||
GTK_SIGNAL_FUNC (savefiledlg_ok), GINT_TO_POINTER (LC_OK));
|
||||
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (dlg)->cancel_button), "clicked",
|
||||
GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (LC_CANCEL));
|
||||
gtk_object_set_data (GTK_OBJECT (dlg), "loop", &loop);
|
||||
gtk_object_set_data (GTK_OBJECT (dlg), "ret", &ret);
|
||||
|
||||
// add the options button
|
||||
button = gtk_button_new_with_label ("Options");
|
||||
gtk_widget_show (button);
|
||||
gtk_box_pack_end (GTK_BOX (GTK_FILE_SELECTION (dlg)->ok_button->parent), button, TRUE, TRUE, 0);
|
||||
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
|
||||
gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (savepicturedlg_options), param);
|
||||
|
||||
/*
|
||||
gtk_file_selection_set_filename (GTK_FILE_SELECTION (dlg), filename);
|
||||
*/
|
||||
gtk_widget_show (dlg);
|
||||
gtk_grab_add (dlg);
|
||||
|
||||
while (loop)
|
||||
gtk_main_iteration ();
|
||||
|
||||
if (ret == LC_OK)
|
||||
{
|
||||
char ext[5], *p;
|
||||
|
||||
strcpy (opts->filename, gtk_file_selection_get_filename (GTK_FILE_SELECTION (dlg)));
|
||||
|
||||
if (strlen (opts->filename) == 0)
|
||||
ret = LC_CANCEL;
|
||||
|
||||
p = strrchr (opts->filename, '.');
|
||||
if (p != NULL)
|
||||
{
|
||||
strcpy (ext, p+1);
|
||||
strlwr (ext);
|
||||
}
|
||||
else
|
||||
ext[0] = '\0';
|
||||
|
||||
if ((strcmp (ext, "jpg") != 0) && (strcmp (ext, "jpeg") != 0) &&
|
||||
(strcmp (ext, "bmp") != 0) && (strcmp (ext, "gif") != 0) &&
|
||||
(strcmp (ext, "png") != 0) && (strcmp (ext, "avi") != 0))
|
||||
{
|
||||
switch (opts->imopts.format)
|
||||
{
|
||||
case LC_IMAGE_BMP: strcat(opts->filename, ".bmp"); break;
|
||||
case LC_IMAGE_GIF: strcat(opts->filename, ".gif"); break;
|
||||
case LC_IMAGE_JPG: strcat(opts->filename, ".jpg"); break;
|
||||
case LC_IMAGE_PNG: strcat(opts->filename, ".png"); break;
|
||||
case LC_IMAGE_AVI: strcat(opts->filename, ".avi"); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gtk_grab_remove (dlg);
|
||||
gtk_widget_destroy (dlg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Piece Library Manager
|
||||
|
408
linux/dlgpiece.cpp
Executable file
408
linux/dlgpiece.cpp
Executable file
|
@ -0,0 +1,408 @@
|
|||
//
|
||||
// This file holds all the dialogs that are called
|
||||
// from the 'Pieces' submenu:
|
||||
//
|
||||
// - Group Name
|
||||
// - Edit Groups
|
||||
// - Minifig Wizard
|
||||
//
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "opengl.h"
|
||||
#include "gtktools.h"
|
||||
#include "system.h"
|
||||
#include "typedefs.h"
|
||||
#include "globals.h"
|
||||
#include "dialogs.h"
|
||||
#include "matrix.h"
|
||||
#include "pieceinf.h"
|
||||
#include "main.h"
|
||||
#include "minifig.h"
|
||||
|
||||
// =========================================================
|
||||
// Minifig Wizard
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MinifigWizard* wizard;
|
||||
GtkWidget *pieces[LC_MFW_NUMITEMS];
|
||||
GtkWidget *colors[LC_MFW_NUMITEMS];
|
||||
GtkWidget *angles[LC_MFW_NUMITEMS];
|
||||
GtkWidget *preview;
|
||||
GtkWidget *combo;
|
||||
} LC_MINIFIGDLG_STRUCT;
|
||||
|
||||
// User wants to add the minifig to the project
|
||||
static void minifigdlg_ok(GtkWidget *widget, gpointer data)
|
||||
{
|
||||
// LC_MINIFIGDLG_STRUCT* s = (LC_MINIFIGDLG_STRUCT*)data;
|
||||
// LC_MINIFIGDLG_OPTS* opts = (LC_MINIFIGDLG_OPTS*)s->data;
|
||||
|
||||
dlg_end (LC_OK);
|
||||
}
|
||||
|
||||
// A new color was selected from the menu
|
||||
static void minifigdlg_color_response (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
LC_MINIFIGDLG_STRUCT* info;
|
||||
GtkWidget* button;
|
||||
int i;
|
||||
|
||||
button = (GtkWidget*)gtk_object_get_data (GTK_OBJECT (widget), "button");
|
||||
info = (LC_MINIFIGDLG_STRUCT*)gtk_object_get_data (GTK_OBJECT (button), "info");
|
||||
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
for (i = 0; i < 15; i++)
|
||||
if (info->colors[i] == button)
|
||||
break;
|
||||
|
||||
info->wizard->SetColor (i, GPOINTER_TO_INT (data));
|
||||
info->wizard->Redraw ();
|
||||
set_button_pixmap2 (button, FlatColorArray[GPOINTER_TO_INT(data)]);
|
||||
}
|
||||
|
||||
// A color button was clicked
|
||||
static void minifigdlg_color_clicked (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
int i;
|
||||
GtkWidget *menu, *menuitem;
|
||||
|
||||
menu = gtk_menu_new ();
|
||||
|
||||
for (i = 0; i < LC_MAXCOLORS; i++)
|
||||
{
|
||||
menuitem = gtk_menu_item_new_with_label (colornames[i]);
|
||||
gtk_widget_show (menuitem);
|
||||
gtk_menu_append (GTK_MENU (menu), menuitem);
|
||||
|
||||
gtk_object_set_data (GTK_OBJECT (menuitem), "button", widget);
|
||||
gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
|
||||
GTK_SIGNAL_FUNC (minifigdlg_color_response), (void*)i);
|
||||
}
|
||||
|
||||
gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, 0);
|
||||
}
|
||||
|
||||
// New piece was selected
|
||||
static void minifigdlg_piece_changed (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
LC_MINIFIGDLG_STRUCT* info;
|
||||
int i, piece_type = -1, piece_index = -1;
|
||||
const gchar* desc;
|
||||
|
||||
info = (LC_MINIFIGDLG_STRUCT*)gtk_object_get_data (GTK_OBJECT (widget), "info");
|
||||
if (info == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < LC_MFW_NUMITEMS; i++)
|
||||
if (GTK_COMBO (info->pieces[i])->entry == widget)
|
||||
{
|
||||
piece_type = i;
|
||||
break;
|
||||
}
|
||||
|
||||
ObjArray<lcMinifigPieceInfo>& InfoArray = info->wizard->mSettings[piece_type];
|
||||
desc = gtk_entry_get_text (GTK_ENTRY (widget));
|
||||
|
||||
for (i = 0; i < InfoArray.GetSize(); i++)
|
||||
{
|
||||
if (!strcmp(InfoArray[i].Description, desc))
|
||||
{
|
||||
piece_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (piece_index == -1 || piece_type == -1)
|
||||
return;
|
||||
|
||||
info->wizard->SetSelectionIndex (piece_type, piece_index);
|
||||
info->wizard->Redraw ();
|
||||
}
|
||||
|
||||
static void minifigdlg_updatecombo (LC_MINIFIGDLG_STRUCT* s)
|
||||
{
|
||||
char **names;
|
||||
int count;
|
||||
GList *lst = NULL;
|
||||
|
||||
s->wizard->GetMinifigNames (&names, &count);
|
||||
for (int i = 0; i < count; i++)
|
||||
lst = g_list_append (lst, names[i]);
|
||||
|
||||
if (lst == NULL)
|
||||
lst = g_list_append (lst, (void*)"");
|
||||
|
||||
gtk_combo_set_popdown_strings (GTK_COMBO (s->combo), lst);
|
||||
g_list_free (lst);
|
||||
}
|
||||
|
||||
static void minifigdlg_updateselection (LC_MINIFIGDLG_STRUCT* s)
|
||||
{
|
||||
for (int i = 0; i < LC_MFW_NUMITEMS; i++)
|
||||
{
|
||||
int index = s->wizard->GetSelectionIndex(i);
|
||||
|
||||
gtk_signal_handler_block_by_func (GTK_OBJECT (GTK_COMBO (s->pieces[i])->entry),
|
||||
GTK_SIGNAL_FUNC (minifigdlg_piece_changed), NULL);
|
||||
gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (s->pieces[i])->entry), s->wizard->mSettings[i][index].Description);
|
||||
gtk_list_select_item (GTK_LIST (GTK_COMBO (s->pieces[i])->list), index);
|
||||
gtk_signal_handler_unblock_by_func (GTK_OBJECT (GTK_COMBO (s->pieces[i])->entry),
|
||||
GTK_SIGNAL_FUNC (minifigdlg_piece_changed), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void minifigdlg_load (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
LC_MINIFIGDLG_STRUCT* s = (LC_MINIFIGDLG_STRUCT*)data;
|
||||
if (s->wizard->LoadMinifig (gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (s->combo)->entry))) == false)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < LC_MFW_NUMITEMS; i++)
|
||||
{
|
||||
set_button_pixmap2 (s->colors[i], FlatColorArray[s->wizard->m_Colors[i]]);
|
||||
if (s->angles[i] != NULL)
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (s->angles[i]), s->wizard->m_Angles[i]);
|
||||
}
|
||||
minifigdlg_updateselection (s);
|
||||
s->wizard->Redraw ();
|
||||
}
|
||||
|
||||
static void minifigdlg_save (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
LC_MINIFIGDLG_STRUCT* s = (LC_MINIFIGDLG_STRUCT*)data;
|
||||
s->wizard->SaveMinifig (gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (s->combo)->entry)));
|
||||
minifigdlg_updatecombo (s);
|
||||
}
|
||||
|
||||
static void minifigdlg_delete (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
LC_MINIFIGDLG_STRUCT* s = (LC_MINIFIGDLG_STRUCT*)data;
|
||||
s->wizard->DeleteMinifig (gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (s->combo)->entry)));
|
||||
minifigdlg_updatecombo (s);
|
||||
}
|
||||
|
||||
static void adj_changed (GtkAdjustment *adj, gpointer data)
|
||||
{
|
||||
LC_MINIFIGDLG_STRUCT* info = (LC_MINIFIGDLG_STRUCT*)data;
|
||||
float val;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LC_MFW_NUMITEMS; i++)
|
||||
if (info->angles[i] != NULL)
|
||||
if (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (info->angles[i])) == adj)
|
||||
break;
|
||||
|
||||
if (i == LC_MFW_NUMITEMS)
|
||||
return;
|
||||
|
||||
val = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (info->angles[i]));
|
||||
|
||||
if (val == info->wizard->m_Angles[i])
|
||||
return;
|
||||
|
||||
info->wizard->SetAngle (i, val);
|
||||
|
||||
if (info->preview != NULL)
|
||||
info->wizard->Redraw ();
|
||||
}
|
||||
|
||||
// Create a combo box with a color selection control
|
||||
static void minifigdlg_createpair (LC_MINIFIGDLG_STRUCT* info, int idx, int num, GtkWidget* table)
|
||||
{
|
||||
GtkWidget *combo, *color, *spin;
|
||||
GtkObject *adj;
|
||||
|
||||
combo = info->pieces[num] = gtk_combo_new ();
|
||||
gtk_widget_show (combo);
|
||||
gtk_table_attach (GTK_TABLE (table), combo, 0, 1, idx, idx+1,
|
||||
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) GTK_EXPAND, 0, 0);
|
||||
gtk_widget_set_usize (combo, 60, 25);
|
||||
gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE);
|
||||
gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed",
|
||||
GTK_SIGNAL_FUNC (minifigdlg_piece_changed), NULL);
|
||||
gtk_object_set_data (GTK_OBJECT (GTK_COMBO (combo)->entry), "info", info);
|
||||
|
||||
color = info->colors[num] = gtk_button_new_with_label ("");
|
||||
gtk_widget_set_events (color, GDK_EXPOSURE_MASK);
|
||||
gtk_widget_show (color);
|
||||
gtk_object_set_data (GTK_OBJECT (color), "color", &info->wizard->m_Colors[num]);
|
||||
gtk_object_set_data (GTK_OBJECT (color), "info", info);
|
||||
gtk_widget_set_usize (color, 40, 25);
|
||||
gtk_signal_connect (GTK_OBJECT (color), "clicked",
|
||||
GTK_SIGNAL_FUNC (minifigdlg_color_clicked), info);
|
||||
gtk_table_attach (GTK_TABLE (table), color, 1, 2, idx, idx+1,
|
||||
(GtkAttachOptions) GTK_FILL, (GtkAttachOptions) GTK_EXPAND, 0, 0);
|
||||
|
||||
if ((num == LC_MFW_TORSO) || (num == LC_MFW_HIPS))
|
||||
{
|
||||
info->angles[num] = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
adj = gtk_adjustment_new (0, -180, 180, 1, 10, 10);
|
||||
gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (adj_changed), info);
|
||||
|
||||
spin = info->angles[num] = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0);
|
||||
gtk_widget_show (spin);
|
||||
gtk_object_set_data (GTK_OBJECT (color), "info", info);
|
||||
// gtk_widget_set_usize (spin, 40, -1);
|
||||
gtk_table_attach (GTK_TABLE (table), spin, 2, 3, idx, idx+1,
|
||||
(GtkAttachOptions) GTK_FILL, (GtkAttachOptions) GTK_EXPAND, 0, 0);
|
||||
gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spin), TRUE);
|
||||
}
|
||||
|
||||
int minifigdlg_execute (void* param)
|
||||
{
|
||||
GtkWidget *vbox, *hbox, *frame, *table;
|
||||
GtkWidget *dlg, *button;
|
||||
LC_MINIFIGDLG_STRUCT s;
|
||||
int i;
|
||||
|
||||
memset (&s, 0, sizeof (s));
|
||||
s.wizard = (MinifigWizard*)param;
|
||||
|
||||
dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (((GtkWidget*)(*main_window))));
|
||||
gtk_signal_connect (GTK_OBJECT (dlg), "delete_event",
|
||||
GTK_SIGNAL_FUNC (dlg_delete_callback), NULL);
|
||||
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
|
||||
GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);
|
||||
gtk_widget_set_usize (dlg, 600, 360);
|
||||
gtk_window_set_title (GTK_WINDOW (dlg), "Minifig Wizard");
|
||||
// gtk_window_set_policy (GTK_WINDOW (dlg), FALSE, FALSE, FALSE);
|
||||
gtk_widget_realize (dlg);
|
||||
|
||||
vbox = gtk_vbox_new (FALSE, 10);
|
||||
gtk_widget_show (vbox);
|
||||
gtk_container_add (GTK_CONTAINER (dlg), vbox);
|
||||
gtk_container_border_width (GTK_CONTAINER (vbox), 5);
|
||||
|
||||
hbox = gtk_hbox_new (FALSE, 5);
|
||||
gtk_widget_show (hbox);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
|
||||
|
||||
table = gtk_table_new (8, 3, FALSE);
|
||||
gtk_widget_show (table);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0);
|
||||
gtk_table_set_col_spacings (GTK_TABLE (table), 5);
|
||||
gtk_table_set_row_spacings (GTK_TABLE (table), 5);
|
||||
|
||||
minifigdlg_createpair (&s, 0, LC_MFW_HAT, table);
|
||||
minifigdlg_createpair (&s, 1, LC_MFW_NECK, table);
|
||||
minifigdlg_createpair (&s, 2, LC_MFW_RIGHT_ARM, table);
|
||||
minifigdlg_createpair (&s, 3, LC_MFW_RIGHT_HAND, table);
|
||||
minifigdlg_createpair (&s, 4, LC_MFW_RIGHT_TOOL, table);
|
||||
minifigdlg_createpair (&s, 5, LC_MFW_HIPS, table);
|
||||
minifigdlg_createpair (&s, 6, LC_MFW_RIGHT_LEG, table);
|
||||
minifigdlg_createpair (&s, 7, LC_MFW_RIGHT_SHOE, table);
|
||||
|
||||
s.wizard->Create (&s.preview);
|
||||
|
||||
frame = gtk_frame_new (NULL);
|
||||
gtk_widget_show (frame);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), frame);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
|
||||
|
||||
gtk_widget_set_usize (GTK_WIDGET (s.preview), 150, 300);
|
||||
gtk_container_add (GTK_CONTAINER (frame), GTK_WIDGET (s.preview));
|
||||
gtk_widget_show (GTK_WIDGET (s.preview));
|
||||
gtk_object_set_data (GTK_OBJECT (s.preview), "minifig", &s);
|
||||
|
||||
table = gtk_table_new (7, 3, FALSE);
|
||||
gtk_widget_show (table);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0);
|
||||
gtk_table_set_col_spacings (GTK_TABLE (table), 5);
|
||||
gtk_table_set_row_spacings (GTK_TABLE (table), 5);
|
||||
|
||||
minifigdlg_createpair (&s, 0, LC_MFW_HEAD, table);
|
||||
minifigdlg_createpair (&s, 1, LC_MFW_TORSO, table);
|
||||
minifigdlg_createpair (&s, 2, LC_MFW_LEFT_ARM, table);
|
||||
minifigdlg_createpair (&s, 3, LC_MFW_LEFT_HAND, table);
|
||||
minifigdlg_createpair (&s, 4, LC_MFW_LEFT_TOOL, table);
|
||||
minifigdlg_createpair (&s, 5, LC_MFW_LEFT_LEG, table);
|
||||
minifigdlg_createpair (&s, 6, LC_MFW_LEFT_SHOE, table);
|
||||
|
||||
hbox = gtk_hbox_new (FALSE, 10);
|
||||
gtk_widget_show (hbox);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
|
||||
|
||||
s.combo = gtk_combo_new ();
|
||||
gtk_widget_show (s.combo);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), s.combo, FALSE, TRUE, 0);
|
||||
gtk_signal_connect (GTK_OBJECT (GTK_COMBO (s.combo)->entry), "changed",
|
||||
GTK_SIGNAL_FUNC (minifigdlg_load), &s);
|
||||
|
||||
button = gtk_button_new_with_label ("Save");
|
||||
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
||||
GTK_SIGNAL_FUNC (minifigdlg_save), &s);
|
||||
gtk_widget_show (button);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
|
||||
gtk_widget_set_usize (button, 70, 25);
|
||||
|
||||
button = gtk_button_new_with_label ("Delete");
|
||||
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
||||
GTK_SIGNAL_FUNC (minifigdlg_delete), &s);
|
||||
gtk_widget_show (button);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
|
||||
gtk_widget_set_usize (button, 70, 25);
|
||||
|
||||
button = gtk_button_new_with_label ("OK");
|
||||
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
||||
GTK_SIGNAL_FUNC (minifigdlg_ok), &s);
|
||||
gtk_widget_show (button);
|
||||
gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, TRUE, 0);
|
||||
gtk_widget_set_usize (button, 70, 25);
|
||||
GtkAccelGroup *accel_group = gtk_accel_group_new ();
|
||||
gtk_window_add_accel_group (GTK_WINDOW (dlg), accel_group);
|
||||
gtk_widget_add_accelerator (button, "clicked", accel_group,
|
||||
GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE);
|
||||
|
||||
button = gtk_button_new_with_label ("Cancel");
|
||||
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
||||
GTK_SIGNAL_FUNC (dlg_default_callback), GINT_TO_POINTER (LC_CANCEL));
|
||||
gtk_widget_show (button);
|
||||
gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, TRUE, 0);
|
||||
gtk_widget_set_usize (button, 70, 25);
|
||||
gtk_widget_add_accelerator (button, "clicked", accel_group,
|
||||
GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE);
|
||||
|
||||
// Fill the combo boxes with the available pieces
|
||||
for (i = 0; i < LC_MFW_NUMITEMS; i++)
|
||||
{
|
||||
GList* names = NULL;
|
||||
int count = s.wizard->mSettings[i].GetSize();
|
||||
|
||||
for (int j = 0; j < count; j++)
|
||||
names = g_list_append (names, s.wizard->mSettings[i][j].Description);
|
||||
|
||||
if (names != NULL)
|
||||
{
|
||||
gtk_signal_handler_block_by_func(GTK_OBJECT(GTK_COMBO(s.pieces[i])->entry),
|
||||
GTK_SIGNAL_FUNC(minifigdlg_piece_changed), NULL);
|
||||
gtk_combo_set_popdown_strings (GTK_COMBO (s.pieces[i]), names);
|
||||
g_list_free (names);
|
||||
gtk_signal_handler_unblock_by_func(GTK_OBJECT(GTK_COMBO(s.pieces[i])->entry),
|
||||
GTK_SIGNAL_FUNC(minifigdlg_piece_changed), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
minifigdlg_updatecombo (&s);
|
||||
minifigdlg_updateselection (&s);
|
||||
|
||||
gtk_widget_show(dlg);
|
||||
|
||||
for (i = 0; i < LC_MFW_NUMITEMS; i++)
|
||||
{
|
||||
set_button_pixmap2(s.colors[i], FlatColorArray[s.wizard->m_Colors[i]]);
|
||||
}
|
||||
|
||||
return dlg_domodal(dlg, LC_CANCEL);
|
||||
}
|
280
linux/glwindow.cpp
Normal file
280
linux/glwindow.cpp
Normal file
|
@ -0,0 +1,280 @@
|
|||
//
|
||||
// OpenGL window
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include "opengl.h"
|
||||
#include "glwindow.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkWidget *widget;
|
||||
Display* xdisplay;
|
||||
GLXContext context;
|
||||
} GLWindowPrivate;
|
||||
|
||||
// =============================================================================
|
||||
// static functions
|
||||
|
||||
static gint realize_event (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
GLWindow *wnd = (GLWindow*)data;
|
||||
|
||||
wnd->OnInitialUpdate ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer data)
|
||||
{
|
||||
GLWindow *wnd = (GLWindow*)data;
|
||||
|
||||
if (event->count > 0)
|
||||
return TRUE;
|
||||
|
||||
wnd->OnDraw ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer data)
|
||||
{
|
||||
GLWindow *wnd = (GLWindow*)data;
|
||||
int x, y;
|
||||
|
||||
x = (int)event->x;
|
||||
y = widget->allocation.height - (int)event->y - 1;
|
||||
|
||||
if (event->type == GDK_BUTTON_PRESS)
|
||||
{
|
||||
if (event->button == 1)
|
||||
wnd->OnLeftButtonDown (x, y, (event->state & GDK_CONTROL_MASK) != 0,
|
||||
(event->state & GDK_SHIFT_MASK) != 0);
|
||||
else if (event->button == 3)
|
||||
wnd->OnRightButtonDown (x, y, (event->state & GDK_CONTROL_MASK) != 0,
|
||||
(event->state & GDK_SHIFT_MASK) != 0);
|
||||
}
|
||||
else if (event->type == GDK_2BUTTON_PRESS)
|
||||
{
|
||||
wnd->OnLeftButtonDoubleClick (x, y, (event->state & GDK_CONTROL_MASK) != 0,
|
||||
(event->state & GDK_SHIFT_MASK) != 0);
|
||||
}
|
||||
|
||||
gtk_window_set_focus (GTK_WINDOW (gtk_widget_get_toplevel (widget)), widget);
|
||||
gdk_pointer_grab (widget->window, FALSE, (GdkEventMask)(GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK|
|
||||
GDK_POINTER_MOTION_MASK|GDK_POINTER_MOTION_HINT_MASK),
|
||||
NULL, NULL, GDK_CURRENT_TIME);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint button_release_event (GtkWidget *widget, GdkEventButton *event, gpointer data)
|
||||
{
|
||||
GLWindow *wnd = (GLWindow*)data;
|
||||
int x, y;
|
||||
|
||||
x = (int)event->x;
|
||||
y = widget->allocation.height - (int)event->y - 1;
|
||||
|
||||
gdk_pointer_ungrab (GDK_CURRENT_TIME);
|
||||
|
||||
if (event->button == 1)
|
||||
wnd->OnLeftButtonUp (x, y, (event->state & GDK_CONTROL_MASK) != 0,
|
||||
(event->state & GDK_SHIFT_MASK) != 0);
|
||||
else if (event->button == 3)
|
||||
wnd->OnRightButtonUp (x, y, (event->state & GDK_CONTROL_MASK) != 0,
|
||||
(event->state & GDK_SHIFT_MASK) != 0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint pointer_motion_event (GtkWidget *widget, GdkEventMotion *event, gpointer data)
|
||||
{
|
||||
GLWindow *wnd = (GLWindow*)data;
|
||||
GdkModifierType state;
|
||||
int x, y;
|
||||
|
||||
if (event->is_hint)
|
||||
{
|
||||
gdk_window_get_pointer (event->window, &x, &y, &state);
|
||||
state = (GdkModifierType)0;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = (int)event->x;
|
||||
y = (int)event->y;
|
||||
state = (GdkModifierType)event->state;
|
||||
}
|
||||
|
||||
y = widget->allocation.height - y - 1;
|
||||
|
||||
wnd->OnMouseMove (x, y, (event->state & GDK_CONTROL_MASK) != 0, (event->state & GDK_SHIFT_MASK) != 0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint size_allocate_event (GtkWidget *widget, GtkAllocation *allocation, gpointer data)
|
||||
{
|
||||
GLWindow *wnd = (GLWindow*)data;
|
||||
|
||||
wnd->OnSize (allocation->width, allocation->height);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
/*
|
||||
static void destroy_event (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
GLWindow *wnd = (GLWindow*)data;
|
||||
|
||||
wnd->DestroyContext ();
|
||||
}
|
||||
*/
|
||||
// =============================================================================
|
||||
// GLWindow class
|
||||
|
||||
GLWindow::GLWindow (GLWindow *share)
|
||||
{
|
||||
m_pShare = share;
|
||||
m_pData = g_malloc (sizeof (GLWindowPrivate));
|
||||
}
|
||||
|
||||
GLWindow::~GLWindow ()
|
||||
{
|
||||
DestroyContext ();
|
||||
g_free (m_pData);
|
||||
}
|
||||
|
||||
bool GLWindow::Create (void *data)
|
||||
{
|
||||
int attrlist[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 16, 0 };
|
||||
GLWindowPrivate *prv = (GLWindowPrivate*)m_pData;
|
||||
Display *dpy = GDK_DISPLAY();
|
||||
GdkVisual *visual;
|
||||
XVisualInfo *vi;
|
||||
|
||||
// choose visual
|
||||
visual = gdk_visual_get_system ();
|
||||
if (visual->depth < 16)
|
||||
printf ("OpenGL fatal error: LeoCAD needs a display with at least 16 bit colors.\n");
|
||||
|
||||
if (dpy == NULL)
|
||||
{
|
||||
printf ("OpenGL fatal error: Cannot get display.\n");
|
||||
return false;
|
||||
}
|
||||
prv->xdisplay = dpy;
|
||||
|
||||
vi = pfnglXChooseVisual (dpy, DefaultScreen (dpy), attrlist);
|
||||
if (vi == NULL)
|
||||
{
|
||||
printf ("OpenGL fatal error: glXChooseVisual failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
visual = gdkx_visual_get (vi->visualid);
|
||||
if (visual == NULL)
|
||||
{
|
||||
printf ("OpenGL fatal error: Cannot get visual.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
gtk_widget_push_colormap (gdk_colormap_new (visual, TRUE));
|
||||
gtk_widget_push_visual (visual);
|
||||
|
||||
prv->widget = gtk_drawing_area_new ();
|
||||
gtk_widget_set_double_buffered(GTK_WIDGET(prv->widget), FALSE);
|
||||
|
||||
if (m_pShare == NULL)
|
||||
prv->context = pfnglXCreateContext (dpy, vi, NULL, True);
|
||||
else
|
||||
{
|
||||
GLWindowPrivate *share = (GLWindowPrivate*)m_pShare->m_pData;
|
||||
|
||||
prv->context = pfnglXCreateContext (dpy, vi, share->context, True);
|
||||
}
|
||||
|
||||
gtk_widget_pop_visual ();
|
||||
gtk_widget_pop_colormap ();
|
||||
|
||||
XFree (vi);
|
||||
|
||||
GTK_WIDGET_SET_FLAGS (prv->widget, GTK_CAN_FOCUS);
|
||||
|
||||
gtk_widget_set_events (GTK_WIDGET (prv->widget), GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
|
||||
GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
|
||||
|
||||
// Connect signal handlers
|
||||
gtk_signal_connect (GTK_OBJECT (prv->widget), "expose_event",
|
||||
GTK_SIGNAL_FUNC (expose_event), this);
|
||||
// gtk_signal_connect (GTK_OBJECT (prv->widget), "destroy",
|
||||
// GTK_SIGNAL_FUNC (destroy_event), this);
|
||||
gtk_signal_connect (GTK_OBJECT (prv->widget), "size_allocate",
|
||||
GTK_SIGNAL_FUNC (size_allocate_event), this);
|
||||
gtk_signal_connect (GTK_OBJECT (prv->widget), "motion_notify_event",
|
||||
GTK_SIGNAL_FUNC (pointer_motion_event), this);
|
||||
gtk_signal_connect (GTK_OBJECT (prv->widget), "button_press_event",
|
||||
GTK_SIGNAL_FUNC (button_press_event), this);
|
||||
gtk_signal_connect (GTK_OBJECT (prv->widget), "button_release_event",
|
||||
GTK_SIGNAL_FUNC (button_release_event), this);
|
||||
gtk_signal_connect (GTK_OBJECT (prv->widget), "realize",
|
||||
GTK_SIGNAL_FUNC (realize_event), this);
|
||||
|
||||
*((GtkWidget**)data) = prv->widget;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLWindow::DestroyContext ()
|
||||
{
|
||||
GLWindowPrivate *prv = (GLWindowPrivate*)m_pData;
|
||||
|
||||
if (prv->context == pfnglXGetCurrentContext ())
|
||||
pfnglXMakeCurrent (prv->xdisplay, None, NULL);
|
||||
|
||||
if (prv->context)
|
||||
pfnglXDestroyContext (prv->xdisplay, prv->context);
|
||||
|
||||
prv->context = NULL;
|
||||
}
|
||||
|
||||
void GLWindow::OnInitialUpdate ()
|
||||
{
|
||||
MakeCurrent ();
|
||||
GL_InitializeExtensions ();
|
||||
}
|
||||
|
||||
bool GLWindow::MakeCurrent ()
|
||||
{
|
||||
GLWindowPrivate *prv = (GLWindowPrivate*)m_pData;
|
||||
gboolean ret = false;
|
||||
|
||||
if (prv->context)
|
||||
ret = pfnglXMakeCurrent (prv->xdisplay, GDK_WINDOW_XWINDOW (prv->widget->window), prv->context);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GLWindow::SwapBuffers ()
|
||||
{
|
||||
GLWindowPrivate *prv = (GLWindowPrivate*)m_pData;
|
||||
|
||||
if (prv->context)
|
||||
pfnglXSwapBuffers (GDK_WINDOW_XDISPLAY (prv->widget->window), GDK_WINDOW_XWINDOW (prv->widget->window));
|
||||
}
|
||||
|
||||
void GLWindow::Redraw ()
|
||||
{
|
||||
GLWindowPrivate *prv = (GLWindowPrivate*)m_pData;
|
||||
|
||||
gtk_widget_draw (prv->widget, (GdkRectangle*)NULL);
|
||||
}
|
||||
|
||||
void GLWindow::CaptureMouse()
|
||||
{
|
||||
}
|
||||
|
||||
void GLWindow::ReleaseMouse()
|
||||
{
|
||||
}
|
229
linux/gtkmisc.cpp
Executable file
229
linux/gtkmisc.cpp
Executable file
|
@ -0,0 +1,229 @@
|
|||
//
|
||||
// Small functions to help with GTK
|
||||
//
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <string.h>
|
||||
#include "gtkmisc.h"
|
||||
#include "globals.h"
|
||||
#include "project.h"
|
||||
//#include "pixmenu.h"
|
||||
#include "gtktools.h"
|
||||
|
||||
// =============================================================================
|
||||
// Pixmap functions
|
||||
|
||||
#include "pixmaps/vports01.xpm"
|
||||
#include "pixmaps/vports02.xpm"
|
||||
#include "pixmaps/vports03.xpm"
|
||||
#include "pixmaps/vports04.xpm"
|
||||
#include "pixmaps/vports05.xpm"
|
||||
#include "pixmaps/vports06.xpm"
|
||||
#include "pixmaps/vports07.xpm"
|
||||
#include "pixmaps/vports08.xpm"
|
||||
#include "pixmaps/vports09.xpm"
|
||||
#include "pixmaps/vports10.xpm"
|
||||
#include "pixmaps/vports11.xpm"
|
||||
#include "pixmaps/vports12.xpm"
|
||||
#include "pixmaps/vports13.xpm"
|
||||
#include "pixmaps/vports14.xpm"
|
||||
|
||||
// Load a pixmap file from the disk
|
||||
void load_pixmap (const char* filename, GdkPixmap **gdkpixmap, GdkBitmap **mask)
|
||||
{
|
||||
struct { const char* name; const char** data; } table[14] =
|
||||
{
|
||||
{ "vports01.xpm", vports01 },
|
||||
{ "vports02.xpm", vports02 },
|
||||
{ "vports03.xpm", vports03 },
|
||||
{ "vports04.xpm", vports04 },
|
||||
{ "vports05.xpm", vports05 },
|
||||
{ "vports06.xpm", vports06 },
|
||||
{ "vports07.xpm", vports07 },
|
||||
{ "vports08.xpm", vports08 },
|
||||
{ "vports09.xpm", vports09 },
|
||||
{ "vports10.xpm", vports10 },
|
||||
{ "vports11.xpm", vports11 },
|
||||
{ "vports12.xpm", vports12 },
|
||||
{ "vports13.xpm", vports13 },
|
||||
{ "vports14.xpm", vports14 },
|
||||
};
|
||||
|
||||
*gdkpixmap = NULL;
|
||||
for (int i = 0; i < 14; i++)
|
||||
if (strcmp (table[i].name, filename) == 0)
|
||||
{
|
||||
*gdkpixmap = gdk_pixmap_create_from_xpm_d (GDK_ROOT_PARENT(), mask, NULL, (gchar**)table[i].data);
|
||||
break;
|
||||
}
|
||||
|
||||
if (*gdkpixmap == NULL)
|
||||
{
|
||||
const char *dummy[] = { "1 1 1 1", " c None", " " };
|
||||
*gdkpixmap = gdk_pixmap_create_from_xpm_d (GDK_ROOT_PARENT(), mask, NULL, (gchar**)dummy);
|
||||
}
|
||||
}
|
||||
|
||||
// Load a xpm file and return a pixmap widget
|
||||
GtkWidget* create_pixmap (const char* filename)
|
||||
{
|
||||
GdkPixmap *gdkpixmap;
|
||||
GdkBitmap *mask;
|
||||
GtkWidget *pixmap;
|
||||
|
||||
load_pixmap (filename, &gdkpixmap, &mask);
|
||||
pixmap = gtk_pixmap_new (gdkpixmap, mask);
|
||||
gtk_widget_show (pixmap);
|
||||
|
||||
gdk_pixmap_unref (gdkpixmap);
|
||||
gdk_pixmap_unref (mask);
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Menu stuff
|
||||
|
||||
GtkWidget* menu_separator (GtkWidget *menu)
|
||||
{
|
||||
GtkWidget *menu_item = gtk_menu_item_new ();
|
||||
gtk_menu_append (GTK_MENU (menu), menu_item);
|
||||
gtk_widget_set_sensitive (menu_item, FALSE);
|
||||
gtk_widget_show (menu_item);
|
||||
return menu_item;
|
||||
}
|
||||
|
||||
GtkWidget* menu_tearoff (GtkWidget *menu)
|
||||
{
|
||||
GtkWidget *menu_item = gtk_tearoff_menu_item_new ();
|
||||
gtk_menu_append (GTK_MENU (menu), menu_item);
|
||||
// gtk_widget_set_sensitive (menu_item, FALSE);
|
||||
gtk_widget_show (menu_item);
|
||||
return menu_item;
|
||||
}
|
||||
|
||||
GtkWidget* create_sub_menu(GtkWidget* bar, const char* label, GtkAccelGroup* accel)
|
||||
{
|
||||
GtkWidget *item, *menu;
|
||||
|
||||
item = gtk_menu_item_new_with_mnemonic(label);
|
||||
gtk_widget_show (item);
|
||||
gtk_container_add (GTK_CONTAINER (bar), item);
|
||||
|
||||
menu = gtk_menu_new ();
|
||||
gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
GtkWidget* create_menu_in_menu(GtkWidget* menu, const char* label, GtkAccelGroup* accel)
|
||||
{
|
||||
GtkWidget *item, *submenu;
|
||||
|
||||
item = gtk_menu_item_new_with_mnemonic(label);
|
||||
gtk_widget_show (item);
|
||||
gtk_container_add (GTK_CONTAINER (menu), item);
|
||||
|
||||
submenu = gtk_menu_new ();
|
||||
gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
|
||||
|
||||
return submenu;
|
||||
}
|
||||
|
||||
GtkWidget* create_menu_item(GtkWidget *menu, const char *label, GtkAccelGroup *menu_accel,
|
||||
GtkSignalFunc func, GtkObject *window, int id, const char* data)
|
||||
{
|
||||
GtkWidget *item;
|
||||
|
||||
item = gtk_menu_item_new_with_mnemonic (label);
|
||||
gtk_widget_show (item);
|
||||
gtk_container_add (GTK_CONTAINER (menu), item);
|
||||
gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id));
|
||||
|
||||
if (data != NULL)
|
||||
gtk_object_set_data (window, data, item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
GtkWidget* create_pixmap_menu_item(GtkWidget *menu, const gchar *label, const char **pixmap, GtkAccelGroup *menu_accel,
|
||||
GtkSignalFunc func, GtkObject *window, int id, const char* data)
|
||||
{
|
||||
GtkWidget *item, *pixmap_widget;
|
||||
|
||||
item = gtk_image_menu_item_new_with_mnemonic(label);
|
||||
|
||||
pixmap_widget = new_pixmap (GTK_WIDGET (window), pixmap);
|
||||
gtk_widget_show (pixmap_widget);
|
||||
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), pixmap_widget);
|
||||
|
||||
gtk_widget_show (item);
|
||||
gtk_container_add (GTK_CONTAINER (menu), item);
|
||||
gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id));
|
||||
|
||||
if (data != NULL)
|
||||
gtk_object_set_data (window, data, item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
GtkWidget* create_check_menu_item(GtkWidget *menu, const char *label, GtkAccelGroup *menu_accel,
|
||||
GtkSignalFunc func, GtkObject *window, int id, const char* data)
|
||||
{
|
||||
GtkWidget *item;
|
||||
|
||||
item = gtk_check_menu_item_new_with_mnemonic(label);
|
||||
gtk_widget_show (item);
|
||||
gtk_container_add (GTK_CONTAINER (menu), item);
|
||||
gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id));
|
||||
|
||||
if (data != NULL)
|
||||
gtk_object_set_data (window, data, item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
GtkWidget* create_radio_menu_item(GtkWidget *menu, GtkWidget *last, const char *label,
|
||||
GtkAccelGroup *menu_accel, GtkSignalFunc func,
|
||||
GtkObject *window, int id, const char* data)
|
||||
{
|
||||
GtkWidget *item;
|
||||
GSList *group = NULL;
|
||||
|
||||
if (last != NULL)
|
||||
group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (last));
|
||||
item = gtk_radio_menu_item_new_with_mnemonic(group, label);
|
||||
gtk_widget_show (item);
|
||||
gtk_container_add (GTK_CONTAINER (menu), item);
|
||||
gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id));
|
||||
|
||||
if (data != NULL)
|
||||
gtk_object_set_data (window, data, item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
GtkWidget* create_radio_menu_pixmap(GtkWidget *menu, GtkWidget *last, const char *filename,
|
||||
GtkAccelGroup *menu_accel, GtkSignalFunc func,
|
||||
GtkObject *window, int id, const char* data)
|
||||
{
|
||||
GtkWidget *item, *pixmap;
|
||||
GSList *group = NULL;
|
||||
|
||||
if (last != NULL)
|
||||
group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (last));
|
||||
|
||||
item = gtk_radio_menu_item_new (group);
|
||||
gtk_widget_show (item);
|
||||
gtk_container_add (GTK_CONTAINER (menu), item);
|
||||
gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id));
|
||||
|
||||
pixmap = create_pixmap (filename);
|
||||
gtk_container_add (GTK_CONTAINER (item), pixmap);
|
||||
|
||||
if (data != NULL)
|
||||
gtk_object_set_data (window, data, item);
|
||||
|
||||
return item;
|
||||
}
|
25
linux/gtkmisc.h
Executable file
25
linux/gtkmisc.h
Executable file
|
@ -0,0 +1,25 @@
|
|||
#ifndef _GTK_MISC_H_
|
||||
#define _GTK_MISC_H_
|
||||
|
||||
GtkWidget* create_pixmap (char* filename);
|
||||
void load_pixmap (const char* filename, GdkPixmap **gdkpixmap, GdkBitmap **mask);
|
||||
|
||||
GtkWidget* menu_separator (GtkWidget *menu);
|
||||
GtkWidget* menu_tearoff (GtkWidget *menu);
|
||||
GtkWidget* create_sub_menu(GtkWidget *bar, const char *label, GtkAccelGroup *accel);
|
||||
GtkWidget* create_menu_in_menu(GtkWidget *menu, const char *label, GtkAccelGroup *accel);
|
||||
GtkWidget* create_menu_item(GtkWidget *menu, const char *label, GtkAccelGroup *accel,
|
||||
GtkSignalFunc func, GtkObject *window, int id, const char* data);
|
||||
GtkWidget* create_pixmap_menu_item(GtkWidget *menu, const char *label, const char **pixmap, GtkAccelGroup *accel,
|
||||
GtkSignalFunc func, GtkObject *window, int id, const char* data);
|
||||
GtkWidget* create_check_menu_item(GtkWidget *menu, const char *label, GtkAccelGroup *menu_accel,
|
||||
GtkSignalFunc func, GtkObject *window, int id, const char* data);
|
||||
GtkWidget* create_radio_menu_item(GtkWidget *menu, GtkWidget *last, const char *label,
|
||||
GtkAccelGroup *menu_accel, GtkSignalFunc func,
|
||||
GtkObject *window, int id, const char* data);
|
||||
GtkWidget* create_radio_menu_pixmap(GtkWidget *menu, GtkWidget *last, const char *filename,
|
||||
GtkAccelGroup *menu_accel, GtkSignalFunc func,
|
||||
GtkObject *window, int id, const char* data);
|
||||
|
||||
|
||||
#endif // _GTKMISC_H_
|
114
linux/gtktools.cpp
Normal file
114
linux/gtktools.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
// Helper functions for GTK
|
||||
//
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "gtktools.h"
|
||||
|
||||
GtkWidget* new_pixmap(GtkWidget *widget, const char **data)
|
||||
{
|
||||
GdkPixmap *gdkpixmap;
|
||||
GdkBitmap *mask;
|
||||
GtkWidget *pixmap;
|
||||
|
||||
gdkpixmap = gdk_pixmap_create_from_xpm_d(widget->window, &mask, &widget->style->bg[GTK_STATE_NORMAL], (gchar**)data);
|
||||
pixmap = gtk_pixmap_new (gdkpixmap, mask);
|
||||
|
||||
gdk_pixmap_unref (gdkpixmap);
|
||||
gdk_pixmap_unref (mask);
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
GtkWidget* clist_title_with_arrow(GtkWidget* clist, char col, const char* label_text)
|
||||
{
|
||||
GtkWidget *hbox = gtk_hbox_new (FALSE, 0);
|
||||
GtkWidget *arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
|
||||
GtkWidget *label = gtk_label_new (label_text);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
|
||||
gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, TRUE, 0);
|
||||
gtk_widget_show (label);
|
||||
|
||||
gtk_widget_show (hbox);
|
||||
gtk_clist_set_column_widget (GTK_CLIST (clist), col, hbox);
|
||||
|
||||
return arrow;
|
||||
}
|
||||
|
||||
void set_notebook_tab (GtkWidget *notebook, gint page_num, GtkWidget *widget)
|
||||
{
|
||||
gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook), gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page_num), widget);
|
||||
/*
|
||||
GtkNotebookPage *page;
|
||||
GtkWidget *notebook_page;
|
||||
|
||||
page = (GtkNotebookPage*) g_list_nth (GTK_NOTEBOOK (notebook)->children, page_num)->data;
|
||||
notebook_page = page->child;
|
||||
gtk_widget_ref (notebook_page);
|
||||
gtk_notebook_remove_page (GTK_NOTEBOOK (notebook), page_num);
|
||||
gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), notebook_page,
|
||||
widget, page_num);
|
||||
gtk_widget_unref (notebook_page);
|
||||
*/
|
||||
}
|
||||
|
||||
void set_button_pixmap (GtkWidget* widget, float* color)
|
||||
{
|
||||
if (widget->window == NULL)
|
||||
return;
|
||||
|
||||
GdkColor c;
|
||||
GdkGC* gc = gdk_gc_new(widget->window);
|
||||
GdkPixmap* pixmap = gdk_pixmap_new(widget->window, widget->allocation.width - 20,
|
||||
widget->allocation.height - 20, -1);
|
||||
|
||||
c.red = (gushort)(color[0]*0xFFFF);
|
||||
c.green = (gushort)(color[1]*0xFFFF);
|
||||
c.blue = (gushort)(color[2]*0xFFFF);
|
||||
gdk_color_alloc (gtk_widget_get_colormap(widget), &c);
|
||||
gdk_gc_set_foreground(gc, &c);
|
||||
|
||||
gdk_draw_rectangle (pixmap, gc, TRUE, 0, 0,
|
||||
widget->allocation.width - 20, widget->allocation.height - 20);
|
||||
|
||||
GtkWidget* pixmapwid = gtk_pixmap_new (pixmap, (GdkBitmap*)NULL);
|
||||
gtk_widget_show (pixmapwid);
|
||||
|
||||
gtk_container_remove (GTK_CONTAINER(widget), GTK_BIN(widget)->child);
|
||||
gtk_container_add (GTK_CONTAINER(widget), pixmapwid);
|
||||
gdk_gc_destroy(gc);
|
||||
}
|
||||
|
||||
void set_button_pixmap2 (GtkWidget* widget, unsigned char* color)
|
||||
{
|
||||
GdkColor c;
|
||||
GdkGC* gc;
|
||||
GdkPixmap* pixmap;
|
||||
|
||||
if (widget->window == NULL)
|
||||
return;
|
||||
|
||||
if ((widget->allocation.width < 10) || (widget->allocation.height < 10))
|
||||
return;
|
||||
|
||||
gc = gdk_gc_new (widget->window);
|
||||
pixmap = gdk_pixmap_new (widget->window, widget->allocation.width - 10,
|
||||
widget->allocation.height - 10, -1);
|
||||
|
||||
c.red = color[0]*256;
|
||||
c.green = color[1]*256;
|
||||
c.blue = color[2]*256;
|
||||
gdk_color_alloc (gtk_widget_get_colormap(widget), &c);
|
||||
gdk_gc_set_foreground(gc, &c);
|
||||
|
||||
gdk_draw_rectangle (pixmap, gc, TRUE, 0, 0,
|
||||
widget->allocation.width - 5, widget->allocation.height - 5);
|
||||
|
||||
GtkWidget* pixmapwid = gtk_pixmap_new (pixmap, (GdkBitmap*)NULL);
|
||||
gtk_widget_show (pixmapwid);
|
||||
|
||||
gtk_container_remove (GTK_CONTAINER(widget), GTK_BIN(widget)->child);
|
||||
gtk_container_add (GTK_CONTAINER(widget), pixmapwid);
|
||||
gdk_gc_destroy(gc);
|
||||
}
|
||||
|
12
linux/gtktools.h
Normal file
12
linux/gtktools.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
#ifndef _GTKTOOLS_H_
|
||||
#define _GTKTOOLS_H_
|
||||
|
||||
GtkWidget* new_pixmap(GtkWidget* widget, const char** data);
|
||||
GtkWidget* clist_title_with_arrow(GtkWidget* clist, char col, const char* label_text);
|
||||
void set_notebook_tab (GtkWidget *notebook, gint page_num, GtkWidget *widget);
|
||||
void set_button_pixmap (GtkWidget* widget, float* color);
|
||||
void set_button_pixmap2 (GtkWidget* widget, unsigned char* color);
|
||||
|
||||
#endif // _GTKTOOLS_H_
|
||||
|
17
linux/lc
Normal file
17
linux/lc
Normal file
|
@ -0,0 +1,17 @@
|
|||
#!/bin/sh
|
||||
|
||||
# set the LeoCAD library path
|
||||
LEOCAD_LIB=/mnt/f/projects/leocad/windows/debug/
|
||||
export LEOCAD_LIB
|
||||
|
||||
# run the program
|
||||
./leocad
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue