home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d5xx
/
d562
/
intuisup.lha
/
Intuisup
/
Gadgets
/
source.lzh
/
gadgets3.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-10-19
|
23KB
|
743 lines
/*************************************
* *
* Gadgets v2.0 *
* by Torsten Jürgeleit in 05/91 *
* *
* Routines - Part 3 *
* *
*************************************/
/* Includes */
#include <exec/types.h>
#include <exec/memory.h>
#include <devices/inputevent.h>
#include <intuition/intuition.h>
#include <functions.h>
#include <string.h>
#include "/render/render.h"
#include "/texts/texts.h"
#include "/borders/borders.h"
#include "gadgets.h"
#include "imports.h"
/* Refresh gadget */
VOID
refresh_gadget(struct ExtendedGadget *egad)
{
struct GadgetList *gl = egad->eg_GadgetList;
struct RenderInfo *ri = gl->gl_RenderInfo;
struct GadgetData *gd = gl->gl_Data + egad->eg_DataEntry;
struct ExtendedGadget *first_egad = egad;
struct Window *win = gl->gl_Window;
struct RastPort *rp = win->RPort;
struct Gadget *gad;
struct Image *image;
APTR render;
UBYTE flags;
SHORT left_edge, top_edge, width, xoffset;
/* render object text - rendering first because of ghosting by GADGDISABLED */
switch (gd->gd_Type) {
case GADGET_DATA_TYPE_CYCLE :
print_cycle_text(egad);
break;
case GADGET_DATA_TYPE_COUNT :
print_count_text(egad);
break;
case GADGET_DATA_TYPE_LISTVIEW :
print_list_view_text(egad);
break;
}
/* render all gadgets belonging to this object */
do {
gad = &egad->eg_Gadget;
flags = egad->eg_Flags;
/* draw additional border or image if any */
if (flags & (EXTENDED_GADGET_FLAG_RENDER_BORDER |
EXTENDED_GADGET_FLAG_RENDER_IMAGE)) {
left_edge = gad->LeftEdge;
top_edge = gad->TopEdge;
if (flags & EXTENDED_GADGET_FLAG_RENDER_BORDER) {
DrawBorder(rp, (struct Border *)egad->eg_Render, (LONG)
left_edge, (LONG)top_edge);
} else {
image = (struct Image *)egad->eg_Render;
xoffset = (gd->gd_Flags & GADGET_DATA_FLAG_NO_BORDER ?
IMAGE_HORIZ_OFFSET : IMAGE_HORIZ_OFFSET + 2);
top_edge += (SHORT)(gad->Height - image->Height) / 2;
width = gad->Width;
switch (egad->eg_Type) {
case EXTENDED_GADGET_TYPE_CYCLE :
left_edge += xoffset;
break;
case EXTENDED_GADGET_TYPE_COUNT :
DrawImage(rp, &ri->ri_Images[IMAGE_COUNT_RIGHT], (LONG)
(left_edge + width - image->Width - xoffset),
(LONG)top_edge);
left_edge += xoffset;
break;
default :
left_edge += (SHORT)(width - image->Width) / 2;
break;
}
DrawImage(rp, image, (LONG)left_edge, (LONG)top_edge);
}
}
/* special refresh for disabled selected toggle select gadgets to force correct ghosting */
if ((gad->Activation & TOGGLESELECT) && (gad->Flags &
(GADGDISABLED | SELECTED)) == (GADGDISABLED | SELECTED)) {
render = gad->GadgetRender;
gad->GadgetRender = gad->SelectRender;
gad->Flags &= ~SELECTED;
RefreshGList(gad, win, (LONG)NULL, 1L);
gad->Flags |= SELECTED;
gad->GadgetRender = render;
} else {
RefreshGList(gad, win, (LONG)NULL, 1L);
}
} while (egad = egad->eg_NextGadget);
print_gadget_text(first_egad);
}
/* Change gadget */
VOID
change_gadget(struct ExtendedGadget *egad)
{
struct GadgetList *gl = egad->eg_GadgetList;
struct Window *win = gl->gl_Window;
struct Gadget *gad = &egad->eg_Gadget;
struct PropInfo *pinfo;
struct Image *image;
struct MXData *mx;
struct SliderData *sl;
struct CycleData *cy;
struct ScrollerData *sc;
struct ListViewData *lv;
struct PaletteData *pd;
VOID *data = (VOID *)(egad + 1);
UBYTE displayed = gl->gl_Flags & GADGET_LIST_FLAG_DISPLAYED;
USHORT i, data_entry = egad->eg_DataEntry;
ULONG min, max, num, body, pot;
switch ((gl->gl_Data + data_entry)->gd_Type) {
case GADGET_DATA_TYPE_BUTTON :
case GADGET_DATA_TYPE_CHECK :
case GADGET_DATA_TYPE_STRING :
case GADGET_DATA_TYPE_INTEGER :
if (displayed) {
RefreshGList(gad, win, (LONG)NULL, 1L);
}
break;
case GADGET_DATA_TYPE_MX :
mx = data;
max = mx->mx_TextEntries;
num = mx->mx_ActiveEntry;
for (i = 0; i < max; i++) {
gad = &egad->eg_Gadget;
if (i == num) {
gad->Flags |= SELECTED;
if (displayed) {
RefreshGList(gad, win, (LONG)NULL, 1L);
}
} else {
if (gad->Flags & SELECTED) {
gad->Flags &= ~SELECTED;
if (displayed) {
RefreshGList(gad, win, (LONG)NULL, 1L);
}
}
}
egad = egad->eg_NextGadget;
}
break;
case GADGET_DATA_TYPE_SLIDER :
pinfo = (struct PropInfo *)gad->SpecialInfo;
sl = data;
min = sl->sl_Min;
max = (LONG)sl->sl_Max - (LONG)min;
num = (LONG)sl->sl_Level - (LONG)min;
if (sl->sl_Flags & GADGET_DATA_FLAG_ORIENTATION_VERT) {
num = max - num; /* if vert slider then maximum is at top */
}
body = calc_prop_body(max + 1, 1L);
pot = calc_prop_pot(max + 1, 1L, num);
if (sl->sl_Flags & GADGET_DATA_FLAG_ORIENTATION_VERT) {
if (displayed) {
NewModifyProp(gad, win, (LONG)NULL, (LONG)pinfo->Flags, 0L,
pot, 0L, body, 1L);
} else {
pinfo->VertBody = body;
pinfo->VertPot = pot;
}
} else {
if (displayed) {
NewModifyProp(gad, win, (LONG)NULL, (LONG)pinfo->Flags, pot,
0L, body, 0L, 1L);
} else {
pinfo->HorizBody = body;
pinfo->HorizPot = pot;
}
}
break;
case GADGET_DATA_TYPE_SCROLLER :
pinfo = (struct PropInfo *)gad->SpecialInfo;
sc = data;
min = sc->sc_Visible;
max = sc->sc_Total;
num = sc->sc_Top;
body = calc_prop_body(max, min);
pot = calc_prop_pot(max, min, num);
if (sc->sc_Flags & GADGET_DATA_FLAG_ORIENTATION_VERT) {
if (displayed) {
NewModifyProp(gad, win, (LONG)NULL, (LONG)pinfo->Flags, 0L,
pot, 0L, body, 1L);
} else {
pinfo->VertBody = body;
pinfo->VertPot = pot;
}
} else {
if (displayed) {
NewModifyProp(gad, win, (LONG)NULL, (LONG)pinfo->Flags, pot,
0L, body, 0L, 1L);
} else {
pinfo->HorizBody = body;
pinfo->HorizPot = pot;
}
}
break;
case GADGET_DATA_TYPE_CYCLE :
cy = data;
cy->cy_ActiveText = cy->cy_TextArray[cy->cy_ActiveEntry];
if (displayed) {
print_cycle_text(egad);
}
break;
case GADGET_DATA_TYPE_COUNT :
if (displayed) {
print_count_text(egad);
}
break;
case GADGET_DATA_TYPE_LISTVIEW :
pinfo = (struct PropInfo *)gad->SpecialInfo;
lv = data;
min = lv->lv_VisibleEntries;
max = lv->lv_ListEntries;
num = lv->lv_TopEntry;
body = calc_prop_body(max, min);
pot = calc_prop_pot(max, min, num);
if (displayed) {
NewModifyProp(gad, win, (LONG)NULL, (LONG)pinfo->Flags, 0L, pot,
0L, body, 1L);
print_list_view_text(egad);
} else {
pinfo->VertBody = body;
pinfo->VertPot = pot;
}
break;
case GADGET_DATA_TYPE_PALETTE :
pd = data;
if (!(pd->pd_Flags & GADGET_DATA_FLAG_PALETTE_NO_INDICATOR)) {
image = (struct Image *)egad->eg_Render;
image->PlaneOnOff = pd->pd_ActiveColor;
if (displayed) {
DrawImage(win->RPort, image, (LONG)(gad->LeftEdge + (SHORT)
(gad->Width - image->Width) / 2), (LONG)(gad->TopEdge +
(SHORT)(gad->Height - image->Height) / 2));
}
}
break;
}
}
/* Change count gadget value */
VOID
change_count_gadget(struct ExtendedGadget *egad)
{
struct GadgetList *gl = egad->eg_GadgetList;
struct Window *win = gl->gl_Window;
struct MsgPort *up = win->UserPort;
struct IntuiMessage *msg;
struct Gadget *gad = &egad->eg_Gadget;
struct CountData *co = (struct CountData *)(egad + 1);
LONG new_count, min = co->co_Min, max = co->co_Max, count = co->co_Value;
ULONG class, old_idcmp_flags = win->IDCMPFlags;
USHORT distance, new_delay, max_delay = MAX_COUNT_DELAY,
delay = MAX_COUNT_DELAY;
SHORT count_change, middle = gad->LeftEdge + gad->Width / 2;
BOOL keepon = TRUE;
ModifyIDCMP(win, (LONG)(GADGETUP | MOUSEBUTTONS | INTUITICKS));
/* calc new delay and change value with new mouse pos */
if (win->MouseX > middle) {
count_change = +1;
if (count < max) {
count++;
}
} else {
count_change = -1;
if (count > min) {
count--;
}
}
co->co_Value = count;
print_count_text(egad);
do {
/* calc new delay and change value with new mouse pos */
if (win->MouseX > middle) {
distance = win->MouseX - middle;
count_change = +1;
} else {
if (win->MouseX < 0) {
distance = middle + win->MouseX;
} else {
distance = middle - win->MouseX;
}
count_change = -1;
}
if (distance > MAX_COUNT_DISTANCE) {
distance = MAX_COUNT_DISTANCE;
}
new_delay = MAX_COUNT_DELAY - distance / MAX_COUNT_STEP_SIZE;
if (new_delay != max_delay) {
max_delay = delay = new_delay;
}
if (msg = (struct IntuiMessage *)GetMsg(up)) {
class = msg->Class;
ReplyMsg((struct Message *)msg);
if (class == INTUITICKS) {
if (max_delay) {
/* delayed change of count value */
if (! --delay) {
new_count = count + count_change;
if (new_count < min) {
new_count = min;
} else {
if (new_count > max) {
new_count = max;
}
}
/* print new count only if changed */
if (new_count != count) {
co->co_Value = count = new_count;
print_count_text(egad);
}
delay = max_delay;
}
}
} else {
keepon = FALSE;
}
}
if (! max_delay) {
/* undelayed change of count value */
if ((count + count_change) >= min && (count + count_change) <=
max) {
co->co_Value = count += count_change;
print_count_text(egad);
timer_delay(0L, MIN_COUNT_DELAY_MICROS);
}
}
} while (keepon == TRUE);
ModifyIDCMP(win, old_idcmp_flags);
/* restore normal count gadget state (unselected) */
if ((gad->Flags & GADGHIGHBITS) == GADGHCOMP) {
RefreshGList(gad, win, (LONG)NULL, 1L); /* complement gadget select box */
}
gad->Flags &= ~SELECTED;
RefreshGList(gad, win, (LONG)NULL, 1L);
}
/* Delay function - can't use Delay() from DOS (no process) */
VOID
timer_delay(ULONG seconds, ULONG micros)
{
struct MsgPort *port;
struct timerequest *timer;
if (port = CreatePort(NULL, 0L)) {
if (timer = (struct timerequest *)CreateExtIO(port, (LONG)
sizeof(struct timerequest))) {
if (!OpenDevice(TIMERNAME, (LONG)UNIT_VBLANK, (struct IORequest *)
timer, 0L)) {
timer->tr_node.io_Command = TR_ADDREQUEST;
timer->tr_time.tv_secs = seconds;
timer->tr_time.tv_micro = micros;
DoIO((struct IORequest *)timer);
CloseDevice((struct IORequest *)timer);
}
DeleteExtIO((struct IORequest *)timer);
}
DeletePort(port);
}
}
/* Print gadget text */
VOID
print_gadget_text(struct ExtendedGadget *egad)
{
struct GadgetList *gl = egad->eg_GadgetList;
struct RenderInfo *ri = gl->gl_RenderInfo;
struct Window *win = gl->gl_Window;
struct RastPort *rp = win->RPort;
struct GadgetData *gd = gl->gl_Data + egad->eg_DataEntry;
struct Gadget *gad = &egad->eg_Gadget;
struct TextAttr *text_attr;
BYTE c, *text, *buffer;
LONG len;
USHORT save_left_edge, left_edge, top_edge, pos, flags = (gd->gd_Flags &
GADGET_DATA_FLAG_TEXT_COLOR2 ? TEXT_DATA_FLAG_ABSOLUTE_POS |
TEXT_DATA_FLAG_COLOR2 : TEXT_DATA_FLAG_ABSOLUTE_POS);
if (text = egad->eg_Text) {
left_edge = gad->LeftEdge + egad->eg_TextLeftEdge;
top_edge = gad->TopEdge + egad->eg_TextTopEdge;
if (!(text_attr = gd->gd_TextAttr)) {
text_attr = &ri->ri_TextAttr;
}
if (egad->eg_Flags & EXTENDED_GADGET_FLAG_HOT_KEY) {
len = strlen(text) + 1;
pos = egad->eg_HotkeyPos;
if (buffer = AllocMem(len, (LONG)MEMF_PUBLIC)) {
strcpy(buffer, text);
*(buffer + pos - 1) = '\0';
left_edge += print_text(ri, win, &buffer[0],
left_edge, top_edge, TEXT_DATA_TYPE_TEXT, flags, text_attr);
c = *(buffer + pos + 1);
*(buffer + pos + 1) = '\0';
/* print and mark hot key in gadget text */
save_left_edge = left_edge;
left_edge += print_text(ri, win, &buffer[pos], left_edge,
top_edge, TEXT_DATA_TYPE_TEXT, flags, text_attr);
SetDrMd(rp, (LONG)JAM1);
SetAPen(rp, (LONG)(gd->gd_Flags & GADGET_DATA_FLAG_TEXT_COLOR2 ?
ri->ri_TextPen2 : ri->ri_TextPen1));
RectFill(rp, (LONG)save_left_edge, (LONG)(top_edge +
text_attr->ta_YSize), (LONG)(left_edge - 1), (LONG)
(top_edge + text_attr->ta_YSize));
*(buffer + pos + 1) = c;
print_text(ri, win, &buffer[pos + 1], left_edge, top_edge,
TEXT_DATA_TYPE_TEXT, flags, text_attr);
FreeMem(buffer, len);
} else {
print_text(ri, win, text, left_edge, top_edge,
TEXT_DATA_TYPE_TEXT, flags, text_attr);
}
} else {
print_text(ri, win, text, left_edge, top_edge, TEXT_DATA_TYPE_TEXT,
flags, text_attr);
}
}
}
/* Print cycle text */
VOID
print_cycle_text(struct ExtendedGadget *egad)
{
struct GadgetList *gl = egad->eg_GadgetList;
struct RenderInfo *ri = gl->gl_RenderInfo;
struct Window *win = gl->gl_Window;
struct RastPort *rp = win->RPort;
struct CycleData *cy = (struct CycleData *)
(gl->gl_Gadgets[egad->eg_DataEntry] + 1);
struct TextAttr *text_attr = cy->cy_TextAttr;
struct IntuiText itext;
BYTE *text = cy->cy_ActiveText;
USHORT flags = (cy->cy_Flags & GADGET_DATA_FLAG_TEXT_COLOR2 ?
TEXT_DATA_FLAG_ABSOLUTE_POS | TEXT_DATA_FLAG_COLOR2 :
TEXT_DATA_FLAG_ABSOLUTE_POS),
left_edge = cy->cy_LeftEdge, top_edge = cy->cy_TopEdge,
width = cy->cy_Width, height = cy->cy_Height;
itext.IText = (UBYTE *)text;
itext.ITextFont = text_attr;
SetDrMd(rp, (LONG)JAM1);
SetAPen(rp, (LONG)ri->ri_BackPen);
RectFill(rp, (LONG)left_edge, (LONG)top_edge, (LONG)(left_edge + width -
1), (LONG)(top_edge + height - 1));
print_text(ri, win, text, left_edge + (SHORT)(width -
IntuiTextLength(&itext)) / 2, top_edge, TEXT_DATA_TYPE_TEXT,
flags, text_attr);
}
/* Print count text */
VOID
print_count_text(struct ExtendedGadget *egad)
{
struct GadgetList *gl = egad->eg_GadgetList;
struct RenderInfo *ri = gl->gl_RenderInfo;
struct Window *win = gl->gl_Window;
struct RastPort *rp = win->RPort;
struct CountData *co = (struct CountData *)
(gl->gl_Gadgets[egad->eg_DataEntry] + 1);
struct TextAttr *text_attr = co->co_TextAttr;
USHORT type = (co->co_Flags & GADGET_DATA_FLAG_COUNT_SIGNED_DEC ?
TEXT_DATA_TYPE_NUM_SIGNED_DEC :
TEXT_DATA_TYPE_NUM_UNSIGNED_DEC),
flags = (co->co_Flags & GADGET_DATA_FLAG_TEXT_COLOR2 ?
TEXT_DATA_FLAG_ABSOLUTE_POS | TEXT_DATA_FLAG_PLACE_LEFT |
TEXT_DATA_FLAG_COLOR2 : TEXT_DATA_FLAG_ABSOLUTE_POS |
TEXT_DATA_FLAG_PLACE_LEFT),
left_edge = co->co_LeftEdge, top_edge = co->co_TopEdge,
width = co->co_Width, height = co->co_Height;
if ((egad->eg_Gadget.Flags & SELECTED) && (egad->eg_Gadget.Flags &
GADGHIGHBITS) == GADGHCOMP) {
flags |= TEXT_DATA_FLAG_COMPLEMENT;
SetAPen(rp, (LONG)(ri->ri_BackPen ^ ((1 << ri->ri_ScreenDepth) - 1)));
} else {
SetAPen(rp, (LONG)ri->ri_BackPen);
}
SetDrMd(rp, (LONG)JAM1);
RectFill(rp, (LONG)left_edge, (LONG)top_edge, (LONG)(left_edge + width -
1), (LONG)(top_edge + height - 1));
print_text(ri, win, (BYTE *)co->co_Value, left_edge + width,
top_edge, type, flags, text_attr);
}
/* Print list view text */
VOID
print_list_view_text(struct ExtendedGadget *egad)
{
struct GadgetList *gl = egad->eg_GadgetList;
struct RenderInfo *ri = gl->gl_RenderInfo;
struct Window *win = gl->gl_Window;
struct RastPort *rp = win->RPort;
struct Layer *layer = rp->Layer;
struct Region *region, *old_region;
struct Rectangle rect;
struct ListViewData *lv = (struct ListViewData *)
(gl->gl_Gadgets[egad->eg_DataEntry] + 1);
struct TextAttr *text_attr = lv->lv_TextAttr;
struct Node *node = lv->lv_TopNode;
USHORT i, text_width, flags = (lv->lv_Flags &
GADGET_DATA_FLAG_TEXT_COLOR2 ? TEXT_DATA_FLAG_COLOR2 |
TEXT_DATA_FLAG_ABSOLUTE_POS | TEXT_DATA_FLAG_BACK_FILL :
TEXT_DATA_FLAG_ABSOLUTE_POS | TEXT_DATA_FLAG_BACK_FILL),
left_edge = lv->lv_LeftEdge, top_edge = lv->lv_TopEdge,
width = lv->lv_Width, height = lv->lv_Height,
entries = lv->lv_ListEntries, visible = lv->lv_VisibleEntries,
entry_height = lv->lv_EntryHeight, top = lv->lv_TopEntry;
/* calc offsets for inner window */
if (region = NewRegion()) {
/* install clipping region around list view entry area */
rect.MinX = left_edge;
rect.MaxX = left_edge + width - 1;
rect.MinY = top_edge;
rect.MaxY = top_edge + height - 1;
OrRectRegion(region, &rect);
old_region = InstallClipRegion(layer, region);
/* print list view entry text with clipping */
SetDrMd(rp, (LONG)JAM1);
SetAPen(rp, (LONG)ri->ri_BackPen);
for (i = visible; i; i--, top++, top_edge += entry_height) {
if (top < entries) {
text_width = print_text(ri, win, node->ln_Name, left_edge,
top_edge, TEXT_DATA_TYPE_TEXT, flags, text_attr);
if (text_width < width) {
RectFill(rp, (LONG)(left_edge + text_width), (LONG)top_edge,
(LONG)(left_edge + width - 1), (LONG)(top_edge +
entry_height - 1));
}
node = node->ln_Succ;
} else {
break;
}
}
if (i) {
RectFill(rp, (LONG)left_edge, (LONG)top_edge, (LONG)(left_edge +
width - 1), (LONG)(top_edge + i * entry_height - 1));
}
/* remove clipping region */
InstallClipRegion(layer, old_region);
DisposeRegion(region);
}
}
/* Proportional gadget support routines (32 bit !!!) */
#asm
; USHORT = calc_prop_body(max_num, size)(d0.l,d1.l)
XDEF _calc_prop_body
_calc_prop_body:
movem.l d2-d6,-(sp)
; --- check max_num
move.l d0,d6 ; save max_num in d6
beq.s cpb_maximum ; max_num == 0 ?
cmp.l d0,d1 ; size > max_num ?
bhi.s cpb_maximum
; --- multiply size [32 bit] by MAXBODY ($ffff) [16 bit] with 48 bit arithmetic
moveq #0,d0 ; clear shift out reg for size
move.l d1,d3 ; init result by doing the first add
moveq #0,d2 ; clear shift out reg of result
moveq #16-2,d4 ; init shift count (MAXBODY has only 16 bits - one add already done)
cpb_mul_loop:
; --- shift size
add.l d1,d1 ; shift left of size
addx.w d0,d0 ; save shift out
; --- inc result
add.l d1,d3 ; add shifted size to result
addx.w d0,d2 ; add shift out and carry
dbra d4,cpb_mul_loop
; --- divide result [48 bit] by max_num [32 bit] with 48 bit arithmetic
moveq #0,d0 ; clear result
moveq #0,d1 ; clear shift out reg for divident
moveq #0,d4 ; clear sub divisor help reg
moveq #32-1,d5 ; init shift count
cpb_div_loop:
; --- shift result and divident
add.l d0,d0 ; shift result
add.l d3,d3 ; shift left of lower LONG of divident
addx.l d2,d2 ; shift left of upper LONG of divident - add shift out
addx.w d1,d1 ; save shift out
; --- check if upper LONG of divident large enough to sub divisor from
tst.w d1 ; any shift out ?
bne.s cpb_sub_divisor
cmp.l d2,d6 ; upper LONG of divident > divisor ?
bhi.s cpb_next_div
cpb_sub_divisor:
sub.l d6,d2 ; sub divisor from upper LONG of divident
subx.w d4,d1 ; sub underflow (d4 = 0) from shift out of upper LONG of divident
addq.l #1,d0 ; set bit 0 of result
cpb_next_div:
dbra d5,cpb_div_loop
; --- don't return ZERO as prop_body
tst.w d0
bne.s cpb_exit
moveq #1,d0
cpb_exit:
movem.l (sp)+,d2-d6
rts
cpb_maximum:
move.l #$ffff,d0 ; prop_body := MAXBODY
bra cpb_exit
; USHORT = calc_prop_pot(max_num, size, num)(d0.l,d1.l,d2.l)
XDEF _calc_prop_pot
_calc_prop_pot:
movem.l d3-d6,-(sp)
; --- prepare max_num
move.l d0,d6 ; save max_num
beq cpp_minimum
sub.l d1,d6 ; max_num -:= size
bcs cpp_minimum
; --- multiply num by MAXPOT ($ffff) by shift num left by 16
move.l d2,d3
swap d3
moveq #0,d2
move.w d3,d2 ; d2 := upper LONG of result
clr.w d3 ; d3 := lower LONG of result
; --- divide result [48 bit] by max_num [32 bit] with 48 bit arithmetic
moveq #0,d0 ; clear result
moveq #0,d1 ; clear shift out reg for divident
moveq #0,d4 ; clear sub divisor help reg
moveq #32-1,d5 ; init shift count
cpp_div_loop:
; --- shift result and divident
add.l d0,d0 ; shift result
add.l d3,d3 ; shift left of lower LONG of divident
addx.l d2,d2 ; shift left of upper LONG of divident - add shift out
addx.w d1,d1 ; save shift out
; --- check if upper LONG of divident large enough to sub divisor from
tst.w d1 ; any shift out ?
bne.s cpp_sub_divisor
cmp.l d2,d6 ; upper LONG of divident > divisor ?
bhi.s cpp_next_div
cpp_sub_divisor:
sub.l d6,d2 ; sub divisor from upper LONG of divident
subx.w d4,d1 ; sub underflow (d4 = 0) from shift out of upper LONG of divident
addq.l #1,d0 ; set bit 0 of result
cpp_next_div:
dbra d5,cpp_div_loop
; --- if pot_value > MAXPOT then return MAXPOT
cmp.l #$ffff,d0
bls cpp_exit
move.l #$ffff,d0 ; prop_pot := MAXPOT
cpp_exit:
movem.l (sp)+,d3-d6
rts
cpp_minimum:
moveq #0,d0 ; prop_pot := 0
bra cpp_exit
; ULONG = get_prop_pos(max_num, size, pot_value)(d0.l,d1.l,d2.w)
XDEF _get_prop_pos
_get_prop_pos:
movem.l d3-d6,-(sp)
; --- prepare max_num
sub.l d1,d0 ; max_num -:= size
bcs gpp_minimum
; --- if pot_value ]0..MAXPOT[ then inc pot_value
move.w d2,d6 ; save pot value
beq gpp_minimum ; pot_value == 0 ?
addq.w #1,d6 ; inc pot_value
bcs gpp_exit ; if pot_value == MAXPOT then return (max_num - size)
; --- multiply max_num [32 bit] by pot_value [16 bit] with 48 bit arithmetic
moveq #0,d1 ; clear shift out reg for max_num
moveq #0,d2 ; clear result
moveq #0,d3 ; clear shift out reg of result
moveq #0,d4 ; reset bit count
moveq #16-1,d5 ; init shift count (16 bits from pot_value)
bra gpp_check_bit
gpp_mul_loop:
add.l d0,d0 ; shift left of max_num
addx.w d1,d1 ; save shift out
gpp_check_bit:
; --- check bit of pot_value
btst d4,d6
beq gpp_next_mul ; bit set ?
; --- if bit set then inc result
add.l d0,d2 ; add shifted max_num to result
addx.w d1,d3 ; add shift out and carry
gpp_next_mul:
addq.w #1,d4 ; inc bit count
dbra d5,gpp_mul_loop
; --- divide result by MAXPOT ($ffff) by shift num right by 16
move.w d3,d2 ; replace lower word (fractional part) of result by shifted out result
swap d2 ; d2 := bits 16..47 (integer part) of result
move.l d2,d0 ; d0 := prop_pos
gpp_exit:
movem.l (sp)+,d3-d6
rts
gpp_minimum:
moveq #0,d0 ; prop_pos := 0
bra gpp_exit
#endasm