home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Magazin: Amiga-CD 2000 April & May
/
AMIGA_2000_04.iso
/
pd-disketten
/
dms-gepackt
/
6_96
/
apd-6-96-2.dms
/
apd-6-96-2.adf
/
Skalieren
/
scale5.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1996-03-21
|
9KB
|
350 lines
// Scale
// (C) 1996 Clemens Marschner
// $VER: Scale 2.4 (12-Apr-96; 13:36)
// Compiliert mit Maxon-C++ (makefile)
#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <graphics/rastport.h>
#include <pragma/intuition_lib.h>
#include <pragma/exec_lib.h>
#include <pragma/graphics_lib.h>
#include <pragma/dos_lib.h>
#include <stream.h>
// defines
#define FOREVER for(;;)
// Protos
// Assembler-Funktion: Schreibt die Pixel horizontal
extern "C" void WriteLine(register __a0 const char *src, register __a1 char *dest,
register __a2 const char *werte, register __d0 int breite);
void PollLoop();
void Scale(struct RastPort *rp, int dx, int dy, int x1, int y1);
void CalcProps(UBYTE *ziel, int b, int dx);
// Konstanten
const int b = 12*8, h = 12*9;
// externe und globale Variablen
extern const char bild[h][b];
// die Bitmap. Der Demonstration halber als Chunky-Array (leichterer Zugriff!)
// siehe bild.c
struct Window *win;
struct RastPort *rp;
void Example() {
int mx = win->Width/2;
int my = win->Height / 2;
for(int i=0; i<40; i+=4) {
Scale(rp, b+i*2+10, h+i+10, 5,15);
}
}
void main() {
win = OpenWindowTags(NULL,
WA_Flags, WFLG_ACTIVATE | WFLG_CLOSEGADGET | WFLG_DEPTHGADGET |
WFLG_DRAGBAR| WFLG_NOCAREREFRESH|WFLG_DEPTHGADGET|WFLG_SIZEGADGET,
WA_Top, 11, WA_Width, 480, WA_Height, 300,
WA_Left, 238, WA_Top, 0, WA_Title, "Scaling",
WA_MinWidth, 50, WA_MinHeight, 25, WA_MaxWidth,~0,WA_MaxHeight,~0,
WA_IDCMP, IDCMP_CLOSEWINDOW|IDCMP_NEWSIZE,
WA_BlockPen, 4, WA_DetailPen, 3, TAG_END);
if(!win) { cout << "Window offenbar nicht offenbar\n"; return; };
rp = win->RPort;
try {
Delay(125); // warten, bis alle Files zu sind (bei Start aus dem Compiler heraus)
Example(); // zeichnet ein paar Bitmaps
PollLoop(); // paßt die Bitmap dem Window an
} catch(...) { cout << "Fehler\n"; }
CloseWindow(win);
}
inline void Clear(UBYTE*m,int sz) {
while(sz--) *m++=0;
}
// zentrale Routine: Berechnet die Pixelweiten und legt sie im Array "ziel" ab.
void CalcProps(UBYTE *ziel, int qubreite, int zlbreite) {
int x = 0, y = 0, error, dx=zlbreite, dy=qubreite;
if(zlbreite > (qubreite<<8)) {
cout << "Zu groß. Höchstens 25500% möglich\n"; return;
}
// double error = -(0.5 - 0.5*m) * 2*(dx+1) - (dx+1)
// ^ 0.5 * s (Prüfbedingung)
// ^ Skalierung (Faktor s) -> ints
// ^ error-Wert durch korrigierte Linie
// = (-1 + m) * (dx+1) - (dx+1) mit m = (dy+1)/(dx+1)
// int error = (-(dx+1) + (dy+1)) - (dx+1)
// = -dx - 1 + dy + 1 - dx -1
// = dy-dy - dx-1
// = dy-2*dx-1
// bei Verkleinerung: dx und dy vertauscht
Clear(ziel, qubreite);
if(qubreite<=zlbreite) { // vergrößern
error= dy-2*dx-1; // (dy-dx - (dx+1))
int sub=2*(dx+1), add=2*(dy+1), i = zlbreite;
// ^ m*s ^ 1*s
for(i=zlbreite; i; i--) { // (i) prüfen ist schneller als (i<zlbreite)
ziel[x]++;
if(error>0) {
x++;
error-=sub;
}
error+=add;
}
return;
} else { // verkleinern: dx und dy vertauscht, um in 1. Oktanden zu kommen
error= dx-2*dy-1;
int sub=2*(dy+1), add=2*(dx+1);
for (int i = 0; i< qubreite; i++) { // hier die langsame Version
x++;
if(error>0) {
ziel[x]++;
error-=sub;
}
error+=add;
}
return;
}
}
UBYTE breiteanz[2000];
UBYTE hoeheanz[2000];
struct RastPort trp; // für WritePixelLine8
struct BitMap tbm; // ""
// Scale: Skaliert Bild bild[][] mit Breite b und Hoehe h
void Scale(struct RastPort *rp, int dx, int dy, int x1, int y1) {
// dx/dy: Zielbreite/Höhe. x1/y1: Linke obere Ecke der Ausgabe
if(!(dx||dy)) return; // Eine Nullfläche brauchen wir nicht ausgeben
// viel Administratives für WritePixelLine8
UBYTE *zbrpuffer = new char[((dx+1 + 15)>>4)<<4]; // auf 16 aufgerundet
UBYTE *zhopuffer = new char[((dy+1 + 15)>>4)<<4];
int quelly = 0;
// RastPort fertigmachen...
trp = *rp; trp.Layer = NULL; tbm.Rows = 1;
tbm.Depth = rp->BitMap->Depth; trp.BitMap = &tbm;
tbm.BytesPerRow = ((dx + 1 + 15) >> 4) << 1; // Empfehlung des RKM
struct BitMap *bm = trp.BitMap;
// Eine Bitmap mit vier Zeilen, die danach als vier Bitmaps mit einer Zeile
// aufgefaßt wird
if(!(tbm.Planes[0] = AllocRaster(dx, rp->BitMap->Depth))) {
cout << "AllocRaster returnierte 0\n";
throw(int(1));
}
for(int m = 1; m < rp->BitMap->Depth; m++) {
tbm.Planes[m] = tbm.Planes[0] + tbm.BytesPerRow * m * tbm.Rows;
}
// Hier werden die Pixelbreiten berechnet:
CalcProps(breiteanz, b, dx);
// und hier die Höhen:
CalcProps(hoeheanz, h, dy);
// -> breiteanz[i]: die Breiten der Pixel mit x=i
// -> hoeheanz[j]: die Höhen der Pixel mit y=j
int dyc = dy+y1;
while(y1 < dyc) {
if(hoeheanz[quelly] > 0) // Wenn die Zeile überhaupt auftaucht...
{
WriteLine(bild[quelly],zbrpuffer,breiteanz,b);
// Die Assembler-Version ist ein Ersatz für:
//UBYTE *zbcp = zbrpuffer;
//for(int i=0; i < b; i++)
// for(int j = 0; j < breiteanz[i]; j++)
// *zbcp++ = bild[quelly][i];
// ziemlich langsam
UBYTE anz = hoeheanz[quelly];
// die erste Zeile mit WritePixelLine8() ausgeben
if(anz) {
WritePixelLine8(rp, x1,y1++, dx, zbrpuffer, &trp);
anz--;
}
// im Ggs. zu einigen Grafikkarten-Routinen löscht WritePixelLine8()
// den Quellbereich zbrpuffer. Dafür steht eine Kopie der Zeile in bm
// d.h.: jede weitere Zeile einfach kopieren
while (anz--) {
BltBitMapRastPort(bm, 0,0,rp,x1,y1++,dx,1,ABC|ABNC);
}
}
quelly++;
}
FreeRaster(tbm.Planes[0],dx, rp->BitMap->Depth);
delete zbrpuffer;
delete zhopuffer;
}
// PollLoop: Paßt das Bild immer auf Fensterbreite an
void PollLoop() {
BOOL running = TRUE, mbpressed=FALSE;
struct IntuiMessage *imsg, icpy;
if(!win) return;
Scale(rp, win->Width - win->BorderLeft - win->BorderRight,
win->Height - win->BorderTop - win->BorderBottom,
win->BorderLeft+1, win->BorderTop+1);
for(;;)
{
Wait(1 << win->UserPort->mp_SigBit);
while(imsg = (struct IntuiMessage*)GetMsg(win->UserPort))
{
icpy = *imsg; // C++-Kopie
ReplyMsg((struct Message*)imsg);
switch(icpy.Class)
{
case IDCMP_CLOSEWINDOW:
running = FALSE;
break;
case IDCMP_NEWSIZE:
Scale(rp, win->Width - win->BorderLeft - win->BorderRight-1,
win->Height - win->BorderTop - win->BorderBottom,
win->BorderLeft+1, win->BorderTop);
break;
}
}
if(!running) break;
}
}
// i.F. einige Vorversionen von CalcProps() (Version 1 ist ganz interessant)
/****
void CalcProps(UBYTE *ziel, int qubreite, int zlbreite) {
double x = 0, y = 0, error, dx, dy;
int summe=0;
if(zlbreite > (qubreite<<8))
{
cout << "Zu groß. Höchstens 25500% möglich\n";
return;
}
BOOL kleiner = FALSE;
if(qubreite >= zlbreite) {
kleiner = TRUE;
}
dx = qubreite;
dy = zlbreite;
error = -dx-1;
if(kleiner) {
for (int i = 0; i< zlbreite; i++)
{
summe+=ziel[x];
x++;
if(error>=0) {
ziel[x]++;
//cout << "z["<<x<<"]="<<ziel[x]<<"; ";
error-=dy+1;
}
error+=2*dx+2;
}
if(summe != qubreite) cout << "Summe: "<<summe<<"; z: "<<zlbreite<<endl;
}
else
{
for (int i = 0; i< qubreite; i++) {
ziel[x]++;
if(error>=0) {
//cout << "z["<<x<<"]="<<ziel[x]<<"; ";
summe+=ziel[x];
x++;
error-=dx+1; // error-=0.5 skaliert mit 2*dy+1
}
error+=2*dy+2; // error+=m skaliert mit 2*(dx+1)
}
if(summe != zlbreite) cout << "Summe: "<<summe<<"; z: "<<zlbreite<<endl;
}
}
// Version 1: mit doubles
void CalcProps(UBYTE *ziel, int qubreite, int zlbreite) {
double x = 0, y = 0, error, dx=zlbreite, dy=qubreite, m;
int summe=0;
if(zlbreite > (qubreite<<8))
{
cout << "Zu groß. Höchstens 25500% möglich\n";
return;
}
BOOL kleiner = (qubreite>=zlbreite);
// nur Vergrößerung
if(kleiner) {
return;
}
for(int i=0; i<qubreite; i++) ziel[i]=0;
// Fehler: 1 bis zwei Pixel -- wegen double-Fehler???
cout << "Vergrößerung von " << qubreite << " auf " << zlbreite << " Pixel\n";
m = (dy+1)/(dx+1);
error= 0.5 - 0.5*m; // muss man sich mit einer Zeichnung klarmachen
cout << "Steigung: "<<m<<"; error = " << error << "\n";
for (i = 0; i< zlbreite; i++) {
ziel[x]++;
if(error>=0.5) {
summe+=ziel[x];
x++;
error--;
}
error+=m;
}
if(summe != zlbreite) cout << "Summe: "<<summe<<"; z: "<<zlbreite<<endl;
}
void CalcProps(UBYTE *ziel, int qubreite, int zlbreite) {
int x = 0, y = 0, error, dx=zlbreite, dy=qubreite, m;
int summe=0;
if(zlbreite > (qubreite<<8))
{
cout << "Zu groß. Höchstens 25500% möglich\n";
return;
}
BOOL kleiner = (qubreite>=zlbreite);
// nur Vergrößerung
if(kleiner) {
return;
}
// alle Werte mit 2*(dx+1) multipliziert
error= dy-dx;
int sub=2*(dx+1);
int add=2*(dy+1);
for (i = 0; i< zlbreite; i++) {
ziel[x]++;
if(error>=dx+1) {
summe+=ziel[x];
x++;
error-=sub;
}
error+=add;
}
if(qubreite != x) cout << "->Qubreite: " << qubreite << "; x: "<<x<<" (Fehler: "<<qubreite-x<<")"<<endl;
if(summe != zlbreite) cout << "->Summe: "<<summe<<"; zlbreite: "<<zlbreite<<" (Fehler: "<<zlbreite-summe<<")"<<endl;
}
***/